diff options
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); |