purego-cef
Go bindings for the Chromium Embedded Framework C API, using purego instead of cgo.
Linux only. CGO_ENABLED=0.
[!WARNING]
This is early stage and very unstable, API changes daily as I iterate to make it work for Dumber. I strongly do not recommend using it yet.
Architecture
The binding layer is generated from CEF C headers (~114 files). The generator parses all headers and produces:
- Inbound port interfaces for every CEF handler and type (Client, LifeSpanHandler, RenderHandler, etc.)
- Outbound port interfaces grouping CEF free functions and object methods by domain
- A composite CAPI interface embedding all outbound ports
- Typed constructors for handlers (
NewClient(impl Client), NewRenderHandler(impl RenderHandler), etc.)
- Typed wrappers for CEF objects with automatic refcount management
- C struct layouts and purego symbol registration
- Doc comments extracted from CEF C headers
A hand-written core domain handles UTF-16 string conversion, reference counting, CEF lifecycle orchestration, and the Bridge adapter implementing the CAPI interface.
Mocks for all interfaces are generated by Mockery v3 and shipped in cef/mocks/.
Usage
package main
import (
"runtime"
"github.com/bnema/purego-cef/cef"
)
func main() {
runtime.LockOSThread()
cef.MaybeExitSubprocess()
if err := cef.Init(cef.DefaultSettings()); err != nil {
panic(err)
}
defer cef.Shutdown()
client := cef.NewClient(myClient{})
_ = client
// Your render loop here
for {
cef.DoMessageLoopWork()
}
}
// Implement the Client interface — only the methods you need.
type myClient struct{}
func (c myClient) GetLifeSpanHandler() cef.LifeSpanHandler { return nil }
func (c myClient) GetRenderHandler() cef.RenderHandler { return myRenderer{} }
// ... other handler getters return nil
Requirements
- Go 1.26+
- CEF 145 runtime in
$CEF_DIR or ~/.local/share/cef
Building
CGO_ENABLED=0 go build ./...
CGO_ENABLED=0 go test ./...
Integration tests need the CEF runtime:
CEF_DIR=$HOME/.local/share/cef go test -tags=cef_integration ./integration
Regenerating bindings
go generate ./...
Or manually:
go run ./cmd/cefgen \
--headers-dir ~/.local/share/cef/include \
--capi-dir internal/capi \
--port-in-dir internal/ports/in \
--port-out-dir internal/ports/out \
--public-dir cef
mockery
Project layout
cef/ public API (generated) + mocks
bridge.go hand-written: handler constructors, string helpers
init.go hand-written: Init(), Shutdown(), orchestration
internal/
ports/in/ inbound port interfaces (generated)
ports/out/ outbound port interfaces (generated) + composite CAPI (hand-written) + mocks
core/ domain logic: engine, string marshaling, refcount (hand-written)
capi/ purego bindings + bridge (generated + hand-written)
loader/ dlopen libcef.so + version validation (hand-written)
cmd/cefgen/ binding generator (parser, model, emitter, templates)
integration/ integration tests (require CEF runtime)
License
MIT