transitioned from manual file utilites to glib

This commit is contained in:
Sven Vogel 2024-06-06 11:26:26 +02:00
parent 14c5ba320c
commit 3e43960508
7 changed files with 117 additions and 80 deletions

View File

@ -102,10 +102,37 @@ TargetConfig* default_target_config() {
config->output_directory = strdup("bin"); config->output_directory = strdup("bin");
config->optimization_level = 1; config->optimization_level = 1;
config->root_module = NULL; config->root_module = NULL;
config->link_search_paths = g_array_new(FALSE, FALSE, sizeof(char*));
return config; return config;
} }
const char* get_absolute_link_path(const TargetConfig* config, const char* link_target_name) {
for (guint i = 0; i < config->link_search_paths->len; i++) {
const char* link_directory_path = g_array_index(config->link_search_paths, char*, i);
char* path = g_build_filename(link_directory_path, link_target_name, NULL);
char* cwd = g_get_current_dir();
char* canonical = g_canonicalize_filename(path, cwd);
const gboolean exists = g_file_test(canonical, G_FILE_TEST_EXISTS);
const gboolean is_dir = g_file_test(canonical, G_FILE_TEST_IS_DIR);
g_free(path);
g_free(cwd);
if (exists && !is_dir) {
return canonical;
}
g_free(canonical);
}
// file not found
return NULL;
}
TargetConfig* default_target_config_from_args() { TargetConfig* default_target_config_from_args() {
DEBUG("generating default target from command line..."); DEBUG("generating default target from command line...");
@ -145,6 +172,36 @@ TargetConfig* default_target_config_from_args() {
} }
} }
if (is_option_set("link-paths")) {
const Option* opt = get_option("link-paths");
if (opt->value != NULL) {
const char* start = opt->value;
const char* end = NULL;
while((end = strchr(start, ',')) != NULL) {
const int len = end - start;
char* link_path = malloc(len + 1);
memcpy(link_path, start, len);
link_path[len] = 0;
g_array_append_val(config->link_search_paths, link_path);
start = end;
}
const int len = strlen(start);
if (len > 0) {
char* link_path = malloc(len + 1);
memcpy(link_path, start, len);
link_path[len] = 0;
g_array_append_val(config->link_search_paths, link_path);
}
}
}
GArray* files = get_non_options_after("compile"); GArray* files = get_non_options_after("compile");
if (files == NULL) { if (files == NULL) {
@ -172,11 +229,12 @@ void print_help(void) {
"Compile non-project file: gsc compile <target-options> [file]", "Compile non-project file: gsc compile <target-options> [file]",
"Output information: gsc <option>", "Output information: gsc <option>",
"Target options:", "Target options:",
" --print-ast print resulting abstract syntax tree to a file", " --print-ast print resulting abstract syntax tree to a file",
" --print-asm print resulting assembly language to a file", " --print-asm print resulting assembly language to a file",
" --print-ir print resulting LLVM-IR to a file", " --print-ir print resulting LLVM-IR to a file",
" --mode=[app|lib] set the compilation mode to either application or library", " --mode=[app|lib] set the compilation mode to either application or library",
" --output=name name of output files without extension", " --output=name name of output files without extension",
" --link-paths=[paths,] set a list of directories to for libraries in"
"Options:", "Options:",
" --verbose print logs with level information or higher", " --verbose print logs with level information or higher",
" --debug print debug logs (if not disabled at compile time)", " --debug print debug logs (if not disabled at compile time)",
@ -373,6 +431,12 @@ void delete_target_config(TargetConfig* config) {
if (config->output_directory != NULL) { if (config->output_directory != NULL) {
free(config->output_directory); free(config->output_directory);
} }
if (config->link_search_paths) {
for (guint i = 0; i < config->link_search_paths->len; i++) {
free(g_array_index(config->link_search_paths, char*, i));
}
g_array_free(config->link_search_paths, TRUE);
}
free(config); free(config);
} }

View File

@ -16,6 +16,11 @@
#define TOML_ERROR_MSG_BUF 256 #define TOML_ERROR_MSG_BUF 256
typedef struct TargetLinkConfig_t {
// name of object files to link
GArray* object_file_names;
} TargetLinktConfig;
typedef enum TargetCompilationMode_t { typedef enum TargetCompilationMode_t {
// output an executable binary // output an executable binary
Application, Application,
@ -44,6 +49,9 @@ typedef struct TargetConfig_t {
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
// (can be extra library paths, auto included is output_directory)
GArray* link_search_paths;
} TargetConfig; } TargetConfig;
/** /**

View File

@ -14,6 +14,8 @@
#include <codegen/backend.h> #include <codegen/backend.h>
#include <llvm/backend.h> #include <llvm/backend.h>
#define GRAPHVIZ_FILE_EXTENSION "gv"
extern void yyrestart(FILE *); extern void yyrestart(FILE *);
// Module AST node used by the parser for AST construction. // Module AST node used by the parser for AST construction.
@ -94,6 +96,8 @@ static int setup_target_environment(const TargetConfig *target) {
return EXIT_FAILURE; return EXIT_FAILURE;
} }
INFO("setup environment successfully");
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
@ -105,26 +109,38 @@ static int setup_target_environment(const TargetConfig *target) {
static void print_ast_to_file(const AST_NODE_PTR ast, const TargetConfig *target) { static void print_ast_to_file(const AST_NODE_PTR ast, const TargetConfig *target) {
assert(ast != NULL); assert(ast != NULL);
assert(target != NULL); assert(target != NULL);
DEBUG("printing AST to file: %s", target->name);
if (!target->print_ast) if (!target->print_ast) {
INFO("no need to print AST");
return; return;
}
// create file path to write graphviz to // create file path to write graphviz to
const char *path = make_file_path(target->name, ".gv", 1, target->archive_directory); // basename of ile
char* filename = g_strjoin(".", target->name, GRAPHVIZ_FILE_EXTENSION, NULL);
// relative path to file
char *path = g_build_filename(target->archive_directory, filename, NULL);
FILE *output = fopen((const char *) path, "w"); DEBUG("Opening file to graph: %s", path);
FILE *output = fopen(path, "w");
if (output == NULL) { if (output == NULL) {
const char *message = get_last_error(); char *message = (char*) get_last_error();
print_message(Error, "Unable to open file for syntax tree at: %s: %s", path, message); print_message(Error, "Unable to open file for syntax tree at: %s: %s", path, message);
free((void *) message); free(message);
} else { } else {
DEBUG("writing graph to file...");
AST_fprint_graphviz(output, ast); AST_fprint_graphviz(output, ast);
fclose(output); fclose(output);
print_message(Info, "AST graph was written to: %s", path);
} }
free((void *) path); g_free(filename);
g_free(path);
} }
static void run_backend_codegen(const Module* module, const TargetConfig* target) { static void run_backend_codegen(const Module* module, const TargetConfig* target) {

View File

@ -294,14 +294,7 @@ int create_directory(const char *path) {
DEBUG("creating directory: %s", path); DEBUG("creating directory: %s", path);
int result; return g_mkdir_with_parents(path, 0755);
#ifdef __unix__
result = mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
#elif defined(_WIN32) || defined(WIN32)
result = _mkdir(path);
#endif
return result;
} }
const char *get_last_error() { const char *get_last_error() {
@ -313,44 +306,9 @@ const char *get_absolute_path(const char *path) {
DEBUG("resolving absolute path of: %s", path); DEBUG("resolving absolute path of: %s", path);
#ifdef __unix__ char* cwd = g_get_current_dir();
// use unix specific function char* canoical = g_canonicalize_filename(path, cwd);
char absolute_path[MAX_PATH_BYTES]; g_free(cwd);
realpath(path, absolute_path);
#elif defined(_WIN32) || defined(WIN32)
// use Windows CRT specific function
char absolute_path[MAX_PATH_BYTES];
_fullpath(path, absolute_path, _MAX_PATH);
#endif
return strdup(absolute_path); return canoical;
}
const char* make_file_path(const char* name, const char* ext, int count, ...) {
DEBUG("building file path...");
va_list args;
va_start(args, count); // Initialize the va_list with the first variadic argument
char* path = calloc(MAX_PATH_BYTES, sizeof(char));
for (int i = 0; i < count; i++) {
const char* arg = va_arg(args, const char*);
assert(arg != NULL);
strcat(path, arg);
strcat(path, PATH_SEPARATOR);
}
va_end(args); // Clean up the va_list
if (name != NULL) {
strcat(path, name);
}
if (name != NULL) {
strcat(path, ext);
}
return path;
} }

View File

@ -142,15 +142,4 @@ const char* get_last_error();
[[nodiscard("pointer must be freed")]] [[nodiscard("pointer must be freed")]]
const char* get_absolute_path(const char* path); const char* get_absolute_path(const char* path);
/**
* @brief Create a file path from a base name, extension a variable amount of directory path segments.
* @param count Amount of path segments to prepend to the basename
* @param name Basename of the file
* @param ext Extension of the file
* @param ... Path segments without path separator
* @return A relative path of a file
*/
[[nodiscard("pointer must be freed")]]
const char* make_file_path(const char* name, const char* ext, int count, ...);
#endif //GEMSTONE_FILES_H #endif //GEMSTONE_FILES_H

View File

@ -24,9 +24,9 @@ BackendError export_IR(LLVMBackendCompileUnit* unit, const Target* target,
// convert module to LLVM-IR // convert module to LLVM-IR
char* ir = LLVMPrintModuleToString(unit->module); char* ir = LLVMPrintModuleToString(unit->module);
char* basename = g_strjoin(".", target->name.str, "ll", NULL);
// construct file name // construct file name
const char* filename = const char* filename = g_build_filename(config->archive_directory, basename, NULL);
make_file_path(target->name.str, ".ll", 1, config->archive_directory);
INFO("Writing LLVM-IR to %s", filename); INFO("Writing LLVM-IR to %s", filename);
@ -49,7 +49,8 @@ BackendError export_IR(LLVMBackendCompileUnit* unit, const Target* target,
INFO("%ld bytes written to %s", bytes, filename); INFO("%ld bytes written to %s", bytes, filename);
free((char*)filename); g_free((char*)filename);
g_free(basename);
// clean up LLVM-IR string // clean up LLVM-IR string
LLVMDisposeMessage(ir); LLVMDisposeMessage(ir);
@ -64,15 +65,16 @@ BackendError emit_module_to_file(LLVMBackendCompileUnit* unit,
BackendError err = SUCCESS; BackendError err = SUCCESS;
DEBUG("Generating code..."); DEBUG("Generating code...");
const char* basename;
const char* filename; const char* filename;
switch (file_type) { switch (file_type) {
case LLVMAssemblyFile: case LLVMAssemblyFile:
filename = make_file_path(config->name, ".s", 1, basename = g_strjoin(".", config->name, "s", NULL);
config->archive_directory); filename = g_build_filename(config->archive_directory, basename, NULL);
break; break;
case LLVMObjectFile: case LLVMObjectFile:
filename = make_file_path(config->name, ".o", 1, basename = g_strjoin("", config->name, "o", NULL);
config->archive_directory); filename = g_build_filename(config->archive_directory, basename, NULL);
break; break;
default: default:
return new_backend_impl_error(Implementation, NULL, return new_backend_impl_error(Implementation, NULL,
@ -87,8 +89,8 @@ BackendError emit_module_to_file(LLVMBackendCompileUnit* unit,
LLVMDisposeMessage(error); LLVMDisposeMessage(error);
} }
free((void*)filename); g_free((void*) filename);
g_free((void*) basename);
return err; return err;
} }

View File

@ -6,8 +6,8 @@ description = "This is a test project"
[target.debug] [target.debug]
root = "src/main.txt" root = "src/main.txt"
output = "bin" output = "bin/debug"
archive = "archive" archive = "archive/debug"
opt = 1 opt = 1
print_ast = true print_ast = true
print_asm = true print_asm = true