mirror of
https://gitlab.kitware.com/cmake/cmake.git
synced 2026-10-07 04:02:23 +03:00
Help/cmake-cxxmodules: document the implementation
This commit is contained in:
1 parent
7006c2fb85
commit
e9e94de9cb
1 file changed
+276
@@ -37,6 +37,8 @@ strategy, which is the most visible modules-related change for CMake users in
|
||||
the context of the build. CMake provides multiple ways to control the
|
||||
scanning behavior of source files.
|
||||
|
||||
.. _cxxmodules-scanning-control:
|
||||
|
||||
Scanning Control
|
||||
================
|
||||
|
||||
@@ -410,6 +412,257 @@ within the target.
|
||||
|
||||
.. _`P1689R5`: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p1689r5.html
|
||||
|
||||
Implementation Details
|
||||
----------------------
|
||||
|
||||
This section describes how CMake actually structures the build graph, the data
|
||||
passed between various parts, and the files which contain that data. It is
|
||||
intended to be used both as functional documentation and as a guide to help
|
||||
those debugging a module build to understand where to locate various bits of
|
||||
data.
|
||||
|
||||
.. note::
|
||||
|
||||
This section documents internal implementation details that may be useful
|
||||
for :manual:`toolchain file <cmake-toolchains(7)>` authors or during
|
||||
debugging of a module-related issue. Projects should not need to inspect
|
||||
or modify any of the variables, properties, files, or targets mentioned
|
||||
here.
|
||||
|
||||
Toolchain (scanning)
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Compilers which support modules must also provide a scanning tool. This will
|
||||
usually be either the compiler itself with some extra flags or a tool shipped
|
||||
with the compiler. The command template for scanning is stored in the
|
||||
``CMAKE_CXX_SCANDEP_SOURCE`` variable. The command is expected to write
|
||||
`P1689R5`_ results to the ``<DYNDEP_FILE>`` placeholder. Additionally, the
|
||||
command should provide any :term:`discovered dependencies` to the
|
||||
``<DEP_FILE>`` placeholder. This allows :term:`build tools <build tool>` to
|
||||
rerun the scan if any of the dependencies of the scanning command change.
|
||||
|
||||
Additionally, toolchains should set the following variables:
|
||||
|
||||
* ``CMAKE_CXX_MODULE_MAP_FORMAT``: The format of the :term:`module map`
|
||||
describing where dependent :term:`BMI` files for imported modules exist
|
||||
during compilation. Must be one of ``gcc``, ``clang``, or ``msvc``.
|
||||
* ``CMAKE_CXX_MODULE_MAP_FLAG``: The arguments used to inform the compiler of
|
||||
the :term:`module map` file. It should use the ``<MODULE_MAP_FILE>``
|
||||
placeholder.
|
||||
* ``CMAKE_CXX_MODULE_BMI_ONLY_FLAG``: The arguments used to compile only a
|
||||
:term:`BMI` file from a :term:`module interface unit`. This is used when
|
||||
consuming modules from external projects to compile :term:`BMI` files for
|
||||
use within the current build.
|
||||
|
||||
If a toolchain does not provide the ``CMAKE_CXX_MODULE_BMI_ONLY_FLAG``, it
|
||||
will not be able to consume modules provided by ``IMPORTED`` targets.
|
||||
|
||||
Toolchain (``import std``)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
If the toolchain supports ``import std``, it must also provide a toolchain
|
||||
identification module named ``${CMAKE_CXX_COMPILER_ID}-CXX-CXXImportStd``.
|
||||
|
||||
.. note::
|
||||
|
||||
Currently only CMake may provide these files due to the way they are
|
||||
included. Once ``import std`` is no longer experimental, external
|
||||
toolchains may provide support independently as well.
|
||||
|
||||
This module must provide the ``_cmake_cxx_import_std`` command. It will be
|
||||
passed two arguments: the version of the C++ standard (e.g., ``23``) and the
|
||||
name of a variable in which to place the result of its ``import std`` support.
|
||||
The variable should be filled in with CMake source code which declares the
|
||||
``__CMAKE::CXX${std}`` target, where ``${std}`` is the version passed in. If
|
||||
the target cannot be made, the source code should instead set the
|
||||
``CMAKE_CXX${std}_COMPILER_IMPORT_STD_NOT_FOUND_MESSAGE`` variable to the
|
||||
reason that ``import std`` is not supported in the current configuration.
|
||||
Note that CMake will guard the returned code with conditional checks to ensure
|
||||
that the target is only defined once.
|
||||
|
||||
Ideally, the ``__CMAKE::CXX${std}`` target will be an ``IMPORTED``
|
||||
``INTERFACE`` target with the ``std`` module sources attached to it. However,
|
||||
it may be necessary to compile objects for some implementations. Object files
|
||||
are required when there are symbols expected to be provided by the consumer of
|
||||
the module by compiling it. There is a concern that, if this happens, more
|
||||
than once within a program, this will result in duplication of these symbols
|
||||
which may violate the :term:`ODR` for them.
|
||||
|
||||
As an example, if consumers of a module are expected to provide symbols for
|
||||
that module, the use of the module is then a global property of the program
|
||||
and cannot be abstracted away. Imagine that a library exposes a C API but
|
||||
uses a C++ module internally. If it is supposed to provide the module
|
||||
symbols, anything using the C API needs to cooperate with its internal module
|
||||
usage if it wants to use the same module for its own purposes. If both end up
|
||||
providing symbols for the imported module, there may be conflicts.
|
||||
|
||||
Configure
|
||||
^^^^^^^^^
|
||||
|
||||
During the configure step, CMake needs to track which sources care about
|
||||
modules at all. See :ref:`Scanning Control <cxxmodules-scanning-control>` for
|
||||
how each source determines whether it cares about modules or not. CMake
|
||||
tracks these in its internal target representation structure (``cmTarget``).
|
||||
The set of sources which need to be scanned may be modified using the
|
||||
:command:`target_sources`, :command:`target_compile_features`, and
|
||||
:command:`set_property` commands.
|
||||
|
||||
Additionally, targets may use the :prop_tgt:`CXX_MODULE_STD` target property
|
||||
to indicate that ``import std`` is desired within the target's sources.
|
||||
|
||||
Generate
|
||||
^^^^^^^^
|
||||
|
||||
During generation, CMake needs to add additional rules to ensure that the
|
||||
sources providing modules can be built before sources that import those
|
||||
modules. Since CMake uses a :term:`static build`, the build graph must
|
||||
contain all possible commands for scanning and module generation. The
|
||||
dependency edges between commands to ensure that modules are provided will
|
||||
then ensure that the build graph executes correctly. This means that, while
|
||||
all sources may get scanned, only modules that are actually used will be
|
||||
generated.
|
||||
|
||||
The first step CMake performs is to generate a :term:`synthetic target` for
|
||||
each unique usage of a module-providing target. These targets are based on
|
||||
other targets, but provide only :term:`BMI` files for other targets rather
|
||||
than object files. This is because the compatibility of :term:`BMI` files is
|
||||
extremely narrow and cannot be shared between arbitrary ``import`` instances.
|
||||
Due to the internal workings of toolchains, there can generally only be a
|
||||
single set of settings for a variety of flags for any one compilation,
|
||||
including :term:`BMI` files for imported modules. As an example, the C++
|
||||
standard in use needs to be consistent across all modules, but there are many
|
||||
settings which may cause incompatibilities.
|
||||
|
||||
.. note::
|
||||
|
||||
CMake currently assumes that all usages are compatible and will only create
|
||||
one set of :term:`BMIs <BMI>` for each target. This may cause build
|
||||
failures where multiple :term:`BMI` files are required, but CMake only
|
||||
provides one set. See `CMake Issue 25916`_ for progress on removing this
|
||||
assumption.
|
||||
|
||||
.. _`CMake Issue 25916`: https://gitlab.kitware.com/cmake/cmake/-/issues/25916
|
||||
|
||||
Once all of the :term:`synthetic targets <synthetic target>` are created,
|
||||
CMake looks at each target that has any source that might use C++ modules and
|
||||
creates a command to :term:`scan` each of them. This command will output a
|
||||
`P1689R5`_-formatted file describing the C++ modules it uses and provides (if
|
||||
any). It will also create a command to :term:`collate` module dependencies
|
||||
for the eligible compilations. This command depends on the :term:`scan`
|
||||
results of all eligible sources, information about the target itself, as well
|
||||
as the :term:`collate` results of any dependent targets which provide C++
|
||||
modules. The :term:`collate` step uses a target-specific
|
||||
``CXXDependInfo.json`` file which contains the following information:
|
||||
|
||||
- ``compiler-*``: basic compiler information (``id``, ``frontend-variant``,
|
||||
and ``simulate-id``) which is used to generate correctly formatted paths
|
||||
when generating paths for the compiler
|
||||
- ``cxx-modules``: a map of object files to the ``FILE_SET`` information,
|
||||
which is used to enforce :term:`module visibility` and generate install
|
||||
rules for :term:`module interface unit` sources
|
||||
- ``module-dir``: where to place :term:`BMI` files for this target
|
||||
- ``dir-{cur,top}-{src,bld}``: the source (``src``) and build (``bld``)
|
||||
directories for the current directory (``cur``) and the top (``top``) of the
|
||||
project, used to compute accurate relative paths for the :term:`build tool`
|
||||
dynamic dependencies
|
||||
- ``exports``: The list of exports which both contain the target and are
|
||||
providing C++ module information, used to provide accurate module properties
|
||||
on ``IMPORTED`` targets from the exported targets.
|
||||
- ``bmi-installation``: installation information, used to generate install
|
||||
scripts for :term:`BMI` files
|
||||
- ``database-info``: information required to generate :term:`build database`
|
||||
information if requested by :prop_tgt:`EXPORT_BUILD_DATABASE`
|
||||
- ``sources``: list of other source files in the target, used to add to the
|
||||
:term:`build database` if requested
|
||||
- ``config``: the configuration for the target, used to set the appropriate
|
||||
properties in generated export files
|
||||
- ``language``: the language (e.g., C++ or Fortran) the
|
||||
:term:`collation <collate>` metadata file is describing
|
||||
- ``include-dirs`` and ``forward-modules-from-target-dirs``: unused for C++
|
||||
|
||||
For each compilation, CMake will also provide a :term:`module map` which will
|
||||
be created during the build by the :term:`collate` command. How this is
|
||||
provided to the compiler is specified by the ``CMAKE_CXX_MODULE_MAP_FORMAT``
|
||||
and ``CMAKE_CXX_MODULE_MAP_FLAG`` toolchain variables.
|
||||
|
||||
Scan
|
||||
^^^^
|
||||
|
||||
The compiler is expected to implement the :term:`scan` command. This is
|
||||
because only the compiler itself can reliably answer preprocessor predicates
|
||||
like ``__has_builtin`` in order to provide accurate module usage information
|
||||
in the face of arbitrary flags that may be used when compiling sources.
|
||||
|
||||
CMake names these files with the ``.ddi`` extension, which stands for "dynamic
|
||||
dependency information". These files are in `P1689R5`_ format and are used by
|
||||
the :term:`collate` command to perform its tasks.
|
||||
|
||||
Collate
|
||||
^^^^^^^
|
||||
|
||||
The :term:`collate` command performs the bulk of the work to make C++ modules
|
||||
work within the build graph. It consumes the following files as input:
|
||||
|
||||
- ``CXXDependInfo.json`` from the generate step
|
||||
- ``.ddi`` files from the :term:`scanning <scan>` results of the target's
|
||||
sources
|
||||
- ``CXXModules.json`` files output from eligible dependent targets'
|
||||
:term:`collate` commands
|
||||
|
||||
It uses the information from these files to generate:
|
||||
|
||||
- ``CXX.dd`` files to inform the :term:`build tool` of dependencies that exist
|
||||
between the compilation of a source and the :term:`BMI` files of the modules
|
||||
that it imports
|
||||
- ``CXXModules.json`` files for use in :term:`collate` commands of depending
|
||||
targets
|
||||
- ``*.modmap`` files for each compilation to find :term:`BMI` files for
|
||||
imported modules
|
||||
- ``install-cxx-module-bmi-$<CONFIG>.cmake`` scripts for the installation of
|
||||
any :term:`BMI` files (included by the ``install`` scripts)
|
||||
- ``target-*-$<CONFIG>.cmake`` export files for any exports of the target to
|
||||
provide the :prop_tgt:`IMPORTED_CXX_MODULES_<CONFIG>` properties
|
||||
- ``CXX_build_database.json`` :term:`build database` files for the target when
|
||||
the its :prop_tgt:`EXPORT_BUILD_DATABASE` property is set
|
||||
|
||||
During its processing, it enforces the following guarantees:
|
||||
|
||||
- :term:`BMI` usage is consistent
|
||||
- :term:`module visibility` is respected
|
||||
|
||||
C++ modules have the rule that only a single module of a given name may
|
||||
exist within a program. This is not exactly enforceable with the existence of
|
||||
private modules, but it is enforceable for public modules. The enforcement is
|
||||
done by the :term:`collate` command. Part of the ``CXXModules.json`` files is
|
||||
the set of modules that are transitively imported by each module it provides.
|
||||
When a module is then imported, the :term:`collate` command ensures that all
|
||||
modules with a given name agree upon a given :term:`BMI` file to provide that
|
||||
module.
|
||||
|
||||
Compile
|
||||
^^^^^^^
|
||||
|
||||
Compilation uses the :term:`module map` file generated by the :term:`collate`
|
||||
command to find imported modules during compilation. Because CMake only
|
||||
provides the locations of modules that are discovered by the :term:`scan`
|
||||
command, any modules missed by it will not be provided to the compilation.
|
||||
|
||||
It is possible for toolchains to reject the :term:`BMI` file that CMake
|
||||
provides to a compilation as incompatible. This is because CMake assumes that
|
||||
all usages are compatible at the moment. See `CMake Issue 25916`_ for
|
||||
progress on removing this assumption.
|
||||
|
||||
Install
|
||||
^^^^^^^
|
||||
|
||||
During installation, install scripts which have been written by the
|
||||
:term:`collate` command during the build are included so that any :term:`BMI`
|
||||
files are installed as needed. These need to be generated, as it is not
|
||||
known what the :term:`BMI` file names will be during CMake's generation
|
||||
(because CMake names the :term:`BMI` files after the module name itself).
|
||||
These install scripts are included with the ``OPTIONAL`` keyword, so an
|
||||
incomplete build may result in an incomplete installation as well.
|
||||
|
||||
Alternative Designs
|
||||
-------------------
|
||||
|
||||
@@ -595,6 +848,10 @@ Module Compilation Glossary
|
||||
Compiled Module Interface. Alternative name for :term:`BMI` used by some
|
||||
compilers.
|
||||
|
||||
build database
|
||||
A JSON file containing compilation commands, module dependencies, and
|
||||
grouping information. Used for IDE integration and build analysis.
|
||||
|
||||
build system
|
||||
A tool that facilitates the building of software which includes a model
|
||||
of how components of the build relate to each other. For example, CMake,
|
||||
@@ -613,6 +870,10 @@ Module Compilation Glossary
|
||||
ensure correct compilation order and to provide metadata for other parts
|
||||
of the build (e.g., installation or a :term:`build database`).
|
||||
|
||||
discovered dependencies
|
||||
Dependencies found during the processing of a command that do not need to
|
||||
be explicitly declared.
|
||||
|
||||
dynamic dependencies
|
||||
Dependencies which require a separate command to detect so that a further
|
||||
command may have its dependencies satisfied.
|
||||
@@ -652,10 +913,17 @@ Module Compilation Glossary
|
||||
using ``export module``. Such a unit may or may not be also be a
|
||||
:term:`partition unit`.
|
||||
|
||||
module map
|
||||
A compiler-specific file mapping module names to BMI locations.
|
||||
|
||||
module visibility
|
||||
CMake's enforcement of access rules for modules based on their
|
||||
declaration scope (PUBLIC/PRIVATE).
|
||||
|
||||
ODR
|
||||
One Definition Rule. The C++ requirement that any entity be defined
|
||||
exactly once per program.
|
||||
|
||||
partition unit
|
||||
A :term:`translation unit` which describes a module with a partition name
|
||||
(i.e., `module MODNAME:PARTITION;`). The partition may or may not use
|
||||
@@ -671,11 +939,19 @@ Module Compilation Glossary
|
||||
The process of analyzing a :term:`translation unit` to discover module
|
||||
imports and exports.
|
||||
|
||||
static build
|
||||
A build configuration where all compilation rules are determined at
|
||||
generate time.
|
||||
|
||||
strong module ownership
|
||||
C++ implementations have settled on a model where the module "owns" the
|
||||
symbols declared within it. In practice, this means that the module name
|
||||
is included into the symbol mangling of entities declared within it.
|
||||
|
||||
synthetic target
|
||||
A CMake-generated build target used to supply :term:`BMIs <BMI>` to a
|
||||
specific user of a module-providing target.
|
||||
|
||||
translation unit
|
||||
The smallest component of a compilation for a C++ program. Generally,
|
||||
there is one translation unit per source file. C++ source files which do
|
||||
|
||||
Reference in new issue
Block a user