Building Go with Xmake
Xmake builds Go via the Go toolchain (go build under the hood, wrapped in xmake's target model). Useful if your project mixes Go with C/C++/Rust and you want a single build tool.
1. Minimal project
xmake create -l go -t console hello
cd hello
xmake run
add_rules("mode.debug", "mode.release")
target("hello")
set_kind("binary")
add_files("src/*.go")
2. Target kinds
target("app") set_kind("binary") -- executable
target("mylib") set_kind("static") -- Go archive
target("mydyn") set_kind("shared") -- Go shared lib (CGO-compatible)
3. Go modules
Keep a normal go.mod at the project root. Xmake picks it up automatically:
myproj/
├── xmake.lua
├── go.mod
├── go.sum
└── src/
└── main.go
Dependencies declared in go.mod (require github.com/... vX.Y.Z) resolve through the Go toolchain as usual — xmake does not second-guess them.
4. Cross-compile
Go is famously easy to cross-compile, and xmake exposes it through standard flags:
xmake f -p windows -a x86_64
xmake # builds a .exe from macOS/Linux
xmake f -p linux -a arm64
xmake
xmake f -p macosx -a arm64 # Apple Silicon
xmake
Xmake sets GOOS / GOARCH for you. Supported plats map to Go's naming automatically.
5. CGO (calling C from Go)
Keep import "C" in your .go files as usual. When building, add any C dependencies the Go code calls into:
target("app")
set_kind("binary")
add_files("src/*.go", "src/*.c")
add_includedirs("include")
add_links("foo")
Xmake compiles the .c files and links them alongside the Go objects.
6. Toolchain selection
xmake f --toolchain=go
xmake f --toolchain=go --sdk=/opt/go-1.22
--sdk pins a specific Go install; otherwise go on PATH is used.
7. Flags
target("app")
add_files("src/*.go")
add_gcflags("-N", "-l") -- passed to `go tool compile`
add_ldflags("-s -w") -- passed to `go tool link` (stripping)
add_gcflags is Go-specific (go compile flags). add_ldflags maps to go tool link -ldflags.
8. Tests
target("app_test")
set_kind("binary")
add_files("tests/*_test.go")
add_tests("default")
Or run Go's native test runner as an xmake task:
task("gotest")
set_menu { usage = "xmake gotest", description = "Run go test" }
on_run(function () os.exec("go test ./...") end)
Pitfalls
- Editing
go.modafterxmake f. Runxmake f -cto re-resolve. - CGO disabled in cross-compile.
CGO_ENABLED=0is often required for pure-Go cross builds. Set it via env oros.setenvinon_load. - Mixing
.goand.cpp(not.c) in one target. Use.cfor the C side; Go's CGO expects C, not C++. GOFLAGSin env. Sometimes overrides what xmake sets —unset GOFLAGSif you hit weird behavior.
When to branch out
- CGO / mixing with C++ →
xmake-targets - Cross-compile flag plumbing →
xmake-cross-compilation - Packaging the built binary →
xmake-xpack