summaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
Diffstat (limited to 'Source')
-rw-r--r--Source/CMakeLists.txt8
-rw-r--r--Source/CMakeVersion.cmake2
-rw-r--r--Source/CPack/cmCPackFreeBSDGenerator.cxx54
-rw-r--r--Source/CPack/cpack.cxx2
-rw-r--r--Source/CTest/cmCTestCoverageCommand.cxx12
-rw-r--r--Source/CTest/cmCTestCoverageCommand.h6
-rw-r--r--Source/CTest/cmCTestHandlerCommand.cxx20
-rw-r--r--Source/CTest/cmCTestHandlerCommand.h5
-rw-r--r--Source/CTest/cmCTestRunTest.cxx146
-rw-r--r--Source/CTest/cmCTestSubmitCommand.cxx65
-rw-r--r--Source/CTest/cmCTestSubmitCommand.h13
-rw-r--r--Source/CTest/cmCTestUploadCommand.cxx2
-rw-r--r--Source/CTest/cmCTestUploadCommand.h5
-rw-r--r--Source/CursesDialog/cmCursesLongMessageForm.cxx2
-rw-r--r--Source/CursesDialog/form/.gitattributes1
-rw-r--r--Source/CursesDialog/form/fty_int.c2
-rw-r--r--Source/CursesDialog/form/fty_num.c2
-rw-r--r--Source/LexerParser/cmFortranLexer.cxx377
-rw-r--r--Source/LexerParser/cmFortranLexer.in.l16
-rw-r--r--Source/LexerParser/cmFortranParser.cxx324
-rw-r--r--Source/LexerParser/cmFortranParser.y18
-rw-r--r--Source/cmArgumentParser.cxx186
-rw-r--r--Source/cmArgumentParser.h400
-rw-r--r--Source/cmArgumentParserTypes.h69
-rw-r--r--Source/cmBlockCommand.cxx200
-rw-r--r--Source/cmBlockCommand.h14
-rw-r--r--Source/cmCMakeHostSystemInformationCommand.cxx12
-rw-r--r--Source/cmCMakeLanguageCommand.cxx35
-rw-r--r--Source/cmCMakePathCommand.cxx134
-rw-r--r--Source/cmCMakePresetsGraph.cxx10
-rw-r--r--Source/cmCMakePresetsGraph.h5
-rw-r--r--Source/cmCMakePresetsGraphReadJSON.cxx23
-rw-r--r--Source/cmCommands.cxx12
-rw-r--r--Source/cmCommonTargetGenerator.cxx4
-rw-r--r--Source/cmConfigure.cmake.h.in4
-rw-r--r--Source/cmCoreTryCompile.cxx622
-rw-r--r--Source/cmCoreTryCompile.h56
-rw-r--r--Source/cmCreateTestSourceList.cxx4
-rw-r--r--Source/cmCxxModuleMapper.cxx308
-rw-r--r--Source/cmCxxModuleMapper.h85
-rw-r--r--Source/cmDefinePropertyCommand.cxx5
-rw-r--r--Source/cmDocumentation.cxx42
-rw-r--r--Source/cmExecuteProcessCommand.cxx12
-rw-r--r--Source/cmExperimental.cxx63
-rw-r--r--Source/cmExperimental.h21
-rw-r--r--Source/cmExportBuildFileGenerator.cxx98
-rw-r--r--Source/cmExportBuildFileGenerator.h16
-rw-r--r--Source/cmExportCommand.cxx23
-rw-r--r--Source/cmExportFileGenerator.cxx33
-rw-r--r--Source/cmExportFileGenerator.h5
-rw-r--r--Source/cmExportInstallAndroidMKGenerator.cxx3
-rw-r--r--Source/cmExportInstallFileGenerator.cxx108
-rw-r--r--Source/cmExportInstallFileGenerator.h25
-rw-r--r--Source/cmExportTryCompileFileGenerator.h3
-rw-r--r--Source/cmFileAPICodemodel.cxx16
-rw-r--r--Source/cmFileCommand.cxx402
-rw-r--r--Source/cmFindBase.cxx62
-rw-r--r--Source/cmFindBase.h7
-rw-r--r--Source/cmFindLibraryCommand.cxx33
-rw-r--r--Source/cmFindPackageCommand.cxx1265
-rw-r--r--Source/cmFindPackageCommand.h2
-rw-r--r--Source/cmFindPathCommand.cxx6
-rw-r--r--Source/cmFindProgramCommand.cxx12
-rw-r--r--Source/cmFunctionBlocker.cxx18
-rw-r--r--Source/cmFunctionBlocker.h2
-rw-r--r--Source/cmGeneratedFileStream.cxx6
-rw-r--r--Source/cmGeneratorTarget.cxx133
-rw-r--r--Source/cmGeneratorTarget.h35
-rw-r--r--Source/cmGhsMultiTargetGenerator.cxx4
-rw-r--r--Source/cmGlobalGenerator.cxx9
-rw-r--r--Source/cmGlobalNinjaGenerator.cxx546
-rw-r--r--Source/cmGlobalNinjaGenerator.h4
-rw-r--r--Source/cmGlobalVisualStudio7Generator.cxx15
-rw-r--r--Source/cmGlobalVisualStudio7Generator.h2
-rw-r--r--Source/cmGlobalXCodeGenerator.cxx38
-rw-r--r--Source/cmInstallCommand.cxx157
-rw-r--r--Source/cmInstallCommandArguments.h5
-rw-r--r--Source/cmInstallCxxModuleBmiGenerator.cxx75
-rw-r--r--Source/cmInstallCxxModuleBmiGenerator.h52
-rw-r--r--Source/cmInstallExportGenerator.cxx73
-rw-r--r--Source/cmInstallExportGenerator.h8
-rw-r--r--Source/cmLinkLineDeviceComputer.cxx21
-rw-r--r--Source/cmLinkLineDeviceComputer.h1
-rw-r--r--Source/cmListFileCache.cxx11
-rw-r--r--Source/cmLocalGenerator.cxx32
-rw-r--r--Source/cmLocalGenerator.h13
-rw-r--r--Source/cmLocalUnixMakefileGenerator3.cxx37
-rw-r--r--Source/cmLocalVisualStudio7Generator.cxx3
-rw-r--r--Source/cmMakefile.cxx86
-rw-r--r--Source/cmMakefile.h19
-rw-r--r--Source/cmMakefileExecutableTargetGenerator.cxx27
-rw-r--r--Source/cmMakefileLibraryTargetGenerator.cxx25
-rw-r--r--Source/cmMakefileTargetGenerator.cxx130
-rw-r--r--Source/cmMakefileTargetGenerator.h20
-rw-r--r--Source/cmMessageCommand.cxx65
-rw-r--r--Source/cmMessageType.h16
-rw-r--r--Source/cmNinjaNormalTargetGenerator.cxx1
-rw-r--r--Source/cmNinjaTargetGenerator.cxx321
-rw-r--r--Source/cmParseArgumentsCommand.cxx17
-rw-r--r--Source/cmQtAutoGenInitializer.cxx3
-rw-r--r--Source/cmQtAutoMocUic.cxx3
-rw-r--r--Source/cmScanDepFormat.cxx37
-rw-r--r--Source/cmScanDepFormat.h5
-rw-r--r--Source/cmScriptGenerator.cxx2
-rw-r--r--Source/cmSetPropertyCommand.cxx4
-rw-r--r--Source/cmSourceGroup.cxx15
-rw-r--r--Source/cmSourceGroup.h6
-rw-r--r--Source/cmStandardLevelResolver.cxx7
-rw-r--r--Source/cmStringCommand.cxx5
-rw-r--r--Source/cmSystemTools.cxx144
-rw-r--r--Source/cmSystemTools.h39
-rw-r--r--Source/cmTarget.cxx121
-rw-r--r--Source/cmTarget.h10
-rw-r--r--Source/cmTargetCompileDefinitionsCommand.cxx4
-rw-r--r--Source/cmTargetExport.h2
-rw-r--r--Source/cmTargetIncludeDirectoriesCommand.cxx3
-rw-r--r--Source/cmTargetLinkLibrariesCommand.cxx8
-rw-r--r--Source/cmTargetPrecompileHeadersCommand.cxx4
-rw-r--r--Source/cmTargetSourcesCommand.cxx47
-rw-r--r--Source/cmTryCompileCommand.cxx58
-rw-r--r--Source/cmTryCompileCommand.h30
-rw-r--r--Source/cmTryRunCommand.cxx339
-rw-r--r--Source/cmTryRunCommand.h44
-rw-r--r--Source/cmVisualStudio10TargetGenerator.cxx71
-rw-r--r--Source/cmVisualStudio10TargetGenerator.h1
-rw-r--r--Source/cmVisualStudioGeneratorOptions.cxx71
-rw-r--r--Source/cmXCodeScheme.cxx10
-rw-r--r--Source/cmake.cxx62
-rw-r--r--Source/cmake.h22
-rw-r--r--Source/cmakemain.cxx17
-rw-r--r--Source/cmcldeps.cxx1
-rw-r--r--Source/cmcmd.cxx51
-rw-r--r--Source/kwsys/Directory.cxx39
-rw-r--r--Source/kwsys/SystemTools.cxx103
134 files changed, 6014 insertions, 2928 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 95b07cb..b6f7c85 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -197,6 +197,8 @@ set(SRCS
cmCustomCommandLines.cxx
cmCustomCommandLines.h
cmCustomCommandTypes.h
+ cmCxxModuleMapper.cxx
+ cmCxxModuleMapper.h
cmDefinitions.cxx
cmDefinitions.h
cmDependencyProvider.h
@@ -543,6 +545,8 @@ set(SRCS
cmExecuteProcessCommand.h
cmExpandedCommandArgument.cxx
cmExpandedCommandArgument.h
+ cmExperimental.cxx
+ cmExperimental.h
cmExportCommand.cxx
cmExportCommand.h
cmExportLibraryDependenciesCommand.cxx
@@ -567,6 +571,8 @@ set(SRCS
cmFindProgramCommand.h
cmForEachCommand.cxx
cmForEachCommand.h
+ cmBlockCommand.cxx
+ cmBlockCommand.h
cmFunctionBlocker.cxx
cmFunctionBlocker.h
cmFunctionCommand.cxx
@@ -603,6 +609,8 @@ set(SRCS
cmInstallCommand.h
cmInstallCommandArguments.cxx
cmInstallCommandArguments.h
+ cmInstallCxxModuleBmiGenerator.cxx
+ cmInstallCxxModuleBmiGenerator.h
cmInstallFilesCommand.cxx
cmInstallFilesCommand.h
cmInstallProgramsCommand.cxx
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index 6851aa2..91c9513 100644
--- a/Source/CMakeVersion.cmake
+++ b/Source/CMakeVersion.cmake
@@ -1,7 +1,7 @@
# CMake version number components.
set(CMake_VERSION_MAJOR 3)
set(CMake_VERSION_MINOR 24)
-set(CMake_VERSION_PATCH 1)
+set(CMake_VERSION_PATCH 20220831)
#set(CMake_VERSION_RC 0)
set(CMake_VERSION_IS_DIRTY 0)
diff --git a/Source/CPack/cmCPackFreeBSDGenerator.cxx b/Source/CPack/cmCPackFreeBSDGenerator.cxx
index 607d797..162dfc7 100644
--- a/Source/CPack/cmCPackFreeBSDGenerator.cxx
+++ b/Source/CPack/cmCPackFreeBSDGenerator.cxx
@@ -23,8 +23,6 @@
// Suffix used to tell libpkg what compression to use
static const char FreeBSDPackageCompression[] = "txz";
-// Resulting package file-suffix, for < 1.17 and >= 1.17 versions of libpkg
-static const char FreeBSDPackageSuffix_10[] = ".txz";
static const char FreeBSDPackageSuffix_17[] = ".pkg";
cmCPackFreeBSDGenerator::cmCPackFreeBSDGenerator()
@@ -83,6 +81,14 @@ public:
{
if (!isValid())
return false;
+ // The API in the FreeBSD sources (the header has no documentation),
+ // is as follows:
+ //
+ // int pkg_create(struct pkg_create *pc, const char *metadata, const char
+ // *plist, bool hash)
+ //
+ // We let the plist be determined from what is installed, and all
+ // the rest comes from the manifest data.
int r = pkg_create(d, manifest.c_str(), nullptr, false);
return r == 0;
}
@@ -402,7 +408,8 @@ int cmCPackFreeBSDGenerator::PackageFiles()
return 0;
}
- std::string output_dir = cmSystemTools::CollapseFullPath("../", toplevel);
+ const std::string output_dir =
+ cmSystemTools::CollapseFullPath("../", toplevel);
PkgCreate package(output_dir, toplevel, manifestname);
if (package.isValid()) {
if (!package.Create()) {
@@ -416,40 +423,33 @@ int cmCPackFreeBSDGenerator::PackageFiles()
return 0;
}
- // Specifically looking for packages suffixed with the TAG, either extension
- std::string broken_suffix_10 =
- cmStrCat('-', var_lookup("CPACK_TOPLEVEL_TAG"), FreeBSDPackageSuffix_10);
+ // Specifically looking for packages suffixed with the TAG
std::string broken_suffix_17 =
cmStrCat('-', var_lookup("CPACK_TOPLEVEL_TAG"), FreeBSDPackageSuffix_17);
for (std::string& name : packageFileNames) {
cmCPackLogger(cmCPackLog::LOG_DEBUG, "Packagefile " << name << std::endl);
- if (cmHasSuffix(name, broken_suffix_10)) {
- name.replace(name.size() - broken_suffix_10.size(), std::string::npos,
- FreeBSDPackageSuffix_10);
- break;
- }
if (cmHasSuffix(name, broken_suffix_17)) {
name.replace(name.size() - broken_suffix_17.size(), std::string::npos,
FreeBSDPackageSuffix_17);
break;
}
}
- // If the name uses a *new* style name, which doesn't exist, but there
- // is an *old* style name, then use that instead. This indicates we used
- // an older libpkg, which still creates .txz instead of .pkg files.
- for (std::string& name : packageFileNames) {
- if (cmHasSuffix(name, FreeBSDPackageSuffix_17) &&
- !cmSystemTools::FileExists(name)) {
- const std::string badSuffix(FreeBSDPackageSuffix_17);
- const std::string goodSuffix(FreeBSDPackageSuffix_10);
- std::string repairedName(name);
- repairedName.replace(repairedName.size() - badSuffix.size(),
- std::string::npos, goodSuffix);
- if (cmSystemTools::FileExists(repairedName)) {
- name = repairedName;
- cmCPackLogger(cmCPackLog::LOG_DEBUG,
- "Repaired packagefile " << name << std::endl);
- }
+
+ const std::string packageFileName =
+ var_lookup("CPACK_PACKAGE_FILE_NAME") + FreeBSDPackageSuffix_17;
+ if (packageFileNames.size() == 1 && !packageFileName.empty() &&
+ packageFileNames[0] != packageFileName) {
+ // Since libpkg always writes <name>-<version>.<suffix>,
+ // if there is a CPACK_PACKAGE_FILE_NAME set, we need to
+ // rename, and then re-set the name.
+ const std::string sourceFile = packageFileNames[0];
+ const std::string packageSubDirectory =
+ cmSystemTools::GetParentDirectory(sourceFile);
+ const std::string targetFileName =
+ packageSubDirectory + '/' + packageFileName;
+ if (cmSystemTools::RenameFile(sourceFile, targetFileName)) {
+ this->packageFileNames.clear();
+ this->packageFileNames.emplace_back(targetFileName);
}
}
diff --git a/Source/CPack/cpack.cxx b/Source/CPack/cpack.cxx
index 221f7dd..4d9a42a 100644
--- a/Source/CPack/cpack.cxx
+++ b/Source/CPack/cpack.cxx
@@ -50,7 +50,7 @@ const char* cmDocumentationOptions[][2] = {
{ "-C <Configuration>", "Specify the project configuration" },
{ "-D <var>=<value>", "Set a CPack variable." },
{ "--config <configFile>", "Specify the config file." },
- { "--verbose,-V", "Enable verbose output" },
+ { "-V,--verbose", "Enable verbose output" },
{ "--trace", "Put underlying cmake scripts in trace mode." },
{ "--trace-expand", "Put underlying cmake scripts in expanded trace mode." },
{ "--debug", "Enable debug output (for CPack developers)" },
diff --git a/Source/CTest/cmCTestCoverageCommand.cxx b/Source/CTest/cmCTestCoverageCommand.cxx
index 7432d08..97b0a89 100644
--- a/Source/CTest/cmCTestCoverageCommand.cxx
+++ b/Source/CTest/cmCTestCoverageCommand.cxx
@@ -4,7 +4,6 @@
#include <set>
-#include <cmext/algorithm>
#include <cmext/string_view>
#include "cmCTest.h"
@@ -18,13 +17,6 @@ void cmCTestCoverageCommand::BindArguments()
this->Bind("LABELS"_s, this->Labels);
}
-void cmCTestCoverageCommand::CheckArguments(
- std::vector<std::string> const& keywords)
-{
- this->LabelsMentioned =
- !this->Labels.empty() || cm::contains(keywords, "LABELS");
-}
-
cmCTestGenericHandler* cmCTestCoverageCommand::InitializeHandler()
{
this->CTest->SetCTestConfigurationFromCMakeVariable(
@@ -36,9 +28,9 @@ cmCTestGenericHandler* cmCTestCoverageCommand::InitializeHandler()
handler->Initialize();
// If a LABELS option was given, select only files with the labels.
- if (this->LabelsMentioned) {
+ if (this->Labels) {
handler->SetLabelFilter(
- std::set<std::string>(this->Labels.begin(), this->Labels.end()));
+ std::set<std::string>(this->Labels->begin(), this->Labels->end()));
}
handler->SetQuiet(this->Quiet);
diff --git a/Source/CTest/cmCTestCoverageCommand.h b/Source/CTest/cmCTestCoverageCommand.h
index 9344852..55c68b2 100644
--- a/Source/CTest/cmCTestCoverageCommand.h
+++ b/Source/CTest/cmCTestCoverageCommand.h
@@ -9,7 +9,9 @@
#include <vector>
#include <cm/memory>
+#include <cm/optional>
+#include "cmArgumentParserTypes.h" // IWYU pragma: keep
#include "cmCTestHandlerCommand.h"
#include "cmCommand.h"
@@ -41,9 +43,7 @@ public:
protected:
void BindArguments() override;
- void CheckArguments(std::vector<std::string> const& keywords) override;
cmCTestGenericHandler* InitializeHandler() override;
- bool LabelsMentioned;
- std::vector<std::string> Labels;
+ cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>> Labels;
};
diff --git a/Source/CTest/cmCTestHandlerCommand.cxx b/Source/CTest/cmCTestHandlerCommand.cxx
index 5494d20..be952cd 100644
--- a/Source/CTest/cmCTestHandlerCommand.cxx
+++ b/Source/CTest/cmCTestHandlerCommand.cxx
@@ -7,6 +7,7 @@
#include <cstring>
#include <sstream>
+#include <cm/string_view>
#include <cmext/string_view>
#include "cmCTest.h"
@@ -81,15 +82,13 @@ bool cmCTestHandlerCommand::InitialPass(std::vector<std::string> const& args,
// Process input arguments.
std::vector<std::string> unparsedArguments;
- std::vector<std::string> keywordsMissingValue;
- std::vector<std::string> parsedKeywords;
- this->Parse(args, &unparsedArguments, &keywordsMissingValue,
- &parsedKeywords);
- this->CheckArguments(keywordsMissingValue);
-
- std::sort(parsedKeywords.begin(), parsedKeywords.end());
- auto it = std::adjacent_find(parsedKeywords.begin(), parsedKeywords.end());
- if (it != parsedKeywords.end()) {
+ this->Parse(args, &unparsedArguments);
+ this->CheckArguments();
+
+ std::sort(this->ParsedKeywords.begin(), this->ParsedKeywords.end());
+ auto it = std::adjacent_find(this->ParsedKeywords.begin(),
+ this->ParsedKeywords.end());
+ if (it != this->ParsedKeywords.end()) {
this->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
cmStrCat("Called with more than one value for ", *it));
@@ -233,6 +232,7 @@ void cmCTestHandlerCommand::ProcessAdditionalValues(cmCTestGenericHandler*)
void cmCTestHandlerCommand::BindArguments()
{
+ this->BindParsedKeywords(this->ParsedKeywords);
this->Bind("APPEND"_s, this->Append);
this->Bind("QUIET"_s, this->Quiet);
this->Bind("RETURN_VALUE"_s, this->ReturnValue);
@@ -242,6 +242,6 @@ void cmCTestHandlerCommand::BindArguments()
this->Bind("SUBMIT_INDEX"_s, this->SubmitIndex);
}
-void cmCTestHandlerCommand::CheckArguments(std::vector<std::string> const&)
+void cmCTestHandlerCommand::CheckArguments()
{
}
diff --git a/Source/CTest/cmCTestHandlerCommand.h b/Source/CTest/cmCTestHandlerCommand.h
index 756952d..ed6d9af 100644
--- a/Source/CTest/cmCTestHandlerCommand.h
+++ b/Source/CTest/cmCTestHandlerCommand.h
@@ -7,6 +7,8 @@
#include <string>
#include <vector>
+#include <cm/string_view>
+
#include "cmArgumentParser.h"
#include "cmCTestCommand.h"
@@ -42,8 +44,9 @@ protected:
// Command argument handling.
virtual void BindArguments();
- virtual void CheckArguments(std::vector<std::string> const& keywords);
+ virtual void CheckArguments();
+ std::vector<cm::string_view> ParsedKeywords;
bool Append = false;
bool Quiet = false;
std::string CaptureCMakeError;
diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx
index 2a2cb1c..5efe69f 100644
--- a/Source/CTest/cmCTestRunTest.cxx
+++ b/Source/CTest/cmCTestRunTest.cxx
@@ -8,16 +8,12 @@
#include <cstdint>
#include <cstdio>
#include <cstring>
-#include <functional>
#include <iomanip>
#include <ratio>
#include <sstream>
#include <utility>
#include <cm/memory>
-#include <cm/optional>
-#include <cm/string_view>
-#include <cmext/string_view>
#include "cmsys/RegularExpression.hxx"
@@ -787,149 +783,31 @@ bool cmCTestRunTest::ForkProcess(
this->TestProcess->SetTimeout(timeout);
-#ifndef CMAKE_BOOTSTRAP
cmSystemTools::SaveRestoreEnvironment sre;
-#endif
-
std::ostringstream envMeasurement;
+
+ // We split processing ENVIRONMENT and ENVIRONMENT_MODIFICATION into two
+ // phases to ensure that MYVAR=reset: in the latter phase resets to the
+ // former phase's settings, rather than to the original environment.
if (environment && !environment->empty()) {
- // Environment modification works on the assumption that the environment is
- // actually modified here. If another strategy is used, there will need to
- // be updates below in `apply_diff`.
- cmSystemTools::AppendEnv(*environment);
- for (auto const& var : *environment) {
- envMeasurement << var << std::endl;
- }
+ cmSystemTools::EnvDiff diff;
+ diff.AppendEnv(*environment);
+ diff.ApplyToCurrentEnv(&envMeasurement);
}
if (environment_modification && !environment_modification->empty()) {
- std::map<std::string, cm::optional<std::string>> env_application;
-
-#ifdef _WIN32
- char path_sep = ';';
-#else
- char path_sep = ':';
-#endif
-
- auto apply_diff =
- [&env_application](const std::string& name,
- std::function<void(std::string&)> const& apply) {
- cm::optional<std::string> old_value = env_application[name];
- std::string output;
- if (old_value) {
- output = *old_value;
- } else {
- // This only works because the environment is actually modified above
- // (`AppendEnv`). If CTest ever just creates an environment block
- // directly, that block will need to be queried for the subprocess'
- // value instead.
- const char* curval = cmSystemTools::GetEnv(name);
- if (curval) {
- output = curval;
- }
- }
- apply(output);
- env_application[name] = output;
- };
-
- bool err_occurred = false;
+ cmSystemTools::EnvDiff diff;
+ bool env_ok = true;
for (auto const& envmod : *environment_modification) {
- // Split on `=`
- auto const eq_loc = envmod.find_first_of('=');
- if (eq_loc == std::string::npos) {
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Error: Missing `=` after the variable name in: "
- << envmod << std::endl);
- err_occurred = true;
- continue;
- }
- auto const name = envmod.substr(0, eq_loc);
-
- // Split value on `:`
- auto const op_value_start = eq_loc + 1;
- auto const colon_loc = envmod.find_first_of(':', op_value_start);
- if (colon_loc == std::string::npos) {
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Error: Missing `:` after the operation in: " << envmod
- << std::endl);
- err_occurred = true;
- continue;
- }
- auto const op =
- envmod.substr(op_value_start, colon_loc - op_value_start);
-
- auto const value_start = colon_loc + 1;
- auto const value = envmod.substr(value_start);
-
- // Determine what to do with the operation.
- if (op == "reset"_s) {
- auto entry = env_application.find(name);
- if (entry != env_application.end()) {
- env_application.erase(entry);
- }
- } else if (op == "set"_s) {
- env_application[name] = value;
- } else if (op == "unset"_s) {
- env_application[name] = {};
- } else if (op == "string_append"_s) {
- apply_diff(name, [&value](std::string& output) { output += value; });
- } else if (op == "string_prepend"_s) {
- apply_diff(name,
- [&value](std::string& output) { output.insert(0, value); });
- } else if (op == "path_list_append"_s) {
- apply_diff(name, [&value, path_sep](std::string& output) {
- if (!output.empty()) {
- output += path_sep;
- }
- output += value;
- });
- } else if (op == "path_list_prepend"_s) {
- apply_diff(name, [&value, path_sep](std::string& output) {
- if (!output.empty()) {
- output.insert(output.begin(), path_sep);
- }
- output.insert(0, value);
- });
- } else if (op == "cmake_list_append"_s) {
- apply_diff(name, [&value](std::string& output) {
- if (!output.empty()) {
- output += ';';
- }
- output += value;
- });
- } else if (op == "cmake_list_prepend"_s) {
- apply_diff(name, [&value](std::string& output) {
- if (!output.empty()) {
- output.insert(output.begin(), ';');
- }
- output.insert(0, value);
- });
- } else {
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Error: Unrecognized environment manipulation argument: "
- << op << std::endl);
- err_occurred = true;
- continue;
- }
+ env_ok &= diff.ParseOperation(envmod);
}
- if (err_occurred) {
+ if (!env_ok) {
return false;
}
- for (auto const& env_apply : env_application) {
- if (env_apply.second) {
- auto const env_update =
- cmStrCat(env_apply.first, '=', *env_apply.second);
- cmSystemTools::PutEnv(env_update);
- envMeasurement << env_update << std::endl;
- } else {
- cmSystemTools::UnsetEnv(env_apply.first.c_str());
- // Signify that this variable is being actively unset
- envMeasurement << "#" << env_apply.first << "=" << std::endl;
- }
- }
+ diff.ApplyToCurrentEnv(&envMeasurement);
}
if (this->UseAllocatedResources) {
diff --git a/Source/CTest/cmCTestSubmitCommand.cxx b/Source/CTest/cmCTestSubmitCommand.cxx
index a2dc615..a1933cc 100644
--- a/Source/CTest/cmCTestSubmitCommand.cxx
+++ b/Source/CTest/cmCTestSubmitCommand.cxx
@@ -8,7 +8,6 @@
#include <cm/memory>
#include <cm/vector>
-#include <cmext/algorithm>
#include <cmext/string_view>
#include "cmCTest.h"
@@ -87,7 +86,7 @@ cmCTestGenericHandler* cmCTestSubmitCommand::InitializeHandler()
// If FILES are given, but not PARTS, only the FILES are submitted
// and *no* PARTS are submitted.
// (This is why we select the empty "noParts" set in the
- // FilesMentioned block below...)
+ // if(this->Files) block below...)
//
// If PARTS are given, only the selected PARTS are submitted.
//
@@ -96,7 +95,7 @@ cmCTestGenericHandler* cmCTestSubmitCommand::InitializeHandler()
// If given explicit FILES to submit, pass them to the handler.
//
- if (this->FilesMentioned) {
+ if (this->Files) {
// Intentionally select *no* PARTS. (Pass an empty set.) If PARTS
// were also explicitly mentioned, they will be selected below...
// But FILES with no PARTS mentioned should just submit the FILES
@@ -104,14 +103,14 @@ cmCTestGenericHandler* cmCTestSubmitCommand::InitializeHandler()
//
handler->SelectParts(std::set<cmCTest::Part>());
handler->SelectFiles(
- std::set<std::string>(this->Files.begin(), this->Files.end()));
+ std::set<std::string>(this->Files->begin(), this->Files->end()));
}
// If a PARTS option was given, select only the named parts for submission.
//
- if (this->PartsMentioned) {
+ if (this->Parts) {
auto parts =
- cmMakeRange(this->Parts).transform([this](std::string const& arg) {
+ cmMakeRange(*(this->Parts)).transform([this](std::string const& arg) {
return this->CTest->GetPartFromName(arg);
});
handler->SelectParts(std::set<cmCTest::Part>(parts.begin(), parts.end()));
@@ -172,33 +171,31 @@ void cmCTestSubmitCommand::BindArguments()
this->cmCTestHandlerCommand::BindArguments();
}
-void cmCTestSubmitCommand::CheckArguments(
- std::vector<std::string> const& keywords)
+void cmCTestSubmitCommand::CheckArguments()
{
- this->PartsMentioned =
- !this->Parts.empty() || cm::contains(keywords, "PARTS");
- this->FilesMentioned =
- !this->Files.empty() || cm::contains(keywords, "FILES");
-
- cm::erase_if(this->Parts, [this](std::string const& arg) -> bool {
- cmCTest::Part p = this->CTest->GetPartFromName(arg);
- if (p == cmCTest::PartCount) {
- std::ostringstream e;
- e << "Part name \"" << arg << "\" is invalid.";
- this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
- return true;
- }
- return false;
- });
-
- cm::erase_if(this->Files, [this](std::string const& arg) -> bool {
- if (!cmSystemTools::FileExists(arg)) {
- std::ostringstream e;
- e << "File \"" << arg << "\" does not exist. Cannot submit "
- << "a non-existent file.";
- this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
- return true;
- }
- return false;
- });
+ if (this->Parts) {
+ cm::erase_if(*(this->Parts), [this](std::string const& arg) -> bool {
+ cmCTest::Part p = this->CTest->GetPartFromName(arg);
+ if (p == cmCTest::PartCount) {
+ std::ostringstream e;
+ e << "Part name \"" << arg << "\" is invalid.";
+ this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return true;
+ }
+ return false;
+ });
+ }
+
+ if (this->Files) {
+ cm::erase_if(*(this->Files), [this](std::string const& arg) -> bool {
+ if (!cmSystemTools::FileExists(arg)) {
+ std::ostringstream e;
+ e << "File \"" << arg << "\" does not exist. Cannot submit "
+ << "a non-existent file.";
+ this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return true;
+ }
+ return false;
+ });
+ }
}
diff --git a/Source/CTest/cmCTestSubmitCommand.h b/Source/CTest/cmCTestSubmitCommand.h
index c5d11df..b67f182 100644
--- a/Source/CTest/cmCTestSubmitCommand.h
+++ b/Source/CTest/cmCTestSubmitCommand.h
@@ -8,6 +8,9 @@
#include <string>
#include <vector>
+#include <cm/optional>
+
+#include "cmArgumentParserTypes.h"
#include "cmCTestHandlerCommand.h"
class cmCommand;
@@ -35,13 +38,11 @@ public:
protected:
void BindArguments() override;
- void CheckArguments(std::vector<std::string> const& keywords) override;
+ void CheckArguments() override;
cmCTestGenericHandler* InitializeHandler() override;
bool CDashUpload = false;
- bool FilesMentioned = false;
bool InternalTest = false;
- bool PartsMentioned = false;
std::string BuildID;
std::string CDashUploadFile;
@@ -50,7 +51,7 @@ protected:
std::string RetryDelay;
std::string SubmitURL;
- std::vector<std::string> Files;
- std::vector<std::string> HttpHeaders;
- std::vector<std::string> Parts;
+ cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>> Files;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> HttpHeaders;
+ cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>> Parts;
};
diff --git a/Source/CTest/cmCTestUploadCommand.cxx b/Source/CTest/cmCTestUploadCommand.cxx
index f86ee0d..2ed671c 100644
--- a/Source/CTest/cmCTestUploadCommand.cxx
+++ b/Source/CTest/cmCTestUploadCommand.cxx
@@ -21,7 +21,7 @@ void cmCTestUploadCommand::BindArguments()
this->Bind("CAPTURE_CMAKE_ERROR"_s, this->CaptureCMakeError);
}
-void cmCTestUploadCommand::CheckArguments(std::vector<std::string> const&)
+void cmCTestUploadCommand::CheckArguments()
{
cm::erase_if(this->Files, [this](std::string const& arg) -> bool {
if (!cmSystemTools::FileExists(arg)) {
diff --git a/Source/CTest/cmCTestUploadCommand.h b/Source/CTest/cmCTestUploadCommand.h
index fe155f6..a9d1dd2 100644
--- a/Source/CTest/cmCTestUploadCommand.h
+++ b/Source/CTest/cmCTestUploadCommand.h
@@ -10,6 +10,7 @@
#include <cm/memory>
+#include "cmArgumentParserTypes.h"
#include "cmCTestHandlerCommand.h"
#include "cmCommand.h"
@@ -42,8 +43,8 @@ public:
protected:
void BindArguments() override;
- void CheckArguments(std::vector<std::string> const&) override;
+ void CheckArguments() override;
cmCTestGenericHandler* InitializeHandler() override;
- std::vector<std::string> Files;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Files;
};
diff --git a/Source/CursesDialog/cmCursesLongMessageForm.cxx b/Source/CursesDialog/cmCursesLongMessageForm.cxx
index b14a751..6e6f0d6 100644
--- a/Source/CursesDialog/cmCursesLongMessageForm.cxx
+++ b/Source/CursesDialog/cmCursesLongMessageForm.cxx
@@ -85,7 +85,7 @@ void cmCursesLongMessageForm::UpdateStatusBar()
for (size_t i = 0; i < sideSpace; i++) {
version[i] = ' ';
}
- sprintf(version + sideSpace, "%s", vertmp);
+ snprintf(version + sideSpace, sizeof(version) - sideSpace, "%s", vertmp);
version[width] = '\0';
char fmt_s[] = "%s";
diff --git a/Source/CursesDialog/form/.gitattributes b/Source/CursesDialog/form/.gitattributes
index 12ede74..6dfa627 100644
--- a/Source/CursesDialog/form/.gitattributes
+++ b/Source/CursesDialog/form/.gitattributes
@@ -1 +1,2 @@
+* -whitespace
* -format.clang-format-6.0
diff --git a/Source/CursesDialog/form/fty_int.c b/Source/CursesDialog/form/fty_int.c
index 7107fcc..7aeb4b8 100644
--- a/Source/CursesDialog/form/fty_int.c
+++ b/Source/CursesDialog/form/fty_int.c
@@ -117,7 +117,7 @@ static bool Check_Integer_Field(FIELD * field, const void * argp)
{
if (val<low || val>high) return FALSE;
}
- sprintf(buf,"%.*ld",(prec>0?prec:0),val);
+ snprintf(buf,sizeof(buf),"%.*ld",(prec>0?prec:0),val);
set_field_buffer(field,0,buf);
return TRUE;
}
diff --git a/Source/CursesDialog/form/fty_num.c b/Source/CursesDialog/form/fty_num.c
index 7809599..4109b6f 100644
--- a/Source/CursesDialog/form/fty_num.c
+++ b/Source/CursesDialog/form/fty_num.c
@@ -140,7 +140,7 @@ static bool Check_Numeric_Field(FIELD * field, const void * argp)
{
if (val<low || val>high) return FALSE;
}
- sprintf(buf,"%.*f",(prec>0?prec:0),val);
+ snprintf(buf,sizeof(buf),"%.*f",(prec>0?prec:0),val);
set_field_buffer(field,0,buf);
return TRUE;
}
diff --git a/Source/LexerParser/cmFortranLexer.cxx b/Source/LexerParser/cmFortranLexer.cxx
index c3d0000..5703de1 100644
--- a/Source/LexerParser/cmFortranLexer.cxx
+++ b/Source/LexerParser/cmFortranLexer.cxx
@@ -557,31 +557,32 @@ struct yy_trans_info
flex_int32_t yy_verify;
flex_int32_t yy_nxt;
};
-static const flex_int16_t yy_accept[210] =
+static const flex_int16_t yy_accept[216] =
{ 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
55, 49, 51, 50, 53, 1, 49, 33, 2, 47,
48, 35, 37, 50, 39, 49, 46, 46, 46, 46,
- 46, 46, 49, 46, 51, 49, 50, 49, 46, 9,
- 8, 9, 4, 3, 49, 0, 10, 0, 0, 0,
- 0, 0, 33, 33, 34, 36, 39, 49, 46, 46,
- 46, 46, 46, 46, 0, 52, 46, 0, 0, 0,
- 12, 0, 0, 0, 0, 0, 0, 49, 0, 11,
- 46, 0, 0, 5, 0, 0, 0, 0, 29, 0,
- 33, 33, 33, 33, 0, 0, 40, 46, 46, 46,
-
- 46, 45, 12, 12, 0, 0, 0, 23, 0, 0,
- 0, 0, 0, 0, 6, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 46, 46, 46, 46, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 30, 31, 0, 0, 0, 0, 0, 46, 46,
- 46, 46, 0, 24, 25, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 20, 32, 27, 0, 0, 0,
- 46, 46, 43, 46, 0, 26, 21, 0, 0, 0,
- 19, 0, 0, 18, 28, 0, 0, 41, 46, 46,
- 17, 22, 0, 7, 38, 7, 15, 0, 46, 46,
-
- 14, 16, 42, 44, 0, 0, 0, 13, 0
+ 46, 46, 49, 46, 51, 49, 50, 51, 49, 46,
+ 9, 8, 9, 9, 4, 3, 49, 0, 10, 0,
+ 0, 0, 0, 0, 33, 33, 34, 36, 39, 49,
+ 46, 46, 46, 46, 46, 46, 0, 52, 0, 46,
+ 0, 0, 0, 12, 0, 0, 0, 0, 0, 0,
+ 0, 49, 0, 11, 46, 0, 0, 0, 5, 0,
+ 0, 0, 0, 0, 29, 0, 33, 33, 33, 33,
+
+ 0, 0, 40, 46, 46, 46, 46, 45, 12, 12,
+ 0, 0, 0, 23, 0, 0, 0, 0, 0, 0,
+ 6, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 46, 46, 46, 46, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 30, 31, 0,
+ 0, 0, 0, 0, 46, 46, 46, 46, 0, 24,
+ 25, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 20, 32, 27, 0, 0, 0, 46, 46, 43, 46,
+ 0, 26, 21, 0, 0, 0, 19, 0, 0, 18,
+ 28, 0, 0, 41, 46, 46, 17, 22, 0, 7,
+
+ 38, 7, 15, 0, 46, 46, 14, 16, 42, 44,
+ 0, 0, 0, 13, 0
} ;
static const YY_CHAR yy_ec[256] =
@@ -618,189 +619,197 @@ static const YY_CHAR yy_ec[256] =
static const YY_CHAR yy_meta[50] =
{ 0,
- 1, 2, 2, 3, 4, 3, 3, 1, 1, 3,
- 3, 3, 3, 1, 3, 5, 3, 3, 1, 3,
+ 1, 2, 2, 2, 3, 4, 4, 1, 1, 4,
+ 4, 4, 4, 1, 4, 5, 4, 4, 1, 4,
6, 1, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 1, 5,
7, 7, 7, 7, 7, 7, 7, 7, 7
} ;
-static const flex_int16_t yy_base[219] =
+static const flex_int16_t yy_base[225] =
{ 0,
- 0, 48, 0, 49, 464, 56, 52, 57, 62, 68,
- 466, 0, 468, 468, 462, 468, 74, 81, 468, 468,
- 468, 468, 447, 468, 442, 440, 0, 19, 41, 427,
- 47, 41, 90, 119, 97, 158, 455, 207, 247, 468,
- 454, 101, 468, 468, 0, 455, 468, 105, 430, 423,
- 62, 67, 119, 151, 468, 468, 468, 121, 0, 90,
- 93, 110, 431, 112, 142, 468, 0, 160, 295, 0,
- 162, 411, 123, 102, 408, 405, 446, 344, 447, 468,
- 0, 444, 170, 174, 420, 421, 132, 404, 95, 404,
- 180, 186, 192, 228, 297, 397, 0, 168, 144, 52,
-
- 411, 0, 204, 217, 397, 179, 390, 170, 389, 378,
- 364, 390, 389, 230, 468, 363, 355, 337, 337, 334,
- 335, 335, 330, 334, 187, 339, 267, 339, 327, 327,
- 327, 324, 325, 325, 318, 319, 318, 354, 352, 323,
- 327, 468, 468, 310, 307, 305, 297, 297, 275, 275,
- 277, 279, 287, 468, 468, 286, 283, 273, 196, 307,
- 200, 238, 234, 210, 468, 468, 468, 174, 171, 162,
- 279, 182, 0, 269, 150, 468, 468, 137, 109, 323,
- 468, 239, 0, 468, 468, 72, 71, 0, 283, 283,
- 468, 468, 51, 468, 468, 468, 468, 37, 283, 288,
-
- 330, 468, 0, 0, 331, 0, 52, 468, 468, 384,
- 391, 397, 400, 407, 414, 421, 428, 435
+ 0, 48, 0, 49, 55, 58, 64, 66, 75, 83,
+ 491, 0, 492, 492, 487, 492, 86, 92, 492, 492,
+ 492, 492, 472, 492, 467, 465, 0, 56, 59, 452,
+ 66, 16, 105, 131, 109, 170, 480, 481, 219, 259,
+ 492, 478, 479, 116, 492, 492, 0, 478, 492, 111,
+ 453, 446, 34, 78, 155, 174, 492, 492, 492, 121,
+ 0, 29, 105, 101, 454, 101, 131, 492, 474, 0,
+ 180, 307, 0, 146, 433, 117, 94, 430, 427, 468,
+ 467, 356, 468, 492, 0, 465, 464, 187, 191, 465,
+ 439, 440, 149, 423, 126, 423, 200, 240, 311, 322,
+
+ 206, 416, 0, 152, 180, 176, 430, 0, 216, 224,
+ 417, 186, 418, 127, 418, 411, 415, 451, 450, 247,
+ 492, 423, 416, 398, 393, 373, 364, 364, 359, 353,
+ 198, 358, 178, 358, 346, 346, 346, 343, 344, 344,
+ 338, 340, 339, 376, 374, 343, 346, 492, 492, 329,
+ 325, 324, 313, 315, 211, 211, 291, 293, 313, 492,
+ 492, 314, 304, 304, 261, 328, 212, 249, 243, 203,
+ 492, 492, 492, 173, 158, 150, 293, 172, 0, 273,
+ 144, 492, 492, 137, 125, 335, 492, 339, 0, 492,
+ 492, 112, 63, 0, 304, 300, 492, 492, 58, 492,
+
+ 492, 492, 492, 30, 311, 312, 361, 492, 0, 0,
+ 366, 0, 44, 492, 492, 396, 403, 409, 412, 419,
+ 426, 433, 440, 447
} ;
-static const flex_int16_t yy_def[219] =
+static const flex_int16_t yy_def[225] =
{ 0,
- 209, 1, 1, 1, 1, 1, 210, 210, 210, 210,
- 209, 211, 209, 209, 212, 209, 211, 209, 209, 209,
- 209, 209, 209, 209, 209, 211, 213, 213, 213, 213,
- 213, 213, 211, 213, 209, 211, 209, 214, 209, 209,
- 209, 209, 209, 209, 211, 212, 209, 209, 209, 209,
- 209, 209, 209, 215, 209, 209, 209, 211, 213, 213,
- 213, 213, 213, 213, 209, 209, 34, 209, 209, 69,
- 211, 209, 209, 209, 209, 209, 209, 214, 214, 209,
- 39, 209, 209, 209, 209, 209, 209, 209, 209, 209,
- 215, 215, 215, 215, 209, 209, 213, 213, 213, 213,
-
- 213, 213, 209, 209, 209, 209, 209, 209, 209, 209,
- 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
- 209, 209, 209, 209, 213, 213, 213, 213, 209, 209,
- 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
- 209, 209, 209, 209, 209, 209, 209, 209, 213, 213,
- 213, 213, 209, 209, 209, 209, 209, 209, 209, 209,
- 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
- 213, 213, 213, 213, 209, 209, 209, 209, 209, 209,
- 209, 216, 217, 209, 209, 209, 209, 213, 213, 213,
- 209, 209, 209, 209, 209, 209, 209, 209, 213, 213,
-
- 209, 209, 213, 213, 209, 218, 218, 209, 0, 209,
- 209, 209, 209, 209, 209, 209, 209, 209
+ 215, 1, 1, 1, 1, 1, 216, 216, 216, 216,
+ 215, 217, 215, 215, 218, 215, 217, 215, 215, 215,
+ 215, 215, 215, 215, 215, 217, 219, 219, 219, 219,
+ 219, 219, 217, 219, 215, 217, 215, 215, 220, 215,
+ 215, 215, 215, 215, 215, 215, 217, 218, 215, 215,
+ 215, 215, 215, 215, 215, 221, 215, 215, 215, 217,
+ 219, 219, 219, 219, 219, 219, 215, 215, 215, 34,
+ 215, 215, 72, 217, 215, 215, 215, 215, 215, 215,
+ 215, 220, 220, 215, 40, 215, 215, 215, 215, 215,
+ 215, 215, 215, 215, 215, 215, 221, 221, 221, 221,
+
+ 215, 215, 219, 219, 219, 219, 219, 219, 215, 215,
+ 215, 215, 215, 215, 215, 215, 215, 215, 215, 215,
+ 215, 215, 215, 215, 215, 215, 215, 215, 215, 215,
+ 219, 219, 219, 219, 215, 215, 215, 215, 215, 215,
+ 215, 215, 215, 215, 215, 215, 215, 215, 215, 215,
+ 215, 215, 215, 215, 219, 219, 219, 219, 215, 215,
+ 215, 215, 215, 215, 215, 215, 215, 215, 215, 215,
+ 215, 215, 215, 215, 215, 215, 219, 219, 219, 219,
+ 215, 215, 215, 215, 215, 215, 215, 222, 223, 215,
+ 215, 215, 215, 219, 219, 219, 215, 215, 215, 215,
+
+ 215, 215, 215, 215, 219, 219, 215, 215, 219, 219,
+ 215, 224, 224, 215, 0, 215, 215, 215, 215, 215,
+ 215, 215, 215, 215
} ;
-static const flex_int16_t yy_nxt[518] =
+static const flex_int16_t yy_nxt[542] =
{ 0,
12, 13, 14, 13, 13, 15, 16, 12, 17, 18,
19, 20, 21, 12, 22, 12, 23, 24, 12, 25,
12, 26, 27, 27, 27, 27, 28, 27, 27, 29,
27, 30, 27, 27, 27, 31, 27, 32, 33, 34,
27, 27, 28, 27, 29, 27, 27, 31, 32, 35,
- 35, 60, 35, 35, 41, 36, 36, 35, 37, 41,
- 35, 42, 43, 36, 41, 60, 42, 43, 44, 38,
- 41, 42, 208, 61, 44, 48, 64, 42, 48, 202,
- 39, 39, 53, 53, 63, 53, 54, 61, 64, 127,
- 55, 65, 66, 201, 65, 63, 39, 39, 68, 49,
-
- 127, 68, 83, 84, 69, 83, 48, 87, 88, 48,
- 89, 50, 198, 90, 197, 97, 51, 98, 52, 45,
- 53, 53, 95, 53, 54, 95, 45, 45, 55, 99,
- 49, 97, 45, 98, 67, 100, 121, 45, 102, 45,
- 45, 122, 50, 65, 66, 108, 65, 51, 109, 52,
- 193, 100, 92, 53, 102, 92, 93, 45, 67, 70,
- 94, 68, 70, 104, 68, 96, 104, 69, 106, 107,
- 126, 83, 84, 71, 83, 114, 118, 71, 114, 119,
- 192, 92, 53, 115, 92, 93, 126, 92, 53, 94,
- 92, 93, 191, 92, 53, 94, 92, 93, 125, 72,
-
- 73, 94, 74, 75, 189, 104, 76, 78, 104, 80,
- 187, 133, 186, 125, 78, 78, 134, 185, 104, 103,
- 78, 104, 78, 130, 149, 78, 131, 78, 78, 92,
- 53, 114, 92, 93, 114, 149, 184, 94, 183, 115,
- 195, 195, 182, 181, 179, 78, 78, 79, 79, 80,
- 79, 79, 79, 79, 79, 79, 79, 79, 79, 79,
- 79, 79, 81, 79, 79, 79, 79, 79, 79, 81,
- 81, 81, 81, 81, 81, 81, 81, 81, 81, 81,
- 81, 81, 81, 81, 81, 79, 81, 81, 81, 81,
- 81, 81, 81, 81, 81, 81, 70, 151, 95, 70,
-
- 171, 95, 172, 173, 174, 188, 190, 199, 180, 203,
- 103, 180, 151, 200, 204, 178, 171, 190, 172, 173,
- 174, 188, 103, 199, 180, 203, 177, 180, 200, 176,
- 204, 205, 205, 175, 205, 205, 72, 73, 103, 74,
- 75, 96, 170, 76, 78, 169, 80, 168, 206, 206,
- 167, 78, 78, 166, 165, 164, 163, 78, 162, 78,
- 161, 160, 78, 159, 78, 78, 158, 157, 156, 155,
- 154, 153, 152, 150, 148, 147, 146, 145, 144, 143,
- 142, 141, 78, 78, 40, 40, 40, 40, 40, 40,
- 40, 45, 140, 139, 138, 45, 45, 46, 46, 46,
-
- 46, 46, 46, 46, 59, 137, 59, 79, 79, 79,
- 79, 79, 79, 79, 91, 91, 91, 91, 91, 91,
- 91, 194, 194, 194, 136, 194, 194, 194, 196, 135,
- 196, 132, 196, 196, 196, 207, 207, 207, 207, 207,
- 129, 207, 128, 124, 123, 120, 117, 116, 113, 80,
- 112, 111, 110, 105, 101, 86, 85, 47, 82, 77,
- 62, 58, 57, 56, 47, 209, 37, 11, 209, 209,
- 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
- 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
- 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
-
- 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
- 209, 209, 209, 209, 209, 209, 209
+ 35, 66, 35, 35, 103, 36, 36, 37, 38, 35,
+ 37, 38, 35, 66, 214, 36, 42, 43, 42, 43,
+ 103, 39, 208, 44, 45, 44, 45, 42, 43, 93,
+ 94, 46, 40, 40, 44, 42, 43, 50, 62, 46,
+ 50, 63, 44, 55, 55, 55, 55, 56, 40, 40,
+
+ 207, 57, 62, 65, 204, 63, 67, 68, 69, 67,
+ 71, 51, 50, 71, 65, 50, 72, 88, 89, 90,
+ 88, 95, 101, 52, 96, 101, 106, 108, 53, 104,
+ 54, 47, 67, 68, 69, 67, 51, 114, 47, 47,
+ 115, 105, 106, 108, 47, 104, 70, 110, 52, 47,
+ 110, 47, 47, 53, 203, 54, 55, 55, 55, 55,
+ 56, 74, 112, 113, 57, 102, 199, 127, 139, 47,
+ 70, 73, 128, 140, 73, 98, 55, 98, 98, 99,
+ 198, 71, 131, 100, 71, 74, 197, 72, 88, 89,
+ 90, 88, 120, 124, 195, 120, 125, 131, 193, 192,
+
+ 121, 98, 55, 98, 98, 99, 132, 101, 157, 100,
+ 101, 75, 76, 133, 77, 78, 191, 110, 79, 82,
+ 110, 84, 132, 157, 133, 110, 82, 82, 110, 190,
+ 136, 109, 82, 137, 82, 155, 177, 82, 178, 82,
+ 82, 98, 55, 98, 98, 99, 155, 189, 120, 100,
+ 102, 120, 177, 188, 178, 187, 121, 82, 82, 83,
+ 83, 84, 83, 83, 83, 83, 83, 83, 83, 83,
+ 83, 83, 83, 83, 85, 83, 83, 83, 83, 83,
+ 83, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+ 85, 85, 85, 85, 85, 85, 85, 83, 85, 85,
+
+ 85, 85, 85, 85, 85, 85, 85, 85, 73, 185,
+ 196, 73, 98, 55, 98, 98, 99, 179, 180, 194,
+ 100, 196, 109, 98, 55, 98, 98, 99, 205, 186,
+ 206, 100, 186, 179, 180, 194, 186, 209, 210, 186,
+ 201, 201, 201, 109, 205, 206, 184, 183, 75, 76,
+ 109, 77, 78, 209, 210, 79, 82, 182, 84, 181,
+ 176, 175, 211, 82, 82, 211, 174, 211, 173, 82,
+ 211, 82, 172, 171, 82, 170, 82, 82, 169, 212,
+ 168, 167, 166, 165, 212, 164, 163, 162, 161, 160,
+ 159, 158, 156, 154, 82, 82, 41, 41, 41, 41,
+
+ 41, 41, 41, 47, 153, 152, 151, 47, 47, 48,
+ 48, 48, 48, 48, 48, 48, 61, 150, 61, 83,
+ 83, 83, 83, 83, 83, 83, 97, 97, 97, 97,
+ 97, 97, 97, 200, 200, 149, 200, 200, 200, 200,
+ 202, 148, 147, 202, 202, 202, 202, 213, 213, 213,
+ 213, 213, 146, 213, 145, 144, 143, 142, 141, 138,
+ 135, 134, 130, 129, 126, 123, 122, 89, 86, 119,
+ 84, 80, 118, 117, 116, 111, 68, 107, 92, 91,
+ 49, 87, 86, 81, 80, 64, 60, 59, 58, 49,
+ 215, 11, 215, 215, 215, 215, 215, 215, 215, 215,
+
+ 215, 215, 215, 215, 215, 215, 215, 215, 215, 215,
+ 215, 215, 215, 215, 215, 215, 215, 215, 215, 215,
+ 215, 215, 215, 215, 215, 215, 215, 215, 215, 215,
+ 215, 215, 215, 215, 215, 215, 215, 215, 215, 215,
+ 215
} ;
-static const flex_int16_t yy_chk[518] =
+static const flex_int16_t yy_chk[542] =
{ 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
- 4, 28, 2, 4, 7, 2, 4, 6, 6, 8,
- 6, 7, 7, 6, 9, 28, 8, 8, 9, 6,
- 10, 9, 207, 29, 10, 17, 32, 10, 17, 198,
- 6, 6, 18, 18, 31, 18, 18, 29, 32, 100,
- 18, 33, 33, 193, 33, 31, 6, 6, 35, 17,
-
- 100, 35, 42, 42, 35, 42, 48, 51, 51, 48,
- 52, 17, 187, 52, 186, 60, 17, 61, 17, 34,
- 53, 53, 58, 53, 53, 58, 34, 34, 53, 61,
- 48, 60, 34, 61, 34, 62, 89, 34, 64, 34,
- 34, 89, 48, 65, 65, 74, 65, 48, 74, 48,
- 179, 62, 54, 54, 64, 54, 54, 34, 34, 36,
- 54, 68, 36, 71, 68, 58, 71, 68, 73, 73,
- 99, 83, 83, 36, 83, 84, 87, 71, 84, 87,
- 178, 91, 91, 84, 91, 91, 99, 92, 92, 91,
- 92, 92, 175, 93, 93, 92, 93, 93, 98, 36,
-
- 36, 93, 36, 36, 172, 103, 36, 38, 103, 38,
- 170, 108, 169, 98, 38, 38, 108, 168, 104, 103,
- 38, 104, 38, 106, 125, 38, 106, 38, 38, 94,
- 94, 114, 94, 94, 114, 125, 164, 94, 163, 114,
- 182, 182, 162, 161, 159, 38, 38, 39, 39, 39,
- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
- 39, 39, 39, 39, 39, 39, 69, 127, 95, 69,
-
- 149, 95, 150, 151, 152, 171, 174, 189, 160, 199,
- 69, 160, 127, 190, 200, 158, 149, 174, 150, 151,
- 152, 171, 160, 189, 180, 199, 157, 180, 190, 156,
- 200, 201, 205, 153, 201, 205, 69, 69, 180, 69,
- 69, 95, 148, 69, 78, 147, 78, 146, 201, 205,
- 145, 78, 78, 144, 141, 140, 139, 78, 138, 78,
- 137, 136, 78, 135, 78, 78, 134, 133, 132, 131,
- 130, 129, 128, 126, 124, 123, 122, 121, 120, 119,
- 118, 117, 78, 78, 210, 210, 210, 210, 210, 210,
- 210, 211, 116, 113, 112, 211, 211, 212, 212, 212,
-
- 212, 212, 212, 212, 213, 111, 213, 214, 214, 214,
- 214, 214, 214, 214, 215, 215, 215, 215, 215, 215,
- 215, 216, 216, 216, 110, 216, 216, 216, 217, 109,
- 217, 107, 217, 217, 217, 218, 218, 218, 218, 218,
- 105, 218, 101, 96, 90, 88, 86, 85, 82, 79,
- 77, 76, 75, 72, 63, 50, 49, 46, 41, 37,
- 30, 26, 25, 23, 15, 11, 5, 209, 209, 209,
- 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
- 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
- 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
-
- 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
- 209, 209, 209, 209, 209, 209, 209
+ 4, 32, 2, 4, 62, 2, 4, 5, 5, 6,
+ 6, 6, 6, 32, 213, 6, 7, 7, 8, 8,
+ 62, 6, 204, 7, 7, 8, 8, 9, 9, 53,
+ 53, 9, 6, 6, 9, 10, 10, 17, 28, 10,
+ 17, 29, 10, 18, 18, 18, 18, 18, 6, 6,
+
+ 199, 18, 28, 31, 193, 29, 33, 33, 33, 33,
+ 35, 17, 50, 35, 31, 50, 35, 44, 44, 44,
+ 44, 54, 60, 17, 54, 60, 64, 66, 17, 63,
+ 17, 34, 67, 67, 67, 67, 50, 77, 34, 34,
+ 77, 63, 64, 66, 34, 63, 34, 74, 50, 34,
+ 74, 34, 34, 50, 192, 50, 55, 55, 55, 55,
+ 55, 74, 76, 76, 55, 60, 185, 95, 114, 34,
+ 34, 36, 95, 114, 36, 56, 56, 56, 56, 56,
+ 184, 71, 104, 56, 71, 36, 181, 71, 88, 88,
+ 88, 88, 89, 93, 178, 89, 93, 104, 176, 175,
+
+ 89, 97, 97, 97, 97, 97, 105, 101, 133, 97,
+ 101, 36, 36, 106, 36, 36, 174, 109, 36, 39,
+ 109, 39, 105, 133, 106, 110, 39, 39, 110, 170,
+ 112, 109, 39, 112, 39, 131, 155, 39, 156, 39,
+ 39, 98, 98, 98, 98, 98, 131, 169, 120, 98,
+ 101, 120, 155, 168, 156, 167, 120, 39, 39, 40,
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+
+ 40, 40, 40, 40, 40, 40, 40, 40, 72, 165,
+ 180, 72, 99, 99, 99, 99, 99, 157, 158, 177,
+ 99, 180, 72, 100, 100, 100, 100, 100, 195, 166,
+ 196, 100, 166, 157, 158, 177, 186, 205, 206, 186,
+ 188, 188, 188, 166, 195, 196, 164, 163, 72, 72,
+ 186, 72, 72, 205, 206, 72, 82, 162, 82, 159,
+ 154, 153, 207, 82, 82, 207, 152, 211, 151, 82,
+ 211, 82, 150, 147, 82, 146, 82, 82, 145, 207,
+ 144, 143, 142, 141, 211, 140, 139, 138, 137, 136,
+ 135, 134, 132, 130, 82, 82, 216, 216, 216, 216,
+
+ 216, 216, 216, 217, 129, 128, 127, 217, 217, 218,
+ 218, 218, 218, 218, 218, 218, 219, 126, 219, 220,
+ 220, 220, 220, 220, 220, 220, 221, 221, 221, 221,
+ 221, 221, 221, 222, 222, 125, 222, 222, 222, 222,
+ 223, 124, 123, 223, 223, 223, 223, 224, 224, 224,
+ 224, 224, 122, 224, 119, 118, 117, 116, 115, 113,
+ 111, 107, 102, 96, 94, 92, 91, 90, 87, 86,
+ 83, 81, 80, 79, 78, 75, 69, 65, 52, 51,
+ 48, 43, 42, 38, 37, 30, 26, 25, 23, 15,
+ 11, 215, 215, 215, 215, 215, 215, 215, 215, 215,
+
+ 215, 215, 215, 215, 215, 215, 215, 215, 215, 215,
+ 215, 215, 215, 215, 215, 215, 215, 215, 215, 215,
+ 215, 215, 215, 215, 215, 215, 215, 215, 215, 215,
+ 215, 215, 215, 215, 215, 215, 215, 215, 215, 215,
+ 215
} ;
/* The intent behind this definition is that it'll catch
@@ -1139,13 +1148,13 @@ yy_match:
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
- if ( yy_current_state >= 210 )
+ if ( yy_current_state >= 216 )
yy_c = yy_meta[yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
++yy_cp;
}
- while ( yy_base[yy_current_state] != 468 );
+ while ( yy_base[yy_current_state] != 492 );
yy_find_action:
yy_act = yy_accept[yy_current_state];
@@ -1733,7 +1742,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
- if ( yy_current_state >= 210 )
+ if ( yy_current_state >= 216 )
yy_c = yy_meta[yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
@@ -1762,11 +1771,11 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
- if ( yy_current_state >= 210 )
+ if ( yy_current_state >= 216 )
yy_c = yy_meta[yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
- yy_is_jam = (yy_current_state == 209);
+ yy_is_jam = (yy_current_state == 215);
(void)yyg;
return yy_is_jam ? 0 : yy_current_state;
diff --git a/Source/LexerParser/cmFortranLexer.in.l b/Source/LexerParser/cmFortranLexer.in.l
index 05769a1..fac3181 100644
--- a/Source/LexerParser/cmFortranLexer.in.l
+++ b/Source/LexerParser/cmFortranLexer.in.l
@@ -75,10 +75,10 @@ Modify cmFortranLexer.cxx:
return STRING;
}
-<str_dq,str_sq>&[ \t]*\n |
-<str_dq,str_sq>&[ \t]*\n[ \t]*& /* Ignore (continued strings, free fmt) */
+<str_dq,str_sq>&[ \t]*\r?\n |
+<str_dq,str_sq>&[ \t]*\r?\n[ \t]*& /* Ignore (continued strings, free fmt) */
-<fixed_fmt,str_dq,str_sq>\n[ ]{5}[^ \t\n] {
+<fixed_fmt,str_dq,str_sq>\r?\n[ ]{5}[^ \t\r\n] {
if (cmFortranParser_GetOldStartcond(yyextra) == fixed_fmt)
; /* Ignore (cont. strings, fixed fmt) */
else
@@ -132,15 +132,15 @@ $[ \t]*else { return F90PPR_ELSE; }
$[ \t]*endif { return F90PPR_ENDIF; }
/* Line continuations, possible involving comments. */
-&([ \t\n]*|!.*)*
-&([ \t\n]*|!.*)*&
+&([ \t\r\n]*|!.*)*
+&([ \t\r\n]*|!.*)*&
, { return COMMA; }
:: { return DCOLON; }
: { return COLON; }
-<fixed_fmt>\n[ ]{5}[^ ] { return GARBAGE; }
+<fixed_fmt>\r?\n[ ]{5}[^ ] { return GARBAGE; }
=|=> { return ASSIGNMENT_OP; }
@@ -159,13 +159,13 @@ $[ \t]*endif { return F90PPR_ENDIF; }
\( { return LPAREN; }
\) { return RPAREN; }
-[^ \t\n\r:;,!'"a-zA-Z=&()]+ { return GARBAGE; }
+[^ \t\r\n:;,!'"a-zA-Z=&()]+ { return GARBAGE; }
;|\n { return EOSTMT; }
[ \t\r,] /* Ignore */
-\\[ \t]*\n /* Ignore line-endings preceded by \ */
+\\[ \t]*\r?\n /* Ignore line-endings preceded by \ */
. { return *yytext; }
diff --git a/Source/LexerParser/cmFortranParser.cxx b/Source/LexerParser/cmFortranParser.cxx
index b177296..5e5cc0b 100644
--- a/Source/LexerParser/cmFortranParser.cxx
+++ b/Source/LexerParser/cmFortranParser.cxx
@@ -548,7 +548,7 @@ union yyalloc
/* YYFINAL -- State number of the termination state. */
#define YYFINAL 2
/* YYLAST -- Last index in YYTABLE. */
-#define YYLAST 594
+#define YYLAST 432
/* YYNTOKENS -- Number of terminals. */
#define YYNTOKENS 41
@@ -557,7 +557,7 @@ union yyalloc
/* YYNRULES -- Number of rules. */
#define YYNRULES 64
/* YYNSTATES -- Number of states. */
-#define YYNSTATES 127
+#define YYNSTATES 121
/* YYMAXUTOK -- Last valid token kind. */
#define YYMAXUTOK 295
@@ -608,15 +608,15 @@ static const yytype_int8 yytranslate[] =
#if YYDEBUG
/* YYRLINE[YYN] -- Source line where rule number YYN was defined. */
-static const yytype_int16 yyrline[] =
+static const yytype_uint8 yyrline[] =
{
- 0, 106, 106, 106, 109, 113, 118, 127, 133, 140,
- 145, 149, 154, 166, 171, 176, 181, 186, 191, 196,
- 201, 206, 210, 214, 218, 222, 223, 228, 228, 228,
- 229, 229, 230, 230, 231, 231, 232, 232, 233, 233,
- 234, 234, 235, 235, 236, 236, 237, 237, 240, 241,
- 242, 243, 244, 245, 246, 247, 248, 249, 250, 251,
- 252, 253, 254, 255, 256
+ 0, 106, 106, 106, 109, 113, 118, 123, 129, 136,
+ 141, 145, 150, 162, 167, 172, 177, 182, 187, 192,
+ 197, 202, 206, 210, 214, 218, 219, 224, 224, 224,
+ 225, 225, 226, 226, 227, 227, 228, 228, 229, 229,
+ 230, 230, 231, 231, 232, 232, 233, 233, 236, 237,
+ 238, 239, 240, 241, 242, 243, 244, 245, 246, 247,
+ 248, 249, 250, 251, 252
};
#endif
@@ -666,19 +666,19 @@ yysymbol_name (yysymbol_kind_t yysymbol)
STATE-NUM. */
static const yytype_int16 yypact[] =
{
- -39, 21, -39, 1, -39, -20, -39, -39, -39, -39,
+ -39, 21, -39, 5, -39, -23, -39, -39, -39, -39,
-39, -39, -39, -39, -39, -39, -39, -39, -39, -39,
- -39, -39, -39, -39, -39, -39, -24, -18, 20, -8,
- -3, 40, -39, 15, 16, 17, 19, 34, -39, -39,
- -39, -39, -39, -39, 59, -39, -39, -39, -39, -39,
- 36, 37, 38, -39, -39, -39, -39, -39, -39, 77,
- 115, 130, 168, 183, -39, -39, -39, -39, -39, -39,
+ -39, -39, -39, -39, -39, -39, -25, -19, 20, -8,
+ -15, -22, -39, -6, 14, 15, 16, 17, -39, -39,
+ -39, -39, -39, -39, 59, 49, 51, -39, 63, 64,
+ 35, 36, 37, -39, -39, -39, -39, -39, -39, 74,
+ 112, 127, 165, 180, -39, -39, -39, -39, -39, -39,
-39, -39, -39, -39, -39, -39, -39, -39, -39, -39,
- -39, -39, -39, 221, 236, 274, 289, -21, 26, -39,
- 327, 342, 380, 395, 433, 448, -39, -39, -39, -39,
- -39, -39, -39, -39, -39, 39, 41, 42, 486, -39,
- -39, -39, -39, -39, -39, 18, -39, -39, -39, 43,
- 501, 539, -39, -39, -39, 554, -39
+ -39, -39, -39, -39, -39, -39, -39, -20, 43, -39,
+ 218, 233, 271, 286, 324, 339, -39, -39, -39, -39,
+ -39, 39, 40, 41, 377, -39, -39, -39, -39, -39,
+ -39, 46, 78, -39, -39, 50, -39, 392, 79, -39,
+ -39
};
/* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
@@ -690,15 +690,15 @@ static const yytype_int8 yydefact[] =
30, 33, 32, 34, 36, 38, 42, 40, 44, 35,
37, 39, 43, 41, 45, 46, 0, 0, 0, 0,
0, 0, 3, 0, 0, 0, 0, 0, 46, 46,
- 46, 46, 26, 46, 0, 46, 46, 4, 46, 46,
+ 46, 46, 26, 46, 0, 0, 0, 4, 0, 0,
0, 0, 0, 46, 46, 46, 46, 46, 46, 0,
0, 0, 0, 0, 15, 57, 56, 64, 62, 58,
59, 60, 61, 63, 55, 48, 49, 50, 51, 52,
- 53, 54, 47, 0, 0, 0, 0, 0, 0, 46,
+ 53, 54, 47, 10, 13, 9, 6, 0, 0, 46,
0, 0, 0, 0, 0, 0, 21, 22, 23, 24,
- 14, 10, 13, 9, 6, 0, 0, 0, 0, 5,
- 16, 17, 18, 19, 20, 0, 46, 46, 11, 0,
- 0, 0, 46, 7, 12, 0, 8
+ 14, 0, 0, 0, 0, 5, 16, 17, 18, 19,
+ 20, 0, 0, 46, 11, 0, 7, 0, 0, 12,
+ 8
};
/* YYPGOTO[NTERM-NUM]. */
@@ -720,81 +720,70 @@ static const yytype_int8 yydefgoto[] =
number is the opposite. If YYTABLE_NINF, syntax error. */
static const yytype_int8 yytable[] =
{
- 59, 60, 61, 62, 42, 63, 105, 83, 84, 106,
- 85, 86, 43, 45, 46, 90, 91, 92, 93, 94,
- 95, 2, 3, 47, 4, 49, 50, 5, 6, 7,
+ 59, 60, 61, 62, 51, 63, 52, 101, 42, 43,
+ 102, 53, 45, 46, 50, 90, 91, 92, 93, 94,
+ 95, 2, 3, 47, 4, 49, 54, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
- 18, 19, 20, 21, 22, 23, 24, 54, 119, 55,
- 56, 108, 57, 48, 107, 25, 26, 27, 28, 29,
- 30, 31, 64, 65, 66, 67, 51, 58, 52, 87,
- 88, 89, 115, 53, 116, 117, 122, 0, 120, 121,
- 96, 65, 66, 67, 125, 68, 69, 70, 71, 72,
+ 18, 19, 20, 21, 22, 23, 24, 55, 56, 57,
+ 58, 104, 83, 48, 84, 25, 26, 27, 28, 29,
+ 30, 31, 64, 65, 66, 67, 85, 86, 87, 88,
+ 89, 103, 111, 112, 113, 117, 115, 96, 65, 66,
+ 67, 116, 120, 118, 0, 68, 69, 70, 71, 72,
73, 74, 75, 0, 76, 77, 78, 79, 80, 81,
- 0, 0, 0, 68, 69, 70, 71, 72, 73, 74,
- 75, 0, 76, 77, 78, 79, 80, 81, 97, 65,
+ 68, 69, 70, 71, 72, 73, 74, 75, 0, 76,
+ 77, 78, 79, 80, 81, 97, 65, 66, 67, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 98, 65, 66, 67, 0, 0, 0, 0, 68, 69,
+ 70, 71, 72, 73, 74, 75, 0, 76, 77, 78,
+ 79, 80, 81, 68, 69, 70, 71, 72, 73, 74,
+ 75, 0, 76, 77, 78, 79, 80, 81, 99, 65,
66, 67, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 98, 65, 66, 67, 0, 0, 0,
+ 0, 0, 0, 100, 65, 66, 67, 0, 0, 0,
0, 68, 69, 70, 71, 72, 73, 74, 75, 0,
76, 77, 78, 79, 80, 81, 68, 69, 70, 71,
72, 73, 74, 75, 0, 76, 77, 78, 79, 80,
- 81, 99, 65, 66, 67, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 100, 65, 66, 67,
+ 81, 105, 65, 66, 67, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 106, 65, 66, 67,
0, 0, 0, 0, 68, 69, 70, 71, 72, 73,
74, 75, 0, 76, 77, 78, 79, 80, 81, 68,
69, 70, 71, 72, 73, 74, 75, 0, 76, 77,
- 78, 79, 80, 81, 101, 65, 66, 67, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 102,
+ 78, 79, 80, 81, 107, 65, 66, 67, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 108,
65, 66, 67, 0, 0, 0, 0, 68, 69, 70,
71, 72, 73, 74, 75, 0, 76, 77, 78, 79,
80, 81, 68, 69, 70, 71, 72, 73, 74, 75,
- 0, 76, 77, 78, 79, 80, 81, 103, 65, 66,
+ 0, 76, 77, 78, 79, 80, 81, 109, 65, 66,
67, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 104, 65, 66, 67, 0, 0, 0, 0,
+ 0, 0, 110, 65, 66, 67, 0, 0, 0, 0,
68, 69, 70, 71, 72, 73, 74, 75, 0, 76,
77, 78, 79, 80, 81, 68, 69, 70, 71, 72,
73, 74, 75, 0, 76, 77, 78, 79, 80, 81,
- 109, 65, 66, 67, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 110, 65, 66, 67, 0,
+ 114, 65, 66, 67, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 119, 65, 66, 67, 0,
0, 0, 0, 68, 69, 70, 71, 72, 73, 74,
75, 0, 76, 77, 78, 79, 80, 81, 68, 69,
70, 71, 72, 73, 74, 75, 0, 76, 77, 78,
- 79, 80, 81, 111, 65, 66, 67, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 112, 65,
- 66, 67, 0, 0, 0, 0, 68, 69, 70, 71,
- 72, 73, 74, 75, 0, 76, 77, 78, 79, 80,
- 81, 68, 69, 70, 71, 72, 73, 74, 75, 0,
- 76, 77, 78, 79, 80, 81, 113, 65, 66, 67,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 114, 65, 66, 67, 0, 0, 0, 0, 68,
- 69, 70, 71, 72, 73, 74, 75, 0, 76, 77,
- 78, 79, 80, 81, 68, 69, 70, 71, 72, 73,
- 74, 75, 0, 76, 77, 78, 79, 80, 81, 118,
- 65, 66, 67, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 123, 65, 66, 67, 0, 0,
- 0, 0, 68, 69, 70, 71, 72, 73, 74, 75,
- 0, 76, 77, 78, 79, 80, 81, 68, 69, 70,
- 71, 72, 73, 74, 75, 0, 76, 77, 78, 79,
- 80, 81, 124, 65, 66, 67, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 126, 65, 66,
- 67, 0, 0, 0, 0, 68, 69, 70, 71, 72,
- 73, 74, 75, 0, 76, 77, 78, 79, 80, 81,
- 68, 69, 70, 71, 72, 73, 74, 75, 0, 76,
- 77, 78, 79, 80, 81
+ 79, 80, 81
};
static const yytype_int8 yycheck[] =
{
- 38, 39, 40, 41, 3, 43, 27, 45, 46, 30,
- 48, 49, 32, 37, 32, 53, 54, 55, 56, 57,
- 58, 0, 1, 3, 3, 33, 29, 6, 7, 8,
+ 38, 39, 40, 41, 26, 43, 28, 27, 3, 32,
+ 30, 33, 37, 32, 29, 53, 54, 55, 56, 57,
+ 58, 0, 1, 3, 3, 33, 32, 6, 7, 8,
9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
- 19, 20, 21, 22, 23, 24, 25, 32, 30, 33,
- 33, 89, 33, 33, 28, 34, 35, 36, 37, 38,
- 39, 40, 3, 4, 5, 6, 26, 33, 28, 33,
- 33, 33, 33, 33, 33, 33, 33, -1, 116, 117,
- 3, 4, 5, 6, 122, 26, 27, 28, 29, 30,
+ 19, 20, 21, 22, 23, 24, 25, 33, 33, 33,
+ 33, 89, 3, 33, 3, 34, 35, 36, 37, 38,
+ 39, 40, 3, 4, 5, 6, 3, 3, 33, 33,
+ 33, 28, 33, 33, 33, 113, 30, 3, 4, 5,
+ 6, 3, 3, 33, -1, 26, 27, 28, 29, 30,
31, 32, 33, -1, 35, 36, 37, 38, 39, 40,
- -1, -1, -1, 26, 27, 28, 29, 30, 31, 32,
+ 26, 27, 28, 29, 30, 31, 32, 33, -1, 35,
+ 36, 37, 38, 39, 40, 3, 4, 5, 6, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 3, 4, 5, 6, -1, -1, -1, -1, 26, 27,
+ 28, 29, 30, 31, 32, 33, -1, 35, 36, 37,
+ 38, 39, 40, 26, 27, 28, 29, 30, 31, 32,
33, -1, 35, 36, 37, 38, 39, 40, 3, 4,
5, 6, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, 3, 4, 5, 6, -1, -1, -1,
@@ -822,28 +811,7 @@ static const yytype_int8 yycheck[] =
-1, -1, -1, 26, 27, 28, 29, 30, 31, 32,
33, -1, 35, 36, 37, 38, 39, 40, 26, 27,
28, 29, 30, 31, 32, 33, -1, 35, 36, 37,
- 38, 39, 40, 3, 4, 5, 6, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, 3, 4,
- 5, 6, -1, -1, -1, -1, 26, 27, 28, 29,
- 30, 31, 32, 33, -1, 35, 36, 37, 38, 39,
- 40, 26, 27, 28, 29, 30, 31, 32, 33, -1,
- 35, 36, 37, 38, 39, 40, 3, 4, 5, 6,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, 3, 4, 5, 6, -1, -1, -1, -1, 26,
- 27, 28, 29, 30, 31, 32, 33, -1, 35, 36,
- 37, 38, 39, 40, 26, 27, 28, 29, 30, 31,
- 32, 33, -1, 35, 36, 37, 38, 39, 40, 3,
- 4, 5, 6, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, 3, 4, 5, 6, -1, -1,
- -1, -1, 26, 27, 28, 29, 30, 31, 32, 33,
- -1, 35, 36, 37, 38, 39, 40, 26, 27, 28,
- 29, 30, 31, 32, 33, -1, 35, 36, 37, 38,
- 39, 40, 3, 4, 5, 6, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, 3, 4, 5,
- 6, -1, -1, -1, -1, 26, 27, 28, 29, 30,
- 31, 32, 33, -1, 35, 36, 37, 38, 39, 40,
- 26, 27, 28, 29, 30, 31, 32, 33, -1, 35,
- 36, 37, 38, 39, 40
+ 38, 39, 40
};
/* YYSTOS[STATE-NUM] -- The symbol kind of the accessing symbol of
@@ -858,11 +826,11 @@ static const yytype_int8 yystos[] =
29, 26, 28, 33, 32, 33, 33, 33, 33, 53,
53, 53, 53, 53, 3, 4, 5, 6, 26, 27,
28, 29, 30, 31, 32, 33, 35, 36, 37, 38,
- 39, 40, 54, 53, 53, 53, 53, 33, 33, 33,
+ 39, 40, 54, 3, 3, 3, 3, 33, 33, 33,
53, 53, 53, 53, 53, 53, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 27, 30, 28, 53, 3,
- 3, 3, 3, 3, 3, 33, 33, 33, 3, 30,
- 53, 53, 33, 3, 3, 53, 3
+ 3, 27, 30, 28, 53, 3, 3, 3, 3, 3,
+ 3, 33, 33, 33, 3, 30, 3, 53, 33, 3,
+ 3
};
/* YYR1[RULE-NUM] -- Symbol kind of the left-hand side of rule RULE-NUM. */
@@ -880,8 +848,8 @@ static const yytype_int8 yyr1[] =
/* YYR2[RULE-NUM] -- Number of symbols on the right-hand side of rule RULE-NUM. */
static const yytype_int8 yyr2[] =
{
- 0, 2, 0, 2, 2, 4, 4, 7, 9, 4,
- 4, 5, 7, 4, 4, 3, 4, 4, 4, 4,
+ 0, 2, 0, 2, 2, 4, 3, 6, 8, 3,
+ 3, 5, 7, 3, 4, 3, 4, 4, 4, 4,
4, 3, 3, 3, 3, 1, 2, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 0, 2, 1, 1,
@@ -1361,19 +1329,19 @@ yydestruct (const char *yymsg,
case YYSYMBOL_STRING: /* STRING */
#line 100 "cmFortranParser.y"
{ free(((*yyvaluep).string)); }
-#line 1365 "cmFortranParser.cxx"
+#line 1333 "cmFortranParser.cxx"
break;
case YYSYMBOL_WORD: /* WORD */
#line 100 "cmFortranParser.y"
{ free(((*yyvaluep).string)); }
-#line 1371 "cmFortranParser.cxx"
+#line 1339 "cmFortranParser.cxx"
break;
case YYSYMBOL_CPP_INCLUDE_ANGLE: /* CPP_INCLUDE_ANGLE */
#line 100 "cmFortranParser.y"
{ free(((*yyvaluep).string)); }
-#line 1377 "cmFortranParser.cxx"
+#line 1345 "cmFortranParser.cxx"
break;
default:
@@ -1655,7 +1623,7 @@ yyreduce:
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
cmFortranParser_SetInInterface(parser, true);
}
-#line 1659 "cmFortranParser.cxx"
+#line 1627 "cmFortranParser.cxx"
break;
case 5: /* stmt: USE WORD other EOSTMT */
@@ -1665,77 +1633,73 @@ yyreduce:
cmFortranParser_RuleUse(parser, (yyvsp[-2].string));
free((yyvsp[-2].string));
}
-#line 1669 "cmFortranParser.cxx"
+#line 1637 "cmFortranParser.cxx"
break;
- case 6: /* stmt: MODULE WORD other EOSTMT */
+ case 6: /* stmt: MODULE WORD EOSTMT */
#line 118 "cmFortranParser.y"
- {
+ {
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
- if (cmsysString_strcasecmp((yyvsp[-2].string), "function") != 0 &&
- cmsysString_strcasecmp((yyvsp[-2].string), "procedure") != 0 &&
- cmsysString_strcasecmp((yyvsp[-2].string), "subroutine") != 0) {
- cmFortranParser_RuleModule(parser, (yyvsp[-2].string));
- }
- free((yyvsp[-2].string));
+ cmFortranParser_RuleModule(parser, (yyvsp[-1].string));
+ free((yyvsp[-1].string));
}
-#line 1683 "cmFortranParser.cxx"
+#line 1647 "cmFortranParser.cxx"
break;
- case 7: /* stmt: SUBMODULE LPAREN WORD RPAREN WORD other EOSTMT */
-#line 127 "cmFortranParser.y"
- {
+ case 7: /* stmt: SUBMODULE LPAREN WORD RPAREN WORD EOSTMT */
+#line 123 "cmFortranParser.y"
+ {
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
- cmFortranParser_RuleSubmodule(parser, (yyvsp[-4].string), (yyvsp[-2].string));
- free((yyvsp[-4].string));
- free((yyvsp[-2].string));
+ cmFortranParser_RuleSubmodule(parser, (yyvsp[-3].string), (yyvsp[-1].string));
+ free((yyvsp[-3].string));
+ free((yyvsp[-1].string));
}
-#line 1694 "cmFortranParser.cxx"
+#line 1658 "cmFortranParser.cxx"
break;
- case 8: /* stmt: SUBMODULE LPAREN WORD COLON WORD RPAREN WORD other EOSTMT */
-#line 133 "cmFortranParser.y"
- {
+ case 8: /* stmt: SUBMODULE LPAREN WORD COLON WORD RPAREN WORD EOSTMT */
+#line 129 "cmFortranParser.y"
+ {
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
- cmFortranParser_RuleSubmoduleNested(parser, (yyvsp[-6].string), (yyvsp[-4].string), (yyvsp[-2].string));
- free((yyvsp[-6].string));
- free((yyvsp[-4].string));
- free((yyvsp[-2].string));
+ cmFortranParser_RuleSubmoduleNested(parser, (yyvsp[-5].string), (yyvsp[-3].string), (yyvsp[-1].string));
+ free((yyvsp[-5].string));
+ free((yyvsp[-3].string));
+ free((yyvsp[-1].string));
}
-#line 1706 "cmFortranParser.cxx"
+#line 1670 "cmFortranParser.cxx"
break;
- case 9: /* stmt: INTERFACE WORD other EOSTMT */
-#line 140 "cmFortranParser.y"
- {
+ case 9: /* stmt: INTERFACE WORD EOSTMT */
+#line 136 "cmFortranParser.y"
+ {
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
cmFortranParser_SetInInterface(parser, true);
- free((yyvsp[-2].string));
+ free((yyvsp[-1].string));
}
-#line 1716 "cmFortranParser.cxx"
+#line 1680 "cmFortranParser.cxx"
break;
- case 10: /* stmt: END INTERFACE other EOSTMT */
-#line 145 "cmFortranParser.y"
- {
+ case 10: /* stmt: END INTERFACE EOSTMT */
+#line 141 "cmFortranParser.y"
+ {
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
cmFortranParser_SetInInterface(parser, false);
}
-#line 1725 "cmFortranParser.cxx"
+#line 1689 "cmFortranParser.cxx"
break;
case 11: /* stmt: USE DCOLON WORD other EOSTMT */
-#line 149 "cmFortranParser.y"
+#line 145 "cmFortranParser.y"
{
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
cmFortranParser_RuleUse(parser, (yyvsp[-2].string));
free((yyvsp[-2].string));
}
-#line 1735 "cmFortranParser.cxx"
+#line 1699 "cmFortranParser.cxx"
break;
case 12: /* stmt: USE COMMA WORD DCOLON WORD other EOSTMT */
-#line 154 "cmFortranParser.y"
+#line 150 "cmFortranParser.y"
{
if (cmsysString_strcasecmp((yyvsp[-4].string), "non_intrinsic") == 0) {
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
@@ -1748,139 +1712,139 @@ yyreduce:
free((yyvsp[-4].string));
free((yyvsp[-2].string));
}
-#line 1752 "cmFortranParser.cxx"
+#line 1716 "cmFortranParser.cxx"
break;
- case 13: /* stmt: INCLUDE STRING other EOSTMT */
-#line 166 "cmFortranParser.y"
- {
+ case 13: /* stmt: INCLUDE STRING EOSTMT */
+#line 162 "cmFortranParser.y"
+ {
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
- cmFortranParser_RuleInclude(parser, (yyvsp[-2].string));
- free((yyvsp[-2].string));
+ cmFortranParser_RuleInclude(parser, (yyvsp[-1].string));
+ free((yyvsp[-1].string));
}
-#line 1762 "cmFortranParser.cxx"
+#line 1726 "cmFortranParser.cxx"
break;
case 14: /* stmt: CPP_LINE_DIRECTIVE STRING other EOSTMT */
-#line 171 "cmFortranParser.y"
+#line 167 "cmFortranParser.y"
{
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
cmFortranParser_RuleLineDirective(parser, (yyvsp[-2].string));
free((yyvsp[-2].string));
}
-#line 1772 "cmFortranParser.cxx"
+#line 1736 "cmFortranParser.cxx"
break;
case 15: /* stmt: CPP_INCLUDE_ANGLE other EOSTMT */
-#line 176 "cmFortranParser.y"
+#line 172 "cmFortranParser.y"
{
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
cmFortranParser_RuleInclude(parser, (yyvsp[-2].string));
free((yyvsp[-2].string));
}
-#line 1782 "cmFortranParser.cxx"
+#line 1746 "cmFortranParser.cxx"
break;
case 16: /* stmt: include STRING other EOSTMT */
-#line 181 "cmFortranParser.y"
+#line 177 "cmFortranParser.y"
{
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
cmFortranParser_RuleInclude(parser, (yyvsp[-2].string));
free((yyvsp[-2].string));
}
-#line 1792 "cmFortranParser.cxx"
+#line 1756 "cmFortranParser.cxx"
break;
case 17: /* stmt: define WORD other EOSTMT */
-#line 186 "cmFortranParser.y"
+#line 182 "cmFortranParser.y"
{
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
cmFortranParser_RuleDefine(parser, (yyvsp[-2].string));
free((yyvsp[-2].string));
}
-#line 1802 "cmFortranParser.cxx"
+#line 1766 "cmFortranParser.cxx"
break;
case 18: /* stmt: undef WORD other EOSTMT */
-#line 191 "cmFortranParser.y"
+#line 187 "cmFortranParser.y"
{
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
cmFortranParser_RuleUndef(parser, (yyvsp[-2].string));
free((yyvsp[-2].string));
}
-#line 1812 "cmFortranParser.cxx"
+#line 1776 "cmFortranParser.cxx"
break;
case 19: /* stmt: ifdef WORD other EOSTMT */
-#line 196 "cmFortranParser.y"
+#line 192 "cmFortranParser.y"
{
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
cmFortranParser_RuleIfdef(parser, (yyvsp[-2].string));
free((yyvsp[-2].string));
}
-#line 1822 "cmFortranParser.cxx"
+#line 1786 "cmFortranParser.cxx"
break;
case 20: /* stmt: ifndef WORD other EOSTMT */
-#line 201 "cmFortranParser.y"
+#line 197 "cmFortranParser.y"
{
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
cmFortranParser_RuleIfndef(parser, (yyvsp[-2].string));
free((yyvsp[-2].string));
}
-#line 1832 "cmFortranParser.cxx"
+#line 1796 "cmFortranParser.cxx"
break;
case 21: /* stmt: if other EOSTMT */
-#line 206 "cmFortranParser.y"
+#line 202 "cmFortranParser.y"
{
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
cmFortranParser_RuleIf(parser);
}
-#line 1841 "cmFortranParser.cxx"
+#line 1805 "cmFortranParser.cxx"
break;
case 22: /* stmt: elif other EOSTMT */
-#line 210 "cmFortranParser.y"
+#line 206 "cmFortranParser.y"
{
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
cmFortranParser_RuleElif(parser);
}
-#line 1850 "cmFortranParser.cxx"
+#line 1814 "cmFortranParser.cxx"
break;
case 23: /* stmt: else other EOSTMT */
-#line 214 "cmFortranParser.y"
+#line 210 "cmFortranParser.y"
{
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
cmFortranParser_RuleElse(parser);
}
-#line 1859 "cmFortranParser.cxx"
+#line 1823 "cmFortranParser.cxx"
break;
case 24: /* stmt: endif other EOSTMT */
-#line 218 "cmFortranParser.y"
+#line 214 "cmFortranParser.y"
{
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
cmFortranParser_RuleEndif(parser);
}
-#line 1868 "cmFortranParser.cxx"
+#line 1832 "cmFortranParser.cxx"
break;
case 48: /* misc_code: WORD */
-#line 240 "cmFortranParser.y"
+#line 236 "cmFortranParser.y"
{ free ((yyvsp[0].string)); }
-#line 1874 "cmFortranParser.cxx"
+#line 1838 "cmFortranParser.cxx"
break;
case 55: /* misc_code: STRING */
-#line 247 "cmFortranParser.y"
+#line 243 "cmFortranParser.y"
{ free ((yyvsp[0].string)); }
-#line 1880 "cmFortranParser.cxx"
+#line 1844 "cmFortranParser.cxx"
break;
-#line 1884 "cmFortranParser.cxx"
+#line 1848 "cmFortranParser.cxx"
default: break;
}
@@ -2104,6 +2068,6 @@ yyreturnlab:
return yyresult;
}
-#line 259 "cmFortranParser.y"
+#line 255 "cmFortranParser.y"
/* End of grammar */
diff --git a/Source/LexerParser/cmFortranParser.y b/Source/LexerParser/cmFortranParser.y
index 07ca630..a5c8976 100644
--- a/Source/LexerParser/cmFortranParser.y
+++ b/Source/LexerParser/cmFortranParser.y
@@ -115,34 +115,30 @@ stmt:
cmFortranParser_RuleUse(parser, $2);
free($2);
}
-| MODULE WORD other EOSTMT {
+| MODULE WORD EOSTMT {
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
- if (cmsysString_strcasecmp($2, "function") != 0 &&
- cmsysString_strcasecmp($2, "procedure") != 0 &&
- cmsysString_strcasecmp($2, "subroutine") != 0) {
- cmFortranParser_RuleModule(parser, $2);
- }
+ cmFortranParser_RuleModule(parser, $2);
free($2);
}
-| SUBMODULE LPAREN WORD RPAREN WORD other EOSTMT {
+| SUBMODULE LPAREN WORD RPAREN WORD EOSTMT {
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
cmFortranParser_RuleSubmodule(parser, $3, $5);
free($3);
free($5);
}
-| SUBMODULE LPAREN WORD COLON WORD RPAREN WORD other EOSTMT {
+| SUBMODULE LPAREN WORD COLON WORD RPAREN WORD EOSTMT {
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
cmFortranParser_RuleSubmoduleNested(parser, $3, $5, $7);
free($3);
free($5);
free($7);
}
-| INTERFACE WORD other EOSTMT {
+| INTERFACE WORD EOSTMT {
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
cmFortranParser_SetInInterface(parser, true);
free($2);
}
-| END INTERFACE other EOSTMT {
+| END INTERFACE EOSTMT {
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
cmFortranParser_SetInInterface(parser, false);
}
@@ -163,7 +159,7 @@ stmt:
free($3);
free($5);
}
-| INCLUDE STRING other EOSTMT {
+| INCLUDE STRING EOSTMT {
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
cmFortranParser_RuleInclude(parser, $2);
free($2);
diff --git a/Source/cmArgumentParser.cxx b/Source/cmArgumentParser.cxx
index 4624f1c..ad57a88 100644
--- a/Source/cmArgumentParser.cxx
+++ b/Source/cmArgumentParser.cxx
@@ -4,9 +4,14 @@
#include <algorithm>
+#include "cmArgumentParserTypes.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmStringAlgorithms.h"
+
namespace ArgumentParser {
-auto ActionMap::Emplace(cm::string_view name, Action action)
+auto KeywordActionMap::Emplace(cm::string_view name, KeywordAction action)
-> std::pair<iterator, bool>
{
auto const it =
@@ -19,7 +24,7 @@ auto ActionMap::Emplace(cm::string_view name, Action action)
: std::make_pair(this->emplace(it, name, std::move(action)), true);
}
-auto ActionMap::Find(cm::string_view name) const -> const_iterator
+auto KeywordActionMap::Find(cm::string_view name) const -> const_iterator
{
auto const it =
std::lower_bound(this->begin(), this->end(), name,
@@ -29,68 +34,171 @@ auto ActionMap::Find(cm::string_view name) const -> const_iterator
return (it != this->end() && it->first == name) ? it : this->end();
}
+auto PositionActionMap::Emplace(std::size_t pos, PositionAction action)
+ -> std::pair<iterator, bool>
+{
+ auto const it = std::lower_bound(
+ this->begin(), this->end(), pos,
+ [](value_type const& elem, std::size_t k) { return elem.first < k; });
+ return (it != this->end() && it->first == pos)
+ ? std::make_pair(it, false)
+ : std::make_pair(this->emplace(it, pos, std::move(action)), true);
+}
+
+auto PositionActionMap::Find(std::size_t pos) const -> const_iterator
+{
+ auto const it = std::lower_bound(
+ this->begin(), this->end(), pos,
+ [](value_type const& elem, std::size_t k) { return elem.first < k; });
+ return (it != this->end() && it->first == pos) ? it : this->end();
+}
+
+void Instance::Bind(std::function<Continue(cm::string_view)> f,
+ ExpectAtLeast expect)
+{
+ this->KeywordValueFunc = std::move(f);
+ this->KeywordValuesExpected = expect.Count;
+}
+
void Instance::Bind(bool& val)
{
val = true;
- this->CurrentString = nullptr;
- this->CurrentList = nullptr;
- this->ExpectValue = false;
+ this->Bind(nullptr, ExpectAtLeast{ 0 });
}
void Instance::Bind(std::string& val)
{
- this->CurrentString = &val;
- this->CurrentList = nullptr;
- this->ExpectValue = true;
+ this->Bind(
+ [&val](cm::string_view arg) -> Continue {
+ val = std::string(arg);
+ return Continue::No;
+ },
+ ExpectAtLeast{ 1 });
+}
+
+void Instance::Bind(NonEmpty<std::string>& val)
+{
+ this->Bind(
+ [this, &val](cm::string_view arg) -> Continue {
+ if (arg.empty() && this->ParseResults) {
+ this->ParseResults->AddKeywordError(this->Keyword,
+ " empty string not allowed\n");
+ }
+ val.assign(std::string(arg));
+ return Continue::No;
+ },
+ ExpectAtLeast{ 1 });
}
-void Instance::Bind(StringList& val)
+void Instance::Bind(Maybe<std::string>& val)
{
- this->CurrentString = nullptr;
- this->CurrentList = &val;
- this->ExpectValue = true;
+ this->Bind(
+ [&val](cm::string_view arg) -> Continue {
+ static_cast<std::string&>(val) = std::string(arg);
+ return Continue::No;
+ },
+ ExpectAtLeast{ 0 });
}
-void Instance::Bind(MultiStringList& val)
+void Instance::Bind(MaybeEmpty<std::vector<std::string>>& val)
{
- this->CurrentString = nullptr;
- this->CurrentList = (static_cast<void>(val.emplace_back()), &val.back());
- this->ExpectValue = false;
+ this->Bind(
+ [&val](cm::string_view arg) -> Continue {
+ val.emplace_back(arg);
+ return Continue::Yes;
+ },
+ ExpectAtLeast{ 0 });
}
-void Instance::Consume(cm::string_view arg, void* result,
- std::vector<std::string>* unparsedArguments,
- std::vector<std::string>* keywordsMissingValue,
- std::vector<std::string>* parsedKeywords)
+void Instance::Bind(NonEmpty<std::vector<std::string>>& val)
{
- auto const it = this->Bindings.Find(arg);
- if (it != this->Bindings.end()) {
- if (parsedKeywords != nullptr) {
- parsedKeywords->emplace_back(arg);
+ this->Bind(
+ [&val](cm::string_view arg) -> Continue {
+ val.emplace_back(arg);
+ return Continue::Yes;
+ },
+ ExpectAtLeast{ 1 });
+}
+
+void Instance::Bind(std::vector<std::vector<std::string>>& multiVal)
+{
+ multiVal.emplace_back();
+ std::vector<std::string>& val = multiVal.back();
+ this->Bind(
+ [&val](cm::string_view arg) -> Continue {
+ val.emplace_back(arg);
+ return Continue::Yes;
+ },
+ ExpectAtLeast{ 0 });
+}
+
+void Instance::Consume(std::size_t pos, cm::string_view arg)
+{
+ auto const it = this->Bindings.Keywords.Find(arg);
+ if (it != this->Bindings.Keywords.end()) {
+ this->FinishKeyword();
+ this->Keyword = it->first;
+ this->KeywordValuesSeen = 0;
+ this->DoneWithPositional = true;
+ if (this->Bindings.ParsedKeyword) {
+ this->Bindings.ParsedKeyword(*this, it->first);
}
- it->second(*this, result);
- if (this->ExpectValue && keywordsMissingValue != nullptr) {
- keywordsMissingValue->emplace_back(arg);
+ it->second(*this);
+ return;
+ }
+
+ if (this->KeywordValueFunc) {
+ switch (this->KeywordValueFunc(arg)) {
+ case Continue::Yes:
+ break;
+ case Continue::No:
+ this->KeywordValueFunc = nullptr;
+ break;
}
+ ++this->KeywordValuesSeen;
return;
}
- if (this->CurrentString != nullptr) {
- this->CurrentString->assign(std::string(arg));
- this->CurrentString = nullptr;
- this->CurrentList = nullptr;
- } else if (this->CurrentList != nullptr) {
- this->CurrentList->emplace_back(arg);
- } else if (unparsedArguments != nullptr) {
- unparsedArguments->emplace_back(arg);
+ if (!this->DoneWithPositional) {
+ auto const pit = this->Bindings.Positions.Find(pos);
+ if (pit != this->Bindings.Positions.end()) {
+ pit->second(*this, pos, arg);
+ return;
+ }
+ }
+
+ if (this->UnparsedArguments != nullptr) {
+ this->UnparsedArguments->emplace_back(arg);
}
+}
- if (this->ExpectValue) {
- if (keywordsMissingValue != nullptr) {
- keywordsMissingValue->pop_back();
+void Instance::FinishKeyword()
+{
+ if (this->Keyword.empty()) {
+ return;
+ }
+ if (this->KeywordValuesSeen < this->KeywordValuesExpected) {
+ if (this->ParseResults != nullptr) {
+ this->ParseResults->AddKeywordError(this->Keyword,
+ " missing required value\n");
}
- this->ExpectValue = false;
+ if (this->Bindings.KeywordMissingValue) {
+ this->Bindings.KeywordMissingValue(*this, this->Keyword);
+ }
+ }
+}
+
+bool ParseResult::MaybeReportError(cmMakefile& mf) const
+{
+ if (*this) {
+ return false;
+ }
+ std::string e;
+ for (auto const& ke : this->KeywordErrors) {
+ e = cmStrCat(e, "Error after keyword \"", ke.first, "\":\n", ke.second);
}
+ mf.IssueMessage(MessageType::FATAL_ERROR, e);
+ return true;
}
} // namespace ArgumentParser
diff --git a/Source/cmArgumentParser.h b/Source/cmArgumentParser.h
index 71ed844..fdf54fb 100644
--- a/Source/cmArgumentParser.h
+++ b/Source/cmArgumentParser.h
@@ -5,59 +5,220 @@
#include "cmConfigure.h" // IWYU pragma: keep
#include <cassert>
+#include <cstddef>
#include <functional>
+#include <map>
#include <string>
#include <utility>
#include <vector>
+#include <cm/optional>
#include <cm/string_view>
+#include <cm/type_traits>
#include <cmext/string_view>
+#include "cmArgumentParserTypes.h" // IWYU pragma: keep
+
+template <typename Result>
+class cmArgumentParser; // IWYU pragma: keep
+
+class cmMakefile;
+
namespace ArgumentParser {
-using StringList = std::vector<std::string>;
-using MultiStringList = std::vector<StringList>;
+class ParseResult
+{
+ std::map<cm::string_view, std::string> KeywordErrors;
+
+public:
+ explicit operator bool() const { return this->KeywordErrors.empty(); }
+
+ void AddKeywordError(cm::string_view key, cm::string_view text)
+
+ {
+ this->KeywordErrors[key] += text;
+ }
+
+ std::map<cm::string_view, std::string> const& GetKeywordErrors() const
+ {
+ return this->KeywordErrors;
+ }
+
+ bool MaybeReportError(cmMakefile& mf) const;
+};
+
+template <typename Result>
+typename std::enable_if<std::is_base_of<ParseResult, Result>::value,
+ ParseResult*>::type
+AsParseResultPtr(Result& result)
+{
+ return &result;
+}
+
+template <typename Result>
+typename std::enable_if<!std::is_base_of<ParseResult, Result>::value,
+ ParseResult*>::type
+AsParseResultPtr(Result&)
+{
+ return nullptr;
+}
+
+enum class Continue
+{
+ No,
+ Yes,
+};
+
+struct ExpectAtLeast
+{
+ std::size_t Count = 0;
+
+ ExpectAtLeast(std::size_t count)
+ : Count(count)
+ {
+ }
+};
class Instance;
-using Action = std::function<void(Instance&, void*)>;
+using KeywordAction = std::function<void(Instance&)>;
+using KeywordNameAction = std::function<void(Instance&, cm::string_view)>;
+using PositionAction =
+ std::function<void(Instance&, std::size_t, cm::string_view)>;
-// using ActionMap = cm::flat_map<cm::string_view, Action>;
-class ActionMap : public std::vector<std::pair<cm::string_view, Action>>
+// using KeywordActionMap = cm::flat_map<cm::string_view, KeywordAction>;
+class KeywordActionMap
+ : public std::vector<std::pair<cm::string_view, KeywordAction>>
{
public:
- std::pair<iterator, bool> Emplace(cm::string_view name, Action action);
+ std::pair<iterator, bool> Emplace(cm::string_view name,
+ KeywordAction action);
const_iterator Find(cm::string_view name) const;
};
+// using PositionActionMap = cm::flat_map<cm::string_view, PositionAction>;
+class PositionActionMap
+ : public std::vector<std::pair<std::size_t, PositionAction>>
+{
+public:
+ std::pair<iterator, bool> Emplace(std::size_t pos, PositionAction action);
+ const_iterator Find(std::size_t pos) const;
+};
+
+class ActionMap
+{
+public:
+ KeywordActionMap Keywords;
+ KeywordNameAction KeywordMissingValue;
+ KeywordNameAction ParsedKeyword;
+ PositionActionMap Positions;
+};
+
+class Base
+{
+public:
+ using ExpectAtLeast = ArgumentParser::ExpectAtLeast;
+ using Continue = ArgumentParser::Continue;
+ using Instance = ArgumentParser::Instance;
+ using ParseResult = ArgumentParser::ParseResult;
+
+ ArgumentParser::ActionMap Bindings;
+
+ bool MaybeBind(cm::string_view name, KeywordAction action)
+ {
+ return this->Bindings.Keywords.Emplace(name, std::move(action)).second;
+ }
+
+ void Bind(cm::string_view name, KeywordAction action)
+ {
+ bool const inserted = this->MaybeBind(name, std::move(action));
+ assert(inserted);
+ static_cast<void>(inserted);
+ }
+
+ void BindParsedKeyword(KeywordNameAction action)
+ {
+ assert(!this->Bindings.ParsedKeyword);
+ this->Bindings.ParsedKeyword = std::move(action);
+ }
+
+ void BindKeywordMissingValue(KeywordNameAction action)
+ {
+ assert(!this->Bindings.KeywordMissingValue);
+ this->Bindings.KeywordMissingValue = std::move(action);
+ }
+
+ void Bind(std::size_t pos, PositionAction action)
+ {
+ bool const inserted =
+ this->Bindings.Positions.Emplace(pos, std::move(action)).second;
+ assert(inserted);
+ static_cast<void>(inserted);
+ }
+};
+
class Instance
{
public:
- Instance(ActionMap const& bindings)
+ Instance(ActionMap const& bindings, ParseResult* parseResult,
+ std::vector<std::string>* unparsedArguments, void* result = nullptr)
: Bindings(bindings)
+ , ParseResults(parseResult)
+ , UnparsedArguments(unparsedArguments)
+ , Result(result)
{
}
+ void Bind(std::function<Continue(cm::string_view)> f, ExpectAtLeast expect);
void Bind(bool& val);
void Bind(std::string& val);
- void Bind(StringList& val);
- void Bind(MultiStringList& val);
+ void Bind(NonEmpty<std::string>& val);
+ void Bind(Maybe<std::string>& val);
+ void Bind(MaybeEmpty<std::vector<std::string>>& val);
+ void Bind(NonEmpty<std::vector<std::string>>& val);
+ void Bind(std::vector<std::vector<std::string>>& val);
+
+ // cm::optional<> records the presence the keyword to which it binds.
+ template <typename T>
+ void Bind(cm::optional<T>& optVal)
+ {
+ if (!optVal) {
+ optVal.emplace();
+ }
+ this->Bind(*optVal);
+ }
- void Consume(cm::string_view arg, void* result,
- std::vector<std::string>* unparsedArguments,
- std::vector<std::string>* keywordsMissingValue,
- std::vector<std::string>* parsedKeywords);
+ template <typename Range>
+ void Parse(Range const& args, std::size_t pos = 0)
+ {
+ for (cm::string_view arg : args) {
+ this->Consume(pos++, arg);
+ }
+ this->FinishKeyword();
+ }
private:
ActionMap const& Bindings;
- std::string* CurrentString = nullptr;
- StringList* CurrentList = nullptr;
- bool ExpectValue = false;
+ ParseResult* ParseResults = nullptr;
+ std::vector<std::string>* UnparsedArguments = nullptr;
+ void* Result = nullptr;
+
+ cm::string_view Keyword;
+ std::size_t KeywordValuesSeen = 0;
+ std::size_t KeywordValuesExpected = 0;
+ std::function<Continue(cm::string_view)> KeywordValueFunc;
+ bool DoneWithPositional = false;
+
+ void Consume(std::size_t pos, cm::string_view arg);
+ void FinishKeyword();
+
+ template <typename Result>
+ friend class ::cmArgumentParser;
};
} // namespace ArgumentParser
template <typename Result>
-class cmArgumentParser
+class cmArgumentParser : private ArgumentParser::Base
{
public:
// I *think* this function could be made `constexpr` when the code is
@@ -65,83 +226,194 @@ public:
template <typename T>
cmArgumentParser& Bind(cm::static_string_view name, T Result::*member)
{
- bool const inserted =
- this->Bindings
- .Emplace(name,
- [member](ArgumentParser::Instance& instance, void* result) {
- instance.Bind(static_cast<Result*>(result)->*member);
- })
- .second;
- assert(inserted), (void)inserted;
+ this->Base::Bind(name, [member](Instance& instance) {
+ instance.Bind(static_cast<Result*>(instance.Result)->*member);
+ });
+ return *this;
+ }
+
+ cmArgumentParser& Bind(cm::static_string_view name,
+ Continue (Result::*member)(cm::string_view),
+ ExpectAtLeast expect = { 1 })
+ {
+ this->Base::Bind(name, [member, expect](Instance& instance) {
+ Result* result = static_cast<Result*>(instance.Result);
+ instance.Bind(
+ [result, member](cm::string_view arg) -> Continue {
+ return (result->*member)(arg);
+ },
+ expect);
+ });
+ return *this;
+ }
+
+ cmArgumentParser& Bind(cm::static_string_view name,
+ Continue (Result::*member)(cm::string_view,
+ cm::string_view),
+ ExpectAtLeast expect = { 1 })
+ {
+ this->Base::Bind(name, [member, expect](Instance& instance) {
+ Result* result = static_cast<Result*>(instance.Result);
+ cm::string_view keyword = instance.Keyword;
+ instance.Bind(
+ [result, member, keyword](cm::string_view arg) -> Continue {
+ return (result->*member)(keyword, arg);
+ },
+ expect);
+ });
+ return *this;
+ }
+
+ cmArgumentParser& Bind(cm::static_string_view name,
+ std::function<Continue(Result&, cm::string_view)> f,
+ ExpectAtLeast expect = { 1 })
+ {
+ this->Base::Bind(name, [f, expect](Instance& instance) {
+ Result* result = static_cast<Result*>(instance.Result);
+ instance.Bind(
+ [result, &f](cm::string_view arg) -> Continue {
+ return f(*result, arg);
+ },
+ expect);
+ });
+ return *this;
+ }
+
+ cmArgumentParser& Bind(
+ cm::static_string_view name,
+ std::function<Continue(Result&, cm::string_view, cm::string_view)> f,
+ ExpectAtLeast expect = { 1 })
+ {
+ this->Base::Bind(name, [f, expect](Instance& instance) {
+ Result* result = static_cast<Result*>(instance.Result);
+ cm::string_view keyword = instance.Keyword;
+ instance.Bind(
+ [result, keyword, &f](cm::string_view arg) -> Continue {
+ return f(*result, keyword, arg);
+ },
+ expect);
+ });
+ return *this;
+ }
+
+ cmArgumentParser& Bind(std::size_t position,
+ cm::optional<std::string> Result::*member)
+ {
+ this->Base::Bind(
+ position,
+ [member](Instance& instance, std::size_t, cm::string_view arg) {
+ Result* result = static_cast<Result*>(instance.Result);
+ result->*member = arg;
+ });
+ return *this;
+ }
+
+ cmArgumentParser& BindParsedKeywords(
+ std::vector<cm::string_view> Result::*member)
+ {
+ this->Base::BindParsedKeyword(
+ [member](Instance& instance, cm::string_view arg) {
+ (static_cast<Result*>(instance.Result)->*member).emplace_back(arg);
+ });
return *this;
}
template <typename Range>
- void Parse(Result& result, Range const& args,
- std::vector<std::string>* unparsedArguments = nullptr,
- std::vector<std::string>* keywordsMissingValue = nullptr,
- std::vector<std::string>* parsedKeywords = nullptr) const
+ bool Parse(Result& result, Range const& args,
+ std::vector<std::string>* unparsedArguments,
+ std::size_t pos = 0) const
{
- ArgumentParser::Instance instance(this->Bindings);
- for (cm::string_view arg : args) {
- instance.Consume(arg, &result, unparsedArguments, keywordsMissingValue,
- parsedKeywords);
- }
+ using ArgumentParser::AsParseResultPtr;
+ ParseResult* parseResultPtr = AsParseResultPtr(result);
+ Instance instance(this->Bindings, parseResultPtr, unparsedArguments,
+ &result);
+ instance.Parse(args, pos);
+ return parseResultPtr ? static_cast<bool>(*parseResultPtr) : true;
}
template <typename Range>
- Result Parse(Range const& args,
- std::vector<std::string>* unparsedArguments = nullptr,
- std::vector<std::string>* keywordsMissingValue = nullptr,
- std::vector<std::string>* parsedKeywords = nullptr) const
+ Result Parse(Range const& args, std::vector<std::string>* unparsedArguments,
+ std::size_t pos = 0) const
{
Result result;
- this->Parse(result, args, unparsedArguments, keywordsMissingValue,
- parsedKeywords);
+ this->Parse(result, args, unparsedArguments, pos);
return result;
}
-
-private:
- ArgumentParser::ActionMap Bindings;
};
template <>
-class cmArgumentParser<void>
+class cmArgumentParser<void> : private ArgumentParser::Base
{
public:
template <typename T>
cmArgumentParser& Bind(cm::static_string_view name, T& ref)
{
- bool const inserted = this->Bind(cm::string_view(name), ref);
- assert(inserted), (void)inserted;
+ this->Base::Bind(name, [&ref](Instance& instance) { instance.Bind(ref); });
+ return *this;
+ }
+
+ cmArgumentParser& Bind(cm::static_string_view name,
+ std::function<Continue(cm::string_view)> f,
+ ExpectAtLeast expect = { 1 })
+ {
+ this->Base::Bind(name, [f, expect](Instance& instance) {
+ instance.Bind([&f](cm::string_view arg) -> Continue { return f(arg); },
+ expect);
+ });
+ return *this;
+ }
+
+ cmArgumentParser& Bind(
+ cm::static_string_view name,
+ std::function<Continue(cm::string_view, cm::string_view)> f,
+ ExpectAtLeast expect = { 1 })
+ {
+ this->Base::Bind(name, [f, expect](Instance& instance) {
+ cm::string_view keyword = instance.Keyword;
+ instance.Bind(
+ [keyword, &f](cm::string_view arg) -> Continue {
+ return f(keyword, arg);
+ },
+ expect);
+ });
+ return *this;
+ }
+
+ cmArgumentParser& Bind(std::size_t position, cm::optional<std::string>& ref)
+ {
+ this->Base::Bind(position,
+ [&ref](Instance&, std::size_t, cm::string_view arg) {
+ ref = std::string(arg);
+ });
+ return *this;
+ }
+
+ cmArgumentParser& BindParsedKeywords(std::vector<cm::string_view>& ref)
+ {
+ this->Base::BindParsedKeyword(
+ [&ref](Instance&, cm::string_view arg) { ref.emplace_back(arg); });
return *this;
}
template <typename Range>
- void Parse(Range const& args,
- std::vector<std::string>* unparsedArguments = nullptr,
- std::vector<std::string>* keywordsMissingValue = nullptr,
- std::vector<std::string>* parsedKeywords = nullptr) const
+ ParseResult Parse(Range const& args,
+ std::vector<std::string>* unparsedArguments,
+ std::size_t pos = 0) const
{
- ArgumentParser::Instance instance(this->Bindings);
- for (cm::string_view arg : args) {
- instance.Consume(arg, nullptr, unparsedArguments, keywordsMissingValue,
- parsedKeywords);
- }
+ ParseResult parseResult;
+ Instance instance(this->Bindings, &parseResult, unparsedArguments);
+ instance.Parse(args, pos);
+ return parseResult;
}
protected:
+ using Base::Instance;
+ using Base::BindKeywordMissingValue;
+
template <typename T>
bool Bind(cm::string_view name, T& ref)
{
- return this->Bindings
- .Emplace(name,
- [&ref](ArgumentParser::Instance& instance, void*) {
- instance.Bind(ref);
- })
- .second;
+ return this->MaybeBind(name,
+ [&ref](Instance& instance) { instance.Bind(ref); });
}
-
-private:
- ArgumentParser::ActionMap Bindings;
};
diff --git a/Source/cmArgumentParserTypes.h b/Source/cmArgumentParserTypes.h
new file mode 100644
index 0000000..7daae09
--- /dev/null
+++ b/Source/cmArgumentParserTypes.h
@@ -0,0 +1,69 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#if defined(__SUNPRO_CC)
+
+# include <string>
+# include <vector>
+
+namespace ArgumentParser {
+
+template <typename T>
+struct Maybe;
+template <>
+struct Maybe<std::string> : public std::string
+{
+ using std::string::basic_string;
+};
+
+template <typename T>
+struct MaybeEmpty;
+template <typename T>
+struct MaybeEmpty<std::vector<T>> : public std::vector<T>
+{
+ using std::vector<T>::vector;
+};
+
+template <typename T>
+struct NonEmpty;
+template <typename T>
+struct NonEmpty<std::vector<T>> : public std::vector<T>
+{
+ using std::vector<T>::vector;
+};
+template <>
+struct NonEmpty<std::string> : public std::string
+{
+ using std::string::basic_string;
+};
+
+} // namespace ArgumentParser
+
+#else
+
+namespace ArgumentParser {
+
+template <typename T>
+struct Maybe : public T
+{
+ using T::T;
+};
+
+template <typename T>
+struct MaybeEmpty : public T
+{
+ using T::T;
+};
+
+template <typename T>
+struct NonEmpty : public T
+{
+ using T::T;
+};
+
+} // namespace ArgumentParser
+
+#endif
diff --git a/Source/cmBlockCommand.cxx b/Source/cmBlockCommand.cxx
new file mode 100644
index 0000000..c358aa2
--- /dev/null
+++ b/Source/cmBlockCommand.cxx
@@ -0,0 +1,200 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmBlockCommand.h"
+
+#include <cstdint> // IWYU pragma: keep
+#include <utility>
+
+#include <cm/memory>
+#include <cm/optional>
+#include <cm/string_view>
+#include <cmext/enum_set>
+#include <cmext/string_view>
+
+#include "cmArgumentParser.h"
+#include "cmArgumentParserTypes.h"
+#include "cmExecutionStatus.h"
+#include "cmFunctionBlocker.h"
+#include "cmListFileCache.h"
+#include "cmMakefile.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+namespace {
+enum class ScopeType : std::uint8_t
+{
+ VARIABLES,
+ POLICIES
+};
+using ScopeSet = cm::enum_set<ScopeType>;
+
+class BlockScopePushPop
+{
+public:
+ BlockScopePushPop(cmMakefile* m, const ScopeSet& scopes);
+ ~BlockScopePushPop() = default;
+
+ BlockScopePushPop(const BlockScopePushPop&) = delete;
+ BlockScopePushPop& operator=(const BlockScopePushPop&) = delete;
+
+private:
+ std::unique_ptr<cmMakefile::PolicyPushPop> PolicyScope;
+ std::unique_ptr<cmMakefile::VariablePushPop> VariableScope;
+};
+
+BlockScopePushPop::BlockScopePushPop(cmMakefile* mf, const ScopeSet& scopes)
+{
+ if (scopes.contains(ScopeType::POLICIES)) {
+ this->PolicyScope = cm::make_unique<cmMakefile::PolicyPushPop>(mf);
+ }
+ if (scopes.contains(ScopeType::VARIABLES)) {
+ this->VariableScope = cm::make_unique<cmMakefile::VariablePushPop>(mf);
+ }
+}
+
+class cmBlockFunctionBlocker : public cmFunctionBlocker
+{
+public:
+ cmBlockFunctionBlocker(cmMakefile* mf, const ScopeSet& scopes,
+ std::vector<std::string> variableNames);
+ ~cmBlockFunctionBlocker() override;
+
+ cm::string_view StartCommandName() const override { return "block"_s; }
+ cm::string_view EndCommandName() const override { return "endblock"_s; }
+
+ bool EndCommandSupportsArguments() const override { return false; }
+
+ bool ArgumentsMatch(cmListFileFunction const& lff,
+ cmMakefile& mf) const override;
+
+ bool Replay(std::vector<cmListFileFunction> functions,
+ cmExecutionStatus& inStatus) override;
+
+private:
+ cmMakefile* Makefile;
+ BlockScopePushPop BlockScope;
+ std::vector<std::string> VariableNames;
+};
+
+cmBlockFunctionBlocker::cmBlockFunctionBlocker(
+ cmMakefile* const mf, const ScopeSet& scopes,
+ std::vector<std::string> variableNames)
+ : Makefile{ mf }
+ , BlockScope{ mf, scopes }
+ , VariableNames{ std::move(variableNames) }
+{
+}
+
+cmBlockFunctionBlocker::~cmBlockFunctionBlocker()
+{
+ for (auto const& varName : this->VariableNames) {
+ if (this->Makefile->IsNormalDefinitionSet(varName)) {
+ this->Makefile->RaiseScope(varName,
+ this->Makefile->GetDefinition(varName));
+ } else {
+ // unset variable in parent scope
+ this->Makefile->RaiseScope(varName, nullptr);
+ }
+ }
+}
+
+bool cmBlockFunctionBlocker::ArgumentsMatch(cmListFileFunction const& lff,
+ cmMakefile&) const
+{
+ // no arguments expected for endblock()
+ // but this method should not be called because EndCommandHasArguments()
+ // returns false.
+ return lff.Arguments().empty();
+}
+
+bool cmBlockFunctionBlocker::Replay(std::vector<cmListFileFunction> functions,
+ cmExecutionStatus& inStatus)
+{
+ auto& mf = inStatus.GetMakefile();
+
+ // Invoke all the functions that were collected in the block.
+ for (cmListFileFunction const& fn : functions) {
+ cmExecutionStatus status(mf);
+ mf.ExecuteCommand(fn, status);
+ if (status.GetReturnInvoked()) {
+ inStatus.SetReturnInvoked();
+ return true;
+ }
+ if (status.GetBreakInvoked()) {
+ inStatus.SetBreakInvoked();
+ return true;
+ }
+ if (status.GetContinueInvoked()) {
+ inStatus.SetContinueInvoked();
+ return true;
+ }
+ if (cmSystemTools::GetFatalErrorOccurred()) {
+ return true;
+ }
+ }
+ return true;
+}
+
+} // anonymous namespace
+
+bool cmBlockCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ struct Arguments : public ArgumentParser::ParseResult
+ {
+ cm::optional<ArgumentParser::NonEmpty<std::vector<std::string>>> ScopeFor;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Propagate;
+ };
+ static auto const parser = cmArgumentParser<Arguments>{}
+ .Bind("SCOPE_FOR"_s, &Arguments::ScopeFor)
+ .Bind("PROPAGATE"_s, &Arguments::Propagate);
+ std::vector<std::string> unrecognizedArguments;
+ auto parsedArgs = parser.Parse(args, &unrecognizedArguments);
+
+ if (!unrecognizedArguments.empty()) {
+ status.SetError(cmStrCat("called with unsupported argument \"",
+ unrecognizedArguments[0], '"'));
+ cmSystemTools::SetFatalErrorOccurred();
+ return false;
+ }
+
+ if (parsedArgs.MaybeReportError(status.GetMakefile())) {
+ cmSystemTools::SetFatalErrorOccurred();
+ return true;
+ }
+
+ ScopeSet scopes;
+
+ if (parsedArgs.ScopeFor) {
+ for (auto const& scope : *parsedArgs.ScopeFor) {
+ if (scope == "VARIABLES"_s) {
+ scopes.insert(ScopeType::VARIABLES);
+ continue;
+ }
+ if (scope == "POLICIES"_s) {
+ scopes.insert(ScopeType::POLICIES);
+ continue;
+ }
+ status.SetError(cmStrCat("SCOPE_FOR unsupported scope \"", scope, '"'));
+ cmSystemTools::SetFatalErrorOccurred();
+ return false;
+ }
+ } else {
+ scopes = { ScopeType::VARIABLES, ScopeType::POLICIES };
+ }
+ if (!scopes.contains(ScopeType::VARIABLES) &&
+ !parsedArgs.Propagate.empty()) {
+ status.SetError(
+ "PROPAGATE cannot be specified without a new scope for VARIABLES");
+ cmSystemTools::SetFatalErrorOccurred();
+ return false;
+ }
+
+ // create a function blocker
+ auto fb = cm::make_unique<cmBlockFunctionBlocker>(
+ &status.GetMakefile(), scopes, parsedArgs.Propagate);
+ status.GetMakefile().AddFunctionBlocker(std::move(fb));
+
+ return true;
+}
diff --git a/Source/cmBlockCommand.h b/Source/cmBlockCommand.h
new file mode 100644
index 0000000..5fd8f42
--- /dev/null
+++ b/Source/cmBlockCommand.h
@@ -0,0 +1,14 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+/// Starts block() ... endblock() block
+bool cmBlockCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmCMakeHostSystemInformationCommand.cxx b/Source/cmCMakeHostSystemInformationCommand.cxx
index 0750eea..58129a0 100644
--- a/Source/cmCMakeHostSystemInformationCommand.cxx
+++ b/Source/cmCMakeHostSystemInformationCommand.cxx
@@ -474,7 +474,7 @@ bool QueryWindowsRegistry(Range args, cmExecutionStatus& status,
}
std::string const& key = *args.begin();
- struct Arguments
+ struct Arguments : public ArgumentParser::ParseResult
{
std::string ValueName;
bool ValueNames = false;
@@ -491,19 +491,15 @@ bool QueryWindowsRegistry(Range args, cmExecutionStatus& status,
.Bind("SEPARATOR"_s, &Arguments::Separator)
.Bind("ERROR_VARIABLE"_s, &Arguments::ErrorVariable);
std::vector<std::string> invalidArgs;
- std::vector<std::string> keywordsMissingValue;
- Arguments const arguments =
- parser.Parse(args.advance(1), &invalidArgs, &keywordsMissingValue);
+ Arguments const arguments = parser.Parse(args.advance(1), &invalidArgs);
if (!invalidArgs.empty()) {
status.SetError(cmStrCat("given invalid argument(s) \"",
cmJoin(invalidArgs, ", "_s), "\"."));
return false;
}
- if (!keywordsMissingValue.empty()) {
- status.SetError(cmStrCat("missing expected value for argument(s) \"",
- cmJoin(keywordsMissingValue, ", "_s), "\"."));
- return false;
+ if (arguments.MaybeReportError(status.GetMakefile())) {
+ return true;
}
if ((!arguments.ValueName.empty() &&
(arguments.ValueNames || arguments.SubKeys)) ||
diff --git a/Source/cmCMakeLanguageCommand.cxx b/Source/cmCMakeLanguageCommand.cxx
index a2aaa2a..68e658c 100644
--- a/Source/cmCMakeLanguageCommand.cxx
+++ b/Source/cmCMakeLanguageCommand.cxx
@@ -14,15 +14,18 @@
#include <cmext/string_view>
#include "cmArgumentParser.h"
+#include "cmArgumentParserTypes.h"
#include "cmDependencyProvider.h"
#include "cmExecutionStatus.h"
#include "cmGlobalGenerator.h"
#include "cmListFileCache.h"
#include "cmMakefile.h"
+#include "cmMessageType.h"
#include "cmRange.h"
#include "cmState.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
+#include "cmake.h"
namespace {
@@ -33,13 +36,14 @@ bool FatalError(cmExecutionStatus& status, std::string const& error)
return false;
}
-std::array<cm::static_string_view, 12> InvalidCommands{
+std::array<cm::static_string_view, 14> InvalidCommands{
{ // clang-format off
"function"_s, "endfunction"_s,
"macro"_s, "endmacro"_s,
"if"_s, "elseif"_s, "else"_s, "endif"_s,
"while"_s, "endwhile"_s,
- "foreach"_s, "endforeach"_s
+ "foreach"_s, "endforeach"_s,
+ "block"_s, "endblock"_s
} // clang-format on
};
@@ -235,7 +239,7 @@ bool cmCMakeLanguageCommandSET_DEPENDENCY_PROVIDER(
struct SetProviderArgs
{
std::string Command;
- std::vector<std::string> Methods;
+ ArgumentParser::NonEmpty<std::vector<std::string>> Methods;
};
auto const ArgsParser =
@@ -303,6 +307,27 @@ bool cmCMakeLanguageCommandSET_DEPENDENCY_PROVIDER(
return true;
}
+
+bool cmCMakeLanguageCommandGET_MESSAGE_LOG_LEVEL(
+ std::vector<cmListFileArgument> const& args, cmExecutionStatus& status)
+{
+ cmMakefile& makefile = status.GetMakefile();
+ std::vector<std::string> expandedArgs;
+ makefile.ExpandArguments(args, expandedArgs);
+
+ if (args.size() < 2 || expandedArgs.size() > 2) {
+ return FatalError(
+ status,
+ "sub-command GET_MESSAGE_LOG_LEVEL expects exactly one argument");
+ }
+
+ Message::LogLevel logLevel = makefile.GetCurrentLogLevel();
+ std::string outputValue = cmake::LogLevelToString(logLevel);
+
+ const std::string& outputVariable = expandedArgs[1];
+ makefile.AddDefinition(outputVariable, outputValue);
+ return true;
+}
}
bool cmCMakeLanguageCommand(std::vector<cmListFileArgument> const& args,
@@ -451,5 +476,9 @@ bool cmCMakeLanguageCommand(std::vector<cmListFileArgument> const& args,
return cmCMakeLanguageCommandEVAL(args, status);
}
+ if (expArgs[expArg] == "GET_MESSAGE_LOG_LEVEL") {
+ return cmCMakeLanguageCommandGET_MESSAGE_LOG_LEVEL(args, status);
+ }
+
return FatalError(status, "called with unknown meta-operation");
}
diff --git a/Source/cmCMakePathCommand.cxx b/Source/cmCMakePathCommand.cxx
index bf94c2d..7755082 100644
--- a/Source/cmCMakePathCommand.cxx
+++ b/Source/cmCMakePathCommand.cxx
@@ -2,7 +2,6 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCMakePathCommand.h"
-#include <algorithm>
#include <functional>
#include <iomanip>
#include <map>
@@ -11,10 +10,12 @@
#include <utility>
#include <vector>
+#include <cm/optional>
#include <cm/string_view>
#include <cmext/string_view>
#include "cmArgumentParser.h"
+#include "cmArgumentParserTypes.h"
#include "cmCMakePath.h"
#include "cmExecutionStatus.h"
#include "cmMakefile.h"
@@ -43,15 +44,12 @@ public:
}
template <int Advance = 2>
- Result Parse(std::vector<std::string> const& args,
- std::vector<std::string>* keywordsMissingValue = nullptr,
- std::vector<std::string>* parsedKeywords = nullptr) const
+ Result Parse(std::vector<std::string> const& args) const
{
this->Inputs.clear();
return this->cmArgumentParser<Result>::Parse(
- cmMakeRange(args).advance(Advance), &this->Inputs, keywordsMissingValue,
- parsedKeywords);
+ cmMakeRange(args).advance(Advance), &this->Inputs);
}
const std::vector<std::string>& GetInputs() const { return this->Inputs; }
@@ -82,52 +80,14 @@ public:
template <int Advance = 2>
Result Parse(std::vector<std::string> const& args) const
{
- this->KeywordsMissingValue.clear();
- this->ParsedKeywords.clear();
-
return this->CMakePathArgumentParser<Result>::template Parse<Advance>(
- args, &this->KeywordsMissingValue, &this->ParsedKeywords);
- }
-
- const std::vector<std::string>& GetKeywordsMissingValue() const
- {
- return this->KeywordsMissingValue;
- }
- const std::vector<std::string>& GetParsedKeywords() const
- {
- return this->ParsedKeywords;
- }
-
- bool checkOutputVariable(const Result& arguments,
- cmExecutionStatus& status) const
- {
- if (std::find(this->GetKeywordsMissingValue().begin(),
- this->GetKeywordsMissingValue().end(),
- "OUTPUT_VARIABLE"_s) !=
- this->GetKeywordsMissingValue().end()) {
- status.SetError("OUTPUT_VARIABLE requires an argument.");
- return false;
- }
-
- if (std::find(this->GetParsedKeywords().begin(),
- this->GetParsedKeywords().end(),
- "OUTPUT_VARIABLE"_s) != this->GetParsedKeywords().end() &&
- arguments.Output.empty()) {
- status.SetError("Invalid name for output variable.");
- return false;
- }
-
- return true;
+ args);
}
-
-private:
- mutable std::vector<std::string> KeywordsMissingValue;
- mutable std::vector<std::string> ParsedKeywords;
};
-struct OutputVariable
+struct OutputVariable : public ArgumentParser::ParseResult
{
- std::string Output;
+ cm::optional<ArgumentParser::NonEmpty<std::string>> Output;
};
// Usable when OUTPUT_VARIABLE is the only option
class OutputVariableParser
@@ -297,8 +257,8 @@ bool HandleAppendCommand(std::vector<std::string> const& args,
const auto arguments = parser.Parse(args);
- if (!parser.checkOutputVariable(arguments, status)) {
- return false;
+ if (arguments.MaybeReportError(status.GetMakefile())) {
+ return true;
}
cmCMakePath path(status.GetMakefile().GetSafeDefinition(args[1]));
@@ -307,7 +267,7 @@ bool HandleAppendCommand(std::vector<std::string> const& args,
}
status.GetMakefile().AddDefinition(
- arguments.Output.empty() ? args[1] : arguments.Output, path.String());
+ arguments.Output ? *arguments.Output : args[1], path.String());
return true;
}
@@ -319,8 +279,8 @@ bool HandleAppendStringCommand(std::vector<std::string> const& args,
const auto arguments = parser.Parse(args);
- if (!parser.checkOutputVariable(arguments, status)) {
- return false;
+ if (arguments.MaybeReportError(status.GetMakefile())) {
+ return true;
}
std::string inputPath;
@@ -334,7 +294,7 @@ bool HandleAppendStringCommand(std::vector<std::string> const& args,
}
status.GetMakefile().AddDefinition(
- arguments.Output.empty() ? args[1] : arguments.Output, path.String());
+ arguments.Output ? *arguments.Output : args[1], path.String());
return true;
}
@@ -346,8 +306,8 @@ bool HandleRemoveFilenameCommand(std::vector<std::string> const& args,
const auto arguments = parser.Parse(args);
- if (!parser.checkOutputVariable(arguments, status)) {
- return false;
+ if (arguments.MaybeReportError(status.GetMakefile())) {
+ return true;
}
if (!parser.GetInputs().empty()) {
@@ -364,7 +324,7 @@ bool HandleRemoveFilenameCommand(std::vector<std::string> const& args,
path.RemoveFileName();
status.GetMakefile().AddDefinition(
- arguments.Output.empty() ? args[1] : arguments.Output, path.String());
+ arguments.Output ? *arguments.Output : args[1], path.String());
return true;
}
@@ -376,8 +336,8 @@ bool HandleReplaceFilenameCommand(std::vector<std::string> const& args,
const auto arguments = parser.Parse(args);
- if (!parser.checkOutputVariable(arguments, status)) {
- return false;
+ if (arguments.MaybeReportError(status.GetMakefile())) {
+ return true;
}
if (parser.GetInputs().size() > 1) {
@@ -395,7 +355,7 @@ bool HandleReplaceFilenameCommand(std::vector<std::string> const& args,
parser.GetInputs().empty() ? "" : parser.GetInputs().front());
status.GetMakefile().AddDefinition(
- arguments.Output.empty() ? args[1] : arguments.Output, path.String());
+ arguments.Output ? *arguments.Output : args[1], path.String());
return true;
}
@@ -403,9 +363,9 @@ bool HandleReplaceFilenameCommand(std::vector<std::string> const& args,
bool HandleRemoveExtensionCommand(std::vector<std::string> const& args,
cmExecutionStatus& status)
{
- struct Arguments
+ struct Arguments : public ArgumentParser::ParseResult
{
- std::string Output;
+ cm::optional<ArgumentParser::NonEmpty<std::string>> Output;
bool LastOnly = false;
};
@@ -415,8 +375,8 @@ bool HandleRemoveExtensionCommand(std::vector<std::string> const& args,
Arguments const arguments = parser.Parse(args);
- if (!parser.checkOutputVariable(arguments, status)) {
- return false;
+ if (arguments.MaybeReportError(status.GetMakefile())) {
+ return true;
}
if (!parser.GetInputs().empty()) {
@@ -438,7 +398,7 @@ bool HandleRemoveExtensionCommand(std::vector<std::string> const& args,
}
status.GetMakefile().AddDefinition(
- arguments.Output.empty() ? args[1] : arguments.Output, path.String());
+ arguments.Output ? *arguments.Output : args[1], path.String());
return true;
}
@@ -446,9 +406,9 @@ bool HandleRemoveExtensionCommand(std::vector<std::string> const& args,
bool HandleReplaceExtensionCommand(std::vector<std::string> const& args,
cmExecutionStatus& status)
{
- struct Arguments
+ struct Arguments : public ArgumentParser::ParseResult
{
- std::string Output;
+ cm::optional<ArgumentParser::NonEmpty<std::string>> Output;
bool LastOnly = false;
};
@@ -458,8 +418,8 @@ bool HandleReplaceExtensionCommand(std::vector<std::string> const& args,
Arguments const arguments = parser.Parse(args);
- if (!parser.checkOutputVariable(arguments, status)) {
- return false;
+ if (arguments.MaybeReportError(status.GetMakefile())) {
+ return true;
}
if (parser.GetInputs().size() > 1) {
@@ -483,7 +443,7 @@ bool HandleReplaceExtensionCommand(std::vector<std::string> const& args,
}
status.GetMakefile().AddDefinition(
- arguments.Output.empty() ? args[1] : arguments.Output, path.String());
+ arguments.Output ? *arguments.Output : args[1], path.String());
return true;
}
@@ -495,8 +455,8 @@ bool HandleNormalPathCommand(std::vector<std::string> const& args,
const auto arguments = parser.Parse(args);
- if (!parser.checkOutputVariable(arguments, status)) {
- return false;
+ if (arguments.MaybeReportError(status.GetMakefile())) {
+ return true;
}
if (!parser.GetInputs().empty()) {
@@ -512,7 +472,7 @@ bool HandleNormalPathCommand(std::vector<std::string> const& args,
auto path = cmCMakePath(inputPath).Normal();
status.GetMakefile().AddDefinition(
- arguments.Output.empty() ? args[1] : arguments.Output, path.String());
+ arguments.Output ? *arguments.Output : args[1], path.String());
return true;
}
@@ -523,10 +483,10 @@ bool HandleTransformPathCommand(
const std::string& base)>& transform,
bool normalizeOption = false)
{
- struct Arguments
+ struct Arguments : public ArgumentParser::ParseResult
{
- std::string Output;
- std::string BaseDirectory;
+ cm::optional<ArgumentParser::NonEmpty<std::string>> Output;
+ cm::optional<std::string> BaseDirectory;
bool Normalize = false;
};
@@ -538,8 +498,8 @@ bool HandleTransformPathCommand(
Arguments arguments = parser.Parse(args);
- if (!parser.checkOutputVariable(arguments, status)) {
- return false;
+ if (arguments.MaybeReportError(status.GetMakefile())) {
+ return true;
}
if (!parser.GetInputs().empty()) {
@@ -547,17 +507,11 @@ bool HandleTransformPathCommand(
return false;
}
- if (std::find(parser.GetKeywordsMissingValue().begin(),
- parser.GetKeywordsMissingValue().end(), "BASE_DIRECTORY"_s) !=
- parser.GetKeywordsMissingValue().end()) {
- status.SetError("BASE_DIRECTORY requires an argument.");
- return false;
- }
-
- if (std::find(parser.GetParsedKeywords().begin(),
- parser.GetParsedKeywords().end(),
- "BASE_DIRECTORY"_s) == parser.GetParsedKeywords().end()) {
- arguments.BaseDirectory = status.GetMakefile().GetCurrentSourceDirectory();
+ std::string baseDirectory;
+ if (arguments.BaseDirectory) {
+ baseDirectory = *arguments.BaseDirectory;
+ } else {
+ baseDirectory = status.GetMakefile().GetCurrentSourceDirectory();
}
std::string inputPath;
@@ -565,13 +519,13 @@ bool HandleTransformPathCommand(
return false;
}
- auto path = transform(cmCMakePath(inputPath), arguments.BaseDirectory);
+ auto path = transform(cmCMakePath(inputPath), baseDirectory);
if (arguments.Normalize) {
path = path.Normal();
}
status.GetMakefile().AddDefinition(
- arguments.Output.empty() ? args[1] : arguments.Output, path.String());
+ arguments.Output ? *arguments.Output : args[1], path.String());
return true;
}
diff --git a/Source/cmCMakePresetsGraph.cxx b/Source/cmCMakePresetsGraph.cxx
index b737c1f..dba79d5 100644
--- a/Source/cmCMakePresetsGraph.cxx
+++ b/Source/cmCMakePresetsGraph.cxx
@@ -901,8 +901,9 @@ cmCMakePresetsGraph::ReadProjectPresetsInternal(bool allowNoFiles)
std::string filename = GetUserFilename(this->SourceDir);
std::vector<File*> inProgressFiles;
if (cmSystemTools::FileExists(filename)) {
- auto result = this->ReadJSONFile(filename, RootType::User,
- ReadReason::Root, inProgressFiles, file);
+ auto result =
+ this->ReadJSONFile(filename, RootType::User, ReadReason::Root,
+ inProgressFiles, file, this->errors);
if (result != ReadFileResult::READ_OK) {
return result;
}
@@ -910,8 +911,9 @@ cmCMakePresetsGraph::ReadProjectPresetsInternal(bool allowNoFiles)
} else {
filename = GetFilename(this->SourceDir);
if (cmSystemTools::FileExists(filename)) {
- auto result = this->ReadJSONFile(
- filename, RootType::Project, ReadReason::Root, inProgressFiles, file);
+ auto result =
+ this->ReadJSONFile(filename, RootType::Project, ReadReason::Root,
+ inProgressFiles, file, this->errors);
if (result != ReadFileResult::READ_OK) {
return result;
}
diff --git a/Source/cmCMakePresetsGraph.h b/Source/cmCMakePresetsGraph.h
index f1f8662..4f3e108 100644
--- a/Source/cmCMakePresetsGraph.h
+++ b/Source/cmCMakePresetsGraph.h
@@ -52,6 +52,7 @@ public:
TEST_OUTPUT_TRUNCATION_UNSUPPORTED,
};
+ std::string errors;
enum class ArchToolsetStrategy
{
Set,
@@ -407,7 +408,7 @@ private:
ReadFileResult ReadProjectPresetsInternal(bool allowNoFiles);
ReadFileResult ReadJSONFile(const std::string& filename, RootType rootType,
ReadReason readReason,
- std::vector<File*>& inProgressFiles,
- File*& file);
+ std::vector<File*>& inProgressFiles, File*& file,
+ std::string& errMsg);
void ClearPresets();
};
diff --git a/Source/cmCMakePresetsGraphReadJSON.cxx b/Source/cmCMakePresetsGraphReadJSON.cxx
index d11e839..d68af22 100644
--- a/Source/cmCMakePresetsGraphReadJSON.cxx
+++ b/Source/cmCMakePresetsGraphReadJSON.cxx
@@ -411,7 +411,7 @@ cmCMakePresetsGraph::ReadFileResult EnvironmentMapHelper(
cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile(
const std::string& filename, RootType rootType, ReadReason readReason,
- std::vector<File*>& inProgressFiles, File*& file)
+ std::vector<File*>& inProgressFiles, File*& file, std::string& errMsg)
{
ReadFileResult result;
@@ -430,6 +430,7 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile(
cmsys::ifstream fin(filename.c_str());
if (!fin) {
+ errMsg = cmStrCat(filename, ": Failed to read file\n", errMsg);
return ReadFileResult::FILE_NOT_FOUND;
}
// If there's a BOM, toss it.
@@ -438,7 +439,8 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile(
Json::Value root;
Json::CharReaderBuilder builder;
Json::CharReaderBuilder::strictMode(&builder.settings_);
- if (!Json::parseFromStream(builder, fin, &root, nullptr)) {
+ if (!Json::parseFromStream(builder, fin, &root, &errMsg)) {
+ errMsg = cmStrCat(filename, ":\n", errMsg);
return ReadFileResult::JSON_PARSE_ERROR;
}
@@ -490,6 +492,8 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile(
for (auto& preset : presets.ConfigurePresets) {
preset.OriginFile = file;
if (preset.Name.empty()) {
+ errMsg += R"(\n\t)";
+ errMsg += filename;
return ReadFileResult::INVALID_PRESET;
}
@@ -523,6 +527,8 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile(
for (auto& preset : presets.BuildPresets) {
preset.OriginFile = file;
if (preset.Name.empty()) {
+ errMsg += R"(\n\t)";
+ errMsg += filename;
return ReadFileResult::INVALID_PRESET;
}
@@ -569,12 +575,13 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile(
auto const includeFile = [this, &inProgressFiles, file](
const std::string& include, RootType rootType2,
- ReadReason readReason2) -> ReadFileResult {
+ ReadReason readReason2,
+ std::string& FailureMessage) -> ReadFileResult {
ReadFileResult r;
File* includedFile;
if ((r = this->ReadJSONFile(include, rootType2, readReason2,
- inProgressFiles, includedFile)) !=
- ReadFileResult::READ_OK) {
+ inProgressFiles, includedFile,
+ FailureMessage)) != ReadFileResult::READ_OK) {
return r;
}
@@ -589,8 +596,8 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile(
include = cmStrCat(directory, '/', include);
}
- if ((result = includeFile(include, rootType, ReadReason::Included)) !=
- ReadFileResult::READ_OK) {
+ if ((result = includeFile(include, rootType, ReadReason::Included,
+ errMsg)) != ReadFileResult::READ_OK) {
return result;
}
}
@@ -599,7 +606,7 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile(
auto cmakePresetsFilename = GetFilename(this->SourceDir);
if (cmSystemTools::FileExists(cmakePresetsFilename)) {
if ((result = includeFile(cmakePresetsFilename, RootType::Project,
- ReadReason::Root)) !=
+ ReadReason::Root, errMsg)) !=
ReadFileResult::READ_OK) {
return result;
}
diff --git a/Source/cmCommands.cxx b/Source/cmCommands.cxx
index c6296f9..3bc4f0e 100644
--- a/Source/cmCommands.cxx
+++ b/Source/cmCommands.cxx
@@ -14,13 +14,13 @@
#include "cmAddLibraryCommand.h"
#include "cmAddSubDirectoryCommand.h"
#include "cmAddTestCommand.h"
+#include "cmBlockCommand.h"
#include "cmBreakCommand.h"
#include "cmBuildCommand.h"
#include "cmCMakeLanguageCommand.h"
#include "cmCMakeMinimumRequired.h"
#include "cmCMakePathCommand.h"
#include "cmCMakePolicyCommand.h"
-#include "cmCommand.h"
#include "cmConfigureFileCommand.h"
#include "cmContinueCommand.h"
#include "cmCreateTestSourceList.h"
@@ -127,6 +127,7 @@ void GetScriptingCommands(cmState* state)
state->AddFlowControlCommand("macro", cmMacroCommand);
state->AddFlowControlCommand("return", cmReturnCommand);
state->AddFlowControlCommand("while", cmWhileCommand);
+ state->AddFlowControlCommand("block", cmBlockCommand);
state->AddBuiltinCommand("cmake_language", cmCMakeLanguageCommand);
state->AddBuiltinCommand("cmake_minimum_required", cmCMakeMinimumRequired);
@@ -199,6 +200,10 @@ void GetScriptingCommands(cmState* state)
"An ENDWHILE command was found outside of a proper "
"WHILE ENDWHILE structure. Or its arguments did not "
"match the opening WHILE command.");
+ state->AddUnexpectedFlowControlCommand(
+ "endblock",
+ "An ENDBLOCK command was found outside of a proper "
+ "BLOCK ENDBLOCK structure.");
#if !defined(CMAKE_BOOTSTRAP)
state->AddBuiltinCommand("cmake_host_system_information",
@@ -264,9 +269,8 @@ void GetProjectCommands(cmState* state)
cmTargetLinkLibrariesCommand);
state->AddBuiltinCommand("target_link_options", cmTargetLinkOptionsCommand);
state->AddBuiltinCommand("target_sources", cmTargetSourcesCommand);
- state->AddBuiltinCommand("try_compile",
- cm::make_unique<cmTryCompileCommand>());
- state->AddBuiltinCommand("try_run", cm::make_unique<cmTryRunCommand>());
+ state->AddBuiltinCommand("try_compile", cmTryCompileCommand);
+ state->AddBuiltinCommand("try_run", cmTryRunCommand);
state->AddBuiltinCommand("target_precompile_headers",
cmTargetPrecompileHeadersCommand);
diff --git a/Source/cmCommonTargetGenerator.cxx b/Source/cmCommonTargetGenerator.cxx
index ba95168..5fe6756 100644
--- a/Source/cmCommonTargetGenerator.cxx
+++ b/Source/cmCommonTargetGenerator.cxx
@@ -9,6 +9,7 @@
#include "cmComputeLinkInformation.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalCommonGenerator.h"
+#include "cmGlobalGenerator.h"
#include "cmLocalCommonGenerator.h"
#include "cmLocalGenerator.h"
#include "cmMakefile.h"
@@ -175,6 +176,9 @@ std::vector<std::string> cmCommonTargetGenerator::GetLinkedTargetDirectories(
cmLocalGenerator* lg = linkee->GetLocalGenerator();
std::string di = cmStrCat(lg->GetCurrentBinaryDirectory(), '/',
lg->GetTargetDirectory(linkee));
+ if (lg->GetGlobalGenerator()->IsMultiConfig()) {
+ di = cmStrCat(di, '/', config);
+ }
dirs.push_back(std::move(di));
}
}
diff --git a/Source/cmConfigure.cmake.h.in b/Source/cmConfigure.cmake.h.in
index 6a419f6..31d03da 100644
--- a/Source/cmConfigure.cmake.h.in
+++ b/Source/cmConfigure.cmake.h.in
@@ -14,6 +14,10 @@
#pragma warning(disable : 1572) /* floating-point equality test */
#endif
+#if defined(__LCC__) && defined(__EDG__) && (__LCC__ == 123)
+#pragma diag_suppress 2910 /* excess -Wunused-function in 1.23.x */
+#endif
+
#cmakedefine HAVE_ENVIRON_NOT_REQUIRE_PROTOTYPE
#cmakedefine HAVE_UNSETENV
#cmakedefine CMake_USE_MACH_PARSER
diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx
index 5418e7c..7b9dc2e 100644
--- a/Source/cmCoreTryCompile.cxx
+++ b/Source/cmCoreTryCompile.cxx
@@ -2,6 +2,7 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCoreTryCompile.h"
+#include <array>
#include <cstdio>
#include <cstring>
#include <set>
@@ -13,12 +14,14 @@
#include "cmsys/Directory.hxx"
+#include "cmArgumentParser.h"
#include "cmExportTryCompileFileGenerator.h"
#include "cmGlobalGenerator.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmOutputConverter.h"
#include "cmPolicies.h"
+#include "cmRange.h"
#include "cmState.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
@@ -28,142 +31,6 @@
#include "cmake.h"
namespace {
-class LanguageStandardState
-{
-public:
- LanguageStandardState(std::string&& lang)
- : StandardFlag(lang + "_STANDARD")
- , RequiredFlag(lang + "_STANDARD_REQUIRED")
- , ExtensionFlag(lang + "_EXTENSIONS")
- {
- }
-
- void Enabled(bool isEnabled) { this->IsEnabled = isEnabled; }
-
- bool UpdateIfMatches(std::vector<std::string> const& argv, size_t& index)
- {
- bool updated = false;
- if (argv[index] == this->StandardFlag) {
- this->DidStandard = true;
- this->StandardValue = argv[++index];
- updated = true;
- } else if (argv[index] == this->RequiredFlag) {
- this->DidStandardRequired = true;
- this->RequiredValue = argv[++index];
- updated = true;
- } else if (argv[index] == this->ExtensionFlag) {
- this->DidExtensions = true;
- this->ExtensionValue = argv[++index];
- updated = true;
- }
- return updated;
- }
-
- bool Validate(cmMakefile* const makefile) const
- {
- if (this->DidStandard) {
- makefile->IssueMessage(
- MessageType::FATAL_ERROR,
- cmStrCat(this->StandardFlag,
- " allowed only in source file signature."));
- return false;
- }
- if (this->DidStandardRequired) {
- makefile->IssueMessage(
- MessageType::FATAL_ERROR,
- cmStrCat(this->RequiredFlag,
- " allowed only in source file signature."));
- return false;
- }
- if (this->DidExtensions) {
- makefile->IssueMessage(
- MessageType::FATAL_ERROR,
- cmStrCat(this->ExtensionFlag,
- " allowed only in source file signature."));
- return false;
- }
-
- return true;
- }
-
- bool DidNone() const
- {
- return !this->DidStandard && !this->DidStandardRequired &&
- !this->DidExtensions;
- }
-
- void LoadUnsetPropertyValues(cmMakefile* const makefile, bool honorStandard,
- bool warnCMP0067,
- std::vector<std::string>& warnCMP0067Variables)
- {
- if (!this->IsEnabled) {
- return;
- }
-
- auto lookupStdVar = [&](std::string const& var) -> std::string {
- std::string value = makefile->GetSafeDefinition(var);
- if (warnCMP0067 && !value.empty()) {
- value.clear();
- warnCMP0067Variables.emplace_back(var);
- }
- return value;
- };
-
- if (honorStandard || warnCMP0067) {
- if (!this->DidStandard) {
- this->StandardValue =
- lookupStdVar(cmStrCat("CMAKE_", this->StandardFlag));
- }
- if (!this->DidStandardRequired) {
- this->RequiredValue =
- lookupStdVar(cmStrCat("CMAKE_", this->RequiredFlag));
- }
- if (!this->DidExtensions) {
- this->ExtensionValue =
- lookupStdVar(cmStrCat("CMAKE_", this->ExtensionFlag));
- }
- }
- }
-
- void WriteProperties(FILE* fout, std::string const& targetName) const
- {
- if (!this->IsEnabled) {
- return;
- }
-
- auto writeProp = [&](std::string const& prop, std::string const& value) {
- fprintf(fout, "set_property(TARGET %s PROPERTY %s %s)\n",
- targetName.c_str(),
- cmOutputConverter::EscapeForCMake(prop).c_str(),
- cmOutputConverter::EscapeForCMake(value).c_str());
- };
-
- if (!this->StandardValue.empty()) {
- writeProp(this->StandardFlag, this->StandardValue);
- }
- if (!this->RequiredValue.empty()) {
- writeProp(this->RequiredFlag, this->RequiredValue);
- }
- if (!this->ExtensionValue.empty()) {
- writeProp(this->ExtensionFlag, this->ExtensionValue);
- }
- }
-
-private:
- bool IsEnabled = false;
- bool DidStandard = false;
- bool DidStandardRequired = false;
- bool DidExtensions = false;
-
- std::string StandardFlag;
- std::string RequiredFlag;
- std::string ExtensionFlag;
-
- std::string StandardValue;
- std::string RequiredValue;
- std::string ExtensionValue;
-};
-
constexpr size_t lang_property_start = 0;
constexpr size_t lang_property_size = 4;
constexpr size_t pie_property_start = 4;
@@ -233,114 +100,160 @@ std::set<std::string> const ghs_platform_vars{
"GHS_OS_ROOT", "GHS_OS_DIR", "GHS_BSP_NAME",
"GHS_OS_DIR_OPTION"
};
+using Arguments = cmCoreTryCompile::Arguments;
+
+ArgumentParser::Continue TryCompileLangProp(Arguments& args,
+ cm::string_view key,
+ cm::string_view val)
+{
+ args.LangProps[std::string(key)] = std::string(val);
+ return ArgumentParser::Continue::No;
+}
+
+ArgumentParser::Continue TryCompileCompileDefs(Arguments& args,
+ cm::string_view val)
+{
+ cmExpandList(val, args.CompileDefs);
+ return ArgumentParser::Continue::Yes;
+}
+
+#define BIND_LANG_PROPS(lang) \
+ Bind(#lang "_STANDARD"_s, TryCompileLangProp) \
+ .Bind(#lang "_STANDARD_REQUIRED"_s, TryCompileLangProp) \
+ .Bind(#lang "_EXTENSIONS"_s, TryCompileLangProp)
+
+auto const TryCompileArgParser =
+ cmArgumentParser<Arguments>{}
+ .Bind(0, &Arguments::CompileResultVariable)
+ .Bind(1, &Arguments::BinaryDirectory)
+ .Bind(2, &Arguments::SourceDirectoryOrFile)
+ .Bind(3, &Arguments::ProjectName)
+ .Bind(4, &Arguments::TargetName)
+ .Bind("SOURCES"_s, &Arguments::Sources)
+ .Bind("CMAKE_FLAGS"_s, &Arguments::CMakeFlags)
+ .Bind("COMPILE_DEFINITIONS"_s, TryCompileCompileDefs,
+ ArgumentParser::ExpectAtLeast{ 0 })
+ .Bind("LINK_LIBRARIES"_s, &Arguments::LinkLibraries)
+ .Bind("LINK_OPTIONS"_s, &Arguments::LinkOptions)
+ .Bind("__CMAKE_INTERNAL"_s, &Arguments::CMakeInternal)
+ .Bind("OUTPUT_VARIABLE"_s, &Arguments::OutputVariable)
+ .Bind("COPY_FILE"_s, &Arguments::CopyFileTo)
+ .Bind("COPY_FILE_ERROR"_s, &Arguments::CopyFileError)
+ .BIND_LANG_PROPS(C)
+ .BIND_LANG_PROPS(CUDA)
+ .BIND_LANG_PROPS(CXX)
+ .BIND_LANG_PROPS(HIP)
+ .BIND_LANG_PROPS(OBJC)
+ .BIND_LANG_PROPS(OBJCXX)
+ /* keep semicolon on own line */;
+
+auto const TryRunArgParser =
+ cmArgumentParser<Arguments>{ TryCompileArgParser }
+ .Bind("COMPILE_OUTPUT_VARIABLE"_s, &Arguments::CompileOutputVariable)
+ .Bind("RUN_OUTPUT_VARIABLE"_s, &Arguments::RunOutputVariable)
+ .Bind("RUN_OUTPUT_STDOUT_VARIABLE"_s, &Arguments::RunOutputStdOutVariable)
+ .Bind("RUN_OUTPUT_STDERR_VARIABLE"_s, &Arguments::RunOutputStdErrVariable)
+ .Bind("WORKING_DIRECTORY"_s, &Arguments::RunWorkingDirectory)
+ .Bind("ARGS"_s, &Arguments::RunArgs)
+ /* keep semicolon on own line */;
+
+#undef BIND_LANG_PROPS
+}
+
+Arguments cmCoreTryCompile::ParseArgs(
+ cmRange<std::vector<std::string>::const_iterator> args, bool isTryRun)
+{
+ std::vector<std::string> unparsedArguments;
+ const auto& parser = (isTryRun ? TryRunArgParser : TryCompileArgParser);
+ auto arguments = parser.Parse(args, &unparsedArguments, 0);
+ if (!arguments.MaybeReportError(*(this->Makefile)) &&
+ !unparsedArguments.empty()) {
+ std::string m = "Unknown arguments:";
+ for (const auto& i : unparsedArguments) {
+ m = cmStrCat(m, "\n \"", i, "\"");
+ }
+ this->Makefile->IssueMessage(MessageType::AUTHOR_WARNING, m);
+ }
+ // For historical reasons, treat some empty-valued keyword
+ // arguments as if they were not specified at all.
+ if (arguments.OutputVariable && arguments.OutputVariable->empty()) {
+ arguments.OutputVariable = cm::nullopt;
+ }
+ if (isTryRun) {
+ if (arguments.CompileOutputVariable &&
+ arguments.CompileOutputVariable->empty()) {
+ arguments.CompileOutputVariable = cm::nullopt;
+ }
+ if (arguments.RunOutputVariable && arguments.RunOutputVariable->empty()) {
+ arguments.RunOutputVariable = cm::nullopt;
+ }
+ if (arguments.RunOutputStdOutVariable &&
+ arguments.RunOutputStdOutVariable->empty()) {
+ arguments.RunOutputStdOutVariable = cm::nullopt;
+ }
+ if (arguments.RunOutputStdErrVariable &&
+ arguments.RunOutputStdErrVariable->empty()) {
+ arguments.RunOutputStdErrVariable = cm::nullopt;
+ }
+ if (arguments.RunWorkingDirectory &&
+ arguments.RunWorkingDirectory->empty()) {
+ arguments.RunWorkingDirectory = cm::nullopt;
+ }
+ }
+ return arguments;
}
-int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
- bool isTryRun)
+bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
+ cmStateEnums::TargetType targetType)
{
- this->BinaryDirectory = argv[1];
this->OutputFile.clear();
// which signature were we called with ?
this->SrcFileSignature = true;
- cmStateEnums::TargetType targetType = cmStateEnums::EXECUTABLE;
- cmValue tt = this->Makefile->GetDefinition("CMAKE_TRY_COMPILE_TARGET_TYPE");
- if (!isTryRun && cmNonempty(tt)) {
- if (*tt == cmState::GetTargetTypeName(cmStateEnums::EXECUTABLE)) {
- targetType = cmStateEnums::EXECUTABLE;
- } else if (*tt ==
- cmState::GetTargetTypeName(cmStateEnums::STATIC_LIBRARY)) {
- targetType = cmStateEnums::STATIC_LIBRARY;
- } else {
+ std::string sourceDirectory;
+ std::string projectName;
+ std::string targetName;
+ if (arguments.SourceDirectoryOrFile && arguments.ProjectName) {
+ this->SrcFileSignature = false;
+ sourceDirectory = *arguments.SourceDirectoryOrFile;
+ projectName = *arguments.ProjectName;
+ if (arguments.TargetName) {
+ targetName = *arguments.TargetName;
+ }
+ } else {
+ projectName = "CMAKE_TRY_COMPILE";
+ /* Use a random file name to avoid rapid creation and deletion
+ of the same executable name (some filesystems fail on that). */
+ char targetNameBuf[64];
+ snprintf(targetNameBuf, sizeof(targetNameBuf), "cmTC_%05x",
+ cmSystemTools::RandomSeed() & 0xFFFFF);
+ targetName = targetNameBuf;
+ }
+
+ if (arguments.BinaryDirectory && !arguments.BinaryDirectory->empty()) {
+ if (!cmSystemTools::FileIsFullPath(*arguments.BinaryDirectory)) {
this->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
- cmStrCat("Invalid value '", *tt,
- "' for CMAKE_TRY_COMPILE_TARGET_TYPE. Only '",
- cmState::GetTargetTypeName(cmStateEnums::EXECUTABLE),
- "' and '",
- cmState::GetTargetTypeName(cmStateEnums::STATIC_LIBRARY),
- "' are allowed."));
- return -1;
+ cmStrCat("<bindir> is not an absolute path:\n '",
+ *arguments.BinaryDirectory, "'"));
+ return false;
+ }
+ this->BinaryDirectory = *arguments.BinaryDirectory;
+ // compute the binary dir when TRY_COMPILE is called with a src file
+ // signature
+ if (this->SrcFileSignature) {
+ this->BinaryDirectory += "/CMakeFiles/CMakeTmp";
}
+ } else {
+ this->Makefile->IssueMessage(MessageType::FATAL_ERROR,
+ "No <bindir> specified.");
+ return false;
}
- std::string sourceDirectory = argv[2];
- std::string projectName;
- std::string targetName;
- std::vector<std::string> cmakeFlags(1, "CMAKE_FLAGS"); // fake argv[0]
- std::vector<std::string> compileDefs;
- std::string cmakeInternal;
- std::string outputVariable;
- std::string copyFile;
- std::string copyFileError;
- LanguageStandardState cState("C");
- LanguageStandardState cudaState("CUDA");
- LanguageStandardState cxxState("CXX");
- LanguageStandardState hipState("HIP");
- LanguageStandardState objcState("OBJC");
- LanguageStandardState objcxxState("OBJCXX");
std::vector<std::string> targets;
- std::vector<std::string> linkOptions;
- std::string libsToLink = " ";
- bool useOldLinkLibs = true;
- char targetNameBuf[64];
- bool didOutputVariable = false;
- bool didCopyFile = false;
- bool didCopyFileError = false;
- bool useSources = argv[2] == "SOURCES";
- std::vector<std::string> sources;
-
- enum Doing
- {
- DoingNone,
- DoingCMakeFlags,
- DoingCompileDefinitions,
- DoingLinkOptions,
- DoingLinkLibraries,
- DoingOutputVariable,
- DoingCopyFile,
- DoingCopyFileError,
- DoingSources,
- DoingCMakeInternal
- };
- Doing doing = useSources ? DoingSources : DoingNone;
- for (size_t i = 3; i < argv.size(); ++i) {
- if (argv[i] == "CMAKE_FLAGS") {
- doing = DoingCMakeFlags;
- } else if (argv[i] == "COMPILE_DEFINITIONS") {
- doing = DoingCompileDefinitions;
- } else if (argv[i] == "LINK_OPTIONS") {
- doing = DoingLinkOptions;
- } else if (argv[i] == "LINK_LIBRARIES") {
- doing = DoingLinkLibraries;
- useOldLinkLibs = false;
- } else if (argv[i] == "OUTPUT_VARIABLE") {
- doing = DoingOutputVariable;
- didOutputVariable = true;
- } else if (argv[i] == "COPY_FILE") {
- doing = DoingCopyFile;
- didCopyFile = true;
- } else if (argv[i] == "COPY_FILE_ERROR") {
- doing = DoingCopyFileError;
- didCopyFileError = true;
- } else if (cState.UpdateIfMatches(argv, i) ||
- cxxState.UpdateIfMatches(argv, i) ||
- cudaState.UpdateIfMatches(argv, i) ||
- hipState.UpdateIfMatches(argv, i) ||
- objcState.UpdateIfMatches(argv, i) ||
- objcxxState.UpdateIfMatches(argv, i)) {
- continue;
- } else if (argv[i] == "__CMAKE_INTERNAL") {
- doing = DoingCMakeInternal;
- } else if (doing == DoingCMakeFlags) {
- cmakeFlags.emplace_back(argv[i]);
- } else if (doing == DoingCompileDefinitions) {
- cmExpandList(argv[i], compileDefs);
- } else if (doing == DoingLinkOptions) {
- linkOptions.emplace_back(argv[i]);
- } else if (doing == DoingLinkLibraries) {
- libsToLink += "\"" + cmTrimWhitespace(argv[i]) + "\" ";
- if (cmTarget* tgt = this->Makefile->FindTargetToUse(argv[i])) {
+ if (arguments.LinkLibraries) {
+ for (std::string const& i : *arguments.LinkLibraries) {
+ if (cmTarget* tgt = this->Makefile->FindTargetToUse(i)) {
switch (tgt->GetType()) {
case cmStateEnums::SHARED_LIBRARY:
case cmStateEnums::STATIC_LIBRARY:
@@ -359,110 +272,62 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
"IMPORTED LINK_LIBRARIES. Got ",
tgt->GetName(), " of type ",
cmState::GetTargetTypeName(tgt->GetType()), "."));
- return -1;
+ return false;
}
if (tgt->IsImported()) {
- targets.emplace_back(argv[i]);
+ targets.emplace_back(i);
}
}
- } else if (doing == DoingOutputVariable) {
- outputVariable = argv[i];
- doing = DoingNone;
- } else if (doing == DoingCopyFile) {
- copyFile = argv[i];
- doing = DoingNone;
- } else if (doing == DoingCopyFileError) {
- copyFileError = argv[i];
- doing = DoingNone;
- } else if (doing == DoingSources) {
- sources.emplace_back(argv[i]);
- } else if (doing == DoingCMakeInternal) {
- cmakeInternal = argv[i];
- doing = DoingNone;
- } else if (i == 3) {
- this->SrcFileSignature = false;
- projectName = argv[i];
- } else if (i == 4 && !this->SrcFileSignature) {
- targetName = argv[i];
- } else {
- std::ostringstream m;
- m << "try_compile given unknown argument \"" << argv[i] << "\".";
- this->Makefile->IssueMessage(MessageType::AUTHOR_WARNING, m.str());
}
}
- if (didCopyFile && copyFile.empty()) {
+ if (arguments.CopyFileTo && arguments.CopyFileTo->empty()) {
this->Makefile->IssueMessage(MessageType::FATAL_ERROR,
"COPY_FILE must be followed by a file path");
- return -1;
+ return false;
}
- if (didCopyFileError && copyFileError.empty()) {
+ if (arguments.CopyFileError && arguments.CopyFileError->empty()) {
this->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
"COPY_FILE_ERROR must be followed by a variable name");
- return -1;
+ return false;
}
- if (didCopyFileError && !didCopyFile) {
+ if (arguments.CopyFileError && !arguments.CopyFileTo) {
this->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
"COPY_FILE_ERROR may be used only with COPY_FILE");
- return -1;
- }
-
- if (didOutputVariable && outputVariable.empty()) {
- this->Makefile->IssueMessage(
- MessageType::FATAL_ERROR,
- "OUTPUT_VARIABLE must be followed by a variable name");
- return -1;
+ return false;
}
- if (useSources && sources.empty()) {
+ if (arguments.Sources && arguments.Sources->empty()) {
this->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
"SOURCES must be followed by at least one source file");
- return -1;
+ return false;
}
+ // only valid for srcfile signatures
if (!this->SrcFileSignature) {
- if (!cState.Validate(this->Makefile)) {
- return -1;
- }
- if (!cudaState.Validate(this->Makefile)) {
- return -1;
- }
- if (!hipState.Validate(this->Makefile)) {
- return -1;
- }
- if (!cxxState.Validate(this->Makefile)) {
- return -1;
- }
- if (!objcState.Validate(this->Makefile)) {
- return -1;
- }
- if (!objcxxState.Validate(this->Makefile)) {
- return -1;
+ if (!arguments.LangProps.empty()) {
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat(arguments.LangProps.begin()->first,
+ " allowed only in source file signature."));
+ return false;
}
- }
-
- // compute the binary dir when TRY_COMPILE is called with a src file
- // signature
- if (this->SrcFileSignature) {
- this->BinaryDirectory += "/CMakeFiles/CMakeTmp";
- } else {
- // only valid for srcfile signatures
- if (!compileDefs.empty()) {
+ if (!arguments.CompileDefs.empty()) {
this->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
"COMPILE_DEFINITIONS specified on a srcdir type TRY_COMPILE");
- return -1;
+ return false;
}
- if (!copyFile.empty()) {
+ if (arguments.CopyFileTo) {
this->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
"COPY_FILE specified on a srcdir type TRY_COMPILE");
- return -1;
+ return false;
}
}
// make sure the binary directory exists
@@ -474,7 +339,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
e << "Attempt at a recursive or nested TRY_COMPILE in directory\n"
<< " " << this->BinaryDirectory << "\n";
this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
- return -1;
+ return false;
}
std::string outFileName = this->BinaryDirectory + "/CMakeLists.txt";
@@ -485,8 +350,12 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
cmSystemTools::RemoveFile(ccFile);
// Choose sources.
- if (!useSources) {
- sources.emplace_back(argv[2]);
+ std::vector<std::string> sources;
+ if (arguments.Sources) {
+ sources = std::move(*arguments.Sources);
+ } else {
+ // TODO: ensure SourceDirectoryOrFile has a value
+ sources.emplace_back(*arguments.SourceDirectoryOrFile);
}
// Detect languages to enable.
@@ -508,7 +377,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
err << cmJoin(langs, " ");
err << "\nSee project() command to enable other languages.";
this->Makefile->IssueMessage(MessageType::FATAL_ERROR, err.str());
- return -1;
+ return false;
}
}
@@ -535,7 +404,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
<< cmSystemTools::GetLastSystemError();
/* clang-format on */
this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
- return -1;
+ return false;
}
cmValue def = this->Makefile->GetDefinition("CMAKE_MODULE_PATH");
@@ -598,13 +467,22 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
}
}
fprintf(fout, "project(CMAKE_TRY_COMPILE%s)\n", projectLangs.c_str());
- if (cmakeInternal == "ABI") {
+ if (arguments.CMakeInternal == "ABI") {
// This is the ABI detection step, also used for implicit includes.
// Erase any include_directories() calls from the toolchain file so
// that we do not see them as implicit. Our ABI detection source
// does not include any system headers anyway.
fprintf(fout,
"set_property(DIRECTORY PROPERTY INCLUDE_DIRECTORIES \"\")\n");
+
+ // The link and compile lines for ABI detection step need to not use
+ // response files so we can extract implicit includes given to
+ // the underlying host compiler
+ if (testLangs.find("CUDA") != testLangs.end()) {
+ fprintf(fout, "set(CMAKE_CUDA_USE_RESPONSE_FILE_FOR_INCLUDES OFF)\n");
+ fprintf(fout, "set(CMAKE_CUDA_USE_RESPONSE_FILE_FOR_LIBRARIES OFF)\n");
+ fprintf(fout, "set(CMAKE_CUDA_USE_RESPONSE_FILE_FOR_OBJECTS OFF)\n");
+ }
}
fprintf(fout, "set(CMAKE_VERBOSE_MAKEFILE 1)\n");
for (std::string const& li : testLangs) {
@@ -696,18 +574,12 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
fprintf(fout, "set(CMAKE_SUPPRESS_REGENERATION 1)\n");
fprintf(fout, "link_directories(${LINK_DIRECTORIES})\n");
// handle any compile flags we need to pass on
- if (!compileDefs.empty()) {
+ if (!arguments.CompileDefs.empty()) {
// Pass using bracket arguments to preserve content.
fprintf(fout, "add_definitions([==[%s]==])\n",
- cmJoin(compileDefs, "]==] [==[").c_str());
+ cmJoin(arguments.CompileDefs, "]==] [==[").c_str());
}
- /* Use a random file name to avoid rapid creation and deletion
- of the same executable name (some filesystems fail on that). */
- snprintf(targetNameBuf, sizeof(targetNameBuf), "cmTC_%05x",
- cmSystemTools::RandomSeed() & 0xFFFFF);
- targetName = targetNameBuf;
-
if (!targets.empty()) {
std::string fname = "/" + std::string(targetName) + "Targets.cmake";
cmExportTryCompileFileGenerator tcfg(gg, targets, this->Makefile,
@@ -719,7 +591,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
this->Makefile->IssueMessage(MessageType::FATAL_ERROR,
"could not write export file.");
fclose(fout);
- return -1;
+ return false;
}
fprintf(fout, "\ninclude(\"${CMAKE_CURRENT_LIST_DIR}/%s\")\n\n",
fname.c_str());
@@ -769,18 +641,10 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
}
fprintf(fout, ")\n");
- cState.Enabled(testLangs.find("C") != testLangs.end());
- cxxState.Enabled(testLangs.find("CXX") != testLangs.end());
- cudaState.Enabled(testLangs.find("CUDA") != testLangs.end());
- hipState.Enabled(testLangs.find("HIP") != testLangs.end());
- objcState.Enabled(testLangs.find("OBJC") != testLangs.end());
- objcxxState.Enabled(testLangs.find("OBJCXX") != testLangs.end());
-
bool warnCMP0067 = false;
bool honorStandard = true;
- if (cState.DidNone() && cxxState.DidNone() && objcState.DidNone() &&
- objcxxState.DidNone() && cudaState.DidNone() && hipState.DidNone()) {
+ if (arguments.LangProps.empty()) {
switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0067)) {
case cmPolicies::WARN:
warnCMP0067 = this->Makefile->PolicyOptionalWarningEnabled(
@@ -805,18 +669,33 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
std::vector<std::string> warnCMP0067Variables;
- cState.LoadUnsetPropertyValues(this->Makefile, honorStandard, warnCMP0067,
- warnCMP0067Variables);
- cxxState.LoadUnsetPropertyValues(this->Makefile, honorStandard,
- warnCMP0067, warnCMP0067Variables);
- cudaState.LoadUnsetPropertyValues(this->Makefile, honorStandard,
- warnCMP0067, warnCMP0067Variables);
- hipState.LoadUnsetPropertyValues(this->Makefile, honorStandard,
- warnCMP0067, warnCMP0067Variables);
- objcState.LoadUnsetPropertyValues(this->Makefile, honorStandard,
- warnCMP0067, warnCMP0067Variables);
- objcxxState.LoadUnsetPropertyValues(this->Makefile, honorStandard,
- warnCMP0067, warnCMP0067Variables);
+ if (honorStandard || warnCMP0067) {
+ static std::array<std::string, 6> const possibleLangs{
+ { "C", "CXX", "CUDA", "HIP", "OBJC", "OBJCXX" }
+ };
+ static std::array<cm::string_view, 3> const langPropSuffixes{
+ { "_STANDARD"_s, "_STANDARD_REQUIRED"_s, "_EXTENSIONS"_s }
+ };
+ for (std::string const& lang : possibleLangs) {
+ if (testLangs.find(lang) == testLangs.end()) {
+ continue;
+ }
+ for (cm::string_view propSuffix : langPropSuffixes) {
+ std::string langProp = cmStrCat(lang, propSuffix);
+ if (!arguments.LangProps.count(langProp)) {
+ std::string langPropVar = cmStrCat("CMAKE_"_s, langProp);
+ std::string value = this->Makefile->GetSafeDefinition(langPropVar);
+ if (warnCMP0067 && !value.empty()) {
+ value.clear();
+ warnCMP0067Variables.emplace_back(langPropVar);
+ }
+ if (!value.empty()) {
+ arguments.LangProps[langProp] = value;
+ }
+ }
+ }
+ }
+ }
if (!warnCMP0067Variables.empty()) {
std::ostringstream w;
@@ -832,17 +711,20 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
this->Makefile->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
}
- cState.WriteProperties(fout, targetName);
- cxxState.WriteProperties(fout, targetName);
- cudaState.WriteProperties(fout, targetName);
- hipState.WriteProperties(fout, targetName);
- objcState.WriteProperties(fout, targetName);
- objcxxState.WriteProperties(fout, targetName);
+ for (auto const& p : arguments.LangProps) {
+ if (p.second.empty()) {
+ continue;
+ }
+ fprintf(fout, "set_property(TARGET %s PROPERTY %s %s)\n",
+ targetName.c_str(),
+ cmOutputConverter::EscapeForCMake(p.first).c_str(),
+ cmOutputConverter::EscapeForCMake(p.second).c_str());
+ }
- if (!linkOptions.empty()) {
+ if (!arguments.LinkOptions.empty()) {
std::vector<std::string> options;
- options.reserve(linkOptions.size());
- for (const auto& option : linkOptions) {
+ options.reserve(arguments.LinkOptions.size());
+ for (const auto& option : arguments.LinkOptions) {
options.emplace_back(cmOutputConverter::EscapeForCMake(option));
}
@@ -856,15 +738,18 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
}
}
- if (useOldLinkLibs) {
- fprintf(fout, "target_link_libraries(%s ${LINK_LIBRARIES})\n",
- targetName.c_str());
- } else {
+ if (arguments.LinkLibraries) {
+ std::string libsToLink = " ";
+ for (std::string const& i : *arguments.LinkLibraries) {
+ libsToLink += "\"" + cmTrimWhitespace(i) + "\" ";
+ }
fprintf(fout, "target_link_libraries(%s %s)\n", targetName.c_str(),
libsToLink.c_str());
+ } else {
+ fprintf(fout, "target_link_libraries(%s ${LINK_LIBRARIES})\n",
+ targetName.c_str());
}
fclose(fout);
- projectName = "CMAKE_TRY_COMPILE";
}
// Forward a set of variables to the inner project cache.
@@ -953,13 +838,13 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
kCMAKE_TRY_COMPILE_OSX_ARCHITECTURES)) {
vars.erase(kCMAKE_OSX_ARCHITECTURES);
std::string flag = "-DCMAKE_OSX_ARCHITECTURES=" + *tcArchs;
- cmakeFlags.emplace_back(std::move(flag));
+ arguments.CMakeFlags.emplace_back(std::move(flag));
}
for (std::string const& var : vars) {
if (cmValue val = this->Makefile->GetDefinition(var)) {
std::string flag = "-D" + var + "=" + *val;
- cmakeFlags.emplace_back(std::move(flag));
+ arguments.CMakeFlags.emplace_back(std::move(flag));
}
}
}
@@ -969,7 +854,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
for (std::string const& var : ghs_platform_vars) {
if (cmValue val = this->Makefile->GetDefinition(var)) {
std::string flag = "-D" + var + "=" + "'" + *val + "'";
- cmakeFlags.emplace_back(std::move(flag));
+ arguments.CMakeFlags.emplace_back(std::move(flag));
}
}
}
@@ -980,26 +865,27 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
// actually do the try compile now that everything is setup
int res = this->Makefile->TryCompile(
sourceDirectory, this->BinaryDirectory, projectName, targetName,
- this->SrcFileSignature, cmake::NO_BUILD_PARALLEL_LEVEL, &cmakeFlags,
- output);
+ this->SrcFileSignature, cmake::NO_BUILD_PARALLEL_LEVEL,
+ &arguments.CMakeFlags, output);
if (erroroc) {
cmSystemTools::SetErrorOccurred();
}
// set the result var to the return value to indicate success or failure
- this->Makefile->AddCacheDefinition(argv[0], (res == 0 ? "TRUE" : "FALSE"),
- "Result of TRY_COMPILE",
- cmStateEnums::INTERNAL);
+ this->Makefile->AddCacheDefinition(
+ *arguments.CompileResultVariable, (res == 0 ? "TRUE" : "FALSE"),
+ "Result of TRY_COMPILE", cmStateEnums::INTERNAL);
- if (!outputVariable.empty()) {
- this->Makefile->AddDefinition(outputVariable, output);
+ if (arguments.OutputVariable) {
+ this->Makefile->AddDefinition(*arguments.OutputVariable, output);
}
if (this->SrcFileSignature) {
std::string copyFileErrorMessage;
this->FindOutputFile(targetName, targetType);
- if ((res == 0) && !copyFile.empty()) {
+ if ((res == 0) && arguments.CopyFileTo) {
+ std::string const& copyFile = *arguments.CopyFileTo;
if (this->OutputFile.empty() ||
!cmSystemTools::CopyFileAlways(this->OutputFile, copyFile)) {
std::ostringstream emsg;
@@ -1012,19 +898,20 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
if (!this->FindErrorMessage.empty()) {
emsg << this->FindErrorMessage;
}
- if (copyFileError.empty()) {
+ if (!arguments.CopyFileError) {
this->Makefile->IssueMessage(MessageType::FATAL_ERROR, emsg.str());
- return -1;
+ return false;
}
copyFileErrorMessage = emsg.str();
}
}
- if (!copyFileError.empty()) {
+ if (arguments.CopyFileError) {
+ std::string const& copyFileError = *arguments.CopyFileError;
this->Makefile->AddDefinition(copyFileError, copyFileErrorMessage);
}
}
- return res;
+ return res == 0;
}
void cmCoreTryCompile::CleanupFiles(std::string const& binDir)
@@ -1117,7 +1004,8 @@ void cmCoreTryCompile::FindOutputFile(const std::string& targetName,
searchDirs.emplace_back(std::move(tmp));
}
searchDirs.emplace_back("/Debug");
-#if defined(__APPLE__)
+
+ // handle app-bundles (for targeting apple-platforms)
std::string app = "/" + targetName + ".app";
if (cmNonempty(config)) {
std::string tmp = cmStrCat('/', *config, app);
@@ -1126,7 +1014,7 @@ void cmCoreTryCompile::FindOutputFile(const std::string& targetName,
std::string tmp = "/Debug" + app;
searchDirs.emplace_back(std::move(tmp));
searchDirs.emplace_back(std::move(app));
-#endif
+
searchDirs.emplace_back("/Development");
for (std::string const& sdir : searchDirs) {
diff --git a/Source/cmCoreTryCompile.h b/Source/cmCoreTryCompile.h
index 594fd7f..deefe57 100644
--- a/Source/cmCoreTryCompile.h
+++ b/Source/cmCoreTryCompile.h
@@ -4,28 +4,75 @@
#include "cmConfigure.h" // IWYU pragma: keep
+#include <map>
#include <string>
#include <vector>
-#include "cmCommand.h"
+#include <cm/optional>
+
+#include "cmArgumentParser.h"
+#include "cmArgumentParserTypes.h"
#include "cmStateTypes.h"
+class cmMakefile;
+template <typename Iter>
+class cmRange;
+
/** \class cmCoreTryCompile
* \brief Base class for cmTryCompileCommand and cmTryRunCommand
*
* cmCoreTryCompile implements the functionality to build a program.
* It is the base class for cmTryCompileCommand and cmTryRunCommand.
*/
-class cmCoreTryCompile : public cmCommand
+class cmCoreTryCompile
{
public:
-protected:
+ cmCoreTryCompile(cmMakefile* mf)
+ : Makefile(mf)
+ {
+ }
+
+ struct Arguments : public ArgumentParser::ParseResult
+ {
+ cm::optional<std::string> CompileResultVariable;
+ cm::optional<std::string> BinaryDirectory;
+ cm::optional<std::string> SourceDirectoryOrFile;
+ cm::optional<std::string> ProjectName;
+ cm::optional<std::string> TargetName;
+ cm::optional<ArgumentParser::NonEmpty<std::vector<std::string>>> Sources;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> CMakeFlags{
+ 1, "CMAKE_FLAGS"
+ }; // fake argv[0]
+ std::vector<std::string> CompileDefs;
+ cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>>
+ LinkLibraries;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> LinkOptions;
+ std::map<std::string, std::string> LangProps;
+ std::string CMakeInternal;
+ cm::optional<std::string> OutputVariable;
+ cm::optional<std::string> CopyFileTo;
+ cm::optional<std::string> CopyFileError;
+
+ // Argument for try_run only.
+ // Keep in sync with warnings in cmCoreTryCompile::ParseArgs.
+ cm::optional<std::string> CompileOutputVariable;
+ cm::optional<std::string> RunOutputVariable;
+ cm::optional<std::string> RunOutputStdOutVariable;
+ cm::optional<std::string> RunOutputStdErrVariable;
+ cm::optional<std::string> RunWorkingDirectory;
+ cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>> RunArgs;
+ };
+
+ Arguments ParseArgs(cmRange<std::vector<std::string>::const_iterator> args,
+ bool isTryRun);
+
/**
* This is the core code for try compile. It is here so that other
* commands, such as TryRun can access the same logic without
* duplication.
*/
- int TryCompileCode(std::vector<std::string> const& argv, bool isTryRun);
+ bool TryCompileCode(Arguments& arguments,
+ cmStateEnums::TargetType targetType);
/**
* This deletes all the files created by TryCompileCode.
@@ -46,4 +93,5 @@ protected:
std::string OutputFile;
std::string FindErrorMessage;
bool SrcFileSignature = false;
+ cmMakefile* Makefile;
};
diff --git a/Source/cmCreateTestSourceList.cxx b/Source/cmCreateTestSourceList.cxx
index 2a52d1a..75c25e3 100644
--- a/Source/cmCreateTestSourceList.cxx
+++ b/Source/cmCreateTestSourceList.cxx
@@ -87,9 +87,7 @@ bool cmCreateTestSourceList(std::vector<std::string> const& args,
func_name = cmSystemTools::GetFilenameWithoutLastExtension(*i);
}
cmSystemTools::ConvertToUnixSlashes(func_name);
- std::replace(func_name.begin(), func_name.end(), ' ', '_');
- std::replace(func_name.begin(), func_name.end(), '/', '_');
- std::replace(func_name.begin(), func_name.end(), ':', '_');
+ func_name = cmSystemTools::MakeCidentifier(func_name);
bool already_declared =
std::find(tests_func_name.begin(), tests_func_name.end(), func_name) !=
tests_func_name.end();
diff --git a/Source/cmCxxModuleMapper.cxx b/Source/cmCxxModuleMapper.cxx
new file mode 100644
index 0000000..84691c9
--- /dev/null
+++ b/Source/cmCxxModuleMapper.cxx
@@ -0,0 +1,308 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCxxModuleMapper.h"
+
+#include <cassert>
+#include <cstddef>
+#include <set>
+#include <sstream>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <cm/string_view>
+#include <cmext/string_view>
+
+#include "cmScanDepFormat.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+cm::optional<std::string> CxxModuleLocations::BmiGeneratorPathForModule(
+ std::string const& logical_name) const
+{
+ if (auto l = this->BmiLocationForModule(logical_name)) {
+ return this->PathForGenerator(*l);
+ }
+ return {};
+}
+
+namespace {
+
+std::string CxxModuleMapContentGcc(CxxModuleLocations const& loc,
+ cmScanDepInfo const& obj)
+{
+ std::stringstream mm;
+
+ // 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 " << loc.RootDirectory << "\n";
+
+ for (auto const& p : obj.Provides) {
+ if (auto bmi_loc = loc.BmiGeneratorPathForModule(p.LogicalName)) {
+ mm << p.LogicalName << ' ' << *bmi_loc << '\n';
+ }
+ }
+ for (auto const& r : obj.Requires) {
+ if (auto bmi_loc = loc.BmiGeneratorPathForModule(r.LogicalName)) {
+ mm << r.LogicalName << ' ' << *bmi_loc << '\n';
+ }
+ }
+
+ return mm.str();
+}
+
+std::string CxxModuleMapContentMsvc(CxxModuleLocations const& loc,
+ cmScanDepInfo const& obj,
+ CxxModuleUsage const& usages)
+{
+ std::stringstream mm;
+
+ // A response file of `-reference NAME=PATH` arguments.
+
+ // MSVC's command line only supports a single output. If more than one is
+ // expected, we cannot make a useful module map file.
+ if (obj.Provides.size() > 1) {
+ return {};
+ }
+
+ auto flag_for_method = [](LookupMethod method) -> cm::static_string_view {
+ switch (method) {
+ case LookupMethod::ByName:
+ return "-reference"_s;
+ case LookupMethod::IncludeAngle:
+ return "-headerUnit:angle"_s;
+ case LookupMethod::IncludeQuote:
+ return "-headerUnit:quote"_s;
+ }
+ assert(false && "unsupported lookup method");
+ return ""_s;
+ };
+
+ for (auto const& p : obj.Provides) {
+ if (p.IsInterface) {
+ mm << "-interface\n";
+ } else {
+ mm << "-internalPartition\n";
+ }
+
+ if (auto bmi_loc = loc.BmiGeneratorPathForModule(p.LogicalName)) {
+ mm << "-ifcOutput " << *bmi_loc << '\n';
+ }
+ }
+
+ std::set<std::string> transitive_usage_directs;
+ std::set<std::string> transitive_usage_names;
+
+ for (auto const& r : obj.Requires) {
+ if (auto bmi_loc = loc.BmiGeneratorPathForModule(r.LogicalName)) {
+ auto flag = flag_for_method(r.Method);
+
+ mm << flag << ' ' << r.LogicalName << '=' << *bmi_loc << "\n";
+ transitive_usage_directs.insert(r.LogicalName);
+
+ // Insert transitive usages.
+ auto transitive_usages = usages.Usage.find(r.LogicalName);
+ if (transitive_usages != usages.Usage.end()) {
+ transitive_usage_names.insert(transitive_usages->second.begin(),
+ transitive_usages->second.end());
+ }
+ }
+ }
+
+ for (auto const& transitive_name : transitive_usage_names) {
+ if (transitive_usage_directs.count(transitive_name)) {
+ continue;
+ }
+
+ auto module_ref = usages.Reference.find(transitive_name);
+ if (module_ref != usages.Reference.end()) {
+ auto flag = flag_for_method(module_ref->second.Method);
+ mm << flag << ' ' << transitive_name << '=' << module_ref->second.Path
+ << "\n";
+ }
+ }
+
+ return mm.str();
+}
+}
+
+bool CxxModuleUsage::AddReference(std::string const& logical,
+ std::string const& loc, LookupMethod method)
+{
+ auto r = this->Reference.find(logical);
+ if (r != this->Reference.end()) {
+ auto& ref = r->second;
+
+ if (ref.Path == loc && ref.Method == method) {
+ return true;
+ }
+
+ auto method_name = [](LookupMethod m) -> cm::static_string_view {
+ switch (m) {
+ case LookupMethod::ByName:
+ return "by-name"_s;
+ case LookupMethod::IncludeAngle:
+ return "include-angle"_s;
+ case LookupMethod::IncludeQuote:
+ return "include-quote"_s;
+ }
+ assert(false && "unsupported lookup method");
+ return ""_s;
+ };
+
+ cmSystemTools::Error(cmStrCat("Disagreement of the location of the '",
+ logical,
+ "' module. "
+ "Location A: '",
+ ref.Path, "' via ", method_name(ref.Method),
+ "; "
+ "Location B: '",
+ loc, "' via ", method_name(method), "."));
+ return false;
+ }
+
+ auto& ref = this->Reference[logical];
+ ref.Path = loc;
+ ref.Method = method;
+
+ return true;
+}
+
+cm::static_string_view CxxModuleMapExtension(
+ cm::optional<CxxModuleMapFormat> format)
+{
+ if (format) {
+ switch (*format) {
+ case CxxModuleMapFormat::Gcc:
+ return ".gcm"_s;
+ case CxxModuleMapFormat::Msvc:
+ return ".ifc"_s;
+ }
+ }
+
+ return ".bmi"_s;
+}
+
+std::set<std::string> CxxModuleUsageSeed(
+ CxxModuleLocations const& loc, std::vector<cmScanDepInfo> const& objects,
+ CxxModuleUsage& usages)
+{
+ // Track inner usages to populate usages from internal bits.
+ //
+ // This is a map of modules that required some other module that was not
+ // found to those that were not found.
+ std::map<std::string, std::set<std::string>> internal_usages;
+ std::set<std::string> unresolved;
+
+ for (cmScanDepInfo const& object : objects) {
+ // Add references for each of the provided modules.
+ for (auto const& p : object.Provides) {
+ if (auto bmi_loc = loc.BmiGeneratorPathForModule(p.LogicalName)) {
+ // XXX(cxx-modules): How to support header units?
+ usages.AddReference(p.LogicalName, loc.PathForGenerator(*bmi_loc),
+ LookupMethod::ByName);
+ }
+ }
+
+ // For each requires, pull in what is required.
+ for (auto const& r : object.Requires) {
+ // Find transitive usages.
+ auto transitive_usages = usages.Usage.find(r.LogicalName);
+ // Find the required name in the current target.
+ auto bmi_loc = loc.BmiGeneratorPathForModule(r.LogicalName);
+
+ for (auto const& p : object.Provides) {
+ auto& this_usages = usages.Usage[p.LogicalName];
+
+ // Add the direct usage.
+ this_usages.insert(r.LogicalName);
+
+ // Add the transitive usage.
+ if (transitive_usages != usages.Usage.end()) {
+ this_usages.insert(transitive_usages->second.begin(),
+ transitive_usages->second.end());
+ } else if (bmi_loc) {
+ // Mark that we need to update transitive usages later.
+ internal_usages[p.LogicalName].insert(r.LogicalName);
+ }
+ }
+
+ if (bmi_loc) {
+ usages.AddReference(r.LogicalName, loc.PathForGenerator(*bmi_loc),
+ r.Method);
+ }
+ }
+ }
+
+ // While we have internal usages to manage.
+ while (!internal_usages.empty()) {
+ size_t starting_size = internal_usages.size();
+
+ // For each internal usage.
+ for (auto usage = internal_usages.begin(); usage != internal_usages.end();
+ /* see end of loop */) {
+ auto& this_usages = usages.Usage[usage->first];
+
+ for (auto use = usage->second.begin(); use != usage->second.end();
+ /* see end of loop */) {
+ // Check if this required module uses other internal modules; defer
+ // if so.
+ if (internal_usages.count(*use)) {
+ // Advance the iterator.
+ ++use;
+ continue;
+ }
+
+ auto transitive_usages = usages.Usage.find(*use);
+ if (transitive_usages != usages.Usage.end()) {
+ this_usages.insert(transitive_usages->second.begin(),
+ transitive_usages->second.end());
+ }
+
+ // Remove the entry and advance the iterator.
+ use = usage->second.erase(use);
+ }
+
+ // Erase the entry if it doesn't have any remaining usages.
+ if (usage->second.empty()) {
+ usage = internal_usages.erase(usage);
+ } else {
+ ++usage;
+ }
+ }
+
+ // Check that at least one usage was resolved.
+ if (starting_size == internal_usages.size()) {
+ // Nothing could be resolved this loop; we have a cycle, so record the
+ // cycle and exit.
+ for (auto const& usage : internal_usages) {
+ unresolved.insert(usage.first);
+ }
+ break;
+ }
+ }
+
+ return unresolved;
+}
+
+std::string CxxModuleMapContent(CxxModuleMapFormat format,
+ CxxModuleLocations const& loc,
+ cmScanDepInfo const& obj,
+ CxxModuleUsage const& usages)
+{
+ switch (format) {
+ case CxxModuleMapFormat::Gcc:
+ return CxxModuleMapContentGcc(loc, obj);
+ case CxxModuleMapFormat::Msvc:
+ return CxxModuleMapContentMsvc(loc, obj, usages);
+ }
+
+ assert(false);
+ return {};
+}
diff --git a/Source/cmCxxModuleMapper.h b/Source/cmCxxModuleMapper.h
new file mode 100644
index 0000000..8526a07
--- /dev/null
+++ b/Source/cmCxxModuleMapper.h
@@ -0,0 +1,85 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <functional>
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include <cm/optional>
+#include <cmext/string_view>
+
+#include "cmScanDepFormat.h"
+
+enum class CxxModuleMapFormat
+{
+ Gcc,
+ Msvc,
+};
+
+struct CxxModuleLocations
+{
+ // The path from which all relative paths should be computed. If
+ // this is relative, it is relative to the compiler's working
+ // directory.
+ std::string RootDirectory;
+
+ // A function to convert a full path to a path for the generator.
+ std::function<std::string(std::string const&)> PathForGenerator;
+
+ // Lookup the BMI location of a logical module name.
+ std::function<cm::optional<std::string>(std::string const&)>
+ BmiLocationForModule;
+
+ // Returns the generator path (if known) for the BMI given a
+ // logical module name.
+ cm::optional<std::string> BmiGeneratorPathForModule(
+ std::string const& logical_name) const;
+};
+
+struct CxxModuleReference
+{
+ // The path to the module file used.
+ std::string Path;
+ // How the module was looked up.
+ LookupMethod Method;
+};
+
+struct CxxModuleUsage
+{
+ // The usage requirements for this object.
+ std::map<std::string, std::set<std::string>> Usage;
+
+ // The references for this object.
+ std::map<std::string, CxxModuleReference> Reference;
+
+ // Add a reference to a module.
+ //
+ // Returns `true` if it matches how it was found previously, `false` if it
+ // conflicts.
+ bool AddReference(std::string const& logical, std::string const& loc,
+ LookupMethod method);
+};
+
+// Return the extension to use for a given modulemap format.
+cm::static_string_view CxxModuleMapExtension(
+ cm::optional<CxxModuleMapFormat> format);
+
+// Fill in module usage information for internal usages.
+//
+// Returns the set of unresolved module usage requirements (these form an
+// import cycle).
+std::set<std::string> CxxModuleUsageSeed(
+ CxxModuleLocations const& loc, std::vector<cmScanDepInfo> const& objects,
+ CxxModuleUsage& usages);
+
+// Return the contents of the module map in the given format for the
+// object file.
+std::string CxxModuleMapContent(CxxModuleMapFormat format,
+ CxxModuleLocations const& loc,
+ cmScanDepInfo const& obj,
+ CxxModuleUsage const& usages);
diff --git a/Source/cmDefinePropertyCommand.cxx b/Source/cmDefinePropertyCommand.cxx
index faefcb8..31ee665 100644
--- a/Source/cmDefinePropertyCommand.cxx
+++ b/Source/cmDefinePropertyCommand.cxx
@@ -8,6 +8,7 @@
#include <cmext/string_view>
#include "cmArgumentParser.h"
+#include "cmArgumentParserTypes.h"
#include "cmExecutionStatus.h"
#include "cmMakefile.h"
#include "cmProperty.h"
@@ -51,8 +52,8 @@ bool cmDefinePropertyCommand(std::vector<std::string> const& args,
// Parse remaining arguments.
bool inherited = false;
std::string PropertyName;
- std::vector<std::string> BriefDocs;
- std::vector<std::string> FullDocs;
+ ArgumentParser::NonEmpty<std::vector<std::string>> BriefDocs;
+ ArgumentParser::NonEmpty<std::vector<std::string>> FullDocs;
std::string initializeFromVariable;
cmArgumentParser<void> parser;
diff --git a/Source/cmDocumentation.cxx b/Source/cmDocumentation.cxx
index 3619ade..d466a12 100644
--- a/Source/cmDocumentation.cxx
+++ b/Source/cmDocumentation.cxx
@@ -17,30 +17,32 @@
#include "cmVersion.h"
static const char* cmDocumentationStandardOptions[][2] = {
- { "--help,-help,-usage,-h,-H,/?", "Print usage information and exit." },
- { "--version,-version,/V [<f>]", "Print version number and exit." },
- { "--help-full [<f>]", "Print all help manuals and exit." },
- { "--help-manual <man> [<f>]", "Print one help manual and exit." },
- { "--help-manual-list [<f>]", "List help manuals available and exit." },
- { "--help-command <cmd> [<f>]", "Print help for one command and exit." },
- { "--help-command-list [<f>]",
+ { "-h,-H,--help,-help,-usage,/?", "Print usage information and exit." },
+ { "--version,-version,/V [<file>]", "Print version number and exit." },
+ { "--help-full [<file>]", "Print all help manuals and exit." },
+ { "--help-manual <man> [<file>]", "Print one help manual and exit." },
+ { "--help-manual-list [<file>]", "List help manuals available and exit." },
+ { "--help-command <cmd> [<file>]", "Print help for one command and exit." },
+ { "--help-command-list [<file>]",
"List commands with help available and exit." },
- { "--help-commands [<f>]", "Print cmake-commands manual and exit." },
- { "--help-module <mod> [<f>]", "Print help for one module and exit." },
- { "--help-module-list [<f>]", "List modules with help available and exit." },
- { "--help-modules [<f>]", "Print cmake-modules manual and exit." },
- { "--help-policy <cmp> [<f>]", "Print help for one policy and exit." },
- { "--help-policy-list [<f>]",
+ { "--help-commands [<file>]", "Print cmake-commands manual and exit." },
+ { "--help-module <mod> [<file>]", "Print help for one module and exit." },
+ { "--help-module-list [<file>]",
+ "List modules with help available and exit." },
+ { "--help-modules [<file>]", "Print cmake-modules manual and exit." },
+ { "--help-policy <cmp> [<file>]", "Print help for one policy and exit." },
+ { "--help-policy-list [<file>]",
"List policies with help available and exit." },
- { "--help-policies [<f>]", "Print cmake-policies manual and exit." },
- { "--help-property <prop> [<f>]", "Print help for one property and exit." },
- { "--help-property-list [<f>]",
+ { "--help-policies [<file>]", "Print cmake-policies manual and exit." },
+ { "--help-property <prop> [<file>]",
+ "Print help for one property and exit." },
+ { "--help-property-list [<file>]",
"List properties with help available and exit." },
- { "--help-properties [<f>]", "Print cmake-properties manual and exit." },
- { "--help-variable var [<f>]", "Print help for one variable and exit." },
- { "--help-variable-list [<f>]",
+ { "--help-properties [<file>]", "Print cmake-properties manual and exit." },
+ { "--help-variable var [<file>]", "Print help for one variable and exit." },
+ { "--help-variable-list [<file>]",
"List variables with help available and exit." },
- { "--help-variables [<f>]", "Print cmake-variables manual and exit." },
+ { "--help-variables [<file>]", "Print cmake-variables manual and exit." },
{ nullptr, nullptr }
};
diff --git a/Source/cmExecuteProcessCommand.cxx b/Source/cmExecuteProcessCommand.cxx
index 222ea80..7fbd826 100644
--- a/Source/cmExecuteProcessCommand.cxx
+++ b/Source/cmExecuteProcessCommand.cxx
@@ -47,7 +47,7 @@ bool cmExecuteProcessCommand(std::vector<std::string> const& args,
return false;
}
- struct Arguments
+ struct Arguments : public ArgumentParser::ParseResult
{
std::vector<std::vector<std::string>> Commands;
std::string OutputVariable;
@@ -95,14 +95,10 @@ bool cmExecuteProcessCommand(std::vector<std::string> const& args,
.Bind("COMMAND_ERROR_IS_FATAL"_s, &Arguments::CommandErrorIsFatal);
std::vector<std::string> unparsedArguments;
- std::vector<std::string> keywordsMissingValue;
- Arguments const arguments =
- parser.Parse(args, &unparsedArguments, &keywordsMissingValue);
+ Arguments const arguments = parser.Parse(args, &unparsedArguments);
- if (!keywordsMissingValue.empty()) {
- status.SetError(" called with no value for " +
- keywordsMissingValue.front() + ".");
- return false;
+ if (arguments.MaybeReportError(status.GetMakefile())) {
+ return true;
}
if (!unparsedArguments.empty()) {
status.SetError(" given unknown argument \"" + unparsedArguments.front() +
diff --git a/Source/cmExperimental.cxx b/Source/cmExperimental.cxx
new file mode 100644
index 0000000..922b53f
--- /dev/null
+++ b/Source/cmExperimental.cxx
@@ -0,0 +1,63 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmExperimental.h"
+
+#include <cassert>
+#include <cstddef>
+#include <string>
+
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmValue.h"
+
+namespace {
+
+/*
+ * The `Uuid` fields of these objects should change periodically.
+ * Search for other instances to keep the documentation and test suite
+ * up-to-date.
+ */
+
+struct FeatureData
+{
+ std::string const Uuid;
+ std::string const Variable;
+ std::string const Description;
+ bool Warned;
+} LookupTable[] = {
+ // CxxModuleCMakeApi
+ { "3c375311-a3c9-4396-a187-3227ef642046",
+ "CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API",
+ "CMake's C++ module support is experimental. It is meant only for "
+ "experimentation and feedback to CMake developers.",
+ false },
+};
+static_assert(sizeof(LookupTable) / sizeof(LookupTable[0]) ==
+ static_cast<size_t>(cmExperimental::Feature::Sentinel),
+ "Experimental feature lookup table mismatch");
+
+FeatureData& DataForFeature(cmExperimental::Feature f)
+{
+ assert(f != cmExperimental::Feature::Sentinel);
+ return LookupTable[static_cast<size_t>(f)];
+}
+}
+
+bool cmExperimental::HasSupportEnabled(cmMakefile const& mf, Feature f)
+{
+ bool enabled = false;
+ auto& data = DataForFeature(f);
+
+ auto value = mf.GetDefinition(data.Variable);
+ if (value == data.Uuid) {
+ enabled = true;
+ }
+
+ if (enabled && !data.Warned) {
+ mf.IssueMessage(MessageType::AUTHOR_WARNING, data.Description);
+ data.Warned = true;
+ }
+
+ return enabled;
+}
diff --git a/Source/cmExperimental.h b/Source/cmExperimental.h
new file mode 100644
index 0000000..26e0d17
--- /dev/null
+++ b/Source/cmExperimental.h
@@ -0,0 +1,21 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+class cmMakefile;
+
+class cmExperimental
+{
+public:
+ enum class Feature
+ {
+ CxxModuleCMakeApi,
+
+ Sentinel,
+ };
+
+ static bool HasSupportEnabled(cmMakefile const& mf, Feature f);
+};
diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx
index 6ce0c98..ed199ea 100644
--- a/Source/cmExportBuildFileGenerator.cxx
+++ b/Source/cmExportBuildFileGenerator.cxx
@@ -9,10 +9,13 @@
#include <sstream>
#include <utility>
+#include <cm/string_view>
#include <cmext/algorithm>
+#include <cmext/string_view>
#include "cmExportSet.h"
#include "cmFileSet.h"
+#include "cmGeneratedFileStream.h"
#include "cmGeneratorExpression.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalGenerator.h"
@@ -23,6 +26,7 @@
#include "cmPolicies.h"
#include "cmStateTypes.h"
#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
#include "cmTarget.h"
#include "cmTargetExport.h"
#include "cmValue.h"
@@ -139,11 +143,18 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os)
this->GenerateTargetFileSets(gte, os);
}
+ this->GenerateCxxModuleInformation(os);
+
// Generate import file content for each configuration.
for (std::string const& c : this->Configurations) {
this->GenerateImportConfig(os, c);
}
+ // Generate import file content for each configuration.
+ for (std::string const& c : this->Configurations) {
+ this->GenerateImportCxxModuleConfigTargetInclusion(c);
+ }
+
this->GenerateMissingTargetsCheckCode(os);
return true;
@@ -382,6 +393,21 @@ std::string cmExportBuildFileGenerator::GetFileSetDirectories(
std::any_of(directoryEntries.begin(), directoryEntries.end(),
EntryIsContextSensitive);
+ auto const& type = fileSet->GetType();
+ // C++ modules do not support interface file sets which are dependent upon
+ // the configuration.
+ if (contextSensitive &&
+ (type == "CXX_MODULES"_s || type == "CXX_MODULE_HEADER_UNITS"_s)) {
+ auto* mf = this->LG->GetMakefile();
+ std::ostringstream e;
+ e << "The \"" << gte->GetName() << "\" target's interface file set \""
+ << fileSet->GetName() << "\" of type \"" << type
+ << "\" contains context-sensitive base directory entries which is not "
+ "supported.";
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return std::string{};
+ }
+
for (auto const& directory : directories) {
auto dest = cmOutputConverter::EscapeForCMake(
directory, cmOutputConverter::WrapQuotes::NoWrap);
@@ -427,6 +453,21 @@ std::string cmExportBuildFileGenerator::GetFileSetFiles(cmGeneratorTarget* gte,
std::any_of(fileEntries.begin(), fileEntries.end(),
EntryIsContextSensitive);
+ auto const& type = fileSet->GetType();
+ // C++ modules do not support interface file sets which are dependent upon
+ // the configuration.
+ if (contextSensitive &&
+ (type == "CXX_MODULES"_s || type == "CXX_MODULE_HEADER_UNITS"_s)) {
+ auto* mf = this->LG->GetMakefile();
+ std::ostringstream e;
+ e << "The \"" << gte->GetName() << "\" target's interface file set \""
+ << fileSet->GetName() << "\" of type \"" << type
+ << "\" contains context-sensitive file entries which is not "
+ "supported.";
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return std::string{};
+ }
+
for (auto const& it : files) {
for (auto const& filename : it.second) {
auto escapedFile = cmOutputConverter::EscapeForCMake(
@@ -447,3 +488,60 @@ std::string cmExportBuildFileGenerator::GetFileSetFiles(cmGeneratorTarget* gte,
return cmJoin(resultVector, " ");
}
+
+std::string cmExportBuildFileGenerator::GetCxxModulesDirectory() const
+{
+ return this->CxxModulesDirectory;
+}
+
+void cmExportBuildFileGenerator::GenerateCxxModuleConfigInformation(
+ std::ostream& os) const
+{
+ const char* opt = "";
+ if (this->Configurations.size() > 1) {
+ // With more than one configuration, each individual file is optional.
+ opt = " OPTIONAL";
+ }
+
+ // Generate import file content for each configuration.
+ for (std::string c : this->Configurations) {
+ if (c.empty()) {
+ c = "noconfig";
+ }
+ os << "include(\"${CMAKE_CURRENT_LIST_DIR}/cxx-modules-" << c << ".cmake\""
+ << opt << ")\n";
+ }
+}
+
+bool cmExportBuildFileGenerator::GenerateImportCxxModuleConfigTargetInclusion(
+ std::string config) const
+{
+ auto cxx_modules_dirname = this->GetCxxModulesDirectory();
+ if (cxx_modules_dirname.empty()) {
+ return true;
+ }
+
+ if (config.empty()) {
+ config = "noconfig";
+ }
+
+ std::string fileName = cmStrCat(this->FileDir, '/', cxx_modules_dirname,
+ "/cxx-modules-", config, ".cmake");
+
+ cmGeneratedFileStream os(fileName, true);
+ if (!os) {
+ std::string se = cmSystemTools::GetLastSystemError();
+ std::ostringstream e;
+ e << "cannot write to file \"" << fileName << "\": " << se;
+ cmSystemTools::Error(e.str());
+ return false;
+ }
+ os.SetCopyIfDifferent(true);
+
+ for (auto const* tgt : this->ExportedTargets) {
+ os << "include(\"${CMAKE_CURRENT_LIST_DIR}/target-" << tgt->GetExportName()
+ << '-' << config << ".cmake\")\n";
+ }
+
+ return true;
+}
diff --git a/Source/cmExportBuildFileGenerator.h b/Source/cmExportBuildFileGenerator.h
index 5681e8f..4636196 100644
--- a/Source/cmExportBuildFileGenerator.h
+++ b/Source/cmExportBuildFileGenerator.h
@@ -47,6 +47,16 @@ public:
}
void SetExportSet(cmExportSet*);
+ /** Set the name of the C++ module directory. */
+ void SetCxxModuleDirectory(std::string cxx_module_dir)
+ {
+ this->CxxModulesDirectory = std::move(cxx_module_dir);
+ }
+ const std::string& GetCxxModuleDirectory() const
+ {
+ return this->CxxModulesDirectory;
+ }
+
/** Set whether to append generated code to the output file. */
void SetAppendMode(bool append) { this->AppendMode = append; }
@@ -81,6 +91,10 @@ protected:
std::string GetFileSetFiles(cmGeneratorTarget* gte, cmFileSet* fileSet,
cmTargetExport* te) override;
+ std::string GetCxxModulesDirectory() const override;
+ void GenerateCxxModuleConfigInformation(std::ostream&) const override;
+ bool GenerateImportCxxModuleConfigTargetInclusion(std::string) const;
+
std::pair<std::vector<std::string>, std::string> FindBuildExportInfo(
cmGlobalGenerator* gg, const std::string& name);
@@ -88,4 +102,6 @@ protected:
cmExportSet* ExportSet;
std::vector<cmGeneratorTarget*> Exports;
cmLocalGenerator* LG;
+ // The directory for C++ module information.
+ std::string CxxModulesDirectory;
};
diff --git a/Source/cmExportCommand.cxx b/Source/cmExportCommand.cxx
index 63440a3..a58f2b7 100644
--- a/Source/cmExportCommand.cxx
+++ b/Source/cmExportCommand.cxx
@@ -7,13 +7,15 @@
#include <utility>
#include <cm/memory>
-#include <cmext/algorithm>
+#include <cm/optional>
#include <cmext/string_view>
#include "cmsys/RegularExpression.hxx"
#include "cmArgumentParser.h"
+#include "cmArgumentParserTypes.h"
#include "cmExecutionStatus.h"
+#include "cmExperimental.h"
#include "cmExportBuildAndroidMKGenerator.h"
#include "cmExportBuildFileGenerator.h"
#include "cmExportSet.h"
@@ -57,10 +59,11 @@ bool cmExportCommand(std::vector<std::string> const& args,
struct Arguments
{
std::string ExportSetName;
- std::vector<std::string> Targets;
+ cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>> Targets;
std::string Namespace;
std::string Filename;
std::string AndroidMKFile;
+ std::string CxxModulesDirectory;
bool Append = false;
bool ExportOld = false;
};
@@ -69,6 +72,12 @@ bool cmExportCommand(std::vector<std::string> const& args,
.Bind("NAMESPACE"_s, &Arguments::Namespace)
.Bind("FILE"_s, &Arguments::Filename);
+ bool const supportCxx20FileSetTypes = cmExperimental::HasSupportEnabled(
+ status.GetMakefile(), cmExperimental::Feature::CxxModuleCMakeApi);
+ if (supportCxx20FileSetTypes) {
+ parser.Bind("CXX_MODULES_DIRECTORY"_s, &Arguments::CxxModulesDirectory);
+ }
+
if (args[0] == "EXPORT") {
parser.Bind("EXPORT"_s, &Arguments::ExportSetName);
} else {
@@ -79,9 +88,7 @@ bool cmExportCommand(std::vector<std::string> const& args,
}
std::vector<std::string> unknownArgs;
- std::vector<std::string> keywordsMissingValue;
- Arguments const arguments =
- parser.Parse(args, &unknownArgs, &keywordsMissingValue);
+ Arguments const arguments = parser.Parse(args, &unknownArgs);
if (!unknownArgs.empty()) {
status.SetError("Unknown argument: \"" + unknownArgs.front() + "\".");
@@ -145,9 +152,8 @@ bool cmExportCommand(std::vector<std::string> const& args,
return false;
}
exportSet = &it->second;
- } else if (!arguments.Targets.empty() ||
- cm::contains(keywordsMissingValue, "TARGETS")) {
- for (std::string const& currentTarget : arguments.Targets) {
+ } else if (arguments.Targets) {
+ for (std::string const& currentTarget : *arguments.Targets) {
if (mf.IsAlias(currentTarget)) {
std::ostringstream e;
e << "given ALIAS target \"" << currentTarget
@@ -214,6 +220,7 @@ bool cmExportCommand(std::vector<std::string> const& args,
}
ebfg->SetExportFile(fname.c_str());
ebfg->SetNamespace(arguments.Namespace);
+ ebfg->SetCxxModuleDirectory(arguments.CxxModulesDirectory);
ebfg->SetAppendMode(arguments.Append);
if (exportSet != nullptr) {
ebfg->SetExportSet(exportSet);
diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx
index 5a33349..50bc78c 100644
--- a/Source/cmExportFileGenerator.cxx
+++ b/Source/cmExportFileGenerator.cxx
@@ -939,13 +939,13 @@ void cmExportFileGenerator::GeneratePolicyHeaderCode(std::ostream& os)
// Isolate the file policy level.
// Support CMake versions as far back as 2.6 but also support using NEW
- // policy settings for up to CMake 3.22 (this upper limit may be reviewed
+ // policy settings for up to CMake 3.23 (this upper limit may be reviewed
// and increased from time to time). This reduces the opportunity for CMake
// warnings when an older export file is later used with newer CMake
// versions.
/* clang-format off */
os << "cmake_policy(PUSH)\n"
- << "cmake_policy(VERSION 2.8.3...3.22)\n";
+ << "cmake_policy(VERSION 2.8.3...3.23)\n";
/* clang-format on */
}
@@ -1095,6 +1095,10 @@ void cmExportFileGenerator::GenerateImportTargetCode(
<< " PROPERTY IMPORTED_NO_SYSTEM 1)\n";
}
+ if (target->GetPropertyAsBool("EXPORT_NO_SYSTEM")) {
+ os << "set_property(TARGET " << targetName << " PROPERTY SYSTEM 0)\n";
+ }
+
os << "\n";
}
@@ -1308,3 +1312,28 @@ void cmExportFileGenerator::GenerateTargetFileSets(cmGeneratorTarget* gte,
os << " )\nendif()\n\n";
}
}
+
+void cmExportFileGenerator::GenerateCxxModuleInformation(std::ostream& os)
+{
+ auto const cxx_module_dirname = this->GetCxxModulesDirectory();
+ if (cxx_module_dirname.empty()) {
+ return;
+ }
+
+ // Write the include.
+ os << "# Include C++ module properties\n"
+ << "include(\"${CMAKE_CURRENT_LIST_DIR}/" << cxx_module_dirname
+ << "/cxx-modules.cmake\")\n\n";
+
+ // Get the path to the file we're going to write.
+ std::string path = this->MainImportFile;
+ path = cmSystemTools::GetFilenamePath(path);
+ auto trampoline_path =
+ cmStrCat(path, '/', cxx_module_dirname, "/cxx-modules.cmake");
+
+ // Include all configuration-specific include files.
+ cmGeneratedFileStream ap(trampoline_path, true);
+ ap.SetCopyIfDifferent(true);
+
+ this->GenerateCxxModuleConfigInformation(ap);
+}
diff --git a/Source/cmExportFileGenerator.h b/Source/cmExportFileGenerator.h
index d27a555..fdda878 100644
--- a/Source/cmExportFileGenerator.h
+++ b/Source/cmExportFileGenerator.h
@@ -182,6 +182,8 @@ protected:
void GenerateTargetFileSets(cmGeneratorTarget* gte, std::ostream& os,
cmTargetExport* te = nullptr);
+ void GenerateCxxModuleInformation(std::ostream& os);
+
virtual std::string GetFileSetDirectories(cmGeneratorTarget* gte,
cmFileSet* fileSet,
cmTargetExport* te) = 0;
@@ -226,4 +228,7 @@ private:
virtual std::string InstallNameDir(cmGeneratorTarget const* target,
const std::string& config) = 0;
+
+ virtual std::string GetCxxModulesDirectory() const = 0;
+ virtual void GenerateCxxModuleConfigInformation(std::ostream& os) const = 0;
};
diff --git a/Source/cmExportInstallAndroidMKGenerator.cxx b/Source/cmExportInstallAndroidMKGenerator.cxx
index 4e4f8a1..d53254d 100644
--- a/Source/cmExportInstallAndroidMKGenerator.cxx
+++ b/Source/cmExportInstallAndroidMKGenerator.cxx
@@ -35,8 +35,7 @@ void cmExportInstallAndroidMKGenerator::GenerateImportHeaderCode(
for (size_t n = 0; n < numDotDot; n++) {
path += "/..";
}
- os << "_IMPORT_PREFIX := "
- << "$(LOCAL_PATH)" << path << "\n\n";
+ os << "_IMPORT_PREFIX := $(LOCAL_PATH)" << path << "\n\n";
for (std::unique_ptr<cmTargetExport> const& te :
this->IEGen->GetExportSet()->GetTargetExports()) {
// Collect import properties for this target.
diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx
index adccdfe..7d8572d 100644
--- a/Source/cmExportInstallFileGenerator.cxx
+++ b/Source/cmExportInstallFileGenerator.cxx
@@ -7,6 +7,9 @@
#include <sstream>
#include <utility>
+#include <cm/string_view>
+#include <cmext/string_view>
+
#include "cmExportSet.h"
#include "cmFileSet.h"
#include "cmGeneratedFileStream.h"
@@ -18,6 +21,7 @@
#include "cmInstallTargetGenerator.h"
#include "cmLocalGenerator.h"
#include "cmMakefile.h"
+#include "cmMessageType.h"
#include "cmOutputConverter.h"
#include "cmPolicies.h"
#include "cmStateTypes.h"
@@ -162,10 +166,20 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os)
this->LoadConfigFiles(os);
+ bool result = true;
+
+ this->GenerateCxxModuleInformation(os);
+ if (requiresConfigFiles) {
+ for (std::string const& c : this->Configurations) {
+ if (!this->GenerateImportCxxModuleConfigTargetInclusion(c)) {
+ result = false;
+ }
+ }
+ }
+
this->CleanupTemporaryVariables(os);
this->GenerateImportedFileCheckLoop(os);
- bool result = true;
// Generate an import file for each configuration.
// Don't do this if we only export INTERFACE_LIBRARY targets.
if (requiresConfigFiles) {
@@ -562,6 +576,21 @@ std::string cmExportInstallFileGenerator::GetFileSetDirectories(
cge->Evaluate(gte->LocalGenerator, config, gte),
cmOutputConverter::WrapQuotes::NoWrap));
+ auto const& type = fileSet->GetType();
+ // C++ modules do not support interface file sets which are dependent upon
+ // the configuration.
+ if (cge->GetHadContextSensitiveCondition() &&
+ (type == "CXX_MODULES"_s || type == "CXX_MODULE_HEADER_UNITS"_s)) {
+ auto* mf = this->IEGen->GetLocalGenerator()->GetMakefile();
+ std::ostringstream e;
+ e << "The \"" << gte->GetName() << "\" target's interface file set \""
+ << fileSet->GetName() << "\" of type \"" << type
+ << "\" contains context-sensitive base file entries which is not "
+ "supported.";
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return std::string{};
+ }
+
if (cge->GetHadContextSensitiveCondition() && configs.size() != 1) {
resultVector.push_back(
cmStrCat("\"$<$<CONFIG:", config, ">:", dest, ">\""));
@@ -610,6 +639,21 @@ std::string cmExportInstallFileGenerator::GetFileSetFiles(
std::any_of(fileEntries.begin(), fileEntries.end(),
EntryIsContextSensitive);
+ auto const& type = fileSet->GetType();
+ // C++ modules do not support interface file sets which are dependent upon
+ // the configuration.
+ if (contextSensitive &&
+ (type == "CXX_MODULES"_s || type == "CXX_MODULE_HEADER_UNITS"_s)) {
+ auto* mf = this->IEGen->GetLocalGenerator()->GetMakefile();
+ std::ostringstream e;
+ e << "The \"" << gte->GetName() << "\" target's interface file set \""
+ << fileSet->GetName() << "\" of type \"" << type
+ << "\" contains context-sensitive base file entries which is not "
+ "supported.";
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return std::string{};
+ }
+
for (auto const& it : files) {
auto prefix = it.first.empty() ? "" : cmStrCat(it.first, '/');
for (auto const& filename : it.second) {
@@ -635,3 +679,65 @@ std::string cmExportInstallFileGenerator::GetFileSetFiles(
return cmJoin(resultVector, " ");
}
+
+std::string cmExportInstallFileGenerator::GetCxxModulesDirectory() const
+{
+ return IEGen->GetCxxModuleDirectory();
+}
+
+void cmExportInstallFileGenerator::GenerateCxxModuleConfigInformation(
+ std::ostream& os) const
+{
+ // Now load per-configuration properties for them.
+ /* clang-format off */
+ os << "# Load information for each installed configuration.\n"
+ "file(GLOB _cmake_cxx_module_includes \"${CMAKE_CURRENT_LIST_DIR}/cxx-modules-*.cmake\")\n"
+ "foreach(_cmake_cxx_module_include IN LISTS _cmake_cxx_module_includes)\n"
+ " include(\"${_cmake_cxx_module_include}\")\n"
+ "endforeach()\n"
+ "unset(_cmake_cxx_module_include)\n"
+ "unset(_cmake_cxx_module_includes)\n";
+ /* clang-format on */
+}
+
+bool cmExportInstallFileGenerator::
+ GenerateImportCxxModuleConfigTargetInclusion(std::string const& config)
+{
+ auto cxx_modules_dirname = this->GetCxxModulesDirectory();
+ if (cxx_modules_dirname.empty()) {
+ return true;
+ }
+
+ std::string filename_config = config;
+ if (filename_config.empty()) {
+ filename_config = "noconfig";
+ }
+
+ std::string const dest =
+ cmStrCat(this->FileDir, '/', cxx_modules_dirname, '/');
+ std::string fileName =
+ cmStrCat(dest, "cxx-modules-", filename_config, ".cmake");
+
+ cmGeneratedFileStream os(fileName, true);
+ if (!os) {
+ std::string se = cmSystemTools::GetLastSystemError();
+ std::ostringstream e;
+ e << "cannot write to file \"" << fileName << "\": " << se;
+ cmSystemTools::Error(e.str());
+ return false;
+ }
+ os.SetCopyIfDifferent(true);
+
+ // Record this per-config import file.
+ this->ConfigCxxModuleFiles[config] = fileName;
+
+ auto& prop_files = this->ConfigCxxModuleTargetFiles[config];
+ for (auto const* tgt : this->ExportedTargets) {
+ auto prop_filename = cmStrCat("target-", tgt->GetExportName(), '-',
+ filename_config, ".cmake");
+ prop_files.emplace_back(cmStrCat(dest, prop_filename));
+ os << "include(\"${CMAKE_CURRENT_LIST_DIR}/" << prop_filename << "\")\n";
+ }
+
+ return true;
+}
diff --git a/Source/cmExportInstallFileGenerator.h b/Source/cmExportInstallFileGenerator.h
index 86fb505..e073a31 100644
--- a/Source/cmExportInstallFileGenerator.h
+++ b/Source/cmExportInstallFileGenerator.h
@@ -50,6 +50,23 @@ public:
return this->ConfigImportFiles;
}
+ /** Get the per-config C++ module file generated for each configuration.
+ This maps from the configuration name to the file temporary location
+ for installation. */
+ std::map<std::string, std::string> const& GetConfigCxxModuleFiles()
+ {
+ return this->ConfigCxxModuleFiles;
+ }
+
+ /** Get the per-config C++ module file generated for each configuration.
+ This maps from the configuration name to the file temporary location
+ for installation for each target in the export set. */
+ std::map<std::string, std::vector<std::string>> const&
+ GetConfigCxxModuleTargetFiles()
+ {
+ return this->ConfigCxxModuleTargetFiles;
+ }
+
/** Compute the globbing expression used to load per-config import
files from the main file. */
std::string GetConfigImportFileGlob();
@@ -100,8 +117,16 @@ protected:
std::string GetFileSetFiles(cmGeneratorTarget* gte, cmFileSet* fileSet,
cmTargetExport* te) override;
+ std::string GetCxxModulesDirectory() const override;
+ void GenerateCxxModuleConfigInformation(std::ostream&) const override;
+ bool GenerateImportCxxModuleConfigTargetInclusion(std::string const&);
+
cmInstallExportGenerator* IEGen;
// The import file generated for each configuration.
std::map<std::string, std::string> ConfigImportFiles;
+ // The C++ module property file generated for each configuration.
+ std::map<std::string, std::string> ConfigCxxModuleFiles;
+ // The C++ module property target files generated for each configuration.
+ std::map<std::string, std::vector<std::string>> ConfigCxxModuleTargetFiles;
};
diff --git a/Source/cmExportTryCompileFileGenerator.h b/Source/cmExportTryCompileFileGenerator.h
index 1dd8a20..5c34fad 100644
--- a/Source/cmExportTryCompileFileGenerator.h
+++ b/Source/cmExportTryCompileFileGenerator.h
@@ -55,6 +55,9 @@ protected:
std::string GetFileSetFiles(cmGeneratorTarget* target, cmFileSet* fileSet,
cmTargetExport* te) override;
+ std::string GetCxxModulesDirectory() const override { return {}; }
+ void GenerateCxxModuleConfigInformation(std::ostream&) const override {}
+
private:
std::string FindTargets(const std::string& prop,
const cmGeneratorTarget* tgt,
diff --git a/Source/cmFileAPICodemodel.cxx b/Source/cmFileAPICodemodel.cxx
index dd0540c..0581802 100644
--- a/Source/cmFileAPICodemodel.cxx
+++ b/Source/cmFileAPICodemodel.cxx
@@ -27,6 +27,7 @@
#include "cmGeneratorExpression.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalGenerator.h"
+#include "cmInstallCxxModuleBmiGenerator.h"
#include "cmInstallDirectoryGenerator.h"
#include "cmInstallExportGenerator.h"
#include "cmInstallFileSetGenerator.h"
@@ -1092,6 +1093,21 @@ Json::Value DirectoryObject::DumpInstaller(cmInstallGenerator* gen)
if (installFileSet->GetOptional()) {
installer["isOptional"] = true;
}
+ } else if (auto* cxxModuleBmi =
+ dynamic_cast<cmInstallCxxModuleBmiGenerator*>(gen)) {
+ installer["type"] = "cxxModuleBmi";
+ installer["destination"] = cxxModuleBmi->GetDestination(this->Config);
+
+ auto const* target = cxxModuleBmi->GetTarget();
+ installer["cxxModuleBmiTarget"] = Json::objectValue;
+ installer["cxxModuleBmiTarget"]["id"] = TargetId(target, this->TopBuild);
+ installer["cxxModuleBmiTarget"]["index"] = this->TargetIndexMap[target];
+
+ // FIXME: Parse FilePermissions.
+ // FIXME: Parse MessageLevel.
+ if (cxxModuleBmi->GetOptional()) {
+ installer["isOptional"] = true;
+ }
}
// Add fields common to all install generators.
diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx
index 7d05347..7810040 100644
--- a/Source/cmFileCommand.cxx
+++ b/Source/cmFileCommand.cxx
@@ -28,8 +28,8 @@
#include "cm_sys_stat.h"
-#include "cmAlgorithms.h"
#include "cmArgumentParser.h"
+#include "cmArgumentParserTypes.h"
#include "cmCMakePath.h"
#include "cmCryptoHash.h"
#include "cmELF.h"
@@ -172,7 +172,8 @@ bool HandleReadCommand(std::vector<std::string> const& args,
.Bind("LIMIT"_s, &Arguments::Limit)
.Bind("HEX"_s, &Arguments::Hex);
- Arguments const arguments = parser.Parse(cmMakeRange(args).advance(3));
+ Arguments const arguments = parser.Parse(cmMakeRange(args).advance(3),
+ /*unparsedArguments=*/nullptr);
std::string fileName = fileNameArg;
if (!cmsys::SystemTools::FileIsFullPath(fileName)) {
@@ -953,42 +954,34 @@ bool HandleRPathChangeCommand(std::vector<std::string> const& args,
{
// Evaluate arguments.
std::string file;
- std::string oldRPath;
- std::string newRPath;
+ cm::optional<std::string> oldRPath;
+ cm::optional<std::string> newRPath;
bool removeEnvironmentRPath = false;
cmArgumentParser<void> parser;
std::vector<std::string> unknownArgs;
- std::vector<std::string> missingArgs;
- std::vector<std::string> parsedArgs;
parser.Bind("FILE"_s, file)
.Bind("OLD_RPATH"_s, oldRPath)
.Bind("NEW_RPATH"_s, newRPath)
.Bind("INSTALL_REMOVE_ENVIRONMENT_RPATH"_s, removeEnvironmentRPath);
- parser.Parse(cmMakeRange(args).advance(1), &unknownArgs, &missingArgs,
- &parsedArgs);
+ ArgumentParser::ParseResult parseResult =
+ parser.Parse(cmMakeRange(args).advance(1), &unknownArgs);
if (!unknownArgs.empty()) {
status.SetError(
cmStrCat("RPATH_CHANGE given unknown argument ", unknownArgs.front()));
return false;
}
- if (!missingArgs.empty()) {
- status.SetError(cmStrCat("RPATH_CHANGE \"", missingArgs.front(),
- "\" argument not given value."));
- return false;
+ if (parseResult.MaybeReportError(status.GetMakefile())) {
+ return true;
}
if (file.empty()) {
status.SetError("RPATH_CHANGE not given FILE option.");
return false;
}
- if (oldRPath.empty() &&
- std::find(parsedArgs.begin(), parsedArgs.end(), "OLD_RPATH") ==
- parsedArgs.end()) {
+ if (!oldRPath) {
status.SetError("RPATH_CHANGE not given OLD_RPATH option.");
return false;
}
- if (newRPath.empty() &&
- std::find(parsedArgs.begin(), parsedArgs.end(), "NEW_RPATH") ==
- parsedArgs.end()) {
+ if (!newRPath) {
status.SetError("RPATH_CHANGE not given NEW_RPATH option.");
return false;
}
@@ -1002,17 +995,17 @@ bool HandleRPathChangeCommand(std::vector<std::string> const& args,
std::string emsg;
bool changed;
- if (!cmSystemTools::ChangeRPath(file, oldRPath, newRPath,
+ if (!cmSystemTools::ChangeRPath(file, *oldRPath, *newRPath,
removeEnvironmentRPath, &emsg, &changed)) {
status.SetError(cmStrCat("RPATH_CHANGE could not write new RPATH:\n ",
- newRPath, "\nto the file:\n ", file, "\n",
+ *newRPath, "\nto the file:\n ", file, "\n",
emsg));
success = false;
}
if (success) {
if (changed) {
std::string message =
- cmStrCat("Set runtime path of \"", file, "\" to \"", newRPath, '"');
+ cmStrCat("Set runtime path of \"", file, "\" to \"", *newRPath, '"');
status.GetMakefile().DisplayStatus(message, -1);
}
ft.Store(file);
@@ -1025,31 +1018,25 @@ bool HandleRPathSetCommand(std::vector<std::string> const& args,
{
// Evaluate arguments.
std::string file;
- std::string newRPath;
+ cm::optional<std::string> newRPath;
cmArgumentParser<void> parser;
std::vector<std::string> unknownArgs;
- std::vector<std::string> missingArgs;
- std::vector<std::string> parsedArgs;
parser.Bind("FILE"_s, file).Bind("NEW_RPATH"_s, newRPath);
- parser.Parse(cmMakeRange(args).advance(1), &unknownArgs, &missingArgs,
- &parsedArgs);
+ ArgumentParser::ParseResult parseResult =
+ parser.Parse(cmMakeRange(args).advance(1), &unknownArgs);
if (!unknownArgs.empty()) {
status.SetError(cmStrCat("RPATH_SET given unrecognized argument \"",
unknownArgs.front(), "\"."));
return false;
}
- if (!missingArgs.empty()) {
- status.SetError(cmStrCat("RPATH_SET \"", missingArgs.front(),
- "\" argument not given value."));
- return false;
+ if (parseResult.MaybeReportError(status.GetMakefile())) {
+ return true;
}
if (file.empty()) {
status.SetError("RPATH_SET not given FILE option.");
return false;
}
- if (newRPath.empty() &&
- std::find(parsedArgs.begin(), parsedArgs.end(), "NEW_RPATH") ==
- parsedArgs.end()) {
+ if (!newRPath) {
status.SetError("RPATH_SET not given NEW_RPATH option.");
return false;
}
@@ -1063,16 +1050,16 @@ bool HandleRPathSetCommand(std::vector<std::string> const& args,
std::string emsg;
bool changed;
- if (!cmSystemTools::SetRPath(file, newRPath, &emsg, &changed)) {
+ if (!cmSystemTools::SetRPath(file, *newRPath, &emsg, &changed)) {
status.SetError(cmStrCat("RPATH_SET could not write new RPATH:\n ",
- newRPath, "\nto the file:\n ", file, "\n",
+ *newRPath, "\nto the file:\n ", file, "\n",
emsg));
success = false;
}
if (success) {
if (changed) {
std::string message =
- cmStrCat("Set runtime path of \"", file, "\" to \"", newRPath, '"');
+ cmStrCat("Set runtime path of \"", file, "\" to \"", *newRPath, '"');
status.GetMakefile().DisplayStatus(message, -1);
}
ft.Store(file);
@@ -1087,18 +1074,16 @@ bool HandleRPathRemoveCommand(std::vector<std::string> const& args,
std::string file;
cmArgumentParser<void> parser;
std::vector<std::string> unknownArgs;
- std::vector<std::string> missingArgs;
parser.Bind("FILE"_s, file);
- parser.Parse(cmMakeRange(args).advance(1), &unknownArgs, &missingArgs);
+ ArgumentParser::ParseResult parseResult =
+ parser.Parse(cmMakeRange(args).advance(1), &unknownArgs);
if (!unknownArgs.empty()) {
status.SetError(
cmStrCat("RPATH_REMOVE given unknown argument ", unknownArgs.front()));
return false;
}
- if (!missingArgs.empty()) {
- status.SetError(cmStrCat("RPATH_REMOVE \"", missingArgs.front(),
- "\" argument not given value."));
- return false;
+ if (parseResult.MaybeReportError(status.GetMakefile())) {
+ return true;
}
if (file.empty()) {
status.SetError("RPATH_REMOVE not given FILE option.");
@@ -1135,31 +1120,25 @@ bool HandleRPathCheckCommand(std::vector<std::string> const& args,
{
// Evaluate arguments.
std::string file;
- std::string rpath;
+ cm::optional<std::string> rpath;
cmArgumentParser<void> parser;
std::vector<std::string> unknownArgs;
- std::vector<std::string> missingArgs;
- std::vector<std::string> parsedArgs;
parser.Bind("FILE"_s, file).Bind("RPATH"_s, rpath);
- parser.Parse(cmMakeRange(args).advance(1), &unknownArgs, &missingArgs,
- &parsedArgs);
+ ArgumentParser::ParseResult parseResult =
+ parser.Parse(cmMakeRange(args).advance(1), &unknownArgs);
if (!unknownArgs.empty()) {
status.SetError(
cmStrCat("RPATH_CHECK given unknown argument ", unknownArgs.front()));
return false;
}
- if (!missingArgs.empty()) {
- status.SetError(cmStrCat("RPATH_CHECK \"", missingArgs.front(),
- "\" argument not given value."));
- return false;
+ if (parseResult.MaybeReportError(status.GetMakefile())) {
+ return true;
}
if (file.empty()) {
status.SetError("RPATH_CHECK not given FILE option.");
return false;
}
- if (rpath.empty() &&
- std::find(parsedArgs.begin(), parsedArgs.end(), "RPATH") ==
- parsedArgs.end()) {
+ if (!rpath) {
status.SetError("RPATH_CHECK not given RPATH option.");
return false;
}
@@ -1168,7 +1147,7 @@ bool HandleRPathCheckCommand(std::vector<std::string> const& args,
// delete it. This is used during installation to re-install a file
// if its RPath will change.
if (cmSystemTools::FileExists(file, true) &&
- !cmSystemTools::CheckRPath(file, rpath)) {
+ !cmSystemTools::CheckRPath(file, *rpath)) {
cmSystemTools::RemoveFile(file);
}
@@ -1197,7 +1176,8 @@ bool HandleReadElfCommand(std::vector<std::string> const& args,
.Bind("RPATH"_s, &Arguments::RPath)
.Bind("RUNPATH"_s, &Arguments::RunPath)
.Bind("CAPTURE_ERROR"_s, &Arguments::Error);
- Arguments const arguments = parser.Parse(cmMakeRange(args).advance(2));
+ Arguments const arguments = parser.Parse(cmMakeRange(args).advance(2),
+ /*unparsedArguments=*/nullptr);
if (!cmSystemTools::FileExists(fileNameArg, true)) {
status.SetError(cmStrCat("READ_ELF given FILE \"", fileNameArg,
@@ -1250,9 +1230,9 @@ bool HandleRealPathCommand(std::vector<std::string> const& args,
return false;
}
- struct Arguments
+ struct Arguments : public ArgumentParser::ParseResult
{
- std::string BaseDirectory;
+ cm::optional<std::string> BaseDirectory;
bool ExpandTilde = false;
};
static auto const parser =
@@ -1261,22 +1241,18 @@ bool HandleRealPathCommand(std::vector<std::string> const& args,
.Bind("EXPAND_TILDE"_s, &Arguments::ExpandTilde);
std::vector<std::string> unparsedArguments;
- std::vector<std::string> keywordsMissingValue;
- std::vector<std::string> parsedKeywords;
auto arguments =
- parser.Parse(cmMakeRange(args).advance(3), &unparsedArguments,
- &keywordsMissingValue, &parsedKeywords);
+ parser.Parse(cmMakeRange(args).advance(3), &unparsedArguments);
if (!unparsedArguments.empty()) {
status.SetError("REAL_PATH called with unexpected arguments");
return false;
}
- if (!keywordsMissingValue.empty()) {
- status.SetError("BASE_DIRECTORY requires a value");
- return false;
+ if (arguments.MaybeReportError(status.GetMakefile())) {
+ return true;
}
- if (parsedKeywords.empty()) {
+ if (!arguments.BaseDirectory) {
arguments.BaseDirectory = status.GetMakefile().GetCurrentSourceDirectory();
}
@@ -1295,7 +1271,7 @@ bool HandleRealPathCommand(std::vector<std::string> const& args,
}
cmCMakePath path(input, cmCMakePath::auto_format);
- path = path.Absolute(arguments.BaseDirectory).Normal();
+ path = path.Absolute(*arguments.BaseDirectory).Normal();
auto realPath = cmSystemTools::GetRealPath(path.GenericString());
status.GetMakefile().AddDefinition(args[2], realPath);
@@ -1938,7 +1914,7 @@ bool HandleDownloadCommand(std::vector<std::string> const& args,
std::string msg;
std::string actualHash = hash->HashFile(file);
if (actualHash == expectedHash) {
- msg = cmStrCat("returning early; file already exists with expected ",
+ msg = cmStrCat("skipping download as file already exists with expected ",
hashMatchMSG, '"');
if (!statusVar.empty()) {
status.GetMakefile().AddDefinition(statusVar, cmStrCat(0, ";\"", msg));
@@ -2495,17 +2471,18 @@ bool HandleGenerateCommand(std::vector<std::string> const& args,
return false;
}
- struct Arguments
+ struct Arguments : public ArgumentParser::ParseResult
{
- std::string Output;
- std::string Input;
- std::string Content;
- std::string Condition;
- std::string Target;
- std::string NewLineStyle;
+ cm::optional<std::string> Output;
+ cm::optional<std::string> Input;
+ cm::optional<std::string> Content;
+ cm::optional<std::string> Condition;
+ cm::optional<std::string> Target;
+ cm::optional<std::string> NewLineStyle;
bool NoSourcePermissions = false;
bool UseSourcePermissions = false;
- std::vector<std::string> FilePermissions;
+ ArgumentParser::NonEmpty<std::vector<std::string>> FilePermissions;
+ std::vector<cm::string_view> ParsedKeywords;
};
static auto const parser =
@@ -2518,18 +2495,15 @@ bool HandleGenerateCommand(std::vector<std::string> const& args,
.Bind("NO_SOURCE_PERMISSIONS"_s, &Arguments::NoSourcePermissions)
.Bind("USE_SOURCE_PERMISSIONS"_s, &Arguments::UseSourcePermissions)
.Bind("FILE_PERMISSIONS"_s, &Arguments::FilePermissions)
- .Bind("NEWLINE_STYLE"_s, &Arguments::NewLineStyle);
+ .Bind("NEWLINE_STYLE"_s, &Arguments::NewLineStyle)
+ .BindParsedKeywords(&Arguments::ParsedKeywords);
std::vector<std::string> unparsedArguments;
- std::vector<std::string> keywordsMissingValues;
- std::vector<std::string> parsedKeywords;
Arguments const arguments =
- parser.Parse(cmMakeRange(args).advance(1), &unparsedArguments,
- &keywordsMissingValues, &parsedKeywords);
+ parser.Parse(cmMakeRange(args).advance(1), &unparsedArguments);
- if (!keywordsMissingValues.empty()) {
- status.SetError("Incorrect arguments to GENERATE subcommand.");
- return false;
+ if (arguments.MaybeReportError(status.GetMakefile())) {
+ return true;
}
if (!unparsedArguments.empty()) {
@@ -2537,56 +2511,41 @@ bool HandleGenerateCommand(std::vector<std::string> const& args,
return false;
}
- bool mandatoryOptionsSpecified = false;
- if (parsedKeywords.size() > 1) {
- const bool outputOprionSpecified = parsedKeywords[0] == "OUTPUT"_s;
- const bool inputOrContentSpecified =
- parsedKeywords[1] == "INPUT"_s || parsedKeywords[1] == "CONTENT"_s;
- if (outputOprionSpecified && inputOrContentSpecified) {
- mandatoryOptionsSpecified = true;
- }
+ if (!arguments.Output || arguments.ParsedKeywords[0] != "OUTPUT"_s) {
+ status.SetError("GENERATE requires OUTPUT as first option.");
+ return false;
}
- if (!mandatoryOptionsSpecified) {
- status.SetError("Incorrect arguments to GENERATE subcommand.");
+ std::string const& output = *arguments.Output;
+
+ if (!arguments.Input && !arguments.Content) {
+ status.SetError("GENERATE requires INPUT or CONTENT option.");
return false;
}
+ const bool inputIsContent = arguments.ParsedKeywords[1] == "CONTENT"_s;
+ if (!inputIsContent && arguments.ParsedKeywords[1] == "INPUT") {
+ status.SetError("Unknown argument to GENERATE subcommand.");
+ }
+ std::string const& input =
+ inputIsContent ? *arguments.Content : *arguments.Input;
- const bool conditionOptionSpecified =
- std::find(parsedKeywords.begin(), parsedKeywords.end(), "CONDITION"_s) !=
- parsedKeywords.end();
- if (conditionOptionSpecified && arguments.Condition.empty()) {
+ if (arguments.Condition && arguments.Condition->empty()) {
status.SetError("CONDITION of sub-command GENERATE must not be empty "
"if specified.");
return false;
}
+ std::string const& condition =
+ arguments.Condition ? *arguments.Condition : std::string();
- const bool targetOptionSpecified =
- std::find(parsedKeywords.begin(), parsedKeywords.end(), "TARGET"_s) !=
- parsedKeywords.end();
- if (targetOptionSpecified && arguments.Target.empty()) {
+ if (arguments.Target && arguments.Target->empty()) {
status.SetError("TARGET of sub-command GENERATE must not be empty "
"if specified.");
return false;
}
+ std::string const& target =
+ arguments.Target ? *arguments.Target : std::string();
- const bool outputOptionSpecified =
- std::find(parsedKeywords.begin(), parsedKeywords.end(), "OUTPUT"_s) !=
- parsedKeywords.end();
- if (outputOptionSpecified && parsedKeywords[0] != "OUTPUT"_s) {
- status.SetError("Incorrect arguments to GENERATE subcommand.");
- return false;
- }
-
- const bool inputIsContent = parsedKeywords[1] != "INPUT"_s;
- if (inputIsContent && parsedKeywords[1] != "CONTENT") {
- status.SetError("Unknown argument to GENERATE subcommand.");
- }
-
- const bool newLineStyleSpecified =
- std::find(parsedKeywords.begin(), parsedKeywords.end(),
- "NEWLINE_STYLE"_s) != parsedKeywords.end();
cmNewLineStyle newLineStyle;
- if (newLineStyleSpecified) {
+ if (arguments.NewLineStyle) {
std::string errorMessage;
if (!newLineStyle.ReadFromArguments(args, errorMessage)) {
status.SetError(cmStrCat("GENERATE ", errorMessage));
@@ -2594,11 +2553,6 @@ bool HandleGenerateCommand(std::vector<std::string> const& args,
}
}
- std::string input = arguments.Input;
- if (inputIsContent) {
- input = arguments.Content;
- }
-
if (arguments.NoSourcePermissions && arguments.UseSourcePermissions) {
status.SetError("given both NO_SOURCE_PERMISSIONS and "
"USE_SOURCE_PERMISSIONS. Only one option allowed.");
@@ -2656,8 +2610,7 @@ bool HandleGenerateCommand(std::vector<std::string> const& args,
}
}
- AddEvaluationFile(input, arguments.Target, arguments.Output,
- arguments.Condition, inputIsContent,
+ AddEvaluationFile(input, target, output, condition, inputIsContent,
newLineStyle.GetCharacters(), permissions, status);
return true;
}
@@ -2836,7 +2789,11 @@ bool HandleTimestampCommand(std::vector<std::string> const& args,
unsigned int argsIndex = 1;
- const std::string& filename = args[argsIndex++];
+ std::string filename = args[argsIndex++];
+ if (!cmsys::SystemTools::FileIsFullPath(filename)) {
+ filename = cmStrCat(status.GetMakefile().GetCurrentSourceDirectory(), '/',
+ filename);
+ }
const std::string& outputVariable = args[argsIndex++];
@@ -3060,24 +3017,25 @@ bool HandleGetRuntimeDependenciesCommand(std::vector<std::string> const& args,
"\n ]])");
}
- struct Arguments
+ struct Arguments : public ArgumentParser::ParseResult
{
std::string ResolvedDependenciesVar;
std::string UnresolvedDependenciesVar;
std::string ConflictingDependenciesPrefix;
std::string RPathPrefix;
std::string BundleExecutable;
- std::vector<std::string> Executables;
- std::vector<std::string> Libraries;
- std::vector<std::string> Directories;
- std::vector<std::string> Modules;
- std::vector<std::string> PreIncludeRegexes;
- std::vector<std::string> PreExcludeRegexes;
- std::vector<std::string> PostIncludeRegexes;
- std::vector<std::string> PostExcludeRegexes;
- std::vector<std::string> PostIncludeFiles;
- std::vector<std::string> PostExcludeFiles;
- std::vector<std::string> PostExcludeFilesStrict;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Executables;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Libraries;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Directories;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Modules;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> PreIncludeRegexes;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> PreExcludeRegexes;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> PostIncludeRegexes;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> PostExcludeRegexes;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> PostIncludeFiles;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> PostExcludeFiles;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>>
+ PostExcludeFilesStrict;
};
static auto const parser =
@@ -3102,10 +3060,8 @@ bool HandleGetRuntimeDependenciesCommand(std::vector<std::string> const& args,
.Bind("POST_EXCLUDE_FILES_STRICT"_s, &Arguments::PostExcludeFilesStrict);
std::vector<std::string> unrecognizedArguments;
- std::vector<std::string> keywordsMissingValues;
auto parsedArgs =
- parser.Parse(cmMakeRange(args).advance(1), &unrecognizedArguments,
- &keywordsMissingValues);
+ parser.Parse(cmMakeRange(args).advance(1), &unrecognizedArguments);
auto argIt = unrecognizedArguments.begin();
if (argIt != unrecognizedArguments.end()) {
status.SetError(cmStrCat("Unrecognized argument: \"", *argIt, "\""));
@@ -3113,26 +3069,9 @@ bool HandleGetRuntimeDependenciesCommand(std::vector<std::string> const& args,
return false;
}
- const std::vector<std::string> LIST_ARGS = {
- "DIRECTORIES",
- "EXECUTABLES",
- "LIBRARIES",
- "MODULES",
- "POST_EXCLUDE_FILES",
- "POST_EXCLUDE_FILES_STRICT",
- "POST_EXCLUDE_REGEXES",
- "POST_INCLUDE_FILES",
- "POST_INCLUDE_REGEXES",
- "PRE_EXCLUDE_REGEXES",
- "PRE_INCLUDE_REGEXES",
- };
- auto kwbegin = keywordsMissingValues.cbegin();
- auto kwend = cmRemoveMatching(keywordsMissingValues, LIST_ARGS);
- if (kwend != kwbegin) {
- status.SetError(cmStrCat("Keywords missing values:\n ",
- cmJoin(cmMakeRange(kwbegin, kwend), "\n ")));
+ if (parsedArgs.MaybeReportError(status.GetMakefile())) {
cmSystemTools::SetFatalErrorOccurred();
- return false;
+ return true;
}
cmRuntimeDependencyArchive archive(
@@ -3232,13 +3171,14 @@ bool HandleGetRuntimeDependenciesCommand(std::vector<std::string> const& args,
bool HandleConfigureCommand(std::vector<std::string> const& args,
cmExecutionStatus& status)
{
- struct Arguments
+ struct Arguments : public ArgumentParser::ParseResult
{
- std::string Output;
- std::string Content;
+ cm::optional<std::string> Output;
+ cm::optional<std::string> Content;
bool EscapeQuotes = false;
bool AtOnly = false;
- std::string NewlineStyle;
+ // "NEWLINE_STYLE" requires one value, but we use a custom check below.
+ ArgumentParser::Maybe<std::string> NewlineStyle;
};
static auto const parser =
@@ -3250,11 +3190,8 @@ bool HandleConfigureCommand(std::vector<std::string> const& args,
.Bind("NEWLINE_STYLE"_s, &Arguments::NewlineStyle);
std::vector<std::string> unrecognizedArguments;
- std::vector<std::string> keywordsMissingArguments;
- std::vector<std::string> parsedKeywords;
auto parsedArgs =
- parser.Parse(cmMakeRange(args).advance(1), &unrecognizedArguments,
- &keywordsMissingArguments, &parsedKeywords);
+ parser.Parse(cmMakeRange(args).advance(1), &unrecognizedArguments);
auto argIt = unrecognizedArguments.begin();
if (argIt != unrecognizedArguments.end()) {
@@ -3264,28 +3201,20 @@ bool HandleConfigureCommand(std::vector<std::string> const& args,
return false;
}
- std::vector<std::string> mandatoryOptions{ "OUTPUT", "CONTENT" };
- for (auto const& e : mandatoryOptions) {
- const bool optionHasNoValue =
- std::find(keywordsMissingArguments.begin(),
- keywordsMissingArguments.end(),
- e) != keywordsMissingArguments.end();
- if (optionHasNoValue) {
- status.SetError(cmStrCat("CONFIGURE ", e, " option needs a value."));
- cmSystemTools::SetFatalErrorOccurred();
- return false;
- }
+ if (parsedArgs.MaybeReportError(status.GetMakefile())) {
+ cmSystemTools::SetFatalErrorOccurred();
+ return true;
}
- for (auto const& e : mandatoryOptions) {
- const bool optionGiven =
- std::find(parsedKeywords.begin(), parsedKeywords.end(), e) !=
- parsedKeywords.end();
- if (!optionGiven) {
- status.SetError(cmStrCat("CONFIGURE ", e, " option is mandatory."));
- cmSystemTools::SetFatalErrorOccurred();
- return false;
- }
+ if (!parsedArgs.Output) {
+ status.SetError("CONFIGURE OUTPUT option is mandatory.");
+ cmSystemTools::SetFatalErrorOccurred();
+ return false;
+ }
+ if (!parsedArgs.Content) {
+ status.SetError("CONFIGURE CONTENT option is mandatory.");
+ cmSystemTools::SetFatalErrorOccurred();
+ return false;
}
std::string errorMessage;
@@ -3297,7 +3226,7 @@ bool HandleConfigureCommand(std::vector<std::string> const& args,
// Check for generator expressions
std::string outputFile = cmSystemTools::CollapseFullPath(
- parsedArgs.Output, status.GetMakefile().GetCurrentBinaryDirectory());
+ *parsedArgs.Output, status.GetMakefile().GetCurrentBinaryDirectory());
std::string::size_type pos = outputFile.find_first_of("<>");
if (pos != std::string::npos) {
@@ -3346,7 +3275,7 @@ bool HandleConfigureCommand(std::vector<std::string> const& args,
fout.SetCopyIfDifferent(true);
// copy input to output and expand variables from input at the same time
- std::stringstream sin(parsedArgs.Content, std::ios::in);
+ std::stringstream sin(*parsedArgs.Content, std::ios::in);
std::string inLine;
std::string outLine;
bool hasNewLine = false;
@@ -3369,15 +3298,19 @@ bool HandleConfigureCommand(std::vector<std::string> const& args,
bool HandleArchiveCreateCommand(std::vector<std::string> const& args,
cmExecutionStatus& status)
{
- struct Arguments
+ struct Arguments : public ArgumentParser::ParseResult
{
std::string Output;
std::string Format;
std::string Compression;
std::string CompressionLevel;
- std::string MTime;
+ // "MTIME" should require one value, but it has long been accidentally
+ // accepted without one and treated as if an empty value were given.
+ // Fixing this would require a policy.
+ ArgumentParser::Maybe<std::string> MTime;
bool Verbose = false;
- std::vector<std::string> Paths;
+ // "PATHS" requires at least one value, but use a custom check below.
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Paths;
};
static auto const parser =
@@ -3391,10 +3324,8 @@ bool HandleArchiveCreateCommand(std::vector<std::string> const& args,
.Bind("PATHS"_s, &Arguments::Paths);
std::vector<std::string> unrecognizedArguments;
- std::vector<std::string> keywordsMissingValues;
auto parsedArgs =
- parser.Parse(cmMakeRange(args).advance(1), &unrecognizedArguments,
- &keywordsMissingValues);
+ parser.Parse(cmMakeRange(args).advance(1), &unrecognizedArguments);
auto argIt = unrecognizedArguments.begin();
if (argIt != unrecognizedArguments.end()) {
status.SetError(cmStrCat("Unrecognized argument: \"", *argIt, "\""));
@@ -3402,16 +3333,9 @@ bool HandleArchiveCreateCommand(std::vector<std::string> const& args,
return false;
}
- const std::vector<std::string> LIST_ARGS = {
- "OUTPUT", "FORMAT", "COMPRESSION", "COMPRESSION_LEVEL", "MTIME", "PATHS"
- };
- auto kwbegin = keywordsMissingValues.cbegin();
- auto kwend = cmRemoveMatching(keywordsMissingValues, LIST_ARGS);
- if (kwend != kwbegin) {
- status.SetError(cmStrCat("Keywords missing values:\n ",
- cmJoin(cmMakeRange(kwbegin, kwend), "\n ")));
+ if (parsedArgs.MaybeReportError(status.GetMakefile())) {
cmSystemTools::SetFatalErrorOccurred();
- return false;
+ return true;
}
const char* knownFormats[] = {
@@ -3500,13 +3424,13 @@ bool HandleArchiveCreateCommand(std::vector<std::string> const& args,
bool HandleArchiveExtractCommand(std::vector<std::string> const& args,
cmExecutionStatus& status)
{
- struct Arguments
+ struct Arguments : public ArgumentParser::ParseResult
{
std::string Input;
bool Verbose = false;
bool ListOnly = false;
std::string Destination;
- std::vector<std::string> Patterns;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Patterns;
bool Touch = false;
};
@@ -3519,10 +3443,8 @@ bool HandleArchiveExtractCommand(std::vector<std::string> const& args,
.Bind("TOUCH"_s, &Arguments::Touch);
std::vector<std::string> unrecognizedArguments;
- std::vector<std::string> keywordsMissingValues;
auto parsedArgs =
- parser.Parse(cmMakeRange(args).advance(1), &unrecognizedArguments,
- &keywordsMissingValues);
+ parser.Parse(cmMakeRange(args).advance(1), &unrecognizedArguments);
auto argIt = unrecognizedArguments.begin();
if (argIt != unrecognizedArguments.end()) {
status.SetError(cmStrCat("Unrecognized argument: \"", *argIt, "\""));
@@ -3530,15 +3452,9 @@ bool HandleArchiveExtractCommand(std::vector<std::string> const& args,
return false;
}
- const std::vector<std::string> LIST_ARGS = { "INPUT", "DESTINATION",
- "PATTERNS" };
- auto kwbegin = keywordsMissingValues.cbegin();
- auto kwend = cmRemoveMatching(keywordsMissingValues, LIST_ARGS);
- if (kwend != kwbegin) {
- status.SetError(cmStrCat("Keywords missing values:\n ",
- cmJoin(cmMakeRange(kwbegin, kwend), "\n ")));
+ if (parsedArgs.MaybeReportError(status.GetMakefile())) {
cmSystemTools::SetFatalErrorOccurred();
- return false;
+ return true;
}
std::string inFile = parsedArgs.Input;
@@ -3593,10 +3509,15 @@ bool HandleArchiveExtractCommand(std::vector<std::string> const& args,
return true;
}
-bool ValidateAndConvertPermissions(const std::vector<std::string>& permissions,
- mode_t& perms, cmExecutionStatus& status)
+bool ValidateAndConvertPermissions(
+ cm::optional<ArgumentParser::NonEmpty<std::vector<std::string>>> const&
+ permissions,
+ mode_t& perms, cmExecutionStatus& status)
{
- for (const auto& i : permissions) {
+ if (!permissions) {
+ return true;
+ }
+ for (const auto& i : *permissions) {
if (!cmFSPermissions::stringToModeT(i, perms)) {
status.SetError(i + " is an invalid permission specifier");
cmSystemTools::SetFatalErrorOccurred();
@@ -3628,11 +3549,14 @@ bool HandleChmodCommandImpl(std::vector<std::string> const& args, bool recurse,
globber.SetRecurse(recurse);
globber.SetRecurseListDirs(recurse);
- struct Arguments
+ struct Arguments : public ArgumentParser::ParseResult
{
- std::vector<std::string> Permissions;
- std::vector<std::string> FilePermissions;
- std::vector<std::string> DirectoryPermissions;
+ cm::optional<ArgumentParser::NonEmpty<std::vector<std::string>>>
+ Permissions;
+ cm::optional<ArgumentParser::NonEmpty<std::vector<std::string>>>
+ FilePermissions;
+ cm::optional<ArgumentParser::NonEmpty<std::vector<std::string>>>
+ DirectoryPermissions;
};
static auto const parser =
@@ -3642,21 +3566,20 @@ bool HandleChmodCommandImpl(std::vector<std::string> const& args, bool recurse,
.Bind("DIRECTORY_PERMISSIONS"_s, &Arguments::DirectoryPermissions);
std::vector<std::string> pathEntries;
- std::vector<std::string> keywordsMissingValues;
- Arguments parsedArgs = parser.Parse(cmMakeRange(args).advance(1),
- &pathEntries, &keywordsMissingValues);
+ Arguments parsedArgs =
+ parser.Parse(cmMakeRange(args).advance(1), &pathEntries);
// check validity of arguments
- if (parsedArgs.Permissions.empty() && parsedArgs.FilePermissions.empty() &&
- parsedArgs.DirectoryPermissions.empty()) // no permissions given
+ if (!parsedArgs.Permissions && !parsedArgs.FilePermissions &&
+ !parsedArgs.DirectoryPermissions) // no permissions given
{
status.SetError("No permissions given");
cmSystemTools::SetFatalErrorOccurred();
return false;
}
- if (!parsedArgs.Permissions.empty() && !parsedArgs.FilePermissions.empty() &&
- !parsedArgs.DirectoryPermissions.empty()) // all keywords are used
+ if (parsedArgs.Permissions && parsedArgs.FilePermissions &&
+ parsedArgs.DirectoryPermissions) // all keywords are used
{
status.SetError("Remove either PERMISSIONS or FILE_PERMISSIONS or "
"DIRECTORY_PERMISSIONS from the invocation");
@@ -3664,12 +3587,9 @@ bool HandleChmodCommandImpl(std::vector<std::string> const& args, bool recurse,
return false;
}
- if (!keywordsMissingValues.empty()) {
- for (const auto& i : keywordsMissingValues) {
- status.SetError(i + " is not given any arguments");
- cmSystemTools::SetFatalErrorOccurred();
- }
- return false;
+ if (parsedArgs.MaybeReportError(status.GetMakefile())) {
+ cmSystemTools::SetFatalErrorOccurred();
+ return true;
}
// validate permissions
@@ -3713,7 +3633,7 @@ bool HandleChmodCommandImpl(std::vector<std::string> const& args, bool recurse,
if (cmSystemTools::FileExists(i, true)) {
bool success = true;
const mode_t& filePermissions =
- parsedArgs.FilePermissions.empty() ? perms : fperms;
+ parsedArgs.FilePermissions ? fperms : perms;
if (filePermissions) {
success = SetPermissions(i, filePermissions, status);
}
@@ -3725,7 +3645,7 @@ bool HandleChmodCommandImpl(std::vector<std::string> const& args, bool recurse,
else if (cmSystemTools::FileIsDirectory(i)) {
bool success = true;
const mode_t& directoryPermissions =
- parsedArgs.DirectoryPermissions.empty() ? perms : dperms;
+ parsedArgs.DirectoryPermissions ? dperms : perms;
if (directoryPermissions) {
success = SetPermissions(i, directoryPermissions, status);
}
diff --git a/Source/cmFindBase.cxx b/Source/cmFindBase.cxx
index 1da995a..b8d345f 100644
--- a/Source/cmFindBase.cxx
+++ b/Source/cmFindBase.cxx
@@ -2,15 +2,20 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmFindBase.h"
+#include <algorithm>
#include <cstddef>
#include <deque>
+#include <functional>
#include <map>
#include <utility>
#include <cm/optional>
#include <cmext/algorithm>
+#include <cmext/string_view>
#include "cmCMakePath.h"
+#include "cmExecutionStatus.h"
+#include "cmListFileCache.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmPolicies.h"
@@ -24,8 +29,6 @@
#include "cmWindowsRegistry.h"
#include "cmake.h"
-class cmExecutionStatus;
-
cmFindBase::cmFindBase(std::string findCommandName, cmExecutionStatus& status)
: cmFindCommon(status)
, FindCommandName(std::move(findCommandName))
@@ -138,6 +141,31 @@ bool cmFindBase::ParseArguments(std::vector<std::string> const& argsIn)
cmStrCat("given invalid value for \"REGISTRY_VIEW\": ", args[j]));
return false;
}
+ } else if (args[j] == "VALIDATOR") {
+ if (++j == args.size()) {
+ this->SetError("missing required argument for \"VALIDATOR\"");
+ return false;
+ }
+ auto command = this->Makefile->GetState()->GetCommand(args[j]);
+ if (command == nullptr) {
+ this->SetError(cmStrCat(
+ "command specified for \"VALIDATOR\" is undefined: ", args[j], '.'));
+ return false;
+ }
+ // ensure a macro is not specified as validator
+ const auto& validatorName = args[j];
+ auto macros = cmExpandedList(this->Makefile->GetProperty("MACROS"));
+ if (std::find_if(macros.begin(), macros.end(),
+ [&validatorName](const std::string& item) {
+ return cmSystemTools::Strucmp(validatorName.c_str(),
+ item.c_str()) == 0;
+ }) != macros.end()) {
+ this->SetError(cmStrCat(
+ "command specified for \"VALIDATOR\" is not a function: ", args[j],
+ '.'));
+ return false;
+ }
+ this->ValidatorName = args[j];
} else if (this->CheckCommonArgument(args[j])) {
doing = DoingNone;
} else {
@@ -188,6 +216,36 @@ bool cmFindBase::ParseArguments(std::vector<std::string> const& argsIn)
return true;
}
+bool cmFindBase::Validate(const std::string& path) const
+{
+ if (this->ValidatorName.empty()) {
+ return true;
+ }
+
+ // The validator command will be executed in an isolated scope.
+ cmMakefile::ScopePushPop varScope(this->Makefile);
+ cmMakefile::PolicyPushPop polScope(this->Makefile);
+ static_cast<void>(varScope);
+ static_cast<void>(polScope);
+
+ auto resultName =
+ cmStrCat("CMAKE_"_s, cmSystemTools::UpperCase(this->FindCommandName),
+ "_VALIDATOR_STATUS"_s);
+
+ this->Makefile->AddDefinitionBool(resultName, true);
+
+ cmListFileFunction validator(
+ this->ValidatorName, 0, 0,
+ { cmListFileArgument(resultName, cmListFileArgument::Unquoted, 0),
+ cmListFileArgument(path, cmListFileArgument::Quoted, 0) });
+ cmExecutionStatus status(*this->Makefile);
+
+ if (this->Makefile->ExecuteCommand(validator, status)) {
+ return this->Makefile->GetDefinition(resultName).IsOn();
+ }
+ return false;
+}
+
void cmFindBase::ExpandPaths()
{
if (!this->NoDefaultPath) {
diff --git a/Source/cmFindBase.h b/Source/cmFindBase.h
index d197424..75d9a6d 100644
--- a/Source/cmFindBase.h
+++ b/Source/cmFindBase.h
@@ -31,6 +31,11 @@ public:
*/
virtual bool ParseArguments(std::vector<std::string> const& args);
+ /**
+ * To check validity of a found path using user's validator, if any
+ */
+ bool Validate(const std::string& path) const;
+
protected:
friend class cmFindBaseDebugState;
void ExpandPaths();
@@ -63,6 +68,8 @@ protected:
bool Required = false;
+ std::string ValidatorName;
+
private:
// Add pieces of the search.
void FillPackageRootPath();
diff --git a/Source/cmFindLibraryCommand.cxx b/Source/cmFindLibraryCommand.cxx
index 1c4039b..6296a60 100644
--- a/Source/cmFindLibraryCommand.cxx
+++ b/Source/cmFindLibraryCommand.cxx
@@ -192,6 +192,7 @@ struct cmFindLibraryHelper
// Context information.
cmMakefile* Makefile;
+ cmFindBase const* FindBase;
cmGlobalGenerator* GG;
// List of valid prefixes and suffixes.
@@ -239,6 +240,11 @@ struct cmFindLibraryHelper
bool CheckDirectory(std::string const& path);
bool CheckDirectoryForName(std::string const& path, Name& name);
+ bool Validate(const std::string& path) const
+ {
+ return this->FindBase->Validate(path);
+ }
+
cmFindBaseDebugState DebugSearches;
void DebugLibraryFailed(std::string const& name, std::string const& path)
@@ -291,6 +297,7 @@ std::string const& get_suffixes(cmMakefile* mf)
cmFindLibraryHelper::cmFindLibraryHelper(std::string debugName, cmMakefile* mf,
cmFindBase const* base)
: Makefile(mf)
+ , FindBase(base)
, DebugMode(base->DebugModeEnabled())
, DebugSearches(std::move(debugName), base)
{
@@ -416,10 +423,13 @@ bool cmFindLibraryHelper::CheckDirectoryForName(std::string const& path,
if (!exists) {
this->DebugLibraryFailed(name.Raw, path);
} else {
- this->DebugLibraryFound(name.Raw, path);
- this->BestPath = cmSystemTools::CollapseFullPath(this->TestPath);
- cmSystemTools::ConvertToUnixSlashes(this->BestPath);
- return true;
+ auto testPath = cmSystemTools::CollapseFullPath(this->TestPath);
+ if (this->Validate(testPath)) {
+ this->DebugLibraryFound(name.Raw, path);
+ this->BestPath = testPath;
+ return true;
+ }
+ this->DebugLibraryFailed(name.Raw, path);
}
}
@@ -443,8 +453,11 @@ bool cmFindLibraryHelper::CheckDirectoryForName(std::string const& path,
this->TestPath = cmStrCat(path, origName);
// Make sure the path is readable and is not a directory.
if (cmSystemTools::FileExists(this->TestPath, true)) {
- this->DebugLibraryFound(name.Raw, dir);
+ if (!this->Validate(cmSystemTools::CollapseFullPath(this->TestPath))) {
+ continue;
+ }
+ this->DebugLibraryFound(name.Raw, dir);
// This is a matching file. Check if it is better than the
// best name found so far. Earlier prefixes are preferred,
// followed by earlier suffixes. For OpenBSD, shared library
@@ -541,7 +554,10 @@ std::string cmFindLibraryCommand::FindFrameworkLibraryNamesPerDir()
for (std::string const& n : this->Names) {
fwPath = cmStrCat(d, n, ".framework");
if (cmSystemTools::FileIsDirectory(fwPath)) {
- return cmSystemTools::CollapseFullPath(fwPath);
+ auto finalPath = cmSystemTools::CollapseFullPath(fwPath);
+ if (this->Validate(finalPath)) {
+ return finalPath;
+ }
}
}
}
@@ -558,7 +574,10 @@ std::string cmFindLibraryCommand::FindFrameworkLibraryDirsPerName()
for (std::string const& d : this->SearchPaths) {
fwPath = cmStrCat(d, n, ".framework");
if (cmSystemTools::FileIsDirectory(fwPath)) {
- return cmSystemTools::CollapseFullPath(fwPath);
+ auto finalPath = cmSystemTools::CollapseFullPath(fwPath);
+ if (this->Validate(finalPath)) {
+ return finalPath;
+ }
}
}
}
diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx
index 8c6a0aa..3f8378b 100644
--- a/Source/cmFindPackageCommand.cxx
+++ b/Source/cmFindPackageCommand.cxx
@@ -5,7 +5,6 @@
#include <algorithm>
#include <cassert>
#include <cstdio>
-#include <cstring>
#include <deque>
#include <functional>
#include <iterator>
@@ -43,8 +42,405 @@
# include <StorageDefs.h>
#endif
+#if defined(_WIN32) && !defined(__CYGWIN__)
+# include <windows.h>
+// http://msdn.microsoft.com/en-us/library/aa384253%28v=vs.85%29.aspx
+# if !defined(KEY_WOW64_32KEY)
+# define KEY_WOW64_32KEY 0x0200
+# endif
+# if !defined(KEY_WOW64_64KEY)
+# define KEY_WOW64_64KEY 0x0100
+# endif
+#endif
+
class cmExecutionStatus;
-class cmFileList;
+
+namespace {
+
+template <template <typename> class Op>
+struct StrverscmpOp
+{
+ bool operator()(const std::string& lhs, const std::string& rhs) const
+ {
+ return Op<int>()(cmSystemTools::strverscmp(lhs, rhs), 0);
+ }
+};
+
+std::size_t collectPathsForDebug(std::string& buffer,
+ cmSearchPath const& searchPath,
+ std::size_t const startIndex = 0)
+{
+ const auto& paths = searchPath.GetPaths();
+ if (paths.empty()) {
+ buffer += " none\n";
+ return 0;
+ }
+ for (auto i = startIndex; i < paths.size(); i++) {
+ buffer += " " + paths[i].Path + "\n";
+ }
+ return paths.size();
+}
+
+#if !(defined(_WIN32) && !defined(__CYGWIN__))
+class cmFindPackageCommandHoldFile
+{
+ const char* File;
+
+public:
+ cmFindPackageCommandHoldFile(const char* const f)
+ : File(f)
+ {
+ }
+ ~cmFindPackageCommandHoldFile()
+ {
+ if (this->File) {
+ cmSystemTools::RemoveFile(this->File);
+ }
+ }
+ cmFindPackageCommandHoldFile(const cmFindPackageCommandHoldFile&) = delete;
+ cmFindPackageCommandHoldFile& operator=(
+ const cmFindPackageCommandHoldFile&) = delete;
+ void Release() { this->File = nullptr; }
+};
+#endif
+
+bool isDirentryToIgnore(const char* const fname)
+{
+ assert(fname != nullptr);
+ assert(fname[0] != 0);
+ return fname[0] == '.' &&
+ (fname[1] == 0 || (fname[1] == '.' && fname[2] == 0));
+}
+
+class cmAppendPathSegmentGenerator
+{
+public:
+ cmAppendPathSegmentGenerator(cm::string_view dirName)
+ : DirName{ dirName }
+ {
+ }
+
+ std::string GetNextCandidate(const std::string& parent)
+ {
+ if (this->NeedReset) {
+ return {};
+ }
+ this->NeedReset = true;
+ return cmStrCat(parent, '/', this->DirName);
+ }
+
+ void Reset() { this->NeedReset = false; }
+
+private:
+ const cm::string_view DirName;
+ bool NeedReset = false;
+};
+
+class cmEnumPathSegmentsGenerator
+{
+public:
+ cmEnumPathSegmentsGenerator(const std::vector<cm::string_view>& init)
+ : Names{ init }
+ , Current{ this->Names.get().cbegin() }
+ {
+ }
+
+ std::string GetNextCandidate(const std::string& parent)
+ {
+ if (this->Current != this->Names.get().cend()) {
+ return cmStrCat(parent, '/', *this->Current++);
+ }
+ return {};
+ }
+
+ void Reset() { this->Current = this->Names.get().cbegin(); }
+
+private:
+ std::reference_wrapper<const std::vector<cm::string_view>> Names;
+ std::vector<cm::string_view>::const_iterator Current;
+};
+
+class cmCaseInsensitiveDirectoryListGenerator
+{
+public:
+ cmCaseInsensitiveDirectoryListGenerator(cm::string_view name)
+ : DirectoryLister{}
+ , DirName{ name }
+ {
+ }
+
+ std::string GetNextCandidate(const std::string& parent)
+ {
+ if (!this->Loaded) {
+ this->CurrentIdx = 0ul;
+ this->Loaded = true;
+ if (!this->DirectoryLister.Load(parent)) {
+ return {};
+ }
+ }
+
+ while (this->CurrentIdx < this->DirectoryLister.GetNumberOfFiles()) {
+ const char* const fname =
+ this->DirectoryLister.GetFile(this->CurrentIdx++);
+ if (isDirentryToIgnore(fname)) {
+ continue;
+ }
+ if (cmsysString_strcasecmp(fname, this->DirName.data()) == 0) {
+ auto candidate = cmStrCat(parent, '/', fname);
+ if (cmSystemTools::FileIsDirectory(candidate)) {
+ return candidate;
+ }
+ }
+ }
+ return {};
+ }
+
+ void Reset() { this->Loaded = false; }
+
+private:
+ cmsys::Directory DirectoryLister;
+ const cm::string_view DirName;
+ unsigned long CurrentIdx = 0ul;
+ bool Loaded = false;
+};
+
+class cmDirectoryListGenerator
+{
+public:
+ cmDirectoryListGenerator(std::vector<std::string> const& names)
+ : Names{ names }
+ , Matches{}
+ , Current{ this->Matches.cbegin() }
+ {
+ }
+ virtual ~cmDirectoryListGenerator() = default;
+
+ std::string GetNextCandidate(const std::string& parent)
+ {
+ // Construct a list of matches if not yet
+ if (this->Matches.empty()) {
+ cmsys::Directory directoryLister;
+ // ALERT `Directory::Load()` keeps only names
+ // internally and LOST entry type from `dirent`.
+ // So, `Directory::FileIsDirectory` gonna use
+ // `SystemTools::FileIsDirectory()` and waste a syscall.
+ // TODO Need to enhance the `Directory` class.
+ directoryLister.Load(parent);
+
+ // ATTENTION Is it guaranteed that first two entries are
+ // `.` and `..`?
+ // TODO If so, just start with index 2 and drop the
+ // `isDirentryToIgnore(i)` condition to check.
+ for (auto i = 0ul; i < directoryLister.GetNumberOfFiles(); ++i) {
+ const char* const fname = directoryLister.GetFile(i);
+ if (isDirentryToIgnore(fname)) {
+ continue;
+ }
+
+ for (const auto& n : this->Names.get()) {
+ // NOTE Customization point for `cmMacProjectDirectoryListGenerator`
+ const auto name = this->TransformNameBeforeCmp(n);
+ // Skip entries that don't match and non-directories.
+ // ATTENTION BTW, original code also didn't check if it's a symlink
+ // to a directory!
+ const auto equal =
+ (cmsysString_strncasecmp(fname, name.c_str(), name.length()) == 0);
+ if (equal && directoryLister.FileIsDirectory(i)) {
+ this->Matches.emplace_back(fname);
+ }
+ }
+ }
+ // NOTE Customization point for `cmProjectDirectoryListGenerator`
+ this->OnMatchesLoaded();
+
+ this->Current = this->Matches.cbegin();
+ }
+
+ if (this->Current != this->Matches.cend()) {
+ auto candidate = cmStrCat(parent, '/', *this->Current++);
+ return candidate;
+ }
+
+ return {};
+ }
+
+ void Reset()
+ {
+ this->Matches.clear();
+ this->Current = this->Matches.cbegin();
+ }
+
+protected:
+ virtual void OnMatchesLoaded() {}
+ virtual std::string TransformNameBeforeCmp(std::string same) { return same; }
+
+ std::reference_wrapper<const std::vector<std::string>> Names;
+ std::vector<std::string> Matches;
+ std::vector<std::string>::const_iterator Current;
+};
+
+class cmProjectDirectoryListGenerator : public cmDirectoryListGenerator
+{
+public:
+ cmProjectDirectoryListGenerator(std::vector<std::string> const& names,
+ cmFindPackageCommand::SortOrderType so,
+ cmFindPackageCommand::SortDirectionType sd)
+ : cmDirectoryListGenerator{ names }
+ , SortOrder{ so }
+ , SortDirection{ sd }
+ {
+ }
+
+protected:
+ void OnMatchesLoaded() override
+ {
+ // check if there is a specific sorting order to perform
+ if (this->SortOrder != cmFindPackageCommand::None) {
+ cmFindPackageCommand::Sort(this->Matches.begin(), this->Matches.end(),
+ this->SortOrder, this->SortDirection);
+ }
+ }
+
+private:
+ // sort parameters
+ const cmFindPackageCommand::SortOrderType SortOrder;
+ const cmFindPackageCommand::SortDirectionType SortDirection;
+};
+
+class cmMacProjectDirectoryListGenerator : public cmDirectoryListGenerator
+{
+public:
+ cmMacProjectDirectoryListGenerator(const std::vector<std::string>& names,
+ cm::string_view ext)
+ : cmDirectoryListGenerator{ names }
+ , Extension{ ext }
+ {
+ }
+
+protected:
+ std::string TransformNameBeforeCmp(std::string name) override
+ {
+ return cmStrCat(name, this->Extension);
+ }
+
+private:
+ const cm::string_view Extension;
+};
+
+class cmFileListGeneratorGlob
+{
+public:
+ cmFileListGeneratorGlob(cm::string_view pattern)
+ : Pattern(pattern)
+ , Files{}
+ , Current{}
+ {
+ }
+
+ std::string GetNextCandidate(const std::string& parent)
+ {
+ if (this->Files.empty()) {
+ // Glob the set of matching files.
+ std::string expr = cmStrCat(parent, this->Pattern);
+ cmsys::Glob g;
+ if (!g.FindFiles(expr)) {
+ return {};
+ }
+ this->Files = g.GetFiles();
+ this->Current = this->Files.cbegin();
+ }
+
+ // Skip non-directories
+ for (; this->Current != this->Files.cend() &&
+ !cmSystemTools::FileIsDirectory(*this->Current);
+ ++this->Current) {
+ }
+
+ return (this->Current != this->Files.cend()) ? *this->Current++
+ : std::string{};
+ }
+
+ void Reset()
+ {
+ this->Files.clear();
+ this->Current = this->Files.cbegin();
+ }
+
+private:
+ cm::string_view Pattern;
+ std::vector<std::string> Files;
+ std::vector<std::string>::const_iterator Current;
+};
+
+#if defined(__LCC__)
+# define CM_LCC_DIAG_SUPPRESS_1222
+# pragma diag_suppress 1222 // invalid error number (3288, but works anyway)
+# define CM_LCC_DIAG_SUPPRESS_3288
+# pragma diag_suppress 3288 // parameter was declared but never referenced
+#endif
+
+void ResetGenerator()
+{
+}
+
+template <typename Generator>
+void ResetGenerator(Generator&& generator)
+{
+ std::forward<Generator&&>(generator).Reset();
+}
+
+template <typename Generator, typename... Generators>
+void ResetGenerator(Generator&& generator, Generators&&... generators)
+{
+ ResetGenerator(std::forward<Generator&&>(generator));
+ ResetGenerator(std::forward<Generators&&>(generators)...);
+}
+
+template <typename CallbackFn>
+bool TryGeneratedPaths(CallbackFn&& filesCollector,
+ const std::string& fullPath)
+{
+ assert(!fullPath.empty() && fullPath.back() != '/');
+ return std::forward<CallbackFn&&>(filesCollector)(fullPath + '/');
+}
+
+template <typename CallbackFn, typename Generator, typename... Rest>
+bool TryGeneratedPaths(CallbackFn&& filesCollector,
+ const std::string& startPath, Generator&& gen,
+ Rest&&... tail)
+{
+ ResetGenerator(std::forward<Generator&&>(gen));
+ for (auto path = gen.GetNextCandidate(startPath); !path.empty();
+ path = gen.GetNextCandidate(startPath)) {
+ ResetGenerator(std::forward<Rest&&>(tail)...);
+ if (TryGeneratedPaths(std::forward<CallbackFn&&>(filesCollector), path,
+ std::forward<Rest&&>(tail)...)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+#ifdef CM_LCC_DIAG_SUPPRESS_3288
+# undef CM_LCC_DIAG_SUPPRESS_3288
+# pragma diag_default 3288
+#endif
+
+#ifdef CM_LCC_DIAG_SUPPRESS_1222
+# undef CM_LCC_DIAG_SUPPRESS_1222
+# pragma diag_default 1222
+#endif
+
+// Parse the version number and store the results that were
+// successfully parsed.
+int parseVersion(const std::string& version, unsigned int& major,
+ unsigned int& minor, unsigned int& patch, unsigned int& tweak)
+{
+ return std::sscanf(version.c_str(), "%u.%u.%u.%u", &major, &minor, &patch,
+ &tweak);
+}
+
+} // anonymous namespace
cmFindPackageCommand::PathLabel
cmFindPackageCommand::PathLabel::PackageRedirect("PACKAGE_REDIRECT");
@@ -60,25 +456,10 @@ const cm::string_view cmFindPackageCommand::VERSION_ENDPOINT_INCLUDED(
const cm::string_view cmFindPackageCommand::VERSION_ENDPOINT_EXCLUDED(
"EXCLUDE");
-struct StrverscmpGreater
-{
- bool operator()(const std::string& lhs, const std::string& rhs) const
- {
- return cmSystemTools::strverscmp(lhs, rhs) > 0;
- }
-};
-
-struct StrverscmpLesser
-{
- bool operator()(const std::string& lhs, const std::string& rhs) const
- {
- return cmSystemTools::strverscmp(lhs, rhs) < 0;
- }
-};
-
void cmFindPackageCommand::Sort(std::vector<std::string>::iterator begin,
std::vector<std::string>::iterator end,
- SortOrderType order, SortDirectionType dir)
+ SortOrderType const order,
+ SortDirectionType const dir)
{
if (order == Name_order) {
if (dir == Dec) {
@@ -86,14 +467,13 @@ void cmFindPackageCommand::Sort(std::vector<std::string>::iterator begin,
} else {
std::sort(begin, end);
}
- } else if (order == Natural)
- // natural order uses letters and numbers (contiguous numbers digit are
- // compared such that e.g. 000 00 < 01 < 010 < 09 < 0 < 1 < 9 < 10
- {
+ } else if (order == Natural) {
+ // natural order uses letters and numbers (contiguous numbers digit are
+ // compared such that e.g. 000 00 < 01 < 010 < 09 < 0 < 1 < 9 < 10
if (dir == Dec) {
- std::sort(begin, end, StrverscmpGreater());
+ std::sort(begin, end, StrverscmpOp<std::greater>());
} else {
- std::sort(begin, end, StrverscmpLesser());
+ std::sort(begin, end, StrverscmpOp<std::less>());
}
}
// else do not sort
@@ -113,11 +493,10 @@ cmFindPackageCommand::cmFindPackageCommand(cmExecutionStatus& status)
void cmFindPackageCommand::AppendSearchPathGroups()
{
- std::vector<cmFindCommon::PathLabel>* labels;
-
// Update the All group with new paths. Note that package redirection must
// take precedence over everything else, so it has to be first in the array.
- labels = &this->PathGroupLabelMap[PathGroup::All];
+ std::vector<cmFindCommon::PathLabel>* const labels =
+ &this->PathGroupLabelMap[PathGroup::All];
labels->insert(labels->begin(), PathLabel::PackageRedirect);
labels->insert(
std::find(labels->begin(), labels->end(), PathLabel::CMakeSystem),
@@ -147,15 +526,15 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
}
// Lookup required version of CMake.
- if (cmValue rv =
+ if (cmValue const rv =
this->Makefile->GetDefinition("CMAKE_MINIMUM_REQUIRED_VERSION")) {
unsigned int v[3] = { 0, 0, 0 };
- sscanf(rv->c_str(), "%u.%u.%u", &v[0], &v[1], &v[2]);
+ std::sscanf(rv->c_str(), "%u.%u.%u", &v[0], &v[1], &v[2]);
this->RequiredCMakeVersion = CMake_VERSION_ENCODE(v[0], v[1], v[2]);
}
// Lookup target architecture, if any.
- if (cmValue arch =
+ if (cmValue const arch =
this->Makefile->GetDefinition("CMAKE_LIBRARY_ARCHITECTURE")) {
this->LibraryArchitecture = *arch;
}
@@ -184,7 +563,7 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
// Check if User Package Registry should be disabled
// The `CMAKE_FIND_USE_PACKAGE_REGISTRY` has
// priority over the deprecated CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY
- if (cmValue def =
+ if (cmValue const def =
this->Makefile->GetDefinition("CMAKE_FIND_USE_PACKAGE_REGISTRY")) {
this->NoUserRegistry = !cmIsOn(*def);
} else if (this->Makefile->IsOn("CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY")) {
@@ -194,7 +573,7 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
// Check if System Package Registry should be disabled
// The `CMAKE_FIND_USE_SYSTEM_PACKAGE_REGISTRY` has
// priority over the deprecated CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY
- if (cmValue def = this->Makefile->GetDefinition(
+ if (cmValue const def = this->Makefile->GetDefinition(
"CMAKE_FIND_USE_SYSTEM_PACKAGE_REGISTRY")) {
this->NoSystemRegistry = !cmIsOn(*def);
} else if (this->Makefile->IsOn(
@@ -208,7 +587,7 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
}
// Check if Sorting should be enabled
- if (cmValue so =
+ if (cmValue const so =
this->Makefile->GetDefinition("CMAKE_FIND_PACKAGE_SORT_ORDER")) {
if (*so == "NAME") {
@@ -219,7 +598,7 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
this->SortOrder = None;
}
}
- if (cmValue sd =
+ if (cmValue const sd =
this->Makefile->GetDefinition("CMAKE_FIND_PACKAGE_SORT_DIRECTION")) {
this->SortDirection = (*sd == "ASC") ? Asc : Dec;
}
@@ -265,9 +644,9 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
cmsys::RegularExpression versionRegex(
R"V(^([0-9]+(\.[0-9]+)*)(\.\.\.(<?)([0-9]+(\.[0-9]+)*))?$)V");
bool haveVersion = false;
- std::set<unsigned int> configArgs;
- std::set<unsigned int> moduleArgs;
- for (unsigned int i = 1; i < args.size(); ++i) {
+ std::vector<std::size_t> configArgs;
+ std::vector<std::size_t> moduleArgs;
+ for (std::size_t i = 1u; i < args.size(); ++i) {
if (args[i] == "QUIET") {
this->Quiet = true;
doing = DoingNone;
@@ -281,17 +660,17 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
this->GlobalScope = true;
doing = DoingNone;
} else if (args[i] == "MODULE") {
- moduleArgs.insert(i);
+ moduleArgs.push_back(i);
doing = DoingNone;
// XXX(clang-tidy): https://bugs.llvm.org/show_bug.cgi?id=44165
// NOLINTNEXTLINE(bugprone-branch-clone)
} else if (args[i] == "CONFIG") {
- configArgs.insert(i);
+ configArgs.push_back(i);
doing = DoingNone;
// XXX(clang-tidy): https://bugs.llvm.org/show_bug.cgi?id=44165
// NOLINTNEXTLINE(bugprone-branch-clone)
} else if (args[i] == "NO_MODULE") {
- configArgs.insert(i);
+ configArgs.push_back(i);
doing = DoingNone;
} else if (args[i] == "REQUIRED") {
this->Required = true;
@@ -301,36 +680,36 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
} else if (args[i] == "OPTIONAL_COMPONENTS") {
doing = DoingOptionalComponents;
} else if (args[i] == "NAMES") {
- configArgs.insert(i);
+ configArgs.push_back(i);
doing = DoingNames;
} else if (args[i] == "PATHS") {
- configArgs.insert(i);
+ configArgs.push_back(i);
doing = DoingPaths;
} else if (args[i] == "HINTS") {
- configArgs.insert(i);
+ configArgs.push_back(i);
doing = DoingHints;
} else if (args[i] == "PATH_SUFFIXES") {
- configArgs.insert(i);
+ configArgs.push_back(i);
doing = DoingPathSuffixes;
} else if (args[i] == "CONFIGS") {
- configArgs.insert(i);
+ configArgs.push_back(i);
doing = DoingConfigs;
} else if (args[i] == "NO_POLICY_SCOPE") {
this->PolicyScope = false;
doing = DoingNone;
} else if (args[i] == "NO_CMAKE_PACKAGE_REGISTRY") {
this->NoUserRegistry = true;
- configArgs.insert(i);
+ configArgs.push_back(i);
doing = DoingNone;
} else if (args[i] == "NO_CMAKE_SYSTEM_PACKAGE_REGISTRY") {
this->NoSystemRegistry = true;
- configArgs.insert(i);
+ configArgs.push_back(i);
doing = DoingNone;
// XXX(clang-tidy): https://bugs.llvm.org/show_bug.cgi?id=44165
// NOLINTNEXTLINE(bugprone-branch-clone)
} else if (args[i] == "NO_CMAKE_BUILDS_PATH") {
// Ignore legacy option.
- configArgs.insert(i);
+ configArgs.push_back(i);
doing = DoingNone;
} else if (args[i] == "REGISTRY_VIEW") {
if (++i == args.size()) {
@@ -347,7 +726,7 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
return false;
}
} else if (this->CheckCommonArgument(args[i])) {
- configArgs.insert(i);
+ configArgs.push_back(i);
doing = DoingNone;
} else if ((doing == DoingComponents) ||
(doing == DoingOptionalComponents)) {
@@ -361,8 +740,8 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
requiredComponents.insert(args[i]);
}
- std::string req_var = this->Name + "_FIND_REQUIRED_" + args[i];
- componentVarDefs.emplace_back(req_var, isRequired);
+ componentVarDefs.emplace_back(this->Name + "_FIND_REQUIRED_" + args[i],
+ isRequired);
// Append to the list of required components.
components += components_sep;
@@ -420,11 +799,11 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
if (!this->UseFindModules && !this->UseConfigFiles) {
std::ostringstream e;
e << "given options exclusive to Module mode:\n";
- for (unsigned int si : moduleArgs) {
+ for (auto si : moduleArgs) {
e << " " << args[si] << "\n";
}
e << "and options exclusive to Config mode:\n";
- for (unsigned int si : configArgs) {
+ for (auto si : configArgs) {
e << " " << args[si] << "\n";
}
e << "The options are incompatible.";
@@ -443,20 +822,20 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
if (this->VersionComplete.empty() || components.empty()) {
// Check whether we are recursing inside "Find<name>.cmake" within
// another find_package(<name>) call.
- std::string mod = cmStrCat(this->Name, "_FIND_MODULE");
+ std::string const mod = cmStrCat(this->Name, "_FIND_MODULE");
if (this->Makefile->IsOn(mod)) {
if (this->VersionComplete.empty()) {
// Get version information from the outer call if necessary.
// Requested version string.
- std::string ver = cmStrCat(this->Name, "_FIND_VERSION_COMPLETE");
+ std::string const ver = cmStrCat(this->Name, "_FIND_VERSION_COMPLETE");
this->VersionComplete = this->Makefile->GetSafeDefinition(ver);
// Whether an exact version is required.
- std::string exact = cmStrCat(this->Name, "_FIND_VERSION_EXACT");
+ std::string const exact = cmStrCat(this->Name, "_FIND_VERSION_EXACT");
this->VersionExact = this->Makefile->IsOn(exact);
}
if (components.empty()) {
- std::string components_var = this->Name + "_FIND_COMPONENTS";
+ std::string const components_var = this->Name + "_FIND_COMPONENTS";
components = this->Makefile->GetSafeDefinition(components_var);
}
}
@@ -497,15 +876,6 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
return false;
}
- // Parse the version number and store the results that were
- // successfully parsed.
- auto parseVersion = [](const std::string& version, unsigned int& major,
- unsigned int& minor, unsigned int& patch,
- unsigned int& tweak) -> unsigned int {
- return sscanf(version.c_str(), "%u.%u.%u.%u", &major, &minor, &patch,
- &tweak);
- };
-
if (!this->Version.empty()) {
this->VersionCount =
parseVersion(this->Version, this->VersionMajor, this->VersionMinor,
@@ -533,7 +903,7 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
}
}
- std::string disableFindPackageVar =
+ std::string const disableFindPackageVar =
cmStrCat("CMAKE_DISABLE_FIND_PACKAGE_", this->Name);
if (this->Makefile->IsOn(disableFindPackageVar)) {
if (this->Required) {
@@ -557,8 +927,8 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
// A dependency provider (if set) gets first look before other methods.
// We do this before modifying the package root path stack because a
// provider might use methods that ignore that.
- cmState* state = this->Makefile->GetState();
- cmState::Command providerCommand = state->GetDependencyProviderCommand(
+ cmState* const state = this->Makefile->GetState();
+ cmState::Command const providerCommand = state->GetDependencyProviderCommand(
cmDependencyProvider::Method::FindPackage);
if (bypassProvider) {
if (this->DebugMode && providerCommand) {
@@ -725,11 +1095,8 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
"package configuration file provided by "
<< this->Name << " (" << this->Name << "Config.cmake or "
<< cmSystemTools::LowerCase(this->Name)
- << "-config.cmake). "
- "Otherwise make Find"
- << this->Name
- << ".cmake available in "
- "CMAKE_MODULE_PATH.";
+ << "-config.cmake). Otherwise make Find" << this->Name
+ << ".cmake available in CMAKE_MODULE_PATH.";
}
aw << "\n"
"(Variable CMAKE_FIND_PACKAGE_WARN_NO_MODULE enabled this "
@@ -813,22 +1180,22 @@ bool cmFindPackageCommand::FindPackageUsingConfigMode()
void cmFindPackageCommand::SetVersionVariables(
const std::function<void(const std::string&, cm::string_view)>&
addDefinition,
- const std::string& prefix, const std::string& version, unsigned int count,
- unsigned int major, unsigned int minor, unsigned int patch,
- unsigned int tweak)
+ const std::string& prefix, const std::string& version,
+ const unsigned int count, const unsigned int major, const unsigned int minor,
+ const unsigned int patch, const unsigned int tweak)
{
addDefinition(prefix, version);
char buf[64];
snprintf(buf, sizeof(buf), "%u", major);
addDefinition(prefix + "_MAJOR", buf);
- sprintf(buf, "%u", minor);
+ snprintf(buf, sizeof(buf), "%u", minor);
addDefinition(prefix + "_MINOR", buf);
- sprintf(buf, "%u", patch);
+ snprintf(buf, sizeof(buf), "%u", patch);
addDefinition(prefix + "_PATCH", buf);
- sprintf(buf, "%u", tweak);
+ snprintf(buf, sizeof(buf), "%u", tweak);
addDefinition(prefix + "_TWEAK", buf);
- sprintf(buf, "%u", count);
+ snprintf(buf, sizeof(buf), "%u", count);
addDefinition(prefix + "_COUNT", buf);
}
@@ -910,7 +1277,7 @@ void cmFindPackageCommand::SetModuleVariables(
}
void cmFindPackageCommand::AddFindDefinition(const std::string& var,
- cm::string_view value)
+ const cm::string_view value)
{
if (cmValue old = this->Makefile->GetDefinition(var)) {
this->OriginalDefs[var].exists = true;
@@ -954,7 +1321,7 @@ bool cmFindPackageCommand::FindModule(bool& found)
if (!mfile.empty()) {
if (system) {
- auto it = this->DeprecatedFindModules.find(this->Name);
+ auto const it = this->DeprecatedFindModules.find(this->Name);
if (it != this->DeprecatedFindModules.end()) {
cmPolicies::PolicyStatus status =
this->Makefile->GetPolicyStatus(it->second);
@@ -978,13 +1345,13 @@ bool cmFindPackageCommand::FindModule(bool& found)
// Load the module we found, and set "<name>_FIND_MODULE" to true
// while inside it.
found = true;
- std::string var = cmStrCat(this->Name, "_FIND_MODULE");
+ std::string const var = cmStrCat(this->Name, "_FIND_MODULE");
this->Makefile->AddDefinition(var, "1");
bool result = this->ReadListFile(mfile, DoPolicyScope);
this->Makefile->RemoveDefinition(var);
if (this->DebugMode) {
- std::string foundVar = cmStrCat(this->Name, "_FOUND");
+ std::string const foundVar = cmStrCat(this->Name, "_FOUND");
if (this->Makefile->IsDefinitionSet(foundVar) &&
!this->Makefile->IsOn(foundVar)) {
@@ -999,7 +1366,7 @@ bool cmFindPackageCommand::FindModule(bool& found)
}
bool cmFindPackageCommand::HandlePackageMode(
- HandlePackageModeType handlePackageModeType)
+ const HandlePackageModeType handlePackageModeType)
{
this->ConsideredConfigs.clear();
@@ -1042,8 +1409,9 @@ bool cmFindPackageCommand::HandlePackageMode(
}
}
- std::string foundVar = cmStrCat(this->Name, "_FOUND");
- std::string notFoundMessageVar = cmStrCat(this->Name, "_NOT_FOUND_MESSAGE");
+ std::string const foundVar = cmStrCat(this->Name, "_FOUND");
+ std::string const notFoundMessageVar =
+ cmStrCat(this->Name, "_NOT_FOUND_MESSAGE");
std::string notFoundMessage;
// If the directory for the config file was found, try to read the file.
@@ -1123,8 +1491,9 @@ bool cmFindPackageCommand::HandlePackageMode(
<< (this->VersionExact ? "exactly matches" : "is compatible with")
<< " requested version "
<< (this->VersionRange.empty() ? "" : "range ") << "\""
- << this->VersionComplete << "\".\n"
- << "The following configuration files were considered but not "
+ << this->VersionComplete
+ << "\".\n"
+ "The following configuration files were considered but not "
"accepted:\n";
for (ConfigFileInfo const& info :
@@ -1172,8 +1541,9 @@ bool cmFindPackageCommand::HandlePackageMode(
"package or SDK, be sure it has been installed.";
} else // if(!this->UseFindModules && !this->UseConfigFiles)
{
- e << "No \"Find" << this->Name << ".cmake\" found in "
- << "CMAKE_MODULE_PATH.";
+ e << "No \"Find" << this->Name
+ << ".cmake\" found in "
+ "CMAKE_MODULE_PATH.";
aw
<< "Find" << this->Name
@@ -1217,16 +1587,16 @@ bool cmFindPackageCommand::HandlePackageMode(
this->Makefile->AddDefinition(foundVar, found ? "1" : "0");
// Set a variable naming the configuration file that was found.
- std::string fileVar = cmStrCat(this->Name, "_CONFIG");
+ std::string const fileVar = cmStrCat(this->Name, "_CONFIG");
if (found) {
this->Makefile->AddDefinition(fileVar, this->FileFound);
} else {
this->Makefile->RemoveDefinition(fileVar);
}
- std::string consideredConfigsVar =
+ std::string const consideredConfigsVar =
cmStrCat(this->Name, "_CONSIDERED_CONFIGS");
- std::string consideredVersionsVar =
+ std::string const consideredVersionsVar =
cmStrCat(this->Name, "_CONSIDERED_VERSIONS");
std::string consideredConfigFiles;
@@ -1312,7 +1682,7 @@ bool cmFindPackageCommand::FindConfig()
void cmFindPackageCommand::SetConfigDirCacheVariable(const std::string& value)
{
- std::string help =
+ std::string const help =
cmStrCat("The directory containing a CMake configuration file for ",
this->Name, '.');
this->Makefile->AddCacheDefinition(this->Variable, value, help.c_str(),
@@ -1351,7 +1721,7 @@ bool cmFindPackageCommand::FindAppBundleConfig()
}
bool cmFindPackageCommand::ReadListFile(const std::string& f,
- PolicyScopeRule psr)
+ const PolicyScopeRule psr)
{
const bool noPolicyScope = !this->PolicyScope || psr == NoPolicyScope;
@@ -1362,12 +1732,12 @@ bool cmFindPackageCommand::ReadListFile(const std::string& f,
if (this->Makefile->ReadDependentFile(f, noPolicyScope)) {
return true;
}
- std::string e = cmStrCat("Error reading CMake code from \"", f, "\".");
+ std::string const e = cmStrCat("Error reading CMake code from \"", f, "\".");
this->SetError(e);
return false;
}
-void cmFindPackageCommand::AppendToFoundProperty(bool found)
+void cmFindPackageCommand::AppendToFoundProperty(const bool found)
{
std::vector<std::string> foundContents;
cmValue foundProp =
@@ -1410,27 +1780,28 @@ void cmFindPackageCommand::AppendToFoundProperty(bool found)
void cmFindPackageCommand::AppendSuccessInformation()
{
{
- std::string transitivePropName =
+ std::string const transitivePropName =
cmStrCat("_CMAKE_", this->Name, "_TRANSITIVE_DEPENDENCY");
this->Makefile->GetState()->SetGlobalProperty(transitivePropName, "False");
}
- std::string found = cmStrCat(this->Name, "_FOUND");
- std::string upperFound = cmSystemTools::UpperCase(found);
+ std::string const found = cmStrCat(this->Name, "_FOUND");
+ std::string const upperFound = cmSystemTools::UpperCase(found);
- bool upperResult = this->Makefile->IsOn(upperFound);
- bool result = this->Makefile->IsOn(found);
- bool packageFound = (result || upperResult);
+ bool const upperResult = this->Makefile->IsOn(upperFound);
+ bool const result = this->Makefile->IsOn(found);
+ bool const packageFound = (result || upperResult);
this->AppendToFoundProperty(packageFound);
// Record whether the find was quiet or not, so this can be used
// e.g. in FeatureSummary.cmake
- std::string quietInfoPropName = cmStrCat("_CMAKE_", this->Name, "_QUIET");
+ std::string const quietInfoPropName =
+ cmStrCat("_CMAKE_", this->Name, "_QUIET");
this->Makefile->GetState()->SetGlobalProperty(
quietInfoPropName, this->Quiet ? "TRUE" : "FALSE");
// set a global property to record the required version of this package
- std::string versionInfoPropName =
+ std::string const versionInfoPropName =
cmStrCat("_CMAKE_", this->Name, "_REQUIRED_VERSION");
std::string versionInfo;
if (!this->VersionRange.empty()) {
@@ -1442,28 +1813,13 @@ void cmFindPackageCommand::AppendSuccessInformation()
this->Makefile->GetState()->SetGlobalProperty(versionInfoPropName,
versionInfo.c_str());
if (this->Required) {
- std::string requiredInfoPropName =
+ std::string const requiredInfoPropName =
cmStrCat("_CMAKE_", this->Name, "_TYPE");
this->Makefile->GetState()->SetGlobalProperty(requiredInfoPropName,
"REQUIRED");
}
}
-inline std::size_t collectPathsForDebug(std::string& buffer,
- cmSearchPath const& searchPath,
- std::size_t startIndex = 0)
-{
- const auto& paths = searchPath.GetPaths();
- if (paths.empty()) {
- buffer += " none\n";
- return 0;
- }
- for (std::size_t i = startIndex; i < paths.size(); i++) {
- buffer += " " + paths[i].Path + "\n";
- }
- return paths.size();
-}
-
void cmFindPackageCommand::ComputePrefixes()
{
this->FillPrefixesPackageRedirect();
@@ -1674,14 +2030,6 @@ void cmFindPackageCommand::FillPrefixesSystemRegistry()
}
#if defined(_WIN32) && !defined(__CYGWIN__)
-# include <windows.h>
-// http://msdn.microsoft.com/en-us/library/aa384253%28v=vs.85%29.aspx
-# if !defined(KEY_WOW64_32KEY)
-# define KEY_WOW64_32KEY 0x0200
-# endif
-# if !defined(KEY_WOW64_64KEY)
-# define KEY_WOW64_64KEY 0x0100
-# endif
void cmFindPackageCommand::LoadPackageRegistryWinUser()
{
// HKEY_CURRENT_USER\\Software shares 32-bit and 64-bit views.
@@ -1704,7 +2052,8 @@ void cmFindPackageCommand::LoadPackageRegistryWinSystem()
}
}
-void cmFindPackageCommand::LoadPackageRegistryWin(bool user, unsigned int view,
+void cmFindPackageCommand::LoadPackageRegistryWin(const bool user,
+ const unsigned int view,
cmSearchPath& outPaths)
{
std::wstring key = L"Software\\Kitware\\CMake\\Packages\\";
@@ -1756,28 +2105,8 @@ void cmFindPackageCommand::LoadPackageRegistryWin(bool user, unsigned int view,
RegCloseKey(hKey);
}
}
-#else
-class cmFindPackageCommandHoldFile
-{
- const char* File;
-
-public:
- cmFindPackageCommandHoldFile(const char* f)
- : File(f)
- {
- }
- ~cmFindPackageCommandHoldFile()
- {
- if (this->File) {
- cmSystemTools::RemoveFile(this->File);
- }
- }
- cmFindPackageCommandHoldFile(const cmFindPackageCommandHoldFile&) = delete;
- cmFindPackageCommandHoldFile& operator=(
- const cmFindPackageCommandHoldFile&) = delete;
- void Release() { this->File = nullptr; }
-};
+#else
void cmFindPackageCommand::LoadPackageRegistryDir(std::string const& dir,
cmSearchPath& outPaths)
{
@@ -1877,7 +2206,7 @@ void cmFindPackageCommand::FillPrefixesCMakeSystemVariable()
std::vector<std::string> expanded = cmExpandedList(*prefix_paths);
long count = 0;
for (const auto& path : expanded) {
- bool to_add =
+ bool const to_add =
!(path == install_path_to_remove && ++count == install_prefix_count);
if (to_add) {
paths.AddPath(path);
@@ -1941,7 +2270,7 @@ bool cmFindPackageCommand::SearchDirectory(std::string const& dir)
std::string d = dir;
if (!s.empty()) {
d += s;
- d += "/";
+ d += '/';
}
if (this->CheckDirectory(d)) {
return true;
@@ -1955,7 +2284,7 @@ bool cmFindPackageCommand::CheckDirectory(std::string const& dir)
assert(!dir.empty() && dir.back() == '/');
// Look for the file in this directory.
- std::string d = dir.substr(0, dir.size() - 1);
+ std::string const d = dir.substr(0, dir.size() - 1);
if (this->FindConfigFile(d, this->FileFound)) {
// Remove duplicate slashes.
cmSystemTools::ConvertToUnixSlashes(this->FileFound);
@@ -2028,8 +2357,8 @@ bool cmFindPackageCommand::CheckVersionFile(std::string const& version_file,
std::string& result_version)
{
// The version file will be loaded in an isolated scope.
- cmMakefile::ScopePushPop varScope(this->Makefile);
- cmMakefile::PolicyPushPop polScope(this->Makefile);
+ cmMakefile::ScopePushPop const varScope(this->Makefile);
+ cmMakefile::PolicyPushPop const polScope(this->Makefile);
static_cast<void>(varScope);
static_cast<void>(polScope);
@@ -2076,7 +2405,7 @@ bool cmFindPackageCommand::CheckVersionFile(std::string const& version_file,
if (this->ReadListFile(version_file, NoPolicyScope)) {
// Check the output variables.
bool okay = this->Makefile->IsOn("PACKAGE_VERSION_EXACT");
- bool unsuitable = this->Makefile->IsOn("PACKAGE_VERSION_UNSUITABLE");
+ bool const unsuitable = this->Makefile->IsOn("PACKAGE_VERSION_UNSUITABLE");
if (!okay && !this->VersionExact) {
okay = this->Makefile->IsOn("PACKAGE_VERSION_COMPATIBLE");
}
@@ -2096,8 +2425,8 @@ bool cmFindPackageCommand::CheckVersionFile(std::string const& version_file,
unsigned int parsed_patch;
unsigned int parsed_tweak;
this->VersionFoundCount =
- sscanf(this->VersionFound.c_str(), "%u.%u.%u.%u", &parsed_major,
- &parsed_minor, &parsed_patch, &parsed_tweak);
+ parseVersion(this->VersionFound, parsed_major, parsed_minor,
+ parsed_patch, parsed_tweak);
switch (this->VersionFoundCount) {
case 4:
this->VersionFoundTweak = parsed_tweak;
@@ -2129,7 +2458,7 @@ bool cmFindPackageCommand::CheckVersionFile(std::string const& version_file,
void cmFindPackageCommand::StoreVersionFound()
{
// Store the whole version string.
- std::string ver = cmStrCat(this->Name, "_VERSION");
+ std::string const ver = cmStrCat(this->Name, "_VERSION");
auto addDefinition = [this](const std::string& variable,
cm::string_view value) {
this->Makefile->AddDefinition(variable, value);
@@ -2145,357 +2474,6 @@ void cmFindPackageCommand::StoreVersionFound()
}
}
-class cmFileListGeneratorBase
-{
-public:
- virtual ~cmFileListGeneratorBase() = default;
-
-protected:
- bool Consider(std::string const& fullPath, cmFileList& listing);
-
-private:
- bool Search(cmFileList&);
- virtual bool Search(std::string const& parent, cmFileList&) = 0;
- virtual std::unique_ptr<cmFileListGeneratorBase> Clone() const = 0;
- friend class cmFileList;
- cmFileListGeneratorBase* SetNext(cmFileListGeneratorBase const& next);
- std::unique_ptr<cmFileListGeneratorBase> Next;
-};
-
-class cmFileList
-{
-public:
- virtual ~cmFileList() = default;
- cmFileList& operator/(cmFileListGeneratorBase const& rhs)
- {
- if (this->Last) {
- this->Last = this->Last->SetNext(rhs);
- } else {
- this->First = rhs.Clone();
- this->Last = this->First.get();
- }
- return *this;
- }
- bool Search()
- {
- if (this->First) {
- return this->First->Search(*this);
- }
- return false;
- }
-
-private:
- virtual bool Visit(std::string const& fullPath) = 0;
- friend class cmFileListGeneratorBase;
- std::unique_ptr<cmFileListGeneratorBase> First;
- cmFileListGeneratorBase* Last = nullptr;
-};
-
-class cmFindPackageFileList : public cmFileList
-{
-public:
- cmFindPackageFileList(cmFindPackageCommand* fpc, bool use_suffixes = true)
- : FPC(fpc)
- , UseSuffixes(use_suffixes)
- {
- }
-
-private:
- bool Visit(std::string const& fullPath) override
- {
- if (this->UseSuffixes) {
- return this->FPC->SearchDirectory(fullPath);
- }
- return this->FPC->CheckDirectory(fullPath);
- }
- cmFindPackageCommand* FPC;
- bool UseSuffixes;
-};
-
-bool cmFileListGeneratorBase::Search(cmFileList& listing)
-{
- return this->Search("", listing);
-}
-
-cmFileListGeneratorBase* cmFileListGeneratorBase::SetNext(
- cmFileListGeneratorBase const& next)
-{
- this->Next = next.Clone();
- return this->Next.get();
-}
-
-bool cmFileListGeneratorBase::Consider(std::string const& fullPath,
- cmFileList& listing)
-{
- if (!fullPath.empty() && !cmSystemTools::FileIsDirectory(fullPath)) {
- return false;
- }
- if (this->Next) {
- return this->Next->Search(fullPath + "/", listing);
- }
- return listing.Visit(fullPath + "/");
-}
-
-class cmFileListGeneratorFixed : public cmFileListGeneratorBase
-{
-public:
- cmFileListGeneratorFixed(std::string str)
- : String(std::move(str))
- {
- }
- cmFileListGeneratorFixed(cmFileListGeneratorFixed const& r)
- : String(r.String)
- {
- }
-
-private:
- std::string String;
- bool Search(std::string const& parent, cmFileList& lister) override
- {
- std::string fullPath = parent + this->String;
- return this->Consider(fullPath, lister);
- }
- std::unique_ptr<cmFileListGeneratorBase> Clone() const override
- {
- std::unique_ptr<cmFileListGeneratorBase> g(
- new cmFileListGeneratorFixed(*this));
- return g;
- }
-};
-
-class cmFileListGeneratorEnumerate : public cmFileListGeneratorBase
-{
-public:
- cmFileListGeneratorEnumerate(std::vector<std::string> const& v)
- : Vector(v)
- {
- }
- cmFileListGeneratorEnumerate(cmFileListGeneratorEnumerate const& r)
- : Vector(r.Vector)
- {
- }
-
-private:
- std::vector<std::string> const& Vector;
- bool Search(std::string const& parent, cmFileList& lister) override
- {
- for (std::string const& i : this->Vector) {
- if (this->Consider(parent + i, lister)) {
- return true;
- }
- }
- return false;
- }
- std::unique_ptr<cmFileListGeneratorBase> Clone() const override
- {
- std::unique_ptr<cmFileListGeneratorBase> g(
- new cmFileListGeneratorEnumerate(*this));
- return g;
- }
-};
-
-class cmFileListGeneratorProject : public cmFileListGeneratorBase
-{
-public:
- cmFileListGeneratorProject(std::vector<std::string> const& names,
- cmFindPackageCommand::SortOrderType so,
- cmFindPackageCommand::SortDirectionType sd)
- : Names(names)
- {
- this->SetSort(so, sd);
- }
- cmFileListGeneratorProject(cmFileListGeneratorProject const& r)
- : Names(r.Names)
- {
- this->SetSort(r.SortOrder, r.SortDirection);
- }
-
- void SetSort(cmFindPackageCommand::SortOrderType o,
- cmFindPackageCommand::SortDirectionType d)
- {
- this->SortOrder = o;
- this->SortDirection = d;
- }
-
-protected:
- // sort parameters
- cmFindPackageCommand::SortOrderType SortOrder;
- cmFindPackageCommand::SortDirectionType SortDirection;
-
-private:
- std::vector<std::string> const& Names;
- bool Search(std::string const& parent, cmFileList& lister) override
- {
- // Construct a list of matches.
- std::vector<std::string> matches;
- cmsys::Directory d;
- d.Load(parent);
- for (unsigned long i = 0; i < d.GetNumberOfFiles(); ++i) {
- const char* fname = d.GetFile(i);
- if (strcmp(fname, ".") == 0 || strcmp(fname, "..") == 0) {
- continue;
- }
- for (std::string const& n : this->Names) {
- if (cmsysString_strncasecmp(fname, n.c_str(), n.length()) == 0) {
- matches.emplace_back(fname);
- }
- }
- }
-
- // before testing the matches check if there is a specific sorting order to
- // perform
- if (this->SortOrder != cmFindPackageCommand::None) {
- cmFindPackageCommand::Sort(matches.begin(), matches.end(),
- this->SortOrder, this->SortDirection);
- }
-
- for (std::string const& i : matches) {
- if (this->Consider(parent + i, lister)) {
- return true;
- }
- }
- return false;
- }
- std::unique_ptr<cmFileListGeneratorBase> Clone() const override
- {
- std::unique_ptr<cmFileListGeneratorBase> g(
- new cmFileListGeneratorProject(*this));
- return g;
- }
-};
-
-class cmFileListGeneratorMacProject : public cmFileListGeneratorBase
-{
-public:
- cmFileListGeneratorMacProject(std::vector<std::string> const& names,
- const char* ext)
- : Names(names)
- , Extension(ext)
- {
- }
- cmFileListGeneratorMacProject(cmFileListGeneratorMacProject const& r)
- : Names(r.Names)
- , Extension(r.Extension)
- {
- }
-
-private:
- std::vector<std::string> const& Names;
- std::string Extension;
- bool Search(std::string const& parent, cmFileList& lister) override
- {
- // Construct a list of matches.
- std::vector<std::string> matches;
- cmsys::Directory d;
- d.Load(parent);
- for (unsigned long i = 0; i < d.GetNumberOfFiles(); ++i) {
- const char* fname = d.GetFile(i);
- if (strcmp(fname, ".") == 0 || strcmp(fname, "..") == 0) {
- continue;
- }
- for (std::string name : this->Names) {
- name += this->Extension;
- if (cmsysString_strcasecmp(fname, name.c_str()) == 0) {
- matches.emplace_back(fname);
- }
- }
- }
-
- for (std::string const& i : matches) {
- if (this->Consider(parent + i, lister)) {
- return true;
- }
- }
- return false;
- }
- std::unique_ptr<cmFileListGeneratorBase> Clone() const override
- {
- std::unique_ptr<cmFileListGeneratorBase> g(
- new cmFileListGeneratorMacProject(*this));
- return g;
- }
-};
-
-class cmFileListGeneratorCaseInsensitive : public cmFileListGeneratorBase
-{
-public:
- cmFileListGeneratorCaseInsensitive(std::string str)
- : String(std::move(str))
- {
- }
- cmFileListGeneratorCaseInsensitive(
- cmFileListGeneratorCaseInsensitive const& r)
- : String(r.String)
- {
- }
-
-private:
- std::string String;
- bool Search(std::string const& parent, cmFileList& lister) override
- {
- // Look for matching files.
- std::vector<std::string> matches;
- cmsys::Directory d;
- d.Load(parent);
- for (unsigned long i = 0; i < d.GetNumberOfFiles(); ++i) {
- const char* fname = d.GetFile(i);
- if (strcmp(fname, ".") == 0 || strcmp(fname, "..") == 0) {
- continue;
- }
- if (cmsysString_strcasecmp(fname, this->String.c_str()) == 0) {
- if (this->Consider(parent + fname, lister)) {
- return true;
- }
- }
- }
- return false;
- }
- std::unique_ptr<cmFileListGeneratorBase> Clone() const override
- {
- std::unique_ptr<cmFileListGeneratorBase> g(
- new cmFileListGeneratorCaseInsensitive(*this));
- return g;
- }
-};
-
-class cmFileListGeneratorGlob : public cmFileListGeneratorBase
-{
-public:
- cmFileListGeneratorGlob(std::string str)
- : Pattern(std::move(str))
- {
- }
- cmFileListGeneratorGlob(cmFileListGeneratorGlob const& r)
- : Pattern(r.Pattern)
- {
- }
-
-private:
- std::string Pattern;
- bool Search(std::string const& parent, cmFileList& lister) override
- {
- // Glob the set of matching files.
- std::string expr = cmStrCat(parent, this->Pattern);
- cmsys::Glob g;
- if (!g.FindFiles(expr)) {
- return false;
- }
- std::vector<std::string> const& files = g.GetFiles();
-
- // Look for directories among the matches.
- for (std::string const& f : files) {
- if (this->Consider(f, lister)) {
- return true;
- }
- }
- return false;
- }
- std::unique_ptr<cmFileListGeneratorBase> Clone() const override
- {
- return cm::make_unique<cmFileListGeneratorGlob>(*this);
- }
-};
-
bool cmFindPackageCommand::SearchPrefix(std::string const& prefix_in)
{
assert(!prefix_in.empty() && prefix_in.back() == '/');
@@ -2515,148 +2493,101 @@ bool cmFindPackageCommand::SearchPrefix(std::string const& prefix_in)
return false;
}
- // PREFIX/ (useful on windows or in build trees)
+ // PREFIX/ (useful on windows or in build trees)
if (this->SearchDirectory(prefix_in)) {
return true;
}
// Strip the trailing slash because the path generator is about to
// add one.
- std::string prefix = prefix_in.substr(0, prefix_in.size() - 1);
+ std::string const prefix = prefix_in.substr(0, prefix_in.size() - 1);
- // PREFIX/(cmake|CMake)/ (useful on windows or in build trees)
- {
- cmFindPackageFileList lister(this);
- lister / cmFileListGeneratorFixed(prefix) /
- cmFileListGeneratorCaseInsensitive("cmake");
- if (lister.Search()) {
- return true;
- }
+ auto searchFn = [this](const std::string& fullPath) -> bool {
+ return this->SearchDirectory(fullPath);
+ };
+
+ auto iCMakeGen = cmCaseInsensitiveDirectoryListGenerator{ "cmake"_s };
+ auto firstPkgDirGen =
+ cmProjectDirectoryListGenerator{ this->Names, this->SortOrder,
+ this->SortDirection };
+
+ // PREFIX/(cmake|CMake)/ (useful on windows or in build trees)
+ if (TryGeneratedPaths(searchFn, prefix, iCMakeGen)) {
+ return true;
}
- // PREFIX/(Foo|foo|FOO).*/
- {
- cmFindPackageFileList lister(this);
- lister / cmFileListGeneratorFixed(prefix) /
- cmFileListGeneratorProject(this->Names, this->SortOrder,
- this->SortDirection);
- if (lister.Search()) {
- return true;
- }
+ // PREFIX/(Foo|foo|FOO).*/
+ if (TryGeneratedPaths(searchFn, prefix, firstPkgDirGen)) {
+ return true;
}
- // PREFIX/(Foo|foo|FOO).*/(cmake|CMake)/
- {
- cmFindPackageFileList lister(this);
- lister / cmFileListGeneratorFixed(prefix) /
- cmFileListGeneratorProject(this->Names, this->SortOrder,
- this->SortDirection) /
- cmFileListGeneratorCaseInsensitive("cmake");
- if (lister.Search()) {
- return true;
- }
+ // PREFIX/(Foo|foo|FOO).*/(cmake|CMake)/
+ if (TryGeneratedPaths(searchFn, prefix, firstPkgDirGen, iCMakeGen)) {
+ return true;
+ }
+
+ auto secondPkgDirGen =
+ cmProjectDirectoryListGenerator{ this->Names, this->SortOrder,
+ this->SortDirection };
+
+ // PREFIX/(Foo|foo|FOO).*/(cmake|CMake)/(Foo|foo|FOO).*/
+ if (TryGeneratedPaths(searchFn, prefix, firstPkgDirGen, iCMakeGen,
+ secondPkgDirGen)) {
+ return true;
}
// Construct list of common install locations (lib and share).
- std::vector<std::string> common;
+ std::vector<cm::string_view> common;
+ std::string libArch;
if (!this->LibraryArchitecture.empty()) {
- common.push_back("lib/" + this->LibraryArchitecture);
+ libArch = "lib/" + this->LibraryArchitecture;
+ common.emplace_back(libArch);
}
if (this->UseLib32Paths) {
- common.emplace_back("lib32");
+ common.emplace_back("lib32"_s);
}
if (this->UseLib64Paths) {
- common.emplace_back("lib64");
+ common.emplace_back("lib64"_s);
}
if (this->UseLibx32Paths) {
- common.emplace_back("libx32");
+ common.emplace_back("libx32"_s);
}
- common.emplace_back("lib");
- common.emplace_back("share");
+ common.emplace_back("lib"_s);
+ common.emplace_back("share"_s);
- // PREFIX/(lib/ARCH|lib*|share)/cmake/(Foo|foo|FOO).*/
- {
- cmFindPackageFileList lister(this);
- lister / cmFileListGeneratorFixed(prefix) /
- cmFileListGeneratorEnumerate(common) /
- cmFileListGeneratorFixed("cmake") /
- cmFileListGeneratorProject(this->Names, this->SortOrder,
- this->SortDirection);
- if (lister.Search()) {
- return true;
- }
+ auto cmnGen = cmEnumPathSegmentsGenerator{ common };
+ auto cmakeGen = cmAppendPathSegmentGenerator{ "cmake"_s };
+
+ // PREFIX/(lib/ARCH|lib*|share)/cmake/(Foo|foo|FOO).*/
+ if (TryGeneratedPaths(searchFn, prefix, cmnGen, cmakeGen, firstPkgDirGen)) {
+ return true;
}
- // PREFIX/(lib/ARCH|lib*|share)/(Foo|foo|FOO).*/
- {
- cmFindPackageFileList lister(this);
- lister / cmFileListGeneratorFixed(prefix) /
- cmFileListGeneratorEnumerate(common) /
- cmFileListGeneratorProject(this->Names, this->SortOrder,
- this->SortDirection);
- if (lister.Search()) {
- return true;
- }
+ // PREFIX/(lib/ARCH|lib*|share)/(Foo|foo|FOO).*/
+ if (TryGeneratedPaths(searchFn, prefix, cmnGen, firstPkgDirGen)) {
+ return true;
}
- // PREFIX/(lib/ARCH|lib*|share)/(Foo|foo|FOO).*/(cmake|CMake)/
- {
- cmFindPackageFileList lister(this);
- lister / cmFileListGeneratorFixed(prefix) /
- cmFileListGeneratorEnumerate(common) /
- cmFileListGeneratorProject(this->Names, this->SortOrder,
- this->SortDirection) /
- cmFileListGeneratorCaseInsensitive("cmake");
- if (lister.Search()) {
- return true;
- }
+ // PREFIX/(lib/ARCH|lib*|share)/(Foo|foo|FOO).*/(cmake|CMake)/
+ if (TryGeneratedPaths(searchFn, prefix, cmnGen, firstPkgDirGen, iCMakeGen)) {
+ return true;
}
// PREFIX/(Foo|foo|FOO).*/(lib/ARCH|lib*|share)/cmake/(Foo|foo|FOO).*/
- {
- cmFindPackageFileList lister(this);
- lister / cmFileListGeneratorFixed(prefix) /
- cmFileListGeneratorProject(this->Names, this->SortOrder,
- this->SortDirection) /
- cmFileListGeneratorEnumerate(common) /
- cmFileListGeneratorFixed("cmake") /
- cmFileListGeneratorProject(this->Names, this->SortOrder,
- this->SortDirection);
- if (lister.Search()) {
- return true;
- }
+ if (TryGeneratedPaths(searchFn, prefix, firstPkgDirGen, cmnGen, cmakeGen,
+ secondPkgDirGen)) {
+ return true;
}
// PREFIX/(Foo|foo|FOO).*/(lib/ARCH|lib*|share)/(Foo|foo|FOO).*/
- {
- cmFindPackageFileList lister(this);
- lister / cmFileListGeneratorFixed(prefix) /
- cmFileListGeneratorProject(this->Names, this->SortOrder,
- this->SortDirection) /
- cmFileListGeneratorEnumerate(common) /
- cmFileListGeneratorProject(this->Names, this->SortOrder,
- this->SortDirection);
- if (lister.Search()) {
- return true;
- }
+ if (TryGeneratedPaths(searchFn, prefix, firstPkgDirGen, cmnGen,
+ secondPkgDirGen)) {
+ return true;
}
// PREFIX/(Foo|foo|FOO).*/(lib/ARCH|lib*|share)/(Foo|foo|FOO).*/(cmake|CMake)/
- {
- cmFindPackageFileList lister(this);
- lister / cmFileListGeneratorFixed(prefix) /
- cmFileListGeneratorProject(this->Names, this->SortOrder,
- this->SortDirection) /
- cmFileListGeneratorEnumerate(common) /
- cmFileListGeneratorProject(this->Names, this->SortOrder,
- this->SortDirection) /
- cmFileListGeneratorCaseInsensitive("cmake");
- if (lister.Search()) {
- return true;
- }
- }
-
- return false;
+ return TryGeneratedPaths(searchFn, prefix, firstPkgDirGen, cmnGen,
+ secondPkgDirGen, iCMakeGen);
}
bool cmFindPackageCommand::SearchFrameworkPrefix(std::string const& prefix_in)
@@ -2665,56 +2596,36 @@ bool cmFindPackageCommand::SearchFrameworkPrefix(std::string const& prefix_in)
// Strip the trailing slash because the path generator is about to
// add one.
- std::string prefix = prefix_in.substr(0, prefix_in.size() - 1);
+ std::string const prefix = prefix_in.substr(0, prefix_in.size() - 1);
+
+ auto searchFn = [this](const std::string& fullPath) -> bool {
+ return this->SearchDirectory(fullPath);
+ };
+
+ auto iCMakeGen = cmCaseInsensitiveDirectoryListGenerator{ "cmake"_s };
+ auto fwGen =
+ cmMacProjectDirectoryListGenerator{ this->Names, ".framework"_s };
+ auto rGen = cmAppendPathSegmentGenerator{ "Resources"_s };
+ auto vGen = cmAppendPathSegmentGenerator{ "Versions"_s };
+ auto grGen = cmFileListGeneratorGlob{ "/*/Resources"_s };
// <prefix>/Foo.framework/Resources/
- {
- cmFindPackageFileList lister(this);
- lister / cmFileListGeneratorFixed(prefix) /
- cmFileListGeneratorMacProject(this->Names, ".framework") /
- cmFileListGeneratorFixed("Resources");
- if (lister.Search()) {
- return true;
- }
+ if (TryGeneratedPaths(searchFn, prefix, fwGen, rGen)) {
+ return true;
}
+
// <prefix>/Foo.framework/Resources/CMake/
- {
- cmFindPackageFileList lister(this);
- lister / cmFileListGeneratorFixed(prefix) /
- cmFileListGeneratorMacProject(this->Names, ".framework") /
- cmFileListGeneratorFixed("Resources") /
- cmFileListGeneratorCaseInsensitive("cmake");
- if (lister.Search()) {
- return true;
- }
+ if (TryGeneratedPaths(searchFn, prefix, fwGen, rGen, iCMakeGen)) {
+ return true;
}
// <prefix>/Foo.framework/Versions/*/Resources/
- {
- cmFindPackageFileList lister(this);
- lister / cmFileListGeneratorFixed(prefix) /
- cmFileListGeneratorMacProject(this->Names, ".framework") /
- cmFileListGeneratorFixed("Versions") /
- cmFileListGeneratorGlob("*/Resources");
- if (lister.Search()) {
- return true;
- }
+ if (TryGeneratedPaths(searchFn, prefix, fwGen, vGen, grGen)) {
+ return true;
}
// <prefix>/Foo.framework/Versions/*/Resources/CMake/
- {
- cmFindPackageFileList lister(this);
- lister / cmFileListGeneratorFixed(prefix) /
- cmFileListGeneratorMacProject(this->Names, ".framework") /
- cmFileListGeneratorFixed("Versions") /
- cmFileListGeneratorGlob("*/Resources") /
- cmFileListGeneratorCaseInsensitive("cmake");
- if (lister.Search()) {
- return true;
- }
- }
-
- return false;
+ return TryGeneratedPaths(searchFn, prefix, fwGen, vGen, grGen, iCMakeGen);
}
bool cmFindPackageCommand::SearchAppBundlePrefix(std::string const& prefix_in)
@@ -2723,32 +2634,24 @@ bool cmFindPackageCommand::SearchAppBundlePrefix(std::string const& prefix_in)
// Strip the trailing slash because the path generator is about to
// add one.
- std::string prefix = prefix_in.substr(0, prefix_in.size() - 1);
+ std::string const prefix = prefix_in.substr(0, prefix_in.size() - 1);
+
+ auto searchFn = [this](const std::string& fullPath) -> bool {
+ return this->SearchDirectory(fullPath);
+ };
+
+ auto appGen = cmMacProjectDirectoryListGenerator{ this->Names, ".app"_s };
+ auto crGen = cmAppendPathSegmentGenerator{ "Contents/Resources"_s };
// <prefix>/Foo.app/Contents/Resources
- {
- cmFindPackageFileList lister(this);
- lister / cmFileListGeneratorFixed(prefix) /
- cmFileListGeneratorMacProject(this->Names, ".app") /
- cmFileListGeneratorFixed("Contents/Resources");
- if (lister.Search()) {
- return true;
- }
+ if (TryGeneratedPaths(searchFn, prefix, appGen, crGen)) {
+ return true;
}
// <prefix>/Foo.app/Contents/Resources/CMake
- {
- cmFindPackageFileList lister(this);
- lister / cmFileListGeneratorFixed(prefix) /
- cmFileListGeneratorMacProject(this->Names, ".app") /
- cmFileListGeneratorFixed("Contents/Resources") /
- cmFileListGeneratorCaseInsensitive("cmake");
- if (lister.Search()) {
- return true;
- }
- }
-
- return false;
+ return TryGeneratedPaths(
+ searchFn, prefix, appGen, crGen,
+ cmCaseInsensitiveDirectoryListGenerator{ "cmake"_s });
}
// TODO: Debug cmsys::Glob double slash problem.
diff --git a/Source/cmFindPackageCommand.h b/Source/cmFindPackageCommand.h
index 80fd8f8..28e00a1 100644
--- a/Source/cmFindPackageCommand.h
+++ b/Source/cmFindPackageCommand.h
@@ -153,8 +153,6 @@ private:
bool SearchFrameworkPrefix(std::string const& prefix_in);
bool SearchAppBundlePrefix(std::string const& prefix_in);
- friend class cmFindPackageFileList;
-
struct OriginalDef
{
bool exists;
diff --git a/Source/cmFindPathCommand.cxx b/Source/cmFindPathCommand.cxx
index 27074ff..74a69d8 100644
--- a/Source/cmFindPathCommand.cxx
+++ b/Source/cmFindPathCommand.cxx
@@ -88,7 +88,8 @@ std::string cmFindPathCommand::FindHeaderInFramework(
if (!frameWorkName.empty()) {
std::string fpath = cmStrCat(dir, frameWorkName, ".framework");
std::string intPath = cmStrCat(fpath, "/Headers/", fileName);
- if (cmSystemTools::FileExists(intPath)) {
+ if (cmSystemTools::FileExists(intPath) &&
+ this->Validate(this->IncludeFileInPath ? intPath : fpath)) {
debug.FoundAt(intPath);
if (this->IncludeFileInPath) {
return intPath;
@@ -124,7 +125,8 @@ std::string cmFindPathCommand::FindNormalHeader(cmFindBaseDebugState& debug)
for (std::string const& n : this->Names) {
for (std::string const& sp : this->SearchPaths) {
tryPath = cmStrCat(sp, n);
- if (cmSystemTools::FileExists(tryPath)) {
+ if (cmSystemTools::FileExists(tryPath) &&
+ this->Validate(this->IncludeFileInPath ? tryPath : sp)) {
debug.FoundAt(tryPath);
if (this->IncludeFileInPath) {
return tryPath;
diff --git a/Source/cmFindProgramCommand.cxx b/Source/cmFindProgramCommand.cxx
index a64e0e4..8a2a69e 100644
--- a/Source/cmFindProgramCommand.cxx
+++ b/Source/cmFindProgramCommand.cxx
@@ -27,6 +27,7 @@ struct cmFindProgramHelper
cmFindBase const* base)
: DebugSearches(std::move(debugName), base)
, Makefile(makefile)
+ , FindBase(base)
, PolicyCMP0109(makefile->GetPolicyStatus(cmPolicies::CMP0109))
{
#if defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__)
@@ -56,6 +57,7 @@ struct cmFindProgramHelper
// Debug state
cmFindBaseDebugState DebugSearches;
cmMakefile* Makefile;
+ cmFindBase const* FindBase;
cmPolicies::PolicyStatus PolicyCMP0109;
@@ -94,7 +96,7 @@ struct cmFindProgramHelper
this->TestNameExt = cmStrCat(name, ext);
this->TestPath = cmSystemTools::CollapseFullPath(
this->TestNameExt, path);
- bool exists = this->FileIsExecutable(this->TestPath);
+ bool exists = this->FileIsValid(this->TestPath);
exists ? this->DebugSearches.FoundAt(this->TestPath)
: this->DebugSearches.FailedAt(this->TestPath);
if (exists) {
@@ -104,12 +106,12 @@ struct cmFindProgramHelper
return false;
});
}
- bool FileIsExecutable(std::string const& file) const
+ bool FileIsValid(std::string const& file) const
{
-#ifdef _WIN32
if (!this->FileIsExecutableCMP0109(file)) {
return false;
}
+#ifdef _WIN32
// Pretend the Windows "python" app installer alias does not exist.
if (cmSystemTools::LowerCase(file).find("/windowsapps/python") !=
std::string::npos) {
@@ -119,10 +121,8 @@ struct cmFindProgramHelper
return false;
}
}
- return true;
-#else
- return this->FileIsExecutableCMP0109(file);
#endif
+ return this->FindBase->Validate(file);
}
bool FileIsExecutableCMP0109(std::string const& file) const
{
diff --git a/Source/cmFunctionBlocker.cxx b/Source/cmFunctionBlocker.cxx
index 40e692d..523482a 100644
--- a/Source/cmFunctionBlocker.cxx
+++ b/Source/cmFunctionBlocker.cxx
@@ -24,10 +24,11 @@ bool cmFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff,
auto self = mf.RemoveFunctionBlocker();
assert(self.get() == this);
- if (!this->ArgumentsMatch(lff, mf)) {
- cmListFileContext const& lfc = this->GetStartingContext();
- cmListFileContext closingContext =
- cmListFileContext::FromListFileFunction(lff, lfc.FilePath);
+ cmListFileContext const& lfc = this->GetStartingContext();
+ cmListFileContext closingContext =
+ cmListFileContext::FromListFileFunction(lff, lfc.FilePath);
+ if (this->EndCommandSupportsArguments() &&
+ !this->ArgumentsMatch(lff, mf)) {
std::ostringstream e;
/* clang-format off */
e << "A logical block opening on the line\n"
@@ -37,6 +38,15 @@ bool cmFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff,
<< "with mis-matching arguments.";
/* clang-format on */
mf.IssueMessage(MessageType::AUTHOR_WARNING, e.str());
+ } else if (!this->EndCommandSupportsArguments() &&
+ !lff.Arguments().empty()) {
+ std::ostringstream e;
+ /* clang-format off */
+ e << "A logical block closing on the line\n"
+ " " << closingContext << "\n"
+ "has unexpected arguments.";
+ /* clang-format on */
+ mf.IssueMessage(MessageType::AUTHOR_WARNING, e.str());
}
return this->Replay(std::move(this->Functions), status);
diff --git a/Source/cmFunctionBlocker.h b/Source/cmFunctionBlocker.h
index 38abeba..3e096f2 100644
--- a/Source/cmFunctionBlocker.h
+++ b/Source/cmFunctionBlocker.h
@@ -38,6 +38,8 @@ private:
virtual cm::string_view StartCommandName() const = 0;
virtual cm::string_view EndCommandName() const = 0;
+ virtual bool EndCommandSupportsArguments() const { return true; }
+
virtual bool ArgumentsMatch(cmListFileFunction const& lff,
cmMakefile& mf) const = 0;
diff --git a/Source/cmGeneratedFileStream.cxx b/Source/cmGeneratedFileStream.cxx
index b529b8f..6212bbd 100644
--- a/Source/cmGeneratedFileStream.cxx
+++ b/Source/cmGeneratedFileStream.cxx
@@ -124,10 +124,10 @@ cmGeneratedFileStreamBase::~cmGeneratedFileStreamBase()
void cmGeneratedFileStreamBase::Open(std::string const& name)
{
// Save the original name of the file.
- this->Name = name;
+ this->Name = cmSystemTools::CollapseFullPath(name);
// Create the name of the temporary file.
- this->TempName = name;
+ this->TempName = this->Name;
#if defined(__VMS)
this->TempName += "_";
#else
@@ -231,7 +231,7 @@ int cmGeneratedFileStreamBase::RenameFile(std::string const& oldname,
void cmGeneratedFileStream::SetName(const std::string& fname)
{
- this->Name = fname;
+ this->Name = cmSystemTools::CollapseFullPath(fname);
}
void cmGeneratedFileStream::SetTempExt(std::string const& ext)
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index 0c351ad..54c900f 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -808,11 +808,16 @@ void handleSystemIncludesDep(cmLocalGenerator* lg,
dagChecker, depTgt, language),
result);
}
- if (!depTgt->IsImported() || excludeImported) {
+ if (!depTgt->GetPropertyAsBool("SYSTEM")) {
return;
}
- if (depTgt->GetPropertyAsBool("IMPORTED_NO_SYSTEM")) {
- return;
+ if (depTgt->IsImported()) {
+ if (excludeImported) {
+ return;
+ }
+ if (depTgt->GetPropertyAsBool("IMPORTED_NO_SYSTEM")) {
+ return;
+ }
}
if (cmValue dirs = depTgt->GetProperty("INTERFACE_INCLUDE_DIRECTORIES")) {
@@ -912,11 +917,19 @@ bool cmGeneratorTarget::IsIPOEnabled(std::string const& lang,
return false;
}
- if (lang != "C" && lang != "CXX" && lang != "Fortran") {
+ if (lang != "C" && lang != "CXX" && lang != "CUDA" && lang != "Fortran") {
// We do not define IPO behavior for other languages.
return false;
}
+ if (lang == "CUDA") {
+ // CUDA IPO requires both CUDA_ARCHITECTURES and CUDA_SEPARABLE_COMPILATION
+ if (cmIsOff(this->GetSafeProperty("CUDA_ARCHITECTURES")) ||
+ cmIsOff(this->GetSafeProperty("CUDA_SEPARABLE_COMPILATION"))) {
+ return false;
+ }
+ }
+
cmPolicies::PolicyStatus cmp0069 = this->GetPolicyStatusCMP0069();
if (cmp0069 == cmPolicies::OLD || cmp0069 == cmPolicies::WARN) {
@@ -1702,13 +1715,14 @@ void addFileSetEntry(cmGeneratorTarget const* headTarget,
}
bool found = false;
for (auto const& sg : headTarget->Makefile->GetSourceGroups()) {
- if (sg.MatchesFiles(path)) {
+ if (sg.MatchChildrenFiles(path)) {
found = true;
break;
}
}
if (!found) {
- if (fileSet->GetType() == "HEADERS"_s) {
+ if (fileSet->GetType() == "HEADERS"_s ||
+ fileSet->GetType() == "CXX_MODULE_HEADER_UNITS"_s) {
headTarget->Makefile->GetOrCreateSourceGroup("Header Files")
->AddGroupFile(path);
}
@@ -1729,6 +1743,20 @@ void AddFileSetEntries(cmGeneratorTarget const* headTarget,
addFileSetEntry(headTarget, config, dagChecker, headerSet, entries);
}
}
+ for (auto const& entry : headTarget->Target->GetCxxModuleSetsEntries()) {
+ for (auto const& name : cmExpandedList(entry.Value)) {
+ auto const* cxxModuleSet = headTarget->Target->GetFileSet(name);
+ addFileSetEntry(headTarget, config, dagChecker, cxxModuleSet, entries);
+ }
+ }
+ for (auto const& entry :
+ headTarget->Target->GetCxxModuleHeaderSetsEntries()) {
+ for (auto const& name : cmExpandedList(entry.Value)) {
+ auto const* cxxModuleHeaderSet = headTarget->Target->GetFileSet(name);
+ addFileSetEntry(headTarget, config, dagChecker, cxxModuleHeaderSet,
+ entries);
+ }
+ }
}
bool processSources(cmGeneratorTarget const* tgt,
@@ -3409,7 +3437,9 @@ void cmGeneratorTarget::AddExplicitLanguageFlags(std::string& flags,
"EXPLICIT_LANGUAGE");
}
-void cmGeneratorTarget::AddCUDAArchitectureFlags(std::string& flags) const
+void cmGeneratorTarget::AddCUDAArchitectureFlags(cmBuildStep compileOrLink,
+ const std::string& config,
+ std::string& flags) const
{
std::string property = this->GetSafeProperty("CUDA_ARCHITECTURES");
@@ -3441,6 +3471,7 @@ void cmGeneratorTarget::AddCUDAArchitectureFlags(std::string& flags) const
std::string const& compiler =
this->Makefile->GetSafeDefinition("CMAKE_CUDA_COMPILER_ID");
+ const bool ipoEnabled = this->IsIPOEnabled("CUDA", config);
// Check for special modes: `all`, `all-major`.
if (property == "all" || property == "all-major") {
@@ -3520,6 +3551,13 @@ void cmGeneratorTarget::AddCUDAArchitectureFlags(std::string& flags) const
}
if (compiler == "NVIDIA") {
+ if (ipoEnabled && compileOrLink == cmBuildStep::Link) {
+ if (cmValue cudaIPOFlags =
+ this->Makefile->GetDefinition("CMAKE_CUDA_LINK_OPTIONS_IPO")) {
+ flags += cudaIPOFlags;
+ }
+ }
+
for (CudaArchitecture& architecture : architectures) {
flags +=
" --generate-code=arch=compute_" + architecture.name + ",code=[";
@@ -3532,7 +3570,13 @@ void cmGeneratorTarget::AddCUDAArchitectureFlags(std::string& flags) const
}
}
- if (architecture.real) {
+ if (ipoEnabled) {
+ if (compileOrLink == cmBuildStep::Compile) {
+ flags += "lto_" + architecture.name;
+ } else if (compileOrLink == cmBuildStep::Link) {
+ flags += "sm_" + architecture.name;
+ }
+ } else if (architecture.real) {
flags += "sm_" + architecture.name;
}
@@ -8724,3 +8768,76 @@ std::string cmGeneratorTarget::GenerateHeaderSetVerificationFile(
return filename;
}
+
+bool cmGeneratorTarget::HaveCxx20ModuleSources() const
+{
+ auto const& fs_names = this->Target->GetAllFileSetNames();
+ return std::any_of(fs_names.begin(), fs_names.end(),
+ [this](std::string const& name) -> bool {
+ auto const* file_set = this->Target->GetFileSet(name);
+ if (!file_set) {
+ this->Makefile->IssueMessage(
+ MessageType::INTERNAL_ERROR,
+ cmStrCat("Target \"", this->Target->GetName(),
+ "\" is tracked to have file set \"", name,
+ "\", but it was not found."));
+ return false;
+ }
+
+ auto const& fs_type = file_set->GetType();
+ return fs_type == "CXX_MODULES"_s ||
+ fs_type == "CXX_MODULE_HEADER_UNITS"_s;
+ });
+}
+
+cmGeneratorTarget::Cxx20SupportLevel cmGeneratorTarget::HaveCxxModuleSupport(
+ std::string const& config) const
+{
+ auto const* state = this->Makefile->GetState();
+ if (!state->GetLanguageEnabled("CXX")) {
+ return Cxx20SupportLevel::MissingCxx;
+ }
+ cmStandardLevelResolver standardResolver(this->Makefile);
+ if (!standardResolver.HaveStandardAvailable(this, "CXX", config,
+ "cxx_std_20")) {
+ return Cxx20SupportLevel::NoCxx20;
+ }
+ if (!this->Makefile->IsOn("CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP")) {
+ return Cxx20SupportLevel::MissingExperimentalFlag;
+ }
+ return Cxx20SupportLevel::Supported;
+}
+
+void cmGeneratorTarget::CheckCxxModuleStatus(std::string const& config) const
+{
+ // Check for `CXX_MODULE*` file sets and a lack of support.
+ if (this->HaveCxx20ModuleSources()) {
+ switch (this->HaveCxxModuleSupport(config)) {
+ case cmGeneratorTarget::Cxx20SupportLevel::MissingCxx:
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat("The \"", this->GetName(),
+ "\" target has C++ module sources but the \"CXX\" language "
+ "has not been enabled"));
+ break;
+ case cmGeneratorTarget::Cxx20SupportLevel::MissingExperimentalFlag:
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat("The \"", this->GetName(),
+ "\" target has C++ module sources but its experimental "
+ "support has not been requested"));
+ break;
+ case cmGeneratorTarget::Cxx20SupportLevel::NoCxx20:
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat(
+ "The \"", this->GetName(),
+ "\" target has C++ module sources but is not using at least "
+ "\"cxx_std_20\""));
+ break;
+ case cmGeneratorTarget::Cxx20SupportLevel::Supported:
+ // All is well.
+ break;
+ }
+ }
+}
diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h
index 6bce7d2..25e6a81 100644
--- a/Source/cmGeneratorTarget.h
+++ b/Source/cmGeneratorTarget.h
@@ -23,6 +23,7 @@
#include "cmStateTypes.h"
#include "cmValue.h"
+enum class cmBuildStep;
class cmComputeLinkInformation;
class cmCustomCommand;
class cmGlobalGenerator;
@@ -471,7 +472,9 @@ public:
void AddExplicitLanguageFlags(std::string& flags,
cmSourceFile const& sf) const;
- void AddCUDAArchitectureFlags(std::string& flags) const;
+ void AddCUDAArchitectureFlags(cmBuildStep compileOrLink,
+ const std::string& config,
+ std::string& flags) const;
void AddCUDAToolkitFlags(std::string& flags) const;
void AddHIPArchitectureFlags(std::string& flags) const;
@@ -1196,4 +1199,34 @@ public:
bool operator()(cmGeneratorTarget const* t1,
cmGeneratorTarget const* t2) const;
};
+
+ // C++20 module support queries.
+
+ /**
+ * Query whether the target expects C++20 module support.
+ *
+ * This will inspect the target itself to see if C++20 module
+ * support is expected to work based on its sources.
+ */
+ bool HaveCxx20ModuleSources() const;
+
+ enum class Cxx20SupportLevel
+ {
+ // C++ is not available.
+ MissingCxx,
+ // The experimental feature is not available.
+ MissingExperimentalFlag,
+ // The target does not require at least C++20.
+ NoCxx20,
+ // C++20 modules are available and working.
+ Supported,
+ };
+ /**
+ * Query whether the target has C++20 module support available (regardless of
+ * whether it is required or not).
+ */
+ Cxx20SupportLevel HaveCxxModuleSupport(std::string const& config) const;
+
+ // Check C++ module status for the target.
+ void CheckCxxModuleStatus(std::string const& config) const;
};
diff --git a/Source/cmGhsMultiTargetGenerator.cxx b/Source/cmGhsMultiTargetGenerator.cxx
index bf019c3..138d3f1 100644
--- a/Source/cmGhsMultiTargetGenerator.cxx
+++ b/Source/cmGhsMultiTargetGenerator.cxx
@@ -183,8 +183,8 @@ void cmGhsMultiTargetGenerator::SetCompilerFlags(std::string const& config,
auto i = this->FlagsByLanguage.find(language);
if (i == this->FlagsByLanguage.end()) {
std::string flags;
- this->LocalGenerator->AddLanguageFlags(flags, this->GeneratorTarget,
- language, config);
+ this->LocalGenerator->AddLanguageFlags(
+ flags, this->GeneratorTarget, cmBuildStep::Compile, language, config);
this->LocalGenerator->AddCMP0018Flags(flags, this->GeneratorTarget,
language, config);
this->LocalGenerator->AddVisibilityPresetFlags(
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
index 4feae6d..07ad1e8 100644
--- a/Source/cmGlobalGenerator.cxx
+++ b/Source/cmGlobalGenerator.cxx
@@ -1854,6 +1854,15 @@ void cmGlobalGenerator::FinalizeTargetCompileInfo()
cmExpandedList(standardIncludesStr);
standardIncludesSet.insert(standardIncludesVec.begin(),
standardIncludesVec.end());
+ if (li == "CUDA") {
+ std::string const& cudaSystemIncludeVar =
+ mf->GetSafeDefinition("CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES");
+ std::vector<std::string> cudaToolkitIncludeVec =
+ cmExpandedList(cudaSystemIncludeVar);
+ standardIncludesSet.insert(cudaToolkitIncludeVec.begin(),
+ cudaToolkitIncludeVec.end());
+ mf->AddIncludeDirectories(cudaToolkitIncludeVec);
+ }
}
mf->AddSystemIncludeDirectories(standardIncludesSet);
}
diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx
index acaed36..c326ca6 100644
--- a/Source/cmGlobalNinjaGenerator.cxx
+++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -3,8 +3,10 @@
#include "cmGlobalNinjaGenerator.h"
#include <algorithm>
+#include <cassert>
#include <cctype>
#include <cstdio>
+#include <functional>
#include <sstream>
#include <utility>
@@ -14,6 +16,7 @@
#include <cm/string_view>
#include <cmext/algorithm>
#include <cmext/memory>
+#include <cmext/string_view>
#include <cm3p/json/reader.h>
#include <cm3p/json/value.h>
@@ -21,7 +24,9 @@
#include "cmsys/FStream.hxx"
+#include "cmCxxModuleMapper.h"
#include "cmDocumentationEntry.h"
+#include "cmFileSet.h"
#include "cmFortranParser.h"
#include "cmGeneratedFileStream.h"
#include "cmGeneratorExpressionEvaluationFile.h"
@@ -2480,13 +2485,53 @@ cm::optional<cmSourceInfo> cmcmd_cmake_ninja_depends_fortran(
}
}
+struct CxxModuleFileSet
+{
+ std::string Name;
+ std::string RelativeDirectory;
+ std::string SourcePath;
+ std::string Type;
+ cmFileSetVisibility Visibility;
+ cm::optional<std::string> Destination;
+};
+
+struct CxxModuleBmiInstall
+{
+ std::string Component;
+ std::string Destination;
+ bool ExcludeFromAll;
+ bool Optional;
+ std::string Permissions;
+ std::string MessageLevel;
+ std::string ScriptLocation;
+};
+
+struct CxxModuleExport
+{
+ std::string Name;
+ std::string Destination;
+ std::string Prefix;
+ std::string CxxModuleInfoDir;
+ std::string Namespace;
+ bool Install;
+};
+
+struct cmGlobalNinjaGenerator::CxxModuleExportInfo
+{
+ std::map<std::string, CxxModuleFileSet> ObjectToFileSet;
+ cm::optional<CxxModuleBmiInstall> BmiInstallation;
+ std::vector<CxxModuleExport> Exports;
+ std::string Config;
+};
+
bool cmGlobalNinjaGenerator::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)
+ std::string const& arg_lang, std::string const& arg_modmapfmt,
+ CxxModuleExportInfo const& export_info)
{
// Setup path conversions.
{
@@ -2511,13 +2556,15 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile(
objects.push_back(std::move(info));
}
+ CxxModuleUsage usages;
+
// Map from module name to module file path, if known.
std::map<std::string, std::string> mod_files;
// Populate the module map with those provided by linked targets first.
for (std::string const& linked_target_dir : linked_target_dirs) {
std::string const ltmn =
- cmStrCat(linked_target_dir, "/", arg_lang, "Modules.json");
+ cmStrCat(linked_target_dir, '/', arg_lang, "Modules.json");
Json::Value ltm;
cmsys::ifstream ltmf(ltmn.c_str(), std::ios::in | std::ios::binary);
Json::Reader reader;
@@ -2528,21 +2575,71 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile(
return false;
}
if (ltm.isObject()) {
- for (Json::Value::iterator i = ltm.begin(); i != ltm.end(); ++i) {
- mod_files[i.key().asString()] = i->asString();
+ Json::Value const& target_modules = ltm["modules"];
+ if (target_modules.isObject()) {
+ for (auto i = target_modules.begin(); i != target_modules.end(); ++i) {
+ mod_files[i.key().asString()] = i->asString();
+ }
+ }
+ Json::Value const& target_modules_references = ltm["references"];
+ if (target_modules_references.isObject()) {
+ for (auto i = target_modules_references.begin();
+ i != target_modules_references.end(); ++i) {
+ if (i->isObject()) {
+ Json::Value const& reference_path = (*i)["path"];
+ CxxModuleReference module_reference;
+ if (reference_path.isString()) {
+ module_reference.Path = reference_path.asString();
+ }
+ Json::Value const& reference_method = (*i)["lookup-method"];
+ if (reference_method.isString()) {
+ std::string reference = reference_method.asString();
+ if (reference == "by-name") {
+ module_reference.Method = LookupMethod::ByName;
+ } else if (reference == "include-angle") {
+ module_reference.Method = LookupMethod::IncludeAngle;
+ } else if (reference == "include-quote") {
+ module_reference.Method = LookupMethod::IncludeQuote;
+ }
+ }
+ usages.Reference[i.key().asString()] = module_reference;
+ }
+ }
+ }
+ Json::Value const& target_modules_usage = ltm["usages"];
+ if (target_modules_usage.isObject()) {
+ for (auto i = target_modules_usage.begin();
+ i != target_modules_usage.end(); ++i) {
+ if (i->isArray()) {
+ for (auto j = i->begin(); j != i->end(); ++j) {
+ usages.Usage[i.key().asString()].insert(j->asString());
+ }
+ }
+ }
}
}
}
- const char* module_ext = "";
- if (arg_modmapfmt == "gcc") {
- module_ext = ".gcm";
+ cm::optional<CxxModuleMapFormat> modmap_fmt;
+ if (arg_modmapfmt.empty()) {
+ // nothing to do.
+ } else if (arg_modmapfmt == "gcc") {
+ modmap_fmt = CxxModuleMapFormat::Gcc;
+ } else if (arg_modmapfmt == "msvc") {
+ modmap_fmt = CxxModuleMapFormat::Msvc;
+ } else {
+ cmSystemTools::Error(
+ cmStrCat("-E cmake_ninja_dyndep does not understand the ", arg_modmapfmt,
+ " module map format"));
+ return false;
}
+ auto module_ext = CxxModuleMapExtension(modmap_fmt);
+
// Extend the module map with those provided by this target.
// We do this after loading the modules provided by linked targets
// in case we have one of the same name that must be preferred.
- Json::Value tm = Json::objectValue;
+ Json::Value target_modules = Json::objectValue;
for (cmScanDepInfo const& object : objects) {
for (auto const& p : object.Provides) {
std::string mod;
@@ -2555,12 +2652,13 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile(
}
} else {
// Assume the module file path matches the logical module name.
- std::string safe_logical_name = p.LogicalName;
+ std::string safe_logical_name =
+ p.LogicalName; // TODO: needs fixing for header units
cmSystemTools::ReplaceString(safe_logical_name, ":", "-");
mod = cmStrCat(module_dir, safe_logical_name, module_ext);
}
mod_files[p.LogicalName] = mod;
- tm[p.LogicalName] = mod;
+ target_modules[p.LogicalName] = mod;
}
}
@@ -2568,6 +2666,32 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile(
ddf << "ninja_dyndep_version = 1.0\n";
{
+ CxxModuleLocations locs;
+ locs.RootDirectory = ".";
+ locs.PathForGenerator = [this](std::string const& path) -> std::string {
+ return this->ConvertToNinjaPath(path);
+ };
+ locs.BmiLocationForModule =
+ [&mod_files](std::string const& logical) -> cm::optional<std::string> {
+ auto m = mod_files.find(logical);
+ if (m != mod_files.end()) {
+ return m->second;
+ }
+ return {};
+ };
+
+ // Insert information about the current target's modules.
+ if (modmap_fmt) {
+ auto cycle_modules = CxxModuleUsageSeed(locs, objects, usages);
+ if (!cycle_modules.empty()) {
+ cmSystemTools::Error(
+ cmStrCat("Circular dependency detected in the C++ module import "
+ "graph. See modules named: \"",
+ cmJoin(cycle_modules, R"(", ")"_s), '"'));
+ return false;
+ }
+ }
+
cmNinjaBuild build("dyndep");
build.Outputs.emplace_back("");
for (cmScanDepInfo const& object : objects) {
@@ -2589,60 +2713,332 @@ 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;
- }
+ if (modmap_fmt) {
+ auto mm = CxxModuleMapContent(*modmap_fmt, locs, object, usages);
// 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();
+ mmf << mm;
}
this->WriteBuild(ddf, build);
}
}
+ Json::Value target_module_info = Json::objectValue;
+ target_module_info["modules"] = target_modules;
+
+ auto& target_usages = target_module_info["usages"] = Json::objectValue;
+ for (auto const& u : usages.Usage) {
+ auto& mod_usage = target_usages[u.first] = Json::arrayValue;
+ for (auto const& v : u.second) {
+ mod_usage.append(v);
+ }
+ }
+
+ auto name_for_method = [](LookupMethod method) -> cm::static_string_view {
+ switch (method) {
+ case LookupMethod::ByName:
+ return "by-name"_s;
+ case LookupMethod::IncludeAngle:
+ return "include-angle"_s;
+ case LookupMethod::IncludeQuote:
+ return "include-quote"_s;
+ }
+ assert(false && "unsupported lookup method");
+ return ""_s;
+ };
+
+ auto& target_references = target_module_info["references"] =
+ Json::objectValue;
+ for (auto const& r : usages.Reference) {
+ auto& mod_ref = target_references[r.first] = Json::objectValue;
+ mod_ref["path"] = r.second.Path;
+ mod_ref["lookup-method"] = std::string(name_for_method(r.second.Method));
+ }
+
// Store the map of modules provided by this target in a file for
// use by dependents that reference this target in linked-target-dirs.
std::string const target_mods_file = cmStrCat(
cmSystemTools::GetFilenamePath(arg_dd), '/', arg_lang, "Modules.json");
cmGeneratedFileStream tmf(target_mods_file);
- tmf << tm;
+ tmf << target_module_info;
+
+ bool result = true;
+
+ // Fortran doesn't support any of the file-set or BMI installation considered
+ // below.
+ if (arg_lang != "Fortran"_s) {
+ // Prepare the export information blocks.
+ std::string const config_upper =
+ cmSystemTools::UpperCase(export_info.Config);
+ std::vector<std::pair<std::unique_ptr<cmGeneratedFileStream>,
+ CxxModuleExport const*>>
+ exports;
+ for (auto const& exp : export_info.Exports) {
+ std::unique_ptr<cmGeneratedFileStream> properties;
+
+ std::string const export_dir =
+ cmStrCat(exp.Prefix, '/', exp.CxxModuleInfoDir, '/');
+ std::string const property_file_path = cmStrCat(
+ export_dir, "target-", exp.Name, '-', export_info.Config, ".cmake");
+ properties = cm::make_unique<cmGeneratedFileStream>(property_file_path);
+
+ // Set up the preamble.
+ *properties << "set_property(TARGET \"" << exp.Namespace << exp.Name
+ << "\"\n"
+ << " PROPERTY IMPORTED_CXX_MODULES_" << config_upper
+ << '\n';
+
+ exports.emplace_back(std::move(properties), &exp);
+ }
+
+ std::unique_ptr<cmGeneratedFileStream> bmi_install_script;
+ if (export_info.BmiInstallation) {
+ bmi_install_script = cm::make_unique<cmGeneratedFileStream>(
+ export_info.BmiInstallation->ScriptLocation);
+ }
+
+ auto cmEscape = [](cm::string_view str) {
+ return cmOutputConverter::EscapeForCMake(
+ str, cmOutputConverter::WrapQuotes::NoWrap);
+ };
+ auto install_destination =
+ [&cmEscape](std::string const& dest) -> std::pair<bool, std::string> {
+ if (cmSystemTools::FileIsFullPath(dest)) {
+ return std::make_pair(true, cmEscape(dest));
+ }
+ return std::make_pair(false,
+ cmStrCat("${_IMPORT_PREFIX}/", cmEscape(dest)));
+ };
- return true;
+ // public/private requirement tracking.
+ std::set<std::string> private_modules;
+ std::map<std::string, std::set<std::string>> public_source_requires;
+
+ for (cmScanDepInfo const& object : objects) {
+ // Convert to forward slashes.
+ auto output_path = object.PrimaryOutput;
+# ifdef _WIN32
+ cmSystemTools::ConvertToUnixSlashes(output_path);
+# endif
+ // Find the fileset for this object.
+ auto fileset_info_itr = export_info.ObjectToFileSet.find(output_path);
+ bool const has_provides = !object.Provides.empty();
+ if (fileset_info_itr == export_info.ObjectToFileSet.end()) {
+ // If it provides anything, it should have a `CXX_MODULES` or
+ // `CXX_MODULE_INTERNAL_PARTITIONS` type and be present.
+ if (has_provides) {
+ // Take the first module provided to provide context.
+ auto const& provides = object.Provides[0];
+ char const* ok_types = "`CXX_MODULES`";
+ if (provides.LogicalName.find(':') != std::string::npos) {
+ ok_types = "`CXX_MODULES` (or `CXX_MODULE_INTERNAL_PARTITIONS` if "
+ "it is not `export`ed)";
+ }
+ cmSystemTools::Error(
+ cmStrCat("Output ", object.PrimaryOutput, " provides the `",
+ provides.LogicalName,
+ "` module but it is not found in a `FILE_SET` of type ",
+ ok_types));
+ result = false;
+ }
+
+ // This object file does not provide anything, so nothing more needs to
+ // be done.
+ continue;
+ }
+
+ auto const& file_set = fileset_info_itr->second;
+
+ // Verify the fileset type for the object.
+ if (file_set.Type == "CXX_MODULES"_s) {
+ if (!has_provides) {
+ cmSystemTools::Error(cmStrCat(
+ "Output ", object.PrimaryOutput,
+ " is of type `CXX_MODULES` but does not provide a module"));
+ result = false;
+ continue;
+ }
+ } else if (file_set.Type == "CXX_MODULE_INTERNAL_PARTITIONS"_s) {
+ if (!has_provides) {
+ cmSystemTools::Error(cmStrCat(
+ "Source ", file_set.SourcePath,
+ " is of type `CXX_MODULE_INTERNAL_PARTITIONS` but does not "
+ "provide a module"));
+ result = false;
+ continue;
+ }
+ auto const& provides = object.Provides[0];
+ if (provides.LogicalName.find(':') == std::string::npos) {
+ cmSystemTools::Error(cmStrCat(
+ "Source ", file_set.SourcePath,
+ " is of type `CXX_MODULE_INTERNAL_PARTITIONS` but does not "
+ "provide a module partition"));
+ result = false;
+ continue;
+ }
+ } else if (file_set.Type == "CXX_MODULE_HEADERS"_s) {
+ // TODO.
+ } else {
+ if (has_provides) {
+ auto const& provides = object.Provides[0];
+ char const* ok_types = "`CXX_MODULES`";
+ if (provides.LogicalName.find(':') != std::string::npos) {
+ ok_types = "`CXX_MODULES` (or `CXX_MODULE_INTERNAL_PARTITIONS` if "
+ "it is not `export`ed)";
+ }
+ cmSystemTools::Error(cmStrCat(
+ "Source ", file_set.SourcePath, " provides the `",
+ provides.LogicalName, "` C++ module but is of type `",
+ file_set.Type, "` module but must be of type ", ok_types));
+ result = false;
+ }
+
+ // Not a C++ module; ignore.
+ continue;
+ }
+
+ if (!cmFileSetVisibilityIsForInterface(file_set.Visibility)) {
+ // Nothing needs to be conveyed about non-`PUBLIC` modules.
+ for (auto const& p : object.Provides) {
+ private_modules.insert(p.LogicalName);
+ }
+ continue;
+ }
+
+ // The module is public. Record what it directly requires.
+ {
+ auto& reqs = public_source_requires[file_set.SourcePath];
+ for (auto const& r : object.Requires) {
+ reqs.insert(r.LogicalName);
+ }
+ }
+
+ // Write out properties and install rules for any exports.
+ for (auto const& p : object.Provides) {
+ bool bmi_dest_is_abs = false;
+ std::string bmi_destination;
+ if (export_info.BmiInstallation) {
+ auto dest =
+ install_destination(export_info.BmiInstallation->Destination);
+ bmi_dest_is_abs = dest.first;
+ bmi_destination = cmStrCat(dest.second, '/');
+ }
+
+ std::string install_bmi_path;
+ std::string build_bmi_path;
+ auto m = mod_files.find(p.LogicalName);
+ if (m != mod_files.end()) {
+ install_bmi_path =
+ cmStrCat(bmi_destination,
+ cmEscape(cmSystemTools::GetFilenameName(m->second)));
+ build_bmi_path = cmEscape(m->second);
+ }
+
+ for (auto const& exp : exports) {
+ std::string iface_source;
+ if (exp.second->Install && file_set.Destination) {
+ auto dest = install_destination(*file_set.Destination);
+ iface_source = cmStrCat(
+ dest.second, '/', cmEscape(file_set.RelativeDirectory),
+ cmEscape(cmSystemTools::GetFilenameName(file_set.SourcePath)));
+ } else {
+ iface_source = cmEscape(file_set.SourcePath);
+ }
+
+ std::string bmi_path;
+ if (exp.second->Install && export_info.BmiInstallation) {
+ bmi_path = install_bmi_path;
+ } else if (!exp.second->Install) {
+ bmi_path = build_bmi_path;
+ }
+
+ if (iface_source.empty()) {
+ // No destination for the C++ module source; ignore this property
+ // value.
+ continue;
+ }
+
+ *exp.first << " \"" << cmEscape(p.LogicalName) << '='
+ << iface_source;
+ if (!bmi_path.empty()) {
+ *exp.first << ',' << bmi_path;
+ }
+ *exp.first << "\"\n";
+ }
+
+ if (bmi_install_script) {
+ auto const& bmi_install = *export_info.BmiInstallation;
+
+ *bmi_install_script << "if (CMAKE_INSTALL_COMPONENT STREQUAL \""
+ << cmEscape(bmi_install.Component) << '\"';
+ if (!bmi_install.ExcludeFromAll) {
+ *bmi_install_script << " OR NOT CMAKE_INSTALL_COMPONENT";
+ }
+ *bmi_install_script << ")\n";
+ *bmi_install_script << " file(INSTALL\n"
+ " DESTINATION \"";
+ if (!bmi_dest_is_abs) {
+ *bmi_install_script << "${CMAKE_INSTALL_PREFIX}/";
+ }
+ *bmi_install_script << cmEscape(bmi_install.Destination)
+ << "\"\n"
+ " TYPE FILE\n";
+ if (bmi_install.Optional) {
+ *bmi_install_script << " OPTIONAL\n";
+ }
+ if (!bmi_install.MessageLevel.empty()) {
+ *bmi_install_script << " " << bmi_install.MessageLevel << "\n";
+ }
+ if (!bmi_install.Permissions.empty()) {
+ *bmi_install_script << " PERMISSIONS" << bmi_install.Permissions
+ << "\n";
+ }
+ *bmi_install_script << " FILES \"" << m->second << "\")\n";
+ if (bmi_dest_is_abs) {
+ *bmi_install_script
+ << " list(APPEND CMAKE_ABSOLUTE_DESTINATION_FILES\n"
+ " \""
+ << cmEscape(cmSystemTools::GetFilenameName(m->second))
+ << "\")\n"
+ " if (CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION)\n"
+ " message(WARNING\n"
+ " \"ABSOLUTE path INSTALL DESTINATION : "
+ "${CMAKE_ABSOLUTE_DESTINATION_FILES}\")\n"
+ " endif ()\n"
+ " if (CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION)\n"
+ " message(FATAL_ERROR\n"
+ " \"ABSOLUTE path INSTALL DESTINATION forbidden (by "
+ "caller): ${CMAKE_ABSOLUTE_DESTINATION_FILES}\")\n"
+ " endif ()\n";
+ }
+ *bmi_install_script << "endif ()\n";
+ }
+ }
+ }
+
+ // Add trailing parenthesis for the `set_property` call.
+ for (auto const& exp : exports) {
+ *exp.first << ")\n";
+ }
+
+ // Check that public sources only require public modules.
+ for (auto const& pub_reqs : public_source_requires) {
+ for (auto const& req : pub_reqs.second) {
+ if (private_modules.count(req)) {
+ cmSystemTools::Error(cmStrCat(
+ "Public C++ module source `", pub_reqs.first, "` requires the `",
+ req, "` C++ module which is provided by a private source"));
+ result = false;
+ }
+ }
+ }
+ }
+
+ return result;
}
int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg,
@@ -2716,6 +3112,59 @@ int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg,
}
}
+ cmGlobalNinjaGenerator::CxxModuleExportInfo export_info;
+ export_info.Config = tdi["config"].asString();
+ if (export_info.Config.empty()) {
+ export_info.Config = "noconfig";
+ }
+ Json::Value const& tdi_exports = tdi["exports"];
+ if (tdi_exports.isArray()) {
+ for (auto const& tdi_export : tdi_exports) {
+ CxxModuleExport exp;
+ exp.Install = tdi_export["install"].asBool();
+ exp.Name = tdi_export["export-name"].asString();
+ exp.Destination = tdi_export["destination"].asString();
+ exp.Prefix = tdi_export["export-prefix"].asString();
+ exp.CxxModuleInfoDir = tdi_export["cxx-module-info-dir"].asString();
+ exp.Namespace = tdi_export["namespace"].asString();
+
+ export_info.Exports.push_back(exp);
+ }
+ }
+ auto const& bmi_installation = tdi["bmi-installation"];
+ if (bmi_installation.isObject()) {
+ CxxModuleBmiInstall bmi_install;
+
+ bmi_install.Component = bmi_installation["component"].asString();
+ bmi_install.Destination = bmi_installation["destination"].asString();
+ bmi_install.ExcludeFromAll = bmi_installation["exclude-from-all"].asBool();
+ bmi_install.Optional = bmi_installation["optional"].asBool();
+ bmi_install.Permissions = bmi_installation["permissions"].asString();
+ bmi_install.MessageLevel = bmi_installation["message-level"].asString();
+ bmi_install.ScriptLocation =
+ bmi_installation["script-location"].asString();
+
+ export_info.BmiInstallation = bmi_install;
+ }
+ Json::Value const& tdi_cxx_modules = tdi["cxx-modules"];
+ if (tdi_cxx_modules.isObject()) {
+ for (auto i = tdi_cxx_modules.begin(); i != tdi_cxx_modules.end(); ++i) {
+ CxxModuleFileSet& fsi = export_info.ObjectToFileSet[i.key().asString()];
+ auto const& tdi_cxx_module_info = *i;
+ fsi.Name = tdi_cxx_module_info["name"].asString();
+ fsi.RelativeDirectory =
+ tdi_cxx_module_info["relative-directory"].asString();
+ fsi.SourcePath = tdi_cxx_module_info["source"].asString();
+ fsi.Type = tdi_cxx_module_info["type"].asString();
+ fsi.Visibility = cmFileSetVisibilityFromName(
+ tdi_cxx_module_info["visibility"].asString(), nullptr);
+ auto const& tdi_fs_dest = tdi_cxx_module_info["destination"];
+ if (tdi_fs_dest.isString()) {
+ fsi.Destination = tdi_fs_dest.asString();
+ }
+ }
+ }
+
cmake cm(cmake::RoleInternal, cmState::Unknown);
cm.SetHomeDirectory(dir_top_src);
cm.SetHomeOutputDirectory(dir_top_bld);
@@ -2723,7 +3172,8 @@ 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, arg_modmapfmt)) {
+ module_dir, linked_target_dirs, arg_lang, arg_modmapfmt,
+ export_info)) {
return 1;
}
return 0;
diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h
index aa2df4d..dc4f444 100644
--- a/Source/cmGlobalNinjaGenerator.h
+++ b/Source/cmGlobalNinjaGenerator.h
@@ -417,13 +417,15 @@ public:
bool HasOutputPathPrefix() const { return !this->OutputPathPrefix.empty(); }
void StripNinjaOutputPathPrefixAsSuffix(std::string& path);
+ struct CxxModuleExportInfo;
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);
+ std::string const& arg_lang, std::string const& arg_modmapfmt,
+ CxxModuleExportInfo const& export_info);
virtual std::string BuildAlias(const std::string& alias,
const std::string& /*config*/) const
diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx
index f7f7317..e53ae8e 100644
--- a/Source/cmGlobalVisualStudio7Generator.cxx
+++ b/Source/cmGlobalVisualStudio7Generator.cxx
@@ -395,12 +395,27 @@ void cmGlobalVisualStudio7Generator::WriteTargetsToSolution(
{
VisualStudioFolders.clear();
+ std::vector<std::string> configs =
+ root->GetMakefile()->GetGeneratorConfigs(cmMakefile::ExcludeEmptyConfig);
+
for (cmGeneratorTarget const* target : projectTargets) {
if (!this->IsInSolution(target)) {
continue;
}
bool written = false;
+ for (auto const& c : configs) {
+ target->CheckCxxModuleStatus(c);
+ }
+
+ if (target->HaveCxx20ModuleSources() && !this->SupportsCxxModuleDyndep()) {
+ root->GetMakefile()->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat("The \"", target->GetName(),
+ "\" target contains C++ module sources which are not "
+ "supported by the generator"));
+ }
+
// handle external vc project files
cmValue expath = target->GetProperty("EXTERNAL_MSPROJECT");
if (expath) {
diff --git a/Source/cmGlobalVisualStudio7Generator.h b/Source/cmGlobalVisualStudio7Generator.h
index a55cf45..288069c 100644
--- a/Source/cmGlobalVisualStudio7Generator.h
+++ b/Source/cmGlobalVisualStudio7Generator.h
@@ -157,6 +157,8 @@ protected:
cmValue typeGuid,
const std::set<BT<std::pair<std::string, bool>>>& dependencies) = 0;
+ virtual bool SupportsCxxModuleDyndep() const { return false; }
+
std::string ConvertToSolutionPath(const std::string& path);
std::set<std::string> IsPartOfDefaultBuild(
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index d5783ef..7523662 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -468,6 +468,10 @@ bool cmGlobalXCodeGenerator::Open(const std::string& bindir,
}
CFRelease(cfStr);
}
+#else
+ (void)bindir;
+ (void)projectName;
+ (void)dryRun;
#endif
return ret;
@@ -1372,6 +1376,18 @@ bool cmGlobalXCodeGenerator::CreateXCodeTarget(
return true;
}
+ for (std::string const& configName : this->CurrentConfigurationTypes) {
+ gtgt->CheckCxxModuleStatus(configName);
+ }
+
+ if (gtgt->HaveCxx20ModuleSources()) {
+ gtgt->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat("The \"", gtgt->GetName(),
+ "\" target contains C++ module sources which are not "
+ "supported by the generator"));
+ }
+
auto& gtgt_visited = this->CommandsVisited[gtgt];
auto& deps = this->GetTargetDirectDepends(gtgt);
for (auto& d : deps) {
@@ -2352,8 +2368,8 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt,
std::string& flags = cflags[lang];
// Add language-specific flags.
- this->CurrentLocalGenerator->AddLanguageFlags(flags, gtgt, lang,
- configName);
+ this->CurrentLocalGenerator->AddLanguageFlags(
+ flags, gtgt, cmBuildStep::Compile, lang, configName);
if (gtgt->IsIPOEnabled(lang, configName)) {
this->CurrentLocalGenerator->AppendFeatureOptions(flags, lang, "IPO");
@@ -2407,6 +2423,18 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt,
this->AppendDefines(ppDefs, targetDefines);
buildSettings->AddAttribute("GCC_PREPROCESSOR_DEFINITIONS",
ppDefs.CreateList());
+ if (languages.count("Swift")) {
+ if (this->XcodeVersion < 80) {
+ std::string defineString;
+ std::set<std::string> defines(targetDefines.begin(),
+ targetDefines.end());
+ this->CurrentLocalGenerator->JoinDefines(defines, defineString, "Swift");
+ cflags["Swift"] += " " + defineString;
+ } else {
+ buildSettings->AddAttribute("SWIFT_ACTIVE_COMPILATION_CONDITIONS",
+ ppDefs.CreateList());
+ }
+ }
std::string extraLinkOptionsVar;
std::string extraLinkOptions;
@@ -2866,8 +2894,8 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt,
}
// Create the INSTALL_PATH attribute.
- std::string install_name_dir;
if (gtgt->GetType() == cmStateEnums::SHARED_LIBRARY) {
+ std::string install_name_dir;
// Get the install_name directory for the build tree.
install_name_dir = gtgt->GetInstallNameDirForBuildTree(configName);
// Xcode doesn't create the correct install_name in some cases.
@@ -2889,9 +2917,9 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt,
extraLinkOptions += " -install_name ";
extraLinkOptions += XCodeEscapePath(install_name);
}
+ buildSettings->AddAttribute("INSTALL_PATH",
+ this->CreateString(install_name_dir));
}
- buildSettings->AddAttribute("INSTALL_PATH",
- this->CreateString(install_name_dir));
// Create the LD_RUNPATH_SEARCH_PATHS
cmComputeLinkInformation* pcli = gtgt->GetLinkInformation(configName);
diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx
index 7ca5b23..82adca8 100644
--- a/Source/cmInstallCommand.cxx
+++ b/Source/cmInstallCommand.cxx
@@ -12,18 +12,22 @@
#include <utility>
#include <cm/memory>
+#include <cm/optional>
#include <cm/string_view>
#include <cmext/string_view>
#include "cmsys/Glob.hxx"
#include "cmArgumentParser.h"
+#include "cmArgumentParserTypes.h"
#include "cmExecutionStatus.h"
+#include "cmExperimental.h"
#include "cmExportSet.h"
#include "cmFileSet.h"
#include "cmGeneratorExpression.h"
#include "cmGlobalGenerator.h"
#include "cmInstallCommandArguments.h"
+#include "cmInstallCxxModuleBmiGenerator.h"
#include "cmInstallDirectoryGenerator.h"
#include "cmInstallExportGenerator.h"
#include "cmInstallFileSetGenerator.h"
@@ -54,13 +58,13 @@ namespace {
struct RuntimeDependenciesArgs
{
- std::vector<std::string> Directories;
- std::vector<std::string> PreIncludeRegexes;
- std::vector<std::string> PreExcludeRegexes;
- std::vector<std::string> PostIncludeRegexes;
- std::vector<std::string> PostExcludeRegexes;
- std::vector<std::string> PostIncludeFiles;
- std::vector<std::string> PostExcludeFiles;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Directories;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> PreIncludeRegexes;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> PreExcludeRegexes;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> PostIncludeRegexes;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> PostExcludeRegexes;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> PostIncludeFiles;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> PostExcludeFiles;
};
auto const RuntimeDependenciesArgHelper =
@@ -109,6 +113,8 @@ public:
const cmInstallCommandArguments* args) const;
std::string GetLibraryDestination(
const cmInstallCommandArguments* args) const;
+ std::string GetCxxModulesBmiDestination(
+ const cmInstallCommandArguments* args) const;
std::string GetIncludeDestination(
const cmInstallCommandArguments* args) const;
std::string GetSysconfDestination(
@@ -401,16 +407,17 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
struct ArgVectors
{
- std::vector<std::string> Archive;
- std::vector<std::string> Library;
- std::vector<std::string> Runtime;
- std::vector<std::string> Object;
- std::vector<std::string> Framework;
- std::vector<std::string> Bundle;
- std::vector<std::string> Includes;
- std::vector<std::string> PrivateHeader;
- std::vector<std::string> PublicHeader;
- std::vector<std::string> Resource;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Archive;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Library;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Runtime;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Object;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Framework;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Bundle;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Includes;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> PrivateHeader;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> PublicHeader;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Resource;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> CxxModulesBmi;
std::vector<std::vector<std::string>> FileSets;
};
@@ -426,7 +433,8 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
.Bind("PRIVATE_HEADER"_s, &ArgVectors::PrivateHeader)
.Bind("PUBLIC_HEADER"_s, &ArgVectors::PublicHeader)
.Bind("RESOURCE"_s, &ArgVectors::Resource)
- .Bind("FILE_SET"_s, &ArgVectors::FileSets);
+ .Bind("FILE_SET"_s, &ArgVectors::FileSets)
+ .Bind("CXX_MODULES_BMI"_s, &ArgVectors::CxxModulesBmi);
std::vector<std::string> genericArgVector;
ArgVectors const argVectors = argHelper.Parse(args, &genericArgVector);
@@ -434,26 +442,25 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
// now parse the generic args (i.e. the ones not specialized on LIBRARY/
// ARCHIVE, RUNTIME etc. (see above)
// These generic args also contain the targets and the export stuff
- std::vector<std::string> targetList;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> targetList;
std::string exports;
- std::vector<std::string> runtimeDependenciesArgVector;
+ cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>>
+ runtimeDependenciesArgVector;
std::string runtimeDependencySetArg;
std::vector<std::string> unknownArgs;
- std::vector<std::string> parsedArgs;
cmInstallCommandArguments genericArgs(helper.DefaultComponentName);
genericArgs.Bind("TARGETS"_s, targetList);
genericArgs.Bind("EXPORT"_s, exports);
genericArgs.Bind("RUNTIME_DEPENDENCIES"_s, runtimeDependenciesArgVector);
genericArgs.Bind("RUNTIME_DEPENDENCY_SET"_s, runtimeDependencySetArg);
- genericArgs.Parse(genericArgVector, &unknownArgs, nullptr, &parsedArgs);
+ genericArgs.Parse(genericArgVector, &unknownArgs);
bool success = genericArgs.Finalize();
- bool withRuntimeDependencies =
- std::find(parsedArgs.begin(), parsedArgs.end(), "RUNTIME_DEPENDENCIES") !=
- parsedArgs.end();
RuntimeDependenciesArgs runtimeDependenciesArgs =
- RuntimeDependenciesArgHelper.Parse(runtimeDependenciesArgVector,
- &unknownArgs);
+ runtimeDependenciesArgVector
+ ? RuntimeDependenciesArgHelper.Parse(*runtimeDependenciesArgVector,
+ &unknownArgs)
+ : RuntimeDependenciesArgs();
cmInstallCommandArguments archiveArgs(helper.DefaultComponentName);
cmInstallCommandArguments libraryArgs(helper.DefaultComponentName);
@@ -467,6 +474,7 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
cmInstallCommandIncludesArgument includesArgs;
std::vector<cmInstallCommandFileSetArguments> fileSetArgs(
argVectors.FileSets.size(), { helper.DefaultComponentName });
+ cmInstallCommandArguments cxxModuleBmiArgs(helper.DefaultComponentName);
// now parse the args for specific parts of the target (e.g. LIBRARY,
// RUNTIME, ARCHIVE etc.
@@ -490,6 +498,15 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
fileSetArgs[i] = std::move(fileSetArg);
}
+ bool const supportCxx20FileSetTypes = cmExperimental::HasSupportEnabled(
+ *helper.Makefile, cmExperimental::Feature::CxxModuleCMakeApi);
+ if (!supportCxx20FileSetTypes) {
+ std::copy(argVectors.CxxModulesBmi.begin(), argVectors.CxxModulesBmi.end(),
+ std::back_inserter(unknownArgs));
+ } else {
+ cxxModuleBmiArgs.Parse(argVectors.CxxModulesBmi, &unknownArgs);
+ }
+
if (!unknownArgs.empty()) {
// Unknown argument.
status.SetError(
@@ -510,6 +527,7 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
for (auto& fileSetArg : fileSetArgs) {
fileSetArg.SetGenericArguments(&genericArgs);
}
+ cxxModuleBmiArgs.SetGenericArguments(&genericArgs);
success = success && archiveArgs.Finalize();
success = success && libraryArgs.Finalize();
@@ -523,6 +541,9 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
for (auto& fileSetArg : fileSetArgs) {
success = success && fileSetArg.Finalize();
}
+ if (supportCxx20FileSetTypes) {
+ success = success && cxxModuleBmiArgs.Finalize();
+ }
if (!success) {
return false;
@@ -536,7 +557,8 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
publicHeaderArgs.GetNamelinkOnly() || resourceArgs.GetNamelinkOnly() ||
std::any_of(fileSetArgs.begin(), fileSetArgs.end(),
[](const cmInstallCommandFileSetArguments& fileSetArg)
- -> bool { return fileSetArg.GetNamelinkOnly(); })) {
+ -> bool { return fileSetArg.GetNamelinkOnly(); }) ||
+ cxxModuleBmiArgs.GetNamelinkOnly()) {
status.SetError(
"TARGETS given NAMELINK_ONLY option not in LIBRARY group. "
"The NAMELINK_ONLY option may be specified only following LIBRARY.");
@@ -548,7 +570,8 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
publicHeaderArgs.GetNamelinkSkip() || resourceArgs.GetNamelinkSkip() ||
std::any_of(fileSetArgs.begin(), fileSetArgs.end(),
[](const cmInstallCommandFileSetArguments& fileSetArg)
- -> bool { return fileSetArg.GetNamelinkSkip(); })) {
+ -> bool { return fileSetArg.GetNamelinkSkip(); }) ||
+ cxxModuleBmiArgs.GetNamelinkSkip()) {
status.SetError(
"TARGETS given NAMELINK_SKIP option not in LIBRARY group. "
"The NAMELINK_SKIP option may be specified only following LIBRARY.");
@@ -564,7 +587,8 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
resourceArgs.HasNamelinkComponent() ||
std::any_of(fileSetArgs.begin(), fileSetArgs.end(),
[](const cmInstallCommandFileSetArguments& fileSetArg)
- -> bool { return fileSetArg.HasNamelinkComponent(); })) {
+ -> bool { return fileSetArg.HasNamelinkComponent(); }) ||
+ cxxModuleBmiArgs.HasNamelinkComponent()) {
status.SetError(
"TARGETS given NAMELINK_COMPONENT option not in LIBRARY group. "
"The NAMELINK_COMPONENT option may be specified only following "
@@ -583,7 +607,8 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
!publicHeaderArgs.GetType().empty() || !resourceArgs.GetType().empty() ||
std::any_of(fileSetArgs.begin(), fileSetArgs.end(),
[](const cmInstallCommandFileSetArguments& fileSetArg)
- -> bool { return !fileSetArg.GetType().empty(); })) {
+ -> bool { return !fileSetArg.GetType().empty(); }) ||
+ !cxxModuleBmiArgs.GetType().empty()) {
status.SetError(
"TARGETS given TYPE option. The TYPE option may only be specified in "
" install(FILES) and install(DIRECTORIES).");
@@ -597,7 +622,7 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
}
cmInstallRuntimeDependencySet* runtimeDependencySet = nullptr;
- if (withRuntimeDependencies) {
+ if (runtimeDependenciesArgVector) {
if (!runtimeDependencySetArg.empty()) {
status.SetError("TARGETS cannot have both RUNTIME_DEPENDENCIES and "
"RUNTIME_DEPENDENCY_SET.");
@@ -706,6 +731,7 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
bool installsPublicHeader = false;
bool installsResource = false;
std::vector<bool> installsFileSet(fileSetArgs.size(), false);
+ bool installsCxxModuleBmi = false;
// Generate install script code to install the given targets.
for (cmTarget* ti : targets) {
@@ -722,6 +748,7 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
std::unique_ptr<cmInstallFilesGenerator> publicHeaderGenerator;
std::unique_ptr<cmInstallFilesGenerator> resourceGenerator;
std::vector<std::unique_ptr<cmInstallFileSetGenerator>> fileSetGenerators;
+ std::unique_ptr<cmInstallCxxModuleBmiGenerator> cxxModuleBmiGenerator;
// Avoid selecting default destinations for PUBLIC_HEADER and
// PRIVATE_HEADER if any artifacts are specified.
@@ -760,6 +787,7 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
for (auto const& gen : fileSetGenerators) {
te->FileSetGenerators[gen->GetFileSet()] = gen.get();
}
+ te->CxxModuleBmiGenerator = cxxModuleBmiGenerator.get();
target.AddInstallIncludeDirectories(
*te, cmMakeRange(includesArgs.GetIncludeDirs()));
te->NamelinkOnly = namelinkOnly;
@@ -1105,6 +1133,19 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
}
}
+ if (supportCxx20FileSetTypes &&
+ !cxxModuleBmiArgs.GetDestination().empty()) {
+ cxxModuleBmiGenerator = cm::make_unique<cmInstallCxxModuleBmiGenerator>(
+ target.GetName(),
+ helper.GetCxxModulesBmiDestination(&cxxModuleBmiArgs),
+ cxxModuleBmiArgs.GetPermissions(),
+ cxxModuleBmiArgs.GetConfigurations(), cxxModuleBmiArgs.GetComponent(),
+ cmInstallGenerator::SelectMessageLevel(target.GetMakefile()),
+ cxxModuleBmiArgs.GetExcludeFromAll(), cxxModuleBmiArgs.GetOptional(),
+ helper.Makefile->GetBacktrace());
+ target.SetHaveInstallRule(true);
+ }
+
// Add this install rule to an export if one was specified.
if (!addTargetExport()) {
return false;
@@ -1121,6 +1162,7 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
installsPrivateHeader = installsPrivateHeader || privateHeaderGenerator;
installsPublicHeader = installsPublicHeader || publicHeaderGenerator;
installsResource = installsResource || resourceGenerator;
+ installsCxxModuleBmi = installsCxxModuleBmi || cxxModuleBmiGenerator;
helper.Makefile->AddInstallGenerator(std::move(archiveGenerator));
helper.Makefile->AddInstallGenerator(std::move(libraryGenerator));
@@ -1135,9 +1177,10 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
for (auto& gen : fileSetGenerators) {
helper.Makefile->AddInstallGenerator(std::move(gen));
}
+ helper.Makefile->AddInstallGenerator(std::move(cxxModuleBmiGenerator));
}
- if (withRuntimeDependencies && !runtimeDependencySet->Empty()) {
+ if (runtimeDependenciesArgVector && !runtimeDependencySet->Empty()) {
AddInstallRuntimeDependenciesGenerator(
helper, runtimeDependencySet, runtimeArgs, libraryArgs, frameworkArgs,
std::move(runtimeDependenciesArgs), installsRuntime, installsLibrary,
@@ -1192,6 +1235,10 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
fileSetArgs[i].GetComponent());
}
}
+ if (installsCxxModuleBmi) {
+ helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
+ cxxModuleBmiArgs.GetComponent());
+ }
return true;
}
@@ -1206,10 +1253,10 @@ bool HandleImportedRuntimeArtifactsMode(std::vector<std::string> const& args,
struct ArgVectors
{
- std::vector<std::string> Library;
- std::vector<std::string> Runtime;
- std::vector<std::string> Framework;
- std::vector<std::string> Bundle;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Library;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Runtime;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Framework;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Bundle;
};
static auto const argHelper = cmArgumentParser<ArgVectors>{}
@@ -1223,7 +1270,7 @@ bool HandleImportedRuntimeArtifactsMode(std::vector<std::string> const& args,
// now parse the generic args (i.e. the ones not specialized on LIBRARY,
// RUNTIME etc. (see above)
- std::vector<std::string> targetList;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> targetList;
std::string runtimeDependencySetArg;
std::vector<std::string> unknownArgs;
cmInstallCommandArguments genericArgs(helper.DefaultComponentName);
@@ -1464,7 +1511,7 @@ bool HandleFilesMode(std::vector<std::string> const& args,
// This is the FILES mode.
bool programs = (args[0] == "PROGRAMS");
cmInstallCommandArguments ica(helper.DefaultComponentName);
- std::vector<std::string> files;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> files;
ica.Bind(programs ? "PROGRAMS"_s : "FILES"_s, files);
std::vector<std::string> unknownArgs;
ica.Parse(args, &unknownArgs);
@@ -1950,7 +1997,7 @@ bool HandleExportAndroidMKMode(std::vector<std::string> const& args,
cm::make_unique<cmInstallExportGenerator>(
&exportSet, ica.GetDestination(), ica.GetPermissions(),
ica.GetConfigurations(), ica.GetComponent(), message,
- ica.GetExcludeFromAll(), fname, name_space, exportOld, true,
+ ica.GetExcludeFromAll(), fname, name_space, "", exportOld, true,
helper.Makefile->GetBacktrace()));
return true;
@@ -1973,12 +2020,19 @@ bool HandleExportMode(std::vector<std::string> const& args,
std::string name_space;
bool exportOld = false;
std::string filename;
+ std::string cxx_modules_directory;
ica.Bind("EXPORT"_s, exp);
ica.Bind("NAMESPACE"_s, name_space);
ica.Bind("EXPORT_LINK_INTERFACE_LIBRARIES"_s, exportOld);
ica.Bind("FILE"_s, filename);
+ bool const supportCxx20FileSetTypes = cmExperimental::HasSupportEnabled(
+ *helper.Makefile, cmExperimental::Feature::CxxModuleCMakeApi);
+ if (supportCxx20FileSetTypes) {
+ ica.Bind("CXX_MODULES_DIRECTORY"_s, cxx_modules_directory);
+ }
+
std::vector<std::string> unknownArgs;
ica.Parse(args, &unknownArgs);
@@ -2064,8 +2118,8 @@ bool HandleExportMode(std::vector<std::string> const& args,
cm::make_unique<cmInstallExportGenerator>(
&exportSet, ica.GetDestination(), ica.GetPermissions(),
ica.GetConfigurations(), ica.GetComponent(), message,
- ica.GetExcludeFromAll(), fname, name_space, exportOld, false,
- helper.Makefile->GetBacktrace()));
+ ica.GetExcludeFromAll(), fname, name_space, cxx_modules_directory,
+ exportOld, false, helper.Makefile->GetBacktrace()));
return true;
}
@@ -2088,9 +2142,9 @@ bool HandleRuntimeDependencySetMode(std::vector<std::string> const& args,
struct ArgVectors
{
- std::vector<std::string> Library;
- std::vector<std::string> Runtime;
- std::vector<std::string> Framework;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Library;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Runtime;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Framework;
};
static auto const argHelper = cmArgumentParser<ArgVectors>{}
@@ -2106,11 +2160,9 @@ bool HandleRuntimeDependencySetMode(std::vector<std::string> const& args,
// These generic args also contain the runtime dependency set
std::string runtimeDependencySetArg;
std::vector<std::string> runtimeDependencyArgVector;
- std::vector<std::string> parsedArgs;
cmInstallCommandArguments genericArgs(helper.DefaultComponentName);
genericArgs.Bind("RUNTIME_DEPENDENCY_SET"_s, runtimeDependencySetArg);
- genericArgs.Parse(genericArgVector, &runtimeDependencyArgVector, nullptr,
- &parsedArgs);
+ genericArgs.Parse(genericArgVector, &runtimeDependencyArgVector);
bool success = genericArgs.Finalize();
cmInstallCommandArguments libraryArgs(helper.DefaultComponentName);
@@ -2280,6 +2332,15 @@ std::string Helper::GetLibraryDestination(
return this->GetDestination(args, "CMAKE_INSTALL_LIBDIR", "lib");
}
+std::string Helper::GetCxxModulesBmiDestination(
+ const cmInstallCommandArguments* args) const
+{
+ if (args) {
+ return args->GetDestination();
+ }
+ return {};
+}
+
std::string Helper::GetIncludeDestination(
const cmInstallCommandArguments* args) const
{
diff --git a/Source/cmInstallCommandArguments.h b/Source/cmInstallCommandArguments.h
index 79bd945..6e46aac 100644
--- a/Source/cmInstallCommandArguments.h
+++ b/Source/cmInstallCommandArguments.h
@@ -8,6 +8,7 @@
#include <vector>
#include "cmArgumentParser.h"
+#include "cmArgumentParserTypes.h"
class cmInstallCommandArguments : public cmArgumentParser<void>
{
@@ -44,8 +45,8 @@ private:
std::string NamelinkComponent;
bool ExcludeFromAll = false;
std::string Rename;
- std::vector<std::string> Permissions;
- std::vector<std::string> Configurations;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Permissions;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Configurations;
bool Optional = false;
bool NamelinkOnly = false;
bool NamelinkSkip = false;
diff --git a/Source/cmInstallCxxModuleBmiGenerator.cxx b/Source/cmInstallCxxModuleBmiGenerator.cxx
new file mode 100644
index 0000000..1ef1eaa
--- /dev/null
+++ b/Source/cmInstallCxxModuleBmiGenerator.cxx
@@ -0,0 +1,75 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmInstallCxxModuleBmiGenerator.h"
+
+#include <ostream>
+#include <utility>
+
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalGenerator.h"
+#include "cmListFileCache.h"
+#include "cmLocalGenerator.h"
+#include "cmOutputConverter.h"
+#include "cmStringAlgorithms.h"
+
+cmInstallCxxModuleBmiGenerator::cmInstallCxxModuleBmiGenerator(
+ std::string target, std::string const& dest, std::string file_permissions,
+ std::vector<std::string> const& configurations, std::string const& component,
+ MessageLevel message, bool exclude_from_all, bool optional,
+ cmListFileBacktrace backtrace)
+ : cmInstallGenerator(dest, configurations, component, message,
+ exclude_from_all, false, std::move(backtrace))
+ , TargetName(std::move(target))
+ , FilePermissions(std::move(file_permissions))
+ , Optional(optional)
+{
+ this->ActionsPerConfig = true;
+}
+
+cmInstallCxxModuleBmiGenerator::~cmInstallCxxModuleBmiGenerator() = default;
+
+bool cmInstallCxxModuleBmiGenerator::Compute(cmLocalGenerator* lg)
+{
+ this->LocalGenerator = lg;
+
+ this->Target = lg->FindLocalNonAliasGeneratorTarget(this->TargetName);
+ if (!this->Target) {
+ // If no local target has been found, find it in the global scope.
+ this->Target =
+ lg->GetGlobalGenerator()->FindGeneratorTarget(this->TargetName);
+ }
+
+ return true;
+}
+
+std::string cmInstallCxxModuleBmiGenerator::GetScriptLocation(
+ std::string const& config) const
+{
+ char const* config_name = config.c_str();
+ if (config.empty()) {
+ config_name = "noconfig";
+ }
+ return cmStrCat(this->Target->GetSupportDirectory(),
+ "/install-cxx-module-bmi-", config_name, ".cmake");
+}
+
+std::string cmInstallCxxModuleBmiGenerator::GetDestination(
+ std::string const& config) const
+{
+ return cmGeneratorExpression::Evaluate(this->Destination,
+ this->LocalGenerator, config);
+}
+
+void cmInstallCxxModuleBmiGenerator::GenerateScriptForConfig(
+ std::ostream& os, const std::string& config, Indent indent)
+{
+ auto const& loc = this->GetScriptLocation(config);
+ if (loc.empty()) {
+ return;
+ }
+ os << indent << "include(\""
+ << cmOutputConverter::EscapeForCMake(
+ loc, cmOutputConverter::WrapQuotes::NoWrap)
+ << "\" OPTIONAL)\n";
+}
diff --git a/Source/cmInstallCxxModuleBmiGenerator.h b/Source/cmInstallCxxModuleBmiGenerator.h
new file mode 100644
index 0000000..21edb2e
--- /dev/null
+++ b/Source/cmInstallCxxModuleBmiGenerator.h
@@ -0,0 +1,52 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <iosfwd>
+#include <string>
+#include <vector>
+
+#include "cmInstallGenerator.h"
+#include "cmScriptGenerator.h"
+
+class cmGeneratorTarget;
+class cmListFileBacktrace;
+class cmLocalGenerator;
+
+/** \class cmInstallCxxModuleBmiGenerator
+ * \brief Generate C++ module BMI installation rules.
+ */
+class cmInstallCxxModuleBmiGenerator : public cmInstallGenerator
+{
+public:
+ cmInstallCxxModuleBmiGenerator(
+ std::string target, std::string const& dest, std::string file_permissions,
+ std::vector<std::string> const& configurations,
+ std::string const& component, MessageLevel message, bool exclude_from_all,
+ bool optional, cmListFileBacktrace backtrace);
+ ~cmInstallCxxModuleBmiGenerator() override;
+
+ bool Compute(cmLocalGenerator* lg) override;
+
+ std::string const& GetFilePermissions() const
+ {
+ return this->FilePermissions;
+ }
+ std::string GetDestination(std::string const& config) const;
+ std::string GetScriptLocation(std::string const& config) const;
+ cmGeneratorTarget const* GetTarget() const { return this->Target; }
+ bool GetOptional() const { return this->Optional; }
+ MessageLevel GetMessageLevel() const { return this->Message; }
+
+protected:
+ void GenerateScriptForConfig(std::ostream& os, const std::string& config,
+ Indent indent) override;
+
+ std::string const TargetName;
+ cmGeneratorTarget const* Target = nullptr;
+ cmLocalGenerator* LocalGenerator = nullptr;
+ std::string const FilePermissions;
+ bool const Optional;
+};
diff --git a/Source/cmInstallExportGenerator.cxx b/Source/cmInstallExportGenerator.cxx
index b80437d..1d81b0b 100644
--- a/Source/cmInstallExportGenerator.cxx
+++ b/Source/cmInstallExportGenerator.cxx
@@ -23,7 +23,8 @@ cmInstallExportGenerator::cmInstallExportGenerator(
cmExportSet* exportSet, std::string const& destination,
std::string file_permissions, std::vector<std::string> const& configurations,
std::string const& component, MessageLevel message, bool exclude_from_all,
- std::string filename, std::string name_space, bool exportOld, bool android,
+ std::string filename, std::string name_space,
+ std::string cxx_modules_directory, bool exportOld, bool android,
cmListFileBacktrace backtrace)
: cmInstallGenerator(destination, configurations, component, message,
exclude_from_all, false, std::move(backtrace))
@@ -31,6 +32,7 @@ cmInstallExportGenerator::cmInstallExportGenerator(
, FilePermissions(std::move(file_permissions))
, FileName(std::move(filename))
, Namespace(std::move(name_space))
+ , CxxModulesDirectory(std::move(cxx_modules_directory))
, ExportOld(exportOld)
{
if (android) {
@@ -141,6 +143,75 @@ void cmInstallExportGenerator::GenerateScriptConfigs(std::ostream& os,
os << indent << "endif()\n";
files.clear();
}
+
+ // Now create a configuration-specific install rule for the C++ module import
+ // property file of each configuration.
+ auto cxx_module_dest =
+ cmStrCat(this->Destination, '/', this->CxxModulesDirectory);
+ std::string config_file_example;
+ for (auto const& i : this->EFGen->GetConfigCxxModuleFiles()) {
+ config_file_example = i.second;
+ break;
+ }
+ if (!config_file_example.empty()) {
+ // Remove old per-configuration export files if the main changes.
+ std::string installedDir = cmStrCat(
+ "$ENV{DESTDIR}", ConvertToAbsoluteDestination(cxx_module_dest), '/');
+ std::string installedFile = cmStrCat(installedDir, "/cxx-modules.cmake");
+ std::string toInstallFile =
+ cmStrCat(cmSystemTools::GetFilenamePath(config_file_example),
+ "/cxx-modules.cmake");
+ os << indent << "if(EXISTS \"" << installedFile << "\")\n";
+ Indent indentN = indent.Next();
+ Indent indentNN = indentN.Next();
+ Indent indentNNN = indentNN.Next();
+ /* clang-format off */
+ os << indentN << "file(DIFFERENT _cmake_export_file_changed FILES\n"
+ << indentN << " \"" << installedFile << "\"\n"
+ << indentN << " \"" << toInstallFile << "\")\n";
+ os << indentN << "if(_cmake_export_file_changed)\n";
+ os << indentNN << "file(GLOB _cmake_old_config_files \"" << installedDir
+ << this->EFGen->GetConfigImportFileGlob() << "\")\n";
+ os << indentNN << "if(_cmake_old_config_files)\n";
+ os << indentNNN << "string(REPLACE \";\" \", \" _cmake_old_config_files_text \"${_cmake_old_config_files}\")\n";
+ os << indentNNN << R"(message(STATUS "Old C++ module export file \")" << installedFile
+ << "\\\" will be replaced. Removing files [${_cmake_old_config_files_text}].\")\n";
+ os << indentNNN << "unset(_cmake_old_config_files_text)\n";
+ os << indentNNN << "file(REMOVE ${_cmake_old_config_files})\n";
+ os << indentNN << "endif()\n";
+ os << indentNN << "unset(_cmake_old_config_files)\n";
+ os << indentN << "endif()\n";
+ os << indentN << "unset(_cmake_export_file_changed)\n";
+ os << indent << "endif()\n";
+ /* clang-format on */
+
+ // All of these files are siblings; get its location to know where the
+ // "anchor" file is.
+ files.push_back(toInstallFile);
+ this->AddInstallRule(os, cxx_module_dest, cmInstallType_FILES, files,
+ false, this->FilePermissions.c_str(), nullptr,
+ nullptr, nullptr, indent);
+ files.clear();
+ }
+ for (auto const& i : this->EFGen->GetConfigCxxModuleFiles()) {
+ files.push_back(i.second);
+ std::string config_test = this->CreateConfigTest(i.first);
+ os << indent << "if(" << config_test << ")\n";
+ this->AddInstallRule(os, cxx_module_dest, cmInstallType_FILES, files,
+ false, this->FilePermissions.c_str(), nullptr,
+ nullptr, nullptr, indent.Next());
+ os << indent << "endif()\n";
+ files.clear();
+ }
+ for (auto const& i : this->EFGen->GetConfigCxxModuleTargetFiles()) {
+ std::string config_test = this->CreateConfigTest(i.first);
+ os << indent << "if(" << config_test << ")\n";
+ this->AddInstallRule(os, cxx_module_dest, cmInstallType_FILES, i.second,
+ false, this->FilePermissions.c_str(), nullptr,
+ nullptr, nullptr, indent.Next());
+ os << indent << "endif()\n";
+ files.clear();
+ }
}
void cmInstallExportGenerator::GenerateScriptActions(std::ostream& os,
diff --git a/Source/cmInstallExportGenerator.h b/Source/cmInstallExportGenerator.h
index 02fe1fa..346ca67 100644
--- a/Source/cmInstallExportGenerator.h
+++ b/Source/cmInstallExportGenerator.h
@@ -28,7 +28,8 @@ public:
const std::vector<std::string>& configurations,
std::string const& component, MessageLevel message,
bool exclude_from_all, std::string filename,
- std::string name_space, bool exportOld,
+ std::string name_space,
+ std::string cxx_modules_directory, bool exportOld,
bool android, cmListFileBacktrace backtrace);
cmInstallExportGenerator(const cmInstallExportGenerator&) = delete;
~cmInstallExportGenerator() override;
@@ -50,6 +51,10 @@ public:
std::string GetDestinationFile() const;
std::string GetFileName() const { return this->FileName; }
std::string GetTempDir() const;
+ std::string GetCxxModuleDirectory() const
+ {
+ return this->CxxModulesDirectory;
+ }
protected:
void GenerateScript(std::ostream& os) override;
@@ -64,6 +69,7 @@ protected:
std::string const FilePermissions;
std::string const FileName;
std::string const Namespace;
+ std::string const CxxModulesDirectory;
bool const ExportOld;
cmLocalGenerator* LocalGenerator = nullptr;
diff --git a/Source/cmLinkLineDeviceComputer.cxx b/Source/cmLinkLineDeviceComputer.cxx
index 43f1b8e..b06dc3d 100644
--- a/Source/cmLinkLineDeviceComputer.cxx
+++ b/Source/cmLinkLineDeviceComputer.cxx
@@ -57,7 +57,6 @@ bool cmLinkLineDeviceComputer::ComputeRequiresDeviceLinking(
// For this we only consider targets
using ItemVector = cmComputeLinkInformation::ItemVector;
ItemVector const& items = cli.GetItems();
- std::string config = cli.GetConfig();
return std::any_of(
items.begin(), items.end(),
[](cmComputeLinkInformation::Item const& item) -> bool {
@@ -69,6 +68,26 @@ bool cmLinkLineDeviceComputer::ComputeRequiresDeviceLinking(
});
}
+bool cmLinkLineDeviceComputer::ComputeRequiresDeviceLinkingIPOFlag(
+ cmComputeLinkInformation& cli)
+{
+ // Determine if this item might requires device linking.
+ // For this we only consider targets
+ using ItemVector = cmComputeLinkInformation::ItemVector;
+ ItemVector const& items = cli.GetItems();
+ std::string config = cli.GetConfig();
+ return std::any_of(
+ items.begin(), items.end(),
+ [config](cmComputeLinkInformation::Item const& item) -> bool {
+ return item.Target &&
+ item.Target->GetType() == cmStateEnums::STATIC_LIBRARY &&
+ // this dependency requires us to device link it
+ !item.Target->GetPropertyAsBool("CUDA_RESOLVE_DEVICE_SYMBOLS") &&
+ item.Target->GetPropertyAsBool("CUDA_SEPARABLE_COMPILATION") &&
+ item.Target->IsIPOEnabled("CUDA", config);
+ });
+}
+
void cmLinkLineDeviceComputer::ComputeLinkLibraries(
cmComputeLinkInformation& cli, std::string const& stdLibString,
std::vector<BT<std::string>>& linkLibraries)
diff --git a/Source/cmLinkLineDeviceComputer.h b/Source/cmLinkLineDeviceComputer.h
index dee625b..0916307 100644
--- a/Source/cmLinkLineDeviceComputer.h
+++ b/Source/cmLinkLineDeviceComputer.h
@@ -30,6 +30,7 @@ public:
delete;
bool ComputeRequiresDeviceLinking(cmComputeLinkInformation& cli);
+ bool ComputeRequiresDeviceLinkingIPOFlag(cmComputeLinkInformation& cli);
void ComputeLinkLibraries(
cmComputeLinkInformation& cli, std::string const& stdLibString,
diff --git a/Source/cmListFileCache.cxx b/Source/cmListFileCache.cxx
index 91157cb..6270c82 100644
--- a/Source/cmListFileCache.cxx
+++ b/Source/cmListFileCache.cxx
@@ -347,6 +347,7 @@ enum class NestingStateEnum
Foreach,
Function,
Macro,
+ Block
};
struct NestingState
@@ -434,6 +435,16 @@ cm::optional<cmListFileContext> cmListFileParser::CheckNesting() const
return cmListFileContext::FromListFileFunction(func, this->FileName);
}
stack.pop_back();
+ } else if (name == "block") {
+ stack.push_back({
+ NestingStateEnum::Block,
+ cmListFileContext::FromListFileFunction(func, this->FileName),
+ });
+ } else if (name == "endblock") {
+ if (!TopIs(stack, NestingStateEnum::Block)) {
+ return cmListFileContext::FromListFileFunction(func, this->FileName);
+ }
+ stack.pop_back();
}
}
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index 67c8bf2..b44d2a0 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -15,6 +15,7 @@
#include <vector>
#include <cm/memory>
+#include <cm/optional>
#include <cm/string_view>
#include <cmext/algorithm>
#include <cmext/string_view>
@@ -36,6 +37,7 @@
#include "cmInstallScriptGenerator.h"
#include "cmInstallTargetGenerator.h"
#include "cmLinkLineComputer.h"
+#include "cmLinkLineDeviceComputer.h"
#include "cmMakefile.h"
#include "cmRange.h"
#include "cmRulePlaceholderExpander.h"
@@ -1381,7 +1383,7 @@ std::vector<BT<std::string>> cmLocalGenerator::GetStaticLibraryFlags(
}
void cmLocalGenerator::GetDeviceLinkFlags(
- cmLinkLineComputer& linkLineComputer, const std::string& config,
+ cmLinkLineDeviceComputer& linkLineComputer, const std::string& config,
std::string& linkLibs, std::string& linkFlags, std::string& frameworkPath,
std::string& linkPath, cmGeneratorTarget* target)
{
@@ -1389,6 +1391,18 @@ void cmLocalGenerator::GetDeviceLinkFlags(
cmComputeLinkInformation* pcli = target->GetLinkInformation(config);
+ auto linklang = linkLineComputer.GetLinkerLanguage(target, config);
+ auto ipoEnabled = target->IsIPOEnabled(linklang, config);
+ if (!ipoEnabled) {
+ ipoEnabled = linkLineComputer.ComputeRequiresDeviceLinkingIPOFlag(*pcli);
+ }
+ if (ipoEnabled) {
+ if (cmValue cudaIPOFlags = this->Makefile->GetDefinition(
+ "CMAKE_CUDA_DEVICE_LINK_OPTIONS_IPO")) {
+ linkFlags += cudaIPOFlags;
+ }
+ }
+
if (pcli) {
// Compute the required device link libraries when
// resolving gpu lang device symbols
@@ -1396,6 +1410,8 @@ void cmLocalGenerator::GetDeviceLinkFlags(
linkPath);
}
+ // iterate link deps and see if any of them need IPO
+
std::vector<std::string> linkOpts;
target->GetLinkOptions(linkOpts, config, "CUDA");
// LINK_OPTIONS are escaped.
@@ -1590,7 +1606,8 @@ std::vector<BT<std::string>> cmLocalGenerator::GetTargetCompileFlags(
cmMakefile* mf = this->GetMakefile();
// Add language-specific flags.
- this->AddLanguageFlags(compileFlags, target, lang, config);
+ this->AddLanguageFlags(compileFlags, target, cmBuildStep::Compile, lang,
+ config);
if (target->IsIPOEnabled(lang, config)) {
this->AppendFeatureOptions(compileFlags, lang, "IPO");
@@ -1903,6 +1920,7 @@ void cmLocalGenerator::AddArchitectureFlags(std::string& flags,
void cmLocalGenerator::AddLanguageFlags(std::string& flags,
cmGeneratorTarget const* target,
+ cmBuildStep compileOrLink,
const std::string& lang,
const std::string& config)
{
@@ -1926,7 +1944,7 @@ void cmLocalGenerator::AddLanguageFlags(std::string& flags,
}
}
} else if (lang == "CUDA") {
- target->AddCUDAArchitectureFlags(flags);
+ target->AddCUDAArchitectureFlags(compileOrLink, config, flags);
target->AddCUDAToolkitFlags(flags);
} else if (lang == "ISPC") {
target->AddISPCTargetFlags(flags);
@@ -2038,7 +2056,7 @@ void cmLocalGenerator::AddLanguageFlagsForLinking(
this->AddCompilerRequirementFlag(flags, target, lang, config);
}
- this->AddLanguageFlags(flags, target, lang, config);
+ this->AddLanguageFlags(flags, target, cmBuildStep::Link, lang, config);
if (target->IsIPOEnabled(lang, config)) {
this->AppendFeatureOptions(flags, lang, "IPO");
@@ -2574,7 +2592,9 @@ void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target)
if (pchSource.empty() || pchHeader.empty()) {
if (this->GetGlobalGenerator()->IsXcode() && !pchLangSet.empty()) {
for (auto* sf : sources) {
- if (pchLangSet.find(sf->GetLanguage()) == pchLangSet.end()) {
+ const auto sourceLanguage = sf->GetLanguage();
+ if (!sourceLanguage.empty() &&
+ pchLangSet.find(sourceLanguage) == pchLangSet.end()) {
sf->SetProperty("SKIP_PRECOMPILE_HEADERS", "ON");
}
}
@@ -2667,7 +2687,7 @@ void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target)
cmStrCat(linkerProperty, configUpper),
cmStrCat(" ",
this->ConvertToOutputFormat(pchSourceObj, SHELL)),
- true);
+ cm::nullopt, true);
} else if (reuseTarget->GetType() ==
cmStateEnums::OBJECT_LIBRARY) {
// FIXME: This can propagate more than one level, unlike
diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h
index 7cae1fc..0529431 100644
--- a/Source/cmLocalGenerator.h
+++ b/Source/cmLocalGenerator.h
@@ -35,6 +35,7 @@ class cmGeneratorTarget;
class cmGlobalGenerator;
class cmImplicitDependsList;
class cmLinkLineComputer;
+class cmLinkLineDeviceComputer;
class cmMakefile;
class cmRulePlaceholderExpander;
class cmSourceFile;
@@ -59,6 +60,13 @@ enum class cmDependencyScannerKind
Compiler
};
+/** What to compute language flags for */
+enum class cmBuildStep
+{
+ Compile,
+ Link
+};
+
/** Target and source file which have a specific output. */
struct cmSourcesWithOutput
{
@@ -143,7 +151,8 @@ public:
const std::string& filterArch = std::string());
void AddLanguageFlags(std::string& flags, cmGeneratorTarget const* target,
- const std::string& lang, const std::string& config);
+ cmBuildStep compileOrLink, const std::string& lang,
+ const std::string& config);
void AddLanguageFlagsForLinking(std::string& flags,
cmGeneratorTarget const* target,
const std::string& lang,
@@ -476,7 +485,7 @@ public:
/** Fill out these strings for the given target. Libraries to link,
* flags, and linkflags. */
- void GetDeviceLinkFlags(cmLinkLineComputer& linkLineComputer,
+ void GetDeviceLinkFlags(cmLinkLineDeviceComputer& linkLineComputer,
const std::string& config, std::string& linkLibs,
std::string& linkFlags, std::string& frameworkPath,
std::string& linkPath, cmGeneratorTarget* target);
diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx
index e125470..de1d3cd 100644
--- a/Source/cmLocalUnixMakefileGenerator3.cxx
+++ b/Source/cmLocalUnixMakefileGenerator3.cxx
@@ -1412,13 +1412,16 @@ bool cmLocalUnixMakefileGenerator3::UpdateDependencies(
if (needRescanDependInfo || needRescanDirInfo || needRescanDependencies) {
// The dependencies must be regenerated.
- std::string targetName = cmSystemTools::GetFilenameName(targetDir);
- targetName = targetName.substr(0, targetName.length() - 4);
- std::string message =
- cmStrCat("Scanning dependencies of target ", targetName);
- cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundMagenta |
- cmsysTerminal_Color_ForegroundBold,
- message.c_str(), true, color);
+ if (verbose) {
+ std::string targetName = cmSystemTools::GetFilenameName(targetDir);
+ targetName = targetName.substr(0, targetName.length() - 4);
+ std::string message =
+ cmStrCat("Scanning dependencies of target ", targetName);
+ cmSystemTools::MakefileColorEcho(
+ cmsysTerminal_Color_ForegroundMagenta |
+ cmsysTerminal_Color_ForegroundBold,
+ message.c_str(), true, color);
+ }
status = this->ScanDependencies(targetDir, dependFile,
internalDependFile, validDependencies);
@@ -1447,13 +1450,19 @@ bool cmLocalUnixMakefileGenerator3::UpdateDependencies(
this->GetBinaryDirectory())
: std::function<bool(const std::string&)>())) {
// regenerate dependencies files
- std::string targetName =
- cmCMakePath(targetDir).GetFileName().RemoveExtension().GenericString();
- auto message = cmStrCat(
- "Consolidate compiler generated dependencies of target ", targetName);
- cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundMagenta |
- cmsysTerminal_Color_ForegroundBold,
- message.c_str(), true, color);
+ if (verbose) {
+ std::string targetName = cmCMakePath(targetDir)
+ .GetFileName()
+ .RemoveExtension()
+ .GenericString();
+ auto message =
+ cmStrCat("Consolidate compiler generated dependencies of target ",
+ targetName);
+ cmSystemTools::MakefileColorEcho(
+ cmsysTerminal_Color_ForegroundMagenta |
+ cmsysTerminal_Color_ForegroundBold,
+ message.c_str(), true, color);
+ }
// Open the make depends file. This should be copy-if-different
// because the make tool may try to reload it needlessly otherwise.
diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx
index f65add1..0451d96 100644
--- a/Source/cmLocalVisualStudio7Generator.cxx
+++ b/Source/cmLocalVisualStudio7Generator.cxx
@@ -680,7 +680,8 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(
langForClCompile = linkLanguage;
if (langForClCompile == "C" || langForClCompile == "CXX" ||
langForClCompile == "Fortran") {
- this->AddLanguageFlags(flags, target, langForClCompile, configName);
+ this->AddLanguageFlags(flags, target, cmBuildStep::Compile,
+ langForClCompile, configName);
}
// set the correct language
if (linkLanguage == "C") {
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index 628eb1d..b228e2b 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -149,6 +149,29 @@ void cmMakefile::IssueMessage(MessageType t, std::string const& text) const
this->GetCMakeInstance()->IssueMessage(t, text, this->Backtrace);
}
+Message::LogLevel cmMakefile::GetCurrentLogLevel() const
+{
+ const cmake* cmakeInstance = this->GetCMakeInstance();
+
+ const Message::LogLevel logLevelCliOrDefault = cmakeInstance->GetLogLevel();
+ assert("Expected a valid log level here" &&
+ logLevelCliOrDefault != Message::LogLevel::LOG_UNDEFINED);
+
+ Message::LogLevel result = logLevelCliOrDefault;
+
+ // If the log-level was set via the command line option, it takes precedence
+ // over the CMAKE_MESSAGE_LOG_LEVEL variable.
+ if (!cmakeInstance->WasLogLevelSetViaCLI()) {
+ const Message::LogLevel logLevelFromVar = cmake::StringToLogLevel(
+ this->GetSafeDefinition("CMAKE_MESSAGE_LOG_LEVEL"));
+ if (logLevelFromVar != Message::LogLevel::LOG_UNDEFINED) {
+ result = logLevelFromVar;
+ }
+ }
+
+ return result;
+}
+
bool cmMakefile::CheckCMP0037(std::string const& targetName,
cmStateEnums::TargetType targetType) const
{
@@ -3456,7 +3479,7 @@ void cmMakefile::AddTargetObject(std::string const& tgtName,
#endif
}
-void cmMakefile::EnableLanguage(std::vector<std::string> const& lang,
+void cmMakefile::EnableLanguage(std::vector<std::string> const& languages,
bool optional)
{
if (this->DeferRunning) {
@@ -3468,24 +3491,48 @@ void cmMakefile::EnableLanguage(std::vector<std::string> const& lang,
if (const char* def = this->GetGlobalGenerator()->GetCMakeCFGIntDir()) {
this->AddDefinition("CMAKE_CFG_INTDIR", def);
}
+
+ std::vector<std::string> unique_languages;
+ {
+ std::vector<std::string> duplicate_languages;
+ for (std::string const& language : languages) {
+ if (!cm::contains(unique_languages, language)) {
+ unique_languages.push_back(language);
+ } else if (!cm::contains(duplicate_languages, language)) {
+ duplicate_languages.push_back(language);
+ }
+ }
+ if (!duplicate_languages.empty()) {
+ auto quantity = duplicate_languages.size() == 1 ? std::string(" has")
+ : std::string("s have");
+ this->IssueMessage(MessageType::AUTHOR_WARNING,
+ "Languages to be enabled may not be specified more "
+ "than once at the same time. The following language" +
+ quantity + " been specified multiple times: " +
+ cmJoin(duplicate_languages, ", "));
+ }
+ }
+
// If RC is explicitly listed we need to do it after other languages.
// On some platforms we enable RC implicitly while enabling others.
// Do not let that look like recursive enable_language(RC).
- std::vector<std::string> langs;
- std::vector<std::string> langsRC;
- langs.reserve(lang.size());
- for (std::string const& i : lang) {
- if (i == "RC") {
- langsRC.push_back(i);
+ std::vector<std::string> languages_without_RC;
+ std::vector<std::string> languages_for_RC;
+ languages_without_RC.reserve(unique_languages.size());
+ for (std::string const& language : unique_languages) {
+ if (language == "RC") {
+ languages_for_RC.push_back(language);
} else {
- langs.push_back(i);
+ languages_without_RC.push_back(language);
}
}
- if (!langs.empty()) {
- this->GetGlobalGenerator()->EnableLanguage(langs, this, optional);
+ if (!languages_without_RC.empty()) {
+ this->GetGlobalGenerator()->EnableLanguage(languages_without_RC, this,
+ optional);
}
- if (!langsRC.empty()) {
- this->GetGlobalGenerator()->EnableLanguage(langsRC, this, optional);
+ if (!languages_for_RC.empty()) {
+ this->GetGlobalGenerator()->EnableLanguage(languages_for_RC, this,
+ optional);
}
}
@@ -4431,7 +4478,7 @@ bool cmMakefile::SetPolicy(cmPolicies::PolicyID id,
}
// Deprecate old policies.
- if (status == cmPolicies::OLD && id <= cmPolicies::CMP0097 &&
+ if (status == cmPolicies::OLD && id <= cmPolicies::CMP0102 &&
!(this->GetCMakeInstance()->GetIsInTryCompile() &&
(
// Policies set by cmCoreTryCompile::TryCompileCode.
@@ -4496,6 +4543,19 @@ bool cmMakefile::SetPolicyVersion(std::string const& version_min,
cmPolicies::WarnCompat::On);
}
+cmMakefile::VariablePushPop::VariablePushPop(cmMakefile* m)
+ : Makefile(m)
+{
+ this->Makefile->StateSnapshot =
+ this->Makefile->GetState()->CreateVariableScopeSnapshot(
+ this->Makefile->StateSnapshot);
+}
+
+cmMakefile::VariablePushPop::~VariablePushPop()
+{
+ this->Makefile->PopSnapshot();
+}
+
bool cmMakefile::HasCMP0054AlreadyBeenReported(
cmListFileContext const& context) const
{
diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h
index e7b9716..10432a8 100644
--- a/Source/cmMakefile.h
+++ b/Source/cmMakefile.h
@@ -376,6 +376,20 @@ public:
};
friend class PolicyPushPop;
+ /** Helper class to push and pop variables scopes automatically. */
+ class VariablePushPop
+ {
+ public:
+ VariablePushPop(cmMakefile* m);
+ ~VariablePushPop();
+
+ VariablePushPop(VariablePushPop const&) = delete;
+ VariablePushPop& operator=(VariablePushPop const&) = delete;
+
+ private:
+ cmMakefile* Makefile;
+ };
+
/**
* Determine if the given context, name pair has already been reported
* in context of CMP0054.
@@ -862,6 +876,10 @@ public:
void PushScope();
void PopScope();
void RaiseScope(const std::string& var, const char* value);
+ void RaiseScope(const std::string& var, cmValue value)
+ {
+ this->RaiseScope(var, value.GetCStr());
+ }
// push and pop loop scopes
void PushLoopBlockBarrier();
@@ -925,6 +943,7 @@ public:
};
void IssueMessage(MessageType t, std::string const& text) const;
+ Message::LogLevel GetCurrentLogLevel() const;
/** Set whether or not to report a CMP0000 violation. */
void SetCheckCMP0000(bool b) { this->CheckCMP0000 = b; }
diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx
index 3849c6f..54f03b9 100644
--- a/Source/cmMakefileExecutableTargetGenerator.cxx
+++ b/Source/cmMakefileExecutableTargetGenerator.cxx
@@ -136,17 +136,11 @@ void cmMakefileExecutableTargetGenerator::WriteNvidiaDeviceExecutableRule(
std::vector<std::string> depends;
this->AppendLinkDepends(depends, linkLanguage);
- // Build a list of compiler flags and linker flags.
- std::string langFlags;
- std::string linkFlags;
-
// Add language feature flags.
+ std::string langFlags;
this->LocalGenerator->AddLanguageFlagsForLinking(
langFlags, this->GeneratorTarget, linkLanguage, this->GetConfigName());
- // Add device-specific linker flags.
- this->GetDeviceLinkFlags(linkFlags, linkLanguage);
-
// Construct a list of files associated with this executable that
// may need to be cleaned.
std::vector<std::string> exeCleanFiles;
@@ -173,23 +167,32 @@ void cmMakefileExecutableTargetGenerator::WriteNvidiaDeviceExecutableRule(
// Set path conversion for link script shells.
this->LocalGenerator->SetLinkScriptShell(useLinkScript);
- std::unique_ptr<cmLinkLineComputer> linkLineComputer(
+ std::unique_ptr<cmLinkLineDeviceComputer> linkLineComputer(
new cmLinkLineDeviceComputer(
this->LocalGenerator,
this->LocalGenerator->GetStateSnapshot().GetDirectory()));
linkLineComputer->SetForResponse(useResponseFileForLibs);
linkLineComputer->SetRelink(relink);
+ // Create set of linking flags.
+ std::string linkFlags;
+ std::string ignored_;
+ this->LocalGenerator->GetDeviceLinkFlags(
+ *linkLineComputer, this->GetConfigName(), ignored_, linkFlags, ignored_,
+ ignored_, this->GeneratorTarget);
+
// Collect up flags to link in needed libraries.
std::string linkLibs;
- this->CreateLinkLibs(linkLineComputer.get(), linkLibs,
- useResponseFileForLibs, depends);
+ this->CreateLinkLibs(
+ linkLineComputer.get(), linkLibs, useResponseFileForLibs, depends,
+ cmMakefileTargetGenerator::ResponseFlagFor::DeviceLink);
// Construct object file lists that may be needed to expand the
// rule.
std::string buildObjs;
- this->CreateObjectLists(useLinkScript, false, useResponseFileForObjects,
- buildObjs, depends, false);
+ this->CreateObjectLists(
+ useLinkScript, false, useResponseFileForObjects, buildObjs, depends,
+ false, cmMakefileTargetGenerator::ResponseFlagFor::DeviceLink);
cmRulePlaceholderExpander::RuleVariables vars;
std::string objectDir = this->GeneratorTarget->GetSupportDirectory();
diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx
index f30ec27..45ef8c8 100644
--- a/Source/cmMakefileLibraryTargetGenerator.cxx
+++ b/Source/cmMakefileLibraryTargetGenerator.cxx
@@ -287,10 +287,6 @@ void cmMakefileLibraryTargetGenerator::WriteNvidiaDeviceLibraryRules(
this->LocalGenerator->AddLanguageFlagsForLinking(
langFlags, this->GeneratorTarget, linkLanguage, this->GetConfigName());
- // Create set of linking flags.
- std::string linkFlags;
- this->GetDeviceLinkFlags(linkFlags, linkLanguage);
-
// Clean files associated with this library.
std::set<std::string> libCleanFiles;
libCleanFiles.insert(
@@ -315,22 +311,31 @@ void cmMakefileLibraryTargetGenerator::WriteNvidiaDeviceLibraryRules(
// Collect up flags to link in needed libraries.
std::string linkLibs;
- std::unique_ptr<cmLinkLineComputer> linkLineComputer(
+ std::unique_ptr<cmLinkLineDeviceComputer> linkLineComputer(
new cmLinkLineDeviceComputer(
this->LocalGenerator,
this->LocalGenerator->GetStateSnapshot().GetDirectory()));
linkLineComputer->SetForResponse(useResponseFileForLibs);
linkLineComputer->SetRelink(relink);
- this->CreateLinkLibs(linkLineComputer.get(), linkLibs,
- useResponseFileForLibs, depends);
+ // Create set of linking flags.
+ std::string linkFlags;
+ std::string ignored_;
+ this->LocalGenerator->GetDeviceLinkFlags(
+ *linkLineComputer, this->GetConfigName(), ignored_, linkFlags, ignored_,
+ ignored_, this->GeneratorTarget);
+
+ this->CreateLinkLibs(
+ linkLineComputer.get(), linkLibs, useResponseFileForLibs, depends,
+ cmMakefileTargetGenerator::ResponseFlagFor::DeviceLink);
// Construct object file lists that may be needed to expand the
// rule.
std::string buildObjs;
- this->CreateObjectLists(useLinkScript, false, // useArchiveRules
- useResponseFileForObjects, buildObjs, depends,
- false);
+ this->CreateObjectLists(
+ useLinkScript, false, // useArchiveRules
+ useResponseFileForObjects, buildObjs, depends, false,
+ cmMakefileTargetGenerator::ResponseFlagFor::DeviceLink);
std::string objectDir = this->GeneratorTarget->GetSupportDirectory();
objectDir = this->LocalGenerator->ConvertToOutputFormat(
diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx
index aec6577..1e1df79 100644
--- a/Source/cmMakefileTargetGenerator.cxx
+++ b/Source/cmMakefileTargetGenerator.cxx
@@ -21,6 +21,7 @@
#include "cmComputeLinkInformation.h"
#include "cmCustomCommand.h"
#include "cmCustomCommandGenerator.h"
+#include "cmFileSet.h"
#include "cmGeneratedFileStream.h"
#include "cmGeneratorExpression.h"
#include "cmGeneratorTarget.h"
@@ -46,6 +47,7 @@
#include "cmStateTypes.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
+#include "cmTarget.h"
#include "cmValue.h"
#include "cmake.h"
@@ -107,7 +109,7 @@ std::unique_ptr<cmMakefileTargetGenerator> cmMakefileTargetGenerator::New(
return result;
}
-std::string cmMakefileTargetGenerator::GetConfigName()
+std::string cmMakefileTargetGenerator::GetConfigName() const
{
auto const& configNames = this->LocalGenerator->GetConfigNames();
assert(configNames.size() == 1);
@@ -190,6 +192,16 @@ void cmMakefileTargetGenerator::CreateRuleFile()
void cmMakefileTargetGenerator::WriteTargetBuildRules()
{
+ this->GeneratorTarget->CheckCxxModuleStatus(this->GetConfigName());
+
+ if (this->GeneratorTarget->HaveCxx20ModuleSources()) {
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat("The \"", this->GeneratorTarget->GetName(),
+ "\" target contains C++ module sources which are not supported "
+ "by the generator"));
+ }
+
// -- Write the custom commands for this target
// Evaluates generator expressions and expands prop_value
@@ -302,6 +314,40 @@ void cmMakefileTargetGenerator::WriteTargetBuildRules()
}
}
+ std::map<std::string, std::string> file_set_map;
+
+ auto const* tgt = this->GeneratorTarget->Target;
+ for (auto const& name : tgt->GetAllFileSetNames()) {
+ auto const* file_set = tgt->GetFileSet(name);
+ if (!file_set) {
+ this->Makefile->IssueMessage(
+ MessageType::INTERNAL_ERROR,
+ cmStrCat("Target \"", tgt->GetName(),
+ "\" is tracked to have file set \"", name,
+ "\", but it was not found."));
+ continue;
+ }
+
+ auto fileEntries = file_set->CompileFileEntries();
+ auto directoryEntries = file_set->CompileDirectoryEntries();
+ auto directories = file_set->EvaluateDirectoryEntries(
+ directoryEntries, this->LocalGenerator, this->GetConfigName(),
+ this->GeneratorTarget);
+
+ std::map<std::string, std::vector<std::string>> files;
+ for (auto const& entry : fileEntries) {
+ file_set->EvaluateFileEntry(directories, files, entry,
+ this->LocalGenerator, this->GetConfigName(),
+ this->GeneratorTarget);
+ }
+
+ for (auto const& it : files) {
+ for (auto const& filename : it.second) {
+ file_set_map[filename] = file_set->GetType();
+ }
+ }
+ }
+
std::vector<cmSourceFile const*> objectSources;
this->GeneratorTarget->GetObjectSources(objectSources,
this->GetConfigName());
@@ -314,6 +360,25 @@ void cmMakefileTargetGenerator::WriteTargetBuildRules()
this->WriteObjectRuleFiles(*sf);
}
}
+
+ for (cmSourceFile const* sf : objectSources) {
+ auto const& path = sf->GetFullPath();
+ auto const it = file_set_map.find(path);
+ if (it != file_set_map.end()) {
+ auto const& file_set_type = it->second;
+ if (file_set_type == "CXX_MODULES"_s ||
+ file_set_type == "CXX_MODULE_HEADER_UNITS"_s) {
+ if (sf->GetLanguage() != "CXX"_s) {
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat(
+ "Target \"", tgt->GetName(), "\" contains the source\n ", path,
+ "\nin a file set of type \"", file_set_type,
+ R"(" but the source is not classified as a "CXX" source.)"));
+ }
+ }
+ }
+ }
}
void cmMakefileTargetGenerator::WriteCommonCodeRules()
@@ -2080,7 +2145,7 @@ bool cmMakefileTargetGenerator::CheckUseResponseFileForLibraries(
}
std::string cmMakefileTargetGenerator::CreateResponseFile(
- const char* name, std::string const& options,
+ const std::string& name, std::string const& options,
std::vector<std::string>& makefile_depends)
{
// FIXME: Find a better way to determine the response file encoding,
@@ -2126,7 +2191,8 @@ cmMakefileTargetGenerator::CreateLinkLineComputer(
void cmMakefileTargetGenerator::CreateLinkLibs(
cmLinkLineComputer* linkLineComputer, std::string& linkLibs,
- bool useResponseFile, std::vector<std::string>& makefile_depends)
+ bool useResponseFile, std::vector<std::string>& makefile_depends,
+ ResponseFlagFor responseMode)
{
std::string frameworkPath;
std::string linkPath;
@@ -2139,20 +2205,13 @@ void cmMakefileTargetGenerator::CreateLinkLibs(
if (useResponseFile &&
linkLibs.find_first_not_of(' ') != std::string::npos) {
// Lookup the response file reference flag.
- std::string responseFlagVar =
- cmStrCat("CMAKE_",
- this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName()),
- "_RESPONSE_FILE_LINK_FLAG");
- std::string responseFlag;
- if (cmValue p = this->Makefile->GetDefinition(responseFlagVar)) {
- responseFlag = *p;
- } else {
- responseFlag = "@";
- }
+ std::string responseFlag = this->GetResponseFlag(responseMode);
// Create this response file.
+ std::string responseFileName =
+ (responseMode == Link) ? "linkLibs.rsp" : "deviceLinkLibs.rsp";
std::string link_rsp =
- this->CreateResponseFile("linklibs.rsp", linkLibs, makefile_depends);
+ this->CreateResponseFile(responseFileName, linkLibs, makefile_depends);
// Reference the response file.
linkLibs = cmStrCat(responseFlag,
@@ -2164,7 +2223,7 @@ void cmMakefileTargetGenerator::CreateLinkLibs(
void cmMakefileTargetGenerator::CreateObjectLists(
bool useLinkScript, bool useArchiveRules, bool useResponseFile,
std::string& buildObjs, std::vector<std::string>& makefile_depends,
- bool useWatcomQuote)
+ bool useWatcomQuote, ResponseFlagFor responseMode)
{
std::string variableName;
std::string variableNameExternal;
@@ -2179,27 +2238,19 @@ void cmMakefileTargetGenerator::CreateObjectLists(
this->WriteObjectsStrings(object_strings, responseFileLimit);
// Lookup the response file reference flag.
- std::string responseFlagVar =
- cmStrCat("CMAKE_",
- this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName()),
- "_RESPONSE_FILE_LINK_FLAG");
- std::string responseFlag;
- if (cmValue p = this->Makefile->GetDefinition(responseFlagVar)) {
- responseFlag = *p;
- } else {
- responseFlag = "@";
- }
+ std::string responseFlag = this->GetResponseFlag(responseMode);
// Write a response file for each string.
const char* sep = "";
for (unsigned int i = 0; i < object_strings.size(); ++i) {
// Number the response files.
- char rsp[32];
- snprintf(rsp, sizeof(rsp), "objects%u.rsp", i + 1);
+ std::string responseFileName =
+ (responseMode == Link) ? "objects" : "deviceObjects";
+ responseFileName += std::to_string(i + 1);
// Create this response file.
- std::string objects_rsp =
- this->CreateResponseFile(rsp, object_strings[i], makefile_depends);
+ std::string objects_rsp = this->CreateResponseFile(
+ responseFileName, object_strings[i], makefile_depends);
// Separate from previous response file references.
buildObjs += sep;
@@ -2251,7 +2302,7 @@ void cmMakefileTargetGenerator::AddIncludeFlags(std::string& flags,
}
std::string name = cmStrCat("includes_", lang, ".rsp");
std::string arg = std::move(responseFlag) +
- this->CreateResponseFile(name.c_str(), includeFlags,
+ this->CreateResponseFile(name, includeFlags,
this->FlagFileDepends[lang]);
this->LocalGenerator->AppendFlags(flags, arg);
} else {
@@ -2304,3 +2355,22 @@ void cmMakefileTargetGenerator::GenDefFile(
fout << src->GetFullPath() << "\n";
}
}
+
+std::string cmMakefileTargetGenerator::GetResponseFlag(
+ ResponseFlagFor mode) const
+{
+ std::string responseFlag = "@";
+ std::string responseFlagVar;
+
+ auto lang = this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName());
+ if (mode == cmMakefileTargetGenerator::ResponseFlagFor::Link) {
+ responseFlagVar = cmStrCat("CMAKE_", lang, "_RESPONSE_FILE_LINK_FLAG");
+ } else if (mode == cmMakefileTargetGenerator::ResponseFlagFor::DeviceLink) {
+ responseFlagVar = "CMAKE_CUDA_RESPONSE_FILE_DEVICE_LINK_FLAG";
+ }
+
+ if (cmValue p = this->Makefile->GetDefinition(responseFlagVar)) {
+ responseFlag = *p;
+ }
+ return responseFlag;
+}
diff --git a/Source/cmMakefileTargetGenerator.h b/Source/cmMakefileTargetGenerator.h
index cb804e0..dafa650 100644
--- a/Source/cmMakefileTargetGenerator.h
+++ b/Source/cmMakefileTargetGenerator.h
@@ -56,7 +56,7 @@ public:
cmGeneratorTarget* GetGeneratorTarget() { return this->GeneratorTarget; }
- std::string GetConfigName();
+ std::string GetConfigName() const;
protected:
void GetDeviceLinkFlags(std::string& linkFlags,
@@ -157,22 +157,31 @@ protected:
/** Create a response file with the given set of options. Returns
the relative path from the target build working directory to the
response file name. */
- std::string CreateResponseFile(const char* name, std::string const& options,
+ std::string CreateResponseFile(const std::string& name,
+ std::string const& options,
std::vector<std::string>& makefile_depends);
bool CheckUseResponseFileForObjects(std::string const& l) const;
bool CheckUseResponseFileForLibraries(std::string const& l) const;
+ enum ResponseFlagFor
+ {
+ Link,
+ DeviceLink
+ };
+
/** Create list of flags for link libraries. */
void CreateLinkLibs(cmLinkLineComputer* linkLineComputer,
std::string& linkLibs, bool useResponseFile,
- std::vector<std::string>& makefile_depends);
+ std::vector<std::string>& makefile_depends,
+ ResponseFlagFor responseMode = ResponseFlagFor::Link);
/** Create lists of object files for linking and cleaning. */
void CreateObjectLists(bool useLinkScript, bool useArchiveRules,
bool useResponseFile, std::string& buildObjs,
std::vector<std::string>& makefile_depends,
- bool useWatcomQuote);
+ bool useWatcomQuote,
+ ResponseFlagFor responseMode = ResponseFlagFor::Link);
/** Add commands for generate def files */
void GenDefFile(std::vector<std::string>& real_link_commands);
@@ -180,6 +189,9 @@ protected:
void AddIncludeFlags(std::string& flags, const std::string& lang,
const std::string& config) override;
+ /** Return the response flag for the given configuration */
+ std::string GetResponseFlag(ResponseFlagFor mode) const;
+
virtual void CloseFileStreams();
cmLocalUnixMakefileGenerator3* LocalGenerator;
cmGlobalUnixMakefileGenerator3* GlobalGenerator;
diff --git a/Source/cmMessageCommand.cxx b/Source/cmMessageCommand.cxx
index cd57600..fa29ec9 100644
--- a/Source/cmMessageCommand.cxx
+++ b/Source/cmMessageCommand.cxx
@@ -81,94 +81,83 @@ bool cmMessageCommand(std::vector<std::string> const& args,
auto type = MessageType::MESSAGE;
auto fatal = false;
- auto level = cmake::LogLevel::LOG_UNDEFINED;
+ auto level = Message::LogLevel::LOG_UNDEFINED;
auto checkingType = CheckingType::UNDEFINED;
if (*i == "SEND_ERROR") {
type = MessageType::FATAL_ERROR;
- level = cmake::LogLevel::LOG_ERROR;
+ level = Message::LogLevel::LOG_ERROR;
++i;
} else if (*i == "FATAL_ERROR") {
fatal = true;
type = MessageType::FATAL_ERROR;
- level = cmake::LogLevel::LOG_ERROR;
+ level = Message::LogLevel::LOG_ERROR;
++i;
} else if (*i == "WARNING") {
type = MessageType::WARNING;
- level = cmake::LogLevel::LOG_WARNING;
+ level = Message::LogLevel::LOG_WARNING;
++i;
} else if (*i == "AUTHOR_WARNING") {
if (mf.IsSet("CMAKE_SUPPRESS_DEVELOPER_ERRORS") &&
!mf.IsOn("CMAKE_SUPPRESS_DEVELOPER_ERRORS")) {
fatal = true;
type = MessageType::AUTHOR_ERROR;
- level = cmake::LogLevel::LOG_ERROR;
+ level = Message::LogLevel::LOG_ERROR;
} else if (!mf.IsOn("CMAKE_SUPPRESS_DEVELOPER_WARNINGS")) {
type = MessageType::AUTHOR_WARNING;
- level = cmake::LogLevel::LOG_WARNING;
+ level = Message::LogLevel::LOG_WARNING;
} else {
return true;
}
++i;
} else if (*i == "CHECK_START") {
- level = cmake::LogLevel::LOG_STATUS;
+ level = Message::LogLevel::LOG_STATUS;
checkingType = CheckingType::CHECK_START;
++i;
} else if (*i == "CHECK_PASS") {
- level = cmake::LogLevel::LOG_STATUS;
+ level = Message::LogLevel::LOG_STATUS;
checkingType = CheckingType::CHECK_PASS;
++i;
} else if (*i == "CHECK_FAIL") {
- level = cmake::LogLevel::LOG_STATUS;
+ level = Message::LogLevel::LOG_STATUS;
checkingType = CheckingType::CHECK_FAIL;
++i;
} else if (*i == "STATUS") {
- level = cmake::LogLevel::LOG_STATUS;
+ level = Message::LogLevel::LOG_STATUS;
++i;
} else if (*i == "VERBOSE") {
- level = cmake::LogLevel::LOG_VERBOSE;
+ level = Message::LogLevel::LOG_VERBOSE;
++i;
} else if (*i == "DEBUG") {
- level = cmake::LogLevel::LOG_DEBUG;
+ level = Message::LogLevel::LOG_DEBUG;
++i;
} else if (*i == "TRACE") {
- level = cmake::LogLevel::LOG_TRACE;
+ level = Message::LogLevel::LOG_TRACE;
++i;
} else if (*i == "DEPRECATION") {
if (mf.IsOn("CMAKE_ERROR_DEPRECATED")) {
fatal = true;
type = MessageType::DEPRECATION_ERROR;
- level = cmake::LogLevel::LOG_ERROR;
+ level = Message::LogLevel::LOG_ERROR;
} else if (!mf.IsSet("CMAKE_WARN_DEPRECATED") ||
mf.IsOn("CMAKE_WARN_DEPRECATED")) {
type = MessageType::DEPRECATION_WARNING;
- level = cmake::LogLevel::LOG_WARNING;
+ level = Message::LogLevel::LOG_WARNING;
} else {
return true;
}
++i;
} else if (*i == "NOTICE") {
// `NOTICE` message type is going to be output to stderr
- level = cmake::LogLevel::LOG_NOTICE;
+ level = Message::LogLevel::LOG_NOTICE;
++i;
} else {
// Messages w/o any type are `NOTICE`s
- level = cmake::LogLevel::LOG_NOTICE;
+ level = Message::LogLevel::LOG_NOTICE;
}
assert("Message log level expected to be set" &&
- level != cmake::LogLevel::LOG_UNDEFINED);
-
- auto desiredLevel = mf.GetCMakeInstance()->GetLogLevel();
- assert("Expected a valid log level here" &&
- desiredLevel != cmake::LogLevel::LOG_UNDEFINED);
-
- // Command line option takes precedence over the cache variable
- if (!mf.GetCMakeInstance()->WasLogLevelSetViaCLI()) {
- const auto desiredLevelFromCache =
- cmake::StringToLogLevel(mf.GetSafeDefinition("CMAKE_MESSAGE_LOG_LEVEL"));
- if (desiredLevelFromCache != cmake::LogLevel::LOG_UNDEFINED) {
- desiredLevel = desiredLevelFromCache;
- }
- }
+ level != Message::LogLevel::LOG_UNDEFINED);
+
+ Message::LogLevel desiredLevel = mf.GetCurrentLogLevel();
if (desiredLevel < level) {
// Suppress the message
@@ -178,17 +167,17 @@ bool cmMessageCommand(std::vector<std::string> const& args,
auto message = cmJoin(cmMakeRange(i, args.cend()), "");
switch (level) {
- case cmake::LogLevel::LOG_ERROR:
- case cmake::LogLevel::LOG_WARNING:
+ case Message::LogLevel::LOG_ERROR:
+ case Message::LogLevel::LOG_WARNING:
// we've overridden the message type, above, so display it directly
mf.GetMessenger()->DisplayMessage(type, message, mf.GetBacktrace());
break;
- case cmake::LogLevel::LOG_NOTICE:
+ case Message::LogLevel::LOG_NOTICE:
cmSystemTools::Message(IndentText(message, mf));
break;
- case cmake::LogLevel::LOG_STATUS:
+ case Message::LogLevel::LOG_STATUS:
switch (checkingType) {
case CheckingType::CHECK_START:
mf.DisplayStatus(IndentText(message, mf), -1);
@@ -209,9 +198,9 @@ bool cmMessageCommand(std::vector<std::string> const& args,
}
break;
- case cmake::LogLevel::LOG_VERBOSE:
- case cmake::LogLevel::LOG_DEBUG:
- case cmake::LogLevel::LOG_TRACE:
+ case Message::LogLevel::LOG_VERBOSE:
+ case Message::LogLevel::LOG_DEBUG:
+ case Message::LogLevel::LOG_TRACE:
mf.DisplayStatus(IndentText(message, mf), -1);
break;
diff --git a/Source/cmMessageType.h b/Source/cmMessageType.h
index 44de429..decb4b3 100644
--- a/Source/cmMessageType.h
+++ b/Source/cmMessageType.h
@@ -16,3 +16,19 @@ enum class MessageType
DEPRECATION_ERROR,
DEPRECATION_WARNING
};
+
+namespace Message {
+
+/** \brief Define log level constants. */
+enum class LogLevel
+{
+ LOG_UNDEFINED,
+ LOG_ERROR,
+ LOG_WARNING,
+ LOG_NOTICE,
+ LOG_STATUS,
+ LOG_VERBOSE,
+ LOG_DEBUG,
+ LOG_TRACE
+};
+}
diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx
index d4f1608..42f0329 100644
--- a/Source/cmNinjaNormalTargetGenerator.cxx
+++ b/Source/cmNinjaNormalTargetGenerator.cxx
@@ -537,7 +537,6 @@ std::vector<std::string> cmNinjaNormalTargetGenerator::ComputeDeviceLinkCmd()
// this target requires separable cuda compilation
// now build the correct command depending on if the target is
// an executable or a dynamic library.
- std::string linkCmd;
switch (this->GetGeneratorTarget()->GetType()) {
case cmStateEnums::STATIC_LIBRARY:
case cmStateEnums::SHARED_LIBRARY:
diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx
index 3fac7f5..a4080d8 100644
--- a/Source/cmNinjaTargetGenerator.cxx
+++ b/Source/cmNinjaTargetGenerator.cxx
@@ -21,11 +21,17 @@
#include "cmComputeLinkInformation.h"
#include "cmCustomCommandGenerator.h"
+#include "cmExportBuildFileGenerator.h"
+#include "cmExportSet.h"
#include "cmFileSet.h"
#include "cmGeneratedFileStream.h"
#include "cmGeneratorExpression.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalNinjaGenerator.h"
+#include "cmInstallCxxModuleBmiGenerator.h"
+#include "cmInstallExportGenerator.h"
+#include "cmInstallFileSetGenerator.h"
+#include "cmInstallGenerator.h"
#include "cmLocalGenerator.h"
#include "cmLocalNinjaGenerator.h"
#include "cmMakefile.h"
@@ -36,12 +42,12 @@
#include "cmRange.h"
#include "cmRulePlaceholderExpander.h"
#include "cmSourceFile.h"
-#include "cmStandardLevelResolver.h"
#include "cmState.h"
#include "cmStateTypes.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
#include "cmTarget.h"
+#include "cmTargetExport.h"
#include "cmValue.h"
#include "cmake.h"
@@ -153,17 +159,12 @@ std::string cmNinjaTargetGenerator::LanguageDyndepRule(
bool cmNinjaTargetGenerator::NeedCxxModuleSupport(
std::string const& lang, std::string const& config) const
{
- if (lang != "CXX") {
+ if (lang != "CXX"_s) {
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();
+ return this->GetGeneratorTarget()->HaveCxxModuleSupport(config) ==
+ cmGeneratorTarget::Cxx20SupportLevel::Supported &&
+ this->GetGlobalGenerator()->CheckCxxModuleSupport();
}
bool cmNinjaTargetGenerator::NeedDyndep(std::string const& lang,
@@ -255,51 +256,53 @@ std::string cmNinjaTargetGenerator::ComputeFlagsForObject(
flags, genexInterpreter.Evaluate(pchOptions, COMPILE_OPTIONS));
}
- if (this->NeedCxxModuleSupport(language, config)) {
- auto const& path = source->GetFullPath();
- auto const* tgt = this->GeneratorTarget->Target;
+ auto const& path = source->GetFullPath();
+ auto const* tgt = this->GeneratorTarget->Target;
- std::string file_set_type;
+ std::string file_set_type;
- for (auto const& name : tgt->GetAllFileSetNames()) {
- auto const* file_set = tgt->GetFileSet(name);
- if (!file_set) {
- this->GetMakefile()->IssueMessage(
- MessageType::INTERNAL_ERROR,
- cmStrCat("Target `", tgt->GetName(),
- "` is tracked to have file set `", name,
- "`, but it was not found."));
- continue;
- }
+ for (auto const& name : tgt->GetAllFileSetNames()) {
+ auto const* file_set = tgt->GetFileSet(name);
+ if (!file_set) {
+ this->GetMakefile()->IssueMessage(
+ MessageType::INTERNAL_ERROR,
+ cmStrCat("Target \"", tgt->GetName(),
+ "\" is tracked to have file set \"", name,
+ "\", but it was not found."));
+ continue;
+ }
- auto fileEntries = file_set->CompileFileEntries();
- auto directoryEntries = file_set->CompileDirectoryEntries();
- auto directories = file_set->EvaluateDirectoryEntries(
- directoryEntries, this->LocalGenerator, config, this->GeneratorTarget);
+ auto fileEntries = file_set->CompileFileEntries();
+ auto directoryEntries = file_set->CompileDirectoryEntries();
+ auto directories = file_set->EvaluateDirectoryEntries(
+ directoryEntries, this->LocalGenerator, config, this->GeneratorTarget);
- std::map<std::string, std::vector<std::string>> files;
- for (auto const& entry : fileEntries) {
- file_set->EvaluateFileEntry(directories, files, entry,
- this->LocalGenerator, config,
- this->GeneratorTarget);
- }
+ std::map<std::string, std::vector<std::string>> files;
+ for (auto const& entry : fileEntries) {
+ file_set->EvaluateFileEntry(directories, files, entry,
+ this->LocalGenerator, config,
+ this->GeneratorTarget);
+ }
- for (auto const& it : files) {
- for (auto const& filename : it.second) {
- if (filename == path) {
- file_set_type = file_set->GetType();
- break;
- }
+ for (auto const& it : files) {
+ for (auto const& filename : it.second) {
+ if (filename == path) {
+ file_set_type = file_set->GetType();
+ break;
}
}
+ }
- if (!file_set_type.empty()) {
- std::string source_type_var = cmStrCat(
- "CMAKE_EXPERIMENTAL_CXX_MODULE_SOURCE_TYPE_FLAG_", file_set_type);
- cmMakefile* mf = this->GetMakefile();
- if (cmValue source_type_flag = mf->GetDefinition(source_type_var)) {
- this->LocalGenerator->AppendFlags(flags, *source_type_flag);
- }
+ if (file_set_type == "CXX_MODULES"_s ||
+ file_set_type == "CXX_MODULE_HEADER_UNITS"_s) {
+ if (source->GetLanguage() != "CXX"_s) {
+ this->GetMakefile()->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat(
+ "Target \"", tgt->GetName(), "\" contains the source\n ", path,
+ "\nin a file set of type \"", file_set_type,
+ R"(" but the source is not classified as a "CXX" source.)"));
+ continue;
}
}
}
@@ -1038,6 +1041,8 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatements(
const std::string& config, const std::string& fileConfig,
bool firstForConfig)
{
+ this->GeneratorTarget->CheckCxxModuleStatus(config);
+
// Write comments.
cmGlobalNinjaGenerator::WriteDivider(this->GetImplFileStream(fileConfig));
this->GetImplFileStream(fileConfig)
@@ -1338,9 +1343,11 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
}
}
- this->ExportObjectCompileCommand(
- language, sourceFilePath, objectDir, objectFileName, objectFileDir,
- vars["FLAGS"], vars["DEFINES"], vars["INCLUDES"], config);
+ if (firstForConfig) {
+ this->ExportObjectCompileCommand(
+ language, sourceFilePath, objectDir, objectFileName, objectFileDir,
+ vars["FLAGS"], vars["DEFINES"], vars["INCLUDES"], config);
+ }
objBuild.Outputs.push_back(objectFileName);
if (firstForConfig) {
@@ -1616,8 +1623,9 @@ void cmNinjaTargetGenerator::WriteTargetDependInfo(std::string const& lang,
mod_dir = this->GeneratorTarget->GetFortranModuleDirectory(
this->Makefile->GetHomeOutputDirectory());
} else if (lang == "CXX") {
- mod_dir =
- cmSystemTools::CollapseFullPath(this->GeneratorTarget->ObjectDirectory);
+ mod_dir = this->GetGlobalGenerator()->ExpandCFGIntDir(
+ cmSystemTools::CollapseFullPath(this->GeneratorTarget->ObjectDirectory),
+ config);
}
if (mod_dir.empty()) {
mod_dir = this->Makefile->GetCurrentBinaryDirectory();
@@ -1654,6 +1662,215 @@ void cmNinjaTargetGenerator::WriteTargetDependInfo(std::string const& lang,
tdi_linked_target_dirs.append(l);
}
+ cmTarget* tgt = this->GeneratorTarget->Target;
+ auto all_file_sets = tgt->GetAllFileSetNames();
+ Json::Value& tdi_cxx_module_info = tdi["cxx-modules"] = Json::objectValue;
+ for (auto const& file_set_name : all_file_sets) {
+ auto* file_set = tgt->GetFileSet(file_set_name);
+ if (!file_set) {
+ this->GetMakefile()->IssueMessage(
+ MessageType::INTERNAL_ERROR,
+ cmStrCat("Target \"", tgt->GetName(),
+ "\" is tracked to have file set \"", file_set_name,
+ "\", but it was not found."));
+ continue;
+ }
+ auto fs_type = file_set->GetType();
+ // We only care about C++ module sources here.
+ if (fs_type != "CXX_MODULES"_s) {
+ continue;
+ }
+
+ auto fileEntries = file_set->CompileFileEntries();
+ auto directoryEntries = file_set->CompileDirectoryEntries();
+
+ auto directories = file_set->EvaluateDirectoryEntries(
+ directoryEntries, this->GeneratorTarget->LocalGenerator, config,
+ this->GeneratorTarget);
+ std::map<std::string, std::vector<std::string>> files_per_dirs;
+ for (auto const& entry : fileEntries) {
+ file_set->EvaluateFileEntry(directories, files_per_dirs, entry,
+ this->GeneratorTarget->LocalGenerator,
+ config, this->GeneratorTarget);
+ }
+
+ std::map<std::string, cmSourceFile const*> sf_map;
+ {
+ std::vector<cmSourceFile const*> objectSources;
+ this->GeneratorTarget->GetObjectSources(objectSources, config);
+ for (auto const* sf : objectSources) {
+ auto full_path = sf->GetFullPath();
+ if (full_path.empty()) {
+ this->GetMakefile()->IssueMessage(
+ MessageType::INTERNAL_ERROR,
+ cmStrCat("Target \"", tgt->GetName(),
+ "\" has a full path-less source file."));
+ continue;
+ }
+ sf_map[full_path] = sf;
+ }
+ }
+
+ Json::Value fs_dest = Json::nullValue;
+ for (auto const& ig : this->GetMakefile()->GetInstallGenerators()) {
+ if (auto const* fsg =
+ dynamic_cast<cmInstallFileSetGenerator const*>(ig.get())) {
+ if (fsg->GetTarget() == this->GeneratorTarget &&
+ fsg->GetFileSet() == file_set) {
+ fs_dest = fsg->GetDestination(config);
+ continue;
+ }
+ }
+ }
+
+ for (auto const& files_per_dir : files_per_dirs) {
+ for (auto const& file : files_per_dir.second) {
+ auto lookup = sf_map.find(file);
+ if (lookup == sf_map.end()) {
+ this->GetMakefile()->IssueMessage(
+ MessageType::INTERNAL_ERROR,
+ cmStrCat("Target \"", tgt->GetName(), "\" has source file \"",
+ file,
+ R"(" which is not in any of its "FILE_SET BASE_DIRS".)"));
+ continue;
+ }
+
+ auto const* sf = lookup->second;
+
+ if (!sf) {
+ this->GetMakefile()->IssueMessage(
+ MessageType::INTERNAL_ERROR,
+ cmStrCat("Target \"", tgt->GetName(), "\" has source file \"",
+ file, "\" which has not been tracked properly."));
+ continue;
+ }
+
+ auto obj_path = this->GetObjectFilePath(sf, config);
+ Json::Value& tdi_module_info = tdi_cxx_module_info[obj_path] =
+ Json::objectValue;
+
+ tdi_module_info["source"] = file;
+ tdi_module_info["relative-directory"] = files_per_dir.first;
+ tdi_module_info["name"] = file_set->GetName();
+ tdi_module_info["type"] = file_set->GetType();
+ tdi_module_info["visibility"] =
+ std::string(cmFileSetVisibilityToName(file_set->GetVisibility()));
+ tdi_module_info["destination"] = fs_dest;
+ }
+ }
+ }
+
+ tdi["config"] = config;
+
+ // Add information about the export sets that this target is a member of.
+ Json::Value& tdi_exports = tdi["exports"] = Json::arrayValue;
+ std::string export_name = this->GeneratorTarget->GetExportName();
+
+ cmInstallCxxModuleBmiGenerator const* bmi_gen = nullptr;
+ for (auto const& ig : this->GetMakefile()->GetInstallGenerators()) {
+ if (auto const* bmig =
+ dynamic_cast<cmInstallCxxModuleBmiGenerator const*>(ig.get())) {
+ if (bmig->GetTarget() == this->GeneratorTarget) {
+ bmi_gen = bmig;
+ continue;
+ }
+ }
+ }
+ if (bmi_gen) {
+ Json::Value tdi_bmi_info = Json::objectValue;
+
+ tdi_bmi_info["permissions"] = bmi_gen->GetFilePermissions();
+ tdi_bmi_info["destination"] = bmi_gen->GetDestination(config);
+ const char* msg_level = "";
+ switch (bmi_gen->GetMessageLevel()) {
+ case cmInstallGenerator::MessageDefault:
+ break;
+ case cmInstallGenerator::MessageAlways:
+ msg_level = "MESSAGE_ALWAYS";
+ break;
+ case cmInstallGenerator::MessageLazy:
+ msg_level = "MESSAGE_LAZY";
+ break;
+ case cmInstallGenerator::MessageNever:
+ msg_level = "MESSAGE_NEVER";
+ break;
+ }
+ tdi_bmi_info["message-level"] = msg_level;
+ tdi_bmi_info["script-location"] = bmi_gen->GetScriptLocation(config);
+
+ tdi["bmi-installation"] = tdi_bmi_info;
+ } else {
+ tdi["bmi-installation"] = Json::nullValue;
+ }
+
+ auto const& all_install_exports =
+ this->GetGlobalGenerator()->GetExportSets();
+ for (auto const& exp : all_install_exports) {
+ // Ignore exports sets which are not for this target.
+ auto const& targets = exp.second.GetTargetExports();
+ auto tgt_export =
+ std::find_if(targets.begin(), targets.end(),
+ [this](std::unique_ptr<cmTargetExport> const& te) {
+ return te->Target == this->GeneratorTarget;
+ });
+ if (tgt_export == targets.end()) {
+ continue;
+ }
+
+ auto const* installs = exp.second.GetInstallations();
+ for (auto const* install : *installs) {
+ Json::Value tdi_export_info = Json::objectValue;
+
+ auto const& ns = install->GetNamespace();
+ auto const& dest = install->GetDestination();
+ auto const& cxxm_dir = install->GetCxxModuleDirectory();
+ auto const& export_prefix = install->GetTempDir();
+
+ tdi_export_info["namespace"] = ns;
+ tdi_export_info["export-name"] = export_name;
+ tdi_export_info["destination"] = dest;
+ tdi_export_info["cxx-module-info-dir"] = cxxm_dir;
+ tdi_export_info["export-prefix"] = export_prefix;
+ tdi_export_info["install"] = true;
+
+ tdi_exports.append(tdi_export_info);
+ }
+ }
+
+ auto const& all_build_exports =
+ this->GetMakefile()->GetExportBuildFileGenerators();
+ for (auto const& exp : all_build_exports) {
+ std::vector<std::string> targets;
+ exp->GetTargets(targets);
+
+ // Ignore exports sets which are not for this target.
+ auto const& name = this->GeneratorTarget->GetName();
+ bool has_current_target =
+ std::any_of(targets.begin(), targets.end(),
+ [name](std::string const& tname) { return tname == name; });
+ if (!has_current_target) {
+ continue;
+ }
+
+ Json::Value tdi_export_info = Json::objectValue;
+
+ auto const& ns = exp->GetNamespace();
+ auto const& main_fn = exp->GetMainExportFileName();
+ auto const& cxxm_dir = exp->GetCxxModuleDirectory();
+ auto dest = cmsys::SystemTools::GetParentDirectory(main_fn);
+ auto const& export_prefix =
+ cmSystemTools::GetFilenamePath(exp->GetMainExportFileName());
+
+ tdi_export_info["namespace"] = ns;
+ tdi_export_info["export-name"] = export_name;
+ tdi_export_info["destination"] = dest;
+ tdi_export_info["cxx-module-info-dir"] = cxxm_dir;
+ tdi_export_info["export-prefix"] = export_prefix;
+ tdi_export_info["install"] = false;
+
+ tdi_exports.append(tdi_export_info);
+ }
+
std::string const tdin = this->GetTargetDependInfoPath(lang, config);
cmGeneratedFileStream tdif(tdin);
tdif << tdi;
diff --git a/Source/cmParseArgumentsCommand.cxx b/Source/cmParseArgumentsCommand.cxx
index 95f3e7e..7e19566 100644
--- a/Source/cmParseArgumentsCommand.cxx
+++ b/Source/cmParseArgumentsCommand.cxx
@@ -10,6 +10,7 @@
#include <cm/string_view>
#include "cmArgumentParser.h"
+#include "cmArgumentParserTypes.h"
#include "cmExecutionStatus.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
@@ -41,11 +42,18 @@ namespace {
using options_map = std::map<std::string, bool>;
using single_map = std::map<std::string, std::string>;
-using multi_map = std::map<std::string, std::vector<std::string>>;
-using options_set = std::set<std::string>;
+using multi_map =
+ std::map<std::string, ArgumentParser::NonEmpty<std::vector<std::string>>>;
+using options_set = std::set<cm::string_view>;
struct UserArgumentParser : public cmArgumentParser<void>
{
+ void BindKeywordsMissingValue(std::vector<cm::string_view>& ref)
+ {
+ this->cmArgumentParser<void>::BindKeywordMissingValue(
+ [&ref](Instance&, cm::string_view arg) { ref.emplace_back(arg); });
+ }
+
template <typename T, typename H>
void Bind(std::vector<std::string> const& names,
std::map<std::string, T>& ref, H duplicateKey)
@@ -208,9 +216,10 @@ bool cmParseArgumentsCommand(std::vector<std::string> const& args,
}
}
- std::vector<std::string> keywordsMissingValues;
+ std::vector<cm::string_view> keywordsMissingValues;
+ parser.BindKeywordsMissingValue(keywordsMissingValues);
- parser.Parse(list, &unparsed, &keywordsMissingValues);
+ parser.Parse(list, &unparsed);
PassParsedArguments(
prefix, status.GetMakefile(), options, singleValArgs, multiValArgs,
diff --git a/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx
index 40f3ab5..6c500b0 100644
--- a/Source/cmQtAutoGenInitializer.cxx
+++ b/Source/cmQtAutoGenInitializer.cxx
@@ -1847,8 +1847,7 @@ void cmQtAutoGenInitializer::AddToSourceGroup(std::string const& fileName,
void cmQtAutoGenInitializer::AddCleanFile(std::string const& fileName)
{
- this->GenTarget->Target->AppendProperty("ADDITIONAL_CLEAN_FILES", fileName,
- false);
+ this->GenTarget->Target->AppendProperty("ADDITIONAL_CLEAN_FILES", fileName);
}
void cmQtAutoGenInitializer::ConfigFileNames(ConfigString& configString,
diff --git a/Source/cmQtAutoMocUic.cxx b/Source/cmQtAutoMocUic.cxx
index 8c09b56..8adaa6c 100644
--- a/Source/cmQtAutoMocUic.cxx
+++ b/Source/cmQtAutoMocUic.cxx
@@ -2183,6 +2183,9 @@ void cmQtAutoMocUicT::JobMocsCompilationT::Process()
content += "// No files found that require moc or the moc files are "
"included\n"
"void " +
+ functionName +
+ "();\n"
+ "void " +
functionName + "() {}\n";
} else {
// Valid content
diff --git a/Source/cmScanDepFormat.cxx b/Source/cmScanDepFormat.cxx
index 82a374a..ec53af5 100644
--- a/Source/cmScanDepFormat.cxx
+++ b/Source/cmScanDepFormat.cxx
@@ -5,6 +5,7 @@
#include <cctype>
#include <cstdio>
+#include <iostream>
#include <utility>
#include <cm/optional>
@@ -188,6 +189,19 @@ bool cmScanDepFormat_P1689_Parse(std::string const& arg_pp,
return false;
}
+ if (provide.isMember("is-interface")) {
+ Json::Value const& is_interface = provide["is-interface"];
+ if (!is_interface.isBool()) {
+ cmSystemTools::Error(
+ cmStrCat("-E cmake_ninja_dyndep failed to parse ", arg_pp,
+ ": is-interface is not a boolean"));
+ return false;
+ }
+ provide_info.IsInterface = is_interface.asBool();
+ } else {
+ provide_info.IsInterface = true;
+ }
+
info->Provides.push_back(provide_info);
}
}
@@ -267,6 +281,27 @@ bool cmScanDepFormat_P1689_Parse(std::string const& arg_pp,
info->Requires.push_back(require_info);
}
}
+
+ // MSVC 17.3 toolchain bug. Remove when 17.4 is available.
+ if (rule.isMember("is-interface")) {
+ std::cerr
+ << "warning: acknowledging an VS 17.3 toolchain bug; accepting "
+ "until a new release which fixes it is available"
+ << std::endl;
+
+ Json::Value const& is_interface_json = rule["is-interface"];
+ if (!is_interface_json.isBool()) {
+ cmSystemTools::Error(
+ cmStrCat("-E cmake_ninja_dyndep failed to parse ", arg_pp,
+ ": is-interface is not a boolean"));
+ return false;
+ }
+ bool is_interface = is_interface_json.asBool();
+
+ for (auto& provide : info->Provides) {
+ provide.IsInterface = is_interface;
+ }
+ }
}
}
@@ -308,6 +343,8 @@ bool cmScanDepFormat_P1689_Write(std::string const& path,
provide_obj["source-path"] = EncodeFilename(provide.SourcePath);
}
+ provide_obj["is-interface"] = provide.IsInterface;
+
provides.append(provide_obj);
}
diff --git a/Source/cmScanDepFormat.h b/Source/cmScanDepFormat.h
index dae28d9..dc55bf1 100644
--- a/Source/cmScanDepFormat.h
+++ b/Source/cmScanDepFormat.h
@@ -18,6 +18,11 @@ struct cmSourceReqInfo
std::string SourcePath;
std::string CompiledModulePath;
bool UseSourcePath = false;
+
+ // Provides-only fields.
+ bool IsInterface = true;
+
+ // Requires-only fields.
LookupMethod Method = LookupMethod::ByName;
};
diff --git a/Source/cmScriptGenerator.cxx b/Source/cmScriptGenerator.cxx
index 166ee56..32f9bec 100644
--- a/Source/cmScriptGenerator.cxx
+++ b/Source/cmScriptGenerator.cxx
@@ -133,7 +133,7 @@ void cmScriptGenerator::GenerateScriptActionsOnce(std::ostream& os,
std::string config_test = this->CreateConfigTest(this->Configurations);
os << indent << "if(" << config_test << ")\n";
this->GenerateScriptActions(os, indent.Next());
- os << indent << "endif(" << config_test << ")\n";
+ os << indent << "endif()\n";
}
}
diff --git a/Source/cmSetPropertyCommand.cxx b/Source/cmSetPropertyCommand.cxx
index db10cd4..521cf63 100644
--- a/Source/cmSetPropertyCommand.cxx
+++ b/Source/cmSetPropertyCommand.cxx
@@ -9,6 +9,7 @@
#include "cmExecutionStatus.h"
#include "cmGlobalGenerator.h"
#include "cmInstalledFile.h"
+#include "cmListFileCache.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmPolicies.h"
@@ -561,7 +562,8 @@ bool HandleTarget(cmTarget* target, cmMakefile& makefile,
{
// Set or append the property.
if (appendMode) {
- target->AppendProperty(propertyName, propertyValue, appendAsString);
+ target->AppendProperty(propertyName, propertyValue,
+ makefile.GetBacktrace(), appendAsString);
} else {
if (remove) {
target->SetProperty(propertyName, nullptr);
diff --git a/Source/cmSourceGroup.cxx b/Source/cmSourceGroup.cxx
index 155068cb..6019de1 100644
--- a/Source/cmSourceGroup.cxx
+++ b/Source/cmSourceGroup.cxx
@@ -124,6 +124,21 @@ cmSourceGroup* cmSourceGroup::MatchChildrenFiles(const std::string& name)
return nullptr;
}
+const cmSourceGroup* cmSourceGroup::MatchChildrenFiles(
+ const std::string& name) const
+{
+ if (this->MatchesFiles(name)) {
+ return this;
+ }
+ for (const cmSourceGroup& group : this->Internal->GroupChildren) {
+ const cmSourceGroup* result = group.MatchChildrenFiles(name);
+ if (result) {
+ return result;
+ }
+ }
+ return nullptr;
+}
+
cmSourceGroup* cmSourceGroup::MatchChildrenRegex(const std::string& name)
{
for (cmSourceGroup& group : this->Internal->GroupChildren) {
diff --git a/Source/cmSourceGroup.h b/Source/cmSourceGroup.h
index 295240d..9ce71c7 100644
--- a/Source/cmSourceGroup.h
+++ b/Source/cmSourceGroup.h
@@ -80,6 +80,12 @@ public:
cmSourceGroup* MatchChildrenFiles(const std::string& name);
/**
+ * Check if the given name matches this group's explicit file list
+ * in children.
+ */
+ const cmSourceGroup* MatchChildrenFiles(const std::string& name) const;
+
+ /**
* Check if the given name matches this group's regex in children.
*/
cmSourceGroup* MatchChildrenRegex(const std::string& name);
diff --git a/Source/cmStandardLevelResolver.cxx b/Source/cmStandardLevelResolver.cxx
index 785f356..be15288 100644
--- a/Source/cmStandardLevelResolver.cxx
+++ b/Source/cmStandardLevelResolver.cxx
@@ -18,6 +18,7 @@
#include "cmGeneratorExpression.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalGenerator.h"
+#include "cmListFileCache.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmPolicies.h"
@@ -416,7 +417,8 @@ bool cmStandardLevelResolver::AddRequiredTargetFeature(
cmTarget* target, const std::string& feature, std::string* error) const
{
if (cmGeneratorExpression::Find(feature) != std::string::npos) {
- target->AppendProperty("COMPILE_FEATURES", feature);
+ target->AppendProperty("COMPILE_FEATURES", feature,
+ this->Makefile->GetBacktrace());
return true;
}
@@ -426,7 +428,8 @@ bool cmStandardLevelResolver::AddRequiredTargetFeature(
return false;
}
- target->AppendProperty("COMPILE_FEATURES", feature);
+ target->AppendProperty("COMPILE_FEATURES", feature,
+ this->Makefile->GetBacktrace());
// FIXME: Add a policy to avoid updating the <LANG>_STANDARD target
// property due to COMPILE_FEATURES. The language standard selection
diff --git a/Source/cmStringCommand.cxx b/Source/cmStringCommand.cxx
index c3ee695..c12d1fe 100644
--- a/Source/cmStringCommand.cxx
+++ b/Source/cmStringCommand.cxx
@@ -143,7 +143,8 @@ bool HandleHexCommand(std::vector<std::string> const& args,
std::string::size_type hexIndex = 0;
for (auto const& c : instr) {
- sprintf(&output[hexIndex], "%.2x", static_cast<unsigned char>(c) & 0xFF);
+ snprintf(&output[hexIndex], 3, "%.2x",
+ static_cast<unsigned char>(c) & 0xFF);
hexIndex += 2;
}
@@ -1013,7 +1014,7 @@ int ParseIndex(
Json::ArrayIndex index = static_cast<Json::ArrayIndex>(lindex);
if (index >= max) {
cmAlphaNum sizeStr{ max };
- throw json_error({ "expected an index less then "_s, sizeStr.View(),
+ throw json_error({ "expected an index less than "_s, sizeStr.View(),
" got '"_s, str, "'"_s },
progress);
}
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx
index f077801..3c4e709 100644
--- a/Source/cmSystemTools.cxx
+++ b/Source/cmSystemTools.cxx
@@ -16,6 +16,7 @@
#include <cm/optional>
#include <cmext/algorithm>
+#include <cmext/string_view>
#include <cm3p/uv.h>
@@ -1256,7 +1257,7 @@ std::string cmSystemTools::ComputeCertificateThumbprint(
certContext, CERT_HASH_PROP_ID, hashData, &hashLength)) {
for (DWORD i = 0; i < hashLength; i++) {
// Convert each byte to hexadecimal
- sprintf(pHashPrint, "%02X", hashData[i]);
+ snprintf(pHashPrint, 3, "%02X", hashData[i]);
pHashPrint += 2;
}
*pHashPrint = '\0';
@@ -1539,8 +1540,7 @@ std::string cmSystemTools::RelativeIfUnder(std::string const& top,
bool cmSystemTools::UnsetEnv(const char* value)
{
# if !defined(HAVE_UNSETENV)
- std::string var = cmStrCat(value, '=');
- return cmSystemTools::PutEnv(var);
+ return cmSystemTools::UnPutEnv(value);
# else
unsetenv(value);
return true;
@@ -1564,6 +1564,144 @@ void cmSystemTools::AppendEnv(std::vector<std::string> const& env)
}
}
+void cmSystemTools::EnvDiff::AppendEnv(std::vector<std::string> const& env)
+{
+ for (std::string const& eit : env) {
+ this->PutEnv(eit);
+ }
+}
+
+void cmSystemTools::EnvDiff::PutEnv(const std::string& env)
+{
+ auto const eq_loc = env.find('=');
+ if (eq_loc != std::string::npos) {
+ std::string name = env.substr(0, eq_loc);
+ diff[name] = env.substr(eq_loc + 1);
+ } else {
+ this->UnPutEnv(env);
+ }
+}
+
+void cmSystemTools::EnvDiff::UnPutEnv(const std::string& env)
+{
+ diff[env] = {};
+}
+
+bool cmSystemTools::EnvDiff::ParseOperation(const std::string& envmod)
+{
+ char path_sep = GetSystemPathlistSeparator();
+
+ auto apply_diff = [this](const std::string& name,
+ std::function<void(std::string&)> const& apply) {
+ cm::optional<std::string> old_value = diff[name];
+ std::string output;
+ if (old_value) {
+ output = *old_value;
+ } else {
+ const char* curval = cmSystemTools::GetEnv(name);
+ if (curval) {
+ output = curval;
+ }
+ }
+ apply(output);
+ diff[name] = output;
+ };
+
+ // Split on `=`
+ auto const eq_loc = envmod.find_first_of('=');
+ if (eq_loc == std::string::npos) {
+ cmSystemTools::Error(cmStrCat(
+ "Error: Missing `=` after the variable name in: ", envmod, '\n'));
+ return false;
+ }
+
+ auto const name = envmod.substr(0, eq_loc);
+
+ // Split value on `:`
+ auto const op_value_start = eq_loc + 1;
+ auto const colon_loc = envmod.find_first_of(':', op_value_start);
+ if (colon_loc == std::string::npos) {
+ cmSystemTools::Error(
+ cmStrCat("Error: Missing `:` after the operation in: ", envmod, '\n'));
+ return false;
+ }
+ auto const op = envmod.substr(op_value_start, colon_loc - op_value_start);
+
+ auto const value_start = colon_loc + 1;
+ auto const value = envmod.substr(value_start);
+
+ // Determine what to do with the operation.
+ if (op == "reset"_s) {
+ auto entry = diff.find(name);
+ if (entry != diff.end()) {
+ diff.erase(entry);
+ }
+ } else if (op == "set"_s) {
+ diff[name] = value;
+ } else if (op == "unset"_s) {
+ diff[name] = {};
+ } else if (op == "string_append"_s) {
+ apply_diff(name, [&value](std::string& output) { output += value; });
+ } else if (op == "string_prepend"_s) {
+ apply_diff(name,
+ [&value](std::string& output) { output.insert(0, value); });
+ } else if (op == "path_list_append"_s) {
+ apply_diff(name, [&value, path_sep](std::string& output) {
+ if (!output.empty()) {
+ output += path_sep;
+ }
+ output += value;
+ });
+ } else if (op == "path_list_prepend"_s) {
+ apply_diff(name, [&value, path_sep](std::string& output) {
+ if (!output.empty()) {
+ output.insert(output.begin(), path_sep);
+ }
+ output.insert(0, value);
+ });
+ } else if (op == "cmake_list_append"_s) {
+ apply_diff(name, [&value](std::string& output) {
+ if (!output.empty()) {
+ output += ';';
+ }
+ output += value;
+ });
+ } else if (op == "cmake_list_prepend"_s) {
+ apply_diff(name, [&value](std::string& output) {
+ if (!output.empty()) {
+ output.insert(output.begin(), ';');
+ }
+ output.insert(0, value);
+ });
+ } else {
+ cmSystemTools::Error(cmStrCat(
+ "Error: Unrecognized environment manipulation argument: ", op, '\n'));
+ return false;
+ }
+
+ return true;
+}
+
+void cmSystemTools::EnvDiff::ApplyToCurrentEnv(std::ostringstream* measurement)
+{
+ for (auto const& env_apply : diff) {
+ if (env_apply.second) {
+ auto const env_update =
+ cmStrCat(env_apply.first, '=', *env_apply.second);
+ cmSystemTools::PutEnv(env_update);
+ if (measurement) {
+ *measurement << env_update << std::endl;
+ }
+ } else {
+ cmSystemTools::UnsetEnv(env_apply.first.c_str());
+ if (measurement) {
+ // Signify that this variable is being actively unset
+ *measurement << '#' << env_apply.first << "=\n";
+ }
+ }
+ }
+}
+
cmSystemTools::SaveRestoreEnvironment::SaveRestoreEnvironment()
{
this->Env = cmSystemTools::GetEnvironmentVariables();
diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h
index ec650f7..48bbe23 100644
--- a/Source/cmSystemTools.h
+++ b/Source/cmSystemTools.h
@@ -6,9 +6,12 @@
#include <cstddef>
#include <functional>
+#include <map>
+#include <sstream>
#include <string>
#include <vector>
+#include <cm/optional>
#include <cm/string_view>
#include "cmsys/Process.h"
@@ -377,6 +380,42 @@ public:
/** Append multiple variables to the current environment. */
static void AppendEnv(std::vector<std::string> const& env);
+ /**
+ * Helper class to represent an environment diff directly. This is to avoid
+ * repeated in-place environment modification (i.e. via setenv/putenv), which
+ * could be slow.
+ */
+ class EnvDiff
+ {
+ public:
+ /** Append multiple variables to the current environment diff */
+ void AppendEnv(std::vector<std::string> const& env);
+
+ /**
+ * Add a single variable (or remove if no = sign) to the current
+ * environment diff.
+ */
+ void PutEnv(const std::string& env);
+
+ /** Remove a single variable from the current environment diff. */
+ void UnPutEnv(const std::string& env);
+
+ /**
+ * Apply an ENVIRONMENT_MODIFICATION operation to this diff. Returns
+ * false and issues an error on parse failure.
+ */
+ bool ParseOperation(const std::string& envmod);
+
+ /**
+ * Apply this diff to the actual environment, optionally writing out the
+ * modifications to a CTest-compatible measurement stream.
+ */
+ void ApplyToCurrentEnv(std::ostringstream* measurement = nullptr);
+
+ private:
+ std::map<std::string, cm::optional<std::string>> diff;
+ };
+
/** Helper class to save and restore the environment.
Instantiate this class as an automatic variable on
the stack. Its constructor saves a copy of the current
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index 62ec344..050206a 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -272,6 +272,8 @@ public:
cmListFileBacktrace Backtrace;
FileSetType HeadersFileSets;
+ FileSetType CxxModulesFileSets;
+ FileSetType CxxModuleHeadersFileSets;
cmTargetInternals();
@@ -293,6 +295,12 @@ public:
cm::string_view fileSetType) const;
cmValue GetFileSetPaths(cmTarget const* self, std::string const& fileSetName,
cm::string_view fileSetType) const;
+
+ cmListFileBacktrace GetBacktrace(
+ cm::optional<cmListFileBacktrace> const& bt) const
+ {
+ return bt ? *bt : this->Makefile->GetBacktrace();
+ }
};
cmTargetInternals::cmTargetInternals()
@@ -301,6 +309,19 @@ cmTargetInternals::cmTargetInternals()
"The default header set"_s, "Header set"_s,
FileSetEntries("HEADER_SETS"_s),
FileSetEntries("INTERFACE_HEADER_SETS"_s))
+ , CxxModulesFileSets("CXX_MODULES"_s, "CXX_MODULE_DIRS"_s,
+ "CXX_MODULE_SET"_s, "CXX_MODULE_DIRS_"_s,
+ "CXX_MODULE_SET_"_s, "C++ module"_s,
+ "The default C++ module set"_s, "C++ module set"_s,
+ FileSetEntries("CXX_MODULE_SETS"_s),
+ FileSetEntries("INTERFACE_CXX_MODULE_SETS"_s))
+ , CxxModuleHeadersFileSets(
+ "CXX_MODULE_HEADER_UNITS"_s, "CXX_MODULE_HEADER_UNIT_DIRS"_s,
+ "CXX_MODULE_HEADER_UNIT_SET"_s, "CXX_MODULE_HEADER_UNIT_DIRS_"_s,
+ "CXX_MODULE_HEADER_UNIT_SET_"_s, "C++ module header"_s,
+ "The default C++ module header set"_s, "C++ module header set"_s,
+ FileSetEntries("CXX_MODULE_HEADER_UNIT_SETS"_s),
+ FileSetEntries("INTERFACE_CXX_MODULE_HEADER_UNIT_SETS"_s))
{
}
@@ -611,6 +632,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
initProp("XCODE_SCHEME_MALLOC_SCRIBBLE");
initProp("XCODE_SCHEME_MALLOC_GUARD_EDGES");
initProp("XCODE_SCHEME_GUARD_MALLOC");
+ initProp("XCODE_SCHEME_LAUNCH_MODE");
initProp("XCODE_SCHEME_ZOMBIE_OBJECTS");
initProp("XCODE_SCHEME_MALLOC_STACK");
initProp("XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE");
@@ -760,6 +782,10 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
}
}
+ if (this->IsImported()) {
+ this->SetProperty("SYSTEM", "ON");
+ }
+
for (auto const& prop : mf->GetState()->GetPropertyDefinitions().GetMap()) {
if (prop.first.second == cmProperty::TARGET &&
!prop.second.GetInitializeFromVariable().empty()) {
@@ -1223,7 +1249,8 @@ void cmTarget::AddLinkLibrary(cmMakefile& mf, std::string const& lib,
? targetNameGenex(lib)
: lib;
this->AppendProperty("LINK_LIBRARIES",
- this->GetDebugGeneratorExpressions(libName, llt));
+ this->GetDebugGeneratorExpressions(libName, llt),
+ mf.GetBacktrace());
}
if (cmGeneratorExpression::Find(lib) != std::string::npos ||
@@ -1367,11 +1394,32 @@ cmBTStringRange cmTarget::GetHeaderSetsEntries() const
return cmMakeRange(this->impl->HeadersFileSets.SelfEntries.Entries);
}
+cmBTStringRange cmTarget::GetCxxModuleSetsEntries() const
+{
+ return cmMakeRange(this->impl->CxxModulesFileSets.SelfEntries.Entries);
+}
+
+cmBTStringRange cmTarget::GetCxxModuleHeaderSetsEntries() const
+{
+ return cmMakeRange(this->impl->CxxModuleHeadersFileSets.SelfEntries.Entries);
+}
+
cmBTStringRange cmTarget::GetInterfaceHeaderSetsEntries() const
{
return cmMakeRange(this->impl->HeadersFileSets.InterfaceEntries.Entries);
}
+cmBTStringRange cmTarget::GetInterfaceCxxModuleSetsEntries() const
+{
+ return cmMakeRange(this->impl->CxxModulesFileSets.InterfaceEntries.Entries);
+}
+
+cmBTStringRange cmTarget::GetInterfaceCxxModuleHeaderSetsEntries() const
+{
+ return cmMakeRange(
+ this->impl->CxxModuleHeadersFileSets.InterfaceEntries.Entries);
+}
+
namespace {
#define MAKE_PROP(PROP) const std::string prop##PROP = #PROP
MAKE_PROP(C_STANDARD);
@@ -1631,13 +1679,21 @@ void cmTarget::StoreProperty(const std::string& prop, ValueType value)
} else if (this->impl->HeadersFileSets.WriteProperties(
this, this->impl.get(), prop, value, true)) {
/* Handled in the `if` condition. */
+ } else if (this->impl->CxxModulesFileSets.WriteProperties(
+ this, this->impl.get(), prop, value, true)) {
+ /* Handled in the `if` condition. */
+ } else if (this->impl->CxxModuleHeadersFileSets.WriteProperties(
+ this, this->impl.get(), prop, value, true)) {
+ /* Handled in the `if` condition. */
} else {
this->impl->Properties.SetProperty(prop, value);
}
}
void cmTarget::AppendProperty(const std::string& prop,
- const std::string& value, bool asString)
+ const std::string& value,
+ cm::optional<cmListFileBacktrace> const& bt,
+ bool asString)
{
if (prop == "NAME") {
this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR,
@@ -1668,32 +1724,32 @@ void cmTarget::AppendProperty(const std::string& prop,
}
if (prop == "INCLUDE_DIRECTORIES") {
if (!value.empty()) {
- cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+ cmListFileBacktrace lfbt = this->impl->GetBacktrace(bt);
this->impl->IncludeDirectoriesEntries.emplace_back(value, lfbt);
}
} else if (prop == "COMPILE_OPTIONS") {
if (!value.empty()) {
- cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+ cmListFileBacktrace lfbt = this->impl->GetBacktrace(bt);
this->impl->CompileOptionsEntries.emplace_back(value, lfbt);
}
} else if (prop == "COMPILE_FEATURES") {
if (!value.empty()) {
- cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+ cmListFileBacktrace lfbt = this->impl->GetBacktrace(bt);
this->impl->CompileFeaturesEntries.emplace_back(value, lfbt);
}
} else if (prop == "COMPILE_DEFINITIONS") {
if (!value.empty()) {
- cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+ cmListFileBacktrace lfbt = this->impl->GetBacktrace(bt);
this->impl->CompileDefinitionsEntries.emplace_back(value, lfbt);
}
} else if (prop == "LINK_OPTIONS") {
if (!value.empty()) {
- cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+ cmListFileBacktrace lfbt = this->impl->GetBacktrace(bt);
this->impl->LinkOptionsEntries.emplace_back(value, lfbt);
}
} else if (prop == "LINK_DIRECTORIES") {
if (!value.empty()) {
- cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+ cmListFileBacktrace lfbt = this->impl->GetBacktrace(bt);
this->impl->LinkDirectoriesEntries.emplace_back(value, lfbt);
}
} else if (prop == "PRECOMPILE_HEADERS") {
@@ -1706,32 +1762,32 @@ void cmTarget::AppendProperty(const std::string& prop,
return;
}
if (!value.empty()) {
- cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+ cmListFileBacktrace lfbt = this->impl->GetBacktrace(bt);
this->impl->PrecompileHeadersEntries.emplace_back(value, lfbt);
}
} else if (prop == "LINK_LIBRARIES") {
if (!value.empty()) {
- cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+ cmListFileBacktrace lfbt = this->impl->GetBacktrace(bt);
this->impl->LinkImplementationPropertyEntries.emplace_back(value, lfbt);
}
} else if (prop == propINTERFACE_LINK_LIBRARIES) {
if (!value.empty()) {
- cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+ cmListFileBacktrace lfbt = this->impl->GetBacktrace(bt);
this->impl->LinkInterfacePropertyEntries.emplace_back(value, lfbt);
}
} else if (prop == propINTERFACE_LINK_LIBRARIES_DIRECT) {
if (!value.empty()) {
- cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+ cmListFileBacktrace lfbt = this->impl->GetBacktrace(bt);
this->impl->LinkInterfaceDirectPropertyEntries.emplace_back(value, lfbt);
}
} else if (prop == propINTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE) {
if (!value.empty()) {
- cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+ cmListFileBacktrace lfbt = this->impl->GetBacktrace(bt);
this->impl->LinkInterfaceDirectExcludePropertyEntries.emplace_back(value,
lfbt);
}
} else if (prop == "SOURCES") {
- cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+ cmListFileBacktrace lfbt = this->impl->GetBacktrace(bt);
this->impl->SourceEntries.emplace_back(value, lfbt);
} else if (cmHasLiteralPrefix(prop, "IMPORTED_LIBNAME")) {
this->impl->Makefile->IssueMessage(
@@ -1742,6 +1798,13 @@ void cmTarget::AppendProperty(const std::string& prop,
this->impl->Makefile->IssueMessage(
MessageType::FATAL_ERROR, prop + " property may not be appended.");
} else if (this->impl->HeadersFileSets.WriteProperties(
+ this, this->impl.get(), prop, value,
+ false)) { // NOLINT(bugprone-branch-clone)
+ /* Handled in the `if` condition. */
+ } else if (this->impl->CxxModulesFileSets.WriteProperties(
+ this, this->impl.get(), prop, value, false)) {
+ /* Handled in the `if` condition. */
+ } else if (this->impl->CxxModuleHeadersFileSets.WriteProperties(
this, this->impl.get(), prop, value, false)) {
/* Handled in the `if` condition. */
} else {
@@ -2295,6 +2358,17 @@ cmValue cmTarget::GetProperty(const std::string& prop) const
if (headers.first) {
return headers.second;
}
+ auto cxx_modules = this->impl->CxxModulesFileSets.ReadProperties(
+ this, this->impl.get(), prop);
+ if (cxx_modules.first) {
+ return cxx_modules.second;
+ }
+ auto cxx_module_headers =
+ this->impl->CxxModuleHeadersFileSets.ReadProperties(
+ this, this->impl.get(), prop);
+ if (cxx_module_headers.first) {
+ return cxx_module_headers.second;
+ }
}
cmValue retVal = this->impl->Properties.GetPropertyValue(prop);
@@ -2572,6 +2646,11 @@ std::pair<cmFileSet*, bool> cmTarget::GetOrCreateFileSet(
auto bt = this->impl->Makefile->GetBacktrace();
if (type == this->impl->HeadersFileSets.TypeName) {
this->impl->HeadersFileSets.AddFileSet(name, vis, std::move(bt));
+ } else if (type == this->impl->CxxModulesFileSets.TypeName) {
+ this->impl->CxxModulesFileSets.AddFileSet(name, vis, std::move(bt));
+ } else if (type == this->impl->CxxModuleHeadersFileSets.TypeName) {
+ this->impl->CxxModuleHeadersFileSets.AddFileSet(name, vis,
+ std::move(bt));
}
}
return std::make_pair(&result.first->second, result.second);
@@ -2582,6 +2661,12 @@ std::string cmTarget::GetFileSetsPropertyName(const std::string& type)
if (type == "HEADERS") {
return "HEADER_SETS";
}
+ if (type == "CXX_MODULES") {
+ return "CXX_MODULE_SETS";
+ }
+ if (type == "CXX_MODULE_HEADER_UNITS") {
+ return "CXX_MODULE_HEADER_UNIT_SETS";
+ }
return "";
}
@@ -2590,6 +2675,12 @@ std::string cmTarget::GetInterfaceFileSetsPropertyName(const std::string& type)
if (type == "HEADERS") {
return "INTERFACE_HEADER_SETS";
}
+ if (type == "CXX_MODULES") {
+ return "INTERFACE_CXX_MODULE_SETS";
+ }
+ if (type == "CXX_MODULE_HEADER_UNITS") {
+ return "INTERFACE_CXX_MODULE_HEADER_UNIT_SETS";
+ }
return "";
}
@@ -2617,6 +2708,8 @@ std::vector<std::string> cmTarget::GetAllInterfaceFileSets() const
};
appendEntries(this->impl->HeadersFileSets.InterfaceEntries.Entries);
+ appendEntries(this->impl->CxxModulesFileSets.InterfaceEntries.Entries);
+ appendEntries(this->impl->CxxModuleHeadersFileSets.InterfaceEntries.Entries);
return result;
}
diff --git a/Source/cmTarget.h b/Source/cmTarget.h
index 37701f0..1550f5b 100644
--- a/Source/cmTarget.h
+++ b/Source/cmTarget.h
@@ -185,8 +185,10 @@ public:
{
this->SetProperty(prop, cmValue(value));
}
- void AppendProperty(const std::string& prop, const std::string& value,
- bool asString = false);
+ void AppendProperty(
+ const std::string& prop, const std::string& value,
+ cm::optional<cmListFileBacktrace> const& bt = cm::nullopt,
+ bool asString = false);
//! Might return a nullptr if the property is not set or invalid
cmValue GetProperty(const std::string& prop) const;
//! Always returns a valid pointer
@@ -281,8 +283,12 @@ public:
cmBTStringRange GetLinkInterfaceDirectExcludeEntries() const;
cmBTStringRange GetHeaderSetsEntries() const;
+ cmBTStringRange GetCxxModuleSetsEntries() const;
+ cmBTStringRange GetCxxModuleHeaderSetsEntries() const;
cmBTStringRange GetInterfaceHeaderSetsEntries() const;
+ cmBTStringRange GetInterfaceCxxModuleSetsEntries() const;
+ cmBTStringRange GetInterfaceCxxModuleHeaderSetsEntries() const;
std::string ImportedGetFullPath(const std::string& config,
cmStateEnums::ArtifactType artifact) const;
diff --git a/Source/cmTargetCompileDefinitionsCommand.cxx b/Source/cmTargetCompileDefinitionsCommand.cxx
index b56b245..268bfac 100644
--- a/Source/cmTargetCompileDefinitionsCommand.cxx
+++ b/Source/cmTargetCompileDefinitionsCommand.cxx
@@ -2,6 +2,7 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmTargetCompileDefinitionsCommand.h"
+#include "cmListFileCache.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmStringAlgorithms.h"
@@ -28,7 +29,8 @@ private:
const std::vector<std::string>& content,
bool /*prepend*/, bool /*system*/) override
{
- tgt->AppendProperty("COMPILE_DEFINITIONS", this->Join(content));
+ tgt->AppendProperty("COMPILE_DEFINITIONS", this->Join(content),
+ this->Makefile->GetBacktrace());
return true; // Successfully handled.
}
diff --git a/Source/cmTargetExport.h b/Source/cmTargetExport.h
index 885ac74..1cef888 100644
--- a/Source/cmTargetExport.h
+++ b/Source/cmTargetExport.h
@@ -8,6 +8,7 @@
class cmFileSet;
class cmGeneratorTarget;
+class cmInstallCxxModuleBmiGenerator;
class cmInstallFileSetGenerator;
class cmInstallFilesGenerator;
class cmInstallTargetGenerator;
@@ -32,6 +33,7 @@ public:
cmInstallTargetGenerator* BundleGenerator;
cmInstallFilesGenerator* HeaderGenerator;
std::map<cmFileSet*, cmInstallFileSetGenerator*> FileSetGenerators;
+ cmInstallCxxModuleBmiGenerator* CxxModuleBmiGenerator;
///@}
bool NamelinkOnly = false;
diff --git a/Source/cmTargetIncludeDirectoriesCommand.cxx b/Source/cmTargetIncludeDirectoriesCommand.cxx
index b4b4319..cb83873 100644
--- a/Source/cmTargetIncludeDirectoriesCommand.cxx
+++ b/Source/cmTargetIncludeDirectoriesCommand.cxx
@@ -88,7 +88,8 @@ void TargetIncludeDirectoriesImpl::HandleInterfaceContent(
system);
if (system) {
std::string joined = this->Join(content);
- tgt->AppendProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES", joined);
+ tgt->AppendProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES", joined,
+ this->Makefile->GetBacktrace());
}
}
diff --git a/Source/cmTargetLinkLibrariesCommand.cxx b/Source/cmTargetLinkLibrariesCommand.cxx
index ba901d0..fb03b62 100644
--- a/Source/cmTargetLinkLibrariesCommand.cxx
+++ b/Source/cmTargetLinkLibrariesCommand.cxx
@@ -625,7 +625,7 @@ bool TLL::HandleLibrary(ProcessingState currentProcessingState,
void TLL::AppendProperty(std::string const& prop, std::string const& value)
{
this->AffectsProperty(prop);
- this->Target->AppendProperty(prop, value);
+ this->Target->AppendProperty(prop, value, this->Makefile.GetBacktrace());
}
void TLL::AffectsProperty(std::string const& prop)
@@ -636,14 +636,16 @@ void TLL::AffectsProperty(std::string const& prop)
// Add a wrapper to the expression to tell LookupLinkItem to look up
// names in the caller's directory.
if (this->Props.insert(prop).second) {
- this->Target->AppendProperty(prop, this->DirectoryId);
+ this->Target->AppendProperty(prop, this->DirectoryId,
+ this->Makefile.GetBacktrace());
}
}
TLL::~TLL()
{
for (std::string const& prop : this->Props) {
- this->Target->AppendProperty(prop, CMAKE_DIRECTORY_ID_SEP);
+ this->Target->AppendProperty(prop, CMAKE_DIRECTORY_ID_SEP,
+ this->Makefile.GetBacktrace());
}
}
diff --git a/Source/cmTargetPrecompileHeadersCommand.cxx b/Source/cmTargetPrecompileHeadersCommand.cxx
index a5066cc..4dd158d 100644
--- a/Source/cmTargetPrecompileHeadersCommand.cxx
+++ b/Source/cmTargetPrecompileHeadersCommand.cxx
@@ -5,6 +5,7 @@
#include <utility>
#include "cmGeneratorExpression.h"
+#include "cmListFileCache.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmStringAlgorithms.h"
@@ -48,7 +49,8 @@ private:
{
std::string const& base = this->Makefile->GetCurrentSourceDirectory();
tgt->AppendProperty("PRECOMPILE_HEADERS",
- this->Join(ConvertToAbsoluteContent(content, base)));
+ this->Join(ConvertToAbsoluteContent(content, base)),
+ this->Makefile->GetBacktrace());
return true;
}
diff --git a/Source/cmTargetSourcesCommand.cxx b/Source/cmTargetSourcesCommand.cxx
index b1367e1..53e25b5 100644
--- a/Source/cmTargetSourcesCommand.cxx
+++ b/Source/cmTargetSourcesCommand.cxx
@@ -9,6 +9,8 @@
#include <cmext/string_view>
#include "cmArgumentParser.h"
+#include "cmArgumentParserTypes.h"
+#include "cmExperimental.h"
#include "cmFileSet.h"
#include "cmGeneratorExpression.h"
#include "cmListFileCache.h"
@@ -27,8 +29,8 @@ struct FileSetArgs
{
std::string Type;
std::string FileSet;
- std::vector<std::string> BaseDirs;
- std::vector<std::string> Files;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> BaseDirs;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Files;
};
auto const FileSetArgsParser = cmArgumentParser<FileSetArgs>()
@@ -77,7 +79,8 @@ private:
{
tgt->AppendProperty("SOURCES",
this->Join(this->ConvertToAbsoluteContent(
- tgt, content, IsInterface::No, CheckCMP0076::Yes)));
+ tgt, content, IsInterface::No, CheckCMP0076::Yes)),
+ this->Makefile->GetBacktrace());
return true; // Successfully handled.
}
@@ -196,7 +199,7 @@ std::vector<std::string> TargetSourcesImpl::ConvertToAbsoluteContent(
bool TargetSourcesImpl::HandleFileSetMode(
const std::string& scope, const std::vector<std::string>& content)
{
- auto args = FileSetsArgsParser.Parse(content);
+ auto args = FileSetsArgsParser.Parse(content, /*unparsedArguments=*/nullptr);
for (auto& argList : args.FileSets) {
argList.emplace(argList.begin(), "FILE_SET"_s);
@@ -256,9 +259,31 @@ bool TargetSourcesImpl::HandleOneFileSet(
this->SetError("Must specify a TYPE when creating file set");
return false;
}
- if (type != "HEADERS"_s) {
- this->SetError("File set TYPE may only be \"HEADERS\"");
- return false;
+ bool const supportCxx20FileSetTypes = cmExperimental::HasSupportEnabled(
+ *this->Makefile, cmExperimental::Feature::CxxModuleCMakeApi);
+
+ if (supportCxx20FileSetTypes) {
+ if (type != "HEADERS"_s && type != "CXX_MODULES"_s &&
+ type != "CXX_MODULE_HEADER_UNITS"_s) {
+ this->SetError(
+ R"(File set TYPE may only be "HEADERS", "CXX_MODULES", or "CXX_MODULE_HEADER_UNITS")");
+ return false;
+ }
+
+ if (cmFileSetVisibilityIsForInterface(visibility) &&
+ !cmFileSetVisibilityIsForSelf(visibility) &&
+ !this->Target->IsImported()) {
+ if (type == "CXX_MODULES"_s || type == "CXX_MODULE_HEADER_UNITS"_s) {
+ this->SetError(
+ R"(File set TYPEs "CXX_MODULES" and "CXX_MODULE_HEADER_UNITS" may not have "INTERFACE" visibility)");
+ return false;
+ }
+ }
+ } else {
+ if (type != "HEADERS"_s) {
+ this->SetError("File set TYPE may only be \"HEADERS\"");
+ return false;
+ }
}
if (args.BaseDirs.empty()) {
@@ -294,17 +319,19 @@ bool TargetSourcesImpl::HandleOneFileSet(
if (!baseDirectories.empty()) {
fileSet.first->AddDirectoryEntry(
BT<std::string>(baseDirectories, this->Makefile->GetBacktrace()));
- if (type == "HEADERS"_s) {
+ if (type == "HEADERS"_s || type == "CXX_MODULE_HEADER_UNITS"_s) {
for (auto const& dir : cmExpandedList(baseDirectories)) {
auto interfaceDirectoriesGenex =
cmStrCat("$<BUILD_INTERFACE:", dir, ">");
if (cmFileSetVisibilityIsForSelf(visibility)) {
this->Target->AppendProperty("INCLUDE_DIRECTORIES",
- interfaceDirectoriesGenex);
+ interfaceDirectoriesGenex,
+ this->Makefile->GetBacktrace());
}
if (cmFileSetVisibilityIsForInterface(visibility)) {
this->Target->AppendProperty("INTERFACE_INCLUDE_DIRECTORIES",
- interfaceDirectoriesGenex);
+ interfaceDirectoriesGenex,
+ this->Makefile->GetBacktrace());
}
}
}
diff --git a/Source/cmTryCompileCommand.cxx b/Source/cmTryCompileCommand.cxx
index 130c228..b59c225 100644
--- a/Source/cmTryCompileCommand.cxx
+++ b/Source/cmTryCompileCommand.cxx
@@ -2,34 +2,66 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmTryCompileCommand.h"
+#include "cmCoreTryCompile.h"
+#include "cmExecutionStatus.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
+#include "cmRange.h"
+#include "cmState.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmValue.h"
#include "cmake.h"
-class cmExecutionStatus;
-
-// cmTryCompileCommand
-bool cmTryCompileCommand::InitialPass(std::vector<std::string> const& argv,
- cmExecutionStatus&)
+bool cmTryCompileCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
{
- if (argv.size() < 3) {
+ if (args.size() < 3) {
return false;
}
- if (this->Makefile->GetCMakeInstance()->GetWorkingMode() ==
- cmake::FIND_PACKAGE_MODE) {
- this->Makefile->IssueMessage(
+ cmMakefile& mf = status.GetMakefile();
+
+ if (mf.GetCMakeInstance()->GetWorkingMode() == cmake::FIND_PACKAGE_MODE) {
+ mf.IssueMessage(
MessageType::FATAL_ERROR,
"The try_compile() command is not supported in --find-package mode.");
return false;
}
- this->TryCompileCode(argv, false);
+ cmStateEnums::TargetType targetType = cmStateEnums::EXECUTABLE;
+ cmValue tt = mf.GetDefinition("CMAKE_TRY_COMPILE_TARGET_TYPE");
+ if (cmNonempty(tt)) {
+ if (*tt == cmState::GetTargetTypeName(cmStateEnums::EXECUTABLE)) {
+ targetType = cmStateEnums::EXECUTABLE;
+ } else if (*tt ==
+ cmState::GetTargetTypeName(cmStateEnums::STATIC_LIBRARY)) {
+ targetType = cmStateEnums::STATIC_LIBRARY;
+ } else {
+ mf.IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat("Invalid value '", *tt,
+ "' for CMAKE_TRY_COMPILE_TARGET_TYPE. Only '",
+ cmState::GetTargetTypeName(cmStateEnums::EXECUTABLE),
+ "' and '",
+ cmState::GetTargetTypeName(cmStateEnums::STATIC_LIBRARY),
+ "' are allowed."));
+ return false;
+ }
+ }
+
+ cmCoreTryCompile tc(&mf);
+ cmCoreTryCompile::Arguments arguments =
+ tc.ParseArgs(cmMakeRange(args), false);
+ if (!arguments) {
+ return true;
+ }
+ tc.TryCompileCode(arguments, targetType);
// if They specified clean then we clean up what we can
- if (this->SrcFileSignature) {
- if (!this->Makefile->GetCMakeInstance()->GetDebugTryCompile()) {
- this->CleanupFiles(this->BinaryDirectory);
+ if (tc.SrcFileSignature) {
+ if (!mf.GetCMakeInstance()->GetDebugTryCompile()) {
+ tc.CleanupFiles(tc.BinaryDirectory);
}
}
return true;
diff --git a/Source/cmTryCompileCommand.h b/Source/cmTryCompileCommand.h
index d8cc16e..6a3430b 100644
--- a/Source/cmTryCompileCommand.h
+++ b/Source/cmTryCompileCommand.h
@@ -7,33 +7,7 @@
#include <string>
#include <vector>
-#include <cm/memory>
-
-#include "cmCommand.h"
-#include "cmCoreTryCompile.h"
-
class cmExecutionStatus;
-/** \class cmTryCompileCommand
- * \brief Specifies where to install some files
- *
- * cmTryCompileCommand is used to test if source code can be compiled
- */
-class cmTryCompileCommand : public cmCoreTryCompile
-{
-public:
- /**
- * This is a virtual constructor for the command.
- */
- std::unique_ptr<cmCommand> Clone() override
- {
- return cm::make_unique<cmTryCompileCommand>();
- }
-
- /**
- * This is called when the command is first encountered in
- * the CMakeLists.txt file.
- */
- bool InitialPass(std::vector<std::string> const& args,
- cmExecutionStatus& status) override;
-};
+bool cmTryCompileCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmTryRunCommand.cxx b/Source/cmTryRunCommand.cxx
index c82ac64..7a29521 100644
--- a/Source/cmTryRunCommand.cxx
+++ b/Source/cmTryRunCommand.cxx
@@ -4,9 +4,14 @@
#include <cstdio>
+#include <cm/optional>
+
#include "cmsys/FStream.hxx"
+#include "cmArgumentParserTypes.h"
+#include "cmCoreTryCompile.h"
#include "cmDuration.h"
+#include "cmExecutionStatus.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmRange.h"
@@ -17,157 +22,155 @@
#include "cmValue.h"
#include "cmake.h"
-class cmExecutionStatus;
+namespace {
-// cmTryRunCommand
-bool cmTryRunCommand::InitialPass(std::vector<std::string> const& argv,
- cmExecutionStatus&)
+class TryRunCommandImpl : public cmCoreTryCompile
{
- if (argv.size() < 4) {
- return false;
+public:
+ TryRunCommandImpl(cmMakefile* mf)
+ : cmCoreTryCompile(mf)
+ {
}
- if (this->Makefile->GetCMakeInstance()->GetWorkingMode() ==
- cmake::FIND_PACKAGE_MODE) {
- this->Makefile->IssueMessage(
- MessageType::FATAL_ERROR,
- "The try_run() command is not supported in --find-package mode.");
- return false;
- }
+ bool TryRunCode(std::vector<std::string> const& args);
- // build an arg list for TryCompile and extract the runArgs,
- std::vector<std::string> tryCompile;
-
- this->CompileResultVariable.clear();
- this->RunResultVariable.clear();
- this->OutputVariable.clear();
- this->RunOutputVariable.clear();
- this->CompileOutputVariable.clear();
-
- std::string runArgs;
- unsigned int i;
- for (i = 1; i < argv.size(); ++i) {
- if (argv[i] == "ARGS") {
- ++i;
- while (i < argv.size() && argv[i] != "COMPILE_DEFINITIONS" &&
- argv[i] != "CMAKE_FLAGS" && argv[i] != "LINK_OPTIONS" &&
- argv[i] != "LINK_LIBRARIES") {
- runArgs += " ";
- runArgs += argv[i];
- ++i;
- }
- if (i < argv.size()) {
- tryCompile.push_back(argv[i]);
- }
- } else {
- if (argv[i] == "OUTPUT_VARIABLE") {
- if (argv.size() <= (i + 1)) {
- cmSystemTools::Error(
- "OUTPUT_VARIABLE specified but there is no variable");
- return false;
- }
- i++;
- this->OutputVariable = argv[i];
- } else if (argv[i] == "RUN_OUTPUT_VARIABLE") {
- if (argv.size() <= (i + 1)) {
- cmSystemTools::Error(
- "RUN_OUTPUT_VARIABLE specified but there is no variable");
- return false;
- }
- i++;
- this->RunOutputVariable = argv[i];
- } else if (argv[i] == "COMPILE_OUTPUT_VARIABLE") {
- if (argv.size() <= (i + 1)) {
- cmSystemTools::Error(
- "COMPILE_OUTPUT_VARIABLE specified but there is no variable");
- return false;
- }
- i++;
- this->CompileOutputVariable = argv[i];
- } else if (argv[i] == "WORKING_DIRECTORY") {
- if (argv.size() <= (i + 1)) {
- cmSystemTools::Error(
- "WORKING_DIRECTORY specified but there is no variable");
- return false;
- }
- i++;
- this->WorkingDirectory = argv[i];
- } else {
- tryCompile.push_back(argv[i]);
- }
- }
+ void RunExecutable(const std::string& runArgs,
+ cm::optional<std::string> const& workDir,
+ std::string* runOutputContents,
+ std::string* runOutputStdOutContents,
+ std::string* runOutputStdErrContents);
+ void DoNotRunExecutable(const std::string& runArgs,
+ const std::string& srcFile,
+ std::string const& compileResultVariable,
+ std::string* runOutputContents,
+ std::string* runOutputStdOutContents,
+ std::string* runOutputStdErrContents);
+
+ std::string RunResultVariable;
+};
+
+bool TryRunCommandImpl::TryRunCode(std::vector<std::string> const& argv)
+{
+ this->RunResultVariable = argv[0];
+ cmCoreTryCompile::Arguments arguments =
+ this->ParseArgs(cmMakeRange(argv).advance(1), true);
+ if (!arguments) {
+ return true;
}
// although they could be used together, don't allow it, because
// using OUTPUT_VARIABLE makes crosscompiling harder
- if (!this->OutputVariable.empty() &&
- (!this->RunOutputVariable.empty() ||
- !this->CompileOutputVariable.empty())) {
+ if (arguments.OutputVariable &&
+ (arguments.CompileOutputVariable || arguments.RunOutputVariable ||
+ arguments.RunOutputStdOutVariable ||
+ arguments.RunOutputStdErrVariable)) {
cmSystemTools::Error(
"You cannot use OUTPUT_VARIABLE together with COMPILE_OUTPUT_VARIABLE "
- "or RUN_OUTPUT_VARIABLE. Please use only COMPILE_OUTPUT_VARIABLE and/or "
- "RUN_OUTPUT_VARIABLE.");
+ ", RUN_OUTPUT_VARIABLE, RUN_OUTPUT_STDOUT_VARIABLE or "
+ "RUN_OUTPUT_STDERR_VARIABLE. "
+ "Please use only COMPILE_OUTPUT_VARIABLE, RUN_OUTPUT_VARIABLE, "
+ "RUN_OUTPUT_STDOUT_VARIABLE "
+ "and/or RUN_OUTPUT_STDERR_VARIABLE.");
return false;
}
- if (!this->WorkingDirectory.empty()) {
- if (!cmSystemTools::MakeDirectory(this->WorkingDirectory)) {
+ if ((arguments.RunOutputStdOutVariable ||
+ arguments.RunOutputStdErrVariable) &&
+ arguments.RunOutputVariable) {
+ cmSystemTools::Error(
+ "You cannot use RUN_OUTPUT_STDOUT_VARIABLE or "
+ "RUN_OUTPUT_STDERR_VARIABLE together "
+ "with RUN_OUTPUT_VARIABLE. Please use only COMPILE_OUTPUT_VARIABLE or "
+ "RUN_OUTPUT_STDOUT_VARIABLE and/or RUN_OUTPUT_STDERR_VARIABLE.");
+ return false;
+ }
+
+ if (arguments.RunWorkingDirectory) {
+ if (!cmSystemTools::MakeDirectory(*arguments.RunWorkingDirectory)) {
cmSystemTools::Error(cmStrCat("Error creating working directory \"",
- this->WorkingDirectory, "\"."));
+ *arguments.RunWorkingDirectory, "\"."));
return false;
}
}
bool captureRunOutput = false;
- if (!this->OutputVariable.empty()) {
+ bool captureRunOutputStdOutErr = false;
+ if (arguments.OutputVariable) {
captureRunOutput = true;
- tryCompile.emplace_back("OUTPUT_VARIABLE");
- tryCompile.push_back(this->OutputVariable);
- }
- if (!this->CompileOutputVariable.empty()) {
- tryCompile.emplace_back("OUTPUT_VARIABLE");
- tryCompile.push_back(this->CompileOutputVariable);
+ } else if (arguments.CompileOutputVariable) {
+ arguments.OutputVariable = arguments.CompileOutputVariable;
}
- if (!this->RunOutputVariable.empty()) {
+ if (arguments.RunOutputStdOutVariable || arguments.RunOutputStdErrVariable) {
+ captureRunOutputStdOutErr = true;
+ } else if (arguments.RunOutputVariable) {
captureRunOutput = true;
}
- this->RunResultVariable = argv[0];
- this->CompileResultVariable = argv[1];
-
// do the try compile
- int res = this->TryCompileCode(tryCompile, true);
+ bool compiled = this->TryCompileCode(arguments, cmStateEnums::EXECUTABLE);
// now try running the command if it compiled
- if (!res) {
+ if (compiled) {
if (this->OutputFile.empty()) {
cmSystemTools::Error(this->FindErrorMessage);
} else {
+ std::string runArgs;
+ if (arguments.RunArgs) {
+ runArgs = cmStrCat(" ", cmJoin(*arguments.RunArgs, " "));
+ }
+
// "run" it and capture the output
std::string runOutputContents;
+ std::string runOutputStdOutContents;
+ std::string runOutputStdErrContents;
if (this->Makefile->IsOn("CMAKE_CROSSCOMPILING") &&
!this->Makefile->IsDefinitionSet("CMAKE_CROSSCOMPILING_EMULATOR")) {
this->DoNotRunExecutable(
- runArgs, argv[3], captureRunOutput ? &runOutputContents : nullptr);
+ runArgs, *arguments.SourceDirectoryOrFile,
+ *arguments.CompileResultVariable,
+ captureRunOutput ? &runOutputContents : nullptr,
+ captureRunOutputStdOutErr && arguments.RunOutputStdOutVariable
+ ? &runOutputStdOutContents
+ : nullptr,
+ captureRunOutputStdOutErr && arguments.RunOutputStdErrVariable
+ ? &runOutputStdErrContents
+ : nullptr);
} else {
- this->RunExecutable(runArgs, &runOutputContents);
+ this->RunExecutable(
+ runArgs, arguments.RunWorkingDirectory,
+ captureRunOutput ? &runOutputContents : nullptr,
+ captureRunOutputStdOutErr && arguments.RunOutputStdOutVariable
+ ? &runOutputStdOutContents
+ : nullptr,
+ captureRunOutputStdOutErr && arguments.RunOutputStdErrVariable
+ ? &runOutputStdErrContents
+ : nullptr);
}
// now put the output into the variables
- if (!this->RunOutputVariable.empty()) {
- this->Makefile->AddDefinition(this->RunOutputVariable,
+ if (arguments.RunOutputVariable) {
+ this->Makefile->AddDefinition(*arguments.RunOutputVariable,
runOutputContents);
}
+ if (arguments.RunOutputStdOutVariable) {
+ this->Makefile->AddDefinition(*arguments.RunOutputStdOutVariable,
+ runOutputStdOutContents);
+ }
+ if (arguments.RunOutputStdErrVariable) {
+ this->Makefile->AddDefinition(*arguments.RunOutputStdErrVariable,
+ runOutputStdErrContents);
+ }
- if (!this->OutputVariable.empty()) {
+ if (arguments.OutputVariable && !arguments.CompileOutputVariable) {
// if the TryCompileCore saved output in this outputVariable then
// prepend that output to this output
cmValue compileOutput =
- this->Makefile->GetDefinition(this->OutputVariable);
+ this->Makefile->GetDefinition(*arguments.OutputVariable);
if (compileOutput) {
runOutputContents = *compileOutput + runOutputContents;
}
- this->Makefile->AddDefinition(this->OutputVariable, runOutputContents);
+ this->Makefile->AddDefinition(*arguments.OutputVariable,
+ runOutputContents);
}
}
}
@@ -179,8 +182,10 @@ bool cmTryRunCommand::InitialPass(std::vector<std::string> const& argv,
return true;
}
-void cmTryRunCommand::RunExecutable(const std::string& runArgs,
- std::string* out)
+void TryRunCommandImpl::RunExecutable(const std::string& runArgs,
+ cm::optional<std::string> const& workDir,
+ std::string* out, std::string* stdOut,
+ std::string* stdErr)
{
int retVal = -1;
@@ -204,9 +209,10 @@ void cmTryRunCommand::RunExecutable(const std::string& runArgs,
finalCommand += runArgs;
}
bool worked = cmSystemTools::RunSingleCommand(
- finalCommand, out, out, &retVal,
- this->WorkingDirectory.empty() ? nullptr : this->WorkingDirectory.c_str(),
- cmSystemTools::OUTPUT_NONE, cmDuration::zero());
+ finalCommand, stdOut || stdErr ? stdOut : out,
+ stdOut || stdErr ? stdErr : out, &retVal,
+ workDir ? workDir->c_str() : nullptr, cmSystemTools::OUTPUT_NONE,
+ cmDuration::zero());
// set the run var
char retChar[16];
const char* retStr;
@@ -225,9 +231,10 @@ void cmTryRunCommand::RunExecutable(const std::string& runArgs,
executable, two cache variables are created which will hold the results
the executable would have produced.
*/
-void cmTryRunCommand::DoNotRunExecutable(const std::string& runArgs,
- const std::string& srcFile,
- std::string* out)
+void TryRunCommandImpl::DoNotRunExecutable(
+ const std::string& runArgs, const std::string& srcFile,
+ std::string const& compileResultVariable, std::string* out,
+ std::string* stdOut, std::string* stdErr)
{
// copy the executable out of the CMakeFiles/ directory, so it is not
// removed at the end of try_run() and the user can run it manually
@@ -246,6 +253,10 @@ void cmTryRunCommand::DoNotRunExecutable(const std::string& runArgs,
std::string internalRunOutputName =
this->RunResultVariable + "__TRYRUN_OUTPUT";
+ std::string internalRunOutputStdOutName =
+ this->RunResultVariable + "__TRYRUN_OUTPUT_STDOUT";
+ std::string internalRunOutputStdErrName =
+ this->RunResultVariable + "__TRYRUN_OUTPUT_STDERR";
bool error = false;
if (!this->Makefile->GetDefinition(this->RunResultVariable)) {
@@ -269,7 +280,51 @@ void cmTryRunCommand::DoNotRunExecutable(const std::string& runArgs,
}
// is the output from the executable used ?
- if (out) {
+ if (stdOut || stdErr) {
+ if (!this->Makefile->GetDefinition(internalRunOutputStdOutName)) {
+ // if the variables doesn't exist, create it with a helpful error text
+ // and mark it as advanced
+ std::string comment = cmStrCat(
+ "Output of try_run(), contains the text, which the executable "
+ "would have printed on stdout on its target platform.\n",
+ detailsString);
+
+ this->Makefile->AddCacheDefinition(
+ internalRunOutputStdOutName, "PLEASE_FILL_OUT-NOTFOUND",
+ comment.c_str(), cmStateEnums::STRING);
+ cmState* state = this->Makefile->GetState();
+ cmValue existing =
+ state->GetCacheEntryValue(internalRunOutputStdOutName);
+ if (existing) {
+ state->SetCacheEntryProperty(internalRunOutputStdOutName, "ADVANCED",
+ "1");
+ }
+
+ error = true;
+ }
+
+ if (!this->Makefile->GetDefinition(internalRunOutputStdErrName)) {
+ // if the variables doesn't exist, create it with a helpful error text
+ // and mark it as advanced
+ std::string comment = cmStrCat(
+ "Output of try_run(), contains the text, which the executable "
+ "would have printed on stderr on its target platform.\n",
+ detailsString);
+
+ this->Makefile->AddCacheDefinition(
+ internalRunOutputStdErrName, "PLEASE_FILL_OUT-NOTFOUND",
+ comment.c_str(), cmStateEnums::STRING);
+ cmState* state = this->Makefile->GetState();
+ cmValue existing =
+ state->GetCacheEntryValue(internalRunOutputStdErrName);
+ if (existing) {
+ state->SetCacheEntryProperty(internalRunOutputStdErrName, "ADVANCED",
+ "1");
+ }
+
+ error = true;
+ }
+ } else if (out) {
if (!this->Makefile->GetDefinition(internalRunOutputName)) {
// if the variables doesn't exist, create it with a helpful error text
// and mark it as advanced
@@ -317,7 +372,34 @@ void cmTryRunCommand::DoNotRunExecutable(const std::string& runArgs,
" to\n"
" the exit code (in many cases 0 for success), otherwise "
"enter \"FAILED_TO_RUN\".\n");
- if (out) {
+ if (stdOut || stdErr) {
+ if (stdOut) {
+ comment += internalRunOutputStdOutName;
+ comment +=
+ "\n contains the text the executable "
+ "would have printed on stdout.\n"
+ " If the executable would not have been able to run, set ";
+ comment += internalRunOutputStdOutName;
+ comment += " empty.\n"
+ " Otherwise check if the output is evaluated by the "
+ "calling CMake code. If so,\n"
+ " check what the source file would have printed when "
+ "called with the given arguments.\n";
+ }
+ if (stdErr) {
+ comment += internalRunOutputStdErrName;
+ comment +=
+ "\n contains the text the executable "
+ "would have printed on stderr.\n"
+ " If the executable would not have been able to run, set ";
+ comment += internalRunOutputStdErrName;
+ comment += " empty.\n"
+ " Otherwise check if the output is evaluated by the "
+ "calling CMake code. If so,\n"
+ " check what the source file would have printed when "
+ "called with the given arguments.\n";
+ }
+ } else if (out) {
comment += internalRunOutputName;
comment +=
"\n contains the text the executable "
@@ -330,8 +412,9 @@ void cmTryRunCommand::DoNotRunExecutable(const std::string& runArgs,
" check what the source file would have printed when "
"called with the given arguments.\n";
}
+
comment += "The ";
- comment += this->CompileResultVariable;
+ comment += compileResultVariable;
comment += " variable holds the build result for this try_run().\n\n"
"Source file : ";
comment += srcFile + "\n";
@@ -370,7 +453,35 @@ void cmTryRunCommand::DoNotRunExecutable(const std::string& runArgs,
return;
}
- if (out) {
+ if (stdOut || stdErr) {
+ if (stdOut) {
+ (*stdOut) = *this->Makefile->GetDefinition(internalRunOutputStdOutName);
+ }
+ if (stdErr) {
+ (*stdErr) = *this->Makefile->GetDefinition(internalRunOutputStdErrName);
+ }
+ } else if (out) {
(*out) = *this->Makefile->GetDefinition(internalRunOutputName);
}
}
+}
+
+bool cmTryRunCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.size() < 4) {
+ return false;
+ }
+
+ cmMakefile& mf = status.GetMakefile();
+
+ if (mf.GetCMakeInstance()->GetWorkingMode() == cmake::FIND_PACKAGE_MODE) {
+ mf.IssueMessage(
+ MessageType::FATAL_ERROR,
+ "The try_run() command is not supported in --find-package mode.");
+ return false;
+ }
+
+ TryRunCommandImpl tr(&mf);
+ return tr.TryRunCode(args);
+}
diff --git a/Source/cmTryRunCommand.h b/Source/cmTryRunCommand.h
index d45acd8..38e3638 100644
--- a/Source/cmTryRunCommand.h
+++ b/Source/cmTryRunCommand.h
@@ -7,47 +7,7 @@
#include <string>
#include <vector>
-#include <cm/memory>
-
-#include "cmCommand.h"
-#include "cmCoreTryCompile.h"
-
class cmExecutionStatus;
-/** \class cmTryRunCommand
- * \brief Specifies where to install some files
- *
- * cmTryRunCommand is used to test if source code can be compiled
- */
-class cmTryRunCommand : public cmCoreTryCompile
-{
-public:
- /**
- * This is a virtual constructor for the command.
- */
- std::unique_ptr<cmCommand> Clone() override
- {
- return cm::make_unique<cmTryRunCommand>();
- }
-
- /**
- * This is called when the command is first encountered in
- * the CMakeLists.txt file.
- */
- bool InitialPass(std::vector<std::string> const& args,
- cmExecutionStatus& status) override;
-
-private:
- void RunExecutable(const std::string& runArgs,
- std::string* runOutputContents);
- void DoNotRunExecutable(const std::string& runArgs,
- const std::string& srcFile,
- std::string* runOutputContents);
-
- std::string CompileResultVariable;
- std::string RunResultVariable;
- std::string OutputVariable;
- std::string RunOutputVariable;
- std::string CompileOutputVariable;
- std::string WorkingDirectory;
-};
+bool cmTryRunCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index 9f3d620..4c1fa01 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -354,6 +354,18 @@ std::ostream& cmVisualStudio10TargetGenerator::Elem::WriteString(
void cmVisualStudio10TargetGenerator::Generate()
{
+ for (std::string const& config : this->Configurations) {
+ this->GeneratorTarget->CheckCxxModuleStatus(config);
+ }
+
+ if (this->GeneratorTarget->HaveCxx20ModuleSources()) {
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat("The \"", this->GeneratorTarget->GetName(),
+ "\" target contains C++ module sources which are not supported "
+ "by the generator"));
+ }
+
this->ProjectType = computeProjectType(this->GeneratorTarget);
this->Managed = this->ProjectType == VsProjectType::csproj;
const std::string ProjectFileExtension =
@@ -957,6 +969,10 @@ void cmVisualStudio10TargetGenerator::WriteSdkStyleProjectFile(
std::string outDir = this->GeneratorTarget->GetDirectory(config) + "/";
ConvertToWindowsSlash(outDir);
e1.Element("OutputPath", outDir);
+
+ Options& o = *(this->ClOptions[config]);
+ OptionsHelper oh(o, e1);
+ oh.OutputFlagMap();
}
this->WriteDotNetDocumentationFile(e0);
@@ -1507,6 +1523,10 @@ void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValues(
this->ASanEnabledConfigurations.end()) {
e1.Element("EnableAsan", "true");
}
+ if (this->FuzzerEnabledConfigurations.find(config) !=
+ this->FuzzerEnabledConfigurations.end()) {
+ e1.Element("EnableFuzzer", "true");
+ }
{
auto s = this->SpectreMitigation.find(config);
if (s != this->SpectreMitigation.end()) {
@@ -2875,7 +2895,7 @@ void cmVisualStudio10TargetGenerator::WritePathAndIncrementalLinkOptions(
Elem& e0)
{
cmStateEnums::TargetType ttype = this->GeneratorTarget->GetType();
- if (ttype > cmStateEnums::GLOBAL_TARGET) {
+ if (ttype > cmStateEnums::INTERFACE_LIBRARY) {
return;
}
if (this->ProjectType == VsProjectType::csproj) {
@@ -3117,6 +3137,7 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions(
this->LangForClCompile = langForClCompile;
if (!langForClCompile.empty()) {
this->LocalGenerator->AddLanguageFlags(flags, this->GeneratorTarget,
+ cmBuildStep::Compile,
langForClCompile, configName);
this->LocalGenerator->AddCompileOptions(flags, this->GeneratorTarget,
langForClCompile, configName);
@@ -3128,10 +3149,17 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions(
}
// Check if ASan is enabled.
- if (flags.find("/fsanitize=address") != std::string::npos) {
+ if (flags.find("/fsanitize=address") != std::string::npos ||
+ flags.find("-fsanitize=address") != std::string::npos) {
this->ASanEnabledConfigurations.insert(configName);
}
+ // Check if (lib)Fuzzer is enabled.
+ if (flags.find("/fsanitize=fuzzer") != std::string::npos ||
+ flags.find("-fsanitize=fuzzer") != std::string::npos) {
+ this->FuzzerEnabledConfigurations.insert(configName);
+ }
+
// Precompile Headers
std::string pchHeader =
this->GeneratorTarget->GetPchHeader(configName, linkLanguage);
@@ -3173,7 +3201,9 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions(
// anymore, because cmGeneratorTarget may not be aware that the
// target uses C++/CLI.
if (flags.find("/clr") != std::string::npos ||
- defineFlags.find("/clr") != std::string::npos) {
+ flags.find("-clr") != std::string::npos ||
+ defineFlags.find("/clr") != std::string::npos ||
+ defineFlags.find("-clr") != std::string::npos) {
if (configName == this->Configurations[0]) {
std::string message = "For the target \"" +
this->GeneratorTarget->GetName() +
@@ -3492,8 +3522,8 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaOptions(
// Get compile flags for CUDA in this directory.
std::string flags;
- this->LocalGenerator->AddLanguageFlags(flags, this->GeneratorTarget, "CUDA",
- configName);
+ this->LocalGenerator->AddLanguageFlags(
+ flags, this->GeneratorTarget, cmBuildStep::Compile, "CUDA", configName);
this->LocalGenerator->AddCompileOptions(flags, this->GeneratorTarget, "CUDA",
configName);
@@ -3685,21 +3715,28 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaLinkOptions(
this->GeneratorTarget->GetLinkOptions(linkOpts, configName, "CUDA");
// LINK_OPTIONS are escaped.
this->LocalGenerator->AppendCompileOptions(linkFlags, linkOpts);
+
+ cmComputeLinkInformation* pcli =
+ this->GeneratorTarget->GetLinkInformation(configName);
+ if (doDeviceLinking && pcli) {
+
+ cmLinkLineDeviceComputer computer(
+ this->LocalGenerator,
+ this->LocalGenerator->GetStateSnapshot().GetDirectory());
+ std::string ignored_;
+ this->LocalGenerator->GetDeviceLinkFlags(computer, configName, ignored_,
+ linkFlags, ignored_, ignored_,
+ this->GeneratorTarget);
+
+ this->LocalGenerator->AddLanguageFlagsForLinking(
+ linkFlags, this->GeneratorTarget, "CUDA", configName);
+ }
cudaLinkOptions.AppendFlagString("AdditionalOptions", linkFlags);
// For static libraries that have device linking enabled compute
// the libraries
if (this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY &&
doDeviceLinking) {
- cmComputeLinkInformation* pcli =
- this->GeneratorTarget->GetLinkInformation(configName);
- if (!pcli) {
- cmSystemTools::Error(
- "CMake can not compute cmComputeLinkInformation for target: " +
- this->Name);
- return false;
- }
-
cmComputeLinkInformation& cli = *pcli;
cmLinkLineDeviceComputer computer(
this->LocalGenerator,
@@ -3757,7 +3794,8 @@ bool cmVisualStudio10TargetGenerator::ComputeMasmOptions(
std::string flags;
this->LocalGenerator->AddLanguageFlags(flags, this->GeneratorTarget,
- "ASM_MASM", configName);
+ cmBuildStep::Compile, "ASM_MASM",
+ configName);
masmOptions.Parse(flags);
@@ -3809,7 +3847,8 @@ bool cmVisualStudio10TargetGenerator::ComputeNasmOptions(
std::string flags;
this->LocalGenerator->AddLanguageFlags(flags, this->GeneratorTarget,
- "ASM_NASM", configName);
+ cmBuildStep::Compile, "ASM_NASM",
+ configName);
flags += " -f";
flags += this->Makefile->GetSafeDefinition("CMAKE_ASM_NASM_OBJECT_FORMAT");
nasmOptions.Parse(flags);
diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h
index 8d777a3..17dcecd 100644
--- a/Source/cmVisualStudio10TargetGenerator.h
+++ b/Source/cmVisualStudio10TargetGenerator.h
@@ -231,6 +231,7 @@ private:
bool TargetCompileAsWinRT;
std::set<std::string> IPOEnabledConfigurations;
std::set<std::string> ASanEnabledConfigurations;
+ std::set<std::string> FuzzerEnabledConfigurations;
std::map<std::string, std::string> SpectreMitigation;
cmGlobalVisualStudio10Generator* const GlobalGenerator;
cmLocalVisualStudio10Generator* const LocalGenerator;
diff --git a/Source/cmVisualStudioGeneratorOptions.cxx b/Source/cmVisualStudioGeneratorOptions.cxx
index 00c65ed..16584f5 100644
--- a/Source/cmVisualStudioGeneratorOptions.cxx
+++ b/Source/cmVisualStudioGeneratorOptions.cxx
@@ -161,71 +161,12 @@ bool cmVisualStudioGeneratorOptions::UsingSBCS() const
void cmVisualStudioGeneratorOptions::FixCudaCodeGeneration()
{
- // Extract temporary values stored by our flag table.
- FlagValue arch = this->TakeFlag("cmake-temp-arch");
- FlagValue code = this->TakeFlag("cmake-temp-code");
- FlagValue gencode = this->TakeFlag("cmake-temp-gencode");
-
- // No -code allowed without -arch.
- if (arch.empty()) {
- code.clear();
- }
-
- // Create a CodeGeneration field with [arch],[code] syntax in each entry.
- // CUDA will convert it to `-gencode=arch=[arch],code="[code],[arch]"`.
- FlagValue& result = this->FlagMap["CodeGeneration"];
-
- // If there are no flags, leave the CodeGeneration field empty.
- if (arch.empty() && gencode.empty()) {
- return;
- }
-
- // First entries for the -arch=<arch> [-code=<code>,...] pair.
- if (!arch.empty()) {
- std::string arch_name = arch[0];
- if (arch_name == "all" || arch_name == "all-major" ||
- arch_name == "native") {
- AppendFlagString("AdditionalOptions", "-arch=" + arch_name);
- return;
- }
- std::vector<std::string> codes;
- if (!code.empty()) {
- codes = cmTokenize(code[0], ",");
- }
- if (codes.empty()) {
- codes.push_back(arch_name);
- // nvcc -arch=<arch> has a special case that allows a real
- // architecture to be specified instead of a virtual arch.
- // It translates to -arch=<virtual> -code=<real>.
- cmSystemTools::ReplaceString(arch_name, "sm_", "compute_");
- }
- for (std::string const& c : codes) {
- std::string entry = arch_name + "," + c;
- result.push_back(entry);
- }
- }
-
- // Now add entries for the following signatures:
- // -gencode=<arch>,<code>
- // -gencode=<arch>,[<code1>,<code2>]
- // -gencode=<arch>,"<code1>,<code2>"
- for (std::string const& e : gencode) {
- std::string entry = e;
- cmSystemTools::ReplaceString(entry, "arch=", "");
- cmSystemTools::ReplaceString(entry, "code=", "");
- cmSystemTools::ReplaceString(entry, "[", "");
- cmSystemTools::ReplaceString(entry, "]", "");
- cmSystemTools::ReplaceString(entry, "\"", "");
-
- std::vector<std::string> codes = cmTokenize(entry, ",");
- if (codes.size() >= 2) {
- auto gencode_arch = cm::cbegin(codes);
- for (auto ci = gencode_arch + 1; ci != cm::cend(codes); ++ci) {
- std::string code_entry = *gencode_arch + "," + *ci;
- result.push_back(code_entry);
- }
- }
- }
+ // Create an empty CodeGeneration field, and pass the the actual
+ // compile flags via additional options so that we have consistent
+ // behavior and avoid issues with MSBuild extensions injecting
+ // virtual code when we request real only.
+ FlagValue& code_gen_flag = this->FlagMap["CodeGeneration"];
+ code_gen_flag = "";
}
void cmVisualStudioGeneratorOptions::FixManifestUACFlags()
diff --git a/Source/cmXCodeScheme.cxx b/Source/cmXCodeScheme.cxx
index adc500a..a62015f 100644
--- a/Source/cmXCodeScheme.cxx
+++ b/Source/cmXCodeScheme.cxx
@@ -147,7 +147,15 @@ void cmXCodeScheme::WriteLaunchAction(cmXMLWriter& xout,
"Xcode.DebuggerFoundation.Debugger.LLDB");
xout.Attribute("selectedLauncherIdentifier",
"Xcode.DebuggerFoundation.Launcher.LLDB");
- xout.Attribute("launchStyle", "0");
+ {
+ cmValue launchMode =
+ this->Target->GetTarget()->GetProperty("XCODE_SCHEME_LAUNCH_MODE");
+ std::string value = "0"; // == 'AUTO'
+ if (launchMode && *launchMode == "WAIT") {
+ value = "1";
+ }
+ xout.Attribute("launchStyle", value);
+ }
WriteCustomWorkingDirectory(xout, configuration);
xout.Attribute("ignoresPersistentStateOnLaunch", "NO");
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index 1c1cab3..9b2b119 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -3,6 +3,7 @@
#include "cmake.h"
#include <algorithm>
+#include <array>
#include <cstdio>
#include <cstdlib>
#include <cstring>
@@ -951,7 +952,7 @@ void cmake::SetArgs(const std::vector<std::string>& args)
CommandArgument::Values::One,
[](std::string const& value, cmake* state) -> bool {
const auto logLevel = StringToLogLevel(value);
- if (logLevel == LogLevel::LOG_UNDEFINED) {
+ if (logLevel == Message::LogLevel::LOG_UNDEFINED) {
cmSystemTools::Error(
"Invalid level specified for --log-level");
return false;
@@ -967,7 +968,7 @@ void cmake::SetArgs(const std::vector<std::string>& args)
CommandArgument::Values::One,
[](std::string const& value, cmake* state) -> bool {
const auto logLevel = StringToLogLevel(value);
- if (logLevel == LogLevel::LOG_UNDEFINED) {
+ if (logLevel == Message::LogLevel::LOG_UNDEFINED) {
cmSystemTools::Error(
"Invalid level specified for --loglevel");
return false;
@@ -1282,9 +1283,13 @@ void cmake::SetArgs(const std::vector<std::string>& args)
cmCMakePresetsGraph presetsGraph;
auto result = presetsGraph.ReadProjectPresets(this->GetHomeDirectory());
if (result != cmCMakePresetsGraph::ReadFileResult::READ_OK) {
- cmSystemTools::Error(
+ std::string errorMsg =
cmStrCat("Could not read presets from ", this->GetHomeDirectory(),
- ": ", cmCMakePresetsGraph::ResultToString(result)));
+ ": ", cmCMakePresetsGraph::ResultToString(result));
+ if (!presetsGraph.errors.empty()) {
+ errorMsg = cmStrCat(errorMsg, "\nErrors:\n", presetsGraph.errors);
+ }
+ cmSystemTools::Error(errorMsg);
return;
}
@@ -1398,23 +1403,52 @@ void cmake::SetArgs(const std::vector<std::string>& args)
#endif
}
-cmake::LogLevel cmake::StringToLogLevel(const std::string& levelStr)
-{
- using LevelsPair = std::pair<std::string, LogLevel>;
- static const std::vector<LevelsPair> levels = {
- { "error", LogLevel::LOG_ERROR }, { "warning", LogLevel::LOG_WARNING },
- { "notice", LogLevel::LOG_NOTICE }, { "status", LogLevel::LOG_STATUS },
- { "verbose", LogLevel::LOG_VERBOSE }, { "debug", LogLevel::LOG_DEBUG },
- { "trace", LogLevel::LOG_TRACE }
+namespace {
+using LevelsPair = std::pair<cm::string_view, Message::LogLevel>;
+using LevelsPairArray = std::array<LevelsPair, 7>;
+const LevelsPairArray& getStringToLogLevelPairs()
+{
+ static const LevelsPairArray levels = {
+ { { "error", Message::LogLevel::LOG_ERROR },
+ { "warning", Message::LogLevel::LOG_WARNING },
+ { "notice", Message::LogLevel::LOG_NOTICE },
+ { "status", Message::LogLevel::LOG_STATUS },
+ { "verbose", Message::LogLevel::LOG_VERBOSE },
+ { "debug", Message::LogLevel::LOG_DEBUG },
+ { "trace", Message::LogLevel::LOG_TRACE } }
};
+ return levels;
+}
+} // namespace
- const auto levelStrLowCase = cmSystemTools::LowerCase(levelStr);
+Message::LogLevel cmake::StringToLogLevel(cm::string_view levelStr)
+{
+ const LevelsPairArray& levels = getStringToLogLevelPairs();
+
+ const auto levelStrLowCase =
+ cmSystemTools::LowerCase(std::string{ levelStr });
+ // NOLINTNEXTLINE(readability-qualified-auto)
const auto it = std::find_if(levels.cbegin(), levels.cend(),
[&levelStrLowCase](const LevelsPair& p) {
return p.first == levelStrLowCase;
});
- return (it != levels.cend()) ? it->second : LogLevel::LOG_UNDEFINED;
+ return (it != levels.cend()) ? it->second : Message::LogLevel::LOG_UNDEFINED;
+}
+
+std::string cmake::LogLevelToString(Message::LogLevel level)
+{
+ const LevelsPairArray& levels = getStringToLogLevelPairs();
+
+ // NOLINTNEXTLINE(readability-qualified-auto)
+ const auto it =
+ std::find_if(levels.cbegin(), levels.cend(),
+ [&level](const LevelsPair& p) { return p.second == level; });
+ const cm::string_view levelStrLowerCase =
+ (it != levels.cend()) ? it->first : "undefined";
+ std::string levelStrUpperCase =
+ cmSystemTools::UpperCase(std::string{ levelStrLowerCase });
+ return levelStrUpperCase;
}
cmake::TraceFormat cmake::StringToTraceFormat(const std::string& traceStr)
diff --git a/Source/cmake.h b/Source/cmake.h
index 3c6af17..a631647 100644
--- a/Source/cmake.h
+++ b/Source/cmake.h
@@ -119,19 +119,6 @@ public:
FIND_PACKAGE_MODE
};
- /** \brief Define log level constants. */
- enum LogLevel
- {
- LOG_UNDEFINED,
- LOG_ERROR,
- LOG_WARNING,
- LOG_NOTICE,
- LOG_STATUS,
- LOG_VERBOSE,
- LOG_DEBUG,
- LOG_TRACE
- };
-
/** \brief Define supported trace formats **/
enum TraceFormat
{
@@ -469,9 +456,10 @@ public:
bool WasLogLevelSetViaCLI() const { return this->LogLevelWasSetViaCLI; }
//! Get the selected log level for `message()` commands during the cmake run.
- LogLevel GetLogLevel() const { return this->MessageLogLevel; }
- void SetLogLevel(LogLevel level) { this->MessageLogLevel = level; }
- static LogLevel StringToLogLevel(const std::string& levelStr);
+ Message::LogLevel GetLogLevel() const { return this->MessageLogLevel; }
+ void SetLogLevel(Message::LogLevel level) { this->MessageLogLevel = level; }
+ static Message::LogLevel StringToLogLevel(cm::string_view levelStr);
+ static std::string LogLevelToString(Message::LogLevel level);
static TraceFormat StringToTraceFormat(const std::string& levelStr);
bool HasCheckInProgress() const
@@ -732,7 +720,7 @@ private:
std::set<std::string> DebugFindPkgs;
std::set<std::string> DebugFindVars;
- LogLevel MessageLogLevel = LogLevel::LOG_STATUS;
+ Message::LogLevel MessageLogLevel = Message::LogLevel::LOG_STATUS;
bool LogLevelWasSetViaCLI = false;
bool LogContext = false;
diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx
index f931e9d..6f3d0eb 100644
--- a/Source/cmakemain.cxx
+++ b/Source/cmakemain.cxx
@@ -71,7 +71,7 @@ const char* cmDocumentationUsageNote[][2] = {
const char* cmDocumentationOptions[][2] = {
CMAKE_STANDARD_OPTIONS_TABLE,
{ "--preset <preset>,--preset=<preset>", "Specify a configure preset." },
- { "--list-presets", "List available presets." },
+ { "--list-presets[=<type>]", "List available presets." },
{ "-E", "CMake command mode." },
{ "-L[A][H]", "List non-advanced cached variables." },
{ "--fresh",
@@ -82,9 +82,9 @@ const char* cmDocumentationOptions[][2] = {
{ "-N", "View mode only." },
{ "-P <file>", "Process script mode." },
{ "--find-package", "Legacy pkg-config like mode. Do not use." },
- { "--graphviz=[file]",
- "Generate graphviz of dependencies, see "
- "CMakeGraphVizOptions.cmake for more." },
+ { "--graphviz=<file>",
+ "Generate graphviz of dependencies, see CMakeGraphVizOptions.cmake for "
+ "more." },
{ "--system-information [file]", "Dump information about this system." },
{ "--log-level=<ERROR|WARNING|NOTICE|STATUS|VERBOSE|DEBUG|TRACE>",
"Set the verbosity of messages from CMake files. "
@@ -109,8 +109,7 @@ const char* cmDocumentationOptions[][2] = {
{ "--warn-uninitialized", "Warn about uninitialized values." },
{ "--no-warn-unused-cli", "Don't warn about command line options." },
{ "--check-system-vars",
- "Find problems with variable usage in system "
- "files." },
+ "Find problems with variable usage in system files." },
{ "--compile-no-warning-as-error",
"Ignore COMPILE_WARNING_AS_ERROR property and "
"CMAKE_COMPILE_WARNING_AS_ERROR variable." },
@@ -616,7 +615,7 @@ int do_build(int ac, char const* const* av)
" <dir> = Project binary directory to be built.\n"
" --preset <preset>, --preset=<preset>\n"
" = Specify a build preset.\n"
- " --list-presets\n"
+ " --list-presets[=<type>]\n"
" = List available build presets.\n"
" --parallel [<jobs>], -j [<jobs>]\n"
" = Build in parallel using the given number of jobs. \n"
@@ -627,14 +626,14 @@ int do_build(int ac, char const* const* av)
" specifies a default parallel level when this "
"option\n"
" is not given.\n"
- " --target <tgt>..., -t <tgt>... \n"
+ " -t <tgt>..., --target <tgt>...\n"
" = Build <tgt> instead of default targets.\n"
" --config <cfg> = For multi-configuration tools, choose <cfg>.\n"
" --clean-first = Build target 'clean' first, then build.\n"
" (To clean only, use --target 'clean'.)\n"
" --resolve-package-references={on|only|off}\n"
" = Restore/resolve package references during build.\n"
- " --verbose, -v = Enable verbose output - if supported - including\n"
+ " -v, --verbose = Enable verbose output - if supported - including\n"
" the build commands to be executed. \n"
" -- = Pass remaining options to the native tool.\n"
;
diff --git a/Source/cmcldeps.cxx b/Source/cmcldeps.cxx
index 8921aa0..69eb19e 100644
--- a/Source/cmcldeps.cxx
+++ b/Source/cmcldeps.cxx
@@ -273,6 +273,7 @@ int main()
std::string clrest = rest;
// rc: /fo x.dir\x.rc.res -> cl: /out:x.dir\x.rc.res.dep.obj
clrest = replace(clrest, "/fo ", "/out:");
+ clrest = replace(clrest, "-fo ", "-out:");
clrest = replace(clrest, objfile, objfile + ".dep.obj ");
cl = "\"" + cl + "\" /P /DRC_INVOKED /TC ";
diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx
index 9ab39f1..00c9bda 100644
--- a/Source/cmcmd.cxx
+++ b/Source/cmcmd.cxx
@@ -791,6 +791,10 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args,
}
if (args[1] == "env") {
+#ifndef CMAKE_BOOTSTRAP
+ cmSystemTools::EnvDiff env;
+#endif
+
auto ai = args.cbegin() + 2;
auto ae = args.cend();
for (; ai != ae; ++ai) {
@@ -803,16 +807,40 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args,
}
if (cmHasLiteralPrefix(a, "--unset=")) {
// Unset environment variable.
+#ifdef CMAKE_BOOTSTRAP
cmSystemTools::UnPutEnv(a.substr(8));
+#else
+ env.UnPutEnv(a.substr(8));
+#endif
+ } else if (a == "--modify") {
+#ifdef CMAKE_BOOTSTRAP
+ std::cerr
+ << "cmake -E env: --modify not available during bootstrapping\n";
+ return 1;
+#else
+ if (++ai == ae) {
+ std::cerr << "cmake -E env: --modify missing a parameter\n";
+ return 1;
+ }
+ std::string const& op = *ai;
+ if (!env.ParseOperation(op)) {
+ std::cerr << "cmake -E env: invalid parameter to --modify: " << op
+ << '\n';
+ return 1;
+ }
+#endif
} else if (!a.empty() && a[0] == '-') {
// Environment variable and command names cannot start in '-',
// so this must be an unknown option.
- std::cerr << "cmake -E env: unknown option '" << a << '\''
- << std::endl;
+ std::cerr << "cmake -E env: unknown option '" << a << "'\n";
return 1;
} else if (a.find('=') != std::string::npos) {
// Set environment variable.
+#ifdef CMAKE_BOOTSTRAP
cmSystemTools::PutEnv(a);
+#else
+ env.PutEnv(a);
+#endif
} else {
// This is the beginning of the command.
break;
@@ -820,10 +848,14 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args,
}
if (ai == ae) {
- std::cerr << "cmake -E env: no command given" << std::endl;
+ std::cerr << "cmake -E env: no command given\n";
return 1;
}
+#ifndef CMAKE_BOOTSTRAP
+ env.ApplyToCurrentEnv();
+#endif
+
// Execute command from remaining arguments.
std::vector<std::string> cmd(ai, ae);
int retval;
@@ -2242,13 +2274,18 @@ bool cmVSLink::Parse(std::vector<std::string>::const_iterator argBeg,
// Parse the link command to extract information we need.
for (; arg != argEnd; ++arg) {
if (cmSystemTools::Strucmp(arg->c_str(), "/INCREMENTAL:YES") == 0 ||
- cmSystemTools::Strucmp(arg->c_str(), "/INCREMENTAL") == 0) {
+ cmSystemTools::Strucmp(arg->c_str(), "-INCREMENTAL:YES") == 0 ||
+ cmSystemTools::Strucmp(arg->c_str(), "/INCREMENTAL") == 0 ||
+ cmSystemTools::Strucmp(arg->c_str(), "-INCREMENTAL") == 0) {
this->Incremental = true;
- } else if (cmSystemTools::Strucmp(arg->c_str(), "/MANIFEST:NO") == 0) {
+ } else if (cmSystemTools::Strucmp(arg->c_str(), "/MANIFEST:NO") == 0 ||
+ cmSystemTools::Strucmp(arg->c_str(), "-MANIFEST:NO") == 0) {
this->LinkGeneratesManifest = false;
- } else if (cmHasLiteralPrefix(*arg, "/Fe")) {
+ } else if (cmHasLiteralPrefix(*arg, "/Fe") ||
+ cmHasLiteralPrefix(*arg, "-Fe")) {
this->TargetFile = arg->substr(3);
- } else if (cmHasLiteralPrefix(*arg, "/out:")) {
+ } else if (cmHasLiteralPrefix(*arg, "/out:") ||
+ cmHasLiteralPrefix(*arg, "-out:")) {
this->TargetFile = arg->substr(5);
}
}
diff --git a/Source/kwsys/Directory.cxx b/Source/kwsys/Directory.cxx
index d520c14..f239576 100644
--- a/Source/kwsys/Directory.cxx
+++ b/Source/kwsys/Directory.cxx
@@ -43,12 +43,12 @@ public:
{
std::string Name;
#if defined(_WIN32) && !defined(__CYGWIN__)
- _wfinddata_t FindData;
+ WIN32_FIND_DATAW FindData;
#endif
FileData(std::string name
#if defined(_WIN32) && !defined(__CYGWIN__)
,
- _wfinddata_t data
+ WIN32_FIND_DATAW data
#endif
)
: Name(std::move(name))
@@ -115,8 +115,8 @@ std::string Directory::GetFilePath(std::size_t i) const
bool Directory::FileIsDirectory(std::size_t i) const
{
#if defined(_WIN32) && !defined(__CYGWIN__)
- _wfinddata_t const& data = this->Internal->Files[i].FindData;
- return (data.attrib & FILE_ATTRIBUTE_DIRECTORY) != 0;
+ auto const& data = this->Internal->Files[i].FindData;
+ return (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
#else
std::string const& path = this->GetFilePath(i);
return kwsys::SystemTools::FileIsDirectory(path);
@@ -127,9 +127,9 @@ bool Directory::FileIsSymlink(std::size_t i) const
{
std::string const& path = this->GetFilePath(i);
#if defined(_WIN32) && !defined(__CYGWIN__)
- _wfinddata_t const& data = this->Internal->Files[i].FindData;
+ auto const& data = this->Internal->Files[i].FindData;
return kwsys::SystemTools::FileIsSymlinkWithAttr(
- Encoding::ToWindowsExtendedPath(path), data.attrib);
+ Encoding::ToWindowsExtendedPath(path), data.dwFileAttributes);
#else
return kwsys::SystemTools::FileIsSymlink(path);
#endif
@@ -157,7 +157,7 @@ namespace KWSYS_NAMESPACE {
Status Directory::Load(std::string const& name, std::string* errorMessage)
{
this->Clear();
- intptr_t srchHandle;
+ HANDLE srchHandle;
char* buf;
size_t bufLength;
size_t n = name.size();
@@ -176,14 +176,14 @@ Status Directory::Load(std::string const& name, std::string* errorMessage)
snprintf(buf, bufLength, "%s/*", name.c_str());
}
}
- struct _wfinddata_t data; // data of current file
+ WIN32_FIND_DATAW data; // data of current file
// Now put them into the file array
srchHandle =
- _wfindfirst((wchar_t*)Encoding::ToWindowsExtendedPath(buf).c_str(), &data);
+ FindFirstFileW(Encoding::ToWindowsExtendedPath(buf).c_str(), &data);
delete[] buf;
- if (srchHandle == -1) {
+ if (srchHandle == INVALID_HANDLE_VALUE) {
Status status = Status::POSIX_errno();
if (errorMessage) {
*errorMessage = status.GetString();
@@ -193,10 +193,11 @@ Status Directory::Load(std::string const& name, std::string* errorMessage)
// Loop through names
do {
- this->Internal->Files.emplace_back(Encoding::ToNarrow(data.name), data);
- } while (_wfindnext(srchHandle, &data) != -1);
+ this->Internal->Files.emplace_back(Encoding::ToNarrow(data.cFileName),
+ data);
+ } while (FindNextFileW(srchHandle, &data));
this->Internal->Path = name;
- if (_findclose(srchHandle) == -1) {
+ if (!FindClose(srchHandle)) {
Status status = Status::POSIX_errno();
if (errorMessage) {
*errorMessage = status.GetString();
@@ -209,7 +210,7 @@ Status Directory::Load(std::string const& name, std::string* errorMessage)
unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name,
std::string* errorMessage)
{
- intptr_t srchHandle;
+ HANDLE srchHandle;
char* buf;
size_t bufLength;
size_t n = name.size();
@@ -222,13 +223,13 @@ unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name,
buf = new char[n + 2 + 1];
snprintf(buf, bufLength, "%s/*", name.c_str());
}
- struct _wfinddata_t data; // data of current file
+ WIN32_FIND_DATAW data; // data of current file
// Now put them into the file array
- srchHandle = _wfindfirst((wchar_t*)Encoding::ToWide(buf).c_str(), &data);
+ srchHandle = FindFirstFileW(Encoding::ToWide(buf).c_str(), &data);
delete[] buf;
- if (srchHandle == -1) {
+ if (srchHandle == INVALID_HANDLE_VALUE) {
if (errorMessage) {
if (unsigned int errorId = GetLastError()) {
LPSTR message = nullptr;
@@ -250,8 +251,8 @@ unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name,
unsigned long count = 0;
do {
count++;
- } while (_wfindnext(srchHandle, &data) != -1);
- _findclose(srchHandle);
+ } while (FindNextFileW(srchHandle, &data));
+ FindClose(srchHandle);
return count;
}
diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx
index 5889a4b..a20901c 100644
--- a/Source/kwsys/SystemTools.cxx
+++ b/Source/kwsys/SystemTools.cxx
@@ -536,9 +536,11 @@ public:
StringMap TranslationMap;
#endif
#ifdef _WIN32
- static std::string GetCasePathName(std::string const& pathIn);
+ static std::string GetCasePathName(std::string const& pathIn,
+ bool const cache);
static std::string GetActualCaseForPathCached(std::string const& path);
static const char* GetEnvBuffered(const char* key);
+ std::map<std::string, std::string, SystemToolsPathCaseCmp> FindFileMap;
std::map<std::string, std::string, SystemToolsPathCaseCmp> PathCaseMap;
std::map<std::string, std::string> EnvMap;
#endif
@@ -571,7 +573,8 @@ public:
static SystemToolsStatic* SystemToolsStatics;
#ifdef _WIN32
-std::string SystemToolsStatic::GetCasePathName(std::string const& pathIn)
+std::string SystemToolsStatic::GetCasePathName(std::string const& pathIn,
+ bool const cache)
{
std::string casePath;
@@ -623,14 +626,31 @@ std::string SystemToolsStatic::GetCasePathName(std::string const& pathIn)
} else {
std::string test_str = casePath;
test_str += path_components[idx];
- WIN32_FIND_DATAW findData;
- HANDLE hFind =
- ::FindFirstFileW(Encoding::ToWide(test_str).c_str(), &findData);
- if (INVALID_HANDLE_VALUE != hFind) {
- path_components[idx] = Encoding::ToNarrow(findData.cFileName);
- ::FindClose(hFind);
- } else {
- converting = false;
+
+ bool found_in_cache = false;
+ if (cache) {
+ auto const it = SystemToolsStatics->FindFileMap.find(test_str);
+ if (it != SystemToolsStatics->FindFileMap.end()) {
+ path_components[idx] = it->second;
+ found_in_cache = true;
+ }
+ }
+
+ if (!found_in_cache) {
+ WIN32_FIND_DATAW findData;
+ HANDLE hFind =
+ ::FindFirstFileW(Encoding::ToWide(test_str).c_str(), &findData);
+ if (INVALID_HANDLE_VALUE != hFind) {
+ auto case_file_name = Encoding::ToNarrow(findData.cFileName);
+ if (cache) {
+ SystemToolsStatics->FindFileMap.emplace(test_str,
+ case_file_name);
+ }
+ path_components[idx] = std::move(case_file_name);
+ ::FindClose(hFind);
+ } else {
+ converting = false;
+ }
}
}
}
@@ -642,19 +662,16 @@ std::string SystemToolsStatic::GetCasePathName(std::string const& pathIn)
std::string SystemToolsStatic::GetActualCaseForPathCached(std::string const& p)
{
- // Check to see if actual case has already been called
- // for this path, and the result is stored in the PathCaseMap
- auto& pcm = SystemToolsStatics->PathCaseMap;
- {
- auto itr = pcm.find(p);
- if (itr != pcm.end()) {
- return itr->second;
- }
- }
- std::string casePath = SystemToolsStatic::GetCasePathName(p);
- if (casePath.size() <= MAX_PATH) {
- pcm[p] = casePath;
+ std::string casePath;
+
+ auto it = SystemToolsStatics->PathCaseMap.find(p);
+ if (it != SystemToolsStatics->PathCaseMap.end()) {
+ casePath = it->second;
+ } else {
+ casePath = SystemToolsStatic::GetCasePathName(p, true);
+ SystemToolsStatics->PathCaseMap.emplace(p, casePath);
}
+
return casePath;
}
#endif
@@ -3067,17 +3084,14 @@ std::string SystemTools::GetRealPath(const std::string& path,
return ret;
}
-bool SystemTools::FileIsDirectory(const std::string& inName)
+// Remove any trailing slash from the name except in a root component.
+static const char* RemoveTrailingSlashes(
+ const std::string& inName, char (&local_buffer)[KWSYS_SYSTEMTOOLS_MAXPATH],
+ std::string& string_buffer)
{
- if (inName.empty()) {
- return false;
- }
size_t length = inName.size();
const char* name = inName.c_str();
- // Remove any trailing slash from the name except in a root component.
- char local_buffer[KWSYS_SYSTEMTOOLS_MAXPATH];
- std::string string_buffer;
size_t last = length - 1;
if (last > 0 && (name[last] == '/' || name[last] == '\\') &&
strcmp(name, "/") != 0 && name[last - 1] != ':') {
@@ -3091,6 +3105,19 @@ bool SystemTools::FileIsDirectory(const std::string& inName)
}
}
+ return name;
+}
+
+bool SystemTools::FileIsDirectory(const std::string& inName)
+{
+ if (inName.empty()) {
+ return false;
+ }
+
+ char local_buffer[KWSYS_SYSTEMTOOLS_MAXPATH];
+ std::string string_buffer;
+ const auto name = RemoveTrailingSlashes(inName, local_buffer, string_buffer);
+
// Now check the file node type.
#if defined(_WIN32)
DWORD attr =
@@ -3107,9 +3134,21 @@ bool SystemTools::FileIsDirectory(const std::string& inName)
}
}
-bool SystemTools::FileIsExecutable(const std::string& name)
+bool SystemTools::FileIsExecutable(const std::string& inName)
{
- return !FileIsDirectory(name) && TestFileAccess(name, TEST_FILE_EXECUTE);
+#ifdef _WIN32
+ char local_buffer[KWSYS_SYSTEMTOOLS_MAXPATH];
+ std::string string_buffer;
+ const auto name = RemoveTrailingSlashes(inName, local_buffer, string_buffer);
+ const auto attr =
+ GetFileAttributesW(Encoding::ToWindowsExtendedPath(name).c_str());
+
+ // On Windows any file that exists and is not a directory is considered
+ // readable and therefore also executable:
+ return attr != INVALID_FILE_ATTRIBUTES && !(attr & FILE_ATTRIBUTE_DIRECTORY);
+#else
+ return !FileIsDirectory(inName) && TestFileAccess(inName, TEST_FILE_EXECUTE);
+#endif
}
#if defined(_WIN32)
@@ -3655,7 +3694,7 @@ std::string SystemTools::RelativePath(const std::string& local,
std::string SystemTools::GetActualCaseForPath(const std::string& p)
{
#ifdef _WIN32
- return SystemToolsStatic::GetCasePathName(p);
+ return SystemToolsStatic::GetCasePathName(p, false);
#else
return p;
#endif