1 #include <stdio.h>
2 #include <stdlib.h>
3 
4 #if defined(PLATFORM_WIN)
5 #include <windows.h>
6 #elif defined(PLATFORM_MAC) || defined(PLATFORM_LINUX)
7 #include <dlfcn.h>
8 #include <libgen.h>
9 #include <string.h>
10 #include <sys/param.h>
11 #define MAX_PATH PATH_MAX
12 #endif
13 
14 #if defined(PLATFORM_WIN)
15 #define MODULE_SUFFIX ".dll"
16 #elif defined(PLATFORM_MAC)
17 #define MODULE_SUFFIX ".so"
18 #elif defined(PLATFORM_LINUX)
19 #define MODULE_SUFFIX ".so"
20 #endif
21 
22 typedef void (*module_symbol)(void);
23 char bin_path[MAX_PATH + 1];
24 
25 
CallModule(const char * module)26 void CallModule(const char* module) {
27   char module_path[MAX_PATH + 1];
28   const char* module_function = "module_main";
29   module_symbol funcptr;
30 #if defined(PLATFORM_WIN)
31   HMODULE dl;
32   char drive[_MAX_DRIVE];
33   char dir[_MAX_DIR];
34 
35   if (_splitpath_s(bin_path, drive, _MAX_DRIVE, dir, _MAX_DIR,
36                     NULL, 0, NULL, 0)) {
37     fprintf(stderr, "Failed to split executable path.\n");
38     return;
39   }
40   if (_makepath_s(module_path, MAX_PATH, drive, dir, module, MODULE_SUFFIX)) {
41     fprintf(stderr, "Failed to calculate module path.\n");
42     return;
43   }
44 
45   dl = LoadLibrary(module_path);
46   if (!dl) {
47     fprintf(stderr, "Failed to open module: %s\n", module_path);
48     return;
49   }
50 
51   funcptr = (module_symbol) GetProcAddress(dl, module_function);
52   if (!funcptr) {
53     fprintf(stderr, "Failed to find symbol: %s\n", module_function);
54     return;
55   }
56   funcptr();
57 
58   FreeLibrary(dl);
59 #elif defined(PLATFORM_MAC) || defined(PLATFORM_LINUX)
60   void* dl;
61   char* path_copy = strdup(bin_path);
62   char* bin_dir = dirname(path_copy);
63   int path_size = snprintf(module_path, MAX_PATH, "%s/%s%s", bin_dir, module,
64                            MODULE_SUFFIX);
65   free(path_copy);
66   if (path_size < 0 || path_size > MAX_PATH) {
67     fprintf(stderr, "Failed to calculate module path.\n");
68     return;
69   }
70   module_path[path_size] = 0;
71 
72   dl = dlopen(module_path, RTLD_LAZY);
73   if (!dl) {
74     fprintf(stderr, "Failed to open module: %s\n", module_path);
75     return;
76   }
77 
78   funcptr = dlsym(dl, module_function);
79   if (!funcptr) {
80     fprintf(stderr, "Failed to find symbol: %s\n", module_function);
81     return;
82   }
83   funcptr();
84 
85   dlclose(dl);
86 #endif
87 }
88 
main(int argc,char * argv[])89 int main(int argc, char *argv[])
90 {
91   fprintf(stdout, "Hello from program.c\n");
92   fflush(stdout);
93 
94 #if defined(PLATFORM_WIN)
95   if (!GetModuleFileName(NULL, bin_path, MAX_PATH)) {
96     fprintf(stderr, "Failed to determine executable path.\n");
97     return 1;
98   }
99 #elif defined(PLATFORM_MAC) || defined(PLATFORM_LINUX)
100   // Using argv[0] should be OK here since we control how the tests run, and
101   // can avoid exec and such issues that make it unreliable.
102   if (!realpath(argv[0], bin_path)) {
103     fprintf(stderr, "Failed to determine executable path (%s).\n", argv[0]);
104     return 1;
105   }
106 #endif
107 
108   CallModule("lib1");
109   CallModule("lib2");
110   return 0;
111 }
112