Skip to content

Commit 9b8340b

Browse files
tychoclaude
andcommitted
docs: document the rust and regen subcommands
README gains `rust` and `regen` entries in the command reference, a "Rust output (experimental)" section showing the generated crate's shape and load API, and a "Regenerating a tree with gloam regen" section under the provenance material. docs/manifest.md points at `gloam regen` as the automated form of the --lock replay it describes. CONTRIBUTING's pipeline sketch and module map pick up generator/rust/ and regen.rs, and CLAUDE.md's design philosophy no longer claims there is no active non-C backend. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent f280bda commit 9b8340b

4 files changed

Lines changed: 102 additions & 8 deletions

File tree

.claude/CLAUDE.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,11 @@ used throughout for insertion-order preservation. Never introduce
2727
non-determinism (HashMap iteration order, random seeds, etc.) and minimize
2828
unnecessary output churn.
2929

30-
**C is the target.** C output is universally compatible — it works in C++
31-
projects too. The `generator/c/` directory structure allows for future
32-
backends, but there is no active non-C backend. Focus effort on the
33-
C generator.
30+
**C is the primary target.** C output is universally compatible — it works
31+
in C++ projects too. An experimental Rust backend (`generator/rust/`)
32+
covers GL/GLES only; it shares the resolver, so the two backends detect
33+
extensions identically. The C generator remains the main focus, and new
34+
resolver/selection features must land in C first.
3435

