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->optimization_level = 1;
|
||||
config->root_module = NULL;
|
||||
config->link_search_paths = g_array_new(FALSE, FALSE, sizeof(char*));
|
||||
|
||||
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() {
|
||||
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");
|
||||
|
||||
if (files == NULL) {
|
||||
|
@ -172,11 +229,12 @@ void print_help(void) {
|
|||
"Compile non-project file: gsc compile <target-options> [file]",
|
||||
"Output information: gsc <option>",
|
||||
"Target options:",
|
||||
" --print-ast print resulting abstract syntax tree to a file",
|
||||
" --print-asm print resulting assembly language to a file",
|
||||
" --print-ir print resulting LLVM-IR to a file",
|
||||
" --mode=[app|lib] set the compilation mode to either application or library",
|
||||
" --output=name name of output files without extension",
|
||||
" --print-ast print resulting abstract syntax tree to a file",
|
||||
" --print-asm print resulting assembly language to a file",
|
||||
" --print-ir print resulting LLVM-IR to a file",
|
||||
" --mode=[app|lib] set the compilation mode to either application or library",
|
||||
" --output=name name of output files without extension",
|
||||
" --link-paths=[paths,] set a list of directories to for libraries in"
|
||||
"Options:",
|
||||
" --verbose print logs with level information or higher",
|
||||
" --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) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,11 @@
|
|||
|
||||
#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 {
|
||||
// output an executable binary
|
||||
Application,
|
||||
|
@ -44,6 +49,9 @@ typedef struct TargetConfig_t {
|
|||
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;
|
||||
} TargetConfig;
|
||||
|
||||
/**
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
#include <codegen/backend.h>
|
||||
#include <llvm/backend.h>
|
||||
|
||||
#define GRAPHVIZ_FILE_EXTENSION "gv"
|
||||
|
||||
extern void yyrestart(FILE *);
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
INFO("setup environment successfully");
|
||||
|
||||
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) {
|
||||
assert(ast != 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;
|
||||
}
|
||||
|
||||
// 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) {
|
||||
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);
|
||||
free((void *) message);
|
||||
free(message);
|
||||
} else {
|
||||
DEBUG("writing graph to file...");
|
||||
|
||||
AST_fprint_graphviz(output, ast);
|
||||
|
||||
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) {
|
||||
|
|
|
@ -294,14 +294,7 @@ int create_directory(const char *path) {
|
|||
|
||||
DEBUG("creating directory: %s", path);
|
||||
|
||||
int result;
|
||||
#ifdef __unix__
|
||||
result = mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
|
||||
#elif defined(_WIN32) || defined(WIN32)
|
||||
result = _mkdir(path);
|
||||
#endif
|
||||
|
||||
return result;
|
||||
return g_mkdir_with_parents(path, 0755);
|
||||
}
|
||||
|
||||
const char *get_last_error() {
|
||||
|
@ -313,44 +306,9 @@ const char *get_absolute_path(const char *path) {
|
|||
|
||||
DEBUG("resolving absolute path of: %s", path);
|
||||
|
||||
#ifdef __unix__
|
||||
// use unix specific function
|
||||
char absolute_path[MAX_PATH_BYTES];
|
||||
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
|
||||
char* cwd = g_get_current_dir();
|
||||
char* canoical = g_canonicalize_filename(path, cwd);
|
||||
g_free(cwd);
|
||||
|
||||
return strdup(absolute_path);
|
||||
}
|
||||
|
||||
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;
|
||||
return canoical;
|
||||
}
|
||||
|
|
|
@ -142,15 +142,4 @@ const char* get_last_error();
|
|||
[[nodiscard("pointer must be freed")]]
|
||||
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
|
||||
|
|
|
@ -24,9 +24,9 @@ BackendError export_IR(LLVMBackendCompileUnit* unit, const Target* target,
|
|||
// convert module to LLVM-IR
|
||||
char* ir = LLVMPrintModuleToString(unit->module);
|
||||
|
||||
char* basename = g_strjoin(".", target->name.str, "ll", NULL);
|
||||
// construct file name
|
||||
const char* filename =
|
||||
make_file_path(target->name.str, ".ll", 1, config->archive_directory);
|
||||
const char* filename = g_build_filename(config->archive_directory, basename, NULL);
|
||||
|
||||
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);
|
||||
|
||||
free((char*)filename);
|
||||
g_free((char*)filename);
|
||||
g_free(basename);
|
||||
|
||||
// clean up LLVM-IR string
|
||||
LLVMDisposeMessage(ir);
|
||||
|
@ -64,15 +65,16 @@ BackendError emit_module_to_file(LLVMBackendCompileUnit* unit,
|
|||
BackendError err = SUCCESS;
|
||||
DEBUG("Generating code...");
|
||||
|
||||
const char* basename;
|
||||
const char* filename;
|
||||
switch (file_type) {
|
||||
case LLVMAssemblyFile:
|
||||
filename = make_file_path(config->name, ".s", 1,
|
||||
config->archive_directory);
|
||||
basename = g_strjoin(".", config->name, "s", NULL);
|
||||
filename = g_build_filename(config->archive_directory, basename, NULL);
|
||||
break;
|
||||
case LLVMObjectFile:
|
||||
filename = make_file_path(config->name, ".o", 1,
|
||||
config->archive_directory);
|
||||
basename = g_strjoin("", config->name, "o", NULL);
|
||||
filename = g_build_filename(config->archive_directory, basename, NULL);
|
||||
break;
|
||||
default:
|
||||
return new_backend_impl_error(Implementation, NULL,
|
||||
|
@ -87,8 +89,8 @@ BackendError emit_module_to_file(LLVMBackendCompileUnit* unit,
|
|||
LLVMDisposeMessage(error);
|
||||
}
|
||||
|
||||
free((void*)filename);
|
||||
|
||||
g_free((void*) filename);
|
||||
g_free((void*) basename);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,8 +6,8 @@ description = "This is a test project"
|
|||
|
||||
[target.debug]
|
||||
root = "src/main.txt"
|
||||
output = "bin"
|
||||
archive = "archive"
|
||||
output = "bin/debug"
|
||||
archive = "archive/debug"
|
||||
opt = 1
|
||||
print_ast = true
|
||||
print_asm = true
|
||||
|
|
Loading…
Reference in New Issue