1 # Distributed under the OSI-approved BSD 3-Clause License. See accompanying
2 # file Copyright.txt or https://cmake.org/licensing for details.
4 #[=======================================================================[.rst:
10 Use :command:`file(GET_RUNTIME_DEPENDENCIES)` instead.
12 Functions to analyze and list executable file prerequisites.
14 This module provides functions to list the .dll, .dylib or .so files
15 that an executable or shared library file depends on. (Its
18 It uses various tools to obtain the list of required shared library
24 objdump (MinGW on Windows)
28 The following functions are provided by this module:
34 list_prerequisites_by_glob
37 gp_item_default_embedded_path
38 (projects can override with gp_item_default_embedded_path_override)
40 (projects can override with gp_resolve_item_override)
42 (projects can override with gp_resolved_file_type_override)
45 Requires CMake 2.6 or greater because it uses function, break, return
50 GET_PREREQUISITES(<target> <prerequisites_var> <exclude_system> <recurse>
51 <exepath> <dirs> [<rpaths>])
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.
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...
70 The variable GET_PREREQUISITES_VERBOSE can be set to true to enable verbose
75 LIST_PREREQUISITES(<target> [<recurse> [<exclude_system> [<verbose>]]])
77 Print a message listing the prerequisites of <target>.
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.
89 LIST_PREREQUISITES_BY_GLOB(<glob_arg> <glob_exp>)
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.
97 Any additional (optional) arguments provided are passed along as the
98 optional arguments to the list_prerequisites calls.
102 GP_APPEND_UNIQUE(<list_var> <value>)
104 Append <value> to the list variable <list_var> only if the value is
105 not already in the list.
109 IS_FILE_EXECUTABLE(<file> <result_var>)
111 Return 1 in <result_var> if <file> is a binary executable, 0
116 GP_ITEM_DEFAULT_EMBEDDED_PATH(<item> <default_embedded_path_var>)
118 Return the path that others should refer to the item by when the item
119 is embedded inside a bundle.
121 Override on a per-project basis by providing a project-specific
122 gp_item_default_embedded_path_override function.
126 GP_RESOLVE_ITEM(<context> <item> <exepath> <dirs> <resolved_item_var>
129 Resolve an item into an existing full path file.
131 Override on a per-project basis by providing a project-specific
132 gp_resolve_item_override function.
136 GP_RESOLVED_FILE_TYPE(<original_file> <file> <exepath> <dirs> <type_var>
139 Return the type of <file> with respect to <original_file>. String
140 describing type of prerequisite is returned in variable named
143 Use <exepath> and <dirs> if necessary to resolve non-absolute <file>
144 values -- but only for non-embedded items.
155 Override on a per-project basis by providing a project-specific
156 gp_resolved_file_type_override function.
160 GP_FILE_TYPE(<original_file> <file> <type_var>)
162 Return the type of <file> with respect to <original_file>. String
163 describing type of prerequisite is returned in variable named
174 #]=======================================================================]
177 cmake_policy(SET CMP0057 NEW) # if IN_LIST
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)
186 function(is_file_executable file result_var)
188 # A file is not executable until proven otherwise:
190 set(${result_var} 0 PARENT_SCOPE)
192 get_filename_component(file_full "${file}" ABSOLUTE)
193 string(TOLOWER "${file_full}" file_full_lower)
195 # If file name ends in .exe on Windows, *assume* executable:
197 if(WIN32 AND NOT UNIX)
198 if("${file_full_lower}" MATCHES "\\.exe$")
199 set(${result_var} 1 PARENT_SCOPE)
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...
209 # Use the information returned from the Unix shell command "file" to
210 # determine if ${file_full} should be considered an executable file...
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.
218 find_program(file_cmd "file")
219 mark_as_advanced(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
229 if(NOT file_rv STREQUAL "0")
230 message(FATAL_ERROR "${file_cmd} failed: ${file_rv}\n${file_ev}")
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...
239 string(REPLACE "${file_full}" " _file_full_ " file_ov "${file_ov}")
240 string(TOLOWER "${file_ov}" file_ov)
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!")
248 set(${result_var} 1 PARENT_SCOPE)
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)
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)
268 message(STATUS "warning: No 'file' command, skipping execute_process...")
274 function(gp_item_default_embedded_path item default_embedded_path_var)
276 # On Windows and Linux, "embed" prerequisites in the same directory
277 # as the executable by default:
279 set(path "@executable_path")
281 # On the Mac, relative to the executable depending on the type
282 # of the thing we are embedding:
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.
294 # By default, embed things right next to the main bundle executable:
296 set(path "@executable_path/../../Contents/MacOS")
298 # Embed frameworks and .dylibs in the embedded "Frameworks" directory
299 # (sibling of MacOS):
301 if(item MATCHES "[^/]+\\.framework/" OR item MATCHES "\\.dylib$")
302 set(path "@executable_path/../Frameworks")
306 # Provide a hook so that projects can override the default embedded location
307 # of any given library by whatever logic they choose:
309 if(COMMAND gp_item_default_embedded_path_override)
310 gp_item_default_embedded_path_override("${item}" path)
313 set(${default_embedded_path_var} "${path}" PARENT_SCOPE)
317 function(gp_resolve_item context item exepath dirs resolved_item_var)
319 set(resolved_item "${item}")
321 set(rpaths "${ARGV5}")
326 # Is it already resolved?
328 if(IS_ABSOLUTE "${resolved_item}" AND EXISTS "${resolved_item}")
333 if(item MATCHES "^@executable_path")
335 # @executable_path references are assumed relative to exepath
337 string(REPLACE "@executable_path" "${exepath}" ri "${item}")
338 get_filename_component(ri "${ri}" ABSOLUTE)
341 #message(STATUS "info: embedded item exists (${ri})")
343 set(resolved_item "${ri}")
345 message(STATUS "warning: embedded item does not exist '${ri}'")
351 if(item MATCHES "^@loader_path")
353 # @loader_path references are assumed relative to the
354 # PATH of the given "context" (presumably another library)
356 get_filename_component(contextpath "${context}" PATH)
357 string(REPLACE "@loader_path" "${contextpath}" ri "${item}")
358 get_filename_component(ri "${ri}" ABSOLUTE)
361 #message(STATUS "info: embedded item exists (${ri})")
363 set(resolved_item "${ri}")
365 message(STATUS "warning: embedded item does not exist '${ri}'")
371 if(item MATCHES "^@rpath")
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
376 string(REPLACE "@rpath/" "" norpath_item "${item}")
378 set(ri "ri-NOTFOUND")
379 find_file(ri "${norpath_item}" ${exepath} ${dirs} ${rpaths} NO_DEFAULT_PATH)
381 #message(STATUS "info: 'find_file' in exepath/dirs/rpaths (${ri})")
383 set(resolved_item "${ri}")
384 set(ri "ri-NOTFOUND")
391 set(ri "ri-NOTFOUND")
392 find_file(ri "${item}" ${exepath} ${dirs} NO_DEFAULT_PATH)
393 find_file(ri "${item}" ${exepath} ${dirs} /usr/lib)
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)
400 #message(STATUS "info: 'find_file' in exepath/dirs (${ri})")
402 set(resolved_item "${ri}")
403 set(ri "ri-NOTFOUND")
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"
416 #message(STATUS "info: 'find_file' found framework (${fw})")
418 set(resolved_item "${fw}")
419 set(fw "fw-NOTFOUND")
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.)
427 if(WIN32 AND NOT UNIX)
429 set(ri "ri-NOTFOUND")
430 find_program(ri "${item}" PATHS ${exepath} ${dirs} NO_DEFAULT_PATH)
431 find_program(ri "${item}" PATHS ${exepath} ${dirs})
433 #message(STATUS "info: 'find_program' in exepath/dirs (${ri})")
435 set(resolved_item "${ri}")
436 set(ri "ri-NOTFOUND")
441 # Provide a hook so that projects can override item resolution
442 # by whatever logic they choose:
444 if(COMMAND gp_resolve_item_override)
445 gp_resolve_item_override("${context}" "${item}" "${exepath}" "${dirs}" resolved_item resolved)
450 warning: cannot resolve item '${item}'
453 need more directories?
454 need to use InstallRequiredSystemLibraries?
455 run in install tree instead of build tree?
458 #******************************************************************************
459 #warning: cannot resolve item '${item}'
462 # need more directories?
463 # need to use InstallRequiredSystemLibraries?
464 # run in install tree instead of build tree?
466 # context='${context}'
468 # exepath='${exepath}'
470 # resolved_item_var='${resolved_item_var}'
471 #******************************************************************************
475 set(${resolved_item_var} "${resolved_item}" PARENT_SCOPE)
479 function(gp_resolved_file_type original_file file exepath dirs type_var)
481 set(rpaths "${ARGV5}")
485 #message(STATUS "**")
487 if(NOT IS_ABSOLUTE "${original_file}")
488 message(STATUS "warning: gp_resolved_file_type expects absolute full path for first arg original_file")
490 if(IS_ABSOLUTE "${original_file}")
491 get_filename_component(original_file "${original_file}" ABSOLUTE) # canonicalize path
498 set(resolved_file "${file}")
500 if("${file}" MATCHES "^@(executable|loader)_path")
505 if(NOT IS_ABSOLUTE "${file}")
506 gp_resolve_item("${original_file}" "${file}" "${exepath}" "${dirs}" resolved_file "${rpaths}")
508 if(IS_ABSOLUTE "${resolved_file}")
509 get_filename_component(resolved_file "${resolved_file}" ABSOLUTE) # canonicalize path
512 string(TOLOWER "${original_file}" original_lower)
513 string(TOLOWER "${resolved_file}" lower)
516 if(resolved_file MATCHES "^(/lib/|/lib32/|/libx32/|/lib64/|/usr/lib/|/usr/lib32/|/usr/libx32/|/usr/lib64/|/usr/X11R6/|/usr/bin/)")
522 if(resolved_file MATCHES "^(/System/Library/|/usr/lib/)")
528 string(TOLOWER "$ENV{SystemRoot}" sysroot)
529 file(TO_CMAKE_PATH "${sysroot}" sysroot)
531 string(TOLOWER "$ENV{windir}" windir)
532 file(TO_CMAKE_PATH "${windir}" windir)
534 if(lower MATCHES "^(${sysroot}/sys(tem|wow)|${windir}/sys(tem|wow)|(.*/)*(msvc|api-ms-win-|vcruntime)[^/]+dll)")
539 # if cygwin, we can get the properly formed windows paths from cygpath
540 find_program(CYGPATH_EXECUTABLE cygpath)
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}")
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}")
559 string(TOLOWER "${env_windir}" windir)
560 string(TOLOWER "${env_sysdir}" sysroot)
562 if(lower MATCHES "^(${sysroot}/sys(tem|wow)|${windir}/sys(tem|wow)|(.*/)*(msvc|api-ms-win-|vcruntime)[^/]+dll)")
570 get_filename_component(original_path "${original_lower}" PATH)
571 get_filename_component(path "${lower}" PATH)
572 if(original_path STREQUAL path)
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)
587 # Return type string based on computed booleans:
599 #message(STATUS "gp_resolved_file_type: '${file}' '${resolved_file}'")
600 #message(STATUS " type: '${type}'")
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}'")
607 message(STATUS "warning: gp_resolved_file_type non-absolute file '${file}' returning type '${type}' -- possibly incorrect")
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:
615 if(COMMAND gp_resolved_file_type_override)
616 gp_resolved_file_type_override("${resolved_file}" type)
619 set(${type_var} "${type}" PARENT_SCOPE)
621 #message(STATUS "**")
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")
630 get_filename_component(exepath "${original_file}" PATH)
633 gp_resolved_file_type("${original_file}" "${file}" "${exepath}" "" type)
635 set(${type_var} "${type}" PARENT_SCOPE)
639 function(get_prerequisites target prerequisites_var exclude_system recurse exepath dirs)
643 set(rpaths "${ARGV6}")
648 if(GET_PREREQUISITES_VERBOSE)
652 if(NOT IS_ABSOLUTE "${target}")
653 message("warning: target '${target}' is not absolute...")
656 if(NOT EXISTS "${target}")
657 message("warning: target '${target}' does not exist...")
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")
666 set(${prerequisites_var} "" PARENT_SCOPE)
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"
697 # <setup-gp_tool-vars>
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.
709 if(WIN32 AND NOT UNIX) # This is how to check for cygwin, har!
710 find_program(gp_dumpbin "dumpbin" PATHS ${gp_cmd_paths})
712 set(gp_tool "dumpbin")
713 elseif(CMAKE_OBJDUMP) # Try harder. Maybe we're on MinGW
714 set(gp_tool "${CMAKE_OBJDUMP}")
716 set(gp_tool "objdump")
721 find_program(gp_cmd ${gp_tool} PATHS ${gp_cmd_paths})
724 message(STATUS "warning: could not find '${gp_tool}' - cannot analyze prerequisites...")
728 set(gp_cmd_maybe_filter) # optional command to pre-filter gp_tool results
730 if(gp_tool MATCHES "ldd$")
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
756 find_program(gp_grep_cmd findstr)
758 find_program(gp_grep_cmd grep)
761 set(gp_cmd_maybe_filter COMMAND ${gp_grep_cmd} "-a" "^[[:blank:]]*DLL Name: ")
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.")
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.
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)
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}")
798 # </setup-gp_tool-vars>
800 if(gp_tool MATCHES "ldd$")
801 set(old_ld_env "$ENV{LD_LIBRARY_PATH}")
802 set(new_ld_env "${exepath}")
804 string(APPEND new_ld_env ":${dir}")
806 set(ENV{LD_LIBRARY_PATH} "${new_ld_env}:$ENV{LD_LIBRARY_PATH}")
810 # Track new prerequisites at each new level of recursion. Start with an
811 # empty list at each level:
815 # Run gp_cmd on the target:
818 COMMAND ${gp_cmd} ${gp_cmd_args} ${target}
819 ${gp_cmd_maybe_filter}
820 RESULT_VARIABLE gp_rv
821 OUTPUT_VARIABLE gp_cmd_ov
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)
832 message(STATUS "GetPrequisites(${target}) : ignoring the following delay load dependencies :\n ${gp_cmd_ov_delayload_deps}")
834 set(gp_cmd_ov ${gp_cmd_ov_no_delayload_deps})
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}")
843 message(FATAL_ERROR "${gp_cmd} failed: ${gp_rv}\n${gp_ev}")
847 if(gp_tool MATCHES "ldd$")
848 set(ENV{LD_LIBRARY_PATH} "${old_ld_env}")
852 message(STATUS "<RawOutput cmd='${gp_cmd} ${gp_cmd_args} ${target}'>")
853 message(STATUS "gp_cmd_ov='${gp_cmd_ov}'")
854 message(STATUS "</RawOutput>")
857 get_filename_component(target_dir "${target}" PATH)
859 # Convert to a list of lines:
861 string(REPLACE ";" "\\;" candidates "${gp_cmd_ov}")
862 string(REPLACE "\n" "${eol_char};" candidates "${candidates}")
864 # check for install id and remove it from list, since otool -L can include a
865 # reference to itself
867 if(gp_tool MATCHES "otool$")
869 COMMAND ${gp_cmd} -D ${target}
870 RESULT_VARIABLE otool_rv
871 OUTPUT_VARIABLE gp_install_id_ov
872 ERROR_VARIABLE otool_ev
874 if(NOT otool_rv STREQUAL "0")
875 message(FATAL_ERROR "otool -D failed: ${otool_rv}\n${otool_ev}")
877 # second line is install name
878 string(REGEX REPLACE ".*:\n" "" gp_install_id "${gp_install_id_ov}")
881 string(REGEX MATCH "[^\n ].*[^\n ]" gp_install_id "${gp_install_id}")
882 #message("INSTALL ID is \"${gp_install_id}\"")
886 # Analyze each line for file names that match the regular expression:
888 foreach(candidate ${candidates})
889 if("${candidate}" MATCHES "${gp_regex}")
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}")
895 string(REGEX REPLACE "${gp_regex}" "\\1" raw_item "${candidate}")
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}")
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}")
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
916 set(item "${raw_item}")
918 # Add each item unless it is excluded:
922 if(item STREQUAL gp_install_id)
926 if(add_item AND ${exclude_system})
928 gp_resolved_file_type("${target}" "${item}" "${exepath}" "${dirs}" type "${rpaths}")
930 if(type STREQUAL "system")
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)
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*
945 # But first: resolve its name to an absolute full path name such
946 # that the analysis tools can simply accept it as input.
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}")
960 message(STATUS "ignoring non-matching line: '${candidate}'")
965 list(LENGTH ${prerequisites_var} prerequisites_var_length)
966 if(prerequisites_var_length GREATER 0)
967 list(SORT ${prerequisites_var})
970 set(more_inputs ${unseen_prereqs})
971 foreach(input ${more_inputs})
972 get_prerequisites("${input}" ${prerequisites_var} ${exclude_system} ${recurse} "${exepath}" "${dirs}" "${rpaths}")
976 set(${prerequisites_var} ${${prerequisites_var}} PARENT_SCOPE)
980 function(list_prerequisites target)
981 if(ARGC GREATER 1 AND NOT "${ARGV1}" STREQUAL "")
987 if(ARGC GREATER 2 AND NOT "${ARGV2}" STREQUAL "")
988 set(exclude_system "${ARGV2}")
990 set(exclude_system 0)
993 if(ARGC GREATER 3 AND NOT "${ARGV3}" STREQUAL "")
994 set(verbose "${ARGV3}")
1001 set(print_count "${verbose}")
1002 set(print_prerequisite_type "${verbose}")
1003 set(print_target "${verbose}")
1006 get_filename_component(exepath "${target}" PATH)
1009 get_prerequisites("${target}" prereqs ${exclude_system} ${all} "${exepath}" "")
1012 message(STATUS "File '${target}' depends on:")
1015 foreach(d ${prereqs})
1016 math(EXPR count "${count} + 1")
1019 set(count_str "${count}. ")
1022 if(print_prerequisite_type)
1023 gp_file_type("${target}" "${d}" type)
1024 set(type_str " (${type})")
1027 message(STATUS "${count_str}${d}${type_str}")
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}'")
1036 file(${glob_arg} file_list ${glob_exp})
1037 foreach(f ${file_list})
1038 is_file_executable("${f}" is_f_executable)
1040 message(STATUS "=============================================================================")
1041 list_prerequisites("${f}" ${ARGN})