C++ Logo

sg15

Advanced search

A straw man module manifest configuration schema

From: Tom Honermann <tom_at_[hidden]>
Date: Tue, 12 Dec 2023 16:33:00 -0500
During the discussion today, several comments were made about wanting to
start with a configuration solution that works for a few use cases and
is extendable to cover more use cases later. Let's play with that idea a
bit.

Our first goal is to be able to build the std and std.compat modules, so
that is our first use case.

Here is the content of the modules.json file that is distributed with
Microsoft Visual C 2022 (in the vc\Tools\MSVC\/X/./Y/./Z/\modules
directory). If there is documentation or a blog post that describes the
format, I haven't been able to find it. But it seems like a good
starting point.

    {
         "version": 1,
         "revision": 0,
         "library": "microsoft/STL",
         "module-sources": [
             "std.ixx",
             "std.compat.ixx"
         ]
    }

The referenced source files are in the same directory as the
configuration file. They look roughly like:

std.ixx:

    module:
    /<local preprocessor definitions>/
    /<include directives for the global module fragment>/
    export module std;
    /<include directives for the module interface unit>/

std.compat.ixx:

    export module std.compat;
    export import std;
    /<export using declarations>/

I don't know what the significance of the "library" key is. I'm guessing
it is effectively a comment at present or intended to provide a
displayable name for tools that consume the file. More details on that
would be useful.

The configuration file does not currently specify the names of the
modules. Should it? Olga mentioned on the call that the format supports
a "module-data" key that allows more information to be provided. More
details on that would be useful.

The configuration file currently only allows one library to be
specified. It will need to allow more than one or have a flexible file
name to fit Daniel's direction of colocating a configuration file with a
built library that resides in the same directory as other built
libraries. Perhaps the top-level value should be a JSON array instead of
a JSON object?

No include paths are provided in the configuration file at present. That
isn't surprising of course since the standard library historically
depends on the compiler implicitly providing them. But in general, we'll
need to allow include paths. It would be useful to be able to provide
include paths that are applicable to all of the source files and ones
that are specific to a (group of) source file(s). Examples follow. This
might be overly complicated as a starting point.

    {
       "include-paths": [
         "../include"
       ],
       "module-groups": [
         {
           "internal": {
    "include-paths": [ "../include/internal" ]
           }
         }
       ],
       "module-sources": [
         {
           "source": "std.ixx",
           "groups": [ "internal" ],
           "include-paths": [ "../include/detail" ]
         }
       ]
    }

Local preprocessor definitions are present in the module source files in
this case. But in general, it would be useful to be able to specify them
with the same granularity provided for include paths.

Parameters are useful in package environments where references to
external dependencies are a possibility. Consumption of a module
configuration file in those cases requires matching arguments. Defaults
can be useful. Perhaps:

    {
       "parameters": [
         "ICU_INSTALL_PATH",
         { "ICU_INCLUDE_PATH": "${ICU_INSTALL_PATH}/include" }
       ],
       "include-paths": [
         "${ICU_INCLUDE_PATH}"
       ]
    }

Real source code has language requirements but specifying compiler
specific command line options is undesirable. Feature test macros might
be useful. It would probably be useful to be able to specify these with
the same granularity as include paths.

    {
       "requirements": [
         { "macro": { "__cplusplus": ">=202002L" } },
         { "macro": { "__cpp_constexpr": ">=202306L" } }
       ]
    }

What to do with object files? I think we've identified two options:

 1. The object file (corresponding to an individual module unit) is
    already linked into a library: complete programs must link the library.
 2. The object file is not linked into a library: build it with
    weak-linkage/comdat and link it in ... somewhere one or more times.

If the second case is made a default, then the link requirement can be
made explicit. Portable library names will presumably be challenging as
usual. Having an explicit syntax for the default is generally useful.

    {
       "requirements": [
         { "link-library": "libstd" }
       ]
    }

Vendor specific configuration is likely to become a requirement at some
point. Perhaps it makes sense to deal with that up front. Perhaps
options to exclude certain source files or add alternate include paths.
Care is needed to not become cmake when providing such flexibility.

The above is a straw man intended to be knocked around. Take it down. Be
a bully! The goal is to identify things we like/want/need and things we
don't.

Tom.

Received on 2023-12-12 21:33:05