1 module llvm.functions.load; 2 3 version (LLVM_Load): 4 5 import std.traits; 6 import std.meta; 7 8 import link = llvm.functions.link; 9 10 private: 11 12 version(Posix) 13 { 14 import core.sys.posix.dlfcn; 15 16 alias SharedLibHandle = void*; 17 18 version(OSX) 19 { 20 enum libPrefix = "lib"; 21 enum libSuffix = "dylib"; 22 } 23 else 24 { 25 enum libPrefix = "lib"; 26 enum libSuffix = "so"; 27 } 28 29 pragma(lib, "dl"); 30 } 31 else version(Windows) 32 { 33 import core.sys.windows.windows; 34 import std.path : dirName; 35 36 alias SharedLibHandle = HMODULE; 37 38 enum libPrefix = ""; 39 enum libSuffix = "dll"; 40 } else { 41 static assert(0, "Unsupported operating system"); 42 } 43 44 struct SharedLib 45 { 46 import std.string : fromStringz, toStringz; 47 private: 48 SharedLibHandle handle; 49 public: 50 bool loaded() @property { return handle !is null; } 51 52 void load(string filename) 53 { 54 version(Posix) 55 { 56 if((handle = dlopen(filename.toStringz(), RTLD_NOW)) is null) 57 { 58 throw new SharedLibException("Failed to load library " ~ filename ~ ": " ~ dlerror().fromStringz().idup); 59 } 60 } 61 else version(Windows) 62 { 63 if((handle = LoadLibraryA(filename.toStringz())) is null) 64 { 65 LPCSTR error; 66 DWORD tchar_length = FormatMessageA( 67 FORMAT_MESSAGE_ALLOCATE_BUFFER | 68 FORMAT_MESSAGE_FROM_SYSTEM | 69 FORMAT_MESSAGE_IGNORE_INSERTS, 70 null, 71 GetLastError(), 72 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 73 cast(char*) &error, 74 0, 75 null); 76 scope(exit) LocalFree(cast(HLOCAL) error); 77 78 throw new SharedLibException("Failed to load library " ~ filename ~ ": " ~ error[0..tchar_length].idup); 79 } 80 } 81 else static assert(0, "Unsupported operating system"); 82 } 83 84 void unload() 85 { 86 version (Posix) alias close = dlclose; 87 else version (Windows) alias close = FreeLibrary; 88 else static assert(0, "Unsupported operating system"); 89 90 if (handle) { 91 close(handle); 92 handle = null; 93 } 94 } 95 96 T getSymbol(T)(string symbol) 97 { 98 version (Posix) alias get = dlsym; 99 else version (Windows) alias get = GetProcAddress; 100 else static assert(0, "Unsupported operating system"); 101 102 return cast(T) get(handle, symbol.toStringz()); 103 } 104 } 105 106 public: 107 108 final class SharedLibException : Exception 109 { 110 this(string msg) @safe pure nothrow 111 { 112 super(msg); 113 } 114 } 115 116 private 117 { 118 bool isSym(string m) { return m != "object" && m != "llvm" && m != "core" && m != "orEmpty"; } 119 120 string declareSymPtr(string m) { return "typeof(link." ~ m ~ ")* " ~ m ~ ";"; } 121 string getSymPtr(string m) { return m ~ " = library.getSymbol!(typeof(" ~ m ~ "))(\"" ~ m ~ "\");"; } 122 } 123 124 __gshared 125 { 126 mixin ({ 127 string code; 128 foreach (m; __traits(allMembers, link)) if (m.isSym) { 129 code ~= m.declareSymPtr; 130 } 131 return code; 132 }()); 133 } 134 135 /// Container for holding the LLVM library and the load/unload functions. 136 public struct LLVM 137 { 138 import llvm.config : LLVM_VersionString; 139 private: 140 __gshared static SharedLib library; 141 142 static void getSymbols() 143 { 144 foreach (m; __traits(allMembers, link)) static if (m.isSym) { 145 mixin (m.getSymPtr); 146 debug { 147 import std.stdio : stderr; 148 if (!mixin(m)) stderr.writeln("Missing LLVM symbol: " ~ m); 149 } 150 } 151 } 152 public: 153 /// true iff the LLVM library is loaded 154 static bool loaded() @property { return library.loaded; } 155 156 /// Loads the LLVM library using the default filename. 157 static void load() 158 { 159 load(null); 160 } 161 162 /// Loads the LLVM library using the specified filename 163 static void load(string filename) 164 { 165 if (filename is null) { 166 filename = libPrefix ~ "LLVM-" ~ LLVM_VersionString ~ "." ~ libSuffix; 167 } 168 169 if (library.loaded) library.unload(); 170 171 library.load(filename); 172 getSymbols(); 173 } 174 175 /// Unloads the LLVM library 176 static void unload() 177 { 178 library.unload(); 179 } 180 } 181 182 version (LLVM_Autoload) 183 { 184 shared static this() 185 { 186 LLVM.load(); 187 } 188 189 shared static ~this() 190 { 191 LLVM.unload(); 192 } 193 }