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).
This commit is contained in:
Ben Boeckel
2022-04-08 13:56:33 -04:00
parent ff30a5397d
commit 386465bf83
82 changed files with 1294 additions and 78 deletions
+62 -15
View File
@@ -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 <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 <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 <type>`` arguments can be
omitted. For all other file set names, ``TYPE`` is required.
``BASE_DIRS <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_<NAME>`
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_<NAME>`
* :prop_tgt:`CXX_MODULE_DIRS`
* :prop_tgt:`CXX_MODULE_DIRS_<NAME>`
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_<NAME>`
* :prop_tgt:`CXX_MODULE_HEADER_UNIT_DIRS`
* :prop_tgt:`CXX_MODULE_HEADER_UNIT_DIRS_<NAME>`
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:`$<BUILD_INTERFACE>` 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:`$<BUILD_INTERFACE>` 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:`$<BUILD_INTERFACE>` 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:`$<BUILD_INTERFACE>` and appended to this
property.
-5
View File
@@ -57,11 +57,6 @@ dependencies to the file specified by the ``<DYNDEP_FILE>`` 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_<FILE_SET_TYPE>`` 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.
+12
View File
@@ -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
+17
View File
@@ -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 <cmake-generator-expressions(7)>`.
This property is normally only set by :command:`target_sources(FILE_SET)`
rather than being manipulated directly.
See :prop_tgt:`CXX_MODULE_DIRS_<NAME>` for the list of base directories in
other C++ module sets.
+17
View File
@@ -0,0 +1,17 @@
CXX_MODULE_DIRS_<NAME>
----------------------
.. note ::
Experimental. Gated by ``CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API``
Semicolon-separated list of base directories of the target's ``<NAME>`` C++
module set, which has the set type ``CXX_MODULES``. The property supports
:manual:`generator expressions <cmake-generator-expressions(7)>`.
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.
@@ -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 <cmake-generator-expressions(7)>`.
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_<NAME>` for the list of base directories
in other C++ module header sets.
@@ -0,0 +1,19 @@
CXX_MODULE_HEADER_UNIT_DIRS_<NAME>
----------------------------------
.. note ::
Experimental. Gated by ``CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API``
Semicolon-separated list of base directories of the target's ``<NAME>`` C++
module header set, which has the set type ``CXX_MODULE_HEADER_UNITS``. The
property supports
:manual:`generator expressions <cmake-generator-expressions(7)>`.
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.
@@ -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 <cmake-generator-expressions(7)>`.
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_<NAME>` for the list of files in
other C++ module header sets.
@@ -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_<NAME>`,
:prop_tgt:`CXX_MODULE_HEADER_UNIT_SET` and
:prop_tgt:`INTERFACE_CXX_MODULE_HEADER_UNIT_SETS`.
@@ -0,0 +1,19 @@
CXX_MODULE_HEADER_UNIT_SET_<NAME>
---------------------------------
.. note ::
Experimental. Gated by ``CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API``
Semicolon-separated list of files in the target's ``<NAME>`` 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 <cmake-generator-expressions(7)>`.
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.
+18
View File
@@ -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 <cmake-generator-expressions(7)>`.
This property is normally only set by :command:`target_sources(FILE_SET)`
rather than being manipulated directly.
See :prop_tgt:`CXX_MODULE_SET_<NAME>` for the list of files in other C++
module sets.
+16
View File
@@ -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_<NAME>`, :prop_tgt:`CXX_MODULE_SET` and
:prop_tgt:`INTERFACE_CXX_MODULE_SETS`.
+18
View File
@@ -0,0 +1,18 @@
CXX_MODULE_SET_<NAME>
---------------------
.. note ::
Experimental. Gated by ``CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API``
Semicolon-separated list of files in the target's ``<NAME>`` 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 <cmake-generator-expressions(7)>`.
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.
@@ -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`.
@@ -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`.
+32
View File
@@ -9,7 +9,9 @@
#include <sstream>
#include <utility>
#include <cm/string_view>
#include <cmext/algorithm>
#include <cmext/string_view>
#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(
+34
View File
@@ -7,6 +7,9 @@
#include <sstream>
#include <utility>
#include <cm/string_view>
#include <cmext/string_view>
#include "cmExportSet.h"
#include "cmFileSet.h"
#include "cmGeneratedFileStream.h"
@@ -18,6 +21,7 @@
#include "cmInstallTargetGenerator.h"
#include "cmLocalGenerator.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmOutputConverter.h"
#include "cmPolicies.h"
#include "cmStateTypes.h"
@@ -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("\"$<$<CONFIG:", config, ">:", 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) {
+89 -1
View File
@@ -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;
}
}
}
+30
View File
@@ -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;
};
+15
View File
@@ -395,12 +395,27 @@ void cmGlobalVisualStudio7Generator::WriteTargetsToSolution(
{
VisualStudioFolders.clear();
std::vector<std::string> configs =
root->GetMakefile()->GetGeneratorConfigs(cmMakefile::ExcludeEmptyConfig);
for (cmGeneratorTarget const* target : projectTargets) {
if (!this->IsInSolution(target)) {
continue;
}
bool written = false;
for (auto const& c : configs) {
target->CheckCxxModuleStatus(c);
}
if (target->HaveCxx20ModuleSources() && !this->SupportsCxxModuleDyndep()) {
root->GetMakefile()->IssueMessage(
MessageType::FATAL_ERROR,
cmStrCat("The \"", target->GetName(),
"\" target contains C++ module sources which are not "
"supported by the generator"));
}
// handle external vc project files
cmValue expath = target->GetProperty("EXTERNAL_MSPROJECT");
if (expath) {
+2
View File
@@ -157,6 +157,8 @@ protected:
cmValue typeGuid,
const std::set<BT<std::pair<std::string, bool>>>& dependencies) = 0;
virtual bool SupportsCxxModuleDyndep() const { return false; }
std::string ConvertToSolutionPath(const std::string& path);
std::set<std::string> IsPartOfDefaultBuild(
+12
View File
@@ -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) {
+65
View File
@@ -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<std::string, std::string> file_set_map;
auto const* tgt = this->GeneratorTarget->Target;
for (auto const& name : tgt->GetAllFileSetNames()) {
auto const* file_set = tgt->GetFileSet(name);
if (!file_set) {
this->Makefile->IssueMessage(
MessageType::INTERNAL_ERROR,
cmStrCat("Target \"", tgt->GetName(),
"\" is tracked to have file set \"", name,
"\", but it was not found."));
continue;
}
auto fileEntries = file_set->CompileFileEntries();
auto directoryEntries = file_set->CompileDirectoryEntries();
auto directories = file_set->EvaluateDirectoryEntries(
directoryEntries, this->LocalGenerator, this->GetConfigName(),
this->GeneratorTarget);
std::map<std::string, std::vector<std::string>> files;
for (auto const& entry : fileEntries) {
file_set->EvaluateFileEntry(directories, files, entry,
this->LocalGenerator, this->GetConfigName(),
this->GeneratorTarget);
}
for (auto const& it : files) {
for (auto const& filename : it.second) {
file_set_map[filename] = file_set->GetType();
}
}
}
std::vector<cmSourceFile const*> objectSources;
this->GeneratorTarget->GetObjectSources(objectSources,
this->GetConfigName());
@@ -314,6 +360,25 @@ void cmMakefileTargetGenerator::WriteTargetBuildRules()
this->WriteObjectRuleFiles(*sf);
}
}
for (cmSourceFile const* sf : objectSources) {
auto const& path = sf->GetFullPath();
auto const it = file_set_map.find(path);
if (it != file_set_map.end()) {
auto const& file_set_type = it->second;
if (file_set_type == "CXX_MODULES"_s ||
file_set_type == "CXX_MODULE_HEADER_UNITS"_s) {
if (sf->GetLanguage() != "CXX"_s) {
this->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
cmStrCat(
"Target \"", tgt->GetName(), "\" contains the source\n ", path,
"\nin a file set of type \"", file_set_type,
R"(" but the source is not classified as a "CXX" source.)"));
}
}
}
}
}
void cmMakefileTargetGenerator::WriteCommonCodeRules()
+49 -51
View File
@@ -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,52 +249,54 @@ 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) {
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);
std::map<std::string, std::vector<std::string>> files;
for (auto const& entry : fileEntries) {
file_set->EvaluateFileEntry(directories, files, entry,
this->LocalGenerator, config,
this->GeneratorTarget);
}
for (auto const& it : files) {
for (auto const& filename : it.second) {
if (filename == path) {
file_set_type = file_set->GetType();
break;
}
}
}
if (file_set_type == "CXX_MODULES"_s ||
file_set_type == "CXX_MODULE_HEADER_UNITS"_s) {
if (source->GetLanguage() != "CXX"_s) {
this->GetMakefile()->IssueMessage(
MessageType::INTERNAL_ERROR,
cmStrCat("Target `", tgt->GetName(),
"` is tracked to have file set `", name,
"`, but it was not found."));
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;
}
auto fileEntries = file_set->CompileFileEntries();
auto directoryEntries = file_set->CompileDirectoryEntries();
auto directories = file_set->EvaluateDirectoryEntries(
directoryEntries, this->LocalGenerator, config, this->GeneratorTarget);
std::map<std::string, std::vector<std::string>> files;
for (auto const& entry : fileEntries) {
file_set->EvaluateFileEntry(directories, files, entry,
this->LocalGenerator, config,
this->GeneratorTarget);
}
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);
}
}
}
}
@@ -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)
+79
View File
@@ -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<cmFileSet*, bool> cmTarget::GetOrCreateFileSet(
auto bt = this->impl->Makefile->GetBacktrace();
if (type == this->impl->HeadersFileSets.TypeName) {
this->impl->HeadersFileSets.AddFileSet(name, vis, std::move(bt));
} else if (type == this->impl->CxxModulesFileSets.TypeName) {
this->impl->CxxModulesFileSets.AddFileSet(name, vis, std::move(bt));
} else if (type == this->impl->CxxModuleHeadersFileSets.TypeName) {
this->impl->CxxModuleHeadersFileSets.AddFileSet(name, vis,
std::move(bt));
}
}
return std::make_pair(&result.first->second, result.second);
@@ -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<std::string> cmTarget::GetAllInterfaceFileSets() const
};
appendEntries(this->impl->HeadersFileSets.InterfaceEntries.Entries);
appendEntries(this->impl->CxxModulesFileSets.InterfaceEntries.Entries);
appendEntries(this->impl->CxxModuleHeadersFileSets.InterfaceEntries.Entries);
return result;
}
+4
View File
@@ -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;
+26 -4
View File
@@ -9,6 +9,7 @@
#include <cmext/string_view>
#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<std::string>(baseDirectories, this->Makefile->GetBacktrace()));
if (type == "HEADERS"_s) {
if (type == "HEADERS"_s || type == "CXX_MODULE_HEADER_UNITS"_s) {
for (auto const& dir : cmExpandedList(baseDirectories)) {
auto interfaceDirectoriesGenex =
cmStrCat("$<BUILD_INTERFACE:", dir, ">");
@@ -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 =
+3
View File
@@ -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.
+6
View File
@@ -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)
@@ -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\)
@@ -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)
@@ -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.
@@ -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)
@@ -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.
@@ -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)
@@ -0,0 +1 @@
1
@@ -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\)
@@ -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)
@@ -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.
@@ -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)
@@ -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.
@@ -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)
@@ -0,0 +1 @@
1
@@ -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.
+9
View File
@@ -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)
@@ -0,0 +1 @@
1
@@ -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.
+10
View File
@@ -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)
@@ -0,0 +1 @@
1
@@ -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.
@@ -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)
@@ -0,0 +1 @@
1
@@ -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.
@@ -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)
@@ -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.
@@ -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)
@@ -0,0 +1 @@
1
@@ -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.
@@ -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)
@@ -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 ()
@@ -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}")
@@ -0,0 +1,4 @@
int c_anchor()
{
return 0;
}
@@ -0,0 +1,4 @@
int cxx_anchor()
{
return 0;
}
@@ -0,0 +1,9 @@
#ifndef module_header_h
#define module_header_h
inline int h()
{
return 0;
}
#endif
@@ -0,0 +1,6 @@
module M;
int f()
{
return 0;
}
@@ -0,0 +1,11 @@
#ifdef _MSC_VER
// Only MSVC supports this pattern.
module M : internal_part;
#else
module M;
#endif
int i()
{
return 0;
}
@@ -0,0 +1,3 @@
module M : internal_part;
int i();
@@ -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();
}
@@ -0,0 +1,3 @@
export module M : part;
int p();
@@ -0,0 +1,6 @@
import M;
int main(int argc, char* argv[])
{
return f() + p();
}
@@ -0,0 +1,5 @@
export module M;
export import M : part;
import M : internal_part;
int f();
@@ -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\)$
@@ -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)
@@ -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\)$
@@ -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)
@@ -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)
@@ -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\):