diff --git a/build.zig b/build.zig index 89142561b..b89958e55 100644 --- a/build.zig +++ b/build.zig @@ -190,11 +190,11 @@ pub fn build(b: *std.Build) !void { if (!config.target.result.os.tag.isDarwin()) { lib_shared.installHeader(); // Only need one header if (config.target.result.os.tag == .windows) { - lib_shared.install("ghostty.dll"); - lib_static.install("ghostty-static.lib"); + lib_shared.install("ghostty-internal.dll"); + lib_static.install("ghostty-internal-static.lib"); } else { - lib_shared.install("libghostty.so"); - lib_static.install("libghostty.a"); + lib_shared.install("ghostty-internal.so"); + lib_static.install("ghostty-internal.a"); } } } diff --git a/src/build/GhosttyLib.zig b/src/build/GhosttyLib.zig index 4e15fbbf4..a6667e334 100644 --- a/src/build/GhosttyLib.zig +++ b/src/build/GhosttyLib.zig @@ -13,6 +13,8 @@ step: *std.Build.Step, /// The final static library file output: std.Build.LazyPath, dsym: ?std.Build.LazyPath, +pkg_config: ?std.Build.LazyPath, +pkg_config_static: ?std.Build.LazyPath, pub fn initStatic( b: *std.Build, @@ -54,6 +56,8 @@ pub fn initStatic( .step = &lib.step, .output = lib.getEmittedBin(), .dsym = null, + .pkg_config = null, + .pkg_config_static = null, }; // Create a static lib that contains all our dependencies. @@ -70,6 +74,8 @@ pub fn initStatic( // Static libraries cannot have dSYMs because they aren't linked. .dsym = null, + .pkg_config = null, + .pkg_config_static = null, }; } @@ -146,10 +152,20 @@ pub fn initShared( break :dsymutil output; }; + // pkg-config + // + // pkg-config's --static only expands Libs.private / Requires.private; + // it doesn't rewrite Libs: 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(b, deps); + return .{ .step = &lib.step, .output = lib.getEmittedBin(), .dsym = dsymutil, + .pkg_config = pcs.shared, + .pkg_config_static = pcs.static, }; } @@ -168,7 +184,7 @@ pub fn initMacOSUniversal( const universal = LipoStep.create(b, .{ .name = "ghostty", - .out_name = "libghostty.a", + .out_name = "ghostty-internal.a", .input_a = aarch64.output, .input_b = x86_64.output, }); @@ -180,13 +196,31 @@ pub fn initMacOSUniversal( // You can't run dsymutil on a universal binary, you have to // do it on the individual binaries. .dsym = null, + .pkg_config = null, + .pkg_config_static = null, }; } pub fn install(self: *const GhosttyLib, name: []const u8) void { const b = self.step.owner; + const step = b.getInstallStep(); const lib_install = b.addInstallLibFile(self.output, name); - b.getInstallStep().dependOn(&lib_install.step); + step.dependOn(&lib_install.step); + + if (self.pkg_config) |pc| { + step.dependOn(&b.addInstallFileWithDir( + pc, + .prefix, + "share/pkgconfig/ghostty-internal.pc", + ).step); + } + if (self.pkg_config_static) |pc| { + step.dependOn(&b.addInstallFileWithDir( + pc, + .prefix, + "share/pkgconfig/ghostty-internal-static.pc", + ).step); + } } pub fn installHeader(self: *const GhosttyLib) void { @@ -197,3 +231,61 @@ pub fn installHeader(self: *const GhosttyLib) void { ); b.getInstallStep().dependOn(&header_install.step); } + +const PkgConfigFiles = struct { + shared: std.Build.LazyPath, + static: std.Build.LazyPath, +}; + +fn pkgConfigFiles( + b: *std.Build, + deps: *const SharedDeps, +) PkgConfigFiles { + const os_tag = deps.config.target.result.os.tag; + const wf = b.addWriteFiles(); + + return .{ + .shared = wf.add("ghostty-internal.pc", b.fmt( + \\prefix={s} + \\includedir=${{prefix}}/include + \\libdir=${{prefix}}/lib + \\ + \\Name: ghostty-internal + \\URL: https://github.com/ghostty-org/ghostty + \\Description: Ghostty internal library (not for external use) + \\Version: {f} + \\Cflags: -I${{includedir}} + \\Libs: ${{libdir}}/{s} + \\Libs.private: + \\Requires.private: + , .{ b.install_prefix, deps.config.version, sharedLibraryName(os_tag) })), + .static = wf.add("ghostty-internal-static.pc", b.fmt( + \\prefix={s} + \\includedir=${{prefix}}/include + \\libdir=${{prefix}}/lib + \\ + \\Name: ghostty-internal-static + \\URL: https://github.com/ghostty-org/ghostty + \\Description: Ghostty internal library, static (not for external use) + \\Version: {f} + \\Cflags: -I${{includedir}} + \\Libs: ${{libdir}}/{s} + \\Libs.private: + \\Requires.private: + , .{ b.install_prefix, deps.config.version, staticLibraryName(os_tag) })), + }; +} + +fn sharedLibraryName(os_tag: std.Target.Os.Tag) []const u8 { + return if (os_tag == .windows) + "ghostty-internal.dll" + else + "ghostty-internal.so"; +} + +fn staticLibraryName(os_tag: std.Target.Os.Tag) []const u8 { + return if (os_tag == .windows) + "ghostty-internal-static.lib" + else + "ghostty-internal.a"; +} diff --git a/test/windows/README.md b/test/windows/README.md index d9047d841..da2be7521 100644 --- a/test/windows/README.md +++ b/test/windows/README.md @@ -4,13 +4,13 @@ Manual test programs for Windows-specific functionality. ## test_dll_init.c -Regression test for the DLL CRT initialization fix. Loads ghostty.dll -at runtime and calls ghostty_info + ghostty_init to verify the MSVC C -runtime is properly initialized. +Regression test for the DLL CRT initialization fix. Loads +ghostty-internal.dll at runtime and calls ghostty_info + ghostty_init to +verify the MSVC C runtime is properly initialized. ### Build -First build ghostty.dll, then compile the test: +First build ghostty-internal.dll, then compile the test: ``` zig build -Dapp-runtime=none -Demit-exe=false @@ -22,7 +22,7 @@ zig cc test_dll_init.c -o test_dll_init.exe -target native-native-msvc From this directory: ``` -copy ..\..\zig-out\lib\ghostty.dll . && test_dll_init.exe +copy ..\..\zig-out\lib\ghostty-internal.dll . && test_dll_init.exe ``` Expected output (after the CRT fix): diff --git a/test/windows/test_dll_init.c b/test/windows/test_dll_init.c index 68363304f..7215e2b69 100644 --- a/test/windows/test_dll_init.c +++ b/test/windows/test_dll_init.c @@ -1,17 +1,18 @@ /* - * Minimal reproducer for the libghostty DLL CRT initialization issue. + * Minimal reproducer for the ghostty-internal DLL CRT initialization issue. * * Before the fix (DllMain calling __vcrt_initialize / __acrt_initialize), - * loading ghostty.dll and calling any function that touches the C runtime - * crashed with "access violation writing 0x0000000000000024" because Zig's - * _DllMainCRTStartup does not initialize the MSVC C runtime for DLL targets. + * loading ghostty-internal.dll and calling any function that touches the C + * runtime crashed with "access violation writing 0x0000000000000024" because + * Zig's _DllMainCRTStartup does not initialize the MSVC C runtime for DLL + * targets. * * This test loads the DLL and calls ghostty_info, which exercises the CRT * (string handling, memory). If it returns a version string without * crashing, the CRT is properly initialized. * * Build: zig cc test_dll_init.c -o test_dll_init.exe -target native-native-msvc - * Run: copy ..\..\zig-out\lib\ghostty.dll . && test_dll_init.exe + * Run: copy ..\..\zig-out\lib\ghostty-internal.dll . && test_dll_init.exe * * Expected output (after fix): * ghostty_info: @@ -29,7 +30,7 @@ typedef struct { typedef ghostty_info_s (*ghostty_info_fn)(void); int main(void) { - HMODULE dll = LoadLibraryA("ghostty.dll"); + HMODULE dll = LoadLibraryA("ghostty-internal.dll"); if (!dll) { fprintf(stderr, "LoadLibrary failed: %lu\n", GetLastError()); return 1;