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 | |
parent | 3bce601c41b8487a18417e32b75c0e22f0750bbc (diff) | |
download | CMake-7740ccd1a41e837b89cd5bb7b87d9654b7b745a2.zip CMake-7740ccd1a41e837b89cd5bb7b87d9654b7b745a2.tar.gz CMake-7740ccd1a41e837b89cd5bb7b87d9654b7b745a2.tar.bz2 |
ENH: some cleanup of the makefile generator
-rw-r--r-- | Source/cmMakefileExecutableTargetGenerator.cxx | 334 | ||||
-rw-r--r-- | Source/cmMakefileExecutableTargetGenerator.h | 34 | ||||
-rw-r--r-- | Source/cmMakefileLibraryTargetGenerator.cxx | 394 | ||||
-rw-r--r-- | Source/cmMakefileLibraryTargetGenerator.h | 37 | ||||
-rw-r--r-- | Source/cmMakefileTargetGenerator.cxx | 794 | ||||
-rw-r--r-- | Source/cmMakefileTargetGenerator.h | 152 | ||||
-rw-r--r-- | Source/cmMakefileUtilityTargetGenerator.cxx | 90 | ||||
-rw-r--r-- | Source/cmMakefileUtilityTargetGenerator.h | 34 |
8 files changed, 1869 insertions, 0 deletions
diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx new file mode 100644 index 0000000..03acb8c --- /dev/null +++ b/Source/cmMakefileExecutableTargetGenerator.cxx @@ -0,0 +1,334 @@ +/*========================================================================= + + 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 link rules + this->WriteExecutableRule(); + + // Write the requires target. + this->WriteTargetRequiresRules(); + + // Write clean target + this->WriteTargetCleanRules(); + + // close the streams + this->CloseFileStreams(); +} + + + +//---------------------------------------------------------------------------- +void cmMakefileExecutableTargetGenerator::WriteExecutableRule() +{ + // Write the dependency generation rule. + this->WriteTargetDependRules(); + + 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->m_ConfigurationName.c_str()); + + // Construct the full path version of the names. + std::string outpath = this->LocalGenerator->m_ExecutableOutputPath; + if(outpath.length() == 0) + { + outpath = this->Makefile->GetStartOutputDirectory(); + outpath += "/"; + } +#ifdef __APPLE__ + if(this->Target->GetPropertyAsBool("MACOSX_BUNDLE")) + { + // Make bundle directories + outpath += this->Target->GetName(); + 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 += this->Target->GetName(); + macdir += ".app/Contents/"; + std::string f2 = macdir + "Info.plist"; + macdir += "MacOS"; + cmSystemTools::MakeDirectory(macdir.c_str()); + this->Makefile->AddDefinition("MACOSX_BUNDLE_EXECUTABLE_NAME", this->Target->GetName()); + this->Makefile->ConfigureFile(f1.c_str(), f2.c_str(), + false, false, false); + } +#endif + std::string targetFullPath = outpath + targetName; + std::string targetFullPathReal = outpath + targetNameReal; + + // 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()); + + // 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"); + + + 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); + + // Add target-specific linker flags. + this->LocalGenerator->AppendFlags(linkFlags, this->Target->GetProperty("LINK_FLAGS")); + + // 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->m_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::MAKEFILE)); + if(cleanRealName != cleanName) + { + exeCleanFiles.push_back(this->Convert(cleanFullRealName.c_str(), + cmLocalGenerator::START_OUTPUT, + cmLocalGenerator::MAKEFILE)); + } + } + + // Add a command to remove any existing files for this executable. + std::vector<std::string> commands1; + this->LocalGenerator->AppendCleanCommand(commands1, exeCleanFiles); + 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 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. + 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, + flags.c_str(), + 0, + 0, + linkFlags.c_str()); + } + + // Write the build rule. + this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, + 0, + targetFullPathReal.c_str(), + depends, commands); + + // 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); + } + + // 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 executable names and symlinks and object files. + this->CleanFiles.insert(this->CleanFiles.end(), + exeCleanFiles.begin(), + exeCleanFiles.end()); + this->CleanFiles.push_back(cleanObjs); +} + diff --git a/Source/cmMakefileExecutableTargetGenerator.h b/Source/cmMakefileExecutableTargetGenerator.h new file mode 100644 index 0000000..a02286c --- /dev/null +++ b/Source/cmMakefileExecutableTargetGenerator.h @@ -0,0 +1,34 @@ +/*========================================================================= + + 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. + +=========================================================================*/ +#ifndef cmMakefileExecutableTargetGenerator_h +#define cmMakefileExecutableTargetGenerator_h + +#include "cmMakefileTargetGenerator.h" + +class cmMakefileExecutableTargetGenerator: public cmMakefileTargetGenerator +{ +public: + /* the main entry point for this class. Writes the Makefiles associated + with this target */ + virtual void WriteRuleFiles(); + +protected: + virtual void WriteExecutableRule(); + +}; + +#endif 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); +} + diff --git a/Source/cmMakefileLibraryTargetGenerator.h b/Source/cmMakefileLibraryTargetGenerator.h new file mode 100644 index 0000000..7c7c43d --- /dev/null +++ b/Source/cmMakefileLibraryTargetGenerator.h @@ -0,0 +1,37 @@ +/*========================================================================= + + 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. + +=========================================================================*/ +#ifndef cmMakefileLibraryTargetGenerator_h +#define cmMakefileLibraryTargetGenerator_h + +#include "cmMakefileTargetGenerator.h" + +class cmMakefileLibraryTargetGenerator: + public cmMakefileTargetGenerator +{ +public: + /* the main entry point for this class. Writes the Makefiles associated + with this target */ + virtual void WriteRuleFiles(); + +protected: + void WriteStaticLibraryRules(); + void WriteSharedLibraryRules(); + void WriteModuleLibraryRules(); + void WriteLibraryRules(const char *linkRule, const char *extraFlags); +}; + +#endif diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx new file mode 100644 index 0000000..87bef28 --- /dev/null +++ b/Source/cmMakefileTargetGenerator.cxx @@ -0,0 +1,794 @@ +/*========================================================================= + + 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 "cmMakefileTargetGenerator.h" + +#include "cmGeneratedFileStream.h" +#include "cmGlobalGenerator.h" +#include "cmLocalUnixMakefileGenerator3.h" +#include "cmMakefile.h" +#include "cmSourceFile.h" +#include "cmTarget.h" + +#include "cmMakefileExecutableTargetGenerator.h" +#include "cmMakefileLibraryTargetGenerator.h" +#include "cmMakefileUtilityTargetGenerator.h" + + +cmMakefileTargetGenerator::cmMakefileTargetGenerator() +{ + this->BuildFileStream = 0; + this->InfoFileStream = 0; + this->FlagFileStream = 0; +} + +cmMakefileTargetGenerator * +cmMakefileTargetGenerator::New(cmLocalUnixMakefileGenerator3 *lg, + cmStdString tgtName, cmTarget *tgt) +{ + cmMakefileTargetGenerator *result = 0; + + switch (tgt->GetType()) + { + case cmTarget::EXECUTABLE: + result = new cmMakefileExecutableTargetGenerator; + break; + case cmTarget::STATIC_LIBRARY: + case cmTarget::SHARED_LIBRARY: + case cmTarget::MODULE_LIBRARY: + result = new cmMakefileLibraryTargetGenerator; + break; + case cmTarget::UTILITY: + result = new cmMakefileUtilityTargetGenerator; + break; + default: + return 0; + break; + } + + result->TargetName = tgtName; + result->Target = tgt; + result->LocalGenerator = lg; + result->GlobalGenerator = lg->GetGlobalGenerator(); + result->Makefile = lg->GetMakefile(); + return result; +} + +//---------------------------------------------------------------------------- +void cmMakefileTargetGenerator::CreateRuleFile() +{ + // Create a directory for this target. + this->TargetBuildDirectory = + this->LocalGenerator->GetTargetDirectory(*this->Target); + this->TargetBuildDirectoryFull = + this->LocalGenerator->ConvertToFullPath(this->TargetBuildDirectory); + cmSystemTools::MakeDirectory(this->TargetBuildDirectoryFull.c_str()); + + // Construct the rule file name. + this->BuildFileName = this->TargetBuildDirectory; + this->BuildFileName += "/build.make"; + this->BuildFileNameFull = this->TargetBuildDirectoryFull; + this->BuildFileNameFull += "/build.make"; + + // 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()); + this->BuildFileStream->SetCopyIfDifferent(true); + if(!this->BuildFileStream) + { + return; + } + this->LocalGenerator->WriteDisclaimer(*this->BuildFileStream); + this->LocalGenerator->WriteSpecialTargetsTop(*this->BuildFileStream); + this->LocalGenerator->WriteMakeVariables(*this->BuildFileStream); +} + +//---------------------------------------------------------------------------- +void cmMakefileTargetGenerator::WriteCustomCommandsForTarget() +{ + // 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); + } + this->WriteCustomCommands(); +} + + +//---------------------------------------------------------------------------- +void cmMakefileTargetGenerator::WriteCommonCodeRules() +{ + // 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->m_IncludeDirective << " " + << this->Convert(dependFileNameFull.c_str(), + cmLocalGenerator::HOME_OUTPUT, + cmLocalGenerator::MAKEFILE) + << "\n\n"; + + // make sure the depend file exists + 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; + } + + // 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()); + this->FlagFileStream->SetCopyIfDifferent(true); + 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->m_IncludeDirective << " " + << this->Convert(this->FlagFileNameFull.c_str(), + cmLocalGenerator::HOME_OUTPUT, + cmLocalGenerator::MAKEFILE) + << "\n\n"; + + // First generate the object rule files. Save a list of all object + // files for this target. + const std::vector<cmSourceFile*>& sources = this->Target->GetSourceFiles(); + for(std::vector<cmSourceFile*>::const_iterator source = sources.begin(); + source != sources.end(); ++source) + { + if(!(*source)->GetPropertyAsBool("HEADER_FILE_ONLY") && + !(*source)->GetCustomCommand()) + { + if(!this->GlobalGenerator->IgnoreFile + ((*source)->GetSourceExtension().c_str())) + { + // Generate this object file's rule file. + this->WriteObjectRuleFiles(*(*source)); + } + else if((*source)->GetPropertyAsBool("EXTERNAL_OBJECT")) + { + // This is an external object file. Just add it. + this->ExternalObjects.push_back((*source)->GetFullPath()); + } + else + { + // We only get here if a source file is not an external object + // and has an extension that is listed as an ignored file type + // for this language. No message or diagnosis should be + // given. + } + } + } + + // write language flags for target + std::map<cmStdString,cmLocalUnixMakefileGenerator3::IntegrityCheckSet>& + checkSet = + this->LocalGenerator->GetIntegrityCheckSet()[this->Target->GetName()]; + for(std::map<cmStdString, + cmLocalUnixMakefileGenerator3::IntegrityCheckSet>::const_iterator + l = checkSet.begin(); l != checkSet.end(); ++l) + { + const char *lang = l->first.c_str(); + std::string flags; + // Add the export symbol definition for shared library objects. + bool shared = ((this->Target->GetType() == cmTarget::SHARED_LIBRARY) || + (this->Target->GetType() == cmTarget::MODULE_LIBRARY)); + if(shared) + { + flags += "-D"; + if(const char* custom_export_name = + this->Target->GetProperty("DEFINE_SYMBOL")) + { + flags += custom_export_name; + } + else + { + std::string in = this->Target->GetName(); + in += "_EXPORTS"; + flags += cmSystemTools::MakeCindentifier(in.c_str()); + } + } + + // Add language-specific flags. + this->LocalGenerator->AddLanguageFlags(flags, lang); + + // Add shared-library flags if needed. + this->LocalGenerator->AddSharedFlags(flags, lang, shared); + + // Add include directory flags. + this->LocalGenerator-> + AppendFlags(flags, this->LocalGenerator->GetIncludeFlags(lang)); + // Add include directory flags. + this->LocalGenerator-> + AppendFlags(flags,this->GetFrameworkFlags().c_str()); + + *this->FlagFileStream << lang << "_FLAGS = " << flags << "\n\n"; + } +} + + + +//---------------------------------------------------------------------------- +void cmMakefileTargetGenerator::WriteObjectRuleFiles(cmSourceFile& source) +{ + // Identify the language of the source file. + const char* lang = this->LocalGenerator->GetSourceFileLanguage(source); + if(!lang) + { + // If language is not known, this is an error. + cmSystemTools::Error("Source file \"", source.GetFullPath().c_str(), + "\" has unknown type."); + return; + } + + // Get the full path name of the object file. + std::string objNoTargetDir; + std::string obj = + this->LocalGenerator->GetObjectFileName(*this->Target, source, &objNoTargetDir); + + // Avoid generating duplicate rules. + if(m_ObjectFiles.find(obj) == m_ObjectFiles.end()) + { + m_ObjectFiles.insert(obj); + } + else + { + cmOStringStream err; + err << "Warning: Source file \"" + << source.GetSourceName().c_str() << "." + << source.GetSourceExtension().c_str() + << "\" is listed multiple times for target \"" + << this->Target->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()); + + // Save this in the target's list of object files. + this->Objects.push_back(obj); + std::string relativeObj = this->LocalGenerator->GetHomeRelativeOutputPath(); + 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. + this->LocalGenerator->m_CheckDependFiles[this->Target->GetName()][lang].insert(&source); + // add this to the list of objects for this local generator + if(cmSystemTools::FileIsFullPath(objNoTargetDir.c_str())) + { + objNoTargetDir = cmSystemTools::GetFilenameName(objNoTargetDir); + } + this->LocalGenerator->m_LocalObjectFiles[objNoTargetDir].push_back(this->Target); +} + +//---------------------------------------------------------------------------- +void +cmMakefileTargetGenerator +::WriteObjectBuildFile(std::string &obj, + const char *lang, + cmSourceFile& source, + std::vector<std::string>& depends) +{ + this->LocalGenerator->AppendRuleDepend(depends, this->FlagFileNameFull.c_str()); + + // generate the depend scanning rule + this->WriteObjectDependRules(source, depends); + + std::string relativeObj = this->LocalGenerator->GetHomeRelativeOutputPath(); + relativeObj += obj; + if(this->Makefile->GetDefinition("CMAKE_WINDOWS_OBJECT_PATH")) + { + relativeObj = cmSystemTools::ConvertToOutputPath(relativeObj.c_str()); + } + // Write the build rule. + // Build the set of compiler flags. + std::string flags; + if(this->Target->GetProperty("COMPILE_FLAGS")) + { + this->LocalGenerator->AppendFlags(flags, this->Target->GetProperty("COMPILE_FLAGS")); + } + + // 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" + << "\n"; + } + + // Add language-specific flags. + std::string langFlags = "$("; + langFlags += lang; + langFlags += "_FLAGS)"; + this->LocalGenerator->AppendFlags(flags, langFlags.c_str()); + + // Get the output paths for source and object files. + std::string sourceFile = source.GetFullPath(); + if(this->LocalGenerator->m_UseRelativePaths) + { + sourceFile = this->Convert(sourceFile.c_str(), + cmLocalGenerator::HOME_OUTPUT); + } + sourceFile = this->Convert(sourceFile.c_str(), + cmLocalGenerator::NONE, + cmLocalGenerator::SHELL); + std::string objectFile = + this->Convert(obj.c_str(), + cmLocalGenerator::START_OUTPUT, + cmLocalGenerator::SHELL); + + // Construct the build message. + std::vector<std::string> no_commands; + std::vector<std::string> commands; + std::string buildEcho = "Building "; + buildEcho += lang; + buildEcho += " object "; + buildEcho += relativeObj; + this->LocalGenerator->AppendEcho(commands, buildEcho.c_str()); + + // Construct the compile rules. + std::string compileRuleVar = "CMAKE_"; + compileRuleVar += lang; + compileRuleVar += "_COMPILE_OBJECT"; + std::string compileRule = + this->Makefile->GetRequiredDefinition(compileRuleVar.c_str()); + cmSystemTools::ExpandListArgument(compileRule, commands); + + // Expand placeholders in the commands. + for(std::vector<std::string>::iterator i = commands.begin(); + i != commands.end(); ++i) + { + this->LocalGenerator->ExpandRuleVariables(*i, + lang, + 0, // no objects + 0, // no target + 0, // no link libs + sourceFile.c_str(), + relativeObj.c_str(), + flags.c_str()); + } + + // Make the target dependency scanning rule include cmake-time-known + // dependencies. The others are handled by the check-build-system + // path. + std::string depMark = + this->LocalGenerator->GetRelativeTargetDirectory(*this->Target); + depMark += "/depend.make.mark"; + this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0, + depMark.c_str(), depends, no_commands); + + // Write the rule. + this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0, + relativeObj.c_str(), depends, commands); + + // If the language needs provides-requires mode, create the + // corresponding targets. + std::string objectRequires = relativeObj; + 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); + + // write a build rule to recursively build what this obj provides + std::string objectProvides = relativeObj; + objectProvides += ".provides"; + std::string temp = relativeObj; + temp += ".provides.build"; + std::vector<std::string> r_commands; + std::string tgtMakefileName = + this->LocalGenerator->GetRelativeTargetDirectory(*this->Target); + tgtMakefileName += "/build.make"; + r_commands.push_back + (this->LocalGenerator->GetRecursiveMakeCall(tgtMakefileName.c_str(),temp.c_str())); + p_depends.clear(); + p_depends.push_back(objectRequires); + this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0, + objectProvides.c_str(), p_depends, + r_commands); + + // 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); +} + +//---------------------------------------------------------------------------- +void cmMakefileTargetGenerator::WriteTargetRequiresRules() +{ + std::vector<std::string> depends; + std::vector<std::string> no_commands; + + // Construct the name of the dependency generation target. + std::string depTarget = + this->LocalGenerator->GetRelativeTargetDirectory(*this->Target); + 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) + { + 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); +} + +//---------------------------------------------------------------------------- +void cmMakefileTargetGenerator::WriteTargetCleanRules() +{ + std::vector<std::string> depends; + const char* sym = this->Makefile->GetDefinition("CMAKE_MAKE_SYMBOLIC_RULE"); + if(sym) + { + depends.push_back(sym); + } + std::vector<std::string> commands; + + // Construct the clean target name. + std::string cleanTarget = + this->LocalGenerator->GetRelativeTargetDirectory(*this->Target); + cleanTarget += "/clean"; + + // Construct the clean command. + this->LocalGenerator->AppendCleanCommand(commands, this->CleanFiles); + this->LocalGenerator->CreateCDCommand(commands, + this->Makefile->GetStartOutputDirectory(), + this->Makefile->GetHomeOutputDirectory()); + + // Write the rule. + this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0, + cleanTarget.c_str(), depends, commands); +} + + +//---------------------------------------------------------------------------- +void cmMakefileTargetGenerator::WriteTargetDependRules() +{ + // must write the targets depend info file + std::string dir = this->LocalGenerator->GetTargetDirectory(*this->Target); + this->InfoFileNameFull = dir; + this->InfoFileNameFull += "/DependInfo.cmake"; + this->InfoFileNameFull = + this->LocalGenerator->ConvertToFullPath(this->InfoFileNameFull); + this->InfoFileStream = + new cmGeneratedFileStream(this->InfoFileNameFull.c_str()); + this->InfoFileStream->SetCopyIfDifferent(true); + if(!*this->InfoFileStream) + { + return; + } + this->LocalGenerator-> + WriteDependLanguageInfo(*this->InfoFileStream,*this->Target); + + // and now write the rule to use it + std::vector<std::string> depends; + std::vector<std::string> commands; + + // Construct the name of the dependency generation target. + std::string depTarget = + this->LocalGenerator->GetRelativeTargetDirectory(*this->Target); + depTarget += "/depend"; + + std::string depMark = depTarget; + depMark += ".make.mark"; + depends.push_back(depMark); + + this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0, + depTarget.c_str(), depends, commands); + depends.clear(); + + // Write the dependency generation rule. + std::string depEcho = "Scanning dependencies of target "; + depEcho += this->Target->GetName(); + this->LocalGenerator->AppendEcho(commands, depEcho.c_str()); + + // 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. + depCmd << "$(CMAKE_COMMAND) -E cmake_depends " + << " \"" + << this->GlobalGenerator->GetName() << "\" " + << this->LocalGenerator->Convert + (this->Makefile->GetHomeOutputDirectory(), + cmLocalGenerator::FULL,cmLocalGenerator::SHELL) + << " " + << this->LocalGenerator->Convert + (this->Makefile->GetStartOutputDirectory(), + cmLocalGenerator::FULL,cmLocalGenerator::SHELL) + << " " + << this->Convert(this->InfoFileNameFull.c_str(), + cmLocalGenerator::FULL, + cmLocalGenerator::SHELL); + commands.push_back(depCmd.str()); + + // Write the rule. + this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0, + depMark.c_str(), depends, commands); +} + +//---------------------------------------------------------------------------- +void cmMakefileTargetGenerator +::WriteObjectDependRules(cmSourceFile& 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()); + } + } +} + +void cmMakefileTargetGenerator::WriteCustomCommands() +{ + // add custom commands to the clean rules? + const char* clean_no_custom = this->Makefile->GetProperty("CLEAN_NO_CUSTOM"); + bool clean = cmSystemTools::IsOff(clean_no_custom); + + // Generate the rule files for each custom command. + const std::vector<cmSourceFile*> &classes = this->Makefile->GetSourceFiles(); + for(std::vector<cmSourceFile*>::const_iterator i = classes.begin(); + i != classes.end(); i++) + { + if(cmCustomCommand* cc = (*i)->GetCustomCommand()) + { + this->GenerateCustomRuleFile(*cc); + if (clean) + { + this->CleanFiles.push_back + (this->Convert(cc->GetOutput(), + cmLocalGenerator::START_OUTPUT, + cmLocalGenerator::SHELL)); + } + } + } +} + +//---------------------------------------------------------------------------- +void cmMakefileTargetGenerator +::GenerateCustomRuleFile(const cmCustomCommand& cc) +{ + // Convert the output name to a relative path if possible. + std::string output = this->Convert(cc.GetOutput(), + cmLocalGenerator::START_OUTPUT); + + // Collect the commands. + std::vector<std::string> commands; + std::string preEcho = "Generating "; + preEcho += output; + this->LocalGenerator->AppendEcho(commands, preEcho.c_str()); + this->LocalGenerator->AppendCustomCommand(commands, cc); + + // Collect the dependencies. + std::vector<std::string> depends; + this->LocalGenerator->AppendCustomDepend(depends, cc); + + // Write the rule. + const char* comment = 0; + if(cc.GetComment() && *cc.GetComment()) + { + comment = cc.GetComment(); + } + this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, comment, + cc.GetOutput(), depends, commands); +} + +//---------------------------------------------------------------------------- +void +cmMakefileTargetGenerator +::WriteObjectsVariable(std::string& variableName, + std::string& variableNameExternal) +{ + // 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() << " ="; + 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) + { + lineContinue = "\\"; + } + 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 << "\n"; + + // Write a make variable assignment that lists all external objects + // for the target. + variableNameExternal = + this->LocalGenerator->CreateMakeVariable(this->Target->GetName(),"_EXTERNAL_OBJECTS"); + *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"; +} + + +//---------------------------------------------------------------------------- +std::string cmMakefileTargetGenerator::GetFrameworkFlags() +{ +#ifndef __APPLE__ + return std::string(); +#else + std::set<cmStdString> emitted; + std::vector<std::string> includes; + this->GetIncludeDirectories(includes); + std::vector<std::string>::iterator i; + // check all include directories for frameworks as this + // will already have added a -F for the framework + for(i = includes.begin(); i != includes.end(); ++i) + { + if(cmSystemTools::IsPathToFramework(i->c_str())) + { + std::string frameworkDir = *i; + frameworkDir += "/../"; + frameworkDir = cmSystemTools::CollapseFullPath(frameworkDir.c_str()); + emitted.insert(frameworkDir); + } + } + + std::string flags; + std::vector<std::string>& frameworks = this->Target->GetFrameworks(); + for(i = frameworks.begin(); + i != frameworks.end(); ++i) + { + if(emitted.insert(*i).second) + { + flags += "-F"; + flags += this->LocalGenerator->ConvertToOutputForExisting(i->c_str()); + flags += " "; + } + } + return flags; +#endif +} + +//---------------------------------------------------------------------------- +void cmMakefileTargetGenerator +::AppendTargetDepends(std::vector<std::string>& depends) +{ + // Static libraries never depend on anything for linking. + if(this->Target->GetType() == cmTarget::STATIC_LIBRARY) + { + return; + } + + // Keep track of dependencies already listed. + std::set<cmStdString> emitted; + + // A target should not depend on itself. + emitted.insert(this->Target->GetName()); + + // Loop over all library dependencies. + const cmTarget::LinkLibraries& tlibs = this->Target->GetLinkLibraries(); + for(cmTarget::LinkLibraries::const_iterator lib = tlibs.begin(); + lib != tlibs.end(); ++lib) + { + // Don't emit the same library twice for this target. + if(emitted.insert(lib->first).second) + { + // Depend only on other CMake targets. + if(cmTarget* tgt = + this->GlobalGenerator->FindTarget(0, lib->first.c_str())) + { + if(const char* location = + tgt->GetLocation(this->LocalGenerator->m_ConfigurationName.c_str())) + { + depends.push_back(location); + } + } + } + } +} + +//---------------------------------------------------------------------------- +void cmMakefileTargetGenerator +::CloseFileStreams() +{ + delete this->BuildFileStream; + delete this->InfoFileStream; + delete this->FlagFileStream; +} diff --git a/Source/cmMakefileTargetGenerator.h b/Source/cmMakefileTargetGenerator.h new file mode 100644 index 0000000..eaf8f86 --- /dev/null +++ b/Source/cmMakefileTargetGenerator.h @@ -0,0 +1,152 @@ +/*========================================================================= + + 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. + +=========================================================================*/ +#ifndef cmMakefileTargetGenerator_h +#define cmMakefileTargetGenerator_h + +#include "cmLocalUnixMakefileGenerator3.h" + +class cmCustomCommand; +class cmDependInformation; +class cmDepends; +class cmGeneratedFileStream; +class cmGlobalGenerator; +class cmLocalUnixMakefileGenerator3; +class cmMakeDepend; +class cmMakefile; +class cmTarget; +class cmSourceFile; + +/** \class cmMakefileTargetGenerator + * \brief Support Routines for writing makefiles + * + */ +class cmMakefileTargetGenerator +{ +public: + // construct using this factory call + static cmMakefileTargetGenerator *New(cmLocalUnixMakefileGenerator3 *lg, + cmStdString tgtName, + cmTarget *tgt); + + /* the main entry point for this class. Writes the Makefiles associated + with this target */ + virtual void WriteRuleFiles() = 0; + +protected: + + // create the file and directory etc + void CreateRuleFile(); + + // outputs the rules for any custom commands used by this target + void WriteCustomCommandsForTarget(); + + // write some common code at the top of build.make + void WriteCommonCodeRules(); + + // write the provide require rules for this target + void WriteTargetRequiresRules(); + + // write the clean rules for this target + void WriteTargetCleanRules(); + + // write the depend rules for this target + void WriteTargetDependRules(); + + // write the rules for an object + void WriteObjectRuleFiles(cmSourceFile& source); + + // write the build rule for an object + void WriteObjectBuildFile(std::string &obj, + const char *lang, + cmSourceFile& source, + std::vector<std::string>& depends); + + // write the depend.make file for an object + void WriteObjectDependRules(cmSourceFile& source, + std::vector<std::string>& depends); + + // this is responsible for writing all of the rules for all this + // directories custom commands (but not utility targets) + void WriteCustomCommands(); + void GenerateCustomRuleFile(const cmCustomCommand& cc); + + // write out the variable that lists the objects for this target + void WriteObjectsVariable(std::string& variableName, + std::string& variableNameExternal); + + // Return the a string with -F flags on apple + std::string GetFrameworkFlags(); + + // append intertarget dependencies + void AppendTargetDepends(std::vector<std::string>& depends); + + virtual void CloseFileStreams(); + + cmStdString TargetName; + cmTarget *Target; + cmLocalUnixMakefileGenerator3 *LocalGenerator; + cmGlobalGenerator *GlobalGenerator; + cmMakefile *Makefile; + + // the full path to the build file + std::string BuildFileName; + std::string BuildFileNameFull; + + // the path to the directory the build file is in + std::string TargetBuildDirectory; + std::string TargetBuildDirectoryFull; + + // the stream for the build file + cmGeneratedFileStream *BuildFileStream; + + // the stream for the flag file + std::string FlagFileNameFull; + cmGeneratedFileStream *FlagFileStream; + + // the stream for the info file + std::string InfoFileNameFull; + cmGeneratedFileStream *InfoFileStream; + + // files to clean + std::vector<std::string> CleanFiles; + + // objects used by this target + std::vector<std::string> Objects; + std::vector<std::string> ExternalObjects; + + // Set of object file names that will be built in this directory. + std::set<cmStdString> m_ObjectFiles; + + + //================================================================== + // Convenience routines that do nothing more than forward to + // implementaitons + std::string Convert(const char* source, + cmLocalGenerator::RelativeRoot relative, + cmLocalGenerator::OutputFormat output = + cmLocalGenerator::UNCHANGED, + bool optional = false) + { + return this->LocalGenerator->Convert(source, relative, output, optional); + } + + // constructor to set the ivarscmMakefileTargetGenerator + cmMakefileTargetGenerator(); + +}; + +#endif diff --git a/Source/cmMakefileUtilityTargetGenerator.cxx b/Source/cmMakefileUtilityTargetGenerator.cxx new file mode 100644 index 0000000..9843a06 --- /dev/null +++ b/Source/cmMakefileUtilityTargetGenerator.cxx @@ -0,0 +1,90 @@ +/*========================================================================= + + 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 "cmMakefileUtilityTargetGenerator.h" + +#include "cmGeneratedFileStream.h" +#include "cmGlobalGenerator.h" +#include "cmLocalUnixMakefileGenerator3.h" +#include "cmMakefile.h" +#include "cmSourceFile.h" +#include "cmTarget.h" + + +//---------------------------------------------------------------------------- +void cmMakefileUtilityTargetGenerator::WriteRuleFiles() +{ + this->CreateRuleFile(); + + *this->BuildFileStream + << "# Utility rule file for " << this->Target->GetName() << ".\n\n"; + + // write the custom commands for this target + this->WriteCustomCommandsForTarget(); + + // Collect the commands and dependencies. + std::vector<std::string> commands; + std::vector<std::string> depends; + const char* sym = this->Makefile->GetDefinition("CMAKE_MAKE_SYMBOLIC_RULE"); + if(sym) + { + depends.push_back(sym); + } + + // Utility targets store their rules in pre- and post-build commands. + this->LocalGenerator->AppendCustomDepends + (depends, this->Target->GetPreBuildCommands()); + this->LocalGenerator->AppendCustomDepends + (depends, this->Target->GetPostBuildCommands()); + this->LocalGenerator->AppendCustomCommands + (commands, this->Target->GetPreBuildCommands()); + this->LocalGenerator->AppendCustomCommands + (commands, this->Target->GetPostBuildCommands()); + + // Add dependencies on targets that must be built first. + this->AppendTargetDepends(depends); + + // Add a dependency on the rule file itself. + std::string relPath = this->LocalGenerator->GetHomeRelativeOutputPath(); + std::string objTarget = relPath; + objTarget += this->BuildFileName; + this->LocalGenerator->AppendRuleDepend(depends, objTarget.c_str()); + + // Write the rule. + this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0, + this->Target->GetName(), 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->LocalGenerator->Convert(buildTargetRuleName.c_str(), + cmLocalGenerator::HOME_OUTPUT, + cmLocalGenerator::MAKEFILE); + this->LocalGenerator->WriteConvenienceRule(*this->BuildFileStream, + this->Target->GetName(), + buildTargetRuleName.c_str()); + + // Write clean target + this->WriteTargetCleanRules(); + + // close the streams + this->CloseFileStreams(); +} + diff --git a/Source/cmMakefileUtilityTargetGenerator.h b/Source/cmMakefileUtilityTargetGenerator.h new file mode 100644 index 0000000..c8642a6 --- /dev/null +++ b/Source/cmMakefileUtilityTargetGenerator.h @@ -0,0 +1,34 @@ +/*========================================================================= + + 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. + +=========================================================================*/ +#ifndef cmMakefileUtilityTargetGenerator_h +#define cmMakefileUtilityTargetGenerator_h + +#include "cmMakefileTargetGenerator.h" + +class cmMakefileUtilityTargetGenerator: + public cmMakefileTargetGenerator +{ +public: + /* the main entry point for this class. Writes the Makefiles associated + with this target */ + virtual void WriteRuleFiles(); + +protected: + +}; + +#endif |