refactor(build): simplify dependency detection logic (#9914)

Closes #9894

**Problem**: Since #9850, a local build incorrectly identifies itself as
1.3.0 stable (in lieu of tip w/ commit info).

**Bug**: `@import("root")` in `Config.zig` resolves to the compilation
root (`main.zig`), not `build.zig` where the marker was defined. So
`@hasDecl` always returned false (i.e. all builds treated as
dependencies).

**Solution**: More or less @rockorager's original approach from #9850.

> _Use `@src().file` to get ghostty's source directory and compare it
with `b.build_root`. When they differ, ghostty is a dependency and we
skip git detection._

However, there is a potential edge case where if a downstream project
also has a `src/build/Config.zig` this will fail silently - seems
unlikely, but worth noting.

**Testing**:

```
$ zig build -p $HOME/.local -Doptimize=ReleaseFast
$ ghostty --version
Ghostty 1.3.0-main+a0a915a06

Version
  - version: 1.3.0-main+a0a915a06
  - channel: tip
```

---

> **AI Disclosure**: I used Claude Code to review and identify edge
cases.
pull/8075/head
Mitchell Hashimoto 2025-12-15 08:46:02 -08:00 committed by GitHub
commit 195c1561fa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 8 additions and 19 deletions

View File

@ -318,8 +318,3 @@ pub fn build(b: *std.Build) !void {
try translations_step.addError("cannot update translations when i18n is disabled", .{});
}
}
/// Marker used by Config.zig to detect if ghostty is the build root.
/// This avoids running logic such as Git tag checking when Ghostty
/// is used as a dependency.
pub const _ghostty_build_root = true;

View File

@ -219,20 +219,14 @@ pub fn init(b: *std.Build, appVersion: []const u8) !Config {
else version: {
const app_version = try std.SemanticVersion.parse(appVersion);
// Detect if ghostty is being built as a dependency by checking if the
// build root has our marker. When used as a dependency, we skip git
// detection entirely to avoid reading the downstream project's git state.
const is_dependency = !@hasDecl(
@import("root"),
"_ghostty_build_root",
);
if (is_dependency) {
break :version .{
.major = app_version.major,
.minor = app_version.minor,
.patch = app_version.patch,
};
}
// Is ghostty a dependency? If so, skip git detection.
// @src().file won't resolve from b.build_root unless ghostty
// is the project being built.
b.build_root.handle.access(@src().file, .{}) catch break :version .{
.major = app_version.major,
.minor = app_version.minor,
.patch = app_version.patch,
};
// If no explicit version is given, we try to detect it from git.
const vsn = GitVersion.detect(b) catch |err| switch (err) {