Roughly link LLVM for self-hosted compiler
All checks were successful
CI / ci (MinSizeRel, ubuntu-latest) (push) Successful in 1m11s
CI / ci (RelWithDebInfo, ubuntu-latest) (push) Successful in 1m10s
CI / ci (Release, ubuntu-latest) (push) Successful in 1m9s
CI / ci (Debug, ubuntu-latest) (push) Successful in 4m4s

This commit is contained in:
David Gonzalez Martin 2025-05-29 07:50:56 -06:00
parent d327813595
commit a6315a388f
5 changed files with 140 additions and 24 deletions

View File

@ -94,7 +94,9 @@ fn void compile(Arena* arena, Options options)
.path = options.path, .path = options.path,
.executable = options.executable, .executable = options.executable,
.objects = options.objects, .objects = options.objects,
.libraries = options.libraries, .library_directories = options.library_directories,
.library_names = options.library_names,
.library_paths = options.library_paths,
.target = options.target, .target = options.target,
.build_mode = options.build_mode, .build_mode = options.build_mode,
.has_debug_info = options.has_debug_info, .has_debug_info = options.has_debug_info,
@ -179,17 +181,80 @@ fn String compile_file(Arena* arena, Compile options)
String c_abi_libraries[] = { String c_abi_libraries[] = {
string_literal("build/libc_abi.a"), string_literal("build/libc_abi.a"),
}; };
Slice<String> library_slice = {}; Slice<String> library_names = {};
Slice<String> library_paths = {};
String library_buffer[256];
Slice<String> library_directories = {};
String library_directory = {};
if (is_compiler) if (is_compiler)
{ {
// ArgBuilder builder = {}; ArgBuilder builder = {};
// auto arguments = builder.flush(); String llvm_config_parts[] = {
// os_execute(arena, arguments, environment, {}); string_literal(CMAKE_PREFIX_PATH),
string_literal("/bin/llvm-config"),
};
builder.add(arena, arena_join_string(arena, array_to_slice(llvm_config_parts)));
builder.add("--libdir");
builder.add("--libs");
auto arguments = builder.flush();
auto llvm_config = os_execute(arena, arguments, environment, {
.policies = { ExecuteStandardStreamPolicy::pipe, ExecuteStandardStreamPolicy::ignore },
});
auto success = llvm_config.termination_kind == TerminationKind::exit && llvm_config.termination_code == 0;
if (!success)
{
report_error();
}
auto stream = llvm_config.streams[0];
auto line = string_first_character(stream, '\n');
if (line == string_no_match)
{
report_error();
}
library_directory = stream(0, line);
library_directories = { &library_directory, 1 };
stream = stream(line + 1);
line = string_first_character(stream, '\n');
if (line == string_no_match)
{
report_error();
}
if (line != stream.length - 1)
{
report_error();
}
auto library_list = stream(0, line);
u64 library_count = 0;
while (1)
{
auto space = string_first_character(library_list, ' ');
if (space == string_no_match)
{
auto library_argument = library_list(2);
library_buffer[library_count] = library_argument;
library_count += 1;
break;
}
// Omit the first two characters: "-l"
auto library_argument = library_list(2, space);
library_buffer[library_count] = library_argument;
library_count += 1;
library_list = library_list(space + 1);
}
library_names = { library_buffer, library_count };
} }
else if (base_name.equal(string_literal("c_abi"))) else if (base_name.equal(string_literal("c_abi")))
{ {
library_slice = array_to_slice(c_abi_libraries); library_paths = array_to_slice(c_abi_libraries);
} }
compile(arena, { compile(arena, {
@ -198,10 +263,12 @@ fn String compile_file(Arena* arena, Compile options)
.executable = output_executable_path, .executable = output_executable_path,
.name = base_name, .name = base_name,
.objects = object_slice, .objects = object_slice,
.libraries = library_slice, .library_paths = library_paths,
.library_names = library_names,
.library_directories = library_directories,
.target = { .target = {
.cpu = CPUArchitecture::x86_64, .cpu = CPUArchitecture::x86_64,
.os = OperatingSystem::linux_, .os = OperatingSystem::linux_,
}, },
.build_mode = options.build_mode, .build_mode = options.build_mode,
.has_debug_info = options.has_debug_info, .has_debug_info = options.has_debug_info,

View File

@ -1213,8 +1213,10 @@ struct Module
String name; String name;
String path; String path;
String executable; String executable;
Slice<String>objects; Slice<String> objects;
Slice<String>libraries; Slice<String> library_directories;
Slice<String> library_names;
Slice<String> library_paths;
Target target; Target target;
BuildMode build_mode; BuildMode build_mode;
@ -1283,7 +1285,9 @@ struct Options
String executable; String executable;
String name; String name;
Slice<String> objects; Slice<String> objects;
Slice<String> libraries; Slice<String> library_paths;
Slice<String> library_names;
Slice<String> library_directories;
Target target; Target target;
BuildMode build_mode; BuildMode build_mode;
bool has_debug_info; bool has_debug_info;
@ -1852,6 +1856,16 @@ struct ArgBuilder
argument_count += 1; argument_count += 1;
} }
void add(Arena* arena, String arg)
{
if (arg.pointer[arg.length] != 0)
{
arg = arena_duplicate_string(arena, arg);
}
add((const char*)arg.pointer);
}
Slice<char* const> flush() Slice<char* const> flush()
{ {
assert(argument_count < array_length(args)); assert(argument_count < array_length(args));

View File

@ -8325,16 +8325,33 @@ fn void link(Module* module)
builder.add("-o"); builder.add("-o");
assert(module->executable.pointer[module->executable.length] == 0); assert(module->executable.pointer[module->executable.length] == 0);
builder.add((char*)module->executable.pointer); builder.add((char*)module->executable.pointer);
for (String object: module->objects) for (String object: module->objects)
{ {
assert(object.pointer[object.length] == 0); builder.add(arena, object);
builder.add((char*)object.pointer);
} }
for (String library: module->libraries) for (String library_directory: module->library_directories)
{ {
assert(library.pointer[library.length] == 0); String parts[] = {
builder.add((char*)library.pointer); string_literal("-L"),
library_directory,
};
builder.add(arena, arena_join_string(arena, array_to_slice(parts)));
}
for (String library_path: module->library_paths)
{
builder.add(arena, library_path);
}
for (String library_name: module->library_names)
{
String parts[] = {
string_literal("-l"),
library_name,
};
builder.add(arena, arena_join_string(arena, array_to_slice(parts)));
} }
String candidate_library_paths[] = { String candidate_library_paths[] = {

View File

@ -37,6 +37,7 @@ extern "C" s32 fork();
extern "C" s32 dup2(s32, s32); extern "C" s32 dup2(s32, s32);
extern "C" s32 execve(const char* path_name, const char* const argv[], char* const envp[]); extern "C" s32 execve(const char* path_name, const char* const argv[], char* const envp[]);
extern "C" s32 waitpid(s32 pid, int* wstatus, int options); extern "C" s32 waitpid(s32 pid, int* wstatus, int options);
extern "C" s32 pipe(int fd[2]);
u64 os_file_size(s32 fd) u64 os_file_size(s32 fd)
{ {
@ -75,6 +76,7 @@ fn bool IFSIGNALED(u32 s)
{ {
return (s & 0xffff) - 1 < 0xff; return (s & 0xffff) - 1 < 0xff;
} }
Execution os_execute(Arena* arena, Slice<char* const> arguments, Slice<char* const> environment, ExecuteOptions options) Execution os_execute(Arena* arena, Slice<char* const> arguments, Slice<char* const> environment, ExecuteOptions options)
{ {
unused(arena); unused(arena);
@ -90,7 +92,7 @@ Execution os_execute(Arena* arena, Slice<char* const> arguments, Slice<char* con
} }
else if (options.policies[0] == ExecuteStandardStreamPolicy::ignore || options.policies[1] == ExecuteStandardStreamPolicy::ignore) else if (options.policies[0] == ExecuteStandardStreamPolicy::ignore || options.policies[1] == ExecuteStandardStreamPolicy::ignore)
{ {
trap(); null_file_descriptor = open("/dev/null", { .access_mode = OPEN::AccessMode::write_only });
} }
int pipes[standard_stream_count][2]; int pipes[standard_stream_count][2];
@ -99,7 +101,10 @@ Execution os_execute(Arena* arena, Slice<char* const> arguments, Slice<char* con
{ {
if (options.policies[i] == ExecuteStandardStreamPolicy::pipe) if (options.policies[i] == ExecuteStandardStreamPolicy::pipe)
{ {
trap(); if (pipe(pipes[i]) == -1)
{
trap();
}
} }
} }
@ -154,16 +159,26 @@ Execution os_execute(Arena* arena, Slice<char* const> arguments, Slice<char* con
} }
} }
// TODO: better allocation strategy
u64 allocation_size = 1024 * 1024;
Slice<u8> allocation = {};
if (options.policies[0] == ExecuteStandardStreamPolicy::pipe || options.policies[1] == ExecuteStandardStreamPolicy::pipe) if (options.policies[0] == ExecuteStandardStreamPolicy::pipe || options.policies[1] == ExecuteStandardStreamPolicy::pipe)
{ {
trap(); allocation = arena_allocate<u8>(arena, allocation_size * ((options.policies[0] == ExecuteStandardStreamPolicy::pipe) + (options.policies[1] == ExecuteStandardStreamPolicy::pipe)));
} }
u64 offset = 0;
for (u64 i = 0; i < standard_stream_count; i += 1) for (u64 i = 0; i < standard_stream_count; i += 1)
{ {
if (options.policies[i] == ExecuteStandardStreamPolicy::pipe) if (options.policies[i] == ExecuteStandardStreamPolicy::pipe)
{ {
trap(); auto buffer = allocation(offset)(0, allocation_size);
auto byte_count = read(pipes[i][0], buffer.pointer, buffer.length);
assert(byte_count >= 0);
execution.streams[i] = buffer(0, byte_count);
close(pipes[i][0]);
offset += allocation_size;
} }
} }

View File

@ -551,7 +551,11 @@ fn void* arena_allocate_bytes(Arena* arena, u64 size, u64 alignment)
if (aligned_size_after > arena->os_position) if (aligned_size_after > arena->os_position)
{ {
unreachable(); auto target_commited_size = align_forward(aligned_size_after, arena->granularity);
auto size_to_commit = target_commited_size - arena->os_position;
auto commit_pointer = ((u8*)arena) + arena->os_position;
os_commit(commit_pointer, size_to_commit, { .read = 1, .write = 1 });
arena->os_position = target_commited_size;
} }
result = (u8*)arena + aligned_offset; result = (u8*)arena + aligned_offset;
@ -709,8 +713,7 @@ enum class TerminationKind : u8
struct Execution struct Execution
{ {
String stdout; String streams[2];
String stderr;
TerminationKind termination_kind; TerminationKind termination_kind;
u32 termination_code; u32 termination_code;
}; };