mirror of
https://github.com/ziglang/zig.git
synced 2026-01-20 22:35:24 +00:00
link-tests: add checkNotPresent and add -dead_strip smoke test
`checkNotPresent` is the inverse of `checkNext` - if the phrase is found in the output, then it fails the test.
This commit is contained in:
parent
2dfc78dc03
commit
2c184f9a5f
@ -50,7 +50,7 @@ pub fn create(builder: *Builder, source: build.FileSource, obj_format: std.Targe
|
||||
/// For example, if the two extracted values were saved as `vmaddr` and `entryoff` respectively
|
||||
/// they could then be added with this simple program `vmaddr entryoff +`.
|
||||
const Action = struct {
|
||||
tag: enum { match, compute_cmp },
|
||||
tag: enum { match, not_present, compute_cmp },
|
||||
phrase: []const u8,
|
||||
expected: ?ComputeCompareExpected = null,
|
||||
|
||||
@ -63,7 +63,7 @@ const Action = struct {
|
||||
/// name {*}libobjc{*}.dylib => will match `name` followed by a token which contains `libobjc` and `.dylib`
|
||||
/// in that order with other letters in between
|
||||
fn match(act: Action, haystack: []const u8, global_vars: anytype) !bool {
|
||||
assert(act.tag == .match);
|
||||
assert(act.tag == .match or act.tag == .not_present);
|
||||
|
||||
var candidate_var: ?struct { name: []const u8, value: u64 } = null;
|
||||
var hay_it = mem.tokenize(u8, mem.trim(u8, haystack, " "), " ");
|
||||
@ -202,6 +202,13 @@ const Check = struct {
|
||||
}) catch unreachable;
|
||||
}
|
||||
|
||||
fn notPresent(self: *Check, phrase: []const u8) void {
|
||||
self.actions.append(.{
|
||||
.tag = .not_present,
|
||||
.phrase = self.builder.dupe(phrase),
|
||||
}) catch unreachable;
|
||||
}
|
||||
|
||||
fn computeCmp(self: *Check, phrase: []const u8, expected: ComputeCompareExpected) void {
|
||||
self.actions.append(.{
|
||||
.tag = .compute_cmp,
|
||||
@ -226,6 +233,15 @@ pub fn checkNext(self: *CheckObjectStep, phrase: []const u8) void {
|
||||
last.match(phrase);
|
||||
}
|
||||
|
||||
/// Adds another searched phrase to the latest created Check with `CheckObjectStep.checkStart(...)`
|
||||
/// however ensures there is no matching phrase in the output.
|
||||
/// Asserts at least one check already exists.
|
||||
pub fn checkNotPresent(self: *CheckObjectStep, phrase: []const u8) void {
|
||||
assert(self.checks.items.len > 0);
|
||||
const last = &self.checks.items[self.checks.items.len - 1];
|
||||
last.notPresent(phrase);
|
||||
}
|
||||
|
||||
/// Creates a new check checking specifically symbol table parsed and dumped from the object
|
||||
/// file.
|
||||
/// Issuing this check will force parsing and dumping of the symbol table.
|
||||
@ -293,6 +309,21 @@ fn make(step: *Step) !void {
|
||||
return error.TestFailed;
|
||||
}
|
||||
},
|
||||
.not_present => {
|
||||
while (it.next()) |line| {
|
||||
if (try act.match(line, &vars)) {
|
||||
std.debug.print(
|
||||
\\
|
||||
\\========= Expected not to find: ===================
|
||||
\\{s}
|
||||
\\========= But parsed file does contain it: ========
|
||||
\\{s}
|
||||
\\
|
||||
, .{ act.phrase, output });
|
||||
return error.TestFailed;
|
||||
}
|
||||
}
|
||||
},
|
||||
.compute_cmp => {
|
||||
const res = act.computeCmp(gpa, vars) catch |err| switch (err) {
|
||||
error.UnknownVariable => {
|
||||
|
||||
@ -60,6 +60,10 @@ pub fn addCases(cases: *tests.StandaloneContext) void {
|
||||
.build_modes = true,
|
||||
});
|
||||
|
||||
cases.addBuildFile("test/link/macho/dead_strip/build.zig", .{
|
||||
.build_modes = false,
|
||||
});
|
||||
|
||||
cases.addBuildFile("test/link/macho/dead_strip_dylibs/build.zig", .{
|
||||
.build_modes = true,
|
||||
.requires_macos_sdk = true,
|
||||
|
||||
49
test/link/macho/dead_strip/build.zig
Normal file
49
test/link/macho/dead_strip/build.zig
Normal file
@ -0,0 +1,49 @@
|
||||
const std = @import("std");
|
||||
const Builder = std.build.Builder;
|
||||
const LibExeObjectStep = std.build.LibExeObjStep;
|
||||
|
||||
pub fn build(b: *Builder) void {
|
||||
const mode = b.standardReleaseOptions();
|
||||
|
||||
const test_step = b.step("test", "Test the program");
|
||||
test_step.dependOn(b.getInstallStep());
|
||||
|
||||
{
|
||||
// Without -dead_strip, we expect `iAmUnused` symbol present
|
||||
const exe = createScenario(b, mode);
|
||||
|
||||
const check = exe.checkObject(.macho);
|
||||
check.checkInSymtab();
|
||||
check.checkNext("{*} (__TEXT,__text) external _iAmUnused");
|
||||
|
||||
test_step.dependOn(&check.step);
|
||||
|
||||
const run_cmd = exe.run();
|
||||
run_cmd.expectStdOutEqual("Hello!\n");
|
||||
test_step.dependOn(&run_cmd.step);
|
||||
}
|
||||
|
||||
{
|
||||
// With -dead_strip, no `iAmUnused` symbol should be present
|
||||
const exe = createScenario(b, mode);
|
||||
exe.link_gc_sections = true;
|
||||
|
||||
const check = exe.checkObject(.macho);
|
||||
check.checkInSymtab();
|
||||
check.checkNotPresent("{*} (__TEXT,__text) external _iAmUnused");
|
||||
|
||||
test_step.dependOn(&check.step);
|
||||
|
||||
const run_cmd = exe.run();
|
||||
run_cmd.expectStdOutEqual("Hello!\n");
|
||||
test_step.dependOn(&run_cmd.step);
|
||||
}
|
||||
}
|
||||
|
||||
fn createScenario(b: *Builder, mode: std.builtin.Mode) *LibExeObjectStep {
|
||||
const exe = b.addExecutable("test", null);
|
||||
exe.addCSourceFile("main.c", &[0][]const u8{});
|
||||
exe.setBuildMode(mode);
|
||||
exe.linkLibC();
|
||||
return exe;
|
||||
}
|
||||
14
test/link/macho/dead_strip/main.c
Normal file
14
test/link/macho/dead_strip/main.c
Normal file
@ -0,0 +1,14 @@
|
||||
#include <stdio.h>
|
||||
|
||||
void printMe() {
|
||||
printf("Hello!\n");
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
printMe();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void iAmUnused() {
|
||||
printf("YOU SHALL NOT PASS!\n");
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user