From dec86c1dd04083ef673548649f18061d81b37327 Mon Sep 17 00:00:00 2001 From: Chris Marchesi Date: Thu, 7 May 2026 09:11:14 -0700 Subject: [PATCH] Update to Zig 0.16.0 This commit represents the majority of the work necessary to upgrade Ghostty to use Zig 0.16.0. At this point, all tests pass under Linux, but more work may be necessary to get them to build and function on other platforms. Build still fails due to outstanding code changes and fixes necessary to translate-c. Co-authored-by: Leah Amelia Chen --- .gitignore | 2 + build.zig | 15 +- build.zig.zon | 39 +- flake.lock | 56 +- flake.nix | 4 +- nix/devShell.nix | 1 - pkg/android-ndk/build.zig | 19 +- pkg/breakpad/build.zig | 22 +- pkg/dcimgui/build.zig | 40 +- pkg/fontconfig/build.zig | 27 +- pkg/freetype/build.zig | 30 +- pkg/glslang/build.zig | 28 +- pkg/gtk4-layer-shell/build.zig | 14 +- pkg/harfbuzz/build.zig | 34 +- pkg/highway/build.zig | 15 +- pkg/libintl/build.zig | 10 +- pkg/libpng/build.zig | 27 +- pkg/libxml2/build.zig | 21 +- pkg/macos/build.zig | 20 +- pkg/oniguruma/build.zig | 12 +- pkg/sentry/build.zig | 38 +- pkg/simdutf/build.zig | 31 +- pkg/spirv-cross/build.zig | 24 +- pkg/wuffs/build.zig | 1 - pkg/zlib/build.zig | 6 +- src/App.zig | 4 +- src/Command.zig | 98 +-- src/apprt/action.zig | 24 +- src/apprt/gtk/adw_version.zig | 36 +- src/apprt/gtk/build/blueprint.zig | 93 +-- src/apprt/gtk/build/gresource.zig | 33 +- src/apprt/gtk/class.zig | 28 +- src/apprt/gtk/class/application.zig | 14 +- src/apprt/gtk/ext/actions.zig | 6 +- src/apprt/gtk/gtk_version.zig | 51 +- src/apprt/gtk/ipc/DBus.zig | 8 +- src/apprt/gtk/portal/OpenURI.zig | 2 +- src/apprt/ipc.zig | 24 +- src/benchmark/Benchmark.zig | 10 +- src/benchmark/CodepointWidth.zig | 10 +- src/benchmark/GraphemeBreak.zig | 8 +- src/benchmark/IsSymbol.zig | 8 +- src/benchmark/OscParser.zig | 6 +- src/benchmark/ScreenClone.zig | 4 +- src/benchmark/TerminalParser.zig | 6 +- src/benchmark/TerminalStream.zig | 6 +- src/benchmark/cli.zig | 9 +- src/benchmark/options.zig | 6 +- src/build/Config.zig | 12 +- src/build/GhosttyBench.zig | 4 +- src/build/GhosttyDist.zig | 4 +- src/build/GhosttyDocs.zig | 6 +- src/build/GhosttyExe.zig | 4 +- src/build/GhosttyFrameData.zig | 8 +- src/build/GhosttyI18n.zig | 13 +- src/build/GhosttyLib.zig | 18 +- src/build/GhosttyResources.zig | 30 +- src/build/GhosttyWebdata.zig | 6 +- src/build/GhosttyXcodebuild.zig | 10 +- src/build/GhosttyZig.zig | 2 +- src/build/GitVersion.zig | 14 +- src/build/HelpStrings.zig | 2 +- src/build/SharedDeps.zig | 210 ++++--- src/build/UnicodeTables.zig | 4 +- src/build/XCFrameworkStep.zig | 4 +- src/build/args.zig | 13 + src/build/combine_archives.zig | 30 +- src/build/gtk.zig | 25 +- src/build/uucode_config.zig | 203 +++--- src/build/wasm_patch_growable_table.zig | 16 +- src/build/webgen/main_actions.zig | 4 +- src/build/webgen/main_commands.zig | 4 +- src/build/webgen/main_config.zig | 4 +- src/cli/Pager.zig | 27 +- src/cli/action.zig | 29 +- src/cli/args.zig | 38 +- src/cli/boo.zig | 6 +- src/cli/crash_report.zig | 10 +- src/cli/diagnostics.zig | 4 +- src/cli/edit_config.zig | 7 +- src/cli/explain_config.zig | 4 +- src/cli/ghostty.zig | 24 +- src/cli/help.zig | 2 +- src/cli/list_actions.zig | 4 +- src/cli/list_colors.zig | 17 +- src/cli/list_fonts.zig | 4 +- src/cli/list_keybinds.zig | 16 +- src/cli/list_themes.zig | 71 ++- src/cli/new_window.zig | 34 +- src/cli/show_face.zig | 4 +- src/cli/ssh-cache/DiskCache.zig | 128 ++-- src/cli/ssh-cache/Entry.zig | 8 +- src/cli/ssh_cache.zig | 10 +- src/cli/validate_config.zig | 8 +- src/cli/version.zig | 6 +- src/config/Config.zig | 108 ++-- src/config/c_get.zig | 2 +- src/config/command.zig | 3 +- src/config/conditional.zig | 20 +- src/config/edit.zig | 11 +- src/config/file_load.zig | 17 +- src/config/io.zig | 2 +- src/config/key.zig | 27 +- src/config/path.zig | 50 +- src/config/theme.zig | 16 +- src/crash/dir.zig | 17 +- src/crash/sentry_envelope.zig | 6 +- src/datastruct/blocking_queue.zig | 41 +- src/datastruct/comparison.zig | 6 +- src/datastruct/segmented_pool.zig | 3 +- src/font/Atlas.zig | 4 +- src/font/Collection.zig | 7 +- src/font/Metrics.zig | 22 +- src/font/SharedGrid.zig | 32 +- src/font/SharedGridSet.zig | 14 +- src/font/face/freetype.zig | 44 +- src/font/library.zig | 6 +- src/font/opentype/glyf.zig | 35 +- src/font/opentype/head.zig | 8 +- src/font/opentype/hhea.zig | 7 +- src/font/opentype/os2.zig | 21 +- src/font/opentype/post.zig | 8 +- src/font/opentype/sfnt.zig | 7 +- src/font/opentype/svg.zig | 26 +- src/font/shaper/feature.zig | 33 +- src/font/shaper/harfbuzz.zig | 10 +- src/font/sprite/Face.zig | 32 +- src/font/sprite/canvas.zig | 2 +- .../testdata/U+1CC00...U+1CCFF-11x21+2.png | Bin 1032 -> 941 bytes .../testdata/U+1CC00...U+1CCFF-12x24+3.png | Bin 1295 -> 1151 bytes .../testdata/U+1CC00...U+1CCFF-18x36+4.png | Bin 2193 -> 1994 bytes .../testdata/U+1CC00...U+1CCFF-9x17+1.png | Bin 794 -> 717 bytes .../testdata/U+1CD00...U+1CDFF-11x21+2.png | Bin 1280 -> 2146 bytes .../testdata/U+1CD00...U+1CDFF-12x24+3.png | Bin 1870 -> 2529 bytes .../testdata/U+1CD00...U+1CDFF-18x36+4.png | Bin 3411 -> 4398 bytes .../testdata/U+1CD00...U+1CDFF-9x17+1.png | Bin 1103 -> 1625 bytes .../testdata/U+1CE00...U+1CEFF-11x21+2.png | Bin 1006 -> 881 bytes .../testdata/U+1CE00...U+1CEFF-12x24+3.png | Bin 1255 -> 1082 bytes .../testdata/U+1CE00...U+1CEFF-18x36+4.png | Bin 2247 -> 2371 bytes .../testdata/U+1CE00...U+1CEFF-9x17+1.png | Bin 751 -> 693 bytes .../testdata/U+1FB00...U+1FBFF-11x21+2.png | Bin 5427 -> 5871 bytes .../testdata/U+1FB00...U+1FBFF-12x24+3.png | Bin 5724 -> 6354 bytes .../testdata/U+1FB00...U+1FBFF-18x36+4.png | Bin 9975 -> 11167 bytes .../testdata/U+1FB00...U+1FBFF-9x17+1.png | Bin 4341 -> 4598 bytes .../testdata/U+2500...U+25FF-11x21+2.png | Bin 2225 -> 2409 bytes .../testdata/U+2500...U+25FF-12x24+3.png | Bin 2635 -> 2839 bytes .../testdata/U+2500...U+25FF-18x36+4.png | Bin 4570 -> 5323 bytes .../testdata/U+2500...U+25FF-9x17+1.png | Bin 1853 -> 1780 bytes .../testdata/U+2800...U+28FF-11x21+2.png | Bin 1022 -> 1010 bytes .../testdata/U+2800...U+28FF-12x24+3.png | Bin 1541 -> 1276 bytes .../testdata/U+2800...U+28FF-18x36+4.png | Bin 2501 -> 1993 bytes .../testdata/U+2800...U+28FF-9x17+1.png | Bin 917 -> 953 bytes .../testdata/U+E000...U+E0FF-11x21+2.png | Bin 1102 -> 1009 bytes .../testdata/U+E000...U+E0FF-12x24+3.png | Bin 1255 -> 1131 bytes .../testdata/U+E000...U+E0FF-18x36+4.png | Bin 2217 -> 1942 bytes .../testdata/U+E000...U+E0FF-9x17+1.png | Bin 894 -> 832 bytes .../testdata/U+F500...U+F5FF-11x21+2.png | Bin 1114 -> 1044 bytes .../testdata/U+F500...U+F5FF-12x24+3.png | Bin 1421 -> 1279 bytes .../testdata/U+F500...U+F5FF-18x36+4.png | Bin 2473 -> 2073 bytes .../testdata/U+F500...U+F5FF-9x17+1.png | Bin 872 -> 831 bytes .../testdata/U+F600...U+F6FF-11x21+2.png | Bin 495 -> 359 bytes .../testdata/U+F600...U+F6FF-12x24+3.png | Bin 637 -> 438 bytes .../testdata/U+F600...U+F6FF-18x36+4.png | Bin 1210 -> 752 bytes .../testdata/U+F600...U+F6FF-9x17+1.png | Bin 393 -> 288 bytes src/global.zig | 4 +- src/helpgen.zig | 9 +- src/input/Binding.zig | 37 +- src/input/key.zig | 10 +- src/input/key_mods.zig | 9 +- src/lib/compat/README.md | 37 ++ src/lib/compat/args.zig | 241 ++++++++ src/lib/compat/dir.zig | 83 +++ src/lib/compat/env.zig | 277 +++++++++ src/lib/compat/exec.zig | 170 +++++ src/lib/compat/fcntl.zig | 31 + src/lib/compat/init.zig | 19 + src/lib/compat/process.zig | 41 ++ src/lib/compat/reader.zig | 64 ++ src/lib/compat/segmented_list.zig | 533 ++++++++++++++++ src/lib/compat/thread.zig | 75 +++ src/lib/enum.zig | 62 +- src/lib/struct.zig | 24 +- src/lib/union.zig | 28 +- src/main_build_data.zig | 7 +- src/main_c.zig | 20 +- src/main_ghostty.zig | 22 +- src/os/TempDir.zig | 20 +- src/os/args.zig | 21 +- src/os/desktop.zig | 12 +- src/os/env.zig | 4 +- src/os/file.zig | 5 +- src/os/flatpak.zig | 5 +- src/os/homedir.zig | 12 +- src/os/kernel_info.zig | 12 +- src/os/path.zig | 25 +- src/os/resourcesdir.zig | 23 +- src/os/xdg.zig | 9 +- src/pty.zig | 5 +- src/renderer/metal/api.zig | 9 +- src/renderer/metal/shaders.zig | 24 +- src/renderer/opengl/shaders.zig | 24 +- src/synthetic/cli.zig | 9 +- src/synthetic/cli/Ascii.zig | 1 - src/synthetic/cli/Utf8.zig | 1 - src/terminal/PageList.zig | 579 +++++++++--------- src/terminal/Screen.zig | 98 +-- src/terminal/Terminal.zig | 181 +++--- src/terminal/c/build_info.zig | 2 +- src/terminal/c/cell.zig | 4 +- src/terminal/c/key_encode.zig | 4 +- src/terminal/c/key_event.zig | 4 +- src/terminal/c/kitty_graphics.zig | 2 +- src/terminal/c/modes.zig | 4 +- src/terminal/c/mouse_encode.zig | 6 +- src/terminal/c/mouse_event.zig | 4 +- src/terminal/c/osc.zig | 2 +- src/terminal/c/render.zig | 10 +- src/terminal/c/row.zig | 2 +- src/terminal/c/sys.zig | 64 +- src/terminal/c/terminal.zig | 4 +- src/terminal/color.zig | 5 +- src/terminal/device_status.zig | 26 +- src/terminal/formatter.zig | 14 +- src/terminal/kitty/graphics_image.zig | 109 ++-- src/terminal/kitty/graphics_storage.zig | 14 +- src/terminal/modes.zig | 48 +- src/terminal/mouse.zig | 2 +- src/terminal/osc/parsers/color.zig | 25 +- src/terminal/page.zig | 118 ++-- src/terminal/render.zig | 2 +- src/terminal/search/Thread.zig | 26 +- src/terminal/stream.zig | 4 +- src/terminal/style.zig | 4 +- src/terminal/tmux/control.zig | 2 +- src/terminal/tmux/output.zig | 24 +- src/termio/Exec.zig | 2 +- src/termio/shell_integration.zig | 82 +-- src/unicode/grapheme.zig | 12 +- src/unicode/props.zig | 2 +- src/unicode/props_uucode.zig | 8 +- src/unicode/symbols_uucode.zig | 8 +- test_align | 0 242 files changed, 4061 insertions(+), 2258 deletions(-) create mode 100644 src/build/args.zig create mode 100644 src/lib/compat/README.md create mode 100644 src/lib/compat/args.zig create mode 100644 src/lib/compat/dir.zig create mode 100644 src/lib/compat/env.zig create mode 100644 src/lib/compat/exec.zig create mode 100644 src/lib/compat/fcntl.zig create mode 100644 src/lib/compat/init.zig create mode 100644 src/lib/compat/process.zig create mode 100644 src/lib/compat/reader.zig create mode 100644 src/lib/compat/segmented_list.zig create mode 100644 src/lib/compat/thread.zig delete mode 100755 test_align diff --git a/.gitignore b/.gitignore index 699ac9a5f..51b929544 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ zig-cache/ .zig-cache/ zig-out/ +zig-pkg/ build-cmake/ CMakeCache.txt CMakeFiles/ @@ -29,3 +30,4 @@ glad.zip vgcore.* +/sprite_face_test* diff --git a/build.zig b/build.zig index 8ef7701e2..9c990a6d6 100644 --- a/build.zig +++ b/build.zig @@ -25,9 +25,10 @@ pub fn build(b: *std.Build) !void { // use that as the version source of truth. Otherwise we fall back // to what is in the build.zig.zon. const file_version: ?[]const u8 = if (b.build_root.handle.readFileAlloc( - b.allocator, + b.graph.io, "VERSION", - 128, + b.allocator, + std.Io.Limit.limited(128), )) |content| std.mem.trim( u8, content, @@ -298,7 +299,7 @@ pub fn build(b: *std.Build) !void { // We need to rebuild Ghostty with a baseline CPU target. const valgrind_exe = exe: { var valgrind_config = config; - valgrind_config.target = valgrind_config.baselineTarget(); + valgrind_config.target = valgrind_config.baselineTarget(b.graph.io); break :exe try buildpkg.GhosttyExe.init( b, &valgrind_config, @@ -343,7 +344,7 @@ pub fn build(b: *std.Build) !void { .filters = test_filters, .root_module = b.createModule(.{ .root_source_file = b.path("src/main.zig"), - .target = config.baselineTarget(), + .target = config.baselineTarget(b.graph.io), .optimize = .Debug, .strip = false, .omit_frame_pointer = false, @@ -358,7 +359,7 @@ pub fn build(b: *std.Build) !void { // Verify our internal libghostty header. const ghostty_h = b.addTranslateC(.{ .root_source_file = b.path("include/ghostty.h"), - .target = config.baselineTarget(), + .target = config.baselineTarget(b.graph.io), .optimize = .Debug, }); test_exe.root_module.addImport("ghostty.h", ghostty_h.createModule()); @@ -367,6 +368,10 @@ pub fn build(b: *std.Build) !void { const test_run = b.addRunArtifact(test_exe); test_step.dependOn(&test_run.step); + // Check step + const check_step = b.step("check-manual", "build but don't run tests (manual version)"); + check_step.dependOn(&test_exe.step); + // Normal tests always test our libghostty modules //test_step.dependOn(test_lib_vt_step); diff --git a/build.zig.zon b/build.zig.zon index 814145c30..06e98c266 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -3,62 +3,61 @@ .version = "1.3.2-dev", .paths = .{""}, .fingerprint = 0x64407a2a0b4147e5, - .minimum_zig_version = "0.15.2", + .minimum_zig_version = "0.16.0", .dependencies = .{ // Zig libs - .libxev = .{ // mitchellh/libxev - .url = "https://deps.files.ghostty.org/libxev-34fa50878aec6e5fa8f532867001ab3c36fae23e.tar.gz", - .hash = "libxev-0.0.0-86vtc4IcEwCqEYxEYoN_3KXmc6A9VLcm22aVImfvecYs", + .url = "https://github.com/mitchellh/libxev/archive/9ce8e8e6ff89e583258a7f8e7adeeeaeae8611bf.tar.gz", + .hash = "libxev-0.0.0-86vtcwIRFADbH4hk-EjROXxlrKIRPQdA41XiTSytYO-F", .lazy = true, }, .vaxis = .{ // rockorager/libvaxis - .url = "https://deps.files.ghostty.org/vaxis-7dbb9fd3122e4ffad262dd7c151d80d863b68558.tar.gz", - .hash = "vaxis-0.5.1-BWNV_LosCQAGmCCNOLljCIw6j6-yt53tji6n6rwJ2BhS", + .url = "https://github.com/rockorager/libvaxis/archive/1dbbe575dff4586fe51e3217aa5c3fecdcbb6089.tar.gz", + .hash = "vaxis-0.6.0-BWNV_CrbCQCscGpzsAlR402rYQ_tV3aAl081c2iRRkka", .lazy = true, }, .z2d = .{ // vancluever/z2d - .url = "https://deps.files.ghostty.org/z2d-0.10.0-j5P_Hu-6FgBsZNgwphIqh17jDnj8_yPtD8yzjO6PpHRQ.tar.gz", - .hash = "z2d-0.10.0-j5P_Hu-6FgBsZNgwphIqh17jDnj8_yPtD8yzjO6PpHRQ", + .url = "https://github.com/vancluever/z2d/archive/refs/tags/v0.11.0.tar.gz", + .hash = "z2d-0.11.0-j5P_HtLzDwBGyQt49DrT0v4BuVqI_SRs6CXsuj7eBVhR", .lazy = true, }, .zig_objc = .{ // mitchellh/zig-objc - .url = "https://deps.files.ghostty.org/zig_objc-f356ed02833f0f1b8e84d50bed9e807bf7cdc0ae.tar.gz", - .hash = "zig_objc-0.0.0-Ir_Sp5gTAQCvxxR7oVIrPXxXwsfKgVP7_wqoOQrZjFeK", + .url = "https://github.com/mitchellh/zig-objc/archive/c8de82ff80281215ad92900866dab7103a8efa8b.tar.gz", + .hash = "zig_objc-0.0.0-Ir_Sp9gsAQCPAJc0oF5xoWePHWP6Y6tCphDeyNUThJoi", .lazy = true, }, .zig_js = .{ // mitchellh/zig-js - .url = "https://deps.files.ghostty.org/zig_js-04db83c617da1956ac5adc1cb9ba1e434c1cb6fd.tar.gz", - .hash = "zig_js-0.0.0-rjCAV-6GAADxFug7rDmPH-uM_XcnJ5NmuAMJCAscMjhi", + .url = "https://github.com/mitchellh/zig-js/archive/3c23860e47fdcdc5af805efb7fd0bdac5fd3e9bc.tar.gz", + .hash = "zig_js-0.0.0-rjCAV7-GAADvMTBL7lPMuvDk7xgS9PCMIZWiOUXLZSlj", .lazy = true, }, .uucode = .{ // jacobsandlund/uucode - .url = "https://deps.files.ghostty.org/uucode-0.2.0-ZZjBPqZVVABQepOqZHR7vV_NcaN-wats0IB6o-Exj6m9.tar.gz", - .hash = "uucode-0.2.0-ZZjBPqZVVABQepOqZHR7vV_NcaN-wats0IB6o-Exj6m9", + .url = "https://github.com/jacobsandlund/uucode/archive/2826a37a4562284fdacd8fa029d49509cc9bffcd.tar.gz", + .hash = "uucode-0.2.0-ZZjBPlK5VADj7fdoq7G8LIHzD5o6FSkcBXXrRWr4jnrA", }, .zig_wayland = .{ // codeberg ifreund/zig-wayland - .url = "https://deps.files.ghostty.org/zig_wayland-1b5c038ec10da20ed3a15b0b2a6db1c21383e8ea.tar.gz", - .hash = "wayland-0.5.0-dev-lQa1khrMAQDJDwYFKpdH3HizherB7sHo5dKMECfvxQHe", + .url = "https://codeberg.org/ifreund/zig-wayland/archive/v0.6.0.tar.gz", + .hash = "wayland-0.6.0-lQa1kqz8AQADQmdNJsNhLoNHcnEGEUjrOaPV-dtEnEmX", .lazy = true, }, .zf = .{ // natecraddock/zf - .url = "https://deps.files.ghostty.org/zf-3c52637b7e937c5ae61fd679717da3e276765b23.tar.gz", - .hash = "zf-0.10.3-OIRy8RuJAACKA3Lohoumrt85nRbHwbpMcUaLES8vxDnh", + .url = "https://github.com/natecraddock/zf/archive/c35c421f84895193246db06c40683c1a30e616ef.tar.gz", + .hash = "zf-0.11.0-OIRy8X-RAAAwaRXHMYpj2uvBnuGTZWEE_3V7acqHQNtW", .lazy = true, }, .gobject = .{ // https://github.com/ghostty-org/zig-gobject based on zig_gobject // Temporary until we generate them at build time automatically. - .url = "https://deps.files.ghostty.org/gobject-2025-11-08-23-1.tar.zst", - .hash = "gobject-0.3.0-Skun7ANLnwDvEfIpVmohcppXgOvg_I6YOJFmPIsKfXk-", + .url = "https://github.com/ghostty-org/zig-gobject/releases/download/0.8.0-2026-04-23-26-1/ghostty-gobject-0.8.0-2026-04-23-26-1.tar.zst", + .hash = "gobject-0.3.1-Skun7E1KnwBGMX5nslHYG1yWHaSevywxQO8oM7tTOgIp", .lazy = true, }, diff --git a/flake.lock b/flake.lock index 410632788..5a92eb7ac 100644 --- a/flake.lock +++ b/flake.lock @@ -3,11 +3,11 @@ "flake-compat": { "flake": false, "locked": { - "lastModified": 1761588595, - "narHash": "sha256-XKUZz9zewJNUj46b4AJdiRZJAvSZ0Dqj2BNfXvFlJC4=", + "lastModified": 1767039857, + "narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=", "owner": "edolstra", "repo": "flake-compat", - "rev": "f387cd2afec9419c8ee37694406ca490c3f34ee5", + "rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab", "type": "github" }, "original": { @@ -23,11 +23,11 @@ ] }, "locked": { - "lastModified": 1770586272, - "narHash": "sha256-Ucci8mu8QfxwzyfER2DQDbvW9t1BnTUJhBmY7ybralo=", + "lastModified": 1778144356, + "narHash": "sha256-dGM+QCstz/DyLB68+JK5GWyMx4QSqmOJEVgZmy63d/g=", "owner": "nix-community", "repo": "home-manager", - "rev": "b1f916ba052341edc1f80d4b2399f1092a4873ca", + "rev": "e4419d3123b780d5f4c0bceeace450424387638c", "type": "github" }, "original": { @@ -38,11 +38,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1770537093, - "narHash": "sha256-XV30uo8tXuxdzuV8l3sojmlPRLd/8tpMsOp4lNzLGUo=", - "rev": "fef9403a3e4d31b0a23f0bacebbec52c248fbb51", + "lastModified": 1778124196, + "narHash": "sha256-Z5mLDoR8p0d7psIY4LnyaHHRykXngMcWXTZ9JWvtvPc=", + "rev": "68a8af93ff4297686cb68880845e61e5e2e41d92", "type": "tarball", - "url": "https://releases.nixos.org/nixpkgs/nixpkgs-26.05pre942631.fef9403a3e4d/nixexprs.tar.xz" + "url": "https://releases.nixos.org/nixpkgs/nixpkgs-26.05pre993588.68a8af93ff42/nixexprs.tar.xz" }, "original": { "type": "tarball", @@ -88,11 +88,11 @@ ] }, "locked": { - "lastModified": 1776789209, - "narHash": "sha256-G6B7Q4TXn7MZ1mB+f9rymjsYF5PLWoSvmbxijb/99bw=", + "lastModified": 1778158259, + "narHash": "sha256-PwPyM4vM1uzxYqT5txYzauxx9Tfgji/iTPO9KwbTcUc=", "owner": "mitchellh", "repo": "zig-overlay", - "rev": "14fe971844e841297ddd2ce9783d6892b467af39", + "rev": "cd6faec62cb29fda88b2195b91edb2dfe6dce9c2", "type": "github" }, "original": { @@ -101,40 +101,18 @@ "type": "github" } }, - "zig_2": { - "inputs": { - "nixpkgs": [ - "zon2nix", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1777234348, - "narHash": "sha256-fKw44a4qbUuI5eTG8k0gPbqMV5TOrjYF35PBzsYgd2U=", - "ref": "refs/heads/main", - "rev": "2c781c0609ecda600ab98f98cca417bbd981bd53", - "revCount": 1677, - "type": "git", - "url": "https://codeberg.org/jcollie/zig-overlay.git" - }, - "original": { - "type": "git", - "url": "https://codeberg.org/jcollie/zig-overlay.git" - } - }, "zon2nix": { "inputs": { "nixpkgs": [ "nixpkgs" - ], - "zig": "zig_2" + ] }, "locked": { - "lastModified": 1777314365, - "narHash": "sha256-eLxQaD0wc96Neqkln8wHS0rNq/chPODifFkhwrwilEU=", + "lastModified": 1778078000, + "narHash": "sha256-0djKIL0E8Y1W495bzIkmbCub571ubghZx3Fg7xQPNrk=", "owner": "jcollie", "repo": "zon2nix", - "rev": "a5a1d412ad1ab6305511997bbc92b3a9dd6cb784", + "rev": "a9f46c6fe9177135a3001e26ec76715bb998c6cf", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 0a4e5340a..38c54ec64 100644 --- a/flake.nix +++ b/flake.nix @@ -77,8 +77,8 @@ default = pkgs.callPackage ./nix/devShell.nix { zig = if pkgs.stdenv.hostPlatform.isDarwin - then zig.packages.${pkgs.stdenv.hostPlatform.system}.brew."0.15.2" - else zig.packages.${pkgs.stdenv.hostPlatform.system}."0.15.2"; + then zig.packages.${pkgs.stdenv.hostPlatform.system}.brew."0.16.0" + else zig.packages.${pkgs.stdenv.hostPlatform.system}."0.16.0"; wraptest = pkgs.callPackage ./nix/pkgs/wraptest.nix {}; zon2nix = zon2nix; diff --git a/nix/devShell.nix b/nix/devShell.nix index b530c56cd..6fa1f14b1 100644 --- a/nix/devShell.nix +++ b/nix/devShell.nix @@ -27,7 +27,6 @@ wasmtime, wraptest, zig, - zig_0_15, zip, llvmPackages_latest, bzip2, diff --git a/pkg/android-ndk/build.zig b/pkg/android-ndk/build.zig index 5b005665b..2f921e7d6 100644 --- a/pkg/android-ndk/build.zig +++ b/pkg/android-ndk/build.zig @@ -118,16 +118,16 @@ pub fn addPaths(b: *std.Build, step: *std.Build.Step.Compile) !void { fn findNDKPath(b: *std.Build) ?[]const u8 { // Check if user has set the environment variable for the NDK path. - if (std.process.getEnvVarOwned(b.allocator, "ANDROID_NDK_HOME") catch null) |value| { + if (b.graph.environ_map.get("ANDROID_NDK_HOME")) |value| { if (value.len == 0) return null; - var dir = std.fs.openDirAbsolute(value, .{}) catch return null; - defer dir.close(); + var dir = std.Io.Dir.openDirAbsolute(b.graph.io, value, .{}) catch return null; + defer dir.close(b.graph.io); return value; } // Check the common environment variables for the Android SDK path and look for the NDK inside it. inline for (.{ "ANDROID_HOME", "ANDROID_SDK_ROOT" }) |env| { - if (std.process.getEnvVarOwned(b.allocator, env) catch null) |sdk| { + if (b.graph.environ_map.get(env)) |sdk| { if (sdk.len > 0) { if (findLatestNDK(b, sdk)) |ndk| return ndk; } @@ -135,10 +135,9 @@ fn findNDKPath(b: *std.Build) ?[]const u8 { } // As a fallback, we assume the most common/default SDK path based on the OS. - const home = std.process.getEnvVarOwned( - b.allocator, + const home = b.graph.environ_map.get( if (builtin.os.tag == .windows) "LOCALAPPDATA" else "HOME", - ) catch return null; + ) orelse return null; const default_sdk_path = b.pathJoin( &.{ @@ -157,8 +156,8 @@ fn findNDKPath(b: *std.Build) ?[]const u8 { fn findLatestNDK(b: *std.Build, sdk_path: []const u8) ?[]const u8 { const ndk_dir = b.pathJoin(&.{ sdk_path, "ndk" }); - var dir = std.fs.openDirAbsolute(ndk_dir, .{ .iterate = true }) catch return null; - defer dir.close(); + var dir = std.Io.Dir.openDirAbsolute(b.graph.io, ndk_dir, .{ .iterate = true }) catch return null; + defer dir.close(b.graph.io); var latest_: ?struct { name: []const u8, @@ -166,7 +165,7 @@ fn findLatestNDK(b: *std.Build, sdk_path: []const u8) ?[]const u8 { } = null; var iterator = dir.iterate(); - while (iterator.next() catch null) |file| { + while (iterator.next(b.graph.io) catch null) |file| { if (file.kind != .directory) continue; const version = std.SemanticVersion.parse(file.name) catch continue; if (latest_) |latest| { diff --git a/pkg/breakpad/build.zig b/pkg/breakpad/build.zig index 56d51b159..ce02b34fe 100644 --- a/pkg/breakpad/build.zig +++ b/pkg/breakpad/build.zig @@ -9,11 +9,11 @@ pub fn build(b: *std.Build) !void { .root_module = b.createModule(.{ .target = target, .optimize = optimize, + .link_libcpp = true, }), .linkage = .static, }); - lib.linkLibCpp(); - lib.addIncludePath(b.path("vendor")); + lib.root_module.addIncludePath(b.path("vendor")); if (target.result.os.tag.isDarwin()) { const apple_sdk = @import("apple_sdk"); try apple_sdk.addPaths(b, lib); @@ -23,20 +23,20 @@ pub fn build(b: *std.Build) !void { defer flags.deinit(b.allocator); if (b.lazyDependency("breakpad", .{})) |upstream| { - lib.addIncludePath(upstream.path("src")); - lib.addCSourceFiles(.{ + lib.root_module.addIncludePath(upstream.path("src")); + lib.root_module.addCSourceFiles(.{ .root = upstream.path(""), .files = common, .flags = flags.items, }); if (target.result.os.tag.isDarwin()) { - lib.addCSourceFiles(.{ + lib.root_module.addCSourceFiles(.{ .root = upstream.path(""), .files = common_apple, .flags = flags.items, }); - lib.addCSourceFiles(.{ + lib.root_module.addCSourceFiles(.{ .root = upstream.path(""), .files = client_apple, .flags = flags.items, @@ -44,19 +44,19 @@ pub fn build(b: *std.Build) !void { switch (target.result.os.tag) { .macos => { - lib.addCSourceFiles(.{ + lib.root_module.addCSourceFiles(.{ .root = upstream.path(""), .files = common_mac, .flags = flags.items, }); - lib.addCSourceFiles(.{ + lib.root_module.addCSourceFiles(.{ .root = upstream.path(""), .files = client_mac, .flags = flags.items, }); }, - .ios => lib.addCSourceFiles(.{ + .ios => lib.root_module.addCSourceFiles(.{ .root = upstream.path(""), .files = client_ios, .flags = flags.items, @@ -67,12 +67,12 @@ pub fn build(b: *std.Build) !void { } if (target.result.os.tag == .linux) { - lib.addCSourceFiles(.{ + lib.root_module.addCSourceFiles(.{ .root = upstream.path(""), .files = common_linux, .flags = flags.items, }); - lib.addCSourceFiles(.{ + lib.root_module.addCSourceFiles(.{ .root = upstream.path(""), .files = client_linux, .flags = flags.items, diff --git a/pkg/dcimgui/build.zig b/pkg/dcimgui/build.zig index 924e7c932..f74d3673b 100644 --- a/pkg/dcimgui/build.zig +++ b/pkg/dcimgui/build.zig @@ -22,18 +22,16 @@ pub fn build(b: *std.Build) !void { .root_module = b.createModule(.{ .target = target, .optimize = optimize, + .link_libc = true, + // On MSVC, we must not use linkLibCpp because Zig unconditionally + // passes -nostdinc++ and then adds its bundled libc++/libc++abi + // include paths, which conflict with MSVC's own C++ runtime + // headers. The MSVC SDK include directories (added via linkLibC) + // contain both C and C++ headers, so linkLibCpp is not needed. + .link_libcpp = target.result.abi != .msvc, }), .linkage = .static, }); - lib.linkLibC(); - // On MSVC, we must not use linkLibCpp because Zig unconditionally - // passes -nostdinc++ and then adds its bundled libc++/libc++abi - // include paths, which conflict with MSVC's own C++ runtime headers. - // The MSVC SDK include directories (added via linkLibC) contain - // both C and C++ headers, so linkLibCpp is not needed. - if (target.result.abi != .msvc) { - lib.linkLibCpp(); - } b.installArtifact(lib); // Zig module @@ -87,8 +85,8 @@ pub fn build(b: *std.Build) !void { // Add the core Dear Imgui source files if (b.lazyDependency("imgui", .{})) |upstream| { - lib.addIncludePath(upstream.path("")); - lib.addCSourceFiles(.{ + lib.root_module.addIncludePath(upstream.path("")); + lib.root_module.addCSourceFiles(.{ .root = upstream.path(""), .files = &.{ "imgui_demo.cpp", @@ -107,20 +105,20 @@ pub fn build(b: *std.Build) !void { ); if (freetype) { - lib.addCSourceFile(.{ + lib.root_module.addCSourceFile(.{ .file = upstream.path("misc/freetype/imgui_freetype.cpp"), .flags = flags.items, }); if (b.systemIntegrationOption("freetype", .{})) { - lib.linkSystemLibrary2("freetype2", dynamic_link_opts); + lib.root_module.linkSystemLibrary("freetype2", dynamic_link_opts); } else { const freetype_dep = b.dependency("freetype", .{ .target = target, .optimize = optimize, .@"enable-libpng" = true, }); - lib.linkLibrary(freetype_dep.artifact("freetype")); + lib.root_module.linkLibrary(freetype_dep.artifact("freetype")); if (freetype_dep.builder.lazyDependency( "freetype", .{}, @@ -131,7 +129,7 @@ pub fn build(b: *std.Build) !void { } if (backend_metal) { - lib.addCSourceFiles(.{ + lib.root_module.addCSourceFiles(.{ .root = upstream.path("backends"), .files = &.{"imgui_impl_metal.mm"}, .flags = flags.items, @@ -143,7 +141,7 @@ pub fn build(b: *std.Build) !void { ); } if (backend_osx) { - lib.addCSourceFiles(.{ + lib.root_module.addCSourceFiles(.{ .root = upstream.path("backends"), .files = &.{"imgui_impl_osx.mm"}, .flags = flags.items, @@ -155,7 +153,7 @@ pub fn build(b: *std.Build) !void { ); } if (backend_opengl3) { - lib.addCSourceFiles(.{ + lib.root_module.addCSourceFiles(.{ .root = upstream.path("backends"), .files = &.{"imgui_impl_opengl3.cpp"}, .flags = flags.items, @@ -170,8 +168,8 @@ pub fn build(b: *std.Build) !void { // Add the C bindings if (b.lazyDependency("bindings", .{})) |upstream| { - lib.addIncludePath(upstream.path("")); - lib.addCSourceFiles(.{ + lib.root_module.addIncludePath(upstream.path("")); + lib.root_module.addCSourceFiles(.{ .root = upstream.path(""), .files = &.{ "dcimgui.cpp", @@ -179,7 +177,7 @@ pub fn build(b: *std.Build) !void { }, .flags = flags.items, }); - lib.addCSourceFiles(.{ + lib.root_module.addCSourceFiles(.{ .root = b.path(""), .files = &.{"ext.cpp"}, .flags = flags.items, @@ -201,7 +199,7 @@ pub fn build(b: *std.Build) !void { }), }); test_exe.root_module.addOptions("build_options", options); - test_exe.linkLibrary(lib); + test_exe.root_module.linkLibrary(lib); const tests_run = b.addRunArtifact(test_exe); const test_step = b.step("test", "Run tests"); test_step.dependOn(&tests_run.step); diff --git a/pkg/fontconfig/build.zig b/pkg/fontconfig/build.zig index 7c87d1f2e..cd507454f 100644 --- a/pkg/fontconfig/build.zig +++ b/pkg/fontconfig/build.zig @@ -41,7 +41,7 @@ pub fn build(b: *std.Build) !void { if (b.systemIntegrationOption("fontconfig", .{})) { module.linkSystemLibrary("fontconfig", dynamic_link_opts); - test_exe.linkSystemLibrary2("fontconfig", dynamic_link_opts); + test_exe.root_module.linkSystemLibrary("fontconfig", dynamic_link_opts); } else { const lib = try buildLib(b, module, .{ .target = target, @@ -54,7 +54,7 @@ pub fn build(b: *std.Build) !void { .dynamic_link_opts = dynamic_link_opts, }); - test_exe.linkLibrary(lib); + test_exe.root_module.linkLibrary(lib); } } @@ -71,15 +71,18 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu .root_module = b.createModule(.{ .target = target, .optimize = optimize, + .link_libc = true, }), .linkage = .static, }); - lib.linkLibC(); + + const dynamic_link_opts = options.dynamic_link_opts; + if (target.result.os.tag != .windows) { - lib.linkSystemLibrary("pthread"); + lib.root_module.linkSystemLibrary("pthread", dynamic_link_opts); } - lib.addIncludePath(b.path("override/include")); + lib.root_module.addIncludePath(b.path("override/include")); module.addIncludePath(b.path("override/include")); var flags: std.ArrayList([]const u8) = .empty; @@ -194,19 +197,17 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu } } - const dynamic_link_opts = options.dynamic_link_opts; - // Freetype2 _ = b.systemIntegrationOption("freetype", .{}); // So it shows up in help if (freetype_enabled) { if (b.systemIntegrationOption("freetype", .{})) { - lib.linkSystemLibrary2("freetype2", dynamic_link_opts); + lib.root_module.linkSystemLibrary("freetype2", dynamic_link_opts); } else { if (b.lazyDependency( "freetype", .{ .target = target, .optimize = optimize }, )) |freetype_dep| { - lib.linkLibrary(freetype_dep.artifact("freetype")); + lib.root_module.linkLibrary(freetype_dep.artifact("freetype")); } } } @@ -227,22 +228,22 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu } if (b.systemIntegrationOption("libxml2", .{})) { - lib.linkSystemLibrary2("libxml-2.0", dynamic_link_opts); + lib.root_module.linkSystemLibrary("libxml-2.0", dynamic_link_opts); } else { if (b.lazyDependency("libxml2", .{ .target = target, .optimize = optimize, .iconv = libxml2_iconv_enabled, })) |libxml2_dep| { - lib.linkLibrary(libxml2_dep.artifact("xml2")); + lib.root_module.linkLibrary(libxml2_dep.artifact("xml2")); } } } if (b.lazyDependency("fontconfig", .{})) |upstream| { - lib.addIncludePath(upstream.path("")); + lib.root_module.addIncludePath(upstream.path("")); module.addIncludePath(upstream.path("")); - lib.addCSourceFiles(.{ + lib.root_module.addCSourceFiles(.{ .root = upstream.path(""), .files = srcs, .flags = flags.items, diff --git a/pkg/freetype/build.zig b/pkg/freetype/build.zig index b85310a5b..c1f4535c7 100644 --- a/pkg/freetype/build.zig +++ b/pkg/freetype/build.zig @@ -39,7 +39,7 @@ pub fn build(b: *std.Build) !void { if (b.systemIntegrationOption("freetype", .{})) { module.linkSystemLibrary("freetype2", dynamic_link_opts); if (test_exe) |exe| { - exe.linkSystemLibrary2("freetype2", dynamic_link_opts); + exe.root_module.linkSystemLibrary("freetype2", dynamic_link_opts); } } else { const lib = try buildLib(b, module, .{ @@ -52,7 +52,7 @@ pub fn build(b: *std.Build) !void { }); if (test_exe) |exe| { - exe.linkLibrary(lib); + exe.root_module.linkLibrary(lib); } } } @@ -68,10 +68,10 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu .root_module = b.createModule(.{ .target = target, .optimize = optimize, + .link_libc = true, }), .linkage = .static, }); - lib.linkLibC(); if (target.result.os.tag.isDarwin()) { const apple_sdk = @import("apple_sdk"); try apple_sdk.addPaths(b, lib); @@ -101,10 +101,10 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu // Zlib if (b.systemIntegrationOption("zlib", .{})) { - lib.linkSystemLibrary2("zlib", dynamic_link_opts); + lib.root_module.linkSystemLibrary("zlib", dynamic_link_opts); } else { const zlib_dep = b.dependency("zlib", .{ .target = target, .optimize = optimize }); - lib.linkLibrary(zlib_dep.artifact("z")); + lib.root_module.linkLibrary(zlib_dep.artifact("z")); } // Libpng @@ -113,50 +113,50 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu try flags.append(b.allocator, "-DFT_CONFIG_OPTION_USE_PNG=1"); if (b.systemIntegrationOption("libpng", .{})) { - lib.linkSystemLibrary2("libpng", dynamic_link_opts); + lib.root_module.linkSystemLibrary("libpng", dynamic_link_opts); } else { const libpng_dep = b.dependency( "libpng", .{ .target = target, .optimize = optimize }, ); - lib.linkLibrary(libpng_dep.artifact("png")); + lib.root_module.linkLibrary(libpng_dep.artifact("png")); } } if (b.lazyDependency("freetype", .{})) |upstream| { - lib.addIncludePath(upstream.path("include")); + lib.root_module.addIncludePath(upstream.path("include")); module.addIncludePath(upstream.path("include")); - lib.addCSourceFiles(.{ + lib.root_module.addCSourceFiles(.{ .root = upstream.path(""), .files = srcs, .flags = flags.items, }); switch (target.result.os.tag) { - .linux => lib.addCSourceFile(.{ + .linux => lib.root_module.addCSourceFile(.{ .file = upstream.path("builds/unix/ftsystem.c"), .flags = flags.items, }), - .windows => lib.addCSourceFile(.{ + .windows => lib.root_module.addCSourceFile(.{ .file = upstream.path("builds/windows/ftsystem.c"), .flags = flags.items, }), - else => lib.addCSourceFile(.{ + else => lib.root_module.addCSourceFile(.{ .file = upstream.path("src/base/ftsystem.c"), .flags = flags.items, }), } switch (target.result.os.tag) { .windows => { - lib.addCSourceFile(.{ + lib.root_module.addCSourceFile(.{ .file = upstream.path("builds/windows/ftdebug.c"), .flags = flags.items, }); - lib.addWin32ResourceFile(.{ + lib.root_module.addWin32ResourceFile(.{ .file = upstream.path("src/base/ftver.rc"), }); }, - else => lib.addCSourceFile(.{ + else => lib.root_module.addCSourceFile(.{ .file = upstream.path("src/base/ftdebug.c"), .flags = flags.items, }), diff --git a/pkg/glslang/build.zig b/pkg/glslang/build.zig index 1dc82a6e3..92e614b1c 100644 --- a/pkg/glslang/build.zig +++ b/pkg/glslang/build.zig @@ -26,7 +26,7 @@ pub fn build(b: *std.Build) !void { .optimize = optimize, }), }); - test_exe.linkLibrary(lib); + test_exe.root_module.linkLibrary(lib); const tests_run = b.addRunArtifact(test_exe); const test_step = b.step("test", "Run tests"); test_step.dependOn(&tests_run.step); @@ -47,20 +47,18 @@ fn buildGlslang( .root_module = b.createModule(.{ .target = target, .optimize = optimize, + .link_libc = true, + // On MSVC, we must not use linkLibCpp because Zig unconditionally + // passes -nostdinc++ and then adds its bundled libc++/libc++abi + // include paths, which conflict with MSVC's own C++ runtime + // headers. The MSVC SDK include directories (added via linkLibC) + // contain both C and C++ headers, so linkLibCpp is not needed. + .link_libcpp = target.result.abi != .msvc, }), .linkage = .static, }); - lib.linkLibC(); - // On MSVC, we must not use linkLibCpp because Zig unconditionally - // passes -nostdinc++ and then adds its bundled libc++/libc++abi - // include paths, which conflict with MSVC's own C++ runtime headers. - // The MSVC SDK include directories (added via linkLibC) contain - // both C and C++ headers, so linkLibCpp is not needed. - if (target.result.abi != .msvc) { - lib.linkLibCpp(); - } - if (upstream_) |upstream| lib.addIncludePath(upstream.path("")); - lib.addIncludePath(b.path("override")); + if (upstream_) |upstream| lib.root_module.addIncludePath(upstream.path("")); + lib.root_module.addIncludePath(b.path("override")); if (target.result.os.tag.isDarwin()) { const apple_sdk = @import("apple_sdk"); try apple_sdk.addPaths(b, lib); @@ -82,7 +80,7 @@ fn buildGlslang( } if (upstream_) |upstream| { - lib.addCSourceFiles(.{ + lib.root_module.addCSourceFiles(.{ .root = upstream.path(""), .flags = flags.items, .files = &.{ @@ -141,7 +139,7 @@ fn buildGlslang( }); if (target.result.os.tag != .windows) { - lib.addCSourceFiles(.{ + lib.root_module.addCSourceFiles(.{ .root = upstream.path(""), .flags = flags.items, .files = &.{ @@ -149,7 +147,7 @@ fn buildGlslang( }, }); } else { - lib.addCSourceFiles(.{ + lib.root_module.addCSourceFiles(.{ .root = upstream.path(""), .flags = flags.items, .files = &.{ diff --git a/pkg/gtk4-layer-shell/build.zig b/pkg/gtk4-layer-shell/build.zig index 818b48f45..bfb1adf66 100644 --- a/pkg/gtk4-layer-shell/build.zig +++ b/pkg/gtk4-layer-shell/build.zig @@ -42,6 +42,7 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu .root_module = b.createModule(.{ .target = target, .optimize = optimize, + .link_libc = true, }), }); b.installArtifact(lib); @@ -52,13 +53,12 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu const upstream = upstream_ orelse return lib; const wayland_protocols = wayland_protocols_ orelse return lib; - lib.linkLibC(); - lib.addIncludePath(upstream.path("include")); - lib.addIncludePath(upstream.path("src")); + lib.root_module.addIncludePath(upstream.path("include")); + lib.root_module.addIncludePath(upstream.path("src")); module.addIncludePath(upstream.path("include")); // GTK - lib.linkSystemLibrary2("gtk4", dynamic_link_opts); + lib.root_module.linkSystemLibrary("gtk4", dynamic_link_opts); // Wayland headers and source files { @@ -92,9 +92,9 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu const source_scanner = b.addSystemCommand(&.{ "wayland-scanner", "private-code" }); source_scanner.addFileArg(xml); const source = source_scanner.addOutputFileArg(b.fmt("{s}.c", .{name})); - lib.addCSourceFile(.{ .file = source }); + lib.root_module.addCSourceFile(.{ .file = source }); } - lib.addIncludePath(wf.getDirectory()); + lib.root_module.addIncludePath(wf.getDirectory()); } lib.installHeadersDirectory( @@ -113,7 +113,7 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu "stubbed-surface.c", "xdg-surface-server.c", }; - lib.addCSourceFiles(.{ + lib.root_module.addCSourceFiles(.{ .root = upstream.path("src"), .files = srcs, .flags = &.{ diff --git a/pkg/harfbuzz/build.zig b/pkg/harfbuzz/build.zig index b482bc8a3..86e2df74e 100644 --- a/pkg/harfbuzz/build.zig +++ b/pkg/harfbuzz/build.zig @@ -54,9 +54,9 @@ pub fn build(b: *std.Build) !void { var it = module.import_table.iterator(); while (it.next()) |entry| test_exe.root_module.addImport(entry.key_ptr.*, entry.value_ptr.*); if (b.systemIntegrationOption("freetype", .{})) { - test_exe.linkSystemLibrary2("freetype2", dynamic_link_opts); + test_exe.root_module.linkSystemLibrary("freetype2", dynamic_link_opts); } else { - test_exe.linkLibrary(freetype.artifact("freetype")); + test_exe.root_module.linkLibrary(freetype.artifact("freetype")); } const tests_run = b.addRunArtifact(test_exe); const test_step = b.step("test", "Run tests"); @@ -65,7 +65,7 @@ pub fn build(b: *std.Build) !void { if (b.systemIntegrationOption("harfbuzz", .{})) { module.linkSystemLibrary("harfbuzz", dynamic_link_opts); - test_exe.linkSystemLibrary2("harfbuzz", dynamic_link_opts); + test_exe.root_module.linkSystemLibrary("harfbuzz", dynamic_link_opts); } else { const lib = try buildLib(b, module, .{ .target = target, @@ -77,7 +77,7 @@ pub fn build(b: *std.Build) !void { .dynamic_link_opts = dynamic_link_opts, }); - test_exe.linkLibrary(lib); + test_exe.root_module.linkLibrary(lib); } } @@ -99,18 +99,16 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu .root_module = b.createModule(.{ .target = target, .optimize = optimize, + .link_libc = true, + // On MSVC, we must not use linkLibCpp because Zig unconditionally + // passes -nostdinc++ and then adds its bundled libc++/libc++abi + // include paths, which conflict with MSVC's own C++ runtime + // headers. The MSVC SDK include directories (added via linkLibC) + // contain both C and C++ headers, so linkLibCpp is not needed. + .link_libcpp = target.result.abi != .msvc, }), .linkage = .static, }); - lib.linkLibC(); - // On MSVC, we must not use linkLibCpp because Zig unconditionally - // passes -nostdinc++ and then adds its bundled libc++/libc++abi - // include paths, which conflict with MSVC's own C++ runtime headers. - // The MSVC SDK include directories (added via linkLibC) contain - // both C and C++ headers, so linkLibCpp is not needed. - if (target.result.abi != .msvc) { - lib.linkLibCpp(); - } if (target.result.os.tag.isDarwin()) { try apple_sdk.addPaths(b, lib); @@ -154,10 +152,10 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu }); if (b.systemIntegrationOption("freetype", .{})) { - lib.linkSystemLibrary2("freetype2", dynamic_link_opts); + lib.root_module.linkSystemLibrary("freetype2", dynamic_link_opts); module.linkSystemLibrary("freetype2", dynamic_link_opts); } else { - lib.linkLibrary(freetype.artifact("freetype")); + lib.root_module.linkLibrary(freetype.artifact("freetype")); if (freetype.builder.lazyDependency( "freetype", @@ -170,14 +168,14 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu if (coretext_enabled) { try flags.appendSlice(b.allocator, &.{"-DHAVE_CORETEXT=1"}); - lib.linkFramework("CoreText"); + lib.root_module.linkFramework("CoreText", .{}); module.linkFramework("CoreText", .{}); } if (b.lazyDependency("harfbuzz", .{})) |upstream| { - lib.addIncludePath(upstream.path("src")); + lib.root_module.addIncludePath(upstream.path("src")); module.addIncludePath(upstream.path("src")); - lib.addCSourceFile(.{ + lib.root_module.addCSourceFile(.{ .file = upstream.path("src/harfbuzz.cc"), .flags = flags.items, }); diff --git a/pkg/highway/build.zig b/pkg/highway/build.zig index 0ac776123..9e8ac22f2 100644 --- a/pkg/highway/build.zig +++ b/pkg/highway/build.zig @@ -18,17 +18,16 @@ pub fn build(b: *std.Build) !void { .root_source_file = b.path("src/detect.zig"), .target = target, .optimize = optimize, + // Our highway package is free of libc at runtime (uses no symbols) + // but does require libc headers at compile time. + .link_libc = true, }), .linkage = .static, }); - // Our highway package is free of libc at runtime (uses no symbols) - // but does require libc headers at compile time. - lib.linkLibC(); - - lib.addIncludePath(b.path("src/cpp")); + lib.root_module.addIncludePath(b.path("src/cpp")); if (upstream_) |upstream| { - lib.addIncludePath(upstream.path("")); + lib.root_module.addIncludePath(upstream.path("")); module.addIncludePath(upstream.path("")); } @@ -95,7 +94,7 @@ pub fn build(b: *std.Build) !void { }); } - lib.addCSourceFiles(.{ .flags = flags.items, .files = &.{ + lib.root_module.addCSourceFiles(.{ .flags = flags.items, .files = &.{ "src/cpp/abort.cc", "src/cpp/per_target.cc", "src/cpp/targets.cpp", @@ -120,7 +119,7 @@ pub fn build(b: *std.Build) !void { .optimize = optimize, }), }); - test_exe.linkLibrary(lib); + test_exe.root_module.linkLibrary(lib); var it = module.import_table.iterator(); while (it.next()) |entry| test_exe.root_module.addImport(entry.key_ptr.*, entry.value_ptr.*); diff --git a/pkg/libintl/build.zig b/pkg/libintl/build.zig index 32221e5ad..8ef26c7a4 100644 --- a/pkg/libintl/build.zig +++ b/pkg/libintl/build.zig @@ -35,11 +35,11 @@ pub fn build(b: *std.Build) !void { .root_module = b.createModule(.{ .target = target, .optimize = optimize, + .link_libc = true, }), .linkage = .static, }); - lib.linkLibC(); - lib.addIncludePath(b.path("")); + lib.root_module.addIncludePath(b.path("")); if (target.result.os.tag.isDarwin()) { const apple_sdk = @import("apple_sdk"); @@ -47,9 +47,9 @@ pub fn build(b: *std.Build) !void { } if (b.lazyDependency("gettext", .{})) |upstream| { - lib.addIncludePath(upstream.path("gettext-runtime/intl")); - lib.addIncludePath(upstream.path("gettext-runtime/intl/gnulib-lib")); - lib.addCSourceFiles(.{ + lib.root_module.addIncludePath(upstream.path("gettext-runtime/intl")); + lib.root_module.addIncludePath(upstream.path("gettext-runtime/intl/gnulib-lib")); + lib.root_module.addCSourceFiles(.{ .root = upstream.path("gettext-runtime/intl"), .files = srcs, .flags = flags.items, diff --git a/pkg/libpng/build.zig b/pkg/libpng/build.zig index 8734b28f9..559f42a06 100644 --- a/pkg/libpng/build.zig +++ b/pkg/libpng/build.zig @@ -9,18 +9,10 @@ pub fn build(b: *std.Build) !void { .root_module = b.createModule(.{ .target = target, .optimize = optimize, + .link_libc = true, }), .linkage = .static, }); - lib.linkLibC(); - if (target.result.os.tag == .linux) { - lib.linkSystemLibrary("m"); - } - if (target.result.os.tag.isDarwin()) { - const apple_sdk = @import("apple_sdk"); - try apple_sdk.addPaths(b, lib); - } - // For dynamic linking, we prefer dynamic linking and to search by // mode first. Mode first will search all paths for a dynamic library // before falling back to static. @@ -28,20 +20,27 @@ pub fn build(b: *std.Build) !void { .preferred_link_mode = .dynamic, .search_strategy = .mode_first, }; + if (target.result.os.tag == .linux) { + lib.root_module.linkSystemLibrary("m", dynamic_link_opts); + } + if (target.result.os.tag.isDarwin()) { + const apple_sdk = @import("apple_sdk"); + try apple_sdk.addPaths(b, lib); + } if (b.systemIntegrationOption("zlib", .{})) { - lib.linkSystemLibrary2("zlib", dynamic_link_opts); + lib.root_module.linkSystemLibrary("zlib", dynamic_link_opts); } else { if (b.lazyDependency( "zlib", .{ .target = target, .optimize = optimize }, )) |zlib_dep| { - lib.linkLibrary(zlib_dep.artifact("z")); - lib.addIncludePath(b.path("")); + lib.root_module.linkLibrary(zlib_dep.artifact("z")); + lib.root_module.addIncludePath(b.path("")); } if (b.lazyDependency("libpng", .{})) |upstream| { - lib.addIncludePath(upstream.path("")); + lib.root_module.addIncludePath(upstream.path("")); } } @@ -61,7 +60,7 @@ pub fn build(b: *std.Build) !void { }); } - lib.addCSourceFiles(.{ + lib.root_module.addCSourceFiles(.{ .root = upstream.path(""), .files = srcs, .flags = flags.items, diff --git a/pkg/libxml2/build.zig b/pkg/libxml2/build.zig index a9b3e4b1a..07a45e947 100644 --- a/pkg/libxml2/build.zig +++ b/pkg/libxml2/build.zig @@ -11,18 +11,25 @@ pub fn build(b: *std.Build) !void { .root_module = b.createModule(.{ .target = target, .optimize = optimize, + .link_libc = true, }), .linkage = .static, }); - lib.linkLibC(); - if (upstream_) |upstream| lib.addIncludePath(upstream.path("include")); - lib.addIncludePath(b.path("override/include")); + if (upstream_) |upstream| lib.root_module.addIncludePath(upstream.path("include")); + lib.root_module.addIncludePath(b.path("override/include")); if (target.result.os.tag == .windows) { - lib.addIncludePath(b.path("override/config/win32")); - lib.linkSystemLibrary("ws2_32"); + lib.root_module.addIncludePath(b.path("override/config/win32")); + // For dynamic linking, we prefer dynamic linking and to search by + // mode first. Mode first will search all paths for a dynamic library + // before falling back to static. + const dynamic_link_opts: std.Build.Module.LinkSystemLibraryOptions = .{ + .preferred_link_mode = .dynamic, + .search_strategy = .mode_first, + }; + lib.root_module.linkSystemLibrary("ws2_32", dynamic_link_opts); } else { - lib.addIncludePath(b.path("override/config/posix")); + lib.root_module.addIncludePath(b.path("override/config/posix")); } var flags: std.ArrayList([]const u8) = .empty; @@ -98,7 +105,7 @@ pub fn build(b: *std.Build) !void { } if (upstream_) |upstream| { - lib.addCSourceFiles(.{ + lib.root_module.addCSourceFiles(.{ .root = upstream.path(""), .files = srcs, .flags = flags.items, diff --git a/pkg/macos/build.zig b/pkg/macos/build.zig index 0525e481e..448abc280 100644 --- a/pkg/macos/build.zig +++ b/pkg/macos/build.zig @@ -21,21 +21,21 @@ pub fn build(b: *std.Build) !void { .linkage = .static, }); - lib.addCSourceFile(.{ + lib.root_module.addCSourceFile(.{ .file = b.path("os/zig_macos.c"), .flags = &.{"-std=c99"}, }); - lib.addCSourceFile(.{ + lib.root_module.addCSourceFile(.{ .file = b.path("text/ext.c"), }); - lib.linkFramework("CoreFoundation"); - lib.linkFramework("CoreGraphics"); - lib.linkFramework("CoreText"); - lib.linkFramework("CoreVideo"); - lib.linkFramework("QuartzCore"); - lib.linkFramework("IOSurface"); + lib.root_module.linkFramework("CoreFoundation", .{}); + lib.root_module.linkFramework("CoreGraphics", .{}); + lib.root_module.linkFramework("CoreText", .{}); + lib.root_module.linkFramework("CoreVideo", .{}); + lib.root_module.linkFramework("QuartzCore", .{}); + lib.root_module.linkFramework("IOSurface", .{}); if (target.result.os.tag == .macos) { - lib.linkFramework("Carbon"); + lib.root_module.linkFramework("Carbon", .{}); module.linkFramework("Carbon", .{}); } @@ -63,7 +63,7 @@ pub fn build(b: *std.Build) !void { if (target.result.os.tag.isDarwin()) { try apple_sdk.addPaths(b, test_exe); } - test_exe.linkLibrary(lib); + test_exe.root_module.linkLibrary(lib); var it = module.import_table.iterator(); while (it.next()) |entry| { diff --git a/pkg/oniguruma/build.zig b/pkg/oniguruma/build.zig index d142e5eb1..f7df86e1b 100644 --- a/pkg/oniguruma/build.zig +++ b/pkg/oniguruma/build.zig @@ -41,7 +41,7 @@ pub fn build(b: *std.Build) !void { module.linkSystemLibrary("oniguruma", dynamic_link_opts); if (test_exe) |exe| { - exe.linkSystemLibrary2("oniguruma", dynamic_link_opts); + exe.root_module.linkSystemLibrary("oniguruma", dynamic_link_opts); } } else { const lib = try buildLib(b, module, .{ @@ -50,7 +50,7 @@ pub fn build(b: *std.Build) !void { }); if (test_exe) |exe| { - exe.linkLibrary(lib); + exe.root_module.linkLibrary(lib); } } } @@ -64,12 +64,12 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu .root_module = b.createModule(.{ .target = target, .optimize = optimize, + .link_libc = true, }), .linkage = .static, }); const t = target.result; const is_windows = t.os.tag == .windows; - lib.linkLibC(); if (target.result.os.tag.isDarwin()) { const apple_sdk = @import("apple_sdk"); @@ -77,10 +77,10 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu } if (b.lazyDependency("oniguruma", .{})) |upstream| { - lib.addIncludePath(upstream.path("src")); + lib.root_module.addIncludePath(upstream.path("src")); module.addIncludePath(upstream.path("src")); - lib.addConfigHeader(b.addConfigHeader(.{ + lib.root_module.addConfigHeader(b.addConfigHeader(.{ .style = .{ .cmake = upstream.path("src/config.h.cmake.in") }, }, .{ .PACKAGE = "oniguruma", @@ -109,7 +109,7 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu "-fno-sanitize-trap=undefined", }); } - lib.addCSourceFiles(.{ + lib.root_module.addCSourceFiles(.{ .root = upstream.path(""), .flags = flags.items, .files = &.{ diff --git a/pkg/sentry/build.zig b/pkg/sentry/build.zig index 3c88df56d..7eb755f65 100644 --- a/pkg/sentry/build.zig +++ b/pkg/sentry/build.zig @@ -17,10 +17,10 @@ pub fn build(b: *std.Build) !void { .root_module = b.createModule(.{ .target = target, .optimize = optimize, + .link_libc = true, }), .linkage = .static, }); - lib.linkLibC(); if (target.result.os.tag.isDarwin()) { const apple_sdk = @import("apple_sdk"); try apple_sdk.addPaths(b, lib); @@ -46,9 +46,9 @@ pub fn build(b: *std.Build) !void { if (b.lazyDependency("sentry", .{})) |upstream| { module.addIncludePath(upstream.path("include")); - lib.addIncludePath(upstream.path("include")); - lib.addIncludePath(upstream.path("src")); - lib.addCSourceFiles(.{ + lib.root_module.addIncludePath(upstream.path("include")); + lib.root_module.addIncludePath(upstream.path("src")); + lib.root_module.addCSourceFiles(.{ .root = upstream.path(""), .files = srcs, .flags = flags.items, @@ -56,7 +56,7 @@ pub fn build(b: *std.Build) !void { // Linux-only if (target.result.os.tag == .linux) { - lib.addCSourceFiles(.{ + lib.root_module.addCSourceFiles(.{ .root = upstream.path(""), .files = &.{ "vendor/stb_sprintf.c", @@ -67,7 +67,7 @@ pub fn build(b: *std.Build) !void { // Symbolizer + Unwinder if (target.result.os.tag == .windows) { - lib.addCSourceFiles(.{ + lib.root_module.addCSourceFiles(.{ .root = upstream.path(""), .files = &.{ "src/sentry_windows_dbghelp.c", @@ -78,7 +78,7 @@ pub fn build(b: *std.Build) !void { .flags = flags.items, }); } else { - lib.addCSourceFiles(.{ + lib.root_module.addCSourceFiles(.{ .root = upstream.path(""), .files = &.{ "src/sentry_unix_pageallocator.c", @@ -92,7 +92,7 @@ pub fn build(b: *std.Build) !void { // Module finder switch (target.result.os.tag) { - .windows => lib.addCSourceFiles(.{ + .windows => lib.root_module.addCSourceFiles(.{ .root = upstream.path(""), .files = &.{ "src/modulefinder/sentry_modulefinder_windows.c", @@ -100,7 +100,7 @@ pub fn build(b: *std.Build) !void { .flags = flags.items, }), - .macos, .ios => lib.addCSourceFiles(.{ + .macos, .ios => lib.root_module.addCSourceFiles(.{ .root = upstream.path(""), .files = &.{ "src/modulefinder/sentry_modulefinder_apple.c", @@ -108,7 +108,7 @@ pub fn build(b: *std.Build) !void { .flags = flags.items, }), - .linux => lib.addCSourceFiles(.{ + .linux => lib.root_module.addCSourceFiles(.{ .root = upstream.path(""), .files = &.{ "src/modulefinder/sentry_modulefinder_linux.c", @@ -126,7 +126,7 @@ pub fn build(b: *std.Build) !void { // Transport switch (transport) { - .curl => lib.addCSourceFiles(.{ + .curl => lib.root_module.addCSourceFiles(.{ .root = upstream.path(""), .files = &.{ "src/transports/sentry_transport_curl.c", @@ -134,7 +134,7 @@ pub fn build(b: *std.Build) !void { .flags = flags.items, }), - .winhttp => lib.addCSourceFiles(.{ + .winhttp => lib.root_module.addCSourceFiles(.{ .root = upstream.path(""), .files = &.{ "src/transports/sentry_transport_winhttp.c", @@ -142,7 +142,7 @@ pub fn build(b: *std.Build) !void { .flags = flags.items, }), - .none => lib.addCSourceFiles(.{ + .none => lib.root_module.addCSourceFiles(.{ .root = upstream.path(""), .files = &.{ "src/transports/sentry_transport_none.c", @@ -153,7 +153,7 @@ pub fn build(b: *std.Build) !void { // Backend switch (backend) { - .crashpad => lib.addCSourceFiles(.{ + .crashpad => lib.root_module.addCSourceFiles(.{ .root = upstream.path(""), .files = &.{ "src/backends/sentry_backend_crashpad.cpp", @@ -162,7 +162,7 @@ pub fn build(b: *std.Build) !void { }), .breakpad => { - lib.addCSourceFiles(.{ + lib.root_module.addCSourceFiles(.{ .root = upstream.path(""), .files = &.{ "src/backends/sentry_backend_breakpad.cpp", @@ -174,15 +174,15 @@ pub fn build(b: *std.Build) !void { .target = target, .optimize = optimize, })) |breakpad_dep| { - lib.linkLibrary(breakpad_dep.artifact("breakpad")); + lib.root_module.linkLibrary(breakpad_dep.artifact("breakpad")); // We need to add this because Sentry includes some breakpad // headers that include this vendored file... - lib.addIncludePath(breakpad_dep.path("vendor")); + lib.root_module.addIncludePath(breakpad_dep.path("vendor")); } }, - .inproc => lib.addCSourceFiles(.{ + .inproc => lib.root_module.addCSourceFiles(.{ .root = upstream.path(""), .files = &.{ "src/backends/sentry_backend_inproc.c", @@ -190,7 +190,7 @@ pub fn build(b: *std.Build) !void { .flags = flags.items, }), - .none => lib.addCSourceFiles(.{ + .none => lib.root_module.addCSourceFiles(.{ .root = upstream.path(""), .files = &.{ "src/backends/sentry_backend_none.c", diff --git a/pkg/simdutf/build.zig b/pkg/simdutf/build.zig index 0859edc26..52afef667 100644 --- a/pkg/simdutf/build.zig +++ b/pkg/simdutf/build.zig @@ -10,26 +10,21 @@ pub fn build(b: *std.Build) !void { .root_module = b.createModule(.{ .target = target, .optimize = optimize, + .link_libc = true, + // We link libcpp even with no_libcxx because simdutf requires + // libc++ headers at build time. But it doesn't require libc++ at + // runtime. For Ghostty itself, we have CI tests to verify this. + // + // On MSVC, we must not use linkLibCpp because Zig unconditionally + // passes -nostdinc++ and then adds its bundled libc++/libc++abi + // include paths, which conflict with MSVC's own C++ runtime + // headers. The MSVC SDK include directories (added via linkLibC) + // contain both C and C++ headers, so linkLibCpp is not needed. + .link_libcpp = target.result.abi != .msvc, }), .linkage = .static, }); - lib.addIncludePath(b.path("vendor")); - lib.linkLibC(); - libcpp: { - if (target.result.abi == .msvc) { - // On MSVC, we must not use linkLibCpp because Zig unconditionally - // passes -nostdinc++ and then adds its bundled libc++/libc++abi - // include paths, which conflict with MSVC's own C++ runtime headers. - // The MSVC SDK include directories (added via linkLibC) contain - // both C and C++ headers, so linkLibCpp is not needed. - break :libcpp; - } - - // We link libcpp even with no_libcxx because simdutf requires - // libc++ headers at build time. But it doesn't require libc++ - // at runtime. For Ghostty itself, we have CI tests to verify this. - lib.linkLibCpp(); - } + lib.root_module.addIncludePath(b.path("vendor")); if (target.result.os.tag.isDarwin()) { const apple_sdk = @import("apple_sdk"); @@ -74,7 +69,7 @@ pub fn build(b: *std.Build) !void { try flags.append(b.allocator, "-fPIC"); } - lib.addCSourceFiles(.{ + lib.root_module.addCSourceFiles(.{ .flags = flags.items, .files = &.{ "vendor/simdutf.cpp", diff --git a/pkg/spirv-cross/build.zig b/pkg/spirv-cross/build.zig index 72ce61eb6..3b85e8f49 100644 --- a/pkg/spirv-cross/build.zig +++ b/pkg/spirv-cross/build.zig @@ -34,12 +34,12 @@ pub fn build(b: *std.Build) !void { if (b.systemIntegrationOption("spirv-cross", .{})) { module.linkSystemLibrary("spirv-cross-c-shared", dynamic_link_opts); if (test_exe) |exe| { - exe.linkSystemLibrary2("spirv-cross-c-shared", dynamic_link_opts); + exe.root_module.linkSystemLibrary("spirv-cross-c-shared", dynamic_link_opts); } } else { const lib = try buildSpirvCross(b, module, target, optimize); b.installArtifact(lib); - if (test_exe) |exe| exe.linkLibrary(lib); + if (test_exe) |exe| exe.root_module.linkLibrary(lib); } } @@ -54,18 +54,16 @@ fn buildSpirvCross( .root_module = b.createModule(.{ .target = target, .optimize = optimize, + .link_libc = true, + // On MSVC, we must not use linkLibCpp because Zig unconditionally + // passes -nostdinc++ and then adds its bundled libc++/libc++abi + // include paths, which conflict with MSVC's own C++ runtime + // headers. The MSVC SDK include directories (added via linkLibC) + // contain both C and C++ headers, so linkLibCpp is not needed. + .link_libcpp = target.result.abi != .msvc, }), .linkage = .static, }); - lib.linkLibC(); - // On MSVC, we must not use linkLibCpp because Zig unconditionally - // passes -nostdinc++ and then adds its bundled libc++/libc++abi - // include paths, which conflict with MSVC's own C++ runtime headers. - // The MSVC SDK include directories (added via linkLibC) contain - // both C and C++ headers, so linkLibCpp is not needed. - if (target.result.abi != .msvc) { - lib.linkLibCpp(); - } if (target.result.os.tag.isDarwin()) { const apple_sdk = @import("apple_sdk"); try apple_sdk.addPaths(b, lib); @@ -86,9 +84,9 @@ fn buildSpirvCross( } if (b.lazyDependency("spirv_cross", .{})) |upstream| { - lib.addIncludePath(upstream.path("")); + lib.root_module.addIncludePath(upstream.path("")); module.addIncludePath(upstream.path("")); - lib.addCSourceFiles(.{ + lib.root_module.addCSourceFiles(.{ .root = upstream.path(""), .flags = flags.items, .files = &.{ diff --git a/pkg/wuffs/build.zig b/pkg/wuffs/build.zig index 95cef3e09..efe88555a 100644 --- a/pkg/wuffs/build.zig +++ b/pkg/wuffs/build.zig @@ -15,7 +15,6 @@ pub fn build(b: *std.Build) !void { .name = "test", .root_module = module, }); - unit_tests.linkLibC(); var flags: std.ArrayList([]const u8) = .empty; defer flags.deinit(b.allocator); diff --git a/pkg/zlib/build.zig b/pkg/zlib/build.zig index 64db13aa1..3fa9e6bd2 100644 --- a/pkg/zlib/build.zig +++ b/pkg/zlib/build.zig @@ -9,17 +9,17 @@ pub fn build(b: *std.Build) !void { .root_module = b.createModule(.{ .target = target, .optimize = optimize, + .link_libc = true, }), .linkage = .static, }); - lib.linkLibC(); if (target.result.os.tag.isDarwin()) { const apple_sdk = @import("apple_sdk"); try apple_sdk.addPaths(b, lib); } if (b.lazyDependency("zlib", .{})) |upstream| { - lib.addIncludePath(upstream.path("")); + lib.root_module.addIncludePath(upstream.path("")); lib.installHeadersDirectory( upstream.path(""), "", @@ -48,7 +48,7 @@ pub fn build(b: *std.Build) !void { "-D_CRT_NONSTDC_NO_DEPRECATE", }); } - lib.addCSourceFiles(.{ + lib.root_module.addCSourceFiles(.{ .root = upstream.path(""), .files = srcs, .flags = flags.items, diff --git a/src/App.zig b/src/App.zig index 93ee7dea1..16457c20a 100644 --- a/src/App.zig +++ b/src/App.zig @@ -56,7 +56,7 @@ font_grid_set: font.SharedGridSet, // Used to rate limit desktop notifications. Some platforms (notably macOS) will // run out of resources if desktop notifications are sent too fast and the OS // will kill Ghostty. -last_notification_time: ?std.time.Instant = null, +last_notification_time: ?std.Io.Timestamp = null, last_notification_digest: u64 = 0, /// The conditional state of the configuration. See the equivalent field @@ -95,7 +95,7 @@ pub fn init( self.* = .{ .alloc = alloc, - .surfaces = .{}, + .surfaces = .empty, .mailbox = .{}, .font_grid_set = font_grid_set, .config_conditional_state = .{}, diff --git a/src/Command.zig b/src/Command.zig index b81936257..b103010a9 100644 --- a/src/Command.zig +++ b/src/Command.zig @@ -26,11 +26,14 @@ const TempDir = internal_os.TempDir; const mem = std.mem; const linux = std.os.linux; const posix = std.posix; +const compat_dir = @import("lib/compat/dir.zig"); +const compat_exec = @import("lib/compat/exec.zig"); +const compat_process = @import("lib/compat/process.zig"); const debug = std.debug; const testing = std.testing; const Allocator = std.mem.Allocator; -const File = std.fs.File; -const EnvMap = std.process.EnvMap; +const File = std.Io.File; +const EnvMap = std.process.Environ.Map; const apprt = @import("apprt.zig"); /// Function prototype for a function executed /in the child process/ after the @@ -65,7 +68,7 @@ env: ?*const EnvMap = null, /// Working directory to change to in the child process. If not set, the /// working directory of the calling process is preserved. -cwd: ?[]const u8 = null, +cwd: ?[:0]const u8 = null, /// The file handle to set for stdin/out/err. If this isn't set, we do /// nothing explicitly so it is up to the behavior of the operating system. @@ -106,7 +109,7 @@ pseudo_console: if (builtin.os.tag == .windows) ?windows.exp.HPCON else void = data: ?*anyopaque = null, /// Process ID is set after start is called. -pid: ?posix.pid_t = null, +pid: ?posix.system.pid_t = null, /// The various methods a process may exit. pub const Exit = if (builtin.os.tag == .windows) union(enum) { @@ -128,9 +131,9 @@ pub const Exit = if (builtin.os.tag == .windows) union(enum) { return if (posix.W.IFEXITED(status)) Exit{ .Exited = posix.W.EXITSTATUS(status) } else if (posix.W.IFSIGNALED(status)) - Exit{ .Signal = posix.W.TERMSIG(status) } + Exit{ .Signal = @intFromEnum(posix.W.TERMSIG(status)) } else if (posix.W.IFSTOPPED(status)) - Exit{ .Stopped = posix.W.STOPSIG(status) } + Exit{ .Stopped = @intFromEnum(posix.W.STOPSIG(status)) } else Exit{ .Unknown = status }; } @@ -186,7 +189,7 @@ fn startPosix(self: *Command, arena: Allocator) !void { @compileError("missing env vars"); // Fork. - const pid = try posix.fork(); + const pid = try compat_process.fork(); if (pid != 0) { // Parent, return immediately. @@ -206,7 +209,7 @@ fn startPosix(self: *Command, arena: Allocator) !void { return error.ExecFailedInChild; // Setup our working directory - if (self.cwd) |cwd| posix.chdir(cwd) catch { + if (self.cwd) |cwd| compat_dir.chdir(cwd) catch { // This can fail if we don't have permission to go to // this directory or if due to race conditions it doesn't // exist or any various other reasons. We don't want to @@ -219,20 +222,20 @@ fn startPosix(self: *Command, arena: Allocator) !void { global_state.rlimits.restore(); // If there are pre exec callbacks, call them now. - if (self.os_pre_exec) |f| if (f(self)) |exitcode| posix.exit(exitcode); - if (self.rt_pre_exec) |f| if (f(self)) |exitcode| posix.exit(exitcode); + if (self.os_pre_exec) |f| if (f(self)) |exitcode| posix.system.exit(exitcode); + if (self.rt_pre_exec) |f| if (f(self)) |exitcode| posix.system.exit(exitcode); // Finally, replace our process. // Note: we must use the "p"-variant of exec here because we // do not guarantee our command is looked up already in the path. - const err = posix.execvpeZ(self.path, argsZ, envp); + const err = compat_exec.execvpeZ(self.path, argsZ, envp); // If we are executing this code, the exec failed. We're in the // child process so there isn't much we can do. We try to output // something reasonable. Its important to note we MUST NOT return // any other error condition from here on out. var stderr_buf: [1024]u8 = undefined; - var stderr_writer = std.fs.File.stderr().writer(&stderr_buf); + var stderr_writer = std.Io.File.stderr().writer(std.Io.Threaded.global_single_threaded.io(), &stderr_buf); const stderr = &stderr_writer.interface; switch (err) { error.FileNotFound => stderr.print( @@ -283,7 +286,7 @@ fn startWindows(self: *Command, arena: Allocator) !void { .creation = windows.OPEN_EXISTING, }, ) else null; - defer if (null_fd) |fd| posix.close(fd); + defer if (null_fd) |fd| posix.system.close(fd); // TODO: In the case of having FDs instead of pty, need to set up // attributes such that the child process only inherits these handles, @@ -395,9 +398,9 @@ fn setupFd(src: File.Handle, target: i32) !void { .freebsd, .ios, .macos => { // Mac doesn't support dup3 so we use dup2. We purposely clear // CLO_ON_EXEC for this fd. - const flags = try posix.fcntl(src, posix.F.GETFD, 0); + const flags = try posix.system.fcntl(src, posix.F.GETFD, 0); if (flags & posix.FD_CLOEXEC != 0) { - _ = try posix.fcntl(src, posix.F.SETFD, flags & ~@as(u32, posix.FD_CLOEXEC)); + _ = try posix.system.fcntl(src, posix.F.SETFD, flags & ~@as(u32, posix.FD_CLOEXEC)); } try posix.dup2(src, target); @@ -425,7 +428,7 @@ pub fn wait(self: Command, block: bool) !Exit { return .{ .Exited = exit_code }; } - const res = if (block) posix.waitpid(self.pid.?, 0) else res: { + const res = if (block) compat_process.waitpid(self.pid.?, 0) else res: { // We specify NOHANG because its not our fault if the process we launch // for the tty doesn't properly waitpid its children. We don't want // to hang the terminal over it. @@ -434,7 +437,7 @@ pub fn wait(self: Command, block: bool) !Exit { // wait call has not been performed, so we need to keep trying until we get // a non-zero pid back, otherwise we end up with zombie processes. while (true) { - const res = posix.waitpid(self.pid.?, std.c.W.NOHANG); + const res = compat_process.waitpid(self.pid.?, std.c.W.NOHANG); if (res.pid != 0) break :res res; } }; @@ -587,7 +590,7 @@ test "Command: os pre exec 1" { fn do(_: *Command) ?u8 { // This runs in the child, so we can exit and it won't // kill the test runner. - posix.exit(42); + posix.system.exit(42); } }).do, .rt_pre_exec = null, @@ -638,7 +641,7 @@ test "Command: rt pre exec 1" { fn do(_: *Command) ?u8 { // This runs in the child, so we can exit and it won't // kill the test runner. - posix.exit(42); + posix.system.exit(42); } }).do, .rt_post_fork = null, @@ -697,8 +700,8 @@ test "Command: rt post fork 1" { try testing.expectError(error.PostForkError, cmd.testingStart()); } -fn createTestStdout(dir: std.fs.Dir) !File { - const file = try dir.createFile("stdout.txt", .{ .read = true }); +fn createTestStdout(io: std.Io, dir: std.Io.Dir) !File { + const file = try dir.createFile(io, "stdout.txt", .{ .read = true }); if (builtin.os.tag == .windows) { try windows.SetHandleInformation( file.handle, @@ -710,8 +713,8 @@ fn createTestStdout(dir: std.fs.Dir) !File { return file; } -fn createTestStderr(dir: std.fs.Dir) !File { - const file = try dir.createFile("stderr.txt", .{ .read = true }); +fn createTestStderr(io: std.Io, dir: std.Io.Dir) !File { + const file = try dir.createFile(io, "stderr.txt", .{ .read = true }); if (builtin.os.tag == .windows) { try windows.SetHandleInformation( file.handle, @@ -726,8 +729,8 @@ fn createTestStderr(dir: std.fs.Dir) !File { test "Command: redirect stdout to file" { var td = try TempDir.init(); defer td.deinit(); - var stdout = try createTestStdout(td.dir); - defer stdout.close(); + var stdout = try createTestStdout(testing.io, td.dir); + defer stdout.close(testing.io); var cmd: Command = if (builtin.os.tag == .windows) .{ .path = "C:\\Windows\\System32\\whoami.exe", @@ -756,8 +759,13 @@ test "Command: redirect stdout to file" { try testing.expectEqual(@as(u32, 0), @as(u32, exit.Exited)); // Read our stdout - try stdout.seekTo(0); - const contents = try stdout.readToEndAlloc(testing.allocator, 1024 * 128); + const contents = contents: { + const size = (try stdout.stat(testing.io)).size; + const data = try testing.allocator.alloc(u8, size); + errdefer testing.allocator.free(data); + try testing.expectEqual(size, try stdout.readPositionalAll(testing.io, data, 0)); + break :contents data; + }; defer testing.allocator.free(contents); try testing.expect(contents.len > 0); } @@ -765,8 +773,8 @@ test "Command: redirect stdout to file" { test "Command: custom env vars" { var td = try TempDir.init(); defer td.deinit(); - var stdout = try createTestStdout(td.dir); - defer stdout.close(); + var stdout = try createTestStdout(testing.io, td.dir); + defer stdout.close(testing.io); var env = EnvMap.init(testing.allocator); defer env.deinit(); @@ -801,8 +809,13 @@ test "Command: custom env vars" { try testing.expect(exit.Exited == 0); // Read our stdout - try stdout.seekTo(0); - const contents = try stdout.readToEndAlloc(testing.allocator, 4096); + const contents = contents: { + const size = (try stdout.stat(testing.io)).size; + const data = try testing.allocator.alloc(u8, size); + errdefer testing.allocator.free(data); + try testing.expectEqual(size, try stdout.readPositionalAll(testing.io, data, 0)); + break :contents data; + }; defer testing.allocator.free(contents); if (builtin.os.tag == .windows) { @@ -815,8 +828,8 @@ test "Command: custom env vars" { test "Command: custom working directory" { var td = try TempDir.init(); defer td.deinit(); - var stdout = try createTestStdout(td.dir); - defer stdout.close(); + var stdout = try createTestStdout(testing.io, td.dir); + defer stdout.close(testing.io); var cmd: Command = if (builtin.os.tag == .windows) .{ .path = "C:\\Windows\\System32\\cmd.exe", @@ -847,8 +860,13 @@ test "Command: custom working directory" { try testing.expect(exit.Exited == 0); // Read our stdout - try stdout.seekTo(0); - const contents = try stdout.readToEndAlloc(testing.allocator, 4096); + const contents = contents: { + const size = (try stdout.stat(testing.io)).size; + const data = try testing.allocator.alloc(u8, size); + errdefer testing.allocator.free(data); + try testing.expectEqual(size, try stdout.readPositionalAll(testing.io, data, 0)); + break :contents data; + }; defer testing.allocator.free(contents); if (builtin.os.tag == .windows) { @@ -872,10 +890,10 @@ test "Command: posix fork handles execveZ failure" { } var td = try TempDir.init(); defer td.deinit(); - var stdout = try createTestStdout(td.dir); - defer stdout.close(); - var stderr = try createTestStderr(td.dir); - defer stderr.close(); + var stdout = try createTestStdout(testing.io, td.dir); + defer stdout.close(testing.io); + var stderr = try createTestStderr(testing.io, td.dir); + defer stderr.close(testing.io); var cmd: Command = .{ .path = "/not/a/binary", @@ -904,7 +922,7 @@ fn testingStart(self: *Command) !void { self.start(testing.allocator) catch |err| { if (err == error.ExecFailedInChild) { // I am a child process, I must not get confused and continue running the rest of the test suite. - posix.exit(1); + posix.system.exit(1); } return err; }; diff --git a/src/apprt/action.zig b/src/apprt/action.zig index f6865af83..ec138547a 100644 --- a/src/apprt/action.zig +++ b/src/apprt/action.zig @@ -419,8 +419,11 @@ pub const Action = union(Key) { /// Sync with: ghostty_action_u pub const CValue = cvalue: { const key_fields = @typeInfo(Key).@"enum".fields; - var union_fields: [key_fields.len]std.builtin.Type.UnionField = undefined; - for (key_fields, 0..) |field, i| { + var names: [key_fields.len][]const u8 = undefined; + var types: [key_fields.len]type = undefined; + var attrs: [key_fields.len]std.builtin.Type.UnionField.Attributes = undefined; + + for (key_fields, &names, &types, &attrs) |field, *name, *ty, *attr| { const action = @unionInit(Action, field.name, undefined); const Type = t: { const Type = @TypeOf(@field(action, field.name)); @@ -429,19 +432,12 @@ pub const Action = union(Key) { break :t Type; }; - union_fields[i] = .{ - .name = field.name, - .type = Type, - .alignment = @alignOf(Type), - }; + name.* = field.name; + ty.* = Type; + attr.* = .{ .@"align" = @alignOf(Type) }; } - break :cvalue @Type(.{ .@"union" = .{ - .layout = .@"extern", - .tag_type = null, - .fields = &union_fields, - .decls = &.{}, - } }); + break :cvalue @Union(.@"extern", null, &names, &types, &attrs); }; /// Sync with: ghostty_action_s @@ -1003,5 +999,5 @@ pub const SearchSelected = struct { }; test { - _ = std.testing.refAllDeclsRecursive(@This()); + _ = std.testing.refAllDecls(@This()); } diff --git a/src/apprt/gtk/adw_version.zig b/src/apprt/gtk/adw_version.zig index 6f7be52da..fce9741ed 100644 --- a/src/apprt/gtk/adw_version.zig +++ b/src/apprt/gtk/adw_version.zig @@ -1,22 +1,16 @@ const std = @import("std"); -// Until the gobject bindings are built at the same time we are building -// Ghostty, we need to import `adwaita.h` directly to ensure that the version -// macros match the version of `libadwaita` that we are building/linking -// against. -const c = @cImport({ - @cInclude("adwaita.h"); -}); - const adw = @import("adw"); const log = std.log.scoped(.gtk); -pub const comptime_version: std.SemanticVersion = .{ - .major = c.ADW_MAJOR_VERSION, - .minor = c.ADW_MINOR_VERSION, - .patch = c.ADW_MICRO_VERSION, -}; +// Until the gobject bindings are built at the same time we are building +// Ghostty, we need to ensure that the version macros match the version of +// `libadwaita` that we are building/linking against. +// +// We pull this in through pkg-config, see src/build/SharedDeps.zig for more +// details. +pub const comptime_version = @import("adw_semver").version; pub fn getRuntimeVersion() std.SemanticVersion { return .{ @@ -89,14 +83,14 @@ test "versionAtLeast" { const funs = &.{ atLeast, runtimeAtLeast }; inline for (funs) |fun| { - try testing.expect(fun(c.ADW_MAJOR_VERSION, c.ADW_MINOR_VERSION, c.ADW_MICRO_VERSION)); - try testing.expect(!fun(c.ADW_MAJOR_VERSION, c.ADW_MINOR_VERSION, c.ADW_MICRO_VERSION + 1)); - try testing.expect(!fun(c.ADW_MAJOR_VERSION, c.ADW_MINOR_VERSION + 1, c.ADW_MICRO_VERSION)); - try testing.expect(!fun(c.ADW_MAJOR_VERSION + 1, c.ADW_MINOR_VERSION, c.ADW_MICRO_VERSION)); - try testing.expect(fun(c.ADW_MAJOR_VERSION - 1, c.ADW_MINOR_VERSION, c.ADW_MICRO_VERSION)); - try testing.expect(fun(c.ADW_MAJOR_VERSION - 1, c.ADW_MINOR_VERSION + 1, c.ADW_MICRO_VERSION)); - try testing.expect(fun(c.ADW_MAJOR_VERSION - 1, c.ADW_MINOR_VERSION, c.ADW_MICRO_VERSION + 1)); - try testing.expect(fun(c.ADW_MAJOR_VERSION, c.ADW_MINOR_VERSION - 1, c.ADW_MICRO_VERSION + 1)); + try testing.expect(fun(comptime_version.major, comptime_version.minor, comptime_version.patch)); + try testing.expect(!fun(comptime_version.major, comptime_version.minor, comptime_version.patch + 1)); + try testing.expect(!fun(comptime_version.major, comptime_version.minor + 1, comptime_version.patch)); + try testing.expect(!fun(comptime_version.major + 1, comptime_version.minor, comptime_version.patch)); + try testing.expect(fun(comptime_version.major - 1, comptime_version.minor, comptime_version.patch)); + try testing.expect(fun(comptime_version.major - 1, comptime_version.minor + 1, comptime_version.patch)); + try testing.expect(fun(comptime_version.major - 1, comptime_version.minor, comptime_version.patch + 1)); + try testing.expect(fun(comptime_version.major, comptime_version.minor - 1, comptime_version.patch + 1)); } } diff --git a/src/apprt/gtk/build/blueprint.zig b/src/apprt/gtk/build/blueprint.zig index 4920ce6f8..a4524e8ed 100644 --- a/src/apprt/gtk/build/blueprint.zig +++ b/src/apprt/gtk/build/blueprint.zig @@ -7,10 +7,6 @@ const std = @import("std"); -pub const c = @cImport({ - @cInclude("adwaita.h"); -}); - pub const blueprint_compiler_help = \\ \\When building from a Git checkout, Ghostty requires @@ -25,24 +21,21 @@ pub const blueprint_compiler_help = \\more information on the recommended build instructions. ; -const adwaita_version = std.SemanticVersion{ - .major = c.ADW_MAJOR_VERSION, - .minor = c.ADW_MINOR_VERSION, - .patch = c.ADW_MICRO_VERSION, -}; +const adwaita_version = @import("adw_semver").version; + const required_blueprint_version = std.SemanticVersion{ .major = 0, .minor = 16, .patch = 0, }; -pub fn main() !void { +pub fn main(init: std.process.Init) !void { var debug_allocator: std.heap.DebugAllocator(.{}) = .init; defer _ = debug_allocator.deinit(); const alloc = debug_allocator.allocator(); // Get our args - var it = try std.process.argsWithAllocator(alloc); + var it = try init.minimal.args.iterateAllocator(alloc); defer it.deinit(); _ = it.next(); // Skip argv0 const arg_major = it.next() orelse return error.NoMajorVersion; @@ -63,51 +56,37 @@ pub fn main() !void { \\compile this blueprint. Please install it, ensure that it is \\available on your PATH, and then retry building Ghostty. , .{required_adwaita_version}); - std.posix.exit(1); + std.process.exit(1); } // Version checks { - var stdout: std.ArrayListUnmanaged(u8) = .empty; - defer stdout.deinit(alloc); - var stderr: std.ArrayListUnmanaged(u8) = .empty; - defer stderr.deinit(alloc); - - var blueprint_compiler = std.process.Child.init( - &.{ - "blueprint-compiler", - "--version", - }, - alloc, - ); - blueprint_compiler.stdout_behavior = .Pipe; - blueprint_compiler.stderr_behavior = .Pipe; - try blueprint_compiler.spawn(); - try blueprint_compiler.collectOutput( - alloc, - &stdout, - &stderr, - std.math.maxInt(u16), - ); - const term = blueprint_compiler.wait() catch |err| switch (err) { + const blueprint_compiler = std.process.run(alloc, init.io, .{ + .argv = &.{ "blueprint-compiler", "--version" }, + }) catch |err| switch (err) { error.FileNotFound => { std.debug.print( \\`blueprint-compiler` not found. ++ blueprint_compiler_help, .{required_blueprint_version}, ); - std.posix.exit(1); + std.process.exit(1); }, else => return err, }; - switch (term) { - .Exited => |rc| if (rc != 0) std.process.exit(1), + defer { + alloc.free(blueprint_compiler.stdout); + alloc.free(blueprint_compiler.stderr); + } + + switch (blueprint_compiler.term) { + .exited => |rc| if (rc != 0) std.process.exit(1), else => std.process.exit(1), } const version = try std.SemanticVersion.parse(std.mem.trim( u8, - stdout.items, + blueprint_compiler.stdout, &std.ascii.whitespace, )); if (version.order(required_blueprint_version) == .lt) { @@ -116,57 +95,45 @@ pub fn main() !void { ++ blueprint_compiler_help, .{required_blueprint_version}, ); - std.posix.exit(1); + std.process.exit(1); } } // Compilation { - var stdout: std.ArrayListUnmanaged(u8) = .empty; - defer stdout.deinit(alloc); - var stderr: std.ArrayListUnmanaged(u8) = .empty; - defer stderr.deinit(alloc); - - var blueprint_compiler = std.process.Child.init( - &.{ + const blueprint_compiler = std.process.run(alloc, init.io, .{ + .argv = &.{ "blueprint-compiler", "compile", "--output", output, input, }, - alloc, - ); - blueprint_compiler.stdout_behavior = .Pipe; - blueprint_compiler.stderr_behavior = .Pipe; - try blueprint_compiler.spawn(); - try blueprint_compiler.collectOutput( - alloc, - &stdout, - &stderr, - std.math.maxInt(u16), - ); - const term = blueprint_compiler.wait() catch |err| switch (err) { + }) catch |err| switch (err) { error.FileNotFound => { std.debug.print( \\`blueprint-compiler` not found. ++ blueprint_compiler_help, .{required_blueprint_version}, ); - std.posix.exit(1); + std.process.exit(1); }, else => return err, }; + defer { + alloc.free(blueprint_compiler.stdout); + alloc.free(blueprint_compiler.stderr); + } - switch (term) { - .Exited => |rc| { + switch (blueprint_compiler.term) { + .exited => |rc| { if (rc != 0) { - std.debug.print("{s}", .{stderr.items}); + std.debug.print("{s}", .{blueprint_compiler.stderr}); std.process.exit(1); } }, else => { - std.debug.print("{s}", .{stderr.items}); + std.debug.print("{s}", .{blueprint_compiler.stderr}); std.process.exit(1); }, } diff --git a/src/apprt/gtk/build/gresource.zig b/src/apprt/gtk/build/gresource.zig index c50ea8cd5..57c32a353 100644 --- a/src/apprt/gtk/build/gresource.zig +++ b/src/apprt/gtk/build/gresource.zig @@ -122,18 +122,17 @@ pub fn blueprint(comptime bp: Blueprint) [:0]const u8 { } } -pub fn main() !void { - var debug_allocator: std.heap.DebugAllocator(.{}) = .init; - defer _ = debug_allocator.deinit(); - const alloc = debug_allocator.allocator(); +pub fn main(init: std.process.Init) !void { + const alloc = init.arena.allocator(); // Collect the UI files that are passed in as arguments. - var ui_files: std.ArrayListUnmanaged([]const u8) = .empty; + var ui_files: std.ArrayList([]const u8) = .empty; defer { for (ui_files.items) |item| alloc.free(item); ui_files.deinit(alloc); } - var it = try std.process.argsWithAllocator(alloc); + + var it = try init.minimal.args.iterateAllocator(alloc); defer it.deinit(); while (it.next()) |arg| { if (!std.mem.endsWith(u8, arg, ".ui")) continue; @@ -144,7 +143,7 @@ pub fn main() !void { } var buf: [4096]u8 = undefined; - var stdout = std.fs.File.stdout().writer(&buf); + var stdout = std.Io.File.stdout().writer(init.io, &buf); const writer = &stdout.interface; try writer.writeAll( \\ @@ -152,8 +151,8 @@ pub fn main() !void { \\ ); - try genRoot(writer); - try genIcons(writer); + try genRoot(init.io, writer); + try genIcons(init.io, writer); try genUi(alloc, writer, &ui_files); try writer.writeAll( @@ -167,19 +166,19 @@ pub fn main() !void { /// Generate the icon resources. This works by looking up all the icons /// specified by `icon_sizes` in `images/icons/`. They are asserted to exist /// by trying to access the file. -fn genIcons(writer: *std.Io.Writer) !void { +fn genIcons(io: std.Io, writer: *std.Io.Writer) !void { try writer.print( \\ \\ , .{build_info.resource_path}); - const cwd = std.fs.cwd(); + const cwd: std.Io.Dir = .cwd(); inline for (icon_sizes) |size| { // 1x { const alias = std.fmt.comptimePrint("{d}x{d}", .{ size, size }); const source = std.fmt.comptimePrint("images/gnome/{d}.png", .{size}); - try cwd.access(source, .{}); + try cwd.access(io, source, .{}); try writer.print( \\ {s} \\ @@ -192,7 +191,7 @@ fn genIcons(writer: *std.Io.Writer) !void { { const alias = std.fmt.comptimePrint("{d}x{d}@2", .{ size, size }); const source = std.fmt.comptimePrint("images/gnome/{d}.png", .{size * 2}); - try cwd.access(source, .{}); + try cwd.access(io, source, .{}); try writer.print( \\ {s} \\ @@ -209,19 +208,19 @@ fn genIcons(writer: *std.Io.Writer) !void { } /// Generate the resources at the root prefix. -fn genRoot(writer: *std.Io.Writer) !void { +fn genRoot(io: std.Io, writer: *std.Io.Writer) !void { try writer.print( \\ \\ , .{build_info.resource_path}); - const cwd = std.fs.cwd(); + const cwd: std.Io.Dir = .cwd(); inline for (css) |name| { const source = std.fmt.comptimePrint( "{s}/{s}", .{ css_path, name }, ); - try cwd.access(source, .{}); + try cwd.access(io, source, .{}); try writer.print( \\ {s} \\ @@ -242,7 +241,7 @@ fn genRoot(writer: *std.Io.Writer) !void { fn genUi( alloc: Allocator, writer: *std.Io.Writer, - files: *const std.ArrayListUnmanaged([]const u8), + files: *const std.ArrayList([]const u8), ) !void { try writer.print( \\ diff --git a/src/apprt/gtk/class.zig b/src/apprt/gtk/class.zig index 942666cf4..dbf3ae8d1 100644 --- a/src/apprt/gtk/class.zig +++ b/src/apprt/gtk/class.zig @@ -145,16 +145,24 @@ pub fn Common( /// as the virtual method but the self parameter points to the /// target instead of the original class. fn ImplementFunc(comptime T: type) type { - var params: [fn_info.params.len]std.builtin.Type.Fn.Param = undefined; - @memcpy(¶ms, fn_info.params); - params[0].type = *ClassInstance(T); - return @Type(.{ .@"fn" = .{ - .calling_convention = fn_info.calling_convention, - .is_generic = fn_info.is_generic, - .is_var_args = fn_info.is_var_args, - .return_type = fn_info.return_type, - .params = ¶ms, - } }); + var types: [fn_info.params.len]type = undefined; + var attrs: [fn_info.params.len]std.builtin.Type.Fn.Param.Attributes = undefined; + + for (fn_info.params, &types, &attrs) |info, *ty, *attr| { + ty.* = info.type.?; + attr.* = .{ .@"noalias" = info.is_noalias }; + } + types[0] = *ClassInstance(T); + + return @Fn( + types, + &attrs, + fn_info.return_type.?, + .{ + .@"callconv" = fn_info.calling_convention, + .varargs = fn_info.is_var_args, + }, + ); } }; } diff --git a/src/apprt/gtk/class/application.zig b/src/apprt/gtk/class/application.zig index 873674cec..43d60bac0 100644 --- a/src/apprt/gtk/class/application.zig +++ b/src/apprt/gtk/class/application.zig @@ -338,7 +338,7 @@ pub const Application = extern struct { // I'm unsure of any scenario where this happens. Because we don't // want to litter null checks everywhere, we just exit here. log.warn("gdk display is null, exiting", .{}); - std.posix.exit(1); + std.process.exit(1); }; // Setup our windowing protocol logic @@ -2831,7 +2831,7 @@ const Action = struct { /// given the runtime environment or configuration. /// /// This must be called BEFORE GTK initialization. -fn setGtkEnv(config: *const CoreConfig) error{NoSpaceLeft}!void { +fn setGtkEnv(config: *const CoreConfig) std.Io.Writer.Error!void { assert(gtk.isInitialized() == 0); var gdk_debug: struct { @@ -2900,8 +2900,7 @@ fn setGtkEnv(config: *const CoreConfig) error{NoSpaceLeft}!void { { var buf: [1024]u8 = undefined; - var fmt = std.io.fixedBufferStream(&buf); - const writer = fmt.writer(); + var writer: std.Io.Writer = .fixed(&buf); var first: bool = true; inline for (@typeInfo(@TypeOf(gdk_debug)).@"struct".fields) |field| { if (@field(gdk_debug, field.name)) { @@ -2911,15 +2910,14 @@ fn setGtkEnv(config: *const CoreConfig) error{NoSpaceLeft}!void { } } try writer.writeByte(0); - const value = fmt.getWritten(); + const value = writer.buffered(); log.warn("setting GDK_DEBUG={s}", .{value[0 .. value.len - 1]}); _ = internal_os.setenv("GDK_DEBUG", value[0 .. value.len - 1 :0]); } { var buf: [1024]u8 = undefined; - var fmt = std.io.fixedBufferStream(&buf); - const writer = fmt.writer(); + var writer: std.Io.Writer = .fixed(&buf); var first: bool = true; inline for (@typeInfo(@TypeOf(gdk_disable)).@"struct".fields) |field| { if (@field(gdk_disable, field.name)) { @@ -2929,7 +2927,7 @@ fn setGtkEnv(config: *const CoreConfig) error{NoSpaceLeft}!void { } } try writer.writeByte(0); - const value = fmt.getWritten(); + const value = writer.buffered(); log.warn("setting GDK_DISABLE={s}", .{value[0 .. value.len - 1]}); _ = internal_os.setenv("GDK_DISABLE", value[0 .. value.len - 1 :0]); } diff --git a/src/apprt/gtk/ext/actions.zig b/src/apprt/gtk/ext/actions.zig index 3232bc18b..6ba9c678b 100644 --- a/src/apprt/gtk/ext/actions.zig +++ b/src/apprt/gtk/ext/actions.zig @@ -176,7 +176,11 @@ test "adding actions to an object" { _ = addAsGroup(gtk.Box, box, "test", &actions); } - const expected = std.crypto.random.intRangeAtMost(i32, 1, std.math.maxInt(u31)); + const expected = expected: { + const rng_impl: std.Random.IoSource = .{ .io = testing.io }; + const rng = rng_impl.interface(); + break :expected rng.intRangeAtMost(i32, 1, std.math.maxInt(u31)); + }; const parameter = glib.Variant.newInt32(expected); try testing.expect(box.as(gtk.Widget).activateActionVariant("test.test", parameter) != 0); diff --git a/src/apprt/gtk/gtk_version.zig b/src/apprt/gtk/gtk_version.zig index 71edb076d..fa67a4106 100644 --- a/src/apprt/gtk/gtk_version.zig +++ b/src/apprt/gtk/gtk_version.zig @@ -1,21 +1,16 @@ const std = @import("std"); -// Until the gobject bindings are built at the same time we are building -// Ghostty, we need to import `gtk/gtk.h` directly to ensure that the version -// macros match the version of `gtk4` that we are building/linking against. -const c = @cImport({ - @cInclude("gtk/gtk.h"); -}); - const gtk = @import("gtk"); const log = std.log.scoped(.gtk); -pub const comptime_version: std.SemanticVersion = .{ - .major = c.GTK_MAJOR_VERSION, - .minor = c.GTK_MINOR_VERSION, - .patch = c.GTK_MICRO_VERSION, -}; +// Until the gobject bindings are built at the same time we are building +// Ghostty, we need to ensure that the version macros match the version of +// `gtk4` that we are building/linking against. +// +// We pull this in through pkg-config, see src/build/SharedDeps.zig for more +// details. +pub const comptime_version = @import("gtk_semver").version; pub fn getRuntimeVersion() std.SemanticVersion { return .{ @@ -105,17 +100,17 @@ test "atLeast" { const funs = &.{ atLeast, runtimeAtLeast }; inline for (funs) |fun| { - try testing.expect(fun(c.GTK_MAJOR_VERSION, c.GTK_MINOR_VERSION, c.GTK_MICRO_VERSION)); + try testing.expect(fun(comptime_version.major, comptime_version.minor, comptime_version.patch)); - try testing.expect(!fun(c.GTK_MAJOR_VERSION, c.GTK_MINOR_VERSION, c.GTK_MICRO_VERSION + 1)); - try testing.expect(!fun(c.GTK_MAJOR_VERSION, c.GTK_MINOR_VERSION + 1, c.GTK_MICRO_VERSION)); - try testing.expect(!fun(c.GTK_MAJOR_VERSION + 1, c.GTK_MINOR_VERSION, c.GTK_MICRO_VERSION)); + try testing.expect(!fun(comptime_version.major, comptime_version.minor, comptime_version.patch + 1)); + try testing.expect(!fun(comptime_version.major, comptime_version.minor + 1, comptime_version.patch)); + try testing.expect(!fun(comptime_version.major + 1, comptime_version.minor, comptime_version.patch)); - try testing.expect(fun(c.GTK_MAJOR_VERSION - 1, c.GTK_MINOR_VERSION, c.GTK_MICRO_VERSION)); - try testing.expect(fun(c.GTK_MAJOR_VERSION - 1, c.GTK_MINOR_VERSION + 1, c.GTK_MICRO_VERSION)); - try testing.expect(fun(c.GTK_MAJOR_VERSION - 1, c.GTK_MINOR_VERSION, c.GTK_MICRO_VERSION + 1)); + try testing.expect(fun(comptime_version.major - 1, comptime_version.minor, comptime_version.patch)); + try testing.expect(fun(comptime_version.major - 1, comptime_version.minor + 1, comptime_version.patch)); + try testing.expect(fun(comptime_version.major - 1, comptime_version.minor, comptime_version.patch + 1)); - try testing.expect(fun(c.GTK_MAJOR_VERSION, c.GTK_MINOR_VERSION - 1, c.GTK_MICRO_VERSION + 1)); + try testing.expect(fun(comptime_version.major, comptime_version.minor - 1, comptime_version.patch + 1)); } } @@ -125,16 +120,16 @@ test "runtimeUntil" { // This is an array in case we add a comptime variant. const funs = &.{runtimeUntil}; inline for (funs) |fun| { - try testing.expect(!fun(c.GTK_MAJOR_VERSION, c.GTK_MINOR_VERSION, c.GTK_MICRO_VERSION)); + try testing.expect(!fun(comptime_version.major, comptime_version.minor, comptime_version.patch)); - try testing.expect(fun(c.GTK_MAJOR_VERSION, c.GTK_MINOR_VERSION, c.GTK_MICRO_VERSION + 1)); - try testing.expect(fun(c.GTK_MAJOR_VERSION, c.GTK_MINOR_VERSION + 1, c.GTK_MICRO_VERSION)); - try testing.expect(fun(c.GTK_MAJOR_VERSION + 1, c.GTK_MINOR_VERSION, c.GTK_MICRO_VERSION)); + try testing.expect(fun(comptime_version.major, comptime_version.minor, comptime_version.patch + 1)); + try testing.expect(fun(comptime_version.major, comptime_version.minor + 1, comptime_version.patch)); + try testing.expect(fun(comptime_version.major + 1, comptime_version.minor, comptime_version.patch)); - try testing.expect(!fun(c.GTK_MAJOR_VERSION - 1, c.GTK_MINOR_VERSION, c.GTK_MICRO_VERSION)); - try testing.expect(!fun(c.GTK_MAJOR_VERSION - 1, c.GTK_MINOR_VERSION + 1, c.GTK_MICRO_VERSION)); - try testing.expect(!fun(c.GTK_MAJOR_VERSION - 1, c.GTK_MINOR_VERSION, c.GTK_MICRO_VERSION + 1)); + try testing.expect(!fun(comptime_version.major - 1, comptime_version.minor, comptime_version.patch)); + try testing.expect(!fun(comptime_version.major - 1, comptime_version.minor + 1, comptime_version.patch)); + try testing.expect(!fun(comptime_version.major - 1, comptime_version.minor, comptime_version.patch + 1)); - try testing.expect(!fun(c.GTK_MAJOR_VERSION, c.GTK_MINOR_VERSION - 1, c.GTK_MICRO_VERSION + 1)); + try testing.expect(!fun(comptime_version.major, comptime_version.minor - 1, comptime_version.patch + 1)); } } diff --git a/src/apprt/gtk/ipc/DBus.zig b/src/apprt/gtk/ipc/DBus.zig index fa4a6723e..76e3c1ad1 100644 --- a/src/apprt/gtk/ipc/DBus.zig +++ b/src/apprt/gtk/ipc/DBus.zig @@ -28,10 +28,12 @@ payload_builder: *glib.VariantBuilder, /// Used to build the parameters for the IPC. parameters_builder: *glib.VariantBuilder, +pub const InitError = Allocator.Error || std.Io.Writer.Error || apprt.ipc.Errors; + /// Initialize the helper. -pub fn init(alloc: Allocator, target: apprt.ipc.Target, action: [:0]const u8) (Allocator.Error || std.Io.Writer.Error || apprt.ipc.Errors)!Self { +pub fn init(alloc: Allocator, target: apprt.ipc.Target, action: [:0]const u8) InitError!Self { var buf: [256]u8 = undefined; - var stderr_writer = std.fs.File.stderr().writer(&buf); + var stderr_writer = std.Io.File.stderr().writer(std.Io.Threaded.global_single_threaded.io(), &buf); const stderr = &stderr_writer.interface; // Get the appropriate bus name and object path for contacting the @@ -133,7 +135,7 @@ pub fn addParameter(self: *Self, variant: *glib.Variant) void { /// should be done with this object other than call `deinit`. pub fn send(self: *Self) (std.Io.Writer.Error || apprt.ipc.Errors)!void { var buf: [256]u8 = undefined; - var stderr_writer = std.fs.File.stderr().writer(&buf); + var stderr_writer = std.Io.File.stderr().writer(std.Io.Threaded.global_single_threaded.io(), &buf); const stderr = &stderr_writer.interface; // finish building the parameters diff --git a/src/apprt/gtk/portal/OpenURI.zig b/src/apprt/gtk/portal/OpenURI.zig index 97aa013e5..3acb5bf0f 100644 --- a/src/apprt/gtk/portal/OpenURI.zig +++ b/src/apprt/gtk/portal/OpenURI.zig @@ -23,7 +23,7 @@ app: *App, dbus: ?*gio.DBusConnection = null, /// Mutex to protect modification of the entries map or the cleanup timer. -mutex: std.Thread.Mutex = .{}, +mutex: std.Io.Mutex = .init, /// Map to store data about any in-flight calls to the portal. entries: std.AutoArrayHashMapUnmanaged(usize, *Entry) = .empty, diff --git a/src/apprt/ipc.zig b/src/apprt/ipc.zig index b37647e02..e4a3e41d1 100644 --- a/src/apprt/ipc.zig +++ b/src/apprt/ipc.zig @@ -122,8 +122,12 @@ pub const Action = union(enum) { /// Sync with: ghostty_ipc_action_u pub const CValue = cvalue: { const key_fields = @typeInfo(Key).@"enum".fields; - var union_fields: [key_fields.len]std.builtin.Type.UnionField = undefined; - for (key_fields, 0..) |field, i| { + + var names: [key_fields.len][]const u8 = undefined; + var types: [key_fields.len]type = undefined; + var attrs: [key_fields.len]std.builtin.Type.UnionField.Attributes = undefined; + + for (key_fields, &names, &types, &attrs) |field, *name, *ty, *attr| { const action = @unionInit(Action, field.name, undefined); const Type = t: { const Type = @TypeOf(@field(action, field.name)); @@ -131,20 +135,12 @@ pub const Action = union(enum) { if (Type != void and @hasDecl(Type, "C")) break :t Type.C; break :t Type; }; - - union_fields[i] = .{ - .name = field.name, - .type = Type, - .alignment = @alignOf(Type), - }; + name.* = field.name; + ty.* = Type; + attr.* = .{ .@"align" = @alignOf(Type) }; } - break :cvalue @Type(.{ .@"union" = .{ - .layout = .@"extern", - .tag_type = null, - .fields = &union_fields, - .decls = &.{}, - } }); + break :cvalue @Union(.@"extern", null, &names, &types, &attrs); }; /// Sync with: ghostty_ipc_action_s diff --git a/src/benchmark/Benchmark.zig b/src/benchmark/Benchmark.zig index 41c3695d4..fa7de241b 100644 --- a/src/benchmark/Benchmark.zig +++ b/src/benchmark/Benchmark.zig @@ -64,21 +64,23 @@ pub fn run( signpost.log.release(); }; - const start = std.time.Instant.now() catch return error.BenchmarkFailed; + const start: std.Io.Timestamp = .now(std.Io.Threaded.global_single_threaded.io(), .awake); while (true) { // Run our step function. If it fails, we return the error. try self.vtable.stepFn(self.ptr); result.iterations += 1; // Get our current monotonic time and check our exit conditions. - const now = std.time.Instant.now() catch return error.BenchmarkFailed; + const now: std.Io.Timestamp = .now(std.Io.Threaded.global_single_threaded.io(), .awake); + const elapsed = start.durationTo(now).nanoseconds; + assert(elapsed >= 0); const exit = switch (mode) { .once => true, - .duration => |ns| now.since(start) >= ns, + .duration => |ns| elapsed >= ns, }; if (exit) { - result.duration = now.since(start); + result.duration = @as(u64, @intCast(std.math.clamp(elapsed, 0, std.math.maxInt(u64)))); return result; } } diff --git a/src/benchmark/CodepointWidth.zig b/src/benchmark/CodepointWidth.zig index 30d3f91e7..ca9174ed6 100644 --- a/src/benchmark/CodepointWidth.zig +++ b/src/benchmark/CodepointWidth.zig @@ -20,7 +20,7 @@ const log = std.log.scoped(.@"terminal-stream-bench"); opts: Options, /// The file, opened in the setup function. -data_f: ?std.fs.File = null, +data_f: ?std.Io.File = null, pub const Options = struct { /// The type of codepoint width calculation to use. @@ -93,7 +93,7 @@ fn setup(ptr: *anyopaque) Benchmark.Error!void { fn teardown(ptr: *anyopaque) void { const self: *CodepointWidth = @ptrCast(@alignCast(ptr)); if (self.data_f) |f| { - f.close(); + f.close(std.Io.Threaded.global_single_threaded.io()); self.data_f = null; } } @@ -114,7 +114,7 @@ fn stepWcwidth(ptr: *anyopaque) Benchmark.Error!void { const f = self.data_f orelse return; var read_buf: [4096]u8 align(std.atomic.cache_line) = undefined; - var f_reader = f.reader(&read_buf); + var f_reader = f.reader(std.Io.Threaded.global_single_threaded.io(), &read_buf); var r = &f_reader.interface; var d: UTF8Decoder = .{}; @@ -141,7 +141,7 @@ fn stepTable(ptr: *anyopaque) Benchmark.Error!void { const f = self.data_f orelse return; var read_buf: [4096]u8 align(std.atomic.cache_line) = undefined; - var f_reader = f.reader(&read_buf); + var f_reader = f.reader(std.Io.Threaded.global_single_threaded.io(), &read_buf); var r = &f_reader.interface; var d: UTF8Decoder = .{}; @@ -173,7 +173,7 @@ fn stepSimd(ptr: *anyopaque) Benchmark.Error!void { const f = self.data_f orelse return; var read_buf: [4096]u8 align(std.atomic.cache_line) = undefined; - var f_reader = f.reader(&read_buf); + var f_reader = f.reader(std.Io.Threaded.global_single_threaded.io(), &read_buf); var r = &f_reader.interface; var d: UTF8Decoder = .{}; diff --git a/src/benchmark/GraphemeBreak.zig b/src/benchmark/GraphemeBreak.zig index 8278c5c2f..5e320ea19 100644 --- a/src/benchmark/GraphemeBreak.zig +++ b/src/benchmark/GraphemeBreak.zig @@ -17,7 +17,7 @@ const log = std.log.scoped(.@"terminal-stream-bench"); opts: Options, /// The file, opened in the setup function. -data_f: ?std.fs.File = null, +data_f: ?std.Io.File = null, pub const Options = struct { /// The type of codepoint width calculation to use. @@ -82,7 +82,7 @@ fn setup(ptr: *anyopaque) Benchmark.Error!void { fn teardown(ptr: *anyopaque) void { const self: *GraphemeBreak = @ptrCast(@alignCast(ptr)); if (self.data_f) |f| { - f.close(); + f.close(std.Io.Threaded.global_single_threaded.io()); self.data_f = null; } } @@ -92,7 +92,7 @@ fn stepNoop(ptr: *anyopaque) Benchmark.Error!void { const f = self.data_f orelse return; var read_buf: [4096]u8 align(std.atomic.cache_line) = undefined; - var f_reader = f.reader(&read_buf); + var f_reader = f.reader(std.Io.Threaded.global_single_threaded.io(), &read_buf); var r = &f_reader.interface; var d: UTF8Decoder = .{}; @@ -115,7 +115,7 @@ fn stepTable(ptr: *anyopaque) Benchmark.Error!void { const f = self.data_f orelse return; var read_buf: [4096]u8 align(std.atomic.cache_line) = undefined; - var f_reader = f.reader(&read_buf); + var f_reader = f.reader(std.Io.Threaded.global_single_threaded.io(), &read_buf); var r = &f_reader.interface; var d: UTF8Decoder = .{}; diff --git a/src/benchmark/IsSymbol.zig b/src/benchmark/IsSymbol.zig index 4fbffd1ec..8204f00a3 100644 --- a/src/benchmark/IsSymbol.zig +++ b/src/benchmark/IsSymbol.zig @@ -17,7 +17,7 @@ const log = std.log.scoped(.@"is-symbol-bench"); opts: Options, /// The file, opened in the setup function. -data_f: ?std.fs.File = null, +data_f: ?std.Io.File = null, pub const Options = struct { /// Which test to run. @@ -80,7 +80,7 @@ fn setup(ptr: *anyopaque) Benchmark.Error!void { fn teardown(ptr: *anyopaque) void { const self: *IsSymbol = @ptrCast(@alignCast(ptr)); if (self.data_f) |f| { - f.close(); + f.close(std.Io.Threaded.global_single_threaded.io()); self.data_f = null; } } @@ -90,7 +90,7 @@ fn stepUucode(ptr: *anyopaque) Benchmark.Error!void { const f = self.data_f orelse return; var read_buf: [4096]u8 align(std.atomic.cache_line) = undefined; - var f_reader = f.reader(&read_buf); + var f_reader = f.reader(std.Io.Threaded.global_single_threaded.io(), &read_buf); var r = &f_reader.interface; var d: UTF8Decoder = .{}; @@ -117,7 +117,7 @@ fn stepTable(ptr: *anyopaque) Benchmark.Error!void { const f = self.data_f orelse return; var read_buf: [4096]u8 align(std.atomic.cache_line) = undefined; - var f_reader = f.reader(&read_buf); + var f_reader = f.reader(std.Io.Threaded.global_single_threaded.io(), &read_buf); var r = &f_reader.interface; var d: UTF8Decoder = .{}; diff --git a/src/benchmark/OscParser.zig b/src/benchmark/OscParser.zig index d4b416de8..cd3273280 100644 --- a/src/benchmark/OscParser.zig +++ b/src/benchmark/OscParser.zig @@ -13,7 +13,7 @@ const log = std.log.scoped(.@"osc-parser-bench"); opts: Options, /// The file, opened in the setup function. -data_f: ?std.fs.File = null, +data_f: ?std.Io.File = null, parser: Parser, @@ -70,7 +70,7 @@ fn setup(ptr: *anyopaque) Benchmark.Error!void { fn teardown(ptr: *anyopaque) void { const self: *OscParser = @ptrCast(@alignCast(ptr)); if (self.data_f) |f| { - f.close(); + f.close(std.Io.Threaded.global_single_threaded.io()); self.data_f = null; } } @@ -80,7 +80,7 @@ fn step(ptr: *anyopaque) Benchmark.Error!void { const f = self.data_f orelse return; var read_buf: [4096]u8 align(std.atomic.cache_line) = undefined; - var r = f.reader(&read_buf); + var r = f.reader(std.Io.Threaded.global_single_threaded.io(), &read_buf); var osc_buf: [4096]u8 align(std.atomic.cache_line) = undefined; while (true) { diff --git a/src/benchmark/ScreenClone.zig b/src/benchmark/ScreenClone.zig index 108eaa0c6..b0dafff9a 100644 --- a/src/benchmark/ScreenClone.zig +++ b/src/benchmark/ScreenClone.zig @@ -99,7 +99,7 @@ fn setup(ptr: *anyopaque) Benchmark.Error!void { s.nextSlice("hello"); // Setup our terminal state - const data_f: std.fs.File = (options.dataFile( + const data_f: std.Io.File = (options.dataFile( self.opts.data, ) catch |err| { log.warn("error opening data file err={}", .{err}); @@ -110,7 +110,7 @@ fn setup(ptr: *anyopaque) Benchmark.Error!void { defer stream.deinit(); var read_buf: [4096]u8 align(std.atomic.cache_line) = undefined; - var f_reader = data_f.reader(&read_buf); + var f_reader = data_f.reader(std.Io.Threaded.global_single_threaded.io(), &read_buf); const r = &f_reader.interface; var buf: [4096]u8 = undefined; diff --git a/src/benchmark/TerminalParser.zig b/src/benchmark/TerminalParser.zig index 78c933121..49dc4b138 100644 --- a/src/benchmark/TerminalParser.zig +++ b/src/benchmark/TerminalParser.zig @@ -13,7 +13,7 @@ const log = std.log.scoped(.@"terminal-stream-bench"); opts: Options, /// The file, opened in the setup function. -data_f: ?std.fs.File = null, +data_f: ?std.Io.File = null, pub const Options = struct { /// The data to read as a filepath. If this is "-" then @@ -61,7 +61,7 @@ fn setup(ptr: *anyopaque) Benchmark.Error!void { fn teardown(ptr: *anyopaque) void { const self: *TerminalParser = @ptrCast(@alignCast(ptr)); if (self.data_f) |f| { - f.close(); + f.close(std.Io.Threaded.global_single_threaded.io()); self.data_f = null; } } @@ -76,7 +76,7 @@ fn step(ptr: *anyopaque) Benchmark.Error!void { // aren't currently IO bound. const f = self.data_f orelse return; var read_buf: [4096]u8 align(std.atomic.cache_line) = undefined; - var f_reader = f.reader(&read_buf); + var f_reader = f.reader(std.Io.Threaded.global_single_threaded.io(), &read_buf); var r = &f_reader.interface; var p: terminalpkg.Parser = .init(); diff --git a/src/benchmark/TerminalStream.zig b/src/benchmark/TerminalStream.zig index 1cac656e2..07ead9fe4 100644 --- a/src/benchmark/TerminalStream.zig +++ b/src/benchmark/TerminalStream.zig @@ -30,7 +30,7 @@ handler: Handler, stream: Stream, /// The file, opened in the setup function. -data_f: ?std.fs.File = null, +data_f: ?std.Io.File = null, pub const Options = struct { /// The size of the terminal. This affects benchmarking when @@ -99,7 +99,7 @@ fn setup(ptr: *anyopaque) Benchmark.Error!void { fn teardown(ptr: *anyopaque) void { const self: *TerminalStream = @ptrCast(@alignCast(ptr)); if (self.data_f) |f| { - f.close(); + f.close(std.Io.Threaded.global_single_threaded.io()); self.data_f = null; } } @@ -115,7 +115,7 @@ fn step(ptr: *anyopaque) Benchmark.Error!void { const f = self.data_f orelse return; var read_buf: [4096]u8 align(std.atomic.cache_line) = undefined; - var f_reader = f.reader(&read_buf); + var f_reader = f.reader(std.Io.Threaded.global_single_threaded.io(), &read_buf); const r = &f_reader.interface; var buf: [4096]u8 = undefined; diff --git a/src/benchmark/cli.zig b/src/benchmark/cli.zig index 13f070774..ef4185dbf 100644 --- a/src/benchmark/cli.zig +++ b/src/benchmark/cli.zig @@ -1,6 +1,8 @@ const std = @import("std"); const Allocator = std.mem.Allocator; const cli = @import("../cli.zig"); +const compat_args = @import("../lib/compat/args.zig"); +const compat_init = @import("../lib/compat/init.zig"); /// The available actions for the CLI. This is the list of available /// benchmarks. View docs for each individual one in the predictably @@ -36,7 +38,8 @@ pub const Action = enum { }; /// An entrypoint for the benchmark CLI. -pub fn main() !void { +pub fn main(init: std.process.Init.Minimal) !void { + compat_init.run(init); const alloc = std.heap.c_allocator; const action_ = try cli.action.detectArgs(Action, alloc); const action = action_ orelse return error.NoAction; @@ -48,7 +51,7 @@ pub const Args = union(enum) { /// The arguments passed to the CLI via argc/argv. cli, - /// Simple string arguments, parsed via std.process.ArgIteratorGeneral. + /// Simple string arguments, parsed via ArgIteratorGeneral. string: []const u8, }; @@ -81,7 +84,7 @@ fn mainActionImpl( try cli.args.parse(Options, alloc, &opts, &iter); }, .string => |str| { - var iter = try std.process.ArgIteratorGeneral(.{}).init( + var iter = try compat_args.ArgIteratorGeneral(.{}).init( alloc, str, ); diff --git a/src/benchmark/options.zig b/src/benchmark/options.zig index 049e80f48..a117259a2 100644 --- a/src/benchmark/options.zig +++ b/src/benchmark/options.zig @@ -6,15 +6,15 @@ const std = @import("std"); /// across our CLI. If the path is not set then no file is returned. /// If the path is "-", then we will return stdin. If the path is /// a file then we will open and return the handle. -pub fn dataFile(path_: ?[]const u8) !?std.fs.File { +pub fn dataFile(path_: ?[]const u8) !?std.Io.File { const path = path_ orelse return null; // Stdin if (std.mem.eql(u8, path, "-")) return .stdin(); // Normal file - const file = try std.fs.cwd().openFile(path, .{}); - errdefer file.close(); + const file = try std.Io.Dir.cwd().openFile(std.Io.Threaded.global_single_threaded.io(), path, .{}); + errdefer file.close(std.Io.Threaded.global_single_threaded.io()); return file; } diff --git a/src/build/Config.zig b/src/build/Config.zig index 0a9947317..dfb62512f 100644 --- a/src/build/Config.zig +++ b/src/build/Config.zig @@ -67,7 +67,7 @@ emit_unicode_table_gen: bool = false, is_dep: bool = false, /// Environmental properties -env: std.process.EnvMap, +env: *const std.process.Environ.Map, pub fn init(b: *std.Build, appVersion: []const u8, libVersion: []const u8) !Config { // Setup our standard Zig target and optimize options, i.e. @@ -124,10 +124,10 @@ pub fn init(b: *std.Build, appVersion: []const u8, libVersion: []const u8) !Conf // defaults. const gtk_targets = gtk.targets(b); - // We use env vars throughout the build so we grab them immediately here. - var env = try std.process.getEnvMap(b.allocator); - errdefer env.deinit(); + // Grab the environment from build state + const env = &b.graph.environ_map; + // We use env vars throughout the build so we grab them immediately here. var config: Config = .{ .optimize = optimize, .target = target, @@ -591,7 +591,7 @@ pub fn terminalOptions(self: *const Config, artifact: TerminalBuildOptions.Artif } /// Returns a baseline CPU target retaining all the other CPU configs. -pub fn baselineTarget(self: *const Config) std.Build.ResolvedTarget { +pub fn baselineTarget(self: *const Config, io: std.Io) std.Build.ResolvedTarget { // Set our cpu model as baseline. There may need to be other modifications // we need to make such as resetting CPU features but for now this works. var q = self.target.query; @@ -601,7 +601,7 @@ pub fn baselineTarget(self: *const Config) std.Build.ResolvedTarget { // handle the native case. return .{ .query = q, - .result = std.zig.system.resolveTargetQuery(q) catch + .result = std.zig.system.resolveTargetQuery(io, q) catch @panic("unable to resolve baseline query"), }; } diff --git a/src/build/GhosttyBench.zig b/src/build/GhosttyBench.zig index 27dda8809..fbf8029d2 100644 --- a/src/build/GhosttyBench.zig +++ b/src/build/GhosttyBench.zig @@ -23,9 +23,9 @@ pub fn init( // We always want our datagen to be fast because it // takes awhile to run. .optimize = .ReleaseFast, + .link_libc = true, }), }); - exe.linkLibC(); _ = try deps.add(exe); try steps.append(b.allocator, exe); } @@ -39,9 +39,9 @@ pub fn init( .target = deps.config.target, // We always want our benchmarks to be in release mode. .optimize = .ReleaseFast, + .link_libc = true, }), }); - exe.linkLibC(); _ = try deps.add(exe); try steps.append(b.allocator, exe); } diff --git a/src/build/GhosttyDist.zig b/src/build/GhosttyDist.zig index 448047f4b..fe8b863fb 100644 --- a/src/build/GhosttyDist.zig +++ b/src/build/GhosttyDist.zig @@ -237,11 +237,11 @@ pub const Resource = struct { /// Returns true if the dist path exists at build time. pub fn exists(self: *const Resource, b: *std.Build) bool { - if (b.build_root.handle.access(self.dist, .{})) { + if (b.build_root.handle.access(b.graph.io, self.dist, .{})) { // If we have a ".git" directory then we're a git checkout // and we never want to use the dist path. This shouldn't happen // so show a warning to the user. - if (b.build_root.handle.access(".git", .{})) { + if (b.build_root.handle.access(b.graph.io, ".git", .{})) { std.log.warn( "dist resource '{s}' should not be in a git checkout", .{self.dist}, diff --git a/src/build/GhosttyDocs.zig b/src/build/GhosttyDocs.zig index cd75fc061..2b207f237 100644 --- a/src/build/GhosttyDocs.zig +++ b/src/build/GhosttyDocs.zig @@ -50,7 +50,7 @@ pub fn init( generate_markdown.root_module.addOptions("build_options", generate_markdown_options); const generate_markdown_step = b.addRunArtifact(generate_markdown); - const markdown_output = generate_markdown_step.captureStdOut(); + const markdown_output = generate_markdown_step.captureStdOut(.{}); try steps.append(b.allocator, &b.addInstallFile( markdown_output, @@ -68,7 +68,7 @@ pub fn init( generate_html.addFileArg(markdown_output); try steps.append(b.allocator, &b.addInstallFile( - generate_html.captureStdOut(), + generate_html.captureStdOut(.{}), "share/ghostty/doc/" ++ manpage.name ++ "." ++ manpage.section ++ ".html", ).step); @@ -83,7 +83,7 @@ pub fn init( generate_manpage.addFileArg(markdown_output); try steps.append(b.allocator, &b.addInstallFile( - generate_manpage.captureStdOut(), + generate_manpage.captureStdOut(.{}), "share/man/man" ++ manpage.section ++ "/" ++ manpage.name ++ "." ++ manpage.section, ).step); } diff --git a/src/build/GhosttyExe.zig b/src/build/GhosttyExe.zig index caa564bf0..9d9d5072b 100644 --- a/src/build/GhosttyExe.zig +++ b/src/build/GhosttyExe.zig @@ -50,7 +50,7 @@ pub fn init(b: *std.Build, cfg: *const Config, deps: *const SharedDeps) !Ghostty switch (cfg.target.result.os.tag) { .windows => { exe.subsystem = .Windows; - exe.addWin32ResourceFile(.{ + exe.root_module.addWin32ResourceFile(.{ .file = b.path("dist/windows/ghostty.rc"), }); }, @@ -85,7 +85,7 @@ fn checkNixShell(exe: *std.Build.Step.Compile, cfg: *const Config) !void { if (!cfg.target.query.isNativeOs()) return; // Verify we're in NixOS - std.fs.accessAbsolute("/etc/NIXOS", .{}) catch return; + std.Io.Dir.accessAbsolute(exe.step.owner.graph.io, "/etc/NIXOS", .{}) catch return; // If we're in a nix shell, not a problem if (cfg.env.get("IN_NIX_SHELL") != null) return; diff --git a/src/build/GhosttyFrameData.zig b/src/build/GhosttyFrameData.zig index 8469759f9..be61f029f 100644 --- a/src/build/GhosttyFrameData.zig +++ b/src/build/GhosttyFrameData.zig @@ -40,16 +40,16 @@ pub fn distResources(b: *std.Build) struct { .name = "framegen", .root_module = b.createModule(.{ .target = b.graph.host, + .link_libc = true, }), }); - exe.addCSourceFile(.{ + exe.root_module.addCSourceFile(.{ .file = b.path("src/build/framegen/main.c"), .flags = &.{}, }); - exe.linkLibC(); if (b.systemIntegrationOption("zlib", .{})) { - exe.linkSystemLibrary2("zlib", .{ + exe.root_module.linkSystemLibrary("zlib", .{ .preferred_link_mode = .dynamic, .search_strategy = .mode_first, }); @@ -58,7 +58,7 @@ pub fn distResources(b: *std.Build) struct { .target = b.graph.host, .optimize = .ReleaseFast, })) |zlib_dep| { - exe.linkLibrary(zlib_dep.artifact("z")); + exe.root_module.linkLibrary(zlib_dep.artifact("z")); } } diff --git a/src/build/GhosttyI18n.zig b/src/build/GhosttyI18n.zig index 0874676cb..434c59a5d 100644 --- a/src/build/GhosttyI18n.zig +++ b/src/build/GhosttyI18n.zig @@ -34,7 +34,7 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyI18n { msgfmt.addFileArg(b.path("po/" ++ locale ++ ".po")); try steps.append(b.allocator, &b.addInstallFile( - msgfmt.captureStdOut(), + msgfmt.captureStdOut(.{}), std.fmt.comptimePrint( "share/locale/{s}/LC_MESSAGES/{s}.mo", .{ target_locale, domain }, @@ -103,14 +103,15 @@ fn createUpdateStep(b: *std.Build) !*std.Build.Step { } var gtk_dir = try b.build_root.handle.openDir( + b.graph.io, "src/apprt/gtk", .{ .iterate = true }, ); - defer gtk_dir.close(); + defer gtk_dir.close(b.graph.io); var walk = try gtk_dir.walk(b.allocator); defer walk.deinit(); - while (try walk.next()) |src| { + while (try walk.next(b.graph.io)) |src| { switch (src.kind) { .file => if (!std.mem.endsWith( u8, @@ -178,15 +179,15 @@ fn createUpdateStep(b: *std.Build) !*std.Build.Step { xgettext_merge.addFileArg(gtk_pot); const usf = b.addUpdateSourceFiles(); usf.addCopyFileToSource( - xgettext_merge.captureStdOut(), + xgettext_merge.captureStdOut(.{}), "po/" ++ domain ++ ".pot", ); inline for (locales) |locale| { const msgmerge = b.addSystemCommand(&.{ "msgmerge", "--quiet", "--no-fuzzy-matching" }); msgmerge.addFileArg(b.path("po/" ++ locale ++ ".po")); - msgmerge.addFileArg(xgettext_merge.captureStdOut()); - usf.addCopyFileToSource(msgmerge.captureStdOut(), "po/" ++ locale ++ ".po"); + msgmerge.addFileArg(xgettext_merge.captureStdOut(.{})); + usf.addCopyFileToSource(msgmerge.captureStdOut(.{}), "po/" ++ locale ++ ".po"); } return &usf.step; diff --git a/src/build/GhosttyLib.zig b/src/build/GhosttyLib.zig index b762da8bb..6fe28370c 100644 --- a/src/build/GhosttyLib.zig +++ b/src/build/GhosttyLib.zig @@ -29,12 +29,12 @@ pub fn initStatic( .strip = deps.config.strip, .omit_frame_pointer = deps.config.strip, .unwind_tables = if (deps.config.strip) .none else .sync, + .link_libc = true, }), // Fails on self-hosted x86_64 on macOS .use_llvm = true, }); - lib.linkLibC(); // These must be bundled since we're compiling into a static lib. // Otherwise, you get undefined symbol errors. @@ -72,6 +72,14 @@ pub fn initShared( b: *std.Build, deps: *const SharedDeps, ) !GhosttyLib { + // For dynamic linking, we prefer dynamic linking and to search by + // mode first. Mode first will search all paths for a dynamic library + // before falling back to static. + const dynamic_link_opts: std.Build.Module.LinkSystemLibraryOptions = .{ + .preferred_link_mode = .dynamic, + .search_strategy = .mode_first, + }; + const lib = b.addLibrary(.{ .name = "ghostty", .linkage = .dynamic, @@ -99,12 +107,12 @@ pub fn initShared( { // The CRT initialization code in msvcrt.lib calls __vcrt_initialize // and __acrt_initialize, which are in the static CRT libraries. - lib.linkSystemLibrary("libvcruntime"); + lib.root_module.linkSystemLibrary("libvcruntime", dynamic_link_opts); // ucrt.lib is in the Windows SDK 'ucrt' dir. Detect the SDK // installation and add the UCRT library path. const arch = deps.config.target.result.cpu.arch; - const sdk = std.zig.WindowsSdk.find(b.allocator, arch) catch null; + const sdk = std.zig.WindowsSdk.find(b.allocator, b.graph.io, arch, &b.graph.environ_map) catch null; if (sdk) |s| { if (s.windows10sdk) |w10| { const arch_str: []const u8 = switch (arch) { @@ -120,11 +128,11 @@ pub fn initShared( ) catch null; if (ucrt_lib_path) |path| { - lib.addLibraryPath(.{ .cwd_relative = path }); + lib.root_module.addLibraryPath(.{ .cwd_relative = path }); } } } - lib.linkSystemLibrary("libucrt"); + lib.root_module.linkSystemLibrary("libucrt", dynamic_link_opts); } // Get our debug symbols diff --git a/src/build/GhosttyResources.zig b/src/build/GhosttyResources.zig index 6f857655b..673c7e56a 100644 --- a/src/build/GhosttyResources.zig +++ b/src/build/GhosttyResources.zig @@ -21,9 +21,9 @@ pub fn init(b: *std.Build, cfg: *const Config, deps: *const SharedDeps) !Ghostty .strip = false, .omit_frame_pointer = false, .unwind_tables = .sync, + .link_libc = true, }), }); - build_data_exe.linkLibC(); deps.help_strings.addImport(build_data_exe); @@ -39,7 +39,7 @@ pub fn init(b: *std.Build, cfg: *const Config, deps: *const SharedDeps) !Ghostty const run = b.addRunArtifact(build_data_exe); run.addArg("+terminfo"); const wf = b.addWriteFiles(); - const source = wf.addCopyFile(run.captureStdOut(), "ghostty.terminfo"); + const source = wf.addCopyFile(run.captureStdOut(.{}), "ghostty.terminfo"); if (cfg.emit_terminfo) { const source_install = b.addInstallFile( @@ -63,8 +63,8 @@ pub fn init(b: *std.Build, cfg: *const Config, deps: *const SharedDeps) !Ghostty const run_step = RunStep.create(b, "infotocap"); run_step.addArg("infotocap"); run_step.addFileArg(source); - const out_source = run_step.captureStdOut(); - _ = run_step.captureStdErr(); // so we don't see stderr + const out_source = run_step.captureStdOut(.{}); + _ = run_step.captureStdErr(.{}); // so we don't see stderr const cap_install = b.addInstallFile( out_source, @@ -84,7 +84,7 @@ pub fn init(b: *std.Build, cfg: *const Config, deps: *const SharedDeps) !Ghostty const path = run_step.addOutputFileArg(terminfo_share_dir); run_step.addFileArg(source); - _ = run_step.captureStdErr(); // so we don't see stderr + _ = run_step.captureStdErr(.{}); // so we don't see stderr // Ensure that `share/terminfo` is a directory, otherwise the `cp // -R` will create a file named `share/terminfo` @@ -143,7 +143,7 @@ pub fn init(b: *std.Build, cfg: *const Config, deps: *const SharedDeps) !Ghostty const run = b.addRunArtifact(build_data_exe); run.addArg("+fish"); const wf = b.addWriteFiles(); - _ = wf.addCopyFile(run.captureStdOut(), "ghostty.fish"); + _ = wf.addCopyFile(run.captureStdOut(.{}), "ghostty.fish"); const install_step = b.addInstallDirectory(.{ .source_dir = wf.getDirectory(), @@ -158,7 +158,7 @@ pub fn init(b: *std.Build, cfg: *const Config, deps: *const SharedDeps) !Ghostty const run = b.addRunArtifact(build_data_exe); run.addArg("+zsh"); const wf = b.addWriteFiles(); - _ = wf.addCopyFile(run.captureStdOut(), "_ghostty"); + _ = wf.addCopyFile(run.captureStdOut(.{}), "_ghostty"); const install_step = b.addInstallDirectory(.{ .source_dir = wf.getDirectory(), @@ -173,7 +173,7 @@ pub fn init(b: *std.Build, cfg: *const Config, deps: *const SharedDeps) !Ghostty const run = b.addRunArtifact(build_data_exe); run.addArg("+bash"); const wf = b.addWriteFiles(); - _ = wf.addCopyFile(run.captureStdOut(), "ghostty.bash"); + _ = wf.addCopyFile(run.captureStdOut(.{}), "ghostty.bash"); const install_step = b.addInstallDirectory(.{ .source_dir = wf.getDirectory(), @@ -190,22 +190,22 @@ pub fn init(b: *std.Build, cfg: *const Config, deps: *const SharedDeps) !Ghostty { const run = b.addRunArtifact(build_data_exe); run.addArg("+vim-syntax"); - _ = wf.addCopyFile(run.captureStdOut(), "syntax/ghostty.vim"); + _ = wf.addCopyFile(run.captureStdOut(.{}), "syntax/ghostty.vim"); } { const run = b.addRunArtifact(build_data_exe); run.addArg("+vim-ftdetect"); - _ = wf.addCopyFile(run.captureStdOut(), "ftdetect/ghostty.vim"); + _ = wf.addCopyFile(run.captureStdOut(.{}), "ftdetect/ghostty.vim"); } { const run = b.addRunArtifact(build_data_exe); run.addArg("+vim-ftplugin"); - _ = wf.addCopyFile(run.captureStdOut(), "ftplugin/ghostty.vim"); + _ = wf.addCopyFile(run.captureStdOut(.{}), "ftplugin/ghostty.vim"); } { const run = b.addRunArtifact(build_data_exe); run.addArg("+vim-compiler"); - _ = wf.addCopyFile(run.captureStdOut(), "compiler/ghostty.vim"); + _ = wf.addCopyFile(run.captureStdOut(.{}), "compiler/ghostty.vim"); } const vim_step = b.addInstallDirectory(.{ @@ -233,7 +233,7 @@ pub fn init(b: *std.Build, cfg: *const Config, deps: *const SharedDeps) !Ghostty const run = b.addRunArtifact(build_data_exe); run.addArg("+sublime"); const wf = b.addWriteFiles(); - _ = wf.addCopyFile(run.captureStdOut(), "ghostty.sublime-syntax"); + _ = wf.addCopyFile(run.captureStdOut(.{}), "ghostty.sublime-syntax"); const install_step = b.addInstallDirectory(.{ .source_dir = wf.getDirectory(), @@ -358,10 +358,10 @@ fn addLinuxAppResources( // Template output has a single header line we want to remove. // We use `tail` to do it since its part of the POSIX standard. const tail = b.addSystemCommand(&.{ "tail", "-n", "+2" }); - tail.setStdIn(.{ .lazy_path = tpl.getOutput() }); + tail.setStdIn(.{ .lazy_path = tpl.getOutputFile() }); const copy = b.addInstallFile( - tail.captureStdOut(), + tail.captureStdOut(.{}), template[1], ); diff --git a/src/build/GhosttyWebdata.zig b/src/build/GhosttyWebdata.zig index e29b20c25..7057ad034 100644 --- a/src/build/GhosttyWebdata.zig +++ b/src/build/GhosttyWebdata.zig @@ -40,7 +40,7 @@ pub fn init( } const webgen_config_step = b.addRunArtifact(webgen_config); - const webgen_config_out = webgen_config_step.captureStdOut(); + const webgen_config_out = webgen_config_step.captureStdOut(.{}); try steps.append(b.allocator, &b.addInstallFile( webgen_config_out, @@ -71,7 +71,7 @@ pub fn init( } const webgen_actions_step = b.addRunArtifact(webgen_actions); - const webgen_actions_out = webgen_actions_step.captureStdOut(); + const webgen_actions_out = webgen_actions_step.captureStdOut(.{}); try steps.append(b.allocator, &b.addInstallFile( webgen_actions_out, @@ -102,7 +102,7 @@ pub fn init( } const webgen_commands_step = b.addRunArtifact(webgen_commands); - const webgen_commands_out = webgen_commands_step.captureStdOut(); + const webgen_commands_out = webgen_commands_step.captureStdOut(.{}); try steps.append(b.allocator, &b.addInstallFile( webgen_commands_out, diff --git a/src/build/GhosttyXcodebuild.zig b/src/build/GhosttyXcodebuild.zig index 81af994ca..6f7e18dc3 100644 --- a/src/build/GhosttyXcodebuild.zig +++ b/src/build/GhosttyXcodebuild.zig @@ -48,21 +48,21 @@ pub fn init( }, }; - const env = try std.process.getEnvMap(b.allocator); + const env = b.graph.environ_map; const app_path = b.fmt("macos/build/{s}/Ghostty.app", .{xc_config}); // Our step to build the Ghostty macOS app. const build = build: { // External environment variables can mess up xcodebuild, so // we create a new empty environment. - const env_map = try b.allocator.create(std.process.EnvMap); + const env_map = try b.allocator.create(std.process.Environ.Map); env_map.* = .init(b.allocator); if (env.get("PATH")) |v| try env_map.put("PATH", v); const step = RunStep.create(b, "xcodebuild"); step.has_side_effects = true; step.cwd = b.path("macos"); - step.env_map = env_map; + step.environ_map = env_map; step.addArgs(&.{ "xcodebuild", "-target", @@ -91,14 +91,14 @@ pub fn init( }; const xctest = xctest: { - const env_map = try b.allocator.create(std.process.EnvMap); + const env_map = try b.allocator.create(std.process.Environ.Map); env_map.* = .init(b.allocator); if (env.get("PATH")) |v| try env_map.put("PATH", v); const step = RunStep.create(b, "xcodebuild test"); step.has_side_effects = true; step.cwd = b.path("macos"); - step.env_map = env_map; + step.environ_map = env_map; step.addArgs(&.{ "xcodebuild", "test", diff --git a/src/build/GhosttyZig.zig b/src/build/GhosttyZig.zig index 44c300e15..202c6464e 100644 --- a/src/build/GhosttyZig.zig +++ b/src/build/GhosttyZig.zig @@ -135,7 +135,7 @@ fn initVt( deps.unicode_tables.addModuleImport(vt); // We need uucode for grapheme break support - deps.addUucode(b, vt, cfg.target, cfg.optimize); + vt.addImport("uucode", deps.uucode_mod); // If SIMD is enabled, add all our SIMD dependencies. if (cfg.simd) { diff --git a/src/build/GitVersion.zig b/src/build/GitVersion.zig index 41cc7f84f..2365a110c 100644 --- a/src/build/GitVersion.zig +++ b/src/build/GitVersion.zig @@ -23,7 +23,7 @@ pub fn detect(b: *std.Build) !Version { const tmp: []u8 = b.runAllowFail( &[_][]const u8{ "git", "-C", b.build_root.path orelse ".", "rev-parse", "--abbrev-ref", "HEAD" }, &code, - .Ignore, + .ignore, ) catch |err| switch (err) { error.FileNotFound => return error.GitNotFound, error.ExitCodeFailure => return error.GitNotRepository, @@ -44,19 +44,19 @@ pub fn detect(b: *std.Build) !Version { const output = b.runAllowFail( &[_][]const u8{ "git", "-C", b.build_root.path orelse ".", "-c", "log.showSignature=false", "log", "--pretty=format:%h", "-n", "1" }, &code, - .Ignore, + .ignore, ) catch |err| switch (err) { error.FileNotFound => return error.GitNotFound, else => return err, }; - break :short_hash std.mem.trimRight(u8, output, "\r\n "); + break :short_hash std.mem.trimEnd(u8, output, "\r\n "); }; const tag = b.runAllowFail( &[_][]const u8{ "git", "-C", b.build_root.path orelse ".", "describe", "--exact-match", "--tags" }, &code, - .Ignore, + .ignore, ) catch |err| switch (err) { error.FileNotFound => return error.GitNotFound, error.ExitCodeFailure => "", // expected @@ -70,7 +70,7 @@ pub fn detect(b: *std.Build) !Version { "diff", "--quiet", "--exit-code", - }, &code, .Ignore) catch |err| switch (err) { + }, &code, .ignore) catch |err| switch (err) { error.FileNotFound => return error.GitNotFound, error.ExitCodeFailure => {}, // expected else => return err, @@ -80,7 +80,7 @@ pub fn detect(b: *std.Build) !Version { return .{ .short_hash = short_hash, .changes = changes, - .tag = if (tag.len > 0) std.mem.trimRight(u8, tag, "\r\n ") else null, - .branch = std.mem.trimRight(u8, branch, "\r\n "), + .tag = if (tag.len > 0) std.mem.trimEnd(u8, tag, "\r\n ") else null, + .branch = std.mem.trimEnd(u8, branch, "\r\n "), }; } diff --git a/src/build/HelpStrings.zig b/src/build/HelpStrings.zig index 96505caba..24ae82e2a 100644 --- a/src/build/HelpStrings.zig +++ b/src/build/HelpStrings.zig @@ -34,7 +34,7 @@ pub fn init(b: *std.Build, cfg: *const Config) !HelpStrings { // Generated Zig files have to end with .zig const wf = b.addWriteFiles(); - const output = wf.addCopyFile(help_run.captureStdOut(), "helpgen.zig"); + const output = wf.addCopyFile(help_run.captureStdOut(.{}), "helpgen.zig"); return .{ .exe = exe, diff --git a/src/build/SharedDeps.zig b/src/build/SharedDeps.zig index b68be92d0..f25dcbb53 100644 --- a/src/build/SharedDeps.zig +++ b/src/build/SharedDeps.zig @@ -9,6 +9,7 @@ const MetallibStep = @import("MetallibStep.zig"); const UnicodeTables = @import("UnicodeTables.zig"); const GhosttyFrameData = @import("GhosttyFrameData.zig"); const DistResource = @import("GhosttyDist.zig").Resource; +const gtk_helpers = @import("gtk.zig"); config: *const Config, @@ -19,6 +20,43 @@ unicode_tables: UnicodeTables, framedata: GhosttyFrameData, uucode_tables: std.Build.LazyPath, +/// Singleton uucode module, instantiated once in `init` and reused +/// everywhere so that ghostty and vaxis share the same compiled tables in +/// each final binary instead of each linking its own copy. +/// +/// Sharing one instance is also a hard requirement (not just an +/// optimization) for Zig 0.16's strict module model. `SharedDeps.add` runs +/// many times across different (target, optimize) tuples (macos-aarch64, +/// macos-x86_64, ios-aarch64, Debug + ReleaseFast, etc.), and on each +/// call we have to wire uucode into both the step's root module and into +/// vaxis_mod (because vaxis's `Parser.zig` does `@import("uucode")` and +/// we pass `external_uucode = true` to vaxis's build.zig so vaxis doesn't +/// instantiate its own uucode dep). If those two import bindings ever +/// resolve to *different* `*Module` pointers within a single Compile +/// step's analysis, Zig fails with: +/// +/// vaxis/src/Parser.zig: file exists in modules 'uucode' and 'uucode0' +/// +/// because all those uucode module instances share the same physical +/// `uucode/src/root.zig` file on disk, and Zig requires every file to belong +/// to exactly one module within a Compile graph. +/// +/// The natural way to keep them the same would be to call +/// `b.lazyDependency("uucode", .{ .tables_path, .build_config_path })` +/// from each call site and let Zig's dependency cache deduplicate +/// identical args. That fails because of a bug in Zig's +/// `userLazyPathsAreTheSame` (Build.zig) where the `.src_path` and +/// `.generated` equality checks are inverted: `if (std.mem.eql(...)) +/// return false` instead of `if (!std.mem.eql(...)) return false`. The +/// dep cache key therefore always misses whenever any arg is a +/// `b.path(...)` LazyPath, so each call returns a fresh `*Dependency` +/// with a fresh `*Module`. Hoisting the dep into one eager +/// `b.dependency` call here sidesteps the cache entirely. +/// +/// This conflict is independent of whether vaxis itself is acquired as a +/// singleton or per-target dep. +uucode_mod: *std.Build.Module, + /// Used to keep track of a list of file sources. pub const LazyPathList = std.ArrayList(std.Build.LazyPath); @@ -31,12 +69,20 @@ pub fn init(b: *std.Build, cfg: *const Config) !SharedDeps { break :blk uucode.namedLazyPath("tables.zig"); }; + // Instantiate the singleton uucode module that both ghostty and vaxis + // import. See the doc comment on `uucode_mod`. + const uucode_mod = b.dependency("uucode", .{ + .tables_path = uucode_tables, + .build_config_path = b.path("src/build/uucode_config.zig"), + }).module("uucode"); + var result: SharedDeps = .{ .config = cfg, .help_strings = try .init(b, cfg), .unicode_tables = try .init(b, uucode_tables), .framedata = try .init(b), .uucode_tables = uucode_tables, + .uucode_mod = uucode_mod, // Setup by retarget .options = undefined, @@ -135,6 +181,9 @@ pub fn add( // Every exe needs the terminal options self.config.terminalOptions(.ghostty).add(b, step.root_module); + // Every exe needs the uucode module + step.root_module.addImport("uucode", self.uucode_mod); + // C imports for locale constants and functions { const c = b.addTranslateC(.{ @@ -143,11 +192,15 @@ pub fn add( .optimize = optimize, }); if (target.result.os.tag.isDarwin()) { - const libc = try std.zig.LibCInstallation.findNative(.{ - .allocator = b.allocator, - .target = &target.result, - .verbose = false, - }); + const libc = try std.zig.LibCInstallation.findNative( + b.allocator, + b.graph.io, + .{ + .environ_map = &b.graph.environ_map, + .target = &target.result, + .verbose = false, + }, + ); c.addSystemIncludePath(.{ .cwd_relative = libc.sys_include_dir.? }); } step.root_module.addImport("locale-c", c.createModule()); @@ -166,11 +219,15 @@ pub fn add( }); switch (target.result.os.tag) { .macos => { - const libc = try std.zig.LibCInstallation.findNative(.{ - .allocator = b.allocator, - .target = &target.result, - .verbose = false, - }); + const libc = try std.zig.LibCInstallation.findNative( + b.allocator, + b.graph.io, + .{ + .environ_map = &b.graph.environ_map, + .target = &target.result, + .verbose = false, + }, + ); c.addSystemIncludePath(.{ .cwd_relative = libc.sys_include_dir.? }); }, else => {}, @@ -194,10 +251,10 @@ pub fn add( ); if (b.systemIntegrationOption("freetype", .{})) { - step.linkSystemLibrary2("bzip2", dynamic_link_opts); - step.linkSystemLibrary2("freetype2", dynamic_link_opts); + step.root_module.linkSystemLibrary("bzip2", dynamic_link_opts); + step.root_module.linkSystemLibrary("freetype2", dynamic_link_opts); } else { - step.linkLibrary(freetype_dep.artifact("freetype")); + step.root_module.linkLibrary(freetype_dep.artifact("freetype")); try static_libs.append( b.allocator, freetype_dep.artifact("freetype").getEmittedBin(), @@ -219,9 +276,9 @@ pub fn add( harfbuzz_dep.module("harfbuzz"), ); if (b.systemIntegrationOption("harfbuzz", .{})) { - step.linkSystemLibrary2("harfbuzz", dynamic_link_opts); + step.root_module.linkSystemLibrary("harfbuzz", dynamic_link_opts); } else { - step.linkLibrary(harfbuzz_dep.artifact("harfbuzz")); + step.root_module.linkLibrary(harfbuzz_dep.artifact("harfbuzz")); try static_libs.append( b.allocator, harfbuzz_dep.artifact("harfbuzz").getEmittedBin(), @@ -243,9 +300,9 @@ pub fn add( ); if (b.systemIntegrationOption("fontconfig", .{})) { - step.linkSystemLibrary2("fontconfig", dynamic_link_opts); + step.root_module.linkSystemLibrary("fontconfig", dynamic_link_opts); } else { - step.linkLibrary(fontconfig_dep.artifact("fontconfig")); + step.root_module.linkLibrary(fontconfig_dep.artifact("fontconfig")); try static_libs.append( b.allocator, fontconfig_dep.artifact("fontconfig").getEmittedBin(), @@ -263,7 +320,7 @@ pub fn add( .target = target, .optimize = optimize, })) |libpng_dep| { - step.linkLibrary(libpng_dep.artifact("png")); + step.root_module.linkLibrary(libpng_dep.artifact("png")); try static_libs.append( b.allocator, libpng_dep.artifact("png").getEmittedBin(), @@ -277,7 +334,7 @@ pub fn add( .target = target, .optimize = optimize, })) |zlib_dep| { - step.linkLibrary(zlib_dep.artifact("z")); + step.root_module.linkLibrary(zlib_dep.artifact("z")); try static_libs.append( b.allocator, zlib_dep.artifact("z").getEmittedBin(), @@ -295,9 +352,9 @@ pub fn add( oniguruma_dep.module("oniguruma"), ); if (b.systemIntegrationOption("oniguruma", .{})) { - step.linkSystemLibrary2("oniguruma", dynamic_link_opts); + step.root_module.linkSystemLibrary("oniguruma", dynamic_link_opts); } else { - step.linkLibrary(oniguruma_dep.artifact("oniguruma")); + step.root_module.linkLibrary(oniguruma_dep.artifact("oniguruma")); try static_libs.append( b.allocator, oniguruma_dep.artifact("oniguruma").getEmittedBin(), @@ -312,13 +369,13 @@ pub fn add( })) |glslang_dep| { step.root_module.addImport("glslang", glslang_dep.module("glslang")); if (b.systemIntegrationOption("glslang", .{})) { - step.linkSystemLibrary2("glslang", dynamic_link_opts); - step.linkSystemLibrary2( + step.root_module.linkSystemLibrary("glslang", dynamic_link_opts); + step.root_module.linkSystemLibrary( "glslang-default-resource-limits", dynamic_link_opts, ); } else { - step.linkLibrary(glslang_dep.artifact("glslang")); + step.root_module.linkLibrary(glslang_dep.artifact("glslang")); try static_libs.append( b.allocator, glslang_dep.artifact("glslang").getEmittedBin(), @@ -336,9 +393,9 @@ pub fn add( spirv_cross_dep.module("spirv_cross"), ); if (b.systemIntegrationOption("spirv-cross", .{})) { - step.linkSystemLibrary2("spirv-cross-c-shared", dynamic_link_opts); + step.root_module.linkSystemLibrary("spirv-cross-c-shared", dynamic_link_opts); } else { - step.linkLibrary(spirv_cross_dep.artifact("spirv_cross")); + step.root_module.linkLibrary(spirv_cross_dep.artifact("spirv_cross")); try static_libs.append( b.allocator, spirv_cross_dep.artifact("spirv_cross").getEmittedBin(), @@ -357,7 +414,7 @@ pub fn add( "sentry", sentry_dep.module("sentry"), ); - step.linkLibrary(sentry_dep.artifact("sentry")); + step.root_module.linkLibrary(sentry_dep.artifact("sentry")); try static_libs.append( b.allocator, sentry_dep.artifact("sentry").getEmittedBin(), @@ -404,18 +461,18 @@ pub fn add( if (step.rootModuleTarget().os.tag == .linux) { const triple = try step.rootModuleTarget().linuxTriple(b.allocator); const path = b.fmt("/usr/lib/{s}", .{triple}); - if (std.fs.accessAbsolute(path, .{})) { - step.addLibraryPath(.{ .cwd_relative = path }); + if (std.Io.Dir.accessAbsolute(b.graph.io, path, .{})) { + step.root_module.addLibraryPath(.{ .cwd_relative = path }); } else |_| {} } // C files - step.linkLibC(); - step.addIncludePath(b.path("src/stb")); + step.root_module.link_libc = true; + step.root_module.addIncludePath(b.path("src/stb")); // Disable ubsan for MSVC: Zig's ubsan runtime cannot be bundled // on Windows (LNK4229), leaving __ubsan_handle_* unresolved when // the static archive is consumed by an external linker. - step.addCSourceFiles(.{ + step.root_module.addCSourceFiles(.{ .files = &.{"src/stb/stb.c"}, .flags = if (step.rootModuleTarget().abi == .msvc) &.{ "-fno-sanitize=undefined", "-fno-sanitize-trap=undefined" } @@ -423,7 +480,7 @@ pub fn add( &.{}, }); if (step.rootModuleTarget().os.tag == .linux) { - step.addIncludePath(b.path("src/apprt/gtk")); + step.root_module.addIncludePath(b.path("src/apprt/gtk")); } // libcpp is required for various dependencies. On MSVC, we must @@ -433,7 +490,7 @@ pub fn add( // include directories (already added via linkLibC above) contain // both C and C++ headers, so linkLibCpp is not needed. if (step.rootModuleTarget().abi != .msvc) { - step.linkLibCpp(); + step.root_module.link_libcpp = true; } // We always require the system SDK so that our system headers are available. @@ -452,8 +509,14 @@ pub fn add( if (b.lazyDependency("opengl", .{})) |dep| { step.root_module.addImport("opengl", dep.module("opengl")); } - if (b.lazyDependency("vaxis", .{})) |dep| { - step.root_module.addImport("vaxis", dep.module("vaxis")); + if (b.lazyDependency("vaxis", .{ + .target = target, + .optimize = optimize, + .external_uucode = true, + })) |dep| { + const vaxis = dep.module("vaxis"); + step.root_module.addImport("vaxis", vaxis); + vaxis.addImport("uucode", self.uucode_mod); } if (b.lazyDependency("wuffs", .{ .target = target, @@ -473,7 +536,6 @@ pub fn add( })) |dep| { step.root_module.addImport("z2d", dep.module("z2d")); } - self.addUucode(b, step.root_module, target, optimize); if (b.lazyDependency("zf", .{ .target = target, .optimize = optimize, @@ -502,7 +564,7 @@ pub fn add( "macos", macos_dep.module("macos"), ); - step.linkLibrary( + step.root_module.linkLibrary( macos_dep.artifact("macos"), ); try static_libs.append( @@ -512,7 +574,7 @@ pub fn add( } if (self.config.renderer == .opengl) { - step.linkFramework("OpenGL"); + step.root_module.linkFramework("OpenGL", .{}); } // Apple platforms do not include libc libintl so we bundle it. @@ -523,7 +585,7 @@ pub fn add( .target = target, .optimize = optimize, })) |libintl_dep| { - step.linkLibrary(libintl_dep.artifact("intl")); + step.root_module.linkLibrary(libintl_dep.artifact("intl")); try static_libs.append( b.allocator, libintl_dep.artifact("intl").getEmittedBin(), @@ -543,7 +605,7 @@ pub fn add( .@"backend-opengl3" = !target.result.os.tag.isDarwin(), })) |dep| { step.root_module.addImport("dcimgui", dep.module("dcimgui")); - step.linkLibrary(dep.artifact("dcimgui")); + step.root_module.linkLibrary(dep.artifact("dcimgui")); try static_libs.append( b.allocator, dep.artifact("dcimgui").getEmittedBin(), @@ -592,15 +654,15 @@ pub fn add( // If we're building an exe then we have additional dependencies. if (step.kind != .lib) { // We always statically compile glad - step.addIncludePath(b.path("vendor/glad/include/")); - step.addCSourceFile(.{ + step.root_module.addIncludePath(b.path("vendor/glad/include/")); + step.root_module.addCSourceFile(.{ .file = b.path("vendor/glad/src/gl.c"), .flags = &.{}, }); // When we're targeting flatpak we ALWAYS link GTK so we // get access to glib for dbus. - if (self.config.flatpak) step.linkSystemLibrary2("gtk4", dynamic_link_opts); + if (self.config.flatpak) step.root_module.linkSystemLibrary("gtk4", dynamic_link_opts); switch (self.config.app_runtime) { .none => {}, @@ -644,11 +706,24 @@ fn addGtkNg( } } - step.linkSystemLibrary2("gtk4", dynamic_link_opts); - step.linkSystemLibrary2("libadwaita-1", dynamic_link_opts); + { + // Expose the build-time GTK version through options. + const opts = b.addOptions(); + opts.addOption(std.SemanticVersion, "version", gtk_helpers.gtkVersion(b)); + step.root_module.addOptions("gtk_semver", opts); + } + { + // Expose the build-time Adwaita version through options. + const opts = b.addOptions(); + opts.addOption(std.SemanticVersion, "version", gtk_helpers.adwVersion(b)); + step.root_module.addOptions("adw_semver", opts); + } + + step.root_module.linkSystemLibrary("gtk4", dynamic_link_opts); + step.root_module.linkSystemLibrary("libadwaita-1", dynamic_link_opts); if (self.config.x11) { - step.linkSystemLibrary2("X11", dynamic_link_opts); + step.root_module.linkSystemLibrary("X11", dynamic_link_opts); if (gobject_) |gobject| { step.root_module.addImport( "gdk_x11", @@ -732,24 +807,24 @@ fn addGtkNg( // IMPORTANT: gtk4-layer-shell must be linked BEFORE // wayland-client, as it relies on shimming libwayland's APIs. if (b.systemIntegrationOption("gtk4-layer-shell", .{})) { - step.linkSystemLibrary2("gtk4-layer-shell-0", dynamic_link_opts); + step.root_module.linkSystemLibrary("gtk4-layer-shell-0", dynamic_link_opts); } else { // gtk4-layer-shell *must* be dynamically linked, // so we don't add it as a static library const shared_lib = gtk4_layer_shell.artifact("gtk4-layer-shell"); b.installArtifact(shared_lib); - step.linkLibrary(shared_lib); + step.root_module.linkLibrary(shared_lib); } } - step.linkSystemLibrary2("wayland-client", dynamic_link_opts); + step.root_module.linkSystemLibrary("wayland-client", dynamic_link_opts); } { // Get our gresource c/h files and add them to our build. const dist = gtkNgDistResources(b); - step.addCSourceFile(.{ .file = dist.resources_c.path(b), .flags = &.{} }); - step.addIncludePath(dist.resources_h.path(b).dirname()); + step.root_module.addCSourceFile(.{ .file = dist.resources_c.path(b), .flags = &.{} }); + step.root_module.addIncludePath(dist.resources_h.path(b).dirname()); } } @@ -890,11 +965,17 @@ pub fn gtkNgDistResources( .root_module = b.createModule(.{ .root_source_file = b.path("src/apprt/gtk/build/blueprint.zig"), .target = b.graph.host, + .link_libc = true, }), }); - blueprint_exe.linkLibC(); - blueprint_exe.linkSystemLibrary2("gtk4", dynamic_link_opts); - blueprint_exe.linkSystemLibrary2("libadwaita-1", dynamic_link_opts); + { + // Expose the build-time Adwaita version through options. + const opts = b.addOptions(); + opts.addOption(std.SemanticVersion, "version", gtk_helpers.adwVersion(b)); + blueprint_exe.root_module.addOptions("adw_semver", opts); + } + blueprint_exe.root_module.linkSystemLibrary("gtk4", dynamic_link_opts); + blueprint_exe.root_module.linkSystemLibrary("libadwaita-1", dynamic_link_opts); for (gresource.blueprints) |bp| { const blueprint_run = b.addRunArtifact(blueprint_exe); @@ -923,7 +1004,7 @@ pub fn gtkNgDistResources( xml_run.addFileArg(ui_file); } - break :gresource_xml xml_run.captureStdOut(); + break :gresource_xml xml_run.captureStdOut(.{}); }; const generate_c = b.addSystemCommand(&.{ @@ -964,23 +1045,6 @@ pub fn gtkNgDistResources( }; } -pub fn addUucode( - self: *const SharedDeps, - b: *std.Build, - module: *std.Build.Module, - target: std.Build.ResolvedTarget, - optimize: std.builtin.OptimizeMode, -) void { - if (b.lazyDependency("uucode", .{ - .target = target, - .optimize = optimize, - .tables_path = self.uucode_tables, - .build_config_path = b.path("src/build/uucode_config.zig"), - })) |dep| { - module.addImport("uucode", dep.module("uucode")); - } -} - // For dynamic linking, we prefer dynamic linking and to search by // mode first. Mode first will search all paths for a dynamic library // before falling back to static. diff --git a/src/build/UnicodeTables.zig b/src/build/UnicodeTables.zig index 17a839eaf..843ada51f 100644 --- a/src/build/UnicodeTables.zig +++ b/src/build/UnicodeTables.zig @@ -54,8 +54,8 @@ pub fn init(b: *std.Build, uucode_tables: std.Build.LazyPath) !UnicodeTables { // Generated Zig files have to end with .zig const wf = b.addWriteFiles(); - const props_output = wf.addCopyFile(props_run.captureStdOut(), "props.zig"); - const symbols_output = wf.addCopyFile(symbols_run.captureStdOut(), "symbols.zig"); + const props_output = wf.addCopyFile(props_run.captureStdOut(.{}), "props.zig"); + const symbols_output = wf.addCopyFile(symbols_run.captureStdOut(.{}), "symbols.zig"); return .{ .props_exe = props_exe, diff --git a/src/build/XCFrameworkStep.zig b/src/build/XCFrameworkStep.zig index 39f0f9bac..5f1b676fb 100644 --- a/src/build/XCFrameworkStep.zig +++ b/src/build/XCFrameworkStep.zig @@ -63,8 +63,8 @@ pub fn create(b: *std.Build, opts: Options) *XCFrameworkStep { run.addArg("-output"); run.addArg(opts.out_path); run.expectExitCode(0); - _ = run.captureStdOut(); - _ = run.captureStdErr(); + _ = run.captureStdOut(.{}); + _ = run.captureStdErr(.{}); break :run run; }; run_create.step.dependOn(&run_delete.step); diff --git a/src/build/args.zig b/src/build/args.zig new file mode 100644 index 000000000..3f3b6b49c --- /dev/null +++ b/src/build/args.zig @@ -0,0 +1,13 @@ +const std = @import("std"); + +/// Helper function for args allocation. Caller fully owns the slice and can +/// deinit as need be. +pub fn argsAlloc(alloc: std.mem.Allocator, args: std.process.Args) std.mem.Allocator.Error![][:0]const u8 { + var result: std.ArrayList([:0]const u8) = .empty; + errdefer result.deinit(alloc); + var it = args.iterate(); + while (it.next()) |arg| { + try result.append(alloc, arg); + } + return try result.toOwnedSlice(alloc); +} diff --git a/src/build/combine_archives.zig b/src/build/combine_archives.zig index 04ec8e978..cb5c92ad3 100644 --- a/src/build/combine_archives.zig +++ b/src/build/combine_archives.zig @@ -10,12 +10,15 @@ //! Usage: combine_archives [input2.a ...] const std = @import("std"); +const argsAlloc = @import("args.zig").argsAlloc; -pub fn main() !void { - var gpa: std.heap.GeneralPurposeAllocator(.{}) = .init; +pub fn main(init: std.process.Init) !void { + var gpa: std.heap.DebugAllocator(.{}) = .init; const alloc = gpa.allocator(); - const args = try std.process.argsAlloc(alloc); + const args = try argsAlloc(alloc, init.minimal.args); + defer alloc.free(args); + if (args.len < 4) { std.log.err("usage: combine_archives ", .{}); std.process.exit(1); @@ -37,19 +40,20 @@ pub fn main() !void { } try script.appendSlice(alloc, "SAVE\nEND\n"); - var child: std.process.Child = .init(&.{ zig_exe, "ar", "-M" }, alloc); - child.stdin_behavior = .Pipe; - child.stdout_behavior = .Inherit; - child.stderr_behavior = .Inherit; + var child = try std.process.spawn(init.io, .{ + .argv = &.{ zig_exe, "ar", "-M" }, + .stdin = .pipe, + .stdout = .inherit, + .stderr = .inherit, + }); - try child.spawn(); - try child.stdin.?.writeAll(script.items); - child.stdin.?.close(); + try child.stdin.?.writeStreamingAll(init.io, script.items); + child.stdin.?.close(init.io); child.stdin = null; - const term = try child.wait(); - if (term.Exited != 0) { - std.log.err("zig ar -M exited with code {d}", .{term.Exited}); + const term = try child.wait(init.io); + if (term.exited != 0) { + std.log.err("zig ar -M exited with code {d}", .{term.exited}); std.process.exit(1); } } diff --git a/src/build/gtk.zig b/src/build/gtk.zig index 7adb3cdb7..120aae4d2 100644 --- a/src/build/gtk.zig +++ b/src/build/gtk.zig @@ -14,7 +14,7 @@ pub fn targets(b: *std.Build) Targets { const output = b.runAllowFail( &.{ "pkg-config", "--variable=targets", "gtk4" }, &code, - .Ignore, + .ignore, ) catch return .{}; const x11 = std.mem.indexOf(u8, output, "x11") != null; @@ -25,3 +25,26 @@ pub fn targets(b: *std.Build) Targets { .wayland = wayland, }; } + +/// Returns the GTK build version. +pub fn gtkVersion(b: *std.Build) std.SemanticVersion { + const version_string = std.mem.trimEnd( + u8, + b.run(&.{ "pkg-config", "--modversion", "gtk4" }), + "\n", + ); + return std.SemanticVersion.parse(version_string) catch unreachable; +} + +/// Returns the Adwaita build version. +pub fn adwVersion(b: *std.Build) std.SemanticVersion { + // Note that we need to use sh here instead of just plain pkg-config + // because libadwaita-1 does not have a semver-conforming version. We could + // use pure Zig, but cut works just as well and it's in coreutils. + const version_string = std.mem.trimEnd( + u8, + b.run(&.{ "sh", "-c", "pkg-config --modversion libadwaita-1 | cut -f-3 -d." }), + "\n", + ); + return std.SemanticVersion.parse(version_string) catch unreachable; +} diff --git a/src/build/uucode_config.zig b/src/build/uucode_config.zig index 2bb0d4508..e7a4f08c4 100644 --- a/src/build/uucode_config.zig +++ b/src/build/uucode_config.zig @@ -1,109 +1,138 @@ const std = @import("std"); const assert = std.debug.assert; const config = @import("config.zig"); -const config_x = @import("config.x.zig"); -const d = config.default; -const wcwidth = config_x.wcwidth; -const grapheme_break_no_control = config_x.grapheme_break_no_control; const Allocator = std.mem.Allocator; -fn computeWidth( - alloc: std.mem.Allocator, - cp: u21, - data: anytype, - backing: anytype, - tracking: anytype, -) Allocator.Error!void { - _ = alloc; - _ = cp; - _ = backing; - _ = tracking; - - // This condition is needed as Ghostty currently has a singular concept for - // the `width` of a code point, while `uucode` splits the concept into - // `wcwidth_standalone` and `wcwidth_zero_in_grapheme`. The two cases where - // we want to use the `wcwidth_standalone` despite the code point occupying - // zero width in a grapheme (`wcwidth_zero_in_grapheme`) are emoji - // modifiers and prepend code points. For emoji modifiers we want to - // support displaying them in isolation as color patches, and if prepend - // characters were to be width 0 they would disappear from the output with - // Ghostty's current width 0 handling. Future work will take advantage of - // the new uucode `wcwidth_standalone` vs `wcwidth_zero_in_grapheme` split. - if (data.wcwidth_zero_in_grapheme and !data.is_emoji_modifier and data.grapheme_break_no_control != .prepend) { - data.width = 0; - } else { - data.width = @min(2, data.wcwidth_standalone); - } -} - -const width = config.Extension{ - .inputs = &.{ - "wcwidth_standalone", - "wcwidth_zero_in_grapheme", - "is_emoji_modifier", - "grapheme_break_no_control", +pub const fields = &config.mergeFields(config.fields, &.{ + .{ .name = "width", .type = u2 }, + .{ .name = "is_symbol", .type = bool }, +}); +pub const build_components = &config.mergeComponents(config.build_components, &.{ + .{ + .Impl = WidthComponent, + .inputs = &.{ + "wcwidth_standalone", + "wcwidth_zero_in_grapheme", + "is_emoji_modifier", + "grapheme_break_no_control", + }, + .fields = &.{"width"}, }, - .compute = &computeWidth, - .fields = &.{ - .{ .name = "width", .type = u2 }, + .{ + .Impl = IsSymbolComponent, + .inputs = &.{ "block", "general_category" }, + .fields = &.{"is_symbol"}, }, -}; +}); -fn computeIsSymbol( - alloc: Allocator, - cp: u21, - data: anytype, - backing: anytype, - tracking: anytype, -) Allocator.Error!void { - _ = alloc; - _ = cp; - _ = backing; - _ = tracking; - const block = data.block; - data.is_symbol = data.general_category == .other_private_use or - block == .arrows or - block == .dingbats or - block == .emoticons or - block == .miscellaneous_symbols or - block == .enclosed_alphanumerics or - block == .enclosed_alphanumeric_supplement or - block == .miscellaneous_symbols_and_pictographs or - block == .transport_and_map_symbols; -} - -const is_symbol = config.Extension{ - .inputs = &.{ "block", "general_category" }, - .compute = &computeIsSymbol, - .fields = &.{ - .{ .name = "is_symbol", .type = bool }, - }, -}; +pub const get_components: []const config.Component = &.{}; pub const tables = [_]config.Table{ .{ .name = "runtime", - .extensions = &.{}, .fields = &.{ - d.field("is_emoji_presentation"), - d.field("case_folding_full"), + "is_emoji_presentation", + "case_folding_full", + }, + }, + .{ + // Fields that libvaxis needs that aren't included in the `runtime` + // table. + .name = "libvaxis_only", + .fields = &.{ + "east_asian_width", + "general_category", + "grapheme_break", }, }, .{ .name = "buildtime", - .extensions = &.{ - wcwidth, - grapheme_break_no_control, - width, - is_symbol, - }, .fields = &.{ - width.field("width"), - wcwidth.field("wcwidth_zero_in_grapheme"), - grapheme_break_no_control.field("grapheme_break_no_control"), - is_symbol.field("is_symbol"), - d.field("is_emoji_vs_base"), + "width", + "wcwidth_zero_in_grapheme", + "grapheme_break_no_control", + "is_symbol", + "is_emoji_vs_base", }, }, }; + +const WidthComponent = struct { + pub fn build( + comptime InputRow: type, + comptime Row: type, + allocator: std.mem.Allocator, + io: std.Io, + inputs: config.MultiSlice(InputRow), + rows: *config.MultiSlice(Row), + backing: anytype, + tracking: anytype, + ) !void { + _ = allocator; + _ = io; + _ = backing; + _ = tracking; + + rows.len = config.num_code_points; + const items = rows.items(.width); + const standalone = inputs.items(.wcwidth_standalone); + const zero_in_grapheme = inputs.items(.wcwidth_zero_in_grapheme); + const is_emoji_modifier = inputs.items(.is_emoji_modifier); + const grapheme_break_no_control = inputs.items(.grapheme_break_no_control); + + // This condition is needed as Ghostty currently has a singular concept for + // the `width` of a code point, while `uucode` splits the concept into + // `wcwidth_standalone` and `wcwidth_zero_in_grapheme`. The two cases where + // we want to use the `wcwidth_standalone` despite the code point occupying + // zero width in a grapheme (`wcwidth_zero_in_grapheme`) are emoji + // modifiers and prepend code points. For emoji modifiers we want to + // support displaying them in isolation as color patches, and if prepend + // characters were to be width 0 they would disappear from the output with + // Ghostty's current width 0 handling. Future work will take advantage of + // the new uucode `wcwidth_standalone` vs `wcwidth_zero_in_grapheme` split. + for (0..config.num_code_points) |i| { + if (zero_in_grapheme[i] and !is_emoji_modifier[i] and grapheme_break_no_control[i] != .prepend) { + items[i] = 0; + } else { + items[i] = @min(2, standalone[i]); + } + } + } +}; + +const IsSymbolComponent = struct { + pub fn build( + comptime InputRow: type, + comptime Row: type, + allocator: std.mem.Allocator, + io: std.Io, + inputs: config.MultiSlice(InputRow), + rows: *config.MultiSlice(Row), + backing: anytype, + tracking: anytype, + ) !void { + _ = allocator; + _ = io; + _ = backing; + _ = tracking; + + rows.len = config.num_code_points; + const items = rows.items(.is_symbol); + const block = inputs.items(.block); + const general_category = inputs.items(.general_category); + + for (0..config.num_code_points) |i| { + items[i] = + general_category[i] == .other_private_use or + block[i] == .arrows or + block[i] == .dingbats or + block[i] == .emoticons or + block[i] == .miscellaneous_symbols or + block[i] == .enclosed_alphanumerics or + block[i] == .enclosed_alphanumeric_supplement or + block[i] == .miscellaneous_symbols_and_pictographs or + block[i] == .transport_and_map_symbols; + } + } +}; diff --git a/src/build/wasm_patch_growable_table.zig b/src/build/wasm_patch_growable_table.zig index c40c0a9c8..56c1de27a 100644 --- a/src/build/wasm_patch_growable_table.zig +++ b/src/build/wasm_patch_growable_table.zig @@ -11,16 +11,17 @@ const std = @import("std"); const testing = std.testing; const Allocator = std.mem.Allocator; +const argsAlloc = @import("args.zig").argsAlloc; -pub fn main() !void { +pub fn main(init: std.process.Init) !void { // This is a one-off patcher, so we leak all our memory on purpose // and let the OS clean it up when we exit. var gpa: std.heap.GeneralPurposeAllocator(.{}) = .init; const alloc = gpa.allocator(); // Parse args: program input output - const args = try std.process.argsAlloc(alloc); - defer std.process.argsFree(alloc, args); + const args = try argsAlloc(alloc, init.minimal.args); + defer alloc.free(args); if (args.len != 3) { std.log.err("usage: wasm_growable_table ", .{}); std.process.exit(1); @@ -30,7 +31,8 @@ pub fn main() !void { // Patch the file. const output: []const u8 = try patchTableGrowable( alloc, - try std.fs.cwd().readFileAlloc( + try std.Io.Dir.cwd().readFileAlloc( + init.io, alloc, args[1], std.math.maxInt(usize), @@ -38,9 +40,9 @@ pub fn main() !void { ); // Write our output - const out_file = try std.fs.cwd().createFile(args[2], .{}); - defer out_file.close(); - try out_file.writeAll(output); + const out_file = try std.Io.Dir.cwd().createFile(init.io, args[2], .{}); + defer out_file.close(init.io); + try out_file.writePositionalAll(init.io, output); } /// Patch the WASM binary's table section to remove the maximum size diff --git a/src/build/webgen/main_actions.zig b/src/build/webgen/main_actions.zig index b0de6537d..38cda3f7a 100644 --- a/src/build/webgen/main_actions.zig +++ b/src/build/webgen/main_actions.zig @@ -1,9 +1,9 @@ const std = @import("std"); const helpgen_actions = @import("../../input/helpgen_actions.zig"); -pub fn main() !void { +pub fn main(init: std.process.Init) !void { var buffer: [2048]u8 = undefined; - var stdout_writer = std.fs.File.stdout().writer(&buffer); + var stdout_writer = std.Io.File.stdout().writer(init.io, &buffer); const stdout = &stdout_writer.interface; try helpgen_actions.generate(stdout, .markdown, true, std.heap.page_allocator); } diff --git a/src/build/webgen/main_commands.zig b/src/build/webgen/main_commands.zig index 65f144522..c895948d4 100644 --- a/src/build/webgen/main_commands.zig +++ b/src/build/webgen/main_commands.zig @@ -2,9 +2,9 @@ const std = @import("std"); const Action = @import("../../cli/ghostty.zig").Action; const help_strings = @import("help_strings"); -pub fn main() !void { +pub fn main(init: std.process.Init) !void { var buffer: [2048]u8 = undefined; - var stdout_writer = std.fs.File.stdout().writer(&buffer); + var stdout_writer = std.Io.File.stdout().writer(init.io, &buffer); const stdout = &stdout_writer.interface; try genActions(stdout); } diff --git a/src/build/webgen/main_config.zig b/src/build/webgen/main_config.zig index 1363fadc4..82ecc950f 100644 --- a/src/build/webgen/main_config.zig +++ b/src/build/webgen/main_config.zig @@ -2,9 +2,9 @@ const std = @import("std"); const Config = @import("../../config/Config.zig"); const help_strings = @import("help_strings"); -pub fn main() !void { +pub fn main(init: std.process.Init) !void { var buffer: [2048]u8 = undefined; - var stdout_writer = std.fs.File.stdout().writer(&buffer); + var stdout_writer = std.Io.File.stdout().writer(init.io, &buffer); const stdout = &stdout_writer.interface; try genConfig(stdout); } diff --git a/src/cli/Pager.zig b/src/cli/Pager.zig index 247c998e1..e8760ebdb 100644 --- a/src/cli/Pager.zig +++ b/src/cli/Pager.zig @@ -15,7 +15,7 @@ child: ?std.process.Child = null, /// The buffered file writer used for both the pager pipe and direct /// stdout paths. -file_writer: std.fs.File.Writer = undefined, +file_writer: std.Io.File.Writer = undefined, /// Initialize the pager. If stdout is a TTY, this spawns the pager /// process. Otherwise, output goes directly to stdout. @@ -26,9 +26,9 @@ pub fn init(alloc: Allocator) Pager { /// Writes to the pager process if available; otherwise, stdout. pub fn writer(self: *Pager, buffer: []u8) *std.Io.Writer { if (self.child) |child| { - self.file_writer = child.stdin.?.writer(buffer); + self.file_writer = child.stdin.?.writer(std.Io.Threaded.global_single_threaded.io(), buffer); } else { - self.file_writer = std.fs.File.stdout().writer(buffer); + self.file_writer = std.Io.File.stdout().writer(std.Io.Threaded.global_single_threaded.io(), buffer); } return &self.file_writer.interface; } @@ -40,18 +40,18 @@ pub fn deinit(self: *Pager) void { // pager sees EOF, then wait for it to exit. self.file_writer.interface.flush() catch {}; if (child.stdin) |stdin| { - stdin.close(); + stdin.close(std.Io.Threaded.global_single_threaded.io()); child.stdin = null; } - _ = child.wait() catch {}; + _ = child.wait(std.Io.Threaded.global_single_threaded.io()) catch {}; } self.* = undefined; } fn initPager(alloc: Allocator) ?std.process.Child { - const stdout_file: std.fs.File = .stdout(); - if (!stdout_file.isTty()) return null; + const stdout_file: std.Io.File = .stdout(); + if (!(stdout_file.isTty(std.Io.Threaded.global_single_threaded.io()) catch return null)) return null; // Resolve the pager command: $GHOSTTY_PAGER > $PAGER > `less`. // An empty value for either env var disables paging. @@ -68,13 +68,12 @@ fn initPager(alloc: Allocator) ?std.process.Child { if (cmd == null) return null; - var child: std.process.Child = .init(&.{cmd.?}, alloc); - child.stdin_behavior = .Pipe; - child.stdout_behavior = .Inherit; - child.stderr_behavior = .Inherit; - - child.spawn() catch return null; - return child; + return std.process.spawn(std.Io.Threaded.global_single_threaded.io(), .{ + .argv = &.{cmd.?}, + .stdin = .pipe, + .stdout = .inherit, + .stderr = .inherit, + }) catch null; } test "pager: non-tty" { diff --git a/src/cli/action.zig b/src/cli/action.zig index 41173a9f1..276a0cfee 100644 --- a/src/cli/action.zig +++ b/src/cli/action.zig @@ -1,5 +1,6 @@ const std = @import("std"); const Allocator = std.mem.Allocator; +const compat_args = @import("../lib/compat/args.zig"); pub const DetectError = error{ /// Multiple actions were detected. You can specify at most one @@ -12,7 +13,7 @@ pub const DetectError = error{ /// Detect the action from CLI args. pub fn detectArgs(comptime E: type, alloc: Allocator) !?E { - var iter = try std.process.argsWithAllocator(alloc); + var iter = try compat_args.getArgs().iterateAllocator(alloc); defer iter.deinit(); return try detectIter(E, &iter); } @@ -83,7 +84,7 @@ test "detect direct match" { const alloc = testing.allocator; const Enum = enum { foo, bar, baz }; - var iter = try std.process.ArgIteratorGeneral(.{}).init( + var iter = try compat_args.ArgIteratorGeneral(.{}).init( alloc, "+foo", ); @@ -97,7 +98,7 @@ test "detect invalid match" { const alloc = testing.allocator; const Enum = enum { foo, bar, baz }; - var iter = try std.process.ArgIteratorGeneral(.{}).init( + var iter = try compat_args.ArgIteratorGeneral(.{}).init( alloc, "+invalid", ); @@ -113,7 +114,7 @@ test "detect multiple actions" { const alloc = testing.allocator; const Enum = enum { foo, bar, baz }; - var iter = try std.process.ArgIteratorGeneral(.{}).init( + var iter = try compat_args.ArgIteratorGeneral(.{}).init( alloc, "+foo +bar", ); @@ -129,7 +130,7 @@ test "detect no match" { const alloc = testing.allocator; const Enum = enum { foo, bar, baz }; - var iter = try std.process.ArgIteratorGeneral(.{}).init( + var iter = try compat_args.ArgIteratorGeneral(.{}).init( alloc, "--some-flag", ); @@ -154,7 +155,7 @@ test "detect special case action" { }; { - var iter = try std.process.ArgIteratorGeneral(.{}).init( + var iter = try compat_args.ArgIteratorGeneral(.{}).init( alloc, "--special +bar", ); @@ -164,7 +165,7 @@ test "detect special case action" { } { - var iter = try std.process.ArgIteratorGeneral(.{}).init( + var iter = try compat_args.ArgIteratorGeneral(.{}).init( alloc, "+bar --special", ); @@ -174,7 +175,7 @@ test "detect special case action" { } { - var iter = try std.process.ArgIteratorGeneral(.{}).init( + var iter = try compat_args.ArgIteratorGeneral(.{}).init( alloc, "+bar", ); @@ -200,7 +201,7 @@ test "detect special case fallback" { }; { - var iter = try std.process.ArgIteratorGeneral(.{}).init( + var iter = try compat_args.ArgIteratorGeneral(.{}).init( alloc, "--special", ); @@ -210,7 +211,7 @@ test "detect special case fallback" { } { - var iter = try std.process.ArgIteratorGeneral(.{}).init( + var iter = try compat_args.ArgIteratorGeneral(.{}).init( alloc, "+bar --special", ); @@ -220,7 +221,7 @@ test "detect special case fallback" { } { - var iter = try std.process.ArgIteratorGeneral(.{}).init( + var iter = try compat_args.ArgIteratorGeneral(.{}).init( alloc, "--special +bar", ); @@ -246,7 +247,7 @@ test "detect special case abort_if_no_action" { }; { - var iter = try std.process.ArgIteratorGeneral(.{}).init( + var iter = try compat_args.ArgIteratorGeneral(.{}).init( alloc, "-e", ); @@ -256,7 +257,7 @@ test "detect special case abort_if_no_action" { } { - var iter = try std.process.ArgIteratorGeneral(.{}).init( + var iter = try compat_args.ArgIteratorGeneral(.{}).init( alloc, "+foo -e", ); @@ -266,7 +267,7 @@ test "detect special case abort_if_no_action" { } { - var iter = try std.process.ArgIteratorGeneral(.{}).init( + var iter = try compat_args.ArgIteratorGeneral(.{}).init( alloc, "-e +bar", ); diff --git a/src/cli/args.zig b/src/cli/args.zig index bd5060d69..543303176 100644 --- a/src/cli/args.zig +++ b/src/cli/args.zig @@ -5,6 +5,7 @@ const Allocator = mem.Allocator; const ArenaAllocator = std.heap.ArenaAllocator; const diags = @import("diagnostics.zig"); const internal_os = @import("../os/main.zig"); +const compat_args = @import("../lib/compat/args.zig"); const Diagnostic = diags.Diagnostic; const DiagnosticList = diags.DiagnosticList; const CommaSplitter = @import("CommaSplitter.zig"); @@ -489,18 +490,13 @@ pub fn parseTaggedUnion(comptime T: type, alloc: Allocator, v: []const u8) !T { // We need to create a struct that looks like this union field. // This lets us use parseIntoField as if its a dedicated struct. - const Target = @Type(.{ .@"struct" = .{ - .layout = .auto, - .fields = &.{.{ - .name = field.name, - .type = field.type, - .default_value_ptr = null, - .is_comptime = false, - .alignment = @alignOf(field.type), - }}, - .decls = &.{}, - .is_tuple = false, - } }); + const Target = @Struct( + .auto, + null, + &.{field.name}, + &.{field.type}, + &.{.{ .@"align" = @alignOf(field.type) }}, + ); // Parse the value into the struct var t: Target = undefined; @@ -677,7 +673,7 @@ test "parse: simple" { } = .{}; defer if (data._arena) |arena| arena.deinit(); - var iter = try std.process.ArgIteratorGeneral(.{}).init( + var iter = try compat_args.ArgIteratorGeneral(.{}).init( testing.allocator, "--a=42 --b --b-f=false", ); @@ -689,7 +685,7 @@ test "parse: simple" { try testing.expect(!data.@"b-f"); // Reparsing works - var iter2 = try std.process.ArgIteratorGeneral(.{}).init( + var iter2 = try compat_args.ArgIteratorGeneral(.{}).init( testing.allocator, "--a=84", ); @@ -711,7 +707,7 @@ test "parse: quoted value" { } = .{}; defer if (data._arena) |arena| arena.deinit(); - var iter = try std.process.ArgIteratorGeneral(.{}).init( + var iter = try compat_args.ArgIteratorGeneral(.{}).init( testing.allocator, "--a=\"42\" --b=\"hello!\"", ); @@ -731,7 +727,7 @@ test "parse: empty value resets to default" { } = .{}; defer if (data._arena) |arena| arena.deinit(); - var iter = try std.process.ArgIteratorGeneral(.{}).init( + var iter = try compat_args.ArgIteratorGeneral(.{}).init( testing.allocator, "--a= --b=", ); @@ -750,7 +746,7 @@ test "parse: positional arguments are invalid" { } = .{}; defer if (data._arena) |arena| arena.deinit(); - var iter = try std.process.ArgIteratorGeneral(.{}).init( + var iter = try compat_args.ArgIteratorGeneral(.{}).init( testing.allocator, "--a=84 what", ); @@ -774,7 +770,7 @@ test "parse: diagnostic tracking" { } = .{}; defer if (data._arena) |arena| arena.deinit(); - var iter = try std.process.ArgIteratorGeneral(.{}).init( + var iter = try compat_args.ArgIteratorGeneral(.{}).init( testing.allocator, "--what --a=42", ); @@ -858,7 +854,7 @@ test "parse: compatibility handler" { } = .{}; defer if (data._arena) |arena| arena.deinit(); - var iter = try std.process.ArgIteratorGeneral(.{}).init( + var iter = try compat_args.ArgIteratorGeneral(.{}).init( testing.allocator, "--a=yuh", ); @@ -884,7 +880,7 @@ test "parse: compatibility renamed" { } = .{}; defer if (data._arena) |arena| arena.deinit(); - var iter = try std.process.ArgIteratorGeneral(.{}).init( + var iter = try compat_args.ArgIteratorGeneral(.{}).init( testing.allocator, "--old=true --b=true", ); @@ -1373,7 +1369,7 @@ pub fn argsIterator(alloc_gpa: Allocator) internal_os.args.ArgIterator.InitError test "ArgsIterator" { const testing = std.testing; - const child = try std.process.ArgIteratorGeneral(.{}).init( + const child = try compat_args.ArgIteratorGeneral(.{}).init( testing.allocator, "--what +list-things --a=42", ); diff --git a/src/cli/boo.zig b/src/cli/boo.zig index 2834eadbd..030072351 100644 --- a/src/cli/boo.zig +++ b/src/cli/boo.zig @@ -3,6 +3,7 @@ const builtin = @import("builtin"); const args = @import("args.zig"); const Action = @import("ghostty.zig").Action; const Allocator = std.mem.Allocator; +const compat_env = @import("../lib/compat/env.zig"); const vaxis = @import("vaxis"); const framedata = @import("framedata").compressed; @@ -173,6 +174,9 @@ const Boo = struct { /// The `boo` command is used to display the animation from the Ghostty website in the terminal pub fn run(gpa: Allocator) !u8 { + var env_map = try compat_env.getEnvMap(gpa); + defer env_map.deinit(); + // Disable on non-desktop systems. switch (builtin.os.tag) { .windows, .macos, .linux, .freebsd => {}, @@ -194,7 +198,7 @@ pub fn run(gpa: Allocator) !u8 { gpa.free(decompressed_data); } - var app = try vxfw.App.init(gpa); + var app = try vxfw.App.init(std.Io.Threaded.global_single_threaded.io(), gpa, &env_map, &.{}); defer app.deinit(); var boo: Boo = undefined; diff --git a/src/cli/crash_report.zig b/src/cli/crash_report.zig index f0940fdab..3fe1a1959 100644 --- a/src/cli/crash_report.zig +++ b/src/cli/crash_report.zig @@ -39,8 +39,8 @@ pub fn run(alloc_gpa: Allocator) !u8 { } var buffer: [1024]u8 = undefined; - var stdout_file: std.fs.File = .stdout(); - var stdout_writer = stdout_file.writer(&buffer); + var stdout_file: std.Io.File = .stdout(); + var stdout_writer = stdout_file.writer(std.Io.Threaded.global_single_threaded.io(), &buffer); const stdout = &stdout_writer.interface; const result = runInner(alloc, &stdout_file, stdout); @@ -50,7 +50,7 @@ pub fn run(alloc_gpa: Allocator) !u8 { fn runInner( alloc: Allocator, - stdout_file: *std.fs.File, + stdout_file: *std.Io.File, stdout: *std.Io.Writer, ) !u8 { const crash_dir = try crash.defaultDir(alloc); @@ -66,7 +66,7 @@ fn runInner( // If we have no reports, then we're done. If we have a tty then we // print a message, otherwise we do nothing. if (reports.items.len == 0) { - if (std.posix.isatty(stdout_file.handle)) { + if (try stdout_file.isTty(std.Io.Threaded.global_single_threaded.io())) { try stdout.writeAll("No crash reports! 👻\n"); } return 0; @@ -76,7 +76,7 @@ fn runInner( for (reports.items) |report| { var buf: [128]u8 = undefined; - const now = std.time.nanoTimestamp(); + const now = std.Io.Timestamp.now(std.Io.Threaded.global_single_threaded.io(), .real).toNanoseconds(); const diff = now - report.mtime; const since = if (diff <= 0) "now" else s: { const d = Config.Duration{ .duration = @intCast(diff) }; diff --git a/src/cli/diagnostics.zig b/src/cli/diagnostics.zig index 7f4dcc45e..0e4048a01 100644 --- a/src/cli/diagnostics.zig +++ b/src/cli/diagnostics.zig @@ -93,7 +93,7 @@ pub const Location = union(enum) { /// and potentially in the future structure them differently. pub const DiagnosticList = struct { /// The list of diagnostics. - list: std.ArrayListUnmanaged(Diagnostic) = .{}, + list: std.ArrayList(Diagnostic) = .empty, /// Precomputed data for diagnostics. This is used specifically /// when we build libghostty so that we can precompute the messages @@ -111,7 +111,7 @@ pub const DiagnosticList = struct { }; const Precompute = if (precompute_enabled) struct { - messages: std.ArrayListUnmanaged([:0]const u8) = .{}, + messages: std.ArrayList([:0]const u8) = .empty, pub fn clone( self: *const Precompute, diff --git a/src/cli/edit_config.zig b/src/cli/edit_config.zig index c08651a06..e6f091d55 100644 --- a/src/cli/edit_config.zig +++ b/src/cli/edit_config.zig @@ -6,6 +6,7 @@ const Allocator = std.mem.Allocator; const Action = @import("ghostty.zig").Action; const configpkg = @import("../config.zig"); const internal_os = @import("../os/main.zig"); +const compat_exec = @import("../lib/compat/exec.zig"); const Config = configpkg.Config; pub const Options = struct { @@ -48,7 +49,7 @@ pub fn run(alloc: Allocator) !u8 { // critical where setting up the defer cleanup is a problem. var buffer: [1024]u8 = undefined; - var stderr_writer = std.fs.File.stderr().writer(&buffer); + var stderr_writer = std.Io.File.stderr().writer(std.Io.Threaded.global_single_threaded.io(), &buffer); const stderr = &stderr_writer.interface; var opts: Options = .{}; @@ -137,7 +138,7 @@ fn runInner(alloc: Allocator, stderr: *std.Io.Writer) !u8 { } const command = command: { - var buffer: std.io.Writer.Allocating = .init(alloc); + var buffer: std.Io.Writer.Allocating = .init(alloc); defer buffer.deinit(); const writer = &buffer.writer; try writer.writeAll(editor); @@ -158,7 +159,7 @@ fn runInner(alloc: Allocator, stderr: *std.Io.Writer) !u8 { // so this is not a big deal. comptime assert(builtin.link_libc); - const err = std.posix.execvpeZ( + const err = compat_exec.execvpeZ( "/bin/sh", &.{ "/bin/sh", "-c", command }, std.c.environ, diff --git a/src/cli/explain_config.zig b/src/cli/explain_config.zig index 4f034afef..575a3823b 100644 --- a/src/cli/explain_config.zig +++ b/src/cli/explain_config.zig @@ -75,9 +75,9 @@ pub fn run(alloc: Allocator) !u8 { // respective lookup. A bare positional argument tries config // options first, then keybind actions as a fallback. const name = keybind_name orelse option_name orelse positional orelse { - var stderr: std.fs.File = .stderr(); + var stderr: std.Io.File = .stderr(); var buffer: [4096]u8 = undefined; - var stderr_writer = stderr.writer(&buffer); + var stderr_writer = stderr.writer(std.Io.Threaded.global_single_threaded.io(), &buffer); try stderr_writer.interface.writeAll("Usage: ghostty +explain-config