dl: add dl.open_opt/2, dl.sym_opt/2 and dl.dlerror/0 utility functions

pull/9451/head
Delyan Angelov 2021-03-24 11:47:04 +02:00
parent 0bde55f77e
commit 9e48826bcb
No known key found for this signature in database
GPG Key ID: 66886C0F12D595ED
4 changed files with 45 additions and 2 deletions

View File

@ -7,10 +7,10 @@ type FNAdder = fn (int, int) int
fn main() { fn main() {
library_file_path := os.join_path(os.getwd(), dl.get_libname('library')) library_file_path := os.join_path(os.getwd(), dl.get_libname('library'))
handle := dl.open(library_file_path, dl.rtld_lazy) handle := dl.open_opt(library_file_path, dl.rtld_lazy) ?
eprintln('handle: ${ptr_str(handle)}') eprintln('handle: ${ptr_str(handle)}')
mut f := FNAdder(0) mut f := FNAdder(0)
f = dl.sym(handle, 'add_1') f = dl.sym_opt(handle, 'add_1') ?
eprintln('f: ${ptr_str(f)}') eprintln('f: ${ptr_str(f)}')
res := f(1, 2) res := f(1, 2)
eprintln('res: $res') eprintln('res: $res')

View File

@ -24,3 +24,25 @@ pub fn get_shared_library_extension() string {
pub fn get_libname(libname string) string { pub fn get_libname(libname string) string {
return '$libname$dl.dl_ext' return '$libname$dl.dl_ext'
} }
// open_opt - loads the dynamic shared object.
// Unlike open, open_opt return an option.
pub fn open_opt(filename string, flags int) ?voidptr {
shared_object_handle := open(filename, flags)
if shared_object_handle == 0 {
e := dlerror()
return error(e)
}
return shared_object_handle
}
// sym_opt returns the address of a symbol in a given shared object, if found.
// Unlike sym, sym_opt returns an option.
pub fn sym_opt(shared_object_handle voidptr, symbol string) ?voidptr {
sym_handle := sym(shared_object_handle, symbol)
if sym_handle == 0 {
e := dlerror()
return error(e)
}
return sym_handle
}

View File

@ -13,6 +13,8 @@ fn C.dlsym(handle voidptr, symbol charptr) voidptr
fn C.dlclose(handle voidptr) int fn C.dlclose(handle voidptr) int
fn C.dlerror() charptr
// open loads the dynamic shared object. // open loads the dynamic shared object.
pub fn open(filename string, flags int) voidptr { pub fn open(filename string, flags int) voidptr {
return C.dlopen(charptr(filename.str), flags) return C.dlopen(charptr(filename.str), flags)
@ -27,3 +29,11 @@ pub fn close(handle voidptr) bool {
pub fn sym(handle voidptr, symbol string) voidptr { pub fn sym(handle voidptr, symbol string) voidptr {
return C.dlsym(handle, charptr(symbol.str)) return C.dlsym(handle, charptr(symbol.str))
} }
// dlerror provides a text error diagnostic message for functions in `dl`
// it returns a human-readable string, describing the most recent error
// that occurred from a call to one of the `dl` functions, since the last
// call to dlerror()
pub fn dlerror() string {
return unsafe { cstring_to_vstring(byteptr(C.dlerror())) }
}

View File

@ -26,3 +26,14 @@ pub fn close(handle voidptr) bool {
pub fn sym(handle voidptr, symbol string) voidptr { pub fn sym(handle voidptr, symbol string) voidptr {
return C.GetProcAddress(handle, symbol.str) return C.GetProcAddress(handle, symbol.str)
} }
// dlerror provides a text error diagnostic message for functions in `dl`
// it returns a human-readable string, describing the most recent error
// that occurred from a call to one of the `dl` functions, since the last
// call to dlerror()
pub fn dlerror() string {
// https://docs.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-getlasterror
// Unlike dlerror(), GetLastError returns just an error code, that is function specific.
cerr := int(C.GetLastError())
return 'error code $cerr'
}