Document #:

ISO/IEC/JTC1/SC22/WG21/P3335R2

Date:

2024-10-15

Audience:

SG15

Authors:

René Ferdinand Rivera Morell

Reply-to:

[email protected]

Copyright:

Copyright 2024 René Ferdinand Rivera Morell, Creative Commons Attribution 4.0 International License (CC BY 4.0)

I: Proposal

1. Abstract

Specify a minimal set of core structured options [1] for C++ compiler front ends.

2. Revision History

2.1. Revision 2 (October 2024)

Added wording and corresponding JSON Schema changes.

2.2. Revision 1 (September 2024)

Per feedback from telecon discussion: remove debug option, remove safe optimization value, avoid file names as keys, use only singly-typed values.

2.3. Revision 0 (July 2024)

Initial text.

3. Motivation

Tools in the C++ ecosystem have dealt with using a myriad of different options to invoke C++ compiler front ends for decades. Although we have found ways to manage the variety it is advantageous to agree on a common language to reduce the growing complexities that the variety creates.

Having a standard common set of structured options allows for:

  • Reuse of implementation by tools that interface with compiler front ends.

  • Wider adoption of tools that use, as consumers or producers, the common options.

  • Lowers the barriers for unexperienced users as they have less to learn.

  • Can be a basis for other standards to form a common configuration vocabulary.

4. Scope

This proposal aims to specify a set of C++ compiler frontend structured options [1] sufficient to build common C++ use cases. This includes specifying both the names and semantics of the structured options.

This does not aim to standardize compiler frontend command line arguments. Although vendors are free to adopt the names and semantics specified if they wish. And we encourage such adoption.

5. Design

The approach for the names and semantics of the options follows these goals:

  • Prefer widely used terms in current tools, not just C++ compiler front ends.

  • Use widely understood semantics.

  • Improve the structure of the data.

5.1. File References

In various places the options need to refer to file names and paths. And in some of those instances it’s also possible to want to specify one or more attributes to the file. For example when indicating the language for a source file. We looked at various ways to achieve an arrangement to make that specification both optional and future proof. After discussions a simple JSON object with one required name key and string value for the path was chosen:

{
  "name": "file.ext"
}

Other fields are possible depending in the context of the file reference. For example to specify the language of a source file:

{
  "name": "main.cpp",
  "language": "c++"
}
Previously we had proposed using a multi-stage scheme to simplify the human editing of file references that allowed: a single string, an object with string, or an object with objects. Discussions pointed out difficulties in such dynamic parsing of values by some JSON parsers.

5.2. Lists

All lists are strictly JSON array values.

Previously we had proposed using a multi-stage scheme to simplify the human editing of lists that allowed lists with a single value to be abbreviated by the single value. Discussions pointed out difficulties in such dynamic parsing of values by some JSON parsers.

5.3. Examples

Below are some examples that show a traditional command line invocation and the corresponding structured options specification. The examples are meant to be informational only to illustrate how the structured options could work. As such they may include options that are not proposed in this document. The example command line invocations may also contain some options that are not present in the structured options. I.e. they are not meant to be a one-to-one correspondence. Generally the examples where generated by running a real build system and collecting the command lines it invokes.

5.3.1. Hello World

This is the classic simplest C++ program with the twist that we want to allow full debugging when running it.

"g++" -O0 -fno-inline -Wall -g -static "hello.cpp" -o "hello"
"cl" "hello.cpp" /Fehello -TP /EHs /GR /Z7 /Od /Ob0 /W3 /Op /MLd /DEBUG
  /subsystem:console

Those invocations can be represented as a somewhat more meaningful structured options. This specification is formulated to be a single cross-vendor object by using a vendor specific section to represent options that only msvc understands. And that other tools could ignore.

{
  "source": [{ "name": "hello.cpp" }],
  "output": [
    {
      "name": "hello",
      "kind": "exec"
    }
  ],
  "optimization": {
    "compile": "off",
    "inline": false
  },
  "warnings": {
    "enable": "all"
  },
  "runtime": {
    "multithread": false,
    "debug": true,
    "static": true
  },
  "vendor": {
    "msvc": {
      "subsystem": "console"
    }
  }
}

A single invocation that does everything is not particularly common, except as basic textbook examples. Here we see the more common case of compiling to produce an object file for the TU. Then linking to get the final executable.

"g++" --fPIC -O0 -fno-inline -Wall -g -c -o "hello.o" "hello.cpp"
"g++" -g "hello.o" -o "hello"

The compile only equivalent structured options:

{
  "source": [{ "name": "hello.cpp" }],
  "output": [{ "name": "hello.o", "kind": "object" }],
  "optimization": {
    "compile": "off",
    "inline": false
  },
  "warnings": {
    "enable": "all"
  },
  "runtime": {
    "multithread": false,
    "debug": true,
    "static": true
  }
}

Followed by the structured options to accomplish the link:

{
  "source": [{ "name": "hello.o" }],
  "output": [
    {
      "name": "hello",
      "kind": "exec"
    }
  ]
}

5.3.3. Many Sources

This is a single command B2 uses to bootstrap its engine on Linux with GCC, and Windows with MSVC. This is a variation on a simple basic invocation that builds many files with some extra options.

