fix: binary not build properly

This commit is contained in:
Sven Vogel 2024-09-17 19:42:01 +02:00
parent 76f5a0fd7f
commit 0b1245b9cc
12 changed files with 266 additions and 120 deletions

View File

@ -17,6 +17,6 @@ print_asm = true
print_ir = true print_ir = true
print_ast = true print_ast = true
[[targets.dependencies]] [targets.dependencies]
# link against system default libc shared library # link against system default libc shared library
libc = { shared = true } libc = { library = "c", shared = true }

View File

@ -10,5 +10,5 @@ fun main()
# entrypoint function # entrypoint function
fun _start() { fun _start() {
main() main()
exit(0 as i32) _exit(0 as i32)
} }

View File

@ -3,8 +3,3 @@ include "types"
# from unistd.h # from unistd.h
fun _exit(in i32: code) fun _exit(in i32: code)
# Return control back to the operating system
fun exit(in i32: code) {
_exit(code)
}

View File

@ -70,10 +70,10 @@ void AST_init() {
lookup_table[AST_Typedef] = "typedef"; lookup_table[AST_Typedef] = "typedef";
lookup_table[AST_Box] = "box"; lookup_table[AST_Box] = "box";
lookup_table[AST_FunDecl] = "fun"; lookup_table[AST_FunDecl] = "fundef";
lookup_table[AST_FunDef] = "fun"; lookup_table[AST_FunDef] = "fundecl";
lookup_table[AST_ProcDecl] = "fun"; lookup_table[AST_ProcDecl] = "procdef";
lookup_table[AST_ProcDef] = "fun"; lookup_table[AST_ProcDef] = "procdef";
lookup_table[AST_Call] = "funcall"; lookup_table[AST_Call] = "funcall";
lookup_table[AST_Typecast] = "typecast"; lookup_table[AST_Typecast] = "typecast";
@ -340,11 +340,16 @@ void AST_import_module(AST_NODE_PTR dst, size_t k, AST_NODE_PTR src) {
assert(dst != NULL); assert(dst != NULL);
assert(src != NULL); assert(src != NULL);
size_t d = 0;
size_t elements = src->children->len; size_t elements = src->children->len;
for (size_t i = 0; i < elements; i++) { for (size_t i = 0; i < elements; i++) {
AST_NODE_PTR node = AST_remove_child(src, 0); AST_NODE_PTR node = AST_remove_child(src, 0);
if (node->kind == AST_FunDef) { // TODO: resolve by public symbols
switch (node->kind) {
case AST_FunDef:
{
AST_NODE_PTR decl = AST_new_node(node->location, AST_FunDecl, NULL); AST_NODE_PTR decl = AST_new_node(node->location, AST_FunDecl, NULL);
for (int u = 0; u < node->children->len - 1; u++) { for (int u = 0; u < node->children->len - 1; u++) {
@ -352,9 +357,30 @@ void AST_import_module(AST_NODE_PTR dst, size_t k, AST_NODE_PTR src) {
} }
node = decl; node = decl;
break;
}
case AST_ProcDef:
{
AST_NODE_PTR decl = AST_new_node(node->location, AST_ProcDecl, NULL);
for (int u = 0; u < node->children->len - 1; u++) {
AST_push_node(decl, AST_get_node(node, u));
} }
AST_insert_node(dst, k + i, node); node = decl;
break;
}
case AST_Typedef:
case AST_Def:
break;
default:
node = NULL;
}
if (node != NULL) {
AST_insert_node(dst, k + d, node);
d++;
}
} }
AST_delete_node(src); AST_delete_node(src);
} }

View File

@ -13,6 +13,8 @@
static GHashTable* args = NULL; static GHashTable* args = NULL;
static Dependency *new_dependency();
static void clean(void) { static void clean(void) {
GHashTableIter iter; GHashTableIter iter;
gpointer key, value; gpointer key, value;
@ -296,7 +298,7 @@ void print_help(void) {
} }
} }
static void get_bool(bool* boolean, const toml_table_t* table, static bool get_bool(bool* boolean, const toml_table_t* table,
const char* name) { const char* name) {
DEBUG("retrieving boolean %s", name); DEBUG("retrieving boolean %s", name);
@ -306,9 +308,11 @@ static void get_bool(bool* boolean, const toml_table_t* table,
*boolean = datum.u.b; *boolean = datum.u.b;
DEBUG("boolean has value: %d", datum.u.b); DEBUG("boolean has value: %d", datum.u.b);
} }
return (bool) datum.ok;
} }
static void get_str(char** string, const toml_table_t* table, static bool get_str(char** string, const toml_table_t* table,
const char* name) { const char* name) {
DEBUG("retrieving string %s", name); DEBUG("retrieving string %s", name);
@ -318,9 +322,11 @@ static void get_str(char** string, const toml_table_t* table,
*string = datum.u.s; *string = datum.u.s;
DEBUG("string has value: %s", datum.u.s); DEBUG("string has value: %s", datum.u.s);
} }
return (bool) datum.ok;
} }
static void get_int(int* integer, const toml_table_t* table, const char* name) { static bool get_int(int* integer, const toml_table_t* table, const char* name) {
DEBUG("retrieving integer %s", name); DEBUG("retrieving integer %s", name);
const toml_datum_t datum = toml_int_in(table, name); const toml_datum_t datum = toml_int_in(table, name);
@ -329,6 +335,8 @@ static void get_int(int* integer, const toml_table_t* table, const char* name) {
*integer = (int) datum.u.i; *integer = (int) datum.u.i;
DEBUG("integer has value: %ld", datum.u.i); DEBUG("integer has value: %ld", datum.u.i);
} }
return (bool) datum.ok;
} }
static void get_array(GArray* array, const toml_table_t* table, static void get_array(GArray* array, const toml_table_t* table,
@ -404,11 +412,28 @@ static int get_mode_from_str(TargetCompilationMode* mode, const char* name) {
static int parse_dependency(Dependency* dependency, toml_table_t* table, char* name) { static int parse_dependency(Dependency* dependency, toml_table_t* table, char* name) {
dependency->name = mem_strdup(MemoryNamespaceOpt, name); dependency->name = mem_strdup(MemoryNamespaceOpt, name);
get_str(&dependency->path, table, "path"); bool is_project = false;
get_str(&dependency->target, table, "target"); is_project |= get_str(&dependency->mode.project.path, table, "build-path");
is_project |= get_str(&dependency->mode.project.target, table, "target");
bool is_library = false;
is_library |= get_str(&dependency->mode.library.name, table, "library");
is_library |= get_bool(&dependency->mode.library.shared, table, "shared");
dependency->libraries = mem_new_g_array(MemoryNamespaceOpt, sizeof(char*)); dependency->libraries = mem_new_g_array(MemoryNamespaceOpt, sizeof(char*));
dependency->kind = is_project ? GemstoneProject : NativeLibrary;
if (is_library && is_project) {
print_message(Error, "Mutually exclusive configs found");
return PROJECT_SEMANTIC_ERR;
}
if (!(is_library || is_project)) {
print_message(Error, "Missing dependency config");
return PROJECT_SEMANTIC_ERR;
}
return PROJECT_OK; return PROJECT_OK;
} }
@ -464,7 +489,7 @@ static int parse_target(const ProjectConfig* config,
} }
toml_table_t* dependency_table = toml_table_in(dependencies, key); toml_table_t* dependency_table = toml_table_in(dependencies, key);
Dependency* dependency = mem_alloc(MemoryNamespaceOpt, sizeof(Dependency)); Dependency* dependency = new_dependency();
if (parse_dependency(dependency, dependency_table, key) == PROJECT_SEMANTIC_ERR) { if (parse_dependency(dependency, dependency_table, key) == PROJECT_SEMANTIC_ERR) {
return PROJECT_SEMANTIC_ERR; return PROJECT_SEMANTIC_ERR;
} }
@ -476,6 +501,14 @@ static int parse_target(const ProjectConfig* config,
return PROJECT_OK; return PROJECT_OK;
} }
static Dependency* new_dependency() {
Dependency* dependency = mem_alloc(MemoryNamespaceOpt, sizeof(Dependency));
memset(dependency, 0, sizeof(Dependency));
return dependency;
}
static int parse_targets(ProjectConfig* config, const toml_table_t* root) { static int parse_targets(ProjectConfig* config, const toml_table_t* root) {
DEBUG("parsing targets of project \"%s\"", config->name); DEBUG("parsing targets of project \"%s\"", config->name);

View File

@ -18,13 +18,13 @@
typedef struct TargetLinkConfig_t { typedef struct TargetLinkConfig_t {
// name of object files to link // name of object files to link
GArray* object_file_names; GArray *object_file_names;
// treat warnings as errors // treat warnings as errors
gboolean fatal_warnings; gboolean fatal_warnings;
// colorize linker output // colorize linker output
bool colorize; bool colorize;
char* output_file; char *output_file;
char* driver; char *driver;
} TargetLinkConfig; } TargetLinkConfig;
typedef enum TargetCompilationMode_t { typedef enum TargetCompilationMode_t {
@ -34,11 +34,28 @@ typedef enum TargetCompilationMode_t {
Library Library
} TargetCompilationMode; } TargetCompilationMode;
typedef enum DependencyKind_t {
GemstoneProject,
NativeLibrary
} DependencyKind;
// Possible configuration modes:
// - build project (local/git)
// - native library (static/shared)
typedef struct Dependency_t { typedef struct Dependency_t {
char* name; char *name;
char* path; DependencyKind kind;
char* target; union {
GArray* libraries; struct {
char *path;
char *target;
} project;
struct {
char *name;
bool shared;
} library;
} mode;
GArray *libraries;
} Dependency; } Dependency;
/** /**
@ -47,33 +64,33 @@ typedef struct Dependency_t {
* Intermediate representations can be printed as well. * Intermediate representations can be printed as well.
*/ */
typedef struct TargetConfig_t { typedef struct TargetConfig_t {
char* name; char *name;
bool print_ast; bool print_ast;
bool print_asm; bool print_asm;
bool print_ir; bool print_ir;
// root module file which imports all submodules // root module file which imports all submodules
// if this is NULL use the first commandline argument as root module // if this is NULL use the first commandline argument as root module
char* root_module; char *root_module;
// output directory for binaries // output directory for binaries
char* output_directory; char *output_directory;
// output directory for intermediate representations (LLVM-IR, Assembly, // output directory for intermediate representations (LLVM-IR, Assembly,
// ...) // ...)
char* archive_directory; char *archive_directory;
// binary driver for executable generation // binary driver for executable generation
char* driver; char *driver;
// mode of compilation // mode of compilation
TargetCompilationMode mode; TargetCompilationMode mode;
// number between 1 and 3 // number between 1 and 3
int optimization_level; int optimization_level;
// path to look for object files // path to look for object files
// (can be extra library paths, auto included is output_directory) // (can be extra library paths, auto included is output_directory)
GArray* link_search_paths; GArray *link_search_paths;
// treat linker warnings as errors // treat linker warnings as errors
bool lld_fatal_warnings; bool lld_fatal_warnings;
// treat parser warnings as errors // treat parser warnings as errors
bool gsc_fatal_warnings; bool gsc_fatal_warnings;
GArray* import_paths; GArray *import_paths;
GHashTable* dependencies; GHashTable *dependencies;
} TargetConfig; } TargetConfig;
/** /**
@ -83,16 +100,16 @@ typedef struct TargetConfig_t {
*/ */
typedef struct ProjectConfig_t { typedef struct ProjectConfig_t {
// name of the project // name of the project
char* name; char *name;
// description // description
char* desc; char *desc;
// version // version
char* version; char *version;
// license // license
char* license; char *license;
// list of authors // list of authors
GArray* authors; GArray *authors;
GHashTable* targets; GHashTable *targets;
} ProjectConfig; } ProjectConfig;
/** /**
@ -102,9 +119,9 @@ typedef struct Option_t {
// index in which the option appeared in the argument array // index in which the option appeared in the argument array
int index; int index;
// identifier of the option // identifier of the option
const char* string; const char *string;
// option if format is equals to --option=value // option if format is equals to --option=value
const char* value; const char *value;
// whether or not this option has a value // whether or not this option has a value
bool is_opt; bool is_opt;
} Option; } Option;
@ -114,7 +131,8 @@ typedef struct Option_t {
* @return A pointer to a new target configuration. * @return A pointer to a new target configuration.
*/ */
[[nodiscard("must be freed")]] [[nodiscard("must be freed")]]
TargetConfig* default_target_config();
TargetConfig *default_target_config();
/** /**
* @brief Create the default configuration for a project. * @brief Create the default configuration for a project.
@ -122,7 +140,8 @@ TargetConfig* default_target_config();
* @return A pointer to a new project configuration. * @return A pointer to a new project configuration.
*/ */
[[nodiscard("must be freed")]] [[nodiscard("must be freed")]]
ProjectConfig* default_project_config();
ProjectConfig *default_project_config();
/** /**
* @brief Create a new default target configuration an write command line * @brief Create a new default target configuration an write command line
@ -130,7 +149,8 @@ ProjectConfig* default_project_config();
* @return A default config with user specified values. * @return A default config with user specified values.
*/ */
[[nodiscard("must be freed")]] [[nodiscard("must be freed")]]
TargetConfig* default_target_config_from_args();
TargetConfig *default_target_config_from_args();
/** /**
* @brief Load a project configuration from a TOML file with the name * @brief Load a project configuration from a TOML file with the name
@ -139,7 +159,8 @@ TargetConfig* default_target_config_from_args();
* @return * @return
*/ */
[[gnu::nonnull(1)]] [[gnu::nonnull(1)]]
int load_project_config(ProjectConfig* config);
int load_project_config(ProjectConfig *config);
/** /**
* @brief Print a help dialog to stdout. * @brief Print a help dialog to stdout.
@ -151,13 +172,15 @@ void print_help(void);
* @param config The config to free. * @param config The config to free.
*/ */
[[gnu::nonnull(1)]] [[gnu::nonnull(1)]]
void delete_project_config(ProjectConfig* config);
void delete_project_config(ProjectConfig *config);
/** /**
* @brief Delete a target configuration by deallocation. * @brief Delete a target configuration by deallocation.
*/ */
[[gnu::nonnull(1)]] [[gnu::nonnull(1)]]
void delete_target_config(TargetConfig*);
void delete_target_config(TargetConfig *);
/** /**
* @brief Parse the given command line arguments so that calls to * @brief Parse the given command line arguments so that calls to
@ -165,7 +188,7 @@ void delete_target_config(TargetConfig*);
* @param argc Number of arguments * @param argc Number of arguments
* @param argv Array of arguments * @param argv Array of arguments
*/ */
void parse_options(int argc, char* argv[]); void parse_options(int argc, char *argv[]);
/** /**
* @brief Tests whether an option was set as argument. * @brief Tests whether an option was set as argument.
@ -174,7 +197,8 @@ void parse_options(int argc, char* argv[]);
* @return 1 if the options was set, 0 otherwise * @return 1 if the options was set, 0 otherwise
*/ */
[[gnu::nonnull(1)]] [[gnu::nonnull(1)]]
bool is_option_set(const char* option);
bool is_option_set(const char *option);
/** /**
* @brief Returns the options information if present * @brief Returns the options information if present
@ -183,7 +207,8 @@ bool is_option_set(const char* option);
* @return A valid option struct or NULL if not found. * @return A valid option struct or NULL if not found.
*/ */
[[gnu::nonnull(1)]] [[gnu::nonnull(1)]]
const Option* get_option(const char* option);
const Option *get_option(const char *option);
/** /**
* @brief Put a copy of all options whos index is greather than the index * @brief Put a copy of all options whos index is greather than the index
@ -192,7 +217,8 @@ const Option* get_option(const char* option);
* @return an array of options that followed command. * @return an array of options that followed command.
*/ */
[[gnu::nonnull(1)]] [[nodiscard("must be freed")]] [[gnu::nonnull(1)]] [[nodiscard("must be freed")]]
GArray* get_non_options_after(const char* command);
GArray *get_non_options_after(const char *command);
void init_toml(); void init_toml();

View File

@ -17,6 +17,7 @@
#include <sys/log.h> #include <sys/log.h>
#include <unistd.h> #include <unistd.h>
#include <yacc/parser.tab.h> #include <yacc/parser.tab.h>
#include <link/lib.h>
#define GRAPHVIZ_FILE_EXTENSION "gv" #define GRAPHVIZ_FILE_EXTENSION "gv"
@ -244,8 +245,10 @@ static int compile_module_with_dependencies(ModuleFileStack* unit,
Dependency* dependency = Dependency* dependency =
g_hash_table_lookup(target->dependencies, child->value); g_hash_table_lookup(target->dependencies, child->value);
switch (dependency->kind) {
case GemstoneProject:
gchar* cwd = g_get_current_dir(); gchar* cwd = g_get_current_dir();
chdir(dependency->path); chdir(dependency->mode.project.path);
ProjectConfig* new_config = default_project_config(); ProjectConfig* new_config = default_project_config();
if (load_project_config(new_config)) { if (load_project_config(new_config)) {
@ -254,21 +257,21 @@ static int compile_module_with_dependencies(ModuleFileStack* unit,
return EXIT_FAILURE; return EXIT_FAILURE;
} }
TargetConfig* dep_target = g_hash_table_lookup(new_config->targets, dependency->target); TargetConfig* dep_target = g_hash_table_lookup(new_config->targets, dependency->mode.project.target);
if (build_target(unit, dep_target)) { if (build_target(unit, dep_target)) {
print_message(Error, "Failed to build project config: `%s`", print_message(Error, "Failed to build project config: `%s`",
child->value); child->value);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
GPathBuf* buf = g_path_buf_new_from_path(dependency->path); GPathBuf* buf = g_path_buf_new_from_path(dependency->mode.project.path);
TargetConfig* dep_conf = g_hash_table_lookup(new_config->targets, dependency->target); TargetConfig* dep_conf = g_hash_table_lookup(new_config->targets, dependency->mode.project.target);
char* root_mod = dep_conf->root_module; char* root_mod = dep_conf->root_module;
g_path_buf_push(buf, root_mod); g_path_buf_push(buf, root_mod);
char* rel_path = g_path_buf_to_path(buf); char* rel_path = g_path_buf_to_path(buf);
GPathBuf* dep_bin = g_path_buf_new(); GPathBuf* dep_bin = g_path_buf_new();
g_path_buf_push(dep_bin, dependency->path); g_path_buf_push(dep_bin, dependency->mode.project.path);
g_path_buf_push(dep_bin, dep_conf->archive_directory); g_path_buf_push(dep_bin, dep_conf->archive_directory);
g_path_buf_push(dep_bin, g_strjoin(".", dep_conf->name, "o", NULL)); g_path_buf_push(dep_bin, g_strjoin(".", dep_conf->name, "o", NULL));
char* dep_bin_path = g_path_buf_to_path(dep_bin); char* dep_bin_path = g_path_buf_to_path(dep_bin);
@ -286,7 +289,7 @@ static int compile_module_with_dependencies(ModuleFileStack* unit,
AST_NODE_PTR imported_module = AST_NODE_PTR imported_module =
AST_new_node(empty_location(imported_file), AST_Module, NULL); AST_new_node(empty_location(imported_file), AST_Module, NULL);
if (compile_file_to_ast(imported_module, imported_file) if (compile_module_with_dependencies(unit, imported_file, dep_conf, imported_module)
== EXIT_SUCCESS) { == EXIT_SUCCESS) {
AST_import_module(root_module, i + 1, imported_module); AST_import_module(root_module, i + 1, imported_module);
} else { } else {
@ -304,6 +307,36 @@ static int compile_module_with_dependencies(ModuleFileStack* unit,
chdir(cwd); chdir(cwd);
GHashTableIter iter;
g_hash_table_iter_init(&iter, dep_target->dependencies);
char* key;
Dependency* dep;
while (g_hash_table_iter_next(&iter, (gpointer) &key, (gpointer) &dep)) {
if (dep->kind == GemstoneProject) {
for (guint i = 0; i < dep->libraries->len; i++) {
char* dep_lib = g_array_index(dep->libraries, char*, i);
g_array_append_val(dependency->libraries, dep_lib);
}
} else if (dep->kind == NativeLibrary) {
char* library_name = build_platform_library_name(dep->mode.library.name, dep->mode.library.shared);
g_array_append_val(dependency->libraries, library_name);
}
}
break;
case NativeLibrary:
char* library_name = build_platform_library_name(dependency->mode.library.name, dependency->mode.library.shared);
g_array_append_val(dependency->libraries, library_name);
break;
default:
break;
}
} else { } else {
print_message(Error, "Cannot resolve path for import: `%s`", print_message(Error, "Cannot resolve path for import: `%s`",
child->value); child->value);

View File

@ -72,3 +72,18 @@ void link_print_available_driver() {
printf(" - %s\n", (char*) key); printf(" - %s\n", (char*) key);
} }
} }
static const char* get_library_file_extension(bool shared) {
if (shared) {
return "so";
} else {
return "o";
}
}
char* build_platform_library_name(char* basename, bool shared) {
char* library_name = g_strjoin("", "lib", basename, ".", get_library_file_extension(shared), NULL);
char* cached_library_name = mem_strdup(MemoryNamespaceLld, library_name);
g_free(library_name);
return cached_library_name;
}

View File

@ -15,4 +15,6 @@ bool link_run(TargetLinkConfig*);
void link_print_available_driver(); void link_print_available_driver();
char* build_platform_library_name(char* basename, bool shared);
#endif // GEMSTONE_LIB_H #endif // GEMSTONE_LIB_H

View File

@ -11,7 +11,9 @@
extern int lld_main(int Argc, const char **Argv, const char **outstr); extern int lld_main(int Argc, const char **Argv, const char **outstr);
const char* FLAGS[] = { const char* FLAGS[] = {
"" "--fatal-warnings",
"--Bdynamic",
"--dynamic-linker=/usr/bin/ld.so"
}; };
bool lldc_link(TargetLinkConfig* config) { bool lldc_link(TargetLinkConfig* config) {
@ -21,17 +23,17 @@ bool lldc_link(TargetLinkConfig* config) {
char* linker = "ld.lld"; char* linker = "ld.lld";
g_array_append_val(arguments, linker); g_array_append_val(arguments, linker);
for (guint i = 0; i < config->object_file_names->len; i++) {
char* obj = g_array_index(config->object_file_names, char*, i);
g_array_append_val(arguments, obj);
}
for (int i = 0; i < sizeof(FLAGS)/sizeof(char*); i++) { for (int i = 0; i < sizeof(FLAGS)/sizeof(char*); i++) {
char* flag = (char*) FLAGS[i]; char* flag = (char*) FLAGS[i];
g_array_append_val(arguments, flag); g_array_append_val(arguments, flag);
} }
for (guint i = 0; i < config->object_file_names->len; i++) {
char* obj = g_array_index(config->object_file_names, char*, i);
g_array_append_val(arguments, obj);
}
char* output_flag = "-o"; char* output_flag = "-o";
g_array_append_val(arguments, output_flag); g_array_append_val(arguments, output_flag);
g_array_append_val(arguments, config->output_file); g_array_append_val(arguments, config->output_file);

View File

@ -98,8 +98,21 @@ TargetLinkConfig* lld_create_link_config(__attribute__((unused))
for (guint k = 0; k < dep->libraries->len; k++) { for (guint k = 0; k < dep->libraries->len; k++) {
char* lib = g_array_index(dep->libraries, char*, k); char* lib = g_array_index(dep->libraries, char*, k);
if (lib == NULL)
continue;
// resolve path to object file
if (g_file_test(lib, G_FILE_TEST_EXISTS)) {
g_array_append_val(config->object_file_names, lib); g_array_append_val(config->object_file_names, lib);
continue;
}
char* path = get_absolute_link_path(target_config, lib);
if (path == NULL) {
print_message(Error, "Unable to resolve dependency: %s", lib);
} else {
g_array_append_val(config->object_file_names, path);
}
} }
} }

View File

@ -8,6 +8,7 @@ authors = [ "Sven Vogel <sven.vogel123@web.de>" ]
[[targets]] [[targets]]
name = "prime" name = "prime"
import-paths = [ "." ] import-paths = [ "." ]
link-paths = [ "/usr/lib" ]
root = "main.gsc" root = "main.gsc"
mode = "application" mode = "application"
output = "bin" output = "bin"
@ -18,4 +19,4 @@ print_ir = true
print_ast = true print_ast = true
[targets.dependencies] [targets.dependencies]
std = { path = "../../lib/src", target = "gsc-libc" } std = { build-path = "../../lib/src", target = "gsc-libc" }