diff --git a/src/build/build.h b/src/build/build.h index 6b84d4731..f119cc8e6 100644 --- a/src/build/build.h +++ b/src/build/build.h @@ -13,6 +13,7 @@ #define MAX_THREADS 0xFFFF #define DEFAULT_SYMTAB_SIZE (256 * 1024) #define DEFAULT_SWITCHRANGE_MAX_SIZE (256) +#define DEFAULT_PATH "." typedef enum { @@ -433,6 +434,7 @@ typedef struct BuildOptions_ const char *project_name; const char *target_select; const char *path; + const char *vendor_download_path; const char *template; LinkerType linker_type; const char *custom_linker_path; diff --git a/src/build/build_options.c b/src/build/build_options.c index eb9e2b60f..329816c95 100644 --- a/src/build/build_options.c +++ b/src/build/build_options.c @@ -1237,7 +1237,8 @@ BuildOptions parse_arguments(int argc, const char *argv[]) } BuildOptions build_options = { - .path = ".", + .path = DEFAULT_PATH, + .vendor_download_path = DEFAULT_PATH, .emit_llvm = false, .optsetting = OPT_SETTING_NOT_SET, .debug_info_override = DEBUG_INFO_NOT_SET, diff --git a/src/build/project.h b/src/build/project.h new file mode 100644 index 000000000..8130c4ffc --- /dev/null +++ b/src/build/project.h @@ -0,0 +1,6 @@ +#pragma once +#include "../utils/json.h" + +const char** get_project_dependency_directories(); + +void add_libraries_to_project_file(const char** libs, const char* target_name); \ No newline at end of file diff --git a/src/build/project_manipulation.c b/src/build/project_manipulation.c index 3cdd07b6e..89dc87adc 100644 --- a/src/build/project_manipulation.c +++ b/src/build/project_manipulation.c @@ -1,4 +1,5 @@ #include "build_internal.h" +#include "project.h" #define PRINTFN(string, ...) fprintf(stdout, string "\n", ##__VA_ARGS__) // NOLINT #define PRINTF(string, ...) fprintf(stdout, string, ##__VA_ARGS__) // NOLINT @@ -22,6 +23,18 @@ static JSONObject *read_project(const char **file_used) return json; } +const char** get_project_dependency_directories() +{ + const char *filename; + JSONObject *json = read_project(&filename); + + const char *target = NULL; + const char **deps_dirs = NULL; + get_list_append_strings(filename, target, json, &deps_dirs, "dependency-search-paths", "dependency-search-paths-override", "dependency-search-paths-add"); + + return deps_dirs; +} + static void print_vec(const char *header, const char **vec, bool opt) { if (opt && !vec) return; @@ -239,6 +252,56 @@ static void view_target(const char *filename, const char *name, JSONObject *targ TARGET_VIEW_BOOL("Return structs on the stack", "x86-stack-struct-return"); } +void add_libraries_to_project_file(const char** libs, const char* target_name) { + + if (!file_exists(PROJECT_JSON5) && !file_exists(PROJECT_JSON)) return; + //TODO! Target name option not implemented + + const char *filename; + JSONObject *project_json = read_project(&filename); + + + // TODO! check if target is specified and exists (NULL at the moment) + JSONObject *libraries_json = json_obj_get(project_json, "dependencies"); + + const char** dependencies = NULL; + for(int i = 0; i < libraries_json->array_len; i++) + { + vec_add(dependencies, libraries_json->elements[i]->str); + } + + // check if libraries are already present + FOREACH(const char*, lib, libs) + { + if (str_findlist(lib, vec_size(dependencies), dependencies)!=-1) continue; + + vec_add(dependencies, lib); + } + + JSONObject** elements = NULL; + + FOREACH(const char*, dep, dependencies) + { + JSONObject* obj = json_new_object(&malloc_arena, J_STRING); + obj->str = dep; + vec_add(elements, obj); + } + + // TODO fancier functions for altering JSON file (quite cumbersome at the moment) + // TODO! check if "dependency" entry exists in the project.json file. + + // Apply changes to JSON object + + libraries_json->elements = elements; + libraries_json->array_len = vec_size(dependencies); + + // write to project json file + FILE *file = fopen(filename, "w"); + print_json_to_file(project_json, file); + fclose(file); + +} + void add_target_project(BuildOptions *build_options) { const char *filename; diff --git a/src/compiler/compiler.c b/src/compiler/compiler.c index bc6b996af..51f4096c6 100644 --- a/src/compiler/compiler.c +++ b/src/compiler/compiler.c @@ -3,6 +3,7 @@ // a copy of which can be found in the LICENSE file. #include "compiler_internal.h" +#include "../build/project.h" #include #include "../utils/whereami.h" #if PLATFORM_POSIX @@ -862,25 +863,55 @@ static void setup_bool_define(const char *id, bool value) } } #if FETCH_AVAILABLE + +const char * vendor_fetch_single(const char* lib, const char* path) +{ + const char *resource = str_printf("/c3lang/vendor/releases/download/latest/%s.c3l", lib); + const char *destination = file_append_path(path, str_printf("%s.c3l", lib)); + const char *error = download_file("https://github.com", resource, destination); + return error; +} + void vendor_fetch(BuildOptions *options) { unsigned count = 0; + if (str_eq(options->path, DEFAULT_PATH)) + { + // check if there is a project JSON file + if (file_exists(PROJECT_JSON5) || file_exists(PROJECT_JSON)) + { + const char** deps_dirs = get_project_dependency_directories(); + int num_lib = vec_size(deps_dirs); + if (num_lib > 0) options->vendor_download_path = deps_dirs[0]; + + } + + } + + const char** fetched_libraries = NULL; FOREACH(const char *, lib, options->libraries_to_fetch) { - const char *resource = str_printf("/c3lang/vendor/releases/download/latest/%s.c3l", lib); + //TODO : Implement progress bar in the download_file function. printf("Fetching library '%s'...", lib); fflush(stdout); - const char *error = download_file("https://github.com", resource, str_printf("%s.c3l", lib)); + + const char *error = vendor_fetch_single(lib, options->vendor_download_path); + if (!error) { - puts("ok."); + puts("finished."); + vec_add(fetched_libraries, lib); count++; } else { - printf("FAILED: '%s'\n", error); + printf("Failed: '%s'\n", error); } } + + // add fetched library to the dependency list + add_libraries_to_project_file(fetched_libraries, options->project_options.target_name); + if (count == 0) error_exit("Error: Failed to download any libraries."); if (count < vec_size(options->libraries_to_fetch)) error_exit("Error: Only some libraries were downloaded."); } diff --git a/src/utils/json.c b/src/utils/json.c index 8b08a94d2..b4adb82e6 100644 --- a/src/utils/json.c +++ b/src/utils/json.c @@ -8,7 +8,6 @@ JSONObject error = { .type = J_ERROR }; JSONObject true_val = { .type = J_BOOL, .b = true }; JSONObject false_val = { .type = J_BOOL, .b = false }; JSONObject zero_val = { .type = J_NUMBER, .f = 0.0 }; -JSONObject empty_array_val = { .type = J_ARRAY, .array_len = 0 }; JSONObject empty_obj_val = { .type = J_OBJECT, .member_len = 0 }; #define CONSUME(token_) do { if (!consume(parser, token_)) { json_error(parser, "Unexpected character encountered."); return &error; } } while(0) @@ -275,7 +274,12 @@ static inline bool consume(JsonParser *parser, JSONTokenType token) JSONObject *json_parse_array(JsonParser *parser) { CONSUME(T_LBRACKET); - if (consume(parser, T_RBRACKET)) return &empty_array_val; + if (consume(parser, T_RBRACKET)) + { + JSONObject *array = json_new_object(parser->allocator, J_ARRAY); + array->array_len = 0; + return array; + } size_t capacity = 16; JSONObject *array = json_new_object(parser->allocator, J_ARRAY); @@ -440,7 +444,6 @@ bool is_freable(JSONObject *obj) if (obj == &true_val) return false; if (obj == &false_val) return false; if (obj == &zero_val) return false; - if (obj == &empty_array_val) return false; if (obj == &empty_obj_val) return false; return true; }