mirror of
https://github.com/Kitware/CMake.git
synced 2025-10-14 02:08:27 +08:00
add_library(): Allow imported object libraries with multi-arch
Fixes: #21276
This commit is contained in:
@@ -3,11 +3,91 @@ IMPORTED_OBJECTS
|
|||||||
|
|
||||||
.. versionadded:: 3.9
|
.. versionadded:: 3.9
|
||||||
|
|
||||||
A :ref:`semicolon-separated list <CMake Language Lists>` of absolute paths to the object
|
A :ref:`semicolon-separated list <CMake Language Lists>` of absolute paths
|
||||||
files on disk for an :ref:`imported <Imported targets>`
|
to the object files on disk for an :ref:`imported <Imported targets>`
|
||||||
:ref:`object library <object libraries>`.
|
:ref:`object library <object libraries>`.
|
||||||
|
|
||||||
Ignored for non-imported targets.
|
Ignored for non-imported targets.
|
||||||
|
|
||||||
Projects may skip ``IMPORTED_OBJECTS`` if the configuration-specific
|
Projects may skip ``IMPORTED_OBJECTS`` if the configuration-specific
|
||||||
property :prop_tgt:`IMPORTED_OBJECTS_<CONFIG>` is set instead.
|
property :prop_tgt:`IMPORTED_OBJECTS_<CONFIG>` is set instead, except in
|
||||||
|
situations as noted in the section below.
|
||||||
|
|
||||||
|
|
||||||
|
Xcode Generator Considerations
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
.. versionadded:: 3.20
|
||||||
|
|
||||||
|
For Apple platforms, a project may be built for more than one architecture.
|
||||||
|
This is controlled by the :variable:`CMAKE_OSX_ARCHITECTURES` variable.
|
||||||
|
For all but the :generator:`Xcode` generator, CMake invokes compilers once
|
||||||
|
per source file and passes multiple ``-arch`` flags, leading to a single
|
||||||
|
object file which will be a universal binary. Such object files work well
|
||||||
|
when listed in the ``IMPORTED_OBJECTS`` of a separate CMake build, even for
|
||||||
|
the :generator:`Xcode` generator. But producing such object files with the
|
||||||
|
:generator:`Xcode` generator is more difficult, since it invokes the compiler
|
||||||
|
once per architecture for each source file. Unlike the other generators,
|
||||||
|
it does not generate universal object file binaries.
|
||||||
|
|
||||||
|
A further complication with the :generator:`Xcode` generator is that when
|
||||||
|
targeting device platforms (iOS, tvOS or watchOS), the :generator:`Xcode`
|
||||||
|
generator has the ability to use either the device or simulator SDK without
|
||||||
|
needing CMake to be re-run. The SDK can be selected at build time.
|
||||||
|
But since some architectures can be supported by both the device and the
|
||||||
|
simulator SDKs (e.g. ``arm64`` with Xcode 12 or later), not all combinations
|
||||||
|
can be represented in a single universal binary. The only solution in this
|
||||||
|
case is to have multiple object files.
|
||||||
|
|
||||||
|
``IMPORTED_OBJECTS`` doesn't support generator expressions, so every file
|
||||||
|
it lists needs to be valid for every architecture and SDK. If incorporating
|
||||||
|
object files that are not universal binaries, the path and/or file name of
|
||||||
|
each object file has to somehow encapsulate the different architectures and
|
||||||
|
SDKs. With the :generator:`Xcode` generator, Xcode variables of the form
|
||||||
|
``$(...)`` can be used to represent these aspects and Xcode will substitute
|
||||||
|
the appropriate values at build time. CMake doesn't interpret these
|
||||||
|
variables and embeds them unchanged in the Xcode project file.
|
||||||
|
``$(CURRENT_ARCH)`` can be used to represent the architecture, while
|
||||||
|
``$(EFFECTIVE_PLATFORM_NAME)`` can be used to differentiate between SDKs.
|
||||||
|
|
||||||
|
The following shows one example of how these two variables can be used to
|
||||||
|
refer to an object file whose location depends on both the SDK and the
|
||||||
|
architecture:
|
||||||
|
|
||||||
|
.. code-block:: cmake
|
||||||
|
|
||||||
|
add_library(someObjs OBJECT IMPORTED)
|
||||||
|
|
||||||
|
set_property(TARGET someObjs PROPERTY IMPORTED_OBJECTS
|
||||||
|
# Quotes are required because of the ()
|
||||||
|
"/path/to/somewhere/objects$(EFFECTIVE_PLATFORM_NAME)/$(CURRENT_ARCH)/func.o"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Example paths:
|
||||||
|
# /path/to/somewhere/objects-iphoneos/arm64/func.o
|
||||||
|
# /path/to/somewhere/objects-iphonesimulator/x86_64/func.o
|
||||||
|
|
||||||
|
In some cases, you may want to have configuration-specific object files
|
||||||
|
as well. The :variable:`CMAKE_CFG_INTDIR` variable can be a convenient
|
||||||
|
way of capturing this in combination with the SDK:
|
||||||
|
|
||||||
|
.. code-block:: cmake
|
||||||
|
|
||||||
|
add_library(someObjs OBJECT IMPORTED)
|
||||||
|
set_property(TARGET someObjs PROPERTY IMPORTED_OBJECTS
|
||||||
|
"/path/to/somewhere/${CMAKE_CFG_INTDIR}/$(CURRENT_ARCH)/func.o"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Example paths:
|
||||||
|
# /path/to/somewhere/Release-iphoneos/arm64/func.o
|
||||||
|
# /path/to/somewhere/Debug-iphonesimulator/x86_64/func.o
|
||||||
|
|
||||||
|
When any Xcode variable or :variable:`CMAKE_CFG_INTDIR` is used, CMake is
|
||||||
|
not able to fully evaluate the path(s) at configure time. One consequence
|
||||||
|
of this is that the configuration-specific
|
||||||
|
:prop_tgt:`IMPORTED_OBJECTS_<CONFIG>` properties cannot be used, since
|
||||||
|
CMake cannot determine whether an object file exists at a particular
|
||||||
|
``<CONFIG>`` location. The ``IMPORTED_OBJECTS`` property must be used for
|
||||||
|
these situations and the configuration-specific aspects of the path must be
|
||||||
|
handled by using :variable:`CMAKE_CFG_INTDIR` or with another Xcode variable
|
||||||
|
``$(CONFIGURATION)``.
|
||||||
|
@@ -3,7 +3,18 @@ IMPORTED_OBJECTS_<CONFIG>
|
|||||||
|
|
||||||
.. versionadded:: 3.9
|
.. versionadded:: 3.9
|
||||||
|
|
||||||
<CONFIG>-specific version of :prop_tgt:`IMPORTED_OBJECTS` property.
|
``<CONFIG>``-specific version of :prop_tgt:`IMPORTED_OBJECTS` property.
|
||||||
|
|
||||||
Configuration names correspond to those provided by the project from
|
Configuration names correspond to those provided by the project from
|
||||||
which the target is imported.
|
which the target is imported.
|
||||||
|
|
||||||
|
|
||||||
|
Xcode Generator Considerations
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Do not use this ``<CONFIG>``-specific property if you need to use Xcode
|
||||||
|
variables like ``$(CURRENT_ARCH)`` or ``$(EFFECTIVE_PLATFORM_NAME)`` in
|
||||||
|
the value. The ``<CONFIG>``-specific properties will be ignored in such
|
||||||
|
cases because CMake cannot determine whether a file exists at the
|
||||||
|
configuration-specific path at configuration time. For such cases, use
|
||||||
|
:prop_tgt:`IMPORTED_OBJECTS` instead.
|
||||||
|
8
Help/release/dev/object-lib-multiarch.rst
Normal file
8
Help/release/dev/object-lib-multiarch.rst
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
object-lib-multiarch
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
* The :command:`add_library` command previously prohibited imported object
|
||||||
|
libraries when using potentially multi-architecture configurations.
|
||||||
|
This mostly affected the :generator:`Xcode` generator, e.g. when targeting
|
||||||
|
iOS or one of the other device platforms. This restriction has now been
|
||||||
|
removed.
|
@@ -238,16 +238,6 @@ bool cmAddLibraryCommand(std::vector<std::string> const& args,
|
|||||||
status.SetError("called with IMPORTED argument but no library type.");
|
status.SetError("called with IMPORTED argument but no library type.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (type == cmStateEnums::OBJECT_LIBRARY) {
|
|
||||||
std::string reason;
|
|
||||||
if (!mf.GetGlobalGenerator()->HasKnownObjectFileLocation(&reason)) {
|
|
||||||
mf.IssueMessage(
|
|
||||||
MessageType::FATAL_ERROR,
|
|
||||||
"The OBJECT library type may not be used for IMPORTED libraries" +
|
|
||||||
reason + ".");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (type == cmStateEnums::INTERFACE_LIBRARY) {
|
if (type == cmStateEnums::INTERFACE_LIBRARY) {
|
||||||
if (!cmGeneratorExpression::IsValidTargetName(libName)) {
|
if (!cmGeneratorExpression::IsValidTargetName(libName)) {
|
||||||
status.SetError(cmStrCat(
|
status.SetError(cmStrCat(
|
||||||
|
15
Tests/RunCMake/ObjectLibrary/ImportMultiArch-check.cmake
Normal file
15
Tests/RunCMake/ObjectLibrary/ImportMultiArch-check.cmake
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
set(xcProjectFile "${RunCMake_TEST_BINARY_DIR}/ImportMultiArch.xcodeproj/project.pbxproj")
|
||||||
|
if(NOT EXISTS "${xcProjectFile}")
|
||||||
|
set(RunCMake_TEST_FAILED "Project file ${xcProjectFile} does not exist.")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
file(READ ${xcProjectFile} pbxFileContents)
|
||||||
|
foreach(config IN ITEMS Debug Release RelWithDebInfo MinSizeRel)
|
||||||
|
set(regex "--findconfig-${config}[^
|
||||||
|
]*\\$\\(CURRENT_ARCH\\)")
|
||||||
|
if(NOT pbxFileContents MATCHES "${regex}")
|
||||||
|
set(RunCMake_TEST_FAILED "$(CURRENT_ARCH) not preserved for config ${config}")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
endforeach()
|
13
Tests/RunCMake/ObjectLibrary/ImportMultiArch.cmake
Normal file
13
Tests/RunCMake/ObjectLibrary/ImportMultiArch.cmake
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
|
||||||
|
add_library(A OBJECT IMPORTED)
|
||||||
|
|
||||||
|
# We don't actually build this example so just configure dummy
|
||||||
|
# object files to test. They do not have to exist.
|
||||||
|
set_target_properties(A PROPERTIES
|
||||||
|
IMPORTED_OBJECTS "${CMAKE_CURRENT_BINARY_DIR}/$(CURRENT_ARCH)/does_not_exist.o"
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library(B SHARED $<TARGET_OBJECTS:A> b.c)
|
||||||
|
|
||||||
|
# We use this to find the relevant lines of the project.pbx file
|
||||||
|
target_link_options(B PRIVATE --findconfig-$<CONFIG>)
|
@@ -1,5 +0,0 @@
|
|||||||
CMake Error at ImportNotSupported.cmake:[0-9]+ \(add_library\):
|
|
||||||
The OBJECT library type may not be used for IMPORTED libraries under Xcode
|
|
||||||
with multiple architectures.
|
|
||||||
Call Stack \(most recent call first\):
|
|
||||||
CMakeLists.txt:3 \(include\)
|
|
@@ -1 +0,0 @@
|
|||||||
add_library(A OBJECT IMPORTED)
|
|
@@ -6,7 +6,7 @@ run_cmake(BadSourceExpression3)
|
|||||||
run_cmake(BadObjSource1)
|
run_cmake(BadObjSource1)
|
||||||
run_cmake(BadObjSource2)
|
run_cmake(BadObjSource2)
|
||||||
if(RunCMake_GENERATOR STREQUAL "Xcode" AND "$ENV{CMAKE_OSX_ARCHITECTURES}" MATCHES "[;$]")
|
if(RunCMake_GENERATOR STREQUAL "Xcode" AND "$ENV{CMAKE_OSX_ARCHITECTURES}" MATCHES "[;$]")
|
||||||
run_cmake(ImportNotSupported)
|
run_cmake(ImportMultiArch)
|
||||||
run_cmake(InstallNotSupported)
|
run_cmake(InstallNotSupported)
|
||||||
else()
|
else()
|
||||||
run_cmake(Import)
|
run_cmake(Import)
|
||||||
|
@@ -2,3 +2,7 @@ include(RunCMake)
|
|||||||
|
|
||||||
run_cmake(NoTarget)
|
run_cmake(NoTarget)
|
||||||
run_cmake(NotObjlibTarget)
|
run_cmake(NotObjlibTarget)
|
||||||
|
|
||||||
|
if(RunCMake_GENERATOR STREQUAL "Xcode" AND "$ENV{CMAKE_OSX_ARCHITECTURES}" MATCHES "[;$]")
|
||||||
|
run_cmake(XcodeVariableNoGenexExpansion)
|
||||||
|
endif()
|
||||||
|
@@ -0,0 +1,10 @@
|
|||||||
|
CMake Error at XcodeVariableNoGenexExpansion\.cmake:9 \(file\):
|
||||||
|
Error evaluating generator expression:
|
||||||
|
|
||||||
|
\$\<TARGET_OBJECTS:A\>
|
||||||
|
|
||||||
|
The evaluation of the TARGET_OBJECTS generator expression is only suitable
|
||||||
|
for consumption by CMake \(limited under Xcode with multiple architectures\)\.
|
||||||
|
It is not suitable for writing out elsewhere\.
|
||||||
|
Call Stack \(most recent call first\):
|
||||||
|
CMakeLists\.txt:3 \(include\)
|
@@ -0,0 +1,12 @@
|
|||||||
|
add_library(A OBJECT IMPORTED)
|
||||||
|
|
||||||
|
# We don't actually build this example so just configure a dummy
|
||||||
|
# object file to test. It does not have to exist.
|
||||||
|
set_target_properties(A PROPERTIES
|
||||||
|
IMPORTED_OBJECTS "${CMAKE_CURRENT_BINARY_DIR}/$(CURRENT_ARCH)/does_not_exist.o"
|
||||||
|
)
|
||||||
|
|
||||||
|
file(GENERATE
|
||||||
|
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/objects.txt
|
||||||
|
CONTENT "$<TARGET_OBJECTS:A>"
|
||||||
|
)
|
Reference in New Issue
Block a user