Skip to content

feat(bindings/go): Add windows platform support #5992

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Apr 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/scripts/test_go_binding/matrix.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ build:
goos: "darwin"
goarch: "arm64"
os: "macos-latest"
- target: "x86_64-pc-windows-msvc"
cc: "cl.exe"
goos: "windows"
goarch: "amd64"
os: "windows-latest"
service:
- "fs"

60 changes: 54 additions & 6 deletions .github/workflows/ci_bindings_go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ on:
- "bindings/c/**"
- "bindings/go/**"
- ".github/workflows/ci_bindings_go.yml"
- ".github/scripts/test_go_binding/matrix.yaml"
workflow_dispatch:

concurrency:
Expand Down Expand Up @@ -82,10 +83,17 @@ jobs:
path: "tools"
- name: Setup Rust toolchain
uses: ./.github/actions/setup
- name: Setup Target
- name: Setup Target (Linux/macOS)
if: runner.os != 'Windows'
env:
TARGET: ${{ matrix.build.target }}
run: rustup target add $TARGET
- name: Setup Target (Windows)
if: runner.os == 'Windows'
env:
TARGET: ${{ matrix.build.target }}
run: |
rustup target add $env:TARGET
- uses: actions/setup-go@v5
with:
go-version: stable
Expand All @@ -104,16 +112,20 @@ jobs:
- name: Install dependencies (macOS)
if: ${{ matrix.build.os == 'macos-latest' }}
run: brew install zstd libffi
- name: Build C Binding
- name: Install dependencies (Windows)
if: ${{ matrix.build.os == 'windows-latest' }}
uses: ilammy/msvc-dev-cmd@v1
- name: Build C Binding (Linux/macOS)
working-directory: bindings/c
if: runner.os != 'Windows'
env:
VERSION: "latest"
SERVICE: ${{ matrix.service }}
TARGET: ${{ matrix.build.target }}
CC: ${{ matrix.build.cc }}
OS: ${{ matrix.build.os }}
run: |
cargo build --target $TARGET --release
cargo build --target $TARGET --release
DIR=$GITHUB_WORKSPACE/libopendal_c_${VERSION}_${SERVICE}_$TARGET
mkdir $DIR
if [ ${OS} == 'ubuntu-latest' ]; then
Expand All @@ -122,29 +134,65 @@ jobs:
SO=dylib
fi
zstd -19 ./target/$TARGET/release/libopendal_c.$SO -o $DIR/libopendal_c.$TARGET.$SO.zst
- name: Build C Binding (Windows)
working-directory: bindings/c
if: runner.os == 'Windows'
env:
VERSION: "latest"
SERVICE: ${{ matrix.service }}
TARGET: ${{ matrix.build.target }}
CC: ${{ matrix.build.cc }}
OS: ${{ matrix.build.os }}
run: |
cargo build --target $env:TARGET --release
$DIR="$env:GITHUB_WORKSPACE\libopendal_c_${env:VERSION}_${env:SERVICE}_${env:TARGET}"
Rename-Item -Path "./target/$env:TARGET/release/opendal_c.dll" -NewName "libopendal_c.dll"
New-Item -ItemType Directory -Force -Path $DIR
zstd -19 "./target/${env:TARGET}/release/libopendal_c.dll" -o "$DIR/libopendal_c.${env:TARGET}.dll.zst"
- name: Build Go Artifact
working-directory: tools/internal/generate
env:
MATRIX: '{"build": [${{ toJson(matrix.build) }}], "service": ["${{ matrix.service }}"]}'
VERSION: "latest"
run: |
go run generate.go
- name: Setup Go Workspace
- name: Setup Go Workspace (Linux/macOS)
env:
SERVICE: ${{ matrix.service }}
working-directory: bindings/go/tests
if: runner.os != 'Windows'
run: |
go work init
go work use ..
go work use ./behavior_tests
go work use $GITHUB_WORKSPACE/$(echo $SERVICE | sed 's/-/_/g')
- name: Run tests
- name: Setup Go Workspace (Windows)
env:
SERVICE: ${{ matrix.service }}
working-directory: bindings/go/tests
if: runner.os == 'Windows'
run: |
go work init
go work use ..
go work use ./behavior_tests
go work use $env:GITHUB_WORKSPACE/$($env:SERVICE -replace '-','_')
- name: Run tests (Linux/macOS)
env:
OPENDAL_TEST: ${{ matrix.service }}
OPENDAL_FS_ROOT: "/tmp/opendal/"
OPENDAL_FS_ROOT: runner.temp
working-directory: bindings/go/tests/behavior_tests
if: runner.os != 'Windows'
run: |
if [ ${{ matrix.build.os }} == 'macos-latest' ]; then
export DYLD_FALLBACK_LIBRARY_PATH=$DYLD_FALLBACK_LIBRARY_PATH:/opt/homebrew/opt/libffi/lib
fi
CGO_ENABLE=0 go test -v -run TestBehavior
- name: Run tests (Windows)
env:
OPENDAL_TEST: ${{ matrix.service }}
OPENDAL_FS_ROOT: runner.temp
working-directory: bindings/go/tests/behavior_tests
if: runner.os == 'Windows'
run: |
$env:CGO_ENABLE = "0"
go test -v -run TestBehavior
3 changes: 1 addition & 2 deletions bindings/go/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import (
"unsafe"

"github.com/jupiterrider/ffi"
"golang.org/x/sys/unix"
)

