cmGeneratorExpressionNode: implement COMPILE_ONLY
genex
This generator expression is the inverse of `LINK_ONLY` and only coveys usage requirements for the purposes of compilation. Its intended use is to avoid needing to export targets that do not have link usage requirements (e.g., header-only libraries) when used by another target. It will also be used to represent private usage requirements on exported C++ module-containing targets in the future. Eventually there should be logic to collapse nesting of `$<COMPILE_ONLY>` and `$<LINK_ONLY>` when generating instances of either. A TODO is left in the code for this case. See: #15415
This commit is contained in:
parent
6c11f7e4a8
commit
0fb923c460
@ -959,6 +959,22 @@ 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 ``...``, except while collecting :ref:`Target Usage Requirements`,
|
||||
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
|
||||
compilation requirements without other usage 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).
|
||||
|
||||
Linker Language And ID
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
@ -1339,7 +1355,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
|
||||
|
5
Help/release/dev/genex-compile-only.rst
Normal file
5
Help/release/dev/genex-compile-only.rst
Normal file
@ -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.
|
@ -734,6 +734,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()) {
|
||||
|
@ -1351,6 +1351,29 @@ 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 via linking");
|
||||
return std::string();
|
||||
}
|
||||
// Linking checks for the inverse, so compiling is the opposite.
|
||||
if (dagChecker->GetTransitivePropertiesOnly()) {
|
||||
return parameters.front();
|
||||
}
|
||||
return std::string();
|
||||
}
|
||||
} compileOnlyNode;
|
||||
|
||||
static const struct LinkOnlyNode : public cmGeneratorExpressionNode
|
||||
{
|
||||
LinkOnlyNode() {} // NOLINT(modernize-use-equals-default)
|
||||
@ -1366,6 +1389,7 @@ static const struct LinkOnlyNode : public cmGeneratorExpressionNode
|
||||
"$<LINK_ONLY:...> may only be used for linking");
|
||||
return std::string();
|
||||
}
|
||||
// Compile-only checks for the inverse, so linking is the opposite.
|
||||
if (!dagChecker->GetTransitivePropertiesOnly()) {
|
||||
return parameters.front();
|
||||
}
|
||||
@ -3805,6 +3829,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 },
|
||||
|
@ -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) ||
|
||||
|
@ -0,0 +1 @@
|
||||
1
|
@ -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 via linking
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:3 \(include\)
|
@ -0,0 +1 @@
|
||||
add_custom_target(Custom ALL COMMAND ${CMAKE_COMMAND} -E echo $<COMPILE_ONLY:something>)
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user