summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Auxiliary/vim/syntax/cmake.vim4
-rw-r--r--Help/command/file.rst32
-rw-r--r--Help/command/install.rst33
-rw-r--r--Help/command/target_link_libraries.rst85
-rw-r--r--Help/envvar/CMAKE_LANG_LINKER_LAUNCHER.rst13
-rw-r--r--Help/manual/cmake-env-variables.7.rst1
-rw-r--r--Help/manual/cmake-file-api.7.rst5
-rw-r--r--Help/manual/cmake-properties.7.rst1
-rw-r--r--Help/manual/cmake-variables.7.rst1
-rw-r--r--Help/prop_tgt/LANG_LINKER_LAUNCHER.rst16
-rw-r--r--Help/release/dev/get-runtime-dependencies-file-filter.rst5
-rw-r--r--Help/release/dev/install-imported-runtime-artifacts.rst5
-rw-r--r--Help/release/dev/link-objects-first.rst8
-rw-r--r--Help/release/dev/linker-launcher.rst7
-rw-r--r--Help/variable/CMAKE_LANG_LINKER_LAUNCHER.rst11
-rw-r--r--Modules/CMakeCInformation.cmake5
-rw-r--r--Modules/CMakeCXXInformation.cmake5
-rw-r--r--Modules/CMakeFindBinUtils.cmake5
-rw-r--r--Modules/CMakeOBJCInformation.cmake5
-rw-r--r--Modules/CMakeOBJCXXInformation.cmake5
-rw-r--r--Modules/Compiler/Clang.cmake15
-rw-r--r--Modules/Compiler/MSVC-CXX.cmake9
-rw-r--r--Modules/Compiler/OpenWatcom.cmake1
-rw-r--r--Modules/UseJava.cmake12
-rw-r--r--Source/CMakeLists.txt2
-rw-r--r--Source/CMakeVersion.cmake2
-rw-r--r--Source/cmCommonTargetGenerator.cxx22
-rw-r--r--Source/cmCommonTargetGenerator.h2
-rw-r--r--Source/cmComputeLinkDepends.cxx36
-rw-r--r--Source/cmComputeLinkDepends.h6
-rw-r--r--Source/cmComputeLinkInformation.cxx44
-rw-r--r--Source/cmComputeLinkInformation.h33
-rw-r--r--Source/cmComputeTargetDepends.cxx62
-rw-r--r--Source/cmComputeTargetDepends.h3
-rw-r--r--Source/cmFileAPICodemodel.cxx10
-rw-r--r--Source/cmFileCommand.cxx34
-rw-r--r--Source/cmGeneratorExpressionNode.cxx2
-rw-r--r--Source/cmGeneratorTarget.cxx79
-rw-r--r--Source/cmGeneratorTarget.h6
-rw-r--r--Source/cmGlobalXCodeGenerator.cxx8
-rw-r--r--Source/cmInstallCommand.cxx224
-rw-r--r--Source/cmInstallExportGenerator.cxx5
-rw-r--r--Source/cmInstallGenerator.cxx63
-rw-r--r--Source/cmInstallGenerator.h16
-rw-r--r--Source/cmInstallImportedRuntimeArtifactsGenerator.cxx146
-rw-r--r--Source/cmInstallImportedRuntimeArtifactsGenerator.h44
-rw-r--r--Source/cmInstallTargetGenerator.cxx73
-rw-r--r--Source/cmInstallTargetGenerator.h9
-rw-r--r--Source/cmLinkItem.h6
-rw-r--r--Source/cmLinkLineComputer.cxx8
-rw-r--r--Source/cmLinkLineDeviceComputer.cxx2
-rw-r--r--Source/cmLocalVisualStudio7Generator.cxx2
-rw-r--r--Source/cmMakefile.cxx3
-rw-r--r--Source/cmMakefileExecutableTargetGenerator.cxx6
-rw-r--r--Source/cmMakefileLibraryTargetGenerator.cxx6
-rw-r--r--Source/cmMakefileTargetGenerator.cxx7
-rw-r--r--Source/cmNinjaNormalTargetGenerator.cxx7
-rw-r--r--Source/cmRulePlaceholderExpander.cxx20
-rw-r--r--Source/cmRulePlaceholderExpander.h1
-rw-r--r--Source/cmRuntimeDependencyArchive.cxx70
-rw-r--r--Source/cmRuntimeDependencyArchive.h8
-rw-r--r--Source/cmTarget.cxx4
-rw-r--r--Source/cmTargetLinkLibrariesCommand.cxx2
-rw-r--r--Source/cmVisualStudio10TargetGenerator.cxx7
-rw-r--r--Tests/ExportImport/CMakeLists.txt28
-rw-r--r--Tests/ExportImport/Export/CMakeLists.txt6
-rw-r--r--Tests/ExportImport/Import/CMakeLists.txt3
-rw-r--r--Tests/ExportImport/Import/install-IMPORTED_RUNTIME_ARTIFACTS/CMakeLists.txt30
-rw-r--r--Tests/ExportImport/Import/install-IMPORTED_RUNTIME_ARTIFACTS/check_installed.cmake57
-rw-r--r--Tests/ObjectLibrary/CMakeLists.txt2
-rw-r--r--Tests/ObjectLibrary/LinkObjects/CMakeLists.txt45
-rw-r--r--Tests/ObjectLibrary/LinkObjects/a_dep.c7
-rw-r--r--Tests/ObjectLibrary/LinkObjects/a_obj.c8
-rw-r--r--Tests/ObjectLibrary/LinkObjects/b_dep.c7
-rw-r--r--Tests/ObjectLibrary/LinkObjects/b_obj.c8
-rw-r--r--Tests/ObjectLibrary/LinkObjects/c_dep.c7
-rw-r--r--Tests/ObjectLibrary/LinkObjects/c_obj.c8
-rw-r--r--Tests/ObjectLibrary/LinkObjects/d_dep.c7
-rw-r--r--Tests/ObjectLibrary/LinkObjects/d_obj.c8
-rw-r--r--Tests/ObjectLibrary/LinkObjects/e_dep.c7
-rw-r--r--Tests/ObjectLibrary/LinkObjects/e_lib.c5
-rw-r--r--Tests/ObjectLibrary/LinkObjects/e_obj.c8
-rw-r--r--Tests/ObjectLibrary/LinkObjects/main.c24
-rw-r--r--Tests/RunCMake/CMakeLists.txt2
-rw-r--r--Tests/RunCMake/CompilerLauncher/C-launch-env-Build-stdout.txt (renamed from Tests/RunCMake/CompilerLauncher/ISPC-env-launch-Build-stdout.txt)0
-rw-r--r--Tests/RunCMake/CompilerLauncher/CUDA-launch-env-Build-stdout.txt (renamed from Tests/RunCMake/CompilerLauncher/Fortran-env-launch-Build-stdout.txt)0
-rw-r--r--Tests/RunCMake/CompilerLauncher/CXX-launch-env-Build-stdout.txt (renamed from Tests/RunCMake/CompilerLauncher/CXX-env-launch-Build-stdout.txt)0
-rw-r--r--Tests/RunCMake/CompilerLauncher/Fortran-launch-env-Build-stdout.txt (renamed from Tests/RunCMake/CompilerLauncher/CUDA-env-launch-Build-stdout.txt)0
-rw-r--r--Tests/RunCMake/CompilerLauncher/ISPC-launch-env-Build-stdout.txt (renamed from Tests/RunCMake/CompilerLauncher/C-env-launch-Build-stdout.txt)0
-rw-r--r--Tests/RunCMake/CompilerLauncher/RunCMakeTest.cmake2
-rw-r--r--Tests/RunCMake/ExportCompileCommands/CustomCompileRule.cmake3
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-check.py2
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/directories/imported.json65
-rw-r--r--Tests/RunCMake/FileAPI/imported/CMakeLists.txt7
-rw-r--r--Tests/RunCMake/LinkerLauncher/C-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/LinkerLauncher/C-common.cmake3
-rw-r--r--Tests/RunCMake/LinkerLauncher/C-env-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/LinkerLauncher/C-env.cmake1
-rw-r--r--Tests/RunCMake/LinkerLauncher/C-launch-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/LinkerLauncher/C-launch-env-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/LinkerLauncher/C-launch-env.cmake3
-rw-r--r--Tests/RunCMake/LinkerLauncher/C-launch.cmake3
-rw-r--r--Tests/RunCMake/LinkerLauncher/C.cmake2
-rw-r--r--Tests/RunCMake/LinkerLauncher/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/LinkerLauncher/CXX-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/LinkerLauncher/CXX-common.cmake3
-rw-r--r--Tests/RunCMake/LinkerLauncher/CXX-env-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/LinkerLauncher/CXX-env.cmake1
-rw-r--r--Tests/RunCMake/LinkerLauncher/CXX-launch-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/LinkerLauncher/CXX-launch-env-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/LinkerLauncher/CXX-launch-env.cmake3
-rw-r--r--Tests/RunCMake/LinkerLauncher/CXX-launch.cmake3
-rw-r--r--Tests/RunCMake/LinkerLauncher/CXX.cmake2
-rw-r--r--Tests/RunCMake/LinkerLauncher/OBJC-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/LinkerLauncher/OBJC-common.cmake3
-rw-r--r--Tests/RunCMake/LinkerLauncher/OBJC-env-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/LinkerLauncher/OBJC-env.cmake1
-rw-r--r--Tests/RunCMake/LinkerLauncher/OBJC-launch-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/LinkerLauncher/OBJC-launch-env-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/LinkerLauncher/OBJC-launch-env.cmake3
-rw-r--r--Tests/RunCMake/LinkerLauncher/OBJC-launch.cmake3
-rw-r--r--Tests/RunCMake/LinkerLauncher/OBJC.cmake2
-rw-r--r--Tests/RunCMake/LinkerLauncher/OBJCXX-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/LinkerLauncher/OBJCXX-common.cmake3
-rw-r--r--Tests/RunCMake/LinkerLauncher/OBJCXX-env-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/LinkerLauncher/OBJCXX-env.cmake1
-rw-r--r--Tests/RunCMake/LinkerLauncher/OBJCXX-launch-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/LinkerLauncher/OBJCXX-launch-env-Build-stdout.txt1
-rw-r--r--Tests/RunCMake/LinkerLauncher/OBJCXX-launch-env.cmake3
-rw-r--r--Tests/RunCMake/LinkerLauncher/OBJCXX-launch.cmake3
-rw-r--r--Tests/RunCMake/LinkerLauncher/OBJCXX.cmake2
-rw-r--r--Tests/RunCMake/LinkerLauncher/RunCMakeTest.cmake37
-rw-r--r--Tests/RunCMake/LinkerLauncher/main.c4
-rw-r--r--Tests/RunCMake/LinkerLauncher/main.cxx4
-rw-r--r--Tests/RunCMake/LinkerLauncher/main.m4
-rw-r--r--Tests/RunCMake/LinkerLauncher/main.mm4
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/RunCMakeTest.cmake24
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/badargs2.cmake2
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/file-filter-all-check.cmake28
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/file-filter.cmake104
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux-all-check.cmake18
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-all-check.cmake18
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-all-check.cmake18
-rwxr-xr-xbootstrap1
144 files changed, 1783 insertions, 285 deletions
diff --git a/Auxiliary/vim/syntax/cmake.vim b/Auxiliary/vim/syntax/cmake.vim
index 611f72a..d2a04fe 100644
--- a/Auxiliary/vim/syntax/cmake.vim
+++ b/Auxiliary/vim/syntax/cmake.vim
@@ -905,6 +905,7 @@ syn keyword cmakeVariable contained
\ CMAKE_CXX_INCLUDE_WHAT_YOU_USE
\ CMAKE_CXX_INIT
\ CMAKE_CXX_LIBRARY_ARCHITECTURE
+ \ CMAKE_CXX_LINKER_LAUNCHER
\ CMAKE_CXX_LINKER_PREFERENCE
\ CMAKE_CXX_LINKER_PREFERENCE_PROPAGATES
\ CMAKE_CXX_LINKER_WRAPPER_FLAG
@@ -970,6 +971,7 @@ syn keyword cmakeVariable contained
\ CMAKE_C_INCLUDE_WHAT_YOU_USE
\ CMAKE_C_INIT
\ CMAKE_C_LIBRARY_ARCHITECTURE
+ \ CMAKE_C_LINKER_LAUNCHER
\ CMAKE_C_LINKER_PREFERENCE
\ CMAKE_C_LINKER_PREFERENCE_PROPAGATES
\ CMAKE_C_LINKER_WRAPPER_FLAG
@@ -1263,10 +1265,12 @@ syn keyword cmakeVariable contained
\ CMAKE_NO_SYSTEM_FROM_IMPORTED
\ CMAKE_OBJCXX_CLANG_TIDY
\ CMAKE_OBJCXX_EXTENSIONS
+ \ CMAKE_OBJCXX_LINKER_LAUNCHER
\ CMAKE_OBJCXX_STANDARD
\ CMAKE_OBJCXX_STANDARD_REQUIRED
\ CMAKE_OBJC_CLANG_TIDY
\ CMAKE_OBJC_EXTENSIONS
+ \ CMAKE_OBJC_LINKER_LAUNCHER
\ CMAKE_OBJC_STANDARD
\ CMAKE_OBJC_STANDARD_REQUIRED
\ CMAKE_OBJECT_PATH_MAX
diff --git a/Help/command/file.rst b/Help/command/file.rst
index f46e55a..761fcbc 100644
--- a/Help/command/file.rst
+++ b/Help/command/file.rst
@@ -179,6 +179,8 @@ the ``<format>`` and ``UTC`` options.
[PRE_EXCLUDE_REGEXES [<regexes>...]]
[POST_INCLUDE_REGEXES [<regexes>...]]
[POST_EXCLUDE_REGEXES [<regexes>...]]
+ [POST_INCLUDE_FILES [<files>...]]
+ [POST_EXCLUDE_FILES [<files>...]]
)
.. versionadded:: 3.16
@@ -276,6 +278,18 @@ be resolved. See below for a full description of how they work.
List of post-exclude regexes through which to filter the names of resolved
dependencies.
+``POST_INCLUDE_FILES <files>``
+ .. versionadded:: 3.21
+
+ List of post-include filenames through which to filter the names of resolved
+ dependencies. Symlinks are resolved when attempting to match these filenames.
+
+``POST_EXCLUDE_FILES <files>``
+ .. versionadded:: 3.21
+
+ List of post-exclude filenames through which to filter the names of resolved
+ dependencies. Symlinks are resolved when attempting to match these filenames.
+
These arguments can be used to exclude unwanted system libraries when
resolving the dependencies, or to include libraries from a specific
directory. The filtering works as follows:
@@ -289,16 +303,18 @@ directory. The filtering works as follows:
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.
+ ``POST_INCLUDE_REGEXES`` or ``POST_INCLUDE_FILES``, 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.
+ ``POST_EXCLUDE_REGEXES`` or ``POST_EXCLUDE_FILES``, 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.
+ ``POST_INCLUDE_REGEXES``, ``POST_INCLUDE_FILES``, ``POST_EXCLUDE_REGEXES``,
+ or ``POST_EXCLUDE_FILES``, 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.
diff --git a/Help/command/install.rst b/Help/command/install.rst
index 2259176..2865e1d 100644
--- a/Help/command/install.rst
+++ b/Help/command/install.rst
@@ -9,6 +9,7 @@ Synopsis
.. parsed-literal::
install(`TARGETS`_ <target>... [...])
+ install(`IMPORTED_RUNTIME_ARTIFACTS`_ <target>... [...])
install({`FILES`_ | `PROGRAMS`_} <file>... [...])
install(`DIRECTORY`_ <dir>... [...])
install(`SCRIPT`_ <file> [...])
@@ -382,6 +383,38 @@ set to ``TRUE`` has undefined behavior.
to ensure that such out-of-directory targets are built before the
subdirectory-specific install rules are run.
+Installing Imported Runtime Artifacts
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. _`install(IMPORTED_RUNTIME_ARTIFACTS)`:
+.. _IMPORTED_RUNTIME_ARTIFACTS:
+
+.. versionadded:: 3.21
+
+.. code-block:: cmake
+
+ install(IMPORTED_RUNTIME_ARTIFACTS targets...
+ [[LIBRARY|RUNTIME|FRAMEWORK|BUNDLE]
+ [DESTINATION <dir>]
+ [PERMISSIONS permissions...]
+ [CONFIGURATIONS [Debug|Release|...]]
+ [COMPONENT <component>]
+ [OPTIONAL] [EXCLUDE_FROM_ALL]
+ ] [...]
+ )
+
+The ``IMPORTED_RUNTIME_ARTIFACTS`` form specifies rules for installing the
+runtime artifacts of imported targets. Projects may do this if they want to
+bundle outside executables or modules inside their installation. The
+``LIBRARY``, ``RUNTIME``, ``FRAMEWORK``, and ``BUNDLE`` arguments have the
+same semantics that they do in the `TARGETS`_ mode. Only the runtime artifacts
+of imported targets are installed (except in the case of :prop_tgt:`FRAMEWORK`
+libraries, :prop_tgt:`MACOSX_BUNDLE` executables, and :prop_tgt:`BUNDLE`
+CFBundles.) For example, headers and import libraries associated with DLLs are
+not installed. In the case of :prop_tgt:`FRAMEWORK` libraries,
+:prop_tgt:`MACOSX_BUNDLE` executables, and :prop_tgt:`BUNDLE` CFBundles, the
+entire directory is installed.
+
Installing Files
^^^^^^^^^^^^^^^^
diff --git a/Help/command/target_link_libraries.rst b/Help/command/target_link_libraries.rst
index 872e264..ac231bc 100644
--- a/Help/command/target_link_libraries.rst
+++ b/Help/command/target_link_libraries.rst
@@ -289,6 +289,91 @@ treated as :ref:`Interface Libraries`, but when they appear in
a target's :prop_tgt:`LINK_LIBRARIES` property their object files
will be included in the link too.
+.. _`Linking Object Libraries via $<TARGET_OBJECTS>`:
+
+Linking Object Libraries via $<TARGET_OBJECTS>
+""""""""""""""""""""""""""""""""""""""""""""""
+
+.. versionadded:: 3.21
+
+The object files associated with an object library may be referenced
+by the :genex:`$<TARGET_OBJECTS>` generator expression. Such object
+files are placed on the link line *before* all libraries, regardless
+of their relative order. Additionally, an ordering dependency will be
+added to the build sysstem to make sure the object library is up-to-date
+before the dependent target links. For example, the code
+
+.. code-block:: cmake
+
+ add_library(obj3 OBJECT obj3.c)
+ target_compile_definitions(obj3 PUBLIC OBJ3)
+
+ add_executable(main3 main3.c)
+ target_link_libraries(main3 PRIVATE a3 $<TARGET_OBJECTS:obj3> b3)
+
+links executable ``main3`` with object files from ``main3.c``
+and ``obj3.c`` followed by the ``a3`` and ``b3`` libraries.
+``main3.c`` is *not* compiled with usage requirements from ``obj3``,
+such as ``-DOBJ3``.
+
+This approach can be used to achieve transitive inclusion of object
+files in link lines as usage requirements. Continuing the above
+example, the code
+
+.. code-block:: cmake
+
+ add_library(iface_obj3 INTERFACE)
+ target_link_libraries(iface_obj3 INTERFACE obj3 $<TARGET_OBJECTS:obj3>)
+
+creates an interface library ``iface_obj3`` that forwards the ``obj3``
+usage requirements and adds the ``obj3`` object files to dependents'
+link lines. The code
+
+.. code-block:: cmake
+
+ add_executable(use_obj3 use_obj3.c)
+ target_link_libraries(use_obj3 PRIVATE iface_obj3)
+
+compiles ``use_obj3.c`` with ``-DOBJ3`` and links executable ``use_obj3``
+with object files from ``use_obj3.c`` and ``obj3.c``.
+
+This also works transitively through a static library. Since a static
+library does not link, it does not consume the object files from
+object libraries referenced this way. Instead, the object files
+become transitive link dependencies of the static library.
+Continuing the above example, the code
+
+.. code-block:: cmake
+
+ add_library(static3 STATIC static3.c)
+ target_link_libraries(static3 PRIVATE iface_obj3)
+
+ add_executable(use_static3 use_static3.c)
+ target_link_libraries(use_static3 PRIVATE static3)
+
+compiles ``static3.c`` with ``-DOBJ3`` and creates ``libstatic3.a``
+using only its own object file. ``use_static3.c`` is compiled *without*
+``-DOBJ3`` because the usage requirement is not transitive through
+the private dependency of ``static3``. However, the link dependencies
+of ``static3`` are propagated, including the ``iface_obj3`` reference
+to ``$<TARGET_OBJECTS:obj3>``. The ``use_static3`` executable is
+created with object files from ``use_static3.c`` and ``obj3.c``, and
+linked to library ``libstatic3.a``.
+
+When using this approach, it is the project's responsibility to avoid
+linking multiple dependent binaries to ``iface_obj3``, because they will
+all get the ``obj3`` object files on their link lines.
+
+.. note::
+
+ Referencing :genex:`$<TARGET_OBJECTS>` in ``target_link_libraries``
+ calls worked in versions of CMake prior to 3.21 for some cases,
+ but was not fully supported:
+
+ * It did not place the object files before libraries on link lines.
+ * It did not add an ordering dependency on the object library.
+ * It did not work in Xcode with multiple architectures.
+
Cyclic Dependencies of Static Libraries
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/Help/envvar/CMAKE_LANG_LINKER_LAUNCHER.rst b/Help/envvar/CMAKE_LANG_LINKER_LAUNCHER.rst
new file mode 100644
index 0000000..6251d9c
--- /dev/null
+++ b/Help/envvar/CMAKE_LANG_LINKER_LAUNCHER.rst
@@ -0,0 +1,13 @@
+CMAKE_<LANG>_LINKER_LAUNCHER
+----------------------------
+
+.. versionadded:: 3.21
+
+.. include:: ENV_VAR.txt
+
+Default launcher to use when linking a target of the specified language. Will
+only be used by CMake to initialize the variable on the first configuration.
+Afterwards, it is available through the cache setting of the variable of the
+same name. For any configuration run (including the first), the environment
+variable will be ignored if the :variable:`CMAKE_<LANG>_LINKER_LAUNCHER`
+variable is defined.
diff --git a/Help/manual/cmake-env-variables.7.rst b/Help/manual/cmake-env-variables.7.rst
index bc1fa1d..8932abf 100644
--- a/Help/manual/cmake-env-variables.7.rst
+++ b/Help/manual/cmake-env-variables.7.rst
@@ -37,6 +37,7 @@ Environment Variables that Control the Build
/envvar/CMAKE_GENERATOR_PLATFORM
/envvar/CMAKE_GENERATOR_TOOLSET
/envvar/CMAKE_LANG_COMPILER_LAUNCHER
+ /envvar/CMAKE_LANG_LINKER_LAUNCHER
/envvar/CMAKE_MSVCIDE_RUN_PATH
/envvar/CMAKE_NO_VERBOSE
/envvar/CMAKE_OSX_ARCHITECTURES
diff --git a/Help/manual/cmake-file-api.7.rst b/Help/manual/cmake-file-api.7.rst
index 0e530bc..e7d78c3 100644
--- a/Help/manual/cmake-file-api.7.rst
+++ b/Help/manual/cmake-file-api.7.rst
@@ -747,6 +747,11 @@ with members:
An :command:`install(CODE)` call.
This type has no additional members.
+ ``importedRuntimeArtifacts``
+ An :command:`install(IMPORTED_RUNTIME_ARTIFACTS)` call.
+ The ``destination`` member is populated. The ``isOptional`` member may
+ exist. This type has no additional members.
+
``isExcludeFromAll``
Optional member that is present with boolean value ``true`` when
:command:`install` is called with the ``EXCLUDE_FROM_ALL`` option.
diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst
index 4f2c1b0..0a3e36b 100644
--- a/Help/manual/cmake-properties.7.rst
+++ b/Help/manual/cmake-properties.7.rst
@@ -272,6 +272,7 @@ Properties on Targets
/prop_tgt/LANG_CPPCHECK
/prop_tgt/LANG_CPPLINT
/prop_tgt/LANG_INCLUDE_WHAT_YOU_USE
+ /prop_tgt/LANG_LINKER_LAUNCHER
/prop_tgt/LANG_VISIBILITY_PRESET
/prop_tgt/LIBRARY_OUTPUT_DIRECTORY
/prop_tgt/LIBRARY_OUTPUT_DIRECTORY_CONFIG
diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst
index 0720d49..873bd89 100644
--- a/Help/manual/cmake-variables.7.rst
+++ b/Help/manual/cmake-variables.7.rst
@@ -424,6 +424,7 @@ Variables that Control the Build
/variable/CMAKE_LANG_CPPCHECK
/variable/CMAKE_LANG_CPPLINT
/variable/CMAKE_LANG_INCLUDE_WHAT_YOU_USE
+ /variable/CMAKE_LANG_LINKER_LAUNCHER
/variable/CMAKE_LANG_LINK_LIBRARY_FILE_FLAG
/variable/CMAKE_LANG_LINK_LIBRARY_FLAG
/variable/CMAKE_LANG_VISIBILITY_PRESET
diff --git a/Help/prop_tgt/LANG_LINKER_LAUNCHER.rst b/Help/prop_tgt/LANG_LINKER_LAUNCHER.rst
new file mode 100644
index 0000000..f6ca5ad
--- /dev/null
+++ b/Help/prop_tgt/LANG_LINKER_LAUNCHER.rst
@@ -0,0 +1,16 @@
+<LANG>_LINKER_LAUNCHER
+----------------------
+
+.. versionadded:: 3.21
+
+This property is implemented only when ``<LANG>`` is ``C``, ``CXX``,
+``OBJC``, or ``OBJCXX``
+
+Specify a :ref:`semicolon-separated list <CMake Language Lists>` containing a
+command line for a linker launching tool. The :ref:`Makefile Generators` and the
+:generator:`Ninja` generator will run this tool and pass the linker and its
+arguments to the tool. This is useful for tools such as static analyzers.
+
+This property is initialized by the value of the
+:variable:`CMAKE_<LANG>_LINKER_LAUNCHER` variable if it is set when a target is
+created.
diff --git a/Help/release/dev/get-runtime-dependencies-file-filter.rst b/Help/release/dev/get-runtime-dependencies-file-filter.rst
new file mode 100644
index 0000000..3fc17ac
--- /dev/null
+++ b/Help/release/dev/get-runtime-dependencies-file-filter.rst
@@ -0,0 +1,5 @@
+get-runtime-dependencies-file-filter
+------------------------------------
+
+* The :command:`file(GET_RUNTIME_DEPENDENCIES)` command gained new
+ ``POST_INCLUDE_FILES`` and ``POST_EXCLUDE_FILES`` arguments.
diff --git a/Help/release/dev/install-imported-runtime-artifacts.rst b/Help/release/dev/install-imported-runtime-artifacts.rst
new file mode 100644
index 0000000..e2821c1
--- /dev/null
+++ b/Help/release/dev/install-imported-runtime-artifacts.rst
@@ -0,0 +1,5 @@
+install-imported-runtime-artifacts
+----------------------------------
+
+* The :command:`install` command gained a new ``IMPORTED_RUNTIME_ARTIFACTS``
+ mode, which can be used to install the runtime artifacts of imported targets.
diff --git a/Help/release/dev/link-objects-first.rst b/Help/release/dev/link-objects-first.rst
new file mode 100644
index 0000000..0c622e7
--- /dev/null
+++ b/Help/release/dev/link-objects-first.rst
@@ -0,0 +1,8 @@
+link-objects-first
+------------------
+
+* :command:`target_link_libraries` calls referencing object libraries
+ via the :genex:`TARGET_OBJECTS` generator expression now place the
+ object files before all libraries on the link line, regardless of
+ their specified order. See documentation on
+ :ref:`Linking Object Libraries via \$\<TARGET_OBJECTS\>` for details.
diff --git a/Help/release/dev/linker-launcher.rst b/Help/release/dev/linker-launcher.rst
new file mode 100644
index 0000000..6563347
--- /dev/null
+++ b/Help/release/dev/linker-launcher.rst
@@ -0,0 +1,7 @@
+linker-launcher
+---------------
+
+* The :ref:`Makefile Generators` and the :generator:`Ninja` generator learned to
+ add linker launcher tools along with the linker for ``C``, ``CXX``, ``OBJC``, and
+ ``OBJCXX`` languages. See the :variable:`CMAKE_<LANG>_LINKER_LAUNCHER` variable
+ and :prop_tgt:`<LANG>_LINKER_LAUNCHER` target property for details.
diff --git a/Help/variable/CMAKE_LANG_LINKER_LAUNCHER.rst b/Help/variable/CMAKE_LANG_LINKER_LAUNCHER.rst
new file mode 100644
index 0000000..b76b939
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_LINKER_LAUNCHER.rst
@@ -0,0 +1,11 @@
+CMAKE_<LANG>_LINKER_LAUNCHER
+----------------------------
+
+.. versionadded:: 3.21
+
+Default value for :prop_tgt:`<LANG>_LINKER_LAUNCHER` target property. This
+variable is used to initialize the property on each target as it is created.
+This is done only when ``<LANG>`` is ``C``, ``CXX``, ``OBJC``, or ``OBJCXX``.
+
+This variable is initialized to the :envvar:`CMAKE_<LANG>_LINKER_LAUNCHER`
+environment variable if it is set.
diff --git a/Modules/CMakeCInformation.cmake b/Modules/CMakeCInformation.cmake
index f6d620f..6be1865 100644
--- a/Modules/CMakeCInformation.cmake
+++ b/Modules/CMakeCInformation.cmake
@@ -115,6 +115,11 @@ if(NOT CMAKE_C_COMPILER_LAUNCHER AND DEFINED ENV{CMAKE_C_COMPILER_LAUNCHER})
CACHE STRING "Compiler launcher for C.")
endif()
+if(NOT CMAKE_C_LINKER_LAUNCHER AND DEFINED ENV{CMAKE_C_LINKER_LAUNCHER})
+ set(CMAKE_C_LINKER_LAUNCHER "$ENV{CMAKE_C_LINKER_LAUNCHER}"
+ CACHE STRING "Linker launcher for C.")
+endif()
+
include(CMakeCommonLanguageInclude)
# now define the following rule variables
diff --git a/Modules/CMakeCXXInformation.cmake b/Modules/CMakeCXXInformation.cmake
index dbb4366..944d236 100644
--- a/Modules/CMakeCXXInformation.cmake
+++ b/Modules/CMakeCXXInformation.cmake
@@ -212,6 +212,11 @@ if(NOT CMAKE_CXX_COMPILER_LAUNCHER AND DEFINED ENV{CMAKE_CXX_COMPILER_LAUNCHER})
CACHE STRING "Compiler launcher for CXX.")
endif()
+if(NOT CMAKE_CXX_LINKER_LAUNCHER AND DEFINED ENV{CMAKE_CXX_LINKER_LAUNCHER})
+ set(CMAKE_CXX_LINKER_LAUNCHER "$ENV{CMAKE_CXX_LINKER_LAUNCHER}"
+ CACHE STRING "Linker launcher for CXX.")
+endif()
+
include(CMakeCommonLanguageInclude)
# now define the following rules:
diff --git a/Modules/CMakeFindBinUtils.cmake b/Modules/CMakeFindBinUtils.cmake
index 9dac4a9..ec6bc8d 100644
--- a/Modules/CMakeFindBinUtils.cmake
+++ b/Modules/CMakeFindBinUtils.cmake
@@ -126,7 +126,10 @@ else()
list(PREPEND _CMAKE_RANLIB_NAMES "llvm-ranlib")
list(PREPEND _CMAKE_STRIP_NAMES "llvm-strip")
list(PREPEND _CMAKE_NM_NAMES "llvm-nm")
- list(PREPEND _CMAKE_OBJDUMP_NAMES "llvm-objdump")
+ if("${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_VERSION}" VERSION_GREATER_EQUAL 9)
+ # llvm-objdump versions prior to 9 did not support everything we need.
+ list(PREPEND _CMAKE_OBJDUMP_NAMES "llvm-objdump")
+ endif()
list(PREPEND _CMAKE_OBJCOPY_NAMES "llvm-objcopy")
list(PREPEND _CMAKE_READELF_NAMES "llvm-readelf")
list(PREPEND _CMAKE_DLLTOOL_NAMES "llvm-dlltool")
diff --git a/Modules/CMakeOBJCInformation.cmake b/Modules/CMakeOBJCInformation.cmake
index d530191..ac67d01 100644
--- a/Modules/CMakeOBJCInformation.cmake
+++ b/Modules/CMakeOBJCInformation.cmake
@@ -115,6 +115,11 @@ if(NOT CMAKE_OBJC_COMPILER_LAUNCHER AND DEFINED ENV{CMAKE_OBJC_COMPILER_LAUNCHER
CACHE STRING "Compiler launcher for OBJC.")
endif()
+if(NOT CMAKE_OBJC_LINKER_LAUNCHER AND DEFINED ENV{CMAKE_OBJC_LINKER_LAUNCHER})
+ set(CMAKE_OBJC_LINKER_LAUNCHER "$ENV{CMAKE_OBJC_LINKER_LAUNCHER}"
+ CACHE STRING "Linker launcher for OBJC.")
+endif()
+
include(CMakeCommonLanguageInclude)
# now define the following rule variables
diff --git a/Modules/CMakeOBJCXXInformation.cmake b/Modules/CMakeOBJCXXInformation.cmake
index 7a3b9d7..70e8579 100644
--- a/Modules/CMakeOBJCXXInformation.cmake
+++ b/Modules/CMakeOBJCXXInformation.cmake
@@ -208,6 +208,11 @@ if(NOT CMAKE_OBJCXX_COMPILER_LAUNCHER AND DEFINED ENV{CMAKE_OBJCXX_COMPILER_LAUN
CACHE STRING "Compiler launcher for OBJCXX.")
endif()
+if(NOT CMAKE_OBJCXX_LINKER_LAUNCHER AND DEFINED ENV{CMAKE_OBJCXX_LINKER_LAUNCHER})
+ set(CMAKE_OBJCXX_LINKER_LAUNCHER "$ENV{CMAKE_OBJCXX_LINKER_LAUNCHER}"
+ CACHE STRING "Linker launcher for OBJCXX.")
+endif()
+
include(CMakeCommonLanguageInclude)
# now define the following rules:
diff --git a/Modules/Compiler/Clang.cmake b/Modules/Compiler/Clang.cmake
index 9f93d41..7035d93 100644
--- a/Modules/Compiler/Clang.cmake
+++ b/Modules/Compiler/Clang.cmake
@@ -194,16 +194,25 @@ macro(__compiler_clang_cxx_standards lang)
set(CMAKE_${lang}11_EXTENSION_COMPILE_OPTION "")
set(CMAKE_${lang}14_STANDARD_COMPILE_OPTION "-std:c++14")
set(CMAKE_${lang}14_EXTENSION_COMPILE_OPTION "-std:c++14")
- if (CMAKE_${lang}_COMPILER_VERSION VERSION_GREATER_EQUAL 6.0)
+
+ if(CMAKE_${lang}_COMPILER_VERSION VERSION_GREATER_EQUAL 6.0)
set(CMAKE_${lang}17_STANDARD_COMPILE_OPTION "-std:c++17")
set(CMAKE_${lang}17_EXTENSION_COMPILE_OPTION "-std:c++17")
- set(CMAKE_${lang}20_STANDARD_COMPILE_OPTION "-std:c++latest")
- set(CMAKE_${lang}20_EXTENSION_COMPILE_OPTION "-std:c++latest")
else()
set(CMAKE_${lang}17_STANDARD_COMPILE_OPTION "-std:c++latest")
set(CMAKE_${lang}17_EXTENSION_COMPILE_OPTION "-std:c++latest")
endif()
+ if(CMAKE_${lang}_COMPILER_VERSION VERSION_GREATER_EQUAL 13.0)
+ set(CMAKE_${lang}23_STANDARD_COMPILE_OPTION "-std:c++latest")
+ set(CMAKE_${lang}23_EXTENSION_COMPILE_OPTION "-std:c++latest")
+ set(CMAKE_${lang}20_STANDARD_COMPILE_OPTION "-std:c++20")
+ set(CMAKE_${lang}20_EXTENSION_COMPILE_OPTION "-std:c++20")
+ elseif(CMAKE_${lang}_COMPILER_VERSION VERSION_GREATER_EQUAL 6.0)
+ set(CMAKE_${lang}20_STANDARD_COMPILE_OPTION "-std:c++latest")
+ set(CMAKE_${lang}20_EXTENSION_COMPILE_OPTION "-std:c++latest")
+ endif()
+
__compiler_check_default_language_standard(${lang} 3.9 14)
else()
# This version of clang-cl, or the MSVC version it simulates, does not have
diff --git a/Modules/Compiler/MSVC-CXX.cmake b/Modules/Compiler/MSVC-CXX.cmake
index 1dfc760..f1c7450 100644
--- a/Modules/Compiler/MSVC-CXX.cmake
+++ b/Modules/Compiler/MSVC-CXX.cmake
@@ -18,6 +18,7 @@ if ((CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.0.24215.1 AND
set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "")
set(CMAKE_CXX14_STANDARD_COMPILE_OPTION "-std:c++14")
set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "-std:c++14")
+
if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.11.25505)
set(CMAKE_CXX11_STANDARD__HAS_FULL_SUPPORT ON)
set(CMAKE_CXX14_STANDARD__HAS_FULL_SUPPORT ON)
@@ -27,7 +28,13 @@ if ((CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.0.24215.1 AND
set(CMAKE_CXX17_STANDARD_COMPILE_OPTION "-std:c++latest")
set(CMAKE_CXX17_EXTENSION_COMPILE_OPTION "-std:c++latest")
endif()
- if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.12.25835)
+
+ if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.29.30129)
+ set(CMAKE_CXX20_STANDARD_COMPILE_OPTION "-std:c++20")
+ set(CMAKE_CXX20_EXTENSION_COMPILE_OPTION "-std:c++20")
+ set(CMAKE_CXX23_STANDARD_COMPILE_OPTION "-std:c++latest")
+ set(CMAKE_CXX23_EXTENSION_COMPILE_OPTION "-std:c++latest")
+ elseif(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.12.25835)
set(CMAKE_CXX20_STANDARD_COMPILE_OPTION "-std:c++latest")
set(CMAKE_CXX20_EXTENSION_COMPILE_OPTION "-std:c++latest")
endif()
diff --git a/Modules/Compiler/OpenWatcom.cmake b/Modules/Compiler/OpenWatcom.cmake
index ec36908..8cfe683 100644
--- a/Modules/Compiler/OpenWatcom.cmake
+++ b/Modules/Compiler/OpenWatcom.cmake
@@ -7,6 +7,7 @@ include_guard()
set(CMAKE_LIBRARY_PATH_FLAG "libpath ")
set(CMAKE_LINK_LIBRARY_FLAG "library ")
set(CMAKE_LINK_LIBRARY_FILE_FLAG "library ")
+set(CMAKE_LINK_OBJECT_FILE_FLAG "file ")
if(CMAKE_VERBOSE_MAKEFILE)
set(CMAKE_WCL_QUIET)
diff --git a/Modules/UseJava.cmake b/Modules/UseJava.cmake
index baed7ef..30b40a0 100644
--- a/Modules/UseJava.cmake
+++ b/Modules/UseJava.cmake
@@ -34,9 +34,12 @@ the jar file. Source files can be java files or listing files
(prefixed by ``@``). If only resource files are given then just a jar file
is created.
-The ``RESOURCES`` parameter adds the named ``<resource>`` files to the jar
-by stripping the source file path and placing the file beneath ``<ns>``
-within the jar. For example::
+.. versionadded:: 3.21
+ The ``RESOURCES`` parameter adds the named ``<resource>`` files to the jar
+ by stripping the source file path and placing the file beneath ``<ns>``
+ within the jar.
+
+For example::
RESOURCES NAMESPACE "/com/my/namespace" "a/path/to/resource.txt"
@@ -49,7 +52,8 @@ paths must be relative to ``CMAKE_CURRENT_SOURCE_DIR``. Adding resources
without using the ``RESOURCES`` parameter in out of source builds will
almost certainly result in confusion.
-.. note:: SOURCES
+.. note::
+
Adding resources via the ``SOURCES`` parameter relies upon a hard-coded
list of file extensions which are tested to determine whether they compile
(e.g. File.java). ``SOURCES`` files which match the extensions are compiled.
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index bd9e4c2..844a2ee 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -350,6 +350,8 @@ set(SRCS
cmInstalledFile.cxx
cmInstallFilesGenerator.h
cmInstallFilesGenerator.cxx
+ cmInstallImportedRuntimeArtifactsGenerator.h
+ cmInstallImportedRuntimeArtifactsGenerator.cxx
cmInstallScriptGenerator.h
cmInstallScriptGenerator.cxx
cmInstallSubdirectoryGenerator.h
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index 5252b25..683e90d 100644
--- a/Source/CMakeVersion.cmake
+++ b/Source/CMakeVersion.cmake
@@ -1,7 +1,7 @@
# CMake version number components.
set(CMake_VERSION_MAJOR 3)
set(CMake_VERSION_MINOR 20)
-set(CMake_VERSION_PATCH 20210529)
+set(CMake_VERSION_PATCH 20210602)
#set(CMake_VERSION_RC 0)
set(CMake_VERSION_IS_DIRTY 0)
diff --git a/Source/cmCommonTargetGenerator.cxx b/Source/cmCommonTargetGenerator.cxx
index 0c5a7df..7c2e20c 100644
--- a/Source/cmCommonTargetGenerator.cxx
+++ b/Source/cmCommonTargetGenerator.cxx
@@ -15,6 +15,7 @@
#include "cmMakefile.h"
#include "cmOutputConverter.h"
#include "cmProperty.h"
+#include "cmRange.h"
#include "cmSourceFile.h"
#include "cmStateTypes.h"
#include "cmStringAlgorithms.h"
@@ -291,3 +292,24 @@ void cmCommonTargetGenerator::AppendOSXVerFlag(std::string& flags,
this->LocalCommonGenerator->AppendFlags(flags, vflag.str());
}
}
+
+std::string cmCommonTargetGenerator::GetLinkerLauncher(
+ const std::string& config)
+{
+ std::string lang = this->GeneratorTarget->GetLinkerLanguage(config);
+ cmProp launcherProp =
+ this->GeneratorTarget->GetProperty(lang + "_LINKER_LAUNCHER");
+ if (cmNonempty(launcherProp)) {
+ // Convert ;-delimited list to single string
+ std::vector<std::string> args = cmExpandedList(*launcherProp, true);
+ if (!args.empty()) {
+ args[0] = this->LocalCommonGenerator->ConvertToOutputFormat(
+ args[0], cmOutputConverter::SHELL);
+ for (std::string& i : cmMakeRange(args.begin() + 1, args.end())) {
+ i = this->LocalCommonGenerator->EscapeForShell(i);
+ }
+ return cmJoin(args, " ");
+ }
+ }
+ return std::string();
+}
diff --git a/Source/cmCommonTargetGenerator.h b/Source/cmCommonTargetGenerator.h
index fba6b0a..a156a41 100644
--- a/Source/cmCommonTargetGenerator.h
+++ b/Source/cmCommonTargetGenerator.h
@@ -64,6 +64,8 @@ protected:
const std::string& config) const;
std::string ComputeTargetCompilePDB(const std::string& config) const;
+ std::string GetLinkerLauncher(const std::string& config);
+
private:
using ByLanguageMap = std::map<std::string, std::string>;
struct ByConfig
diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx
index 5341e8d..4a6518fd 100644
--- a/Source/cmComputeLinkDepends.cxx
+++ b/Source/cmComputeLinkDepends.cxx
@@ -263,6 +263,12 @@ cmComputeLinkDepends::Compute()
this->FinalLinkEntries.push_back(e);
}
}
+ // Place explicitly linked object files in the front. The linker will
+ // always use them anyway, and they may depend on symbols from libraries.
+ // Append in reverse order since we reverse the final order below.
+ for (int i : cmReverseRange(this->ObjectEntries)) {
+ this->FinalLinkEntries.emplace_back(this->EntryList[i]);
+ }
// Reverse the resulting order since we iterated in reverse.
std::reverse(this->FinalLinkEntries.begin(), this->FinalLinkEntries.end());
@@ -328,6 +334,27 @@ int cmComputeLinkDepends::AddLinkEntry(cmLinkItem const& item)
return index;
}
+void cmComputeLinkDepends::AddLinkObject(cmLinkItem const& item)
+{
+ // Check if the item entry has already been added.
+ auto lei = this->LinkEntryIndex.find(item);
+ if (lei != this->LinkEntryIndex.end()) {
+ return;
+ }
+
+ // Allocate a spot for the item entry.
+ lei = this->AllocateLinkEntry(item);
+
+ // Initialize the item entry.
+ int index = lei->second;
+ LinkEntry& entry = this->EntryList[index];
+ entry.Item = BT<std::string>(item.AsStr(), item.Backtrace);
+ entry.IsObject = true;
+
+ // Record explicitly linked object files separately.
+ this->ObjectEntries.emplace_back(index);
+}
+
void cmComputeLinkDepends::FollowLinkEntry(BFSEntry qe)
{
// Get this entry representation.
@@ -343,6 +370,7 @@ void cmComputeLinkDepends::FollowLinkEntry(BFSEntry qe)
entry.Target->GetType() == cmStateEnums::INTERFACE_LIBRARY;
// This target provides its own link interface information.
this->AddLinkEntries(depender_index, iface->Libraries);
+ this->AddLinkObjects(iface->Objects);
if (isIface) {
return;
@@ -487,6 +515,7 @@ void cmComputeLinkDepends::AddDirectLinkEntries()
cmLinkImplementation const* impl =
this->Target->GetLinkImplementation(this->Config);
this->AddLinkEntries(-1, impl->Libraries);
+ this->AddLinkObjects(impl->Objects);
for (cmLinkItem const& wi : impl->WrongConfigLibraries) {
this->CheckWrongConfigItem(wi);
}
@@ -546,6 +575,13 @@ void cmComputeLinkDepends::AddLinkEntries(int depender_index,
}
}
+void cmComputeLinkDepends::AddLinkObjects(std::vector<cmLinkItem> const& objs)
+{
+ for (cmLinkItem const& obj : objs) {
+ this->AddLinkObject(obj);
+ }
+}
+
cmLinkItem cmComputeLinkDepends::ResolveLinkItem(int depender_index,
const std::string& name)
{
diff --git a/Source/cmComputeLinkDepends.h b/Source/cmComputeLinkDepends.h
index 902500a..72316f1 100644
--- a/Source/cmComputeLinkDepends.h
+++ b/Source/cmComputeLinkDepends.h
@@ -42,6 +42,7 @@ public:
cmGeneratorTarget const* Target = nullptr;
bool IsSharedDep = false;
bool IsFlag = false;
+ bool IsObject = false;
};
using EntryVector = std::vector<LinkEntry>;
@@ -65,10 +66,12 @@ private:
std::map<cmLinkItem, int>::iterator AllocateLinkEntry(
cmLinkItem const& item);
int AddLinkEntry(cmLinkItem const& item);
+ void AddLinkObject(cmLinkItem const& item);
void AddVarLinkEntries(int depender_index, const char* value);
void AddDirectLinkEntries();
template <typename T>
void AddLinkEntries(int depender_index, std::vector<T> const& libs);
+ void AddLinkObjects(std::vector<cmLinkItem> const& objs);
cmLinkItem ResolveLinkItem(int depender_index, const std::string& name);
// One entry for each unique item.
@@ -153,6 +156,9 @@ private:
std::set<cmGeneratorTarget const*> OldWrongConfigItems;
void CheckWrongConfigItem(cmLinkItem const& item);
+ // Record of explicitly linked object files.
+ std::vector<int> ObjectEntries;
+
int ComponentOrderId;
cmTargetLinkLibraryType LinkType;
bool HasConfig;
diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx
index 5473316..2647998 100644
--- a/Source/cmComputeLinkInformation.cxx
+++ b/Source/cmComputeLinkInformation.cxx
@@ -309,6 +309,13 @@ cmComputeLinkInformation::cmComputeLinkInformation(
this->LibLinkSuffix =
this->Makefile->GetSafeDefinition("CMAKE_LINK_LIBRARY_SUFFIX");
}
+ if (cmProp flag = this->Makefile->GetDefinition(
+ "CMAKE_" + this->LinkLanguage + "_LINK_OBJECT_FILE_FLAG")) {
+ this->ObjLinkFileFlag = *flag;
+ } else {
+ this->ObjLinkFileFlag =
+ this->Makefile->GetSafeDefinition("CMAKE_LINK_OBJECT_FILE_FLAG");
+ }
// Get options needed to specify RPATHs.
this->RuntimeUseChrpath = false;
@@ -514,7 +521,8 @@ bool cmComputeLinkInformation::Compute()
if (linkEntry.IsSharedDep) {
this->AddSharedDepItem(linkEntry.Item, linkEntry.Target);
} else {
- this->AddItem(linkEntry.Item, linkEntry.Target);
+ this->AddItem(linkEntry.Item, linkEntry.Target,
+ linkEntry.IsObject ? ItemIsObject::Yes : ItemIsObject::No);
}
}
@@ -634,7 +642,8 @@ void cmComputeLinkInformation::AddImplicitLinkInfo(std::string const& lang)
}
void cmComputeLinkInformation::AddItem(BT<std::string> const& item,
- cmGeneratorTarget const* tgt)
+ cmGeneratorTarget const* tgt,
+ ItemIsObject isObject)
{
// Compute the proper name to use to link this library.
const std::string& config = this->Config;
@@ -659,14 +668,15 @@ void cmComputeLinkInformation::AddItem(BT<std::string> const& item,
std::string exe = tgt->GetFullPath(config, artifact, true);
linkItem += exe;
- this->Items.emplace_back(BT<std::string>(linkItem, item.Backtrace), true,
- tgt);
+ this->Items.emplace_back(BT<std::string>(linkItem, item.Backtrace),
+ ItemIsPath::Yes, ItemIsObject::No, tgt);
this->Depends.push_back(std::move(exe));
} else if (tgt->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
// Add the interface library as an item so it can be considered as part
// of COMPATIBLE_INTERFACE_ enforcement. The generators will ignore
// this for the actual link line.
- this->Items.emplace_back(std::string(), false, tgt);
+ this->Items.emplace_back(std::string(), ItemIsPath::No, ItemIsObject::No,
+ tgt);
// Also add the item the interface specifies to be used in its place.
std::string const& libName = tgt->GetImportedLibName(config);
@@ -719,7 +729,7 @@ void cmComputeLinkInformation::AddItem(BT<std::string> const& item,
} else {
// Use the full path given to the library file.
this->Depends.push_back(item.Value);
- this->AddFullItem(item);
+ this->AddFullItem(item, isObject);
this->AddLibraryRuntimeInfo(item.Value);
}
} else {
@@ -1038,10 +1048,10 @@ void cmComputeLinkInformation::SetCurrentLinkType(LinkType lt)
if (this->LinkTypeEnabled) {
switch (this->CurrentLinkType) {
case LinkStatic:
- this->Items.emplace_back(this->StaticLinkTypeFlag, false);
+ this->Items.emplace_back(this->StaticLinkTypeFlag, ItemIsPath::No);
break;
case LinkShared:
- this->Items.emplace_back(this->SharedLinkTypeFlag, false);
+ this->Items.emplace_back(this->SharedLinkTypeFlag, ItemIsPath::No);
break;
default:
break;
@@ -1084,10 +1094,11 @@ void cmComputeLinkInformation::AddTargetItem(BT<std::string> const& item,
}
// Now add the full path to the library.
- this->Items.emplace_back(item, true, target);
+ this->Items.emplace_back(item, ItemIsPath::Yes, ItemIsObject::No, target);
}
-void cmComputeLinkInformation::AddFullItem(BT<std::string> const& item)
+void cmComputeLinkInformation::AddFullItem(BT<std::string> const& item,
+ ItemIsObject isObject)
{
// Check for the implicit link directory special case.
if (this->CheckImplicitDirItem(item.Value)) {
@@ -1138,7 +1149,7 @@ void cmComputeLinkInformation::AddFullItem(BT<std::string> const& item)
}
// Now add the full path to the library.
- this->Items.emplace_back(item, true);
+ this->Items.emplace_back(item, ItemIsPath::Yes, isObject);
}
bool cmComputeLinkInformation::CheckImplicitDirItem(std::string const& item)
@@ -1226,7 +1237,7 @@ void cmComputeLinkInformation::AddUserItem(BT<std::string> const& item,
this->SetCurrentLinkType(this->StartLinkType);
// Use the item verbatim.
- this->Items.emplace_back(item, false);
+ this->Items.emplace_back(item, ItemIsPath::No);
return;
}
@@ -1296,7 +1307,8 @@ void cmComputeLinkInformation::AddUserItem(BT<std::string> const& item,
// Create an option to ask the linker to search for the library.
std::string out = cmStrCat(this->LibLinkFlag, lib, this->LibLinkSuffix);
- this->Items.emplace_back(BT<std::string>(out, item.Backtrace), false);
+ this->Items.emplace_back(BT<std::string>(out, item.Backtrace),
+ ItemIsPath::No);
// Here we could try to find the library the linker will find and
// add a runtime information entry for it. It would probably not be
@@ -1328,13 +1340,13 @@ void cmComputeLinkInformation::AddFrameworkItem(std::string const& item)
if (this->GlobalGenerator->IsXcode()) {
// Add framework path - it will be handled by Xcode after it's added to
// "Link Binary With Libraries" build phase
- this->Items.emplace_back(item, true);
+ this->Items.emplace_back(item, ItemIsPath::Yes);
} else {
// Add the item using the -framework option.
- this->Items.emplace_back(std::string("-framework"), false);
+ this->Items.emplace_back(std::string("-framework"), ItemIsPath::No);
cmOutputConverter converter(this->Makefile->GetStateSnapshot());
fw = converter.EscapeForShell(fw);
- this->Items.emplace_back(fw, false);
+ this->Items.emplace_back(fw, ItemIsPath::No);
}
}
diff --git a/Source/cmComputeLinkInformation.h b/Source/cmComputeLinkInformation.h
index 4acb99f..7fe30b3 100644
--- a/Source/cmComputeLinkInformation.h
+++ b/Source/cmComputeLinkInformation.h
@@ -35,17 +35,33 @@ public:
~cmComputeLinkInformation();
bool Compute();
+ enum class ItemIsPath
+ {
+ No,
+ Yes,
+ };
+
+ enum class ItemIsObject
+ {
+ No,
+ Yes,
+ };
+
struct Item
{
Item() = default;
- Item(BT<std::string> v, bool p, cmGeneratorTarget const* target = nullptr)
+ Item(BT<std::string> v, ItemIsPath isPath,
+ ItemIsObject isObject = ItemIsObject::No,
+ cmGeneratorTarget const* target = nullptr)
: Value(std::move(v))
- , IsPath(p)
+ , IsPath(isPath)
+ , IsObject(isObject)
, Target(target)
{
}
BT<std::string> Value;
- bool IsPath = true;
+ ItemIsPath IsPath = ItemIsPath::Yes;
+ ItemIsObject IsObject = ItemIsObject::No;
cmGeneratorTarget const* Target = nullptr;
};
using ItemVector = std::vector<Item>;
@@ -74,6 +90,11 @@ public:
return this->LibLinkFileFlag;
}
+ std::string const& GetObjLinkFileFlag() const
+ {
+ return this->ObjLinkFileFlag;
+ }
+
std::string const& GetRPathLinkFlag() const { return this->RPathLinkFlag; }
std::string GetRPathLinkString() const;
@@ -82,7 +103,8 @@ public:
const cmGeneratorTarget* GetTarget() { return this->Target; }
private:
- void AddItem(BT<std::string> const& item, const cmGeneratorTarget* tgt);
+ void AddItem(BT<std::string> const& item, const cmGeneratorTarget* tgt,
+ ItemIsObject isObject = ItemIsObject::No);
void AddSharedDepItem(BT<std::string> const& item,
cmGeneratorTarget const* tgt);
void AddRuntimeDLL(cmGeneratorTarget const* tgt);
@@ -118,6 +140,7 @@ private:
const char* LoaderFlag;
std::string LibLinkFlag;
std::string LibLinkFileFlag;
+ std::string ObjLinkFileFlag;
std::string LibLinkSuffix;
std::string RuntimeFlag;
std::string RuntimeSep;
@@ -159,7 +182,7 @@ private:
// Handling of link items.
void AddTargetItem(BT<std::string> const& item,
const cmGeneratorTarget* target);
- void AddFullItem(BT<std::string> const& item);
+ void AddFullItem(BT<std::string> const& item, ItemIsObject isObject);
bool CheckImplicitDirItem(std::string const& item);
void AddUserItem(BT<std::string> const& item, bool pathNotKnown);
void AddFrameworkItem(std::string const& item);
diff --git a/Source/cmComputeTargetDepends.cxx b/Source/cmComputeTargetDepends.cxx
index 85a9d9c..76712f4 100644
--- a/Source/cmComputeTargetDepends.cxx
+++ b/Source/cmComputeTargetDepends.cxx
@@ -20,6 +20,7 @@
#include "cmProperty.h"
#include "cmRange.h"
#include "cmSourceFile.h"
+#include "cmSourceFileLocationKind.h"
#include "cmState.h"
#include "cmStateTypes.h"
#include "cmStringAlgorithms.h"
@@ -227,32 +228,19 @@ void cmComputeTargetDepends::CollectTargetDepends(int depender_index)
this->AddInterfaceDepends(depender_index, lib, it, emitted);
}
}
+ for (cmLinkItem const& obj : impl->Objects) {
+ if (cmSourceFile const* o = depender->Makefile->GetSource(
+ obj.AsStr(), cmSourceFileLocationKind::Known)) {
+ this->AddObjectDepends(depender_index, o, emitted);
+ }
+ }
}
// Add dependencies on object libraries not otherwise handled above.
std::vector<cmSourceFile const*> objectFiles;
depender->GetExternalObjects(objectFiles, it);
for (cmSourceFile const* o : objectFiles) {
- std::string const& objLib = o->GetObjectLibrary();
- if (!objLib.empty()) {
- cmLinkItem const& objItem =
- depender->ResolveLinkItem(objLib, cmListFileBacktrace());
- if (emitted.insert(objItem).second) {
- if (depender->GetType() != cmStateEnums::EXECUTABLE &&
- depender->GetType() != cmStateEnums::STATIC_LIBRARY &&
- depender->GetType() != cmStateEnums::SHARED_LIBRARY &&
- depender->GetType() != cmStateEnums::MODULE_LIBRARY &&
- depender->GetType() != cmStateEnums::OBJECT_LIBRARY) {
- this->GlobalGenerator->GetCMakeInstance()->IssueMessage(
- MessageType::FATAL_ERROR,
- "Only executables and libraries may reference target objects.",
- depender->GetBacktrace());
- return;
- }
- const_cast<cmGeneratorTarget*>(depender)->Target->AddUtility(
- objLib, false);
- }
- }
+ this->AddObjectDepends(depender_index, o, emitted);
}
}
}
@@ -293,6 +281,12 @@ void cmComputeTargetDepends::AddInterfaceDepends(
this->AddInterfaceDepends(depender_index, libBT, config, emitted);
}
}
+ for (cmLinkItem const& obj : iface->Objects) {
+ if (cmSourceFile const* o = depender->Makefile->GetSource(
+ obj.AsStr(), cmSourceFileLocationKind::Known)) {
+ this->AddObjectDepends(depender_index, o, emitted);
+ }
+ }
}
}
@@ -319,6 +313,34 @@ void cmComputeTargetDepends::AddInterfaceDepends(
}
}
+void cmComputeTargetDepends::AddObjectDepends(int depender_index,
+ cmSourceFile const* o,
+ std::set<cmLinkItem>& emitted)
+{
+ std::string const& objLib = o->GetObjectLibrary();
+ if (objLib.empty()) {
+ return;
+ }
+ cmGeneratorTarget const* depender = this->Targets[depender_index];
+ cmLinkItem const& objItem =
+ depender->ResolveLinkItem(objLib, cmListFileBacktrace());
+ if (emitted.insert(objItem).second) {
+ if (depender->GetType() != cmStateEnums::EXECUTABLE &&
+ depender->GetType() != cmStateEnums::STATIC_LIBRARY &&
+ depender->GetType() != cmStateEnums::SHARED_LIBRARY &&
+ depender->GetType() != cmStateEnums::MODULE_LIBRARY &&
+ depender->GetType() != cmStateEnums::OBJECT_LIBRARY) {
+ this->GlobalGenerator->GetCMakeInstance()->IssueMessage(
+ MessageType::FATAL_ERROR,
+ "Only executables and libraries may reference target objects.",
+ depender->GetBacktrace());
+ return;
+ }
+ const_cast<cmGeneratorTarget*>(depender)->Target->AddUtility(objLib,
+ false);
+ }
+}
+
void cmComputeTargetDepends::AddTargetDepend(int depender_index,
cmLinkItem const& dependee_name,
bool linking, bool cross)
diff --git a/Source/cmComputeTargetDepends.h b/Source/cmComputeTargetDepends.h
index 3517844..0eab368 100644
--- a/Source/cmComputeTargetDepends.h
+++ b/Source/cmComputeTargetDepends.h
@@ -16,6 +16,7 @@ class cmComputeComponentGraph;
class cmGeneratorTarget;
class cmGlobalGenerator;
class cmLinkItem;
+class cmSourceFile;
class cmTargetDependSet;
/** \class cmComputeTargetDepends
@@ -71,6 +72,8 @@ private:
cmListFileBacktrace const& dependee_backtrace,
const std::string& config,
std::set<cmLinkItem>& emitted);
+ void AddObjectDepends(int depender_index, cmSourceFile const* o,
+ std::set<cmLinkItem>& emitted);
cmGlobalGenerator* GlobalGenerator;
bool DebugMode;
bool NoCycles;
diff --git a/Source/cmFileAPICodemodel.cxx b/Source/cmFileAPICodemodel.cxx
index 945b547..ff11f4a 100644
--- a/Source/cmFileAPICodemodel.cxx
+++ b/Source/cmFileAPICodemodel.cxx
@@ -29,6 +29,7 @@
#include "cmInstallExportGenerator.h"
#include "cmInstallFilesGenerator.h"
#include "cmInstallGenerator.h"
+#include "cmInstallImportedRuntimeArtifactsGenerator.h"
#include "cmInstallScriptGenerator.h"
#include "cmInstallSubdirectoryGenerator.h"
#include "cmInstallTargetGenerator.h"
@@ -1009,6 +1010,15 @@ Json::Value DirectoryObject::DumpInstaller(cmInstallGenerator* gen)
installer["scriptFile"] = RelativeIfUnder(
this->TopSource, installScript->GetScript(this->Config));
}
+ } else if (auto* installImportedRuntimeArtifacts =
+ dynamic_cast<cmInstallImportedRuntimeArtifactsGenerator*>(
+ gen)) {
+ installer["type"] = "importedRuntimeArtifacts";
+ installer["destination"] =
+ installImportedRuntimeArtifacts->GetDestination(this->Config);
+ if (installImportedRuntimeArtifacts->GetOptional()) {
+ installer["isOptional"] = true;
+ }
}
// Add fields common to all install generators.
diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx
index 1088347..f2d4cda 100644
--- a/Source/cmFileCommand.cxx
+++ b/Source/cmFileCommand.cxx
@@ -3041,6 +3041,9 @@ bool HandleGetRuntimeDependenciesCommand(std::vector<std::string> const& args,
std::vector<std::string> PreExcludeRegexes;
std::vector<std::string> PostIncludeRegexes;
std::vector<std::string> PostExcludeRegexes;
+ std::vector<std::string> PostIncludeFiles;
+ std::vector<std::string> PostExcludeFiles;
+ std::vector<std::string> PostExcludeFilesStrict;
};
static auto const parser =
@@ -3058,7 +3061,10 @@ bool HandleGetRuntimeDependenciesCommand(std::vector<std::string> const& args,
.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);
+ .Bind("POST_EXCLUDE_REGEXES"_s, &Arguments::PostExcludeRegexes)
+ .Bind("POST_INCLUDE_FILES"_s, &Arguments::PostIncludeFiles)
+ .Bind("POST_EXCLUDE_FILES"_s, &Arguments::PostExcludeFiles)
+ .Bind("POST_EXCLUDE_FILES_STRICT"_s, &Arguments::PostExcludeFilesStrict);
std::vector<std::string> unrecognizedArguments;
std::vector<std::string> keywordsMissingValues;
@@ -3072,14 +3078,19 @@ bool HandleGetRuntimeDependenciesCommand(std::vector<std::string> const& args,
return false;
}
- const std::vector<std::string> LIST_ARGS = { "DIRECTORIES",
- "EXECUTABLES",
- "LIBRARIES",
- "MODULES",
- "POST_EXCLUDE_REGEXES",
- "POST_INCLUDE_REGEXES",
- "PRE_EXCLUDE_REGEXES",
- "PRE_INCLUDE_REGEXES" };
+ const std::vector<std::string> LIST_ARGS = {
+ "DIRECTORIES",
+ "EXECUTABLES",
+ "LIBRARIES",
+ "MODULES",
+ "POST_EXCLUDE_FILES",
+ "POST_EXCLUDE_FILES_STRICT",
+ "POST_EXCLUDE_REGEXES",
+ "POST_INCLUDE_FILES",
+ "POST_INCLUDE_REGEXES",
+ "PRE_EXCLUDE_REGEXES",
+ "PRE_INCLUDE_REGEXES",
+ };
auto kwbegin = keywordsMissingValues.cbegin();
auto kwend = cmRemoveMatching(keywordsMissingValues, LIST_ARGS);
if (kwend != kwbegin) {
@@ -3092,7 +3103,10 @@ bool HandleGetRuntimeDependenciesCommand(std::vector<std::string> const& args,
cmRuntimeDependencyArchive archive(
status, parsedArgs.Directories, parsedArgs.BundleExecutable,
parsedArgs.PreIncludeRegexes, parsedArgs.PreExcludeRegexes,
- parsedArgs.PostIncludeRegexes, parsedArgs.PostExcludeRegexes);
+ parsedArgs.PostIncludeRegexes, parsedArgs.PostExcludeRegexes,
+ std::move(parsedArgs.PostIncludeFiles),
+ std::move(parsedArgs.PostExcludeFiles),
+ std::move(parsedArgs.PostExcludeFilesStrict));
if (!archive.Prepare()) {
cmSystemTools::SetFatalErrorOccured();
return false;
diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx
index 7125170..8030b64 100644
--- a/Source/cmGeneratorExpressionNode.cxx
+++ b/Source/cmGeneratorExpressionNode.cxx
@@ -1681,7 +1681,7 @@ static const struct TargetObjectsNode : public cmGeneratorExpressionNode
// Create the cmSourceFile instances in the referencing directory.
cmMakefile* mf = context->LG->GetMakefile();
- for (std::string& o : objects) {
+ for (std::string const& o : objects) {
mf->AddTargetObject(tgtName, o);
}
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index a7d825d..5deb2df 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -6255,29 +6255,28 @@ bool cmGeneratorTarget::IsLinkLookupScope(std::string const& n,
return false;
}
-void cmGeneratorTarget::LookupLinkItems(std::vector<std::string> const& names,
- cmListFileBacktrace const& bt,
- std::vector<cmLinkItem>& items) const
+cm::optional<cmLinkItem> cmGeneratorTarget::LookupLinkItem(
+ std::string const& n, cmListFileBacktrace const& bt) const
{
+ cm::optional<cmLinkItem> maybeItem;
cmLocalGenerator const* lg = this->LocalGenerator;
- for (std::string const& n : names) {
- if (this->IsLinkLookupScope(n, lg)) {
- continue;
- }
+ if (this->IsLinkLookupScope(n, lg)) {
+ return maybeItem;
+ }
- std::string name = this->CheckCMP0004(n);
- if (name == this->GetName() || name.empty()) {
- continue;
- }
- items.push_back(this->ResolveLinkItem(name, bt, lg));
+ std::string name = this->CheckCMP0004(n);
+ if (name == this->GetName() || name.empty()) {
+ return maybeItem;
}
+ maybeItem = this->ResolveLinkItem(name, bt, lg);
+ return maybeItem;
}
void cmGeneratorTarget::ExpandLinkItems(
std::string const& prop, std::string const& value, std::string const& config,
cmGeneratorTarget const* headTarget, bool usage_requirements_only,
- std::vector<cmLinkItem>& items, bool& hadHeadSensitiveCondition,
- bool& hadContextSensitiveCondition,
+ std::vector<cmLinkItem>& items, std::vector<cmLinkItem>& objects,
+ bool& hadHeadSensitiveCondition, bool& hadContextSensitiveCondition,
bool& hadLinkLanguageSensitiveCondition) const
{
// Keep this logic in sync with ComputeLinkImplementationLibraries.
@@ -6295,7 +6294,25 @@ void cmGeneratorTarget::ExpandLinkItems(
cmExpandList(cge->Evaluate(this->LocalGenerator, config, headTarget,
&dagChecker, this, headTarget->LinkerLanguage),
libs);
- this->LookupLinkItems(libs, cge->GetBacktrace(), items);
+ cmMakefile const* mf = this->LocalGenerator->GetMakefile();
+ for (std::string const& lib : libs) {
+ if (cm::optional<cmLinkItem> maybeItem =
+ this->LookupLinkItem(lib, cge->GetBacktrace())) {
+ if (!maybeItem->Target) {
+ // Report explicitly linked object files separately.
+ std::string const& maybeObj = maybeItem->AsStr();
+ if (cmSystemTools::FileIsFullPath(maybeObj)) {
+ cmSourceFile const* sf =
+ mf->GetSource(maybeObj, cmSourceFileLocationKind::Known);
+ if (sf && sf->GetPropertyAsBool("EXTERNAL_OBJECT")) {
+ objects.emplace_back(std::move(*maybeItem));
+ continue;
+ }
+ }
+ }
+ items.emplace_back(std::move(*maybeItem));
+ }
+ }
hadHeadSensitiveCondition = cge->GetHadHeadSensitiveCondition();
hadContextSensitiveCondition = cge->GetHadContextSensitiveCondition();
hadLinkLanguageSensitiveCondition =
@@ -6800,7 +6817,7 @@ void cmGeneratorTarget::ComputeLinkInterfaceLibraries(
// The interface libraries have been explicitly set.
this->ExpandLinkItems(linkIfaceProp, *explicitLibraries, config,
headTarget, usage_requirements_only, iface.Libraries,
- iface.HadHeadSensitiveCondition,
+ iface.Objects, iface.HadHeadSensitiveCondition,
iface.HadContextSensitiveCondition,
iface.HadLinkLanguageSensitiveCondition);
return;
@@ -6824,6 +6841,7 @@ void cmGeneratorTarget::ComputeLinkInterfaceLibraries(
// Compare the link implementation fallback link interface to the
// preferred new link interface property and warn if different.
std::vector<cmLinkItem> ifaceLibs;
+ std::vector<cmLinkItem> ifaceObjects;
static const std::string newProp = "INTERFACE_LINK_LIBRARIES";
if (cmProp newExplicitLibraries = this->GetProperty(newProp)) {
bool hadHeadSensitiveConditionDummy = false;
@@ -6831,7 +6849,7 @@ void cmGeneratorTarget::ComputeLinkInterfaceLibraries(
bool hadLinkLanguageSensitiveConditionDummy = false;
this->ExpandLinkItems(newProp, *newExplicitLibraries, config,
headTarget, usage_requirements_only, ifaceLibs,
- hadHeadSensitiveConditionDummy,
+ ifaceObjects, hadHeadSensitiveConditionDummy,
hadContextSensitiveConditionDummy,
hadLinkLanguageSensitiveConditionDummy);
}
@@ -6899,11 +6917,16 @@ const cmLinkInterface* cmGeneratorTarget::GetImportLinkInterface(
cmExpandList(info->Languages, iface.Languages);
this->ExpandLinkItems(info->LibrariesProp, info->Libraries, config,
headTarget, usage_requirements_only, iface.Libraries,
- iface.HadHeadSensitiveCondition,
+ iface.Objects, iface.HadHeadSensitiveCondition,
iface.HadContextSensitiveCondition,
iface.HadLinkLanguageSensitiveCondition);
std::vector<std::string> deps = cmExpandedList(info->SharedDeps);
- this->LookupLinkItems(deps, cmListFileBacktrace(), iface.SharedDeps);
+ for (std::string const& dep : deps) {
+ if (cm::optional<cmLinkItem> maybeItem =
+ this->LookupLinkItem(dep, cmListFileBacktrace())) {
+ iface.SharedDeps.emplace_back(std::move(*maybeItem));
+ }
+ }
}
return &iface;
@@ -7416,6 +7439,7 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries(
cmGeneratorTarget const* head) const
{
cmLocalGenerator const* lg = this->LocalGenerator;
+ cmMakefile const* mf = lg->GetMakefile();
cmStringRange entryRange = this->Target->GetLinkImplementationEntries();
cmBacktraceRange btRange = this->Target->GetLinkImplementationBacktraces();
cmBacktraceRange::const_iterator btIt = btRange.begin();
@@ -7490,8 +7514,21 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries(
}
// The entry is meant for this configuration.
- impl.Libraries.emplace_back(this->ResolveLinkItem(name, *btIt, lg),
- evaluated != *le);
+ cmLinkItem item = this->ResolveLinkItem(name, *btIt, lg);
+ if (!item.Target) {
+ // Report explicitly linked object files separately.
+ std::string const& maybeObj = item.AsStr();
+ if (cmSystemTools::FileIsFullPath(maybeObj)) {
+ cmSourceFile const* sf =
+ mf->GetSource(maybeObj, cmSourceFileLocationKind::Known);
+ if (sf && sf->GetPropertyAsBool("EXTERNAL_OBJECT")) {
+ impl.Objects.emplace_back(std::move(item));
+ continue;
+ }
+ }
+ }
+
+ impl.Libraries.emplace_back(std::move(item), evaluated != *le);
}
std::set<std::string> const& seenProps = cge->GetSeenTargetProperties();
diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h
index 2935e0b..be36f3f 100644
--- a/Source/cmGeneratorTarget.h
+++ b/Source/cmGeneratorTarget.h
@@ -1036,12 +1036,12 @@ private:
const cmGeneratorTarget* headTarget,
bool usage_requirements_only,
std::vector<cmLinkItem>& items,
+ std::vector<cmLinkItem>& objects,
bool& hadHeadSensitiveCondition,
bool& hadContextSensitiveCondition,
bool& hadLinkLanguageSensitiveCondition) const;
- void LookupLinkItems(std::vector<std::string> const& names,
- cmListFileBacktrace const& bt,
- std::vector<cmLinkItem>& items) const;
+ cm::optional<cmLinkItem> LookupLinkItem(std::string const& n,
+ cmListFileBacktrace const& bt) const;
std::vector<BT<std::string>> GetSourceFilePaths(
std::string const& config) const;
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index 009d133..693a11c 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -3454,7 +3454,9 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target)
libItem.Target->GetType() == cmStateEnums::SHARED_LIBRARY ||
libItem.Target->GetType() == cmStateEnums::MODULE_LIBRARY ||
libItem.Target->GetType() == cmStateEnums::UNKNOWN_LIBRARY)) ||
- (!libItem.Target && libItem.IsPath && forceLinkPhase))) {
+ (!libItem.Target &&
+ libItem.IsPath == cmComputeLinkInformation::ItemIsPath::Yes &&
+ forceLinkPhase))) {
std::string libName;
bool canUseLinkPhase = true;
if (libItem.Target) {
@@ -3565,7 +3567,7 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target)
auto* libTarget = FindXCodeTarget(libItem->Target);
cmXCodeObject* buildFile;
if (!libTarget) {
- if (libItem->IsPath) {
+ if (libItem->IsPath == cmComputeLinkInformation::ItemIsPath::Yes) {
// Get or create a direct file ref in the root project
auto cleanPath = libItem->Value.Value;
if (cmSystemTools::FileIsFullPath(cleanPath)) {
@@ -3724,7 +3726,7 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target)
BuildObjectListOrString libPaths(this, true);
for (auto const& libItem : configItemMap[configName]) {
auto const& libName = *libItem;
- if (libName.IsPath) {
+ if (libName.IsPath == cmComputeLinkInformation::ItemIsPath::Yes) {
auto cleanPath = libName.Value.Value;
if (cmSystemTools::FileIsFullPath(cleanPath)) {
cleanPath = cmSystemTools::CollapseFullPath(cleanPath);
diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx
index e973764..c9bb467 100644
--- a/Source/cmInstallCommand.cxx
+++ b/Source/cmInstallCommand.cxx
@@ -2,6 +2,7 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmInstallCommand.h"
+#include <cassert>
#include <cstddef>
#include <set>
#include <sstream>
@@ -22,6 +23,7 @@
#include "cmInstallExportGenerator.h"
#include "cmInstallFilesGenerator.h"
#include "cmInstallGenerator.h"
+#include "cmInstallImportedRuntimeArtifactsGenerator.h"
#include "cmInstallScriptGenerator.h"
#include "cmInstallTargetGenerator.h"
#include "cmListFileCache.h"
@@ -865,6 +867,227 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
return true;
}
+bool HandleImportedRuntimeArtifactsMode(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ Helper helper(status);
+
+ // This is the IMPORTED_RUNTIME_ARTIFACTS mode.
+ std::vector<cmTarget*> targets;
+
+ struct ArgVectors
+ {
+ std::vector<std::string> Library;
+ std::vector<std::string> Runtime;
+ std::vector<std::string> Framework;
+ std::vector<std::string> Bundle;
+ };
+
+ static auto const argHelper = cmArgumentParser<ArgVectors>{}
+ .Bind("LIBRARY"_s, &ArgVectors::Library)
+ .Bind("RUNTIME"_s, &ArgVectors::Runtime)
+ .Bind("FRAMEWORK"_s, &ArgVectors::Framework)
+ .Bind("BUNDLE"_s, &ArgVectors::Bundle);
+
+ std::vector<std::string> genericArgVector;
+ ArgVectors const argVectors = argHelper.Parse(args, &genericArgVector);
+
+ // now parse the generic args (i.e. the ones not specialized on LIBRARY,
+ // RUNTIME etc. (see above)
+ std::vector<std::string> targetList;
+ std::vector<std::string> unknownArgs;
+ cmInstallCommandArguments genericArgs(helper.DefaultComponentName);
+ genericArgs.Bind("IMPORTED_RUNTIME_ARTIFACTS"_s, targetList);
+ genericArgs.Parse(genericArgVector, &unknownArgs);
+ bool success = genericArgs.Finalize();
+
+ cmInstallCommandArguments libraryArgs(helper.DefaultComponentName);
+ cmInstallCommandArguments runtimeArgs(helper.DefaultComponentName);
+ cmInstallCommandArguments frameworkArgs(helper.DefaultComponentName);
+ cmInstallCommandArguments bundleArgs(helper.DefaultComponentName);
+
+ // now parse the args for specific parts of the target (e.g. LIBRARY,
+ // RUNTIME etc.
+ libraryArgs.Parse(argVectors.Library, &unknownArgs);
+ runtimeArgs.Parse(argVectors.Runtime, &unknownArgs);
+ frameworkArgs.Parse(argVectors.Framework, &unknownArgs);
+ bundleArgs.Parse(argVectors.Bundle, &unknownArgs);
+
+ if (!unknownArgs.empty()) {
+ // Unknown argument.
+ status.SetError(
+ cmStrCat("IMPORTED_RUNTIME_ARTIFACTS given unknown argument \"",
+ unknownArgs[0], "\"."));
+ return false;
+ }
+
+ // apply generic args
+ libraryArgs.SetGenericArguments(&genericArgs);
+ runtimeArgs.SetGenericArguments(&genericArgs);
+ frameworkArgs.SetGenericArguments(&genericArgs);
+ bundleArgs.SetGenericArguments(&genericArgs);
+
+ success = success && libraryArgs.Finalize();
+ success = success && runtimeArgs.Finalize();
+ success = success && frameworkArgs.Finalize();
+ success = success && bundleArgs.Finalize();
+
+ if (!success) {
+ return false;
+ }
+
+ // Check if there is something to do.
+ if (targetList.empty()) {
+ return true;
+ }
+
+ for (std::string const& tgt : targetList) {
+ if (helper.Makefile->IsAlias(tgt)) {
+ status.SetError(cmStrCat("IMPORTED_RUNTIME_ARTIFACTS given target \"",
+ tgt, "\" which is an alias."));
+ return false;
+ }
+ // Lookup this target in the current directory.
+ cmTarget* target = helper.Makefile->FindTargetToUse(tgt);
+ if (!target || !target->IsImported()) {
+ // If no local target has been found, find it in the global scope.
+ cmTarget* const global_target =
+ helper.Makefile->GetGlobalGenerator()->FindTarget(tgt, true);
+ if (global_target && global_target->IsImported()) {
+ target = global_target;
+ }
+ }
+ if (target) {
+ // Found the target. Check its type.
+ if (target->GetType() != cmStateEnums::EXECUTABLE &&
+ target->GetType() != cmStateEnums::SHARED_LIBRARY &&
+ target->GetType() != cmStateEnums::MODULE_LIBRARY) {
+ status.SetError(
+ cmStrCat("IMPORTED_RUNTIME_ARTIFACTS given target \"", tgt,
+ "\" which is not an executable, library, or module."));
+ return false;
+ }
+ // Store the target in the list to be installed.
+ targets.push_back(target);
+ } else {
+ // Did not find the target.
+ status.SetError(cmStrCat("IMPORTED_RUNTIME_ARTIFACTS given target \"",
+ tgt, "\" which does not exist."));
+ return false;
+ }
+ }
+
+ // Keep track of whether we will be performing an installation of
+ // any files of the given type.
+ bool installsLibrary = false;
+ bool installsRuntime = false;
+ bool installsFramework = false;
+ bool installsBundle = false;
+
+ auto const createInstallGenerator =
+ [helper](cmTarget& target, const cmInstallCommandArguments& typeArgs,
+ const std::string& destination)
+ -> std::unique_ptr<cmInstallImportedRuntimeArtifactsGenerator> {
+ return cm::make_unique<cmInstallImportedRuntimeArtifactsGenerator>(
+ target.GetName(), destination, typeArgs.GetPermissions(),
+ typeArgs.GetConfigurations(), typeArgs.GetComponent(),
+ cmInstallGenerator::SelectMessageLevel(helper.Makefile),
+ typeArgs.GetExcludeFromAll(), typeArgs.GetOptional(),
+ helper.Makefile->GetBacktrace());
+ };
+
+ // Generate install script code to install the given targets.
+ for (cmTarget* ti : targets) {
+ // Handle each target type.
+ cmTarget& target = *ti;
+ std::unique_ptr<cmInstallImportedRuntimeArtifactsGenerator>
+ libraryGenerator;
+ std::unique_ptr<cmInstallImportedRuntimeArtifactsGenerator>
+ runtimeGenerator;
+ std::unique_ptr<cmInstallImportedRuntimeArtifactsGenerator>
+ frameworkGenerator;
+ std::unique_ptr<cmInstallImportedRuntimeArtifactsGenerator>
+ bundleGenerator;
+
+ switch (target.GetType()) {
+ case cmStateEnums::SHARED_LIBRARY:
+ if (target.IsDLLPlatform()) {
+ runtimeGenerator = createInstallGenerator(
+ target, runtimeArgs, helper.GetRuntimeDestination(&runtimeArgs));
+ } else if (target.IsFrameworkOnApple()) {
+ if (frameworkArgs.GetDestination().empty()) {
+ status.SetError(cmStrCat("IMPORTED_RUNTIME_ARTIFACTS given no "
+ "FRAMEWORK DESTINATION for shared "
+ "library FRAMEWORK target \"",
+ target.GetName(), "\"."));
+ return false;
+ }
+ frameworkGenerator = createInstallGenerator(
+ target, frameworkArgs, frameworkArgs.GetDestination());
+ } else {
+ libraryGenerator = createInstallGenerator(
+ target, libraryArgs, helper.GetLibraryDestination(&libraryArgs));
+ }
+ break;
+ case cmStateEnums::MODULE_LIBRARY:
+ libraryGenerator = createInstallGenerator(
+ target, libraryArgs, helper.GetLibraryDestination(&libraryArgs));
+ break;
+ case cmStateEnums::EXECUTABLE:
+ if (target.IsAppBundleOnApple()) {
+ if (bundleArgs.GetDestination().empty()) {
+ status.SetError(
+ cmStrCat("IMPORTED_RUNTIME_ARTIFACTS given no BUNDLE "
+ "DESTINATION for MACOSX_BUNDLE executable target \"",
+ target.GetName(), "\"."));
+ return false;
+ }
+ bundleGenerator = createInstallGenerator(
+ target, bundleArgs, bundleArgs.GetDestination());
+ } else {
+ runtimeGenerator = createInstallGenerator(
+ target, runtimeArgs, helper.GetRuntimeDestination(&runtimeArgs));
+ }
+ break;
+ default:
+ assert(false && "This should never happen");
+ break;
+ }
+
+ // Keep track of whether we're installing anything in each category
+ installsLibrary = installsLibrary || libraryGenerator;
+ installsRuntime = installsRuntime || runtimeGenerator;
+ installsFramework = installsFramework || frameworkGenerator;
+ installsBundle = installsBundle || bundleGenerator;
+
+ helper.Makefile->AddInstallGenerator(std::move(libraryGenerator));
+ helper.Makefile->AddInstallGenerator(std::move(runtimeGenerator));
+ helper.Makefile->AddInstallGenerator(std::move(frameworkGenerator));
+ helper.Makefile->AddInstallGenerator(std::move(bundleGenerator));
+ }
+
+ // Tell the global generator about any installation component names
+ // specified
+ if (installsLibrary) {
+ helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
+ libraryArgs.GetComponent());
+ }
+ if (installsRuntime) {
+ helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
+ runtimeArgs.GetComponent());
+ }
+ if (installsFramework) {
+ helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
+ frameworkArgs.GetComponent());
+ }
+ if (installsBundle) {
+ helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
+ bundleArgs.GetComponent());
+ }
+
+ return true;
+}
+
bool HandleFilesMode(std::vector<std::string> const& args,
cmExecutionStatus& status)
{
@@ -1705,6 +1928,7 @@ bool cmInstallCommand(std::vector<std::string> const& args,
{ "SCRIPT"_s, HandleScriptMode },
{ "CODE"_s, HandleScriptMode },
{ "TARGETS"_s, HandleTargetsMode },
+ { "IMPORTED_RUNTIME_ARTIFACTS"_s, HandleImportedRuntimeArtifactsMode },
{ "FILES"_s, HandleFilesMode },
{ "PROGRAMS"_s, HandleFilesMode },
{ "DIRECTORY"_s, HandleDirectoryMode },
diff --git a/Source/cmInstallExportGenerator.cxx b/Source/cmInstallExportGenerator.cxx
index ccefd92..d932fd9 100644
--- a/Source/cmInstallExportGenerator.cxx
+++ b/Source/cmInstallExportGenerator.cxx
@@ -184,9 +184,8 @@ void cmInstallExportGenerator::GenerateScriptActions(std::ostream& os,
Indent indent)
{
// Remove old per-configuration export files if the main changes.
- std::string installedDir =
- cmStrCat("$ENV{DESTDIR}",
- this->ConvertToAbsoluteDestination(this->Destination), '/');
+ std::string installedDir = cmStrCat(
+ "$ENV{DESTDIR}", ConvertToAbsoluteDestination(this->Destination), '/');
std::string installedFile = cmStrCat(installedDir, this->FileName);
os << indent << "if(EXISTS \"" << installedFile << "\")\n";
Indent indentN = indent.Next();
diff --git a/Source/cmInstallGenerator.cxx b/Source/cmInstallGenerator.cxx
index cf5f45e..9f0d119 100644
--- a/Source/cmInstallGenerator.cxx
+++ b/Source/cmInstallGenerator.cxx
@@ -2,10 +2,11 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmInstallGenerator.h"
-#include <ostream>
+#include <sstream>
#include <utility>
#include "cmMakefile.h"
+#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
cmInstallGenerator::cmInstallGenerator(
@@ -98,7 +99,7 @@ void cmInstallGenerator::AddInstallRule(
<< "${CMAKE_ABSOLUTE_DESTINATION_FILES}\")\n";
os << indent << "endif()\n";
}
- std::string absDest = this->ConvertToAbsoluteDestination(dest);
+ std::string absDest = ConvertToAbsoluteDestination(dest);
os << "file(INSTALL DESTINATION \"" << absDest << "\" TYPE " << stype;
if (optional) {
os << " OPTIONAL";
@@ -183,7 +184,7 @@ bool cmInstallGenerator::InstallsForConfig(const std::string& config)
}
std::string cmInstallGenerator::ConvertToAbsoluteDestination(
- std::string const& dest) const
+ std::string const& dest)
{
std::string result;
if (!dest.empty() && !cmSystemTools::FileIsFullPath(dest)) {
@@ -211,3 +212,59 @@ cmInstallGenerator::MessageLevel cmInstallGenerator::SelectMessageLevel(
}
return MessageDefault;
}
+
+std::string cmInstallGenerator::GetDestDirPath(std::string const& file)
+{
+ // Construct the path of the file on disk after installation on
+ // which tweaks may be performed.
+ std::string toDestDirPath = "$ENV{DESTDIR}";
+ if (file[0] != '/' && file[0] != '$') {
+ toDestDirPath += "/";
+ }
+ toDestDirPath += file;
+ return toDestDirPath;
+}
+
+void cmInstallGenerator::AddTweak(std::ostream& os, Indent indent,
+ const std::string& config,
+ std::string const& file,
+ const TweakMethod& tweak)
+{
+ std::ostringstream tw;
+ tweak(tw, indent.Next(), config, file);
+ std::string tws = tw.str();
+ if (!tws.empty()) {
+ os << indent << "if(EXISTS \"" << file << "\" AND\n"
+ << indent << " NOT IS_SYMLINK \"" << file << "\")\n";
+ os << tws;
+ os << indent << "endif()\n";
+ }
+}
+
+void cmInstallGenerator::AddTweak(std::ostream& os, Indent indent,
+ const std::string& config,
+ std::string const& dir,
+ std::vector<std::string> const& files,
+ const TweakMethod& tweak)
+{
+ if (files.size() == 1) {
+ // Tweak a single file.
+ AddTweak(os, indent, config, GetDestDirPath(cmStrCat(dir, files[0])),
+ tweak);
+ } else {
+ // Generate a foreach loop to tweak multiple files.
+ std::ostringstream tw;
+ AddTweak(tw, indent.Next(), config, "${file}", tweak);
+ std::string tws = tw.str();
+ if (!tws.empty()) {
+ Indent indent2 = indent.Next().Next();
+ os << indent << "foreach(file\n";
+ for (std::string const& f : files) {
+ os << indent2 << "\"" << GetDestDirPath(cmStrCat(dir, f)) << "\"\n";
+ }
+ os << indent2 << ")\n";
+ os << tws;
+ os << indent << "endforeach()\n";
+ }
+ }
+}
diff --git a/Source/cmInstallGenerator.h b/Source/cmInstallGenerator.h
index 0117617..97acb88 100644
--- a/Source/cmInstallGenerator.h
+++ b/Source/cmInstallGenerator.h
@@ -4,6 +4,7 @@
#include "cmConfigure.h" // IWYU pragma: keep
+#include <functional>
#include <iosfwd>
#include <string>
#include <vector>
@@ -53,7 +54,7 @@ public:
/** Get the install destination as it should appear in the
installation script. */
- std::string ConvertToAbsoluteDestination(std::string const& dest) const;
+ static std::string ConvertToAbsoluteDestination(std::string const& dest);
/** Test if this generator installs something for a given configuration. */
bool InstallsForConfig(const std::string& config);
@@ -70,12 +71,25 @@ public:
cmListFileBacktrace const& GetBacktrace() const { return this->Backtrace; }
+ static std::string GetDestDirPath(std::string const& file);
+
protected:
void GenerateScript(std::ostream& os) override;
std::string CreateComponentTest(const std::string& component,
bool exclude_from_all);
+ using TweakMethod =
+ std::function<void(std::ostream& os, Indent indent,
+ const std::string& config, const std::string& file)>;
+ static void AddTweak(std::ostream& os, Indent indent,
+ const std::string& config, std::string const& file,
+ const TweakMethod& tweak);
+ static void AddTweak(std::ostream& os, Indent indent,
+ const std::string& config, std::string const& dir,
+ std::vector<std::string> const& files,
+ const TweakMethod& tweak);
+
// Information shared by most generator types.
std::string const Destination;
std::string const Component;
diff --git a/Source/cmInstallImportedRuntimeArtifactsGenerator.cxx b/Source/cmInstallImportedRuntimeArtifactsGenerator.cxx
new file mode 100644
index 0000000..01980ac
--- /dev/null
+++ b/Source/cmInstallImportedRuntimeArtifactsGenerator.cxx
@@ -0,0 +1,146 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmInstallImportedRuntimeArtifactsGenerator.h"
+
+#include <cassert>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalGenerator.h"
+#include "cmInstallType.h"
+#include "cmListFileCache.h"
+#include "cmLocalGenerator.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+
+namespace {
+const cmsys::RegularExpression FrameworkRegularExpression(
+ "^(.*/)?([^/]*)\\.framework/(.*)$");
+
+const cmsys::RegularExpression BundleRegularExpression(
+ "^(.*/)?([^/]*)\\.app/(.*)$");
+
+const cmsys::RegularExpression CFBundleRegularExpression(
+ "^(.*/)?([^/]*)\\.bundle/(.*)$");
+}
+
+cmInstallImportedRuntimeArtifactsGenerator::
+ cmInstallImportedRuntimeArtifactsGenerator(
+ std::string targetName, std::string const& dest,
+ std::string file_permissions,
+ std::vector<std::string> const& configurations,
+ std::string const& component, MessageLevel message, bool exclude_from_all,
+ bool optional, cmListFileBacktrace backtrace)
+ : cmInstallGenerator(dest, configurations, component, message,
+ exclude_from_all, false, std::move(backtrace))
+ , TargetName(std::move(targetName))
+ , FilePermissions(std::move(file_permissions))
+ , Optional(optional)
+{
+ this->ActionsPerConfig = true;
+}
+
+bool cmInstallImportedRuntimeArtifactsGenerator::Compute(cmLocalGenerator* lg)
+{
+ // Lookup this target in the current directory.
+ this->Target = lg->FindGeneratorTargetToUse(this->TargetName);
+ if (!this->Target || !this->Target->IsImported()) {
+ // If no local target has been found, find it in the global scope.
+ this->Target =
+ lg->GetGlobalGenerator()->FindGeneratorTarget(this->TargetName);
+ }
+
+ return true;
+}
+
+std::string cmInstallImportedRuntimeArtifactsGenerator::GetDestination(
+ std::string const& config) const
+{
+ return cmGeneratorExpression::Evaluate(
+ this->Destination, this->Target->GetLocalGenerator(), config);
+}
+
+void cmInstallImportedRuntimeArtifactsGenerator::GenerateScriptForConfig(
+ std::ostream& os, const std::string& config, Indent indent)
+{
+ auto location = this->Target->GetFullPath(config);
+
+ switch (this->Target->GetType()) {
+ case cmStateEnums::EXECUTABLE:
+ if (this->Target->IsBundleOnApple()) {
+ cmsys::RegularExpressionMatch match;
+ if (BundleRegularExpression.find(location.c_str(), match)) {
+ auto bundleDir = match.match(1);
+ auto bundleName = match.match(2);
+ auto bundlePath = cmStrCat(bundleDir, bundleName, ".app");
+ this->AddInstallRule(os, this->GetDestination(config),
+ cmInstallType_DIRECTORY, { bundlePath },
+ this->Optional, nullptr,
+ this->FilePermissions.c_str(), nullptr,
+ " USE_SOURCE_PERMISSIONS", indent);
+ }
+ } else {
+ this->AddInstallRule(os, this->GetDestination(config),
+ cmInstallType_EXECUTABLE, { location },
+ this->Optional, this->FilePermissions.c_str(),
+ nullptr, nullptr, nullptr, indent);
+ }
+ break;
+ case cmStateEnums::SHARED_LIBRARY:
+ if (this->Target->IsFrameworkOnApple()) {
+ cmsys::RegularExpressionMatch match;
+ if (FrameworkRegularExpression.find(location.c_str(), match)) {
+ auto frameworkDir = match.match(1);
+ auto frameworkName = match.match(2);
+ auto frameworkPath =
+ cmStrCat(frameworkDir, frameworkName, ".framework");
+ this->AddInstallRule(os, this->GetDestination(config),
+ cmInstallType_DIRECTORY, { frameworkPath },
+ this->Optional, nullptr,
+ this->FilePermissions.c_str(), nullptr,
+ " USE_SOURCE_PERMISSIONS", indent);
+ }
+ } else {
+ std::vector<std::string> files{ location };
+ auto soName = this->Target->GetSOName(config);
+ auto soNameFile =
+ cmStrCat(this->Target->GetDirectory(config), '/', soName);
+ if (!soName.empty() && soNameFile != location) {
+ files.push_back(soNameFile);
+ }
+ this->AddInstallRule(os, this->GetDestination(config),
+ cmInstallType_SHARED_LIBRARY, files,
+ this->Optional, this->FilePermissions.c_str(),
+ nullptr, nullptr, nullptr, indent);
+ }
+ break;
+ case cmStateEnums::MODULE_LIBRARY:
+ if (this->Target->IsCFBundleOnApple()) {
+ cmsys::RegularExpressionMatch match;
+ if (CFBundleRegularExpression.find(location.c_str(), match)) {
+ auto bundleDir = match.match(1);
+ auto bundleName = match.match(2);
+ auto bundlePath = cmStrCat(bundleDir, bundleName, ".bundle");
+ this->AddInstallRule(os, this->GetDestination(config),
+ cmInstallType_DIRECTORY, { bundlePath },
+ this->Optional, nullptr,
+ this->FilePermissions.c_str(), nullptr,
+ " USE_SOURCE_PERMISSIONS", indent);
+ }
+ } else {
+ this->AddInstallRule(os, this->GetDestination(config),
+ cmInstallType_MODULE_LIBRARY, { location },
+ this->Optional, this->FilePermissions.c_str(),
+ nullptr, nullptr, nullptr, indent);
+ }
+ break;
+ default:
+ assert(false && "This should never happen");
+ break;
+ }
+}
diff --git a/Source/cmInstallImportedRuntimeArtifactsGenerator.h b/Source/cmInstallImportedRuntimeArtifactsGenerator.h
new file mode 100644
index 0000000..9e045ee
--- /dev/null
+++ b/Source/cmInstallImportedRuntimeArtifactsGenerator.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. */
+#pragma once
+
+#include <iosfwd>
+#include <string>
+#include <vector>
+
+#include "cmInstallGenerator.h"
+#include "cmListFileCache.h"
+#include "cmScriptGenerator.h"
+
+class cmGeneratorTarget;
+class cmLocalGenerator;
+
+class cmInstallImportedRuntimeArtifactsGenerator : public cmInstallGenerator
+{
+public:
+ cmInstallImportedRuntimeArtifactsGenerator(
+ std::string targetName, std::string const& dest,
+ std::string file_permissions,
+ std::vector<std::string> const& configurations,
+ std::string const& component, MessageLevel message, bool exclude_from_all,
+ bool optional, cmListFileBacktrace backtrace = cmListFileBacktrace());
+ ~cmInstallImportedRuntimeArtifactsGenerator() override = default;
+
+ bool Compute(cmLocalGenerator* lg) override;
+
+ cmGeneratorTarget* GetTarget() const { return this->Target; }
+
+ bool GetOptional() const { return this->Optional; }
+
+ std::string GetDestination(std::string const& config) const;
+
+protected:
+ void GenerateScriptForConfig(std::ostream& os, const std::string& config,
+ Indent indent) override;
+
+private:
+ std::string const TargetName;
+ cmGeneratorTarget* Target;
+ std::string const FilePermissions;
+ bool const Optional;
+};
diff --git a/Source/cmInstallTargetGenerator.cxx b/Source/cmInstallTargetGenerator.cxx
index 3e79ad8..35165cf 100644
--- a/Source/cmInstallTargetGenerator.cxx
+++ b/Source/cmInstallTargetGenerator.cxx
@@ -77,12 +77,15 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(
}
// Tweak files located in the destination directory.
- std::string toDir = cmStrCat(this->ConvertToAbsoluteDestination(dest), '/');
+ std::string toDir = cmStrCat(ConvertToAbsoluteDestination(dest), '/');
// Add pre-installation tweaks.
if (!files.NoTweak) {
- this->AddTweak(os, indent, config, toDir, files.To,
- &cmInstallTargetGenerator::PreReplacementTweaks);
+ AddTweak(os, indent, config, toDir, files.To,
+ [this](std::ostream& o, Indent i, const std::string& c,
+ const std::string& f) {
+ this->PreReplacementTweaks(o, i, c, f);
+ });
}
// Write code to install the target file.
@@ -102,8 +105,11 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(
// Add post-installation tweaks.
if (!files.NoTweak) {
- this->AddTweak(os, indent, config, toDir, files.To,
- &cmInstallTargetGenerator::PostReplacementTweaks);
+ AddTweak(os, indent, config, toDir, files.To,
+ [this](std::ostream& o, Indent i, const std::string& c,
+ const std::string& f) {
+ this->PostReplacementTweaks(o, i, c, f);
+ });
}
}
@@ -461,63 +467,6 @@ bool cmInstallTargetGenerator::Compute(cmLocalGenerator* lg)
return true;
}
-void cmInstallTargetGenerator::AddTweak(std::ostream& os, Indent indent,
- const std::string& config,
- std::string const& file,
- TweakMethod tweak)
-{
- std::ostringstream tw;
- (this->*tweak)(tw, indent.Next(), config, file);
- std::string tws = tw.str();
- if (!tws.empty()) {
- os << indent << "if(EXISTS \"" << file << "\" AND\n"
- << indent << " NOT IS_SYMLINK \"" << file << "\")\n";
- os << tws;
- os << indent << "endif()\n";
- }
-}
-
-void cmInstallTargetGenerator::AddTweak(std::ostream& os, Indent indent,
- const std::string& config,
- std::string const& dir,
- std::vector<std::string> const& files,
- TweakMethod tweak)
-{
- if (files.size() == 1) {
- // Tweak a single file.
- this->AddTweak(os, indent, config,
- this->GetDestDirPath(cmStrCat(dir, files[0])), tweak);
- } else {
- // Generate a foreach loop to tweak multiple files.
- std::ostringstream tw;
- this->AddTweak(tw, indent.Next(), config, "${file}", tweak);
- std::string tws = tw.str();
- if (!tws.empty()) {
- Indent indent2 = indent.Next().Next();
- os << indent << "foreach(file\n";
- for (std::string const& f : files) {
- os << indent2 << "\"" << this->GetDestDirPath(cmStrCat(dir, f))
- << "\"\n";
- }
- os << indent2 << ")\n";
- os << tws;
- os << indent << "endforeach()\n";
- }
- }
-}
-
-std::string cmInstallTargetGenerator::GetDestDirPath(std::string const& file)
-{
- // Construct the path of the file on disk after installation on
- // which tweaks may be performed.
- std::string toDestDirPath = "$ENV{DESTDIR}";
- if (file[0] != '/' && file[0] != '$') {
- toDestDirPath += "/";
- }
- toDestDirPath += file;
- return toDestDirPath;
-}
-
void cmInstallTargetGenerator::PreReplacementTweaks(std::ostream& os,
Indent indent,
const std::string& config,
diff --git a/Source/cmInstallTargetGenerator.h b/Source/cmInstallTargetGenerator.h
index 84fce42..6173f2c 100644
--- a/Source/cmInstallTargetGenerator.h
+++ b/Source/cmInstallTargetGenerator.h
@@ -93,15 +93,6 @@ public:
protected:
void GenerateScriptForConfig(std::ostream& os, const std::string& config,
Indent indent) override;
- using TweakMethod = void (cmInstallTargetGenerator::*)(std::ostream&, Indent,
- const std::string&,
- const std::string&);
- void AddTweak(std::ostream& os, Indent indent, const std::string& config,
- std::string const& file, TweakMethod tweak);
- void AddTweak(std::ostream& os, Indent indent, const std::string& config,
- std::string const& dir, std::vector<std::string> const& files,
- TweakMethod tweak);
- std::string GetDestDirPath(std::string const& file);
void PreReplacementTweaks(std::ostream& os, Indent indent,
const std::string& config,
std::string const& file);
diff --git a/Source/cmLinkItem.h b/Source/cmLinkItem.h
index 5a90e7e..db44938 100644
--- a/Source/cmLinkItem.h
+++ b/Source/cmLinkItem.h
@@ -50,6 +50,9 @@ struct cmLinkImplementationLibraries
// Libraries linked directly in this configuration.
std::vector<cmLinkImplItem> Libraries;
+ // Object files linked directly in this configuration.
+ std::vector<cmLinkItem> Objects;
+
// Libraries linked directly in other configurations.
// Needed only for OLD behavior of CMP0003.
std::vector<cmLinkItem> WrongConfigLibraries;
@@ -63,6 +66,9 @@ struct cmLinkInterfaceLibraries
// Libraries listed in the interface.
std::vector<cmLinkItem> Libraries;
+ // Object files listed in the interface.
+ std::vector<cmLinkItem> Objects;
+
// Whether the list depends on a genex referencing the head target.
bool HadHeadSensitiveCondition = false;
diff --git a/Source/cmLinkLineComputer.cxx b/Source/cmLinkLineComputer.cxx
index a3f2968..5646368 100644
--- a/Source/cmLinkLineComputer.cxx
+++ b/Source/cmLinkLineComputer.cxx
@@ -74,8 +74,12 @@ void cmLinkLineComputer::ComputeLinkLibs(
}
BT<std::string> linkLib;
- if (item.IsPath) {
- linkLib.Value += cli.GetLibLinkFileFlag();
+ if (item.IsPath == cmComputeLinkInformation::ItemIsPath::Yes) {
+ if (item.IsObject == cmComputeLinkInformation::ItemIsObject::Yes) {
+ linkLib.Value += cli.GetObjLinkFileFlag();
+ } else {
+ linkLib.Value += cli.GetLibLinkFileFlag();
+ }
linkLib.Value += this->ConvertToOutputFormat(
this->ConvertToLinkReference(item.Value.Value));
linkLib.Backtrace = item.Value.Backtrace;
diff --git a/Source/cmLinkLineDeviceComputer.cxx b/Source/cmLinkLineDeviceComputer.cxx
index 9cae926..2ffff96 100644
--- a/Source/cmLinkLineDeviceComputer.cxx
+++ b/Source/cmLinkLineDeviceComputer.cxx
@@ -111,7 +111,7 @@ void cmLinkLineDeviceComputer::ComputeLinkLibraries(
}
BT<std::string> linkLib;
- if (item.IsPath) {
+ if (item.IsPath == cmComputeLinkInformation::ItemIsPath::Yes) {
// nvcc understands absolute paths to libraries ending in '.a' or '.lib'.
// These should be passed to nvlink. Other extensions need to be left
// out because nvlink may not understand or need them. Even though it
diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx
index c50cc5d..151470b 100644
--- a/Source/cmLocalVisualStudio7Generator.cxx
+++ b/Source/cmLocalVisualStudio7Generator.cxx
@@ -1254,7 +1254,7 @@ void cmLocalVisualStudio7GeneratorInternals::OutputLibraries(
{
cmLocalVisualStudio7Generator* lg = this->LocalGenerator;
for (auto const& lib : libs) {
- if (lib.IsPath) {
+ if (lib.IsPath == cmComputeLinkInformation::ItemIsPath::Yes) {
std::string rel = lg->MaybeRelativeToCurBinDir(lib.Value.Value);
fout << lg->ConvertToXMLOutputPath(rel) << " ";
} else if (!lib.Target ||
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index ffe94ba..908b3f0 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -3454,7 +3454,8 @@ void cmMakefile::CreateGeneratedOutputs(
void cmMakefile::AddTargetObject(std::string const& tgtName,
std::string const& objFile)
{
- cmSourceFile* sf = this->GetOrCreateSource(objFile, true);
+ cmSourceFile* sf =
+ this->GetOrCreateSource(objFile, true, cmSourceFileLocationKind::Known);
sf->SetObjectLibrary(tgtName);
sf->SetProperty("EXTERNAL_OBJECT", "1");
#if !defined(CMAKE_BOOTSTRAP)
diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx
index 2940b8b..3a2744e 100644
--- a/Source/cmMakefileExecutableTargetGenerator.cxx
+++ b/Source/cmMakefileExecutableTargetGenerator.cxx
@@ -571,6 +571,12 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
vars.LinkFlags = linkFlags.c_str();
vars.Manifests = manifests.c_str();
+ std::string linkerLauncher =
+ this->GetLinkerLauncher(this->GetConfigName());
+ if (cmNonempty(linkerLauncher)) {
+ vars.Launcher = linkerLauncher.c_str();
+ }
+
if (this->GeneratorTarget->GetPropertyAsBool("LINK_WHAT_YOU_USE")) {
std::string cmakeCommand =
cmStrCat(this->LocalGenerator->ConvertToOutputFormat(
diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx
index f96bcde..d0e3837 100644
--- a/Source/cmMakefileLibraryTargetGenerator.cxx
+++ b/Source/cmMakefileLibraryTargetGenerator.cxx
@@ -804,6 +804,12 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
vars.LanguageCompileFlags = langFlags.c_str();
+ std::string linkerLauncher =
+ this->GetLinkerLauncher(this->GetConfigName());
+ if (cmNonempty(linkerLauncher)) {
+ vars.Launcher = linkerLauncher.c_str();
+ }
+
std::string launcher;
cmProp val = this->LocalGenerator->GetRuleLauncher(this->GeneratorTarget,
"RULE_LAUNCH_LINK");
diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx
index 4542672..e87f81b 100644
--- a/Source/cmMakefileTargetGenerator.cxx
+++ b/Source/cmMakefileTargetGenerator.cxx
@@ -909,8 +909,11 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
compileCommand, vars);
std::string workingDirectory =
this->LocalGenerator->GetCurrentBinaryDirectory();
- compileCommand.replace(compileCommand.find(langFlags), langFlags.size(),
- this->GetFlags(lang, this->GetConfigName()));
+ std::string::size_type lfPos = compileCommand.find(langFlags);
+ if (lfPos != std::string::npos) {
+ compileCommand.replace(lfPos, langFlags.size(),
+ this->GetFlags(lang, this->GetConfigName()));
+ }
std::string langDefines = std::string("$(") + lang + "_DEFINES)";
std::string::size_type ldPos = compileCommand.find(langDefines);
if (ldPos != std::string::npos) {
diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx
index 4c33334..9a48047 100644
--- a/Source/cmNinjaNormalTargetGenerator.cxx
+++ b/Source/cmNinjaNormalTargetGenerator.cxx
@@ -368,7 +368,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkRule(bool useResponseFile,
vars.CMTargetType = cmState::GetTargetTypeName(targetType).c_str();
std::string lang = this->TargetLinkLanguage(config);
- vars.Language = config.c_str();
+ vars.Language = lang.c_str();
vars.AIXExports = "$AIX_EXPORTS";
if (this->TargetLinkLanguage(config) == "Swift") {
@@ -456,6 +456,11 @@ void cmNinjaNormalTargetGenerator::WriteLinkRule(bool useResponseFile,
vars.LanguageCompileFlags = langFlags.c_str();
}
+ std::string linkerLauncher = this->GetLinkerLauncher(config);
+ if (cmNonempty(linkerLauncher)) {
+ vars.Launcher = linkerLauncher.c_str();
+ }
+
std::string launcher;
cmProp val = this->GetLocalGenerator()->GetRuleLauncher(
this->GetGeneratorTarget(), "RULE_LAUNCH_LINK");
diff --git a/Source/cmRulePlaceholderExpander.cxx b/Source/cmRulePlaceholderExpander.cxx
index d00bbdf..7480aeb 100644
--- a/Source/cmRulePlaceholderExpander.cxx
+++ b/Source/cmRulePlaceholderExpander.cxx
@@ -6,6 +6,7 @@
#include <utility>
#include "cmOutputConverter.h"
+#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
cmRulePlaceholderExpander::cmRulePlaceholderExpander(
@@ -280,6 +281,13 @@ std::string cmRulePlaceholderExpander::ExpandRuleVariable(
this->VariableMappings["CMAKE_" + compIt->second +
"_COMPILE_OPTIONS_SYSROOT"];
+ if (compIt->second == replaceValues.Language && replaceValues.Launcher) {
+ // Add launcher as part of expansion so that it always appears
+ // immediately before the command itself, regardless of whether the
+ // overall rule template contains other content at the front.
+ ret = cmStrCat(replaceValues.Launcher, " ", ret);
+ }
+
// if there are required arguments to the compiler add it
// to the compiler string
if (!compilerArg1.empty()) {
@@ -317,7 +325,17 @@ std::string cmRulePlaceholderExpander::ExpandRuleVariable(
auto mapIt = this->VariableMappings.find(variable);
if (mapIt != this->VariableMappings.end()) {
if (variable.find("_FLAG") == std::string::npos) {
- return outputConverter->ConvertToOutputForExisting(mapIt->second);
+ std::string ret =
+ outputConverter->ConvertToOutputForExisting(mapIt->second);
+
+ if (replaceValues.Launcher && variable == "CMAKE_LINKER") {
+ // Add launcher as part of expansion so that it always appears
+ // immediately before the command itself, regardless of whether the
+ // overall rule template contains other content at the front.
+ ret = cmStrCat(replaceValues.Launcher, " ", ret);
+ }
+
+ return ret;
}
return mapIt->second;
}
diff --git a/Source/cmRulePlaceholderExpander.h b/Source/cmRulePlaceholderExpander.h
index f8dc368..c22e0fa 100644
--- a/Source/cmRulePlaceholderExpander.h
+++ b/Source/cmRulePlaceholderExpander.h
@@ -67,6 +67,7 @@ public:
const char* ISPCHeader = nullptr;
const char* Fatbinary = nullptr;
const char* RegisterFile = nullptr;
+ const char* Launcher = nullptr;
};
// Expand rule variables in CMake of the type found in language rules
diff --git a/Source/cmRuntimeDependencyArchive.cxx b/Source/cmRuntimeDependencyArchive.cxx
index 472f234..a6ed523 100644
--- a/Source/cmRuntimeDependencyArchive.cxx
+++ b/Source/cmRuntimeDependencyArchive.cxx
@@ -115,7 +115,10 @@ cmRuntimeDependencyArchive::cmRuntimeDependencyArchive(
const std::vector<std::string>& preIncludeRegexes,
const std::vector<std::string>& preExcludeRegexes,
const std::vector<std::string>& postIncludeRegexes,
- const std::vector<std::string>& postExcludeRegexes)
+ const std::vector<std::string>& postExcludeRegexes,
+ std::vector<std::string> postIncludeFiles,
+ std::vector<std::string> postExcludeFiles,
+ std::vector<std::string> postExcludeFilesStrict)
: Status(status)
, SearchDirectories(std::move(searchDirectories))
, BundleExecutable(std::move(bundleExecutable))
@@ -123,6 +126,9 @@ cmRuntimeDependencyArchive::cmRuntimeDependencyArchive(
, PreExcludeRegexes(preExcludeRegexes.size())
, PostIncludeRegexes(postIncludeRegexes.size())
, PostExcludeRegexes(postExcludeRegexes.size())
+ , PostIncludeFiles(std::move(postIncludeFiles))
+ , PostExcludeFiles(std::move(postExcludeFiles))
+ , PostExcludeFilesStrict(std::move(postExcludeFilesStrict))
{
std::transform(preIncludeRegexes.begin(), preIncludeRegexes.end(),
this->PreIncludeRegexes.begin(), TransformCompile);
@@ -306,39 +312,45 @@ bool cmRuntimeDependencyArchive::GetGetRuntimeDependenciesCommand(
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;
+ auto const regexMatch =
+ [&match, name](const cmsys::RegularExpression& regex) -> bool {
+ return regex.find(name.c_str(), match);
+ };
+ auto const regexSearch =
+ [&regexMatch](
+ const std::vector<cmsys::RegularExpression>& regexes) -> bool {
+ return std::any_of(regexes.begin(), regexes.end(), regexMatch);
+ };
+
+ return !regexSearch(this->PreIncludeRegexes) &&
+ regexSearch(this->PreExcludeRegexes);
}
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;
+ auto const regexMatch =
+ [&match, name](const cmsys::RegularExpression& regex) -> bool {
+ return regex.find(name.c_str(), match);
+ };
+ auto const regexSearch =
+ [&regexMatch](
+ const std::vector<cmsys::RegularExpression>& regexes) -> bool {
+ return std::any_of(regexes.begin(), regexes.end(), regexMatch);
+ };
+ auto const fileMatch = [name](const std::string& file) -> bool {
+ return cmSystemTools::SameFile(file, name);
+ };
+ auto const fileSearch =
+ [&fileMatch](const std::vector<std::string>& files) -> bool {
+ return std::any_of(files.begin(), files.end(), fileMatch);
+ };
+
+ return fileSearch(this->PostExcludeFilesStrict) ||
+ (!(regexSearch(this->PostIncludeRegexes) ||
+ fileSearch(this->PostIncludeFiles)) &&
+ (regexSearch(this->PostExcludeRegexes) ||
+ fileSearch(this->PostExcludeFiles)));
}
void cmRuntimeDependencyArchive::AddResolvedPath(const std::string& name,
diff --git a/Source/cmRuntimeDependencyArchive.h b/Source/cmRuntimeDependencyArchive.h
index 7f3b8e9..1dc3261 100644
--- a/Source/cmRuntimeDependencyArchive.h
+++ b/Source/cmRuntimeDependencyArchive.h
@@ -25,7 +25,10 @@ public:
const std::vector<std::string>& preIncludeRegexes,
const std::vector<std::string>& preExcludeRegexes,
const std::vector<std::string>& postIncludeRegexes,
- const std::vector<std::string>& postExcludeRegexes);
+ const std::vector<std::string>& postExcludeRegexes,
+ std::vector<std::string> postIncludeFiles,
+ std::vector<std::string> postExcludeFiles,
+ std::vector<std::string> postExcludeFilesStrict);
bool Prepare();
bool GetRuntimeDependencies(const std::vector<std::string>& executables,
const std::vector<std::string>& libraries,
@@ -62,6 +65,9 @@ private:
std::vector<cmsys::RegularExpression> PreExcludeRegexes;
std::vector<cmsys::RegularExpression> PostIncludeRegexes;
std::vector<cmsys::RegularExpression> PostExcludeRegexes;
+ std::vector<std::string> PostIncludeFiles;
+ std::vector<std::string> PostExcludeFiles;
+ std::vector<std::string> PostExcludeFilesStrict;
std::map<std::string, std::set<std::string>> ResolvedPaths;
std::set<std::string> UnresolvedPaths;
};
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index 29e361c..6f2e447 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -354,11 +354,13 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
initProp("C_CPPLINT");
initProp("C_CPPCHECK");
initProp("C_INCLUDE_WHAT_YOU_USE");
+ initProp("C_LINKER_LAUNCHER");
initProp("LINK_WHAT_YOU_USE");
initProp("CXX_CLANG_TIDY");
initProp("CXX_CPPLINT");
initProp("CXX_CPPCHECK");
initProp("CXX_INCLUDE_WHAT_YOU_USE");
+ initProp("CXX_LINKER_LAUNCHER");
initProp("CUDA_SEPARABLE_COMPILATION");
initProp("CUDA_RESOLVE_DEVICE_SYMBOLS");
initProp("CUDA_RUNTIME_LIBRARY");
@@ -374,7 +376,9 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
initProp("LINK_SEARCH_START_STATIC");
initProp("LINK_SEARCH_END_STATIC");
initProp("OBJC_CLANG_TIDY");
+ initProp("OBJC_LINKER_LAUNCHER");
initProp("OBJCXX_CLANG_TIDY");
+ initProp("OBJCXX_LINKER_LAUNCHER");
initProp("Swift_LANGUAGE_VERSION");
initProp("Swift_MODULE_DIRECTORY");
initProp("VS_JUST_MY_CODE_DEBUGGING");
diff --git a/Source/cmTargetLinkLibrariesCommand.cxx b/Source/cmTargetLinkLibrariesCommand.cxx
index aecc18e..3423b30 100644
--- a/Source/cmTargetLinkLibrariesCommand.cxx
+++ b/Source/cmTargetLinkLibrariesCommand.cxx
@@ -565,7 +565,7 @@ void TLL::AffectsProperty(std::string const& prop)
if (!this->EncodeRemoteReference) {
return;
}
- // Add a wrapper to the expression to tell LookupLinkItems to look up
+ // Add a wrapper to the expression to tell LookupLinkItem to look up
// names in the caller's directory.
if (this->Props.insert(prop).second) {
this->Target->AppendProperty(prop, this->DirectoryId);
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index 1c8b672..98d56df 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -3391,7 +3391,7 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaLinkOptions(
}
}
- if (l.IsPath) {
+ if (l.IsPath == cmComputeLinkInformation::ItemIsPath::Yes) {
std::string path =
this->LocalGenerator->MaybeRelativeToCurBinDir(l.Value.Value);
ConvertToWindowsSlash(path);
@@ -3945,7 +3945,8 @@ bool cmVisualStudio10TargetGenerator::ComputeLibOptions(
using ItemVector = cmComputeLinkInformation::ItemVector;
const ItemVector& libs = cli.GetItems();
for (cmComputeLinkInformation::Item const& l : libs) {
- if (l.IsPath && cmVS10IsTargetsFile(l.Value.Value)) {
+ if (l.IsPath == cmComputeLinkInformation::ItemIsPath::Yes &&
+ cmVS10IsTargetsFile(l.Value.Value)) {
std::string path =
this->LocalGenerator->MaybeRelativeToCurBinDir(l.Value.Value);
ConvertToWindowsSlash(path);
@@ -4028,7 +4029,7 @@ void cmVisualStudio10TargetGenerator::AddLibraries(
}
}
- if (l.IsPath) {
+ if (l.IsPath == cmComputeLinkInformation::ItemIsPath::Yes) {
std::string path =
this->LocalGenerator->MaybeRelativeToCurBinDir(l.Value.Value);
ConvertToWindowsSlash(path);
diff --git a/Tests/ExportImport/CMakeLists.txt b/Tests/ExportImport/CMakeLists.txt
index d88eb11..4999612 100644
--- a/Tests/ExportImport/CMakeLists.txt
+++ b/Tests/ExportImport/CMakeLists.txt
@@ -16,14 +16,12 @@ set_property(
)
get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
-if(_isMultiConfig)
- set(NESTED_CONFIG_TYPE -C "${CMAKE_CFG_INTDIR}")
+if(_isMultiConfig OR CMAKE_BUILD_TYPE)
+ set(NESTED_CONFIG_TYPE -C "$<CONFIG>")
+ set(NESTED_CONFIG_INSTALL_TYPE --config "$<CONFIG>")
else()
- if(CMAKE_BUILD_TYPE)
- set(NESTED_CONFIG_TYPE -C "${CMAKE_BUILD_TYPE}")
- else()
- set(NESTED_CONFIG_TYPE)
- endif()
+ set(NESTED_CONFIG_TYPE)
+ set(NESTED_CONFIG_INSTALL_TYPE)
endif()
if(MINGW OR MSYS)
@@ -79,5 +77,21 @@ set_property(
PROPERTY SYMBOLIC 1
)
+# Install the imported targets.
+add_custom_command(
+ OUTPUT ${ExportImport_BINARY_DIR}/ImportInstall
+ COMMAND ${CMAKE_COMMAND} -E rm -rf ${ExportImport_BINARY_DIR}/Import/install
+ COMMAND ${CMAKE_COMMAND}
+ --install ${ExportImport_BINARY_DIR}/Import
+ --prefix ${ExportImport_BINARY_DIR}/Import/install
+ ${NESTED_CONFIG_INSTALL_TYPE}
+ )
+add_custom_target(ImportInstallTarget ALL DEPENDS ${ExportImport_BINARY_DIR}/ImportInstall)
+add_dependencies(ImportInstallTarget ImportTarget)
+set_property(
+ SOURCE ${ExportImport_BINARY_DIR}/ImportInstall
+ PROPERTY SYMBOLIC 1
+ )
+
add_executable(ExportImport main.c)
add_dependencies(ExportImport ImportTarget)
diff --git a/Tests/ExportImport/Export/CMakeLists.txt b/Tests/ExportImport/Export/CMakeLists.txt
index 6d9b4ab..fa0016b 100644
--- a/Tests/ExportImport/Export/CMakeLists.txt
+++ b/Tests/ExportImport/Export/CMakeLists.txt
@@ -395,6 +395,10 @@ target_include_directories(systemlib
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
)
+add_library(testMod1 MODULE empty.cpp)
+add_library(testMod2 MODULE empty.cpp)
+set_property(TARGET testMod2 PROPERTY BUNDLE 1)
+
install(TARGETS testLibRequired
EXPORT RequiredExp DESTINATION lib
INCLUDES DESTINATION
@@ -523,6 +527,7 @@ install(
testLibDeprecation
testLibCycleA testLibCycleB
testLibNoSONAME
+ testMod1 testMod2
cmp0022NEW cmp0022OLD
TopDirLib SubDirLinkA
systemlib
@@ -595,6 +600,7 @@ export(TARGETS testExe2 testLib4 testLib5 testLib6 testLib7 testExe3 testExe4 te
testLib4lib testLib4libdbg testLib4libopt
testLibCycleA testLibCycleB
testLibNoSONAME
+ testMod1 testMod2
testLibPerConfigDest
NAMESPACE bld_
APPEND FILE ExportBuildTree.cmake
diff --git a/Tests/ExportImport/Import/CMakeLists.txt b/Tests/ExportImport/Import/CMakeLists.txt
index a8a98fc..e64c6b4 100644
--- a/Tests/ExportImport/Import/CMakeLists.txt
+++ b/Tests/ExportImport/Import/CMakeLists.txt
@@ -26,3 +26,6 @@ add_subdirectory(Interface)
# Test package version range
add_subdirectory(version_range)
+
+# Test install(IMPORTED_RUNTIME_ARTIFACTS)
+add_subdirectory(install-IMPORTED_RUNTIME_ARTIFACTS)
diff --git a/Tests/ExportImport/Import/install-IMPORTED_RUNTIME_ARTIFACTS/CMakeLists.txt b/Tests/ExportImport/Import/install-IMPORTED_RUNTIME_ARTIFACTS/CMakeLists.txt
new file mode 100644
index 0000000..76efe2f
--- /dev/null
+++ b/Tests/ExportImport/Import/install-IMPORTED_RUNTIME_ARTIFACTS/CMakeLists.txt
@@ -0,0 +1,30 @@
+# Import targets from the exported build tree.
+include(${Import_BINARY_DIR}/../Export/ExportBuildTree.cmake)
+
+set(_tgts
+ bld_testExe1 # Ordinary executable
+ bld_testExe2lib # Ordinary shared library
+ bld_testLib3 # Shared library with version and soversion
+ bld_testLib4 # Framework library
+ bld_testExe3 # Bundle executable
+ bld_testMod1 # Module library
+ bld_testMod2 # CFBundle
+ )
+
+install(IMPORTED_RUNTIME_ARTIFACTS ${_tgts}
+ RUNTIME DESTINATION aaa/executables
+ LIBRARY DESTINATION aaa/libraries
+ BUNDLE DESTINATION aaa/bundles
+ FRAMEWORK DESTINATION aaa/frameworks
+ )
+
+install(IMPORTED_RUNTIME_ARTIFACTS ${_tgts}
+ DESTINATION bbb
+ )
+
+install(IMPORTED_RUNTIME_ARTIFACTS ${_tgts}
+ BUNDLE DESTINATION zzz/bundles
+ FRAMEWORK DESTINATION zzz/frameworks
+ )
+
+install(SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/check_installed.cmake")
diff --git a/Tests/ExportImport/Import/install-IMPORTED_RUNTIME_ARTIFACTS/check_installed.cmake b/Tests/ExportImport/Import/install-IMPORTED_RUNTIME_ARTIFACTS/check_installed.cmake
new file mode 100644
index 0000000..29b298f
--- /dev/null
+++ b/Tests/ExportImport/Import/install-IMPORTED_RUNTIME_ARTIFACTS/check_installed.cmake
@@ -0,0 +1,57 @@
+cmake_minimum_required(VERSION 3.20)
+
+function(check_installed expect)
+ file(GLOB_RECURSE actual
+ LIST_DIRECTORIES TRUE
+ RELATIVE ${CMAKE_INSTALL_PREFIX}
+ ${CMAKE_INSTALL_PREFIX}/*
+ )
+ if(actual)
+ list(SORT actual)
+ endif()
+ if(NOT "${actual}" MATCHES "${expect}")
+ message(FATAL_ERROR "Installed files:
+ ${actual}
+do not match what we expected:
+ ${expect}
+in directory:
+ ${CMAKE_INSTALL_PREFIX}")
+ endif()
+endfunction()
+
+if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux")
+ set(_dirs [[aaa;aaa/executables;aaa/executables/testExe1-4;aaa/executables/testExe3;aaa/libraries;aaa/libraries/libtestExe2lib\.so;aaa/libraries/libtestLib3lib(-d|-r)?\.so\.1\.2;aaa/libraries/libtestLib3lib(-d|-r)?\.so\.3;aaa/libraries/libtestLib4\.so;aaa/libraries/libtestMod1\.so;aaa/libraries/libtestMod2\.so]])
+ set(_alldest [[bbb;bbb/libtestExe2lib\.so;bbb/libtestLib3lib(-d|-r)?\.so\.1\.2;bbb/libtestLib3lib(-d|-r)?\.so\.3;bbb/libtestLib4\.so;bbb/libtestMod1\.so;bbb/libtestMod2\.so;bbb/testExe1-4;bbb/testExe3]])
+ set(_default [[bin;bin/testExe1-4;bin/testExe3;lib;lib/libtestExe2lib\.so;lib/libtestLib3lib(-d|-r)?\.so\.1\.2;lib/libtestLib3lib(-d|-r)?\.so\.3;lib/libtestLib4\.so;lib/libtestMod1\.so;lib/libtestMod2\.so]])
+ check_installed("^${_dirs};${_alldest};${_default}$")
+elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
+ set(_dirs_msvc [[aaa;aaa/executables;aaa/executables/testExe1\.exe;aaa/executables/testExe2lib\.dll;aaa/executables/testExe3\.exe;aaa/executables/testLib3dll(-d|-r)?\.dll;aaa/executables/testLib4\.dll;aaa/libraries;aaa/libraries/testMod1\.dll;aaa/libraries/testMod2\.dll]])
+ set(_dirs_mingw [[aaa;aaa/executables;aaa/executables/libtestExe2lib\.dll;aaa/executables/libtestLib3dll(-d|-r)?\.dll;aaa/executables/libtestLib4\.dll;aaa/executables/testExe1\.exe;aaa/executables/testExe3\.exe;aaa/libraries;aaa/libraries/libtestMod1\.dll;aaa/libraries/libtestMod2\.dll]])
+
+ set(_alldest_msvc [[bbb;bbb/testExe1\.exe;bbb/testExe2lib\.dll;bbb/testExe3\.exe;bbb/testLib3dll(-d|-r)?\.dll;bbb/testLib4\.dll;bbb/testMod1\.dll;bbb/testMod2\.dll]])
+ set(_alldest_mingw [[bbb;bbb/libtestExe2lib\.dll;bbb/libtestLib3dll(-d|-r)?\.dll;bbb/libtestLib4\.dll;bbb/libtestMod1\.dll;bbb/libtestMod2\.dll;bbb/testExe1\.exe;bbb/testExe3\.exe]])
+
+ set(_default_msvc [[bin;bin/testExe1\.exe;bin/testExe2lib\.dll;bin/testExe3\.exe;bin/testLib3dll(-d|-r)?\.dll;bin/testLib4\.dll;lib;lib/testMod1\.dll;lib/testMod2\.dll]])
+ set(_default_mingw [[bin;bin/libtestExe2lib\.dll;bin/libtestLib3dll(-d|-r)?\.dll;bin/libtestLib4\.dll;bin/testExe1\.exe;bin/testExe3\.exe;lib;lib/libtestMod1\.dll;lib/libtestMod2\.dll]])
+
+ check_installed("^(${_dirs_msvc};${_alldest_msvc};${_default_msvc}|${_dirs_mingw};${_alldest_mingw};${_default_mingw})$")
+elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
+ set(_bundles [[aaa/bundles;aaa/bundles/testExe3\.app;aaa/bundles/testExe3\.app/Contents;aaa/bundles/testExe3\.app/Contents/Info\.plist;aaa/bundles/testExe3\.app/Contents/MacOS;aaa/bundles/testExe3\.app/Contents/MacOS/testExe3(;aaa/bundles/testExe3\.app/Contents/PkgInfo)?(;aaa/bundles/testExe3\.app/Contents/_CodeSignature;aaa/bundles/testExe3\.app/Contents/_CodeSignature/CodeResources)?]])
+ set(_executables [[aaa/executables;aaa/executables/testExe1(-4)?]])
+ set(_frameworks [[aaa/frameworks;aaa/frameworks/testLib4\.framework;aaa/frameworks/testLib4\.framework/Headers;aaa/frameworks/testLib4\.framework/Headers/testLib4\.h;aaa/frameworks/testLib4\.framework/Resources;aaa/frameworks/testLib4\.framework/Versions;aaa/frameworks/testLib4\.framework/Versions/A;aaa/frameworks/testLib4\.framework/Versions/A/Resources;aaa/frameworks/testLib4\.framework/Versions/A/Resources/Info\.plist(;aaa/frameworks/testLib4\.framework/Versions/A/_CodeSignature;aaa/frameworks/testLib4\.framework/Versions/A/_CodeSignature/CodeResources)?;aaa/frameworks/testLib4\.framework/Versions/A/testLib4;aaa/frameworks/testLib4\.framework/Versions/Current;aaa/frameworks/testLib4\.framework/testLib4]])
+ set(_libraries [[aaa/libraries;aaa/libraries/libtestExe2lib\.dylib;aaa/libraries/libtestLib3lib(-d|-r)?\.1\.2\.dylib;aaa/libraries/libtestLib3lib(-d|-r)?\.3\.dylib;aaa/libraries/libtestMod1\.so;aaa/libraries/testMod2\.bundle;aaa/libraries/testMod2\.bundle/Contents;aaa/libraries/testMod2\.bundle/Contents/Info\.plist;aaa/libraries/testMod2\.bundle/Contents/MacOS;aaa/libraries/testMod2\.bundle/Contents/MacOS/testMod2(;aaa/libraries/testMod2\.bundle/Contents/_CodeSignature;aaa/libraries/testMod2\.bundle/Contents/_CodeSignature/CodeResources)?]])
+ set(_dirs "aaa;${_bundles};${_executables};${_frameworks};${_libraries}")
+
+ set(_alldest [[bbb;bbb/libtestExe2lib\.dylib;bbb/libtestLib3lib(-d|-r)?\.1\.2\.dylib;bbb/libtestLib3lib(-d|-r)?\.3\.dylib;bbb/libtestMod1\.so;bbb/testExe1(-4)?;bbb/testExe3\.app;bbb/testExe3\.app/Contents;bbb/testExe3\.app/Contents/Info\.plist;bbb/testExe3\.app/Contents/MacOS;bbb/testExe3\.app/Contents/MacOS/testExe3(;bbb/testExe3\.app/Contents/PkgInfo)?(;bbb/testExe3\.app/Contents/_CodeSignature;bbb/testExe3\.app/Contents/_CodeSignature/CodeResources)?;bbb/testLib4\.framework;bbb/testLib4\.framework/Headers;bbb/testLib4\.framework/Headers/testLib4\.h;bbb/testLib4\.framework/Resources;bbb/testLib4\.framework/Versions;bbb/testLib4\.framework/Versions/A;bbb/testLib4\.framework/Versions/A/Resources;bbb/testLib4\.framework/Versions/A/Resources/Info\.plist(;bbb/testLib4\.framework/Versions/A/_CodeSignature;bbb/testLib4\.framework/Versions/A/_CodeSignature/CodeResources)?;bbb/testLib4\.framework/Versions/A/testLib4;bbb/testLib4\.framework/Versions/Current;bbb/testLib4\.framework/testLib4;bbb/testMod2\.bundle;bbb/testMod2\.bundle/Contents;bbb/testMod2\.bundle/Contents/Info\.plist;bbb/testMod2\.bundle/Contents/MacOS;bbb/testMod2\.bundle/Contents/MacOS/testMod2(;bbb/testMod2\.bundle/Contents/_CodeSignature;bbb/testMod2\.bundle/Contents/_CodeSignature/CodeResources)?]])
+
+ set(_default_bin [[bin;bin/testExe1(-4)?]])
+ set(_default_lib [[lib;lib/libtestExe2lib\.dylib;lib/libtestLib3lib(-d|-r)?\.1\.2\.dylib;lib/libtestLib3lib(-d|-r)?\.3\.dylib;lib/libtestMod1\.so;lib/testMod2\.bundle;lib/testMod2\.bundle/Contents;lib/testMod2\.bundle/Contents/Info\.plist;lib/testMod2\.bundle/Contents/MacOS;lib/testMod2\.bundle/Contents/MacOS/testMod2(;lib/testMod2\.bundle/Contents/_CodeSignature;lib/testMod2\.bundle/Contents/_CodeSignature/CodeResources)?]])
+ set(_default_bundles [[zzz/bundles;zzz/bundles/testExe3\.app;zzz/bundles/testExe3\.app/Contents;zzz/bundles/testExe3\.app/Contents/Info\.plist;zzz/bundles/testExe3\.app/Contents/MacOS;zzz/bundles/testExe3\.app/Contents/MacOS/testExe3(;zzz/bundles/testExe3\.app/Contents/PkgInfo)?(;zzz/bundles/testExe3\.app/Contents/_CodeSignature;zzz/bundles/testExe3\.app/Contents/_CodeSignature/CodeResources)?]])
+ set(_default_frameworks [[zzz/frameworks;zzz/frameworks/testLib4\.framework;zzz/frameworks/testLib4\.framework/Headers;zzz/frameworks/testLib4\.framework/Headers/testLib4\.h;zzz/frameworks/testLib4\.framework/Resources;zzz/frameworks/testLib4\.framework/Versions;zzz/frameworks/testLib4\.framework/Versions/A;zzz/frameworks/testLib4\.framework/Versions/A/Resources;zzz/frameworks/testLib4\.framework/Versions/A/Resources/Info\.plist(;zzz/frameworks/testLib4\.framework/Versions/A/_CodeSignature;zzz/frameworks/testLib4\.framework/Versions/A/_CodeSignature/CodeResources)?;zzz/frameworks/testLib4\.framework/Versions/A/testLib4;zzz/frameworks/testLib4\.framework/Versions/Current;zzz/frameworks/testLib4\.framework/testLib4]])
+ set(_default "${_default_bin};${_default_lib};zzz;${_default_bundles};${_default_frameworks}")
+
+ # Need to break this up due to too many pairs of parentheses
+ check_installed("^${_dirs};bbb;")
+ check_installed(";${_alldest};bin;")
+ check_installed(";${_default}$")
+endif()
diff --git a/Tests/ObjectLibrary/CMakeLists.txt b/Tests/ObjectLibrary/CMakeLists.txt
index 74f34e4..06167a8 100644
--- a/Tests/ObjectLibrary/CMakeLists.txt
+++ b/Tests/ObjectLibrary/CMakeLists.txt
@@ -74,4 +74,6 @@ target_link_libraries(UseABstaticObjs ABstatic)
add_subdirectory(ExportLanguages)
+add_subdirectory(LinkObjects)
+
add_subdirectory(Transitive)
diff --git a/Tests/ObjectLibrary/LinkObjects/CMakeLists.txt b/Tests/ObjectLibrary/LinkObjects/CMakeLists.txt
new file mode 100644
index 0000000..899be45
--- /dev/null
+++ b/Tests/ObjectLibrary/LinkObjects/CMakeLists.txt
@@ -0,0 +1,45 @@
+add_executable(LinkObjects main.c)
+
+# Link TARGET_OBJECTS through LINK_LIBRARIES.
+add_library(LinkObjectsAObj OBJECT a_obj.c)
+add_library(LinkObjectsADep STATIC a_dep.c)
+target_compile_definitions(LinkObjectsAObj PUBLIC OBJA)
+target_link_libraries(LinkObjects PRIVATE LinkObjectsADep $<TARGET_OBJECTS:LinkObjectsAObj>)
+
+# Link TARGET_OBJECTS through INTERFACE_LINK_LIBRARIES with usage requirements.
+add_library(LinkObjectsB INTERFACE)
+add_library(LinkObjectsBObj OBJECT b_obj.c)
+add_library(LinkObjectsBDep STATIC b_dep.c)
+target_compile_definitions(LinkObjectsBObj PUBLIC OBJB)
+target_link_libraries(LinkObjectsB INTERFACE LinkObjectsBObj $<TARGET_OBJECTS:LinkObjectsBObj>)
+target_link_libraries(LinkObjectsBObj PRIVATE LinkObjectsBDep)
+target_link_libraries(LinkObjects PRIVATE LinkObjectsB)
+
+# Link TARGET_OBJECTS through INTERFACE_LINK_LIBRARIES without usage requirements.
+add_library(LinkObjectsC INTERFACE)
+add_library(LinkObjectsCObj OBJECT c_obj.c)
+add_library(LinkObjectsCDep STATIC c_dep.c)
+target_compile_definitions(LinkObjectsCObj PUBLIC OBJC)
+target_link_libraries(LinkObjectsC INTERFACE LinkObjectsCDep $<TARGET_OBJECTS:LinkObjectsCObj>)
+target_link_libraries(LinkObjectsCObj PRIVATE LinkObjectsCDep)
+target_link_libraries(LinkObjects PRIVATE LinkObjectsC)
+
+# Link TARGET_OBJECTS through both LINK_LIBRARIES and INTERFACE_LINK_LIBRARIES, deduplicated.
+add_library(LinkObjectsD INTERFACE)
+add_library(LinkObjectsDObj OBJECT d_obj.c)
+add_library(LinkObjectsDDep STATIC d_dep.c)
+target_compile_definitions(LinkObjectsDObj PUBLIC OBJD)
+target_link_libraries(LinkObjectsD INTERFACE LinkObjectsDObj $<TARGET_OBJECTS:LinkObjectsDObj>)
+target_link_libraries(LinkObjectsDObj PRIVATE LinkObjectsDDep)
+target_link_libraries(LinkObjects PRIVATE $<TARGET_OBJECTS:LinkObjectsDObj> LinkObjectsD)
+
+# Link TARGET_OBJECTS through STATIC library private dependency.
+add_library(LinkObjectsE INTERFACE)
+add_library(LinkObjectsEObj OBJECT e_obj.c)
+add_library(LinkObjectsEDep STATIC e_dep.c)
+add_library(LinkObjectsEStatic STATIC e_lib.c)
+target_compile_definitions(LinkObjectsEObj PUBLIC OBJE)
+target_link_libraries(LinkObjectsE INTERFACE LinkObjectsEObj $<TARGET_OBJECTS:LinkObjectsEObj>)
+target_link_libraries(LinkObjectsEObj PRIVATE LinkObjectsEDep)
+target_link_libraries(LinkObjectsEStatic PRIVATE LinkObjectsE)
+target_link_libraries(LinkObjects PRIVATE LinkObjectsEStatic)
diff --git a/Tests/ObjectLibrary/LinkObjects/a_dep.c b/Tests/ObjectLibrary/LinkObjects/a_dep.c
new file mode 100644
index 0000000..0128740
--- /dev/null
+++ b/Tests/ObjectLibrary/LinkObjects/a_dep.c
@@ -0,0 +1,7 @@
+#ifdef OBJA
+# error "OBJA is defined, but should not be"
+#endif
+int a_dep(void)
+{
+ return 0;
+}
diff --git a/Tests/ObjectLibrary/LinkObjects/a_obj.c b/Tests/ObjectLibrary/LinkObjects/a_obj.c
new file mode 100644
index 0000000..5e79c60
--- /dev/null
+++ b/Tests/ObjectLibrary/LinkObjects/a_obj.c
@@ -0,0 +1,8 @@
+#ifndef OBJA
+# error "OBJA is not defined, but should be"
+#endif
+extern int a_dep(void);
+int a_obj(void)
+{
+ return a_dep();
+}
diff --git a/Tests/ObjectLibrary/LinkObjects/b_dep.c b/Tests/ObjectLibrary/LinkObjects/b_dep.c
new file mode 100644
index 0000000..ad5d367
--- /dev/null
+++ b/Tests/ObjectLibrary/LinkObjects/b_dep.c
@@ -0,0 +1,7 @@
+#ifdef OBJB
+# error "OBJB is defined, but should not be"
+#endif
+int b_dep(void)
+{
+ return 0;
+}
diff --git a/Tests/ObjectLibrary/LinkObjects/b_obj.c b/Tests/ObjectLibrary/LinkObjects/b_obj.c
new file mode 100644
index 0000000..d0f426a
--- /dev/null
+++ b/Tests/ObjectLibrary/LinkObjects/b_obj.c
@@ -0,0 +1,8 @@
+#ifndef OBJB
+# error "OBJB is not defined, but should be"
+#endif
+extern int b_dep(void);
+int b_obj(void)
+{
+ return b_dep();
+}
diff --git a/Tests/ObjectLibrary/LinkObjects/c_dep.c b/Tests/ObjectLibrary/LinkObjects/c_dep.c
new file mode 100644
index 0000000..1d99ab8
--- /dev/null
+++ b/Tests/ObjectLibrary/LinkObjects/c_dep.c
@@ -0,0 +1,7 @@
+#ifdef OBJC
+# error "OBJC is defined, but should not be"
+#endif
+int c_dep(void)
+{
+ return 0;
+}
diff --git a/Tests/ObjectLibrary/LinkObjects/c_obj.c b/Tests/ObjectLibrary/LinkObjects/c_obj.c
new file mode 100644
index 0000000..08fa5f5
--- /dev/null
+++ b/Tests/ObjectLibrary/LinkObjects/c_obj.c
@@ -0,0 +1,8 @@
+#ifndef OBJC
+# error "OBJC is not defined, but should be"
+#endif
+extern int c_dep(void);
+int c_obj(void)
+{
+ return c_dep();
+}
diff --git a/Tests/ObjectLibrary/LinkObjects/d_dep.c b/Tests/ObjectLibrary/LinkObjects/d_dep.c
new file mode 100644
index 0000000..cf09314
--- /dev/null
+++ b/Tests/ObjectLibrary/LinkObjects/d_dep.c
@@ -0,0 +1,7 @@
+#ifdef OBJD
+# error "OBJD is defined, but should not be"
+#endif
+int d_dep(void)
+{
+ return 0;
+}
diff --git a/Tests/ObjectLibrary/LinkObjects/d_obj.c b/Tests/ObjectLibrary/LinkObjects/d_obj.c
new file mode 100644
index 0000000..d14ce66
--- /dev/null
+++ b/Tests/ObjectLibrary/LinkObjects/d_obj.c
@@ -0,0 +1,8 @@
+#ifndef OBJD
+# error "OBJD is not defined, but should be"
+#endif
+extern int d_dep(void);
+int d_obj(void)
+{
+ return d_dep();
+}
diff --git a/Tests/ObjectLibrary/LinkObjects/e_dep.c b/Tests/ObjectLibrary/LinkObjects/e_dep.c
new file mode 100644
index 0000000..7fb70c1
--- /dev/null
+++ b/Tests/ObjectLibrary/LinkObjects/e_dep.c
@@ -0,0 +1,7 @@
+#ifdef OBJE
+# error "OBJE is defined, but should not be"
+#endif
+int e_dep(void)
+{
+ return 0;
+}
diff --git a/Tests/ObjectLibrary/LinkObjects/e_lib.c b/Tests/ObjectLibrary/LinkObjects/e_lib.c
new file mode 100644
index 0000000..9bb3a44
--- /dev/null
+++ b/Tests/ObjectLibrary/LinkObjects/e_lib.c
@@ -0,0 +1,5 @@
+extern int e_obj(void);
+int e_lib(void)
+{
+ return e_obj();
+}
diff --git a/Tests/ObjectLibrary/LinkObjects/e_obj.c b/Tests/ObjectLibrary/LinkObjects/e_obj.c
new file mode 100644
index 0000000..02624eb
--- /dev/null
+++ b/Tests/ObjectLibrary/LinkObjects/e_obj.c
@@ -0,0 +1,8 @@
+#ifndef OBJE
+# error "OBJE is not defined, but should be"
+#endif
+extern int e_dep(void);
+int e_obj(void)
+{
+ return e_dep();
+}
diff --git a/Tests/ObjectLibrary/LinkObjects/main.c b/Tests/ObjectLibrary/LinkObjects/main.c
new file mode 100644
index 0000000..c09c4f1
--- /dev/null
+++ b/Tests/ObjectLibrary/LinkObjects/main.c
@@ -0,0 +1,24 @@
+#ifdef OBJA
+# error "OBJA is defined, but should not be"
+#endif
+#ifndef OBJB
+# error "OBJB is not defined, but should be"
+#endif
+#ifdef OBJC
+# error "OBJC is defined, but should not be"
+#endif
+#ifndef OBJD
+# error "OBJD is not defined, but should be"
+#endif
+#ifdef OBJE
+# error "OBJE is defined, but should not be"
+#endif
+extern int a_obj(void);
+extern int b_obj(void);
+extern int c_obj(void);
+extern int d_obj(void);
+extern int e_lib(void);
+int main(void)
+{
+ return a_obj() + b_obj() + c_obj() + d_obj() + e_lib();
+}
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index 14a7fa3..d02d7a2 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -732,12 +732,14 @@ if("${CMAKE_GENERATOR}" MATCHES "Make|Ninja")
endif()
if (APPLE AND CMAKE_C_COMPILER_ID MATCHES "Clang|GNU")
list(APPEND CompilerLauncher_ARGS -DCMake_TEST_OBJC=1)
+ list(APPEND LinkerLauncher_ARGS -DCMake_TEST_OBJC=1)
endif()
add_RunCMake_test(CompilerLauncher)
set_property(TEST RunCMake.CompilerLauncher APPEND
PROPERTY LABELS "CUDA;ISPC")
add_RunCMake_test(ctest_labels_for_subprojects)
add_RunCMake_test(CompilerArgs)
+ add_RunCMake_test(LinkerLauncher)
endif()
set(cpack_tests
diff --git a/Tests/RunCMake/CompilerLauncher/ISPC-env-launch-Build-stdout.txt b/Tests/RunCMake/CompilerLauncher/C-launch-env-Build-stdout.txt
index 3313e31..3313e31 100644
--- a/Tests/RunCMake/CompilerLauncher/ISPC-env-launch-Build-stdout.txt
+++ b/Tests/RunCMake/CompilerLauncher/C-launch-env-Build-stdout.txt
diff --git a/Tests/RunCMake/CompilerLauncher/Fortran-env-launch-Build-stdout.txt b/Tests/RunCMake/CompilerLauncher/CUDA-launch-env-Build-stdout.txt
index 3313e31..3313e31 100644
--- a/Tests/RunCMake/CompilerLauncher/Fortran-env-launch-Build-stdout.txt
+++ b/Tests/RunCMake/CompilerLauncher/CUDA-launch-env-Build-stdout.txt
diff --git a/Tests/RunCMake/CompilerLauncher/CXX-env-launch-Build-stdout.txt b/Tests/RunCMake/CompilerLauncher/CXX-launch-env-Build-stdout.txt
index 3313e31..3313e31 100644
--- a/Tests/RunCMake/CompilerLauncher/CXX-env-launch-Build-stdout.txt
+++ b/Tests/RunCMake/CompilerLauncher/CXX-launch-env-Build-stdout.txt
diff --git a/Tests/RunCMake/CompilerLauncher/CUDA-env-launch-Build-stdout.txt b/Tests/RunCMake/CompilerLauncher/Fortran-launch-env-Build-stdout.txt
index 3313e31..3313e31 100644
--- a/Tests/RunCMake/CompilerLauncher/CUDA-env-launch-Build-stdout.txt
+++ b/Tests/RunCMake/CompilerLauncher/Fortran-launch-env-Build-stdout.txt
diff --git a/Tests/RunCMake/CompilerLauncher/C-env-launch-Build-stdout.txt b/Tests/RunCMake/CompilerLauncher/ISPC-launch-env-Build-stdout.txt
index 3313e31..3313e31 100644
--- a/Tests/RunCMake/CompilerLauncher/C-env-launch-Build-stdout.txt
+++ b/Tests/RunCMake/CompilerLauncher/ISPC-launch-env-Build-stdout.txt
diff --git a/Tests/RunCMake/CompilerLauncher/RunCMakeTest.cmake b/Tests/RunCMake/CompilerLauncher/RunCMakeTest.cmake
index 293d711..787282a 100644
--- a/Tests/RunCMake/CompilerLauncher/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CompilerLauncher/RunCMakeTest.cmake
@@ -1,7 +1,7 @@
include(RunCMake)
function(run_compiler_launcher lang)
- # Use a single build tree for tests without cleaning.
+ # Preserve build tree so we can reuse it for the ${lang}-Build subtest below
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${lang}-build)
set(RunCMake_TEST_NO_CLEAN 1)
file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
diff --git a/Tests/RunCMake/ExportCompileCommands/CustomCompileRule.cmake b/Tests/RunCMake/ExportCompileCommands/CustomCompileRule.cmake
index 12368a2..b1b120f 100644
--- a/Tests/RunCMake/ExportCompileCommands/CustomCompileRule.cmake
+++ b/Tests/RunCMake/ExportCompileCommands/CustomCompileRule.cmake
@@ -1,5 +1,6 @@
enable_language(C)
+set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
add_library(empty STATIC empty.c)
string(REPLACE "<DEFINES>" "" CMAKE_C_COMPILE_OBJECT "${CMAKE_C_COMPILE_OBJECT}")
string(REPLACE "<INCLUDES>" "" CMAKE_C_COMPILE_OBJECT "${CMAKE_C_COMPILE_OBJECT}")
-set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
+string(REPLACE "<FLAGS>" "" CMAKE_C_COMPILE_OBJECT "${CMAKE_C_COMPILE_OBJECT}")
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-check.py b/Tests/RunCMake/FileAPI/codemodel-v2-check.py
index b9a1fbf..9911ad5 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-check.py
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-check.py
@@ -644,7 +644,7 @@ def gen_check_directories(c, g):
if sys.platform not in ("win32", "cygwin", "msys"):
for e in expected:
- e["installers"] = list(filter(lambda i: "_dllExtra" not in i or not i["_dllExtra"], e["installers"]))
+ e["installers"] = list(filter(lambda i: not i.get("_dllExtra", False), e["installers"]))
if "aix" not in sys.platform:
for i in e["installers"]:
if "pathsNamelink" in i:
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/imported.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/imported.json
index d127274..92b9526 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/imported.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/imported.json
@@ -14,6 +14,67 @@
],
"projectName": "Imported",
"minimumCMakeVersion": "3.12",
- "hasInstallRule": null,
- "installers": []
+ "hasInstallRule": true,
+ "installers": [
+ {
+ "component": "Unspecified",
+ "type": "importedRuntimeArtifacts",
+ "destination": "lib",
+ "paths": null,
+ "isExcludeFromAll": null,
+ "isForAllComponents": null,
+ "isOptional": null,
+ "targetId": null,
+ "targetIndex": null,
+ "targetIsImportLibrary": null,
+ "targetInstallNamelink": null,
+ "exportName": null,
+ "exportTargets": null,
+ "scriptFile": null,
+ "backtrace": [
+ {
+ "file": "^imported/CMakeLists\\.txt$",
+ "line": 32,
+ "command": "install",
+ "hasParent": true
+ },
+ {
+ "file": "^imported/CMakeLists\\.txt$",
+ "line": null,
+ "command": null,
+ "hasParent": false
+ }
+ ]
+ },
+ {
+ "component": "Unspecified",
+ "type": "importedRuntimeArtifacts",
+ "destination": "lib2",
+ "paths": null,
+ "isExcludeFromAll": null,
+ "isForAllComponents": null,
+ "isOptional": true,
+ "targetId": null,
+ "targetIndex": null,
+ "targetIsImportLibrary": null,
+ "targetInstallNamelink": null,
+ "exportName": null,
+ "exportTargets": null,
+ "scriptFile": null,
+ "backtrace": [
+ {
+ "file": "^imported/CMakeLists\\.txt$",
+ "line": 35,
+ "command": "install",
+ "hasParent": true
+ },
+ {
+ "file": "^imported/CMakeLists\\.txt$",
+ "line": null,
+ "command": null,
+ "hasParent": false
+ }
+ ]
+ }
+ ]
}
diff --git a/Tests/RunCMake/FileAPI/imported/CMakeLists.txt b/Tests/RunCMake/FileAPI/imported/CMakeLists.txt
index f79d87c..770838b 100644
--- a/Tests/RunCMake/FileAPI/imported/CMakeLists.txt
+++ b/Tests/RunCMake/FileAPI/imported/CMakeLists.txt
@@ -28,3 +28,10 @@ endif()
add_library(imported_interface_lib INTERFACE IMPORTED)
add_executable(link_imported_interface_exe ../empty.c)
target_link_libraries(link_imported_interface_exe PRIVATE imported_interface_lib)
+
+install(IMPORTED_RUNTIME_ARTIFACTS imported_shared_lib
+ DESTINATION lib
+)
+install(IMPORTED_RUNTIME_ARTIFACTS imported_shared_lib
+ DESTINATION lib2 OPTIONAL
+)
diff --git a/Tests/RunCMake/LinkerLauncher/C-Build-stdout.txt b/Tests/RunCMake/LinkerLauncher/C-Build-stdout.txt
new file mode 100644
index 0000000..3313e31
--- /dev/null
+++ b/Tests/RunCMake/LinkerLauncher/C-Build-stdout.txt
@@ -0,0 +1 @@
+.*-E env USED_LAUNCHER=1.*
diff --git a/Tests/RunCMake/LinkerLauncher/C-common.cmake b/Tests/RunCMake/LinkerLauncher/C-common.cmake
new file mode 100644
index 0000000..96b004b
--- /dev/null
+++ b/Tests/RunCMake/LinkerLauncher/C-common.cmake
@@ -0,0 +1,3 @@
+enable_language(C)
+set(CMAKE_VERBOSE_MAKEFILE TRUE)
+add_executable(main main.c)
diff --git a/Tests/RunCMake/LinkerLauncher/C-env-Build-stdout.txt b/Tests/RunCMake/LinkerLauncher/C-env-Build-stdout.txt
new file mode 100644
index 0000000..3313e31
--- /dev/null
+++ b/Tests/RunCMake/LinkerLauncher/C-env-Build-stdout.txt
@@ -0,0 +1 @@
+.*-E env USED_LAUNCHER=1.*
diff --git a/Tests/RunCMake/LinkerLauncher/C-env.cmake b/Tests/RunCMake/LinkerLauncher/C-env.cmake
new file mode 100644
index 0000000..09b5167
--- /dev/null
+++ b/Tests/RunCMake/LinkerLauncher/C-env.cmake
@@ -0,0 +1 @@
+include(C-common.cmake)
diff --git a/Tests/RunCMake/LinkerLauncher/C-launch-Build-stdout.txt b/Tests/RunCMake/LinkerLauncher/C-launch-Build-stdout.txt
new file mode 100644
index 0000000..3313e31
--- /dev/null
+++ b/Tests/RunCMake/LinkerLauncher/C-launch-Build-stdout.txt
@@ -0,0 +1 @@
+.*-E env USED_LAUNCHER=1.*
diff --git a/Tests/RunCMake/LinkerLauncher/C-launch-env-Build-stdout.txt b/Tests/RunCMake/LinkerLauncher/C-launch-env-Build-stdout.txt
new file mode 100644
index 0000000..3313e31
--- /dev/null
+++ b/Tests/RunCMake/LinkerLauncher/C-launch-env-Build-stdout.txt
@@ -0,0 +1 @@
+.*-E env USED_LAUNCHER=1.*
diff --git a/Tests/RunCMake/LinkerLauncher/C-launch-env.cmake b/Tests/RunCMake/LinkerLauncher/C-launch-env.cmake
new file mode 100644
index 0000000..68abcb5
--- /dev/null
+++ b/Tests/RunCMake/LinkerLauncher/C-launch-env.cmake
@@ -0,0 +1,3 @@
+set(CTEST_USE_LAUNCHERS 1)
+include(CTestUseLaunchers)
+include(C-env.cmake)
diff --git a/Tests/RunCMake/LinkerLauncher/C-launch.cmake b/Tests/RunCMake/LinkerLauncher/C-launch.cmake
new file mode 100644
index 0000000..e66ca20
--- /dev/null
+++ b/Tests/RunCMake/LinkerLauncher/C-launch.cmake
@@ -0,0 +1,3 @@
+set(CTEST_USE_LAUNCHERS 1)
+include(CTestUseLaunchers)
+include(C.cmake)
diff --git a/Tests/RunCMake/LinkerLauncher/C.cmake b/Tests/RunCMake/LinkerLauncher/C.cmake
new file mode 100644
index 0000000..b55ca8e
--- /dev/null
+++ b/Tests/RunCMake/LinkerLauncher/C.cmake
@@ -0,0 +1,2 @@
+set(CMAKE_C_LINKER_LAUNCHER "${CMAKE_COMMAND};-E;env;USED_LAUNCHER=1")
+include(C-common.cmake)
diff --git a/Tests/RunCMake/LinkerLauncher/CMakeLists.txt b/Tests/RunCMake/LinkerLauncher/CMakeLists.txt
new file mode 100644
index 0000000..7cabeb6
--- /dev/null
+++ b/Tests/RunCMake/LinkerLauncher/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.20)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/LinkerLauncher/CXX-Build-stdout.txt b/Tests/RunCMake/LinkerLauncher/CXX-Build-stdout.txt
new file mode 100644
index 0000000..3313e31
--- /dev/null
+++ b/Tests/RunCMake/LinkerLauncher/CXX-Build-stdout.txt
@@ -0,0 +1 @@
+.*-E env USED_LAUNCHER=1.*
diff --git a/Tests/RunCMake/LinkerLauncher/CXX-common.cmake b/Tests/RunCMake/LinkerLauncher/CXX-common.cmake
new file mode 100644
index 0000000..3d2ee00
--- /dev/null
+++ b/Tests/RunCMake/LinkerLauncher/CXX-common.cmake
@@ -0,0 +1,3 @@
+enable_language(CXX)
+set(CMAKE_VERBOSE_MAKEFILE TRUE)
+add_executable(main main.cxx)
diff --git a/Tests/RunCMake/LinkerLauncher/CXX-env-Build-stdout.txt b/Tests/RunCMake/LinkerLauncher/CXX-env-Build-stdout.txt
new file mode 100644
index 0000000..3313e31
--- /dev/null
+++ b/Tests/RunCMake/LinkerLauncher/CXX-env-Build-stdout.txt
@@ -0,0 +1 @@
+.*-E env USED_LAUNCHER=1.*
diff --git a/Tests/RunCMake/LinkerLauncher/CXX-env.cmake b/Tests/RunCMake/LinkerLauncher/CXX-env.cmake
new file mode 100644
index 0000000..db36956
--- /dev/null
+++ b/Tests/RunCMake/LinkerLauncher/CXX-env.cmake
@@ -0,0 +1 @@
+include(CXX-common.cmake)
diff --git a/Tests/RunCMake/LinkerLauncher/CXX-launch-Build-stdout.txt b/Tests/RunCMake/LinkerLauncher/CXX-launch-Build-stdout.txt
new file mode 100644
index 0000000..3313e31
--- /dev/null
+++ b/Tests/RunCMake/LinkerLauncher/CXX-launch-Build-stdout.txt
@@ -0,0 +1 @@
+.*-E env USED_LAUNCHER=1.*
diff --git a/Tests/RunCMake/LinkerLauncher/CXX-launch-env-Build-stdout.txt b/Tests/RunCMake/LinkerLauncher/CXX-launch-env-Build-stdout.txt
new file mode 100644
index 0000000..3313e31
--- /dev/null
+++ b/Tests/RunCMake/LinkerLauncher/CXX-launch-env-Build-stdout.txt
@@ -0,0 +1 @@
+.*-E env USED_LAUNCHER=1.*
diff --git a/Tests/RunCMake/LinkerLauncher/CXX-launch-env.cmake b/Tests/RunCMake/LinkerLauncher/CXX-launch-env.cmake
new file mode 100644
index 0000000..a65cc89
--- /dev/null
+++ b/Tests/RunCMake/LinkerLauncher/CXX-launch-env.cmake
@@ -0,0 +1,3 @@
+set(CTEST_USE_LAUNCHERS 1)
+include(CTestUseLaunchers)
+include(CXX-env.cmake)
diff --git a/Tests/RunCMake/LinkerLauncher/CXX-launch.cmake b/Tests/RunCMake/LinkerLauncher/CXX-launch.cmake
new file mode 100644
index 0000000..3002c9d
--- /dev/null
+++ b/Tests/RunCMake/LinkerLauncher/CXX-launch.cmake
@@ -0,0 +1,3 @@
+set(CTEST_USE_LAUNCHERS 1)
+include(CTestUseLaunchers)
+include(CXX.cmake)
diff --git a/Tests/RunCMake/LinkerLauncher/CXX.cmake b/Tests/RunCMake/LinkerLauncher/CXX.cmake
new file mode 100644
index 0000000..4326614
--- /dev/null
+++ b/Tests/RunCMake/LinkerLauncher/CXX.cmake
@@ -0,0 +1,2 @@
+set(CMAKE_CXX_LINKER_LAUNCHER "${CMAKE_COMMAND};-E;env;USED_LAUNCHER=1")
+include(CXX-common.cmake)
diff --git a/Tests/RunCMake/LinkerLauncher/OBJC-Build-stdout.txt b/Tests/RunCMake/LinkerLauncher/OBJC-Build-stdout.txt
new file mode 100644
index 0000000..3313e31
--- /dev/null
+++ b/Tests/RunCMake/LinkerLauncher/OBJC-Build-stdout.txt
@@ -0,0 +1 @@
+.*-E env USED_LAUNCHER=1.*
diff --git a/Tests/RunCMake/LinkerLauncher/OBJC-common.cmake b/Tests/RunCMake/LinkerLauncher/OBJC-common.cmake
new file mode 100644
index 0000000..7b565f4
--- /dev/null
+++ b/Tests/RunCMake/LinkerLauncher/OBJC-common.cmake
@@ -0,0 +1,3 @@
+enable_language(OBJC)
+set(CMAKE_VERBOSE_MAKEFILE TRUE)
+add_executable(main main.m)
diff --git a/Tests/RunCMake/LinkerLauncher/OBJC-env-Build-stdout.txt b/Tests/RunCMake/LinkerLauncher/OBJC-env-Build-stdout.txt
new file mode 100644
index 0000000..3313e31
--- /dev/null
+++ b/Tests/RunCMake/LinkerLauncher/OBJC-env-Build-stdout.txt
@@ -0,0 +1 @@
+.*-E env USED_LAUNCHER=1.*
diff --git a/Tests/RunCMake/LinkerLauncher/OBJC-env.cmake b/Tests/RunCMake/LinkerLauncher/OBJC-env.cmake
new file mode 100644
index 0000000..949e88d
--- /dev/null
+++ b/Tests/RunCMake/LinkerLauncher/OBJC-env.cmake
@@ -0,0 +1 @@
+include(OBJC-common.cmake)
diff --git a/Tests/RunCMake/LinkerLauncher/OBJC-launch-Build-stdout.txt b/Tests/RunCMake/LinkerLauncher/OBJC-launch-Build-stdout.txt
new file mode 100644
index 0000000..3313e31
--- /dev/null
+++ b/Tests/RunCMake/LinkerLauncher/OBJC-launch-Build-stdout.txt
@@ -0,0 +1 @@
+.*-E env USED_LAUNCHER=1.*
diff --git a/Tests/RunCMake/LinkerLauncher/OBJC-launch-env-Build-stdout.txt b/Tests/RunCMake/LinkerLauncher/OBJC-launch-env-Build-stdout.txt
new file mode 100644
index 0000000..3313e31
--- /dev/null
+++ b/Tests/RunCMake/LinkerLauncher/OBJC-launch-env-Build-stdout.txt
@@ -0,0 +1 @@
+.*-E env USED_LAUNCHER=1.*
diff --git a/Tests/RunCMake/LinkerLauncher/OBJC-launch-env.cmake b/Tests/RunCMake/LinkerLauncher/OBJC-launch-env.cmake
new file mode 100644
index 0000000..1cf13d3
--- /dev/null
+++ b/Tests/RunCMake/LinkerLauncher/OBJC-launch-env.cmake
@@ -0,0 +1,3 @@
+set(CTEST_USE_LAUNCHERS 1)
+include(CTestUseLaunchers)
+include(OBJC-env.cmake)
diff --git a/Tests/RunCMake/LinkerLauncher/OBJC-launch.cmake b/Tests/RunCMake/LinkerLauncher/OBJC-launch.cmake
new file mode 100644
index 0000000..43e8521
--- /dev/null
+++ b/Tests/RunCMake/LinkerLauncher/OBJC-launch.cmake
@@ -0,0 +1,3 @@
+set(CTEST_USE_LAUNCHERS 1)
+include(CTestUseLaunchers)
+include(OBJC.cmake)
diff --git a/Tests/RunCMake/LinkerLauncher/OBJC.cmake b/Tests/RunCMake/LinkerLauncher/OBJC.cmake
new file mode 100644
index 0000000..e0360b3
--- /dev/null
+++ b/Tests/RunCMake/LinkerLauncher/OBJC.cmake
@@ -0,0 +1,2 @@
+set(CMAKE_OBJC_LINKER_LAUNCHER "${CMAKE_COMMAND};-E;env;USED_LAUNCHER=1")
+include(OBJC-common.cmake)
diff --git a/Tests/RunCMake/LinkerLauncher/OBJCXX-Build-stdout.txt b/Tests/RunCMake/LinkerLauncher/OBJCXX-Build-stdout.txt
new file mode 100644
index 0000000..3313e31
--- /dev/null
+++ b/Tests/RunCMake/LinkerLauncher/OBJCXX-Build-stdout.txt
@@ -0,0 +1 @@
+.*-E env USED_LAUNCHER=1.*
diff --git a/Tests/RunCMake/LinkerLauncher/OBJCXX-common.cmake b/Tests/RunCMake/LinkerLauncher/OBJCXX-common.cmake
new file mode 100644
index 0000000..e2ee4eb
--- /dev/null
+++ b/Tests/RunCMake/LinkerLauncher/OBJCXX-common.cmake
@@ -0,0 +1,3 @@
+enable_language(OBJCXX)
+set(CMAKE_VERBOSE_MAKEFILE TRUE)
+add_executable(main main.mm)
diff --git a/Tests/RunCMake/LinkerLauncher/OBJCXX-env-Build-stdout.txt b/Tests/RunCMake/LinkerLauncher/OBJCXX-env-Build-stdout.txt
new file mode 100644
index 0000000..3313e31
--- /dev/null
+++ b/Tests/RunCMake/LinkerLauncher/OBJCXX-env-Build-stdout.txt
@@ -0,0 +1 @@
+.*-E env USED_LAUNCHER=1.*
diff --git a/Tests/RunCMake/LinkerLauncher/OBJCXX-env.cmake b/Tests/RunCMake/LinkerLauncher/OBJCXX-env.cmake
new file mode 100644
index 0000000..3ed966d
--- /dev/null
+++ b/Tests/RunCMake/LinkerLauncher/OBJCXX-env.cmake
@@ -0,0 +1 @@
+include(OBJCXX-common.cmake)
diff --git a/Tests/RunCMake/LinkerLauncher/OBJCXX-launch-Build-stdout.txt b/Tests/RunCMake/LinkerLauncher/OBJCXX-launch-Build-stdout.txt
new file mode 100644
index 0000000..3313e31
--- /dev/null
+++ b/Tests/RunCMake/LinkerLauncher/OBJCXX-launch-Build-stdout.txt
@@ -0,0 +1 @@
+.*-E env USED_LAUNCHER=1.*
diff --git a/Tests/RunCMake/LinkerLauncher/OBJCXX-launch-env-Build-stdout.txt b/Tests/RunCMake/LinkerLauncher/OBJCXX-launch-env-Build-stdout.txt
new file mode 100644
index 0000000..3313e31
--- /dev/null
+++ b/Tests/RunCMake/LinkerLauncher/OBJCXX-launch-env-Build-stdout.txt
@@ -0,0 +1 @@
+.*-E env USED_LAUNCHER=1.*
diff --git a/Tests/RunCMake/LinkerLauncher/OBJCXX-launch-env.cmake b/Tests/RunCMake/LinkerLauncher/OBJCXX-launch-env.cmake
new file mode 100644
index 0000000..04c916a
--- /dev/null
+++ b/Tests/RunCMake/LinkerLauncher/OBJCXX-launch-env.cmake
@@ -0,0 +1,3 @@
+set(CTEST_USE_LAUNCHERS 1)
+include(CTestUseLaunchers)
+include(OBJCXX-env.cmake)
diff --git a/Tests/RunCMake/LinkerLauncher/OBJCXX-launch.cmake b/Tests/RunCMake/LinkerLauncher/OBJCXX-launch.cmake
new file mode 100644
index 0000000..5a54bff
--- /dev/null
+++ b/Tests/RunCMake/LinkerLauncher/OBJCXX-launch.cmake
@@ -0,0 +1,3 @@
+set(CTEST_USE_LAUNCHERS 1)
+include(CTestUseLaunchers)
+include(OBJCXX.cmake)
diff --git a/Tests/RunCMake/LinkerLauncher/OBJCXX.cmake b/Tests/RunCMake/LinkerLauncher/OBJCXX.cmake
new file mode 100644
index 0000000..3667745
--- /dev/null
+++ b/Tests/RunCMake/LinkerLauncher/OBJCXX.cmake
@@ -0,0 +1,2 @@
+set(CMAKE_OBJCXX_LINKER_LAUNCHER "${CMAKE_COMMAND};-E;env;USED_LAUNCHER=1")
+include(OBJCXX-common.cmake)
diff --git a/Tests/RunCMake/LinkerLauncher/RunCMakeTest.cmake b/Tests/RunCMake/LinkerLauncher/RunCMakeTest.cmake
new file mode 100644
index 0000000..8f2bf63
--- /dev/null
+++ b/Tests/RunCMake/LinkerLauncher/RunCMakeTest.cmake
@@ -0,0 +1,37 @@
+include(RunCMake)
+
+function(run_linker_launcher lang)
+ # Preserve build tree so we can reuse it for the ${lang}-Build subtest below
+ set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${lang}-build)
+ set(RunCMake_TEST_NO_CLEAN 1)
+ file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+ file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+ run_cmake(${lang})
+
+ set(RunCMake_TEST_OUTPUT_MERGE 1)
+ if("${RunCMake_GENERATOR}" MATCHES "Ninja")
+ set(verbose_args -- -v)
+ endif()
+ run_cmake_command(${lang}-Build ${CMAKE_COMMAND} --build . ${verbose_args})
+endfunction()
+
+function(run_linker_launcher_env lang)
+ string(REGEX REPLACE "-.*" "" core_lang "${lang}")
+ set(ENV{CMAKE_${core_lang}_LINKER_LAUNCHER} "${CMAKE_COMMAND};-E;env;USED_LAUNCHER=1")
+ run_linker_launcher(${lang})
+ unset(ENV{CMAKE_${core_lang}_LINKER_LAUNCHER})
+endfunction()
+
+set(langs C CXX)
+if(CMake_TEST_OBJC)
+ list(APPEND langs OBJC OBJCXX)
+endif()
+
+foreach(lang ${langs})
+ run_linker_launcher(${lang})
+ run_linker_launcher_env(${lang}-env)
+ if(NOT RunCMake_GENERATOR STREQUAL "Watcom WMake")
+ run_linker_launcher(${lang}-launch)
+ run_linker_launcher_env(${lang}-launch-env)
+ endif()
+endforeach()
diff --git a/Tests/RunCMake/LinkerLauncher/main.c b/Tests/RunCMake/LinkerLauncher/main.c
new file mode 100644
index 0000000..8488f4e
--- /dev/null
+++ b/Tests/RunCMake/LinkerLauncher/main.c
@@ -0,0 +1,4 @@
+int main(void)
+{
+ return 0;
+}
diff --git a/Tests/RunCMake/LinkerLauncher/main.cxx b/Tests/RunCMake/LinkerLauncher/main.cxx
new file mode 100644
index 0000000..f8b643a
--- /dev/null
+++ b/Tests/RunCMake/LinkerLauncher/main.cxx
@@ -0,0 +1,4 @@
+int main()
+{
+ return 0;
+}
diff --git a/Tests/RunCMake/LinkerLauncher/main.m b/Tests/RunCMake/LinkerLauncher/main.m
new file mode 100644
index 0000000..8488f4e
--- /dev/null
+++ b/Tests/RunCMake/LinkerLauncher/main.m
@@ -0,0 +1,4 @@
+int main(void)
+{
+ return 0;
+}
diff --git a/Tests/RunCMake/LinkerLauncher/main.mm b/Tests/RunCMake/LinkerLauncher/main.mm
new file mode 100644
index 0000000..f8b643a
--- /dev/null
+++ b/Tests/RunCMake/LinkerLauncher/main.mm
@@ -0,0 +1,4 @@
+int main()
+{
+ return 0;
+}
diff --git a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/RunCMakeTest.cmake b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/RunCMakeTest.cmake
index 763d57c..c71b9ba 100644
--- a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/RunCMakeTest.cmake
+++ b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/RunCMakeTest.cmake
@@ -11,7 +11,26 @@ function(run_install_test case)
run_cmake_command(${case}-build ${CMAKE_COMMAND} --build . --config Debug)
# Check "all" components.
set(CMAKE_INSTALL_PREFIX ${RunCMake_TEST_BINARY_DIR}/root-all)
- run_cmake_command(${case}-all ${CMAKE_COMMAND} -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX} -DBUILD_TYPE=Debug -P cmake_install.cmake)
+ run_cmake_command(${case}-all ${CMAKE_COMMAND} --install . --prefix ${CMAKE_INSTALL_PREFIX} --config Debug)
+endfunction()
+
+# Function to check the contents of the output files.
+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()
if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
@@ -20,6 +39,7 @@ if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
run_install_test(macos-unresolved)
run_install_test(macos-conflict)
run_install_test(macos-notfile)
+ run_install_test(file-filter)
endif()
run_cmake(project)
run_cmake(badargs1)
@@ -29,6 +49,7 @@ elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
run_install_test(windows-unresolved)
run_install_test(windows-conflict)
run_install_test(windows-notfile)
+ run_install_test(file-filter)
run_cmake(project)
run_cmake(badargs1)
run_cmake(badargs2)
@@ -41,6 +62,7 @@ elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux")
if(NOT CMAKE_C_COMPILER_ID MATCHES "^XL")
run_install_test(linux)
+ run_install_test(file-filter)
endif()
run_install_test(linux-unresolved)
run_install_test(linux-conflict)
diff --git a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/badargs2.cmake b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/badargs2.cmake
index ac6af85..f80829d 100644
--- a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/badargs2.cmake
+++ b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/badargs2.cmake
@@ -11,5 +11,7 @@ file(GET_RUNTIME_DEPENDENCIES
PRE_EXCLUDE_REGEXES
POST_INCLUDE_REGEXES
POST_EXCLUDE_REGEXES
+ POST_INCLUDE_FILES
+ POST_EXCLUDE_FILES
)
message(FATAL_ERROR "This message should not be displayed")
diff --git a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/file-filter-all-check.cmake b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/file-filter-all-check.cmake
new file mode 100644
index 0000000..9622f87
--- /dev/null
+++ b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/file-filter-all-check.cmake
@@ -0,0 +1,28 @@
+if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux")
+ set(_check
+ [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/file-filter-build/root-all/bin/\.\./lib/libdep1\.so]]
+ [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/file-filter-build/root-all/bin/\.\./lib/libdep2\.so]]
+ [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/file-filter-build/root-all/bin/\.\./lib/libdep3\.so]]
+ [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/file-filter-build/root-all/bin/\.\./lib/libdep4\.so]]
+ )
+ check_contents(deps/deps.txt "^${_check}$")
+elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
+ set(_check
+ [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/file-filter-build/root-all/bin/\.\./lib/libdep1\.dylib]]
+ [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/file-filter-build/root-all/bin/\.\./lib/libdep2\.dylib]]
+ [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/file-filter-build/root-all/bin/\.\./lib/libdep3\.dylib]]
+ [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/file-filter-build/root-all/bin/\.\./lib/libdep4\.dylib]]
+ )
+ check_contents(deps/deps.txt "^${_check}$")
+elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
+ set(_check
+ [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/file-filter-build/root-all/bin/(lib)?dep1\.dll]]
+ [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/file-filter-build/root-all/bin/(lib)?dep2\.dll]]
+ [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/file-filter-build/root-all/bin/(lib)?dep3\.dll]]
+ [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/file-filter-build/root-all/bin/(lib)?dep4\.dll]]
+ )
+ check_contents(deps/deps.txt "^${_check}$")
+endif()
+
+check_contents(deps/udeps.txt "^$")
+check_contents(deps/cdeps.txt "^$")
diff --git a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/file-filter.cmake b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/file-filter.cmake
new file mode 100644
index 0000000..fef084b
--- /dev/null
+++ b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/file-filter.cmake
@@ -0,0 +1,104 @@
+enable_language(C)
+
+set(dep_list)
+set(import_list)
+set(call_list)
+foreach(i 1 2 3 4 5 6 7 8 9)
+ file(WRITE "${CMAKE_BINARY_DIR}/dep${i}.c"
+"#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ void dep${i}(void)
+{
+}
+")
+ add_library(dep${i} SHARED "${CMAKE_BINARY_DIR}/dep${i}.c")
+ list(APPEND dep_list dep${i})
+ string(APPEND import_list "EXE_IMPORT extern void dep${i}(void);\n")
+ string(APPEND call_list " dep${i}();\n")
+endforeach()
+set_target_properties(dep5 PROPERTIES
+ VERSION 1.2.3
+ SOVERSION 1
+ )
+
+file(WRITE "${CMAKE_BINARY_DIR}/main.c"
+"#ifdef _WIN32
+# define EXE_IMPORT __declspec(dllimport)
+#else
+# define EXE_IMPORT
+#endif
+
+${import_list}
+int main(void)
+{
+${call_list}
+ return 0;
+}
+")
+
+add_executable(exe "${CMAKE_BINARY_DIR}/main.c")
+target_link_libraries(exe PRIVATE ${dep_list})
+
+if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
+ set_property(TARGET exe PROPERTY INSTALL_RPATH "\${ORIGIN}/../lib")
+elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
+ set_property(TARGET exe PROPERTY INSTALL_RPATH "@loader_path/../lib")
+endif()
+
+install(TARGETS exe ${dep_list})
+
+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 "dep[123456789]"
+ PRE_EXCLUDE_REGEXES ".*"
+ POST_INCLUDE_REGEXES "dep9"
+ POST_INCLUDE_FILES
+ "${CMAKE_INSTALL_PREFIX}/bin/$<TARGET_FILE_NAME:dep1>"
+ "${CMAKE_INSTALL_PREFIX}/lib/$<TARGET_FILE_NAME:dep1>"
+ "${CMAKE_INSTALL_PREFIX}/bin/../bin/$<TARGET_FILE_NAME:dep2>"
+ "${CMAKE_INSTALL_PREFIX}/bin/../lib/$<TARGET_FILE_NAME:dep2>"
+ "${CMAKE_INSTALL_PREFIX}/bin/$<TARGET_FILE_NAME:dep3>"
+ "${CMAKE_INSTALL_PREFIX}/lib/$<TARGET_FILE_NAME:dep3>"
+ "${CMAKE_INSTALL_PREFIX}/bin/$<TARGET_FILE_NAME:dep8>"
+ "${CMAKE_INSTALL_PREFIX}/lib/$<TARGET_FILE_NAME:dep8>"
+ POST_EXCLUDE_FILES
+ "${CMAKE_INSTALL_PREFIX}/bin/$<TARGET_FILE_NAME:dep3>"
+ "${CMAKE_INSTALL_PREFIX}/lib/$<TARGET_FILE_NAME:dep3>"
+ "${CMAKE_INSTALL_PREFIX}/bin/$<TARGET_FILE_NAME:dep5>"
+ "${CMAKE_INSTALL_PREFIX}/lib/$<TARGET_FILE_NAME:dep5>"
+ "${CMAKE_INSTALL_PREFIX}/bin/$<TARGET_FILE_NAME:dep6>"
+ "${CMAKE_INSTALL_PREFIX}/lib/$<TARGET_FILE_NAME:dep6>"
+ "${CMAKE_INSTALL_PREFIX}/bin/../bin/$<TARGET_FILE_NAME:dep7>"
+ "${CMAKE_INSTALL_PREFIX}/bin/../lib/$<TARGET_FILE_NAME:dep7>"
+ POST_EXCLUDE_FILES_STRICT
+ "${CMAKE_INSTALL_PREFIX}/bin/$<TARGET_FILE_NAME:dep8>"
+ "${CMAKE_INSTALL_PREFIX}/lib/$<TARGET_FILE_NAME:dep8>"
+ "${CMAKE_INSTALL_PREFIX}/bin/$<TARGET_FILE_NAME:dep9>"
+ "${CMAKE_INSTALL_PREFIX}/lib/$<TARGET_FILE_NAME:dep9>"
+ ${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(
+ deps.txt udeps.txt cdeps.txt
+ EXECUTABLES
+ "${CMAKE_INSTALL_PREFIX}/bin/$<TARGET_FILE_NAME:exe>"
+ )
+ ]])
diff --git a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux-all-check.cmake b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux-all-check.cmake
index 381b602..d3d1cd6 100644
--- a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux-all-check.cmake
+++ b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux-all-check.cmake
@@ -1,21 +1,3 @@
-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/file-GET_RUNTIME_DEPENDENCIES/linux-build/root-all/lib/libtest_rpath\.so]]
[[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux-build/root-all/lib/libtest_runpath\.so]]
diff --git a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-all-check.cmake b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-all-check.cmake
index e7cdbf6..e9ff9f6 100644
--- a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-all-check.cmake
+++ b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-all-check.cmake
@@ -1,21 +1,3 @@
-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()
-
function(set_with_libsystem var)
set(_tmp "${ARGN}")
if(EXISTS "/usr/lib/libSystem.B.dylib")
diff --git a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-all-check.cmake b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-all-check.cmake
index f1d70a1..cb0e534 100644
--- a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-all-check.cmake
+++ b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-all-check.cmake
@@ -1,21 +1,3 @@
-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/file-GET_RUNTIME_DEPENDENCIES/windows-build/root-all/bin/\.conflict/\.\./(lib)?libdir\.dll]=]
[=[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-build/root-all/bin/\.search/(lib)?search\.dll]=]
diff --git a/bootstrap b/bootstrap
index aefd210..911558d 100755
--- a/bootstrap
+++ b/bootstrap
@@ -387,6 +387,7 @@ CMAKE_CXX_SOURCES="\
cmInstallFilesCommand \
cmInstallFilesGenerator \
cmInstallGenerator \
+ cmInstallImportedRuntimeArtifactsGenerator \
cmInstallScriptGenerator \
cmInstallSubdirectoryGenerator \
cmInstallTargetGenerator \