Tiny C++ integration

This commit is contained in:
David Gonzalez Martin 2024-03-24 20:38:26 -06:00
parent 0b928835a0
commit 328b907506
5 changed files with 296 additions and 78 deletions

View File

@ -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();
}

View File

@ -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",

View File

@ -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;
}

View File

@ -1,6 +1,6 @@
#include <stdio.h>
int main()
{
printf("Hello world\n");
printf("Hello \n");
return 0;
}