diff --git a/examples/dynamic_library_loading/use.v b/examples/dynamic_library_loading/use.v index 3d9f456fed..71a0099f75 100644 --- a/examples/dynamic_library_loading/use.v +++ b/examples/dynamic_library_loading/use.v @@ -7,10 +7,10 @@ type FNAdder = fn (int, int) int fn main() { 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)}') mut f := FNAdder(0) - f = dl.sym(handle, 'add_1') + f = dl.sym_opt(handle, 'add_1') ? eprintln('f: ${ptr_str(f)}') res := f(1, 2) eprintln('res: $res') diff --git a/vlib/dl/dl.v b/vlib/dl/dl.v index 9d9fd1ab8e..04ad16ba48 100644 --- a/vlib/dl/dl.v +++ b/vlib/dl/dl.v @@ -24,3 +24,25 @@ pub fn get_shared_library_extension() string { pub fn get_libname(libname string) string { 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 +} diff --git a/vlib/dl/dl_nix.c.v b/vlib/dl/dl_nix.c.v index 0c55940f1f..56f128dbbe 100644 --- a/vlib/dl/dl_nix.c.v +++ b/vlib/dl/dl_nix.c.v @@ -13,6 +13,8 @@ fn C.dlsym(handle voidptr, symbol charptr) voidptr fn C.dlclose(handle voidptr) int +fn C.dlerror() charptr + // open loads the dynamic shared object. pub fn open(filename string, flags int) voidptr { 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 { 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())) } +} diff --git a/vlib/dl/dl_windows.c.v b/vlib/dl/dl_windows.c.v index e057f186ae..b33a5970f1 100644 --- a/vlib/dl/dl_windows.c.v +++ b/vlib/dl/dl_windows.c.v @@ -26,3 +26,14 @@ pub fn close(handle voidptr) bool { pub fn sym(handle voidptr, symbol string) voidptr { 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' +}