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 @disable this(this); 51 52 this(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 ~this() 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) 122 { 123 string code; 124 code ~= "foreach (library; libraries) { "; 125 code ~= m ~ " = library.getSymbol!(typeof(" ~ m ~ "))(\"" ~ m ~ "\");"; 126 code ~= "if (" ~ m ~ " !is null) break;"; 127 code ~= " }"; 128 return code; 129 } 130 } 131 132 __gshared 133 { 134 mixin ({ 135 string code; 136 foreach (m; __traits(allMembers, link)) if (m.isSym) { 137 code ~= m.declareSymPtr; 138 } 139 return code; 140 }()); 141 } 142 143 /// Container for holding the LLVM library and the load/unload functions. 144 public struct LLVM 145 { 146 import llvm.config : LLVM_VersionString; 147 private: 148 import std.typecons : RefCounted; 149 150 __gshared static RefCounted!SharedLib[] libraries; 151 152 static void getSymbols() 153 { 154 foreach (m; __traits(allMembers, link)) static if (m.isSym) { 155 mixin (m.getSymPtr); 156 debug { 157 import std.stdio : stderr; 158 if (!mixin(m)) stderr.writeln("Missing LLVM symbol: " ~ m); 159 } 160 } 161 } 162 public: 163 /// true iff the LLVM library is loaded 164 static bool loaded() @property { return libraries.length > 0; } 165 166 /// Loads the LLVM libraries using the specified filenames 167 static void load(string[] filenames...) 168 { 169 if (filenames.length == 0) { 170 filenames ~= libPrefix ~ "LLVM" ~ "." ~ libSuffix; 171 filenames ~= libPrefix ~ "LTO" ~ "." ~ libSuffix; 172 } 173 174 if (loaded) unload(); 175 176 foreach (filename; filenames) { 177 libraries ~= RefCounted!SharedLib(filename); 178 } 179 getSymbols(); 180 } 181 182 /// Unloads the LLVM library 183 static void unload() 184 { 185 libraries.length = 0; 186 } 187 } 188 189 version (LLVM_Autoload) 190 { 191 shared static this() 192 { 193 LLVM.load(); 194 } 195 196 shared static ~this() 197 { 198 LLVM.unload(); 199 } 200 }