diff --git a/.agents/skills/acknowledg-client/SKILL.md b/.agents/skills/acknowledg-client/SKILL.md index f666d6df4c..d8c5b87c1d 100644 --- a/.agents/skills/acknowledg-client/SKILL.md +++ b/.agents/skills/acknowledg-client/SKILL.md @@ -30,7 +30,9 @@ From `edgacknowledg.client` (`__all__`): - `ConnectionStatusListener` — `connected` / `attempting_reconnect` / `disconnected` - `ReviewClient` (structural **Protocol**): `review_id`, `name`, `timestamp`, - `sections()`, `add_section` / `remove_section` + `sections()`, `add_section` / `remove_section`. `name` is a `RichName` + (segments built with `rich_text` / `rich_link` from `edgacknowledg`; see + PROTOCOL.md "Rich names"); a plain title is `[rich_text(title)]` - URL/env helpers: `add_endpoint_arguments`, `form_section_http_url`, `default_*` host/port helpers - Shared: `BackgroundWorkerPool`, errors @@ -79,6 +81,17 @@ Auth header: `X-AcknowlEDG-API-Key` (never put the key in query strings). `RoleOccupied`: discard that handler / stop reconnecting that section; keep other sections running. +Batch subscribe / unsubscribe answers are not timed: the server answers at +once, and a lost connection (keepalive pings notice) fails what is pending +as `NotConnectedError`; `add_section` keeps the section registered, and the +next session restores it. + +`IncompatibleProtocolVersion` carries the peer's `revision` (the server's +`outdated-proto` says its own) and `peer_is_newer`. It stops a session; +`BatchClient(wait_for_server_update=True)` instead waits out an older +server, reconnecting every `SERVER_UPDATE_RETRY_S` (5 s) with its sections +still registered. A newer server still stops it: the client must be updated. + ## Batch subscription maps `_BatchClientReview` tracks: diff --git a/.agents/skills/edg-agent-temp-files/SKILL.md b/.agents/skills/edg-agent-temp-files/SKILL.md new file mode 100644 index 0000000000..52290118a5 --- /dev/null +++ b/.agents/skills/edg-agent-temp-files/SKILL.md @@ -0,0 +1,103 @@ +--- +name: edg-agent-temp-files +description: >- + Where agents put temporary files and directories (scratchpad, the project's + .tmp/agent-* directory, or the container's /tmp), how to share them with the + docker container via edg-exec, and how to run edgy ad hoc with --runs-dir + (and a scratch EDG_TEST_HOME) instead of edg-docker-test. Use when creating + scratch inputs or outputs, running throwaway tests or recordings, or cleaning + up temporary state. +--- + +# Temporary state and the docker boundary + +Tools run either on the host or in the docker container (`edg-exec`). The +container sees **only the project root**, mounted at `/edg/workspace`; the host +`/tmp` and your scratchpad are not visible to it. Project root = directory +containing `src/cfe.c` and `dev_tools/`. + +## Where to put temporary state + +| Need | Put it in | Notes | +| --- | --- | --- | +| Host-only (scripts, outputs of host tools) | your scratchpad directory | no permission prompts | +| Shared with the container | `/.tmp/agent-` | seen as `/edg/workspace/.tmp/agent-`; `.tmp/` is gitignored | +| Only needed inside the container | the container's `/tmp` | ephemeral, nothing is left on the host | + +- Everything you create in `.tmp/` **must** be named `agent-` (the + rest of `.tmp/` is the user's host-to-docker bridge; see `.tmp/README.md`). +- Do not use `build/`, `tests/runs/`, or the host `/tmp` for scratch state. +- Files created in the container are owned by the host user, so they are + directly usable from the host. + +## edg-exec rules + +- Run `edg-exec` from the project root (the current directory is mounted as + `/edg/workspace`). +- `edg-exec` joins its arguments with spaces and **does not preserve + quoting**: `edg-exec -- sh -c '. env.sh; cmd'` runs `sh -c .` and drops the + rest. Pass a compound command as ONE quoted string: + + ```bash + edg-exec -- "mkdir -p .tmp/agent-foo && echo hi > .tmp/agent-foo/x" + edg-exec --dry-run -- "..." # shows exactly what the container will run + ``` + +- `edgy` and the other `dev_tools/bin` tools are on the container `PATH`. + +## Running edgy outside the standard workflow + +`edg-docker-test` is for the standard front-end change workflow, where the +user wants results kept in `tests/runs/` (see **edg-cpfe-build-test**). For +anything else (experiments, verification of tooling, comparisons), run `edgy` +with `--runs-dir` so nothing lands in `tests/runs/`: + +```bash +# In docker: results appear on the host under .tmp/agent-foo/runs// +edg-exec -- ". build/gcc/environment.sh && edgy --runs-dir=/edg/workspace/.tmp/agent-foo/runs regressions/foo.sft.cpp" +``` + +- `. build//environment.sh` provides `CPFE`/`CPFE_CP`, which `edgy` uses + to find the front end (use the build directory you are testing). The default + configs need both `cpfe` and `cpfe-cp` built; `-c edg_x86_64` runs the C + config alone. +- Use an **absolute** container path for `--runs-dir`. `edgy` copies the front + end under the runs directory and a relative path breaks tools that change + directory (e.g. `cpfe-cp-gen-be` fails with "No such file or directory"). +- Host-side tools that take `--runs-dir` (e.g. `edg-rematerialize-test-run`) + have no docker constraint: point them at the scratchpad. +- If `edg-docker-test` is still used for a throwaway run, pass + `--discard-test-results` (results stay in the container's `/tmp`). + +## Scratch test home (for `-W` and other mutating experiments) + +`edg-docker-test` does not forward a host `EDG_TEST_HOME`, but setting it +**inside** the container command works. Build a small test home and point at +it; never run `-W` against the real tree: + +```bash +H=.tmp/agent-foo/home +mkdir -p $H/tests +cp -r tests/.edgy $H/.edgy +cp -r tests/expectations $H/expectations +cp -r tests/tests/ $H/tests/ # only the suites you need +CMD='. build/gcc/environment.sh && EDG_TEST_HOME=/edg/workspace/.tmp/agent-foo/home edgy --runs-dir=/edg/workspace/.tmp/agent-foo/runs /' +edg-exec -- "$CMD" # read-only first: logs must land under .tmp/agent-foo +edg-exec -- "${CMD/edgy /edgy -W }" # then record (expectations and .rto files in the scratch home only) +``` + +Check `git status --short tests` and that `tests/runs/` did not gain an entry. + +## Cleanup + +- Remove the `.tmp/agent-*` paths **you created** in a batch step as the LAST + step before reporting results to the user (not after each sub-task), in ONE + command that lists them (one approval instead of many): + + ```bash + rm -rf .tmp/agent-foo .tmp/agent-bar + ``` + +- Never glob other entries, never remove non-`agent-` names in `.tmp/`, and + do not delete `tests/runs/` content (it is gitignored and may be the user's). +- Say in the final summary what you created and removed. diff --git a/.agents/skills/edg-changes-example/SKILL.md b/.agents/skills/edg-changes-example/SKILL.md index 3ebe70f96f..e01da5d968 100644 --- a/.agents/skills/edg-changes-example/SKILL.md +++ b/.agents/skills/edg-changes-example/SKILL.md @@ -1,14 +1,16 @@ --- name: edg-changes-example description: >- - Encodes and decodes non-UTF-8 example bytes in Changes changelogs with - edg-changes-example («HHHH...» markers) and writes Changes files as UTF-8. - Use when editing any Changes file (src/Changes, util/Changes, …), adding + Writes Changes entries as pending_changes/*.txt files (collected + nightly by edg-collect-changes, checked with edg-collect-changes --check), + and encodes/decodes non-UTF-8 example bytes with edg-changes-example + («HHHH...» markers). Use when adding a Changes entry, editing any Changes + file (src/Changes, util/Changes, …) or pending_changes/ entry, adding examples with Latin-1/EUC-JP/Shift-JIS/other non-UTF-8 bytes, or verifying changelog encoding. --- -# `edg-changes-example` and Changes files +# Changes entries, `edg-collect-changes`, and `edg-changes-example` ## Policy (all `Changes` files) @@ -64,8 +66,9 @@ To rebuild the real example bytes (for local reproduction, not for commit): ```bash edg-changes-example decode utf8-fragment.txt > raw-fragment.txt edg-changes-example decode -o raw-fragment.txt utf8-fragment.txt -# Whole file: -edg-changes-example decode src/Changes > /tmp/Changes.raw +# Whole file (write host-only output to your scratchpad, see +# edg-agent-temp-files): +edg-changes-example decode src/Changes > /Changes.raw ``` Decode replaces each `«HHHH…»` (or legacy `«HH»«HH»`) with the corresponding @@ -73,7 +76,50 @@ bytes. No other escapes are interpreted. ## Workflow for a new changelog entry -1. Draft the entry as UTF-8 prose. +New entries are **not** written into a `Changes` file. Each `Changes` file +has a `pending_changes/` directory beside it (`src/pending_changes/`, +`util/pending_changes/`, …); add one entry file there per change, named +`*.txt` (suggested: `gh--.txt`). A nightly job +(`.github/workflows/collect-changes.yml`, midnight US Eastern) runs +`edg-collect-changes`, which moves every entry into its `Changes` file under +the newest `Version x.y` line, adds the date, orders that night's entries by +summary line, and deletes the entry files. + +Entry file format: + +```text +//allowed_words: reflectable memoized +[GH #335] +Type transformations of qualified function types + +Previously, the __add_lvalue_reference, __add_rvalue_reference, ... +For example, with --c++11: + + using F = void() const; + using F = __add_pointer(F); // Previously a spurious error, now okay. +``` + +- Optional leading `//key: value` directives (EDG C++ line directive + syntax). `//allowed_words:` lists space-separated words the spell check + should accept (identifiers, jargon); repeat the line as needed. Words the + target `Changes` file already uses (`constexpr`, `lvalue`, …) are accepted + without it. Directives are dropped when the entry is collected. +- The tag block: one or more comma-separated `GH #N` tags in brackets + (`[GH #12,GH #34]`; only `GH #N`, never `[]`). It may wrap onto several + lines; the tool re-wraps it the way existing entries are wrapped. +- **No date.** The tool adds it (`m/d/yy`, padded to 8 columns) in front of + the tags. +- The summary line, one blank line, then the description, in the same style + as existing entries (unindented prose wrapped at 79 columns, two spaces + after periods, examples indented 2 spaces). +- UTF-8, no tabs, at most **79** columns per line. Trailing whitespace is + tolerated (it's stripped on collection). + +Steps: + +1. Draft the entry as UTF-8 prose in + `/pending_changes/.txt` (the `pending_changes/` beside + the `Changes` file the entry belongs in, usually `src/`). 2. If an example needs non-UTF-8 bytes, author the example in a small raw file (or produce the markers by hand only when the bytes are already known), then run `edg-changes-example encode` and paste the UTF-8 result @@ -82,20 +128,39 @@ bytes. No other escapes are interpreted. `Note: The above example must be decoded using the edg-changes-example tool.` -4. Insert the entry into the appropriate `Changes` file with a **UTF-8** - write (keep the rest of the file valid UTF-8). -5. Verify the file still decodes as UTF-8 (raises on failure): +4. Check the entry (format, spelling, typos, line length). This is the + check `edg-check-file-changes` does for `pending_changes/*.txt` files, + which pull request CI runs and which makes the pre-push hook refuse the + push (no override) if anything is wrong: ```bash - python3 -c "open('path/to/Changes', encoding='utf-8').read()" + edg-exec -- edg-collect-changes --check src/Changes src/pending_changes ``` - Use the real path (for example `src/Changes`). A clean exit means the - whole file is valid UTF-8; a `UnicodeDecodeError` means the write - introduced non-UTF-8 bytes and must be fixed before continuing. + (Name the `Changes` file and `pending_changes/` directory the entry is + in. `edg-exec` runs it in the dev-env container, which has `aspell`.) For + misspellings that are really identifiers or terms, add them to an + `//allowed_words:` line at the very top of the entry, as the failure + message shows; fix real misspellings instead. `edgspelling.preprocess` + leaves an identifier like `getXValue` whole because it contains a + one-letter part. If aspell reports such an identifier whole, add the + whole identifier to `//allowed_words:`; adding only its parts (`get`, + `X`, `Value`) will not suppress the warning. +5. Optionally preview the result without changing anything: + `edg-collect-changes --dry-run src/Changes src/pending_changes`. + +Edit a `Changes` file directly only to correct an entry that has already +been collected; then write it as **UTF-8** and verify the file still decodes +(raises on failure): + +```bash +python3 -c "open('path/to/Changes', encoding='utf-8').read()" +``` ## Do not +- Add new entries directly to a `Changes` file, or put a date in a + `pending_changes/` entry. - Commit raw Latin-1 / Shift-JIS / etc. bytes inside a `Changes` file. - Invent alternate note wording; match the existing sentence above. - Run `encode` on the entire historical `src/Changes` and rewrite it unless diff --git a/.agents/skills/edg-cmakedef-build-config/SKILL.md b/.agents/skills/edg-cmakedef-build-config/SKILL.md new file mode 100644 index 0000000000..6de2545c02 --- /dev/null +++ b/.agents/skills/edg-cmakedef-build-config/SKILL.md @@ -0,0 +1,132 @@ +--- +name: edg-cmakedef-build-config +description: >- + Explains EDG macro/build configurations: the .cmakedef files under + cmake/macro-conf, the edg-cmakedef resolver, EDG_MACRO_CONF selection, and + CMakePresets.json. Use when adding or changing a macro for a build, creating + a new configuration or variant, finding out why a macro is (not) set, or + choosing a preset. For running builds and tests, use edg-cpfe-build-test. +--- + +# EDG cmakedef build configurations + +A **macro configuration** is a named set of `.cmakedef` files that decide +which preprocessor macros each binary is compiled with. CMake resolves them +with `dev_tools/bin/edg-cmakedef`. Project root = directory containing +`src/cfe.c` and `dev_tools/`. + +Source of truth (read these rather than trusting this summary): + +- `dev_tools/bin/edg-cmakedef` — the resolver / language. +- `cmake/macro-conf.cmake` — CMake glue. +- `cmake/host-defaults.cmake` — auto-selection when nothing is specified. +- `cmake/macro-conf/` — the configurations. +- `CMakePresets.json` — presets that pick a configuration. + +## The cmakedef language + +One statement per line; blank lines and `#` comments are ignored. + +| Line | Meaning | +| --- | --- | +| `NAME` | define `NAME` (emitted as `NAME=1` in `#define` output) | +| `NAME=value` | define with a value (may be empty) | +| `import ` | process `cmake/macro-conf/dir/file.cmakedef` here (root-relative, no extension) | +| `delete NAME` | remove a prior definition; **error** if not set | +| `delete_if_set NAME` | remove a prior definition; message only if not set | + +- Later lines override earlier ones (including across imports), so order + matters: import the base first, then add overrides. +- `@VAR@` in a value is expanded by CMake (`string(CONFIGURE)`). +- Any unparsable line or failing `delete` makes the file invalid; the + CMake configure then fails with "Failed to process cmakedef." + +## Layout of `cmake/macro-conf/` + +- `/.cmakedef`, one file per target. Targets and who reads + them: `base` (`src/CMakeLists.txt`, emitted as a generated + `cmake_defines.h` plus `USE_CMAKE_DEFINES`), `cpfe`, `cpfe-cp`, `cdisp` + (`src/cmake//CMakeLists.txt`) and `cpprtlib` + (`lib_src/CMakeLists.txt`); the last four become `-D` flags. +- `default/` — baseline each config imports first + (e.g. `default/cpfe` sets `BACK_END_IS_C_GEN_BE`, `DO_IL_LOWERING`). + `default/base.cmakedef` is a "should not be used" stub. +- `support/` — reusable fragments: `platform/`, `arch/`, `compiler/`, + `build-type/`, `simple-conf/`, `feature/` (`on`/`off`), `target/`. + Fragments are per-target too (e.g. `support/build-type/debug/cpfe`). +- Named configs (`linux-gcc`, `linux-gcc-release`, `linux-clang`, + `linux-i686-gcc`, `macos-arm-clang`, `windows-msvc`, …). Variants layer on + a parent: `linux-gcc-multi-thread-release/cpfe.cmakedef` imports + `` and then appends its own macros. +- A config directory missing a target file is auto-populated by CMake with + `import >`; don't rely on that for real configs. + +## Selection + +- Single-config generators (Ninja): cache var `EDG_MACRO_CONF`. +- Multi-config generators: `EDG_DEBUG_MACRO_CONF` and + `EDG_RELEASE_MACRO_CONF`. +- If empty, `host-defaults.cmake` picks one from OS, arch, compiler, and + build type (`detect_host_defaults`); otherwise CMake warns. +- Presets set it explicitly, e.g. `linux-gcc-debug` → + `EDG_MACRO_CONF=linux-gcc`, binary dir `build/gcc`. +- Every cmakedef file reached is added to `CMAKE_CONFIGURE_DEPENDS`, so + editing one re-runs configure on the next build. + +## Recipes + +Inspect what a config resolves to (host Python, read-only, no build): + +```bash +edg-cmakedef cmake/macro-conf linux-gcc/cpfe.cmakedef print-values +edg-cmakedef --verbose cmake/macro-conf linux-gcc/cpfe.cmakedef print-values +edg-cmakedef cmake/macro-conf linux-gcc/base.cmakedef print-defines +edg-cmakedef cmake/macro-conf linux-gcc/cpfe.cmakedef print-paths +``` + +- The target is resolved against the root if relative (CMake passes + absolute paths); never repeat the root in it. +- `print-values` → `NAME=value` lines; `print-defines` → `#ifndef/#define` + blocks (the `base` form); `print-paths` → the files visited. +- `--verbose` writes the import chain and each Setting / Overwriting / + Deleting step to **stderr**, which shows exactly which file last set a + macro. Use it to answer "why is X set?". +- Compare two configs by diffing the `print-values` output (sort first). + +Change a macro for one build: edit the narrowest file that covers it. +Shared by everything → `default/`; one platform / build type / +compiler → the matching `support/…` fragment; one named config or variant → +that config's `.cmakedef`. Check all targets that need it +(`base` vs `cpfe` vs `cpprtlib` are separate files). + +Add a new configuration: + +1. Copy the nearest sibling directory under `cmake/macro-conf/` with all + its target files; keep imports of `default/` and `support/` fragments. +2. If it is a variant, import the parent's file instead of copying it. +3. Add a preset to `CMakePresets.json` (inherit `linux-common` or the + platform's common preset; set `EDG_MACRO_CONF`, `binaryDir`). +4. If it should be auto-selected, add a branch in + `cmake/host-defaults.cmake` (and note release builds use the + `-release` directory). +5. Validate with the `print-values` recipe for every target, then + configure/build in Docker (see **edg-cpfe-build-test**): + + ```bash + edg-exec -- cmake --preset + edg-exec --wdir build/ -- ninja + ``` + +## Pitfalls + +- `import <…>` paths are relative to `cmake/macro-conf`, with no extension. +- `delete` of a never-set key fails the configure; use `delete_if_set` when + the key might legitimately be absent. +- A macro in a cmakedef only matters if the source consumes it; the generated + `cmake_defines.h` is only used when `USE_CMAKE_DEFINES` is set. Editing + `src/defines.h` (BUILD.md) does not change what a CMake configuration + produces. +- `print-paths` output order is unspecified (set iteration). +- Windows uses `dev_tools/win-bin/edg-cmakedef.bat`; the Python is + type-checked by `dev_tools/typecheck-python.sh` (follow + **edg-python-style** if editing the tool). diff --git a/.agents/skills/edg-cpfe-build-test/SKILL.md b/.agents/skills/edg-cpfe-build-test/SKILL.md index 4c5e95af74..33ffa7cdcd 100644 --- a/.agents/skills/edg-cpfe-build-test/SKILL.md +++ b/.agents/skills/edg-cpfe-build-test/SKILL.md @@ -24,6 +24,8 @@ edg-exec --wdir build/gcc -- ninja cpfe-cp # C++ → C++ from IL ``` - Default dirs: `build/gcc`, `bases/docker/dev-env/gcc` (`EDG_BASE`). +- Changing which macros a build uses (`cmake/macro-conf/*.cmakedef`, + `EDG_MACRO_CONF`, new presets): skill **edg-cmakedef-build-config**. - Clang: preset `linux-clang-debug` → `build/clang`. - Shell in container (cwd → `/edg/workspace`): `edg-exec` or `edg-docker-shell`. - If `src/defines.h` is swapped for reproduction, one binary may not build; @@ -45,7 +47,14 @@ edg-docker-test --dry-run rma - Postures: `day`, `night`, `quick-c-fe`, `extensive`, or `--posture=@file.json`. - Results: `tests/runs///` (e.g. `changes.elog`, `executed.elist`). Empty / no unexpected diffs means a clean match. -- Optional override: `EDG_TEST_HOME` (must contain `.edgy/config.json`). +- `edg-docker-test` is for the standard front-end change workflow, where the + user wants these results kept. For ad-hoc runs and experiments, use + `edgy --runs-dir` instead (skill **edg-agent-temp-files**); if you still use + `edg-docker-test` for a throwaway run, pass `--discard-test-results`. +- `EDG_TEST_HOME` (must contain `.edgy/config.json`) overrides the test home + but a host value is **not** forwarded into the container by + `edg-docker-test`; set it inside an `edg-exec` command string (see + **edg-agent-temp-files**). First-test walkthrough: [dev_annex/tutorials/FIRST_TEST.md](../../../dev_annex/tutorials/FIRST_TEST.md). @@ -63,6 +72,12 @@ First-test walkthrough: [dev_annex/tutorials/FIRST_TEST.md](../../../dev_annex/t that are gitignored. See edgy helpers in `dev_tools/pylibs/edgtest`. 4. Re-run without `-W` to confirm a clean match before asking to commit. +Expectations inherit like recordings: a non-default config's +`tests/expectations//.log` holds only differences from the +default config's (an explicit `...:PASS:` line overrides an inherited +failure). Record the default config first (`edgy -W` does this when both run). +See "Expectation Inheritance" in `doc/source/testing.rst`. + ## Finding a regressing or fixing commit Use skill **edg-cpfe-bisect** (`edg-docker-test-bisect` / diff --git a/.agents/skills/edg-cpfe-frontend/SKILL.md b/.agents/skills/edg-cpfe-frontend/SKILL.md index efd7da0233..0c16152b9d 100644 --- a/.agents/skills/edg-cpfe-frontend/SKILL.md +++ b/.agents/skills/edg-cpfe-frontend/SKILL.md @@ -45,15 +45,19 @@ Language: `--c++11` … `--c++26`. Emulation: `--gnu=XXYYZZ`, ## Editing `Changes` files -Write every `Changes` file as **UTF-8** (`src/Changes`, `util/Changes`, and -any other `Changes` in the tree). For non-UTF-8 example bytes, `«HHHH…»` -markers, the required note line, encode/decode commands, and verification, -follow skill **edg-changes-example** — do not invent a parallel procedure here. +Add new entries as `pending_changes/*.txt` files beside the `Changes` +file (usually `src/pending_changes/`), not in the `Changes` file itself; a +nightly job collects them with `edg-collect-changes`. Write everything as +**UTF-8**. For the entry format, `//allowed_words:`, `edg-collect-changes +--check`, non-UTF-8 example bytes (`«HHHH…»` markers and the note line), and +verification, follow skill **edg-changes-example** — do not invent a parallel +procedure here. ## Related skills - **edg-cpfe-style** — coding style; [code_style.rst](../../../doc/source/code_style.rst). -- **edg-changes-example** — UTF-8 Changes writes; `edg-changes-example` CLI. +- **edg-changes-example** — Changes entries (`pending_changes/`), UTF-8; + `edg-collect-changes` and `edg-changes-example` CLIs. - **edg-cpfe-build-test** — rebuild, `edg-docker-test`, recording. - **edg-cpfe-bisect** — `edg-docker-test-bisect` between good/bad commits. - Do not invent a separate defect-tracker workflow; use the project's current diff --git a/.agents/skills/edg-spelling-allowlist/SKILL.md b/.agents/skills/edg-spelling-allowlist/SKILL.md new file mode 100644 index 0000000000..a3af3dea04 --- /dev/null +++ b/.agents/skills/edg-spelling-allowlist/SKILL.md @@ -0,0 +1,126 @@ +--- +name: edg-spelling-allowlist +description: >- + How the pre-push spell check (edg-check-file-changes, aspell, edgspelling) + decides what to report, and how to add words to the hierarchical spelling + allowlist (dev_tools/spelling_allowlist.json). Use when the pre-push hook + or edg-collect-changes --check reports misspelled words, when choosing + where a new allowed word belongs, or when editing the allowlist file. +--- + +# Spell check and the spelling allowlist + +## How the check works + +The pre-push hook (`.git-hooks/pre-push.py`) runs +`dev_tools/bin/edg-check-file-changes` on every changed file, through +`edg-exec` when docker is preferred. Its spelling pass: + +- Runs `aspell list` on the text. For code files (`.c`, `.cpp`, `.h`, + `.hpp`) only the comments are checked (extracted with `get-comments`). + Other files are checked whole. +- First splits identifiers into words (`edgspelling.preprocess`): `fooBar` + becomes `foo Bar`. Underscores already split words, so `foo_bar` is + checked as `foo` and `bar`. +- Reports only words that are **new** relative to the old version of the + file, minus the allowlist words for that file's path. +- For pending Changes entries (`*/pending_changes/*.txt`), also accepts + the entry's `//allowed_words:` directives and any word already in the + target `Changes` file (see skill **edg-changes-example**). CI runs the + same check with `edg-collect-changes --check`. + +The hook skips some paths entirely (`EXCLUDES_PATH_PREFIXES` in +`.git-hooks/pre-push.py`), including `AGENTS.md`, `.agents/`, and the +allowlist itself. + +## The allowlist file + +`dev_tools/spelling_allowlist.json` is a tree of nodes. Each node may have: + +| Key | Meaning | +| --- | --- | +| `words` | Sorted lowercase words, allowed in any capitalization | +| `names` | Sorted words allowed only with exactly this capitalization | +| `paths` | Object mapping one path component (directory or file name) to a child node | + +A file's allowed words are the union of the nodes on the way down to it, so a +word in the root node is allowed everywhere. The format is documented in +`dev_tools/pylibs/edgspelling/__init__.py`. + +Rules that `edgspelling.Allowlist` enforces when the file loads (a bad +file makes the check refuse to run and fails `ShippedAllowlistTests` in CI): + +- Each list is sorted by code point and has no duplicates. +- `words` entries are lowercase. Use `names` when the capitalization must + match (proper nouns like `EDG` or `Coverity`). +- Only `words`, `names`, and `paths` keys are allowed. +- Each entry is one word. `foo_bar` or `fooBar` would never match, because + identifiers are split before lookup. Add the parts instead. + +## Choosing where a word goes + +Put a word in the **narrowest node** that covers the places it's used +often (see "Prompting is the default" below): + +- **Root:** terms used across the project (C++ terminology, `src`, `utf`). +- **A directory node** (`src`, `dev_tools`, `dev_tools/pylibs/edgtest`, + `doc/source`, …): jargon used only there. Common Python names like + `isinstance` and `pathlib`, and the pylib package names (`edgutil`, …), + live in `dev_tools`. The rare uses elsewhere (`dev-init.py`, + `.git-hooks/`, `doc/source/conf.py`) are left to prompt. + +A word used in only one file almost never earns an entry. The check +reports only words that are new to a file, so the entry would save a prompt +only when the word shows up in a second file. A word used only in a +`Changes` file never needs one, because pending entries already accept +every word in their target `Changes` file. +- **A file node:** a one-off term in a single file. + +### Prompting is the default + +Each allowed word is a blind spot: a typo that happens to match it is never +reported anywhere the entry applies. A broader node makes the blind spot +bigger. Being prompted again costs little, because the check reports only +words that are new to a file. Weigh the two: + +- Prefer leaving a word out and letting people be prompted. Add it only when + people would otherwise be prompted for it very often (for example, a term + used constantly across a directory or the project). +- When a word does earn an entry, choose the narrowest node that stops the + frequent prompts, even if rare uses elsewhere still prompt. For example, + the Python names are in `dev_tools` rather than at the root. +- Be most careful with short words and words that are one letter away from + a common English word (`len`, `str`, `dir`). They're the likeliest to hide + a real typo. + +Don't add a real misspelling. Fix the text. For a Changes entry, prefer an +`//allowed_words:` directive over a new allowlist word unless the term will +recur. + +## Editing the file + +Keep the existing formatting (one-space JSON indent, UTF-8, non-ASCII kept as +is). A Python round trip keeps it exact and keeps the lists sorted: + +```python +import json, pathlib +path = pathlib.Path('dev_tools/spelling_allowlist.json') +tree = json.loads(path.read_text(encoding = 'utf-8')) +tree['words'] = sorted(set(tree['words']) | {'newword'}) +# For a nested node: tree['paths']['src']['words'] = ... +path.write_text( + json.dumps(tree, indent = 1, ensure_ascii = False) + '\n', + encoding = 'utf-8' +) +``` + +Then check that the file still loads, and run the tests: + +```sh +PYTHONPATH=dev_tools/pylibs python3 -c 'import edgspelling; edgspelling.Allowlist()' +PYTHONPATH=dev_tools/pylibs python3 -m unittest discover -s dev_tools/tests \ + -p 'test_edg_check_file_changes.py' +``` + +To see what aspell rejects in some text: +`printf '%s\n' word1 word2 | aspell list`. diff --git a/.coderabbit.yaml b/.coderabbit.yaml new file mode 100644 index 0000000000..9248ab3df8 --- /dev/null +++ b/.coderabbit.yaml @@ -0,0 +1,7 @@ +# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json +reviews: + pre_merge_checks: + # Docstring coverage does not suit this codebase (C/C++ with + # prose-after-declarator comments), so the check is turned off. + docstrings: + mode: "off" diff --git a/.git-hooks/pre-push.py b/.git-hooks/pre-push.py index aba11c4a77..cb867f4b7d 100755 --- a/.git-hooks/pre-push.py +++ b/.git-hooks/pre-push.py @@ -36,35 +36,75 @@ import json import os import platform -import re import shutil import subprocess import sys import tempfile +import time +from pathlib import Path + +# Git invokes this hook with the ambient environment, which does not +# necessarily have PYTHONPATH configured (e.g., on Windows). Locate +# "dev_tools/pylibs" relative to this script so "edgutil" can be imported. +sys.path.insert( + 0, str(Path(__file__).resolve().parents[1] / 'dev_tools' / 'pylibs') +) +import edgchanges +import edgshell import edgutil -from pathlib import Path +START_TIME = time.monotonic() + +# The push isn't allowed to proceed until the hook has run for this long, so +# that there's time to read the target of the push and cancel it (e.g., with +# Ctrl-C) before it happens. +MIN_RUN_SECONDS = 3.0 + +def read_push_refs(): + '''Return the lines git supplied on standard input describing what is to be + pushed. A relaunched delegate (see below) can't read them from standard + input, so its parent passes them in the environment.''' + if os.environ.get('EDG_PREPUSH_DELEGATE') == '1': + refs_text = os.environ.get('EDG_PREPUSH_REFS', '') + elif sys.stdin.isatty(): + # Run by hand rather than by git. + refs_text = '' + else: + refs_text = sys.stdin.read() + return refs_text.splitlines() + +# Git supplies the remote name and location as arguments (both are the +# location if the push doesn't use a named remote). Read the refs before +# standard input is replaced below. +PUSH_REMOTE_NAME = sys.argv[1] if len(sys.argv) > 1 else None +PUSH_REMOTE_LOCATION = sys.argv[2] if len(sys.argv) > 2 else None +PUSH_REFS = read_push_refs() if platform.system() == 'Windows': - # On Windows we need to use the kernel API to detect if this script is - # running in a standalone console window (if so, there will be only one - # processes at this point). - import ctypes - - kernel32 = ctypes.WinDLL('kernel32', use_last_error = True) - process_array = (ctypes.c_uint * 2)() - num_processes = kernel32.GetConsoleProcessList(process_array, 2) - if num_processes != 1: - # When not running in a standalone console window, the script relaunches - # itself to make sure the user has an interactive shell. Then it forwards - # the exit code from the delegate process. + # The standard input of this hook carries the push ref list supplied by + # git, so it cannot be used to prompt the user. When a console is + # attached, open the console input device directly ("CONIN$" is the + # Windows counterpart of "/dev/tty") so that all prompts and output stay + # in the user's current terminal. + try: + sys.stdin = open('CONIN$', 'r') + except OSError: + # No console is attached (e.g., a GUI git client or a pseudo terminal + # such as mintty). Relaunch in a standalone console window so that the + # user can still respond to interactive prompts. delegate_proc = subprocess.run( [ sys.executable, - __file__ + __file__, + *sys.argv[1:] ], - creationflags = subprocess.CREATE_NEW_CONSOLE + creationflags = subprocess.CREATE_NEW_CONSOLE, + env = { + **os.environ, + 'EDG_PREPUSH_DELEGATE': '1', + 'EDG_PREPUSH_REFS': '\n'.join(PUSH_REFS) + } ) sys.exit(delegate_proc.returncode) else: @@ -88,7 +128,9 @@ 'src/error_msg.txt', # Don't check AGENT files. 'AGENTS.md', - '.agents/' + '.agents/', + # Don't check the spelling allowlist; it is made of words aspell rejects. + 'dev_tools/spelling_allowlist.json' ] def _is_excluded_file_path(path_str: str) -> bool: @@ -96,12 +138,33 @@ def _is_excluded_file_path(path_str: str) -> bool: path_str.startswith(prefix) for prefix in EXCLUDES_PATH_PREFIXES ) -COMMIT_SUBJECT_POLICY_REGEX = re.compile( - r'^.*\[(GH #[0-9]+|(EDG[cfjp]+fe/([0-9]+))|,)*\].*$' -) +def pause_delegate_window() -> None: + '''When running as a relaunch delegate, wait for the user before the + standalone console window closes so that failure output can be read.''' + if os.environ.get('EDG_PREPUSH_DELEGATE') != '1': + return + + try: + input('Push checks failed; press Enter to close this window. ') + except EOFError: + pass TOOL_PATH_GIT = shutil.which('git') +def find_dev_tool(name): + '''Return the path of the dev tool called name on PATH, or exit with an + error if the environment lacks it (e.g., direnv isn't applied).''' + tool_path = shutil.which(name) + if tool_path is None: + print( + f"error: the environment is missing the required tool '{name}'; " + 'put dev_tools/bin on PATH (e.g., via direnv) and push again.', + file = sys.stderr + ) + pause_delegate_window() + sys.exit(1) + return tool_path + def run_git(args, *, check = True, text = True): '''Run a git command and return the completed process.''' return subprocess.run( @@ -132,11 +195,43 @@ def git_show_blob(revision_path: str) -> bytes: return b'' return completed_process.stdout +ZERO_OBJECT_NAME_CHARS = set('0') + +def describe_push_ref(line): + '''Return a description of one of the ref lines git supplies to the hook + ( ), or None if line + isn't of that form.''' + fields = line.split() + if len(fields) != 4: + return None + local_ref, local_name, remote_ref, remote_name = fields + if set(local_name) <= ZERO_OBJECT_NAME_CHARS: + return f"delete {remote_ref}" + description = f"{local_ref} -> {remote_ref}" + if set(remote_name) <= ZERO_OBJECT_NAME_CHARS: + description += ' (new)' + return description + +def print_push_target(): + '''Print where the push is targeted.''' + if PUSH_REMOTE_NAME is None: + return + target = PUSH_REMOTE_NAME + if PUSH_REMOTE_LOCATION not in (None, PUSH_REMOTE_NAME): + target += f" ({PUSH_REMOTE_LOCATION})" + print(f"Pushing to {target}:\n") + for line in PUSH_REFS: + description = describe_push_ref(line) + if description is not None: + print(f" {description}") + print('') + class PrePushChecker: '''Runs EDG pre-push policy checks against new commits and changed files.''' def __init__(self): self.errors = 0 + self.abort = False def confirm_okay(self): '''Ask the user whether a policy warning is acceptable. @@ -159,7 +254,8 @@ def confirm_okay(self): return if response == 'q': self.errors = 1 - sys.exit(1) + self.abort = True + return print( "Please answer 'y' (to accept), 'n' (to continue check) or " @@ -168,15 +264,23 @@ def confirm_okay(self): tries += 1 if tries >= 10: print('Too many attempts.') - sys.exit(1) + self.errors = 1 + self.abort = True + return + + def reject(self): + '''Record a problem that can't be accepted, without asking.''' + print(' Not allowed: CI would reject this; fix it and push again.') + self.errors = 1 def check_commits(self): '''Walk commits until one already on a remote branch is found. As commits are walked, check to make sure they match formatting guidance. - Returns the oldest new commit hash, or None if there are no new commits. - Exits immediately if a commit subject fails the PR-number policy. + Returns the oldest new commit hash, or None if there are no new commits + (or if a commit subject fails the PR-number policy, in which case an + error is recorded and the check sequence is aborted). ''' first_new_commit = None @@ -195,12 +299,18 @@ def check_commits(self): print_indented(show_output, ' ') print('') - subject = git_output(['show', '--no-patch', '--format=%s', commit]) - if COMMIT_SUBJECT_POLICY_REGEX.match(subject) is None: - print( - " [POLICY] Commit message doesn't contain valid PR number (or [])." - ) - sys.exit(1) + # Read bytes: text mode would turn any \r into \n, hiding it from the + # check. Don't strip: that would also remove \r, \x0c, etc. at the ends + # of the message. + message = run_git( + ['show', '--no-patch', '--format=%B', commit], text = False + ).stdout.decode('utf-8', errors = 'replace') + problem = edgchanges.check_commit_message(message) + if problem is not None: + print(f" [POLICY] Commit message: {problem}.") + self.errors = 1 + self.abort = True + return None first_new_commit = commit @@ -212,9 +322,20 @@ def check_changed_files(self, first_new_commit): remote_head = f"{first_new_commit}~1" print('Checking changed files:') - changed_files = git_output( - ['diff', '--no-commit-id', '--name-only', '-r', f"{remote_head}..HEAD"] - ).splitlines() + # Use -z so that git doesn't C-quote paths with unusual characters (e.g., + # non-ASCII ones): the quoted form isn't a usable path. + changed_files = [ + path for path in run_git( + ['diff', '--no-commit-id', '--name-only', '-r', '-z', + f"{remote_head}..HEAD"] + ).stdout.split('\0') if path + ] + + # Binary files have no text to check, so don't extract them. Ask git + # rather than sniffing the contents so that .gitattributes is honored. + binary_files = edgshell.list_binary_files_in_git_diff( + f"{remote_head}..HEAD" + ) mono_repo_dir = edgutil.find_mono_repo_or_exit() containing_tmp_dir = mono_repo_dir / '.tmp' @@ -224,6 +345,8 @@ def check_changed_files(self, first_new_commit): for file_path_str in changed_files: if _is_excluded_file_path(file_path_str): continue + if file_path_str in binary_files: + continue file_path = Path(file_path_str) named_tmp_args = { @@ -258,7 +381,7 @@ def check_changed_files(self, first_new_commit): if use_docker: file_change_check_proc = subprocess.run( [ - shutil.which('edg-exec'), + find_dev_tool('edg-exec'), '--', 'edg-check-file-changes', str(input_file.relative_to(mono_repo_dir).as_posix()), @@ -270,7 +393,7 @@ def check_changed_files(self, first_new_commit): else: file_change_check_proc = subprocess.run( [ - shutil.which('edg-check-file-changes'), + find_dev_tool('edg-check-file-changes'), str(input_file), str(output_file) ], @@ -279,14 +402,39 @@ def check_changed_files(self, first_new_commit): ) if file_change_check_proc.returncode != 0: - sys.exit(1) + # Record the failure and return (rather than exiting) so that the + # status propagates through checker.run() and main(), allowing the + # delegate window pause to run. + self.errors = 1 + return with open(output_file, 'r') as file_handle: results = json.load(file_handle) for file_path_str, file_results in results.items(): + if self.abort: + break print(f" Checking file: {file_path_str}") + # A pending Changes entry with any of these problems fails the + # changes-fragments CI check, so there's no accepting them here. + is_changes_entry = edgchanges.is_fragment_path(file_path_str) + confirm_okay = ( + self.reject if is_changes_entry else self.confirm_okay + ) + + format_errors = [ + edgchanges.FormatError(*error) + for error in file_results['format_errors'] + ] + if len(format_errors) != 0: + print(' Badly formatted Changes entry:') + for error in format_errors: + print(f" - {edgchanges.describe_error(file_path_str, error)}") + confirm_okay() + if self.abort: + break + misspellings = file_results['misspellings'] if misspellings is None: print(' Spell check failed:') @@ -297,14 +445,24 @@ def check_changed_files(self, first_new_commit): print(' New misspelled words:') for misspelling in misspellings: print(f" - {misspelling}") - self.confirm_okay() + if is_changes_entry: + hint_lines = edgchanges.allowed_words_hint( + file_path_str, + misspellings + ) + print_indented('\n'.join(hint_lines), ' ') + confirm_okay() + if self.abort: + break typos = file_results['typos'] if len(typos) != 0: print(' New typos:') for typo in typos: print(f" - {typo}") - self.confirm_okay() + confirm_okay() + if self.abort: + break coding_errors = file_results['coding_errors'] if len(coding_errors) != 0: @@ -313,41 +471,74 @@ def check_changed_files(self, first_new_commit): print(f" Missing comment on #endif:") print_indented('\n'.join(endif_hits), ' ') self.confirm_okay() + if self.abort: + break else_hits = coding_errors['missing_elses'] if len(else_hits) != 0: print(f" Missing comment on #else:") print_indented('\n'.join(else_hits), ' ') self.confirm_okay() + if self.abort: + break closing_comments = coding_errors['closing_comments'] if len(closing_comments) != 0: print_indented('\n'.join(closing_comments), ' ') self.confirm_okay() + if self.abort: + break overlong_lines = file_results['overlong_lines'] if len(overlong_lines) != 0: - for line_no, (line_start, lines) in overlong_lines.items(): - print(f" Line {line_no} too long:") - line_end = line_start + (len(lines) - 1) - print(f" {line_start} -> {line_end} ".center(79, '=')) - for line in lines: - print(line, end = '') - print('=' * 79) - self.confirm_okay() - - def run(self) -> bool: - '''Execute the full pre-push check sequence.''' + for line in edgutil.format_overlong_lines(overlong_lines, ' '): + print(line) + confirm_okay() + if self.abort: + break + + def run(self) -> int: + '''Execute the full pre-push check sequence. Return the exit status.''' + print_push_target() first_new_commit = self.check_commits() # Skip per file checks if we didn't actually detect a new commit. - if first_new_commit is not None: + if not self.abort and first_new_commit is not None: self.check_changed_files(first_new_commit) - return self.errors == 0 + print('Checking documentation coverage for LLVM Backend...') + mono_repo_dir = edgutil.find_mono_repo_or_exit() + doc_check_proc = subprocess.run( + [sys.executable, 'dev_tools/check_doc_coverage.py', 'src/llvm_gen_be.cpp', 'src/llvm_gen_be_abi_aapcs64.cpp', 'src/llvm_gen_be_abi_arm32.cpp', 'src/llvm_gen_be_abi_loongarch64.cpp', 'src/llvm_gen_be_abi_mips.cpp', 'src/llvm_gen_be_abi_ppc64.cpp', 'src/llvm_gen_be_abi_riscv64.cpp', 'src/llvm_gen_be_abi_s390x.cpp', 'src/llvm_gen_be_abi_sparc.cpp', 'src/llvm_gen_be_abi_sysv_x86_64.cpp', 'src/llvm_gen_be_abi_wasm.cpp', 'src/llvm_gen_be_abi_win64.cpp', 'src/llvm_gen_be_abi_x86_32.cpp', 'src/llvm_gen_be_asm.cpp', 'src/llvm_gen_be_codegen.cpp', 'src/llvm_gen_be_const.cpp', 'src/llvm_gen_be_coro.cpp', 'src/llvm_gen_be_debug.cpp', 'src/llvm_gen_be_debug_scopes.cpp', 'src/llvm_gen_be_debug_types.cpp', 'src/llvm_gen_be_decl.cpp', 'src/llvm_gen_be_eh.cpp', 'src/llvm_gen_be_error.cpp', 'src/llvm_gen_be_expr.cpp', 'src/llvm_gen_be_omp.cpp', 'src/llvm_gen_be_opt.cpp', 'src/llvm_gen_be_ptrmem.cpp', 'src/llvm_gen_be_rtti.cpp', 'src/llvm_gen_be_stmt.cpp', 'src/llvm_gen_be_type.cpp', 'src/llvm_gen_be_vtable.cpp'], + cwd = mono_repo_dir + ) + if doc_check_proc.returncode != 0: + print(' [POLICY] LLVM Backend documentation coverage check failed.') + self.errors += 1 + + return 0 if (self.errors == 0 and not self.abort) else 1 + +def wait_for_minimum_run_time() -> None: + '''Sleep until the hook has been running for MIN_RUN_SECONDS.''' + remaining = MIN_RUN_SECONDS - (time.monotonic() - START_TIME) + if remaining > 0: + print(f"Pushing in {remaining:.0f}s (Ctrl-C to cancel)...") + time.sleep(remaining) + +def wait_for_minimum_run_time() -> None: + '''Sleep until the hook has been running for MIN_RUN_SECONDS.''' + remaining = MIN_RUN_SECONDS - (time.monotonic() - START_TIME) + if remaining > 0: + print(f"Pushing in {remaining:.0f}s (Ctrl-C to cancel)...") + time.sleep(remaining) def main(): checker = PrePushChecker() - sys.exit(0 if checker.run() else 1) + returncode = checker.run() + if returncode != 0: + pause_delegate_window() + else: + wait_for_minimum_run_time() + sys.exit(returncode) main() diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 0637bbc66d..0000000000 --- a/.gitattributes +++ /dev/null @@ -1,5 +0,0 @@ -/nt_util/Changes merge=union -/lib_src/Changes merge=union -/include_c++/Changes merge=union -/src/Changes merge=union -/util/Changes merge=union diff --git a/.github/DISCUSSION_TEMPLATE/issue-triage-compilation.yml b/.github/DISCUSSION_TEMPLATE/issue-triage-compilation.yml index ca75af1f06..5c50674039 100644 --- a/.github/DISCUSSION_TEMPLATE/issue-triage-compilation.yml +++ b/.github/DISCUSSION_TEMPLATE/issue-triage-compilation.yml @@ -1,3 +1,5 @@ +# Mirrored by .github/ISSUE_TEMPLATE/issue-triage-compilation.yml: keep the body: +# sections identical (dev_tools/bin/edg-check-issue-templates checks this). body: - type: textarea attributes: diff --git a/.github/DISCUSSION_TEMPLATE/issue-triage-general.yml b/.github/DISCUSSION_TEMPLATE/issue-triage-general.yml index eadb73f9f4..2157475df6 100644 --- a/.github/DISCUSSION_TEMPLATE/issue-triage-general.yml +++ b/.github/DISCUSSION_TEMPLATE/issue-triage-general.yml @@ -1,7 +1,10 @@ +# Mirrored by .github/ISSUE_TEMPLATE/issue-triage-general.yml: keep the body: +# sections identical, apart from links to the other form +# (dev_tools/bin/edg-check-issue-templates checks this). body: - type: markdown attributes: - value: Please use the [compilation issue triage](https://github.com/edgcpp/compiler/discussions/categories/compilation-issue-triage) for filing issues involving source code compilation (i.e., most issues). + value: Please use the [compilation issue triage](https://github.com/edgcpp/compiler/discussions/categories/issue-triage-compilation) for filing issues involving source code compilation (i.e., most issues). - type: textarea attributes: label: Issue Summary diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000000..1d94741cfd --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,14 @@ +# The issue template chooser. Collaborators may still open a blank issue (e.g. +# for a task or feature); everyone else can report problems through the +# Discussions triage categories. +blank_issues_enabled: true +contact_links: + - name: Compilation issue triage (Discussions) + url: https://github.com/edgcpp/compiler/discussions/categories/issue-triage-compilation + about: Report a compilation problem for triage if you can't file issues directly. + - name: General issue triage (Discussions) + url: https://github.com/edgcpp/compiler/discussions/categories/issue-triage-general + about: Report any other problem for triage if you can't file issues directly. + - name: Questions (Discussions) + url: https://github.com/edgcpp/compiler/discussions/categories/q-a + about: Ask questions about using or contributing to the project. diff --git a/.github/ISSUE_TEMPLATE/issue-triage-compilation.yml b/.github/ISSUE_TEMPLATE/issue-triage-compilation.yml new file mode 100644 index 0000000000..88f9c5cb33 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/issue-triage-compilation.yml @@ -0,0 +1,118 @@ +# Mirrors .github/DISCUSSION_TEMPLATE/issue-triage-compilation.yml: keep the +# body: sections identical (dev_tools/bin/edg-check-issue-templates checks +# this). +name: Compilation issue +description: The front end mis-compiles, rejects, accepts, or crashes on source code (most issues). +type: Bug +body: + - type: textarea + attributes: + label: Issue Summary + description: Provide a high level description of what you believe is going wrong and how it is impacting you. + placeholder: In rare instances when using lambdas inside of class templates, the front end refuses to instantiate the template. This code compiles fine with GCC and Clang. I had to adapt the code to work around the issue, but I prefer the implementation strategy I am sharing in this report. + validations: + required: true + - type: textarea + attributes: + label: Reproducing Source Code + description: | + Provide the source code reproducing the issue. + + *Please*: + 1. Reduce the translation unit to the smallest possible reproducing case. + 2. Upload the source code file(s) as a: `.cpp`, `.zip`, or `.tar.gz`. + 3. DO NOT paste a large code block here (a small legally-unencumbered code block is okay in place of an upload). + + > [!TIP] + > If you would like to reduce the issue but do not know how, checkout the [cvise](https://github.com/marxin/cvise/) project as this is VERY helpful for automatic issue reduction. Additionally, in many cases AI agents can successfully create a reduced test case (that is similar enough to still reproduce the problem) in a fraction of the time. + + > [!IMPORTANT] + > If this source code is not compatible with the [project license](https://edgcpp.org/LICENSE.txt), please include a LICENSE.txt file or license disclosure comment at the start of all relevant files. + placeholder: | + [reproducer.zip](https://github.com/user-attachments/files/...) + validations: + required: true + - type: input + attributes: + label: Command-line Options + description: Provide the command-line options needed for reproducing the problem. + placeholder: cpfe --c++26 test.cpp + validations: + required: true + - type: dropdown + attributes: + label: Type of Issue + options: + - | + [Front End] This code *SHOULD* compile with these options. + - | + [Front End] This code *SHOULD NOT* compile with these options. + - | + [Front End] I do not care but this code *CRASHES* the compiler. + - | + [Back End] There is a problem with the generated C code. + - | + [Back End] There is a problem with the generated C++ code. + validations: + required: true + - type: textarea + attributes: + label: Additional Details + description: Provide any additional clarifying details that might help us better understand what is currently happening and what you expect to happen. + placeholder: The generated C code does not compile with gcc 14. + - type: dropdown + attributes: + label: Reproducing (Standard) Configuration(s) + description: | + What CMake preset-based configurations have you observed reproducing this issue (if any)? + + > [!NOTE] + > While you can select any configuration you know to reproduce the problem, you do not need to check every configuration. + multiple: true + options: + - macos-arm-clang-debug + - macos-arm-clang-release + - macos-x86-clang-debug + - macos-x86-clang-multi-thread-debug + - macos-x86-clang-release + - linux-clang-debug + - linux-clang-lsp + - linux-clang-release + - linux-clang-debuggable-release + - linux-gcc-debug + - linux-i686-gcc-debug + - linux-gcc-multi-thread-debug + - linux-gcc-multi-thread-release + - linux-gcc-release + - linux-gcc-debuggable-release + - linux-gcc-reflection-release + - windows-msvc-debug + - windows-msvc-release + - type: textarea + attributes: + label: Reproducing (Non-standard) Configuration + description: | + If this problem does not reproduce in one of the above "standard" configurations, please provide the output obtained when using the `--dump_configuration` command-line option with the EDG front end you are using. + + > [!TIP] + > Consider contributing a new build & testing configuration to increase coverage and make it easier to report (and reproduce) any future issues. + placeholder: | + [config.txt](https://github.com/user-attachments/files/...) + - type: checkboxes + attributes: + label: "I acknowledge that:" + options: + - label: I have checked open issues and existing discussions before filing this report. + required: true + - label: The reproducing source code that I have provided does not depend on headers that I have not included with my submission. + required: true + - label: I have reduced the reproducing source code to the best of my ability. + required: true + - label: I have selected at least one standard configuration or uploaded a non-standard configuration dump. + required: true + - label: I understand code shared via this form is NOT confidential. + required: true + - label: I have permission to share the reproducing source code and grant permission for the project to use the source code (or derivatives of the source code) to create tests. + required: true + - label: I agree that any tests created using the reproducing source code (or deriatives of it) will be licensed under [project license](https://edgcpp.org/LICENSE.txt) unless I included a `LICENSE.txt` file in my `.zip` or `.tar.gz` upload. If I included a `LICENSE.txt` file, any tests created using the reproducing source code will be governed by the terms of the license I provided instead. + required: true diff --git a/.github/ISSUE_TEMPLATE/issue-triage-general.yml b/.github/ISSUE_TEMPLATE/issue-triage-general.yml new file mode 100644 index 0000000000..7f7ea6519b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/issue-triage-general.yml @@ -0,0 +1,43 @@ +# Mirrors .github/DISCUSSION_TEMPLATE/issue-triage-general.yml: keep the body: +# sections identical, apart from links to the other form +# (dev_tools/bin/edg-check-issue-templates checks this). +name: General issue +description: Tooling, build, documentation, or other problems not involving compiling source code. +type: Bug +body: + - type: markdown + attributes: + value: Please use the [compilation issue triage](https://github.com/edgcpp/compiler/issues/new?template=issue-triage-compilation.yml) for filing issues involving source code compilation (i.e., most issues). + - type: textarea + attributes: + label: Issue Summary + description: Provide a high level description of what you believe is going wrong and how it is impacting you. + placeholder: | + `edg-docker-test` is printing the incorrect host path for some of the log files when run on MacOS Monterey. This is making it difficult for me to test my changes. + validations: + required: true + - type: textarea + attributes: + label: Observed Behavior + description: Please provide the behavior observed. + placeholder: When I run `edg-docker-test` I see the following log lines printed ... note how the second log is printed with its container path rather than a host path. + validations: + required: true + - type: textarea + attributes: + label: Expected Behavior + description: Please provide a description of how you would like things to work. + placeholder: All printed paths should be host paths. + validations: + required: true + - type: textarea + attributes: + label: Additional Details + description: Provide any additional details that you think may be helpful. + placeholder: I tried setting EDG_DOCKER_HOST_PATHS to 1 explicity and that did not help. However, setting EDG_DOCKER_HOST_PATHS to 2 does print the host and container path as expected. This makes me think the issue is specific to setting EDG_DOCKER_HOST_PATHS to 1. + - type: checkboxes + attributes: + label: "I acknowledge that:" + options: + - label: I have checked open issues and existing discussions before filing this report. + required: true diff --git a/.github/codecov.yml b/.github/codecov.yml new file mode 100644 index 0000000000..6725491a68 --- /dev/null +++ b/.github/codecov.yml @@ -0,0 +1,55 @@ +# Part of the EDG Compiler Project, under the Apache License v2.0 with LLVM +# Exceptions. +# See https://edgcpp.org/LICENSE.txt for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# +# Codecov configuration (https://docs.codecov.com/docs/codecov-yaml). +# The coverage job of .github/workflows/build-and-test-ci.yml merges the +# reports of the test legs that ran and uploads them as a single report, so +# no upload count needs to be configured here. +# +# Only the nightly scheduled run on main tests every leg; other runs skip +# the legs whose results they can reuse, so their reports cover only part of +# the tests. Codecov therefore compares nothing: no comment, no status +# checks, and no annotations of uncovered lines. A pull request links to its +# report through the "coverage" commit status that the coverage job sets. + +codecov: + require_ci_to_pass: true + +coverage: + precision: 2 + round: down + range: "20...80" + status: + project: off + patch: off + changes: off + +comment: false + +github_checks: + annotations: false + +# Only src/ is reported (see the gcovr --filter in build-and-test-ci.yml); +# keep the rest of the tree out of Codecov's view even if a report includes +# it. +ignore: + - "benchmarks/**" + - "dev_tools/**" + - "tests/**" + - "util/**" + # Sources produced by dev_tools/bin/gen-ifc-map. + - '^src/ifc_map\.h$' + - '^src/ifc_map_functions\.c$' + - '^src/ifc_map_functions\.h$' + - '^src/ifc_map_functions_acc\.c$' + - '^src/ifc_map_functions_dbg\.c$' + - '^src/ifc_map_functions_mut\.c$' + - '^src/ifc_map_functions_val\.c$' + - '^src/ifc_modules_inst\.h$' + - '^src/ifc_modules_spec\.h$' + # Large generated data tables. + - '^src/unicode_name_fsm\.c$' + - '^src/builtin_defs\.h$' + - '^src/builtin_kinds\.h$' diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000..c0a62d9a4f --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,20 @@ +version: 2 + +multi-ecosystem-groups: + dev-tools: + schedule: + interval: "weekly" + +updates: + - package-ecosystem: "npm" + directory: "/dev_tools/services/acknowledg/client" + patterns: ["*"] + multi-ecosystem-group: "dev-tools" + + - package-ecosystem: "uv" + directories: + - "/dev_tools/services/acknowledg/server" + - "/dev_tools/services/acknowledg-forge/github" + - "/dev_tools/services/acknowledg-forge/gitlab" + patterns: ["*"] + multi-ecosystem-group: "dev-tools" diff --git a/.github/workflows/acknowledg-deploy.yml b/.github/workflows/acknowledg-deploy.yml new file mode 100644 index 0000000000..276dfc4f67 --- /dev/null +++ b/.github/workflows/acknowledg-deploy.yml @@ -0,0 +1,173 @@ +# Part of the EDG Compiler Project, under the Apache License v2.0 with LLVM +# Exceptions. +# See https://edgcpp.org/LICENSE.txt for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# +# Build and deploy AcknowlEDG over SSH. Two independent jobs: +# +# client builds the Vue client and rsyncs the static files into the web +# root. Nothing is restarted; browsers pick up the new files once +# their caches expire. +# server builds the server wheel, uploads it, and runs +# dev_tools/services/acknowledg/server/deploy-remote.sh on the host, +# which installs it and restarts the systemd unit only when the +# wheel's contents differ from what is already deployed. +# +# Host, paths, and credentials come from secrets in the `acknowledg` +# environment (see dev_tools/services/acknowledg/README.md). The SSH setup +# writes them into a `Host acknowledg` alias so they never appear on a command +# line. The public API URL is the ACKNOWLEDG_API_HOST repository variable, +# shared with acknowledg-forge-deploy.yml. + +name: AcknowlEDG Deploy + +on: + push: + branches: + - main + paths: + - dev_tools/services/acknowledg/** + - dev_tools/pylibs/edgacknowledg/** + # acknowledg-forge is a separate service. + - '!dev_tools/pylibs/edgacknowledg/forge/**' + - .github/workflows/acknowledg-deploy.yml + workflow_dispatch: + +concurrency: + group: acknowledg-deploy + cancel-in-progress: false + +permissions: + contents: read + +env: + ACKNOWLEDG_DIR: dev_tools/services/acknowledg + +jobs: + client: + name: Deploy client + if: github.ref == 'refs/heads/main' + runs-on: ubuntu-latest + timeout-minutes: 15 + environment: acknowledg + steps: + - name: Check out repository + uses: actions/checkout@v7 + with: + persist-credentials: false + + - name: Set up Node + uses: actions/setup-node@v7 + with: + node-version: '22' + cache: npm + cache-dependency-path: ${{ env.ACKNOWLEDG_DIR }}/client/package-lock.json + + - name: Build client + working-directory: ${{ env.ACKNOWLEDG_DIR }}/client + env: + VITE_EDG_ACKNOWLEDG_API_HOST: ${{ vars.ACKNOWLEDG_API_HOST }} + run: | + # The client opens `${VITE_EDG_ACKNOWLEDG_API_HOST}/review`; without + # a scheme the browser resolves that relative to the page instead. + case "${VITE_EDG_ACKNOWLEDG_API_HOST}" in + ws://?*|wss://?*) ;; + *) + echo '::error::ACKNOWLEDG_API_HOST must be a ws:// or wss:// URL' + exit 1 + ;; + esac + npm ci + npm run build + + - name: Configure SSH + env: + SSH_HOST: ${{ secrets.ACKNOWLEDG_SSH_HOST }} + SSH_USER: ${{ secrets.ACKNOWLEDG_SSH_USER }} + SSH_PORT: ${{ secrets.ACKNOWLEDG_SSH_PORT || '22' }} + SSH_PRIVATE_KEY: ${{ secrets.ACKNOWLEDG_SSH_PRIVATE_KEY }} + SSH_KNOWN_HOSTS: ${{ secrets.ACKNOWLEDG_SSH_KNOWN_HOSTS }} + run: &configure-ssh | + install -d -m 700 ~/.ssh + install -m 600 /dev/null ~/.ssh/deploy_key + printf '%s\n' "${SSH_PRIVATE_KEY}" > ~/.ssh/deploy_key + printf '%s\n' "${SSH_KNOWN_HOSTS}" > ~/.ssh/known_hosts + cat > ~/.ssh/config <> "${GITHUB_OUTPUT}" + echo "fingerprint=${fingerprint}" >> "${GITHUB_OUTPUT}" + + - name: Configure SSH + env: + SSH_HOST: ${{ secrets.ACKNOWLEDG_SSH_HOST }} + SSH_USER: ${{ secrets.ACKNOWLEDG_SSH_USER }} + SSH_PORT: ${{ secrets.ACKNOWLEDG_SSH_PORT || '22' }} + SSH_PRIVATE_KEY: ${{ secrets.ACKNOWLEDG_SSH_PRIVATE_KEY }} + SSH_KNOWN_HOSTS: ${{ secrets.ACKNOWLEDG_SSH_KNOWN_HOSTS }} + run: *configure-ssh + + - name: Install server + working-directory: ${{ env.ACKNOWLEDG_DIR }}/server + env: + SERVER_PATH: ${{ secrets.ACKNOWLEDG_SERVER_PATH }} + SERVICE_NAME: ${{ secrets.ACKNOWLEDG_SERVICE_NAME }} + WHEEL: ${{ steps.build.outputs.wheel }} + FINGERPRINT: ${{ steps.build.outputs.fingerprint }} + run: | + wheel_name=$(basename "${WHEEL}") + ssh acknowledg "mkdir -p $(printf '%q' "${SERVER_PATH}/incoming")" + rsync --checksum "${WHEEL}" "acknowledg:${SERVER_PATH}/incoming/" + ssh acknowledg "bash -s -- $(printf '%q ' \ + "${SERVER_PATH}" "${SERVICE_NAME}" "${wheel_name}" \ + "${FINGERPRINT}")" < deploy-remote.sh diff --git a/.github/workflows/acknowledg-forge-deploy.yml b/.github/workflows/acknowledg-forge-deploy.yml new file mode 100644 index 0000000000..bc6700e35a --- /dev/null +++ b/.github/workflows/acknowledg-forge-deploy.yml @@ -0,0 +1,140 @@ +# Part of the EDG Compiler Project, under the Apache License v2.0 with LLVM +# Exceptions. +# See https://edgcpp.org/LICENSE.txt for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# +# Publish the acknowledg-forge container image and deploy it: +# +# test the acknowledg-forge typecheck and tests (acknowledg-forge.yml) +# publish build the image (build-edg-env acknowledg-forge) and push it to +# ghcr.io/edgcpp/acknowledg-forge:latest (deployments use the +# pushed digest) +# deploy over SSH, run the host's deploy helper (an administrator- +# installed copy of +# dev_tools/services/acknowledg-forge/deploy-remote.py, the only +# thing the deploy user may run as root) to point the service at +# the pushed digest, set its AcknowlEDG API and UI URLs, and +# restart it (only if any of those changed) +# +# The image is public and holds no credentials or configuration: the publish +# job has no access to the deployment's secrets. Everything else about the +# service (its unit, tokens, API key) is configured on the host. +# +# Host, user, and SSH credentials come from secrets in the +# `acknowledg-forge` environment; the public AcknowlEDG URLs come from +# repository variables shared with acknowledg-deploy.yml (see +# dev_tools/services/acknowledg-forge/README.md). + +name: acknowledg-forge Deploy + +on: + push: + branches: + - main + paths: + # The image freezes all of dev_tools/bin and dev_tools/pylibs. + - dev_tools/bin/** + - dev_tools/pylibs/** + - dev_tools/services/acknowledg-forge/** + - dev_tools/docker/acknowledg-forge/** + - .github/workflows/acknowledg-forge.yml + - .github/workflows/acknowledg-forge-deploy.yml + workflow_dispatch: + +concurrency: + group: acknowledg-forge-deploy + cancel-in-progress: false + +permissions: + contents: read + +jobs: + test: + name: Test + if: github.ref == 'refs/heads/main' + uses: ./.github/workflows/acknowledg-forge.yml + + publish: + name: Publish image + needs: test + runs-on: ubuntu-latest + timeout-minutes: 30 + permissions: + contents: read + packages: write + outputs: + image: ${{ steps.push.outputs.image }} + steps: + - name: Check out repository + uses: actions/checkout@v7 + with: + persist-credentials: false + + - name: Set up uv + uses: astral-sh/setup-uv@v10.3.0 + + - name: Build image + env: + PYTHONPATH: ${{ github.workspace }}/dev_tools/pylibs + run: dev_tools/bin/build-edg-env --quiet acknowledg-forge + + - name: Push image + id: push + env: + REGISTRY_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + image=ghcr.io/edgcpp/acknowledg-forge + printf '%s' "${REGISTRY_TOKEN}" \ + | docker login ghcr.io --username "${GITHUB_ACTOR}" \ + --password-stdin + docker push --quiet "${image}:latest" + docker logout ghcr.io + digest="$(docker inspect \ + --format '{{range .RepoDigests}}{{println .}}{{end}}' \ + "${image}:latest" | grep "^${image}@sha256:" | head -n 1)" + echo "Pushed ${digest}" + echo "image=${digest}" >> "${GITHUB_OUTPUT}" + + deploy: + name: Deploy + needs: publish + runs-on: ubuntu-latest + timeout-minutes: 15 + environment: acknowledg-forge + steps: + - name: Configure SSH + env: + SSH_HOST: ${{ secrets.ACKNOWLEDG_FORGE_SSH_HOST }} + SSH_USER: ${{ secrets.ACKNOWLEDG_FORGE_SSH_USER }} + SSH_PORT: ${{ secrets.ACKNOWLEDG_FORGE_SSH_PORT || '22' }} + SSH_PRIVATE_KEY: ${{ secrets.ACKNOWLEDG_FORGE_SSH_PRIVATE_KEY }} + SSH_KNOWN_HOSTS: ${{ secrets.ACKNOWLEDG_FORGE_SSH_KNOWN_HOSTS }} + run: | + install -d -m 700 ~/.ssh + install -m 600 /dev/null ~/.ssh/deploy_key + printf '%s\n' "${SSH_PRIVATE_KEY}" > ~/.ssh/deploy_key + printf '%s\n' "${SSH_KNOWN_HOSTS}" > ~/.ssh/known_hosts + cat > ~/.ssh/config < / Test +# " (e.g., "linux-gcc-debug / Test edg_x86_64"). # # A shared run timestamp keeps results under the same tests/runs// # tree; the publish job republishes failure artifacts from all test legs. +# +# The builds set EDG_BUILD_IDENTIFIER so that identical sources produce +# byte-identical build products. Each test leg keys a cache entry on the +# SHA-256 of the products of its toolchain's uninstrumented build (which +# leaves out line numbers, so that changes that merely move code don't change +# the key; see the hash job in ci-toolchain.yml), the test files its +# configuration can read (edg-test-inputs-hash, so re-recording a test for +# one configuration doesn't invalidate the others), and the git trees of the +# other inputs it reads from the checkout (bases/, include_c++/, +# util/eccp.sh, and the workflow files, computed once by the prepare job). +# When a leg passes, it saves that entry; a later run on the same ref (a +# re-run, or a push that leaves the build products and test inputs +# unchanged) restores it and skips edgy, and so reports no coverage (the +# earlier run's coverage could point at lines that have since moved). +# Scheduled and manual runs reuse nothing (see reuse_results). +# actions/cache scopes entries to the ref that saved them (plus the default +# branch), so one pull request can never vouch for another's build. The +# merge queue's entries are saved again for main by promote-test-cache.yml +# once the commit they tested lands, so later pull requests can reuse them. +# +# The bench job runs the cachegrind benchmarks the way +# `edg-docker-bench --posture=release` does and uploads them as bench-results +# (c/ and cpp/ runs, for comparison against the checked-in +# benchmarks/baselines/project/release-{c,cpp}). +# +# The debug builds are instrumented for gcov (EDG_CPFE_USE_GCOV) and ship +# their .gcno files with the build products. Each test leg turns the .gcda +# files its run produces into a gcovr JSON report for src/; the coverage job +# merges the reports of the test legs that ran and uploads one report to +# Codecov (see .github/codecov.yml), which compares nothing and posts +# nothing on pull requests; a pull request links to its report through a +# "coverage" commit status. The nightly scheduled run tests every leg, so it +# gives main complete coverage. The coverage steps never fail the run; only +# edgy's results do. name: Build & Test CI on: - push: - branches: - - main pull_request: + merge_group: + # The nightly run tests every leg (no reused results), for complete + # coverage of main. + schedule: + - cron: '17 6 * * *' + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} + cancel-in-progress: true + +env: + GCOVR_VERSION: '8.7' jobs: prepare: @@ -34,6 +85,7 @@ jobs: timeout-minutes: 5 outputs: run_timestamp: ${{ steps.timestamp.outputs.run_timestamp }} + test_inputs: ${{ steps.test-inputs.outputs.test_inputs }} steps: - name: Declare shared edgy run timestamp id: timestamp @@ -41,170 +93,272 @@ jobs: # Match edgutil.RUN_TIMESTAMP_FORMAT (%Y.%m.%d-%H.%M.%S). echo "run_timestamp=$(date -u +'%Y.%m.%d-%H.%M.%S')" >> "${GITHUB_OUTPUT}" - build-gcc: - name: Build linux-gcc-debug - runs-on: ubuntu-latest - timeout-minutes: 120 - container: - image: docker.io/edgcpp/ci-runner:latest - defaults: - run: - shell: edg-container-exec "bash -eo pipefail {0}" - - steps: - - name: Check out repository + # Only the git trees are needed, so skip blobs and most of the + # working tree. + - name: Check out repository metadata uses: actions/checkout@v7 + with: + persist-credentials: false + filter: blob:none + sparse-checkout: .github - - name: Configure linux-gcc-debug - env: - EDG_BASE: ${{ github.workspace }}/bases/docker/dev-env/gcc - run: cmake --preset linux-gcc-debug + - name: Hash test inputs + id: test-inputs + run: | + # What the test legs read from the checkout, other than the build + # products and tests/ (which each leg hashes per configuration): + # EDG_BASE (whose include/ is include_c++/) and eccp. The workflow + # files cover the container image and the edgy options; edgy and + # the other tools come from that image, not from dev_tools/. + hash="$(git rev-parse HEAD:bases HEAD:include_c++ \ + HEAD:util/eccp.sh \ + HEAD:.github/workflows/build-and-test-ci.yml \ + HEAD:.github/workflows/ci-toolchain.yml | + sha256sum | cut -c1-64)" + echo "test_inputs=${hash}" >> "${GITHUB_OUTPUT}" + + # Each toolchain builds its preset and then tests each of its + # configurations (see ci-toolchain.yml), so its test legs wait only on its + # own build. The legs report as " / Test ". + toolchain: + name: ${{ matrix.preset }} + needs: prepare + strategy: + fail-fast: false + matrix: + include: + - preset: linux-gcc-debug + build_dir: build/gcc + base: gcc + configs: '["edg_x86_64", "edg_x86_64_cp"]' + - preset: linux-i686-gcc-debug + build_dir: build/gcc-i686 + base: gcc-i686 + configs: '["edg_x86_32", "edg_x86_32_cp"]' + uses: ./.github/workflows/ci-toolchain.yml + with: + preset: ${{ matrix.preset }} + build_dir: ${{ matrix.build_dir }} + base: ${{ matrix.base }} + configs: ${{ matrix.configs }} + run_timestamp: ${{ needs.prepare.outputs.run_timestamp }} + test_inputs: ${{ needs.prepare.outputs.test_inputs }} + reuse_results: >- + ${{ github.event_name == 'pull_request' || + github.event_name == 'merge_group' }} + + publish-test-results: + name: Publish aggregated test results + needs: + - prepare + - toolchain + # Republish whenever any test leg failed (partial artifacts may exist). + if: ${{ always() && needs.toolchain.result == 'failure' }} + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - name: Download partial test-result artifacts + uses: actions/download-artifact@v7 + with: + pattern: test-results-* + path: aggregated-test-results + merge-multiple: true - - name: Build linux-gcc-debug + # Record which commit was tested so consumers of the artifact (e.g. + # acknowledg-forge) can check out the matching tree. For pull requests + # this is the merge commit, not the PR head. + - name: Record CI metadata env: - EDG_BASE: ${{ github.workspace }}/bases/docker/dev-env/gcc - run: cmake --build build/gcc + TESTED_SHA: ${{ github.sha }} + HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }} + RUN_ID: ${{ github.run_id }} + RUN_ATTEMPT: ${{ github.run_attempt }} + run: | + python3 - > aggregated-test-results/ci-meta.json <<'EOF' + import json, os + print(json.dumps({ + 'tested_sha': os.environ['TESTED_SHA'], + 'head_sha': os.environ['HEAD_SHA'], + 'run_id': int(os.environ['RUN_ID']), + 'run_attempt': int(os.environ['RUN_ATTEMPT']), + }, indent = 2)) + EOF - # Runtime layout only: environment.sh / eccp need bin/, lib/, and the - # per-target lib_linux_* / lib_win* dirs (eccp rewrites ECCP_LIBDIR to - # lib_). lib_src is build-only and omitted. - - name: Upload build products + - name: Upload elist, elog, and .rt.tar.gz results uses: actions/upload-artifact@v7 with: - name: build-linux-gcc-debug - path: | - build/gcc/bin - build/gcc/lib - build/gcc/lib_linux_* - build/gcc/lib_win* - build/gcc/environment.sh - if-no-files-found: error - retention-days: 1 - compression-level: 6 + name: test-results-all + path: aggregated-test-results/ + if-no-files-found: warn + retention-days: 14 - build-i686: - name: Build linux-i686-gcc-debug + coverage-llvm: + name: LLVM Backend Code Coverage runs-on: ubuntu-latest - timeout-minutes: 120 + timeout-minutes: 60 container: image: docker.io/edgcpp/ci-runner:latest defaults: run: shell: edg-container-exec "bash -eo pipefail {0}" - steps: - name: Check out repository uses: actions/checkout@v7 - - name: Configure linux-i686-gcc-debug + - name: Configure CMake with coverage env: - EDG_BASE: ${{ github.workspace }}/bases/docker/dev-env/gcc-i686 - run: cmake --preset linux-i686-gcc-debug + EDG_BASE: ${{ github.workspace }}/bases/docker/dev-env/gcc + run: | + cmake --preset linux-gcc-debug \ + -DEDG_CPFE_USE_GCOV=TRUE \ + -DENABLE_LLVM_BACKEND=TRUE - - name: Build linux-i686-gcc-debug + - name: Build cpfe env: - EDG_BASE: ${{ github.workspace }}/bases/docker/dev-env/gcc-i686 - run: cmake --build build/gcc-i686 + EDG_BASE: ${{ github.workspace }}/bases/docker/dev-env/gcc + run: cmake --build build/gcc --target cpfe - - name: Upload build products - uses: actions/upload-artifact@v7 - with: - name: build-linux-i686-gcc-debug - path: | - build/gcc-i686/bin - build/gcc-i686/lib - build/gcc-i686/lib_linux_* - build/gcc-i686/lib_win* - build/gcc-i686/environment.sh - if-no-files-found: error - retention-days: 1 - compression-level: 6 + - name: Run LLVM Tests + env: + RUN_LLVM_LINK_TESTS: "1" + run: | + mkdir -p build/test_llvm_enabled/bin + cp build/gcc/bin/cpfe build/test_llvm_enabled/bin/ + ./tests/test_llvm_globals.sh + ./tests/test_llvm_functions.sh + ./tests/test_llvm_expressions.sh + ./tests/test_llvm_control_flow.sh + ./tests/test_llvm_output_generation.sh - test-gcc: - name: Test ${{ matrix.config }} - needs: - - prepare - - build-gcc - runs-on: ubuntu-latest - timeout-minutes: 360 - strategy: - fail-fast: false - matrix: - config: - - edg_x86_64 - - edg_x86_64_cp - container: - image: docker.io/edgcpp/ci-runner:latest - # Required for setarch ... -R (disable ASLR) used by the test harness. - options: --privileged - defaults: - run: - shell: edg-container-exec "bash -eo pipefail {0}" + - name: Check 100% Coverage for llvm_gen_be.cpp + run: | + cd build/gcc + gcov -r ../../src/llvm_gen_be.cpp + # Ensure coverage fails if not 100 + if ! grep -q "Lines executed:100.00% of" llvm_gen_be.cpp.gcov; then + echo "FAIL: llvm_gen_be.cpp does not have 100% code coverage." + cat llvm_gen_be.cpp.gcov + exit 1 + fi + echo "PASS: llvm_gen_be.cpp has 100% code coverage." + coverage: + name: Publish coverage to Codecov + needs: toolchain + # Like publish-test-results, merge whatever the test legs produced, + # whether or not their tests passed. The number of configs is not + # fixed: every coverage-* artifact is merged into one report and + # uploaded once. + if: ${{ !cancelled() }} + runs-on: ubuntu-latest + timeout-minutes: 30 + permissions: + contents: read + # To link a pull request to its coverage report. + statuses: write steps: - name: Check out repository uses: actions/checkout@v7 + with: + persist-credentials: false - - name: Download linux-gcc-debug build + - name: Download per-config coverage reports + continue-on-error: true uses: actions/download-artifact@v7 with: - name: build-linux-gcc-debug - # upload-artifact strips the shared build/gcc/ prefix, leaving - # bin/, lib/, and environment.sh at the artifact root. - path: build/gcc + pattern: coverage-* + path: coverage + merge-multiple: true - - name: Restore execute bits on build binaries + - name: Install gcovr + continue-on-error: true run: | - # Artifact round-trip does not reliably preserve +x. - chmod -R a+x build/gcc/bin + python3 -m venv "${RUNNER_TEMP}/gcovr" + "${RUNNER_TEMP}/gcovr/bin/pip" install --quiet \ + "gcovr==${GCOVR_VERSION}" - - name: Run edgy (${{ matrix.config }}) - env: - RUN_TIMESTAMP: ${{ needs.prepare.outputs.run_timestamp }} - CONFIG: ${{ matrix.config }} + - name: Merge coverage reports + if: ${{ hashFiles('coverage/*.json') != '' }} + continue-on-error: true run: | - mkdir -p .tmp - cat > .tmp/extensive-ci-edg-base.sh < .tmp/extensive-ci.edgivk <> "${GITHUB_STEP_SUMMARY}" + exit 0 + fi + url="https://app.codecov.io/gh/${GITHUB_REPOSITORY}/commit/${TESTED_SHA}" + echo "[Coverage report](${url}) of the test legs this run ran" \ + "(legs that reused earlier results add none)." \ + >> "${GITHUB_STEP_SUMMARY}" + if [ "${IS_PULL_REQUEST}" = true ]; then + gh api "repos/${GITHUB_REPOSITORY}/statuses/${HEAD_SHA}" \ + -f state=success -f context=coverage \ + -f description='Coverage of the tests this run ran' \ + -f target_url="${url}" > /dev/null + fi + + bench: + name: Benchmark linux-gcc-release + if: ${{ github.event_name == 'pull_request' }} + # Benchmark infrastructure problems shouldn't fail a pull request's CI. + continue-on-error: true runs-on: ubuntu-latest - timeout-minutes: 360 - strategy: - fail-fast: false - matrix: - config: - - edg_x86_32 - - edg_x86_32_cp + timeout-minutes: 120 container: - image: docker.io/edgcpp/ci-runner:latest - # Required for setarch ... -R (disable ASLR) used by the test harness. - options: --privileged + image: ghcr.io/edgcpp/ci-runner@sha256:565d7b6581912008ca91c5dbc940280c6e28a02c8cb6487d88ee5f0d7e8c51d7 defaults: run: shell: edg-container-exec "bash -eo pipefail {0}" @@ -212,75 +366,58 @@ jobs: steps: - name: Check out repository uses: actions/checkout@v7 - - - name: Download linux-i686-gcc-debug build - uses: actions/download-artifact@v7 with: - name: build-linux-i686-gcc-debug - # upload-artifact strips the shared build/gcc-i686/ prefix, leaving - # bin/, lib/, and environment.sh at the artifact root. - path: build/gcc-i686 + persist-credentials: false - - name: Restore execute bits on build binaries - run: | - # Artifact round-trip does not reliably preserve +x. - chmod -R a+x build/gcc-i686/bin + - name: Configure linux-gcc-release + env: + EDG_BASE: ${{ github.workspace }}/bases/docker/dev-env/gcc + run: cmake --preset linux-gcc-release - - name: Run edgy (${{ matrix.config }}) + - name: Build linux-gcc-release env: - RUN_TIMESTAMP: ${{ needs.prepare.outputs.run_timestamp }} - CONFIG: ${{ matrix.config }} + EDG_BASE: ${{ github.workspace }}/bases/docker/dev-env/gcc + run: cmake --build build/gcc-release --target cpfe cpfe-cp + + - name: Run benchmarks + env: + EDG_BASE: ${{ github.workspace }}/bases/docker/dev-env/gcc + EDG_BENCH_RUNS_KEPT: '0' run: | - mkdir -p .tmp - cat > .tmp/extensive-ci-edg-base.sh < .tmp/extensive-ci.edgivk < bench-results/ci-meta.json <<'EOF' + import json, os + print(json.dumps({ + 'tested_sha': os.environ['TESTED_SHA'], + 'head_sha': os.environ['HEAD_SHA'], + 'run_id': int(os.environ['RUN_ID']), + 'run_attempt': int(os.environ['RUN_ATTEMPT']), + }, indent = 2)) EOF - edg-prefix-env-loader .tmp/extensive-ci.edgivk - - - name: Upload partial elist, elog, and .rt.tar.gz results - if: ${{ failure() }} - uses: actions/upload-artifact@v7 - with: - name: test-results-${{ matrix.config }} - path: | - tests/runs/${{ needs.prepare.outputs.run_timestamp }}/**/*.elist - tests/runs/${{ needs.prepare.outputs.run_timestamp }}/**/*.elog - tests/runs/${{ needs.prepare.outputs.run_timestamp }}/**/*.rt.tar.gz - if-no-files-found: warn - retention-days: 1 - - publish-test-results: - name: Publish aggregated test results - needs: - - prepare - - test-gcc - - test-i686 - # Republish whenever any test leg failed (partial artifacts may exist). - if: >- - ${{ always() && - (needs.test-gcc.result == 'failure' || - needs.test-i686.result == 'failure') }} - runs-on: ubuntu-latest - timeout-minutes: 15 - steps: - - name: Download partial test-result artifacts - uses: actions/download-artifact@v7 - with: - pattern: test-results-* - path: aggregated-test-results - merge-multiple: true - - - name: Upload elist, elog, and .rt.tar.gz results + - name: Upload benchmark results uses: actions/upload-artifact@v7 with: - name: test-results-all - path: aggregated-test-results/ - if-no-files-found: warn + name: bench-results + path: bench-results/ + if-no-files-found: error retention-days: 14 diff --git a/.github/workflows/changes-fragments.yml b/.github/workflows/changes-fragments.yml new file mode 100644 index 0000000000..6a5acdc2e6 --- /dev/null +++ b/.github/workflows/changes-fragments.yml @@ -0,0 +1,72 @@ +# Part of the EDG Compiler Project, under the Apache License v2.0 with LLVM +# Exceptions. +# See https://edgcpp.org/LICENSE.txt for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# +# Check the pending Changes entries (*/pending_changes/*.txt) with +# `edg-collect-changes --check` (format, spelling, typos, line length), so a +# bad entry is caught before the nightly collect-changes job meets it. This +# checks the entries, not the tools; their unit tests are dev-tools-tests.yml. +# The tool paths below are triggers only so that a change to the checks is +# tried against the entries already pending. + +name: Pending Changes Entries + +on: + push: + branches: + - main + paths: + - '**/pending_changes/**' + - .github/workflows/changes-fragments.yml + - dev_tools/bin/edg-check-file-changes + - dev_tools/bin/edg-collect-changes + - dev_tools/pylibs/edgchanges/** + - dev_tools/pylibs/edgspelling/** + - dev_tools/pylibs/edgutil/** + - dev_tools/spelling_allowlist.json + pull_request: + paths: + - '**/pending_changes/**' + - .github/workflows/changes-fragments.yml + - dev_tools/bin/edg-check-file-changes + - dev_tools/bin/edg-collect-changes + - dev_tools/pylibs/edgchanges/** + - dev_tools/pylibs/edgspelling/** + - dev_tools/pylibs/edgutil/** + - dev_tools/spelling_allowlist.json + +permissions: + contents: read + +jobs: + check: + name: check-pending-changes + runs-on: ubuntu-latest + timeout-minutes: 10 + env: + PYTHONPATH: ${{ github.workspace }}/dev_tools/pylibs + # Each holds a Changes file and its pending_changes/ directory (keep in + # step with the list in collect-changes.yml). + CHANGES_DIRS: src util lib_src include_c++ nt_util + steps: + - name: Check out repository + uses: actions/checkout@v7 + with: + persist-credentials: false + + # The same dictionary as the dev-env image + # (dev_tools/docker/dev-env/setup-scripts/install-software.sh). + - name: Install aspell + run: | + sudo apt-get update + sudo apt-get install -y aspell aspell-en + + - name: Check pending Changes entries + run: | + status=0 + for dir in ${CHANGES_DIRS}; do + dev_tools/bin/edg-collect-changes --check \ + "${dir}/Changes" "${dir}/pending_changes" || status=1 + done + exit "${status}" diff --git a/.github/workflows/ci-toolchain.yml b/.github/workflows/ci-toolchain.yml new file mode 100644 index 0000000000..87cfdb7cd8 --- /dev/null +++ b/.github/workflows/ci-toolchain.yml @@ -0,0 +1,371 @@ +# Part of the EDG Compiler Project, under the Apache License v2.0 with LLVM +# Exceptions. +# See https://edgcpp.org/LICENSE.txt for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# +# Builds one toolchain's preset and tests it with each of its configurations. +# Called once per toolchain by build-and-test-ci.yml, which describes the +# overall job graph, the test cache, and coverage; each test leg waits only on +# this workflow's builds, so the toolchains are independent of one another. +# +# There is deliberately no concurrency group here: in a called workflow, +# github.workflow is the caller's name, so a group would make the toolchains +# cancel each other. The caller's group covers this workflow. + +name: CI Toolchain + +on: + workflow_call: + inputs: + preset: + description: The CMake preset to build (also names the build artifact) + required: true + type: string + build_dir: + description: The preset's build directory (e.g., build/gcc) + required: true + type: string + base: + description: The directory under bases/docker/dev-env/ for EDG_BASE + required: true + type: string + configs: + description: A JSON list of the edgy configurations to test + required: true + type: string + run_timestamp: + description: The edgy run timestamp shared by all test legs + required: true + type: string + test_inputs: + description: The hash of the test inputs (part of the test cache key) + required: true + type: string + reuse_results: + description: >- + Whether a test leg may skip its tests when an earlier run already + passed them (false runs every leg, e.g., for complete coverage) + required: false + type: boolean + default: true + +permissions: + contents: read + +# The steps refer to the inputs through these variables (in run scripts, as +# shell variables rather than expressions). +env: + GCOVR_VERSION: '8.7' + CI_PRESET: ${{ inputs.preset }} + CI_BUILD_DIR: ${{ inputs.build_dir }} + CI_BASE: ${{ inputs.base }} + +jobs: + build: + name: Build ${{ inputs.preset }} + runs-on: ubuntu-latest + timeout-minutes: 120 + container: + image: &ci-runner-image ghcr.io/edgcpp/ci-runner@sha256:565d7b6581912008ca91c5dbc940280c6e28a02c8cb6487d88ee5f0d7e8c51d7 + defaults: &container-defaults + run: + shell: edg-container-exec "bash -eo pipefail {0}" + + steps: + - name: Check out repository + uses: actions/checkout@v7 + with: + persist-credentials: false + + - name: Configure ${{ env.CI_PRESET }} + env: + EDG_BASE: ${{ github.workspace }}/bases/docker/dev-env/${{ env.CI_BASE }} + run: >- + cmake --preset "${CI_PRESET}" -DEDG_CPFE_USE_GCOV=ON + -DEDG_BUILD_IDENTIFIER=ci + + - name: Build ${{ env.CI_PRESET }} + env: + EDG_BASE: ${{ github.workspace }}/bases/docker/dev-env/${{ env.CI_BASE }} + run: cmake --build "${CI_BUILD_DIR}" + + # Runtime layout only: environment.sh / eccp need bin/, lib/, and the + # per-target lib_linux_* / lib_win* dirs (eccp rewrites ECCP_LIBDIR to + # lib_). lib_src is build-only and omitted. The .gcno files + # let the test legs produce coverage reports. + - name: Upload build products + uses: actions/upload-artifact@v7 + with: + name: build-${{ env.CI_PRESET }} + path: | + ${{ env.CI_BUILD_DIR }}/bin + ${{ env.CI_BUILD_DIR }}/lib + ${{ env.CI_BUILD_DIR }}/lib_linux_* + ${{ env.CI_BUILD_DIR }}/lib_win* + ${{ env.CI_BUILD_DIR }}/environment.sh + ${{ env.CI_BUILD_DIR }}/src/**/*.gcno + if-no-files-found: error + retention-days: 1 + compression-level: 6 + + # Builds the same preset again, without debug info, ASan, or gcov and with + # __LINE__ defined as 0, and hashes the products for the test cache key; + # the build itself is thrown away. The instrumented build can't serve for + # the key: its debug info, ASan's stack descriptions, gcov's checksums, the + # .gcno files, and the assertions' __LINE__ arguments all record line + # numbers, so changes that merely move code would change its products. + hash: + name: Hash ${{ inputs.preset }} + runs-on: ubuntu-latest + timeout-minutes: 120 + container: + image: *ci-runner-image + defaults: *container-defaults + outputs: + build_hash: ${{ steps.hash.outputs.build_hash }} + + steps: + - name: Check out repository + uses: actions/checkout@v7 + with: + persist-credentials: false + + # The Release build type leaves out the debug info (and ASan); the + # preset's macro configuration, which a single-configuration generator + # uses whatever the build type, keeps the front end's debug code, and + # -O0 replaces Release's optimization (and its -DNDEBUG, which the + # front end doesn't use). The -fmacro-prefix-map keeps __FILE__ + # relative, as the debug build types do (the step starts in the + # checkout, and pwd -P gives the path CMake records for it). + # + # __LINE__ is defined as 0 because the front end's assertions + # (check_assertion and the like in src/checking.h, compiled in whenever + # CHECKING is on, which is the default) pass __LINE__ to + # assertion_failed. Without this, every assertion below a line that is + # added or removed would pass a different line number, and the build + # products would change even though no code did. GCC warns about + # redefining __LINE__ even with -Wno-builtin-macro-redefined, so this + # build's warnings are turned off (-w); the build job still shows them. + - name: Configure ${{ env.CI_PRESET }} (uninstrumented) + env: + EDG_BASE: ${{ github.workspace }}/bases/docker/dev-env/${{ env.CI_BASE }} + run: >- + cmake --preset "${CI_PRESET}" -DCMAKE_BUILD_TYPE=Release + -DCMAKE_CXX_FLAGS_RELEASE=-O0 -DEDG_BUILD_IDENTIFIER=ci + "-DCMAKE_CXX_FLAGS=-D__LINE__=0 -w + -fmacro-prefix-map=$(pwd -P)=." + + - name: Build ${{ env.CI_PRESET }} (uninstrumented) + env: + EDG_BASE: ${{ github.workspace }}/bases/docker/dev-env/${{ env.CI_BASE }} + run: cmake --build "${CI_BUILD_DIR}" + + - name: Hash build products + id: hash + run: | + # Hash the names and contents of what the build job uploads (other + # than the .gcno files). + build="$(cd "${CI_BUILD_DIR}" && + find bin lib lib_linux_* lib_win* environment.sh \ + -type f -print0 | LC_ALL=C sort -z | + xargs -0 sha256sum | sha256sum | cut -c1-64)" + echo "Build products: ${build}" + echo "build_hash=${build}" >> "${GITHUB_OUTPUT}" + + test: + name: Test ${{ matrix.config }} + needs: [build, hash] + runs-on: ubuntu-latest + timeout-minutes: 360 + strategy: + fail-fast: false + matrix: + config: ${{ fromJSON(inputs.configs) }} + container: + image: *ci-runner-image + # Required for setarch ... -R (disable ASLR) used by the test harness. + options: --privileged + defaults: *container-defaults + + steps: + - name: Check out repository + uses: actions/checkout@v7 + with: + persist-credentials: false + + - name: Download ${{ env.CI_PRESET }} build + uses: actions/download-artifact@v7 + with: + name: build-${{ env.CI_PRESET }} + # upload-artifact strips the shared build directory prefix, leaving + # bin/, lib/, and environment.sh at the artifact root. + path: ${{ env.CI_BUILD_DIR }} + + - name: Restore execute bits on build binaries + run: | + # Artifact round-trip does not reliably preserve +x. + chmod -R a+x "${CI_BUILD_DIR}/bin" + + - name: Compute test cache key + id: key + env: + CONFIG: ${{ matrix.config }} + TEST_INPUTS: ${{ inputs.test_inputs }} + BUILD_HASH: ${{ needs.hash.outputs.build_hash }} + run: | + # Hash the test files this configuration can read, using the + # image's tools (like edgy itself, so the selection rules match). + # The helper reads git trees, and git refuses a repository owned + # by another user (the workspace belongs to the runner's user, not + # the container's) unless it is marked safe. + git config --global --add safe.directory "${GITHUB_WORKSPACE}" + tests="$(EDG_TEST_HOME="${GITHUB_WORKSPACE}/tests" \ + edg-test-inputs-hash --config "${CONFIG}")" + echo "Test files: ${tests}" + # The build products are represented by the hash job's hash of + # the uninstrumented build, not by the instrumented build tested + # here (see the hash job). + echo "Build products: ${BUILD_HASH}" + echo "key=tested-${CONFIG}-${TEST_INPUTS}-${tests}-${BUILD_HASH}" \ + >> "${GITHUB_OUTPUT}" + + - name: Look for an earlier passing run of this build + id: tested + if: ${{ inputs.reuse_results }} + uses: actions/cache/restore@v6 + with: + key: ${{ steps.key.outputs.key }} + path: .tmp/tested + + # A leg that reuses an earlier run contributes no coverage: that run + # may have tested different sources (the key ignores line numbers), so + # its coverage could point at the wrong lines. + - name: Reuse earlier results + if: ${{ steps.tested.outputs.cache-hit == 'true' }} + run: | + echo "::notice::This build already passed with the same test" \ + "inputs, so this leg reports no coverage:" \ + "$(cat .tmp/tested/ci-meta.json)" + + - name: Run edgy (${{ matrix.config }}) + id: edgy + if: ${{ steps.tested.outputs.cache-hit != 'true' }} + env: + RUN_TIMESTAMP: ${{ inputs.run_timestamp }} + CONFIG: ${{ matrix.config }} + run: | + mkdir -p .tmp + cat > .tmp/extensive-ci-edg-base.sh < .tmp/extensive-ci.edgivk < .tmp/tested/ci-meta.json <<'EOF' + import json, os + print(json.dumps({ + 'tested_sha': os.environ['TESTED_SHA'], + 'run_id': int(os.environ['RUN_ID']), + 'run_attempt': int(os.environ['RUN_ATTEMPT']), + 'cache_key': os.environ['CACHE_KEY'], + })) + EOF + + - name: Save record of this passing run + if: ${{ steps.record.outcome == 'success' }} + uses: actions/cache/save@v6 + with: + key: ${{ steps.key.outputs.key }} + path: .tmp/tested + + # A merge queue run's cache entries are visible only to its own + # temporary ref, so the record is also published for + # promote-test-cache.yml, which saves it again for main (where every + # pull request can see it) once the tested commit lands. + - name: Publish record for main + if: >- + ${{ steps.record.outcome == 'success' && + github.event_name == 'merge_group' }} + uses: actions/upload-artifact@v7 + with: + name: tested-record-${{ matrix.config }} + path: .tmp/tested + include-hidden-files: true + if-no-files-found: error + retention-days: 3 + overwrite: true diff --git a/.github/workflows/collect-changes.yml b/.github/workflows/collect-changes.yml new file mode 100644 index 0000000000..46eca99b78 --- /dev/null +++ b/.github/workflows/collect-changes.yml @@ -0,0 +1,135 @@ +# Part of the EDG Compiler Project, under the Apache License v2.0 with LLVM +# Exceptions. +# See https://edgcpp.org/LICENSE.txt for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# +# Nightly (midnight US Eastern) collection of the pending Changes entries: +# edg-collect-changes moves every /pending_changes/*.txt entry into +# /Changes, dated with the day that just ended, and this job commits and +# pushes the result to main. The directories are listed in CHANGES_DIRS +# below (keep it in step with the one in changes-fragments.yml). +# +# Malformed entries are left in place and fail the run (after the good ones +# are pushed), so they get noticed. +# +# One-time setup (repository/organization admin): +# +# 1. Create a GitHub App for the organization with only the "Contents: +# Read and write" repository permission, and install it on this +# repository only. +# 2. Add the repository secrets CHANGELOG_APP_CLIENT_ID (the App's client +# ID) and CHANGELOG_APP_PRIVATE_KEY (a private key generated for it). +# 3. Add the App to the bypass list of the ruleset protecting main, as +# "Always allow". (Classic branch protection doesn't document Apps as +# bypass actors; move main to a ruleset.) +# +# If an App isn't an option, a deploy key with write access can be the +# ruleset bypass actor instead: drop the token step and check out with +# `ssh-key: ${{ secrets.CHANGELOG_DEPLOY_KEY }}`. + +name: Collect Changes Entries + +on: + schedule: + - cron: '0 0 * * *' + timezone: 'America/New_York' + workflow_dispatch: + inputs: + date: + description: 'Date for the entries (YYYY-MM-DD; default: yesterday, US Eastern)' + required: false + default: '' + +permissions: + contents: read + +concurrency: + group: collect-changes + cancel-in-progress: false + +jobs: + collect: + name: collect-changes + runs-on: ubuntu-latest + timeout-minutes: 10 + env: + PYTHONPATH: ${{ github.workspace }}/dev_tools/pylibs + # Each holds a Changes file and its pending_changes/ directory. + CHANGES_DIRS: src util lib_src include_c++ nt_util + steps: + - name: Create App token + id: app + uses: actions/create-github-app-token@v3 + with: + client-id: ${{ secrets.CHANGELOG_APP_CLIENT_ID }} + private-key: ${{ secrets.CHANGELOG_APP_PRIVATE_KEY }} + permission-contents: write + + - name: Check out main + uses: actions/checkout@v7 + with: + ref: main + token: ${{ steps.app.outputs.token }} + + - name: Determine the entry date + id: date + env: + INPUT_DATE: ${{ inputs.date }} + run: | + # The day that just ended; a late start doesn't change it. + date="${INPUT_DATE:-$(TZ=America/New_York date -d yesterday +%F)}" + echo "date=${date}" >> "${GITHUB_OUTPUT}" + + - name: Collect pending Changes entries + id: collect + env: + ENTRY_DATE: ${{ steps.date.outputs.date }} + run: | + # A released newest version gets a new section for the version + # src/Changes has open. + status=0 + for dir in ${CHANGES_DIRS}; do + dev_tools/bin/edg-collect-changes \ + --date "${ENTRY_DATE}" --version-from src/Changes \ + "${dir}/Changes" "${dir}/pending_changes" || status=1 + done + echo "status=${status}" >> "${GITHUB_OUTPUT}" + + - name: Commit and push + env: + ENTRY_DATE: ${{ steps.date.outputs.date }} + APP_SLUG: ${{ steps.app.outputs.app-slug }} + GH_TOKEN: ${{ steps.app.outputs.token }} + run: | + # Stage the updated Changes files and the deleted entries. + for dir in ${CHANGES_DIRS}; do + git add -- "${dir}/Changes" "${dir}/pending_changes" + done + if git diff --cached --quiet; then + echo 'No pending Changes entries.' + exit 0 + fi + + bot_user_id="$(gh api "/users/${APP_SLUG}%5Bbot%5D" --jq .id)" + git config user.name "${APP_SLUG}[bot]" + git config user.email \ + "${bot_user_id}+${APP_SLUG}[bot]@users.noreply.github.com" + git commit -m "Collect pending Changes entries for ${ENTRY_DATE} []" + + # Retry if main moved on while this ran; a real conflict (e.g., a + # hand edit of a Changes file) stops the rebase and fails the job. + for attempt in 1 2 3; do + if git push origin HEAD:main; then + exit 0 + fi + git pull --rebase origin main + done + echo 'Could not push to main.' >&2 + exit 1 + + - name: Report malformed entries + if: steps.collect.outputs.status != '0' + run: | + echo 'edg-collect-changes left malformed entries in place; see the' \ + '"Collect pending Changes entries" step.' >&2 + exit 1 diff --git a/.github/workflows/commit-messages.yml b/.github/workflows/commit-messages.yml new file mode 100644 index 0000000000..29b48f351d --- /dev/null +++ b/.github/workflows/commit-messages.yml @@ -0,0 +1,72 @@ +# Part of the EDG Compiler Project, under the Apache License v2.0 with LLVM +# Exceptions. +# See https://edgcpp.org/LICENSE.txt for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# +# Check the messages of every pull request's commits and of every merge queue +# entry with edg-check-commit-messages (the same policy the pre-push hook +# applies, from edgchanges). Only commits with a violation are reported. +# +# A pull request is checked from its base commit to its head commit, and a +# merge queue entry from the branch it is merged into to its tip (so the +# commits the queue creates are checked too). Commits land on main only +# through the merge queue, so pushes to main are not checked again. +# +# The checker and the commits come from one checkout of github.sha, the same +# commit GitHub loads this workflow from. For a pull request that is the merge +# commit, so the checker is there even if the pull request's branch predates +# it. +# +# Merge commits are rejected too. A fork that wants them sets the repository +# variable ALLOW_MERGE_COMMITS to 'true' (Settings > Secrets and variables > +# Actions > Variables). + +name: Commit Messages + +on: + pull_request: + merge_group: + +permissions: + contents: read + +jobs: + check: + name: check-commit-messages + runs-on: ubuntu-latest + timeout-minutes: 10 + env: + PYTHONPATH: ${{ github.workspace }}/dev_tools/pylibs + steps: + - name: Check out repository + uses: actions/checkout@v7 + with: + # The checker is pull-request code; keep the token away from it. + # Nothing here needs authenticated git. + persist-credentials: false + fetch-depth: 0 + # Only commit messages are read, so skip the blobs and check out + # just the checker. + filter: blob:none + sparse-checkout: dev_tools + ref: ${{ github.sha }} + + - name: Check commit messages + env: + EVENT_NAME: ${{ github.event_name }} + PR_BASE_SHA: ${{ github.event.pull_request.base.sha }} + PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }} + QUEUE_BASE_SHA: ${{ github.event.merge_group.base_sha }} + QUEUE_HEAD_SHA: ${{ github.event.merge_group.head_sha }} + ALLOW_MERGE_COMMITS: ${{ vars.ALLOW_MERGE_COMMITS }} + run: | + if [[ "${EVENT_NAME}" == pull_request ]]; then + range=("${PR_BASE_SHA}..${PR_HEAD_SHA}") + else + range=("${QUEUE_BASE_SHA}..${QUEUE_HEAD_SHA}") + fi + options=() + if [[ "${ALLOW_MERGE_COMMITS}" == true ]]; then + options+=(--allow-merges) + fi + dev_tools/bin/edg-check-commit-messages "${options[@]}" "${range[@]}" diff --git a/.github/workflows/dev-tools-tests.yml b/.github/workflows/dev-tools-tests.yml new file mode 100644 index 0000000000..f83db9f7c9 --- /dev/null +++ b/.github/workflows/dev-tools-tests.yml @@ -0,0 +1,50 @@ +# Part of the EDG Compiler Project, under the Apache License v2.0 with LLVM +# Exceptions. +# See https://edgcpp.org/LICENSE.txt for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# +# Run the unit tests of the dev_tools (dev_tools/tests). Checking the pending +# Changes entries themselves is changes-fragments.yml. + +name: Dev Tools Tests + +on: + pull_request: + paths: + - .github/workflows/dev-tools-tests.yml + - dev_tools/bin/edg-check-commit-messages + - dev_tools/bin/edg-check-file-changes + - dev_tools/bin/edg-collect-changes + - dev_tools/pylibs/edgchanges/** + - dev_tools/pylibs/edgshell/** + - dev_tools/pylibs/edgspelling/** + - dev_tools/pylibs/edgutil/** + - dev_tools/spelling_allowlist.json + - dev_tools/tests/** + merge_group: + +permissions: + contents: read + +jobs: + unit-tests: + name: dev-tools-unit-tests + runs-on: ubuntu-latest + timeout-minutes: 10 + env: + PYTHONPATH: ${{ github.workspace }}/dev_tools/pylibs + steps: + - name: Check out repository + uses: actions/checkout@v7 + with: + persist-credentials: false + + # The same dictionary as the dev-env image + # (dev_tools/docker/dev-env/setup-scripts/install-software.sh). + - name: Install aspell + run: | + sudo apt-get update + sudo apt-get install -y aspell aspell-en + + - name: Run unit tests + run: python3 -m unittest discover -s dev_tools/tests -v diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 79799fd0e2..baebcd9b7e 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -6,10 +6,11 @@ # Build the Sphinx documentation in doc/ with warnings treated as errors, so # documentation changes stay publishable. # -# The build runs in the edgcpp/sphinx-env image, which the site workflow -# described below also builds the published documentation with. That image -# installs the packages pinned in doc/requirements.txt, so after changing -# them, rebuild it with build-edg-env sphinx-env and push it to Docker Hub. +# The build runs in the ghcr.io/edgcpp/sphinx-env image, which the site +# workflow described below also builds the published documentation with. +# That image installs the packages pinned in doc/requirements.txt, so after +# changing them, rebuild it with build-edg-env sphinx-env and push it to +# ghcr.io/edgcpp. # # The documentation is published by the edgcpp/edgcpp.github.io site # workflow, not from here: it builds the release tag into @@ -47,10 +48,12 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 15 container: - image: docker.io/edgcpp/sphinx-env:latest + image: ghcr.io/edgcpp/sphinx-env:latest steps: - name: Check out repository uses: actions/checkout@v7 + with: + persist-credentials: false # The published site uses the dirhtml builder, so check that one. - name: Build HTML diff --git a/.github/workflows/issue-templates.yml b/.github/workflows/issue-templates.yml new file mode 100644 index 0000000000..a5fcb9e6ce --- /dev/null +++ b/.github/workflows/issue-templates.yml @@ -0,0 +1,46 @@ +# Part of the EDG Compiler Project, under the Apache License v2.0 with LLVM +# Exceptions. +# See https://edgcpp.org/LICENSE.txt for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# +# Check that the issue forms (.github/ISSUE_TEMPLATE) and the discussion forms +# (.github/DISCUSSION_TEMPLATE) they mirror haven't drifted apart. + +name: Issue Templates + +on: + push: + branches: + - main + paths: + - .github/ISSUE_TEMPLATE/** + - .github/DISCUSSION_TEMPLATE/** + - .github/workflows/issue-templates.yml + - dev_tools/bin/edg-check-issue-templates + pull_request: + paths: + - .github/ISSUE_TEMPLATE/** + - .github/DISCUSSION_TEMPLATE/** + - .github/workflows/issue-templates.yml + - dev_tools/bin/edg-check-issue-templates + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + check: + name: check-issue-templates + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - name: Check out repository + uses: actions/checkout@v7 + with: + persist-credentials: false + + - name: Compare issue and discussion forms + run: python3 dev_tools/bin/edg-check-issue-templates diff --git a/.github/workflows/llvm_be_coverage.yml b/.github/workflows/llvm_be_coverage.yml new file mode 100644 index 0000000000..65cac553c0 --- /dev/null +++ b/.github/workflows/llvm_be_coverage.yml @@ -0,0 +1,38 @@ +name: LLVM Backend Coverage + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +jobs: + coverage: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y cmake llvm-14-dev clang-14 lcov valgrind + + - name: Run Tests with Coverage + run: | + export CXX=clang++-14 + export CC=clang-14 + OUTPUT=$(./dev_tools/bin/run_coverage.sh) + echo "$OUTPUT" + if ! echo "$OUTPUT" | grep -q "100%"; then + echo "Coverage is below strict 100% threshold!" + exit 1 + fi + + - name: Run Valgrind Tests + run: | + export CXX=clang++-14 + export CC=clang-14 + cmake -S . -B build/valgrind -DBUILD_TESTING=ON -DENABLE_LLVM_BACKEND=ON + cmake --build build/valgrind + cd build/valgrind + ctest -T memcheck diff --git a/.github/workflows/promote-test-cache.yml b/.github/workflows/promote-test-cache.yml new file mode 100644 index 0000000000..85f0784ee4 --- /dev/null +++ b/.github/workflows/promote-test-cache.yml @@ -0,0 +1,101 @@ +# Part of the EDG Compiler Project, under the Apache License v2.0 with LLVM +# Exceptions. +# See https://edgcpp.org/LICENSE.txt for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# +# Saves the test cache entries of the merge queue run that tested a commit +# again for main, once that commit lands there. +# +# Each test leg of build-and-test-ci.yml saves a cache entry when it passes, +# so that a later run whose build products and test inputs are the same can +# skip its tests. But actions/cache scopes an entry to the ref that saved it +# (plus the base and default branches), and the merge queue runs on a +# temporary gh-readonly-queue/... ref that nothing else can see, while +# nothing runs on main itself. So the merge queue's test legs also publish +# their records as tested-record- artifacts, and this workflow saves +# each one under its original key from main, where every pull request can +# restore it. Only commits that the merge queue tested and that then landed +# on main are promoted, so one pull request still can't vouch for another's +# build. +# +# A push the merge queue didn't test (e.g., from collect-changes.yml) has no +# such run and promotes nothing. + +name: Promote Test Cache + +on: + push: + branches: [main] + +permissions: + contents: read + # To find the merge queue run and download its artifacts. + actions: read + +jobs: + find: + name: Find merge queue records + runs-on: ubuntu-latest + timeout-minutes: 5 + outputs: + run_id: ${{ steps.find.outputs.run_id }} + records: ${{ steps.find.outputs.records }} + steps: + - name: Find the merge queue run of this commit + id: find + env: + GH_TOKEN: ${{ github.token }} + run: | + # The merge queue fast-forwards main to the commit it tested, so + # that run has this push's SHA. + run_id="$(gh api \ + "repos/${GITHUB_REPOSITORY}/actions/workflows/build-and-test-ci.yml/runs?event=merge_group&head_sha=${GITHUB_SHA}" \ + --jq '.workflow_runs[0].id // empty')" + records='[]' + if [ -n "${run_id}" ]; then + records="$(gh api --paginate \ + "repos/${GITHUB_REPOSITORY}/actions/runs/${run_id}/artifacts" \ + --jq '.artifacts[] | select(.name | startswith("tested-record-")) + | select(.expired | not) | .name' | + jq -cRs 'split("\n") | map(select(. != ""))')" + fi + echo "Merge queue run: ${run_id:-none}; records: ${records}" + echo "run_id=${run_id}" >> "${GITHUB_OUTPUT}" + echo "records=${records}" >> "${GITHUB_OUTPUT}" + + promote: + name: Promote ${{ matrix.record }} + needs: find + if: ${{ needs.find.outputs.records != '[]' }} + runs-on: ubuntu-latest + timeout-minutes: 10 + # The test legs' image, so that actions/cache picks the same compression + # (part of an entry's version) and the test legs can restore the entry. + container: + image: ghcr.io/edgcpp/ci-runner@sha256:565d7b6581912008ca91c5dbc940280c6e28a02c8cb6487d88ee5f0d7e8c51d7 + strategy: + fail-fast: false + matrix: + record: ${{ fromJSON(needs.find.outputs.records) }} + steps: + - name: Download ${{ matrix.record }} + uses: actions/download-artifact@v7 + with: + name: ${{ matrix.record }} + path: .tmp/tested + run-id: ${{ needs.find.outputs.run_id }} + github-token: ${{ github.token }} + + - name: Read the record's cache key + id: key + shell: bash + run: | + key="$(python3 -c 'import json, sys + print(json.load(sys.stdin)["cache_key"])' < .tmp/tested/ci-meta.json)" + echo "key=${key}" >> "${GITHUB_OUTPUT}" + + - name: Save the record for main + uses: actions/cache/save@v6 + with: + key: ${{ steps.key.outputs.key }} + path: .tmp/tested diff --git a/.github/workflows/strict-build-check.yml b/.github/workflows/strict-build-check.yml index 8fe66727b1..ebdb1f94ff 100644 --- a/.github/workflows/strict-build-check.yml +++ b/.github/workflows/strict-build-check.yml @@ -9,10 +9,15 @@ name: Strict Build Check on: - push: - branches: - - main pull_request: + merge_group: + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} + cancel-in-progress: true jobs: windows-msvc-release: @@ -22,6 +27,8 @@ jobs: steps: - name: Check out repository uses: actions/checkout@v7 + with: + persist-credentials: false - name: Install Ninja run: choco install ninja -y @@ -151,13 +158,15 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 120 container: - image: docker.io/edgcpp/ci-runner:latest + image: ghcr.io/edgcpp/ci-runner@sha256:565d7b6581912008ca91c5dbc940280c6e28a02c8cb6487d88ee5f0d7e8c51d7 defaults: run: shell: edg-container-exec "bash -eo pipefail {0}" steps: - name: Check out repository uses: actions/checkout@v7 + with: + persist-credentials: false - name: Configure linux-gcc-release env: @@ -176,13 +185,15 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 120 container: - image: docker.io/edgcpp/ci-runner:latest + image: ghcr.io/edgcpp/ci-runner@sha256:565d7b6581912008ca91c5dbc940280c6e28a02c8cb6487d88ee5f0d7e8c51d7 defaults: run: shell: edg-container-exec "bash -eo pipefail {0}" steps: - name: Check out repository uses: actions/checkout@v7 + with: + persist-credentials: false - name: Configure linux-gcc-debug env: @@ -201,13 +212,15 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 120 container: - image: docker.io/edgcpp/ci-runner:latest + image: ghcr.io/edgcpp/ci-runner@sha256:565d7b6581912008ca91c5dbc940280c6e28a02c8cb6487d88ee5f0d7e8c51d7 defaults: run: shell: edg-container-exec "bash -eo pipefail {0}" steps: - name: Check out repository uses: actions/checkout@v7 + with: + persist-credentials: false - name: Configure linux-clang-release env: @@ -226,13 +239,15 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 120 container: - image: docker.io/edgcpp/ci-runner:latest + image: ghcr.io/edgcpp/ci-runner@sha256:565d7b6581912008ca91c5dbc940280c6e28a02c8cb6487d88ee5f0d7e8c51d7 defaults: run: shell: edg-container-exec "bash -eo pipefail {0}" steps: - name: Check out repository uses: actions/checkout@v7 + with: + persist-credentials: false - name: Configure linux-clang-debug env: diff --git a/.github/workflows/typecheck-python.yml b/.github/workflows/typecheck-python.yml index 263e645543..a871d03b98 100644 --- a/.github/workflows/typecheck-python.yml +++ b/.github/workflows/typecheck-python.yml @@ -11,10 +11,15 @@ name: Python Typecheck on: - push: - branches: - - main pull_request: + merge_group: + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} + cancel-in-progress: true jobs: typecheck: @@ -42,6 +47,8 @@ jobs: steps: - name: Check out repository uses: actions/checkout@v7 + with: + persist-credentials: false - name: Set up Python ${{ matrix.python-version }} if: ${{ !matrix.use-docker }} diff --git a/.gitignore b/.gitignore index 4c0397994d..54ccae9e8c 100644 --- a/.gitignore +++ b/.gitignore @@ -66,3 +66,6 @@ cmake/macro-conf/*.cmakedef # AI tooling items to ignore: CLAUDE.md + +# macOS specific items to ignore: +*.DS_Store diff --git a/.tmp/README.md b/.tmp/README.md index cd3b791675..76a72de863 100644 --- a/.tmp/README.md +++ b/.tmp/README.md @@ -9,3 +9,20 @@ This allows for the host to pass non-trivial empherial information to Docker for further processing (that if packaged entirely as command line arguments would exceed the maximum command line argument limit -- primarily a problem on Windows). + +## Notes for Agents + +This section is an instruction for AI coding agents that come across this +file; it is not required reading for human users. + +Agents may use this directory for temporary files and directories that must be +visible both on the host and inside the docker container (the project root is +mounted at `/edg/workspace`, so `.tmp/agent-foo` on the host is +`/edg/workspace/.tmp/agent-foo` in the container). Everything an agent creates +here must be named `agent-` so it can be told apart from (and cleaned +up separately from) anything else in this directory. Agents remove these +temporary files and directories in a batch step as the last step before +reporting results to the user. + +See the `edg-agent-temp-files` skill (`.agents/skills/edg-agent-temp-files/`) +for the full rules. diff --git a/AGENTS.md b/AGENTS.md index 617311268d..74c548f3a1 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -48,7 +48,9 @@ the host toolchain for normal development; use `edg-exec` / [HACKING.md](HACKING.md). For full recipes (presets, filters, recording), read the project skill -**edg-cpfe-build-test**. For good/bad commit bisection, read +**edg-cpfe-build-test**. For macro/build configurations (`.cmakedef`, +`edg-cmakedef`, `EDG_MACRO_CONF`, presets), read +**edg-cmakedef-build-config**. For good/bad commit bisection, read **edg-cpfe-bisect**. Agent-friendly defaults: @@ -57,6 +59,10 @@ Agent-friendly defaults: - `edg-docker-test-bisect` — automatic regression/fix bisect (skill **edg-cpfe-bisect**; [TEST_BISECT.md](dev_annex/tutorials/TEST_BISECT.md)). +- Temporary files and directories: scratchpad for host-only state, + `.tmp/agent-` for anything the docker container must see, and + `edgy --runs-dir` (not `edg-docker-test`) for ad-hoc runs. See skill + **edg-agent-temp-files**. ## Source overview (`src/`) @@ -86,9 +92,21 @@ Hard always-on reminders (details in the RST / skill): ## Editing `Changes` files -Any `Changes` changelog in the tree (not only `src/Changes`) must be written -and kept as **valid UTF-8**. Prefer UTF-8 writes when adding or editing -entries. +New changelog entries go in `pending_changes/*.txt` files beside the +`Changes` file (e.g. `src/pending_changes/gh-123-short-slug.txt`), not +in the `Changes` file itself: tag block (`[GH #N]`, no date), summary line, +blank line, description; optional leading `//allowed_words: …` lines accept +words the spell check rejects (words already in the target `Changes` file +pass without them). A nightly job runs `edg-collect-changes` to +date them and move them into `Changes`. Check entries with +`edg-exec -- edg-collect-changes --check src/Changes src/pending_changes` +(for the directory in question). Edit a `Changes` file directly +only to correct an already-collected entry. Details: skill +**edg-changes-example**. + +Any `Changes` changelog in the tree (not only `src/Changes`) and every +pending entry must be written and kept as **valid UTF-8**. Prefer UTF-8 +writes when adding or editing entries. Examples that need non-UTF-8 bytes must use `edg-changes-example` (`«HHHH…»` markers) and the standard note line — see skill **edg-changes-example**. After @@ -124,10 +142,13 @@ If an agent does not auto-load skills, open the matching | Skill | Path | Load when | | --- | --- | --- | | `edg-cpfe-build-test` | [`.agents/skills/edg-cpfe-build-test/SKILL.md`](.agents/skills/edg-cpfe-build-test/SKILL.md) | Building, `edg-docker-test`, recording | +| `edg-agent-temp-files` | [`.agents/skills/edg-agent-temp-files/SKILL.md`](.agents/skills/edg-agent-temp-files/SKILL.md) | Temporary files/dirs, `.tmp/agent-*`, `edg-exec` quoting, ad-hoc `edgy --runs-dir`, scratch test homes | +| `edg-cmakedef-build-config` | [`.agents/skills/edg-cmakedef-build-config/SKILL.md`](.agents/skills/edg-cmakedef-build-config/SKILL.md) | Macro/build configurations, `.cmakedef` files, `edg-cmakedef`, presets | | `edg-cpfe-bisect` | [`.agents/skills/edg-cpfe-bisect/SKILL.md`](.agents/skills/edg-cpfe-bisect/SKILL.md) | Good/bad commit bisect for a test regression or fix | | `edg-cpfe-frontend` | [`.agents/skills/edg-cpfe-frontend/SKILL.md`](.agents/skills/edg-cpfe-frontend/SKILL.md) | Editing `src/`, IL/templates/overload, `Changes` | | `edg-cpfe-style` | [`.agents/skills/edg-cpfe-style/SKILL.md`](.agents/skills/edg-cpfe-style/SKILL.md) | Front-end coding style (`doc/source/code_style.rst`) | | `edg-python-style` | [`.agents/skills/edg-python-style/SKILL.md`](.agents/skills/edg-python-style/SKILL.md) | Python under `dev_tools/` (no formal RST; match in-tree) | -| `edg-changes-example` | [`.agents/skills/edg-changes-example/SKILL.md`](.agents/skills/edg-changes-example/SKILL.md) | Encoding non-UTF-8 examples in any `Changes` file | +| `edg-changes-example` | [`.agents/skills/edg-changes-example/SKILL.md`](.agents/skills/edg-changes-example/SKILL.md) | Adding a Changes entry (`pending_changes/`); encoding non-UTF-8 examples in any `Changes` file | +| `edg-spelling-allowlist` | [`.agents/skills/edg-spelling-allowlist/SKILL.md`](.agents/skills/edg-spelling-allowlist/SKILL.md) | Spell check reports from pre-push or `edg-collect-changes --check`; adding words to `dev_tools/spelling_allowlist.json` | | `acknowledg-client` | [`.agents/skills/acknowledg-client/SKILL.md`](.agents/skills/acknowledg-client/SKILL.md) | Batch/Direct client, reconnect, provider CLIs | | `acknowledg-bench` | [`.agents/skills/acknowledg-bench/SKILL.md`](.agents/skills/acknowledg-bench/SKILL.md) | `.cgout` / Ir / baselines / bench review | diff --git a/CMakeLists.txt b/CMakeLists.txt index f6ffff8dcf..b226994c77 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,6 +26,10 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) +# A generator expression that is true for the build types that generate +# debugging information (for use as "$<${EDG_HAS_DEBUG_INFO}:...>"). +set(EDG_HAS_DEBUG_INFO "$") + if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") if (UNIX AND NOT APPLE) @@ -33,8 +37,13 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR add_link_options("$<$:-static>") endif() # If we're building with GCC or any variant of Clang, use -g3 as our debug - # flag to include macro information in our debug builds. - add_compile_options("$<$:-g3>") + # flag to include macro information in builds with debugging information. + add_compile_options("$<${EDG_HAS_DEBUG_INFO}:-g3>") +endif() + +if (EDG_LLVM_BE_COVERAGE) + add_compile_options("-fprofile-instr-generate" "-fcoverage-mapping") + add_link_options("-fprofile-instr-generate" "-fcoverage-mapping") endif() # Attempt to determine the best linker @@ -49,8 +58,8 @@ if(NOT DEFINED EDG_PREFERRED_LINKER) endif() # Only use lld with Clang, it doesn't understand GCC's LTO format well (at - # least at the time of writing). - if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + # least at the time of writing). Do not use lld on Apple due to TAPI bugs. + if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND NOT APPLE) if(NOT DEFINED EDG_PREFERRED_LINKER_TRIAL) find_program(LLD_LINKER ld.lld NO_CACHE) if(NOT LLD_LINKER STREQUAL "LLD_LINKER-NOTFOUND") @@ -96,6 +105,27 @@ set(EDG_EAGER_REBUILD_LIB FALSE CACHE BOOL # Support for 32-bit build set(32BIT_BUILD FALSE CACHE BOOL "Build cpfe as a 32-bit executable") +# Support for reproducible builds. A build identifier replaces the build date +# and time in the front end (see src/CMakeLists.txt). +set(EDG_BUILD_IDENTIFIER "" CACHE STRING + "Build identifier to use in place of the build date and time") +if(NOT "$CACHE{EDG_BUILD_IDENTIFIER}" STREQUAL "" AND + (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR + CMAKE_CXX_COMPILER_ID MATCHES "Clang")) + # In builds with debugging information, record the source and build + # directories as relative paths in that information and in __FILE__, so the + # same sources produce the same executables wherever they are checked out + # and built. The build directory is listed last so that it takes precedence + # when it is inside the source directory. (-ffile-prefix-map is avoided + # because it also remaps the paths recorded for gcov, which coverage reports + # use to find the sources.) + add_compile_options( + "$<${EDG_HAS_DEBUG_INFO}:-fdebug-prefix-map=${CMAKE_SOURCE_DIR}=.>" + "$<${EDG_HAS_DEBUG_INFO}:-fmacro-prefix-map=${CMAKE_SOURCE_DIR}=.>" + "$<${EDG_HAS_DEBUG_INFO}:-fdebug-prefix-map=${CMAKE_BINARY_DIR}=build>" + "$<${EDG_HAS_DEBUG_INFO}:-fmacro-prefix-map=${CMAKE_BINARY_DIR}=build>") +endif() + # Detect the defaults (macro configuration, EDG_BASE, etc.) for this host and # compiler, used when a configuration doesn't specify them. include(${CMAKE_SOURCE_DIR}/cmake/host-defaults.cmake) @@ -145,3 +175,16 @@ include(${CMAKE_SOURCE_DIR}/cmake/wrapper.cmake) # Handle wrapping eccp, needed for building the C library, and general # development add_edg_wrapper_script(eccp "." ${CMAKE_SOURCE_DIR}/util/eccp.sh) + +if(BUILD_TESTING) + add_subdirectory(tests) +endif() +enable_testing() + +# 100% Doc Coverage Check for LLVM Backend +add_custom_target( + check_doc_coverage ALL + COMMAND ${Python3_EXECUTABLE} ${CMAKE_SOURCE_DIR}/dev_tools/check_doc_coverage.py + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + COMMENT "Verifying 100% LLVM backend Doxygen coverage..." +) diff --git a/CMakePresets.json b/CMakePresets.json index 2b28c6578c..9a5cf26954 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -324,6 +324,41 @@ "EDG_DEBUG_MACRO_CONF": "windows-msvc", "EDG_RELEASE_MACRO_CONF": "windows-msvc-release" } + }, + { + "name": "llvm-backend-debug", + "displayName": "LLVM Backend Debug", + "description": "Debug build of the EDG front end with the LLVM IR backend enabled.", + "binaryDir": "${sourceDir}/build/llvm-debug", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug", + "ENABLE_LLVM_BACKEND": "ON", + "BUILD_TESTING": "ON" + } + }, + { + "name": "llvm-backend-release", + "displayName": "LLVM Backend Release", + "description": "Release build of the EDG front end with the LLVM IR backend enabled.", + "binaryDir": "${sourceDir}/build/llvm-release", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release", + "ENABLE_LLVM_BACKEND": "ON", + "BUILD_TESTING": "ON" + } + }, + { + "name": "llvm-backend-coverage", + "displayName": "LLVM Backend Coverage", + "description": "Coverage-instrumented build of the EDG LLVM IR backend and test suite.", + "binaryDir": "${sourceDir}/build/llvm-coverage", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug", + "ENABLE_LLVM_BACKEND": "ON", + "BUILD_TESTING": "ON", + "EDG_LLVM_BE_COVERAGE": "ON", + "EDG_BUILD_LIB": "OFF" + } } ] } diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 91d0753e5f..53ddcf7e6b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -104,8 +104,9 @@ implementation characeristics). - [ ] You've put effort into maintaining code quality: - [ ] Your code is formatted in "EDG Style". - [ ] Your code has good comments. - - [ ] Your code has a Changes entry (not needed for `dev_tools` or build - system changes). + - [ ] Your code has a [Changes entry](#changes-entries) in + `pending_changes/` (not needed for `dev_tools` or build system + changes). - [ ] You used `edg-docker-test`: - [ ] You have added tests (or there are existing tests) that FAIL before your change but PASS after your change. @@ -114,6 +115,31 @@ implementation characeristics). - [ ] You've updated the default recordings after reviewing differences with `edg-docker-test -W`. +### Changes Entries + +The project includes a number of `Changes` files (effectively changelog/NEWS +files). Due to the number of concurrent changes, it has become impractical to +directly maintain the `Changes` files (particularly `src/Changes`). + +Instead, there is a nightly job that updates the `Changes` files for all the +work that happened over the last 24-hours. To take advantage, add a file +named `.txt` (e.g., `gh-335-qualified-function-types.txt`) +to the `pending_changes/` directory beside the `Changes` file your work belongs +with: + +```text +[GH #335] +Type transformations of qualified function types + +Previously, the __add_lvalue_reference, __add_rvalue_reference, __add_pointer, +and __decay intrinsics produced incorrect types for function types with cv- or +ref-qualifiers. They now leave such types unchanged. For example, with +--c++11: + + using F = void() const; + using F = __add_pointer(F); // Previously a spurious error, now okay. +``` + ### Early Design Feedback Please use the open issue for discussion about the proposed design if diff --git a/Doxyfile.llvm_be b/Doxyfile.llvm_be new file mode 100644 index 0000000000..6bedaf9503 --- /dev/null +++ b/Doxyfile.llvm_be @@ -0,0 +1,3003 @@ +# Doxyfile 1.18.0 + +# This file describes the settings to be used by the documentation system +# Doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" "). +# +# Note: +# +# Use Doxygen to compare the used configuration file with the template +# configuration file: +# doxygen -x [configFile] +# Use Doxygen to compare the used configuration file with the template +# configuration file without replacing the environment variables or CMake type +# replacement variables: +# doxygen -x_noenv [configFile] + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the configuration +# file that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# https://www.gnu.org/software/libiconv/ for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = "My Project" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewers a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = + +# With the PROJECT_ICON tag one can specify an icon that is included in the tabs +# when the HTML document is shown. Doxygen will copy the logo to the output +# directory. + +PROJECT_ICON = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where Doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = .tmp/doxygen + +# If the CREATE_SUBDIRS tag is set to YES then Doxygen will create up to 4096 +# sub-directories (in 2 levels) under the output directory of each output format +# and will distribute the generated files over these directories. Enabling this +# option can be useful when feeding Doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise cause +# performance problems for the file system. Adjust CREATE_SUBDIRS_LEVEL to +# control the number of sub-directories. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# Controls the number of sub-directories that will be created when +# CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every +# level increment doubles the number of directories, resulting in 4096 +# directories at level 8 which is the default and also the maximum value. The +# sub-directories are organized in 2 levels, the first level always has a fixed +# number of 16 directories. +# Minimum value: 0, maximum value: 8, default value: 8. +# This tag requires that the tag CREATE_SUBDIRS is set to YES. + +CREATE_SUBDIRS_LEVEL = 8 + +# If the ALLOW_UNICODE_NAMES tag is set to YES, Doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by Doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian, +# Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English +# (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek, +# Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with +# English messages), Korean, Korean-en (Korean with English messages), Latvian, +# Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, +# Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, +# Swedish, Turkish, Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES, Doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, Doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, Doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES, Doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which Doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where Doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, Doxygen will generate much shorter (but +# less readable) file names. This can be useful if your file system doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen will interpret the +# first line (until the first dot, question mark or exclamation mark) of a +# Javadoc-style comment as the brief description. If set to NO, the Javadoc- +# style will behave just like regular Qt-style comments (thus requiring an +# explicit @brief command for a brief description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = NO + +# If the JAVADOC_BANNER tag is set to YES then Doxygen will interpret a line +# such as +# /*************** +# as being the beginning of a Javadoc-style comment "banner". If set to NO, the +# Javadoc-style will behave just like regular comments and it will not be +# interpreted by Doxygen. +# The default value is: NO. + +JAVADOC_BANNER = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will interpret the first +# line (until the first dot, question mark or exclamation mark) of a Qt-style +# comment as the brief description. If set to NO, the Qt-style will behave just +# like regular Qt-style comments (thus requiring an explicit \brief command for +# a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# By default Python docstrings are displayed as preformatted text and Doxygen's +# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the +# Doxygen's special commands can be used and the contents of the docstring +# documentation blocks is shown as Doxygen documentation. +# The default value is: YES. + +PYTHON_DOCSTRING = YES + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES then Doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:^^" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". Note that you cannot put \n's in the value part of an alias +# to insert newlines (in the resulting output). You can put ^^ in the value part +# of an alias to insert a newline as if a physical newline was in the original +# file. When you need a literal { or } or , in the value part of an alias you +# have to escape them by means of a backslash (\), this can lead to conflicts +# with the commands \{ and \} for these it is advised to use the version @{ and +# @} or use a double escape (\\{ and \\}) + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice +# sources only. Doxygen will then generate output that is more tailored for that +# language. For instance, namespaces will be presented as modules, types will be +# separated into more groups, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_SLICE = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by Doxygen: IDL, Java, JavaScript, +# Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice, +# VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: +# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser +# tries to guess whether the code is fixed or free formatted code, this is the +# default for Fortran type files). For instance to make Doxygen treat .inc files +# as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by Doxygen. When specifying no_extension you should add +# * to the FILE_PATTERNS. +# +# Note see also the list of default file extension mappings. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then Doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See https://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by Doxygen, so you can +# mix Doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# If the MARKDOWN_STRICT tag is enabled then Doxygen treats text in comments as +# Markdown formatted also in cases where Doxygen's native markup format +# conflicts with that of Markdown. This is only relevant in cases where +# backticks are used. Doxygen's native markup style allows a single quote to end +# a text fragment started with a backtick and then treat it as a piece of quoted +# text, whereas in Markdown such text fragment is treated as verbatim and only +# ends when a second matching backtick is found. Also, Doxygen's native markup +# format requires double quotes to be escaped when they appear in a backtick +# section, whereas this is not needed for Markdown. +# The default value is: YES. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +MARKDOWN_STRICT = YES + +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 6. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 6 + +# The MARKDOWN_ID_STYLE tag can be used to specify the algorithm used to +# generate identifiers for the Markdown headings. Note: Every identifier is +# unique. +# Possible values are: DOXYGEN use a fixed 'autotoc_md' string followed by a +# sequence number starting at 0 and GITHUB use the lower case version of title +# with any whitespace replaced by '-' and punctuation characters removed. +# The default value is: DOXYGEN. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +MARKDOWN_ID_STYLE = DOXYGEN + +# When enabled Doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. Words listed in the +# AUTOLINK_IGNORE_WORDS tag are excluded from automatic linking. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# This tag specifies a list of words that, when matching the start of a word in +# the documentation, will suppress auto links generation, if it is enabled via +# AUTOLINK_SUPPORT. This list does not affect links explicitly created using # +# or the \link or \ref commands. +# This tag requires that the tag AUTOLINK_SUPPORT is set to YES. + +AUTOLINK_IGNORE_WORDS = + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let Doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also makes the inheritance and +# collaboration diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# https://www.riverbankcomputing.com/software) sources only. Doxygen will parse +# them like normal C++ but will assume all classes use public instead of private +# inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# Doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then Doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, Doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# Doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run Doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +# The NUM_PROC_THREADS specifies the number of threads Doxygen is allowed to use +# during processing. When set to 0 Doxygen will based this on the number of +# cores available in the system. You can set it explicitly to a value larger +# than 0 to get more control over the balance between CPU load and processing +# speed. At this moment only the input processing can be done using multiple +# threads. Since this is still an experimental feature the default is set to 1, +# which effectively disables parallel processing. Please report any issues you +# encounter. Generating dot graphs in parallel is controlled by the +# DOT_NUM_THREADS setting. +# Minimum value: 0, maximum value: 512, default value: 1. + +NUM_PROC_THREADS = 1 + +# If the TIMESTAMP tag is set different from NO then each generated page will +# contain the date or date and time when the page was generated. Setting this to +# NO can help when comparing the output of multiple runs. +# Possible values are: YES, NO, DATETIME and DATE. +# The default value is: NO. + +TIMESTAMP = NO + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, Doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = YES + +# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual +# methods of a class will be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIV_VIRTUAL = YES + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If this flag is set to YES, the name of an unnamed parameter in a declaration +# will be determined by the corresponding definition. By default unnamed +# parameters remain unnamed in the output. +# The default value is: YES. + +RESOLVE_UNNAMED_PARAMS = YES + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# will also hide undocumented C++ concepts if enabled. This option has no effect +# if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_UNDOC_NAMESPACES tag is set to YES, Doxygen will hide all +# undocumented namespaces that are normally visible in the namespace hierarchy. +# If set to NO, these namespaces will be included in the various overviews. This +# option has no effect if EXTRACT_ALL is enabled. +# The default value is: YES. + +HIDE_UNDOC_NAMESPACES = YES + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all friend +# declarations. If set to NO, these declarations will be included in the +# documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# With the correct setting of option CASE_SENSE_NAMES Doxygen will better be +# able to match the capabilities of the underlying filesystem. In case the +# filesystem is case sensitive (i.e. it supports files in the same directory +# whose names only differ in casing), the option must be set to YES to properly +# deal with such files in case they appear in the input. For filesystems that +# are not case sensitive the option should be set to NO to properly deal with +# output files written for symbols that only differ in casing, such as for two +# classes, one named CLASS and the other named Class, and to also support +# references to files without having to specify the exact matching casing. On +# Windows (including Cygwin) and macOS, users should typically set this option +# to NO, whereas on Linux or other Unix flavors it should typically be set to +# YES. +# Possible values are: SYSTEM, NO and YES. +# The default value is: SYSTEM. + +CASE_SENSE_NAMES = SYSTEM + +# If the HIDE_SCOPE_NAMES tag is set to NO then Doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then Doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_HEADERFILE tag is set to YES then the documentation for a class +# will show which file needs to be included to use the class. +# The default value is: YES. + +SHOW_HEADERFILE = YES + +# If the SHOW_INCLUDE_FILES tag is set to YES then Doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then Doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then Doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then Doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then Doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and Doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING Doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The GENERATE_REQUIREMENTS tag can be used to enable (YES) or disable (NO) the +# requirements page. When enabled, this page is automatically created when at +# least one comment block with a \requirement command appears in the input. +# The default value is: YES. + +GENERATE_REQUIREMENTS = YES + +# The REQ_TRACEABILITY_INFO tag controls if traceability information is shown on +# the requirements page (only relevant when using \requirement comment blocks). +# The setting NO will disable the traceability information altogether. The +# setting UNSATISFIED_ONLY will show a list of requirements that are missing a +# satisfies relation (through the command: \satisfies). Similarly the setting +# UNVERIFIED_ONLY will show a list of requirements that are missing a verifies +# relation (through the command: \verifies). Setting the tag to YES (the +# default) will show both lists if applicable. +# Possible values are: YES, NO, UNSATISFIED_ONLY and UNVERIFIED_ONLY. +# The default value is: YES. +# This tag requires that the tag GENERATE_REQUIREMENTS is set to YES. + +REQ_TRACEABILITY_INFO = YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# Doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input_file, where command is the value of the +# FILE_VERSION_FILTER tag, and input_file is the name of an input file provided +# by Doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by Doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents Doxygen's defaults, run Doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. See also section "Changing the +# layout of pages" for information. +# +# Note that if you run Doxygen from a directory containing a file called +# DoxygenLayout.xml, Doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +# The EXTERNAL_TOOL_PATH tag can be used to extend the search path (PATH +# environment variable) so that external tools such as latex and gs can be +# found. +# Note: Directories specified with EXTERNAL_TOOL_PATH are added in front of the +# path already specified by the PATH variable, and are added in the order +# specified. +# Note: This option is particularly useful for macOS version 14 (Sonoma) and +# higher, when running Doxygen from Doxywizard, because in this case any user- +# defined changes to the PATH are ignored. A typical example on macOS is to set +# EXTERNAL_TOOL_PATH = /Library/TeX/texbin /usr/local/bin +# together with the standard path, the full search path used by doxygen when +# launching external tools will then become +# PATH=/Library/TeX/texbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin + +EXTERNAL_TOOL_PATH = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by Doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by Doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES then Doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, Doxygen will generate warnings for +# potential errors in the documentation, such as documenting some parameters in +# a documented function twice, or documenting parameters that don't exist or +# using markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = NO + +# If WARN_IF_INCOMPLETE_DOC is set to YES, Doxygen will warn about incomplete +# function parameter documentation. If set to NO, Doxygen will accept that some +# parameters have no documentation without warning. +# The default value is: YES. + +WARN_IF_INCOMPLETE_DOC = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, Doxygen will only warn about wrong parameter +# documentation, but not about the absence of documentation. If EXTRACT_ALL is +# set to YES then this flag will automatically be disabled. See also +# WARN_IF_INCOMPLETE_DOC +# The default value is: NO. + +WARN_NO_PARAMDOC = YES + +# If WARN_IF_UNDOC_ENUM_VAL option is set to YES, Doxygen will warn about +# undocumented enumeration values. If set to NO, Doxygen will accept +# undocumented enumeration values. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: NO. + +WARN_IF_UNDOC_ENUM_VAL = YES + +# If WARN_LAYOUT_FILE option is set to YES, Doxygen will warn about issues found +# while parsing the user defined layout file, such as missing or wrong elements. +# See also LAYOUT_FILE for details. If set to NO, problems with the layout file +# will be suppressed. +# The default value is: YES. + +WARN_LAYOUT_FILE = YES + +# If the WARN_AS_ERROR tag is set to YES then Doxygen will immediately stop when +# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS +# then Doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but +# at the end of the Doxygen process Doxygen will return with a non-zero status. +# If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS_PRINT then Doxygen behaves +# like FAIL_ON_WARNINGS but in case no WARN_LOGFILE is defined Doxygen will not +# write the warning messages in between other messages but write them at the end +# of a run, in case a WARN_LOGFILE is defined the warning messages will be +# besides being in the defined file also be shown at the end of a run, unless +# the WARN_LOGFILE is defined as - i.e. standard output (stdout) in that case +# the behavior will remain as with the setting FAIL_ON_WARNINGS. +# Possible values are: NO, YES, FAIL_ON_WARNINGS and FAIL_ON_WARNINGS_PRINT. +# The default value is: NO. + +WARN_AS_ERROR = YES + +# The WARN_FORMAT tag determines the format of the warning messages that Doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# See also: WARN_LINE_FORMAT +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# In the $text part of the WARN_FORMAT command it is possible that a reference +# to a more specific place is given. To make it easier to jump to this place +# (outside of Doxygen) the user can define a custom "cut" / "paste" string. +# Example: +# WARN_LINE_FORMAT = "'vi $file +$line'" +# See also: WARN_FORMAT +# The default value is: at line $line of file $file. + +WARN_LINE_FORMAT = "at line $line of file $file" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). In case the file specified cannot be opened for writing the +# warning and error messages are written to standard error. When as file - is +# specified the warning and error messages are written to standard output +# (stdout). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + +INPUT = src/ tests/ + +# This tag can be used to specify the character encoding of the source files +# that Doxygen parses. Internally Doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: +# https://www.gnu.org/software/libiconv/) for the list of possible encodings. +# See also: INPUT_FILE_ENCODING +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# This tag can be used to specify the character encoding of the source files +# that Doxygen parses. The INPUT_FILE_ENCODING tag can be used to specify +# character encoding on a per file pattern basis. Doxygen will compare the file +# name with each pattern and apply the encoding instead of the default +# INPUT_ENCODING if there is a match. The character encodings are a list of the +# form: pattern=encoding (like *.php=ISO-8859-1). +# See also: INPUT_ENCODING for further information on supported encodings. + +INPUT_FILE_ENCODING = + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by Doxygen. +# +# Note the list of default checked file patterns might differ from the list of +# default file extension mappings. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cxxm, +# *.cpp, *.cppm, *.ccm, *.c++, *.c++m, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, +# *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, +# *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be +# provided as Doxygen C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, +# *.f18, *.f, *.for, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice. + +FILE_PATTERNS = llvm_gen_be*.cpp llvm_gen_be*.h test_llvm*.cpp + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which Doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# ANamespace::AClass, ANamespace::*Test + +EXCLUDE_SYMBOLS = edg edg::* + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that Doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. +# +# Note that Doxygen will use the data processed and written to standard output +# for further processing, therefore nothing else, like debug statements or used +# commands (so in case of a Windows batch file always use @echo OFF), should be +# written to standard output. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by Doxygen. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by Doxygen. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the Doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +# If the IMPLICIT_DIR_DOCS tag is set to YES, any README.md file found in sub- +# directories of the project's root, is used as the documentation for that sub- +# directory, except when the README.md starts with a \dir, \page or \mainpage +# command. If set to NO, the README.md file needs to start with an explicit \dir +# command in order to be used as directory documentation. +# The default value is: YES. + +IMPLICIT_DIR_DOCS = YES + +# The Fortran standard specifies that for fixed formatted Fortran code all +# characters from position 72 are to be considered as comment. A common +# extension is to allow longer lines before the automatic comment starts. The +# setting FORTRAN_COMMENT_AFTER will also make it possible that longer lines can +# be processed before the automatic comment starts. +# Minimum value: 7, maximum value: 10000, default value: 72. + +FORTRAN_COMMENT_AFTER = 72 + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# multi-line macros, enums or list initialized variables directly into the +# documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct Doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# entity all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of Doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see https://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by Doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then Doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The IGNORE_PREFIX tag can be used to specify a prefix (or a list of prefixes) +# that should be ignored while generating the index headers. The IGNORE_PREFIX +# tag works for classes, function and member names. The entity will be placed in +# the alphabetical list under the first letter of the entity name that remains +# after removing the prefix. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, Doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank Doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that Doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that Doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of Doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank Doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that Doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank Doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that Doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by Doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). +# Note: Since the styling of scrollbars can currently not be overruled in +# Webkit/Chromium, the styling will be left out of the default doxygen.css if +# one or more extra stylesheets have been specified. So if scrollbar +# customization is desired it has to be added explicitly. For an example see the +# documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE tag can be used to specify if the generated HTML output +# should be rendered with a dark or light theme. +# Possible values are: LIGHT always generates light mode output, DARK always +# generates dark mode output, AUTO_LIGHT automatically sets the mode according +# to the user preference, uses light mode if no preference is set (the default), +# AUTO_DARK automatically sets the mode according to the user preference, uses +# dark mode if no preference is set and TOGGLE allows a user to switch between +# light and dark mode via a button. +# The default value is: AUTO_LIGHT. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE = AUTO_LIGHT + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a color-wheel, see +# https://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use gray-scales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML +# documentation will contain a main index with vertical navigation menus that +# are dynamically created via JavaScript. If disabled, the navigation index will +# consists of multiple levels of tabs that are statically embedded in every HTML +# page. Disable this option to support browsers that do not have JavaScript, +# like the Qt help browser. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_MENUS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# If the HTML_CODE_FOLDING tag is set to YES then classes and functions can be +# dynamically folded and expanded in the generated HTML source code. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_CODE_FOLDING = YES + +# If the HTML_COPY_CLIPBOARD tag is set to YES then Doxygen will show an icon in +# the top right corner of code and text fragments that allows the user to copy +# its content to the clipboard. Note this only works if supported by the browser +# and the web page is served via a secure context (see: +# https://www.w3.org/TR/secure-contexts/), i.e. using the https: or file: +# protocol. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COPY_CLIPBOARD = YES + +# Doxygen stores a couple of settings persistently in the browser (via e.g. +# cookies). By default these settings apply to all HTML pages generated by +# Doxygen across all projects. The HTML_PROJECT_COOKIE tag can be used to store +# the settings under a project specific key, such that the user preferences will +# be stored separately. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_PROJECT_COOKIE = + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: +# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To +# create a documentation set, Doxygen will generate a Makefile in the HTML +# output directory. Running make will produce the docset in that directory and +# running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy +# genXcode/_index.html for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag determines the URL of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDURL = + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then Doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# on Windows. In the beginning of 2021 Microsoft took the original page, with +# a.o. the download links, offline (the HTML help workshop was already many +# years in maintenance mode). You can download the HTML help workshop from the +# web archives at Installation executable (see: +# http://web.archive.org/web/20160201063255/https://download.microsoft.com/downl +# oad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe). +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by Doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# Doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the main .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# The SITEMAP_URL tag is used to specify the full URL of the place where the +# generated documentation will be placed on the server by the user during the +# deployment of the documentation. The generated sitemap is called sitemap.xml +# and placed on the directory specified by HTML_OUTPUT. In case no SITEMAP_URL +# is specified no sitemap is generated. For information about the sitemap +# protocol see https://www.sitemaps.org +# This tag requires that the tag GENERATE_HTML is set to YES. + +SITEMAP_URL = + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location (absolute path +# including file name) of Qt's qhelpgenerator. If non-empty Doxygen will try to +# run qhelpgenerator on the generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine tune the look of the index (see "Fine-tuning the output"). As an +# example, the default style sheet generated by Doxygen has an example that +# shows how to put an image at the root of the tree instead of the PROJECT_NAME. +# Since the tree basically has more details information than the tab index, you +# could consider setting DISABLE_INDEX to YES when enabling this option. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = YES + +# When GENERATE_TREEVIEW is set to YES, the PAGE_OUTLINE_PANEL option determines +# if an additional navigation panel is shown at the right hand side of the +# screen, displaying an outline of the contents of the main page, similar to +# e.g. https://developer.android.com/reference If GENERATE_TREEVIEW is set to +# NO, this option has no effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +PAGE_OUTLINE_PANEL = YES + +# When GENERATE_TREEVIEW is set to YES, the FULL_SIDEBAR option determines if +# the side bar is limited to only the treeview area (value NO) or if it should +# extend to the full height of the window (value YES). Setting this to YES gives +# a layout similar to e.g. https://docs.readthedocs.io with more room for +# contents, but less room for the project logo, title, and description. If +# GENERATE_TREEVIEW is set to NO, this option has no effect. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FULL_SIDEBAR = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# Doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# When the SHOW_ENUM_VALUES tag is set doxygen will show the specified +# enumeration values besides the enumeration mnemonics. +# The default value is: NO. + +SHOW_ENUM_VALUES = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, Doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# If the OBFUSCATE_EMAILS tag is set to YES, Doxygen will obfuscate email +# addresses. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +OBFUSCATE_EMAILS = YES + +# If the HTML_FORMULA_FORMAT option is set to svg, Doxygen will use the pdf2svg +# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see +# https://inkscape.org) to generate formulas as SVG images instead of PNGs for +# the HTML output. These images will generally look nicer at scaled resolutions. +# Possible values are: png (the default) and svg (looks nicer but requires the +# pdf2svg or inkscape tool). +# The default value is: png. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FORMULA_FORMAT = png + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# Doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands +# to create new LaTeX commands to be used in formulas as building blocks. See +# the section "Including formulas" for details. + +FORMULA_MACROFILE = + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# https://www.mathjax.org) which uses client side JavaScript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# With MATHJAX_VERSION it is possible to specify the MathJax version to be used. +# Note that the different versions of MathJax have different requirements with +# regards to the different settings, so it is possible that also other MathJax +# settings have to be changed when switching between the different MathJax +# versions. +# Possible values are: MathJax_2, MathJax_3 and MathJax_4. +# The default value is: MathJax_2. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_VERSION = MathJax_2 + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. For more details about the output format see MathJax +# version 2 (see: +# https://docs.mathjax.org/en/v2.7/output.html), MathJax version 3 (see: +# https://docs.mathjax.org/en/v3.2/output/index.html) and MathJax version 4 +# (see: +# https://docs.mathjax.org/en/v4.0/output/index.htm). +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility. This is the name for Mathjax version 2, for MathJax version 3 +# this will be translated into chtml), NativeMML (i.e. MathML. Only supported +# for MathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This +# is the name for Mathjax version 3, for MathJax version 2 this will be +# translated into HTML-CSS) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. For Mathjax version 2 the +# destination directory should contain the MathJax.js script. For instance, if +# the mathjax directory is located at the same level as the HTML output +# directory, then MATHJAX_RELPATH should be ../mathjax. For Mathjax versions 3 +# and 4 the destination directory should contain the tex-.js script +# (where is either chtml or svg). The default value points to the +# MathJax Content Delivery Network so you can quickly see the result without +# installing MathJax. However, it is strongly recommended to install a local +# copy of MathJax from https://www.mathjax.org before deployment. The default +# value is: +# - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2 +# - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3 +# - in case of MathJax version 4: https://cdn.jsdelivr.net/npm/mathjax@4 +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# for MathJax version 2 (see https://docs.mathjax.org/en/v2.7/tex.html): +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# For example for MathJax version 3 (see +# https://docs.mathjax.org/en/v3.2/input/tex/extensions/): +# MATHJAX_EXTENSIONS = ams +# For example for MathJax version 4 (see +# https://docs.mathjax.org/en/v4.0/input/tex/extensions/): +# MATHJAX_EXTENSIONS = units +# Note that for Mathjax version 4 quite a few extensions are already +# automatically loaded. To disable a package in Mathjax version 4 one can use +# the package name prepended with a minus sign (- like MATHJAX_EXTENSIONS += +# -textmacros) +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with JavaScript pieces +# of code that will be used on startup of the MathJax code. See the Mathjax site +# for more details: +# - MathJax version 2 (see: +# https://docs.mathjax.org/en/v2.7/) +# - MathJax version 3 (see: +# https://docs.mathjax.org/en/v3.2/) +# - MathJax version 4 (see: +# https://docs.mathjax.org/en/v4.0/) For an example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled Doxygen will generate a search box for +# the HTML output. The underlying search engine uses JavaScript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the JavaScript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /