Contributing to goffi - Zero-CGO FFI for Go
November 17, 2025 · View on GitHub
Thank you for considering contributing to goffi! This document outlines the development workflow and guidelines.
Git Workflow (Git-Flow)
This project uses Git-Flow branching model for development.
Branch Structure
main # Production-ready code (tagged releases)
└─ develop # Integration branch for next release
├─ feature/* # New features
├─ experiment/* # FFI research and prototypes
├─ bugfix/* # Bug fixes
└─ hotfix/* # Critical fixes from main
Branch Purposes
- main: Production-ready code. Only releases are merged here.
- develop: Active development branch. All features merge here first.
- feature/*: New features. Branch from
develop, merge back todevelop. - experiment/*: FFI research, platform support, assembly prototypes. Branch from
develop. - bugfix/*: Bug fixes. Branch from
develop, merge back todevelop. - hotfix/*: Critical production fixes. Branch from
main, merge to bothmainanddevelop.
Workflow Commands
Starting a New Feature
# Create feature branch from develop
git checkout develop
git pull origin develop
git checkout -b feature/my-new-feature
# Work on your feature...
git add .
git commit -m "feat: add my new feature"
# When done, merge back to develop
git checkout develop
git merge --no-ff feature/my-new-feature
git branch -d feature/my-new-feature
git push origin develop
Experimenting with FFI (Assembly, Platform Support)
# Create experiment branch from develop
git checkout develop
git pull origin develop
git checkout -b experiment/arm64-support
# Prototype assembly, test platforms...
git add .
git commit -m "experiment: ARM64 AAPCS64 ABI prototype"
# Push to share progress
git push origin experiment/arm64-support
# When stable, merge to develop
git checkout develop
git merge --no-ff experiment/arm64-support
Fixing a Bug
# Create bugfix branch from develop
git checkout develop
git pull origin develop
git checkout -b bugfix/fix-issue-123
# Fix the bug...
git add .
git commit -m "fix: resolve issue #123"
# Merge back to develop
git checkout develop
git merge --no-ff bugfix/fix-issue-123
git branch -d bugfix/fix-issue-123
git push origin develop
Creating a Release
# Create release branch from develop
git checkout develop
git pull origin develop
git checkout -b release/v0.2.0
# Update version numbers, CHANGELOG, etc.
git add .
git commit -m "chore: prepare release v0.2.0"
# Merge to main and tag
git checkout main
git merge --no-ff release/v0.2.0
git tag -a v0.2.0 -m "Release v0.2.0"
# Merge back to develop
git checkout develop
git merge --no-ff release/v0.2.0
# Delete release branch
git branch -d release/v0.2.0
# Push everything
git push origin main develop --tags
Hotfix (Critical Production Bug)
# Create hotfix branch from main
git checkout main
git pull origin main
git checkout -b hotfix/critical-bug
# Fix the bug...
git add .
git commit -m "fix: critical production bug"
# Merge to main and tag
git checkout main
git merge --no-ff hotfix/critical-bug
git tag -a v0.1.1 -m "Hotfix v0.1.1"
# Merge to develop
git checkout develop
git merge --no-ff hotfix/critical-bug
# Delete hotfix branch
git branch -d hotfix/critical-bug
# Push everything
git push origin main develop --tags
Commit Message Guidelines
Follow Conventional Commits specification:
<type>(<scope>): <description>
[optional body]
[optional footer]
Types
- feat: New feature (e.g., new platform support, API improvements)
- fix: Bug fix (e.g., assembly errors, race conditions)
- docs: Documentation changes
- style: Code style changes (formatting, etc.)
- refactor: Code refactoring (e.g., assembly optimization)
- test: Adding or updating tests
- chore: Maintenance tasks (build, dependencies, etc.)
- perf: Performance improvements (critical for FFI!)
- experiment: Research and prototypes (platform support, new ABIs)
Examples
feat: add ARM64 Linux support with AAPCS64 ABI
fix: correct Win64 shadow space handling in assembly
docs: update PERFORMANCE.md with ARM64 benchmarks
refactor: optimize System V register loading sequence
test: add race detector tests for concurrent FFI calls
chore: update golangci-lint configuration
perf: reduce FFI overhead to 80ns with assembly tweaks
experiment: prototype macOS Apple Silicon support
Code Quality Standards
Before Committing
-
Format code:
go fmt ./... -
Run linter:
golangci-lint run --config=.golangci.yml ./... -
Run tests with race detector:
go test -race ./... -
Run benchmarks (FFI performance critical!):
go test -bench=BenchmarkGoffi -benchmem ./ffi -
Pre-release check (comprehensive):
bash scripts/pre-release-check.sh
Pull Request Requirements
- Code is formatted (
go fmt ./...) - Linter passes (
golangci-lint run) - All tests pass with race detector (
go test -race ./...) - Benchmarks don't regress (FFI overhead < 200ns)
- New code has tests (minimum 70% coverage, current: 89.1%)
- Platform-specific code tested on target OS
- Assembly changes validated on real hardware
- Documentation updated (if applicable)
- Commit messages follow conventions
- No sensitive data (credentials, tokens, etc.)
Development Setup
Prerequisites
- Go 1.25 or later (required for latest runtime.cgocall features)
- golangci-lint (code quality)
- GCC or Clang (for race detector, optional but recommended)
- Platform access:
- Linux AMD64 (primary development)
- Windows AMD64 (cross-platform testing)
- WSL2 with Go (alternative for Windows developers)
Install Dependencies
# Install golangci-lint
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
# Verify installation
golangci-lint --version
go version # Should be 1.25+
Running Tests
# Run all tests
go test ./...
# Run with coverage
go test -cover ./...
# Run with race detector (CRITICAL for FFI!)
go test -race ./...
# Run benchmarks
go test -bench=. -benchmem ./ffi
# Run platform-specific tests
GOOS=linux GOARCH=amd64 go test ./...
GOOS=windows GOARCH=amd64 go test ./...
Running Linter
# Run linter
golangci-lint run --config=.golangci.yml ./...
# Run with verbose output
golangci-lint run --config=.golangci.yml --verbose ./...
Project Structure
goffi/
├── .github/
│ ├── CODEOWNERS # Code ownership
│ └── workflows/ # CI/CD
│ └── ci.yml # GitHub Actions
├── .golangci.yml # Linter configuration
├── .codecov.yml # Codecov configuration
├── scripts/
│ └── pre-release-check.sh # Pre-release validation
├── docs/
│ └── PERFORMANCE.md # Performance guide & benchmarks
├── examples/
│ └── simple/ # Usage examples
├── experiments/ # Research & prototypes (not production)
├── ffi/ # Core FFI package
│ ├── ffi.go # Public API
│ ├── ffi_test.go # Tests
│ └── benchmark_test.go # Performance benchmarks
├── types/ # Type system
│ ├── types.go # Type descriptors
│ └── types_test.go # Type tests
├── internal/
│ ├── arch/ # Architecture-specific code
│ ├── syscall/ # Low-level syscalls
│ │ ├── call_unix.s # System V AMD64 assembly
│ │ └── call_windows.s # Win64 assembly
│ ├── runtime/ # Go runtime integration
│ ├── fakecgo/ # runtime.cgocall implementation
│ └── dl/ # Dynamic library loading
├── reference/ # External reference code (gitignored)
│ ├── libffi/ # libffi reference
│ └── purego/ # purego comparison
├── CHANGELOG.md # Version history
├── API_TODO.md # API improvement backlog
├── CONTRIBUTING.md # This file
├── CODE_OF_CONDUCT.md # Community standards
└── README.md # Main documentation
Adding New Features
- Check if issue exists, if not create one
- Discuss approach in the issue (especially for assembly/platform changes!)
- Create feature or experiment branch from
develop - Implement feature with tests
- Test on target platform (critical for FFI!)
- Run benchmarks to ensure no performance regression
- Update documentation (README.md, PERFORMANCE.md, etc.)
- Run quality checks (
scripts/pre-release-check.sh) - Create pull request to
develop - Wait for code review
- Address feedback
- Merge when approved
Platform-Specific Development
Adding New Platform Support
- Research platform ABI (System V, Win64, AAPCS64, etc.)
- Create
experiment/platform-namebranch - Implement assembly in
internal/syscall/call_platform.s - Add platform detection in
internal/arch/ - Write platform-specific tests
- Run benchmarks on real hardware
- Document limitations and ABI details
- Update CHANGELOG.md with platform support
Assembly Guidelines
- Comment every instruction - Assembly is hard to review!
- Reference ABI specification - Add links in comments
- Test on real hardware - VMs may hide bugs
- Benchmark before/after - Performance is critical
- Handle edge cases - Variadic, floats, large structs
- Follow platform conventions - Red zones, shadow space, etc.
Example assembly header:
// System V AMD64 ABI Implementation
// Specification: https://refspecs.linuxbase.org/elf/x86_64-abi-0.99.pdf
// Registers: RDI, RSI, RDX, RCX, R8, R9 (GP), XMM0-7 (FP)
// Red zone: 128 bytes below RSP
Code Style Guidelines
General Principles
- Follow Go conventions and idioms
- Write self-documenting code
- Add comments for complex logic (especially assembly!)
- Keep functions small and focused
- Use meaningful variable names
- Performance matters - This is a low-level FFI library
Naming Conventions
- Public types/functions:
PascalCase(e.g.,CallFunction,TypeDescriptor) - Private types/functions:
camelCase(e.g.,loadLibrary,prepareArgs) - Constants:
PascalCasewith context (e.g.,DefaultCall,WindowsCallingConvention) - Test functions:
Test*(e.g.,TestCallFunction) - Benchmark functions:
Benchmark*(e.g.,BenchmarkGoffiOverhead)
Error Handling
- Use typed errors (
LibraryError,InvalidCallInterfaceError, etc.) - Always check and handle errors
- Add context with error wrapping:
fmt.Errorf("context: %w", err) - Never ignore errors
- Validate inputs (type safety critical for FFI!)
Testing
- Use
testingpackage (standard library) - Test both success and error cases
- Use table-driven tests when appropriate
- Always test with race detector (
-race) - Write benchmarks for performance-critical code
- Test on all supported platforms
Performance Considerations
- FFI overhead matters - Every nanosecond counts
- Profile before optimizing:
go test -cpuprofile=cpu.prof - Benchmark before/after changes:
benchstat before.txt after.txt - Target: < 200ns FFI overhead (current: 88-114ns)
- Avoid allocations in hot paths
- Reuse
CallInterfaceobjects
Getting Help
- Check existing issues and discussions
- Read documentation in
docs/ - Review
CHANGELOG.mdfor known limitations - Review
API_TODO.mdfor planned improvements - Ask questions in GitHub Issues: https://github.com/go-webgpu/goffi/issues
License
By contributing, you agree that your contributions will be licensed under the MIT License.
Thank you for contributing to goffi! 🚀
Building the future of Zero-CGO FFI for Go