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