diff options
Diffstat (limited to 'Source/cmMakefileTargetGenerator.cxx')
-rw-r--r-- | Source/cmMakefileTargetGenerator.cxx | 2312 |
1 files changed, 1036 insertions, 1276 deletions
diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 5e6c54822..a4511b63b 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -1,57 +1,54 @@ -/*============================================================================ - CMake - Cross Platform Makefile Generator - Copyright 2000-2009 Kitware, Inc., Insight Software Consortium - - Distributed under the OSI-approved BSD License (the "License"); - see accompanying file Copyright.txt for details. - - This software is distributed WITHOUT ANY WARRANTY; without even the - implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the License for more information. -============================================================================*/ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmMakefileTargetGenerator.h" -#include "cmGeneratorTarget.h" +#include <sstream> +#include <stdio.h> +#include <utility> + +#include "cmAlgorithms.h" +#include "cmComputeLinkInformation.h" +#include "cmCustomCommand.h" +#include "cmCustomCommandGenerator.h" #include "cmGeneratedFileStream.h" -#include "cmGlobalGenerator.h" +#include "cmGeneratorExpression.h" +#include "cmGeneratorTarget.h" #include "cmGlobalUnixMakefileGenerator3.h" #include "cmLocalUnixMakefileGenerator3.h" #include "cmMakefile.h" -#include "cmSourceFile.h" -#include "cmTarget.h" -#include "cmake.h" -#include "cmComputeLinkInformation.h" - #include "cmMakefileExecutableTargetGenerator.h" #include "cmMakefileLibraryTargetGenerator.h" #include "cmMakefileUtilityTargetGenerator.h" +#include "cmOutputConverter.h" +#include "cmRulePlaceholderExpander.h" +#include "cmSourceFile.h" +#include "cmState.h" +#include "cmStateDirectory.h" +#include "cmStateSnapshot.h" +#include "cmStateTypes.h" +#include "cmSystemTools.h" +#include "cm_auto_ptr.hxx" +#include "cmake.h" - -cmMakefileTargetGenerator::cmMakefileTargetGenerator(cmTarget* target) - : OSXBundleGenerator(0) - , MacOSXContentGenerator(0) +cmMakefileTargetGenerator::cmMakefileTargetGenerator(cmGeneratorTarget* target) + : cmCommonTargetGenerator(target) + , OSXBundleGenerator(CM_NULLPTR) + , MacOSXContentGenerator(CM_NULLPTR) { - this->BuildFileStream = 0; - this->InfoFileStream = 0; - this->FlagFileStream = 0; + this->BuildFileStream = CM_NULLPTR; + this->InfoFileStream = CM_NULLPTR; + this->FlagFileStream = CM_NULLPTR; this->CustomCommandDriver = OnBuild; - this->FortranModuleDirectoryComputed = false; - this->Target = target; - this->Makefile = this->Target->GetMakefile(); this->LocalGenerator = - static_cast<cmLocalUnixMakefileGenerator3*>( - this->Makefile->GetLocalGenerator()); - this->ConfigName = this->LocalGenerator->ConfigurationName.c_str(); - this->GlobalGenerator = - static_cast<cmGlobalUnixMakefileGenerator3*>( - this->LocalGenerator->GetGlobalGenerator()); - this->GeneratorTarget = this->GlobalGenerator->GetGeneratorTarget(target); + static_cast<cmLocalUnixMakefileGenerator3*>(target->GetLocalGenerator()); + this->GlobalGenerator = static_cast<cmGlobalUnixMakefileGenerator3*>( + this->LocalGenerator->GetGlobalGenerator()); cmake* cm = this->GlobalGenerator->GetCMakeInstance(); this->NoRuleMessages = false; - if(const char* ruleStatus = cm->GetProperty("RULE_MESSAGES")) - { + if (const char* ruleStatus = + cm->GetState()->GetGlobalProperty("RULE_MESSAGES")) { this->NoRuleMessages = cmSystemTools::IsOff(ruleStatus); - } + } MacOSXContentGenerator = new MacOSXContentGeneratorType(this); } @@ -60,38 +57,36 @@ cmMakefileTargetGenerator::~cmMakefileTargetGenerator() delete MacOSXContentGenerator; } -cmMakefileTargetGenerator * -cmMakefileTargetGenerator::New(cmTarget *tgt) +cmMakefileTargetGenerator* cmMakefileTargetGenerator::New( + cmGeneratorTarget* tgt) { - cmMakefileTargetGenerator *result = 0; + cmMakefileTargetGenerator* result = CM_NULLPTR; - switch (tgt->GetType()) - { - case cmTarget::EXECUTABLE: + switch (tgt->GetType()) { + case cmStateEnums::EXECUTABLE: result = new cmMakefileExecutableTargetGenerator(tgt); break; - case cmTarget::STATIC_LIBRARY: - case cmTarget::SHARED_LIBRARY: - case cmTarget::MODULE_LIBRARY: - case cmTarget::OBJECT_LIBRARY: + case cmStateEnums::STATIC_LIBRARY: + case cmStateEnums::SHARED_LIBRARY: + case cmStateEnums::MODULE_LIBRARY: + case cmStateEnums::OBJECT_LIBRARY: result = new cmMakefileLibraryTargetGenerator(tgt); break; - case cmTarget::UTILITY: + case cmStateEnums::UTILITY: result = new cmMakefileUtilityTargetGenerator(tgt); break; default: return result; // break; /* unreachable */ - } + } return result; } -//---------------------------------------------------------------------------- void cmMakefileTargetGenerator::CreateRuleFile() { // Create a directory for this target. this->TargetBuildDirectory = - this->LocalGenerator->GetTargetDirectory(*this->Target); + this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget); this->TargetBuildDirectoryFull = this->LocalGenerator->ConvertToFullPath(this->TargetBuildDirectory); cmSystemTools::MakeDirectory(this->TargetBuildDirectoryFull.c_str()); @@ -112,268 +107,219 @@ void cmMakefileTargetGenerator::CreateRuleFile() // Open the rule file. This should be copy-if-different because the // rules may depend on this file itself. this->BuildFileStream = - new cmGeneratedFileStream(this->BuildFileNameFull.c_str()); + new cmGeneratedFileStream(this->BuildFileNameFull.c_str(), false, + this->GlobalGenerator->GetMakefileEncoding()); this->BuildFileStream->SetCopyIfDifferent(true); - if(!this->BuildFileStream) - { + if (!this->BuildFileStream) { return; - } + } this->LocalGenerator->WriteDisclaimer(*this->BuildFileStream); + if (this->GlobalGenerator->AllowDeleteOnError()) { + std::vector<std::string> no_depends; + std::vector<std::string> no_commands; + this->LocalGenerator->WriteMakeRule( + *this->BuildFileStream, "Delete rule output on recipe failure.", + ".DELETE_ON_ERROR", no_depends, no_commands, false); + } this->LocalGenerator->WriteSpecialTargetsTop(*this->BuildFileStream); } -//---------------------------------------------------------------------------- void cmMakefileTargetGenerator::WriteTargetBuildRules() { + const std::string& config = + this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"); + // write the custom commands for this target // Look for files registered for cleaning in this directory. - if(const char* additional_clean_files = - this->Makefile->GetProperty - ("ADDITIONAL_MAKE_CLEAN_FILES")) - { - cmSystemTools::ExpandListArgument(additional_clean_files, - this->CleanFiles); - } + if (const char* additional_clean_files = + this->Makefile->GetProperty("ADDITIONAL_MAKE_CLEAN_FILES")) { + cmGeneratorExpression ge; + CM_AUTO_PTR<cmCompiledGeneratorExpression> cge = + ge.Parse(additional_clean_files); + + cmSystemTools::ExpandListArgument( + cge->Evaluate(this->LocalGenerator, config, false, this->GeneratorTarget, + CM_NULLPTR, CM_NULLPTR), + this->CleanFiles); + } // add custom commands to the clean rules? - const char* clean_no_custom = - this->Makefile->GetProperty("CLEAN_NO_CUSTOM"); + const char* clean_no_custom = this->Makefile->GetProperty("CLEAN_NO_CUSTOM"); bool clean = cmSystemTools::IsOff(clean_no_custom); // First generate the object rule files. Save a list of all object // files for this target. - for(std::vector<cmSourceFile*>::const_iterator - si = this->GeneratorTarget->CustomCommands.begin(); - si != this->GeneratorTarget->CustomCommands.end(); ++si) - { - cmCustomCommand const* cc = (*si)->GetCustomCommand(); - this->GenerateCustomRuleFile(*cc); - if (clean) - { - const std::vector<std::string>& outputs = cc->GetOutputs(); - for(std::vector<std::string>::const_iterator o = outputs.begin(); - o != outputs.end(); ++o) - { - this->CleanFiles.push_back - (this->Convert(o->c_str(), - cmLocalGenerator::START_OUTPUT, - cmLocalGenerator::UNCHANGED)); - } + std::vector<cmSourceFile const*> customCommands; + this->GeneratorTarget->GetCustomCommands(customCommands, config); + std::string currentBinDir = + this->LocalGenerator->GetCurrentBinaryDirectory(); + for (std::vector<cmSourceFile const*>::const_iterator si = + customCommands.begin(); + si != customCommands.end(); ++si) { + cmCustomCommandGenerator ccg(*(*si)->GetCustomCommand(), this->ConfigName, + this->LocalGenerator); + this->GenerateCustomRuleFile(ccg); + if (clean) { + const std::vector<std::string>& outputs = ccg.GetOutputs(); + for (std::vector<std::string>::const_iterator o = outputs.begin(); + o != outputs.end(); ++o) { + this->CleanFiles.push_back( + this->LocalGenerator->MaybeConvertToRelativePath(currentBinDir, *o)); } } + } + std::vector<cmSourceFile const*> headerSources; + this->GeneratorTarget->GetHeaderSources(headerSources, config); this->OSXBundleGenerator->GenerateMacOSXContentStatements( - this->GeneratorTarget->HeaderSources, - this->MacOSXContentGenerator); + headerSources, this->MacOSXContentGenerator); + std::vector<cmSourceFile const*> extraSources; + this->GeneratorTarget->GetExtraSources(extraSources, config); this->OSXBundleGenerator->GenerateMacOSXContentStatements( - this->GeneratorTarget->ExtraSources, - this->MacOSXContentGenerator); - for(std::vector<cmSourceFile*>::const_iterator - si = this->GeneratorTarget->ExternalObjects.begin(); - si != this->GeneratorTarget->ExternalObjects.end(); ++si) - { + extraSources, this->MacOSXContentGenerator); + std::vector<cmSourceFile const*> externalObjects; + this->GeneratorTarget->GetExternalObjects(externalObjects, config); + for (std::vector<cmSourceFile const*>::const_iterator si = + externalObjects.begin(); + si != externalObjects.end(); ++si) { this->ExternalObjects.push_back((*si)->GetFullPath()); - } - for(std::vector<cmSourceFile*>::const_iterator - si = this->GeneratorTarget->ObjectSources.begin(); - si != this->GeneratorTarget->ObjectSources.end(); ++si) - { + } + std::vector<cmSourceFile const*> objectSources; + this->GeneratorTarget->GetObjectSources(objectSources, config); + for (std::vector<cmSourceFile const*>::const_iterator si = + objectSources.begin(); + si != objectSources.end(); ++si) { // Generate this object file's rule file. this->WriteObjectRuleFiles(**si); - } - - // Add object library contents as external objects. - this->GeneratorTarget->UseObjectLibraries(this->ExternalObjects); + } } -//---------------------------------------------------------------------------- void cmMakefileTargetGenerator::WriteCommonCodeRules() { - const char* root = (this->Makefile->IsOn("CMAKE_MAKE_INCLUDE_FROM_ROOT")? - "$(CMAKE_BINARY_DIR)/" : ""); + const char* root = (this->Makefile->IsOn("CMAKE_MAKE_INCLUDE_FROM_ROOT") + ? "$(CMAKE_BINARY_DIR)/" + : ""); // Include the dependencies for the target. std::string dependFileNameFull = this->TargetBuildDirectoryFull; dependFileNameFull += "/depend.make"; *this->BuildFileStream << "# Include any dependencies generated for this target.\n" - << this->LocalGenerator->IncludeDirective << " " << root - << this->Convert(dependFileNameFull.c_str(), - cmLocalGenerator::HOME_OUTPUT, - cmLocalGenerator::MAKEFILE) + << this->GlobalGenerator->IncludeDirective << " " << root + << cmSystemTools::ConvertToOutputPath( + this->LocalGenerator + ->MaybeConvertToRelativePath( + this->LocalGenerator->GetBinaryDirectory(), dependFileNameFull) + .c_str()) << "\n\n"; - if(!this->NoRuleMessages) - { + if (!this->NoRuleMessages) { // Include the progress variables for the target. *this->BuildFileStream << "# Include the progress variables for this target.\n" - << this->LocalGenerator->IncludeDirective << " " << root - << this->Convert(this->ProgressFileNameFull.c_str(), - cmLocalGenerator::HOME_OUTPUT, - cmLocalGenerator::MAKEFILE) + << this->GlobalGenerator->IncludeDirective << " " << root + << cmSystemTools::ConvertToOutputPath( + this->LocalGenerator + ->MaybeConvertToRelativePath( + this->LocalGenerator->GetBinaryDirectory(), + this->ProgressFileNameFull) + .c_str()) << "\n\n"; - } + } // make sure the depend file exists - if (!cmSystemTools::FileExists(dependFileNameFull.c_str())) - { + if (!cmSystemTools::FileExists(dependFileNameFull.c_str())) { // Write an empty dependency file. - cmGeneratedFileStream depFileStream(dependFileNameFull.c_str()); - depFileStream - << "# Empty dependencies file for " << this->Target->GetName() << ".\n" - << "# This may be replaced when dependencies are built." << std::endl; - } + cmGeneratedFileStream depFileStream( + dependFileNameFull.c_str(), false, + this->GlobalGenerator->GetMakefileEncoding()); + depFileStream << "# Empty dependencies file for " + << this->GeneratorTarget->GetName() << ".\n" + << "# This may be replaced when dependencies are built." + << std::endl; + } // Open the flags file. This should be copy-if-different because the // rules may depend on this file itself. this->FlagFileNameFull = this->TargetBuildDirectoryFull; this->FlagFileNameFull += "/flags.make"; this->FlagFileStream = - new cmGeneratedFileStream(this->FlagFileNameFull.c_str()); + new cmGeneratedFileStream(this->FlagFileNameFull.c_str(), false, + this->GlobalGenerator->GetMakefileEncoding()); this->FlagFileStream->SetCopyIfDifferent(true); - if(!this->FlagFileStream) - { + if (!this->FlagFileStream) { return; - } + } this->LocalGenerator->WriteDisclaimer(*this->FlagFileStream); // Include the flags for the target. *this->BuildFileStream << "# Include the compile flags for this target's objects.\n" - << this->LocalGenerator->IncludeDirective << " " << root - << this->Convert(this->FlagFileNameFull.c_str(), - cmLocalGenerator::HOME_OUTPUT, - cmLocalGenerator::MAKEFILE) + << this->GlobalGenerator->IncludeDirective << " " << root + << cmSystemTools::ConvertToOutputPath( + this->LocalGenerator + ->MaybeConvertToRelativePath( + this->LocalGenerator->GetBinaryDirectory(), + this->FlagFileNameFull) + .c_str()) << "\n\n"; } -//---------------------------------------------------------------------------- -std::string cmMakefileTargetGenerator::GetFlags(const std::string &l) -{ - ByLanguageMap::iterator i = this->FlagsByLanguage.find(l); - if (i == this->FlagsByLanguage.end()) - { - std::string flags; - const char *lang = l.c_str(); - - // Add language feature flags. - this->AddFeatureFlags(flags, lang); - - this->LocalGenerator->AddArchitectureFlags(flags, this->GeneratorTarget, - lang, this->ConfigName); - - // Fortran-specific flags computed for this target. - if(l == "Fortran") - { - this->AddFortranFlags(flags); - } - - this->LocalGenerator->AddCMP0018Flags(flags, this->Target, - lang, this->ConfigName); - - this->LocalGenerator->AddVisibilityPresetFlags(flags, this->Target, - lang); - - // Add include directory flags. - this->AddIncludeFlags(flags, lang); - - // Append old-style preprocessor definition flags. - this->LocalGenerator-> - AppendFlags(flags, this->Makefile->GetDefineFlags()); - - // Add include directory flags. - this->LocalGenerator-> - AppendFlags(flags,this->GetFrameworkFlags().c_str()); - - // Add target-specific flags. - this->LocalGenerator->AddCompileOptions(flags, this->Target, - lang, this->ConfigName); - - ByLanguageMap::value_type entry(l, flags); - i = this->FlagsByLanguage.insert(entry).first; - } - return i->second; -} - -std::string cmMakefileTargetGenerator::GetDefines(const std::string &l) -{ - ByLanguageMap::iterator i = this->DefinesByLanguage.find(l); - if (i == this->DefinesByLanguage.end()) - { - std::set<std::string> defines; - const char *lang = l.c_str(); - // Add the export symbol definition for shared library objects. - if(const char* exportMacro = this->Target->GetExportMacro()) - { - this->LocalGenerator->AppendDefines(defines, exportMacro); - } - - // Add preprocessor definitions for this target and configuration. - this->LocalGenerator->AddCompileDefinitions(defines, this->Target, - this->LocalGenerator->ConfigurationName.c_str()); - - std::string definesString; - this->LocalGenerator->JoinDefines(defines, definesString, lang); - - ByLanguageMap::value_type entry(l, definesString); - i = this->DefinesByLanguage.insert(entry).first; - } - return i->second; -} - void cmMakefileTargetGenerator::WriteTargetLanguageFlags() { // write language flags for target - std::set<cmStdString> languages; - this->Target->GetLanguages(languages); - // put the compiler in the rules.make file so that if it changes + std::set<std::string> languages; + this->GeneratorTarget->GetLanguages( + languages, this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE")); + // put the compiler in the rules.make file so that if it changes // things rebuild - for(std::set<cmStdString>::const_iterator l = languages.begin(); - l != languages.end(); ++l) - { - cmStdString compiler = "CMAKE_"; + for (std::set<std::string>::const_iterator l = languages.begin(); + l != languages.end(); ++l) { + std::string compiler = "CMAKE_"; compiler += *l; compiler += "_COMPILER"; - *this->FlagFileStream << "# compile " << l->c_str() << " with " << - this->Makefile->GetSafeDefinition(compiler.c_str()) << "\n"; - } + *this->FlagFileStream << "# compile " << *l << " with " + << this->Makefile->GetSafeDefinition(compiler) + << "\n"; + } - for(std::set<cmStdString>::const_iterator l = languages.begin(); - l != languages.end(); ++l) - { - *this->FlagFileStream << *l << "_FLAGS = " << this->GetFlags(*l) << "\n\n"; - *this->FlagFileStream << *l << "_DEFINES = " << this->GetDefines(*l) << - "\n\n"; - } + for (std::set<std::string>::const_iterator l = languages.begin(); + l != languages.end(); ++l) { + std::string flags = this->GetFlags(*l); + std::string defines = this->GetDefines(*l); + std::string includes = this->GetIncludes(*l); + // Escape comment characters so they do not terminate assignment. + cmSystemTools::ReplaceString(flags, "#", "\\#"); + cmSystemTools::ReplaceString(defines, "#", "\\#"); + cmSystemTools::ReplaceString(includes, "#", "\\#"); + *this->FlagFileStream << *l << "_FLAGS = " << flags << "\n\n"; + *this->FlagFileStream << *l << "_DEFINES = " << defines << "\n\n"; + *this->FlagFileStream << *l << "_INCLUDES = " << includes << "\n\n"; + } } - -//---------------------------------------------------------------------------- -void -cmMakefileTargetGenerator::MacOSXContentGeneratorType::operator() - (cmSourceFile& source, const char* pkgloc) +void cmMakefileTargetGenerator::MacOSXContentGeneratorType::operator()( + cmSourceFile const& source, const char* pkgloc) { // Skip OS X content when not building a Framework or Bundle. - if(!this->Generator->GetTarget()->IsBundleOnApple()) - { + if (!this->Generator->GetGeneratorTarget()->IsBundleOnApple()) { return; - } + } std::string macdir = this->Generator->OSXBundleGenerator->InitMacOSXContentDirectory(pkgloc); // Get the input file location. - std::string input = source.GetFullPath(); + std::string const& input = source.GetFullPath(); // Get the output file location. std::string output = macdir; output += "/"; output += cmSystemTools::GetFilenameName(input); this->Generator->CleanFiles.push_back( - this->Generator->Convert(output.c_str(), - cmLocalGenerator::START_OUTPUT)); - output = this->Generator->Convert(output.c_str(), - cmLocalGenerator::HOME_OUTPUT); + this->Generator->LocalGenerator->MaybeConvertToRelativePath( + this->Generator->LocalGenerator->GetCurrentBinaryDirectory(), output)); + output = this->Generator->LocalGenerator->MaybeConvertToRelativePath( + this->Generator->LocalGenerator->GetBinaryDirectory(), output); // Create a rule to copy the content into the bundle. std::vector<std::string> depends; @@ -382,131 +328,87 @@ cmMakefileTargetGenerator::MacOSXContentGeneratorType::operator() std::string copyEcho = "Copying OS X content "; copyEcho += output; this->Generator->LocalGenerator->AppendEcho( - commands, copyEcho.c_str(), - cmLocalUnixMakefileGenerator3::EchoBuild); + commands, copyEcho, cmLocalUnixMakefileGenerator3::EchoBuild); std::string copyCommand = "$(CMAKE_COMMAND) -E copy "; - copyCommand += this->Generator->Convert(input.c_str(), - cmLocalGenerator::NONE, - cmLocalGenerator::SHELL); + copyCommand += this->Generator->LocalGenerator->ConvertToOutputFormat( + input, cmOutputConverter::SHELL); copyCommand += " "; - copyCommand += this->Generator->Convert(output.c_str(), - cmLocalGenerator::NONE, - cmLocalGenerator::SHELL); + copyCommand += this->Generator->LocalGenerator->ConvertToOutputFormat( + output, cmOutputConverter::SHELL); commands.push_back(copyCommand); this->Generator->LocalGenerator->WriteMakeRule( - *this->Generator->BuildFileStream, 0, - output.c_str(), - depends, commands, false); + *this->Generator->BuildFileStream, CM_NULLPTR, output, depends, commands, + false); this->Generator->ExtraFiles.insert(output); } -//---------------------------------------------------------------------------- -void cmMakefileTargetGenerator::WriteObjectRuleFiles(cmSourceFile& source) +void cmMakefileTargetGenerator::WriteObjectRuleFiles( + cmSourceFile const& source) { // Identify the language of the source file. - const char* lang = this->LocalGenerator->GetSourceFileLanguage(source); - if(!lang) - { + const std::string& lang = + this->LocalGenerator->GetSourceFileLanguage(source); + if (lang.empty()) { // don't know anything about this file so skip it return; - } + } // Get the full path name of the object file. - std::string const& objectName = this->GeneratorTarget->Objects[&source]; - std::string obj = this->LocalGenerator->GetTargetDirectory(*this->Target); + std::string const& objectName = + this->GeneratorTarget->GetObjectName(&source); + std::string obj = + this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget); obj += "/"; obj += objectName; // Avoid generating duplicate rules. - if(this->ObjectFiles.find(obj) == this->ObjectFiles.end()) - { + if (this->ObjectFiles.find(obj) == this->ObjectFiles.end()) { this->ObjectFiles.insert(obj); - } - else - { - cmOStringStream err; - err << "Warning: Source file \"" - << source.GetFullPath() + } else { + std::ostringstream err; + err << "Warning: Source file \"" << source.GetFullPath() << "\" is listed multiple times for target \"" - << this->Target->GetName() - << "\"."; + << this->GeneratorTarget->GetName() << "\"."; cmSystemTools::Message(err.str().c_str(), "Warning"); return; - } + } // Create the directory containing the object file. This may be a // subdirectory under the target's directory. - std::string dir = cmSystemTools::GetFilenamePath(obj.c_str()); - cmSystemTools::MakeDirectory - (this->LocalGenerator->ConvertToFullPath(dir).c_str()); + std::string dir = cmSystemTools::GetFilenamePath(obj); + cmSystemTools::MakeDirectory( + this->LocalGenerator->ConvertToFullPath(dir).c_str()); // Save this in the target's list of object files. this->Objects.push_back(obj); this->CleanFiles.push_back(obj); // TODO: Remove - //std::string relativeObj + // std::string relativeObj //= this->LocalGenerator->GetHomeRelativeOutputPath(); - //relativeObj += obj; + // relativeObj += obj; // we compute some depends when writing the depend.make that we will also // use in the build.make, same with depMakeFile std::vector<std::string> depends; - std::string depMakeFile; // generate the build rule file this->WriteObjectBuildFile(obj, lang, source, depends); // The object file should be checked for dependency integrity. - std::string objFullPath = this->Makefile->GetCurrentOutputDirectory(); + std::string objFullPath = this->LocalGenerator->GetCurrentBinaryDirectory(); objFullPath += "/"; objFullPath += obj; - objFullPath = - this->Convert(objFullPath.c_str(), cmLocalGenerator::FULL); + objFullPath = cmSystemTools::CollapseFullPath(objFullPath); std::string srcFullPath = - this->Convert(source.GetFullPath().c_str(), cmLocalGenerator::FULL); - this->LocalGenerator-> - AddImplicitDepends(*this->Target, lang, - objFullPath.c_str(), - srcFullPath.c_str()); + cmSystemTools::CollapseFullPath(source.GetFullPath()); + this->LocalGenerator->AddImplicitDepends( + this->GeneratorTarget, lang, objFullPath.c_str(), srcFullPath.c_str()); } -//---------------------------------------------------------------------------- -void -cmMakefileTargetGenerator -::AppendFortranFormatFlags(std::string& flags, cmSourceFile& source) -{ - const char* srcfmt = source.GetProperty("Fortran_FORMAT"); - cmLocalGenerator::FortranFormat format = - this->LocalGenerator->GetFortranFormat(srcfmt); - if(format == cmLocalGenerator::FortranFormatNone) - { - const char* tgtfmt = this->Target->GetProperty("Fortran_FORMAT"); - format = this->LocalGenerator->GetFortranFormat(tgtfmt); - } - const char* var = 0; - switch (format) - { - case cmLocalGenerator::FortranFormatFixed: - var = "CMAKE_Fortran_FORMAT_FIXED_FLAG"; break; - case cmLocalGenerator::FortranFormatFree: - var = "CMAKE_Fortran_FORMAT_FREE_FLAG"; break; - default: break; - } - if(var) - { - this->LocalGenerator->AppendFlags( - flags, this->Makefile->GetDefinition(var)); - } -} - -//---------------------------------------------------------------------------- -void -cmMakefileTargetGenerator -::WriteObjectBuildFile(std::string &obj, - const char *lang, - cmSourceFile& source, - std::vector<std::string>& depends) +void cmMakefileTargetGenerator::WriteObjectBuildFile( + std::string& obj, const std::string& lang, cmSourceFile const& source, + std::vector<std::string>& depends) { this->LocalGenerator->AppendRuleDepend(depends, this->FlagFileNameFull.c_str()); @@ -527,122 +429,134 @@ cmMakefileTargetGenerator std::string langFlags = "$("; langFlags += lang; langFlags += "_FLAGS)"; - this->LocalGenerator->AppendFlags(flags, langFlags.c_str()); + this->LocalGenerator->AppendFlags(flags, langFlags); - std::string configUpper = - cmSystemTools::UpperCase(this->LocalGenerator->ConfigurationName); + std::string config = this->LocalGenerator->GetConfigName(); + std::string configUpper = cmSystemTools::UpperCase(config); // Add Fortran format flags. - if(strcmp(lang, "Fortran") == 0) - { + if (lang == "Fortran") { this->AppendFortranFormatFlags(flags, source); - } + } // Add flags from source file properties. - if (source.GetProperty("COMPILE_FLAGS")) - { - this->LocalGenerator->AppendFlags - (flags, source.GetProperty("COMPILE_FLAGS")); - *this->FlagFileStream << "# Custom flags: " - << relativeObj << "_FLAGS = " - << source.GetProperty("COMPILE_FLAGS") - << "\n" + if (const char* cflags = source.GetProperty("COMPILE_FLAGS")) { + cmGeneratorExpression ge; + CM_AUTO_PTR<cmCompiledGeneratorExpression> cge = ge.Parse(cflags); + const char* evaluatedFlags = cge->Evaluate(this->LocalGenerator, config, + false, this->GeneratorTarget); + this->LocalGenerator->AppendFlags(flags, evaluatedFlags); + *this->FlagFileStream << "# Custom flags: " << relativeObj + << "_FLAGS = " << evaluatedFlags << "\n" << "\n"; - } + } // Add language-specific defines. std::set<std::string> defines; // Add source-sepcific preprocessor definitions. - if(const char* compile_defs = source.GetProperty("COMPILE_DEFINITIONS")) - { + if (const char* compile_defs = source.GetProperty("COMPILE_DEFINITIONS")) { this->LocalGenerator->AppendDefines(defines, compile_defs); - *this->FlagFileStream << "# Custom defines: " - << relativeObj << "_DEFINES = " - << compile_defs << "\n" + *this->FlagFileStream << "# Custom defines: " << relativeObj + << "_DEFINES = " << compile_defs << "\n" << "\n"; - } + } std::string defPropName = "COMPILE_DEFINITIONS_"; defPropName += configUpper; - if(const char* config_compile_defs = - source.GetProperty(defPropName.c_str())) - { + if (const char* config_compile_defs = source.GetProperty(defPropName)) { this->LocalGenerator->AppendDefines(defines, config_compile_defs); - *this->FlagFileStream - << "# Custom defines: " - << relativeObj << "_DEFINES_" << configUpper - << " = " << config_compile_defs << "\n" - << "\n"; - } + *this->FlagFileStream << "# Custom defines: " << relativeObj << "_DEFINES_" + << configUpper << " = " << config_compile_defs + << "\n" + << "\n"; + } // Get the output paths for source and object files. - std::string sourceFile = source.GetFullPath(); - if(this->LocalGenerator->UseRelativePaths) - { - sourceFile = this->Convert(sourceFile.c_str(), - cmLocalGenerator::START_OUTPUT); - } - sourceFile = this->Convert(sourceFile.c_str(), - cmLocalGenerator::NONE, - cmLocalGenerator::SHELL); + std::string sourceFile = this->LocalGenerator->ConvertToOutputFormat( + source.GetFullPath(), cmOutputConverter::SHELL); // Construct the build message. std::vector<std::string> no_commands; std::vector<std::string> commands; // add in a progress call if needed - this->AppendProgress(commands); + this->NumberOfProgressActions++; - if(!this->NoRuleMessages) - { + if (!this->NoRuleMessages) { + cmLocalUnixMakefileGenerator3::EchoProgress progress; + this->MakeEchoProgress(progress); std::string buildEcho = "Building "; buildEcho += lang; buildEcho += " object "; buildEcho += relativeObj; - this->LocalGenerator->AppendEcho - (commands, buildEcho.c_str(), cmLocalUnixMakefileGenerator3::EchoBuild); - } + this->LocalGenerator->AppendEcho(commands, buildEcho, + cmLocalUnixMakefileGenerator3::EchoBuild, + &progress); + } std::string targetOutPathReal; std::string targetOutPathPDB; + std::string targetOutPathCompilePDB; { - std::string targetFullPathReal; - std::string targetFullPathPDB; - if(this->Target->GetType() == cmTarget::EXECUTABLE || - this->Target->GetType() == cmTarget::STATIC_LIBRARY || - this->Target->GetType() == cmTarget::SHARED_LIBRARY || - this->Target->GetType() == cmTarget::MODULE_LIBRARY) - { - targetFullPathReal = - this->Target->GetFullPath(this->ConfigName, false, true); - targetFullPathPDB = this->Target->GetPDBDirectory(this->ConfigName); - targetFullPathPDB += "/"; - targetFullPathPDB += this->Target->GetPDBName(this->ConfigName); + std::string targetFullPathReal; + std::string targetFullPathPDB; + std::string targetFullPathCompilePDB = this->ComputeTargetCompilePDB(); + if (this->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE || + this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY || + this->GeneratorTarget->GetType() == cmStateEnums::SHARED_LIBRARY || + this->GeneratorTarget->GetType() == cmStateEnums::MODULE_LIBRARY) { + targetFullPathReal = this->GeneratorTarget->GetFullPath( + this->ConfigName, cmStateEnums::RuntimeBinaryArtifact, true); + targetFullPathPDB = + this->GeneratorTarget->GetPDBDirectory(this->ConfigName); + targetFullPathPDB += "/"; + targetFullPathPDB += this->GeneratorTarget->GetPDBName(this->ConfigName); + } + + targetOutPathReal = this->LocalGenerator->ConvertToOutputFormat( + this->LocalGenerator->MaybeConvertToRelativePath( + this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPathReal), + cmOutputConverter::SHELL); + targetOutPathPDB = this->LocalGenerator->ConvertToOutputFormat( + targetFullPathPDB, cmOutputConverter::SHELL); + targetOutPathCompilePDB = this->LocalGenerator->ConvertToOutputFormat( + this->LocalGenerator->MaybeConvertToRelativePath( + this->LocalGenerator->GetCurrentBinaryDirectory(), + targetFullPathCompilePDB), + cmOutputConverter::SHELL); + + if (this->LocalGenerator->IsMinGWMake() && + cmHasLiteralSuffix(targetOutPathCompilePDB, "\\")) { + // mingw32-make incorrectly interprets 'a\ b c' as 'a b' and 'c' + // (but 'a\ b "c"' as 'a\', 'b', and 'c'!). Workaround this by + // avoiding a trailing backslash in the argument. + targetOutPathCompilePDB[targetOutPathCompilePDB.size() - 1] = '/'; } - targetOutPathReal = this->Convert(targetFullPathReal.c_str(), - cmLocalGenerator::START_OUTPUT, - cmLocalGenerator::SHELL); - targetOutPathPDB = - this->Convert(targetFullPathPDB.c_str(),cmLocalGenerator::NONE, - cmLocalGenerator::SHELL); - } - cmLocalGenerator::RuleVariables vars; - vars.RuleLauncher = "RULE_LAUNCH_COMPILE"; - vars.CMTarget = this->Target; - vars.Language = lang; + } + cmRulePlaceholderExpander::RuleVariables vars; + vars.CMTargetName = this->GeneratorTarget->GetName().c_str(); + vars.CMTargetType = + cmState::GetTargetTypeName(this->GeneratorTarget->GetType()); + vars.Language = lang.c_str(); vars.Target = targetOutPathReal.c_str(); vars.TargetPDB = targetOutPathPDB.c_str(); + vars.TargetCompilePDB = targetOutPathCompilePDB.c_str(); vars.Source = sourceFile.c_str(); std::string shellObj = - this->Convert(obj.c_str(), - cmLocalGenerator::NONE, - cmLocalGenerator::SHELL).c_str(); + this->LocalGenerator->ConvertToOutputFormat(obj, cmOutputConverter::SHELL); vars.Object = shellObj.c_str(); - std::string objectDir = this->Target->GetSupportDirectory(); - objectDir = this->Convert(objectDir.c_str(), - cmLocalGenerator::START_OUTPUT, - cmLocalGenerator::SHELL); + std::string objectDir = this->GeneratorTarget->GetSupportDirectory(); + objectDir = this->LocalGenerator->ConvertToOutputFormat( + this->LocalGenerator->MaybeConvertToRelativePath( + this->LocalGenerator->GetCurrentBinaryDirectory(), objectDir), + cmOutputConverter::SHELL); vars.ObjectDir = objectDir.c_str(); + std::string objectFileDir = cmSystemTools::GetFilenamePath(obj); + objectFileDir = this->LocalGenerator->ConvertToOutputFormat( + this->LocalGenerator->MaybeConvertToRelativePath( + this->LocalGenerator->GetCurrentBinaryDirectory(), objectFileDir), + cmOutputConverter::SHELL); + vars.ObjectFileDir = objectFileDir.c_str(); vars.Flags = flags.c_str(); std::string definesString = "$("; @@ -653,91 +567,165 @@ cmMakefileTargetGenerator vars.Defines = definesString.c_str(); - bool lang_is_c_or_cxx = ((strcmp(lang, "C") == 0) || - (strcmp(lang, "CXX") == 0)); + std::string const includesString = "$(" + lang + "_INCLUDES)"; + vars.Includes = includesString.c_str(); + + // At the moment, it is assumed that C, C++, Fortran, and CUDA have both + // assembly and preprocessor capabilities. The same is true for the + // ability to export compile commands + bool lang_has_preprocessor = ((lang == "C") || (lang == "CXX") || + (lang == "Fortran") || (lang == "CUDA")); + bool const lang_has_assembly = lang_has_preprocessor; + bool const lang_can_export_cmds = lang_has_preprocessor; + + CM_AUTO_PTR<cmRulePlaceholderExpander> rulePlaceholderExpander( + this->LocalGenerator->CreateRulePlaceholderExpander()); // Construct the compile rules. { - std::string compileRuleVar = "CMAKE_"; - compileRuleVar += lang; - compileRuleVar += "_COMPILE_OBJECT"; - std::string compileRule = - this->Makefile->GetRequiredDefinition(compileRuleVar.c_str()); - std::vector<std::string> compileCommands; - cmSystemTools::ExpandListArgument(compileRule, compileCommands); - - if (this->Makefile->IsOn("CMAKE_EXPORT_COMPILE_COMMANDS") && - lang_is_c_or_cxx && compileCommands.size() == 1) - { - std::string compileCommand = compileCommands[0]; - this->LocalGenerator->ExpandRuleVariables(compileCommand, vars); - std::string workingDirectory = - this->LocalGenerator->Convert( - this->Makefile->GetStartOutputDirectory(), cmLocalGenerator::FULL); - compileCommand.replace(compileCommand.find(langFlags), - langFlags.size(), this->GetFlags(lang)); - std::string langDefines = std::string("$(") + lang + "_DEFINES)"; - compileCommand.replace(compileCommand.find(langDefines), - langDefines.size(), this->GetDefines(lang)); - this->GlobalGenerator->AddCXXCompileCommand( - source.GetFullPath(), workingDirectory, compileCommand); + std::vector<std::string> compileCommands; + if (lang == "CUDA") { + std::string cmdVar; + if (this->GeneratorTarget->GetPropertyAsBool( + "CUDA_SEPARABLE_COMPILATION")) { + cmdVar = std::string("CMAKE_CUDA_COMPILE_SEPARABLE_COMPILATION"); + } else if (this->GeneratorTarget->GetPropertyAsBool( + "CUDA_PTX_COMPILATION")) { + cmdVar = std::string("CMAKE_CUDA_COMPILE_PTX_COMPILATION"); + } else { + cmdVar = std::string("CMAKE_CUDA_COMPILE_WHOLE_COMPILATION"); + } + std::string compileRule = this->Makefile->GetRequiredDefinition(cmdVar); + cmSystemTools::ExpandListArgument(compileRule, compileCommands); + } else { + const std::string cmdVar = + std::string("CMAKE_") + lang + "_COMPILE_OBJECT"; + std::string compileRule = this->Makefile->GetRequiredDefinition(cmdVar); + cmSystemTools::ExpandListArgument(compileRule, compileCommands); + } + + if (this->Makefile->IsOn("CMAKE_EXPORT_COMPILE_COMMANDS") && + lang_can_export_cmds && compileCommands.size() == 1) { + std::string compileCommand = compileCommands[0]; + + // no launcher for CMAKE_EXPORT_COMPILE_COMMANDS + rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator, + compileCommand, vars); + std::string workingDirectory = cmSystemTools::CollapseFullPath( + this->LocalGenerator->GetCurrentBinaryDirectory()); + compileCommand.replace(compileCommand.find(langFlags), langFlags.size(), + this->GetFlags(lang)); + std::string langDefines = std::string("$(") + lang + "_DEFINES)"; + compileCommand.replace(compileCommand.find(langDefines), + langDefines.size(), this->GetDefines(lang)); + std::string langIncludes = std::string("$(") + lang + "_INCLUDES)"; + compileCommand.replace(compileCommand.find(langIncludes), + langIncludes.size(), this->GetIncludes(lang)); + this->GlobalGenerator->AddCXXCompileCommand( + source.GetFullPath(), workingDirectory, compileCommand); + } + + // Maybe insert an include-what-you-use runner. + if (!compileCommands.empty() && (lang == "C" || lang == "CXX")) { + std::string const iwyu_prop = lang + "_INCLUDE_WHAT_YOU_USE"; + const char* iwyu = this->GeneratorTarget->GetProperty(iwyu_prop); + std::string const tidy_prop = lang + "_CLANG_TIDY"; + const char* tidy = this->GeneratorTarget->GetProperty(tidy_prop); + std::string const cpplint_prop = lang + "_CPPLINT"; + const char* cpplint = this->GeneratorTarget->GetProperty(cpplint_prop); + if ((iwyu && *iwyu) || (tidy && *tidy) || (cpplint && *cpplint)) { + std::string run_iwyu = "$(CMAKE_COMMAND) -E __run_iwyu"; + if (iwyu && *iwyu) { + run_iwyu += " --iwyu="; + run_iwyu += this->LocalGenerator->EscapeForShell(iwyu); + } + if (tidy && *tidy) { + run_iwyu += " --tidy="; + run_iwyu += this->LocalGenerator->EscapeForShell(tidy); + } + if (cpplint && *cpplint) { + run_iwyu += " --cpplint="; + run_iwyu += this->LocalGenerator->EscapeForShell(cpplint); + } + if ((tidy && *tidy) || (cpplint && *cpplint)) { + run_iwyu += " --source="; + run_iwyu += sourceFile; + } + run_iwyu += " -- "; + compileCommands.front().insert(0, run_iwyu); + } } - // Expand placeholders in the commands. - for(std::vector<std::string>::iterator i = compileCommands.begin(); - i != compileCommands.end(); ++i) + // Maybe insert a compiler launcher like ccache or distcc + if (!compileCommands.empty() && (lang == "C" || lang == "CXX")) { + std::string const clauncher_prop = lang + "_COMPILER_LAUNCHER"; + const char* clauncher = + this->GeneratorTarget->GetProperty(clauncher_prop); + if (clauncher && *clauncher) { + std::vector<std::string> launcher_cmd; + cmSystemTools::ExpandListArgument(clauncher, launcher_cmd, true); + for (std::vector<std::string>::iterator i = launcher_cmd.begin(), + e = launcher_cmd.end(); + i != e; ++i) { + *i = this->LocalGenerator->EscapeForShell(*i); + } + std::string const& run_launcher = cmJoin(launcher_cmd, " ") + " "; + compileCommands.front().insert(0, run_launcher); + } + } + + std::string launcher; { - this->LocalGenerator->ExpandRuleVariables(*i, vars); + const char* val = this->LocalGenerator->GetRuleLauncher( + this->GeneratorTarget, "RULE_LAUNCH_COMPILE"); + if (val && *val) { + launcher = val; + launcher += " "; + } } - // Change the command working directory to the local build tree. - this->LocalGenerator->CreateCDCommand - (compileCommands, - this->Makefile->GetStartOutputDirectory(), - cmLocalGenerator::HOME_OUTPUT); - commands.insert(commands.end(), - compileCommands.begin(), compileCommands.end()); - } + // Expand placeholders in the commands. + for (std::vector<std::string>::iterator i = compileCommands.begin(); + i != compileCommands.end(); ++i) { + *i = launcher + *i; + rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator, *i, + vars); + } - // Write the rule. - this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0, - relativeObj.c_str(), - depends, commands, false); + // Change the command working directory to the local build tree. + this->LocalGenerator->CreateCDCommand( + compileCommands, this->LocalGenerator->GetCurrentBinaryDirectory(), + this->LocalGenerator->GetBinaryDirectory()); + commands.insert(commands.end(), compileCommands.begin(), + compileCommands.end()); + } // Check for extra outputs created by the compilation. - if(const char* extra_outputs_str = - source.GetProperty("OBJECT_OUTPUTS")) - { - std::vector<std::string> extra_outputs; - cmSystemTools::ExpandListArgument(extra_outputs_str, extra_outputs); - for(std::vector<std::string>::const_iterator eoi = extra_outputs.begin(); - eoi != extra_outputs.end(); ++eoi) - { - // Register this as an extra output for the object file rule. - // This will cause the object file to be rebuilt if the extra - // output is missing. - this->GenerateExtraOutput(eoi->c_str(), relativeObj.c_str(), false); - - // Register this as an extra file to clean. - this->CleanFiles.push_back(eoi->c_str()); - } - } + std::vector<std::string> outputs(1, relativeObj); + if (const char* extra_outputs_str = source.GetProperty("OBJECT_OUTPUTS")) { + // Register these as extra files to clean. + cmSystemTools::ExpandListArgument(extra_outputs_str, outputs); + this->CleanFiles.insert(this->CleanFiles.end(), outputs.begin() + 1, + outputs.end()); + } + + // Write the rule. + this->WriteMakeRule(*this->BuildFileStream, CM_NULLPTR, outputs, depends, + commands); - bool do_preprocess_rules = lang_is_c_or_cxx && + bool do_preprocess_rules = lang_has_preprocessor && this->LocalGenerator->GetCreatePreprocessedSourceRules(); - bool do_assembly_rules = lang_is_c_or_cxx && - this->LocalGenerator->GetCreateAssemblySourceRules(); - if(do_preprocess_rules || do_assembly_rules) - { + bool do_assembly_rules = + lang_has_assembly && this->LocalGenerator->GetCreateAssemblySourceRules(); + if (do_preprocess_rules || do_assembly_rules) { std::vector<std::string> force_depends; force_depends.push_back("cmake_force"); - std::string::size_type dot_pos = relativeObj.rfind("."); + std::string::size_type dot_pos = relativeObj.rfind('.'); std::string relativeObjBase = relativeObj.substr(0, dot_pos); - dot_pos = obj.rfind("."); + dot_pos = obj.rfind('.'); std::string objBase = obj.substr(0, dot_pos); - if(do_preprocess_rules) - { + if (do_preprocess_rules) { commands.clear(); std::string relativeObjI = relativeObjBase + ".i"; std::string objI = objBase + ".i"; @@ -747,54 +735,46 @@ cmMakefileTargetGenerator preprocessEcho += " source to "; preprocessEcho += objI; this->LocalGenerator->AppendEcho( - commands, preprocessEcho.c_str(), - cmLocalUnixMakefileGenerator3::EchoBuild - ); + commands, preprocessEcho, cmLocalUnixMakefileGenerator3::EchoBuild); std::string preprocessRuleVar = "CMAKE_"; preprocessRuleVar += lang; preprocessRuleVar += "_CREATE_PREPROCESSED_SOURCE"; - if(const char* preprocessRule = - this->Makefile->GetDefinition(preprocessRuleVar.c_str())) - { + if (const char* preprocessRule = + this->Makefile->GetDefinition(preprocessRuleVar)) { std::vector<std::string> preprocessCommands; cmSystemTools::ExpandListArgument(preprocessRule, preprocessCommands); - std::string shellObjI = - this->Convert(objI.c_str(), - cmLocalGenerator::NONE, - cmLocalGenerator::SHELL).c_str(); + std::string shellObjI = this->LocalGenerator->ConvertToOutputFormat( + objI, cmOutputConverter::SHELL); vars.PreprocessedSource = shellObjI.c_str(); // Expand placeholders in the commands. - for(std::vector<std::string>::iterator i = preprocessCommands.begin(); - i != preprocessCommands.end(); ++i) - { - this->LocalGenerator->ExpandRuleVariables(*i, vars); - } - - this->LocalGenerator->CreateCDCommand - (preprocessCommands, - this->Makefile->GetStartOutputDirectory(), - cmLocalGenerator::HOME_OUTPUT); - commands.insert(commands.end(), - preprocessCommands.begin(), - preprocessCommands.end()); + for (std::vector<std::string>::iterator i = preprocessCommands.begin(); + i != preprocessCommands.end(); ++i) { + // no launcher for preprocessor commands + rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator, + *i, vars); } - else - { + + this->LocalGenerator->CreateCDCommand( + preprocessCommands, + this->LocalGenerator->GetCurrentBinaryDirectory(), + this->LocalGenerator->GetBinaryDirectory()); + commands.insert(commands.end(), preprocessCommands.begin(), + preprocessCommands.end()); + } else { std::string cmd = "$(CMAKE_COMMAND) -E cmake_unimplemented_variable "; cmd += preprocessRuleVar; commands.push_back(cmd); - } - - this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0, - relativeObjI.c_str(), - force_depends, commands, false); } - if(do_assembly_rules) - { + this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, CM_NULLPTR, + relativeObjI, force_depends, + commands, false); + } + + if (do_assembly_rules) { commands.clear(); std::string relativeObjS = relativeObjBase + ".s"; std::string objS = objBase + ".s"; @@ -804,52 +784,44 @@ cmMakefileTargetGenerator assemblyEcho += " source to assembly "; assemblyEcho += objS; this->LocalGenerator->AppendEcho( - commands, assemblyEcho.c_str(), - cmLocalUnixMakefileGenerator3::EchoBuild - ); + commands, assemblyEcho, cmLocalUnixMakefileGenerator3::EchoBuild); std::string assemblyRuleVar = "CMAKE_"; assemblyRuleVar += lang; assemblyRuleVar += "_CREATE_ASSEMBLY_SOURCE"; - if(const char* assemblyRule = - this->Makefile->GetDefinition(assemblyRuleVar.c_str())) - { + if (const char* assemblyRule = + this->Makefile->GetDefinition(assemblyRuleVar)) { std::vector<std::string> assemblyCommands; cmSystemTools::ExpandListArgument(assemblyRule, assemblyCommands); - std::string shellObjS = - this->Convert(objS.c_str(), - cmLocalGenerator::NONE, - cmLocalGenerator::SHELL).c_str(); + std::string shellObjS = this->LocalGenerator->ConvertToOutputFormat( + objS, cmOutputConverter::SHELL); vars.AssemblySource = shellObjS.c_str(); // Expand placeholders in the commands. - for(std::vector<std::string>::iterator i = assemblyCommands.begin(); - i != assemblyCommands.end(); ++i) - { - this->LocalGenerator->ExpandRuleVariables(*i, vars); - } - - this->LocalGenerator->CreateCDCommand - (assemblyCommands, - this->Makefile->GetStartOutputDirectory(), - cmLocalGenerator::HOME_OUTPUT); - commands.insert(commands.end(), - assemblyCommands.begin(), - assemblyCommands.end()); + for (std::vector<std::string>::iterator i = assemblyCommands.begin(); + i != assemblyCommands.end(); ++i) { + // no launcher for assembly commands + rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator, + *i, vars); } - else - { + + this->LocalGenerator->CreateCDCommand( + assemblyCommands, this->LocalGenerator->GetCurrentBinaryDirectory(), + this->LocalGenerator->GetBinaryDirectory()); + commands.insert(commands.end(), assemblyCommands.begin(), + assemblyCommands.end()); + } else { std::string cmd = "$(CMAKE_COMMAND) -E cmake_unimplemented_variable "; cmd += assemblyRuleVar; commands.push_back(cmd); - } - - this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0, - relativeObjS.c_str(), - force_depends, commands, false); } + + this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, CM_NULLPTR, + relativeObjS, force_depends, + commands, false); } + } // If the language needs provides-requires mode, create the // corresponding targets. @@ -857,9 +829,9 @@ cmMakefileTargetGenerator objectRequires += ".requires"; std::vector<std::string> p_depends; // always provide an empty requires target - this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0, - objectRequires.c_str(), p_depends, - no_commands, true); + this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, CM_NULLPTR, + objectRequires, p_depends, no_commands, + true); // write a build rule to recursively build what this obj provides std::string objectProvides = relativeObj; @@ -868,27 +840,24 @@ cmMakefileTargetGenerator temp += ".provides.build"; std::vector<std::string> r_commands; std::string tgtMakefileName = - this->LocalGenerator->GetRelativeTargetDirectory(*this->Target); + this->LocalGenerator->GetRelativeTargetDirectory(this->GeneratorTarget); tgtMakefileName += "/build.make"; - r_commands.push_back - (this->LocalGenerator->GetRecursiveMakeCall(tgtMakefileName.c_str(), - temp.c_str())); + r_commands.push_back( + this->LocalGenerator->GetRecursiveMakeCall(tgtMakefileName.c_str(), temp)); p_depends.clear(); p_depends.push_back(objectRequires); - this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0, - objectProvides.c_str(), p_depends, - r_commands, true); + this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, CM_NULLPTR, + objectProvides, p_depends, r_commands, + true); // write the provides.build rule dependency on the obj file p_depends.clear(); p_depends.push_back(relativeObj); - this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0, - temp.c_str(), p_depends, no_commands, - false); + this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, CM_NULLPTR, temp, + p_depends, no_commands, false); } -//---------------------------------------------------------------------------- void cmMakefileTargetGenerator::WriteTargetRequiresRules() { std::vector<std::string> depends; @@ -896,28 +865,25 @@ void cmMakefileTargetGenerator::WriteTargetRequiresRules() // Construct the name of the dependency generation target. std::string depTarget = - this->LocalGenerator->GetRelativeTargetDirectory(*this->Target); + this->LocalGenerator->GetRelativeTargetDirectory(this->GeneratorTarget); depTarget += "/requires"; // This target drives dependency generation for all object files. std::string relPath = this->LocalGenerator->GetHomeRelativeOutputPath(); std::string objTarget; - for(std::vector<std::string>::const_iterator obj = this->Objects.begin(); - obj != this->Objects.end(); ++obj) - { + for (std::vector<std::string>::const_iterator obj = this->Objects.begin(); + obj != this->Objects.end(); ++obj) { objTarget = relPath; objTarget += *obj; objTarget += ".requires"; depends.push_back(objTarget); - } + } // Write the rule. - this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0, - depTarget.c_str(), - depends, no_commands, true); + this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, CM_NULLPTR, + depTarget, depends, no_commands, true); } -//---------------------------------------------------------------------------- void cmMakefileTargetGenerator::WriteTargetCleanRules() { std::vector<std::string> depends; @@ -925,29 +891,92 @@ void cmMakefileTargetGenerator::WriteTargetCleanRules() // Construct the clean target name. std::string cleanTarget = - this->LocalGenerator->GetRelativeTargetDirectory(*this->Target); + this->LocalGenerator->GetRelativeTargetDirectory(this->GeneratorTarget); cleanTarget += "/clean"; // Construct the clean command. this->LocalGenerator->AppendCleanCommand(commands, this->CleanFiles, - *this->Target); - this->LocalGenerator->CreateCDCommand - (commands, - this->Makefile->GetStartOutputDirectory(), - cmLocalGenerator::HOME_OUTPUT); + this->GeneratorTarget); + this->LocalGenerator->CreateCDCommand( + commands, this->LocalGenerator->GetCurrentBinaryDirectory(), + this->LocalGenerator->GetBinaryDirectory()); // Write the rule. - this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0, - cleanTarget.c_str(), - depends, commands, true); + this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, CM_NULLPTR, + cleanTarget, depends, commands, true); } +bool cmMakefileTargetGenerator::WriteMakeRule( + std::ostream& os, const char* comment, + const std::vector<std::string>& outputs, + const std::vector<std::string>& depends, + const std::vector<std::string>& commands, bool in_help) +{ + bool symbolic = false; + if (outputs.empty()) { + return symbolic; + } + + // Check whether we need to bother checking for a symbolic output. + bool need_symbolic = this->GlobalGenerator->GetNeedSymbolicMark(); + + // Check whether the first output is marked as symbolic. + if (need_symbolic) { + if (cmSourceFile* sf = this->Makefile->GetSource(outputs[0])) { + symbolic = sf->GetPropertyAsBool("SYMBOLIC"); + } + } + + // We always attach the actual commands to the first output. + this->LocalGenerator->WriteMakeRule(os, comment, outputs[0], depends, + commands, symbolic, in_help); + + // For single outputs, we are done. + if (outputs.size() == 1) { + return symbolic; + } + + // For multiple outputs, make the extra ones depend on the first one. + std::vector<std::string> const output_depends(1, outputs[0]); + std::string binDir = this->LocalGenerator->GetBinaryDirectory(); + for (std::vector<std::string>::const_iterator o = outputs.begin() + 1; + o != outputs.end(); ++o) { + // Touch the extra output so "make" knows that it was updated, + // but only if the output was acually created. + std::string const out = this->LocalGenerator->ConvertToOutputFormat( + this->LocalGenerator->MaybeConvertToRelativePath(binDir, *o), + cmOutputConverter::SHELL); + std::vector<std::string> output_commands; + + bool o_symbolic = false; + if (need_symbolic) { + if (cmSourceFile* sf = this->Makefile->GetSource(*o)) { + o_symbolic = sf->GetPropertyAsBool("SYMBOLIC"); + } + } + symbolic = symbolic && o_symbolic; + + if (!o_symbolic) { + output_commands.push_back("@$(CMAKE_COMMAND) -E touch_nocreate " + out); + } + this->LocalGenerator->WriteMakeRule(os, CM_NULLPTR, *o, output_depends, + output_commands, o_symbolic, in_help); + + if (!o_symbolic) { + // At build time, remove the first output if this one does not exist + // so that "make" will rerun the real commands that create this one. + MultipleOutputPairsType::value_type p(*o, outputs[0]); + this->MultipleOutputPairs.insert(p); + } + } + return symbolic; +} -//---------------------------------------------------------------------------- void cmMakefileTargetGenerator::WriteTargetDependRules() { // must write the targets depend info file - std::string dir = this->LocalGenerator->GetTargetDirectory(*this->Target); + std::string dir = + this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget); this->InfoFileNameFull = dir; this->InfoFileNameFull += "/DependInfo.cmake"; this->InfoFileNameFull = @@ -955,104 +984,57 @@ void cmMakefileTargetGenerator::WriteTargetDependRules() this->InfoFileStream = new cmGeneratedFileStream(this->InfoFileNameFull.c_str()); this->InfoFileStream->SetCopyIfDifferent(true); - if(!*this->InfoFileStream) - { + if (!*this->InfoFileStream) { return; - } - this->LocalGenerator-> - WriteDependLanguageInfo(*this->InfoFileStream,*this->Target); + } + this->LocalGenerator->WriteDependLanguageInfo(*this->InfoFileStream, + this->GeneratorTarget); // Store multiple output pairs in the depend info file. - if(!this->MultipleOutputPairs.empty()) - { + if (!this->MultipleOutputPairs.empty()) { + /* clang-format off */ *this->InfoFileStream << "\n" << "# Pairs of files generated by the same build rule.\n" - << "SET(CMAKE_MULTIPLE_OUTPUT_PAIRS\n"; - for(MultipleOutputPairsType::const_iterator pi = - this->MultipleOutputPairs.begin(); - pi != this->MultipleOutputPairs.end(); ++pi) - { + << "set(CMAKE_MULTIPLE_OUTPUT_PAIRS\n"; + /* clang-format on */ + for (MultipleOutputPairsType::const_iterator pi = + this->MultipleOutputPairs.begin(); + pi != this->MultipleOutputPairs.end(); ++pi) { *this->InfoFileStream - << " " << this->LocalGenerator->EscapeForCMake(pi->first.c_str()) - << " " << this->LocalGenerator->EscapeForCMake(pi->second.c_str()) - << "\n"; - } - *this->InfoFileStream << " )\n\n"; + << " " << cmOutputConverter::EscapeForCMake(pi->first) << " " + << cmOutputConverter::EscapeForCMake(pi->second) << "\n"; } + *this->InfoFileStream << " )\n\n"; + } // Store list of targets linked directly or transitively. { + /* clang-format off */ *this->InfoFileStream << "\n" << "# Targets to which this target links.\n" - << "SET(CMAKE_TARGET_LINKED_INFO_FILES\n"; - std::set<cmTarget const*> emitted; - const char* cfg = this->LocalGenerator->ConfigurationName.c_str(); - if(cmComputeLinkInformation* cli = this->Target->GetLinkInformation(cfg)) - { - cmComputeLinkInformation::ItemVector const& items = cli->GetItems(); - for(cmComputeLinkInformation::ItemVector::const_iterator - i = items.begin(); i != items.end(); ++i) - { - cmTarget const* linkee = i->Target; - if(linkee && !linkee->IsImported() && emitted.insert(linkee).second) - { - cmMakefile* mf = linkee->GetMakefile(); - cmLocalGenerator* lg = mf->GetLocalGenerator(); - std::string di = mf->GetStartOutputDirectory(); - di += "/"; - di += lg->GetTargetDirectory(*linkee); - di += "/DependInfo.cmake"; - *this->InfoFileStream << " \"" << di << "\"\n"; - } - } - } - *this->InfoFileStream - << " )\n"; + << "set(CMAKE_TARGET_LINKED_INFO_FILES\n"; + /* clang-format on */ + std::vector<std::string> dirs = this->GetLinkedTargetDirectories(); + for (std::vector<std::string>::iterator i = dirs.begin(); i != dirs.end(); + ++i) { + *this->InfoFileStream << " \"" << *i << "/DependInfo.cmake\"\n"; + } + *this->InfoFileStream << " )\n"; } - // Check for a target-specific module output directory. - if(const char* mdir = this->GetFortranModuleDirectory()) - { - *this->InfoFileStream - << "\n" - << "# Fortran module output directory.\n" - << "SET(CMAKE_Fortran_TARGET_MODULE_DIR \"" << mdir << "\")\n"; - } + std::string const& working_dir = + this->LocalGenerator->GetCurrentBinaryDirectory(); - // Target-specific include directories: + /* clang-format off */ *this->InfoFileStream << "\n" - << "# The include file search paths:\n"; - *this->InfoFileStream - << "SET(CMAKE_C_TARGET_INCLUDE_PATH\n"; - std::vector<std::string> includes; - - const char *config = this->Makefile->GetDefinition("CMAKE_BUILD_TYPE"); - this->LocalGenerator->GetIncludeDirectories(includes, - this->GeneratorTarget, - "C", config); - for(std::vector<std::string>::iterator i = includes.begin(); - i != includes.end(); ++i) - { - *this->InfoFileStream - << " \"" - << this->LocalGenerator->Convert(i->c_str(), - cmLocalGenerator::HOME_OUTPUT) - << "\"\n"; - } - *this->InfoFileStream - << " )\n"; - *this->InfoFileStream - << "SET(CMAKE_CXX_TARGET_INCLUDE_PATH " - << "${CMAKE_C_TARGET_INCLUDE_PATH})\n"; - *this->InfoFileStream - << "SET(CMAKE_Fortran_TARGET_INCLUDE_PATH " - << "${CMAKE_C_TARGET_INCLUDE_PATH})\n"; - *this->InfoFileStream - << "SET(CMAKE_ASM_TARGET_INCLUDE_PATH " - << "${CMAKE_C_TARGET_INCLUDE_PATH})\n"; + << "# Fortran module output directory.\n" + << "set(CMAKE_Fortran_TARGET_MODULE_DIR \"" + << this->GeneratorTarget->GetFortranModuleDirectory(working_dir) + << "\")\n"; + /* clang-format on */ // and now write the rule to use it std::vector<std::string> depends; @@ -1060,23 +1042,23 @@ void cmMakefileTargetGenerator::WriteTargetDependRules() // Construct the name of the dependency generation target. std::string depTarget = - this->LocalGenerator->GetRelativeTargetDirectory(*this->Target); + this->LocalGenerator->GetRelativeTargetDirectory(this->GeneratorTarget); depTarget += "/depend"; // Add a command to call CMake to scan dependencies. CMake will // touch the corresponding depends file after scanning dependencies. - cmOStringStream depCmd; - // TODO: Account for source file properties and directory-level - // definitions when scanning for dependencies. + std::ostringstream depCmd; +// TODO: Account for source file properties and directory-level +// definitions when scanning for dependencies. #if !defined(_WIN32) || defined(__CYGWIN__) // This platform supports symlinks, so cmSystemTools will translate // paths. Make sure PWD is set to the original name of the home // output directory to help cmSystemTools to create the same // translation table for the dependency scanning process. - depCmd << "cd " - << (this->LocalGenerator->Convert( - this->Makefile->GetHomeOutputDirectory(), - cmLocalGenerator::FULL, cmLocalGenerator::SHELL)) + depCmd << "cd " << (this->LocalGenerator->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath( + this->LocalGenerator->GetBinaryDirectory()), + cmOutputConverter::SHELL)) << " && "; #endif // Generate a call this signature: @@ -1090,325 +1072,212 @@ void cmMakefileTargetGenerator::WriteTargetDependRules() // the state of our local generator sufficiently for its needs. depCmd << "$(CMAKE_COMMAND) -E cmake_depends \"" << this->GlobalGenerator->GetName() << "\" " - << this->Convert(this->Makefile->GetHomeDirectory(), - cmLocalGenerator::FULL, cmLocalGenerator::SHELL) + << this->LocalGenerator->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath( + this->LocalGenerator->GetSourceDirectory()), + cmOutputConverter::SHELL) << " " - << this->Convert(this->Makefile->GetStartDirectory(), - cmLocalGenerator::FULL, cmLocalGenerator::SHELL) + << this->LocalGenerator->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath( + this->LocalGenerator->GetCurrentSourceDirectory()), + cmOutputConverter::SHELL) << " " - << this->Convert(this->Makefile->GetHomeOutputDirectory(), - cmLocalGenerator::FULL, cmLocalGenerator::SHELL) + << this->LocalGenerator->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath( + this->LocalGenerator->GetBinaryDirectory()), + cmOutputConverter::SHELL) << " " - << this->Convert(this->Makefile->GetStartOutputDirectory(), - cmLocalGenerator::FULL, cmLocalGenerator::SHELL) + << this->LocalGenerator->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath( + this->LocalGenerator->GetCurrentBinaryDirectory()), + cmOutputConverter::SHELL) << " " - << this->Convert(this->InfoFileNameFull.c_str(), - cmLocalGenerator::FULL, cmLocalGenerator::SHELL); - if(this->LocalGenerator->GetColorMakefile()) - { + << this->LocalGenerator->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(this->InfoFileNameFull), + cmOutputConverter::SHELL); + if (this->LocalGenerator->GetColorMakefile()) { depCmd << " --color=$(COLOR)"; - } + } commands.push_back(depCmd.str()); // Make sure all custom command outputs in this target are built. - if(this->CustomCommandDriver == OnDepends) - { + if (this->CustomCommandDriver == OnDepends) { this->DriveCustomCommands(depends); - } + } // Write the rule. - this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0, - depTarget.c_str(), - depends, commands, true); + this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, CM_NULLPTR, + depTarget, depends, commands, true); } -//---------------------------------------------------------------------------- -void -cmMakefileTargetGenerator -::DriveCustomCommands(std::vector<std::string>& depends) +void cmMakefileTargetGenerator::DriveCustomCommands( + std::vector<std::string>& depends) { // Depend on all custom command outputs. - const std::vector<cmSourceFile*>& sources = - this->Target->GetSourceFiles(); - for(std::vector<cmSourceFile*>::const_iterator source = sources.begin(); - source != sources.end(); ++source) - { - if(cmCustomCommand* cc = (*source)->GetCustomCommand()) - { - const std::vector<std::string>& outputs = cc->GetOutputs(); - for(std::vector<std::string>::const_iterator o = outputs.begin(); - o != outputs.end(); ++o) - { - depends.push_back(*o); - } - } + std::vector<cmSourceFile*> sources; + this->GeneratorTarget->GetSourceFiles( + sources, this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE")); + for (std::vector<cmSourceFile*>::const_iterator source = sources.begin(); + source != sources.end(); ++source) { + if (cmCustomCommand* cc = (*source)->GetCustomCommand()) { + cmCustomCommandGenerator ccg(*cc, this->ConfigName, + this->LocalGenerator); + const std::vector<std::string>& outputs = ccg.GetOutputs(); + depends.insert(depends.end(), outputs.begin(), outputs.end()); } + } } -//---------------------------------------------------------------------------- -void cmMakefileTargetGenerator -::WriteObjectDependRules(cmSourceFile& source, - std::vector<std::string>& depends) +void cmMakefileTargetGenerator::WriteObjectDependRules( + cmSourceFile const& source, std::vector<std::string>& depends) { // Create the list of dependencies known at cmake time. These are // shared between the object file and dependency scanning rule. depends.push_back(source.GetFullPath()); - if(const char* objectDeps = source.GetProperty("OBJECT_DEPENDS")) - { - std::vector<std::string> deps; - cmSystemTools::ExpandListArgument(objectDeps, deps); - for(std::vector<std::string>::iterator i = deps.begin(); - i != deps.end(); ++i) - { - depends.push_back(i->c_str()); - } - } + if (const char* objectDeps = source.GetProperty("OBJECT_DEPENDS")) { + cmSystemTools::ExpandListArgument(objectDeps, depends); + } } -//---------------------------------------------------------------------------- -void cmMakefileTargetGenerator -::GenerateCustomRuleFile(const cmCustomCommand& cc) +void cmMakefileTargetGenerator::GenerateCustomRuleFile( + cmCustomCommandGenerator const& ccg) { // Collect the commands. std::vector<std::string> commands; - std::string comment = this->LocalGenerator->ConstructComment(cc); - if(!comment.empty()) - { + std::string comment = this->LocalGenerator->ConstructComment(ccg); + if (!comment.empty()) { // add in a progress call if needed - this->AppendProgress(commands); - if(!this->NoRuleMessages) - { - this->LocalGenerator - ->AppendEcho(commands, comment.c_str(), - cmLocalUnixMakefileGenerator3::EchoGenerate); - } + this->NumberOfProgressActions++; + if (!this->NoRuleMessages) { + cmLocalUnixMakefileGenerator3::EchoProgress progress; + this->MakeEchoProgress(progress); + this->LocalGenerator->AppendEcho( + commands, comment, cmLocalUnixMakefileGenerator3::EchoGenerate, + &progress); } + } // Now append the actual user-specified commands. - cmOStringStream content; - this->LocalGenerator->AppendCustomCommand(commands, cc, this->Target, false, - cmLocalGenerator::HOME_OUTPUT, - &content); + std::ostringstream content; + this->LocalGenerator->AppendCustomCommand( + commands, ccg, this->GeneratorTarget, + this->LocalGenerator->GetBinaryDirectory(), false, &content); // Collect the dependencies. std::vector<std::string> depends; - this->LocalGenerator->AppendCustomDepend(depends, cc); - - // Check whether we need to bother checking for a symbolic output. - bool need_symbolic = this->GlobalGenerator->GetNeedSymbolicMark(); + this->LocalGenerator->AppendCustomDepend(depends, ccg); // Write the rule. - const std::vector<std::string>& outputs = cc.GetOutputs(); - std::vector<std::string>::const_iterator o = outputs.begin(); - { - bool symbolic = false; - if(need_symbolic) - { - if(cmSourceFile* sf = this->Makefile->GetSource(o->c_str())) - { - symbolic = sf->GetPropertyAsBool("SYMBOLIC"); - } - } - this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0, - o->c_str(), depends, commands, - symbolic); + const std::vector<std::string>& outputs = ccg.GetOutputs(); + bool symbolic = this->WriteMakeRule(*this->BuildFileStream, CM_NULLPTR, + outputs, depends, commands); // If the rule has changed make sure the output is rebuilt. - if(!symbolic) - { - this->GlobalGenerator->AddRuleHash(cc.GetOutputs(), content.str()); - } + if (!symbolic) { + this->GlobalGenerator->AddRuleHash(ccg.GetOutputs(), content.str()); } - // Write rules to drive building any outputs beyond the first. - const char* in = o->c_str(); - for(++o; o != outputs.end(); ++o) - { - bool symbolic = false; - if(need_symbolic) - { - if(cmSourceFile* sf = this->Makefile->GetSource(o->c_str())) - { - symbolic = sf->GetPropertyAsBool("SYMBOLIC"); - } - } - this->GenerateExtraOutput(o->c_str(), in, symbolic); - } - // Setup implicit dependency scanning. - for(cmCustomCommand::ImplicitDependsList::const_iterator - idi = cc.GetImplicitDepends().begin(); - idi != cc.GetImplicitDepends().end(); ++idi) - { - std::string objFullPath = - this->Convert(outputs[0].c_str(), cmLocalGenerator::FULL); - std::string srcFullPath = - this->Convert(idi->second.c_str(), cmLocalGenerator::FULL); - this->LocalGenerator-> - AddImplicitDepends(*this->Target, idi->first.c_str(), - objFullPath.c_str(), - srcFullPath.c_str()); - } -} - -//---------------------------------------------------------------------------- -void -cmMakefileTargetGenerator -::GenerateExtraOutput(const char* out, const char* in, bool symbolic) -{ - // Add a rule to build the primary output if the extra output needs - // to be created. - std::vector<std::string> commands; - std::vector<std::string> depends; - std::string emptyCommand = this->GlobalGenerator->GetEmptyRuleHackCommand(); - if(!emptyCommand.empty()) - { - commands.push_back(emptyCommand); - } - depends.push_back(in); - this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0, - out, depends, commands, - symbolic); - - // Register the extra output as paired with the first output so that - // the check-build-system step will remove the primary output if any - // extra outputs are missing. This forces the rule to regenerate - // all outputs. - this->AddMultipleOutputPair(out, in); + for (cmCustomCommand::ImplicitDependsList::const_iterator idi = + ccg.GetCC().GetImplicitDepends().begin(); + idi != ccg.GetCC().GetImplicitDepends().end(); ++idi) { + std::string objFullPath = cmSystemTools::CollapseFullPath(outputs[0]); + std::string srcFullPath = cmSystemTools::CollapseFullPath(idi->second); + this->LocalGenerator->AddImplicitDepends(this->GeneratorTarget, idi->first, + objFullPath.c_str(), + srcFullPath.c_str()); + } } -//---------------------------------------------------------------------------- -void -cmMakefileTargetGenerator::AppendProgress(std::vector<std::string>& commands) +void cmMakefileTargetGenerator::MakeEchoProgress( + cmLocalUnixMakefileGenerator3::EchoProgress& progress) const { - this->NumberOfProgressActions++; - if(this->NoRuleMessages) - { - return; - } - std::string progressDir = this->Makefile->GetHomeOutputDirectory(); - progressDir += cmake::GetCMakeFilesDirectory(); - cmOStringStream progCmd; - progCmd << "$(CMAKE_COMMAND) -E cmake_progress_report "; - progCmd << this->LocalGenerator->Convert(progressDir.c_str(), - cmLocalGenerator::FULL, - cmLocalGenerator::SHELL); - progCmd << " $(CMAKE_PROGRESS_" << this->NumberOfProgressActions << ")"; - commands.push_back(progCmd.str()); + progress.Dir = this->LocalGenerator->GetBinaryDirectory(); + progress.Dir += cmake::GetCMakeFilesDirectory(); + std::ostringstream progressArg; + progressArg << "$(CMAKE_PROGRESS_" << this->NumberOfProgressActions << ")"; + progress.Arg = progressArg.str(); } -//---------------------------------------------------------------------------- -void -cmMakefileTargetGenerator -::WriteObjectsVariable(std::string& variableName, - std::string& variableNameExternal) +void cmMakefileTargetGenerator::WriteObjectsVariable( + std::string& variableName, std::string& variableNameExternal, + bool useWatcomQuote) { // Write a make variable assignment that lists all objects for the // target. - variableName = - this->LocalGenerator->CreateMakeVariable(this->Target->GetName(), - "_OBJECTS"); - *this->BuildFileStream - << "# Object files for target " << this->Target->GetName() << "\n" - << variableName.c_str() << " ="; + variableName = this->LocalGenerator->CreateMakeVariable( + this->GeneratorTarget->GetName(), "_OBJECTS"); + *this->BuildFileStream << "# Object files for target " + << this->GeneratorTarget->GetName() << "\n" + << variableName << " ="; std::string object; - const char* objName = - this->Makefile->GetDefinition("CMAKE_NO_QUOTED_OBJECTS"); const char* lineContinue = this->Makefile->GetDefinition("CMAKE_MAKE_LINE_CONTINUE"); - if(!lineContinue) - { + if (!lineContinue) { lineContinue = "\\"; - } - for(std::vector<std::string>::const_iterator i = this->Objects.begin(); - i != this->Objects.end(); ++i) - { + } + for (std::vector<std::string>::const_iterator i = this->Objects.begin(); + i != this->Objects.end(); ++i) { *this->BuildFileStream << " " << lineContinue << "\n"; - if(objName) - { - *this->BuildFileStream << - this->Convert(i->c_str(), cmLocalGenerator::START_OUTPUT, - cmLocalGenerator::MAKEFILE); - } - else - { - *this->BuildFileStream << - this->LocalGenerator->ConvertToQuotedOutputPath(i->c_str()); - } - } + *this->BuildFileStream << this->LocalGenerator->ConvertToQuotedOutputPath( + i->c_str(), useWatcomQuote); + } *this->BuildFileStream << "\n"; // Write a make variable assignment that lists all external objects // for the target. - variableNameExternal = - this->LocalGenerator->CreateMakeVariable(this->Target->GetName(), - "_EXTERNAL_OBJECTS"); + variableNameExternal = this->LocalGenerator->CreateMakeVariable( + this->GeneratorTarget->GetName(), "_EXTERNAL_OBJECTS"); + /* clang-format off */ *this->BuildFileStream << "\n" << "# External object files for target " - << this->Target->GetName() << "\n" - << variableNameExternal.c_str() << " ="; - for(std::vector<std::string>::const_iterator i = - this->ExternalObjects.begin(); - i != this->ExternalObjects.end(); ++i) - { - object = this->Convert(i->c_str(),cmLocalGenerator::START_OUTPUT); - *this->BuildFileStream - << " " << lineContinue << "\n" - << this->Makefile->GetSafeDefinition("CMAKE_OBJECT_NAME"); - if(objName) - { - *this->BuildFileStream << - this->Convert(i->c_str(), cmLocalGenerator::START_OUTPUT, - cmLocalGenerator::MAKEFILE); - } - else - { - *this->BuildFileStream << - this->LocalGenerator->ConvertToQuotedOutputPath(i->c_str()); - } - } - *this->BuildFileStream << "\n" << "\n"; -} - -//---------------------------------------------------------------------------- -void -cmMakefileTargetGenerator -::WriteObjectsString(std::string& buildObjs) -{ - std::vector<std::string> objStrings; - this->WriteObjectsStrings(objStrings); - buildObjs = objStrings[0]; + << this->GeneratorTarget->GetName() << "\n" + << variableNameExternal << " ="; + /* clang-format on */ + std::string currentBinDir = + this->LocalGenerator->GetCurrentBinaryDirectory(); + for (std::vector<std::string>::const_iterator i = + this->ExternalObjects.begin(); + i != this->ExternalObjects.end(); ++i) { + object = + this->LocalGenerator->MaybeConvertToRelativePath(currentBinDir, *i); + *this->BuildFileStream << " " << lineContinue << "\n"; + *this->BuildFileStream << this->LocalGenerator->ConvertToQuotedOutputPath( + i->c_str(), useWatcomQuote); + } + *this->BuildFileStream << "\n" + << "\n"; } -//---------------------------------------------------------------------------- class cmMakefileTargetGeneratorObjectStrings { public: cmMakefileTargetGeneratorObjectStrings(std::vector<std::string>& strings, - cmLocalUnixMakefileGenerator3* lg, - std::string::size_type limit): - Strings(strings), LocalGenerator(lg), LengthLimit(limit) - { + cmOutputConverter* outputConverter, + cmStateDirectory const& stateDir, + std::string::size_type limit) + : Strings(strings) + , OutputConverter(outputConverter) + , StateDir(stateDir) + , LengthLimit(limit) + { this->Space = ""; - } + } void Feed(std::string const& obj) - { + { // Construct the name of the next object. - this->NextObject = - this->LocalGenerator->Convert(obj.c_str(), - cmLocalGenerator::START_OUTPUT, - cmLocalGenerator::RESPONSE); + this->NextObject = this->OutputConverter->ConvertToOutputFormat( + this->MaybeConvertToRelativePath(obj), cmOutputConverter::RESPONSE); // Roll over to next string if the limit will be exceeded. - if(this->LengthLimit != std::string::npos && - (this->CurrentString.length() + 1 + this->NextObject.length() - > this->LengthLimit)) - { + if (this->LengthLimit != std::string::npos && + (this->CurrentString.length() + 1 + this->NextObject.length() > + this->LengthLimit)) { this->Strings.push_back(this->CurrentString); this->CurrentString = ""; this->Space = ""; - } + } // Separate from previous object. this->CurrentString += this->Space; @@ -1416,201 +1285,128 @@ public: // Append this object. this->CurrentString += this->NextObject; - } - void Done() - { - this->Strings.push_back(this->CurrentString); - } + } + void Done() { this->Strings.push_back(this->CurrentString); } + private: + std::string MaybeConvertToRelativePath(std::string const& obj) + { + if (!cmOutputConverter::ContainedInDirectory( + this->StateDir.GetCurrentBinary(), obj, this->StateDir)) { + return obj; + } + return cmOutputConverter::ForceToRelativePath( + this->StateDir.GetCurrentBinary(), obj); + } + std::vector<std::string>& Strings; - cmLocalUnixMakefileGenerator3* LocalGenerator; + cmOutputConverter* OutputConverter; + cmStateDirectory StateDir; std::string::size_type LengthLimit; std::string CurrentString; std::string NextObject; const char* Space; }; -//---------------------------------------------------------------------------- -void -cmMakefileTargetGenerator -::WriteObjectsStrings(std::vector<std::string>& objStrings, - std::string::size_type limit) +void cmMakefileTargetGenerator::WriteObjectsStrings( + std::vector<std::string>& objStrings, std::string::size_type limit) { - cmMakefileTargetGeneratorObjectStrings - helper(objStrings, this->LocalGenerator, limit); - for(std::vector<std::string>::const_iterator i = this->Objects.begin(); - i != this->Objects.end(); ++i) - { + cmMakefileTargetGeneratorObjectStrings helper( + objStrings, this->LocalGenerator, + this->LocalGenerator->GetStateSnapshot().GetDirectory(), limit); + for (std::vector<std::string>::const_iterator i = this->Objects.begin(); + i != this->Objects.end(); ++i) { helper.Feed(*i); - } - for(std::vector<std::string>::const_iterator i = - this->ExternalObjects.begin(); - i != this->ExternalObjects.end(); ++i) - { + } + for (std::vector<std::string>::const_iterator i = + this->ExternalObjects.begin(); + i != this->ExternalObjects.end(); ++i) { helper.Feed(*i); - } + } helper.Done(); } -//---------------------------------------------------------------------------- -void cmMakefileTargetGenerator::WriteTargetDriverRule(const char* main_output, - bool relink) +void cmMakefileTargetGenerator::WriteTargetDriverRule( + const std::string& main_output, bool relink) { // Compute the name of the driver target. std::string dir = - this->LocalGenerator->GetRelativeTargetDirectory(*this->Target); + this->LocalGenerator->GetRelativeTargetDirectory(this->GeneratorTarget); std::string buildTargetRuleName = dir; - buildTargetRuleName += relink?"/preinstall":"/build"; - buildTargetRuleName = this->Convert(buildTargetRuleName.c_str(), - cmLocalGenerator::HOME_OUTPUT, - cmLocalGenerator::UNCHANGED); + buildTargetRuleName += relink ? "/preinstall" : "/build"; + buildTargetRuleName = this->LocalGenerator->MaybeConvertToRelativePath( + this->LocalGenerator->GetBinaryDirectory(), buildTargetRuleName); // Build the list of target outputs to drive. std::vector<std::string> depends; - if(main_output) - { - depends.push_back(main_output); - } + depends.push_back(main_output); - const char* comment = 0; - if(relink) - { + const char* comment = CM_NULLPTR; + if (relink) { // Setup the comment for the preinstall driver. comment = "Rule to relink during preinstall."; - } - else - { + } else { // Setup the comment for the main build driver. comment = "Rule to build all files generated by this target."; // Make sure all custom command outputs in this target are built. - if(this->CustomCommandDriver == OnBuild) - { + if (this->CustomCommandDriver == OnBuild) { this->DriveCustomCommands(depends); - } + } // Make sure the extra files are built. - for(std::set<cmStdString>::const_iterator i = this->ExtraFiles.begin(); - i != this->ExtraFiles.end(); ++i) - { - depends.push_back(*i); - } - } + depends.insert(depends.end(), this->ExtraFiles.begin(), + this->ExtraFiles.end()); + } // Write the driver rule. std::vector<std::string> no_commands; this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, comment, - buildTargetRuleName.c_str(), - depends, no_commands, true); -} - -//---------------------------------------------------------------------------- -std::string cmMakefileTargetGenerator::GetFrameworkFlags() -{ - if(!this->Makefile->IsOn("APPLE")) - { - return std::string(); - } - - std::set<cmStdString> emitted; -#ifdef __APPLE__ /* don't insert this when crosscompiling e.g. to iphone */ - emitted.insert("/System/Library/Frameworks"); -#endif - std::vector<std::string> includes; - - const char *config = this->Makefile->GetDefinition("CMAKE_BUILD_TYPE"); - this->LocalGenerator->GetIncludeDirectories(includes, - this->GeneratorTarget, - "C", config); - // check all include directories for frameworks as this - // will already have added a -F for the framework - for(std::vector<std::string>::iterator i = includes.begin(); - i != includes.end(); ++i) - { - if(this->Target->NameResolvesToFramework(i->c_str())) - { - std::string frameworkDir = *i; - frameworkDir += "/../"; - frameworkDir = cmSystemTools::CollapseFullPath(frameworkDir.c_str()); - emitted.insert(frameworkDir); - } - } - - std::string flags; - const char* cfg = this->LocalGenerator->ConfigurationName.c_str(); - if(cmComputeLinkInformation* cli = this->Target->GetLinkInformation(cfg)) - { - std::vector<std::string> const& frameworks = cli->GetFrameworkPaths(); - for(std::vector<std::string>::const_iterator i = frameworks.begin(); - i != frameworks.end(); ++i) - { - if(emitted.insert(*i).second) - { - flags += "-F"; - flags += this->Convert(i->c_str(), - cmLocalGenerator::START_OUTPUT, - cmLocalGenerator::SHELL, true); - flags += " "; - } - } - } - return flags; + buildTargetRuleName, depends, + no_commands, true); } -//---------------------------------------------------------------------------- -void cmMakefileTargetGenerator -::AppendTargetDepends(std::vector<std::string>& depends) +void cmMakefileTargetGenerator::AppendTargetDepends( + std::vector<std::string>& depends) { // Static libraries never depend on anything for linking. - if(this->Target->GetType() == cmTarget::STATIC_LIBRARY) - { + if (this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY) { return; - } + } // Loop over all library dependencies. - const char* cfg = this->LocalGenerator->ConfigurationName.c_str(); - if(cmComputeLinkInformation* cli = this->Target->GetLinkInformation(cfg)) - { + const char* cfg = this->LocalGenerator->GetConfigName().c_str(); + if (cmComputeLinkInformation* cli = + this->GeneratorTarget->GetLinkInformation(cfg)) { std::vector<std::string> const& libDeps = cli->GetDepends(); - for(std::vector<std::string>::const_iterator j = libDeps.begin(); - j != libDeps.end(); ++j) - { - depends.push_back(*j); - } - } + depends.insert(depends.end(), libDeps.begin(), libDeps.end()); + } } -//---------------------------------------------------------------------------- -void cmMakefileTargetGenerator -::AppendObjectDepends(std::vector<std::string>& depends) +void cmMakefileTargetGenerator::AppendObjectDepends( + std::vector<std::string>& depends) { // Add dependencies on the compiled object files. std::string relPath = this->LocalGenerator->GetHomeRelativeOutputPath(); std::string objTarget; - for(std::vector<std::string>::const_iterator obj = this->Objects.begin(); - obj != this->Objects.end(); ++obj) - { + for (std::vector<std::string>::const_iterator obj = this->Objects.begin(); + obj != this->Objects.end(); ++obj) { objTarget = relPath; objTarget += *obj; depends.push_back(objTarget); - } + } // Add dependencies on the external object files. - for(std::vector<std::string>::const_iterator obj - = this->ExternalObjects.begin(); - obj != this->ExternalObjects.end(); ++obj) - { - depends.push_back(*obj); - } + depends.insert(depends.end(), this->ExternalObjects.begin(), + this->ExternalObjects.end()); // Add a dependency on the rule file itself. this->LocalGenerator->AppendRuleDepend(depends, this->BuildFileNameFull.c_str()); } -//---------------------------------------------------------------------------- -void cmMakefileTargetGenerator -::AppendLinkDepends(std::vector<std::string>& depends) +void cmMakefileTargetGenerator::AppendLinkDepends( + std::vector<std::string>& depends) { this->AppendObjectDepends(depends); @@ -1618,83 +1414,57 @@ void cmMakefileTargetGenerator this->AppendTargetDepends(depends); // Add a dependency on the link definitions file, if any. - if(!this->GeneratorTarget->ModuleDefinitionFile.empty()) - { - depends.push_back(this->GeneratorTarget->ModuleDefinitionFile); + if (cmGeneratorTarget::ModuleDefinitionInfo const* mdi = + this->GeneratorTarget->GetModuleDefinitionInfo( + this->GetConfigName())) { + for (std::vector<cmSourceFile const*>::const_iterator i = + mdi->Sources.begin(); + i != mdi->Sources.end(); ++i) { + depends.push_back((*i)->GetFullPath()); } + } + + // Add a dependency on user-specified manifest files, if any. + std::vector<cmSourceFile const*> manifest_srcs; + this->GeneratorTarget->GetManifests(manifest_srcs, this->ConfigName); + for (std::vector<cmSourceFile const*>::iterator mi = manifest_srcs.begin(); + mi != manifest_srcs.end(); ++mi) { + depends.push_back((*mi)->GetFullPath()); + } // Add user-specified dependencies. - if(const char* linkDepends = - this->Target->GetProperty("LINK_DEPENDS")) - { + if (const char* linkDepends = + this->GeneratorTarget->GetProperty("LINK_DEPENDS")) { cmSystemTools::ExpandListArgument(linkDepends, depends); - } + } } -//---------------------------------------------------------------------------- -std::string cmMakefileTargetGenerator::GetLinkRule(const char* linkRuleVar) +std::string cmMakefileTargetGenerator::GetLinkRule( + const std::string& linkRuleVar) { std::string linkRule = this->Makefile->GetRequiredDefinition(linkRuleVar); - if(this->Target->HasImplibGNUtoMS()) - { + if (this->GeneratorTarget->HasImplibGNUtoMS()) { std::string ruleVar = "CMAKE_"; - ruleVar += this->Target->GetLinkerLanguage(this->ConfigName); + ruleVar += this->GeneratorTarget->GetLinkerLanguage(this->ConfigName); ruleVar += "_GNUtoMS_RULE"; - if(const char* rule = this->Makefile->GetDefinition(ruleVar.c_str())) - { + if (const char* rule = this->Makefile->GetDefinition(ruleVar)) { linkRule += rule; - } } + } return linkRule; } -//---------------------------------------------------------------------------- -void cmMakefileTargetGenerator -::CloseFileStreams() +void cmMakefileTargetGenerator::CloseFileStreams() { delete this->BuildFileStream; delete this->InfoFileStream; delete this->FlagFileStream; } -void cmMakefileTargetGenerator::RemoveForbiddenFlags(const char* flagVar, - const char* linkLang, - std::string& linkFlags) -{ - // check for language flags that are not allowed at link time, and - // remove them, -w on darwin for gcc -w -dynamiclib sends -w to libtool - // which fails, there may be more] - - std::string removeFlags = "CMAKE_"; - removeFlags += linkLang; - removeFlags += flagVar; - std::string removeflags = - this->Makefile->GetSafeDefinition(removeFlags.c_str()); - std::vector<std::string> removeList; - cmSystemTools::ExpandListArgument(removeflags, removeList); - for(std::vector<std::string>::iterator i = removeList.begin(); - i != removeList.end(); ++i) - { - cmSystemTools::ReplaceString(linkFlags, i->c_str(), ""); - } -} - -//---------------------------------------------------------------------------- -void -cmMakefileTargetGenerator -::AddMultipleOutputPair(const char* depender, const char* dependee) -{ - MultipleOutputPairsType::value_type p(depender, dependee); - this->MultipleOutputPairs.insert(p); -} - -//---------------------------------------------------------------------------- -void -cmMakefileTargetGenerator -::CreateLinkScript(const char* name, - std::vector<std::string> const& link_commands, - std::vector<std::string>& makefile_commands, - std::vector<std::string>& makefile_depends) +void cmMakefileTargetGenerator::CreateLinkScript( + const char* name, std::vector<std::string> const& link_commands, + std::vector<std::string>& makefile_commands, + std::vector<std::string>& makefile_depends) { // Create the link script file. std::string linkScriptName = this->TargetBuildDirectoryFull; @@ -1702,32 +1472,87 @@ cmMakefileTargetGenerator linkScriptName += name; cmGeneratedFileStream linkScriptStream(linkScriptName.c_str()); linkScriptStream.SetCopyIfDifferent(true); - for(std::vector<std::string>::const_iterator cmd = link_commands.begin(); - cmd != link_commands.end(); ++cmd) - { + for (std::vector<std::string>::const_iterator cmd = link_commands.begin(); + cmd != link_commands.end(); ++cmd) { // Do not write out empty commands or commands beginning in the // shell no-op ":". - if(!cmd->empty() && (*cmd)[0] != ':') - { + if (!cmd->empty() && (*cmd)[0] != ':') { linkScriptStream << *cmd << "\n"; - } } + } // Create the makefile command to invoke the link script. std::string link_command = "$(CMAKE_COMMAND) -E cmake_link_script "; - link_command += this->Convert(linkScriptName.c_str(), - cmLocalGenerator::START_OUTPUT, - cmLocalGenerator::SHELL); + link_command += this->LocalGenerator->ConvertToOutputFormat( + this->LocalGenerator->MaybeConvertToRelativePath( + this->LocalGenerator->GetCurrentBinaryDirectory(), linkScriptName), + cmOutputConverter::SHELL); link_command += " --verbose=$(VERBOSE)"; makefile_commands.push_back(link_command); makefile_depends.push_back(linkScriptName); } -//---------------------------------------------------------------------------- -std::string -cmMakefileTargetGenerator -::CreateResponseFile(const char* name, std::string const& options, - std::vector<std::string>& makefile_depends) +bool cmMakefileTargetGenerator::CheckUseResponseFileForObjects( + std::string const& l) const +{ + // Check for an explicit setting one way or the other. + std::string const responseVar = + "CMAKE_" + l + "_USE_RESPONSE_FILE_FOR_OBJECTS"; + if (const char* val = this->Makefile->GetDefinition(responseVar)) { + if (*val) { + return cmSystemTools::IsOn(val); + } + } + + // Check for a system limit. + if (size_t const limit = cmSystemTools::CalculateCommandLineLengthLimit()) { + // Compute the total length of our list of object files with room + // for argument separation and quoting. This does not convert paths + // relative to CMAKE_CURRENT_BINARY_DIR like the final list will be, so the + // actual list will likely be much shorter than this. However, in the + // worst case all objects will remain as absolute paths. + size_t length = 0; + for (std::vector<std::string>::const_iterator i = this->Objects.begin(); + i != this->Objects.end(); ++i) { + length += i->size() + 3; + } + for (std::vector<std::string>::const_iterator i = + this->ExternalObjects.begin(); + i != this->ExternalObjects.end(); ++i) { + length += i->size() + 3; + } + + // We need to guarantee room for both objects and libraries, so + // if the objects take up more than half then use a response file + // for them. + if (length > (limit / 2)) { + return true; + } + } + + // We do not need a response file for objects. + return false; +} + +bool cmMakefileTargetGenerator::CheckUseResponseFileForLibraries( + std::string const& l) const +{ + // Check for an explicit setting one way or the other. + std::string const responseVar = + "CMAKE_" + l + "_USE_RESPONSE_FILE_FOR_LIBRARIES"; + if (const char* val = this->Makefile->GetDefinition(responseVar)) { + if (*val) { + return cmSystemTools::IsOn(val); + } + } + + // We do not need a response file for libraries. + return false; +} + +std::string cmMakefileTargetGenerator::CreateResponseFile( + const char* name, std::string const& options, + std::vector<std::string>& makefile_depends) { // Create the response file. std::string responseFileNameFull = this->TargetBuildDirectoryFull; @@ -1748,18 +1573,63 @@ cmMakefileTargetGenerator return responseFileName; } -//---------------------------------------------------------------------------- -void -cmMakefileTargetGenerator -::CreateObjectLists(bool useLinkScript, bool useArchiveRules, - bool useResponseFile, std::string& buildObjs, - std::vector<std::string>& makefile_depends) +cmLinkLineComputer* cmMakefileTargetGenerator::CreateLinkLineComputer( + cmOutputConverter* outputConverter, cmStateDirectory const& stateDir) +{ + if (this->Makefile->IsOn("MSVC60")) { + return this->GlobalGenerator->CreateMSVC60LinkLineComputer(outputConverter, + stateDir); + } + return this->GlobalGenerator->CreateLinkLineComputer(outputConverter, + stateDir); +} + +void cmMakefileTargetGenerator::CreateLinkLibs( + cmLinkLineComputer* linkLineComputer, std::string& linkLibs, + bool useResponseFile, std::vector<std::string>& makefile_depends) +{ + std::string frameworkPath; + std::string linkPath; + std::string config = this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"); + cmComputeLinkInformation* pcli = + this->GeneratorTarget->GetLinkInformation(config); + this->LocalGenerator->OutputLinkLibraries(pcli, linkLineComputer, linkLibs, + frameworkPath, linkPath); + linkLibs = frameworkPath + linkPath + linkLibs; + + if (useResponseFile && + linkLibs.find_first_not_of(' ') != std::string::npos) { + // Lookup the response file reference flag. + std::string responseFlagVar = "CMAKE_"; + responseFlagVar += + this->GeneratorTarget->GetLinkerLanguage(this->ConfigName); + responseFlagVar += "_RESPONSE_FILE_LINK_FLAG"; + const char* responseFlag = this->Makefile->GetDefinition(responseFlagVar); + if (!responseFlag) { + responseFlag = "@"; + } + + // Create this response file. + std::string link_rsp = + this->CreateResponseFile("linklibs.rsp", linkLibs, makefile_depends); + + // Reference the response file. + linkLibs = responseFlag; + linkLibs += this->LocalGenerator->ConvertToOutputFormat( + link_rsp, cmOutputConverter::SHELL); + } +} + +void cmMakefileTargetGenerator::CreateObjectLists( + bool useLinkScript, bool useArchiveRules, bool useResponseFile, + std::string& buildObjs, std::vector<std::string>& makefile_depends, + bool useWatcomQuote) { std::string variableName; std::string variableNameExternal; - this->WriteObjectsVariable(variableName, variableNameExternal); - if(useResponseFile) - { + this->WriteObjectsVariable(variableName, variableNameExternal, + useWatcomQuote); + if (useResponseFile) { // MSVC response files cannot exceed 128K. std::string::size_type const responseFileLimit = 131000; @@ -1769,22 +1639,20 @@ cmMakefileTargetGenerator // Lookup the response file reference flag. std::string responseFlagVar = "CMAKE_"; - responseFlagVar += this->Target->GetLinkerLanguage(this->ConfigName); + responseFlagVar += + this->GeneratorTarget->GetLinkerLanguage(this->ConfigName); responseFlagVar += "_RESPONSE_FILE_LINK_FLAG"; - const char* responseFlag = - this->Makefile->GetDefinition(responseFlagVar.c_str()); - if(!responseFlag) - { + const char* responseFlag = this->Makefile->GetDefinition(responseFlagVar); + if (!responseFlag) { responseFlag = "@"; - } + } // Write a response file for each string. const char* sep = ""; - for(unsigned int i = 0; i < object_strings.size(); ++i) - { + for (unsigned int i = 0; i < object_strings.size(); ++i) { // Number the response files. char rsp[32]; - sprintf(rsp, "objects%u.rsp", i+1); + sprintf(rsp, "objects%u.rsp", i + 1); // Create this response file. std::string objects_rsp = @@ -1796,208 +1664,100 @@ cmMakefileTargetGenerator // Reference the response file. buildObjs += responseFlag; - buildObjs += this->Convert(objects_rsp.c_str(), - cmLocalGenerator::NONE, - cmLocalGenerator::SHELL); - } + buildObjs += this->LocalGenerator->ConvertToOutputFormat( + objects_rsp, cmOutputConverter::SHELL); } - else if(useLinkScript) - { - if(!useArchiveRules) - { - this->WriteObjectsString(buildObjs); - } + } else if (useLinkScript) { + if (!useArchiveRules) { + std::vector<std::string> objStrings; + this->WriteObjectsStrings(objStrings); + buildObjs = objStrings[0]; } - else - { + } else { buildObjs = "$("; buildObjs += variableName; buildObjs += ") $("; buildObjs += variableNameExternal; buildObjs += ")"; - } + } } -//---------------------------------------------------------------------------- void cmMakefileTargetGenerator::AddIncludeFlags(std::string& flags, - const char* lang) + const std::string& lang) { std::string responseVar = "CMAKE_"; responseVar += lang; responseVar += "_USE_RESPONSE_FILE_FOR_INCLUDES"; - bool useResponseFile = this->Makefile->IsOn(responseVar.c_str()); - + bool useResponseFile = this->Makefile->IsOn(responseVar); std::vector<std::string> includes; - const char *config = this->Makefile->GetDefinition("CMAKE_BUILD_TYPE"); - this->LocalGenerator->GetIncludeDirectories(includes, - this->GeneratorTarget, + const std::string& config = + this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"); + this->LocalGenerator->GetIncludeDirectories(includes, this->GeneratorTarget, lang, config); - std::string includeFlags = - this->LocalGenerator->GetIncludeFlags(includes, this->GeneratorTarget, - lang, useResponseFile); - if(includeFlags.empty()) - { + std::string includeFlags = this->LocalGenerator->GetIncludeFlags( + includes, this->GeneratorTarget, lang, false, useResponseFile, config); + if (includeFlags.empty()) { return; - } + } - if(useResponseFile) - { + if (useResponseFile) { std::string name = "includes_"; name += lang; name += ".rsp"; std::string arg = "@" + this->CreateResponseFile(name.c_str(), includeFlags, this->FlagFileDepends[lang]); - this->LocalGenerator->AppendFlags(flags, arg.c_str()); - } - else - { - this->LocalGenerator->AppendFlags(flags, includeFlags.c_str()); - } -} - -//---------------------------------------------------------------------------- -const char* cmMakefileTargetGenerator::GetFortranModuleDirectory() -{ - // Compute the module directory. - if(!this->FortranModuleDirectoryComputed) - { - const char* target_mod_dir = - this->Target->GetProperty("Fortran_MODULE_DIRECTORY"); - const char* moddir_flag = - this->Makefile->GetDefinition("CMAKE_Fortran_MODDIR_FLAG"); - if(target_mod_dir && moddir_flag) - { - // Compute the full path to the module directory. - if(cmSystemTools::FileIsFullPath(target_mod_dir)) - { - // Already a full path. - this->FortranModuleDirectory = target_mod_dir; - } - else - { - // Interpret relative to the current output directory. - this->FortranModuleDirectory = - this->Makefile->GetCurrentOutputDirectory(); - this->FortranModuleDirectory += "/"; - this->FortranModuleDirectory += target_mod_dir; - } - - // Make sure the module output directory exists. - cmSystemTools::MakeDirectory(this->FortranModuleDirectory.c_str()); - } - this->FortranModuleDirectoryComputed = true; - } - - // Return the computed directory. - if(this->FortranModuleDirectory.empty()) - { - return 0; - } - else - { - return this->FortranModuleDirectory.c_str(); - } -} - -//---------------------------------------------------------------------------- -void cmMakefileTargetGenerator::AddFortranFlags(std::string& flags) -{ - // Enable module output if necessary. - if(const char* modout_flag = - this->Makefile->GetDefinition("CMAKE_Fortran_MODOUT_FLAG")) - { - this->LocalGenerator->AppendFlags(flags, modout_flag); - } - - // Add a module output directory flag if necessary. - const char* mod_dir = this->GetFortranModuleDirectory(); - if(!mod_dir) - { - mod_dir = this->Makefile->GetDefinition("CMAKE_Fortran_MODDIR_DEFAULT"); - } - if(mod_dir) - { - const char* moddir_flag = - this->Makefile->GetRequiredDefinition("CMAKE_Fortran_MODDIR_FLAG"); - std::string modflag = moddir_flag; - modflag += this->Convert(mod_dir, - cmLocalGenerator::START_OUTPUT, - cmLocalGenerator::SHELL); - this->LocalGenerator->AppendFlags(flags, modflag.c_str()); - } - - // If there is a separate module path flag then duplicate the - // include path with it. This compiler does not search the include - // path for modules. - if(const char* modpath_flag = - this->Makefile->GetDefinition("CMAKE_Fortran_MODPATH_FLAG")) - { - std::vector<std::string> includes; - const char *config = this->Makefile->GetDefinition("CMAKE_BUILD_TYPE"); - this->LocalGenerator->GetIncludeDirectories(includes, - this->GeneratorTarget, - "C", config); - for(std::vector<std::string>::const_iterator idi = includes.begin(); - idi != includes.end(); ++idi) - { - std::string flg = modpath_flag; - flg += this->Convert(idi->c_str(), - cmLocalGenerator::NONE, - cmLocalGenerator::SHELL); - this->LocalGenerator->AppendFlags(flags, flg.c_str()); - } - } + this->LocalGenerator->AppendFlags(flags, arg); + } else { + this->LocalGenerator->AppendFlags(flags, includeFlags); + } } -//---------------------------------------------------------------------------- -void cmMakefileTargetGenerator::AddModuleDefinitionFlag(std::string& flags) +void cmMakefileTargetGenerator::GenDefFile( + std::vector<std::string>& real_link_commands) { - if(this->GeneratorTarget->ModuleDefinitionFile.empty()) - { + cmGeneratorTarget::ModuleDefinitionInfo const* mdi = + this->GeneratorTarget->GetModuleDefinitionInfo(this->GetConfigName()); + if (!mdi || !mdi->DefFileGenerated) { return; + } + std::string cmd = cmSystemTools::GetCMakeCommand(); + cmd = + this->LocalGenerator->ConvertToOutputFormat(cmd, cmOutputConverter::SHELL); + cmd += " -E __create_def "; + cmd += this->LocalGenerator->ConvertToOutputFormat( + this->LocalGenerator->MaybeConvertToRelativePath( + this->LocalGenerator->GetCurrentBinaryDirectory(), mdi->DefFile), + cmOutputConverter::SHELL); + cmd += " "; + std::string objlist_file = mdi->DefFile + ".objs"; + cmd += this->LocalGenerator->ConvertToOutputFormat( + this->LocalGenerator->MaybeConvertToRelativePath( + this->LocalGenerator->GetCurrentBinaryDirectory(), objlist_file), + cmOutputConverter::SHELL); + real_link_commands.insert(real_link_commands.begin(), cmd); + // create a list of obj files for the -E __create_def to read + cmGeneratedFileStream fout(objlist_file.c_str()); + + if (mdi->WindowsExportAllSymbols) { + for (std::vector<std::string>::const_iterator i = this->Objects.begin(); + i != this->Objects.end(); ++i) { + if (cmHasLiteralSuffix(*i, ".obj")) { + fout << *i << "\n"; + } } - - // TODO: Create a per-language flag variable. - const char* defFileFlag = - this->Makefile->GetDefinition("CMAKE_LINK_DEF_FILE_FLAG"); - if(!defFileFlag) - { - return; + for (std::vector<std::string>::const_iterator i = + this->ExternalObjects.begin(); + i != this->ExternalObjects.end(); ++i) { + fout << *i << "\n"; } + } - // Append the flag and value. Use ConvertToLinkReference to help - // vs6's "cl -link" pass it to the linker. - std::string flag = defFileFlag; - flag += (this->LocalGenerator->ConvertToLinkReference( - this->GeneratorTarget->ModuleDefinitionFile.c_str())); - this->LocalGenerator->AppendFlags(flags, flag.c_str()); -} - -//---------------------------------------------------------------------------- -const char* cmMakefileTargetGenerator::GetFeature(const char* feature) -{ - return this->Target->GetFeature(feature, this->ConfigName); -} - -//---------------------------------------------------------------------------- -bool cmMakefileTargetGenerator::GetFeatureAsBool(const char* feature) -{ - return cmSystemTools::IsOn(this->GetFeature(feature)); -} - -//---------------------------------------------------------------------------- -void cmMakefileTargetGenerator::AddFeatureFlags( - std::string& flags, const char* lang - ) -{ - // Add language-specific flags. - this->LocalGenerator->AddLanguageFlags(flags, lang, this->ConfigName); - - if(this->GetFeatureAsBool("INTERPROCEDURAL_OPTIMIZATION")) - { - this->LocalGenerator->AppendFeatureOptions(flags, lang, "IPO"); - } + for (std::vector<cmSourceFile const*>::const_iterator i = + mdi->Sources.begin(); + i != mdi->Sources.end(); ++i) { + fout << (*i)->GetFullPath() << "\n"; + } } |