mirror of
https://github.com/reactos/CMake.git
synced 2025-01-25 05:04:37 +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.
1280 lines
44 KiB
C++
1280 lines
44 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 "cmMakefileTargetGenerator.h"
|
|
|
|
#include "cmGeneratedFileStream.h"
|
|
#include "cmGlobalGenerator.h"
|
|
#include "cmGlobalUnixMakefileGenerator3.h"
|
|
#include "cmLocalUnixMakefileGenerator3.h"
|
|
#include "cmMakefile.h"
|
|
#include "cmSourceFile.h"
|
|
#include "cmTarget.h"
|
|
#include "cmake.h"
|
|
|
|
#include "cmMakefileExecutableTargetGenerator.h"
|
|
#include "cmMakefileLibraryTargetGenerator.h"
|
|
#include "cmMakefileUtilityTargetGenerator.h"
|
|
|
|
|
|
cmMakefileTargetGenerator::cmMakefileTargetGenerator()
|
|
{
|
|
this->BuildFileStream = 0;
|
|
this->InfoFileStream = 0;
|
|
this->FlagFileStream = 0;
|
|
this->CustomCommandDriver = OnBuild;
|
|
}
|
|
|
|
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 result;
|
|
// break; /* unreachable */
|
|
}
|
|
|
|
result->TargetName = tgtName;
|
|
result->Target = tgt;
|
|
result->LocalGenerator = lg;
|
|
result->GlobalGenerator =
|
|
static_cast<cmGlobalUnixMakefileGenerator3*>(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";
|
|
|
|
// Construct the rule file name.
|
|
this->ProgressFileName = this->TargetBuildDirectory;
|
|
this->ProgressFileName += "/progress.make";
|
|
this->ProgressFileNameFull = this->TargetBuildDirectoryFull;
|
|
this->ProgressFileNameFull += "/progress.make";
|
|
|
|
// reset the progress count
|
|
this->NumberOfProgressActions = 0;
|
|
|
|
// 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);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void cmMakefileTargetGenerator::WriteTargetBuildRules()
|
|
{
|
|
// 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);
|
|
}
|
|
|
|
// 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);
|
|
|
|
// 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(cmCustomCommand* cc = (*source)->GetCustomCommand())
|
|
{
|
|
this->GenerateCustomRuleFile(*cc);
|
|
if (clean)
|
|
{
|
|
const std::vector<std::string>& outputs = cc->GetOutputs();
|
|
for(std::vector<std::string>::const_iterator o = outputs.begin();
|
|
o != outputs.end(); ++o)
|
|
{
|
|
this->CleanFiles.push_back
|
|
(this->Convert(o->c_str(),
|
|
cmLocalGenerator::START_OUTPUT,
|
|
cmLocalGenerator::UNCHANGED));
|
|
}
|
|
}
|
|
}
|
|
else if(!(*source)->GetPropertyAsBool("HEADER_FILE_ONLY"))
|
|
{
|
|
if(!this->GlobalGenerator->IgnoreFile
|
|
((*source)->GetExtension().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.
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
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->IncludeDirective << " "
|
|
<< this->Convert(dependFileNameFull.c_str(),
|
|
cmLocalGenerator::HOME_OUTPUT,
|
|
cmLocalGenerator::MAKEFILE)
|
|
<< "\n\n";
|
|
|
|
// Include the progress variables for the target.
|
|
*this->BuildFileStream
|
|
<< "# Include the progress variables for this target.\n"
|
|
<< this->LocalGenerator->IncludeDirective << " "
|
|
<< this->Convert(this->ProgressFileNameFull.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->IncludeDirective << " "
|
|
<< this->Convert(this->FlagFileNameFull.c_str(),
|
|
cmLocalGenerator::HOME_OUTPUT,
|
|
cmLocalGenerator::MAKEFILE)
|
|
<< "\n\n";
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void cmMakefileTargetGenerator::WriteTargetLanguageFlags()
|
|
{
|
|
// 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;
|
|
bool shared = ((this->Target->GetType() == cmTarget::SHARED_LIBRARY) ||
|
|
(this->Target->GetType() == cmTarget::MODULE_LIBRARY));
|
|
|
|
// Add the export symbol definition for shared library objects.
|
|
if(const char* exportMacro = this->Target->GetExportMacro())
|
|
{
|
|
flags += "-D";
|
|
flags += exportMacro;
|
|
}
|
|
|
|
// Add language-specific flags.
|
|
this->LocalGenerator
|
|
->AddLanguageFlags(flags, lang,
|
|
this->LocalGenerator->ConfigurationName.c_str());
|
|
|
|
// 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";
|
|
}
|
|
|
|
// Add target-specific flags.
|
|
if(this->Target->GetProperty("COMPILE_FLAGS"))
|
|
{
|
|
std::string flags;
|
|
this->LocalGenerator->AppendFlags
|
|
(flags, this->Target->GetProperty("COMPILE_FLAGS"));
|
|
*this->FlagFileStream << "# TARGET_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)
|
|
{
|
|
// don't know anything about this file so skip it
|
|
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(this->ObjectFiles.find(obj) == this->ObjectFiles.end())
|
|
{
|
|
this->ObjectFiles.insert(obj);
|
|
}
|
|
else
|
|
{
|
|
cmOStringStream err;
|
|
err << "Warning: Source file \""
|
|
<< source.GetFullPath()
|
|
<< "\" 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.
|
|
if ( source.GetPropertyAsBool("EXTRA_CONTENT") )
|
|
{
|
|
this->ExtraContent.insert(obj);
|
|
}
|
|
this->Objects.push_back(obj);
|
|
|
|
// TODO: Remove
|
|
//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->
|
|
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->LocalObjectFiles[objNoTargetDir].
|
|
push_back(
|
|
cmLocalUnixMakefileGenerator3::LocalObjectEntry(this->Target, lang)
|
|
);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
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();
|
|
if ( source.GetPropertyAsBool("MACOSX_CONTENT") )
|
|
{
|
|
relativeObj = "";
|
|
}
|
|
relativeObj += obj;
|
|
// Write the build rule.
|
|
|
|
// Build the set of compiler flags.
|
|
std::string flags;
|
|
|
|
// Add language-specific flags.
|
|
std::string langFlags = "$(";
|
|
langFlags += lang;
|
|
langFlags += "_FLAGS)";
|
|
this->LocalGenerator->AppendFlags(flags, langFlags.c_str());
|
|
|
|
// Add target-specific 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";
|
|
}
|
|
|
|
// Get the output paths for source and object files.
|
|
std::string sourceFile = source.GetFullPath();
|
|
if(this->LocalGenerator->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;
|
|
|
|
// add in a progress call if needed
|
|
std::string progressDir = this->Makefile->GetHomeOutputDirectory();
|
|
progressDir += cmake::GetCMakeFilesDirectory();
|
|
cmOStringStream progCmd;
|
|
progCmd << "$(CMAKE_COMMAND) -E cmake_progress_report ";
|
|
progCmd << this->LocalGenerator->Convert(progressDir.c_str(),
|
|
cmLocalGenerator::FULL,
|
|
cmLocalGenerator::SHELL);
|
|
this->NumberOfProgressActions++;
|
|
progCmd << " $(CMAKE_PROGRESS_"
|
|
<< this->NumberOfProgressActions
|
|
<< ")";
|
|
commands.push_back(progCmd.str());
|
|
|
|
std::string buildEcho = "Building ";
|
|
buildEcho += lang;
|
|
buildEcho += " object ";
|
|
buildEcho += relativeObj;
|
|
this->LocalGenerator->AppendEcho(commands, buildEcho.c_str(),
|
|
cmLocalUnixMakefileGenerator3::EchoBuild);
|
|
|
|
// 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);
|
|
|
|
std::string targetOutPathPDB;
|
|
{
|
|
std::string targetFullPathPDB;
|
|
const char* configName = this->LocalGenerator->ConfigurationName.c_str();
|
|
if(this->Target->GetType() == cmTarget::EXECUTABLE ||
|
|
this->Target->GetType() == cmTarget::STATIC_LIBRARY ||
|
|
this->Target->GetType() == cmTarget::SHARED_LIBRARY ||
|
|
this->Target->GetType() == cmTarget::MODULE_LIBRARY)
|
|
{
|
|
targetFullPathPDB = this->Target->GetDirectory();
|
|
targetFullPathPDB += "/";
|
|
targetFullPathPDB += this->Target->GetPDBName(configName);
|
|
}
|
|
targetOutPathPDB =
|
|
this->Convert(targetFullPathPDB.c_str(),cmLocalGenerator::FULL,
|
|
cmLocalGenerator::SHELL);
|
|
}
|
|
cmLocalGenerator::RuleVariables vars;
|
|
vars.Language = lang;
|
|
vars.TargetPDB = targetOutPathPDB.c_str();
|
|
vars.Source = sourceFile.c_str();
|
|
std::string shellrelativeObj =
|
|
this->Convert(relativeObj.c_str(),
|
|
cmLocalGenerator::NONE,
|
|
cmLocalGenerator::SHELL).c_str();
|
|
vars.Object = shellrelativeObj.c_str();
|
|
std::string objdir = this->LocalGenerator->GetHomeRelativeOutputPath();
|
|
objdir = this->Convert(objdir.c_str(),
|
|
cmLocalGenerator::START_OUTPUT,
|
|
cmLocalGenerator::SHELL);
|
|
std::string objectDir = cmSystemTools::GetFilenamePath(obj);
|
|
vars.ObjectDir = objectDir.c_str();
|
|
vars.Flags = flags.c_str();
|
|
|
|
// Expand placeholders in the commands.
|
|
for(std::vector<std::string>::iterator i = commands.begin();
|
|
i != commands.end(); ++i)
|
|
{
|
|
this->LocalGenerator->ExpandRuleVariables(*i, vars);
|
|
}
|
|
|
|
// 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, false);
|
|
|
|
// Write the rule.
|
|
this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0,
|
|
relativeObj.c_str(),
|
|
depends, commands, false);
|
|
|
|
bool lang_is_c_or_cxx = ((strcmp(lang, "C") == 0) ||
|
|
(strcmp(lang, "CXX") == 0));
|
|
bool do_preprocess_rules = lang_is_c_or_cxx &&
|
|
this->LocalGenerator->GetCreatePreprocessedSourceRules();
|
|
bool do_assembly_rules = lang_is_c_or_cxx &&
|
|
this->LocalGenerator->GetCreateAssemblySourceRules();
|
|
if(do_preprocess_rules || do_assembly_rules)
|
|
{
|
|
std::vector<std::string> force_depends;
|
|
force_depends.push_back("cmake_force");
|
|
std::string::size_type dot_pos = relativeObj.rfind(".");
|
|
std::string relativeObjBase = relativeObj.substr(0, dot_pos);
|
|
|
|
if(do_preprocess_rules)
|
|
{
|
|
commands.clear();
|
|
std::string relativeObjI = relativeObjBase + ".i";
|
|
|
|
std::string preprocessEcho = "Preprocessing ";
|
|
preprocessEcho += lang;
|
|
preprocessEcho += " source to ";
|
|
preprocessEcho += relativeObjI;
|
|
this->LocalGenerator->AppendEcho(
|
|
commands, preprocessEcho.c_str(),
|
|
cmLocalUnixMakefileGenerator3::EchoBuild
|
|
);
|
|
|
|
std::string preprocessRuleVar = "CMAKE_";
|
|
preprocessRuleVar += lang;
|
|
preprocessRuleVar += "_CREATE_PREPROCESSED_SOURCE";
|
|
if(const char* preprocessRule =
|
|
this->Makefile->GetDefinition(preprocessRuleVar.c_str()))
|
|
{
|
|
cmSystemTools::ExpandListArgument(preprocessRule, commands);
|
|
|
|
vars.PreprocessedSource = relativeObjI.c_str();
|
|
|
|
// Expand placeholders in the commands.
|
|
for(std::vector<std::string>::iterator i = commands.begin();
|
|
i != commands.end(); ++i)
|
|
{
|
|
this->LocalGenerator->ExpandRuleVariables(*i, vars);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
std::string cmd = "$(CMAKE_COMMAND) -E cmake_unimplemented_variable ";
|
|
cmd += preprocessRuleVar;
|
|
commands.push_back(cmd);
|
|
}
|
|
|
|
this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0,
|
|
relativeObjI.c_str(),
|
|
force_depends, commands, false);
|
|
}
|
|
|
|
if(do_assembly_rules)
|
|
{
|
|
commands.clear();
|
|
std::string relativeObjS = relativeObjBase + ".s";
|
|
|
|
std::string assemblyEcho = "Compiling ";
|
|
assemblyEcho += lang;
|
|
assemblyEcho += " source to assembly ";
|
|
assemblyEcho += relativeObjS;
|
|
this->LocalGenerator->AppendEcho(
|
|
commands, assemblyEcho.c_str(),
|
|
cmLocalUnixMakefileGenerator3::EchoBuild
|
|
);
|
|
|
|
std::string assemblyRuleVar = "CMAKE_";
|
|
assemblyRuleVar += lang;
|
|
assemblyRuleVar += "_CREATE_ASSEMBLY_SOURCE";
|
|
if(const char* assemblyRule =
|
|
this->Makefile->GetDefinition(assemblyRuleVar.c_str()))
|
|
{
|
|
cmSystemTools::ExpandListArgument(assemblyRule, commands);
|
|
|
|
vars.AssemblySource = relativeObjS.c_str();
|
|
|
|
// Expand placeholders in the commands.
|
|
for(std::vector<std::string>::iterator i = commands.begin();
|
|
i != commands.end(); ++i)
|
|
{
|
|
this->LocalGenerator->ExpandRuleVariables(*i, vars);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
std::string cmd = "$(CMAKE_COMMAND) -E cmake_unimplemented_variable ";
|
|
cmd += assemblyRuleVar;
|
|
commands.push_back(cmd);
|
|
}
|
|
|
|
this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0,
|
|
relativeObjS.c_str(),
|
|
force_depends, commands, false);
|
|
}
|
|
}
|
|
|
|
// 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, true);
|
|
|
|
// 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, true);
|
|
|
|
// 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,
|
|
true);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
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, true);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void cmMakefileTargetGenerator::WriteTargetCleanRules()
|
|
{
|
|
std::vector<std::string> depends;
|
|
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->Target);
|
|
this->LocalGenerator->CreateCDCommand
|
|
(commands,
|
|
this->Makefile->GetStartOutputDirectory(),
|
|
this->Makefile->GetHomeOutputDirectory());
|
|
|
|
// Write the rule.
|
|
this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0,
|
|
cleanTarget.c_str(),
|
|
depends, commands, true);
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
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, true);
|
|
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(),
|
|
cmLocalUnixMakefileGenerator3::EchoDepend);
|
|
|
|
// 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.
|
|
#if !defined(_WIN32) || defined(__CYGWIN__)
|
|
// This platform supports symlinks, so cmSystemTools will translate
|
|
// paths. Make sure PWD is set to the original name of the home
|
|
// output directory to help cmSystemTools to create the same
|
|
// translation table for the dependency scanning process.
|
|
depCmd << "cd "
|
|
<< (this->LocalGenerator->Convert(
|
|
this->Makefile->GetHomeOutputDirectory(),
|
|
cmLocalGenerator::FULL, cmLocalGenerator::SHELL))
|
|
<< " && ";
|
|
#endif
|
|
// Generate a call this signature:
|
|
//
|
|
// cmake -E cmake_depends <generator>
|
|
// <home-src-dir> <start-src-dir>
|
|
// <home-out-dir> <start-out-dir>
|
|
// <dep-info>
|
|
//
|
|
// This gives the dependency scanner enough information to recreate
|
|
// the state of our local generator sufficiently for its needs.
|
|
depCmd << "$(CMAKE_COMMAND) -E cmake_depends \""
|
|
<< this->GlobalGenerator->GetName() << "\" "
|
|
<< this->Convert(this->Makefile->GetHomeDirectory(),
|
|
cmLocalGenerator::FULL, cmLocalGenerator::SHELL)
|
|
<< " "
|
|
<< this->Convert(this->Makefile->GetStartDirectory(),
|
|
cmLocalGenerator::FULL, cmLocalGenerator::SHELL)
|
|
<< " "
|
|
<< this->Convert(this->Makefile->GetHomeOutputDirectory(),
|
|
cmLocalGenerator::FULL, cmLocalGenerator::SHELL)
|
|
<< " "
|
|
<< this->Convert(this->Makefile->GetStartOutputDirectory(),
|
|
cmLocalGenerator::FULL, cmLocalGenerator::SHELL)
|
|
<< " "
|
|
<< this->Convert(this->InfoFileNameFull.c_str(),
|
|
cmLocalGenerator::FULL, cmLocalGenerator::SHELL);
|
|
commands.push_back(depCmd.str());
|
|
|
|
// Make sure all custom command outputs in this target are built.
|
|
if(this->CustomCommandDriver == OnDepends)
|
|
{
|
|
this->DriveCustomCommands(depends);
|
|
}
|
|
|
|
// Write the rule.
|
|
this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0,
|
|
depMark.c_str(),
|
|
depends, commands, false);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void
|
|
cmMakefileTargetGenerator
|
|
::DriveCustomCommands(std::vector<std::string>& depends)
|
|
{
|
|
// Depend on all custom command outputs.
|
|
const std::vector<cmSourceFile*>& sources =
|
|
this->Target->GetSourceFiles();
|
|
for(std::vector<cmSourceFile*>::const_iterator source = sources.begin();
|
|
source != sources.end(); ++source)
|
|
{
|
|
if(cmCustomCommand* cc = (*source)->GetCustomCommand())
|
|
{
|
|
const std::vector<std::string>& outputs = cc->GetOutputs();
|
|
for(std::vector<std::string>::const_iterator o = outputs.begin();
|
|
o != outputs.end(); ++o)
|
|
{
|
|
depends.push_back(*o);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
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
|
|
::GenerateCustomRuleFile(const cmCustomCommand& cc)
|
|
{
|
|
// Collect the commands.
|
|
std::vector<std::string> commands;
|
|
std::string comment = this->LocalGenerator->ConstructComment(cc);
|
|
if(!comment.empty())
|
|
{
|
|
// add in a progress call if needed
|
|
std::string progressDir = this->Makefile->GetHomeOutputDirectory();
|
|
progressDir += cmake::GetCMakeFilesDirectory();
|
|
cmOStringStream progCmd;
|
|
progCmd << "$(CMAKE_COMMAND) -E cmake_progress_report ";
|
|
progCmd << this->LocalGenerator->Convert(progressDir.c_str(),
|
|
cmLocalGenerator::FULL,
|
|
cmLocalGenerator::SHELL);
|
|
this->NumberOfProgressActions++;
|
|
progCmd << " $(CMAKE_PROGRESS_"
|
|
<< this->NumberOfProgressActions
|
|
<< ")";
|
|
commands.push_back(progCmd.str());
|
|
this->LocalGenerator
|
|
->AppendEcho(commands, comment.c_str(),
|
|
cmLocalUnixMakefileGenerator3::EchoGenerate);
|
|
}
|
|
this->LocalGenerator->AppendCustomCommand(commands, cc);
|
|
|
|
// Collect the dependencies.
|
|
std::vector<std::string> depends;
|
|
this->LocalGenerator->AppendCustomDepend(depends, cc);
|
|
|
|
// Add a dependency on the rule file itself.
|
|
this->LocalGenerator->AppendRuleDepend(depends,
|
|
this->BuildFileNameFull.c_str());
|
|
|
|
// Check whether we need to bother checking for a symbolic output.
|
|
bool need_symbolic = this->GlobalGenerator->GetNeedSymbolicMark();
|
|
|
|
// Write the rule.
|
|
const std::vector<std::string>& outputs = cc.GetOutputs();
|
|
std::vector<std::string>::const_iterator o = outputs.begin();
|
|
{
|
|
bool symbolic = false;
|
|
if(need_symbolic)
|
|
{
|
|
if(cmSourceFile* sf = this->Makefile->GetSource(o->c_str()))
|
|
{
|
|
symbolic = sf->GetPropertyAsBool("SYMBOLIC");
|
|
}
|
|
}
|
|
this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0,
|
|
o->c_str(), depends, commands,
|
|
symbolic);
|
|
}
|
|
|
|
// Write rules to drive building any outputs beyond the first.
|
|
const char* in = o->c_str();
|
|
for(++o; o != outputs.end(); ++o)
|
|
{
|
|
bool symbolic = false;
|
|
if(need_symbolic)
|
|
{
|
|
if(cmSourceFile* sf = this->Makefile->GetSource(o->c_str()))
|
|
{
|
|
symbolic = sf->GetPropertyAsBool("SYMBOLIC");
|
|
}
|
|
}
|
|
this->GenerateExtraOutput(o->c_str(), in, symbolic);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void
|
|
cmMakefileTargetGenerator
|
|
::GenerateExtraOutput(const char* out, const char* in, bool symbolic)
|
|
{
|
|
// Add a rule to build the primary output if the extra output needs
|
|
// to be created.
|
|
std::vector<std::string> commands;
|
|
std::vector<std::string> depends;
|
|
std::string emptyCommand = this->GlobalGenerator->GetEmptyRuleHackCommand();
|
|
if(!emptyCommand.empty())
|
|
{
|
|
commands.push_back(emptyCommand);
|
|
}
|
|
depends.push_back(in);
|
|
this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0,
|
|
out, depends, commands,
|
|
symbolic);
|
|
|
|
// Register the extra output as paired with the first output so that
|
|
// the check-build-system step will remove the primary output if any
|
|
// extra outputs are missing. This forces the rule to regenerate
|
|
// all outputs.
|
|
this->GlobalGenerator->AddMultipleOutputPair(out, in);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
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)
|
|
{
|
|
if ( this->ExtraContent.find(i->c_str()) != this->ExtraContent.end() )
|
|
{
|
|
continue;
|
|
}
|
|
*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";
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void
|
|
cmMakefileTargetGenerator
|
|
::WriteObjectsString(std::string& buildObjs)
|
|
{
|
|
std::string object;
|
|
const char* no_quoted =
|
|
this->Makefile->GetDefinition("CMAKE_NO_QUOTED_OBJECTS");
|
|
const char* space = "";
|
|
for(std::vector<std::string>::const_iterator i = this->Objects.begin();
|
|
i != this->Objects.end(); ++i)
|
|
{
|
|
if ( this->ExtraContent.find(i->c_str()) != this->ExtraContent.end() )
|
|
{
|
|
continue;
|
|
}
|
|
buildObjs += space;
|
|
space = " ";
|
|
if(no_quoted)
|
|
{
|
|
buildObjs +=
|
|
this->Convert(i->c_str(), cmLocalGenerator::START_OUTPUT,
|
|
cmLocalGenerator::SHELL);
|
|
}
|
|
else
|
|
{
|
|
buildObjs +=
|
|
this->LocalGenerator->ConvertToQuotedOutputPath(i->c_str());
|
|
}
|
|
}
|
|
for(std::vector<std::string>::const_iterator i =
|
|
this->ExternalObjects.begin();
|
|
i != this->ExternalObjects.end(); ++i)
|
|
{
|
|
buildObjs += space;
|
|
space = " ";
|
|
if(no_quoted)
|
|
{
|
|
buildObjs +=
|
|
this->Convert(i->c_str(), cmLocalGenerator::START_OUTPUT,
|
|
cmLocalGenerator::SHELL);
|
|
}
|
|
else
|
|
{
|
|
buildObjs +=
|
|
this->LocalGenerator->ConvertToQuotedOutputPath(i->c_str());
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void cmMakefileTargetGenerator::WriteTargetDriverRule(const char* main_output,
|
|
bool relink)
|
|
{
|
|
// Compute the name of the driver target.
|
|
std::string dir =
|
|
this->LocalGenerator->GetRelativeTargetDirectory(*this->Target);
|
|
std::string buildTargetRuleName = dir;
|
|
buildTargetRuleName += relink?"/preinstall":"/build";
|
|
buildTargetRuleName = this->Convert(buildTargetRuleName.c_str(),
|
|
cmLocalGenerator::HOME_OUTPUT,
|
|
cmLocalGenerator::UNCHANGED);
|
|
|
|
// Build the list of target outputs to drive.
|
|
std::vector<std::string> depends;
|
|
if(main_output)
|
|
{
|
|
depends.push_back(main_output);
|
|
}
|
|
|
|
const char* comment = 0;
|
|
if(relink)
|
|
{
|
|
// Setup the comment for the preinstall driver.
|
|
comment = "Rule to relink during preinstall.";
|
|
}
|
|
else
|
|
{
|
|
// Setup the comment for the main build driver.
|
|
comment = "Rule to build all files generated by this target.";
|
|
|
|
// Make sure all custom command outputs in this target are built.
|
|
if(this->CustomCommandDriver == OnBuild)
|
|
{
|
|
this->DriveCustomCommands(depends);
|
|
}
|
|
}
|
|
|
|
// Write the driver rule.
|
|
std::vector<std::string> no_commands;
|
|
this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, comment,
|
|
buildTargetRuleName.c_str(),
|
|
depends, no_commands, true);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
std::string cmMakefileTargetGenerator::GetFrameworkFlags()
|
|
{
|
|
#ifndef __APPLE__
|
|
return std::string();
|
|
#else
|
|
std::set<cmStdString> emitted;
|
|
emitted.insert("/System/Library/Frameworks");
|
|
std::vector<std::string> includes;
|
|
this->LocalGenerator->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;
|
|
}
|
|
// Compute which library configuration to link.
|
|
cmTarget::LinkLibraryType linkType = cmTarget::OPTIMIZED;
|
|
if(cmSystemTools::UpperCase(
|
|
this->LocalGenerator->ConfigurationName.c_str()) == "DEBUG")
|
|
{
|
|
linkType = cmTarget::DEBUG;
|
|
}
|
|
// 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::LinkLibraryVectorType& tlibs =
|
|
this->Target->GetLinkLibraries();
|
|
for(cmTarget::LinkLibraryVectorType::const_iterator lib = tlibs.begin();
|
|
lib != tlibs.end(); ++lib)
|
|
{
|
|
// skip the library if it is not general and the link type
|
|
// does not match the current target
|
|
if(lib->second != cmTarget::GENERAL &&
|
|
lib->second != linkType)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Don't emit the same library twice for this target.
|
|
if(emitted.insert(lib->first).second)
|
|
{
|
|
// Depend on other CMake targets.
|
|
if(cmTarget* tgt =
|
|
this->GlobalGenerator->FindTarget(0, lib->first.c_str(), false))
|
|
{
|
|
if(const char* location =
|
|
tgt->GetLocation(this->LocalGenerator->ConfigurationName.c_str()))
|
|
{
|
|
depends.push_back(location);
|
|
}
|
|
}
|
|
// depend on full path libs as well
|
|
else if(cmSystemTools::FileIsFullPath(lib->first.c_str()))
|
|
{
|
|
depends.push_back(lib->first.c_str());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void cmMakefileTargetGenerator
|
|
::CloseFileStreams()
|
|
{
|
|
delete this->BuildFileStream;
|
|
delete this->InfoFileStream;
|
|
delete this->FlagFileStream;
|
|
}
|
|
|
|
void cmMakefileTargetGenerator::RemoveForbiddenFlags(const char* flagVar,
|
|
const char* linkLang,
|
|
std::string& linkFlags)
|
|
{
|
|
// check for language flags that are not allowed at link time, and
|
|
// remove them, -w on darwin for gcc -w -dynamiclib sends -w to libtool
|
|
// which fails, there may be more]
|
|
|
|
std::string removeFlags = "CMAKE_";
|
|
removeFlags += linkLang;
|
|
removeFlags += flagVar;
|
|
std::string removeflags =
|
|
this->Makefile->GetSafeDefinition(removeFlags.c_str());
|
|
std::vector<std::string> removeList;
|
|
cmSystemTools::ExpandListArgument(removeflags, removeList);
|
|
for(std::vector<std::string>::iterator i = removeList.begin();
|
|
i != removeList.end(); ++i)
|
|
{
|
|
cmSystemTools::ReplaceString(linkFlags, i->c_str(), "");
|
|
}
|
|
}
|
|
|
|
void cmMakefileTargetGenerator::WriteProgressVariables(unsigned long total,
|
|
unsigned long ¤t)
|
|
{
|
|
cmGeneratedFileStream *progressFileStream =
|
|
new cmGeneratedFileStream(this->ProgressFileNameFull.c_str());
|
|
if(!progressFileStream)
|
|
{
|
|
return;
|
|
}
|
|
|
|
unsigned long num;
|
|
unsigned long i;
|
|
for (i = 1; i <= this->NumberOfProgressActions; ++i)
|
|
{
|
|
*progressFileStream
|
|
<< "CMAKE_PROGRESS_" << i << " = ";
|
|
if (total <= 100)
|
|
{
|
|
num = i + current;
|
|
*progressFileStream << num;
|
|
this->LocalGenerator->ProgressFiles[this->Target->GetName()]
|
|
.push_back(num);
|
|
}
|
|
else if (((i+current)*100)/total > ((i-1+current)*100)/total)
|
|
{
|
|
num = ((i+current)*100)/total;
|
|
*progressFileStream << num;
|
|
this->LocalGenerator->ProgressFiles[this->Target->GetName()]
|
|
.push_back(num);
|
|
}
|
|
*progressFileStream << "\n";
|
|
}
|
|
*progressFileStream << "\n";
|
|
current += this->NumberOfProgressActions;
|
|
delete progressFileStream;
|
|
}
|