summaryrefslogtreecommitdiff
path: root/Source/cmMakefileTargetGenerator.cxx
diff options
context:
space:
mode:
authorMarc Chevrier <marc.chevrier@gmail.com>2020-10-18 16:11:27 +0200
committerMarc Chevrier <marc.chevrier@gmail.com>2020-11-29 15:25:42 +0100
commit2c71d051facad13b0a42a57066be2489d5fff6ea (patch)
treed07f850f8abc74d9df34ad885681c08d36c14472 /Source/cmMakefileTargetGenerator.cxx
parentafd0f6785dc1220a07743d31699fcd9097cca46a (diff)
downloadcmake-2c71d051facad13b0a42a57066be2489d5fff6ea.tar.gz
Makefiles Generators: use compiler for dependencies generation
Each source compilation generates a dependencies file. These dependencies files are consolidated in one file per target. This consolidation is done as part of command 'cmake -E cmake_depends` launched before evaluation of makefile dependency graph. The consolidation uses the same approach as `CMake` dependencies management. Fixes: #21321
Diffstat (limited to 'Source/cmMakefileTargetGenerator.cxx')
-rw-r--r--Source/cmMakefileTargetGenerator.cxx155
1 files changed, 140 insertions, 15 deletions
diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx
index 6bc915d858..155a097eae 100644
--- a/Source/cmMakefileTargetGenerator.cxx
+++ b/Source/cmMakefileTargetGenerator.cxx
@@ -12,7 +12,9 @@
#include <utility>
#include <cm/memory>
+#include <cm/string_view>
#include <cmext/algorithm>
+#include <cmext/string_view>
#include "cmComputeLinkInformation.h"
#include "cmCustomCommand.h"
@@ -326,7 +328,45 @@ void cmMakefileTargetGenerator::WriteCommonCodeRules()
<< cmSystemTools::ConvertToOutputPath(
this->LocalGenerator->MaybeConvertToRelativePath(
this->LocalGenerator->GetBinaryDirectory(), dependFileNameFull))
- << "\n\n";
+ << "\n";
+
+ std::string depsUseCompiler = "CMAKE_DEPENDS_USE_COMPILER";
+ if (!this->Makefile->IsDefinitionSet(depsUseCompiler) ||
+ this->Makefile->IsOn(depsUseCompiler)) {
+ std::string compilerDependFile =
+ cmStrCat(this->TargetBuildDirectoryFull, "/compiler_depend.make");
+ *this->BuildFileStream
+ << "# Include any dependencies generated by the "
+ "compiler for this target.\n"
+ << this->GlobalGenerator->IncludeDirective << " " << root
+ << cmSystemTools::ConvertToOutputPath(
+ this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetBinaryDirectory(), compilerDependFile))
+ << "\n\n";
+
+ if (!cmSystemTools::FileExists(compilerDependFile)) {
+ // Write an empty dependency file.
+ cmGeneratedFileStream depFileStream(
+ compilerDependFile, false,
+ this->GlobalGenerator->GetMakefileEncoding());
+ depFileStream << "# Empty compiler generated dependencies file for "
+ << this->GeneratorTarget->GetName() << ".\n"
+ << "# This may be replaced when dependencies are built.\n";
+ }
+
+ std::string compilerDependTimestamp =
+ cmStrCat(this->TargetBuildDirectoryFull, "/compiler_depend.ts");
+ if (!cmSystemTools::FileExists(compilerDependTimestamp)) {
+ // Write a dependency timestamp file.
+ cmGeneratedFileStream depFileStream(
+ compilerDependTimestamp, false,
+ this->GlobalGenerator->GetMakefileEncoding());
+ depFileStream << "# CMAKE generated file: DO NOT EDIT!\n"
+ << "# Timestamp file for compiler generated dependencies "
+ "management for "
+ << this->GeneratorTarget->GetName() << ".\n";
+ }
+ }
if (!this->NoRuleMessages) {
// Include the progress variables for the target.
@@ -473,6 +513,14 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
return;
}
+ // Use compiler to generate dependencies, if supported.
+ bool compilerGenerateDeps =
+ this->GlobalGenerator->SupportsCompilerDependencies() &&
+ cmIsOn(this->Makefile->GetDefinition(
+ cmStrCat("CMAKE_", lang, "_DEPENDS_USE_COMPILER")));
+ auto scanner = compilerGenerateDeps ? cmDependencyScannerKind::Compiler
+ : cmDependencyScannerKind::CMake;
+
// Get the full path name of the object file.
std::string const& objectName =
this->GeneratorTarget->GetObjectName(&source);
@@ -512,7 +560,7 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
std::string srcFullPath =
cmSystemTools::CollapseFullPath(source.GetFullPath());
this->LocalGenerator->AddImplicitDepends(this->GeneratorTarget, lang,
- objFullPath, srcFullPath);
+ objFullPath, srcFullPath, scanner);
this->LocalGenerator->AppendRuleDepend(depends,
this->FlagFileNameFull.c_str());
@@ -554,8 +602,8 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
depends.push_back(
this->GeneratorTarget->GetPchFile(config, lang, arch));
}
- this->LocalGenerator->AddImplicitDepends(this->GeneratorTarget, lang,
- objFullPath, pchHeader);
+ this->LocalGenerator->AddImplicitDepends(
+ this->GeneratorTarget, lang, objFullPath, pchHeader, scanner);
}
}
@@ -689,7 +737,7 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
source.GetFullPath(), cmOutputConverter::SHELL);
// Construct the build message.
- std::vector<std::string> no_commands;
+ std::vector<std::string> no_depends;
std::vector<std::string> commands;
// add in a progress call if needed
@@ -783,6 +831,26 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
"$(" + lang + "_INCLUDES)");
vars.Includes = includesString.c_str();
+ std::string dependencyTarget;
+ std::string shellDependencyFile;
+ std::string dependencyTimestamp;
+ if (compilerGenerateDeps) {
+ dependencyTarget = this->LocalGenerator->EscapeForShell(
+ this->LocalGenerator->ConvertToMakefilePath(
+ this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetBinaryDirectory(), relativeObj)));
+ vars.DependencyTarget = dependencyTarget.c_str();
+
+ auto depFile = cmStrCat(obj, ".d");
+ shellDependencyFile = this->LocalGenerator->ConvertToOutputFormat(
+ depFile, cmOutputConverter::SHELL);
+ vars.DependencyFile = shellDependencyFile.c_str();
+
+ dependencyTimestamp = this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetBinaryDirectory(),
+ cmStrCat(this->TargetBuildDirectoryFull, "/compiler_depend.ts"));
+ }
+
// At the moment, it is assumed that C, C++, Fortran, and CUDA have both
// assembly and preprocessor capabilities. The same is true for the
// ability to export compile commands
@@ -954,6 +1022,53 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
}
}
+ std::string flagsWithDeps(flags);
+
+ if (compilerGenerateDeps) {
+ // Injects dependency computation
+ auto depFlags = this->Makefile->GetSafeDefinition(
+ cmStrCat("CMAKE_DEPFILE_FLAGS_", lang));
+
+ if (!depFlags.empty()) {
+ // Add dependency flags
+ rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator,
+ depFlags, vars);
+ flagsWithDeps.append(1, ' ');
+ flagsWithDeps.append(depFlags);
+ }
+ vars.Flags = flagsWithDeps.c_str();
+
+ const auto& extraCommands = this->Makefile->GetSafeDefinition(
+ cmStrCat("CMAKE_", lang, "_DEPENDS_EXTRA_COMMANDS"));
+ if (!extraCommands.empty()) {
+ auto commandList = cmExpandedList(extraCommands);
+ compileCommands.insert(compileCommands.end(), commandList.cbegin(),
+ commandList.cend());
+ }
+
+ const auto& depFormat = this->Makefile->GetRequiredDefinition(
+ cmStrCat("CMAKE_", lang, "_DEPFILE_FORMAT"));
+
+ if (depFormat == "msvc"_s) {
+ // compiler must be launched through a wrapper to pick-up dependencies
+ std::string depFilter =
+ "$(CMAKE_COMMAND) -E cmake_cl_compile_depends ";
+ depFilter += cmStrCat("--dep-file=", shellDependencyFile);
+ depFilter +=
+ cmStrCat(" --working-dir=",
+ this->LocalGenerator->ConvertToOutputFormat(
+ this->LocalGenerator->GetCurrentBinaryDirectory(),
+ cmOutputConverter::SHELL));
+ const auto& prefix = this->Makefile->GetSafeDefinition(
+ cmStrCat("CMAKE_", lang, "_CL_SHOWINCLUDES_PREFIX"));
+ depFilter += cmStrCat(" --filter-prefix=",
+ this->LocalGenerator->ConvertToOutputFormat(
+ prefix, cmOutputConverter::SHELL));
+ depFilter += " -- ";
+ compileCommands.front().insert(0, depFilter);
+ }
+ }
+
// Expand placeholders in the commands.
for (std::string& compileCommand : compileCommands) {
compileCommand = cmStrCat(launcher, compileCommand);
@@ -979,8 +1094,8 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
cmExpandList(evaluated_outputs, outputs);
}
}
- if (!ispcHeaderRelative
- .empty()) { // can't move ispcHeader as vars is using it
+ if (!ispcHeaderRelative.empty()) {
+ // can't move ispcHeader as vars is using it
outputs.emplace_back(ispcHeaderRelative);
}
@@ -988,10 +1103,19 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
this->CleanFiles.insert(outputs.begin() + 1, outputs.end());
}
+ if (compilerGenerateDeps) {
+ depends.push_back(dependencyTimestamp);
+ }
+
// Write the rule.
this->WriteMakeRule(*this->BuildFileStream, nullptr, outputs, depends,
commands);
+ if (compilerGenerateDeps) {
+ // set back flags without dependency generation
+ vars.Flags = flags.c_str();
+ }
+
bool do_preprocess_rules = lang_has_preprocessor &&
this->LocalGenerator->GetCreatePreprocessedSourceRules();
bool do_assembly_rules =
@@ -1388,10 +1512,10 @@ void cmMakefileTargetGenerator::WriteDeviceLinkRule(
std::string registerFileCmd;
- // The generated register file contains macros that when expanded register
- // the device routines. Because the routines are the same for all
- // architectures the register file will be the same too. Thus generate it
- // only on the first invocation to reduce overhead.
+ // The generated register file contains macros that when expanded
+ // register the device routines. Because the routines are the same for
+ // all architectures the register file will be the same too. Thus
+ // generate it only on the first invocation to reduce overhead.
if (fatbinaryDepends.size() == 1) {
std::string registerFileRel =
this->LocalGenerator->MaybeConvertToRelativePath(
@@ -1426,7 +1550,8 @@ void cmMakefileTargetGenerator::WriteDeviceLinkRule(
fatbinaryOutputRel, fatbinaryDepends,
{ fatbinaryCommand }, false);
- // Compile the stub that registers the kernels and contains the fatbinaries.
+ // Compile the stub that registers the kernels and contains the
+ // fatbinaries.
cmRulePlaceholderExpander::RuleVariables vars;
vars.CMTargetName = this->GetGeneratorTarget()->GetName().c_str();
vars.CMTargetType =
@@ -1839,9 +1964,9 @@ bool cmMakefileTargetGenerator::CheckUseResponseFileForObjects(
if (size_t const limit = cmSystemTools::CalculateCommandLineLengthLimit()) {
// Compute the total length of our list of object files with room
// for argument separation and quoting. This does not convert paths
- // relative to CMAKE_CURRENT_BINARY_DIR like the final list will be, so the
- // actual list will likely be much shorter than this. However, in the
- // worst case all objects will remain as absolute paths.
+ // relative to CMAKE_CURRENT_BINARY_DIR like the final list will be, so
+ // the actual list will likely be much shorter than this. However, in
+ // the worst case all objects will remain as absolute paths.
size_t length = 0;
for (std::string const& obj : this->Objects) {
length += obj.size() + 3;