blob: e3b1e16277b0ea2ec408899ad19fd0a064ae18ba [file] [log] [blame]
Nicolas Capens68a82382018-10-02 13:16:55 -04001// 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)
Ben Clayton595d9112019-12-17 20:37:57 +000019# include <Windows.h>
Nicolas Capens68a82382018-10-02 13:16:55 -040020#else
Ben Clayton595d9112019-12-17 20:37:57 +000021# include <dlfcn.h>
Nicolas Capens68a82382018-10-02 13:16:55 -040022#endif
23
24#include <string>
25
26void *getLibraryHandle(const char *path);
27void *loadLibrary(const char *path);
28void freeLibrary(void *library);
29void *getProcAddress(void *library, const char *name);
30
31template<int n>
32void *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)
Ben Clayton595d9112019-12-17 20:37:57 +000070inline void *loadLibrary(const char *path)
71{
72 return (void *)LoadLibrary(path);
73}
74
75inline void *getLibraryHandle(const char *path)
76{
77 HMODULE module = NULL;
78 GetModuleHandleEx(0, path, &module);
79 return (void *)module;
80}
81
82inline void freeLibrary(void *library)
83{
84 FreeLibrary((HMODULE)library);
85}
86
87inline void *getProcAddress(void *library, const char *name)
88{
89 return (void *)GetProcAddress((HMODULE)library, name);
90}
91
92inline 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))
Nicolas Capens68a82382018-10-02 13:16:55 -0400101 {
Ben Clayton595d9112019-12-17 20:37:57 +0000102 std::string directory(filename);
103 return directory.substr(0, directory.find_last_of("\\/") + 1).c_str();
Nicolas Capens68a82382018-10-02 13:16:55 -0400104 }
Ben Clayton595d9112019-12-17 20:37:57 +0000105 else
Nicolas Capens68a82382018-10-02 13:16:55 -0400106 {
Ben Clayton595d9112019-12-17 20:37:57 +0000107 return "";
Nicolas Capens68a82382018-10-02 13:16:55 -0400108 }
Ben Clayton595d9112019-12-17 20:37:57 +0000109}
Nicolas Capens68a82382018-10-02 13:16:55 -0400110#else
Ben Clayton595d9112019-12-17 20:37:57 +0000111inline void *loadLibrary(const char *path)
112{
113 return dlopen(path, RTLD_LAZY | RTLD_LOCAL);
114}
115
116inline 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)
Nicolas Capens68a82382018-10-02 13:16:55 -0400125 {
Ben Clayton595d9112019-12-17 20:37:57 +0000126 return dlopen(path, RTLD_LAZY | RTLD_LOCAL); // Increment reference count
Nicolas Capens68a82382018-10-02 13:16:55 -0400127 }
128
Ben Clayton595d9112019-12-17 20:37:57 +0000129 return nullptr;
130# endif
131}
132
133inline void freeLibrary(void *library)
134{
135 if(library)
Nicolas Capens68a82382018-10-02 13:16:55 -0400136 {
Ben Clayton595d9112019-12-17 20:37:57 +0000137 dlclose(library);
138 }
139}
Nicolas Capens68a82382018-10-02 13:16:55 -0400140
Ben Clayton595d9112019-12-17 20:37:57 +0000141inline void *getProcAddress(void *library, const char *name)
142{
143 void *symbol = dlsym(library, name);
Nicolas Capens68a82382018-10-02 13:16:55 -0400144
Ben Clayton595d9112019-12-17 20:37:57 +0000145 if(!symbol)
146 {
147 const char *reason = dlerror(); // Silence the error
148 (void)reason;
Nicolas Capens68a82382018-10-02 13:16:55 -0400149 }
150
Ben Clayton595d9112019-12-17 20:37:57 +0000151 return symbol;
152}
153
154inline std::string getModuleDirectory()
155{
156 static int dummy_symbol = 0;
157
158 Dl_info dl_info;
159 if(dladdr(&dummy_symbol, &dl_info) != 0)
Nicolas Capens68a82382018-10-02 13:16:55 -0400160 {
Ben Clayton595d9112019-12-17 20:37:57 +0000161 std::string directory(dl_info.dli_fname);
162 return directory.substr(0, directory.find_last_of("\\/") + 1).c_str();
Nicolas Capens68a82382018-10-02 13:16:55 -0400163 }
Ben Clayton595d9112019-12-17 20:37:57 +0000164 else
Nicolas Capens68a82382018-10-02 13:16:55 -0400165 {
Ben Clayton595d9112019-12-17 20:37:57 +0000166 return "";
Nicolas Capens68a82382018-10-02 13:16:55 -0400167 }
Ben Clayton595d9112019-12-17 20:37:57 +0000168}
Nicolas Capens68a82382018-10-02 13:16:55 -0400169#endif
170
Ben Clayton595d9112019-12-17 20:37:57 +0000171#endif // SharedLibrary_hpp