g++ -x c++ -std=c++11 -pthread -O2 -s -DNDEBUG bindjam.cpp builtins.cpp
  class.cpp command.cpp compile.cpp constants.cpp cwd.cpp debug.cpp
  debugger.cpp events.cpp execcmd.cpp execnt.cpp execunix.cpp filent.cpp
  filesys.cpp fileunix.cpp frames.cpp function.cpp glob.cpp hash.cpp
  hcache.cpp hdrmacro.cpp headers.cpp jam_strings.cpp jam.cpp jamgram.cpp
  lists.cpp make.cpp make1.cpp md5.cpp mem.cpp modules.cpp native.cpp
  option.cpp output.cpp parse.cpp pathnt.cpp pathsys.cpp pathunix.cpp
  regexp.cpp rules.cpp scan.cpp search.cpp startup.cpp tasks.cpp
  timestamp.cpp value.cpp variable.cpp w32_getreg.cpp mod_command_db.cpp
  mod_db.cpp mod_jam_builtin.cpp mod_jam_class.cpp mod_jam_errors.cpp
  mod_jam_modules.cpp mod_order.cpp mod_path.cpp mod_property_set.cpp
  mod_regex.cpp mod_sequence.cpp mod_set.cpp mod_string.cpp mod_summary.cpp
  mod_sysinfo.cpp mod_version.cpp -o b2

Other than many more files this example doesn’t differ much from the Hello World example.

{
  "source": [
    { "name": "bindjam.cpp" },
    { "name": "builtins.cpp" },
    { "name": "class.cpp" },
    { "name": "command.cpp" },
    { "name": "compile.cpp" },
    { "name": "constants.cpp" },
    { "name": "cwd.cpp" },
    { "name": "debug.cpp" },
    { "name": "debugger.cpp" },
    { "name": "events.cpp" },
    { "name": "execcmd.cpp" },
    { "name": "execnt.cpp" },
    { "name": "execunix.cpp" },
    { "name": "filent.cpp" },
    { "name": "filesys.cpp" },
    { "name": "fileunix.cpp" },
    { "name": "frames.cpp" },
    { "name": "function.cpp" },
    { "name": "glob.cpp" },
    { "name": "hash.cpp" },
    { "name": "hcache.cpp" },
    { "name": "hdrmacro.cpp" },
    { "name": "headers.cpp" },
    { "name": "jam_strings.cpp" },
    { "name": "jam.cpp" },
    { "name": "jamgram.cpp" },
    { "name": "lists.cpp" },
    { "name": "make.cpp" },
    { "name": "make1.cpp" },
    { "name": "md5.cpp" },
    { "name": "mem.cpp" },
    { "name": "modules.cpp" },
    { "name": "native.cpp" },
    { "name": "option.cpp" },
    { "name": "output.cpp" },
    { "name": "parse.cpp" },
    { "name": "pathnt.cpp" },
    { "name": "pathsys.cpp" },
    { "name": "pathunix.cpp" },
    { "name": "regexp.cpp" },
    { "name": "rules.cpp" },
    { "name": "scan.cpp" },
    { "name": "search.cpp" },
    { "name": "startup.cpp" },
    { "name": "tasks.cpp" },
    { "name": "timestamp.cpp" },
    { "name": "value.cpp" },
    { "name": "variable.cpp" },
    { "name": "w32_getreg.cpp" },
    { "name": "mod_command_db.cpp" },
    { "name": "mod_db.cpp" },
    { "name": "mod_jam_builtin.cpp" },
    { "name": "mod_jam_class.cpp" },
    { "name": "mod_jam_errors.cpp" },
    { "name": "mod_jam_modules.cpp" },
    { "name": "mod_order.cpp" },
    { "name": "mod_path.cpp" },
    { "name": "mod_property_set.cpp" },
    { "name": "mod_regex.cpp" },
    { "name": "mod_sequence.cpp" },
    { "name": "mod_set.cpp" },
    { "name": "mod_string.cpp" },
    { "name": "mod_summary.cpp" },
    { "name": "mod_sysinfo.cpp" },
    { "name": "mod_version.cpp" }
  ],
  "output": [{ "name": "b2", "kind": "exec" }],
  "define": [{ "name": "NDEBUG" }],
  "language": {
    "name": "c++",
    "standard": "11"
  },
  "optimization": {
    "compile": "minimal",
    "link": true,
    "msvc.global_data": true
  },
  "runtime": {
    "multithread": true,
    "debug": false,
    "static": true
  }
}
"cl" /nologo /MP /MT /TP /Feb2 /wd4996 /wd4675 /O2 /GL /EHsc /Zc:wchar_t /Gw
  -DNDEBUG  bindjam.cpp builtins.cpp class.cpp command.cpp compile.cpp
  constants.cpp cwd.cpp debug.cpp debugger.cpp events.cpp execcmd.cpp
  execnt.cpp execunix.cpp filent.cpp filesys.cpp fileunix.cpp frames.cpp
  function.cpp glob.cpp hash.cpp hcache.cpp hdrmacro.cpp headers.cpp jam.cpp
  jamgram.cpp lists.cpp make.cpp make1.cpp md5.cpp mem.cpp modules.cpp
  native.cpp option.cpp output.cpp parse.cpp pathnt.cpp pathsys.cpp
  pathunix.cpp regexp.cpp rules.cpp scan.cpp search.cpp jam_strings.cpp
  startup.cpp tasks.cpp timestamp.cpp value.cpp variable.cpp w32_getreg.cpp
  mod_command_db.cpp mod_db.cpp mod_jam_builtin.cpp mod_jam_class.cpp
  mod_jam_errors.cpp mod_jam_modules.cpp mod_order.cpp mod_path.cpp
  mod_property_set.cpp mod_regex.cpp mod_sequence.cpp mod_set.cpp
  mod_string.cpp mod_summary.cpp mod_sysinfo.cpp mod_version.cpp
  /link kernel32.lib advapi32.lib user32.lib
  /MANIFEST:EMBED /MANIFESTINPUT:b2.exe.manifest

