getprerequisites.cmake

来自「编译器」· CMAKE 代码 · 共 493 行 · 第 1/2 页

CMAKE
493
字号
# GetPrerequisites.cmake
#
# This script provides functions to list the .dll, .dylib or .so files that an
# executable or shared library file depends on. (Its prerequisites.)
#
# It uses various tools to obtain the list of required shared library files:
#   dumpbin (Windows)
#   ldd (Linux/Unix)
#   otool (Mac OSX)
#
# The following functions are provided by this script:
#   gp_append_unique
#   gp_file_type
#   is_file_executable
#   get_prerequisites
#   list_prerequisites
#
# Requires CMake 2.5 or greater because it uses function, break, return and
# PARENT_SCOPE.
#
cmake_minimum_required(VERSION 2.5 FATAL_ERROR)


# gp_append_unique list_var value
#
# Append value to the list variable ${list_var} only if the value is not
# already in the list.
#
function(gp_append_unique list_var value)
  set(contains 0)

  foreach(item ${${list_var}})
    if("${item}" STREQUAL "${value}")
      set(contains 1)
      break()
    endif("${item}" STREQUAL "${value}")
  endforeach(item)

  if(NOT contains)
    set(${list_var} ${${list_var}} "${value}" PARENT_SCOPE)
  endif(NOT contains)
endfunction(gp_append_unique)


# gp_file_type original_file file type_var
#
# Return the type of ${file} with respect to ${original_file}. String
# describing type of prerequisite is returned in variable named ${type_var}.
#
# Possible types are:
#   system
#   local
#   embedded
#   other
#
function(gp_file_type original_file file type_var)
  set(is_embedded 0)
  set(is_local 0)
  set(is_system 0)

  string(TOLOWER "${original_file}" original_lower)
  string(TOLOWER "${file}" lower)

  if("${file}" MATCHES "^@(executable|loader)_path")
    set(is_embedded 1)
  endif("${file}" MATCHES "^@(executable|loader)_path")

  if(NOT is_embedded)
    if("${file}" MATCHES "^(/System/Library/|/usr/lib/)")
      set(is_system 1)
    endif("${file}" MATCHES "^(/System/Library/|/usr/lib/)")

    if(WIN32)
      string(TOLOWER "$ENV{SystemRoot}" sysroot)
      string(REGEX REPLACE "\\\\" "/" sysroot "${sysroot}")

      string(TOLOWER "$ENV{windir}" windir)
      string(REGEX REPLACE "\\\\" "/" windir "${windir}")

      if("${lower}" MATCHES "^(${sysroot}/system|${windir}/system|msvc[^/]+dll)")
        set(is_system 1)
      endif("${lower}" MATCHES "^(${sysroot}/system|${windir}/system|msvc[^/]+dll)")
    endif(WIN32)

    if(NOT is_system)
      get_filename_component(original_path "${original_lower}" PATH)
      get_filename_component(path "${lower}" PATH)
      if("${original_path}" STREQUAL "${path}")
        set(is_local 1)
      endif("${original_path}" STREQUAL "${path}")
    endif(NOT is_system)
  endif(NOT is_embedded)

  # Return type string based on computed booleans:
  #
  set(type "other")

  if(is_system)
    set(type "system")
  else(is_system)
    if(is_embedded)
      set(type "embedded")
    else(is_embedded)
      if(is_local)
        set(type "local")
      endif(is_local)
    endif(is_embedded)
  endif(is_system)

  set(${type_var} "${type}" PARENT_SCOPE)
endfunction(gp_file_type)


