Merge topic 'cpp-named-module-file-sets'

07bc3b07ec gitlab-ci: test C++ modules using GCC
1b2270aa4e ci: add a Docker image to test out C++ modules with GCC
8c5a53096a Tests/RunCMake/CXXModules: add module-using examples
4151547e2f cmGlobalNinjaGenerator: use `cmModuleMapper` implementation
b43bdaff3c cmCxxModuleMapper: implement support for GCC's module map format
02d0f0e752 cmCxxModuleMapper: add source to handle module mapper contents
a046a45aad cmGlobalNinjaGenerator: add a TODO for header units
386465bf83 cmTarget: add support for C++ module fileset types
...

Acked-by: Kitware Robot <kwrobot@kitware.com>
Tested-by: buildbot <buildbot@kitware.com>
Merge-request: !7369
This commit is contained in:
Brad King
2022-06-17 15:35:03 +00:00
committed by Kitware Robot
123 changed files with 2014 additions and 121 deletions
+20
View File
@@ -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
@@ -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")
@@ -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")
+10
View File
@@ -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
"<CMAKE_CXX_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -E -x c++ <SOURCE>"
" -MT <DYNDEP_FILE> -MD -MF <DEP_FILE>"
" -fmodules-ts -fdep-file=<DYNDEP_FILE> -fdep-output=<OBJECT> -fdep-format=trtbd"
" -o <PREPROCESSED_SOURCE>")
set(CMAKE_EXPERIMENTAL_CXX_MODULE_MAP_FORMAT "gcc")
set(CMAKE_EXPERIMENTAL_CXX_MODULE_MAP_FLAG "-fmodules-ts -fmodule-mapper=<MODULE_MAP_FILE> -fdep-format=trtbd -x c++")
@@ -0,0 +1,9 @@
FROM fedora:36
MAINTAINER Ben Boeckel <ben.boeckel@kitware.com>
# 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
+7
View File
@@ -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
+26
View File
@@ -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"
+24
View File
@@ -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:
+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.
+17 -5
View File
@@ -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
=========================
@@ -40,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`.
+4
View File
@@ -197,6 +197,8 @@ set(SRCS
cmCustomCommandLines.cxx
cmCustomCommandLines.h
cmCustomCommandTypes.h
cmCxxModuleMapper.cxx
cmCxxModuleMapper.h
cmDefinitions.cxx
cmDefinitions.h
cmDependencyProvider.h
@@ -543,6 +545,8 @@ set(SRCS
cmExecuteProcessCommand.h
cmExpandedCommandArgument.cxx
cmExpandedCommandArgument.h
cmExperimental.cxx
cmExperimental.h
cmExportCommand.cxx
cmExportCommand.h
cmExportLibraryDependenciesCommand.cxx
+4
View File
@@ -9,6 +9,7 @@
#include "cmComputeLinkInformation.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalCommonGenerator.h"
#include "cmGlobalGenerator.h"
#include "cmLocalCommonGenerator.h"
#include "cmLocalGenerator.h"
#include "cmMakefile.h"
@@ -175,6 +176,9 @@ std::vector<std::string> cmCommonTargetGenerator::GetLinkedTargetDirectories(
cmLocalGenerator* lg = linkee->GetLocalGenerator();
std::string di = cmStrCat(lg->GetCurrentBinaryDirectory(), '/',
lg->GetTargetDirectory(linkee));
if (lg->GetGlobalGenerator()->IsMultiConfig()) {
di = cmStrCat(di, '/', config);
}
dirs.push_back(std::move(di));
}
}
+76
View File
@@ -0,0 +1,76 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCxxModuleMapper.h"
#include <cassert>
#include <sstream>
#include <vector>
#include "cmScanDepFormat.h"
cm::optional<std::string> CxxModuleLocations::BmiGeneratorPathForModule(
std::string const& logical_name) const
{
if (auto l = this->BmiLocationForModule(logical_name)) {
return this->PathForGenerator(*l);
}
return {};
}
namespace {
std::string CxxModuleMapContentGcc(CxxModuleLocations const& loc,
cmScanDepInfo const& obj)
{
std::stringstream mm;
// Documented in GCC's documentation. The format is a series of
// lines with a module name and the associated filename separated
// by spaces. The first line may use `$root` as the module name
// to specify a "repository root". That is used to anchor any
// relative paths present in the file (CMake should never
// generate any).
// Write the root directory to use for module paths.
mm << "$root " << loc.RootDirectory << "\n";
for (auto const& p : obj.Provides) {
if (auto bmi_loc = loc.BmiGeneratorPathForModule(p.LogicalName)) {
mm << p.LogicalName << ' ' << *bmi_loc << '\n';
}
}
for (auto const& r : obj.Requires) {
if (auto bmi_loc = loc.BmiGeneratorPathForModule(r.LogicalName)) {
mm << r.LogicalName << ' ' << *bmi_loc << '\n';
}
}
return mm.str();
}
}
cm::static_string_view CxxModuleMapExtension(
cm::optional<CxxModuleMapFormat> format)
{
if (format) {
switch (*format) {
case CxxModuleMapFormat::Gcc:
return ".gcm"_s;
}
}
return ".bmi"_s;
}
std::string CxxModuleMapContent(CxxModuleMapFormat format,
CxxModuleLocations const& loc,
cmScanDepInfo const& obj)
{
switch (format) {
case CxxModuleMapFormat::Gcc:
return CxxModuleMapContentGcc(loc, obj);
}
assert(false);
return {};
}
+48
View File
@@ -0,0 +1,48 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#pragma once
#include "cmConfigure.h" // IWYU pragma: keep
#include <functional>
#include <string>
#include <cm/optional>
#include <cmext/string_view>
struct cmScanDepInfo;
enum class CxxModuleMapFormat
{
Gcc,
};
struct CxxModuleLocations
{
// The path from which all relative paths should be computed. If
// this is relative, it is relative to the compiler's working
// directory.
std::string RootDirectory;
// A function to convert a full path to a path for the generator.
std::function<std::string(std::string const&)> PathForGenerator;
// Lookup the BMI location of a logical module name.
std::function<cm::optional<std::string>(std::string const&)>
BmiLocationForModule;
// Returns the generator path (if known) for the BMI given a
// logical module name.
cm::optional<std::string> BmiGeneratorPathForModule(
std::string const& logical_name) const;
};
// Return the extension to use for a given modulemap format.
cm::static_string_view CxxModuleMapExtension(
cm::optional<CxxModuleMapFormat> 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);
+63
View File
@@ -0,0 +1,63 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmExperimental.h"
#include <cassert>
#include <cstddef>
#include <string>
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmValue.h"
namespace {
/*
* The `Uuid` fields of these objects should change periodically.
* Search for other instances to keep the documentation and test suite
* up-to-date.
*/
struct FeatureData
{
std::string const Uuid;
std::string const Variable;
std::string const Description;
bool Warned;
} LookupTable[] = {
// CxxModuleCMakeApi
{ "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<size_t>(cmExperimental::Feature::Sentinel),
"Experimental feature lookup table mismatch");
FeatureData& DataForFeature(cmExperimental::Feature f)
{
assert(f != cmExperimental::Feature::Sentinel);
return LookupTable[static_cast<size_t>(f)];
}
}
bool cmExperimental::HasSupportEnabled(cmMakefile const& mf, Feature f)
{
bool enabled = false;
auto& data = DataForFeature(f);
auto value = mf.GetDefinition(data.Variable);
if (value == data.Uuid) {
enabled = true;
}
if (enabled && !data.Warned) {
mf.IssueMessage(MessageType::AUTHOR_WARNING, data.Description);
data.Warned = true;
}
return enabled;
}
+21
View File
@@ -0,0 +1,21 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#pragma once
#include "cmConfigure.h" // IWYU pragma: keep
class cmMakefile;
class cmExperimental
{
public:
enum class Feature
{
CxxModuleCMakeApi,
Sentinel,
};
static bool HasSupportEnabled(cmMakefile const& mf, Feature f);
};
+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
@@ -1712,7 +1712,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);
}
@@ -1733,6 +1734,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,
@@ -8705,3 +8720,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;
};
+34 -40
View File
@@ -5,6 +5,7 @@
#include <algorithm>
#include <cctype>
#include <cstdio>
#include <functional>
#include <sstream>
#include <utility>
@@ -21,6 +22,7 @@
#include "cmsys/FStream.hxx"
#include "cmCxxModuleMapper.h"
#include "cmDocumentationEntry.h"
#include "cmFortranParser.h"
#include "cmGeneratedFileStream.h"
@@ -2517,7 +2519,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;
@@ -2534,11 +2536,20 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile(
}
}
const char* module_ext = "";
if (arg_modmapfmt == "gcc") {
module_ext = ".gcm";
cm::optional<CxxModuleMapFormat> modmap_fmt;
if (arg_modmapfmt.empty()) {
// nothing to do.
} else if (arg_modmapfmt == "gcc") {
modmap_fmt = CxxModuleMapFormat::Gcc;
} else {
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.
@@ -2555,7 +2566,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);
}
@@ -2568,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<std::string> {
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) {
@@ -2589,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);
+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(
+16
View File
@@ -468,6 +468,10 @@ bool cmGlobalXCodeGenerator::Open(const std::string& bindir,
}
CFRelease(cfStr);
}
#else
(void)bindir;
(void)projectName;
(void)dryRun;
#endif
return ret;
@@ -1372,6 +1376,18 @@ bool cmGlobalXCodeGenerator::CreateXCodeTarget(
return true;
}
for (std::string const& configName : this->CurrentConfigurationTypes) {
gtgt->CheckCxxModuleStatus(configName);
}
if (gtgt->HaveCxx20ModuleSources()) {
gtgt->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
cmStrCat("The \"", gtgt->GetName(),
"\" target contains C++ module sources which are not "
"supported by the generator"));
}
auto& gtgt_visited = this->CommandsVisited[gtgt];
auto& deps = this->GetTargetDirectDepends(gtgt);
for (auto& d : deps) {
+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()
+52 -53
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)
@@ -1616,8 +1614,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();
+1 -1
View File
@@ -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";
}
}
+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))
{
}
@@ -1371,11 +1386,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);
@@ -1635,6 +1671,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);
}
@@ -1746,6 +1788,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 {
@@ -2254,6 +2303,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);
@@ -2531,6 +2591,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);
@@ -2541,6 +2606,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 "";
}
@@ -2549,6 +2620,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 "";
}
@@ -2576,6 +2653,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 -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.)
# 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,120 @@
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 ()
# 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 ()
@@ -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,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()
@@ -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.
@@ -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)
@@ -0,0 +1,5 @@
export module importable;
export int from_import() {
return 0;
}
@@ -0,0 +1,6 @@
import importable;
int main(int argc, char* argv[])
{
return from_import();
}
@@ -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.
@@ -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)
@@ -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();
}
@@ -0,0 +1,6 @@
import importable;
int main(int argc, char* argv[])
{
return from_import();
}
@@ -0,0 +1,6 @@
module importable : internal_partition;
int from_partition()
{
return 0;
}
@@ -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.
@@ -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.
@@ -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)
@@ -0,0 +1,8 @@
export module importable;
#include "library_export.h"
export LIBRARY_EXPORT int from_import()
{
return 0;
}
@@ -0,0 +1,6 @@
import importable;
int main(int argc, char* argv[])
{
return from_import();
}
@@ -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.
@@ -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)
@@ -0,0 +1,9 @@
export module importable;
export import importable : partition;
#include "partitions_export.h"
export PARTITIONS_EXPORT int from_import()
{
return from_partition();
}
@@ -0,0 +1,6 @@
import importable;
int main(int argc, char* argv[])
{
return from_import() + from_partition();
}
@@ -0,0 +1,8 @@
export module importable : partition;
#include "partitions_export.h"
export PARTITIONS_EXPORT int from_partition()
{
return 0;
}

Some files were not shown because too many files have changed in this diff Show More