mirror of
https://github.com/ziglang/zig.git
synced 2025-12-26 16:13:07 +00:00
Merge branch 'master' into streamline-stage2-build-script
This commit is contained in:
commit
1aee896cae
@ -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");
|
||||
|
||||
188
lib/std/mem.zig
188
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
|
||||
|
||||
@ -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) ++ "'");
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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());
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
94
src/main.zig
94
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.
|
||||
|
||||
@ -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",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user