Improve clang integration

LLVM can now be compiled with nat
This commit is contained in:
David Gonzalez Martin 2024-03-25 14:22:55 -06:00
parent f245b28ed8
commit dfcda18a70
18 changed files with 1044 additions and 276 deletions

3
.gitignore vendored
View File

@ -1,3 +1,6 @@
zig-cache/ zig-cache/
zig-out/ zig-out/
nat/ nat/
*.o
*.out
*.obj

View File

@ -6,6 +6,8 @@ const data_structures = @import("library.zig");
const assert = data_structures.assert; const assert = data_structures.assert;
const byte_equal = data_structures.byte_equal; const byte_equal = data_structures.byte_equal;
const byte_equal_terminated = data_structures.byte_equal_terminated; const byte_equal_terminated = data_structures.byte_equal_terminated;
const first_slice = data_structures.first_slice;
const starts_with_slice = data_structures.starts_with_slice;
const UnpinnedArray = data_structures.UnpinnedArray; const UnpinnedArray = data_structures.UnpinnedArray;
const BlockList = data_structures.BlockList; const BlockList = data_structures.BlockList;
const MyAllocator = data_structures.MyAllocator; const MyAllocator = data_structures.MyAllocator;
@ -17,6 +19,7 @@ const lexer = @import("frontend/lexer.zig");
const parser = @import("frontend/parser.zig"); const parser = @import("frontend/parser.zig");
const Node = parser.Node; const Node = parser.Node;
const llvm = @import("backend/llvm.zig"); const llvm = @import("backend/llvm.zig");
const linker = @import("linker/linker.zig");
const cache_dir_name = "cache"; const cache_dir_name = "cache";
const installation_dir_name = "installation"; const installation_dir_name = "installation";
@ -59,7 +62,7 @@ pub fn createContext(allocator: Allocator, my_allocator: *MyAllocator) !*const C
return context; return context;
} }
pub fn compileBuildExecutable(context: *const Context, arguments: [][*:0]u8) !void { pub fn compileBuildExecutable(context: *const Context, arguments: []const []const u8) !void {
_ = arguments; // autofix _ = arguments; // autofix
const unit = try context.my_allocator.allocate_one(Unit); const unit = try context.my_allocator.allocate_one(Unit);
unit.* = .{ unit.* = .{
@ -83,7 +86,9 @@ pub fn compileBuildExecutable(context: *const Context, arguments: [][*:0]u8) !vo
}, },
.only_parse = false, .only_parse = false,
.executable_path = "nat/build", .executable_path = "nat/build",
.object_path = "nat/build.o",
.link_libc = @import("builtin").os.tag == .macos, .link_libc = @import("builtin").os.tag == .macos,
.link_libcpp = false,
.generate_debug_information = true, .generate_debug_information = true,
.name = "build", .name = "build",
.is_test = false, .is_test = false,
@ -263,126 +268,608 @@ fn compileMusl(context: *const Context) MuslContext{
return musl; return musl;
} }
pub fn compileCSourceFile(context: *const Context, arguments: [][*:0]u8, kind: CSourceKind) !void { pub fn compileCSourceFile(context: *const Context, arguments: []const []const u8, kind: CSourceKind) !void {
var clang_args = UnpinnedArray([]const u8){}; _ = kind; // autofix
try clang_args.append(context.my_allocator, context.executable_absolute_path); var argument_index: usize = 0;
try clang_args.append(context.my_allocator, "clang"); _ = &argument_index;
const Mode = enum{ const Mode = enum{
object, object,
link, link,
}; };
const mode: Mode = for (arguments) |argz| { var out_path: ?[]const u8 = null;
const arg = span(argz); var out_mode: ?Mode = null;
if (byte_equal(arg, "-c")) break .object; const Extension = enum{
} else .link; c,
_ = mode; // autofix cpp,
assembly,
object,
static_library,
shared_library,
};
const CSourceFile = struct{
path: []const u8,
extension: Extension,
};
const DebugInfo = enum{
yes,
no,
};
const LinkArch = enum{
arm64,
};
var debug_info: ?DebugInfo = null;
var stack_protector: ?bool = null;
var link_arch: ?LinkArch = null;
if (kind == .cpp) { var cc_argv = UnpinnedArray([]const u8){};
try clang_args.append(context.my_allocator, "-nostdinc++"); var ld_argv = UnpinnedArray([]const u8){};
var c_source_files = UnpinnedArray(CSourceFile){};
var link_objects = UnpinnedArray(linker.Object){};
var link_libraries = UnpinnedArray(linker.Library){};
switch (@import("builtin").os.tag) { while (argument_index < arguments.len) {
.linux => { const argument = arguments[argument_index];
switch (@import("builtin").abi) {
.gnu => { if (argument[0] != '-') {
try clang_args.append_slice(context.my_allocator, &.{ if (data_structures.last_byte(argument, '.')) |dot_index| {
"-isystem", "/usr/include/c++/13.2.1", const extension_string = argument[dot_index..];
"-isystem", "/usr/include/c++/13.2.1/x86_64-pc-linux-gnu", const extension: Extension =
if (byte_equal(extension_string, ".c")) .c
else if (byte_equal(extension_string, ".cpp") or byte_equal(extension_string, ".cxx") or byte_equal(extension_string, ".cc")) .cpp
else if (byte_equal(extension_string, ".S")) .assembly
else if (byte_equal(extension_string, ".o")) .object
else if (byte_equal(extension_string, ".a")) .static_library
else if (byte_equal(extension_string, ".so") or
byte_equal(extension_string, ".dll") or
byte_equal(extension_string, ".dylib") or
byte_equal(extension_string, ".tbd")
) .shared_library
else {
try write(.panic, argument);
try write(.panic, "\n");
@panic("Unable to recognize extension for the file above");
};
switch (extension) {
.c, .cpp, .assembly => {
try c_source_files.append(context.my_allocator, .{
.path = argument,
.extension = extension,
}); });
}, },
.musl => { .object, .static_library, .shared_library => {
try clang_args.append_slice(context.my_allocator, &.{ try link_objects.append(context.my_allocator, .{
"-isystem", try context.pathFromCompiler("lib/libcxx/include"), .path = argument,
"-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,
} }
}, } else {
.macos => { try write(.panic, argument);
try clang_args.append_slice(context.my_allocator, &.{ try write(.panic, "\n");
"-isystem", try context.pathFromCompiler("lib/libcxx/include"), @panic("Positional argument without extension");
"-isystem", try context.pathFromCompiler("lib/libcxxabi/include"), }
"-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS", } else if (byte_equal(argument, "-c")) {
"-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS", out_mode = .object;
"-D_LIBCPP_HAS_NO_VENDOR_AVAILABILITY_ANNOTATIONS", } else if (byte_equal(argument, "-o")) {
"-D_LIBCPP_PSTL_CPU_BACKEND_SERIAL", argument_index += 1;
"-D_LIBCPP_ABI_VERSION=1", out_path = arguments[argument_index];
"-D_LIBCPP_ABI_NAMESPACE=__1", } else if (byte_equal(argument, "-g")) {
}); debug_info = .yes;
}, } else if (byte_equal(argument, "-fno-stack-protector")) {
else => @compileError("Operating system not supported"), stack_protector = false;
} else if (byte_equal(argument, "-arch")) {
argument_index += 1;
const arch_argument = arguments[argument_index];
if (byte_equal(arch_argument, "arm64")) {
link_arch = .arm64;
try cc_argv.append(context.my_allocator, "-arch");
try cc_argv.append(context.my_allocator, "arm64");
} else {
unreachable;
}
} else if (byte_equal(argument, "-bundle")) {
try ld_argv.append(context.my_allocator, argument);
} else if (byte_equal(argument, "-pthread")) {
try cc_argv.append(context.my_allocator, argument);
} else if (byte_equal(argument, "-fPIC")) {
try cc_argv.append(context.my_allocator, argument);
} else if (byte_equal(argument, "-MD")) {
try cc_argv.append(context.my_allocator, argument);
} else if (byte_equal(argument, "-MT")) {
try cc_argv.append(context.my_allocator, argument);
argument_index += 1;
const arg = arguments[argument_index];
try cc_argv.append(context.my_allocator, arg);
} else if (byte_equal(argument, "-MF")) {
try cc_argv.append(context.my_allocator, argument);
argument_index += 1;
const arg = arguments[argument_index];
try cc_argv.append(context.my_allocator, arg);
} else if (byte_equal(argument, "-isysroot")) {
try cc_argv.append(context.my_allocator, argument);
argument_index += 1;
const arg = arguments[argument_index];
try cc_argv.append(context.my_allocator, arg);
} else if (byte_equal(argument, "-isystem")) {
try cc_argv.append(context.my_allocator, argument);
argument_index += 1;
const arg = arguments[argument_index];
try cc_argv.append(context.my_allocator, arg);
} else if (byte_equal(argument, "-h")) {
try cc_argv.append(context.my_allocator, argument);
} else if (byte_equal(argument, "-framework")) {
try ld_argv.append(context.my_allocator, argument);
argument_index += 1;
const framework = arguments[argument_index];
try ld_argv.append(context.my_allocator, framework);
} else if (byte_equal(argument, "--coverage")) {
try cc_argv.append(context.my_allocator, argument);
} else if (byte_equal(argument, "-pedantic")) {
try cc_argv.append(context.my_allocator, argument);
} else if (byte_equal(argument, "-pedantic-errors")) {
try cc_argv.append(context.my_allocator, argument);
} else if (byte_equal(argument, "-?")) {
try cc_argv.append(context.my_allocator, argument);
} else if (byte_equal(argument, "-v")) {
try cc_argv.append(context.my_allocator, argument);
} else if (byte_equal(argument, "-V")) {
try cc_argv.append(context.my_allocator, argument);
} else if (byte_equal(argument, "--version")) {
try cc_argv.append(context.my_allocator, argument);
} else if (byte_equal(argument, "-version")) {
try cc_argv.append(context.my_allocator, argument);
} else if (byte_equal(argument, "-qversion")) {
try cc_argv.append(context.my_allocator, argument);
} else if (byte_equal(argument, "-print-resource-dir")) {
try cc_argv.append(context.my_allocator, argument);
} else if (byte_equal(argument, "-shared")) {
try ld_argv.append(context.my_allocator, argument);
} else if (byte_equal(argument, "-compatibility_version")) {
try ld_argv.append(context.my_allocator, argument);
argument_index += 1;
const arg = arguments[argument_index];
try ld_argv.append(context.my_allocator, arg);
} else if (byte_equal(argument, "-current_version")) {
try ld_argv.append(context.my_allocator, argument);
argument_index += 1;
const arg = arguments[argument_index];
try ld_argv.append(context.my_allocator, arg);
} else if (byte_equal(argument, "-install_name")) {
try ld_argv.append(context.my_allocator, argument);
argument_index += 1;
const arg = arguments[argument_index];
try ld_argv.append(context.my_allocator, arg);
} else if (starts_with_slice(argument, "-f")) {
try cc_argv.append(context.my_allocator, argument);
} else if (starts_with_slice(argument, "-wd")) {
try cc_argv.append(context.my_allocator, argument);
} else if (starts_with_slice(argument, "-D")) {
try cc_argv.append(context.my_allocator, argument);
} else if (starts_with_slice(argument, "-I")) {
try cc_argv.append(context.my_allocator, argument);
} else if (starts_with_slice(argument, "-W")) {
try cc_argv.append(context.my_allocator, argument);
} else if (starts_with_slice(argument, "-l")) {
try link_libraries.append(context.my_allocator, .{
.path = argument[2..],
});
} else if (starts_with_slice(argument, "-O")) {
try cc_argv.append(context.my_allocator, argument);
} else if (starts_with_slice(argument, "-std=")) {
try cc_argv.append(context.my_allocator, argument);
} else if (starts_with_slice(argument, "-rdynamic")) {
try ld_argv.append(context.my_allocator, "-export_dynamic");
} else if (starts_with_slice(argument, "-dynamiclib")) {
try ld_argv.append(context.my_allocator, "-dylib");
} else if (starts_with_slice(argument, "-Wl,")) {
const wl_arg = argument["-Wl,".len..];
if (data_structures.first_byte(wl_arg, ',')) |comma_index| {
const key = wl_arg[0..comma_index];
const value = wl_arg[comma_index + 1..];
try ld_argv.append(context.my_allocator, key);
try ld_argv.append(context.my_allocator, value);
} else {
try ld_argv.append(context.my_allocator, wl_arg);
}
} else if (starts_with_slice(argument, "-m")) {
try cc_argv.append(context.my_allocator, argument);
} else {
const debug_args = true;
if (debug_args) {
const home_dir = std.posix.getenv("HOME") orelse unreachable;
var list = UnpinnedArray(u8){};
for (arguments) |arg| {
try list.append_slice(context.my_allocator, arg);
try list.append(context.my_allocator, ' ');
}
try list.append(context.my_allocator, '\n');
try list.append_slice(context.my_allocator, "Unhandled argument: ");
try list.append_slice(context.my_allocator, argument);
try list.append(context.my_allocator, '\n');
try std.fs.cwd().writeFile(try std.fmt.allocPrint(context.allocator, "{s}/dev/nativity/nat/unhandled_arg_{}", .{home_dir, std.time.milliTimestamp()}), list.slice());
}
try write(.panic, "unhandled argument: '");
try write(.panic, argument);
try write(.panic, "'\n");
@panic("Unhandled argument");
} }
argument_index += 1;
} }
if (kind == .c or kind == .cpp) { const link_libcpp = true;
try clang_args.append(context.my_allocator, "-nostdinc"); const mode = out_mode orelse .link;
switch (@import("builtin").os.tag) { if (c_source_files.length > 0) {
.linux => { for (c_source_files.slice()) |c_source_file| {
switch (@import("builtin").abi) { var argv = UnpinnedArray([]const u8){};
.gnu => { try argv.append(context.my_allocator, context.executable_absolute_path);
try clang_args.append_slice(context.my_allocator, &.{ try argv.append(context.my_allocator, "clang");
"-isystem", "/usr/lib/clang/17/include", try argv.append(context.my_allocator, "--no-default-config");
"-isystem", "/usr/include",
"-isystem", "/usr/include/linux", try argv.append(context.my_allocator, c_source_file.path);
});
if (c_source_file.extension == .cpp) {
try argv.append(context.my_allocator, "-nostdinc++");
}
const caret = true;
if (!caret) {
try argv.append(context.my_allocator, "-fno-caret-diagnostics");
}
const function_sections = false;
if (function_sections) {
try argv.append(context.my_allocator, "-ffunction-sections");
}
const data_sections = false;
if (data_sections) {
try argv.append(context.my_allocator, "-fdata-sections");
}
const builtin = true;
if (!builtin) {
try argv.append(context.my_allocator, "-fno-builtin");
}
if (link_libcpp) {
// include paths
}
const link_libc = c_source_file.extension == .c;
if (link_libc) {
}
const link_libunwind = false;
if (link_libunwind) {
unreachable;
}
const target_triple = blk: {
// Emit target
var target_triple_buffer = UnpinnedArray(u8){};
switch (@import("builtin").target.cpu.arch) {
.x86_64 => {
try target_triple_buffer.append_slice(context.my_allocator, "x86_64-");
}, },
.musl => { .aarch64 => {
try clang_args.append_slice(context.my_allocator, &.{ try target_triple_buffer.append_slice(context.my_allocator, "aarch64-");
"-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"), else => @compileError("Architecture not supported"),
} }
},
.macos => {
try clang_args.append_slice(context.my_allocator, &.{
"-iframework", "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks",
"-isystem", try context.pathFromCompiler("lib/include"),
"-isystem", "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include",
});
},
else => @compileError("Operating system not supported"),
}
}
if (kind == .cpp) { if (@import("builtin").target.cpu.arch == .aarch64 and @import("builtin").target.os.tag == .macos) {
switch (@import("builtin").os.tag) { try target_triple_buffer.append_slice(context.my_allocator, "apple-");
.linux => { } else {
switch (@import("builtin").abi) { try target_triple_buffer.append_slice(context.my_allocator, "pc-");
.gnu => { }
try clang_args.append(context.my_allocator, "-lstdc++");
switch (@import("builtin").target.os.tag) {
.linux => {
try target_triple_buffer.append_slice(context.my_allocator, "linux-");
}, },
.macos => {
try target_triple_buffer.append_slice(context.my_allocator, "macos-");
},
else => @compileError("OS not supported"),
}
switch (@import("builtin").target.abi) {
.musl => { .musl => {
try target_triple_buffer.append_slice(context.my_allocator, "musl");
},
.gnu => {
try target_triple_buffer.append_slice(context.my_allocator, "gnu");
},
.none => {
try target_triple_buffer.append_slice(context.my_allocator, "unknown");
},
else => @compileError("OS not supported"),
}
break :blk target_triple_buffer.slice();
};
try argv.append_slice(context.my_allocator, &.{"-target", target_triple});
const object_path = switch (mode) {
.object => out_path.?,
.link => try std.mem.concat(context.allocator, u8, &.{if (out_path) |op| op else "a.o", ".o"}),
};
try link_objects.append(context.my_allocator, .{
.path = object_path,
});
switch (c_source_file.extension) {
.c, .cpp => {
try argv.append(context.my_allocator, "-nostdinc");
try argv.append(context.my_allocator, "-fno-spell-checking");
const lto = false;
if (lto) {
try argv.append(context.my_allocator, "-flto");
}
const mm = false;
if (mm) {
try argv.append(context.my_allocator, "-ObjC++");
}
const libc_framework_dirs: []const []const u8 = switch (@import("builtin").os.tag) {
.macos => &.{"/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks"},
else => &.{},
};
for (libc_framework_dirs) |framework_dir| {
try argv.append_slice(context.my_allocator, &.{"-iframework", framework_dir});
}
const framework_dirs = &[_][]const u8{};
for (framework_dirs) |framework_dir| {
try argv.append_slice(context.my_allocator, &.{"-F", framework_dir});
}
// TODO: c headers dir
const libc_include_dirs: []const []const u8 = switch (@import("builtin").os.tag) {
.macos => &.{
"/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1",
try context.pathFromCompiler("lib/include"),
"/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include",
},
.linux => switch (@import("builtin").abi) {
.gnu => &.{
"/usr/include/c++/13.2.1",
"/usr/include/c++/13.2.1/x86_64-pc-linux-gnu",
"/usr/lib/clang/17/include",
"/usr/include",
"/usr/include/linux",
},
else => unreachable, //@compileError("ABI not supported"),
},
else => @compileError("OS not supported"),
};
for (libc_include_dirs) |include_dir| {
try argv.append_slice(context.my_allocator, &.{"-isystem", include_dir});
}
// TODO: cpu model
// TODO: cpu features
// TODO: code model
// TODO: OS-specific flags
// TODO: sanitize flags
// const red_zone = true;
// if (red_zone) {
// try argv.append(context.my_allocator, "-mred-zone");
// } else {
// unreachable;
// }
const omit_frame_pointer = false;
if (omit_frame_pointer) {
try argv.append(context.my_allocator, "-fomit-frame-pointer");
} else {
try argv.append(context.my_allocator, "-fno-omit-frame-pointer");
}
if (stack_protector orelse false) {
try argv.append(context.my_allocator, "-fstack-protector-strong");
} else {
try argv.append(context.my_allocator, "-fno-stack-protector");
}
const is_debug = true;
if (is_debug) {
try argv.append(context.my_allocator, "-D_DEBUG");
try argv.append(context.my_allocator, "-O0");
} else {
unreachable; unreachable;
}, }
else => @compileError("Abi not supported"),
} const pic = false;
}, if (pic) {
.macos => unreachable, try argv.append(context.my_allocator, "-fPIC");
else => @compileError("OS not supported"), }
const unwind_tables = false;
if (unwind_tables) {
try argv.append(context.my_allocator, "-funwind-tables");
} else {
try argv.append(context.my_allocator, "-fno-unwind-tables");
}
},
.assembly => {
// TODO:
},
.object, .static_library, .shared_library => unreachable,
}
const has_debug_info = true;
if (has_debug_info) {
try argv.append(context.my_allocator, "-g");
} else {
unreachable;
}
// TODO: machine ABI
const freestanding = false;
if (freestanding) {
try argv.append(context.my_allocator, "-ffrestanding");
}
// TODO: native system include paths
// TODO: global cc argv
try argv.append_slice(context.my_allocator, cc_argv.slice());
// TODO: extra flags
// TODO: cache exempt flags
try argv.append_slice(context.my_allocator, &.{"-c", "-o", object_path});
// TODO: emit ASM/LLVM IR
const debug_clang_args = false;
if (debug_clang_args) {
std.debug.print("Argv: {s}\n", .{argv.slice()});
}
const result = try clangMain(context.allocator, argv.slice());
if (result != 0) {
unreachable;
}
} }
} else if (link_objects.length == 0) {
var argv = UnpinnedArray([]const u8){};
try argv.append(context.my_allocator, context.executable_absolute_path);
try argv.append(context.my_allocator, "clang");
try argv.append(context.my_allocator, "--no-default-config");
try argv.append_slice(context.my_allocator, cc_argv.slice());
const result = try clangMain(context.allocator, argv.slice());
if (result != 0) {
unreachable;
}
return;
} }
for (arguments) |arg| { if (mode == .link) {
try clang_args.append(context.my_allocator, span(arg)); assert(link_objects.length > 0);
try linker.link(context, .{
.backend = .lld,
.output_file_path = out_path orelse "a.out",
.objects = link_objects.slice(),
.libraries = link_libraries.slice(),
.extra_arguments = ld_argv.slice(),
.link_libc = true,
.link_libcpp = link_libcpp,
});
} }
const result = try clangMain(context.allocator, clang_args.slice()); // if (kind == .cpp) {
if (result != 0) { // try clang_args.append(context.my_allocator, "-nostdinc++");
unreachable; //
} // switch (@import("builtin").os.tag) {
// .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"),
// }
// }
//
// if (kind == .c or kind == .cpp) {
// try clang_args.append(context.my_allocator, "-nostdinc");
//
// switch (@import("builtin").os.tag) {
// .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, &.{
// "-iframework", "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks",
// "-isystem", try context.pathFromCompiler("lib/include"),
// "-isystem", "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include",
// });
// },
// else => @compileError("Operating system not supported"),
// }
// }
//
// 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));
// }
//
// const result = try clangMain(context.allocator, clang_args.slice());
// if (result != 0) {
// 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 }); // 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 });
@ -2230,7 +2717,7 @@ const musl_arch_files = [_][]const u8{
musl_lib_dir_relative_path ++ "src/unistd/x32/lseek.c", musl_lib_dir_relative_path ++ "src/unistd/x32/lseek.c",
}; };
fn argsCopyZ(alloc: Allocator, args: []const []const u8) ![:null]?[*:0]u8 { pub fn argsCopyZ(alloc: Allocator, args: []const []const u8) ![:null]?[*:0]u8 {
var argv = try alloc.allocSentinel(?[*:0]u8, args.len, null); var argv = try alloc.allocSentinel(?[*:0]u8, args.len, null);
for (args, 0..) |arg, i| { for (args, 0..) |arg, i| {
argv[i] = try alloc.dupeZ(u8, arg); // TODO If there was an argsAllocZ we could avoid this allocation. argv[i] = try alloc.dupeZ(u8, arg); // TODO If there was an argsAllocZ we could avoid this allocation.
@ -2246,7 +2733,7 @@ fn arMain(allocator: Allocator, arguments: []const []const u8) !u8 {
} }
extern "c" fn NativityClangMain(argc: c_int, argv: [*:null]?[*:0]u8) c_int; extern "c" fn NativityClangMain(argc: c_int, argv: [*:null]?[*:0]u8) c_int;
fn clangMain(allocator: Allocator, arguments: []const []const u8) !u8 { pub fn clangMain(allocator: Allocator, arguments: []const []const u8) !u8 {
const argv = try argsCopyZ(allocator, arguments); const argv = try argsCopyZ(allocator, arguments);
const exit_code = NativityClangMain(@as(c_int, @intCast(arguments.len)), argv.ptr); const exit_code = NativityClangMain(@as(c_int, @intCast(arguments.len)), argv.ptr);
return @as(u8, @bitCast(@as(i8, @truncate(exit_code)))); return @as(u8, @bitCast(@as(i8, @truncate(exit_code))));
@ -2272,7 +2759,7 @@ const Abi = enum {
musl, musl,
}; };
pub fn buildExecutable(context: *const Context, arguments: [][*:0]u8, options: ExecutableOptions) !void { pub fn buildExecutable(context: *const Context, arguments: []const []const u8, options: ExecutableOptions) !void {
var maybe_executable_path: ?[]const u8 = null; var maybe_executable_path: ?[]const u8 = null;
var maybe_main_package_path: ?[]const u8 = null; var maybe_main_package_path: ?[]const u8 = null;
var arch: Arch = undefined; var arch: Arch = undefined;
@ -2296,17 +2783,17 @@ pub fn buildExecutable(context: *const Context, arguments: [][*:0]u8, options: E
var maybe_only_parse: ?bool = null; var maybe_only_parse: ?bool = null;
var link_libc = false; var link_libc = false;
var maybe_executable_name: ?[]const u8 = null; var maybe_executable_name: ?[]const u8 = null;
var c_source_files = UnpinnedArray([*:0]u8){}; var c_source_files = UnpinnedArray([]const u8){};
const generate_debug_information = true; const generate_debug_information = true;
if (arguments.len == 0) return error.InvalidInput; if (arguments.len == 0) return error.InvalidInput;
var i: usize = 0; var i: usize = 0;
while (i < arguments.len) : (i += 1) { while (i < arguments.len) : (i += 1) {
const current_argument = span(arguments[i]); const current_argument = arguments[i];
if (byte_equal(current_argument, "-o")) { if (byte_equal(current_argument, "-o")) {
if (i + 1 != arguments.len) { if (i + 1 != arguments.len) {
maybe_executable_path = span(arguments[i + 1]); maybe_executable_path = arguments[i + 1];
assert(maybe_executable_path.?.len != 0); assert(maybe_executable_path.?.len != 0);
i += 1; i += 1;
} else { } else {
@ -2364,7 +2851,7 @@ pub fn buildExecutable(context: *const Context, arguments: [][*:0]u8, options: E
if (i + 1 != arguments.len) { if (i + 1 != arguments.len) {
i += 1; i += 1;
const arg = span(arguments[i]); const arg = arguments[i];
maybe_main_package_path = arg; maybe_main_package_path = arg;
maybe_only_parse = true; maybe_only_parse = true;
} else { } else {
@ -2374,7 +2861,7 @@ pub fn buildExecutable(context: *const Context, arguments: [][*:0]u8, options: E
if (i + 1 != arguments.len) { if (i + 1 != arguments.len) {
i += 1; i += 1;
const arg = span(arguments[i]); const arg = arguments[i];
if (byte_equal(arg, "true")) { if (byte_equal(arg, "true")) {
link_libc = true; link_libc = true;
} else if (byte_equal(arg, "false")) { } else if (byte_equal(arg, "false")) {
@ -2389,7 +2876,7 @@ pub fn buildExecutable(context: *const Context, arguments: [][*:0]u8, options: E
if (i + 1 != arguments.len) { if (i + 1 != arguments.len) {
i += 1; i += 1;
const arg = span(arguments[i]); const arg = arguments[i];
maybe_main_package_path = arg; maybe_main_package_path = arg;
} else { } else {
reportUnterminatedArgumentError(current_argument); reportUnterminatedArgumentError(current_argument);
@ -2398,7 +2885,7 @@ pub fn buildExecutable(context: *const Context, arguments: [][*:0]u8, options: E
if (i + 1 != arguments.len) { if (i + 1 != arguments.len) {
i += 1; i += 1;
const arg = span(arguments[i]); const arg = arguments[i];
maybe_executable_name = arg; maybe_executable_name = arg;
} else { } else {
reportUnterminatedArgumentError(current_argument); reportUnterminatedArgumentError(current_argument);
@ -2437,11 +2924,20 @@ pub fn buildExecutable(context: *const Context, arguments: [][*:0]u8, options: E
break :blk result; break :blk result;
}; };
const object_file_path = blk: {
const slice = try context.allocator.alloc(u8, executable_path.len + 2);
@memcpy(slice[0..executable_path.len], executable_path);
slice[executable_path.len] = '.';
slice[executable_path.len + 1] = 'o';
break :blk slice;
};
const unit = try context.allocator.create(Unit); const unit = try context.allocator.create(Unit);
unit.* = .{ unit.* = .{
.descriptor = .{ .descriptor = .{
.main_package_path = main_package_path, .main_package_path = main_package_path,
.executable_path = executable_path, .executable_path = executable_path,
.object_path = object_file_path,
.only_parse = only_parse, .only_parse = only_parse,
.arch = arch, .arch = arch,
.os = os, .os = os,
@ -2452,6 +2948,7 @@ pub fn buildExecutable(context: *const Context, arguments: [][*:0]u8, options: E
// .windows => link_libc, // .windows => link_libc,
// else => unreachable, // else => unreachable,
}, },
.link_libcpp = false,
.generate_debug_information = generate_debug_information, .generate_debug_information = generate_debug_information,
.name = executable_name, .name = executable_name,
.is_test = options.is_test, .is_test = options.is_test,
@ -14427,7 +14924,7 @@ pub const Unit = struct {
cc_type: Type.Index = .null, cc_type: Type.Index = .null,
test_function_type: Type.Index = .null, test_function_type: Type.Index = .null,
descriptor: Descriptor, descriptor: Descriptor,
object_files: UnpinnedArray([*:0]const u8) = .{}, // object_files: []const linker.Object,
discard_identifiers: usize = 0, discard_identifiers: usize = 0,
anon_i: usize = 0, anon_i: usize = 0,
anon_arr: usize = 0, anon_arr: usize = 0,
@ -15157,30 +15654,40 @@ pub const Unit = struct {
} }
if (!unit.descriptor.only_parse) { if (!unit.descriptor.only_parse) {
try unit.object_files.ensure_capacity(context.my_allocator, @intCast(unit.descriptor.c_source_files.len)); var object_files = try UnpinnedArray(linker.Object).initialize_with_capacity(context.my_allocator, @intCast(unit.descriptor.c_source_files.len + 1));
object_files.append_with_capacity(.{
.path = unit.descriptor.object_path,
});
for (unit.descriptor.c_source_files) |c_source_file| { for (unit.descriptor.c_source_files) |c_source_file| {
const c_src = span(c_source_file); const dot_index = data_structures.last_byte(c_source_file, '.') orelse unreachable;
const dot_index = data_structures.last(c_src, '.') orelse unreachable; const path_without_extension = c_source_file[0..dot_index];
const path_without_extension = c_src[0..dot_index];
const basename = std.fs.path.basename(path_without_extension); const basename = std.fs.path.basename(path_without_extension);
const o_file = try std.mem.concat(context.allocator, u8, &.{ basename, ".o" }); const o_file = try std.mem.concat(context.allocator, u8, &.{ basename, ".o" });
const basename_z = try std.mem.joinZ(context.allocator, "/", &.{ const object_path = try std.mem.concat(context.allocator, u8, &.{
"nat", "nat/",
o_file, o_file,
}); });
var c_flag = "-c".*;
var o_flag = "-o".*;
var g_flag = "-g".*;
var stack_protector = "-fno-stack-protector".*;
var arguments = [_][*:0]u8{ &c_flag, c_source_file, &o_flag, basename_z, &g_flag, &stack_protector }; var arguments = [_][]const u8{ "-c", c_source_file, "-o", object_path, "-g", "-fno-stack-protector"};
try compileCSourceFile(context, &arguments, .c); try compileCSourceFile(context, &arguments, .c);
unit.object_files.append_with_capacity(basename_z); object_files.append_with_capacity(.{
.path = object_path,
});
} }
try unit.analyze(context); try unit.analyze(context);
try llvm.codegen(unit, context); try llvm.codegen(unit, context);
try linker.link(context, .{
.output_file_path = unit.descriptor.executable_path,
.objects = object_files.slice(),
.libraries = &.{},
.link_libc = unit.descriptor.link_libc,
.link_libcpp = false,
.extra_arguments = &.{},
});
} }
} }
@ -15241,14 +15748,16 @@ pub const FixedKeyword = enum {
pub const Descriptor = struct { pub const Descriptor = struct {
main_package_path: []const u8, main_package_path: []const u8,
executable_path: []const u8, executable_path: []const u8,
object_path: []const u8,
arch: Arch, arch: Arch,
os: Os, os: Os,
abi: Abi, abi: Abi,
only_parse: bool, only_parse: bool,
link_libc: bool, link_libc: bool,
link_libcpp: bool,
is_test: bool, is_test: bool,
generate_debug_information: bool, generate_debug_information: bool,
c_source_files: []const [*:0]u8, c_source_files: []const []const u8,
name: []const u8, name: []const u8,
}; };

View File

@ -3173,118 +3173,121 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo
const object_file_path = slice[0 .. slice.len - 1 :0]; const object_file_path = slice[0 .. slice.len - 1 :0];
break :blk object_file_path; break :blk object_file_path;
}; };
const destination_file_path = blk: { // const destination_file_path = blk: {
const slice = try context.allocator.alloc(u8, file_path.len + 1); // try std.mem.concatWithSentinel(context.allocator, &.{file_path}); // const slice = try context.allocator.alloc(u8, file_path.len + 1); // try std.mem.concatWithSentinel(context.allocator, &.{file_path});
@memcpy(slice[0..file_path.len], file_path); // @memcpy(slice[0..file_path.len], file_path);
slice[slice.len - 1] = 0; // slice[slice.len - 1] = 0;
const destination_file_path = slice[0..file_path.len :0]; // const destination_file_path = slice[0..file_path.len :0];
break :blk destination_file_path; // break :blk destination_file_path;
}; // };
// _ = destination_file_path; // autofix
const disable_verify = false; const disable_verify = false;
const result = llvm.module.addPassesToEmitFile(target_machine, object_file_path.ptr, object_file_path.len, LLVM.CodeGenFileType.object, disable_verify); const result = llvm.module.addPassesToEmitFile(target_machine, object_file_path.ptr, object_file_path.len, LLVM.CodeGenFileType.object, disable_verify);
if (!result) { if (!result) {
@panic("can't generate machine code"); @panic("can't generate machine code");
} }
const format: Format = switch (unit.descriptor.os) { // const format: Format = switch (unit.descriptor.os) {
// .windows => .coff, // // .windows => .coff,
.macos => .macho, // .macos => .macho,
.linux => .elf, // .linux => .elf,
// else => unreachable, // // else => unreachable,
}; // };
const driver_program = switch (format) { // const driver_program = switch (format) {
.coff => "lld-link", // .coff => "lld-link",
.elf => "ld.lld", // .elf => "ld.lld",
.macho => "ld64.lld", // .macho => "ld64.lld",
}; // };
var arguments = UnpinnedArray([*:0]const u8){}; // _ = driver_program; // autofix
try arguments.append(context.my_allocator, driver_program);
try arguments.append(context.my_allocator, "--error-limit=0"); // var arguments = UnpinnedArray([]const u8){};
// try arguments.append(context.my_allocator, driver_program);
try arguments.append(context.my_allocator, "-o"); //
try arguments.append(context.my_allocator, destination_file_path.ptr); // try arguments.append(context.my_allocator, "--error-limit=0");
//
try arguments.append(context.my_allocator, object_file_path.ptr); // try arguments.append(context.my_allocator, "-o");
// try arguments.append(context.my_allocator, destination_file_path.ptr);
try arguments.append_slice(context.my_allocator, unit.object_files.slice()); //
// for (unit.object_files.slice()) |object_file| { // try arguments.append(context.my_allocator, object_file_path.ptr);
// _ = object_file; // autofix //
// try arguments.append_slice(context.my_allocator, unit.object_files.slice());
// // for (unit.object_files.slice()) |object_file| {
// // _ = object_file; // autofix
// // }
//
// switch (unit.descriptor.os) {
// .macos => {
// try arguments.append(context.my_allocator, "-dynamic");
// try arguments.append_slice(context.my_allocator, &.{ "-platform_version", "macos", "13.4.1", "13.3" });
// try arguments.append(context.my_allocator, "-arch");
// try arguments.append(context.my_allocator, switch (unit.descriptor.arch) {
// .aarch64 => "arm64",
// else => |t| @panic(@tagName(t)),
// });
// try arguments.append_slice(context.my_allocator, &.{ "-syslibroot", "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk" });
// try arguments.append_slice(context.my_allocator, &.{ "-e", "_main" });
// try arguments.append(context.my_allocator, "-lSystem");
// },
// .linux => {
// try arguments.append_slice(context.my_allocator, &.{ "--entry", "_start" });
// try arguments.append(context.my_allocator, "-m");
// try arguments.append(context.my_allocator, switch (unit.descriptor.arch) {
// .x86_64 => "elf_x86_64",
// else => |t| @panic(@tagName(t)),
// });
//
// if (unit.descriptor.link_libc) {
// try arguments.append(context.my_allocator, "/usr/lib/crt1.o");
// try arguments.append(context.my_allocator, "/usr/lib/crti.o");
// try arguments.append_slice(context.my_allocator, &.{ "-L", "/usr/lib" });
// try arguments.append_slice(context.my_allocator, &.{ "-dynamic-linker", "/lib64/ld-linux-x86-64.so.2" });
// try arguments.append(context.my_allocator, "--as-needed");
// try arguments.append(context.my_allocator, "-lm");
// try arguments.append(context.my_allocator, "-lpthread");
// try arguments.append(context.my_allocator, "-lc");
// try arguments.append(context.my_allocator, "-ldl");
// try arguments.append(context.my_allocator, "-lrt");
// try arguments.append(context.my_allocator, "-lutil");
// try arguments.append(context.my_allocator, "/usr/lib/crtn.o");
// }
//
// // if (unit.descriptor.link_libc) {
// // try arguments.append_slice(context.allocator, &.{ "-lc" });
// // }
// },
// // .windows => {},
// // else => |t| @panic(@tagName(t)),
// }
//
// var stdout_ptr: [*]const u8 = undefined;
// var stdout_len: usize = 0;
// var stderr_ptr: [*]const u8 = undefined;
// var stderr_len: usize = 0;
//
// const linking_result = switch (format) {
// .elf => bindings.NativityLLDLinkELF(arguments.pointer, arguments.length, &stdout_ptr, &stdout_len, &stderr_ptr, &stderr_len),
// .coff => bindings.NativityLLDLinkCOFF(arguments.pointer, arguments.length, &stdout_ptr, &stdout_len, &stderr_ptr, &stderr_len),
// .macho => bindings.NativityLLDLinkMachO(arguments.pointer, arguments.length, &stdout_ptr, &stdout_len, &stderr_ptr, &stderr_len),
// };
//
// if (stdout_len > 0) {
// // std.debug.print("{s}\n", .{stdout_ptr[0..stdout_len]});
// }
//
// if (stderr_len > 0) {
// // std.debug.print("{s}\n", .{stderr_ptr[0..stderr_len]});
// }
//
// if (!linking_result) {
// try write(.panic, "\n");
// for (arguments.slice()) |argument| {
// const arg = data_structures.span(argument);
// try write(.panic, arg);
// try write(.panic, " ");
// }
// try write(.panic, "\n");
//
// @panic(stderr_ptr[0..stderr_len]);
// } // }
switch (unit.descriptor.os) {
.macos => {
try arguments.append(context.my_allocator, "-dynamic");
try arguments.append_slice(context.my_allocator, &.{ "-platform_version", "macos", "13.4.1", "13.3" });
try arguments.append(context.my_allocator, "-arch");
try arguments.append(context.my_allocator, switch (unit.descriptor.arch) {
.aarch64 => "arm64",
else => |t| @panic(@tagName(t)),
});
try arguments.append_slice(context.my_allocator, &.{ "-syslibroot", "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk" });
try arguments.append_slice(context.my_allocator, &.{ "-e", "_main" });
try arguments.append(context.my_allocator, "-lSystem");
},
.linux => {
try arguments.append_slice(context.my_allocator, &.{ "--entry", "_start" });
try arguments.append(context.my_allocator, "-m");
try arguments.append(context.my_allocator, switch (unit.descriptor.arch) {
.x86_64 => "elf_x86_64",
else => |t| @panic(@tagName(t)),
});
if (unit.descriptor.link_libc) {
try arguments.append(context.my_allocator, "/usr/lib/crt1.o");
try arguments.append(context.my_allocator, "/usr/lib/crti.o");
try arguments.append_slice(context.my_allocator, &.{ "-L", "/usr/lib" });
try arguments.append_slice(context.my_allocator, &.{ "-dynamic-linker", "/lib64/ld-linux-x86-64.so.2" });
try arguments.append(context.my_allocator, "--as-needed");
try arguments.append(context.my_allocator, "-lm");
try arguments.append(context.my_allocator, "-lpthread");
try arguments.append(context.my_allocator, "-lc");
try arguments.append(context.my_allocator, "-ldl");
try arguments.append(context.my_allocator, "-lrt");
try arguments.append(context.my_allocator, "-lutil");
try arguments.append(context.my_allocator, "/usr/lib/crtn.o");
}
// if (unit.descriptor.link_libc) {
// try arguments.append_slice(context.allocator, &.{ "-lc" });
// }
},
// .windows => {},
// else => |t| @panic(@tagName(t)),
}
var stdout_ptr: [*]const u8 = undefined;
var stdout_len: usize = 0;
var stderr_ptr: [*]const u8 = undefined;
var stderr_len: usize = 0;
const linking_result = switch (format) {
.elf => bindings.NativityLLDLinkELF(arguments.pointer, arguments.length, &stdout_ptr, &stdout_len, &stderr_ptr, &stderr_len),
.coff => bindings.NativityLLDLinkCOFF(arguments.pointer, arguments.length, &stdout_ptr, &stdout_len, &stderr_ptr, &stderr_len),
.macho => bindings.NativityLLDLinkMachO(arguments.pointer, arguments.length, &stdout_ptr, &stdout_len, &stderr_ptr, &stderr_len),
};
if (stdout_len > 0) {
// std.debug.print("{s}\n", .{stdout_ptr[0..stdout_len]});
}
if (stderr_len > 0) {
// std.debug.print("{s}\n", .{stderr_ptr[0..stderr_len]});
}
if (!linking_result) {
try write(.panic, "\n");
for (arguments.slice()) |argument| {
const arg = data_structures.span(argument);
try write(.panic, arg);
try write(.panic, " ");
}
try write(.panic, "\n");
@panic(stderr_ptr[0..stderr_len]);
}
} }

View File

@ -152,7 +152,3 @@ pub extern fn NativityLLVMModuleSetTargetMachineDataLayout(module: *LLVM.Module,
pub extern fn NativityLLVMModuleSetTargetTriple(module: *LLVM.Module, target_triple_ptr: [*]const u8, target_triple_len: usize) void; pub extern fn NativityLLVMModuleSetTargetTriple(module: *LLVM.Module, target_triple_ptr: [*]const u8, target_triple_len: usize) void;
pub extern fn NativityLLVMModuleAddPassesToEmitFile(module: *LLVM.Module, target_machine: *LLVM.Target.Machine, object_file_path_ptr: [*]const u8, object_file_path_len: usize, codegen_file_type: LLVM.CodeGenFileType, disable_verify: bool) bool; pub extern fn NativityLLVMModuleAddPassesToEmitFile(module: *LLVM.Module, target_machine: *LLVM.Target.Machine, object_file_path_ptr: [*]const u8, object_file_path_len: usize, codegen_file_type: LLVM.CodeGenFileType, disable_verify: bool) bool;
pub extern fn NativityLLVMTypeAssertEqual(a: *LLVM.Type, b: *LLVM.Type) void; pub extern fn NativityLLVMTypeAssertEqual(a: *LLVM.Type, b: *LLVM.Type) void;
pub extern fn NativityLLDLinkELF(argument_ptr: [*]const [*:0]const u8, argument_count: usize, stdout_ptr: *[*]const u8, stdout_len: *usize, stderr_ptr: *[*]const u8, stderr_len: *usize) bool;
pub extern fn NativityLLDLinkCOFF(argument_ptr: [*]const [*:0]const u8, argument_count: usize, stdout_ptr: *[*]const u8, stdout_len: *usize, stderr_ptr: *[*]const u8, stderr_len: *usize) bool;
pub extern fn NativityLLDLinkMachO(argument_ptr: [*]const [*:0]const u8, argument_count: usize, stdout_ptr: *[*]const u8, stdout_len: *usize, stderr_ptr: *[*]const u8, stderr_len: *usize) bool;
pub extern fn NativityLLDLinkWasm(argument_ptr: [*]const [*:0]const u8, argument_count: usize, stdout_ptr: *[*]const u8, stdout_len: *usize, stderr_ptr: *[*]const u8, stderr_len: *usize) bool;

View File

@ -724,7 +724,53 @@ pub fn span(ptr: [*:0]const u8) [:0]const u8 {
return ptr[0..len :0]; return ptr[0..len :0];
} }
pub fn last(bytes: []const u8, byte: u8) ?usize { pub fn starts_with_slice(bytes: []const u8, slice: []const u8) bool {
if (slice.len <= bytes.len) {
if (byte_equal(bytes[0..slice.len], slice)) {
return true;
}
}
return false;
}
pub fn ends_with_slice(bytes: []const u8, slice: []const u8) bool {
if (slice.len <= bytes.len) {
if (byte_equal(bytes[bytes.len - slice.len..], slice)) {
return true;
}
}
return false;
}
pub fn first_byte(bytes: []const u8, byte: u8) ?usize {
for (bytes, 0..) |b, i| {
if (b == byte) {
return i;
}
}
return null;
}
pub fn first_slice(bytes: []const u8, slice: []const u8) ?usize {
if (slice.len <= bytes.len) {
const top = bytes.len - slice.len;
var i: usize = 0;
while (i < top) : (i += 1) {
const chunk = bytes[i..][0..slice.len];
if (byte_equal(chunk, slice)) {
return i;
}
}
}
return null;
}
pub fn last_byte(bytes: []const u8, byte: u8) ?usize {
var i = bytes.len; var i = bytes.len;
while (i > 0) { while (i > 0) {
i -= 1; i -= 1;

View File

@ -0,0 +1,30 @@
const Compilation = @import("../Compilation.zig");
const Context = Compilation.Context;
const lld = @import("lld.zig");
pub const Options = struct{
backend: Backend = .lld,
output_file_path: []const u8,
objects: []const Object,
libraries: []const Library,
extra_arguments: []const []const u8,
link_libc: bool,
link_libcpp: bool,
};
const Backend = enum{
lld,
};
pub const Object = struct{
path: []const u8,
};
pub const Library = struct{
path: []const u8,
};
pub fn link(context: *const Context, options: Options) !void {
switch (options.backend) {
.lld => try lld.link(context, options),
}
}

126
bootstrap/linker/lld.zig Normal file
View File

@ -0,0 +1,126 @@
const std = @import("std");
const assert = std.debug.assert;
const linker = @import("linker.zig");
const library = @import("../library.zig");
const UnpinnedArray = library.UnpinnedArray;
const Compilation = @import("../Compilation.zig");
const write = Compilation.write;
pub fn link(context: *const Compilation.Context, options: linker.Options) !void {
assert(options.backend == .lld);
var argv = UnpinnedArray([]const u8){};
const driver_program = switch (@import("builtin").os.tag) {
.windows => "lld-link",
.linux => "ld.lld",
.macos => "ld64.lld",
else => @compileError("OS not supported"),
};
try argv.append(context.my_allocator, driver_program);
try argv.append(context.my_allocator, "--error-limit=0");
// const output_path = out_path orelse "a.out";
try argv.append(context.my_allocator, "-o");
const is_dylib = library.ends_with_slice(options.output_file_path, ".dylib");
try argv.append(context.my_allocator, options.output_file_path);
if (library.byte_equal(options.output_file_path, "lib/LLVMHello.dylib")) {
assert(is_dylib);
}
try argv.append_slice(context.my_allocator, options.extra_arguments);
for (options.objects) |object| {
try argv.append(context.my_allocator, object.path);
}
switch (@import("builtin").os.tag) {
.macos => {
try argv.append(context.my_allocator, "-dynamic");
try argv.append_slice(context.my_allocator, &.{ "-platform_version", "macos", "13.4.1", "13.3" });
try argv.append(context.my_allocator, "-arch");
try argv.append(context.my_allocator, switch (@import("builtin").cpu.arch) {
.aarch64 => "arm64",
else => |t| @panic(@tagName(t)),
});
try argv.append_slice(context.my_allocator, &.{ "-syslibroot", "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk" });
if (!library.ends_with_slice(options.output_file_path, ".dylib")) {
try argv.append_slice(context.my_allocator, &.{ "-e", "_main" });
}
try argv.append(context.my_allocator, "-lSystem");
if (options.link_libcpp) {
try argv.append(context.my_allocator, "-L/Library/Developer/CommandLineTools/SDKs/MacOSX13.3.sdk/usr/lib");
try argv.append(context.my_allocator, "-lc++");
}
},
.linux => {
if (options.link_libcpp) {
assert(options.link_libc);
try argv.append(context.my_allocator, "/usr/lib/libstdc++.so" );
}
if (options.link_libc) {
try argv.append(context.my_allocator, "/usr/lib/crt1.o");
try argv.append(context.my_allocator, "/usr/lib/crti.o");
try argv.append_slice(context.my_allocator, &.{ "-L", "/usr/lib" });
try argv.append_slice(context.my_allocator, &.{ "-dynamic-linker", "/lib64/ld-linux-x86-64.so.2" });
try argv.append(context.my_allocator, "--as-needed");
try argv.append(context.my_allocator, "-lm");
try argv.append(context.my_allocator, "-lpthread");
try argv.append(context.my_allocator, "-lc");
try argv.append(context.my_allocator, "-ldl");
try argv.append(context.my_allocator, "-lrt");
try argv.append(context.my_allocator, "-lutil");
try argv.append(context.my_allocator, "/usr/lib/crtn.o");
}
},
else => @compileError("OS not supported"),
}
for (options.libraries) |lib| {
try argv.append(context.my_allocator, try std.mem.concat(context.allocator, u8, &.{"-l", lib.path}));
}
const argv_zero_terminated = try Compilation.argsCopyZ(context.allocator, argv.slice());
var stdout_ptr: [*]const u8 = undefined;
var stdout_len: usize = 0;
var stderr_ptr: [*]const u8 = undefined;
var stderr_len: usize = 0;
const result = switch (@import("builtin").os.tag) {
.linux => NativityLLDLinkELF (argv_zero_terminated.ptr, argv_zero_terminated.len, &stdout_ptr, &stdout_len, &stderr_ptr, &stderr_len),
.macos => NativityLLDLinkMachO (argv_zero_terminated.ptr, argv_zero_terminated.len, &stdout_ptr, &stdout_len, &stderr_ptr, &stderr_len),
.windows => NativityLLDLinkCOFF(argv_zero_terminated.ptr, argv_zero_terminated.len, &stdout_ptr, &stdout_len, &stderr_ptr, &stderr_len),
else => @compileError("OS not supported"),
};
if (!result) {
const stdout = stdout_ptr[0..stdout_len];
const stderr = stderr_ptr[0..stderr_len];
for (argv.slice()) |arg| {
try write(.panic, arg);
try write(.panic, " ");
}
try write(.panic, "\n");
if (stdout.len > 0) {
try write(.panic, stdout);
try write(.panic, "\n");
}
if (stderr.len > 0) {
try write(.panic, stderr);
try write(.panic, "\n");
}
@panic("Linking with LLD failed");
}
}
extern fn NativityLLDLinkELF(argument_ptr: [*:null]?[*:0]u8, argument_count: usize, stdout_ptr: *[*]const u8, stdout_len: *usize, stderr_ptr: *[*]const u8, stderr_len: *usize) bool;
extern fn NativityLLDLinkCOFF(argument_ptr: [*:null]?[*:0]u8, argument_count: usize, stdout_ptr: *[*]const u8, stdout_len: *usize, stderr_ptr: *[*]const u8, stderr_len: *usize) bool;
extern fn NativityLLDLinkMachO(argument_ptr: [*:null]?[*:0]u8, argument_count: usize, stdout_ptr: *[*]const u8, stdout_len: *usize, stderr_ptr: *[*]const u8, stderr_len: *usize) bool;
extern fn NativityLLDLinkWasm(argument_ptr: [*:null]?[*:0]u8, argument_count: usize, stdout_ptr: *[*]const u8, stdout_len: *usize, stderr_ptr: *[*]const u8, stderr_len: *usize) bool;

View File

@ -1,5 +1,6 @@
const std = @import("std"); const std = @import("std");
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
const assert = std.debug.assert;
const Compilation = @import("Compilation.zig"); const Compilation = @import("Compilation.zig");
pub const panic = Compilation.panic; pub const panic = Compilation.panic;
@ -21,35 +22,53 @@ fn todo() noreturn {
} }
var my_allocator = PageAllocator{}; var my_allocator = PageAllocator{};
pub export fn main(c_argc: c_int, c_argv: [*][*:0]c_char, c_envp: [*:null]?[*:0]c_char) callconv(.C) c_int { // pub export fn main(c_argc: c_int, c_argv: [*][*:0]c_char, c_envp: [*:null]?[*:0]c_char) callconv(.C) c_int {
_ = c_envp; // autofix // _ = c_envp; // autofix
const argument_count: usize = @intCast(c_argc); // // const argument_count: usize = @intCast(c_argc);
const argument_values: [*][*:0]u8 = @ptrCast(c_argv); // // const argument_values: [*][*:0]u8 = @ptrCast(c_argv);
const arguments = argument_values[0..argument_count]; // if (entry_point(arguments)) |_| {
if (entry_point(arguments)) |_| { // return 0;
return 0; // } else |err| {
} else |err| { // const print_stack_trace = @import("configuration").print_stack_trace;
const print_stack_trace = @import("configuration").print_stack_trace; // switch (print_stack_trace) {
switch (print_stack_trace) { // true => if (@errorReturnTrace()) |trace| {
true => if (@errorReturnTrace()) |trace| { // std.debug.dumpStackTrace(trace.*);
std.debug.dumpStackTrace(trace.*); // },
}, // false => {
false => { // const error_name: []const u8 = @errorName(err);
const error_name: []const u8 = @errorName(err); // Compilation.write(.panic, "Error: ") catch {};
Compilation.write(.panic, "Error: ") catch {}; // Compilation.write(.panic, error_name) catch {};
Compilation.write(.panic, error_name) catch {}; // Compilation.write(.panic, "\n") catch {};
Compilation.write(.panic, "\n") catch {}; // },
}, // }
} //
// return 1;
// }
// }
return 1; pub fn main() !void {
}
}
pub fn entry_point(arguments: [][*:0]u8) !void {
var arena_allocator = std.heap.ArenaAllocator.init(std.heap.page_allocator); var arena_allocator = std.heap.ArenaAllocator.init(std.heap.page_allocator);
const allocator = arena_allocator.allocator(); const allocator = arena_allocator.allocator();
// const arguments = try std.process.argsAlloc(allocator); var arg_it = std.process.ArgIterator.init();
var args = library.UnpinnedArray([]const u8){};
const context = try Compilation.createContext(allocator, &my_allocator.allocator);
while (arg_it.next()) |arg| {
try args.append(context.my_allocator, arg);
}
const arguments = args.slice();
const debug_args = true;
if (debug_args) {
assert(arguments.len > 0);
const home_dir = std.posix.getenv("HOME") orelse unreachable;
const timestamp = std.time.milliTimestamp();
var argument_list = std.ArrayList(u8).init(std.heap.page_allocator);
for (arguments) |arg| {
argument_list.appendSlice(arg) catch {};
argument_list.append(' ') catch {};
}
argument_list.append('\n') catch {};
std.fs.cwd().writeFile(std.fmt.allocPrint(std.heap.page_allocator, "{s}/dev/nativity/nat/invocation_log_{}", .{home_dir, timestamp}) catch unreachable, argument_list.items) catch {};
}
if (arguments.len <= 1) { if (arguments.len <= 1) {
return error.InvalidInput; return error.InvalidInput;
@ -59,15 +78,14 @@ pub fn entry_point(arguments: [][*:0]u8) !void {
todo(); todo();
} }
const command = library.span(arguments[1]); const command = arguments[1];
const command_arguments = arguments[2..]; const command_arguments = arguments[2..];
const context = try Compilation.createContext(allocator, &my_allocator.allocator);
if (byte_equal(command, "build")) { if (byte_equal(command, "build")) {
try Compilation.compileBuildExecutable(context, command_arguments); try Compilation.compileBuildExecutable(context, command_arguments);
} else if (byte_equal(command, "clang") or byte_equal(command, "-cc1") or byte_equal(command, "-cc1as")) { } else if (byte_equal(command, "clang") or byte_equal(command, "-cc1") or byte_equal(command, "-cc1as")) {
// const exit_code = try clangMain(allocator, arguments); const exit_code = try Compilation.clangMain(allocator, arguments);
// std.process.exit(exit_code); std.process.exit(exit_code);
} else if (byte_equal(command, "cc")) { } else if (byte_equal(command, "cc")) {
try Compilation.compileCSourceFile(context, command_arguments, .c); try Compilation.compileCSourceFile(context, command_arguments, .c);
} else if (byte_equal(command, "c++")) { } else if (byte_equal(command, "c++")) {
@ -88,3 +106,7 @@ pub fn entry_point(arguments: [][*:0]u8) !void {
todo(); todo();
} }
} }
pub const std_options = std.Options{
.enable_segfault_handler = false,
};

View File

@ -353,10 +353,10 @@ fn runStdTests(allocator: Allocator) !void {
if (errors) return error.fail; if (errors) return error.fail;
} }
fn runCmakeTests(allocator: Allocator) !void { fn runCmakeTests(allocator: Allocator, dir_path: []const u8) !void {
var errors = false; var errors = false;
const original_dir = try std.fs.cwd().realpathAlloc(allocator, "."); const original_dir = try std.fs.cwd().realpathAlloc(allocator, ".");
const cc_dir = try std.fs.cwd().openDir("test/cc", .{ const cc_dir = try std.fs.cwd().openDir(dir_path, .{
.iterate = true, .iterate = true,
}); });
@ -379,8 +379,10 @@ fn runCmakeTests(allocator: Allocator) !void {
.argv = &.{ .argv = &.{
"cmake", "cmake",
"..", "..",
"-G", "Unix Makefiles", // "--debug-trycompile",
"-DCMAKE_VERBOSE_MAKEFILE=On", // "--debug-output",
// "-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_C_COMPILER=", "nat;cc" }),
try std.mem.concat(allocator, u8, &.{ "-DCMAKE_CXX_COMPILER=", "nat;c++" }), try std.mem.concat(allocator, u8, &.{ "-DCMAKE_CXX_COMPILER=", "nat;c++" }),
try std.mem.concat(allocator, u8, &.{ "-DCMAKE_ASM_COMPILER=", "nat;cc" }), try std.mem.concat(allocator, u8, &.{ "-DCMAKE_ASM_COMPILER=", "nat;cc" }),
@ -399,13 +401,11 @@ fn runCmakeTests(allocator: Allocator) !void {
break :b false; break :b false;
}; };
if (!cmake_success) { if (cmake.stdout.len > 0) {
if (cmake.stdout.len > 0) { std.debug.print("STDOUT:\n\n{s}\n\n", .{cmake.stdout});
std.debug.print("STDOUT:\n\n{s}\n\n", .{cmake.stdout}); }
} if (cmake.stderr.len > 0) {
if (cmake.stderr.len > 0) { std.debug.print("STDERR:\n\n{s}\n\n", .{cmake.stderr});
std.debug.print("STDERR:\n\n{s}\n\n", .{cmake.stderr});
}
} }
var success = cmake_success; var success = cmake_success;
@ -414,10 +414,10 @@ fn runCmakeTests(allocator: Allocator) !void {
.allocator = allocator, .allocator = allocator,
// TODO: delete -main_source_file? // TODO: delete -main_source_file?
.argv = &.{ .argv = &.{
"make" "ninja"
}, },
.max_output_bytes = std.math.maxInt(u64), .max_output_bytes = std.math.maxInt(u64),
}); });
const ninja_result: TestError!bool = switch (ninja.term) { const ninja_result: TestError!bool = switch (ninja.term) {
.Exited => |exit_code| if (exit_code == 0) true else error.abnormal_exit_code, .Exited => |exit_code| if (exit_code == 0) true else error.abnormal_exit_code,
.Signal => error.signaled, .Signal => error.signaled,
@ -429,6 +429,7 @@ fn runCmakeTests(allocator: Allocator) !void {
errors = true; errors = true;
break :b false; break :b false;
}; };
if (!ninja_success) { if (!ninja_success) {
if (ninja.stdout.len > 0) { if (ninja.stdout.len > 0) {
std.debug.print("STDOUT:\n\n{s}\n\n", .{ninja.stdout}); std.debug.print("STDOUT:\n\n{s}\n\n", .{ninja.stdout});
@ -508,15 +509,25 @@ pub fn main() !void {
}) catch { }) catch {
errors = true; errors = true;
}; };
//
runStdTests(allocator) catch { runStdTests(allocator) catch {
errors = true; errors = true;
}; };
runCmakeTests(allocator, "test/cc") catch {
errors = true;
};
runCmakeTests(allocator, "test/c++") catch {
errors = true;
};
switch (@import("builtin").os.tag) { switch (@import("builtin").os.tag) {
.macos => {}, .macos => {},
// .macos => {},
.linux => switch (@import("builtin").abi) { .linux => switch (@import("builtin").abi) {
.gnu => try runCmakeTests(allocator), .gnu => runCmakeTests(allocator, "test/cc_linux") catch {
errors = true;
},
.musl => {}, .musl => {},
else => @compileError("ABI not supported"), else => @compileError("ABI not supported"),
}, },

View File

@ -0,0 +1,6 @@
cmake_minimum_required(VERSION 3.15)
project(cpp_first CXX)
include(CMakePrintHelpers)
cmake_print_variables(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES)
cmake_print_variables(CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES)
add_executable(cpp_first main.cpp)

View File

@ -1,3 +1,6 @@
cmake_minimum_required(VERSION 3.15) cmake_minimum_required(VERSION 3.15)
project(c_first C) project(c_first C)
include(CMakePrintHelpers)
cmake_print_variables(CMAKE_C_IMPLICIT_LINK_LIBRARIES)
cmake_print_variables(CMAKE_C_IMPLICIT_LINK_DIRECTORIES)
add_executable(c_first main.c) add_executable(c_first main.c)

View File

@ -1,3 +0,0 @@
cmake_minimum_required(VERSION 3.15)
project(cpp_first CXX)
add_executable(cpp_first main.cpp)

2
test/cc_linux/c_asm/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*.o
build/

View File

@ -0,0 +1,3 @@
cmake_minimum_required(VERSION 3.15)
project(c_asm C ASM)
add_executable(c_asm main.c assembly.S)

View File

@ -0,0 +1,4 @@
.global foo
foo:
mov $42, %eax
ret

View File

@ -0,0 +1,7 @@
extern int foo();
#include <assert.h>
int main()
{
assert(foo() == 42);
return 0;
}