Merge topic 'ninja_phony_targets'
539356f
Ninja: Custom Command file depends don't need to exist before building874e171
Ninja: GlobalNinjaGenerator WriteBuild and WritePhonyBuild non static88d27ad
Add a test to expose a bug with add_custom_command and ninja.
This commit is contained in:
commit
62428f5e72
|
@ -10,11 +10,12 @@
|
|||
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the License for more information.
|
||||
============================================================================*/
|
||||
#include "cmGeneratedFileStream.h"
|
||||
#include "cmGeneratorExpressionEvaluationFile.h"
|
||||
#include "cmGeneratorTarget.h"
|
||||
#include "cmGlobalNinjaGenerator.h"
|
||||
#include "cmLocalNinjaGenerator.h"
|
||||
#include "cmMakefile.h"
|
||||
#include "cmGeneratedFileStream.h"
|
||||
#include "cmGeneratorTarget.h"
|
||||
#include "cmVersion.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
@ -140,8 +141,15 @@ void cmGlobalNinjaGenerator::WriteBuild(std::ostream& os,
|
|||
for(cmNinjaDeps::const_iterator i = explicitDeps.begin();
|
||||
i != explicitDeps.end();
|
||||
++i)
|
||||
{
|
||||
arguments << " " << EncodeIdent(EncodePath(*i), os);
|
||||
|
||||
//we need to track every dependency that comes in, since we are trying
|
||||
//to find dependencies that are side effects of build commands
|
||||
//
|
||||
this->CombinedBuildExplicitDependencies.insert(*i);
|
||||
}
|
||||
|
||||
// Write implicit dependencies.
|
||||
if(!implicitDeps.empty())
|
||||
{
|
||||
|
@ -170,7 +178,10 @@ void cmGlobalNinjaGenerator::WriteBuild(std::ostream& os,
|
|||
build << "build";
|
||||
for(cmNinjaDeps::const_iterator i = outputs.begin();
|
||||
i != outputs.end(); ++i)
|
||||
{
|
||||
build << " " << EncodeIdent(EncodePath(*i), os);
|
||||
this->CombinedBuildOutputs.insert(*i);
|
||||
}
|
||||
build << ":";
|
||||
|
||||
// Write the rule.
|
||||
|
@ -208,7 +219,7 @@ void cmGlobalNinjaGenerator::WritePhonyBuild(std::ostream& os,
|
|||
const cmNinjaDeps& orderOnlyDeps,
|
||||
const cmNinjaVars& variables)
|
||||
{
|
||||
cmGlobalNinjaGenerator::WriteBuild(os,
|
||||
this->WriteBuild(os,
|
||||
comment,
|
||||
"phony",
|
||||
outputs,
|
||||
|
@ -251,7 +262,7 @@ cmGlobalNinjaGenerator::WriteCustomCommandBuild(const std::string& command,
|
|||
vars["COMMAND"] = cmd;
|
||||
vars["DESC"] = EncodeLiteral(description);
|
||||
|
||||
cmGlobalNinjaGenerator::WriteBuild(*this->BuildFileStream,
|
||||
this->WriteBuild(*this->BuildFileStream,
|
||||
comment,
|
||||
"CUSTOM_COMMAND",
|
||||
outputs,
|
||||
|
@ -293,7 +304,7 @@ cmGlobalNinjaGenerator::WriteMacOSXContentBuild(const std::string& input,
|
|||
deps.push_back(input);
|
||||
cmNinjaVars vars;
|
||||
|
||||
cmGlobalNinjaGenerator::WriteBuild(*this->BuildFileStream,
|
||||
this->WriteBuild(*this->BuildFileStream,
|
||||
"",
|
||||
"COPY_OSX_CONTENT",
|
||||
outputs,
|
||||
|
@ -478,6 +489,7 @@ void cmGlobalNinjaGenerator::Generate()
|
|||
|
||||
this->WriteAssumedSourceDependencies();
|
||||
this->WriteTargetAliases(*this->BuildFileStream);
|
||||
this->WriteUnknownExplicitDependencies(*this->BuildFileStream);
|
||||
this->WriteBuiltinTargets(*this->BuildFileStream);
|
||||
|
||||
if (cmSystemTools::GetErrorOccuredFlag()) {
|
||||
|
@ -887,7 +899,7 @@ void cmGlobalNinjaGenerator::WriteTargetAliases(std::ostream& os)
|
|||
cmGlobalNinjaGenerator::WriteDivider(os);
|
||||
os << "# Target aliases.\n\n";
|
||||
|
||||
for (TargetAliasMap::iterator i = TargetAliases.begin();
|
||||
for (TargetAliasMap::const_iterator i = TargetAliases.begin();
|
||||
i != TargetAliases.end(); ++i) {
|
||||
// Don't write ambiguous aliases.
|
||||
if (!i->second)
|
||||
|
@ -896,13 +908,124 @@ void cmGlobalNinjaGenerator::WriteTargetAliases(std::ostream& os)
|
|||
cmNinjaDeps deps;
|
||||
this->AppendTargetOutputs(i->second, deps);
|
||||
|
||||
cmGlobalNinjaGenerator::WritePhonyBuild(os,
|
||||
this->WritePhonyBuild(os,
|
||||
"",
|
||||
cmNinjaDeps(1, i->first),
|
||||
deps);
|
||||
}
|
||||
}
|
||||
|
||||
void cmGlobalNinjaGenerator::WriteUnknownExplicitDependencies(std::ostream& os)
|
||||
{
|
||||
//now write out the unknown explicit dependencies.
|
||||
|
||||
//union the configured files, evaluations files and the CombinedBuildOutputs,
|
||||
//and then difference with CombinedExplicitDependencies to find the explicit
|
||||
//dependencies that we have no rule for
|
||||
|
||||
cmGlobalNinjaGenerator::WriteDivider(os);
|
||||
os << "# Unknown Build Time Dependencies.\n"
|
||||
<< "# Tell Ninja that they may appear as side effects of build rules\n"
|
||||
<< "# otherwise ordered by order-only dependencies.\n\n";
|
||||
|
||||
//get the list of files that cmake itself has generated as a
|
||||
//product of configuration.
|
||||
cmLocalNinjaGenerator *ng =
|
||||
static_cast<cmLocalNinjaGenerator *>(this->LocalGenerators[0]);
|
||||
|
||||
std::set<std::string> knownDependencies;
|
||||
for (std::vector<cmLocalGenerator *>::const_iterator i =
|
||||
this->LocalGenerators.begin(); i != this->LocalGenerators.end(); ++i)
|
||||
{
|
||||
//get the vector of files created by this makefile and convert them
|
||||
//to ninja paths, which are all relative in respect to the build directory
|
||||
const std::vector<std::string>& files =
|
||||
(*i)->GetMakefile()->GetOutputFiles();
|
||||
typedef std::vector<std::string>::const_iterator vect_it;
|
||||
for(vect_it j = files.begin(); j != files.end(); ++j)
|
||||
{
|
||||
knownDependencies.insert(ng->ConvertToNinjaPath( j->c_str() ));
|
||||
}
|
||||
}
|
||||
|
||||
for(std::vector<cmGeneratorExpressionEvaluationFile*>::const_iterator
|
||||
li = this->EvaluationFiles.begin();
|
||||
li != this->EvaluationFiles.end();
|
||||
++li)
|
||||
{
|
||||
//get all the files created by generator expressions and convert them
|
||||
//to ninja paths
|
||||
std::vector<std::string> files = (*li)->GetFiles();
|
||||
typedef std::vector<std::string>::const_iterator vect_it;
|
||||
for(vect_it j = files.begin(); j != files.end(); ++j)
|
||||
{
|
||||
knownDependencies.insert(ng->ConvertToNinjaPath( j->c_str() ));
|
||||
}
|
||||
}
|
||||
|
||||
//insert outputs from all WirteBuild commands
|
||||
for(std::set<std::string>::iterator i = this->CombinedBuildOutputs.begin();
|
||||
i != this->CombinedBuildOutputs.end(); ++i)
|
||||
{
|
||||
knownDependencies.insert(*i);
|
||||
}
|
||||
|
||||
//after we have combined the data into knownDependencies we have no need
|
||||
//to keep this data around
|
||||
this->CombinedBuildOutputs.clear();
|
||||
|
||||
for(TargetAliasMap::const_iterator i= this->TargetAliases.begin();
|
||||
i != this->TargetAliases.end();
|
||||
++i)
|
||||
{
|
||||
knownDependencies.insert(i->first);
|
||||
}
|
||||
|
||||
//remove all source files we know will exist.
|
||||
typedef std::map<std::string, std::set<std::string> >::const_iterator map_it;
|
||||
for(map_it i = this->AssumedSourceDependencies.begin();
|
||||
i != this->AssumedSourceDependencies.end();
|
||||
++i)
|
||||
{
|
||||
knownDependencies.insert(i->first);
|
||||
}
|
||||
|
||||
//now we difference with CombinedBuildExplicitDependencies to find
|
||||
//the list of items we know nothing about
|
||||
|
||||
std::vector<std::string> unkownExplicitDepends;
|
||||
this->CombinedBuildExplicitDependencies.erase("all");
|
||||
|
||||
std::set_difference(this->CombinedBuildExplicitDependencies.begin(),
|
||||
this->CombinedBuildExplicitDependencies.end(),
|
||||
knownDependencies.begin(),
|
||||
knownDependencies.end(),
|
||||
std::back_inserter(unkownExplicitDepends));
|
||||
|
||||
|
||||
std::string const rootBuildDirectory =
|
||||
this->GetCMakeInstance()->GetHomeOutputDirectory();
|
||||
for (std::vector<std::string>::const_iterator
|
||||
i = unkownExplicitDepends.begin();
|
||||
i != unkownExplicitDepends.end();
|
||||
++i)
|
||||
{
|
||||
//verify the file is in the build directory
|
||||
std::string const absDepPath = cmSystemTools::CollapseFullPath(
|
||||
i->c_str(), rootBuildDirectory.c_str());
|
||||
bool const inBuildDir = cmSystemTools::IsSubDirectory(absDepPath.c_str(),
|
||||
rootBuildDirectory.c_str());
|
||||
if(inBuildDir)
|
||||
{
|
||||
cmNinjaDeps deps(1,*i);
|
||||
this->WritePhonyBuild(os,
|
||||
"",
|
||||
deps,
|
||||
deps);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cmGlobalNinjaGenerator::WriteBuiltinTargets(std::ostream& os)
|
||||
{
|
||||
// Write headers.
|
||||
|
@ -920,7 +1043,7 @@ void cmGlobalNinjaGenerator::WriteTargetAll(std::ostream& os)
|
|||
cmNinjaDeps outputs;
|
||||
outputs.push_back("all");
|
||||
|
||||
cmGlobalNinjaGenerator::WritePhonyBuild(os,
|
||||
this->WritePhonyBuild(os,
|
||||
"The main all target.",
|
||||
outputs,
|
||||
this->AllDependencies);
|
||||
|
@ -970,7 +1093,7 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os)
|
|||
implicitDeps.end());
|
||||
implicitDeps.push_back("CMakeCache.txt");
|
||||
|
||||
WriteBuild(os,
|
||||
this->WriteBuild(os,
|
||||
"Re-run CMake if any of its inputs changed.",
|
||||
"RERUN_CMAKE",
|
||||
/*outputs=*/ cmNinjaDeps(1, NINJA_BUILD_FILE),
|
||||
|
@ -979,7 +1102,7 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os)
|
|||
/*orderOnlyDeps=*/ cmNinjaDeps(),
|
||||
/*variables=*/ cmNinjaVars());
|
||||
|
||||
WritePhonyBuild(os,
|
||||
this->WritePhonyBuild(os,
|
||||
"A missing CMake input file is not an error.",
|
||||
implicitDeps,
|
||||
cmNinjaDeps());
|
||||
|
|
|
@ -77,7 +77,7 @@ public:
|
|||
* It also writes the variables bound to this build statement.
|
||||
* @warning no escaping of any kind is done here.
|
||||
*/
|
||||
static void WriteBuild(std::ostream& os,
|
||||
void WriteBuild(std::ostream& os,
|
||||
const std::string& comment,
|
||||
const std::string& rule,
|
||||
const cmNinjaDeps& outputs,
|
||||
|
@ -91,7 +91,7 @@ public:
|
|||
/**
|
||||
* Helper to write a build statement with the special 'phony' rule.
|
||||
*/
|
||||
static void WritePhonyBuild(std::ostream& os,
|
||||
void WritePhonyBuild(std::ostream& os,
|
||||
const std::string& comment,
|
||||
const cmNinjaDeps& outputs,
|
||||
const cmNinjaDeps& explicitDeps,
|
||||
|
@ -321,6 +321,7 @@ private:
|
|||
void WriteAssumedSourceDependencies();
|
||||
|
||||
void WriteTargetAliases(std::ostream& os);
|
||||
void WriteUnknownExplicitDependencies(std::ostream& os);
|
||||
|
||||
void WriteBuiltinTargets(std::ostream& os);
|
||||
void WriteTargetAll(std::ostream& os);
|
||||
|
@ -358,6 +359,12 @@ private:
|
|||
/// The set of custom command outputs we have seen.
|
||||
std::set<std::string> CustomCommandOutputs;
|
||||
|
||||
//The combined explicit dependencies of all build commands that the global
|
||||
//generator has issued. When combined with CombinedBuildOutputs it allows
|
||||
//us to detect the set of explicit dependencies that have
|
||||
std::set<std::string> CombinedBuildExplicitDependencies;
|
||||
std::set<std::string> CombinedBuildOutputs;
|
||||
|
||||
/// The mapping from source file to assumed dependencies.
|
||||
std::map<std::string, std::set<std::string> > AssumedSourceDependencies;
|
||||
|
||||
|
|
|
@ -340,7 +340,8 @@ cmLocalNinjaGenerator::WriteCustomCommandBuildStatement(
|
|||
this->AppendCustomCommandLines(cc, cmdLines);
|
||||
|
||||
if (cmdLines.empty()) {
|
||||
cmGlobalNinjaGenerator::WritePhonyBuild(this->GetBuildFileStream(),
|
||||
this->GetGlobalNinjaGenerator()->WritePhonyBuild(
|
||||
this->GetBuildFileStream(),
|
||||
"Phony custom command for " +
|
||||
ninjaOutputs[0],
|
||||
ninjaOutputs,
|
||||
|
|
|
@ -598,12 +598,17 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
|
|||
#endif
|
||||
}
|
||||
|
||||
//Get the global generator as we are going to be call WriteBuild numerous
|
||||
//times in the following section
|
||||
cmGlobalNinjaGenerator* globalGenerator = this->GetGlobalGenerator();
|
||||
|
||||
|
||||
const std::string rspfile = std::string
|
||||
(cmake::GetCMakeFilesDirectoryPostSlash()) +
|
||||
this->GetTarget()->GetName() + ".rsp";
|
||||
|
||||
// Write the build statement for this target.
|
||||
cmGlobalNinjaGenerator::WriteBuild(this->GetBuildFileStream(),
|
||||
globalGenerator->WriteBuild(this->GetBuildFileStream(),
|
||||
comment.str(),
|
||||
this->LanguageLinkerRule(),
|
||||
outputs,
|
||||
|
@ -616,7 +621,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
|
|||
|
||||
if (targetOutput != targetOutputReal) {
|
||||
if (targetType == cmTarget::EXECUTABLE) {
|
||||
cmGlobalNinjaGenerator::WriteBuild(this->GetBuildFileStream(),
|
||||
globalGenerator->WriteBuild(this->GetBuildFileStream(),
|
||||
"Create executable symlink " + targetOutput,
|
||||
"CMAKE_SYMLINK_EXECUTABLE",
|
||||
cmNinjaDeps(1, targetOutput),
|
||||
|
@ -635,7 +640,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
|
|||
symlinks.push_back(soName);
|
||||
}
|
||||
symlinks.push_back(targetOutput);
|
||||
cmGlobalNinjaGenerator::WriteBuild(this->GetBuildFileStream(),
|
||||
globalGenerator->WriteBuild(this->GetBuildFileStream(),
|
||||
"Create library symlink " + targetOutput,
|
||||
"CMAKE_SYMLINK_LIBRARY",
|
||||
symlinks,
|
||||
|
@ -649,16 +654,16 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
|
|||
if (!this->TargetNameImport.empty()) {
|
||||
// Since using multiple outputs would mess up the $out variable, use an
|
||||
// alias for the import library.
|
||||
cmGlobalNinjaGenerator::WritePhonyBuild(this->GetBuildFileStream(),
|
||||
globalGenerator->WritePhonyBuild(this->GetBuildFileStream(),
|
||||
"Alias for import library.",
|
||||
cmNinjaDeps(1, targetOutputImplib),
|
||||
cmNinjaDeps(1, targetOutputReal));
|
||||
}
|
||||
|
||||
// Add aliases for the file name and the target name.
|
||||
this->GetGlobalGenerator()->AddTargetAlias(this->TargetNameOut,
|
||||
globalGenerator->AddTargetAlias(this->TargetNameOut,
|
||||
this->GetTarget());
|
||||
this->GetGlobalGenerator()->AddTargetAlias(this->GetTargetName(),
|
||||
globalGenerator->AddTargetAlias(this->GetTargetName(),
|
||||
this->GetTarget());
|
||||
}
|
||||
|
||||
|
@ -669,7 +674,7 @@ void cmNinjaNormalTargetGenerator::WriteObjectLibStatement()
|
|||
cmNinjaDeps outputs;
|
||||
this->GetLocalGenerator()->AppendTargetOutputs(this->GetTarget(), outputs);
|
||||
cmNinjaDeps depends = this->GetObjects();
|
||||
cmGlobalNinjaGenerator::WritePhonyBuild(this->GetBuildFileStream(),
|
||||
this->GetGlobalGenerator()->WritePhonyBuild(this->GetBuildFileStream(),
|
||||
"Object library "
|
||||
+ this->GetTargetName(),
|
||||
outputs,
|
||||
|
|
|
@ -612,7 +612,7 @@ cmNinjaTargetGenerator
|
|||
sourceFileName);
|
||||
}
|
||||
|
||||
cmGlobalNinjaGenerator::WriteBuild(this->GetBuildFileStream(),
|
||||
this->GetGlobalGenerator()->WriteBuild(this->GetBuildFileStream(),
|
||||
comment,
|
||||
rule,
|
||||
outputs,
|
||||
|
@ -626,7 +626,7 @@ cmNinjaTargetGenerator
|
|||
cmSystemTools::ExpandListArgument(objectOutputs, outputList);
|
||||
std::transform(outputList.begin(), outputList.end(), outputList.begin(),
|
||||
MapToNinjaPath());
|
||||
cmGlobalNinjaGenerator::WritePhonyBuild(this->GetBuildFileStream(),
|
||||
this->GetGlobalGenerator()->WritePhonyBuild(this->GetBuildFileStream(),
|
||||
"Additional output files.",
|
||||
outputList,
|
||||
outputs);
|
||||
|
|
|
@ -61,7 +61,7 @@ void cmNinjaUtilityTargetGenerator::Generate()
|
|||
this->GetLocalGenerator()->AppendTargetDepends(this->GetTarget(), deps);
|
||||
|
||||
if (commands.empty()) {
|
||||
cmGlobalNinjaGenerator::WritePhonyBuild(this->GetBuildFileStream(),
|
||||
this->GetGlobalGenerator()->WritePhonyBuild(this->GetBuildFileStream(),
|
||||
"Utility command for "
|
||||
+ this->GetTargetName(),
|
||||
outputs,
|
||||
|
@ -105,10 +105,11 @@ void cmNinjaUtilityTargetGenerator::Generate()
|
|||
cmNinjaDeps(1, utilCommandName),
|
||||
deps);
|
||||
|
||||
cmGlobalNinjaGenerator::WritePhonyBuild(this->GetBuildFileStream(),
|
||||
this->GetGlobalGenerator()->WritePhonyBuild(this->GetBuildFileStream(),
|
||||
"",
|
||||
outputs,
|
||||
cmNinjaDeps(1, utilCommandName));
|
||||
cmNinjaDeps(1, utilCommandName)
|
||||
);
|
||||
}
|
||||
|
||||
this->GetGlobalGenerator()->AddTargetAlias(this->GetTargetName(),
|
||||
|
|
|
@ -123,6 +123,19 @@ add_custom_command(
|
|||
COMMENT "Running TDocument post-build commands"
|
||||
)
|
||||
|
||||
# Setup a custom target that will fail if the POST_BUILD custom command
|
||||
# isn't run before it.
|
||||
add_custom_command(
|
||||
OUTPUT doc3post.txt
|
||||
DEPENDS ${PROJECT_BINARY_DIR}/doc2post.txt
|
||||
COMMAND ${CMAKE_COMMAND} -E echo " Copying doc2pre.txt to doc3post.txt."
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_BINARY_DIR}/doc2post.txt
|
||||
${PROJECT_BINARY_DIR}/doc3post.txt
|
||||
COMMENT "Running TDocument post-build dependent custom command"
|
||||
)
|
||||
add_custom_target(doc3Post ALL DEPENDS doc3post.txt)
|
||||
add_dependencies(doc3Post TDocument)
|
||||
|
||||
################################################################
|
||||
#
|
||||
# Test using a multistep generated file
|
||||
|
|
Loading…
Reference in New Issue