Support c-file compilation in libraries.

This commit is contained in:
Christoffer Lerno
2024-07-06 23:49:10 +02:00
parent c3ecad96b7
commit 3f62775f4b
19 changed files with 421 additions and 347 deletions

View File

@@ -45,6 +45,7 @@ jobs:
- name: Build testproject - name: Build testproject
run: | run: |
set PATH=%PATH%;"C:/Program Files/Microsoft Visual Studio/2022/Enterprise/VC/Tools/MSVC/14.40.33807/bin/Hostx64/x64"
cd resources/testproject cd resources/testproject
..\..\build\${{ matrix.build_type }}\c3c.exe --debug-log --emit-llvm run hello_world_win32 ..\..\build\${{ matrix.build_type }}\c3c.exe --debug-log --emit-llvm run hello_world_win32
dir build\llvm_ir dir build\llvm_ir

View File

@@ -244,6 +244,7 @@ add_executable(c3c
src/build/builder.c src/build/builder.c
src/build/build_options.c src/build/build_options.c
src/build/project_creation.c src/build/project_creation.c
src/build/libraries.c
src/compiler/ast.c src/compiler/ast.c
src/compiler/bigint.c src/compiler/bigint.c
src/compiler/codegen_general.c src/compiler/codegen_general.c
@@ -256,7 +257,6 @@ add_executable(c3c
src/compiler/headers.c src/compiler/headers.c
src/compiler/json_output.c src/compiler/json_output.c
src/compiler/lexer.c src/compiler/lexer.c
src/compiler/libraries.c
src/compiler/linker.c src/compiler/linker.c
src/compiler/llvm_codegen.c src/compiler/llvm_codegen.c
src/compiler/abi/c_abi_aarch64.c src/compiler/abi/c_abi_aarch64.c
@@ -325,7 +325,8 @@ add_executable(c3c
src/compiler/expr.c src/compiler/expr.c
src/utils/time.c src/utils/time.c
src/utils/http.c src/utils/http.c
src/compiler/sema_liveness.c) src/compiler/sema_liveness.c
src/build/common_build.c)
if (C3_USE_TB) if (C3_USE_TB)

View File

@@ -13,6 +13,7 @@
- Updated mangling. - Updated mangling.
- Added `$$unaligned_load` and `$$unaligned_store`. - Added `$$unaligned_load` and `$$unaligned_store`.
- `--no-headers` option to suppress creating headers when generating a library. - `--no-headers` option to suppress creating headers when generating a library.
- Support c-file compilation in libraries.
### Fixes ### Fixes
- Error with unsigned compare in `@ensure` when early returning 0 #1207. - Error with unsigned compare in `@ensure` when early returning 0 #1207.

View File

@@ -1,6 +1,7 @@
module hello_world; module hello_world;
import std; import std;
import bar; import bar;
import clib;
fn int test_doubler(int x) @if(env::WIN32) => x * x; fn int test_doubler(int x) @if(env::WIN32) => x * x;
extern fn int test_doubler(int) @if(!env::WIN32); extern fn int test_doubler(int) @if(!env::WIN32);
@@ -12,6 +13,6 @@ fn int main()
bar::test(); bar::test();
printf("Hello double: %d\n", test_doubler(11)); printf("Hello double: %d\n", test_doubler(11));
if ($feature(ABCD)) io::printn("ABCD"); if ($feature(ABCD)) io::printn("ABCD");
clib::hello_from_c();
return 0; return 0;
} }

View File

@@ -0,0 +1,3 @@
module clib;
extern fn void hello_from_c();

View File

@@ -0,0 +1,5 @@
#include <stdio.h>
void hello_from_c(void)
{
puts("Hello from C!");
}

View File

@@ -0,0 +1,13 @@
{
"provides" : "clib",
"c-sources" : ["hello.c"],
"targets" : {
"macos-x64" : {
},
"macos-aarch64" : {},
"linux-x64" : {
"c-flags-override": "-fPIE"
},
"windows-x64" : { }
}
}

View File

