summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2023-05-05 16:42:08 (GMT)
committerKitware Robot <kwrobot@kitware.com>2023-05-05 16:42:23 (GMT)
commit5924630e6d4a383ef76412a6f560fbe852837e50 (patch)
treefbab8184157448c3251e09feee8e4ce5c0b6234e
parent2b5b09556c08bdbcd949e600daa3059f63da240a (diff)
parentc42630ee62df80e649211e99c510cab7ac28fc0b (diff)
downloadCMake-5924630e6d4a383ef76412a6f560fbe852837e50.zip
CMake-5924630e6d4a383ef76412a6f560fbe852837e50.tar.gz
CMake-5924630e6d4a383ef76412a6f560fbe852837e50.tar.bz2
Merge topic 'compile-only-genex'
c42630ee62 cmGeneratorExpressionNode: implement `COMPILE_ONLY` genex 0fb923c460 cmGeneratorExpressionNode: implement `COMPILE_ONLY` genex Acked-by: Kitware Robot <kwrobot@kitware.com> Tested-by: buildbot <buildbot@kitware.com> Merge-request: !8411
-rw-r--r--Help/manual/cmake-generator-expressions.7.rst22
-rw-r--r--Help/release/dev/genex-compile-only.rst5
-rw-r--r--Source/cmExportFileGenerator.cxx16
-rw-r--r--Source/cmGeneratorExpressionDAGChecker.cxx8
-rw-r--r--Source/cmGeneratorExpressionDAGChecker.h4
-rw-r--r--Source/cmGeneratorExpressionNode.cxx25
-rw-r--r--Source/cmGeneratorTarget.cxx4
-rw-r--r--Source/cmTargetLinkLibrariesCommand.cxx1
-rw-r--r--Tests/CMakeCommands/target_link_libraries/CMakeLists.txt16
-rw-r--r--Tests/CMakeCommands/target_link_libraries/compile_only.cpp8
-rw-r--r--Tests/ExportImport/Export/CMakeLists.txt10
-rw-r--r--Tests/ExportImport/Export/testLib2.c4
-rw-r--r--Tests/RunCMake/GeneratorExpression/COMPILE_ONLY-not-compiling-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorExpression/COMPILE_ONLY-not-compiling-stderr.txt8
-rw-r--r--Tests/RunCMake/GeneratorExpression/COMPILE_ONLY-not-compiling.cmake1
-rw-r--r--Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake1
16 files changed, 131 insertions, 3 deletions
diff --git a/Help/manual/cmake-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst
index 9d29dc3..473e8d7 100644
--- a/Help/manual/cmake-generator-expressions.7.rst
+++ b/Help/manual/cmake-generator-expressions.7.rst
@@ -1219,6 +1219,25 @@ Compile Features
:manual:`cmake-compile-features(7)` manual for information on
compile features and a list of supported compilers.
+Compile Context
+^^^^^^^^^^^^^^^
+
+.. genex:: $<COMPILE_ONLY:...>
+
+ .. versionadded:: 3.27
+
+ Content of ``...``, when collecting :ref:`Target Usage Requirements`,
+ otherwise it is the empty string. This is intended for use in an
+ :prop_tgt:`INTERFACE_LINK_LIBRARIES` and :prop_tgt:`LINK_LIBRARIES` target
+ properties, typically populated via the :command:`target_link_libraries` command.
+ Provides compilation usage requirements without any linking requirements.
+
+ Use cases include header-only usage where all usages are known to not have
+ linking requirements (e.g., all-``inline`` or C++ template libraries).
+
+ Note that for proper evaluation of this expression requires policy :policy:`CMP0099`
+ to be set to `NEW`.
+
Linker Language And ID
^^^^^^^^^^^^^^^^^^^^^^
@@ -1599,7 +1618,8 @@ Link Context
in which case it is the empty string. This is intended for use in an
:prop_tgt:`INTERFACE_LINK_LIBRARIES` target property, typically populated
via the :command:`target_link_libraries` command, to specify private link
- dependencies without other usage requirements.
+ dependencies without other usage requirements such as include directories or
+ compile options.
.. versionadded:: 3.24
``LINK_ONLY`` may also be used in a :prop_tgt:`LINK_LIBRARIES` target
diff --git a/Help/release/dev/genex-compile-only.rst b/Help/release/dev/genex-compile-only.rst
new file mode 100644
index 0000000..1f898d8
--- /dev/null
+++ b/Help/release/dev/genex-compile-only.rst
@@ -0,0 +1,5 @@
+genex-compile-only
+------------------
+
+* The :genex:`COMPILE_ONLY` generator expression has been added which provides
+ compilation usage requirements without any linking requirements.
diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx
index 2ad2b47..22276ae 100644
--- a/Source/cmExportFileGenerator.cxx
+++ b/Source/cmExportFileGenerator.cxx
@@ -735,6 +735,22 @@ void cmExportFileGenerator::ResolveTargetsInGeneratorExpression(
lastPos = nameStartPos + libName.size() + 1;
}
+ while (errorString.empty() &&
+ (pos = input.find("$<COMPILE_ONLY:", lastPos)) != std::string::npos) {
+ std::string::size_type nameStartPos = pos + cmStrLen("$<COMPILE_ONLY:");
+ std::string::size_type endPos = input.find('>', nameStartPos);
+ if (endPos == std::string::npos) {
+ errorString = "$<COMPILE_ONLY:...> expression incomplete";
+ break;
+ }
+ std::string libName = input.substr(nameStartPos, endPos - nameStartPos);
+ if (cmGeneratorExpression::IsValidTargetName(libName) &&
+ this->AddTargetNamespace(libName, target, lg)) {
+ input.replace(nameStartPos, endPos - nameStartPos, libName);
+ }
+ lastPos = nameStartPos + libName.size() + 1;
+ }
+
this->ReplaceInstallPrefix(input);
if (!errorString.empty()) {
diff --git a/Source/cmGeneratorExpressionDAGChecker.cxx b/Source/cmGeneratorExpressionDAGChecker.cxx
index 82a6c57..d51dbd0 100644
--- a/Source/cmGeneratorExpressionDAGChecker.cxx
+++ b/Source/cmGeneratorExpressionDAGChecker.cxx
@@ -27,6 +27,7 @@ cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker(
, Content(content)
, Backtrace(std::move(backtrace))
, TransitivePropertiesOnly(false)
+ , CMP0131(false)
{
this->Initialize();
}
@@ -41,6 +42,7 @@ cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker(
, Content(content)
, Backtrace()
, TransitivePropertiesOnly(false)
+ , CMP0131(false)
{
this->Initialize();
}
@@ -143,6 +145,12 @@ bool cmGeneratorExpressionDAGChecker::GetTransitivePropertiesOnly() const
return this->Top()->TransitivePropertiesOnly;
}
+bool cmGeneratorExpressionDAGChecker::GetTransitivePropertiesOnlyCMP0131()
+ const
+{
+ return this->Top()->CMP0131;
+}
+
bool cmGeneratorExpressionDAGChecker::EvaluatingGenexExpression() const
{
return cmHasLiteralPrefix(this->Property, "TARGET_GENEX_EVAL:") ||
diff --git a/Source/cmGeneratorExpressionDAGChecker.h b/Source/cmGeneratorExpressionDAGChecker.h
index df1e005..1919b01 100644
--- a/Source/cmGeneratorExpressionDAGChecker.h
+++ b/Source/cmGeneratorExpressionDAGChecker.h
@@ -90,6 +90,9 @@ struct cmGeneratorExpressionDAGChecker
bool GetTransitivePropertiesOnly() const;
void SetTransitivePropertiesOnly() { this->TransitivePropertiesOnly = true; }
+ bool GetTransitivePropertiesOnlyCMP0131() const;
+ void SetTransitivePropertiesOnlyCMP0131() { this->CMP0131 = true; }
+
cmGeneratorExpressionDAGChecker const* Top() const;
cmGeneratorTarget const* TopTarget() const;
@@ -105,4 +108,5 @@ private:
const cmListFileBacktrace Backtrace;
Result CheckResult;
bool TransitivePropertiesOnly;
+ bool CMP0131;
};
diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx
index 4f5a663..bb4fc7e 100644
--- a/Source/cmGeneratorExpressionNode.cxx
+++ b/Source/cmGeneratorExpressionNode.cxx
@@ -2046,6 +2046,28 @@ static const VersionNode<cmSystemTools::OP_LESS> versionLessNode;
static const VersionNode<cmSystemTools::OP_LESS_EQUAL> versionLessEqNode;
static const VersionNode<cmSystemTools::OP_EQUAL> versionEqualNode;
+static const struct CompileOnlyNode : public cmGeneratorExpressionNode
+{
+ CompileOnlyNode() {} // NOLINT(modernize-use-equals-default)
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* dagChecker) const override
+ {
+ if (!dagChecker) {
+ reportError(context, content->GetOriginalExpression(),
+ "$<COMPILE_ONLY:...> may only be used for linking");
+ return std::string();
+ }
+ if (dagChecker->GetTransitivePropertiesOnly()) {
+ return parameters.front();
+ }
+ return std::string{};
+ }
+} compileOnlyNode;
+
static const struct LinkOnlyNode : public cmGeneratorExpressionNode
{
LinkOnlyNode() {} // NOLINT(modernize-use-equals-default)
@@ -2061,7 +2083,7 @@ static const struct LinkOnlyNode : public cmGeneratorExpressionNode
"$<LINK_ONLY:...> may only be used for linking");
return std::string();
}
- if (!dagChecker->GetTransitivePropertiesOnly()) {
+ if (!dagChecker->GetTransitivePropertiesOnlyCMP0131()) {
return parameters.front();
}
return std::string();
@@ -4501,6 +4523,7 @@ const cmGeneratorExpressionNode* cmGeneratorExpressionNode::GetNode(
{ "BUILD_LOCAL_INTERFACE", &buildLocalInterfaceNode },
{ "INSTALL_PREFIX", &installPrefixNode },
{ "JOIN", &joinNode },
+ { "COMPILE_ONLY", &compileOnlyNode },
{ "LINK_ONLY", &linkOnlyNode },
{ "COMPILE_LANG_AND_ID", &languageAndIdNode },
{ "COMPILE_LANGUAGE", &languageNode },
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index 897619c..28ba60f 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -6791,6 +6791,7 @@ void cmGeneratorTarget::ExpandLinkItems(
// requirements.
if (interfaceFor == LinkInterfaceFor::Usage) {
dagChecker.SetTransitivePropertiesOnly();
+ dagChecker.SetTransitivePropertiesOnlyCMP0131();
}
cmMakefile const* mf = this->LocalGenerator->GetMakefile();
LookupLinkItemScope scope{ this->LocalGenerator };
@@ -8228,6 +8229,7 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries(
// The $<LINK_ONLY> expression may be used to specify link dependencies
// that are otherwise excluded from usage requirements.
if (implFor == LinkInterfaceFor::Usage) {
+ dagChecker.SetTransitivePropertiesOnly();
switch (this->GetPolicyStatusCMP0131()) {
case cmPolicies::WARN:
case cmPolicies::OLD:
@@ -8235,7 +8237,7 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries(
case cmPolicies::REQUIRED_IF_USED:
case cmPolicies::REQUIRED_ALWAYS:
case cmPolicies::NEW:
- dagChecker.SetTransitivePropertiesOnly();
+ dagChecker.SetTransitivePropertiesOnlyCMP0131();
break;
}
}
diff --git a/Source/cmTargetLinkLibrariesCommand.cxx b/Source/cmTargetLinkLibrariesCommand.cxx
index 0b123b2..03d7c9f 100644
--- a/Source/cmTargetLinkLibrariesCommand.cxx
+++ b/Source/cmTargetLinkLibrariesCommand.cxx
@@ -552,6 +552,7 @@ bool TLL::HandleLibrary(ProcessingState currentProcessingState,
currentProcessingState == ProcessingPlainPrivateInterface) {
if (this->Target->GetType() == cmStateEnums::STATIC_LIBRARY ||
this->Target->GetType() == cmStateEnums::OBJECT_LIBRARY) {
+ // TODO: Detect and no-op `$<COMPILE_ONLY>` genexes here.
std::string configLib =
this->Target->GetDebugGeneratorExpressions(lib, llt);
if (cmGeneratorExpression::IsValidTargetName(lib) ||
diff --git a/Tests/CMakeCommands/target_link_libraries/CMakeLists.txt b/Tests/CMakeCommands/target_link_libraries/CMakeLists.txt
index b2365ca..8231a5c 100644
--- a/Tests/CMakeCommands/target_link_libraries/CMakeLists.txt
+++ b/Tests/CMakeCommands/target_link_libraries/CMakeLists.txt
@@ -155,3 +155,19 @@ target_link_libraries(TopDir SubDirC)
add_library(TopDirImported IMPORTED INTERFACE)
target_compile_definitions(TopDirImported INTERFACE DEF_TopDirImported)
cmake_policy(POP)
+
+#----------------------------------------------------------------------------
+# Test $<COMPILE_ONLY:> genex.
+cmake_policy(SET CMP0099 NEW)
+add_library(dont_link_too SHARED compile_only.cpp)
+target_compile_definitions(dont_link_too PUBLIC USE_EXAMPLE)
+target_link_options(dont_link_too INTERFACE invalid_link_option)
+target_link_libraries(dont_link_too INTERFACE invalid_link_library)
+
+add_library(uses_compile_only_genex SHARED compile_only.cpp)
+target_link_libraries(uses_compile_only_genex PUBLIC $<COMPILE_ONLY:dont_link_too>)
+
+add_library(uses_compile_only_genex_static STATIC compile_only.cpp)
+target_link_libraries(uses_compile_only_genex_static PRIVATE $<COMPILE_ONLY:dont_link_too>)
+add_executable(uses_via_static_linking main.cxx)
+target_link_libraries(uses_via_static_linking PRIVATE uses_compile_only_genex_static)
diff --git a/Tests/CMakeCommands/target_link_libraries/compile_only.cpp b/Tests/CMakeCommands/target_link_libraries/compile_only.cpp
new file mode 100644
index 0000000..7519bd0
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/compile_only.cpp
@@ -0,0 +1,8 @@
+
+#ifndef USE_EXAMPLE
+# error "Missing propagated define"
+#endif
+
+// Solaris needs non-empty content so ensure
+// we have at least one symbol
+int Solaris_requires_a_symbol_here = 0;
diff --git a/Tests/ExportImport/Export/CMakeLists.txt b/Tests/ExportImport/Export/CMakeLists.txt
index 6f19c13..67f2fcb 100644
--- a/Tests/ExportImport/Export/CMakeLists.txt
+++ b/Tests/ExportImport/Export/CMakeLists.txt
@@ -22,9 +22,18 @@ add_executable(testExe2 testExe2.c)
set_property(TARGET testExe2 PROPERTY ENABLE_EXPORTS 1)
set_property(TARGET testExe2 PROPERTY LINK_INTERFACE_LIBRARIES testExe2lib)
+add_library(compileOnly INTERFACE)
+target_compile_definitions(compileOnly INTERFACE FROM_compileOnly)
+target_link_options(compileOnly INTERFACE -fthis-flag-does-not-exist)
+
add_library(testLib1 STATIC testLib1.c)
add_library(testLib2 STATIC testLib2.c)
target_link_libraries(testLib2 testLib1)
+target_link_libraries(testLib2
+ PRIVATE
+ testLib1
+ "$<COMPILE_ONLY:compileOnly>")
+
# Test install(FILES) with generator expressions referencing testLib1.
add_custom_command(TARGET testLib1 POST_BUILD
@@ -556,6 +565,7 @@ install(FILES
# Install and export from install tree.
install(
TARGETS
+ compileOnly
testExe1 testLib1 testLib2 testExe2 testLib3 testLib4 testExe3 testExe4
testExe2lib testLib4lib testLib4libdbg testLib4libopt
testLib6 testLib7 testLib8
diff --git a/Tests/ExportImport/Export/testLib2.c b/Tests/ExportImport/Export/testLib2.c
index 7a5206f..f5faffa 100644
--- a/Tests/ExportImport/Export/testLib2.c
+++ b/Tests/ExportImport/Export/testLib2.c
@@ -1,4 +1,8 @@
+#ifndef FROM_compileOnly
+# error "Usage requirements from `compileOnly` not found"
+#endif
+
extern int testLib1(void);
int testLib2(void)
diff --git a/Tests/RunCMake/GeneratorExpression/COMPILE_ONLY-not-compiling-result.txt b/Tests/RunCMake/GeneratorExpression/COMPILE_ONLY-not-compiling-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/COMPILE_ONLY-not-compiling-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GeneratorExpression/COMPILE_ONLY-not-compiling-stderr.txt b/Tests/RunCMake/GeneratorExpression/COMPILE_ONLY-not-compiling-stderr.txt
new file mode 100644
index 0000000..8c93d59
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/COMPILE_ONLY-not-compiling-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at COMPILE_ONLY-not-compiling.cmake:1 \(add_custom_target\):
+ Error evaluating generator expression:
+
+ \$<COMPILE_ONLY:something>
+
+ \$<COMPILE_ONLY:...> may only be used for linking
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/COMPILE_ONLY-not-compiling.cmake b/Tests/RunCMake/GeneratorExpression/COMPILE_ONLY-not-compiling.cmake
new file mode 100644
index 0000000..1bc75f9
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/COMPILE_ONLY-not-compiling.cmake
@@ -0,0 +1 @@
+add_custom_target(Custom ALL COMMAND ${CMAKE_COMMAND} -E echo $<COMPILE_ONLY:something>)
diff --git a/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake b/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake
index b139210..3fd9947 100644
--- a/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake
+++ b/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake
@@ -22,6 +22,7 @@ run_cmake(NonValidTarget-CXX_COMPILER_VERSION)
run_cmake(NonValidTarget-Fortran_COMPILER_VERSION)
run_cmake(NonValidTarget-TARGET_PROPERTY)
run_cmake(NonValidTarget-TARGET_POLICY)
+run_cmake(COMPILE_ONLY-not-compiling)
run_cmake(LINK_ONLY-not-linking)
run_cmake(TARGET_EXISTS-no-arg)
run_cmake(TARGET_EXISTS-empty-arg)