diff options
author | Ken Martin <ken.martin@kitware.com> | 2006-02-14 15:36:04 (GMT) |
---|---|---|
committer | Ken Martin <ken.martin@kitware.com> | 2006-02-14 15:36:04 (GMT) |
commit | 7740ccd1a41e837b89cd5bb7b87d9654b7b745a2 (patch) | |
tree | 126259e7c3b07471a47f0e596f1d6f63bf001a51 /Source/cmMakefileLibraryTargetGenerator.cxx | |
parent | 3bce601c41b8487a18417e32b75c0e22f0750bbc (diff) | |
download | CMake-7740ccd1a41e837b89cd5bb7b87d9654b7b745a2.zip CMake-7740ccd1a41e837b89cd5bb7b87d9654b7b745a2.tar.gz CMake-7740ccd1a41e837b89cd5bb7b87d9654b7b745a2.tar.bz2 |
ENH: some cleanup of the makefile generator
Diffstat (limited to 'Source/cmMakefileLibraryTargetGenerator.cxx')
-rw-r--r-- | Source/cmMakefileLibraryTargetGenerator.cxx | 394 |
1 files changed, 394 insertions, 0 deletions
diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx new file mode 100644 index 0000000..89057f6 --- /dev/null +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -0,0 +1,394 @@ +/*========================================================================= + + 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 "cmMakefileLibraryTargetGenerator.h" + +#include "cmGeneratedFileStream.h" +#include "cmGlobalGenerator.h" +#include "cmLocalUnixMakefileGenerator3.h" +#include "cmMakefile.h" +#include "cmSourceFile.h" +#include "cmTarget.h" + +//---------------------------------------------------------------------------- +void cmMakefileLibraryTargetGenerator::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 link rules + // Write the rule for this target type. + switch(this->Target->GetType()) + { + case cmTarget::STATIC_LIBRARY: + this->WriteStaticLibraryRules(); + break; + case cmTarget::SHARED_LIBRARY: + this->WriteSharedLibraryRules(); + break; + case cmTarget::MODULE_LIBRARY: + this->WriteModuleLibraryRules(); + break; + default: + // If language is not known, this is an error. + cmSystemTools::Error("Unknown Library Type"); + break; + } + + // Write the requires target. + this->WriteTargetRequiresRules(); + + // Write clean target + this->WriteTargetCleanRules(); + + // close the streams + this->CloseFileStreams(); +} + + +//---------------------------------------------------------------------------- +void cmMakefileLibraryTargetGenerator::WriteStaticLibraryRules() +{ + const char* linkLanguage = + this->Target->GetLinkerLanguage(this->GlobalGenerator); + std::string linkRuleVar = "CMAKE_"; + if (linkLanguage) + { + linkRuleVar += linkLanguage; + } + linkRuleVar += "_CREATE_STATIC_LIBRARY"; + + std::string extraFlags; + this->LocalGenerator->AppendFlags(extraFlags, this->Target->GetProperty("STATIC_LIBRARY_FLAGS")); + this->WriteLibraryRules(linkRuleVar.c_str(), extraFlags.c_str()); +} + +//---------------------------------------------------------------------------- +void cmMakefileLibraryTargetGenerator::WriteSharedLibraryRules() +{ + const char* linkLanguage = + this->Target->GetLinkerLanguage(this->GlobalGenerator); + std::string linkRuleVar = "CMAKE_"; + if (linkLanguage) + { + linkRuleVar += linkLanguage; + } + linkRuleVar += "_CREATE_SHARED_LIBRARY"; + + std::string extraFlags; + this->LocalGenerator->AppendFlags(extraFlags, this->Target->GetProperty("LINK_FLAGS")); + this->LocalGenerator->AddConfigVariableFlags(extraFlags, "CMAKE_SHARED_LINKER_FLAGS"); + if(this->Makefile->IsOn("WIN32") && !(this->Makefile->IsOn("CYGWIN") || this->Makefile->IsOn("MINGW"))) + { + const std::vector<cmSourceFile*>& sources = this->Target->GetSourceFiles(); + for(std::vector<cmSourceFile*>::const_iterator i = sources.begin(); + i != sources.end(); ++i) + { + if((*i)->GetSourceExtension() == "def") + { + extraFlags += " "; + extraFlags += this->Makefile->GetSafeDefinition("CMAKE_LINK_DEF_FILE_FLAG"); + extraFlags += + this->Convert((*i)->GetFullPath().c_str(),cmLocalGenerator::START_OUTPUT,cmLocalGenerator::MAKEFILE); + } + } + } + this->WriteLibraryRules(linkRuleVar.c_str(), extraFlags.c_str()); +} + +//---------------------------------------------------------------------------- +void cmMakefileLibraryTargetGenerator::WriteModuleLibraryRules() +{ + const char* linkLanguage = + this->Target->GetLinkerLanguage(this->GlobalGenerator); + std::string linkRuleVar = "CMAKE_"; + if (linkLanguage) + { + linkRuleVar += linkLanguage; + } + linkRuleVar += "_CREATE_SHARED_MODULE"; + + std::string extraFlags; + this->LocalGenerator->AppendFlags(extraFlags, this->Target->GetProperty("LINK_FLAGS")); + this->LocalGenerator->AddConfigVariableFlags(extraFlags, "CMAKE_MODULE_LINKER_FLAGS"); + // TODO: .def files should be supported here also. + this->WriteLibraryRules(linkRuleVar.c_str(), extraFlags.c_str()); +} + +//---------------------------------------------------------------------------- +void cmMakefileLibraryTargetGenerator::WriteLibraryRules +(const char* linkRuleVar, const char* extraFlags) +{ + // Write the dependency generation rule. + this->WriteTargetDependRules(); + + // TODO: Merge the methods that call this method to avoid + // code duplication. + 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); + } + + // Get the language to use for linking this library. + 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; + } + + // Create set of linking flags. + std::string linkFlags; + this->LocalGenerator->AppendFlags(linkFlags, extraFlags); + + // Construct the name of the library. + std::string targetName; + std::string targetNameSO; + std::string targetNameReal; + this->Target->GetLibraryNames(targetName, targetNameSO, targetNameReal, + this->LocalGenerator->m_ConfigurationName.c_str()); + + // Construct the full path version of the names. + std::string outpath = this->LocalGenerator->m_LibraryOutputPath; + if(outpath.length() == 0) + { + outpath = this->Makefile->GetStartOutputDirectory(); + outpath += "/"; + } + std::string targetFullPath = outpath + targetName; + std::string targetFullPathSO = outpath + targetNameSO; + std::string targetFullPathReal = outpath + targetNameReal; + + // Construct the output path version of the names for use in command + // arguments. + std::string targetOutPath = + this->Convert(targetFullPath.c_str(),cmLocalGenerator::START_OUTPUT, + cmLocalGenerator::MAKEFILE); + std::string targetOutPathSO = + this->Convert(targetFullPathSO.c_str(),cmLocalGenerator::START_OUTPUT, + cmLocalGenerator::MAKEFILE); + std::string targetOutPathReal = + this->Convert(targetFullPathReal.c_str(),cmLocalGenerator::START_OUTPUT, + cmLocalGenerator::MAKEFILE); + + // Add the link message. + std::string buildEcho = "Linking "; + buildEcho += linkLanguage; + switch(this->Target->GetType()) + { + case cmTarget::STATIC_LIBRARY: + buildEcho += " static library "; break; + case cmTarget::SHARED_LIBRARY: + buildEcho += " shared library "; break; + case cmTarget::MODULE_LIBRARY: + buildEcho += " shared module "; break; + default: + buildEcho += " library "; break; + } + buildEcho += targetOutPath.c_str(); + this->LocalGenerator->AppendEcho(commands, buildEcho.c_str()); + + // Construct a list of files associated with this library that may + // need to be cleaned. + std::vector<std::string> libCleanFiles; + { + std::string cleanStaticName; + std::string cleanSharedName; + std::string cleanSharedSOName; + std::string cleanSharedRealName; + this->Target->GetLibraryCleanNames(cleanStaticName, + cleanSharedName, + cleanSharedSOName, + cleanSharedRealName, + this->LocalGenerator->m_ConfigurationName.c_str()); + std::string cleanFullStaticName = outpath + cleanStaticName; + std::string cleanFullSharedName = outpath + cleanSharedName; + std::string cleanFullSharedSOName = outpath + cleanSharedSOName; + std::string cleanFullSharedRealName = outpath + cleanSharedRealName; + libCleanFiles.push_back + (this->Convert(cleanFullStaticName.c_str(),cmLocalGenerator::START_OUTPUT, + cmLocalGenerator::MAKEFILE)); + if(cleanSharedRealName != cleanStaticName) + { + libCleanFiles.push_back(this->Convert(cleanFullSharedRealName.c_str(), + cmLocalGenerator::START_OUTPUT, + cmLocalGenerator::MAKEFILE)); + } + if(cleanSharedSOName != cleanStaticName && + cleanSharedSOName != cleanSharedRealName) + { + libCleanFiles.push_back(this->Convert(cleanFullSharedSOName.c_str(), + cmLocalGenerator::START_OUTPUT, + cmLocalGenerator::MAKEFILE)); + } + if(cleanSharedName != cleanStaticName && + cleanSharedName != cleanSharedSOName && + cleanSharedName != cleanSharedRealName) + { + libCleanFiles.push_back(this->Convert(cleanFullSharedName.c_str(), + cmLocalGenerator::START_OUTPUT, + cmLocalGenerator::MAKEFILE)); + } + } + // Add a command to remove any existing files for this library. + std::vector<std::string> commands1; + this->LocalGenerator->AppendCleanCommand(commands1, libCleanFiles); + 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. + this->LocalGenerator->AppendCustomCommands(commands, this->Target->GetPreBuildCommands()); + this->LocalGenerator->AppendCustomCommands(commands, this->Target->GetPreLinkCommands()); + + // Construct the main link rule. + std::string linkRule = this->Makefile->GetRequiredDefinition(linkRuleVar); + 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_library "; + symlink += targetOutPathReal; + symlink += " "; + symlink += targetOutPathSO; + symlink += " "; + symlink += targetOutPath; + commands1.clear(); + commands1.push_back(symlink); + this->LocalGenerator->CreateCDCommand(commands1, + this->Makefile->GetStartOutputDirectory(), + this->Makefile->GetHomeOutputDirectory()); + commands.insert(commands.end(), commands1.begin(), commands1.end()); + } + + // Add the post-build rules. + this->LocalGenerator->AppendCustomCommands(commands, this->Target->GetPostBuildCommands()); + + // Collect up flags to link in needed libraries. + cmOStringStream linklibs; + this->LocalGenerator->OutputLinkLibraries(linklibs, *this->Target); + + // 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 += ")"; + + // Expand placeholders in the commands. + for(std::vector<std::string>::iterator i = commands.begin(); + i != commands.end(); ++i) + { + this->LocalGenerator->ExpandRuleVariables(*i, + linkLanguage, + buildObjs.c_str(), + targetOutPathReal.c_str(), + linklibs.str().c_str(), + 0, 0, 0, buildObjs.c_str(), + targetNameSO.c_str(), + linkFlags.c_str()); + } + + // Write the build rule. + this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0, + targetFullPathReal.c_str(), depends, commands); + + // The symlink names for the target should depend on the real target + // so if the target version changes it rebuilds and recreates the + // symlinks. + if(targetFullPathSO != targetFullPathReal) + { + depends.clear(); + commands.clear(); + depends.push_back(targetFullPathReal.c_str()); + this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0, + targetFullPathSO.c_str(), depends, commands); + } + if(targetFullPath != targetFullPathSO) + { + depends.clear(); + commands.clear(); + depends.push_back(targetFullPathSO.c_str()); + this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0, + targetFullPath.c_str(), depends, commands); + } + + // Write convenience targets. + std::string dir = this->Makefile->GetStartOutputDirectory(); + dir += "/"; + dir += this->LocalGenerator->GetTargetDirectory(*this->Target); + std::string buildTargetRuleName = dir; + buildTargetRuleName += "/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 library names and symlinks and object files. + this->CleanFiles.insert(this->CleanFiles.end(), + libCleanFiles.begin(),libCleanFiles.end()); + this->CleanFiles.push_back(cleanObjs); +} + |