The msvc equivalent has the addition of listing some system libraries and the special Windows embedded manifest for the executable.

{
  "source": [
    { "name": "bindjam.cpp" },
    { "name": "builtins.cpp" },
    { "name": "class.cpp" },
    { "name": "command.cpp" },
    { "name": "compile.cpp" },
    { "name": "constants.cpp" },
    { "name": "cwd.cpp" },
    { "name": "debug.cpp" },
    { "name": "debugger.cpp" },
    { "name": "events.cpp" },
    { "name": "execcmd.cpp" },
    { "name": "execnt.cpp" },
    { "name": "execunix.cpp" },
    { "name": "filent.cpp" },
    { "name": "filesys.cpp" },
    { "name": "fileunix.cpp" },
    { "name": "frames.cpp" },
    { "name": "function.cpp" },
    { "name": "glob.cpp" },
    { "name": "hash.cpp" },
    { "name": "hcache.cpp" },
    { "name": "hdrmacro.cpp" },
    { "name": "headers.cpp" },
    { "name": "jam_strings.cpp" },
    { "name": "jam.cpp" },
    { "name": "jamgram.cpp" },
    { "name": "lists.cpp" },
    { "name": "make.cpp" },
    { "name": "make1.cpp" },
    { "name": "md5.cpp" },
    { "name": "mem.cpp" },
    { "name": "modules.cpp" },
    { "name": "native.cpp" },
    { "name": "option.cpp" },
    { "name": "output.cpp" },
    { "name": "parse.cpp" },
    { "name": "pathnt.cpp" },
    { "name": "pathsys.cpp" },
    { "name": "pathunix.cpp" },
    { "name": "regexp.cpp" },
    { "name": "rules.cpp" },
    { "name": "scan.cpp" },
    { "name": "search.cpp" },
    { "name": "startup.cpp" },
    { "name": "tasks.cpp" },
    { "name": "timestamp.cpp" },
    { "name": "value.cpp" },
    { "name": "variable.cpp" },
    { "name": "w32_getreg.cpp" },
    { "name": "mod_command_db.cpp" },
    { "name": "mod_db.cpp" },
    { "name": "mod_jam_builtin.cpp" },
    { "name": "mod_jam_class.cpp" },
    { "name": "mod_jam_errors.cpp" },
    { "name": "mod_jam_modules.cpp" },
    { "name": "mod_order.cpp" },
    { "name": "mod_path.cpp" },
    { "name": "mod_property_set.cpp" },
    { "name": "mod_regex.cpp" },
    { "name": "mod_sequence.cpp" },
    { "name": "mod_set.cpp" },
    { "name": "mod_string.cpp" },
    { "name": "mod_summary.cpp" },
    { "name": "mod_sysinfo.cpp" },
    { "name": "mod_version.cpp" },
    { "name": "kernel32.lib" },
    { "name": "advapi32.lib" },
    { "name": "user32.lib" }
  ],
  "output": [{ "name": "b2", "kind": "exec" }],
  "define": [{ "name": "NDEBUG", "value": null }],
  "language": { "name": "c++", "standard": "11" },
  "optimization": {
    "compile": "minimal",
    "link": true,
    "msvc.global_data": true
  },
  "runtime": {
    "multithread": true,
    "debug": false,
    "static": true
  },
  "vendor": {
    "msvc": {
      "manifest": {
        "source": "b2.exe.manifest",
        "embed": true
      }
    }
  }
}

5.4. Options

In the tables below compiler drivers or front ends we list the un-prefixed option name. And for build systems we list any abstraction for the option. But importantly, we don’t list if the build system only allows for specifying the raw option. As it doesn’t add any more information than what is given for the compiler driver information.

The options specified below show first how the concept is specified in two kinds of tools, compiler driver/front-ends and build systems. This is a small, but hopefully representative, sampling of syntax and semantics. The tools considered are: MSVC, [2] GCC, [3] CMake, [4] B2 [5]

And subsequently show the chosen key, value, and semantics of the option. The schema for the value is explained in the value if it’s brief. But otherwise defined in the semantics of each. As mentioned previously there can be multiple value types for an option. Each of those is outlined to the extent that the specific option allows (currently). The explanations of the options are not exhaustively precise. That is left for future wording.

5.4.1. Source

Tool Name Semantics

MSVC

file

A file specified as a regular argument is added as a source to process.

GCC

file

