2024-03-18 09:47:07 -07:00
|
|
|
// The main program that runs compilation
|
2024-03-24 13:26:07 -07:00
|
|
|
#include <ctype.h>
|
2024-02-04 12:23:59 -08:00
|
|
|
#include <gc.h>
|
|
|
|
#include <gc/cord.h>
|
2024-03-20 23:27:43 -07:00
|
|
|
#include <libgen.h>
|
2024-02-07 21:52:18 -08:00
|
|
|
#include <printf.h>
|
2024-03-24 13:26:07 -07:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
2024-03-20 22:33:44 -07:00
|
|
|
#include <sys/stat.h>
|
2024-02-04 12:23:59 -08:00
|
|
|
|
|
|
|
#include "ast.h"
|
2024-03-20 22:33:44 -07:00
|
|
|
#include "builtins/array.h"
|
|
|
|
#include "builtins/datatypes.h"
|
2024-03-03 15:15:45 -08:00
|
|
|
#include "builtins/text.h"
|
2024-02-04 12:23:59 -08:00
|
|
|
#include "compile.h"
|
2024-02-17 20:23:37 -08:00
|
|
|
#include "parse.h"
|
2024-03-30 09:14:24 -07:00
|
|
|
#include "repl.h"
|
2024-02-17 17:07:04 -08:00
|
|
|
#include "typecheck.h"
|
2024-02-07 21:52:18 -08:00
|
|
|
#include "types.h"
|
2024-02-04 12:23:59 -08:00
|
|
|
|
2024-05-27 14:25:13 -07:00
|
|
|
typedef enum { MODE_TRANSPILE = 0, MODE_COMPILE_OBJ = 1, MODE_COMPILE_SHARED_OBJ = 2, MODE_COMPILE_EXE = 3, MODE_RUN = 4 } mode_e;
|
2024-03-20 22:33:44 -07:00
|
|
|
|
|
|
|
static bool verbose = false;
|
2024-05-27 21:30:09 -07:00
|
|
|
static bool show_codegen = false;
|
2024-05-27 13:25:08 -07:00
|
|
|
static const char *autofmt, *cconfig, *cflags, *objfiles, *ldlibs, *ldflags, *cc;
|
2024-03-03 11:36:09 -08:00
|
|
|
|
2024-05-27 21:30:09 -07:00
|
|
|
static array_t get_file_dependencies(const char *filename, array_t *object_files);
|
2024-04-20 11:55:27 -07:00
|
|
|
static int transpile(const char *filename, bool force_retranspile, module_code_t *module_code);
|
2024-05-27 14:25:13 -07:00
|
|
|
static int compile_object_file(const char *filename, bool force_recompile, bool shared);
|
2024-05-27 21:30:09 -07:00
|
|
|
static int compile_executable(const char *filename, array_t object_files, module_code_t *module_code);
|
2024-03-20 23:27:43 -07:00
|
|
|
|
2024-02-04 12:23:59 -08:00
|
|
|
int main(int argc, char *argv[])
|
|
|
|
{
|
2024-03-03 11:36:09 -08:00
|
|
|
mode_e mode = MODE_RUN;
|
|
|
|
const char *filename = NULL;
|
2024-04-12 10:09:31 -07:00
|
|
|
int program_arg_index = argc + 1;
|
2024-03-03 11:36:09 -08:00
|
|
|
for (int i = 1; i < argc; i++) {
|
|
|
|
if (streq(argv[i], "-t")) {
|
|
|
|
mode = MODE_TRANSPILE;
|
2024-03-06 21:30:52 -08:00
|
|
|
} else if (streq(argv[i], "-c")) {
|
2024-04-12 11:36:25 -07:00
|
|
|
mode = MODE_COMPILE_OBJ;
|
2024-05-27 14:25:13 -07:00
|
|
|
} else if (streq(argv[i], "-s")) {
|
|
|
|
mode = MODE_COMPILE_SHARED_OBJ;
|
2024-04-12 11:36:25 -07:00
|
|
|
} else if (streq(argv[i], "-r")) {
|
|
|
|
mode = MODE_RUN;
|
|
|
|
} else if (streq(argv[i], "-e")) {
|
|
|
|
mode = MODE_COMPILE_EXE;
|
|
|
|
} else if (streq(argv[i], "-h") || streq(argv[i], "--help")) {
|
|
|
|
printf("Usage: %s [[-t|-c|-e|-r] [option=value]* file.tm [args...]]\n", argv[0]);
|
|
|
|
return 0;
|
2024-03-24 13:26:07 -07:00
|
|
|
} else if (strchr(argv[i], '=')) {
|
|
|
|
while (argv[i][0] == '-')
|
|
|
|
++argv[i];
|
|
|
|
char *eq = strchr(argv[i], '=');
|
|
|
|
*eq = '\0';
|
|
|
|
for (char *p = argv[i]; *p; p++)
|
|
|
|
*p = toupper(*p);
|
|
|
|
setenv(argv[i], eq + 1, 1);
|
2024-03-03 11:36:09 -08:00
|
|
|
} else {
|
|
|
|
filename = argv[i];
|
2024-04-12 10:09:31 -07:00
|
|
|
program_arg_index = i + 1;
|
2024-03-03 11:36:09 -08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-07 21:52:18 -08:00
|
|
|
// register_printf_modifier(L"p");
|
|
|
|
if (register_printf_specifier('T', printf_type, printf_pointer_size))
|
|
|
|
errx(1, "Couldn't set printf specifier");
|
|
|
|
if (register_printf_specifier('W', printf_ast, printf_pointer_size))
|
|
|
|
errx(1, "Couldn't set printf specifier");
|
|
|
|
|
2024-05-27 21:30:09 -07:00
|
|
|
setenv("TOMO_IMPORT_PATH", "~/.local/tomo/src:.", 0);
|
|
|
|
|
2024-03-20 22:33:44 -07:00
|
|
|
autofmt = getenv("AUTOFMT");
|
2024-02-13 20:03:58 -08:00
|
|
|
if (!autofmt) autofmt = "indent -kr -l100 -nbbo -nut -sob";
|
2024-03-09 21:42:17 -08:00
|
|
|
if (!autofmt[0]) autofmt = "cat";
|
2024-02-04 15:04:41 -08:00
|
|
|
|
2024-05-27 21:30:09 -07:00
|
|
|
verbose = (getenv("VERBOSE") && (streq(getenv("VERBOSE"), "1") || streq(getenv("VERBOSE"), "2")));
|
|
|
|
show_codegen = (getenv("VERBOSE") && streq(getenv("VERBOSE"), "2"));
|
2024-03-20 22:33:44 -07:00
|
|
|
|
2024-03-30 09:14:24 -07:00
|
|
|
if (filename == NULL) {
|
|
|
|
repl();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2024-05-01 10:25:19 -07:00
|
|
|
if (strlen(filename) < strlen(".tm") + 1 || strncmp(filename + strlen(filename) - strlen(".tm"), ".tm", strlen(".tm")) != 0)
|
|
|
|
errx(1, "Not a valid .tm file: %s", filename);
|
|
|
|
|
2024-03-20 22:33:44 -07:00
|
|
|
cconfig = getenv("CCONFIG");
|
|
|
|
if (!cconfig)
|
2024-04-13 12:20:42 -07:00
|
|
|
cconfig = "-std=c11 -fdollars-in-identifiers -fsanitize=signed-integer-overflow -fno-sanitize-recover"
|
|
|
|
" -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -D_DEFAULT_SOURCE";
|
2024-03-20 22:33:44 -07:00
|
|
|
|
2024-03-24 13:19:59 -07:00
|
|
|
const char *optimization = getenv("O");
|
2024-03-24 13:26:07 -07:00
|
|
|
if (!optimization || !optimization[0]) optimization = "-O1";
|
|
|
|
else optimization = heap_strf("-O%s", optimization);
|
2024-03-24 13:19:59 -07:00
|
|
|
|
2024-05-27 13:25:08 -07:00
|
|
|
objfiles = getenv("OBJFILES");
|
|
|
|
if (!objfiles)
|
|
|
|
objfiles = "";
|
|
|
|
|
2024-03-20 22:33:44 -07:00
|
|
|
cflags = getenv("CFLAGS");
|
|
|
|
if (!cflags)
|
2024-05-27 21:30:09 -07:00
|
|
|
cflags = heap_strf("%s %s -fPIC -ggdb -I./include -I%s/.local/tomo/include -D_DEFAULT_SOURCE", cconfig, optimization, getenv("HOME"));
|
2024-03-20 22:33:44 -07:00
|
|
|
|
2024-05-27 21:30:09 -07:00
|
|
|
ldflags = heap_strf("-Wl,-rpath,'$ORIGIN',-rpath,'%s/.local/tomo/lib' -L. -L%s/.local/tomo/lib", getenv("HOME"), getenv("HOME"));
|
2024-05-01 10:25:19 -07:00
|
|
|
|
|
|
|
ldlibs = "-lgc -lcord -lm -ltomo";
|
2024-03-20 22:33:44 -07:00
|
|
|
if (getenv("LDLIBS"))
|
|
|
|
ldlibs = heap_strf("%s %s", ldlibs, getenv("LDLIBS"));
|
|
|
|
|
|
|
|
cc = getenv("CC");
|
|
|
|
if (!cc) cc = "tcc";
|
|
|
|
|
2024-05-27 21:30:09 -07:00
|
|
|
array_t object_files = {};
|
|
|
|
const char *my_obj = heap_strf("%s.o", resolve_path(filename, ".", "."));
|
|
|
|
Array$insert(&object_files, &my_obj, 0, $ArrayInfo(&$Text));
|
|
|
|
array_t file_deps = get_file_dependencies(filename, &object_files);
|
|
|
|
|
|
|
|
module_code_t module_code = {};
|
2024-04-20 11:55:27 -07:00
|
|
|
int transpile_status = transpile(filename, true, &module_code);
|
2024-05-27 21:30:09 -07:00
|
|
|
if (transpile_status != 0) return transpile_status;
|
|
|
|
|
|
|
|
for (int64_t i = 0; i < file_deps.length; i++) {
|
|
|
|
const char *dep = *(char**)(file_deps.data + i*file_deps.stride);
|
|
|
|
module_code_t _ = {};
|
|
|
|
transpile_status = transpile(dep, false, &_);
|
|
|
|
if (transpile_status != 0) return transpile_status;
|
|
|
|
}
|
2024-03-20 22:33:44 -07:00
|
|
|
|
2024-03-20 23:27:43 -07:00
|
|
|
for (int64_t i = 0; i < file_deps.length; i++) {
|
|
|
|
const char *dep = *(char**)(file_deps.data + i*file_deps.stride);
|
2024-05-27 21:30:09 -07:00
|
|
|
int compile_status = compile_object_file(dep, false, false);
|
2024-03-22 10:47:30 -07:00
|
|
|
if (compile_status != 0) return compile_status;
|
2024-03-20 23:27:43 -07:00
|
|
|
}
|
2024-03-20 22:33:44 -07:00
|
|
|
|
2024-05-27 21:30:09 -07:00
|
|
|
if (mode == MODE_COMPILE_OBJ)
|
2024-04-12 11:36:25 -07:00
|
|
|
return 0;
|
|
|
|
|
2024-05-27 21:30:09 -07:00
|
|
|
if (mode == MODE_COMPILE_SHARED_OBJ) {
|
|
|
|
printf("Do you want to install your library? [Y/n] ");
|
|
|
|
fflush(stdout);
|
|
|
|
switch (getchar()) {
|
|
|
|
case 'y': case 'Y': case '\n':
|
|
|
|
system("mkdir -p ~/.local/tomo/lib ~/.local/tomo/src ~/.local/tomo/include");
|
|
|
|
system(heap_strf("cp -v lib%s.so ~/.local/tomo/lib/", file_base_name(filename)));
|
|
|
|
system(heap_strf("cp -v %s %s.c ~/.local/tomo/src/", filename, filename));
|
|
|
|
system(heap_strf("cp -v %s.h ~/.local/tomo/include/", filename));
|
|
|
|
default: break;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2024-04-20 11:55:27 -07:00
|
|
|
int executable_status = compile_executable(filename, object_files, &module_code);
|
2024-04-12 11:36:25 -07:00
|
|
|
if (mode == MODE_COMPILE_EXE || executable_status != 0)
|
2024-04-12 10:09:31 -07:00
|
|
|
return executable_status;
|
|
|
|
|
2024-05-01 10:25:19 -07:00
|
|
|
char *exe_name = heap_strn(filename, strlen(filename) - strlen(".tm"));
|
2024-04-12 11:36:25 -07:00
|
|
|
int num_args = argc - program_arg_index;
|
|
|
|
char *prog_args[num_args + 2];
|
|
|
|
prog_args[0] = exe_name;
|
|
|
|
for (int i = 0; i < num_args; i++)
|
|
|
|
prog_args[i+1] = argv[program_arg_index+i];
|
|
|
|
prog_args[num_args+1] = NULL;
|
|
|
|
execv(exe_name, prog_args);
|
2024-04-12 10:09:31 -07:00
|
|
|
|
2024-05-01 10:25:19 -07:00
|
|
|
errx(1, "Failed to run compiled program");
|
2024-03-20 22:33:44 -07:00
|
|
|
}
|
|
|
|
|
2024-05-27 21:30:09 -07:00
|
|
|
static void build_file_dependency_graph(const char *filename, table_t *dependencies, array_t *object_files)
|
2024-03-20 22:33:44 -07:00
|
|
|
{
|
|
|
|
size_t len = strlen(filename);
|
2024-05-27 21:30:09 -07:00
|
|
|
assert(strncmp(filename + len - 3, ".tm", 3) == 0);
|
|
|
|
|
|
|
|
if (Table$str_get(*dependencies, filename))
|
2024-03-20 22:33:44 -07:00
|
|
|
return;
|
|
|
|
|
|
|
|
array_t *deps = new(array_t);
|
2024-05-27 21:30:09 -07:00
|
|
|
Array$insert(deps, &filename, 0, $ArrayInfo(&$Text));
|
|
|
|
Table$str_set(dependencies, filename, deps);
|
2024-03-20 22:33:44 -07:00
|
|
|
|
2024-05-27 21:30:09 -07:00
|
|
|
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);
|
2024-03-20 23:27:43 -07:00
|
|
|
|
|
|
|
char *file_dir = realpath(filename, NULL);
|
|
|
|
dirname(file_dir);
|
2024-05-27 21:30:09 -07:00
|
|
|
for (ast_list_t *stmt = Match(ast, Block)->statements; stmt; stmt = stmt->next) {
|
|
|
|
const char *use_path = NULL;
|
|
|
|
if (stmt->ast->tag == Use) {
|
|
|
|
use_path = Match(stmt->ast, Use)->raw_path;
|
|
|
|
} else if (stmt->ast->tag == Declare) {
|
|
|
|
auto decl = Match(stmt->ast, Declare);
|
|
|
|
if (decl->value->tag == Use)
|
|
|
|
use_path = Match(decl->value, Use)->raw_path;
|
|
|
|
}
|
|
|
|
if (!use_path) continue;
|
|
|
|
const char *import, *obj_file;
|
|
|
|
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, "");
|
|
|
|
obj_file = heap_strf("%s.o", resolve_path(use_path, filename, ""));
|
|
|
|
} else {
|
|
|
|
import = resolve_path(use_path, filename, getenv("TOMO_IMPORT_PATH"));
|
|
|
|
obj_file = heap_strf("-l%.*s", strlen(use_path)-3, use_path);
|
2024-03-20 22:33:44 -07:00
|
|
|
}
|
2024-05-27 21:30:09 -07:00
|
|
|
Array$insert(deps, &import, 0, $ArrayInfo(&$Text));
|
|
|
|
Array$insert(object_files, &obj_file, 0, $ArrayInfo(&$Text));
|
|
|
|
build_file_dependency_graph(import, dependencies, object_files);
|
2024-03-20 22:33:44 -07:00
|
|
|
}
|
2024-03-20 23:27:43 -07:00
|
|
|
free(file_dir);
|
|
|
|
}
|
|
|
|
|
2024-05-27 21:30:09 -07:00
|
|
|
array_t get_file_dependencies(const char *filename, array_t *object_files)
|
2024-03-20 23:27:43 -07:00
|
|
|
{
|
|
|
|
const char *resolved = resolve_path(filename, ".", ".");
|
|
|
|
|
|
|
|
table_t file_dependencies = {};
|
2024-05-27 21:30:09 -07:00
|
|
|
build_file_dependency_graph(resolved, &file_dependencies, object_files);
|
2024-03-20 23:27:43 -07:00
|
|
|
table_t dependency_set = {};
|
|
|
|
|
|
|
|
const TypeInfo unit = {.size=0, .align=0, .tag=CustomInfo};
|
|
|
|
const TypeInfo info = {.size=sizeof(table_t), .align=__alignof__(table_t),
|
2024-03-29 09:54:31 -07:00
|
|
|
.tag=TableInfo, .TableInfo.key=&$Text, .TableInfo.value=&unit};
|
2024-03-20 23:27:43 -07:00
|
|
|
|
2024-03-29 09:54:31 -07:00
|
|
|
for (int64_t i = 1; i <= Table$length(file_dependencies); i++) {
|
|
|
|
struct { const char *name; array_t *deps; } *entry = Table$entry(file_dependencies, i);
|
2024-03-20 23:27:43 -07:00
|
|
|
for (int64_t j = 0; j < entry->deps->length; j++) {
|
|
|
|
const char *dep = *(char**)(entry->deps->data + j*entry->deps->stride);
|
2024-03-29 09:54:31 -07:00
|
|
|
Table$set(&dependency_set, &dep, &dep, &info);
|
2024-03-20 23:27:43 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return dependency_set.entries;
|
2024-03-20 22:33:44 -07:00
|
|
|
}
|
|
|
|
|
2024-05-27 21:30:09 -07:00
|
|
|
static bool is_stale(const char *filename, const char *relative_to)
|
2024-03-20 22:33:44 -07:00
|
|
|
{
|
|
|
|
struct stat target_stat;
|
|
|
|
if (stat(filename, &target_stat))
|
|
|
|
return true;
|
|
|
|
struct stat relative_to_stat;
|
2024-03-20 23:43:15 -07:00
|
|
|
if (stat(relative_to, &relative_to_stat))
|
2024-05-27 21:30:09 -07:00
|
|
|
errx(1, "File doesn't exist: %s", relative_to);
|
2024-03-20 22:33:44 -07:00
|
|
|
return target_stat.st_mtime < relative_to_stat.st_mtime;
|
|
|
|
}
|
|
|
|
|
2024-04-20 11:55:27 -07:00
|
|
|
int transpile(const char *filename, bool force_retranspile, module_code_t *module_code)
|
2024-03-20 22:33:44 -07:00
|
|
|
{
|
|
|
|
const char *tm_file = filename;
|
2024-03-26 10:20:47 -07:00
|
|
|
const char *c_filename = heap_strf("%s.c", tm_file);
|
|
|
|
const char *h_filename = heap_strf("%s.h", tm_file);
|
2024-05-27 21:30:09 -07:00
|
|
|
if (!force_retranspile && !is_stale(c_filename, tm_file) && !is_stale(h_filename, tm_file)) {
|
2024-03-20 22:33:44 -07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2024-03-03 11:36:09 -08:00
|
|
|
file_t *f = load_file(filename);
|
|
|
|
if (!f)
|
|
|
|
errx(1, "No such file: %s", filename);
|
2024-02-04 15:04:41 -08:00
|
|
|
|
2024-02-04 12:23:59 -08:00
|
|
|
ast_t *ast = parse_file(f, NULL);
|
2024-02-04 15:04:41 -08:00
|
|
|
if (!ast)
|
2024-05-27 21:30:09 -07:00
|
|
|
errx(1, "Could not parse %s", f);
|
2024-02-04 15:04:41 -08:00
|
|
|
|
2024-05-27 21:30:09 -07:00
|
|
|
if (show_codegen) {
|
2024-03-03 11:36:09 -08:00
|
|
|
FILE *out = popen(heap_strf("bat -P --file-name='%s'", filename), "w");
|
2024-02-10 12:36:35 -08:00
|
|
|
fputs(f->text, out);
|
2024-03-03 11:36:09 -08:00
|
|
|
pclose(out);
|
2024-02-10 12:36:35 -08:00
|
|
|
}
|
|
|
|
|
2024-05-27 21:30:09 -07:00
|
|
|
if (show_codegen) {
|
2024-03-24 16:04:57 -07:00
|
|
|
FILE *out = popen("xmllint --format - | bat -P --file-name=AST", "w");
|
|
|
|
CORD_put(ast_to_xml(ast), out);
|
2024-03-03 11:36:09 -08:00
|
|
|
pclose(out);
|
2024-02-04 15:04:41 -08:00
|
|
|
}
|
|
|
|
|
2024-04-20 11:55:27 -07:00
|
|
|
*module_code = compile_file(ast);
|
2024-02-04 15:04:41 -08:00
|
|
|
|
2024-03-26 10:20:47 -07:00
|
|
|
FILE *h_file = fopen(h_filename, "w");
|
|
|
|
if (!h_file)
|
|
|
|
errx(1, "Couldn't open file: %s", h_filename);
|
|
|
|
CORD_put("#pragma once\n", h_file);
|
2024-04-20 11:55:27 -07:00
|
|
|
CORD_put(module_code->header, h_file);
|
2024-03-26 10:20:47 -07:00
|
|
|
if (fclose(h_file))
|
|
|
|
errx(1, "Failed to close file: %s", h_filename);
|
|
|
|
if (verbose)
|
|
|
|
printf("Transpiled to %s\n", h_filename);
|
|
|
|
|
|
|
|
if (autofmt && autofmt[0]) {
|
|
|
|
FILE *prog = popen(heap_strf("%s %s -o %s >/dev/null 2>/dev/null", autofmt, h_filename, h_filename), "w");
|
|
|
|
pclose(prog);
|
2024-03-20 23:29:46 -07:00
|
|
|
}
|
2024-02-13 22:24:04 -08:00
|
|
|
|
2024-03-26 10:20:47 -07:00
|
|
|
FILE *c_file = fopen(c_filename, "w");
|
|
|
|
if (!c_file)
|
|
|
|
errx(1, "Couldn't open file: %s", c_filename);
|
2024-05-25 10:04:59 -07:00
|
|
|
CORD_put(CORD_all(
|
|
|
|
"#include <tomo/tomo.h>\n"
|
|
|
|
"#include \"", module_code->module_name, ".tm.h\"\n\n",
|
|
|
|
module_code->c_file), c_file);
|
2024-03-26 10:20:47 -07:00
|
|
|
if (fclose(c_file))
|
|
|
|
errx(1, "Failed to close file: %s", c_filename);
|
|
|
|
if (verbose)
|
|
|
|
printf("Transpiled to %s\n", c_filename);
|
|
|
|
|
|
|
|
if (autofmt && autofmt[0]) {
|
|
|
|
FILE *prog = popen(heap_strf("%s %s -o %s >/dev/null 2>/dev/null", autofmt, c_filename, c_filename), "w");
|
|
|
|
pclose(prog);
|
2024-03-20 23:29:46 -07:00
|
|
|
}
|
2024-03-24 13:11:11 -07:00
|
|
|
|
2024-05-27 21:30:09 -07:00
|
|
|
if (show_codegen) {
|
2024-03-26 10:20:47 -07:00
|
|
|
FILE *out = popen(heap_strf("bat -P %s %s", h_filename, c_filename), "w");
|
2024-03-24 13:11:11 -07:00
|
|
|
pclose(out);
|
|
|
|
}
|
|
|
|
|
2024-03-26 10:20:47 -07:00
|
|
|
return 0;
|
2024-03-20 22:33:44 -07:00
|
|
|
}
|
2024-03-03 11:36:09 -08:00
|
|
|
|
2024-05-27 14:25:13 -07:00
|
|
|
int compile_object_file(const char *filename, bool force_recompile, bool shared)
|
2024-03-20 22:33:44 -07:00
|
|
|
{
|
|
|
|
const char *obj_file = heap_strf("%s.o", filename);
|
2024-05-27 21:30:09 -07:00
|
|
|
if (!force_recompile && !is_stale(obj_file, filename)
|
|
|
|
&& !is_stale(obj_file, heap_strf("%s.c", filename))
|
|
|
|
&& !is_stale(obj_file, heap_strf("%s.h", filename))) {
|
2024-03-20 22:33:44 -07:00
|
|
|
return 0;
|
2024-03-06 21:30:52 -08:00
|
|
|
}
|
2024-05-27 21:30:09 -07:00
|
|
|
const char *base = file_base_name(filename);
|
2024-05-27 14:25:13 -07:00
|
|
|
const char *outfile = shared ? heap_strf("lib%s.so", base) : heap_strf("%s.o", filename);
|
|
|
|
const char *cmd = shared ?
|
|
|
|
heap_strf("%s %s %s %s %s -Wl,-soname,lib%s.so -shared %s.c -o %s", cc, cflags, ldflags, ldlibs, objfiles, base, filename, outfile)
|
|
|
|
: heap_strf("%s %s -c %s.c -o %s", cc, cflags, filename, outfile);
|
2024-03-20 22:33:44 -07:00
|
|
|
if (verbose)
|
|
|
|
printf("Running: %s\n", cmd);
|
|
|
|
FILE *prog = popen(cmd, "w");
|
|
|
|
int status = pclose(prog);
|
2024-03-20 23:29:46 -07:00
|
|
|
if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
|
|
|
|
if (verbose)
|
2024-05-27 14:25:13 -07:00
|
|
|
printf("Compiled to %s\n", outfile);
|
2024-03-20 23:29:46 -07:00
|
|
|
}
|
2024-03-20 22:33:44 -07:00
|
|
|
return WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE;
|
|
|
|
}
|
2024-03-03 11:45:36 -08:00
|
|
|
|
2024-05-27 21:30:09 -07:00
|
|
|
int compile_executable(const char *filename, array_t object_files, module_code_t *module_code)
|
2024-03-20 22:33:44 -07:00
|
|
|
{
|
2024-05-01 10:25:19 -07:00
|
|
|
const char *bin_name = heap_strn(filename, strlen(filename) - strlen(".tm"));
|
2024-05-27 21:30:09 -07:00
|
|
|
const char *run = heap_strf("%s | %s %s %s %s %s %s -x c - -o %s",
|
|
|
|
autofmt, cc, cflags, ldflags, ldlibs, objfiles, CORD_to_const_char_star(Text$join(" ", object_files)), bin_name);
|
2024-03-20 22:33:44 -07:00
|
|
|
if (verbose)
|
|
|
|
printf("%s\n", run);
|
|
|
|
FILE *runner = popen(run, "w");
|
|
|
|
|
2024-04-20 11:55:27 -07:00
|
|
|
binding_t *main_binding = get_binding(module_code->env, "main");
|
2024-03-20 22:33:44 -07:00
|
|
|
CORD program = CORD_all(
|
2024-03-20 23:27:43 -07:00
|
|
|
"#include <tomo/tomo.h>\n"
|
2024-03-20 22:33:44 -07:00
|
|
|
"#include \"", filename, ".h\"\n"
|
|
|
|
"\n"
|
2024-04-12 10:09:31 -07:00
|
|
|
"int main(int argc, char *argv[]) {\n"
|
2024-05-25 10:56:34 -07:00
|
|
|
"tomo_init();\n"
|
2024-04-20 11:55:27 -07:00
|
|
|
"\n",
|
|
|
|
main_binding && main_binding->type->tag == FunctionType ?
|
|
|
|
CORD_all(compile_cli_arg_call(module_code->env, main_binding->code, main_binding->type), "return 0;\n")
|
|
|
|
: "errx(1, \"No main function is defined!\");\n",
|
2024-03-20 22:33:44 -07:00
|
|
|
"}\n"
|
|
|
|
);
|
2024-04-12 10:09:31 -07:00
|
|
|
|
2024-05-27 21:30:09 -07:00
|
|
|
if (show_codegen) {
|
2024-03-20 22:33:44 -07:00
|
|
|
FILE *out = popen(heap_strf("%s | bat -P --file-name=run.c", autofmt), "w");
|
|
|
|
CORD_put(program, out);
|
|
|
|
pclose(out);
|
2024-03-03 11:36:09 -08:00
|
|
|
}
|
2024-03-20 22:33:44 -07:00
|
|
|
|
|
|
|
CORD_put(program, runner);
|
|
|
|
int status = pclose(runner);
|
2024-04-12 11:36:25 -07:00
|
|
|
if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
|
|
|
|
if (verbose)
|
2024-04-13 12:20:42 -07:00
|
|
|
printf("Compiled executable: %s\n", bin_name);
|
2024-04-12 11:36:25 -07:00
|
|
|
}
|
2024-03-20 22:33:44 -07:00
|
|
|
return WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE;
|
2024-02-04 12:23:59 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
|