Files

342 lines
11 KiB
Zig

pub fn addCases(ctx: *LinkContext) void {
if (ctx.target.result.isMinGW())
@import("link/mingw.zig").addCases(ctx);
if (ctx.includeTest("static-lib")) |case| {
const obj1 = case.addObject(.{
.name = "obj1",
.name_prefix = false,
.name_target = false,
.use_llvm = true,
.use_lld = true,
.c_source_bytes =
\\int foo1 = 1;
\\int foo2 = 2;
\\unsigned int fooBar() {
\\ return foo1 + foo2;
\\}
,
});
const obj2 = case.addObject(.{
.name = "this_is_a_long_name",
.name_prefix = false,
.name_target = false,
.zig_source_bytes =
\\fn fooWeak() callconv(.c) usize {
\\ return 0xaabbccddaabbccdd;
\\}
\\export var foo_array: [2]u16 = .{ 0xffff, 0xabcd };
\\export var foo_strong: usize = 0x1122334411223344;
\\comptime {
\\ @export(&fooWeak, .{ .name = "fooWeak", .linkage = .weak });
\\ @export(&foo_strong, .{ .name = "foo_strong_alias", .linkage = .strong });
\\}
,
});
const lib = case.addLibrary(.static, .{
.name = "lib",
.name_prefix = false,
.name_target = false,
});
lib.root_module.addObject(obj1);
lib.root_module.addObject(obj2);
case.verifyObjdump(lib.getEmittedBin(), &.{
"-s",
"--elements=file-type",
"--symbols",
"--only-symbol=foo",
}, .{ .use_llvm = true });
const exe = case.addExecutable(.{
.name = "test",
.zig_source_bytes =
\\extern fn fooBar() c_uint;
\\extern fn fooWeak() usize;
\\extern var foo_array: [2]u16;
\\extern var foo_strong: usize;
\\extern var foo_strong_alias: usize;
\\pub fn main() !u8 {
\\ return @intFromBool(0xcd003365cd00df35 != fooBar() +
\\ fooWeak() +
\\ foo_array[1] +
\\ foo_strong +
\\ foo_strong_alias);
\\}
,
});
exe.root_module.linkLibrary(lib);
const run = case.addRunArtifact(exe);
run.addCheck(.{ .expect_term = .{ .exited = 0 } });
}
if (ctx.includeTest("tls")) |case| {
const obj = case.addObject(.{
.name = "obj",
.zig_source_bytes =
\\threadlocal var threadlocal_var: u32 = 1234;
\\threadlocal var threadlocal_arr: [4]u16 = .{ 0x1111, 0x2222, 0x3333, 0x4444, };
\\export fn threadlocal_read(a: *u32, b: *u16) void {
\\ a.* = threadlocal_var;
\\ b.* = threadlocal_arr[3];
\\}
\\export fn threadlocal_write(a: u32, b: u16) void {
\\ threadlocal_var = a;
\\ threadlocal_arr[3] = b;
\\}
,
});
case.verifyObjdump(obj.getEmittedBin(), &.{
"-s",
"--symbols",
"--only-symbol=threadlocal",
"--only-symbol=tls",
}, .{ .use_llvm = true });
const exe = case.addExecutable(.{
.name = "test",
.zig_source_bytes =
\\extern fn threadlocal_read(a: *u32, b: *u16) void;
\\extern fn threadlocal_write(a: u32, b: u16) void;
\\threadlocal var threadlocal_foo: u64 = 0xcafecafecafecafe;
\\pub fn main() !u8 {
\\ var a: u32 = undefined;
\\ var b: u16 = undefined;
\\ threadlocal_read(&a, &b);
\\ if (a != 1234 or b != 0x4444) return 1;
\\ if (threadlocal_foo != 0xcafecafecafecafe) return 2;
\\ threadlocal_write(0xabcdabcd, 0x5555);
\\ threadlocal_foo = 1;
\\ threadlocal_read(&a, &b);
\\ if (a != 0xabcdabcd or b != 0x5555) return 3;
\\ if (threadlocal_foo != 1) return 4;
\\ return 0;
\\}
,
});
exe.root_module.addObject(obj);
const run = case.addRunArtifact(exe);
run.addCheck(.{ .expect_term = .{ .exited = 0 } });
}
if (ctx.includeTest("dynamic-lib-code")) |case| {
const lib = case.addLibrary(.dynamic, .{
.name = "lib",
.name_target = false,
.zig_source_bytes =
\\export fn foo1() callconv(.c) u64 {
\\ return 0x1122334411223344;
\\}
\\export fn foo2() callconv(.c) u64 {
\\ return 0xaabbccddaabbccdd;
\\}
,
});
case.verifyObjdump(lib.getEmittedBin(), &.{
"-s",
"--exports",
"--only-symbol=foo",
}, .{ .os = true });
if (ctx.target.result.os.tag == .windows) {
case.verifyObjdump(lib.getEmittedImplib(), &.{
"-s",
"--exports=sort",
"--only-symbol=foo",
}, .{ .sub_name = "implib", .os = true, .arch = true });
}
const exe = case.addExecutable(.{
.name = "test",
.zig_source_bytes =
\\extern fn foo1() u64;
\\pub fn main() !u8 {
\\ const foo2 = @extern(
\\ *const fn () callconv(.c) u64,
\\ .{ .name = "foo2", .is_dll_import = true },
\\ );
\\ return @intFromBool(0xbbde0021bbde0021 != foo1() + foo2());
\\}
,
});
exe.root_module.linkLibrary(lib);
const run = case.addRunArtifact(exe);
run.addCheck(.{ .expect_term = .{ .exited = 0 } });
}
if (ctx.includeTest("dynamic-lib-data")) |case| {
const lib = case.addLibrary(.dynamic, .{
.name = "lib",
.name_target = false,
.zig_source_bytes =
\\export var foo_array: [2]u16 = .{ 0xffff, 0xabcd };
\\export var foo_strong: usize = 0x1122334411223344;
\\comptime {
\\ @export(&foo_strong, .{ .name = "foo_strong_alias", .linkage = .strong });
\\}
,
});
case.verifyObjdump(lib.getEmittedBin(), &.{
"-s",
"--exports",
"--only-symbol=foo",
}, .{});
if (ctx.target.result.os.tag == .windows) {
case.verifyObjdump(lib.getEmittedImplib(), &.{
"-s",
"--exports=sort",
"--only-symbol=foo",
}, .{ .sub_name = "implib", .os = true, .arch = true });
}
const exe = case.addExecutable(.{
.name = "test",
.zig_source_bytes =
\\pub fn main() !u8 {
\\ const foo_array = @extern(*[2]u16, .{ .name = "foo_array", .is_dll_import = true });
\\ const foo_strong = @extern(*usize, .{ .name = "foo_strong", .is_dll_import = true });
\\ const foo_strong_alias = @extern(*usize, .{ .name = "foo_strong_alias", .is_dll_import = true });
\\ return @intFromBool(0x2244668822451255 !=
\\ foo_array[1] +
\\ foo_strong.* +
\\ foo_strong_alias.*);
\\}
,
});
exe.root_module.linkLibrary(lib);
const run = case.addRunArtifact(exe);
run.addCheck(.{ .expect_term = .{ .exited = 0 } });
}
if (ctx.includeTest("abs-symbol")) |case| {
const abs = case.addObject(.{
.name = "abs",
.use_llvm = true, // TODO: .globl not supported on self-hosted
.use_lld = true,
.asm_source_bytes =
\\.globl foo
\\foo = 0xcafecafe
\\
,
});
const abs_reloc = case.addObject(.{
.name = "abs_reloc",
.use_llvm = true, // TODO: .globl not supported on self-hosted
.use_lld = true,
.asm_source_bytes =
\\.data
\\.globl foo_copy
\\foo_copy:
\\.long foo
,
});
case.verifyObjdump(abs_reloc.getEmittedBin(), &.{
"-s",
"--relocs",
}, .{ .arch = true });
const exe = case.addExecutable(.{
.name = "test",
.zig_source_bytes =
\\extern var foo_copy: u32;
\\pub fn main() !u8 {
\\ return @intFromBool(foo_copy != 0xcafecafe);
\\}
,
});
exe.root_module.addObject(abs);
exe.root_module.addObject(abs_reloc);
const run = case.addRunArtifact(exe);
run.addCheck(.{ .expect_term = .{ .exited = 0 } });
if (!ctx.use_llvm) {
const exe_reloc_err = case.addExecutable(.{
.name = "test-reloc-err",
.zig_source_bytes =
\\extern const foo: u32;
\\pub fn main() !u8 {
\\ return @intFromBool(foo != 0xcafecafe);
\\}
,
});
exe_reloc_err.root_module.addObject(abs);
case.expectLinkErrors(exe_reloc_err, .{
.contains = "error: absolute symbol 'foo' targeted by invalid relocation type: /?/",
});
}
}
if (ctx.includeTest("explicit-extern-lib-name")) |case| {
// TODO: Lld.zig does not look at explicit inputs to resolve explicit extern lib names
if (ctx.use_llvm) return;
const lib1 = case.addLibrary(.dynamic, .{
.name = "lib1",
.name_target = false,
.zig_source_bytes =
\\export fn foo() u8 {
\\ return 43;
\\}
,
});
const lib2 = case.addLibrary(.dynamic, .{
.name = "lib2",
.name_target = false,
.zig_source_bytes =
\\export fn foo() u8 {
\\ return 42;
\\}
,
});
const lib3 = case.addLibrary(.static, .{
.name = "lib3",
.zig_source_bytes =
\\extern fn foo() u8;
\\export fn callFoo() u8 {
\\ return foo();
\\}
,
});
const exe = case.addExecutable(.{
.name = "test",
.zig_source_bytes =
\\extern "explicit-extern-lib-name-lib2" fn foo() u8;
\\extern fn callFoo() u8;
\\pub fn main() !u8 {
\\ return foo() + callFoo();
\\}
,
});
exe.root_module.linkLibrary(lib1);
exe.root_module.linkLibrary(lib2);
// exe.root_module.addLibraryPath(.{
// .generated = .{
// .index = lib2.getEmittedBin().generated.index,
// .up = 1,
// },
// });
exe.root_module.linkLibrary(lib3);
const run = case.addRunArtifact(exe);
run.addCheck(.{ .expect_term = .{ .exited = 84 } });
}
}
const LinkContext = @import("tests.zig").LinkContext;
const std = @import("std");