cgo

package module
v0.0.9 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 17, 2026 License: MIT Imports: 11 Imported by: 1

README

cgo

Pure-Go FFI Library for Windows, Linux, and macOS - No CGO Required

Overview

cgo is a zero-c-dependency, pure-Go Foreign Function Interface (FFI) library that enables calling C shared libraries directly from Go code without requiring the CGO toolchain. Built on top of https://github.com/ebitengine/purego, it provides a unified API for Windows, Linux, and macOS with enhanced features for modern Go development.

And in addition, it adds support for struct parameters and return values on the Windows platform.

Features

  • 🚫 No CGO - Eliminates cross-compilation complexities and C toolchain dependencies
  • 🎯 Unified API - Consistent interface across all supported platforms
  • 📦 Zero Dependencies - Pure Go implementation, only standard library + purego
  • 🔍 Extern Variable Support - Read and write C extern global variables
  • 🚀 Fast Development - No recompilation needed when changing Go code
  • 🏃 Cross-Platform Support: Windows (dll), Linux (so), macOS (dylib)

Quick Start

Installation
go get github.com/goexlib/cgo
1. Basic Library Usage
package main

import (
    "fmt"
    "github.com/goexlib/cgo"
)

func main() {
    // Load a shared library file
    lib, err := cgo.LoadLibrary("path/to/library.file")
    if err != nil {
        panic(err)
    }
    defer lib.Close()

    // Load a function symbol
    sym, err := lib.GetSymbol("add")
    if err != nil {
        panic(err)
    }

    // Call the C function
    result := cgo.CallRet[cgo.Int](sym.Addr(), cgo.Int(5), cgo.Int(3))
    fmt.Printf("5 + 3 = %d\n", result)
}
2. Working with Extern Variables
package main

import (
    "fmt"
    "github.com/goexlib/cgo"
)

func main() {
    lib, err := cgo.LoadLibrary("mylib")
    if err != nil {
        panic(err)
    }
    defer lib.Close()
	
    // Access an extern integer variable
    counter,err := cgo.GetExternVariant[cgo.Int](lib, "counter")
    if err != nil {
        panic(err)
    }

    fmt.Printf("Counter value: %d\n", *counter) // 0
	
	fnIncrement, err := lib.GetSymbol("increment")
	if err != nil {
		panic(err)
	}
	cgo.Call(fnIncrement)
	
	fmt.Printf("Counter value: %d\n", *counter) // 1
	
	*counter = 999
	cgo.Call(fnIncrement)
	fmt.Printf("Counter value: %d\n", *counter) // 1000
}
3. Platform-Specific Code Paths
package main

import (
    "runtime"
    "github.com/goexlib/cgo"
)

func main() {
    var libPath string
    
    switch runtime.GOOS {
    case "windows":
        libPath = "C:\\libs\\mylib.dll"
    case "darwin":
        libPath = "/usr/local/lib/libmylib.dylib"
    case "linux":
        libPath = "/usr/lib/libmylib.so"
    }
    
    lib, err := cgo.LoadLibrary(libPath)
    if err != nil {
        panic(err)
    }
    defer lib.Close()
    
    // Use library...
}
4. Callbacks with Float/Struct Arguments and Return Values

cgo.NewCallback converts a Go function into a C function pointer. It implements the full platform C calling convention — including float32/float64 and struct arguments and return values — via this package's own assembly thunks on linux/amd64, linux/arm64, darwin/amd64, darwin/arm64 and windows/amd64. (purego.NewCallback and syscall.NewCallback support neither float/struct returns nor struct arguments.)

package main

import "github.com/goexlib/cgo"

type Point struct {
    X, Y cgo.Float
}

func main() {
    // A callback taking and returning a struct:
    cb := cgo.NewCallback(func(p Point) Point {
        return Point{X: p.X * 2, Y: p.Y * 2}
    })

    // Pass cb to a C function expecting: Point (*)(Point)
    _ = cb
}

Supported callback signatures:

int/pointer/bool args float args struct args float return struct return
linux/amd64, linux/arm64
darwin/amd64, darwin/arm64
windows/amd64
other purego platforms

