From a8115deebe49565089af6477dc70f9085e988dc0 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Tue, 14 Jun 2022 19:12:10 -0400 Subject: cmCommonTargetGenerator: fix linked target directory for multi-config builds Without this, `Ninja Multi-Config` generators were not getting the right directory to look for `Modules.json` files for module information. --- Source/cmCommonTargetGenerator.cxx | 4 ++++ 1 file changed, 4 insertions(+) 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 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)); } } -- cgit v0.12 From 52d47fd4e69fd69c3eb8dc837f137fdc26e2bac7 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Tue, 14 Jun 2022 19:11:33 -0400 Subject: cmGlobalNinjaGenerator: simplify a string building call --- Source/cmGlobalNinjaGenerator.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index acaed36..fcd3b23 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -2517,7 +2517,7 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile( // 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; -- cgit v0.12 From 030754a8b3f33291124ef69d21cda7d197602e97 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Tue, 14 Jun 2022 19:13:47 -0400 Subject: cmNinjaTargetGenerator: expand CFGIntDir for NMC --- Source/cmNinjaTargetGenerator.cxx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 3fac7f5..4a9396a 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -1616,8 +1616,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(); -- cgit v0.12 From 7c7af09c5e740261e5469a2d45a250d779b6217d Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Fri, 29 Apr 2022 08:58:12 -0400 Subject: cmScriptGenerator: remove unnecessary `endif` arguments --- Source/cmScriptGenerator.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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"; } } -- cgit v0.12 From fffc7813a42b9a2256981b575ef7e1a9799d1adf Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Wed, 4 May 2022 12:00:35 -0400 Subject: cmGlobalXCodeGenerator: avoid unused parameter warnings --- Source/cmGlobalXCodeGenerator.cxx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index d5783ef..e02f30e 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; -- cgit v0.12 From fb289dfcd9be3ceb9dcca20b3f51b779d77e01ee Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Tue, 24 May 2022 17:19:59 -0400 Subject: cmExperimental: add a mechanism for experimental CMake features --- Source/CMakeLists.txt | 2 ++ Source/cmExperimental.cxx | 56 +++++++++++++++++++++++++++++++++++++++++++++++ Source/cmExperimental.h | 19 ++++++++++++++++ bootstrap | 1 + 4 files changed, 78 insertions(+) create mode 100644 Source/cmExperimental.cxx create mode 100644 Source/cmExperimental.h diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 95b07cb..e6f7d69 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -543,6 +543,8 @@ set(SRCS cmExecuteProcessCommand.h cmExpandedCommandArgument.cxx cmExpandedCommandArgument.h + cmExperimental.cxx + cmExperimental.h cmExportCommand.cxx cmExportCommand.h cmExportLibraryDependenciesCommand.cxx diff --git a/Source/cmExperimental.cxx b/Source/cmExperimental.cxx new file mode 100644 index 0000000..5689714 --- /dev/null +++ b/Source/cmExperimental.cxx @@ -0,0 +1,56 @@ +/* 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 +#include +#include + +#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[] = {}; +static_assert(sizeof(LookupTable) / sizeof(LookupTable[0]) == + static_cast(cmExperimental::Feature::Sentinel), + "Experimental feature lookup table mismatch"); + +FeatureData& DataForFeature(cmExperimental::Feature f) +{ + assert(f != cmExperimental::Feature::Sentinel); + return LookupTable[static_cast(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..c2df019 --- /dev/null +++ b/Source/cmExperimental.h @@ -0,0 +1,19 @@ +/* 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 + { + Sentinel, + }; + + static bool HasSupportEnabled(cmMakefile const& mf, Feature f); +}; diff --git a/bootstrap b/bootstrap index 9a87413..fa9f40c 100755 --- a/bootstrap +++ b/bootstrap @@ -337,6 +337,7 @@ CMAKE_CXX_SOURCES="\ cmExecProgramCommand \ cmExecuteProcessCommand \ cmExpandedCommandArgument \ + cmExperimental \ cmExportBuildFileGenerator \ cmExportFileGenerator \ cmExportInstallFileGenerator \ -- cgit v0.12 From ff30a5397d804b9de564d54868bd5fdf504361c2 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Tue, 24 May 2022 17:20:42 -0400 Subject: cmExperimental: add an experimental feature to handle C++ modules --- Help/dev/experimental.rst | 17 +++++++++++++++++ Source/cmExperimental.cxx | 9 ++++++++- Source/cmExperimental.h | 2 ++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/Help/dev/experimental.rst b/Help/dev/experimental.rst index 7638d22..2c2eb21 100644 --- a/Help/dev/experimental.rst +++ b/Help/dev/experimental.rst @@ -7,6 +7,23 @@ See documentation on `CMake Development`_ for more information. .. _`CMake Development`: README.rst +Features are gated behind ``CMAKE_EXPERIMENTAL_`` variables which must be set +to specific values in order to enable their gated behaviors. Note that the +specific values will change over time to reinforce their experimental nature. +When used, a warning will be generated to indicate that an experimental +feature is in use and that the affected behavior in the project is not part of +CMake's stability guarantees. + +C++20 Module APIs +================= + +Variable: ``CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API`` +Value: ``17be90bd-a850-44e0-be50-448de847d652`` + +In order to support C++20 modules, there are a number of behaviors that have +CMake APIs to provide the required features to build and export them from a +project. + C++20 Module Dependencies ========================= diff --git a/Source/cmExperimental.cxx b/Source/cmExperimental.cxx index 5689714..e815d0e 100644 --- a/Source/cmExperimental.cxx +++ b/Source/cmExperimental.cxx @@ -25,7 +25,14 @@ struct FeatureData std::string const Variable; std::string const Description; bool Warned; -} LookupTable[] = {}; +} LookupTable[] = { + // CxxModuleCMakeApi + { "17be90bd-a850-44e0-be50-448de847d652", + "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(cmExperimental::Feature::Sentinel), "Experimental feature lookup table mismatch"); diff --git a/Source/cmExperimental.h b/Source/cmExperimental.h index c2df019..26e0d17 100644 --- a/Source/cmExperimental.h +++ b/Source/cmExperimental.h @@ -12,6 +12,8 @@ class cmExperimental public: enum class Feature { + CxxModuleCMakeApi, + Sentinel, }; -- cgit v0.12 From 386465bf8396dca8d00448b23734bc5edafb17c8 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Fri, 8 Apr 2022 13:56:33 -0400 Subject: cmTarget: add support for C++ module fileset types C++ modules have two variants which are of importance to CMake: - `CXX_MODULES`: interface modules (those using `export module M;`, `export module M:part;`, or `module M:internal_part;`) - `CXX_MODULE_HEADER_UNITS`: importable header units Creating C++ modules or partitions are *not* supported in any other source listing. This is because the source files must be installed (so their scope matters), but not part of usage requirements (what it means for a module source to be injected into a consumer is not clear at this moment). Due to the way `FILE_SET` works with scopes, they are a perfect fit as long as `INTERFACE` is not allowed (which it is not). --- Help/command/target_sources.rst | 77 ++++++++++++++---- Help/dev/experimental.rst | 5 -- Help/manual/cmake-properties.7.rst | 12 +++ Help/prop_tgt/CXX_MODULE_DIRS.rst | 17 ++++ Help/prop_tgt/CXX_MODULE_DIRS_NAME.rst | 17 ++++ Help/prop_tgt/CXX_MODULE_HEADER_UNIT_DIRS.rst | 17 ++++ Help/prop_tgt/CXX_MODULE_HEADER_UNIT_DIRS_NAME.rst | 19 +++++ Help/prop_tgt/CXX_MODULE_HEADER_UNIT_SET.rst | 18 +++++ Help/prop_tgt/CXX_MODULE_HEADER_UNIT_SETS.rst | 18 +++++ Help/prop_tgt/CXX_MODULE_HEADER_UNIT_SET_NAME.rst | 19 +++++ Help/prop_tgt/CXX_MODULE_SET.rst | 18 +++++ Help/prop_tgt/CXX_MODULE_SETS.rst | 16 ++++ Help/prop_tgt/CXX_MODULE_SET_NAME.rst | 18 +++++ .../INTERFACE_CXX_MODULE_HEADER_UNIT_SETS.rst | 16 ++++ Help/prop_tgt/INTERFACE_CXX_MODULE_SETS.rst | 16 ++++ Source/cmExportBuildFileGenerator.cxx | 32 ++++++++ Source/cmExportInstallFileGenerator.cxx | 34 ++++++++ Source/cmGeneratorTarget.cxx | 90 ++++++++++++++++++++- Source/cmGeneratorTarget.h | 30 +++++++ Source/cmGlobalVisualStudio7Generator.cxx | 15 ++++ Source/cmGlobalVisualStudio7Generator.h | 2 + Source/cmGlobalXCodeGenerator.cxx | 12 +++ Source/cmMakefileTargetGenerator.cxx | 65 +++++++++++++++ Source/cmNinjaTargetGenerator.cxx | 92 +++++++++++----------- Source/cmTarget.cxx | 79 +++++++++++++++++++ Source/cmTarget.h | 4 + Source/cmTargetSourcesCommand.cxx | 30 ++++++- Source/cmVisualStudio10TargetGenerator.cxx | 12 +++ Tests/RunCMake/CMakeLists.txt | 3 + Tests/RunCMake/CXXModules/CMakeLists.txt | 6 ++ .../FileSetModuleHeaderUnitsInterface-result.txt | 1 + .../FileSetModuleHeaderUnitsInterface-stderr.txt | 12 +++ .../FileSetModuleHeaderUnitsInterface.cmake | 8 ++ .../FileSetModuleHeaderUnitsPrivate-stderr.txt | 11 +++ .../FileSetModuleHeaderUnitsPrivate.cmake | 13 +++ .../FileSetModuleHeaderUnitsPublic-stderr.txt | 11 +++ .../FileSetModuleHeaderUnitsPublic.cmake | 13 +++ .../CXXModules/FileSetModulesInterface-result.txt | 1 + .../CXXModules/FileSetModulesInterface-stderr.txt | 12 +++ .../CXXModules/FileSetModulesInterface.cmake | 8 ++ .../CXXModules/FileSetModulesPrivate-stderr.txt | 11 +++ .../CXXModules/FileSetModulesPrivate.cmake | 12 +++ .../CXXModules/FileSetModulesPublic-stderr.txt | 11 +++ .../RunCMake/CXXModules/FileSetModulesPublic.cmake | 12 +++ Tests/RunCMake/CXXModules/NoCXX-result.txt | 1 + Tests/RunCMake/CXXModules/NoCXX-stderr.txt | 20 +++++ Tests/RunCMake/CXXModules/NoCXX.cmake | 9 +++ Tests/RunCMake/CXXModules/NoCXX20-result.txt | 1 + Tests/RunCMake/CXXModules/NoCXX20-stderr.txt | 20 +++++ Tests/RunCMake/CXXModules/NoCXX20.cmake | 10 +++ .../CXXModules/NoCXX20ModuleFlag-result.txt | 1 + .../CXXModules/NoCXX20ModuleFlag-stderr.txt | 20 +++++ Tests/RunCMake/CXXModules/NoCXX20ModuleFlag.cmake | 10 +++ .../RunCMake/CXXModules/NoDyndepSupport-result.txt | 1 + .../RunCMake/CXXModules/NoDyndepSupport-stderr.txt | 30 +++++++ Tests/RunCMake/CXXModules/NoDyndepSupport.cmake | 16 ++++ .../NotCXXSourceModuleHeaderUnits-result.txt | 1 + .../NotCXXSourceModuleHeaderUnits-stderr.txt | 22 ++++++ .../CXXModules/NotCXXSourceModuleHeaderUnits.cmake | 15 ++++ .../CXXModules/NotCXXSourceModules-result.txt | 1 + .../CXXModules/NotCXXSourceModules-stderr.txt | 17 ++++ .../RunCMake/CXXModules/NotCXXSourceModules.cmake | 13 +++ Tests/RunCMake/CXXModules/RunCMakeTest.cmake | 67 ++++++++++++++++ .../CXXModules/compiler_introspection.cmake | 25 ++++++ Tests/RunCMake/CXXModules/sources/c-anchor.c | 4 + Tests/RunCMake/CXXModules/sources/cxx-anchor.cxx | 4 + Tests/RunCMake/CXXModules/sources/module-header.h | 9 +++ Tests/RunCMake/CXXModules/sources/module-impl.cxx | 6 ++ .../sources/module-internal-part-impl.cxx | 11 +++ .../CXXModules/sources/module-internal-part.cxx | 3 + .../CXXModules/sources/module-part-impl.cxx | 13 +++ Tests/RunCMake/CXXModules/sources/module-part.cxx | 3 + Tests/RunCMake/CXXModules/sources/module-use.cxx | 6 ++ Tests/RunCMake/CXXModules/sources/module.cxx | 5 ++ .../FileSetDefaultWrongTypeExperimental-result.txt | 1 + .../FileSetDefaultWrongTypeExperimental-stderr.txt | 12 +++ .../FileSetDefaultWrongTypeExperimental.cmake | 6 ++ .../FileSetWrongTypeExperimental-result.txt | 1 + .../FileSetWrongTypeExperimental-stderr.txt | 12 +++ .../FileSetWrongTypeExperimental.cmake | 6 ++ Tests/RunCMake/target_sources/RunCMakeTest.cmake | 2 + Tests/RunCMake/try_compile/CxxStandard-stderr.txt | 15 +++- 82 files changed, 1290 insertions(+), 74 deletions(-) create mode 100644 Help/prop_tgt/CXX_MODULE_DIRS.rst create mode 100644 Help/prop_tgt/CXX_MODULE_DIRS_NAME.rst create mode 100644 Help/prop_tgt/CXX_MODULE_HEADER_UNIT_DIRS.rst create mode 100644 Help/prop_tgt/CXX_MODULE_HEADER_UNIT_DIRS_NAME.rst create mode 100644 Help/prop_tgt/CXX_MODULE_HEADER_UNIT_SET.rst create mode 100644 Help/prop_tgt/CXX_MODULE_HEADER_UNIT_SETS.rst create mode 100644 Help/prop_tgt/CXX_MODULE_HEADER_UNIT_SET_NAME.rst create mode 100644 Help/prop_tgt/CXX_MODULE_SET.rst create mode 100644 Help/prop_tgt/CXX_MODULE_SETS.rst create mode 100644 Help/prop_tgt/CXX_MODULE_SET_NAME.rst create mode 100644 Help/prop_tgt/INTERFACE_CXX_MODULE_HEADER_UNIT_SETS.rst create mode 100644 Help/prop_tgt/INTERFACE_CXX_MODULE_SETS.rst create mode 100644 Tests/RunCMake/CXXModules/CMakeLists.txt create mode 100644 Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsInterface-result.txt create mode 100644 Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsInterface-stderr.txt create mode 100644 Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsInterface.cmake create mode 100644 Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsPrivate-stderr.txt create mode 100644 Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsPrivate.cmake create mode 100644 Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsPublic-stderr.txt create mode 100644 Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsPublic.cmake create mode 100644 Tests/RunCMake/CXXModules/FileSetModulesInterface-result.txt create mode 100644 Tests/RunCMake/CXXModules/FileSetModulesInterface-stderr.txt create mode 100644 Tests/RunCMake/CXXModules/FileSetModulesInterface.cmake create mode 100644 Tests/RunCMake/CXXModules/FileSetModulesPrivate-stderr.txt create mode 100644 Tests/RunCMake/CXXModules/FileSetModulesPrivate.cmake create mode 100644 Tests/RunCMake/CXXModules/FileSetModulesPublic-stderr.txt create mode 100644 Tests/RunCMake/CXXModules/FileSetModulesPublic.cmake create mode 100644 Tests/RunCMake/CXXModules/NoCXX-result.txt create mode 100644 Tests/RunCMake/CXXModules/NoCXX-stderr.txt create mode 100644 Tests/RunCMake/CXXModules/NoCXX.cmake create mode 100644 Tests/RunCMake/CXXModules/NoCXX20-result.txt create mode 100644 Tests/RunCMake/CXXModules/NoCXX20-stderr.txt create mode 100644 Tests/RunCMake/CXXModules/NoCXX20.cmake create mode 100644 Tests/RunCMake/CXXModules/NoCXX20ModuleFlag-result.txt create mode 100644 Tests/RunCMake/CXXModules/NoCXX20ModuleFlag-stderr.txt create mode 100644 Tests/RunCMake/CXXModules/NoCXX20ModuleFlag.cmake create mode 100644 Tests/RunCMake/CXXModules/NoDyndepSupport-result.txt create mode 100644 Tests/RunCMake/CXXModules/NoDyndepSupport-stderr.txt create mode 100644 Tests/RunCMake/CXXModules/NoDyndepSupport.cmake create mode 100644 Tests/RunCMake/CXXModules/NotCXXSourceModuleHeaderUnits-result.txt create mode 100644 Tests/RunCMake/CXXModules/NotCXXSourceModuleHeaderUnits-stderr.txt create mode 100644 Tests/RunCMake/CXXModules/NotCXXSourceModuleHeaderUnits.cmake create mode 100644 Tests/RunCMake/CXXModules/NotCXXSourceModules-result.txt create mode 100644 Tests/RunCMake/CXXModules/NotCXXSourceModules-stderr.txt create mode 100644 Tests/RunCMake/CXXModules/NotCXXSourceModules.cmake create mode 100644 Tests/RunCMake/CXXModules/RunCMakeTest.cmake create mode 100644 Tests/RunCMake/CXXModules/compiler_introspection.cmake create mode 100644 Tests/RunCMake/CXXModules/sources/c-anchor.c create mode 100644 Tests/RunCMake/CXXModules/sources/cxx-anchor.cxx create mode 100644 Tests/RunCMake/CXXModules/sources/module-header.h create mode 100644 Tests/RunCMake/CXXModules/sources/module-impl.cxx create mode 100644 Tests/RunCMake/CXXModules/sources/module-internal-part-impl.cxx create mode 100644 Tests/RunCMake/CXXModules/sources/module-internal-part.cxx create mode 100644 Tests/RunCMake/CXXModules/sources/module-part-impl.cxx create mode 100644 Tests/RunCMake/CXXModules/sources/module-part.cxx create mode 100644 Tests/RunCMake/CXXModules/sources/module-use.cxx create mode 100644 Tests/RunCMake/CXXModules/sources/module.cxx create mode 100644 Tests/RunCMake/target_sources/FileSetDefaultWrongTypeExperimental-result.txt create mode 100644 Tests/RunCMake/target_sources/FileSetDefaultWrongTypeExperimental-stderr.txt create mode 100644 Tests/RunCMake/target_sources/FileSetDefaultWrongTypeExperimental.cmake create mode 100644 Tests/RunCMake/target_sources/FileSetWrongTypeExperimental-result.txt create mode 100644 Tests/RunCMake/target_sources/FileSetWrongTypeExperimental-stderr.txt create mode 100644 Tests/RunCMake/target_sources/FileSetWrongTypeExperimental.cmake diff --git a/Help/command/target_sources.rst b/Help/command/target_sources.rst index 1ad6c37..0c4323c 100644 --- a/Help/command/target_sources.rst +++ b/Help/command/target_sources.rst @@ -75,9 +75,33 @@ File Sets Adds a file set to a target, or adds files to an existing file set. Targets have zero or more named file sets. Each file set has a name, a type, a scope of ``INTERFACE``, ``PUBLIC``, or ``PRIVATE``, one or more base directories, and -files within those directories. The only acceptable type is ``HEADERS``. The -optional default file sets are named after their type. The target may not be a -custom target or :prop_tgt:`FRAMEWORK` target. +files within those directories. The acceptable types include: + +``HEADERS`` + + Sources intended to be used via a language's ``#include`` mechanism. + +``CXX_MODULES`` + +.. note :: + + Experimental. Gated by ``CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API`` + + Sources which contain C++ interface module or partition units (i.e., those + using the ``export`` keyword). This file set type may not have an + ``INTERFACE`` scope. + +``CXX_MODULE_HEADER_UNITS`` + +.. note :: + + Experimental. Gated by ``CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API`` + + C++ header sources which may be imported by other C++ source code. This file + set type may not have an ``INTERFACE`` scope. + +The optional default file sets are named after their type. The target may not +be a custom target or :prop_tgt:`FRAMEWORK` target. Files in a ``PRIVATE`` or ``PUBLIC`` file set are marked as source files for the purposes of IDE integration. Additionally, files in ``HEADERS`` file sets @@ -93,16 +117,17 @@ Each ``target_sources(FILE_SET)`` entry starts with ``INTERFACE``, ``PUBLIC``, o The name of the file set to create or add to. It must contain only letters, numbers and underscores. Names starting with a capital letter are reserved - for built-in file sets predefined by CMake. The only predefined set name is - ``HEADERS``. All other set names must not start with a capital letter or + for built-in file sets predefined by CMake. The only predefined set names + are those matching the acceptable types. All other set names must not start + with a capital letter or underscore. ``TYPE `` - Every file set is associated with a particular type of file. ``HEADERS`` - is currently the only defined type and it is an error to specify anything - else. As a special case, if the name of the file set is ``HEADERS``, the - type does not need to be specified and the ``TYPE `` arguments can be + Every file set is associated with a particular type of file. Only types + specified above may be used and it is an error to specify anything else. As + a special case, if the name of the file set is one of the types, the type + does not need to be specified and the ``TYPE `` arguments can be omitted. For all other file set names, ``TYPE`` is required. ``BASE_DIRS ...`` @@ -134,6 +159,8 @@ Each ``target_sources(FILE_SET)`` entry starts with ``INTERFACE``, ``PUBLIC``, o The following target properties are set by ``target_sources(FILE_SET)``, but they should not generally be manipulated directly: +For file sets of type ``HEADERS``: + * :prop_tgt:`HEADER_SETS` * :prop_tgt:`INTERFACE_HEADER_SETS` * :prop_tgt:`HEADER_SET` @@ -141,17 +168,37 @@ but they should not generally be manipulated directly: * :prop_tgt:`HEADER_DIRS` * :prop_tgt:`HEADER_DIRS_` +For file sets of type ``CXX_MODULES``: + +* :prop_tgt:`CXX_MODULE_SETS` +* :prop_tgt:`INTERFACE_CXX_MODULE_SETS` +* :prop_tgt:`CXX_MODULE_SET` +* :prop_tgt:`CXX_MODULE_SET_` +* :prop_tgt:`CXX_MODULE_DIRS` +* :prop_tgt:`CXX_MODULE_DIRS_` + +For file sets of type ``CXX_MODULE_HEADER_UNITS``: + +* :prop_tgt:`CXX_MODULE_HEADER_UNIT_SETS` +* :prop_tgt:`INTERFACE_CXX_MODULE_HEADER_UNIT_SETS` +* :prop_tgt:`CXX_MODULE_HEADER_UNIT_SET` +* :prop_tgt:`CXX_MODULE_HEADER_UNIT_SET_` +* :prop_tgt:`CXX_MODULE_HEADER_UNIT_DIRS` +* :prop_tgt:`CXX_MODULE_HEADER_UNIT_DIRS_` + Target properties related to include directories are also modified by ``target_sources(FILE_SET)`` as follows: :prop_tgt:`INCLUDE_DIRECTORIES` - If the ``TYPE`` is ``HEADERS``, and the scope of the file set is ``PRIVATE`` - or ``PUBLIC``, all of the ``BASE_DIRS`` of the file set are wrapped in - :genex:`$` and appended to this property. + If the ``TYPE`` is ``HEADERS`` or ``CXX_MODULE_HEADER_UNITS``, and the scope + of the file set is ``PRIVATE`` or ``PUBLIC``, all of the ``BASE_DIRS`` of + the file set are wrapped in :genex:`$` and appended to this + property. :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` - If the ``TYPE`` is ``HEADERS``, and the scope of the file set is - ``INTERFACE`` or ``PUBLIC``, all of the ``BASE_DIRS`` of the file set are - wrapped in :genex:`$` and appended to this property. + If the ``TYPE`` is ``HEADERS`` or ``CXX_MODULE_HEADER_UNITS``, and the scope + of the file set is ``INTERFACE`` or ``PUBLIC``, all of the ``BASE_DIRS`` of + the file set are wrapped in :genex:`$` and appended to this + property. diff --git a/Help/dev/experimental.rst b/Help/dev/experimental.rst index 2c2eb21..14e6075 100644 --- a/Help/dev/experimental.rst +++ b/Help/dev/experimental.rst @@ -57,11 +57,6 @@ dependencies to the file specified by the ```` placeholder. The ``CMAKE_EXPERIMENTAL_CXX_SCANDEP_DEPFILE_FORMAT`` file may be set to ``msvc`` for scandep rules which use ``msvc``-style dependency reporting. -For tools which need to know the file set the source belongs to, the -``CMAKE_EXPERIMENTAL_CXX_MODULE_SOURCE_TYPE_FLAG_`` flag may -be provided so that different source types can be distinguished prior to -scanning. - The module dependencies should be written in the format described by the `P1689r4`_ paper. diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst index d88322c..dc2c591 100644 --- a/Help/manual/cmake-properties.7.rst +++ b/Help/manual/cmake-properties.7.rst @@ -184,6 +184,16 @@ Properties on Targets /prop_tgt/CUDA_STANDARD /prop_tgt/CUDA_STANDARD_REQUIRED /prop_tgt/CXX_EXTENSIONS + /prop_tgt/CXX_MODULE_DIRS + /prop_tgt/CXX_MODULE_DIRS_NAME + /prop_tgt/CXX_MODULE_SET + /prop_tgt/CXX_MODULE_SET_NAME + /prop_tgt/CXX_MODULE_SETS + /prop_tgt/CXX_MODULE_HEADER_UNIT_DIRS + /prop_tgt/CXX_MODULE_HEADER_UNIT_DIRS_NAME + /prop_tgt/CXX_MODULE_HEADER_UNIT_SET + /prop_tgt/CXX_MODULE_HEADER_UNIT_SET_NAME + /prop_tgt/CXX_MODULE_HEADER_UNIT_SETS /prop_tgt/CXX_STANDARD /prop_tgt/CXX_STANDARD_REQUIRED /prop_tgt/DEBUG_POSTFIX @@ -262,6 +272,8 @@ Properties on Targets /prop_tgt/INTERFACE_COMPILE_DEFINITIONS /prop_tgt/INTERFACE_COMPILE_FEATURES /prop_tgt/INTERFACE_COMPILE_OPTIONS + /prop_tgt/INTERFACE_CXX_MODULE_SETS + /prop_tgt/INTERFACE_CXX_MODULE_HEADER_UNIT_SETS /prop_tgt/INTERFACE_HEADER_SETS /prop_tgt/INTERFACE_HEADER_SETS_TO_VERIFY /prop_tgt/INTERFACE_INCLUDE_DIRECTORIES diff --git a/Help/prop_tgt/CXX_MODULE_DIRS.rst b/Help/prop_tgt/CXX_MODULE_DIRS.rst new file mode 100644 index 0000000..fdf3831 --- /dev/null +++ b/Help/prop_tgt/CXX_MODULE_DIRS.rst @@ -0,0 +1,17 @@ +CXX_MODULE_DIRS +--------------- + +.. note :: + + Experimental. Gated by ``CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API`` + +Semicolon-separated list of base directories of the target's default +C++ module set (i.e. the file set with name and type ``CXX_MODULES``). The +property supports +:manual:`generator expressions `. + +This property is normally only set by :command:`target_sources(FILE_SET)` +rather than being manipulated directly. + +See :prop_tgt:`CXX_MODULE_DIRS_` for the list of base directories in +other C++ module sets. diff --git a/Help/prop_tgt/CXX_MODULE_DIRS_NAME.rst b/Help/prop_tgt/CXX_MODULE_DIRS_NAME.rst new file mode 100644 index 0000000..8c27d45 --- /dev/null +++ b/Help/prop_tgt/CXX_MODULE_DIRS_NAME.rst @@ -0,0 +1,17 @@ +CXX_MODULE_DIRS_ +---------------------- + +.. note :: + + Experimental. Gated by ``CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API`` + +Semicolon-separated list of base directories of the target's ```` C++ +module set, which has the set type ``CXX_MODULES``. The property supports +:manual:`generator expressions `. + +This property is normally only set by :command:`target_sources(FILE_SET)` +rather than being manipulated directly. + +See :prop_tgt:`CXX_MODULE_DIRS` for the list of base directories in the +default C++ module set. See :prop_tgt:`CXX_MODULE_SETS` for the file set names +of all C++ module sets. diff --git a/Help/prop_tgt/CXX_MODULE_HEADER_UNIT_DIRS.rst b/Help/prop_tgt/CXX_MODULE_HEADER_UNIT_DIRS.rst new file mode 100644 index 0000000..17e5cf0 --- /dev/null +++ b/Help/prop_tgt/CXX_MODULE_HEADER_UNIT_DIRS.rst @@ -0,0 +1,17 @@ +CXX_MODULE_HEADER_UNIT_DIRS +--------------------------- + +.. note :: + + Experimental. Gated by ``CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API`` + +Semicolon-separated list of base directories of the target's default C++ +module header set (i.e. the file set with name and type +``CXX_MODULE_HEADER_UNITS``). The property supports +:manual:`generator expressions `. + +This property is normally only set by :command:`target_sources(FILE_SET)` +rather than being manipulated directly. + +See :prop_tgt:`CXX_MODULE_HEADER_UNIT_DIRS_` for the list of base directories +in other C++ module header sets. diff --git a/Help/prop_tgt/CXX_MODULE_HEADER_UNIT_DIRS_NAME.rst b/Help/prop_tgt/CXX_MODULE_HEADER_UNIT_DIRS_NAME.rst new file mode 100644 index 0000000..ca30f23 --- /dev/null +++ b/Help/prop_tgt/CXX_MODULE_HEADER_UNIT_DIRS_NAME.rst @@ -0,0 +1,19 @@ +CXX_MODULE_HEADER_UNIT_DIRS_ +---------------------------------- + +.. note :: + + Experimental. Gated by ``CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API`` + +Semicolon-separated list of base directories of the target's ```` C++ +module header set, which has the set type ``CXX_MODULE_HEADER_UNITS``. The +property supports +:manual:`generator expressions `. + +This property is normally only set by :command:`target_sources(FILE_SET)` +rather than being manipulated directly. + +See :prop_tgt:`CXX_MODULE_HEADER_UNIT_DIRS` for the list of base directories +in the default C++ module header set. See +:prop_tgt:`CXX_MODULE_HEADER_UNIT_SETS` for the file set names of all C++ +module header sets. diff --git a/Help/prop_tgt/CXX_MODULE_HEADER_UNIT_SET.rst b/Help/prop_tgt/CXX_MODULE_HEADER_UNIT_SET.rst new file mode 100644 index 0000000..f67a848 --- /dev/null +++ b/Help/prop_tgt/CXX_MODULE_HEADER_UNIT_SET.rst @@ -0,0 +1,18 @@ +CXX_MODULE_HEADER_UNIT_SET +-------------------------- + +.. note :: + + Experimental. Gated by ``CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API`` + +Semicolon-separated list of files in the target's default C++ module header +set, (i.e. the file set with name and type ``CXX_MODULE_HEADER_UNITS``). If +any of the paths are relative, they are computed relative to the target's +source directory. The property supports +:manual:`generator expressions `. + +This property is normally only set by :command:`target_sources(FILE_SET)` +rather than being manipulated directly. + +See :prop_tgt:`CXX_MODULE_HEADER_UNIT_SET_` for the list of files in +other C++ module header sets. diff --git a/Help/prop_tgt/CXX_MODULE_HEADER_UNIT_SETS.rst b/Help/prop_tgt/CXX_MODULE_HEADER_UNIT_SETS.rst new file mode 100644 index 0000000..7b4bd3f --- /dev/null +++ b/Help/prop_tgt/CXX_MODULE_HEADER_UNIT_SETS.rst @@ -0,0 +1,18 @@ +CXX_MODULE_HEADER_UNIT_SETS +--------------------------- + +.. note :: + + Experimental. Gated by ``CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API`` + +Read-only list of the target's ``PRIVATE`` and ``PUBLIC`` C++ module header +sets (i.e. all file sets with the type ``CXX_MODULE_HEADER_UNITS``). Files +listed in these file sets are treated as source files for the purpose of IDE +integration. + +C++ module header sets may be defined using the :command:`target_sources` +command ``FILE_SET`` option with type ``CXX_MODULE_HEADER_UNITS``. + +See also :prop_tgt:`CXX_MODULE_HEADER_UNIT_SET_`, +:prop_tgt:`CXX_MODULE_HEADER_UNIT_SET` and +:prop_tgt:`INTERFACE_CXX_MODULE_HEADER_UNIT_SETS`. diff --git a/Help/prop_tgt/CXX_MODULE_HEADER_UNIT_SET_NAME.rst b/Help/prop_tgt/CXX_MODULE_HEADER_UNIT_SET_NAME.rst new file mode 100644 index 0000000..d328950 --- /dev/null +++ b/Help/prop_tgt/CXX_MODULE_HEADER_UNIT_SET_NAME.rst @@ -0,0 +1,19 @@ +CXX_MODULE_HEADER_UNIT_SET_ +--------------------------------- + +.. note :: + + Experimental. Gated by ``CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API`` + +Semicolon-separated list of files in the target's ```` C++ module header +set, which has the set type ``CXX_MODULE_HEADER_UNITS``. If any of the paths +are relative, they are computed relative to the target's source directory. The +property supports +:manual:`generator expressions `. + +This property is normally only set by :command:`target_sources(FILE_SET)` +rather than being manipulated directly. + +See :prop_tgt:`CXX_MODULE_HEADER_UNIT_SET` for the list of files in the +default C++ module header set. See :prop_tgt:`CXX_MODULE_HEADER_UNIT_SETS` for +the file set names of all C++ module header sets. diff --git a/Help/prop_tgt/CXX_MODULE_SET.rst b/Help/prop_tgt/CXX_MODULE_SET.rst new file mode 100644 index 0000000..ae9000e --- /dev/null +++ b/Help/prop_tgt/CXX_MODULE_SET.rst @@ -0,0 +1,18 @@ +CXX_MODULE_SET +-------------- + +.. note :: + + Experimental. Gated by ``CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API`` + +Semicolon-separated list of files in the target's default C++ module set, +(i.e. the file set with name and type ``CXX_MODULES``). If any of the paths +are relative, they are computed relative to the target's source directory. The +property supports +:manual:`generator expressions `. + +This property is normally only set by :command:`target_sources(FILE_SET)` +rather than being manipulated directly. + +See :prop_tgt:`CXX_MODULE_SET_` for the list of files in other C++ +module sets. diff --git a/Help/prop_tgt/CXX_MODULE_SETS.rst b/Help/prop_tgt/CXX_MODULE_SETS.rst new file mode 100644 index 0000000..c03df39 --- /dev/null +++ b/Help/prop_tgt/CXX_MODULE_SETS.rst @@ -0,0 +1,16 @@ +CXX_MODULE_SETS +--------------- + +.. note :: + + Experimental. Gated by ``CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API`` + +Read-only list of the target's ``PRIVATE`` and ``PUBLIC`` C++ module sets (i.e. +all file sets with the type ``CXX_MODULES``). Files listed in these file sets are +treated as source files for the purpose of IDE integration. + +C++ module sets may be defined using the :command:`target_sources` command +``FILE_SET`` option with type ``CXX_MODULES``. + +See also :prop_tgt:`CXX_MODULE_SET_`, :prop_tgt:`CXX_MODULE_SET` and +:prop_tgt:`INTERFACE_CXX_MODULE_SETS`. diff --git a/Help/prop_tgt/CXX_MODULE_SET_NAME.rst b/Help/prop_tgt/CXX_MODULE_SET_NAME.rst new file mode 100644 index 0000000..27c88f3 --- /dev/null +++ b/Help/prop_tgt/CXX_MODULE_SET_NAME.rst @@ -0,0 +1,18 @@ +CXX_MODULE_SET_ +--------------------- + +.. note :: + + Experimental. Gated by ``CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API`` + +Semicolon-separated list of files in the target's ```` C++ module set, +which has the set type ``CXX_MODULES``. If any of the paths are relative, they +are computed relative to the target's source directory. The property supports +:manual:`generator expressions `. + +This property is normally only set by :command:`target_sources(FILE_SET)` +rather than being manipulated directly. + +See :prop_tgt:`CXX_MODULE_SET` for the list of files in the default C++ module +set. See :prop_tgt:`CXX_MODULE_SETS` for the file set names of all C++ module +sets. diff --git a/Help/prop_tgt/INTERFACE_CXX_MODULE_HEADER_UNIT_SETS.rst b/Help/prop_tgt/INTERFACE_CXX_MODULE_HEADER_UNIT_SETS.rst new file mode 100644 index 0000000..eb3a9ff --- /dev/null +++ b/Help/prop_tgt/INTERFACE_CXX_MODULE_HEADER_UNIT_SETS.rst @@ -0,0 +1,16 @@ +INTERFACE_CXX_MODULE_HEADER_UNIT_SETS +------------------------------------- + +.. note :: + + Experimental. Gated by ``CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API`` + +Read-only list of the target's ``PUBLIC`` C++ module header sets (i.e. all +file sets with the type ``CXX_MODULE_HEADER_UNITS``). Files listed in these +C++ module header sets can be installed with :command:`install(TARGETS)` and +exported with :command:`install(EXPORT)` and :command:`export`. + +C++ module header sets may be defined using the :command:`target_sources` +command ``FILE_SET`` option with type ``CXX_MODULE_HEADER_UNITS``. + +See also :prop_tgt:`CXX_MODULE_HEADER_UNIT_SETS`. diff --git a/Help/prop_tgt/INTERFACE_CXX_MODULE_SETS.rst b/Help/prop_tgt/INTERFACE_CXX_MODULE_SETS.rst new file mode 100644 index 0000000..cc30386 --- /dev/null +++ b/Help/prop_tgt/INTERFACE_CXX_MODULE_SETS.rst @@ -0,0 +1,16 @@ +INTERFACE_CXX_MODULE_SETS +------------------------- + +.. note :: + + Experimental. Gated by ``CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API`` + +Read-only list of the target's ``PUBLIC`` C++ module sets (i.e. all file sets +with the type ``CXX_MODULES``). Files listed in these C++ module sets can be +installed with :command:`install(TARGETS)` and exported with +:command:`install(EXPORT)` and :command:`export`. + +C++ module sets may be defined using the :command:`target_sources` command +``FILE_SET`` option with type ``CXX_MODULES``. + +See also :prop_tgt:`CXX_MODULE_SETS`. diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx index 6ce0c98..af33ada 100644 --- a/Source/cmExportBuildFileGenerator.cxx +++ b/Source/cmExportBuildFileGenerator.cxx @@ -9,7 +9,9 @@ #include #include +#include #include +#include #include "cmExportSet.h" #include "cmFileSet.h" @@ -382,6 +384,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 +444,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( diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx index adccdfe..3a06769 100644 --- a/Source/cmExportInstallFileGenerator.cxx +++ b/Source/cmExportInstallFileGenerator.cxx @@ -7,6 +7,9 @@ #include #include +#include +#include + #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" @@ -562,6 +566,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("\"$<$:", dest, ">\"")); @@ -610,6 +629,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) { diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 8a7215b..6fb28ae 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -1707,7 +1707,8 @@ void addFileSetEntry(cmGeneratorTarget const* headTarget, } } 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); } @@ -1728,6 +1729,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, @@ -8700,3 +8715,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..349afa7 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -1196,4 +1196,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/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 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>>& dependencies) = 0; + virtual bool SupportsCxxModuleDyndep() const { return false; } + std::string ConvertToSolutionPath(const std::string& path); std::set IsPartOfDefaultBuild( diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index e02f30e..5738799 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -1376,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) { diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index aec6577..b066c34 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" @@ -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 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> 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 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() diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 4a9396a..ee065c4 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -36,7 +36,6 @@ #include "cmRange.h" #include "cmRulePlaceholderExpander.h" #include "cmSourceFile.h" -#include "cmStandardLevelResolver.h" #include "cmState.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" @@ -153,17 +152,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 +249,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> files; - for (auto const& entry : fileEntries) { - file_set->EvaluateFileEntry(directories, files, entry, - this->LocalGenerator, config, - this->GeneratorTarget); - } + std::map> 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 +1034,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) diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 83dc1c2..4a94dc6 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -272,6 +272,8 @@ public: cmListFileBacktrace Backtrace; FileSetType HeadersFileSets; + FileSetType CxxModulesFileSets; + FileSetType CxxModuleHeadersFileSets; cmTargetInternals(); @@ -301,6 +303,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)) { } @@ -1366,11 +1381,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); @@ -1630,6 +1666,12 @@ 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); } @@ -1741,6 +1783,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 { @@ -2249,6 +2298,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); @@ -2526,6 +2586,11 @@ std::pair 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); @@ -2536,6 +2601,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 ""; } @@ -2544,6 +2615,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 ""; } @@ -2571,6 +2648,8 @@ std::vector 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 5ed018e..94d6688 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -275,8 +275,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/cmTargetSourcesCommand.cxx b/Source/cmTargetSourcesCommand.cxx index b1367e1..e4244a6 100644 --- a/Source/cmTargetSourcesCommand.cxx +++ b/Source/cmTargetSourcesCommand.cxx @@ -9,6 +9,7 @@ #include #include "cmArgumentParser.h" +#include "cmExperimental.h" #include "cmFileSet.h" #include "cmGeneratorExpression.h" #include "cmListFileCache.h" @@ -256,9 +257,30 @@ 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)) { + 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,7 +316,7 @@ bool TargetSourcesImpl::HandleOneFileSet( if (!baseDirectories.empty()) { fileSet.first->AddDirectoryEntry( BT(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("$"); diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index c79331c..5b9a8a7 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -347,6 +347,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 = this->ComputeProjectType(this->GeneratorTarget); this->Managed = this->ProjectType == VsProjectType::csproj; const std::string ProjectFileExtension = diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index 5325a3a..3d2654c 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -564,6 +564,9 @@ if(CMake_TEST_CUDA) endif() add_RunCMake_test(DependencyGraph -DCMAKE_Fortran_COMPILER=${CMAKE_Fortran_COMPILER}) +# Add C++ Module tests. +add_RunCMake_test(CXXModules) + # ctresalloc links against CMakeLib and CTestLib, which means it can't be built # if CMake_TEST_EXTERNAL_CMAKE is activated (the compiler might be different.) # So, it has to be provided in the original build tree. diff --git a/Tests/RunCMake/CXXModules/CMakeLists.txt b/Tests/RunCMake/CXXModules/CMakeLists.txt new file mode 100644 index 0000000..338a412 --- /dev/null +++ b/Tests/RunCMake/CXXModules/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.23) +project(${RunCMake_TEST} NONE) + +set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "17be90bd-a850-44e0-be50-448de847d652") + +include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsInterface-result.txt b/Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsInterface-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsInterface-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsInterface-stderr.txt b/Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsInterface-stderr.txt new file mode 100644 index 0000000..d573a02 --- /dev/null +++ b/Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsInterface-stderr.txt @@ -0,0 +1,12 @@ +CMake Warning \(dev\) at FileSetModuleHeaderUnitsInterface.cmake:2 \(target_sources\): + CMake's C\+\+ module support is experimental. It is meant only for + experimentation and feedback to CMake developers. +Call Stack \(most recent call first\): + CMakeLists.txt:6 \(include\) +This warning is for project developers. Use -Wno-dev to suppress it. + +CMake Error at FileSetModuleHeaderUnitsInterface.cmake:2 \(target_sources\): + target_sources File set TYPEs "CXX_MODULES" and "CXX_MODULE_HEADER_UNITS" + may not have "INTERFACE" visibility +Call Stack \(most recent call first\): + CMakeLists.txt:6 \(include\) diff --git a/Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsInterface.cmake b/Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsInterface.cmake new file mode 100644 index 0000000..03ca17e --- /dev/null +++ b/Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsInterface.cmake @@ -0,0 +1,8 @@ +add_library(module-header) +target_sources(module-header + INTERFACE + FILE_SET fs TYPE CXX_MODULE_HEADER_UNITS FILES + sources/module-header.h) +target_compile_features(module-header + PRIVATE + cxx_std_20) diff --git a/Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsPrivate-stderr.txt b/Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsPrivate-stderr.txt new file mode 100644 index 0000000..a7ac88e --- /dev/null +++ b/Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsPrivate-stderr.txt @@ -0,0 +1,11 @@ +CMake Warning \(dev\) at FileSetModuleHeaderUnitsPrivate.cmake:7 \(target_sources\): + CMake's C\+\+ module support is experimental. It is meant only for + experimentation and feedback to CMake developers. +Call Stack \(most recent call first\): + CMakeLists.txt:6 \(include\) +This warning is for project developers. Use -Wno-dev to suppress it. + +CMake Warning \(dev\): + C\+\+20 modules support via CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP is + experimental. It is meant only for compiler developers to try. +This warning is for project developers. Use -Wno-dev to suppress it. diff --git a/Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsPrivate.cmake b/Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsPrivate.cmake new file mode 100644 index 0000000..ebf9853 --- /dev/null +++ b/Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsPrivate.cmake @@ -0,0 +1,13 @@ +enable_language(CXX) +set(CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP 1) +set(CMAKE_EXPERIMENTAL_CXX_SCANDEP_SOURCE "") + +add_library(module-header + sources/cxx-anchor.cxx) +target_sources(module-header + PRIVATE + FILE_SET fs TYPE CXX_MODULE_HEADER_UNITS FILES + sources/module-header.h) +target_compile_features(module-header + PRIVATE + cxx_std_20) diff --git a/Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsPublic-stderr.txt b/Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsPublic-stderr.txt new file mode 100644 index 0000000..a5b4ede --- /dev/null +++ b/Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsPublic-stderr.txt @@ -0,0 +1,11 @@ +CMake Warning \(dev\) at FileSetModuleHeaderUnitsPublic.cmake:7 \(target_sources\): + CMake's C\+\+ module support is experimental. It is meant only for + experimentation and feedback to CMake developers. +Call Stack \(most recent call first\): + CMakeLists.txt:6 \(include\) +This warning is for project developers. Use -Wno-dev to suppress it. + +CMake Warning \(dev\): + C\+\+20 modules support via CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP is + experimental. It is meant only for compiler developers to try. +This warning is for project developers. Use -Wno-dev to suppress it. diff --git a/Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsPublic.cmake b/Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsPublic.cmake new file mode 100644 index 0000000..3dfccbb5 --- /dev/null +++ b/Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsPublic.cmake @@ -0,0 +1,13 @@ +enable_language(CXX) +set(CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP 1) +set(CMAKE_EXPERIMENTAL_CXX_SCANDEP_SOURCE "") + +add_library(module-header + sources/cxx-anchor.cxx) +target_sources(module-header + PUBLIC + FILE_SET fs TYPE CXX_MODULE_HEADER_UNITS FILES + sources/module-header.h) +target_compile_features(module-header + PRIVATE + cxx_std_20) diff --git a/Tests/RunCMake/CXXModules/FileSetModulesInterface-result.txt b/Tests/RunCMake/CXXModules/FileSetModulesInterface-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CXXModules/FileSetModulesInterface-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CXXModules/FileSetModulesInterface-stderr.txt b/Tests/RunCMake/CXXModules/FileSetModulesInterface-stderr.txt new file mode 100644 index 0000000..81a35e8 --- /dev/null +++ b/Tests/RunCMake/CXXModules/FileSetModulesInterface-stderr.txt @@ -0,0 +1,12 @@ +CMake Warning \(dev\) at FileSetModulesInterface.cmake:2 \(target_sources\): + CMake's C\+\+ module support is experimental. It is meant only for + experimentation and feedback to CMake developers. +Call Stack \(most recent call first\): + CMakeLists.txt:6 \(include\) +This warning is for project developers. Use -Wno-dev to suppress it. + +CMake Error at FileSetModulesInterface.cmake:2 \(target_sources\): + target_sources File set TYPEs "CXX_MODULES" and "CXX_MODULE_HEADER_UNITS" + may not have "INTERFACE" visibility +Call Stack \(most recent call first\): + CMakeLists.txt:6 \(include\) diff --git a/Tests/RunCMake/CXXModules/FileSetModulesInterface.cmake b/Tests/RunCMake/CXXModules/FileSetModulesInterface.cmake new file mode 100644 index 0000000..24cec3e --- /dev/null +++ b/Tests/RunCMake/CXXModules/FileSetModulesInterface.cmake @@ -0,0 +1,8 @@ +add_library(module) +target_sources(module + INTERFACE + FILE_SET fs TYPE CXX_MODULES FILES + sources/module.cxx) +target_compile_features(module + PRIVATE + cxx_std_20) diff --git a/Tests/RunCMake/CXXModules/FileSetModulesPrivate-stderr.txt b/Tests/RunCMake/CXXModules/FileSetModulesPrivate-stderr.txt new file mode 100644 index 0000000..03e06cc --- /dev/null +++ b/Tests/RunCMake/CXXModules/FileSetModulesPrivate-stderr.txt @@ -0,0 +1,11 @@ +CMake Warning \(dev\) at FileSetModulesPrivate.cmake:6 \(target_sources\): + CMake's C\+\+ module support is experimental. It is meant only for + experimentation and feedback to CMake developers. +Call Stack \(most recent call first\): + CMakeLists.txt:6 \(include\) +This warning is for project developers. Use -Wno-dev to suppress it. + +CMake Warning \(dev\): + C\+\+20 modules support via CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP is + experimental. It is meant only for compiler developers to try. +This warning is for project developers. Use -Wno-dev to suppress it. diff --git a/Tests/RunCMake/CXXModules/FileSetModulesPrivate.cmake b/Tests/RunCMake/CXXModules/FileSetModulesPrivate.cmake new file mode 100644 index 0000000..ca18982 --- /dev/null +++ b/Tests/RunCMake/CXXModules/FileSetModulesPrivate.cmake @@ -0,0 +1,12 @@ +enable_language(CXX) +set(CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP 1) +set(CMAKE_EXPERIMENTAL_CXX_SCANDEP_SOURCE "") + +add_library(module) +target_sources(module + PRIVATE + FILE_SET fs TYPE CXX_MODULES FILES + sources/module.cxx) +target_compile_features(module + PRIVATE + cxx_std_20) diff --git a/Tests/RunCMake/CXXModules/FileSetModulesPublic-stderr.txt b/Tests/RunCMake/CXXModules/FileSetModulesPublic-stderr.txt new file mode 100644 index 0000000..0c110c3 --- /dev/null +++ b/Tests/RunCMake/CXXModules/FileSetModulesPublic-stderr.txt @@ -0,0 +1,11 @@ +CMake Warning \(dev\) at FileSetModulesPublic.cmake:6 \(target_sources\): + CMake's C\+\+ module support is experimental. It is meant only for + experimentation and feedback to CMake developers. +Call Stack \(most recent call first\): + CMakeLists.txt:6 \(include\) +This warning is for project developers. Use -Wno-dev to suppress it. + +CMake Warning \(dev\): + C\+\+20 modules support via CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP is + experimental. It is meant only for compiler developers to try. +This warning is for project developers. Use -Wno-dev to suppress it. diff --git a/Tests/RunCMake/CXXModules/FileSetModulesPublic.cmake b/Tests/RunCMake/CXXModules/FileSetModulesPublic.cmake new file mode 100644 index 0000000..58de174 --- /dev/null +++ b/Tests/RunCMake/CXXModules/FileSetModulesPublic.cmake @@ -0,0 +1,12 @@ +enable_language(CXX) +set(CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP 1) +set(CMAKE_EXPERIMENTAL_CXX_SCANDEP_SOURCE "") + +add_library(module) +target_sources(module + PUBLIC + FILE_SET fs TYPE CXX_MODULES FILES + sources/module.cxx) +target_compile_features(module + PRIVATE + cxx_std_20) diff --git a/Tests/RunCMake/CXXModules/NoCXX-result.txt b/Tests/RunCMake/CXXModules/NoCXX-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CXXModules/NoCXX-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CXXModules/NoCXX-stderr.txt b/Tests/RunCMake/CXXModules/NoCXX-stderr.txt new file mode 100644 index 0000000..aa7f406 --- /dev/null +++ b/Tests/RunCMake/CXXModules/NoCXX-stderr.txt @@ -0,0 +1,20 @@ +CMake Warning \(dev\) at NoCXX.cmake:4 \(target_sources\): + CMake's C\+\+ module support is experimental. It is meant only for + experimentation and feedback to CMake developers. +Call Stack \(most recent call first\): + CMakeLists.txt:6 \(include\) +This warning is for project developers. Use -Wno-dev to suppress it. + +CMake Error in CMakeLists.txt: + The "nocxx" target has C\+\+ module sources but the "CXX" language has not + been enabled + +( +CMake Error in CMakeLists.txt: +( The "nocxx" target has C\+\+ module sources but the "CXX" language has not + been enabled +| The "nocxx" target contains C\+\+ module sources which are not supported by + the generator +) +)* +CMake Generate step failed. Build files cannot be regenerated correctly. diff --git a/Tests/RunCMake/CXXModules/NoCXX.cmake b/Tests/RunCMake/CXXModules/NoCXX.cmake new file mode 100644 index 0000000..3c46f9d --- /dev/null +++ b/Tests/RunCMake/CXXModules/NoCXX.cmake @@ -0,0 +1,9 @@ +enable_language(C) + +add_library(nocxx) +target_sources(nocxx + PRIVATE + sources/c-anchor.c + PUBLIC + FILE_SET fs TYPE CXX_MODULES FILES + sources/module.cxx) diff --git a/Tests/RunCMake/CXXModules/NoCXX20-result.txt b/Tests/RunCMake/CXXModules/NoCXX20-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CXXModules/NoCXX20-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CXXModules/NoCXX20-stderr.txt b/Tests/RunCMake/CXXModules/NoCXX20-stderr.txt new file mode 100644 index 0000000..95d73b1 --- /dev/null +++ b/Tests/RunCMake/CXXModules/NoCXX20-stderr.txt @@ -0,0 +1,20 @@ +CMake Warning \(dev\) at NoCXX20.cmake:4 \(target_sources\): + CMake's C\+\+ module support is experimental. It is meant only for + experimentation and feedback to CMake developers. +Call Stack \(most recent call first\): + CMakeLists.txt:6 \(include\) +This warning is for project developers. Use -Wno-dev to suppress it. + +CMake Error in CMakeLists.txt: + The "nocxx20" target has C\+\+ module sources but is not using at least + "cxx_std_20" + +( +CMake Error in CMakeLists.txt: +( The "nocxx20" target has C\+\+ module sources but is not using at least + "cxx_std_20" +| The "nocxx20" target contains C\+\+ module sources which are not supported by + the generator +) +)* +CMake Generate step failed. Build files cannot be regenerated correctly. diff --git a/Tests/RunCMake/CXXModules/NoCXX20.cmake b/Tests/RunCMake/CXXModules/NoCXX20.cmake new file mode 100644 index 0000000..d502f7c --- /dev/null +++ b/Tests/RunCMake/CXXModules/NoCXX20.cmake @@ -0,0 +1,10 @@ +enable_language(CXX) + +add_library(nocxx20) +target_sources(nocxx20 + PUBLIC + FILE_SET fs TYPE CXX_MODULES FILES + sources/module.cxx) +target_compile_features(nocxx20 + PRIVATE + cxx_std_17) diff --git a/Tests/RunCMake/CXXModules/NoCXX20ModuleFlag-result.txt b/Tests/RunCMake/CXXModules/NoCXX20ModuleFlag-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CXXModules/NoCXX20ModuleFlag-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CXXModules/NoCXX20ModuleFlag-stderr.txt b/Tests/RunCMake/CXXModules/NoCXX20ModuleFlag-stderr.txt new file mode 100644 index 0000000..5f90ec8 --- /dev/null +++ b/Tests/RunCMake/CXXModules/NoCXX20ModuleFlag-stderr.txt @@ -0,0 +1,20 @@ +CMake Warning \(dev\) at NoCXX20ModuleFlag.cmake:4 \(target_sources\): + CMake's C\+\+ module support is experimental. It is meant only for + experimentation and feedback to CMake developers. +Call Stack \(most recent call first\): + CMakeLists.txt:6 \(include\) +This warning is for project developers. Use -Wno-dev to suppress it. + +CMake Error in CMakeLists.txt: + The "noexperimentalflag" target has C\+\+ module sources but its experimental + support has not been requested + +( +CMake Error in CMakeLists.txt: +( The "noexperimentalflag" target has C\+\+ module sources but its experimental + support has not been requested +| The "noexperimentalflag" target contains C\+\+ module sources which are not + supported by the generator +) +)* +CMake Generate step failed. Build files cannot be regenerated correctly. diff --git a/Tests/RunCMake/CXXModules/NoCXX20ModuleFlag.cmake b/Tests/RunCMake/CXXModules/NoCXX20ModuleFlag.cmake new file mode 100644 index 0000000..5f896f9 --- /dev/null +++ b/Tests/RunCMake/CXXModules/NoCXX20ModuleFlag.cmake @@ -0,0 +1,10 @@ +enable_language(CXX) + +add_library(noexperimentalflag) +target_sources(noexperimentalflag + PUBLIC + FILE_SET fs TYPE CXX_MODULES FILES + sources/module.cxx) +target_compile_features(noexperimentalflag + PRIVATE + cxx_std_20) diff --git a/Tests/RunCMake/CXXModules/NoDyndepSupport-result.txt b/Tests/RunCMake/CXXModules/NoDyndepSupport-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CXXModules/NoDyndepSupport-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CXXModules/NoDyndepSupport-stderr.txt b/Tests/RunCMake/CXXModules/NoDyndepSupport-stderr.txt new file mode 100644 index 0000000..52f781f --- /dev/null +++ b/Tests/RunCMake/CXXModules/NoDyndepSupport-stderr.txt @@ -0,0 +1,30 @@ +CMake Warning \(dev\) at NoDyndepSupport.cmake:10 \(target_sources\): + CMake's C\+\+ module support is experimental. It is meant only for + experimentation and feedback to CMake developers. +Call Stack \(most recent call first\): + CMakeLists.txt:6 \(include\) +This warning is for project developers. Use -Wno-dev to suppress it. + +(CMake Warning \(dev\): + C\+\+20 modules support via CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP is + experimental. It is meant only for compiler developers to try. +This warning is for project developers. Use -Wno-dev to suppress it. + +CMake Error: + The Ninja generator does not support C\+\+20 modules using Ninja version + + .* + + due to lack of required features. Ninja 1.10 or higher is required. + +|CMake Error in CMakeLists.txt: + The "nodyndep" target contains C\+\+ module sources which are not supported + by the generator + +( +CMake Error in CMakeLists.txt: + The "nodyndep" target contains C\+\+ module sources which are not supported + by the generator + +)*) +CMake Generate step failed. Build files cannot be regenerated correctly. diff --git a/Tests/RunCMake/CXXModules/NoDyndepSupport.cmake b/Tests/RunCMake/CXXModules/NoDyndepSupport.cmake new file mode 100644 index 0000000..0954400 --- /dev/null +++ b/Tests/RunCMake/CXXModules/NoDyndepSupport.cmake @@ -0,0 +1,16 @@ +enable_language(CXX) +set(CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP 1) +set(CMAKE_EXPERIMENTAL_CXX_SCANDEP_SOURCE "") + +if (NOT CMAKE_CXX_STANDARD_DEFAULT) + set(CMAKE_CXX_STANDARD_DEFAULT "11") +endif () + +add_library(nodyndep) +target_sources(nodyndep + PUBLIC + FILE_SET fs TYPE CXX_MODULES FILES + sources/module.cxx) +target_compile_features(nodyndep + PRIVATE + cxx_std_20) diff --git a/Tests/RunCMake/CXXModules/NotCXXSourceModuleHeaderUnits-result.txt b/Tests/RunCMake/CXXModules/NotCXXSourceModuleHeaderUnits-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CXXModules/NotCXXSourceModuleHeaderUnits-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CXXModules/NotCXXSourceModuleHeaderUnits-stderr.txt b/Tests/RunCMake/CXXModules/NotCXXSourceModuleHeaderUnits-stderr.txt new file mode 100644 index 0000000..a93eb40 --- /dev/null +++ b/Tests/RunCMake/CXXModules/NotCXXSourceModuleHeaderUnits-stderr.txt @@ -0,0 +1,22 @@ +CMake Warning \(dev\) at NotCXXSourceModuleHeaderUnits.cmake:7 \(target_sources\): + CMake's C\+\+ module support is experimental. It is meant only for + experimentation and feedback to CMake developers. +Call Stack \(most recent call first\): + CMakeLists.txt:6 \(include\) +This warning is for project developers. Use -Wno-dev to suppress it. + +CMake Warning \(dev\): + C\+\+20 modules support via CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP is + experimental. It is meant only for compiler developers to try. +This warning is for project developers. Use -Wno-dev to suppress it. + +CMake Error in CMakeLists.txt: + Target "not-cxx-source" contains the source + + .*/Tests/RunCMake/CXXModules/sources/c-anchor.c + + in a file set of type "CXX_MODULE_HEADER_UNITS" but the source is not + classified as a "CXX" source. + + +CMake Generate step failed. Build files cannot be regenerated correctly. diff --git a/Tests/RunCMake/CXXModules/NotCXXSourceModuleHeaderUnits.cmake b/Tests/RunCMake/CXXModules/NotCXXSourceModuleHeaderUnits.cmake new file mode 100644 index 0000000..af4ddac --- /dev/null +++ b/Tests/RunCMake/CXXModules/NotCXXSourceModuleHeaderUnits.cmake @@ -0,0 +1,15 @@ +enable_language(C) +enable_language(CXX) +set(CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP 1) +set(CMAKE_EXPERIMENTAL_CXX_SCANDEP_SOURCE "") + +add_library(not-cxx-source) +target_sources(not-cxx-source + PRIVATE + sources/cxx-anchor.cxx + PUBLIC + FILE_SET fs TYPE CXX_MODULE_HEADER_UNITS FILES + sources/c-anchor.c) +target_compile_features(not-cxx-source + PRIVATE + cxx_std_20) diff --git a/Tests/RunCMake/CXXModules/NotCXXSourceModules-result.txt b/Tests/RunCMake/CXXModules/NotCXXSourceModules-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CXXModules/NotCXXSourceModules-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CXXModules/NotCXXSourceModules-stderr.txt b/Tests/RunCMake/CXXModules/NotCXXSourceModules-stderr.txt new file mode 100644 index 0000000..d341c1f --- /dev/null +++ b/Tests/RunCMake/CXXModules/NotCXXSourceModules-stderr.txt @@ -0,0 +1,17 @@ +CMake Warning \(dev\) at NotCXXSourceModules.cmake:7 \(target_sources\): + CMake's C\+\+ module support is experimental. It is meant only for + experimentation and feedback to CMake developers. +Call Stack \(most recent call first\): + CMakeLists.txt:6 \(include\) +This warning is for project developers. Use -Wno-dev to suppress it. + +CMake Error in CMakeLists.txt: + Target "not-cxx-source" contains the source + + .*/Tests/RunCMake/CXXModules/sources/c-anchor.c + + in a file set of type "CXX_MODULES" but the source is not classified as a + "CXX" source. + + +CMake Generate step failed. Build files cannot be regenerated correctly. diff --git a/Tests/RunCMake/CXXModules/NotCXXSourceModules.cmake b/Tests/RunCMake/CXXModules/NotCXXSourceModules.cmake new file mode 100644 index 0000000..f7a6060 --- /dev/null +++ b/Tests/RunCMake/CXXModules/NotCXXSourceModules.cmake @@ -0,0 +1,13 @@ +enable_language(C) +enable_language(CXX) +set(CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP 1) +set(CMAKE_EXPERIMENTAL_CXX_SCANDEP_SOURCE "") + +add_library(not-cxx-source) +target_sources(not-cxx-source + PUBLIC + FILE_SET fs TYPE CXX_MODULES FILES + sources/c-anchor.c) +target_compile_features(not-cxx-source + PRIVATE + cxx_std_20) diff --git a/Tests/RunCMake/CXXModules/RunCMakeTest.cmake b/Tests/RunCMake/CXXModules/RunCMakeTest.cmake new file mode 100644 index 0000000..00c1a8b --- /dev/null +++ b/Tests/RunCMake/CXXModules/RunCMakeTest.cmake @@ -0,0 +1,67 @@ +include(RunCMake) + +# For `if (IN_LIST)` +cmake_policy(SET CMP0057 NEW) + +run_cmake(compiler_introspection) +include("${RunCMake_BINARY_DIR}/compiler_introspection-build/info.cmake") + +# Test negative cases where C++20 modules do not work. +run_cmake(NoCXX) +if ("cxx_std_20" IN_LIST CMAKE_CXX_COMPILE_FEATURES) + # This test requires that the compiler be told to compile in an older-than-20 + # standard. If the compiler forces a standard to be used, skip it. + if (NOT forced_cxx_standard) + run_cmake(NoCXX20) + endif () + + # This test uses C++20, but another prerequisite is missing, so forced + # standards don't matter. + run_cmake(NoCXX20ModuleFlag) +endif () + +if (RunCMake_GENERATOR MATCHES "Ninja") + execute_process( + COMMAND "${CMAKE_MAKE_PROGRAM}" --version + RESULT_VARIABLE res + OUTPUT_VARIABLE ninja_version + ERROR_VARIABLE err + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_STRIP_TRAILING_WHITESPACE) + + if (res) + message(WARNING + "Failed to determine `ninja` version: ${err}") + set(ninja_version "0") + endif () +endif () + +# Test behavior when the generator does not support C++20 modules. +if (NOT RunCMake_GENERATOR MATCHES "Ninja" OR + ninja_version VERSION_LESS "1.10" OR + NOT "cxx_std_20" IN_LIST CMAKE_CXX_COMPILE_FEATURES) + if ("cxx_std_20" IN_LIST CMAKE_CXX_COMPILE_FEATURES) + run_cmake(NoDyndepSupport) + endif () + + # Bail; the remaining tests require the generator to successfully generate + # with C++20 modules in the source list. + return () +endif () + +set(fileset_types + Modules + ModuleHeaderUnits) +set(scopes + Interface + Private + Public) +foreach (fileset_type IN LISTS fileset_types) + foreach (scope IN LISTS scopes) + run_cmake("FileSet${fileset_type}${scope}") + endforeach () + + # Test the error message when a non-C++ source file is found in the source + # list. + run_cmake("NotCXXSource${fileset_type}") +endforeach () diff --git a/Tests/RunCMake/CXXModules/compiler_introspection.cmake b/Tests/RunCMake/CXXModules/compiler_introspection.cmake new file mode 100644 index 0000000..7a2df3d --- /dev/null +++ b/Tests/RunCMake/CXXModules/compiler_introspection.cmake @@ -0,0 +1,25 @@ +enable_language(CXX) + +set(info "") + +# See `Modules/Compiler/MSVC-CXX.cmake` for this. If there is explicitly no +# default, the feature list is populated to be everything. +if (DEFINED CMAKE_CXX_STANDARD_DEFAULT AND + CMAKE_CXX_STANDARD_DEFAULT STREQUAL "") + set(CMAKE_CXX_COMPILE_FEATURES "") +endif () + +# Detect if the environment forces a C++ standard, let the test selection know. +set(forced_cxx_standard 0) +if (CMAKE_CXX_FLAGS MATCHES "-std=") + set(forced_cxx_standard 1) +endif () + +# Forward information about the C++ compile features. +string(APPEND info "\ +set(CMAKE_CXX_COMPILE_FEATURES \"${CMAKE_CXX_COMPILE_FEATURES}\") +set(CMAKE_MAKE_PROGRAM \"${CMAKE_MAKE_PROGRAM}\") +set(forced_cxx_standard \"${forced_cxx_standard}\") +") + +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/info.cmake" "${info}") diff --git a/Tests/RunCMake/CXXModules/sources/c-anchor.c b/Tests/RunCMake/CXXModules/sources/c-anchor.c new file mode 100644 index 0000000..c782188 --- /dev/null +++ b/Tests/RunCMake/CXXModules/sources/c-anchor.c @@ -0,0 +1,4 @@ +int c_anchor() +{ + return 0; +} diff --git a/Tests/RunCMake/CXXModules/sources/cxx-anchor.cxx b/Tests/RunCMake/CXXModules/sources/cxx-anchor.cxx new file mode 100644 index 0000000..9c94ec1 --- /dev/null +++ b/Tests/RunCMake/CXXModules/sources/cxx-anchor.cxx @@ -0,0 +1,4 @@ +int cxx_anchor() +{ + return 0; +} diff --git a/Tests/RunCMake/CXXModules/sources/module-header.h b/Tests/RunCMake/CXXModules/sources/module-header.h new file mode 100644 index 0000000..982617e --- /dev/null +++ b/Tests/RunCMake/CXXModules/sources/module-header.h @@ -0,0 +1,9 @@ +#ifndef module_header_h +#define module_header_h + +inline int h() +{ + return 0; +} + +#endif diff --git a/Tests/RunCMake/CXXModules/sources/module-impl.cxx b/Tests/RunCMake/CXXModules/sources/module-impl.cxx new file mode 100644 index 0000000..4718999 --- /dev/null +++ b/Tests/RunCMake/CXXModules/sources/module-impl.cxx @@ -0,0 +1,6 @@ +module M; + +int f() +{ + return 0; +} diff --git a/Tests/RunCMake/CXXModules/sources/module-internal-part-impl.cxx b/Tests/RunCMake/CXXModules/sources/module-internal-part-impl.cxx new file mode 100644 index 0000000..be77b0d --- /dev/null +++ b/Tests/RunCMake/CXXModules/sources/module-internal-part-impl.cxx @@ -0,0 +1,11 @@ +#ifdef _MSC_VER +// Only MSVC supports this pattern. +module M : internal_part; +#else +module M; +#endif + +int i() +{ + return 0; +} diff --git a/Tests/RunCMake/CXXModules/sources/module-internal-part.cxx b/Tests/RunCMake/CXXModules/sources/module-internal-part.cxx new file mode 100644 index 0000000..fa82afb --- /dev/null +++ b/Tests/RunCMake/CXXModules/sources/module-internal-part.cxx @@ -0,0 +1,3 @@ +module M : internal_part; + +int i(); diff --git a/Tests/RunCMake/CXXModules/sources/module-part-impl.cxx b/Tests/RunCMake/CXXModules/sources/module-part-impl.cxx new file mode 100644 index 0000000..46d5d9f --- /dev/null +++ b/Tests/RunCMake/CXXModules/sources/module-part-impl.cxx @@ -0,0 +1,13 @@ +#ifdef _MSC_VER +// Only MSVC supports this pattern. +module M : part; +#else +module M; +#endif + +import M : internal_part; + +int p() +{ + return i(); +} diff --git a/Tests/RunCMake/CXXModules/sources/module-part.cxx b/Tests/RunCMake/CXXModules/sources/module-part.cxx new file mode 100644 index 0000000..137c16f --- /dev/null +++ b/Tests/RunCMake/CXXModules/sources/module-part.cxx @@ -0,0 +1,3 @@ +export module M : part; + +int p(); diff --git a/Tests/RunCMake/CXXModules/sources/module-use.cxx b/Tests/RunCMake/CXXModules/sources/module-use.cxx new file mode 100644 index 0000000..2d060cd --- /dev/null +++ b/Tests/RunCMake/CXXModules/sources/module-use.cxx @@ -0,0 +1,6 @@ +import M; + +int main(int argc, char* argv[]) +{ + return f() + p(); +} diff --git a/Tests/RunCMake/CXXModules/sources/module.cxx b/Tests/RunCMake/CXXModules/sources/module.cxx new file mode 100644 index 0000000..a631354 --- /dev/null +++ b/Tests/RunCMake/CXXModules/sources/module.cxx @@ -0,0 +1,5 @@ +export module M; +export import M : part; +import M : internal_part; + +int f(); diff --git a/Tests/RunCMake/target_sources/FileSetDefaultWrongTypeExperimental-result.txt b/Tests/RunCMake/target_sources/FileSetDefaultWrongTypeExperimental-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/target_sources/FileSetDefaultWrongTypeExperimental-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/target_sources/FileSetDefaultWrongTypeExperimental-stderr.txt b/Tests/RunCMake/target_sources/FileSetDefaultWrongTypeExperimental-stderr.txt new file mode 100644 index 0000000..042d67d --- /dev/null +++ b/Tests/RunCMake/target_sources/FileSetDefaultWrongTypeExperimental-stderr.txt @@ -0,0 +1,12 @@ +^CMake Warning \(dev\) at FileSetDefaultWrongTypeExperimental.cmake:6 \(target_sources\): + CMake's C\+\+ module support is experimental. It is meant only for + experimentation and feedback to CMake developers. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) +This warning is for project developers. Use -Wno-dev to suppress it. + +CMake Error at FileSetDefaultWrongTypeExperimental\.cmake:[0-9]+ \(target_sources\): + target_sources File set TYPE may only be "HEADERS", "CXX_MODULES", or + "CXX_MODULE_HEADER_UNITS" +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/target_sources/FileSetDefaultWrongTypeExperimental.cmake b/Tests/RunCMake/target_sources/FileSetDefaultWrongTypeExperimental.cmake new file mode 100644 index 0000000..2dbcee7 --- /dev/null +++ b/Tests/RunCMake/target_sources/FileSetDefaultWrongTypeExperimental.cmake @@ -0,0 +1,6 @@ +enable_language(C) + +set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "17be90bd-a850-44e0-be50-448de847d652") + +add_library(lib1 STATIC empty.c) +target_sources(lib1 PRIVATE FILE_SET UNKNOWN) diff --git a/Tests/RunCMake/target_sources/FileSetWrongTypeExperimental-result.txt b/Tests/RunCMake/target_sources/FileSetWrongTypeExperimental-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/target_sources/FileSetWrongTypeExperimental-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/target_sources/FileSetWrongTypeExperimental-stderr.txt b/Tests/RunCMake/target_sources/FileSetWrongTypeExperimental-stderr.txt new file mode 100644 index 0000000..a1b784f --- /dev/null +++ b/Tests/RunCMake/target_sources/FileSetWrongTypeExperimental-stderr.txt @@ -0,0 +1,12 @@ +^CMake Warning \(dev\) at FileSetWrongTypeExperimental.cmake:6 \(target_sources\): + CMake's C\+\+ module support is experimental. It is meant only for + experimentation and feedback to CMake developers. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) +This warning is for project developers. Use -Wno-dev to suppress it. + +CMake Error at FileSetWrongTypeExperimental\.cmake:[0-9]+ \(target_sources\): + target_sources File set TYPE may only be "HEADERS", "CXX_MODULES", or + "CXX_MODULE_HEADER_UNITS" +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/target_sources/FileSetWrongTypeExperimental.cmake b/Tests/RunCMake/target_sources/FileSetWrongTypeExperimental.cmake new file mode 100644 index 0000000..024c2cb --- /dev/null +++ b/Tests/RunCMake/target_sources/FileSetWrongTypeExperimental.cmake @@ -0,0 +1,6 @@ +enable_language(C) + +set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "17be90bd-a850-44e0-be50-448de847d652") + +add_library(lib1 STATIC empty.c) +target_sources(lib1 PRIVATE FILE_SET a TYPE UNKNOWN) diff --git a/Tests/RunCMake/target_sources/RunCMakeTest.cmake b/Tests/RunCMake/target_sources/RunCMakeTest.cmake index e78ee9d..135777b 100644 --- a/Tests/RunCMake/target_sources/RunCMakeTest.cmake +++ b/Tests/RunCMake/target_sources/RunCMakeTest.cmake @@ -26,6 +26,8 @@ run_cmake(FileSetProperties) run_cmake(FileSetNoType) run_cmake(FileSetWrongType) run_cmake(FileSetDefaultWrongType) +run_cmake(FileSetWrongTypeExperimental) +run_cmake(FileSetDefaultWrongTypeExperimental) run_cmake(FileSetChangeScope) run_cmake(FileSetChangeType) run_cmake(FileSetWrongBaseDirs) diff --git a/Tests/RunCMake/try_compile/CxxStandard-stderr.txt b/Tests/RunCMake/try_compile/CxxStandard-stderr.txt index ec7245f..cee1b44 100644 --- a/Tests/RunCMake/try_compile/CxxStandard-stderr.txt +++ b/Tests/RunCMake/try_compile/CxxStandard-stderr.txt @@ -1,6 +1,17 @@ -^CMake Error at .*/Tests/RunCMake/try_compile/CxxStandard-build/CMakeFiles/CMakeTmp/CMakeLists.txt:[0-9]+ \(add_executable\): +^(CMake Error in .*/Tests/RunCMake/try_compile/CxxStandard-build/CMakeFiles/CMakeTmp/CMakeLists.txt: + The CXX_STANDARD property on target "cmTC_[0-9a-f]*" contained an invalid + value: "3". + + +)?CMake Error at .*/Tests/RunCMake/try_compile/CxxStandard-build/CMakeFiles/CMakeTmp/CMakeLists.txt:[0-9]+ \(add_executable\): CXX_STANDARD is set to invalid value '3' -+ + +( +CMake Error in .*/Tests/RunCMake/try_compile/CxxStandard-build/CMakeFiles/CMakeTmp/CMakeLists.txt: + The CXX_STANDARD property on target "cmTC_[0-9a-f]*" contained an invalid + value: "3". + +)? CMake Error at CxxStandard.cmake:[0-9]+ \(try_compile\): Failed to generate test project build system. Call Stack \(most recent call first\): -- cgit v0.12 From a046a45aada109861741f45bc6b097e15084ddd4 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Tue, 31 May 2022 19:46:01 -0400 Subject: cmGlobalNinjaGenerator: add a TODO for header units --- Source/cmGlobalNinjaGenerator.cxx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index fcd3b23..9c1d4e5 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -2555,7 +2555,8 @@ 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); } -- cgit v0.12 From 02d0f0e752ec9d9ab099c7005a9eedd7bf4b94a1 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Thu, 2 Jun 2022 17:18:37 -0400 Subject: cmCxxModuleMapper: add source to handle module mapper contents This will allow all generators to share an implementation for actually writing out the module map formats. --- Source/CMakeLists.txt | 2 ++ Source/cmCxxModuleMapper.cxx | 30 ++++++++++++++++++++++++++++ Source/cmCxxModuleMapper.h | 47 ++++++++++++++++++++++++++++++++++++++++++++ bootstrap | 1 + 4 files changed, 80 insertions(+) create mode 100644 Source/cmCxxModuleMapper.cxx create mode 100644 Source/cmCxxModuleMapper.h diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index e6f7d69..6312e93 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 diff --git a/Source/cmCxxModuleMapper.cxx b/Source/cmCxxModuleMapper.cxx new file mode 100644 index 0000000..ddb95e3 --- /dev/null +++ b/Source/cmCxxModuleMapper.cxx @@ -0,0 +1,30 @@ +/* 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 + +#include "cmScanDepFormat.h" + +cm::optional CxxModuleLocations::BmiGeneratorPathForModule( + std::string const& logical_name) const +{ + if (auto l = this->BmiLocationForModule(logical_name)) { + return this->PathForGenerator(*l); + } + return {}; +} + +cm::static_string_view CxxModuleMapExtension( + cm::optional format) +{ + return ".bmi"_s; +} + +std::string CxxModuleMapContent(CxxModuleMapFormat format, + CxxModuleLocations const& loc, + cmScanDepInfo const& obj) +{ + assert(false); + return {}; +} diff --git a/Source/cmCxxModuleMapper.h b/Source/cmCxxModuleMapper.h new file mode 100644 index 0000000..ad2f88c --- /dev/null +++ b/Source/cmCxxModuleMapper.h @@ -0,0 +1,47 @@ +/* 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 +#include + +#include +#include + +struct cmScanDepInfo; + +enum class CxxModuleMapFormat +{ +}; + +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 PathForGenerator; + + // Lookup the BMI location of a logical module name. + std::function(std::string const&)> + BmiLocationForModule; + + // Returns the generator path (if known) for the BMI given a + // logical module name. + cm::optional BmiGeneratorPathForModule( + std::string const& logical_name) const; +}; + +// Return the extension to use for a given modulemap format. +cm::static_string_view CxxModuleMapExtension( + cm::optional format); + +// 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); diff --git a/bootstrap b/bootstrap index fa9f40c..f7e1544 100755 --- a/bootstrap +++ b/bootstrap @@ -328,6 +328,7 @@ CMAKE_CXX_SOURCES="\ cmCustomCommand \ cmCustomCommandGenerator \ cmCustomCommandLines \ + cmCxxModuleMapper \ cmDefinePropertyCommand \ cmDefinitions \ cmDocumentationFormatter \ -- cgit v0.12 From b43bdaff3c13fe2273ec407797ff05db89bf3761 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Thu, 2 Jun 2022 17:20:05 -0400 Subject: cmCxxModuleMapper: implement support for GCC's module map format --- Source/cmCxxModuleMapper.cxx | 46 ++++++++++++++++++++++++++++++++++++++++++++ Source/cmCxxModuleMapper.h | 1 + 2 files changed, 47 insertions(+) diff --git a/Source/cmCxxModuleMapper.cxx b/Source/cmCxxModuleMapper.cxx index ddb95e3..94ad721 100644 --- a/Source/cmCxxModuleMapper.cxx +++ b/Source/cmCxxModuleMapper.cxx @@ -3,6 +3,8 @@ #include "cmCxxModuleMapper.h" #include +#include +#include #include "cmScanDepFormat.h" @@ -15,9 +17,48 @@ cm::optional CxxModuleLocations::BmiGeneratorPathForModule( 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(); +} +} + cm::static_string_view CxxModuleMapExtension( cm::optional format) { + if (format) { + switch (*format) { + case CxxModuleMapFormat::Gcc: + return ".gcm"_s; + } + } + return ".bmi"_s; } @@ -25,6 +66,11 @@ std::string CxxModuleMapContent(CxxModuleMapFormat format, CxxModuleLocations const& loc, cmScanDepInfo const& obj) { + switch (format) { + case CxxModuleMapFormat::Gcc: + return CxxModuleMapContentGcc(loc, obj); + } + assert(false); return {}; } diff --git a/Source/cmCxxModuleMapper.h b/Source/cmCxxModuleMapper.h index ad2f88c..99384c9 100644 --- a/Source/cmCxxModuleMapper.h +++ b/Source/cmCxxModuleMapper.h @@ -14,6 +14,7 @@ struct cmScanDepInfo; enum class CxxModuleMapFormat { + Gcc, }; struct CxxModuleLocations -- cgit v0.12 From 4151547e2ffa45b50439f071353955e4566e0571 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Thu, 2 Jun 2022 17:22:57 -0400 Subject: cmGlobalNinjaGenerator: use `cmModuleMapper` implementation --- Source/cmGlobalNinjaGenerator.cxx | 69 ++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 38 deletions(-) diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index 9c1d4e5..7cbe80a 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -21,6 +22,7 @@ #include "cmsys/FStream.hxx" +#include "cmCxxModuleMapper.h" #include "cmDocumentationEntry.h" #include "cmFortranParser.h" #include "cmGeneratedFileStream.h" @@ -2534,11 +2536,20 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile( } } - const char* module_ext = ""; - if (arg_modmapfmt == "gcc") { - module_ext = ".gcm"; + cm::optional modmap_fmt; + if (arg_modmapfmt.empty()) { + // nothing to do. + } else if (arg_modmapfmt == "gcc") { + modmap_fmt = CxxModuleMapFormat::Gcc; + } 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. @@ -2569,6 +2580,20 @@ 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 { + auto m = mod_files.find(logical); + if (m != mod_files.end()) { + return m->second; + } + return {}; + }; + cmNinjaBuild build("dyndep"); build.Outputs.emplace_back(""); for (cmScanDepInfo const& object : objects) { @@ -2590,46 +2615,14 @@ 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); // 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); -- cgit v0.12 From 8c5a53096ab596aa77623b19d94d9b84046213cc Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Tue, 14 Jun 2022 15:30:42 -0400 Subject: Tests/RunCMake/CXXModules: add module-using examples This includes a number of examples that should work for various levels of support in a compiler. There are a number of tests which are gated on various features in the compilers. To enable the tests, set `CMake_TEST_MODULE_COMPILATION` to a comma-separated (to avoid `;`-escaping problems) to the list of features which are supported: - `named`: Named modules are supported. - `shared`: Shared libraries with module usage at the API boundary are supported. - `partitions`: Named module partitions are supported. - `internal_partitions`: Named module internal partitions are supported. Additionally, a `CMake_TEST_MODULE_COMPILATION_RULES` file must be passed which contains the rules for how to build modules using the provided compiler. It will be included in the tests to provide these rules. To verify that the file provided works as intended, it must set `CMake_TEST_CXXModules_UUID` to a specific version to indicate that it is an expected file. --- Tests/RunCMake/CMakeLists.txt | 2 +- Tests/RunCMake/CXXModules/RunCMakeTest.cmake | 53 ++++++++++++++++++++++ .../CXXModules/examples/cxx-modules-rules.cmake | 18 ++++++++ .../CXXModules/examples/generated-stderr.txt | 9 ++++ .../CXXModules/examples/generated/CMakeLists.txt | 23 ++++++++++ .../examples/generated/importable.cxx.in | 5 ++ .../CXXModules/examples/generated/main.cxx | 6 +++ .../examples/internal-partitions-stderr.txt | 9 ++++ .../examples/internal-partitions/CMakeLists.txt | 31 +++++++++++++ .../examples/internal-partitions/importable.cxx | 9 ++++ .../examples/internal-partitions/main.cxx | 6 +++ .../examples/internal-partitions/partition.cxx | 6 +++ .../CXXModules/examples/library-shared-stderr.txt | 9 ++++ .../CXXModules/examples/library-static-stderr.txt | 9 ++++ .../CXXModules/examples/library/CMakeLists.txt | 30 ++++++++++++ .../CXXModules/examples/library/importable.cxx | 8 ++++ .../RunCMake/CXXModules/examples/library/main.cxx | 6 +++ .../CXXModules/examples/partitions-stderr.txt | 9 ++++ .../CXXModules/examples/partitions/CMakeLists.txt | 31 +++++++++++++ .../CXXModules/examples/partitions/importable.cxx | 9 ++++ .../CXXModules/examples/partitions/main.cxx | 6 +++ .../CXXModules/examples/partitions/partition.cxx | 8 ++++ .../RunCMake/CXXModules/examples/simple-stderr.txt | 9 ++++ .../CXXModules/examples/simple/CMakeLists.txt | 18 ++++++++ .../CXXModules/examples/simple/importable.cxx | 6 +++ Tests/RunCMake/CXXModules/examples/simple/main.cxx | 6 +++ 26 files changed, 340 insertions(+), 1 deletion(-) create mode 100644 Tests/RunCMake/CXXModules/examples/cxx-modules-rules.cmake create mode 100644 Tests/RunCMake/CXXModules/examples/generated-stderr.txt create mode 100644 Tests/RunCMake/CXXModules/examples/generated/CMakeLists.txt create mode 100644 Tests/RunCMake/CXXModules/examples/generated/importable.cxx.in create mode 100644 Tests/RunCMake/CXXModules/examples/generated/main.cxx create mode 100644 Tests/RunCMake/CXXModules/examples/internal-partitions-stderr.txt create mode 100644 Tests/RunCMake/CXXModules/examples/internal-partitions/CMakeLists.txt create mode 100644 Tests/RunCMake/CXXModules/examples/internal-partitions/importable.cxx create mode 100644 Tests/RunCMake/CXXModules/examples/internal-partitions/main.cxx create mode 100644 Tests/RunCMake/CXXModules/examples/internal-partitions/partition.cxx create mode 100644 Tests/RunCMake/CXXModules/examples/library-shared-stderr.txt create mode 100644 Tests/RunCMake/CXXModules/examples/library-static-stderr.txt create mode 100644 Tests/RunCMake/CXXModules/examples/library/CMakeLists.txt create mode 100644 Tests/RunCMake/CXXModules/examples/library/importable.cxx create mode 100644 Tests/RunCMake/CXXModules/examples/library/main.cxx create mode 100644 Tests/RunCMake/CXXModules/examples/partitions-stderr.txt create mode 100644 Tests/RunCMake/CXXModules/examples/partitions/CMakeLists.txt create mode 100644 Tests/RunCMake/CXXModules/examples/partitions/importable.cxx create mode 100644 Tests/RunCMake/CXXModules/examples/partitions/main.cxx create mode 100644 Tests/RunCMake/CXXModules/examples/partitions/partition.cxx create mode 100644 Tests/RunCMake/CXXModules/examples/simple-stderr.txt create mode 100644 Tests/RunCMake/CXXModules/examples/simple/CMakeLists.txt create mode 100644 Tests/RunCMake/CXXModules/examples/simple/importable.cxx create mode 100644 Tests/RunCMake/CXXModules/examples/simple/main.cxx diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index 3d2654c..bbf8ddc 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -565,7 +565,7 @@ endif() add_RunCMake_test(DependencyGraph -DCMAKE_Fortran_COMPILER=${CMAKE_Fortran_COMPILER}) # Add C++ Module tests. -add_RunCMake_test(CXXModules) +add_RunCMake_test(CXXModules -DCMake_TEST_MODULE_COMPILATION=${CMake_TEST_MODULE_COMPILATION} -DCMake_TEST_MODULE_COMPILATION_RULES=${CMake_TEST_MODULE_COMPILATION_RULES}) # ctresalloc links against CMakeLib and CTestLib, which means it can't be built # if CMake_TEST_EXTERNAL_CMAKE is activated (the compiler might be different.) diff --git a/Tests/RunCMake/CXXModules/RunCMakeTest.cmake b/Tests/RunCMake/CXXModules/RunCMakeTest.cmake index 00c1a8b..68fdcae 100644 --- a/Tests/RunCMake/CXXModules/RunCMakeTest.cmake +++ b/Tests/RunCMake/CXXModules/RunCMakeTest.cmake @@ -65,3 +65,56 @@ foreach (fileset_type IN LISTS fileset_types) # list. run_cmake("NotCXXSource${fileset_type}") endforeach () + +# Actual compilation tests. +if (NOT CMake_TEST_MODULE_COMPILATION) + return () +endif () + +function (run_cxx_module_test directory) + set(test_name "${directory}") + if (NOT ARGN STREQUAL "") + list(POP_FRONT ARGN test_name) + endif () + + set(RunCMake_TEST_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/examples/${directory}") + set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/examples/${test_name}-build") + + if (RunCMake_GENERATOR_IS_MULTI_CONFIG) + set(RunCMake_TEST_OPTIONS -DCMAKE_CONFIGURATION_TYPES=Debug) + else () + set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Debug) + endif () + + set(RunCMake_TEST_OPTIONS + "-DCMake_TEST_MODULE_COMPILATION_RULES=${CMake_TEST_MODULE_COMPILATION_RULES}" + ${ARGN}) + run_cmake("examples/${test_name}") + set(RunCMake_TEST_NO_CLEAN 1) + run_cmake_command("${test_name}-build" "${CMAKE_COMMAND}" --build . --config Debug) + run_cmake_command("${test_name}-test" "${CMAKE_CTEST_COMMAND}" -C Debug) +endfunction () + +string(REPLACE "," ";" CMake_TEST_MODULE_COMPILATION "${CMake_TEST_MODULE_COMPILATION}") + +# Tests which use named modules. +if ("named" IN_LIST CMake_TEST_MODULE_COMPILATION) + run_cxx_module_test(simple) + run_cxx_module_test(library library-static -DBUILD_SHARED_LIBS=OFF) + run_cxx_module_test(generated) +endif () + +# Tests which use named modules in shared libraries. +if ("shared" IN_LIST CMake_TEST_MODULE_COMPILATION) + run_cxx_module_test(library library-shared -DBUILD_SHARED_LIBS=ON) +endif () + +# Tests which use partitions. +if ("partitions" IN_LIST CMake_TEST_MODULE_COMPILATION) + run_cxx_module_test(partitions) +endif () + +# Tests which use internal partitions. +if ("internal_partitions" IN_LIST CMake_TEST_MODULE_COMPILATION) + run_cxx_module_test(internal-partitions) +endif () diff --git a/Tests/RunCMake/CXXModules/examples/cxx-modules-rules.cmake b/Tests/RunCMake/CXXModules/examples/cxx-modules-rules.cmake new file mode 100644 index 0000000..91ad208 --- /dev/null +++ b/Tests/RunCMake/CXXModules/examples/cxx-modules-rules.cmake @@ -0,0 +1,18 @@ +set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "17be90bd-a850-44e0-be50-448de847d652") + +if (NOT EXISTS "${CMake_TEST_MODULE_COMPILATION_RULES}") + message(FATAL_ERROR + "The `CMake_TEST_MODULE_COMPILATION_RULES` file must be specified " + "for these tests to operate.") +endif () + +include("${CMake_TEST_MODULE_COMPILATION_RULES}") + +if (NOT CMake_TEST_CXXModules_UUID STREQUAL "a246741c-d067-4019-a8fb-3d16b0c9d1d3") + message(FATAL_ERROR + "The compilation rule file needs updated for changes in the test " + "suite. Please see the history for what needs to be updated.") +endif () + +include(CTest) +enable_testing() diff --git a/Tests/RunCMake/CXXModules/examples/generated-stderr.txt b/Tests/RunCMake/CXXModules/examples/generated-stderr.txt new file mode 100644 index 0000000..b9bbf34 --- /dev/null +++ b/Tests/RunCMake/CXXModules/examples/generated-stderr.txt @@ -0,0 +1,9 @@ +CMake Warning \(dev\) at CMakeLists.txt:12 \(target_sources\): + CMake's C\+\+ module support is experimental. It is meant only for + experimentation and feedback to CMake developers. +This warning is for project developers. Use -Wno-dev to suppress it. + +CMake Warning \(dev\): + C\+\+20 modules support via CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP is + experimental. It is meant only for compiler developers to try. +This warning is for project developers. Use -Wno-dev to suppress it. diff --git a/Tests/RunCMake/CXXModules/examples/generated/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/generated/CMakeLists.txt new file mode 100644 index 0000000..73f7ff7 --- /dev/null +++ b/Tests/RunCMake/CXXModules/examples/generated/CMakeLists.txt @@ -0,0 +1,23 @@ +cmake_minimum_required(VERSION 3.24) +project(cxx_modules_generated CXX) + +include("${CMAKE_SOURCE_DIR}/../cxx-modules-rules.cmake") + +configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/importable.cxx.in" + "${CMAKE_CURRENT_BINARY_DIR}/importable.cxx" + COPYONLY) + +add_executable(generated) +target_sources(generated + PRIVATE + main.cxx + PRIVATE + FILE_SET CXX_MODULES + BASE_DIRS + "${CMAKE_CURRENT_BINARY_DIR}" + FILES + "${CMAKE_CURRENT_BINARY_DIR}/importable.cxx") +target_compile_features(generated PUBLIC cxx_std_20) + +add_test(NAME generated COMMAND generated) diff --git a/Tests/RunCMake/CXXModules/examples/generated/importable.cxx.in b/Tests/RunCMake/CXXModules/examples/generated/importable.cxx.in new file mode 100644 index 0000000..a9287d7 --- /dev/null +++ b/Tests/RunCMake/CXXModules/examples/generated/importable.cxx.in @@ -0,0 +1,5 @@ +export module importable; + +export int from_import() { + return 0; +} diff --git a/Tests/RunCMake/CXXModules/examples/generated/main.cxx b/Tests/RunCMake/CXXModules/examples/generated/main.cxx new file mode 100644 index 0000000..feb38d2 --- /dev/null +++ b/Tests/RunCMake/CXXModules/examples/generated/main.cxx @@ -0,0 +1,6 @@ +import importable; + +int main(int argc, char* argv[]) +{ + return from_import(); +} diff --git a/Tests/RunCMake/CXXModules/examples/internal-partitions-stderr.txt b/Tests/RunCMake/CXXModules/examples/internal-partitions-stderr.txt new file mode 100644 index 0000000..4652aec --- /dev/null +++ b/Tests/RunCMake/CXXModules/examples/internal-partitions-stderr.txt @@ -0,0 +1,9 @@ +CMake Warning \(dev\) at CMakeLists.txt:10 \(target_sources\): + CMake's C\+\+ module support is experimental. It is meant only for + experimentation and feedback to CMake developers. +This warning is for project developers. Use -Wno-dev to suppress it. + +CMake Warning \(dev\): + C\+\+20 modules support via CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP is + experimental. It is meant only for compiler developers to try. +This warning is for project developers. Use -Wno-dev to suppress it. diff --git a/Tests/RunCMake/CXXModules/examples/internal-partitions/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/internal-partitions/CMakeLists.txt new file mode 100644 index 0000000..f5e9d94 --- /dev/null +++ b/Tests/RunCMake/CXXModules/examples/internal-partitions/CMakeLists.txt @@ -0,0 +1,31 @@ +cmake_minimum_required(VERSION 3.24) +project(cxx_modules_internal_partitions CXX) + +include("${CMAKE_SOURCE_DIR}/../cxx-modules-rules.cmake") + +include(GenerateExportHeader) + +add_library(internal-partitions) +generate_export_header(internal-partitions) +target_sources(internal-partitions + PUBLIC + FILE_SET HEADERS + BASE_DIRS + "${CMAKE_CURRENT_BINARY_DIR}" + FILES + "${CMAKE_CURRENT_BINARY_DIR}/internal-partitions_export.h" + FILE_SET CXX_MODULES + BASE_DIRS + "${CMAKE_CURRENT_SOURCE_DIR}" + FILES + importable.cxx + partition.cxx) +target_compile_features(internal-partitions PUBLIC cxx_std_20) + +add_executable(exe) +target_link_libraries(exe PRIVATE internal-partitions) +target_sources(exe + PRIVATE + main.cxx) + +add_test(NAME exe COMMAND exe) diff --git a/Tests/RunCMake/CXXModules/examples/internal-partitions/importable.cxx b/Tests/RunCMake/CXXModules/examples/internal-partitions/importable.cxx new file mode 100644 index 0000000..8be521b --- /dev/null +++ b/Tests/RunCMake/CXXModules/examples/internal-partitions/importable.cxx @@ -0,0 +1,9 @@ +export module importable; +import importable : internal_partition; + +#include "internal-partitions_export.h" + +export INTERNAL_PARTITIONS_EXPORT int from_import() +{ + return from_partition(); +} diff --git a/Tests/RunCMake/CXXModules/examples/internal-partitions/main.cxx b/Tests/RunCMake/CXXModules/examples/internal-partitions/main.cxx new file mode 100644 index 0000000..feb38d2 --- /dev/null +++ b/Tests/RunCMake/CXXModules/examples/internal-partitions/main.cxx @@ -0,0 +1,6 @@ +import importable; + +int main(int argc, char* argv[]) +{ + return from_import(); +} diff --git a/Tests/RunCMake/CXXModules/examples/internal-partitions/partition.cxx b/Tests/RunCMake/CXXModules/examples/internal-partitions/partition.cxx new file mode 100644 index 0000000..b15f53c --- /dev/null +++ b/Tests/RunCMake/CXXModules/examples/internal-partitions/partition.cxx @@ -0,0 +1,6 @@ +module importable : internal_partition; + +int from_partition() +{ + return 0; +} diff --git a/Tests/RunCMake/CXXModules/examples/library-shared-stderr.txt b/Tests/RunCMake/CXXModules/examples/library-shared-stderr.txt new file mode 100644 index 0000000..4652aec --- /dev/null +++ b/Tests/RunCMake/CXXModules/examples/library-shared-stderr.txt @@ -0,0 +1,9 @@ +CMake Warning \(dev\) at CMakeLists.txt:10 \(target_sources\): + CMake's C\+\+ module support is experimental. It is meant only for + experimentation and feedback to CMake developers. +This warning is for project developers. Use -Wno-dev to suppress it. + +CMake Warning \(dev\): + C\+\+20 modules support via CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP is + experimental. It is meant only for compiler developers to try. +This warning is for project developers. Use -Wno-dev to suppress it. diff --git a/Tests/RunCMake/CXXModules/examples/library-static-stderr.txt b/Tests/RunCMake/CXXModules/examples/library-static-stderr.txt new file mode 100644 index 0000000..4652aec --- /dev/null +++ b/Tests/RunCMake/CXXModules/examples/library-static-stderr.txt @@ -0,0 +1,9 @@ +CMake Warning \(dev\) at CMakeLists.txt:10 \(target_sources\): + CMake's C\+\+ module support is experimental. It is meant only for + experimentation and feedback to CMake developers. +This warning is for project developers. Use -Wno-dev to suppress it. + +CMake Warning \(dev\): + C\+\+20 modules support via CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP is + experimental. It is meant only for compiler developers to try. +This warning is for project developers. Use -Wno-dev to suppress it. diff --git a/Tests/RunCMake/CXXModules/examples/library/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/library/CMakeLists.txt new file mode 100644 index 0000000..27fd94f --- /dev/null +++ b/Tests/RunCMake/CXXModules/examples/library/CMakeLists.txt @@ -0,0 +1,30 @@ +cmake_minimum_required(VERSION 3.24) +project(cxx_modules_library CXX) + +include("${CMAKE_SOURCE_DIR}/../cxx-modules-rules.cmake") + +include(GenerateExportHeader) + +add_library(library) +generate_export_header(library) +target_sources(library + PUBLIC + FILE_SET HEADERS + BASE_DIRS + "${CMAKE_CURRENT_BINARY_DIR}" + FILES + "${CMAKE_CURRENT_BINARY_DIR}/library_export.h" + FILE_SET CXX_MODULES + BASE_DIRS + "${CMAKE_CURRENT_SOURCE_DIR}" + FILES + importable.cxx) +target_compile_features(library PUBLIC cxx_std_20) + +add_executable(exe) +target_link_libraries(exe PRIVATE library) +target_sources(exe + PRIVATE + main.cxx) + +add_test(NAME exe COMMAND exe) diff --git a/Tests/RunCMake/CXXModules/examples/library/importable.cxx b/Tests/RunCMake/CXXModules/examples/library/importable.cxx new file mode 100644 index 0000000..72ed0df --- /dev/null +++ b/Tests/RunCMake/CXXModules/examples/library/importable.cxx @@ -0,0 +1,8 @@ +export module importable; + +#include "library_export.h" + +export LIBRARY_EXPORT int from_import() +{ + return 0; +} diff --git a/Tests/RunCMake/CXXModules/examples/library/main.cxx b/Tests/RunCMake/CXXModules/examples/library/main.cxx new file mode 100644 index 0000000..feb38d2 --- /dev/null +++ b/Tests/RunCMake/CXXModules/examples/library/main.cxx @@ -0,0 +1,6 @@ +import importable; + +int main(int argc, char* argv[]) +{ + return from_import(); +} diff --git a/Tests/RunCMake/CXXModules/examples/partitions-stderr.txt b/Tests/RunCMake/CXXModules/examples/partitions-stderr.txt new file mode 100644 index 0000000..4652aec --- /dev/null +++ b/Tests/RunCMake/CXXModules/examples/partitions-stderr.txt @@ -0,0 +1,9 @@ +CMake Warning \(dev\) at CMakeLists.txt:10 \(target_sources\): + CMake's C\+\+ module support is experimental. It is meant only for + experimentation and feedback to CMake developers. +This warning is for project developers. Use -Wno-dev to suppress it. + +CMake Warning \(dev\): + C\+\+20 modules support via CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP is + experimental. It is meant only for compiler developers to try. +This warning is for project developers. Use -Wno-dev to suppress it. diff --git a/Tests/RunCMake/CXXModules/examples/partitions/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/partitions/CMakeLists.txt new file mode 100644 index 0000000..3a7b0d4 --- /dev/null +++ b/Tests/RunCMake/CXXModules/examples/partitions/CMakeLists.txt @@ -0,0 +1,31 @@ +cmake_minimum_required(VERSION 3.24) +project(cxx_modules_partitions CXX) + +include("${CMAKE_SOURCE_DIR}/../cxx-modules-rules.cmake") + +include(GenerateExportHeader) + +add_library(partitions) +generate_export_header(partitions) +target_sources(partitions + PUBLIC + FILE_SET HEADERS + BASE_DIRS + "${CMAKE_CURRENT_BINARY_DIR}" + FILES + "${CMAKE_CURRENT_BINARY_DIR}/partitions_export.h" + FILE_SET CXX_MODULES + BASE_DIRS + "${CMAKE_CURRENT_SOURCE_DIR}" + FILES + importable.cxx + partition.cxx) +target_compile_features(partitions PUBLIC cxx_std_20) + +add_executable(exe) +target_link_libraries(exe PRIVATE partitions) +target_sources(exe + PRIVATE + main.cxx) + +add_test(NAME exe COMMAND exe) diff --git a/Tests/RunCMake/CXXModules/examples/partitions/importable.cxx b/Tests/RunCMake/CXXModules/examples/partitions/importable.cxx new file mode 100644 index 0000000..1e81aaf --- /dev/null +++ b/Tests/RunCMake/CXXModules/examples/partitions/importable.cxx @@ -0,0 +1,9 @@ +export module importable; +export import importable : partition; + +#include "partitions_export.h" + +export PARTITIONS_EXPORT int from_import() +{ + return from_partition(); +} diff --git a/Tests/RunCMake/CXXModules/examples/partitions/main.cxx b/Tests/RunCMake/CXXModules/examples/partitions/main.cxx new file mode 100644 index 0000000..c5b78c9 --- /dev/null +++ b/Tests/RunCMake/CXXModules/examples/partitions/main.cxx @@ -0,0 +1,6 @@ +import importable; + +int main(int argc, char* argv[]) +{ + return from_import() + from_partition(); +} diff --git a/Tests/RunCMake/CXXModules/examples/partitions/partition.cxx b/Tests/RunCMake/CXXModules/examples/partitions/partition.cxx new file mode 100644 index 0000000..a47a4fd --- /dev/null +++ b/Tests/RunCMake/CXXModules/examples/partitions/partition.cxx @@ -0,0 +1,8 @@ +export module importable : partition; + +#include "partitions_export.h" + +export PARTITIONS_EXPORT int from_partition() +{ + return 0; +} diff --git a/Tests/RunCMake/CXXModules/examples/simple-stderr.txt b/Tests/RunCMake/CXXModules/examples/simple-stderr.txt new file mode 100644 index 0000000..5e4392a --- /dev/null +++ b/Tests/RunCMake/CXXModules/examples/simple-stderr.txt @@ -0,0 +1,9 @@ +CMake Warning \(dev\) at CMakeLists.txt:7 \(target_sources\): + CMake's C\+\+ module support is experimental. It is meant only for + experimentation and feedback to CMake developers. +This warning is for project developers. Use -Wno-dev to suppress it. + +CMake Warning \(dev\): + C\+\+20 modules support via CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP is + experimental. It is meant only for compiler developers to try. +This warning is for project developers. Use -Wno-dev to suppress it. diff --git a/Tests/RunCMake/CXXModules/examples/simple/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/simple/CMakeLists.txt new file mode 100644 index 0000000..442e425 --- /dev/null +++ b/Tests/RunCMake/CXXModules/examples/simple/CMakeLists.txt @@ -0,0 +1,18 @@ +cmake_minimum_required(VERSION 3.24) +project(cxx_modules_simple CXX) + +include("${CMAKE_SOURCE_DIR}/../cxx-modules-rules.cmake") + +add_executable(simple) +target_sources(simple + PRIVATE + main.cxx + PRIVATE + FILE_SET CXX_MODULES + BASE_DIRS + "${CMAKE_CURRENT_SOURCE_DIR}" + FILES + importable.cxx) +target_compile_features(simple PUBLIC cxx_std_20) + +add_test(NAME simple COMMAND simple) diff --git a/Tests/RunCMake/CXXModules/examples/simple/importable.cxx b/Tests/RunCMake/CXXModules/examples/simple/importable.cxx new file mode 100644 index 0000000..607680a --- /dev/null +++ b/Tests/RunCMake/CXXModules/examples/simple/importable.cxx @@ -0,0 +1,6 @@ +export module importable; + +export int from_import() +{ + return 0; +} diff --git a/Tests/RunCMake/CXXModules/examples/simple/main.cxx b/Tests/RunCMake/CXXModules/examples/simple/main.cxx new file mode 100644 index 0000000..feb38d2 --- /dev/null +++ b/Tests/RunCMake/CXXModules/examples/simple/main.cxx @@ -0,0 +1,6 @@ +import importable; + +int main(int argc, char* argv[]) +{ + return from_import(); +} -- cgit v0.12 From 1b2270aa4ed963b64e841e42b3273fe9ffe56a5e Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Tue, 14 Jun 2022 17:10:12 -0400 Subject: ci: add a Docker image to test out C++ modules with GCC --- .gitlab/ci/docker/gcc_cxx_modules/Dockerfile | 9 ++++++++ .gitlab/ci/docker/gcc_cxx_modules/install_deps.sh | 7 ++++++ .gitlab/ci/docker/gcc_cxx_modules/install_gcc.sh | 26 +++++++++++++++++++++++ 3 files changed, 42 insertions(+) create mode 100644 .gitlab/ci/docker/gcc_cxx_modules/Dockerfile create mode 100755 .gitlab/ci/docker/gcc_cxx_modules/install_deps.sh create mode 100755 .gitlab/ci/docker/gcc_cxx_modules/install_gcc.sh diff --git a/.gitlab/ci/docker/gcc_cxx_modules/Dockerfile b/.gitlab/ci/docker/gcc_cxx_modules/Dockerfile new file mode 100644 index 0000000..e0af0b9 --- /dev/null +++ b/.gitlab/ci/docker/gcc_cxx_modules/Dockerfile @@ -0,0 +1,9 @@ +FROM fedora:36 +MAINTAINER Ben Boeckel + +# Install build dependencies for packages. +COPY install_deps.sh /root/install_deps.sh +RUN sh /root/install_deps.sh + +COPY install_gcc.sh /root/install_gcc.sh +RUN sh /root/install_gcc.sh diff --git a/.gitlab/ci/docker/gcc_cxx_modules/install_deps.sh b/.gitlab/ci/docker/gcc_cxx_modules/install_deps.sh new file mode 100755 index 0000000..2556b54 --- /dev/null +++ b/.gitlab/ci/docker/gcc_cxx_modules/install_deps.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +set -e + +dnf install -y --setopt=install_weak_deps=False \ + gcc-c++ mpfr-devel libmpc-devel isl-devel flex bison file findutils diffutils +dnf clean all diff --git a/.gitlab/ci/docker/gcc_cxx_modules/install_gcc.sh b/.gitlab/ci/docker/gcc_cxx_modules/install_gcc.sh new file mode 100755 index 0000000..20ea35f --- /dev/null +++ b/.gitlab/ci/docker/gcc_cxx_modules/install_gcc.sh @@ -0,0 +1,26 @@ +#!/bin/sh + +set -e + +readonly revision="p1689r5-cmake-ci-20220614" # 3075e510e3d29583f8886b95aff044c0474c84a5 +readonly tarball="https://github.com/mathstuf/gcc/archive/$revision.tar.gz" + +readonly workdir="$HOME/gcc" +readonly srcdir="$workdir/gcc" +readonly builddir="$workdir/build" +readonly njobs="$( nproc )" + +mkdir -p "$workdir" +cd "$workdir" +curl -L "$tarball" > "gcc-$revision.tar.gz" +tar xf "gcc-$revision.tar.gz" +mv "gcc-$revision" "$srcdir" +mkdir -p "$builddir" +cd "$builddir" +"$srcdir/configure" \ + --disable-multilib \ + --enable-languages=c,c++ \ + --prefix="/opt/gcc-p1689" +make "-j$njobs" +make "-j$njobs" install-strip +rm -rf "$workdir" -- cgit v0.12 From 07bc3b07ec8796f4a067ede7f4426ccbfa8ab858 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Tue, 14 Jun 2022 17:11:55 -0400 Subject: gitlab-ci: test C++ modules using GCC --- .gitlab-ci.yml | 20 ++++++++++++++++++ .../ci/configure_linux_gcc_cxx_modules_ninja.cmake | 4 ++++ ...nfigure_linux_gcc_cxx_modules_ninja_multi.cmake | 4 ++++ .gitlab/ci/cxx_modules_rules_gcc.cmake | 10 +++++++++ .gitlab/os-linux.yml | 24 ++++++++++++++++++++++ 5 files changed, 62 insertions(+) create mode 100644 .gitlab/ci/configure_linux_gcc_cxx_modules_ninja.cmake create mode 100644 .gitlab/ci/configure_linux_gcc_cxx_modules_ninja_multi.cmake create mode 100644 .gitlab/ci/cxx_modules_rules_gcc.cmake diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index fc05626..930c4bb 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -275,6 +275,26 @@ t:hip4.2-radeon: variables: CMAKE_CI_NO_MR: "true" +t:linux-gcc-cxx-modules-ninja: + extends: + - .gcc_cxx_modules_ninja + - .cmake_test_linux_release + - .linux_builder_tags + - .run_dependent + - .needs_centos6_x86_64 + variables: + CMAKE_CI_JOB_NIGHTLY: "true" + +t:linux-gcc-cxx-modules-ninja-multi: + extends: + - .gcc_cxx_modules_ninja_multi + - .cmake_test_linux_release + - .linux_builder_tags + - .run_dependent + - .needs_centos6_x86_64 + variables: + CMAKE_CI_JOB_NIGHTLY: "true" + b:fedora36-ninja: extends: - .fedora36_ninja diff --git a/.gitlab/ci/configure_linux_gcc_cxx_modules_ninja.cmake b/.gitlab/ci/configure_linux_gcc_cxx_modules_ninja.cmake new file mode 100644 index 0000000..bf990c8 --- /dev/null +++ b/.gitlab/ci/configure_linux_gcc_cxx_modules_ninja.cmake @@ -0,0 +1,4 @@ +set(CMake_TEST_MODULE_COMPILATION "named,partitions,internal_partitions" CACHE STRING "") +set(CMake_TEST_MODULE_COMPILATION_RULES "${CMAKE_CURRENT_LIST_DIR}/cxx_modules_rules_gcc.cmake" CACHE STRING "") + +include("${CMAKE_CURRENT_LIST_DIR}/configure_external_test.cmake") diff --git a/.gitlab/ci/configure_linux_gcc_cxx_modules_ninja_multi.cmake b/.gitlab/ci/configure_linux_gcc_cxx_modules_ninja_multi.cmake new file mode 100644 index 0000000..bf990c8 --- /dev/null +++ b/.gitlab/ci/configure_linux_gcc_cxx_modules_ninja_multi.cmake @@ -0,0 +1,4 @@ +set(CMake_TEST_MODULE_COMPILATION "named,partitions,internal_partitions" CACHE STRING "") +set(CMake_TEST_MODULE_COMPILATION_RULES "${CMAKE_CURRENT_LIST_DIR}/cxx_modules_rules_gcc.cmake" CACHE STRING "") + +include("${CMAKE_CURRENT_LIST_DIR}/configure_external_test.cmake") diff --git a/.gitlab/ci/cxx_modules_rules_gcc.cmake b/.gitlab/ci/cxx_modules_rules_gcc.cmake new file mode 100644 index 0000000..d800099 --- /dev/null +++ b/.gitlab/ci/cxx_modules_rules_gcc.cmake @@ -0,0 +1,10 @@ +set(CMake_TEST_CXXModules_UUID "a246741c-d067-4019-a8fb-3d16b0c9d1d3") + +set(CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP 1) +string(CONCAT CMAKE_EXPERIMENTAL_CXX_SCANDEP_SOURCE + " -E -x c++ " + " -MT -MD -MF " + " -fmodules-ts -fdep-file= -fdep-output= -fdep-format=trtbd" + " -o ") +set(CMAKE_EXPERIMENTAL_CXX_MODULE_MAP_FORMAT "gcc") +set(CMAKE_EXPERIMENTAL_CXX_MODULE_MAP_FLAG "-fmodules-ts -fmodule-mapper= -fdep-format=trtbd -x c++") diff --git a/.gitlab/os-linux.yml b/.gitlab/os-linux.yml index 0b2d382..6afd299 100644 --- a/.gitlab/os-linux.yml +++ b/.gitlab/os-linux.yml @@ -299,6 +299,30 @@ CMAKE_CONFIGURATION: hip4.2_radeon CMAKE_GENERATOR: "Ninja Multi-Config" +### C++ modules + +.gcc_cxx_modules_x86_64: + image: "kitware/cmake:ci-gcc_cxx_modules-x86_64-2022-06-14" + + variables: + GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci" + CMAKE_ARCH: x86_64 + CC: "/opt/gcc-p1689/bin/gcc" + CXX: "/opt/gcc-p1689/bin/g++" + +.gcc_cxx_modules_ninja: + extends: .gcc_cxx_modules_x86_64 + + variables: + CMAKE_CONFIGURATION: linux_gcc_cxx_modules_ninja + +.gcc_cxx_modules_ninja_multi: + extends: .gcc_cxx_modules_x86_64 + + variables: + CMAKE_CONFIGURATION: linux_gcc_cxx_modules_ninja_multi + CMAKE_GENERATOR: "Ninja Multi-Config" + ## Tags .linux_builder_tags: -- cgit v0.12