ENH: some cleanup of the makefile generator

This commit is contained in:
Ken Martin 2006-02-14 10:36:04 -05:00
parent 3bce601c41
commit 7740ccd1a4
8 changed files with 1869 additions and 0 deletions

View File

@ -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);
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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();
}

View File

@ -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