Do dynamic library symbol prefixing using 'patchelf'

This commit is contained in:
Bruce Hill 2024-06-13 21:20:50 -04:00
parent dab2c399f1
commit 81d55cacb7
6 changed files with 76 additions and 42 deletions

View File

@ -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: {

View File

@ -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);

View File

@ -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;
}

View File

@ -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);

86
tomo.c
View File

@ -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);

View File

@ -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");
}