Skip to content

Commit 8ada077

Browse files
domenkozarclaude
andcommitted
libghostty-vt: fix pkg-config libdir/includedir under split install
`pkgConfigFiles` in GhosttyLibVt.zig was emitting `libdir=${prefix}/lib` and `includedir=${prefix}/include`, interpolating a single install prefix for both the header and library locations. When a packager installs libghostty-vt with the header tree rooted in one place and the shared library in another (e.g. Nix multi-output derivations splitting `$out` for runtime and `$dev` for development artifacts), the interpolated libdir points at the wrong directory and pkg-config-built consumers fail at runtime with libghostty-vt.so.<N>: cannot open shared object file because the SONAME-versioned library does not actually live next to `prefix`. Resolve `libdir` and `includedir` to absolute paths via `b.getInstallPath(.lib, "")` and `b.getInstallPath(.header, "")`, which honor `--prefix-lib-dir` and `--prefix-include-dir` from zig's install options. Single-prefix installs produce the same output as before; split-prefix installs now embed the real, resolved locations into libghostty-vt.pc without any downstream fixup. The Nix package takes advantage of this by installing headers directly into the `dev` output with `--prefix-include-dir`, which lets us drop the entire postInstall dance (`mv $out/include $dev`, `rm $out/lib/libghostty-vt.so` plus the `ln -sf` into `$dev/lib`, and the equivalent darwin unversioned dylib relocation) and the postFixup that used to rewrite the .pc files. libghostty-vt.a now stays alongside the shared library in `$out/lib` so the shared and static .pc files share a single correct libdir, eliminating the need for per-variant postFixup rewriting. Removes the `-Wl,-rpath,"${finalAttrs.finalPackage}/lib"` workaround from the `build-with-shared` and `build-example-c-vt-build-info` passthru tests; they now prove that pkg-config alone is sufficient to produce a binary whose dynamic loader can find libghostty-vt.so.<N> at runtime. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 691b7ac commit 8ada077

2 files changed

Lines changed: 42 additions & 54 deletions

File tree

‎nix/libghostty-vt.nix‎

