diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 85df234..ecddf1b 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -34,3 +34,4 @@ jobs: ./generate.sh ./build.sh ./build/bb test + ./build/bb reproduce diff --git a/src/compiler.bbb b/src/compiler.bbb index e1099b8..a5d68ab 100644 --- a/src/compiler.bbb +++ b/src/compiler.bbb @@ -984,6 +984,7 @@ CompilerCommand = enum { compile, test, + reproduce, } BuildMode = enum @@ -18283,7 +18284,7 @@ compile_file = fn (arena: &Arena, compile_options: CompileFile, envp: &&u8) []u8 { >builder: ArgumentBuilder = zero; - add_argument(&builder, "/home/david/dev/llvm/install/llvm_20.1.3_x86_64-linux-Release/bin/llvm-config"); + add_argument(&builder, arena_join_string(module.arena, [ CMAKE_PREFIX_PATH, "/bin/llvm-config"][..]); add_argument(&builder, "--libdir"); add_argument(&builder, "--libs"); add_argument(&builder, "--system-libs"); @@ -18558,7 +18559,10 @@ names: [_][]u8 = return 1; } + >debug_info_array: [_]u1 = [1, 0]; + >command = command_string_to_enum.enum_value; + switch (command) { .compile => @@ -18620,7 +18624,6 @@ names: [_][]u8 = report_error(); } - >debug_info_array: [_]u1 = [1, 0]; for (name: names) { for (build_mode: #enum_values(BuildMode)) @@ -18656,6 +18659,43 @@ names: [_][]u8 = } } }, + .reproduce => + { + for (build_mode: #enum_values(BuildMode)) + { + for (has_debug_info: debug_info_array) + { + >position = arena.position; + + // Produce the compiler + >relative_file_path = "src/compiler.bbb"; + >executable_path = compile_file(arena, { + .relative_file_path = relative_file_path, + .build_mode = build_mode, + .has_debug_info = has_debug_info, + .silent = 1, + }, envp); + + // Test the compiler + >arguments: [_]&u8 = [ + executable_path.pointer, + "test", + zero, + ]; + >args = arguments[..arguments.length - 1]; + >execution = os_execute(arena, args, envp, zero); + + >success = execution.termination_kind == .exit and execution.termination_code == 0; + + if (!success) + { + #trap(); + } + + arena.position = position; + } + } + }, } return 0; diff --git a/src/compiler.cpp b/src/compiler.cpp index 8ba2702..a697397 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -93,6 +93,7 @@ fn void compile(Arena* arena, Options options) .name = options.name, .path = options.path, .executable = options.executable, + .definitions = options.definitions, .objects = options.objects, .library_directories = options.library_directories, .library_names = options.library_names, @@ -174,6 +175,13 @@ fn String compile_file(Arena* arena, Compile options) auto file_content = file_read(arena, relative_file_path); auto file_path = path_absolute(arena, relative_file_path); + Slice definitions = {}; + auto cmake_prefix_path = string_literal(CMAKE_PREFIX_PATH); + auto cmake_prefix_path_definition = Definition{ + .name = string_literal("CMAKE_PREFIX_PATH"), + .value = cmake_prefix_path, + }; + String objects[] = { output_object_path, }; @@ -190,9 +198,11 @@ fn String compile_file(Arena* arena, Compile options) if (is_compiler) { + definitions = { .pointer = &cmake_prefix_path_definition, .length = 1 }; + ArgBuilder builder = {}; String llvm_config_parts[] = { - string_literal(CMAKE_PREFIX_PATH), + cmake_prefix_path, string_literal("/bin/llvm-config"), }; builder.add(arena, arena_join_string(arena, array_to_slice(llvm_config_parts))); @@ -300,6 +310,7 @@ fn String compile_file(Arena* arena, Compile options) .path = file_path, .executable = output_executable_path, .name = base_name, + .definitions = definitions, .objects = object_slice, .library_paths = library_paths, .library_names = library_names, @@ -619,6 +630,24 @@ void entry_point(Slice arguments, Slice envp) print(compiler_has_debug_info ? string_literal(" with debug info\n") : string_literal(" with no debug info\n")); bb_fail(); } + + char* const reproduce_arguments[] = + { + (char*)compiler.pointer, + (char*)"reproduce", + 0, + }; + arg_slice = array_to_slice(reproduce_arguments); + arg_slice.length -= 1; + execution = os_execute(arena, arg_slice, environment, {}); + success = execution.termination_kind == TerminationKind::exit && execution.termination_code == 0; + if (!success) + { + print(string_literal("Self-hosted reproduction failed: ")); + print(build_mode_to_string(compiler_build_mode)); + print(compiler_has_debug_info ? string_literal(" with debug info\n") : string_literal(" with no debug info\n")); + bb_fail(); + } } } } break; diff --git a/src/compiler.hpp b/src/compiler.hpp index c11bb2e..1c9d699 100644 --- a/src/compiler.hpp +++ b/src/compiler.hpp @@ -1296,6 +1296,12 @@ struct ModuleLLVM u32 debug_tag; }; +struct Definition +{ + String name; + String value; +}; + struct Module { Arena* arena; @@ -1330,6 +1336,7 @@ struct Module String path; String executable; + Slice definitions; Slice objects; Slice library_directories; Slice library_names; @@ -1408,6 +1415,7 @@ struct Options String path; String executable; String name; + Slice definitions; Slice objects; Slice library_paths; Slice library_names; diff --git a/src/parser.cpp b/src/parser.cpp index 1eca489..486692c 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -3166,6 +3166,25 @@ fn Block* parse_block(Module* module, Scope* parent_scope) void parse(Module* module) { auto scope = &module->scope; + + for (auto definition: module->definitions) + { + auto definition_global = new_global(module); + auto definition_value = new_value(module); + *definition_value = { + .string_literal = definition.value, + .id = ValueId::string_literal, + }; + *definition_global = Global{ + .variable = { + .initial_value = definition_value, + .type = get_slice_type(module, uint8(module)), + .scope = scope, + .name = definition.name, + }, + }; + } + while (1) { skip_space(module);