A file specified as a regular argument is added as a source to process.

CMake

file

A file specified as an argument to a target is added as a source to process.

B2

file

A file specified as an argument to a target is added as a source to process.

Key

Use std.source or shortened source.

Value

An array of Source Object values.

Semantics

Adds the sources given to the set of files to process.

Merge Semantics

The sources in this specification are appended to any existing sources.

5.4.1.1. Source Object

A source is specified as an object it consist of at minimum a name field specifying the file name of the source. Other fields are optional. And, if possible, the tool can inspect the source (or name) to determine values for unspecified fields.

name

The required file name of the source.

language

An optional Language that the source contains.

kind

An optional value that indicates the kind of Output that generated the file.

Examples

{
  "source": [{ "name": "main.cpp", "language": { "name": "c++" } }]
}
{
  "source": [
    { "name": "main.cpp" },
    { "name": "utils.cpp" },
    { "name": "algo.cpp" },
    { "name": "api.i", "language": { "name": "c" } }
  ]
}

5.4.2. Output

Tool Name Semantics

MSVC

FA, Fa, Fd, Fe, Fi, Fm, Fo, Fp, FR

Set the name of the generated output. The option specifies the kind of output generated as: FA, Fa (assembly); Fd (debug); Fe (executable); Fi (preprocessed); Fm (mapfile); Fo (object); Fp (pch); FR (browser)

GCC

o, along with c, S, and E

Sets the file to output with (o). And with the related options controls the kind of output to generate: c (compile → object), S (compile → assembly), E (preprocessed).

CMake

add_executable, add_library

Defines a target for an executable or library.

B2

exe, obj, lib

Defines a target of the given type: exe (executable), obj (object), lib (static or dynamic library).

Key

Use std.output or shortened output.

Value

An array of Output Object values.

Semantics

Specifies the output file, or files, to generate when processing the sources.

Merge Semantics

The outputs in this specification are appended to any existing outputs.

5.4.2.1. Output Object

A single output specifies an object consisting at minimum of the name and kind fields. Other fields are optional. And, if possible, the tool can infer the other fields as needed.

name

The required file name of the output.

kind

The kind of output. The kind of output also indicates the type of operation the tool will do. Possible kinds of outputs:

exec

Links the compiled sources into an executable file.

object

Compiles the sources into a linkable object file.

dynamic_lib

Links the compiled sources into a dynamically loadable library.

archive_lib

Collects the compiled sources into an archive library of object files.

Examples

{
  "output": [{ "name": "a.out", "kind": "exec" }]
}

5.4.3. Include Directories

Tool Name Semantics

MSVC

I, INCLUDE env var

Adds the directory to the include search list.

GCC

I

Adds the directory to the include search list.

CMake

include_directories() or INCLUDE_DIRECTORIES

Adds the directories to the include search list.

B2

include

Adds the directory, order unspecified, to the include search list.

Key

Use std.include_dirs or shortened include_dirs.

Value

An array of string-s. Each string is a pathname of which interpretation is up to the application.

Semantics

Adds the listed pathnames to the end of the include directories of the application. It is up to the application to interpret how the composed list of directories is used. But it commonly interpreted as #include preprocessor directives to look for files in the order of the include directories list.

Merge Semantics

The directories in this specification are appended to any existing directories.

Examples

{
  "include_dirs": ["/opt/boost_config/include", "/opt/openssl/include"]
}

5.4.4. Library Directories

Tool Name Semantics

MSVC

/link /LIBPATH:dir or LIB env var

Adds to the list of directories to search for link libs. The LIBPATH paths are searched before the LIB paths.

GCC

L

CMake

link_directories(AFTER/BEFORE …​)

Adds to the list of directories which will be used by the linker to search for libraries. Specifying AFTER or BEFORE will append or prepend the given directories to the existing list of directories.

B2

library-path

Adds to the list of directories which will be used by the linker to search for libraries.

Key

Use std.library_dirs or shortened library_dirs.

Value

An array of string-s. Each string is a pathname of which interpretation is up to the application.

Semantics

Adds the listed pathnames to the end of the library search directories of the application. It is up to the application to interpret how the composed list of directories is used.

Merge Semantics

The directories in this specification are appended to any existing directories.

Examples

{
  "library_dirs": ["/opt/boost_config/lib", "/opt/openssl/lib"]
}

5.4.5. Define Preprocessor Symbols

Tool Name Semantics

MSVC

D

Defines a preprocessor symbol to a value overriding any previous definition. If no value is given 1 is used as the value.

GCC

D

Defines a preprocessor symbol to a value overriding any previous definition. If no value is given 1 is used as the value.

CMake

add_compile_definitions, target_compile_definitions, COMPILE_DEFINITIONS

Defines a preprocessor symbol to a value overriding any previous definition. If no value is given no value is used and the value is up to the compiler.

B2

define

Defines a preprocessor symbol to a value overriding any previous definition. If no value is given no value is used and the value is up to the compiler.

Key

Use std.define or shortened define.

Value

An array of Preprocessor Symbol values.

Semantics

For each symbol a language preprocessor will define the symbol to the value.

Merge Semantics

The definitions in this specification either: add to existing set of definitions when the symbol doesn’t exist, or replace the definitions when the symbol already exists.

