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
22typedef void (*module_symbol)(void);
23char bin_path[MAX_PATH + 1];
24
25
26void 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
89int 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