aboutsummaryrefslogtreecommitdiff
path: root/v_windows/v/vlib/dl
diff options
context:
space:
mode:
Diffstat (limited to 'v_windows/v/vlib/dl')
-rw-r--r--v_windows/v/vlib/dl/dl.v48
-rw-r--r--v_windows/v/vlib/dl/dl_nix.c.v43
-rw-r--r--v_windows/v/vlib/dl/dl_test.v46
-rw-r--r--v_windows/v/vlib/dl/dl_windows.c.v39
4 files changed, 176 insertions, 0 deletions
diff --git a/v_windows/v/vlib/dl/dl.v b/v_windows/v/vlib/dl/dl.v
new file mode 100644
index 0000000..04ad16b
--- /dev/null
+++ b/v_windows/v/vlib/dl/dl.v
@@ -0,0 +1,48 @@
+module dl
+
+pub const (
+ version = 1
+ dl_ext = get_shared_library_extension()
+)
+
+// get_shared_library_extension returns the platform dependent shared library extension
+// i.e. .dll on windows, .so on most unixes, .dylib on macos.
+[inline]
+pub fn get_shared_library_extension() string {
+ return $if windows {
+ '.dll'
+ } $else $if macos {
+ '.dylib'
+ } $else {
+ '.so'
+ }
+}
+
+// get_libname returns a library name with the operating system specific extension for
+// shared libraries.
+[inline]
+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/v_windows/v/vlib/dl/dl_nix.c.v b/v_windows/v/vlib/dl/dl_nix.c.v
new file mode 100644
index 0000000..40f63b5
--- /dev/null
+++ b/v_windows/v/vlib/dl/dl_nix.c.v
@@ -0,0 +1,43 @@
+module dl
+
+#include <dlfcn.h>
+
+$if linux {
+ #flag -ldl
+}
+
+pub const (
+ rtld_now = C.RTLD_NOW
+ rtld_lazy = C.RTLD_LAZY
+)
+
+fn C.dlopen(filename &char, flags int) voidptr
+
+fn C.dlsym(handle voidptr, symbol &char) voidptr
+
+fn C.dlclose(handle voidptr) int
+
+fn C.dlerror() &char
+
+// open loads the dynamic shared object.
+pub fn open(filename string, flags int) voidptr {
+ return C.dlopen(&char(filename.str), flags)
+}
+
+// close frees a given shared object.
+pub fn close(handle voidptr) bool {
+ return C.dlclose(handle) == 0
+}
+
+// sym returns an address of a symbol in a given shared object.
+pub fn sym(handle voidptr, symbol string) voidptr {
+ return C.dlsym(handle, &char(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(C.dlerror()) }
+}
diff --git a/v_windows/v/vlib/dl/dl_test.v b/v_windows/v/vlib/dl/dl_test.v
new file mode 100644
index 0000000..c4f0824
--- /dev/null
+++ b/v_windows/v/vlib/dl/dl_test.v
@@ -0,0 +1,46 @@
+import dl
+
+fn test_dl() {
+ $if linux {
+ run_test_invalid_lib_linux()
+ return
+ }
+ $if windows {
+ run_test_invalid_lib_windows()
+ run_test_valid_lib_windows()
+ run_test_invalid_sym_windows()
+ run_test_valid_sym_windows()
+ return
+ } $else {
+ eprint('currently not implemented on this platform')
+ }
+}
+
+fn run_test_invalid_lib_linux() {
+ // ensure a not-existing dl won't be loaded
+ h := dl.open('not-existing-dynamic-link-library', dl.rtld_now)
+ assert h == 0
+}
+
+fn run_test_invalid_lib_windows() {
+ // ensure a not-existing dl won't be loaded
+ h := dl.open('not-existing-dynamic-link-library', dl.rtld_now)
+ assert h == 0
+}
+
+fn run_test_valid_lib_windows() {
+ h := dl.open('shell32', dl.rtld_now)
+ assert h != 0
+}
+
+fn run_test_invalid_sym_windows() {
+ h := dl.open('shell32', dl.rtld_now)
+ proc := dl.sym(h, 'CommandLineToArgvW2')
+ assert proc == 0
+}
+
+fn run_test_valid_sym_windows() {
+ h := dl.open('shell32', dl.rtld_now)
+ proc := dl.sym(h, 'CommandLineToArgvW')
+ assert proc != 0
+}
diff --git a/v_windows/v/vlib/dl/dl_windows.c.v b/v_windows/v/vlib/dl/dl_windows.c.v
new file mode 100644
index 0000000..b6ae2fc
--- /dev/null
+++ b/v_windows/v/vlib/dl/dl_windows.c.v
@@ -0,0 +1,39 @@
+module dl
+
+pub const (
+ rtld_now = 0
+ rtld_lazy = 0
+)
+
+fn C.LoadLibrary(libfilename &u16) voidptr
+
+fn C.GetProcAddress(handle voidptr, procname &byte) voidptr
+
+fn C.FreeLibrary(handle voidptr) bool
+
+// open loads a given module into the address space of the calling process.
+pub fn open(filename string, flags int) voidptr {
+ res := C.LoadLibrary(filename.to_wide())
+ return res
+}
+
+// close frees the loaded a given module.
+pub fn close(handle voidptr) bool {
+ return C.FreeLibrary(handle)
+}
+
+// sym returns an address of an exported function or variable from a given module.
+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'
+}