diff options
| author | Bruce Hill <bruce@bruce-hill.com> | 2024-06-13 21:20:50 -0400 |
|---|---|---|
| committer | Bruce Hill <bruce@bruce-hill.com> | 2024-06-13 21:20:50 -0400 |
| commit | 81d55cacb7b86add20613510b8fa9da74e58bdca (patch) | |
| tree | 0051267dda1a43265251bb6e0d36ebd26022bef5 | |
| parent | dab2c399f1b574b598c908124acebaa06c80938a (diff) | |
Do dynamic library symbol prefixing using 'patchelf'
| -rw-r--r-- | compile.c | 8 | ||||
| -rw-r--r-- | compile.h | 1 | ||||
| -rw-r--r-- | environment.c | 6 | ||||
| -rw-r--r-- | environment.h | 2 | ||||
| -rw-r--r-- | tomo.c | 86 | ||||
| -rw-r--r-- | typecheck.c | 15 |
6 files changed, 76 insertions, 42 deletions
@@ -16,7 +16,6 @@ static CORD compile_to_pointer_depth(env_t *env, ast_t *ast, int64_t target_depth, bool allow_optional); static env_t *with_enum_scope(env_t *env, type_t *t); -static CORD compile_statement_header(env_t *env, ast_t *ast); CORD compile_type_ast(env_t *env, type_ast_t *t) { @@ -2276,10 +2275,9 @@ CORD compile_statement_header(env_t *env, ast_t *ast) } case FunctionDef: { auto fndef = Match(ast, FunctionDef); - bool is_private = Match(fndef->name, Var)->name[0] == '_'; + const char *decl_name = Match(fndef->name, Var)->name; + bool is_private = decl_name[0] == '_'; if (is_private) return CORD_EMPTY; - CORD name = compile(env, fndef->name); - CORD arg_signature = "("; for (arg_ast_t *arg = fndef->args; arg; arg = arg->next) { type_t *arg_type = get_arg_ast_type(env, arg); @@ -2290,7 +2288,7 @@ CORD compile_statement_header(env_t *env, ast_t *ast) type_t *ret_t = fndef->ret_type ? parse_type_ast(env, fndef->ret_type) : Type(VoidType); CORD ret_type_code = compile_type(env, ret_t); - CORD header = CORD_all(ret_type_code, " ", name, arg_signature, ";\n"); + CORD header = CORD_all(ret_type_code, " ", CORD_cat(env->file_prefix, decl_name), arg_signature, ";\n"); return header; } case Lambda: { @@ -19,6 +19,7 @@ CORD compile(env_t *env, ast_t *ast); void compile_namespace(env_t *env, const char *ns_name, ast_t *block); CORD compile_namespace_headers(env_t *env, const char *ns_name, ast_t *block); CORD compile_statement(env_t *env, ast_t *ast); +CORD compile_statement_header(env_t *env, ast_t *ast); CORD compile_type_info(env_t *env, type_t *t); CORD compile_cli_arg_call(env_t *env, CORD fn_name, type_t *fn_type); diff --git a/environment.c b/environment.c index 38c6f104..c71699e1 100644 --- a/environment.c +++ b/environment.c @@ -235,14 +235,14 @@ env_t *new_compilation_unit(void) return env; } -env_t *load_module_env(env_t *env, ast_t *ast) +env_t *load_module_env(env_t *env, const char *prefix, ast_t *ast) { const char *name = file_base_name(ast->file->filename); env_t *cached = Table$str_get(*env->imports, name); if (cached) return cached; env = fresh_scope(env); env->code = new(compilation_unit_t); - env->file_prefix = heap_strf("%s$", name); + env->file_prefix = prefix; Table$str_set(env->imports, name, env); for (ast_list_t *stmt = Match(ast, Block)->statements; stmt; stmt = stmt->next) @@ -251,7 +251,7 @@ env_t *load_module_env(env_t *env, ast_t *ast) for (ast_list_t *stmt = Match(ast, Block)->statements; stmt; stmt = stmt->next) { // Hack: make sure global variables are bound as foo$var: if (stmt->ast->tag == Declare && Match(Match(stmt->ast, Declare)->var, Var)->name[0] != '_') - env->scope_prefix = heap_strf("%s$", name); + env->scope_prefix = prefix; bind_statement(env, stmt->ast); env->scope_prefix = NULL; } diff --git a/environment.h b/environment.h index f2229df8..6cc083ef 100644 --- a/environment.h +++ b/environment.h @@ -45,7 +45,7 @@ typedef struct { } binding_t; env_t *new_compilation_unit(void); -env_t *load_module_env(env_t *env, ast_t *ast); +env_t *load_module_env(env_t *env, const char *prefix, ast_t *ast); env_t *global_scope(env_t *env); env_t *fresh_scope(env_t *env); env_t *for_scope(env_t *env, ast_t *ast); @@ -177,16 +177,25 @@ int main(int argc, char *argv[]) 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) - errx(1, "Couldn't open file: %s", h_filename); - fputs("#pragma once\n", h_file); + FILE *header_prog = CORD_RUN(autofmt ? autofmt : "cat", " 2>/dev/null >", h_filename); + fputs("#pragma once\n", header_prog); for (int i = after_flags; i < argc; i++) { const char *filename = argv[i]; - fprintf(h_file, "#include \"../../src/tomo/%s/%s.h\"\n", libname, filename); + file_t *f = load_file(filename); + if (!f) errx(1, "No such file: %s", filename); + ast_t *ast = parse_file(f, NULL); + if (!ast) errx(1, "Could not parse %s", f); + env->file_prefix = heap_strf("%s$%s$", libname, file_base_name(filename)); + + for (ast_list_t *stmt = Match(ast, Block)->statements; stmt; stmt = stmt->next) { + if (stmt->ast->tag == Import || (stmt->ast->tag == Declare && Match(stmt->ast, Declare)->value->tag == Import)) + continue; + CORD h = compile_statement_header(env, stmt->ast); + if (h) CORD_put(h, header_prog); + } } - if (fclose(h_file)) - errx(1, "Failed to close file: %s", h_filename); + if (pclose(header_prog) == -1) + errx(1, "Failed to run autoformat program on header file: %s", autofmt); // Also output a "libwhatever.files" file that lists the .tm files it used: const char *files_filename = heap_strf("lib%s.files", libname); @@ -198,14 +207,37 @@ int main(int argc, char *argv[]) if (fclose(files_file)) errx(1, "Failed to close file: %s", files_filename); + // Build up a list of symbol renamings: + unlink("symbol_renames.txt"); + FILE *prog; + for (int i = after_flags; i < argc; i++) { + prog = CORD_RUN("nm -U -fjust-symbols ", argv[i], ".o | sed 's/.*/\\0 ", libname, "$\\0/' >>symbol_renames.txt"); + status = pclose(prog); + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) + errx(WEXITSTATUS(status), "Failed to create symbol rename table with `nm` and `sed`"); + } + CORD outfile = CORD_all("lib", libname, ".so"); - FILE *prog = CORD_RUN(cc, " ", cflags, " ", ldflags, " ", ldlibs, " -Wl,-soname=", outfile, " -shared ", object_files, " -o ", outfile); + prog = CORD_RUN(cc, " ", cflags, " ", ldflags, " ", ldlibs, " -Wl,-soname=", outfile, " -shared ", object_files, " -o ", outfile); status = pclose(prog); if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) - return WEXITSTATUS(status); + errx(WEXITSTATUS(status), "Failed to compile shared library file"); if (verbose) CORD_printf("Compiled to %r\n", outfile); + prog = CORD_RUN("objcopy --redefine-syms=symbol_renames.txt lib", libname, ".so"); + status = pclose(prog); + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) + errx(WEXITSTATUS(status), "Failed to run `objcopy` to add library prefix to symbols"); + + prog = CORD_RUN("patchelf --rename-dynamic-symbols symbol_renames.txt lib", libname, ".so"); + status = pclose(prog); + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) + errx(WEXITSTATUS(status), "Failed to run `patchelf` to rename dynamic symbols with library prefix"); + + if (verbose) + CORD_printf("Successfully renamed symbols with library prefix!\n"); + printf("Do you want to install your library? [Y/n] "); fflush(stdout); switch (getchar()) { @@ -218,23 +250,23 @@ int main(int argc, char *argv[]) default: break; } return 0; + } else { + const char *filename = argv[after_flags]; + int executable_status = compile_executable(env, filename, object_files); + if (mode == MODE_COMPILE_EXE || executable_status != 0) + return executable_status; + + char *exe_name = heap_strn(filename, strlen(filename) - strlen(".tm")); + int num_args = argc - after_flags - 1; + char *prog_args[num_args + 2]; + prog_args[0] = exe_name; + for (int i = 0; i < num_args; i++) + prog_args[i+1] = argv[after_flags+1+i]; + prog_args[num_args+1] = NULL; + execv(exe_name, prog_args); + + errx(1, "Failed to run compiled program"); } - - const char *filename = argv[after_flags]; - int executable_status = compile_executable(env, filename, object_files); - if (mode == MODE_COMPILE_EXE || executable_status != 0) - return executable_status; - - char *exe_name = heap_strn(filename, strlen(filename) - strlen(".tm")); - int num_args = argc - after_flags - 1; - char *prog_args[num_args + 2]; - prog_args[0] = exe_name; - for (int i = 0; i < num_args; i++) - prog_args[i+1] = argv[after_flags+1+i]; - prog_args[num_args+1] = NULL; - execv(exe_name, prog_args); - - errx(1, "Failed to run compiled program"); } void build_file_dependency_graph(const char *filename, table_t *to_compile, table_t *to_link) @@ -307,7 +339,7 @@ int transpile_header(env_t *base_env, const char *filename, bool force_retranspi if (!ast) errx(1, "Could not parse %s", f); - env_t *module_env = load_module_env(base_env, ast); + env_t *module_env = load_module_env(base_env, heap_strf("%s$", file_base_name(filename)), ast); CORD h_code = compile_header(module_env, ast); @@ -351,7 +383,7 @@ int transpile_code(env_t *base_env, const char *filename, bool force_retranspile if (!ast) errx(1, "Could not parse %s", f); - env_t *module_env = load_module_env(base_env, ast); + env_t *module_env = load_module_env(base_env, heap_strf("%s$", file_base_name(filename)), ast); CORD c_code = compile_file(module_env, ast); diff --git a/typecheck.c b/typecheck.c index 121135eb..a92c0060 100644 --- a/typecheck.c +++ b/typecheck.c @@ -121,7 +121,7 @@ static env_t *load_module(env_t *env, ast_t *module_ast) ast_t *ast = parse_file(f, NULL); if (!ast) errx(1, "Could not compile!"); - return load_module_env(env, ast); + return load_module_env(env, heap_strf("%s$", name), ast); } else if (module_ast->tag == Use) { const char *name = Match(module_ast, Use)->name; const char *files_filename = heap_strf("%s/lib%s.files", name, name); @@ -131,8 +131,7 @@ static env_t *load_module(env_t *env, ast_t *module_ast) 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); + env_t *ret_env = fresh_scope(env); 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")); @@ -145,15 +144,19 @@ static env_t *load_module(env_t *env, ast_t *module_ast) ast_t *ast = parse_file(tm_f, NULL); if (!ast) errx(1, "Could not compile!"); - env_t *subenv = load_module_env(env, ast); + const char *prefix = file_base_name(line); + env_t *tmp_env = fresh_scope(env); + tmp_env->file_prefix = heap_strf("%s$", name); + tmp_env->imports = new(table_t); + env_t *subenv = load_module_env(tmp_env, heap_strf("%s$%s$", name, prefix), 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); + set_binding(ret_env, entry->name, entry->binding); } } - return env; + return ret_env; } else { code_err(module_ast, "This is not a module import"); } |
