diff options
author | Brad King <brad.king@kitware.com> | 2005-02-22 15:32:44 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2005-02-22 15:32:44 (GMT) |
commit | 39af9ee1e496db77849015541f687897ed819a56 (patch) | |
tree | 79bd7c1765408c80822dc9b87853bdac24704332 /Source/cmMakefile.cxx | |
parent | 4d30cb309cc0cd191e89a7969599b79dea111a08 (diff) | |
download | CMake-39af9ee1e496db77849015541f687897ed819a56.zip CMake-39af9ee1e496db77849015541f687897ed819a56.tar.gz CMake-39af9ee1e496db77849015541f687897ed819a56.tar.bz2 |
ENH: Updated implementation of custom commands. Multiple command lines are now supported effectively allowing entire scripts to be written. Also removed extra variable expansions and cleaned up passing of commands through to the generators. The command and individual arguments are now kept separate all the way until the generator writes them out. This cleans up alot of escaping issues.
Diffstat (limited to 'Source/cmMakefile.cxx')
-rw-r--r-- | Source/cmMakefile.cxx | 491 |
1 files changed, 194 insertions, 297 deletions
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 62a1e7c..25671c9 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -496,278 +496,253 @@ void cmMakefile::ConfigureFinalPass() } } +//---------------------------------------------------------------------------- +void +cmMakefile::AddCustomCommandToTarget(const char* target, + const std::vector<std::string>& depends, + const cmCustomCommandLines& commandLines, + cmTarget::CustomCommandType type, + const char* comment) +{ + // Find the target to which to add the custom command. + cmTargets::iterator ti = m_Targets.find(target); + if(ti != m_Targets.end()) + { + // Add the command to the appropriate build step for the target. + const char* no_output = 0; + cmCustomCommand cc(no_output, depends, commandLines, comment); + switch(type) + { + case cmTarget::PRE_BUILD: + ti->second.GetPreBuildCommands().push_back(cc); + break; + case cmTarget::PRE_LINK: + ti->second.GetPreLinkCommands().push_back(cc); + break; + case cmTarget::POST_BUILD: + ti->second.GetPostBuildCommands().push_back(cc); + break; + } -// this is the old style signature, we convert to new style -void cmMakefile::AddCustomCommand(const char* source, - const char* command, - const std::vector<std::string>& commandArgs, - const std::vector<std::string>& depends, - const std::vector<std::string>& outputs, - const char *target, - const char *comment) -{ - if (strcmp(source,target)) - { - // what a pain, for backwards compatibility we will try to - // convert this to an output based rule... so for each output.. - for(std::vector<std::string>::const_iterator d = outputs.begin(); - d != outputs.end(); ++d) - { - // if this looks like a real file then use is as the main depend - cmsys::RegularExpression SourceFiles("\\.(C|M|c|c\\+\\+|cc|cpp|cxx|m|mm|rc|def|r|odl|idl|hpj|bat|h|h\\+\\+|hm|hpp|hxx|in|txx|inl)$"); - if (SourceFiles.find(source)) - { - this->AddCustomCommandToOutput(d->c_str(), command, commandArgs, - source, depends, comment); - } - // otherwise do not use a main depend - else - { - std::vector<std::string> depends2 = depends; - depends2.push_back(source); - this->AddCustomCommandToOutput(d->c_str(), command, commandArgs, - 0, depends2, comment); - } - - // add the output to the target? - std::string sname = *d; - sname += ".rule"; - this->ExpandVariablesInString(sname); - // if the rule was added to the source, - // then add the source to the target - if (!this->GetSource(sname.c_str())) + // Add dependencies on commands CMake knows how to build. + for(cmCustomCommandLines::const_iterator cli = commandLines.begin(); + cli != commandLines.end(); ++cli) + { + std::string cacheCommand = *cli->begin(); + if(const char* knownTarget = + this->GetCacheManager()->GetCacheValue(cacheCommand.c_str())) { - if (m_Targets.find(target) != m_Targets.end()) - { - m_Targets[target].GetSourceLists().push_back(source); - } - else - { - cmSystemTools::Error("Attempt to add a custom rule to a target that does not exist yet for target ", target); - return; - } + ti->second.AddUtility(knownTarget); } } } - else - { - this->AddCustomCommandToTarget(target, command, commandArgs, - cmTarget::POST_BUILD, comment, depends); - } } -void cmMakefile::AddCustomCommand(const char* source, - const char* command, - const std::vector<std::string>& commandArgs, - const std::vector<std::string>& depends, - const char* output, - const char *target) +//---------------------------------------------------------------------------- +void +cmMakefile::AddCustomCommandToOutput(const char* output, + const std::vector<std::string>& depends, + const char* main_dependency, + const cmCustomCommandLines& commandLines, + const char* comment, + bool replace) { - std::vector<std::string> outputs; - outputs.push_back(output); - this->AddCustomCommand(source, command, commandArgs, depends, - outputs, target); -} - -void cmMakefile:: -AddCustomCommandToOutput(const char* outputIn, - const char* inCommand, - const std::vector<std::string>& commandArgs, - const char *main_dependency, - const std::vector<std::string>& depends, - const char *comment, - bool replace) -{ - std::string expandC; - std::string combinedArgs; - std::string command = inCommand; - - // process the command's string - this->ExpandVariablesInString(command); - command = cmSystemTools::EscapeSpaces(command.c_str()); - - unsigned int i; - bool escapeSpaces = true; - for (i = 0; i < commandArgs.size(); ++i) + // Choose a source file on which to store the custom command. + cmSourceFile* file = 0; + if(main_dependency && main_dependency[0]) { - expandC = commandArgs[i].c_str(); - // This is a hack to fix a problem with cmCustomCommand - // The cmCustomCommand should store the arguments as a vector - // and not a string, and the cmAddCustomTargetCommand should - // not EscapeSpaces. - if(expandC == "This is really a single argument do not escape spaces") - { - escapeSpaces = false; - } - else + // The main dependency was specified. Use it unless a different + // custom command already used it. + file = this->GetSource(main_dependency); + if(file && file->GetCustomCommand() && !replace) { - this->ExpandVariablesInString(expandC); - if(escapeSpaces) + // The main dependency already has a custom command. + if(commandLines == file->GetCustomCommand()->GetCommandLines()) { - combinedArgs += cmSystemTools::EscapeSpaces(expandC.c_str()); + // The existing custom command is identical. Silently ignore + // the duplicate. + return; } else { - combinedArgs += expandC; + // The existing custom command is different. We need to + // generate a rule file for this new command. + file = 0; } - combinedArgs += " "; - } - } - cmSourceFile *file = 0; - - // setup the output name and make sure we expand any variables - std::string output = outputIn; - this->ExpandVariablesInString(output); - std::string outName = output; - outName += ".rule"; - - // setup the main dependency name and expand vars of course - std::string mainDepend; - if (main_dependency && main_dependency[0] != '\0') - { - mainDepend = main_dependency; - this->ExpandVariablesInString(mainDepend); - } - - // OK this rule will be placed on a generated output file unless the main - // depednency was specified. - if (main_dependency && main_dependency[0] != '\0') - { - file = this->GetSource(mainDepend.c_str()); - if (file && file->GetCustomCommand() && !replace) - { - cmCustomCommand* cc = file->GetCustomCommand(); - // if the command and args are the same - // as the command already there, then silently skip - // this add command - if(cc->IsEquivalent(command.c_str(), combinedArgs.c_str())) - { - return; - } - // generate a source instead - file = 0; } else { - file = this->GetOrCreateSource(mainDepend.c_str()); + // The main dependency does not have a custom command or we are + // allowed to replace it. Use it to store the command. + file = this->GetOrCreateSource(main_dependency); } } - if (!file) + // Generate a rule file if the main dependency is not available. + if(!file) { + // Construct a rule file associated with the output produced. + std::string outName = output; + outName += ".rule"; + + // Check if the rule file already exists. file = this->GetSource(outName.c_str()); - if (file && file->GetCustomCommand() && !replace) + if(file && file->GetCustomCommand() && !replace) { - cmCustomCommand* cc = file->GetCustomCommand(); - // if the command and args are the same - // as the command already there, then silently skip - // this add command - if(cc->IsEquivalent(command.c_str(), combinedArgs.c_str())) + // The rule file already exists. + if(commandLines != file->GetCustomCommand()->GetCommandLines()) { - return; + cmSystemTools::Error("Attempt to add a custom rule to output \"", + output, "\" which already has a custom rule."); } - // produce error if two different commands are given to produce - // the same output - cmSystemTools::Error("Attempt to add a custom rule to an output that already" - " has a custom rule. For output: ", outputIn); return; } - // create a cmSourceFile for the output + + // Create a cmSourceFile for the rule file. file = this->GetOrCreateSource(outName.c_str(), true); - if(file) - { - // always mark as generated - file->SetProperty("GENERATED","1"); - } } - - // always create the output and mark it generated - if(cmSourceFile *out = this->GetOrCreateSource(output.c_str(), true)) + + // Always create the output and mark it generated. + if(cmSourceFile* out = this->GetOrCreateSource(output, true)) { - out->SetProperty("GENERATED","1"); + out->SetProperty("GENERATED", "1"); } - + + // Construct a complete list of dependencies. std::vector<std::string> depends2(depends); - if (main_dependency && main_dependency[0] != '\0') + if(main_dependency && main_dependency[0]) { - depends2.push_back(mainDepend.c_str()); - } - cmCustomCommand *cc = - new cmCustomCommand(command.c_str(),combinedArgs.c_str(),depends2, - output.c_str()); - if ( comment && comment[0] ) - { - cc->SetComment(comment); + depends2.push_back(main_dependency); } + + // Attach the custom command to the file. if(file) { + cmCustomCommand* cc = + new cmCustomCommand(output, depends2, commandLines, comment); file->SetCustomCommand(cc); } } -void cmMakefile:: -AddCustomCommandToTarget(const char* target, const char* command, - const std::vector<std::string>& commandArgs, - cmTarget::CustomCommandType type, - const char *comment) +//---------------------------------------------------------------------------- +void +cmMakefile::AddCustomCommandOldStyle(const char* target, + const std::vector<std::string>& outputs, + const std::vector<std::string>& depends, + const char* source, + const cmCustomCommandLines& commandLines, + const char* comment) { - std::vector<std::string> empty; - this->AddCustomCommandToTarget(target,command,commandArgs,type, - comment, empty); -} + // Translate the old-style signature to one of the new-style + // signatures. + if(strcmp(source, target) == 0) + { + // In the old-style signature if the source and target were the + // same then it added a post-build rule to the target. Preserve + // this behavior. + this->AddCustomCommandToTarget(target, depends, commandLines, + cmTarget::POST_BUILD, comment); + return; + } -void cmMakefile:: -AddCustomCommandToTarget(const char* target, const char* command, - const std::vector<std::string>& commandArgs, - cmTarget::CustomCommandType type, - const char *comment, - const std::vector<std::string>& depends) -{ - // find the target, - if (m_Targets.find(target) != m_Targets.end()) + // Each output must get its own copy of this rule. + cmsys::RegularExpression sourceFiles("\\.(C|M|c|c\\+\\+|cc|cpp|cxx|m|mm|" + "rc|def|r|odl|idl|hpj|bat|h|h\\+\\+|" + "hm|hpp|hxx|in|txx|inl)$"); + for(std::vector<std::string>::const_iterator oi = outputs.begin(); + oi != outputs.end(); ++oi) { - std::string expandC = command; - this->ExpandVariablesInString(expandC); - std::string c = cmSystemTools::EscapeSpaces(expandC.c_str()); - - std::string combinedArgs; - unsigned int i; - - for (i = 0; i < commandArgs.size(); ++i) + // Get the name of this output. + const char* output = oi->c_str(); + + // Choose whether to use a main dependency. + if(sourceFiles.find(source)) { - expandC = commandArgs[i].c_str(); - this->ExpandVariablesInString(expandC); - combinedArgs += cmSystemTools::EscapeSpaces(expandC.c_str()); - combinedArgs += " "; + // The source looks like a real file. Use it as the main dependency. + this->AddCustomCommandToOutput(output, depends, source, + commandLines, comment); } - - cmCustomCommand cc(c.c_str(),combinedArgs.c_str(),depends,0); - if ( comment && comment[0] ) + else { - cc.SetComment(comment); + // The source may not be a real file. Do not use a main dependency. + const char* no_main_dependency = 0; + std::vector<std::string> depends2 = depends; + depends2.push_back(source); + this->AddCustomCommandToOutput(output, depends2, no_main_dependency, + commandLines, comment); } - switch (type) - { - case cmTarget::PRE_BUILD: - m_Targets[target].GetPreBuildCommands().push_back(cc); - break; - case cmTarget::PRE_LINK: - m_Targets[target].GetPreLinkCommands().push_back(cc); - break; - case cmTarget::POST_BUILD: - m_Targets[target].GetPostBuildCommands().push_back(cc); - break; - } - std::string cacheCommand = command; - this->ExpandVariablesInString(cacheCommand); - if(this->GetCacheManager()->GetCacheValue(cacheCommand.c_str())) + + // 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())) { - m_Targets[target].AddUtility( - this->GetCacheManager()->GetCacheValue(cacheCommand.c_str())); + if (m_Targets.find(target) != m_Targets.end()) + { + m_Targets[target].GetSourceLists().push_back(source); + } + else + { + cmSystemTools::Error("Attempt to add a custom rule to a target " + "that does not exist yet for target ", target); + return; + } } } } +//---------------------------------------------------------------------------- +void cmMakefile::AddUtilityCommand(const char* utilityName, bool all, + const char* output, + const std::vector<std::string>& depends, + const char* command, + const char* arg1, + const char* arg2, + const char* arg3) +{ + // Construct the command line for the custom command. + cmCustomCommandLine commandLine; + commandLine.push_back(command); + if(arg1) + { + commandLine.push_back(arg1); + } + if(arg2) + { + commandLine.push_back(arg2); + } + if(arg3) + { + commandLine.push_back(arg3); + } + cmCustomCommandLines commandLines; + commandLines.push_back(commandLine); + + // Call the real signature of this method. + this->AddUtilityCommand(utilityName, all, output, depends, commandLines); +} + +//---------------------------------------------------------------------------- +void cmMakefile::AddUtilityCommand(const char* utilityName, bool all, + const char* output, + const std::vector<std::string>& depends, + const cmCustomCommandLines& commandLines) +{ + // Create a target instance for this utility. + cmTarget target; + target.SetType(cmTarget::UTILITY, utilityName); + target.SetInAll(all); + + // Store the custom command in the target. + cmCustomCommand cc(output, depends, commandLines, 0); + target.GetPostBuildCommands().push_back(cc); + + // Add the target to the set of targets. + m_Targets.insert(cmTargets::value_type(utilityName, target)); +} + void cmMakefile::AddDefineFlag(const char* flag) { m_DefineFlags += " "; @@ -1128,48 +1103,6 @@ cmTarget* cmMakefile::AddExecutable(const char *exeName, return &it->second; } - -void cmMakefile::AddUtilityCommand(const char* utilityName, - const char* command, - const char* arguments, - bool all, - const std::vector<std::string> &depends) -{ - std::vector<std::string> empty; - this->AddUtilityCommand(utilityName,command,arguments,all, - depends, empty); -} - -void cmMakefile::AddUtilityCommand(const char* utilityName, - const char* command, - const char* arguments, - bool all, - const std::vector<std::string> &dep, - const std::vector<std::string> &out) -{ - cmTarget target; - target.SetType(cmTarget::UTILITY, utilityName); - target.SetInAll(all); - if (out.size() > 1) - { - cmSystemTools::Error( - "Utility targets can only have one output. For utilityNamed: ", - utilityName); - return; - } - if (out.size()) - { - cmCustomCommand cc(command, arguments, dep, out[0].c_str()); - target.GetPostBuildCommands().push_back(cc); - } - else - { - cmCustomCommand cc(command, arguments, dep, (const char *)0); - target.GetPostBuildCommands().push_back(cc); - } - m_Targets.insert(cmTargets::value_type(utilityName,target)); -} - cmSourceFile *cmMakefile::GetSourceFileWithOutput(const char *cname) { std::string name = cname; @@ -1323,42 +1256,6 @@ void cmMakefile::ExpandVariables() } } -void cmMakefile::ExpandVariablesInCustomCommands() -{ - // do source files - for(std::vector<cmSourceFile*>::iterator i = m_SourceFiles.begin(); - i != m_SourceFiles.end(); ++i) - { - cmCustomCommand *cc = (*i)->GetCustomCommand(); - if (cc) - { - cc->ExpandVariables(*this); - } - } - - // now do targets - std::vector<cmCustomCommand>::iterator ic; - for (cmTargets::iterator l = m_Targets.begin(); - l != m_Targets.end(); l++) - { - for (ic = l->second.GetPreBuildCommands().begin(); - ic != l->second.GetPreBuildCommands().end(); ++ic) - { - ic->ExpandVariables(*this); - } - for (ic = l->second.GetPreLinkCommands().begin(); - ic != l->second.GetPreLinkCommands().end(); ++ic) - { - ic->ExpandVariables(*this); - } - for (ic = l->second.GetPostBuildCommands().begin(); - ic != l->second.GetPostBuildCommands().end(); ++ic) - { - ic->ExpandVariables(*this); - } - } -} - bool cmMakefile::IsOn(const char* name) const { const char* value = this->GetDefinition(name); |