mirror of
https://github.com/Kitware/CMake.git
synced 2026-04-23 06:47:08 -05:00
Merge topic 'cpp-modules'
39cbbb59a5ninja: add experimental infrastructure to generate gcc-format modmap files791b4d26d6ninja: add experimental infrastructure to generate modmap files with dyndep4b23359117ninja: Add experimental infrastructure for C++20 module dependency scanningf814d3b3c6cmNinjaTargetGenerator: use $OBJ_FILE for the objectb0fc2993e1Treat the '.mpp' file extension as C++ code988f997100cmScanDepFormat: Fix name of our internal tool in parse errorsdacd93a2dbninja: De-duplicate version numbers required for ninja features533386ca29cmStandardLevelResolver: Factor out helper to capture stoi exceptions Acked-by: Kitware Robot <kwrobot@kitware.com> Acked-by: Ben Boeckel <ben.boeckel@kitware.com> Acked-by: Robert Maynard <robert.maynard@kitware.com> Acked-by: Shannon Booth <shannon.ml.booth@gmail.com> Merge-request: !5562
This commit is contained in:
@@ -555,6 +555,7 @@ void cmGlobalNinjaGenerator::Generate()
|
||||
this->TargetAll = this->NinjaOutputPath("all");
|
||||
this->CMakeCacheFile = this->NinjaOutputPath("CMakeCache.txt");
|
||||
this->DisableCleandead = false;
|
||||
this->DiagnosedCxxModuleSupport = false;
|
||||
|
||||
this->PolicyCMP0058 =
|
||||
this->LocalGenerators[0]->GetMakefile()->GetPolicyStatus(
|
||||
@@ -755,6 +756,37 @@ bool cmGlobalNinjaGenerator::CheckLanguages(
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cmGlobalNinjaGenerator::CheckCxxModuleSupport()
|
||||
{
|
||||
bool const diagnose = !this->DiagnosedCxxModuleSupport &&
|
||||
!this->CMakeInstance->GetIsInTryCompile();
|
||||
if (diagnose) {
|
||||
this->DiagnosedCxxModuleSupport = true;
|
||||
this->GetCMakeInstance()->IssueMessage(
|
||||
MessageType::AUTHOR_WARNING,
|
||||
"C++20 modules support via CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP "
|
||||
"is experimental. It is meant only for compiler developers to try.");
|
||||
}
|
||||
if (this->NinjaSupportsDyndeps) {
|
||||
return true;
|
||||
}
|
||||
if (diagnose) {
|
||||
std::ostringstream e;
|
||||
/* clang-format off */
|
||||
e <<
|
||||
"The Ninja generator does not support C++20 modules "
|
||||
"using Ninja version \n"
|
||||
" " << this->NinjaVersion << "\n"
|
||||
"due to lack of required features. "
|
||||
"Ninja " << RequiredNinjaVersionForDyndeps() << " or higher is required."
|
||||
;
|
||||
/* clang-format on */
|
||||
this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e.str());
|
||||
cmSystemTools::SetFatalErrorOccured();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cmGlobalNinjaGenerator::CheckFortran(cmMakefile* mf) const
|
||||
{
|
||||
if (this->NinjaSupportsDyndeps) {
|
||||
@@ -766,7 +798,8 @@ bool cmGlobalNinjaGenerator::CheckFortran(cmMakefile* mf) const
|
||||
e <<
|
||||
"The Ninja generator does not support Fortran using Ninja version\n"
|
||||
" " << this->NinjaVersion << "\n"
|
||||
"due to lack of required features. Ninja 1.10 or higher is required."
|
||||
"due to lack of required features. "
|
||||
"Ninja " << RequiredNinjaVersionForDyndeps() << " or higher is required."
|
||||
;
|
||||
/* clang-format on */
|
||||
mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
|
||||
@@ -785,7 +818,9 @@ bool cmGlobalNinjaGenerator::CheckISPC(cmMakefile* mf) const
|
||||
e <<
|
||||
"The Ninja generator does not support ISPC using Ninja version\n"
|
||||
" " << this->NinjaVersion << "\n"
|
||||
"due to lack of required features. Ninja 1.10 or higher is required."
|
||||
"due to lack of required features. "
|
||||
"Ninja " << RequiredNinjaVersionForMultipleOutputs() <<
|
||||
" or higher is required."
|
||||
;
|
||||
/* clang-format on */
|
||||
mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
|
||||
@@ -2336,7 +2371,7 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile(
|
||||
std::string const& arg_dd, std::vector<std::string> const& arg_ddis,
|
||||
std::string const& module_dir,
|
||||
std::vector<std::string> const& linked_target_dirs,
|
||||
std::string const& arg_lang)
|
||||
std::string const& arg_lang, std::string const& arg_modmapfmt)
|
||||
{
|
||||
// Setup path conversions.
|
||||
{
|
||||
@@ -2423,6 +2458,48 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile(
|
||||
build.Variables.emplace("restat", "1");
|
||||
}
|
||||
|
||||
if (arg_modmapfmt.empty()) {
|
||||
// nothing to do.
|
||||
} else {
|
||||
std::stringstream mm;
|
||||
if (arg_modmapfmt == "gcc") {
|
||||
// Documented in GCC's documentation. The format is a series of lines
|
||||
// with a module name and the associated filename separated by
|
||||
// spaces. The first line may use `$root` as the module name to
|
||||
// specify a "repository root". That is used to anchor any relative
|
||||
// paths present in the file (CMake should never generate any).
|
||||
|
||||
// Write the root directory to use for module paths.
|
||||
mm << "$root .\n";
|
||||
|
||||
for (auto const& l : object.Provides) {
|
||||
auto m = mod_files.find(l.LogicalName);
|
||||
if (m != mod_files.end()) {
|
||||
mm << l.LogicalName << " " << this->ConvertToNinjaPath(m->second)
|
||||
<< "\n";
|
||||
}
|
||||
}
|
||||
for (auto const& r : object.Requires) {
|
||||
auto m = mod_files.find(r.LogicalName);
|
||||
if (m != mod_files.end()) {
|
||||
mm << r.LogicalName << " " << this->ConvertToNinjaPath(m->second)
|
||||
<< "\n";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cmSystemTools::Error(
|
||||
cmStrCat("-E cmake_ninja_dyndep does not understand the ",
|
||||
arg_modmapfmt, " module map format"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// XXX(modmap): If changing this path construction, change
|
||||
// `cmNinjaTargetGenerator::WriteObjectBuildStatements` to generate the
|
||||
// corresponding file path.
|
||||
cmGeneratedFileStream mmf(cmStrCat(object.PrimaryOutput, ".modmap"));
|
||||
mmf << mm.str();
|
||||
}
|
||||
|
||||
this->WriteBuild(ddf, build);
|
||||
}
|
||||
}
|
||||
@@ -2446,6 +2523,7 @@ int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg,
|
||||
std::string arg_dd;
|
||||
std::string arg_lang;
|
||||
std::string arg_tdi;
|
||||
std::string arg_modmapfmt;
|
||||
std::vector<std::string> arg_ddis;
|
||||
for (std::string const& arg : arg_full) {
|
||||
if (cmHasLiteralPrefix(arg, "--tdi=")) {
|
||||
@@ -2454,6 +2532,8 @@ int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg,
|
||||
arg_lang = arg.substr(7);
|
||||
} else if (cmHasLiteralPrefix(arg, "--dd=")) {
|
||||
arg_dd = arg.substr(5);
|
||||
} else if (cmHasLiteralPrefix(arg, "--modmapfmt=")) {
|
||||
arg_modmapfmt = arg.substr(12);
|
||||
} else if (!cmHasLiteralPrefix(arg, "--") &&
|
||||
cmHasLiteralSuffix(arg, ".ddi")) {
|
||||
arg_ddis.push_back(arg);
|
||||
@@ -2512,7 +2592,7 @@ int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg,
|
||||
if (!ggd ||
|
||||
!cm::static_reference_cast<cmGlobalNinjaGenerator>(ggd).WriteDyndepFile(
|
||||
dir_top_src, dir_top_bld, dir_cur_src, dir_cur_bld, arg_dd, arg_ddis,
|
||||
module_dir, linked_target_dirs, arg_lang)) {
|
||||
module_dir, linked_target_dirs, arg_lang, arg_modmapfmt)) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
@@ -396,15 +396,13 @@ public:
|
||||
bool HasOutputPathPrefix() const { return !this->OutputPathPrefix.empty(); }
|
||||
void StripNinjaOutputPathPrefixAsSuffix(std::string& path);
|
||||
|
||||
bool WriteDyndepFile(std::string const& dir_top_src,
|
||||
std::string const& dir_top_bld,
|
||||
std::string const& dir_cur_src,
|
||||
std::string const& dir_cur_bld,
|
||||
std::string const& arg_dd,
|
||||
std::vector<std::string> const& arg_ddis,
|
||||
std::string const& module_dir,
|
||||
std::vector<std::string> const& linked_target_dirs,
|
||||
std::string const& arg_lang);
|
||||
bool WriteDyndepFile(
|
||||
std::string const& dir_top_src, std::string const& dir_top_bld,
|
||||
std::string const& dir_cur_src, std::string const& dir_cur_bld,
|
||||
std::string const& arg_dd, std::vector<std::string> const& arg_ddis,
|
||||
std::string const& module_dir,
|
||||
std::vector<std::string> const& linked_target_dirs,
|
||||
std::string const& arg_lang, std::string const& arg_modmapfmt);
|
||||
|
||||
virtual std::string BuildAlias(const std::string& alias,
|
||||
const std::string& /*config*/) const
|
||||
@@ -448,6 +446,8 @@ public:
|
||||
|
||||
bool IsSingleConfigUtility(cmGeneratorTarget const* target) const;
|
||||
|
||||
bool CheckCxxModuleSupport();
|
||||
|
||||
protected:
|
||||
void Generate() override;
|
||||
|
||||
@@ -568,6 +568,8 @@ private:
|
||||
bool NinjaSupportsMultipleOutputs = false;
|
||||
bool NinjaSupportsMetadataOnRegeneration = false;
|
||||
|
||||
bool DiagnosedCxxModuleSupport = false;
|
||||
|
||||
private:
|
||||
void InitOutputPathPrefix();
|
||||
|
||||
|
||||
@@ -1216,9 +1216,10 @@ void cmMakefile::AddCustomCommandOldStyle(
|
||||
};
|
||||
|
||||
// Each output must get its own copy of this rule.
|
||||
cmsys::RegularExpression sourceFiles("\\.(C|M|c|c\\+\\+|cc|cpp|cxx|cu|m|mm|"
|
||||
"rc|def|r|odl|idl|hpj|bat|h|h\\+\\+|"
|
||||
"hm|hpp|hxx|in|txx|inl)$");
|
||||
cmsys::RegularExpression sourceFiles(
|
||||
"\\.(C|M|c|c\\+\\+|cc|cpp|cxx|mpp|cu|m|mm|"
|
||||
"rc|def|r|odl|idl|hpj|bat|h|h\\+\\+|"
|
||||
"hm|hpp|hxx|in|txx|inl)$");
|
||||
|
||||
// Choose whether to use a main dependency.
|
||||
if (sourceFiles.find(source)) {
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "cmRange.h"
|
||||
#include "cmRulePlaceholderExpander.h"
|
||||
#include "cmSourceFile.h"
|
||||
#include "cmStandardLevelResolver.h"
|
||||
#include "cmState.h"
|
||||
#include "cmStateTypes.h"
|
||||
#include "cmStringAlgorithms.h"
|
||||
@@ -146,9 +147,26 @@ std::string cmNinjaTargetGenerator::LanguageDyndepRule(
|
||||
'_', config);
|
||||
}
|
||||
|
||||
bool cmNinjaTargetGenerator::NeedDyndep(std::string const& lang) const
|
||||
bool cmNinjaTargetGenerator::NeedCxxModuleSupport(
|
||||
std::string const& lang, std::string const& config) const
|
||||
{
|
||||
return lang == "Fortran";
|
||||
if (lang != "CXX") {
|
||||
return false;
|
||||
}
|
||||
if (!this->Makefile->IsOn("CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP")) {
|
||||
return false;
|
||||
}
|
||||
cmGeneratorTarget const* tgt = this->GetGeneratorTarget();
|
||||
cmStandardLevelResolver standardResolver(this->Makefile);
|
||||
bool const uses_cxx20 =
|
||||
standardResolver.HaveStandardAvailable(tgt, "CXX", config, "cxx_std_20");
|
||||
return uses_cxx20 && this->GetGlobalGenerator()->CheckCxxModuleSupport();
|
||||
}
|
||||
|
||||
bool cmNinjaTargetGenerator::NeedDyndep(std::string const& lang,
|
||||
std::string const& config) const
|
||||
{
|
||||
return lang == "Fortran" || this->NeedCxxModuleSupport(lang, config);
|
||||
}
|
||||
|
||||
std::string cmNinjaTargetGenerator::OrderDependsTargetForTarget(
|
||||
@@ -530,8 +548,9 @@ cmNinjaRule GetScanRule(
|
||||
scanVars.CMTargetName = vars.CMTargetName;
|
||||
scanVars.CMTargetType = vars.CMTargetType;
|
||||
scanVars.Language = vars.Language;
|
||||
scanVars.Object = "$out"; // for RULE_LAUNCH_COMPILE
|
||||
scanVars.Object = "$OBJ_FILE";
|
||||
scanVars.PreprocessedSource = "$out";
|
||||
scanVars.DynDepFile = "$DYNDEP_INTERMEDIATE_FILE";
|
||||
scanVars.DependencyFile = rule.DepFile.c_str();
|
||||
scanVars.DependencyTarget = "$out";
|
||||
|
||||
@@ -586,7 +605,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
|
||||
cmMakefile* mf = this->GetMakefile();
|
||||
|
||||
// For some cases we scan to dynamically discover dependencies.
|
||||
bool const needDyndep = this->NeedDyndep(lang);
|
||||
bool const needDyndep = this->NeedDyndep(lang, config);
|
||||
bool const compilationPreprocesses = !this->NeedExplicitPreprocessing(lang);
|
||||
|
||||
std::string flags = "$FLAGS";
|
||||
@@ -601,6 +620,10 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
|
||||
responseFlag = "@";
|
||||
}
|
||||
}
|
||||
std::string const modmapFormatVar =
|
||||
cmStrCat("CMAKE_EXPERIMENTAL_", lang, "_MODULE_MAP_FORMAT");
|
||||
std::string const modmapFormat =
|
||||
this->Makefile->GetSafeDefinition(modmapFormatVar);
|
||||
|
||||
std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander(
|
||||
this->GetLocalGenerator()->CreateRulePlaceholderExpander());
|
||||
@@ -624,16 +647,26 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
|
||||
// Rule to scan dependencies of sources that need preprocessing.
|
||||
{
|
||||
std::vector<std::string> scanCommands;
|
||||
std::string const& scanRuleName =
|
||||
this->LanguagePreprocessAndScanRule(lang, config);
|
||||
std::string const& ppCommmand = mf->GetRequiredDefinition(
|
||||
cmStrCat("CMAKE_", lang, "_PREPROCESS_SOURCE"));
|
||||
cmExpandList(ppCommmand, scanCommands);
|
||||
for (std::string& i : scanCommands) {
|
||||
i = cmStrCat(launcher, i);
|
||||
std::string scanRuleName;
|
||||
if (compilationPreprocesses) {
|
||||
scanRuleName = this->LanguageScanRule(lang, config);
|
||||
std::string const& scanCommand = mf->GetRequiredDefinition(
|
||||
cmStrCat("CMAKE_EXPERIMENTAL_", lang, "_SCANDEP_SOURCE"));
|
||||
cmExpandList(scanCommand, scanCommands);
|
||||
for (std::string& i : scanCommands) {
|
||||
i = cmStrCat(launcher, i);
|
||||
}
|
||||
} else {
|
||||
scanRuleName = this->LanguagePreprocessAndScanRule(lang, config);
|
||||
std::string const& ppCommmand = mf->GetRequiredDefinition(
|
||||
cmStrCat("CMAKE_", lang, "_PREPROCESS_SOURCE"));
|
||||
cmExpandList(ppCommmand, scanCommands);
|
||||
for (std::string& i : scanCommands) {
|
||||
i = cmStrCat(launcher, i);
|
||||
}
|
||||
scanCommands.emplace_back(GetScanCommand(cmakeCmd, tdi, lang, "$out",
|
||||
"$DYNDEP_INTERMEDIATE_FILE"));
|
||||
}
|
||||
scanCommands.emplace_back(GetScanCommand(cmakeCmd, tdi, lang, "$out",
|
||||
"$DYNDEP_INTERMEDIATE_FILE"));
|
||||
|
||||
auto scanRule = GetScanRule(
|
||||
scanRuleName, vars, responseFlag, flags, rulePlaceholderExpander.get(),
|
||||
@@ -641,12 +674,18 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
|
||||
|
||||
scanRule.Comment =
|
||||
cmStrCat("Rule for generating ", lang, " dependencies.");
|
||||
scanRule.Description = cmStrCat("Building ", lang, " preprocessed $out");
|
||||
if (compilationPreprocesses) {
|
||||
scanRule.Description =
|
||||
cmStrCat("Scanning $in for ", lang, " dependencies");
|
||||
} else {
|
||||
scanRule.Description =
|
||||
cmStrCat("Building ", lang, " preprocessed $out");
|
||||
}
|
||||
|
||||
this->GetGlobalGenerator()->AddRule(scanRule);
|
||||
}
|
||||
|
||||
{
|
||||
if (!compilationPreprocesses) {
|
||||
// Compilation will not preprocess, so it does not need the defines
|
||||
// unless the compiler wants them for some other purpose.
|
||||
if (!this->CompileWithDefines(lang)) {
|
||||
@@ -681,12 +720,16 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
|
||||
|
||||
// Run CMake dependency scanner on the source file (using the preprocessed
|
||||
// source if that was performed).
|
||||
std::string ddModmapArg;
|
||||
if (!modmapFormat.empty()) {
|
||||
ddModmapArg += cmStrCat(" --modmapfmt=", modmapFormat);
|
||||
}
|
||||
{
|
||||
std::vector<std::string> ddCmds;
|
||||
{
|
||||
std::string ccmd =
|
||||
cmStrCat(cmakeCmd, " -E cmake_ninja_dyndep --tdi=", tdi,
|
||||
" --lang=", lang, " --dd=$out @", rule.RspFile);
|
||||
std::string ccmd = cmStrCat(
|
||||
cmakeCmd, " -E cmake_ninja_dyndep --tdi=", tdi, " --lang=", lang,
|
||||
ddModmapArg, " --dd=$out @", rule.RspFile);
|
||||
ddCmds.emplace_back(std::move(ccmd));
|
||||
}
|
||||
rule.Command = this->GetLocalGenerator()->BuildCommandLine(ddCmds);
|
||||
@@ -748,6 +791,14 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
|
||||
}
|
||||
}
|
||||
|
||||
if (needDyndep && !modmapFormat.empty()) {
|
||||
std::string modmapFlags = mf->GetRequiredDefinition(
|
||||
cmStrCat("CMAKE_EXPERIMENTAL_", lang, "_MODULE_MAP_FLAG"));
|
||||
cmSystemTools::ReplaceString(modmapFlags, "<MODULE_MAP_FILE>",
|
||||
"$DYNDEP_MODULE_MAP_FILE");
|
||||
flags += cmStrCat(' ', modmapFlags);
|
||||
}
|
||||
|
||||
vars.Flags = flags.c_str();
|
||||
vars.DependencyFile = rule.DepFile.c_str();
|
||||
|
||||
@@ -1053,6 +1104,7 @@ cmNinjaBuild GetScanBuildStatement(const std::string& ruleName,
|
||||
const std::string& ppFileName,
|
||||
bool compilePP, bool compilePPWithDefines,
|
||||
cmNinjaBuild& objBuild, cmNinjaVars& vars,
|
||||
std::string const& modmapFormat,
|
||||
const std::string& objectFileName,
|
||||
cmLocalGenerator* lg)
|
||||
{
|
||||
@@ -1123,6 +1175,15 @@ cmNinjaBuild GetScanBuildStatement(const std::string& ruleName,
|
||||
vars.erase("DEP_FILE");
|
||||
}
|
||||
|
||||
if (!modmapFormat.empty()) {
|
||||
// XXX(modmap): If changing this path construction, change
|
||||
// `cmGlobalNinjaGenerator::WriteDyndep` to expect the corresponding
|
||||
// file path.
|
||||
std::string const ddModmapFile = cmStrCat(objectFileName, ".modmap");
|
||||
scanBuild.Variables["DYNDEP_MODULE_MAP_FILE"] = ddModmapFile;
|
||||
scanBuild.ImplicitOuts.push_back(ddModmapFile);
|
||||
}
|
||||
|
||||
return scanBuild;
|
||||
}
|
||||
}
|
||||
@@ -1262,10 +1323,17 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
|
||||
}
|
||||
|
||||
// For some cases we scan to dynamically discover dependencies.
|
||||
bool const needDyndep = this->NeedDyndep(language);
|
||||
bool const needDyndep = this->NeedDyndep(language, config);
|
||||
bool const compilationPreprocesses =
|
||||
!this->NeedExplicitPreprocessing(language);
|
||||
|
||||
std::string modmapFormat;
|
||||
if (needDyndep) {
|
||||
std::string const modmapFormatVar =
|
||||
cmStrCat("CMAKE_EXPERIMENTAL_", language, "_MODULE_MAP_FORMAT");
|
||||
modmapFormat = this->Makefile->GetSafeDefinition(modmapFormatVar);
|
||||
}
|
||||
|
||||
if (needDyndep) {
|
||||
// If source/target has preprocessing turned off, we still need to
|
||||
// generate an explicit dependency step
|
||||
@@ -1295,7 +1363,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
|
||||
|
||||
cmNinjaBuild ppBuild = GetScanBuildStatement(
|
||||
scanRuleName, ppFileName, compilePP, compilePPWithDefines, objBuild,
|
||||
vars, objectFileName, this->LocalGenerator);
|
||||
vars, modmapFormat, objectFileName, this->LocalGenerator);
|
||||
|
||||
if (compilePP) {
|
||||
// In case compilation requires flags that are incompatible with
|
||||
@@ -1331,6 +1399,12 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
|
||||
std::string const dyndep = this->GetDyndepFilePath(language, config);
|
||||
objBuild.OrderOnlyDeps.push_back(dyndep);
|
||||
vars["dyndep"] = dyndep;
|
||||
|
||||
if (!modmapFormat.empty()) {
|
||||
std::string const ddModmapFile = cmStrCat(objectFileName, ".modmap");
|
||||
vars["DYNDEP_MODULE_MAP_FILE"] = ddModmapFile;
|
||||
objBuild.OrderOnlyDeps.push_back(ddModmapFile);
|
||||
}
|
||||
}
|
||||
|
||||
this->EnsureParentDirectoryExists(objectFileName);
|
||||
@@ -1444,17 +1518,26 @@ void cmNinjaTargetGenerator::WriteTargetDependInfo(std::string const& lang,
|
||||
tdi["compiler-id"] = this->Makefile->GetSafeDefinition(
|
||||
cmStrCat("CMAKE_", lang, "_COMPILER_ID"));
|
||||
|
||||
std::string mod_dir;
|
||||
if (lang == "Fortran") {
|
||||
std::string mod_dir = this->GeneratorTarget->GetFortranModuleDirectory(
|
||||
mod_dir = this->GeneratorTarget->GetFortranModuleDirectory(
|
||||
this->Makefile->GetHomeOutputDirectory());
|
||||
if (mod_dir.empty()) {
|
||||
mod_dir = this->Makefile->GetCurrentBinaryDirectory();
|
||||
}
|
||||
tdi["module-dir"] = mod_dir;
|
||||
} else if (lang == "CXX") {
|
||||
mod_dir =
|
||||
cmSystemTools::CollapseFullPath(this->GeneratorTarget->ObjectDirectory);
|
||||
}
|
||||
if (mod_dir.empty()) {
|
||||
mod_dir = this->Makefile->GetCurrentBinaryDirectory();
|
||||
}
|
||||
tdi["module-dir"] = mod_dir;
|
||||
|
||||
if (lang == "Fortran") {
|
||||
tdi["submodule-sep"] =
|
||||
this->Makefile->GetSafeDefinition("CMAKE_Fortran_SUBMODULE_SEP");
|
||||
tdi["submodule-ext"] =
|
||||
this->Makefile->GetSafeDefinition("CMAKE_Fortran_SUBMODULE_EXT");
|
||||
} else if (lang == "CXX") {
|
||||
// No extra information necessary.
|
||||
}
|
||||
|
||||
tdi["dir-cur-bld"] = this->Makefile->GetCurrentBinaryDirectory();
|
||||
|
||||
@@ -71,9 +71,11 @@ protected:
|
||||
const std::string& config) const;
|
||||
std::string LanguageDyndepRule(std::string const& lang,
|
||||
const std::string& config) const;
|
||||
bool NeedDyndep(std::string const& lang) const;
|
||||
bool NeedDyndep(std::string const& lang, std::string const& config) const;
|
||||
bool NeedExplicitPreprocessing(std::string const& lang) const;
|
||||
bool CompileWithDefines(std::string const& lang) const;
|
||||
bool NeedCxxModuleSupport(std::string const& lang,
|
||||
std::string const& config) const;
|
||||
|
||||
std::string OrderDependsTargetForTarget(const std::string& config);
|
||||
|
||||
|
||||
@@ -44,6 +44,11 @@ std::string cmRulePlaceholderExpander::ExpandRuleVariable(
|
||||
return replaceValues.Source;
|
||||
}
|
||||
}
|
||||
if (replaceValues.DynDepFile) {
|
||||
if (variable == "DYNDEP_FILE") {
|
||||
return replaceValues.DynDepFile;
|
||||
}
|
||||
}
|
||||
if (replaceValues.PreprocessedSource) {
|
||||
if (variable == "PREPROCESSED_SOURCE") {
|
||||
return replaceValues.PreprocessedSource;
|
||||
|
||||
@@ -41,6 +41,7 @@ public:
|
||||
const char* Source = nullptr;
|
||||
const char* AssemblySource = nullptr;
|
||||
const char* PreprocessedSource = nullptr;
|
||||
const char* DynDepFile = nullptr;
|
||||
const char* Output = nullptr;
|
||||
const char* Object = nullptr;
|
||||
const char* ObjectDir = nullptr;
|
||||
|
||||
+11
-13
@@ -55,9 +55,8 @@ static Json::Value EncodeFilename(std::string const& path)
|
||||
#define PARSE_BLOB(val, res) \
|
||||
do { \
|
||||
if (!ParseFilename(val, res)) { \
|
||||
cmSystemTools::Error( \
|
||||
cmStrCat("-E cmake_ninja_depends failed to parse ", arg_pp, \
|
||||
": invalid blob")); \
|
||||
cmSystemTools::Error(cmStrCat("-E cmake_ninja_dyndep failed to parse ", \
|
||||
arg_pp, ": invalid blob")); \
|
||||
return false; \
|
||||
} \
|
||||
} while (0)
|
||||
@@ -65,9 +64,8 @@ static Json::Value EncodeFilename(std::string const& path)
|
||||
#define PARSE_FILENAME(val, res) \
|
||||
do { \
|
||||
if (!ParseFilename(val, res)) { \
|
||||
cmSystemTools::Error( \
|
||||
cmStrCat("-E cmake_ninja_depends failed to parse ", arg_pp, \
|
||||
": invalid filename")); \
|
||||
cmSystemTools::Error(cmStrCat("-E cmake_ninja_dyndep failed to parse ", \
|
||||
arg_pp, ": invalid filename")); \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
@@ -84,7 +82,7 @@ bool cmScanDepFormat_P1689_Parse(std::string const& arg_pp, cmSourceInfo* info)
|
||||
{
|
||||
Json::Reader reader;
|
||||
if (!reader.parse(ppf, ppio, false)) {
|
||||
cmSystemTools::Error(cmStrCat("-E cmake_ninja_depends failed to parse ",
|
||||
cmSystemTools::Error(cmStrCat("-E cmake_ninja_dyndep failed to parse ",
|
||||
arg_pp,
|
||||
reader.getFormattedErrorMessages()));
|
||||
return false;
|
||||
@@ -93,7 +91,7 @@ bool cmScanDepFormat_P1689_Parse(std::string const& arg_pp, cmSourceInfo* info)
|
||||
|
||||
Json::Value const& version = ppi["version"];
|
||||
if (version.asUInt() != 0) {
|
||||
cmSystemTools::Error(cmStrCat("-E cmake_ninja_depends failed to parse ",
|
||||
cmSystemTools::Error(cmStrCat("-E cmake_ninja_dyndep failed to parse ",
|
||||
arg_pp, ": version ", version.asString()));
|
||||
return false;
|
||||
}
|
||||
@@ -101,7 +99,7 @@ bool cmScanDepFormat_P1689_Parse(std::string const& arg_pp, cmSourceInfo* info)
|
||||
Json::Value const& rules = ppi["rules"];
|
||||
if (rules.isArray()) {
|
||||
if (rules.size() != 1) {
|
||||
cmSystemTools::Error(cmStrCat("-E cmake_ninja_depends failed to parse ",
|
||||
cmSystemTools::Error(cmStrCat("-E cmake_ninja_dyndep failed to parse ",
|
||||
arg_pp, ": expected 1 source entry"));
|
||||
return false;
|
||||
}
|
||||
@@ -109,9 +107,9 @@ bool cmScanDepFormat_P1689_Parse(std::string const& arg_pp, cmSourceInfo* info)
|
||||
for (auto const& rule : rules) {
|
||||
Json::Value const& workdir = rule["work-directory"];
|
||||
if (!workdir.isString()) {
|
||||
cmSystemTools::Error(
|
||||
cmStrCat("-E cmake_ninja_depends failed to parse ", arg_pp,
|
||||
": work-directory is not a string"));
|
||||
cmSystemTools::Error(cmStrCat("-E cmake_ninja_dyndep failed to parse ",
|
||||
arg_pp,
|
||||
": work-directory is not a string"));
|
||||
return false;
|
||||
}
|
||||
std::string work_directory;
|
||||
@@ -134,7 +132,7 @@ bool cmScanDepFormat_P1689_Parse(std::string const& arg_pp, cmSourceInfo* info)
|
||||
if (outputs.isArray()) {
|
||||
if (outputs.empty()) {
|
||||
cmSystemTools::Error(
|
||||
cmStrCat("-E cmake_ninja_depends failed to parse ", arg_pp,
|
||||
cmStrCat("-E cmake_ninja_dyndep failed to parse ", arg_pp,
|
||||
": expected at least one 1 output"));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -175,7 +175,7 @@ private:
|
||||
#define CM_HEADER_REGEX "\\.(h|hh|h\\+\\+|hm|hpp|hxx|in|txx|inl)$"
|
||||
|
||||
#define CM_SOURCE_REGEX \
|
||||
"\\.(C|F|M|c|c\\+\\+|cc|cpp|cxx|cu|f|f90|for|fpp|ftn|m|mm|" \
|
||||
"\\.(C|F|M|c|c\\+\\+|cc|cpp|mpp|cxx|cu|f|f90|for|fpp|ftn|m|mm|" \
|
||||
"rc|def|r|odl|idl|hpj|bat)$"
|
||||
|
||||
#define CM_PCH_REGEX "cmake_pch(_[^.]+)?\\.(h|hxx)$"
|
||||
|
||||
@@ -44,6 +44,16 @@ struct StandardNeeded
|
||||
int value;
|
||||
};
|
||||
|
||||
int ParseStd(std::string const& level)
|
||||
{
|
||||
try {
|
||||
return std::stoi(level);
|
||||
} catch (std::invalid_argument&) {
|
||||
// Fall through to use an invalid value.
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct StanardLevelComputer
|
||||
{
|
||||
explicit StanardLevelComputer(std::string lang, std::vector<int> levels,
|
||||
@@ -113,17 +123,8 @@ struct StanardLevelComputer
|
||||
standardStr = "03";
|
||||
}
|
||||
|
||||
int standardValue = -1;
|
||||
int defaultValue = -1;
|
||||
try {
|
||||
standardValue = std::stoi(standardStr);
|
||||
defaultValue = std::stoi(*defaultStd);
|
||||
} catch (std::invalid_argument&) {
|
||||
// fall through as we want an error
|
||||
// when we can't find the bad value in the `stds` vector
|
||||
}
|
||||
|
||||
auto stdIt = std::find(cm::cbegin(stds), cm::cend(stds), standardValue);
|
||||
auto stdIt =
|
||||
std::find(cm::cbegin(stds), cm::cend(stds), ParseStd(standardStr));
|
||||
if (stdIt == cm::cend(stds)) {
|
||||
std::string e =
|
||||
cmStrCat(this->Language, "_STANDARD is set to invalid value '",
|
||||
@@ -134,7 +135,7 @@ struct StanardLevelComputer
|
||||
}
|
||||
|
||||
auto defaultStdIt =
|
||||
std::find(cm::cbegin(stds), cm::cend(stds), defaultValue);
|
||||
std::find(cm::cbegin(stds), cm::cend(stds), ParseStd(*defaultStd));
|
||||
if (defaultStdIt == cm::cend(stds)) {
|
||||
std::string e = cmStrCat("CMAKE_", this->Language,
|
||||
"_STANDARD_DEFAULT is set to invalid value '",
|
||||
@@ -195,7 +196,7 @@ struct StanardLevelComputer
|
||||
if (existingStandard) {
|
||||
existingLevelIter =
|
||||
std::find(cm::cbegin(this->Levels), cm::cend(this->Levels),
|
||||
std::stoi(*existingStandard));
|
||||
ParseStd(*existingStandard));
|
||||
if (existingLevelIter == cm::cend(this->Levels)) {
|
||||
const std::string e =
|
||||
cmStrCat("The ", this->Language, "_STANDARD property on target \"",
|
||||
@@ -240,7 +241,7 @@ struct StanardLevelComputer
|
||||
}
|
||||
// convert defaultStandard to an integer
|
||||
if (std::find(cm::cbegin(this->Levels), cm::cend(this->Levels),
|
||||
std::stoi(*defaultStandard)) == cm::cend(this->Levels)) {
|
||||
ParseStd(*defaultStandard)) == cm::cend(this->Levels)) {
|
||||
const std::string e = cmStrCat("The CMAKE_", this->Language,
|
||||
"_STANDARD_DEFAULT variable contains an "
|
||||
"invalid value: \"",
|
||||
@@ -257,7 +258,7 @@ struct StanardLevelComputer
|
||||
|
||||
auto existingLevelIter =
|
||||
std::find(cm::cbegin(this->Levels), cm::cend(this->Levels),
|
||||
std::stoi(*existingStandard));
|
||||
ParseStd(*existingStandard));
|
||||
if (existingLevelIter == cm::cend(this->Levels)) {
|
||||
const std::string e =
|
||||
cmStrCat("The ", this->Language, "_STANDARD property on target \"",
|
||||
|
||||
+3
-2
@@ -208,8 +208,9 @@ cmake::cmake(Role role, cmState::Mode mode)
|
||||
};
|
||||
|
||||
// The "c" extension MUST precede the "C" extension.
|
||||
setupExts(this->CLikeSourceFileExtensions,
|
||||
{ "c", "C", "c++", "cc", "cpp", "cxx", "cu", "m", "M", "mm" });
|
||||
setupExts(
|
||||
this->CLikeSourceFileExtensions,
|
||||
{ "c", "C", "c++", "cc", "cpp", "cxx", "cu", "mpp", "m", "M", "mm" });
|
||||
setupExts(this->HeaderFileExtensions,
|
||||
{ "h", "hh", "h++", "hm", "hpp", "hxx", "in", "txx" });
|
||||
setupExts(this->CudaFileExtensions, { "cu" });
|
||||
|
||||
Reference in New Issue
Block a user