@@ -11,23 +11,23 @@
"sources": [ "sources": [
"./**" "./**"
], ],
// libraries to use "dependency-search-paths": [ "./lib" ],
"dependencies": [], "dependencies": ["clib"],
"features": ["ABCD"], "features": ["ABCD"],
// c compiler
"cc": "cc",
// c sources // c sources
"targets": { "targets": {
"hello_world": { "hello_world": {
"type": "executable", "type": "executable",
"c-sources-override": [ "c-sources-override": [
"./csource/**" "./csource/**"
] ],
"reloc": "PIE",
}, },
"hello_world_win32": { "hello_world_win32": {
"type": "executable", "type": "executable",
"cc" : "cl.exe",
"c-sources-override": [ "c-sources-override": [
] ]
}, },

View File

@@ -419,19 +419,27 @@ typedef enum
typedef struct typedef struct
{ {
struct Library__ *parent;
ArchOsTarget arch_os; ArchOsTarget arch_os;
const char *cc;
const char *cflags;
const char **csource_dirs;
const char **csources;
const char **execs; const char **execs;
const char **link_flags; const char **link_flags;
const char **linked_libs; const char **linked_libs;
const char **depends; const char **depends;
} LibraryTarget; } LibraryTarget;
typedef struct typedef struct Library__
{ {
const char *dir; const char *dir;
const char *provides; const char *provides;
const char **depends; const char **depends;
const char **execs; const char **execs;
const char *cc;
const char *cflags;
const char **csource_dirs;
LibraryTarget *target_used; LibraryTarget *target_used;
LibraryTarget **targets; LibraryTarget **targets;
} Library; } Library;
@@ -441,6 +449,7 @@ typedef struct
{ {
TargetType type; TargetType type;
Library **library_list; Library **library_list;
LibraryTarget **ccompling_libraries;
const char *name; const char *name;
const char *version; const char *version;
const char *langrev; const char *langrev;
@@ -501,9 +510,9 @@ typedef struct
const char *testfn; const char *testfn;
const char *cc; const char *cc;
const char *cflags; const char *cflags;
const char **exec;
const char **csource_dirs; const char **csource_dirs;
const char **csources; const char **csources;
const char **exec;
const char **feature_list; const char **feature_list;
const char *custom_linker_path; const char *custom_linker_path;
struct struct
@@ -566,7 +575,7 @@ static BuildTarget default_build_target = {
.strip_unused = STRIP_UNUSED_NOT_SET, .strip_unused = STRIP_UNUSED_NOT_SET,
.symtab_size = DEFAULT_SYMTAB_SIZE, .symtab_size = DEFAULT_SYMTAB_SIZE,
.reloc_model = RELOC_DEFAULT, .reloc_model = RELOC_DEFAULT,
.cc = "cc", .cc = NULL,
.version = "1.0.0", .version = "1.0.0",
.langrev = "1", .langrev = "1",
.cpu = "generic", .cpu = "generic",
@@ -591,3 +600,4 @@ bool command_accepts_files(CompilerCommand command);
void update_build_target_with_opt_level(BuildTarget *target, OptimizationSetting level); void update_build_target_with_opt_level(BuildTarget *target, OptimizationSetting level);
void create_project(BuildOptions *build_options); void create_project(BuildOptions *build_options);
void create_library(BuildOptions *build_options); void create_library(BuildOptions *build_options);
void resolve_libraries(BuildTarget *build_target);

View File

@@ -12,6 +12,8 @@ typedef struct
BuildTarget **targets; BuildTarget **targets;
} Project; } Project;
extern const char *trust_level[3];
static const char *memory_environment[6] = { static const char *memory_environment[6] = {
[MEMORY_ENV_NORMAL] = "normal", [MEMORY_ENV_NORMAL] = "normal",
[MEMORY_ENV_SMALL] = "small", [MEMORY_ENV_SMALL] = "small",
@@ -85,3 +87,15 @@ static const char *reloc_models[5] = {
Project *project_load(void); Project *project_load(void);
BuildTarget *project_select_target(Project *project, const char *optional_target); 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); 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);

135
src/build/common_build.c Normal file
View File

@@ -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);
}

View File

@@ -1,49 +1,10 @@
#include "compiler_internal.h" #include "build_internal.h"
#include "../utils/json.h" #include "compiler/compiler.h"
#define MANIFEST_FILE "manifest.json" #define MANIFEST_FILE "manifest.json"
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);
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_type(Library *library, LibraryTarget ***target_group, 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]; 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); if (member->type != J_OBJECT) error_exit("Expected a list of properties for a target in %s.", library->dir);
LibraryTarget *library_target = CALLOCS(LibraryTarget); LibraryTarget *library_target = CALLOCS(LibraryTarget);
library_target->parent = library;
ArchOsTarget target = arch_os_target_from_string(key); ArchOsTarget target = arch_os_target_from_string(key);
if (target == ARCH_OS_TARGET_DEFAULT) 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; library_target->arch_os = target;
vec_add(*target_group, library_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->link_flags = get_string_array(library->dir, target_name, object, "linkflags", false);
target->linked_libs = get_optional_string_array_as_array(library, object, "linked-libs"); target->linked_libs = get_string_array(library->dir, target_name, object, "linked-libs", false);
target->depends = get_optional_string_array_as_array(library, object, "depends"); target->depends = get_string_array(library->dir, target_name, object, "depends", false);
target->execs = get_optional_string_array_as_array(library, object, "execs"); 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) static Library *add_library(JSONObject *object, const char *dir)
{ {
Library *library = CALLOCS(Library); Library *library = CALLOCS(Library);
library->dir = dir; 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)) if (!str_is_valid_lowercase_name(provides))
{ {
char *res = strdup(provides); char *res = strdup(provides);
str_ellide_in_place(res, 32); str_ellide_in_place(res, 32);
error_exit("Invalid 'provides' module name in %s, was '%s'.", library->dir, error_exit("Invalid 'provides' module name in %s, was '%s'.", library->dir, res);
json_obj_get(object, "provides")->str);
} }
library->provides = provides; library->provides = provides;
library->execs = get_optional_string_array_as_array(library, object, "execs"); library->execs = get_optional_string_array(library->dir, NULL, object, "execs");
library->depends = get_optional_string_array_as_array(library, object, "depends"); 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")); parse_library_type(library, &library->targets, json_obj_get(object, "targets"));
return library; return library;
} }
static Library *find_library(Library **libs, size_t lib_count, const char *name) static Library *find_library(Library **libs, size_t lib_count, const char *name)
{ {
for (size_t i = 0; i < lib_count; i++) 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); 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; if (library->target_used) return;
LibraryTarget *target_found = NULL; LibraryTarget *target_found = NULL;
FOREACH(LibraryTarget *, target, library->targets) 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; target_found = target;
break; break;
@@ -118,16 +86,17 @@ static void add_library_dependency(Library *library, Library **library_list, siz
} }
if (!target_found) 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; library->target_used = target_found;
FOREACH(const char *, dependency, library->depends) 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) 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, library_list,
lib_count); lib_count);
} }
@@ -150,7 +119,7 @@ INLINE JSONObject* read_manifest(const char *lib, const char *manifest_data)
return json; 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"); FILE *f = fopen(lib, "rb");
if (!f) error_exit("Failed to open library '%s' for reading.", lib); 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. // Create the directory for the temporary files.
const char *lib_name = filename(lib); const char *lib_name = filename(lib);
scratch_buffer_clear(); 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); scratch_buffer_printf("/_c3l/%s_%x/", lib_name, file.file_crc32);
const char *lib_dir = scratch_buffer_copy(); const char *lib_dir = scratch_buffer_copy();
dir_make_recursive(scratch_buffer_to_string()); 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; return json;
} }
void resolve_libraries(void) void resolve_libraries(BuildTarget *build_target)
{ {
DEBUG_LOG("Resolve libraries");
static const char *c3lib_suffix = ".c3l"; static const char *c3lib_suffix = ".c3l";
const char **c3_libs = NULL; const char **c3_libs = NULL;
unsigned libdir_count = vec_size(active_target.libdirs); unsigned libdir_count = vec_size(build_target->libdirs);
if (libdir_count) 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); file_add_wildcard_files(&c3_libs, dir, false, &c3lib_suffix, 1);
} }
} }
else else
{ {
// Default to '.' // Default to '.'
DEBUG_LOG("Search '.'");
file_add_wildcard_files(&c3_libs, ".", false, &c3lib_suffix, 1); file_add_wildcard_files(&c3_libs, ".", false, &c3lib_suffix, 1);
} }
Library *libraries[MAX_LIB_DIRS * 2]; Library *libraries[MAX_LIB_DIRS * 2];
@@ -221,7 +193,7 @@ void resolve_libraries(void)
JSONObject *json; JSONObject *json;
if (!file_is_dir(lib)) if (!file_is_dir(lib))
{ {
json = resolve_zip_library(lib, &lib); json = resolve_zip_library(build_target, lib, &lib);
} }
else 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); 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); 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++) for (size_t i = 0; i < lib_count; i++)
{ {
Library *library = libraries[i]; Library *library = libraries[i];
LibraryTarget *target = library->target_used; LibraryTarget *target = library->target_used;
if (!target) continue; if (!target) continue;
file_add_wildcard_files(&active_target.sources, library->dir, false, c3_suffix_list, 3); if (vec_size(target->csource_dirs))
vec_add(active_target.library_list, library); {
const char *libdir = file_append_path(library->dir, arch_os_target[active_target.arch_os_target]); vec_add(build_target->ccompling_libraries, 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) 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 " 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.", "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) FOREACH(const char *, exec, library->execs)
{ {

View File

@@ -4,8 +4,13 @@
#include <math.h> #include <math.h>
#include "build_internal.h" #include "build_internal.h"
#include "utils/json.h"
#define MAX_SYMTAB_SIZE (1024 * 1024) #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] = { const char *project_default_keys[][2] = {
{"authors", "Authors, optionally with email."}, {"authors", "Authors, optionally with email."},
{"benchfn", "Override the benchmark function."}, {"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); 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) 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); return (long)trunc(value->f);
} }
static void check_json_keys(const char* valid_keys[][2], size_t key_count, JSONObject *json, const char *target_name)
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 bool failed_shown = false; static bool failed_shown = false;
bool failed = 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; 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; failed = true;
OK:; 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); check_json_keys(project_target_keys, project_target_keys_count, json, target_name);
}
}
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);
} }
else 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 // Exec
const char **exec = get_valid_array(json, is_default ? "exec" : "exec-override" , type, false); get_list_append_strings(PROJECT_JSON, target_name, json, &target->exec, "exec", "exec-override", "exec-add");
const char **exec_add = is_default ? NULL : get_valid_array(json, "exec-add" , type, false);
if (exec && exec_add) target->output_dir = get_string(PROJECT_JSON, target_name, json,"output", target->output_dir);
{
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);
// CFlags // CFlags
const char *cflags = get_valid_string(json, is_default ? "cflags" : "cflags-override" , type); target->cflags = get_cflags(PROJECT_JSON, target_name, json, target->cflags);
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;
}
}
// C source dirs. // 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 // 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 // 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 // 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 // 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 // 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 // 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) FOREACH(const char *, name, target->libs)
{ {
if (!str_is_valid_lowercase_name(name)) 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_NONE] = "none",
[DEBUG_INFO_LINE_TABLES] = "line-tables" [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; if (info > -1) target->debug_info = info;
// Optimization Level // Optimization Level
OptimizationLevel optlevel = (OptimizationLevel)get_valid_string_setting(json, "optlevel", type, optlevels, 0, ELEMENTLEN(optlevels), "`none`, `less`, `more`, `max`."); target->optlevel = GET_SETTING(OptimizationLevel, "optlevel", optlevels, "`none`, `less`, `more`, `max`.");
target->optlevel = optlevel;
// Size optimization // Size optimization
SizeOptimizationLevel optsize = (SizeOptimizationLevel)get_valid_string_setting(json, "optsize", type, optsizes, 0, ELEMENTLEN(optlevels), "`none`, `small`, `tiny`."); target->optsize = GET_SETTING(SizeOptimizationLevel, "optsize", optlevels, "`none`, `small`, `tiny`.");
target->optsize = optsize;
static const char *opt_settings[8] = { static const char *opt_settings[8] = {
[OPT_SETTING_O0] = "O0", [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_OSMALL] = "Os",
[OPT_SETTING_OTINY] = "Oz" [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; if (opt != OPT_SETTING_NOT_SET) target->optsetting = opt;
// Safety level // 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 // 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 // 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. // 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'."); MemoryEnvironment env = GET_SETTING(MemoryEnvironment, "memory-env", memory_environment, "one of 'normal', 'small', 'tiny' or 'none'.");
if (env > -1) target->memory_environment = env; if (env != MEMORY_ENV_NOT_SET) target->memory_environment = env;
// Symtab // 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 > 0)
{ {
if (symtab_size < 1024) 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) 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->symtab_size = (uint32_t)symtab_size;
} }
// Target // 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) if (arch_os_string)
{ {
ArchOsTarget arch_os = arch_os_target_from_string(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; target->arch_os_target = arch_os;
} }
// Reloc // Reloc
int reloc = get_valid_string_setting(json, "reloc", type, reloc_models, 0, ELEMENTLEN(reloc_models), "'none', 'pic', 'PIC', 'pie' or 'PIE'."); RelocModel reloc = GET_SETTING(RelocModel, "reloc", reloc_models, "'none', 'pic', 'PIC', 'pie' or 'PIE'.");
if (reloc > -1) target->reloc_model = (RelocModel)reloc; if (reloc != RELOC_DEFAULT) target->reloc_model = reloc;
// Cpu // Cpu
target->cpu = get_string(json, "cpu", type, target->cpu); target->cpu = get_string(PROJECT_JSON, target_name, json, "cpu", target->cpu);
// WinCRT // WinCRT
int wincrt = get_valid_string_setting(json, "wincrt", type, wincrt_linking, 0, ELEMENTLEN(wincrt_linking), "'none', 'static' or 'dynamic'."); WinCrtLinking wincrt = GET_SETTING(WinCrtLinking, "wincrt", wincrt_linking, "'none', 'static' or 'dynamic'.");
if (wincrt > -1) target->win.crt_linking = (WinCrtLinking)wincrt; if (wincrt != WIN_CRT_DEFAULT) target->win.crt_linking = wincrt;
// fp-math // 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; 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) if (features)
{ {
FOREACH(const char *, feature, features) FOREACH(const char *, feature, features)
@@ -441,61 +313,61 @@ static void load_into_build_target(JSONObject *json, const char *type, BuildTarg
} }
// x86vec // 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; if (x86vec > -1) target->feature.x86_vector_capability = x86vec;
// 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`."); X86CpuSet x86cpu = GET_SETTING(X86CpuSet, "x86cpu", x86_cpu_set, "`baseline`, `ssse3`, `sse4`, `avx1`, `avx2-v1`, `avx2-v2`, `avx512` or `native`.");
if (x86cpu > -1) target->feature.x86_cpu_set = x86cpu; if (x86cpu > X86CPU_DEFAULT) target->feature.x86_cpu_set = x86cpu;
// riscvfloat // riscvfloat
int riscv_float = get_valid_string_setting(json, "riscvfloat", type, riscv_capability, 0, ELEMENTLEN(riscv_capability), "`none`, `float` or `double`."); RiscvFloatCapability riscv_float = GET_SETTING(RiscvFloatCapability, "riscvfloat", riscv_capability, "`none`, `float` or `double`.");
if (riscv_float > -1) target->feature.riscv_float_capability = riscv_float; if (riscv_float != RISCVFLOAT_DEFAULT) target->feature.riscv_float_capability = riscv_float;
// winsdk // 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 // 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 // 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 // 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 // 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 // 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 // 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 // version
target->version = get_string(json, "version", type, target->version); target->version = get_string(PROJECT_JSON, target_name, json, "version", target->version);
// langrev // langrev
target->langrev = get_string(json, "langrev", type, target->langrev); target->langrev = get_string(PROJECT_JSON, target_name, json, "langrev", target->langrev);
// panicfn // panicfn
target->panicfn = get_string(json, "panicfn", type, target->panicfn); target->panicfn = get_string(PROJECT_JSON, target_name, json, "panicfn", target->panicfn);
// testfn // testfn
target->testfn = get_string(json, "testfn", type, target->testfn); target->testfn = get_string(PROJECT_JSON, target_name, json, "testfn", target->testfn);
// 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 // 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 // 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 // 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 (linker_selection)
{ {
if (str_eq("cc", 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 // 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 // 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 // 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 // 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 // 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 // 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.x86_struct_return = get_valid_bool(PROJECT_JSON, target_name, json, "x86-stack-struct-return",
target->feature.soft_float = get_valid_bool(json, "soft-float", type, target->feature.soft_float); target->feature.x86_struct_return);
target->feature.pass_win64_simd_as_arrays = get_valid_bool(json, "win64-simd-array", type, target->feature.pass_win64_simd_as_arrays); 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) 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); 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); 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; 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"); JSONObject *targets_json = json_obj_get(project_data, "targets");
if (!targets_json) 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); 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); 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); project_add_target(project, &default_target, object, key, target_desc[type], type);
} }

View File

@@ -253,6 +253,16 @@ static void free_arenas(void)
if (debug_stats) print_arena_status(); 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) static void compiler_print_bench(void)
{ {
if (debug_stats) if (debug_stats)
@@ -439,8 +449,12 @@ void compiler_compile(void)
uint32_t output_file_count = vec_size(gen_contexts); uint32_t output_file_count = vec_size(gen_contexts);
unsigned cfiles = vec_size(active_target.csources); unsigned cfiles = vec_size(active_target.csources);
unsigned cfiles_library = 0;
if (output_file_count + cfiles > MAX_OUTPUT_FILES) 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."); error_exit("Too many output files.");
} }
@@ -450,16 +464,18 @@ void compiler_compile(void)
} }
CompileData *compile_data = ccalloc(sizeof(CompileData), output_file_count); 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) if (cfiles)
{ {
for (int i = 0; i < cfiles; i++) int compiled = compile_cfiles(active_target.cc, active_target.csources, active_target.cflags, &obj_files[output_file_count]);
{ assert(cfiles == compiled);
const char *file = active_target.csources[i]; (void)compiled;
const char *obj = platform_compiler(file, active_target.cflags); }
obj_files[output_file_count + i] = obj; 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; Task **tasks = NULL;
@@ -501,7 +517,7 @@ void compiler_compile(void)
puts("# output-files-end"); puts("# output-files-end");
} }
output_file_count += cfiles; output_file_count += cfiles + cfiles_library;
free(compile_data); free(compile_data);
compiler_codegen_time = bench_mark(); compiler_codegen_time = bench_mark();
@@ -663,11 +679,12 @@ void compiler_compile(void)
free(obj_files); 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; const char **files = NULL;
FOREACH(const char *, name, dirs) FOREACH(const char *, name, dirs)
{ {
if (base_dir) name = file_append_path(base_dir, name);
INFO_LOG("Searching for sources in %s", name); INFO_LOG("Searching for sources in %s", name);
size_t name_len = strlen(name); size_t name_len = strlen(name);
if (name_len < 1) goto INVALID_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); INFO_LOG("Searching for wildcard sources in %s", name);
if (name_len == 2 || name[name_len - 3] == '/') 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); DEBUG_LOG("Reduced path %s", path);
file_add_wildcard_files(&files, path, true, suffix_list, suffix_count); file_add_wildcard_files(&files, path, true, suffix_list, suffix_count);
continue; continue;
@@ -705,6 +722,15 @@ static const char **target_expand_source_names(const char** dirs, const char **s
return files; 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) void compile_target(BuildOptions *options)
{ {
init_default_build_target(&active_target, 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() static int jump_buffer_size()
{ {
switch (active_target.arch_os_target) switch (active_target.arch_os_target)
@@ -980,24 +1004,22 @@ static void execute_scripts(void)
dir_change(old_path); dir_change(old_path);
free(old_path); free(old_path);
} }
void compile() void compile()
{ {
symtab_init(active_target.symtab_size); symtab_init(active_target.symtab_size);
active_target.sources = target_expand_source_names(active_target.source_dirs, c3_suffix_list, 3, true); active_target.sources = target_expand_source_names(NULL, active_target.source_dirs, c3_suffix_list, 3, true);
if (active_target.csource_dirs) expand_csources(NULL, active_target.csource_dirs, &active_target.csources);
{
static const char* c_suffix_list[3] = { ".c" };
active_target.csources = target_expand_source_names(active_target.csource_dirs, c_suffix_list, 1, false);
}
execute_scripts(); execute_scripts();
global_context.main = NULL; global_context.main = NULL;
global_context.string_type = NULL; global_context.string_type = NULL;
asm_target.initialized = false; asm_target.initialized = false;
target_setup(&active_target); target_setup(&active_target);
resolve_libraries(); resolve_libraries(&active_target);
global_context.sources = active_target.sources; 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; TokenType type = TOKEN_CONST_IDENT;
FOREACH(const char *, feature_flag, active_target.feature_list) 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 (!vec_size(active_target.sources) && !active_target.read_stdin) error_exit("No files to compile.");
if (active_target.exec)
{
}
if (active_target.lex_only) if (active_target.lex_only)
{ {
compiler_lex(); compiler_lex();

View File

@@ -49,7 +49,6 @@ extern const char *project_default_keys[][2];
extern const int project_default_keys_count; extern const int project_default_keys_count;
extern const char* project_target_keys[][2]; extern const char* project_target_keys[][2];
extern const int project_target_keys_count; extern const int project_target_keys_count;
extern const char *trust_level[3];
typedef struct Ast_ Ast; typedef struct Ast_ Ast;
typedef struct Decl_ Decl; 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 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); 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); 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); const char *arch_to_linker_arch(ArchType arch);
#define CAT(a,b) CAT2(a,b) // force expand #define CAT(a,b) CAT2(a,b) // force expand

View File

@@ -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); 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; const char *dir = active_target.object_file_dir;
if (!dir) dir = active_target.build_dir; if (!dir) dir = active_target.build_dir;
bool is_cl_exe = str_eq(cc, "cl.exe");
char *filename = NULL; char *filename = NULL;
bool split_worked = file_namesplit(file, &filename, NULL); bool split_worked = file_namesplit(file, &filename, NULL);
if (!split_worked) error_exit("Cannot compile '%s'", file); 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; len -= 2;
filename[len] = 0; filename[len] = 0;
} }
const char *out_name = dir const char *out_name;
? str_printf("%s/%s%s", dir, filename, get_object_extension()) if (is_cl_exe)
: str_printf("%s%s", filename, get_object_extension()); {
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; const char **parts = NULL;
vec_add(parts, active_target.cc); vec_add(parts, cc);
const bool pie_set = const bool pie_set =
flags != NULL && 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, "-fno-pie") || // it is being set in user defined cflags.
strstr(flags, "-fpie") || strstr(flags, "-fpie") ||
strstr(flags, "-fPIE")); // strcasestr is apparently nonstandard >:( 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); 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); if (flags) vec_add(parts, flags);
vec_add(parts, file); vec_add(parts, file);
vec_add(parts, "-o"); if (!is_cl_exe) vec_add(parts, "-o");
vec_add(parts, out_name); vec_add(parts, out_name);
const char *output = concat_string_parts(parts); const char *output = concat_string_parts(parts);
DEBUG_LOG("Compiling c sources using '%s'", output);
if (system(output) != 0) if (system(output) != 0)
{ {
error_exit("Failed to compile c sources using command '%s'.\n", output); error_exit("Failed to compile c sources using command '%s'.\n", output);

View File

@@ -302,6 +302,8 @@ static char *x86_feature_name[] = {
[X86_FEAT_SSE4_2] = "sse4.2", [X86_FEAT_SSE4_2] = "sse4.2",
[X86_FEAT_AVX] = "avx", [X86_FEAT_AVX] = "avx",
[X86_FEAT_AVX2] = "avx2", [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_SSE4_A] = "sse4a",
[X86_FEAT_FMA4] = "fma4", [X86_FEAT_FMA4] = "fma4",
[X86_FEAT_XOP] = "xop", [X86_FEAT_XOP] = "xop",
@@ -375,6 +377,7 @@ static char *x86_feature_name[] = {
[X86_FEAT_TBM] = "tbm", [X86_FEAT_TBM] = "tbm",
[X86_FEAT_TSXLDTRK] = "tsxldtrk", [X86_FEAT_TSXLDTRK] = "tsxldtrk",
[X86_FEAT_UINTR] = "uintr", [X86_FEAT_UINTR] = "uintr",
[X86_FEAT_USERMSR] = "usermsr",
[X86_FEAT_VAES] = "vaes", [X86_FEAT_VAES] = "vaes",
[X86_FEAT_VZEROUPPER] = "vzeroupper", [X86_FEAT_VZEROUPPER] = "vzeroupper",
[X86_FEAT_WAITPKG] = "waitpkg", [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_X87:
case X86_FEAT_XSAVE: case X86_FEAT_XSAVE:
return; return;
case X86_FEAT_AVX10_1_256:
case X86_FEAT_AVX10_1_512:
case X86_FEAT_USERMSR:
// TODO
return;
} }
UNREACHABLE UNREACHABLE
} }
@@ -1864,7 +1872,10 @@ void target_setup(BuildTarget *target)
default: default:
break; 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.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); platform_target.vec128f = os_target_supports_vec(platform_target.os, platform_target.arch, 128, false);

