dyncalls.nim 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. #
  2. #
  3. # Nim's Runtime Library
  4. # (c) Copyright 2012 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. # This file implements the ability to call native procs from libraries.
  10. # It is not possible to do this in a platform independent way, unfortunately.
  11. # However, the interface has been designed to take platform differences into
  12. # account and been ported to all major platforms.
  13. {.push stack_trace: off.}
  14. const
  15. NilLibHandle: LibHandle = nil
  16. proc nimLoadLibraryError(path: string) =
  17. # carefully written to avoid memory allocation:
  18. stderr.rawWrite("could not load: ")
  19. stderr.rawWrite(path)
  20. stderr.rawWrite("\n")
  21. when not defined(nimDebugDlOpen) and not defined(windows):
  22. stderr.rawWrite("compile with -d:nimDebugDlOpen for more information\n")
  23. when defined(windows) and defined(guiapp):
  24. # Because console output is not shown in GUI apps, display error as message box:
  25. const prefix = "could not load: "
  26. var msg: array[1000, char]
  27. copyMem(msg[0].addr, prefix.cstring, prefix.len)
  28. copyMem(msg[prefix.len].addr, path.cstring, min(path.len + 1, 1000 - prefix.len))
  29. discard MessageBoxA(0, msg[0].addr, nil, 0)
  30. quit(1)
  31. proc procAddrError(name: cstring) {.noinline.} =
  32. # carefully written to avoid memory allocation:
  33. stderr.rawWrite("could not import: ")
  34. stderr.rawWrite(name)
  35. stderr.rawWrite("\n")
  36. quit(1)
  37. # this code was inspired from Lua's source code:
  38. # Lua - An Extensible Extension Language
  39. # Tecgraf: Computer Graphics Technology Group, PUC-Rio, Brazil
  40. # http://www.lua.org
  41. # mailto:info@lua.org
  42. when defined(posix):
  43. #
  44. # =========================================================================
  45. # This is an implementation based on the dlfcn interface.
  46. # The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD,
  47. # NetBSD, AIX 4.2, HPUX 11, and probably most other Unix flavors, at least
  48. # as an emulation layer on top of native functions.
  49. # =========================================================================
  50. #
  51. # c stuff:
  52. when defined(linux) or defined(macosx):
  53. const RTLD_NOW = cint(2)
  54. else:
  55. var
  56. RTLD_NOW {.importc: "RTLD_NOW", header: "<dlfcn.h>".}: cint
  57. proc dlclose(lib: LibHandle) {.importc, header: "<dlfcn.h>".}
  58. proc dlopen(path: cstring, mode: cint): LibHandle {.
  59. importc, header: "<dlfcn.h>".}
  60. proc dlsym(lib: LibHandle, name: cstring): ProcAddr {.
  61. importc, header: "<dlfcn.h>".}
  62. proc dlerror(): cstring {.importc, header: "<dlfcn.h>".}
  63. proc nimUnloadLibrary(lib: LibHandle) =
  64. dlclose(lib)
  65. proc nimLoadLibrary(path: string): LibHandle =
  66. result = dlopen(path, RTLD_NOW)
  67. when defined(nimDebugDlOpen):
  68. let error = dlerror()
  69. if error != nil:
  70. stderr.rawWrite(error)
  71. stderr.rawWrite("\n")
  72. proc nimGetProcAddr(lib: LibHandle, name: cstring): ProcAddr =
  73. result = dlsym(lib, name)
  74. if result == nil: procAddrError(name)
  75. elif defined(windows) or defined(dos):
  76. #
  77. # =======================================================================
  78. # Native Windows Implementation
  79. # =======================================================================
  80. #
  81. when defined(cpp):
  82. type
  83. THINSTANCE {.importc: "HINSTANCE".} = object
  84. x: pointer
  85. proc getProcAddress(lib: THINSTANCE, name: cstring): ProcAddr {.
  86. importcpp: "(void*)GetProcAddress(@)", header: "<windows.h>", stdcall.}
  87. else:
  88. type
  89. THINSTANCE {.importc: "HINSTANCE".} = pointer
  90. proc getProcAddress(lib: THINSTANCE, name: cstring): ProcAddr {.
  91. importc: "GetProcAddress", header: "<windows.h>", stdcall.}
  92. proc freeLibrary(lib: THINSTANCE) {.
  93. importc: "FreeLibrary", header: "<windows.h>", stdcall.}
  94. proc winLoadLibrary(path: cstring): THINSTANCE {.
  95. importc: "LoadLibraryA", header: "<windows.h>", stdcall.}
  96. proc nimUnloadLibrary(lib: LibHandle) =
  97. freeLibrary(cast[THINSTANCE](lib))
  98. proc nimLoadLibrary(path: string): LibHandle =
  99. result = cast[LibHandle](winLoadLibrary(path))
  100. proc nimGetProcAddr(lib: LibHandle, name: cstring): ProcAddr =
  101. result = getProcAddress(cast[THINSTANCE](lib), name)
  102. if result != nil: return
  103. const decorated_length = 250
  104. var decorated: array[decorated_length, char]
  105. decorated[0] = '_'
  106. var m = 1
  107. while m < (decorated_length - 5):
  108. if name[m - 1] == '\x00': break
  109. decorated[m] = name[m - 1]
  110. inc(m)
  111. decorated[m] = '@'
  112. for i in countup(0, 50):
  113. var k = i * 4
  114. if k div 100 == 0:
  115. if k div 10 == 0:
  116. m = m + 1
  117. else:
  118. m = m + 2
  119. else:
  120. m = m + 3
  121. decorated[m + 1] = '\x00'
  122. while true:
  123. decorated[m] = chr(ord('0') + (k %% 10))
  124. dec(m)
  125. k = k div 10
  126. if k == 0: break
  127. when defined(nimNoArrayToCstringConversion):
  128. result = getProcAddress(cast[THINSTANCE](lib), addr decorated)
  129. else:
  130. result = getProcAddress(cast[THINSTANCE](lib), decorated)
  131. if result != nil: return
  132. procAddrError(name)
  133. elif defined(genode):
  134. proc nimUnloadLibrary(lib: LibHandle) {.
  135. error: "nimUnloadLibrary not implemented".}
  136. proc nimLoadLibrary(path: string): LibHandle {.
  137. error: "nimLoadLibrary not implemented".}
  138. proc nimGetProcAddr(lib: LibHandle, name: cstring): ProcAddr {.
  139. error: "nimGetProcAddr not implemented".}
  140. elif defined(nintendoswitch):
  141. proc nimUnloadLibrary(lib: LibHandle) =
  142. stderr.rawWrite("nimUnLoadLibrary not implemented")
  143. stderr.rawWrite("\n")
  144. quit(1)
  145. proc nimLoadLibrary(path: string): LibHandle =
  146. stderr.rawWrite("nimLoadLibrary not implemented")
  147. stderr.rawWrite("\n")
  148. quit(1)
  149. proc nimGetProcAddr(lib: LibHandle, name: cstring): ProcAddr =
  150. stderr.rawWrite("nimGetProAddr not implemented")
  151. stderr.rawWrite(name)
  152. stderr.rawWrite("\n")
  153. quit(1)
  154. else:
  155. {.error: "no implementation for dyncalls".}
  156. {.pop.}