ENH: Implemented generation of custom command rule files.

This commit is contained in:
Brad King 2004-11-02 17:14:04 -05:00
parent 95f67dca9e
commit 04f958b6d9
2 changed files with 188 additions and 38 deletions

View File

@ -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();
@ -481,6 +502,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
@ -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;
}
return;
}
// 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";
}
}
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";
}
//----------------------------------------------------------------------------
@ -1620,6 +1737,30 @@ cmLocalUnixMakefileGenerator2
return obj;
}
//----------------------------------------------------------------------------
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

View File

@ -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