diff options
Diffstat (limited to 'Source/cmMakefileTargetGenerator.cxx')
-rw-r--r-- | Source/cmMakefileTargetGenerator.cxx | 155 |
1 files changed, 140 insertions, 15 deletions
diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 6bc915d..155a097 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; |