diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e0b0ded6b..8a98584a2 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -18,6 +18,7 @@ jobs: - build-nix - build-snap - build-macos + - build-macos-tahoe - build-macos-matrix - build-windows - build-windows-cross @@ -284,7 +285,7 @@ jobs: name: ghostty authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" - - name: XCode Select + - name: Xcode Select run: sudo xcode-select -s /Applications/Xcode_16.0.app - name: get the Zig deps @@ -296,7 +297,58 @@ jobs: - name: Build GhosttyKit run: nix develop -c zig build --system ${{ steps.deps.outputs.deps }} - # The native app is built with native XCode tooling. This also does + # The native app is built with native Xcode tooling. This also does + # codesigning. IMPORTANT: this must NOT run in a Nix environment. + # Nix breaks xcodebuild so this has to be run outside. + - name: Build Ghostty.app + run: cd macos && xcodebuild -target Ghostty + + # Build the iOS target without code signing just to verify it works. + - name: Build Ghostty iOS + run: | + cd macos + xcodebuild -target Ghostty-iOS "CODE_SIGNING_ALLOWED=NO" + + build-macos-tahoe: + runs-on: namespace-profile-ghostty-macos-tahoe + needs: test + steps: + - name: Checkout code + uses: actions/checkout@v4 + + # TODO(tahoe): https://github.com/NixOS/nix/issues/13342 + - uses: DeterminateSystems/nix-installer-action@main + with: + determinate: true + - uses: cachix/cachix-action@v16 + with: + name: ghostty + authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" + + - name: Xcode Select + run: sudo xcode-select -s /Applications/Xcode_26.0.app + + # TODO(tahoe): + # https://developer.apple.com/documentation/xcode-release-notes/xcode-26-release-notes#Interface-Builder + # We allow this step to fail because if our image already has + # the workaround in place this will fail. + - name: Xcode 26 Beta 17A5241e Metal Workaround + continue-on-error: true + run: | + xcodebuild -downloadComponent metalToolchain -exportPath /tmp/MyMetalExport/ + sed -i '' -e 's/17A5241c/17A5241e/g' /tmp/MyMetalExport/MetalToolchain-17A5241c.exportedBundle/ExportMetadata.plist + xcodebuild -importComponent metalToolchain -importPath /tmp/MyMetalExport/MetalToolchain-17A5241c.exportedBundle + + - name: get the Zig deps + id: deps + run: nix build -L .#deps && echo "deps=$(readlink ./result)" >> $GITHUB_OUTPUT + + # GhosttyKit is the framework that is built from Zig for our native + # Mac app to access. + - name: Build GhosttyKit + run: nix develop -c zig build --system ${{ steps.deps.outputs.deps }} + + # The native app is built with native Xcode tooling. This also does # codesigning. IMPORTANT: this must NOT run in a Nix environment. # Nix breaks xcodebuild so this has to be run outside. - name: Build Ghostty.app @@ -324,7 +376,7 @@ jobs: name: ghostty authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" - - name: XCode Select + - name: Xcode Select run: sudo xcode-select -s /Applications/Xcode_16.0.app - name: get the Zig deps @@ -642,7 +694,7 @@ jobs: name: ghostty authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" - - name: XCode Select + - name: Xcode Select run: sudo xcode-select -s /Applications/Xcode_16.0.app - name: get the Zig deps diff --git a/src/build/MetallibStep.zig b/src/build/MetallibStep.zig index 12adf3edb..bac3a72c5 100644 --- a/src/build/MetallibStep.zig +++ b/src/build/MetallibStep.zig @@ -22,13 +22,12 @@ step: *Step, output: LazyPath, pub fn create(b: *std.Build, opts: Options) ?*MetallibStep { - const self = b.allocator.create(MetallibStep) catch @panic("OOM"); + switch (opts.target.result.os.tag) { + .macos, .ios => {}, + else => return null, // Only macOS and iOS are supported. + } - const sdk = switch (opts.target.result.os.tag) { - .macos => "macosx", - .ios => "iphoneos", - else => return null, - }; + const self = b.allocator.create(MetallibStep) catch @panic("OOM"); const min_version = if (opts.target.query.os_version_min) |v| b.fmt("{}", .{v.semver}) @@ -38,11 +37,31 @@ pub fn create(b: *std.Build, opts: Options) ?*MetallibStep { else => unreachable, }; + // Find the metal and metallib executables. The Apple docs + // at the time of writing (June 2025) say to use + // `xcrun --sdk metal` but this doesn't work with Xcode 26. + // + // I don't know if this is a bug but the xcodebuild approach also + // works with Xcode 15 so it seems safe to use this instead. + // + // Reported bug: FB17874042. + var code: u8 = undefined; + const metal_exe = std.mem.trim(u8, b.runAllowFail( + &.{ "xcodebuild", "-find-executable", "metal" }, + &code, + .Ignore, + ) catch return null, "\r\n "); + const metallib_exe = std.mem.trim(u8, b.runAllowFail( + &.{ "xcodebuild", "-find-executable", "metallib" }, + &code, + .Ignore, + ) catch return null, "\r\n "); + const run_ir = RunStep.create( b, b.fmt("metal {s}", .{opts.name}), ); - run_ir.addArgs(&.{ "/usr/bin/xcrun", "-sdk", sdk, "metal", "-o" }); + run_ir.addArgs(&.{ metal_exe, "-o" }); const output_ir = run_ir.addOutputFileArg(b.fmt("{s}.ir", .{opts.name})); run_ir.addArgs(&.{"-c"}); for (opts.sources) |source| run_ir.addFileArg(source); @@ -62,7 +81,7 @@ pub fn create(b: *std.Build, opts: Options) ?*MetallibStep { b, b.fmt("metallib {s}", .{opts.name}), ); - run_lib.addArgs(&.{ "/usr/bin/xcrun", "-sdk", sdk, "metallib", "-o" }); + run_lib.addArgs(&.{ metallib_exe, "-o" }); const output_lib = run_lib.addOutputFileArg(b.fmt("{s}.metallib", .{opts.name})); run_lib.addFileArg(output_ir); run_lib.step.dependOn(&run_ir.step);