mirror of
https://github.com/reactos/CMake.git
synced 2025-01-10 05:31:02 +00:00
35936433e1
CMake-SourceFile2-bp and CMake-SourceFile2-b-mp1 to trunk. This commit is surrounded by tags CMake-SourceFile2-b-mp1-pre and CMake-SourceFile2-b-mp1-post on the trunk. The changes re-implement cmSourceFile and the use of it to allow instances to be created much earlier. The use of cmSourceFileLocation allows locating a source file referenced by a user to be much simpler and more robust. The two SetName methods are no longer needed so some duplicate code has been removed. The strange "SourceName" stuff is gone. Code that created cmSourceFile instances on the stack and then sent them to cmMakefile::AddSource has been simplified and converted to getting cmSourceFile instances from cmMakefile. The CPluginAPI has preserved the old API through a compatibility interface. Source lists are gone. Targets now get real instances of cmSourceFile right away instead of storing a list of strings until the final pass. TraceVSDependencies has been re-written to avoid the use of SourceName. It is now called TraceDependencies since it is not just for VS. It is now implemented with a helper object which makes the code simpler.
921 lines
32 KiB
C++
921 lines
32 KiB
C++
/*=========================================================================
|
|
|
|
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 "cmGlobalUnixMakefileGenerator3.h"
|
|
#include "cmLocalUnixMakefileGenerator3.h"
|
|
#include "cmMakefile.h"
|
|
#include "cmSourceFile.h"
|
|
#include "cmTarget.h"
|
|
#include "cmake.h"
|
|
|
|
#include <memory> // auto_ptr
|
|
|
|
//----------------------------------------------------------------------------
|
|
cmMakefileLibraryTargetGenerator::cmMakefileLibraryTargetGenerator()
|
|
{
|
|
this->CustomCommandDriver = OnDepends;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void cmMakefileLibraryTargetGenerator::WriteRuleFiles()
|
|
{
|
|
// create the build.make file and directory, put in the common blocks
|
|
this->CreateRuleFile();
|
|
|
|
// write rules used to help build object files
|
|
this->WriteCommonCodeRules();
|
|
|
|
// write in rules for object files and custom commands
|
|
this->WriteTargetBuildRules();
|
|
|
|
// write the per-target per-language flags
|
|
this->WriteTargetLanguageFlags();
|
|
|
|
// Write the dependency generation rule.
|
|
this->WriteTargetDependRules();
|
|
|
|
// 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(false);
|
|
if(this->Target->NeedRelinkBeforeInstall())
|
|
{
|
|
// Write rules to link an installable version of the target.
|
|
this->WriteSharedLibraryRules(true);
|
|
}
|
|
break;
|
|
case cmTarget::MODULE_LIBRARY:
|
|
this->WriteModuleLibraryRules(false);
|
|
if(this->Target->NeedRelinkBeforeInstall())
|
|
{
|
|
// Write rules to link an installable version of the target.
|
|
this->WriteModuleLibraryRules(true);
|
|
}
|
|
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(), false);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void cmMakefileLibraryTargetGenerator::WriteSharedLibraryRules(bool relink)
|
|
{
|
|
#ifdef __APPLE__
|
|
if(this->Target->GetPropertyAsBool("FRAMEWORK"))
|
|
{
|
|
this->WriteFrameworkRules(relink);
|
|
return;
|
|
}
|
|
#endif
|
|
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"));
|
|
std::string linkFlagsConfig = "LINK_FLAGS_";
|
|
linkFlagsConfig +=
|
|
cmSystemTools::UpperCase(this->LocalGenerator->ConfigurationName.c_str());
|
|
this->LocalGenerator->AppendFlags
|
|
(extraFlags, this->Target->GetProperty(linkFlagsConfig.c_str()));
|
|
|
|
this->LocalGenerator->AddConfigVariableFlags
|
|
(extraFlags, "CMAKE_SHARED_LINKER_FLAGS",
|
|
this->LocalGenerator->ConfigurationName.c_str());
|
|
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)
|
|
{
|
|
cmSourceFile* sf = *i;
|
|
if(sf->GetExtension() == "def")
|
|
{
|
|
extraFlags += " ";
|
|
extraFlags +=
|
|
this->Makefile->GetSafeDefinition("CMAKE_LINK_DEF_FILE_FLAG");
|
|
extraFlags +=
|
|
this->Convert(sf->GetFullPath().c_str(),
|
|
cmLocalGenerator::START_OUTPUT,
|
|
cmLocalGenerator::SHELL);
|
|
}
|
|
}
|
|
}
|
|
this->WriteLibraryRules(linkRuleVar.c_str(), extraFlags.c_str(), relink);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void cmMakefileLibraryTargetGenerator::WriteModuleLibraryRules(bool relink)
|
|
{
|
|
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"));
|
|
std::string linkFlagsConfig = "LINK_FLAGS_";
|
|
linkFlagsConfig +=
|
|
cmSystemTools::UpperCase(this->LocalGenerator->ConfigurationName.c_str());
|
|
this->LocalGenerator->AppendFlags
|
|
(extraFlags, this->Target->GetProperty(linkFlagsConfig.c_str()));
|
|
this->LocalGenerator->AddConfigVariableFlags
|
|
(extraFlags, "CMAKE_MODULE_LINKER_FLAGS",
|
|
this->LocalGenerator->ConfigurationName.c_str());
|
|
|
|
// TODO: .def files should be supported here also.
|
|
this->WriteLibraryRules(linkRuleVar.c_str(), extraFlags.c_str(), relink);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void cmMakefileLibraryTargetGenerator::WriteFrameworkRules(bool relink)
|
|
{
|
|
const char* linkLanguage =
|
|
this->Target->GetLinkerLanguage(this->GlobalGenerator);
|
|
std::string linkRuleVar = "CMAKE_";
|
|
if (linkLanguage)
|
|
{
|
|
linkRuleVar += linkLanguage;
|
|
}
|
|
linkRuleVar += "_CREATE_MACOSX_FRAMEWORK";
|
|
|
|
std::string extraFlags;
|
|
this->LocalGenerator->AppendFlags(extraFlags,
|
|
this->Target->GetProperty("LINK_FLAGS"));
|
|
std::string linkFlagsConfig = "LINK_FLAGS_";
|
|
linkFlagsConfig +=
|
|
cmSystemTools::UpperCase(this->LocalGenerator->ConfigurationName.c_str());
|
|
this->LocalGenerator->AppendFlags
|
|
(extraFlags, this->Target->GetProperty(linkFlagsConfig.c_str()));
|
|
this->LocalGenerator->AddConfigVariableFlags
|
|
(extraFlags, "CMAKE_MACOSX_FRAMEWORK_LINKER_FLAGS",
|
|
this->LocalGenerator->ConfigurationName.c_str());
|
|
|
|
// TODO: .def files should be supported here also.
|
|
this->WriteLibraryRules(linkRuleVar.c_str(), extraFlags.c_str(), relink);
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
void cmMakefileLibraryTargetGenerator::CreateFrameworkLinksAndDirs(
|
|
std::string& targetName,
|
|
std::string& outpath,
|
|
const char* version)
|
|
{
|
|
std::string symlink;
|
|
std::string symlink2;
|
|
// Make foo.framework/Versions
|
|
std::string dir = outpath;
|
|
dir += "Versions";
|
|
cmSystemTools::MakeDirectory(dir.c_str());
|
|
std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
|
|
// cd foo.framework to setup symlinks with relative paths
|
|
cmSystemTools::ChangeDirectory((outpath+"Versions").c_str());
|
|
// Current -> version
|
|
symlink = version;
|
|
symlink2 = "Current";
|
|
cmSystemTools::RemoveFile("Current");
|
|
cmSystemTools::CreateSymlink(symlink.c_str(), symlink2.c_str());
|
|
this->Makefile->AddCMakeOutputFile((outpath + "Versions/Current").c_str());
|
|
// change to top level of framework to create next set of symlinks
|
|
cmSystemTools::ChangeDirectory(outpath.c_str());
|
|
// foo -> Versions/Current/foo
|
|
symlink = "Versions/Current/";
|
|
symlink += targetName;
|
|
symlink2 = targetName;
|
|
cmSystemTools::CreateSymlink(symlink.c_str(), symlink2.c_str());
|
|
this->Makefile->AddCMakeOutputFile((outpath + targetName).c_str());
|
|
// Resources -> Versions/Current/Resources
|
|
symlink = "Versions/Current/Resources";
|
|
symlink2 = "Resources";
|
|
cmSystemTools::CreateSymlink(symlink.c_str(), symlink2.c_str());
|
|
this->Makefile->AddCMakeOutputFile((outpath + "Resources").c_str());
|
|
// Libraries -> Versions/Current/Libraries
|
|
symlink = "Versions/Current/Libraries";
|
|
symlink2 = "Libraries";
|
|
cmSystemTools::CreateSymlink(symlink.c_str(), symlink2.c_str());
|
|
this->Makefile->AddCMakeOutputFile((outpath + "Libraries").c_str());
|
|
// Headers -> Versions/Current/Headers
|
|
symlink = "Versions/Current/Headers";
|
|
symlink2 = "Headers";
|
|
cmSystemTools::CreateSymlink(symlink.c_str(), symlink2.c_str());
|
|
this->Makefile->AddCMakeOutputFile((outpath + "Headers").c_str());
|
|
// go back to where we were
|
|
cmSystemTools::ChangeDirectory(cwd.c_str());
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void cmMakefileLibraryTargetGenerator::CopyFrameworkPublicHeaders(
|
|
std::string& targetName,
|
|
std::string& outpath,
|
|
const char* /*version*/)
|
|
{
|
|
std::string fullOutput= outpath + targetName;
|
|
const char* headers = this->Target->GetProperty("FRAMEWORK_PUBLIC_HEADERS");
|
|
if(!headers)
|
|
{
|
|
return;
|
|
}
|
|
std::vector<std::string> headersVec;
|
|
cmSystemTools::ExpandListArgument(headers,
|
|
headersVec);
|
|
cmCustomCommandLines commandLines;
|
|
std::vector<std::string> depends;
|
|
for(std::vector<std::string>::iterator i = headersVec.begin();
|
|
i != headersVec.end(); ++i)
|
|
{
|
|
cmCustomCommandLine line;
|
|
cmSourceFile* sf = this->Makefile->GetOrCreateSource(i->c_str());
|
|
std::string dest = outpath + "Headers/";
|
|
dest += cmSystemTools::GetFilenameName(sf->GetFullPath());
|
|
line.push_back("$(CMAKE_COMMAND)");
|
|
line.push_back("-E");
|
|
line.push_back("copy_if_different");
|
|
line.push_back(sf->GetFullPath());
|
|
depends.push_back(sf->GetFullPath());
|
|
line.push_back(dest);
|
|
commandLines.push_back(line);
|
|
// make sure the target gets rebuilt if any of the headers is removed
|
|
this->GenerateExtraOutput(dest.c_str(),
|
|
fullOutput.c_str());
|
|
}
|
|
// add a set of prebuild commands to run on the target
|
|
this->Makefile->
|
|
AddCustomCommandToTarget(this->Target->GetName(),
|
|
depends,
|
|
commandLines,
|
|
cmTarget::PRE_BUILD,
|
|
"copy files",
|
|
this->Makefile->GetCurrentOutputDirectory());
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void cmMakefileLibraryTargetGenerator::CopyFrameworkResources(
|
|
std::string& targetName,
|
|
std::string& outpath,
|
|
const char* /*version*/)
|
|
{
|
|
std::string fullOutput= outpath + targetName;
|
|
const char* resources = this->Target->GetProperty("FRAMEWORK_RESOURCES");
|
|
if(!resources)
|
|
{
|
|
return;
|
|
}
|
|
std::vector<std::string> resourcesVec;
|
|
cmSystemTools::ExpandListArgument(resources,
|
|
resourcesVec);
|
|
cmCustomCommandLines commandLines;
|
|
std::vector<std::string> depends;
|
|
for(std::vector<std::string>::iterator i = resourcesVec.begin();
|
|
i != resourcesVec.end(); ++i)
|
|
{
|
|
cmCustomCommandLine line;
|
|
cmSourceFile* sf = this->Makefile->GetOrCreateSource(i->c_str());
|
|
if(!sf)
|
|
{
|
|
cmSystemTools::Error(
|
|
"could not find resource file.", i->c_str());
|
|
continue;
|
|
}
|
|
std::string dest = outpath + "Resources/";
|
|
dest += cmSystemTools::GetFilenameName(sf->GetFullPath());
|
|
line.push_back("$(CMAKE_COMMAND)");
|
|
line.push_back("-E");
|
|
line.push_back("copy_if_different");
|
|
line.push_back(sf->GetFullPath());
|
|
depends.push_back(sf->GetFullPath());
|
|
line.push_back(dest);
|
|
commandLines.push_back(line);
|
|
// make sure the target gets rebuilt if any of the resources is removed
|
|
this->GenerateExtraOutput(dest.c_str(),
|
|
fullOutput.c_str());
|
|
}
|
|
// add a set of prebuild commands to run on the target
|
|
this->Makefile->
|
|
AddCustomCommandToTarget(this->Target->GetName(),
|
|
depends,
|
|
commandLines,
|
|
cmTarget::PRE_BUILD,
|
|
"copy files",
|
|
this->Makefile->GetCurrentOutputDirectory());
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void cmMakefileLibraryTargetGenerator::CreateFramework(
|
|
std::string& targetName,
|
|
std::string& outpath)
|
|
{
|
|
std::string macdir = outpath;
|
|
const char* version = this->Target->GetProperty("FRAMEWORK_VERSION");
|
|
if(!version)
|
|
{
|
|
version = "A";
|
|
std::string message =
|
|
"Warning: FRAMEWORK_VERSION property not found on ";
|
|
message += targetName;
|
|
message += ". Default to verison A.";
|
|
cmSystemTools::Message(message.c_str());
|
|
}
|
|
// create the symbolic links and directories
|
|
this->CreateFrameworkLinksAndDirs(targetName,
|
|
outpath,
|
|
version);
|
|
macdir += "Versions/";
|
|
macdir += version;
|
|
macdir += "/";
|
|
outpath += "Versions/";
|
|
outpath += version;
|
|
outpath += "/";
|
|
|
|
cmSystemTools::MakeDirectory((macdir + "Libraries").c_str());
|
|
cmSystemTools::MakeDirectory((macdir + "Headers").c_str());
|
|
// Configure the Info.plist file. Note that it needs the executable name
|
|
// to be set
|
|
std::string rsrcDir = macdir + "Resources/";
|
|
cmSystemTools::MakeDirectory(rsrcDir.c_str());
|
|
this->Makefile->AddDefinition("MACOSX_FRAMEWORK_NAME",
|
|
targetName.c_str());
|
|
std::string f1 =
|
|
this->Makefile->GetModulesFile("MacOSXFrameworkInfo.plist.in");
|
|
if ( f1.size() == 0 )
|
|
{
|
|
cmSystemTools::Error(
|
|
"could not find Mac OSX framework Info.plist template file.");
|
|
}
|
|
std::string f2 = rsrcDir + "Info.plist";
|
|
this->Makefile->ConfigureFile(f1.c_str(), f2.c_str(),
|
|
false, false, false);
|
|
this->CopyFrameworkPublicHeaders(targetName,
|
|
outpath,
|
|
version);
|
|
this->CopyFrameworkResources(targetName,
|
|
outpath,
|
|
version);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void cmMakefileLibraryTargetGenerator::WriteLibraryRules
|
|
(const char* linkRuleVar, const char* extraFlags, bool relink)
|
|
{
|
|
// 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;
|
|
std::string targetNameImport;
|
|
std::string targetNamePDB;
|
|
this->Target->GetLibraryNames(
|
|
targetName, targetNameSO, targetNameReal, targetNameImport, targetNamePDB,
|
|
this->LocalGenerator->ConfigurationName.c_str());
|
|
|
|
// Construct the full path version of the names.
|
|
std::string outpath;
|
|
std::string outpathImp;
|
|
if(relink)
|
|
{
|
|
outpath = this->Makefile->GetStartOutputDirectory();
|
|
outpath += cmake::GetCMakeFilesDirectory();
|
|
outpath += "/CMakeRelink.dir";
|
|
cmSystemTools::MakeDirectory(outpath.c_str());
|
|
outpath += "/";
|
|
if(!targetNameImport.empty())
|
|
{
|
|
outpathImp = outpath;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
outpath = this->Target->GetDirectory();
|
|
outpath += "/";
|
|
if(!targetNameImport.empty())
|
|
{
|
|
outpathImp = this->Target->GetDirectory(0, true);
|
|
outpathImp += "/";
|
|
}
|
|
}
|
|
#if defined(__APPLE__)
|
|
// If we're creating a framework, place the output into a framework directory
|
|
if(this->Target->GetPropertyAsBool("FRAMEWORK"))
|
|
{
|
|
this->CreateFramework(targetName, outpath);
|
|
}
|
|
#endif
|
|
std::string targetFullPath = outpath + targetName;
|
|
std::string targetFullPathPDB = outpath + targetNamePDB;
|
|
std::string targetFullPathSO = outpath + targetNameSO;
|
|
std::string targetFullPathReal = outpath + targetNameReal;
|
|
std::string targetFullPathImport = outpathImp + targetNameImport;
|
|
|
|
// Construct the output path version of the names for use in command
|
|
// arguments.
|
|
std::string targetOutPathPDB =
|
|
this->Convert(targetFullPathPDB.c_str(),cmLocalGenerator::FULL,
|
|
cmLocalGenerator::SHELL);
|
|
std::string targetOutPath =
|
|
this->Convert(targetFullPath.c_str(),cmLocalGenerator::START_OUTPUT,
|
|
cmLocalGenerator::SHELL);
|
|
std::string targetOutPathSO =
|
|
this->Convert(targetFullPathSO.c_str(),cmLocalGenerator::START_OUTPUT,
|
|
cmLocalGenerator::SHELL);
|
|
std::string targetOutPathReal =
|
|
this->Convert(targetFullPathReal.c_str(),cmLocalGenerator::START_OUTPUT,
|
|
cmLocalGenerator::SHELL);
|
|
std::string targetOutPathImport =
|
|
this->Convert(targetFullPathImport.c_str(),cmLocalGenerator::START_OUTPUT,
|
|
cmLocalGenerator::SHELL);
|
|
|
|
// Add the link message.
|
|
std::string buildEcho = "Linking ";
|
|
buildEcho += linkLanguage;
|
|
const char* forbiddenFlagVar = 0;
|
|
switch(this->Target->GetType())
|
|
{
|
|
case cmTarget::STATIC_LIBRARY:
|
|
buildEcho += " static library ";
|
|
break;
|
|
case cmTarget::SHARED_LIBRARY:
|
|
forbiddenFlagVar = "_CREATE_SHARED_LIBRARY_FORBIDDEN_FLAGS";
|
|
buildEcho += " shared library ";
|
|
break;
|
|
case cmTarget::MODULE_LIBRARY:
|
|
forbiddenFlagVar = "_CREATE_SHARED_MODULE_FORBIDDEN_FLAGS";
|
|
buildEcho += " shared module ";
|
|
break;
|
|
default:
|
|
buildEcho += " library ";
|
|
break;
|
|
}
|
|
buildEcho += targetOutPath.c_str();
|
|
this->LocalGenerator->AppendEcho(commands, buildEcho.c_str(),
|
|
cmLocalUnixMakefileGenerator3::EchoLink);
|
|
|
|
// Construct a list of files associated with this library that may
|
|
// need to be cleaned.
|
|
std::vector<std::string> libCleanFiles;
|
|
if(this->Target->GetPropertyAsBool("CLEAN_DIRECT_OUTPUT"))
|
|
{
|
|
// The user has requested that only the files directly built
|
|
// by this target be cleaned instead of all possible names.
|
|
libCleanFiles.push_back(this->Convert(targetFullPath.c_str(),
|
|
cmLocalGenerator::START_OUTPUT,
|
|
cmLocalGenerator::UNCHANGED));
|
|
if(targetNameReal != targetName)
|
|
{
|
|
libCleanFiles.push_back(this->Convert(targetFullPathReal.c_str(),
|
|
cmLocalGenerator::START_OUTPUT,
|
|
cmLocalGenerator::UNCHANGED));
|
|
}
|
|
if(targetNameSO != targetName &&
|
|
targetNameSO != targetNameReal)
|
|
{
|
|
libCleanFiles.push_back(this->Convert(targetFullPathSO.c_str(),
|
|
cmLocalGenerator::START_OUTPUT,
|
|
cmLocalGenerator::UNCHANGED));
|
|
}
|
|
if(!targetNameImport.empty())
|
|
{
|
|
libCleanFiles.push_back(this->Convert(targetFullPathImport.c_str(),
|
|
cmLocalGenerator::START_OUTPUT,
|
|
cmLocalGenerator::UNCHANGED));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// This target may switch between static and shared based
|
|
// on a user option or the BUILD_SHARED_LIBS switch. Clean
|
|
// all possible names.
|
|
std::string cleanStaticName;
|
|
std::string cleanSharedName;
|
|
std::string cleanSharedSOName;
|
|
std::string cleanSharedRealName;
|
|
std::string cleanImportName;
|
|
std::string cleanPDBName;
|
|
this->Target->GetLibraryCleanNames(
|
|
cleanStaticName,
|
|
cleanSharedName,
|
|
cleanSharedSOName,
|
|
cleanSharedRealName,
|
|
cleanImportName,
|
|
cleanPDBName,
|
|
this->LocalGenerator->ConfigurationName.c_str());
|
|
std::string cleanFullStaticName = outpath + cleanStaticName;
|
|
std::string cleanFullSharedName = outpath + cleanSharedName;
|
|
std::string cleanFullSharedSOName = outpath + cleanSharedSOName;
|
|
std::string cleanFullSharedRealName = outpath + cleanSharedRealName;
|
|
std::string cleanFullImportName = outpathImp + cleanImportName;
|
|
std::string cleanFullPDBName = outpath + cleanPDBName;
|
|
libCleanFiles.push_back
|
|
(this->Convert(cleanFullStaticName.c_str(),
|
|
cmLocalGenerator::START_OUTPUT,
|
|
cmLocalGenerator::UNCHANGED));
|
|
if(cleanSharedRealName != cleanStaticName)
|
|
{
|
|
libCleanFiles.push_back(this->Convert(cleanFullSharedRealName.c_str(),
|
|
cmLocalGenerator::START_OUTPUT,
|
|
cmLocalGenerator::UNCHANGED));
|
|
}
|
|
if(cleanSharedSOName != cleanStaticName &&
|
|
cleanSharedSOName != cleanSharedRealName)
|
|
{
|
|
libCleanFiles.push_back(this->Convert(cleanFullSharedSOName.c_str(),
|
|
cmLocalGenerator::START_OUTPUT,
|
|
cmLocalGenerator::UNCHANGED));
|
|
}
|
|
if(cleanSharedName != cleanStaticName &&
|
|
cleanSharedName != cleanSharedSOName &&
|
|
cleanSharedName != cleanSharedRealName)
|
|
{
|
|
libCleanFiles.push_back(this->Convert(cleanFullSharedName.c_str(),
|
|
cmLocalGenerator::START_OUTPUT,
|
|
cmLocalGenerator::UNCHANGED));
|
|
}
|
|
if(!cleanImportName.empty())
|
|
{
|
|
libCleanFiles.push_back(this->Convert(cleanFullImportName.c_str(),
|
|
cmLocalGenerator::START_OUTPUT,
|
|
cmLocalGenerator::UNCHANGED));
|
|
}
|
|
|
|
// List the PDB for cleaning only when the whole target is
|
|
// cleaned. We do not want to delete the .pdb file just before
|
|
// linking the target.
|
|
this->CleanFiles.push_back
|
|
(this->Convert(cleanFullPDBName.c_str(),
|
|
cmLocalGenerator::START_OUTPUT,
|
|
cmLocalGenerator::UNCHANGED));
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
// There may be a manifest file for this target. Add it to the
|
|
// clean set just in case.
|
|
if(this->Target->GetType() != cmTarget::STATIC_LIBRARY)
|
|
{
|
|
libCleanFiles.push_back(
|
|
this->Convert((targetFullPath+".manifest").c_str(),
|
|
cmLocalGenerator::START_OUTPUT,
|
|
cmLocalGenerator::UNCHANGED));
|
|
}
|
|
#endif
|
|
|
|
// Add a command to remove any existing files for this library.
|
|
std::vector<std::string> commands1;
|
|
this->LocalGenerator->AppendCleanCommand(commands1, libCleanFiles,
|
|
*this->Target, "target");
|
|
this->LocalGenerator->CreateCDCommand
|
|
(commands1,
|
|
this->Makefile->GetStartOutputDirectory(),
|
|
this->Makefile->GetHomeOutputDirectory());
|
|
commands.insert(commands.end(), commands1.begin(), commands1.end());
|
|
commands1.clear();
|
|
|
|
// Add the pre-build and pre-link rules building but not when relinking.
|
|
if(!relink)
|
|
{
|
|
this->LocalGenerator
|
|
->AppendCustomCommands(commands, this->Target->GetPreBuildCommands());
|
|
this->LocalGenerator
|
|
->AppendCustomCommands(commands, this->Target->GetPreLinkCommands());
|
|
}
|
|
|
|
// Open the link script if it will be used.
|
|
bool useLinkScript = false;
|
|
std::string linkScriptName;
|
|
std::auto_ptr<cmGeneratedFileStream> linkScriptStream;
|
|
if(this->GlobalGenerator->GetUseLinkScript() &&
|
|
(this->Target->GetType() == cmTarget::STATIC_LIBRARY ||
|
|
this->Target->GetType() == cmTarget::SHARED_LIBRARY ||
|
|
this->Target->GetType() == cmTarget::MODULE_LIBRARY))
|
|
{
|
|
useLinkScript = true;
|
|
linkScriptName = this->TargetBuildDirectoryFull;
|
|
if(relink)
|
|
{
|
|
linkScriptName += "/relink.txt";
|
|
}
|
|
else
|
|
{
|
|
linkScriptName += "/link.txt";
|
|
}
|
|
std::auto_ptr<cmGeneratedFileStream> lss(
|
|
new cmGeneratedFileStream(linkScriptName.c_str()));
|
|
linkScriptStream = lss;
|
|
}
|
|
|
|
std::vector<std::string> link_script_commands;
|
|
|
|
// Construct the main link rule.
|
|
std::string linkRule = this->Makefile->GetRequiredDefinition(linkRuleVar);
|
|
if(useLinkScript)
|
|
{
|
|
cmSystemTools::ExpandListArgument(linkRule, link_script_commands);
|
|
std::string link_command = "$(CMAKE_COMMAND) -E cmake_link_script ";
|
|
link_command += this->Convert(linkScriptName.c_str(),
|
|
cmLocalGenerator::START_OUTPUT,
|
|
cmLocalGenerator::SHELL);
|
|
link_command += " --verbose=$(VERBOSE)";
|
|
commands1.push_back(link_command);
|
|
}
|
|
else
|
|
{
|
|
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 when building but not when relinking.
|
|
if(!relink)
|
|
{
|
|
this->LocalGenerator->
|
|
AppendCustomCommands(commands, this->Target->GetPostBuildCommands());
|
|
}
|
|
|
|
// Collect up flags to link in needed libraries.
|
|
cmOStringStream linklibs;
|
|
this->LocalGenerator->OutputLinkLibraries(linklibs, *this->Target, relink);
|
|
|
|
// Construct object file lists that may be needed to expand the
|
|
// rule.
|
|
std::string variableName;
|
|
std::string variableNameExternal;
|
|
this->WriteObjectsVariable(variableName, variableNameExternal);
|
|
std::string buildObjs;
|
|
if(useLinkScript)
|
|
{
|
|
this->WriteObjectsString(buildObjs);
|
|
}
|
|
else
|
|
{
|
|
buildObjs = "$(";
|
|
buildObjs += variableName;
|
|
buildObjs += ") $(";
|
|
buildObjs += variableNameExternal;
|
|
buildObjs += ")";
|
|
}
|
|
std::string cleanObjs = "$(";
|
|
cleanObjs += variableName;
|
|
cleanObjs += ")";
|
|
cmLocalGenerator::RuleVariables vars;
|
|
vars.TargetPDB = targetOutPathPDB.c_str();
|
|
|
|
// Setup the target version.
|
|
std::string targetVersionMajor;
|
|
std::string targetVersionMinor;
|
|
{
|
|
cmOStringStream majorStream;
|
|
cmOStringStream minorStream;
|
|
int major;
|
|
int minor;
|
|
this->Target->GetTargetVersion(major, minor);
|
|
majorStream << major;
|
|
minorStream << minor;
|
|
targetVersionMajor = majorStream.str();
|
|
targetVersionMinor = minorStream.str();
|
|
}
|
|
vars.TargetVersionMajor = targetVersionMajor.c_str();
|
|
vars.TargetVersionMinor = targetVersionMinor.c_str();
|
|
|
|
vars.Language = linkLanguage;
|
|
vars.Objects = buildObjs.c_str();
|
|
std::string objdir = cmake::GetCMakeFilesDirectoryPostSlash();
|
|
objdir += this->Target->GetName();
|
|
objdir += ".dir";
|
|
vars.ObjectDir = objdir.c_str();
|
|
vars.Target = targetOutPathReal.c_str();
|
|
std::string linkString = linklibs.str();
|
|
vars.LinkLibraries = linkString.c_str();
|
|
vars.ObjectsQuoted = buildObjs.c_str();
|
|
vars.TargetSOName= targetNameSO.c_str();
|
|
vars.LinkFlags = linkFlags.c_str();
|
|
|
|
// Compute the directory portion of the install_name setting.
|
|
std::string install_name_dir;
|
|
if(this->Target->GetType() == cmTarget::SHARED_LIBRARY)
|
|
{
|
|
// Get the install_name directory for the build tree.
|
|
const char* config = this->LocalGenerator->ConfigurationName.c_str();
|
|
install_name_dir = this->Target->GetInstallNameDirForBuildTree(config);
|
|
|
|
// Set the rule variable replacement value.
|
|
if(install_name_dir.empty())
|
|
{
|
|
vars.TargetInstallNameDir = "";
|
|
}
|
|
else
|
|
{
|
|
// Convert to a path for the native build tool.
|
|
install_name_dir =
|
|
this->LocalGenerator->Convert(install_name_dir.c_str(),
|
|
cmLocalGenerator::NONE,
|
|
cmLocalGenerator::SHELL, false);
|
|
vars.TargetInstallNameDir = install_name_dir.c_str();
|
|
}
|
|
}
|
|
std::string langFlags;
|
|
this->LocalGenerator
|
|
->AddLanguageFlags(langFlags, linkLanguage,
|
|
this->LocalGenerator->ConfigurationName.c_str());
|
|
// remove any language flags that might not work with the
|
|
// particular os
|
|
if(forbiddenFlagVar)
|
|
{
|
|
this->RemoveForbiddenFlags(forbiddenFlagVar,
|
|
linkLanguage, langFlags);
|
|
}
|
|
vars.LanguageCompileFlags = langFlags.c_str();
|
|
// Expand placeholders in the commands.
|
|
this->LocalGenerator->TargetImplib = targetOutPathImport;
|
|
if(useLinkScript)
|
|
{
|
|
for(std::vector<std::string>::iterator i = link_script_commands.begin();
|
|
i != link_script_commands.end(); ++i)
|
|
{
|
|
this->LocalGenerator->ExpandRuleVariables(*i, vars);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for(std::vector<std::string>::iterator i = commands.begin();
|
|
i != commands.end(); ++i)
|
|
{
|
|
this->LocalGenerator->ExpandRuleVariables(*i, vars);
|
|
}
|
|
}
|
|
this->LocalGenerator->TargetImplib = "";
|
|
|
|
// Optionally convert the build rule to use a script to avoid long
|
|
// command lines in the make shell.
|
|
if(useLinkScript)
|
|
{
|
|
for(std::vector<std::string>::iterator cmd = link_script_commands.begin();
|
|
cmd != link_script_commands.end(); ++cmd)
|
|
{
|
|
// Do not write out empty commands or commands beginning in the
|
|
// shell no-op ":".
|
|
if(!cmd->empty() && (*cmd)[0] != ':')
|
|
{
|
|
(*linkScriptStream) << *cmd << "\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
// Write the build rule.
|
|
this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0,
|
|
targetFullPathReal.c_str(),
|
|
depends, commands, false);
|
|
|
|
// Some targets have more than one output file. Create rules to
|
|
// drive the build if any extra outputs are missing.
|
|
std::vector<std::string> extraOutputs;
|
|
if(targetNameSO != targetNameReal)
|
|
{
|
|
this->GenerateExtraOutput(targetFullPathSO.c_str(),
|
|
targetFullPathReal.c_str());
|
|
}
|
|
if(targetName != targetNameSO &&
|
|
targetName != targetNameReal)
|
|
{
|
|
this->GenerateExtraOutput(targetFullPath.c_str(),
|
|
targetFullPathReal.c_str());
|
|
}
|
|
|
|
// Write the main driver rule to build everything in this target.
|
|
this->WriteTargetDriverRule(targetFullPath.c_str(), relink);
|
|
|
|
// Clean all the possible library names and symlinks and object files.
|
|
this->CleanFiles.insert(this->CleanFiles.end(),
|
|
libCleanFiles.begin(),libCleanFiles.end());
|
|
this->CleanFiles.insert(this->CleanFiles.end(),
|
|
this->Objects.begin(),
|
|
this->Objects.end());
|
|
}
|
|
|