Do dynamic library symbol prefixing using 'patchelf'
This commit is contained in:
parent
dab2c399f1
commit
81d55cacb7
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
86
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);
|
||||
|
||||
|
15
typecheck.c
15
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");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user