5.4.5.1. Preprocessor Symbol

A preprocessor symbol specifies a name and value. The value defined by the preprocessor is converted as follows based on the type of JSON value given:

  • JSON number is converted to a string and pasted.

  • JSON string is used directly.

  • JSON boolean is converted as true1 and false0.

  • JSON null converts to nothing, and hence the default implementation value should be used.

Examples

{
  "define": [
    { "name": "BOOST_ALL_NO_LIB", "value": 1 },
    { "name": "_WIN32_WINNT", "value": "0x0600" },
    { "name": "_GNU_SOURCE", "value": true },
    { "name": "U_USING_ICU_NAMESPACE", "value": false },
    { "name": "NOMINMAX", "value": null }
  ]
}

5.4.6. Undefine Preprocessor Symbols

Tool Name Semantics

MSVC

U

Undefines the given preprocessor symbol.

GCC

U

Undefines the given preprocessor symbol.

CMake

N/A

B2

undef

Undefines the given preprocessor symbol.

Key

Use std.undef or shortened undef.

Value

The option would be either a single string or an array of string-s. Each string is a symbol to undefine.

Semantics

For each string in the value "undefines" the preprocessor symbol. The option is evaluated after the define option.

Merge Semantics

The undefs in this specification either: add to existing set of undefs when the symbol doesn’t exist, or replace the undefs when the symbol already exists.

{
  "undef": ["NDEBUG"]
}

5.4.7. Language

Tool Name Semantics

MSVC

Tc, TC, Tp, TP

Specified a source file is a C (Tc or TC) or C++ (Tp or TP) file. Otherwise the file extension is used.

GCC

x language

Specified source files are the given language. Otherwise the file extension is used.

CMake

set_property(SOURCE language …​)

Specified source files are the given language. Otherwise the file extension is used.

B2

[ cast _ language : …​ ]

Specified source files are the given language. Otherwise the file extension is used.

Key

Use std.language or shortened language.

Value

The option value is a single string indicating the name of a language. The set of values is open. But at minimum c++ and c must be recognized. Other values could be: assembly, objective-c, objective-c++, fortran, go, d, ada.

Semantics

The given language sets the one to use for sources that do not otherwise specify one. The tool should indicate an error for languages it doesn’t recognize.

{
  "language": { "name": "c++" }
}
Merge Semantics

The language in this specification replaces an existing language specification.

5.4.8. Optimization

Tool Name Semantics

MSVC

Od, O1, O2, Os, Ot, Ox, and more

Disables (Od) or enables (the rest) code generation optimizations.

GCC

O0, O1, O2, O3, Os, Og, Oz, and more

Disables (O0) or enables (the rest) code generation optimizations.

CMake

DCMAKE_BUILD_TYPE=Release

Generates build description that may enable optimizations.

B2

<optimization>off, <optimization>minimal, <optimization>speed, <optimization>space, <optimization>debug

Disables (off) or enables (the rest) code generation optimizations for the targets it’s applied to.

Key

Use std.optimization or shortened optimization.

Value

An Optimization Object.

Semantics

The level of optimization is applied to all the sources being processed.

Merge Semantics

The fields in the object value replace existing optimization fields. For a single string value the equivalent object for that value is merged.

Examples

{
  "optimization": { "compile": "minimal" }
}
5.4.8.1. Optimization Object

An optimization object can have the following fields:

If the value is an object it can have the following fields, and semantics:

compile

The set of values for compile is fixed, but tools are free to ignore or use equivalent for the various values. Which optimizations the tool performs for each value is up to the tool. The only required semantic is for off that must disable all optimizations. Possible values:

  • off - Disable optimizations.

  • minimal - Optimizations that may improve speed and space.

  • speed - Prefer speed over space optimizations.

  • space - Prefer smaller binaries over speed optimizations.

  • debug - Optimize such that debugging capabilities are preserved.

link

A boolean value that when true enables link time (whole program) optimizations. When false, or not present, disables link time optimizations.

5.4.9. Vendor

We recognize that std options will never be sufficient, or practical, to delineate all possible functionality. To accommodate the flexibility needed over time to support all build capabilities we need to allow for tools to define their own options outside of the standard. While it is possible for tools to use scoped keys to specify their own options, that method may be harder to manage for some environments. To allow for easier destructuring we introduce a vendor option.

Key

Use std.vendor or shortened vendor.

Value

The option contains a single object with tool defined keys and values. The names of the keys, or the type of the values, or the semantics are not specified here. And it is up to the tool creators to coordinate on unique keys.

Semantics

The value in the vendor specific fields is interpreted per the tool requirements. Any number of vendor keys+values is allowed. Tools are not restricted in what they support. Either of their own keys+values. Or the Keys+values of other vendor tools. This allows from some level of interchange for tools that need to support some understanding of what other tools specify. For example static analyzers that often need to digest sources across different vendors.

Merge Semantics

The semantics are up to the vendor to specify for the individual options they define. Above that, if a vendor key in this specification is not present in the existing specification it is added. Otherwise, for a key in the vendor object in this specification is not present in the existing specification it is added.

Examples

