| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451 | /*============================================================================  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.============================================================================*/#include "cmMakefileExecutableTargetGenerator.h"#include "cmGeneratedFileStream.h"#include "cmGlobalUnixMakefileGenerator3.h"#include "cmLocalUnixMakefileGenerator3.h"#include "cmMakefile.h"#include "cmSourceFile.h"#include "cmTarget.h"#include "cmake.h"//----------------------------------------------------------------------------cmMakefileExecutableTargetGenerator::cmMakefileExecutableTargetGenerator(cmGeneratorTarget* target):  cmMakefileTargetGenerator(target->Target){  this->CustomCommandDriver = OnDepends;  this->Target->GetExecutableNames(    this->TargetNameOut, this->TargetNameReal, this->TargetNameImport,    this->TargetNamePDB, this->ConfigName);  this->OSXBundleGenerator = new cmOSXBundleGenerator(target,                                                      this->ConfigName);  this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders);}//----------------------------------------------------------------------------cmMakefileExecutableTargetGenerator::~cmMakefileExecutableTargetGenerator(){  delete this->OSXBundleGenerator;}//----------------------------------------------------------------------------void cmMakefileExecutableTargetGenerator::WriteRuleFiles(){  // create the build.make file and directory, put in the common blocks  this->CreateRuleFile();  // write rules used to help build object files  this->WriteCommonCodeRules();  // write the per-target per-language flags  this->WriteTargetLanguageFlags();  // write in rules for object files and custom commands  this->WriteTargetBuildRules();  // write the link rules  this->WriteExecutableRule(false);  if(this->Target->NeedRelinkBeforeInstall(this->ConfigName))    {    // Write rules to link an installable version of the target.    this->WriteExecutableRule(true);    }  // Write the requires target.  this->WriteTargetRequiresRules();  // Write clean target  this->WriteTargetCleanRules();  // Write the dependency generation rule.  This must be done last so  // that multiple output pair information is available.  this->WriteTargetDependRules();  // close the streams  this->CloseFileStreams();}//----------------------------------------------------------------------------void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink){  std::vector<std::string> commands;  // Build list of dependencies.  std::vector<std::string> depends;  this->AppendLinkDepends(depends);  // Get the name of the executable to generate.  std::string targetName;  std::string targetNameReal;  std::string targetNameImport;  std::string targetNamePDB;  this->Target->GetExecutableNames    (targetName, targetNameReal, targetNameImport, targetNamePDB,     this->ConfigName);  // Construct the full path version of the names.  std::string outpath = this->Target->GetDirectory(this->ConfigName);  if(this->Target->IsAppBundleOnApple())    {    this->OSXBundleGenerator->CreateAppBundle(targetName, outpath);    }  outpath += "/";  std::string outpathImp;  if(relink)    {    outpath = this->Makefile->GetStartOutputDirectory();    outpath += cmake::GetCMakeFilesDirectory();    outpath += "/CMakeRelink.dir";    cmSystemTools::MakeDirectory(outpath.c_str());    outpath += "/";    if(!targetNameImport.empty())      {      outpathImp = outpath;      }    }  else    {    cmSystemTools::MakeDirectory(outpath.c_str());    if(!targetNameImport.empty())      {      outpathImp = this->Target->GetDirectory(this->ConfigName, true);      cmSystemTools::MakeDirectory(outpathImp.c_str());      outpathImp += "/";      }    }  std::string compilePdbOutputPath =    this->Target->GetCompilePDBDirectory(this->ConfigName);  cmSystemTools::MakeDirectory(compilePdbOutputPath.c_str());  std::string pdbOutputPath = this->Target->GetPDBDirectory(this->ConfigName);  cmSystemTools::MakeDirectory(pdbOutputPath.c_str());  pdbOutputPath += "/";  std::string targetFullPath = outpath + targetName;  std::string targetFullPathReal = outpath + targetNameReal;  std::string targetFullPathPDB =  pdbOutputPath + targetNamePDB;  std::string targetFullPathImport = outpathImp + targetNameImport;  std::string targetOutPathPDB =    this->Convert(targetFullPathPDB.c_str(),                  cmLocalGenerator::NONE,                  cmLocalGenerator::SHELL);  // Convert to the output path to use in constructing commands.  std::string targetOutPath =    this->Convert(targetFullPath.c_str(),                  cmLocalGenerator::START_OUTPUT,                  cmLocalGenerator::SHELL);  std::string targetOutPathReal =    this->Convert(targetFullPathReal.c_str(),                  cmLocalGenerator::START_OUTPUT,                  cmLocalGenerator::SHELL);  std::string targetOutPathImport =    this->Convert(targetFullPathImport.c_str(),                  cmLocalGenerator::START_OUTPUT,                  cmLocalGenerator::SHELL);  // Get the language to use for linking this executable.  const char* linkLanguage =    this->Target->GetLinkerLanguage(this->ConfigName);  // Make sure we have a link language.  if(!linkLanguage)    {    cmSystemTools::Error("Cannot determine link language for target \"",                         this->Target->GetName(), "\".");    return;    }  if(!this->NoRuleMessages)    {    // Add the link message.    std::string buildEcho = "Linking ";    buildEcho += linkLanguage;    buildEcho += " executable ";    buildEcho += targetOutPath;    this->LocalGenerator->AppendEcho(commands, buildEcho.c_str(),                                     cmLocalUnixMakefileGenerator3::EchoLink);    }  // Build a list of compiler flags and linker flags.  std::string flags;  std::string linkFlags;  // Add flags to create an executable.  this->LocalGenerator->    AddConfigVariableFlags(linkFlags, "CMAKE_EXE_LINKER_FLAGS",                           this->ConfigName);  if(this->Target->GetPropertyAsBool("WIN32_EXECUTABLE"))    {    this->LocalGenerator->AppendFlags      (linkFlags, this->Makefile->GetDefinition("CMAKE_CREATE_WIN32_EXE"));    }  else    {    this->LocalGenerator->AppendFlags      (linkFlags, this->Makefile->GetDefinition("CMAKE_CREATE_CONSOLE_EXE"));    }  // Add symbol export flags if necessary.  if(this->Target->IsExecutableWithExports())    {    std::string export_flag_var = "CMAKE_EXE_EXPORTS_";    export_flag_var += linkLanguage;    export_flag_var += "_FLAG";    this->LocalGenerator->AppendFlags      (linkFlags, this->Makefile->GetDefinition(export_flag_var.c_str()));    }  // Add language feature flags.  this->AddFeatureFlags(flags, linkLanguage);  this->LocalGenerator->AddArchitectureFlags(flags, this->GeneratorTarget,                                             linkLanguage, this->ConfigName);  // Add target-specific linker flags.  this->LocalGenerator->AppendFlags    (linkFlags, this->Target->GetProperty("LINK_FLAGS"));  std::string linkFlagsConfig = "LINK_FLAGS_";  linkFlagsConfig += cmSystemTools::UpperCase(this->ConfigName);  this->LocalGenerator->AppendFlags    (linkFlags, this->Target->GetProperty(linkFlagsConfig.c_str()));  this->AddModuleDefinitionFlag(linkFlags);  // Construct a list of files associated with this executable that  // may need to be cleaned.  std::vector<std::string> exeCleanFiles;  exeCleanFiles.push_back(this->Convert(targetFullPath.c_str(),                                        cmLocalGenerator::START_OUTPUT,                                        cmLocalGenerator::UNCHANGED));#ifdef _WIN32  // There may be a manifest file for this target.  Add it to the  // clean set just in case.  exeCleanFiles.push_back(this->Convert((targetFullPath+".manifest").c_str(),                                        cmLocalGenerator::START_OUTPUT,                                        cmLocalGenerator::UNCHANGED));#endif  if(targetNameReal != targetName)    {    exeCleanFiles.push_back(this->Convert(targetFullPathReal.c_str(),                                          cmLocalGenerator::START_OUTPUT,                                          cmLocalGenerator::UNCHANGED));    }  if(!targetNameImport.empty())    {    exeCleanFiles.push_back(this->Convert(targetFullPathImport.c_str(),                                          cmLocalGenerator::START_OUTPUT,                                          cmLocalGenerator::UNCHANGED));    std::string implib;    if(this->Target->GetImplibGNUtoMS(targetFullPathImport, implib))      {      exeCleanFiles.push_back(this->Convert(implib.c_str(),                                            cmLocalGenerator::START_OUTPUT,                                            cmLocalGenerator::UNCHANGED));      }    }  // List the PDB for cleaning only when the whole target is  // cleaned.  We do not want to delete the .pdb file just before  // linking the target.  this->CleanFiles.push_back    (this->Convert(targetFullPathPDB.c_str(),                   cmLocalGenerator::START_OUTPUT,                   cmLocalGenerator::UNCHANGED));  // Add the pre-build and pre-link rules building but not when relinking.  if(!relink)    {    this->LocalGenerator      ->AppendCustomCommands(commands, this->Target->GetPreBuildCommands(),                             this->Target);    this->LocalGenerator      ->AppendCustomCommands(commands, this->Target->GetPreLinkCommands(),                             this->Target);    }  // Determine whether a link script will be used.  bool useLinkScript = this->GlobalGenerator->GetUseLinkScript();  // Construct the main link rule.  std::vector<std::string> real_link_commands;  std::string linkRuleVar = "CMAKE_";  linkRuleVar += linkLanguage;  linkRuleVar += "_LINK_EXECUTABLE";  std::string linkRule = this->GetLinkRule(linkRuleVar.c_str());  std::vector<std::string> commands1;  cmSystemTools::ExpandListArgument(linkRule, real_link_commands);  if(this->Target->IsExecutableWithExports())    {    // If a separate rule for creating an import library is specified    // add it now.    std::string implibRuleVar = "CMAKE_";    implibRuleVar += linkLanguage;    implibRuleVar += "_CREATE_IMPORT_LIBRARY";    if(const char* rule =       this->Makefile->GetDefinition(implibRuleVar.c_str()))      {      cmSystemTools::ExpandListArgument(rule, real_link_commands);      }    }  // Select whether to use a response file for objects.  bool useResponseFileForObjects = false;  {  std::string responseVar = "CMAKE_";  responseVar += linkLanguage;  responseVar += "_USE_RESPONSE_FILE_FOR_OBJECTS";  if(this->Makefile->IsOn(responseVar.c_str()))    {    useResponseFileForObjects = true;    }  }  // Expand the rule variables.  {  // Set path conversion for link script shells.  this->LocalGenerator->SetLinkScriptShell(useLinkScript);  // Collect up flags to link in needed libraries.  std::string linkLibs;  this->CreateLinkLibs(linkLibs, relink, depends);  // Construct object file lists that may be needed to expand the  // rule.  std::string buildObjs;  this->CreateObjectLists(useLinkScript, false,                          useResponseFileForObjects, buildObjs, depends);  cmLocalGenerator::RuleVariables vars;  vars.RuleLauncher = "RULE_LAUNCH_LINK";  vars.CMTarget = this->Target;  vars.Language = linkLanguage;  vars.Objects = buildObjs.c_str();  std::string objectDir = this->Target->GetSupportDirectory();  objectDir = this->Convert(objectDir.c_str(),                            cmLocalGenerator::START_OUTPUT,                            cmLocalGenerator::SHELL);  vars.ObjectDir = objectDir.c_str();  vars.Target = targetOutPathReal.c_str();  vars.TargetPDB = targetOutPathPDB.c_str();  // Setup the target version.  std::string targetVersionMajor;  std::string targetVersionMinor;  {  cmOStringStream majorStream;  cmOStringStream minorStream;  int major;  int minor;  this->Target->GetTargetVersion(major, minor);  majorStream << major;  minorStream << minor;  targetVersionMajor = majorStream.str();  targetVersionMinor = minorStream.str();  }  vars.TargetVersionMajor = targetVersionMajor.c_str();  vars.TargetVersionMinor = targetVersionMinor.c_str();  vars.LinkLibraries = linkLibs.c_str();  vars.Flags = flags.c_str();  vars.LinkFlags = linkFlags.c_str();  // Expand placeholders in the commands.  this->LocalGenerator->TargetImplib = targetOutPathImport;  for(std::vector<std::string>::iterator i = real_link_commands.begin();      i != real_link_commands.end(); ++i)    {    this->LocalGenerator->ExpandRuleVariables(*i, vars);    }  this->LocalGenerator->TargetImplib = "";  // Restore path conversion to normal shells.  this->LocalGenerator->SetLinkScriptShell(false);  }  // Optionally convert the build rule to use a script to avoid long  // command lines in the make shell.  if(useLinkScript)    {    // Use a link script.    const char* name = (relink? "relink.txt" : "link.txt");    this->CreateLinkScript(name, real_link_commands, commands1, depends);    }  else    {    // No link script.  Just use the link rule directly.    commands1 = real_link_commands;    }  this->LocalGenerator->CreateCDCommand    (commands1,     this->Makefile->GetStartOutputDirectory(),     cmLocalGenerator::HOME_OUTPUT);  commands.insert(commands.end(), commands1.begin(), commands1.end());  commands1.clear();  // Add a rule to create necessary symlinks for the library.  if(targetOutPath != targetOutPathReal)    {    std::string symlink = "$(CMAKE_COMMAND) -E cmake_symlink_executable ";    symlink += targetOutPathReal;    symlink += " ";    symlink += targetOutPath;    commands1.push_back(symlink);    this->LocalGenerator->CreateCDCommand(commands1,                                  this->Makefile->GetStartOutputDirectory(),                                  cmLocalGenerator::HOME_OUTPUT);    commands.insert(commands.end(), commands1.begin(), commands1.end());    commands1.clear();    }  // Add the post-build rules when building but not when relinking.  if(!relink)    {    this->LocalGenerator->      AppendCustomCommands(commands, this->Target->GetPostBuildCommands(),                           this->Target);    }  // Write the build rule.  this->LocalGenerator->WriteMakeRule(*this->BuildFileStream,                                      0,                                      targetFullPathReal.c_str(),                                      depends, commands, false);  // The symlink name for the target should depend on the real target  // so if the target version changes it rebuilds and recreates the  // symlink.  if(targetFullPath != targetFullPathReal)    {    depends.clear();    commands.clear();    depends.push_back(targetFullPathReal.c_str());    this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0,                                        targetFullPath.c_str(),                                        depends, commands, false);    }  // Write the main driver rule to build everything in this target.  this->WriteTargetDriverRule(targetFullPath.c_str(), relink);  // Clean all the possible executable names and symlinks.  this->CleanFiles.insert(this->CleanFiles.end(),                          exeCleanFiles.begin(),                          exeCleanFiles.end());}
 |