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_ast = true
[[targets.dependencies]]
[targets.dependencies]
# 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
fun _start() {
main()
exit(0 as i32)
_exit(0 as i32)
}

View File

@ -3,8 +3,3 @@ include "types"
# from unistd.h
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_Box] = "box";
lookup_table[AST_FunDecl] = "fun";
lookup_table[AST_FunDef] = "fun";
lookup_table[AST_ProcDecl] = "fun";
lookup_table[AST_ProcDef] = "fun";
lookup_table[AST_FunDecl] = "fundef";
lookup_table[AST_FunDef] = "fundecl";
lookup_table[AST_ProcDecl] = "procdef";
lookup_table[AST_ProcDef] = "procdef";
lookup_table[AST_Call] = "funcall";
lookup_table[AST_Typecast] = "typecast";
@ -340,21 +340,47 @@ void AST_import_module(AST_NODE_PTR dst, size_t k, AST_NODE_PTR src) {
assert(dst != NULL);
assert(src != NULL);
size_t d = 0;
size_t elements = src->children->len;
for (size_t i = 0; i < elements; i++) {
AST_NODE_PTR node = AST_remove_child(src, 0);
if (node->kind == AST_FunDef) {
AST_NODE_PTR decl = AST_new_node(node->location, AST_FunDecl, NULL);
// TODO: resolve by public symbols
switch (node->kind) {
case AST_FunDef:
{
AST_NODE_PTR decl = AST_new_node(node->location, AST_FunDecl, NULL);
for (int u = 0; u < node->children->len - 1; u++) {
AST_push_node(decl, AST_get_node(node, u));
for (int u = 0; u < node->children->len - 1; u++) {
AST_push_node(decl, AST_get_node(node, u));
}
node = decl;
break;
}
case AST_ProcDef:
{
AST_NODE_PTR decl = AST_new_node(node->location, AST_ProcDecl, NULL);
node = decl;
for (int u = 0; u < node->children->len - 1; u++) {
AST_push_node(decl, AST_get_node(node, u));
}
node = decl;
break;
}
case AST_Typedef:
case AST_Def:
break;
default:
node = NULL;
}
AST_insert_node(dst, k + i, node);
if (node != NULL) {
AST_insert_node(dst, k + d, node);
d++;
}
}
AST_delete_node(src);
}

View File

@ -13,6 +13,8 @@
static GHashTable* args = NULL;
static Dependency *new_dependency();
static void clean(void) {
GHashTableIter iter;
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) {
DEBUG("retrieving boolean %s", name);
@ -306,9 +308,11 @@ static void get_bool(bool* boolean, const toml_table_t* table,
*boolean = 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) {
DEBUG("retrieving string %s", name);
@ -318,9 +322,11 @@ static void get_str(char** string, const toml_table_t* table,
*string = 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);
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;
DEBUG("integer has value: %ld", datum.u.i);
}
return (bool) datum.ok;
}
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) {
dependency->name = mem_strdup(MemoryNamespaceOpt, name);
get_str(&dependency->path, table, "path");
get_str(&dependency->target, table, "target");
bool is_project = false;
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->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;
}
@ -464,7 +489,7 @@ static int parse_target(const ProjectConfig* config,
}
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) {
return PROJECT_SEMANTIC_ERR;
}
@ -476,6 +501,14 @@ static int parse_target(const ProjectConfig* config,
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) {
DEBUG("parsing targets of project \"%s\"", config->name);

View File

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

View File

@ -17,6 +17,7 @@
#include <sys/log.h>
#include <unistd.h>
#include <yacc/parser.tab.h>
#include <link/lib.h>
#define GRAPHVIZ_FILE_EXTENSION "gv"
@ -244,65 +245,97 @@ static int compile_module_with_dependencies(ModuleFileStack* unit,
Dependency* dependency =
g_hash_table_lookup(target->dependencies, child->value);
gchar* cwd = g_get_current_dir();
chdir(dependency->path);
switch (dependency->kind) {
case GemstoneProject:
gchar* cwd = g_get_current_dir();
chdir(dependency->mode.project.path);
ProjectConfig* new_config = default_project_config();
if (load_project_config(new_config)) {
print_message(Error, "Failed to load project config: `%s`",
child->value);
return EXIT_FAILURE;
ProjectConfig* new_config = default_project_config();
if (load_project_config(new_config)) {
print_message(Error, "Failed to load project config: `%s`",
child->value);
return EXIT_FAILURE;
}
TargetConfig* dep_target = g_hash_table_lookup(new_config->targets, dependency->mode.project.target);
if (build_target(unit, dep_target)) {
print_message(Error, "Failed to build project config: `%s`",
child->value);
return EXIT_FAILURE;
}
GPathBuf* buf = g_path_buf_new_from_path(dependency->mode.project.path);
TargetConfig* dep_conf = g_hash_table_lookup(new_config->targets, dependency->mode.project.target);
char* root_mod = dep_conf->root_module;
g_path_buf_push(buf, root_mod);
char* rel_path = g_path_buf_to_path(buf);
GPathBuf* dep_bin = g_path_buf_new();
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, g_strjoin(".", dep_conf->name, "o", NULL));
char* dep_bin_path = g_path_buf_to_path(dep_bin);
g_array_append_val(dependency->libraries, dep_bin_path);
const char* path =
get_absolute_import_path(target, rel_path);
if (g_hash_table_contains(imports, path)) {
continue;
}
ModuleFile* imported_file = push_file(unit, path);
AST_NODE_PTR imported_module =
AST_new_node(empty_location(imported_file), AST_Module, NULL);
if (compile_module_with_dependencies(unit, imported_file, dep_conf, imported_module)
== EXIT_SUCCESS) {
AST_import_module(root_module, i + 1, imported_module);
} else {
return EXIT_FAILURE;
}
g_hash_table_insert(imports, (gpointer) path, NULL);
g_path_buf_pop(buf);
gchar* directory = g_path_buf_to_path(buf);
gchar* cached_directory =
mem_strdup(MemoryNamespaceLld, directory);
g_free(directory);
g_array_append_val(target->import_paths, cached_directory);
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;
}
TargetConfig* dep_target = g_hash_table_lookup(new_config->targets, dependency->target);
if (build_target(unit, dep_target)) {
print_message(Error, "Failed to build project config: `%s`",
child->value);
return EXIT_FAILURE;
}
GPathBuf* buf = g_path_buf_new_from_path(dependency->path);
TargetConfig* dep_conf = g_hash_table_lookup(new_config->targets, dependency->target);
char* root_mod = dep_conf->root_module;
g_path_buf_push(buf, root_mod);
char* rel_path = g_path_buf_to_path(buf);
GPathBuf* dep_bin = g_path_buf_new();
g_path_buf_push(dep_bin, dependency->path);
g_path_buf_push(dep_bin, dep_conf->archive_directory);
g_path_buf_push(dep_bin, g_strjoin(".", dep_conf->name, "o", NULL));
char* dep_bin_path = g_path_buf_to_path(dep_bin);
g_array_append_val(dependency->libraries, dep_bin_path);
const char* path =
get_absolute_import_path(target, rel_path);
if (g_hash_table_contains(imports, path)) {
continue;
}
ModuleFile* imported_file = push_file(unit, path);
AST_NODE_PTR imported_module =
AST_new_node(empty_location(imported_file), AST_Module, NULL);
if (compile_file_to_ast(imported_module, imported_file)
== EXIT_SUCCESS) {
AST_import_module(root_module, i + 1, imported_module);
} else {
return EXIT_FAILURE;
}
g_hash_table_insert(imports, (gpointer) path, NULL);
g_path_buf_pop(buf);
gchar* directory = g_path_buf_to_path(buf);
gchar* cached_directory =
mem_strdup(MemoryNamespaceLld, directory);
g_free(directory);
g_array_append_val(target->import_paths, cached_directory);
chdir(cwd);
} else {
print_message(Error, "Cannot resolve path for import: `%s`",

View File

@ -72,3 +72,18 @@ void link_print_available_driver() {
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();
char* build_platform_library_name(char* basename, bool shared);
#endif // GEMSTONE_LIB_H

View File

@ -11,7 +11,9 @@
extern int lld_main(int Argc, const char **Argv, const char **outstr);
const char* FLAGS[] = {
""
"--fatal-warnings",
"--Bdynamic",
"--dynamic-linker=/usr/bin/ld.so"
};
bool lldc_link(TargetLinkConfig* config) {
@ -21,17 +23,17 @@ bool lldc_link(TargetLinkConfig* config) {
char* linker = "ld.lld";
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++) {
char* flag = (char*) FLAGS[i];
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";
g_array_append_val(arguments, output_flag);
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++) {
char* lib = g_array_index(dep->libraries, char*, k);
if (lib == NULL)
continue;
g_array_append_val(config->object_file_names, lib);
// resolve path to object file
if (g_file_test(lib, G_FILE_TEST_EXISTS)) {
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]]
name = "prime"
import-paths = [ "." ]
link-paths = [ "/usr/lib" ]
root = "main.gsc"
mode = "application"
output = "bin"
@ -18,4 +19,4 @@ print_ir = true
print_ast = true
[targets.dependencies]
std = { path = "../../lib/src", target = "gsc-libc" }
std = { build-path = "../../lib/src", target = "gsc-libc" }