diff --git a/nix/libghostty-vt.nix b/nix/libghostty-vt.nix index 5a819a0cc..35c3cbc36 100644 --- a/nix/libghostty-vt.nix +++ b/nix/libghostty-vt.nix @@ -80,6 +80,8 @@ stdenv.mkDerivation (finalAttrs: { postFixup = '' substituteInPlace "$dev/share/pkgconfig/libghostty-vt.pc" \ --replace-fail "$out" "$dev" + substituteInPlace "$dev/share/pkgconfig/libghostty-vt-static.pc" \ + --replace-fail "$out" "$dev" ''; passthru.tests = { @@ -105,6 +107,17 @@ stdenv.mkDerivation (finalAttrs: { pkg-config = testers.hasPkgConfigModules { package = finalAttrs.finalPackage.dev; }; + pkg-config-libs = + runCommand "pkg-config-libs" { + nativeBuildInputs = [pkg-config]; + } '' + export PKG_CONFIG_PATH="${finalAttrs.finalPackage.dev}/share/pkgconfig" + + pkg-config --libs --static libghostty-vt | grep -q -- '-lghostty-vt' + pkg-config --libs --static libghostty-vt-static | grep -q -- '${finalAttrs.finalPackage.dev}/lib/libghostty-vt.a' + + touch "$out" + ''; build-with-shared = stdenv.mkDerivation { name = "build-with-shared"; src = ./test-src; @@ -154,10 +167,7 @@ stdenv.mkDerivation (finalAttrs: { runHook preBuildHooks cc -o test test_libghostty_vt.c \ - ''$(pkg-config --cflags libghostty-vt) \ - ${finalAttrs.finalPackage.dev}/lib/libghostty-vt.a \ - ''$(pkg-config --libs-only-l --static libghostty-vt | sed 's/-lghostty-vt//') \ - -Wl,-rpath,"${finalAttrs.finalPackage}/lib" + ''$(pkg-config --cflags --libs --static libghostty-vt-static) runHook postBuildHooks ''; @@ -227,6 +237,9 @@ stdenv.mkDerivation (finalAttrs: { homepage = "https://ghostty.org"; license = lib.licenses.mit; platforms = zig_0_15.meta.platforms; - pkgConfigModules = ["libghostty-vt"]; + pkgConfigModules = [ + "libghostty-vt" + "libghostty-vt-static" + ]; }; }) diff --git a/src/build/GhosttyLibVt.zig b/src/build/GhosttyLibVt.zig index e3e6cf8c1..32f2e10a7 100644 --- a/src/build/GhosttyLibVt.zig +++ b/src/build/GhosttyLibVt.zig @@ -24,6 +24,7 @@ kind: Kind, output: std.Build.LazyPath, dsym: ?std.Build.LazyPath, pkg_config: ?std.Build.LazyPath, +pkg_config_static: ?std.Build.LazyPath, /// The kind of library being built. This is similar to LinkMode but /// also includes wasm which is an executable, not a library. @@ -85,6 +86,7 @@ pub fn initWasm( .output = output, .dsym = null, .pkg_config = null, + .pkg_config_static = null, }; } @@ -162,6 +164,7 @@ pub fn initStaticAppleUniversal( .output = universal.output, .dsym = null, .pkg_config = null, + .pkg_config_static = null, }); // Additional Apple platforms, each gated on SDK availability. @@ -264,23 +267,15 @@ fn initLib( }; // pkg-config - const pc: std.Build.LazyPath = pc: { - const wf = b.addWriteFiles(); - break :pc wf.add("libghostty-vt.pc", b.fmt( - \\prefix={s} - \\includedir=${{prefix}}/include - \\libdir=${{prefix}}/lib - \\ - \\Name: libghostty-vt - \\URL: https://github.com/ghostty-org/ghostty - \\Description: Ghostty VT library - \\Version: {f} - \\Cflags: -I${{includedir}} - \\Libs: -L${{libdir}} -lghostty-vt - \\Libs.private: {s} - \\Requires.private: {s} - , .{ b.install_prefix, zig.version, libsPrivate(zig), requiresPrivate(b) })); - }; + // + // pkg-config's --static only expands Libs.private / Requires.private; + // it doesn't change -lghostty-vt into an archive-only reference when + // both shared and static libraries are installed. Install a dedicated + // static module so consumers can request the archive explicitly. + const pcs: ?PkgConfigFiles = if (kind == .shared) + pkgConfigFiles(b, zig, target.result.os.tag) + else + null; // For static libraries with vendored SIMD dependencies, combine // all archives into a single fat archive so consumers only need @@ -302,7 +297,8 @@ fn initLib( .kind = kind, .output = combined.output, .dsym = dsymutil, - .pkg_config = pc, + .pkg_config = if (pcs) |v| v.shared else null, + .pkg_config_static = if (pcs) |v| v.static else null, }; } @@ -312,7 +308,8 @@ fn initLib( .kind = kind, .output = lib.getEmittedBin(), .dsym = dsymutil, - .pkg_config = pc, + .pkg_config = if (pcs) |v| v.shared else null, + .pkg_config_static = if (pcs) |v| v.static else null, }; } @@ -370,6 +367,65 @@ fn libsPrivate( return if (zig.vt_c.link_libcpp orelse false) "-lc++" else ""; } +const PkgConfigFiles = struct { + shared: std.Build.LazyPath, + static: std.Build.LazyPath, +}; + +fn pkgConfigFiles( + b: *std.Build, + zig: *const GhosttyZig, + os_tag: std.Target.Os.Tag, +) PkgConfigFiles { + const wf = b.addWriteFiles(); + const libs_private = libsPrivate(zig); + const requires_private = requiresPrivate(b); + + return .{ + .shared = wf.add("libghostty-vt.pc", b.fmt( + \\prefix={s} + \\includedir=${{prefix}}/include + \\libdir=${{prefix}}/lib + \\ + \\Name: libghostty-vt + \\URL: https://github.com/ghostty-org/ghostty + \\Description: Ghostty VT library + \\Version: {f} + \\Cflags: -I${{includedir}} + \\Libs: -L${{libdir}} -lghostty-vt + \\Libs.private: {s} + \\Requires.private: {s} + , .{ b.install_prefix, zig.version, libs_private, requires_private })), + .static = wf.add("libghostty-vt-static.pc", b.fmt( + \\prefix={s} + \\includedir=${{prefix}}/include + \\libdir=${{prefix}}/lib + \\ + \\Name: libghostty-vt-static + \\URL: https://github.com/ghostty-org/ghostty + \\Description: Ghostty VT library (static) + \\Version: {f} + \\Cflags: -I${{includedir}} + \\Libs: ${{libdir}}/{s} + \\Libs.private: {s} + \\Requires.private: {s} + , .{ + b.install_prefix, + zig.version, + staticLibraryName(os_tag), + libs_private, + requires_private, + })), + }; +} + +fn staticLibraryName(os_tag: std.Target.Os.Tag) []const u8 { + return if (os_tag == .windows) + "ghostty-vt-static.lib" + else + "libghostty-vt.a"; +} + /// Returns the Requires.private value for the pkg-config file. /// When SIMD dependencies are provided by the system (via /// -Dsystem-integration), we reference their pkg-config names so @@ -450,4 +506,11 @@ pub fn install( "share/pkgconfig/libghostty-vt.pc", ).step); } + if (self.pkg_config_static) |pkg_config_static| { + step.dependOn(&b.addInstallFileWithDir( + pkg_config_static, + .prefix, + "share/pkgconfig/libghostty-vt-static.pc", + ).step); + } }