mirror of
https://github.com/Kitware/CMake.git
synced 2025-10-14 02:08:27 +08:00
Merge topic 'genex-target-intermediate-dir'
f195c9ef2a
genex: Add TARGET_INTERMEDIATE_DIR expression5c5634db52
cmGeneratorExpressionNode: Factor out HasKnownObjectFileLocation check Acked-by: Kitware Robot <kwrobot@kitware.com> Merge-request: !11217
This commit is contained in:
@@ -2836,6 +2836,13 @@ In the following, the phrase "the ``tgt`` filename" means the name of the
|
||||
This generator expression can e.g. be used to create a batch file using
|
||||
:command:`file(GENERATE)` which sets the PATH environment variable accordingly.
|
||||
|
||||
.. genex:: $<TARGET_INTERMEDIATE_DIR:tgt>
|
||||
|
||||
.. versionadded:: 4.2
|
||||
|
||||
The full path to the directory where intermediate target files, such as
|
||||
object and dependency files, are stored.
|
||||
|
||||
Export And Install Expressions
|
||||
------------------------------
|
||||
|
||||
|
6
Help/release/dev/genex-target-intermediate-dir.rst
Normal file
6
Help/release/dev/genex-target-intermediate-dir.rst
Normal file
@@ -0,0 +1,6 @@
|
||||
genex-target-intermediate-dir
|
||||
-----------------------------
|
||||
|
||||
* The :genex:`TARGET_INTERMEDIATE_DIR` generator expression was
|
||||
added to refer to a target's intermediate files directory in
|
||||
the build tree.
|
@@ -52,6 +52,31 @@
|
||||
#include "cmValue.h"
|
||||
#include "cmake.h"
|
||||
|
||||
namespace {
|
||||
|
||||
bool HasKnownObjectFileLocation(cm::GenEx::Evaluation* eval,
|
||||
GeneratorExpressionContent const* content,
|
||||
std::string const& genex,
|
||||
cmGeneratorTarget const* target)
|
||||
{
|
||||
std::string reason;
|
||||
if (!eval->EvaluateForBuildsystem &&
|
||||
!target->Target->HasKnownObjectFileLocation(&reason)) {
|
||||
std::ostringstream e;
|
||||
e << "The evaluation of the " << genex
|
||||
<< " generator expression "
|
||||
"is only suitable for consumption by CMake (limited"
|
||||
<< reason
|
||||
<< "). "
|
||||
"It is not suitable for writing out elsewhere.";
|
||||
reportError(eval, content->GetOriginalExpression(), e.str());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::string cmGeneratorExpressionNode::EvaluateDependentExpression(
|
||||
std::string const& prop, cm::GenEx::Evaluation* eval,
|
||||
cmGeneratorTarget const* headTarget,
|
||||
@@ -3227,6 +3252,71 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
|
||||
}
|
||||
} targetPropertyNode;
|
||||
|
||||
static const struct targetIntermediateDirNode
|
||||
: public cmGeneratorExpressionNode
|
||||
{
|
||||
targetIntermediateDirNode() {} // NOLINT(modernize-use-equals-default)
|
||||
|
||||
static char const* GetErrorText(std::string const& targetName)
|
||||
{
|
||||
static cmsys::RegularExpression propertyNameValidator("^[A-Za-z0-9_]+$");
|
||||
if (targetName.empty()) {
|
||||
return "$<TARGET_INTERMEDIATE_DIR:tgt> expression requires a non-empty "
|
||||
"target name.";
|
||||
}
|
||||
if (!cmGeneratorExpression::IsValidTargetName(targetName)) {
|
||||
return "Target name not supported.";
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string Evaluate(
|
||||
std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
|
||||
GeneratorExpressionContent const* content,
|
||||
cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
|
||||
{
|
||||
cmGeneratorTarget const* target = nullptr;
|
||||
std::string targetName;
|
||||
|
||||
if (parameters.size() == 1) {
|
||||
targetName = parameters[0];
|
||||
|
||||
if (char const* e = GetErrorText(targetName)) {
|
||||
reportError(eval, content->GetOriginalExpression(), e);
|
||||
return std::string();
|
||||
}
|
||||
cmLocalGenerator const* lg = eval->CurrentTarget
|
||||
? eval->CurrentTarget->GetLocalGenerator()
|
||||
: eval->Context.LG;
|
||||
target = lg->FindGeneratorTargetToUse(targetName);
|
||||
|
||||
if (!target) {
|
||||
std::ostringstream e;
|
||||
e << "Target \"" << targetName << "\" not found.";
|
||||
reportError(eval, content->GetOriginalExpression(), e.str());
|
||||
return std::string();
|
||||
}
|
||||
eval->AllTargets.insert(target);
|
||||
|
||||
} else {
|
||||
reportError(
|
||||
eval, content->GetOriginalExpression(),
|
||||
"$<TARGET_INTERMEDIATE_DIR:...> expression requires one parameter");
|
||||
return std::string();
|
||||
}
|
||||
|
||||
assert(target);
|
||||
|
||||
if (!HasKnownObjectFileLocation(eval, content, "TARGET_INTERMEDIATE_DIR",
|
||||
target)) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
return cmSystemTools::CollapseFullPath(
|
||||
target->GetObjectDirectory(eval->Context.Config));
|
||||
}
|
||||
} targetIntermediateDirNode;
|
||||
|
||||
static const struct TargetNameNode : public cmGeneratorExpressionNode
|
||||
{
|
||||
TargetNameNode() {} // NOLINT(modernize-use-equals-default)
|
||||
@@ -3282,19 +3372,8 @@ static const struct TargetObjectsNode : public cmGeneratorExpressionNode
|
||||
return std::string();
|
||||
}
|
||||
cmGlobalGenerator const* gg = eval->Context.LG->GetGlobalGenerator();
|
||||
{
|
||||
std::string reason;
|
||||
if (!eval->EvaluateForBuildsystem &&
|
||||
!gt->Target->HasKnownObjectFileLocation(&reason)) {
|
||||
std::ostringstream e;
|
||||
e << "The evaluation of the TARGET_OBJECTS generator expression "
|
||||
"is only suitable for consumption by CMake (limited"
|
||||
<< reason
|
||||
<< "). "
|
||||
"It is not suitable for writing out elsewhere.";
|
||||
reportError(eval, content->GetOriginalExpression(), e.str());
|
||||
return std::string();
|
||||
}
|
||||
if (!HasKnownObjectFileLocation(eval, content, "TARGET_OBJECTS", gt)) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
cmList objects;
|
||||
@@ -4809,6 +4888,7 @@ cmGeneratorExpressionNode const* cmGeneratorExpressionNode::GetNode(
|
||||
{ "SEMICOLON", &semicolonNode },
|
||||
{ "QUOTE", "eNode },
|
||||
{ "TARGET_PROPERTY", &targetPropertyNode },
|
||||
{ "TARGET_INTERMEDIATE_DIR", &targetIntermediateDirNode },
|
||||
{ "TARGET_NAME", &targetNameNode },
|
||||
{ "TARGET_OBJECTS", &targetObjectsNode },
|
||||
{ "TARGET_POLICY", &targetPolicyNode },
|
||||
|
@@ -526,8 +526,13 @@ add_RunCMake_test(GenEx-TARGET_RUNTIME_DLLS)
|
||||
add_RunCMake_test(GenEx-PATH)
|
||||
add_RunCMake_test(GenEx-PATH_EQUAL)
|
||||
add_RunCMake_test(GenEx-LIST)
|
||||
add_RunCMake_test(GeneratorExpression -DCMake_TEST_OBJC=${CMake_TEST_OBJC} -DCMake_TEST_Fortran=${CMake_TEST_Fortran}
|
||||
-DCMake_TEST_CUDA=${CMake_TEST_CUDA} -DCMake_TEST_HIP=${CMake_TEST_HIP})
|
||||
add_RunCMake_test(GeneratorExpression
|
||||
-DCMake_TEST_OBJC=${CMake_TEST_OBJC}
|
||||
-DCMake_TEST_Fortran=${CMake_TEST_Fortran}
|
||||
-DCMake_TEST_CUDA=${CMake_TEST_CUDA}
|
||||
-DCMake_TEST_HIP=${CMake_TEST_HIP}
|
||||
-DCMAKE_C_OUTPUT_EXTENSION=${CMAKE_C_OUTPUT_EXTENSION}
|
||||
)
|
||||
add_RunCMake_test(GeneratorExpressionShortCircuit)
|
||||
add_RunCMake_test(GeneratorInstance)
|
||||
add_RunCMake_test(GeneratorPlatform)
|
||||
|
@@ -56,7 +56,10 @@ function(run_cmake_build test)
|
||||
list(APPEND RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Release)
|
||||
endif()
|
||||
|
||||
run_cmake(${test})
|
||||
block()
|
||||
unset(RunCMake-check-file)
|
||||
run_cmake(${test})
|
||||
endblock()
|
||||
|
||||
set(RunCMake_TEST_NO_CLEAN TRUE)
|
||||
run_cmake_command(${test}-build ${CMAKE_COMMAND} --build . --config Release)
|
||||
@@ -138,3 +141,19 @@ run_cmake(CMP0085-WARN)
|
||||
set(RunCMake_TEST_OPTIONS -DCMAKE_POLICY_DEFAULT_CMP0085:STRING=NEW)
|
||||
run_cmake(CMP0085-NEW)
|
||||
unset(RunCMake_TEST_OPTIONS)
|
||||
|
||||
if(RunCMake_GENERATOR STREQUAL "Xcode" AND "$ENV{CMAKE_OSX_ARCHITECTURES}" MATCHES "[;$]")
|
||||
run_cmake(TARGET_INTERMEDIATE_DIR-Xcode)
|
||||
else()
|
||||
block()
|
||||
set(RunCMake-check-file TARGET_INTERMEDIATE_DIR-build-check.cmake)
|
||||
foreach(strategy IN ITEMS SHORT FULL)
|
||||
set(CMAKE_INTERMEDIATE_DIR_STRATEGY ${strategy})
|
||||
set(RunCMake_TEST_OPTIONS -DCMAKE_INTERMEDIATE_DIR_STRATEGY=${strategy})
|
||||
run_cmake_build(TARGET_INTERMEDIATE_DIR-${strategy})
|
||||
endforeach()
|
||||
endblock()
|
||||
endif()
|
||||
run_cmake(TARGET_INTERMEDIATE_DIR-bad-arg)
|
||||
run_cmake(TARGET_INTERMEDIATE_DIR-bad-target)
|
||||
run_cmake(TARGET_INTERMEDIATE_DIR-not-a-target)
|
||||
|
@@ -0,0 +1 @@
|
||||
include(TARGET_INTERMEDIATE_DIR.cmake)
|
@@ -0,0 +1 @@
|
||||
include(TARGET_INTERMEDIATE_DIR.cmake)
|
@@ -0,0 +1 @@
|
||||
1
|
@@ -0,0 +1,8 @@
|
||||
CMake Error at TARGET_INTERMEDIATE_DIR\.cmake:[0-9]+ \(file\):
|
||||
Error evaluating generator expression:
|
||||
|
||||
\$\<TARGET_INTERMEDIATE_DIR:foo\>
|
||||
|
||||
The evaluation of the TARGET_INTERMEDIATE_DIR generator expression is only
|
||||
suitable for consumption by CMake \(limited under Xcode with multiple
|
||||
architectures\)\. It is not suitable for writing out elsewhere\.
|
@@ -0,0 +1 @@
|
||||
include(TARGET_INTERMEDIATE_DIR.cmake)
|
@@ -0,0 +1 @@
|
||||
1
|
@@ -0,0 +1,8 @@
|
||||
CMake Error at TARGET_INTERMEDIATE_DIR-bad-arg.cmake:1 \(file\):
|
||||
Error evaluating generator expression:
|
||||
|
||||
\$<TARGET_INTERMEDIATE_DIR>
|
||||
|
||||
\$<TARGET_INTERMEDIATE_DIR> expression requires exactly one parameter.
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)
|
@@ -0,0 +1,2 @@
|
||||
file(GENERATE OUTPUT TARGET_INTERMEDIATE_DIR-no-arg-generated.txt
|
||||
CONTENT "$<TARGET_INTERMEDIATE_DIR>")
|
@@ -0,0 +1 @@
|
||||
1
|
@@ -0,0 +1,8 @@
|
||||
CMake Error at TARGET_INTERMEDIATE_DIR-bad-target.cmake:1 \(file\):
|
||||
Error evaluating generator expression:
|
||||
|
||||
\$<TARGET_INTERMEDIATE_DIR:!>
|
||||
|
||||
Target name not supported.
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)
|
@@ -0,0 +1,2 @@
|
||||
file(GENERATE OUTPUT TARGET_INTERMEDIATE_DIR-no-arg-generated.txt
|
||||
CONTENT "$<TARGET_INTERMEDIATE_DIR:!>")
|
@@ -0,0 +1,46 @@
|
||||
file(READ "${RunCMake_TEST_BINARY_DIR}/TARGET_INTERMEDIATE_DIR-generated.txt" dir)
|
||||
|
||||
# Default Case
|
||||
set(expected "foo\\.dir")
|
||||
|
||||
# Short Object Names
|
||||
if (CMAKE_INTERMEDIATE_DIR_STRATEGY STREQUAL "SHORT")
|
||||
if (RunCMake_GENERATOR MATCHES "Ninja|Make|Visual Studio")
|
||||
set(expected "[\\\\/][._]o[\\\\/][0-9a-f]+")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Xcode
|
||||
if (RunCMake_GENERATOR MATCHES "Xcode")
|
||||
set(expected "foo.build")
|
||||
endif()
|
||||
|
||||
# Append Config subdirectory
|
||||
if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
|
||||
string(APPEND expected "[\\\\/]Release")
|
||||
endif()
|
||||
|
||||
# Xcode has additional paths
|
||||
if (NOT RunCMake_GENERATOR MATCHES "Xcode")
|
||||
string(APPEND expected "$")
|
||||
endif()
|
||||
|
||||
if(NOT dir MATCHES "${expected}")
|
||||
set(RunCMake_TEST_FAILED "actual content:\n [[${dir}]]\nbut expected to match:\n [[${expected}]]")
|
||||
elseif(NOT IS_DIRECTORY "${dir}")
|
||||
set(RunCMake_TEST_FAILED "target intermediate directory does not exist: [[${dir}]]")
|
||||
else()
|
||||
file(GLOB object_files "${dir}/*${CMAKE_C_OUTPUT_EXTENSION}")
|
||||
if (NOT object_files)
|
||||
set(RunCMake_TEST_FAILED "no object files found in intermediate directory: [[${dir}]]")
|
||||
endif()
|
||||
if (CMAKE_INTERMEDIATE_DIR_STRATEGY STREQUAL "FULL")
|
||||
set(object_name "${dir}/simple.c${CMAKE_C_OUTPUT_EXTENSION}")
|
||||
if (RunCMake_GENERATOR MATCHES "Xcode|Visual Studio")
|
||||
set(object_name "${dir}/simple${CMAKE_C_OUTPUT_EXTENSION}")
|
||||
endif()
|
||||
if (NOT EXISTS "${object_name}")
|
||||
set(RunCMake_TEST_FAILED "simple.c object file not found in intermediate directory: [[${dir}]]")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
@@ -0,0 +1 @@
|
||||
1
|
@@ -0,0 +1,8 @@
|
||||
CMake Error at TARGET_INTERMEDIATE_DIR-not-a-target.cmake:1 \(file\):
|
||||
Error evaluating generator expression:
|
||||
|
||||
\$<TARGET_INTERMEDIATE_DIR:bar>
|
||||
|
||||
Target \"bar\" not found.
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)
|
@@ -0,0 +1,2 @@
|
||||
file(GENERATE OUTPUT TARGET_INTERMEDIATE_DIR-not-a-target-generated.txt
|
||||
CONTENT "$<TARGET_INTERMEDIATE_DIR:bar>")
|
@@ -0,0 +1,4 @@
|
||||
enable_language(C)
|
||||
add_executable(foo simple.c)
|
||||
file(GENERATE OUTPUT TARGET_INTERMEDIATE_DIR-generated.txt
|
||||
CONTENT "$<TARGET_INTERMEDIATE_DIR:foo>")
|
4
Tests/RunCMake/GeneratorExpression/simple.c
Normal file
4
Tests/RunCMake/GeneratorExpression/simple.c
Normal file
@@ -0,0 +1,4 @@
|
||||
int main(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
Reference in New Issue
Block a user