mirror of
https://github.com/Kitware/CMake.git
synced 2026-01-01 11:22:21 -06:00
Teach target_* commands to set INTERFACE properties of IMPORTED targets
Now, several `INTERFACE_*` properties can be set on `IMPORTED` targets, not only via `set_property` and `set_target_properties` but also via `target_compile_definitions`, `target_compile_features`, `target_compile_options`, `target_include_directories`, `target_sources` and `target_link_libraries`. Fixes: #15689 Issue: #17197
This commit is contained in:
@@ -12,14 +12,15 @@ Add compile definitions to a target.
|
||||
Specify compile definitions to use when compiling a given ``<target>``. The
|
||||
named ``<target>`` must have been created by a command such as
|
||||
:command:`add_executable` or :command:`add_library` and must not be an
|
||||
:ref:`Imported Target <Imported Targets>`.
|
||||
:ref:`ALIAS target <Alias Targets>`.
|
||||
|
||||
The ``INTERFACE``, ``PUBLIC`` and ``PRIVATE`` keywords are required to
|
||||
specify the scope of the following arguments. ``PRIVATE`` and ``PUBLIC``
|
||||
items will populate the :prop_tgt:`COMPILE_DEFINITIONS` property of
|
||||
``<target>``. ``PUBLIC`` and ``INTERFACE`` items will populate the
|
||||
:prop_tgt:`INTERFACE_COMPILE_DEFINITIONS` property of ``<target>``. The
|
||||
following arguments specify compile definitions. Repeated calls for the
|
||||
:prop_tgt:`INTERFACE_COMPILE_DEFINITIONS` property of ``<target>``.
|
||||
(:ref:`IMPORTED targets <Imported Targets>` only support ``INTERFACE`` items.)
|
||||
The following arguments specify compile definitions. Repeated calls for the
|
||||
same ``<target>`` append items in the order called.
|
||||
|
||||
Arguments to ``target_compile_definitions`` may use "generator expressions"
|
||||
|
||||
@@ -18,12 +18,13 @@ The ``INTERFACE``, ``PUBLIC`` and ``PRIVATE`` keywords are required to
|
||||
specify the scope of the features. ``PRIVATE`` and ``PUBLIC`` items will
|
||||
populate the :prop_tgt:`COMPILE_FEATURES` property of ``<target>``.
|
||||
``PUBLIC`` and ``INTERFACE`` items will populate the
|
||||
:prop_tgt:`INTERFACE_COMPILE_FEATURES` property of ``<target>``. Repeated
|
||||
calls for the same ``<target>`` append items.
|
||||
:prop_tgt:`INTERFACE_COMPILE_FEATURES` property of ``<target>``.
|
||||
(:ref:`IMPORTED targets <Imported Targets>` only support ``INTERFACE`` items.)
|
||||
Repeated calls for the same ``<target>`` append items.
|
||||
|
||||
The named ``<target>`` must have been created by a command such as
|
||||
:command:`add_executable` or :command:`add_library` and must not be
|
||||
an ``IMPORTED`` target.
|
||||
:command:`add_executable` or :command:`add_library` and must not be an
|
||||
:ref:`ALIAS target <Alias Targets>`.
|
||||
|
||||
Arguments to ``target_compile_features`` may use "generator expressions"
|
||||
with the syntax ``$<...>``.
|
||||
|
||||
@@ -12,8 +12,10 @@ Add compile options to a target.
|
||||
Specify compile options to use when compiling a given target. The
|
||||
named ``<target>`` must have been created by a command such as
|
||||
:command:`add_executable` or :command:`add_library` and must not be an
|
||||
:ref:`IMPORTED Target <Imported Targets>`. If ``BEFORE`` is specified,
|
||||
the content will be prepended to the property instead of being appended.
|
||||
:ref:`ALIAS target <Alias Targets>`.
|
||||
|
||||
If ``BEFORE`` is specified, the content will be prepended to the property
|
||||
instead of being appended.
|
||||
|
||||
This command can be used to add any options, but
|
||||
alternative commands exist to add preprocessor definitions
|
||||
@@ -27,8 +29,9 @@ The ``INTERFACE``, ``PUBLIC`` and ``PRIVATE`` keywords are required to
|
||||
specify the scope of the following arguments. ``PRIVATE`` and ``PUBLIC``
|
||||
items will populate the :prop_tgt:`COMPILE_OPTIONS` property of
|
||||
``<target>``. ``PUBLIC`` and ``INTERFACE`` items will populate the
|
||||
:prop_tgt:`INTERFACE_COMPILE_OPTIONS` property of ``<target>``. The
|
||||
following arguments specify compile options. Repeated calls for the same
|
||||
:prop_tgt:`INTERFACE_COMPILE_OPTIONS` property of ``<target>``.
|
||||
(:ref:`IMPORTED targets <Imported Targets>` only support ``INTERFACE`` items.)
|
||||
The following arguments specify compile options. Repeated calls for the same
|
||||
``<target>`` append items in the order called.
|
||||
|
||||
Arguments to ``target_compile_options`` may use "generator expressions"
|
||||
|
||||
@@ -12,7 +12,7 @@ Add include directories to a target.
|
||||
Specify include directories to use when compiling a given target.
|
||||
The named ``<target>`` must have been created by a command such
|
||||
as :command:`add_executable` or :command:`add_library` and must not be an
|
||||
:prop_tgt:`IMPORTED` target.
|
||||
:ref:`ALIAS target <Alias Targets>`.
|
||||
|
||||
If ``BEFORE`` is specified, the content will be prepended to the property
|
||||
instead of being appended.
|
||||
@@ -21,9 +21,9 @@ The ``INTERFACE``, ``PUBLIC`` and ``PRIVATE`` keywords are required to specify
|
||||
the scope of the following arguments. ``PRIVATE`` and ``PUBLIC`` items will
|
||||
populate the :prop_tgt:`INCLUDE_DIRECTORIES` property of ``<target>``.
|
||||
``PUBLIC`` and ``INTERFACE`` items will populate the
|
||||
:prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES`
|
||||
property of ``<target>``. The following arguments specify include
|
||||
directories.
|
||||
:prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` property of ``<target>``.
|
||||
(:ref:`IMPORTED targets <Imported Targets>` only support ``INTERFACE`` items.)
|
||||
The following arguments specify include directories.
|
||||
|
||||
Specified include directories may be absolute paths or relative paths.
|
||||
Repeated calls for the same <target> append items in the order called. If
|
||||
|
||||
@@ -19,7 +19,8 @@ All of them have the general form::
|
||||
target_link_libraries(<target> ... <item>... ...)
|
||||
|
||||
The named ``<target>`` must have been created in the current directory by
|
||||
a command such as :command:`add_executable` or :command:`add_library`.
|
||||
a command such as :command:`add_executable` or :command:`add_library` and
|
||||
must not be an :ref:`ALIAS target <Alias Targets>`.
|
||||
Repeated calls for the same ``<target>`` append items in the order called.
|
||||
Each ``<item>`` may be:
|
||||
|
||||
|
||||
@@ -12,14 +12,15 @@ Add sources to a target.
|
||||
Specify sources to use when compiling a given target. The
|
||||
named ``<target>`` must have been created by a command such as
|
||||
:command:`add_executable` or :command:`add_library` and must not be an
|
||||
:ref:`IMPORTED Target <Imported Targets>`.
|
||||
:ref:`ALIAS target <Alias Targets>`.
|
||||
|
||||
The ``INTERFACE``, ``PUBLIC`` and ``PRIVATE`` keywords are required to
|
||||
specify the scope of the following arguments. ``PRIVATE`` and ``PUBLIC``
|
||||
items will populate the :prop_tgt:`SOURCES` property of
|
||||
``<target>``. ``PUBLIC`` and ``INTERFACE`` items will populate the
|
||||
:prop_tgt:`INTERFACE_SOURCES` property of ``<target>``. The
|
||||
following arguments specify sources. Repeated calls for the same
|
||||
:prop_tgt:`INTERFACE_SOURCES` property of ``<target>``.
|
||||
(:ref:`IMPORTED targets <Imported Targets>` only support ``INTERFACE`` items.)
|
||||
The following arguments specify sources. Repeated calls for the same
|
||||
``<target>`` append items in the order called.
|
||||
|
||||
Arguments to ``target_sources`` may use "generator expressions"
|
||||
|
||||
@@ -17,15 +17,6 @@ bool cmTargetCompileDefinitionsCommand::InitialPass(
|
||||
return this->HandleArguments(args, "COMPILE_DEFINITIONS");
|
||||
}
|
||||
|
||||
void cmTargetCompileDefinitionsCommand::HandleImportedTarget(
|
||||
const std::string& tgt)
|
||||
{
|
||||
std::ostringstream e;
|
||||
e << "Cannot specify compile definitions for imported target \"" << tgt
|
||||
<< "\".";
|
||||
this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
|
||||
}
|
||||
|
||||
void cmTargetCompileDefinitionsCommand::HandleMissingTarget(
|
||||
const std::string& name)
|
||||
{
|
||||
@@ -56,5 +47,5 @@ bool cmTargetCompileDefinitionsCommand::HandleDirectContent(
|
||||
cmTarget* tgt, const std::vector<std::string>& content, bool, bool)
|
||||
{
|
||||
tgt->AppendProperty("COMPILE_DEFINITIONS", this->Join(content).c_str());
|
||||
return true;
|
||||
return true; // Successfully handled.
|
||||
}
|
||||
|
||||
@@ -30,7 +30,6 @@ public:
|
||||
cmExecutionStatus& status) override;
|
||||
|
||||
private:
|
||||
void HandleImportedTarget(const std::string& tgt) override;
|
||||
void HandleMissingTarget(const std::string& name) override;
|
||||
|
||||
bool HandleDirectContent(cmTarget* tgt,
|
||||
|
||||
@@ -17,15 +17,6 @@ bool cmTargetCompileFeaturesCommand::InitialPass(
|
||||
return this->HandleArguments(args, "COMPILE_FEATURES", NO_FLAGS);
|
||||
}
|
||||
|
||||
void cmTargetCompileFeaturesCommand::HandleImportedTarget(
|
||||
const std::string& tgt)
|
||||
{
|
||||
std::ostringstream e;
|
||||
e << "Cannot specify compile features for imported target \"" << tgt
|
||||
<< "\".";
|
||||
this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
|
||||
}
|
||||
|
||||
void cmTargetCompileFeaturesCommand::HandleMissingTarget(
|
||||
const std::string& name)
|
||||
{
|
||||
@@ -49,8 +40,8 @@ bool cmTargetCompileFeaturesCommand::HandleDirectContent(
|
||||
std::string error;
|
||||
if (!this->Makefile->AddRequiredTargetFeature(tgt, it, &error)) {
|
||||
this->SetError(error);
|
||||
return false;
|
||||
return false; // Not (successfully) handled.
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return true; // Successfully handled.
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ class cmTargetCompileFeaturesCommand : public cmTargetPropCommandBase
|
||||
cmExecutionStatus& status) override;
|
||||
|
||||
private:
|
||||
void HandleImportedTarget(const std::string& tgt) override;
|
||||
void HandleMissingTarget(const std::string& name) override;
|
||||
|
||||
bool HandleDirectContent(cmTarget* tgt,
|
||||
|
||||
@@ -18,21 +18,12 @@ bool cmTargetCompileOptionsCommand::InitialPass(
|
||||
return this->HandleArguments(args, "COMPILE_OPTIONS", PROCESS_BEFORE);
|
||||
}
|
||||
|
||||
void cmTargetCompileOptionsCommand::HandleImportedTarget(
|
||||
const std::string& tgt)
|
||||
{
|
||||
std::ostringstream e;
|
||||
e << "Cannot specify compile options for imported target \"" << tgt << "\".";
|
||||
this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
|
||||
}
|
||||
|
||||
void cmTargetCompileOptionsCommand::HandleMissingTarget(
|
||||
const std::string& name)
|
||||
{
|
||||
std::ostringstream e;
|
||||
e << "Cannot specify compile options for target \"" << name
|
||||
<< "\" "
|
||||
"which is not built by this project.";
|
||||
<< "\" which is not built by this project.";
|
||||
this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
|
||||
}
|
||||
|
||||
@@ -47,5 +38,5 @@ bool cmTargetCompileOptionsCommand::HandleDirectContent(
|
||||
{
|
||||
cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
|
||||
tgt->InsertCompileOption(this->Join(content), lfbt);
|
||||
return true;
|
||||
return true; // Successfully handled.
|
||||
}
|
||||
|
||||
@@ -30,7 +30,6 @@ public:
|
||||
cmExecutionStatus& status) override;
|
||||
|
||||
private:
|
||||
void HandleImportedTarget(const std::string& tgt) override;
|
||||
void HandleMissingTarget(const std::string& name) override;
|
||||
|
||||
bool HandleDirectContent(cmTarget* tgt,
|
||||
|
||||
@@ -21,22 +21,12 @@ bool cmTargetIncludeDirectoriesCommand::InitialPass(
|
||||
ArgumentFlags(PROCESS_BEFORE | PROCESS_SYSTEM));
|
||||
}
|
||||
|
||||
void cmTargetIncludeDirectoriesCommand::HandleImportedTarget(
|
||||
const std::string& tgt)
|
||||
{
|
||||
std::ostringstream e;
|
||||
e << "Cannot specify include directories for imported target \"" << tgt
|
||||
<< "\".";
|
||||
this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
|
||||
}
|
||||
|
||||
void cmTargetIncludeDirectoriesCommand::HandleMissingTarget(
|
||||
const std::string& name)
|
||||
{
|
||||
std::ostringstream e;
|
||||
e << "Cannot specify include directories for target \"" << name
|
||||
<< "\" "
|
||||
"which is not built by this project.";
|
||||
<< "\" which is not built by this project.";
|
||||
this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
|
||||
}
|
||||
|
||||
@@ -79,7 +69,7 @@ bool cmTargetIncludeDirectoriesCommand::HandleDirectContent(
|
||||
}
|
||||
tgt->AddSystemIncludeDirectories(sdirs);
|
||||
}
|
||||
return true;
|
||||
return true; // Successfully handled.
|
||||
}
|
||||
|
||||
void cmTargetIncludeDirectoriesCommand::HandleInterfaceContent(
|
||||
|
||||
@@ -30,7 +30,6 @@ public:
|
||||
cmExecutionStatus& status) override;
|
||||
|
||||
private:
|
||||
void HandleImportedTarget(const std::string& tgt) override;
|
||||
void HandleMissingTarget(const std::string& name) override;
|
||||
|
||||
bool HandleDirectContent(cmTarget* tgt,
|
||||
|
||||
@@ -39,6 +39,16 @@ bool cmTargetLinkLibrariesCommand::InitialPass(
|
||||
this->Target =
|
||||
this->Makefile->GetCMakeInstance()->GetGlobalGenerator()->FindTarget(
|
||||
args[0]);
|
||||
if (!this->Target) {
|
||||
const std::vector<cmTarget*>& importedTargets =
|
||||
this->Makefile->GetOwnedImportedTargets();
|
||||
for (cmTarget* importedTarget : importedTargets) {
|
||||
if (importedTarget->GetName() == args[0]) {
|
||||
this->Target = importedTarget;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!this->Target) {
|
||||
cmake::MessageType t = cmake::FATAL_ERROR; // fail by default
|
||||
std::ostringstream e;
|
||||
@@ -228,7 +238,7 @@ bool cmTargetLinkLibrariesCommand::InitialPass(
|
||||
} else {
|
||||
// Lookup old-style cache entry if type is unspecified. So if you
|
||||
// do a target_link_libraries(foo optimized bar) it will stay optimized
|
||||
// and not use the lookup. As there maybe the case where someone has
|
||||
// and not use the lookup. As there may be the case where someone has
|
||||
// specifed that a library is both debug and optimized. (this check is
|
||||
// only there for backwards compatibility when mixing projects built
|
||||
// with old versions of CMake and new)
|
||||
@@ -299,6 +309,14 @@ bool cmTargetLinkLibrariesCommand::HandleLibrary(const std::string& lib,
|
||||
"target_link_libraries");
|
||||
return false;
|
||||
}
|
||||
if (this->Target->IsImported() &&
|
||||
this->CurrentProcessingState != ProcessingKeywordLinkInterface) {
|
||||
this->Makefile->IssueMessage(
|
||||
cmake::FATAL_ERROR,
|
||||
"IMPORTED library can only be used with the INTERFACE keyword of "
|
||||
"target_link_libraries");
|
||||
return false;
|
||||
}
|
||||
|
||||
cmTarget::TLLSignature sig =
|
||||
(this->CurrentProcessingState == ProcessingPlainPrivateInterface ||
|
||||
@@ -354,6 +372,16 @@ bool cmTargetLinkLibrariesCommand::HandleLibrary(const std::string& lib,
|
||||
|
||||
cmTarget* t =
|
||||
this->Makefile->FindLocalNonAliasTarget(this->Target->GetName());
|
||||
if (!t) {
|
||||
const std::vector<cmTarget*>& importedTargets =
|
||||
this->Makefile->GetOwnedImportedTargets();
|
||||
for (cmTarget* importedTarget : importedTargets) {
|
||||
if (importedTarget->GetName() == this->Target->GetName()) {
|
||||
t = importedTarget;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!t) {
|
||||
std::ostringstream e;
|
||||
e << "Attempt to add link library \"" << lib << "\" to target \""
|
||||
|
||||
@@ -84,17 +84,15 @@ bool cmTargetPropCommandBase::ProcessContentArgs(
|
||||
this->SetError("called with invalid arguments");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this->Target->IsImported()) {
|
||||
this->HandleImportedTarget(args[0]);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this->Target->GetType() == cmStateEnums::INTERFACE_LIBRARY &&
|
||||
scope != "INTERFACE") {
|
||||
this->SetError("may only set INTERFACE properties on INTERFACE targets");
|
||||
return false;
|
||||
}
|
||||
if (this->Target->IsImported() && scope != "INTERFACE") {
|
||||
this->SetError("may only set INTERFACE properties on IMPORTED targets");
|
||||
return false;
|
||||
}
|
||||
|
||||
++argIndex;
|
||||
|
||||
|
||||
@@ -35,7 +35,6 @@ protected:
|
||||
bool prepend, bool system);
|
||||
|
||||
private:
|
||||
virtual void HandleImportedTarget(const std::string& tgt) = 0;
|
||||
virtual void HandleMissingTarget(const std::string& name) = 0;
|
||||
|
||||
virtual bool HandleDirectContent(cmTarget* tgt,
|
||||
|
||||
@@ -17,13 +17,6 @@ bool cmTargetSourcesCommand::InitialPass(std::vector<std::string> const& args,
|
||||
return this->HandleArguments(args, "SOURCES");
|
||||
}
|
||||
|
||||
void cmTargetSourcesCommand::HandleImportedTarget(const std::string& tgt)
|
||||
{
|
||||
std::ostringstream e;
|
||||
e << "Cannot specify sources for imported target \"" << tgt << "\".";
|
||||
this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
|
||||
}
|
||||
|
||||
void cmTargetSourcesCommand::HandleMissingTarget(const std::string& name)
|
||||
{
|
||||
std::ostringstream e;
|
||||
@@ -43,5 +36,5 @@ bool cmTargetSourcesCommand::HandleDirectContent(
|
||||
cmTarget* tgt, const std::vector<std::string>& content, bool, bool)
|
||||
{
|
||||
tgt->AppendProperty("SOURCES", this->Join(content).c_str());
|
||||
return true;
|
||||
return true; // Successfully handled.
|
||||
}
|
||||
|
||||
@@ -30,7 +30,6 @@ public:
|
||||
cmExecutionStatus& status) override;
|
||||
|
||||
private:
|
||||
void HandleImportedTarget(const std::string& tgt) override;
|
||||
void HandleMissingTarget(const std::string& name) override;
|
||||
|
||||
bool HandleDirectContent(cmTarget* tgt,
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
^CMake Error at UNKNOWNwithNoSourcesButLinkObjects.cmake:[0-9]+ \(target_link_libraries\):
|
||||
Cannot specify link libraries for target \"TestUnknownLibWithoutSources\"
|
||||
which is not built by this project.
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)$
|
||||
@@ -2,4 +2,4 @@ enable_language(CXX)
|
||||
add_library(ObjectLibDependency OBJECT test.cpp)
|
||||
|
||||
add_library(TestUnknownLibWithoutSources UNKNOWN IMPORTED)
|
||||
target_link_libraries(TestUnknownLibWithoutSources PUBLIC $<TARGET_OBJECTS:ObjectLibDependency>)
|
||||
target_link_libraries(TestUnknownLibWithoutSources INTERFACE $<TARGET_OBJECTS:ObjectLibDependency>)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
CMake Error at imported_target.cmake:[0-9]+ \(target_compile_features\):
|
||||
Cannot specify compile features for imported target "main".
|
||||
^CMake Error at imported_target.cmake:[0-9]+ \(target_compile_features\):
|
||||
target_compile_features may only set INTERFACE properties on INTERFACE
|
||||
targets
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:3 \(include\)
|
||||
CMakeLists.txt:3 \(include\)$
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
enable_language(CXX)
|
||||
|
||||
add_library(main INTERFACE IMPORTED)
|
||||
target_compile_features(main INTERFACE cxx_delegating_constructors)
|
||||
add_library(lib1-interface INTERFACE IMPORTED)
|
||||
target_compile_features(lib1-interface INTERFACE cxx_delegating_constructors)
|
||||
|
||||
add_library(lib2-interface INTERFACE IMPORTED)
|
||||
target_compile_features(lib2-interface PUBLIC cxx_delegating_constructors)
|
||||
|
||||
add_library(lib-shared SHARED IMPORTED)
|
||||
target_compile_features(lib-shared INTERFACE cxx_delegating_constructors)
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
add_library(UnknownImportedGlobal UNKNOWN IMPORTED GLOBAL)
|
||||
target_link_libraries(UnknownImportedGlobal INTERFACE z)
|
||||
@@ -0,0 +1,5 @@
|
||||
^CMake Error at ImportedTargetFailure.cmake:[0-9]+ \(target_link_libraries\):
|
||||
IMPORTED library can only be used with the INTERFACE keyword of
|
||||
target_link_libraries
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists\.txt:[0-9]+ \(include\)$
|
||||
@@ -0,0 +1,2 @@
|
||||
add_library(UnknownImportedGlobal UNKNOWN IMPORTED GLOBAL)
|
||||
target_link_libraries(UnknownImportedGlobal PRIVATE z)
|
||||
@@ -4,6 +4,8 @@ run_cmake(CMP0023-WARN)
|
||||
run_cmake(CMP0023-NEW)
|
||||
run_cmake(CMP0023-WARN-2)
|
||||
run_cmake(CMP0023-NEW-2)
|
||||
run_cmake(ImportedTarget)
|
||||
run_cmake(ImportedTargetFailure)
|
||||
run_cmake(MixedSignature)
|
||||
run_cmake(Separate-PRIVATE-LINK_PRIVATE-uses)
|
||||
run_cmake(SubDirTarget)
|
||||
|
||||
Reference in New Issue
Block a user