diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 168163ee2..c0acfa9b5 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -45,6 +45,7 @@ jobs: - name: Build testproject run: | + set PATH=%PATH%;"C:/Program Files/Microsoft Visual Studio/2022/Enterprise/VC/Tools/MSVC/14.40.33807/bin/Hostx64/x64" cd resources/testproject ..\..\build\${{ matrix.build_type }}\c3c.exe --debug-log --emit-llvm run hello_world_win32 dir build\llvm_ir diff --git a/CMakeLists.txt b/CMakeLists.txt index 4f7a37822..894de8500 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -244,6 +244,7 @@ add_executable(c3c src/build/builder.c src/build/build_options.c src/build/project_creation.c + src/build/libraries.c src/compiler/ast.c src/compiler/bigint.c src/compiler/codegen_general.c @@ -256,7 +257,6 @@ add_executable(c3c src/compiler/headers.c src/compiler/json_output.c src/compiler/lexer.c - src/compiler/libraries.c src/compiler/linker.c src/compiler/llvm_codegen.c src/compiler/abi/c_abi_aarch64.c @@ -325,7 +325,8 @@ add_executable(c3c src/compiler/expr.c src/utils/time.c src/utils/http.c - src/compiler/sema_liveness.c) + src/compiler/sema_liveness.c + src/build/common_build.c) if (C3_USE_TB) diff --git a/releasenotes.md b/releasenotes.md index 306f0d554..a76042666 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -13,6 +13,7 @@ - Updated mangling. - Added `$$unaligned_load` and `$$unaligned_store`. - `--no-headers` option to suppress creating headers when generating a library. +- Support c-file compilation in libraries. ### Fixes - Error with unsigned compare in `@ensure` when early returning 0 #1207. diff --git a/resources/testproject/hello_world.c3 b/resources/testproject/hello_world.c3 index 0909b0113..97c720056 100644 --- a/resources/testproject/hello_world.c3 +++ b/resources/testproject/hello_world.c3 @@ -1,6 +1,7 @@ module hello_world; import std; import bar; +import clib; fn int test_doubler(int x) @if(env::WIN32) => x * x; extern fn int test_doubler(int) @if(!env::WIN32); @@ -12,6 +13,6 @@ fn int main() bar::test(); printf("Hello double: %d\n", test_doubler(11)); if ($feature(ABCD)) io::printn("ABCD"); - + clib::hello_from_c(); return 0; } \ No newline at end of file diff --git a/resources/testproject/lib/clib.c3l/clib.c3i b/resources/testproject/lib/clib.c3l/clib.c3i new file mode 100644 index 000000000..dee7235d9 --- /dev/null +++ b/resources/testproject/lib/clib.c3l/clib.c3i @@ -0,0 +1,3 @@ +module clib; + +extern fn void hello_from_c(); diff --git a/resources/testproject/lib/clib.c3l/hello.c b/resources/testproject/lib/clib.c3l/hello.c new file mode 100644 index 000000000..85c7216b1 --- /dev/null +++ b/resources/testproject/lib/clib.c3l/hello.c @@ -0,0 +1,5 @@ +#include +void hello_from_c(void) +{ + puts("Hello from C!"); +} \ No newline at end of file diff --git a/resources/testproject/lib/clib.c3l/manifest.json b/resources/testproject/lib/clib.c3l/manifest.json new file mode 100644 index 000000000..8169c6505 --- /dev/null +++ b/resources/testproject/lib/clib.c3l/manifest.json @@ -0,0 +1,13 @@ +{ + "provides" : "clib", + "c-sources" : ["hello.c"], + "targets" : { + "macos-x64" : { + }, + "macos-aarch64" : {}, + "linux-x64" : { + "c-flags-override": "-fPIE" + }, + "windows-x64" : { } + } +} diff --git a/resources/testproject/project.json b/resources/testproject/project.json index 68e21e6e3..9698f7010 100644 --- a/resources/testproject/project.json +++ b/resources/testproject/project.json @@ -11,23 +11,23 @@ "sources": [ "./**" ], - // libraries to use - "dependencies": [], + "dependency-search-paths": [ "./lib" ], + "dependencies": ["clib"], "features": ["ABCD"], - // c compiler - "cc": "cc", // c sources "targets": { "hello_world": { "type": "executable", "c-sources-override": [ "./csource/**" - ] + ], + "reloc": "PIE", }, "hello_world_win32": { "type": "executable", + "cc" : "cl.exe", "c-sources-override": [ ] }, diff --git a/src/build/build.h b/src/build/build.h index 75a34040b..a5f1b8765 100644 --- a/src/build/build.h +++ b/src/build/build.h @@ -419,19 +419,27 @@ typedef enum typedef struct { + struct Library__ *parent; ArchOsTarget arch_os; + const char *cc; + const char *cflags; + const char **csource_dirs; + const char **csources; const char **execs; const char **link_flags; const char **linked_libs; const char **depends; } LibraryTarget; -typedef struct +typedef struct Library__ { const char *dir; const char *provides; const char **depends; const char **execs; + const char *cc; + const char *cflags; + const char **csource_dirs; LibraryTarget *target_used; LibraryTarget **targets; } Library; @@ -441,6 +449,7 @@ typedef struct { TargetType type; Library **library_list; + LibraryTarget **ccompling_libraries; const char *name; const char *version; const char *langrev; @@ -501,9 +510,9 @@ typedef struct const char *testfn; const char *cc; const char *cflags; - const char **exec; const char **csource_dirs; const char **csources; + const char **exec; const char **feature_list; const char *custom_linker_path; struct @@ -566,7 +575,7 @@ static BuildTarget default_build_target = { .strip_unused = STRIP_UNUSED_NOT_SET, .symtab_size = DEFAULT_SYMTAB_SIZE, .reloc_model = RELOC_DEFAULT, - .cc = "cc", + .cc = NULL, .version = "1.0.0", .langrev = "1", .cpu = "generic", @@ -591,3 +600,4 @@ bool command_accepts_files(CompilerCommand command); void update_build_target_with_opt_level(BuildTarget *target, OptimizationSetting level); void create_project(BuildOptions *build_options); void create_library(BuildOptions *build_options); +void resolve_libraries(BuildTarget *build_target); \ No newline at end of file diff --git a/src/build/build_internal.h b/src/build/build_internal.h index 6e51b992c..7e142bd70 100644 --- a/src/build/build_internal.h +++ b/src/build/build_internal.h @@ -12,6 +12,8 @@ typedef struct BuildTarget **targets; } Project; +extern const char *trust_level[3]; + static const char *memory_environment[6] = { [MEMORY_ENV_NORMAL] = "normal", [MEMORY_ENV_SMALL] = "small", @@ -85,3 +87,15 @@ static const char *reloc_models[5] = { Project *project_load(void); BuildTarget *project_select_target(Project *project, const char *optional_target); void update_feature_flags(const char ***flags, const char ***removed_flag, const char *arg, bool add); + +const char *get_string(const char *file, const char *category, JSONObject *table, const char *key, + const char *default_value); +int get_valid_bool(const char *file, const char *target, JSONObject *json, const char *key, int default_val); +const char *get_optional_string(const char *file, const char *category, JSONObject *table, const char *key); +const char *get_mandatory_string(const char *file, const char *category, JSONObject *object, const char *key); +const char **get_string_array(const char *file, const char *category, JSONObject *table, const char *key, bool mandatory); +const char **get_optional_string_array(const char *file, const char *target, JSONObject *table, const char *key); +const char *get_cflags(const char *file, const char *target, JSONObject *json, const char *original_flags); +void get_list_append_strings(const char *file, const char *target, JSONObject *json, const char ***list_ptr, + const char *base, const char *override, const char *add); +int get_valid_string_setting(const char *file, const char *target, JSONObject *json, const char *key, const char** values, int first_result, int count, const char *expected); diff --git a/src/build/common_build.c b/src/build/common_build.c new file mode 100644 index 000000000..aac546a7e --- /dev/null +++ b/src/build/common_build.c @@ -0,0 +1,135 @@ +#include "build_internal.h" +#include "utils/common.h" + +const char *get_optional_string(const char *file, const char *category, JSONObject *table, const char *key) +{ + JSONObject *value = json_obj_get(table, key); + if (!value) return NULL; + if (value->type != J_STRING) + { + if (category) error_exit("In file '%s': '%s' had an invalid '%s' field that was not a string, please correct it.", file, category, key); + error_exit("File '%s' had an invalid '%s' field that was not a string, please correct it.", file, category, key); + } + return value->str; +} + +const char *get_mandatory_string(const char *file, const char *category, JSONObject *object, const char *key) +{ + const char *value = get_optional_string(file, category, object, key); + if (!value) + { + if (category) error_exit("In file '%s': The mandatory field '%s' was missing in '%s'.", file, key, category); + error_exit("In file '%s': The mandatory field '%s' was missing.", file); + } + return value; +} + +const char *get_string(const char *file, const char *category, JSONObject *table, const char *key, + const char *default_value) +{ + const char *value = get_optional_string(file, category, table, key); + return value ? value : default_value; +} + + +int get_valid_bool(const char *file, const char *target, JSONObject *json, const char *key, int default_val) +{ + JSONObject *value = json_obj_get(json, key); + if (!value) return default_val; + if (value->type != J_BOOL) + { + if (target) error_exit("In file '%s': '%s' had an invalid '%s' field that was not a boolean, please correct it.", file, target, key); + error_exit("In file '%s': An invalid '%s' field that was not a boolean, please correct it.", file, target, key); + } + return value->b; +} + +const char **get_string_array(const char *file, const char *category, JSONObject *table, const char *key, bool mandatory) +{ + JSONObject *value = json_obj_get(table, key); + if (!value) + { + if (mandatory) + { + if (category) error_exit("In file '%s': '%s' was missing a mandatory '%s' field, please add it.", file, category, key); + error_exit("In file '%s': mandatory '%s' field is missing, please add it.", file, key); + } + return NULL; + } + if (value->type != J_ARRAY) goto NOT_ARRAY; + const char **values = NULL; + for (unsigned i = 0; i < value->array_len; i++) + { + JSONObject *val = value->elements[i]; + if (val->type != J_STRING) goto NOT_ARRAY; + vec_add(values, val->str); + } + return values; +NOT_ARRAY: + if (category) error_exit("In file '%s': '%s' had an invalid mandatory '%s' field that was not a string array, please correct it", file, category, key); + error_exit("In file '%s': mandatory '%s' field that was not a string array, please correct it.", file, key); +} + +const char **get_optional_string_array(const char *file, const char *target, JSONObject *table, const char *key) +{ + return get_string_array(file, target, table, key, false); +} + +const char *get_cflags(const char *file, const char *target, JSONObject *json, const char *original_flags) +{ + // CFlags + const char *cflags = get_optional_string(file, target, json, target ? "cflags-override" : "cflags"); + const char *cflags_add = target ? get_optional_string(file, target, json, "cflags-add") : NULL; + if (cflags && cflags_add) + { + error_exit("In file '%s': '%s' is combining both 'cflags-add' and 'cflags-override', only one may be used.", file, target); + } + if (cflags) original_flags = cflags; + if (!cflags_add) return original_flags; + if (original_flags) + { + return str_printf("%s %s", original_flags, cflags_add); + } + return cflags_add; +} + +INLINE void append_strings_to_strings(const char*** list_of_strings_ptr, const char **strings_to_append) +{ + FOREACH(const char *, string, strings_to_append) vec_add(*list_of_strings_ptr, string); +} + +void get_list_append_strings(const char *file, const char *target, JSONObject *json, const char ***list_ptr, + const char *base, const char *override, const char *add) +{ + const char **value = get_optional_string_array(file, target, json, target ? override : base); + const char **add_value = target ? get_optional_string_array(file, target, json, add) : NULL; + if (value && add_value) + { + error_exit("In file '%s': '%s' is combining both '%s' and '%s', only one may be used.", file, target, override, add); + } + if (value) *list_ptr = value; + if (add_value) + { + append_strings_to_strings(&add_value, *list_ptr); + *list_ptr = add_value; + } +} + +int get_valid_string_setting(const char *file, const char *target, JSONObject *json, const char *key, const char** values, int first_result, int count, const char *expected) +{ + JSONObject *value = json_obj_get(json, key); + if (!value) + { + return -1; + } + if (value->type == J_STRING) + { + int res = str_findlist(value->str, count, values); + if (res >= 0) return res + first_result; + } + if (target) + { + error_exit("In file '%s': '%s' had an invalid value for '%s', expected %s", file, target, key, expected); + } + error_exit("In file '%s': Invalid value for '%s', expected %s", file, key, expected); +} diff --git a/src/compiler/libraries.c b/src/build/libraries.c similarity index 61% rename from src/compiler/libraries.c rename to src/build/libraries.c index 21004bdd3..cdf638bb1 100644 --- a/src/compiler/libraries.c +++ b/src/build/libraries.c @@ -1,49 +1,10 @@ -#include "compiler_internal.h" -#include "../utils/json.h" +#include "build_internal.h" +#include "compiler/compiler.h" #define MANIFEST_FILE "manifest.json" -static inline void parse_library_target(Library *library, LibraryTarget *target, JSONObject *object); - -static inline JSONObject *get_mandatory(Library *library, JSONObject *object, const char *key) -{ - JSONObject *value = json_obj_get(object, key); - if (!value) error_exit("The mandatory '%s' field was missing in '%s'.", library->dir); - return value; -} - -static inline const char *get_mandatory_string(Library *library, JSONObject *object, const char *key) -{ - JSONObject *value = get_mandatory(library, object, key); - if (value->type != J_STRING) error_exit("Expected string value for '%s' in '%s'.", library->dir); - return value->str; -} - -static inline JSONObject *get_optional_string_array(Library *library, JSONObject *object, const char *key) -{ - JSONObject *value = json_obj_get(object, key); - if (!value) return NULL; - if (value->type != J_ARRAY) error_exit("Expected an array value for '%s' in '%s'.", library->dir); - for (int i = 0; i < value->array_len; i++) - { - JSONObject *val = value->elements[i]; - if (val->type != J_STRING) error_exit("Expected only strings in array '%s' in '%s'.", library->dir); - } - return value; -} - -static inline const char **get_optional_string_array_as_array(Library *library, JSONObject *object, const char *key) -{ - JSONObject *array = get_optional_string_array(library, object, key); - if (!array || !array->array_len) return NULL; - const char **array_result = VECNEW(const char*, array->array_len); - for (size_t i = 0; i < array->array_len; i++) - { - vec_add(array_result, array->elements[i]->str); - } - return array_result; -} - +static inline void parse_library_target(Library *library, LibraryTarget *target, const char *target_name, + JSONObject *object); static inline void parse_library_type(Library *library, LibraryTarget ***target_group, JSONObject *object) { @@ -55,6 +16,7 @@ static inline void parse_library_type(Library *library, LibraryTarget ***target_ const char *key = object->keys[i]; if (member->type != J_OBJECT) error_exit("Expected a list of properties for a target in %s.", library->dir); LibraryTarget *library_target = CALLOCS(LibraryTarget); + library_target->parent = library; ArchOsTarget target = arch_os_target_from_string(key); if (target == ARCH_OS_TARGET_DEFAULT) { @@ -62,39 +24,45 @@ static inline void parse_library_type(Library *library, LibraryTarget ***target_ } library_target->arch_os = target; vec_add(*target_group, library_target); - parse_library_target(library, library_target, member); + parse_library_target(library, library_target, key, member); } } -static inline void parse_library_target(Library *library, LibraryTarget *target, JSONObject *object) +static inline void parse_library_target(Library *library, LibraryTarget *target, const char *target_name, + JSONObject *object) { - target->link_flags = get_optional_string_array_as_array(library, object, "linkflags"); - target->linked_libs = get_optional_string_array_as_array(library, object, "linked-libs"); - target->depends = get_optional_string_array_as_array(library, object, "depends"); - target->execs = get_optional_string_array_as_array(library, object, "execs"); + target->link_flags = get_string_array(library->dir, target_name, object, "linkflags", false); + target->linked_libs = get_string_array(library->dir, target_name, object, "linked-libs", false); + target->depends = get_string_array(library->dir, target_name, object, "depends", false); + target->execs = get_string_array(library->dir, target_name, object, "execs", false); + target->cc = get_string(library->dir, target_name, object, "cc", library->cc); + target->cflags = get_cflags(library->dir, target_name, object, library->cflags); + target->csource_dirs = library->csource_dirs; + get_list_append_strings(library->dir, target_name, object, &target->csource_dirs, "c-sources", "c-sources-override", "c-sources-add"); } static Library *add_library(JSONObject *object, const char *dir) { Library *library = CALLOCS(Library); library->dir = dir; - const char *provides = get_mandatory_string(library, object, "provides"); + const char *provides = get_mandatory_string(dir, NULL, object, "provides"); + DEBUG_LOG("Added library %s", provides); if (!str_is_valid_lowercase_name(provides)) { char *res = strdup(provides); str_ellide_in_place(res, 32); - error_exit("Invalid 'provides' module name in %s, was '%s'.", library->dir, - json_obj_get(object, "provides")->str); + error_exit("Invalid 'provides' module name in %s, was '%s'.", library->dir, res); } library->provides = provides; - library->execs = get_optional_string_array_as_array(library, object, "execs"); - library->depends = get_optional_string_array_as_array(library, object, "depends"); + library->execs = get_optional_string_array(library->dir, NULL, object, "execs"); + library->depends = get_optional_string_array(library->dir, NULL, object, "depends"); + library->cc = get_optional_string(dir, NULL, object, "cc"); + library->cflags = get_cflags(library->dir, NULL, object, NULL); + get_list_append_strings(library->dir, NULL, object, &library->csource_dirs, "c-sources", "c-sources-override", "c-sources-add"); parse_library_type(library, &library->targets, json_obj_get(object, "targets")); return library; } - - static Library *find_library(Library **libs, size_t lib_count, const char *name) { for (size_t i = 0; i < lib_count; i++) @@ -104,13 +72,13 @@ static Library *find_library(Library **libs, size_t lib_count, const char *name) error_exit("Required library '%s' could not be found. You can add additional library search paths using '--libdir' in case you forgot one.", name); } -static void add_library_dependency(Library *library, Library **library_list, size_t lib_count) +static void add_library_dependency(BuildTarget *build_target, Library *library, Library **library_list, size_t lib_count) { if (library->target_used) return; LibraryTarget *target_found = NULL; FOREACH(LibraryTarget *, target, library->targets) { - if (target->arch_os == active_target.arch_os_target) + if (target->arch_os == build_target->arch_os_target) { target_found = target; break; @@ -118,16 +86,17 @@ static void add_library_dependency(Library *library, Library **library_list, siz } if (!target_found) { - error_exit("Library '%s' cannot be used with arch/os '%s'.", library->provides, arch_os_target[active_target.arch_os_target]); + error_exit("Library '%s' cannot be used with arch/os '%s'.", library->provides, arch_os_target[build_target->arch_os_target]); } library->target_used = target_found; FOREACH(const char *, dependency, library->depends) { - add_library_dependency(find_library(library_list, lib_count, dependency), library_list, lib_count); + add_library_dependency(build_target, find_library(library_list, lib_count, dependency), library_list, lib_count); } FOREACH(const char *, dependency, target_found->depends) { - add_library_dependency(find_library(library_list, lib_count, dependency), + add_library_dependency(build_target, + find_library(library_list, lib_count, dependency), library_list, lib_count); } @@ -150,7 +119,7 @@ INLINE JSONObject* read_manifest(const char *lib, const char *manifest_data) return json; } -static inline JSONObject *resolve_zip_library(const char *lib, const char **resulting_library) +static inline JSONObject *resolve_zip_library(BuildTarget *build_target, const char *lib, const char **resulting_library) { FILE *f = fopen(lib, "rb"); if (!f) error_exit("Failed to open library '%s' for reading.", lib); @@ -176,7 +145,7 @@ static inline JSONObject *resolve_zip_library(const char *lib, const char **resu // Create the directory for the temporary files. const char *lib_name = filename(lib); scratch_buffer_clear(); - scratch_buffer_append(active_target.build_dir ? active_target.build_dir : "_temp_build"); + scratch_buffer_append(build_target->build_dir ? build_target->build_dir : "_temp_build"); scratch_buffer_printf("/_c3l/%s_%x/", lib_name, file.file_crc32); const char *lib_dir = scratch_buffer_copy(); dir_make_recursive(scratch_buffer_to_string()); @@ -197,21 +166,24 @@ static inline JSONObject *resolve_zip_library(const char *lib, const char **resu return json; } -void resolve_libraries(void) +void resolve_libraries(BuildTarget *build_target) { + DEBUG_LOG("Resolve libraries"); static const char *c3lib_suffix = ".c3l"; const char **c3_libs = NULL; - unsigned libdir_count = vec_size(active_target.libdirs); + unsigned libdir_count = vec_size(build_target->libdirs); if (libdir_count) { - FOREACH(const char *, dir, active_target.libdirs) + FOREACH(const char *, dir, build_target->libdirs) { + DEBUG_LOG("Search %s", dir); file_add_wildcard_files(&c3_libs, dir, false, &c3lib_suffix, 1); } } else { // Default to '.' + DEBUG_LOG("Search '.'"); file_add_wildcard_files(&c3_libs, ".", false, &c3lib_suffix, 1); } Library *libraries[MAX_LIB_DIRS * 2]; @@ -221,7 +193,7 @@ void resolve_libraries(void) JSONObject *json; if (!file_is_dir(lib)) { - json = resolve_zip_library(lib, &lib); + json = resolve_zip_library(build_target, lib, &lib); } else { @@ -232,24 +204,28 @@ void resolve_libraries(void) if (lib_count == MAX_LIB_DIRS * 2) error_exit("Too many libraries added, exceeded %d.", MAX_LIB_DIRS * 2); libraries[lib_count++] = add_library(json, lib); } - FOREACH(const char *, lib_name, active_target.libs) + FOREACH(const char *, lib_name, build_target->libs) { - add_library_dependency(find_library(libraries, lib_count, lib_name), libraries, lib_count); + add_library_dependency(build_target, find_library(libraries, lib_count, lib_name), libraries, lib_count); } for (size_t i = 0; i < lib_count; i++) { Library *library = libraries[i]; LibraryTarget *target = library->target_used; if (!target) continue; - file_add_wildcard_files(&active_target.sources, library->dir, false, c3_suffix_list, 3); - vec_add(active_target.library_list, library); - const char *libdir = file_append_path(library->dir, arch_os_target[active_target.arch_os_target]); - if (file_is_dir(libdir)) vec_add(active_target.linker_libdirs, libdir); - if ((vec_size(library->execs) || vec_size(target->execs)) && active_target.trust_level < TRUST_FULL) + if (vec_size(target->csource_dirs)) + { + vec_add(build_target->ccompling_libraries, target); + } + file_add_wildcard_files(&build_target->sources, library->dir, false, c3_suffix_list, 3); + vec_add(build_target->library_list, library); + const char *libdir = file_append_path(library->dir, arch_os_target[build_target->arch_os_target]); + if (file_is_dir(libdir)) vec_add(build_target->linker_libdirs, libdir); + if ((vec_size(library->execs) || vec_size(target->execs)) && build_target->trust_level < TRUST_FULL) { error_exit("Could not use library '%s' as it requires 'exec' trust level to execute (it " "is currently '%s'). Use the '--trust=full' option to enable it.", - library->provides, trust_level[active_target.trust_level]); + library->provides, trust_level[build_target->trust_level]); } FOREACH(const char *, exec, library->execs) { diff --git a/src/build/project.c b/src/build/project.c index 20a8553ea..cca127336 100644 --- a/src/build/project.c +++ b/src/build/project.c @@ -4,8 +4,13 @@ #include #include "build_internal.h" +#include "utils/json.h" + #define MAX_SYMTAB_SIZE (1024 * 1024) +#define GET_SETTING(type__, key__, strings__, comment__) \ + (type__)get_valid_string_setting(PROJECT_JSON, target_name, json, key__, strings__, 0, ELEMENTLEN(strings__), comment__) + const char *project_default_keys[][2] = { {"authors", "Authors, optionally with email."}, {"benchfn", "Override the benchmark function."}, @@ -120,54 +125,6 @@ const char* project_target_keys[][2] = { const int project_target_keys_count = ELEMENTLEN(project_target_keys); -static const char *get_string(JSONObject *table, const char *key, const char *category, const char *default_value) -{ - JSONObject *value = json_obj_get(table, key); - if (!value) return default_value; - if (value->type != J_STRING) - { - error_exit("%s had an invalid '%s' field that was not a string, please correct it.", category, key); - } - return value->str; -} - -static const char *get_valid_string(JSONObject *table, const char *key, const char *category) -{ - JSONObject *value = json_obj_get(table, key); - if (!value) return NULL; - if (value->type != J_STRING) - { - error_exit("%s had an invalid '%s' field that was not a string, please correct it.", category, key); - } - return value->str; -} - -int get_valid_bool(JSONObject *json, const char *key, const char *category, int default_val) -{ - JSONObject *value = json_obj_get(json, key); - if (!value) return default_val; - if (value->type != J_BOOL) - { - error_exit("%s had an invalid mandatory '%s' field that was not a boolean, please correct it.", category, key); - } - return value->b; -} - - -static int get_valid_string_setting(JSONObject *json, const char *key, const char *category, const char** values, int first_result, int count, const char *expected) -{ - JSONObject *value = json_obj_get(json, key); - if (!value) - { - return -1; - } - if (value->type == J_STRING) - { - int res = str_findlist(value->str, count, values); - if (res >= 0) return res + first_result; - } - error_exit("%s had an invalid value for '%s', expected %s", category, key, expected); -} long get_valid_integer(JSONObject *table, const char *key, const char *category, bool mandatory) { @@ -187,36 +144,7 @@ long get_valid_integer(JSONObject *table, const char *key, const char *category, return (long)trunc(value->f); } - -static const char **get_valid_array(JSONObject *table, const char *key, const char *category, bool mandatory) -{ - JSONObject *value = json_obj_get(table, key); - if (!value) - { - if (mandatory) - { - error_exit("Error reading %s: %s was missing a mandatory '%s' field, please add it.", PROJECT_JSON, category, key); - } - return NULL; - } - if (value->type != J_ARRAY) - { - error_exit("Error reading %s: %s had an invalid mandatory '%s' field that was not an array, please correct it.", PROJECT_JSON, category, key); - } - const char **values = NULL; - for (unsigned i = 0; i < value->array_len; i++) - { - JSONObject *val = value->elements[i]; - if (val->type != J_STRING) - { - error_exit("Error reading %s: %s had an invalid mandatory '%s' array that did not only hold strings, please correct it.", PROJECT_JSON, category, key); - } - vec_add(values, val->str); - } - return values; -} - -static void check_json_keys(const char* valid_keys[][2], size_t key_count, JSONObject *json, const char *type) +static void check_json_keys(const char* valid_keys[][2], size_t key_count, JSONObject *json, const char *target_name) { static bool failed_shown = false; bool failed = false; @@ -227,7 +155,7 @@ static void check_json_keys(const char* valid_keys[][2], size_t key_count, JSONO { if (strcmp(key, valid_keys[j][0]) == 0) goto OK; } - eprintf("WARNING: Unknown parameter '%s' in '%s'.\n", key, type); + eprintf("WARNING: Unknown parameter '%s' in '%s'.\n", key, target_name ? target_name : "default_target"); failed = true; OK:; } @@ -238,103 +166,48 @@ static void check_json_keys(const char* valid_keys[][2], size_t key_count, JSONO } } -INLINE void append_strings_to_strings(const char*** list_of_strings_ptr, const char **strings_to_append) +static void load_into_build_target(JSONObject *json, const char *target_name, BuildTarget *target) { - FOREACH(const char *, string, strings_to_append) + if (target_name) { - vec_add(*list_of_strings_ptr, string); - } -} - -static void target_append_strings(JSONObject *json, const char *type, const char ***list_ptr, const char *base, const char *override, const char *add, bool is_default) -{ - const char **value = get_valid_array(json, is_default ? base : override, type, false); - const char **add_value = is_default ? NULL : get_valid_array(json, add, type, false); - if (value && add_value) - { - error_exit("'%s' is combining both '%s' and '%s', only one may be used.", type, override, add); - } - if (value) *list_ptr = value; - if (add_value) - { - append_strings_to_strings(&add_value, *list_ptr); - *list_ptr = add_value; - } -} -static void load_into_build_target(JSONObject *json, const char *type, BuildTarget *target, bool is_default) -{ - if (is_default) - { - check_json_keys(project_default_keys, project_default_keys_count, json, type); + check_json_keys(project_target_keys, project_target_keys_count, json, target_name); } else { - check_json_keys(project_target_keys, project_target_keys_count, json, type); + check_json_keys(project_default_keys, project_default_keys_count, json, NULL); } - target->cc = get_string(json, "cc", type, target->cc); + target->cc = get_string(PROJECT_JSON, target_name, json, "cc", target->cc); - target->script_dir = get_string(json, "script-dir", type, target->script_dir); + target->script_dir = get_string(PROJECT_JSON, target_name, json, "script-dir", target->script_dir); // Exec - const char **exec = get_valid_array(json, is_default ? "exec" : "exec-override" , type, false); - const char **exec_add = is_default ? NULL : get_valid_array(json, "exec-add" , type, false); - if (exec && exec_add) - { - error_exit("'%s' is combining both 'exec-add' and 'exec-override', only one may be used.", type); - } - if (exec_add && !target->exec) - { - target->exec = exec_add; - exec_add = NULL; - } - if (exec) target->exec = exec; - if (exec_add) - { - assert(target->exec); - FOREACH(const char *, exec_command, exec_add) vec_add(target->exec, exec_command); - } - - target->output_dir = get_string(json, "output", type, target->output_dir); + get_list_append_strings(PROJECT_JSON, target_name, json, &target->exec, "exec", "exec-override", "exec-add"); + + target->output_dir = get_string(PROJECT_JSON, target_name, json,"output", target->output_dir); // CFlags - const char *cflags = get_valid_string(json, is_default ? "cflags" : "cflags-override" , type); - const char *cflags_add = is_default ? NULL : get_valid_string(json, "cflags-add" , type); - if (cflags && cflags_add) - { - error_exit("'%s' is combining both 'cflags-add' and 'cflags-override', only one may be used.", type); - } - if (cflags) target->cflags = cflags; - if (cflags_add) - { - if (target->cflags) - { - target->cflags = str_printf("%s %s", target->cflags, cflags_add); - } - else - { - target->cflags = cflags_add; - } - } + target->cflags = get_cflags(PROJECT_JSON, target_name, json, target->cflags); + // C source dirs. - target_append_strings(json, type, &target->csource_dirs, "c-sources", "c-sources-override", "c-sources-add", is_default); + get_list_append_strings(PROJECT_JSON, target_name, json, &target->csource_dirs, "c-sources", "c-sources-override", "c-sources-add"); // Sources - target_append_strings(json, type, &target->source_dirs, "sources", "sources-override", "sources-add", is_default); + get_list_append_strings(PROJECT_JSON, target_name, json, &target->source_dirs, "sources", "sources-override", "sources-add"); // Linked-libraries - libraries to add at link time - target_append_strings(json, type, &target->linker_libs, "linked-libraries", "linked-libraries-override", "linked-libraries-add", is_default); + get_list_append_strings(PROJECT_JSON, target_name, json, &target->linker_libs, "linked-libraries", "linked-libraries-override", "linked-libraries-add"); // linker-search-paths libs dir - libraries to add at link time - target_append_strings(json, type, &target->linker_libdirs, "linker-search-paths", "linker-search-paths-override", "linker-search-paths-add", is_default); + get_list_append_strings(PROJECT_JSON, target_name, json, &target->linker_libdirs, "linker-search-paths", "linker-search-paths-override", "linker-search-paths-add"); // link-args - link args to add at link time - target_append_strings(json, type, &target->link_args, "link-args", "link-args-override", "link-args-add", is_default); + get_list_append_strings(PROJECT_JSON, target_name, json, &target->link_args, "link-args", "link-args-override", "link-args-add"); // dependency-search-paths - path to search for libraries - target_append_strings(json, type, &target->libdirs, "dependency-search-paths", "dependency-search-paths-override", "dependency-search-paths-add", is_default); + get_list_append_strings(PROJECT_JSON, target_name, json, &target->libdirs, "dependency-search-paths", "dependency-search-paths-override", "dependency-search-paths-add"); // Dependencies - target_append_strings(json, type, &target->libs, "dependencies", "dependencies-override", "dependencies-add", is_default); + get_list_append_strings(PROJECT_JSON, target_name, json, &target->libs, "dependencies", "dependencies-override", "dependencies-add"); FOREACH(const char *, name, target->libs) { if (!str_is_valid_lowercase_name(name)) @@ -351,16 +224,14 @@ static void load_into_build_target(JSONObject *json, const char *type, BuildTarg [DEBUG_INFO_NONE] = "none", [DEBUG_INFO_LINE_TABLES] = "line-tables" }; - DebugInfo info = get_valid_string_setting(json, "debug-info", type, debug_infos, 0, ELEMENTLEN(debug_infos), "one of 'full' 'line-table' or 'none'."); + DebugInfo info = GET_SETTING(DebugInfo, "debug-info", debug_infos, "one of 'full' 'line-table' or 'none'."); if (info > -1) target->debug_info = info; // Optimization Level - OptimizationLevel optlevel = (OptimizationLevel)get_valid_string_setting(json, "optlevel", type, optlevels, 0, ELEMENTLEN(optlevels), "`none`, `less`, `more`, `max`."); - target->optlevel = optlevel; + target->optlevel = GET_SETTING(OptimizationLevel, "optlevel", optlevels, "`none`, `less`, `more`, `max`."); // Size optimization - SizeOptimizationLevel optsize = (SizeOptimizationLevel)get_valid_string_setting(json, "optsize", type, optsizes, 0, ELEMENTLEN(optlevels), "`none`, `small`, `tiny`."); - target->optsize = optsize; + target->optsize = GET_SETTING(SizeOptimizationLevel, "optsize", optlevels, "`none`, `small`, `tiny`."); static const char *opt_settings[8] = { [OPT_SETTING_O0] = "O0", @@ -372,62 +243,63 @@ static void load_into_build_target(JSONObject *json, const char *type, BuildTarg [OPT_SETTING_OSMALL] = "Os", [OPT_SETTING_OTINY] = "Oz" }; - OptimizationSetting opt = (OptimizationSetting)get_valid_string_setting(json, "opt", type, opt_settings, 0, ELEMENTLEN(opt_settings), "'O0', 'O1' etc."); + OptimizationSetting opt = GET_SETTING(OptimizationSetting, "opt", opt_settings, "'O0', 'O1' etc."); if (opt != OPT_SETTING_NOT_SET) target->optsetting = opt; // Safety level - target->feature.safe_mode = (SafetyLevel)get_valid_bool(json, "safe", type, target->feature.safe_mode); + target->feature.safe_mode = (SafetyLevel)get_valid_bool(PROJECT_JSON, target_name, json, "safe", target->feature.safe_mode); // Panic level - target->feature.panic_level = (PanicLevel)get_valid_bool(json, "panic-msg", type, target->feature.panic_level); + target->feature.panic_level = (PanicLevel)get_valid_bool(PROJECT_JSON, target_name, json, "panic-msg", + target->feature.panic_level); // Single module - target->single_module = (SingleModule)get_valid_bool(json, "single-module", type, target->single_module); + target->single_module = (SingleModule) get_valid_bool(PROJECT_JSON, target_name, json, "single-module", target->single_module); // Memory environment for memory constrained environments. - MemoryEnvironment env = get_valid_string_setting(json, "memory-env", type, memory_environment, 0, ELEMENTLEN(memory_environment), "one of 'normal', 'small', 'tiny' or 'none'."); - if (env > -1) target->memory_environment = env; + MemoryEnvironment env = GET_SETTING(MemoryEnvironment, "memory-env", memory_environment, "one of 'normal', 'small', 'tiny' or 'none'."); + if (env != MEMORY_ENV_NOT_SET) target->memory_environment = env; // Symtab - long symtab_size = get_valid_integer(json, "symtab", type, false); + long symtab_size = get_valid_integer(json, "symtab", target_name, false); if (symtab_size > 0) { if (symtab_size < 1024) { - error_exit("Error reading %s: %s symtab was less than 1024.", PROJECT_JSON, type); + error_exit("Error reading %s: %s symtab was less than 1024.", PROJECT_JSON, target_name); } if (symtab_size > MAX_SYMTAB_SIZE) { - error_exit("Error reading %s: %s symtab may not exceed %d.", PROJECT_JSON, type, MAX_SYMTAB_SIZE); + error_exit("Error reading %s: %s symtab may not exceed %d.", PROJECT_JSON, target_name, MAX_SYMTAB_SIZE); } target->symtab_size = (uint32_t)symtab_size; } // Target - const char *arch_os_string = get_valid_string(json, "target", type); + const char *arch_os_string = get_optional_string(PROJECT_JSON, target_name, json, "target"); if (arch_os_string) { ArchOsTarget arch_os = arch_os_target_from_string(arch_os_string); - if (arch_os == ARCH_OS_TARGET_DEFAULT) error_exit("Error reading %s: %s target was not valid.", PROJECT_JSON, type); + if (arch_os == ARCH_OS_TARGET_DEFAULT) error_exit("Error reading %s: %s target was not valid.", PROJECT_JSON, target_name); target->arch_os_target = arch_os; } // Reloc - int reloc = get_valid_string_setting(json, "reloc", type, reloc_models, 0, ELEMENTLEN(reloc_models), "'none', 'pic', 'PIC', 'pie' or 'PIE'."); - if (reloc > -1) target->reloc_model = (RelocModel)reloc; + RelocModel reloc = GET_SETTING(RelocModel, "reloc", reloc_models, "'none', 'pic', 'PIC', 'pie' or 'PIE'."); + if (reloc != RELOC_DEFAULT) target->reloc_model = reloc; // Cpu - target->cpu = get_string(json, "cpu", type, target->cpu); + target->cpu = get_string(PROJECT_JSON, target_name, json, "cpu", target->cpu); // WinCRT - int wincrt = get_valid_string_setting(json, "wincrt", type, wincrt_linking, 0, ELEMENTLEN(wincrt_linking), "'none', 'static' or 'dynamic'."); - if (wincrt > -1) target->win.crt_linking = (WinCrtLinking)wincrt; + WinCrtLinking wincrt = GET_SETTING(WinCrtLinking, "wincrt", wincrt_linking, "'none', 'static' or 'dynamic'."); + if (wincrt != WIN_CRT_DEFAULT) target->win.crt_linking = wincrt; // fp-math - int fpmath = get_valid_string_setting(json, "fp-math", type, fp_math, 0, ELEMENTLEN(fp_math), "`strict`, `relaxed` or `fast`."); + FpOpt fpmath = GET_SETTING(FpOpt, "fp-math", fp_math, "`strict`, `relaxed` or `fast`."); if (fpmath > -1) target->feature.fp_math = fpmath; - const char **features = get_valid_array(json, "features", type, false); + const char **features = get_optional_string_array(PROJECT_JSON, target_name, json, "features"); if (features) { FOREACH(const char *, feature, features) @@ -441,61 +313,61 @@ static void load_into_build_target(JSONObject *json, const char *type, BuildTarg } // x86vec - int x86vec = get_valid_string_setting(json, "x86vec", type, x86_vector_capability, 0, ELEMENTLEN(x86_vector_capability), "`none`, `native`, `mmx`, `sse`, `avx` or `avx512`."); + X86VectorCapability x86vec = GET_SETTING(X86VectorCapability, "x86vec", x86_vector_capability, "`none`, `native`, `mmx`, `sse`, `avx` or `avx512`."); if (x86vec > -1) target->feature.x86_vector_capability = x86vec; // x86vec - int x86cpu = get_valid_string_setting(json, "x86cpu", type, x86_cpu_set, 0, ELEMENTLEN(x86_cpu_set), "`baseline`, `ssse3`, `sse4`, `avx1`, `avx2-v1`, `avx2-v2`, `avx512` or `native`."); - if (x86cpu > -1) target->feature.x86_cpu_set = x86cpu; + X86CpuSet x86cpu = GET_SETTING(X86CpuSet, "x86cpu", x86_cpu_set, "`baseline`, `ssse3`, `sse4`, `avx1`, `avx2-v1`, `avx2-v2`, `avx512` or `native`."); + if (x86cpu > X86CPU_DEFAULT) target->feature.x86_cpu_set = x86cpu; // riscvfloat - int riscv_float = get_valid_string_setting(json, "riscvfloat", type, riscv_capability, 0, ELEMENTLEN(riscv_capability), "`none`, `float` or `double`."); - if (riscv_float > -1) target->feature.riscv_float_capability = riscv_float; + RiscvFloatCapability riscv_float = GET_SETTING(RiscvFloatCapability, "riscvfloat", riscv_capability, "`none`, `float` or `double`."); + if (riscv_float != RISCVFLOAT_DEFAULT) target->feature.riscv_float_capability = riscv_float; // winsdk - target->win.sdk = get_string(json, "winsdk", type, target->win.sdk); + target->win.sdk = get_string(PROJECT_JSON, target_name, json, "winsdk", target->win.sdk); // windef - target->win.def = get_string(json, "windef", type, target->win.def); + target->win.def = get_string(PROJECT_JSON, target_name, json, "windef", target->win.def); // macossdk - target->macos.sysroot = get_string(json, "macossdk", type, target->macos.sysroot); + target->macos.sysroot = get_string(PROJECT_JSON, target_name, json, "macossdk", target->macos.sysroot); // macos-min-version - target->macos.min_version = get_string(json, "macos-min-version", type, target->macos.min_version); + target->macos.min_version = get_string(PROJECT_JSON, target_name, json, "macos-min-version", target->macos.min_version); // macos-sdk-version - target->macos.sdk_version = get_string(json, "macos-sdk-version", type, target->macos.sdk_version); + target->macos.sdk_version = get_string(PROJECT_JSON, target_name, json, "macos-sdk-version", target->macos.sdk_version); // Linux crt - target->linuxpaths.crt = get_string(json, "linux-crt", type, target->linuxpaths.crt); + target->linuxpaths.crt = get_string(PROJECT_JSON, target_name, json, "linux-crt", target->linuxpaths.crt); // Linux crtbegin - target->linuxpaths.crtbegin = get_string(json, "linux-crtbegin", type, target->linuxpaths.crtbegin); + target->linuxpaths.crtbegin = get_string(PROJECT_JSON, target_name, json, "linux-crtbegin", target->linuxpaths.crtbegin); // version - target->version = get_string(json, "version", type, target->version); + target->version = get_string(PROJECT_JSON, target_name, json, "version", target->version); // langrev - target->langrev = get_string(json, "langrev", type, target->langrev); + target->langrev = get_string(PROJECT_JSON, target_name, json, "langrev", target->langrev); // panicfn - target->panicfn = get_string(json, "panicfn", type, target->panicfn); + target->panicfn = get_string(PROJECT_JSON, target_name, json, "panicfn", target->panicfn); // testfn - target->testfn = get_string(json, "testfn", type, target->testfn); + target->testfn = get_string(PROJECT_JSON, target_name, json, "testfn", target->testfn); // testfn - target->benchfn = get_string(json, "benchfn", type, target->benchfn); + target->benchfn = get_string(PROJECT_JSON, target_name, json, "benchfn", target->benchfn); // link-libc - target->link_libc = (LinkLibc)get_valid_bool(json, "link-libc", type, target->link_libc); + target->link_libc = (LinkLibc) get_valid_bool(PROJECT_JSON, target_name, json, "link-libc", target->link_libc); // strip-unused - target->strip_unused = (StripUnused)get_valid_bool(json, "strip-unused", type, target->strip_unused); + target->strip_unused = (StripUnused) get_valid_bool(PROJECT_JSON, target_name, json, "strip-unused", target->strip_unused); // linker - const char *linker_selection = get_string(json, "linker", type, NULL); + const char *linker_selection = get_optional_string(PROJECT_JSON, target_name, json, "linker"); if (linker_selection) { if (str_eq("cc", linker_selection)) @@ -516,24 +388,26 @@ static void load_into_build_target(JSONObject *json, const char *type, BuildTarg } // no-entry - target->no_entry = get_valid_bool(json, "no-entry", type, target->no_entry); + target->no_entry = get_valid_bool(PROJECT_JSON, target_name, json, "no-entry", target->no_entry); // use-stdlib - target->use_stdlib = (UseStdlib)get_valid_bool(json, "use-stdlib", type, target->use_stdlib); + target->use_stdlib = (UseStdlib) get_valid_bool(PROJECT_JSON, target_name, json, "use-stdlib", target->use_stdlib); // emit-stdlib - target->emit_stdlib = (EmitStdlib)get_valid_bool(json, "emit-stdlib", type, target->emit_stdlib); + target->emit_stdlib = (EmitStdlib) get_valid_bool(PROJECT_JSON, target_name, json, "emit-stdlib", target->emit_stdlib); // single-module - target->single_module = (SingleModule)get_valid_bool(json, "single-module", type, target->single_module); + target->single_module = (SingleModule) get_valid_bool(PROJECT_JSON, target_name, json, "single-module", target->single_module); // Trap on wrap - target->feature.trap_on_wrap = get_valid_bool(json, "trap-on-wrap", type, target->feature.trap_on_wrap); + target->feature.trap_on_wrap = get_valid_bool(PROJECT_JSON, target_name, json, "trap-on-wrap", target->feature.trap_on_wrap); // Use the fact that they correspond to 0, 1, -1 - target->feature.x86_struct_return = get_valid_bool(json, "x86-stack-struct-return", type, target->feature.x86_struct_return); - target->feature.soft_float = get_valid_bool(json, "soft-float", type, target->feature.soft_float); - target->feature.pass_win64_simd_as_arrays = get_valid_bool(json, "win64-simd-array", type, target->feature.pass_win64_simd_as_arrays); + target->feature.x86_struct_return = get_valid_bool(PROJECT_JSON, target_name, json, "x86-stack-struct-return", + target->feature.x86_struct_return); + target->feature.soft_float = get_valid_bool(PROJECT_JSON, target_name, json, "soft-float", target->feature.soft_float); + target->feature.pass_win64_simd_as_arrays = get_valid_bool(PROJECT_JSON, target_name, json, "win64-simd-array", + target->feature.pass_win64_simd_as_arrays); } static void project_add_target(Project *project, BuildTarget *default_target, JSONObject *json, const char *name, const char *type, TargetType target_type) @@ -553,7 +427,7 @@ static void project_add_target(Project *project, BuildTarget *default_target, J } } type = str_printf("%s %s", type, target->name); - load_into_build_target(json, type, target, false); + load_into_build_target(json, type, target); update_build_target_with_opt_level(target, target->optsetting); } @@ -578,7 +452,7 @@ static void project_add_targets(Project *project, JSONObject *project_data) }; BuildTarget default_target = default_build_target; - load_into_build_target(project_data, "default target", &default_target, true); + load_into_build_target(project_data, NULL, &default_target); JSONObject *targets_json = json_obj_get(project_data, "targets"); if (!targets_json) { @@ -596,7 +470,7 @@ static void project_add_targets(Project *project, JSONObject *project_data) { error_exit("Invalid data in target '%s'", key); } - int type = get_valid_string_setting(object, "type", "Target type", targets, 0, ELEMENTLEN(targets), "a target type like 'executable' or 'static-lib'"); + int type = get_valid_string_setting(PROJECT_JSON, NULL, object, "type", targets, 0, ELEMENTLEN(targets), "a target type like 'executable' or 'static-lib'"); if (type < 0) error_exit("Target %s did not contain 'type' key.", key); project_add_target(project, &default_target, object, key, target_desc[type], type); } diff --git a/src/compiler/compiler.c b/src/compiler/compiler.c index c441190d5..00d122250 100644 --- a/src/compiler/compiler.c +++ b/src/compiler/compiler.c @@ -253,6 +253,16 @@ static void free_arenas(void) if (debug_stats) print_arena_status(); } +static int compile_cfiles(const char *compiler, const char **files, const char *flags, const char **out_files) +{ + int total = 0; + FOREACH(const char *, file, files) + { + out_files[total++] = cc_compiler(compiler, file, flags); + } + return total; +} + static void compiler_print_bench(void) { if (debug_stats) @@ -439,8 +449,12 @@ void compiler_compile(void) uint32_t output_file_count = vec_size(gen_contexts); unsigned cfiles = vec_size(active_target.csources); - - if (output_file_count + cfiles > MAX_OUTPUT_FILES) + unsigned cfiles_library = 0; + FOREACH(LibraryTarget *, lib, active_target.ccompling_libraries) + { + cfiles_library += vec_size(lib->csources); + } + if (output_file_count + cfiles + cfiles_library > MAX_OUTPUT_FILES) { error_exit("Too many output files."); } @@ -450,16 +464,18 @@ void compiler_compile(void) } CompileData *compile_data = ccalloc(sizeof(CompileData), output_file_count); - const char **obj_files = cmalloc(sizeof(char*) * (output_file_count + cfiles)); + const char **obj_files = cmalloc(sizeof(char*) * (output_file_count + cfiles + cfiles_library)); if (cfiles) { - for (int i = 0; i < cfiles; i++) - { - const char *file = active_target.csources[i]; - const char *obj = platform_compiler(file, active_target.cflags); - obj_files[output_file_count + i] = obj; - } + int compiled = compile_cfiles(active_target.cc, active_target.csources, active_target.cflags, &obj_files[output_file_count]); + assert(cfiles == compiled); + (void)compiled; + } + const char **obj_file_next = &obj_files[output_file_count + cfiles]; + FOREACH(LibraryTarget *, lib, active_target.ccompling_libraries) + { + obj_file_next += compile_cfiles(lib->cc ? lib->cc : active_target.cc, lib->csources, lib->cflags, obj_file_next); } Task **tasks = NULL; @@ -501,7 +517,7 @@ void compiler_compile(void) puts("# output-files-end"); } - output_file_count += cfiles; + output_file_count += cfiles + cfiles_library; free(compile_data); compiler_codegen_time = bench_mark(); @@ -663,11 +679,12 @@ void compiler_compile(void) free(obj_files); } -static const char **target_expand_source_names(const char** dirs, const char **suffix_list, int suffix_count, bool error_on_mismatch) +static const char **target_expand_source_names(const char *base_dir, const char** dirs, const char **suffix_list, int suffix_count, bool error_on_mismatch) { const char **files = NULL; FOREACH(const char *, name, dirs) { + if (base_dir) name = file_append_path(base_dir, name); INFO_LOG("Searching for sources in %s", name); size_t name_len = strlen(name); if (name_len < 1) goto INVALID_NAME; @@ -683,7 +700,7 @@ static const char **target_expand_source_names(const char** dirs, const char **s INFO_LOG("Searching for wildcard sources in %s", name); if (name_len == 2 || name[name_len - 3] == '/') { - char *path = str_copy(name, name_len - 2); + const char *path = str_copy(name, name_len - 2); DEBUG_LOG("Reduced path %s", path); file_add_wildcard_files(&files, path, true, suffix_list, suffix_count); continue; @@ -705,6 +722,15 @@ static const char **target_expand_source_names(const char** dirs, const char **s return files; } +INLINE void expand_csources(const char *base_dir, const char **source_dirs, const char ***sources_ref) +{ + if (source_dirs) + { + static const char* c_suffix_list[3] = { ".c" }; + *sources_ref = target_expand_source_names(base_dir, source_dirs, c_suffix_list, 1, false); + } +} + void compile_target(BuildOptions *options) { init_default_build_target(&active_target, options); @@ -890,8 +916,6 @@ void print_syntax(BuildOptions *options) } -void resolve_libraries(void); - static int jump_buffer_size() { switch (active_target.arch_os_target) @@ -980,24 +1004,22 @@ static void execute_scripts(void) dir_change(old_path); free(old_path); } - void compile() { symtab_init(active_target.symtab_size); - active_target.sources = target_expand_source_names(active_target.source_dirs, c3_suffix_list, 3, true); - if (active_target.csource_dirs) - { - static const char* c_suffix_list[3] = { ".c" }; - active_target.csources = target_expand_source_names(active_target.csource_dirs, c_suffix_list, 1, false); - } + active_target.sources = target_expand_source_names(NULL, active_target.source_dirs, c3_suffix_list, 3, true); + expand_csources(NULL, active_target.csource_dirs, &active_target.csources); execute_scripts(); global_context.main = NULL; global_context.string_type = NULL; asm_target.initialized = false; target_setup(&active_target); - resolve_libraries(); + resolve_libraries(&active_target); global_context.sources = active_target.sources; - + FOREACH(LibraryTarget *, lib, active_target.ccompling_libraries) + { + expand_csources(lib->parent->dir, lib->csource_dirs, &lib->csources); + } TokenType type = TOKEN_CONST_IDENT; FOREACH(const char *, feature_flag, active_target.feature_list) { @@ -1034,10 +1056,6 @@ void compile() if (!vec_size(active_target.sources) && !active_target.read_stdin) error_exit("No files to compile."); - if (active_target.exec) - { - - } if (active_target.lex_only) { compiler_lex(); diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 09be41c5f..ba8f12ae8 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -49,7 +49,6 @@ extern const char *project_default_keys[][2]; extern const int project_default_keys_count; extern const char* project_target_keys[][2]; extern const int project_target_keys_count; -extern const char *trust_level[3]; typedef struct Ast_ Ast; typedef struct Decl_ Decl; @@ -3505,7 +3504,7 @@ bool static_lib_linker(const char *output_file, const char **files, unsigned fil bool dynamic_lib_linker(const char *output_file, const char **files, unsigned file_count); bool linker(const char *output_file, const char **files, unsigned file_count); void platform_linker(const char *output_file, const char **files, unsigned file_count); -const char *platform_compiler(const char *file, const char* flags); +const char *cc_compiler(const char *cc, const char *file, const char *flags); const char *arch_to_linker_arch(ArchType arch); #define CAT(a,b) CAT2(a,b) // force expand diff --git a/src/compiler/linker.c b/src/compiler/linker.c index c12ff56de..38d71d1e9 100644 --- a/src/compiler/linker.c +++ b/src/compiler/linker.c @@ -761,11 +761,12 @@ void platform_linker(const char *output_file, const char **files, unsigned file_ printf("Program linked to executable '%s'.\n", output_file); } -const char *platform_compiler(const char *file, const char *flags) +const char *cc_compiler(const char *cc, const char *file, const char *flags) { const char *dir = active_target.object_file_dir; if (!dir) dir = active_target.build_dir; + bool is_cl_exe = str_eq(cc, "cl.exe"); char *filename = NULL; bool split_worked = file_namesplit(file, &filename, NULL); if (!split_worked) error_exit("Cannot compile '%s'", file); @@ -781,12 +782,21 @@ const char *platform_compiler(const char *file, const char *flags) len -= 2; filename[len] = 0; } - const char *out_name = dir - ? str_printf("%s/%s%s", dir, filename, get_object_extension()) - : str_printf("%s%s", filename, get_object_extension()); - + const char *out_name; + if (is_cl_exe) + { + out_name = dir + ? str_printf("/Fo:\"%s\\%s%s\"", dir, filename, get_object_extension()) + : str_printf("/Fo:\"%s%s\"", filename, get_object_extension()); + } + else + { + out_name = dir + ? str_printf("%s/%s%s", dir, filename, get_object_extension()) + : str_printf("%s%s", filename, get_object_extension()); + } const char **parts = NULL; - vec_add(parts, active_target.cc); + vec_add(parts, cc); const bool pie_set = flags != NULL && @@ -794,18 +804,19 @@ const char *platform_compiler(const char *file, const char *flags) strstr(flags, "-fno-pie") || // it is being set in user defined cflags. strstr(flags, "-fpie") || strstr(flags, "-fPIE")); // strcasestr is apparently nonstandard >:( - if (!pie_set) + if (!pie_set && !is_cl_exe) { append_fpie_pic_options(platform_target.reloc_model, &parts); } - vec_add(parts, "-c"); + vec_add(parts, is_cl_exe ? "/c" : "-c"); if (flags) vec_add(parts, flags); vec_add(parts, file); - vec_add(parts, "-o"); + if (!is_cl_exe) vec_add(parts, "-o"); vec_add(parts, out_name); const char *output = concat_string_parts(parts); + DEBUG_LOG("Compiling c sources using '%s'", output); if (system(output) != 0) { error_exit("Failed to compile c sources using command '%s'.\n", output); diff --git a/src/compiler/target.c b/src/compiler/target.c index 4b790c28a..94b7bbf52 100644 --- a/src/compiler/target.c +++ b/src/compiler/target.c @@ -302,6 +302,8 @@ static char *x86_feature_name[] = { [X86_FEAT_SSE4_2] = "sse4.2", [X86_FEAT_AVX] = "avx", [X86_FEAT_AVX2] = "avx2", + [X86_FEAT_AVX10_1_512] = "avx10.1-512", + [X86_FEAT_AVX10_1_256] = "avx10.1-256", [X86_FEAT_SSE4_A] = "sse4a", [X86_FEAT_FMA4] = "fma4", [X86_FEAT_XOP] = "xop", @@ -375,6 +377,7 @@ static char *x86_feature_name[] = { [X86_FEAT_TBM] = "tbm", [X86_FEAT_TSXLDTRK] = "tsxldtrk", [X86_FEAT_UINTR] = "uintr", + [X86_FEAT_USERMSR] = "usermsr", [X86_FEAT_VAES] = "vaes", [X86_FEAT_VZEROUPPER] = "vzeroupper", [X86_FEAT_WAITPKG] = "waitpkg", @@ -664,6 +667,11 @@ static void x86_features_add_feature(X86Features *cpu_features, X86Feature featu case X86_FEAT_X87: case X86_FEAT_XSAVE: return; + case X86_FEAT_AVX10_1_256: + case X86_FEAT_AVX10_1_512: + case X86_FEAT_USERMSR: + // TODO + return; } UNREACHABLE } @@ -1864,7 +1872,10 @@ void target_setup(BuildTarget *target) default: break; } - + if (!target->cc) + { + target->cc = platform_target.os == OS_TYPE_WIN32 ? "cl.exe" : "cc"; + } platform_target.int128 = os_target_supports_int128(platform_target.os, platform_target.arch); platform_target.vec128f = os_target_supports_vec(platform_target.os, platform_target.arch, 128, false); diff --git a/src/compiler/target.h b/src/compiler/target.h index 048c130fc..90b3379fa 100644 --- a/src/compiler/target.h +++ b/src/compiler/target.h @@ -392,6 +392,8 @@ typedef enum X64Feature X86_FEAT_AMX_INT8, X86_FEAT_AMX_TILE, X86_FEAT_AVX, + X86_FEAT_AVX10_1_512, + X86_FEAT_AVX10_1_256, X86_FEAT_AVX2, X86_FEAT_AVX5124FMAPS, X86_FEAT_AVX5124VNNIW, @@ -476,6 +478,7 @@ typedef enum X64Feature X86_FEAT_TBM, X86_FEAT_TSXLDTRK, X86_FEAT_UINTR, + X86_FEAT_USERMSR, X86_FEAT_VAES, X86_FEAT_VPCLMULQDQ, X86_FEAT_VZEROUPPER, diff --git a/src/utils/file_utils.c b/src/utils/file_utils.c index 70797f96a..a130676ca 100644 --- a/src/utils/file_utils.c +++ b/src/utils/file_utils.c @@ -507,28 +507,26 @@ void file_add_wildcard_files(const char ***files, const char *path, bool recursi bool path_ends_with_slash = is_path_separator(path[strlen(path) - 1]); struct _wfinddata_t file_data; intptr_t file_handle; - const char *search = str_printf(path_ends_with_slash ? "%s*.*" : "%s/*.*", path); + const char *search = str_printf(path_ends_with_slash ? "%s*.*" : "%s\\*.*", path); + DEBUG_LOG("Search %s", search); if ((file_handle = _wfindfirst(win_utf8to16(search), &file_data)) == -1L) return; do { - if ((file_data.attrib & _A_SUBDIR)) + char *name = win_utf16to8(file_data.name); + if (file_has_suffix_in_list(name, strlen(name), suffix_list, suffix_count)) { - if (recursive) - { - if (file_data.name[0] == L'.') - { - continue; - } - char *format = path_ends_with_slash ? "%s%ls" : "%s/%ls"; - char *new_path = str_printf(format, path, file_data.name); - file_add_wildcard_files(files, new_path, true, suffix_list, suffix_count); - } + char *format = path_ends_with_slash ? "%s%s" : "%s\\%s"; + vec_add(*files, str_printf(format, path, name)); continue; } - char *name = win_utf16to8(file_data.name); - if (!file_has_suffix_in_list(name, strlen(name), suffix_list, suffix_count)) continue; - char *format = path_ends_with_slash ? "%s%s" : "%s/%s"; - vec_add(*files, str_printf(format, path, name)); + if (!(file_data.attrib & _A_SUBDIR)) continue; + if (recursive) + { + if (file_data.name[0] == L'.') continue; + char *format = path_ends_with_slash ? "%s%s" : "%s\\%s"; + char *new_path = str_printf(format, path, name); + file_add_wildcard_files(files, new_path, true, suffix_list, suffix_count); + } } while (_wfindnext(file_handle, &file_data) == 0); _findclose(file_handle); }