mirror of
https://github.com/Kitware/CMake.git
synced 2026-01-01 19:30:13 -06:00
file(GENERATE): Add TARGET argument
Adds TARGET argument to file(GENERATE) to make resolving generator expressions requiring a target possible. Implements #21101, fixes #21074.
This commit is contained in:
@@ -449,7 +449,7 @@ modified.
|
||||
|
||||
file(GENERATE OUTPUT output-file
|
||||
<INPUT input-file|CONTENT content>
|
||||
[CONDITION expression])
|
||||
[CONDITION expression] [TARGET target])
|
||||
|
||||
Generate an output file for each build configuration supported by the current
|
||||
:manual:`CMake Generator <cmake-generators(7)>`. Evaluate
|
||||
@@ -479,6 +479,10 @@ from the input content to produce the output content. The options are:
|
||||
with respect to the value of :variable:`CMAKE_CURRENT_BINARY_DIR`.
|
||||
See policy :policy:`CMP0070`.
|
||||
|
||||
``TARGET <target>``
|
||||
Specify target which to use when evaluating generator expressions. Enables
|
||||
use of generator expressions requiring a target.
|
||||
|
||||
Exactly one ``CONTENT`` or ``INPUT`` option must be given. A specific
|
||||
``OUTPUT`` file may be named by at most one invocation of ``file(GENERATE)``.
|
||||
Generated files are modified and their timestamp updated on subsequent cmake
|
||||
|
||||
5
Help/release/dev/file-generate-target.rst
Normal file
5
Help/release/dev/file-generate-target.rst
Normal file
@@ -0,0 +1,5 @@
|
||||
file-generate-target
|
||||
--------------------
|
||||
|
||||
* The :command:`file(GENERATE)` command gained a new ``TARGET`` keyword to
|
||||
support resolving target-dependent generator expressions.
|
||||
@@ -2240,6 +2240,7 @@ bool HandleUploadCommand(std::vector<std::string> const& args,
|
||||
}
|
||||
|
||||
void AddEvaluationFile(const std::string& inputName,
|
||||
const std::string& targetName,
|
||||
const std::string& outputExpr,
|
||||
const std::string& condition, bool inputIsContent,
|
||||
cmExecutionStatus& status)
|
||||
@@ -2255,7 +2256,8 @@ void AddEvaluationFile(const std::string& inputName,
|
||||
conditionGe.Parse(condition);
|
||||
|
||||
status.GetMakefile().AddEvaluationFile(
|
||||
inputName, std::move(outputCge), std::move(conditionCge), inputIsContent);
|
||||
inputName, targetName, std::move(outputCge), std::move(conditionCge),
|
||||
inputIsContent);
|
||||
}
|
||||
|
||||
bool HandleGenerateCommand(std::vector<std::string> const& args,
|
||||
@@ -2269,23 +2271,36 @@ bool HandleGenerateCommand(std::vector<std::string> const& args,
|
||||
status.SetError("Incorrect arguments to GENERATE subcommand.");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string condition;
|
||||
if (args.size() > 5) {
|
||||
if (args[5] != "CONDITION") {
|
||||
std::string target;
|
||||
|
||||
for (std::size_t i = 5; i < args.size();) {
|
||||
const std::string& arg = args[i++];
|
||||
|
||||
if (args.size() - i == 0) {
|
||||
status.SetError("Incorrect arguments to GENERATE subcommand.");
|
||||
return false;
|
||||
}
|
||||
if (args.size() != 7) {
|
||||
status.SetError("Incorrect arguments to GENERATE subcommand.");
|
||||
|
||||
const std::string& value = args[i++];
|
||||
|
||||
if (value.empty()) {
|
||||
status.SetError(
|
||||
arg + " of sub-command GENERATE must not be empty if specified.");
|
||||
return false;
|
||||
}
|
||||
condition = args[6];
|
||||
if (condition.empty()) {
|
||||
status.SetError("CONDITION of sub-command GENERATE must not be empty if "
|
||||
"specified.");
|
||||
|
||||
if (arg == "CONDITION") {
|
||||
condition = value;
|
||||
} else if (arg == "TARGET") {
|
||||
target = value;
|
||||
} else {
|
||||
status.SetError("Unknown argument to GENERATE subcommand.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::string output = args[2];
|
||||
const bool inputIsContent = args[3] != "INPUT";
|
||||
if (inputIsContent && args[3] != "CONTENT") {
|
||||
@@ -2294,7 +2309,7 @@ bool HandleGenerateCommand(std::vector<std::string> const& args,
|
||||
}
|
||||
std::string input = args[4];
|
||||
|
||||
AddEvaluationFile(input, output, condition, inputIsContent, status);
|
||||
AddEvaluationFile(input, target, output, condition, inputIsContent, status);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,11 +19,12 @@
|
||||
#include "cmSystemTools.h"
|
||||
|
||||
cmGeneratorExpressionEvaluationFile::cmGeneratorExpressionEvaluationFile(
|
||||
std::string input,
|
||||
std::string input, std::string target,
|
||||
std::unique_ptr<cmCompiledGeneratorExpression> outputFileExpr,
|
||||
std::unique_ptr<cmCompiledGeneratorExpression> condition,
|
||||
bool inputIsContent, cmPolicies::PolicyStatus policyStatusCMP0070)
|
||||
: Input(std::move(input))
|
||||
, Target(std::move(target))
|
||||
, OutputFileExpr(std::move(outputFileExpr))
|
||||
, Condition(std::move(condition))
|
||||
, InputIsContent(inputIsContent)
|
||||
@@ -37,9 +38,10 @@ void cmGeneratorExpressionEvaluationFile::Generate(
|
||||
std::map<std::string, std::string>& outputFiles, mode_t perm)
|
||||
{
|
||||
std::string rawCondition = this->Condition->GetInput();
|
||||
cmGeneratorTarget* target = lg->FindGeneratorTargetToUse(Target);
|
||||
if (!rawCondition.empty()) {
|
||||
std::string condResult =
|
||||
this->Condition->Evaluate(lg, config, nullptr, nullptr, nullptr, lang);
|
||||
this->Condition->Evaluate(lg, config, target, nullptr, nullptr, lang);
|
||||
if (condResult == "0") {
|
||||
return;
|
||||
}
|
||||
@@ -54,9 +56,10 @@ void cmGeneratorExpressionEvaluationFile::Generate(
|
||||
}
|
||||
}
|
||||
|
||||
const std::string outputFileName = this->GetOutputFileName(lg, config, lang);
|
||||
const std::string outputFileName =
|
||||
this->GetOutputFileName(lg, target, config, lang);
|
||||
const std::string& outputContent =
|
||||
inputExpression->Evaluate(lg, config, nullptr, nullptr, nullptr, lang);
|
||||
inputExpression->Evaluate(lg, config, target, nullptr, nullptr, lang);
|
||||
|
||||
auto it = outputFiles.find(outputFileName);
|
||||
|
||||
@@ -91,10 +94,11 @@ void cmGeneratorExpressionEvaluationFile::CreateOutputFile(
|
||||
{
|
||||
std::vector<std::string> enabledLanguages;
|
||||
cmGlobalGenerator* gg = lg->GetGlobalGenerator();
|
||||
cmGeneratorTarget* target = lg->FindGeneratorTargetToUse(Target);
|
||||
gg->GetEnabledLanguages(enabledLanguages);
|
||||
|
||||
for (std::string const& le : enabledLanguages) {
|
||||
std::string const name = this->GetOutputFileName(lg, config, le);
|
||||
std::string const name = this->GetOutputFileName(lg, target, config, le);
|
||||
cmSourceFile* sf = lg->GetMakefile()->GetOrCreateSource(
|
||||
name, false, cmSourceFileLocationKind::Known);
|
||||
// Tell TraceDependencies that the file is not expected to exist
|
||||
@@ -176,10 +180,11 @@ std::string cmGeneratorExpressionEvaluationFile::GetInputFileName(
|
||||
}
|
||||
|
||||
std::string cmGeneratorExpressionEvaluationFile::GetOutputFileName(
|
||||
cmLocalGenerator* lg, const std::string& config, const std::string& lang)
|
||||
cmLocalGenerator* lg, cmGeneratorTarget* target, const std::string& config,
|
||||
const std::string& lang)
|
||||
{
|
||||
std::string outputFileName = this->OutputFileExpr->Evaluate(
|
||||
lg, config, nullptr, nullptr, nullptr, lang);
|
||||
std::string outputFileName =
|
||||
this->OutputFileExpr->Evaluate(lg, config, target, nullptr, nullptr, lang);
|
||||
|
||||
if (cmSystemTools::FileIsFullPath(outputFileName)) {
|
||||
outputFileName = cmSystemTools::CollapseFullPath(outputFileName);
|
||||
|
||||
@@ -15,13 +15,14 @@
|
||||
#include "cmGeneratorExpression.h"
|
||||
#include "cmPolicies.h"
|
||||
|
||||
class cmGeneratorTarget;
|
||||
class cmLocalGenerator;
|
||||
|
||||
class cmGeneratorExpressionEvaluationFile
|
||||
{
|
||||
public:
|
||||
cmGeneratorExpressionEvaluationFile(
|
||||
std::string input,
|
||||
std::string input, std::string target,
|
||||
std::unique_ptr<cmCompiledGeneratorExpression> outputFileExpr,
|
||||
std::unique_ptr<cmCompiledGeneratorExpression> condition,
|
||||
bool inputIsContent, cmPolicies::PolicyStatus policyStatusCMP0070);
|
||||
@@ -40,6 +41,7 @@ private:
|
||||
|
||||
std::string GetInputFileName(cmLocalGenerator* lg);
|
||||
std::string GetOutputFileName(cmLocalGenerator* lg,
|
||||
cmGeneratorTarget* target,
|
||||
const std::string& config,
|
||||
const std::string& lang);
|
||||
enum PathRole
|
||||
@@ -52,6 +54,7 @@ private:
|
||||
|
||||
private:
|
||||
const std::string Input;
|
||||
const std::string Target;
|
||||
const std::unique_ptr<cmCompiledGeneratorExpression> OutputFileExpr;
|
||||
const std::unique_ptr<cmCompiledGeneratorExpression> Condition;
|
||||
std::vector<std::string> Files;
|
||||
|
||||
@@ -801,15 +801,15 @@ void cmMakefile::EnforceDirectoryLevelRules() const
|
||||
}
|
||||
|
||||
void cmMakefile::AddEvaluationFile(
|
||||
const std::string& inputFile,
|
||||
const std::string& inputFile, const std::string& targetName,
|
||||
std::unique_ptr<cmCompiledGeneratorExpression> outputName,
|
||||
std::unique_ptr<cmCompiledGeneratorExpression> condition,
|
||||
bool inputIsContent)
|
||||
{
|
||||
this->EvaluationFiles.push_back(
|
||||
cm::make_unique<cmGeneratorExpressionEvaluationFile>(
|
||||
inputFile, std::move(outputName), std::move(condition), inputIsContent,
|
||||
this->GetPolicyStatus(cmPolicies::CMP0070)));
|
||||
inputFile, targetName, std::move(outputName), std::move(condition),
|
||||
inputIsContent, this->GetPolicyStatus(cmPolicies::CMP0070)));
|
||||
}
|
||||
|
||||
const std::vector<std::unique_ptr<cmGeneratorExpressionEvaluationFile>>&
|
||||
|
||||
@@ -949,7 +949,7 @@ public:
|
||||
void EnforceDirectoryLevelRules() const;
|
||||
|
||||
void AddEvaluationFile(
|
||||
const std::string& inputFile,
|
||||
const std::string& inputFile, const std::string& targetName,
|
||||
std::unique_ptr<cmCompiledGeneratorExpression> outputName,
|
||||
std::unique_ptr<cmCompiledGeneratorExpression> condition,
|
||||
bool inputIsContent);
|
||||
|
||||
@@ -33,6 +33,13 @@ foreach(l CXX C)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
run_cmake(Target)
|
||||
file(READ "${RunCMake_BINARY_DIR}/Target-build/sub1/output.txt" sub_1)
|
||||
file(READ "${RunCMake_BINARY_DIR}/Target-build/sub2/output.txt" sub_2)
|
||||
if(NOT sub_1 MATCHES "first" OR NOT sub_2 MATCHES "second")
|
||||
message(SEND_ERROR "Wrong target used by TARGET argument! ${sub_1} ${sub_2}")
|
||||
endif()
|
||||
|
||||
set(timeformat "%Y%j%H%M%S")
|
||||
|
||||
file(REMOVE "${RunCMake_BINARY_DIR}/WriteIfDifferent-build/output_file.txt")
|
||||
|
||||
2
Tests/RunCMake/File_Generate/Target.cmake
Normal file
2
Tests/RunCMake/File_Generate/Target.cmake
Normal file
@@ -0,0 +1,2 @@
|
||||
add_subdirectory(sub1)
|
||||
add_subdirectory(sub2)
|
||||
7
Tests/RunCMake/File_Generate/sub1/CMakeLists.txt
Normal file
7
Tests/RunCMake/File_Generate/sub1/CMakeLists.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
add_library(library IMPORTED STATIC)
|
||||
set_property(TARGET library PROPERTY COMPILE_DEFINITIONS "first")
|
||||
|
||||
file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/output.txt"
|
||||
CONTENT "$<TARGET_PROPERTY:COMPILE_DEFINITIONS>"
|
||||
TARGET library
|
||||
)
|
||||
7
Tests/RunCMake/File_Generate/sub2/CMakeLists.txt
Normal file
7
Tests/RunCMake/File_Generate/sub2/CMakeLists.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
add_library(library IMPORTED STATIC)
|
||||
set_property(TARGET library PROPERTY COMPILE_DEFINITIONS "second")
|
||||
|
||||
file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/output.txt"
|
||||
CONTENT "$<TARGET_PROPERTY:COMPILE_DEFINITIONS>"
|
||||
TARGET library
|
||||
)
|
||||
Reference in New Issue
Block a user