# is_file_executable file result_var
#
# Return 1 in ${result_var} if ${file} is a binary executable.
#
# Return 0 in ${result_var} otherwise.
#
function(is_file_executable file result_var)
  #
  # A file is not executable until proven otherwise:
  #
  set(${result_var} 0 PARENT_SCOPE)

  get_filename_component(file_full "${file}" ABSOLUTE)
  string(TOLOWER "${file_full}" file_full_lower)

  # If file name ends in .exe or .dll on Windows, *assume* executable:
  #
  if(WIN32)
    if("${file_full_lower}" MATCHES "\\.(exe|dll)$")
      set(${result_var} 1 PARENT_SCOPE)
      return()
    endif("${file_full_lower}" MATCHES "\\.(exe|dll)$")

    # A clause could be added here that uses output or return value of dumpbin
    # to determine ${result_var}. In 95%+ practical cases, the exe|dll name
    # match will be sufficient...
    #
  endif(WIN32)

  # Use the information returned from the Unix shell command "file" to
  # determine if ${file_full} should be considered an executable file...
  #
  # If the file command's output contains "executable" and does *not* contain
  # "text" then it is likely an executable suitable for prerequisite analysis
  # via the get_prerequisites macro.
  #
  if(UNIX)
    if(NOT file_cmd)
      find_program(file_cmd "file")
    endif(NOT file_cmd)

    if(file_cmd)
      execute_process(COMMAND "${file_cmd}" "${file_full}"
        OUTPUT_VARIABLE file_ov
        OUTPUT_STRIP_TRAILING_WHITESPACE
        )

      # Replace the name of the file in the output with a placeholder token
      # (the string " _file_full_ ") so that just in case the path name of
      # the file contains the word "text" or "executable" we are not fooled
      # into thinking "the wrong thing" because the file name matches the
      # other 'file' command output we are looking for...
      #
      string(REPLACE "${file_full}" " _file_full_ " file_ov "${file_ov}")
      string(TOLOWER "${file_ov}" file_ov)

      #message(STATUS "file_ov='${file_ov}'")
      if("${file_ov}" MATCHES "executable")
        #message(STATUS "executable!")
        if("${file_ov}" MATCHES "text")
          #message(STATUS "but text, so *not* a binary executable!")
        else("${file_ov}" MATCHES "text")
          set(${result_var} 1 PARENT_SCOPE)
          return()
        endif("${file_ov}" MATCHES "text")
      endif("${file_ov}" MATCHES "executable")
    else(file_cmd)
      message(STATUS "warning: No 'file' command, skipping execute_process...")
    endif(file_cmd)
  endif(UNIX)
endfunction(is_file_executable)


# get_prerequisites target prerequisites_var exclude_system recurse
#
# Get the list of shared library files required by ${target}. The list in
# the variable named ${prerequisites_var} should be empty on first entry to
# this function. On exit, ${prerequisites_var} will contain the list of
# required shared library files.
#
#  target is the full path to an executable file
#
#  prerequisites_var is the name of a CMake variable to contain the results
#
#  exclude_system is 0 or 1: 0 to include "system" prerequisites , 1 to
#   exclude them
#
#  recurse is 0 or 1: 0 for direct prerequisites only, 1 for all prerequisites
#   recursively
#
#  optional ARGV4 (verbose) is 0 or 1: 0 to skip informational message output,
#   1 to print it
#
function(get_prerequisites target prerequisites_var exclude_system recurse)
#  set(verbose 0)
#  if(NOT "${ARGV4}" STREQUAL "")
#    message(STATUS "ARGV4='${ARGV4}'")
#    set(verbose "${ARGV4}")
#  endif(NOT "${ARGV4}" STREQUAL "")
#  message(STATUS "verbose='${verbose}'")
  set(verbose 0)

  set(eol_char "E")

  # <setup-gp_tool-vars>
  #
  # Try to choose the right tool by default. Caller can set gp_tool prior to
  # calling this function to force using a different tool.
  #
  if("${gp_tool}" STREQUAL "")
    set(gp_tool "ldd")
    if(APPLE)
      set(gp_tool "otool")
    endif(APPLE)
    if(WIN32)
      set(gp_tool "dumpbin")
    endif(WIN32)
  endif("${gp_tool}" STREQUAL "")

  set(gp_tool_known 0)

  if("${gp_tool}" STREQUAL "ldd")
    set(gp_cmd_args "")
    set(gp_regex "^\t([\t ]+)[\t ].*${eol_char}$")
    set(gp_regex_cmp_count 1)
    set(gp_tool_known 1)
  endif("${gp_tool}" STREQUAL "ldd")

  if("${gp_tool}" STREQUAL "otool")
    set(gp_cmd_args "-L")
    set(gp_regex "^\t([^\t]+) \\(compatibility version ([0-9]+.[0-9]+.[0-9]+), current version ([0-9]+.[0-9]+.[0-9]+)\\)${eol_char}$")
    set(gp_regex_cmp_count 3)
    set(gp_tool_known 1)
  endif("${gp_tool}" STREQUAL "otool")

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?