summary refs log tree commit diff stats
path: root/lib/system/dyncalls.nim
blob: 88870a209e0bd8f9474d05c63934f68ce6309290 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#
#
#            Nimrod's Runtime Library
#        (c) Copyright 2010 Andreas Rumpf
#
#    See the file "copying.txt", included in this
#    distribution, for details about the copyright.
#

# This file implements the ability to call native procs from libraries.
# It is not possible to do this in a platform independant way, unfortunately.
# However, the interface has been designed to take platform differences into
# account and been ported to all major platforms.

const
  NilLibHandle: TLibHandle = nil

proc rawWrite(f: TFile, 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.write("could not load: ")
  #quit(path)
  stdout.rawWrite("could not load: ")
  stdout.rawWrite(path)
  stdout.rawWrite("\n")
  quit(1)

proc ProcAddrError(name: cstring) {.noinline.} =
  # carefully written to avoid memory allocation:
  stdout.rawWrite("could not import: ")
  stdout.write(name)
  stdout.rawWrite("\n")
  quit(1)

# this code was inspired from Lua's source code:
# Lua - An Extensible Extension Language
# Tecgraf: Computer Graphics Technology Group, PUC-Rio, Brazil
# http://www.lua.org
# mailto:info@lua.org

when defined(posix):
  #
  # =========================================================================
  # This is an implementation based on the dlfcn interface.
  # The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD,
  # NetBSD, AIX 4.2, HPUX 11, and probably most other Unix flavors, at least
  # as an emulation layer on top of native functions.
  # =========================================================================
  #

  # c stuff:
  var
    RTLD_NOW {.importc: "RTLD_NOW", header: "<dlfcn.h>".}: int

  proc dlclose(lib: TLibHandle) {.importc, header: "<dlfcn.h>".}
  proc dlopen(path: CString, mode: int): TLibHandle {.
      importc, header: "<dlfcn.h>".}
  proc dlsym(lib: TLibHandle, name: cstring): TProcAddr {.
      importc, header: "<dlfcn.h>".}

  proc dlerror(): cstring {.importc, header: "<dlfcn.h>".}

  proc nimUnloadLibrary(lib: TLibHandle) =
    dlclose(lib)

  proc nimLoadLibrary(path: string): TLibHandle =
    result = dlopen(path, RTLD_NOW)
    #c_fprintf(c_stdout, "%s\n", dlerror())

  proc nimGetProcAddr(lib: TLibHandle, name: cstring): TProcAddr =
    result = dlsym(lib, name)
    if result == nil: ProcAddrError(name)

elif defined(windows) or defined(dos):
  #
  # =======================================================================
  # Native Windows Implementation
  # =======================================================================
  #
  type
    THINSTANCE {.importc: "HINSTANCE".} = pointer

  proc FreeLibrary(lib: THINSTANCE) {.importc, header: "<windows.h>", stdcall.}
  proc winLoadLibrary(path: cstring): THINSTANCE {.
      importc: "LoadLibraryA", header: "<windows.h>", stdcall.}
  proc GetProcAddress(lib: THINSTANCE, name: cstring): TProcAddr {.
      importc: "GetProcAddress", header: "<windows.h>", stdcall.}

  proc nimUnloadLibrary(lib: TLibHandle) =
    FreeLibrary(cast[THINSTANCE](lib))

  proc nimLoadLibrary(path: string): TLibHandle =
    result = cast[TLibHandle](winLoadLibrary(path))

  proc nimGetProcAddr(lib: TLibHandle, name: cstring): TProcAddr =
    result = GetProcAddress(cast[THINSTANCE](lib), name)
    if result == nil: ProcAddrError(name)

elif defined(mac):
  #
  # =======================================================================
  # Native Mac OS X / Darwin Implementation
  # =======================================================================
  #
  {.error: "no implementation for dyncalls yet".}

  proc nimUnloadLibrary(lib: TLibHandle) =
    NSUnLinkModule(NSModule(lib), NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES)

  var
    dyld_present {.importc: "_dyld_present", header: "<dyld.h>".}: int

  proc nimLoadLibrary(path: string): TLibHandle =
    var
      img: NSObjectFileImage
      ret: NSObjectFileImageReturnCode
      modul: NSModule
    # this would be a rare case, but prevents crashing if it happens
    result = nil
    if dyld_present != 0:
      ret = NSCreateObjectFileImageFromFile(path, addr(img))
      if ret == NSObjectFileImageSuccess:
        modul = NSLinkModule(img, path, NSLINKMODULE_OPTION_PRIVATE or
                                        NSLINKMODULE_OPTION_RETURN_ON_ERROR)
        NSDestroyObjectFileImage(img)
        result = TLibHandle(modul)

  proc nimGetProcAddr(lib: TLibHandle, name: cstring): TProcAddr =
    var
      nss: NSSymbol
    nss = NSLookupSymbolInModule(NSModule(lib), name)
    result = TProcAddr(NSAddressOfSymbol(nss))
    if result == nil: ProcAddrError(name)

else:
  {.error: "no implementation for dyncalls".}