1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586 | #include <bhash.h>
#include <gc.h>
#include <dlfcn.h>
#include <err.h>
#include <libgen.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <fcntl.h>
typedef void* (*bl_module_load)(void);
static hashmap_t *loaded = NULL;
void *bl_use(const char *from_file, const char *module_path) {
if (!loaded) loaded = hashmap_new();
const void *cached = hashmap_get(loaded, module_path);
if (cached) return (void*)cached;
const char *paths = getenv("BLANG_MODULE_PATHS");
if (!paths) paths = ".";
char *copy = strdup(paths);
void *exports = NULL;
char cwd[PATH_MAX] = {0};
getcwd(cwd, PATH_MAX);
char buf[PATH_MAX] = {0};
strncpy(buf, from_file, sizeof(buf));
char *from_dir = dirname(buf);
chdir(from_dir);
char module_parts[PATH_MAX];
strncpy(module_parts, module_path, sizeof(module_parts));
char *module_basename = basename(module_parts);
char *module_dirname = dirname(module_parts);
for (char *folder; (folder = strsep(©, ":")) != NULL; ) {
char *path = NULL;
if (asprintf(&path, "%s/%s/lib%s.so", folder, module_dirname, module_basename) <= 0)
errx(1, "Allocation failure");
void *module = dlopen(path, RTLD_LAZY);
free(path);
if (!module) {
if (asprintf(&path, "%s/%s/%s.bl", folder, module_dirname, module_basename) <= 0)
errx(1, "Allocation failure");
int test = open(path, O_RDONLY);
if (test) {
close(test);
// Compile on-demand:
char tmp[] = "/tmp/blang-module-XXXXXX.so";
int xx = mkstemps(tmp, 3);
if (!xx) errx(1, "Could not create temp file");
close(xx);
pid_t child = fork();
if (!child) {
char *rpath = realpath(path, NULL);
chdir(cwd);
execvp("./blangc", (char*[]){"./blangc", "-c", rpath, "-s", tmp, NULL});
}
int status;
waitpid(child, &status, 0);
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
free(path);
continue;
}
module = dlopen(tmp, RTLD_LAZY);
free(path);
if (module) goto load_module;
else continue;
} else {
free(path);
}
continue;
}
load_module:;
bl_module_load load_module = dlsym(module, "load");
if (!load_module) continue;
exports = load_module();
if (exports) break;
}
free(copy);
chdir(cwd);
if (exports) hashmap_set(loaded, (void*)module_path, exports);
return exports;
}
|