From c0369575218d3dccb69f62495de31c8e22d41ae9 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Tue, 11 May 2021 22:21:22 +0200 Subject: [PATCH 1/9] std.meta.Elem: support all optional types --- lib/std/meta.zig | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/lib/std/meta.zig b/lib/std/meta.zig index 391b7259e3c4d6b4b30a976c1954d958736ff515..473d4fcf26c627562652480123e62a969b42a67f 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) ++ "'"); -- 2.54.0 From cd7b5a37186332e90fee91dd366cba46e3c29ca0 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Thu, 6 May 2021 18:33:21 +0200 Subject: [PATCH 2/9] std/mem: add sliceTo(), deprecate spanZ(), lenZ() The current spanZ() function will not scan for a 0 terminator if the type is not 0 terminated. This encourages using 0 terminated array types to bind C arrays which hold 0 terminated strings. However, this is a big footgun as nothing in the C type system guarantees there to be a 0 terminator at the end of the array and if there is none this becomes Illegal Behavior in Zig. To solve this, deprecate spanZ() and lenZ(), adding a new sliceTo() function that always scans for the given terminator even if the type is not sentinel terminated. --- lib/std/mem.zig | 188 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 188 insertions(+) diff --git a/lib/std/mem.zig b/lib/std/mem.zig index df91adddb26e646989e9768f3b5a797636a6c0ac..aeec384da181362a2db18da311f8657f9e8b32f5 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 -- 2.54.0 From 7b7724628974067f1a66069699fd1433d32da50d Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Wed, 12 May 2021 15:17:21 +0200 Subject: [PATCH 3/9] macho: allow overriding stack size in binary --- src/link/MachO.zig | 5 ++++- src/link/MachO/Zld.zig | 12 +++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 09414b4cddafb24c6ac9d13064f3719956c291f4..2ae9575b7e569e9ac76726efdd21316aba1699e5 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 3904192995489bb36934b8819ef27764e881f3b5..c619d0634b0ae6fc98be495089d20181a09b6dbd 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 { -- 2.54.0 From 893a4286569c9250c29eec8d1cff386ddbf38b3c Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Wed, 12 May 2021 11:26:37 +0200 Subject: [PATCH 4/9] stage2: Drop LLVM's host CPU detection method as fallback The CPU detection code is nearly at feature parity, we do support detecting the native CPU on Sparc systems and macos, our ARM/AArch64 model list is quite comprehensive and so is our PPC one. The only missing pieces are: - ARM32 detection on Darwin hosts (I don't think anybody is planning on running the compiler on a old-ass iPhone) - s390x detection on Linux hosts, this can be easily added at a later stage. --- lib/std/zig/system.zig | 9 ----- src/main.zig | 82 +----------------------------------------- 2 files changed, 1 insertion(+), 90 deletions(-) diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig index 5522367d36469574873a62cdcf90e277cd10049e..c504f93efd27411a39b5436f2b3944190236dcd9 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/main.zig b/src/main.zig index a0a11bbbbcb48edae9803c7319f9fadc3e1756fd..dc98044642e21ae4a2a21d027fc752bcb7104932 100644 --- a/src/main.zig +++ b/src/main.zig @@ -3396,88 +3396,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. -- 2.54.0 From 19aab5302c71edccae7959065062fd1695a396aa Mon Sep 17 00:00:00 2001 From: Evan Haas Date: Fri, 30 Apr 2021 23:07:40 -0700 Subject: [PATCH 5/9] translate-c: Ensure extra_cflags are passed to clang Additionally ensure that the Zig cache incorporates any extra cflags when using translate-c. Fixes the issue identified in #8662 --- src/Cache.zig | 21 ++++++++++++++++++++- src/Compilation.zig | 18 +----------------- src/main.zig | 12 ++++++++---- 3 files changed, 29 insertions(+), 22 deletions(-) diff --git a/src/Cache.zig b/src/Cache.zig index 5bc32b4b68bd401922f314b621bfd6a9f873a175..6c17f52d695030a465a0794ccd3c7a8fc7bcadf4 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 71df7768551b1fb358ecbbf42f9ff8f25ad0f223..6a9f75acf59d6c0f8d7f318ce732f350e55960c3 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: { diff --git a/src/main.zig b/src/main.zig index dc98044642e21ae4a2a21d027fc752bcb7104932..bd57c1f14f0830f1af30f8a819b6083d856634af 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); -- 2.54.0 From 40a47eae65b918866abc9d745f89d837f6a1e591 Mon Sep 17 00:00:00 2001 From: Matthew Borkowski Date: Sun, 9 May 2021 01:13:18 -0400 Subject: [PATCH 6/9] fix shrinkAndFree and remove shrinkRetainingCapacity in PriorityQueue and PriorityDequeue --- lib/std/priority_dequeue.zig | 17 +---------------- lib/std/priority_queue.zig | 17 +---------------- 2 files changed, 2 insertions(+), 32 deletions(-) diff --git a/lib/std/priority_dequeue.zig b/lib/std/priority_dequeue.zig index f0f8d7f6f74b7b1442a4301e55b131b69c49f797..0bb1f1350356f50e43188e99e3e58cba989f1994 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 621af4e97f1273bad55b346097b018ca4079d826..4e5320a92b7d4caeeb423d859d23a07a39ebe555 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); -- 2.54.0 From 799d1f0d36f69c8aead5184a76f87b557d690d7b Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 12 May 2021 20:34:54 -0700 Subject: [PATCH 7/9] build system: fix wrong glibc dir passed to qemu for i386 Without this, and with `-Denable-qemu -Denable-foreign-glibc`, i386-linux-gnu tests failed because the `-L` path passed to qemu was "i386-linux-gnu" (nonexistent) rather than "i686-linux-gnu". Fixes std lib and behavior tests when using these options to enable test coverage with cross compiled glibcs. --- lib/std/build.zig | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/lib/std/build.zig b/lib/std/build.zig index 1bdd97b253793e2c97bd9a6700a784c2b9bb4e64..9d12a4de51fa33815dcdfc0a9dbf330cc9a08de6 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"); -- 2.54.0 From 459c9f05359e3405f39e4c954c62c61a493e49ae Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Wed, 12 May 2021 22:39:10 +0200 Subject: [PATCH 8/9] stage2: fix build on OpenBSD/NetBSD Apparently these systems do not provide libdl or librt. --- src/link/Elf.zig | 10 +--------- src/target.zig | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 91ee6f3206e6e60d545db4350f686325ed3519db..9a0aeabe6cc719ceeaaafe830f857cbcabd1f12b 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -1650,15 +1650,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { if (self.base.options.libc_installation != null) { 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/target.zig b/src/target.zig index 1e31f99dc18f001daeaeffbf4f83301d9412d237..c2018db0127feb0388bdcec22525a2f47f0c155b 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", + }, + }; +} -- 2.54.0 From 4b59f564344598b4d1f1a51839a4dc5cbf357012 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 12 May 2021 22:25:20 -0700 Subject: [PATCH 9/9] stage2: build and provide libunwind when compiling for native libc 5ac91794cce8bd53916a378815be01e4365d53d9 made Zig link against the system libc when targeting the native C ABI. However this made it stop putting libunwind.a on the linker line when it needed to sometimes, causing undefined symbols when linking against C++ code. --- src/Compilation.zig | 1 - src/link/Elf.zig | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Compilation.zig b/src/Compilation.zig index 6a9f75acf59d6c0f8d7f318ce732f350e55960c3..b14e598f71512836707cfcab2fd8c2f376ca9aa6 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -3023,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 9a0aeabe6cc719ceeaaafe830f857cbcabd1f12b..fbbe40022a7d081a7337571746bba34532375e46 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -1648,6 +1648,9 @@ 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"); try argv.appendSlice(target_util.libcFullLinkFlags(target)); -- 2.54.0