{
  "optimization": {
    "compile": "debug",
    "link": true,
    "vendor": {
      "msvc": {
        "global_data": true
      }
    }
  },
  "vendor": {
    "msvc": {
      "manifest": {
        "source": "b2.exe.manifest",
        "embed": true
      },
      "subsystem": "console"
    }
  }
}

II: Wording

Wording is relative to P3342R0 Working Draft, Standard for C++ Ecosystem. [6]

An important goal in the wording below is to minimize how much application behavior is mandated. As specifying more than absolutely needed can impede current and future behavior of applications.

6. Edit 1

Replace 7 Structured Parameters Core Options ([strctparamopt]) with [strctopt.core] below.

6.1. Structured Core Options [strctopt.core]

6.1.1. Preamble [strctopt.core.pre]

This clause describes the schema and semantics of core structured options ([strctopt.schema.struct]) for C++ compiler front-end applications.

This clause specifies the std.strctopt.core capability ([intspct.cap]) version 1.0.0.

An application can implement this capability.

An application that implements the std.strctopt.core capability shall include the std.strctopt.core field and version value in the introspection JSON text output ([intspct.schema.cap]).

6.1.2. Source [strctopt.core.src]

Name: std.source or source
Type: array
Value: The value shall be a JSON array. The items in the array shall be of JSON object items specifying source objects ([strctopt.core.srcobj]).
Description: Defines a list of source files for an application to process.

The application shall add the given sources to the set of files to process.

The sources given shall be appended to existing sources in the order given.

6.1.2.1. Source Object [strctopt.core.srcobj]

A source object shall have a name field.

Name: std.name or name
Type: string
Value: A pathname to a file.
Description: The pathname of the source file.

A source object can have a language field ([strctopt.core.lang]).

Specifying a language field for a source shall replace any other determination of the source language by the application.

Specifying a language field for a source shall replace a language field specified in the structured parameters options field ([strctparam.schema.opts]).

A source object can have a kind field ([strctopt.core.kind]).

Specifying a kind field for a source shall replace any other determination of the source kind by the application.

Specifying a kind field for a source shall replace a kind field specified in the structured parameters options field ([strctparam.schema.opts]).

A source object can have a vendor field ([strctopt.core.vendor]).

6.1.3. Output [strctopt.core.out]

Name: std.output or output
Type: array
Value: The value shall be a JSON array. The items in the array shall be JSON object items specifying output objects ([strctopt-core-outobj]).
Description: Specifies the output files to generated when processing sources ([strctopt.core.src]).

6.1.3.1. Output Object [strctopt.core.outobj]

An output object shall have a name field.

Name: std.name or name
Type: string
Value: A pathname to a file.
Description: The name of the output file.

An output object can have a kind field ([strctopt.core.kind]).

Specifying a kind field for output shall replace any other determination of the output kind by the application.

An output object can have a vendor field ([strctopt.core.vendor]).

6.1.4. Include Directories [strctopt.core.incd]

Name: std.include_dirs or include_dirs
Type: array
Value: The value shall be a JSON array. The items in the array shall be JSON string items of pathnames to directories.
Description: One or more entries to directories that are searched by the header inclusion of a C++ preprocessor.

The application shall add the given directories to the set of directories searched by the header inclusion of a C++ preprocessor.

The directories given shall be appended to the existing include search directories in the order given.

6.1.5. Library Directories [strctopt.core.libd]

Name: std.library_dirs or library_dirs
Type: array
Value: The value shall be a JSON array. The items in the array shall be JSON string items of pathnames to directories.
Description: One or more entries to directories that are searched for libraries.

The application shall add the given directories to the set of directories searched for libraries.

The directories given shall be appended to the existing library search directories in the order given.

6.1.6. Define Preprocessor Symbols [strctopt.core.def]

Name: std.define or define
Type: array
Value: The value shall be a JSON array. The items in the array shall be JSON object items specifying preprocessor symbol definition objects ([strctopt.core.def.sym]).
Description: Specifies preprocessor symbols to define during processing of sources.

6.1.6.1. Preprocessor Symbol Definition Object [strctopt.core.def.sym]

Name: std.name or name
Type: string
Value: A valid preprocessor symbol.
Description: The field specifies the preprocessor symbol to define.

The symbol shall be valid for the consuming application.

The application shall indicate an error for invalid symbols.

Name: std.value or value
Type: number, string, boolean, or null
Value: A valid preprocessor define value.
Description: The field specifies the value to assign to the preprocessor symbol.

The value shall be valid for the consuming application.

A number value shall be converted to a string value.

A `string`value shall be used as given.

A true value shall be converted to a string value of 1.

A false value shall be converted to a string value of 0.

A null value shall not convert and the application default value will be used.

6.1.7. Undefine Preprocessor Symbols [strctopt.core.undef]

Name: std.undef or undef
Type: array
Value: The value shall be a JSON array. The items in the array shall be of JSON string defining preprocessor symbol names.
Description: Specifies preprocessor symbols to "undefine".

The symbols shall be valid for the consuming application.

The application shall indicate an error for invalid symbols.

The application shall evaluate this option after any std.define ([strctopt.core.def]) options.

6.1.8. Optimization [strctopt.core.opt]

Name: std.optimization or optimization
Type: string
Value: An optimization object item ([strctopt-core-optobj])
Description: The optimization to apply when generating the output.

The application shall replace each existing field in the optimization object ([strctopt-core-optobj]).

6.1.8.1. Optimization Object [strctopt.core.optobj]

An optimization object can have any of compile and link fields.

Name: compile
Type: string
Value: off, minimal, speed, space, or debug
Description: The amount or type of optimization to apply to the generated output.

An application shall not perform optimization when given the off value.

For minimal,speed, space, and debug values the application behavior is unspecified.

Name: link
Type: boolean
Value: true or false
Description: Specify if optimizations that happen for linked output generation happen.

An application shall not perform optimizations for linked output generation when the value is false.

For a true value the application behavior is unspecified.

An optimization object can have a vendor field ([strctopt.core.vendor]).

6.1.9. Vendor [strctopt.core.vendor]

Name: std.vendor or vendor
Type: object
Value: A vendor object strctopt.core.vendorobj
Description: Specifies vendor defined options to apply in the context they appear.

An application shall apply the vendor option semantics in the context they appear.

6.1.9.1. Vendor Object [strctopt.core.vendorobj]

A vendor object can have any number of fields.

The name of a field is unspecified.

The value of a field is unspecified.

It is up to application vendors to agree on the name fields.
It is up to application vendors to document the schema of the field values.

6.1.10. Language [strctopt.core.lang]

Name: language
Type: object
Value: A language object ([strctop.core.langobj])
Description: The language to interpret the source as.

6.1.10.1. Language Object [strctopt.core.langobj]

A language object shall have a name field.

Name: std.name or name
Type: string
Value: One of: c++ or an application defined value.
Description: Specifies the source text language.

Only a value of c++ specifies that source text ([strctopt.core.src]) is C++ ISO language.

6.1.11. Kind [strctopt.core.kind]

Name: kind
Type: string
Value: A kind item ([strctopt.core.kind])
Description: The kind, or format, of the source file corresponding to the output file ([strctopt.core.out]).

6.1.11.1. Kind Object [strctopt.core.kindobj]

Name: std.name or name
Type: string
Value: One of: text, exec, object, dynamic_lib, archive_lib
Description: The kind, or format, of source and output files.

A text value specifies that the source or output is textual.

A exec value specifies that the source or output is an executable program.

A object value specifies that the source or output is a linkable object.

A dynamic_lib value specifies that the source or output is dynamically linkable.

A archive_lib value specifies that the source or output is an archive, or collection, of linkable objects.

7. Edit 2

Replace B.2 JSON Schema Specification ([strctparamjschm.spec]) with [strctparamjschm.spec] below.

7.1. JSON Schema Specification [strctparamjschm.spec]

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "std_param-1.0.0.json",
  "title": "Structured Parameters Version 1.0.0 JSON Schema",
  "type": "object",
  "properties": {
    "$schema": {
      "description": "JSON Schema URI for the version of the structured parameters format.",
      "type": "string",
      "format": "uri"
    },
    "version": {
      "description": "The Structured Parameters format version.",
      "type": "string",
      "$ref": "#/$defs/Version"
    }
  },
  "patternProperties": {
    "(std\\.)?arguments": {
      "description": "Application direct arguments.",
      "type": "array",
      "items": { "type": "string" }
    },
    "(std\\.)?options": {
      "type": "object",
      "patternProperties": {
        "(std\\.)?param": { "$ref": "#/$defs/Std.Param" },
        "(std\\.)?source": {
          "$ref": "std_opt_core-1.0.0.json#/$defs/Std.Source"
        },
        "(std\\.)?output": {
          "$ref": "std_opt_core-1.0.0.json#/$defs/Std.Output"
        },
        "(std\\.)?include_dirs": {
          "$ref": "std_opt_core-1.0.0.json#/$defs/Std.IncludeDirs"
        },
        "(std\\.)?library_dirs": {
          "$ref": "std_opt_core-1.0.0.json#/$defs/Std.LibraryDirs"
        },
        "(std\\.)?define": {
          "$ref": "std_opt_core-1.0.0.json#/$defs/Std.Define"
        },
        "(std\\.)?undef": {
          "$ref": "std_opt_core-1.0.0.json#/$defs/Std.Undef"
        },
        "(std\\.)?language": {
          "$ref": "std_opt_core-1.0.0.json#/$defs/Std.Language"
        },
        "(std\\.)?optimization": {
          "$ref": "std_opt_core-1.0.0.json#/$defs/Std.Optimization"
        },
        "(std\\.)?vendor": {
          "$ref": "std_opt_core-1.0.0.json#/$defs/Std.Vendor"
        }
      }
    }
  },
  "additionalProperties": false,
  "oneOf": [{ "required": ["arguments"] }, { "required": ["options"] }],
  "$defs": {
    "Version": {
      "type": "string",
      "pattern": "^[0-9]+([.][0-9]+){0,2}$"
    },
    "Name": {
      "type": "string",
      "pattern": "^([a-z0-9_-]+[.])*([a-z0-9_-]+)$"
    },
    "StringOrArray": {
      "type": ["string", "array"],
      "items": { "type": "string" }
    },
    "Std.Param": {
      "description": "Recursive reference to one or more structured parameters files.",
      "type": "object",
      "properties": {
        "pre": { "$ref": "#/$defs/StringOrArray" },
        "post": { "$ref": "#/$defs/StringOrArray" }
      },
      "additionalProperties": false
    }
  }
}

