aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2024-06-13 21:20:50 -0400
committerBruce Hill <bruce@bruce-hill.com>2024-06-13 21:20:50 -0400
commit81d55cacb7b86add20613510b8fa9da74e58bdca (patch)
tree0051267dda1a43265251bb6e0d36ebd26022bef5
parentdab2c399f1b574b598c908124acebaa06c80938a (diff)
Do dynamic library symbol prefixing using 'patchelf'
-rw-r--r--compile.c8
-rw-r--r--compile.h1
-rw-r--r--environment.c6
-rw-r--r--environment.h2
-rw-r--r--tomo.c86
-rw-r--r--typecheck.c15
6 files changed, 76 insertions, 42 deletions
diff --git a/compile.c b/compile.c
index a33a5f1e..324fdef3 100644
--- a/compile.c
+++ b/compile.c
@@ -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: {
diff --git a/compile.h b/compile.h
index 04715e54..10e7a36c 100644
--- a/compile.h
+++ b/compile.h
@@ -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);
diff --git a/tomo.c b/tomo.c
index 8c011f33..5ca4acb5 100644
--- a/tomo.c
+++ b/tomo.c
@@ -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");
}