From f2300e4829cdbce714db2ad455a1c7ebef031353 Mon Sep 17 00:00:00 2001 From: speak-agent <248744407+speak-agent@users.noreply.github.com> Date: Sun, 27 Sep 2026 21:55:18 +0800 Subject: [PATCH 1/2] spec: S1 0.3.0, generated files and the path the build writes them to A set's ide object gains generated (section 7.2): each file or directory the build generates and the set's units compile or include, with the path the document names, the path the build of the same configuration writes, its kind, and for a file the step that writes it. A consumer does not report a missing generated file as an error in the referring source, may read the build's copy read-only, and runs a step only with its user's consent. Motivated by mcpp-community/mcpp#724. --- conformance/traceability.json | 52 ++++++++++- docs/specs/CHANGELOG.md | 14 +++ docs/specs/README.md | 2 +- .../examples/s1-level2-clang-two-sets.json | 2 +- docs/specs/examples/s1-level3-gcc.json | 2 +- docs/specs/s1-build-database.md | 28 +++++- .../schema/s1-build-database.schema.json | 87 ++++++++++++++++++- 7 files changed, 178 insertions(+), 9 deletions(-) diff --git a/conformance/traceability.json b/conformance/traceability.json index c13ccdf..7bdd2ff 100644 --- a/conformance/traceability.json +++ b/conformance/traceability.json @@ -1,6 +1,11 @@ { "$comment": "Rule identifiers of specifications S1 to S5 mapped to evidence (usable plan W10.2), checked by docs/specs/tools/validate.py. Evidence: validate (a passing check of validate.py, by label prefix), test (tests/.cpp: ), check (/), review (a review fixture under tools/bench/review), script (a file and a line that enforces the rule), manual (why no automated evidence can exist).", - "$pending": {}, + "$pending": { + "S1-7.2-10": "the server does not read `generated` yet", + "S1-7.2-11": "the server does not read `generated` yet", + "S1-7.2-12": "the server does not read `generated` yet", + "S1-7.2-13": "the server does not read `generated` yet" + }, "S1-3-1": [ { "test": "tests/test_spec.cpp: private units are not visible and duplicates are ambiguous" @@ -248,6 +253,51 @@ "test": "tests/test_spec.cpp: the level 3 GCC example loads" } ], + "S1-7.2-1": [ + { + "manual": "A producer rule. mcpp-community/mcpp writes the object, and its e2e 815 checks the fields; this repository contains no producer that could be tested." + } + ], + "S1-7.2-2": [ + { + "manual": "A producer rule. mcpp-community/mcpp writes the object, and its e2e 815 checks the fields; this repository contains no producer that could be tested." + } + ], + "S1-7.2-3": [ + { + "manual": "A producer rule. mcpp-community/mcpp writes the object, and its e2e 815 checks the fields; this repository contains no producer that could be tested." + } + ], + "S1-7.2-4": [ + { + "manual": "A producer rule. mcpp-community/mcpp writes the object, and its e2e 815 checks the fields; this repository contains no producer that could be tested." + } + ], + "S1-7.2-5": [ + { + "manual": "A producer rule. mcpp-community/mcpp writes the object, and its e2e 815 checks the fields; this repository contains no producer that could be tested." + } + ], + "S1-7.2-6": [ + { + "manual": "A producer rule. mcpp-community/mcpp writes the object, and its e2e 815 checks the fields; this repository contains no producer that could be tested." + } + ], + "S1-7.2-7": [ + { + "manual": "A producer rule. mcpp-community/mcpp writes the object, and its e2e 815 checks the fields; this repository contains no producer that could be tested." + } + ], + "S1-7.2-8": [ + { + "manual": "A producer rule. mcpp-community/mcpp writes the object, and its e2e 815 checks the fields; this repository contains no producer that could be tested." + } + ], + "S1-7.2-9": [ + { + "manual": "A producer rule. mcpp-community/mcpp writes the object, and its e2e 815 checks the fields; this repository contains no producer that could be tested." + } + ], "S1-8-1": [ { "validate": "S1 schema rejects unit without source" diff --git a/docs/specs/CHANGELOG.md b/docs/specs/CHANGELOG.md index d168398..0072d6d 100644 --- a/docs/specs/CHANGELOG.md +++ b/docs/specs/CHANGELOG.md @@ -2,6 +2,20 @@ Changes to the specifications in this directory. Each specification is versioned independently. +## 2026-09-27 — S1 0.3.0: generated files + +A set's `ide` object gains `generated` (optional, section 7.2): the files and directories that the +build generates and that the set's units compile or include, each with the path this document names +(`path`), the path the build of the same configuration writes (`build-path`), its `kind` (`source`, +`header` or `directory`) and, for a file, the step that writes it (`generator`: `id`, `inputs`, +`arguments`, `work-directory`). A consumer does not report a reference to a generated file that does +not exist as an error in the referring source; it may read the file at `build-path` read-only, and it +runs a step only with its user's consent (S1-7.2-10 to S1-7.2-13). A producer that plans without +building, such as `mcpp emit build-database`, plans in a directory of its own; before this, a header a +rule generates was missing there, and every source that included it lost its semantics +(mcpp-community/mcpp#724). Additive: a 0.2.0 consumer ignores the field (S1-11.2-1). mcpp writes it +from mcpp-community/mcpp's release that closes #724. + ## 2026-09-27 — S3: a download the client may offer, and two more build systems `CxxModulesIssue` gains `askOnline` (optional): on a `producer-needs-download` issue, the server will diff --git a/docs/specs/README.md b/docs/specs/README.md index efe1612..51a14c8 100644 --- a/docs/specs/README.md +++ b/docs/specs/README.md @@ -4,7 +4,7 @@ This directory holds the normative specifications that let C++ named modules be | Spec | Title | Version | Status | Schema | |---|---|---|---|---| -| [S1](s1-build-database.md) | C++ Build Database: IDE Profile | profile-version 0.2.0 | Draft | [s1-build-database.schema.json](schema/s1-build-database.schema.json) | +| [S1](s1-build-database.md) | C++ Build Database: IDE Profile | profile-version 0.3.0 | Draft | [s1-build-database.schema.json](schema/s1-build-database.schema.json) | | [S2](s2-discovery.md) | Build Database Discovery Protocol | 0.3.0 | Draft | [s2-discovery.schema.json](schema/s2-discovery.schema.json) | | [S3](s3-lsp-extensions.md) | Language Server Protocol Extensions for C++ Modules | protocol version 1 | Draft | TypeScript interfaces in the text | | [S4](s4-semantic-kit.md) | Semantic Kit | kit-version 1 | Draft | [s4-kit.schema.json](schema/s4-kit.schema.json) | diff --git a/docs/specs/examples/s1-level2-clang-two-sets.json b/docs/specs/examples/s1-level2-clang-two-sets.json index 9caf910..d2a2bb1 100644 --- a/docs/specs/examples/s1-level2-clang-two-sets.json +++ b/docs/specs/examples/s1-level2-clang-two-sets.json @@ -2,7 +2,7 @@ "version": 1, "revision": 0, "ide": { - "profile-version": "0.2.0", + "profile-version": "0.3.0", "generator": { "name": "example-cmake-adapter", "version": "0.1.0" }, "toolchains": { "clang-22.1.8-x86_64-unknown-linux-gnu": { diff --git a/docs/specs/examples/s1-level3-gcc.json b/docs/specs/examples/s1-level3-gcc.json index bfcf006..3257343 100644 --- a/docs/specs/examples/s1-level3-gcc.json +++ b/docs/specs/examples/s1-level3-gcc.json @@ -2,7 +2,7 @@ "version": 1, "revision": 0, "ide": { - "profile-version": "0.2.0", + "profile-version": "0.3.0", "generator": { "name": "example-producer", "version": "1.0.0" }, "toolchains": { "gcc-16.1.0-x86_64-linux-gnu": { diff --git a/docs/specs/s1-build-database.md b/docs/specs/s1-build-database.md index f2b82ca..cc029ec 100644 --- a/docs/specs/s1-build-database.md +++ b/docs/specs/s1-build-database.md @@ -3,7 +3,7 @@ | | | |---|---| | Specification | S1 | -| Profile version | 0.2.0 | +| Profile version | 0.3.0 | | Status | Draft | | Schema | [`schema/s1-build-database.schema.json`](schema/s1-build-database.schema.json) | | Examples | [`examples/s1-level3-gcc.json`](examples/s1-level3-gcc.json), [`examples/s1-level2-clang-two-sets.json`](examples/s1-level2-clang-two-sets.json) | @@ -108,7 +108,7 @@ Database (P2977R2) | Field | Type | Requirement | Description | |---|---|---|---| -| `profile-version` | string | MUST | The version of this profile the document conforms to, as a semantic version, for example `"0.2.0"`. S1-5.1-1 | +| `profile-version` | string | MUST | The version of this profile the document conforms to, as a semantic version, for example `"0.3.0"`. S1-5.1-1 | | `generator` | object | SHOULD | The producer: `name` (string, MUST) and `version` (string, SHOULD). S1-5.1-2, S1-5.1-3, S1-5.1-4 | | `toolchains` | object | MUST | Map from toolchain id to Toolchain object (section 6). Ids are opaque strings. S1-5.1-5 | | `extensions` | object | MAY | Vendor extensions (section 13). | @@ -165,8 +165,30 @@ How units are grouped into sets follows how the build resolves imports. A build | `kind` | enum | SHOULD | `library`, `executable`, `test` or `other`. Consumers use it to choose a default context. S1-7.1-3 | | `options` | SemanticOptions | level 3 MUST | Structured form of `baseline-arguments` (section 9). S1-7.1-4 | | `module-metadata` | string[] | MAY | Module metadata files of external modules visible to this set, excluding the toolchain's standard library. | +| `generated` | Generated[] | MAY | Files and directories that the build generates and that the units of this set compile or include (section 7.2). | | `extensions` | object | MAY | Vendor extensions. | +### 7.2 Generated object + +A build can generate files that the units of a set compile or include: sources and headers written by code generators, and the directories that hold them. A producer that performs no build describes them, so that a consumer can tell a file that a build has not written yet from a file that is missing. + +| Field | Type | Requirement | Description | +|---|---|---|---| +| `path` | string | MUST | Absolute path of the file or directory in the configuration this document describes, as the units' `arguments` name it. S1-7.2-1 | +| `build-path` | string | SHOULD | Absolute path at which the build of the same configuration writes it. It differs from `path` when the producer plans in a directory of its own, and equals `path` otherwise. It is stated whether or not the file exists. S1-7.2-2 | +| `kind` | enum | MUST | `source` (a unit of the set is compiled from it), `header` (units of the set include it) or `directory` (an include directory whose contents are generated). S1-7.2-3 | +| `generator` | object | conditional MUST | REQUIRED for `source` and `header`, absent for `directory`. It has `id` (string, MUST), the producer's name for the step that writes the file; `inputs` (string[], SHOULD), the absolute paths of the files the step reads; `arguments` (string[], SHOULD), the step's command, program first; and `work-directory` (string, MAY). S1-7.2-4, S1-7.2-5, S1-7.2-6, S1-7.2-7, S1-7.2-8 | + +A producer **SHOULD** list every generated file that a unit's `arguments` name, and every generated file in an include directory that the `arguments` name, whenever it knows the step that writes the file. S1-7.2-9 A translation unit whose `source` is the `path` of a `source` entry is a generated unit: before a build its source may be absent or empty. + +A consumer: + +- **MUST NOT** report a unit's reference to a generated file that does not exist as an error in that unit's source, and **SHOULD** tell the user that the file is generated, by which step, and that a build writes it; S1-7.2-10, S1-7.2-11 +- **MAY** read the file at `build-path` when it exists, read-only (section 14), and **MUST** then treat it as possibly stale relative to the step's inputs; S1-7.2-12 +- **MUST NOT** run a step's `arguments` unless the user has allowed it for the workspace (section 14). S1-7.2-13 + +Rationale: a producer that does not build (for example mcpp's `emit build-database`, which writes nothing into the project and runs no build step) plans in a directory of its own, so a generated header named by the units' `-I` arguments is absent there. Without this object a consumer reports a missing header in every source that includes it and loses the semantics of that source. The object states which files are generated and where the build writes them; running the generators remains a decision of the consumer and its user. + ## 8. Translation unit object | Field | Type | Requirement | Description | @@ -297,7 +319,7 @@ The example project below is built with GCC 16. It has module `hello.greet` with "version": 1, "revision": 0, "ide": { - "profile-version": "0.2.0", + "profile-version": "0.3.0", "generator": { "name": "example-producer", "version": "1.0.0" }, "toolchains": { "gcc-16.1.0-x86_64-linux-gnu": { diff --git a/docs/specs/schema/s1-build-database.schema.json b/docs/specs/schema/s1-build-database.schema.json index dc35b22..f469616 100644 --- a/docs/specs/schema/s1-build-database.schema.json +++ b/docs/specs/schema/s1-build-database.schema.json @@ -1,7 +1,7 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://github.com/mcpp-community/mcpp-language-server/specs/schema/s1-build-database/0.2.0", - "title": "C++ Build Database: IDE Profile 0.2.0 (S1)", + "$id": "https://github.com/mcpp-community/mcpp-language-server/specs/schema/s1-build-database/0.3.0", + "title": "C++ Build Database: IDE Profile 0.3.0 (S1)", "description": "A P2977R2-compatible build database with the IDE profile fields of S1. Unknown fields are permitted everywhere; consumers ignore them.", "type": "object", "required": [ @@ -226,11 +226,94 @@ "$ref": "#/$defs/nonEmptyString" } }, + "generated": { + "type": "array", + "items": { + "$ref": "#/$defs/generated" + } + }, "extensions": { "$ref": "#/$defs/extensions" } } }, + "generated": { + "type": "object", + "required": [ + "path", + "kind" + ], + "properties": { + "path": { + "$ref": "#/$defs/nonEmptyString" + }, + "build-path": { + "$ref": "#/$defs/nonEmptyString" + }, + "kind": { + "enum": [ + "source", + "header", + "directory" + ] + }, + "generator": { + "type": "object", + "required": [ + "id" + ], + "properties": { + "id": { + "$ref": "#/$defs/nonEmptyString" + }, + "inputs": { + "$ref": "#/$defs/stringArray" + }, + "arguments": { + "$ref": "#/$defs/stringArray" + }, + "work-directory": { + "type": "string" + } + } + } + }, + "allOf": [ + { + "if": { + "properties": { + "kind": { + "enum": [ + "source", + "header" + ] + } + } + }, + "then": { + "required": [ + "generator" + ] + } + }, + { + "if": { + "properties": { + "kind": { + "const": "directory" + } + } + }, + "then": { + "not": { + "required": [ + "generator" + ] + } + } + } + ] + }, "translationUnit": { "type": "object", "required": [ From 3f18747e515652d2be5706b34d3e92ad1a49471c Mon Sep 17 00:00:00 2001 From: speak-agent <248744407+speak-agent@users.noreply.github.com> Date: Sun, 27 Sep 2026 22:48:01 +0800 Subject: [PATCH 2/2] spec: keep the examples at 0.2.0; a 0.2.0 document is a valid 0.3.0 document --- docs/specs/examples/s1-level2-clang-two-sets.json | 2 +- docs/specs/examples/s1-level3-gcc.json | 2 +- docs/specs/s1-build-database.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/specs/examples/s1-level2-clang-two-sets.json b/docs/specs/examples/s1-level2-clang-two-sets.json index d2a2bb1..9caf910 100644 --- a/docs/specs/examples/s1-level2-clang-two-sets.json +++ b/docs/specs/examples/s1-level2-clang-two-sets.json @@ -2,7 +2,7 @@ "version": 1, "revision": 0, "ide": { - "profile-version": "0.3.0", + "profile-version": "0.2.0", "generator": { "name": "example-cmake-adapter", "version": "0.1.0" }, "toolchains": { "clang-22.1.8-x86_64-unknown-linux-gnu": { diff --git a/docs/specs/examples/s1-level3-gcc.json b/docs/specs/examples/s1-level3-gcc.json index 3257343..bfcf006 100644 --- a/docs/specs/examples/s1-level3-gcc.json +++ b/docs/specs/examples/s1-level3-gcc.json @@ -2,7 +2,7 @@ "version": 1, "revision": 0, "ide": { - "profile-version": "0.3.0", + "profile-version": "0.2.0", "generator": { "name": "example-producer", "version": "1.0.0" }, "toolchains": { "gcc-16.1.0-x86_64-linux-gnu": { diff --git a/docs/specs/s1-build-database.md b/docs/specs/s1-build-database.md index cc029ec..7b778ea 100644 --- a/docs/specs/s1-build-database.md +++ b/docs/specs/s1-build-database.md @@ -319,7 +319,7 @@ The example project below is built with GCC 16. It has module `hello.greet` with "version": 1, "revision": 0, "ide": { - "profile-version": "0.3.0", + "profile-version": "0.2.0", "generator": { "name": "example-producer", "version": "1.0.0" }, "toolchains": { "gcc-16.1.0-x86_64-linux-gnu": {