Commit 3f4b81f5 authored by Shane Parris's avatar Shane Parris

Add glob verify support to XCode, VS, Ninja, and Makefile generators

parent ca0befc2
......@@ -475,6 +475,7 @@ cmGlobalNinjaGenerator::cmGlobalNinjaGenerator(cmake* cm)
, PolicyCMP0058(cmPolicies::WARN)
, NinjaSupportsConsolePool(false)
, NinjaSupportsImplicitOuts(false)
, NinjaSupportsManifestRestat(false)
, NinjaSupportsDyndeps(0)
{
#ifdef _WIN32
......@@ -597,6 +598,9 @@ void cmGlobalNinjaGenerator::CheckNinjaFeatures()
this->NinjaSupportsImplicitOuts = !cmSystemTools::VersionCompare(
cmSystemTools::OP_LESS, this->NinjaVersion.c_str(),
this->RequiredNinjaVersionForImplicitOuts().c_str());
this->NinjaSupportsManifestRestat = !cmSystemTools::VersionCompare(
cmSystemTools::OP_LESS, this->NinjaVersion.c_str(),
RequiredNinjaVersionForManifestRestat().c_str());
{
// Our ninja branch adds ".dyndep-#" to its version number,
// where '#' is a feature-specific version number. Extract it.
......@@ -1361,6 +1365,7 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os)
/*generator=*/true);
cmNinjaDeps implicitDeps;
cmNinjaDeps explicitDeps;
for (cmLocalGenerator* localGen : this->LocalGenerators) {
std::vector<std::string> const& lf =
localGen->GetMakefile()->GetListFiles();
......@@ -1370,10 +1375,6 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os)
}
implicitDeps.push_back(this->CMakeCacheFile);
std::sort(implicitDeps.begin(), implicitDeps.end());
implicitDeps.erase(std::unique(implicitDeps.begin(), implicitDeps.end()),
implicitDeps.end());
cmNinjaVars variables;
// Use 'console' pool to get non buffered output of the CMake re-run call
// Available since Ninja 1.5
......@@ -1381,12 +1382,71 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os)
variables["pool"] = "console";
}
cmake* cm = this->GetCMakeInstance();
if (this->SupportsManifestRestat() && cm->DoWriteGlobVerifyTarget()) {
std::ostringstream verify_cmd;
verify_cmd << lg->ConvertToOutputFormat(cmSystemTools::GetCMakeCommand(),
cmOutputConverter::SHELL)
<< " -P "
<< lg->ConvertToOutputFormat(cm->GetGlobVerifyScript(),
cmOutputConverter::SHELL);
WriteRule(*this->RulesFileStream, "VERIFY_GLOBS", verify_cmd.str(),
"Re-checking globbed directories...",
"Rule for re-checking globbed directories.",
/*depfile=*/"",
/*deptype=*/"",
/*rspfile=*/"",
/*rspcontent*/ "",
/*restat=*/"",
/*generator=*/true);
std::string verifyForce = cm->GetGlobVerifyScript() + "_force";
cmNinjaDeps verifyForceDeps(1, this->NinjaOutputPath(verifyForce));
this->WritePhonyBuild(os, "Phony target to force glob verification run.",
verifyForceDeps, cmNinjaDeps());
variables["restat"] = "1";
std::string const verifyScriptFile =
this->NinjaOutputPath(cm->GetGlobVerifyScript());
std::string const verifyStampFile =
this->NinjaOutputPath(cm->GetGlobVerifyStamp());
this->WriteBuild(os,
"Re-run CMake to check if globbed directories changed.",
"VERIFY_GLOBS",
/*outputs=*/cmNinjaDeps(1, verifyStampFile),
/*implicitOuts=*/cmNinjaDeps(),
/*explicitDeps=*/cmNinjaDeps(),
/*implicitDeps=*/verifyForceDeps,
/*orderOnlyDeps=*/cmNinjaDeps(), variables);
variables.erase("restat");
implicitDeps.push_back(verifyScriptFile);
explicitDeps.push_back(verifyStampFile);
} else if (!this->SupportsManifestRestat() &&
cm->DoWriteGlobVerifyTarget()) {
std::ostringstream msg;
msg << "The detected version of Ninja:\n"
<< " " << this->NinjaVersion << "\n"
<< "is less than the version of Ninja required by CMake for adding "
"restat dependencies to the build.ninja manifest regeneration "
"target:\n"
<< " " << this->RequiredNinjaVersionForManifestRestat() << "\n";
msg << "Any pre-check scripts, such as those generated for file(GLOB "
"CONFIGURE_DEPENDS), will not be run by Ninja.";
this->GetCMakeInstance()->IssueMessage(cmake::AUTHOR_WARNING, msg.str());
}
std::sort(implicitDeps.begin(), implicitDeps.end());
implicitDeps.erase(std::unique(implicitDeps.begin(), implicitDeps.end()),
implicitDeps.end());
std::string const ninjaBuildFile = this->NinjaOutputPath(NINJA_BUILD_FILE);
this->WriteBuild(os, "Re-run CMake if any of its inputs changed.",
"RERUN_CMAKE",
/*outputs=*/cmNinjaDeps(1, ninjaBuildFile),
/*implicitOuts=*/cmNinjaDeps(),
/*explicitDeps=*/cmNinjaDeps(), implicitDeps,
/*implicitOuts=*/cmNinjaDeps(), explicitDeps, implicitDeps,
/*orderOnlyDeps=*/cmNinjaDeps(), variables);
cmNinjaDeps missingInputs;
......@@ -1419,6 +1479,11 @@ bool cmGlobalNinjaGenerator::SupportsImplicitOuts() const
return this->NinjaSupportsImplicitOuts;
}
bool cmGlobalNinjaGenerator::SupportsManifestRestat() const
{
return this->NinjaSupportsManifestRestat;
}
void cmGlobalNinjaGenerator::WriteTargetClean(std::ostream& os)
{
WriteRule(*this->RulesFileStream, "CLEAN", ninjaCmd() + " -t clean",
......
......@@ -346,8 +346,10 @@ public:
static std::string RequiredNinjaVersion() { return "1.3"; }
static std::string RequiredNinjaVersionForConsolePool() { return "1.5"; }
static std::string RequiredNinjaVersionForImplicitOuts() { return "1.7"; }
static std::string RequiredNinjaVersionForManifestRestat() { return "1.8"; }
bool SupportsConsolePool() const;
bool SupportsImplicitOuts() const;
bool SupportsManifestRestat() const;
std::string NinjaOutputPath(std::string const& path) const;
bool HasOutputPathPrefix() const { return !this->OutputPathPrefix.empty(); }
......@@ -460,6 +462,7 @@ private:
std::string NinjaVersion;
bool NinjaSupportsConsolePool;
bool NinjaSupportsImplicitOuts;
bool NinjaSupportsManifestRestat;
unsigned long NinjaSupportsDyndeps;
private:
......
......@@ -301,6 +301,13 @@ void cmGlobalUnixMakefileGenerator3::WriteMainCMakefile()
lfiles.insert(lfiles.end(), lg->GetMakefile()->GetListFiles().begin(),
lg->GetMakefile()->GetListFiles().end());
}
cmake* cm = this->GetCMakeInstance();
if (cm->DoWriteGlobVerifyTarget()) {
lfiles.push_back(cm->GetGlobVerifyScript());
lfiles.push_back(cm->GetGlobVerifyStamp());
}
// Sort the list and remove duplicates.
std::sort(lfiles.begin(), lfiles.end(), std::less<std::string>());
#if !defined(__VMS) // The Compaq STL on VMS crashes, so accept duplicates.
......
......@@ -209,18 +209,18 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget()
{
// Add a special target on which all other targets depend that
// checks the build system and optionally re-runs CMake.
const char* no_working_directory = 0;
// Skip the target if no regeneration is to be done.
if (this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION")) {
return false;
}
const char* no_working_directory = nullptr;
std::vector<std::string> no_depends;
std::vector<cmLocalGenerator*> const& generators = this->LocalGenerators;
cmLocalVisualStudio7Generator* lg =
static_cast<cmLocalVisualStudio7Generator*>(generators[0]);
cmMakefile* mf = lg->GetMakefile();
// Skip the target if no regeneration is to be done.
if (this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION")) {
return false;
}
cmCustomCommandLines noCommandLines;
cmTarget* tgt = mf->AddUtilityCommand(
CMAKE_CHECK_BUILD_SYSTEM_TARGET, cmMakefile::TargetOrigin::Generator,
......@@ -266,6 +266,30 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget()
listFiles.insert(listFiles.end(), lmf->GetListFiles().begin(),
lmf->GetListFiles().end());
}
// Add a custom prebuild target to run the VerifyGlobs script.
cmake* cm = this->GetCMakeInstance();
if (cm->DoWriteGlobVerifyTarget()) {
cmCustomCommandLine verifyCommandLine;
verifyCommandLine.push_back(cmSystemTools::GetCMakeCommand());
verifyCommandLine.push_back("-P");
verifyCommandLine.push_back(cm->GetGlobVerifyScript());
cmCustomCommandLines verifyCommandLines;
verifyCommandLines.push_back(verifyCommandLine);
std::vector<std::string> byproducts;
byproducts.push_back(cm->GetGlobVerifyStamp());
mf->AddCustomCommandToTarget(CMAKE_CHECK_BUILD_SYSTEM_TARGET, byproducts,
no_depends, verifyCommandLines,
cmTarget::PRE_BUILD, "Checking File Globs",
no_working_directory, false);
// Ensure ZERO_CHECK always runs in Visual Studio using MSBuild,
// otherwise the prebuild command will not be run.
tgt->SetProperty("VS_GLOBAL_DisableFastUpToDateCheck", "true");
listFiles.push_back(cm->GetGlobVerifyStamp());
}
// Sort the list of input files and remove duplicates.
std::sort(listFiles.begin(), listFiles.end(), std::less<std::string>());
std::vector<std::string>::iterator new_end =
......@@ -273,8 +297,6 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget()
listFiles.erase(new_end, listFiles.end());
// Create a rule to re-run CMake.
std::string stampName = cmake::GetCMakeFilesDirectoryPostSlash();
stampName += "generate.stamp";
cmCustomCommandLine commandLine;
commandLine.push_back(cmSystemTools::GetCMakeCommand());
std::string argH = "-H";
......
......@@ -537,6 +537,12 @@ void cmGlobalXCodeGenerator::CreateReRunCMakeFile(
std::vector<std::string>::iterator new_end =
std::unique(lfiles.begin(), lfiles.end());
lfiles.erase(new_end, lfiles.end());
cmake* cm = this->GetCMakeInstance();
if (cm->DoWriteGlobVerifyTarget()) {
lfiles.emplace_back(cm->GetGlobVerifyStamp());
}
this->CurrentReRunCMakeMakefile = root->GetCurrentBinaryDirectory();
this->CurrentReRunCMakeMakefile += "/CMakeScripts";
cmSystemTools::MakeDirectory(this->CurrentReRunCMakeMakefile.c_str());
......@@ -555,14 +561,28 @@ void cmGlobalXCodeGenerator::CreateReRunCMakeFile(
makefileStream << "TARGETS += $(subst $(space),$(spaceplus),$(wildcard "
<< this->ConvertToRelativeForMake(lfile) << "))\n";
}
makefileStream << "\n";
std::string checkCache = root->GetBinaryDirectory();
checkCache += "/";
checkCache += cmake::GetCMakeFilesDirectoryPostSlash();
checkCache += "cmake.check_cache";
makefileStream << "\n"
<< this->ConvertToRelativeForMake(checkCache)
if (cm->DoWriteGlobVerifyTarget()) {
makefileStream << ".NOTPARALLEL:\n\n";
makefileStream << ".PHONY: all VERIFY_GLOBS\n\n";
makefileStream << "all: VERIFY_GLOBS "
<< this->ConvertToRelativeForMake(checkCache) << "\n\n";
makefileStream << "VERIFY_GLOBS:\n";
makefileStream << "\t"
<< this->ConvertToRelativeForMake(
cmSystemTools::GetCMakeCommand())
<< " -P "
<< this->ConvertToRelativeForMake(cm->GetGlobVerifyScript())
<< "\n\n";
}
makefileStream << this->ConvertToRelativeForMake(checkCache)
<< ": $(TARGETS)\n";
makefileStream << "\t"
<< this->ConvertToRelativeForMake(
......
......@@ -197,6 +197,16 @@ void cmLocalNinjaGenerator::WriteNinjaRequiredVersion(std::ostream& os)
this->GetGlobalNinjaGenerator()->RequiredNinjaVersionForConsolePool();
}
// The Ninja generator writes rules which require support for restat
// when rebuilding build.ninja manifest (>= 1.8)
if (this->GetGlobalNinjaGenerator()->SupportsManifestRestat() &&
this->GetCMakeInstance()->DoWriteGlobVerifyTarget() &&
!this->GetGlobalNinjaGenerator()->GlobalSettingIsOn(
"CMAKE_SUPPRESS_REGENERATION")) {
requiredVersion =
this->GetGlobalNinjaGenerator()->RequiredNinjaVersionForManifestRestat();
}
cmGlobalNinjaGenerator::WriteComment(
os, "Minimal version of Ninja required by this file");
os << "ninja_required_version = " << requiredVersion << std::endl
......
......@@ -763,6 +763,14 @@ void cmLocalUnixMakefileGenerator3::WriteSpecialTargetsBottom(
if (!this->GlobalGenerator->GlobalSettingIsOn(
"CMAKE_SUPPRESS_REGENERATION")) {
// Build command to run CMake to check if anything needs regenerating.
std::vector<std::string> commands;
cmake* cm = this->GlobalGenerator->GetCMakeInstance();
if (cm->DoWriteGlobVerifyTarget()) {
std::string rescanRule = "$(CMAKE_COMMAND) -P ";
rescanRule += this->ConvertToOutputFormat(cm->GetGlobVerifyScript(),
cmOutputConverter::SHELL);
commands.push_back(rescanRule);
}
std::string cmakefileName = cmake::GetCMakeFilesDirectoryPostSlash();
cmakefileName += "Makefile.cmake";
std::string runRule =
......@@ -773,7 +781,6 @@ void cmLocalUnixMakefileGenerator3::WriteSpecialTargetsBottom(
runRule += " 0";
std::vector<std::string> no_depends;
std::vector<std::string> commands;
commands.push_back(std::move(runRule));
if (!this->IsRootMakefile()) {
this->CreateCDCommand(commands, this->GetBinaryDirectory(),
......@@ -1666,6 +1673,13 @@ void cmLocalUnixMakefileGenerator3::WriteLocalAllRules(
// write the depend rule, really a recompute depends rule
depends.clear();
commands.clear();
cmake* cm = this->GlobalGenerator->GetCMakeInstance();
if (cm->DoWriteGlobVerifyTarget()) {
std::string rescanRule = "$(CMAKE_COMMAND) -P ";
rescanRule += this->ConvertToOutputFormat(cm->GetGlobVerifyScript(),
cmOutputConverter::SHELL);
commands.push_back(rescanRule);
}
std::string cmakefileName = cmake::GetCMakeFilesDirectoryPostSlash();
cmakefileName += "Makefile.cmake";
{
......
......@@ -160,10 +160,21 @@ void cmLocalVisualStudio7Generator::WriteStampFiles()
depName += ".depend";
cmsys::ofstream depFile(depName.c_str());
depFile << "# CMake generation dependency list for this directory.\n";
std::vector<std::string> const& listFiles = this->Makefile->GetListFiles();
for (std::vector<std::string>::const_iterator lf = listFiles.begin();
lf != listFiles.end(); ++lf) {
depFile << *lf << std::endl;
std::vector<std::string> listFiles(this->Makefile->GetListFiles());
cmake* cm = this->GlobalGenerator->GetCMakeInstance();
if (cm->DoWriteGlobVerifyTarget()) {
listFiles.push_back(cm->GetGlobVerifyStamp());
}
// Sort the list of input files and remove duplicates.
std::sort(listFiles.begin(), listFiles.end(), std::less<std::string>());
std::vector<std::string>::iterator new_end =
std::unique(listFiles.begin(), listFiles.end());
listFiles.erase(new_end, listFiles.end());
for (const std::string& lf : listFiles) {
depFile << lf << "\n";
}
}
......@@ -228,6 +239,18 @@ cmSourceFile* cmLocalVisualStudio7Generator::CreateVCProjBuildRule()
return nullptr;
}
std::vector<std::string> listFiles = this->Makefile->GetListFiles();
cmake* cm = this->GlobalGenerator->GetCMakeInstance();
if (cm->DoWriteGlobVerifyTarget()) {
listFiles.push_back(cm->GetGlobVerifyStamp());
}
// Sort the list of input files and remove duplicates.
std::sort(listFiles.begin(), listFiles.end(), std::less<std::string>());
std::vector<std::string>::iterator new_end =
std::unique(listFiles.begin(), listFiles.end());
listFiles.erase(new_end, listFiles.end());
std::string stampName = this->GetCurrentBinaryDirectory();
stampName += "/";
stampName += cmake::GetCMakeFilesDirectoryPostSlash();
......@@ -245,17 +268,14 @@ cmSourceFile* cmLocalVisualStudio7Generator::CreateVCProjBuildRule()
commandLine.push_back(args);
commandLine.push_back("--check-stamp-file");
commandLine.push_back(stampName);
std::vector<std::string> const& listFiles = this->Makefile->GetListFiles();
cmCustomCommandLines commandLines;
commandLines.push_back(commandLine);
const char* no_working_directory = 0;
std::string fullpathStampName =
cmSystemTools::CollapseFullPath(stampName.c_str());
this->Makefile->AddCustomCommandToOutput(
fullpathStampName.c_str(), listFiles, makefileIn.c_str(), commandLines,
comment.c_str(), no_working_directory, true, false);
fullpathStampName, listFiles, makefileIn, commandLines, comment.c_str(),
no_working_directory, true, false);
if (cmSourceFile* file = this->Makefile->GetSource(makefileIn.c_str())) {
// Finalize the source file path now since we're adding this after
// the generator validated all project-named sources.
......
......@@ -2465,37 +2465,49 @@ int cmake::Build(const std::string& dir, const std::string& target,
cmGlobalVisualStudio8Generator::GetGenerateStampList();
// Note that the stampList file only exists for VS generators.
if (cmSystemTools::FileExists(stampList) &&
!cmakeCheckStampList(stampList.c_str(), false)) {
// Correctly initialize the home (=source) and home output (=binary)
// directories, which is required for running the generation step.
std::string homeOrig = this->GetHomeDirectory();
std::string homeOutputOrig = this->GetHomeOutputDirectory();
this->SetDirectoriesFromFile(cachePath.c_str());
if (cmSystemTools::FileExists(stampList)) {
// Check if running for Visual Studio 9 - we need to explicitly run
// the glob verification script before starting the build
this->AddScriptingCommands();
this->AddProjectCommands();
if (this->GlobalGenerator->MatchesGeneratorName("Visual Studio 9 2008")) {
std::string const globVerifyScript = cachePath + "/" +
GetCMakeFilesDirectoryPostSlash() + "VerifyGlobs.cmake";
if (cmSystemTools::FileExists(globVerifyScript)) {
std::vector<std::string> args;
this->ReadListFile(args, globVerifyScript.c_str());
}
}
int ret = this->Configure();
if (ret) {
cmSystemTools::Message("CMake Configure step failed. "
"Build files cannot be regenerated correctly.");
return ret;
}
ret = this->Generate();
if (ret) {
cmSystemTools::Message("CMake Generate step failed. "
"Build files cannot be regenerated correctly.");
return ret;
}
std::string message = "Build files have been written to: ";
message += this->GetHomeOutputDirectory();
this->UpdateProgress(message.c_str(), -1);
// Restore the previously set directories to their original value.
this->SetHomeDirectory(homeOrig);
this->SetHomeOutputDirectory(homeOutputOrig);
if (!cmakeCheckStampList(stampList.c_str(), false)) {
// Correctly initialize the home (=source) and home output (=binary)
// directories, which is required for running the generation step.
std::string homeOrig = this->GetHomeDirectory();
std::string homeOutputOrig = this->GetHomeOutputDirectory();
this->SetDirectoriesFromFile(cachePath.c_str());
this->AddProjectCommands();
int ret = this->Configure();
if (ret) {
cmSystemTools::Message("CMake Configure step failed. "
"Build files cannot be regenerated correctly.");
return ret;
}
ret = this->Generate();
if (ret) {
cmSystemTools::Message("CMake Generate step failed. "
"Build files cannot be regenerated correctly.");
return ret;
}
std::string message = "Build files have been written to: ";
message += this->GetHomeOutputDirectory();
this->UpdateProgress(message.c_str(), -1);
// Restore the previously set directories to their original value.
this->SetHomeDirectory(homeOrig);
this->SetHomeOutputDirectory(homeOutputOrig);
}
}
#endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment