| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389 |
- /*=========================================================================
- Program: CMake - Cross-Platform Makefile Generator
- Module: $RCSfile$
- Language: C++
- Date: $Date$
- Version: $Revision$
- Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
- See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
- This software is distributed WITHOUT ANY WARRANTY; without even
- the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- PURPOSE. See the above copyright notices for more information.
- =========================================================================*/
- #include "cmMakefileExecutableTargetGenerator.h"
- #include "cmGeneratedFileStream.h"
- #include "cmGlobalGenerator.h"
- #include "cmLocalUnixMakefileGenerator3.h"
- #include "cmMakefile.h"
- #include "cmSourceFile.h"
- #include "cmTarget.h"
- //----------------------------------------------------------------------------
- void cmMakefileExecutableTargetGenerator::WriteRuleFiles()
- {
- // create the build.make file and directory, put in the common blocks
- this->CreateRuleFile();
- // Add in any rules for custom commands
- this->WriteCustomCommandsForTarget();
- // write in rules for object files
- this->WriteCommonCodeRules();
- // Write the dependency generation rule.
- this->WriteTargetDependRules();
- // write the link rules
- this->WriteExecutableRule(false);
- if(this->Target->NeedRelinkBeforeInstall())
- {
- // Write rules to link an installable version of the target.
- this->WriteExecutableRule(true);
- }
- // Write the requires target.
- this->WriteTargetRequiresRules();
- // Write clean target
- this->WriteTargetCleanRules();
- // close the streams
- this->CloseFileStreams();
- }
- //----------------------------------------------------------------------------
- void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
- {
- std::vector<std::string> commands;
- std::string relPath = this->LocalGenerator->GetHomeRelativeOutputPath();
- std::string objTarget;
- // Build list of dependencies.
- std::vector<std::string> depends;
- 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 targets that must be built first.
- this->AppendTargetDepends(depends);
- // Add a dependency on the rule file itself.
- this->LocalGenerator->AppendRuleDepend(depends,
- this->BuildFileNameFull.c_str());
- for(std::vector<std::string>::const_iterator obj =
- this->ExternalObjects.begin();
- obj != this->ExternalObjects.end(); ++obj)
- {
- depends.push_back(*obj);
- }
- // from here up is the same for exe or lib
- // Get the name of the executable to generate.
- std::string targetName;
- std::string targetNameReal;
- this->Target->GetExecutableNames(targetName, targetNameReal,
- this->LocalGenerator->ConfigurationName.c_str());
- // Construct the full path version of the names.
- std::string outpath = this->LocalGenerator->ExecutableOutputPath;
- if(outpath.length() == 0)
- {
- outpath = this->Makefile->GetStartOutputDirectory();
- outpath += "/";
- }
- #ifdef __APPLE__
- if(this->Target->GetPropertyAsBool("MACOSX_BUNDLE"))
- {
- // Make bundle directories
- outpath += targetName;
- outpath += ".app/Contents/MacOS/";
- std::string f1 =
- this->Makefile->GetModulesFile("MacOSXBundleInfo.plist.in");
- if ( f1.size() == 0 )
- {
- cmSystemTools::Error("could not find Mac OSX bundle template file.");
- }
- std::string macdir =
- this->Makefile->GetSafeDefinition("EXECUTABLE_OUTPUT_PATH");
- if ( macdir.size() == 0 )
- {
- macdir = this->Makefile->GetCurrentOutputDirectory();
- }
- if(macdir.size() && macdir[macdir.size()-1] != '/')
- {
- macdir += "/";
- }
- macdir += targetName;
- macdir += ".app/Contents/";
- std::vector<cmSourceFile*>::iterator sourceIt;
- for ( sourceIt = this->Target->GetSourceFiles().begin();
- sourceIt != this->Target->GetSourceFiles().end();
- ++ sourceIt )
- {
- const char* subDir = (*sourceIt)->GetProperty("MACOSX_PACKAGE_LOCATION");
- if ( subDir )
- {
- std::string newDir = macdir;
- newDir += subDir;
- if ( !cmSystemTools::MakeDirectory(newDir.c_str()) )
- {
- cmSystemTools::Error("Cannot create a subdirectory for \"",
- newDir.c_str(), "\".");
- return;
- }
- }
- }
- // Configure the Info.plist file. Note that it needs the executable name
- // to be set.
- std::string f2 = macdir + "Info.plist";
- macdir += "MacOS";
- cmSystemTools::MakeDirectory(macdir.c_str());
- this->Makefile->AddDefinition("MACOSX_BUNDLE_EXECUTABLE_NAME",
- targetName.c_str());
- this->Makefile->ConfigureFile(f1.c_str(), f2.c_str(), false, false, false);
- }
- #endif
- if(relink)
- {
- outpath = this->Makefile->GetStartOutputDirectory();
- outpath += "/CMakeFiles/CMakeRelink.dir";
- cmSystemTools::MakeDirectory(outpath.c_str());
- outpath += "/";
- }
- std::string targetFullPath = outpath + targetName;
- std::string targetFullPathReal = outpath + targetNameReal;
- std::string targetFullPathPDB = outpath + this->Target->GetName();
- targetFullPathPDB += ".pdb";
- std::string targetOutPathPDB =
- this->Convert(targetFullPathPDB.c_str(),
- cmLocalGenerator::FULL,
- cmLocalGenerator::MAKEFILE);
- // Convert to the output path to use in constructing commands.
- std::string targetOutPath =
- this->Convert(targetFullPath.c_str(),
- cmLocalGenerator::START_OUTPUT,
- cmLocalGenerator::MAKEFILE);
- std::string targetOutPathReal =
- this->Convert(targetFullPathReal.c_str(),
- cmLocalGenerator::START_OUTPUT,
- cmLocalGenerator::MAKEFILE);
-
- // Get the language to use for linking this executable.
- const char* linkLanguage =
- this->Target->GetLinkerLanguage(this->GlobalGenerator);
- // Make sure we have a link language.
- if(!linkLanguage)
- {
- cmSystemTools::Error("Cannot determine link language for target \"",
- this->Target->GetName(), "\".");
- return;
- }
- // 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 deal with shared libraries. Any library being
- // linked in might be shared, so always use shared flags for an
- // executable.
- this->LocalGenerator->AddSharedFlags(linkFlags, linkLanguage, true);
- // Add flags to create an executable.
- this->LocalGenerator->
- AddConfigVariableFlags(linkFlags, "CMAKE_EXE_LINKER_FLAGS",
- this->LocalGenerator->ConfigurationName.c_str());
- 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 language-specific flags.
- this->LocalGenerator
- ->AddLanguageFlags(flags, linkLanguage,
- this->LocalGenerator->ConfigurationName.c_str());
- // Add target-specific linker flags.
- this->LocalGenerator->AppendFlags(linkFlags, this->Target->GetProperty("LINK_FLAGS"));
- std::string linkFlagsConfig = "LINK_FLAGS_";
- linkFlagsConfig += cmSystemTools::UpperCase(this->LocalGenerator->ConfigurationName.c_str());
- this->LocalGenerator->AppendFlags(linkFlags,
- this->Target->GetProperty(linkFlagsConfig.c_str()));
- // Construct a list of files associated with this executable that
- // may need to be cleaned.
- std::vector<std::string> exeCleanFiles;
- {
- std::string cleanName;
- std::string cleanRealName;
- this->Target->GetExecutableCleanNames(cleanName, cleanRealName,
- this->LocalGenerator->ConfigurationName.c_str());
- std::string cleanFullName = outpath + cleanName;
- std::string cleanFullRealName = outpath + cleanRealName;
- exeCleanFiles.push_back(this->Convert(cleanFullName.c_str(),
- cmLocalGenerator::START_OUTPUT,
- cmLocalGenerator::UNCHANGED));
- if(cleanRealName != cleanName)
- {
- exeCleanFiles.push_back(this->Convert(cleanFullRealName.c_str(),
- cmLocalGenerator::START_OUTPUT,
- cmLocalGenerator::UNCHANGED));
- }
- }
- // Add a command to remove any existing files for this executable.
- std::vector<std::string> commands1;
- this->LocalGenerator->AppendCleanCommand(commands1, exeCleanFiles,
- *this->Target, "target");
- this->LocalGenerator->CreateCDCommand(commands1,
- this->Makefile->GetStartOutputDirectory(),
- this->Makefile->GetHomeOutputDirectory());
- commands.insert(commands.end(), commands1.begin(), commands1.end());
- commands1.clear();
- // Add the pre-build and pre-link rules building but not when relinking.
- if(!relink)
- {
- this->LocalGenerator
- ->AppendCustomCommands(commands, this->Target->GetPreBuildCommands());
- this->LocalGenerator
- ->AppendCustomCommands(commands, this->Target->GetPreLinkCommands());
- }
- // Construct the main link rule.
- std::string linkRuleVar = "CMAKE_";
- linkRuleVar += linkLanguage;
- linkRuleVar += "_LINK_EXECUTABLE";
- std::string linkRule =
- this->Makefile->GetRequiredDefinition(linkRuleVar.c_str());
- cmSystemTools::ExpandListArgument(linkRule, commands1);
- this->LocalGenerator->CreateCDCommand
- (commands1,
- this->Makefile->GetStartOutputDirectory(),
- this->Makefile->GetHomeOutputDirectory());
- commands.insert(commands.end(), commands1.begin(), commands1.end());
- // 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;
- commands.push_back(symlink);
- }
- // Add the post-build rules when building but not when relinking.
- if(!relink)
- {
- this->LocalGenerator->
- AppendCustomCommands(commands, this->Target->GetPostBuildCommands());
- }
- // Collect up flags to link in needed libraries.
- cmOStringStream linklibs;
- this->LocalGenerator->OutputLinkLibraries(linklibs, *this->Target, relink);
- // Construct object file lists that may be needed to expand the
- // rule.
- std::string variableName;
- std::string variableNameExternal;
- this->WriteObjectsVariable(variableName, variableNameExternal);
- std::string buildObjs = "$(";
- buildObjs += variableName;
- buildObjs += ") $(";
- buildObjs += variableNameExternal;
- buildObjs += ")";
- std::string cleanObjs = "$(";
- cleanObjs += variableName;
- cleanObjs += ")";
- cmLocalGenerator::RuleVariables vars;
- vars.Language = linkLanguage;
- vars.Objects = buildObjs.c_str();
- vars.Target = targetOutPathReal.c_str();
- vars.TargetPDB = targetOutPathPDB.c_str();
- std::string linkString = linklibs.str();
- vars.LinkLibraries = linkString.c_str();
- vars.Flags = flags.c_str();
- vars.LinkFlags = linkFlags.c_str();
- // Expand placeholders in the commands.
- for(std::vector<std::string>::iterator i = commands.begin();
- i != commands.end(); ++i)
- {
- this->LocalGenerator->ExpandRuleVariables(*i, vars);
- }
- // 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 convenience targets.
- std::string dir = this->Makefile->GetStartOutputDirectory();
- dir += "/";
- dir += this->LocalGenerator->GetTargetDirectory(*this->Target);
- std::string buildTargetRuleName = dir;
- buildTargetRuleName += relink?"/preinstall":"/build";
- buildTargetRuleName =
- this->Convert(buildTargetRuleName.c_str(),
- cmLocalGenerator::HOME_OUTPUT,
- cmLocalGenerator::MAKEFILE);
- this->LocalGenerator->WriteConvenienceRule(*this->BuildFileStream,
- targetFullPath.c_str(),
- buildTargetRuleName.c_str());
- // Clean all the possible executable names and symlinks and object files.
- this->CleanFiles.insert(this->CleanFiles.end(),
- exeCleanFiles.begin(),
- exeCleanFiles.end());
- this->CleanFiles.insert(this->CleanFiles.end(),
- this->Objects.begin(),
- this->Objects.end());
- }
|