Merge pull request #89 from birth-software/more-apple-support

Pass all tests on Apple M1
This commit is contained in:
David 2024-02-20 19:56:43 -06:00 committed by GitHub
commit 38f6b3c1ab
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 1064 additions and 295 deletions

2
.vscode/launch.json vendored
View File

@ -12,7 +12,7 @@
"args": [
"exe",
"-main_source_file",
"test/standalone/first/main.nat"
"test/standalone/hello_world/main.nat"
],
"cwd": "${workspaceFolder}",
},

File diff suppressed because it is too large Load Diff

View File

@ -32,6 +32,7 @@ pub const LLVM = struct {
debug_type_map: AutoHashMap(Compilation.Type.Index, *LLVM.DebugInfo.Type) = .{},
type_name_map: AutoHashMap(Compilation.Type.Index, []const u8) = .{},
type_map: AutoHashMap(Compilation.Type.Index, *LLVM.Type) = .{},
function_declaration_map: AutoArrayHashMap(*Compilation.Debug.Declaration.Global, *LLVM.Value.Constant.Function) = .{},
function_definition_map: AutoArrayHashMap(*Compilation.Debug.Declaration.Global, *LLVM.Value.Constant.Function) = .{},
llvm_instruction_map: AutoHashMap(Compilation.Instruction.Index, *LLVM.Value) = .{},
llvm_value_map: AutoArrayHashMap(Compilation.V, *LLVM.Value) = .{},
@ -47,7 +48,7 @@ pub const LLVM = struct {
return_phi_node: ?*LLVM.Value.Instruction.PhiNode = null,
scope: *LLVM.DebugInfo.Scope = undefined,
file: *LLVM.DebugInfo.File = undefined,
subprogram: *LLVM.DebugInfo.Subprogram = undefined,
// subprogram: *LLVM.DebugInfo.Subprogram = undefined,
arg_index: u32 = 0,
tag_count: c_uint = 0,
inside_branch: bool = false,
@ -1281,13 +1282,13 @@ pub const LLVM = struct {
}
fn renderTypeName(llvm: *LLVM, unit: *Compilation.Unit, context: *const Compilation.Context, sema_type_index: Compilation.Type.Index) ![]const u8 {
const gop = try llvm.type_name_map.getOrPut(context.allocator, sema_type_index);
if (gop.found_existing) {
return gop.value_ptr.*;
if (llvm.type_name_map.get(sema_type_index)) |result| {
return result;
} else {
if (unit.type_declarations.get(sema_type_index)) |global_declaration| {
gop.value_ptr.* = unit.getIdentifier(global_declaration.declaration.name);
return gop.value_ptr.*;
const result = unit.getIdentifier(global_declaration.declaration.name);
try llvm.type_name_map.putNoClobber(context.allocator, sema_type_index, result);
return result;
} else {
const sema_type = unit.types.get(sema_type_index);
const result: []const u8 = switch (sema_type.*) {
@ -2241,6 +2242,114 @@ pub const LLVM = struct {
const call = llvm.builder.createCall(intrinsic_type, intrinsic_function.toValue(), intrinsic_arguments.ptr, intrinsic_arguments.len, name.ptr, name.len, null) orelse return LLVM.Value.Instruction.Error.call;
return call.toValue();
}
fn emitFunctionDeclaration(llvm: *LLVM, unit: *Compilation.Unit, context: *const Compilation.Context, declaration: *Compilation.Debug.Declaration.Global) !void {
const function_type = try llvm.getType(unit, context, declaration.declaration.type);
const is_export = declaration.attributes.contains(.@"export");
const is_extern = declaration.attributes.contains(.@"extern");
const export_or_extern = is_export or is_extern;
const linkage: LLVM.Linkage = switch (export_or_extern) {
true => .@"extern",
false => .internal,
};
// TODO: Check name collision
const mangle_name = !export_or_extern;
_ = mangle_name; // autofix
const name = unit.getIdentifier(declaration.declaration.name);
const function = llvm.module.createFunction(function_type.toFunction() orelse unreachable, linkage, address_space, name.ptr, name.len) orelse return Error.function;
const function_prototype = unit.function_prototypes.get(unit.types.get(declaration.declaration.type).function);
switch (unit.types.get(function_prototype.return_type).*) {
.noreturn => {
function.addAttributeKey(.NoReturn);
},
else => {},
}
if (function_prototype.attributes.naked) {
function.addAttributeKey(.Naked);
}
const calling_convention = getCallingConvention(function_prototype.calling_convention);
function.setCallingConvention(calling_convention);
switch (declaration.initial_value) {
.function_declaration => try llvm.function_declaration_map.putNoClobber(context.allocator, declaration, function),
.function_definition => try llvm.function_definition_map.putNoClobber(context.allocator, declaration, function),
else => unreachable,
}
if (unit.descriptor.generate_debug_information) {
const debug_file = try llvm.getDebugInfoFile(unit, context, declaration.declaration.scope.file);
var parameter_types = try ArrayList(*LLVM.DebugInfo.Type).initCapacity(context.allocator, function_prototype.argument_types.len);
for (function_prototype.argument_types) |argument_type_index| {
const argument_type = try llvm.getDebugType(unit, context, argument_type_index);
parameter_types.appendAssumeCapacity(argument_type);
}
const subroutine_type_flags = LLVM.DebugInfo.Node.Flags{
.visibility = .none,
.forward_declaration = is_extern,
.apple_block = false,
.block_by_ref_struct = false,
.virtual = false,
.artificial = false,
.explicit = false,
.prototyped = false,
.objective_c_class_complete = false,
.object_pointer = false,
.vector = false,
.static_member = false,
.lvalue_reference = false,
.rvalue_reference = false,
.reserved = false,
.inheritance = .none,
.introduced_virtual = false,
.bit_field = false,
.no_return = false,
.type_pass_by_value = false,
.type_pass_by_reference = false,
.enum_class = false,
.thunk = false,
.non_trivial = false,
.big_endian = false,
.little_endian = false,
.all_calls_described = false,
};
const subroutine_type_calling_convention = LLVM.DebugInfo.CallingConvention.none;
const subroutine_type = llvm.debug_info_builder.createSubroutineType(parameter_types.items.ptr, parameter_types.items.len, subroutine_type_flags, subroutine_type_calling_convention) orelse unreachable;
const scope_line = 0;
const subprogram_flags = LLVM.DebugInfo.Subprogram.Flags{
.virtuality = .none,
.local_to_unit = !export_or_extern,
.definition = !is_extern,
.optimized = false,
.pure = false,
.elemental = false,
.recursive = false,
.main_subprogram = false,
.deleted = false,
.object_c_direct = false,
};
const subprogram_declaration = null;
const function_name = unit.getIdentifier(declaration.declaration.name);
const subprogram = llvm.debug_info_builder.createFunction(debug_file.toScope(), function_name.ptr, function_name.len, function_name.ptr, function_name.len, debug_file, declaration.declaration.line + 1, subroutine_type, scope_line, subroutine_type_flags, subprogram_flags, subprogram_declaration) orelse unreachable;
function.setSubprogram(subprogram);
switch (declaration.initial_value) {
.function_declaration => {},
.function_definition => |function_definition_index| {
const function_definition = unit.function_definitions.get(function_definition_index);
const scope = subprogram.toLocalScope().toScope();
try llvm.scope_map.putNoClobber(context.allocator, &function_definition.scope.scope, scope);
},
else => |t| @panic(@tagName(t)),
}
}
}
};
fn getCallingConvention(calling_convention: Compilation.Function.CallingConvention) LLVM.Value.Constant.Function.CallingConvention {
@ -2305,49 +2414,26 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo
try llvm.scope_map.putNoClobber(context.allocator, &unit.scope.scope, llvm.scope);
}
for (unit.external_functions.values()) |external_function_declaration| {
try llvm.emitFunctionDeclaration(unit, context, external_function_declaration);
}
const functions = unit.code_to_emit.values();
{
var function_i: usize = functions.len;
// Emit it in reverse order so the code goes the right order, from entry point to leaves
while (function_i > 0) {
function_i -= 1;
const function_declaration = functions[function_i];
const function_definition_index = function_declaration.getFunctionDefinitionIndex();
const function_definition = unit.function_definitions.get(function_definition_index);
const function_type = try llvm.getType(unit, context, function_definition.type);
const is_export = function_declaration.attributes.contains(.@"export");
const linkage: LLVM.Linkage = switch (is_export) {
true => .@"extern",
false => .internal,
};
// TODO: Check name collision
const mangle_name = !is_export;
_ = mangle_name; // autofix
const name = unit.getIdentifier(function_declaration.declaration.name);
const function = llvm.module.createFunction(function_type.toFunction() orelse unreachable, linkage, address_space, name.ptr, name.len) orelse return Error.function;
const function_prototype = unit.function_prototypes.get(unit.types.get(function_definition.type).function);
switch (unit.types.get(function_prototype.return_type).*) {
.noreturn => {
function.addAttributeKey(.NoReturn);
},
else => {},
}
if (function_prototype.attributes.naked) {
function.addAttributeKey(.Naked);
}
const calling_convention = getCallingConvention(function_prototype.calling_convention);
function.setCallingConvention(calling_convention);
try llvm.function_definition_map.putNoClobber(context.allocator, function_declaration, function);
try llvm.emitFunctionDeclaration(unit, context, function_declaration);
}
}
// First, cache all the global variables
for (unit.data_to_emit.items) |global_declaration| {
const name = unit.getIdentifier(global_declaration.declaration.name);
switch (global_declaration.initial_value) {
.string_literal => |hash| {
const string_literal = unit.string_literal_values.get(hash).?;
@ -2402,68 +2488,11 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo
llvm.function = function;
llvm.sema_function = function_declaration;
llvm.inside_branch = false;
const function_prototype = unit.function_prototypes.get(unit.types.get(function_definition.type).function);
const function_name = unit.getIdentifier(function_declaration.declaration.name);
if (unit.descriptor.generate_debug_information) {
const debug_file = try llvm.getDebugInfoFile(unit, context, function_declaration.declaration.scope.file);
var parameter_types = try ArrayList(*LLVM.DebugInfo.Type).initCapacity(context.allocator, function_prototype.argument_types.len);
for (function_prototype.argument_types) |argument_type_index| {
const argument_type = try llvm.getDebugType(unit, context, argument_type_index);
parameter_types.appendAssumeCapacity(argument_type);
}
const subroutine_type_flags = LLVM.DebugInfo.Node.Flags{
.visibility = .none,
.forward_declaration = false,
.apple_block = false,
.block_by_ref_struct = false,
.virtual = false,
.artificial = false,
.explicit = false,
.prototyped = false,
.objective_c_class_complete = false,
.object_pointer = false,
.vector = false,
.static_member = false,
.lvalue_reference = false,
.rvalue_reference = false,
.reserved = false,
.inheritance = .none,
.introduced_virtual = false,
.bit_field = false,
.no_return = false,
.type_pass_by_value = false,
.type_pass_by_reference = false,
.enum_class = false,
.thunk = false,
.non_trivial = false,
.big_endian = false,
.little_endian = false,
.all_calls_described = false,
};
const subroutine_type_calling_convention = LLVM.DebugInfo.CallingConvention.none;
const subroutine_type = llvm.debug_info_builder.createSubroutineType(parameter_types.items.ptr, parameter_types.items.len, subroutine_type_flags, subroutine_type_calling_convention) orelse unreachable;
const scope_line = 0;
const subprogram_flags = LLVM.DebugInfo.Subprogram.Flags{
.virtuality = .none,
.local_to_unit = true,
.definition = true,
.optimized = false,
.pure = false,
.elemental = false,
.recursive = false,
.main_subprogram = false,
.deleted = false,
.object_c_direct = false,
};
const subprogram_declaration = null;
const subprogram = llvm.debug_info_builder.createFunction(debug_file.toScope(), function_name.ptr, function_name.len, function_name.ptr, function_name.len, debug_file, function_declaration.declaration.line + 1, subroutine_type, scope_line, subroutine_type_flags, subprogram_flags, subprogram_declaration) orelse unreachable;
llvm.function.setSubprogram(subprogram);
const subprogram = llvm.function.getSubprogram() orelse unreachable;
llvm.file = subprogram.getFile() orelse unreachable;
llvm.subprogram = subprogram;
llvm.scope = subprogram.toLocalScope().toScope();
try llvm.scope_map.putNoClobber(context.allocator, &function_definition.scope.scope, llvm.scope);
}
llvm.arg_index = 0;
@ -2496,7 +2525,7 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo
.pop_scope => |pop_scope| {
const new = try llvm.getScope(unit, context, pop_scope.new);
if (pop_scope.new.kind == .function) {
assert(new.toSubprogram() orelse unreachable == llvm.subprogram);
assert(new.toSubprogram() orelse unreachable == llvm.function.getSubprogram() orelse unreachable);
}
llvm.scope = new;
var scope = pop_scope.old;
@ -2504,7 +2533,7 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo
scope = scope.parent.?;
}
const subprogram_scope = try llvm.getScope(unit, context, scope);
assert(llvm.subprogram == subprogram_scope.toSubprogram() orelse unreachable);
assert(llvm.function.getSubprogram() orelse unreachable == subprogram_scope.toSubprogram() orelse unreachable);
},
.debug_checkpoint => |debug_checkpoint| {
const scope = try llvm.getScope(unit, context, debug_checkpoint.scope);
@ -2600,6 +2629,7 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo
.slice => {},
.array => {},
}
const declaration_type = try llvm.getType(unit, context, stack_slot.type);
const alloca_array_size = null;
const declaration_alloca = llvm.builder.createAlloca(declaration_type, address_space, alloca_array_size, "", "".len) orelse return LLVM.Value.Instruction.Error.alloca;
@ -2630,6 +2660,7 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo
.enum_to_int,
.slice_to_nullable,
.slice_to_not_null,
.slice_coerce_to_zero_termination,
.pointer_to_nullable,
.pointer_const_to_var,
.pointer_to_array_to_pointer_to_many,
@ -2676,7 +2707,6 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo
};
const value_type = try llvm.getType(unit, context, load.type);
// const value_type = try llvm.getType(unit, context, load.value.type);
const is_volatile = false;
const load_i = llvm.builder.createLoad(value_type, value, is_volatile, "", "".len) orelse return LLVM.Value.Instruction.Error.load;
try llvm.llvm_instruction_map.putNoClobber(context.allocator, instruction_index, load_i.toValue());
@ -2722,11 +2752,18 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo
switch (call.callable.value) {
.@"comptime" => |ct| switch (ct) {
.global => |call_function_declaration| {
const call_function_definition_index = call_function_declaration.getFunctionDefinitionIndex();
const callee = llvm.function_definition_map.get(call_function_declaration).?;
const call_function_definition = unit.function_definitions.get(call_function_definition_index);
const call_function_prototype = unit.function_prototypes.get(unit.types.get(call_function_definition.type).function);
assert(call_function_definition.type == call.function_type);
const call_function_type = call_function_declaration.declaration.type;
// const call_function_definition_index = call_function_declaration.getFunctionDefinitionIndex();
// const callee = llvm.function_definition_map.get(call_function_declaration).?;
const call_function_prototype = unit.function_prototypes.get(unit.types.get(call_function_type).function);
assert(call_function_type == call.function_type);
const callee = switch (call_function_declaration.initial_value) {
.function_definition => llvm.function_definition_map.get(call_function_declaration).?,
.function_declaration => llvm.function_declaration_map.get(call_function_declaration).?,
else => |t| @panic(@tagName(t)),
};
for (call.arguments, arguments) |argument_value, *argument| {
argument.* = try llvm.emitRightValue(unit, context, argument_value);
@ -3062,7 +3099,7 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo
}
if (unit.descriptor.generate_debug_information) {
llvm.debug_info_builder.finalizeSubprogram(llvm.subprogram, llvm.function);
llvm.debug_info_builder.finalizeSubprogram(llvm.function.getSubprogram() orelse unreachable, llvm.function);
}
const verify_function = true;

View File

@ -304,7 +304,7 @@ const Analyzer = struct {
if (equal(u8, identifier_name, enum_field.name)) {
const attribute = @field(Compilation.Debug.Declaration.Global.Attribute, enum_field.name);
const attribute_node = switch (attribute) {
.@"export" => try analyzer.addNode(.{
.@"export", .@"extern", => try analyzer.addNode(.{
.id = @field(Node.Id, "symbol_attribute_" ++ @tagName(attribute)),
.token = identifier,
.left = .null,
@ -313,7 +313,7 @@ const Analyzer = struct {
};
break attribute_node;
}
} else @panic("Not known attribute");
} else panic("Unknown symbol attribute: {s}", .{identifier_name});
try list.append(analyzer.allocator, attribute_node);
switch (analyzer.peekToken()) {
@ -400,7 +400,7 @@ const Analyzer = struct {
};
break attribute_node;
}
} else @panic("Not known attribute");
} else panic("Unknown function attribute: {s}", .{identifier_name});
try attribute_and_return_type_node_list.append(analyzer.allocator, attribute_node);
@ -1128,7 +1128,8 @@ const Analyzer = struct {
fn primaryExpression(analyzer: *Analyzer) !Node.Index {
const result = switch (analyzer.peekToken()) {
.identifier => switch (analyzer.peekTokenAhead(1)) {
.operator_colon => unreachable,
// TODO: tags
// .operator_colon => unreachable,
else => try analyzer.curlySuffixExpression(),
},
.string_literal,
@ -1349,6 +1350,7 @@ const Analyzer = struct {
.operator_right_parenthesis,
.operator_left_brace,
.operator_assign,
.operator_semicolon,
=> return node_index,
else => |t| @panic(@tagName(t)),
}

View File

@ -5,7 +5,7 @@ pub fn build(b: *std.Build) !void {
const self_hosted_ci = b.option(bool, "self_hosted_ci", "This option enables the self-hosted CI behavior") orelse false;
const third_party_ci = b.option(bool, "third_party_ci", "This option enables the third-party CI behavior") orelse false;
const is_ci = self_hosted_ci or third_party_ci;
const print_stack_trace = b.option(bool, "print_stack_trace", "This option enables printing stack traces inside the compiler") orelse is_ci;
const print_stack_trace = b.option(bool, "print_stack_trace", "This option enables printing stack traces inside the compiler") orelse is_ci or @import("builtin").os.tag == .macos;
const native_target = b.resolveTargetQuery(.{});
const optimization = b.standardOptimizeOption(.{});
var target_query = b.standardTargetOptionsQueryOnly(.{});
@ -14,6 +14,32 @@ pub fn build(b: *std.Build) !void {
target_query.abi = .musl;
}
const target = b.resolveTargetQuery(target_query);
const compiler_options = b.addOptions();
compiler_options.addOption(bool, "print_stack_trace", print_stack_trace);
const compiler = b.addExecutable(.{
.name = "nat",
.root_source_file = .{ .path = "bootstrap/main.zig" },
.target = target,
.optimize = optimization,
});
compiler.root_module.addOptions("configuration", compiler_options);
compiler.formatted_panics = print_stack_trace;
compiler.root_module.unwind_tables = print_stack_trace;
compiler.root_module.omit_frame_pointer = false;
compiler.want_lto = false;
compiler.linkLibC();
compiler.linkSystemLibrary("c++");
// TODO:
// if (target.result.os.tag == .windows) {
// compiler.linkSystemLibrary("ole32");
// compiler.linkSystemLibrary("version");
// compiler.linkSystemLibrary("uuid");
// compiler.linkSystemLibrary("msvcrt-os");
// }
const llvm_version = "17.0.6";
var fetcher_run: ?*std.Build.Step.Run = null;
const llvm_path = b.option([]const u8, "llvm_path", "LLVM prefix path") orelse blk: {
@ -69,30 +95,6 @@ pub fn build(b: *std.Build) !void {
};
}
};
const compiler_options = b.addOptions();
compiler_options.addOption(bool, "print_stack_trace", print_stack_trace);
const compiler = b.addExecutable(.{
.name = "nat",
.root_source_file = .{ .path = "bootstrap/main.zig" },
.target = target,
.optimize = optimization,
});
compiler.root_module.addOptions("configuration", compiler_options);
compiler.formatted_panics = print_stack_trace;
compiler.root_module.unwind_tables = print_stack_trace;
compiler.root_module.omit_frame_pointer = false;
compiler.want_lto = false;
compiler.linkLibC();
compiler.linkSystemLibrary("c++");
if (target.result.os.tag == .windows) {
compiler.linkSystemLibrary("ole32");
compiler.linkSystemLibrary("version");
compiler.linkSystemLibrary("uuid");
compiler.linkSystemLibrary("msvcrt-os");
}
if (fetcher_run) |fr| {
compiler.step.dependOn(&fr.step);
@ -408,13 +410,9 @@ pub fn build(b: *std.Build) !void {
test_command.step.dependOn(b.getInstallStep());
if (b.args) |args| {
std.debug.print("Args: {s}", .{args});
run_command.addArgs(args);
debug_command.addArgs(args);
test_command.addArgs(args);
for (debug_command.argv.items, 0..) |arg, i| {
std.debug.print("Arg #{}: {s}\n", .{i, arg.bytes});
}
}
const run_step = b.step("run", "Test the Nativity compiler");

View File

@ -7,6 +7,7 @@ const Os = enum{
const Cpu = enum{
x86_64,
aarch64,
};
const Abi = enum{

View File

@ -11,17 +11,20 @@ const exit = fn(exit_code: s32) noreturn {
switch (current) {
.linux => _ = #syscall(#cast(linux.Syscall.exit_group), #cast(exit_code)),
.macos => macos.exit(exit_code),
.windows => windows.ExitProcess(exit_code),
.windows => windows.ExitProcess(#cast(exit_code)),
}
unreachable;
}
const max_file_operation_byte_count = switch (current) {
.linux => 0x7ffff000,
.macos => 0x7fffffff,
else => #error("OS not supported"),
};
const unwrap_syscall_signed = fn(syscall_result: ssize) bool {
return syscall_result >= 0;
}
const FileDescriptor = struct{
handle: system.FileDescriptor,
@ -54,6 +57,15 @@ const FileDescriptor = struct{
return null;
}
},
.macos => {
const raw_result = macos.write(file_descriptor.handle, bytes.ptr, bytes.len);
if (unwrap_syscall_signed(raw_result)) {
const bytes_written: usize = #cast(raw_result);
return bytes_written;
} else {
return null;
}
},
else => #error("OS not supported"),
}
}
@ -90,16 +102,27 @@ const MapFlags = struct(u32){
const allocate_virtual_memory = fn(address: ?[&]u8, length: usize, general_protection_flags: ProtectionFlags, general_map_flags: MapFlags) ?[&]u8 {
const protection_flags = system.get_protection_flags(flags = general_protection_flags);
const map_flags = system.get_map_flags(flags = general_map_flags);
const fd = -1;
const offset = 0;
switch (current) {
.linux => {
if (linux.unwrap_syscall(syscall_result = linux.mmap(address, length, protection_flags, map_flags, fd = -1, offset = 0))) |result_address| {
if (linux.unwrap_syscall(syscall_result = linux.mmap(address, length, protection_flags, map_flags, fd, offset))) |result_address| {
const pointer: [&]u8 = #cast(result_address);
return pointer;
} else {
return null;
}
},
.macos => {
const result = macos.mmap(address, length, protection_flags, map_flags, fd, offset);
if (result != macos.MAP_FAILED) {
const result_address: [&]u8 = #cast(result);
return result_address;
} else {
return null;
}
},
else => #error("OS not supported"),
}
@ -114,6 +137,11 @@ const free_virtual_memory = fn(bytes_ptr: [&]const u8, bytes_len: usize) bool {
return false;
}
},
.macos => {
const raw_result = macos.munmap(bytes_ptr, bytes_len);
const result = unwrap_syscall_signed(raw_result);
return result;
},
else => #error("OS not supported"),
}
}
@ -136,10 +164,11 @@ const readlink = fn(file_path: [&:0]const u8, buffer: []u8) ?[]u8 {
const max_path_byte_count = switch (current) {
.linux => 0x1000,
.macos => 1024,
else => #error("OS not supported"),
};
const current_executable_path = fn(buffer: []u8) ?[]u8 {
const current_executable_path = fn(buffer: [:0]u8) ?[]u8 {
switch (current) {
.linux => {
if (readlink(file_path = "/proc/self/exe", buffer)) |bytes| {
@ -148,6 +177,31 @@ const current_executable_path = fn(buffer: []u8) ?[]u8 {
return null;
}
},
.macos => {
var symlink_path_buffer: [max_path_byte_count:0]u8 = undefined;
var symlink_path_len: u32 = symlink_path_buffer.len + 1;
const ns_result = macos._NSGetExecutablePath(symlink_path_buffer.&, symlink_path_len.&);
if (ns_result == 0) {
const symlink_path = symlink_path_buffer[0..symlink_path_len];
const result = macos.realpath(symlink_path.ptr, buffer.ptr);
if (result != null) {
var i: usize = 0;
while (i < buffer.len) {
if (result[i] == 0) {
break;
}
i += 1;
}
#assert(i < buffer.len);
return result[0..i];
} else {
return null;
}
} else {
return null;
}
},
else => #error("OS not supported"),
}
}
@ -167,14 +221,25 @@ const duplicate_process = fn () ?Process.Id {
return null;
}
},
.macos => {
const fork_result = macos.fork();
if (unwrap_syscall_signed(fork_result)) {
return fork_result;
} else {
return null;
}
},
else => #error("OS not supported"),
}
}
const execute = fn(path: [&:0]const u8, argv: [&:null]const ?[&:0]const u8, env: [&:null]const ?[&:null]const u8) usize {
const execute = fn(path: [&:0]const u8, argv: [&:null]const ?[&:0]const u8, env: [&:null]const ?[&:null]const u8) void {
switch (current) {
.linux => {
return linux.execve(path, argv, env);
_ = linux.execve(path, argv, env);
},
.macos => {
_ = macos.execve(path, argv, env);
},
else => #error("OS not supported"),
}

View File

@ -494,7 +494,7 @@ const memfd_create = fn(name: [&:0]const u8, flags: u32) usize {
const unwrap_syscall = fn(syscall_result: usize) ?usize {
const signed_syscall_result: ssize = #cast(syscall_result);
if (signed_syscall_result >= 0) {
if (std.os.unwrap_syscall_signed(signed_syscall_result)) {
return syscall_result;
} else {
return null;

View File

@ -1,3 +1,56 @@
const std = #import("std");
const FileDescriptor = s32;
const write = fn (file_descriptor: FileDescriptor, bytes_ptr: [&]const u8, bytes_len: usize) ssize extern;
const exit = fn (exit_code: u32) noreturn extern;
const ProcessId = s32;
const MAP_FAILED = 0xffffffffffffffff;
const MapFlags = struct(u32){
shared: bool,
private: bool,
reserved: u2 = 0,
fixed: bool,
reserved0: bool = 0,
noreserve: bool,
reserved1: u2 = 0,
has_semaphore: bool,
no_cache: bool,
reserved2: u1 = 0,
anonymous: bool,
reserved3: u19 = 0,
};
const ProtectionFlags = struct(u32) {
read: bool,
write: bool,
execute: bool,
};
const get_protection_flags = fn(flags: std.os.ProtectionFlags) ProtectionFlags {
return ProtectionFlags{
.read = flags.read,
.write = flags.write,
.execute = flags.execute,
};
}
const get_map_flags = fn(flags: std.os.MapFlags) MapFlags{
return MapFlags{
.shared = false,
.private = true,
.fixed = false,
.noreserve = false,
.has_semaphore = false,
.no_cache = false,
.anonymous = true,
};
}
const write :: extern = fn (file_descriptor: FileDescriptor, bytes_ptr: [&]const u8, bytes_len: usize) ssize;
const exit :: extern = fn (exit_code: s32) noreturn;
const fork :: extern = fn () ProcessId;
const mmap :: extern = fn (address: ?[&]const u8, length: usize, protection_flags: ProtectionFlags, map_flags: MapFlags, file_descriptor: FileDescriptor, offset: u64) usize;
const munmap :: extern = fn (address: [&]const u8, length: usize) s32;
const execve :: extern = fn(path: [&:0]const u8, argv: [&:null]const ?[&:0]const u8, env: [&:null]const ?[&:null]const u8) s32;
const realpath :: extern = fn(path: [&:0]const u8, resolved_path: [&:0]u8) [&:0]u8;
const _NSGetExecutablePath :: extern = fn (buffer: [&:0]u8, buffer_size: &u32) s32;

View File

@ -2,7 +2,7 @@ const std = #import("std");
const print = std.print;
const main = fn() s32 {
var buffer: [std.os.max_path_byte_count + 1]u8 = undefined;
var buffer: [std.os.max_path_byte_count:0]u8 = undefined;
if (std.os.current_executable_path(buffer = buffer.&)) |bytes| {
print(bytes);
print(bytes = "\n");