c99c7725a9ab9b9d32a3d36cc7aac897444c641c
[platform/upstream/cmake.git] / Modules / GetPrerequisites.cmake
1 # Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2 # file Copyright.txt or https://cmake.org/licensing for details.
3
4 #[=======================================================================[.rst:
5 GetPrerequisites
6 ----------------
7
8 .. deprecated:: 3.16
9
10   Use :command:`file(GET_RUNTIME_DEPENDENCIES)` instead.
11
12 Functions to analyze and list executable file prerequisites.
13
14 This module provides functions to list the .dll, .dylib or .so files
15 that an executable or shared library file depends on.  (Its
16 prerequisites.)
17
18 It uses various tools to obtain the list of required shared library
19 files:
20
21 ::
22
23    dumpbin (Windows)
24    objdump (MinGW on Windows)
25    ldd (Linux/Unix)
26    otool (Mac OSX)
27
28 The following functions are provided by this module:
29
30 ::
31
32    get_prerequisites
33    list_prerequisites
34    list_prerequisites_by_glob
35    gp_append_unique
36    is_file_executable
37    gp_item_default_embedded_path
38      (projects can override with gp_item_default_embedded_path_override)
39    gp_resolve_item
40      (projects can override with gp_resolve_item_override)
41    gp_resolved_file_type
42      (projects can override with gp_resolved_file_type_override)
43    gp_file_type
44
45 Requires CMake 2.6 or greater because it uses function, break, return
46 and PARENT_SCOPE.
47
48 ::
49
50   GET_PREREQUISITES(<target> <prerequisites_var> <exclude_system> <recurse>
51                     <exepath> <dirs> [<rpaths>])
52
53 Get the list of shared library files required by <target>.  The list
54 in the variable named <prerequisites_var> should be empty on first
55 entry to this function.  On exit, <prerequisites_var> will contain the
56 list of required shared library files.
57
58 <target> is the full path to an executable file.  <prerequisites_var>
59 is the name of a CMake variable to contain the results.
60 <exclude_system> must be 0 or 1 indicating whether to include or
61 exclude "system" prerequisites.  If <recurse> is set to 1 all
62 prerequisites will be found recursively, if set to 0 only direct
63 prerequisites are listed.  <exepath> is the path to the top level
64 executable used for @executable_path replacement on the Mac.  <dirs> is
65 a list of paths where libraries might be found: these paths are
66 searched first when a target without any path info is given.  Then
67 standard system locations are also searched: PATH, Framework
68 locations, /usr/lib...
69
70 The variable GET_PREREQUISITES_VERBOSE can be set to true to enable verbose
71 output.
72
73 ::
74
75   LIST_PREREQUISITES(<target> [<recurse> [<exclude_system> [<verbose>]]])
76
77 Print a message listing the prerequisites of <target>.
78
79 <target> is the name of a shared library or executable target or the
80 full path to a shared library or executable file.  If <recurse> is set
81 to 1 all prerequisites will be found recursively, if set to 0 only
82 direct prerequisites are listed.  <exclude_system> must be 0 or 1
83 indicating whether to include or exclude "system" prerequisites.  With
84 <verbose> set to 0 only the full path names of the prerequisites are
85 printed, set to 1 extra informatin will be displayed.
86
87 ::
88
89   LIST_PREREQUISITES_BY_GLOB(<glob_arg> <glob_exp>)
90
91 Print the prerequisites of shared library and executable files
92 matching a globbing pattern.  <glob_arg> is GLOB or GLOB_RECURSE and
93 <glob_exp> is a globbing expression used with "file(GLOB" or
94 "file(GLOB_RECURSE" to retrieve a list of matching files.  If a
95 matching file is executable, its prerequisites are listed.
96
97 Any additional (optional) arguments provided are passed along as the
98 optional arguments to the list_prerequisites calls.
99
100 ::
101
102   GP_APPEND_UNIQUE(<list_var> <value>)
103
104 Append <value> to the list variable <list_var> only if the value is
105 not already in the list.
106
107 ::
108
109   IS_FILE_EXECUTABLE(<file> <result_var>)
110
111 Return 1 in <result_var> if <file> is a binary executable, 0
112 otherwise.
113
114 ::
115
116   GP_ITEM_DEFAULT_EMBEDDED_PATH(<item> <default_embedded_path_var>)
117
118 Return the path that others should refer to the item by when the item
119 is embedded inside a bundle.
120
121 Override on a per-project basis by providing a project-specific
122 gp_item_default_embedded_path_override function.
123
124 ::
125
126   GP_RESOLVE_ITEM(<context> <item> <exepath> <dirs> <resolved_item_var>
127                   [<rpaths>])
128
129 Resolve an item into an existing full path file.
130
131 Override on a per-project basis by providing a project-specific
132 gp_resolve_item_override function.
133
134 ::
135
136   GP_RESOLVED_FILE_TYPE(<original_file> <file> <exepath> <dirs> <type_var>
137                         [<rpaths>])
138
139 Return the type of <file> with respect to <original_file>.  String
140 describing type of prerequisite is returned in variable named
141 <type_var>.
142
143 Use <exepath> and <dirs> if necessary to resolve non-absolute <file>
144 values -- but only for non-embedded items.
145
146 Possible types are:
147
148 ::
149
150    system
151    local
152    embedded
153    other
154
155 Override on a per-project basis by providing a project-specific
156 gp_resolved_file_type_override function.
157
158 ::
159
160   GP_FILE_TYPE(<original_file> <file> <type_var>)
161
162 Return the type of <file> with respect to <original_file>.  String
163 describing type of prerequisite is returned in variable named
164 <type_var>.
165
166 Possible types are:
167
168 ::
169
170    system
171    local
172    embedded
173    other
174 #]=======================================================================]
175
176 cmake_policy(PUSH)
177 cmake_policy(SET CMP0057 NEW) # if IN_LIST
178
179 function(gp_append_unique list_var value)
180   if(NOT value IN_LIST ${list_var})
181     set(${list_var} ${${list_var}} "${value}" PARENT_SCOPE)
182   endif()
183 endfunction()
184
185
186 function(is_file_executable file result_var)
187   #
188   # A file is not executable until proven otherwise:
189   #
190   set(${result_var} 0 PARENT_SCOPE)
191
192   get_filename_component(file_full "${file}" ABSOLUTE)
193   string(TOLOWER "${file_full}" file_full_lower)
194
195   # If file name ends in .exe on Windows, *assume* executable:
196   #
197   if(WIN32 AND NOT UNIX)
198     if("${file_full_lower}" MATCHES "\\.exe$")
199       set(${result_var} 1 PARENT_SCOPE)
200       return()
201     endif()
202
203     # A clause could be added here that uses output or return value of dumpbin
204     # to determine ${result_var}. In 99%+? practical cases, the exe name
205     # match will be sufficient...
206     #
207   endif()
208
209   # Use the information returned from the Unix shell command "file" to
210   # determine if ${file_full} should be considered an executable file...
211   #
212   # If the file command's output contains "executable" and does *not* contain
213   # "text" then it is likely an executable suitable for prerequisite analysis
214   # via the get_prerequisites macro.
215   #
216   if(UNIX)
217     if(NOT file_cmd)
218       find_program(file_cmd "file")
219       mark_as_advanced(file_cmd)
220     endif()
221
222     if(file_cmd)
223       execute_process(COMMAND "${file_cmd}" "${file_full}"
224         RESULT_VARIABLE file_rv
225         OUTPUT_VARIABLE file_ov
226         ERROR_VARIABLE file_ev
227         OUTPUT_STRIP_TRAILING_WHITESPACE
228         )
229       if(NOT file_rv STREQUAL "0")
230         message(FATAL_ERROR "${file_cmd} failed: ${file_rv}\n${file_ev}")
231       endif()
232
233       # Replace the name of the file in the output with a placeholder token
234       # (the string " _file_full_ ") so that just in case the path name of
235       # the file contains the word "text" or "executable" we are not fooled
236       # into thinking "the wrong thing" because the file name matches the
237       # other 'file' command output we are looking for...
238       #
239       string(REPLACE "${file_full}" " _file_full_ " file_ov "${file_ov}")
240       string(TOLOWER "${file_ov}" file_ov)
241
242       #message(STATUS "file_ov='${file_ov}'")
243       if("${file_ov}" MATCHES "executable")
244         #message(STATUS "executable!")
245         if("${file_ov}" MATCHES "text")
246           #message(STATUS "but text, so *not* a binary executable!")
247         else()
248           set(${result_var} 1 PARENT_SCOPE)
249           return()
250         endif()
251       endif()
252
253       # Also detect position independent executables on Linux,
254       # where "file" gives "shared object ... (uses shared libraries)"
255       if("${file_ov}" MATCHES "shared object.*\(uses shared libs\)")
256         set(${result_var} 1 PARENT_SCOPE)
257         return()
258       endif()
259
260       # "file" version 5.22 does not print "(used shared libraries)"
261       # but uses "interpreter"
262       if("${file_ov}" MATCHES "shared object.*interpreter")
263         set(${result_var} 1 PARENT_SCOPE)
264         return()
265       endif()
266
267     else()
268       message(STATUS "warning: No 'file' command, skipping execute_process...")
269     endif()
270   endif()
271 endfunction()
272
273
274 function(gp_item_default_embedded_path item default_embedded_path_var)
275
276   # On Windows and Linux, "embed" prerequisites in the same directory
277   # as the executable by default:
278   #
279   set(path "@executable_path")
280
281   # On the Mac, relative to the executable depending on the type
282   # of the thing we are embedding:
283   #
284   if(APPLE)
285     #
286     # The assumption here is that all executables in the bundle will be
287     # in same-level-directories inside the bundle. The parent directory
288     # of an executable inside the bundle should be MacOS or a sibling of
289     # MacOS and all embedded paths returned from here will begin with
290     # "@executable_path/../" and will work from all executables in all
291     # such same-level-directories inside the bundle.
292     #
293
294     # By default, embed things right next to the main bundle executable:
295     #
296     set(path "@executable_path/../../Contents/MacOS")
297
298     # Embed frameworks and .dylibs in the embedded "Frameworks" directory
299     # (sibling of MacOS):
300     #
301     if(item MATCHES "[^/]+\\.framework/" OR item MATCHES "\\.dylib$")
302       set(path "@executable_path/../Frameworks")
303     endif()
304   endif()
305
306   # Provide a hook so that projects can override the default embedded location
307   # of any given library by whatever logic they choose:
308   #
309   if(COMMAND gp_item_default_embedded_path_override)
310     gp_item_default_embedded_path_override("${item}" path)
311   endif()
312
313   set(${default_embedded_path_var} "${path}" PARENT_SCOPE)
314 endfunction()
315
316
317 function(gp_resolve_item context item exepath dirs resolved_item_var)
318   set(resolved 0)
319   set(resolved_item "${item}")
320   if(ARGC GREATER 5)
321     set(rpaths "${ARGV5}")
322   else()
323     set(rpaths "")
324   endif()
325
326   # Is it already resolved?
327   #
328   if(IS_ABSOLUTE "${resolved_item}" AND EXISTS "${resolved_item}")
329     set(resolved 1)
330   endif()
331
332   if(NOT resolved)
333     if(item MATCHES "^@executable_path")
334       #
335       # @executable_path references are assumed relative to exepath
336       #
337       string(REPLACE "@executable_path" "${exepath}" ri "${item}")
338       get_filename_component(ri "${ri}" ABSOLUTE)
339
340       if(EXISTS "${ri}")
341         #message(STATUS "info: embedded item exists (${ri})")
342         set(resolved 1)
343         set(resolved_item "${ri}")
344       else()
345         message(STATUS "warning: embedded item does not exist '${ri}'")
346       endif()
347     endif()
348   endif()
349
350   if(NOT resolved)
351     if(item MATCHES "^@loader_path")
352       #
353       # @loader_path references are assumed relative to the
354       # PATH of the given "context" (presumably another library)
355       #
356       get_filename_component(contextpath "${context}" PATH)
357       string(REPLACE "@loader_path" "${contextpath}" ri "${item}")
358       get_filename_component(ri "${ri}" ABSOLUTE)
359
360       if(EXISTS "${ri}")
361         #message(STATUS "info: embedded item exists (${ri})")
362         set(resolved 1)
363         set(resolved_item "${ri}")
364       else()
365         message(STATUS "warning: embedded item does not exist '${ri}'")
366       endif()
367     endif()
368   endif()
369
370   if(NOT resolved)
371     if(item MATCHES "^@rpath")
372       #
373       # @rpath references are relative to the paths built into the binaries with -rpath
374       # We handle this case like we do for other Unixes
375       #
376       string(REPLACE "@rpath/" "" norpath_item "${item}")
377
378       set(ri "ri-NOTFOUND")
379       find_file(ri "${norpath_item}" ${exepath} ${dirs} ${rpaths} NO_DEFAULT_PATH)
380       if(ri)
381         #message(STATUS "info: 'find_file' in exepath/dirs/rpaths (${ri})")
382         set(resolved 1)
383         set(resolved_item "${ri}")
384         set(ri "ri-NOTFOUND")
385       endif()
386
387     endif()
388   endif()
389
390   if(NOT resolved)
391     set(ri "ri-NOTFOUND")
392     find_file(ri "${item}" ${exepath} ${dirs} NO_DEFAULT_PATH)
393     find_file(ri "${item}" ${exepath} ${dirs} /usr/lib)
394
395     get_filename_component(basename_item "${item}" NAME)
396     find_file(ri "${basename_item}" PATHS ${exepath} ${dirs} NO_DEFAULT_PATH)
397     find_file(ri "${basename_item}" PATHS /usr/lib)
398
399     if(ri)
400       #message(STATUS "info: 'find_file' in exepath/dirs (${ri})")
401       set(resolved 1)
402       set(resolved_item "${ri}")
403       set(ri "ri-NOTFOUND")
404     endif()
405   endif()
406
407   if(NOT resolved)
408     if(item MATCHES "[^/]+\\.framework/")
409       set(fw "fw-NOTFOUND")
410       find_file(fw "${item}"
411         "~/Library/Frameworks"
412         "/Library/Frameworks"
413         "/System/Library/Frameworks"
414       )
415       if(fw)
416         #message(STATUS "info: 'find_file' found framework (${fw})")
417         set(resolved 1)
418         set(resolved_item "${fw}")
419         set(fw "fw-NOTFOUND")
420       endif()
421     endif()
422   endif()
423
424   # Using find_program on Windows will find dll files that are in the PATH.
425   # (Converting simple file names into full path names if found.)
426   #
427   if(WIN32 AND NOT UNIX)
428   if(NOT resolved)
429     set(ri "ri-NOTFOUND")
430     find_program(ri "${item}" PATHS ${exepath} ${dirs} NO_DEFAULT_PATH)
431     find_program(ri "${item}" PATHS ${exepath} ${dirs})
432     if(ri)
433       #message(STATUS "info: 'find_program' in exepath/dirs (${ri})")
434       set(resolved 1)
435       set(resolved_item "${ri}")
436       set(ri "ri-NOTFOUND")
437     endif()
438   endif()
439   endif()
440
441   # Provide a hook so that projects can override item resolution
442   # by whatever logic they choose:
443   #
444   if(COMMAND gp_resolve_item_override)
445     gp_resolve_item_override("${context}" "${item}" "${exepath}" "${dirs}" resolved_item resolved)
446   endif()
447
448   if(NOT resolved)
449     message(STATUS "
450 warning: cannot resolve item '${item}'
451
452   possible problems:
453     need more directories?
454     need to use InstallRequiredSystemLibraries?
455     run in install tree instead of build tree?
456 ")
457 #    message(STATUS "
458 #******************************************************************************
459 #warning: cannot resolve item '${item}'
460 #
461 #  possible problems:
462 #    need more directories?
463 #    need to use InstallRequiredSystemLibraries?
464 #    run in install tree instead of build tree?
465 #
466 #    context='${context}'
467 #    item='${item}'
468 #    exepath='${exepath}'
469 #    dirs='${dirs}'
470 #    resolved_item_var='${resolved_item_var}'
471 #******************************************************************************
472 #")
473   endif()
474
475   set(${resolved_item_var} "${resolved_item}" PARENT_SCOPE)
476 endfunction()
477
478
479 function(gp_resolved_file_type original_file file exepath dirs type_var)
480   if(ARGC GREATER 5)
481     set(rpaths "${ARGV5}")
482   else()
483     set(rpaths "")
484   endif()
485   #message(STATUS "**")
486
487   if(NOT IS_ABSOLUTE "${original_file}")
488     message(STATUS "warning: gp_resolved_file_type expects absolute full path for first arg original_file")
489   endif()
490   if(IS_ABSOLUTE "${original_file}")
491     get_filename_component(original_file "${original_file}" ABSOLUTE) # canonicalize path
492   endif()
493
494   set(is_embedded 0)
495   set(is_local 0)
496   set(is_system 0)
497
498   set(resolved_file "${file}")
499
500   if("${file}" MATCHES "^@(executable|loader)_path")
501     set(is_embedded 1)
502   endif()
503
504   if(NOT is_embedded)
505     if(NOT IS_ABSOLUTE "${file}")
506       gp_resolve_item("${original_file}" "${file}" "${exepath}" "${dirs}" resolved_file "${rpaths}")
507     endif()
508     if(IS_ABSOLUTE "${resolved_file}")
509       get_filename_component(resolved_file "${resolved_file}" ABSOLUTE) # canonicalize path
510     endif()
511
512     string(TOLOWER "${original_file}" original_lower)
513     string(TOLOWER "${resolved_file}" lower)
514
515     if(UNIX)
516       if(resolved_file MATCHES "^(/lib/|/lib32/|/libx32/|/lib64/|/usr/lib/|/usr/lib32/|/usr/libx32/|/usr/lib64/|/usr/X11R6/|/usr/bin/)")
517         set(is_system 1)
518       endif()
519     endif()
520
521     if(APPLE)
522       if(resolved_file MATCHES "^(/System/Library/|/usr/lib/)")
523         set(is_system 1)
524       endif()
525     endif()
526
527     if(WIN32)
528       string(TOLOWER "$ENV{SystemRoot}" sysroot)
529       file(TO_CMAKE_PATH "${sysroot}" sysroot)
530
531       string(TOLOWER "$ENV{windir}" windir)
532       file(TO_CMAKE_PATH "${windir}" windir)
533
534       if(lower MATCHES "^(${sysroot}/sys(tem|wow)|${windir}/sys(tem|wow)|(.*/)*(msvc|api-ms-win-|vcruntime)[^/]+dll)")
535         set(is_system 1)
536       endif()
537
538       if(UNIX)
539         # if cygwin, we can get the properly formed windows paths from cygpath
540         find_program(CYGPATH_EXECUTABLE cygpath)
541
542         if(CYGPATH_EXECUTABLE)
543           execute_process(COMMAND ${CYGPATH_EXECUTABLE} -W
544                           RESULT_VARIABLE env_rv
545                           OUTPUT_VARIABLE env_windir
546                           ERROR_VARIABLE env_ev
547                           OUTPUT_STRIP_TRAILING_WHITESPACE)
548           if(NOT env_rv STREQUAL "0")
549             message(FATAL_ERROR "${CYGPATH_EXECUTABLE} -W failed: ${env_rv}\n${env_ev}")
550           endif()
551           execute_process(COMMAND ${CYGPATH_EXECUTABLE} -S
552                           RESULT_VARIABLE env_rv
553                           OUTPUT_VARIABLE env_sysdir
554                           ERROR_VARIABLE env_ev
555                           OUTPUT_STRIP_TRAILING_WHITESPACE)
556           if(NOT env_rv STREQUAL "0")
557             message(FATAL_ERROR "${CYGPATH_EXECUTABLE} -S failed: ${env_rv}\n${env_ev}")
558           endif()
559           string(TOLOWER "${env_windir}" windir)
560           string(TOLOWER "${env_sysdir}" sysroot)
561
562           if(lower MATCHES "^(${sysroot}/sys(tem|wow)|${windir}/sys(tem|wow)|(.*/)*(msvc|api-ms-win-|vcruntime)[^/]+dll)")
563             set(is_system 1)
564           endif()
565         endif()
566       endif()
567     endif()
568
569     if(NOT is_system)
570       get_filename_component(original_path "${original_lower}" PATH)
571       get_filename_component(path "${lower}" PATH)
572       if(original_path STREQUAL path)
573         set(is_local 1)
574       else()
575         string(LENGTH "${original_path}/" original_length)
576         string(LENGTH "${lower}" path_length)
577         if(${path_length} GREATER ${original_length})
578           string(SUBSTRING "${lower}" 0 ${original_length} path)
579           if("${original_path}/" STREQUAL path)
580             set(is_embedded 1)
581           endif()
582         endif()
583       endif()
584     endif()
585   endif()
586
587   # Return type string based on computed booleans:
588   #
589   set(type "other")
590
591   if(is_system)
592     set(type "system")
593   elseif(is_embedded)
594     set(type "embedded")
595   elseif(is_local)
596     set(type "local")
597   endif()
598
599   #message(STATUS "gp_resolved_file_type: '${file}' '${resolved_file}'")
600   #message(STATUS "                type: '${type}'")
601
602   if(NOT is_embedded)
603     if(NOT IS_ABSOLUTE "${resolved_file}")
604       if(lower MATCHES "^(msvc|api-ms-win-|vcruntime)[^/]+dll" AND is_system)
605         message(STATUS "info: non-absolute msvc file '${file}' returning type '${type}'")
606       else()
607         message(STATUS "warning: gp_resolved_file_type non-absolute file '${file}' returning type '${type}' -- possibly incorrect")
608       endif()
609     endif()
610   endif()
611
612   # Provide a hook so that projects can override the decision on whether a
613   # library belongs to the system or not by whatever logic they choose:
614   #
615   if(COMMAND gp_resolved_file_type_override)
616     gp_resolved_file_type_override("${resolved_file}" type)
617   endif()
618
619   set(${type_var} "${type}" PARENT_SCOPE)
620
621   #message(STATUS "**")
622 endfunction()
623
624
625 function(gp_file_type original_file file type_var)
626   if(NOT IS_ABSOLUTE "${original_file}")
627     message(STATUS "warning: gp_file_type expects absolute full path for first arg original_file")
628   endif()
629
630   get_filename_component(exepath "${original_file}" PATH)
631
632   set(type "")
633   gp_resolved_file_type("${original_file}" "${file}" "${exepath}" "" type)
634
635   set(${type_var} "${type}" PARENT_SCOPE)
636 endfunction()
637
638
639 function(get_prerequisites target prerequisites_var exclude_system recurse exepath dirs)
640   set(verbose 0)
641   set(eol_char "E")
642   if(ARGC GREATER 6)
643     set(rpaths "${ARGV6}")
644   else()
645     set(rpaths "")
646   endif()
647
648   if(GET_PREREQUISITES_VERBOSE)
649     set(verbose 1)
650   endif()
651
652   if(NOT IS_ABSOLUTE "${target}")
653     message("warning: target '${target}' is not absolute...")
654   endif()
655
656   if(NOT EXISTS "${target}")
657     message("warning: target '${target}' does not exist...")
658     return()
659   endif()
660
661   # Check for a script by extension (.bat,.sh,...) or if the file starts with "#!" (shebang)
662   file(READ ${target} file_contents LIMIT 5)
663   if(target MATCHES "\\.(bat|c?sh|bash|ksh|cmd)$" OR file_contents MATCHES "^#!")
664     message(STATUS "GetPrequisites(${target}) : ignoring script file")
665     # Clear var
666     set(${prerequisites_var} "" PARENT_SCOPE)
667     return()
668   endif()
669
670   set(gp_cmd_paths ${gp_cmd_paths}
671     "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\14.0;InstallDir]/../../VC/bin"
672     "$ENV{VS140COMNTOOLS}/../../VC/bin"
673     "C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/bin"
674     "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\12.0;InstallDir]/../../VC/bin"
675     "$ENV{VS120COMNTOOLS}/../../VC/bin"
676     "C:/Program Files (x86)/Microsoft Visual Studio 12.0/VC/bin"
677     "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\11.0;InstallDir]/../../VC/bin"
678     "$ENV{VS110COMNTOOLS}/../../VC/bin"
679     "C:/Program Files (x86)/Microsoft Visual Studio 11.0/VC/bin"
680     "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\10.0;InstallDir]/../../VC/bin"
681     "$ENV{VS100COMNTOOLS}/../../VC/bin"
682     "C:/Program Files (x86)/Microsoft Visual Studio 10.0/VC/bin"
683     "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\9.0;InstallDir]/../../VC/bin"
684     "$ENV{VS90COMNTOOLS}/../../VC/bin"
685     "C:/Program Files/Microsoft Visual Studio 9.0/VC/bin"
686     "C:/Program Files (x86)/Microsoft Visual Studio 9.0/VC/bin"
687     "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0;InstallDir]/../../VC/bin"
688     "$ENV{VS80COMNTOOLS}/../../VC/bin"
689     "C:/Program Files/Microsoft Visual Studio 8/VC/BIN"
690     "C:/Program Files (x86)/Microsoft Visual Studio 8/VC/BIN"
691     "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\7.1;InstallDir]/../../VC7/bin"
692     "$ENV{VS71COMNTOOLS}/../../VC7/bin"
693     "C:/Program Files/Microsoft Visual Studio .NET 2003/VC7/BIN"
694     "C:/Program Files (x86)/Microsoft Visual Studio .NET 2003/VC7/BIN"
695     )
696
697   # <setup-gp_tool-vars>
698   #
699   # Try to choose the right tool by default. Caller can set gp_tool prior to
700   # calling this function to force using a different tool.
701   #
702   if(NOT gp_tool)
703     set(gp_tool "ldd")
704
705     if(APPLE)
706       set(gp_tool "otool")
707     endif()
708
709     if(WIN32 AND NOT UNIX) # This is how to check for cygwin, har!
710       find_program(gp_dumpbin "dumpbin" PATHS ${gp_cmd_paths})
711       if(gp_dumpbin)
712         set(gp_tool "dumpbin")
713       elseif(CMAKE_OBJDUMP) # Try harder. Maybe we're on MinGW
714         set(gp_tool "${CMAKE_OBJDUMP}")
715       else()
716         set(gp_tool "objdump")
717       endif()
718     endif()
719   endif()
720
721   find_program(gp_cmd ${gp_tool} PATHS ${gp_cmd_paths})
722
723   if(NOT gp_cmd)
724     message(STATUS "warning: could not find '${gp_tool}' - cannot analyze prerequisites...")
725     return()
726   endif()
727
728   set(gp_cmd_maybe_filter)      # optional command to pre-filter gp_tool results
729
730   if(gp_tool MATCHES "ldd$")
731     set(gp_cmd_args "")
732     set(gp_regex "^[\t ]*[^\t ]+ =>[\t ]+([^\t\(]+)( \(.+\))?${eol_char}$")
733     set(gp_regex_error "not found${eol_char}$")
734     set(gp_regex_fallback "^[\t ]*([^\t ]+) => ([^\t ]+).*${eol_char}$")
735     set(gp_regex_cmp_count 1)
736   elseif(gp_tool MATCHES "otool$")
737     set(gp_cmd_args "-L")
738     set(gp_regex "^\t([^\t]+) \\(compatibility version ([0-9]+.[0-9]+.[0-9]+), current version ([0-9]+.[0-9]+.[0-9]+)\\)${eol_char}$")
739     set(gp_regex_error "")
740     set(gp_regex_fallback "")
741     set(gp_regex_cmp_count 3)
742   elseif(gp_tool MATCHES "dumpbin$")
743     set(gp_cmd_args "/dependents")
744     set(gp_regex "^    ([^ ].*[Dd][Ll][Ll])${eol_char}$")
745     set(gp_regex_error "")
746     set(gp_regex_fallback "")
747     set(gp_regex_cmp_count 1)
748   elseif(gp_tool MATCHES "objdump$")
749     set(gp_cmd_args "-p")
750     set(gp_regex "^\t*DLL Name: (.*\\.[Dd][Ll][Ll])${eol_char}$")
751     set(gp_regex_error "")
752     set(gp_regex_fallback "")
753     set(gp_regex_cmp_count 1)
754     # objdump generates copious output so we create a grep filter to pre-filter results
755     if(WIN32)
756       find_program(gp_grep_cmd findstr)
757     else()
758       find_program(gp_grep_cmd grep)
759     endif()
760     if(gp_grep_cmd)
761       set(gp_cmd_maybe_filter COMMAND ${gp_grep_cmd} "-a" "^[[:blank:]]*DLL Name: ")
762     endif()
763   else()
764     message(STATUS "warning: gp_tool='${gp_tool}' is an unknown tool...")
765     message(STATUS "CMake function get_prerequisites needs more code to handle '${gp_tool}'")
766     message(STATUS "Valid gp_tool values are dumpbin, ldd, objdump and otool.")
767     return()
768   endif()
769
770
771   if(gp_tool MATCHES "dumpbin$")
772     # When running dumpbin, it also needs the "Common7/IDE" directory in the
773     # PATH. It will already be in the PATH if being run from a Visual Studio
774     # command prompt. Add it to the PATH here in case we are running from a
775     # different command prompt.
776     #
777     get_filename_component(gp_cmd_dir "${gp_cmd}" PATH)
778     get_filename_component(gp_cmd_dlls_dir "${gp_cmd_dir}/../../Common7/IDE" ABSOLUTE)
779     # Use cmake paths as a user may have a PATH element ending with a backslash.
780     # This will escape the list delimiter and create havoc!
781     if(EXISTS "${gp_cmd_dlls_dir}")
782       # only add to the path if it is not already in the path
783       set(gp_found_cmd_dlls_dir 0)
784       file(TO_CMAKE_PATH "$ENV{PATH}" env_path)
785       foreach(gp_env_path_element ${env_path})
786         if(gp_env_path_element STREQUAL gp_cmd_dlls_dir)
787           set(gp_found_cmd_dlls_dir 1)
788         endif()
789       endforeach()
790
791       if(NOT gp_found_cmd_dlls_dir)
792         file(TO_NATIVE_PATH "${gp_cmd_dlls_dir}" gp_cmd_dlls_dir)
793         set(ENV{PATH} "$ENV{PATH};${gp_cmd_dlls_dir}")
794       endif()
795     endif()
796   endif()
797   #
798   # </setup-gp_tool-vars>
799
800   if(gp_tool MATCHES "ldd$")
801     set(old_ld_env "$ENV{LD_LIBRARY_PATH}")
802     set(new_ld_env "${exepath}")
803     foreach(dir ${dirs})
804       string(APPEND new_ld_env ":${dir}")
805     endforeach()
806     set(ENV{LD_LIBRARY_PATH} "${new_ld_env}:$ENV{LD_LIBRARY_PATH}")
807   endif()
808
809
810   # Track new prerequisites at each new level of recursion. Start with an
811   # empty list at each level:
812   #
813   set(unseen_prereqs)
814
815   # Run gp_cmd on the target:
816   #
817   execute_process(
818     COMMAND ${gp_cmd} ${gp_cmd_args} ${target}
819     ${gp_cmd_maybe_filter}
820     RESULT_VARIABLE gp_rv
821     OUTPUT_VARIABLE gp_cmd_ov
822     ERROR_VARIABLE gp_ev
823     )
824
825   if(gp_tool MATCHES "dumpbin$")
826     # Exclude delay load dependencies under windows (they are listed in dumpbin output after the message below)
827     string(FIND "${gp_cmd_ov}" "Image has the following delay load dependencies" gp_delayload_pos)
828     if (${gp_delayload_pos} GREATER -1)
829       string(SUBSTRING "${gp_cmd_ov}" 0 ${gp_delayload_pos} gp_cmd_ov_no_delayload_deps)
830       string(SUBSTRING "${gp_cmd_ov}" ${gp_delayload_pos} -1 gp_cmd_ov_delayload_deps)
831       if (verbose)
832         message(STATUS "GetPrequisites(${target}) : ignoring the following delay load dependencies :\n ${gp_cmd_ov_delayload_deps}")
833       endif()
834       set(gp_cmd_ov ${gp_cmd_ov_no_delayload_deps})
835     endif()
836   endif()
837
838   if(NOT gp_rv STREQUAL "0")
839     if(gp_tool MATCHES "dumpbin$")
840       # dumpbin error messages seem to go to stdout
841       message(FATAL_ERROR "${gp_cmd} failed: ${gp_rv}\n${gp_ev}\n${gp_cmd_ov}")
842     else()
843       message(FATAL_ERROR "${gp_cmd} failed: ${gp_rv}\n${gp_ev}")
844     endif()
845   endif()
846
847   if(gp_tool MATCHES "ldd$")
848     set(ENV{LD_LIBRARY_PATH} "${old_ld_env}")
849   endif()
850
851   if(verbose)
852     message(STATUS "<RawOutput cmd='${gp_cmd} ${gp_cmd_args} ${target}'>")
853     message(STATUS "gp_cmd_ov='${gp_cmd_ov}'")
854     message(STATUS "</RawOutput>")
855   endif()
856
857   get_filename_component(target_dir "${target}" PATH)
858
859   # Convert to a list of lines:
860   #
861   string(REPLACE ";" "\\;" candidates "${gp_cmd_ov}")
862   string(REPLACE "\n" "${eol_char};" candidates "${candidates}")
863
864   # check for install id and remove it from list, since otool -L can include a
865   # reference to itself
866   set(gp_install_id)
867   if(gp_tool MATCHES "otool$")
868     execute_process(
869       COMMAND ${gp_cmd} -D ${target}
870       RESULT_VARIABLE otool_rv
871       OUTPUT_VARIABLE gp_install_id_ov
872       ERROR_VARIABLE otool_ev
873       )
874     if(NOT otool_rv STREQUAL "0")
875       message(FATAL_ERROR "otool -D failed: ${otool_rv}\n${otool_ev}")
876     endif()
877     # second line is install name
878     string(REGEX REPLACE ".*:\n" "" gp_install_id "${gp_install_id_ov}")
879     if(gp_install_id)
880       # trim
881       string(REGEX MATCH "[^\n ].*[^\n ]" gp_install_id "${gp_install_id}")
882       #message("INSTALL ID is \"${gp_install_id}\"")
883     endif()
884   endif()
885
886   # Analyze each line for file names that match the regular expression:
887   #
888   foreach(candidate ${candidates})
889   if("${candidate}" MATCHES "${gp_regex}")
890
891     # Extract information from each candidate:
892     if(gp_regex_error AND "${candidate}" MATCHES "${gp_regex_error}")
893       string(REGEX REPLACE "${gp_regex_fallback}" "\\1" raw_item "${candidate}")
894     else()
895       string(REGEX REPLACE "${gp_regex}" "\\1" raw_item "${candidate}")
896     endif()
897
898     if(gp_regex_cmp_count GREATER 1)
899       string(REGEX REPLACE "${gp_regex}" "\\2" raw_compat_version "${candidate}")
900       string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\1" compat_major_version "${raw_compat_version}")
901       string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\2" compat_minor_version "${raw_compat_version}")
902       string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\3" compat_patch_version "${raw_compat_version}")
903     endif()
904
905     if(gp_regex_cmp_count GREATER 2)
906       string(REGEX REPLACE "${gp_regex}" "\\3" raw_current_version "${candidate}")
907       string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\1" current_major_version "${raw_current_version}")
908       string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\2" current_minor_version "${raw_current_version}")
909       string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\3" current_patch_version "${raw_current_version}")
910     endif()
911
912     # Use the raw_item as the list entries returned by this function. Use the
913     # gp_resolve_item function to resolve it to an actual full path file if
914     # necessary.
915     #
916     set(item "${raw_item}")
917
918     # Add each item unless it is excluded:
919     #
920     set(add_item 1)
921
922     if(item STREQUAL gp_install_id)
923       set(add_item 0)
924     endif()
925
926     if(add_item AND ${exclude_system})
927       set(type "")
928       gp_resolved_file_type("${target}" "${item}" "${exepath}" "${dirs}" type "${rpaths}")
929
930       if(type STREQUAL "system")
931         set(add_item 0)
932       endif()
933     endif()
934
935     if(add_item)
936       list(LENGTH ${prerequisites_var} list_length_before_append)
937       gp_append_unique(${prerequisites_var} "${item}")
938       list(LENGTH ${prerequisites_var} list_length_after_append)
939
940       if(${recurse})
941         # If item was really added, this is the first time we have seen it.
942         # Add it to unseen_prereqs so that we can recursively add *its*
943         # prerequisites...
944         #
945         # But first: resolve its name to an absolute full path name such
946         # that the analysis tools can simply accept it as input.
947         #
948         if(NOT list_length_before_append EQUAL list_length_after_append)
949           gp_resolve_item("${target}" "${item}" "${exepath}" "${dirs}" resolved_item "${rpaths}")
950           if(EXISTS "${resolved_item}")
951             # Recurse only if we could resolve the item.
952             # Otherwise the prerequisites_var list will be cleared
953             set(unseen_prereqs ${unseen_prereqs} "${resolved_item}")
954           endif()
955         endif()
956       endif()
957     endif()
958   else()
959     if(verbose)
960       message(STATUS "ignoring non-matching line: '${candidate}'")
961     endif()
962   endif()
963   endforeach()
964
965   list(LENGTH ${prerequisites_var} prerequisites_var_length)
966   if(prerequisites_var_length GREATER 0)
967     list(SORT ${prerequisites_var})
968   endif()
969   if(${recurse})
970     set(more_inputs ${unseen_prereqs})
971     foreach(input ${more_inputs})
972       get_prerequisites("${input}" ${prerequisites_var} ${exclude_system} ${recurse} "${exepath}" "${dirs}" "${rpaths}")
973     endforeach()
974   endif()
975
976   set(${prerequisites_var} ${${prerequisites_var}} PARENT_SCOPE)
977 endfunction()
978
979
980 function(list_prerequisites target)
981   if(ARGC GREATER 1 AND NOT "${ARGV1}" STREQUAL "")
982     set(all "${ARGV1}")
983   else()
984     set(all 1)
985   endif()
986
987   if(ARGC GREATER 2 AND NOT "${ARGV2}" STREQUAL "")
988     set(exclude_system "${ARGV2}")
989   else()
990     set(exclude_system 0)
991   endif()
992
993   if(ARGC GREATER 3 AND NOT "${ARGV3}" STREQUAL "")
994     set(verbose "${ARGV3}")
995   else()
996     set(verbose 0)
997   endif()
998
999   set(count 0)
1000   set(count_str "")
1001   set(print_count "${verbose}")
1002   set(print_prerequisite_type "${verbose}")
1003   set(print_target "${verbose}")
1004   set(type_str "")
1005
1006   get_filename_component(exepath "${target}" PATH)
1007
1008   set(prereqs "")
1009   get_prerequisites("${target}" prereqs ${exclude_system} ${all} "${exepath}" "")
1010
1011   if(print_target)
1012     message(STATUS "File '${target}' depends on:")
1013   endif()
1014
1015   foreach(d ${prereqs})
1016     math(EXPR count "${count} + 1")
1017
1018     if(print_count)
1019       set(count_str "${count}. ")
1020     endif()
1021
1022     if(print_prerequisite_type)
1023       gp_file_type("${target}" "${d}" type)
1024       set(type_str " (${type})")
1025     endif()
1026
1027     message(STATUS "${count_str}${d}${type_str}")
1028   endforeach()
1029 endfunction()
1030
1031
1032 function(list_prerequisites_by_glob glob_arg glob_exp)
1033   message(STATUS "=============================================================================")
1034   message(STATUS "List prerequisites of executables matching ${glob_arg} '${glob_exp}'")
1035   message(STATUS "")
1036   file(${glob_arg} file_list ${glob_exp})
1037   foreach(f ${file_list})
1038     is_file_executable("${f}" is_f_executable)
1039     if(is_f_executable)
1040       message(STATUS "=============================================================================")
1041       list_prerequisites("${f}" ${ARGN})
1042       message(STATUS "")
1043     endif()
1044   endforeach()
1045 endfunction()
1046
1047 cmake_policy(POP)