1pub fn addCases(ctx: *LinkContext) void {
2 if (ctx.target.result.isMinGW())
3 @import("link/mingw.zig").addCases(ctx);
4
5 if (ctx.includeTest("static-lib")) |case| {
6 const obj1 = case.addObject(.{
7 .name = "obj1",
8 .name_prefix = false,
9 .name_target = false,
10 .use_llvm = true,
11 .use_lld = true,
12 .c_source_bytes =
13 \\int foo1 = 1;
14 \\int foo2 = 2;
15 \\unsigned int fooBar() {
16 \\ return foo1 + foo2;
17 \\}
18 ,
19 });
20 const obj2 = case.addObject(.{
21 .name = "this_is_a_long_name",
22 .name_prefix = false,
23 .name_target = false,
24 .zig_source_bytes =
25 \\fn fooWeak() callconv(.c) usize {
26 \\ return 0xaabbccddaabbccdd;
27 \\}
28 \\export var foo_array: [2]u16 = .{ 0xffff, 0xabcd };
29 \\export var foo_strong: usize = 0x1122334411223344;
30 \\comptime {
31 \\ @export(&fooWeak, .{ .name = "fooWeak", .linkage = .weak });
32 \\ @export(&foo_strong, .{ .name = "foo_strong_alias", .linkage = .strong });
33 \\}
34 ,
35 });
36
37 const lib = case.addLibrary(.static, .{
38 .name = "lib",
39 .name_prefix = false,
40 .name_target = false,
41 });
42 lib.root_module.addObject(obj1);
43 lib.root_module.addObject(obj2);
44
45 case.verifyObjdump(lib.getEmittedBin(), &.{
46 "-s",
47 "--elements=file-type",
48 "--symbols",
49 "--only-symbol=foo",
50 }, .{ .use_llvm = true });
51
52 const exe = case.addExecutable(.{
53 .name = "test",
54 .zig_source_bytes =
55 \\extern fn fooBar() c_uint;
56 \\extern fn fooWeak() usize;
57 \\extern var foo_array: [2]u16;
58 \\extern var foo_strong: usize;
59 \\extern var foo_strong_alias: usize;
60 \\pub fn main() !u8 {
61 \\ return @intFromBool(0xcd003365cd00df35 != fooBar() +
62 \\ fooWeak() +
63 \\ foo_array[1] +
64 \\ foo_strong +
65 \\ foo_strong_alias);
66 \\}
67 ,
68 });
69 exe.root_module.linkLibrary(lib);
70
71 const run = case.addRunArtifact(exe);
72 run.addCheck(.{ .expect_term = .{ .exited = 0 } });
73 }
74
75 if (ctx.includeTest("tls")) |case| {
76 const obj = case.addObject(.{
77 .name = "obj",
78 .zig_source_bytes =
79 \\threadlocal var threadlocal_var: u32 = 1234;
80 \\threadlocal var threadlocal_arr: [4]u16 = .{ 0x1111, 0x2222, 0x3333, 0x4444, };
81 \\export fn threadlocal_read(a: *u32, b: *u16) void {
82 \\ a.* = threadlocal_var;
83 \\ b.* = threadlocal_arr[3];
84 \\}
85 \\export fn threadlocal_write(a: u32, b: u16) void {
86 \\ threadlocal_var = a;
87 \\ threadlocal_arr[3] = b;
88 \\}
89 ,
90 });
91
92 case.verifyObjdump(obj.getEmittedBin(), &.{
93 "-s",
94 "--symbols",
95 "--only-symbol=threadlocal",
96 "--only-symbol=tls",
97 }, .{ .use_llvm = true });
98
99 const exe = case.addExecutable(.{
100 .name = "test",
101 .zig_source_bytes =
102 \\extern fn threadlocal_read(a: *u32, b: *u16) void;
103 \\extern fn threadlocal_write(a: u32, b: u16) void;
104 \\threadlocal var threadlocal_foo: u64 = 0xcafecafecafecafe;
105 \\pub fn main() !u8 {
106 \\ var a: u32 = undefined;
107 \\ var b: u16 = undefined;
108 \\ threadlocal_read(&a, &b);
109 \\ if (a != 1234 or b != 0x4444) return 1;
110 \\ if (threadlocal_foo != 0xcafecafecafecafe) return 2;
111 \\ threadlocal_write(0xabcdabcd, 0x5555);
112 \\ threadlocal_foo = 1;
113 \\ threadlocal_read(&a, &b);
114 \\ if (a != 0xabcdabcd or b != 0x5555) return 3;
115 \\ if (threadlocal_foo != 1) return 4;
116 \\ return 0;
117 \\}
118 ,
119 });
120 exe.root_module.addObject(obj);
121
122 const run = case.addRunArtifact(exe);
123 run.addCheck(.{ .expect_term = .{ .exited = 0 } });
124 }
125
126 if (ctx.includeTest("dynamic-lib-code")) |case| {
127 const lib = case.addLibrary(.dynamic, .{
128 .name = "lib",
129 .name_target = false,
130 .zig_source_bytes =
131 \\export fn foo1() callconv(.c) u64 {
132 \\ return 0x1122334411223344;
133 \\}
134 \\export fn foo2() callconv(.c) u64 {
135 \\ return 0xaabbccddaabbccdd;
136 \\}
137 ,
138 });
139
140 case.verifyObjdump(lib.getEmittedBin(), &.{
141 "-s",
142 "--exports",
143 "--only-symbol=foo",
144 }, .{ .os = true });
145
146 if (ctx.target.result.os.tag == .windows) {
147 case.verifyObjdump(lib.getEmittedImplib(), &.{
148 "-s",
149 "--exports=sort",
150 "--only-symbol=foo",
151 }, .{ .sub_name = "implib", .os = true, .arch = true });
152 }
153
154 const exe = case.addExecutable(.{
155 .name = "test",
156 .zig_source_bytes =
157 \\extern fn foo1() u64;
158 \\pub fn main() !u8 {
159 \\ const foo2 = @extern(
160 \\ *const fn () callconv(.c) u64,
161 \\ .{ .name = "foo2", .is_dll_import = true },
162 \\ );
163 \\ return @intFromBool(0xbbde0021bbde0021 != foo1() + foo2());
164 \\}
165 ,
166 });
167 exe.root_module.linkLibrary(lib);
168
169 const run = case.addRunArtifact(exe);
170 run.addCheck(.{ .expect_term = .{ .exited = 0 } });
171 }
172
173 if (ctx.includeTest("dynamic-lib-data")) |case| {
174 const lib = case.addLibrary(.dynamic, .{
175 .name = "lib",
176 .name_target = false,
177 .zig_source_bytes =
178 \\export var foo_array: [2]u16 = .{ 0xffff, 0xabcd };
179 \\export var foo_strong: usize = 0x1122334411223344;
180 \\comptime {
181 \\ @export(&foo_strong, .{ .name = "foo_strong_alias", .linkage = .strong });
182 \\}
183 ,
184 });
185
186 case.verifyObjdump(lib.getEmittedBin(), &.{
187 "-s",
188 "--exports",
189 "--only-symbol=foo",
190 }, .{});
191
192 if (ctx.target.result.os.tag == .windows) {
193 case.verifyObjdump(lib.getEmittedImplib(), &.{
194 "-s",
195 "--exports=sort",
196 "--only-symbol=foo",
197 }, .{ .sub_name = "implib", .os = true, .arch = true });
198 }
199
200 const exe = case.addExecutable(.{
201 .name = "test",
202 .zig_source_bytes =
203 \\pub fn main() !u8 {
204 \\ const foo_array = @extern(*[2]u16, .{ .name = "foo_array", .is_dll_import = true });
205 \\ const foo_strong = @extern(*usize, .{ .name = "foo_strong", .is_dll_import = true });
206 \\ const foo_strong_alias = @extern(*usize, .{ .name = "foo_strong_alias", .is_dll_import = true });
207 \\ return @intFromBool(0x2244668822451255 !=
208 \\ foo_array[1] +
209 \\ foo_strong.* +
210 \\ foo_strong_alias.*);
211 \\}
212 ,
213 });
214 exe.root_module.linkLibrary(lib);
215
216 const run = case.addRunArtifact(exe);
217 run.addCheck(.{ .expect_term = .{ .exited = 0 } });
218 }
219
220 if (ctx.includeTest("abs-symbol")) |case| {
221 const abs = case.addObject(.{
222 .name = "abs",
223 .use_llvm = true, // TODO: .globl not supported on self-hosted
224 .use_lld = true,
225 .asm_source_bytes =
226 \\.globl foo
227 \\foo = 0xcafecafe
228 \\
229 ,
230 });
231
232 const abs_reloc = case.addObject(.{
233 .name = "abs_reloc",
234 .use_llvm = true, // TODO: .globl not supported on self-hosted
235 .use_lld = true,
236 .asm_source_bytes =
237 \\.data
238 \\.globl foo_copy
239 \\foo_copy:
240 \\.long foo
241 ,
242 });
243
244 case.verifyObjdump(abs_reloc.getEmittedBin(), &.{
245 "-s",
246 "--relocs",
247 }, .{ .arch = true });
248
249 const exe = case.addExecutable(.{
250 .name = "test",
251 .zig_source_bytes =
252 \\extern var foo_copy: u32;
253 \\pub fn main() !u8 {
254 \\ return @intFromBool(foo_copy != 0xcafecafe);
255 \\}
256 ,
257 });
258 exe.root_module.addObject(abs);
259 exe.root_module.addObject(abs_reloc);
260
261 const run = case.addRunArtifact(exe);
262 run.addCheck(.{ .expect_term = .{ .exited = 0 } });
263
264 if (!ctx.use_llvm) {
265 const exe_reloc_err = case.addExecutable(.{
266 .name = "test-reloc-err",
267 .zig_source_bytes =
268 \\extern const foo: u32;
269 \\pub fn main() !u8 {
270 \\ return @intFromBool(foo != 0xcafecafe);
271 \\}
272 ,
273 });
274 exe_reloc_err.root_module.addObject(abs);
275 case.expectLinkErrors(exe_reloc_err, .{
276 .contains = "error: absolute symbol 'foo' targeted by invalid relocation type: /?/",
277 });
278 }
279 }
280
281 if (ctx.includeTest("explicit-extern-lib-name")) |case| {
282 // TODO: Lld.zig does not look at explicit inputs to resolve explicit extern lib names
283 if (ctx.use_llvm) return;
284
285 const lib1 = case.addLibrary(.dynamic, .{
286 .name = "lib1",
287 .name_target = false,
288 .zig_source_bytes =
289 \\export fn foo() u8 {
290 \\ return 43;
291 \\}
292 ,
293 });
294
295 const lib2 = case.addLibrary(.dynamic, .{
296 .name = "lib2",
297 .name_target = false,
298 .zig_source_bytes =
299 \\export fn foo() u8 {
300 \\ return 42;
301 \\}
302 ,
303 });
304
305 const lib3 = case.addLibrary(.static, .{
306 .name = "lib3",
307 .zig_source_bytes =
308 \\extern fn foo() u8;
309 \\export fn callFoo() u8 {
310 \\ return foo();
311 \\}
312 ,
313 });
314
315 const exe = case.addExecutable(.{
316 .name = "test",
317 .zig_source_bytes =
318 \\extern "explicit-extern-lib-name-lib2" fn foo() u8;
319 \\extern fn callFoo() u8;
320 \\pub fn main() !u8 {
321 \\ return foo() + callFoo();
322 \\}
323 ,
324 });
325 exe.root_module.linkLibrary(lib1);
326 exe.root_module.linkLibrary(lib2);
327 // exe.root_module.addLibraryPath(.{
328 // .generated = .{
329 // .index = lib2.getEmittedBin().generated.index,
330 // .up = 1,
331 // },
332 // });
333 exe.root_module.linkLibrary(lib3);
334
335 const run = case.addRunArtifact(exe);
336 run.addCheck(.{ .expect_term = .{ .exited = 84 } });
337 }
338}
339
340const LinkContext = @import("tests.zig").LinkContext;
341const std = @import("std");