From f9b758e91a9afa17123c5b81b5568ebbd52db598 Mon Sep 17 00:00:00 2001 From: Brad King Date: Wed, 18 Apr 2012 14:42:43 -0400 Subject: [PATCH 1/3] Cleanup custom command .rule file internal handling Teach cmMakefile::AddCustomCommandToOutput to return the cmSourceFile instance to which the custom command is attached. Use the return value instead of separately adding a .rule extension and searching for the source. Mark CMake-generated .rule files explicitly with a property instead of trusting the file extension. --- Source/cmGlobalVisualStudio8Generator.cxx | 12 +++----- Source/cmLocalVisualStudio6Generator.cxx | 2 +- Source/cmMakefile.cxx | 36 +++++++++++----------- Source/cmMakefile.h | 30 +++++++++--------- Source/cmVisualStudio10TargetGenerator.cxx | 2 +- 5 files changed, 41 insertions(+), 41 deletions(-) diff --git a/Source/cmGlobalVisualStudio8Generator.cxx b/Source/cmGlobalVisualStudio8Generator.cxx index a723109786..ac70a9bdfc 100644 --- a/Source/cmGlobalVisualStudio8Generator.cxx +++ b/Source/cmGlobalVisualStudio8Generator.cxx @@ -214,13 +214,11 @@ void cmGlobalVisualStudio8Generator::AddCheckTarget() // (this could be avoided with per-target source files) const char* no_main_dependency = 0; const char* no_working_directory = 0; - mf->AddCustomCommandToOutput( - stamps, listFiles, - no_main_dependency, commandLines, "Checking Build System", - no_working_directory, true); - std::string ruleName = stamps[0]; - ruleName += ".rule"; - if(cmSourceFile* file = mf->GetSource(ruleName.c_str())) + if(cmSourceFile* file = + mf->AddCustomCommandToOutput( + stamps, listFiles, + no_main_dependency, commandLines, "Checking Build System", + no_working_directory, true)) { tgt->AddSourceFile(file); } diff --git a/Source/cmLocalVisualStudio6Generator.cxx b/Source/cmLocalVisualStudio6Generator.cxx index 99a4c95fc2..5ab223b7e7 100644 --- a/Source/cmLocalVisualStudio6Generator.cxx +++ b/Source/cmLocalVisualStudio6Generator.cxx @@ -320,7 +320,7 @@ void cmLocalVisualStudio6Generator::WriteDSPFile(std::ostream& fout, sourceGroup.AssignSource(*i); // while we are at it, if it is a .rule file then for visual studio 6 we // must generate it - if ((*i)->GetExtension() == "rule") + if ((*i)->GetPropertyAsBool("__CMAKE_RULE")) { if(!cmSystemTools::FileExists(source.c_str())) { diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index e7e5edaa39..f2865f6ccd 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -883,7 +883,7 @@ cmMakefile::AddCustomCommandToTarget(const char* target, } //---------------------------------------------------------------------------- -void +cmSourceFile* cmMakefile::AddCustomCommandToOutput(const std::vector& outputs, const std::vector& depends, const char* main_dependency, @@ -897,7 +897,7 @@ cmMakefile::AddCustomCommandToOutput(const std::vector& outputs, if(outputs.empty()) { cmSystemTools::Error("Attempt to add a custom rule with no output!"); - return; + return 0; } // Validate custom commands. TODO: More strict? @@ -910,7 +910,7 @@ cmMakefile::AddCustomCommandToOutput(const std::vector& outputs, cmOStringStream e; e << "COMMAND may not contain literal quotes:\n " << cl[0] << "\n"; this->IssueMessage(cmake::FATAL_ERROR, e.str()); - return; + return 0; } } @@ -928,7 +928,7 @@ cmMakefile::AddCustomCommandToOutput(const std::vector& outputs, { // The existing custom command is identical. Silently ignore // the duplicate. - return; + return file; } else { @@ -970,11 +970,12 @@ cmMakefile::AddCustomCommandToOutput(const std::vector& outputs, outName.c_str(), "\" which already has a custom rule."); } - return; + return file; } // Create a cmSourceFile for the rule file. file = this->GetOrCreateSource(outName.c_str(), true); + file->SetProperty("__CMAKE_RULE", "1"); } // Always create the output sources and mark them generated. @@ -1004,10 +1005,11 @@ cmMakefile::AddCustomCommandToOutput(const std::vector& outputs, cc->SetEscapeAllowMakeVars(true); file->SetCustomCommand(cc); } + return file; } //---------------------------------------------------------------------------- -void +cmSourceFile* cmMakefile::AddCustomCommandToOutput(const char* output, const std::vector& depends, const char* main_dependency, @@ -1019,9 +1021,9 @@ cmMakefile::AddCustomCommandToOutput(const char* output, { std::vector outputs; outputs.push_back(output); - this->AddCustomCommandToOutput(outputs, depends, main_dependency, - commandLines, comment, workingDir, - replace, escapeOldStyle); + return this->AddCustomCommandToOutput(outputs, depends, main_dependency, + commandLines, comment, workingDir, + replace, escapeOldStyle); } //---------------------------------------------------------------------------- @@ -1054,13 +1056,14 @@ cmMakefile::AddCustomCommandOldStyle(const char* target, { // Get the name of this output. const char* output = oi->c_str(); + cmSourceFile* sf; // Choose whether to use a main dependency. if(sourceFiles.find(source)) { // The source looks like a real file. Use it as the main dependency. - this->AddCustomCommandToOutput(output, depends, source, - commandLines, comment, 0); + sf = this->AddCustomCommandToOutput(output, depends, source, + commandLines, comment, 0); } else { @@ -1068,20 +1071,18 @@ cmMakefile::AddCustomCommandOldStyle(const char* target, const char* no_main_dependency = 0; std::vector depends2 = depends; depends2.push_back(source); - this->AddCustomCommandToOutput(output, depends2, no_main_dependency, - commandLines, comment, 0); + sf = this->AddCustomCommandToOutput(output, depends2, no_main_dependency, + commandLines, comment, 0); } // If the rule was added to the source (and not a .rule file), // then add the source to the target to make sure the rule is // included. - std::string sname = output; - sname += ".rule"; - if(!this->GetSource(sname.c_str())) + if(sf && !sf->GetPropertyAsBool("__CMAKE_RULE")) { if (this->Targets.find(target) != this->Targets.end()) { - this->Targets[target].AddSource(source); + this->Targets[target].AddSourceFile(sf); } else { @@ -1976,7 +1977,6 @@ cmSourceFile *cmMakefile::GetSourceFileWithOutput(const char *cname) // look through all the source files that have custom commands // and see if the custom command has the passed source file as an output - // keep in mind the possible .rule extension that may be tacked on for(std::vector::const_iterator i = this->SourceFiles.begin(); i != this->SourceFiles.end(); ++i) { diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index 960ba39db8..8b3bef701f 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -175,20 +175,22 @@ public: cmTarget::CustomCommandType type, const char* comment, const char* workingDir, bool escapeOldStyle = true); - void AddCustomCommandToOutput(const std::vector& outputs, - const std::vector& depends, - const char* main_dependency, - const cmCustomCommandLines& commandLines, - const char* comment, const char* workingDir, - bool replace = false, - bool escapeOldStyle = true); - void AddCustomCommandToOutput(const char* output, - const std::vector& depends, - const char* main_dependency, - const cmCustomCommandLines& commandLines, - const char* comment, const char* workingDir, - bool replace = false, - bool escapeOldStyle = true); + cmSourceFile* AddCustomCommandToOutput( + const std::vector& outputs, + const std::vector& depends, + const char* main_dependency, + const cmCustomCommandLines& commandLines, + const char* comment, const char* workingDir, + bool replace = false, + bool escapeOldStyle = true); + cmSourceFile* AddCustomCommandToOutput( + const char* output, + const std::vector& depends, + const char* main_dependency, + const cmCustomCommandLines& commandLines, + const char* comment, const char* workingDir, + bool replace = false, + bool escapeOldStyle = true); void AddCustomCommandOldStyle(const char* target, const std::vector& outputs, const std::vector& depends, diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 6caaad1bcc..592153059a 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -460,7 +460,7 @@ cmVisualStudio10TargetGenerator::WriteCustomRule(cmSourceFile* source, { std::string sourcePath = source->GetFullPath(); // the rule file seems to need to exist for vs10 - if (source->GetExtension() == "rule") + if (source->GetPropertyAsBool("__CMAKE_RULE")) { if(!cmSystemTools::FileExists(sourcePath.c_str())) { From 369e3464beb8258ce5b2af8bcbe6b476fca379de Mon Sep 17 00:00:00 2001 From: Brad King Date: Wed, 18 Apr 2012 15:28:12 -0400 Subject: [PATCH 2/3] Factor out custom command .rule file path generation Add cmGlobalGenerator::GenerateRuleFile to compute a generator-specific rule file location. This will allow specific generators to override the location of .rule files without changing the behavior of other generators. --- Source/cmGlobalGenerator.cxx | 15 +++++++++++++++ Source/cmGlobalGenerator.h | 3 +++ Source/cmMakefile.cxx | 14 ++++---------- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 545f9e87f5..b06cdb4eee 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -2091,6 +2091,21 @@ cmTarget cmGlobalGenerator::CreateGlobalTarget( return target; } +//---------------------------------------------------------------------------- +std::string +cmGlobalGenerator::GenerateRuleFile(std::string const& output) const +{ + std::string ruleFile = output; + ruleFile += ".rule"; + const char* dir = this->GetCMakeCFGIntDir(); + if(dir && dir[0] == '$') + { + cmSystemTools::ReplaceString(ruleFile, dir, + cmake::GetCMakeFilesDirectory()); + } + return ruleFile; +} + //---------------------------------------------------------------------------- void cmGlobalGenerator::AppendDirectoryForConfig(const char*, const char*, const char*, std::string&) diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index 80b948bc4c..5254b89a67 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -277,6 +277,9 @@ public: i.e. "Can I build Debug and Release in the same tree?" */ virtual bool IsMultiConfig() { return false; } + /** Generate an .rule file path for a given command output. */ + virtual std::string GenerateRuleFile(std::string const& output) const; + protected: typedef std::vector GeneratorVector; // for a project collect all its targets by following depend diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index f2865f6ccd..17bb5ed027 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -948,17 +948,11 @@ cmMakefile::AddCustomCommandToOutput(const std::vector& outputs, // Generate a rule file if the main dependency is not available. if(!file) { + cmGlobalGenerator* gg = this->LocalGenerator->GetGlobalGenerator(); + // Construct a rule file associated with the first output produced. - std::string outName = outputs[0]; - outName += ".rule"; - const char* dir = - this->LocalGenerator->GetGlobalGenerator()-> - GetCMakeCFGIntDir(); - if(dir && dir[0] == '$') - { - cmSystemTools::ReplaceString(outName, dir, - cmake::GetCMakeFilesDirectory()); - } + std::string outName = gg->GenerateRuleFile(outputs[0]); + // Check if the rule file already exists. file = this->GetSource(outName.c_str()); if(file && file->GetCustomCommand() && !replace) From 72333a464870155d040e215bec37a7a31070f875 Mon Sep 17 00:00:00 2001 From: Brad King Date: Wed, 18 Apr 2012 15:50:49 -0400 Subject: [PATCH 3/3] VS10: Avoid creating .rule files next to outputs (#13141) Hide custom command .rule files inside the CMakeFiles directory. Ensure a short, deterministic, and unique name by using a hash of the directory path containing the output file. Preserve the file name so the entry in the IDE is human-readable. Clarify the comment that explains why the rule file must be created on disk. --- Source/cmGlobalVisualStudio10Generator.cxx | 18 ++++++++++++++++++ Source/cmGlobalVisualStudio10Generator.h | 4 ++++ Source/cmVisualStudio10TargetGenerator.cxx | 3 ++- 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx index 22ead10a5a..28d738a8f2 100644 --- a/Source/cmGlobalVisualStudio10Generator.cxx +++ b/Source/cmGlobalVisualStudio10Generator.cxx @@ -212,3 +212,21 @@ bool cmGlobalVisualStudio10Generator::Find64BitTools(cmMakefile* mf) return false; } } + +//---------------------------------------------------------------------------- +std::string +cmGlobalVisualStudio10Generator +::GenerateRuleFile(std::string const& output) const +{ + // The VS 10 generator needs to create the .rule files on disk. + // Hide them away under the CMakeFiles directory. + std::string ruleDir = this->GetCMakeInstance()->GetHomeOutputDirectory(); + ruleDir += cmake::GetCMakeFilesDirectory(); + ruleDir += "/"; + ruleDir += cmSystemTools::ComputeStringMD5( + cmSystemTools::GetFilenamePath(output).c_str()); + std::string ruleFile = ruleDir + "/"; + ruleFile += cmSystemTools::GetFilenameName(output); + ruleFile += ".rule"; + return ruleFile; +} diff --git a/Source/cmGlobalVisualStudio10Generator.h b/Source/cmGlobalVisualStudio10Generator.h index 750b89c4c1..e2cc14ece1 100644 --- a/Source/cmGlobalVisualStudio10Generator.h +++ b/Source/cmGlobalVisualStudio10Generator.h @@ -75,6 +75,10 @@ public: virtual const char* GetCMakeCFGIntDir() const { return "$(Configuration)";} bool Find64BitTools(cmMakefile* mf); + + /** Generate an .rule file path for a given command output. */ + virtual std::string GenerateRuleFile(std::string const& output) const; + protected: virtual const char* GetIDEVersion() { return "10.0"; } diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 592153059a..9c25b0cd43 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -459,7 +459,8 @@ cmVisualStudio10TargetGenerator::WriteCustomRule(cmSourceFile* source, command) { std::string sourcePath = source->GetFullPath(); - // the rule file seems to need to exist for vs10 + // VS 10 will always rebuild a custom command attached to a .rule + // file that doesn't exist so create the file explicitly. if (source->GetPropertyAsBool("__CMAKE_RULE")) { if(!cmSystemTools::FileExists(sourcePath.c_str()))