Load sibling libraries from the same directory

When libEGL and either libGLESv2 or libGLES_CM are in a different
folder from the executable's folder, libEGL wasn't successfully
finding libGLESv2/libGLES_CM (or vice versa). Since these libraries
are generally in the same folder, using the current library's folder
as a starting location to find another library solves this issue.

Change-Id: Ice9217411de4e269d511549411297b57fc1a4bbb
Reviewed-on: https://swiftshader-review.googlesource.com/18548
Tested-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/Common/SharedLibrary.hpp b/src/Common/SharedLibrary.hpp
index ab710eb..85e5e7d 100644
--- a/src/Common/SharedLibrary.hpp
+++ b/src/Common/SharedLibrary.hpp
@@ -21,14 +21,35 @@
 	#include <dlfcn.h>
 #endif
 
+#include <string>
+
 void *getLibraryHandle(const char *path);
 void *loadLibrary(const char *path);
 void freeLibrary(void *library);
 void *getProcAddress(void *library, const char *name);
 
 template<int n>
-void *loadLibrary(const char *(&names)[n], const char *mustContainSymbol = nullptr)
+void *loadLibrary(const std::string &libraryDirectory, const char *(&names)[n], const char *mustContainSymbol = nullptr)
 {
+	if(!libraryDirectory.empty())
+	{
+		for(int i = 0; i < n; i++)
+		{
+			std::string nameWithPath = libraryDirectory + names[i];
+			void *library = getLibraryHandle(nameWithPath.c_str());
+
+			if(library)
+			{
+				if(!mustContainSymbol || getProcAddress(library, mustContainSymbol))
+				{
+					return library;
+				}
+
+				freeLibrary(library);
+			}
+		}
+	}
+
 	for(int i = 0; i < n; i++)
 	{
 		void *library = getLibraryHandle(names[i]);
@@ -84,6 +105,22 @@
 	{
 		return (void*)GetProcAddress((HMODULE)library, name);
 	}
+
+	inline std::string getLibraryDirectoryFromSymbol(void* symbol)
+	{
+		HMODULE module = NULL;
+		GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCTSTR)symbol, &module);
+		char filename[1024];
+		if(module && (GetModuleFileName(module, filename, sizeof(filename)) != 0))
+		{
+			std::string directory(filename);
+			return directory.substr(0, directory.find_last_of("\\/") + 1).c_str();
+		}
+		else
+		{
+			return "";
+		}
+	}
 #else
 	inline void *loadLibrary(const char *path)
 	{
@@ -127,6 +164,20 @@
 
 		return symbol;
 	}
+
+	inline std::string getLibraryDirectoryFromSymbol(void* symbol)
+	{
+		Dl_info dl_info;
+		if(dladdr(symbol, &dl_info) != 0)
+		{
+			std::string directory(dl_info.dli_fname);
+			return directory.substr(0, directory.find_last_of("\\/") + 1).c_str();
+		}
+		else
+		{
+			return "";
+		}
+	}
 #endif
 
 #endif   // SharedLibrary_hpp
diff --git a/src/OpenGL/libEGL/libEGL.hpp b/src/OpenGL/libEGL/libEGL.hpp
index 46e319a..7ef0d31 100644
--- a/src/OpenGL/libEGL/libEGL.hpp
+++ b/src/OpenGL/libEGL/libEGL.hpp
@@ -73,10 +73,8 @@
 class LibEGL
 {
 public:
-	LibEGL()
+	LibEGL(const std::string libraryDirectory) : libraryDirectory(libraryDirectory)
 	{
-		libEGL = nullptr;
-		libEGLexports = nullptr;
 	}
 
 	~LibEGL()
@@ -124,7 +122,7 @@
 				#error "libEGL::loadExports unimplemented for this platform"
 			#endif
 
-			libEGL = loadLibrary(libEGL_lib, "libEGL_swiftshader");
+			libEGL = loadLibrary(libraryDirectory, libEGL_lib, "libEGL_swiftshader");
 
 			if(libEGL)
 			{
@@ -136,8 +134,9 @@
 		return libEGLexports;
 	}
 
-	void *libEGL;
-	LibEGLexports *libEGLexports;
+	void *libEGL = nullptr;
+	LibEGLexports *libEGLexports = nullptr;
+	const std::string libraryDirectory;
 };
 
 #endif   // libEGL_hpp
diff --git a/src/OpenGL/libEGL/main.cpp b/src/OpenGL/libEGL/main.cpp
index a1ff6f1..c850610 100644
--- a/src/OpenGL/libEGL/main.cpp
+++ b/src/OpenGL/libEGL/main.cpp
@@ -649,5 +649,5 @@
 	return &libEGL;
 }
 
