mirror of
https://github.com/ziglang/zig.git
synced 2026-01-20 14:25:16 +00:00
Merge pull request #22067 from alexrp/pie-tests
Add PIC/PIE tests and fix some bugs + some improvements to the test harness
This commit is contained in:
commit
8594f179f9
@ -442,7 +442,7 @@ pub fn build(b: *std.Build) !void {
|
||||
test_step.dependOn(check_fmt);
|
||||
|
||||
const test_cases_step = b.step("test-cases", "Run the main compiler test cases");
|
||||
try tests.addCases(b, test_cases_step, test_filters, target, .{
|
||||
try tests.addCases(b, test_cases_step, test_filters, test_target_filters, target, .{
|
||||
.skip_translate_c = skip_translate_c,
|
||||
.skip_run_translated_c = skip_run_translated_c,
|
||||
}, .{
|
||||
@ -541,13 +541,18 @@ pub fn build(b: *std.Build) !void {
|
||||
enable_ios_sdk,
|
||||
enable_symlinks_windows,
|
||||
));
|
||||
test_step.dependOn(tests.addCAbiTests(b, skip_non_native, skip_release));
|
||||
test_step.dependOn(tests.addCAbiTests(b, .{
|
||||
.test_target_filters = test_target_filters,
|
||||
.skip_non_native = skip_non_native,
|
||||
.skip_release = skip_release,
|
||||
}));
|
||||
test_step.dependOn(tests.addLinkTests(b, enable_macos_sdk, enable_ios_sdk, enable_symlinks_windows));
|
||||
test_step.dependOn(tests.addStackTraceTests(b, test_filters, optimization_modes));
|
||||
test_step.dependOn(tests.addCliTests(b));
|
||||
test_step.dependOn(tests.addAssembleAndLinkTests(b, test_filters, optimization_modes));
|
||||
if (tests.addDebuggerTests(b, .{
|
||||
.test_filters = test_filters,
|
||||
.test_target_filters = test_target_filters,
|
||||
.gdb = b.option([]const u8, "gdb", "path to gdb binary"),
|
||||
.lldb = b.option([]const u8, "lldb", "path to lldb binary"),
|
||||
.optimize_modes = optimization_modes,
|
||||
|
||||
@ -217,6 +217,11 @@ pub const HashHelper = struct {
|
||||
},
|
||||
std.Target.Os.TaggedVersionRange => {
|
||||
switch (x) {
|
||||
.hurd => |hurd| {
|
||||
hh.add(hurd.range.min);
|
||||
hh.add(hurd.range.max);
|
||||
hh.add(hurd.glibc);
|
||||
},
|
||||
.linux => |linux| {
|
||||
hh.add(linux.range.min);
|
||||
hh.add(linux.range.max);
|
||||
|
||||
@ -187,7 +187,6 @@ pub const Os = struct {
|
||||
.hermit,
|
||||
|
||||
.aix,
|
||||
.hurd,
|
||||
.rtems,
|
||||
.zos,
|
||||
|
||||
@ -218,6 +217,7 @@ pub const Os = struct {
|
||||
.vulkan,
|
||||
=> .semver,
|
||||
|
||||
.hurd => .hurd,
|
||||
.linux => .linux,
|
||||
|
||||
.windows => .windows,
|
||||
@ -356,6 +356,21 @@ pub const Os = struct {
|
||||
}
|
||||
};
|
||||
|
||||
pub const HurdVersionRange = struct {
|
||||
range: std.SemanticVersion.Range,
|
||||
glibc: std.SemanticVersion,
|
||||
|
||||
pub inline fn includesVersion(range: HurdVersionRange, ver: std.SemanticVersion) bool {
|
||||
return range.range.includesVersion(ver);
|
||||
}
|
||||
|
||||
/// Checks if system is guaranteed to be at least `version` or older than `version`.
|
||||
/// Returns `null` if a runtime check is required.
|
||||
pub inline fn isAtLeast(range: HurdVersionRange, ver: std.SemanticVersion) ?bool {
|
||||
return range.range.isAtLeast(ver);
|
||||
}
|
||||
};
|
||||
|
||||
pub const LinuxVersionRange = struct {
|
||||
range: std.SemanticVersion.Range,
|
||||
glibc: std.SemanticVersion,
|
||||
@ -400,6 +415,7 @@ pub const Os = struct {
|
||||
pub const VersionRange = union {
|
||||
none: void,
|
||||
semver: std.SemanticVersion.Range,
|
||||
hurd: HurdVersionRange,
|
||||
linux: LinuxVersionRange,
|
||||
windows: WindowsVersion.Range,
|
||||
|
||||
@ -456,9 +472,12 @@ pub const Os = struct {
|
||||
},
|
||||
},
|
||||
.hurd => .{
|
||||
.semver = .{
|
||||
.min = .{ .major = 0, .minor = 9, .patch = 0 },
|
||||
.max = .{ .major = 0, .minor = 9, .patch = 0 },
|
||||
.hurd = .{
|
||||
.range = .{
|
||||
.min = .{ .major = 0, .minor = 9, .patch = 0 },
|
||||
.max = .{ .major = 0, .minor = 9, .patch = 0 },
|
||||
},
|
||||
.glibc = .{ .major = 2, .minor = 28, .patch = 0 },
|
||||
},
|
||||
},
|
||||
.linux => .{
|
||||
@ -632,8 +651,17 @@ pub const Os = struct {
|
||||
pub const TaggedVersionRange = union(enum) {
|
||||
none: void,
|
||||
semver: std.SemanticVersion.Range,
|
||||
hurd: HurdVersionRange,
|
||||
linux: LinuxVersionRange,
|
||||
windows: WindowsVersion.Range,
|
||||
|
||||
pub fn gnuLibCVersion(range: TaggedVersionRange) ?std.SemanticVersion {
|
||||
return switch (range) {
|
||||
.none, .semver, .windows => null,
|
||||
.hurd => |h| h.glibc,
|
||||
.linux => |l| l.glibc,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/// Provides a tagged union. `Target` does not store the tag because it is
|
||||
@ -642,6 +670,7 @@ pub const Os = struct {
|
||||
return switch (os.tag.versionRangeTag()) {
|
||||
.none => .{ .none = {} },
|
||||
.semver => .{ .semver = os.version_range.semver },
|
||||
.hurd => .{ .hurd = os.version_range.hurd },
|
||||
.linux => .{ .linux = os.version_range.linux },
|
||||
.windows => .{ .windows = os.version_range.windows },
|
||||
};
|
||||
@ -651,12 +680,13 @@ pub const Os = struct {
|
||||
/// Returns `null` if a runtime check is required.
|
||||
pub inline fn isAtLeast(os: Os, comptime tag: Tag, ver: switch (tag.versionRangeTag()) {
|
||||
.none => void,
|
||||
.semver, .linux => std.SemanticVersion,
|
||||
.semver, .hurd, .linux => std.SemanticVersion,
|
||||
.windows => WindowsVersion,
|
||||
}) ?bool {
|
||||
return if (os.tag != tag) false else switch (tag.versionRangeTag()) {
|
||||
.none => true,
|
||||
inline .semver,
|
||||
.hurd,
|
||||
.linux,
|
||||
.windows,
|
||||
=> |field| @field(os.version_range, @tagName(field)).isAtLeast(ver),
|
||||
@ -832,6 +862,9 @@ pub const Abi = enum {
|
||||
.mips,
|
||||
.mipsel,
|
||||
=> .musleabi,
|
||||
.mips64,
|
||||
.mips64el,
|
||||
=> .muslabi64,
|
||||
else => .musl,
|
||||
},
|
||||
.rtems => switch (arch) {
|
||||
|
||||
@ -102,7 +102,7 @@ pub fn fromTarget(target: Target) Query {
|
||||
.os_version_min = undefined,
|
||||
.os_version_max = undefined,
|
||||
.abi = target.abi,
|
||||
.glibc_version = if (target.isGnuLibC()) target.os.version_range.linux.glibc else null,
|
||||
.glibc_version = target.os.versionRange().gnuLibCVersion(),
|
||||
.android_api_level = if (target.abi.isAndroid()) target.os.version_range.linux.android else null,
|
||||
};
|
||||
result.updateOsVersionRange(target.os);
|
||||
@ -132,9 +132,9 @@ fn updateOsVersionRange(self: *Query, os: Target.Os) void {
|
||||
.{ .semver = os.version_range.semver.min },
|
||||
.{ .semver = os.version_range.semver.max },
|
||||
},
|
||||
.linux => .{
|
||||
.{ .semver = os.version_range.linux.range.min },
|
||||
.{ .semver = os.version_range.linux.range.max },
|
||||
inline .hurd, .linux => |t| .{
|
||||
.{ .semver = @field(os.version_range, @tagName(t)).range.min },
|
||||
.{ .semver = @field(os.version_range, @tagName(t)).range.max },
|
||||
},
|
||||
.windows => .{
|
||||
.{ .windows = os.version_range.windows.min },
|
||||
@ -544,7 +544,7 @@ fn parseOs(result: *Query, diags: *ParseOptions.Diagnostics, text: []const u8) !
|
||||
const version_text = it.rest();
|
||||
if (version_text.len > 0) switch (tag.versionRangeTag()) {
|
||||
.none => return error.InvalidOperatingSystemVersion,
|
||||
.semver, .linux => range: {
|
||||
.semver, .hurd, .linux => range: {
|
||||
var range_it = mem.splitSequence(u8, version_text, "...");
|
||||
result.os_version_min = .{
|
||||
.semver = parseVersion(range_it.first()) catch |err| switch (err) {
|
||||
|
||||
@ -56,9 +56,8 @@ pub inline fn versionCheck(comptime version: std.SemanticVersion) bool {
|
||||
if (!builtin.link_libc) break :blk false;
|
||||
if (native_abi.isMusl()) break :blk true;
|
||||
if (builtin.target.isGnuLibC()) {
|
||||
const ver = builtin.os.version_range.linux.glibc;
|
||||
const order = ver.order(version);
|
||||
break :blk switch (order) {
|
||||
const ver = builtin.os.versionRange().gnuLibCVersion().?;
|
||||
break :blk switch (ver.order(version)) {
|
||||
.gt, .eq => true,
|
||||
.lt => false,
|
||||
};
|
||||
|
||||
@ -178,7 +178,7 @@ inline fn getDynamicSymbol() [*]elf.Dyn {
|
||||
\\ .hidden _DYNAMIC
|
||||
\\ larl %[ret], 1f
|
||||
\\ ag %[ret], 0(%[ret])
|
||||
\\ b 2f
|
||||
\\ jg 2f
|
||||
\\ 1: .quad _DYNAMIC - .
|
||||
\\ 2:
|
||||
: [ret] "=r" (-> [*]elf.Dyn),
|
||||
|
||||
@ -311,8 +311,8 @@ pub fn resolveTargetQuery(query: Target.Query) DetectError!Target {
|
||||
|
||||
if (query.os_version_min) |min| switch (min) {
|
||||
.none => {},
|
||||
.semver => |semver| switch (os.tag) {
|
||||
.linux => os.version_range.linux.range.min = semver,
|
||||
.semver => |semver| switch (os.tag.versionRangeTag()) {
|
||||
inline .hurd, .linux => |t| @field(os.version_range, @tagName(t)).range.min = semver,
|
||||
else => os.version_range.semver.min = semver,
|
||||
},
|
||||
.windows => |win_ver| os.version_range.windows.min = win_ver,
|
||||
@ -320,15 +320,18 @@ pub fn resolveTargetQuery(query: Target.Query) DetectError!Target {
|
||||
|
||||
if (query.os_version_max) |max| switch (max) {
|
||||
.none => {},
|
||||
.semver => |semver| switch (os.tag) {
|
||||
.linux => os.version_range.linux.range.max = semver,
|
||||
.semver => |semver| switch (os.tag.versionRangeTag()) {
|
||||
inline .hurd, .linux => |t| @field(os.version_range, @tagName(t)).range.max = semver,
|
||||
else => os.version_range.semver.max = semver,
|
||||
},
|
||||
.windows => |win_ver| os.version_range.windows.max = win_ver,
|
||||
};
|
||||
|
||||
if (query.glibc_version) |glibc| {
|
||||
os.version_range.linux.glibc = glibc;
|
||||
switch (os.tag.versionRangeTag()) {
|
||||
inline .hurd, .linux => |t| @field(os.version_range, @tagName(t)).glibc = glibc,
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
if (query.android_api_level) |android| {
|
||||
|
||||
@ -88,10 +88,10 @@ pub fn canBuildLibC(target: std.Target) bool {
|
||||
const ver = target.os.version_range.semver;
|
||||
return ver.min.order(libc.os_ver.?) != .lt;
|
||||
}
|
||||
// Ensure glibc (aka *-linux-gnu) version is supported
|
||||
// Ensure glibc (aka *-(linux,hurd)-gnu) version is supported
|
||||
if (target.isGnuLibC()) {
|
||||
const min_glibc_ver = libc.glibc_min orelse return true;
|
||||
const target_glibc_ver = target.os.version_range.linux.glibc;
|
||||
const target_glibc_ver = target.os.versionRange().gnuLibCVersion().?;
|
||||
return target_glibc_ver.order(min_glibc_ver) != .lt;
|
||||
}
|
||||
return true;
|
||||
|
||||
@ -142,6 +142,40 @@ pub fn append(opts: @This(), buffer: *std.ArrayList(u8)) Allocator.Error!void {
|
||||
|
||||
linux.android,
|
||||
}),
|
||||
.hurd => |hurd| try buffer.writer().print(
|
||||
\\ .hurd = .{{
|
||||
\\ .range = .{{
|
||||
\\ .min = .{{
|
||||
\\ .major = {},
|
||||
\\ .minor = {},
|
||||
\\ .patch = {},
|
||||
\\ }},
|
||||
\\ .max = .{{
|
||||
\\ .major = {},
|
||||
\\ .minor = {},
|
||||
\\ .patch = {},
|
||||
\\ }},
|
||||
\\ }},
|
||||
\\ .glibc = .{{
|
||||
\\ .major = {},
|
||||
\\ .minor = {},
|
||||
\\ .patch = {},
|
||||
\\ }},
|
||||
\\ }}}},
|
||||
\\
|
||||
, .{
|
||||
hurd.range.min.major,
|
||||
hurd.range.min.minor,
|
||||
hurd.range.min.patch,
|
||||
|
||||
hurd.range.max.major,
|
||||
hurd.range.max.minor,
|
||||
hurd.range.max.patch,
|
||||
|
||||
hurd.glibc.major,
|
||||
hurd.glibc.minor,
|
||||
hurd.glibc.patch,
|
||||
}),
|
||||
.windows => |windows| try buffer.writer().print(
|
||||
\\ .windows = .{{
|
||||
\\ .min = {c},
|
||||
|
||||
@ -5315,7 +5315,7 @@ pub fn addCCArgs(
|
||||
|
||||
if (comp.config.link_libc) {
|
||||
if (target.isGnuLibC()) {
|
||||
const target_version = target.os.version_range.linux.glibc;
|
||||
const target_version = target.os.versionRange().gnuLibCVersion().?;
|
||||
const glibc_minor_define = try std.fmt.allocPrint(arena, "-D__GLIBC_MINOR__={d}", .{
|
||||
target_version.minor,
|
||||
});
|
||||
|
||||
@ -245,7 +245,7 @@ pub fn targetTriple(allocator: Allocator, target: std.Target) ![]const u8 {
|
||||
ver.min.minor,
|
||||
ver.min.patch,
|
||||
}),
|
||||
.linux => |ver| try llvm_triple.writer().print("{d}.{d}.{d}", .{
|
||||
inline .linux, .hurd => |ver| try llvm_triple.writer().print("{d}.{d}.{d}", .{
|
||||
ver.range.min.major,
|
||||
ver.range.min.minor,
|
||||
ver.range.min.patch,
|
||||
@ -290,11 +290,15 @@ pub fn targetTriple(allocator: Allocator, target: std.Target) ![]const u8 {
|
||||
.semver,
|
||||
.windows,
|
||||
=> {},
|
||||
.linux => |ver| if (target.abi.isGnu()) try llvm_triple.writer().print("{d}.{d}.{d}", .{
|
||||
ver.glibc.major,
|
||||
ver.glibc.minor,
|
||||
ver.glibc.patch,
|
||||
}) else if (target.abi.isAndroid()) try llvm_triple.writer().print("{d}", .{ver.android}),
|
||||
inline .hurd, .linux => |ver| if (target.abi.isGnu()) {
|
||||
try llvm_triple.writer().print("{d}.{d}.{d}", .{
|
||||
ver.glibc.major,
|
||||
ver.glibc.minor,
|
||||
ver.glibc.patch,
|
||||
});
|
||||
} else if (@TypeOf(ver) == std.Target.Os.LinuxVersionRange and target.abi.isAndroid()) {
|
||||
try llvm_triple.writer().print("{d}", .{ver.android});
|
||||
},
|
||||
}
|
||||
|
||||
return llvm_triple.toOwnedSlice();
|
||||
|
||||
@ -188,7 +188,7 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre
|
||||
const arena = arena_allocator.allocator();
|
||||
|
||||
const target = comp.root_mod.resolved_target.result;
|
||||
const target_ver = target.os.version_range.linux.glibc;
|
||||
const target_ver = target.os.versionRange().gnuLibCVersion().?;
|
||||
const nonshared_stat = target_ver.order(.{ .major = 2, .minor = 32, .patch = 0 }) != .gt;
|
||||
const start_old_init_fini = target_ver.order(.{ .major = 2, .minor = 33, .patch = 0 }) != .gt;
|
||||
|
||||
@ -750,7 +750,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) !voi
|
||||
const arena = arena_allocator.allocator();
|
||||
|
||||
const target = comp.getTarget();
|
||||
const target_version = target.os.version_range.linux.glibc;
|
||||
const target_version = target.os.versionRange().gnuLibCVersion().?;
|
||||
|
||||
// Use the global cache directory.
|
||||
var cache: Cache = .{
|
||||
@ -1218,7 +1218,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) !voi
|
||||
}
|
||||
|
||||
fn queueSharedObjects(comp: *Compilation, so_files: BuiltSharedObjects) void {
|
||||
const target_version = comp.getTarget().os.version_range.linux.glibc;
|
||||
const target_version = comp.getTarget().os.versionRange().gnuLibCVersion().?;
|
||||
|
||||
assert(comp.glibc_so_files == null);
|
||||
comp.glibc_so_files = so_files;
|
||||
|
||||
@ -262,7 +262,7 @@ pub fn buildLibCXX(comp: *Compilation, prog_node: std.Progress.Node) BuildError!
|
||||
|
||||
if (target.isGnuLibC()) {
|
||||
// glibc 2.16 introduced aligned_alloc
|
||||
if (target.os.version_range.linux.glibc.order(.{ .major = 2, .minor = 16, .patch = 0 }) == .lt) {
|
||||
if (target.os.versionRange().gnuLibCVersion().?.order(.{ .major = 2, .minor = 16, .patch = 0 }) == .lt) {
|
||||
try cflags.append("-D_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION");
|
||||
}
|
||||
}
|
||||
@ -477,7 +477,7 @@ pub fn buildLibCXXABI(comp: *Compilation, prog_node: std.Progress.Node) BuildErr
|
||||
}
|
||||
try cflags.append("-D_LIBCXXABI_HAS_NO_THREADS");
|
||||
} else if (target.abi.isGnu()) {
|
||||
if (target.os.tag != .linux or !(target.os.version_range.linux.glibc.order(.{ .major = 2, .minor = 18, .patch = 0 }) == .lt))
|
||||
if (target.os.tag != .linux or !(target.os.versionRange().gnuLibCVersion().?.order(.{ .major = 2, .minor = 18, .patch = 0 }) == .lt))
|
||||
try cflags.append("-DHAVE___CXA_THREAD_ATEXIT_IMPL");
|
||||
}
|
||||
|
||||
@ -500,7 +500,7 @@ pub fn buildLibCXXABI(comp: *Compilation, prog_node: std.Progress.Node) BuildErr
|
||||
|
||||
if (target.isGnuLibC()) {
|
||||
// glibc 2.16 introduced aligned_alloc
|
||||
if (target.os.version_range.linux.glibc.order(.{ .major = 2, .minor = 16, .patch = 0 }) == .lt) {
|
||||
if (target.os.versionRange().gnuLibCVersion().?.order(.{ .major = 2, .minor = 16, .patch = 0 }) == .lt) {
|
||||
try cflags.append("-D_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION");
|
||||
}
|
||||
}
|
||||
|
||||
@ -2013,7 +2013,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
|
||||
} else if (target.isGnuLibC()) {
|
||||
for (glibc.libs) |lib| {
|
||||
if (lib.removed_in) |rem_in| {
|
||||
if (target.os.version_range.linux.glibc.order(rem_in) != .lt) continue;
|
||||
if (target.os.versionRange().gnuLibCVersion().?.order(rem_in) != .lt) continue;
|
||||
}
|
||||
|
||||
const lib_path = try std.fmt.allocPrint(arena, "{}{c}lib{s}.so.{d}", .{
|
||||
|
||||
@ -35,3 +35,4 @@ pub export fn entry() usize {
|
||||
|
||||
// compile
|
||||
// output_mode=Obj
|
||||
// emit_bin=false
|
||||
|
||||
@ -13,4 +13,4 @@ export fn entry() usize {
|
||||
|
||||
// compile
|
||||
// output_mode=Obj
|
||||
// backend=stage2,llvm
|
||||
// emit_bin=false
|
||||
|
||||
14
test/cases/pic_freestanding.zig
Normal file
14
test/cases/pic_freestanding.zig
Normal file
@ -0,0 +1,14 @@
|
||||
const builtin = @import("builtin");
|
||||
const std = @import("std");
|
||||
|
||||
fn _start() callconv(.naked) void {}
|
||||
|
||||
comptime {
|
||||
@export(&_start, .{ .name = if (builtin.cpu.arch.isMIPS()) "__start" else "_start" });
|
||||
}
|
||||
|
||||
// compile
|
||||
// backend=stage2,llvm
|
||||
// target=arm-freestanding,armeb-freestanding,thumb-freestanding,thumbeb-freestanding,aarch64-freestanding,aarch64_be-freestanding,loongarch64-freestanding,mips-freestanding,mipsel-freestanding,mips64-freestanding,mips64el-freestanding,powerpc-freestanding,powerpcle-freestanding,powerpc64-freestanding,powerpc64le-freestanding,riscv32-freestanding,riscv64-freestanding,s390x-freestanding,x86-freestanding,x86_64-freestanding
|
||||
// pic=true
|
||||
// output_mode=Exe
|
||||
14
test/cases/pic_linux.zig
Normal file
14
test/cases/pic_linux.zig
Normal file
@ -0,0 +1,14 @@
|
||||
const std = @import("std");
|
||||
|
||||
// Eventually, this test should be made to work without libc by providing our
|
||||
// own `__tls_get_addr` implementation. powerpcle-linux should be added to the
|
||||
// target list here when that happens.
|
||||
//
|
||||
// https://github.com/ziglang/zig/issues/20625
|
||||
pub fn main() void {}
|
||||
|
||||
// run
|
||||
// backend=stage2,llvm
|
||||
// target=arm-linux,armeb-linux,thumb-linux,thumbeb-linux,aarch64-linux,aarch64_be-linux,loongarch64-linux,mips-linux,mipsel-linux,mips64-linux,mips64el-linux,powerpc-linux,powerpc64-linux,powerpc64le-linux,riscv32-linux,riscv64-linux,s390x-linux,x86-linux,x86_64-linux
|
||||
// pic=true
|
||||
// link_libc=true
|
||||
16
test/cases/pie_freestanding.zig
Normal file
16
test/cases/pie_freestanding.zig
Normal file
@ -0,0 +1,16 @@
|
||||
const builtin = @import("builtin");
|
||||
const std = @import("std");
|
||||
|
||||
// The self-hosted backends currently output a bunch of bad relocations for PIE,
|
||||
// so this test is LLVM only for now.
|
||||
fn _start() callconv(.naked) void {}
|
||||
|
||||
comptime {
|
||||
@export(&_start, .{ .name = if (builtin.cpu.arch.isMIPS()) "__start" else "_start" });
|
||||
}
|
||||
|
||||
// compile
|
||||
// backend=llvm
|
||||
// target=arm-freestanding,armeb-freestanding,thumb-freestanding,thumbeb-freestanding,aarch64-freestanding,aarch64_be-freestanding,loongarch64-freestanding,mips-freestanding,mipsel-freestanding,mips64-freestanding,mips64el-freestanding,powerpc-freestanding,powerpcle-freestanding,powerpc64-freestanding,powerpc64le-freestanding,riscv32-freestanding,riscv64-freestanding,s390x-freestanding,x86-freestanding,x86_64-freestanding
|
||||
// pie=true
|
||||
// output_mode=Exe
|
||||
10
test/cases/pie_linux.zig
Normal file
10
test/cases/pie_linux.zig
Normal file
@ -0,0 +1,10 @@
|
||||
const std = @import("std");
|
||||
|
||||
// The self-hosted backends can't handle `.hidden _DYNAMIC` and `.weak _DYNAMIC`
|
||||
// directives in inline assembly yet, so this test is LLVM only for now.
|
||||
pub fn main() void {}
|
||||
|
||||
// run
|
||||
// backend=llvm
|
||||
// target=arm-linux,armeb-linux,thumb-linux,thumbeb-linux,aarch64-linux,aarch64_be-linux,loongarch64-linux,mips-linux,mipsel-linux,mips64-linux,mips64el-linux,powerpc-linux,powerpcle-linux,powerpc64-linux,powerpc64le-linux,riscv32-linux,riscv64-linux,s390x-linux,x86-linux,x86_64-linux
|
||||
// pie=true
|
||||
@ -14,3 +14,4 @@ export fn a() void {
|
||||
// output_mode=Obj
|
||||
// backend=stage2
|
||||
// target=spirv64-vulkan
|
||||
// emit_bin=false
|
||||
|
||||
@ -5,10 +5,7 @@ const builtin = @import("builtin");
|
||||
// run-time glibc version needs to be new enough. Check the host's glibc
|
||||
// version. Note that this does not allow for translation/vm/emulation
|
||||
// services to run these tests.
|
||||
const running_glibc_ver: ?std.SemanticVersion = switch (builtin.os.tag) {
|
||||
.linux => builtin.os.version_range.linux.glibc,
|
||||
else => null,
|
||||
};
|
||||
const running_glibc_ver = builtin.os.versionRange().gnuLibCVersion();
|
||||
|
||||
pub fn build(b: *std.Build) void {
|
||||
const test_step = b.step("test", "Test");
|
||||
|
||||
@ -21,7 +21,7 @@ const c_string = @cImport(
|
||||
);
|
||||
|
||||
// Version of glibc this test is being built to run against
|
||||
const glibc_ver = builtin.target.os.version_range.linux.glibc;
|
||||
const glibc_ver = builtin.os.versionRange().gnuLibCVersion().?;
|
||||
|
||||
// PR #17034 - fstat moved between libc_nonshared and libc
|
||||
fn checkStat() !void {
|
||||
|
||||
@ -95,6 +95,7 @@ fn addPtx(ctx: *Cases, target: std.Build.ResolvedTarget, name: []const u8) *Case
|
||||
.output_mode = .Obj,
|
||||
.deps = std.ArrayList(Cases.DepModule).init(ctx.cases.allocator),
|
||||
.link_libc = false,
|
||||
.emit_bin = false,
|
||||
.backend = .llvm,
|
||||
// Bug in Debug mode
|
||||
.optimize_mode = .ReleaseSafe,
|
||||
|
||||
@ -88,6 +88,8 @@ pub const Case = struct {
|
||||
expect_exact: bool = false,
|
||||
backend: Backend = .stage2,
|
||||
link_libc: bool = false,
|
||||
pic: ?bool = null,
|
||||
pie: ?bool = null,
|
||||
|
||||
deps: std.ArrayList(DepModule),
|
||||
|
||||
@ -425,6 +427,9 @@ fn addFromDirInner(
|
||||
const is_test = try manifest.getConfigForKeyAssertSingle("is_test", bool);
|
||||
const link_libc = try manifest.getConfigForKeyAssertSingle("link_libc", bool);
|
||||
const output_mode = try manifest.getConfigForKeyAssertSingle("output_mode", std.builtin.OutputMode);
|
||||
const pic = try manifest.getConfigForKeyAssertSingle("pic", ?bool);
|
||||
const pie = try manifest.getConfigForKeyAssertSingle("pie", ?bool);
|
||||
const emit_bin = try manifest.getConfigForKeyAssertSingle("emit_bin", bool);
|
||||
|
||||
if (manifest.type == .translate_c) {
|
||||
for (c_frontends) |c_frontend| {
|
||||
@ -485,9 +490,12 @@ fn addFromDirInner(
|
||||
.target = resolved_target,
|
||||
.backend = backend,
|
||||
.updates = std.ArrayList(Cases.Update).init(ctx.cases.allocator),
|
||||
.emit_bin = emit_bin,
|
||||
.is_test = is_test,
|
||||
.output_mode = output_mode,
|
||||
.link_libc = link_libc,
|
||||
.pic = pic,
|
||||
.pie = pie,
|
||||
.deps = std.ArrayList(DepModule).init(ctx.cases.allocator),
|
||||
});
|
||||
try cases.append(next);
|
||||
@ -539,13 +547,14 @@ pub fn lowerToTranslateCSteps(
|
||||
b: *std.Build,
|
||||
parent_step: *std.Build.Step,
|
||||
test_filters: []const []const u8,
|
||||
test_target_filters: []const []const u8,
|
||||
target: std.Build.ResolvedTarget,
|
||||
translate_c_options: TranslateCOptions,
|
||||
) void {
|
||||
const tests = @import("../tests.zig");
|
||||
const test_translate_c_step = b.step("test-translate-c", "Run the C translation tests");
|
||||
if (!translate_c_options.skip_translate_c) {
|
||||
tests.addTranslateCTests(b, test_translate_c_step, test_filters);
|
||||
tests.addTranslateCTests(b, test_translate_c_step, test_filters, test_target_filters);
|
||||
parent_step.dependOn(test_translate_c_step);
|
||||
}
|
||||
|
||||
@ -620,6 +629,7 @@ pub fn lowerToBuildSteps(
|
||||
b: *std.Build,
|
||||
parent_step: *std.Build.Step,
|
||||
test_filters: []const []const u8,
|
||||
test_target_filters: []const []const u8,
|
||||
) void {
|
||||
const host = std.zig.system.resolveTargetQuery(.{}) catch |err|
|
||||
std.debug.panic("unable to detect native host: {s}\n", .{@errorName(err)});
|
||||
@ -648,6 +658,14 @@ pub fn lowerToBuildSteps(
|
||||
if (std.mem.indexOf(u8, case.name, test_filter)) |_| break;
|
||||
} else if (test_filters.len > 0) continue;
|
||||
|
||||
const triple_txt = case.target.result.zigTriple(b.allocator) catch @panic("OOM");
|
||||
|
||||
if (test_target_filters.len > 0) {
|
||||
for (test_target_filters) |filter| {
|
||||
if (std.mem.indexOf(u8, triple_txt, filter) != null) break;
|
||||
} else continue;
|
||||
}
|
||||
|
||||
const writefiles = b.addWriteFiles();
|
||||
var file_sources = std.StringHashMap(std.Build.LazyPath).init(b.allocator);
|
||||
defer file_sources.deinit();
|
||||
@ -685,6 +703,8 @@ pub fn lowerToBuildSteps(
|
||||
};
|
||||
|
||||
if (case.link_libc) artifact.linkLibC();
|
||||
if (case.pic) |pic| artifact.root_module.pic = pic;
|
||||
if (case.pie) |pie| artifact.pie = pie;
|
||||
|
||||
switch (case.backend) {
|
||||
.stage1 => continue,
|
||||
@ -705,6 +725,10 @@ pub fn lowerToBuildSteps(
|
||||
|
||||
switch (update.case) {
|
||||
.Compile => {
|
||||
// Force the binary to be emitted if requested.
|
||||
if (case.emit_bin) {
|
||||
_ = artifact.getEmittedBin();
|
||||
}
|
||||
parent_step.dependOn(&artifact.step);
|
||||
},
|
||||
.CompareObjectFile => |expected_output| {
|
||||
@ -740,7 +764,7 @@ pub fn lowerToBuildSteps(
|
||||
"--",
|
||||
"-lc",
|
||||
"-target",
|
||||
case.target.result.zigTriple(b.allocator) catch @panic("OOM"),
|
||||
triple_txt,
|
||||
});
|
||||
run_c.addArtifactArg(artifact);
|
||||
break :run_step run_c;
|
||||
@ -942,12 +966,18 @@ const TestManifestConfigDefaults = struct {
|
||||
.run_translated_c => "Obj",
|
||||
.cli => @panic("TODO test harness for CLI tests"),
|
||||
};
|
||||
} else if (std.mem.eql(u8, key, "emit_bin")) {
|
||||
return "true";
|
||||
} else if (std.mem.eql(u8, key, "is_test")) {
|
||||
return "false";
|
||||
} else if (std.mem.eql(u8, key, "link_libc")) {
|
||||
return "false";
|
||||
} else if (std.mem.eql(u8, key, "c_frontend")) {
|
||||
return "clang";
|
||||
} else if (std.mem.eql(u8, key, "pic")) {
|
||||
return "null";
|
||||
} else if (std.mem.eql(u8, key, "pie")) {
|
||||
return "null";
|
||||
} else unreachable;
|
||||
}
|
||||
};
|
||||
@ -975,12 +1005,15 @@ const TestManifest = struct {
|
||||
trailing_bytes: []const u8 = "",
|
||||
|
||||
const valid_keys = std.StaticStringMap(void).initComptime(.{
|
||||
.{ "emit_bin", {} },
|
||||
.{ "is_test", {} },
|
||||
.{ "output_mode", {} },
|
||||
.{ "target", {} },
|
||||
.{ "c_frontend", {} },
|
||||
.{ "link_libc", {} },
|
||||
.{ "backend", {} },
|
||||
.{ "pic", {} },
|
||||
.{ "pie", {} },
|
||||
});
|
||||
|
||||
const Type = enum {
|
||||
@ -1209,7 +1242,12 @@ const TestManifest = struct {
|
||||
};
|
||||
}
|
||||
}.parse,
|
||||
.@"struct" => @compileError("no default parser for " ++ @typeName(T)),
|
||||
.optional => |o| return struct {
|
||||
fn parse(str: []const u8) anyerror!T {
|
||||
if (std.mem.eql(u8, str, "null")) return null;
|
||||
return try getDefaultParser(o.child)(str);
|
||||
}
|
||||
}.parse,
|
||||
else => @compileError("no default parser for " ++ @typeName(T)),
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@ root_step: *std.Build.Step,
|
||||
|
||||
pub const Options = struct {
|
||||
test_filters: []const []const u8,
|
||||
test_target_filters: []const []const u8,
|
||||
gdb: ?[]const u8,
|
||||
lldb: ?[]const u8,
|
||||
optimize_modes: []const std.builtin.OptimizeMode,
|
||||
@ -2406,6 +2407,12 @@ fn addTest(
|
||||
for (db.options.test_filters) |test_filter| {
|
||||
if (std.mem.indexOf(u8, name, test_filter)) |_| return;
|
||||
}
|
||||
if (db.options.test_target_filters.len > 0) {
|
||||
const triple_txt = target.resolved.result.zigTriple(db.b.allocator) catch @panic("OOM");
|
||||
for (db.options.test_target_filters) |filter| {
|
||||
if (std.mem.indexOf(u8, triple_txt, filter) != null) break;
|
||||
} else return;
|
||||
}
|
||||
const files_wf = db.b.addWriteFiles();
|
||||
const exe = db.b.addExecutable(.{
|
||||
.name = name,
|
||||
|
||||
@ -2,6 +2,7 @@ b: *std.Build,
|
||||
step: *std.Build.Step,
|
||||
test_index: usize,
|
||||
test_filters: []const []const u8,
|
||||
test_target_filters: []const []const u8,
|
||||
|
||||
const TestCase = struct {
|
||||
name: []const u8,
|
||||
@ -92,6 +93,16 @@ pub fn addCase(self: *TranslateCContext, case: *const TestCase) void {
|
||||
if (mem.indexOf(u8, annotated_case_name, test_filter)) |_| break;
|
||||
} else if (self.test_filters.len > 0) return;
|
||||
|
||||
const target = b.resolveTargetQuery(case.target);
|
||||
|
||||
if (self.test_target_filters.len > 0) {
|
||||
const triple_txt = target.result.zigTriple(b.allocator) catch @panic("OOM");
|
||||
|
||||
for (self.test_target_filters) |filter| {
|
||||
if (std.mem.indexOf(u8, triple_txt, filter) != null) break;
|
||||
} else return;
|
||||
}
|
||||
|
||||
const write_src = b.addWriteFiles();
|
||||
const first_src = case.sources.items[0];
|
||||
const root_source_file = write_src.add(first_src.filename, first_src.source);
|
||||
@ -101,7 +112,7 @@ pub fn addCase(self: *TranslateCContext, case: *const TestCase) void {
|
||||
|
||||
const translate_c = b.addTranslateC(.{
|
||||
.root_source_file = root_source_file,
|
||||
.target = b.resolveTargetQuery(case.target),
|
||||
.target = target,
|
||||
.optimize = .Debug,
|
||||
});
|
||||
|
||||
|
||||
@ -1237,18 +1237,22 @@ pub fn addAssembleAndLinkTests(b: *std.Build, test_filters: []const []const u8,
|
||||
return cases.step;
|
||||
}
|
||||
|
||||
pub fn addTranslateCTests(b: *std.Build, parent_step: *std.Build.Step, test_filters: []const []const u8) void {
|
||||
pub fn addTranslateCTests(
|
||||
b: *std.Build,
|
||||
parent_step: *std.Build.Step,
|
||||
test_filters: []const []const u8,
|
||||
test_target_filters: []const []const u8,
|
||||
) void {
|
||||
const cases = b.allocator.create(TranslateCContext) catch @panic("OOM");
|
||||
cases.* = TranslateCContext{
|
||||
.b = b,
|
||||
.step = parent_step,
|
||||
.test_index = 0,
|
||||
.test_filters = test_filters,
|
||||
.test_target_filters = test_target_filters,
|
||||
};
|
||||
|
||||
translate_c.addCases(cases);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
pub fn addRunTranslatedCTests(
|
||||
@ -1267,8 +1271,6 @@ pub fn addRunTranslatedCTests(
|
||||
};
|
||||
|
||||
run_translated_c.addCases(cases);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const ModuleTestOptions = struct {
|
||||
@ -1486,19 +1488,32 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
|
||||
return step;
|
||||
}
|
||||
|
||||
pub fn addCAbiTests(b: *std.Build, skip_non_native: bool, skip_release: bool) *Step {
|
||||
const CAbiTestOptions = struct {
|
||||
test_target_filters: []const []const u8,
|
||||
skip_non_native: bool,
|
||||
skip_release: bool,
|
||||
};
|
||||
|
||||
pub fn addCAbiTests(b: *std.Build, options: CAbiTestOptions) *Step {
|
||||
const step = b.step("test-c-abi", "Run the C ABI tests");
|
||||
|
||||
const optimize_modes: [3]OptimizeMode = .{ .Debug, .ReleaseSafe, .ReleaseFast };
|
||||
|
||||
for (optimize_modes) |optimize_mode| {
|
||||
if (optimize_mode != .Debug and skip_release) continue;
|
||||
if (optimize_mode != .Debug and options.skip_release) continue;
|
||||
|
||||
for (c_abi_targets) |c_abi_target| {
|
||||
if (skip_non_native and !c_abi_target.target.isNative()) continue;
|
||||
if (options.skip_non_native and !c_abi_target.target.isNative()) continue;
|
||||
|
||||
const resolved_target = b.resolveTargetQuery(c_abi_target.target);
|
||||
const target = resolved_target.result;
|
||||
const triple_txt = target.zigTriple(b.allocator) catch @panic("OOM");
|
||||
|
||||
if (options.test_target_filters.len > 0) {
|
||||
for (options.test_target_filters) |filter| {
|
||||
if (std.mem.indexOf(u8, triple_txt, filter) != null) break;
|
||||
} else continue;
|
||||
}
|
||||
|
||||
if (target.os.tag == .windows and target.cpu.arch == .aarch64) {
|
||||
// https://github.com/ziglang/zig/issues/14908
|
||||
@ -1507,7 +1522,7 @@ pub fn addCAbiTests(b: *std.Build, skip_non_native: bool, skip_release: bool) *S
|
||||
|
||||
const test_step = b.addTest(.{
|
||||
.name = b.fmt("test-c-abi-{s}-{s}-{s}{s}{s}{s}", .{
|
||||
target.zigTriple(b.allocator) catch @panic("OOM"),
|
||||
triple_txt,
|
||||
target.cpu.model.name,
|
||||
@tagName(optimize_mode),
|
||||
if (c_abi_target.use_llvm == true)
|
||||
@ -1552,6 +1567,7 @@ pub fn addCases(
|
||||
b: *std.Build,
|
||||
parent_step: *Step,
|
||||
test_filters: []const []const u8,
|
||||
test_target_filters: []const []const u8,
|
||||
target: std.Build.ResolvedTarget,
|
||||
translate_c_options: @import("src/Cases.zig").TranslateCOptions,
|
||||
build_options: @import("cases.zig").BuildOptions,
|
||||
@ -1567,12 +1583,13 @@ pub fn addCases(
|
||||
cases.addFromDir(dir, b);
|
||||
try @import("cases.zig").addCases(&cases, build_options, b);
|
||||
|
||||
cases.lowerToTranslateCSteps(b, parent_step, test_filters, target, translate_c_options);
|
||||
cases.lowerToTranslateCSteps(b, parent_step, test_filters, test_target_filters, target, translate_c_options);
|
||||
|
||||
cases.lowerToBuildSteps(
|
||||
b,
|
||||
parent_step,
|
||||
test_filters,
|
||||
test_target_filters,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user