| #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 ".so" |
| #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 1; |
| } |
| #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 1; |
| } |
| #endif |
| |
| CallModule("lib1"); |
| CallModule("lib2"); |
| return 0; |
| } |