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/s1-build-database.md b/docs/specs/s1-build-database.md index f2b82ca..7b778ea 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 | 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": [