A build system for creating Python packages with Go extensions, inspired by maturin for Rust/Python.
- Pure Go: No CGo required, thanks to purego
- cffi Bindings: Fast, type-safe Python bindings
- Cross-Platform: Linux, macOS, Windows support
- PEP 517 Compliant: Standard Python packaging
- Binary Bundling: Include Go binaries in your Python packages
go install github.com/NoRaincheck/gofre@latestOr build from source:
git clone https://github.com/NoRaincheck/gofre
cd gofre
go build -o gofre .gofre new my-package
cd my-package// pkg/core/core.go
package core
//export Add
func Add(a, b int64) int64 {
return a + b
}
//export Multiply
func Multiply(a, b int64) int64 {
return a * b
}gofre developimport my_package
result = my_package.Add(2, 3)
print(result) # 5| Command | Description |
|---|---|
gofre new <name> |
Create a new project |
gofre build |
Build the package |
gofre build -o <dir> |
Build with custom output directory |
gofre develop |
Build and install in current venv |
gofre publish |
Publish to PyPI |
gofre bench |
Run benchmarks |
GoFre provides significant performance improvements over pure Python by leveraging Go's performance.
Note: The overhead of FFI calls means that very simple operations (like sum()) may not benefit from Go extensions.
GoFre shines for complex computational workloads.
| Implementation | Time | Speedup |
|---|---|---|
| Pure Python | 175.1 ms | 1.0x |
| GoFre | 3.0 ms | 58x |
| Implementation | Time | Speedup |
|---|---|---|
| Pure Python | 97.9 ms | 1.0x |
| GoFre | 1.5 ms | 63x |
| Implementation | Time | Speedup |
|---|---|---|
| Pure Python | 14.8 ms | 1.0x |
| GoFre | 0.6 ms | 24x |
Based on programming-language-benchmarks:
| Benchmark | Pure Python | Go Forge | Speedup |
|---|---|---|---|
| binarytrees(18) | >30s | 2.3s | >13x |
| fasta(2.5M) | 4.7s | 0.12s | 39x |
| knucleotide | >30s | 0.68s | >44x |
| json-serde | 1.9s | 0.14s | 14x |
GoFre also benchmarks HTTP server performance across six approaches β from pure Python to Go with embedded pocketpy. See the full results and methodology.
| Server | Req/sec (avg) | Idle RSS | Peak RSS | Binary |
|---|---|---|---|---|
| Pure Go (stdlib) | ~42,000 | 10.3 MB | 19.0 MB | 8.0 MB |
| Go + pocketpy | ~40,000 | 13.3 MB | 21.8 MB | 9.7 MB |
| Pure Python | ~4,600 | 15.2 MB | 15.4 MB | β |
| CPython + Go cffi | ~4,500 | 23.1 MB | 29.6 MB | 2.1 MB |
| FastAPI + uvicorn | ~7,000 | 36.9 MB | 37.4 MB | β |
| Flask (dev server) | ~2,100 | 26.5 MB | 27.8 MB | β |
Go + pocketpy delivers ~5-6x the throughput of FastAPI/Flask while keeping memory under 22 MB peak in a single 9.7 MB binary. See examples/webserver/README.md for full details.
gofre/
βββ main.go
βββ go.mod
βββ cmd/ # CLI commands
βββ internal/ # Library code
β βββ bindings/ # Go parser + Python code generator
β βββ build/ # Build system (Go + wheel)
β βββ config/ # Config loader (pyproject.toml)
β βββ pocketpy/ # Embedded pocketpy interpreter (excluded with no_pocketpy tag)
β βββ gomod/ # Bridge modules (http, json)
βββ tests/ # Unit tests
my-package/
βββ pyproject.toml
βββ go.mod
βββ pkg/
β βββ core/
β βββ core.go # Go code with //export functions
βββ cmd/
βββ main.go # CGo bridge
Build artifacts go to build/ and dist/ by default. Use --output-dir to put them elsewhere.
- Parse: GoFre parses your Go source files to find exported functions
- Build: Compiles Go code to a shared library (
.so,.dylib,.dll) - Generate: Creates cffi bindings for Python
- Package: Builds a wheel with the shared library and Python wrappers
# Build for Linux from macOS
GOOS=linux GOARCH=amd64 gofre build
# Build for Windows from macOS
GOOS=windows GOARCH=amd64 gofre build
# Build for macOS arm64 from Intel
GOOS=darwin GOARCH=arm64 gofre build| Platform | Architecture | Status |
|---|---|---|
| Linux | x86_64 | β |
| Linux | aarch64 | β |
| macOS | x86_64 | β |
| macOS | arm64 | β |
| Windows | x86_64 | β |
| Windows | arm64 | β |
[build-system]
requires = ["gofre>=0.1.0"]
build-backend = "gofre.build"
[project]
name = "my-package"
version = "0.1.0"
requires-python = ">=3.8"
dependencies = ["cffi>=1.0.0"]
[tool.gofre]
module = "github.com/user/my-package"
bindings = "cffi"
pkg-dir = "pkg"
build-tags = []Use build-tags to pass custom Go build tags to go build. This is useful for excluding parts of the codebase from
compilation.
[tool.gofre]
module = "github.com/user/my-package"
build-tags = ["no_pocketpy"]This produces:
go build -buildmode=c-shared -tags no_pocketpy -o output ./cmd/
GoFre ships with the no_pocketpy build tag, which excludes the embedded pocketpy interpreter and related bridge code.
Files excluded by build tags:
internal/pocketpy/*β pocketpy Go wrapper and C sourceinternal/gomod/http/register.goβ pocketpy HTTP bridgeinternal/gomod/json/register.goβ pocketpy JSON bridgeexamples/webserver_binary/β pocketpy-based webserver example
When no_pocketpy is set, the cffi exports in http/cffi_exports.go and json/cffi_exports.go remain available. If
your cmd/ imports pocketpy directly, the build will fail with a missing import error.
Contributions are welcome! Please feel free to submit a Pull Request.
MIT License
- maturin - Inspiration for the build system
- purego - CGo-free C function calls
- cffi - Python FFI
- programming-language-benchmarks - Benchmark data