Lines changed: 14 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,14 @@ stdenv.mkDerivation (finalAttrs: {
6969
"-Dapp-runtime=none"
7070
"-Demit-lib-vt=true"
7171
"-Dsimd=${lib.boolToString simd}"
72+
# Install headers directly into the `dev` output instead of letting
73+
# them land in $out/include and relying on nixpkgs's multi-output
74+
# fixup to relocate them. Because zig's pkg-config generator now
75+
# records the resolved include path in libghostty-vt.pc, installing
76+
# straight to $dev/include means the emitted `includedir=` is
77+
# already correct -- no postFixup rewrite needed.
78+
"--prefix-include-dir"
79+
"${placeholder "dev"}/include"
7280
];
7381
zigCheckFlags = finalAttrs.zigBuildFlags ++ ["test-lib-vt"];
7482

@@ -77,61 +85,20 @@ stdenv.mkDerivation (finalAttrs: {
7785
"dev"
7886
];
7987

80-
postInstall =
81-
''
82-
mkdir -p "$dev/lib"
83-
mv "$out/lib/libghostty-vt.a" "$dev/lib"
84-
mv "$out/include" "$dev"
85-
mv "$out/share" "$dev"
86-
''
87-
+ lib.optionalString stdenv.hostPlatform.isLinux ''
88-
rm "$out/lib/libghostty-vt.so"
89-
ln -sf "$out/lib/libghostty-vt.so.${lib.versions.major finalAttrs.version}" "$dev/lib/libghostty-vt.so"
90-
''
91-
+ lib.optionalString stdenv.hostPlatform.isDarwin ''
92-
# Zig's darwin install emits a versioned `libghostty-vt.<ver>.dylib`
93-
# plus an unversioned `libghostty-vt.dylib` symlink in $out/lib.
94-
# We want the build-time unversioned symlink to live in $dev so
95-
# consumers can link via `-lghostty-vt` without pulling $out into
96-
# their dev closure; remove $out's symlink and recreate an absolute
97-
# one in $dev pointing at the versioned file in $out.
98-
real=
99-
for f in "$out/lib"/libghostty-vt*.dylib; do
100-
if [ -e "$f" ] && [ ! -L "$f" ]; then
101-
real="$f"
102-
break
103-
fi
104-
done
105-
if [ -z "$real" ]; then
106-
echo "libghostty-vt: no versioned dylib found in $out/lib" >&2
107-
ls -la "$out/lib" >&2
108-
exit 1
109-
fi
110-
rm -f "$out/lib/libghostty-vt.dylib"
111-
ln -sf "$real" "$dev/lib/libghostty-vt.dylib"
112-
'';
113-
114-
postFixup = ''
115-
substituteInPlace "$dev/share/pkgconfig/libghostty-vt.pc" \
116-
--replace-fail "$out" "$dev"
117-
substituteInPlace "$dev/share/pkgconfig/libghostty-vt-static.pc" \
118-
--replace-fail "$out" "$dev"
119-
'';
120-
12188
passthru.tests = {
12289
sanity-check = let
12390
version = "${lib.versions.major finalAttrs.version}.${lib.versions.minor finalAttrs.version}.${lib.versions.patch finalAttrs.version}";
12491
in
12592
runCommand "sanity-check" {} (builtins.concatStringsSep "\n" [
12693
''
12794
${lib.getExe' stdenv.cc "nm"} "${finalAttrs.finalPackage}/lib/libghostty-vt.so.${version}" | grep -q 'T ghostty_terminal_new'
128-
${lib.getExe' stdenv.cc "nm"} "${finalAttrs.finalPackage.dev}/lib/libghostty-vt.a" | grep -q 'T ghostty_terminal_new'
95+
${lib.getExe' stdenv.cc "nm"} "${finalAttrs.finalPackage}/lib/libghostty-vt.a" | grep -q 'T ghostty_terminal_new'
12996
''
13097
(
13198
lib.optionalString simd
13299
''
133-
${lib.getExe' stdenv.cc "nm"} "${finalAttrs.finalPackage.dev}/lib/libghostty-vt.a" | grep -q 'T .*simdutf'
134-
${lib.getExe' stdenv.cc "nm"} "${finalAttrs.finalPackage.dev}/lib/libghostty-vt.a" | grep -q 'T .*3hwy'
100+
${lib.getExe' stdenv.cc "nm"} "${finalAttrs.finalPackage}/lib/libghostty-vt.a" | grep -q 'T .*simdutf'
101+
${lib.getExe' stdenv.cc "nm"} "${finalAttrs.finalPackage}/lib/libghostty-vt.a" | grep -q 'T .*3hwy'
135102
''
136103
)
137104
''
@@ -148,7 +115,7 @@ stdenv.mkDerivation (finalAttrs: {
148115
export PKG_CONFIG_PATH="${finalAttrs.finalPackage.dev}/share/pkgconfig"
149116
150117
pkg-config --libs --static libghostty-vt | grep -q -- '-lghostty-vt'
151-
pkg-config --libs --static libghostty-vt-static | grep -q -- '${finalAttrs.finalPackage.dev}/lib/libghostty-vt.a'
118+
pkg-config --libs --static libghostty-vt-static | grep -q -- '${finalAttrs.finalPackage}/lib/libghostty-vt.a'
152119
153120
touch "$out"
154121
'';
@@ -162,8 +129,7 @@ stdenv.mkDerivation (finalAttrs: {
162129
runHook preBuildHooks
163130
164131
cc -o test test_libghostty_vt.c \
165-
''$(pkg-config --cflags --libs libghostty-vt) \
166-
-Wl,-rpath,"${finalAttrs.finalPackage}/lib"
132+
''$(pkg-config --cflags --libs libghostty-vt)
167133
168134
runHook postBuildHooks
169135
'';
@@ -241,8 +207,7 @@ stdenv.mkDerivation (finalAttrs: {
241207
runHook preBuildHooks
242208
243209
cc -o test main.c \
244-
''$(pkg-config --cflags --libs libghostty-vt) \
245-
-Wl,-rpath,"${finalAttrs.finalPackage}/lib"
210+
''$(pkg-config --cflags --libs libghostty-vt)
246211
247212
runHook postBuildHooks
248213
'';

‎src/build/GhosttyLibVt.zig‎

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -371,11 +371,25 @@ fn pkgConfigFiles(
371371
const libs_private = libsPrivate(zig);
372372
const requires_private = requiresPrivate(b);
373373

374+
// Resolve `includedir` and `libdir` to absolute paths instead of
375+
// interpolating `${prefix}/include` and `${prefix}/lib`. When a packager
376+
// installs libghostty-vt with split prefixes (e.g. Nix multi-output
377+
// derivations that put headers in a `-dev` output and runtime libraries
378+
// in the default output), `${prefix}/lib` points at the wrong directory
379+
// and pkg-config-built consumers fail at runtime with
380+
// libghostty-vt.so.<N>: cannot open shared object file
381+
// because the SONAME-versioned library doesn't live next to `prefix`.
382+
// Honoring `--prefix-lib-dir` / `--prefix-include-dir` by asking zig for
383+
// the resolved install path keeps the default single-prefix behavior
384+
// identical and additionally makes split-prefix installs correct.
385+
const includedir = b.getInstallPath(.header, "");
386+
const libdir = b.getInstallPath(.lib, "");
387+
374388
return .{
375389
.shared = wf.add("libghostty-vt.pc", b.fmt(
376390
\\prefix={s}
377-
\\includedir=${{prefix}}/include
378-
\\libdir=${{prefix}}/lib
391+
\\includedir={s}
392+
\\libdir={s}
379393
\\
380394
\\Name: libghostty-vt
381395
\\URL: https://github.com/ghostty-org/ghostty
@@ -385,11 +399,18 @@ fn pkgConfigFiles(
385399
\\Libs: -L${{libdir}} -lghostty-vt
386400
\\Libs.private: {s}
387401
\\Requires.private: {s}
388-
, .{ b.install_prefix, zig.version, libs_private, requires_private })),
402+
, .{
403+
b.install_prefix,
404+
includedir,
405+
libdir,
406+
zig.version,
407+
libs_private,
408+
requires_private,
409+
})),
389410
.static = wf.add("libghostty-vt-static.pc", b.fmt(
390411
\\prefix={s}
391-
\\includedir=${{prefix}}/include
392-
\\libdir=${{prefix}}/lib
412+
\\includedir={s}
413+
\\libdir={s}
393414
\\
394415
\\Name: libghostty-vt-static
395416
\\URL: https://github.com/ghostty-org/ghostty
@@ -401,6 +422,8 @@ fn pkgConfigFiles(
401422
\\Requires.private: {s}
402423
, .{
403424
b.install_prefix,
425+
includedir,
426+
libdir,
404427
zig.version,
405428
staticLibraryName(os_tag),
406429
libs_private,

0 commit comments

Comments
 (0)