1 // Copyright 2016 The SwiftShader Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //    http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef SharedLibrary_hpp
16 #define SharedLibrary_hpp
17 
18 #if defined(_WIN32)
19 	#include <Windows.h>
20 #else
21 	#include <dlfcn.h>
22 #endif
23 
24 #include <string>
25 
26 void *getLibraryHandle(const char *path);
27 void *loadLibrary(const char *path);
28 void freeLibrary(void *library);
29 void *getProcAddress(void *library, const char *name);
30 
31 template<int n>
loadLibrary(const std::string & libraryDirectory,const char * (& names)[n],const char * mustContainSymbol=nullptr)32 void *loadLibrary(const std::string &libraryDirectory, const char *(&names)[n], const char *mustContainSymbol = nullptr)
33 {
34 	for(const char *libraryName : names)
35 	{
36 		std::string libraryPath = libraryDirectory + libraryName;
37 		void *library = getLibraryHandle(libraryPath.c_str());
38 
39 		if(library)
40 		{
41 			if(!mustContainSymbol || getProcAddress(library, mustContainSymbol))
42 			{
43 				return library;
44 			}
45 
46 			freeLibrary(library);
47 		}
48 	}
49 
50 	for(const char *libraryName : names)
51 	{
52 		std::string libraryPath = libraryDirectory + libraryName;
53 		void *library = loadLibrary(libraryPath.c_str());
54 
55 		if(library)
56 		{
57 			if(!mustContainSymbol || getProcAddress(library, mustContainSymbol))
58 			{
59 				return library;
60 			}
61 
62 			freeLibrary(library);
63 		}
64 	}
65 
66 	return nullptr;
67 }
68 
69 #if defined(_WIN32)
loadLibrary(const char * path)70 	inline void *loadLibrary(const char *path)
71 	{
72 		return (void*)LoadLibrary(path);
73 	}
74 
getLibraryHandle(const char * path)75 	inline void *getLibraryHandle(const char *path)
76 	{
77 		HMODULE module = NULL;
78 		GetModuleHandleEx(0, path, &module);
79 		return (void*)module;
80 	}
81 
freeLibrary(void * library)82 	inline void freeLibrary(void *library)
83 	{
84 		FreeLibrary((HMODULE)library);
85 	}
86 
getProcAddress(void * library,const char * name)87 	inline void *getProcAddress(void *library, const char *name)
88 	{
89 		return (void*)GetProcAddress((HMODULE)library, name);
90 	}
91 
getModuleDirectory()92 	inline std::string getModuleDirectory()
93 	{
94 		static int dummy_symbol = 0;
95 
96 		HMODULE module = NULL;
97 		GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCTSTR)&dummy_symbol, &module);
98 
99 		char filename[1024];
100 		if(module && (GetModuleFileName(module, filename, sizeof(filename)) != 0))
101 		{
102 			std::string directory(filename);
103 			return directory.substr(0, directory.find_last_of("\\/") + 1).c_str();
104 		}
105 		else
106 		{
107 			return "";
108 		}
109 	}
110 #else
loadLibrary(const char * path)111 	inline void *loadLibrary(const char *path)
112 	{
113 		return dlopen(path, RTLD_LAZY | RTLD_LOCAL);
114 	}
115 
getLibraryHandle(const char * path)116 	inline void *getLibraryHandle(const char *path)
117 	{
118 		#ifdef __ANDROID__
119 			// bionic doesn't support RTLD_NOLOAD before L
120 			return dlopen(path, RTLD_NOW | RTLD_LOCAL);
121 		#else
122 			void *resident = dlopen(path, RTLD_LAZY | RTLD_NOLOAD | RTLD_LOCAL);
123 
124 			if(resident)
125 			{
126 				return dlopen(path, RTLD_LAZY | RTLD_LOCAL);   // Increment reference count
127 			}
128 
129 			return nullptr;
130 		#endif
131 	}
132 
freeLibrary(void * library)133 	inline void freeLibrary(void *library)
134 	{
135 		if(library)
136 		{
137 			dlclose(library);
138 		}
139 	}
140 
getProcAddress(void * library,const char * name)141 	inline void *getProcAddress(void *library, const char *name)
142 	{
143 		void *symbol = dlsym(library, name);
144 
145 		if(!symbol)
146 		{
147 			const char *reason = dlerror();   // Silence the error
148 			(void)reason;
149 		}
150 
151 		return symbol;
152 	}
153 
getModuleDirectory()154 	inline std::string getModuleDirectory()
155 	{
156 		static int dummy_symbol = 0;
157 
158 		Dl_info dl_info;
159 		if(dladdr(&dummy_symbol, &dl_info) != 0)
160 		{
161 			std::string directory(dl_info.dli_fname);
162 			return directory.substr(0, directory.find_last_of("\\/") + 1).c_str();
163 		}
164 		else
165 		{
166 			return "";
167 		}
168 	}
169 #endif
170 
171 #endif   // SharedLibrary_hpp
172