dyncalls.nim 6.1 KB

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