diff options
Diffstat (limited to 'lib/system/dyncalls.nim')
-rw-r--r-- | lib/system/dyncalls.nim | 126 |
1 files changed, 103 insertions, 23 deletions
diff --git a/lib/system/dyncalls.nim b/lib/system/dyncalls.nim index 22ac613f8..2162b234f 100644 --- a/lib/system/dyncalls.nim +++ b/lib/system/dyncalls.nim @@ -17,23 +17,44 @@ const NilLibHandle: LibHandle = nil -proc rawWrite(f: File, s: string) = - # we cannot throw an exception here! - discard writeBuffer(f, cstring(s), s.len) - proc nimLoadLibraryError(path: string) = # carefully written to avoid memory allocation: - stdout.rawWrite("could not load: ") - stdout.rawWrite(path) - stdout.rawWrite("\n") - quit(1) - -proc procAddrError(name: cstring) {.noinline.} = + const prefix = "could not load: " + cstderr.rawWrite(prefix) + cstderr.rawWrite(path) + when not defined(nimDebugDlOpen) and not defined(windows): + cstderr.rawWrite("\n(compile with -d:nimDebugDlOpen for more information)") + when defined(windows): + const badExe = "\n(bad format; library may be wrong architecture)" + let loadError = GetLastError() + if loadError == ERROR_BAD_EXE_FORMAT: + cstderr.rawWrite(badExe) + when defined(guiapp): + # Because console output is not shown in GUI apps, display the error as a + # message box instead: + var + msg: array[1000, char] + msgLeft = msg.len - 1 # leave (at least) one for nullchar + msgIdx = 0 + copyMem(msg[msgIdx].addr, prefix.cstring, prefix.len) + msgLeft -= prefix.len + msgIdx += prefix.len + let pathLen = min(path.len, msgLeft) + copyMem(msg[msgIdx].addr, path.cstring, pathLen) + msgLeft -= pathLen + msgIdx += pathLen + if loadError == ERROR_BAD_EXE_FORMAT and msgLeft >= badExe.len: + copyMem(msg[msgIdx].addr, badExe.cstring, badExe.len) + discard MessageBoxA(nil, msg[0].addr, nil, 0) + cstderr.rawWrite("\n") + rawQuit(1) + +proc procAddrError(name: cstring) {.compilerproc, nonReloadable, hcrInline.} = # carefully written to avoid memory allocation: - stdout.rawWrite("could not import: ") - stdout.write(name) - stdout.rawWrite("\n") - quit(1) + cstderr.rawWrite("could not import: ") + cstderr.rawWrite(name) + cstderr.rawWrite("\n") + rawQuit(1) # this code was inspired from Lua's source code: # Lua - An Extensible Extension Language @@ -52,11 +73,14 @@ when defined(posix): # # c stuff: - var - RTLD_NOW {.importc: "RTLD_NOW", header: "<dlfcn.h>".}: int + when defined(linux) or defined(macosx): + const RTLD_NOW = cint(2) + else: + var + RTLD_NOW {.importc: "RTLD_NOW", header: "<dlfcn.h>".}: cint proc dlclose(lib: LibHandle) {.importc, header: "<dlfcn.h>".} - proc dlopen(path: cstring, mode: int): LibHandle {. + proc dlopen(path: cstring, mode: cint): LibHandle {. importc, header: "<dlfcn.h>".} proc dlsym(lib: LibHandle, name: cstring): ProcAddr {. importc, header: "<dlfcn.h>".} @@ -67,10 +91,15 @@ when defined(posix): dlclose(lib) proc nimLoadLibrary(path: string): LibHandle = - result = dlopen(path, RTLD_NOW) - let error = dlerror() - if error != nil: - c_fprintf(c_stdout, "%s\n", error) + let flags = + when defined(globalSymbols): RTLD_NOW or RTLD_GLOBAL + else: RTLD_NOW + result = dlopen(path, flags) + when defined(nimDebugDlOpen): + let error = dlerror() + if error != nil: + cstderr.rawWrite(error) + cstderr.rawWrite("\n") proc nimGetProcAddr(lib: LibHandle, name: cstring): ProcAddr = result = dlsym(lib, name) @@ -108,12 +137,63 @@ elif defined(windows) or defined(dos): proc nimGetProcAddr(lib: LibHandle, name: cstring): ProcAddr = result = getProcAddress(cast[THINSTANCE](lib), name) if result != nil: return + const decoratedLength = 250 + var decorated: array[decoratedLength, char] + decorated[0] = '_' + var m = 1 + while m < (decoratedLength - 5): + if name[m - 1] == '\x00': break + decorated[m] = name[m - 1] + inc(m) + decorated[m] = '@' for i in countup(0, 50): - var decorated = "_" & $name & "@" & $(i * 4) - result = getProcAddress(cast[THINSTANCE](lib), cstring(decorated)) + var k = i * 4 + if k div 100 == 0: + if k div 10 == 0: + m = m + 1 + else: + m = m + 2 + else: + m = m + 3 + decorated[m + 1] = '\x00' + while true: + decorated[m] = chr(ord('0') + (k %% 10)) + dec(m) + k = k div 10 + if k == 0: break + result = getProcAddress(cast[THINSTANCE](lib), cast[cstring](addr decorated)) if result != nil: return procAddrError(name) +elif defined(genode): + + proc nimUnloadLibrary(lib: LibHandle) = + raiseAssert("nimUnloadLibrary not implemented") + + proc nimLoadLibrary(path: string): LibHandle = + raiseAssert("nimLoadLibrary not implemented") + + proc nimGetProcAddr(lib: LibHandle, name: cstring): ProcAddr = + raiseAssert("nimGetProcAddr not implemented") + +elif defined(nintendoswitch) or defined(freertos) or defined(zephyr) or defined(nuttx): + proc nimUnloadLibrary(lib: LibHandle) = + cstderr.rawWrite("nimUnLoadLibrary not implemented") + cstderr.rawWrite("\n") + rawQuit(1) + + proc nimLoadLibrary(path: string): LibHandle = + cstderr.rawWrite("nimLoadLibrary not implemented") + cstderr.rawWrite("\n") + rawQuit(1) + + + proc nimGetProcAddr(lib: LibHandle, name: cstring): ProcAddr = + cstderr.rawWrite("nimGetProAddr not implemented") + cstderr.rawWrite(name) + cstderr.rawWrite("\n") + rawQuit(1) + else: {.error: "no implementation for dyncalls".} |