3536
**Merged output is the primary use case.** `--merge` with GL+GLES2 is how
3637
the loader is actually used in production (Darwinia runs on desktop GL or

CONTRIBUTING.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ CLI args
1414
-> fetch/bundled XML specs
1515
-> parse into RawSpec (IR)
1616
-> resolve into FeatureSet (indexed, sorted, grouped)
17-
-> generate C code via minijinja templates
17+
-> generate C code via minijinja templates (or Rust via string emission)
1818
```
1919

2020
### Module map
@@ -28,6 +28,7 @@ CLI args
2828
| `fetch.rs` | Load specs from bundled copies or remote Khronos URLs (`--fetch`) |
2929
| `build_info.rs` | Git version metadata embedded at compile time (generated by `build.rs`) |
3030
| `preamble.rs` | Copyright/license/provenance comment block for generated files |
31+
| `regen.rs` | `gloam regen`: replays each tree's recorded command line to regenerate it in place |
3132
| **`parse/`** | **XML -> `RawSpec` IR** |
3233
| `parse/mod.rs` | Orchestrator; raw C text extraction, enum value computation |
3334
| `parse/types.rs` | `<types>` -> `RawType[]` with topological sort (Kahn's algorithm) |
@@ -48,6 +49,7 @@ CLI args
4849
| **`generator/`** | **`FeatureSet` -> output files** |
4950
| `generator/c/mod.rs` | C generator: template rendering, function-name blob layout, aux header copying |
5051
| `generator/c/templates/` | Minijinja templates (`header.h.j2`, `source.c.j2`, `hash_search.j2`, `library.j2`, `loader.j2`, etc.) |
52+
| `generator/rust/mod.rs` | Rust generator (experimental; GL/GLES): emits a self-contained `#![no_std]` crate by string emission |
5153

5254
### Key data types
5355

README.md

Lines changed: 87 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@
66
[crates.io]: https://crates.io/crates/gloam
77

88
A loader generator for Vulkan, OpenGL, OpenGL ES, EGL, GLX, and WGL.
9-
Reads Khronos XML spec files and generates C dispatch code. The gloam
10-
binary is fully self-contained — XML specs and auxiliary headers are
11-
embedded at compile time.
9+
Reads Khronos XML spec files and generates C dispatch code, with an
10+
experimental Rust backend for GL/GLES. The gloam binary is fully
11+
self-contained — XML specs and auxiliary headers are embedded at compile
12+
time.
1213

1314
## Why gloam?
1415

@@ -168,6 +169,17 @@ Commands:
168169
(vk_platform.h, vk_video/*) are not bundled in the
169170
output directory.
170171
172+
rust Generate a Rust loader (experimental; GL and GLES only). Emits a
173+
self-contained #![no_std] crate — Cargo.toml plus src/lib.rs —
174+
instead of C sources. See "Rust output" below.
175+
--alias Enable bijective function-pointer alias resolution at
176+
load time (same semantics as the C generator).
177+
--mx-global
178+
Also emit a process-global context with free-function
179+
dispatch (gl::DrawArrays(...) after `use gloam_gl as
180+
gl`), the analogue of the C loader's global-context
181+
macros.
182+
171183
lock Write a provenance-only snapshot manifest (no loader output)
172184
pinning every supported upstream source — at the current bundle,
173185
or at upstream HEAD with --fetch. Reuse it later with --lock.
@@ -177,6 +189,19 @@ Commands:
177189
all match it keeps its previously recorded
178190
commit/describe; delete the file to force a full
179191
re-snapshot.
192+
193+
regen Regenerate existing gloam output trees in place by replaying the
194+
command line recorded in each tree's .gloam/manifest.json. Takes
195+
any number of paths — a tree root, a directory to search
196+
recursively (also finds `gloam lock` snapshots), or a manifest
197+
file itself [default: .]. The output path is derived from each
198+
manifest's own location, so regeneration works from any working
199+
directory. By default every tree is pinned to its recorded
200+
provenance, so output changes only if gloam itself changed. See
201+
"Regenerating a tree with gloam regen" below.
202+
--fresh Re-resolve sources instead (bundled, or upstream HEAD
203+
if the recorded command used --fetch), advancing the
204+
tree — the update workflow.
180205
```
181206

182207
### Extension selection flags
@@ -254,6 +279,31 @@ changed. Unlike an explicit `--lock`, the baseline is best-effort rather than a
254279
contract: sources missing from the old manifest resolve fresh (advancing their
255280
whole repo) instead of being refused.
256281

282+
### Regenerating a tree with `gloam regen`
283+
284+
Because every output tree records its own command line, a checked-in tree is
285+
self-describing — you don't need to remember (or script) the invocation that
286+
produced it:
287+
288+
```sh
289+
gloam regen path/to/gloam # reproduce the tree with this gloam
290+
gloam regen --fresh path/to/gloam # advance it to this gloam's bundle
291+
```
292+
293+
`gloam regen` replays the recorded command with the current gloam. The output
294+
path is derived from the manifest's own location (the recorded `--out-path`
295+
was relative to the original invocation's working directory, so it is treated
296+
as a historical record and re-recorded verbatim), which means regeneration
297+
works from any directory. A directory argument is searched recursively, so one
298+
command can regenerate several vendored trees at once; bare `gloam lock`
299+
snapshots found along the way are re-snapshotted in place.
300+
301+
By default each tree is pinned to its recorded provenance — with an unchanged
302+
gloam the result is byte-identical, and after upgrading gloam the diff shows
303+
exactly what the new version changed. `--fresh` re-resolves sources instead
304+
(the embedded bundle, or upstream HEAD if the recorded command used
305+
`--fetch`), which is how you pull in new spec content.
306+
257307
## Generated output
258308

259309
### Context struct and dispatch
@@ -457,6 +507,40 @@ if(UNIX)
457507
endif()
458508
```
459509

510+
## Rust output (experimental)
511+
512+
The `rust` subcommand generates the loader as a self-contained Rust crate
513+
instead of C sources. It currently covers GL and GLES only:
514+
515+
```sh
516+
gloam --api gl:core=3.3,gles2=3.0 --merge --out-path gloam rust --alias --mx-global
517+
```
518+
519+
This emits `Cargo.toml` and `src/lib.rs` (crate name `gloam_<stem>`, e.g.
520+
`gloam_gl`) — add it to your workspace or reference it by path. The crate is
521+
`#![no_std]` with a single dependency (`xxhash-rust`, for the same XXH3
522+
extension detection the C loader uses; the two backends detect identically).
523+
524+
Loading takes a `GetProcAddress`-style closure and returns a context struct
525+
with an `#[inline]` dispatch method per command plus feature/extension
526+
presence queries:
527+
528+
```rust
529+
use gloam_gl::*;
530+
531+
let gl = unsafe { Gl::load_gl(|name| display.get_proc_address(name))? };
532+
unsafe { gl.Clear(GL_COLOR_BUFFER_BIT) };
533+
if gl.VERSION_3_3() { /* GL 3.3 core available */ }
534+
if gl.KHR_debug() { /* KHR_debug available */ }
535+
```
536+
537+
With `--mx-global`, the crate also emits a process-global context with
538+
free-function dispatch — the analogue of the C loader's global-context
539+
macros. After one `load_gl_global(...)`, every command is a free function
540+
(`gl::DrawArrays(...)`) with no context threading. See
541+
[examples/rust/gl-triangle](examples/rust/gl-triangle) for a complete
542+
winit + glutin application using this mode.
543+
460544
## Bundled specs
461545

462546
gloam embeds compile-time snapshots of upstream Khronos XML specs and

docs/manifest.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,13 @@ regenerate with the same or different flags:
207207
gloam --lock path/to/.gloam/manifest.json --api gl:core=4.6 c --loader
208208
```
209209

210+
To reproduce a tree with its *original* flags, `gloam regen <tree>` automates
211+
this replay: it re-runs the manifest's recorded `command_line` pinned to the
212+
manifest's own `provenance` (or re-resolved with `--fresh`), deriving the
213+
output path from the manifest's location so it works from any directory. The
214+
rest of this section describes the underlying `--lock` mechanism, which regen
215+
uses and which you drive directly when changing flags.
216+
210217
When reading a `--lock` manifest, gloam uses **only its `provenance` section**.
211218
The `gloam` and `output` sections of the input are ignored and regenerated
212219
fresh for the new run.

0 commit comments

Comments
 (0)