summaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
Diffstat (limited to 'Source')
-rw-r--r--Source/CMakeVersion.cmake6
-rw-r--r--Source/CTest/cmCTestRunTest.cxx11
-rw-r--r--Source/cmCoreTryCompile.cxx24
-rw-r--r--Source/cmDebugTools.h23
-rw-r--r--Source/cmDocumentation.cxx86
-rw-r--r--Source/cmDocumentation.h3
-rw-r--r--Source/cmExperimental.cxx11
-rw-r--r--Source/cmExperimental.h1
-rw-r--r--Source/cmExportCommand.cxx15
-rw-r--r--Source/cmGeneratorTarget.cxx182
-rw-r--r--Source/cmGeneratorTarget.h4
-rw-r--r--Source/cmGlobalVisualStudio7Generator.cxx8
-rw-r--r--Source/cmGlobalXCodeGenerator.cxx8
-rw-r--r--Source/cmInstallCommand.cxx25
-rw-r--r--Source/cmMakefileTargetGenerator.cxx8
-rw-r--r--Source/cmNinjaTargetGenerator.cxx44
-rw-r--r--Source/cmPolicies.h7
-rw-r--r--Source/cmTargetSourcesCommand.cxx31
-rw-r--r--Source/cmVisualStudio10TargetGenerator.cxx9
19 files changed, 310 insertions, 196 deletions
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index 23556d9..c1f5c25 100644
--- a/Source/CMakeVersion.cmake
+++ b/Source/CMakeVersion.cmake
@@ -1,8 +1,8 @@
# CMake version number components.
set(CMake_VERSION_MAJOR 3)
-set(CMake_VERSION_MINOR 27)
-set(CMake_VERSION_PATCH 20230928)
-#set(CMake_VERSION_RC 0)
+set(CMake_VERSION_MINOR 28)
+set(CMake_VERSION_PATCH 0)
+set(CMake_VERSION_RC 0)
set(CMake_VERSION_IS_DIRTY 0)
# Start with the full version number used in tags. It has no dev info.
diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx
index 4c57cf6..8ceb9db 100644
--- a/Source/CTest/cmCTestRunTest.cxx
+++ b/Source/CTest/cmCTestRunTest.cxx
@@ -791,11 +791,12 @@ bool cmCTestRunTest::ForkProcess()
timeout = this->CTest->GetGlobalTimeout();
}
- // Check CTEST_TEST_TIMEOUT.
- cmDuration ctestTestTimeout = this->CTest->GetTimeOut();
- if (ctestTestTimeout > cmDuration::zero() &&
- (!timeout || ctestTestTimeout < *timeout)) {
- timeout = ctestTestTimeout;
+ if (!timeout) {
+ // Check CTEST_TEST_TIMEOUT.
+ cmDuration ctestTestTimeout = this->CTest->GetTimeOut();
+ if (ctestTestTimeout > cmDuration::zero()) {
+ timeout = ctestTestTimeout;
+ }
}
}
diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx
index ee40bd5..67462f5 100644
--- a/Source/cmCoreTryCompile.cxx
+++ b/Source/cmCoreTryCompile.cxx
@@ -235,25 +235,16 @@ ArgumentParser::Continue cmCoreTryCompile::Arguments::SetSourceType(
this->SourceTypeContext = SourceType::Normal;
matched = true;
} else if (sourceType == "CXX_MODULE"_s) {
- bool const supportCxxModuleSources = cmExperimental::HasSupportEnabled(
- *this->Makefile, cmExperimental::Feature::CxxModuleCMakeApi);
- if (supportCxxModuleSources) {
- this->SourceTypeContext = SourceType::CxxModule;
- matched = true;
- }
+ this->SourceTypeContext = SourceType::CxxModule;
+ matched = true;
}
if (!matched && this->SourceTypeError.empty()) {
- bool const supportCxxModuleSources = cmExperimental::HasSupportEnabled(
- *this->Makefile, cmExperimental::Feature::CxxModuleCMakeApi);
- auto const* message = "'SOURCE'";
- if (supportCxxModuleSources) {
- message = "one of 'SOURCE' or 'CXX_MODULE'";
- }
// Only remember one error at a time; all other errors related to argument
// parsing are "indicate one error and return" anyways.
this->SourceTypeError =
- cmStrCat("Invalid 'SOURCE_TYPE' '", sourceType, "'; must be ", message);
+ cmStrCat("Invalid 'SOURCE_TYPE' '", sourceType,
+ "'; must be one of 'SOURCE' or 'CXX_MODULE'");
}
return ArgumentParser::Continue::Yes;
}
@@ -880,6 +871,13 @@ cm::optional<cmTryCompileResult> cmCoreTryCompile::TryCompileCode(
? "NEW"
: "OLD");
+ /* Set the appropriate policy information for C++ module support */
+ fprintf(fout, "cmake_policy(SET CMP0155 %s)\n",
+ this->Makefile->GetPolicyStatus(cmPolicies::CMP0155) ==
+ cmPolicies::NEW
+ ? "NEW"
+ : "OLD");
+
// Workaround for -Wl,-headerpad_max_install_names issue until we can avoid
// adding that flag in the platform and compiler language files
fprintf(fout,
diff --git a/Source/cmDebugTools.h b/Source/cmDebugTools.h
new file mode 100644
index 0000000..99c0c6b
--- /dev/null
+++ b/Source/cmDebugTools.h
@@ -0,0 +1,23 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <iostream>
+
+#define CM_DBG(expr) cm::dbg_impl(__FILE__, __LINE__, #expr, expr)
+
+namespace cm {
+
+namespace {
+
+template <typename T>
+T dbg_impl(const char* fname, int line, const char* expr, T value)
+{
+ std::cerr << fname << ':' << line << ": " << expr << " = " << value
+ << std::endl;
+ return value;
+}
+
+} // namespace
+
+} // namespace cm
diff --git a/Source/cmDocumentation.cxx b/Source/cmDocumentation.cxx
index 77c5295..db2a606 100644
--- a/Source/cmDocumentation.cxx
+++ b/Source/cmDocumentation.cxx
@@ -9,17 +9,20 @@
#include "cmsys/FStream.hxx"
#include "cmsys/Glob.hxx"
+#include "cmsys/RegularExpression.hxx"
#include "cmDocumentationEntry.h"
#include "cmDocumentationSection.h"
#include "cmRST.h"
+#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
#include "cmVersion.h"
namespace {
-const cmDocumentationEntry cmDocumentationStandardOptions[20] = {
+const cmDocumentationEntry cmDocumentationStandardOptions[21] = {
{ "-h,-H,--help,-help,-usage,/?", "Print usage information and exit." },
{ "--version,-version,/V [<file>]", "Print version number and exit." },
+ { "--help <keyword> [<file>]", "Print help for one keyword 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." },
@@ -92,6 +95,8 @@ bool cmDocumentation::PrintDocumentation(Type ht, std::ostream& os)
return this->PrintHelp(os);
case cmDocumentation::Full:
return this->PrintHelpFull(os);
+ case cmDocumentation::OneArbitrary:
+ return this->PrintHelpOneArbitrary(os);
case cmDocumentation::OneManual:
return this->PrintHelpOneManual(os);
case cmDocumentation::OneCommand:
@@ -176,6 +181,30 @@ void cmDocumentation::WarnFormFromFilename(
}
}
+std::string cmDocumentation::GeneralizeKeyword(std::string cname)
+{
+ std::map<std::string, const std::vector<std::string>> conversions;
+ std::vector<std::string> languages = {
+ "C", "CXX", "CSharp", "CUDA", "OBJC",
+ "OBJCXX", "Fortran", "HIP", "ISPC", "Swift",
+ "ASM", "ASM_NASM", "ASM_MARMASM", "ASM_MASM", "ASM-ATT"
+ };
+ std::vector<std::string> configs = { "DEBUG", "RELEASE", "RELWITHDEBINFO",
+ "MINSIZEREL" };
+ conversions.emplace("LANG", std::move(languages));
+ conversions.emplace("CONFIG", std::move(configs));
+ for (auto const& it : conversions) {
+ for (auto const& to_replace : it.second) {
+ cmsys::RegularExpression reg(
+ cmStrCat("(^|_)(", to_replace, ")(\\.|$|_)"));
+ if (reg.find(cname)) {
+ cname.replace(reg.start(2), to_replace.length(), it.first);
+ }
+ }
+ }
+ return cname;
+}
+
void cmDocumentation::addCommonStandardDocSections()
{
cmDocumentationSection sec{ "Options" };
@@ -237,10 +266,10 @@ bool cmDocumentation::CheckOptions(int argc, const char* const* argv,
(strcmp(argv[i], "-h") == 0) || (strcmp(argv[i], "-H") == 0)) {
help.HelpType = cmDocumentation::Help;
i += int(get_opt_argument(i + 1, help.Argument));
- help.Argument = cmSystemTools::LowerCase(help.Argument);
- // special case for single command
+ // special case for arbitrary keyword help
if (!help.Argument.empty()) {
- help.HelpType = cmDocumentation::OneCommand;
+ help.HelpType = cmDocumentation::OneArbitrary;
+ i += int(get_opt_argument(i + 1, help.Filename));
}
} else if (strcmp(argv[i], "--help-properties") == 0) {
help.HelpType = cmDocumentation::OneManual;
@@ -400,7 +429,7 @@ void cmDocumentation::GlobHelp(std::vector<std::string>& files,
{
cmsys::Glob gl;
std::string findExpr =
- cmSystemTools::GetCMakeRoot() + "/Help/" + pattern + ".rst";
+ cmStrCat(cmSystemTools::GetCMakeRoot(), "/Help/", pattern, ".rst");
if (gl.FindFiles(findExpr)) {
files = gl.GetFiles();
}
@@ -452,8 +481,8 @@ bool cmDocumentation::PrintHelpOneManual(std::ostream& os)
if (mlen > 3 && mname[mlen - 3] == '(' && mname[mlen - 1] == ')') {
mname = mname.substr(0, mlen - 3) + "." + mname[mlen - 2];
}
- if (this->PrintFiles(os, "manual/" + mname) ||
- this->PrintFiles(os, "manual/" + mname + ".[0-9]")) {
+ if (this->PrintFiles(os, cmStrCat("manual/", mname)) ||
+ this->PrintFiles(os, cmStrCat("manual/", mname, ".[0-9]"))) {
return true;
}
// Argument was not a manual. Complain.
@@ -469,10 +498,43 @@ bool cmDocumentation::PrintHelpListManuals(std::ostream& os)
return true;
}
+bool cmDocumentation::PrintHelpOneArbitrary(std::ostream& os)
+{
+ std::string word = cmSystemTools::HelpFileName(this->CurrentArgument);
+ std::string word_m = GeneralizeKeyword(word);
+
+ // Support legacy style uppercase commands, with LANG and CONFIG
+ // substitutions
+ bool found = this->PrintFiles(os, cmStrCat("*/", word));
+ if (found) {
+ os << "\n";
+ }
+ found = this->PrintFiles(
+ os, cmStrCat("command/", cmSystemTools::LowerCase(word))) ||
+ found;
+ if (found) {
+ return true;
+ }
+ found = this->PrintFiles(os, cmStrCat("*/", word_m));
+ if (found) {
+ os << "\n";
+ }
+ found = this->PrintFiles(
+ os, cmStrCat("command/", cmSystemTools::LowerCase(word_m))) ||
+ found;
+ if (found) {
+ return true;
+ }
+ os << "Argument \"" << this->CurrentArgument
+ << "\" to --help did not match any keywords. "
+ "Use --help without any arguments to print CMake help information.\n";
+ return false;
+}
+
bool cmDocumentation::PrintHelpOneCommand(std::ostream& os)
{
std::string cname = cmSystemTools::LowerCase(this->CurrentArgument);
- if (this->PrintFiles(os, "command/" + cname)) {
+ if (this->PrintFiles(os, cmStrCat("command/", cname))) {
return true;
}
// Argument was not a command. Complain.
@@ -491,7 +553,7 @@ bool cmDocumentation::PrintHelpListCommands(std::ostream& os)
bool cmDocumentation::PrintHelpOneModule(std::ostream& os)
{
std::string mname = this->CurrentArgument;
- if (this->PrintFiles(os, "module/" + mname)) {
+ if (this->PrintFiles(os, cmStrCat("module/", mname))) {
return true;
}
// Argument was not a module. Complain.
@@ -519,7 +581,7 @@ bool cmDocumentation::PrintHelpListModules(std::ostream& os)
bool cmDocumentation::PrintHelpOneProperty(std::ostream& os)
{
std::string pname = cmSystemTools::HelpFileName(this->CurrentArgument);
- if (this->PrintFiles(os, "prop_*/" + pname)) {
+ if (this->PrintFiles(os, cmStrCat("prop_*/", pname))) {
return true;
}
// Argument was not a property. Complain.
@@ -539,7 +601,7 @@ bool cmDocumentation::PrintHelpOnePolicy(std::ostream& os)
{
std::string pname = this->CurrentArgument;
std::vector<std::string> files;
- if (this->PrintFiles(os, "policy/" + pname)) {
+ if (this->PrintFiles(os, cmStrCat("policy/", pname))) {
return true;
}
@@ -567,7 +629,7 @@ bool cmDocumentation::PrintHelpListGenerators(std::ostream& os)
bool cmDocumentation::PrintHelpOneVariable(std::ostream& os)
{
std::string vname = cmSystemTools::HelpFileName(this->CurrentArgument);
- if (this->PrintFiles(os, "variable/" + vname)) {
+ if (this->PrintFiles(os, cmStrCat("variable/", vname))) {
return true;
}
// Argument was not a variable. Complain.
diff --git a/Source/cmDocumentation.h b/Source/cmDocumentation.h
index 6930986..3e6bdfb 100644
--- a/Source/cmDocumentation.h
+++ b/Source/cmDocumentation.h
@@ -34,6 +34,7 @@ public:
ListVariables,
ListPolicies,
ListGenerators,
+ OneArbitrary,
OneManual,
OneCommand,
OneModule,
@@ -118,6 +119,7 @@ private:
bool PrintUsage(std::ostream& os);
bool PrintHelp(std::ostream& os);
bool PrintHelpFull(std::ostream& os);
+ bool PrintHelpOneArbitrary(std::ostream& os);
bool PrintHelpOneManual(std::ostream& os);
bool PrintHelpOneCommand(std::ostream& os);
bool PrintHelpOneModule(std::ostream& os);
@@ -154,4 +156,5 @@ private:
cmDocumentationFormatter Formatter;
static void WarnFormFromFilename(RequestedHelpItem& request, bool& result);
+ static std::string GeneralizeKeyword(std::string word);
};
diff --git a/Source/cmExperimental.cxx b/Source/cmExperimental.cxx
index 104ab81..d75879f 100644
--- a/Source/cmExperimental.cxx
+++ b/Source/cmExperimental.cxx
@@ -19,17 +19,6 @@ namespace {
* up-to-date.
*/
cmExperimental::FeatureData LookupTable[] = {
- // CxxModuleCMakeApi
- { "CxxModuleCMakeApi",
- "ac01f462-0f5f-432a-86aa-acef252918a6",
- "CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API",
- "CMake's C++ module support is experimental. It is meant only for "
- "experimentation and feedback to CMake developers.",
- { "CMAKE_EXPERIMENTAL_CXX_SCANDEP_SOURCE",
- "CMAKE_EXPERIMENTAL_CXX_MODULE_MAP_FORMAT",
- "CMAKE_EXPERIMENTAL_CXX_MODULE_MAP_FLAG" },
- cmExperimental::TryCompileCondition::SkipCompilerChecks,
- false },
// WindowsKernelModeDriver
{ "WindowsKernelModeDriver",
"5c2d848d-4efa-4529-a768-efd57171bf68",
diff --git a/Source/cmExperimental.h b/Source/cmExperimental.h
index c958ab6..e4c1448 100644
--- a/Source/cmExperimental.h
+++ b/Source/cmExperimental.h
@@ -15,7 +15,6 @@ class cmExperimental
public:
enum class Feature
{
- CxxModuleCMakeApi,
WindowsKernelModeDriver,
Sentinel,
diff --git a/Source/cmExportCommand.cxx b/Source/cmExportCommand.cxx
index 273296d..e78b869 100644
--- a/Source/cmExportCommand.cxx
+++ b/Source/cmExportCommand.cxx
@@ -16,7 +16,6 @@
#include "cmArgumentParserTypes.h"
#include "cmCryptoHash.h"
#include "cmExecutionStatus.h"
-#include "cmExperimental.h"
#include "cmExportBuildAndroidMKGenerator.h"
#include "cmExportBuildFileGenerator.h"
#include "cmExportSet.h"
@@ -69,15 +68,11 @@ bool cmExportCommand(std::vector<std::string> const& args,
bool ExportOld = false;
};
- auto parser = cmArgumentParser<Arguments>{}
- .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);
- }
+ auto parser =
+ cmArgumentParser<Arguments>{}
+ .Bind("NAMESPACE"_s, &Arguments::Namespace)
+ .Bind("FILE"_s, &Arguments::Filename)
+ .Bind("CXX_MODULES_DIRECTORY"_s, &Arguments::CxxModulesDirectory);
if (args[0] == "EXPORT") {
parser.Bind("EXPORT"_s, &Arguments::ExportSetName);
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index 04d7bb1..422d927 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -31,7 +31,6 @@
#include "cmCustomCommandGenerator.h"
#include "cmCxxModuleUsageEffects.h"
#include "cmEvaluatedTargetProperty.h"
-#include "cmExperimental.h"
#include "cmFileSet.h"
#include "cmFileTimes.h"
#include "cmGeneratedFileStream.h"
@@ -9047,7 +9046,7 @@ std::string cmGeneratorTarget::GetImportedXcFrameworkPath(
bool cmGeneratorTarget::HaveFortranSources(std::string const& config) const
{
- auto sources = cmGeneratorTarget::GetSourceFiles(config);
+ auto sources = this->GetSourceFiles(config);
return std::any_of(sources.begin(), sources.end(),
[](BT<cmSourceFile*> const& sf) -> bool {
return sf.Value->GetLanguage() == "Fortran"_s;
@@ -9094,66 +9093,112 @@ cmGeneratorTarget::Cxx20SupportLevel cmGeneratorTarget::HaveCxxModuleSupport(
if (!state->GetLanguageEnabled("CXX")) {
return Cxx20SupportLevel::MissingCxx;
}
+
cmValue standardDefault =
- this->Target->GetMakefile()->GetDefinition("CMAKE_CXX_STANDARD_DEFAULT");
- if (standardDefault && !standardDefault->empty()) {
- cmStandardLevelResolver standardResolver(this->Makefile);
- if (!standardResolver.HaveStandardAvailable(this, "CXX", config,
- "cxx_std_20")) {
- return Cxx20SupportLevel::NoCxx20;
- }
+ this->Makefile->GetDefinition("CMAKE_CXX_STANDARD_DEFAULT");
+ if (!standardDefault || standardDefault->empty()) {
+ // We do not know any meaningful C++ standard levels for this compiler.
+ return Cxx20SupportLevel::NoCxx20;
+ }
+
+ cmStandardLevelResolver standardResolver(this->Makefile);
+ if (!standardResolver.HaveStandardAvailable(this, "CXX", config,
+ "cxx_std_20") ||
+ // During the ABI detection step we do not know the compiler's features.
+ // HaveStandardAvailable may return true as a fallback, but in this code
+ // path we do not want to assume C++ 20 is available.
+ this->Makefile->GetDefinition("CMAKE_CXX20_COMPILE_FEATURES")
+ .IsEmpty()) {
+ return Cxx20SupportLevel::NoCxx20;
}
- // Else, an empty CMAKE_CXX_STANDARD_DEFAULT means CMake does not detect and
- // set a default standard level for this compiler, so assume all standards
- // are available.
- if (!cmExperimental::HasSupportEnabled(
- *this->Makefile, cmExperimental::Feature::CxxModuleCMakeApi)) {
- return Cxx20SupportLevel::MissingExperimentalFlag;
+
+ cmValue scandepRule =
+ this->Makefile->GetDefinition("CMAKE_CXX_SCANDEP_SOURCE");
+ if (!scandepRule) {
+ return Cxx20SupportLevel::MissingRule;
}
return Cxx20SupportLevel::Supported;
}
void cmGeneratorTarget::CheckCxxModuleStatus(std::string const& config) const
{
+ bool haveScannableSources = false;
+
// 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 target named \"", this->GetName(),
- "\" has C++ sources that export modules but the \"CXX\" "
- "language has not been enabled"));
- break;
- case cmGeneratorTarget::Cxx20SupportLevel::MissingExperimentalFlag:
- this->Makefile->IssueMessage(
- MessageType::FATAL_ERROR,
- cmStrCat("The target named \"", this->GetName(),
- "\" has C++ sources that export modules but its "
- "experimental support has not been requested"));
- break;
- case cmGeneratorTarget::Cxx20SupportLevel::NoCxx20: {
- cmStandardLevelResolver standardResolver(this->Makefile);
- auto effStandard =
- standardResolver.GetEffectiveStandard(this, "CXX", config);
- if (effStandard.empty()) {
- effStandard = "; no C++ standard found";
- } else {
- effStandard = cmStrCat("; found \"cxx_std_", effStandard, '"');
- }
- this->Makefile->IssueMessage(
- MessageType::FATAL_ERROR,
- cmStrCat(
- "The target named \"", this->GetName(),
- "\" has C++ sources that export modules but does not include "
- "\"cxx_std_20\" (or newer) among its `target_compile_features`",
- effStandard));
- } break;
- case cmGeneratorTarget::Cxx20SupportLevel::Supported:
- // All is well.
- break;
+ haveScannableSources = true;
+ }
+
+ if (!haveScannableSources) {
+ // Check to see if there are regular sources that have requested scanning.
+ auto sources = this->GetSourceFiles(config);
+ for (auto const& source : sources) {
+ auto const* sf = source.Value;
+ auto const& lang = sf->GetLanguage();
+ if (lang != "CXX"_s) {
+ continue;
+ }
+ // Ignore sources which do not need dyndep.
+ if (this->NeedDyndepForSource(lang, config, sf)) {
+ haveScannableSources = true;
+ }
}
}
+
+ // If there isn't anything scannable, ignore it.
+ if (!haveScannableSources) {
+ return;
+ }
+
+ // If the generator doesn't support modules at all, error that we have
+ // sources that require the support.
+ if (!this->GetGlobalGenerator()->CheckCxxModuleSupport()) {
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat(
+ "The target named \"", this->GetName(),
+ "\" contains C++ "
+ "sources that use modules which is not supported by the generator"));
+ return;
+ }
+
+ switch (this->HaveCxxModuleSupport(config)) {
+ case cmGeneratorTarget::Cxx20SupportLevel::MissingCxx:
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat("The target named \"", this->GetName(),
+ "\" has C++ sources that use modules but the \"CXX\" "
+ "language has not been enabled"));
+ break;
+ case cmGeneratorTarget::Cxx20SupportLevel::NoCxx20: {
+ cmStandardLevelResolver standardResolver(this->Makefile);
+ auto effStandard =
+ standardResolver.GetEffectiveStandard(this, "CXX", config);
+ if (effStandard.empty()) {
+ effStandard = "; no C++ standard found";
+ } else {
+ effStandard = cmStrCat("; found \"cxx_std_", effStandard, '"');
+ }
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat(
+ "The target named \"", this->GetName(),
+ "\" has C++ sources that use modules but does not include "
+ "\"cxx_std_20\" (or newer) among its `target_compile_features`",
+ effStandard));
+ } break;
+ case cmGeneratorTarget::Cxx20SupportLevel::MissingRule: {
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat("The target named \"", this->GetName(),
+ "\" has C++ sources that use modules but the compiler does "
+ "not provide a way to discover the import graph "
+ "dependencies"));
+ } break;
+ case cmGeneratorTarget::Cxx20SupportLevel::Supported:
+ // All is well.
+ break;
+ }
}
bool cmGeneratorTarget::NeedCxxModuleSupport(std::string const& lang,
@@ -9191,14 +9236,30 @@ bool cmGeneratorTarget::NeedDyndepForSource(std::string const& lang,
std::string const& config,
cmSourceFile const* sf) const
{
- bool const needDyndep = this->NeedDyndep(lang, config);
- if (!needDyndep) {
+ // Fortran always needs to be scanned.
+ if (lang == "Fortran"_s) {
+ return true;
+ }
+ // Only C++ code needs scanned otherwise.
+ if (lang != "CXX"_s) {
return false;
}
+
+ // Any file in `CXX_MODULES` file sets need scanned (it being `CXX` is
+ // enforced elsewhere).
auto const* fs = this->GetFileSetForSource(config, sf);
if (fs && fs->GetType() == "CXX_MODULES"_s) {
return true;
}
+
+ switch (this->HaveCxxModuleSupport(config)) {
+ case Cxx20SupportLevel::MissingCxx:
+ case Cxx20SupportLevel::NoCxx20:
+ return false;
+ case Cxx20SupportLevel::MissingRule:
+ case Cxx20SupportLevel::Supported:
+ break;
+ }
auto const sfProp = sf->GetProperty("CXX_SCAN_FOR_MODULES");
if (sfProp.IsSet()) {
return sfProp.IsOn();
@@ -9207,7 +9268,22 @@ bool cmGeneratorTarget::NeedDyndepForSource(std::string const& lang,
if (tgtProp.IsSet()) {
return tgtProp.IsOn();
}
- return true;
+
+ bool policyAnswer = false;
+ switch (this->GetPolicyStatusCMP0155()) {
+ case cmPolicies::WARN:
+ case cmPolicies::OLD:
+ // The OLD behavior is to not scan the source.
+ policyAnswer = false;
+ break;
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::NEW:
+ // The NEW behavior is to scan the source.
+ policyAnswer = true;
+ break;
+ }
+ return policyAnswer;
}
void cmGeneratorTarget::BuildFileSetInfoCache(std::string const& config) const
diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h
index 751f907..72920d6 100644
--- a/Source/cmGeneratorTarget.h
+++ b/Source/cmGeneratorTarget.h
@@ -1288,10 +1288,10 @@ public:
{
// C++ is not available.
MissingCxx,
- // The experimental feature is not available.
- MissingExperimentalFlag,
// The target does not require at least C++20.
NoCxx20,
+ // C++20 module scanning rules are not present.
+ MissingRule,
// C++20 modules are available and working.
Supported,
};
diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx
index 6953ec6..1abdd0b 100644
--- a/Source/cmGlobalVisualStudio7Generator.cxx
+++ b/Source/cmGlobalVisualStudio7Generator.cxx
@@ -435,14 +435,6 @@ void cmGlobalVisualStudio7Generator::WriteTargetsToSolution(
target->CheckCxxModuleStatus(c);
}
- if (target->HaveCxx20ModuleSources() && !this->SupportsCxxModuleDyndep()) {
- root->GetMakefile()->IssueMessage(
- MessageType::FATAL_ERROR,
- cmStrCat("The target named \"", target->GetName(),
- "\" contains C++ sources that export modules which is not "
- "supported by the generator"));
- }
-
// handle external vc project files
cmValue expath = target->GetProperty("EXTERNAL_MSPROJECT");
if (expath) {
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index 90b8839..5076e6c 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -1384,14 +1384,6 @@ bool cmGlobalXCodeGenerator::CreateXCodeTarget(
gtgt->CheckCxxModuleStatus(configName);
}
- if (gtgt->HaveCxx20ModuleSources()) {
- gtgt->Makefile->IssueMessage(
- MessageType::FATAL_ERROR,
- cmStrCat("The target named \"", gtgt->GetName(),
- "\" contains C++ sources that export modules which is not "
- "supported by the generator"));
- }
-
auto& gtgt_visited = this->CommandsVisited[gtgt];
auto const& deps = this->GetTargetDirectDepends(gtgt);
for (auto const& d : deps) {
diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx
index 1b47ec4..0fc4011 100644
--- a/Source/cmInstallCommand.cxx
+++ b/Source/cmInstallCommand.cxx
@@ -21,7 +21,6 @@
#include "cmArgumentParser.h"
#include "cmArgumentParserTypes.h"
#include "cmExecutionStatus.h"
-#include "cmExperimental.h"
#include "cmExportSet.h"
#include "cmFileSet.h"
#include "cmGeneratorExpression.h"
@@ -491,6 +490,7 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
publicHeaderArgs.Parse(argVectors.PublicHeader, &unknownArgs);
resourceArgs.Parse(argVectors.Resource, &unknownArgs);
includesArgs.Parse(&argVectors.Includes, &unknownArgs);
+ cxxModuleBmiArgs.Parse(argVectors.CxxModulesBmi, &unknownArgs);
for (std::size_t i = 0; i < argVectors.FileSets.size(); i++) {
// We have to create a separate object for the parsing because
// cmArgumentParser<void>::Bind() binds to a specific address, but the
@@ -501,15 +501,6 @@ 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(
@@ -541,12 +532,10 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
success = success && privateHeaderArgs.Finalize();
success = success && publicHeaderArgs.Finalize();
success = success && resourceArgs.Finalize();
+ success = success && cxxModuleBmiArgs.Finalize();
for (auto& fileSetArg : fileSetArgs) {
success = success && fileSetArg.Finalize();
}
- if (supportCxx20FileSetTypes) {
- success = success && cxxModuleBmiArgs.Finalize();
- }
if (!success) {
return false;
@@ -1173,8 +1162,7 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
}
}
- if (supportCxx20FileSetTypes &&
- !cxxModuleBmiArgs.GetDestination().empty()) {
+ if (!cxxModuleBmiArgs.GetDestination().empty()) {
cxxModuleBmiGenerator = cm::make_unique<cmInstallCxxModuleBmiGenerator>(
target.GetName(),
helper.GetCxxModulesBmiDestination(&cxxModuleBmiArgs),
@@ -2071,12 +2059,7 @@ bool HandleExportMode(std::vector<std::string> const& args,
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);
- }
+ ica.Bind("CXX_MODULES_DIRECTORY"_s, cxx_modules_directory);
std::vector<std::string> unknownArgs;
ica.Parse(args, &unknownArgs);
diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx
index caa5e67..0c2a719 100644
--- a/Source/cmMakefileTargetGenerator.cxx
+++ b/Source/cmMakefileTargetGenerator.cxx
@@ -204,14 +204,6 @@ void cmMakefileTargetGenerator::WriteTargetBuildRules()
{
this->GeneratorTarget->CheckCxxModuleStatus(this->GetConfigName());
- if (this->GeneratorTarget->HaveCxx20ModuleSources()) {
- this->Makefile->IssueMessage(
- MessageType::FATAL_ERROR,
- cmStrCat("The target named \"", this->GeneratorTarget->GetName(),
- "\" contains C++ sources that export modules which is not "
- "supported by the generator"));
- }
-
// -- Write the custom commands for this target
// Evaluates generator expressions and expands prop_value
diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx
index 193cc0f..0bda945 100644
--- a/Source/cmNinjaTargetGenerator.cxx
+++ b/Source/cmNinjaTargetGenerator.cxx
@@ -266,7 +266,7 @@ std::string cmNinjaTargetGenerator::ComputeFlagsForObject(
if (!this->GeneratorTarget->Target->IsNormal()) {
auto flag = this->GetMakefile()->GetSafeDefinition(
- "CMAKE_EXPERIMENTAL_CXX_MODULE_BMI_ONLY_FLAG");
+ "CMAKE_CXX_MODULE_BMI_ONLY_FLAG");
cmRulePlaceholderExpander::RuleVariables compileObjectVars;
compileObjectVars.Object = objectFileName.c_str();
auto rulePlaceholderExpander =
@@ -710,7 +710,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
}
}
std::string const modmapFormatVar =
- cmStrCat("CMAKE_EXPERIMENTAL_", lang, "_MODULE_MAP_FORMAT");
+ cmStrCat("CMAKE_", lang, "_MODULE_MAP_FORMAT");
std::string const modmapFormat =
this->Makefile->GetSafeDefinition(modmapFormatVar);
@@ -734,7 +734,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
if (withScanning == WithScanning::Yes) {
const auto& scanDepType = this->GetMakefile()->GetSafeDefinition(
- cmStrCat("CMAKE_EXPERIMENTAL_", lang, "_SCANDEP_DEPFILE_FORMAT"));
+ cmStrCat("CMAKE_", lang, "_SCANDEP_DEPFILE_FORMAT"));
// Rule to scan dependencies of sources that need preprocessing.
{
@@ -745,7 +745,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
scanRuleName = this->LanguageScanRule(lang, config);
ppFileName = "$PREPROCESSED_OUTPUT_FILE";
std::string const& scanCommand = mf->GetRequiredDefinition(
- cmStrCat("CMAKE_EXPERIMENTAL_", lang, "_SCANDEP_SOURCE"));
+ cmStrCat("CMAKE_", lang, "_SCANDEP_SOURCE"));
scanCommands.assign(scanCommand);
for (auto& i : scanCommands) {
i = cmStrCat(launcher, i);
@@ -893,8 +893,8 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
}
if (withScanning == WithScanning::Yes && !modmapFormat.empty()) {
- std::string modmapFlags = mf->GetRequiredDefinition(
- cmStrCat("CMAKE_EXPERIMENTAL_", lang, "_MODULE_MAP_FLAG"));
+ std::string modmapFlags =
+ mf->GetRequiredDefinition(cmStrCat("CMAKE_", lang, "_MODULE_MAP_FLAG"));
cmSystemTools::ReplaceString(modmapFlags, "<MODULE_MAP_FILE>",
"$DYNDEP_MODULE_MAP_FILE");
flags += cmStrCat(' ', modmapFlags);
@@ -1143,6 +1143,30 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatements(
}
}
+ // Detect sources in `CXX_MODULES` which are not compiled.
+ {
+ std::vector<cmSourceFile*> sources;
+ this->GeneratorTarget->GetSourceFiles(sources, config);
+ for (cmSourceFile const* sf : sources) {
+ cmFileSet const* fs =
+ this->GeneratorTarget->GetFileSetForSource(config, sf);
+ if (!fs) {
+ continue;
+ }
+ if (fs->GetType() != "CXX_MODULES"_s) {
+ continue;
+ }
+ if (sf->GetLanguage().empty()) {
+ this->GeneratorTarget->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat("Target \"", this->GeneratorTarget->GetName(),
+ "\" has source file\n ", sf->GetFullPath(),
+ "\nin a \"FILE_SET TYPE CXX_MODULES\" but it is not "
+ "scheduled for compilation."));
+ }
+ }
+ }
+
for (auto const& langScanningFiles : this->Configs[config].ScanningInfo) {
std::string const& language = langScanningFiles.first;
std::vector<ScanningFiles> const& scanningFiles = langScanningFiles.second;
@@ -1477,7 +1501,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
std::string modmapFormat;
if (needDyndep) {
std::string const modmapFormatVar =
- cmStrCat("CMAKE_EXPERIMENTAL_", language, "_MODULE_MAP_FORMAT");
+ cmStrCat("CMAKE_", language, "_MODULE_MAP_FORMAT");
modmapFormat = this->Makefile->GetSafeDefinition(modmapFormatVar);
}
@@ -1758,7 +1782,7 @@ void cmNinjaTargetGenerator::WriteCxxModuleBmiBuildStatement(
std::string modmapFormat;
if (true) {
std::string const modmapFormatVar =
- cmStrCat("CMAKE_EXPERIMENTAL_", language, "_MODULE_MAP_FORMAT");
+ cmStrCat("CMAKE_", language, "_MODULE_MAP_FORMAT");
modmapFormat = this->Makefile->GetSafeDefinition(modmapFormatVar);
}
@@ -1969,12 +1993,12 @@ void cmNinjaTargetGenerator::ExportObjectCompileCommand(
bool const needDyndep =
this->GetGeneratorTarget()->NeedDyndep(language, outputConfig);
std::string const modmapFormatVar =
- cmStrCat("CMAKE_EXPERIMENTAL_", language, "_MODULE_MAP_FORMAT");
+ cmStrCat("CMAKE_", language, "_MODULE_MAP_FORMAT");
std::string const modmapFormat =
this->Makefile->GetSafeDefinition(modmapFormatVar);
if (needDyndep && !modmapFormat.empty()) {
std::string modmapFlags = this->GetMakefile()->GetRequiredDefinition(
- cmStrCat("CMAKE_EXPERIMENTAL_", language, "_MODULE_MAP_FLAG"));
+ cmStrCat("CMAKE_", language, "_MODULE_MAP_FLAG"));
// XXX(modmap): If changing this path construction, change
// `cmGlobalNinjaGenerator::WriteDyndep` and
// `cmNinjaTargetGenerator::WriteObjectBuildStatement` to expect the
diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h
index e894073..1ea2ce2 100644
--- a/Source/cmPolicies.h
+++ b/Source/cmPolicies.h
@@ -469,6 +469,10 @@ class cmMakefile;
SELECT( \
POLICY, CMP0154, \
"Generated files are private by default in targets using file sets.", 3, \
+ 28, 0, cmPolicies::WARN) \
+ SELECT( \
+ POLICY, CMP0155, \
+ "C++ sources in targets with at least C++20 are scanned for imports", 3, \
28, 0, cmPolicies::WARN)
#define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
@@ -508,7 +512,8 @@ class cmMakefile;
F(CMP0119) \
F(CMP0131) \
F(CMP0142) \
- F(CMP0154)
+ F(CMP0154) \
+ F(CMP0155)
#define CM_FOR_EACH_CUSTOM_COMMAND_POLICY(F) \
F(CMP0116) \
diff --git a/Source/cmTargetSourcesCommand.cxx b/Source/cmTargetSourcesCommand.cxx
index 3d484f5..babbaa5 100644
--- a/Source/cmTargetSourcesCommand.cxx
+++ b/Source/cmTargetSourcesCommand.cxx
@@ -10,7 +10,6 @@
#include "cmArgumentParser.h"
#include "cmArgumentParserTypes.h"
-#include "cmExperimental.h"
#include "cmFileSet.h"
#include "cmGeneratorExpression.h"
#include "cmList.h"
@@ -260,28 +259,18 @@ bool TargetSourcesImpl::HandleOneFileSet(
this->SetError("Must specify a TYPE when creating file set");
return false;
}
- bool const supportCxx20FileSetTypes = cmExperimental::HasSupportEnabled(
- *this->Makefile, cmExperimental::Feature::CxxModuleCMakeApi);
+ if (type != "HEADERS"_s && type != "CXX_MODULES"_s) {
+ this->SetError(
+ R"(File set TYPE may only be "HEADERS" or "CXX_MODULES")");
+ return false;
+ }
- if (supportCxx20FileSetTypes) {
- if (type != "HEADERS"_s && type != "CXX_MODULES"_s) {
+ if (cmFileSetVisibilityIsForInterface(visibility) &&
+ !cmFileSetVisibilityIsForSelf(visibility) &&
+ !this->Target->IsImported()) {
+ if (type == "CXX_MODULES"_s) {
this->SetError(
- R"(File set TYPE may only be "HEADERS" or "CXX_MODULES")");
- return false;
- }
-
- if (cmFileSetVisibilityIsForInterface(visibility) &&
- !cmFileSetVisibilityIsForSelf(visibility) &&
- !this->Target->IsImported()) {
- if (type == "CXX_MODULES"_s) {
- this->SetError(
- R"(File set TYPE "CXX_MODULES" may not have "INTERFACE" visibility)");
- return false;
- }
- }
- } else {
- if (type != "HEADERS"_s) {
- this->SetError("File set TYPE may only be \"HEADERS\"");
+ R"(File set TYPE "CXX_MODULES" may not have "INTERFACE" visibility)");
return false;
}
}
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index 2a54a55..ce94fe1 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -362,15 +362,6 @@ void cmVisualStudio10TargetGenerator::Generate()
this->GeneratorTarget->CheckCxxModuleStatus(config);
}
- if (this->GeneratorTarget->HaveCxx20ModuleSources() &&
- !this->GlobalGenerator->SupportsCxxModuleDyndep()) {
- this->Makefile->IssueMessage(
- MessageType::FATAL_ERROR,
- cmStrCat("The target named \"", this->GeneratorTarget->GetName(),
- "\" contains C++ sources that export modules which is not "
- "supported by the generator"));
- }
-
this->ProjectType = computeProjectType(this->GeneratorTarget);
this->Managed = this->ProjectType == VsProjectType::csproj;
const std::string ProjectFileExtension =