This is an automated email from the ASF dual-hosted git repository. yuchanns pushed a commit to branch go-binding-windows in repository https://gitbox.apache.org/repos/asf/opendal.git
commit a2e1bc3c83c2fd712bfc6ea335a1eaa27fc64b85 Author: Hanchin Hsieh <[email protected]> AuthorDate: Wed Apr 9 13:30:56 2025 +0800 feat(bindings/go): support windows platform Hanchin Hsieh <[email protected]> --- bindings/go/delete.go | 3 +- bindings/go/ffi.go | 7 ++--- bindings/go/go.mod | 4 +-- bindings/go/go.sum | 4 +++ bindings/go/lister.go | 7 ++--- bindings/go/operator.go | 15 +++++----- bindings/go/operator_info.go | 7 ++--- bindings/go/reader.go | 5 ++-- bindings/go/stat.go | 5 ++-- bindings/go/util_unix.go | 67 ++++++++++++++++++++++++++++++++++++++++++ bindings/go/util_windows.go | 70 ++++++++++++++++++++++++++++++++++++++++++++ bindings/go/write.go | 7 ++--- 12 files changed, 167 insertions(+), 34 deletions(-) diff --git a/bindings/go/delete.go b/bindings/go/delete.go index f92df487a..1a8b64317 100644 --- a/bindings/go/delete.go +++ b/bindings/go/delete.go @@ -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. @@ -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 } diff --git a/bindings/go/ffi.go b/bindings/go/ffi.go index 931c345f2..3a39f0b20 100644 --- a/bindings/go/ffi.go +++ b/bindings/go/ffi.go @@ -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 } @@ -41,7 +40,7 @@ func contextWithFFIs(path string) (ctx context.Context, cancel context.CancelFun } } cancel = func() { - purego.Dlclose(libopendal) + FreeLibrary(libopendal) } return } @@ -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 } diff --git a/bindings/go/go.mod b/bindings/go/go.mod index ac1f39f5c..17bc50945 100644 --- a/bindings/go/go.mod +++ b/bindings/go/go.mod @@ -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 ) diff --git a/bindings/go/go.sum b/bindings/go/go.sum index b08aa464c..ac2837037 100644 --- a/bindings/go/go.sum +++ b/bindings/go/go.sum @@ -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= diff --git a/bindings/go/lister.go b/bindings/go/lister.go index bbd58f1f1..a328f3d05 100644 --- a/bindings/go/lister.go +++ b/bindings/go/lister.go @@ -24,7 +24,6 @@ import ( "unsafe" "github.com/jupiterrider/ffi" - "golang.org/x/sys/unix" ) // Check verifies if the operator is functioning correctly. @@ -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 } @@ -400,7 +399,7 @@ var withEntryName = withFFI(ffiOpts{ unsafe.Pointer(&bytePtr), unsafe.Pointer(&e), ) - return unix.BytePtrToString(bytePtr) + return BytePtrToString(bytePtr) } }) @@ -419,6 +418,6 @@ var withEntryPath = withFFI(ffiOpts{ unsafe.Pointer(&bytePtr), unsafe.Pointer(&e), ) - return unix.BytePtrToString(bytePtr) + return BytePtrToString(bytePtr) } }) diff --git a/bindings/go/operator.go b/bindings/go/operator.go index d63bacda6..304b05d06 100644 --- a/bindings/go/operator.go +++ b/bindings/go/operator.go @@ -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. @@ -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 } @@ -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 } @@ -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 } @@ -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 } diff --git a/bindings/go/operator_info.go b/bindings/go/operator_info.go index 6ea7f15fc..9fffe909c 100644 --- a/bindings/go/operator_info.go +++ b/bindings/go/operator_info.go @@ -24,7 +24,6 @@ import ( "unsafe" "github.com/jupiterrider/ffi" - "golang.org/x/sys/unix" ) // Info returns metadata about the Operator. @@ -325,7 +324,7 @@ var withOperatorInfoGetScheme = withFFI(ffiOpts{ unsafe.Pointer(&bytePtr), unsafe.Pointer(&info), ) - return unix.BytePtrToString(bytePtr) + return BytePtrToString(bytePtr) } }) @@ -344,7 +343,7 @@ var withOperatorInfoGetRoot = withFFI(ffiOpts{ unsafe.Pointer(&bytePtr), unsafe.Pointer(&info), ) - return unix.BytePtrToString(bytePtr) + return BytePtrToString(bytePtr) } }) @@ -363,6 +362,6 @@ var withOperatorInfoGetName = withFFI(ffiOpts{ unsafe.Pointer(&bytePtr), unsafe.Pointer(&info), ) - return unix.BytePtrToString(bytePtr) + return BytePtrToString(bytePtr) } }) diff --git a/bindings/go/reader.go b/bindings/go/reader.go index ce26ce663..52810ddeb 100644 --- a/bindings/go/reader.go +++ b/bindings/go/reader.go @@ -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. @@ -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 } @@ -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 } diff --git a/bindings/go/stat.go b/bindings/go/stat.go index 7eb734593..feb37d860 100644 --- a/bindings/go/stat.go +++ b/bindings/go/stat.go @@ -24,7 +24,6 @@ import ( "unsafe" "github.com/jupiterrider/ffi" - "golang.org/x/sys/unix" ) // Stat retrieves metadata for the specified path. @@ -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 } @@ -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 } diff --git a/bindings/go/util_unix.go b/bindings/go/util_unix.go new file mode 100644 index 000000000..fb6e45f25 --- /dev/null +++ b/bindings/go/util_unix.go @@ -0,0 +1,67 @@ +//go:build !windows + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package opendal + +import ( + "github.com/ebitengine/purego" + "golang.org/x/sys/unix" +) + +func BytePtrFromString(s string) (*byte, error) { + if s == "" { + return nil, nil + } + return unix.BytePtrFromString(s) +} + +func BytePtrToString(p *byte) string { + if p == nil { + return "" + } + return unix.BytePtrToString(p) +} + +func LoadLibrary(path string) (uintptr, error) { + return purego.Dlopen(path, purego.RTLD_LAZY|purego.RTLD_GLOBAL) +} + +func FreeLibrary(handle uintptr) error { + if handle == 0 { + return nil + } + err := purego.Dlclose(handle) + if err != nil { + return err + } + return nil +} + +func GetProcAddress(handle uintptr, name string) (uintptr, error) { + if handle == 0 { + return 0, nil + } + addr, err := purego.Dlsym(handle, name) + if err != nil { + return 0, err + } + return addr, nil +} diff --git a/bindings/go/util_windows.go b/bindings/go/util_windows.go new file mode 100644 index 000000000..1ead26988 --- /dev/null +++ b/bindings/go/util_windows.go @@ -0,0 +1,70 @@ +//go:build windows + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package opendal + +import ( + "golang.org/x/sys/windows" +) + +func BytePtrFromString(s string) (*byte, error) { + if s == "" { + return nil, nil + } + return windows.BytePtrFromString(s) +} + +func BytePtrToString(p *byte) string { + if p == nil { + return "" + } + return windows.BytePtrToString(p) +} + +func LoadLibrary(path string) (uintptr, error) { + handle, err := windows.LoadLibrary(path) + if err != nil { + return 0, err + } + return uintptr(handle), nil +} + +func FreeLibrary(handle uintptr) error { + if handle == 0 { + return nil + } + err := windows.FreeLibrary(windows.Handle(handle)) + if err != nil { + return err + } + return nil +} + +func GetProcAddress(handle uintptr, name string) (uintptr, error) { + if handle == 0 { + return 0, nil + } + proc, err := windows.GetProcAddress(windows.Handle(handle), name) + if err != nil { + return 0, err + } + return proc, nil +} diff --git a/bindings/go/write.go b/bindings/go/write.go index f0c23b816..a426c9eae 100644 --- a/bindings/go/write.go +++ b/bindings/go/write.go @@ -25,7 +25,6 @@ import ( "unsafe" "github.com/jupiterrider/ffi" - "golang.org/x/sys/unix" ) // Write writes the given bytes to the specified path. @@ -199,7 +198,7 @@ var withOperatorWrite = withFFI(ffiOpts{ aTypes: []*ffi.Type{&ffi.TypePointer, &ffi.TypePointer, &ffi.TypePointer}, }, func(ctx context.Context, ffiCall func(rValue unsafe.Pointer, aValues ...unsafe.Pointer)) operatorWrite { return func(op *opendalOperator, path string, data []byte) error { - bytePath, err := unix.BytePtrFromString(path) + bytePath, err := BytePtrFromString(path) if err != nil { return err } @@ -225,7 +224,7 @@ var withOperatorCreateDir = withFFI(ffiOpts{ aTypes: []*ffi.Type{&ffi.TypePointer, &ffi.TypePointer}, }, func(ctx context.Context, ffiCall func(rValue unsafe.Pointer, aValues ...unsafe.Pointer)) operatorCreateDir { return func(op *opendalOperator, path string) error { - bytePath, err := unix.BytePtrFromString(path) + bytePath, err := BytePtrFromString(path) if err != nil { return err } @@ -249,7 +248,7 @@ var withOperatorWriter = withFFI(ffiOpts{ aTypes: []*ffi.Type{&ffi.TypePointer, &ffi.TypePointer}, }, func(ctx context.Context, ffiCall func(rValue unsafe.Pointer, aValues ...unsafe.Pointer)) operatorWriter { return func(op *opendalOperator, path string) (*opendalWriter, error) { - bytePath, err := unix.BytePtrFromString(path) + bytePath, err := BytePtrFromString(path) if err != nil { return nil, err }
