mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Support c-file compilation in libraries.
This commit is contained in:
1
.github/workflows/main.yml
vendored
1
.github/workflows/main.yml
vendored
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
3
resources/testproject/lib/clib.c3l/clib.c3i
Normal file
3
resources/testproject/lib/clib.c3l/clib.c3i
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
module clib;
|
||||||
|
|
||||||
|
extern fn void hello_from_c();
|
||||||
5
resources/testproject/lib/clib.c3l/hello.c
Normal file
5
resources/testproject/lib/clib.c3l/hello.c
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
void hello_from_c(void)
|
||||||
|
{
|
||||||
|
puts("Hello from C!");
|
||||||
|
}
|
||||||
13
resources/testproject/lib/clib.c3l/manifest.json
Normal file
13
resources/testproject/lib/clib.c3l/manifest.json
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"provides" : "clib",
|
||||||
|
"c-sources" : ["hello.c"],
|
||||||
|
"targets" : {
|
||||||
|
"macos-x64" : {
|
||||||
|
},
|
||||||
|
"macos-aarch64" : {},
|
||||||
|
"linux-x64" : {
|
||||||
|
"c-flags-override": "-fPIE"
|
||||||
|
},
|
||||||
|
"windows-x64" : { }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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": [
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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);
|
||||||
@@ -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
135
src/build/common_build.c
Normal 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);
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
{
|
{
|
||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user