From 5757a5023c4c4b252c6a0440e14e8efacaa2668b Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Thu, 13 Jun 2024 12:59:19 -0400 Subject: [PATCH] Support loading shared libraries --- compile.c | 6 +++--- parse.c | 2 +- tomo.c | 29 ++++++++++++++++++++--------- typecheck.c | 51 +++++++++++++++++++++++++++++++++++++++++++-------- 4 files changed, 67 insertions(+), 21 deletions(-) diff --git a/compile.c b/compile.c index 1cf6e5e..e558f3c 100644 --- a/compile.c +++ b/compile.c @@ -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 \n"); } } default: diff --git a/parse.c b/parse.c index c6d8cec..c98bacd 100644 --- a/parse.c +++ b/parse.c @@ -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); diff --git a/tomo.c b/tomo.c index 45a1733..667a497 100644 --- a/tomo.c +++ b/tomo.c @@ -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); } diff --git a/typecheck.c b/typecheck.c index d7c4930..3b260fe 100644 --- a/typecheck.c +++ b/typecheck.c @@ -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)