summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2004-11-02 22:14:04 (GMT)
committerBrad King <brad.king@kitware.com>2004-11-02 22:14:04 (GMT)
commit04f958b6d9b024ba7cefd5b914fb946685a71d8d (patch)
treec63dd7b965f73a56778cb22b6dc77e7cb495edcf
parent95f67dca9e93ad789088dec47526acf7331d2969 (diff)
downloadCMake-04f958b6d9b024ba7cefd5b914fb946685a71d8d.zip
CMake-04f958b6d9b024ba7cefd5b914fb946685a71d8d.tar.gz
CMake-04f958b6d9b024ba7cefd5b914fb946685a71d8d.tar.bz2
ENH: Implemented generation of custom command rule files.
-rw-r--r--Source/cmLocalUnixMakefileGenerator2.cxx215
-rw-r--r--Source/cmLocalUnixMakefileGenerator2.h11
2 files changed, 188 insertions, 38 deletions
diff --git a/Source/cmLocalUnixMakefileGenerator2.cxx b/Source/cmLocalUnixMakefileGenerator2.cxx
index ac73b96..aaae759 100644
--- a/Source/cmLocalUnixMakefileGenerator2.cxx
+++ b/Source/cmLocalUnixMakefileGenerator2.cxx
@@ -67,6 +67,17 @@ void cmLocalUnixMakefileGenerator2::Generate(bool fromTheTop)
}
}
+ // Generate the rule files for each custom command.
+ const std::vector<cmSourceFile*>& sources = m_Makefile->GetSourceFiles();
+ for(std::vector<cmSourceFile*>::const_iterator i = sources.begin();
+ i != sources.end(); ++i)
+ {
+ if((*i)->GetCustomCommand())
+ {
+ this->GenerateCustomRuleFile(*(*i));
+ }
+ }
+
// Generate the main makefile.
this->GenerateMakefile();
@@ -104,8 +115,8 @@ void cmLocalUnixMakefileGenerator2::GenerateMakefile()
// Write the subdirectory driver rules.
this->WriteSubdirRules(makefileStream, "all");
- // Write include statements to get rules for each target.
- this->WriteTargetIncludes(makefileStream);
+ // Write include statements to get rules for this directory.
+ this->WriteRuleFileIncludes(makefileStream);
// Write jump-and-build rules that were recorded in the map.
this->WriteJumpAndBuildRules(makefileStream);
@@ -196,6 +207,11 @@ cmLocalUnixMakefileGenerator2
for(std::vector<cmSourceFile*>::const_iterator source = sources.begin();
source != sources.end(); ++source)
{
+ if((*source)->GetCustomCommand())
+ {
+ // Generate this custom command's rule file.
+ std::cout << "Found custom command!" << std::endl;
+ }
if(!(*source)->GetPropertyAsBool("HEADER_FILE_ONLY") &&
!(*source)->GetCustomCommand() &&
!m_GlobalGenerator->IgnoreFile((*source)->GetSourceExtension().c_str()))
@@ -214,12 +230,17 @@ cmLocalUnixMakefileGenerator2
depBase += target.GetName();
std::string depMakeFile = this->GenerateDependsMakeFile(depBase.c_str());
- // Open the rule file. This should be copy-if-different because the
- // rules may depend on this file itself.
+ // Construct the rule file name.
std::string ruleFileName = dir;
ruleFileName += "/";
ruleFileName += target.GetName();
ruleFileName += ".make";
+
+ // The rule file must be included by the makefile.
+ m_IncludeRuleFiles.push_back(ruleFileName);
+
+ // Open the rule file. This should be copy-if-different because the
+ // rules may depend on this file itself.
std::string ruleFileNameFull = this->ConvertToFullPath(ruleFileName);
cmGeneratedFileStream ruleFile(ruleFileNameFull.c_str());
std::ostream& ruleFileStream = ruleFile.GetStream();
@@ -482,6 +503,115 @@ cmLocalUnixMakefileGenerator2
}
//----------------------------------------------------------------------------
+void
+cmLocalUnixMakefileGenerator2
+::GenerateCustomRuleFile(const cmSourceFile& source)
+{
+ // Get the custom command for the source.
+ if(!source.GetCustomCommand())
+ {
+ cmSystemTools::Error("GenerateCustomRuleFile called for non-custom source.");
+ return;
+ }
+ const cmCustomCommand& cc = *source.GetCustomCommand();
+
+ // Construct the name of the rule file.
+ std::string customName = this->GetCustomBaseName(cc);
+ std::string ruleFileName = customName;
+ ruleFileName += ".make";
+
+ // If this is a duplicate rule produce an error.
+ if(m_CustomRuleFiles.find(ruleFileName) != m_CustomRuleFiles.end())
+ {
+ cmSystemTools::Error("An output was found with multiple rules on how to build it for output: ",
+ cc.GetOutput().c_str());
+ return;
+ }
+ m_CustomRuleFiles.insert(ruleFileName);
+
+ // This rule should be included by the makefile.
+ m_IncludeRuleFiles.push_back(ruleFileName);
+
+ // TODO: Convert outputs/dependencies (arguments?) to relative paths.
+
+ // Open the rule file. This should be copy-if-different because the
+ // rules may depend on this file itself.
+ std::string ruleFileNameFull = this->ConvertToFullPath(ruleFileName);
+ cmGeneratedFileStream ruleFile(ruleFileNameFull.c_str());
+ std::ostream& ruleFileStream = ruleFile.GetStream();
+ if(!ruleFileStream)
+ {
+ // TODO: Produce error message that accounts for generated stream
+ // .tmp.
+ return;
+ }
+ this->WriteDisclaimer(ruleFileStream);
+ ruleFileStream
+ << "# Custom command rule file for " << customName.c_str() << ".\n\n";
+
+ // Build the command line in a single string.
+ std::vector<std::string> commands;
+ std::string cmd = cc.GetCommand();
+ cmSystemTools::ReplaceString(cmd, "/./", "/");
+ cmd = this->ConvertToRelativeOutputPath(cmd.c_str());
+ if(cc.GetArguments().size() > 0)
+ {
+ cmd += " ";
+ cmd += cc.GetArguments();
+ }
+ commands.push_back(cmd);
+
+ // Collect the dependencies.
+ std::vector<std::string> depends;
+ for(std::vector<std::string>::const_iterator d = cc.GetDepends().begin();
+ d != cc.GetDepends().end(); ++d)
+ {
+ // Get the dependency with variables expanded.
+ std::string dep = *d;
+ m_Makefile->ExpandVariablesInString(dep);
+
+ // If the rule depends on a target CMake knows how to build,
+ // convert it to the path where it will be built.
+ std::string libPath = dep + "_CMAKE_PATH";
+ const char* cacheValue = m_Makefile->GetDefinition(libPath.c_str());
+ if(cacheValue && *cacheValue)
+ {
+ libPath = cacheValue;
+ if (m_Makefile->GetDefinition("EXECUTABLE_OUTPUT_PATH") &&
+ m_Makefile->GetDefinition("EXECUTABLE_OUTPUT_PATH")[0] != '\0')
+ {
+ libPath = m_Makefile->GetDefinition("EXECUTABLE_OUTPUT_PATH");
+ }
+ libPath += "/";
+ libPath += dep;
+ libPath += cmSystemTools::GetExecutableExtension();
+ dep = libPath;
+ }
+
+ // Cleanup the dependency and add it.
+ cmSystemTools::ReplaceString(dep, "/./", "/");
+ cmSystemTools::ReplaceString(dep, "/$(IntDir)/", "/");
+ dep = this->ConvertToRelativeOutputPath(dep.c_str());
+ depends.push_back(dep.c_str());
+ }
+
+ // Add a dependency on the rule file itself.
+ depends.push_back(ruleFileName);
+
+ // Write the rule.
+ const char* comment = 0;
+ if(cc.GetComment().size())
+ {
+ comment = cc.GetComment().c_str();
+ }
+ std::string preEcho = "Generating ";
+ preEcho += customName;
+ preEcho += "...";
+ this->WriteMakeRule(ruleFileStream, comment, preEcho.c_str(),
+ cc.GetOutput().c_str(), depends, commands);
+}
+
+//----------------------------------------------------------------------------
std::string
cmLocalUnixMakefileGenerator2
::GenerateDependsMakeFile(const char* file)
@@ -790,7 +920,7 @@ cmLocalUnixMakefileGenerator2
std::vector<std::string> no_depends;
std::vector<std::string> commands;
commands.push_back(
- "$(CMAKE_EDIT_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)");
+ "@$(CMAKE_EDIT_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)");
this->WriteMakeRule(makefileStream,
"Special rule to re-run CMake cache editor using make.",
"Running CMake cache editor...",
@@ -1105,43 +1235,30 @@ cmLocalUnixMakefileGenerator2
//----------------------------------------------------------------------------
void
cmLocalUnixMakefileGenerator2
-::WriteTargetIncludes(std::ostream& makefileStream)
+::WriteRuleFileIncludes(std::ostream& makefileStream)
{
- bool first = true;
- const cmTargets& targets = m_Makefile->GetTargets();
- for(cmTargets::const_iterator t = targets.begin(); t != targets.end(); ++t)
+ // Make sure we have some rules to include.
+ if(m_IncludeRuleFiles.empty())
{
- // TODO: Handle the rest of the target types.
- if((t->second.GetType() == cmTarget::EXECUTABLE) ||
- (t->second.GetType() == cmTarget::STATIC_LIBRARY) ||
- (t->second.GetType() == cmTarget::SHARED_LIBRARY) ||
- (t->second.GetType() == cmTarget::MODULE_LIBRARY))
- {
- // Write the header for this section.
- if(first)
- {
- this->WriteDivider(makefileStream);
- makefileStream
- << "# Include rule files for each target in this directory.\n"
- << "\n";
- first = false;
- }
-
- // Construct the rule file name for this target.
- std::string ruleFileName = this->GetTargetDirectory(t->second);
- ruleFileName += "/";
- ruleFileName += t->first;
- ruleFileName += ".make";
- makefileStream
- << m_IncludeDirective << " "
- << this->ConvertToOutputForExisting(ruleFileName.c_str()).c_str()
- << "\n";
- }
+ return;
}
- if(!first)
+
+ // Write section header.
+ this->WriteDivider(makefileStream);
+ makefileStream
+ << "# Include rule files for this directory.\n"
+ << "\n";
+
+ // Write the include rules.
+ for(std::vector<std::string>::const_iterator i = m_IncludeRuleFiles.begin();
+ i != m_IncludeRuleFiles.end(); ++i)
{
- makefileStream << "\n";
+ makefileStream
+ << m_IncludeDirective << " "
+ << this->ConvertToOutputForExisting(i->c_str()).c_str()
+ << "\n";
}
+ makefileStream << "\n";
}
//----------------------------------------------------------------------------
@@ -1621,6 +1738,30 @@ cmLocalUnixMakefileGenerator2
}
//----------------------------------------------------------------------------
+std::string
+cmLocalUnixMakefileGenerator2
+::GetCustomBaseName(const cmCustomCommand& cc)
+{
+ // If the full path to the output file includes this build
+ // directory, we want to use the relative path for the filename of
+ // the custom file. Otherwise, we will use just the filename
+ // portion.
+ std::string customName;
+ if(cmSystemTools::FileIsFullPath(cc.GetOutput().c_str()) &&
+ (cc.GetOutput().find(m_Makefile->GetStartOutputDirectory()) == 0))
+ {
+ customName =
+ cmSystemTools::RelativePath(m_Makefile->GetStartOutputDirectory(),
+ cc.GetOutput().c_str());
+ }
+ else
+ {
+ customName = cmSystemTools::GetFilenameName(cc.GetOutput().c_str());
+ }
+ return customName;
+}
+
+//----------------------------------------------------------------------------
const char*
cmLocalUnixMakefileGenerator2
::GetSourceFileLanguage(const cmSourceFile& source)
diff --git a/Source/cmLocalUnixMakefileGenerator2.h b/Source/cmLocalUnixMakefileGenerator2.h
index ae0c156..3ad7b25 100644
--- a/Source/cmLocalUnixMakefileGenerator2.h
+++ b/Source/cmLocalUnixMakefileGenerator2.h
@@ -19,6 +19,7 @@
#include "cmLocalUnixMakefileGenerator.h"
+class cmCustomCommand;
class cmDependInformation;
class cmMakeDepend;
class cmTarget;
@@ -65,6 +66,7 @@ protected:
void GenerateTargetRuleFile(const cmTarget& target);
void GenerateObjectRuleFile(const cmTarget& target,
const cmSourceFile& source);
+ void GenerateCustomRuleFile(const cmSourceFile& source);
std::string GenerateDependsMakeFile(const char* file);
void WriteMakeRule(std::ostream& os,
const char* comment,
@@ -78,7 +80,7 @@ protected:
void WriteMakeVariables(std::ostream& makefileStream);
void WriteSpecialTargetsTop(std::ostream& makefileStream);
void WriteSpecialTargetsBottom(std::ostream& makefileStream);
- void WriteTargetIncludes(std::ostream& makefileStream);
+ void WriteRuleFileIncludes(std::ostream& makefileStream);
void WriteAllRule(std::ostream& makefileStream);
void WriteSubdirRules(std::ostream& makefileStream, const char* pass);
void WriteSubdirRule(std::ostream& makefileStream, const char* pass,
@@ -114,6 +116,7 @@ protected:
std::string GetSubdirTargetName(const char* pass, const char* subdir);
std::string GetObjectFileName(const cmTarget& target,
const cmSourceFile& source);
+ std::string GetCustomBaseName(const cmCustomCommand& cc);
const char* GetSourceFileLanguage(const cmSourceFile& source);
std::string ConvertToFullPath(const std::string& localPath);
@@ -146,6 +149,12 @@ private:
// Command used when a rule has no dependencies or commands.
std::vector<std::string> m_EmptyCommands;
+
+ // List of make rule files that need to be included by the makefile.
+ std::vector<std::string> m_IncludeRuleFiles;
+
+ // Set of custom rule files that have been generated.
+ std::set<cmStdString> m_CustomRuleFiles;
};
#endif