1
0
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 expression
5c5634db52 cmGeneratorExpressionNode: Factor out HasKnownObjectFileLocation check

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !11217
This commit is contained in:
Brad King
2025-10-09 13:12:12 +00:00
committed by Kitware Robot
22 changed files with 232 additions and 16 deletions

View File

@@ -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
------------------------------

View 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.

View File

@@ -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,20 +3372,9 @@ 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());
if (!HasKnownObjectFileLocation(eval, content, "TARGET_OBJECTS", gt)) {
return std::string();
}
}
cmList objects;
@@ -4809,6 +4888,7 @@ cmGeneratorExpressionNode const* cmGeneratorExpressionNode::GetNode(
{ "SEMICOLON", &semicolonNode },
{ "QUOTE", &quoteNode },
{ "TARGET_PROPERTY", &targetPropertyNode },
{ "TARGET_INTERMEDIATE_DIR", &targetIntermediateDirNode },
{ "TARGET_NAME", &targetNameNode },
{ "TARGET_OBJECTS", &targetObjectsNode },
{ "TARGET_POLICY", &targetPolicyNode },

View File

@@ -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)

View File

@@ -56,7 +56,10 @@ function(run_cmake_build test)
list(APPEND RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Release)
endif()
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)

View File

@@ -0,0 +1 @@
include(TARGET_INTERMEDIATE_DIR.cmake)

View File

@@ -0,0 +1 @@
include(TARGET_INTERMEDIATE_DIR.cmake)

View File

@@ -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\.

View File

@@ -0,0 +1 @@
include(TARGET_INTERMEDIATE_DIR.cmake)

View File

@@ -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\)

View File

@@ -0,0 +1,2 @@
file(GENERATE OUTPUT TARGET_INTERMEDIATE_DIR-no-arg-generated.txt
CONTENT "$<TARGET_INTERMEDIATE_DIR>")

View File

@@ -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\)

View File

@@ -0,0 +1,2 @@
file(GENERATE OUTPUT TARGET_INTERMEDIATE_DIR-no-arg-generated.txt
CONTENT "$<TARGET_INTERMEDIATE_DIR:!>")

View File

@@ -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()

View File

@@ -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\)

View File

@@ -0,0 +1,2 @@
file(GENERATE OUTPUT TARGET_INTERMEDIATE_DIR-not-a-target-generated.txt
CONTENT "$<TARGET_INTERMEDIATE_DIR:bar>")

View File

@@ -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>")

View File

@@ -0,0 +1,4 @@
int main(void)
{
return 0;
}