diff --git a/Help/command/add_custom_command.rst b/Help/command/add_custom_command.rst index 569f1e853b3709a5c536bb8d78f262adf6e9bc5d..a053e59f79268d90d154aa25f7d0a5abc27fdae8 100644 --- a/Help/command/add_custom_command.rst +++ b/Help/command/add_custom_command.rst @@ -338,6 +338,8 @@ will re-run whenever ``in.txt`` changes. where ``<config>`` is the build configuration, and then compile the generated source as part of a library. +.. _`add_custom_command(TARGET)`: + Build Events ^^^^^^^^^^^^ @@ -388,6 +390,9 @@ of the following is specified: This allows to add individual build events for every configuration. +.. versionadded:: 3.21 + Support for target-dependent generator expressions. + Examples: Build Events ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/Help/release/dev/add_custom_command-TARGET-genex.rst b/Help/release/dev/add_custom_command-TARGET-genex.rst new file mode 100644 index 0000000000000000000000000000000000000000..86f8b36be56cfbbf110775712fa8d3ab094bb126 --- /dev/null +++ b/Help/release/dev/add_custom_command-TARGET-genex.rst @@ -0,0 +1,5 @@ +add_custom_command-TARGET-genex +------------------------------- + +* The :ref:`add_custom_command(TARGET) <add_custom_command(TARGET)>` command + gained support for resolving target-dependent generator expressions. diff --git a/Source/cmCustomCommand.cxx b/Source/cmCustomCommand.cxx index f6b99898485da54b96a73f4b86a71f74891830f1..ec60ff7559ed96559a253c1145c9bf4226786538 100644 --- a/Source/cmCustomCommand.cxx +++ b/Source/cmCustomCommand.cxx @@ -150,3 +150,13 @@ void cmCustomCommand::SetCMP0116Status(cmPolicies::PolicyStatus cmp0116) { this->CMP0116Status = cmp0116; } + +const std::string& cmCustomCommand::GetTarget() const +{ + return this->Target; +} + +void cmCustomCommand::SetTarget(const std::string& target) +{ + this->Target = target; +} diff --git a/Source/cmCustomCommand.h b/Source/cmCustomCommand.h index e22c7a4064c8e426267b744e0a6b6b669ca0c36c..5cbd3d17a9e1273514753190381df01c2b0e29c4 100644 --- a/Source/cmCustomCommand.h +++ b/Source/cmCustomCommand.h @@ -100,6 +100,10 @@ public: cmPolicies::PolicyStatus GetCMP0116Status() const; void SetCMP0116Status(cmPolicies::PolicyStatus cmp0116); + /** Set/Get the associated target */ + const std::string& GetTarget() const; + void SetTarget(const std::string& target); + private: std::vector<std::string> Outputs; std::vector<std::string> Byproducts; @@ -107,6 +111,7 @@ private: cmCustomCommandLines CommandLines; cmListFileBacktrace Backtrace; cmImplicitDependsList ImplicitDepends; + std::string Target; std::string Comment; std::string WorkingDirectory; std::string Depfile; diff --git a/Source/cmCustomCommandGenerator.cxx b/Source/cmCustomCommandGenerator.cxx index 1054beb375f769df13e3c488edf35a0243299446..77779ba781070ddb972181bb2faf21659a9046cc 100644 --- a/Source/cmCustomCommandGenerator.cxx +++ b/Source/cmCustomCommandGenerator.cxx @@ -29,7 +29,7 @@ namespace { std::string EvaluateSplitConfigGenex( cm::string_view input, cmGeneratorExpression const& ge, cmLocalGenerator* lg, bool useOutputConfig, std::string const& outputConfig, - std::string const& commandConfig, + std::string const& commandConfig, cmGeneratorTarget const* target, std::set<BT<std::pair<std::string, bool>>>* utils = nullptr) { std::string result; @@ -87,7 +87,7 @@ std::string EvaluateSplitConfigGenex( // Evaluate this genex in the selected configuration. std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(std::string(genex)); - result += cge->Evaluate(lg, *config); + result += cge->Evaluate(lg, *config, target); // Record targets referenced by the genex. if (utils) { @@ -114,7 +114,8 @@ std::vector<std::string> EvaluateDepends(std::vector<std::string> const& paths, std::string const& ep = EvaluateSplitConfigGenex(p, ge, lg, /*useOutputConfig=*/true, /*outputConfig=*/outputConfig, - /*commandConfig=*/commandConfig); + /*commandConfig=*/commandConfig, + /*target=*/nullptr); cm::append(depends, cmExpandedList(ep)); } for (std::string& p : depends) { @@ -157,6 +158,7 @@ cmCustomCommandGenerator::cmCustomCommandGenerator( : CC(&cc) , OutputConfig(crossConfig ? *crossConfig : config) , CommandConfig(std::move(config)) + , Target(cc.GetTarget()) , LG(lg) , OldStyle(cc.GetEscapeOldStyle()) , MakeVars(cc.GetEscapeAllowMakeVars()) @@ -171,6 +173,8 @@ cmCustomCommandGenerator::cmCustomCommandGenerator( } cmGeneratorExpression ge(cc.GetBacktrace()); + cmGeneratorTarget const* target{ lg->FindGeneratorTargetToUse( + this->Target) }; const cmCustomCommandLines& cmdlines = this->CC->GetCommandLines(); for (cmCustomCommandLine const& cmdline : cmdlines) { @@ -180,7 +184,7 @@ cmCustomCommandGenerator::cmCustomCommandGenerator( for (std::string const& clarg : cmdline) { std::string parsed_arg = EvaluateSplitConfigGenex( clarg, ge, this->LG, useOutputConfig, this->OutputConfig, - this->CommandConfig, &this->Utilities); + this->CommandConfig, target, &this->Utilities); if (this->CC->GetCommandExpandLists()) { cm::append(argv, cmExpandedList(parsed_arg)); } else { @@ -249,9 +253,9 @@ cmCustomCommandGenerator::cmCustomCommandGenerator( const std::string& workingdirectory = this->CC->GetWorkingDirectory(); if (!workingdirectory.empty()) { - this->WorkingDirectory = - EvaluateSplitConfigGenex(workingdirectory, ge, this->LG, true, - this->OutputConfig, this->CommandConfig); + this->WorkingDirectory = EvaluateSplitConfigGenex( + workingdirectory, ge, this->LG, true, this->OutputConfig, + this->CommandConfig, target); // Convert working directory to a full path. if (!this->WorkingDirectory.empty()) { std::string const& build_dir = this->LG->GetCurrentBinaryDirectory(); diff --git a/Source/cmCustomCommandGenerator.h b/Source/cmCustomCommandGenerator.h index e70909a74a0f7190db37797794df480ee3f84eba..73a8d387deadde59b8cf5b4c3ed33f9856d88451 100644 --- a/Source/cmCustomCommandGenerator.h +++ b/Source/cmCustomCommandGenerator.h @@ -25,6 +25,7 @@ class cmCustomCommandGenerator cmCustomCommand const* CC; std::string OutputConfig; std::string CommandConfig; + std::string Target; cmLocalGenerator* LG; bool OldStyle; bool MakeVars; diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 0c686aa2963f55d4be76d737ded8d08c3e58c68b..6a49b84a797ff9cecf852b520a83fd1945abb82b 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -4096,6 +4096,7 @@ void AddCustomCommandToTarget(cmLocalGenerator& lg, cc.SetDepfile(depfile); cc.SetJobPool(job_pool); cc.SetCMP0116Status(cmp0116); + cc.SetTarget(target->GetName()); switch (type) { case cmCustomCommandType::PRE_BUILD: target->AddPreBuildCommand(std::move(cc)); diff --git a/Tests/RunCMake/add_custom_command/RunCMakeTest.cmake b/Tests/RunCMake/add_custom_command/RunCMakeTest.cmake index 9c59b4b75e538b11c7625bd4618f044752d22cc6..ad6b2586c55d0d55773693861828a0c1ff28a318 100644 --- a/Tests/RunCMake/add_custom_command/RunCMakeTest.cmake +++ b/Tests/RunCMake/add_custom_command/RunCMakeTest.cmake @@ -43,3 +43,20 @@ if(NOT RunCMake_GENERATOR STREQUAL "Ninja Multi-Config") unset(RunCMake_TEST_BINARY_DIR) unset(RunCMake_TEST_NO_CLEAN) endif() + +function(test_genex name) + run_cmake(${name}) + + set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/${name}-build") + set(RunCMake_TEST_NO_CLEAN 1) + run_cmake_command(${name}-build ${CMAKE_COMMAND} --build .) + + if(NOT EXISTS "${RunCMake_TEST_BINARY_DIR}/wdir/touched") + message(SEND_ERROR "File not created by target-dependent add_custom_command()!") + endif() + + unset(RunCMake_TEST_NO_CLEAN) + unset(RunCMake_TEST_BINARY_DIR) +endfunction() + +test_genex(TargetGenexEvent) diff --git a/Tests/RunCMake/add_custom_command/TargetGenexEvent.cmake b/Tests/RunCMake/add_custom_command/TargetGenexEvent.cmake new file mode 100644 index 0000000000000000000000000000000000000000..8591b74fce6b787bfd1382d56e11bfef6ee6d8d9 --- /dev/null +++ b/Tests/RunCMake/add_custom_command/TargetGenexEvent.cmake @@ -0,0 +1,10 @@ +add_custom_target(target ALL) +set_target_properties(target PROPERTIES COMPILE_DEFINITIONS "touched" COMPILE_OPTIONS "${CMAKE_BINARY_DIR}/wdir") +file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/wdir") + +add_custom_command( + TARGET target + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E touch $<TARGET_PROPERTY:COMPILE_DEFINITIONS> + WORKING_DIRECTORY $<TARGET_PROPERTY:COMPILE_OPTIONS> +)