diff --git a/lib/std/build.zig b/lib/std/build.zig index 1bdd97b253..9d12a4de51 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -2480,9 +2480,19 @@ pub const LibExeObjStep = struct { try zig_args.append("--test-cmd"); try zig_args.append(bin_name); if (glibc_dir_arg) |dir| { - const full_dir = try fs.path.join(builder.allocator, &[_][]const u8{ - dir, - try self.target.linuxTriple(builder.allocator), + // TODO look into making this a call to `linuxTriple`. This + // needs the directory to be called "i686" rather than + // "i386" which is why we do it manually here. + const fmt_str = "{s}" ++ fs.path.sep_str ++ "{s}-{s}-{s}"; + const cpu_arch = self.target.getCpuArch(); + const os_tag = self.target.getOsTag(); + const abi = self.target.getAbi(); + const cpu_arch_name: []const u8 = if (cpu_arch == .i386) + "i686" + else + @tagName(cpu_arch); + const full_dir = try std.fmt.allocPrint(builder.allocator, fmt_str, .{ + dir, cpu_arch_name, @tagName(os_tag), @tagName(abi), }); try zig_args.append("--test-cmd"); diff --git a/lib/std/mem.zig b/lib/std/mem.zig index df91adddb2..aeec384da1 100644 --- a/lib/std/mem.zig +++ b/lib/std/mem.zig @@ -602,6 +602,7 @@ test "span" { try testing.expectEqual(@as(?[:0]u16, null), span(@as(?[*:0]u16, null))); } +/// Deprecated: use std.mem.span() or std.mem.sliceTo() /// Same as `span`, except when there is both a sentinel and an array /// length or slice length, scans the memory for the sentinel value /// rather than using the length. @@ -630,6 +631,192 @@ test "spanZ" { try testing.expectEqual(@as(?[:0]u16, null), spanZ(@as(?[*:0]u16, null))); } +/// Helper for the return type of sliceTo() +fn SliceTo(comptime T: type, comptime end: meta.Elem(T)) type { + switch (@typeInfo(T)) { + .Optional => |optional_info| { + return ?SliceTo(optional_info.child, end); + }, + .Pointer => |ptr_info| { + var new_ptr_info = ptr_info; + new_ptr_info.size = .Slice; + switch (ptr_info.size) { + .One => switch (@typeInfo(ptr_info.child)) { + .Array => |array_info| { + new_ptr_info.child = array_info.child; + // The return type must only be sentinel terminated if we are guaranteed + // to find the value searched for, which is only the case if it matches + // the sentinel of the type passed. + if (array_info.sentinel) |sentinel| { + if (end == sentinel) { + new_ptr_info.sentinel = end; + } else { + new_ptr_info.sentinel = null; + } + } + }, + else => {}, + }, + .Many, .Slice => { + // The return type must only be sentinel terminated if we are guaranteed + // to find the value searched for, which is only the case if it matches + // the sentinel of the type passed. + if (ptr_info.sentinel) |sentinel| { + if (end == sentinel) { + new_ptr_info.sentinel = end; + } else { + new_ptr_info.sentinel = null; + } + } + }, + .C => { + new_ptr_info.sentinel = end; + // C pointers are always allowzero, but we don't want the return type to be. + assert(new_ptr_info.is_allowzero); + new_ptr_info.is_allowzero = false; + }, + } + return @Type(std.builtin.TypeInfo{ .Pointer = new_ptr_info }); + }, + else => {}, + } + @compileError("invalid type given to std.mem.sliceTo: " ++ @typeName(T)); +} + +/// Takes a pointer to an array, an array, a sentinel-terminated pointer, or a slice and +/// iterates searching for the first occurrence of `end`, returning the scanned slice. +/// If `end` is not found, the full length of the array/slice/sentinel terminated pointer is returned. +/// If the pointer type is sentinel terminated and `end` matches that terminator, the +/// resulting slice is also sentinel terminated. +/// Pointer properties such as mutability and alignment are preserved. +/// C pointers are assumed to be non-null. +pub fn sliceTo(ptr: anytype, comptime end: meta.Elem(@TypeOf(ptr))) SliceTo(@TypeOf(ptr), end) { + if (@typeInfo(@TypeOf(ptr)) == .Optional) { + const non_null = ptr orelse return null; + return sliceTo(non_null, end); + } + const Result = SliceTo(@TypeOf(ptr), end); + const length = lenSliceTo(ptr, end); + if (@typeInfo(Result).Pointer.sentinel) |s| { + return ptr[0..length :s]; + } else { + return ptr[0..length]; + } +} + +test "sliceTo" { + try testing.expectEqualSlices(u8, "aoeu", sliceTo("aoeu", 0)); + + { + var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 }; + try testing.expectEqualSlices(u16, &array, sliceTo(&array, 0)); + try testing.expectEqualSlices(u16, array[0..3], sliceTo(array[0..3], 0)); + try testing.expectEqualSlices(u16, array[0..2], sliceTo(&array, 3)); + try testing.expectEqualSlices(u16, array[0..2], sliceTo(array[0..3], 3)); + + const sentinel_ptr = @ptrCast([*:5]u16, &array); + try testing.expectEqualSlices(u16, array[0..2], sliceTo(sentinel_ptr, 3)); + try testing.expectEqualSlices(u16, array[0..4], sliceTo(sentinel_ptr, 99)); + + const optional_sentinel_ptr = @ptrCast(?[*:5]u16, &array); + try testing.expectEqualSlices(u16, array[0..2], sliceTo(optional_sentinel_ptr, 3).?); + try testing.expectEqualSlices(u16, array[0..4], sliceTo(optional_sentinel_ptr, 99).?); + + const c_ptr = @as([*c]u16, &array); + try testing.expectEqualSlices(u16, array[0..2], sliceTo(c_ptr, 3)); + + const slice: []u16 = &array; + try testing.expectEqualSlices(u16, array[0..2], sliceTo(slice, 3)); + try testing.expectEqualSlices(u16, &array, sliceTo(slice, 99)); + + const sentinel_slice: [:5]u16 = array[0..4 :5]; + try testing.expectEqualSlices(u16, array[0..2], sliceTo(sentinel_slice, 3)); + try testing.expectEqualSlices(u16, array[0..4], sliceTo(sentinel_slice, 99)); + } + { + var sentinel_array: [5:0]u16 = [_:0]u16{ 1, 2, 3, 4, 5 }; + try testing.expectEqualSlices(u16, sentinel_array[0..2], sliceTo(&sentinel_array, 3)); + try testing.expectEqualSlices(u16, &sentinel_array, sliceTo(&sentinel_array, 0)); + try testing.expectEqualSlices(u16, &sentinel_array, sliceTo(&sentinel_array, 99)); + } + + try testing.expectEqual(@as(?[]u8, null), sliceTo(@as(?[]u8, null), 0)); +} + +/// Private helper for sliceTo(). If you want the length, use sliceTo(foo, x).len +fn lenSliceTo(ptr: anytype, comptime end: meta.Elem(@TypeOf(ptr))) usize { + switch (@typeInfo(@TypeOf(ptr))) { + .Pointer => |ptr_info| switch (ptr_info.size) { + .One => switch (@typeInfo(ptr_info.child)) { + .Array => |array_info| { + if (array_info.sentinel) |sentinel| { + if (sentinel == end) { + return indexOfSentinel(array_info.child, end, ptr); + } + } + return indexOfScalar(array_info.child, ptr, end) orelse array_info.len; + }, + else => {}, + }, + .Many => if (ptr_info.sentinel) |sentinel| { + // We may be looking for something other than the sentinel, + // but iterating past the sentinel would be a bug so we need + // to check for both. + var i: usize = 0; + while (ptr[i] != end and ptr[i] != sentinel) i += 1; + return i; + }, + .C => { + assert(ptr != null); + return indexOfSentinel(ptr_info.child, end, ptr); + }, + .Slice => { + if (ptr_info.sentinel) |sentinel| { + if (sentinel == end) { + return indexOfSentinel(ptr_info.child, sentinel, ptr); + } + } + return indexOfScalar(ptr_info.child, ptr, end) orelse ptr.len; + }, + }, + else => {}, + } + @compileError("invalid type given to std.mem.sliceTo: " ++ @typeName(@TypeOf(ptr))); +} + +test "lenSliceTo" { + try testing.expect(lenSliceTo("aoeu", 0) == 4); + + { + var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 }; + try testing.expectEqual(@as(usize, 5), lenSliceTo(&array, 0)); + try testing.expectEqual(@as(usize, 3), lenSliceTo(array[0..3], 0)); + try testing.expectEqual(@as(usize, 2), lenSliceTo(&array, 3)); + try testing.expectEqual(@as(usize, 2), lenSliceTo(array[0..3], 3)); + + const sentinel_ptr = @ptrCast([*:5]u16, &array); + try testing.expectEqual(@as(usize, 2), lenSliceTo(sentinel_ptr, 3)); + try testing.expectEqual(@as(usize, 4), lenSliceTo(sentinel_ptr, 99)); + + const c_ptr = @as([*c]u16, &array); + try testing.expectEqual(@as(usize, 2), lenSliceTo(c_ptr, 3)); + + const slice: []u16 = &array; + try testing.expectEqual(@as(usize, 2), lenSliceTo(slice, 3)); + try testing.expectEqual(@as(usize, 5), lenSliceTo(slice, 99)); + + const sentinel_slice: [:5]u16 = array[0..4 :5]; + try testing.expectEqual(@as(usize, 2), lenSliceTo(sentinel_slice, 3)); + try testing.expectEqual(@as(usize, 4), lenSliceTo(sentinel_slice, 99)); + } + { + var sentinel_array: [5:0]u16 = [_:0]u16{ 1, 2, 3, 4, 5 }; + try testing.expectEqual(@as(usize, 2), lenSliceTo(&sentinel_array, 3)); + try testing.expectEqual(@as(usize, 5), lenSliceTo(&sentinel_array, 0)); + try testing.expectEqual(@as(usize, 5), lenSliceTo(&sentinel_array, 99)); + } +} + /// Takes a pointer to an array, an array, a vector, a sentinel-terminated pointer, /// a slice or a tuple, and returns the length. /// In the case of a sentinel-terminated array, it uses the array length. @@ -688,6 +875,7 @@ test "len" { } } +/// Deprecated: use std.mem.len() or std.mem.sliceTo().len /// Takes a pointer to an array, an array, a sentinel-terminated pointer, /// or a slice, and returns the length. /// In the case of a sentinel-terminated array, it scans the array diff --git a/lib/std/meta.zig b/lib/std/meta.zig index 391b7259e3..473d4fcf26 100644 --- a/lib/std/meta.zig +++ b/lib/std/meta.zig @@ -175,13 +175,7 @@ pub fn Elem(comptime T: type) type { }, .Many, .C, .Slice => return info.child, }, - .Optional => |info| switch (@typeInfo(info.child)) { - .Pointer => |ptr_info| switch (ptr_info.size) { - .Many => return ptr_info.child, - else => {}, - }, - else => {}, - }, + .Optional => |info| return Elem(info.child), else => {}, } @compileError("Expected pointer, slice, array or vector type, found '" ++ @typeName(T) ++ "'"); diff --git a/lib/std/priority_dequeue.zig b/lib/std/priority_dequeue.zig index f0f8d7f6f7..0bb1f13503 100644 --- a/lib/std/priority_dequeue.zig +++ b/lib/std/priority_dequeue.zig @@ -387,17 +387,6 @@ pub fn PriorityDequeue(comptime T: type) type { return; }, }; - self.len = new_len; - } - - /// Reduce length to `new_len`. - pub fn shrinkRetainingCapacity(self: *Self, new_len: usize) void { - assert(new_len <= self.items.len); - - // Cannot shrink to smaller than the current queue size without invalidating the heap property - assert(new_len >= self.len); - - self.len = new_len; } pub fn update(self: *Self, elem: T, new_elem: T) !void { @@ -836,7 +825,7 @@ test "std.PriorityDequeue: iterator while empty" { try expectEqual(it.next(), null); } -test "std.PriorityDequeue: shrinkRetainingCapacity and shrinkAndFree" { +test "std.PriorityDequeue: shrinkAndFree" { var queue = PDQ.init(testing.allocator, lessThanComparison); defer queue.deinit(); @@ -849,10 +838,6 @@ test "std.PriorityDequeue: shrinkRetainingCapacity and shrinkAndFree" { try expect(queue.capacity() >= 4); try expectEqual(@as(usize, 3), queue.len); - queue.shrinkRetainingCapacity(3); - try expect(queue.capacity() >= 4); - try expectEqual(@as(usize, 3), queue.len); - queue.shrinkAndFree(3); try expectEqual(@as(usize, 3), queue.capacity()); try expectEqual(@as(usize, 3), queue.len); diff --git a/lib/std/priority_queue.zig b/lib/std/priority_queue.zig index 621af4e97f..4e5320a92b 100644 --- a/lib/std/priority_queue.zig +++ b/lib/std/priority_queue.zig @@ -203,17 +203,6 @@ pub fn PriorityQueue(comptime T: type) type { return; }, }; - self.len = new_len; - } - - /// Reduce length to `new_len`. - pub fn shrinkRetainingCapacity(self: *Self, new_len: usize) void { - assert(new_len <= self.items.len); - - // Cannot shrink to smaller than the current queue size without invalidating the heap property - assert(new_len >= self.len); - - self.len = new_len; } pub fn update(self: *Self, elem: T, new_elem: T) !void { @@ -495,7 +484,7 @@ test "std.PriorityQueue: iterator while empty" { try expectEqual(it.next(), null); } -test "std.PriorityQueue: shrinkRetainingCapacity and shrinkAndFree" { +test "std.PriorityQueue: shrinkAndFree" { var queue = PQ.init(testing.allocator, lessThan); defer queue.deinit(); @@ -508,10 +497,6 @@ test "std.PriorityQueue: shrinkRetainingCapacity and shrinkAndFree" { try expect(queue.capacity() >= 4); try expectEqual(@as(usize, 3), queue.len); - queue.shrinkRetainingCapacity(3); - try expect(queue.capacity() >= 4); - try expectEqual(@as(usize, 3), queue.len); - queue.shrinkAndFree(3); try expectEqual(@as(usize, 3), queue.capacity()); try expectEqual(@as(usize, 3), queue.len); diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig index 5522367d36..c504f93efd 100644 --- a/lib/std/zig/system.zig +++ b/lib/std/zig/system.zig @@ -208,11 +208,6 @@ pub const NativeTargetInfo = struct { dynamic_linker: DynamicLinker = DynamicLinker{}, - /// Only some architectures have CPU detection implemented. This field reveals whether - /// CPU detection actually occurred. When this is `true` it means that the reported - /// CPU is baseline only because of a missing implementation for that architecture. - cpu_detection_unimplemented: bool = false, - pub const DynamicLinker = Target.DynamicLinker; pub const DetectError = error{ @@ -367,8 +362,6 @@ pub const NativeTargetInfo = struct { os.version_range.linux.glibc = glibc; } - var cpu_detection_unimplemented = false; - // Until https://github.com/ziglang/zig/issues/4592 is implemented (support detecting the // native CPU architecture as being different than the current target), we use this: const cpu_arch = cross_target.getCpuArch(); @@ -382,7 +375,6 @@ pub const NativeTargetInfo = struct { Target.Cpu.baseline(cpu_arch), .explicit => |model| model.toCpu(cpu_arch), } orelse backup_cpu_detection: { - cpu_detection_unimplemented = true; break :backup_cpu_detection Target.Cpu.baseline(cpu_arch); }; var result = try detectAbiAndDynamicLinker(allocator, cpu, os, cross_target); @@ -419,7 +411,6 @@ pub const NativeTargetInfo = struct { else => {}, } cross_target.updateCpuFeatures(&result.target.cpu.features); - result.cpu_detection_unimplemented = cpu_detection_unimplemented; return result; } diff --git a/src/Cache.zig b/src/Cache.zig index 5bc32b4b68..6c17f52d69 100644 --- a/src/Cache.zig +++ b/src/Cache.zig @@ -11,6 +11,7 @@ const testing = std.testing; const mem = std.mem; const fmt = std.fmt; const Allocator = std.mem.Allocator; +const Compilation = @import("Compilation.zig"); /// Be sure to call `Manifest.deinit` after successful initialization. pub fn obtain(cache: *const Cache) Manifest { @@ -61,7 +62,7 @@ pub const File = struct { pub const HashHelper = struct { hasher: Hasher = hasher_init, - const EmitLoc = @import("Compilation.zig").EmitLoc; + const EmitLoc = Compilation.EmitLoc; /// Record a slice of bytes as an dependency of the process being cached pub fn addBytes(hh: *HashHelper, bytes: []const u8) void { @@ -220,6 +221,24 @@ pub const Manifest = struct { return idx; } + pub fn hashCSource(self: *Manifest, c_source: Compilation.CSourceFile) !void { + _ = try self.addFile(c_source.src_path, null); + // Hash the extra flags, with special care to call addFile for file parameters. + // TODO this logic can likely be improved by utilizing clang_options_data.zig. + const file_args = [_][]const u8{"-include"}; + var arg_i: usize = 0; + while (arg_i < c_source.extra_flags.len) : (arg_i += 1) { + const arg = c_source.extra_flags[arg_i]; + self.hash.addBytes(arg); + for (file_args) |file_arg| { + if (mem.eql(u8, file_arg, arg) and arg_i + 1 < c_source.extra_flags.len) { + arg_i += 1; + _ = try self.addFile(c_source.extra_flags[arg_i], null); + } + } + } + } + pub fn addOptionalFile(self: *Manifest, optional_file_path: ?[]const u8) !void { self.hash.add(optional_file_path != null); const file_path = optional_file_path orelse return; diff --git a/src/Compilation.zig b/src/Compilation.zig index 71df776855..b14e598f71 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -2260,23 +2260,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_comp_progress_node: * man.hash.add(comp.clang_preprocessor_mode); - _ = try man.addFile(c_object.src.src_path, null); - { - // Hash the extra flags, with special care to call addFile for file parameters. - // TODO this logic can likely be improved by utilizing clang_options_data.zig. - const file_args = [_][]const u8{"-include"}; - var arg_i: usize = 0; - while (arg_i < c_object.src.extra_flags.len) : (arg_i += 1) { - const arg = c_object.src.extra_flags[arg_i]; - man.hash.addBytes(arg); - for (file_args) |file_arg| { - if (mem.eql(u8, file_arg, arg) and arg_i + 1 < c_object.src.extra_flags.len) { - arg_i += 1; - _ = try man.addFile(c_object.src.extra_flags[arg_i], null); - } - } - } - } + try man.hashCSource(c_object.src); { const is_collision = blk: { @@ -3039,7 +3023,6 @@ fn wantBuildLibUnwindFromSource(comp: *Compilation) bool { .Exe => true, }; return comp.bin_file.options.link_libc and is_exe_or_dyn_lib and - comp.bin_file.options.libc_installation == null and target_util.libcNeedsLibUnwind(comp.getTarget()); } diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 91ee6f3206..fbbe40022a 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -1648,17 +1648,12 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { // libc dep if (self.base.options.link_libc) { if (self.base.options.libc_installation != null) { + if (target_util.libcNeedsLibUnwind(target)) { + try argv.append(comp.libunwind_static_lib.?.full_object_path); + } const needs_grouping = self.base.options.link_mode == .Static; if (needs_grouping) try argv.append("--start-group"); - // This matches the order of glibc.libs - try argv.appendSlice(&[_][]const u8{ - "-lm", - "-lpthread", - "-lc", - "-ldl", - "-lrt", - "-lutil", - }); + try argv.appendSlice(target_util.libcFullLinkFlags(target)); if (needs_grouping) try argv.append("--end-group"); } else if (target.isGnuLibC()) { try argv.append(comp.libunwind_static_lib.?.full_object_path); diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 09414b4cdd..2ae9575b7e 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -442,6 +442,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; const main_cmd = &self.load_commands.items[self.main_cmd_index.?].Main; main_cmd.entryoff = addr - text_segment.inner.vmaddr; + main_cmd.stacksize = self.base.options.stack_size_override orelse 0; self.load_commands_dirty = true; } try self.writeRebaseInfoTable(); @@ -695,7 +696,9 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { Compilation.dump_argv(argv.items); } - try zld.link(input_files.items, full_out_path); + try zld.link(input_files.items, full_out_path, .{ + .stack_size = self.base.options.stack_size_override, + }); break :outer; } diff --git a/src/link/MachO/Zld.zig b/src/link/MachO/Zld.zig index 3904192995..c619d0634b 100644 --- a/src/link/MachO/Zld.zig +++ b/src/link/MachO/Zld.zig @@ -29,6 +29,10 @@ page_size: ?u16 = null, file: ?fs.File = null, out_path: ?[]const u8 = null, +// TODO these args will become obselete once Zld is coalesced with incremental +// linker. +stack_size: u64 = 0, + objects: std.ArrayListUnmanaged(*Object) = .{}, archives: std.ArrayListUnmanaged(*Archive) = .{}, @@ -172,7 +176,11 @@ pub fn closeFiles(self: Zld) void { if (self.file) |f| f.close(); } -pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void { +const LinkArgs = struct { + stack_size: ?u64 = null, +}; + +pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8, args: LinkArgs) !void { if (files.len == 0) return error.NoInputFiles; if (out_path.len == 0) return error.EmptyOutputPath; @@ -206,6 +214,7 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void { .read = true, .mode = if (std.Target.current.os.tag == .windows) 0 else 0o777, }); + self.stack_size = args.stack_size orelse 0; try self.populateMetadata(); try self.parseInputFiles(files); @@ -2204,6 +2213,7 @@ fn setEntryPoint(self: *Zld) !void { const entry_sym = sym.cast(Symbol.Regular) orelse unreachable; const ec = &self.load_commands.items[self.main_cmd_index.?].Main; ec.entryoff = @intCast(u32, entry_sym.address - seg.inner.vmaddr); + ec.stacksize = self.stack_size; } fn writeRebaseInfoTable(self: *Zld) !void { diff --git a/src/main.zig b/src/main.zig index a0a11bbbbc..bd57c1f14f 100644 --- a/src/main.zig +++ b/src/main.zig @@ -2172,7 +2172,7 @@ fn cmdTranslateC(comp: *Compilation, arena: *Allocator, enable_cache: bool) !voi defer if (enable_cache) man.deinit(); man.hash.add(@as(u16, 0xb945)); // Random number to distinguish translate-c from compiling C objects - _ = man.addFile(c_source_file.src_path, null) catch |err| { + man.hashCSource(c_source_file) catch |err| { fatal("unable to process '{s}': {s}", .{ c_source_file.src_path, @errorName(err) }); }; @@ -2202,12 +2202,16 @@ fn cmdTranslateC(comp: *Compilation, arena: *Allocator, enable_cache: bool) !voi } // Convert to null terminated args. - const new_argv_with_sentinel = try arena.alloc(?[*:0]const u8, argv.items.len + 1); - new_argv_with_sentinel[argv.items.len] = null; - const new_argv = new_argv_with_sentinel[0..argv.items.len :null]; + const clang_args_len = argv.items.len + c_source_file.extra_flags.len; + const new_argv_with_sentinel = try arena.alloc(?[*:0]const u8, clang_args_len + 1); + new_argv_with_sentinel[clang_args_len] = null; + const new_argv = new_argv_with_sentinel[0..clang_args_len :null]; for (argv.items) |arg, i| { new_argv[i] = try arena.dupeZ(u8, arg); } + for (c_source_file.extra_flags) |arg, i| { + new_argv[argv.items.len + i] = try arena.dupeZ(u8, arg); + } const c_headers_dir_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{"include"}); const c_headers_dir_path_z = try arena.dupeZ(u8, c_headers_dir_path); @@ -3396,88 +3400,8 @@ test "fds" { gimmeMoreOfThoseSweetSweetFileDescriptors(); } -fn detectNativeCpuWithLLVM( - arch: std.Target.Cpu.Arch, - llvm_cpu_name_z: ?[*:0]const u8, - llvm_cpu_features_opt: ?[*:0]const u8, -) !std.Target.Cpu { - var result = std.Target.Cpu.baseline(arch); - - if (llvm_cpu_name_z) |cpu_name_z| { - const llvm_cpu_name = mem.spanZ(cpu_name_z); - - for (arch.allCpuModels()) |model| { - const this_llvm_name = model.llvm_name orelse continue; - if (mem.eql(u8, this_llvm_name, llvm_cpu_name)) { - // Here we use the non-dependencies-populated set, - // so that subtracting features later in this function - // affect the prepopulated set. - result = std.Target.Cpu{ - .arch = arch, - .model = model, - .features = model.features, - }; - break; - } - } - } - - const all_features = arch.allFeaturesList(); - - if (llvm_cpu_features_opt) |llvm_cpu_features| { - var it = mem.tokenize(mem.spanZ(llvm_cpu_features), ","); - while (it.next()) |decorated_llvm_feat| { - var op: enum { - add, - sub, - } = undefined; - var llvm_feat: []const u8 = undefined; - if (mem.startsWith(u8, decorated_llvm_feat, "+")) { - op = .add; - llvm_feat = decorated_llvm_feat[1..]; - } else if (mem.startsWith(u8, decorated_llvm_feat, "-")) { - op = .sub; - llvm_feat = decorated_llvm_feat[1..]; - } else { - return error.InvalidLlvmCpuFeaturesFormat; - } - for (all_features) |feature, index_usize| { - const this_llvm_name = feature.llvm_name orelse continue; - if (mem.eql(u8, llvm_feat, this_llvm_name)) { - const index = @intCast(std.Target.Cpu.Feature.Set.Index, index_usize); - switch (op) { - .add => result.features.addFeature(index), - .sub => result.features.removeFeature(index), - } - break; - } - } - } - } - - result.features.populateDependencies(all_features); - return result; -} - fn detectNativeTargetInfo(gpa: *Allocator, cross_target: std.zig.CrossTarget) !std.zig.system.NativeTargetInfo { - var info = try std.zig.system.NativeTargetInfo.detect(gpa, cross_target); - if (info.cpu_detection_unimplemented) { - const arch = std.Target.current.cpu.arch; - - // We want to just use detected_info.target but implementing - // CPU model & feature detection is todo so here we rely on LLVM. - // https://github.com/ziglang/zig/issues/4591 - if (!build_options.have_llvm) - fatal("CPU features detection is not yet available for {s} without LLVM extensions", .{@tagName(arch)}); - - const llvm = @import("codegen/llvm/bindings.zig"); - const llvm_cpu_name = llvm.GetHostCPUName(); - const llvm_cpu_features = llvm.GetNativeFeatures(); - info.target.cpu = try detectNativeCpuWithLLVM(arch, llvm_cpu_name, llvm_cpu_features); - cross_target.updateCpuFeatures(&info.target.cpu.features); - info.target.cpu.arch = cross_target.getCpuArch(); - } - return info; + return std.zig.system.NativeTargetInfo.detect(gpa, cross_target); } /// Indicate that we are now terminating with a successful exit code. diff --git a/src/target.zig b/src/target.zig index 1e31f99dc1..c2018db012 100644 --- a/src/target.zig +++ b/src/target.zig @@ -374,3 +374,24 @@ pub fn hasRedZone(target: std.Target) bool { else => false, }; } + +pub fn libcFullLinkFlags(target: std.Target) []const []const u8 { + // The linking order of these is significant and should match the order other + // c compilers such as gcc or clang use. + return switch (target.os.tag) { + .netbsd, .openbsd => &[_][]const u8{ + "-lm", + "-lpthread", + "-lc", + "-lutil", + }, + else => &[_][]const u8{ + "-lm", + "-lpthread", + "-lc", + "-ldl", + "-lrt", + "-lutil", + }, + }; +}