Struct types must have the same memory layout as the C struct (including padding). Register/stack placement, homogeneous float aggregates, small structs in registers, by-reference and by-value large structs, and the hidden struct-return pointer all follow the platform C ABI (System V AMD64, AAPCS64 incl. Apple's stack packing, and the Microsoft x64 convention).

Platform-Specific Notes

Windows
  • Searches in: application directory, system directories, PATH
  • Supports both stdcall and cdecl calling conventions (X64 ABI)
Linux
  • Respects LD_LIBRARY_PATH environment variable
macOS
  • Searges in: @rpath, @executable_path, system directories
  • Supports framework bundles

License

This project is licensed under the MIT License

Documentation

Index

Constants

View Source
const (
	RTLD_DEFAULT = purego.RTLD_DEFAULT
	RTLD_LAZY    = purego.RTLD_LAZY
	RTLD_NOW     = purego.RTLD_NOW
	RTLD_LOCAL   = purego.RTLD_LOCAL
	RTLD_GLOBAL  = purego.RTLD_GLOBAL
)

Variables

This section is empty.

Functions

func CBool

func CBool(b bool) int8

func CSlice

func CSlice[S ~[]E, E any](s S) unsafe.Pointer

func CString

func CString(s string) unsafe.Pointer

func Call

func Call[F ~uintptr](fn F, args ...any)

Call calls a C function.

func CallRaw

func CallRaw(fn uintptr, args ...uintptr) (r1, r2 uintptr, err syscall.Errno)

func CallRet

func CallRet[T any, F ~uintptr](fn F, args ...any) (ret T)

CallRet calls a C function and returns a value.

func Dlclose

func Dlclose(handle uintptr) error

Dlclose decrements the reference count on the dynamic library handle.

func Dlopen

func Dlopen(path string, mode int) (uintptr, error)

Dlopen examines the dynamic library or bundle file specified by path.

The mode was ignored on Windows.

func Dlsym

func Dlsym(handle uintptr, name string) (uintptr, error)

Dlsym takes a "handle" of a dynamic library returned by Dlopen and the symbol name.

func Free added in v0.0.6

func Free(p Pointer)

func GetExternVariant

func GetExternVariant[T any, L ~uintptr](lib L, name string) (pv *T, err error)

func GoBool

func GoBool[T comparable](v T) bool

func GoPointer added in v0.0.5

func GoPointer[T any](p uintptr) *T

func GoSlice

func GoSlice[T comparable](p unsafe.Pointer) []T

func GoSliceN

func GoSliceN[T any](p unsafe.Pointer, n int) []T

func GoSliceNTemp

func GoSliceNTemp[T any](p unsafe.Pointer, n int) []T

func GoSliceTemp

func GoSliceTemp[T comparable](p unsafe.Pointer) []T

func GoString

func GoString(s unsafe.Pointer) string

func GoStringN

func GoStringN(s unsafe.Pointer, n int) string

func GoStringNTemp

func GoStringNTemp(s unsafe.Pointer, n int) string

func GoStringTemp

func GoStringTemp(s unsafe.Pointer) string

func Length

func Length[T comparable](p unsafe.Pointer) (n int)

Length Get the length of an array ending with zero

func Memcpy added in v0.0.2

func Memcpy(dst, src Pointer, size Sizet)

func Memset added in v0.0.2

func Memset(p Pointer, val int, size Sizet)

func NewCallback

func NewCallback(fn any) uintptr

NewCallback converts a Go function to a C function pointer that can be passed to C code as a callback.

On linux/amd64, linux/arm64, darwin/amd64 and darwin/arm64 the full C calling convention is supported, including float32/float64 and struct arguments and return values, following the System V AMD64 and AAPCS64 ABIs. Struct types must have the same memory layout as their C counterpart (add explicit padding fields if needed).

Only a limited number of callbacks may be created in a single Go process, and any memory allocated for these callbacks is never released.

func RegisterFunc

func RegisterFunc(pf any, cfn uintptr) (err error)

func RegisterLibFunc

func RegisterLibFunc(pf any, lib uintptr, symbol string) (err error)

func Strlen

func Strlen(s unsafe.Pointer) (n int)

Types

type Char

type Char = int8

C types.

type Double

type Double = float64

C types.

type Float

type Float = float32

C types.

type Int

type Int = int32

C types.

type Intptr

type Intptr = int

C types.

type LazyLibrary

type LazyLibrary struct {
	// contains filtered or unexported fields
}

func NewLazyLibrary

func NewLazyLibrary(name string, fallbacks ...string) (l *LazyLibrary)

func (*LazyLibrary) Handle added in v0.0.3

func (l *LazyLibrary) Handle() uintptr

func (*LazyLibrary) Load

func (l *LazyLibrary) Load() error

func (*LazyLibrary) NewSymbol

func (l *LazyLibrary) NewSymbol(name string) *LazySymbol

type LazySymbol

type LazySymbol struct {
	// contains filtered or unexported fields
}

func (*LazySymbol) Addr

func (s *LazySymbol) Addr() uintptr

func (*LazySymbol) CallRaw

func (s *LazySymbol) CallRaw(args ...uintptr) (r1, r2 uintptr, err error)

func (*LazySymbol) Find

func (s *LazySymbol) Find() error

type Library

type Library uintptr

func LoadLibrary

func LoadLibrary(path string) (Library, error)

func (Library) Close

func (l Library) Close()

func (Library) GetSymbol

func (l Library) GetSymbol(name string) (Symbol, error)

func (Library) Handle

func (l Library) Handle() uintptr

type Long

type Long = int32

C types.

type LongLong

type LongLong = int64

C types.

type Pointer

type Pointer = unsafe.Pointer

C types.

func Malloc added in v0.0.6

func Malloc(size Sizet) Pointer

type Short

type Short = int16

C types.

type Sizet

type Sizet = uint

C types.

type Ssize

type Ssize = int

C types.

type Symbol

type Symbol uintptr

func (Symbol) Addr

func (s Symbol) Addr() uintptr

func (Symbol) CallRaw

func (s Symbol) CallRaw(args ...uintptr) (r1, r2 uintptr, err syscall.Errno)

type Uchar

type Uchar = uint8

C types.

type Uint

type Uint = uint32

C types.

type Uintptr

type Uintptr = uintptr

C types.

type Ulong

type Ulong = uint32

C types.

type UlongLong

type UlongLong = uint64

C types.

type Ushort

type Ushort = uint16

C types.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL