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