add_custom_command: Evaluate generator expressions in DEPENDS

Rely on evaluation in cmCustomCommandGenerator for the generators.

When tracing target dependencies, depend on the union of dependencies
for all configurations.
This commit is contained in:
Stephen Kelly 2014-03-07 17:20:10 +01:00 committed by Brad King
parent fb4aff058d
commit bbffccca42
6 changed files with 66 additions and 9 deletions

View File

@ -156,3 +156,7 @@ target is built before any target using this custom command.
Additionally, if the target is an executable or library a file-level
dependency is created to cause the custom command to re-run whenever
the target is recompiled.
Arguments to ``DEPENDS`` may use "generator expressions" with the syntax
``$<...>``. See the :manual:`cmake-generator-expressions(7)` manual for
available expressions.

View File

@ -0,0 +1,5 @@
add_custom_command-DEPENDS-genex
--------------------------------
* The :command:`add_custom_command` command learned to interpret
:manual:`cmake-generator-expressions(7)` in arguments to ``DEPENDS``.

View File

@ -21,7 +21,7 @@ cmCustomCommandGenerator::cmCustomCommandGenerator(
cmCustomCommand const& cc, const std::string& config, cmMakefile* mf):
CC(cc), Config(config), Makefile(mf), LG(mf->GetLocalGenerator()),
OldStyle(cc.GetEscapeOldStyle()), MakeVars(cc.GetEscapeAllowMakeVars()),
GE(new cmGeneratorExpression(cc.GetBacktrace()))
GE(new cmGeneratorExpression(cc.GetBacktrace())), DependsDone(false)
{
}
@ -93,5 +93,19 @@ std::vector<std::string> const& cmCustomCommandGenerator::GetOutputs() const
//----------------------------------------------------------------------------
std::vector<std::string> const& cmCustomCommandGenerator::GetDepends() const
{
return this->CC.GetDepends();
if (!this->DependsDone)
{
this->DependsDone = true;
std::vector<std::string> depends = this->CC.GetDepends();
for(std::vector<std::string>::const_iterator
i = depends.begin();
i != depends.end(); ++i)
{
cmsys::auto_ptr<cmCompiledGeneratorExpression> cge
= this->GE->Parse(*i);
cmSystemTools::ExpandListArgument(
cge->Evaluate(this->Makefile, this->Config), this->Depends);
}
}
return this->Depends;
}

View File

@ -28,6 +28,8 @@ class cmCustomCommandGenerator
bool OldStyle;
bool MakeVars;
cmGeneratorExpression* GE;
mutable bool DependsDone;
mutable std::vector<std::string> Depends;
public:
cmCustomCommandGenerator(cmCustomCommand const& cc,
const std::string& config,

View File

@ -19,6 +19,7 @@
#include "cmGeneratorExpression.h"
#include "cmGeneratorExpressionDAGChecker.h"
#include "cmComputeLinkInformation.h"
#include "cmCustomCommandGenerator.h"
#include <queue>
@ -610,6 +611,9 @@ private:
bool IsUtility(std::string const& dep);
void CheckCustomCommand(cmCustomCommand const& cc);
void CheckCustomCommands(const std::vector<cmCustomCommand>& commands);
void FollowCommandDepends(cmCustomCommand const& cc,
const std::string& config,
std::set<std::string>& emitted);
};
//----------------------------------------------------------------------------
@ -826,16 +830,41 @@ cmTargetTraceDependencies
}
// Queue the custom command dependencies.
std::vector<std::string> const& depends = cc.GetDepends();
std::vector<std::string> configs;
std::set<std::string> emitted;
this->Makefile->GetConfigurations(configs);
if (configs.empty())
{
configs.push_back("");
}
for(std::vector<std::string>::const_iterator ci = configs.begin();
ci != configs.end(); ++ci)
{
this->FollowCommandDepends(cc, *ci, emitted);
}
}
//----------------------------------------------------------------------------
void cmTargetTraceDependencies::FollowCommandDepends(cmCustomCommand const& cc,
const std::string& config,
std::set<std::string>& emitted)
{
cmCustomCommandGenerator ccg(cc, config, this->Makefile);
const std::vector<std::string>& depends = ccg.GetDepends();
for(std::vector<std::string>::const_iterator di = depends.begin();
di != depends.end(); ++di)
{
std::string const& dep = *di;
if(!this->IsUtility(dep))
if(emitted.insert(dep).second)
{
// The dependency does not name a target and may be a file we
// know how to generate. Queue it.
this->FollowName(dep);
if(!this->IsUtility(dep))
{
// The dependency does not name a target and may be a file we
// know how to generate. Queue it.
this->FollowName(dep);
}
}
}
}

View File

@ -185,7 +185,7 @@ add_executable(CustomCommand
# here to test adding the generation rule after referencing the
# generated source in a target.
add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/generated.c
DEPENDS generator
DEPENDS $<1:generator> $<0:does_not_exist>
COMMAND generator
ARGS ${PROJECT_BINARY_DIR}/generated.c
)
@ -221,8 +221,11 @@ add_subdirectory(GeneratorInExtraDir)
add_executable(tcat tcat.cxx)
# Test that list expansion from a generator expression works.
set_property(TARGET tcat PROPERTY DEPSLIST tcat gen_redirect_in.c)
add_custom_command(OUTPUT gen_redirect.c
DEPENDS tcat gen_redirect_in.c
DEPENDS $<TARGET_PROPERTY:tcat,DEPSLIST>
COMMAND tcat < ${CMAKE_CURRENT_SOURCE_DIR}/gen_redirect_in.c > gen_redirect.c
COMMAND ${CMAKE_COMMAND} -E echo "#endif" >> gen_redirect.c
VERBATIM