diff options
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 = + [®exMatch]( + 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 = + [®exMatch]( + 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]=] @@ -387,6 +387,7 @@ CMAKE_CXX_SOURCES="\ cmInstallFilesCommand \ cmInstallFilesGenerator \ cmInstallGenerator \ + cmInstallImportedRuntimeArtifactsGenerator \ cmInstallScriptGenerator \ cmInstallSubdirectoryGenerator \ cmInstallTargetGenerator \ |