diff --git a/bootstrap/Compilation.zig b/bootstrap/Compilation.zig index ff3f5f7..cbd74ae 100644 --- a/bootstrap/Compilation.zig +++ b/bootstrap/Compilation.zig @@ -171,7 +171,7 @@ const CSourceKind = enum { cpp, }; -pub fn compileCSourceFile(context: *const Context, arguments: [][*:0]u8, kind: CSourceKind) !void { +fn compileMusl(context: *const Context) MuslContext{ const musl = try MuslContext.init(context); var exists = true; var dir = std.fs.cwd().openDir(musl.global_cache_dir, .{}) catch b: { @@ -260,26 +260,63 @@ pub fn compileCSourceFile(context: *const Context, arguments: [][*:0]u8, kind: C } } + return musl; +} + +pub fn compileCSourceFile(context: *const Context, arguments: [][*:0]u8, kind: CSourceKind) !void { var clang_args = UnpinnedArray([]const u8){}; try clang_args.append(context.my_allocator, context.executable_absolute_path); try clang_args.append(context.my_allocator, "clang"); + const Mode = enum{ + object, + link, + }; + const mode: Mode = for (arguments) |argz| { + const arg = span(argz); + if (byte_equal(arg, "-c")) break .object; + } else .link; + _ = mode; // autofix + if (kind == .cpp) { try clang_args.append(context.my_allocator, "-nostdinc++"); - try clang_args.append_slice(context.my_allocator, &.{ - "-isystem", try context.pathFromCompiler("lib/libcxx/include"), - "-isystem", try context.pathFromCompiler("lib/libcxxabi/include"), - "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS", - "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS", - "-D_LIBCPP_HAS_NO_VENDOR_AVAILABILITY_ANNOTATIONS", - "-D_LIBCPP_PSTL_CPU_BACKEND_SERIAL", - "-D_LIBCPP_ABI_VERSION=1", - "-D_LIBCPP_ABI_NAMESPACE=__1", - }); switch (@import("builtin").os.tag) { - .linux => {}, - .macos => {}, + .linux => { + switch (@import("builtin").abi) { + .gnu => { + try clang_args.append_slice(context.my_allocator, &.{ + "-isystem", "/usr/include/c++/13.2.1", + "-isystem", "/usr/include/c++/13.2.1/x86_64-pc-linux-gnu", + }); + }, + .musl => { + try clang_args.append_slice(context.my_allocator, &.{ + "-isystem", try context.pathFromCompiler("lib/libcxx/include"), + "-isystem", try context.pathFromCompiler("lib/libcxxabi/include"), + "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS", + "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS", + "-D_LIBCPP_HAS_NO_VENDOR_AVAILABILITY_ANNOTATIONS", + "-D_LIBCPP_PSTL_CPU_BACKEND_SERIAL", + "-D_LIBCPP_ABI_VERSION=1", + "-D_LIBCPP_ABI_NAMESPACE=__1", + }); + }, + else => unreachable, + } + }, + .macos => { + try clang_args.append_slice(context.my_allocator, &.{ + "-isystem", try context.pathFromCompiler("lib/libcxx/include"), + "-isystem", try context.pathFromCompiler("lib/libcxxabi/include"), + "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS", + "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS", + "-D_LIBCPP_HAS_NO_VENDOR_AVAILABILITY_ANNOTATIONS", + "-D_LIBCPP_PSTL_CPU_BACKEND_SERIAL", + "-D_LIBCPP_ABI_VERSION=1", + "-D_LIBCPP_ABI_NAMESPACE=__1", + }); + }, else => @compileError("Operating system not supported"), } } @@ -289,15 +326,25 @@ pub fn compileCSourceFile(context: *const Context, arguments: [][*:0]u8, kind: C switch (@import("builtin").os.tag) { .linux => { - try clang_args.append_slice(context.my_allocator, &.{ - "-isystem", try context.pathFromCompiler("lib/include"), - "-isystem", try context.pathFromCompiler("lib/libc/include/x86_64-linux-gnu"), - "-isystem", try context.pathFromCompiler("lib/libc/include/generic-glibc"), - "-isystem", try context.pathFromCompiler("lib/libc/include/x86-linux-any"), - "-isystem", try context.pathFromCompiler("lib/libc/include/any-linux-any"), - "-isystem", "/usr/include", - "-isystem", "/usr/include/linux", - }); + switch (@import("builtin").abi) { + .gnu => { + try clang_args.append_slice(context.my_allocator, &.{ + "-isystem", "/usr/lib/clang/17/include", + "-isystem", "/usr/include", + "-isystem", "/usr/include/linux", + }); + }, + .musl => { + try clang_args.append_slice(context.my_allocator, &.{ + "-isystem", try context.pathFromCompiler("lib/include"), + "-isystem", try context.pathFromCompiler("lib/libc/include/x86_64-linux-gnu"), + "-isystem", try context.pathFromCompiler("lib/libc/include/generic-glibc"), + "-isystem", try context.pathFromCompiler("lib/libc/include/x86-linux-any"), + "-isystem", try context.pathFromCompiler("lib/libc/include/any-linux-any"), + }); + }, + else => @compileError("Abi not supported"), + } }, .macos => { try clang_args.append_slice(context.my_allocator, &.{ @@ -310,6 +357,24 @@ pub fn compileCSourceFile(context: *const Context, arguments: [][*:0]u8, kind: C } } + if (kind == .cpp) { + switch (@import("builtin").os.tag) { + .linux => { + switch (@import("builtin").abi) { + .gnu => { + try clang_args.append(context.my_allocator, "-lstdc++"); + }, + .musl => { + unreachable; + }, + else => @compileError("Abi not supported"), + } + }, + .macos => unreachable, + else => @compileError("OS not supported"), + } + } + for (arguments) |arg| { try clang_args.append(context.my_allocator, span(arg)); } @@ -319,43 +384,43 @@ pub fn compileCSourceFile(context: *const Context, arguments: [][*:0]u8, kind: C unreachable; } - const output_object_file = "nat/main.o"; + // const output_object_file = "nat/main.o"; // const exit_code = try clangMain(context.allocator, &.{ context.executable_absolute_path, "--no-default-config", "-target", "x86_64-unknown-linux-musl", "-nostdinc", "-fno-spell-checking", "-isystem", "lib/include", "-isystem", "lib/libc/include/x86_64-linux-musl", "-isystem", "lib/libc/include/generic-musl", "-isystem", "lib/libc/include/x86-linux-any", "-isystem", "lib/libc/include/any-linux-any", "-c", argument, "-o", output_object_file }); // if (exit_code != 0) { // unreachable; // } - const link = false; - if (link) { - var lld_args = UnpinnedArray([*:0]const u8){}; - try lld_args.append(context.my_allocator, "ld.lld"); - try lld_args.append(context.my_allocator, "--error-limit=0"); - try lld_args.append(context.my_allocator, "--entry"); - try lld_args.append(context.my_allocator, "_start"); - try lld_args.append(context.my_allocator, "-z"); - try lld_args.append(context.my_allocator, "stack-size=16777216"); - try lld_args.append(context.my_allocator, "--image-base=16777216"); - try lld_args.append(context.my_allocator, "-m"); - try lld_args.append(context.my_allocator, "elf_x86_64"); - try lld_args.append(context.my_allocator, "-static"); - try lld_args.append(context.my_allocator, "-o"); - try lld_args.append(context.my_allocator, "nat/main"); - try lld_args.append(context.my_allocator, try std.mem.joinZ(context.allocator, "", &.{ musl.global_cache_dir, "crt1.o" })); - try lld_args.append(context.my_allocator, try std.mem.joinZ(context.allocator, "", &.{ musl.global_cache_dir, "crti.o" })); - try lld_args.append(context.my_allocator, output_object_file); - try lld_args.append(context.my_allocator, "--as-needed"); - try lld_args.append(context.my_allocator, try std.mem.joinZ(context.allocator, "", &.{ musl.global_cache_dir, "libc.a" })); - try lld_args.append(context.my_allocator, try std.mem.joinZ(context.allocator, "", &.{ musl.global_cache_dir, "crtn.o" })); - - var stdout_ptr: [*]const u8 = undefined; - var stdout_len: usize = 0; - var stderr_ptr: [*]const u8 = undefined; - var stderr_len: usize = 0; - const link_result = llvm.bindings.NativityLLDLinkELF(lld_args.pointer, lld_args.length, &stdout_ptr, &stdout_len, &stderr_ptr, &stderr_len); - if (!link_result) { - unreachable; - } - } + // const link = false; + // if (link) { + // var lld_args = UnpinnedArray([*:0]const u8){}; + // try lld_args.append(context.my_allocator, "ld.lld"); + // try lld_args.append(context.my_allocator, "--error-limit=0"); + // try lld_args.append(context.my_allocator, "--entry"); + // try lld_args.append(context.my_allocator, "_start"); + // try lld_args.append(context.my_allocator, "-z"); + // try lld_args.append(context.my_allocator, "stack-size=16777216"); + // try lld_args.append(context.my_allocator, "--image-base=16777216"); + // try lld_args.append(context.my_allocator, "-m"); + // try lld_args.append(context.my_allocator, "elf_x86_64"); + // try lld_args.append(context.my_allocator, "-static"); + // try lld_args.append(context.my_allocator, "-o"); + // try lld_args.append(context.my_allocator, "nat/main"); + // try lld_args.append(context.my_allocator, try std.mem.joinZ(context.allocator, "", &.{ musl.global_cache_dir, "crt1.o" })); + // try lld_args.append(context.my_allocator, try std.mem.joinZ(context.allocator, "", &.{ musl.global_cache_dir, "crti.o" })); + // try lld_args.append(context.my_allocator, output_object_file); + // try lld_args.append(context.my_allocator, "--as-needed"); + // try lld_args.append(context.my_allocator, try std.mem.joinZ(context.allocator, "", &.{ musl.global_cache_dir, "libc.a" })); + // try lld_args.append(context.my_allocator, try std.mem.joinZ(context.allocator, "", &.{ musl.global_cache_dir, "crtn.o" })); + // + // var stdout_ptr: [*]const u8 = undefined; + // var stdout_len: usize = 0; + // var stderr_ptr: [*]const u8 = undefined; + // var stderr_len: usize = 0; + // const link_result = llvm.bindings.NativityLLDLinkELF(lld_args.pointer, lld_args.length, &stdout_ptr, &stdout_len, &stderr_ptr, &stderr_len); + // if (!link_result) { + // unreachable; + // } + // } // const thread = try std.Thread.spawn(.{}, clang_job, .{args}); // thread.join(); } diff --git a/build.zig b/build.zig index ae86107..2d73559 100644 --- a/build.zig +++ b/build.zig @@ -26,7 +26,8 @@ pub fn build(b: *std.Build) !void { const print_stack_trace = b.option(bool, "print_stack_trace", "This option enables printing stack traces inside the compiler") orelse is_ci or os == .macos; const native_target = b.resolveTargetQuery(.{}); const optimization = b.standardOptimizeOption(.{}); - const static = b.option(bool, "static", "This option enables the compiler to be built statically") orelse true; + const use_debug = b.option(bool, "use_debug", "This option enables the LLVM debug build in the development PC") orelse false; + const static = b.option(bool, "static", "This option enables the compiler to be built statically") orelse use_debug; const compiler_options = b.addOptions(); compiler_options.addOption(bool, "print_stack_trace", print_stack_trace); @@ -384,7 +385,6 @@ pub fn build(b: *std.Build) !void { break :blk llvm_directory.items; } else { - const use_debug = b.option(bool, "use_debug", "This option enables the LLVM debug build in the development PC") orelse false; break :blk switch (use_debug) { true => "../llvm-17-static-debug", false => "../llvm-17-static-release", diff --git a/build/test_runner.zig b/build/test_runner.zig index 8ac9d7f..b792d0a 100644 --- a/build/test_runner.zig +++ b/build/test_runner.zig @@ -53,6 +53,7 @@ fn runStandalone(allocator: Allocator, args: struct { .allocator = allocator, // TODO: delete -main_source_file? .argv = &.{ "zig-out/bin/nat", if (args.is_test) "test" else "exe", "-main_source_file", source_file_path }, + .max_output_bytes = std.math.maxInt(u64), }); ran_compilation_count += 1; @@ -82,6 +83,7 @@ fn runStandalone(allocator: Allocator, args: struct { .allocator = allocator, // TODO: delete -main_source_file? .argv = &.{test_path}, + .max_output_bytes = std.math.maxInt(u64), }); ran_test_count += 1; const test_result: TestError!bool = switch (test_run.term) { @@ -134,6 +136,7 @@ fn runStandaloneTests(allocator: Allocator) !void { .allocator = allocator, // TODO: delete -main_source_file? .argv = &.{ "zig-out/bin/nat", "exe", "-main_source_file", source_file_path }, + .max_output_bytes = std.math.maxInt(u64), }); ran_compilation_count += 1; @@ -163,6 +166,7 @@ fn runStandaloneTests(allocator: Allocator) !void { .allocator = allocator, // TODO: delete -main_source_file? .argv = &.{test_path}, + .max_output_bytes = std.math.maxInt(u64), }); ran_test_count += 1; const test_result: TestError!bool = switch (test_run.term) { @@ -221,6 +225,7 @@ fn runBuildTests(allocator: Allocator) !void { .allocator = allocator, // TODO: delete -main_source_file? .argv = &.{ compiler_realpath, "build" }, + .max_output_bytes = std.math.maxInt(u64), }); ran_compilation_count += 1; @@ -251,6 +256,7 @@ fn runBuildTests(allocator: Allocator) !void { .allocator = allocator, // TODO: delete -main_source_file? .argv = &.{test_path}, + .max_output_bytes = std.math.maxInt(u64), }); ran_test_count += 1; const test_result: TestError!bool = switch (test_run.term) { @@ -288,33 +294,14 @@ fn runBuildTests(allocator: Allocator) !void { } } -pub fn main() !void { +fn runStdTests(allocator: Allocator) !void { var errors = false; - var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); - const allocator = arena.allocator(); - runStandalone(allocator, .{ - .directory_path = "test/standalone", - .group_name = "STANDALONE", - .is_test = false, - }) catch { - errors = true; - }; - runBuildTests(allocator) catch { - errors = true; - }; - runStandalone(allocator, .{ - .directory_path = "test/tests", - .group_name = "TEST EXECUTABLE", - .is_test = true, - }) catch { - errors = true; - }; - std.debug.print("std... ", .{}); const result = try std.ChildProcess.run(.{ .allocator = allocator, .argv = &.{ "zig-out/bin/nat", "test", "-main_source_file", "lib/std/std.nat", "-name", "std" }, + .max_output_bytes = std.math.maxInt(u64), }); const compilation_result: TestError!bool = switch (result.term) { .Exited => |exit_code| if (exit_code == 0) true else error.abnormal_exit_code, @@ -341,6 +328,7 @@ pub fn main() !void { .allocator = allocator, // TODO: delete -main_source_file? .argv = &.{"nat/std"}, + .max_output_bytes = std.math.maxInt(u64), }); const test_result: TestError!bool = switch (test_run.term) { .Exited => |exit_code| if (exit_code == 0) true else error.abnormal_exit_code, @@ -362,6 +350,171 @@ pub fn main() !void { } } + if (errors) return error.fail; +} + +fn runCmakeTests(allocator: Allocator) !void { + var errors = false; + const original_dir = try std.fs.cwd().realpathAlloc(allocator, "."); + const cc_dir = try std.fs.cwd().openDir("test/cc", .{ + .iterate = true, + }); + + const cc_dir_path = try cc_dir.realpathAlloc(allocator, "."); + try std.posix.chdir(cc_dir_path); + + var cc_dir_iterator = cc_dir.iterate(); + while (try cc_dir_iterator.next()) |cc_entry| { + switch (cc_entry.kind) { + .directory => { + std.debug.print("{s}...\n", .{cc_entry.name}); + try std.posix.chdir(cc_entry.name); + try std.fs.cwd().deleteTree("build"); + try std.fs.cwd().makeDir("build"); + try std.posix.chdir("build"); + + const cmake = try std.ChildProcess.run(.{ + .allocator = allocator, + // TODO: delete -main_source_file? + .argv = &.{ + "cmake", + "..", + "-G", "Unix Makefiles", + "-DCMAKE_VERBOSE_MAKEFILE=On", + try std.mem.concat(allocator, u8, &.{ "-DCMAKE_C_COMPILER=", "nat;cc" }), + try std.mem.concat(allocator, u8, &.{ "-DCMAKE_CXX_COMPILER=", "nat;c++" }), + try std.mem.concat(allocator, u8, &.{ "-DCMAKE_ASM_COMPILER=", "nat;cc" }), + }, + .max_output_bytes = std.math.maxInt(u64), + }); + const cmake_result: TestError!bool = switch (cmake.term) { + .Exited => |exit_code| if (exit_code == 0) true else error.abnormal_exit_code, + .Signal => error.signaled, + .Stopped => error.stopped, + .Unknown => error.unknown, + }; + + const cmake_success = cmake_result catch b: { + errors = true; + break :b false; + }; + + if (!cmake_success) { + if (cmake.stdout.len > 0) { + std.debug.print("STDOUT:\n\n{s}\n\n", .{cmake.stdout}); + } + if (cmake.stderr.len > 0) { + std.debug.print("STDERR:\n\n{s}\n\n", .{cmake.stderr}); + } + } + + var success = cmake_success; + if (success) { + const ninja = try std.ChildProcess.run(.{ + .allocator = allocator, + // TODO: delete -main_source_file? + .argv = &.{ + "make" + }, + .max_output_bytes = std.math.maxInt(u64), + }); + const ninja_result: TestError!bool = switch (ninja.term) { + .Exited => |exit_code| if (exit_code == 0) true else error.abnormal_exit_code, + .Signal => error.signaled, + .Stopped => error.stopped, + .Unknown => error.unknown, + }; + + const ninja_success = ninja_result catch b: { + errors = true; + break :b false; + }; + if (!ninja_success) { + if (ninja.stdout.len > 0) { + std.debug.print("STDOUT:\n\n{s}\n\n", .{ninja.stdout}); + } + if (ninja.stderr.len > 0) { + std.debug.print("STDERR:\n\n{s}\n\n", .{ninja.stderr}); + } + } + + success = success and ninja_success; + + if (success) { + const run = try std.ChildProcess.run(.{ + .allocator = allocator, + // TODO: delete -main_source_file? + .argv = &.{ + try std.mem.concat(allocator, u8, &.{ "./", cc_entry.name}), + }, + .max_output_bytes = std.math.maxInt(u64), + }); + const run_result: TestError!bool = switch (run.term) { + .Exited => |exit_code| if (exit_code == 0) true else error.abnormal_exit_code, + .Signal => error.signaled, + .Stopped => error.stopped, + .Unknown => error.unknown, + }; + + const run_success = run_result catch b: { + errors = true; + break :b false; + }; + + if (run.stdout.len > 0) { + std.debug.print("STDOUT:\n\n{s}\n\n", .{run.stdout}); + } + if (run.stderr.len > 0) { + std.debug.print("STDERR:\n\n{s}\n\n", .{run.stderr}); + } + + success = success and run_success; + } + } + + std.debug.print("[TEST {s}]\n", .{if (success) "\x1b[32mOK\x1b[0m" else "\x1b[31mFAILED\x1b[0m"}); + }, + else => std.debug.panic("Entry {s} is a {s}", .{cc_entry.name, @tagName(cc_entry.kind)}), + } + + try std.posix.chdir(cc_dir_path); + } + + try std.posix.chdir(original_dir); + + if (errors) { + return error.fail; + } +} + +pub fn main() !void { + var errors = false; + var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); + const allocator = arena.allocator(); + runStandalone(allocator, .{ + .directory_path = "test/standalone", + .group_name = "STANDALONE", + .is_test = false, + }) catch { + errors = true; + }; + runBuildTests(allocator) catch { + errors = true; + }; + runStandalone(allocator, .{ + .directory_path = "test/tests", + .group_name = "TEST EXECUTABLE", + .is_test = true, + }) catch { + errors = true; + }; + + runStdTests(allocator) catch { + errors = true; + }; + + try runCmakeTests(allocator); + if (errors) { return error.fail; } diff --git a/test/cc/.gitignore b/test/cc/c_first/.gitignore similarity index 100% rename from test/cc/.gitignore rename to test/cc/c_first/.gitignore diff --git a/test/cc/c_first/main.c b/test/cc/c_first/main.c index f2c7519..31014af 100644 --- a/test/cc/c_first/main.c +++ b/test/cc/c_first/main.c @@ -1,6 +1,6 @@ #include int main() { - printf("Hello world\n"); + printf("Hello \n"); return 0; }