From a6315a388f2f38b1616bc5b380e96740db215153 Mon Sep 17 00:00:00 2001 From: David Gonzalez Martin Date: Thu, 29 May 2025 07:50:56 -0600 Subject: [PATCH] Roughly link LLVM for self-hosted compiler --- src/compiler.cpp | 85 +++++++++++++++++++++++++++++++++++++++++++----- src/compiler.hpp | 20 ++++++++++-- src/emitter.cpp | 27 ++++++++++++--- src/lib.cpp | 23 ++++++++++--- src/lib.hpp | 9 +++-- 5 files changed, 140 insertions(+), 24 deletions(-) diff --git a/src/compiler.cpp b/src/compiler.cpp index c0e4874..35434f6 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -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 library_slice = {}; + Slice library_names = {}; + Slice library_paths = {}; + String library_buffer[256]; + + Slice 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, diff --git a/src/compiler.hpp b/src/compiler.hpp index cbd788b..d3e4b03 100644 --- a/src/compiler.hpp +++ b/src/compiler.hpp @@ -1213,8 +1213,10 @@ struct Module String name; String path; String executable; - Sliceobjects; - Slicelibraries; + Slice objects; + Slice library_directories; + Slice library_names; + Slice library_paths; Target target; BuildMode build_mode; @@ -1283,7 +1285,9 @@ struct Options String executable; String name; Slice objects; - Slice libraries; + Slice library_paths; + Slice library_names; + Slice 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 flush() { assert(argument_count < array_length(args)); diff --git a/src/emitter.cpp b/src/emitter.cpp index 729bcad..43919b8 100644 --- a/src/emitter.cpp +++ b/src/emitter.cpp @@ -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[] = { diff --git a/src/lib.cpp b/src/lib.cpp index f631bbe..fba49b4 100644 --- a/src/lib.cpp +++ b/src/lib.cpp @@ -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 arguments, Slice environment, ExecuteOptions options) { unused(arena); @@ -90,7 +92,7 @@ Execution os_execute(Arena* arena, Slice arguments, Slice arguments, Slice arguments, Slice allocation = {}; if (options.policies[0] == ExecuteStandardStreamPolicy::pipe || options.policies[1] == ExecuteStandardStreamPolicy::pipe) { - trap(); + allocation = arena_allocate(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; } } diff --git a/src/lib.hpp b/src/lib.hpp index f262391..92c2112 100644 --- a/src/lib.hpp +++ b/src/lib.hpp @@ -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; };