CMake/Source/cmGlobalUnixMakefileGenerat...

1003 lines
36 KiB
C++
Raw Normal View History

Simplify CMake per-source license notices Per-source copyright/license notice headers that spell out copyright holder names and years are hard to maintain and often out-of-date or plain wrong. Precise contributor information is already maintained automatically by the version control tool. Ultimately it is the receiver of a file who is responsible for determining its licensing status, and per-source notices are merely a convenience. Therefore it is simpler and more accurate for each source to have a generic notice of the license name and references to more detailed information on copyright holders and full license terms. Our `Copyright.txt` file now contains a list of Contributors whose names appeared source-level copyright notices. It also references version control history for more precise information. Therefore we no longer need to spell out the list of Contributors in each source file notice. Replace CMake per-source copyright/license notice headers with a short description of the license and links to `Copyright.txt` and online information available from "https://cmake.org/licensing". The online URL also handles cases of modules being copied out of our source into other projects, so we can drop our notices about replacing links with full license text. Run the `Utilities/Scripts/filter-notices.bash` script to perform the majority of the replacements mechanically. Manually fix up shebang lines and trailing newlines in a few files. Manually update the notices in a few files that the script does not handle.
2016-09-27 22:01:08 +03:00
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
2005-05-05 20:45:53 +04:00
#include "cmGlobalUnixMakefileGenerator3.h"
#include "cmAlgorithms.h"
#include "cmDocumentationEntry.h"
#include "cmGeneratedFileStream.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalGenerator.h"
#include "cmLocalGenerator.h"
2005-05-05 20:45:53 +04:00
#include "cmLocalUnixMakefileGenerator3.h"
#include "cmMakefile.h"
#include "cmMakefileTargetGenerator.h"
#include "cmOutputConverter.h"
#include "cmSystemTools.h"
#include "cmTarget.h"
#include "cmTargetDepend.h"
2005-05-05 20:45:53 +04:00
#include "cmake.h"
#include <algorithm>
#include <functional>
#include <sstream>
#include <utility>
cmGlobalUnixMakefileGenerator3::cmGlobalUnixMakefileGenerator3(cmake* cm)
: cmGlobalCommonGenerator(cm)
2005-05-05 20:45:53 +04:00
{
// This type of makefile always requires unix style paths
2006-03-15 19:02:08 +03:00
this->ForceUnixPaths = true;
this->FindMakeProgramFile = "CMakeUnixFindMake.cmake";
this->ToolSupportsColor = true;
#if defined(_WIN32) || defined(__VMS)
this->UseLinkScript = false;
#else
this->UseLinkScript = true;
#endif
2016-06-27 23:44:16 +03:00
this->CommandDatabase = CM_NULLPTR;
this->IncludeDirective = "include";
this->DefineWindowsNULL = false;
this->PassMakeflags = false;
this->UnixCD = true;
2005-05-05 20:45:53 +04:00
}
void cmGlobalUnixMakefileGenerator3::EnableLanguage(
std::vector<std::string> const& languages, cmMakefile* mf, bool optional)
2005-05-05 20:45:53 +04:00
{
this->cmGlobalGenerator::EnableLanguage(languages, mf, optional);
for (std::vector<std::string>::const_iterator l = languages.begin();
l != languages.end(); ++l) {
if (*l == "NONE") {
2005-09-02 01:14:56 +04:00
continue;
2005-05-05 20:45:53 +04:00
}
this->ResolveLanguageCompiler(*l, mf, optional);
}
2005-05-05 20:45:53 +04:00
}
///! Create a local generator appropriate to this Global Generator
cmLocalGenerator* cmGlobalUnixMakefileGenerator3::CreateLocalGenerator(
cmMakefile* mf)
2005-05-05 20:45:53 +04:00
{
return new cmLocalUnixMakefileGenerator3(this, mf);
2005-05-05 20:45:53 +04:00
}
void cmGlobalUnixMakefileGenerator3::GetDocumentation(
cmDocumentationEntry& entry)
2005-05-05 20:45:53 +04:00
{
entry.Name = cmGlobalUnixMakefileGenerator3::GetActualName();
entry.Brief = "Generates standard UNIX makefiles.";
2005-05-05 20:45:53 +04:00
}
std::string cmGlobalUnixMakefileGenerator3::GetEditCacheCommand() const
{
// If generating for an extra IDE, the edit_cache target cannot
// launch a terminal-interactive tool, so always use cmake-gui.
if (!this->GetExtraGeneratorName().empty()) {
return cmSystemTools::GetCMakeGUICommand();
}
// Use an internal cache entry to track the latest dialog used
// to edit the cache, and use that for the edit_cache target.
cmake* cm = this->GetCMakeInstance();
std::string editCacheCommand = cm->GetCMakeEditCommand();
if (!cm->GetCacheDefinition("CMAKE_EDIT_COMMAND") ||
!editCacheCommand.empty()) {
if (editCacheCommand.empty()) {
editCacheCommand = cmSystemTools::GetCMakeCursesCommand();
}
if (editCacheCommand.empty()) {
editCacheCommand = cmSystemTools::GetCMakeGUICommand();
}
if (!editCacheCommand.empty()) {
cm->AddCacheEntry("CMAKE_EDIT_COMMAND", editCacheCommand.c_str(),
"Path to cache edit program executable.",
cmState::INTERNAL);
}
}
const char* edit_cmd = cm->GetCacheDefinition("CMAKE_EDIT_COMMAND");
return edit_cmd ? edit_cmd : "";
}
void cmGlobalUnixMakefileGenerator3::ComputeTargetObjectDirectory(
cmGeneratorTarget* gt) const
{
// Compute full path to object file directory for this target.
std::string dir;
2015-10-21 20:59:12 +03:00
dir += gt->LocalGenerator->GetCurrentBinaryDirectory();
dir += "/";
dir += gt->LocalGenerator->GetTargetDirectory(gt);
dir += "/";
gt->ObjectDirectory = dir;
}
void cmGlobalUnixMakefileGenerator3::Configure()
{
// Initialize CMAKE_EDIT_COMMAND cache entry.
this->GetEditCacheCommand();
this->cmGlobalGenerator::Configure();
}
2010-11-12 00:02:07 +03:00
void cmGlobalUnixMakefileGenerator3::Generate()
2005-05-06 22:49:38 +04:00
{
// first do superclass method
this->cmGlobalGenerator::Generate();
// initialize progress
unsigned long total = 0;
for (ProgressMapType::const_iterator pmi = this->ProgressMap.begin();
pmi != this->ProgressMap.end(); ++pmi) {
total += pmi->second.NumberOfActions;
}
2005-05-06 22:49:38 +04:00
// write each target's progress.make this loop is done twice. Bascially the
// Generate pass counts all the actions, the first loop below determines
// how many actions have progress updates for each target and writes to
// corrrect variable values for everything except the all targets. The
// second loop actually writes out correct values for the all targets as
// well. This is because the all targets require more information that is
// computed in the first loop.
unsigned long current = 0;
for (ProgressMapType::iterator pmi = this->ProgressMap.begin();
pmi != this->ProgressMap.end(); ++pmi) {
pmi->second.WriteProgressVariables(total, current);
}
for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) {
cmLocalGenerator* lg = this->LocalGenerators[i];
std::string markFileName = lg->GetCurrentBinaryDirectory();
markFileName += "/";
markFileName += cmake::GetCMakeFilesDirectory();
markFileName += "/progress.marks";
cmGeneratedFileStream markFile(markFileName.c_str());
markFile << this->CountProgressMarksInAll(lg) << "\n";
}
2005-05-06 22:49:38 +04:00
// write the main makefile
this->WriteMainMakefile2();
2005-05-06 22:49:38 +04:00
this->WriteMainCMakefile();
2011-01-13 07:39:13 +03:00
2016-06-27 23:44:16 +03:00
if (this->CommandDatabase != CM_NULLPTR) {
2011-01-13 07:39:13 +03:00
*this->CommandDatabase << std::endl << "]";
delete this->CommandDatabase;
2016-06-27 23:44:16 +03:00
this->CommandDatabase = CM_NULLPTR;
2011-01-13 07:39:13 +03:00
}
}
void cmGlobalUnixMakefileGenerator3::AddCXXCompileCommand(
const std::string& sourceFile, const std::string& workingDirectory,
const std::string& compileCommand)
{
2016-06-27 23:44:16 +03:00
if (this->CommandDatabase == CM_NULLPTR) {
2011-01-13 07:39:13 +03:00
std::string commandDatabaseName =
std::string(this->GetCMakeInstance()->GetHomeOutputDirectory()) +
"/compile_commands.json";
2011-01-13 07:39:13 +03:00
this->CommandDatabase =
new cmGeneratedFileStream(commandDatabaseName.c_str());
*this->CommandDatabase << "[" << std::endl;
} else {
2011-01-13 07:39:13 +03:00
*this->CommandDatabase << "," << std::endl;
}
2011-01-13 07:39:13 +03:00
*this->CommandDatabase << "{" << std::endl
<< " \"directory\": \""
<< cmGlobalGenerator::EscapeJSON(workingDirectory)
<< "\"," << std::endl
<< " \"command\": \""
<< cmGlobalGenerator::EscapeJSON(compileCommand)
<< "\"," << std::endl
<< " \"file\": \""
<< cmGlobalGenerator::EscapeJSON(sourceFile) << "\""
<< std::endl
<< "}";
2005-05-06 22:49:38 +04:00
}
void cmGlobalUnixMakefileGenerator3::WriteMainMakefile2()
{
// Open the output file. This should not be copy-if-different
// because the check-build-system step compares the makefile time to
// see if the build system must be regenerated.
2010-11-12 00:02:07 +03:00
std::string makefileName =
this->GetCMakeInstance()->GetHomeOutputDirectory();
makefileName += cmake::GetCMakeFilesDirectory();
makefileName += "/Makefile2";
cmGeneratedFileStream makefileStream(makefileName.c_str());
if (!makefileStream) {
return;
}
2010-11-12 00:02:07 +03:00
// get a local generator for some useful methods
cmLocalUnixMakefileGenerator3* lg =
static_cast<cmLocalUnixMakefileGenerator3*>(this->LocalGenerators[0]);
2010-11-12 00:02:07 +03:00
// Write the do not edit header.
lg->WriteDisclaimer(makefileStream);
// Write the main entry point target. This must be the VERY first
// target so that make with no arguments will run it.
// Just depend on the all target to drive the build.
std::vector<std::string> depends;
std::vector<std::string> no_commands;
depends.push_back("all");
// Write the rule.
lg->WriteMakeRule(makefileStream,
"Default target executed when no arguments are "
"given to make.",
"default_target", depends, no_commands, true);
depends.clear();
// The all and preinstall rules might never have any dependencies
// added to them.
if (this->EmptyRuleHackDepends != "") {
2006-03-15 19:02:08 +03:00
depends.push_back(this->EmptyRuleHackDepends);
}
// Write and empty all:
lg->WriteMakeRule(makefileStream, "The main recursive all target", "all",
depends, no_commands, true);
// Write an empty preinstall:
lg->WriteMakeRule(makefileStream, "The main recursive preinstall target",
"preinstall", depends, no_commands, true);
// Write out the "special" stuff
lg->WriteSpecialTargetsTop(makefileStream);
2010-11-12 00:02:07 +03:00
// write the target convenience rules
unsigned int i;
for (i = 0; i < this->LocalGenerators.size(); ++i) {
lg = static_cast<cmLocalUnixMakefileGenerator3*>(this->LocalGenerators[i]);
this->WriteConvenienceRules2(makefileStream, lg);
}
lg = static_cast<cmLocalUnixMakefileGenerator3*>(this->LocalGenerators[0]);
lg->WriteSpecialTargetsBottom(makefileStream);
}
2005-05-05 20:45:53 +04:00
void cmGlobalUnixMakefileGenerator3::WriteMainCMakefile()
{
// Open the output file. This should not be copy-if-different
// because the check-build-system step compares the makefile time to
// see if the build system must be regenerated.
2010-11-12 00:02:07 +03:00
std::string cmakefileName =
2005-05-06 22:49:38 +04:00
this->GetCMakeInstance()->GetHomeOutputDirectory();
cmakefileName += cmake::GetCMakeFilesDirectory();
cmakefileName += "/Makefile.cmake";
2005-05-05 20:45:53 +04:00
cmGeneratedFileStream cmakefileStream(cmakefileName.c_str());
if (!cmakefileStream) {
2005-05-05 20:45:53 +04:00
return;
}
2005-05-06 22:49:38 +04:00
2010-11-12 00:02:07 +03:00
std::string makefileName =
2005-05-06 22:49:38 +04:00
this->GetCMakeInstance()->GetHomeOutputDirectory();
makefileName += "/Makefile";
2010-11-12 00:02:07 +03:00
2005-05-05 20:45:53 +04:00
// get a local generator for some useful methods
cmLocalUnixMakefileGenerator3* lg =
static_cast<cmLocalUnixMakefileGenerator3*>(this->LocalGenerators[0]);
2010-11-12 00:02:07 +03:00
2005-05-05 20:45:53 +04:00
// Write the do not edit header.
lg->WriteDisclaimer(cmakefileStream);
2005-05-12 18:49:56 +04:00
// Save the generator name
cmakefileStream << "# The generator used is:\n"
<< "set(CMAKE_DEPENDS_GENERATOR \"" << this->GetName()
<< "\")\n\n";
2005-05-12 18:49:56 +04:00
2005-05-05 20:45:53 +04:00
// for each cmMakefile get its list of dependencies
std::vector<std::string> lfiles;
for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) {
lg = static_cast<cmLocalUnixMakefileGenerator3*>(this->LocalGenerators[i]);
2010-11-12 00:02:07 +03:00
2005-05-05 20:45:53 +04:00
// Get the list of files contributing to this generation step.
lfiles.insert(lfiles.end(), lg->GetMakefile()->GetListFiles().begin(),
2005-05-05 20:45:53 +04:00
lg->GetMakefile()->GetListFiles().end());
}
2005-05-05 20:45:53 +04:00
// Sort the list and remove duplicates.
std::sort(lfiles.begin(), lfiles.end(), std::less<std::string>());
#if !defined(__VMS) // The Compaq STL on VMS crashes, so accept duplicates.
2010-11-12 00:02:07 +03:00
std::vector<std::string>::iterator new_end =
std::unique(lfiles.begin(), lfiles.end());
2005-05-05 20:45:53 +04:00
lfiles.erase(new_end, lfiles.end());
#endif
2005-05-05 20:45:53 +04:00
// reset lg to the first makefile
lg = static_cast<cmLocalUnixMakefileGenerator3*>(this->LocalGenerators[0]);
2005-05-05 20:45:53 +04:00
// Build the path to the cache file.
std::string cache = this->GetCMakeInstance()->GetHomeOutputDirectory();
cache += "/CMakeCache.txt";
std::string currentBinDir = lg->GetCurrentBinaryDirectory();
2005-05-05 20:45:53 +04:00
// Save the list to the cmake file.
cmakefileStream
<< "# The top level Makefile was generated from the following files:\n"
<< "set(CMAKE_MAKEFILE_DEPENDS\n"
<< " \"" << lg->ConvertToRelativePath(currentBinDir, cache) << "\"\n";
for (std::vector<std::string>::const_iterator i = lfiles.begin();
i != lfiles.end(); ++i) {
cmakefileStream << " \"" << lg->ConvertToRelativePath(currentBinDir, *i)
<< "\"\n";
}
cmakefileStream << " )\n\n";
2005-05-05 20:45:53 +04:00
// Build the path to the cache check file.
std::string check = this->GetCMakeInstance()->GetHomeOutputDirectory();
check += cmake::GetCMakeFilesDirectory();
check += "/cmake.check_cache";
2005-05-05 20:45:53 +04:00
// Set the corresponding makefile in the cmake file.
cmakefileStream << "# The corresponding makefile is:\n"
<< "set(CMAKE_MAKEFILE_OUTPUTS\n"
<< " \""
<< lg->ConvertToRelativePath(currentBinDir, makefileName)
<< "\"\n"
<< " \"" << lg->ConvertToRelativePath(currentBinDir, check)
<< "\"\n";
2005-05-05 20:45:53 +04:00
cmakefileStream << " )\n\n";
2005-05-06 22:49:38 +04:00
const std::string binDir = lg->GetBinaryDirectory();
// CMake must rerun if a byproduct is missing.
{
cmakefileStream << "# Byproducts of CMake generate step:\n"
<< "set(CMAKE_MAKEFILE_PRODUCTS\n";
const std::vector<std::string>& outfiles =
lg->GetMakefile()->GetOutputFiles();
for (std::vector<std::string>::const_iterator k = outfiles.begin();
k != outfiles.end(); ++k) {
cmakefileStream << " \"" << lg->ConvertToRelativePath(binDir, *k)
<< "\"\n";
}
// add in all the directory information files
std::string tmpStr;
for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) {
lg =
static_cast<cmLocalUnixMakefileGenerator3*>(this->LocalGenerators[i]);
tmpStr = lg->GetCurrentBinaryDirectory();
tmpStr += cmake::GetCMakeFilesDirectory();
tmpStr += "/CMakeDirectoryInformation.cmake";
cmakefileStream << " \"" << lg->ConvertToRelativePath(binDir, tmpStr)
<< "\"\n";
}
cmakefileStream << " )\n\n";
}
2010-11-12 00:02:07 +03:00
this->WriteMainCMakefileLanguageRules(cmakefileStream,
2006-05-11 18:40:28 +04:00
this->LocalGenerators);
}
void cmGlobalUnixMakefileGenerator3::WriteMainCMakefileLanguageRules(
cmGeneratedFileStream& cmakefileStream,
std::vector<cmLocalGenerator*>& lGenerators)
2005-05-06 22:49:38 +04:00
{
cmLocalUnixMakefileGenerator3* lg;
2005-05-06 22:49:38 +04:00
// now list all the target info files
cmakefileStream << "# Dependency information for all targets:\n";
cmakefileStream << "set(CMAKE_DEPEND_INFO_FILES\n";
for (unsigned int i = 0; i < lGenerators.size(); ++i) {
lg = static_cast<cmLocalUnixMakefileGenerator3*>(lGenerators[i]);
// for all of out targets
2015-10-18 18:06:14 +03:00
std::vector<cmGeneratorTarget*> tgts = lg->GetGeneratorTargets();
for (std::vector<cmGeneratorTarget*>::iterator l = tgts.begin();
l != tgts.end(); l++) {
if (((*l)->GetType() == cmState::EXECUTABLE) ||
((*l)->GetType() == cmState::STATIC_LIBRARY) ||
((*l)->GetType() == cmState::SHARED_LIBRARY) ||
((*l)->GetType() == cmState::MODULE_LIBRARY) ||
((*l)->GetType() == cmState::OBJECT_LIBRARY) ||
((*l)->GetType() == cmState::UTILITY)) {
2015-10-18 18:06:14 +03:00
cmGeneratorTarget* gt = *l;
std::string tname = lg->GetRelativeTargetDirectory(gt);
tname += "/DependInfo.cmake";
cmSystemTools::ConvertToUnixSlashes(tname);
cmakefileStream << " \"" << tname << "\"\n";
2005-05-05 20:45:53 +04:00
}
}
}
cmakefileStream << " )\n";
2005-05-05 20:45:53 +04:00
}
void cmGlobalUnixMakefileGenerator3::WriteDirectoryRule2(
std::ostream& ruleFileStream, cmLocalUnixMakefileGenerator3* lg,
const char* pass, bool check_all, bool check_relink)
2005-05-06 22:49:38 +04:00
{
// Get the relative path to the subdirectory from the top.
std::string makeTarget = lg->GetCurrentBinaryDirectory();
makeTarget += "/";
makeTarget += pass;
// The directory-level rule should depend on the target-level rules
// for all targets in the directory.
std::vector<std::string> depends;
std::vector<cmGeneratorTarget*> targets = lg->GetGeneratorTargets();
for (std::vector<cmGeneratorTarget*>::iterator l = targets.begin();
l != targets.end(); ++l) {
cmGeneratorTarget* gtarget = *l;
int type = gtarget->GetType();
if ((type == cmState::EXECUTABLE) || (type == cmState::STATIC_LIBRARY) ||
(type == cmState::SHARED_LIBRARY) ||
(type == cmState::MODULE_LIBRARY) ||
(type == cmState::OBJECT_LIBRARY) || (type == cmState::UTILITY)) {
// Add this to the list of depends rules in this directory.
if ((!check_all || !gtarget->GetPropertyAsBool("EXCLUDE_FROM_ALL")) &&
(!check_relink ||
gtarget->NeedRelinkBeforeInstall(lg->GetConfigName()))) {
std::string tname = lg->GetRelativeTargetDirectory(gtarget);
tname += "/";
tname += pass;
depends.push_back(tname);
2005-05-19 23:00:35 +04:00
}
}
}
// The directory-level rule should depend on the directory-level
// rules of the subdirectories.
std::vector<cmState::Snapshot> children =
lg->GetStateSnapshot().GetChildren();
for (std::vector<cmState::Snapshot>::const_iterator ci = children.begin();
ci != children.end(); ++ci) {
std::string subdir = ci->GetDirectory().GetCurrentBinary();
subdir += "/";
subdir += pass;
depends.push_back(subdir);
}
// Work-around for makes that drop rules that have no dependencies
// or commands.
if (depends.empty() && this->EmptyRuleHackDepends != "") {
2006-03-15 19:02:08 +03:00
depends.push_back(this->EmptyRuleHackDepends);
}
// Write the rule.
std::string doc = "Convenience name for \"";
doc += pass;
doc += "\" pass in the directory.";
std::vector<std::string> no_commands;
lg->WriteMakeRule(ruleFileStream, doc.c_str(), makeTarget, depends,
no_commands, true);
}
void cmGlobalUnixMakefileGenerator3::WriteDirectoryRules2(
std::ostream& ruleFileStream, cmLocalUnixMakefileGenerator3* lg)
{
// Only subdirectories need these rules.
if (lg->IsRootMakefile()) {
return;
}
2005-05-25 23:09:06 +04:00
// Begin the directory-level rules section.
std::string dir = cmSystemTools::ConvertToOutputPath(
lg->ConvertToRelativePath(lg->GetBinaryDirectory(),
lg->GetCurrentBinaryDirectory())
.c_str());
lg->WriteDivider(ruleFileStream);
ruleFileStream << "# Directory level rules for directory " << dir << "\n\n";
// Write directory-level rules for "all".
this->WriteDirectoryRule2(ruleFileStream, lg, "all", true, false);
// Write directory-level rules for "clean".
this->WriteDirectoryRule2(ruleFileStream, lg, "clean", false, false);
// Write directory-level rules for "preinstall".
this->WriteDirectoryRule2(ruleFileStream, lg, "preinstall", true, true);
}
void cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
std::vector<std::string>& makeCommand, const std::string& makeProgram,
const std::string& /*projectName*/, const std::string& /*projectDir*/,
const std::string& targetName, const std::string& /*config*/, bool fast,
bool /*verbose*/, std::vector<std::string> const& makeOptions)
2006-05-02 17:56:42 +04:00
{
makeCommand.push_back(this->SelectMakeProgram(makeProgram));
2010-11-12 00:02:07 +03:00
2006-05-02 17:56:42 +04:00
// Since we have full control over the invocation of nmake, let us
// make it quiet.
if (cmHasLiteralPrefix(this->GetName(), "NMake Makefiles")) {
makeCommand.push_back("/NOLOGO");
}
makeCommand.insert(makeCommand.end(), makeOptions.begin(),
makeOptions.end());
if (!targetName.empty()) {
cmMakefile* mf;
if (!this->Makefiles.empty()) {
mf = this->Makefiles[0];
} else {
cmState::Snapshot snapshot = this->CMakeInstance->GetCurrentSnapshot();
snapshot.GetDirectory().SetCurrentSource(
this->CMakeInstance->GetHomeDirectory());
snapshot.GetDirectory().SetCurrentBinary(
this->CMakeInstance->GetHomeOutputDirectory());
snapshot.SetDefaultDefinitions();
mf = new cmMakefile(this, snapshot);
}
2010-11-12 00:02:07 +03:00
2006-05-02 17:56:42 +04:00
std::string tname = targetName;
if (fast) {
tname += "/fast";
}
2015-09-24 10:34:53 +03:00
cmOutputConverter conv(mf->GetStateSnapshot());
tname =
conv.ConvertToRelativePath(mf->GetState()->GetBinaryDirectory(), tname);
cmSystemTools::ConvertToOutputSlashes(tname);
makeCommand.push_back(tname);
if (this->Makefiles.empty()) {
delete mf;
2006-05-02 17:56:42 +04:00
}
}
2006-05-02 17:56:42 +04:00
}
void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules(
std::ostream& ruleFileStream, std::set<std::string>& emitted)
{
2010-11-12 00:02:07 +03:00
std::vector<std::string> depends;
std::vector<std::string> commands;
depends.push_back("cmake_check_build_system");
2010-11-12 00:02:07 +03:00
// write the target convenience rules
unsigned int i;
cmLocalUnixMakefileGenerator3* lg;
for (i = 0; i < this->LocalGenerators.size(); ++i) {
lg = static_cast<cmLocalUnixMakefileGenerator3*>(this->LocalGenerators[i]);
// for each target Generate the rule files for each target.
std::vector<cmGeneratorTarget*> targets = lg->GetGeneratorTargets();
for (std::vector<cmGeneratorTarget*>::iterator t = targets.begin();
t != targets.end(); ++t) {
cmGeneratorTarget* gtarget = *t;
// Don't emit the same rule twice (e.g. two targets with the same
// simple name)
int type = gtarget->GetType();
std::string name = gtarget->GetName();
if (!name.empty() && emitted.insert(name).second &&
// Handle user targets here. Global targets are handled in
// the local generator on a per-directory basis.
((type == cmState::EXECUTABLE) ||
(type == cmState::STATIC_LIBRARY) ||
(type == cmState::SHARED_LIBRARY) ||
(type == cmState::MODULE_LIBRARY) ||
(type == cmState::OBJECT_LIBRARY) || (type == cmState::UTILITY))) {
// Add a rule to build the target by name.
lg->WriteDivider(ruleFileStream);
ruleFileStream << "# Target rules for targets named " << name
<< "\n\n";
2010-11-12 00:02:07 +03:00
// Write the rule.
commands.clear();
std::string tmp = cmake::GetCMakeFilesDirectoryPostSlash();
tmp += "Makefile2";
commands.push_back(lg->GetRecursiveMakeCall(tmp.c_str(), name));
depends.clear();
depends.push_back("cmake_check_build_system");
lg->WriteMakeRule(ruleFileStream, "Build rule for target.", name,
depends, commands, true);
2010-11-12 00:02:07 +03:00
// Add a fast rule to build the target
std::string localName = lg->GetRelativeTargetDirectory(gtarget);
std::string makefileName;
makefileName = localName;
2010-11-12 00:02:07 +03:00
makefileName += "/build.make";
depends.clear();
commands.clear();
std::string makeTargetName = localName;
makeTargetName += "/build";
localName = name;
localName += "/fast";
commands.push_back(
lg->GetRecursiveMakeCall(makefileName.c_str(), makeTargetName));
lg->WriteMakeRule(ruleFileStream, "fast build rule for target.",
localName, depends, commands, true);
// Add a local name for the rule to relink the target before
// installation.
if (gtarget->NeedRelinkBeforeInstall(lg->GetConfigName())) {
makeTargetName = lg->GetRelativeTargetDirectory(gtarget);
makeTargetName += "/preinstall";
localName = name;
localName += "/preinstall";
depends.clear();
commands.clear();
commands.push_back(
lg->GetRecursiveMakeCall(makefileName.c_str(), makeTargetName));
lg->WriteMakeRule(ruleFileStream,
"Manual pre-install relink rule for target.",
localName, depends, commands, true);
2006-05-02 17:56:42 +04:00
}
}
}
}
}
void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2(
std::ostream& ruleFileStream, cmLocalUnixMakefileGenerator3* lg)
{
2010-11-12 00:02:07 +03:00
std::vector<std::string> depends;
std::vector<std::string> commands;
std::string localName;
std::string makeTargetName;
// write the directory level rules for this local gen
this->WriteDirectoryRules2(ruleFileStream, lg);
2010-11-12 00:02:07 +03:00
depends.push_back("cmake_check_build_system");
2005-05-25 23:09:06 +04:00
2005-05-11 20:44:01 +04:00
// for each target Generate the rule files for each target.
std::vector<cmGeneratorTarget*> targets = lg->GetGeneratorTargets();
for (std::vector<cmGeneratorTarget*>::iterator t = targets.begin();
t != targets.end(); ++t) {
cmGeneratorTarget* gtarget = *t;
int type = gtarget->GetType();
std::string name = gtarget->GetName();
if (!name.empty() &&
((type == cmState::EXECUTABLE) || (type == cmState::STATIC_LIBRARY) ||
(type == cmState::SHARED_LIBRARY) ||
(type == cmState::MODULE_LIBRARY) ||
(type == cmState::OBJECT_LIBRARY) || (type == cmState::UTILITY))) {
2006-05-02 17:56:42 +04:00
std::string makefileName;
2005-05-06 22:49:38 +04:00
// Add a rule to build the target by name.
localName = lg->GetRelativeTargetDirectory(gtarget);
2006-05-02 17:56:42 +04:00
makefileName = localName;
2005-05-19 18:52:59 +04:00
makefileName += "/build.make";
2010-11-12 00:02:07 +03:00
2015-10-19 00:20:47 +03:00
bool needRequiresStep = this->NeedRequiresStep(gtarget);
2010-11-12 00:02:07 +03:00
lg->WriteDivider(ruleFileStream);
ruleFileStream << "# Target rules for target " << localName << "\n\n";
2010-11-12 00:02:07 +03:00
commands.clear();
makeTargetName = localName;
makeTargetName += "/depend";
commands.push_back(
lg->GetRecursiveMakeCall(makefileName.c_str(), makeTargetName));
// add requires if we need it for this generator
if (needRequiresStep) {
makeTargetName = localName;
makeTargetName += "/requires";
commands.push_back(
lg->GetRecursiveMakeCall(makefileName.c_str(), makeTargetName));
}
makeTargetName = localName;
makeTargetName += "/build";
commands.push_back(
lg->GetRecursiveMakeCall(makefileName.c_str(), makeTargetName));
2010-11-12 00:02:07 +03:00
// Write the rule.
localName += "/all";
depends.clear();
cmLocalUnixMakefileGenerator3::EchoProgress progress;
progress.Dir = lg->GetBinaryDirectory();
progress.Dir += cmake::GetCMakeFilesDirectory();
{
std::ostringstream progressArg;
const char* sep = "";
std::vector<unsigned long>& progFiles =
this->ProgressMap[gtarget].Marks;
for (std::vector<unsigned long>::iterator i = progFiles.begin();
i != progFiles.end(); ++i) {
progressArg << sep << *i;
sep = ",";
}
progress.Arg = progressArg.str();
}
bool targetMessages = true;
if (const char* tgtMsg =
this->GetCMakeInstance()->GetState()->GetGlobalProperty(
"TARGET_MESSAGES")) {
targetMessages = cmSystemTools::IsOn(tgtMsg);
}
if (targetMessages) {
lg->AppendEcho(commands, "Built target " + name,
cmLocalUnixMakefileGenerator3::EchoNormal, &progress);
}
this->AppendGlobalTargetDepends(depends, gtarget);
lg->WriteMakeRule(ruleFileStream, "All Build rule for target.",
localName, depends, commands, true);
2010-11-12 00:02:07 +03:00
// add the all/all dependency
if (!this->IsExcluded(this->LocalGenerators[0], gtarget)) {
depends.clear();
depends.push_back(localName);
commands.clear();
lg->WriteMakeRule(ruleFileStream, "Include target in all.", "all",
depends, commands, true);
}
// Write the rule.
commands.clear();
{
// TODO: Convert the total progress count to a make variable.
std::ostringstream progCmd;
progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start ";
// # in target
progCmd << lg->ConvertToOutputFormat(
cmSystemTools::CollapseFullPath(progress.Dir),
cmOutputConverter::SHELL);
//
std::set<cmGeneratorTarget const*> emitted;
progCmd << " " << this->CountProgressMarksInTarget(gtarget, emitted);
commands.push_back(progCmd.str());
}
std::string tmp = cmake::GetCMakeFilesDirectoryPostSlash();
tmp += "Makefile2";
commands.push_back(lg->GetRecursiveMakeCall(tmp.c_str(), localName));
{
std::ostringstream progCmd;
progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start "; // # 0
progCmd << lg->ConvertToOutputFormat(
cmSystemTools::CollapseFullPath(progress.Dir),
cmOutputConverter::SHELL);
progCmd << " 0";
commands.push_back(progCmd.str());
}
depends.clear();
depends.push_back("cmake_check_build_system");
localName = lg->GetRelativeTargetDirectory(gtarget);
localName += "/rule";
2010-11-12 00:02:07 +03:00
lg->WriteMakeRule(ruleFileStream,
"Build rule for subdir invocation for target.",
localName, depends, commands, true);
2010-11-12 00:02:07 +03:00
// Add a target with the canonical name (no prefix, suffix or path).
commands.clear();
depends.clear();
depends.push_back(localName);
lg->WriteMakeRule(ruleFileStream, "Convenience name for target.", name,
depends, commands, true);
2010-11-12 00:02:07 +03:00
// Add rules to prepare the target for installation.
if (gtarget->NeedRelinkBeforeInstall(lg->GetConfigName())) {
localName = lg->GetRelativeTargetDirectory(gtarget);
localName += "/preinstall";
2006-05-02 17:56:42 +04:00
depends.clear();
commands.clear();
commands.push_back(
lg->GetRecursiveMakeCall(makefileName.c_str(), localName));
2010-11-12 00:02:07 +03:00
lg->WriteMakeRule(ruleFileStream,
"Pre-install relink rule for target.", localName,
depends, commands, true);
if (!this->IsExcluded(this->LocalGenerators[0], gtarget)) {
depends.clear();
depends.push_back(localName);
commands.clear();
lg->WriteMakeRule(ruleFileStream, "Prepare target for install.",
"preinstall", depends, commands, true);
}
}
2010-11-12 00:02:07 +03:00
// add the clean rule
localName = lg->GetRelativeTargetDirectory(gtarget);
makeTargetName = localName;
makeTargetName += "/clean";
depends.clear();
commands.clear();
commands.push_back(
lg->GetRecursiveMakeCall(makefileName.c_str(), makeTargetName));
lg->WriteMakeRule(ruleFileStream, "clean rule for target.",
makeTargetName, depends, commands, true);
commands.clear();
depends.push_back(makeTargetName);
lg->WriteMakeRule(ruleFileStream, "clean rule for target.", "clean",
depends, commands, true);
}
}
}
// Build a map that contains a the set of targets used by each local
// generator directory level.
void cmGlobalUnixMakefileGenerator3::InitializeProgressMarks()
{
this->DirectoryTargetsMap.clear();
// Loop over all targets in all local generators.
for (std::vector<cmLocalGenerator*>::const_iterator lgi =
this->LocalGenerators.begin();
lgi != this->LocalGenerators.end(); ++lgi) {
cmLocalGenerator* lg = *lgi;
2015-10-18 18:06:14 +03:00
std::vector<cmGeneratorTarget*> targets = lg->GetGeneratorTargets();
for (std::vector<cmGeneratorTarget*>::const_iterator t = targets.begin();
t != targets.end(); ++t) {
2015-10-18 18:06:14 +03:00
cmGeneratorTarget* gt = *t;
cmLocalGenerator* tlg = gt->GetLocalGenerator();
if (gt->GetType() == cmState::INTERFACE_LIBRARY ||
gt->GetPropertyAsBool("EXCLUDE_FROM_ALL")) {
continue;
}
cmState::Snapshot csnp = lg->GetStateSnapshot();
cmState::Snapshot tsnp = tlg->GetStateSnapshot();
// Consider the directory containing the target and all its
// parents until something excludes the target.
for (; csnp.IsValid() && !this->IsExcluded(csnp, tsnp);
csnp = csnp.GetBuildsystemDirectoryParent()) {
// This local generator includes the target.
std::set<cmGeneratorTarget const*>& targetSet =
this->DirectoryTargetsMap[csnp];
targetSet.insert(gt);
// Add dependencies of the included target. An excluded
// target may still be included if it is a dependency of a
// non-excluded target.
TargetDependSet const& tgtdeps = this->GetTargetDirectDepends(gt);
for (TargetDependSet::const_iterator ti = tgtdeps.begin();
ti != tgtdeps.end(); ++ti) {
targetSet.insert(*ti);
}
}
}
}
}
size_t cmGlobalUnixMakefileGenerator3::CountProgressMarksInTarget(
cmGeneratorTarget const* target, std::set<cmGeneratorTarget const*>& emitted)
2006-05-23 17:11:46 +04:00
{
size_t count = 0;
if (emitted.insert(target).second) {
count = this->ProgressMap[target].Marks.size();
TargetDependSet const& depends = this->GetTargetDirectDepends(target);
for (TargetDependSet::const_iterator di = depends.begin();
di != depends.end(); ++di) {
if ((*di)->GetType() == cmState::INTERFACE_LIBRARY) {
continue;
}
count += this->CountProgressMarksInTarget(*di, emitted);
2006-05-23 17:11:46 +04:00
}
}
return count;
2006-05-23 17:11:46 +04:00
}
size_t cmGlobalUnixMakefileGenerator3::CountProgressMarksInAll(
cmLocalGenerator* lg)
{
size_t count = 0;
std::set<cmGeneratorTarget const*> emitted;
std::set<cmGeneratorTarget const*> const& targets =
this->DirectoryTargetsMap[lg->GetStateSnapshot()];
for (std::set<cmGeneratorTarget const*>::const_iterator t = targets.begin();
t != targets.end(); ++t) {
count += this->CountProgressMarksInTarget(*t, emitted);
}
return count;
}
void cmGlobalUnixMakefileGenerator3::RecordTargetProgress(
cmMakefileTargetGenerator* tg)
{
TargetProgress& tp = this->ProgressMap[tg->GetGeneratorTarget()];
tp.NumberOfActions = tg->GetNumberOfProgressActions();
tp.VariableFile = tg->GetProgressFileNameFull();
}
void cmGlobalUnixMakefileGenerator3::TargetProgress::WriteProgressVariables(
unsigned long total, unsigned long& current)
{
cmGeneratedFileStream fout(this->VariableFile.c_str());
for (unsigned long i = 1; i <= this->NumberOfActions; ++i) {
fout << "CMAKE_PROGRESS_" << i << " = ";
if (total <= 100) {
unsigned long num = i + current;
fout << num;
this->Marks.push_back(num);
} else if (((i + current) * 100) / total >
((i - 1 + current) * 100) / total) {
unsigned long num = ((i + current) * 100) / total;
fout << num;
this->Marks.push_back(num);
}
fout << "\n";
}
fout << "\n";
current += this->NumberOfActions;
}
2006-05-23 17:11:46 +04:00
void cmGlobalUnixMakefileGenerator3::AppendGlobalTargetDepends(
std::vector<std::string>& depends, cmGeneratorTarget* target)
{
TargetDependSet const& depends_set = this->GetTargetDirectDepends(target);
for (TargetDependSet::const_iterator i = depends_set.begin();
i != depends_set.end(); ++i) {
// Create the target-level dependency.
cmGeneratorTarget const* dep = *i;
if (dep->GetType() == cmState::INTERFACE_LIBRARY) {
continue;
}
cmLocalUnixMakefileGenerator3* lg3 =
static_cast<cmLocalUnixMakefileGenerator3*>(dep->GetLocalGenerator());
std::string tgtName =
lg3->GetRelativeTargetDirectory(const_cast<cmGeneratorTarget*>(dep));
tgtName += "/all";
depends.push_back(tgtName);
}
}
void cmGlobalUnixMakefileGenerator3::WriteHelpRule(
std::ostream& ruleFileStream, cmLocalUnixMakefileGenerator3* lg)
{
// add the help target
std::string path;
std::vector<std::string> no_depends;
std::vector<std::string> commands;
lg->AppendEcho(commands, "The following are some of the valid targets "
"for this Makefile:");
lg->AppendEcho(commands, "... all (the default if no target is provided)");
lg->AppendEcho(commands, "... clean");
lg->AppendEcho(commands, "... depend");
2010-11-12 00:02:07 +03:00
// Keep track of targets already listed.
std::set<std::string> emittedTargets;
// for each local generator
unsigned int i;
cmLocalUnixMakefileGenerator3* lg2;
for (i = 0; i < this->LocalGenerators.size(); ++i) {
2010-11-12 00:02:07 +03:00
lg2 =
static_cast<cmLocalUnixMakefileGenerator3*>(this->LocalGenerators[i]);
// for the passed in makefile or if this is the top Makefile wripte out
// the targets
if (lg2 == lg || lg->IsRootMakefile()) {
// for each target Generate the rule files for each target.
2015-10-18 18:06:14 +03:00
std::vector<cmGeneratorTarget*> targets = lg2->GetGeneratorTargets();
for (std::vector<cmGeneratorTarget*>::iterator t = targets.begin();
t != targets.end(); ++t) {
2015-10-18 18:06:14 +03:00
cmGeneratorTarget* target = *t;
cmState::TargetType type = target->GetType();
if ((type == cmState::EXECUTABLE) ||
(type == cmState::STATIC_LIBRARY) ||
(type == cmState::SHARED_LIBRARY) ||
(type == cmState::MODULE_LIBRARY) ||
(type == cmState::OBJECT_LIBRARY) ||
(type == cmState::GLOBAL_TARGET) || (type == cmState::UTILITY)) {
2015-10-18 18:06:14 +03:00
std::string name = target->GetName();
if (emittedTargets.insert(name).second) {
path = "... ";
path += name;
lg->AppendEcho(commands, path);
}
}
}
}
}
std::vector<std::string> const& localHelp = lg->GetLocalHelp();
for (std::vector<std::string>::const_iterator o = localHelp.begin();
o != localHelp.end(); ++o) {
path = "... ";
path += *o;
lg->AppendEcho(commands, path);
}
lg->WriteMakeRule(ruleFileStream, "Help Target", "help", no_depends,
commands, true);
ruleFileStream << "\n\n";
}
bool cmGlobalUnixMakefileGenerator3::NeedRequiresStep(
const cmGeneratorTarget* target)
{
std::set<std::string> languages;
target->GetLanguages(
languages,
target->Target->GetMakefile()->GetSafeDefinition("CMAKE_BUILD_TYPE"));
for (std::set<std::string>::const_iterator l = languages.begin();
l != languages.end(); ++l) {
std::string var = "CMAKE_NEEDS_REQUIRES_STEP_";
var += *l;
var += "_FLAG";
if (target->Target->GetMakefile()->GetDefinition(var)) {
return true;
}
}
return false;
}