summaryrefslogtreecommitdiff
path: root/build.zig
diff options
context:
space:
mode:
Diffstat (limited to 'build.zig')
-rw-r--r--build.zig80
1 files changed, 73 insertions, 7 deletions
diff --git a/build.zig b/build.zig
index 07620ee1..c67caf20 100644
--- a/build.zig
+++ b/build.zig
@@ -3,6 +3,9 @@ const builtin = @import("builtin");
const mupdf_build = @import("mupdf.zig");
const snap_build = @import("build/snap.zig");
const grammar_manifest = @import("src/grammar_manifest.zig");
+/// The package manifest, imported UNTYPED on purpose — see the `version`
+/// option in `shellOptions` for why that word is load-bearing.
+const zon = @import("build.zig.zon");
/// `esp32p4` is not a shell in this package at all: it is one freestanding
/// OBJECT, compiled for riscv32-freestanding, which the `zig_p4` firmware
@@ -17,11 +20,30 @@ pub const Platform = enum { tty, gui, web, macos, esp32p4 };
/// from this, so there is one string and no drift.
pub const macos_min_version: std.SemanticVersion = .{ .major = 13, .minor = 0, .patch = 0 };
-/// The ZLS the language backend links, spelled once. It names the commit
-/// build.zig.zon pins (0.16.x branch) and is passed BOTH to ZLS's own
-/// `-Dversion-string` (its build.zig otherwise shells out to `git describe`,
-/// which fails on a fetched package that has no .git) and to `SPC l i`.
+/// The ZLS the language backend links. It names the commit build.zig.zon pins
+/// (0.16.x branch) and is passed BOTH to ZLS's own `-Dversion-string` (its
+/// build.zig otherwise shells out to `git describe`, which fails on a fetched
+/// package that has no .git) and to `SPC l i`.
+///
+/// It is spelled TWICE — here and in `.dependencies.zls.url` — and the comment
+/// that used to claim "spelled once" was wrong. The duplication is unavoidable
+/// (the semver half exists nowhere in the manifest), so the `comptime` block
+/// below makes the two AGREE by construction: a .zon bump that forgets this
+/// line is now a build error instead of a `SPC l i` that names a build nobody
+/// linked.
const zls_version = "0.16.1-dev+3e0d0820";
+
+comptime {
+ const plus = std.mem.indexOfScalar(u8, zls_version, '+') orelse
+ @compileError("zls_version must end in +<short commit>");
+ const short = zls_version[plus + 1 ..];
+ const url = zon.dependencies.zls.url;
+ const hash = std.mem.indexOfScalar(u8, url, '#') orelse
+ @compileError("the zls dependency url must pin a commit with #<sha>");
+ if (!std.mem.startsWith(u8, url[hash + 1 ..], short)) @compileError(
+ "zls_version pins commit " ++ short ++ ", build.zig.zon pins " ++ url[hash + 1 ..],
+ );
+}
pub const TreeSitterGrammars = enum { disabled, zig, minimal, full };
/// The GUI shell's shaders, spelled ONCE. The runtime SPIR-V imports, their
@@ -481,6 +503,7 @@ pub fn build(b: *std.Build) void {
.theme_animation = theme_animation,
.prebuilt_shaders = prebuilt_shaders,
.zig_lib_dir = b.graph.zig_lib_directory.path orelse "",
+ .commit = gitCommit(b),
};
// ONE `pardes_config` per distinct frontend in this build: two when the
// cli and the gui are made together, one otherwise. hxdiff's core and
@@ -1810,6 +1833,39 @@ fn prefixIsUntouched(b: *std.Build) bool {
std.mem.eql(u8, b.h_dir, b.pathJoin(&.{ b.install_path, "include" }));
}
+/// The commit this build came from, or null when there is nothing to say.
+///
+/// Read at CONFIGURE time and handed to `pardes_config`, so the binary carries
+/// a string rather than the ability to shell out. That is the whole point: a
+/// `--version` that runs `git` itself reports the tree it happens to be
+/// standing in rather than the one it was built from, and on the board there is
+/// no `git` to run and no process to run it with.
+///
+/// ABSENCE IS NOT AN ERROR, and must not be. A release tarball has no `.git`, a
+/// container may have no `git` binary, and a source drop is not a repository —
+/// none of those is a reason to refuse to build. Every way of having no answer
+/// (no binary, no repository, a git that exits non-zero, a git that prints
+/// nothing) lands on the same `null`, and the frontends print the version alone.
+///
+/// Deliberately NOT `--dirty`. Marking a dirty tree costs a worktree stat on
+/// every configure, and — the real cost — it would change `pardes_config` on
+/// every file edit. Every module in this build imports that options module, so
+/// a dirty marker means editing one line rebuilds the world. The commit alone
+/// changes only when a commit does.
+fn gitCommit(b: *std.Build) ?[]const u8 {
+ var code: u8 = 0;
+ // `-C` the build root rather than trusting the cwd: `zig build` may be run
+ // from anywhere, and a `git` resolved against the wrong directory would
+ // cheerfully answer about a DIFFERENT repository.
+ const out = b.runAllowFail(
+ &.{ "git", "-C", b.build_root.path orelse ".", "rev-parse", "--short=12", "HEAD" },
+ &code,
+ .ignore,
+ ) catch return null;
+ const trimmed = std.mem.trim(u8, out, " \t\r\n");
+ return if (trimmed.len == 0) null else trimmed;
+}
+
/// Everything `pardes_config` says that does NOT depend on which frontend is
/// being built. Gathered into one value so the two options modules a default
/// build makes cannot drift apart in any field but the one that is supposed to
@@ -1827,6 +1883,10 @@ const ShellConfig = struct {
theme_animation: ?bool,
prebuilt_shaders: bool,
zig_lib_dir: []const u8,
+ /// Which commit this build came from, or null when there is no answer. Read
+ /// once in `build()` so the two shells of a default build cannot disagree,
+ /// and so `git` is spawned once rather than per frontend.
+ commit: ?[]const u8,
};
/// One `pardes_config` options module, for one frontend. `module_names` and
@@ -1852,9 +1912,15 @@ fn shellOptions(b: *std.Build, cfg: ShellConfig, platform: Platform) *std.Build.
// names: the .zon pins a commit, and a status screen that cannot say WHICH
// analyser answered is not worth opening.
o.addOption([]const u8, "zls_version", if (cfg.zls_backend) zls_version else "none");
- // Mirrors build.zig.zon's `.version`; kept in sync by hand because a typed
- // @import of the .zon rejects its other fields on this Zig 0.16 build.
- o.addOption([]const u8, "version", "0.0.1");
+ // THE version, read from the manifest rather than copied beside it. The
+ // `@import` being UNTYPED is what makes that possible: annotating its type
+ // would demand an exact field match and reject `.dependencies`, `.paths`
+ // and the rest, which is the failure the hand-synced literal that used to
+ // sit here was working around. Verified against this exact manifest.
+ o.addOption([]const u8, "version", zon.version);
+ // ...and the commit it was built from, when there is one. See `gitCommit`
+ // for why this is optional and why it is read at configure time.
+ o.addOption(?[]const u8, "commit", cfg.commit);
// The stdlib this binary was compiled against, so `gd` on `std.mem.count`
// can open the same mem.zig the compiler used. ZLS resolves `@import("std")`
// through `zig_lib_dir` and nothing else; without it every std symbol is a