8. Edit 3

Insert [strctoptcorejschm] (below) after Annex B.

8.1. Annex C

8.1.1. Structured Core Options JSON Schema [strctoptcorejschm]

8.1.1.1. General [strctoptcorejschm.general]

This Annex defines the structured parameter core options schema ([strctopt.core]) in terms os a JSON Schema.

8.1.1.2. JSON Schema Specification [strctoptcorejschm.spec]
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "std_opt_core-1.0.0",
  "title": "Structured Core Options Version 1.0.0 JSON Schema",
  "patternProperties": {
    "(std\\.)?source": { "$ref": "#/$defs/Std.Source" },
    "(std\\.)?output": { "$ref": "#/$defs/Std.Output" },
    "(std\\.)?include_dirs": { "$ref": "#/$defs/Std.IncludeDirs" },
    "(std\\.)?library_dirs": { "$ref": "#/$defs/Std.LibraryDirs" },
    "(std\\.)?define": { "$ref": "#/$defs/Std.Define" },
    "(std\\.)?undef": { "$ref": "#/$defs/Std.Undef" },
    "(std\\.)?optimization": { "$ref": "#/$defs/Std.Optimization" },
    "(std\\.)?vendor": { "$ref": "#/$defs/Std.Vendor" },
    "(std\\.)?language": { "$ref": "#/$defs/Std.Language" },
    "(std\\.)?kind": { "$ref": "#/$defs/Std.Kind" }
  },
  "$defs": {
    "Std.Source": {
      "description": "The source files to process.",
      "type": "array",
      "items": {
        "description": "A file to process.",
        "type": "object",
        "patternProperties": {
          "(std\\.)?name": { "type": "string" },
          "(std\\.)?language": { "$ref": "#/$defs/Std.Language" },
          "(std\\.)?kind": { "$ref": "#/$defs/Std.Kind" },
          "(std\\.)?vendor": { "$ref": "#/$defs/Std.Vendor" }
        },
        "additionalProperties": false
      }
    },
    "Std.Output": {
      "description": "The output files to generate.",
      "type": "array",
      "items": {
        "description": "An output file.",
        "type": "object",
        "patternProperties": {
          "(std\\.)?name": { "type": "string" },
          "(std\\.)?kind": { "$ref": "#/$defs/Std.Kind" },
          "(std\\.)?vendor": { "$ref": "#/$defs/Std.Vendor" }
        },
        "additionalProperties": false
      }
    },
    "Std.IncludeDirs": {
      "description": "Include directories.",
      "type": "array",
      "items": { "type": "string" }
    },
    "Std.LibraryDirs": {
      "description": "Library directories.",
      "type": "array",
      "items": { "type": "string" }
    },
    "Std.Define": {
      "description": "Define preprocessor symbols.",
      "type": "array",
      "items": {
        "type": "object",
        "patternProperties": {
          "(std\\.)?name": { "type": "string" },
          "(std\\.)?value": {
            "type": ["number", "integer", "string", "boolean", "null"]
          }
        },
        "additionalProperties": false
      }
    },
    "Std.Undef": {
      "description": "Undefine preprocessor symbols.",
      "type": "array",
      "items": { "type": "string" }
    },
    "Std.Language": {
      "description": "The language to interpret sources for.",
      "type": "object",
      "patternProperties": {
        "(std\\.)?name": {
          "type": "string"
        }
      }
    },
    "Std.Optimization": {
      "description": "The optimizations to apply to different stages of the processing.",
      "type": "object",
      "patternProperties": {
        "(std\\.)?compile": {
          "type": "string",
          "enum": ["off", "minimal", "speed", "space", "debug"]
        },
        "(std\\.)?link": {
          "type": "boolean"
        },
        "(std\\.)?vendor": { "$ref": "#/$defs/Std.Vendor" }
      }
    },
    "Std.Vendor": {
      "description": "Vendor defined specifications.",
      "type": "object",
      "patterProperties": {
        "^[a-z]+$": {
          "type": "object"
        }
      }
    },
    "Std.Kind": {
      "description": "The kind of data a source of output is.",
      "type": "string",
      "enum": ["text", "exec", "object", "dynamic_lib", "archive_lib"]
    }
  }
}

III: Colophon

9. License

This work is licensed under the Creative Commons Attribution 4.0 International License. To view a copy of this license, visit http://creativecommons.org/licenses/by/4.0/ or send a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.


1. P3051; Structured Response Files(https://wg21.link/P3051)
2. MSVC, Compiler options listed by category (https://learn.microsoft.com/en-us/cpp/build/reference/compiler-options-listed-by-category)
3. GCC Command Options (https://gcc.gnu.org/onlinedocs/gcc-14.1.0/gcc/Invoking-GCC.html)
4. CMake Reference Documentation (https://cmake.org/cmake/help/latest/index.html)
5. B2 User Manual (https://www.bfgroup.xyz/b2/manual/release/index.html)
6. P3342R0; Working Draft, Standard for C++ Ecosystem(https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3342r0.pdf)