Skip to content

refactor(go): replace Go bridge with direct C FFI, redesign API#338

Merged
DorianZheng merged 8 commits intomainfrom
refactor/go-sdk-direct-ffi
Mar 4, 2026
Merged

refactor(go): replace Go bridge with direct C FFI, redesign API#338
DorianZheng merged 8 commits intomainfrom
refactor/go-sdk-direct-ffi

Conversation

@DorianZheng
Copy link
Copy Markdown
Member

Summary

  • Remove the internal/binding layer and custom boxlite-go-bridge Rust crate — the Go SDK now statically links libboxlite.a and calls the C FFI (boxlite.h) directly via CGo
  • Redesign the public API with functional options (WithName, WithCPUs), os/exec.Cmd-style command execution, typed errors with ErrorCode, and context.Context on all methods
  • Add fix-go-symbols.sh to localize Go runtime symbols from embedded libgvproxy, preventing duplicate symbol conflicts when linking into a Go binary
  • Add full Makefile integration: dev:go, dist:go, test:unit:go, fmt:go, lint:go
  • Fix FFI box_stop to borrow handle (&*handle) instead of taking ownership (Box::from_raw)

Test plan

  • All 15 Go SDK unit tests pass (go test -v ./...)
  • All 7 FFI unit tests pass (cargo nextest run -p boxlite-ffi)
  • go vet clean
  • gofmt clean
  • CI validates full test matrix

Rename pkg/client → pkg/boxlite and internal/binding → pkg/boxlite
to prepare for the idiomatic Go SDK rewrite. Delete the Rust bridge
crate (sdks/go/rust/) and standalone Makefile, as the Go SDK now
links directly against the C FFI via cgo.
Remove the internal/binding layer and custom boxlite-go-bridge Rust crate.
The Go SDK now statically links against libboxlite.a (the C SDK library)
and calls boxlite.h directly via CGo, eliminating a full layer of
indirection.

Key changes:
- Package renamed from `client` to `boxlite` (idiomatic Go)
- Functional options pattern (WithName, WithCPUs, WithMemory, etc.)
- os/exec.Cmd-style command execution (Box.Command / Cmd.Run)
- Typed errors with ErrorCode and helper predicates (IsNotFound, etc.)
- Static linking with fix-go-symbols.sh to resolve Go runtime symbol
  conflicts from embedded libgvproxy
- Full Makefile integration (dev:go, test:unit:go, fmt:go, lint:go)
- Fix FFI box_stop to borrow handle instead of taking ownership
…t-ffi

# Conflicts:
#	Cargo.lock
#	sdks/go/internal/binding/binding.go
#	sdks/go/pkg/client/binding_mock_test.go
#	sdks/go/pkg/client/box.go
#	sdks/go/pkg/client/client.go
#	sdks/go/pkg/client/types.go
#	sdks/go/rust/Cargo.toml
#	sdks/go/rust/src/lib.rs
The Go SDK now uses CGo against libboxlite.a instead of a separate Go
bridge. Update CI workflows to:

- test.yml: Install LLVM (for fix-go-symbols.sh), run `make test:unit:go`
  with BOXLITE_DEPS_STUB=1 instead of non-existent `make test-stub`
- lint.yml: Add Rust + system deps build steps so golangci-lint can
  compile CGo code, add gofmt check and go vet
BOXLITE_DEPS_STUB only works with cargo check/clippy, not cargo build
(the linker needs actual library files). The Go SDK requires a real
libboxlite.a to link against, so use full native builds instead.

Also consolidate LLVM installation into system deps steps.
Go SDK now statically links libboxlite.a which requires building the
native vendored dependencies (libkrun, libgvproxy, etc.) from git
submodules.
Replace manual apt-get/brew install with make setup:build which serves
as single source of truth for all build dependencies. This fixes the
bubblewrap-sys build failure (missing meson/ninja/libcap-dev) and
handles submodule initialization.
Two CI fixes:

1. Segfault: libboxlite.a embeds libgvproxy (a Go c-archive) whose
   .init_array constructors try to start a second Go runtime on Linux
   ELF, crashing the test binary. Remove .init_array section to prevent
   double-init.

2. errcheck: handle Write return values in bridge_callback.go.

Also switch fix-go-symbols.sh from 20 explicit --localize-symbol flags
to --wildcard patterns with [a-z] character classes, which match Go
runtime symbols (_cgo_panic, x_cgo_init, crosscall2) while preserving
package-specific CGo function bridges (_cgo_<hash>_Cfunc_*).
@DorianZheng DorianZheng merged commit c1c54c9 into main Mar 4, 2026
19 checks passed
@DorianZheng DorianZheng deleted the refactor/go-sdk-direct-ffi branch March 4, 2026 07:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant