Skip to content

Commit

Permalink
New linker build option. "system-linker" deprecated and removed from …
Browse files Browse the repository at this point in the history
…project settings.
  • Loading branch information
lerno committed Mar 12, 2024
1 parent a030985 commit 95fb5f9
Show file tree
Hide file tree
Showing 10 changed files with 212 additions and 176 deletions.
2 changes: 2 additions & 0 deletions releasenotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
### Changes / improvements
- Disallow multiple `_` in a row in digits, e.g. `1__000`.
- Added `@link` attribute.
- New 'linker' build option.
- "linker" project setting updated, "system-linker" removed.

### Fixes
- Struct/union members now correctly rejects members without storage size #1147.
Expand Down
18 changes: 13 additions & 5 deletions src/build/build.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,14 @@ typedef enum
SAFETY_ON = 1,
} SafetyLevel;

typedef enum
{
LINKER_TYPE_NOT_SET = -1,
LINKER_TYPE_BUILTIN = 0,
LINKER_TYPE_CC = 1,
LINKER_TYPE_CUSTOM = 2,
} LinkerType;

typedef enum
{
TRUST_NONE,
Expand Down Expand Up @@ -330,7 +338,8 @@ typedef struct BuildOptions_
const char *target_select;
const char *path;
const char *template;
const char *linker;
LinkerType linker_type;
const char *custom_linker_path;
uint32_t symtab_size;
unsigned version;
CompilerBackend backend;
Expand Down Expand Up @@ -367,7 +376,6 @@ typedef struct BuildOptions_
EmitStdlib emit_stdlib;
UseStdlib use_stdlib;
LinkLibc link_libc;
SystemLinker system_linker;
StripUnused strip_unused;
OptimizationLevel optlevel;
SizeOptimizationLevel optsize;
Expand Down Expand Up @@ -471,7 +479,7 @@ typedef struct
RelocModel reloc_model;
ArchOsTarget arch_os_target;
CompilerBackend backend;
SystemLinker system_linker;
LinkerType linker_type;
uint32_t symtab_size;
uint32_t switchrange_max_size;
const char *panicfn;
Expand All @@ -483,7 +491,7 @@ typedef struct
const char **csource_dirs;
const char **csources;
const char **feature_list;
const char *linker;
const char *custom_linker_path;
struct
{
SoftFloat soft_float : 3;
Expand Down Expand Up @@ -537,7 +545,7 @@ static BuildTarget default_build_target = {
.use_stdlib = USE_STDLIB_NOT_SET,
.link_libc = LINK_LIBC_NOT_SET,
.emit_stdlib = EMIT_STDLIB_NOT_SET,
.system_linker = SYSTEM_LINKER_NOT_SET,
.linker_type = LINKER_TYPE_NOT_SET,
.single_module = SINGLE_MODULE_NOT_SET,
.strip_unused = STRIP_UNUSED_NOT_SET,
.symtab_size = DEFAULT_SYMTAB_SIZE,
Expand Down
11 changes: 5 additions & 6 deletions src/build/build_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,17 @@ static const char *wincrt_linking[3] = {
[WIN_CRT_STATIC] = "static",
};

static const char *trust_level[3] = {
[TRUST_NONE] = "none",
[TRUST_INCLUDE] = "include",
[TRUST_FULL] = "full",
};

static const char *optsizes[3] = {
[SIZE_OPTIMIZATION_NONE] = "none",
[SIZE_OPTIMIZATION_SMALL] = "small",
[SIZE_OPTIMIZATION_TINY] = "tiny",
};

static const char *linker[3] = {
[LINKER_TYPE_BUILTIN] = "builtin",
[LINKER_TYPE_CC] = "cc",
[LINKER_TYPE_CUSTOM] = "custom"
};
static const char *on_off[2] = {
[SAFETY_OFF] = "no",
[SAFETY_ON] = "yes",
Expand Down
208 changes: 119 additions & 89 deletions src/build/build_options.c

Large diffs are not rendered by default.

11 changes: 3 additions & 8 deletions src/build/builder.c
Original file line number Diff line number Diff line change
Expand Up @@ -277,15 +277,10 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions *
if (options->win.def) target->win.def = options->win.def;
if (options->use_stdlib != USE_STDLIB_NOT_SET) target->use_stdlib = options->use_stdlib;
if (options->link_libc != LINK_LIBC_NOT_SET) target->link_libc = options->link_libc;
if (options->system_linker != SYSTEM_LINKER_NOT_SET)
if (options->linker_type != LINKER_TYPE_NOT_SET)
{
target->system_linker = options->system_linker;
target->linker = NULL;
}
if (options->linker)
{
target->linker = options->linker;
target->system_linker = SYSTEM_LINKER_NOT_SET;
target->custom_linker_path = options->custom_linker_path;
target->linker_type = options->linker_type;
}
if (options->emit_stdlib != EMIT_STDLIB_NOT_SET) target->emit_stdlib = options->emit_stdlib;
if (options->no_entry) target->no_entry = true;
Expand Down
29 changes: 20 additions & 9 deletions src/build/project.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const char *project_default_keys[][2] = {
{"fp-math", "Set math behaviour: `strict`, `relaxed` or `fast`."},
{"langrev", "Version of the C3 language used."},
{"linked-libraries", "Libraries linked by the linker for all targets."},
{"linker", "'builtin' for the builtin linker, 'cc' for the system linker or <path> to a custom compiler."},
{"linker-search-paths", "Linker search paths."},
{"link-args", "Linker arguments for all targets."},
{"link-libc", "Link libc (default: true)."},
Expand All @@ -40,7 +41,6 @@ const char *project_default_keys[][2] = {
{"sources", "Paths to project sources for all targets."},
{"strip-unused", "Strip unused code and globals from the output. (default: true)"},
{"symtab", "Sets the preferred symtab size."},
{"system-linker", "Use the system linker (default: no for cross compilation, yes otherwise)."},
{"target", "Compile for a particular architecture + OS target."},
{"targets", "Set of targets for the project."},
{"testfn", "Override the test function."},
Expand Down Expand Up @@ -78,6 +78,7 @@ const char* project_target_keys[][2] = {
{"langrev", "Version of the C3 language used."},
{"linked-libraries-add", "Additional libraries linked by the linker for the target."},
{"linked-libraries-override", "Libraries linked by the linker for this target, overriding global settings."},
{"linker", "'builtin' for the builtin linker, 'cc' for the system linker or <path> to a custom compiler."},
{"linker-search-paths-add", "Additional linker search paths for the target."},
{"linker-search-paths-override", "Linker search paths for this target, overriding global settings."},
{"link-args-add", "Additional linker arguments for the target."},
Expand All @@ -100,7 +101,6 @@ const char* project_target_keys[][2] = {
{"sources-override", "Paths to project sources for this target, overriding global settings."},
{"strip-unused", "Strip unused code and globals from the output. (default: true)"},
{"symtab", "Sets the preferred symtab size."},
{"system-linker", "Use the system linker (default: no for cross compilation, yes otherwise)."},
{"target", "Compile for a particular architecture + OS target."},
{"testfn", "Override the test function."},
{"trap-on-wrap", "Make signed and unsigned integer overflow generate a panic rather than wrapping."},
Expand Down Expand Up @@ -488,16 +488,27 @@ static void load_into_build_target(JSONObject *json, const char *type, BuildTarg
// strip-unused
target->strip_unused = (StripUnused)get_valid_bool(json, "strip-unused", type, target->strip_unused);

// system-linker
target->system_linker = (SystemLinker)get_valid_bool(json, "system-linker", type, target->system_linker);

// linker
target->linker = get_string(json, "linker", type, target->linker);

if (target->system_linker != SYSTEM_LINKER_NOT_SET && target->linker)
const char *linker_selection = get_string(json, "linker", type, NULL);
if (linker_selection)
{
error_exit("%s has both 'linker' and 'system-linker' set. They cannot be combined, so please remove one of them.", type);
if (str_eq("cc", linker_selection))
{
target->linker_type = LINKER_TYPE_CC;
target->custom_linker_path = NULL;
}
else if (str_eq("builtin", linker_selection))
{
target->linker_type = LINKER_TYPE_BUILTIN;
target->custom_linker_path = NULL;
}
else
{
target->linker_type = LINKER_TYPE_CUSTOM;
target->custom_linker_path = linker_selection;
}
}

// no-entry
target->no_entry = get_valid_bool(json, "no-entry", type, target->no_entry);

Expand Down
8 changes: 4 additions & 4 deletions src/compiler/compiler.c
Original file line number Diff line number Diff line change
Expand Up @@ -493,23 +493,23 @@ void compiler_compile(void)
}
bool system_linker_available = link_libc() && platform_target.os != OS_TYPE_WIN32;
bool use_system_linker = system_linker_available && active_target.arch_os_target == default_target;
switch (active_target.system_linker)
switch (active_target.linker_type)
{
case SYSTEM_LINKER_ON:
case LINKER_TYPE_CC:
if (!system_linker_available)
{
eprintf("System linker is not supported, defaulting to built-in linker\n");
break;
}
use_system_linker = true;
break;
case SYSTEM_LINKER_OFF:
case LINKER_TYPE_BUILTIN:
use_system_linker = false;
break;
default:
break;
}
if (use_system_linker || active_target.linker)
if (use_system_linker || active_target.linker_type == LINKER_TYPE_BUILTIN)
{
platform_linker(output_exe, obj_files, output_file_count);
compiler_link_time = bench_mark();
Expand Down
1 change: 1 addition & 0 deletions src/compiler/compiler_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ extern const char *project_default_keys[][2];
extern const int project_default_keys_count;
extern const char* project_target_keys[][2];
extern const int project_target_keys_count;
extern const char *trust_level[3];

typedef struct Ast_ Ast;
typedef struct Decl_ Decl;
Expand Down
62 changes: 26 additions & 36 deletions src/compiler/libraries.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

#define MANIFEST_FILE "manifest.json"

static inline void parse_library_target(Library *library, LibraryTarget *target, JSONObject *object);

static inline JSONObject *get_mandatory(Library *library, JSONObject *object, const char *key)
{
JSONObject *value = json_obj_get(object, key);
Expand Down Expand Up @@ -43,37 +45,6 @@ static inline const char **get_optional_string_array_as_array(Library *library,
}


static inline void parse_provides(Library *library, JSONObject *object)
{
const char *provides = get_mandatory_string(library, object, "provides");
if (!str_is_valid_lowercase_name(provides))
{
char *res = strdup(provides);
str_ellide_in_place(res, 32);
error_exit("Invalid 'provides' module name in %s, was '%s'.", library->dir, json_obj_get(object, "provides")->str);
}
library->provides = provides;
}

static inline void parse_execs(Library *library, JSONObject *object)
{
library->execs = get_optional_string_array_as_array(library, object, "execs");
}
static inline void parse_depends(Library *library, JSONObject *object)
{
library->depends = get_optional_string_array_as_array(library, object, "depends");
}

static inline void parse_library_run(Library *library, LibraryTarget *target, JSONObject *object)
{
target->execs = get_optional_string_array_as_array(library, object, "execs");
}
static inline void parse_library_target(Library *library, LibraryTarget *target, JSONObject *object)
{
target->link_flags = get_optional_string_array_as_array(library, object, "linkflags");
target->linked_libs = get_optional_string_array_as_array(library, object, "linked-libs");
target->depends = get_optional_string_array_as_array(library, object, "depends");
}
static inline void parse_library_type(Library *library, LibraryTarget ***target_group, JSONObject *object)
{
if (!object) return;
Expand All @@ -95,16 +66,35 @@ static inline void parse_library_type(Library *library, LibraryTarget ***target_
}
}

static inline void parse_library_target(Library *library, LibraryTarget *target, JSONObject *object)
{
target->link_flags = get_optional_string_array_as_array(library, object, "linkflags");
target->linked_libs = get_optional_string_array_as_array(library, object, "linked-libs");
target->depends = get_optional_string_array_as_array(library, object, "depends");
target->execs = get_optional_string_array_as_array(library, object, "execs");
}

static Library *add_library(JSONObject *object, const char *dir)
{
Library *library = CALLOCS(Library);
library->dir = dir;
parse_provides(library, object);
parse_depends(library, object);
const char *provides = get_mandatory_string(library, object, "provides");
if (!str_is_valid_lowercase_name(provides))
{
char *res = strdup(provides);
str_ellide_in_place(res, 32);
error_exit("Invalid 'provides' module name in %s, was '%s'.", library->dir,
json_obj_get(object, "provides")->str);
}
library->provides = provides;
library->execs = get_optional_string_array_as_array(library, object, "execs");
library->depends = get_optional_string_array_as_array(library, object, "depends");
parse_library_type(library, &library->targets, json_obj_get(object, "targets"));
return library;
}



static Library *find_library(Library **libs, size_t lib_count, const char *name)
{
for (size_t i = 0; i < lib_count; i++)
Expand Down Expand Up @@ -260,9 +250,9 @@ void resolve_libraries(void)
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)
{
error_exit("Could not use library '%s' as it requires the 'exec' trust level (it "
"is currently %d). Use the '-t' option to enable it.",
library->provides, active_target.trust_level + 1);
error_exit("Could not use library '%s' as it requires 'exec' trust level to execute (it "
"is currently '%s'). Use the '--trust=full' option to enable it.",
library->provides, trust_level[active_target.trust_level]);
}
FOREACH_BEGIN(const char *exec, library->execs)
printf("] Execute '%s' for library '%s':", exec, library->provides);
Expand Down
Loading

0 comments on commit 95fb5f9

Please sign in to comment.