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,
.executable = options.executable,
.objects = options.objects,
.libraries = options.libraries,
.library_directories = options.library_directories,
.library_names = options.library_names,
.library_paths = options.library_paths,
.target = options.target,
.build_mode = options.build_mode,
.has_debug_info = options.has_debug_info,
@ -179,17 +181,80 @@ fn String compile_file(Arena* arena, Compile options)
String c_abi_libraries[] = {
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)
{
// ArgBuilder builder = {};
// auto arguments = builder.flush();
// os_execute(arena, arguments, environment, {});
ArgBuilder builder = {};
String llvm_config_parts[] = {
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")))
{
library_slice = array_to_slice(c_abi_libraries);
library_paths = array_to_slice(c_abi_libraries);
}
compile(arena, {
@ -198,10 +263,12 @@ fn String compile_file(Arena* arena, Compile options)
.executable = output_executable_path,
.name = base_name,
.objects = object_slice,
.libraries = library_slice,
.library_paths = library_paths,
.library_names = library_names,
.library_directories = library_directories,
.target = {
.cpu = CPUArchitecture::x86_64,
.os = OperatingSystem::linux_,
.cpu = CPUArchitecture::x86_64,
.os = OperatingSystem::linux_,
},
.build_mode = options.build_mode,
.has_debug_info = options.has_debug_info,

View File

@ -1213,8 +1213,10 @@ struct Module
String name;
String path;
String executable;
Slice<String>objects;
Slice<String>libraries;
Slice<String> objects;
Slice<String> library_directories;
Slice<String> library_names;
Slice<String> library_paths;
Target target;
BuildMode build_mode;
@ -1283,7 +1285,9 @@ struct Options
String executable;
String name;
Slice<String> objects;
Slice<String> libraries;
Slice<String> library_paths;
Slice<String> library_names;
Slice<String> library_directories;
Target target;
BuildMode build_mode;
bool has_debug_info;
@ -1852,6 +1856,16 @@ struct ArgBuilder
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()
{
assert(argument_count < array_length(args));

View File

@ -8325,16 +8325,33 @@ fn void link(Module* module)
builder.add("-o");
assert(module->executable.pointer[module->executable.length] == 0);
builder.add((char*)module->executable.pointer);
for (String object: module->objects)
{
assert(object.pointer[object.length] == 0);
builder.add((char*)object.pointer);
builder.add(arena, object);
}
for (String library: module->libraries)
for (String library_directory: module->library_directories)
{
assert(library.pointer[library.length] == 0);
builder.add((char*)library.pointer);
String parts[] = {
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[] = {

View File

@ -37,6 +37,7 @@ extern "C" s32 fork();
extern "C" s32 dup2(s32, s32);
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 pipe(int fd[2]);
u64 os_file_size(s32 fd)
{
@ -75,6 +76,7 @@ fn bool IFSIGNALED(u32 s)
{
return (s & 0xffff) - 1 < 0xff;
}
Execution os_execute(Arena* arena, Slice<char* const> arguments, Slice<char* const> environment, ExecuteOptions options)
{
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)
{
trap();
null_file_descriptor = open("/dev/null", { .access_mode = OPEN::AccessMode::write_only });
}
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)
{
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)
{
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)
{
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)
{
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;
@ -709,8 +713,7 @@ enum class TerminationKind : u8
struct Execution
{
String stdout;
String stderr;
String streams[2];
TerminationKind termination_kind;
u32 termination_code;
};