github.com/notti/go-dynamic@v0.0.0-20190619201224-fc443047424c/dlopen.go (about) 1 package nocgo 2 3 import ( 4 "errors" 5 "reflect" 6 "unsafe" 7 8 "github.com/notti/nocgo/internal/dlopen" 9 "github.com/notti/nocgo/internal/ffi" 10 ) 11 12 func getLastError() error { 13 err := dlopen.DLError() 14 if err == 0 { 15 return errors.New("Unknown dl error") 16 } 17 return errors.New(MakeGoStringFromPointer(err)) 18 } 19 20 // Library holds the handle to a loaded library 21 type Library uintptr 22 23 // Open opens the given dynamic library and returns a handle for loading symbols and functions. 24 func Open(library string) (Library, error) { 25 handle := dlopen.DLOpen(MakeCString(library), 2 /* RTLD_NOW */) 26 if handle != 0 { 27 return Library(handle), nil 28 } 29 return 0, getLastError() 30 } 31 32 // Close closes the library. This might also release all resources. Any Func and Value calls on the Library after this point can give unexpected results. 33 func (l Library) Close() error { 34 ret := dlopen.DLClose(uintptr(l)) 35 if ret == 0 { 36 return nil 37 } 38 return getLastError() 39 } 40 41 // Func returns a callable spec for the given symbol name and argument specification. 42 // 43 // WARNING! This does not and cannot check if the size of the given type is correct! 44 // 45 // Example: 46 // var puts func(s []byte) int32 47 // if err := lib.Func("puts", &puts); err != nil { 48 // //handle error; err will contain an error message from dlerror, or if something went wrong with building the spec 49 // } 50 // num := puts(nocgo.MakeCString("hello world!\n")) 51 // fmt.Printf("Successfully printed %d characters from C!\n", num) 52 // 53 // See package documentation for an explanation of C-types 54 func (l Library) Func(name string, fun interface{}) error { 55 addr := dlopen.DLSym(uintptr(l), MakeCString(name)) 56 if addr == 0 { 57 return getLastError() 58 } 59 return ffi.MakeSpec(addr, fun) 60 } 61 62 // Value sets the given value (which must be pointer to pointer to the correct type) to the global symbol given by name. 63 // 64 // WARNING! This does not and cannot check if the size of the given type is correct! This might be possibly dangerous. 65 // See above for an explanation of C-types. 66 // 67 // Example: 68 // var value *int32 69 // if err := lib.Value("some_value", &value); err != nil { 70 // //handle error; error will contain an error message from dlerror 71 // } 72 // 73 // // *value now is the contents of the global symbol in the library 74 // fmt.Printf(*value) 75 func (l Library) Value(name string, value interface{}) error { 76 v := reflect.ValueOf(value) 77 if v.Kind() != reflect.Ptr { 78 return errors.New("value must be a pointer to a pointer") 79 } 80 v = v.Elem() 81 if v.Kind() != reflect.Ptr { 82 return errors.New("value must be pointer to a pointer") 83 } 84 85 addr := dlopen.DLSym(uintptr(l), MakeCString(name)) 86 if addr == 0 { 87 return getLastError() 88 } 89 90 *(*uintptr)(unsafe.Pointer(v.UnsafeAddr())) = addr 91 92 return nil 93 }