mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Use JSON, unifying settings.
This commit is contained in:
committed by
Christoffer Lerno
parent
fd82f9685f
commit
7226bff6ea
@@ -187,7 +187,8 @@ add_executable(c3c
|
||||
src/utils/malloc.c
|
||||
src/utils/stringutils.c
|
||||
src/utils/taskqueue.c
|
||||
src/utils/toml.c src/build/project.c
|
||||
src/utils/json.c
|
||||
src/build/project.c
|
||||
src/utils/vmem.c
|
||||
src/utils/vmem.h
|
||||
src/utils/whereami.c
|
||||
|
||||
27
resources/testproject/project.c3p
Normal file
27
resources/testproject/project.c3p
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"version": "0.1.0",
|
||||
"authors": [
|
||||
"John Doe <john.doe@example.com>"
|
||||
],
|
||||
"langrev": "1",
|
||||
"warnings": [
|
||||
"no-unused"
|
||||
],
|
||||
// sources compiled
|
||||
"sources": [
|
||||
"./**"
|
||||
],
|
||||
// libraries to use
|
||||
"libs": [],
|
||||
// c compiler
|
||||
"cc": "cc",
|
||||
// c sources
|
||||
"csources": [
|
||||
"./csource/**"
|
||||
],
|
||||
"targets": {
|
||||
"hello_world": {
|
||||
"type": "executable",
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
// a copy of which can be found in the LICENSE file.
|
||||
|
||||
#include "utils/lib.h"
|
||||
#include "utils/toml.h"
|
||||
#include "utils/json.h"
|
||||
#include "build_options.h"
|
||||
#define DEFAULT_SYMTAB_SIZE (2 * 1024 * 1024)
|
||||
#define DEFAULT_SWITCHRANGE_MAX_SIZE (256)
|
||||
|
||||
@@ -85,7 +85,6 @@ static void usage(void)
|
||||
OUTPUT(" -O3 - Aggressive optimization.");
|
||||
OUTPUT(" --emit-llvm - Emit LLVM IR as a .ll file per module.");
|
||||
OUTPUT(" --target <target> - Compile for a particular architecture + OS target.");
|
||||
OUTPUT(" --target-list - List all architectures the compiler supports.");
|
||||
OUTPUT(" --threads <number> - Set the number of threads to use for compilation.");
|
||||
OUTPUT(" --safe - Set mode to 'safe', generating runtime traps on overflows and contract violations.");
|
||||
OUTPUT(" --fast - Set mode to 'fast', removes runtime traps.");
|
||||
@@ -94,18 +93,14 @@ static void usage(void)
|
||||
OUTPUT(" -g0 - Emit no debug info.");
|
||||
OUTPUT(" -gline-tables-only - Only emit line tables for debugging.");
|
||||
OUTPUT("");
|
||||
OUTPUT(" -fpic - Generate position independent (PIC) code if suitable.");
|
||||
OUTPUT(" -fno-pic - Do not generate position independent code.");
|
||||
OUTPUT(" -fPIC - Always generate position independent (PIC) code.");
|
||||
OUTPUT(" -fno-PIC - Generate position independent (PIC) code.");
|
||||
OUTPUT("");
|
||||
OUTPUT(" -z <argument> - Send the <argument> as a parameter to the linker.");
|
||||
OUTPUT("");
|
||||
OUTPUT(" -mavx - Enable AVX on x64 targets.");
|
||||
OUTPUT(" -mavx512 - Enable AVX512 on x64 targets.");
|
||||
OUTPUT(" -mno-avx - Disable AVX on x64 targets.");
|
||||
OUTPUT(" --reloc=<option> - Relocation model: none, pic, PIC, pie, PIE");
|
||||
OUTPUT(" --x86vec=<option> - Set max level of vector instructions: none, mmx, sse, avx, avx512.");
|
||||
OUTPUT("");
|
||||
OUTPUT(" --debug-stats - Print debug statistics.");
|
||||
OUTPUT(" --list-targets - List all architectures the compiler supports.");
|
||||
OUTPUT(" --list-keywords - List all keywords.");
|
||||
OUTPUT(" --list-operators - List all operators.");
|
||||
OUTPUT(" --list-attributes - List all attributes.");
|
||||
@@ -164,6 +159,14 @@ static inline bool match_longopt(const char* name)
|
||||
return strcmp(¤t_arg[2], name) == 0;
|
||||
}
|
||||
|
||||
static inline const char *match_argopt(const char* name)
|
||||
{
|
||||
size_t len = strlen(name);
|
||||
if (memcmp(¤t_arg[2], name, len) != 0) return false;
|
||||
if (current_arg[2 + len] != '=') return false;
|
||||
return ¤t_arg[2 + len + 1];
|
||||
}
|
||||
|
||||
static inline bool match_shortopt(const char* name)
|
||||
{
|
||||
return strcmp(¤t_arg[1], name) == 0;
|
||||
@@ -291,9 +294,17 @@ static void print_version(void)
|
||||
OUTPUT("LLVM default target: %s", llvm_target);
|
||||
}
|
||||
|
||||
static int parse_multi_option(const char *start, unsigned count, const char** elements)
|
||||
{
|
||||
const char *arg = current_arg;
|
||||
int select = str_in_list(start, count, elements);
|
||||
if (select < 0) error_exit("error: %.*s invalid option '%s' given.", (int)(start - arg), start, arg);
|
||||
return select;
|
||||
}
|
||||
|
||||
static void parse_option(BuildOptions *options)
|
||||
{
|
||||
const char *argopt;
|
||||
switch (current_arg[1])
|
||||
{
|
||||
case '?':
|
||||
@@ -327,38 +338,6 @@ static void parse_option(BuildOptions *options)
|
||||
return;
|
||||
}
|
||||
FAIL_WITH_ERR("Unknown debug argument -%s.", ¤t_arg[1]);
|
||||
case 'f':
|
||||
if (match_shortopt("fpie"))
|
||||
{
|
||||
options->pie = PIE_SMALL;
|
||||
return;
|
||||
}
|
||||
if (match_shortopt("fPIE"))
|
||||
{
|
||||
options->pie = PIE_BIG;
|
||||
return;
|
||||
}
|
||||
if (match_shortopt("fno-pie"))
|
||||
{
|
||||
options->pie = PIE_NONE;
|
||||
return;
|
||||
}
|
||||
if (match_shortopt("fpic"))
|
||||
{
|
||||
options->pic = PIC_SMALL;
|
||||
return;
|
||||
}
|
||||
if (match_shortopt("fPIC"))
|
||||
{
|
||||
options->pic = PIC_BIG;
|
||||
return;
|
||||
}
|
||||
if (match_shortopt("fno-pic"))
|
||||
{
|
||||
options->pic = PIC_NONE;
|
||||
return;
|
||||
}
|
||||
FAIL_WITH_ERR("Unknown argument -%s.", ¤t_arg[1]);
|
||||
case 'h':
|
||||
break;
|
||||
case 'z':
|
||||
@@ -403,22 +382,6 @@ static void parse_option(BuildOptions *options)
|
||||
FAIL_WITH_ERR("Invalid optimization level.");
|
||||
}
|
||||
return;
|
||||
case 'm':
|
||||
if (match_shortopt("mno-avx"))
|
||||
{
|
||||
options->no_avx = true;
|
||||
} else if (match_shortopt("mavx"))
|
||||
{
|
||||
options->avx = true;
|
||||
} else if (match_shortopt("mavx512"))
|
||||
{
|
||||
options->avx512 = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
FAIL_WITH_ERR("Invalid -m option.");
|
||||
}
|
||||
return;
|
||||
case 'E':
|
||||
if (options->compile_option != COMPILE_NORMAL)
|
||||
{
|
||||
@@ -464,6 +427,16 @@ static void parse_option(BuildOptions *options)
|
||||
print_version();
|
||||
exit_compiler(COMPILER_SUCCESS_EXIT);
|
||||
}
|
||||
if ((argopt = match_argopt("x86vec")))
|
||||
{
|
||||
options->x86_vector_capability = (X86VectorCapability)parse_multi_option(argopt, 5, vector_capability);
|
||||
return;
|
||||
}
|
||||
if ((argopt = match_argopt("reloc")))
|
||||
{
|
||||
options->reloc_model = (RelocModel)parse_multi_option(argopt, 5, reloc_models);
|
||||
return;
|
||||
}
|
||||
if (match_longopt("about"))
|
||||
{
|
||||
OUTPUT("The C3 Compiler");
|
||||
@@ -540,7 +513,7 @@ static void parse_option(BuildOptions *options)
|
||||
}
|
||||
exit_compiler(EXIT_FAILURE);
|
||||
}
|
||||
if (match_longopt("target-list"))
|
||||
if (match_longopt("list-targets"))
|
||||
{
|
||||
print_all_targets();
|
||||
exit_compiler(COMPILER_SUCCESS_EXIT);
|
||||
@@ -623,9 +596,9 @@ BuildOptions parse_arguments(int argc, const char *argv[])
|
||||
.safe_mode = -1,
|
||||
.build_threads = 16,
|
||||
.command = COMMAND_MISSING,
|
||||
.pie = PIE_DEFAULT,
|
||||
.pic = PIC_DEFAULT,
|
||||
.reloc_model = RELOC_DEFAULT,
|
||||
.backend = BACKEND_LLVM,
|
||||
.x86_vector_capability = X86VECTOR_DEFAULT,
|
||||
.files = NULL
|
||||
};
|
||||
for (int i = DIAG_NONE; i < DIAG_WARNING_TYPE; i++)
|
||||
|
||||
@@ -144,6 +144,42 @@ typedef enum
|
||||
STRUCT_RETURN_REG = 1
|
||||
} StructReturn;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
X86VECTOR_DEFAULT = -1,
|
||||
X86VECTOR_NONE = 0,
|
||||
X86VECTOR_MMX = 1,
|
||||
X86VECTOR_SSE = 2,
|
||||
X86VECTOR_AVX = 3,
|
||||
X86VECTOR_AVX512 = 4,
|
||||
} X86VectorCapability;
|
||||
|
||||
static const char *vector_capability[5] = {
|
||||
[X86VECTOR_NONE] = "none",
|
||||
[X86VECTOR_MMX] = "mmx",
|
||||
[X86VECTOR_SSE] = "sse",
|
||||
[X86VECTOR_AVX] = "avx",
|
||||
[X86VECTOR_AVX512] = "avx512",
|
||||
};
|
||||
|
||||
typedef enum
|
||||
{
|
||||
RELOC_DEFAULT = -1,
|
||||
RELOC_NONE = 0,
|
||||
RELOC_SMALL_PIC = 1,
|
||||
RELOC_BIG_PIC = 2,
|
||||
RELOC_SMALL_PIE = 3,
|
||||
RELOC_BIG_PIE = 4,
|
||||
} RelocModel;
|
||||
|
||||
static const char *reloc_models[5] = {
|
||||
[RELOC_NONE] = "none",
|
||||
[RELOC_SMALL_PIC] = "pic",
|
||||
[RELOC_BIG_PIC] = "PIC",
|
||||
[RELOC_SMALL_PIE] = "pie",
|
||||
[RELOC_BIG_PIE] = "PIE",
|
||||
};
|
||||
|
||||
typedef enum
|
||||
{
|
||||
DEBUG_INFO_NOT_SET = -1,
|
||||
@@ -194,8 +230,6 @@ typedef struct BuildOptions_
|
||||
CompilerBackend backend;
|
||||
CompilerCommand command;
|
||||
CompileOption compile_option;
|
||||
PieGeneration pie;
|
||||
PicGeneration pic;
|
||||
DiagnosticsSeverity severity[DIAG_END_SENTINEL];
|
||||
OptimizationSetting optimization_setting_override;
|
||||
DebugInfo debug_info_override;
|
||||
@@ -205,14 +239,14 @@ typedef struct BuildOptions_
|
||||
bool emit_bitcode;
|
||||
bool test_mode;
|
||||
bool no_stdlib;
|
||||
bool no_avx;
|
||||
bool avx;
|
||||
bool avx512;
|
||||
RelocModel reloc_model;
|
||||
X86VectorCapability x86_vector_capability;
|
||||
bool print_keywords;
|
||||
bool print_attributes;
|
||||
bool print_builtins;
|
||||
bool print_operators;
|
||||
bool print_precedence;
|
||||
bool print_build_settings;
|
||||
} BuildOptions;
|
||||
|
||||
|
||||
@@ -251,8 +285,7 @@ typedef struct
|
||||
OptimizationLevel optimization_level;
|
||||
SizeOptimizationLevel size_optimization_level;
|
||||
DebugInfo debug_info;
|
||||
PieGeneration pie;
|
||||
PicGeneration pic;
|
||||
RelocModel reloc_model;
|
||||
ArchOsTarget arch_os_target;
|
||||
CompilerBackend backend;
|
||||
uint32_t symtab_size;
|
||||
@@ -264,15 +297,10 @@ typedef struct
|
||||
struct
|
||||
{
|
||||
SoftFloat soft_float : 3;
|
||||
StructReturn struct_return : 3;
|
||||
bool no_memcpy_pass : 1;
|
||||
StructReturn x86_struct_return : 3;
|
||||
X86VectorCapability x86_vector_capability : 4;
|
||||
bool trap_on_wrap : 1;
|
||||
bool safe_mode : 1;
|
||||
bool no_sse : 1;
|
||||
bool no_mmx : 1;
|
||||
bool no_avx : 1;
|
||||
bool avx : 1;
|
||||
bool avx512 : 1;
|
||||
} feature;
|
||||
} BuildTarget;
|
||||
|
||||
|
||||
@@ -108,8 +108,7 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions *
|
||||
// ARCH_OS_TARGET_DEFAULT could be handled in a more cross-platform manner later on.
|
||||
target->arch_os_target = X64_WINDOWS;
|
||||
}
|
||||
if (options->pie != PIE_DEFAULT) target->pie = options->pie;
|
||||
if (options->pic != PIC_DEFAULT) target->pic = options->pic;
|
||||
if (options->reloc_model != RELOC_DEFAULT) target->reloc_model = options->reloc_model;
|
||||
|
||||
for (int i = 0; i < options->linker_arg_count; i++)
|
||||
{
|
||||
@@ -117,9 +116,10 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions *
|
||||
}
|
||||
target->no_stdlib = options->no_stdlib;
|
||||
target->emit_llvm = options->emit_llvm;
|
||||
if (options->no_avx) target->feature.no_avx = true;
|
||||
if (options->avx) target->feature.avx = true;
|
||||
if (options->avx512) target->feature.avx512 = true;
|
||||
if (options->x86_vector_capability != X86VECTOR_DEFAULT)
|
||||
{
|
||||
target->feature.x86_vector_capability = options->x86_vector_capability;
|
||||
}
|
||||
switch (options->compile_option)
|
||||
{
|
||||
case COMPILE_NORMAL:
|
||||
@@ -164,8 +164,8 @@ void init_default_build_target(BuildTarget *target, BuildOptions *options)
|
||||
.switchrange_max_size = DEFAULT_SWITCHRANGE_MAX_SIZE,
|
||||
.debug_info = DEBUG_INFO_NONE,
|
||||
.arch_os_target = ARCH_OS_TARGET_DEFAULT,
|
||||
.pie = PIE_DEFAULT,
|
||||
.pic = PIC_DEFAULT
|
||||
.reloc_model = RELOC_DEFAULT,
|
||||
.feature.x86_vector_capability = X86VECTOR_DEFAULT,
|
||||
};
|
||||
update_build_target_from_options(target, options);
|
||||
}
|
||||
|
||||
@@ -2,34 +2,15 @@
|
||||
// Use of this source code is governed by a LGPLv3.0
|
||||
// a copy of which can be found in the LICENSE file.
|
||||
|
||||
#include <utils/toml.h>
|
||||
#include <math.h>
|
||||
#include "build_internal.h"
|
||||
#define MAX_SYMTAB_SIZE (1024 * 1024)
|
||||
|
||||
TomlArray *get_array(TomlTable *table, const char *key)
|
||||
{
|
||||
TomlValue *value = toml_table_get(table, key);
|
||||
if (!value) return NULL;
|
||||
if (value->type != TOML_ARRAY)
|
||||
{
|
||||
error_exit("The key '%s' was not an array field. Did you type '[%s]' instead of '[[%s]]'?");
|
||||
}
|
||||
return value->value.array;
|
||||
}
|
||||
|
||||
|
||||
static inline const char *copy_toml_string(TomlString *string)
|
||||
const char *get_valid_string(JSONObject *table, const char *key, const char *category, bool mandatory)
|
||||
{
|
||||
size_t len = string->len;
|
||||
char *new_str = malloc_string(len + 1);
|
||||
memcpy(new_str, string->str, len);
|
||||
new_str[len] = '\0';
|
||||
return new_str;
|
||||
}
|
||||
|
||||
const char *get_valid_string(TomlTable *table, const char *key, const char *category, bool mandatory)
|
||||
{
|
||||
TomlValue *value = toml_table_get(table, key);
|
||||
JSONObject *value = json_obj_get(table, key);
|
||||
if (!value)
|
||||
{
|
||||
if (mandatory)
|
||||
@@ -38,47 +19,43 @@ const char *get_valid_string(TomlTable *table, const char *key, const char *cate
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
if (value->type != TOML_STRING)
|
||||
if (value->type != J_STRING)
|
||||
{
|
||||
error_exit("%s had an invalid mandatory '%s' field that was not a string, please correct it.", category, key);
|
||||
}
|
||||
return copy_toml_string(value->value.string);
|
||||
return value->str;
|
||||
}
|
||||
|
||||
int get_valid_bool(TomlTable *table, const char *key, const char *category, int default_val)
|
||||
int get_valid_bool(JSONObject *json, const char *key, const char *category, int default_val)
|
||||
{
|
||||
TomlValue *value = toml_table_get(table, key);
|
||||
JSONObject *value = json_obj_get(json, key);
|
||||
if (!value) return default_val;
|
||||
if (value->type != TOML_BOOLEAN)
|
||||
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->value.boolean;
|
||||
return value->b;
|
||||
}
|
||||
|
||||
|
||||
static int get_valid_string_setting(TomlTable *table, const char *key, const char *category, const char** values, int first_result, int count, const char *expected)
|
||||
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)
|
||||
{
|
||||
TomlValue *value = toml_table_get(table, key);
|
||||
JSONObject *value = json_obj_get(json, key);
|
||||
if (!value)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (value->type == TOML_STRING)
|
||||
if (value->type == J_STRING)
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
unsigned str_len = (unsigned) strlen(values[i]);
|
||||
if (str_len != value->value.string->len) continue;
|
||||
if (memcmp(values[i], value->value.string->str, str_len) == 0) return i + first_result;
|
||||
}
|
||||
int res = str_in_list(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(TomlTable *table, const char *key, const char *category, bool mandatory)
|
||||
long get_valid_integer(JSONObject *table, const char *key, const char *category, bool mandatory)
|
||||
{
|
||||
TomlValue *value = toml_table_get(table, key);
|
||||
JSONObject *value = json_obj_get(table, key);
|
||||
if (!value)
|
||||
{
|
||||
if (mandatory)
|
||||
@@ -87,134 +64,171 @@ long get_valid_integer(TomlTable *table, const char *key, const char *category,
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
if (value->type != TOML_INTEGER)
|
||||
if (value->type != J_NUMBER || trunc(value->f) != value->f)
|
||||
{
|
||||
error_exit("%s had an invalid mandatory '%s' field that was not an integer, please correct it.", category, key);
|
||||
}
|
||||
return value->value.integer;
|
||||
return trunc(value->f);
|
||||
}
|
||||
|
||||
|
||||
static const char **get_valid_array(TomlTable *table, const char *key, const char *category, bool mandatory)
|
||||
static const char **get_valid_array(JSONObject *table, const char *key, const char *category, bool mandatory)
|
||||
{
|
||||
TomlValue *value = toml_table_get(table, key);
|
||||
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_TOML, category, key);
|
||||
error_exit("Error reading %s: %s was missing a mandatory '%s' field, please add it.", PROJECT_JSON, category, key);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
if (value->type != TOML_ARRAY)
|
||||
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_TOML, category, key);
|
||||
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->value.array->len; i++)
|
||||
for (unsigned i = 0; i < value->array_len; i++)
|
||||
{
|
||||
TomlValue *val = value->value.array->elements[i];
|
||||
if (val->type != TOML_STRING)
|
||||
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_TOML, category, key);
|
||||
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, copy_toml_string(val->value.string));
|
||||
vec_add(values, val->str);
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
void project_add_target(Project *project, TomlValue *wrapped_table, const char *type, const char *type_key, TargetType target_type)
|
||||
static void load_into_build_target(JSONObject *json, const char *type, BuildTarget *target)
|
||||
{
|
||||
if (wrapped_table->type != TOML_TABLE)
|
||||
const char *cc = get_valid_string(json, "cc", type, false);
|
||||
const char *cflags = get_valid_string(json, "cflags", type, false);
|
||||
const char **csource_dirs = get_valid_array(json, "csources", type, false);
|
||||
const char *version = get_valid_string(json, "version", type, false);
|
||||
const char *langrev = get_valid_string(json, "langrev", type, false);
|
||||
const char **source_dirs = get_valid_array(json, "sources", type, target->source_dirs == NULL);
|
||||
const char **libraries = get_valid_array(json, "libs", type, false);
|
||||
static const char *debug_infos[3] = {
|
||||
[DEBUG_INFO_FULL] = "full",
|
||||
[DEBUG_INFO_NONE] = "none",
|
||||
[DEBUG_INFO_LINE_TABLES] = "line-tables"
|
||||
};
|
||||
DebugInfo info = get_valid_string_setting(json, "debug-info", type, debug_infos, 0, 3, "one of 'full' 'line-table' or 'none'.");
|
||||
const char *arch_os_string = get_valid_string(json, "target", type, false);
|
||||
long symtab_size = get_valid_integer(json, "symtab", type, false);
|
||||
const char *cpu = get_valid_string(json, "cpu", type, false);
|
||||
int reloc = get_valid_string_setting(json, "reloc", type, reloc_models, 0, 5, "'none', 'pic', 'PIC', 'pie' or 'PIE'.");
|
||||
int x86vec = get_valid_string_setting(json, "x86vec", type, vector_capability, 0, 5, "none, mmx, sse, avx or avx512");
|
||||
|
||||
if (cc) target->cc = cc;
|
||||
if (cflags) target->cflags = cflags;
|
||||
if (csource_dirs) target->csource_dirs = csource_dirs;
|
||||
if (version) target->version = version;
|
||||
if (langrev) target->langrev = langrev;
|
||||
if (source_dirs) target->source_dirs = source_dirs;
|
||||
if (libraries) target->libraries = libraries;
|
||||
if (info > -1) target->debug_info = info;
|
||||
if (cpu) target->cpu = cpu;
|
||||
if (reloc > -1) target->reloc_model = (RelocModel)reloc;
|
||||
if (x86vec > -1) target->feature.x86_vector_capability = x86vec;
|
||||
|
||||
if (arch_os_string)
|
||||
{
|
||||
error_exit("The %s had an invalid %s. Please check your [[%s]] configurations.", PROJECT_TOML, type, type_key);
|
||||
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);
|
||||
target->arch_os_target = arch_os;
|
||||
}
|
||||
if (symtab_size > 0)
|
||||
{
|
||||
if (symtab_size < 1024)
|
||||
{
|
||||
error_exit("Error reading %s: %s symtab was less than 1024.", PROJECT_JSON, type);
|
||||
}
|
||||
if (symtab_size > MAX_SYMTAB_SIZE)
|
||||
{
|
||||
error_exit("Error reading %s: %s symtab may not exceed %d.", PROJECT_JSON, type, MAX_SYMTAB_SIZE);
|
||||
}
|
||||
target->symtab_size = (uint32_t)symtab_size;
|
||||
}
|
||||
|
||||
target->feature.trap_on_wrap = get_valid_bool(json, "trap-on-wrap", type, target->feature.trap_on_wrap);
|
||||
// Use the fact that they correspond to 0, 1, -1
|
||||
target->feature.x86_struct_return = get_valid_bool(json, "x86-stack-struct-return", type, target->feature.x86_struct_return);
|
||||
target->feature.soft_float = get_valid_bool(json, "soft-float", type, target->feature.soft_float);
|
||||
|
||||
}
|
||||
static void project_add_target(Project *project, BuildTarget *default_target, JSONObject *json, const char *name, const char *type)
|
||||
{
|
||||
assert(json->type == J_OBJECT);
|
||||
BuildTarget *target = CALLOCS(BuildTarget);
|
||||
target->optimization_level = OPTIMIZATION_DEFAULT;
|
||||
target->size_optimization_level = SIZE_OPTIMIZATION_NONE;
|
||||
target->arch_os_target = ARCH_OS_TARGET_DEFAULT;
|
||||
target->debug_info = DEBUG_INFO_NONE;
|
||||
target->symtab_size = DEFAULT_SYMTAB_SIZE;
|
||||
*target = *default_target;
|
||||
vec_add(project->targets, target);
|
||||
TomlTable *table = wrapped_table->value.table;
|
||||
target->name = get_valid_string(table, "name", type, true);
|
||||
target->name = name;
|
||||
VECEACH(project->targets, i)
|
||||
{
|
||||
BuildTarget *other_target = project->targets[i];
|
||||
if (other_target == target) continue;
|
||||
if (strcmp(other_target->name, target->name) == 0)
|
||||
{
|
||||
error_exit("More %s contained more than one target with the name %s. Please make all target names unique.", PROJECT_TOML, target->name);
|
||||
error_exit("More %s contained more than one target with the name %s. Please make all target names unique.", PROJECT_JSON, target->name);
|
||||
}
|
||||
}
|
||||
target->cc = get_valid_string(table, "cc", type, false);
|
||||
if (!target->cc) target->cc = "cc";
|
||||
target->cflags = get_valid_string(table, "cflags", type, false);
|
||||
target->csource_dirs = get_valid_array(table, "csources", type, false);
|
||||
|
||||
type = strformat("%s %s", type, target->name);
|
||||
target->version = get_valid_string(table, "version", type, false);
|
||||
if (!target->version) target->version = "1.0.0";
|
||||
target->langrev = get_valid_string(table, "langrev", type, false);
|
||||
target->source_dirs = get_valid_array(table, "sources", type, true);
|
||||
target->libraries = get_valid_array(table, "libs", type, false);
|
||||
static const char *debug_infos[3] = {
|
||||
[DEBUG_INFO_FULL] = "full",
|
||||
[DEBUG_INFO_NONE] = "none",
|
||||
[DEBUG_INFO_LINE_TABLES] = "line-tables"
|
||||
};
|
||||
DebugInfo info = get_valid_string_setting(table, "debug-info", type, debug_infos, 0, 3, "one of 'full' 'line-table' or 'none'.");
|
||||
if (info > -1) target->debug_info = info;
|
||||
const char *arch_os_string = get_valid_string(table, "target", type, false);
|
||||
if (arch_os_string)
|
||||
{
|
||||
ArchOsTarget arch_os = arch_os_target_from_string(arch_os_string);
|
||||
if (arch_os == ARCH_OS_TARGET_DEFAULT) error_exit("Error reading %s: %s target was not valid.", PROJECT_TOML, type);
|
||||
target->arch_os_target = arch_os;
|
||||
}
|
||||
long symtab_size = get_valid_integer(table, "symtab", type, false);
|
||||
if (symtab_size > 0)
|
||||
{
|
||||
if (symtab_size < 1024)
|
||||
{
|
||||
error_exit("Error reading %s: %s symtab was less than 1024.", PROJECT_TOML, type);
|
||||
}
|
||||
if (symtab_size > MAX_SYMTAB_SIZE)
|
||||
{
|
||||
error_exit("Error reading %s: %s symtab may not exceed %d.", PROJECT_TOML, type, MAX_SYMTAB_SIZE);
|
||||
}
|
||||
target->symtab_size = (uint32_t)symtab_size;
|
||||
}
|
||||
const char *cpu = get_valid_string(table, "cpu", type, false);
|
||||
target->cpu = cpu ? cpu : "generic";
|
||||
|
||||
static const char *pies[3] = {
|
||||
[PIE_SMALL] = "yes-limited",
|
||||
[PIE_NONE] = "no",
|
||||
[PIE_BIG] = "yes-unlimited"
|
||||
};
|
||||
target->pie = get_valid_string_setting(table, "pie", type, pies, 0, 3, "'yes-limited', 'yes-unlimited' or 'no'.");
|
||||
target->pic = get_valid_string_setting(table, "pic", type, pies, 0, 3, "'yes-limited', 'yes-unlimited' or 'no'.");
|
||||
|
||||
target->feature.no_memcpy_pass = get_valid_bool(table, "no-memcpy-pass", type, false);
|
||||
target->feature.trap_on_wrap = get_valid_bool(table, "trap-on-wrap", type, false);
|
||||
// Use the fact that they correspond to 0, 1, -1
|
||||
target->feature.struct_return = get_valid_bool(table, "stack-struct-return", type, STRUCT_RETURN_DEFAULT);
|
||||
target->feature.soft_float = get_valid_bool(table, "soft-float", type, SOFT_FLOAT_DEFAULT);
|
||||
target->feature.avx = get_valid_bool(table, "avx", type, false);
|
||||
target->feature.avx512 = get_valid_bool(table, "avx512", type, false);
|
||||
target->feature.no_avx = get_valid_bool(table, "no-avx", type, false);
|
||||
target->feature.no_sse = get_valid_bool(table, "no-sse", type, false);
|
||||
target->feature.no_mmx = get_valid_bool(table, "no-mmx", type, false);
|
||||
load_into_build_target(json, type, target);
|
||||
}
|
||||
|
||||
static void project_add_targets(Project *project, TomlTable *table, const char *type, const char *type_key, TargetType target_type)
|
||||
static void project_add_targets(Project *project, JSONObject *project_data)
|
||||
{
|
||||
TomlArray *targets = get_array(table, type_key);
|
||||
if (!targets) return;
|
||||
for (unsigned i = 0; i < targets->len; i++)
|
||||
assert(project_data->type == J_OBJECT);
|
||||
static const char* targets[4] = { [TARGET_TYPE_EXECUTABLE] = "executable",
|
||||
[TARGET_TYPE_STATIC_LIB] = "static-lib",
|
||||
[TARGET_TYPE_DYNAMIC_LIB] = "dynamic-lib",
|
||||
[TARGET_TYPE_TEST] = "test" };
|
||||
static const char *target_desc[4] = {
|
||||
[TARGET_TYPE_EXECUTABLE] = "Executable",
|
||||
[TARGET_TYPE_STATIC_LIB] = "Static library",
|
||||
[TARGET_TYPE_DYNAMIC_LIB] = "Dynamic library",
|
||||
[TARGET_TYPE_TEST] = "test suite" };
|
||||
|
||||
BuildTarget default_target = {
|
||||
.optimization_level = OPTIMIZATION_DEFAULT,
|
||||
.size_optimization_level = SIZE_OPTIMIZATION_NONE,
|
||||
.arch_os_target = ARCH_OS_TARGET_DEFAULT,
|
||||
.debug_info = DEBUG_INFO_NONE,
|
||||
.symtab_size = DEFAULT_SYMTAB_SIZE,
|
||||
.cc = "cc",
|
||||
.version = "1.0.0",
|
||||
.langrev = "1",
|
||||
.cpu = "generic",
|
||||
.feature.x86_struct_return = STRUCT_RETURN_DEFAULT,
|
||||
.feature.soft_float = SOFT_FLOAT_DEFAULT,
|
||||
.feature.trap_on_wrap = false,
|
||||
.feature.x86_vector_capability = X86VECTOR_DEFAULT,
|
||||
.feature.safe_mode = true,
|
||||
};
|
||||
load_into_build_target(project_data, "default target", &default_target);
|
||||
JSONObject *targets_json = json_obj_get(project_data, "targets");
|
||||
if (!targets_json)
|
||||
{
|
||||
project_add_target(project, targets->elements[i], type, type_key, target_type);
|
||||
error_exit("No targets found in project.");
|
||||
}
|
||||
if (targets_json->type != J_OBJECT)
|
||||
{
|
||||
error_exit("'targets' did not contain map of targets.");
|
||||
}
|
||||
JSONObject *targets_find = NULL;
|
||||
for (unsigned i = 0; i < targets_json->member_len; i++)
|
||||
{
|
||||
JSONObject *object = targets_json->members[i];
|
||||
const char *key = targets_json->keys[i];
|
||||
if (object->type != J_OBJECT)
|
||||
{
|
||||
error_exit("Invalid data in target '%s'", key);
|
||||
}
|
||||
int type = get_valid_string_setting(object, "type", "Target type", targets, 0, 4, "a target type like 'executable' or 'static-lib'");
|
||||
if (type < 0) error_exit("Target %s did not contain 'type' key.", key);
|
||||
project_add_target(project, &default_target, object, key, target_desc[type]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,7 +246,7 @@ BuildTarget *project_select_target(Project *project, const char *optional_target
|
||||
{
|
||||
if (!vec_size(project->targets))
|
||||
{
|
||||
error_exit("No targets could be found in %s. Please define at least one target, for example a [[executable]] and try again.", PROJECT_TOML);
|
||||
error_exit("No targets could be found in %s. Please define at least one target, for example an 'executable' and try again.", PROJECT_JSON);
|
||||
}
|
||||
if (!optional_target)
|
||||
{
|
||||
@@ -243,20 +257,25 @@ BuildTarget *project_select_target(Project *project, const char *optional_target
|
||||
BuildTarget *target = project->targets[i];
|
||||
if (strcmp(target->name, optional_target) == 0) return target;
|
||||
}
|
||||
error_exit("No build target named '%s' was found in %s. Was it misspelled?", optional_target, PROJECT_TOML);
|
||||
error_exit("No build target named '%s' was found in %s. Was it misspelled?", optional_target, PROJECT_JSON);
|
||||
}
|
||||
|
||||
Project *project_load(void)
|
||||
{
|
||||
Project *project = CALLOCS(Project);
|
||||
TomlErr err = { .code = TOML_OK };
|
||||
TomlTable *toml = toml_load_filename(PROJECT_TOML, &err);
|
||||
if (err.code != TOML_OK)
|
||||
size_t size;
|
||||
char *read = read_file(PROJECT_JSON, &size);
|
||||
JsonParser parser;
|
||||
json_init_string(&parser, read, &malloc_arena);
|
||||
JSONObject *json = json_parse(&parser);
|
||||
if (parser.error_message)
|
||||
{
|
||||
error_exit("%s could not be read. Can you please check the read permissions on the file?", PROJECT_TOML);
|
||||
error_exit("Error on line %d reading '%s':'%s'", parser.line, PROJECT_JSON, parser.error_message);
|
||||
}
|
||||
project_add_targets(project, toml, "executable", "executable", TARGET_TYPE_EXECUTABLE);
|
||||
project_add_targets(project, toml, "dynamic library", "dynamic-lib", TARGET_TYPE_DYNAMIC_LIB);
|
||||
project_add_targets(project, toml, "static library", "static-lib", TARGET_TYPE_STATIC_LIB);
|
||||
if (!json || json->type != J_OBJECT)
|
||||
{
|
||||
error_exit("Expected a map of targets in '%s'.", PROJECT_JSON);
|
||||
}
|
||||
project_add_targets(project, json);
|
||||
return project;
|
||||
}
|
||||
|
||||
@@ -14,22 +14,61 @@
|
||||
#include "build_options.h"
|
||||
#include "../utils/lib.h"
|
||||
|
||||
const char* TOML =
|
||||
"[[executable]]\n"
|
||||
"# name of the target\n"
|
||||
"name = \"%s\"\n"
|
||||
"# version using semantic versioning\n"
|
||||
"version = \"0.1.0\"\n"
|
||||
"# authors, optionally with email\n"
|
||||
"authors = [\"John Doe <john.doe@example.com>\"]\n"
|
||||
"# language version of C3\n"
|
||||
"langrev = \"1\"\n"
|
||||
"# warnings used\n"
|
||||
"warnings = [\"no-unused\"]\n"
|
||||
"# sources compiled\n"
|
||||
"sources = [\"src/**\"]\n"
|
||||
"# libraries to use\n"
|
||||
"libs = [\"lib/**\"]\n";
|
||||
const char* JSON =
|
||||
"{\n"
|
||||
" // language version of C3\n"
|
||||
" \"langrev\": \"1\",\n"
|
||||
" // warnings used for all targets\n"
|
||||
" \"warnings\": [ \"no-unused\" ],\n"
|
||||
" // libraries to use for all targets\n"
|
||||
" \"libs\": [ \"lib/**\" ],\n"
|
||||
" // authors, optionally with email\n"
|
||||
" \"authors\": [ \"John Doe <john.doe@example.com>\" ],\n"
|
||||
" // Version using semantic versioning\n"
|
||||
" \"version\": \"0.1.0\",\n"
|
||||
" // sources compiled for all targets\n"
|
||||
" \"sources\": [ \"src/**\" ],\n"
|
||||
" // Targets\n"
|
||||
" \"targets\": {\n"
|
||||
" \"%s\": {\n"
|
||||
" // executable or library\n"
|
||||
" \"type\": \"executable\"\n"
|
||||
" // additional libraries, sources\n"
|
||||
" // and overrides of global settings here\n"
|
||||
" },\n"
|
||||
" }\n"
|
||||
" /*\n"
|
||||
" // Debug information, may be 'none', 'full' and 'line-tables'\n"
|
||||
" \"debug-info\": \"full\",\n"
|
||||
" // Architecture and OS target:\n"
|
||||
" \"target\": \"x64-windows\",\n"
|
||||
" // The size of the symtab, which limits the amount\n"
|
||||
" // of symbols that can be used. Should usually not\n"
|
||||
" // be changed.\n"
|
||||
" \"symtab\": 4194304,\n"
|
||||
" // \"none\", \"pic\", \"PIC\", \"pie\", \"PIE\"\n"
|
||||
" \"reloc\": \"none\",\n"
|
||||
" // Trap on signed and unsigned integer wrapping\n"
|
||||
" // for testing\n"
|
||||
" \"trap-on-wrap\": false,\n"
|
||||
" // Use / don't use soft float, value is otherwise target default\n"
|
||||
" \"soft-float\": false,\n"
|
||||
" // Vector settings on x86: none/mmx/sse/avx/avx512\n"
|
||||
" \"x86vec\": \"sse\",\n"
|
||||
" // CPU name, used for optimizations in the LLVM backend\n"
|
||||
" \"cpu\": \"generic\",\n"
|
||||
" // Output location, relative to project file\n"
|
||||
" \"output\": \"../build\",\n"
|
||||
" // C compiler if the project also compiles c sources\n"
|
||||
" // defaults to 'cc'\n"
|
||||
" \"cc\": \"cc\",\n"
|
||||
" // c sources if the project also compiles c sources\n"
|
||||
" // relative to the project file\n"
|
||||
" \"csources\": [\n"
|
||||
" \"csource/**\"\n"
|
||||
" ]\n"
|
||||
" */\n"
|
||||
"}";
|
||||
|
||||
void create_project(BuildOptions *build_options)
|
||||
{
|
||||
@@ -67,9 +106,9 @@ void create_project(BuildOptions *build_options)
|
||||
if (!file) goto ERROR;
|
||||
if (fclose(file)) goto ERROR;
|
||||
|
||||
file = fopen("project.toml", "a");
|
||||
file = fopen("project.c3p", "a");
|
||||
if (!file) goto ERROR;
|
||||
(void) fprintf(file, TOML, build_options->project_name);
|
||||
(void) fprintf(file, JSON, build_options->project_name);
|
||||
if (fclose(file)) goto ERROR;
|
||||
|
||||
if (mkdir("lib", 0755)) goto ERROR;
|
||||
|
||||
@@ -69,6 +69,64 @@ static void prepare_msys2_linker_flags(const char ***args, const char **files_to
|
||||
#undef add_arg
|
||||
}
|
||||
|
||||
static void append_pie_pic_options(RelocModel reloc, const char ***args_ref)
|
||||
{
|
||||
switch (reloc)
|
||||
{
|
||||
case RELOC_DEFAULT:
|
||||
UNREACHABLE
|
||||
case RELOC_NONE:
|
||||
vec_add(*args_ref, "-no-pic");
|
||||
vec_add(*args_ref, "-no-pie");
|
||||
vec_add(*args_ref, "-no-PIC");
|
||||
vec_add(*args_ref, "-no-PIE");
|
||||
break;
|
||||
case RELOC_SMALL_PIC:
|
||||
vec_add(*args_ref, "-pic");
|
||||
break;
|
||||
case RELOC_BIG_PIC:
|
||||
vec_add(*args_ref, "-PIC");
|
||||
break;
|
||||
case RELOC_SMALL_PIE:
|
||||
vec_add(*args_ref, "-pie");
|
||||
vec_add(*args_ref, "-pic");
|
||||
break;
|
||||
case RELOC_BIG_PIE:
|
||||
vec_add(*args_ref, "-PIE");
|
||||
vec_add(*args_ref, "-PIC");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void append_fpie_pic_options(RelocModel reloc, const char ***args_ref)
|
||||
{
|
||||
switch (reloc)
|
||||
{
|
||||
case RELOC_DEFAULT:
|
||||
UNREACHABLE
|
||||
case RELOC_NONE:
|
||||
vec_add(*args_ref, "-fno-pic");
|
||||
vec_add(*args_ref, "-fno-pie");
|
||||
vec_add(*args_ref, "-fno-PIC");
|
||||
vec_add(*args_ref, "-fno-PIE");
|
||||
break;
|
||||
case RELOC_SMALL_PIC:
|
||||
vec_add(*args_ref, "-fpic");
|
||||
break;
|
||||
case RELOC_BIG_PIC:
|
||||
vec_add(*args_ref, "-fPIC");
|
||||
break;
|
||||
case RELOC_SMALL_PIE:
|
||||
vec_add(*args_ref, "-fpie");
|
||||
vec_add(*args_ref, "-fpic");
|
||||
break;
|
||||
case RELOC_BIG_PIE:
|
||||
vec_add(*args_ref, "-fPIE");
|
||||
vec_add(*args_ref, "-fPIC");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static bool link_exe(const char *output_file, const char **files_to_link, unsigned file_count)
|
||||
{
|
||||
const char **args = NULL;
|
||||
@@ -141,15 +199,11 @@ static bool link_exe(const char *output_file, const char **files_to_link, unsign
|
||||
vec_add(args, "-lm");
|
||||
vec_add(args, "-syslibroot");
|
||||
vec_add(args, "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk");
|
||||
if (platform_target.pie)
|
||||
append_pie_pic_options(platform_target.reloc_model, &args);
|
||||
if (platform_target.reloc_model == RELOC_SMALL_PIE || platform_target.reloc_model == RELOC_BIG_PIE)
|
||||
{
|
||||
vec_add(args, "-macosx_version_min");
|
||||
vec_add(args, platform_target.arch == ARCH_TYPE_AARCH64 ? "11.0" : "10.8");
|
||||
vec_add(args, "-pie");
|
||||
}
|
||||
else
|
||||
{
|
||||
vec_add(args, "-no_pie");
|
||||
}
|
||||
break;
|
||||
case OS_TYPE_WATCHOS:
|
||||
@@ -167,7 +221,8 @@ static bool link_exe(const char *output_file, const char **files_to_link, unsign
|
||||
{
|
||||
case ARCH_TYPE_X86_64:
|
||||
vec_add(args, "elf_x86_64");
|
||||
if (platform_target.pie || platform_target.pic)
|
||||
append_pie_pic_options(platform_target.reloc_model, &args);
|
||||
if (is_pie_pic(platform_target.reloc_model))
|
||||
{
|
||||
vec_add(args, "--eh-frame-hdr");
|
||||
vec_add(args, "/usr/lib/x86_64-linux-gnu/crt1.o");
|
||||
@@ -175,7 +230,6 @@ static bool link_exe(const char *output_file, const char **files_to_link, unsign
|
||||
add_files(&args, files_to_link, file_count);
|
||||
vec_add(args, "/usr/lib/x86_64-linux-gnu/crti.o");
|
||||
vec_add(args, "/usr/lib/gcc/x86_64-linux-gnu/10/crtendS.o");
|
||||
vec_add(args, "-pie");
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -186,7 +240,6 @@ static bool link_exe(const char *output_file, const char **files_to_link, unsign
|
||||
vec_add(args, "-lm");
|
||||
vec_add(args, "/usr/lib/x86_64-linux-gnu/crti.o");
|
||||
vec_add(args, "/usr/lib/gcc/x86_64-linux-gnu/10/crtend.o");
|
||||
vec_add(args, "-no-pie");
|
||||
}
|
||||
vec_add(args, "/usr/lib/x86_64-linux-gnu/crtn.o");
|
||||
vec_add(args, "-L/usr/lib/x86_64-linux-gnu/");
|
||||
@@ -212,7 +265,7 @@ static bool link_exe(const char *output_file, const char **files_to_link, unsign
|
||||
break;
|
||||
default:
|
||||
add_files(&args, files_to_link, file_count);
|
||||
vec_add(args, platform_target.pie ? "-pie" : "-no_pie");
|
||||
append_pie_pic_options(platform_target.reloc_model, &args);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -301,21 +354,7 @@ void platform_linker(const char *output_file, const char **files, unsigned file_
|
||||
{
|
||||
vec_add(parts, active_target.link_args[i]);
|
||||
}
|
||||
switch (platform_target.pie)
|
||||
{
|
||||
case PIE_DEFAULT:
|
||||
UNREACHABLE
|
||||
case PIE_NONE:
|
||||
vec_add(parts, "-fno-PIE");
|
||||
vec_add(parts, "-fno-pie");
|
||||
break;
|
||||
case PIE_SMALL:
|
||||
vec_add(parts, "-fpie");
|
||||
break;
|
||||
case PIE_BIG:
|
||||
vec_add(parts, "-fPIE");
|
||||
break;
|
||||
}
|
||||
append_fpie_pic_options(platform_target.reloc_model, &parts);
|
||||
vec_add(parts, "-o");
|
||||
vec_add(parts, output_file);
|
||||
for (unsigned i = 0; i < file_count; i++)
|
||||
@@ -344,21 +383,7 @@ void platform_compiler(const char **files, unsigned file_count, const char *flag
|
||||
strstr(flags, "-fPIE")); // strcasestr is apparently nonstandard >:(
|
||||
if (!pie_set)
|
||||
{
|
||||
switch (platform_target.pie)
|
||||
{
|
||||
case PIE_DEFAULT:
|
||||
UNREACHABLE
|
||||
case PIE_NONE:
|
||||
vec_add(parts, "-fno-PIE");
|
||||
vec_add(parts, "-fno-pie");
|
||||
break;
|
||||
case PIE_SMALL:
|
||||
vec_add(parts, "-fpie");
|
||||
break;
|
||||
case PIE_BIG:
|
||||
vec_add(parts, "-fPIE");
|
||||
break;
|
||||
}
|
||||
append_fpie_pic_options(platform_target.reloc_model, &parts);
|
||||
}
|
||||
|
||||
vec_add(parts, "-c");
|
||||
|
||||
@@ -51,19 +51,6 @@ ABIArgInfo *x64_indirect_return_result(Type *type)
|
||||
}
|
||||
return abi_arg_new_direct();
|
||||
}
|
||||
static ByteSize x64_native_vector_size_for_avx(void)
|
||||
{
|
||||
switch (platform_target.x64.avx_level)
|
||||
{
|
||||
case AVX_NONE:
|
||||
return 16;
|
||||
case AVX:
|
||||
return 32;
|
||||
case AVX_512:
|
||||
return 64;
|
||||
}
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
|
||||
static bool x64_type_is_illegal_vector(Type *type)
|
||||
@@ -72,7 +59,7 @@ static bool x64_type_is_illegal_vector(Type *type)
|
||||
if (type->type_kind != TYPE_VECTOR) return false;
|
||||
ByteSize size = type_size(type);
|
||||
// Less than 64 bits or larger than the avx native size => not allowed.
|
||||
if (size <= 8 || size > x64_native_vector_size_for_avx()) return true;
|
||||
if (size <= 8 || size > platform_target.x64.native_vector_size_avx) return true;
|
||||
// If we pass i128 in mem, then check for that.
|
||||
if (platform_target.x64.pass_int128_vector_in_mem)
|
||||
{
|
||||
@@ -257,7 +244,7 @@ void x64_classify_struct_union(Type *type, ByteSize offset_base, X64Class *curre
|
||||
// and fallback to memory.
|
||||
if (size > 16 &&
|
||||
((!is_union && size != type_size(member->type))
|
||||
|| size > x64_native_vector_size_for_avx()))
|
||||
|| size > platform_target.x64.native_vector_size_avx))
|
||||
{
|
||||
*lo_class = CLASS_MEMORY;
|
||||
x64_classify_post_merge(size, lo_class, hi_class);
|
||||
@@ -302,7 +289,7 @@ void x64_classify_array(Type *type, ByteSize offset_base, X64Class *current, X64
|
||||
// The only case a 256-bit or a 512-bit wide vector could be used is when
|
||||
// the struct contains a single 256-bit or 512-bit field. Early check
|
||||
// and fallback to memory.
|
||||
if (size > 16 && (size != type_size(element) || size > x64_native_vector_size_for_avx()))
|
||||
if (size > 16 && (size != type_size(element) || size > platform_target.x64.native_vector_size_avx))
|
||||
{
|
||||
*lo_class = CLASS_MEMORY;
|
||||
return;
|
||||
@@ -359,7 +346,7 @@ void x64_classify_vector(Type *type, ByteSize offset_base, X64Class *current, X6
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (size == 16 || (named_arg == NAMED && size <= x64_native_vector_size_for_avx()))
|
||||
if (size == 16 || (named_arg == NAMED && size <= platform_target.x64.native_vector_size_avx))
|
||||
{
|
||||
if (platform_target.x64.pass_int128_vector_in_mem) return;
|
||||
|
||||
|
||||
@@ -20,17 +20,29 @@ void gencontext_begin_module(GenContext *c)
|
||||
LLVMSetSourceFileName(c->module, c->code_module->name->module, strlen(c->code_module->name->module));
|
||||
LLVMTypeRef options_type = LLVMInt8TypeInContext(c->context);
|
||||
|
||||
if (active_target.pic == PIC_BIG || active_target.pic == PIC_SMALL)
|
||||
static const char *pic_level = "PIC Level";
|
||||
static const char *pie_level = "PIE Level";
|
||||
LLVMMetadataRef setting;
|
||||
switch (active_target.reloc_model)
|
||||
{
|
||||
static const char *pic_level = "PIC Level";
|
||||
LLVMMetadataRef setting = LLVMValueAsMetadata(LLVMConstInt(options_type, (unsigned)active_target.pic, false));
|
||||
LLVMAddModuleFlag(c->module, LLVMModuleFlagBehaviorOverride, pic_level, strlen(pic_level), setting);
|
||||
}
|
||||
if (active_target.pie == PIE_BIG || active_target.pie == PIE_SMALL)
|
||||
{
|
||||
static const char *pie_level = "PIE Level";
|
||||
LLVMMetadataRef setting = LLVMValueAsMetadata(LLVMConstInt(options_type, (unsigned)active_target.pie, false));
|
||||
LLVMAddModuleFlag(c->module, LLVMModuleFlagBehaviorOverride, pie_level, strlen(pie_level), setting);
|
||||
case RELOC_BIG_PIE:
|
||||
setting = LLVMValueAsMetadata(LLVMConstInt(options_type, (unsigned)2 /* PIE */, false));
|
||||
LLVMAddModuleFlag(c->module, LLVMModuleFlagBehaviorOverride, pie_level, strlen(pie_level), setting);
|
||||
FALLTHROUGH;
|
||||
case RELOC_BIG_PIC:
|
||||
setting = LLVMValueAsMetadata(LLVMConstInt(options_type, (unsigned)2 /* PIC */, false));
|
||||
LLVMAddModuleFlag(c->module, LLVMModuleFlagBehaviorOverride, pic_level, strlen(pic_level), setting);
|
||||
break;
|
||||
case RELOC_SMALL_PIE:
|
||||
setting = LLVMValueAsMetadata(LLVMConstInt(options_type, (unsigned)1 /* pie */, false));
|
||||
LLVMAddModuleFlag(c->module, LLVMModuleFlagBehaviorOverride, pie_level, strlen(pie_level), setting);
|
||||
FALLTHROUGH;
|
||||
case RELOC_SMALL_PIC:
|
||||
setting = LLVMValueAsMetadata(LLVMConstInt(options_type, (unsigned)1 /* pic */, false));
|
||||
LLVMAddModuleFlag(c->module, LLVMModuleFlagBehaviorOverride, pic_level, strlen(pic_level), setting);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
LLVMSetTarget(c->module, platform_target.target_triple);
|
||||
|
||||
@@ -413,9 +413,9 @@ static inline void target_setup_x86_abi(BuildTarget *target)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (target->feature.struct_return != STRUCT_RETURN_DEFAULT)
|
||||
if (target->feature.x86_struct_return != STRUCT_RETURN_DEFAULT)
|
||||
{
|
||||
platform_target.x86.return_small_struct_in_reg_abi = target->feature.struct_return == STRUCT_RETURN_REG;
|
||||
platform_target.x86.return_small_struct_in_reg_abi = target->feature.x86_struct_return == STRUCT_RETURN_REG;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -423,13 +423,17 @@ static inline void target_setup_x86_abi(BuildTarget *target)
|
||||
static inline void target_setup_x64_abi(BuildTarget *target)
|
||||
{
|
||||
platform_target.abi = ABI_X64;
|
||||
platform_target.x64.avx_level = AVX;
|
||||
X86VectorCapability vector_capability;
|
||||
platform_target.x64.is_win64 = platform_target.os == OS_TYPE_WIN32;
|
||||
if (target->feature.avx512) platform_target.x64.avx_level = AVX_512;
|
||||
if (target->feature.avx) platform_target.x64.avx_level = AVX;
|
||||
if (target->feature.no_avx) platform_target.x64.avx_level = AVX_NONE;
|
||||
if (target->feature.no_mmx) platform_target.x64.no_mmx = true;
|
||||
if (target->feature.no_sse) platform_target.x64.no_sse = true;
|
||||
if (target->feature.x86_vector_capability != X86VECTOR_DEFAULT)
|
||||
{
|
||||
vector_capability = target->feature.x86_vector_capability;
|
||||
}
|
||||
else
|
||||
{
|
||||
vector_capability = X86VECTOR_AVX;
|
||||
}
|
||||
platform_target.x64.x86_vector_capability = vector_capability;
|
||||
if (target->feature.soft_float == SOFT_FLOAT_YES) platform_target.x64.soft_float = true;
|
||||
if (platform_target.environment_type == ENV_TYPE_GNU)
|
||||
{
|
||||
@@ -439,17 +443,20 @@ static inline void target_setup_x64_abi(BuildTarget *target)
|
||||
{
|
||||
platform_target.x64.pass_int128_vector_in_mem = true;
|
||||
}
|
||||
switch (platform_target.x64.avx_level)
|
||||
switch (vector_capability)
|
||||
{
|
||||
case AVX_NONE:
|
||||
platform_target.x64.align_simd_default = 128;
|
||||
break;
|
||||
case AVX:
|
||||
case X86VECTOR_AVX:
|
||||
platform_target.x64.native_vector_size_avx = 32;
|
||||
platform_target.x64.align_simd_default = 256;
|
||||
break;
|
||||
case AVX_512:
|
||||
case X86VECTOR_AVX512:
|
||||
platform_target.x64.native_vector_size_avx = 64;
|
||||
platform_target.x64.align_simd_default = 512;
|
||||
break;
|
||||
default:
|
||||
platform_target.x64.native_vector_size_avx = 16;
|
||||
platform_target.x64.align_simd_default = 128;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1027,35 +1034,61 @@ static const char *os_dynamic_library_suffix(OsType os)
|
||||
return ".so";
|
||||
}
|
||||
|
||||
static PicGeneration arch_os_pic_default(ArchType arch, OsType os)
|
||||
static RelocModel arch_os_reloc_default(ArchType arch, OsType os, EnvironmentType env, bool library)
|
||||
{
|
||||
if (library)
|
||||
{
|
||||
switch (os)
|
||||
{
|
||||
case OS_UNSUPPORTED:
|
||||
UNREACHABLE
|
||||
case OS_TYPE_OPENBSD:
|
||||
case OS_DARWIN_TYPES:
|
||||
return RELOC_SMALL_PIC;
|
||||
case OS_TYPE_WIN32:
|
||||
return ARCH_TYPE_X86_64 == arch ? RELOC_SMALL_PIC : RELOC_NONE;
|
||||
case OS_TYPE_WASI:
|
||||
return RELOC_NONE;
|
||||
case OS_TYPE_UNKNOWN:
|
||||
case OS_TYPE_NONE:
|
||||
case OS_TYPE_FREE_BSD:
|
||||
case OS_TYPE_LINUX:
|
||||
case OS_TYPE_NETBSD:
|
||||
switch (arch)
|
||||
{
|
||||
case ARCH_TYPE_MIPS64:
|
||||
case ARCH_TYPE_MIPS64EL:
|
||||
return RELOC_SMALL_PIC;
|
||||
default:
|
||||
return RELOC_NONE;
|
||||
}
|
||||
}
|
||||
UNREACHABLE
|
||||
}
|
||||
switch (os)
|
||||
{
|
||||
case OS_UNSUPPORTED:
|
||||
UNREACHABLE
|
||||
case OS_TYPE_OPENBSD:
|
||||
case OS_DARWIN_TYPES:
|
||||
return PIC_SMALL;
|
||||
case OS_TYPE_WIN32:
|
||||
return ARCH_TYPE_X86_64 == arch;
|
||||
case OS_TYPE_WASI:
|
||||
return PIC_NONE;
|
||||
case OS_TYPE_UNKNOWN:
|
||||
case OS_TYPE_NONE:
|
||||
return RELOC_NONE;
|
||||
case OS_TYPE_OPENBSD:
|
||||
case OS_TYPE_WIN32:
|
||||
case OS_DARWIN_TYPES:
|
||||
case OS_TYPE_WASI:
|
||||
case OS_TYPE_FREE_BSD:
|
||||
case OS_TYPE_LINUX:
|
||||
case OS_TYPE_NETBSD:
|
||||
switch (arch)
|
||||
return RELOC_SMALL_PIE;
|
||||
case OS_TYPE_LINUX:
|
||||
if (env == ENV_TYPE_MUSLEABI || env == ENV_TYPE_MUSLEABIHF || env == ENV_TYPE_ANDROID)
|
||||
{
|
||||
case ARCH_TYPE_MIPS64:
|
||||
case ARCH_TYPE_MIPS64EL:
|
||||
return PIC_SMALL;
|
||||
default:
|
||||
return PIC_NONE;
|
||||
return RELOC_SMALL_PIE;
|
||||
}
|
||||
return RELOC_NONE;
|
||||
case OS_UNSUPPORTED:
|
||||
UNREACHABLE
|
||||
}
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
static bool arch_os_pic_default_forced(ArchType arch, OsType os)
|
||||
{
|
||||
switch (os)
|
||||
@@ -1078,28 +1111,6 @@ static bool arch_os_pic_default_forced(ArchType arch, OsType os)
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
static PieGeneration arch_os_pie_default(ArchType arch, OsType os, EnvironmentType env)
|
||||
{
|
||||
switch (os)
|
||||
{
|
||||
case OS_TYPE_UNKNOWN:
|
||||
case OS_TYPE_NONE:
|
||||
return PIE_NONE;
|
||||
case OS_TYPE_OPENBSD:
|
||||
return PIE_SMALL;
|
||||
case OS_TYPE_WIN32:
|
||||
case OS_DARWIN_TYPES:
|
||||
case OS_TYPE_WASI:
|
||||
case OS_TYPE_FREE_BSD:
|
||||
case OS_TYPE_NETBSD:
|
||||
return PIE_SMALL;
|
||||
case OS_TYPE_LINUX:
|
||||
return env == ENV_TYPE_MUSLEABI || env == ENV_TYPE_MUSLEABIHF || env == ENV_TYPE_ANDROID ? PIE_SMALL : PIE_NONE;
|
||||
case OS_UNSUPPORTED:
|
||||
UNREACHABLE
|
||||
}
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
static AlignSize os_target_pref_alignment_of_float(OsType os, ArchType arch, uint32_t bits)
|
||||
{
|
||||
@@ -1144,23 +1155,42 @@ void *llvm_target_machine_create(void)
|
||||
}
|
||||
LLVMRelocMode reloc_mode;
|
||||
|
||||
if (platform_target.pic != PIC_NONE)
|
||||
switch (platform_target.reloc_model)
|
||||
{
|
||||
reloc_mode = LLVMRelocPIC;
|
||||
case RELOC_SMALL_PIC:
|
||||
case RELOC_BIG_PIC:
|
||||
case RELOC_SMALL_PIE:
|
||||
case RELOC_BIG_PIE:
|
||||
reloc_mode = LLVMRelocPIC;
|
||||
break;
|
||||
case RELOC_NONE:
|
||||
reloc_mode = LLVMRelocDynamicNoPic;
|
||||
break;
|
||||
case RELOC_DEFAULT:
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(platform_target.pic == PIC_NONE);
|
||||
reloc_mode = LLVMRelocDynamicNoPic;
|
||||
}
|
||||
|
||||
scratch_buffer_clear();
|
||||
if (platform_target.arch == ARCH_TYPE_X86_64)
|
||||
{
|
||||
if (platform_target.x64.avx_level == AVX_NONE) scratch_buffer_append("-avx,");
|
||||
if (platform_target.x64.no_sse) scratch_buffer_append("-sse,");
|
||||
switch (platform_target.x64.x86_vector_capability)
|
||||
{
|
||||
case X86VECTOR_DEFAULT:
|
||||
UNREACHABLE
|
||||
case X86VECTOR_NONE:
|
||||
scratch_buffer_append("-sse,-avx,-mmx,");
|
||||
break;
|
||||
case X86VECTOR_MMX:
|
||||
scratch_buffer_append("-sse,-avx,");
|
||||
break;
|
||||
case X86VECTOR_SSE:
|
||||
scratch_buffer_append("-avx,");
|
||||
break;
|
||||
case X86VECTOR_AVX:
|
||||
case X86VECTOR_AVX512:
|
||||
break;
|
||||
}
|
||||
if (platform_target.x64.soft_float) scratch_buffer_append("+soft-float,");
|
||||
if (platform_target.x64.no_mmx) scratch_buffer_append("-mmx,");
|
||||
}
|
||||
char *features = scratch_buffer_to_string();
|
||||
size_t len = strlen(features);
|
||||
@@ -1354,38 +1384,20 @@ void target_setup(BuildTarget *target)
|
||||
platform_target.align_max_tls = os_arch_max_alignment_of_tls(platform_target.os,
|
||||
platform_target.arch,
|
||||
platform_target.environment_type);
|
||||
platform_target.pic = arch_os_pic_default(platform_target.arch, platform_target.os);
|
||||
platform_target.pie = arch_os_pie_default(platform_target.arch, platform_target.os, platform_target.environment_type);
|
||||
platform_target.reloc_model = arch_os_reloc_default(platform_target.arch,
|
||||
platform_target.os,
|
||||
platform_target.environment_type,
|
||||
active_target.type != TARGET_TYPE_EXECUTABLE);
|
||||
platform_target.pic_required = arch_os_pic_default_forced(platform_target.arch, platform_target.os);
|
||||
|
||||
// Override PIE if needed.
|
||||
if (target->pie != PIE_DEFAULT) platform_target.pie = target->pie;
|
||||
// Override PIC, but only if the platform does not require PIC
|
||||
if (target->pic != PIC_DEFAULT && (target->pic != PIC_NONE || !platform_target.pic_required))
|
||||
if (target->reloc_model != RELOC_DEFAULT
|
||||
&& (target->reloc_model != RELOC_NONE || !platform_target.pic_required))
|
||||
{
|
||||
platform_target.pic = target->pic;
|
||||
platform_target.reloc_model = target->reloc_model;
|
||||
}
|
||||
|
||||
assert(platform_target.pic != PIC_DEFAULT && platform_target.pie != PIE_DEFAULT && "PIC and PIE must have been set.");
|
||||
|
||||
if (active_target.type == TARGET_TYPE_EXECUTABLE)
|
||||
{
|
||||
platform_target.pic = (PicGeneration)platform_target.pie;
|
||||
}
|
||||
switch (platform_target.pic)
|
||||
{
|
||||
case PIC_DEFAULT:
|
||||
UNREACHABLE;
|
||||
case PIC_NONE:
|
||||
DEBUG_LOG("Using no-PIC");
|
||||
break;
|
||||
case PIC_SMALL:
|
||||
DEBUG_LOG("Using pic");
|
||||
break;
|
||||
case PIC_BIG:
|
||||
DEBUG_LOG("Using PIC");
|
||||
break;
|
||||
}
|
||||
assert(platform_target.reloc_model != RELOC_DEFAULT);
|
||||
|
||||
|
||||
// TODO remove
|
||||
|
||||
@@ -211,12 +211,6 @@ typedef enum
|
||||
FLOAT_ABI_HARD,
|
||||
} FloatABI;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
AVX_NONE,
|
||||
AVX,
|
||||
AVX_512,
|
||||
} AVXLevel;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
@@ -267,8 +261,7 @@ typedef struct
|
||||
ABI abi;
|
||||
AlignData integers[BITSIZES_LEN];
|
||||
AlignData floats[BITSIZES_LEN];
|
||||
PicGeneration pic : 3;
|
||||
PieGeneration pie : 3;
|
||||
RelocModel reloc_model;
|
||||
bool pic_required : 1;
|
||||
bool signed_c_char : 1;
|
||||
FloatABI float_abi : 3;
|
||||
@@ -287,13 +280,12 @@ typedef struct
|
||||
struct
|
||||
{
|
||||
unsigned align_simd_default : 16;
|
||||
AVXLevel avx_level : 3;
|
||||
bool no_mmx : 1;
|
||||
bool no_sse : 1;
|
||||
X86VectorCapability x86_vector_capability : 4;
|
||||
bool soft_float : 1;
|
||||
bool is_win64 : 1;
|
||||
bool is_mingw64 : 1;
|
||||
bool pass_int128_vector_in_mem : 1;
|
||||
int native_vector_size_avx;
|
||||
} x64;
|
||||
struct
|
||||
{
|
||||
@@ -367,5 +359,20 @@ typedef struct
|
||||
|
||||
} PlatformTarget;
|
||||
|
||||
static inline bool is_pie_pic(RelocModel reloc)
|
||||
{
|
||||
switch (reloc)
|
||||
{
|
||||
case RELOC_DEFAULT:
|
||||
case RELOC_NONE:
|
||||
return false;
|
||||
case RELOC_SMALL_PIC:
|
||||
case RELOC_BIG_PIC:
|
||||
case RELOC_SMALL_PIE:
|
||||
case RELOC_BIG_PIE:
|
||||
return true;
|
||||
}
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
extern PlatformTarget platform_target;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include <stdio.h>
|
||||
#include "compiler/compiler_internal.h"
|
||||
#include "benchmark.h"
|
||||
|
||||
#include "utils/json.h"
|
||||
|
||||
void test_file(void)
|
||||
{
|
||||
@@ -162,6 +162,30 @@ void test128()
|
||||
|
||||
|
||||
}
|
||||
|
||||
static void test_json(void)
|
||||
{
|
||||
printf("Begin json testing.\n");
|
||||
JsonParser parser;
|
||||
json_init_string(&parser, "123", &malloc);
|
||||
JSONObject *obj = json_parse(&parser);
|
||||
TEST_ASSERT(obj->type == J_NUMBER, "Expected number");
|
||||
TEST_ASSERT(obj->f == 123.0, "Expected number match");
|
||||
json_init_string(&parser, "[123, 23.123]", &malloc);
|
||||
JSONObject *array = json_parse(&parser);
|
||||
TEST_ASSERT(array->type == J_ARRAY, "Expected array");
|
||||
TEST_ASSERT(array->array_len == 2, "Expected 2 elements");
|
||||
TEST_ASSERT(array->elements[0]->f == 123.0, "Matching element 1");
|
||||
TEST_ASSERT(array->elements[1]->f == 23.123, "Matching element 1");
|
||||
json_init_string(&parser, "[\"hello\\nworld\\t.\", 123]", &malloc);
|
||||
array = json_parse(&parser);
|
||||
TEST_ASSERT(array->type == J_ARRAY, "Expected array");
|
||||
TEST_ASSERT(array->array_len == 2, "Expected 2 elements");
|
||||
TEST_ASSERT(array->elements[1]->f == 123.0, "Matching element 1");
|
||||
TEST_ASSERT(array->elements[0]->type == J_STRING, "Matching element 0");
|
||||
TEST_ASSERT(strcmp(array->elements[0]->str, "hello\nworld\t.") == 0, "Mismatching string");
|
||||
}
|
||||
|
||||
void compiler_tests(void)
|
||||
{
|
||||
symtab_init(0x100000);
|
||||
@@ -170,5 +194,6 @@ void compiler_tests(void)
|
||||
test128();
|
||||
run_arena_allocator_tests();
|
||||
|
||||
test_json();
|
||||
exit_compiler(COMPILER_SUCCESS_EXIT);
|
||||
}
|
||||
@@ -18,7 +18,7 @@
|
||||
#define MAX_VECTOR_WIDTH 65536
|
||||
#define MAX_ARRAY_SIZE INT64_MAX
|
||||
#define MAX_IDENTIFIER_LENGTH 31
|
||||
#define PROJECT_TOML "project.toml"
|
||||
#define PROJECT_JSON "project.c3p"
|
||||
#ifndef __unused
|
||||
#define __unused
|
||||
#endif
|
||||
|
||||
@@ -247,12 +247,12 @@ void file_find_top_dir()
|
||||
while (1)
|
||||
{
|
||||
struct stat info;
|
||||
int err = stat(PROJECT_TOML, &info);
|
||||
int err = stat(PROJECT_JSON, &info);
|
||||
|
||||
// Error and the it's not a "missing file"?
|
||||
if (err && errno != ENOENT)
|
||||
{
|
||||
error_exit("Can't open %s: %s.", PROJECT_TOML, strerror(errno));
|
||||
error_exit("Can't open %s: %s.", PROJECT_JSON, strerror(errno));
|
||||
}
|
||||
|
||||
// Everything worked and it's a regular file? We're done!
|
||||
@@ -264,13 +264,13 @@ void file_find_top_dir()
|
||||
getcwd(start_path, PATH_MAX);
|
||||
if (chdir(".."))
|
||||
{
|
||||
error_exit("Can't change directory to search for %s: %s.", PROJECT_TOML, strerror(errno));
|
||||
error_exit("Can't change directory to search for %s: %s.", PROJECT_JSON, strerror(errno));
|
||||
}
|
||||
char new_path[PATH_MAX + 1];
|
||||
getcwd(new_path, PATH_MAX);
|
||||
if (strcmp(new_path, start_path) != 0) continue;
|
||||
error_exit("The root build directory containing %s could not be found. Did you use the correct directory?",
|
||||
PROJECT_TOML);
|
||||
PROJECT_JSON);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
426
src/utils/json.c
Normal file
426
src/utils/json.c
Normal file
@@ -0,0 +1,426 @@
|
||||
#include "lib.h"
|
||||
#include "json.h"
|
||||
|
||||
|
||||
JSONObject error = { .type = J_ERROR };
|
||||
JSONObject true_val = { .type = J_BOOL, .b = true };
|
||||
JSONObject false_val = { .type = J_BOOL, .b = false };
|
||||
JSONObject zero_val = { .type = J_NUMBER, .f = 0.0 };
|
||||
JSONObject empty_array_val = { .type = J_ARRAY, .array_len = 0 };
|
||||
JSONObject empty_obj_val = { .type = J_OBJECT, .member_len = 0 };
|
||||
|
||||
#define CONSUME(token_) do { if (!consume(parser, token_)) { json_error(parser, "Unexpected character encountered."); return &error; } } while(0)
|
||||
|
||||
static inline void json_skip_whitespace(JsonParser *parser)
|
||||
{
|
||||
char c;
|
||||
while (1)
|
||||
{
|
||||
RETRY:
|
||||
switch (parser->current[0])
|
||||
{
|
||||
case '/':
|
||||
c = parser->current[1];
|
||||
if (c == '/')
|
||||
{
|
||||
parser->current++;
|
||||
while ((c = (++parser->current)[0]) && c != '\n') {}
|
||||
goto RETRY;
|
||||
}
|
||||
if (c == '*')
|
||||
{
|
||||
parser->current++;
|
||||
while ((c = (++parser->current)[0]))
|
||||
{
|
||||
if (c == '*' && parser->current[1] == '/')
|
||||
{
|
||||
parser->current += 2;
|
||||
goto RETRY;
|
||||
}
|
||||
}
|
||||
goto RETRY;
|
||||
}
|
||||
return;
|
||||
case '\n':
|
||||
parser->line++;
|
||||
case '\r':
|
||||
case ' ':
|
||||
case '\v':
|
||||
case '\t':
|
||||
parser->current++;
|
||||
continue;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool json_match(JsonParser *parser, const char *str)
|
||||
{
|
||||
const char *curr = parser->current;
|
||||
while (str[0] != '\0')
|
||||
{
|
||||
if (str++[0] != curr++[0]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline JSONObject *json_new_object(JsonParser *parser, JSONType type)
|
||||
{
|
||||
JSONObject *obj = parser->allocator(sizeof(JSONObject));
|
||||
obj->type = type;
|
||||
return obj;
|
||||
}
|
||||
|
||||
void json_error(JsonParser *parser, const char *error_message)
|
||||
{
|
||||
if (!parser->error_message) parser->error_message = error_message;
|
||||
parser->current_token_type = T_ERROR;
|
||||
}
|
||||
|
||||
static void json_parse_number(JsonParser *parser)
|
||||
{
|
||||
char c = parser->current[0];
|
||||
bool negate = c == '-';
|
||||
if (negate) c = (++parser->current)[0];
|
||||
double value = 0;
|
||||
while (c >= '0' && c <= '9')
|
||||
{
|
||||
value = value * 10.0 + (c - '0');
|
||||
c = (++parser->current)[0];
|
||||
}
|
||||
double decimals = 0;
|
||||
double divide = 10.0;
|
||||
if (c == '.')
|
||||
{
|
||||
c = (++parser->current)[0];
|
||||
while (c >= '0' && c <= '9')
|
||||
{
|
||||
decimals = decimals + (c - '0') / divide;
|
||||
divide *= 10.0;
|
||||
c = (++parser->current)[0];
|
||||
}
|
||||
}
|
||||
value += decimals;
|
||||
parser->current_token_type = T_NUMBER;
|
||||
parser->last_number = value;
|
||||
}
|
||||
|
||||
static void json_parse_string(JsonParser *parser)
|
||||
{
|
||||
parser->current_token_type = T_STRING;
|
||||
const char *current = ++parser->current;
|
||||
char c;
|
||||
while (c = current++[0], c != '\0' && c != '"')
|
||||
{
|
||||
if (c == '\\' && current[0] != '\0') current++;
|
||||
}
|
||||
size_t max_size = current - parser->current;
|
||||
char *str = parser->allocator(max_size + 1);
|
||||
char *str_current = str;
|
||||
while (1)
|
||||
{
|
||||
c = parser->current++[0];
|
||||
if (c == '\0')
|
||||
{
|
||||
json_error(parser, "Unterminated string.");
|
||||
return;
|
||||
}
|
||||
if (c == '"')
|
||||
{
|
||||
parser->last_string = str;
|
||||
str_current[0] = '\0';
|
||||
return;
|
||||
}
|
||||
if (c != '\\')
|
||||
{
|
||||
str_current++[0] = c;
|
||||
continue;
|
||||
}
|
||||
c = parser->current++[0];
|
||||
switch (c)
|
||||
{
|
||||
case '\\':
|
||||
case '"':
|
||||
case '/':
|
||||
break;
|
||||
case 'b':
|
||||
c = '\b';
|
||||
break;
|
||||
case 'n':
|
||||
c = '\n';
|
||||
break;
|
||||
case 'f':
|
||||
c = '\f';
|
||||
break;
|
||||
case 'r':
|
||||
c = '\r';
|
||||
break;
|
||||
case 't':
|
||||
c = '\t';
|
||||
break;
|
||||
case 'u':
|
||||
{
|
||||
char u1 = parser->current++[0];
|
||||
char u2 = parser->current++[0];
|
||||
char u3 = parser->current++[0];
|
||||
char u4 = parser->current++[0];
|
||||
if (!is_hex(u1) || !is_hex(u2) || !is_hex(u3) || !is_hex(u4))
|
||||
{
|
||||
json_error(parser, "Invalid hex in \\u escape sequence.");
|
||||
return;
|
||||
}
|
||||
c = (hex_nibble(u1) << 12) + (hex_nibble(u2) << 8) + (hex_nibble(u3) << 4) + hex_nibble(u4);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
json_error(parser, "Invalid escape sequence.");
|
||||
return;
|
||||
}
|
||||
str_current++[0] = c;
|
||||
}
|
||||
|
||||
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
static inline void json_lexer_advance(JsonParser *parser)
|
||||
{
|
||||
json_skip_whitespace(parser);
|
||||
switch (parser->current[0])
|
||||
{
|
||||
case '\0':
|
||||
parser->current_token_type = T_EOF;
|
||||
return;
|
||||
case '{':
|
||||
parser->current_token_type = T_LBRACE;
|
||||
parser->current++;
|
||||
return;
|
||||
case '}':
|
||||
parser->current_token_type = T_RBRACE;
|
||||
parser->current++;
|
||||
return;
|
||||
case '[':
|
||||
parser->current_token_type = T_LBRACKET;
|
||||
parser->current++;
|
||||
return;
|
||||
case ']':
|
||||
parser->current_token_type = T_RBRACKET;
|
||||
parser->current++;
|
||||
return;
|
||||
case ':':
|
||||
parser->current_token_type = T_COLON;
|
||||
parser->current++;
|
||||
return;
|
||||
case ',':
|
||||
parser->current_token_type = T_COMMA;
|
||||
parser->current++;
|
||||
return;
|
||||
case '"':
|
||||
json_parse_string(parser);
|
||||
return;
|
||||
case '-':
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
json_parse_number(parser);
|
||||
return;
|
||||
case 't':
|
||||
if (!json_match(parser, "true"))
|
||||
{
|
||||
json_error(parser, "Unexpected symbol, I expected maybe 'true' here.");
|
||||
return;
|
||||
}
|
||||
parser->current += 4;
|
||||
parser->current_token_type = T_TRUE;
|
||||
return;
|
||||
case 'f':
|
||||
if (!json_match(parser, "false"))
|
||||
{
|
||||
json_error(parser, "Unexpected symbol, I expected maybe 'false' here.");
|
||||
return;
|
||||
}
|
||||
parser->current += 4;
|
||||
parser->current_token_type = T_FALSE;
|
||||
return;
|
||||
case 'n':
|
||||
if (!json_match(parser, "null"))
|
||||
{
|
||||
json_error(parser, "Unexpected symbol, I expected maybe 'null' here.");
|
||||
return;
|
||||
}
|
||||
parser->current += 4;
|
||||
parser->current_token_type = T_NULL;
|
||||
return;
|
||||
default:
|
||||
json_error(parser, "Unexpected symbol found.");
|
||||
return;
|
||||
}
|
||||
UNREACHABLE
|
||||
}
|
||||
static inline bool consume(JsonParser *parser, JSONTokenType token)
|
||||
{
|
||||
if (parser->current_token_type == token)
|
||||
{
|
||||
json_lexer_advance(parser);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
JSONObject *json_parse_array(JsonParser *parser)
|
||||
{
|
||||
CONSUME(T_LBRACKET);
|
||||
if (consume(parser, T_RBRACKET))
|
||||
{
|
||||
return &empty_array_val;
|
||||
}
|
||||
size_t capacity = 16;
|
||||
JSONObject *array = json_new_object(parser, J_ARRAY);
|
||||
JSONObject** elements = parser->allocator(sizeof(JSONObject*) * capacity);
|
||||
size_t index = 0;
|
||||
while (1)
|
||||
{
|
||||
JSONObject *parsed = json_parse(parser);
|
||||
if (parser->error_message) return &error;
|
||||
if (index >= capacity)
|
||||
{
|
||||
JSONObject **elements_old = elements;
|
||||
size_t copy_size = capacity * sizeof(JSONObject*);
|
||||
capacity *= 2;
|
||||
elements = parser->allocator(sizeof(JSONObject*) * capacity);
|
||||
memcpy(elements, elements_old, copy_size);
|
||||
}
|
||||
elements[index++] = parsed;
|
||||
if (consume(parser, T_RBRACKET)) break;
|
||||
CONSUME(T_COMMA);
|
||||
// Allow trailing comma
|
||||
if (consume(parser, T_RBRACKET)) break;
|
||||
}
|
||||
array->elements = elements;
|
||||
array->array_len = index;
|
||||
return array;
|
||||
}
|
||||
|
||||
JSONObject *json_parse_object(JsonParser *parser)
|
||||
{
|
||||
CONSUME(T_LBRACE);
|
||||
if (consume(parser, T_RBRACE))
|
||||
{
|
||||
return &empty_obj_val;
|
||||
}
|
||||
size_t capacity = 16;
|
||||
JSONObject *obj = json_new_object(parser, J_OBJECT);
|
||||
JSONObject** elements = parser->allocator(sizeof(JSONObject*) * capacity);
|
||||
const char** keys = parser->allocator(sizeof(JSONObject*) * capacity);
|
||||
size_t index = 0;
|
||||
while (1)
|
||||
{
|
||||
const char *key = parser->last_string;
|
||||
CONSUME(T_STRING);
|
||||
CONSUME(T_COLON);
|
||||
JSONObject *value = json_parse(parser);
|
||||
if (parser->error_message) return NULL;
|
||||
if (index >= capacity)
|
||||
{
|
||||
JSONObject **elements_old = elements;
|
||||
const char **keys_old = keys;
|
||||
size_t copy_size = capacity * sizeof(void*);
|
||||
capacity *= 2;
|
||||
elements = parser->allocator(sizeof(JSONObject*) * capacity);
|
||||
keys = parser->allocator(sizeof(JSONObject*) * capacity);
|
||||
memcpy(elements, elements_old, copy_size);
|
||||
memcpy(keys, keys_old, copy_size);
|
||||
}
|
||||
keys[index] = key;
|
||||
elements[index++] = value;
|
||||
if (consume(parser, T_RBRACE)) break;
|
||||
if (!consume(parser, T_COMMA))
|
||||
{
|
||||
json_error(parser, "Expected a comma.");
|
||||
return NULL;
|
||||
}
|
||||
// Allow trailing comma
|
||||
if (consume(parser, T_RBRACE)) break;
|
||||
}
|
||||
obj->members = elements;
|
||||
obj->keys = keys;
|
||||
obj->member_len = index;
|
||||
return obj;
|
||||
|
||||
}
|
||||
|
||||
JSONObject *json_obj_get(JSONObject *obj, const char *key)
|
||||
{
|
||||
assert(obj->type == J_OBJECT);
|
||||
for (unsigned i = 0; i < obj->member_len; i++)
|
||||
{
|
||||
if (strcmp(obj->keys[i], key) == 0) return obj->elements[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
JSONObject *json_parse(JsonParser *parser)
|
||||
{
|
||||
if (parser->error_message) return &error;
|
||||
switch (parser->current_token_type)
|
||||
{
|
||||
case T_EOF:
|
||||
return NULL;
|
||||
case T_ERROR:
|
||||
UNREACHABLE
|
||||
case T_LBRACE:
|
||||
return json_parse_object(parser);
|
||||
case T_LBRACKET:
|
||||
return json_parse_array(parser);
|
||||
case T_COMMA:
|
||||
case T_RBRACE:
|
||||
case T_RBRACKET:
|
||||
case T_COLON:
|
||||
json_error(parser, "Unexpected character.");
|
||||
return NULL;
|
||||
case T_STRING:
|
||||
{
|
||||
JSONObject *obj = json_new_object(parser, J_STRING);
|
||||
obj->type = J_STRING;
|
||||
obj->str = parser->last_string;
|
||||
json_lexer_advance(parser);
|
||||
return obj;
|
||||
}
|
||||
case T_NUMBER:
|
||||
{
|
||||
if (parser->last_number == 0) return &zero_val;
|
||||
JSONObject *obj = json_new_object(parser, J_NUMBER);
|
||||
obj->type = J_NUMBER;
|
||||
obj->f = parser->last_number;
|
||||
json_lexer_advance(parser);
|
||||
return obj;
|
||||
}
|
||||
case T_TRUE:
|
||||
json_lexer_advance(parser);
|
||||
return &true_val;
|
||||
case T_FALSE:
|
||||
json_lexer_advance(parser);
|
||||
return &false_val;
|
||||
case T_NULL:
|
||||
json_lexer_advance(parser);
|
||||
return NULL;
|
||||
}
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
void json_init_string(JsonParser *parser, const char *str, JsonAllocator *allocator)
|
||||
{
|
||||
parser->current = str;
|
||||
parser->allocator = allocator;
|
||||
parser->error_message = NULL;
|
||||
parser->line = 1;
|
||||
json_lexer_advance(parser);
|
||||
}
|
||||
67
src/utils/json.h
Normal file
67
src/utils/json.h
Normal file
@@ -0,0 +1,67 @@
|
||||
#pragma once
|
||||
typedef enum
|
||||
{
|
||||
J_OBJECT,
|
||||
J_STRING,
|
||||
J_ARRAY,
|
||||
J_NUMBER,
|
||||
J_BOOL,
|
||||
J_ERROR,
|
||||
} JSONType;
|
||||
|
||||
|
||||
typedef struct JSONObject_
|
||||
{
|
||||
JSONType type;
|
||||
union
|
||||
{
|
||||
bool b;
|
||||
const char *str;
|
||||
double f;
|
||||
struct
|
||||
{
|
||||
struct JSONObject_ **elements;
|
||||
size_t array_len;
|
||||
};
|
||||
struct
|
||||
{
|
||||
struct JSONObject_ **members;
|
||||
const char **keys;
|
||||
size_t member_len;
|
||||
};
|
||||
};
|
||||
} JSONObject;
|
||||
|
||||
typedef enum JSONTokenType_
|
||||
{
|
||||
T_LBRACE,
|
||||
T_LBRACKET,
|
||||
T_COMMA,
|
||||
T_COLON,
|
||||
T_RBRACE,
|
||||
T_RBRACKET,
|
||||
T_STRING,
|
||||
T_NUMBER,
|
||||
T_ERROR,
|
||||
T_TRUE,
|
||||
T_FALSE,
|
||||
T_NULL,
|
||||
T_EOF,
|
||||
} JSONTokenType;
|
||||
|
||||
typedef void*(JsonAllocator)(size_t);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned line;
|
||||
const char *current;
|
||||
JSONTokenType current_token_type;
|
||||
const char *error_message;
|
||||
JsonAllocator *allocator;
|
||||
const char *last_string;
|
||||
double last_number;
|
||||
} JsonParser;
|
||||
|
||||
void json_init_string(JsonParser *parser, const char *str, JsonAllocator *allocator);
|
||||
JSONObject *json_parse(JsonParser *parser);
|
||||
JSONObject *json_obj_get(JSONObject *obj, const char *key);
|
||||
@@ -496,6 +496,7 @@ typedef struct StringSlice_
|
||||
} StringSlice;
|
||||
|
||||
char *strcat_arena(const char *a, const char *b);
|
||||
int str_in_list(const char *value, unsigned count, const char** elements);
|
||||
char *strformat(const char *var, ...) __printflike(1, 2);
|
||||
char *stringcopy(const char *start, size_t len);
|
||||
StringSlice strnexttok(StringSlice *slice, char separator);
|
||||
|
||||
@@ -8,6 +8,15 @@
|
||||
#include "lib.h"
|
||||
#include "stdio.h"
|
||||
|
||||
int str_in_list(const char *value, unsigned count, const char** elements)
|
||||
{
|
||||
for (unsigned i = 0; i < count; i++)
|
||||
{
|
||||
if (strcmp(value, elements[i]) == 0) return (int)i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *strformat(const char *var, ...)
|
||||
{
|
||||
va_list list;
|
||||
|
||||
2354
src/utils/toml.c
2354
src/utils/toml.c
File diff suppressed because it is too large
Load Diff
222
src/utils/toml.h
222
src/utils/toml.h
@@ -1,222 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef __TOML_H__
|
||||
#define __TOML_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define TOML_FALSE 0
|
||||
#define TOML_TRUE 1
|
||||
|
||||
#if !defined(_MSC_VER) || _MSC_VER >= 1800
|
||||
#define TOML_CONST const
|
||||
#else
|
||||
#define TOML_CONST
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
TOML_OK,
|
||||
TOML_ERR,
|
||||
TOML_ERR_IO,
|
||||
TOML_ERR_NOMEM,
|
||||
TOML_ERR_SYNTAX,
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int code;
|
||||
char *message;
|
||||
int _is_literal;
|
||||
} TomlErr;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *str;
|
||||
size_t len;
|
||||
size_t _capacity;
|
||||
} TomlString;
|
||||
|
||||
typedef struct _TomlValue TomlValue;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
TomlValue **elements;
|
||||
size_t len;
|
||||
size_t _capacity;
|
||||
} TomlArray;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
TomlString *key;
|
||||
TomlValue *value;
|
||||
} TomlKeyValue;
|
||||
|
||||
typedef struct _TomlTable TomlTable;
|
||||
typedef struct _TomlTableIter TomlTableIter;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int year;
|
||||
int month;
|
||||
int day;
|
||||
int hour;
|
||||
int minute;
|
||||
double second;
|
||||
int offset_hour;
|
||||
int offset_minute;
|
||||
} TomlDateTime;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TOML_TABLE,
|
||||
TOML_ARRAY,
|
||||
TOML_STRING,
|
||||
TOML_INTEGER,
|
||||
TOML_FLOAT,
|
||||
TOML_DATETIME,
|
||||
TOML_BOOLEAN,
|
||||
} TomlType;
|
||||
|
||||
struct _TomlValue
|
||||
{
|
||||
TomlType type;
|
||||
union
|
||||
{
|
||||
TomlTable *table;
|
||||
TomlArray *array;
|
||||
TomlString *string;
|
||||
#if defined(_MSC_VER)
|
||||
long long integer;
|
||||
#else
|
||||
long integer;
|
||||
#endif
|
||||
double float_;
|
||||
TomlDateTime *datetime;
|
||||
int boolean;
|
||||
} value;
|
||||
};
|
||||
|
||||
char *toml_strdup(TOML_CONST char *str);
|
||||
|
||||
char *toml_strndup(TOML_CONST char *str, size_t n);
|
||||
|
||||
int toml_vasprintf(char **str, TOML_CONST char *format, va_list args);
|
||||
|
||||
int toml_asprintf(char **str, TOML_CONST char *format, ...);
|
||||
|
||||
#define TOML_ERR_INIT {TOML_OK, NULL, TOML_FALSE}
|
||||
|
||||
void toml_err_init(TomlErr *err);
|
||||
|
||||
void toml_clear_err(TomlErr *err);
|
||||
|
||||
void toml_err_move(TomlErr *to, TomlErr *from);
|
||||
|
||||
void toml_set_err_v(TomlErr *err, int code, TOML_CONST char *format, va_list args);
|
||||
|
||||
void toml_set_err(TomlErr *err, int code, TOML_CONST char *format, ...);
|
||||
|
||||
void toml_set_err_literal(TomlErr *err, int code, TOML_CONST char *message);
|
||||
|
||||
TomlString *toml_string_new(TomlErr *err);
|
||||
|
||||
TomlString *toml_string_new_string(TOML_CONST char *str, TomlErr *err);
|
||||
|
||||
TomlString *toml_string_new_nstring(TOML_CONST char *str, size_t len, TomlErr *err);
|
||||
|
||||
void toml_string_append_char(TomlString *self, char ch, TomlErr *err);
|
||||
|
||||
void toml_string_append_string(TomlString *self, TOML_CONST char *str, TomlErr *err);
|
||||
|
||||
void toml_string_append_nstring(TomlString *self, TOML_CONST char *str, size_t len, TomlErr *err);
|
||||
|
||||
TomlString *toml_string_copy(TOML_CONST TomlString *self, TomlErr *err);
|
||||
|
||||
void toml_string_free(TomlString *self);
|
||||
|
||||
int toml_string_equals(TOML_CONST TomlString *self, TOML_CONST TomlString *other);
|
||||
|
||||
TomlTable *toml_table_new(TomlErr *err);
|
||||
|
||||
void toml_table_free(TomlTable *self);
|
||||
|
||||
void toml_table_set_by_string(TomlTable *self, TomlString *key,
|
||||
TomlValue *value, TomlErr *err);
|
||||
|
||||
TomlValue *toml_table_get_by_string(TOML_CONST TomlTable *self, TOML_CONST TomlString *key);
|
||||
|
||||
void toml_table_set(TomlTable *self, TOML_CONST char *key, TomlValue *value, TomlErr *err);
|
||||
|
||||
void toml_table_setn(TomlTable *self, TOML_CONST char *key, size_t key_len,
|
||||
TomlValue *value, TomlErr *err);
|
||||
|
||||
TomlValue *toml_table_get(TOML_CONST TomlTable *self, TOML_CONST char *key);
|
||||
|
||||
TomlValue *toml_table_getn(TOML_CONST TomlTable *self, TOML_CONST char *key, size_t key_len);
|
||||
|
||||
TomlTableIter *toml_table_iter_new(TomlTable *table, TomlErr *err);
|
||||
|
||||
void toml_table_iter_free(TomlTableIter *self);
|
||||
|
||||
TomlKeyValue *toml_table_iter_get(TomlTableIter *self);
|
||||
|
||||
int toml_table_iter_has_next(TomlTableIter *self);
|
||||
|
||||
void toml_table_iter_next(TomlTableIter *self);
|
||||
|
||||
TomlArray *toml_array_new(TomlErr *err);
|
||||
|
||||
void toml_array_free(TomlArray *self);
|
||||
|
||||
void toml_array_append(TomlArray *self, TomlValue *value, TomlErr *err);
|
||||
|
||||
TomlValue *toml_value_new(TomlType type, TomlErr *err);
|
||||
|
||||
TomlValue *toml_value_new_string(TOML_CONST char *str, TomlErr *err);
|
||||
|
||||
TomlValue *toml_value_new_nstring(TOML_CONST char *str, size_t len, TomlErr *err);
|
||||
|
||||
TomlValue *toml_value_new_table(TomlErr *err);
|
||||
|
||||
TomlValue *toml_value_new_array(TomlErr *err);
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
TomlValue *toml_value_new_integer(long long integer, TomlErr *err);
|
||||
#else
|
||||
|
||||
TomlValue *toml_value_new_integer(long integer, TomlErr *err);
|
||||
|
||||
#endif
|
||||
|
||||
TomlValue *toml_value_new_float(double flt, TomlErr *err);
|
||||
|
||||
TomlValue *toml_value_new_datetime(TomlErr *err);
|
||||
|
||||
TomlValue *toml_value_new_boolean(int boolean, TomlErr *err);
|
||||
|
||||
void toml_value_free(TomlValue *self);
|
||||
|
||||
TomlTable *toml_load_string(TOML_CONST char *str, TomlErr *err);
|
||||
|
||||
TomlTable *toml_load_nstring(TOML_CONST char *str, size_t len, TomlErr *err);
|
||||
|
||||
TomlTable *toml_load_file(FILE *file, TomlErr *err);
|
||||
|
||||
TomlTable *toml_load_filename(TOML_CONST char *filename, TomlErr *err);
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* end of include guard: __TOML_H__ */
|
||||
@@ -112,7 +112,7 @@ class Issues:
|
||||
debug = "-g "
|
||||
opts = ""
|
||||
for opt in self.opts:
|
||||
opts += ' -' + opt
|
||||
opts += ' ' + opt
|
||||
code = subprocess.run(self.conf.compiler + target + ' -O0 ' + opts + ' ' + debug + args, universal_newlines=True, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
os.chdir(self.conf.cwd)
|
||||
if code.returncode != 0 and code.returncode != 1:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// #target: x64-darwin
|
||||
// #opt: mavx
|
||||
// #opt: --x86vec=avx
|
||||
module test;
|
||||
|
||||
define Mm256 = float[<8>];
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// #target: x64-darwin
|
||||
// #opt: mavx512
|
||||
// #opt: --x86vec=avx512
|
||||
module test;
|
||||
|
||||
define Mm256 = float[<8>];
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// #target: x64-darwin
|
||||
// #opt: mno-avx
|
||||
// #opt: --x86vec=sse
|
||||
module test;
|
||||
|
||||
define Mm256 = float[<8>];
|
||||
|
||||
Reference in New Issue
Block a user