Merge branch 'release-3.15'
diff --git a/Help/command/add_test.rst b/Help/command/add_test.rst
index 46b9b63..884b2ee 100644
--- a/Help/command/add_test.rst
+++ b/Help/command/add_test.rst
@@ -7,7 +7,8 @@
add_test(NAME <name> COMMAND <command> [<arg>...]
[CONFIGURATIONS <config>...]
- [WORKING_DIRECTORY <dir>])
+ [WORKING_DIRECTORY <dir>]
+ [COMMAND_EXPAND_LISTS])
Adds a test called ``<name>``. The test name may not contain spaces,
quotes, or other characters special in CMake syntax. The options are:
@@ -28,6 +29,11 @@
directory set to the build directory corresponding to the
current source directory.
+``COMMAND_EXPAND_LISTS``
+ Lists in ``COMMAND`` arguments will be expanded, including those
+ created with
+ :manual:`generator expressions <cmake-generator-expressions(7)>`.
+
The given test command is expected to exit with code ``0`` to pass and
non-zero to fail, or vice-versa if the :prop_test:`WILL_FAIL` test
property is set. Any output written to stdout or stderr will be
diff --git a/Help/command/file.rst b/Help/command/file.rst
index f99021e..666a532 100644
--- a/Help/command/file.rst
+++ b/Help/command/file.rst
@@ -13,6 +13,7 @@
file(`STRINGS`_ <filename> <out-var> [...])
file(`\<HASH\> <HASH_>`_ <filename> <out-var>)
file(`TIMESTAMP`_ <filename> <out-var> [...])
+ file(`GET_RUNTIME_DEPENDENCIES`_ [...])
`Writing`_
file({`WRITE`_ | `APPEND`_} <filename> <content>...)
@@ -130,6 +131,273 @@
See the :command:`string(TIMESTAMP)` command for documentation of
the ``<format>`` and ``UTC`` options.
+.. _GET_RUNTIME_DEPENDENCIES:
+
+.. code-block:: cmake
+
+ file(GET_RUNTIME_DEPENDENCIES
+ [RESOLVED_DEPENDENCIES_VAR <deps_var>]
+ [UNRESOLVED_DEPENDENCIES_VAR <unresolved_deps_var>]
+ [CONFLICTING_DEPENDENICES_PREFIX <conflicting_deps_prefix>]
+ [EXECUTABLES [<executable_files>...]]
+ [LIBRARIES [<library_files>...]]
+ [MODULES [<module_files>...]]
+ [DIRECTORIES [<directories>...]]
+ [BUNDLE_EXECUTABLE <bundle_executable_file>]
+ [PRE_INCLUDE_REGEXES [<regexes>...]]
+ [PRE_EXCLUDE_REGEXES [<regexes>...]]
+ [POST_INCLUDE_REGEXES [<regexes>...]]
+ [POST_EXCLUDE_REGEXES [<regexes>...]]
+ )
+
+Recursively get the list of libraries depended on by the given files.
+
+Please note that this sub-command is not intended to be used in project mode.
+Instead, use it in an :command:`install(CODE)` or :command:`install(SCRIPT)`
+block. For example:
+
+.. code-block:: cmake
+
+ install(CODE [[
+ file(GET_RUNTIME_DEPENDENCIES
+ # ...
+ )
+ ]])
+
+The arguments are as follows:
+
+``RESOLVED_DEPENDENCIES_VAR <deps_var>``
+ Name of the variable in which to store the list of resolved dependencies.
+
+``UNRESOLVED_DEPENDENCIES_VAR <unresolved_deps_var>``
+ Name of the variable in which to store the list of unresolved dependencies.
+ If this variable is not specified, and there are any unresolved dependencies,
+ an error is issued.
+
+``CONFLICTING_DEPENDENCIES_PREFIX <conflicting_deps_prefix>``
+ Variable prefix in which to store conflicting dependency information.
+ Dependencies are conflicting if two files with the same name are found in
+ two different directories. The list of filenames that conflict are stored in
+ ``<conflicting_deps_prefix>_FILENAMES``. For each filename, the list of paths
+ that were found for that filename are stored in
+ ``<conflicting_deps_prefix>_<filename>``.
+
+``EXECUTABLES <executable_files>``
+ List of executable files to read for dependencies. These are executables that
+ are typically created with :command:`add_executable`, but they do not have to
+ be created by CMake. On Apple platforms, the paths to these files determine
+ the value of ``@executable_path`` when recursively resolving the libraries.
+ Specifying ``STATIC`` libraries, ``MODULE`` s, or ``SHARED`` libraries here
+ will result in undefined behavior.
+
+``LIBRARIES <library_files>``
+ List of library files to read for dependencies. These are libraries that are
+ typically created with :command:`add_library(SHARED)`, but they do not have
+ to be created by CMake. Specifying ``STATIC`` libraries, ``MODULE`` s, or
+ executables here will result in undefined behavior.
+
+``MODULES <module_files>``
+ List of loadable module files to read for dependencies. These are modules
+ that are typically created with :command:`add_library(MODULE)`, but they do
+ not have to be created by CMake. They are typically used by calling
+ ``dlopen()`` at runtime rather than linked at link time with ``ld -l``.
+ Specifying ``STATIC`` libraries, ``SHARED`` libraries, or executables here
+ will result in undefined behavior.
+
+``DIRECTORIES <directories>``
+ List of additional directories to search for dependencies. On Linux
+ platforms, these directories are searched if the dependency is not found in
+ any of the other usual paths. If it is found in such a directory, a warning
+ is issued, because it means that the file is incomplete (it does not list all
+ of the directories that contain its dependencies.) On Windows platforms,
+ these directories are searched if the dependency is not found in any of the
+ other search paths, but no warning is issued, because searching other paths
+ is a normal part of Windows dependency resolution. On Apple platforms, this
+ argument has no effect.
+
+``BUNDLE_EXECTUBLE <bundle_executable_file>``
+ Executable to treat as the "bundle executable" when resolving libraries. On
+ Apple platforms, this argument determines the value of ``@executable_path``
+ when recursively resolving libraries for ``LIBRARIES`` and ``MODULES`` files.
+ It has no effect on ``EXECUTABLES`` files. On other platforms, it has no
+ effect. This is typically (but not always) one of the executables in the
+ ``EXECUTABLES`` argument which designates the "main" executable of the
+ package.
+
+The following arguments specify filters for including or excluding libraries to
+be resolved. See below for a full description of how they work.
+
+``PRE_INCLUDE_REGEXES <regexes>``
+ List of pre-include regexes through which to filter the names of
+ not-yet-resolved dependencies.
+
+``PRE_EXCLUDE_REGEXES <regexes>``
+ List of pre-exclude regexes through which to filter the names of
+ not-yet-resolved dependencies.
+
+``POST_INCLUDE_REGEXES <regexes>``
+ List of post-include regexes through which to filter the names of resolved
+ dependencies.
+
+``POST_EXCLUDE_REGEXES <regexes>``
+ List of post-exclude regexes through which to filter the names of resolved
+ dependencies.
+
+These arguments can be used to blacklist unwanted system libraries when
+resolving the dependencies, or to whitelist libraries from a specific
+directory. The filtering works as follows:
+
+1. If the not-yet-resolved dependency matches any of the
+ ``PRE_INCLUDE_REGEXES``, steps 2 and 3 are skipped, and the dependency
+ resolution proceeds to step 4.
+2. If the not-yet-resolved dependency matches any of the
+ ``PRE_EXCLUDE_REGEXES``, dependency resolution stops for that dependency.
+3. Otherwise, dependency resolution proceeds.
+4. ``file(GET_RUNTIME_DEPENDENCIES)`` searches for the dependency according to
+ the linking rules of the platform (see below).
+5. If the dependency is found, and its full path matches one of the
+ ``POST_INCLUDE_REGEXES``, the full path is added to the resolved
+ dependencies, and ``file(GET_RUNTIME_DEPENDENCIES)`` recursively resolves
+ that library's own dependencies. Otherwise, resolution proceeds to step 6.
+6. If the dependency is found, but its full path matches one of the
+ ``POST_EXCLUDE_REGEXES``, it is not added to the resolved dependencies, and
+ dependency resolution stops for that dependency.
+7. If the dependency is found, and its full path does not match either
+ ``POST_INCLUDE_REGEXES`` or ``POST_EXCLUDE_REGEXES``, the full path is added
+ to the resolved dependencies, and ``file(GET_RUNTIME_DEPENDENCIES)``
+ recursively resolves that library's own dependencies.
+
+Different platforms have different rules for how dependencies are resolved.
+These specifics are described here.
+
+On Linux platforms, library resolution works as follows:
+
+1. If the depending file does not have any ``RUNPATH`` entries, and the library
+ exists in one of the depending file's ``RPATH`` entries, or its parents', in
+ that order, the dependency is resolved to that file.
+2. Otherwise, if the depending file has any ``RUNPATH`` entries, and the
+ library exists in one of those entries, the dependency is resolved to that
+ file.
+3. Otherwise, if the library exists in one of the directories listed by
+ ``ldconfig``, the dependency is resolved to that file.
+4. Otherwise, if the library exists in one of the ``DIRECTORIES`` entries, the
+ dependency is resolved to that file. In this case, a warning is issued,
+ because finding a file in one of the ``DIRECTORIES`` means that the
+ depending file is not complete (it does not list all the directories from
+ which it pulls dependencies.)
+5. Otherwise, the dependency is unresolved.
+
+On Windows platforms, library resolution works as follows:
+
+1. The dependent DLL name is converted to lowercase. Windows DLL names are
+ case-insensitive, and some linkers mangle the case of the DLL dependency
+ names. However, this makes it more difficult for ``PRE_INCLUDE_REGEXES``,
+ ``PRE_EXCLUDE_REGEXES``, ``POST_INCLUDE_REGEXES``, and
+ ``POST_EXCLUDE_REGEXES`` to properly filter DLL names - every regex would
+ have to check for both uppercase and lowercase letters. For example:
+
+ .. code-block:: cmake
+
+ file(GET_RUNTIME_DEPENDENCIES
+ # ...
+ PRE_INCLUDE_REGEXES "^[Mm][Yy][Ll][Ii][Bb][Rr][Aa][Rr][Yy]\\.[Dd][Ll][Ll]$"
+ )
+
+ Converting the DLL name to lowercase allows the regexes to only match
+ lowercase names, thus simplifying the regex. For example:
+
+ .. code-block:: cmake
+
+ file(GET_RUNTIME_DEPENDENCIES
+ # ...
+ PRE_INCLUDE_REGEXES "^mylibrary\\.dll$"
+ )
+
+ This regex will match ``mylibrary.dll`` regardless of how it is cased,
+ either on disk or in the depending file. (For example, it will match
+ ``mylibrary.dll``, ``MyLibrary.dll``, and ``MYLIBRARY.DLL``.)
+
+ Please note that the directory portion of any resolved DLLs retains its
+ casing and is not converted to lowercase. Only the filename portion is
+ converted.
+
+2. (**Not yet implemented**) If the depending file is a Windows Store app, and
+ the dependency is listed as a dependency in the application's package
+ manifest, the dependency is resolved to that file.
+3. Otherwise, if the library exists in the same directory as the depending
+ file, the dependency is resolved to that file.
+4. Otherwise, if the library exists in either the operating system's
+ ``system32`` directory or the ``Windows`` directory, in that order, the
+ dependency is resolved to that file.
+5. Otherwise, if the library exists in one of the directories specified by
+ ``DIRECTORIES``, in the order they are listed, the dependency is resolved to
+ that file. (In this case, a warning is not issued, because searching other
+ directories is a normal part of Windows library resolution.)
+6. Otherwise, the dependency is unresolved.
+
+On Apple platforms, library resolution works as follows:
+
+1. If the dependency starts with ``@executable_path/``, and an ``EXECUTABLES``
+ argument is in the process of being resolved, and replacing
+ ``@executable_path/`` with the directory of the executable yields an
+ existing file, the dependency is resolved to that file.
+2. Otherwise, if the dependency starts with ``@executable_path/``, and there is
+ a ``BUNDLE_EXECUTABLE`` argument, and replacing ``@executable_path/`` with
+ the directory of the bundle executable yields an existing file, the
+ dependency is resolved to that file.
+3. Otherwise, if the dependency starts with ``@loader_path/``, and replacing
+ ``@loader_path/`` with the directory of the depending file yields an
+ existing file, the dependency is resolved to that file.
+4. Otherwise, if the dependency starts with ``@rpath/``, and replacing
+ ``@rpath/`` with one of the ``RPATH`` entries of the depending file yields
+ an existing file, the dependency is resolved to that file. (Note that
+ ``RPATH`` entries that start with ``@executable_path/`` or ``@loader_path/``
+ also have these items replaced with the appropriate path.)
+5. Otherwise, if the dependency is an absolute file that exists, the dependency
+ is resolved to that file.
+6. Otherwise, the dependency is unresolved.
+
+This function accepts several variables that determine which tool is used for
+dependency resolution:
+
+.. variable:: CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM
+
+ Determines which operating system and executable format the files are built
+ for. This could be one of several values:
+
+ * ``linux+elf``
+ * ``windows+pe``
+ * ``macos+macho``
+
+ If this variable is not specified, it is determined automatically by system
+ introspection.
+
+.. variable:: CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL
+
+ Determines the tool to use for dependency resolution. It could be one of
+ several values, depending on the value of
+ :variable:`CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM`:
+
+ ================================================= =============================================
+ ``CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM`` ``CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL``
+ ================================================= =============================================
+ ``linux+elf`` ``objdump``
+ ``windows+pe`` ``dumpbin``
+ ``windows+pe`` ``objdump``
+ ``macos+macho`` ``otool``
+ ================================================= =============================================
+
+ If this variable is not specified, it is determined automatically by system
+ introspection.
+
+.. variable:: CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND
+
+ Determines the path to the tool to use for dependency resolution. This is the
+ actual path to ``objdump``, ``dumpbin``, or ``otool``.
+
+ If this variable is not specified, it is determined automatically by system
+ introspection.
+
Writing
^^^^^^^
diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst
index 1d023cb..bac1c6c 100644
--- a/Help/manual/cmake-policies.7.rst
+++ b/Help/manual/cmake-policies.7.rst
@@ -57,6 +57,7 @@
.. toctree::
:maxdepth: 1
+ CMP0095: RPATH entries are properly escaped in the intermediary CMake install script. </policy/CMP0095>
CMP0094: FindPython3, FindPython2 and FindPython use LOCATION for lookup strategy. </policy/CMP0094>
CMP0093: FindBoost reports Boost_VERSION in x.y.z format. </policy/CMP0093>
CMP0092: MSVC warning flags are not in CMAKE_{C,CXX}_FLAGS by default. </policy/CMP0092>
diff --git a/Help/policy/CMP0095.rst b/Help/policy/CMP0095.rst
new file mode 100644
index 0000000..4c56a05
--- /dev/null
+++ b/Help/policy/CMP0095.rst
@@ -0,0 +1,30 @@
+CMP0095
+-------
+
+``RPATH`` entries are properly escaped in the intermediary CMake install script.
+
+In CMake 3.15 and earlier, ``RPATH`` entries set via
+:variable:`CMAKE_INSTALL_RPATH` or via :prop_tgt:`INSTALL_RPATH` have not been
+escaped before being inserted into the ``cmake_install.cmake`` script. Dynamic
+linkers on ELF-based systems (e.g. Linux and FreeBSD) allow certain keywords in
+``RPATH`` entries, such as ``${ORIGIN}`` (More details are available in the
+``ld.so`` man pages on those systems). The syntax of these keywords can match
+CMake's variable syntax. In order to not be substituted (usually to an empty
+string) already by the intermediary ``cmake_install.cmake`` script, the user had
+to double-escape such ``RPATH`` keywords, e.g.
+``set(CMAKE_INSTALL_RPATH "\\\${ORIGIN}/../lib")``. Since the intermediary
+``cmake_install.cmake`` script is an implementation detail of CMake, CMake 3.16
+and later will make sure ``RPATH`` entries are inserted literally by escaping
+any coincidental CMake syntax.
+
+The ``OLD`` behavior of this policy is to not escape ``RPATH`` entries in the
+intermediary ``cmake_install.cmake`` script. The ``NEW`` behavior is to properly
+escape coincidental CMake syntax in ``RPATH`` entries when generating the
+intermediary ``cmake_install.cmake`` script.
+
+This policy was introduced in CMake version 3.16. CMake version |release| warns
+when the policy is not set and detected usage of CMake-like syntax and uses
+``OLD`` behavior. Use the :command:`cmake_policy` command to set it to ``OLD``
+or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/release/dev/0-sample-topic.rst b/Help/release/dev/0-sample-topic.rst
new file mode 100644
index 0000000..e4cc01e
--- /dev/null
+++ b/Help/release/dev/0-sample-topic.rst
@@ -0,0 +1,7 @@
+0-sample-topic
+--------------
+
+* This is a sample release note for the change in a topic.
+ Developers should add similar notes for each topic branch
+ making a noteworthy change. Each document should be named
+ and titled to match the topic name to avoid merge conflicts.
diff --git a/Help/release/dev/CMP0095.rst b/Help/release/dev/CMP0095.rst
new file mode 100644
index 0000000..21d0550
--- /dev/null
+++ b/Help/release/dev/CMP0095.rst
@@ -0,0 +1,5 @@
+CMP0095
+-------
+
+* ``RPATH`` entries are properly escaped in the intermediary CMake install script.
+ See policy :policy:`CMP0095`.
diff --git a/Help/release/dev/add_test-expand_lists.rst b/Help/release/dev/add_test-expand_lists.rst
new file mode 100644
index 0000000..88d26b7
--- /dev/null
+++ b/Help/release/dev/add_test-expand_lists.rst
@@ -0,0 +1,6 @@
+add_test-expand_lists
+---------------------
+
+* The command :command:`add_test` learned the option ``COMMAND_EXPAND_LISTS``
+ which causes lists in the ``COMMAND`` argument to be expanded, including
+ lists created by generator expressions.
diff --git a/Help/release/dev/get-runtime-dependencies.rst b/Help/release/dev/get-runtime-dependencies.rst
new file mode 100644
index 0000000..b9dc6e6
--- /dev/null
+++ b/Help/release/dev/get-runtime-dependencies.rst
@@ -0,0 +1,9 @@
+get-runtime-dependencies
+------------------------
+
+* The :command:`file` command learned a new sub-command,
+ ``GET_RUNTIME_DEPENDENCIES``, which allows you to recursively get the list of
+ libraries linked by an executable or library. This sub-command is intended as
+ a replacement for :module:`GetPrerequisites`.
+* The :module:`GetPrerequisites` module has been deprecated, as it has been
+ superceded by :command:`file(GET_RUNTIME_DEPENDENCIES)`.
diff --git a/Help/release/index.rst b/Help/release/index.rst
index 35a47aa..62032e6 100644
--- a/Help/release/index.rst
+++ b/Help/release/index.rst
@@ -7,6 +7,8 @@
This file should include the adjacent "dev.txt" file
in development versions but not in release versions.
+.. include:: dev.txt
+
Releases
========
diff --git a/Modules/CMakeSwiftInformation.cmake b/Modules/CMakeSwiftInformation.cmake
index 21f18d4..6f99c1f 100644
--- a/Modules/CMakeSwiftInformation.cmake
+++ b/Modules/CMakeSwiftInformation.cmake
@@ -23,6 +23,8 @@
set(CMAKE_Swift_COMPILER_ARG1 -frontend)
set(CMAKE_Swift_DEFINE_FLAG -D)
set(CMAKE_Swift_FRAMEWORK_SEARCH_FLAG "-F ")
+set(CMAKE_Swift_LIBRARY_PATH_FLAG "-L ")
+set(CMAKE_Swift_LIBRARY_PATH_TERMINATOR "")
set(CMAKE_Swift_LINKER_WRAPPER_FLAG "-Xlinker" " ")
set(CMAKE_Swift_RESPONSE_FILE_LINK_FLAG @)
diff --git a/Modules/GetPrerequisites.cmake b/Modules/GetPrerequisites.cmake
index 5be4676..41d9dc1 100644
--- a/Modules/GetPrerequisites.cmake
+++ b/Modules/GetPrerequisites.cmake
@@ -5,6 +5,10 @@
GetPrerequisites
----------------
+.. deprecated:: 3.16
+
+ Use :command:`file(GET_RUNTIME_DEPENDENCIES)` instead.
+
Functions to analyze and list executable file prerequisites.
This module provides functions to list the .dll, .dylib or .so files
diff --git a/Modules/Internal/CPack/CPackDeb.cmake b/Modules/Internal/CPack/CPackDeb.cmake
index 89dc6f0..7791822 100644
--- a/Modules/Internal/CPack/CPackDeb.cmake
+++ b/Modules/Internal/CPack/CPackDeb.cmake
@@ -45,7 +45,7 @@
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE)
if(result EQUAL 0)
- string(REGEX MATCH "\\(SONAME\\)[^\n]*\\[([^\n]+)\\.so\\.([^\n]*)\\]" soname "${output}")
+ string(REGEX MATCH "\\(?SONAME\\)?[^\n]*\\[([^\n]+)\\.so\\.([^\n]*)\\]" soname "${output}")
set(${libname} "${CMAKE_MATCH_1}" PARENT_SCOPE)
set(${version} "${CMAKE_MATCH_2}" PARENT_SCOPE)
else()
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 695e075..0316532 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -146,6 +146,28 @@
cmArgumentParser.cxx
cmArgumentParser.h
cmBase32.cxx
+ cmBinUtilsLinker.cxx
+ cmBinUtilsLinker.h
+ cmBinUtilsLinuxELFGetRuntimeDependenciesTool.cxx
+ cmBinUtilsLinuxELFGetRuntimeDependenciesTool.h
+ cmBinUtilsLinuxELFLinker.cxx
+ cmBinUtilsLinuxELFLinker.h
+ cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool.cxx
+ cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool.h
+ cmBinUtilsMacOSMachOGetRuntimeDependenciesTool.cxx
+ cmBinUtilsMacOSMachOGetRuntimeDependenciesTool.h
+ cmBinUtilsMacOSMachOLinker.cxx
+ cmBinUtilsMacOSMachOLinker.h
+ cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool.cxx
+ cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool.h
+ cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool.cxx
+ cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool.h
+ cmBinUtilsWindowsPEGetRuntimeDependenciesTool.cxx
+ cmBinUtilsWindowsPEGetRuntimeDependenciesTool.h
+ cmBinUtilsWindowsPELinker.cxx
+ cmBinUtilsWindowsPELinker.h
+ cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.cxx
+ cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.h
cmCacheManager.cxx
cmCacheManager.h
cmCLocaleEnvironmentScope.h
@@ -295,6 +317,10 @@
cmInstallTargetGenerator.cxx
cmInstallDirectoryGenerator.h
cmInstallDirectoryGenerator.cxx
+ cmLDConfigLDConfigTool.cxx
+ cmLDConfigLDConfigTool.h
+ cmLDConfigTool.cxx
+ cmLDConfigTool.h
cmLinkedTree.h
cmLinkItem.cxx
cmLinkItem.h
@@ -338,7 +364,6 @@
cmProcessOutput.h
cmProcessTools.cxx
cmProcessTools.h
- cmProperty.cxx
cmProperty.h
cmPropertyDefinition.cxx
cmPropertyDefinition.h
@@ -360,6 +385,8 @@
cmQtAutoRcc.h
cmRST.cxx
cmRST.h
+ cmRuntimeDependencyArchive.cxx
+ cmRuntimeDependencyArchive.h
cmScriptGenerator.h
cmScriptGenerator.cxx
cmSourceFile.cxx
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index e22d37c..9bef298 100644
--- a/Source/CMakeVersion.cmake
+++ b/Source/CMakeVersion.cmake
@@ -1,5 +1,5 @@
# CMake version number components.
set(CMake_VERSION_MAJOR 3)
set(CMake_VERSION_MINOR 15)
-set(CMake_VERSION_PATCH 0)
-set(CMake_VERSION_RC 1)
+set(CMake_VERSION_PATCH 20190618)
+#set(CMake_VERSION_RC 1)
diff --git a/Source/cmAddCustomCommandCommand.cxx b/Source/cmAddCustomCommandCommand.cxx
index 0be3c85..6eb38bd 100644
--- a/Source/cmAddCustomCommandCommand.cxx
+++ b/Source/cmAddCustomCommandCommand.cxx
@@ -95,30 +95,29 @@
MAKE_STATIC_KEYWORD(VERBATIM);
MAKE_STATIC_KEYWORD(WORKING_DIRECTORY);
#undef MAKE_STATIC_KEYWORD
- static std::unordered_set<std::string> keywords;
- if (keywords.empty()) {
- keywords.insert(keyAPPEND);
- keywords.insert(keyARGS);
- keywords.insert(keyBYPRODUCTS);
- keywords.insert(keyCOMMAND);
- keywords.insert(keyCOMMAND_EXPAND_LISTS);
- keywords.insert(keyCOMMENT);
- keywords.insert(keyDEPENDS);
- keywords.insert(keyDEPFILE);
- keywords.insert(keyIMPLICIT_DEPENDS);
- keywords.insert(keyJOB_POOL);
- keywords.insert(keyMAIN_DEPENDENCY);
- keywords.insert(keyOUTPUT);
- keywords.insert(keyOUTPUTS);
- keywords.insert(keyPOST_BUILD);
- keywords.insert(keyPRE_BUILD);
- keywords.insert(keyPRE_LINK);
- keywords.insert(keySOURCE);
- keywords.insert(keyTARGET);
- keywords.insert(keyUSES_TERMINAL);
- keywords.insert(keyVERBATIM);
- keywords.insert(keyWORKING_DIRECTORY);
- }
+ static std::unordered_set<std::string> const keywords{
+ keyAPPEND,
+ keyARGS,
+ keyBYPRODUCTS,
+ keyCOMMAND,
+ keyCOMMAND_EXPAND_LISTS,
+ keyCOMMENT,
+ keyDEPENDS,
+ keyDEPFILE,
+ keyIMPLICIT_DEPENDS,
+ keyJOB_POOL,
+ keyMAIN_DEPENDENCY,
+ keyOUTPUT,
+ keyOUTPUTS,
+ keyPOST_BUILD,
+ keyPRE_BUILD,
+ keyPRE_LINK,
+ keySOURCE,
+ keyTARGET,
+ keyUSES_TERMINAL,
+ keyVERBATIM,
+ keyWORKING_DIRECTORY
+ };
for (std::string const& copy : args) {
if (keywords.count(copy)) {
diff --git a/Source/cmAddTestCommand.cxx b/Source/cmAddTestCommand.cxx
index bf28702..b0c462b 100644
--- a/Source/cmAddTestCommand.cxx
+++ b/Source/cmAddTestCommand.cxx
@@ -58,6 +58,7 @@
std::vector<std::string> configurations;
std::string working_directory;
std::vector<std::string> command;
+ bool command_expand_lists = false;
// Read the arguments.
enum Doing
@@ -88,6 +89,13 @@
return false;
}
doing = DoingWorkingDirectory;
+ } else if (args[i] == "COMMAND_EXPAND_LISTS") {
+ if (command_expand_lists) {
+ this->SetError(" may be given at most one COMMAND_EXPAND_LISTS.");
+ return false;
+ }
+ command_expand_lists = true;
+ doing = DoingNone;
} else if (doing == DoingName) {
name = args[i];
doing = DoingNone;
@@ -134,6 +142,7 @@
if (!working_directory.empty()) {
test->SetProperty("WORKING_DIRECTORY", working_directory.c_str());
}
+ test->SetCommandExpandLists(command_expand_lists);
this->Makefile->AddTestGenerator(new cmTestGenerator(test, configurations));
return true;
diff --git a/Source/cmBinUtilsLinker.cxx b/Source/cmBinUtilsLinker.cxx
new file mode 100644
index 0000000..3dac85c
--- /dev/null
+++ b/Source/cmBinUtilsLinker.cxx
@@ -0,0 +1,15 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmBinUtilsLinker.h"
+#include "cmRuntimeDependencyArchive.h"
+
+cmBinUtilsLinker::cmBinUtilsLinker(cmRuntimeDependencyArchive* archive)
+ : Archive(archive)
+{
+}
+
+void cmBinUtilsLinker::SetError(const std::string& e)
+{
+ this->Archive->SetError(e);
+}
diff --git a/Source/cmBinUtilsLinker.h b/Source/cmBinUtilsLinker.h
new file mode 100644
index 0000000..29853a5
--- /dev/null
+++ b/Source/cmBinUtilsLinker.h
@@ -0,0 +1,30 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#ifndef cmBinUtilsLinker_h
+#define cmBinUtilsLinker_h
+
+#include "cmStateTypes.h"
+
+#include <string>
+
+class cmRuntimeDependencyArchive;
+
+class cmBinUtilsLinker
+{
+public:
+ cmBinUtilsLinker(cmRuntimeDependencyArchive* archive);
+ virtual ~cmBinUtilsLinker() = default;
+
+ virtual bool Prepare() { return true; }
+
+ virtual bool ScanDependencies(std::string const& file,
+ cmStateEnums::TargetType type) = 0;
+
+protected:
+ cmRuntimeDependencyArchive* Archive;
+
+ void SetError(const std::string& e);
+};
+
+#endif // cmBinUtilsLinker_h
diff --git a/Source/cmBinUtilsLinuxELFGetRuntimeDependenciesTool.cxx b/Source/cmBinUtilsLinuxELFGetRuntimeDependenciesTool.cxx
new file mode 100644
index 0000000..40de592
--- /dev/null
+++ b/Source/cmBinUtilsLinuxELFGetRuntimeDependenciesTool.cxx
@@ -0,0 +1,18 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmBinUtilsLinuxELFGetRuntimeDependenciesTool.h"
+#include "cmRuntimeDependencyArchive.h"
+
+cmBinUtilsLinuxELFGetRuntimeDependenciesTool::
+ cmBinUtilsLinuxELFGetRuntimeDependenciesTool(
+ cmRuntimeDependencyArchive* archive)
+ : Archive(archive)
+{
+}
+
+void cmBinUtilsLinuxELFGetRuntimeDependenciesTool::SetError(
+ const std::string& error)
+{
+ this->Archive->SetError(error);
+}
diff --git a/Source/cmBinUtilsLinuxELFGetRuntimeDependenciesTool.h b/Source/cmBinUtilsLinuxELFGetRuntimeDependenciesTool.h
new file mode 100644
index 0000000..d514e7f
--- /dev/null
+++ b/Source/cmBinUtilsLinuxELFGetRuntimeDependenciesTool.h
@@ -0,0 +1,30 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#ifndef cmBinUtilsLinuxELFGetRuntimeDependenciesTool_h
+#define cmBinUtilsLinuxELFGetRuntimeDependenciesTool_h
+
+#include <string>
+#include <vector>
+
+class cmRuntimeDependencyArchive;
+
+class cmBinUtilsLinuxELFGetRuntimeDependenciesTool
+{
+public:
+ cmBinUtilsLinuxELFGetRuntimeDependenciesTool(
+ cmRuntimeDependencyArchive* archive);
+ virtual ~cmBinUtilsLinuxELFGetRuntimeDependenciesTool() = default;
+
+ virtual bool GetFileInfo(std::string const& file,
+ std::vector<std::string>& needed,
+ std::vector<std::string>& rpaths,
+ std::vector<std::string>& runpaths) = 0;
+
+protected:
+ cmRuntimeDependencyArchive* Archive;
+
+ void SetError(const std::string& e);
+};
+
+#endif // cmBinUtilsLinuxELFGetRuntimeDependenciesTool_h
diff --git a/Source/cmBinUtilsLinuxELFLinker.cxx b/Source/cmBinUtilsLinuxELFLinker.cxx
new file mode 100644
index 0000000..4fb15f2
--- /dev/null
+++ b/Source/cmBinUtilsLinuxELFLinker.cxx
@@ -0,0 +1,177 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmBinUtilsLinuxELFLinker.h"
+#include "cmAlgorithms.h"
+#include "cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool.h"
+#include "cmLDConfigLDConfigTool.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmRuntimeDependencyArchive.h"
+#include "cmSystemTools.h"
+
+#include <cmsys/RegularExpression.hxx>
+
+#include <memory>
+#include <sstream>
+
+static std::string ReplaceOrigin(const std::string& rpath,
+ const std::string& origin)
+{
+ static const cmsys::RegularExpression originRegex(
+ "(\\$ORIGIN)([^a-zA-Z0-9_]|$)");
+ static const cmsys::RegularExpression originCurlyRegex("\\${ORIGIN}");
+
+ cmsys::RegularExpressionMatch match;
+ if (originRegex.find(rpath.c_str(), match)) {
+ std::string begin = rpath.substr(0, match.start(1));
+ std::string end = rpath.substr(match.end(1));
+ return begin + origin + end;
+ }
+ if (originCurlyRegex.find(rpath.c_str(), match)) {
+ std::string begin = rpath.substr(0, match.start());
+ std::string end = rpath.substr(match.end());
+ return begin + origin + end;
+ }
+ return rpath;
+}
+
+cmBinUtilsLinuxELFLinker::cmBinUtilsLinuxELFLinker(
+ cmRuntimeDependencyArchive* archive)
+ : cmBinUtilsLinker(archive)
+{
+}
+
+bool cmBinUtilsLinuxELFLinker::Prepare()
+{
+ std::string tool = this->Archive->GetGetRuntimeDependenciesTool();
+ if (tool.empty()) {
+ tool = "objdump";
+ }
+ if (tool == "objdump") {
+ this->Tool =
+ cm::make_unique<cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool>(
+ this->Archive);
+ } else {
+ std::ostringstream e;
+ e << "Invalid value for CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL: " << tool;
+ this->SetError(e.str());
+ return false;
+ }
+
+ std::string ldConfigTool =
+ this->Archive->GetMakefile()->GetSafeDefinition("CMAKE_LDCONFIG_TOOL");
+ if (ldConfigTool.empty()) {
+ ldConfigTool = "ldconfig";
+ }
+ if (ldConfigTool == "ldconfig") {
+ this->LDConfigTool =
+ cm::make_unique<cmLDConfigLDConfigTool>(this->Archive);
+ } else {
+ std::ostringstream e;
+ e << "Invalid value for CMAKE_LDCONFIG_TOOL: " << ldConfigTool;
+ this->SetError(e.str());
+ return false;
+ }
+
+ return true;
+}
+
+bool cmBinUtilsLinuxELFLinker::ScanDependencies(
+ std::string const& file, cmStateEnums::TargetType /* unused */)
+{
+ std::vector<std::string> parentRpaths;
+ return this->ScanDependencies(file, parentRpaths);
+}
+
+bool cmBinUtilsLinuxELFLinker::ScanDependencies(
+ std::string const& file, std::vector<std::string> const& parentRpaths)
+{
+ std::string origin = cmSystemTools::GetFilenamePath(file);
+ std::vector<std::string> needed;
+ std::vector<std::string> rpaths;
+ std::vector<std::string> runpaths;
+ if (!this->Tool->GetFileInfo(file, needed, rpaths, runpaths)) {
+ return false;
+ }
+ for (auto& runpath : runpaths) {
+ runpath = ReplaceOrigin(runpath, origin);
+ }
+ for (auto& rpath : rpaths) {
+ rpath = ReplaceOrigin(rpath, origin);
+ }
+
+ std::vector<std::string> searchPaths;
+ if (!runpaths.empty()) {
+ searchPaths = runpaths;
+ } else {
+ searchPaths = rpaths;
+ searchPaths.insert(searchPaths.end(), parentRpaths.begin(),
+ parentRpaths.end());
+ }
+
+ std::vector<std::string> ldConfigPaths;
+ if (!this->LDConfigTool->GetLDConfigPaths(ldConfigPaths)) {
+ return false;
+ }
+ searchPaths.insert(searchPaths.end(), ldConfigPaths.begin(),
+ ldConfigPaths.end());
+
+ for (auto const& dep : needed) {
+ if (!this->Archive->IsPreExcluded(dep)) {
+ std::string path;
+ bool resolved = false;
+ if (dep.find('/') != std::string::npos) {
+ this->SetError("Paths to dependencies are not supported");
+ return false;
+ }
+ if (!this->ResolveDependency(dep, searchPaths, path, resolved)) {
+ return false;
+ }
+ if (resolved) {
+ if (!this->Archive->IsPostExcluded(path)) {
+ bool unique;
+ this->Archive->AddResolvedPath(dep, path, unique);
+ if (unique && !this->ScanDependencies(path, rpaths)) {
+ return false;
+ }
+ }
+ } else {
+ this->Archive->AddUnresolvedPath(dep);
+ }
+ }
+ }
+
+ return true;
+}
+
+bool cmBinUtilsLinuxELFLinker::ResolveDependency(
+ std::string const& name, std::vector<std::string> const& searchPaths,
+ std::string& path, bool& resolved)
+{
+ for (auto const& searchPath : searchPaths) {
+ path = searchPath + '/' + name;
+ if (cmSystemTools::PathExists(path)) {
+ resolved = true;
+ return true;
+ }
+ }
+
+ for (auto const& searchPath : this->Archive->GetSearchDirectories()) {
+ path = searchPath + '/' + name;
+ if (cmSystemTools::PathExists(path)) {
+ std::ostringstream warning;
+ warning << "Dependency " << name << " found in search directory:\n "
+ << searchPath
+ << "\nSee file(GET_RUNTIME_DEPENDENCIES) documentation for "
+ << "more information.";
+ this->Archive->GetMakefile()->IssueMessage(MessageType::WARNING,
+ warning.str());
+ resolved = true;
+ return true;
+ }
+ }
+
+ resolved = false;
+ return true;
+}
diff --git a/Source/cmBinUtilsLinuxELFLinker.h b/Source/cmBinUtilsLinuxELFLinker.h
new file mode 100644
index 0000000..348edc4
--- /dev/null
+++ b/Source/cmBinUtilsLinuxELFLinker.h
@@ -0,0 +1,44 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#ifndef cmBinUtilsLinuxELFLinker_h
+#define cmBinUtilsLinuxELFLinker_h
+
+#include "cmBinUtilsLinker.h"
+#include "cmBinUtilsLinuxELFGetRuntimeDependenciesTool.h"
+#include "cmLDConfigTool.h"
+#include "cmStateTypes.h"
+
+#include <memory> // IWYU pragma: keep
+#include <string>
+#include <vector>
+
+class cmRuntimeDependencyArchive;
+
+class cmBinUtilsLinuxELFLinker : public cmBinUtilsLinker
+{
+public:
+ cmBinUtilsLinuxELFLinker(cmRuntimeDependencyArchive* archive);
+
+ bool Prepare() override;
+
+ bool ScanDependencies(std::string const& file,
+ cmStateEnums::TargetType type) override;
+
+private:
+ std::unique_ptr<cmBinUtilsLinuxELFGetRuntimeDependenciesTool> Tool;
+ std::unique_ptr<cmLDConfigTool> LDConfigTool;
+ bool HaveLDConfigPaths = false;
+ std::vector<std::string> LDConfigPaths;
+
+ bool ScanDependencies(std::string const& file,
+ std::vector<std::string> const& parentRpaths);
+
+ bool ResolveDependency(std::string const& name,
+ std::vector<std::string> const& searchPaths,
+ std::string& path, bool& resolved);
+
+ bool GetLDConfigPaths();
+};
+
+#endif // cmBinUtilsLinuxELFLinker_h
diff --git a/Source/cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool.cxx b/Source/cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool.cxx
new file mode 100644
index 0000000..3bf7bf8
--- /dev/null
+++ b/Source/cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool.cxx
@@ -0,0 +1,84 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool.h"
+#include "cmRuntimeDependencyArchive.h"
+#include "cmSystemTools.h"
+#include "cmUVProcessChain.h"
+
+#include <cmsys/RegularExpression.hxx>
+
+#include <sstream>
+
+cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool::
+ cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool(
+ cmRuntimeDependencyArchive* archive)
+ : cmBinUtilsLinuxELFGetRuntimeDependenciesTool(archive)
+{
+}
+
+bool cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool::GetFileInfo(
+ std::string const& file, std::vector<std::string>& needed,
+ std::vector<std::string>& rpaths, std::vector<std::string>& runpaths)
+{
+ cmUVProcessChainBuilder builder;
+ builder.SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT);
+
+ std::vector<std::string> command;
+ if (!this->Archive->GetGetRuntimeDependenciesCommand("objdump", command)) {
+ this->SetError("Could not find objdump");
+ return false;
+ }
+ command.emplace_back("-p");
+ command.push_back(file);
+ builder.AddCommand(command);
+
+ auto process = builder.Start();
+ if (!process.Valid()) {
+ std::ostringstream e;
+ e << "Failed to start objdump process for:\n " << file;
+ this->SetError(e.str());
+ return false;
+ }
+
+ std::string line;
+ static const cmsys::RegularExpression neededRegex("^ *NEEDED *([^\n]*)$");
+ static const cmsys::RegularExpression rpathRegex("^ *RPATH *([^\n]*)$");
+ static const cmsys::RegularExpression runpathRegex("^ *RUNPATH *([^\n]*)$");
+ while (std::getline(*process.OutputStream(), line)) {
+ cmsys::RegularExpressionMatch match;
+ if (neededRegex.find(line.c_str(), match)) {
+ needed.push_back(match.match(1));
+ } else if (rpathRegex.find(line.c_str(), match)) {
+ std::vector<std::string> rpathSplit =
+ cmSystemTools::SplitString(match.match(1), ':');
+ rpaths.reserve(rpaths.size() + rpathSplit.size());
+ for (auto const& rpath : rpathSplit) {
+ rpaths.push_back(rpath);
+ }
+ } else if (runpathRegex.find(line.c_str(), match)) {
+ std::vector<std::string> runpathSplit =
+ cmSystemTools::SplitString(match.match(1), ':');
+ runpaths.reserve(runpaths.size() + runpathSplit.size());
+ for (auto const& runpath : runpathSplit) {
+ runpaths.push_back(runpath);
+ }
+ }
+ }
+
+ if (!process.Wait()) {
+ std::ostringstream e;
+ e << "Failed to wait on objdump process for:\n " << file;
+ this->SetError(e.str());
+ return false;
+ }
+ auto status = process.GetStatus();
+ if (!status[0] || status[0]->ExitStatus != 0) {
+ std::ostringstream e;
+ e << "Failed to run objdump on:\n " << file;
+ this->SetError(e.str());
+ return false;
+ }
+
+ return true;
+}
diff --git a/Source/cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool.h b/Source/cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool.h
new file mode 100644
index 0000000..286337f
--- /dev/null
+++ b/Source/cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool.h
@@ -0,0 +1,26 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#ifndef cmBinUtilsLinuxELFGetRuntimeCollectDependenciesTool_h
+#define cmBinUtilsLinuxELFGetRuntimeCollectDependenciesTool_h
+
+#include "cmBinUtilsLinuxELFGetRuntimeDependenciesTool.h"
+
+#include <string>
+#include <vector>
+
+class cmRuntimeDependencyArchive;
+
+class cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool
+ : public cmBinUtilsLinuxELFGetRuntimeDependenciesTool
+{
+public:
+ cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool(
+ cmRuntimeDependencyArchive* archive);
+
+ bool GetFileInfo(std::string const& file, std::vector<std::string>& needed,
+ std::vector<std::string>& rpaths,
+ std::vector<std::string>& runpaths) override;
+};
+
+#endif // cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool_h
diff --git a/Source/cmBinUtilsMacOSMachOGetRuntimeDependenciesTool.cxx b/Source/cmBinUtilsMacOSMachOGetRuntimeDependenciesTool.cxx
new file mode 100644
index 0000000..a296a47
--- /dev/null
+++ b/Source/cmBinUtilsMacOSMachOGetRuntimeDependenciesTool.cxx
@@ -0,0 +1,19 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmBinUtilsMacOSMachOGetRuntimeDependenciesTool.h"
+
+#include "cmRuntimeDependencyArchive.h"
+
+cmBinUtilsMacOSMachOGetRuntimeDependenciesTool::
+ cmBinUtilsMacOSMachOGetRuntimeDependenciesTool(
+ cmRuntimeDependencyArchive* archive)
+ : Archive(archive)
+{
+}
+
+void cmBinUtilsMacOSMachOGetRuntimeDependenciesTool::SetError(
+ const std::string& error)
+{
+ this->Archive->SetError(error);
+}
diff --git a/Source/cmBinUtilsMacOSMachOGetRuntimeDependenciesTool.h b/Source/cmBinUtilsMacOSMachOGetRuntimeDependenciesTool.h
new file mode 100644
index 0000000..dbb2882
--- /dev/null
+++ b/Source/cmBinUtilsMacOSMachOGetRuntimeDependenciesTool.h
@@ -0,0 +1,29 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#ifndef cmBinUtilsMacOSMachOGetRuntimeDependenciesTool_h
+#define cmBinUtilsMacOSMachOGetRuntimeDependenciesTool_h
+
+#include <string>
+#include <vector>
+
+class cmRuntimeDependencyArchive;
+
+class cmBinUtilsMacOSMachOGetRuntimeDependenciesTool
+{
+public:
+ cmBinUtilsMacOSMachOGetRuntimeDependenciesTool(
+ cmRuntimeDependencyArchive* archive);
+ virtual ~cmBinUtilsMacOSMachOGetRuntimeDependenciesTool() = default;
+
+ virtual bool GetFileInfo(std::string const& file,
+ std::vector<std::string>& libs,
+ std::vector<std::string>& rpaths) = 0;
+
+protected:
+ cmRuntimeDependencyArchive* Archive;
+
+ void SetError(const std::string& error);
+};
+
+#endif // cmBinUtilsMacOSMachOGetRuntimeDependenciesTool_h
diff --git a/Source/cmBinUtilsMacOSMachOLinker.cxx b/Source/cmBinUtilsMacOSMachOLinker.cxx
new file mode 100644
index 0000000..e219847
--- /dev/null
+++ b/Source/cmBinUtilsMacOSMachOLinker.cxx
@@ -0,0 +1,228 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmBinUtilsMacOSMachOLinker.h"
+
+#include "cmAlgorithms.h"
+#include "cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool.h"
+#include "cmRuntimeDependencyArchive.h"
+#include "cmSystemTools.h"
+
+#include <sstream>
+#include <string>
+#include <vector>
+
+cmBinUtilsMacOSMachOLinker::cmBinUtilsMacOSMachOLinker(
+ cmRuntimeDependencyArchive* archive)
+ : cmBinUtilsLinker(archive)
+{
+}
+
+bool cmBinUtilsMacOSMachOLinker::Prepare()
+{
+ std::string tool = this->Archive->GetGetRuntimeDependenciesTool();
+ if (tool.empty()) {
+ tool = "otool";
+ }
+ if (tool == "otool") {
+ this->Tool =
+ cm::make_unique<cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool>(
+ this->Archive);
+ } else {
+ std::ostringstream e;
+ e << "Invalid value for CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL: " << tool;
+ this->SetError(e.str());
+ return false;
+ }
+
+ return true;
+}
+
+bool cmBinUtilsMacOSMachOLinker::ScanDependencies(
+ std::string const& file, cmStateEnums::TargetType type)
+{
+ std::string executableFile;
+ if (type == cmStateEnums::EXECUTABLE) {
+ executableFile = file;
+ } else {
+ executableFile = this->Archive->GetBundleExecutable();
+ }
+ std::string executablePath;
+ if (!executableFile.empty()) {
+ executablePath = cmSystemTools::GetFilenamePath(executableFile);
+ }
+ return this->ScanDependencies(file, executablePath);
+}
+
+bool cmBinUtilsMacOSMachOLinker::ScanDependencies(
+ std::string const& file, std::string const& executablePath)
+{
+ std::vector<std::string> libs, rpaths;
+ if (!this->Tool->GetFileInfo(file, libs, rpaths)) {
+ return false;
+ }
+
+ std::string loaderPath = cmSystemTools::GetFilenamePath(file);
+ return this->GetFileDependencies(libs, executablePath, loaderPath, rpaths);
+}
+
+bool cmBinUtilsMacOSMachOLinker::GetFileDependencies(
+ std::vector<std::string> const& names, std::string const& executablePath,
+ std::string const& loaderPath, std::vector<std::string> const& rpaths)
+{
+ for (std::string const& name : names) {
+ if (!this->Archive->IsPreExcluded(name)) {
+ std::string path;
+ bool resolved;
+ if (!this->ResolveDependency(name, executablePath, loaderPath, rpaths,
+ path, resolved)) {
+ return false;
+ }
+ if (resolved) {
+ if (!this->Archive->IsPostExcluded(path)) {
+ auto filename = cmSystemTools::GetFilenameName(path);
+ bool unique;
+ this->Archive->AddResolvedPath(filename, path, unique);
+ if (unique && !this->ScanDependencies(path, executablePath)) {
+ return false;
+ }
+ }
+ } else {
+ this->Archive->AddUnresolvedPath(name);
+ }
+ }
+ }
+
+ return true;
+}
+
+bool cmBinUtilsMacOSMachOLinker::ResolveDependency(
+ std::string const& name, std::string const& executablePath,
+ std::string const& loaderPath, std::vector<std::string> const& rpaths,
+ std::string& path, bool& resolved)
+{
+ resolved = false;
+ if (cmHasLiteralPrefix(name, "@rpath/")) {
+ if (!this->ResolveRPathDependency(name, executablePath, loaderPath, rpaths,
+ path, resolved)) {
+ return false;
+ }
+ } else if (cmHasLiteralPrefix(name, "@loader_path/")) {
+ if (!this->ResolveLoaderPathDependency(name, loaderPath, path, resolved)) {
+ return false;
+ }
+ } else if (cmHasLiteralPrefix(name, "@executable_path/")) {
+ if (!this->ResolveExecutablePathDependency(name, executablePath, path,
+ resolved)) {
+ return false;
+ }
+ } else {
+ resolved = true;
+ path = name;
+ }
+
+ if (resolved && !cmSystemTools::FileIsFullPath(path)) {
+ this->SetError("Resolved path is not absolute");
+ return false;
+ }
+
+ return true;
+}
+
+bool cmBinUtilsMacOSMachOLinker::ResolveExecutablePathDependency(
+ std::string const& name, std::string const& executablePath,
+ std::string& path, bool& resolved)
+{
+ if (executablePath.empty()) {
+ resolved = false;
+ return true;
+ }
+
+ // 16 is == "@executable_path".length()
+ path = name;
+ path.replace(0, 16, executablePath);
+
+ if (!cmSystemTools::PathExists(path)) {
+ resolved = false;
+ return true;
+ }
+
+ resolved = true;
+ return true;
+}
+
+bool cmBinUtilsMacOSMachOLinker::ResolveLoaderPathDependency(
+ std::string const& name, std::string const& loaderPath, std::string& path,
+ bool& resolved)
+{
+ if (loaderPath.empty()) {
+ resolved = false;
+ return true;
+ }
+
+ // 12 is "@loader_path".length();
+ path = name;
+ path.replace(0, 12, loaderPath);
+
+ if (!cmSystemTools::PathExists(path)) {
+ resolved = false;
+ return true;
+ }
+
+ resolved = true;
+ return true;
+}
+
+bool cmBinUtilsMacOSMachOLinker::ResolveRPathDependency(
+ std::string const& name, std::string const& executablePath,
+ std::string const& loaderPath, std::vector<std::string> const& rpaths,
+ std::string& path, bool& resolved)
+{
+ for (std::string const& rpath : rpaths) {
+ std::string searchFile = name;
+ searchFile.replace(0, 6, rpath);
+ if (cmHasLiteralPrefix(searchFile, "@loader_path/")) {
+ if (!this->ResolveLoaderPathDependency(searchFile, loaderPath, path,
+ resolved)) {
+ return false;
+ }
+ if (resolved) {
+ return true;
+ }
+ } else if (cmHasLiteralPrefix(searchFile, "@executable_path/")) {
+ if (!this->ResolveExecutablePathDependency(searchFile, executablePath,
+ path, resolved)) {
+ return false;
+ }
+ if (resolved) {
+ return true;
+ }
+ } else if (cmSystemTools::PathExists(searchFile)) {
+ /*
+ * paraphrasing @ben.boeckel:
+ * if /b/libB.dylib is supposed to be used,
+ * /a/libbB.dylib will be found first if it exists. CMake tries to
+ * sort rpath directories to avoid this, but sometimes there is no
+ * right answer.
+ *
+ * I believe it is possible to resolve this using otools -l
+ * then checking the LC_LOAD_DYLIB command whose name is
+ * equal to the value of search_file, UNLESS the build
+ * specifically sets the RPath to paths that will match
+ * duplicate libs; at this point can we just point to
+ * user error, or is there a reason why the advantages
+ * to this scenario outweigh its disadvantages?
+ *
+ * Also priority seems to be the order as passed in when compiled
+ * so as long as this method's resolution guarantees priority
+ * in that manner further checking should not be necessary?
+ */
+ path = searchFile;
+ resolved = true;
+ return true;
+ }
+ }
+
+ resolved = false;
+ return true;
+}
diff --git a/Source/cmBinUtilsMacOSMachOLinker.h b/Source/cmBinUtilsMacOSMachOLinker.h
new file mode 100644
index 0000000..0350d1e
--- /dev/null
+++ b/Source/cmBinUtilsMacOSMachOLinker.h
@@ -0,0 +1,59 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#ifndef cmBinUtilsMacOSMachOLinker_h
+#define cmBinUtilsMacOSMachOLinker_h
+
+#include "cmBinUtilsLinker.h"
+#include "cmBinUtilsMacOSMachOGetRuntimeDependenciesTool.h"
+#include "cmStateTypes.h"
+
+#include <memory> // IWYU pragma: keep
+#include <string>
+#include <vector>
+
+class cmRuntimeDependencyArchive;
+
+class cmBinUtilsMacOSMachOLinker : public cmBinUtilsLinker
+{
+public:
+ cmBinUtilsMacOSMachOLinker(cmRuntimeDependencyArchive* archive);
+
+ bool Prepare() override;
+
+ bool ScanDependencies(std::string const& file,
+ cmStateEnums::TargetType type) override;
+
+private:
+ std::unique_ptr<cmBinUtilsMacOSMachOGetRuntimeDependenciesTool> Tool;
+
+ bool ScanDependencies(std::string const& file,
+ std::string const& executablePath);
+
+ bool GetFileDependencies(std::vector<std::string> const& names,
+ std::string const& executablePath,
+ std::string const& loaderPath,
+ std::vector<std::string> const& rpaths);
+
+ bool ResolveDependency(std::string const& name,
+ std::string const& executablePath,
+ std::string const& loaderPath,
+ std::vector<std::string> const& rpaths,
+ std::string& path, bool& resolved);
+
+ bool ResolveExecutablePathDependency(std::string const& name,
+ std::string const& executablePath,
+ std::string& path, bool& resolved);
+
+ bool ResolveLoaderPathDependency(std::string const& name,
+ std::string const& loaderPath,
+ std::string& path, bool& resolved);
+
+ bool ResolveRPathDependency(std::string const& name,
+ std::string const& executablePath,
+ std::string const& loaderPath,
+ std::vector<std::string> const& rpaths,
+ std::string& path, bool& resolved);
+};
+
+#endif // cmBinUtilsMacOSMachOLinker_h
diff --git a/Source/cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool.cxx b/Source/cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool.cxx
new file mode 100644
index 0000000..bab2382
--- /dev/null
+++ b/Source/cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool.cxx
@@ -0,0 +1,100 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool.h"
+
+#include "cmRuntimeDependencyArchive.h"
+#include "cmUVProcessChain.h"
+
+#include <cmsys/RegularExpression.hxx>
+
+#include <sstream>
+
+cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool::
+ cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool(
+ cmRuntimeDependencyArchive* archive)
+ : cmBinUtilsMacOSMachOGetRuntimeDependenciesTool(archive)
+{
+}
+
+bool cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool::GetFileInfo(
+ std::string const& file, std::vector<std::string>& libs,
+ std::vector<std::string>& rpaths)
+{
+ std::vector<std::string> command;
+ if (!this->Archive->GetGetRuntimeDependenciesCommand("otool", command)) {
+ this->SetError("Could not find otool");
+ return false;
+ }
+ command.emplace_back("-l");
+ command.emplace_back(file);
+
+ cmUVProcessChainBuilder builder;
+ builder.SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT)
+ .AddCommand(command);
+
+ auto process = builder.Start();
+ if (!process.Valid()) {
+ std::ostringstream e;
+ e << "Failed to start otool process for:\n " << file;
+ this->SetError(e.str());
+ return false;
+ }
+
+ std::string line;
+ static const cmsys::RegularExpression rpathRegex("^ *cmd LC_RPATH$");
+ static const cmsys::RegularExpression loadDylibRegex(
+ "^ *cmd LC_LOAD_DYLIB$");
+ static const cmsys::RegularExpression pathRegex(
+ "^ *path (.*) \\(offset [0-9]+\\)$");
+ static const cmsys::RegularExpression nameRegex(
+ "^ *name (.*) \\(offset [0-9]+\\)$");
+ while (std::getline(*process.OutputStream(), line)) {
+ cmsys::RegularExpressionMatch cmdMatch;
+ if (rpathRegex.find(line.c_str(), cmdMatch)) {
+ if (!std::getline(*process.OutputStream(), line) ||
+ !std::getline(*process.OutputStream(), line)) {
+ this->SetError("Invalid output from otool");
+ return false;
+ }
+
+ cmsys::RegularExpressionMatch pathMatch;
+ if (pathRegex.find(line.c_str(), pathMatch)) {
+ rpaths.push_back(pathMatch.match(1));
+ } else {
+ this->SetError("Invalid output from otool");
+ return false;
+ }
+ } else if (loadDylibRegex.find(line.c_str(), cmdMatch)) {
+ if (!std::getline(*process.OutputStream(), line) ||
+ !std::getline(*process.OutputStream(), line)) {
+ this->SetError("Invalid output from otool");
+ return false;
+ }
+
+ cmsys::RegularExpressionMatch nameMatch;
+ if (nameRegex.find(line.c_str(), nameMatch)) {
+ libs.push_back(nameMatch.match(1));
+ } else {
+ this->SetError("Invalid output from otool");
+ return false;
+ }
+ }
+ }
+
+ if (!process.Wait()) {
+ std::ostringstream e;
+ e << "Failed to wait on otool process for:\n " << file;
+ this->SetError(e.str());
+ return false;
+ }
+ auto status = process.GetStatus();
+ if (!status[0] || status[0]->ExitStatus != 0) {
+ std::ostringstream e;
+ e << "Failed to run otool on:\n " << file;
+ this->SetError(e.str());
+ return false;
+ }
+
+ return true;
+}
diff --git a/Source/cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool.h b/Source/cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool.h
new file mode 100644
index 0000000..12bcbc1
--- /dev/null
+++ b/Source/cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool.h
@@ -0,0 +1,25 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#ifndef cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool_h
+#define cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool_h
+
+#include "cmBinUtilsMacOSMachOGetRuntimeDependenciesTool.h"
+
+#include <string>
+#include <vector>
+
+class cmRuntimeDependencyArchive;
+
+class cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool
+ : public cmBinUtilsMacOSMachOGetRuntimeDependenciesTool
+{
+public:
+ cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool(
+ cmRuntimeDependencyArchive* archive);
+
+ bool GetFileInfo(std::string const& file, std::vector<std::string>& libs,
+ std::vector<std::string>& rpaths) override;
+};
+
+#endif // cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool_h
diff --git a/Source/cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool.cxx b/Source/cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool.cxx
new file mode 100644
index 0000000..2b35e30
--- /dev/null
+++ b/Source/cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool.cxx
@@ -0,0 +1,67 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool.h"
+#include "cmRuntimeDependencyArchive.h"
+#include "cmUVProcessChain.h"
+
+#include <cmsys/RegularExpression.hxx>
+
+#include <sstream>
+
+cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool::
+ cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool(
+ cmRuntimeDependencyArchive* archive)
+ : cmBinUtilsWindowsPEGetRuntimeDependenciesTool(archive)
+{
+}
+
+bool cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool::GetFileInfo(
+ const std::string& file, std::vector<std::string>& needed)
+{
+ cmUVProcessChainBuilder builder;
+ builder.SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT);
+
+ std::vector<std::string> command;
+ if (!this->Archive->GetGetRuntimeDependenciesCommand("dumpbin", command)) {
+ this->SetError("Could not find dumpbin");
+ return false;
+ }
+ command.emplace_back("/dependents");
+ command.push_back(file);
+ builder.AddCommand(command);
+
+ auto process = builder.Start();
+ if (!process.Valid()) {
+ std::ostringstream e;
+ e << "Failed to start dumpbin process for:\n " << file;
+ this->SetError(e.str());
+ return false;
+ }
+
+ std::string line;
+ static const cmsys::RegularExpression regex(
+ "^ ([^\n]*\\.[Dd][Ll][Ll])\r$");
+ while (std::getline(*process.OutputStream(), line)) {
+ cmsys::RegularExpressionMatch match;
+ if (regex.find(line.c_str(), match)) {
+ needed.push_back(match.match(1));
+ }
+ }
+
+ if (!process.Wait()) {
+ std::ostringstream e;
+ e << "Failed to wait on dumpbin process for:\n " << file;
+ this->SetError(e.str());
+ return false;
+ }
+ auto status = process.GetStatus();
+ if (!status[0] || status[0]->ExitStatus != 0) {
+ std::ostringstream e;
+ e << "Failed to run dumpbin on:\n " << file;
+ this->SetError(e.str());
+ return false;
+ }
+
+ return true;
+}
diff --git a/Source/cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool.h b/Source/cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool.h
new file mode 100644
index 0000000..4c17f8d
--- /dev/null
+++ b/Source/cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool.h
@@ -0,0 +1,25 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#ifndef cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool_h
+#define cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool_h
+
+#include "cmBinUtilsWindowsPEGetRuntimeDependenciesTool.h"
+
+#include <string>
+#include <vector>
+
+class cmRuntimeDependencyArchive;
+
+class cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool
+ : public cmBinUtilsWindowsPEGetRuntimeDependenciesTool
+{
+public:
+ cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool(
+ cmRuntimeDependencyArchive* archive);
+
+ bool GetFileInfo(const std::string& file,
+ std::vector<std::string>& needed) override;
+};
+
+#endif // cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool_h
diff --git a/Source/cmBinUtilsWindowsPEGetRuntimeDependenciesTool.cxx b/Source/cmBinUtilsWindowsPEGetRuntimeDependenciesTool.cxx
new file mode 100644
index 0000000..f5a4431
--- /dev/null
+++ b/Source/cmBinUtilsWindowsPEGetRuntimeDependenciesTool.cxx
@@ -0,0 +1,18 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmBinUtilsWindowsPEGetRuntimeDependenciesTool.h"
+#include "cmRuntimeDependencyArchive.h"
+
+cmBinUtilsWindowsPEGetRuntimeDependenciesTool::
+ cmBinUtilsWindowsPEGetRuntimeDependenciesTool(
+ cmRuntimeDependencyArchive* archive)
+ : Archive(archive)
+{
+}
+
+void cmBinUtilsWindowsPEGetRuntimeDependenciesTool::SetError(
+ const std::string& error)
+{
+ this->Archive->SetError(error);
+}
diff --git a/Source/cmBinUtilsWindowsPEGetRuntimeDependenciesTool.h b/Source/cmBinUtilsWindowsPEGetRuntimeDependenciesTool.h
new file mode 100644
index 0000000..e9e402b
--- /dev/null
+++ b/Source/cmBinUtilsWindowsPEGetRuntimeDependenciesTool.h
@@ -0,0 +1,28 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#ifndef cmBinUtilsWindowsPEGetRuntimeDependenciesTool_h
+#define cmBinUtilsWindowsPEGetRuntimeDependenciesTool_h
+
+#include <string>
+#include <vector>
+
+class cmRuntimeDependencyArchive;
+
+class cmBinUtilsWindowsPEGetRuntimeDependenciesTool
+{
+public:
+ cmBinUtilsWindowsPEGetRuntimeDependenciesTool(
+ cmRuntimeDependencyArchive* archive);
+ virtual ~cmBinUtilsWindowsPEGetRuntimeDependenciesTool() = default;
+
+ virtual bool GetFileInfo(const std::string& file,
+ std::vector<std::string>& needed) = 0;
+
+protected:
+ cmRuntimeDependencyArchive* Archive;
+
+ void SetError(const std::string& error);
+};
+
+#endif // cmBinUtilsWindowsPEGetRuntimeDependenciesTool_h
diff --git a/Source/cmBinUtilsWindowsPELinker.cxx b/Source/cmBinUtilsWindowsPELinker.cxx
new file mode 100644
index 0000000..796e9ed
--- /dev/null
+++ b/Source/cmBinUtilsWindowsPELinker.cxx
@@ -0,0 +1,121 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmBinUtilsWindowsPELinker.h"
+#include "cmAlgorithms.h"
+#include "cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool.h"
+#include "cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.h"
+#include "cmRuntimeDependencyArchive.h"
+#include "cmSystemTools.h"
+
+#include <memory>
+#include <sstream>
+#include <vector>
+
+#ifdef _WIN32
+# include <windows.h>
+#endif
+
+cmBinUtilsWindowsPELinker::cmBinUtilsWindowsPELinker(
+ cmRuntimeDependencyArchive* archive)
+ : cmBinUtilsLinker(archive)
+{
+}
+
+bool cmBinUtilsWindowsPELinker::Prepare()
+{
+ std::string tool = this->Archive->GetGetRuntimeDependenciesTool();
+ if (tool.empty()) {
+ std::vector<std::string> command;
+ if (this->Archive->GetGetRuntimeDependenciesCommand("dumpbin", command)) {
+ tool = "dumpbin";
+ } else {
+ tool = "objdump";
+ }
+ }
+ if (tool == "dumpbin") {
+ this->Tool =
+ cm::make_unique<cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool>(
+ this->Archive);
+ } else if (tool == "objdump") {
+ this->Tool =
+ cm::make_unique<cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool>(
+ this->Archive);
+ } else {
+ std::ostringstream e;
+ e << "Invalid value for CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL: " << tool;
+ this->SetError(e.str());
+ return false;
+ }
+
+ return true;
+}
+
+bool cmBinUtilsWindowsPELinker::ScanDependencies(
+ std::string const& file, cmStateEnums::TargetType /* unused */)
+{
+ std::vector<std::string> needed;
+ if (!this->Tool->GetFileInfo(file, needed)) {
+ return false;
+ }
+ for (auto& n : needed) {
+ n = cmSystemTools::LowerCase(n);
+ }
+ std::string origin = cmSystemTools::GetFilenamePath(file);
+
+ for (auto const& lib : needed) {
+ if (!this->Archive->IsPreExcluded(lib)) {
+ std::string path;
+ bool resolved = false;
+ if (!this->ResolveDependency(lib, origin, path, resolved)) {
+ return false;
+ }
+ if (resolved) {
+ if (!this->Archive->IsPostExcluded(path)) {
+ bool unique;
+ this->Archive->AddResolvedPath(lib, path, unique);
+ if (unique &&
+ !this->ScanDependencies(path, cmStateEnums::SHARED_LIBRARY)) {
+ return false;
+ }
+ }
+ } else {
+ this->Archive->AddUnresolvedPath(lib);
+ }
+ }
+ }
+
+ return true;
+}
+
+bool cmBinUtilsWindowsPELinker::ResolveDependency(std::string const& name,
+ std::string const& origin,
+ std::string& path,
+ bool& resolved)
+{
+ auto dirs = this->Archive->GetSearchDirectories();
+
+#ifdef _WIN32
+ char buf[MAX_PATH];
+ unsigned int len;
+ if ((len = GetWindowsDirectoryA(buf, MAX_PATH)) > 0) {
+ dirs.insert(dirs.begin(), std::string(buf, len));
+ }
+ if ((len = GetSystemDirectoryA(buf, MAX_PATH)) > 0) {
+ dirs.insert(dirs.begin(), std::string(buf, len));
+ }
+#endif
+
+ dirs.insert(dirs.begin(), origin);
+
+ for (auto const& searchPath : dirs) {
+ path = searchPath + '/' + name;
+ if (cmSystemTools::PathExists(path)) {
+ resolved = true;
+ return true;
+ }
+ }
+
+ resolved = false;
+ return true;
+}
diff --git a/Source/cmBinUtilsWindowsPELinker.h b/Source/cmBinUtilsWindowsPELinker.h
new file mode 100644
index 0000000..d742195
--- /dev/null
+++ b/Source/cmBinUtilsWindowsPELinker.h
@@ -0,0 +1,33 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#ifndef cmBinUtilsWindowsPELinker_h
+#define cmBinUtilsWindowsPELinker_h
+
+#include "cmBinUtilsLinker.h"
+#include "cmBinUtilsWindowsPEGetRuntimeDependenciesTool.h"
+#include "cmStateTypes.h"
+
+#include <memory> // IWYU pragma: keep
+#include <string>
+
+class cmRuntimeDependencyArchive;
+
+class cmBinUtilsWindowsPELinker : public cmBinUtilsLinker
+{
+public:
+ cmBinUtilsWindowsPELinker(cmRuntimeDependencyArchive* archive);
+
+ bool Prepare() override;
+
+ bool ScanDependencies(std::string const& file,
+ cmStateEnums::TargetType type) override;
+
+private:
+ std::unique_ptr<cmBinUtilsWindowsPEGetRuntimeDependenciesTool> Tool;
+
+ bool ResolveDependency(std::string const& name, std::string const& origin,
+ std::string& path, bool& resolved);
+};
+
+#endif // cmBinUtilsWindowsPELinker_h
diff --git a/Source/cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.cxx b/Source/cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.cxx
new file mode 100644
index 0000000..1f27003
--- /dev/null
+++ b/Source/cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.cxx
@@ -0,0 +1,67 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.h"
+#include "cmRuntimeDependencyArchive.h"
+#include "cmUVProcessChain.h"
+
+#include <cmsys/RegularExpression.hxx>
+
+#include <sstream>
+
+cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool::
+ cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool(
+ cmRuntimeDependencyArchive* archive)
+ : cmBinUtilsWindowsPEGetRuntimeDependenciesTool(archive)
+{
+}
+
+bool cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool::GetFileInfo(
+ const std::string& file, std::vector<std::string>& needed)
+{
+ cmUVProcessChainBuilder builder;
+ builder.SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT);
+
+ std::vector<std::string> command;
+ if (!this->Archive->GetGetRuntimeDependenciesCommand("objdump", command)) {
+ this->SetError("Could not find objdump");
+ return false;
+ }
+ command.emplace_back("-p");
+ command.push_back(file);
+ builder.AddCommand(command);
+
+ auto process = builder.Start();
+ if (!process.Valid()) {
+ std::ostringstream e;
+ e << "Failed to start objdump process for:\n " << file;
+ this->SetError(e.str());
+ return false;
+ }
+
+ std::string line;
+ static const cmsys::RegularExpression regex(
+ "^\t*DLL Name: ([^\n]*\\.[Dd][Ll][Ll])\r$");
+ while (std::getline(*process.OutputStream(), line)) {
+ cmsys::RegularExpressionMatch match;
+ if (regex.find(line.c_str(), match)) {
+ needed.push_back(match.match(1));
+ }
+ }
+
+ if (!process.Wait()) {
+ std::ostringstream e;
+ e << "Failed to wait on objdump process for:\n " << file;
+ this->SetError(e.str());
+ return false;
+ }
+ auto status = process.GetStatus();
+ if (!status[0] || status[0]->ExitStatus != 0) {
+ std::ostringstream e;
+ e << "Failed to run objdump on:\n " << file;
+ this->SetError(e.str());
+ return false;
+ }
+
+ return true;
+}
diff --git a/Source/cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.h b/Source/cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.h
new file mode 100644
index 0000000..1d1a5b0
--- /dev/null
+++ b/Source/cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.h
@@ -0,0 +1,25 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#ifndef cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool_h
+#define cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool_h
+
+#include "cmBinUtilsWindowsPEGetRuntimeDependenciesTool.h"
+
+#include <string>
+#include <vector>
+
+class cmRuntimeDependencyArchive;
+
+class cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool
+ : public cmBinUtilsWindowsPEGetRuntimeDependenciesTool
+{
+public:
+ cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool(
+ cmRuntimeDependencyArchive* archive);
+
+ bool GetFileInfo(const std::string& file,
+ std::vector<std::string>& needed) override;
+};
+
+#endif // cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool_h
diff --git a/Source/cmCacheManager.cxx b/Source/cmCacheManager.cxx
index 358f095..e8fc350 100644
--- a/Source/cmCacheManager.cxx
+++ b/Source/cmCacheManager.cxx
@@ -620,7 +620,7 @@
std::vector<std::string> cmCacheManager::CacheEntry::GetPropertyList() const
{
- return this->Properties.GetPropertyList();
+ return this->Properties.GetKeys();
}
const char* cmCacheManager::CacheEntry::GetProperty(
diff --git a/Source/cmDefinitions.cxx b/Source/cmDefinitions.cxx
index 5fafaf9..894447c 100644
--- a/Source/cmDefinitions.cxx
+++ b/Source/cmDefinitions.cxx
@@ -57,8 +57,7 @@
void cmDefinitions::Set(const std::string& key, const char* value)
{
- Def def(value);
- this->Map[key] = def;
+ this->Map[key] = Def(value);
}
std::vector<std::string> cmDefinitions::UnusedKeys() const
diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx
index a12e0c4..c366183 100644
--- a/Source/cmExportFileGenerator.cxx
+++ b/Source/cmExportFileGenerator.cxx
@@ -12,7 +12,6 @@
#include "cmMessageType.h"
#include "cmOutputConverter.h"
#include "cmPolicies.h"
-#include "cmProperty.h"
#include "cmPropertyMap.h"
#include "cmStateTypes.h"
#include "cmSystemTools.h"
@@ -1205,12 +1204,9 @@
std::string& errorMessage)
{
auto& targetProperties = gte->Target->GetProperties();
- const auto& exportProperties = targetProperties.find("EXPORT_PROPERTIES");
- if (exportProperties != targetProperties.end()) {
- std::vector<std::string> propsToExport;
- cmSystemTools::ExpandListArgument(exportProperties->second.GetValue(),
- propsToExport);
- for (auto& prop : propsToExport) {
+ if (const char* exportProperties =
+ targetProperties.GetPropertyValue("EXPORT_PROPERTIES")) {
+ for (auto& prop : cmSystemTools::ExpandedListArgument(exportProperties)) {
/* Black list reserved properties */
if (cmSystemTools::StringStartsWith(prop, "IMPORTED_") ||
cmSystemTools::StringStartsWith(prop, "INTERFACE_")) {
diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx
index 7a3954e..980ad21 100644
--- a/Source/cmFileCommand.cxx
+++ b/Source/cmFileCommand.cxx
@@ -12,7 +12,9 @@
#include <assert.h>
#include <cmath>
#include <ctype.h>
+#include <map>
#include <memory> // IWYU pragma: keep
+#include <set>
#include <sstream>
#include <stdio.h>
#include <stdlib.h>
@@ -34,6 +36,8 @@
#include "cmMessageType.h"
#include "cmPolicies.h"
#include "cmRange.h"
+#include "cmRuntimeDependencyArchive.h"
+#include "cmState.h"
#include "cmSystemTools.h"
#include "cmTimestamp.h"
#include "cm_sys_stat.h"
@@ -184,6 +188,9 @@
if (subCommand == "CREATE_LINK") {
return this->HandleCreateLinkCommand(args);
}
+ if (subCommand == "GET_RUNTIME_DEPENDENCIES") {
+ return this->HandleGetRuntimeDependenciesCommand(args);
+ }
std::string e = "does not recognize sub-command " + subCommand;
this->SetError(e);
@@ -2690,3 +2697,171 @@
return true;
}
+
+bool cmFileCommand::HandleGetRuntimeDependenciesCommand(
+ std::vector<std::string> const& args)
+{
+ static const std::set<std::string> supportedPlatforms = { "Windows", "Linux",
+ "Darwin" };
+ std::string platform =
+ this->Makefile->GetSafeDefinition("CMAKE_HOST_SYSTEM_NAME");
+ if (!supportedPlatforms.count(platform)) {
+ std::ostringstream e;
+ e << "GET_RUNTIME_DEPENDENCIES is not supported on system \"" << platform
+ << "\"";
+ this->SetError(e.str());
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ if (this->Makefile->GetState()->GetMode() == cmState::Project) {
+ this->Makefile->IssueMessage(MessageType::AUTHOR_WARNING,
+ "You have used file(GET_RUNTIME_DEPENDENCIES)"
+ " in project mode. This is probably not what "
+ "you intended to do. Instead, please consider"
+ " using it in an install(CODE) or "
+ "install(SCRIPT) command. For example:"
+ "\n install(CODE [["
+ "\n file(GET_RUNTIME_DEPENDENCIES"
+ "\n # ..."
+ "\n )"
+ "\n ]])");
+ }
+
+ struct Arguments
+ {
+ std::string ResolvedDependenciesVar;
+ std::string UnresolvedDependenciesVar;
+ std::string ConflictingDependenciesPrefix;
+ std::string BundleExecutable;
+ std::vector<std::string> Executables;
+ std::vector<std::string> Libraries;
+ std::vector<std::string> Directories;
+ std::vector<std::string> Modules;
+ std::vector<std::string> PreIncludeRegexes;
+ std::vector<std::string> PreExcludeRegexes;
+ std::vector<std::string> PostIncludeRegexes;
+ std::vector<std::string> PostExcludeRegexes;
+ };
+
+ static auto const parser =
+ cmArgumentParser<Arguments>{}
+ .Bind("RESOLVED_DEPENDENCIES_VAR"_s, &Arguments::ResolvedDependenciesVar)
+ .Bind("UNRESOLVED_DEPENDENCIES_VAR"_s,
+ &Arguments::UnresolvedDependenciesVar)
+ .Bind("CONFLICTING_DEPENDENCIES_PREFIX"_s,
+ &Arguments::ConflictingDependenciesPrefix)
+ .Bind("BUNDLE_EXECUTABLE"_s, &Arguments::BundleExecutable)
+ .Bind("EXECUTABLES"_s, &Arguments::Executables)
+ .Bind("LIBRARIES"_s, &Arguments::Libraries)
+ .Bind("MODULES"_s, &Arguments::Modules)
+ .Bind("DIRECTORIES"_s, &Arguments::Directories)
+ .Bind("PRE_INCLUDE_REGEXES"_s, &Arguments::PreIncludeRegexes)
+ .Bind("PRE_EXCLUDE_REGEXES"_s, &Arguments::PreExcludeRegexes)
+ .Bind("POST_INCLUDE_REGEXES"_s, &Arguments::PostIncludeRegexes)
+ .Bind("POST_EXCLUDE_REGEXES"_s, &Arguments::PostExcludeRegexes);
+
+ std::vector<std::string> unrecognizedArguments;
+ std::vector<std::string> keywordsMissingValues;
+ auto parsedArgs =
+ parser.Parse(cmMakeRange(args).advance(1), &unrecognizedArguments,
+ &keywordsMissingValues);
+ auto argIt = unrecognizedArguments.begin();
+ if (argIt != unrecognizedArguments.end()) {
+ std::ostringstream e;
+ e << "Unrecognized argument: \"" << *argIt << "\"";
+ this->SetError(e.str());
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+ argIt = keywordsMissingValues.begin();
+ if (argIt != keywordsMissingValues.end()) {
+ std::ostringstream e;
+ e << "Keyword missing value: " << *argIt;
+ this->SetError(e.str());
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ cmRuntimeDependencyArchive archive(
+ this, parsedArgs.Directories, parsedArgs.BundleExecutable,
+ parsedArgs.PreIncludeRegexes, parsedArgs.PreExcludeRegexes,
+ parsedArgs.PostIncludeRegexes, parsedArgs.PostExcludeRegexes);
+ if (!archive.Prepare()) {
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ if (!archive.GetRuntimeDependencies(
+ parsedArgs.Executables, parsedArgs.Libraries, parsedArgs.Modules)) {
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ std::vector<std::string> deps, unresolvedDeps, conflictingDeps;
+ for (auto const& val : archive.GetResolvedPaths()) {
+ bool unique = true;
+ auto it = val.second.begin();
+ assert(it != val.second.end());
+ auto const& firstPath = *it;
+ while (++it != val.second.end()) {
+ if (!cmSystemTools::SameFile(firstPath, *it)) {
+ unique = false;
+ break;
+ }
+ }
+
+ if (unique) {
+ deps.push_back(firstPath);
+ } else if (!parsedArgs.ConflictingDependenciesPrefix.empty()) {
+ conflictingDeps.push_back(val.first);
+ std::vector<std::string> paths;
+ paths.insert(paths.begin(), val.second.begin(), val.second.end());
+ std::string varName =
+ parsedArgs.ConflictingDependenciesPrefix + "_" + val.first;
+ std::string pathsStr = cmJoin(paths, ";");
+ this->Makefile->AddDefinition(varName, pathsStr.c_str());
+ } else {
+ std::ostringstream e;
+ e << "Multiple conflicting paths found for " << val.first << ":";
+ for (auto const& path : val.second) {
+ e << "\n " << path;
+ }
+ this->SetError(e.str());
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+ }
+ if (!archive.GetUnresolvedPaths().empty()) {
+ if (!parsedArgs.UnresolvedDependenciesVar.empty()) {
+ unresolvedDeps.insert(unresolvedDeps.begin(),
+ archive.GetUnresolvedPaths().begin(),
+ archive.GetUnresolvedPaths().end());
+ } else {
+ auto it = archive.GetUnresolvedPaths().begin();
+ assert(it != archive.GetUnresolvedPaths().end());
+ std::ostringstream e;
+ e << "Could not resolve file " << *it;
+ this->SetError(e.str());
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+ }
+
+ if (!parsedArgs.ResolvedDependenciesVar.empty()) {
+ std::string val = cmJoin(deps, ";");
+ this->Makefile->AddDefinition(parsedArgs.ResolvedDependenciesVar,
+ val.c_str());
+ }
+ if (!parsedArgs.UnresolvedDependenciesVar.empty()) {
+ std::string val = cmJoin(unresolvedDeps, ";");
+ this->Makefile->AddDefinition(parsedArgs.UnresolvedDependenciesVar,
+ val.c_str());
+ }
+ if (!parsedArgs.ConflictingDependenciesPrefix.empty()) {
+ std::string val = cmJoin(conflictingDeps, ";");
+ this->Makefile->AddDefinition(
+ parsedArgs.ConflictingDependenciesPrefix + "_FILENAMES", val.c_str());
+ }
+ return true;
+}
diff --git a/Source/cmFileCommand.h b/Source/cmFileCommand.h
index 12c5115..cfff894 100644
--- a/Source/cmFileCommand.h
+++ b/Source/cmFileCommand.h
@@ -62,6 +62,8 @@
bool HandleSizeCommand(std::vector<std::string> const& args);
bool HandleReadSymlinkCommand(std::vector<std::string> const& args);
bool HandleCreateLinkCommand(std::vector<std::string> const& args);
+ bool HandleGetRuntimeDependenciesCommand(
+ std::vector<std::string> const& args);
private:
void AddEvaluationFile(const std::string& inputName,
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index 036a07d..de0f371 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -5032,13 +5032,7 @@
std::vector<std::string> cmGeneratorTarget::GetPropertyKeys() const
{
- cmPropertyMap const& propsObject = this->Target->GetProperties();
- std::vector<std::string> props;
- props.reserve(propsObject.size());
- for (auto const& it : propsObject) {
- props.push_back(it.first);
- }
- return props;
+ return this->Target->GetProperties().GetKeys();
}
void cmGeneratorTarget::ReportPropertyOrigin(
diff --git a/Source/cmInstallTargetGenerator.cxx b/Source/cmInstallTargetGenerator.cxx
index 7c5a55b..0774436 100644
--- a/Source/cmInstallTargetGenerator.cxx
+++ b/Source/cmInstallTargetGenerator.cxx
@@ -16,6 +16,8 @@
#include "cmLocalGenerator.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
+#include "cmOutputConverter.h"
+#include "cmPolicies.h"
#include "cmStateTypes.h"
#include "cmSystemTools.h"
#include "cmTarget.h"
@@ -632,17 +634,34 @@
return;
}
- // Get the install RPATH from the link information.
- std::string newRpath = cli->GetChrpathString();
-
// Write a rule to remove the installed file if its rpath is not the
// new rpath. This is needed for existing build/install trees when
// the installed rpath changes but the file is not rebuilt.
- /* clang-format off */
os << indent << "file(RPATH_CHECK\n"
- << indent << " FILE \"" << toDestDirPath << "\"\n"
- << indent << " RPATH \"" << newRpath << "\")\n";
- /* clang-format on */
+ << indent << " FILE \"" << toDestDirPath << "\"\n";
+
+ // CMP0095: ``RPATH`` entries are properly escaped in the intermediary
+ // CMake install script.
+ switch (this->Target->GetPolicyStatusCMP0095()) {
+ case cmPolicies::WARN:
+ // No author warning needed here, we warn later in
+ // cmInstallTargetGenerator::AddChrpathPatchRule().
+ CM_FALLTHROUGH;
+ case cmPolicies::OLD: {
+ // Get the install RPATH from the link information.
+ std::string newRpath = cli->GetChrpathString();
+ os << indent << " RPATH \"" << newRpath << "\")\n";
+ break;
+ }
+ default: {
+ // Get the install RPATH from the link information and
+ // escape any CMake syntax in the install RPATH.
+ std::string escapedNewRpath =
+ cmOutputConverter::EscapeForCMake(cli->GetChrpathString());
+ os << indent << " RPATH " << escapedNewRpath << ")\n";
+ break;
+ }
+ }
}
void cmInstallTargetGenerator::AddChrpathPatchRule(
@@ -731,11 +750,28 @@
return;
}
+ // Escape any CMake syntax in the RPATHs.
+ std::string escapedOldRpath = cmOutputConverter::EscapeForCMake(oldRpath);
+ std::string escapedNewRpath = cmOutputConverter::EscapeForCMake(newRpath);
+
// Write a rule to run chrpath to set the install-tree RPATH
os << indent << "file(RPATH_CHANGE\n"
<< indent << " FILE \"" << toDestDirPath << "\"\n"
- << indent << " OLD_RPATH \"" << oldRpath << "\"\n"
- << indent << " NEW_RPATH \"" << newRpath << "\")\n";
+ << indent << " OLD_RPATH " << escapedOldRpath << "\n";
+
+ // CMP0095: ``RPATH`` entries are properly escaped in the intermediary
+ // CMake install script.
+ switch (this->Target->GetPolicyStatusCMP0095()) {
+ case cmPolicies::WARN:
+ this->IssueCMP0095Warning(newRpath);
+ CM_FALLTHROUGH;
+ case cmPolicies::OLD:
+ os << indent << " NEW_RPATH \"" << newRpath << "\")\n";
+ break;
+ default:
+ os << indent << " NEW_RPATH " << escapedNewRpath << ")\n";
+ break;
+ }
}
}
@@ -838,3 +874,26 @@
<< "\"" << this->Target->Target->GetName() << "\" "
<< "\"" << toDestDirPath << "\")\n";
}
+
+void cmInstallTargetGenerator::IssueCMP0095Warning(
+ const std::string& unescapedRpath)
+{
+ // Reduce warning noise to cases where used RPATHs may actually be affected
+ // by CMP0095. This filter is meant to skip warnings in cases when
+ // non-curly-braces syntax (e.g. $ORIGIN) or no keyword is used which has
+ // worked already before CMP0095. We intend to issue a warning in all cases
+ // with curly-braces syntax, even if the workaround of double-escaping is in
+ // place, since we deprecate the need for it with CMP0095.
+ const bool potentially_affected(unescapedRpath.find("${") !=
+ std::string::npos);
+
+ if (potentially_affected) {
+ std::ostringstream w;
+ w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0095) << "\n";
+ w << "RPATH entries for target '" << this->Target->GetName() << "' "
+ << "will not be escaped in the intermediary "
+ << "cmake_install.cmake script.";
+ this->Target->GetGlobalGenerator()->GetCMakeInstance()->IssueMessage(
+ MessageType::AUTHOR_WARNING, w.str(), this->GetBacktrace());
+ }
+}
diff --git a/Source/cmInstallTargetGenerator.h b/Source/cmInstallTargetGenerator.h
index ed3ab52..9ccad63 100644
--- a/Source/cmInstallTargetGenerator.h
+++ b/Source/cmInstallTargetGenerator.h
@@ -104,6 +104,7 @@
const std::string& toDestDirPath);
void AddUniversalInstallRule(std::ostream& os, Indent indent,
const std::string& toDestDirPath);
+ void IssueCMP0095Warning(const std::string& unescapedRpath);
std::string TargetName;
cmGeneratorTarget* Target;
diff --git a/Source/cmJsonObjects.cxx b/Source/cmJsonObjects.cxx
index 636a8e1..8d065e1 100644
--- a/Source/cmJsonObjects.cxx
+++ b/Source/cmJsonObjects.cxx
@@ -14,7 +14,6 @@
#include "cmLinkLineComputer.h"
#include "cmLocalGenerator.h"
#include "cmMakefile.h"
-#include "cmProperty.h"
#include "cmPropertyMap.h"
#include "cmSourceFile.h"
#include "cmState.h"
@@ -363,12 +362,12 @@
// Build up the list of properties that may have been specified
Json::Value properties = Json::arrayValue;
- for (auto& prop : testInfo->GetProperties()) {
+ for (auto& prop : testInfo->GetProperties().GetList()) {
Json::Value entry = Json::objectValue;
entry[kKEY_KEY] = prop.first;
// Remove config variables from the value too.
- auto cge_value = ge.Parse(prop.second.GetValue());
+ auto cge_value = ge.Parse(prop.second);
const std::string& processed_value = cge_value->Evaluate(lg, config);
entry[kVALUE_KEY] = processed_value;
properties.append(entry);
diff --git a/Source/cmLDConfigLDConfigTool.cxx b/Source/cmLDConfigLDConfigTool.cxx
new file mode 100644
index 0000000..586ea96
--- /dev/null
+++ b/Source/cmLDConfigLDConfigTool.cxx
@@ -0,0 +1,70 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmLDConfigLDConfigTool.h"
+#include "cmMakefile.h"
+#include "cmRuntimeDependencyArchive.h"
+#include "cmSystemTools.h"
+#include "cmUVProcessChain.h"
+
+#include "cmsys/RegularExpression.hxx"
+
+#include <istream>
+#include <string>
+#include <vector>
+
+cmLDConfigLDConfigTool::cmLDConfigLDConfigTool(
+ cmRuntimeDependencyArchive* archive)
+ : cmLDConfigTool(archive)
+{
+}
+
+bool cmLDConfigLDConfigTool::GetLDConfigPaths(std::vector<std::string>& paths)
+{
+ std::string ldConfigPath =
+ this->Archive->GetMakefile()->GetSafeDefinition("CMAKE_LDCONFIG_COMMAND");
+ if (ldConfigPath.empty()) {
+ ldConfigPath = cmSystemTools::FindProgram(
+ "ldconfig", { "/sbin", "/usr/sbin", "/usr/local/sbin" });
+ if (ldConfigPath.empty()) {
+ this->Archive->SetError("Could not find ldconfig");
+ return false;
+ }
+ }
+
+ std::vector<std::string> ldConfigCommand;
+ cmSystemTools::ExpandListArgument(ldConfigPath, ldConfigCommand);
+ ldConfigCommand.emplace_back("-v");
+ ldConfigCommand.emplace_back("-N"); // Don't rebuild the cache.
+ ldConfigCommand.emplace_back("-X"); // Don't update links.
+
+ cmUVProcessChainBuilder builder;
+ builder.SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT)
+ .AddCommand(ldConfigCommand);
+ auto process = builder.Start();
+ if (!process.Valid()) {
+ this->Archive->SetError("Failed to start ldconfig process");
+ return false;
+ }
+
+ std::string line;
+ static const cmsys::RegularExpression regex("^([^\t:]*):");
+ while (std::getline(*process.OutputStream(), line)) {
+ cmsys::RegularExpressionMatch match;
+ if (regex.find(line.c_str(), match)) {
+ paths.push_back(match.match(1));
+ }
+ }
+
+ if (!process.Wait()) {
+ this->Archive->SetError("Failed to wait on ldconfig process");
+ return false;
+ }
+ auto status = process.GetStatus();
+ if (!status[0] || status[0]->ExitStatus != 0) {
+ this->Archive->SetError("Failed to run ldconfig");
+ return false;
+ }
+
+ return true;
+}
diff --git a/Source/cmLDConfigLDConfigTool.h b/Source/cmLDConfigLDConfigTool.h
new file mode 100644
index 0000000..d945a9b
--- /dev/null
+++ b/Source/cmLDConfigLDConfigTool.h
@@ -0,0 +1,22 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#ifndef cmLDConfigLDConfigTool_h
+#define cmLDConfigLDConfigTool_h
+
+#include "cmLDConfigTool.h"
+
+#include <string>
+#include <vector>
+
+class cmRuntimeDependencyArchive;
+
+class cmLDConfigLDConfigTool : public cmLDConfigTool
+{
+public:
+ cmLDConfigLDConfigTool(cmRuntimeDependencyArchive* archive);
+
+ bool GetLDConfigPaths(std::vector<std::string>& paths) override;
+};
+
+#endif
diff --git a/Source/cmLDConfigTool.cxx b/Source/cmLDConfigTool.cxx
new file mode 100644
index 0000000..8d5d563
--- /dev/null
+++ b/Source/cmLDConfigTool.cxx
@@ -0,0 +1,9 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmLDConfigTool.h"
+
+cmLDConfigTool::cmLDConfigTool(cmRuntimeDependencyArchive* archive)
+ : Archive(archive)
+{
+}
diff --git a/Source/cmLDConfigTool.h b/Source/cmLDConfigTool.h
new file mode 100644
index 0000000..c816562
--- /dev/null
+++ b/Source/cmLDConfigTool.h
@@ -0,0 +1,24 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#ifndef cmLDConfigTool_h
+#define cmLDConfigTool_h
+
+#include <string>
+#include <vector>
+
+class cmRuntimeDependencyArchive;
+
+class cmLDConfigTool
+{
+public:
+ cmLDConfigTool(cmRuntimeDependencyArchive* archive);
+ virtual ~cmLDConfigTool() = default;
+
+ virtual bool GetLDConfigPaths(std::vector<std::string>& paths) = 0;
+
+protected:
+ cmRuntimeDependencyArchive* Archive;
+};
+
+#endif
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index fe5c8af..3abf2dd 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -1444,10 +1444,23 @@
std::string linkLanguage = cli.GetLinkLanguage();
- const std::string& libPathFlag =
- this->Makefile->GetRequiredDefinition("CMAKE_LIBRARY_PATH_FLAG");
- const std::string& libPathTerminator =
- this->Makefile->GetSafeDefinition("CMAKE_LIBRARY_PATH_TERMINATOR");
+ std::string libPathFlag;
+ if (const char* value = this->Makefile->GetDefinition(
+ "CMAKE_" + cli.GetLinkLanguage() + "_LIBRARY_PATH_FLAG")) {
+ libPathFlag = value;
+ } else {
+ libPathFlag =
+ this->Makefile->GetRequiredDefinition("CMAKE_LIBRARY_PATH_FLAG");
+ }
+
+ std::string libPathTerminator;
+ if (const char* value = this->Makefile->GetDefinition(
+ "CMAKE_" + cli.GetLinkLanguage() + "_LIBRARY_PATH_TERMINATOR")) {
+ libPathTerminator = value;
+ } else {
+ libPathTerminator =
+ this->Makefile->GetRequiredDefinition("CMAKE_LIBRARY_PATH_TERMINATOR");
+ }
// Add standard libraries for this language.
std::string standardLibsVar = "CMAKE_";
diff --git a/Source/cmOutputConverter.cxx b/Source/cmOutputConverter.cxx
index 7d88b08..d7bcf7e 100644
--- a/Source/cmOutputConverter.cxx
+++ b/Source/cmOutputConverter.cxx
@@ -73,22 +73,10 @@
static bool cmOutputConverterIsShellOperator(const std::string& str)
{
- static std::set<std::string> shellOperators;
- if (shellOperators.empty()) {
- shellOperators.insert("<");
- shellOperators.insert(">");
- shellOperators.insert("<<");
- shellOperators.insert(">>");
- shellOperators.insert("|");
- shellOperators.insert("||");
- shellOperators.insert("&&");
- shellOperators.insert("&>");
- shellOperators.insert("1>");
- shellOperators.insert("2>");
- shellOperators.insert("2>&1");
- shellOperators.insert("1>&2");
- }
- return shellOperators.count(str) > 0;
+ static std::set<std::string> const shellOperators{
+ "<", ">", "<<", ">>", "|", "||", "&&", "&>", "1>", "2>", "2>&1", "1>&2"
+ };
+ return (shellOperators.count(str) != 0);
}
std::string cmOutputConverter::EscapeForShell(const std::string& str,
diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h
index b705119..c16a46f 100644
--- a/Source/cmPolicies.h
+++ b/Source/cmPolicies.h
@@ -279,7 +279,11 @@
SELECT(POLICY, CMP0094, \
"FindPython3, FindPython2 and FindPyton use " \
"LOCATION for lookup strategy.", \
- 3, 15, 0, cmPolicies::WARN)
+ 3, 15, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0095, \
+ "RPATH entries are properly escaped in the intermediary CMake " \
+ "install script.", \
+ 3, 16, 0, cmPolicies::WARN)
#define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
#define CM_FOR_EACH_POLICY_ID(POLICY) \
@@ -307,7 +311,8 @@
F(CMP0073) \
F(CMP0076) \
F(CMP0081) \
- F(CMP0083)
+ F(CMP0083) \
+ F(CMP0095)
/** \class cmPolicies
* \brief Handles changes in CMake behavior and policies
diff --git a/Source/cmProperty.cxx b/Source/cmProperty.cxx
deleted file mode 100644
index 27f0ecd..0000000
--- a/Source/cmProperty.cxx
+++ /dev/null
@@ -1,26 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file Copyright.txt or https://cmake.org/licensing for details. */
-#include "cmProperty.h"
-
-void cmProperty::Set(const char* value)
-{
- this->Value = value;
- this->ValueHasBeenSet = true;
-}
-
-void cmProperty::Append(const char* value, bool asString)
-{
- if (!this->Value.empty() && *value && !asString) {
- this->Value += ";";
- }
- this->Value += value;
- this->ValueHasBeenSet = true;
-}
-
-const char* cmProperty::GetValue() const
-{
- if (this->ValueHasBeenSet) {
- return this->Value.c_str();
- }
- return nullptr;
-}
diff --git a/Source/cmProperty.h b/Source/cmProperty.h
index d11c5ef..80f131a 100644
--- a/Source/cmProperty.h
+++ b/Source/cmProperty.h
@@ -5,8 +5,6 @@
#include "cmConfigure.h" // IWYU pragma: keep
-#include <string>
-
class cmProperty
{
public:
@@ -22,22 +20,6 @@
CACHED_VARIABLE,
INSTALL
};
-
- // set this property
- void Set(const char* value);
-
- // append to this property
- void Append(const char* value, bool asString = false);
-
- // get the value
- const char* GetValue() const;
-
- // construct with the value not set
- cmProperty() { this->ValueHasBeenSet = false; }
-
-protected:
- std::string Value;
- bool ValueHasBeenSet;
};
#endif
diff --git a/Source/cmPropertyMap.cxx b/Source/cmPropertyMap.cxx
index 3f6d7c8..3ed4c05 100644
--- a/Source/cmPropertyMap.cxx
+++ b/Source/cmPropertyMap.cxx
@@ -3,40 +3,21 @@
#include "cmPropertyMap.h"
#include <algorithm>
-#include <assert.h>
#include <utility>
-cmProperty* cmPropertyMap::GetOrCreateProperty(const std::string& name)
+void cmPropertyMap::Clear()
{
- cmPropertyMap::iterator it = this->find(name);
- cmProperty* prop;
- if (it == this->end()) {
- prop = &(*this)[name];
- } else {
- prop = &(it->second);
- }
- return prop;
-}
-
-std::vector<std::string> cmPropertyMap::GetPropertyList() const
-{
- std::vector<std::string> keyList;
- for (auto const& i : *this) {
- keyList.push_back(i.first);
- }
- std::sort(keyList.begin(), keyList.end());
- return keyList;
+ Map_.clear();
}
void cmPropertyMap::SetProperty(const std::string& name, const char* value)
{
if (!value) {
- this->erase(name);
+ Map_.erase(name);
return;
}
- cmProperty* prop = this->GetOrCreateProperty(name);
- prop->Set(value);
+ Map_[name] = value;
}
void cmPropertyMap::AppendProperty(const std::string& name, const char* value,
@@ -47,17 +28,53 @@
return;
}
- cmProperty* prop = this->GetOrCreateProperty(name);
- prop->Append(value, asString);
+ {
+ std::string& pVal = Map_[name];
+ if (!pVal.empty() && !asString) {
+ pVal += ';';
+ }
+ pVal += value;
+ }
+}
+
+void cmPropertyMap::RemoveProperty(const std::string& name)
+{
+ Map_.erase(name);
}
const char* cmPropertyMap::GetPropertyValue(const std::string& name) const
{
- assert(!name.empty());
-
- cmPropertyMap::const_iterator it = this->find(name);
- if (it == this->end()) {
- return nullptr;
+ {
+ auto it = Map_.find(name);
+ if (it != Map_.end()) {
+ return it->second.c_str();
+ }
}
- return it->second.GetValue();
+ return nullptr;
+}
+
+std::vector<std::string> cmPropertyMap::GetKeys() const
+{
+ std::vector<std::string> keyList;
+ keyList.reserve(Map_.size());
+ for (auto const& item : Map_) {
+ keyList.push_back(item.first);
+ }
+ std::sort(keyList.begin(), keyList.end());
+ return keyList;
+}
+
+std::vector<std::pair<std::string, std::string>> cmPropertyMap::GetList() const
+{
+ typedef std::pair<std::string, std::string> StringPair;
+ std::vector<StringPair> kvList;
+ kvList.reserve(Map_.size());
+ for (auto const& item : Map_) {
+ kvList.emplace_back(item.first, item.second);
+ }
+ std::sort(kvList.begin(), kvList.end(),
+ [](StringPair const& a, StringPair const& b) {
+ return a.first < b.first;
+ });
+ return kvList;
}
diff --git a/Source/cmPropertyMap.h b/Source/cmPropertyMap.h
index 5a05150..9aed349 100644
--- a/Source/cmPropertyMap.h
+++ b/Source/cmPropertyMap.h
@@ -5,25 +5,47 @@
#include "cmConfigure.h" // IWYU pragma: keep
-#include "cmProperty.h"
-
-#include <map>
#include <string>
+#include <unordered_map>
+#include <utility>
#include <vector>
-class cmPropertyMap : public std::map<std::string, cmProperty>
+/** \class cmPropertyMap
+ * \brief String property map.
+ */
+class cmPropertyMap
{
public:
- cmProperty* GetOrCreateProperty(const std::string& name);
+ // -- General
- std::vector<std::string> GetPropertyList() const;
+ //! Clear property list
+ void Clear();
+ // -- Properties
+
+ //! Set the property value
void SetProperty(const std::string& name, const char* value);
+ //! Append to the property value
void AppendProperty(const std::string& name, const char* value,
bool asString = false);
+ //! Get the property value
const char* GetPropertyValue(const std::string& name) const;
+
+ //! Remove the property @a name from the map
+ void RemoveProperty(const std::string& name);
+
+ // -- Lists
+
+ //! Get a sorted list of property keys
+ std::vector<std::string> GetKeys() const;
+
+ //! Get a sorted by key list of property key,value pairs
+ std::vector<std::pair<std::string, std::string>> GetList() const;
+
+private:
+ std::unordered_map<std::string, std::string> Map_;
};
#endif
diff --git a/Source/cmRuntimeDependencyArchive.cxx b/Source/cmRuntimeDependencyArchive.cxx
new file mode 100644
index 0000000..b4c6c32
--- /dev/null
+++ b/Source/cmRuntimeDependencyArchive.cxx
@@ -0,0 +1,378 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmRuntimeDependencyArchive.h"
+
+#include "cmAlgorithms.h"
+#include "cmBinUtilsLinuxELFLinker.h"
+#include "cmBinUtilsMacOSMachOLinker.h"
+#include "cmBinUtilsWindowsPELinker.h"
+#include "cmCommand.h"
+#include "cmMakefile.h"
+#include "cmStateTypes.h"
+#include "cmSystemTools.h"
+
+#if defined(_WIN32)
+# include "cmGlobalGenerator.h"
+# ifdef CMAKE_BUILD_WITH_CMAKE
+# include "cmGlobalVisualStudioVersionedGenerator.h"
+# endif
+# include "cmVSSetupHelper.h"
+# include "cmsys/Glob.hxx"
+#endif
+
+#include <algorithm>
+#include <sstream>
+#include <string>
+#include <utility>
+#include <vector>
+
+#if defined(_WIN32)
+static void AddVisualStudioPath(std::vector<std::string>& paths,
+ const std::string& prefix,
+ unsigned int version, cmGlobalGenerator* gg)
+{
+ // If generating for the VS IDE, use the same instance.
+ std::string vsloc;
+ bool found = false;
+# ifdef CMAKE_BUILD_WITH_CMAKE
+ if (gg->GetName().find(prefix) == 0) {
+ cmGlobalVisualStudioVersionedGenerator* vsgen =
+ static_cast<cmGlobalVisualStudioVersionedGenerator*>(gg);
+ if (vsgen->GetVSInstance(vsloc)) {
+ found = true;
+ }
+ }
+# endif
+
+ // Otherwise, find a VS instance ourselves.
+ if (!found) {
+ cmVSSetupAPIHelper vsSetupAPIHelper(version);
+ if (vsSetupAPIHelper.GetVSInstanceInfo(vsloc)) {
+ cmSystemTools::ConvertToUnixSlashes(vsloc);
+ found = true;
+ }
+ }
+
+ if (found) {
+ cmsys::Glob glob;
+ glob.SetListDirs(true);
+ glob.FindFiles(vsloc + "/VC/Tools/MSVC/*");
+ for (auto const& vcdir : glob.GetFiles()) {
+ paths.push_back(vcdir + "/bin/Hostx64/x64");
+ paths.push_back(vcdir + "/bin/Hostx86/x64");
+ paths.push_back(vcdir + "/bin/Hostx64/x86");
+ paths.push_back(vcdir + "/bin/Hostx86/x86");
+ }
+ }
+}
+
+static void AddRegistryPath(std::vector<std::string>& paths,
+ const std::string& path, cmMakefile* mf)
+{
+ // We should view the registry as the target application would view
+ // it.
+ cmSystemTools::KeyWOW64 view = cmSystemTools::KeyWOW64_32;
+ cmSystemTools::KeyWOW64 other_view = cmSystemTools::KeyWOW64_64;
+ if (mf->PlatformIs64Bit()) {
+ view = cmSystemTools::KeyWOW64_64;
+ other_view = cmSystemTools::KeyWOW64_32;
+ }
+
+ // Expand using the view of the target application.
+ std::string expanded = path;
+ cmSystemTools::ExpandRegistryValues(expanded, view);
+ cmSystemTools::GlobDirs(expanded, paths);
+
+ // Executables can be either 32-bit or 64-bit, so expand using the
+ // alternative view.
+ expanded = path;
+ cmSystemTools::ExpandRegistryValues(expanded, other_view);
+ cmSystemTools::GlobDirs(expanded, paths);
+}
+
+static void AddEnvPath(std::vector<std::string>& paths, const std::string& var,
+ const std::string& suffix)
+{
+ std::string value;
+ if (cmSystemTools::GetEnv(var, value)) {
+ paths.push_back(value + suffix);
+ }
+}
+#endif
+
+static cmsys::RegularExpression TransformCompile(const std::string& str)
+{
+ return cmsys::RegularExpression(str);
+}
+
+cmRuntimeDependencyArchive::cmRuntimeDependencyArchive(
+ cmCommand* command, std::vector<std::string> searchDirectories,
+ std::string bundleExecutable,
+ const std::vector<std::string>& preIncludeRegexes,
+ const std::vector<std::string>& preExcludeRegexes,
+ const std::vector<std::string>& postIncludeRegexes,
+ const std::vector<std::string>& postExcludeRegexes)
+ : Command(command)
+ , SearchDirectories(std::move(searchDirectories))
+ , BundleExecutable(std::move(bundleExecutable))
+ , PreIncludeRegexes(preIncludeRegexes.size())
+ , PreExcludeRegexes(preExcludeRegexes.size())
+ , PostIncludeRegexes(postIncludeRegexes.size())
+ , PostExcludeRegexes(postExcludeRegexes.size())
+{
+ std::transform(preIncludeRegexes.begin(), preIncludeRegexes.end(),
+ this->PreIncludeRegexes.begin(), TransformCompile);
+ std::transform(preExcludeRegexes.begin(), preExcludeRegexes.end(),
+ this->PreExcludeRegexes.begin(), TransformCompile);
+ std::transform(postIncludeRegexes.begin(), postIncludeRegexes.end(),
+ this->PostIncludeRegexes.begin(), TransformCompile);
+ std::transform(postExcludeRegexes.begin(), postExcludeRegexes.end(),
+ this->PostExcludeRegexes.begin(), TransformCompile);
+}
+
+bool cmRuntimeDependencyArchive::Prepare()
+{
+ std::string platform = this->GetMakefile()->GetSafeDefinition(
+ "CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM");
+ if (platform.empty()) {
+ std::string systemName =
+ this->GetMakefile()->GetSafeDefinition("CMAKE_HOST_SYSTEM_NAME");
+ if (systemName == "Windows") {
+ platform = "windows+pe";
+ } else if (systemName == "Darwin") {
+ platform = "macos+macho";
+ } else if (systemName == "Linux") {
+ platform = "linux+elf";
+ }
+ }
+ if (platform == "linux+elf") {
+ this->Linker = cm::make_unique<cmBinUtilsLinuxELFLinker>(this);
+ } else if (platform == "windows+pe") {
+ this->Linker = cm::make_unique<cmBinUtilsWindowsPELinker>(this);
+ } else if (platform == "macos+macho") {
+ this->Linker = cm::make_unique<cmBinUtilsMacOSMachOLinker>(this);
+ } else {
+ std::ostringstream e;
+ e << "Invalid value for CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM: "
+ << platform;
+ this->SetError(e.str());
+ return false;
+ }
+
+ return this->Linker->Prepare();
+}
+
+bool cmRuntimeDependencyArchive::GetRuntimeDependencies(
+ const std::vector<std::string>& executables,
+ const std::vector<std::string>& libraries,
+ const std::vector<std::string>& modules)
+{
+ for (auto const& exe : executables) {
+ if (!this->Linker->ScanDependencies(exe, cmStateEnums::EXECUTABLE)) {
+ return false;
+ }
+ }
+ for (auto const& lib : libraries) {
+ if (!this->Linker->ScanDependencies(lib, cmStateEnums::SHARED_LIBRARY)) {
+ return false;
+ }
+ }
+ for (auto const& mod : modules) {
+ if (!this->Linker->ScanDependencies(mod, cmStateEnums::MODULE_LIBRARY)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void cmRuntimeDependencyArchive::SetError(const std::string& e)
+{
+ this->Command->SetError(e);
+}
+
+std::string cmRuntimeDependencyArchive::GetBundleExecutable()
+{
+ return this->BundleExecutable;
+}
+
+const std::vector<std::string>&
+cmRuntimeDependencyArchive::GetSearchDirectories()
+{
+ return this->SearchDirectories;
+}
+
+std::string cmRuntimeDependencyArchive::GetGetRuntimeDependenciesTool()
+{
+ return this->GetMakefile()->GetSafeDefinition(
+ "CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL");
+}
+
+bool cmRuntimeDependencyArchive::GetGetRuntimeDependenciesCommand(
+ const std::string& search, std::vector<std::string>& command)
+{
+ // First see if it was supplied by the user
+ std::string toolCommand = this->GetMakefile()->GetSafeDefinition(
+ "CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND");
+ if (!toolCommand.empty()) {
+ cmSystemTools::ExpandListArgument(toolCommand, command);
+ return true;
+ }
+
+ // Now go searching for it
+ std::vector<std::string> paths;
+#ifdef _WIN32
+ cmGlobalGenerator* gg = this->GetMakefile()->GetGlobalGenerator();
+
+ // Add newer Visual Studio paths
+ AddVisualStudioPath(paths, "Visual Studio 16 ", 16, gg);
+ AddVisualStudioPath(paths, "Visual Studio 15 ", 15, gg);
+
+ // Add older Visual Studio paths
+ AddRegistryPath(
+ paths,
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\14.0;InstallDir]/"
+ "../../VC/bin",
+ this->GetMakefile());
+ AddEnvPath(paths, "VS140COMNTOOLS", "/../../VC/bin");
+ paths.push_back(
+ "C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/bin");
+ AddRegistryPath(
+ paths,
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\12.0;InstallDir]/"
+ "../../VC/bin",
+ this->GetMakefile());
+ AddEnvPath(paths, "VS120COMNTOOLS", "/../../VC/bin");
+ paths.push_back(
+ "C:/Program Files (x86)/Microsoft Visual Studio 12.0/VC/bin");
+ AddRegistryPath(
+ paths,
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\11.0;InstallDir]/"
+ "../../VC/bin",
+ this->GetMakefile());
+ AddEnvPath(paths, "VS110COMNTOOLS", "/../../VC/bin");
+ paths.push_back(
+ "C:/Program Files (x86)/Microsoft Visual Studio 11.0/VC/bin");
+ AddRegistryPath(
+ paths,
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\10.0;InstallDir]/"
+ "../../VC/bin",
+ this->GetMakefile());
+ AddEnvPath(paths, "VS100COMNTOOLS", "/../../VC/bin");
+ paths.push_back(
+ "C:/Program Files (x86)/Microsoft Visual Studio 10.0/VC/bin");
+ AddRegistryPath(
+ paths,
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\9.0;InstallDir]/"
+ "../../VC/bin",
+ this->GetMakefile());
+ AddEnvPath(paths, "VS90COMNTOOLS", "/../../VC/bin");
+ paths.push_back("C:/Program Files/Microsoft Visual Studio 9.0/VC/bin");
+ paths.push_back("C:/Program Files (x86)/Microsoft Visual Studio 9.0/VC/bin");
+ AddRegistryPath(
+ paths,
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0;InstallDir]/"
+ "../../VC/bin",
+ this->GetMakefile());
+ AddEnvPath(paths, "VS80COMNTOOLS", "/../../VC/bin");
+ paths.push_back("C:/Program Files/Microsoft Visual Studio 8/VC/BIN");
+ paths.push_back("C:/Program Files (x86)/Microsoft Visual Studio 8/VC/BIN");
+ AddRegistryPath(
+ paths,
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\7.1;InstallDir]/"
+ "../../VC7/bin",
+ this->GetMakefile());
+ AddEnvPath(paths, "VS71COMNTOOLS", "/../../VC7/bin");
+ paths.push_back(
+ "C:/Program Files/Microsoft Visual Studio .NET 2003/VC7/BIN");
+ paths.push_back(
+ "C:/Program Files (x86)/Microsoft Visual Studio .NET 2003/VC7/BIN");
+#endif
+
+ std::string program = cmSystemTools::FindProgram(search, paths);
+ if (!program.empty()) {
+ command = { program };
+ return true;
+ }
+
+ // Couldn't find it
+ return false;
+}
+
+bool cmRuntimeDependencyArchive::IsPreExcluded(const std::string& name)
+{
+ cmsys::RegularExpressionMatch match;
+
+ for (auto const& regex : this->PreIncludeRegexes) {
+ if (regex.find(name.c_str(), match)) {
+ return false;
+ }
+ }
+
+ for (auto const& regex : this->PreExcludeRegexes) {
+ if (regex.find(name.c_str(), match)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool cmRuntimeDependencyArchive::IsPostExcluded(const std::string& name)
+{
+ cmsys::RegularExpressionMatch match;
+
+ for (auto const& regex : this->PostIncludeRegexes) {
+ if (regex.find(name.c_str(), match)) {
+ return false;
+ }
+ }
+
+ for (auto const& regex : this->PostExcludeRegexes) {
+ if (regex.find(name.c_str(), match)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void cmRuntimeDependencyArchive::AddResolvedPath(const std::string& name,
+ const std::string& path,
+ bool& unique)
+{
+ auto it =
+ this->ResolvedPaths
+ .insert(std::pair<std::string, std::set<std::string>>{ name, {} })
+ .first;
+ unique = true;
+ for (auto const& other : it->second) {
+ if (cmSystemTools::SameFile(path, other)) {
+ unique = false;
+ break;
+ }
+ }
+ it->second.insert(path);
+}
+
+void cmRuntimeDependencyArchive::AddUnresolvedPath(const std::string& name)
+{
+ this->UnresolvedPaths.insert(name);
+}
+
+cmMakefile* cmRuntimeDependencyArchive::GetMakefile()
+{
+ return this->Command->GetMakefile();
+}
+
+const std::map<std::string, std::set<std::string>>&
+cmRuntimeDependencyArchive::GetResolvedPaths()
+{
+ return this->ResolvedPaths;
+}
+
+const std::set<std::string>& cmRuntimeDependencyArchive::GetUnresolvedPaths()
+{
+ return this->UnresolvedPaths;
+}
diff --git a/Source/cmRuntimeDependencyArchive.h b/Source/cmRuntimeDependencyArchive.h
new file mode 100644
index 0000000..ec3ecd4
--- /dev/null
+++ b/Source/cmRuntimeDependencyArchive.h
@@ -0,0 +1,70 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#ifndef cmRuntimeDependencyArchive_h
+#define cmRuntimeDependencyArchive_h
+
+#include "cmBinUtilsLinker.h"
+
+#include "cmsys/RegularExpression.hxx"
+
+#include <map>
+#include <memory> // IWYU pragma: keep
+#include <set>
+#include <string>
+#include <vector>
+
+class cmCommand;
+class cmMakefile;
+
+class cmRuntimeDependencyArchive
+{
+public:
+ explicit cmRuntimeDependencyArchive(
+ cmCommand* command, std::vector<std::string> searchDirectories,
+ std::string bundleExecutable,
+ const std::vector<std::string>& preIncludeRegexes,
+ const std::vector<std::string>& preExcludeRegexes,
+ const std::vector<std::string>& postIncludeRegexes,
+ const std::vector<std::string>& postExcludeRegexes);
+ bool Prepare();
+ bool GetRuntimeDependencies(const std::vector<std::string>& executables,
+ const std::vector<std::string>& libraries,
+ const std::vector<std::string>& modules);
+
+ void SetError(const std::string& e);
+
+ std::string GetBundleExecutable();
+ const std::vector<std::string>& GetSearchDirectories();
+ std::string GetGetRuntimeDependenciesTool();
+ bool GetGetRuntimeDependenciesCommand(const std::string& search,
+ std::vector<std::string>& command);
+ bool IsPreExcluded(const std::string& name);
+ bool IsPostExcluded(const std::string& name);
+
+ void AddResolvedPath(const std::string& name, const std::string& path,
+ bool& unique);
+ void AddUnresolvedPath(const std::string& name);
+
+ cmMakefile* GetMakefile();
+ const std::map<std::string, std::set<std::string>>& GetResolvedPaths();
+ const std::set<std::string>& GetUnresolvedPaths();
+
+private:
+ cmCommand* Command;
+ std::unique_ptr<cmBinUtilsLinker> Linker;
+
+ std::string GetRuntimeDependenciesTool;
+ std::vector<std::string> GetRuntimeDependenciesCommand;
+
+ std::vector<std::string> SearchDirectories;
+ std::string BundleExecutable;
+ std::vector<cmsys::RegularExpression> PreIncludeRegexes;
+ std::vector<cmsys::RegularExpression> PreExcludeRegexes;
+ std::vector<cmsys::RegularExpression> PostIncludeRegexes;
+ std::vector<cmsys::RegularExpression> PostExcludeRegexes;
+ std::map<std::string, std::set<std::string>> ResolvedPaths;
+ std::set<std::string> UnresolvedPaths;
+};
+
+#endif // cmRuntimeDependencyArchive_h
diff --git a/Source/cmState.cxx b/Source/cmState.cxx
index fa7df0b..091c2e0 100644
--- a/Source/cmState.cxx
+++ b/Source/cmState.cxx
@@ -267,7 +267,7 @@
cmStateSnapshot cmState::Reset()
{
- this->GlobalProperties.clear();
+ this->GlobalProperties.Clear();
this->PropertyDefinitions.clear();
this->GlobVerificationManager->Reset();
@@ -289,7 +289,7 @@
it->LinkDirectoriesBacktraces.clear();
it->DirectoryEnd = pos;
it->NormalTargetNames.clear();
- it->Properties.clear();
+ it->Properties.Clear();
it->Children.clear();
}
diff --git a/Source/cmStateDirectory.cxx b/Source/cmStateDirectory.cxx
index 182d3fe..6ca1c9f 100644
--- a/Source/cmStateDirectory.cxx
+++ b/Source/cmStateDirectory.cxx
@@ -6,7 +6,6 @@
#include <algorithm>
#include <assert.h>
#include <iterator>
-#include <utility>
#include "cmAlgorithms.h"
#include "cmProperty.h"
@@ -667,12 +666,7 @@
std::vector<std::string> cmStateDirectory::GetPropertyKeys() const
{
- std::vector<std::string> keys;
- keys.reserve(this->DirectoryState->Properties.size());
- for (auto const& it : this->DirectoryState->Properties) {
- keys.push_back(it.first);
- }
- return keys;
+ return this->DirectoryState->Properties.GetKeys();
}
void cmStateDirectory::AddNormalTargetName(std::string const& name)
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index cd67586..b10b30f 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -231,14 +231,21 @@
impl->IsAndroid =
(impl->Makefile->GetSafeDefinition("CMAKE_SYSTEM_NAME") == "Android");
- std::string gKey;
- gKey.reserve(128);
- gKey += "CMAKE_";
- auto InitProperty = [this, mf, &gKey](const std::string& property,
- const char* default_value) {
+ std::string defKey;
+ defKey.reserve(128);
+ defKey += "CMAKE_";
+ auto initProp = [this, mf, &defKey](const std::string& property) {
// Replace everything after "CMAKE_"
- gKey.replace(gKey.begin() + 6, gKey.end(), property);
- if (const char* value = mf->GetDefinition(gKey)) {
+ defKey.replace(defKey.begin() + 6, defKey.end(), property);
+ if (const char* value = mf->GetDefinition(defKey)) {
+ this->SetProperty(property, value);
+ }
+ };
+ auto initPropValue = [this, mf, &defKey](const std::string& property,
+ const char* default_value) {
+ // Replace everything after "CMAKE_"
+ defKey.replace(defKey.begin() + 6, defKey.end(), property);
+ if (const char* value = mf->GetDefinition(defKey)) {
this->SetProperty(property, value);
} else if (default_value) {
this->SetProperty(property, default_value);
@@ -248,107 +255,107 @@
// Setup default property values.
if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY &&
this->GetType() != cmStateEnums::UTILITY) {
- InitProperty("ANDROID_API", nullptr);
- InitProperty("ANDROID_API_MIN", nullptr);
- InitProperty("ANDROID_ARCH", nullptr);
- InitProperty("ANDROID_STL_TYPE", nullptr);
- InitProperty("ANDROID_SKIP_ANT_STEP", nullptr);
- InitProperty("ANDROID_PROCESS_MAX", nullptr);
- InitProperty("ANDROID_PROGUARD", nullptr);
- InitProperty("ANDROID_PROGUARD_CONFIG_PATH", nullptr);
- InitProperty("ANDROID_SECURE_PROPS_PATH", nullptr);
- InitProperty("ANDROID_NATIVE_LIB_DIRECTORIES", nullptr);
- InitProperty("ANDROID_NATIVE_LIB_DEPENDENCIES", nullptr);
- InitProperty("ANDROID_JAVA_SOURCE_DIR", nullptr);
- InitProperty("ANDROID_JAR_DIRECTORIES", nullptr);
- InitProperty("ANDROID_JAR_DEPENDENCIES", nullptr);
- InitProperty("ANDROID_ASSETS_DIRECTORIES", nullptr);
- InitProperty("ANDROID_ANT_ADDITIONAL_OPTIONS", nullptr);
- InitProperty("BUILD_RPATH", nullptr);
- InitProperty("BUILD_RPATH_USE_ORIGIN", nullptr);
- InitProperty("INSTALL_NAME_DIR", nullptr);
- InitProperty("INSTALL_RPATH", "");
- InitProperty("INSTALL_RPATH_USE_LINK_PATH", "OFF");
- InitProperty("INTERPROCEDURAL_OPTIMIZATION", nullptr);
- InitProperty("SKIP_BUILD_RPATH", "OFF");
- InitProperty("BUILD_WITH_INSTALL_RPATH", "OFF");
- InitProperty("ARCHIVE_OUTPUT_DIRECTORY", nullptr);
- InitProperty("LIBRARY_OUTPUT_DIRECTORY", nullptr);
- InitProperty("RUNTIME_OUTPUT_DIRECTORY", nullptr);
- InitProperty("PDB_OUTPUT_DIRECTORY", nullptr);
- InitProperty("COMPILE_PDB_OUTPUT_DIRECTORY", nullptr);
- InitProperty("FRAMEWORK", nullptr);
- InitProperty("Fortran_FORMAT", nullptr);
- InitProperty("Fortran_MODULE_DIRECTORY", nullptr);
- InitProperty("Fortran_COMPILER_LAUNCHER", nullptr);
- InitProperty("GNUtoMS", nullptr);
- InitProperty("OSX_ARCHITECTURES", nullptr);
- InitProperty("IOS_INSTALL_COMBINED", nullptr);
- InitProperty("AUTOMOC", nullptr);
- InitProperty("AUTOUIC", nullptr);
- InitProperty("AUTORCC", nullptr);
- InitProperty("AUTOGEN_ORIGIN_DEPENDS", nullptr);
- InitProperty("AUTOGEN_PARALLEL", nullptr);
- InitProperty("AUTOMOC_COMPILER_PREDEFINES", nullptr);
- InitProperty("AUTOMOC_DEPEND_FILTERS", nullptr);
- InitProperty("AUTOMOC_MACRO_NAMES", nullptr);
- InitProperty("AUTOMOC_MOC_OPTIONS", nullptr);
- InitProperty("AUTOUIC_OPTIONS", nullptr);
- InitProperty("AUTOUIC_SEARCH_PATHS", nullptr);
- InitProperty("AUTORCC_OPTIONS", nullptr);
- InitProperty("LINK_DEPENDS_NO_SHARED", nullptr);
- InitProperty("LINK_INTERFACE_LIBRARIES", nullptr);
- InitProperty("MSVC_RUNTIME_LIBRARY", nullptr);
- InitProperty("WIN32_EXECUTABLE", nullptr);
- InitProperty("MACOSX_BUNDLE", nullptr);
- InitProperty("MACOSX_RPATH", nullptr);
- InitProperty("NO_SYSTEM_FROM_IMPORTED", nullptr);
- InitProperty("BUILD_WITH_INSTALL_NAME_DIR", nullptr);
- InitProperty("C_CLANG_TIDY", nullptr);
- InitProperty("C_COMPILER_LAUNCHER", nullptr);
- InitProperty("C_CPPLINT", nullptr);
- InitProperty("C_CPPCHECK", nullptr);
- InitProperty("C_INCLUDE_WHAT_YOU_USE", nullptr);
- InitProperty("LINK_WHAT_YOU_USE", nullptr);
- InitProperty("C_STANDARD", nullptr);
- InitProperty("C_STANDARD_REQUIRED", nullptr);
- InitProperty("C_EXTENSIONS", nullptr);
- InitProperty("CXX_CLANG_TIDY", nullptr);
- InitProperty("CXX_COMPILER_LAUNCHER", nullptr);
- InitProperty("CXX_CPPLINT", nullptr);
- InitProperty("CXX_CPPCHECK", nullptr);
- InitProperty("CXX_INCLUDE_WHAT_YOU_USE", nullptr);
- InitProperty("CXX_STANDARD", nullptr);
- InitProperty("CXX_STANDARD_REQUIRED", nullptr);
- InitProperty("CXX_EXTENSIONS", nullptr);
- InitProperty("CUDA_STANDARD", nullptr);
- InitProperty("CUDA_STANDARD_REQUIRED", nullptr);
- InitProperty("CUDA_EXTENSIONS", nullptr);
- InitProperty("CUDA_COMPILER_LAUNCHER", nullptr);
- InitProperty("CUDA_SEPARABLE_COMPILATION", nullptr);
- InitProperty("LINK_SEARCH_START_STATIC", nullptr);
- InitProperty("LINK_SEARCH_END_STATIC", nullptr);
- InitProperty("FOLDER", nullptr);
- InitProperty("Swift_MODULE_DIRECTORY", nullptr);
- InitProperty("VS_JUST_MY_CODE_DEBUGGING", nullptr);
+ initProp("ANDROID_API");
+ initProp("ANDROID_API_MIN");
+ initProp("ANDROID_ARCH");
+ initProp("ANDROID_STL_TYPE");
+ initProp("ANDROID_SKIP_ANT_STEP");
+ initProp("ANDROID_PROCESS_MAX");
+ initProp("ANDROID_PROGUARD");
+ initProp("ANDROID_PROGUARD_CONFIG_PATH");
+ initProp("ANDROID_SECURE_PROPS_PATH");
+ initProp("ANDROID_NATIVE_LIB_DIRECTORIES");
+ initProp("ANDROID_NATIVE_LIB_DEPENDENCIES");
+ initProp("ANDROID_JAVA_SOURCE_DIR");
+ initProp("ANDROID_JAR_DIRECTORIES");
+ initProp("ANDROID_JAR_DEPENDENCIES");
+ initProp("ANDROID_ASSETS_DIRECTORIES");
+ initProp("ANDROID_ANT_ADDITIONAL_OPTIONS");
+ initProp("BUILD_RPATH");
+ initProp("BUILD_RPATH_USE_ORIGIN");
+ initProp("INSTALL_NAME_DIR");
+ initPropValue("INSTALL_RPATH", "");
+ initPropValue("INSTALL_RPATH_USE_LINK_PATH", "OFF");
+ initProp("INTERPROCEDURAL_OPTIMIZATION");
+ initPropValue("SKIP_BUILD_RPATH", "OFF");
+ initPropValue("BUILD_WITH_INSTALL_RPATH", "OFF");
+ initProp("ARCHIVE_OUTPUT_DIRECTORY");
+ initProp("LIBRARY_OUTPUT_DIRECTORY");
+ initProp("RUNTIME_OUTPUT_DIRECTORY");
+ initProp("PDB_OUTPUT_DIRECTORY");
+ initProp("COMPILE_PDB_OUTPUT_DIRECTORY");
+ initProp("FRAMEWORK");
+ initProp("Fortran_FORMAT");
+ initProp("Fortran_MODULE_DIRECTORY");
+ initProp("Fortran_COMPILER_LAUNCHER");
+ initProp("GNUtoMS");
+ initProp("OSX_ARCHITECTURES");
+ initProp("IOS_INSTALL_COMBINED");
+ initProp("AUTOMOC");
+ initProp("AUTOUIC");
+ initProp("AUTORCC");
+ initProp("AUTOGEN_ORIGIN_DEPENDS");
+ initProp("AUTOGEN_PARALLEL");
+ initProp("AUTOMOC_COMPILER_PREDEFINES");
+ initProp("AUTOMOC_DEPEND_FILTERS");
+ initProp("AUTOMOC_MACRO_NAMES");
+ initProp("AUTOMOC_MOC_OPTIONS");
+ initProp("AUTOUIC_OPTIONS");
+ initProp("AUTOUIC_SEARCH_PATHS");
+ initProp("AUTORCC_OPTIONS");
+ initProp("LINK_DEPENDS_NO_SHARED");
+ initProp("LINK_INTERFACE_LIBRARIES");
+ initProp("MSVC_RUNTIME_LIBRARY");
+ initProp("WIN32_EXECUTABLE");
+ initProp("MACOSX_BUNDLE");
+ initProp("MACOSX_RPATH");
+ initProp("NO_SYSTEM_FROM_IMPORTED");
+ initProp("BUILD_WITH_INSTALL_NAME_DIR");
+ initProp("C_CLANG_TIDY");
+ initProp("C_COMPILER_LAUNCHER");
+ initProp("C_CPPLINT");
+ initProp("C_CPPCHECK");
+ initProp("C_INCLUDE_WHAT_YOU_USE");
+ initProp("LINK_WHAT_YOU_USE");
+ initProp("C_STANDARD");
+ initProp("C_STANDARD_REQUIRED");
+ initProp("C_EXTENSIONS");
+ initProp("CXX_CLANG_TIDY");
+ initProp("CXX_COMPILER_LAUNCHER");
+ initProp("CXX_CPPLINT");
+ initProp("CXX_CPPCHECK");
+ initProp("CXX_INCLUDE_WHAT_YOU_USE");
+ initProp("CXX_STANDARD");
+ initProp("CXX_STANDARD_REQUIRED");
+ initProp("CXX_EXTENSIONS");
+ initProp("CUDA_STANDARD");
+ initProp("CUDA_STANDARD_REQUIRED");
+ initProp("CUDA_EXTENSIONS");
+ initProp("CUDA_COMPILER_LAUNCHER");
+ initProp("CUDA_SEPARABLE_COMPILATION");
+ initProp("LINK_SEARCH_START_STATIC");
+ initProp("LINK_SEARCH_END_STATIC");
+ initProp("FOLDER");
+ initProp("Swift_MODULE_DIRECTORY");
+ initProp("VS_JUST_MY_CODE_DEBUGGING");
#ifdef __APPLE__
if (this->GetGlobalGenerator()->IsXcode()) {
- InitProperty("XCODE_GENERATE_SCHEME", nullptr);
- InitProperty("XCODE_SCHEME_ADDRESS_SANITIZER", nullptr);
- InitProperty("XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN", nullptr);
- InitProperty("XCODE_SCHEME_THREAD_SANITIZER", nullptr);
- InitProperty("XCODE_SCHEME_THREAD_SANITIZER_STOP", nullptr);
- InitProperty("XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER", nullptr);
- InitProperty("XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP", nullptr);
- InitProperty("XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER", nullptr);
- InitProperty("XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP", nullptr);
- InitProperty("XCODE_SCHEME_MALLOC_SCRIBBLE", nullptr);
- InitProperty("XCODE_SCHEME_MALLOC_GUARD_EDGES", nullptr);
- InitProperty("XCODE_SCHEME_GUARD_MALLOC", nullptr);
- InitProperty("XCODE_SCHEME_ZOMBIE_OBJECTS", nullptr);
- InitProperty("XCODE_SCHEME_MALLOC_STACK", nullptr);
- InitProperty("XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE", nullptr);
- InitProperty("XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS", nullptr);
+ initProp("XCODE_GENERATE_SCHEME");
+ initProp("XCODE_SCHEME_ADDRESS_SANITIZER");
+ initProp("XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN");
+ initProp("XCODE_SCHEME_THREAD_SANITIZER");
+ initProp("XCODE_SCHEME_THREAD_SANITIZER_STOP");
+ initProp("XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER");
+ initProp("XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP");
+ initProp("XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER");
+ initProp("XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP");
+ initProp("XCODE_SCHEME_MALLOC_SCRIBBLE");
+ initProp("XCODE_SCHEME_MALLOC_GUARD_EDGES");
+ initProp("XCODE_SCHEME_GUARD_MALLOC");
+ initProp("XCODE_SCHEME_ZOMBIE_OBJECTS");
+ initProp("XCODE_SCHEME_MALLOC_STACK");
+ initProp("XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE");
+ initProp("XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS");
}
#endif
}
@@ -376,7 +383,7 @@
}
std::string property = prop;
property += configUpper;
- InitProperty(property, nullptr);
+ initProp(property);
}
// Initialize per-configuration name postfix property from the
@@ -388,7 +395,7 @@
impl->TargetType != cmStateEnums::INTERFACE_LIBRARY) {
std::string property = cmSystemTools::UpperCase(configName);
property += "_POSTFIX";
- InitProperty(property, nullptr);
+ initProp(property);
}
}
}
@@ -427,16 +434,16 @@
if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY &&
this->GetType() != cmStateEnums::UTILITY) {
- InitProperty("C_VISIBILITY_PRESET", nullptr);
- InitProperty("CXX_VISIBILITY_PRESET", nullptr);
- InitProperty("CUDA_VISIBILITY_PRESET", nullptr);
- InitProperty("VISIBILITY_INLINES_HIDDEN", nullptr);
+ initProp("C_VISIBILITY_PRESET");
+ initProp("CXX_VISIBILITY_PRESET");
+ initProp("CUDA_VISIBILITY_PRESET");
+ initProp("VISIBILITY_INLINES_HIDDEN");
}
if (impl->TargetType == cmStateEnums::EXECUTABLE) {
- InitProperty("ANDROID_GUI", nullptr);
- InitProperty("CROSSCOMPILING_EMULATOR", nullptr);
- InitProperty("ENABLE_EXPORTS", nullptr);
+ initProp("ANDROID_GUI");
+ initProp("CROSSCOMPILING_EMULATOR");
+ initProp("ENABLE_EXPORTS");
}
if (impl->TargetType == cmStateEnums::SHARED_LIBRARY ||
impl->TargetType == cmStateEnums::MODULE_LIBRARY) {
@@ -444,12 +451,12 @@
}
if (impl->TargetType == cmStateEnums::SHARED_LIBRARY ||
impl->TargetType == cmStateEnums::EXECUTABLE) {
- InitProperty("WINDOWS_EXPORT_ALL_SYMBOLS", nullptr);
+ initProp("WINDOWS_EXPORT_ALL_SYMBOLS");
}
if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY &&
this->GetType() != cmStateEnums::UTILITY) {
- InitProperty("POSITION_INDEPENDENT_CODE", nullptr);
+ initProp("POSITION_INDEPENDENT_CODE");
}
// Record current policies for later use.
@@ -465,12 +472,12 @@
if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY &&
this->GetType() != cmStateEnums::UTILITY) {
- InitProperty("JOB_POOL_COMPILE", nullptr);
- InitProperty("JOB_POOL_LINK", nullptr);
+ initProp("JOB_POOL_COMPILE");
+ initProp("JOB_POOL_LINK");
}
if (impl->TargetType <= cmStateEnums::UTILITY) {
- InitProperty("DOTNET_TARGET_FRAMEWORK_VERSION", nullptr);
+ initProp("DOTNET_TARGET_FRAMEWORK_VERSION");
}
if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY &&
@@ -491,7 +498,7 @@
if (assignment != std::string::npos) {
const std::string propName = vsGlobal + i.substr(0, assignment);
const std::string propValue = i.substr(assignment + 1);
- InitProperty(propName, propValue.c_str());
+ initPropValue(propName, propValue.c_str());
}
}
}
@@ -1484,7 +1491,6 @@
const char* cmTarget::GetProperty(const std::string& prop) const
{
- static std::unordered_set<std::string> specialProps;
#define MAKE_STATIC_PROP(PROP) static const std::string prop##PROP = #PROP
MAKE_STATIC_PROP(LINK_LIBRARIES);
MAKE_STATIC_PROP(TYPE);
@@ -1502,23 +1508,23 @@
MAKE_STATIC_PROP(SOURCE_DIR);
MAKE_STATIC_PROP(SOURCES);
#undef MAKE_STATIC_PROP
- if (specialProps.empty()) {
- specialProps.insert(propLINK_LIBRARIES);
- specialProps.insert(propTYPE);
- specialProps.insert(propINCLUDE_DIRECTORIES);
- specialProps.insert(propCOMPILE_FEATURES);
- specialProps.insert(propCOMPILE_OPTIONS);
- specialProps.insert(propCOMPILE_DEFINITIONS);
- specialProps.insert(propLINK_OPTIONS);
- specialProps.insert(propLINK_DIRECTORIES);
- specialProps.insert(propIMPORTED);
- specialProps.insert(propIMPORTED_GLOBAL);
- specialProps.insert(propMANUALLY_ADDED_DEPENDENCIES);
- specialProps.insert(propNAME);
- specialProps.insert(propBINARY_DIR);
- specialProps.insert(propSOURCE_DIR);
- specialProps.insert(propSOURCES);
- }
+ static std::unordered_set<std::string> const specialProps{
+ propLINK_LIBRARIES,
+ propTYPE,
+ propINCLUDE_DIRECTORIES,
+ propCOMPILE_FEATURES,
+ propCOMPILE_OPTIONS,
+ propCOMPILE_DEFINITIONS,
+ propLINK_OPTIONS,
+ propLINK_DIRECTORIES,
+ propIMPORTED,
+ propIMPORTED_GLOBAL,
+ propMANUALLY_ADDED_DEPENDENCIES,
+ propNAME,
+ propBINARY_DIR,
+ propSOURCE_DIR,
+ propSOURCES
+ };
if (specialProps.count(prop)) {
if (prop == propLINK_LIBRARIES) {
if (impl->LinkImplementationPropertyEntries.empty()) {
diff --git a/Source/cmTargetPropertyComputer.cxx b/Source/cmTargetPropertyComputer.cxx
index 3f763af..eac300f 100644
--- a/Source/cmTargetPropertyComputer.cxx
+++ b/Source/cmTargetPropertyComputer.cxx
@@ -56,22 +56,21 @@
if (std::islower(prop[0])) {
return true;
}
- static std::unordered_set<std::string> builtIns;
- if (builtIns.empty()) {
- builtIns.insert("COMPATIBLE_INTERFACE_BOOL");
- builtIns.insert("COMPATIBLE_INTERFACE_NUMBER_MAX");
- builtIns.insert("COMPATIBLE_INTERFACE_NUMBER_MIN");
- builtIns.insert("COMPATIBLE_INTERFACE_STRING");
- builtIns.insert("EXPORT_NAME");
- builtIns.insert("EXPORT_PROPERTIES");
- builtIns.insert("IMPORTED");
- builtIns.insert("IMPORTED_GLOBAL");
- builtIns.insert("MANUALLY_ADDED_DEPENDENCIES");
- builtIns.insert("NAME");
- builtIns.insert("PRIVATE_HEADER");
- builtIns.insert("PUBLIC_HEADER");
- builtIns.insert("TYPE");
- }
+ static std::unordered_set<std::string> const builtIns{
+ "COMPATIBLE_INTERFACE_BOOL",
+ "COMPATIBLE_INTERFACE_NUMBER_MAX",
+ "COMPATIBLE_INTERFACE_NUMBER_MIN",
+ "COMPATIBLE_INTERFACE_STRING",
+ "EXPORT_NAME",
+ "EXPORT_PROPERTIES",
+ "IMPORTED",
+ "IMPORTED_GLOBAL",
+ "MANUALLY_ADDED_DEPENDENCIES",
+ "NAME",
+ "PRIVATE_HEADER",
+ "PUBLIC_HEADER",
+ "TYPE"
+ };
if (builtIns.count(prop)) {
return true;
diff --git a/Source/cmTest.cxx b/Source/cmTest.cxx
index 7d45cf5..01f2b96 100644
--- a/Source/cmTest.cxx
+++ b/Source/cmTest.cxx
@@ -8,7 +8,8 @@
#include "cmSystemTools.h"
cmTest::cmTest(cmMakefile* mf)
- : Backtrace(mf->GetBacktrace())
+ : CommandExpandLists(false)
+ , Backtrace(mf->GetBacktrace())
{
this->Makefile = mf;
this->OldStyle = true;
@@ -59,3 +60,13 @@
{
this->Properties.AppendProperty(prop, value, asString);
}
+
+bool cmTest::GetCommandExpandLists() const
+{
+ return this->CommandExpandLists;
+}
+
+void cmTest::SetCommandExpandLists(bool b)
+{
+ this->CommandExpandLists = b;
+}
diff --git a/Source/cmTest.h b/Source/cmTest.h
index 88dc730..02d8f46 100644
--- a/Source/cmTest.h
+++ b/Source/cmTest.h
@@ -51,10 +51,15 @@
bool GetOldStyle() const { return this->OldStyle; }
void SetOldStyle(bool b) { this->OldStyle = b; }
+ /** Set/Get whether lists in command lines should be expanded. */
+ bool GetCommandExpandLists() const;
+ void SetCommandExpandLists(bool b);
+
private:
cmPropertyMap Properties;
std::string Name;
std::vector<std::string> Command;
+ bool CommandExpandLists;
bool OldStyle;
diff --git a/Source/cmTestGenerator.cxx b/Source/cmTestGenerator.cxx
index 571cd09..498953e 100644
--- a/Source/cmTestGenerator.cxx
+++ b/Source/cmTestGenerator.cxx
@@ -10,7 +10,6 @@
#include "cmListFileCache.h"
#include "cmLocalGenerator.h"
#include "cmOutputConverter.h"
-#include "cmProperty.h"
#include "cmPropertyMap.h"
#include "cmRange.h"
#include "cmStateTypes.h"
@@ -76,12 +75,22 @@
// Start the test command.
os << indent << "add_test(" << this->Test->GetName() << " ";
- // Get the test command line to be executed.
- std::vector<std::string> const& command = this->Test->GetCommand();
+ // Evaluate command line arguments
+ std::vector<std::string> argv =
+ EvaluateCommandLineArguments(this->Test->GetCommand(), ge, config);
+
+ // Expand arguments if COMMAND_EXPAND_LISTS is set
+ if (this->Test->GetCommandExpandLists()) {
+ argv = cmSystemTools::ExpandedLists(argv.begin(), argv.end());
+ // Expanding lists on an empty command may have left it empty
+ if (argv.empty()) {
+ argv.emplace_back();
+ }
+ }
// Check whether the command executable is a target whose name is to
// be translated.
- std::string exe = command[0];
+ std::string exe = argv[0];
cmGeneratorTarget* target = this->LG->FindGeneratorTargetToUse(exe);
if (target && target->GetType() == cmStateEnums::EXECUTABLE) {
// Use the target file on disk.
@@ -101,29 +110,26 @@
}
} else {
// Use the command name given.
- exe = ge.Parse(exe)->Evaluate(this->LG, config);
cmSystemTools::ConvertToUnixSlashes(exe);
}
// Generate the command line with full escapes.
os << cmOutputConverter::EscapeForCMake(exe);
- for (std::string const& arg : cmMakeRange(command).advance(1)) {
- os << " "
- << cmOutputConverter::EscapeForCMake(
- ge.Parse(arg)->Evaluate(this->LG, config));
+
+ for (auto const& arg : cmMakeRange(argv).advance(1)) {
+ os << " " << cmOutputConverter::EscapeForCMake(arg);
}
// Finish the test command.
os << ")\n";
// Output properties for the test.
- cmPropertyMap& pm = this->Test->GetProperties();
os << indent << "set_tests_properties(" << this->Test->GetName()
<< " PROPERTIES ";
- for (auto const& i : pm) {
+ for (auto const& i : this->Test->GetProperties().GetList()) {
os << " " << i.first << " "
<< cmOutputConverter::EscapeForCMake(
- ge.Parse(i.second.GetValue())->Evaluate(this->LG, config));
+ ge.Parse(i.second)->Evaluate(this->LG, config));
}
this->GenerateInternalProperties(os);
os << ")" << std::endl;
@@ -173,12 +179,11 @@
fout << ")" << std::endl;
// Output properties for the test.
- cmPropertyMap& pm = this->Test->GetProperties();
fout << indent << "set_tests_properties(" << this->Test->GetName()
<< " PROPERTIES ";
- for (auto const& i : pm) {
+ for (auto const& i : this->Test->GetProperties().GetList()) {
fout << " " << i.first << " "
- << cmOutputConverter::EscapeForCMake(i.second.GetValue());
+ << cmOutputConverter::EscapeForCMake(i.second);
}
this->GenerateInternalProperties(fout);
fout << ")" << std::endl;
@@ -208,3 +213,16 @@
os << "\"";
}
+
+std::vector<std::string> cmTestGenerator::EvaluateCommandLineArguments(
+ const std::vector<std::string>& argv, cmGeneratorExpression& ge,
+ const std::string& config) const
+{
+ // Evaluate executable name and arguments
+ auto evaluatedRange =
+ cmMakeRange(argv).transform([&](const std::string& arg) {
+ return ge.Parse(arg)->Evaluate(this->LG, config);
+ });
+
+ return { evaluatedRange.begin(), evaluatedRange.end() };
+}
diff --git a/Source/cmTestGenerator.h b/Source/cmTestGenerator.h
index 8b9cf78..7ac68eb 100644
--- a/Source/cmTestGenerator.h
+++ b/Source/cmTestGenerator.h
@@ -11,6 +11,7 @@
#include <string>
#include <vector>
+class cmGeneratorExpression;
class cmLocalGenerator;
class cmTest;
@@ -38,6 +39,9 @@
private:
void GenerateInternalProperties(std::ostream& os);
+ std::vector<std::string> EvaluateCommandLineArguments(
+ const std::vector<std::string>& argv, cmGeneratorExpression& ge,
+ const std::string& config) const;
protected:
void GenerateScriptConfigs(std::ostream& os, Indent indent) override;
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index 9368414..634c990 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -774,11 +774,11 @@
cmSystemTools::ExpandListArgument(vsDotNetReferences, references);
}
cmPropertyMap const& props = this->GeneratorTarget->Target->GetProperties();
- for (auto const& i : props) {
+ for (auto const& i : props.GetList()) {
if (i.first.find("VS_DOTNET_REFERENCE_") == 0) {
std::string name = i.first.substr(20);
if (!name.empty()) {
- std::string path = i.second.GetValue();
+ std::string path = i.second;
if (!cmsys::SystemTools::FileIsFullPath(path)) {
path = this->Makefile->GetCurrentSourceDirectory() + "/" + path;
}
@@ -870,10 +870,10 @@
typedef std::map<std::string, std::string> CustomTags;
CustomTags tags;
cmPropertyMap const& props = this->GeneratorTarget->Target->GetProperties();
- for (const auto& i : props) {
+ for (const auto& i : props.GetList()) {
if (i.first.find(refPropFullPrefix) == 0) {
std::string refTag = i.first.substr(refPropFullPrefix.length());
- std::string refVal = i.second.GetValue();
+ std::string refVal = i.second;
if (!refTag.empty() && !refVal.empty()) {
tags[refTag] = refVal;
}
@@ -967,12 +967,12 @@
}
}
const cmPropertyMap& props = oi->GetProperties();
- for (const auto& p : props) {
+ for (const std::string& p : props.GetKeys()) {
static const std::string propNamePrefix = "VS_CSHARP_";
- if (p.first.find(propNamePrefix) == 0) {
- std::string tagName = p.first.substr(propNamePrefix.length());
+ if (p.find(propNamePrefix) == 0) {
+ std::string tagName = p.substr(propNamePrefix.length());
if (!tagName.empty()) {
- std::string value = props.GetPropertyValue(p.first);
+ std::string value = props.GetPropertyValue(p);
if (!value.empty()) {
e2.Element(tagName.c_str(), value);
}
@@ -4681,12 +4681,12 @@
{
if (this->ProjectType == csproj) {
const cmPropertyMap& props = sf->GetProperties();
- for (auto const& p : props) {
+ for (const std::string& p : props.GetKeys()) {
static const std::string propNamePrefix = "VS_CSHARP_";
- if (p.first.find(propNamePrefix) == 0) {
- std::string tagName = p.first.substr(propNamePrefix.length());
+ if (p.find(propNamePrefix) == 0) {
+ std::string tagName = p.substr(propNamePrefix.length());
if (!tagName.empty()) {
- const std::string val = props.GetPropertyValue(p.first);
+ const std::string val = props.GetPropertyValue(p);
if (!val.empty()) {
tags[tagName] = val;
} else {
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index 69f8162..735ad5f 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -408,7 +408,12 @@
set(NO_NAMELINK 0)
endif()
-add_RunCMake_test(install -DNO_NAMELINK=${NO_NAMELINK} -DCYGWIN=${CYGWIN})
+add_RunCMake_test(install -DNO_NAMELINK=${NO_NAMELINK} -DCYGWIN=${CYGWIN} -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID}
+ -DCMAKE_SHARED_LIBRARY_RPATH_ORIGIN_TOKEN=${CMAKE_SHARED_LIBRARY_RPATH_ORIGIN_TOKEN}
+ -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}
+ -DCMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG=${CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG}
+ -DCMAKE_EXECUTABLE_FORMAT=${CMAKE_EXECUTABLE_FORMAT})
+
add_RunCMake_test(CPackCommandLine)
add_RunCMake_test(CPackConfig)
add_RunCMake_test(CPackInstallProperties)
@@ -565,3 +570,5 @@
add_RunCMake_test(CSharpCustomCommand)
add_RunCMake_test(CSharpReferenceImport)
endif()
+
+add_RunCMake_test("CTestCommandExpandLists")
diff --git a/Tests/RunCMake/CTestCommandExpandLists/CMakeLists.txt b/Tests/RunCMake/CTestCommandExpandLists/CMakeLists.txt
new file mode 100644
index 0000000..3e470a2
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandExpandLists/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.14)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CTestCommandExpandLists/CMakeLists.txt.in b/Tests/RunCMake/CTestCommandExpandLists/CMakeLists.txt.in
new file mode 100644
index 0000000..7d56c90
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandExpandLists/CMakeLists.txt.in
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.14)
+project(@CASE_NAME@ NONE)
+include("@RunCMake_SOURCE_DIR@/@CASE_NAME@.cmake")
diff --git a/Tests/RunCMake/CTestCommandExpandLists/RunCMakeTest.cmake b/Tests/RunCMake/CTestCommandExpandLists/RunCMakeTest.cmake
new file mode 100644
index 0000000..7c3779e
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandExpandLists/RunCMakeTest.cmake
@@ -0,0 +1,5 @@
+include(RunCTest)
+
+run_ctest(expandGeneratorExpressionResult)
+run_ctest(expandEmptyCommand)
+run_cmake(multipleExpandOptions)
diff --git a/Tests/RunCMake/CTestCommandExpandLists/compare_options.cmake b/Tests/RunCMake/CTestCommandExpandLists/compare_options.cmake
new file mode 100644
index 0000000..a32e579
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandExpandLists/compare_options.cmake
@@ -0,0 +1,14 @@
+set(range 1 2 3 4 5 6 7 8 9 10)
+set(aargs "")
+set(bargs "")
+foreach(n IN LISTS range)
+ set(aval "${A${n}ARG}")
+ set(bval "${B${n}ARG}")
+ if(aval OR bval)
+ list(APPEND aargs "\"${aval}\"")
+ list(APPEND bargs "\"${bval}\"")
+ endif()
+endforeach()
+if(NOT "${aargs}" STREQUAL "${bargs}")
+ message(FATAL_ERROR "COMPARE_OPTIONS: \n\t${aargs} != \n\t${bargs}")
+endif()
diff --git a/Tests/RunCMake/CTestCommandExpandLists/expandEmptyCommand-result.txt b/Tests/RunCMake/CTestCommandExpandLists/expandEmptyCommand-result.txt
new file mode 100644
index 0000000..b57e2de
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandExpandLists/expandEmptyCommand-result.txt
@@ -0,0 +1 @@
+(-1|255)
diff --git a/Tests/RunCMake/CTestCommandExpandLists/expandEmptyCommand-stderr.txt b/Tests/RunCMake/CTestCommandExpandLists/expandEmptyCommand-stderr.txt
new file mode 100644
index 0000000..c656b4c
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandExpandLists/expandEmptyCommand-stderr.txt
@@ -0,0 +1 @@
+Unable to find executable:
diff --git a/Tests/RunCMake/CTestCommandExpandLists/expandEmptyCommand-stdout.txt b/Tests/RunCMake/CTestCommandExpandLists/expandEmptyCommand-stdout.txt
new file mode 100644
index 0000000..0752580
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandExpandLists/expandEmptyCommand-stdout.txt
@@ -0,0 +1,13 @@
+Test project .*/Tests/RunCMake/CTestCommandExpandLists/expandEmptyCommand-build
+.* +Start 1: CommandExpandEmptyList
+Could not find executable +
+Looked in the following places:
+.*
+1/1 Test #1: CommandExpandEmptyList +\.+\*\*\*Not Run +[0-9.]+ sec
++
+0% tests passed, 1 tests failed out of 1
++
+Total Test time \(real\) = +[0-9.]+ sec
++
+The following tests FAILED:
+.* +1 - CommandExpandEmptyList \(Not Run\)$
diff --git a/Tests/RunCMake/CTestCommandExpandLists/expandEmptyCommand.cmake b/Tests/RunCMake/CTestCommandExpandLists/expandEmptyCommand.cmake
new file mode 100644
index 0000000..b75828e
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandExpandLists/expandEmptyCommand.cmake
@@ -0,0 +1,10 @@
+include(CTest)
+
+set(argv /bin/true)
+list(POP_BACK argv)
+
+add_test(
+ NAME CommandExpandEmptyList
+ COMMAND "$<JOIN:${argv},;>"
+ COMMAND_EXPAND_LISTS
+)
diff --git a/Tests/RunCMake/CTestCommandExpandLists/expandGeneratorExpressionResult-result.txt b/Tests/RunCMake/CTestCommandExpandLists/expandGeneratorExpressionResult-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandExpandLists/expandGeneratorExpressionResult-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CTestCommandExpandLists/expandGeneratorExpressionResult-stdout.txt b/Tests/RunCMake/CTestCommandExpandLists/expandGeneratorExpressionResult-stdout.txt
new file mode 100644
index 0000000..2f21592
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandExpandLists/expandGeneratorExpressionResult-stdout.txt
@@ -0,0 +1,7 @@
+Test project .*/Tests/RunCMake/CTestCommandExpandLists/expandGeneratorExpressionResult-build
+.* +Start 1: CommandExpandList
+1/1 Test #1: CommandExpandList +\.+ +Passed +[0-9.]+ sec
++
+100% tests passed, 0 tests failed out of 1
++
+Total Test time \(real\) = +[0-9.]+ sec
diff --git a/Tests/RunCMake/CTestCommandExpandLists/expandGeneratorExpressionResult.cmake b/Tests/RunCMake/CTestCommandExpandLists/expandGeneratorExpressionResult.cmake
new file mode 100644
index 0000000..20608ae
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandExpandLists/expandGeneratorExpressionResult.cmake
@@ -0,0 +1,19 @@
+include(CTest)
+
+
+set(cmp_args "1ARG=COMMAND_EXPAND_LISTS" "2ARG=test" "3ARG=outfile"
+ "4ARG=content")
+set(AARGS "")
+foreach(arg IN LISTS cmp_args)
+ list(APPEND AARGS "-DA${arg}")
+endforeach()
+
+
+
+add_test(
+ NAME CommandExpandList
+ COMMAND ${CMAKE_COMMAND} ${AARGS} -V
+ "-DB$<JOIN:${cmp_args},;-DB>"
+ "-P" "${CMAKE_CURRENT_LIST_DIR}/compare_options.cmake"
+ COMMAND_EXPAND_LISTS
+)
diff --git a/Tests/RunCMake/CTestCommandExpandLists/multipleExpandOptions-result.txt b/Tests/RunCMake/CTestCommandExpandLists/multipleExpandOptions-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandExpandLists/multipleExpandOptions-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CTestCommandExpandLists/multipleExpandOptions-stderr.txt b/Tests/RunCMake/CTestCommandExpandLists/multipleExpandOptions-stderr.txt
new file mode 100644
index 0000000..e48513f
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandExpandLists/multipleExpandOptions-stderr.txt
@@ -0,0 +1,2 @@
+CMake Error at multipleExpandOptions\.cmake:3 \(add_test\):
+ +add_test may be given at most one COMMAND_EXPAND_LISTS\.
diff --git a/Tests/RunCMake/CTestCommandExpandLists/multipleExpandOptions-stdout.txt b/Tests/RunCMake/CTestCommandExpandLists/multipleExpandOptions-stdout.txt
new file mode 100644
index 0000000..55bb894
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandExpandLists/multipleExpandOptions-stdout.txt
@@ -0,0 +1,2 @@
+-- Configuring incomplete, errors occurred!
+See also ".*/Tests/RunCMake/CTestCommandExpandLists/multipleExpandOptions-build/CMakeFiles/CMakeOutput\.log".
diff --git a/Tests/RunCMake/CTestCommandExpandLists/multipleExpandOptions.cmake b/Tests/RunCMake/CTestCommandExpandLists/multipleExpandOptions.cmake
new file mode 100644
index 0000000..dcf2dc4
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandExpandLists/multipleExpandOptions.cmake
@@ -0,0 +1,8 @@
+include(CTest)
+
+add_test(
+ NAME MultipleExpandOptions
+ COMMAND /bin/true
+ COMMAND_EXPAND_LISTS
+ COMMAND_EXPAND_LISTS
+)
diff --git a/Tests/RunCMake/CTestCommandExpandLists/test.cmake.in b/Tests/RunCMake/CTestCommandExpandLists/test.cmake.in
new file mode 100644
index 0000000..d9a8ccb
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandExpandLists/test.cmake.in
@@ -0,0 +1,15 @@
+cmake_minimum_required(VERSION 3.14)
+
+set(CTEST_SITE "test-site")
+set(CTEST_BUILD_NAME "test-build-name")
+set(CTEST_SOURCE_DIRECTORY "@RunCMake_BINARY_DIR@/@CASE_NAME@")
+set(CTEST_BINARY_DIRECTORY "@RunCMake_BINARY_DIR@/@CASE_NAME@-build")
+set(CTEST_CMAKE_GENERATOR "@RunCMake_GENERATOR@")
+set(CTEST_CMAKE_GENERATOR_PLATFORM "@RunCMake_GENERATOR_PLATFORM@")
+set(CTEST_CMAKE_GENERATOR_TOOLSET "@RunCMake_GENERATOR_TOOLSET@")
+set(CTEST_BUILD_CONFIGURATION "$ENV{CMAKE_CONFIG_TYPE}")
+
+ctest_start(Experimental)
+ctest_configure()
+ctest_build()
+ctest_test()
diff --git a/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt b/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt
index 0bcf886..6d72fac 100644
--- a/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt
+++ b/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt
@@ -27,6 +27,7 @@
\* CMP0076
\* CMP0081
\* CMP0083
+ \* CMP0095
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/install/CMakeLists.txt b/Tests/RunCMake/install/CMakeLists.txt
index 6dd8cdf..c7e99ad 100644
--- a/Tests/RunCMake/install/CMakeLists.txt
+++ b/Tests/RunCMake/install/CMakeLists.txt
@@ -1,3 +1,6 @@
cmake_minimum_required(VERSION 3.4)
+if(RunCMake_TEST MATCHES "^file-GET_RUNTIME_DEPENDENCIES")
+ cmake_policy(SET CMP0087 NEW)
+endif()
project(${RunCMake_TEST} NONE)
include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/install/RunCMakeTest.cmake b/Tests/RunCMake/install/RunCMakeTest.cmake
index c637db1..21c320b 100644
--- a/Tests/RunCMake/install/RunCMakeTest.cmake
+++ b/Tests/RunCMake/install/RunCMakeTest.cmake
@@ -48,6 +48,22 @@
endif()
endfunction()
+# Wrapper for run_cmake() that skips platforms that are non-ELF or have no RPATH support
+function(run_cmake_ELFRPATH_only case)
+ if(UNIX AND CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG AND CMAKE_EXECUTABLE_FORMAT STREQUAL "ELF")
+ run_cmake(${case})
+ else()
+ # Sanity check against a platform known to be ELF-based
+ if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
+ message(FATAL_ERROR "Expected platform Linux to advertize itself as ELF-based, but it did not.")
+ else()
+ message(STATUS "${case} - SKIPPED (No ELF-based platform found)")
+ endif()
+ endif()
+endfunction()
+
+run_cmake(TARGETS-FILE_RPATH_CHANGE-old_rpath)
+run_cmake_ELFRPATH_only(TARGETS-FILE_RPATH_CHANGE-new_rpath)
run_cmake(DIRECTORY-MESSAGE_NEVER)
run_cmake(DIRECTORY-PATTERN-MESSAGE_NEVER)
run_cmake(DIRECTORY-message)
@@ -139,6 +155,36 @@
run_install_test(TARGETS-RPATH)
run_install_test(InstallRequiredSystemLibraries)
+if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
+ run_install_test(file-GET_RUNTIME_DEPENDENCIES-macos)
+ run_install_test(file-GET_RUNTIME_DEPENDENCIES-macos-unresolved)
+ run_install_test(file-GET_RUNTIME_DEPENDENCIES-macos-conflict)
+ run_install_test(file-GET_RUNTIME_DEPENDENCIES-macos-notfile)
+ run_cmake(file-GET_RUNTIME_DEPENDENCIES-project)
+ run_cmake(file-GET_RUNTIME_DEPENDENCIES-badargs1)
+ run_cmake(file-GET_RUNTIME_DEPENDENCIES-badargs2)
+elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
+ run_install_test(file-GET_RUNTIME_DEPENDENCIES-windows)
+ run_install_test(file-GET_RUNTIME_DEPENDENCIES-windows-unresolved)
+ run_install_test(file-GET_RUNTIME_DEPENDENCIES-windows-conflict)
+ run_install_test(file-GET_RUNTIME_DEPENDENCIES-windows-notfile)
+ run_cmake(file-GET_RUNTIME_DEPENDENCIES-project)
+ run_cmake(file-GET_RUNTIME_DEPENDENCIES-badargs1)
+ run_cmake(file-GET_RUNTIME_DEPENDENCIES-badargs2)
+elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux")
+ if(NOT CMAKE_C_COMPILER_ID MATCHES "^XL")
+ run_install_test(file-GET_RUNTIME_DEPENDENCIES-linux)
+ endif()
+ run_install_test(file-GET_RUNTIME_DEPENDENCIES-linux-unresolved)
+ run_install_test(file-GET_RUNTIME_DEPENDENCIES-linux-conflict)
+ run_install_test(file-GET_RUNTIME_DEPENDENCIES-linux-notfile)
+ run_cmake(file-GET_RUNTIME_DEPENDENCIES-project)
+ run_cmake(file-GET_RUNTIME_DEPENDENCIES-badargs1)
+ run_cmake(file-GET_RUNTIME_DEPENDENCIES-badargs2)
+else()
+ run_cmake(file-GET_RUNTIME_DEPENDENCIES-unsupported)
+endif()
+
set(run_install_test_components 1)
run_install_test(FILES-EXCLUDE_FROM_ALL)
run_install_test(TARGETS-EXCLUDE_FROM_ALL)
diff --git a/Tests/RunCMake/install/TARGETS-FILE_RPATH_CHANGE-check-common.cmake b/Tests/RunCMake/install/TARGETS-FILE_RPATH_CHANGE-check-common.cmake
new file mode 100644
index 0000000..673fdde
--- /dev/null
+++ b/Tests/RunCMake/install/TARGETS-FILE_RPATH_CHANGE-check-common.cmake
@@ -0,0 +1,30 @@
+file(READ ${RunCMake_TEST_BINARY_DIR}/cmake_install.cmake install_script)
+#message(STATUS ${install_script})
+
+set(wsnl " *[\n\r]+ *") # whitespace + single newline + whitespace
+set(wssl " *[\n\r]+[^\n\r]*[\n\r]+ *") # ws nl skipline nl ws
+string(CONCAT prefix [[file\(RPATH_CHANGE]])
+set(_msg "cmake_install.cmake does not match ")
+
+macro(check)
+ if(NOT install_script MATCHES "${regex}")
+ message(STATUS "${test} - check \"${target}\" - FAILED:")
+ string(CONCAT RunCMake_TEST_FAILED "${_msg}" ">>>${regex}<<<")
+ return()
+ else()
+ message(STATUS "${test} - check \"${target}\" - PASSED")
+ endif()
+endmacro()
+
+macro(skip_without_rpath_change_rule)
+# Not all platforms generate a file(RPATH_CHANGE) rule
+ if(NOT install_script MATCHES [[file\(RPATH_CHANGE]])
+ # Sanity check against a platform known to generate a file(RPATH_CHANGE) rule
+ if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
+ message(FATAL_ERROR "Expected generated file(RPATH_CHANGE) rule on platform Linux.")
+ else()
+ message(STATUS "${test} - All checks skipped. No file(RPATH_CHANGE) rule found on this platform.")
+ return()
+ endif()
+ endif()
+endmacro()
diff --git a/Tests/RunCMake/install/TARGETS-FILE_RPATH_CHANGE-new_rpath-check.cmake b/Tests/RunCMake/install/TARGETS-FILE_RPATH_CHANGE-new_rpath-check.cmake
new file mode 100644
index 0000000..930ef70
--- /dev/null
+++ b/Tests/RunCMake/install/TARGETS-FILE_RPATH_CHANGE-new_rpath-check.cmake
@@ -0,0 +1,63 @@
+include(${RunCMake_SOURCE_DIR}/TARGETS-FILE_RPATH_CHANGE-check-common.cmake)
+skip_without_rpath_change_rule()
+string(APPEND prefix "${wsnl}" [[FILE "[^"]*/]])
+
+set(target "exe1_cmp0095_old")
+string(CONCAT regex "${prefix}${target}\"${wssl}"
+ [[NEW_RPATH "/foo/bar]])
+check()
+
+set(target "exe1_cmp0095_warn")
+string(CONCAT regex "${prefix}${target}\"${wssl}"
+ [[NEW_RPATH "/foo/bar]])
+check()
+
+set(target "exe1_cmp0095_new")
+string(CONCAT regex "${prefix}${target}\"${wssl}"
+ [[NEW_RPATH "/foo/bar]])
+check()
+
+set(target "exe2_cmp0095_old")
+string(CONCAT regex "${prefix}${target}\"${wssl}"
+ [[NEW_RPATH "\$ORIGIN/../lib]])
+check()
+
+set(target "exe2_cmp0095_warn")
+string(CONCAT regex "${prefix}${target}\"${wssl}"
+ [[NEW_RPATH "\$ORIGIN/../lib]])
+check()
+
+set(target "exe2_cmp0095_new")
+string(CONCAT regex "${prefix}${target}\"${wssl}"
+ [[NEW_RPATH "\\\$ORIGIN/../lib]])
+check()
+
+set(target "exe3_cmp0095_old")
+string(CONCAT regex "${prefix}${target}\"${wssl}"
+ [[NEW_RPATH "\${ORIGIN}/../lib]])
+check()
+
+set(target "exe3_cmp0095_warn")
+string(CONCAT regex "${prefix}${target}\"${wssl}"
+ [[NEW_RPATH "\${ORIGIN}/../lib]])
+check()
+
+set(target "exe3_cmp0095_new")
+string(CONCAT regex "${prefix}${target}\"${wssl}"
+ [[NEW_RPATH "\\\${ORIGIN}/../lib]])
+check()
+
+set(target "exe4_cmp0095_old")
+string(CONCAT regex "${prefix}${target}\"${wssl}"
+ [[NEW_RPATH "/foo/bar/\${PLATFORM}]])
+check()
+
+set(target "exe4_cmp0095_warn")
+string(CONCAT regex "${prefix}${target}\"${wssl}"
+ [[NEW_RPATH "/foo/bar/\${PLATFORM}]])
+check()
+
+set(target "exe4_cmp0095_new")
+string(CONCAT regex "${prefix}${target}\"${wssl}"
+ [[NEW_RPATH "/foo/bar/\\\${PLATFORM}]])
+check()
diff --git a/Tests/RunCMake/install/TARGETS-FILE_RPATH_CHANGE-new_rpath-stderr.txt b/Tests/RunCMake/install/TARGETS-FILE_RPATH_CHANGE-new_rpath-stderr.txt
new file mode 100644
index 0000000..1e123f6
--- /dev/null
+++ b/Tests/RunCMake/install/TARGETS-FILE_RPATH_CHANGE-new_rpath-stderr.txt
@@ -0,0 +1,23 @@
+^CMake Warning \(dev\) at TARGETS-FILE_RPATH_CHANGE-new_rpath\.cmake:[0-9]+ \(install\):
+ Policy CMP0095 is not set: RPATH entries are properly escaped in the
+ intermediary CMake install script\. Run "cmake --help-policy CMP0095" for
+ policy details\. Use the cmake_policy command to set the policy and
+ suppress this warning\.
+
+ RPATH entries for target 'exe3_cmp0095_warn' will not be escaped in the
+ intermediary cmake_install\.cmake script\.
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
+
+CMake Warning \(dev\) at TARGETS-FILE_RPATH_CHANGE-new_rpath\.cmake:[0-9]+ \(install\):
+ Policy CMP0095 is not set: RPATH entries are properly escaped in the
+ intermediary CMake install script\. Run "cmake --help-policy CMP0095" for
+ policy details\. Use the cmake_policy command to set the policy and
+ suppress this warning\.
+
+ RPATH entries for target 'exe4_cmp0095_warn' will not be escaped in the
+ intermediary cmake_install\.cmake script\.
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.$
diff --git a/Tests/RunCMake/install/TARGETS-FILE_RPATH_CHANGE-new_rpath.cmake b/Tests/RunCMake/install/TARGETS-FILE_RPATH_CHANGE-new_rpath.cmake
new file mode 100644
index 0000000..cba04b2
--- /dev/null
+++ b/Tests/RunCMake/install/TARGETS-FILE_RPATH_CHANGE-new_rpath.cmake
@@ -0,0 +1,72 @@
+cmake_minimum_required(VERSION 3.14)
+enable_language(C)
+
+# test matrix
+#
+# A :=
+# | no cmake syntax | cmake syntax |
+# -----------------------+-----------------+--------------+
+# absolute install RPATH | exe1 | exe4 |
+# relative install RPATH | exe2 | exe3 |
+#
+# all := A * CMP005_OLD + A * CMP0095_WARN + A * CMP0095_NEW
+
+add_library(utils SHARED obj1.c)
+set(targets utils)
+
+set(exe1_install_rpath "/foo/bar")
+set(exe2_install_rpath "\$ORIGIN/../lib")
+set(exe3_install_rpath "\${ORIGIN}/../lib")
+set(exe4_install_rpath "/foo/bar/\${PLATFORM}")
+
+macro(A_CMP0095 policy_value)
+ cmake_policy(PUSH)
+ if(NOT "x${policy_value}x" STREQUAL "xWARNx")
+ cmake_policy(SET CMP0095 ${policy_value})
+ endif()
+ string(TOLOWER "${policy_value}" p)
+
+ # exe1: absolute install RPATH, no cmake syntax
+ set(case "exe1")
+ set(target "${case}_cmp0095_${p}")
+ list(APPEND targets ${target})
+ add_executable(${target} main.c)
+ target_link_libraries(${target} PRIVATE utils)
+ set_target_properties(${target} PROPERTIES
+ INSTALL_RPATH "${${case}_install_rpath}")
+
+ # exe2: relative install RPATH, no cmake syntax
+ set(case "exe2")
+ set(target "${case}_cmp0095_${p}")
+ list(APPEND targets ${target})
+ add_executable(${target} main.c)
+ target_link_libraries(${target} PRIVATE utils)
+ set_target_properties(${target} PROPERTIES
+ INSTALL_RPATH "${${case}_install_rpath}")
+
+ # exe3: relative install RPATH, cmake syntax
+ set(case "exe3")
+ set(target "${case}_cmp0095_${p}")
+ list(APPEND targets ${target})
+ add_executable(${target} main.c)
+ target_link_libraries(${target} PRIVATE utils)
+ set_target_properties(${target} PROPERTIES
+ INSTALL_RPATH "${${case}_install_rpath}")
+
+ # exe4: absolute install RPATH, cmake syntax
+ set(case "exe4")
+ set(target "${case}_cmp0095_${p}")
+ list(APPEND targets ${target})
+ add_executable(${target} main.c)
+ target_link_libraries(${target} PRIVATE utils)
+ set_target_properties(${target} PROPERTIES
+ INSTALL_RPATH "${${case}_install_rpath}")
+
+ cmake_policy(POP)
+endmacro()
+
+A_CMP0095("OLD")
+A_CMP0095("WARN") # exe3 and exe4 are expected to issue an author warning
+A_CMP0095("NEW")
+
+install(TARGETS ${targets})
diff --git a/Tests/RunCMake/install/TARGETS-FILE_RPATH_CHANGE-old_rpath-check.cmake b/Tests/RunCMake/install/TARGETS-FILE_RPATH_CHANGE-old_rpath-check.cmake
new file mode 100644
index 0000000..814f405
--- /dev/null
+++ b/Tests/RunCMake/install/TARGETS-FILE_RPATH_CHANGE-old_rpath-check.cmake
@@ -0,0 +1,15 @@
+include(${RunCMake_SOURCE_DIR}/TARGETS-FILE_RPATH_CHANGE-check-common.cmake)
+skip_without_rpath_change_rule()
+string(APPEND prefix "${wsnl}" [[FILE "[^"]*/]])
+
+set(target "exe1")
+string(CONCAT regex "${prefix}${target}\"${wsnl}"
+ [[OLD_RPATH "]] "${RunCMake_BINARY_DIR}")
+check()
+
+if("x${CMAKE_SHARED_LIBRARY_RPATH_ORIGIN_TOKEN}" STREQUAL "x\$ORIGIN")
+ set(target "exe2")
+ string(CONCAT regex "${prefix}${target}\"${wsnl}"
+ [[OLD_RPATH "\\\$ORIGIN]])
+ check()
+endif()
diff --git a/Tests/RunCMake/install/TARGETS-FILE_RPATH_CHANGE-old_rpath.cmake b/Tests/RunCMake/install/TARGETS-FILE_RPATH_CHANGE-old_rpath.cmake
new file mode 100644
index 0000000..43ae787
--- /dev/null
+++ b/Tests/RunCMake/install/TARGETS-FILE_RPATH_CHANGE-old_rpath.cmake
@@ -0,0 +1,18 @@
+cmake_minimum_required(VERSION 3.14)
+enable_language(C)
+
+add_library(utils SHARED obj1.c)
+
+# exe1: absolute build RPATH, no cmake syntax
+set(CMAKE_BUILD_RPATH_USE_ORIGIN OFF)
+set(CMAKE_INSTALL_RPATH "/foo/bar")
+add_executable(exe1 main.c)
+target_link_libraries(exe1 PRIVATE utils)
+
+# exe2: relative build RPATH, no cmake syntax
+set(CMAKE_BUILD_RPATH_USE_ORIGIN ON)
+set(CMAKE_INSTALL_RPATH "/foo/bar")
+add_executable(exe2 main.c)
+target_link_libraries(exe2 PRIVATE utils)
+
+install(TARGETS utils exe1 exe2)
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-badargs1-result.txt b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-badargs1-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-badargs1-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-badargs1-stderr.txt b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-badargs1-stderr.txt
new file mode 100644
index 0000000..b66d1fe
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-badargs1-stderr.txt
@@ -0,0 +1,18 @@
+^CMake Warning \(dev\) at file-GET_RUNTIME_DEPENDENCIES-badargs1\.cmake:[0-9]+ \(file\):
+ You have used file\(GET_RUNTIME_DEPENDENCIES\) in project mode\. This is
+ probably not what you intended to do\. Instead, please consider using it in
+ an install\(CODE\) or install\(SCRIPT\) command\. For example:
+
+ install\(CODE \[\[
+ file\(GET_RUNTIME_DEPENDENCIES
+ # \.\.\.
+ \)
+ ]]\)
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
+
+CMake Error at file-GET_RUNTIME_DEPENDENCIES-badargs1\.cmake:[0-9]+ \(file\):
+ file Unrecognized argument: "invalid"
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-badargs1.cmake b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-badargs1.cmake
new file mode 100644
index 0000000..f3b8ce4
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-badargs1.cmake
@@ -0,0 +1,2 @@
+file(GET_RUNTIME_DEPENDENCIES invalid)
+message(FATAL_ERROR "This message should not be displayed")
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-badargs2-result.txt b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-badargs2-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-badargs2-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-badargs2-stderr.txt b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-badargs2-stderr.txt
new file mode 100644
index 0000000..94f0f46
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-badargs2-stderr.txt
@@ -0,0 +1,18 @@
+^CMake Warning \(dev\) at file-GET_RUNTIME_DEPENDENCIES-badargs2\.cmake:[0-9]+ \(file\):
+ You have used file\(GET_RUNTIME_DEPENDENCIES\) in project mode\. This is
+ probably not what you intended to do\. Instead, please consider using it in
+ an install\(CODE\) or install\(SCRIPT\) command\. For example:
+
+ install\(CODE \[\[
+ file\(GET_RUNTIME_DEPENDENCIES
+ # \.\.\.
+ \)
+ ]]\)
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.
+
+CMake Error at file-GET_RUNTIME_DEPENDENCIES-badargs2\.cmake:[0-9]+ \(file\):
+ file Keyword missing value: BUNDLE_EXECUTABLE
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-badargs2.cmake b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-badargs2.cmake
new file mode 100644
index 0000000..138ab95
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-badargs2.cmake
@@ -0,0 +1,2 @@
+file(GET_RUNTIME_DEPENDENCIES BUNDLE_EXECUTABLE)
+message(FATAL_ERROR "This message should not be displayed")
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-all-check.cmake b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-all-check.cmake
new file mode 100644
index 0000000..ab630f0
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-all-check.cmake
@@ -0,0 +1,44 @@
+function(check_contents filename contents_regex)
+ if(EXISTS "${CMAKE_INSTALL_PREFIX}/${filename}")
+ file(READ "${CMAKE_INSTALL_PREFIX}/${filename}" contents)
+ if(NOT contents MATCHES "${contents_regex}")
+ string(APPEND RunCMake_TEST_FAILED "File contents:
+ ${contents}
+do not match what we expected:
+ ${contents_regex}
+in file:
+ ${CMAKE_INSTALL_PREFIX}/${filename}\n")
+ set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
+ endif()
+ else()
+ string(APPEND RunCMake_TEST_FAILED "File ${CMAKE_INSTALL_PREFIX}/${filename} does not exist")
+ set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+set(_check
+ [[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-build/root-all/lib/libtest_rpath\.so]]
+ [[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-build/root-all/lib/libtest_runpath\.so]]
+ [[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-build/root-all/lib/rpath/librpath\.so]]
+ [[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-build/root-all/lib/rpath_parent/librpath_parent\.so]]
+ [[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-build/root-all/lib/rpath_search/librpath_search\.so]]
+ [[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-build/root-all/lib/runpath/librunpath\.so]]
+ [[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-build/root-all/lib/runpath_search/librunpath_search\.so]]
+ )
+check_contents(deps/deps1.txt "^${_check}$")
+check_contents(deps/deps2.txt "^${_check}$")
+check_contents(deps/deps3.txt "^${_check}$")
+set(_check
+ [[librpath_unresolved\.so]]
+ [[librunpath_parent_unresolved\.so]]
+ [[librunpath_unresolved\.so]]
+ )
+check_contents(deps/udeps1.txt "^${_check}$")
+check_contents(deps/udeps2.txt "^${_check}$")
+check_contents(deps/udeps3.txt "^${_check}$")
+set(_check
+ "^libconflict\\.so:[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-build/root-all/lib/conflict/libconflict\\.so;[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-build/root-all/lib/conflict2/libconflict\\.so\n$"
+ )
+check_contents(deps/cdeps1.txt "${_check}")
+check_contents(deps/cdeps2.txt "${_check}")
+check_contents(deps/cdeps3.txt "${_check}")
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-all-stderr.txt b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-all-stderr.txt
new file mode 100644
index 0000000..123ae48
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-all-stderr.txt
@@ -0,0 +1,119 @@
+^CMake Warning at cmake_install\.cmake:[0-9]+ \(file\):
+ Dependency librpath_search_postexcluded\.so found in search directory:
+
+ [^
+]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-build/root-all/lib/rpath_search_postexcluded
+
+ See file\(GET_RUNTIME_DEPENDENCIES\) documentation for more information\.
+Call Stack \(most recent call first\):
+ cmake_install\.cmake:[0-9]+ \(exec_get_runtime_dependencies\)
+
+*CMake Warning at cmake_install\.cmake:[0-9]+ \(file\):
+ Dependency librpath_search\.so found in search directory:
+
+ [^
+]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-build/root-all/lib/rpath_search
+
+ See file\(GET_RUNTIME_DEPENDENCIES\) documentation for more information\.
+Call Stack \(most recent call first\):
+ cmake_install\.cmake:[0-9]+ \(exec_get_runtime_dependencies\)
+
+*CMake Warning at cmake_install\.cmake:[0-9]+ \(file\):
+ Dependency librunpath_search_postexcluded\.so found in search directory:
+
+ [^
+]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-build/root-all/lib/runpath_search_postexcluded
+
+ See file\(GET_RUNTIME_DEPENDENCIES\) documentation for more information\.
+Call Stack \(most recent call first\):
+ cmake_install\.cmake:[0-9]+ \(exec_get_runtime_dependencies\)
+
+*CMake Warning at cmake_install\.cmake:[0-9]+ \(file\):
+ Dependency librunpath_search\.so found in search directory:
+
+ [^
+]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-build/root-all/lib/runpath_search
+
+ See file\(GET_RUNTIME_DEPENDENCIES\) documentation for more information\.
+Call Stack \(most recent call first\):
+ cmake_install\.cmake:[0-9]+ \(exec_get_runtime_dependencies\)
+
+*CMake Warning at cmake_install\.cmake:[0-9]+ \(file\):
+ Dependency librpath_search_postexcluded\.so found in search directory:
+
+ [^
+]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-build/root-all/lib/rpath_search_postexcluded
+
+ See file\(GET_RUNTIME_DEPENDENCIES\) documentation for more information\.
+Call Stack \(most recent call first\):
+ cmake_install\.cmake:[0-9]+ \(exec_get_runtime_dependencies\)
+
+*CMake Warning at cmake_install\.cmake:[0-9]+ \(file\):
+ Dependency librpath_search\.so found in search directory:
+
+ [^
+]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-build/root-all/lib/rpath_search
+
+ See file\(GET_RUNTIME_DEPENDENCIES\) documentation for more information\.
+Call Stack \(most recent call first\):
+ cmake_install\.cmake:[0-9]+ \(exec_get_runtime_dependencies\)
+
+*CMake Warning at cmake_install\.cmake:[0-9]+ \(file\):
+ Dependency librunpath_search_postexcluded\.so found in search directory:
+
+ [^
+]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-build/root-all/lib/runpath_search_postexcluded
+
+ See file\(GET_RUNTIME_DEPENDENCIES\) documentation for more information\.
+Call Stack \(most recent call first\):
+ cmake_install\.cmake:[0-9]+ \(exec_get_runtime_dependencies\)
+
+*CMake Warning at cmake_install\.cmake:[0-9]+ \(file\):
+ Dependency librunpath_search\.so found in search directory:
+
+ [^
+]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-build/root-all/lib/runpath_search
+
+ See file\(GET_RUNTIME_DEPENDENCIES\) documentation for more information\.
+Call Stack \(most recent call first\):
+ cmake_install\.cmake:[0-9]+ \(exec_get_runtime_dependencies\)
+
+*CMake Warning at cmake_install\.cmake:[0-9]+ \(file\):
+ Dependency librpath_search_postexcluded\.so found in search directory:
+
+ [^
+]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-build/root-all/lib/rpath_search_postexcluded
+
+ See file\(GET_RUNTIME_DEPENDENCIES\) documentation for more information\.
+Call Stack \(most recent call first\):
+ cmake_install\.cmake:[0-9]+ \(exec_get_runtime_dependencies\)
+
+*CMake Warning at cmake_install\.cmake:[0-9]+ \(file\):
+ Dependency librpath_search\.so found in search directory:
+
+ [^
+]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-build/root-all/lib/rpath_search
+
+ See file\(GET_RUNTIME_DEPENDENCIES\) documentation for more information\.
+Call Stack \(most recent call first\):
+ cmake_install\.cmake:[0-9]+ \(exec_get_runtime_dependencies\)
+
+*CMake Warning at cmake_install\.cmake:[0-9]+ \(file\):
+ Dependency librunpath_search_postexcluded\.so found in search directory:
+
+ [^
+]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-build/root-all/lib/runpath_search_postexcluded
+
+ See file\(GET_RUNTIME_DEPENDENCIES\) documentation for more information\.
+Call Stack \(most recent call first\):
+ cmake_install\.cmake:[0-9]+ \(exec_get_runtime_dependencies\)
+
+*CMake Warning at cmake_install\.cmake:[0-9]+ \(file\):
+ Dependency librunpath_search\.so found in search directory:
+
+ [^
+]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-build/root-all/lib/runpath_search
+
+ See file\(GET_RUNTIME_DEPENDENCIES\) documentation for more information\.
+Call Stack \(most recent call first\):
+ cmake_install\.cmake:[0-9]+ \(exec_get_runtime_dependencies\)$
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-conflict-all-result.txt b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-conflict-all-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-conflict-all-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-conflict-all-stderr.txt b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-conflict-all-stderr.txt
new file mode 100644
index 0000000..1692348
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-conflict-all-stderr.txt
@@ -0,0 +1,7 @@
+^CMake Error at cmake_install\.cmake:[0-9]+ \(file\):
+ file Multiple conflicting paths found for librpath\.so:
+
+ [^
+]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-conflict-build/root-all/lib/rpath1/librpath\.so
+ [^
+]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-conflict-build/root-all/lib/rpath2/librpath\.so$
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-conflict.cmake b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-conflict.cmake
new file mode 100644
index 0000000..f719499
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-conflict.cmake
@@ -0,0 +1,54 @@
+enable_language(C)
+
+set(test1_names rpath)
+set(test2_names rpath)
+
+file(WRITE "${CMAKE_BINARY_DIR}/rpath.c" "void rpath(void) {}\n")
+add_library(rpath SHARED "${CMAKE_BINARY_DIR}/rpath.c")
+install(TARGETS rpath DESTINATION lib/rpath1)
+install(TARGETS rpath DESTINATION lib/rpath2)
+
+file(REMOVE "${CMAKE_BINARY_DIR}/test1.c")
+add_library(test1 SHARED "${CMAKE_BINARY_DIR}/test1.c")
+foreach(name ${test1_names})
+ file(APPEND "${CMAKE_BINARY_DIR}/test1.c" "extern void ${name}(void);\n")
+endforeach()
+file(APPEND "${CMAKE_BINARY_DIR}/test1.c" "void test1(void)\n{\n")
+foreach(name ${test1_names})
+ file(APPEND "${CMAKE_BINARY_DIR}/test1.c" " ${name}();\n")
+endforeach()
+file(APPEND "${CMAKE_BINARY_DIR}/test1.c" "}\n")
+
+target_link_libraries(test1 PRIVATE ${test1_names})
+set_property(TARGET test1 PROPERTY INSTALL_RPATH
+ "${CMAKE_BINARY_DIR}/root-all/lib/rpath1"
+ )
+
+file(REMOVE "${CMAKE_BINARY_DIR}/test2.c")
+add_library(test2 SHARED "${CMAKE_BINARY_DIR}/test2.c")
+foreach(name ${test2_names})
+ file(APPEND "${CMAKE_BINARY_DIR}/test2.c" "extern void ${name}(void);\n")
+endforeach()
+file(APPEND "${CMAKE_BINARY_DIR}/test2.c" "void test2(void)\n{\n")
+foreach(name ${test2_names})
+ file(APPEND "${CMAKE_BINARY_DIR}/test2.c" " ${name}();\n")
+endforeach()
+file(APPEND "${CMAKE_BINARY_DIR}/test2.c" "}\n")
+
+target_link_libraries(test2 PRIVATE ${test2_names})
+set_property(TARGET test2 PROPERTY INSTALL_RPATH
+ "${CMAKE_BINARY_DIR}/root-all/lib/rpath2"
+ )
+
+install(TARGETS test1 test2 DESTINATION lib)
+
+install(CODE [[
+ file(GET_RUNTIME_DEPENDENCIES
+ LIBRARIES
+ "${CMAKE_INSTALL_PREFIX}/lib/$<TARGET_FILE_NAME:test1>"
+ "${CMAKE_INSTALL_PREFIX}/lib/$<TARGET_FILE_NAME:test2>"
+ PRE_INCLUDE_REGEXES "^librpath\\.so$"
+ PRE_EXCLUDE_REGEXES ".*"
+ )
+ message(FATAL_ERROR "This message should not be displayed")
+ ]])
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-notfile-all-result.txt b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-notfile-all-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-notfile-all-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-notfile-all-stderr.txt b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-notfile-all-stderr.txt
new file mode 100644
index 0000000..83a87c9
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-notfile-all-stderr.txt
@@ -0,0 +1,5 @@
+^CMake Error at cmake_install\.cmake:[0-9]+ \(file\):
+ file Failed to run objdump on:
+
+ [^
+]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-notfile-build/root-all/bin/\.\./lib/libtest\.so$
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-notfile.cmake b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-notfile.cmake
new file mode 100644
index 0000000..6567438
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-notfile.cmake
@@ -0,0 +1,30 @@
+enable_language(C)
+cmake_policy(SET CMP0095 NEW)
+
+file(WRITE "${CMAKE_BINARY_DIR}/test.c" "void test(void) {}\n")
+file(WRITE "${CMAKE_BINARY_DIR}/main.c" [[extern void test(void);
+
+int main(void)
+{
+ test();
+ return 0;
+}
+]])
+
+add_library(test SHARED "${CMAKE_BINARY_DIR}/test.c")
+add_executable(exe "${CMAKE_BINARY_DIR}/main.c")
+target_link_libraries(exe PRIVATE test)
+set_property(TARGET exe PROPERTY INSTALL_RPATH "\${ORIGIN}/../lib")
+
+install(TARGETS exe DESTINATION bin)
+
+install(CODE [[
+ file(MAKE_DIRECTORY "${CMAKE_INSTALL_PREFIX}/lib/$<TARGET_FILE_NAME:test>")
+ file(GET_RUNTIME_DEPENDENCIES
+ EXECUTABLES
+ "${CMAKE_INSTALL_PREFIX}/bin/$<TARGET_FILE_NAME:exe>"
+ PRE_INCLUDE_REGEXES "^libtest\\.so$"
+ PRE_EXCLUDE_REGEXES ".*"
+ )
+ message(FATAL_ERROR "This message should not be displayed")
+ ]])
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-unresolved-all-result.txt b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-unresolved-all-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-unresolved-all-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-unresolved-all-stderr.txt b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-unresolved-all-stderr.txt
new file mode 100644
index 0000000..eaca512
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-unresolved-all-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error at cmake_install\.cmake:[0-9]+ \(file\):
+ file Could not resolve file libunresolved\.so$
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-unresolved.cmake b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-unresolved.cmake
new file mode 100644
index 0000000..3efa305
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-unresolved.cmake
@@ -0,0 +1,18 @@
+enable_language(C)
+
+file(WRITE "${CMAKE_BINARY_DIR}/testlib.c" "extern void unresolved(void);\nvoid testlib(void)\n{\n unresolved();\n}\n")
+add_library(testlib SHARED "${CMAKE_BINARY_DIR}/testlib.c")
+file(WRITE "${CMAKE_BINARY_DIR}/unresolved.c" "void unresolved(void) {}\n")
+add_library(unresolved SHARED "${CMAKE_BINARY_DIR}/unresolved.c")
+target_link_libraries(testlib PRIVATE unresolved)
+install(TARGETS testlib DESTINATION lib)
+
+install(CODE [[
+ file(GET_RUNTIME_DEPENDENCIES
+ PRE_INCLUDE_REGEXES "^libunresolved\\.so$"
+ PRE_EXCLUDE_REGEXES ".*"
+ LIBRARIES
+ "${CMAKE_INSTALL_PREFIX}/lib/$<TARGET_FILE_NAME:testlib>"
+ )
+ message(FATAL_ERROR "This message should not be displayed")
+ ]])
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux.cmake b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux.cmake
new file mode 100644
index 0000000..bd0f9f1
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux.cmake
@@ -0,0 +1,169 @@
+enable_language(C)
+cmake_policy(SET CMP0095 NEW)
+
+set(test_rpath_names
+ preexcluded
+ rpath_postexcluded
+ rpath
+ rpath_parent_postexcluded
+ rpath_parent
+ rpath_origin_postexcluded
+ rpath_origin
+ rpath_search_postexcluded
+ rpath_search
+ rpath_unresolved
+ conflict
+ )
+set(test_runpath_names
+ runpath_postexcluded
+ runpath
+ runpath_origin_postexcluded
+ runpath_origin
+ runpath_parent_unresolved
+ runpath_search_postexcluded
+ runpath_search
+ runpath_unresolved
+ )
+
+file(REMOVE "${CMAKE_BINARY_DIR}/test_rpath.c")
+add_library(test_rpath SHARED "${CMAKE_BINARY_DIR}/test_rpath.c")
+foreach(name ${test_rpath_names})
+ file(WRITE "${CMAKE_BINARY_DIR}/${name}.c" "void ${name}(void) {}\n")
+ add_library(${name} SHARED "${CMAKE_BINARY_DIR}/${name}.c")
+
+ file(APPEND "${CMAKE_BINARY_DIR}/test_rpath.c" "extern void ${name}(void);\n")
+endforeach()
+file(APPEND "${CMAKE_BINARY_DIR}/test_rpath.c" "void test_rpath(void)\n{\n")
+foreach(name ${test_rpath_names})
+ file(APPEND "${CMAKE_BINARY_DIR}/test_rpath.c" " ${name}();\n")
+endforeach()
+file(APPEND "${CMAKE_BINARY_DIR}/test_rpath.c" "}\n")
+
+install(TARGETS rpath_postexcluded DESTINATION lib/rpath_postexcluded)
+install(TARGETS rpath DESTINATION lib/rpath)
+install(TARGETS rpath_origin_postexcluded DESTINATION lib/rpath_origin_postexcluded)
+install(TARGETS rpath_origin DESTINATION lib/rpath_origin)
+install(TARGETS rpath_parent_postexcluded DESTINATION lib/rpath_parent_postexcluded)
+install(TARGETS rpath rpath_origin rpath_parent DESTINATION lib/rpath_parent)
+install(TARGETS rpath_search_postexcluded DESTINATION lib/rpath_search_postexcluded)
+install(TARGETS rpath rpath_origin rpath_parent rpath_search DESTINATION lib/rpath_search)
+install(TARGETS conflict DESTINATION lib/conflict)
+
+target_link_libraries(test_rpath PRIVATE ${test_rpath_names})
+set_property(TARGET test_rpath PROPERTY INSTALL_RPATH
+ "${CMAKE_BINARY_DIR}/root-all/lib/rpath_postexcluded"
+ "${CMAKE_BINARY_DIR}/root-all/lib/rpath"
+ "\$ORIGIN/rpath_origin_postexcluded"
+ "\${ORIGIN}/rpath_origin"
+ "${CMAKE_BINARY_DIR}/root-all/lib/conflict"
+ )
+target_link_options(test_rpath PRIVATE -Wl,--disable-new-dtags)
+
+file(REMOVE "${CMAKE_BINARY_DIR}/test_runpath.c")
+add_library(test_runpath SHARED "${CMAKE_BINARY_DIR}/test_runpath.c")
+foreach(name ${test_runpath_names} rpath conflict)
+ file(WRITE "${CMAKE_BINARY_DIR}/${name}.c" "void ${name}(void) {}\n")
+ if(NOT name MATCHES "^(rpath|conflict)$")
+ add_library(${name} SHARED "${CMAKE_BINARY_DIR}/${name}.c")
+ endif()
+
+ file(APPEND "${CMAKE_BINARY_DIR}/test_runpath.c" "extern void ${name}(void);\n")
+endforeach()
+file(APPEND "${CMAKE_BINARY_DIR}/test_runpath.c" "void test_runpath(void)\n{\n")
+foreach(name ${test_runpath_names} rpath conflict)
+ file(APPEND "${CMAKE_BINARY_DIR}/test_runpath.c" " ${name}();\n")
+endforeach()
+file(APPEND "${CMAKE_BINARY_DIR}/test_runpath.c" "}\n")
+
+install(TARGETS runpath_postexcluded DESTINATION lib/runpath_postexcluded)
+install(TARGETS runpath DESTINATION lib/runpath)
+install(TARGETS runpath_origin_postexcluded DESTINATION lib/runpath_origin_postexcluded)
+install(TARGETS runpath_origin DESTINATION lib/runpath_origin)
+install(TARGETS runpath_parent_unresolved DESTINATION lib/runpath_parent_unresolved)
+install(TARGETS runpath_search_postexcluded DESTINATION lib/runpath_search_postexcluded)
+install(TARGETS runpath runpath_origin runpath_search DESTINATION lib/runpath_search)
+install(TARGETS conflict DESTINATION lib/conflict2)
+
+target_link_libraries(test_runpath PRIVATE ${test_runpath_names} rpath conflict)
+set_property(TARGET test_runpath PROPERTY INSTALL_RPATH
+ "${CMAKE_BINARY_DIR}/root-all/lib/runpath/../rpath" # Ensure that files that don't conflict are treated correctly
+ "${CMAKE_BINARY_DIR}/root-all/lib/runpath_postexcluded"
+ "${CMAKE_BINARY_DIR}/root-all/lib/runpath"
+ "\${ORIGIN}/runpath_origin_postexcluded"
+ "\$ORIGIN/runpath_origin"
+ "${CMAKE_BINARY_DIR}/root-all/lib/conflict2"
+ )
+target_link_options(test_runpath PRIVATE -Wl,--enable-new-dtags)
+
+set_property(TARGET test_rpath ${test_rpath_names} test_runpath ${test_runpath_names} PROPERTY LIBRARY_OUTPUT_DIRECTORY lib)
+install(TARGETS test_rpath test_runpath DESTINATION lib)
+
+add_executable(topexe file-GET_RUNTIME_DEPENDENCIES-linux/topexe.c)
+add_library(toplib SHARED file-GET_RUNTIME_DEPENDENCIES-linux/toplib.c)
+add_library(topmod MODULE file-GET_RUNTIME_DEPENDENCIES-linux/toplib.c)
+target_link_libraries(topexe PRIVATE test_rpath test_runpath)
+target_link_libraries(toplib PRIVATE test_rpath test_runpath)
+target_link_libraries(topmod PRIVATE test_rpath test_runpath)
+set_property(TARGET topexe toplib topmod PROPERTY INSTALL_RPATH
+ "${CMAKE_BINARY_DIR}/root-all/lib"
+ "${CMAKE_BINARY_DIR}/root-all/lib/rpath_parent_postexcluded"
+ "${CMAKE_BINARY_DIR}/root-all/lib/rpath_parent"
+ "${CMAKE_BINARY_DIR}/root-all/lib/runpath_parent_unresolved"
+ )
+target_link_options(topexe PRIVATE -Wl,--disable-new-dtags)
+target_link_options(toplib PRIVATE -Wl,--disable-new-dtags)
+target_link_options(topmod PRIVATE -Wl,--disable-new-dtags)
+
+install(TARGETS topexe toplib RUNTIME DESTINATION bin LIBRARY DESTINATION lib)
+install(TARGETS topmod LIBRARY DESTINATION lib/modules)
+
+install(CODE [[
+ function(exec_get_runtime_dependencies depsfile udepsfile cdepsfile)
+ file(GET_RUNTIME_DEPENDENCIES
+ RESOLVED_DEPENDENCIES_VAR deps
+ UNRESOLVED_DEPENDENCIES_VAR udeps
+ CONFLICTING_DEPENDENCIES_PREFIX cdeps
+ PRE_INCLUDE_REGEXES
+ "^lib(test_rpath|rpath_postexcluded|rpath|rpath_parent_postexcluded|rpath_parent|rpath_origin_postexcluded|rpath_origin|rpath_search_postexcluded|rpath_search|rpath_unresolved|test_runpath|runpath_postexcluded|runpath|runpath_origin_postexcluded|runpath_origin|runpath_parent_unresolved|runpath_search_postexcluded|runpath_search|runpath_unresolved|conflict)\\.so$"
+ "^libc\\.so"
+ PRE_EXCLUDE_REGEXES ".*"
+ POST_INCLUDE_REGEXES "^.*/(libtest_rpath|rpath/librpath|rpath_parent/librpath_parent|rpath_search/librpath_search|libtest_runpath|runpath/librunpath|runpath_origin_postexcluded|runpath_origin|runpath_search/librunpath_search|conflict2?/libconflict)\\.so$"
+ POST_EXCLUDE_REGEXES ".*"
+ DIRECTORIES
+ "${CMAKE_INSTALL_PREFIX}/lib/rpath_search_postexcluded"
+ "${CMAKE_INSTALL_PREFIX}/lib/rpath_search"
+ "${CMAKE_INSTALL_PREFIX}/lib/runpath_search_postexcluded"
+ "${CMAKE_INSTALL_PREFIX}/lib/runpath_search"
+ ${ARGN}
+ )
+ list(SORT deps)
+ list(SORT udeps)
+ list(SORT cdeps_FILENAMES)
+ file(WRITE "${CMAKE_INSTALL_PREFIX}/deps/${depsfile}" "${deps}")
+ file(WRITE "${CMAKE_INSTALL_PREFIX}/deps/${udepsfile}" "${udeps}")
+ file(WRITE "${CMAKE_INSTALL_PREFIX}/deps/${cdepsfile}" "")
+ foreach(cdep IN LISTS cdeps_FILENAMES)
+ set(cdep_values ${cdeps_${cdep}})
+ list(SORT cdep_values)
+ file(APPEND "${CMAKE_INSTALL_PREFIX}/deps/${cdepsfile}" "${cdep}:${cdep_values}\n")
+ endforeach()
+ endfunction()
+
+ exec_get_runtime_dependencies(
+ deps1.txt udeps1.txt cdeps1.txt
+ EXECUTABLES
+ "${CMAKE_INSTALL_PREFIX}/bin/$<TARGET_FILE_NAME:topexe>"
+ )
+
+ exec_get_runtime_dependencies(
+ deps2.txt udeps2.txt cdeps2.txt
+ LIBRARIES
+ "${CMAKE_INSTALL_PREFIX}/lib/$<TARGET_FILE_NAME:toplib>"
+ )
+
+ exec_get_runtime_dependencies(
+ deps3.txt udeps3.txt cdeps3.txt
+ MODULES
+ "${CMAKE_INSTALL_PREFIX}/lib/modules/$<TARGET_FILE_NAME:topmod>"
+ )
+ ]])
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux/topexe.c b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux/topexe.c
new file mode 100644
index 0000000..d196afe
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux/topexe.c
@@ -0,0 +1,9 @@
+extern void test_rpath(void);
+extern void test_runpath(void);
+
+int main(void)
+{
+ test_rpath();
+ test_runpath();
+ return 0;
+}
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux/toplib.c b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux/toplib.c
new file mode 100644
index 0000000..040e591
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux/toplib.c
@@ -0,0 +1,8 @@
+extern void test_rpath(void);
+extern void test_runpath(void);
+
+void toplib(void)
+{
+ test_rpath();
+ test_runpath();
+}
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-all-check.cmake b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-all-check.cmake
new file mode 100644
index 0000000..4d6dde1
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-all-check.cmake
@@ -0,0 +1,157 @@
+function(check_contents filename contents_regex)
+ if(EXISTS "${CMAKE_INSTALL_PREFIX}/${filename}")
+ file(READ "${CMAKE_INSTALL_PREFIX}/${filename}" contents)
+ if(NOT contents MATCHES "${contents_regex}")
+ string(APPEND RunCMake_TEST_FAILED "File contents:
+ ${contents}
+do not match what we expected:
+ ${contents_regex}
+in file:
+ ${CMAKE_INSTALL_PREFIX}/${filename}\n")
+ set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
+ endif()
+ else()
+ string(APPEND RunCMake_TEST_FAILED "File ${CMAKE_INSTALL_PREFIX}/${filename} does not exist")
+ set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+set(_check
+ [[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/bin/../lib/executable_path/libexecutable_path\.dylib]]
+ [[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/bin/../lib/rpath_executable_path/librpath_executable_path\.dylib]]
+ [[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/libtestlib\.dylib]]
+ [[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/loader_path/libloader_path\.dylib]]
+ [[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/normal/../rpath/librpath\.dylib]]
+ [[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/normal/libnormal\.dylib]]
+ [[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/rpath_loader_path/librpath_loader_path\.dylib]]
+ [[/usr/lib/libSystem\.B\.dylib]]
+ )
+check_contents(deps/deps1.txt "^${_check}$")
+
+set(_check
+ [[@executable_path/../lib/executable_path_bundle/libexecutable_path_bundle\.dylib]]
+ [[@loader_path/loader_path_unresolved/libloader_path_unresolved\.dylib]]
+ [[@rpath/librpath_executable_path_bundle\.dylib]]
+ [[@rpath/librpath_loader_path_unresolved\.dylib]]
+ [[@rpath/librpath_unresolved\.dylib]]
+ )
+check_contents(deps/udeps1.txt "^${_check}$")
+
+set(_check
+ [[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/libtestlib\.dylib]]
+ [[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/loader_path/libloader_path\.dylib]]
+ [[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/normal/../rpath/librpath\.dylib]]
+ [[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/normal/libnormal\.dylib]]
+ [[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/rpath_loader_path/librpath_loader_path\.dylib]]
+ [[/usr/lib/libSystem\.B\.dylib]]
+ )
+check_contents(deps/deps2.txt "^${_check}$")
+
+set(_check
+ [[@executable_path/../lib/executable_path/libexecutable_path\.dylib]]
+ [[@executable_path/../lib/executable_path_bundle/libexecutable_path_bundle\.dylib]]
+ [[@executable_path/../lib/executable_path_postexcluded/libexecutable_path_postexcluded\.dylib]]
+ [[@loader_path/loader_path_unresolved/libloader_path_unresolved\.dylib]]
+ [[@rpath/librpath_executable_path\.dylib]]
+ [[@rpath/librpath_executable_path_bundle\.dylib]]
+ [[@rpath/librpath_executable_path_postexcluded\.dylib]]
+ [[@rpath/librpath_loader_path_unresolved\.dylib]]
+ [[@rpath/librpath_unresolved\.dylib]]
+ )
+check_contents(deps/udeps2.txt "^${_check}$")
+
+set(_check
+ [[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/libtestlib\.dylib]]
+ [[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/loader_path/libloader_path\.dylib]]
+ [[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/normal/../rpath/librpath\.dylib]]
+ [[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/normal/libnormal\.dylib]]
+ [[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/rpath_loader_path/librpath_loader_path\.dylib]]
+ [[/usr/lib/libSystem\.B\.dylib]]
+ )
+check_contents(deps/deps3.txt "^${_check}$")
+
+set(_check
+ [[@executable_path/../lib/executable_path/libexecutable_path\.dylib]]
+ [[@executable_path/../lib/executable_path_bundle/libexecutable_path_bundle\.dylib]]
+ [[@executable_path/../lib/executable_path_postexcluded/libexecutable_path_postexcluded\.dylib]]
+ [[@loader_path/loader_path_unresolved/libloader_path_unresolved\.dylib]]
+ [[@rpath/librpath_executable_path\.dylib]]
+ [[@rpath/librpath_executable_path_bundle\.dylib]]
+ [[@rpath/librpath_executable_path_postexcluded\.dylib]]
+ [[@rpath/librpath_loader_path_unresolved\.dylib]]
+ [[@rpath/librpath_unresolved\.dylib]]
+ )
+check_contents(deps/udeps3.txt "^${_check}$")
+
+set(_check
+ [[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/bin/../lib/executable_path/libexecutable_path\.dylib]]
+ [[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/bin/../lib/rpath_executable_path/librpath_executable_path\.dylib]]
+ [[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/libtestlib\.dylib]]
+ [[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/loader_path/libloader_path\.dylib]]
+ [[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/normal/../rpath/librpath\.dylib]]
+ [[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/normal/libnormal\.dylib]]
+ [[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/rpath_loader_path/librpath_loader_path\.dylib]]
+ [[/usr/lib/libSystem\.B\.dylib]]
+ )
+check_contents(deps/deps4.txt "^${_check}$")
+
+set(_check
+ [[@executable_path/../lib/executable_path_bundle/libexecutable_path_bundle\.dylib]]
+ [[@loader_path/loader_path_unresolved/libloader_path_unresolved\.dylib]]
+ [[@rpath/librpath_executable_path_bundle\.dylib]]
+ [[@rpath/librpath_loader_path_unresolved\.dylib]]
+ [[@rpath/librpath_unresolved\.dylib]]
+ )
+check_contents(deps/udeps4.txt "^${_check}$")
+
+set(_check
+ [[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/bundle_executable/bin/../lib/executable_path_bundle/libexecutable_path_bundle\.dylib]]
+ [[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/libtestlib\.dylib]]
+ [[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/loader_path/libloader_path\.dylib]]
+ [[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/normal/../rpath/librpath\.dylib]]
+ [[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/normal/libnormal\.dylib]]
+ [[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/rpath_loader_path/librpath_loader_path\.dylib]]
+ [[/usr/lib/libSystem\.B\.dylib]]
+ )
+check_contents(deps/deps5.txt "^${_check}$")
+
+set(_check
+ [[@executable_path/../lib/executable_path/libexecutable_path\.dylib]]
+ [[@loader_path/loader_path_unresolved/libloader_path_unresolved\.dylib]]
+ [[@rpath/librpath_executable_path\.dylib]]
+ [[@rpath/librpath_executable_path_bundle\.dylib]]
+ [[@rpath/librpath_loader_path_unresolved\.dylib]]
+ [[@rpath/librpath_unresolved\.dylib]]
+ )
+check_contents(deps/udeps5.txt "^${_check}$")
+
+set(_check
+ [[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/bundle_executable/bin/../lib/executable_path_bundle/libexecutable_path_bundle\.dylib]]
+ [[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/libtestlib\.dylib]]
+ [[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/loader_path/libloader_path\.dylib]]
+ [[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/normal/../rpath/librpath\.dylib]]
+ [[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/normal/libnormal\.dylib]]
+ [[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/rpath_loader_path/librpath_loader_path\.dylib]]
+ [[/usr/lib/libSystem\.B\.dylib]]
+ )
+check_contents(deps/deps6.txt "^${_check}$")
+
+set(_check
+ [[@executable_path/../lib/executable_path/libexecutable_path\.dylib]]
+ [[@loader_path/loader_path_unresolved/libloader_path_unresolved\.dylib]]
+ [[@rpath/librpath_executable_path\.dylib]]
+ [[@rpath/librpath_executable_path_bundle\.dylib]]
+ [[@rpath/librpath_loader_path_unresolved\.dylib]]
+ [[@rpath/librpath_unresolved\.dylib]]
+ )
+check_contents(deps/udeps6.txt "^${_check}$")
+
+set(_check
+ "^libconflict\\.dylib:[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/conflict/libconflict\\.dylib;[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/conflict2/libconflict\\.dylib\n$"
+ )
+check_contents(deps/cdeps1.txt "${_check}")
+check_contents(deps/cdeps2.txt "${_check}")
+check_contents(deps/cdeps3.txt "${_check}")
+check_contents(deps/cdeps4.txt "${_check}")
+check_contents(deps/cdeps5.txt "${_check}")
+check_contents(deps/cdeps6.txt "${_check}")
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-conflict-all-result.txt b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-conflict-all-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-conflict-all-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-conflict-all-stderr.txt b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-conflict-all-stderr.txt
new file mode 100644
index 0000000..bc9e97a
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-conflict-all-stderr.txt
@@ -0,0 +1,7 @@
+^CMake Error at cmake_install\.cmake:[0-9]+ \(file\):
+ file Multiple conflicting paths found for librpath\.dylib:
+
+ [^
+]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-conflict-build/root-all/lib/rpath1/librpath\.dylib
+ [^
+]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-conflict-build/root-all/lib/rpath2/librpath\.dylib$
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-conflict.cmake b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-conflict.cmake
new file mode 100644
index 0000000..a8446fe
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-conflict.cmake
@@ -0,0 +1,55 @@
+enable_language(C)
+
+set(test1_names rpath)
+set(test2_names rpath)
+
+file(WRITE "${CMAKE_BINARY_DIR}/rpath.c" "void rpath(void) {}\n")
+add_library(rpath SHARED "${CMAKE_BINARY_DIR}/rpath.c")
+set_property(TARGET rpath PROPERTY INSTALL_NAME_DIR @rpath)
+install(TARGETS rpath DESTINATION lib/rpath1)
+install(TARGETS rpath DESTINATION lib/rpath2)
+
+file(REMOVE "${CMAKE_BINARY_DIR}/test1.c")
+add_library(test1 SHARED "${CMAKE_BINARY_DIR}/test1.c")
+foreach(name ${test1_names})
+ file(APPEND "${CMAKE_BINARY_DIR}/test1.c" "extern void ${name}(void);\n")
+endforeach()
+file(APPEND "${CMAKE_BINARY_DIR}/test1.c" "void test1(void)\n{\n")
+foreach(name ${test1_names})
+ file(APPEND "${CMAKE_BINARY_DIR}/test1.c" " ${name}();\n")
+endforeach()
+file(APPEND "${CMAKE_BINARY_DIR}/test1.c" "}\n")
+
+target_link_libraries(test1 PRIVATE ${test1_names})
+set_property(TARGET test1 PROPERTY INSTALL_RPATH
+ "${CMAKE_BINARY_DIR}/root-all/lib/rpath1"
+ )
+
+file(REMOVE "${CMAKE_BINARY_DIR}/test2.c")
+add_library(test2 SHARED "${CMAKE_BINARY_DIR}/test2.c")
+foreach(name ${test2_names})
+ file(APPEND "${CMAKE_BINARY_DIR}/test2.c" "extern void ${name}(void);\n")
+endforeach()
+file(APPEND "${CMAKE_BINARY_DIR}/test2.c" "void test2(void)\n{\n")
+foreach(name ${test2_names})
+ file(APPEND "${CMAKE_BINARY_DIR}/test2.c" " ${name}();\n")
+endforeach()
+file(APPEND "${CMAKE_BINARY_DIR}/test2.c" "}\n")
+
+target_link_libraries(test2 PRIVATE ${test2_names})
+set_property(TARGET test2 PROPERTY INSTALL_RPATH
+ "${CMAKE_BINARY_DIR}/root-all/lib/rpath2"
+ )
+
+install(TARGETS test1 test2 DESTINATION lib)
+
+install(CODE [[
+ file(GET_RUNTIME_DEPENDENCIES
+ LIBRARIES
+ "${CMAKE_INSTALL_PREFIX}/lib/$<TARGET_FILE_NAME:test1>"
+ "${CMAKE_INSTALL_PREFIX}/lib/$<TARGET_FILE_NAME:test2>"
+ PRE_INCLUDE_REGEXES "^@rpath/librpath\\.dylib$"
+ PRE_EXCLUDE_REGEXES ".*"
+ )
+ message(FATAL_ERROR "This message should not be displayed")
+ ]])
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-notfile-all-result.txt b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-notfile-all-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-notfile-all-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-notfile-all-stderr.txt b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-notfile-all-stderr.txt
new file mode 100644
index 0000000..73ab9f1
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-notfile-all-stderr.txt
@@ -0,0 +1,5 @@
+^CMake Error at cmake_install\.cmake:[0-9]+ \(file\):
+ file Failed to run otool on:
+
+ [^
+]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-notfile-build/root-all/bin/\.\./lib/libtest\.dylib$
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-notfile.cmake b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-notfile.cmake
new file mode 100644
index 0000000..3e4c434
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-notfile.cmake
@@ -0,0 +1,30 @@
+enable_language(C)
+
+file(WRITE "${CMAKE_BINARY_DIR}/test.c" "void test(void) {}\n")
+file(WRITE "${CMAKE_BINARY_DIR}/main.c" [[extern void test(void);
+
+int main(void)
+{
+ test();
+ return 0;
+}
+]])
+
+add_library(test SHARED "${CMAKE_BINARY_DIR}/test.c")
+set_property(TARGET test PROPERTY INSTALL_NAME_DIR @rpath)
+add_executable(exe "${CMAKE_BINARY_DIR}/main.c")
+target_link_libraries(exe PRIVATE test)
+set_property(TARGET exe PROPERTY INSTALL_RPATH "@loader_path/../lib")
+
+install(TARGETS exe DESTINATION bin)
+
+install(CODE [[
+ file(MAKE_DIRECTORY "${CMAKE_INSTALL_PREFIX}/lib/$<TARGET_FILE_NAME:test>")
+ file(GET_RUNTIME_DEPENDENCIES
+ EXECUTABLES
+ "${CMAKE_INSTALL_PREFIX}/bin/$<TARGET_FILE_NAME:exe>"
+ PRE_INCLUDE_REGEXES "^@rpath/libtest\\.dylib$"
+ PRE_EXCLUDE_REGEXES ".*"
+ )
+ message(FATAL_ERROR "This message should not be displayed")
+ ]])
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-unresolved-all-result.txt b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-unresolved-all-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-unresolved-all-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-unresolved-all-stderr.txt b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-unresolved-all-stderr.txt
new file mode 100644
index 0000000..01762b4
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-unresolved-all-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error at cmake_install\.cmake:[0-9]+ \(file\):
+ file Could not resolve file @rpath/libunresolved\.dylib$
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-unresolved.cmake b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-unresolved.cmake
new file mode 100644
index 0000000..c9b6c95
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-unresolved.cmake
@@ -0,0 +1,18 @@
+enable_language(C)
+
+file(WRITE "${CMAKE_BINARY_DIR}/testlib.c" "extern void unresolved(void);\nvoid testlib(void)\n{\n unresolved();\n}\n")
+add_library(testlib SHARED "${CMAKE_BINARY_DIR}/testlib.c")
+file(WRITE "${CMAKE_BINARY_DIR}/unresolved.c" "void unresolved(void) {}\n")
+add_library(unresolved SHARED "${CMAKE_BINARY_DIR}/unresolved.c")
+target_link_libraries(testlib PRIVATE unresolved)
+install(TARGETS testlib DESTINATION lib)
+
+install(CODE [[
+ file(GET_RUNTIME_DEPENDENCIES
+ PRE_INCLUDE_REGEXES "^@rpath/libunresolved\\.dylib$"
+ PRE_EXCLUDE_REGEXES ".*"
+ LIBRARIES
+ "${CMAKE_INSTALL_PREFIX}/lib/$<TARGET_FILE_NAME:testlib>"
+ )
+ message(FATAL_ERROR "This message should not be displayed")
+ ]])
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos.cmake b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos.cmake
new file mode 100644
index 0000000..6db05b3
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos.cmake
@@ -0,0 +1,216 @@
+enable_language(C)
+
+set(testlib_names
+ preexcluded
+ executable_path
+ executable_path_bundle
+ executable_path_postexcluded
+ loader_path
+ loader_path_unresolved
+ loader_path_postexcluded
+ rpath
+ rpath_unresolved
+ rpath_postexcluded
+ rpath_executable_path
+ rpath_executable_path_bundle
+ rpath_executable_path_postexcluded
+ rpath_loader_path
+ rpath_loader_path_unresolved
+ rpath_loader_path_postexcluded
+ normal
+ normal_unresolved
+ normal_postexcluded
+ conflict
+ )
+
+file(REMOVE "${CMAKE_BINARY_DIR}/testlib.c")
+add_library(testlib SHARED "${CMAKE_BINARY_DIR}/testlib.c")
+foreach(name ${testlib_names})
+ if(name STREQUAL "normal")
+ file(WRITE "${CMAKE_BINARY_DIR}/normal.c" "extern void rpath(void);\nvoid normal(void)\n{\n rpath();\n}\n")
+ else()
+ file(WRITE "${CMAKE_BINARY_DIR}/${name}.c" "void ${name}(void) {}\n")
+ endif()
+ add_library(${name} SHARED "${CMAKE_BINARY_DIR}/${name}.c")
+
+ file(APPEND "${CMAKE_BINARY_DIR}/testlib.c" "extern void ${name}(void);\n")
+endforeach()
+file(APPEND "${CMAKE_BINARY_DIR}/testlib.c" "void testlib(void)\n{\n")
+foreach(name ${testlib_names})
+ file(APPEND "${CMAKE_BINARY_DIR}/testlib.c" " ${name}();\n")
+endforeach()
+file(APPEND "${CMAKE_BINARY_DIR}/testlib.c" "}\n")
+set_property(TARGET ${testlib_names} PROPERTY BUILD_WITH_INSTALL_NAME_DIR 1)
+target_link_libraries(normal PRIVATE rpath)
+set_property(TARGET normal PROPERTY INSTALL_RPATH
+ "${CMAKE_BINARY_DIR}/root-all/executable/lib/normal/../rpath"
+ )
+
+file(WRITE "${CMAKE_BINARY_DIR}/testlib_conflict.c" "extern void conflict(void);\nvoid testlib_conflict(void)\n{\n conflict();\n}\n")
+add_library(testlib_conflict SHARED "${CMAKE_BINARY_DIR}/testlib_conflict.c")
+target_link_libraries(testlib_conflict PRIVATE conflict)
+
+set_property(TARGET testlib PROPERTY INSTALL_RPATH
+ "${CMAKE_BINARY_DIR}/root-all/executable/lib/rpath"
+ "${CMAKE_BINARY_DIR}/root-all/executable/lib/rpath_unresolved"
+ "${CMAKE_BINARY_DIR}/root-all/executable/lib/rpath_postexcluded"
+ "${CMAKE_BINARY_DIR}/root-all/executable/lib/conflict"
+ @executable_path/../lib/rpath_executable_path
+ @executable_path/../lib/rpath_executable_path_unresolved
+ @executable_path/../lib/rpath_executable_path_postexcluded
+ @loader_path/rpath_loader_path
+ @loader_path/rpath_loader_path_unresolved
+ @loader_path/rpath_loader_path_postexcluded
+ )
+set_property(TARGET testlib_conflict PROPERTY INSTALL_RPATH
+ "${CMAKE_BINARY_DIR}/root-all/executable/lib/conflict2"
+ )
+
+foreach(t
+ executable_path
+ executable_path_postexcluded
+ loader_path
+ loader_path_postexcluded
+ rpath
+ rpath_postexcluded
+ rpath_executable_path
+ rpath_executable_path_postexcluded
+ rpath_loader_path
+ rpath_loader_path_postexcluded
+ conflict
+ )
+ install(TARGETS ${t} DESTINATION executable/lib/${t})
+endforeach()
+install(TARGETS conflict DESTINATION executable/lib/conflict2)
+
+foreach(t
+ executable_path_bundle
+ executable_path_postexcluded
+ loader_path_postexcluded
+ rpath_postexcluded
+ rpath_executable_path_bundle
+ rpath_executable_path_postexcluded
+ rpath_loader_path_postexcluded
+ )
+ install(TARGETS ${t} DESTINATION bundle_executable/lib/${t})
+endforeach()
+
+foreach(t executable_path executable_path_bundle executable_path_postexcluded)
+ set_property(TARGET ${t} PROPERTY INSTALL_NAME_DIR @executable_path/../lib/${t})
+endforeach()
+
+foreach(t loader_path loader_path_unresolved loader_path_postexcluded)
+ set_property(TARGET ${t} PROPERTY INSTALL_NAME_DIR @loader_path/${t})
+endforeach()
+
+foreach(t
+ rpath
+ rpath_unresolved
+ rpath_postexcluded
+ rpath_executable_path
+ rpath_executable_path_bundle
+ rpath_executable_path_postexcluded
+ rpath_loader_path
+ rpath_loader_path_unresolved
+ rpath_loader_path_postexcluded
+ conflict
+ )
+ set_property(TARGET ${t} PROPERTY INSTALL_NAME_DIR @rpath)
+endforeach()
+
+foreach(t normal normal_unresolved normal_postexcluded)
+ set_property(TARGET ${t} PROPERTY INSTALL_NAME_DIR "${CMAKE_BINARY_DIR}/root-all/executable/lib/${t}")
+ if(NOT t STREQUAL "normal_unresolved")
+ install(TARGETS ${t} DESTINATION executable/lib/${t})
+ endif()
+endforeach()
+
+target_link_libraries(testlib PRIVATE ${testlib_names})
+
+add_executable(topexe file-GET_RUNTIME_DEPENDENCIES-macos/topexe.c)
+add_library(toplib SHARED file-GET_RUNTIME_DEPENDENCIES-macos/toplib.c)
+add_library(topmod MODULE file-GET_RUNTIME_DEPENDENCIES-macos/toplib.c)
+target_link_libraries(topexe PRIVATE testlib)
+target_link_libraries(toplib PRIVATE testlib)
+target_link_libraries(topmod PRIVATE testlib)
+
+set_property(TARGET topexe toplib topmod PROPERTY INSTALL_RPATH "${CMAKE_BINARY_DIR}/root-all/executable/lib")
+
+install(TARGETS topexe toplib topmod testlib testlib_conflict RUNTIME DESTINATION executable/bin LIBRARY DESTINATION executable/lib)
+install(TARGETS topexe toplib topmod testlib testlib_conflict RUNTIME DESTINATION bundle_executable/bin LIBRARY DESTINATION bundle_executable/lib)
+
+install(CODE [[
+ function(exec_get_runtime_dependencies depsfile udepsfile cdepsfile)
+ file(GET_RUNTIME_DEPENDENCIES
+ RESOLVED_DEPENDENCIES_VAR deps
+ UNRESOLVED_DEPENDENCIES_VAR udeps
+ CONFLICTING_DEPENDENCIES_PREFIX cdeps
+ PRE_INCLUDE_REGEXES "^.*/lib(testlib|executable_path|executable_path_bundle|executable_path_postexcluded|loader_path|loader_path_unresolved|loader_path_postexcluded|rpath|rpath_unresolved|rpath_postexcluded|rpath_executable_path|rpath_executable_path_bundle|rpath_executable_path_postexcluded|rpath_loader_path|rpath_loader_path_unresolved|rpath_loader_path_postexcluded|normal|normal_unresolved|normal_postexcluded|conflict|System\\.B)\\.dylib$"
+ PRE_EXCLUDE_REGEXES ".*"
+ POST_INCLUDE_REGEXES "^.*/lib(testlib|executable_path|executable_path_bundle|loader_path|rpath|rpath_executable_path|rpath_executable_path_bundle|rpath_loader_path|normal|conflict|System\\.B)\\.dylib$"
+ POST_EXCLUDE_REGEXES ".*"
+ ${ARGN}
+ )
+ list(SORT deps)
+ list(SORT udeps)
+ list(SORT cdeps_FILENAMES)
+ file(WRITE "${CMAKE_INSTALL_PREFIX}/deps/${depsfile}" "${deps}")
+ file(WRITE "${CMAKE_INSTALL_PREFIX}/deps/${udepsfile}" "${udeps}")
+ file(WRITE "${CMAKE_INSTALL_PREFIX}/deps/${cdepsfile}" "")
+ foreach(cdep IN LISTS cdeps_FILENAMES)
+ set(cdep_values ${cdeps_${cdep}})
+ list(SORT cdep_values)
+ file(APPEND "${CMAKE_INSTALL_PREFIX}/deps/${cdepsfile}" "${cdep}:${cdep_values}\n")
+ endforeach()
+ endfunction()
+
+ exec_get_runtime_dependencies(
+ deps1.txt udeps1.txt cdeps1.txt
+ EXECUTABLES
+ "${CMAKE_INSTALL_PREFIX}/executable/bin/$<TARGET_FILE_NAME:topexe>"
+ LIBRARIES
+ "${CMAKE_INSTALL_PREFIX}/executable/lib/$<TARGET_FILE_NAME:testlib_conflict>"
+ )
+
+ exec_get_runtime_dependencies(
+ deps2.txt udeps2.txt cdeps2.txt
+ LIBRARIES
+ "${CMAKE_INSTALL_PREFIX}/executable/lib/$<TARGET_FILE_NAME:toplib>"
+ "${CMAKE_INSTALL_PREFIX}/executable/lib/$<TARGET_FILE_NAME:testlib_conflict>"
+ )
+
+ exec_get_runtime_dependencies(
+ deps3.txt udeps3.txt cdeps3.txt
+ MODULES
+ "${CMAKE_INSTALL_PREFIX}/executable/lib/$<TARGET_FILE_NAME:topmod>"
+ LIBRARIES
+ "${CMAKE_INSTALL_PREFIX}/executable/lib/$<TARGET_FILE_NAME:testlib_conflict>"
+ )
+
+ exec_get_runtime_dependencies(
+ deps4.txt udeps4.txt cdeps4.txt
+ EXECUTABLES
+ "${CMAKE_INSTALL_PREFIX}/executable/bin/$<TARGET_FILE_NAME:topexe>"
+ LIBRARIES
+ "${CMAKE_INSTALL_PREFIX}/executable/lib/$<TARGET_FILE_NAME:testlib_conflict>"
+ BUNDLE_EXECUTABLE
+ "${CMAKE_INSTALL_PREFIX}/bundle_executable/bin/$<TARGET_FILE_NAME:topexe>"
+ )
+
+ exec_get_runtime_dependencies(
+ deps5.txt udeps5.txt cdeps5.txt
+ LIBRARIES
+ "${CMAKE_INSTALL_PREFIX}/executable/lib/$<TARGET_FILE_NAME:toplib>"
+ "${CMAKE_INSTALL_PREFIX}/executable/lib/$<TARGET_FILE_NAME:testlib_conflict>"
+ BUNDLE_EXECUTABLE "${CMAKE_INSTALL_PREFIX}/bundle_executable/bin/$<TARGET_FILE_NAME:topexe>"
+ )
+
+ exec_get_runtime_dependencies(
+ deps6.txt udeps6.txt cdeps6.txt
+ MODULES
+ "${CMAKE_INSTALL_PREFIX}/executable/lib/$<TARGET_FILE_NAME:topmod>"
+ LIBRARIES
+ "${CMAKE_INSTALL_PREFIX}/executable/lib/$<TARGET_FILE_NAME:testlib_conflict>"
+ BUNDLE_EXECUTABLE "${CMAKE_INSTALL_PREFIX}/bundle_executable/bin/$<TARGET_FILE_NAME:topexe>"
+ )
+ ]])
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos/topexe.c b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos/topexe.c
new file mode 100644
index 0000000..20c6087
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos/topexe.c
@@ -0,0 +1,7 @@
+extern void testlib(void);
+
+int main(void)
+{
+ testlib();
+ return 0;
+}
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos/toplib.c b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos/toplib.c
new file mode 100644
index 0000000..cff1bff
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos/toplib.c
@@ -0,0 +1,6 @@
+extern void testlib(void);
+
+void toplib(void)
+{
+ testlib();
+}
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-project-stderr.txt b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-project-stderr.txt
new file mode 100644
index 0000000..d506645
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-project-stderr.txt
@@ -0,0 +1,13 @@
+^CMake Warning \(dev\) at file-GET_RUNTIME_DEPENDENCIES-project\.cmake:[0-9]+ \(file\):
+ You have used file\(GET_RUNTIME_DEPENDENCIES\) in project mode\. This is
+ probably not what you intended to do\. Instead, please consider using it in
+ an install\(CODE\) or install\(SCRIPT\) command\. For example:
+
+ install\(CODE \[\[
+ file\(GET_RUNTIME_DEPENDENCIES
+ # \.\.\.
+ \)
+ ]]\)
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\. Use -Wno-dev to suppress it\.$
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-project.cmake b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-project.cmake
new file mode 100644
index 0000000..842d7ab
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-project.cmake
@@ -0,0 +1 @@
+file(GET_RUNTIME_DEPENDENCIES RESOLVED_DEPENDENCIES_VAR deps)
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-unsupported-result.txt b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-unsupported-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-unsupported-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-unsupported-stderr.txt b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-unsupported-stderr.txt
new file mode 100644
index 0000000..3db835c
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-unsupported-stderr.txt
@@ -0,0 +1,5 @@
+^CMake Error at file-GET_RUNTIME_DEPENDENCIES-unsupported\.cmake:[0-9]+ \(file\):
+ file GET_RUNTIME_DEPENDENCIES is not supported on system "[^
+ ]+"
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-unsupported.cmake b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-unsupported.cmake
new file mode 100644
index 0000000..b91eefe
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-unsupported.cmake
@@ -0,0 +1,2 @@
+file(GET_RUNTIME_DEPENDENCIES RESOLVED_DEPENDENCIES_VAR deps)
+message(FATAL_ERROR "This message should not be displayed")
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows-all-check.cmake b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows-all-check.cmake
new file mode 100644
index 0000000..c120ce4
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows-all-check.cmake
@@ -0,0 +1,38 @@
+function(check_contents filename contents_regex)
+ if(EXISTS "${CMAKE_INSTALL_PREFIX}/${filename}")
+ file(READ "${CMAKE_INSTALL_PREFIX}/${filename}" contents)
+ if(NOT contents MATCHES "${contents_regex}")
+ string(APPEND RunCMake_TEST_FAILED "File contents:
+ ${contents}
+do not match what we expected:
+ ${contents_regex}
+in file:
+ ${CMAKE_INSTALL_PREFIX}/${filename}\n")
+ set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
+ endif()
+ else()
+ string(APPEND RunCMake_TEST_FAILED "File ${CMAKE_INSTALL_PREFIX}/${filename} does not exist")
+ set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+set(_check
+ [=[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows-build/root-all/bin/\.conflict/\.\./(lib)?libdir\.dll]=]
+ [=[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows-build/root-all/bin/\.search/(lib)?search\.dll]=]
+ [=[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows-build/root-all/bin/(lib)?testlib\.dll]=]
+ )
+check_contents(deps/deps1.txt "^${_check}$")
+check_contents(deps/deps2.txt "^${_check}$")
+check_contents(deps/deps3.txt "^${_check}$")
+set(_check
+ [=[(lib)?unresolved\.dll]=]
+ )
+check_contents(deps/udeps1.txt "^${_check}$")
+check_contents(deps/udeps2.txt "^${_check}$")
+check_contents(deps/udeps3.txt "^${_check}$")
+set(_check
+ "^(lib)?conflict\\.dll:[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows-build/root-all/bin/\\.conflict/(lib)?conflict\\.dll;[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows-build/root-all/bin/(lib)?conflict\\.dll\n$"
+ )
+check_contents(deps/cdeps1.txt "${_check}")
+check_contents(deps/cdeps2.txt "${_check}")
+check_contents(deps/cdeps3.txt "${_check}")
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows-conflict-all-result.txt b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows-conflict-all-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows-conflict-all-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows-conflict-all-stderr.txt b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows-conflict-all-stderr.txt
new file mode 100644
index 0000000..66ecb93
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows-conflict-all-stderr.txt
@@ -0,0 +1,7 @@
+^CMake Error at cmake_install\.cmake:[0-9]+ \(file\):
+ file Multiple conflicting paths found for (lib)?path\.dll:
+
+ [^
+]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows-conflict-build/root-all/lib/test1/(lib)?path\.dll
+ [^
+]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows-conflict-build/root-all/lib/test2/(lib)?path\.dll$
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows-conflict.cmake b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows-conflict.cmake
new file mode 100644
index 0000000..d413443
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows-conflict.cmake
@@ -0,0 +1,47 @@
+enable_language(C)
+
+set(test1_names path)
+set(test2_names path)
+
+file(WRITE "${CMAKE_BINARY_DIR}/path.c" "__declspec(dllexport) void path(void) {}\n")
+add_library(path SHARED "${CMAKE_BINARY_DIR}/path.c")
+
+file(REMOVE "${CMAKE_BINARY_DIR}/test1.c")
+add_library(test1 SHARED "${CMAKE_BINARY_DIR}/test1.c")
+foreach(name ${test1_names})
+ file(APPEND "${CMAKE_BINARY_DIR}/test1.c" "__declspec(dllimport) extern void ${name}(void);\n")
+endforeach()
+file(APPEND "${CMAKE_BINARY_DIR}/test1.c" "__declspec(dllexport) void test1(void)\n{\n")
+foreach(name ${test1_names})
+ file(APPEND "${CMAKE_BINARY_DIR}/test1.c" " ${name}();\n")
+endforeach()
+file(APPEND "${CMAKE_BINARY_DIR}/test1.c" "}\n")
+
+target_link_libraries(test1 PRIVATE ${test1_names})
+
+file(REMOVE "${CMAKE_BINARY_DIR}/test2.c")
+add_library(test2 SHARED "${CMAKE_BINARY_DIR}/test2.c")
+foreach(name ${test2_names})
+ file(APPEND "${CMAKE_BINARY_DIR}/test2.c" "__declspec(dllimport) extern void ${name}(void);\n")
+endforeach()
+file(APPEND "${CMAKE_BINARY_DIR}/test2.c" "__declspec(dllexport) void test2(void)\n{\n")
+foreach(name ${test2_names})
+ file(APPEND "${CMAKE_BINARY_DIR}/test2.c" " ${name}();\n")
+endforeach()
+file(APPEND "${CMAKE_BINARY_DIR}/test2.c" "}\n")
+
+target_link_libraries(test2 PRIVATE ${test2_names})
+
+install(TARGETS test1 path DESTINATION lib/test1)
+install(TARGETS test2 path DESTINATION lib/test2)
+
+install(CODE [[
+ file(GET_RUNTIME_DEPENDENCIES
+ LIBRARIES
+ "${CMAKE_INSTALL_PREFIX}/lib/test1/$<TARGET_FILE_NAME:test1>"
+ "${CMAKE_INSTALL_PREFIX}/lib/test2/$<TARGET_FILE_NAME:test2>"
+ PRE_INCLUDE_REGEXES "^(lib)?path\\.dll$"
+ PRE_EXCLUDE_REGEXES ".*"
+ )
+ message(FATAL_ERROR "This message should not be displayed")
+ ]])
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows-notfile-all-result.txt b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows-notfile-all-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows-notfile-all-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows-notfile-all-stderr.txt b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows-notfile-all-stderr.txt
new file mode 100644
index 0000000..f921409
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows-notfile-all-stderr.txt
@@ -0,0 +1,5 @@
+^CMake Error at cmake_install\.cmake:[0-9]+ \(file\):
+ file Failed to run (dumpbin|objdump) on:
+
+ [^
+]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows-notfile-build/root-all/bin/(lib)?test\.dll$
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows-notfile.cmake b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows-notfile.cmake
new file mode 100644
index 0000000..6665a3b
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows-notfile.cmake
@@ -0,0 +1,28 @@
+enable_language(C)
+
+file(WRITE "${CMAKE_BINARY_DIR}/test.c" "__declspec(dllexport) void test(void) {}\n")
+file(WRITE "${CMAKE_BINARY_DIR}/main.c" [[__declspec(dllimport) extern void test(void);
+
+int main(void)
+{
+ test();
+ return 0;
+}
+]])
+
+add_library(test SHARED "${CMAKE_BINARY_DIR}/test.c")
+add_executable(exe "${CMAKE_BINARY_DIR}/main.c")
+target_link_libraries(exe PRIVATE test)
+
+install(TARGETS exe DESTINATION bin)
+
+install(CODE [[
+ file(MAKE_DIRECTORY "${CMAKE_INSTALL_PREFIX}/bin/$<TARGET_FILE_NAME:test>")
+ file(GET_RUNTIME_DEPENDENCIES
+ EXECUTABLES
+ "${CMAKE_INSTALL_PREFIX}/bin/$<TARGET_FILE_NAME:exe>"
+ PRE_INCLUDE_REGEXES "^(lib)?test\\.dll$"
+ PRE_EXCLUDE_REGEXES ".*"
+ )
+ message(FATAL_ERROR "This message should not be displayed")
+ ]])
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows-unresolved-all-result.txt b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows-unresolved-all-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows-unresolved-all-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows-unresolved-all-stderr.txt b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows-unresolved-all-stderr.txt
new file mode 100644
index 0000000..a20654c
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows-unresolved-all-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error at cmake_install\.cmake:[0-9]+ \(file\):
+ file Could not resolve file (lib)?unresolved\.dll$
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows-unresolved.cmake b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows-unresolved.cmake
new file mode 100644
index 0000000..4cc74c7
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows-unresolved.cmake
@@ -0,0 +1,18 @@
+enable_language(C)
+
+file(WRITE "${CMAKE_BINARY_DIR}/testlib.c" "__declspec(dllimport) extern void unresolved(void);\n__declspec(dllexport) void testlib(void)\n{\n unresolved();\n}\n")
+add_library(testlib SHARED "${CMAKE_BINARY_DIR}/testlib.c")
+file(WRITE "${CMAKE_BINARY_DIR}/unresolved.c" "__declspec(dllexport) void unresolved(void) {}\n")
+add_library(unresolved SHARED "${CMAKE_BINARY_DIR}/unresolved.c")
+target_link_libraries(testlib PRIVATE unresolved)
+install(TARGETS testlib DESTINATION lib)
+
+install(CODE [[
+ file(GET_RUNTIME_DEPENDENCIES
+ PRE_INCLUDE_REGEXES "^(lib)?unresolved\\.dll$"
+ PRE_EXCLUDE_REGEXES ".*"
+ LIBRARIES
+ "${CMAKE_INSTALL_PREFIX}/lib/$<TARGET_FILE_NAME:testlib>"
+ )
+ message(FATAL_ERROR "This message should not be displayed")
+ ]])
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows.cmake b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows.cmake
new file mode 100644
index 0000000..19288d8
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows.cmake
@@ -0,0 +1,114 @@
+enable_language(C)
+
+set(testlib_names
+ preexcluded
+ libdir_postexcluded
+ libdir
+ search_postexcluded
+ search
+ unresolved
+ conflict
+ )
+
+file(REMOVE "${CMAKE_BINARY_DIR}/testlib.c")
+add_library(testlib SHARED "${CMAKE_BINARY_DIR}/testlib.c")
+foreach(name ${testlib_names})
+ file(WRITE "${CMAKE_BINARY_DIR}/${name}.c" "__declspec(dllexport) void ${name}(void) {}\n")
+ add_library(${name} SHARED "${CMAKE_BINARY_DIR}/${name}.c")
+
+ file(APPEND "${CMAKE_BINARY_DIR}/testlib.c" "__declspec(dllimport) extern void ${name}(void);\n")
+endforeach()
+file(APPEND "${CMAKE_BINARY_DIR}/testlib.c" "__declspec(dllexport) void testlib(void)\n{\n")
+foreach(name ${testlib_names})
+ file(APPEND "${CMAKE_BINARY_DIR}/testlib.c" " ${name}();\n")
+endforeach()
+file(APPEND "${CMAKE_BINARY_DIR}/testlib.c" "}\n")
+
+target_link_libraries(testlib PRIVATE ${testlib_names})
+
+file(WRITE "${CMAKE_BINARY_DIR}/testlib_conflict.c" "__declspec(dllimport) extern void conflict(void);\n__declspec(dllexport) void testlib_conflict(void)\n{\n conflict();\n}\n")
+add_library(testlib_conflict SHARED "${CMAKE_BINARY_DIR}/testlib_conflict.c")
+target_link_libraries(testlib_conflict PRIVATE conflict)
+
+file(WRITE "${CMAKE_BINARY_DIR}/testlib_noconflict.c" "__declspec(dllimport) extern void libdir(void);\n__declspec(dllexport) void testlib_noconflict(void)\n{\n libdir();\n}\n")
+add_library(testlib_noconflict SHARED "${CMAKE_BINARY_DIR}/testlib_noconflict.c")
+target_link_libraries(testlib_noconflict PRIVATE libdir)
+
+install(TARGETS testlib libdir_postexcluded libdir conflict testlib_noconflict DESTINATION bin)
+install(TARGETS libdir search_postexcluded search DESTINATION bin/.search) # Prefixing with "." ensures it is the first item after list(SORT)
+install(TARGETS testlib_conflict conflict DESTINATION bin/.conflict)
+
+add_executable(topexe file-GET_RUNTIME_DEPENDENCIES-windows/topexe.c)
+add_library(toplib SHARED file-GET_RUNTIME_DEPENDENCIES-windows/toplib.c)
+add_library(topmod MODULE file-GET_RUNTIME_DEPENDENCIES-windows/toplib.c)
+target_link_libraries(topexe PRIVATE testlib)
+target_link_libraries(toplib PRIVATE testlib)
+target_link_libraries(topmod PRIVATE testlib)
+
+install(TARGETS topexe toplib topmod DESTINATION bin)
+
+install(CODE [[
+ function(exec_get_runtime_dependencies depsfile udepsfile cdepsfile)
+ file(GET_RUNTIME_DEPENDENCIES
+ RESOLVED_DEPENDENCIES_VAR deps
+ UNRESOLVED_DEPENDENCIES_VAR udeps
+ CONFLICTING_DEPENDENCIES_PREFIX cdeps
+ PRE_INCLUDE_REGEXES
+ "^(lib)?testlib\\.dll$"
+ "^(lib)?libdir_postexcluded\\.dll$"
+ "^(lib)?libdir\\.dll$"
+ "^(lib)?search_postexcluded\\.dll$"
+ "^(lib)?search\\.dll$"
+ "^(lib)?unresolved\\.dll$"
+ "^(lib)?conflict\\.dll$"
+ "^kernel32\\.dll$"
+ PRE_EXCLUDE_REGEXES ".*"
+ POST_INCLUDE_REGEXES
+ "^.*/(lib)?testlib\\.dll$"
+ "^.*/(lib)?libdir\\.dll$"
+ "^.*/(lib)?search\\.dll$"
+ "^.*/(lib)?conflict\\.dll$"
+ POST_EXCLUDE_REGEXES ".*"
+ DIRECTORIES
+ "${CMAKE_INSTALL_PREFIX}/bin/.search"
+ ${ARGN}
+ )
+ list(SORT deps)
+ list(SORT udeps)
+ list(SORT cdeps_FILENAMES)
+ file(WRITE "${CMAKE_INSTALL_PREFIX}/deps/${depsfile}" "${deps}")
+ file(WRITE "${CMAKE_INSTALL_PREFIX}/deps/${udepsfile}" "${udeps}")
+ file(WRITE "${CMAKE_INSTALL_PREFIX}/deps/${cdepsfile}" "")
+ foreach(cdep IN LISTS cdeps_FILENAMES)
+ set(cdep_values ${cdeps_${cdep}})
+ list(SORT cdep_values)
+ file(APPEND "${CMAKE_INSTALL_PREFIX}/deps/${cdepsfile}" "${cdep}:${cdep_values}\n")
+ endforeach()
+ endfunction()
+
+ exec_get_runtime_dependencies(
+ deps1.txt udeps1.txt cdeps1.txt
+ EXECUTABLES
+ "${CMAKE_INSTALL_PREFIX}/bin/$<TARGET_FILE_NAME:topexe>"
+ LIBRARIES
+ "${CMAKE_INSTALL_PREFIX}/bin/.conflict/$<TARGET_FILE_NAME:testlib_conflict>"
+ "${CMAKE_INSTALL_PREFIX}/bin/.conflict/../$<TARGET_FILE_NAME:testlib_noconflict>"
+ )
+
+ exec_get_runtime_dependencies(
+ deps2.txt udeps2.txt cdeps2.txt
+ LIBRARIES
+ "${CMAKE_INSTALL_PREFIX}/bin/$<TARGET_FILE_NAME:toplib>"
+ "${CMAKE_INSTALL_PREFIX}/bin/.conflict/$<TARGET_FILE_NAME:testlib_conflict>"
+ "${CMAKE_INSTALL_PREFIX}/bin/.conflict/../$<TARGET_FILE_NAME:testlib_noconflict>"
+ )
+
+ exec_get_runtime_dependencies(
+ deps3.txt udeps3.txt cdeps3.txt
+ MODULES
+ "${CMAKE_INSTALL_PREFIX}/bin/$<TARGET_FILE_NAME:topmod>"
+ LIBRARIES
+ "${CMAKE_INSTALL_PREFIX}/bin/.conflict/$<TARGET_FILE_NAME:testlib_conflict>"
+ "${CMAKE_INSTALL_PREFIX}/bin/.conflict/../$<TARGET_FILE_NAME:testlib_noconflict>"
+ )
+ ]])
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows/topexe.c b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows/topexe.c
new file mode 100644
index 0000000..713b8eb
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows/topexe.c
@@ -0,0 +1,7 @@
+__declspec(dllimport) extern void testlib(void);
+
+int main(void)
+{
+ testlib();
+ return 0;
+}
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows/toplib.c b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows/toplib.c
new file mode 100644
index 0000000..6997175
--- /dev/null
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows/toplib.c
@@ -0,0 +1,6 @@
+__declspec(dllimport) extern void testlib(void);
+
+__declspec(dllexport) void toplib(void)
+{
+ testlib();
+}
diff --git a/Tests/Tutorial/Complete/tutorial.cxx b/Tests/Tutorial/Complete/tutorial.cxx
index 443d195..4451cbd 100644
--- a/Tests/Tutorial/Complete/tutorial.cxx
+++ b/Tests/Tutorial/Complete/tutorial.cxx
@@ -10,7 +10,7 @@
{
if (argc < 2) {
std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "."
- << Tutorial_VERSION_MAJOR << std::endl;
+ << Tutorial_VERSION_MINOR << std::endl;
std::cout << "Usage: " << argv[0] << " number" << std::endl;
return 1;
}
diff --git a/Tests/Tutorial/MultiPackage/tutorial.cxx b/Tests/Tutorial/MultiPackage/tutorial.cxx
index 443d195..4451cbd 100644
--- a/Tests/Tutorial/MultiPackage/tutorial.cxx
+++ b/Tests/Tutorial/MultiPackage/tutorial.cxx
@@ -10,7 +10,7 @@
{
if (argc < 2) {
std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "."
- << Tutorial_VERSION_MAJOR << std::endl;
+ << Tutorial_VERSION_MINOR << std::endl;
std::cout << "Usage: " << argv[0] << " number" << std::endl;
return 1;
}
diff --git a/Tests/Tutorial/Step10/tutorial.cxx b/Tests/Tutorial/Step10/tutorial.cxx
index 443d195..4451cbd 100644
--- a/Tests/Tutorial/Step10/tutorial.cxx
+++ b/Tests/Tutorial/Step10/tutorial.cxx
@@ -10,7 +10,7 @@
{
if (argc < 2) {
std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "."
- << Tutorial_VERSION_MAJOR << std::endl;
+ << Tutorial_VERSION_MINOR << std::endl;
std::cout << "Usage: " << argv[0] << " number" << std::endl;
return 1;
}
diff --git a/Tests/Tutorial/Step11/tutorial.cxx b/Tests/Tutorial/Step11/tutorial.cxx
index 3768855..38d4a79 100644
--- a/Tests/Tutorial/Step11/tutorial.cxx
+++ b/Tests/Tutorial/Step11/tutorial.cxx
@@ -10,7 +10,7 @@
{
if (argc < 2) {
std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "."
- << Tutorial_VERSION_MAJOR << std::endl;
+ << Tutorial_VERSION_MINOR << std::endl;
std::cout << "Usage: " << argv[0] << " number" << std::endl;
return 1;
}
diff --git a/Tests/Tutorial/Step2/tutorial.cxx b/Tests/Tutorial/Step2/tutorial.cxx
index 75b7d67..5ba34e8 100644
--- a/Tests/Tutorial/Step2/tutorial.cxx
+++ b/Tests/Tutorial/Step2/tutorial.cxx
@@ -9,7 +9,7 @@
{
if (argc < 2) {
std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "."
- << Tutorial_VERSION_MAJOR << std::endl;
+ << Tutorial_VERSION_MINOR << std::endl;
std::cout << "Usage: " << argv[0] << " number" << std::endl;
return 1;
}
diff --git a/Tests/Tutorial/Step3/tutorial.cxx b/Tests/Tutorial/Step3/tutorial.cxx
index 1d5742d..c2b89df 100644
--- a/Tests/Tutorial/Step3/tutorial.cxx
+++ b/Tests/Tutorial/Step3/tutorial.cxx
@@ -13,7 +13,7 @@
{
if (argc < 2) {
std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "."
- << Tutorial_VERSION_MAJOR << std::endl;
+ << Tutorial_VERSION_MINOR << std::endl;
std::cout << "Usage: " << argv[0] << " number" << std::endl;
return 1;
}
diff --git a/Tests/Tutorial/Step4/tutorial.cxx b/Tests/Tutorial/Step4/tutorial.cxx
index 1d5742d..c2b89df 100644
--- a/Tests/Tutorial/Step4/tutorial.cxx
+++ b/Tests/Tutorial/Step4/tutorial.cxx
@@ -13,7 +13,7 @@
{
if (argc < 2) {
std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "."
- << Tutorial_VERSION_MAJOR << std::endl;
+ << Tutorial_VERSION_MINOR << std::endl;
std::cout << "Usage: " << argv[0] << " number" << std::endl;
return 1;
}
diff --git a/Tests/Tutorial/Step5/tutorial.cxx b/Tests/Tutorial/Step5/tutorial.cxx
index 1d5742d..c2b89df 100644
--- a/Tests/Tutorial/Step5/tutorial.cxx
+++ b/Tests/Tutorial/Step5/tutorial.cxx
@@ -13,7 +13,7 @@
{
if (argc < 2) {
std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "."
- << Tutorial_VERSION_MAJOR << std::endl;
+ << Tutorial_VERSION_MINOR << std::endl;
std::cout << "Usage: " << argv[0] << " number" << std::endl;
return 1;
}
diff --git a/Tests/Tutorial/Step6/tutorial.cxx b/Tests/Tutorial/Step6/tutorial.cxx
index 1d5742d..c2b89df 100644
--- a/Tests/Tutorial/Step6/tutorial.cxx
+++ b/Tests/Tutorial/Step6/tutorial.cxx
@@ -13,7 +13,7 @@
{
if (argc < 2) {
std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "."
- << Tutorial_VERSION_MAJOR << std::endl;
+ << Tutorial_VERSION_MINOR << std::endl;
std::cout << "Usage: " << argv[0] << " number" << std::endl;
return 1;
}
diff --git a/Tests/Tutorial/Step7/tutorial.cxx b/Tests/Tutorial/Step7/tutorial.cxx
index 1d5742d..c2b89df 100644
--- a/Tests/Tutorial/Step7/tutorial.cxx
+++ b/Tests/Tutorial/Step7/tutorial.cxx
@@ -13,7 +13,7 @@
{
if (argc < 2) {
std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "."
- << Tutorial_VERSION_MAJOR << std::endl;
+ << Tutorial_VERSION_MINOR << std::endl;
std::cout << "Usage: " << argv[0] << " number" << std::endl;
return 1;
}
diff --git a/Tests/Tutorial/Step8/tutorial.cxx b/Tests/Tutorial/Step8/tutorial.cxx
index 1d5742d..c2b89df 100644
--- a/Tests/Tutorial/Step8/tutorial.cxx
+++ b/Tests/Tutorial/Step8/tutorial.cxx
@@ -13,7 +13,7 @@
{
if (argc < 2) {
std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "."
- << Tutorial_VERSION_MAJOR << std::endl;
+ << Tutorial_VERSION_MINOR << std::endl;
std::cout << "Usage: " << argv[0] << " number" << std::endl;
return 1;
}
diff --git a/Tests/Tutorial/Step9/tutorial.cxx b/Tests/Tutorial/Step9/tutorial.cxx
index 73e67a9..6c41859 100644
--- a/Tests/Tutorial/Step9/tutorial.cxx
+++ b/Tests/Tutorial/Step9/tutorial.cxx
@@ -14,7 +14,7 @@
{
if (argc < 2) {
std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "."
- << Tutorial_VERSION_MAJOR << std::endl;
+ << Tutorial_VERSION_MINOR << std::endl;
std::cout << "Usage: " << argv[0] << " number" << std::endl;
return 1;
}
diff --git a/bootstrap b/bootstrap
index 38fa32b..c2194fe 100755
--- a/bootstrap
+++ b/bootstrap
@@ -261,6 +261,17 @@
cmAddSubDirectoryCommand \
cmAddTestCommand \
cmArgumentParser \
+ cmBinUtilsLinker \
+ cmBinUtilsLinuxELFGetRuntimeDependenciesTool \
+ cmBinUtilsLinuxELFLinker \
+ cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool \
+ cmBinUtilsMacOSMachOGetRuntimeDependenciesTool \
+ cmBinUtilsMacOSMachOLinker \
+ cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool \
+ cmBinUtilsWindowsPEGetRuntimeDependenciesTool \
+ cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool \
+ cmBinUtilsWindowsPELinker \
+ cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool \
cmBreakCommand \
cmBuildCommand \
cmCMakeMinimumRequired \
@@ -357,6 +368,8 @@
cmInstallTargetGenerator \
cmInstallTargetsCommand \
cmInstalledFile \
+ cmLDConfigLDConfigTool \
+ cmLDConfigTool \
cmLinkDirectoriesCommand \
cmLinkItem \
cmLinkLineComputer \
@@ -388,12 +401,12 @@
cmPolicies \
cmProcessOutput \
cmProjectCommand \
- cmProperty \
cmPropertyDefinition \
cmPropertyDefinitionMap \
cmPropertyMap \
cmReturnCommand \
cmRulePlaceholderExpander \
+ cmRuntimeDependencyArchive \
cmScriptGenerator \
cmSearchPath \
cmSeparateArgumentsCommand \
@@ -443,7 +456,9 @@
if ${cmake_system_mingw}; then
CMAKE_CXX_SOURCES="${CMAKE_CXX_SOURCES}\
cmGlobalMSYSMakefileGenerator \
- cmGlobalMinGWMakefileGenerator"
+ cmGlobalMinGWMakefileGenerator \
+ cmVSSetupHelper \
+ "
fi
LexerParser_CXX_SOURCES="\
@@ -1370,7 +1385,7 @@
uv_c_flags=""
if ${cmake_system_mingw}; then
uv_c_flags="${uv_c_flags} -DWIN32_LEAN_AND_MEAN -D_WIN32_WINNT=0x0600"
- libs="${libs} -lws2_32 -lpsapi -liphlpapi -lshell32 -luserenv"
+ libs="${libs} -lws2_32 -lpsapi -liphlpapi -lshell32 -luserenv -lole32 -loleaut32"
else
uv_c_flags="${uv_c_flags} -DCMAKE_BOOTSTRAP"
case "${cmake_system}" in