From bc666b9a3725062e1352b50431bca4d83215bb12 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 24 Apr 2026 13:29:13 -0700 Subject: [PATCH] Document and test cross-compilation One of the common stigmas of cgo in Go projects is that it makes cross-compilation overly difficult. Its more difficult than pure Go projects, to be sure, but with the right shape of libraries and build scripts, it can be made to work well. libghostty is a good example of this. libghostty only depends on libc and the Zig compiler (tool, not language) as a drop-in replacement for c/c++ compilation means we can easily cross-compile! This commit adds documentation, tests, and examples on how to do this. --- .github/workflows/test.yml | 32 ++++++++++++++++++++++++ CMakeLists.txt | 10 ++++++++ Makefile | 50 +++++++++++++++++++++++++++++++++++++- README.md | 41 +++++++++++++++++++++++++++++++ 4 files changed, 132 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 482c8cf..7d23181 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -88,6 +88,38 @@ jobs: - name: Run example run: nix develop -c go run ./examples/${{ matrix.example }}/ + cross: + strategy: + fail-fast: false + matrix: + target: + - linux-amd64 + - linux-arm64 + - macos-amd64 + - macos-arm64 + - windows-amd64 + - windows-arm64 + name: Cross ${{ matrix.target }} + runs-on: namespace-profile-ghostty-sm + env: + ZIG_LOCAL_CACHE_DIR: /zig/local-cache + ZIG_GLOBAL_CACHE_DIR: /zig/global-cache + steps: + - name: Checkout code + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - name: Setup Cache + uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2 + with: + path: | + /nix + /zig + - name: Setup Nix + uses: cachix/install-nix-action@616559265b40713947b9c190a8ff4b507b5df49b # v31.10.4 + with: + nix_path: nixpkgs=channel:nixos-unstable + - name: Cross-compile + run: nix develop -c make cross-${{ matrix.target }} + build-shared: runs-on: namespace-profile-ghostty-sm env: diff --git a/CMakeLists.txt b/CMakeLists.txt index 108d7a8..a288c49 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,3 +7,13 @@ FetchContent_Declare(ghostty GIT_TAG 2ed382a15566b267c32fae440b065f7844b15bfb ) FetchContent_MakeAvailable(ghostty) + +# Cross-compilation targets for CI and multi-platform builds. +# Each call produces ghostty-vt-static- and ghostty-vt- +# IMPORTED targets whose output lands under build/ghostty-/. +ghostty_vt_add_target(NAME linux-amd64 ZIG_TARGET x86_64-linux-gnu) +ghostty_vt_add_target(NAME linux-arm64 ZIG_TARGET aarch64-linux-gnu) +ghostty_vt_add_target(NAME macos-amd64 ZIG_TARGET x86_64-macos) +ghostty_vt_add_target(NAME macos-arm64 ZIG_TARGET aarch64-macos) +ghostty_vt_add_target(NAME windows-amd64 ZIG_TARGET x86_64-windows-gnu) +ghostty_vt_add_target(NAME windows-arm64 ZIG_TARGET aarch64-windows-gnu) diff --git a/Makefile b/Makefile index 2a773a8..8a7c7ba 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,36 @@ LD_LIBRARY_PATH := $(GHOSTTY_ZIG_OUT)/lib # Stamp file to track whether the cmake build has run. STAMP := $(BUILD_DIR)/.ghostty-built -.PHONY: build test clean +# Cross-compilation target definitions. +# Each entry maps a make target suffix to GOOS, GOARCH, zig target triple, +# and the CC/CXX target flag for zig cc. +CROSS_TARGETS := linux-amd64 linux-arm64 macos-amd64 macos-arm64 windows-amd64 windows-arm64 + +linux-amd64_GOOS := linux +linux-amd64_GOARCH := amd64 +linux-amd64_ZIG := x86_64-linux-gnu + +linux-arm64_GOOS := linux +linux-arm64_GOARCH := arm64 +linux-arm64_ZIG := aarch64-linux-gnu + +macos-amd64_GOOS := darwin +macos-amd64_GOARCH := amd64 +macos-amd64_ZIG := x86_64-macos + +macos-arm64_GOOS := darwin +macos-arm64_GOARCH := arm64 +macos-arm64_ZIG := aarch64-macos + +windows-amd64_GOOS := windows +windows-amd64_GOARCH := amd64 +windows-amd64_ZIG := x86_64-windows-gnu + +windows-arm64_GOOS := windows +windows-arm64_GOARCH := arm64 +windows-arm64_ZIG := aarch64-windows-gnu + +.PHONY: build test clean cross $(addprefix cross-,$(CROSS_TARGETS)) $(STAMP): cmake -B $(BUILD_DIR) -DCMAKE_BUILD_TYPE=Release @@ -22,5 +51,24 @@ build: $(STAMP) test: $(STAMP) PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) DYLD_LIBRARY_PATH=$(DYLD_LIBRARY_PATH) LD_LIBRARY_PATH=$(LD_LIBRARY_PATH) go test ./... +# cross builds all cross-compilation targets. +cross: $(addprefix cross-,$(CROSS_TARGETS)) + +# cross- cross-compiles the Go package for the given target using +# zig cc and the libghostty-vt static library built by CMake. +define CROSS_RULE +cross-$(1): $(STAMP) + CGO_ENABLED=1 \ + CC="zig cc -target $$($(1)_ZIG)" \ + CXX="zig c++ -target $$($(1)_ZIG)" \ + GOOS=$$($(1)_GOOS) \ + GOARCH=$$($(1)_GOARCH) \ + CGO_CFLAGS="-I$(CURDIR)/$(BUILD_DIR)/ghostty-$(1)/include -DGHOSTTY_STATIC" \ + CGO_LDFLAGS="-L$(CURDIR)/$(BUILD_DIR)/ghostty-$(1)/lib -lghostty-vt" \ + go build . ./sys/... +endef + +$(foreach t,$(CROSS_TARGETS),$(eval $(call CROSS_RULE,$(t)))) + clean: rm -rf $(BUILD_DIR) diff --git a/README.md b/README.md index e30491a..17b1825 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,47 @@ go build -tags dynamic See the [Ghostty docs](https://ghostty.org/docs/install/build) for building `libghostty-vt` from source. +### Cross-Compilation + +Because `libghostty-vt` only depends on libc, cross-compilation is +straightforward using [Zig](https://ziglang.org/) as the C compiler. +Zig is already required to build `libghostty-vt`, so no extra tooling +is needed. You don't need to write any Zig code, we're just using +Zig as a C/C++ compiler. + +First, build `libghostty-vt` for your target (from the ghostty source tree): + +```shell +zig build -Demit-lib-vt -Dtarget=x86_64-linux-gnu --prefix /tmp/ghostty-linux-amd64 +``` + +Then cross-compile your Go project with `zig cc`: + +```shell +CGO_ENABLED=1 \ +GOOS=linux GOARCH=amd64 \ +CC="zig cc -target x86_64-linux-gnu" \ +CXX="zig c++ -target x86_64-linux-gnu" \ +CGO_CFLAGS="-I/tmp/ghostty-linux-amd64/include -DGHOSTTY_STATIC" \ +CGO_LDFLAGS="-L/tmp/ghostty-linux-amd64/lib -lghostty-vt" \ +go build ./... +``` + +Supported targets include `x86_64-linux-gnu`, `aarch64-linux-gnu`, +`x86_64-macos`, `aarch64-macos`, `x86_64-windows-gnu`, and +`aarch64-windows-gnu`. + +If you are using ghostty's CMake integration via `FetchContent`, the +`ghostty_vt_add_target()` function handles the zig build for you: + +```cmake +FetchContent_MakeAvailable(ghostty) +ghostty_vt_add_target(NAME linux-amd64 ZIG_TARGET x86_64-linux-gnu) +``` + +See the [ghostty CMakeLists.txt](https://github.com/ghostty-org/ghostty/blob/main/CMakeLists.txt) +for full documentation of `ghostty_vt_add_target()`. + ## Development CMake fetches and builds `libghostty-vt` automatically. CMake is only