Index: test/module/src/program.c |
=================================================================== |
--- test/module/src/program.c (revision 0) |
+++ test/module/src/program.c (revision 0) |
@@ -0,0 +1,111 @@ |
+#include <stdio.h> |
+#include <stdlib.h> |
+ |
+#if defined(PLATFORM_WIN) |
+#include <windows.h> |
+#elif defined(PLATFORM_MAC) || defined(PLATFORM_LINUX) |
+#include <dlfcn.h> |
+#include <libgen.h> |
+#include <string.h> |
+#include <sys/param.h> |
+#define MAX_PATH PATH_MAX |
+#endif |
+ |
+#if defined(PLATFORM_WIN) |
+#define MODULE_SUFFIX ".dll" |
+#elif defined(PLATFORM_MAC) |
+#define MODULE_SUFFIX ".dylib" |
+#elif defined(PLATFORM_LINUX) |
+#define MODULE_SUFFIX ".so" |
+#endif |
+ |
+typedef void (*module_symbol)(void); |
+char bin_path[MAX_PATH + 1]; |
+ |
+ |
+void CallModule(const char* module) { |
+ char module_path[MAX_PATH + 1]; |
+ const char* module_function = "module_main"; |
+ module_symbol funcptr; |
+#if defined(PLATFORM_WIN) |
+ HMODULE dl; |
+ char drive[_MAX_DRIVE]; |
+ char dir[_MAX_DIR]; |
+ |
+ if (_splitpath_s(bin_path, drive, _MAX_DRIVE, dir, _MAX_DIR, |
+ NULL, 0, NULL, 0)) { |
+ fprintf(stderr, "Failed to split executable path.\n"); |
+ return; |
+ } |
+ if (_makepath_s(module_path, MAX_PATH, drive, dir, module, MODULE_SUFFIX)) { |
+ fprintf(stderr, "Failed to calculate module path.\n"); |
+ return; |
+ } |
+ |
+ dl = LoadLibrary(module_path); |
+ if (!dl) { |
+ fprintf(stderr, "Failed to open module: %s\n", module_path); |
+ return; |
+ } |
+ |
+ funcptr = (module_symbol) GetProcAddress(dl, module_function); |
+ if (!funcptr) { |
+ fprintf(stderr, "Failed to find symbol: %s\n", module_function); |
+ return; |
+ } |
+ funcptr(); |
+ |
+ FreeLibrary(dl); |
+#elif defined(PLATFORM_MAC) || defined(PLATFORM_LINUX) |
+ void* dl; |
+ char* path_copy = strdup(bin_path); |
+ char* bin_dir = dirname(path_copy); |
+ int path_size = snprintf(module_path, MAX_PATH, "%s/%s%s", bin_dir, module, |
+ MODULE_SUFFIX); |
+ free(path_copy); |
+ if (path_size < 0 || path_size > MAX_PATH) { |
+ fprintf(stderr, "Failed to calculate module path.\n"); |
+ return; |
+ } |
+ module_path[path_size] = 0; |
+ |
+ dl = dlopen(module_path, RTLD_LAZY); |
+ if (!dl) { |
+ fprintf(stderr, "Failed to open module: %s\n", module_path); |
+ return; |
+ } |
+ |
+ funcptr = dlsym(dl, module_function); |
+ if (!funcptr) { |
+ fprintf(stderr, "Failed to find symbol: %s\n", module_function); |
+ return; |
+ } |
+ funcptr(); |
+ |
+ dlclose(dl); |
+#endif |
+} |
+ |
+int main(int argc, char *argv[]) |
+{ |
+ fprintf(stdout, "Hello from program.c\n"); |
+ fflush(stdout); |
+ |
+#if defined(PLATFORM_WIN) |
+ if (!GetModuleFileName(NULL, bin_path, MAX_PATH)) { |
+ fprintf(stderr, "Failed to determine executable path.\n"); |
+ return; |
+ } |
+#elif defined(PLATFORM_MAC) || defined(PLATFORM_LINUX) |
+ // Using argv[0] should be OK here since we control how the tests run, and |
+ // can avoid exec and such issues that make it unreliable. |
+ if (!realpath(argv[0], bin_path)) { |
+ fprintf(stderr, "Failed to determine executable path (%s).\n", argv[0]); |
+ return; |
+ } |
+#endif |
+ |
+ CallModule("lib1"); |
+ CallModule("lib2"); |
+ return 0; |
+} |