-LibGLES_CM libGLES_CM;
-LibGLESv2 libGLESv2;
+LibGLES_CM libGLES_CM(getLibraryDirectoryFromSymbol((void*)libEGL_swiftshader));
+LibGLESv2 libGLESv2(getLibraryDirectoryFromSymbol((void*)libEGL_swiftshader));
diff --git a/src/OpenGL/libGLES_CM/libGLES_CM.hpp b/src/OpenGL/libGLES_CM/libGLES_CM.hpp
index d6740ec..b9c29f5 100644
--- a/src/OpenGL/libGLES_CM/libGLES_CM.hpp
+++ b/src/OpenGL/libGLES_CM/libGLES_CM.hpp
@@ -229,10 +229,8 @@
 class LibGLES_CM
 {
 public:
-	LibGLES_CM()
+	LibGLES_CM(const std::string libraryDirectory) : libraryDirectory(libraryDirectory)
 	{
-		libGLES_CM = nullptr;
-		libGLES_CMexports = nullptr;
 	}
 
 	~LibGLES_CM()
@@ -285,7 +283,7 @@
 				#error "libGLES_CM::loadExports unimplemented for this platform"
 			#endif
 
-			libGLES_CM = loadLibrary(libGLES_CM_lib, "libGLES_CM_swiftshader");
+			libGLES_CM = loadLibrary(libraryDirectory, libGLES_CM_lib, "libGLES_CM_swiftshader");
 
 			if(libGLES_CM)
 			{
@@ -297,8 +295,9 @@
 		return libGLES_CMexports;
 	}
 
-	void *libGLES_CM;
-	LibGLES_CMexports *libGLES_CMexports;
+	void *libGLES_CM = nullptr;
+	LibGLES_CMexports *libGLES_CMexports = nullptr;
+	const std::string libraryDirectory;
 };
 
 #endif   // libGLES_CM_hpp
diff --git a/src/OpenGL/libGLES_CM/main.cpp b/src/OpenGL/libGLES_CM/main.cpp
index f2bd0b7..ea56c81 100644
--- a/src/OpenGL/libGLES_CM/main.cpp
+++ b/src/OpenGL/libGLES_CM/main.cpp
@@ -1610,4 +1610,4 @@
 	return &libGLES_CM;
 }
 
-LibEGL libEGL;
+LibEGL libEGL(getLibraryDirectoryFromSymbol((void*)libGLES_CM_swiftshader));
diff --git a/src/OpenGL/libGLESv2/entry_points.cpp b/src/OpenGL/libGLESv2/entry_points.cpp
index b142b85..378f9fe 100644
--- a/src/OpenGL/libGLESv2/entry_points.cpp
+++ b/src/OpenGL/libGLESv2/entry_points.cpp
@@ -1426,5 +1426,5 @@
 	return &libGLESv2;
 }
 
-LibEGL libEGL;
-LibGLES_CM libGLES_CM;
+LibEGL libEGL(getLibraryDirectoryFromSymbol((void*)libGLESv2_swiftshader));
+LibGLES_CM libGLES_CM(getLibraryDirectoryFromSymbol((void*)libGLESv2_swiftshader));
diff --git a/src/OpenGL/libGLESv2/libGLESv2.hpp b/src/OpenGL/libGLESv2/libGLESv2.hpp
index 8946f0b..1677d16 100644
--- a/src/OpenGL/libGLESv2/libGLESv2.hpp
+++ b/src/OpenGL/libGLESv2/libGLESv2.hpp
@@ -254,10 +254,8 @@
 class LibGLESv2
 {
 public:
-	LibGLESv2()
+	LibGLESv2(const std::string libraryDirectory) : libraryDirectory(libraryDirectory)
 	{
-		libGLESv2 = nullptr;
-		libGLESv2exports = nullptr;
 	}
 
 	~LibGLESv2()
@@ -310,7 +308,7 @@
 				#error "libGLESv2::loadExports unimplemented for this platform"
 			#endif
 
-			libGLESv2 = loadLibrary(libGLESv2_lib, "libGLESv2_swiftshader");
+			libGLESv2 = loadLibrary(libraryDirectory, libGLESv2_lib, "libGLESv2_swiftshader");
 
 			if(libGLESv2)
 			{
@@ -322,8 +320,9 @@
 		return libGLESv2exports;
 	}
 
-	void *libGLESv2;
-	LibGLESv2exports *libGLESv2exports;
+	void *libGLESv2 = nullptr;
+	LibGLESv2exports *libGLESv2exports = nullptr;
+	const std::string libraryDirectory;
 };
 
 #endif   // libGLESv2_hpp