From f5a9b3b249efdafacbff1060999c60257c0ff72c Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Wed, 7 Dec 2016 05:24:38 +0530 Subject: [PATCH] Fix shared module support on Windows Unlike Linux and OS X, when a library is loaded, all the symbols aren't loaded into a single namespace. You must fetch the symbol by iterating over all loaded modules. So, we shouldn't use /FORCE:UNRESOLVED since that is not what modules do on Windows. Instead, we now do exactly what GModule does on Windows. Also use `void` for functions that take no arguments. --- mesonbuild/compilers.py | 3 - test cases/common/125 shared module/module.c | 51 +++++++++- test cases/common/125 shared module/prog.c | 92 ++++++++++++++++--- test cases/common/125 shared module/runtime.c | 2 +- 4 files changed, 129 insertions(+), 19 deletions(-) diff --git a/mesonbuild/compilers.py b/mesonbuild/compilers.py index 63117e89e..b019e5f5f 100644 --- a/mesonbuild/compilers.py +++ b/mesonbuild/compilers.py @@ -1926,9 +1926,6 @@ class VisualStudioCCompiler(CCompiler): pdbarr += ['pdb'] return ['/DEBUG', '/PDB:' + '.'.join(pdbarr)] - def get_std_shared_module_link_args(self): - return ['/DLL', '/FORCE:UNRESOLVED'] - class VisualStudioCPPCompiler(VisualStudioCCompiler, CPPCompiler): def __init__(self, exelist, version, is_cross, exe_wrap): self.language = 'cpp' diff --git a/test cases/common/125 shared module/module.c b/test cases/common/125 shared module/module.c index ed2712c2a..56078c565 100644 --- a/test cases/common/125 shared module/module.c +++ b/test cases/common/125 shared module/module.c @@ -9,6 +9,54 @@ #endif #endif +#ifdef _WIN32 + +#include +#include +#include + +typedef int (*fptr) (void); + +/* Unlike Linux and OS X, when a library is loaded, all the symbols aren't + * loaded into a single namespace. You must fetch the symbol by iterating over + * all loaded modules. Code for finding the function from any of the loaded + * modules is taken from gmodule.c in glib */ +fptr find_any_f (const char *name) { + fptr f; + HANDLE snapshot; + MODULEENTRY32 me32; + + snapshot = CreateToolhelp32Snapshot (TH32CS_SNAPMODULE, 0); + if (snapshot == (HANDLE) -1) { + printf("Could not get snapshot\n"); + return 0; + } + + me32.dwSize = sizeof (me32); + + f = NULL; + if (Module32First (snapshot, &me32)) { + do { + if ((f = (fptr) GetProcAddress (me32.hModule, name)) != NULL) + break; + } while (Module32Next (snapshot, &me32)); + } + + CloseHandle (snapshot); + return f; +} + +int DLL_PUBLIC func() { + fptr f; + + f = find_any_f ("func_from_language_runtime"); + if (f != NULL) + return f(); + printf ("Could not find function\n"); + return 1; +} + +#else /* * Shared modules often have references to symbols that are not defined * at link time, but which will be provided from deps of the executable that @@ -17,6 +65,7 @@ */ int func_from_language_runtime(); -int DLL_PUBLIC func() { +int DLL_PUBLIC func(void) { return func_from_language_runtime(); } +#endif diff --git a/test cases/common/125 shared module/prog.c b/test cases/common/125 shared module/prog.c index 839703401..2b638409b 100644 --- a/test cases/common/125 shared module/prog.c +++ b/test cases/common/125 shared module/prog.c @@ -1,38 +1,102 @@ + +#include + +int func_from_language_runtime(void); +typedef int (*fptr) (void); + #ifdef _WIN32 -// FIXME: add implementation using Winapi functions for dlopen. -int main(int argc, char **argv) { - return 0; +#include + +wchar_t* +win32_get_last_error (void) +{ + wchar_t *msg = NULL; + + FormatMessageW (FORMAT_MESSAGE_ALLOCATE_BUFFER + | FORMAT_MESSAGE_IGNORE_INSERTS + | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, GetLastError (), 0, + (LPWSTR) &msg, 0, NULL); + return msg; +} + +int +main (int argc, char **argv) +{ + HINSTANCE handle; + fptr importedfunc; + int expected, actual; + int ret = 1; + + handle = LoadLibraryA (argv[1]); + if (!handle) { + wchar_t *msg = win32_get_last_error (); + printf ("Could not open %s: %S\n", argv[1], msg); + goto nohandle; + } + + importedfunc = (fptr) GetProcAddress (handle, "func"); + if (importedfunc == NULL) { + wchar_t *msg = win32_get_last_error (); + printf ("Could not find 'func': %S\n", msg); + goto out; + } + + actual = importedfunc (); + expected = func_from_language_runtime (); + if (actual != expected) { + printf ("Got %i instead of %i\n", actual, expected); + goto out; + } + + ret = 0; +out: + FreeLibrary (handle); +nohandle: + return ret; } #else #include #include -#include - -int func(); -int func_from_language_runtime(); int main(int argc, char **argv) { void *dl; - int (*importedfunc)(); - int success; + fptr importedfunc; + int expected, actual; char *error; + int ret = 1; dlerror(); dl = dlopen(argv[1], RTLD_LAZY); error = dlerror(); if(error) { printf("Could not open %s: %s\n", argv[1], error); - return 1; + goto nodl; } - importedfunc = (int (*)()) dlsym(dl, "func"); - assert(importedfunc); + + importedfunc = (fptr) dlsym(dl, "func"); + if (importedfunc == NULL) { + printf ("Could not find 'func'\n"); + goto out; + } + assert(importedfunc != func_from_language_runtime); - success = (*importedfunc)() == func_from_language_runtime(); + + actual = (*importedfunc)(); + expected = func_from_language_runtime (); + if (actual != expected) { + printf ("Got %i instead of %i\n", actual, expected); + goto out; + } + + ret = 0; +out: dlclose(dl); - return !success; +nodl: + return ret; } #endif diff --git a/test cases/common/125 shared module/runtime.c b/test cases/common/125 shared module/runtime.c index 68c813a4d..03bde8614 100644 --- a/test cases/common/125 shared module/runtime.c +++ b/test cases/common/125 shared module/runtime.c @@ -14,6 +14,6 @@ * modules. */ -int DLL_PUBLIC func_from_language_runtime() { +int DLL_PUBLIC func_from_language_runtime(void) { return 86; }