// Delete removes the file or directory at the specified path.
Expand Down Expand Up @@ -55,7 +54,7 @@ var withOperatorDelete = withFFI(ffiOpts{
aTypes: []*ffi.Type{&ffi.TypePointer, &ffi.TypePointer},
}, func(ctx context.Context, ffiCall func(rValue unsafe.Pointer, aValues ...unsafe.Pointer)) operatorDelete {
return func(op *opendalOperator, path string) error {
bytePath, err := unix.BytePtrFromString(path)
bytePath, err := BytePtrFromString(path)
if err != nil {
return err
}
Expand Down
7 changes: 3 additions & 4 deletions bindings/go/ffi.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,11 @@ import (
"errors"
"unsafe"

"github.com/ebitengine/purego"
"github.com/jupiterrider/ffi"
)

func contextWithFFIs(path string) (ctx context.Context, cancel context.CancelFunc, err error) {
libopendal, err := purego.Dlopen(path, purego.RTLD_LAZY|purego.RTLD_GLOBAL)
libopendal, err := LoadLibrary(path)
if err != nil {
return
}
Expand All @@ -41,7 +40,7 @@ func contextWithFFIs(path string) (ctx context.Context, cancel context.CancelFun
}
}
cancel = func() {
purego.Dlclose(libopendal)
_ = FreeLibrary(libopendal)
}
return
}
Expand Down Expand Up @@ -83,7 +82,7 @@ func withFFI[T any](
); status != ffi.OK {
return nil, errors.New(status.String())
}
fn, err := purego.Dlsym(libopendal, opts.sym.String())
fn, err := GetProcAddress(libopendal, opts.sym.String())
if err != nil {
return nil, err
}
Expand Down
4 changes: 2 additions & 2 deletions bindings/go/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ go 1.22.4
toolchain go1.22.5

require (
github.com/ebitengine/purego v0.7.1
github.com/jupiterrider/ffi v0.1.0
github.com/ebitengine/purego v0.8.2
github.com/jupiterrider/ffi v0.4.0
golang.org/x/sys v0.24.0
)
4 changes: 4 additions & 0 deletions bindings/go/go.sum
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
github.com/ebitengine/purego v0.7.1 h1:6/55d26lG3o9VCZX8lping+bZcmShseiqlh2bnUDiPA=
github.com/ebitengine/purego v0.7.1/go.mod h1:ah1In8AOtksoNK6yk5z1HTJeUkC1Ez4Wk2idgGslMwQ=
github.com/ebitengine/purego v0.8.2 h1:jPPGWs2sZ1UgOSgD2bClL0MJIqu58nOmIcBuXr62z1I=
github.com/ebitengine/purego v0.8.2/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/jupiterrider/ffi v0.1.0 h1:OI6ZHZJW1Io1PcfqGeLk/CBLj+//8aNdOuo558ykQQo=
github.com/jupiterrider/ffi v0.1.0/go.mod h1:tyr9EitV+PW99I6137IDwdO6ZzNyFp/noXNSfU3OYqk=
github.com/jupiterrider/ffi v0.4.0 h1:7mhlrfiBZa0kHhh2DV7mGAdXN/D8zDeu8UlaBO+ZSko=
github.com/jupiterrider/ffi v0.4.0/go.mod h1:1QCaf2VVPpGyIeU3RqQ2rHYrAPT8m9l0GhQupVYQB24=
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
7 changes: 3 additions & 4 deletions bindings/go/lister.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import (
"unsafe"

"github.com/jupiterrider/ffi"
"golang.org/x/sys/unix"
)

// Check verifies if the operator is functioning correctly.
Expand Down Expand Up @@ -312,7 +311,7 @@ var withOperatorList = withFFI(ffiOpts{
aTypes: []*ffi.Type{&ffi.TypePointer, &ffi.TypePointer},
}, func(ctx context.Context, ffiCall func(rValue unsafe.Pointer, aValues ...unsafe.Pointer)) operatorList {
return func(op *opendalOperator, path string) (*opendalLister, error) {
bytePath, err := unix.BytePtrFromString(path)
bytePath, err := BytePtrFromString(path)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -400,7 +399,7 @@ var withEntryName = withFFI(ffiOpts{
unsafe.Pointer(&bytePtr),
unsafe.Pointer(&e),
)
return unix.BytePtrToString(bytePtr)
return BytePtrToString(bytePtr)
}
})

Expand All @@ -419,6 +418,6 @@ var withEntryPath = withFFI(ffiOpts{
unsafe.Pointer(&bytePtr),
unsafe.Pointer(&e),
)
return unix.BytePtrToString(bytePtr)
return BytePtrToString(bytePtr)
}
})
15 changes: 7 additions & 8 deletions bindings/go/operator.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import (
"unsafe"

"github.com/jupiterrider/ffi"
"golang.org/x/sys/unix"
)

// Copy duplicates a file from the source path to the destination path.
Expand Down Expand Up @@ -111,7 +110,7 @@ var withOperatorNew = withFFI(ffiOpts{
}, func(ctx context.Context, ffiCall func(rValue unsafe.Pointer, aValues ...unsafe.Pointer)) operatorNew {
return func(scheme Scheme, opts *operatorOptions) (op *opendalOperator, err error) {
var byteName *byte
byteName, err = unix.BytePtrFromString(scheme.Name())
byteName, err = BytePtrFromString(scheme.Name())
if err != nil {
return
}
Expand Down Expand Up @@ -177,11 +176,11 @@ var withOperatorOptionsSet = withFFI(ffiOpts{
byteKey *byte
byteValue *byte
)
byteKey, err = unix.BytePtrFromString(key)
byteKey, err = BytePtrFromString(key)
if err != nil {
return err
}
byteValue, err = unix.BytePtrFromString(value)
byteValue, err = BytePtrFromString(value)
if err != nil {
return err
}
Expand Down Expand Up @@ -226,11 +225,11 @@ var withOperatorCopy = withFFI(ffiOpts{
byteSrc *byte
byteDest *byte
)
byteSrc, err = unix.BytePtrFromString(src)
byteSrc, err = BytePtrFromString(src)
if err != nil {
return err
}
byteDest, err = unix.BytePtrFromString(dest)
byteDest, err = BytePtrFromString(dest)
if err != nil {
return err
}
Expand Down Expand Up @@ -259,11 +258,11 @@ var withOperatorRename = withFFI(ffiOpts{
byteSrc *byte
byteDest *byte
)
byteSrc, err = unix.BytePtrFromString(src)
byteSrc, err = BytePtrFromString(src)
if err != nil {
return err
}
byteDest, err = unix.BytePtrFromString(dest)
byteDest, err = BytePtrFromString(dest)
if err != nil {
return err
}
Expand Down
7 changes: 3 additions & 4 deletions bindings/go/operator_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import (
"unsafe"

"github.com/jupiterrider/ffi"
"golang.org/x/sys/unix"
)

// Info returns metadata about the Operator.
Expand Down Expand Up @@ -325,7 +324,7 @@ var withOperatorInfoGetScheme = withFFI(ffiOpts{
unsafe.Pointer(&bytePtr),
unsafe.Pointer(&info),
)
return unix.BytePtrToString(bytePtr)
return BytePtrToString(bytePtr)
}
})

Expand All @@ -344,7 +343,7 @@ var withOperatorInfoGetRoot = withFFI(ffiOpts{
unsafe.Pointer(&bytePtr),
unsafe.Pointer(&info),
)
return unix.BytePtrToString(bytePtr)
return BytePtrToString(bytePtr)
}
})

Expand All @@ -363,6 +362,6 @@ var withOperatorInfoGetName = withFFI(ffiOpts{
unsafe.Pointer(&bytePtr),
unsafe.Pointer(&info),
)
return unix.BytePtrToString(bytePtr)
return BytePtrToString(bytePtr)
}
})
5 changes: 2 additions & 3 deletions bindings/go/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import (
"unsafe"

"github.com/jupiterrider/ffi"
"golang.org/x/sys/unix"
)

// Read reads the entire contents of the file at the specified path into a byte slice.
Expand Down Expand Up @@ -210,7 +209,7 @@ var withOperatorRead = withFFI(ffiOpts{
aTypes: []*ffi.Type{&ffi.TypePointer, &ffi.TypePointer},
}, func(ctx context.Context, ffiCall func(rValue unsafe.Pointer, aValues ...unsafe.Pointer)) operatorRead {
return func(op *opendalOperator, path string) (opendalBytes, error) {
bytePath, err := unix.BytePtrFromString(path)
bytePath, err := BytePtrFromString(path)
if err != nil {
return opendalBytes{}, err
}
Expand All @@ -234,7 +233,7 @@ var withOperatorReader = withFFI(ffiOpts{
aTypes: []*ffi.Type{&ffi.TypePointer, &ffi.TypePointer},
}, func(ctx context.Context, ffiCall func(rValue unsafe.Pointer, aValues ...unsafe.Pointer)) operatorReader {
return func(op *opendalOperator, path string) (*opendalReader, error) {
bytePath, err := unix.BytePtrFromString(path)
bytePath, err := BytePtrFromString(path)
if err != nil {
return nil, err
}
Expand Down
5 changes: 2 additions & 3 deletions bindings/go/stat.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import (
"unsafe"

"github.com/jupiterrider/ffi"
"golang.org/x/sys/unix"
)

// Stat retrieves metadata for the specified path.
Expand Down Expand Up @@ -111,7 +110,7 @@ var withOperatorStat = withFFI(ffiOpts{
aTypes: []*ffi.Type{&ffi.TypePointer, &ffi.TypePointer},
}, func(ctx context.Context, ffiCall func(rValue unsafe.Pointer, aValues ...unsafe.Pointer)) operatorStat {
return func(op *opendalOperator, path string) (*opendalMetadata, error) {
bytePath, err := unix.BytePtrFromString(path)
bytePath, err := BytePtrFromString(path)
if err != nil {
return nil, err
}
Expand All @@ -138,7 +137,7 @@ var withOperatorIsExists = withFFI(ffiOpts{
aTypes: []*ffi.Type{&ffi.TypePointer, &ffi.TypePointer},
}, func(ctx context.Context, ffiCall func(rValue unsafe.Pointer, aValues ...unsafe.Pointer)) operatorIsExist {
return func(op *opendalOperator, path string) (bool, error) {
bytePath, err := unix.BytePtrFromString(path)
bytePath, err := BytePtrFromString(path)
if err != nil {
return false, err
}
Expand Down
Loading
Loading