View File

@@ -392,6 +392,8 @@ typedef enum X64Feature
X86_FEAT_AMX_INT8, X86_FEAT_AMX_INT8,
X86_FEAT_AMX_TILE, X86_FEAT_AMX_TILE,
X86_FEAT_AVX, X86_FEAT_AVX,
X86_FEAT_AVX10_1_512,
X86_FEAT_AVX10_1_256,
X86_FEAT_AVX2, X86_FEAT_AVX2,
X86_FEAT_AVX5124FMAPS, X86_FEAT_AVX5124FMAPS,
X86_FEAT_AVX5124VNNIW, X86_FEAT_AVX5124VNNIW,
@@ -476,6 +478,7 @@ typedef enum X64Feature
X86_FEAT_TBM, X86_FEAT_TBM,
X86_FEAT_TSXLDTRK, X86_FEAT_TSXLDTRK,
X86_FEAT_UINTR, X86_FEAT_UINTR,
X86_FEAT_USERMSR,
X86_FEAT_VAES, X86_FEAT_VAES,
X86_FEAT_VPCLMULQDQ, X86_FEAT_VPCLMULQDQ,
X86_FEAT_VZEROUPPER, X86_FEAT_VZEROUPPER,

View File

@@ -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]); bool path_ends_with_slash = is_path_separator(path[strlen(path) - 1]);
struct _wfinddata_t file_data; struct _wfinddata_t file_data;
intptr_t file_handle; 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; if ((file_handle = _wfindfirst(win_utf8to16(search), &file_data)) == -1L) return;
do 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) char *format = path_ends_with_slash ? "%s%s" : "%s\\%s";
{ vec_add(*files, str_printf(format, path, name));
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);
}
continue; continue;
} }
char *name = win_utf16to8(file_data.name); if (!(file_data.attrib & _A_SUBDIR)) continue;
if (!file_has_suffix_in_list(name, strlen(name), suffix_list, suffix_count)) continue; if (recursive)
char *format = path_ends_with_slash ? "%s%s" : "%s/%s"; {
vec_add(*files, str_printf(format, path, name)); 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); } while (_wfindnext(file_handle, &file_data) == 0);
_findclose(file_handle); _findclose(file_handle);
} }