build: fix freetype compilation on Windows with MSVC#11807
Merged
mitchellh merged 1 commit intoghostty-org:mainfrom Mar 24, 2026
Merged
build: fix freetype compilation on Windows with MSVC#11807mitchellh merged 1 commit intoghostty-org:mainfrom
mitchellh merged 1 commit intoghostty-org:mainfrom
Conversation
Gate HAVE_UNISTD_H and HAVE_FCNTL_H behind a non-Windows check since these headers do not exist with MSVC. Freetype includes zlib headers which conditionally include unistd.h based on this define. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This was referenced Mar 24, 2026
mitchellh
added a commit
that referenced
this pull request
Mar 24, 2026
> [!WARNING] > Review/approve this AFTER #11807 (this PR includes its commits) 92% progress with the fixes! ## Summary - Add a conditional `ssize_t` typedef for MSVC in `include/ghostty.h` - MSVC's `<sys/types.h>` does not define `ssize_t` (it is a POSIX type), which causes the `translate-c` build step to fail when translating `ghostty.h` on Windows - Uses `SSIZE_T` from `<BaseTsd.h>`, the standard Windows SDK equivalent ## Context The `translate-c` step translates `ghostty.h` to Zig for test compilation. On MSVC, it fails with 3 errors on `ssize_t` (used in `ghostty_action_move_tab_s`, `ghostty_action_search_total_s`, `ghostty_action_search_selected_s`). The `#ifdef _MSC_VER` guard means this only affects MSVC builds. `BaseTsd.h` is a standard Windows SDK header and `SSIZE_T` is a signed pointer-sized integer, matching POSIX `ssize_t` and Zig's `isize`. This pattern is used by libuv, curl, and other cross-platform C projects. ## Test plan ### Cross-platform results (`zig build test` / `zig build -Dapp-runtime=none test` on Windows) | | Windows | Linux | Mac | |---|---|---|---| | **BEFORE** (d5aef6e) | FAIL - 47/51 steps, 1 failed | PASS - 86/86, 2655/2678 tests, 23 skipped | PASS - 160/160, 2655/2662 tests, 7 skipped | | **AFTER** (a35f84d) | FAIL - 48/51 steps, 1 failed | PASS - 86/86, 2655/2678 tests, 23 skipped | PASS - 160/160, 2655/2662 tests, 7 skipped | ### Windows: what changed (47 -> 48 steps, translate-c fixed) **Fixed by this PR:** - `translate-c` - was `3 errors` (unknown type name 'ssize_t' at lines 582, 842, 847) -> `success` **Remaining failure (pre-existing, unrelated):** - `compile test ghostty-test` - 3 errors in libcxxabi (`std::get_new_handler` not found, `type_info` redefinition). This is Zig's bundled libc++ ABI conflicting with MSVC headers when compiling the test binary. It was previously masked by the translate-c failure blocking this step. ### Linux/macOS: no regressions Identical pass counts and test results before and after. ## What Have I Learnt - I tried fixing this issue the old way, googling and stuff, I eventually figured out but it took me way more than I am prepared to share. Yikes.
mitchellh
added a commit
that referenced
this pull request
Mar 24, 2026
> [!WARNING] > Review/approve this AFTER #11807 and #11810 (this PR includes their commits) ## Summary ### **And `run test ghostty-test` finally runs on Windows! 🎉almost there!** - Skip `linkLibCpp()` on MSVC for dcimgui, spirv-cross, and harfbuzz (same fix already applied upstream to highway, simdutf, utfcpp, glslang, SharedDeps, GhosttyZig) - Fix freetype C enum signedness: MSVC translates C enums as signed `int`, while GCC/Clang uses unsigned `int`. Add `@intCast` at call sites and `@bitCast` for bit-shift operations on glyph format tags. ## Context Zig unconditionally passes `-nostdinc++` and adds its bundled libc++/libc++abi include paths, which conflict with MSVC's own C++ runtime headers. The MSVC SDK directories (added via `linkLibC`) already contain both C and C++ headers, so `linkLibCpp` is not needed. The freetype enum issue is a different facet of the same MSVC vs GCC/Clang divide: `FT_Render_Mode` and `FT_Glyph_Format` are C enums that get different signedness on different compilers. ## Stack Stacked on 015-windows/fix-ssize-t-msvc. ## Test plan ### Cross-platform results (`zig build test` / `zig build -Dapp-runtime=none test` on Windows) | | Windows | Linux | Mac | |---|---|---|---| | **BEFORE** (015, a35f84d) | FAIL - 48/51, 1 failed (compile ghostty-test) | PASS - 86/86, 2655/2678, 23 skipped | PASS - 160/160, 2655/2662, 7 skipped | | **AFTER** (016, ce99300) | FAIL - 49/51, 2630/2654 tests passed, 1 failed, 23 skipped | PASS - 86/86, 2655/2678, 23 skipped | PASS - 160/160, 2655/2662, 7 skipped | ### Windows: what changed (48 -> 49 steps, tests now run) **Fixed by this PR:** - `compile test ghostty-test` - was `3 errors` (libcxxabi conflicts + freetype type mismatches) -> `success` - `run test ghostty-test` - now actually runs: 2630 passed, 23 skipped, 1 failed **Remaining test failure (pre-existing, unrelated):** - `ghostty.h MouseShape` - `checkGhosttyHEnum` cannot find `GHOSTTY_MOUSE_SHAPE_*` constants in the translate-c output. This is a translate-c issue with how MSVC enum constants are exposed, not related to C++ linking or enum signedness. ### Linux/macOS: no regressions Identical pass counts and test results before and after. ## Discussion ### Grep wider: other unconditional linkLibCpp calls `pkg/breakpad/build.zig` still calls `linkLibCpp()` unconditionally but is behind sentry and not in the Windows build path. Noted for completeness. ### Freetype enum signedness The freetype Zig bindings define `RenderMode = enum(c_uint)` and `Encoding = enum(u31)`. On MSVC, C enums are `int` (signed), so the translated C functions expect `c_int` parameters. The fix adds `@intCast` to convert between signed and unsigned at call sites. This is safe because the enum values are small positive integers that fit in both types. Also, not sure if there's a better way to make this change more elegantly. The comments are replicated in each instance, probably overkill but I have seen this same pattern elsewhere in the codebase. ## What I Learnt - More of the same
mitchellh
added a commit
that referenced
this pull request
Mar 27, 2026
## Summary This PR effectively enables testing for all the Windows related stuff that is coming soon. > [!IMPORTANT] >This PR builds on top of #11782 which fixes the last (as we speak) bug that we have in the Windows pipeline. So it would be great to review that PR first and then work on this one. Then we'll have the real windows testing, basically achieving parity, infrastructurally, with the other platforms. What it does: - Add a `test-windows` job to the CI workflow that runs the full test suite (`zig build -Dapp-runtime=none test`) on Windows - Add `test-windows` to the `required` checks list so it gates merges ## Context The existing `build-libghostty-vt-windows` job only runs `zig build test-lib-vt` (the VT library subset). I realized that in c5092b0 we removed the TODO comment in that job: "Work towards passing the full test suite on Windows." But effectively we weren't running tests in CI yet! The full test suite now passes on Windows (51/51 steps, 2654 tests, 23 skipped). This job mirrors what the other platforms do — Linux runs `zig build -Dapp-runtime=none test` via Nix, macOS runs `zig build test` via Nix. Windows runs the same command directly via `setup-zig` since there's no Nix on Windows. ## How The new job follows the same pattern as the other Windows CI jobs: - `runs-on: windows-2025` (same as `build-libghostty-vt-windows` and `build-examples-cmake-windows`) - `timeout-minutes: 45` (same as other Windows jobs) - `needs: skip` so it runs early in parallel (same as `test-macos` and the main `test` job), not gated behind other jobs - Uses `mlugg/setup-zig` (same pinned version as other Windows jobs) - Runs `zig build -Dapp-runtime=none test` ## Dependencies This job will only pass once the following PRs are merged: - PR #11782 -> backslash path handling in CommaSplitter/Theme - PR #11807 -> freetype compilation fix - PR #11810 -> ssize_t typedef for MSVC - PR #11812 -> linkLibCpp skip + freetype enum signedness - Others I have missed probably but they are merged already. ## Test plan - The workflow YAML is valid (standard GitHub Actions syntax, matches existing job patterns) - I will be ready to issue fix PRs if any issue related to this arises. I cannot reliably test GH actions locally unfortunately. - Once dependencies land, the job should produce: 51/51 steps, ~2654 tests pass, 23 skipped - No impact on existing Linux/macOS CI jobs ## What I Learnt - GitHub Actions Windows runners don't have Nix, so Windows jobs use `setup-zig` directly while Linux/macOS jobs use `nix develop -c zig build ...`. The Nix wrapper ensures the exact same environment as the flake, but on Windows we get that consistency from the `setup-zig` action which reads the version from `build.zig.zon`. - The `needs: skip` pattern allows a job to run in parallel with the main test job rather than waiting for it. The main `test` job is the gatekeeper for most build jobs (`needs: test`), but platform-specific test jobs like `test-macos` run in parallel since they're independent. - The `required` job aggregates all needed jobs and uses a grep-based check to determine overall pass/fail, so adding a new job there means it becomes a merge blocker.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Getting there! Goal for today/tomorrow is to get it all green.
This one is easy:
HAVE_UNISTD_HandHAVE_FCNTL_Hbehind a non-Windows check since these headers do not exist with MSVCunistd.hbased on this defineContext
Same pattern as the zlib fix (010-* branch from my fork). Freetype passes
-DHAVE_UNISTD_Hunconditionally, which causes zlib'szconf.hto try includingunistd.hwhen freetype compiles its gzip support. The fix follows the same approach used inpkg/zlib/build.zig(line 36-38).Stack
Stacked on 013-windows/fix-helpgen-framegen.
Test plan
Cross-platform results (
zig build test/zig build -Dapp-runtime=none teston Windows)Windows: what changed (44 to 47 steps, 2 to 1 failure)
Fixed by this PR:
compile lib freetype- was2 errors(unistd.h/fcntl.h not found) ->successRemaining failure (pre-existing, tracked separately):
translate-c- 3 errors (ssize_tunknown in ghostty.h on MSVC)Linux/macOS: no regressions
Identical pass counts and test results before and after.
Discussion
Other build files with the same pattern
pkg/fontconfig/build.zigandpkg/harfbuzz/build.zigalso pass-DHAVE_UNISTD_Hand/or-DHAVE_FCNTL_Hunconditionally. They are not in the Windows build path today, but will need the same fix when they are.What I Learnt
More of the same