diff --git a/.github/workflows/run_examples.yml b/.github/workflows/run_examples.yml new file mode 100644 index 0000000..7c6dc2c --- /dev/null +++ b/.github/workflows/run_examples.yml @@ -0,0 +1,30 @@ +name: Run examples + +on: [push, pull_request] + +env: + CGO_ENABLED: 0 + +jobs: + run: + strategy: + matrix: + os: [ubuntu-latest, macos-latest] + + runs-on: ${{ matrix.os }} + + steps: + - uses: actions/checkout@v4 + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version: '1.22.x' + - name: Install libffi + if: runner.os == 'macOS' + run: | + brew update + brew install libffi + - name: Run example + run: go run examples/simple/cos/main_unix.go + env: + DYLD_FALLBACK_LIBRARY_PATH: $DYLD_FALLBACK_LIBRARY_PATH:/opt/homebrew/opt/libffi/lib diff --git a/README.md b/README.md index c958585..c1d32ff 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,8 @@ You can use [purego](https://github.com/ebitengine/purego) to call C code withou ## Requirements ### OS/Architecture +- darwin/amd64 +- darwin/arm64 - freebsd/amd64 - freebsd/arm64 - linux/amd64 @@ -42,6 +44,16 @@ Note: Use this `-gcflags="github.com/ebitengine/purego/internal/fakecgo=-std"` b #### Windows You need a `libffi-8.dll` next to the executable/root folder of your project or inside C:\Windows\System32. If you don't want to build libffi from source, you can find this dll for example inside the [Windows embeddable package](https://www.python.org/downloads/windows/) of Python. +#### macOS +You can use [Homebrew](https://brew.sh/) to install libffi: +```sh +brew install libffi +``` +Note: If dlopen can't find the libffi.8.dylib file, you can try setting this environment variable: +```sh +export DYLD_FALLBACK_LIBRARY_PATH=$DYLD_FALLBACK_LIBRARY_PATH:/opt/homebrew/opt/libffi/lib +``` + ## Examples In this example we use the puts function inside the standard C library to print "Hello World!" to the console: diff --git a/abi.go b/abi.go index b129aab..6009fa5 100644 --- a/abi.go +++ b/abi.go @@ -1,4 +1,4 @@ -//go:build ((freebsd || linux) && arm64) || (windows && (amd64 || arm64)) +//go:build ((freebsd || linux || darwin) && arm64) || (windows && (amd64 || arm64)) package ffi diff --git a/abi_amd64.go b/abi_amd64.go index 79768c7..2456760 100644 --- a/abi_amd64.go +++ b/abi_amd64.go @@ -1,4 +1,4 @@ -//go:build freebsd || linux +//go:build freebsd || linux || darwin package ffi diff --git a/examples/simple/cos/main_unix.go b/examples/simple/cos/main_unix.go index e56ccb3..fb21b8e 100644 --- a/examples/simple/cos/main_unix.go +++ b/examples/simple/cos/main_unix.go @@ -1,4 +1,4 @@ -//go:build (freebsd || linux) && (amd64 || arm64) +//go:build (freebsd || linux || darwin) && (amd64 || arm64) package main @@ -18,6 +18,8 @@ func main() { filename = "libm.so.6" case "freebsd": filename = "libm.so.5" + case "darwin": + filename = "libm.dylib" } // open the shared library diff --git a/ffi.go b/ffi.go index 5cb5c3e..45b0f38 100644 --- a/ffi.go +++ b/ffi.go @@ -1,4 +1,4 @@ -//go:build (freebsd || linux || windows) && (amd64 || arm64) +//go:build (freebsd || linux || windows || darwin) && (amd64 || arm64) package ffi diff --git a/ffi_darwin.go b/ffi_darwin.go new file mode 100644 index 0000000..a3b5441 --- /dev/null +++ b/ffi_darwin.go @@ -0,0 +1,31 @@ +//go:build darwin && (amd64 || arm64) + +package ffi + +import ( + "github.com/ebitengine/purego" +) + +func init() { + const filename = "libffi.8.dylib" + + libffi, err := purego.Dlopen(filename, purego.RTLD_LAZY) + if err != nil { + panic(err) + } + + prepCif, err = purego.Dlsym(libffi, "ffi_prep_cif") + if err != nil { + panic(err) + } + + prepCifVar, err = purego.Dlsym(libffi, "ffi_prep_cif_var") + if err != nil { + panic(err) + } + + call, err = purego.Dlsym(libffi, "ffi_call") + if err != nil { + panic(err) + } +} diff --git a/types.go b/types.go index bb68047..741626e 100644 --- a/types.go +++ b/types.go @@ -1,4 +1,4 @@ -//go:build (freebsd || linux || windows) && (amd64 || arm64) +//go:build (freebsd || linux || windows || darwin) && (amd64 || arm64) package ffi