summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc Chevrier <marc.chevrier@gmail.com>2023-02-01 17:58:30 +0100
committerMarc Chevrier <marc.chevrier@gmail.com>2023-03-01 12:23:28 +0100
commitede33f30cfef9e03ecccdb9ce4c7fdf1e8208d75 (patch)
tree338052612b36c9394f6f0ad71bab57109cf60957
parentfcbd723a5085c11c57ec966f8aea605a55d0bdd5 (diff)
downloadcmake-ede33f30cfef9e03ecccdb9ce4c7fdf1e8208d75.tar.gz
Apple: Handle generation and comsuption of text-based stubs (.tbd files)
Fixes: #24123
-rw-r--r--Help/command/install.rst18
-rw-r--r--Help/manual/cmake-buildsystem.7.rst4
-rw-r--r--Help/manual/cmake-generator-expressions.7.rst251
-rw-r--r--Help/manual/cmake-variables.7.rst2
-rw-r--r--Help/prop_tgt/ARCHIVE_OUTPUT_DIRECTORY.rst3
-rw-r--r--Help/prop_tgt/ARCHIVE_OUTPUT_NAME.rst3
-rw-r--r--Help/prop_tgt/ENABLE_EXPORTS.rst29
-rw-r--r--Help/prop_tgt/IMPORTED_IMPLIB.rst14
-rw-r--r--Help/prop_tgt/IMPORTED_LOCATION.rst2
-rw-r--r--Help/prop_tgt/MACOS_IMPORT_FILES.txt12
-rw-r--r--Help/release/dev/Apple-tbd-files-management.rst6
-rw-r--r--Help/variable/CMAKE_ENABLE_EXPORTS.rst4
-rw-r--r--Help/variable/CMAKE_EXECUTABLE_ENABLE_EXPORTS.rst12
-rw-r--r--Help/variable/CMAKE_SHARED_LIBRARY_ENABLE_EXPORTS.rst10
-rw-r--r--Modules/CMakeASMCompiler.cmake.in1
-rw-r--r--Modules/CMakeCCompiler.cmake.in1
-rw-r--r--Modules/CMakeCXXCompiler.cmake.in1
-rw-r--r--Modules/CMakeFindBinUtils.cmake17
-rw-r--r--Modules/CMakeFortranCompiler.cmake.in1
-rw-r--r--Modules/CMakeHIPCompiler.cmake.in1
-rw-r--r--Modules/CMakeOBJCCompiler.cmake.in1
-rw-r--r--Modules/CMakeOBJCXXCompiler.cmake.in1
-rw-r--r--Modules/Platform/Darwin.cmake5
-rw-r--r--Source/cmCommonTargetGenerator.cxx1
-rw-r--r--Source/cmCoreTryCompile.cxx6
-rw-r--r--Source/cmExportBuildFileGenerator.cxx2
-rw-r--r--Source/cmExportFileGenerator.cxx3
-rw-r--r--Source/cmExportInstallFileGenerator.cxx15
-rw-r--r--Source/cmGeneratorExpressionNode.cxx370
-rw-r--r--Source/cmGeneratorTarget.cxx138
-rw-r--r--Source/cmGeneratorTarget.h14
-rw-r--r--Source/cmGlobalNinjaGenerator.cxx4
-rw-r--r--Source/cmGlobalXCodeGenerator.cxx29
-rw-r--r--Source/cmInstallCommand.cxx73
-rw-r--r--Source/cmInstallTargetGenerator.cxx185
-rw-r--r--Source/cmInstallTargetGenerator.h8
-rw-r--r--Source/cmLocalGenerator.cxx8
-rw-r--r--Source/cmMakefile.cxx5
-rw-r--r--Source/cmMakefile.h4
-rw-r--r--Source/cmMakefileLibraryTargetGenerator.cxx102
-rw-r--r--Source/cmNinjaNormalTargetGenerator.cxx104
-rw-r--r--Source/cmNinjaNormalTargetGenerator.h1
-rw-r--r--Source/cmOSXBundleGenerator.cxx14
-rw-r--r--Source/cmOSXBundleGenerator.h11
-rw-r--r--Source/cmTarget.cxx39
-rw-r--r--Source/cmTarget.h4
-rw-r--r--Tests/RunCMake/AppleTextStubs/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/AppleTextStubs/Framework-export.cmake12
-rw-r--r--Tests/RunCMake/AppleTextStubs/Framework-import.cmake62
-rw-r--r--Tests/RunCMake/AppleTextStubs/Framework-install-check.cmake1
-rw-r--r--Tests/RunCMake/AppleTextStubs/Framework.cmake59
-rw-r--r--Tests/RunCMake/AppleTextStubs/Library-export.cmake12
-rw-r--r--Tests/RunCMake/AppleTextStubs/Library-import.cmake54
-rw-r--r--Tests/RunCMake/AppleTextStubs/LibraryWithOutputs-install-check.cmake1
-rw-r--r--Tests/RunCMake/AppleTextStubs/LibraryWithOutputs.cmake52
-rw-r--r--Tests/RunCMake/AppleTextStubs/LibraryWithVersions-install-check.cmake1
-rw-r--r--Tests/RunCMake/AppleTextStubs/LibraryWithVersions.cmake96
-rw-r--r--Tests/RunCMake/AppleTextStubs/RunCMakeTest.cmake58
-rw-r--r--Tests/RunCMake/AppleTextStubs/Simple-install-check.cmake1
-rw-r--r--Tests/RunCMake/AppleTextStubs/Simple.cmake41
-rw-r--r--Tests/RunCMake/AppleTextStubs/foo-config.cmake.in1
-rw-r--r--Tests/RunCMake/AppleTextStubs/foo.c5
-rw-r--r--Tests/RunCMake/AppleTextStubs/main.c7
-rw-r--r--Tests/RunCMake/CMakeLists.txt2
-rw-r--r--Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/RunCMakeTest.cmake21
-rw-r--r--Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_IMPORT_FILE-check.cmake1
-rw-r--r--Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_IMPORT_FILE.cmake47
-rw-r--r--Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_IMPORT_FILE_SUFFIX-check.cmake1
-rw-r--r--Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_IMPORT_FILE_SUFFIX.cmake44
-rw-r--r--Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_LINKER_IMPORT_FILE-non-valid-target-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_LINKER_IMPORT_FILE-non-valid-target-stderr.txt9
-rw-r--r--Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_LINKER_IMPORT_FILE-non-valid-target.cmake9
-rw-r--r--Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_LINKER_LIBRARY_FILE-non-valid-target-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_LINKER_LIBRARY_FILE-non-valid-target-stderr.txt9
-rw-r--r--Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_LINKER_LIBRARY_FILE-non-valid-target.cmake9
-rw-r--r--Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_SONAME_IMPORT_FILE-check.cmake1
-rw-r--r--Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_SONAME_IMPORT_FILE-non-valid-target-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_SONAME_IMPORT_FILE-non-valid-target-stderr.txt8
-rw-r--r--Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_SONAME_IMPORT_FILE-non-valid-target.cmake8
-rw-r--r--Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_SONAME_IMPORT_FILE.cmake32
-rw-r--r--Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/empty.c0
-rw-r--r--Tests/RunCMake/install/TARGETS-NAMELINK_COMPONENT-bad-all-stderr.txt5
-rw-r--r--Tests/RunCMake/install/TARGETS-NAMELINK_COMPONENT-bad-exc-stderr.txt5
84 files changed, 2054 insertions, 168 deletions
diff --git a/Help/command/install.rst b/Help/command/install.rst
index 126888aa7a..d5092ae12e 100644
--- a/Help/command/install.rst
+++ b/Help/command/install.rst
@@ -158,6 +158,9 @@ that may be installed:
``.lib``, in contrast to the ``.dll`` libraries that go to ``RUNTIME``);
* On AIX, the *linker import file* created for executables with
:prop_tgt:`ENABLE_EXPORTS` enabled.
+ * On macOS, the *linker import file* created for shared libraries with
+ :prop_tgt:`ENABLE_EXPORTS` enabled (except when marked as ``FRAMEWORK``,
+ see below).
``LIBRARY``
Target artifacts of this kind include:
@@ -308,6 +311,11 @@ the following additional arguments:
value of ``COMPONENT``. It is an error to use this parameter outside of a
``LIBRARY`` block.
+ .. versionchanged:: 3.27
+ This parameter is also usable for an ``ARCHIVE`` block to manage
+ the linker import file created, on macOS, for shared libraries with
+ :prop_tgt:`ENABLE_EXPORTS` enabled.
+
Consider the following example:
.. code-block:: cmake
@@ -342,6 +350,11 @@ the following additional arguments:
option installs nothing. It is an error to use this parameter outside of a
``LIBRARY`` block.
+ .. versionchanged:: 3.27
+ This parameter is also usable for an ``ARCHIVE`` block to manage
+ the linker import file created, on macOS, for shared libraries with
+ :prop_tgt:`ENABLE_EXPORTS` enabled.
+
When ``NAMELINK_ONLY`` is given, either ``NAMELINK_COMPONENT`` or
``COMPONENT`` may be used to specify the installation component of the
namelink, but ``COMPONENT`` should generally be preferred.
@@ -355,6 +368,11 @@ the following additional arguments:
installs the library. It is an error to use this parameter outside of a
``LIBRARY`` block.
+ .. versionchanged:: 3.27
+ This parameter is also usable for an ``ARCHIVE`` block to manage
+ the linker import file created, on macOS, for shared libraries with
+ :prop_tgt:`ENABLE_EXPORTS` enabled.
+
If ``NAMELINK_SKIP`` is specified, ``NAMELINK_COMPONENT`` has no effect. It
is not recommended to use ``NAMELINK_SKIP`` in conjunction with
``NAMELINK_COMPONENT``.
diff --git a/Help/manual/cmake-buildsystem.7.rst b/Help/manual/cmake-buildsystem.7.rst
index b9d621bafa..9fdb26c1dd 100644
--- a/Help/manual/cmake-buildsystem.7.rst
+++ b/Help/manual/cmake-buildsystem.7.rst
@@ -797,6 +797,10 @@ An *archive* output artifact of a buildsystem target may be:
created by the :command:`add_executable` command when its
:prop_tgt:`ENABLE_EXPORTS` target property is set.
+* On macOS: the linker import file (e.g. ``.tbd``) of a shared library target
+ created by the :command:`add_library` command with the ``SHARED`` option and
+ when its :prop_tgt:`ENABLE_EXPORTS` target property is set.
+
The :prop_tgt:`ARCHIVE_OUTPUT_DIRECTORY` and :prop_tgt:`ARCHIVE_OUTPUT_NAME`
target properties may be used to control archive output artifact locations
and names in the build tree.
diff --git a/Help/manual/cmake-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst
index ae52ba1a4c..66ae6ae498 100644
--- a/Help/manual/cmake-generator-expressions.7.rst
+++ b/Help/manual/cmake-generator-expressions.7.rst
@@ -1503,6 +1503,76 @@ In the following, the phrase "the ``tgt`` filename" means the name of the
Note that ``tgt`` is not added as a dependency of the target this
expression is evaluated on (see policy :policy:`CMP0112`).
+.. genex:: $<TARGET_IMPORT_FILE:tgt>
+
+ .. versionadded:: 3.27
+
+ Full path to the linker import file. On DLL platforms, it would be the
+ ``.lib`` file. On AIX, for the executables, and on macOS, for the shared
+ libraries, it could be, respectively, the ``.imp`` or ``.tbd`` import file,
+ depending of the value of :prop_tgt:`ENABLE_EXPORTS` property.
+
+ An empty string is returned when there is no import file associated with the
+ target.
+
+.. genex:: $<TARGET_IMPORT_FILE_BASE_NAME:tgt>
+
+ .. versionadded:: 3.27
+
+ Base name of file linker import file of the target ``tgt`` without prefix and
+ suffix. For example, if target file name is ``libbase.tbd``, the base name is
+ ``base``.
+
+ See also the :prop_tgt:`OUTPUT_NAME` and :prop_tgt:`ARCHIVE_OUTPUT_NAME`
+ target properties and their configuration specific variants
+ :prop_tgt:`OUTPUT_NAME_<CONFIG>` and :prop_tgt:`ARCHIVE_OUTPUT_NAME_<CONFIG>`.
+
+ The :prop_tgt:`<CONFIG>_POSTFIX` and :prop_tgt:`DEBUG_POSTFIX` target
+ properties can also be considered.
+
+ Note that ``tgt`` is not added as a dependency of the target this
+ expression is evaluated on.
+
+.. genex:: $<TARGET_IMPORT_FILE_PREFIX:tgt>
+
+ .. versionadded:: 3.27
+
+ Prefix of the import file of the target ``tgt``.
+
+ See also the :prop_tgt:`IMPORT_PREFIX` target property.
+
+ Note that ``tgt`` is not added as a dependency of the target this
+ expression is evaluated on.
+
+.. genex:: $<TARGET_IMPORT_FILE_SUFFIX:tgt>
+
+ .. versionadded:: 3.27
+
+ Suffix of the import file of the target ``tgt``.
+
+ The suffix corresponds to the file extension (such as ".lib" or ".tbd").
+
+ See also the :prop_tgt:`IMPORT_SUFFIX` target property.
+
+ Note that ``tgt`` is not added as a dependency of the target this
+ expression is evaluated on.
+
+.. genex:: $<TARGET_IMPORT_FILE_NAME:tgt>
+
+ .. versionadded:: 3.27
+
+ Name of the import file of the target target ``tgt``.
+
+ Note that ``tgt`` is not added as a dependency of the target this
+ expression is evaluated on.
+
+.. genex:: $<TARGET_IMPORT_FILE_DIR:tgt>
+
+ Directory of the import file of the target ``tgt``.
+
+ Note that ``tgt`` is not added as a dependency of the target this
+ expression is evaluated on.
+
.. genex:: $<TARGET_LINKER_FILE:tgt>
File used when linking to the ``tgt`` target. This will usually
@@ -1510,13 +1580,22 @@ In the following, the phrase "the ``tgt`` filename" means the name of the
but for a shared library on DLL platforms, it would be the ``.lib``
import library associated with the DLL.
+ .. versionadded:: 3.27
+ On macOS, it could be the ``.tbd`` import file associated with the shared
+ library, depending of the value of :prop_tgt:`ENABLE_EXPORTS` property.
+
+ This generator expression is equivalent to
+ :genex:`$<TARGET_LINKER_LIBRARY_FILE>` or
+ :genex:`$<TARGET_LINKER_IMPORT_FILE>` generator expressions, depending of the
+ characteristics of the target and the platform.
+
.. genex:: $<TARGET_LINKER_FILE_BASE_NAME:tgt>
.. versionadded:: 3.15
Base name of file used to link the target ``tgt``, i.e.
- ``$<TARGET_LINKER_FILE_NAME:tgt>`` without prefix and suffix. For example,
- if target file name is ``libbase.a``, the base name is ``base``.
+ :genex:`$<TARGET_LINKER_FILE_NAME:tgt>` without prefix and suffix. For
+ example, if target file name is ``libbase.a``, the base name is ``base``.
See also the :prop_tgt:`OUTPUT_NAME`, :prop_tgt:`ARCHIVE_OUTPUT_NAME`,
and :prop_tgt:`LIBRARY_OUTPUT_NAME` target properties and their configuration
@@ -1570,9 +1649,151 @@ In the following, the phrase "the ``tgt`` filename" means the name of the
Note that ``tgt`` is not added as a dependency of the target this
expression is evaluated on (see policy :policy:`CMP0112`).
+.. genex:: $<TARGET_LINKER_LIBRARY_FILE:tgt>
+
+ .. versionadded:: 3.27
+
+ File used when linking o the ``tgt`` target is done using directly the
+ library, and not an import file. This will usually be the library that
+ ``tgt`` represents (``.a``, ``.so``, ``.dylib``). So, on DLL platforms, it
+ will be an empty string.
+
+.. genex:: $<TARGET_LINKER_LIBRARY_FILE_BASE_NAME:tgt>
+
+ .. versionadded:: 3.27
+
+ Base name of library file used to link the target ``tgt``, i.e.
+ :genex:`$<TARGET_LINKER_LIBRARY_FILE_NAME:tgt>` without prefix and suffix.
+ For example, if target file name is ``libbase.a``, the base name is ``base``.
+
+ See also the :prop_tgt:`OUTPUT_NAME`, :prop_tgt:`ARCHIVE_OUTPUT_NAME`,
+ and :prop_tgt:`LIBRARY_OUTPUT_NAME` target properties and their configuration
+ specific variants :prop_tgt:`OUTPUT_NAME_<CONFIG>`,
+ :prop_tgt:`ARCHIVE_OUTPUT_NAME_<CONFIG>` and
+ :prop_tgt:`LIBRARY_OUTPUT_NAME_<CONFIG>`.
+
+ The :prop_tgt:`<CONFIG>_POSTFIX` and :prop_tgt:`DEBUG_POSTFIX` target
+ properties can also be considered.
+
+ Note that ``tgt`` is not added as a dependency of the target this
+ expression is evaluated on.
+
+.. genex:: $<TARGET_LINKER_LIBRARY_FILE_PREFIX:tgt>
+
+ .. versionadded:: 3.27
+
+ Prefix of the library file used to link target ``tgt``.
+
+ See also the :prop_tgt:`PREFIX` target property.
+
+ Note that ``tgt`` is not added as a dependency of the target this
+ expression is evaluated on.
+
+.. genex:: $<TARGET_LINKER_LIBRARY_FILE_SUFFIX:tgt>
+
+ .. versionadded:: 3.27
+
+ Suffix of the library file used to link target ``tgt``.
+
+ The suffix corresponds to the file extension (such as ".a" or ".dylib").
+
+ See also the :prop_tgt:`SUFFIX` target property.
+
+ Note that ``tgt`` is not added as a dependency of the target this
+ expression is evaluated on.
+
+.. genex:: $<TARGET_LINKER_LIBRARY_FILE_NAME:tgt>
+
+ .. versionadded:: 3.27
+
+ Name of the library file used to link target ``tgt``.
+
+ Note that ``tgt`` is not added as a dependency of the target this
+ expression is evaluated on.
+
+.. genex:: $<TARGET_LINKER_LIBRARY_FILE_DIR:tgt>
+
+ .. versionadded:: 3.27
+
+ Directory of the library file used to link target ``tgt``.
+
+ Note that ``tgt`` is not added as a dependency of the target this
+ expression is evaluated on.
+
+.. genex:: $<TARGET_LINKER_IMPORT_FILE:tgt>
+
+ .. versionadded:: 3.27
+
+ File used when linking to the ``tgt`` target is done using an import
+ file. This will usually be the import file that ``tgt`` represents
+ (``.lib``, ``.tbd``). So, when no import file is involved in the link step,
+ an empty string is returned.
+
+.. genex:: $<TARGET_LINKER_IMPORT_FILE_BASE_NAME:tgt>
+
+ .. versionadded:: 3.27
+
+ Base name of the import file used to link the target ``tgt``, i.e.
+ :genex:`$<TARGET_LINKER_IMPORT_FILE_NAME:tgt>` without prefix and suffix.
+ For example, if target file name is ``libbase.tbd``, the base name is ``base``.
+
+ See also the :prop_tgt:`OUTPUT_NAME` and :prop_tgt:`ARCHIVE_OUTPUT_NAME`,
+ target properties and their configuration
+ specific variants :prop_tgt:`OUTPUT_NAME_<CONFIG>` and
+ :prop_tgt:`ARCHIVE_OUTPUT_NAME_<CONFIG>`.
+
+ The :prop_tgt:`<CONFIG>_POSTFIX` and :prop_tgt:`DEBUG_POSTFIX` target
+ properties can also be considered.
+
+ Note that ``tgt`` is not added as a dependency of the target this
+ expression is evaluated on.
+
+.. genex:: $<TARGET_LINKER_IMPORT_FILE_PREFIX:tgt>
+
+ .. versionadded:: 3.27
+
+ Prefix of the import file used to link target ``tgt``.
+
+ See also the :prop_tgt:`IMPORT_PREFIX` target property.
+
+ Note that ``tgt`` is not added as a dependency of the target this
+ expression is evaluated on.
+
+.. genex:: $<TARGET_LINKER_IMPORT_FILE_SUFFIX:tgt>
+
+ .. versionadded:: 3.27
+
+ Suffix of the import file used to link target ``tgt``.
+
+ The suffix corresponds to the file extension (such as ".lib" or ".tbd").
+
+ See also the :prop_tgt:`IMPORT_SUFFIX` target property.
+
+ Note that ``tgt`` is not added as a dependency of the target this
+ expression is evaluated on.
+
+.. genex:: $<TARGET_LINKER_IMPORT_FILE_NAME:tgt>
+
+ .. versionadded:: 3.27
+
+ Name of the import file used to link target ``tgt``.
+
+ Note that ``tgt`` is not added as a dependency of the target this
+ expression is evaluated on.
+
+.. genex:: $<TARGET_LINKER_IMPORT_FILE_DIR:tgt>
+
+ .. versionadded:: 3.27
+
+ Directory of the import file used to link target ``tgt``.
+
+ Note that ``tgt`` is not added as a dependency of the target this
+ expression is evaluated on.
+
.. genex:: $<TARGET_SONAME_FILE:tgt>
File with soname (``.so.3``) where ``tgt`` is the name of a target.
+
.. genex:: $<TARGET_SONAME_FILE_NAME:tgt>
Name of file with soname (``.so.3``).
@@ -1582,11 +1803,35 @@ In the following, the phrase "the ``tgt`` filename" means the name of the
.. genex:: $<TARGET_SONAME_FILE_DIR:tgt>
- Directory of with soname (``.so.3``).
+ Directory of file with soname (``.so.3``).
Note that ``tgt`` is not added as a dependency of the target this
expression is evaluated on (see policy :policy:`CMP0112`).
+.. genex:: $<TARGET_SONAME_IMPORT_FILE:tgt>
+
+ .. versionadded:: 3.27
+
+ Import file with soname (``.3.tbd``) where ``tgt`` is the name of a target.
+
+.. genex:: $<TARGET_SONAME_IMPORT_FILE_NAME:tgt>
+
+ .. versionadded:: 3.27
+
+ Name of the import file with soname (``.3.tbd``).
+
+ Note that ``tgt`` is not added as a dependency of the target this
+ expression is evaluated on.
+
+.. genex:: $<TARGET_SONAME_IMPORT_FILE_DIR:tgt>
+
+ .. versionadded:: 3.27
+
+ Directory of the import file with soname (``.3.tbd``).
+
+ Note that ``tgt`` is not added as a dependency of the target this
+ expression is evaluated on.
+
.. genex:: $<TARGET_PDB_FILE:tgt>
.. versionadded:: 3.1
diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst
index 0ba83636d4..05c173c300 100644
--- a/Help/manual/cmake-variables.7.rst
+++ b/Help/manual/cmake-variables.7.rst
@@ -428,6 +428,7 @@ Variables that Control the Build
/variable/CMAKE_DEPENDS_USE_COMPILER
/variable/CMAKE_DISABLE_PRECOMPILE_HEADERS
/variable/CMAKE_ENABLE_EXPORTS
+ /variable/CMAKE_EXECUTABLE_ENABLE_EXPORTS
/variable/CMAKE_EXE_LINKER_FLAGS
/variable/CMAKE_EXE_LINKER_FLAGS_CONFIG
/variable/CMAKE_EXE_LINKER_FLAGS_CONFIG_INIT
@@ -507,6 +508,7 @@ Variables that Control the Build
/variable/CMAKE_POSITION_INDEPENDENT_CODE
/variable/CMAKE_RUNTIME_OUTPUT_DIRECTORY
/variable/CMAKE_RUNTIME_OUTPUT_DIRECTORY_CONFIG
+ /variable/CMAKE_SHARED_LIBRARY_ENABLE_EXPORTS
/variable/CMAKE_SHARED_LINKER_FLAGS
/variable/CMAKE_SHARED_LINKER_FLAGS_CONFIG
/variable/CMAKE_SHARED_LINKER_FLAGS_CONFIG_INIT
diff --git a/Help/prop_tgt/ARCHIVE_OUTPUT_DIRECTORY.rst b/Help/prop_tgt/ARCHIVE_OUTPUT_DIRECTORY.rst
index 677e06df0f..abb627cdad 100644
--- a/Help/prop_tgt/ARCHIVE_OUTPUT_DIRECTORY.rst
+++ b/Help/prop_tgt/ARCHIVE_OUTPUT_DIRECTORY.rst
@@ -6,4 +6,7 @@ ARCHIVE_OUTPUT_DIRECTORY
.. |CMAKE_XXX_OUTPUT_DIRECTORY| replace:: :variable:`CMAKE_ARCHIVE_OUTPUT_DIRECTORY`
.. include:: XXX_OUTPUT_DIRECTORY.txt
+.. |IDEM| replace:: in the same directory
+.. include:: MACOS_IMPORT_FILES.txt
+
See also the :prop_tgt:`ARCHIVE_OUTPUT_DIRECTORY_<CONFIG>` target property.
diff --git a/Help/prop_tgt/ARCHIVE_OUTPUT_NAME.rst b/Help/prop_tgt/ARCHIVE_OUTPUT_NAME.rst
index 6150193739..1f1c4671f1 100644
--- a/Help/prop_tgt/ARCHIVE_OUTPUT_NAME.rst
+++ b/Help/prop_tgt/ARCHIVE_OUTPUT_NAME.rst
@@ -5,4 +5,7 @@ ARCHIVE_OUTPUT_NAME
.. |xxx| replace:: archive
.. include:: XXX_OUTPUT_NAME.txt
+.. |IDEM| replace:: with the same name
+.. include:: MACOS_IMPORT_FILES.txt
+
See also the :prop_tgt:`ARCHIVE_OUTPUT_NAME_<CONFIG>` target property.
diff --git a/Help/prop_tgt/ENABLE_EXPORTS.rst b/Help/prop_tgt/ENABLE_EXPORTS.rst
index 0b1064ab4e..3e9b285534 100644
--- a/Help/prop_tgt/ENABLE_EXPORTS.rst
+++ b/Help/prop_tgt/ENABLE_EXPORTS.rst
@@ -1,7 +1,7 @@
ENABLE_EXPORTS
--------------
-Specify whether an executable exports symbols for loadable modules.
+Specify whether an executable or a shared library exports symbols.
Normally an executable does not export any symbols because it is the
final program. It is possible for an executable to export symbols to
@@ -28,4 +28,29 @@ varies by platform:
automatically bind symbols when the module is loaded.
This property is initialized by the value of the variable
-:variable:`CMAKE_ENABLE_EXPORTS` if it is set when a target is created.
+:variable:`CMAKE_EXECUTABLE_ENABLE_EXPORTS` if it is set when an executable
+target is created.
+
+.. versionadded:: 3.27
+ On macOS, to link with a shared library (standard one as well as framework),
+ a linker import file (e.g. a text-based stubs file, with ``.tbd`` extension)
+ can be used instead of the shared library itself.
+
+The generation of these linker import files, as well as the consumption, is
+controlled by this property. When this property is set to true, CMake will
+generate a ``.tbd`` file for each shared library created by
+:command:`add_library` command. This allow other targets to use this ``.tbd``
+file to link to the library with the :command:`target_link_libraries`
+command.
+
+.. note::
+
+ For compatibility purpose, this property will be ignored if
+ :prop_tgt:`XCODE_ATTRIBUTE_GENERATE_TEXT_BASED_STUBS <XCODE_ATTRIBUTE_<an-attribute>>`
+ target property or the
+ :variable:`CMAKE_XCODE_ATTRIBUTE_GENERATE_TEXT_BASED_STUBS <CMAKE_XCODE_ATTRIBUTE_<an-attribute>>`
+ variable is set to ``NO``.
+
+This property is initialized by the value of the variable
+:variable:`CMAKE_SHARED_LIBRARY_ENABLE_EXPORTS` if it is set when a shared
+library target is created.
diff --git a/Help/prop_tgt/IMPORTED_IMPLIB.rst b/Help/prop_tgt/IMPORTED_IMPLIB.rst
index c8b6fde95c..77549f3729 100644
--- a/Help/prop_tgt/IMPORTED_IMPLIB.rst
+++ b/Help/prop_tgt/IMPORTED_IMPLIB.rst
@@ -3,7 +3,13 @@ IMPORTED_IMPLIB
Full path to the import library for an ``IMPORTED`` target.
-Set this to the location of the ``.lib`` part of a Windows DLL, or on
-AIX set it to an import file created for executables that export symbols
-(see the :prop_tgt:`ENABLE_EXPORTS` target property).
-Ignored for non-imported targets.
+This property may be set:
+
+* On DLL platforms, to the location of the ``.lib`` part of the DLL.
+* On AIX, to an import file (e.g. ``.imp``) created for executables that export
+ symbols (see the :prop_tgt:`ENABLE_EXPORTS` target property).
+* On macOS, to an import file (e.g. ``.tbd``) created for shared libraries (see
+ the :prop_tgt:`ENABLE_EXPORTS` target property). For frameworks this is the
+ location of the ``.tbd`` file symlink just inside the framework folder.
+
+This property is ignored for non-imported targets.
diff --git a/Help/prop_tgt/IMPORTED_LOCATION.rst b/Help/prop_tgt/IMPORTED_LOCATION.rst
index ddd910aafb..a7207d845b 100644
--- a/Help/prop_tgt/IMPORTED_LOCATION.rst
+++ b/Help/prop_tgt/IMPORTED_LOCATION.rst
@@ -27,5 +27,5 @@ selected and its :prop_tgt:`IMPORTED_LOCATION_<CONFIG>` value used.
To get the location of an imported target read one of the :prop_tgt:`LOCATION`
or ``LOCATION_<CONFIG>`` properties.
-For platforms with import libraries (e.g. Windows) see also
+For platforms with import libraries (e.g. Windows, AIX or macOS) see also
:prop_tgt:`IMPORTED_IMPLIB`.
diff --git a/Help/prop_tgt/MACOS_IMPORT_FILES.txt b/Help/prop_tgt/MACOS_IMPORT_FILES.txt
new file mode 100644
index 0000000000..3c98fc8ca8
--- /dev/null
+++ b/Help/prop_tgt/MACOS_IMPORT_FILES.txt
@@ -0,0 +1,12 @@
+.. note::
+
+ On macOS, this property will be ignored for the linker import files (e.g.
+ ``.tbd`` files, see :prop_tgt:`ENABLE_EXPORTS` property for details) when:
+
+ * The :prop_tgt:`FRAMEWORK` is set, because the framework layout cannot be
+ changed.
+ * The :generator:`Xcode` generator is used, due to the limitations and
+ constraints of the ``Xcode`` tool.
+
+ In both cases, the linker import files will be generated |IDEM| as the shared
+ library.
diff --git a/Help/release/dev/Apple-tbd-files-management.rst b/Help/release/dev/Apple-tbd-files-management.rst
new file mode 100644
index 0000000000..edcfe55436
--- /dev/null
+++ b/Help/release/dev/Apple-tbd-files-management.rst
@@ -0,0 +1,6 @@
+Apple-tbd-files-management
+--------------------------
+
+* Support for text-based stubs (i.e. ``.tbd`` files) was added on macOS
+ platform. This capability is managed through the :prop_tgt:`ENABLE_EXPORTS`
+ property.
diff --git a/Help/variable/CMAKE_ENABLE_EXPORTS.rst b/Help/variable/CMAKE_ENABLE_EXPORTS.rst
index 9f43de3fac..d2c5ed086e 100644
--- a/Help/variable/CMAKE_ENABLE_EXPORTS.rst
+++ b/Help/variable/CMAKE_ENABLE_EXPORTS.rst
@@ -8,3 +8,7 @@ Specify whether executables export symbols for loadable modules.
This variable is used to initialize the :prop_tgt:`ENABLE_EXPORTS` target
property for executable targets when they are created by calls to the
:command:`add_executable` command. See the property documentation for details.
+
+This command has been superseded by the
+:variable:`CMAKE_EXECUTABLE_ENABLE_EXPORTS` command. It is provided for
+compatibility with older CMake code.
diff --git a/Help/variable/CMAKE_EXECUTABLE_ENABLE_EXPORTS.rst b/Help/variable/CMAKE_EXECUTABLE_ENABLE_EXPORTS.rst
new file mode 100644
index 0000000000..aa6dda2219
--- /dev/null
+++ b/Help/variable/CMAKE_EXECUTABLE_ENABLE_EXPORTS.rst
@@ -0,0 +1,12 @@
+CMAKE_EXECUTABLE_ENABLE_EXPORTS
+-------------------------------
+
+.. versionadded:: 3.27
+
+Specify whether executables export symbols for loadable modules.
+
+This variable is used to initialize the :prop_tgt:`ENABLE_EXPORTS` target
+property for executable targets when they are created by calls to the
+:command:`add_executable` command. See the property documentation for details.
+
+This variable supersede the :variable:`CMAKE_ENABLE_EXPORTS` variable.
diff --git a/Help/variable/CMAKE_SHARED_LIBRARY_ENABLE_EXPORTS.rst b/Help/variable/CMAKE_SHARED_LIBRARY_ENABLE_EXPORTS.rst
new file mode 100644
index 0000000000..3e2c6df8f7
--- /dev/null
+++ b/Help/variable/CMAKE_SHARED_LIBRARY_ENABLE_EXPORTS.rst
@@ -0,0 +1,10 @@
+CMAKE_SHARED_LIBRARY_ENABLE_EXPORTS
+-----------------------------------
+
+.. versionadded:: 3.27
+
+Specify whether shared library generates an import file.
+
+This variable is used to initialize the :prop_tgt:`ENABLE_EXPORTS` target
+property for shared library targets when they are created by calls to the
+:command:`add_library` command. See the property documentation for details.
diff --git a/Modules/CMakeASMCompiler.cmake.in b/Modules/CMakeASMCompiler.cmake.in
index 3953b304b0..e300782aee 100644
--- a/Modules/CMakeASMCompiler.cmake.in
+++ b/Modules/CMakeASMCompiler.cmake.in
@@ -6,6 +6,7 @@ set(CMAKE_RANLIB "@CMAKE_RANLIB@")
set(CMAKE_ASM@ASM_DIALECT@_COMPILER_RANLIB "@_CMAKE_ASM_COMPILER_RANLIB@")
set(CMAKE_LINKER "@CMAKE_LINKER@")
set(CMAKE_MT "@CMAKE_MT@")
+set(CMAKE_TAPI "@CMAKE_TAPI@")
set(CMAKE_ASM@ASM_DIALECT@_COMPILER_LOADED 1)
set(CMAKE_ASM@ASM_DIALECT@_COMPILER_ID "@_CMAKE_ASM_COMPILER_ID@")
set(CMAKE_ASM@ASM_DIALECT@_COMPILER_VERSION "@_CMAKE_ASM_COMPILER_VERSION@")
diff --git a/Modules/CMakeCCompiler.cmake.in b/Modules/CMakeCCompiler.cmake.in
index 2b24ff2aad..8ae07a34e1 100644
--- a/Modules/CMakeCCompiler.cmake.in
+++ b/Modules/CMakeCCompiler.cmake.in
@@ -27,6 +27,7 @@ set(CMAKE_RANLIB "@CMAKE_RANLIB@")
set(CMAKE_C_COMPILER_RANLIB "@CMAKE_C_COMPILER_RANLIB@")
set(CMAKE_LINKER "@CMAKE_LINKER@")
set(CMAKE_MT "@CMAKE_MT@")
+set(CMAKE_TAPI "@CMAKE_TAPI@")
set(CMAKE_COMPILER_IS_GNUCC @CMAKE_COMPILER_IS_GNUCC@)
set(CMAKE_C_COMPILER_LOADED 1)
set(CMAKE_C_COMPILER_WORKS @CMAKE_C_COMPILER_WORKS@)
diff --git a/Modules/CMakeCXXCompiler.cmake.in b/Modules/CMakeCXXCompiler.cmake.in
index 534e96055f..dcfff6fb8f 100644
--- a/Modules/CMakeCXXCompiler.cmake.in
+++ b/Modules/CMakeCXXCompiler.cmake.in
@@ -28,6 +28,7 @@ set(CMAKE_RANLIB "@CMAKE_RANLIB@")
set(CMAKE_CXX_COMPILER_RANLIB "@CMAKE_CXX_COMPILER_RANLIB@")
set(CMAKE_LINKER "@CMAKE_LINKER@")
set(CMAKE_MT "@CMAKE_MT@")
+set(CMAKE_TAPI "@CMAKE_TAPI@")
set(CMAKE_COMPILER_IS_GNUCXX @CMAKE_COMPILER_IS_GNUCXX@)
set(CMAKE_CXX_COMPILER_LOADED 1)
set(CMAKE_CXX_COMPILER_WORKS @CMAKE_CXX_COMPILER_WORKS@)
diff --git a/Modules/CMakeFindBinUtils.cmake b/Modules/CMakeFindBinUtils.cmake
index 2ac8879923..190117c70a 100644
--- a/Modules/CMakeFindBinUtils.cmake
+++ b/Modules/CMakeFindBinUtils.cmake
@@ -165,6 +165,7 @@ else()
set(_CMAKE_READELF_NAMES "readelf")
set(_CMAKE_DLLTOOL_NAMES "dlltool")
set(_CMAKE_ADDR2LINE_NAMES "addr2line")
+ set(_CMAKE_TAPI_NAMES "tapi")
# Prepend toolchain-specific names.
if("${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" STREQUAL Clang)
@@ -201,7 +202,7 @@ else()
list(PREPEND _CMAKE_LINKER_NAMES "armlink")
endif()
- list(APPEND _CMAKE_TOOL_VARS AR RANLIB STRIP LINKER NM OBJDUMP OBJCOPY READELF DLLTOOL ADDR2LINE)
+ list(APPEND _CMAKE_TOOL_VARS AR RANLIB STRIP LINKER NM OBJDUMP OBJCOPY READELF DLLTOOL ADDR2LINE TAPI)
endif()
foreach(_CMAKE_TOOL IN LISTS _CMAKE_TOOL_VARS)
@@ -225,6 +226,20 @@ if(NOT CMAKE_RANLIB)
set(CMAKE_RANLIB : CACHE INTERNAL "noop for ranlib")
endif()
+if(NOT CMAKE_TAPI)
+ # try to pick-up from Apple toolchain
+ execute_process(COMMAND xcrun --find tapi
+ OUTPUT_VARIABLE _xcrun_out
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_QUIET
+ RESULT_VARIABLE _xcrun_failed)
+ if(NOT _xcrun_failed AND EXISTS "${_xcrun_out}")
+ set_property(CACHE CMAKE_TAPI PROPERTY VALUE "${_xcrun_out}")
+ endif()
+ unset(_xcrun_out)
+ unset(_xcrun_failed)
+endif()
+
if(CMAKE_PLATFORM_HAS_INSTALLNAME)
find_program(CMAKE_INSTALL_NAME_TOOL NAMES ${_CMAKE_TOOLCHAIN_PREFIX}install_name_tool HINTS ${_CMAKE_TOOLCHAIN_LOCATION} NO_CMAKE_PATH NO_CMAKE_ENVIRONMENT_PATH)
diff --git a/Modules/CMakeFortranCompiler.cmake.in b/Modules/CMakeFortranCompiler.cmake.in
index f52ad02bb2..b8b409a5f4 100644
--- a/Modules/CMakeFortranCompiler.cmake.in
+++ b/Modules/CMakeFortranCompiler.cmake.in
@@ -14,6 +14,7 @@ set(CMAKE_Fortran_SIMULATE_VERSION "@CMAKE_Fortran_SIMULATE_VERSION@")
set(CMAKE_AR "@CMAKE_AR@")
set(CMAKE_Fortran_COMPILER_AR "@CMAKE_Fortran_COMPILER_AR@")
set(CMAKE_RANLIB "@CMAKE_RANLIB@")
+set(CMAKE_TAPI "@CMAKE_TAPI@")
set(CMAKE_Fortran_COMPILER_RANLIB "@CMAKE_Fortran_COMPILER_RANLIB@")
set(CMAKE_COMPILER_IS_GNUG77 @CMAKE_COMPILER_IS_GNUG77@)
set(CMAKE_Fortran_COMPILER_LOADED 1)
diff --git a/Modules/CMakeHIPCompiler.cmake.in b/Modules/CMakeHIPCompiler.cmake.in
index ce4e2cf656..8a747c67d8 100644
--- a/Modules/CMakeHIPCompiler.cmake.in
+++ b/Modules/CMakeHIPCompiler.cmake.in
@@ -58,3 +58,4 @@ set(CMAKE_RANLIB "@CMAKE_RANLIB@")
set(CMAKE_HIP_COMPILER_RANLIB "@CMAKE_HIP_COMPILER_RANLIB@")
set(CMAKE_LINKER "@CMAKE_LINKER@")
set(CMAKE_MT "@CMAKE_MT@")
+set(CMAKE_TAPI "@CMAKE_TAPI@")
diff --git a/Modules/CMakeOBJCCompiler.cmake.in b/Modules/CMakeOBJCCompiler.cmake.in
index 36f6ec1505..ea11a7aa36 100644
--- a/Modules/CMakeOBJCCompiler.cmake.in
+++ b/Modules/CMakeOBJCCompiler.cmake.in
@@ -25,6 +25,7 @@ set(CMAKE_RANLIB "@CMAKE_RANLIB@")
set(CMAKE_OBJC_COMPILER_RANLIB "@CMAKE_OBJC_COMPILER_RANLIB@")
set(CMAKE_LINKER "@CMAKE_LINKER@")
set(CMAKE_MT "@CMAKE_MT@")
+set(CMAKE_TAPI "@CMAKE_TAPI@")
set(CMAKE_COMPILER_IS_GNUOBJC @CMAKE_COMPILER_IS_GNUOBJC@)
set(CMAKE_OBJC_COMPILER_LOADED 1)
set(CMAKE_OBJC_COMPILER_WORKS @CMAKE_OBJC_COMPILER_WORKS@)
diff --git a/Modules/CMakeOBJCXXCompiler.cmake.in b/Modules/CMakeOBJCXXCompiler.cmake.in
index 4f271003a5..5d0b381257 100644
--- a/Modules/CMakeOBJCXXCompiler.cmake.in
+++ b/Modules/CMakeOBJCXXCompiler.cmake.in
@@ -26,6 +26,7 @@ set(CMAKE_RANLIB "@CMAKE_RANLIB@")
set(CMAKE_OBJCXX_COMPILER_RANLIB "@CMAKE_OBJCXX_COMPILER_RANLIB@")
set(CMAKE_LINKER "@CMAKE_LINKER@")
set(CMAKE_MT "@CMAKE_MT@")
+set(CMAKE_TAPI "@CMAKE_TAPI@")
set(CMAKE_COMPILER_IS_GNUOBJCXX @CMAKE_COMPILER_IS_GNUOBJCXX@)
set(CMAKE_OBJCXX_COMPILER_LOADED 1)
set(CMAKE_OBJCXX_COMPILER_WORKS @CMAKE_OBJCXX_COMPILER_WORKS@)
diff --git a/Modules/Platform/Darwin.cmake b/Modules/Platform/Darwin.cmake
index ac2478bc77..a6c86f1303 100644
--- a/Modules/Platform/Darwin.cmake
+++ b/Modules/Platform/Darwin.cmake
@@ -45,6 +45,8 @@ set(CMAKE_SHARED_LIBRARY_SUFFIX ".dylib")
set(CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES ".tbd" ".so")
set(CMAKE_SHARED_MODULE_PREFIX "lib")
set(CMAKE_SHARED_MODULE_SUFFIX ".so")
+set(CMAKE_APPLE_IMPORT_FILE_PREFIX "lib")
+set(CMAKE_APPLE_IMPORT_FILE_SUFFIX ".tbd")
set(CMAKE_MODULE_EXISTS 1)
set(CMAKE_DL_LIBS "")
if(NOT "${_CURRENT_OSX_VERSION}" VERSION_LESS "10.5")
@@ -108,6 +110,9 @@ foreach(lang C CXX Fortran OBJC OBJCXX)
set(CMAKE_${lang}_FRAMEWORK_SEARCH_FLAG -F)
endforeach()
+# To generate text-based stubs
+set(CMAKE_CREATE_TEXT_STUBS "<CMAKE_TAPI> stubify -isysroot <CMAKE_OSX_SYSROOT> -o <TARGET_IMPLIB> <TARGET>")
+
# Defines LINK_LIBRARY features for frameworks
set(CMAKE_LINK_LIBRARY_USING_FRAMEWORK "LINKER:-framework,<LIBRARY>")
set(CMAKE_LINK_LIBRARY_USING_FRAMEWORK_SUPPORTED TRUE)
diff --git a/Source/cmCommonTargetGenerator.cxx b/Source/cmCommonTargetGenerator.cxx
index 59448a4154..5601bf2bc1 100644
--- a/Source/cmCommonTargetGenerator.cxx
+++ b/Source/cmCommonTargetGenerator.cxx
@@ -25,7 +25,6 @@
#include "cmState.h"
#include "cmStateTypes.h"
#include "cmStringAlgorithms.h"
-#include "cmTarget.h"
#include "cmValue.h"
cmCommonTargetGenerator::cmCommonTargetGenerator(cmGeneratorTarget* gt)
diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx
index acf1c206be..3149ccfa9c 100644
--- a/Source/cmCoreTryCompile.cxx
+++ b/Source/cmCoreTryCompile.cxx
@@ -72,6 +72,10 @@ SETUP_LANGUAGE(swift_properties, Swift);
std::string const kCMAKE_CUDA_ARCHITECTURES = "CMAKE_CUDA_ARCHITECTURES";
std::string const kCMAKE_CUDA_RUNTIME_LIBRARY = "CMAKE_CUDA_RUNTIME_LIBRARY";
std::string const kCMAKE_ENABLE_EXPORTS = "CMAKE_ENABLE_EXPORTS";
+std::string const kCMAKE_EXECUTABLE_ENABLE_EXPORTS =
+ "CMAKE_EXECUTABLE_ENABLE_EXPORTS";
+std::string const kCMAKE_SHARED_LIBRARY_ENABLE_EXPORTS =
+ "CMAKE_SHARED_LIBRARY_ENABLE_EXPORTS";
std::string const kCMAKE_HIP_ARCHITECTURES = "CMAKE_HIP_ARCHITECTURES";
std::string const kCMAKE_HIP_RUNTIME_LIBRARY = "CMAKE_HIP_RUNTIME_LIBRARY";
std::string const kCMAKE_ISPC_INSTRUCTION_SETS = "CMAKE_ISPC_INSTRUCTION_SETS";
@@ -997,6 +1001,8 @@ cm::optional<cmTryCompileResult> cmCoreTryCompile::TryCompileCode(
vars.insert(kCMAKE_CUDA_ARCHITECTURES);
vars.insert(kCMAKE_CUDA_RUNTIME_LIBRARY);
vars.insert(kCMAKE_ENABLE_EXPORTS);
+ vars.insert(kCMAKE_EXECUTABLE_ENABLE_EXPORTS);
+ vars.insert(kCMAKE_SHARED_LIBRARY_ENABLE_EXPORTS);
vars.insert(kCMAKE_HIP_ARCHITECTURES);
vars.insert(kCMAKE_HIP_RUNTIME_LIBRARY);
vars.insert(kCMAKE_ISPC_INSTRUCTION_SETS);
diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx
index ed199ea5d3..caf8ac213e 100644
--- a/Source/cmExportBuildFileGenerator.cxx
+++ b/Source/cmExportBuildFileGenerator.cxx
@@ -254,7 +254,7 @@ void cmExportBuildFileGenerator::SetImportLocationProperty(
if (target->HasImportLibrary(config)) {
std::string prop = cmStrCat("IMPORTED_IMPLIB", suffix);
std::string value =
- target->GetFullPath(config, cmStateEnums::ImportLibraryArtifact);
+ target->GetFullPath(config, cmStateEnums::ImportLibraryArtifact, true);
if (mf->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX")) {
target->GetImplibGNUtoMS(config, value, value,
"${CMAKE_IMPORT_LIBRARY_SUFFIX}");
diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx
index 7f1afba56f..6e7ef4e735 100644
--- a/Source/cmExportFileGenerator.cxx
+++ b/Source/cmExportFileGenerator.cxx
@@ -1063,7 +1063,8 @@ void cmExportFileGenerator::GenerateImportTargetCode(
}
// Mark the imported executable if it has exports.
- if (target->IsExecutableWithExports()) {
+ if (target->IsExecutableWithExports() ||
+ (target->IsSharedLibraryWithExports() && target->HasImportLibrary(""))) {
os << "set_property(TARGET " << targetName
<< " PROPERTY ENABLE_EXPORTS 1)\n";
}
diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx
index 5e190f490c..def822721f 100644
--- a/Source/cmExportInstallFileGenerator.cxx
+++ b/Source/cmExportInstallFileGenerator.cxx
@@ -409,7 +409,7 @@ void cmExportInstallFileGenerator::SetImportLocationProperty(
// Append the installed file name.
value += cmInstallTargetGenerator::GetInstallFilename(
- target, config, cmInstallTargetGenerator::NameImplib);
+ target, config, cmInstallTargetGenerator::NameImplibReal);
// Store the property.
properties[prop] = value;
@@ -430,6 +430,19 @@ void cmExportInstallFileGenerator::SetImportLocationProperty(
properties[prop] = cmJoin(objects, ";");
importedLocations.insert(prop);
} else {
+ if (target->IsFrameworkOnApple() && target->HasImportLibrary(config)) {
+ // store as well IMPLIB value
+ auto importProp = cmStrCat("IMPORTED_IMPLIB", suffix);
+ auto importValue =
+ cmStrCat(value,
+ cmInstallTargetGenerator::GetInstallFilename(
+ target, config, cmInstallTargetGenerator::NameImplibReal));
+
+ // Store the property.
+ properties[importProp] = importValue;
+ importedLocations.insert(importProp);
+ }
+
// Construct the property name.
std::string prop = cmStrCat("IMPORTED_LOCATION", suffix);
diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx
index 5c7d217010..2a01c9e8d1 100644
--- a/Source/cmGeneratorExpressionNode.cxx
+++ b/Source/cmGeneratorExpressionNode.cxx
@@ -2658,10 +2658,14 @@ static const struct InstallPrefixNode : public cmGeneratorExpressionNode
class ArtifactDirTag;
class ArtifactLinkerTag;
+class ArtifactLinkerLibraryTag;
+class ArtifactLinkerImportTag;
class ArtifactNameTag;
+class ArtifactImportTag;
class ArtifactPathTag;
class ArtifactPdbTag;
class ArtifactSonameTag;
+class ArtifactSonameImportTag;
class ArtifactBundleDirTag;
class ArtifactBundleDirNameTag;
class ArtifactBundleContentDirTag;
@@ -2771,6 +2775,38 @@ struct TargetFilesystemArtifactResultCreator<ArtifactSonameTag>
};
template <>
+struct TargetFilesystemArtifactResultCreator<ArtifactSonameImportTag>
+{
+ static std::string Create(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content)
+ {
+ // The target soname file (.so.1).
+ if (target->IsDLLPlatform()) {
+ ::reportError(context, content->GetOriginalExpression(),
+ "TARGET_SONAME_IMPORT_FILE is not allowed "
+ "for DLL target platforms.");
+ return std::string();
+ }
+ if (target->GetType() != cmStateEnums::SHARED_LIBRARY) {
+ ::reportError(context, content->GetOriginalExpression(),
+ "TARGET_SONAME_IMPORT_FILE is allowed only for "
+ "SHARED libraries.");
+ return std::string();
+ }
+
+ if (target->HasImportLibrary(context->Config)) {
+ return cmStrCat(target->GetDirectory(
+ context->Config, cmStateEnums::ImportLibraryArtifact),
+ '/',
+ target->GetSOName(context->Config,
+ cmStateEnums::ImportLibraryArtifact));
+ }
+ return std::string{};
+ }
+};
+
+template <>
struct TargetFilesystemArtifactResultCreator<ArtifactPdbTag>
{
static std::string Create(cmGeneratorTarget* target,
@@ -2817,7 +2853,8 @@ struct TargetFilesystemArtifactResultCreator<ArtifactLinkerTag>
cmGeneratorExpressionContext* context,
const GeneratorExpressionContent* content)
{
- // The file used to link to the target (.so, .lib, .a).
+ // The file used to link to the target (.so, .lib, .a) or import file
+ // (.lib, .tbd).
if (!target->IsLinkable()) {
::reportError(context, content->GetOriginalExpression(),
"TARGET_LINKER_FILE is allowed only for libraries and "
@@ -2833,6 +2870,55 @@ struct TargetFilesystemArtifactResultCreator<ArtifactLinkerTag>
};
template <>
+struct TargetFilesystemArtifactResultCreator<ArtifactLinkerLibraryTag>
+{
+ static std::string Create(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content)
+ {
+ // The file used to link to the target (.dylib, .so, .a).
+ if (!target->IsLinkable() ||
+ target->GetType() == cmStateEnums::EXECUTABLE) {
+ ::reportError(context, content->GetOriginalExpression(),
+ "TARGET_LINKER_LIBRARY_FILE is allowed only for libraries "
+ "with ENABLE_EXPORTS.");
+ return std::string();
+ }
+
+ if (!target->IsDLLPlatform() ||
+ target->GetType() == cmStateEnums::STATIC_LIBRARY) {
+ return target->GetFullPath(context->Config,
+ cmStateEnums::RuntimeBinaryArtifact);
+ }
+ return std::string{};
+ }
+};
+
+template <>
+struct TargetFilesystemArtifactResultCreator<ArtifactLinkerImportTag>
+{
+ static std::string Create(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content)
+ {
+ // The file used to link to the target (.lib, .tbd).
+ if (!target->IsLinkable()) {
+ ::reportError(
+ context, content->GetOriginalExpression(),
+ "TARGET_LINKER_IMPORT_FILE is allowed only for libraries and "
+ "executables with ENABLE_EXPORTS.");
+ return std::string();
+ }
+
+ if (target->HasImportLibrary(context->Config)) {
+ return target->GetFullPath(context->Config,
+ cmStateEnums::ImportLibraryArtifact);
+ }
+ return std::string{};
+ }
+};
+
+template <>
struct TargetFilesystemArtifactResultCreator<ArtifactBundleDirTag>
{
static std::string Create(cmGeneratorTarget* target,
@@ -2929,6 +3015,21 @@ struct TargetFilesystemArtifactResultCreator<ArtifactNameTag>
}
};
+template <>
+struct TargetFilesystemArtifactResultCreator<ArtifactImportTag>
+{
+ static std::string Create(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* /*unused*/)
+ {
+ if (target->HasImportLibrary(context->Config)) {
+ return target->GetFullPath(context->Config,
+ cmStateEnums::ImportLibraryArtifact, true);
+ }
+ return std::string{};
+ }
+};
+
template <typename ArtifactT>
struct TargetFilesystemArtifactResultGetter
{
@@ -3054,12 +3155,24 @@ struct TargetFilesystemArtifactNodeGroup
static const TargetFilesystemArtifactNodeGroup<ArtifactNameTag>
targetNodeGroup;
+static const TargetFilesystemArtifactNodeGroup<ArtifactImportTag>
+ targetImportNodeGroup;
+
static const TargetFilesystemArtifactNodeGroup<ArtifactLinkerTag>
targetLinkerNodeGroup;
+static const TargetFilesystemArtifactNodeGroup<ArtifactLinkerLibraryTag>
+ targetLinkerLibraryNodeGroup;
+
+static const TargetFilesystemArtifactNodeGroup<ArtifactLinkerImportTag>
+ targetLinkerImportNodeGroup;
+
static const TargetFilesystemArtifactNodeGroup<ArtifactSonameTag>
targetSoNameNodeGroup;
+static const TargetFilesystemArtifactNodeGroup<ArtifactSonameImportTag>
+ targetSoNameImportNodeGroup;
+
static const TargetFilesystemArtifactNodeGroup<ArtifactPdbTag>
targetPdbNodeGroup;
@@ -3099,13 +3212,30 @@ struct TargetOutputNameArtifactResultGetter<ArtifactNameTag>
};
template <>
+struct TargetOutputNameArtifactResultGetter<ArtifactImportTag>
+{
+ static std::string Get(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* /*unused*/)
+ {
+ if (target->HasImportLibrary(context->Config)) {
+ return target->GetOutputName(context->Config,
+ cmStateEnums::ImportLibraryArtifact) +
+ target->GetFilePostfix(context->Config);
+ }
+ return std::string{};
+ }
+};
+
+template <>
struct TargetOutputNameArtifactResultGetter<ArtifactLinkerTag>
{
static std::string Get(cmGeneratorTarget* target,
cmGeneratorExpressionContext* context,
const GeneratorExpressionContent* content)
{
- // The file used to link to the target (.so, .lib, .a).
+ // The library file used to link to the target (.so, .lib, .a) or import
+ // file (.lin, .tbd).
if (!target->IsLinkable()) {
::reportError(context, content->GetOriginalExpression(),
"TARGET_LINKER_FILE_BASE_NAME is allowed only for "
@@ -3122,6 +3252,56 @@ struct TargetOutputNameArtifactResultGetter<ArtifactLinkerTag>
};
template <>
+struct TargetOutputNameArtifactResultGetter<ArtifactLinkerLibraryTag>
+{
+ static std::string Get(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content)
+ {
+ // The library file used to link to the target (.so, .lib, .a).
+ if (!target->IsLinkable() ||
+ target->GetType() == cmStateEnums::EXECUTABLE) {
+ ::reportError(context, content->GetOriginalExpression(),
+ "TARGET_LINKER_LIBRARY_FILE_BASE_NAME is allowed only for "
+ "libraries with ENABLE_EXPORTS.");
+ return std::string();
+ }
+
+ if (!target->IsDLLPlatform() ||
+ target->GetType() == cmStateEnums::STATIC_LIBRARY) {
+ return target->GetOutputName(context->Config,
+ cmStateEnums::ImportLibraryArtifact) +
+ target->GetFilePostfix(context->Config);
+ }
+ return std::string{};
+ }
+};
+
+template <>
+struct TargetOutputNameArtifactResultGetter<ArtifactLinkerImportTag>
+{
+ static std::string Get(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content)
+ {
+ // The import file used to link to the target (.lib, .tbd).
+ if (!target->IsLinkable()) {
+ ::reportError(context, content->GetOriginalExpression(),
+ "TARGET_LINKER_IMPORT_FILE_BASE_NAME is allowed only for "
+ "libraries and executables with ENABLE_EXPORTS.");
+ return std::string();
+ }
+
+ if (target->HasImportLibrary(context->Config)) {
+ return target->GetOutputName(context->Config,
+ cmStateEnums::ImportLibraryArtifact) +
+ target->GetFilePostfix(context->Config);
+ }
+ return std::string{};
+ }
+};
+
+template <>
struct TargetOutputNameArtifactResultGetter<ArtifactPdbTag>
{
static std::string Get(cmGeneratorTarget* target,
@@ -3192,15 +3372,27 @@ struct TargetFileBaseNameArtifact : public TargetArtifactBase
static const TargetFileBaseNameArtifact<ArtifactNameTag>
targetFileBaseNameNode;
+static const TargetFileBaseNameArtifact<ArtifactImportTag>
+ targetImportFileBaseNameNode;
static const TargetFileBaseNameArtifact<ArtifactLinkerTag>
targetLinkerFileBaseNameNode;
+static const TargetFileBaseNameArtifact<ArtifactLinkerLibraryTag>
+ targetLinkerLibraryFileBaseNameNode;
+static const TargetFileBaseNameArtifact<ArtifactLinkerImportTag>
+ targetLinkerImportFileBaseNameNode;
static const TargetFileBaseNameArtifact<ArtifactPdbTag>
targetPdbFileBaseNameNode;
class ArtifactFilePrefixTag;
+class ArtifactImportFilePrefixTag;
class ArtifactLinkerFilePrefixTag;
+class ArtifactLinkerLibraryFilePrefixTag;
+class ArtifactLinkerImportFilePrefixTag;
class ArtifactFileSuffixTag;
+class ArtifactImportFileSuffixTag;
class ArtifactLinkerFileSuffixTag;
+class ArtifactLinkerLibraryFileSuffixTag;
+class ArtifactLinkerImportFileSuffixTag;
template <typename ArtifactT>
struct TargetFileArtifactResultGetter
@@ -3221,6 +3413,20 @@ struct TargetFileArtifactResultGetter<ArtifactFilePrefixTag>
}
};
template <>
+struct TargetFileArtifactResultGetter<ArtifactImportFilePrefixTag>
+{
+ static std::string Get(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent*)
+ {
+ if (target->HasImportLibrary(context->Config)) {
+ return target->GetFilePrefix(context->Config,
+ cmStateEnums::ImportLibraryArtifact);
+ }
+ return std::string{};
+ }
+};
+template <>
struct TargetFileArtifactResultGetter<ArtifactLinkerFilePrefixTag>
{
static std::string Get(cmGeneratorTarget* target,
@@ -3228,9 +3434,10 @@ struct TargetFileArtifactResultGetter<ArtifactLinkerFilePrefixTag>
const GeneratorExpressionContent* content)
{
if (!target->IsLinkable()) {
- ::reportError(context, content->GetOriginalExpression(),
- "TARGET_LINKER_PREFIX is allowed only for libraries and "
- "executables with ENABLE_EXPORTS.");
+ ::reportError(
+ context, content->GetOriginalExpression(),
+ "TARGET_LINKER_FILE_PREFIX is allowed only for libraries and "
+ "executables with ENABLE_EXPORTS.");
return std::string();
}
@@ -3243,6 +3450,52 @@ struct TargetFileArtifactResultGetter<ArtifactLinkerFilePrefixTag>
}
};
template <>
+struct TargetFileArtifactResultGetter<ArtifactLinkerLibraryFilePrefixTag>
+{
+ static std::string Get(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content)
+ {
+ if (!target->IsLinkable() ||
+ target->GetType() == cmStateEnums::EXECUTABLE) {
+ ::reportError(
+ context, content->GetOriginalExpression(),
+ "TARGET_LINKER_LIBRARY_FILE_PREFIX is allowed only for libraries "
+ "with ENABLE_EXPORTS.");
+ return std::string();
+ }
+
+ if (!target->IsDLLPlatform() ||
+ target->GetType() == cmStateEnums::STATIC_LIBRARY) {
+ return target->GetFilePrefix(context->Config,
+ cmStateEnums::RuntimeBinaryArtifact);
+ }
+ return std::string{};
+ }
+};
+template <>
+struct TargetFileArtifactResultGetter<ArtifactLinkerImportFilePrefixTag>
+{
+ static std::string Get(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content)
+ {
+ if (!target->IsLinkable()) {
+ ::reportError(
+ context, content->GetOriginalExpression(),
+ "TARGET_LINKER_IMPORT_FILE_PREFIX is allowed only for libraries and "
+ "executables with ENABLE_EXPORTS.");
+ return std::string();
+ }
+
+ if (target->HasImportLibrary(context->Config)) {
+ return target->GetFilePrefix(context->Config,
+ cmStateEnums::ImportLibraryArtifact);
+ }
+ return std::string{};
+ }
+};
+template <>
struct TargetFileArtifactResultGetter<ArtifactFileSuffixTag>
{
static std::string Get(cmGeneratorTarget* target,
@@ -3253,6 +3506,20 @@ struct TargetFileArtifactResultGetter<ArtifactFileSuffixTag>
}
};
template <>
+struct TargetFileArtifactResultGetter<ArtifactImportFileSuffixTag>
+{
+ static std::string Get(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent*)
+ {
+ if (target->HasImportLibrary(context->Config)) {
+ return target->GetFileSuffix(context->Config,
+ cmStateEnums::ImportLibraryArtifact);
+ }
+ return std::string{};
+ }
+};
+template <>
struct TargetFileArtifactResultGetter<ArtifactLinkerFileSuffixTag>
{
static std::string Get(cmGeneratorTarget* target,
@@ -3260,9 +3527,10 @@ struct TargetFileArtifactResultGetter<ArtifactLinkerFileSuffixTag>
const GeneratorExpressionContent* content)
{
if (!target->IsLinkable()) {
- ::reportError(context, content->GetOriginalExpression(),
- "TARGET_LINKER_SUFFIX is allowed only for libraries and "
- "executables with ENABLE_EXPORTS.");
+ ::reportError(
+ context, content->GetOriginalExpression(),
+ "TARGET_LINKER_FILE_SUFFIX is allowed only for libraries and "
+ "executables with ENABLE_EXPORTS.");
return std::string();
}
@@ -3274,6 +3542,51 @@ struct TargetFileArtifactResultGetter<ArtifactLinkerFileSuffixTag>
return target->GetFileSuffix(context->Config, artifact);
}
};
+template <>
+struct TargetFileArtifactResultGetter<ArtifactLinkerLibraryFileSuffixTag>
+{
+ static std::string Get(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content)
+ {
+ if (!target->IsLinkable() ||
+ target->GetType() == cmStateEnums::STATIC_LIBRARY) {
+ ::reportError(context, content->GetOriginalExpression(),
+ "TARGET_LINKER_LIBRARY_FILE_SUFFIX is allowed only for "
+ "libraries with ENABLE_EXPORTS.");
+ return std::string();
+ }
+
+ if (!target->IsDLLPlatform() ||
+ target->GetType() == cmStateEnums::STATIC_LIBRARY) {
+ return target->GetFileSuffix(context->Config,
+ cmStateEnums::RuntimeBinaryArtifact);
+ }
+ return std::string{};
+ }
+};
+template <>
+struct TargetFileArtifactResultGetter<ArtifactLinkerImportFileSuffixTag>
+{
+ static std::string Get(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content)
+ {
+ if (!target->IsLinkable()) {
+ ::reportError(
+ context, content->GetOriginalExpression(),
+ "TARGET_LINKER_IMPORT_FILE_SUFFIX is allowed only for libraries and "
+ "executables with ENABLE_EXPORTS.");
+ return std::string();
+ }
+
+ if (target->HasImportLibrary(context->Config)) {
+ return target->GetFileSuffix(context->Config,
+ cmStateEnums::ImportLibraryArtifact);
+ }
+ return std::string{};
+ }
+};
template <typename ArtifactT>
struct TargetFileArtifact : public TargetArtifactBase
@@ -3304,11 +3617,23 @@ struct TargetFileArtifact : public TargetArtifactBase
};
static const TargetFileArtifact<ArtifactFilePrefixTag> targetFilePrefixNode;
+static const TargetFileArtifact<ArtifactImportFilePrefixTag>
+ targetImportFilePrefixNode;
static const TargetFileArtifact<ArtifactLinkerFilePrefixTag>
targetLinkerFilePrefixNode;
+static const TargetFileArtifact<ArtifactLinkerLibraryFilePrefixTag>
+ targetLinkerLibraryFilePrefixNode;
+static const TargetFileArtifact<ArtifactLinkerImportFilePrefixTag>
+ targetLinkerImportFilePrefixNode;
static const TargetFileArtifact<ArtifactFileSuffixTag> targetFileSuffixNode;
+static const TargetFileArtifact<ArtifactImportFileSuffixTag>
+ targetImportFileSuffixNode;
static const TargetFileArtifact<ArtifactLinkerFileSuffixTag>
targetLinkerFileSuffixNode;
+static const TargetFileArtifact<ArtifactLinkerLibraryFileSuffixTag>
+ targetLinkerLibraryFileSuffixNode;
+static const TargetFileArtifact<ArtifactLinkerImportFileSuffixTag>
+ targetLinkerImportFileSuffixNode;
static const struct ShellPathNode : public cmGeneratorExpressionNode
{
@@ -3376,23 +3701,52 @@ const cmGeneratorExpressionNode* cmGeneratorExpressionNode::GetNode(
{ "CONFIGURATION", &configurationNode },
{ "CONFIG", &configurationTestNode },
{ "TARGET_FILE", &targetNodeGroup.File },
+ { "TARGET_IMPORT_FILE", &targetImportNodeGroup.File },
{ "TARGET_LINKER_FILE", &targetLinkerNodeGroup.File },
+ { "TARGET_LINKER_LIBRARY_FILE", &targetLinkerLibraryNodeGroup.File },
+ { "TARGET_LINKER_IMPORT_FILE", &targetLinkerImportNodeGroup.File },
{ "TARGET_SONAME_FILE", &targetSoNameNodeGroup.File },
+ { "TARGET_SONAME_IMPORT_FILE", &targetSoNameImportNodeGroup.File },
{ "TARGET_PDB_FILE", &targetPdbNodeGroup.File },
{ "TARGET_FILE_BASE_NAME", &targetFileBaseNameNode },
+ { "TARGET_IMPORT_FILE_BASE_NAME", &targetImportFileBaseNameNode },
{ "TARGET_LINKER_FILE_BASE_NAME", &targetLinkerFileBaseNameNode },
+ { "TARGET_LINKER_LIBRARY_FILE_BASE_NAME",
+ &targetLinkerLibraryFileBaseNameNode },
+ { "TARGET_LINKER_IMPORT_FILE_BASE_NAME",
+ &targetLinkerImportFileBaseNameNode },
{ "TARGET_PDB_FILE_BASE_NAME", &targetPdbFileBaseNameNode },
{ "TARGET_FILE_PREFIX", &targetFilePrefixNode },
+ { "TARGET_IMPORT_FILE_PREFIX", &targetImportFilePrefixNode },
{ "TARGET_LINKER_FILE_PREFIX", &targetLinkerFilePrefixNode },
+ { "TARGET_LINKER_LIBRARY_FILE_PREFIX",
+ &targetLinkerLibraryFilePrefixNode },
+ { "TARGET_LINKER_IMPORT_FILE_PREFIX", &targetLinkerImportFilePrefixNode },
{ "TARGET_FILE_SUFFIX", &targetFileSuffixNode },
+ { "TARGET_IMPORT_FILE_SUFFIX", &targetImportFileSuffixNode },
{ "TARGET_LINKER_FILE_SUFFIX", &targetLinkerFileSuffixNode },
+ { "TARGET_LINKER_LIBRARY_FILE_SUFFIX",
+ &targetLinkerLibraryFileSuffixNode },
+ { "TARGET_LINKER_IMPORT_FILE_SUFFIX", &targetLinkerImportFileSuffixNode },
{ "TARGET_FILE_NAME", &targetNodeGroup.FileName },
+ { "TARGET_IMPORT_FILE_NAME", &targetImportNodeGroup.FileName },
{ "TARGET_LINKER_FILE_NAME", &targetLinkerNodeGroup.FileName },
+ { "TARGET_LINKER_LIBRARY_FILE_NAME",
+ &targetLinkerLibraryNodeGroup.FileName },
+ { "TARGET_LINKER_IMPORT_FILE_NAME",
+ &targetLinkerImportNodeGroup.FileName },
{ "TARGET_SONAME_FILE_NAME", &targetSoNameNodeGroup.FileName },
+ { "TARGET_SONAME_IMPORT_FILE_NAME",
+ &targetSoNameImportNodeGroup.FileName },
{ "TARGET_PDB_FILE_NAME", &targetPdbNodeGroup.FileName },
{ "TARGET_FILE_DIR", &targetNodeGroup.FileDir },
+ { "TARGET_IMPORT_FILE_DIR", &targetImportNodeGroup.FileDir },
{ "TARGET_LINKER_FILE_DIR", &targetLinkerNodeGroup.FileDir },
+ { "TARGET_LINKER_LIBRARY_FILE_DIR",
+ &targetLinkerLibraryNodeGroup.FileDir },
+ { "TARGET_LINKER_IMPORT_FILE_DIR", &targetLinkerImportNodeGroup.FileDir },
{ "TARGET_SONAME_FILE_DIR", &targetSoNameNodeGroup.FileDir },
+ { "TARGET_SONAME_IMPORT_FILE_DIR", &targetSoNameImportNodeGroup.FileDir },
{ "TARGET_PDB_FILE_DIR", &targetPdbNodeGroup.FileDir },
{ "TARGET_BUNDLE_DIR", &targetBundleDirNode },
{ "TARGET_BUNDLE_DIR_NAME", &targetBundleDirNameNode },
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index 446e908be6..488c32de75 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -458,6 +458,11 @@ std::string const& cmGeneratorTarget::GetSafeProperty(
const char* cmGeneratorTarget::GetOutputTargetType(
cmStateEnums::ArtifactType artifact) const
{
+ if (this->IsFrameworkOnApple() || this->GetGlobalGenerator()->IsXcode()) {
+ // import file (i.e. .tbd file) is always in same location as library
+ artifact = cmStateEnums::RuntimeBinaryArtifact;
+ }
+
switch (this->GetType()) {
case cmStateEnums::SHARED_LIBRARY:
if (this->IsDLLPlatform()) {
@@ -470,9 +475,15 @@ const char* cmGeneratorTarget::GetOutputTargetType(
return "ARCHIVE";
}
} else {
- // For non-DLL platforms shared libraries are treated as
- // library targets.
- return "LIBRARY";
+ switch (artifact) {
+ case cmStateEnums::RuntimeBinaryArtifact:
+ // For non-DLL platforms shared libraries are treated as
+ // library targets.
+ return "LIBRARY";
+ case cmStateEnums::ImportLibraryArtifact:
+ // Library import libraries are treated as archive targets.
+ return "ARCHIVE";
+ }
}
break;
case cmStateEnums::STATIC_LIBRARY:
@@ -2518,7 +2529,8 @@ bool cmGeneratorTarget::CanGenerateInstallNameDir(
return !skip;
}
-std::string cmGeneratorTarget::GetSOName(const std::string& config) const
+std::string cmGeneratorTarget::GetSOName(
+ const std::string& config, cmStateEnums::ArtifactType artifact) const
{
if (this->IsImported()) {
// Lookup the imported soname.
@@ -2546,7 +2558,9 @@ std::string cmGeneratorTarget::GetSOName(const std::string& config) const
return "";
}
// Compute the soname that will be built.
- return this->GetLibraryNames(config).SharedObject;
+ return artifact == cmStateEnums::RuntimeBinaryArtifact
+ ? this->GetLibraryNames(config).SharedObject
+ : this->GetLibraryNames(config).ImportLibrary;
}
namespace {
@@ -5088,10 +5102,18 @@ void cmGeneratorTarget::ComputeTargetManifest(const std::string& config) const
f = cmStrCat(dir, '/', targetNames.PDB);
gg->AddToManifest(f);
}
+
+ dir = this->GetDirectory(config, cmStateEnums::ImportLibraryArtifact);
+ if (!targetNames.ImportOutput.empty()) {
+ f = cmStrCat(dir, '/', targetNames.ImportOutput);
+ gg->AddToManifest(f);
+ }
if (!targetNames.ImportLibrary.empty()) {
- f =
- cmStrCat(this->GetDirectory(config, cmStateEnums::ImportLibraryArtifact),
- '/', targetNames.ImportLibrary);
+ f = cmStrCat(dir, '/', targetNames.ImportLibrary);
+ gg->AddToManifest(f);
+ }
+ if (!targetNames.ImportReal.empty()) {
+ f = cmStrCat(dir, '/', targetNames.ImportReal);
gg->AddToManifest(f);
}
}
@@ -5211,14 +5233,20 @@ std::string cmGeneratorTarget::NormalGetFullPath(
}
break;
case cmStateEnums::ImportLibraryArtifact:
- fpath += this->GetFullName(config, cmStateEnums::ImportLibraryArtifact);
+ if (realname) {
+ fpath +=
+ this->NormalGetRealName(config, cmStateEnums::ImportLibraryArtifact);
+ } else {
+ fpath +=
+ this->GetFullName(config, cmStateEnums::ImportLibraryArtifact);
+ }
break;
}
return fpath;
}
std::string cmGeneratorTarget::NormalGetRealName(
- const std::string& config) const
+ const std::string& config, cmStateEnums::ArtifactType artifact) const
{
// This should not be called for imported targets.
// TODO: Split cmTarget into a class hierarchy to get compile-time
@@ -5229,12 +5257,13 @@ std::string cmGeneratorTarget::NormalGetRealName(
this->LocalGenerator->IssueMessage(MessageType::INTERNAL_ERROR, msg);
}
- if (this->GetType() == cmStateEnums::EXECUTABLE) {
- // Compute the real name that will be built.
- return this->GetExecutableNames(config).Real;
- }
+ Names names = this->GetType() == cmStateEnums::EXECUTABLE
+ ? this->GetExecutableNames(config)
+ : this->GetLibraryNames(config);
+
// Compute the real name that will be built.
- return this->GetLibraryNames(config).Real;
+ return artifact == cmStateEnums::RuntimeBinaryArtifact ? names.Real
+ : names.ImportReal;
}
cmGeneratorTarget::Names cmGeneratorTarget::GetLibraryNames(
@@ -5279,17 +5308,16 @@ cmGeneratorTarget::Names cmGeneratorTarget::GetLibraryNames(
// The library name.
targetNames.Base = components.base;
targetNames.Output =
- components.prefix + targetNames.Base + components.suffix;
+ cmStrCat(components.prefix, targetNames.Base, components.suffix);
if (this->IsFrameworkOnApple()) {
targetNames.Real = components.prefix;
if (!this->Makefile->PlatformIsAppleEmbedded()) {
- targetNames.Real += "Versions/";
- targetNames.Real += this->GetFrameworkVersion();
- targetNames.Real += "/";
+ targetNames.Real +=
+ cmStrCat("Versions/", this->GetFrameworkVersion(), '/');
}
- targetNames.Real += targetNames.Base + components.suffix;
- targetNames.SharedObject = targetNames.Real + components.suffix;
+ targetNames.Real += cmStrCat(targetNames.Base, components.suffix);
+ targetNames.SharedObject = targetNames.Real;
} else {
// The library's soname.
this->ComputeVersionedName(targetNames.SharedObject, components.prefix,
@@ -5302,11 +5330,36 @@ cmGeneratorTarget::Names cmGeneratorTarget::GetLibraryNames(
targetNames.Output, version);
}
- // The import library name.
+ // The import library names.
if (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
this->GetType() == cmStateEnums::MODULE_LIBRARY) {
- targetNames.ImportLibrary =
- this->GetFullNameInternal(config, cmStateEnums::ImportLibraryArtifact);
+ NameComponents const& importComponents =
+ this->GetFullNameInternalComponents(config,
+ cmStateEnums::ImportLibraryArtifact);
+ targetNames.ImportOutput = cmStrCat(
+ importComponents.prefix, importComponents.base, importComponents.suffix);
+
+ if (this->IsFrameworkOnApple() && this->IsSharedLibraryWithExports()) {
+ targetNames.ImportReal = components.prefix;
+ if (!this->Makefile->PlatformIsAppleEmbedded()) {
+ targetNames.ImportReal +=
+ cmStrCat("Versions/", this->GetFrameworkVersion(), '/');
+ }
+ targetNames.ImportReal +=
+ cmStrCat(importComponents.base, importComponents.suffix);
+ targetNames.ImportLibrary = targetNames.ImportOutput;
+ } else {
+ // The import library's soname.
+ this->ComputeVersionedName(
+ targetNames.ImportLibrary, importComponents.prefix,
+ importComponents.base, importComponents.suffix,
+ targetNames.ImportOutput, soversion);
+
+ // The import library's real name on disk.
+ this->ComputeVersionedName(
+ targetNames.ImportReal, importComponents.prefix, importComponents.base,
+ importComponents.suffix, targetNames.ImportOutput, version);
+ }
}
// The program database file name.
@@ -5368,6 +5421,8 @@ cmGeneratorTarget::Names cmGeneratorTarget::GetExecutableNames(
// The import library name.
targetNames.ImportLibrary =
this->GetFullNameInternal(config, cmStateEnums::ImportLibraryArtifact);
+ targetNames.ImportReal = targetNames.ImportLibrary;
+ targetNames.ImportOutput = targetNames.ImportLibrary;
// The program database file name.
targetNames.PDB = this->GetPDBName(config);
@@ -5449,15 +5504,18 @@ cmGeneratorTarget::GetFullNameInternalComponents(
}
// Compute the full name for main target types.
- const std::string configPostfix = this->GetFilePostfix(config);
+ std::string configPostfix = this->GetFilePostfix(config);
- // frameworks have directory prefix but no suffix
+ // frameworks have directory prefix
std::string fw_prefix;
if (this->IsFrameworkOnApple()) {
fw_prefix =
cmStrCat(this->GetFrameworkDirectory(config, ContentLevel), '/');
targetPrefix = cmValue(fw_prefix);
- targetSuffix = nullptr;
+ if (!isImportedLibraryArtifact) {
+ // no suffix
+ targetSuffix = nullptr;
+ }
}
if (this->IsCFBundleOnApple()) {
@@ -5476,8 +5534,8 @@ cmGeneratorTarget::GetFullNameInternalComponents(
// When using Xcode, the postfix should be part of the suffix rather than
// the base, because the suffix ends up being used in Xcode's
// EXECUTABLE_SUFFIX attribute.
- if (this->IsFrameworkOnApple() &&
- this->GetGlobalGenerator()->GetName() == "Xcode") {
+ if (this->IsFrameworkOnApple() && this->GetGlobalGenerator()->IsXcode()) {
+ configPostfix += *targetSuffix;
targetSuffix = cmValue(configPostfix);
} else {
outBase += configPostfix;
@@ -8544,15 +8602,35 @@ bool cmGeneratorTarget::IsExecutableWithExports() const
return this->Target->IsExecutableWithExports();
}
+bool cmGeneratorTarget::IsSharedLibraryWithExports() const
+{
+ return this->Target->IsSharedLibraryWithExports();
+}
+
bool cmGeneratorTarget::HasImportLibrary(std::string const& config) const
{
+ bool generate_Stubs = true;
+ if (this->GetGlobalGenerator()->IsXcode()) {
+ // take care of CMAKE_XCODE_ATTRIBUTE_GENERATE_TEXT_BASED_STUBS variable
+ // as well as XCODE_ATTRIBUTE_GENERATE_TEXT_BASED_STUBS property
+ if (cmValue propGenStubs =
+ this->GetProperty("XCODE_ATTRIBUTE_GENERATE_TEXT_BASED_STUBS")) {
+ generate_Stubs = propGenStubs == "YES";
+ } else if (cmValue varGenStubs = this->Makefile->GetDefinition(
+ "CMAKE_XCODE_ATTRIBUTE_GENERATE_TEXT_BASED_STUBS")) {
+ generate_Stubs = varGenStubs == "YES";
+ }
+ }
+
return (this->IsDLLPlatform() &&
(this->GetType() == cmStateEnums::SHARED_LIBRARY ||
this->IsExecutableWithExports()) &&
// Assemblies which have only managed code do not have
// import libraries.
this->GetManagedType(config) != ManagedType::Managed) ||
- (this->IsAIX() && this->IsExecutableWithExports());
+ (this->IsAIX() && this->IsExecutableWithExports()) ||
+ (this->Makefile->PlatformSupportsAppleTextStubs() &&
+ this->IsSharedLibraryWithExports() && generate_Stubs);
}
bool cmGeneratorTarget::NeedImportLibraryName(std::string const& config) const
diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h
index f1014d9477..5d26191706 100644
--- a/Source/cmGeneratorTarget.h
+++ b/Source/cmGeneratorTarget.h
@@ -273,7 +273,9 @@ public:
std::string NormalGetFullPath(const std::string& config,
cmStateEnums::ArtifactType artifact,
bool realname) const;
- std::string NormalGetRealName(const std::string& config) const;
+ std::string NormalGetRealName(const std::string& config,
+ cmStateEnums::ArtifactType artifact =
+ cmStateEnums::RuntimeBinaryArtifact) const;
/** Get the names of an object library's object files underneath
its object file directory. */
@@ -348,7 +350,9 @@ public:
const std::string* GetExportMacro() const;
/** Get the soname of the target. Allowed only for a shared library. */
- std::string GetSOName(const std::string& config) const;
+ std::string GetSOName(const std::string& config,
+ cmStateEnums::ArtifactType artifact =
+ cmStateEnums::RuntimeBinaryArtifact) const;
struct NameComponents
{
@@ -740,6 +744,8 @@ public:
std::string Base;
std::string Output;
std::string Real;
+ std::string ImportOutput;
+ std::string ImportReal;
std::string ImportLibrary;
std::string PDB;
std::string SharedObject;
@@ -786,6 +792,10 @@ public:
bool IsExecutableWithExports() const;
+ /* Return whether this target is a shared library with capability to generate
+ * a file describing symbols exported (for example, .tbd file on Apple). */
+ bool IsSharedLibraryWithExports() const;
+
/** Return whether or not the target has a DLL import library. */
bool HasImportLibrary(std::string const& config) const;
diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx
index b5e1529880..ba7d7a74bd 100644
--- a/Source/cmGlobalNinjaGenerator.cxx
+++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -1270,6 +1270,10 @@ void cmGlobalNinjaGenerator::AppendTargetOutputs(
}
CM_FALLTHROUGH;
case cmStateEnums::EXECUTABLE: {
+ if (target->IsApple() && target->HasImportLibrary(config)) {
+ outputs.push_back(this->ConvertToNinjaPath(target->GetFullPath(
+ config, cmStateEnums::ImportLibraryArtifact, realname)));
+ }
outputs.push_back(this->ConvertToNinjaPath(target->GetFullPath(
config, cmStateEnums::RuntimeBinaryArtifact, realname)));
break;
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index d4ce69e1f3..5b3ac60544 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -1739,7 +1739,7 @@ void cmGlobalXCodeGenerator::CreateCustomCommands(
std::string str_so_file =
cmStrCat("$<TARGET_SONAME_FILE:", gtgt->GetName(), '>');
std::string str_link_file =
- cmStrCat("$<TARGET_LINKER_FILE:", gtgt->GetName(), '>');
+ cmStrCat("$<TARGET_LINKER_LIBRARY_FILE:", gtgt->GetName(), '>');
cmCustomCommandLines cmd = cmMakeSingleCommandLine(
{ cmSystemTools::GetCMakeCommand(), "-E", "cmake_symlink_library",
str_file, str_so_file, str_link_file });
@@ -1754,6 +1754,27 @@ void cmGlobalXCodeGenerator::CreateCustomCommands(
postbuild.push_back(std::move(command));
}
+ if (gtgt->HasImportLibrary("") && !gtgt->IsFrameworkOnApple()) {
+ // create symbolic links for .tbd file
+ std::string file = cmStrCat("$<TARGET_IMPORT_FILE:", gtgt->GetName(), '>');
+ std::string soFile =
+ cmStrCat("$<TARGET_SONAME_IMPORT_FILE:", gtgt->GetName(), '>');
+ std::string linkFile =
+ cmStrCat("$<TARGET_LINKER_IMPORT_FILE:", gtgt->GetName(), '>');
+ cmCustomCommandLines symlink_command = cmMakeSingleCommandLine(
+ { cmSystemTools::GetCMakeCommand(), "-E", "cmake_symlink_library", file,
+ soFile, linkFile });
+
+ cmCustomCommand command;
+ command.SetCommandLines(symlink_command);
+ command.SetComment("Creating import symlinks");
+ command.SetWorkingDirectory("");
+ command.SetBacktrace(this->CurrentMakefile->GetBacktrace());
+ command.SetStdPipesUTF8(true);
+
+ postbuild.push_back(std::move(command));
+ }
+
cmXCodeObject* legacyCustomCommandsBuildPhase = nullptr;
cmXCodeObject* preBuildPhase = nullptr;
cmXCodeObject* preLinkPhase = nullptr;
@@ -2682,6 +2703,12 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt,
buildSettings->AddAttribute("LIBRARY_STYLE",
this->CreateString("DYNAMIC"));
+
+ if (gtgt->HasImportLibrary(configName)) {
+ // Request .tbd file generation
+ buildSettings->AddAttribute("GENERATE_TEXT_BASED_STUBS",
+ this->CreateString("YES"));
+ }
break;
}
case cmStateEnums::EXECUTABLE: {
diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx
index 56c8b26119..40230d9fb6 100644
--- a/Source/cmInstallCommand.cxx
+++ b/Source/cmInstallCommand.cxx
@@ -553,34 +553,35 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
// Enforce argument rules too complex to specify for the
// general-purpose parser.
- if (archiveArgs.GetNamelinkOnly() || runtimeArgs.GetNamelinkOnly() ||
- objectArgs.GetNamelinkOnly() || frameworkArgs.GetNamelinkOnly() ||
- bundleArgs.GetNamelinkOnly() || privateHeaderArgs.GetNamelinkOnly() ||
+ if (runtimeArgs.GetNamelinkOnly() || objectArgs.GetNamelinkOnly() ||
+ frameworkArgs.GetNamelinkOnly() || bundleArgs.GetNamelinkOnly() ||
+ privateHeaderArgs.GetNamelinkOnly() ||
publicHeaderArgs.GetNamelinkOnly() || resourceArgs.GetNamelinkOnly() ||
std::any_of(fileSetArgs.begin(), fileSetArgs.end(),
[](const cmInstallCommandFileSetArguments& fileSetArg)
-> bool { return fileSetArg.GetNamelinkOnly(); }) ||
cxxModuleBmiArgs.GetNamelinkOnly()) {
status.SetError(
- "TARGETS given NAMELINK_ONLY option not in LIBRARY group. "
- "The NAMELINK_ONLY option may be specified only following LIBRARY.");
+ "TARGETS given NAMELINK_ONLY option not in LIBRARY or ARCHIVE group. "
+ "The NAMELINK_ONLY option may be specified only following LIBRARY or "
+ "ARCHIVE.");
return false;
}
- if (archiveArgs.GetNamelinkSkip() || runtimeArgs.GetNamelinkSkip() ||
- objectArgs.GetNamelinkSkip() || frameworkArgs.GetNamelinkSkip() ||
- bundleArgs.GetNamelinkSkip() || privateHeaderArgs.GetNamelinkSkip() ||
+ if (runtimeArgs.GetNamelinkSkip() || objectArgs.GetNamelinkSkip() ||
+ frameworkArgs.GetNamelinkSkip() || bundleArgs.GetNamelinkSkip() ||
+ privateHeaderArgs.GetNamelinkSkip() ||
publicHeaderArgs.GetNamelinkSkip() || resourceArgs.GetNamelinkSkip() ||
std::any_of(fileSetArgs.begin(), fileSetArgs.end(),
[](const cmInstallCommandFileSetArguments& fileSetArg)
-> bool { return fileSetArg.GetNamelinkSkip(); }) ||
cxxModuleBmiArgs.GetNamelinkSkip()) {
status.SetError(
- "TARGETS given NAMELINK_SKIP option not in LIBRARY group. "
- "The NAMELINK_SKIP option may be specified only following LIBRARY.");
+ "TARGETS given NAMELINK_SKIP option not in LIBRARY or ARCHIVE group. "
+ "The NAMELINK_SKIP option may be specified only following LIBRARY or "
+ "ARCHIVE.");
return false;
}
- if (archiveArgs.HasNamelinkComponent() ||
- runtimeArgs.HasNamelinkComponent() ||
+ if (runtimeArgs.HasNamelinkComponent() ||
objectArgs.HasNamelinkComponent() ||
frameworkArgs.HasNamelinkComponent() ||
bundleArgs.HasNamelinkComponent() ||
@@ -592,9 +593,9 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
-> bool { return fileSetArg.HasNamelinkComponent(); }) ||
cxxModuleBmiArgs.HasNamelinkComponent()) {
status.SetError(
- "TARGETS given NAMELINK_COMPONENT option not in LIBRARY group. "
- "The NAMELINK_COMPONENT option may be specified only following "
- "LIBRARY.");
+ "TARGETS given NAMELINK_COMPONENT option not in LIBRARY or ARCHIVE "
+ "group. The NAMELINK_COMPONENT option may be specified only following "
+ "LIBRARY or ARCHIVE.");
return false;
}
if (libraryArgs.GetNamelinkOnly() && libraryArgs.GetNamelinkSkip()) {
@@ -674,6 +675,14 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
} else if (libraryArgs.GetNamelinkSkip()) {
namelinkMode = cmInstallTargetGenerator::NamelinkModeSkip;
}
+ // Select the mode for installing symlinks to versioned imported libraries.
+ cmInstallTargetGenerator::NamelinkModeType importlinkMode =
+ cmInstallTargetGenerator::NamelinkModeNone;
+ if (archiveArgs.GetNamelinkOnly()) {
+ importlinkMode = cmInstallTargetGenerator::NamelinkModeOnly;
+ } else if (archiveArgs.GetNamelinkSkip()) {
+ importlinkMode = cmInstallTargetGenerator::NamelinkModeSkip;
+ }
// Check if there is something to do.
if (targetList.empty()) {
@@ -725,6 +734,7 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
bool installsArchive = false;
bool installsLibrary = false;
bool installsNamelink = false;
+ bool installsImportlink = false;
bool installsRuntime = false;
bool installsObject = false;
bool installsFramework = false;
@@ -742,6 +752,7 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
std::unique_ptr<cmInstallTargetGenerator> archiveGenerator;
std::unique_ptr<cmInstallTargetGenerator> libraryGenerator;
std::unique_ptr<cmInstallTargetGenerator> namelinkGenerator;
+ std::unique_ptr<cmInstallTargetGenerator> importlinkGenerator;
std::unique_ptr<cmInstallTargetGenerator> runtimeGenerator;
std::unique_ptr<cmInstallTargetGenerator> objectGenerator;
std::unique_ptr<cmInstallTargetGenerator> frameworkGenerator;
@@ -885,6 +896,32 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
}
namelinkOnly =
(namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly);
+
+ if (target.GetMakefile()->PlatformSupportsAppleTextStubs() &&
+ target.IsSharedLibraryWithExports()) {
+ // Apple .tbd files use the ARCHIVE properties
+ if (!archiveArgs.GetDestination().empty()) {
+ artifactsSpecified = true;
+ }
+ if (importlinkMode !=
+ cmInstallTargetGenerator::NamelinkModeOnly) {
+ archiveGenerator = CreateInstallTargetGenerator(
+ target, archiveArgs, true, helper.Makefile->GetBacktrace(),
+ helper.GetLibraryDestination(&archiveArgs));
+ archiveGenerator->SetImportlinkMode(
+ cmInstallTargetGenerator::NamelinkModeSkip);
+ }
+ if (importlinkMode !=
+ cmInstallTargetGenerator::NamelinkModeSkip) {
+ importlinkGenerator = CreateInstallTargetGenerator(
+ target, archiveArgs, true, helper.Makefile->GetBacktrace(),
+ helper.GetLibraryDestination(&archiveArgs), false, true);
+ importlinkGenerator->SetImportlinkMode(
+ cmInstallTargetGenerator::NamelinkModeOnly);
+ }
+ namelinkOnly =
+ (importlinkMode == cmInstallTargetGenerator::NamelinkModeOnly);
+ }
}
if (runtimeDependencySet && libraryGenerator) {
runtimeDependencySet->AddLibrary(libraryGenerator.get());
@@ -1157,6 +1194,7 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
installsArchive = installsArchive || archiveGenerator;
installsLibrary = installsLibrary || libraryGenerator;
installsNamelink = installsNamelink || namelinkGenerator;
+ installsImportlink = installsImportlink || importlinkGenerator;
installsRuntime = installsRuntime || runtimeGenerator;
installsObject = installsObject || objectGenerator;
installsFramework = installsFramework || frameworkGenerator;
@@ -1169,6 +1207,7 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
helper.Makefile->AddInstallGenerator(std::move(archiveGenerator));
helper.Makefile->AddInstallGenerator(std::move(libraryGenerator));
helper.Makefile->AddInstallGenerator(std::move(namelinkGenerator));
+ helper.Makefile->AddInstallGenerator(std::move(importlinkGenerator));
helper.Makefile->AddInstallGenerator(std::move(runtimeGenerator));
helper.Makefile->AddInstallGenerator(std::move(objectGenerator));
helper.Makefile->AddInstallGenerator(std::move(frameworkGenerator));
@@ -1203,6 +1242,10 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
libraryArgs.GetNamelinkComponent());
}
+ if (installsImportlink) {
+ helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
+ archiveArgs.GetNamelinkComponent());
+ }
if (installsRuntime) {
helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
runtimeArgs.GetComponent());
diff --git a/Source/cmInstallTargetGenerator.cxx b/Source/cmInstallTargetGenerator.cxx
index e837cc340a..6c31da62a6 100644
--- a/Source/cmInstallTargetGenerator.cxx
+++ b/Source/cmInstallTargetGenerator.cxx
@@ -4,12 +4,15 @@
#include <algorithm>
#include <cassert>
+#include <functional>
#include <map>
#include <set>
#include <sstream>
#include <utility>
#include <vector>
+#include <cm/optional>
+
#include "cmComputeLinkInformation.h"
#include "cmGeneratorExpression.h"
#include "cmGeneratorTarget.h"
@@ -40,6 +43,84 @@ std::string computeInstallObjectDir(cmGeneratorTarget* gt,
objectDir += gt->GetName();
return objectDir;
}
+
+void computeFilesToInstall(
+ cmInstallTargetGenerator::Files& files,
+ cmInstallTargetGenerator::NamelinkModeType namelinkMode,
+ std::string const& fromDirConfig, std::string const& output,
+ std::string const& library, std::string const& real,
+ cm::optional<std::function<void(std::string const&)>> GNUToMS = cm::nullopt)
+{
+ bool haveNamelink = false;
+ auto convert = [&GNUToMS](std::string const& file) {
+ if (GNUToMS) {
+ (*GNUToMS)(file);
+ }
+ };
+
+ // Library link name.
+ std::string fromName = cmStrCat(fromDirConfig, output);
+ std::string toName = output;
+
+ // Library interface name.
+ std::string fromSOName;
+ std::string toSOName;
+ if (library != output) {
+ haveNamelink = true;
+ fromSOName = cmStrCat(fromDirConfig, library);
+ toSOName = library;
+ }
+
+ // Library implementation name.
+ std::string fromRealName;
+ std::string toRealName;
+ if (real != output && real != library) {
+ haveNamelink = true;
+ fromRealName = cmStrCat(fromDirConfig, real);
+ toRealName = real;
+ }
+
+ // Add the names based on the current namelink mode.
+ if (haveNamelink) {
+ files.NamelinkMode = namelinkMode;
+ // With a namelink we need to check the mode.
+ if (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly) {
+ // Install the namelink only.
+ files.From.emplace_back(fromName);
+ files.To.emplace_back(toName);
+ convert(output);
+ } else {
+ // Install the real file if it has its own name.
+ if (!fromRealName.empty()) {
+ files.From.emplace_back(fromRealName);
+ files.To.emplace_back(toRealName);
+ convert(real);
+ }
+
+ // Install the soname link if it has its own name.
+ if (!fromSOName.empty()) {
+ files.From.emplace_back(fromSOName);
+ files.To.emplace_back(toSOName);
+ convert(library);
+ }
+
+ // Install the namelink if it is not to be skipped.
+ if (namelinkMode != cmInstallTargetGenerator::NamelinkModeSkip) {
+ files.From.emplace_back(fromName);
+ files.To.emplace_back(toName);
+ convert(output);
+ }
+ }
+ } else {
+ // Without a namelink there will be only one file. Install it
+ // if this is not a namelink-only rule.
+ if (namelinkMode != cmInstallTargetGenerator::NamelinkModeOnly) {
+ files.From.emplace_back(fromName);
+ files.To.emplace_back(toName);
+ convert(output);
+ }
+ }
+}
}
cmInstallTargetGenerator::cmInstallTargetGenerator(
@@ -56,6 +137,7 @@ cmInstallTargetGenerator::cmInstallTargetGenerator(
{
this->ActionsPerConfig = true;
this->NamelinkMode = NamelinkModeNone;
+ this->ImportlinkMode = NamelinkModeNone;
}
cmInstallTargetGenerator::~cmInstallTargetGenerator() = default;
@@ -247,18 +329,21 @@ cmInstallTargetGenerator::Files cmInstallTargetGenerator::GetFiles(
this->Target->GetLibraryNames(config);
if (this->ImportLibrary) {
// There is a bug in cmInstallCommand if this fails.
- assert(this->NamelinkMode == NamelinkModeNone);
+ assert(this->Target->Makefile->PlatformSupportsAppleTextStubs() ||
+ this->ImportlinkMode == NamelinkModeNone);
+
+ auto GNUToMS = [this, &config, &files,
+ &fromDirConfig](const std::string& lib) {
+ std::string importLib;
+ if (this->Target->GetImplibGNUtoMS(config, lib, importLib)) {
+ files.From.emplace_back(fromDirConfig + importLib);
+ files.To.emplace_back(importLib);
+ }
+ };
- std::string from1 = fromDirConfig + targetNames.ImportLibrary;
- std::string to1 = targetNames.ImportLibrary;
- files.From.emplace_back(std::move(from1));
- files.To.emplace_back(std::move(to1));
- std::string targetNameImportLib;
- if (this->Target->GetImplibGNUtoMS(config, targetNames.ImportLibrary,
- targetNameImportLib)) {
- files.From.emplace_back(fromDirConfig + targetNameImportLib);
- files.To.emplace_back(targetNameImportLib);
- }
+ computeFilesToInstall(
+ files, this->ImportlinkMode, fromDirConfig, targetNames.ImportOutput,
+ targetNames.ImportLibrary, targetNames.ImportReal, GNUToMS);
// An import library looks like a static library.
files.Type = cmInstallType_STATIC_LIBRARY;
@@ -318,66 +403,9 @@ cmInstallTargetGenerator::Files cmInstallTargetGenerator::GetFiles(
files.From.emplace_back(std::move(from1));
files.To.emplace_back(std::move(to1));
} else {
- bool haveNamelink = false;
-
- // Library link name.
- std::string fromName = fromDirConfig + targetNames.Output;
- std::string toName = targetNames.Output;
-
- // Library interface name.
- std::string fromSOName;
- std::string toSOName;
- if (targetNames.SharedObject != targetNames.Output) {
- haveNamelink = true;
- fromSOName = fromDirConfig + targetNames.SharedObject;
- toSOName = targetNames.SharedObject;
- }
-
- // Library implementation name.
- std::string fromRealName;
- std::string toRealName;
- if (targetNames.Real != targetNames.Output &&
- targetNames.Real != targetNames.SharedObject) {
- haveNamelink = true;
- fromRealName = fromDirConfig + targetNames.Real;
- toRealName = targetNames.Real;
- }
-
- // Add the names based on the current namelink mode.
- if (haveNamelink) {
- files.NamelinkMode = this->NamelinkMode;
- // With a namelink we need to check the mode.
- if (this->NamelinkMode == NamelinkModeOnly) {
- // Install the namelink only.
- files.From.emplace_back(fromName);
- files.To.emplace_back(toName);
- } else {
- // Install the real file if it has its own name.
- if (!fromRealName.empty()) {
- files.From.emplace_back(fromRealName);
- files.To.emplace_back(toRealName);
- }
-
- // Install the soname link if it has its own name.
- if (!fromSOName.empty()) {
- files.From.emplace_back(fromSOName);
- files.To.emplace_back(toSOName);
- }
-
- // Install the namelink if it is not to be skipped.
- if (this->NamelinkMode != NamelinkModeSkip) {
- files.From.emplace_back(fromName);
- files.To.emplace_back(toName);
- }
- }
- } else {
- // Without a namelink there will be only one file. Install it
- // if this is not a namelink-only rule.
- if (this->NamelinkMode != NamelinkModeOnly) {
- files.From.emplace_back(fromName);
- files.To.emplace_back(toName);
- }
- }
+ computeFilesToInstall(files, this->NamelinkMode, fromDirConfig,
+ targetNames.Output, targetNames.SharedObject,
+ targetNames.Real);
}
}
@@ -425,6 +453,12 @@ std::string cmInstallTargetGenerator::GetInstallFilename(
"${CMAKE_IMPORT_LIBRARY_SUFFIX}")) {
fname = targetNames.ImportLibrary;
}
+ } else if (nameType == NameImplibReal) {
+ // Use the import library name.
+ if (!target->GetImplibGNUtoMS(config, targetNames.ImportReal, fname,
+ "${CMAKE_IMPORT_LIBRARY_SUFFIX}")) {
+ fname = targetNames.ImportReal;
+ }
} else if (nameType == NameReal) {
// Use the canonical name.
fname = targetNames.Real;
@@ -434,11 +468,14 @@ std::string cmInstallTargetGenerator::GetInstallFilename(
}
} else {
cmGeneratorTarget::Names targetNames = target->GetLibraryNames(config);
- if (nameType == NameImplib) {
+ if (nameType == NameImplib || nameType == NameImplibReal) {
+ const auto& importName = nameType == NameImplib
+ ? targetNames.ImportLibrary
+ : targetNames.ImportReal;
// Use the import library name.
- if (!target->GetImplibGNUtoMS(config, targetNames.ImportLibrary, fname,
+ if (!target->GetImplibGNUtoMS(config, importName, fname,
"${CMAKE_IMPORT_LIBRARY_SUFFIX}")) {
- fname = targetNames.ImportLibrary;
+ fname = importName;
}
} else if (nameType == NameSO) {
// Use the soname.
diff --git a/Source/cmInstallTargetGenerator.h b/Source/cmInstallTargetGenerator.h
index 3fc4b598ca..2f41163bc7 100644
--- a/Source/cmInstallTargetGenerator.h
+++ b/Source/cmInstallTargetGenerator.h
@@ -39,6 +39,10 @@ public:
NamelinkModeSkip
};
void SetNamelinkMode(NamelinkModeType mode) { this->NamelinkMode = mode; }
+ void SetImportlinkMode(NamelinkModeType mode)
+ {
+ this->ImportlinkMode = mode;
+ }
std::string GetInstallFilename(const std::string& config) const;
@@ -50,7 +54,8 @@ public:
NameNormal,
NameImplib,
NameSO,
- NameReal
+ NameReal,
+ NameImplibReal
};
static std::string GetInstallFilename(const cmGeneratorTarget* target,
@@ -121,6 +126,7 @@ protected:
cmGeneratorTarget* Target = nullptr;
std::string const FilePermissions;
NamelinkModeType NamelinkMode;
+ NamelinkModeType ImportlinkMode;
bool const ImportLibrary;
bool const Optional;
};
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index 0271ee4a66..bd7eb3ffb9 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -85,6 +85,7 @@ static auto ruleReplaceVars = { "CMAKE_${LANG}_COMPILER",
"CMAKE_RANLIB",
"CMAKE_LINKER",
"CMAKE_MT",
+ "CMAKE_TAPI",
"CMAKE_CUDA_HOST_COMPILER",
"CMAKE_CUDA_HOST_LINK_LAUNCHER",
"CMAKE_CL_SHOWINCLUDES_PREFIX" };
@@ -134,6 +135,13 @@ cmLocalGenerator::cmLocalGenerator(cmGlobalGenerator* gg, cmMakefile* makefile)
this->LinkerSysroot = this->Makefile->GetSafeDefinition("CMAKE_SYSROOT");
}
+ // OSX SYSROOT can be required by some tools, like tapi
+ {
+ cmValue osxSysroot = this->Makefile->GetDefinition("CMAKE_OSX_SYSROOT");
+ this->VariableMappings["CMAKE_OSX_SYSROOT"] =
+ osxSysroot.IsEmpty() ? "/" : this->EscapeForShell(*osxSysroot, true);
+ }
+
if (cmValue appleArchSysroots =
this->Makefile->GetDefinition("CMAKE_APPLE_ARCH_SYSROOTS")) {
std::string const& appleArchs =
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index 2fc2974f86..33843e2916 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -2493,6 +2493,11 @@ bool cmMakefile::PlatformIsAppleEmbedded() const
return this->GetAppleSDKType() != AppleSDK::MacOS;
}
+bool cmMakefile::PlatformSupportsAppleTextStubs() const
+{
+ return this->IsOn("APPLE") && this->IsSet("CMAKE_TAPI");
+}
+
const char* cmMakefile::GetSONameFlag(const std::string& language) const
{
std::string name = "CMAKE_SHARED_LIBRARY_SONAME";
diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h
index 3cf6e61933..6f04937fa2 100644
--- a/Source/cmMakefile.h
+++ b/Source/cmMakefile.h
@@ -562,6 +562,10 @@ public:
/** Return whether the target platform is Apple iOS. */
bool PlatformIsAppleEmbedded() const;
+ /** Return whether the target platform supports generation of text base stubs
+ (.tbd file) describing exports (Apple specific). */
+ bool PlatformSupportsAppleTextStubs() const;
+
/** Retrieve soname flag for the specified language if supported */
const char* GetSONameFlag(const std::string& language) const;
diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx
index cb567ff404..c8d589d005 100644
--- a/Source/cmMakefileLibraryTargetGenerator.cxx
+++ b/Source/cmMakefileLibraryTargetGenerator.cxx
@@ -465,9 +465,20 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
std::string outpathImp;
if (this->GeneratorTarget->IsFrameworkOnApple()) {
outpath = this->GeneratorTarget->GetDirectory(this->GetConfigName());
+ cmOSXBundleGenerator::SkipParts bundleSkipParts;
+ if (this->GeneratorTarget->HasImportLibrary(this->GetConfigName())) {
+ bundleSkipParts.TextStubs = false;
+ }
this->OSXBundleGenerator->CreateFramework(this->TargetNames.Output,
- outpath, this->GetConfigName());
+ outpath, this->GetConfigName(),
+ bundleSkipParts);
outpath += '/';
+ if (!this->TargetNames.ImportLibrary.empty()) {
+ outpathImp = this->GeneratorTarget->GetDirectory(
+ this->GetConfigName(), cmStateEnums::ImportLibraryArtifact);
+ cmSystemTools::MakeDirectory(outpathImp);
+ outpathImp += '/';
+ }
} else if (this->GeneratorTarget->IsCFBundleOnApple()) {
outpath = this->GeneratorTarget->GetDirectory(this->GetConfigName());
this->OSXBundleGenerator->CreateCFBundle(this->TargetNames.Output, outpath,
@@ -679,11 +690,12 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
}
// Expand the rule variables.
+ std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander(
+ this->LocalGenerator->CreateRulePlaceholderExpander());
+ bool useWatcomQuote =
+ this->Makefile->IsOn(linkRuleVar + "_USE_WATCOM_QUOTE");
std::vector<std::string> real_link_commands;
{
- bool useWatcomQuote =
- this->Makefile->IsOn(linkRuleVar + "_USE_WATCOM_QUOTE");
-
// Set path conversion for link script shells.
this->LocalGenerator->SetLinkScriptShell(useLinkScript);
@@ -816,8 +828,6 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
launcher = cmStrCat(val, ' ');
}
- std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander(
- this->LocalGenerator->CreateRulePlaceholderExpander());
// Construct the main link rule and expand placeholders.
rulePlaceholderExpander->SetTargetImpLib(targetOutPathImport);
if (useArchiveRules) {
@@ -950,6 +960,86 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
this->WriteMakeRule(*this->BuildFileStream, nullptr, outputs, depends,
commands, false);
+ // Add rule to generate text-based stubs, if required
+ if (this->GeneratorTarget->IsApple() &&
+ this->GeneratorTarget->HasImportLibrary(this->GetConfigName())) {
+ auto genStubsRule =
+ this->Makefile->GetDefinition("CMAKE_CREATE_TEXT_STUBS");
+ auto genStubs_commands = cmExpandedList(genStubsRule);
+
+ std::string TBDFullPath =
+ cmStrCat(outpathImp, this->TargetNames.ImportOutput);
+ std::string TBDFullPathReal =
+ cmStrCat(outpathImp, this->TargetNames.ImportReal);
+ std::string TBDFullPathSO =
+ cmStrCat(outpathImp, this->TargetNames.ImportLibrary);
+
+ // Expand placeholders.
+ cmRulePlaceholderExpander::RuleVariables vars;
+ std::string target = this->LocalGenerator->ConvertToOutputFormat(
+ this->LocalGenerator->MaybeRelativeToCurBinDir(targetFullPathReal),
+ cmOutputConverter::SHELL, useWatcomQuote);
+ vars.Target = target.c_str();
+ std::string TBDOutPathReal = this->LocalGenerator->ConvertToOutputFormat(
+ this->LocalGenerator->MaybeRelativeToCurBinDir(TBDFullPathReal),
+ cmOutputConverter::SHELL, useWatcomQuote);
+ rulePlaceholderExpander->SetTargetImpLib(TBDOutPathReal);
+ for (std::string& command : genStubs_commands) {
+ rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator,
+ command, vars);
+ }
+ outputs.clear();
+ outputs.push_back(TBDFullPathReal);
+ if (this->TargetNames.ImportLibrary != this->TargetNames.ImportReal) {
+ outputs.push_back(TBDFullPathSO);
+ }
+ if (this->TargetNames.ImportOutput != this->TargetNames.ImportLibrary &&
+ this->TargetNames.ImportOutput != this->TargetNames.ImportReal) {
+ outputs.push_back(TBDFullPath);
+ }
+ this->ExtraFiles.insert(TBDFullPath);
+
+ depends.clear();
+ depends.push_back(targetFullPathReal);
+
+ // Add a rule to create necessary symlinks for the library.
+ // Frameworks are handled by cmOSXBundleGenerator.
+ if (TBDFullPath != TBDFullPathReal &&
+ !this->GeneratorTarget->IsFrameworkOnApple()) {
+ auto TBDOutPathSO = this->LocalGenerator->ConvertToOutputFormat(
+ this->LocalGenerator->MaybeRelativeToCurBinDir(TBDFullPathSO),
+ cmOutputConverter::SHELL, useWatcomQuote);
+ auto TBDOutPath = this->LocalGenerator->ConvertToOutputFormat(
+ this->LocalGenerator->MaybeRelativeToCurBinDir(TBDFullPath),
+ cmOutputConverter::SHELL, useWatcomQuote);
+
+ std::string symlink =
+ cmStrCat("$(CMAKE_COMMAND) -E cmake_symlink_library ", TBDOutPathReal,
+ ' ', TBDOutPathSO, ' ', TBDOutPath);
+ commands1.push_back(std::move(symlink));
+ this->LocalGenerator->CreateCDCommand(
+ commands1, this->Makefile->GetCurrentBinaryDirectory(),
+ this->LocalGenerator->GetBinaryDirectory());
+ cm::append(genStubs_commands, commands1);
+ commands1.clear();
+ }
+
+ this->WriteMakeRule(*this->BuildFileStream, nullptr, outputs, depends,
+ genStubs_commands, false);
+
+ // clean actions for apple specific outputs
+ // clean actions for ImportLibrary are already specified
+ if (this->TargetNames.ImportReal != this->TargetNames.ImportLibrary) {
+ libCleanFiles.insert(
+ this->LocalGenerator->MaybeRelativeToCurBinDir(TBDFullPathReal));
+ }
+ if (this->TargetNames.ImportOutput != this->TargetNames.ImportReal &&
+ this->TargetNames.ImportOutput != this->TargetNames.ImportLibrary) {
+ libCleanFiles.insert(
+ this->LocalGenerator->MaybeRelativeToCurBinDir(TBDFullPath));
+ }
+ }
+
// Write the main driver rule to build everything in this target.
this->WriteTargetDriverRule(targetFullPath, relink);
diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx
index 45a4dda1d2..4d68460521 100644
--- a/Source/cmNinjaNormalTargetGenerator.cxx
+++ b/Source/cmNinjaNormalTargetGenerator.cxx
@@ -204,6 +204,15 @@ std::string cmNinjaNormalTargetGenerator::LanguageLinkerCudaFatbinaryRule(
'_', config);
}
+std::string cmNinjaNormalTargetGenerator::TextStubsGeneratorRule(
+ const std::string& config) const
+{
+ return cmStrCat(
+ "TEXT_STUBS_GENERATOR__",
+ cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName()),
+ '_', config);
+}
+
struct cmNinjaRemoveNoOpCommands
{
bool operator()(std::string const& cmd)
@@ -527,6 +536,45 @@ void cmNinjaNormalTargetGenerator::WriteLinkRule(bool useResponseFile,
this->GetGlobalGenerator()->AddRule(rule);
}
}
+
+ if (this->GetGeneratorTarget()->IsApple() &&
+ this->GetGeneratorTarget()->HasImportLibrary(config)) {
+ cmNinjaRule rule(this->TextStubsGeneratorRule(config));
+ rule.Comment = cmStrCat("Rule for generating text-based stubs for ",
+ this->GetVisibleTypeName(), '.');
+ rule.Description = "Creating text-based stubs $out";
+
+ std::string cmd =
+ this->GetMakefile()->GetDefinition("CMAKE_CREATE_TEXT_STUBS");
+ std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander(
+ this->GetLocalGenerator()->CreateRulePlaceholderExpander());
+ cmRulePlaceholderExpander::RuleVariables vars;
+ vars.Target = "$in";
+ rulePlaceholderExpander->SetTargetImpLib("$out");
+ rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(),
+ cmd, vars);
+
+ rule.Command =
+ this->GetLocalGenerator()->BuildCommandLine({ cmd }, config, config);
+ this->GetGlobalGenerator()->AddRule(rule);
+
+ if (tgtNames.ImportOutput != tgtNames.ImportReal &&
+ !this->GetGeneratorTarget()->IsFrameworkOnApple()) {
+ cmNinjaRule slRule("CMAKE_SYMLINK_IMPORT_LIBRARY");
+ {
+ std::string cmakeCommand =
+ this->GetLocalGenerator()->ConvertToOutputFormat(
+ cmSystemTools::GetCMakeCommand(), cmOutputConverter::SHELL);
+ std::string slCmd =
+ cmStrCat(cmakeCommand, " -E cmake_symlink_library $in $SONAME $out");
+ slRule.Command = this->GetLocalGenerator()->BuildCommandLine(
+ { slCmd }, config, config);
+ }
+ slRule.Description = "Creating import library symlink $out";
+ slRule.Comment = "Rule for creating import library symlink.";
+ this->GetGlobalGenerator()->AddRule(slRule);
+ }
+ }
}
std::vector<std::string> cmNinjaNormalTargetGenerator::ComputeDeviceLinkCmd()
@@ -1030,9 +1078,12 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement(
// the current configuration has a postfix. The non-postfix configuration
// Info.plist can be used by all the other configurations.
if (!postFix.empty()) {
- bundleSkipParts.infoPlist = true;
+ bundleSkipParts.InfoPlist = true;
}
}
+ if (gt->HasImportLibrary(config)) {
+ bundleSkipParts.TextStubs = false;
+ }
this->OSXBundleGenerator->CreateFramework(
tgtNames.Output, gt->GetDirectory(config), config, bundleSkipParts);
@@ -1214,7 +1265,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement(
cmGlobalNinjaGenerator::CCOutputs byproducts(this->GetGlobalGenerator());
- if (!tgtNames.ImportLibrary.empty()) {
+ if (!gt->IsApple() && !tgtNames.ImportLibrary.empty()) {
const std::string impLibPath = localGen.ConvertToOutputFormat(
targetOutputImplib, cmOutputConverter::SHELL);
vars["TARGET_IMPLIB"] = impLibPath;
@@ -1471,6 +1522,55 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement(
// Add aliases for the file name and the target name.
globalGen->AddTargetAlias(tgtNames.Output, gt, config);
globalGen->AddTargetAlias(this->GetTargetName(), gt, config);
+
+ if (this->GetGeneratorTarget()->IsApple() &&
+ this->GetGeneratorTarget()->HasImportLibrary(config)) {
+ auto dirTBD =
+ gt->GetDirectory(config, cmStateEnums::ImportLibraryArtifact);
+ auto targetTBD =
+ this->ConvertToNinjaPath(cmStrCat(dirTBD, '/', tgtNames.ImportReal));
+ this->EnsureParentDirectoryExists(targetTBD);
+ cmNinjaBuild build(this->TextStubsGeneratorRule(config));
+ build.Comment = cmStrCat("Generate the text-based stubs file ", targetTBD);
+ build.Outputs.push_back(targetTBD);
+ build.ExplicitDeps.push_back(targetOutputReal);
+ globalGen->WriteBuild(this->GetImplFileStream(fileConfig), build);
+
+ if (tgtNames.ImportOutput != tgtNames.ImportReal &&
+ !this->GetGeneratorTarget()->IsFrameworkOnApple()) {
+ auto outputTBD =
+ this->ConvertToNinjaPath(cmStrCat(dirTBD, '/', tgtNames.ImportOutput));
+ std::string const soNameTBD = this->ConvertToNinjaPath(
+ cmStrCat(dirTBD, '/', tgtNames.ImportLibrary));
+
+ cmNinjaBuild slBuild("CMAKE_SYMLINK_IMPORT_LIBRARY");
+ slBuild.Comment = cmStrCat("Create import library symlink ", outputTBD);
+ cmNinjaVars slVars;
+
+ // If one link has to be created.
+ if (targetTBD == soNameTBD || outputTBD == soNameTBD) {
+ slVars["SONAME"] = this->GetLocalGenerator()->ConvertToOutputFormat(
+ soNameTBD, cmOutputConverter::SHELL);
+ } else {
+ slVars["SONAME"].clear();
+ slBuild.Outputs.push_back(soNameTBD);
+ if (firstForConfig) {
+ globalGen->GetByproductsForCleanTarget(config).push_back(soNameTBD);
+ }
+ }
+ slBuild.Outputs.push_back(outputTBD);
+ if (firstForConfig) {
+ globalGen->GetByproductsForCleanTarget(config).push_back(outputTBD);
+ }
+ slBuild.ExplicitDeps.push_back(targetTBD);
+ slBuild.Variables = std::move(slVars);
+
+ globalGen->WriteBuild(this->GetImplFileStream(fileConfig), slBuild);
+ }
+
+ // Add alias for the import file name
+ globalGen->AddTargetAlias(tgtNames.ImportOutput, gt, config);
+ }
}
void cmNinjaNormalTargetGenerator::WriteObjectLibStatement(
diff --git a/Source/cmNinjaNormalTargetGenerator.h b/Source/cmNinjaNormalTargetGenerator.h
index 30127fe8b5..85f42a4487 100644
--- a/Source/cmNinjaNormalTargetGenerator.h
+++ b/Source/cmNinjaNormalTargetGenerator.h
@@ -25,6 +25,7 @@ private:
std::string LanguageLinkerCudaDeviceCompileRule(
const std::string& config) const;
std::string LanguageLinkerCudaFatbinaryRule(const std::string& config) const;
+ std::string TextStubsGeneratorRule(const std::string& config) const;
const char* GetVisibleTypeName() const;
void WriteLanguagesRules(const std::string& config);
diff --git a/Source/cmOSXBundleGenerator.cxx b/Source/cmOSXBundleGenerator.cxx
index 674735b9c0..4301f052f8 100644
--- a/Source/cmOSXBundleGenerator.cxx
+++ b/Source/cmOSXBundleGenerator.cxx
@@ -11,6 +11,7 @@
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
#include "cmTarget.h"
+#include "cmValue.h"
class cmSourceFile;
@@ -77,7 +78,7 @@ void cmOSXBundleGenerator::CreateFramework(
std::string frameworkVersion = this->GT->GetFrameworkVersion();
std::string name = cmSystemTools::GetFilenameName(targetName);
- if (!skipParts.infoPlist) {
+ if (!skipParts.InfoPlist) {
// Configure the Info.plist file
std::string plist = newoutpath;
if (!this->Makefile->PlatformIsAppleEmbedded()) {
@@ -120,6 +121,17 @@ void cmOSXBundleGenerator::CreateFramework(
cmSystemTools::CreateSymlink(oldName, newName);
this->Makefile->AddCMakeOutputFile(newName);
+ if (!skipParts.TextStubs) {
+ // foo.tbd -> Versions/Current/foo.tbd
+ cmValue tbdSuffix =
+ this->Makefile->GetDefinition("CMAKE_APPLE_IMPORT_FILE_SUFFIX");
+ oldName = cmStrCat("Versions/Current/", name, tbdSuffix);
+ newName = cmStrCat(contentdir, name, tbdSuffix);
+ cmSystemTools::RemoveFile(newName);
+ cmSystemTools::CreateSymlink(oldName, newName);
+ this->Makefile->AddCMakeOutputFile(newName);
+ }
+
// Resources -> Versions/Current/Resources
if (this->MacContentFolders->find("Resources") !=
this->MacContentFolders->end()) {
diff --git a/Source/cmOSXBundleGenerator.h b/Source/cmOSXBundleGenerator.h
index c33b08720f..38453fd3d7 100644
--- a/Source/cmOSXBundleGenerator.h
+++ b/Source/cmOSXBundleGenerator.h
@@ -20,11 +20,10 @@ public:
struct SkipParts
{
- SkipParts()
- : infoPlist(false)
- {
- }
- bool infoPlist; // NOLINT(modernize-use-default-member-init)
+ SkipParts() {} // NOLINT(modernize-use-equals-default)
+
+ bool InfoPlist = false;
+ bool TextStubs = true;
};
// create an app bundle at a given root, and return
@@ -35,7 +34,7 @@ public:
// create a framework at a given root
void CreateFramework(const std::string& targetName, const std::string& root,
const std::string& config,
- const SkipParts& skipParts = SkipParts());
+ const SkipParts& skipParts = SkipParts{});
// create a cf bundle at a given root
void CreateCFBundle(const std::string& targetName, const std::string& root,
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index 9ae25762b1..f4e859c845 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -445,7 +445,7 @@ TargetProperty const StaticTargetProperties[] = {
{ "AUTORCC_OPTIONS"_s, IC::CanCompileSources },
// Linking properties
- { "ENABLE_EXPORTS"_s, IC::ExecutableTarget },
+ { "ENABLE_EXPORTS"_s, IC::TargetWithSymbolExports },
{ "LINK_LIBRARIES_ONLY_TARGETS"_s, IC::NormalNonImportedTarget },
{ "LINK_SEARCH_START_STATIC"_s, IC::CanCompileSources },
{ "LINK_SEARCH_END_STATIC"_s, IC::CanCompileSources },
@@ -1031,6 +1031,31 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
defKey += "CMAKE_";
auto initProperty = [this, mf, &defKey](const std::string& property,
const char* default_value) {
+ // special init for ENABLE_EXPORTS
+ // For SHARED_LIBRARY, only CMAKE_SHARED_LIBRARY_ENABLE_EXPORTS variable
+ // is used
+ // For EXECUTABLE, CMAKE_EXECUTABLE_ENABLE_EXPORTS or else
+ // CMAKE_ENABLE_EXPORTS variables are used
+ if (property == "ENABLE_EXPORTS"_s) {
+ // Replace everything after "CMAKE_"
+ defKey.replace(
+ defKey.begin() + 6, defKey.end(),
+ cmStrCat(this->impl->TargetType == cmStateEnums::EXECUTABLE
+ ? "EXECUTABLE"
+ : "SHARED_LIBRARY",
+ '_', property));
+ if (cmValue value = mf->GetDefinition(defKey)) {
+ this->SetProperty(property, value);
+ return;
+ }
+ if (this->impl->TargetType == cmStateEnums::SHARED_LIBRARY) {
+ if (default_value) {
+ this->SetProperty(property, default_value);
+ }
+ return;
+ }
+ }
+
// Replace everything after "CMAKE_"
defKey.replace(defKey.begin() + 6, defKey.end(), property);
if (cmValue value = mf->GetDefinition(defKey)) {
@@ -1205,6 +1230,12 @@ bool cmTarget::IsExecutableWithExports() const
this->GetPropertyAsBool("ENABLE_EXPORTS"));
}
+bool cmTarget::IsSharedLibraryWithExports() const
+{
+ return (this->GetType() == cmStateEnums::SHARED_LIBRARY &&
+ this->GetPropertyAsBool("ENABLE_EXPORTS"));
+}
+
bool cmTarget::IsFrameworkOnApple() const
{
return ((this->GetType() == cmStateEnums::SHARED_LIBRARY ||
@@ -2657,7 +2688,8 @@ const char* cmTarget::GetSuffixVariableInternal(
case cmStateEnums::RuntimeBinaryArtifact:
return "CMAKE_SHARED_LIBRARY_SUFFIX";
case cmStateEnums::ImportLibraryArtifact:
- return "CMAKE_IMPORT_LIBRARY_SUFFIX";
+ return this->IsApple() ? "CMAKE_APPLE_IMPORT_FILE_SUFFIX"
+ : "CMAKE_IMPORT_LIBRARY_SUFFIX";
}
break;
case cmStateEnums::MODULE_LIBRARY:
@@ -2698,7 +2730,8 @@ const char* cmTarget::GetPrefixVariableInternal(
case cmStateEnums::RuntimeBinaryArtifact:
return "CMAKE_SHARED_LIBRARY_PREFIX";
case cmStateEnums::ImportLibraryArtifact:
- return "CMAKE_IMPORT_LIBRARY_PREFIX";
+ return this->IsApple() ? "CMAKE_APPLE_IMPORT_FILE_PREFIX"
+ : "CMAKE_IMPORT_LIBRARY_PREFIX";
}
break;
case cmStateEnums::MODULE_LIBRARY:
diff --git a/Source/cmTarget.h b/Source/cmTarget.h
index 95523f4833..24f6fcdb2d 100644
--- a/Source/cmTarget.h
+++ b/Source/cmTarget.h
@@ -221,6 +221,10 @@ public:
//! Return whether this target is an executable with symbol exports enabled.
bool IsExecutableWithExports() const;
+ //! Return whether this target is a shared library with symbol exports
+ //! enabled.
+ bool IsSharedLibraryWithExports() const;
+
//! Return whether this target is a shared library Framework on Apple.
bool IsFrameworkOnApple() const;
diff --git a/Tests/RunCMake/AppleTextStubs/CMakeLists.txt b/Tests/RunCMake/AppleTextStubs/CMakeLists.txt
new file mode 100644
index 0000000000..93ee9dfd5f
--- /dev/null
+++ b/Tests/RunCMake/AppleTextStubs/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.5)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/AppleTextStubs/Framework-export.cmake b/Tests/RunCMake/AppleTextStubs/Framework-export.cmake
new file mode 100644
index 0000000000..f75c6d1ed2
--- /dev/null
+++ b/Tests/RunCMake/AppleTextStubs/Framework-export.cmake
@@ -0,0 +1,12 @@
+enable_language(C)
+
+add_library(foo SHARED foo.c)
+set_property(TARGET foo PROPERTY FRAMEWORK TRUE)
+set_property(TARGET foo PROPERTY ENABLE_EXPORTS TRUE)
+set_property(TARGET foo PROPERTY LIBRARY_OUTPUT_DIRECTORY $<CONFIG>)
+
+install(TARGETS foo EXPORT foo FRAMEWORK DESTINATION DESTINATION "${CMAKE_BINARY_DIR}/$<CONFIG>")
+install(EXPORT foo DESTINATION lib/foo NAMESPACE foo-install::)
+install(FILES foo-config.cmake.in RENAME foo-config.cmake DESTINATION lib/foo)
+
+export(TARGETS foo NAMESPACE foo-build:: FILE Release/foo.cmake)
diff --git a/Tests/RunCMake/AppleTextStubs/Framework-import.cmake b/Tests/RunCMake/AppleTextStubs/Framework-import.cmake
new file mode 100644
index 0000000000..e0001d0b84
--- /dev/null
+++ b/Tests/RunCMake/AppleTextStubs/Framework-import.cmake
@@ -0,0 +1,62 @@
+enable_language(C)
+
+find_package(foo REQUIRED CONFIG NO_DEFAULT_PATH)
+
+add_executable(main main.c)
+target_link_libraries(main PRIVATE foo-install::foo)
+
+get_property(is_framework TARGET foo-install::foo PROPERTY FRAMEWORK)
+if (NOT is_framework)
+ message(SEND_ERROR "foo-build::foo: FRAMEWORK not set.")
+endif()
+get_property(enable_exports TARGET foo-install::foo PROPERTY ENABLE_EXPORTS)
+if (CAMKE_TAPI AND NOT enable_exports)
+ message(SEND_ERROR "foo-install::foo: ENABLE_EXPORTS not set.")
+endif()
+
+get_property(implib TARGET foo-install::foo PROPERTY IMPORTED_IMPLIB_RELEASE)
+if (CAMKE_TAPI AND NOT implib)
+ message(SEND_ERROR "foo-install::foo: IMPORTED_IMPLIB_RELEASE not set.")
+endif()
+if (CAMKE_TAPI AND NOT implib MATCHES "foo.framework/Versions/A/foo.tbd$")
+ message(SEND_ERROR "foo-install::foo: ${implib}: wrong value for IMPORTED_IMPLIB_RELEASE.")
+endif()
+
+get_property(location TARGET foo-install::foo PROPERTY IMPORTED_LOCATION_RELEASE)
+if (NOT location)
+ message(SEND_ERROR "foo-install::foo: IMPORTED_LOCATION_RELEASE not set.")
+endif()
+if (NOT location MATCHES "foo.framework/Versions/A/foo$")
+ message(SEND_ERROR "foo-install::foo: ${location}: wrong value for IMPORTED_LOCATION_RELEASE.")
+endif()
+
+
+include(${foo_BUILD}/foo.cmake)
+
+add_executable(main2 main.c)
+target_link_libraries(main2 PRIVATE foo-build::foo)
+
+get_property(is_framework TARGET foo-build::foo PROPERTY FRAMEWORK)
+if (NOT is_framework)
+ message(SEND_ERROR "foo-build::foo: FRAMEWORK not set.")
+endif()
+get_property(enable_exports TARGET foo-build::foo PROPERTY ENABLE_EXPORTS)
+if (CAMKE_TAPI AND NOT enable_exports)
+ message(SEND_ERROR "foo-build::foo: ENABLE_EXPORTS not set.")
+endif()
+
+get_property(implib TARGET foo-build::foo PROPERTY IMPORTED_IMPLIB_RELEASE)
+if (CAMKE_TAPI AND NOT implib)
+ message(SEND_ERROR "foo-build::foo: IMPORTED_IMPLIB_RELEASE not set.")
+endif()
+if (CAMKE_TAPI AND NOT implib STREQUAL "${foo_BUILD}/foo.framework/Versions/A/foo.tbd")
+ message(SEND_ERROR "foo-build::foo: ${implib}: wrong value for IMPORTED_IMPLIB_RELEASE.")
+endif()
+
+get_property(location TARGET foo-build::foo PROPERTY IMPORTED_LOCATION_RELEASE)
+if (NOT location)
+ message(SEND_ERROR "foo-build::foo: IMPORTED_LOCATION_RELEASE not set.")
+endif()
+if (NOT location STREQUAL "${foo_BUILD}/foo.framework/Versions/A/foo")
+ message(SEND_ERROR "foo-build::foo: ${location}: wrong value for IMPORTED_LOCATION_RELEASE.")
+endif()
diff --git a/Tests/RunCMake/AppleTextStubs/Framework-install-check.cmake b/Tests/RunCMake/AppleTextStubs/Framework-install-check.cmake
new file mode 100644
index 0000000000..e8a555773c
--- /dev/null
+++ b/Tests/RunCMake/AppleTextStubs/Framework-install-check.cmake
@@ -0,0 +1 @@
+include ("${RunCMake_TEST_BINARY_DIR}/Framework-Release-generated.cmake")
diff --git a/Tests/RunCMake/AppleTextStubs/Framework.cmake b/Tests/RunCMake/AppleTextStubs/Framework.cmake
new file mode 100644
index 0000000000..f99eb5e813
--- /dev/null
+++ b/Tests/RunCMake/AppleTextStubs/Framework.cmake
@@ -0,0 +1,59 @@
+enable_language(C)
+
+add_library(foo SHARED foo.c)
+set_property(TARGET foo PROPERTY ENABLE_EXPORTS TRUE)
+set_property(TARGET foo PROPERTY FRAMEWORK TRUE)
+
+add_executable(main main.c)
+target_link_libraries(main PRIVATE foo)
+
+
+install(TARGETS foo FRAMEWORK DESTINATION "${CMAKE_BINARY_DIR}/INSTALL")
+
+# LIBRARY and ARCHIVE should be ignored
+install(TARGETS foo FRAMEWORK DESTINATION "${CMAKE_BINARY_DIR}/INSTALL2"
+ LIBRARY DESTINATION "${CMAKE_BINARY_DIR}/INSTALL2/lib"
+ ARCHIVE DESTINATION "${CMAKE_BINARY_DIR}/INSTALL2/dev")
+
+
+set (GENERATE_CONTENT "if (\"${CMAKE_TAPI}\")
+ set (APPLE_TEXT_STUBS_SUPPORTED TRUE)
+endif()\n\n")
+
+string (APPEND GENERATE_CONTENT [[
+macro (CHECK_FILE test_msg path)
+ if (NOT EXISTS "${path}")
+ string (APPEND RunCMake_TEST_FAILED "${test_msg}: \"${path}\" not found\n")
+ endif()
+endmacro()
+
+macro (CHECK_SYMLINK test_msg path)
+ if(NOT IS_SYMLINK "${path}")
+ string (APPEND RunCMake_TEST_FAILED "${test_msg}: \"${path}\" is not a symbolic link\n")
+ elseif (NOT EXISTS "${path}")
+ string (APPEND RunCMake_TEST_FAILED "${test_msg}: \"${path}\" is not a valid symlink\n")
+ endif()
+endmacro()
+
+check_file("DYLIB file" "$<TARGET_FILE:foo>")
+check_symlink("Public DYLIB file" "$<TARGET_LINKER_LIBRARY_FILE:foo>")
+check_file("executable file" "$<TARGET_FILE:main>")
+
+check_file("Installed DYLIB file" "${RunCMake_TEST_BINARY_DIR}/INSTALL/foo.framework/Versions/A/$<TARGET_FILE_NAME:foo>")
+check_symlink("Installed Public DULIB file" "${RunCMake_TEST_BINARY_DIR}/INSTALL/foo.framework/$<TARGET_FILE_NAME:foo>")
+check_file("Installed DULIB file" "${RunCMake_TEST_BINARY_DIR}/INSTALL2/foo.framework/Versions/A/$<TARGET_FILE_NAME:foo>")
+check_symlink("Installed Public DYLIB file" "${RunCMake_TEST_BINARY_DIR}/INSTALL2/foo.framework/$<TARGET_FILE_NAME:foo>")
+
+if (APPLE_TEXT_STUBS_SUPPORTED)
+ check_file("TBD file" "$<TARGET_IMPORT_FILE:foo>")
+ check_symlink("Public TBD file" "$<TARGET_LINKER_IMPORT_FILE:foo>")
+
+ check_file("Installed TBD file" "${RunCMake_TEST_BINARY_DIR}/INSTALL/foo.framework/Versions/A/$<TARGET_IMPORT_FILE_NAME:foo>")
+ check_symlink("Installed Public TBD file" "${RunCMake_TEST_BINARY_DIR}/INSTALL/foo.framework/$<TARGET_IMPORT_FILE_NAME:foo>")
+ check_file("Installed TBD file" "${RunCMake_TEST_BINARY_DIR}/INSTALL2/foo.framework/Versions/A/$<TARGET_IMPORT_FILE_NAME:foo>")
+ check_symlink("Installed Public TBD file" "${RunCMake_TEST_BINARY_DIR}/INSTALL2/foo.framework/$<TARGET_IMPORT_FILE_NAME:foo>")
+endif()
+]])
+
+file (GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Framework-$<CONFIG>-generated.cmake"
+ CONTENT "${GENERATE_CONTENT}")
diff --git a/Tests/RunCMake/AppleTextStubs/Library-export.cmake b/Tests/RunCMake/AppleTextStubs/Library-export.cmake
new file mode 100644
index 0000000000..d2e09ea35d
--- /dev/null
+++ b/Tests/RunCMake/AppleTextStubs/Library-export.cmake
@@ -0,0 +1,12 @@
+enable_language(C)
+
+add_library(foo SHARED foo.c)
+set_property(TARGET foo PROPERTY ENABLE_EXPORTS TRUE)
+set_property(TARGET foo PROPERTY LIBRARY_OUTPUT_DIRECTORY $<CONFIG>)
+set_property(TARGET foo PROPERTY ARCHIVE_OUTPUT_DIRECTORY $<CONFIG>)
+
+install(TARGETS foo EXPORT foo DESTINATION "${CMAKE_BINARY_DIR}/$<CONFIG>")
+install(EXPORT foo DESTINATION lib/foo NAMESPACE foo-install::)
+install(FILES foo-config.cmake.in RENAME foo-config.cmake DESTINATION lib/foo)
+
+export(TARGETS foo NAMESPACE foo-build:: FILE Release/foo.cmake)
diff --git a/Tests/RunCMake/AppleTextStubs/Library-import.cmake b/Tests/RunCMake/AppleTextStubs/Library-import.cmake
new file mode 100644
index 0000000000..9406aacac0
--- /dev/null
+++ b/Tests/RunCMake/AppleTextStubs/Library-import.cmake
@@ -0,0 +1,54 @@
+enable_language(C)
+
+find_package(foo REQUIRED CONFIG NO_DEFAULT_PATH)
+
+add_executable(main main.c)
+target_link_libraries(main PRIVATE foo-install::foo)
+
+get_property(enable_exports TARGET foo-install::foo PROPERTY ENABLE_EXPORTS)
+if (CMAKE_TAPI AND NOT enable_exports)
+ message(SEND_ERROR "foo-install::foo: ENABLE_EXPORTS not set.")
+endif()
+
+get_property(implib TARGET foo-install::foo PROPERTY IMPORTED_IMPLIB_RELEASE)
+if (CMAKE_TAPI AND NOT implib)
+ message(SEND_ERROR "foo-install::foo: IMPORTED_IMPLIB_RELEASE not set.")
+endif()
+if (CMAKE_TAPI AND NOT implib MATCHES "Release/libfoo.tbd$")
+ message(SEND_ERROR "foo-install::foo: ${implib}: wrong value for IMPORTED_IMPLIB_RELEASE.")
+endif()
+
+get_property(location TARGET foo-install::foo PROPERTY IMPORTED_LOCATION_RELEASE)
+if (NOT location)
+ message(SEND_ERROR "foo-install::foo: IMPORTED_LOCATION_RELEASE not set.")
+endif()
+if (NOT location MATCHES "Release/libfoo.dylib$")
+ message(SEND_ERROR "foo-install::foo: ${location}: wrong value for IMPORTED_LOCATION_RELEASE.")
+endif()
+
+
+include(${foo_BUILD}/foo.cmake)
+
+add_executable(main2 main.c)
+target_link_libraries(main2 PRIVATE foo-build::foo)
+
+get_property(enable_exports TARGET foo-build::foo PROPERTY ENABLE_EXPORTS)
+if (CMAKE_TAPI AND NOT enable_exports)
+ message(SEND_ERROR "foo-build::foo: ENABLE_EXPORTS not set.")
+endif()
+
+get_property(implib TARGET foo-build::foo PROPERTY IMPORTED_IMPLIB_RELEASE)
+if (CMAKE_TAPI AND NOT implib)
+ message(SEND_ERROR "foo-build::foo: IMPORTED_IMPLIB_RELEASE not set.")
+endif()
+if (CMAKE_TAPI AND NOT implib STREQUAL "${foo_BUILD}/libfoo.tbd")
+ message(SEND_ERROR "foo-build::foo: ${implib}: wrong value for IMPORTED_IMPLIB_RELEASE.")
+endif()
+
+get_property(location TARGET foo-build::foo PROPERTY IMPORTED_LOCATION_RELEASE)
+if (NOT location)
+ message(SEND_ERROR "foo-build::foo: IMPORTED_LOCATION_RELEASE not set.")
+endif()
+if (NOT location STREQUAL "${foo_BUILD}/libfoo.dylib")
+ message(SEND_ERROR "foo-build::foo: ${location}: wrong value for IMPORTED_LOCATION_RELEASE.")
+endif()
diff --git a/Tests/RunCMake/AppleTextStubs/LibraryWithOutputs-install-check.cmake b/Tests/RunCMake/AppleTextStubs/LibraryWithOutputs-install-check.cmake
new file mode 100644
index 0000000000..40ec0a6ffc
--- /dev/null
+++ b/Tests/RunCMake/AppleTextStubs/LibraryWithOutputs-install-check.cmake
@@ -0,0 +1 @@
+include ("${RunCMake_TEST_BINARY_DIR}/LibraryWithOutputs-Release-generated.cmake")
diff --git a/Tests/RunCMake/AppleTextStubs/LibraryWithOutputs.cmake b/Tests/RunCMake/AppleTextStubs/LibraryWithOutputs.cmake
new file mode 100644
index 0000000000..f61c8f2a7e
--- /dev/null
+++ b/Tests/RunCMake/AppleTextStubs/LibraryWithOutputs.cmake
@@ -0,0 +1,52 @@
+enable_language(C)
+
+add_library(foo SHARED foo.c)
+set_property(TARGET foo PROPERTY ENABLE_EXPORTS TRUE)
+set_property(TARGET foo PROPERTY ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/TBD/$<CONFIG>")
+set_property(TARGET foo PROPERTY ARCHIVE_OUTPUT_NAME "tbd")
+
+add_executable(main main.c)
+target_link_libraries(main PRIVATE foo)
+
+
+set (GENERATE_CONTENT "if (\"${CMAKE_TAPI}\")
+ set (APPLE_TEXT_STUBS_SUPPORTED TRUE)
+endif()\n\n")
+
+string (APPEND GENERATE_CONTENT [[
+macro (CHECK_FILE test_msg path)
+ if (NOT EXISTS "${path}")
+ string (APPEND RunCMake_TEST_FAILED "${test_msg}: \"${path}\" not found\n")
+ endif()
+endmacro()
+
+check_file("DYLIB file" "$<TARGET_FILE:foo>")
+check_file("executable file" "$<TARGET_FILE:main>")
+
+if (APPLE_TEXT_STUBS_SUPPORTED)
+ check_file("TBD file" "$<TARGET_IMPORT_FILE:foo>")
+]])
+
+if (CMAKE_GENERATOR STREQUAL "Xcode")
+ # ARCHIVE outputs are ignored by this generator
+ string (APPEND GENERATE_CONTENT
+ "\n if (NOT \"$<TARGET_IMPORT_FILE_DIR:foo>\" STREQUAL \"${CMAKE_BINARY_DIR}/$<CONFIG>\")
+ string (APPEND RunCMake_TEST_FAILED \"Wrong directory for TBD file: \\\"$<TARGET_IMPORT_FILE_DIR:foo>\\\"\n\")
+ endif()
+ if (NOT \"$<TARGET_IMPORT_FILE_BASE_NAME:foo>\" STREQUAL \"foo\")
+ string (APPEND RunCMake_TEST_FAILED \"Wrong base name for TBD file: \\\"$<TARGET_IMPORT_FILE_BASE_NAME:foo>\\\"\n\")
+ endif()\n")
+else()
+ string (APPEND GENERATE_CONTENT
+ "\n if (NOT \"$<TARGET_IMPORT_FILE_DIR:foo>\" STREQUAL \"${CMAKE_BINARY_DIR}/TBD/$<CONFIG>\")
+ string (APPEND RunCMake_TEST_FAILED \"Wrong directory for TBD file: \\\"$<TARGET_IMPORT_FILE_DIR:foo>\\\"\n\")
+ endif()
+ if (NOT \"$<TARGET_IMPORT_FILE_BASE_NAME:foo>\" STREQUAL \"tbd\")
+ string (APPEND RunCMake_TEST_FAILED \"Wrong base name for TBD file: \\\"$<TARGET_IMPORT_FILE_BASE_NAME:foo>\\\"\n\")
+ endif()\n")
+endif()
+string (APPEND GENERATE_CONTENT "endif()\n")
+
+
+file (GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/LibraryWithOutputs-$<CONFIG>-generated.cmake"
+ CONTENT "${GENERATE_CONTENT}")
diff --git a/Tests/RunCMake/AppleTextStubs/LibraryWithVersions-install-check.cmake b/Tests/RunCMake/AppleTextStubs/LibraryWithVersions-install-check.cmake
new file mode 100644
index 0000000000..af7328610b
--- /dev/null
+++ b/Tests/RunCMake/AppleTextStubs/LibraryWithVersions-install-check.cmake
@@ -0,0 +1 @@
+include ("${RunCMake_TEST_BINARY_DIR}/LibraryWithVersions-Release-generated.cmake")
diff --git a/Tests/RunCMake/AppleTextStubs/LibraryWithVersions.cmake b/Tests/RunCMake/AppleTextStubs/LibraryWithVersions.cmake
new file mode 100644
index 0000000000..28c175df31
--- /dev/null
+++ b/Tests/RunCMake/AppleTextStubs/LibraryWithVersions.cmake
@@ -0,0 +1,96 @@
+enable_language(C)
+
+add_library(foo SHARED foo.c)
+set_property(TARGET foo PROPERTY ENABLE_EXPORTS TRUE)
+set_property (TARGET foo PROPERTY VERSION 2.5.0)
+set_property (TARGET foo PROPERTY SOVERSION 2.0.0)
+
+add_executable(main main.c)
+target_link_libraries(main PRIVATE foo)
+
+
+install(TARGETS foo DESTINATION "${CMAKE_BINARY_DIR}/INSTALL" COMPONENT default)
+
+install(TARGETS foo ARCHIVE DESTINATION "${CMAKE_BINARY_DIR}/INSTALL2/dev1" NAMELINK_SKIP COMPONENT default)
+install(TARGETS foo ARCHIVE DESTINATION "${CMAKE_BINARY_DIR}/INSTALL2/dev2" NAMELINK_ONLY COMPONENT default)
+
+install(TARGETS foo ARCHIVE DESTINATION "${CMAKE_BINARY_DIR}/INSTALL3"
+ COMPONENT lib3 NAMELINK_COMPONENT dev3)
+install(TARGETS foo ARCHIVE DESTINATION "${CMAKE_BINARY_DIR}/INSTALL4"
+ COMPONENT lib4 NAMELINK_COMPONENT dev4)
+
+
+set (GENERATE_CONTENT "if (\"${CMAKE_TAPI}\")
+ set (APPLE_TEXT_STUBS_SUPPORTED TRUE)
+endif()\n\n")
+
+string (APPEND GENERATE_CONTENT [[
+cmake_policy (SET CMP0011 NEW)
+cmake_policy (SET CMP0057 NEW)
+
+macro (CHECK_FILE test_msg path)
+ if (NOT EXISTS "${path}")
+ string (APPEND RunCMake_TEST_FAILED "${test_msg}: \"${path}\" not found\n")
+ endif()
+endmacro()
+
+macro (CHECK_SYMLINK test_msg path)
+ if (NOT IS_SYMLINK "${path}")
+ string (APPEND RunCMake_TEST_FAILED "${test_msg}: \"${path}\" is not a symbolic link\n")
+ elseif (NOT EXISTS "${path}")
+ string (APPEND RunCMake_TEST_FAILED "${test_msg}: \"${path}\" not a valid symlink\n")
+ endif()
+endmacro()
+
+macro (CHECK_NOFILE test_msg path)
+ if (EXISTS "${path}")
+ string (APPEND RunCMake_TEST_FAILED "${test_msg}: \"${path}\" was found\n")
+ endif()
+endmacro()
+
+macro (CHECK_INSTALLED test_msg dir file)
+ file(GLOB installed_files LIST_DIRECTORIES FALSE RELATIVE "${dir}" "${dir}/*")
+ if (NOT "${file}" IN_LIST installed_files)
+ string (APPEND RunCMake_TEST_FAILED "${test_msg}: \"${dir}/${file}\" not found\n")
+ endif()
+endmacro()
+
+
+check_file("DYLIB file" "$<TARGET_FILE:foo>")
+check_symlink("Linkable DYLIB file" "$<TARGET_LINKER_LIBRARY_FILE:foo>")
+check_symlink("SONAME DYLIB file" "$<TARGET_SONAME_FILE:foo>")
+check_file("executable file" "$<TARGET_FILE:main>")
+
+check_file("Installed DYLIB file" "${RunCMake_TEST_BINARY_DIR}/INSTALL/$<TARGET_FILE_NAME:foo>")
+check_symlink("Installed Linkable DYLIB file" "${RunCMake_TEST_BINARY_DIR}/INSTALL/$<TARGET_LINKER_LIBRARY_FILE_NAME:foo>")
+check_symlink("Installed SONAME DYLIB file" "${RunCMake_TEST_BINARY_DIR}/INSTALL/$<TARGET_SONAME_FILE_NAME:foo>")
+
+if (APPLE_TEXT_STUBS_SUPPORTED)
+ check_file("TBD file" "$<TARGET_IMPORT_FILE:foo>")
+ check_symlink("Linkable TBD file" "$<TARGET_LINKER_IMPORT_FILE:foo>")
+ check_symlink("SONAME TBD file" "$<TARGET_SONAME_IMPORT_FILE:foo>")
+
+ check_file("Installed TBD file" "${RunCMake_TEST_BINARY_DIR}/INSTALL/$<TARGET_IMPORT_FILE_NAME:foo>")
+ check_symlink("Installed Linkable TBD file" "${RunCMake_TEST_BINARY_DIR}/INSTALL/$<TARGET_LINKER_IMPORT_FILE_NAME:foo>")
+ check_symlink("Installed SONAME TBD file" "${RunCMake_TEST_BINARY_DIR}/INSTALL/$<TARGET_SONAME_IMPORT_FILE_NAME:foo>")
+
+ check_file("Installed TBD file" "${RunCMake_TEST_BINARY_DIR}/INSTALL2/dev1/$<TARGET_IMPORT_FILE_NAME:foo>")
+ check_symlink("Installed SONAME TBD file" "${RunCMake_TEST_BINARY_DIR}/INSTALL2/dev1/$<TARGET_SONAME_IMPORT_FILE_NAME:foo>")
+ check_nofile("Installed Linkable TBD file" "${RunCMake_TEST_BINARY_DIR}/INSTALL2/dev1/$<TARGET_LINKER_IMPORT_FILE_NAME:foo>")
+
+ check_installed("Installed Linkable TBD file" "${RunCMake_TEST_BINARY_DIR}/INSTALL2/dev2" "$<TARGET_LINKER_IMPORT_FILE_NAME:foo>")
+ check_nofile("Installed TBD file" "${RunCMake_TEST_BINARY_DIR}/INSTALL2/dev2/$<TARGET_IMPORT_FILE_NAME:foo>")
+ check_nofile("Installed SONAME TBD file" "${RunCMake_TEST_BINARY_DIR}/INSTALL2/dev2/$<TARGET_SONAME_IMPORT_FILE_NAME:foo>")
+
+ check_file("Installed TBD file" "${RunCMake_TEST_BINARY_DIR}/INSTALL3/$<TARGET_IMPORT_FILE_NAME:foo>")
+ check_symlink("Installed SONAME TBD file" "${RunCMake_TEST_BINARY_DIR}/INSTALL3/$<TARGET_SONAME_IMPORT_FILE_NAME:foo>")
+ check_nofile("Installed Linkable TBD file" "${RunCMake_TEST_BINARY_DIR}/INSTALL3/$<TARGET_LINKER_IMPORT_FILE_NAME:foo>")
+
+ check_file("Installed TBD file" "${RunCMake_TEST_BINARY_DIR}/INSTALL4/$<TARGET_IMPORT_FILE_NAME:foo>")
+ check_symlink("Installed SONAME TBD file" "${RunCMake_TEST_BINARY_DIR}/INSTALL4/$<TARGET_SONAME_IMPORT_FILE_NAME:foo>")
+ check_symlink("Installed Linkable TBD file" "${RunCMake_TEST_BINARY_DIR}/INSTALL4/$<TARGET_LINKER_IMPORT_FILE_NAME:foo>")
+endif()
+]])
+
+file (GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/LibraryWithVersions-$<CONFIG>-generated.cmake"
+ CONTENT "${GENERATE_CONTENT}")
diff --git a/Tests/RunCMake/AppleTextStubs/RunCMakeTest.cmake b/Tests/RunCMake/AppleTextStubs/RunCMakeTest.cmake
new file mode 100644
index 0000000000..9ccd685d03
--- /dev/null
+++ b/Tests/RunCMake/AppleTextStubs/RunCMakeTest.cmake
@@ -0,0 +1,58 @@
+include(RunCMake)
+
+function(build_project test)
+ if (NOT RunCMake_GENERATOR_IS_MULTI_CONFIG)
+ set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Release)
+ endif()
+ run_cmake(${test})
+ set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${test}-build)
+ set(RunCMake_TEST_NO_CLEAN 1)
+
+ run_cmake_command(${test}-build ${CMAKE_COMMAND} --build . --config Release)
+ if ("${ARGC}" GREATER "1")
+ # custom install step
+ cmake_language(CALL ${ARGV1})
+ else()
+ run_cmake_command(${test}-install ${CMAKE_COMMAND} --install . --config Release)
+ endif()
+endfunction()
+
+build_project(Simple)
+build_project(Framework)
+build_project(LibraryWithOutputs)
+
+
+function(LibraryWithVersions-install)
+ run_cmake_command(LibraryWithVersions-install-component-lib3 ${CMAKE_COMMAND} --install . --config Release --component lib3)
+ run_cmake_command(LibraryWithVersions-install-component-lib4 ${CMAKE_COMMAND} --install . --config Release --component lib4)
+ run_cmake_command(LibraryWithVersions-install-components-dev4 ${CMAKE_COMMAND} --install . --config Release --component dev4)
+ run_cmake_command(LibraryWithVersions-install ${CMAKE_COMMAND} --install . --config Release --component default)
+endfunction()
+
+build_project(LibraryWithVersions LibraryWithVersions-install)
+
+
+function(build_ExportImport_project test)
+ set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${test}-export-build)
+ set(CMAKE_INSTALL_PREFIX ${RunCMake_TEST_BINARY_DIR}/root)
+ if (NOT RunCMake_GENERATOR_IS_MULTI_CONFIG)
+ set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Release)
+ endif()
+ run_cmake(${test}-export)
+ unset(RunCMake_TEST_OPTIONS)
+ set(RunCMake_TEST_NO_CLEAN 1)
+ run_cmake_command(${test}-export-build ${CMAKE_COMMAND} --build . --config Release)
+ run_cmake_command(${test}-export-install ${CMAKE_COMMAND} --install . --prefix ${CMAKE_INSTALL_PREFIX} --config Release)
+
+ set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${test}-import-build)
+ set (foo_BUILD "${RunCMake_BINARY_DIR}/${test}-export-build")
+ if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
+ string (APPEND foo_BUILD "/Release")
+ endif()
+ run_cmake_with_options(${test}-import -Dfoo_DIR=${CMAKE_INSTALL_PREFIX}/lib/foo
+ -Dfoo_BUILD=${RunCMake_BINARY_DIR}/${test}-export-build/Release)
+ run_cmake_command(${test}-import-build ${CMAKE_COMMAND} --build . --config Release)
+endfunction()
+
+build_ExportImport_project(Library)
+build_ExportImport_project(Framework)
diff --git a/Tests/RunCMake/AppleTextStubs/Simple-install-check.cmake b/Tests/RunCMake/AppleTextStubs/Simple-install-check.cmake
new file mode 100644
index 0000000000..94054fad5f
--- /dev/null
+++ b/Tests/RunCMake/AppleTextStubs/Simple-install-check.cmake
@@ -0,0 +1 @@
+include ("${RunCMake_TEST_BINARY_DIR}/Simple-Release-generated.cmake")
diff --git a/Tests/RunCMake/AppleTextStubs/Simple.cmake b/Tests/RunCMake/AppleTextStubs/Simple.cmake
new file mode 100644
index 0000000000..9f6318c561
--- /dev/null
+++ b/Tests/RunCMake/AppleTextStubs/Simple.cmake
@@ -0,0 +1,41 @@
+enable_language(C)
+
+add_library(foo SHARED foo.c)
+set_property(TARGET foo PROPERTY ENABLE_EXPORTS TRUE)
+
+add_executable(main main.c)
+target_link_libraries(main PRIVATE foo)
+
+
+install(TARGETS foo DESTINATION "${CMAKE_BINARY_DIR}/INSTALL")
+
+install(TARGETS foo LIBRARY DESTINATION "${CMAKE_BINARY_DIR}/INSTALL2/lib"
+ ARCHIVE DESTINATION "${CMAKE_BINARY_DIR}/INSTALL2/dev")
+
+
+set (GENERATE_CONTENT "if (\"${CMAKE_TAPI}\")
+ set (APPLE_TEXT_STUBS_SUPPORTED TRUE)
+endif()\n\n")
+
+string (APPEND GENERATE_CONTENT [[
+macro (CHECK_FILE test_msg path)
+ if (NOT EXISTS "${path}")
+ string (APPEND RunCMake_TEST_FAILED "${test_msg}: \"${path}\" not found\n")
+ endif()
+endmacro()
+
+check_file("DYLIB file" "$<TARGET_FILE:foo>")
+check_file("executable file" "$<TARGET_FILE:main>")
+
+check_file("Installed DYLIB file" "${RunCMake_TEST_BINARY_DIR}/INSTALL2/lib/$<TARGET_FILE_NAME:foo>")
+
+if (APPLE_TEXT_STUBS_SUPPORTED)
+ check_file("TBD file" "$<TARGET_IMPORT_FILE:foo>")
+
+ check_file("Installed TBD file" "${RunCMake_TEST_BINARY_DIR}/INSTALL/$<TARGET_IMPORT_FILE_NAME:foo>")
+ check_file("Installed TBD file" "${RunCMake_TEST_BINARY_DIR}/INSTALL2/dev/$<TARGET_IMPORT_FILE_NAME:foo>")
+endif()
+]])
+
+file (GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Simple-$<CONFIG>-generated.cmake"
+ CONTENT "${GENERATE_CONTENT}")
diff --git a/Tests/RunCMake/AppleTextStubs/foo-config.cmake.in b/Tests/RunCMake/AppleTextStubs/foo-config.cmake.in
new file mode 100644
index 0000000000..b0381387a6
--- /dev/null
+++ b/Tests/RunCMake/AppleTextStubs/foo-config.cmake.in
@@ -0,0 +1 @@
+include(${CMAKE_CURRENT_LIST_DIR}/foo.cmake)
diff --git a/Tests/RunCMake/AppleTextStubs/foo.c b/Tests/RunCMake/AppleTextStubs/foo.c
new file mode 100644
index 0000000000..7f39d71755
--- /dev/null
+++ b/Tests/RunCMake/AppleTextStubs/foo.c
@@ -0,0 +1,5 @@
+
+int foo()
+{
+ return 0;
+}
diff --git a/Tests/RunCMake/AppleTextStubs/main.c b/Tests/RunCMake/AppleTextStubs/main.c
new file mode 100644
index 0000000000..dc5ce3d101
--- /dev/null
+++ b/Tests/RunCMake/AppleTextStubs/main.c
@@ -0,0 +1,7 @@
+
+extern int foo(void);
+
+int main()
+{
+ return foo();
+}
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index e3722867a4..c7c98bb467 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -357,6 +357,7 @@ add_RunCMake_test(GenEx-DEVICE_LINK)
add_RunCMake_test(GenEx-LINK_LIBRARY)
add_RunCMake_test(GenEx-LINK_GROUP)
add_RunCMake_test(GenEx-TARGET_FILE -DLINKER_SUPPORTS_PDB=${LINKER_SUPPORTS_PDB})
+add_RunCMake_test(GenEx-TARGET_IMPORT_FILE)
add_RunCMake_test(GenEx-GENEX_EVAL)
add_RunCMake_test(GenEx-TARGET_PROPERTY)
add_RunCMake_test(GenEx-TARGET_RUNTIME_DLLS)
@@ -515,6 +516,7 @@ add_RunCMake_test(BundleUtilities)
if(APPLE)
add_RunCMake_test(INSTALL_NAME_DIR)
add_RunCMake_test(MacOSVersions)
+ add_RunCMake_test(AppleTextStubs)
endif()
function(add_RunCMake_test_try_compile)
diff --git a/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/CMakeLists.txt b/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/CMakeLists.txt
new file mode 100644
index 0000000000..93ee9dfd5f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.5)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/RunCMakeTest.cmake b/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/RunCMakeTest.cmake
new file mode 100644
index 0000000000..04ff640942
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/RunCMakeTest.cmake
@@ -0,0 +1,21 @@
+include(RunCMake)
+
+cmake_policy(SET CMP0057 NEW)
+
+function(run_cmake_with_config test)
+ if (NOT RunCMake_GENERATOR_IS_MULTI_CONFIG)
+ set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Release)
+ endif()
+ run_cmake(${test})
+endfunction()
+
+run_cmake(TARGET_LINKER_IMPORT_FILE-non-valid-target)
+run_cmake(TARGET_LINKER_LIBRARY_FILE-non-valid-target)
+run_cmake_with_config(TARGET_IMPORT_FILE)
+run_cmake_with_config(TARGET_IMPORT_FILE_SUFFIX)
+
+set (Windows_platforms Windows CYGWIN MSYS)
+if (NOT CMAKE_HOST_SYSTEM_NAME IN_LIST Windows_platforms)
+ run_cmake(TARGET_SONAME_IMPORT_FILE-non-valid-target)
+ run_cmake_with_config(TARGET_SONAME_IMPORT_FILE)
+endif()
diff --git a/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_IMPORT_FILE-check.cmake b/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_IMPORT_FILE-check.cmake
new file mode 100644
index 0000000000..9a101fc704
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_IMPORT_FILE-check.cmake
@@ -0,0 +1 @@
+include ("${RunCMake_TEST_BINARY_DIR}/TARGET_IMPORT_FILE-Release-generated.cmake")
diff --git a/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_IMPORT_FILE.cmake b/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_IMPORT_FILE.cmake
new file mode 100644
index 0000000000..08765a68fe
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_IMPORT_FILE.cmake
@@ -0,0 +1,47 @@
+enable_language(C)
+
+set (platforms_with_import Windows CYGWIN MSYS)
+
+set (GENERATE_CONTENT [[
+macro (CHECK_VALUE test_msg value expected)
+ if (NOT "${value}" STREQUAL "${expected}")
+ string (APPEND RunCMake_TEST_FAILED "${test_msg}: actual result:\n [${value}]\nbut expected:\n [${expected}]\n")
+ endif()
+endmacro()
+]])
+
+add_library (shared1 SHARED empty.c)
+add_library (static1 STATIC empty.c)
+add_executable (exec1 empty.c)
+
+
+string (APPEND GENERATE_CONTENT
+"\ncheck_value (\"TARGET_IMPORT_FILE shared library\" \"$<TARGET_IMPORT_FILE:shared1>\" \"$<IF:$<IN_LIST:$<PLATFORM_ID>,${platforms_with_import}>,$<TARGET_LINKER_IMPORT_FILE:shared1>,>\")
+check_value (\"TARGET_LINKER_FILE shared library\" \"$<TARGET_LINKER_FILE:shared1>\" \"$<IF:$<IN_LIST:$<PLATFORM_ID>,${platforms_with_import}>,$<TARGET_LINKER_IMPORT_FILE:shared1>,$<TARGET_LINKER_LIBRARY_FILE:shared1>>\")
+check_value (\"TARGET_IMPORT_FILE static library\" \"$<TARGET_IMPORT_FILE:static1>\" \"\")
+check_value (\"TARGET_IMPORT_FILE executable\" \"$<TARGET_IMPORT_FILE:exec1>\" \"\")\n")
+
+
+set(lib_with_import ${platforms_with_import})
+set(exec_with_import ${platforms_with_import})
+if (APPLE AND CMAKE_TAPI)
+ list(APPEND lib_with_import Darwin)
+endif()
+if (CMAKE_SYSTEM_NAME STREQUAL "AIX")
+ list(APPEND exec_with_import "AIX")
+endif()
+set(CMAKE_SHARED_LIBRARY_ENABLE_EXPORTS TRUE)
+set(CMAKE_EXECUTABLE_ENABLE_EXPORTS TRUE)
+
+add_library (shared2 SHARED empty.c)
+add_executable (exec2 empty.c)
+
+
+string (APPEND GENERATE_CONTENT
+"\ncheck_value (\"TARGET_IMPORT_FILE shared library\" \"$<TARGET_IMPORT_FILE:shared2>\" \"$<IF:$<IN_LIST:$<PLATFORM_ID>,${lib_with_import}>,$<TARGET_LINKER_IMPORT_FILE:shared2>,>\")
+check_value (\"TARGET_LINKER_FILE shared library\" \"$<TARGET_LINKER_FILE:shared2>\" \"$<IF:$<IN_LIST:$<PLATFORM_ID>,${lib_with_import}>,$<TARGET_LINKER_IMPORT_FILE:shared2>,$<TARGET_LINKER_LIBRARY_FILE:shared2>>\")
+check_value (\"TARGET_IMPORT_FILE executable\" \"$<TARGET_IMPORT_FILE:exec2>\" \"$<IF:$<IN_LIST:$<PLATFORM_ID>,${exec_with_import}>,$<TARGET_LINKER_IMPORT_FILE:exec2>,>\")\n")
+
+
+file (GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/TARGET_IMPORT_FILE-$<CONFIG>-generated.cmake"
+ CONTENT "${GENERATE_CONTENT}")
diff --git a/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_IMPORT_FILE_SUFFIX-check.cmake b/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_IMPORT_FILE_SUFFIX-check.cmake
new file mode 100644
index 0000000000..2a1357aaa9
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_IMPORT_FILE_SUFFIX-check.cmake
@@ -0,0 +1 @@
+include ("${RunCMake_TEST_BINARY_DIR}/TARGET_IMPORT_FILE_SUFFIX-Release-generated.cmake")
diff --git a/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_IMPORT_FILE_SUFFIX.cmake b/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_IMPORT_FILE_SUFFIX.cmake
new file mode 100644
index 0000000000..933471b651
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_IMPORT_FILE_SUFFIX.cmake
@@ -0,0 +1,44 @@
+enable_language (C)
+
+set (platforms_with_import Windows CYGWIN MSYS)
+
+set (GENERATE_CONTENT [[
+macro (CHECK_VALUE test_msg value expected)
+ if (NOT "${value}" STREQUAL "${expected}")
+ string (APPEND RunCMake_TEST_FAILED "${test_msg}: actual result:\n [${value}]\nbut expected:\n [${expected}]\n")
+ endif()
+endmacro()
+]])
+
+add_library (shared1 SHARED empty.c)
+add_library (static1 STATIC empty.c)
+add_executable (exec1 empty.c)
+
+string (APPEND GENERATE_CONTENT
+"\ncheck_value (\"TARGET_IMPORT_FILE_SUFFIX executable default\" \"$<TARGET_IMPORT_FILE_SUFFIX:exec1>\" \"\")
+check_value (\"TARGET_IMPORT_FILE_SUFFIX shared default\" \"$<TARGET_IMPORT_FILE_SUFFIX:shared1>\" \"$<IF:$<IN_LIST:$<PLATFORM_ID>,${platforms_with_import}>,$<TARGET_LINKER_IMPORT_FILE_SUFFIX:shared1>,>\")
+check_value (\"TARGET_FILE_SUFFIX static default\" \"$<TARGET_IMPORT_FILE_SUFFIX:static1>\" \"\")
+check_value (\"TARGET_IMPORT_FILE_SUFFIX executable default\" \"$<TARGET_IMPORT_FILE_SUFFIX:exec1>\" \"\")\n")
+
+
+
+if (APPLE AND CMAKE_TAPI)
+ list(APPEND platforms_with_import Darwin)
+endif()
+if (CMAKE_SYSTEM_NAME STREQUAL "AIX")
+ list(APPEND platforms_with_import AIX)
+endif()
+set(CMAKE_SHARED_LIBRARY_ENABLE_EXPORTS TRUE)
+set(CMAKE_EXECUTABLE_ENABLE_EXPORTS TRUE)
+
+add_library (shared2 SHARED empty.c)
+add_executable (exec2 empty.c)
+
+string (APPEND GENERATE_CONTENT
+"\ncheck_value (\"TARGET_IMPORT_FILE_SUFFIX executable default\" \"$<TARGET_IMPORT_FILE_SUFFIX:exec2>\" \"$<IF:$<IN_LIST:$<PLATFORM_ID>,${platforms_with_import}>,$<TARGET_LINKER_IMPORT_FILE_SUFFIX:exec2>,>\")
+check_value (\"TARGET_IMPORT_FILE_SUFFIX shared default\" \"$<TARGET_IMPORT_FILE_SUFFIX:shared2>\" \"$<IF:$<IN_LIST:$<PLATFORM_ID>,${platforms_with_import}>,$<TARGET_LINKER_IMPORT_FILE_SUFFIX:shared2>,>\")\n")
+
+
+
+file (GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/TARGET_IMPORT_FILE_SUFFIX-$<CONFIG>-generated.cmake"
+ CONTENT "${GENERATE_CONTENT}")
diff --git a/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_LINKER_IMPORT_FILE-non-valid-target-result.txt b/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_LINKER_IMPORT_FILE-non-valid-target-result.txt
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_LINKER_IMPORT_FILE-non-valid-target-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_LINKER_IMPORT_FILE-non-valid-target-stderr.txt b/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_LINKER_IMPORT_FILE-non-valid-target-stderr.txt
new file mode 100644
index 0000000000..8ba2223dfa
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_LINKER_IMPORT_FILE-non-valid-target-stderr.txt
@@ -0,0 +1,9 @@
+CMake Error at TARGET_LINKER_IMPORT_FILE-non-valid-target.cmake:[0-9]+ \(file\):
+ Error evaluating generator expression:
+
+ \$<TARGET_LINKER_IMPORT_FILE:exe1>
+
+ TARGET_LINKER_IMPORT_FILE is allowed only for libraries and executables
+ with ENABLE_EXPORTS.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_LINKER_IMPORT_FILE-non-valid-target.cmake b/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_LINKER_IMPORT_FILE-non-valid-target.cmake
new file mode 100644
index 0000000000..3f060cdc92
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_LINKER_IMPORT_FILE-non-valid-target.cmake
@@ -0,0 +1,9 @@
+
+enable_language(C)
+
+add_executable(exe1 empty.c)
+
+file(GENERATE
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/test.txt"
+ CONTENT "[$<TARGET_LINKER_IMPORT_FILE:exe1>]"
+)
diff --git a/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_LINKER_LIBRARY_FILE-non-valid-target-result.txt b/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_LINKER_LIBRARY_FILE-non-valid-target-result.txt
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_LINKER_LIBRARY_FILE-non-valid-target-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_LINKER_LIBRARY_FILE-non-valid-target-stderr.txt b/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_LINKER_LIBRARY_FILE-non-valid-target-stderr.txt
new file mode 100644
index 0000000000..06e7b3ad77
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_LINKER_LIBRARY_FILE-non-valid-target-stderr.txt
@@ -0,0 +1,9 @@
+CMake Error at TARGET_LINKER_LIBRARY_FILE-non-valid-target.cmake:[0-9]+ \(file\):
+ Error evaluating generator expression:
+
+ \$<TARGET_LINKER_LIBRARY_FILE:exe1>
+
+ TARGET_LINKER_LIBRARY_FILE is allowed only for libraries with
+ ENABLE_EXPORTS.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_LINKER_LIBRARY_FILE-non-valid-target.cmake b/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_LINKER_LIBRARY_FILE-non-valid-target.cmake
new file mode 100644
index 0000000000..bb95546633
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_LINKER_LIBRARY_FILE-non-valid-target.cmake
@@ -0,0 +1,9 @@
+
+enable_language(C)
+
+add_executable(exe1 empty.c)
+
+file(GENERATE
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/test.txt"
+ CONTENT "[$<TARGET_LINKER_LIBRARY_FILE:exe1>]"
+)
diff --git a/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_SONAME_IMPORT_FILE-check.cmake b/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_SONAME_IMPORT_FILE-check.cmake
new file mode 100644
index 0000000000..ab4443e10d
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_SONAME_IMPORT_FILE-check.cmake
@@ -0,0 +1 @@
+include ("${RunCMake_TEST_BINARY_DIR}/TARGET_SONAME_IMPORT_FILE-Release-generated.cmake")
diff --git a/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_SONAME_IMPORT_FILE-non-valid-target-result.txt b/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_SONAME_IMPORT_FILE-non-valid-target-result.txt
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_SONAME_IMPORT_FILE-non-valid-target-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_SONAME_IMPORT_FILE-non-valid-target-stderr.txt b/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_SONAME_IMPORT_FILE-non-valid-target-stderr.txt
new file mode 100644
index 0000000000..0640088a86
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_SONAME_IMPORT_FILE-non-valid-target-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at TARGET_SONAME_IMPORT_FILE-non-valid-target.cmake:[0-9]+ \(file\):
+ Error evaluating generator expression:
+
+ \$<TARGET_SONAME_IMPORT_FILE:static1>
+
+ TARGET_SONAME_IMPORT_FILE is allowed only for SHARED libraries.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_SONAME_IMPORT_FILE-non-valid-target.cmake b/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_SONAME_IMPORT_FILE-non-valid-target.cmake
new file mode 100644
index 0000000000..cc79580292
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_SONAME_IMPORT_FILE-non-valid-target.cmake
@@ -0,0 +1,8 @@
+enable_language(C)
+
+add_library (static1 STATIC empty.c)
+set_property (TARGET static1 PROPERTY VERSION 2.5.0)
+set_property (TARGET static1 PROPERTY SOVERSION 2.0.0)
+
+file (GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/test.txt"
+ CONTENT "[$<TARGET_SONAME_IMPORT_FILE:static1>]")
diff --git a/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_SONAME_IMPORT_FILE.cmake b/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_SONAME_IMPORT_FILE.cmake
new file mode 100644
index 0000000000..02ba513759
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/TARGET_SONAME_IMPORT_FILE.cmake
@@ -0,0 +1,32 @@
+enable_language(C)
+
+set (GENERATE_CONTENT [[
+macro (CHECK_VALUE test_msg value expected)
+ if (NOT "${value}" STREQUAL "${expected}")
+ string (APPEND RunCMake_TEST_FAILED "${test_msg}: actual result:\n [${value}]\nbut expected:\n [${expected}]\n")
+ endif()
+endmacro()
+]])
+
+add_library (shared1 SHARED empty.c)
+set_property (TARGET shared1 PROPERTY VERSION 2.5.0)
+set_property (TARGET shared1 PROPERTY SOVERSION 2.0.0)
+
+
+string (APPEND GENERATE_CONTENT
+"\ncheck_value (\"TARGET_SONAME_IMPORT_FILE shared library\" \"$<TARGET_SONAME_IMPORT_FILE:shared1>\" \"\")\n")
+
+
+
+add_library (shared2 SHARED empty.c)
+set_property(TARGET shared2 PROPERTY ENABLE_EXPORTS ON)
+set_property (TARGET shared2 PROPERTY VERSION 2.5.0)
+set_property (TARGET shared2 PROPERTY SOVERSION 2.0.0)
+
+
+string (APPEND GENERATE_CONTENT
+"\ncheck_value (\"TARGET_SONAME_IMPORT_FILE shared library\" \"$<TARGET_SONAME_IMPORT_FILE:shared2>\" \"$<$<BOOL:${CMAKE_TAPI}>:$<PATH:REPLACE_EXTENSION,LAST_ONLY,$<TARGET_SONAME_FILE:shared2>,.tbd>>\")\n")
+
+
+file (GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/TARGET_SONAME_IMPORT_FILE-$<CONFIG>-generated.cmake"
+ CONTENT "${GENERATE_CONTENT}")
diff --git a/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/empty.c b/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/empty.c
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_IMPORT_FILE/empty.c
diff --git a/Tests/RunCMake/install/TARGETS-NAMELINK_COMPONENT-bad-all-stderr.txt b/Tests/RunCMake/install/TARGETS-NAMELINK_COMPONENT-bad-all-stderr.txt
index fe65fd3006..26dcd42bb2 100644
--- a/Tests/RunCMake/install/TARGETS-NAMELINK_COMPONENT-bad-all-stderr.txt
+++ b/Tests/RunCMake/install/TARGETS-NAMELINK_COMPONENT-bad-all-stderr.txt
@@ -1,5 +1,6 @@
^CMake Error at TARGETS-NAMELINK_COMPONENT-bad-all\.cmake:5 \(install\):
- install TARGETS given NAMELINK_COMPONENT option not in LIBRARY group\. The
- NAMELINK_COMPONENT option may be specified only following LIBRARY\.
+ install TARGETS given NAMELINK_COMPONENT option not in LIBRARY or ARCHIVE
+ group\. The NAMELINK_COMPONENT option may be specified only following
+ LIBRARY or ARCHIVE\.
Call Stack \(most recent call first\):
CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/install/TARGETS-NAMELINK_COMPONENT-bad-exc-stderr.txt b/Tests/RunCMake/install/TARGETS-NAMELINK_COMPONENT-bad-exc-stderr.txt
index 60f52c4889..8aed62b6b9 100644
--- a/Tests/RunCMake/install/TARGETS-NAMELINK_COMPONENT-bad-exc-stderr.txt
+++ b/Tests/RunCMake/install/TARGETS-NAMELINK_COMPONENT-bad-exc-stderr.txt
@@ -1,5 +1,6 @@
^CMake Error at TARGETS-NAMELINK_COMPONENT-bad-exc\.cmake:5 \(install\):
- install TARGETS given NAMELINK_COMPONENT option not in LIBRARY group\. The
- NAMELINK_COMPONENT option may be specified only following LIBRARY\.
+ install TARGETS given NAMELINK_COMPONENT option not in LIBRARY or ARCHIVE
+ group\. The NAMELINK_COMPONENT option may be specified only following
+ LIBRARY or ARCHIVE\.
Call Stack \(most recent call first\):
CMakeLists\.txt:[0-9]+ \(include\)$