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  }