Support loading shared libraries

This commit is contained in:
Bruce Hill 2024-06-13 12:59:19 -04:00
parent 217eb51280
commit 5757a5023c
4 changed files with 67 additions and 21 deletions

View File

@ -2330,10 +2330,10 @@ CORD compile_statement_header(env_t *env, ast_t *ast)
case Use: {
auto use = Match(ast, Use);
const char *path = use->raw_path;
if (strncmp(path, "./", 2) == 0 || strncmp(path, "../", 3) == 0) {
return CORD_all("#include \"", path, ".h\"\n");
if (strncmp(path, "./", 2) == 0 || strncmp(path, "../", 3) == 0 || strncmp(path, "~/", 2) == 0 || strncmp(path, "/", 1) == 0) {
return CORD_all("#include \"", path, ".tm.h\"\n");
} else {
return CORD_all("#include <", path, ".h>\n");
return CORD_all("#include <tomo/lib", path, ".h>\n");
}
}
default:

View File

@ -2017,7 +2017,7 @@ PARSER(parse_use) {
size_t path_len = strcspn(pos, " \t\r\n;");
if (path_len < 1)
parser_err(ctx, start, pos, "There is no filename here to use");
char *path = heap_strf("%.*s.tm", (int)path_len, pos);
char *path = heap_strn(pos, path_len);
pos += path_len;
while (match(&pos, ";")) continue;
return NewAST(ctx->file, start, pos, Use, .raw_path=path);

29
tomo.c
View File

@ -78,6 +78,7 @@ int main(int argc, char *argv[])
errx(1, "Couldn't set printf specifier");
setenv("TOMO_IMPORT_PATH", "~/.local/src/tomo:.", 0);
setenv("TOMO_LIB_PATH", "~/.local/lib/tomo:.", 0);
CORD home = ENV_CORD("HOME");
autofmt = ENV_CORD("AUTOFMT");
@ -103,7 +104,7 @@ int main(int argc, char *argv[])
cflags = ENV_CORD("CFLAGS");
if (!cflags)
cflags = CORD_all(cconfig, " ", optimization, " -fPIC -ggdb -I./include -I'", home, "/.local/include/tomo' -D_DEFAULT_SOURCE");
cflags = CORD_all(cconfig, " ", optimization, " -fPIC -ggdb -I./include -I'", home, "/.local/include' -D_DEFAULT_SOURCE");
ldflags = CORD_all("-Wl,-rpath='$ORIGIN',-rpath='", home, "/.local/lib/tomo' -L. -L'", home, "/.local/lib/tomo'");
@ -174,6 +175,7 @@ int main(int argc, char *argv[])
// For shared objects, link up all the object files into one .so file:
if (mode == MODE_COMPILE_SHARED_OBJ) {
// Build a "libwhatever.h" header that loads all the headers:
const char *h_filename = heap_strf("lib%s.h", libname);
FILE *h_file = fopen(h_filename, "w");
if (!h_file)
@ -181,11 +183,21 @@ int main(int argc, char *argv[])
fputs("#pragma once\n", h_file);
for (int i = after_flags; i < argc; i++) {
const char *filename = argv[i];
fprintf(h_file, "#include <%s/%s.h>\n", libname, filename);
fprintf(h_file, "#include \"../../src/tomo/%s/%s.h\"\n", libname, filename);
}
if (fclose(h_file))
errx(1, "Failed to close file: %s", h_filename);
// Also output a "libwhatever.files" file that lists the .tm files it used:
const char *files_filename = heap_strf("lib%s.files", libname);
FILE *files_file = fopen(files_filename, "w");
if (!files_file)
errx(1, "Couldn't open file: %s", files_filename);
for (int i = after_flags; i < argc; i++)
fprintf(files_file, "%s\n", argv[i]);
if (fclose(files_file))
errx(1, "Failed to close file: %s", files_filename);
CORD outfile = CORD_all("lib", libname, ".so");
FILE *prog = CORD_RUN(cc, " ", cflags, " ", ldflags, " ", ldlibs, " -Wl,-soname=", outfile, " -shared ", object_files, " -o ", outfile);
status = pclose(prog);
@ -255,20 +267,19 @@ void build_file_dependency_graph(const char *filename, table_t *to_compile, tabl
use_path = Match(decl->value, Use)->raw_path;
}
if (!use_path) continue;
const char *import;
if (use_path[0] == '/' || strncmp(use_path, "~/", 2) == 0 || strncmp(use_path, "./", 2) == 0 || strncmp(use_path, "../", 3) == 0) {
import = resolve_path(use_path, filename, "");
if (!import) errx(1, "Couldn't resolve path: %s", use_path);
const char *path = resolve_path(use_path, filename, "");
const char *path = resolve_path(heap_strf("%s.tm", use_path), filename, "");
if (!path) errx(1, "Couldn't resolve import: %s", use_path);
if (Table$str_get(*to_compile, path))
continue;
Table$str_set(to_compile, path, path);
build_file_dependency_graph(path, to_compile, to_link);
} else {
import = resolve_path(use_path, filename, getenv("TOMO_IMPORT_PATH"));
const char *lib = heap_strf("-l%.*s", strlen(use_path)-strlen(".tm"), use_path);
const char *libfile = resolve_path(heap_strf("%s/lib%s.so", use_path, use_path), filename, getenv("TOMO_IMPORT_PATH"));
if (!libfile) errx(1, "Couldn't resolve path: %s", use_path);
const char *lib = heap_strf("-l%s", use_path);
Table$str_set(to_link, lib, lib);
}
build_file_dependency_graph(import, to_compile, to_link);
}
free(file_dir);
}

View File

@ -110,16 +110,51 @@ static env_t *load_module(env_t *env, ast_t *use_ast)
if (module_env)
return module_env;
const char *resolved_path = resolve_path(use->raw_path, use_ast->file->filename, getenv("TOMO_IMPORT_PATH"));
if (!resolved_path)
code_err(use_ast, "No such file exists: \"%s\"", use->raw_path);
if (strncmp(use->raw_path, "/", 1) == 0 || strncmp(use->raw_path, "./", 2) == 0
|| strncmp(use->raw_path, "../", 3) == 0 || strncmp(use->raw_path, "~/", 2) == 0) {
const char *path = heap_strf("%s.tm", use->raw_path);
const char *resolved_path = resolve_path(path, use_ast->file->filename, use_ast->file->filename);
if (!resolved_path)
code_err(use_ast, "No such file exists: \"%s\"", path);
file_t *f = load_file(resolved_path);
if (!f) errx(1, "No such file: %s", resolved_path);
file_t *f = load_file(resolved_path);
if (!f) errx(1, "No such file: %s", resolved_path);
ast_t *ast = parse_file(f, NULL);
if (!ast) errx(1, "Could not compile!");
return load_module_env(env, ast);
ast_t *ast = parse_file(f, NULL);
if (!ast) errx(1, "Could not compile!");
return load_module_env(env, ast);
} else {
const char *files_filename = heap_strf("%s/lib%s.files", use->raw_path, use->raw_path);
const char *resolved_path = resolve_path(files_filename, use_ast->file->filename, getenv("TOMO_IMPORT_PATH"));
if (!resolved_path)
code_err(use_ast, "No such library exists: \"lib%s.files\"", use->raw_path);
file_t *files_f = load_file(resolved_path);
if (!files_f) errx(1, "Couldn't open file: %s", resolved_path);
env = fresh_scope(env);
env->imports = new(table_t);
for (int64_t i = 1; i <= files_f->num_lines; i++) {
const char *line = get_line(files_f, i);
line = heap_strn(line, strcspn(line, "\r\n"));
if (!line || line[0] == '\0') continue;
const char *tm_path = resolve_path(line, resolved_path, ".");
if (!tm_path) errx(1, "Couldn't find library %s dependency: %s", use->raw_path, line);
file_t *tm_f = load_file(tm_path);
if (!tm_f) errx(1, "No such file: %s", tm_path);
ast_t *ast = parse_file(tm_f, NULL);
if (!ast) errx(1, "Could not compile!");
env_t *subenv = load_module_env(env, ast);
for (int64_t j = 0; j < subenv->locals->entries.length; j++) {
struct {
const char *name; binding_t *binding;
} *entry = subenv->locals->entries.data + j*subenv->locals->entries.stride;
set_binding(env, entry->name, entry->binding);
}
}
return env;
}
}
void prebind_statement(env_t *env, ast_t *statement)