transitioned from manual file utilites to glib
This commit is contained in:
parent
14c5ba320c
commit
3e43960508
|
@ -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) {
|
||||||
|
@ -177,6 +234,7 @@ void print_help(void) {
|
||||||
" --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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue