blob 30982e6b (98800B) - Raw
1 //! Here we test our MachO linker for correctness and functionality. 2 3 pub fn testAll(b: *Build, build_opts: BuildOptions) *Step { 4 const macho_step = b.step("test-macho", "Run MachO tests"); 5 6 const x86_64_target = b.resolveTargetQuery(.{ 7 .cpu_arch = .x86_64, 8 .os_tag = .macos, 9 }); 10 const aarch64_target = b.resolveTargetQuery(.{ 11 .cpu_arch = .aarch64, 12 .os_tag = .macos, 13 }); 14 15 const default_target = switch (builtin.cpu.arch) { 16 .x86_64, .aarch64 => b.resolveTargetQuery(.{ 17 .os_tag = .macos, 18 }), 19 else => aarch64_target, 20 }; 21 22 // Exercise linker with self-hosted backend (no LLVM) 23 macho_step.dependOn(testEmptyZig(b, .{ .use_llvm = false, .target = x86_64_target })); 24 macho_step.dependOn(testHelloZig(b, .{ .use_llvm = false, .target = x86_64_target })); 25 macho_step.dependOn(testLinkingStaticLib(b, .{ .use_llvm = false, .target = x86_64_target })); 26 macho_step.dependOn(testReexportsZig(b, .{ .use_llvm = false, .target = x86_64_target })); 27 macho_step.dependOn(testRelocatableZig(b, .{ .use_llvm = false, .target = x86_64_target })); 28 macho_step.dependOn(testTlsZig(b, .{ .use_llvm = false, .target = x86_64_target })); 29 macho_step.dependOn(testUnresolvedError(b, .{ .use_llvm = false, .target = x86_64_target })); 30 31 // Exercise linker with LLVM backend 32 macho_step.dependOn(testDeadStrip(b, .{ .target = default_target })); 33 macho_step.dependOn(testDuplicateDefinitions(b, .{ .target = default_target })); 34 macho_step.dependOn(testEmptyObject(b, .{ .target = default_target })); 35 macho_step.dependOn(testEmptyZig(b, .{ .target = default_target })); 36 macho_step.dependOn(testEntryPoint(b, .{ .target = default_target })); 37 macho_step.dependOn(testHeaderWeakFlags(b, .{ .target = default_target })); 38 macho_step.dependOn(testHelloC(b, .{ .target = default_target })); 39 macho_step.dependOn(testHelloZig(b, .{ .target = default_target })); 40 macho_step.dependOn(testLargeBss(b, .{ .target = default_target })); 41 macho_step.dependOn(testLayout(b, .{ .target = default_target })); 42 macho_step.dependOn(testLinkingStaticLib(b, .{ .target = default_target })); 43 macho_step.dependOn(testLinksection(b, .{ .target = default_target })); 44 macho_step.dependOn(testMergeLiteralsX64(b, .{ .target = x86_64_target })); 45 macho_step.dependOn(testMergeLiteralsArm64(b, .{ .target = aarch64_target })); 46 macho_step.dependOn(testMergeLiteralsArm642(b, .{ .target = aarch64_target })); 47 macho_step.dependOn(testMergeLiteralsAlignment(b, .{ .target = aarch64_target })); 48 macho_step.dependOn(testMhExecuteHeader(b, .{ .target = default_target })); 49 macho_step.dependOn(testNoDeadStrip(b, .{ .target = default_target })); 50 macho_step.dependOn(testNoExportsDylib(b, .{ .target = default_target })); 51 macho_step.dependOn(testPagezeroSize(b, .{ .target = default_target })); 52 macho_step.dependOn(testReexportsZig(b, .{ .target = default_target })); 53 macho_step.dependOn(testRelocatable(b, .{ .target = default_target })); 54 macho_step.dependOn(testRelocatableZig(b, .{ .target = default_target })); 55 macho_step.dependOn(testSectionBoundarySymbols(b, .{ .target = default_target })); 56 macho_step.dependOn(testSectionBoundarySymbols2(b, .{ .target = default_target })); 57 macho_step.dependOn(testSegmentBoundarySymbols(b, .{ .target = default_target })); 58 macho_step.dependOn(testSymbolStabs(b, .{ .target = default_target })); 59 macho_step.dependOn(testStackSize(b, .{ .target = default_target })); 60 macho_step.dependOn(testTentative(b, .{ .target = default_target })); 61 macho_step.dependOn(testThunks(b, .{ .target = aarch64_target })); 62 macho_step.dependOn(testTlsLargeTbss(b, .{ .target = default_target })); 63 macho_step.dependOn(testTlsZig(b, .{ .target = default_target })); 64 macho_step.dependOn(testUndefinedFlag(b, .{ .target = default_target })); 65 macho_step.dependOn(testUnresolvedError(b, .{ .target = default_target })); 66 macho_step.dependOn(testUnwindInfo(b, .{ .target = default_target })); 67 macho_step.dependOn(testUnwindInfoNoSubsectionsX64(b, .{ .target = x86_64_target })); 68 macho_step.dependOn(testUnwindInfoNoSubsectionsArm64(b, .{ .target = aarch64_target })); 69 macho_step.dependOn(testWeakBind(b, .{ .target = x86_64_target })); 70 macho_step.dependOn(testWeakRef(b, .{ .target = b.resolveTargetQuery(.{ 71 .cpu_arch = .x86_64, 72 .os_tag = .macos, 73 .os_version_min = .{ .semver = .{ .major = 10, .minor = 13, .patch = 0 } }, 74 }) })); 75 76 // Tests requiring symlinks 77 if (build_opts.has_symlinks) { 78 macho_step.dependOn(testEntryPointArchive(b, .{ .target = default_target })); 79 macho_step.dependOn(testEntryPointDylib(b, .{ .target = default_target })); 80 macho_step.dependOn(testDylib(b, .{ .target = default_target })); 81 macho_step.dependOn(testDylibVersionTbd(b, .{ .target = default_target })); 82 macho_step.dependOn(testNeededLibrary(b, .{ .target = default_target })); 83 macho_step.dependOn(testSearchStrategy(b, .{ .target = default_target })); 84 macho_step.dependOn(testTbdv3(b, .{ .target = default_target })); 85 macho_step.dependOn(testTls(b, .{ .target = default_target })); 86 macho_step.dependOn(testTlsPointers(b, .{ .target = default_target })); 87 macho_step.dependOn(testTwoLevelNamespace(b, .{ .target = default_target })); 88 macho_step.dependOn(testWeakLibrary(b, .{ .target = default_target })); 89 90 // Tests requiring presence of macOS SDK in system path 91 if (build_opts.has_macos_sdk) { 92 macho_step.dependOn(testDeadStripDylibs(b, .{ .target = b.graph.host })); 93 macho_step.dependOn(testHeaderpad(b, .{ .target = b.graph.host })); 94 macho_step.dependOn(testLinkDirectlyCppTbd(b, .{ .target = b.graph.host })); 95 macho_step.dependOn(testMergeLiteralsObjc(b, .{ .target = b.graph.host })); 96 macho_step.dependOn(testNeededFramework(b, .{ .target = b.graph.host })); 97 macho_step.dependOn(testObjc(b, .{ .target = b.graph.host })); 98 macho_step.dependOn(testObjcpp(b, .{ .target = b.graph.host })); 99 macho_step.dependOn(testWeakFramework(b, .{ .target = b.graph.host })); 100 } 101 } 102 103 return macho_step; 104 } 105 106 fn testDeadStrip(b: *Build, opts: Options) *Step { 107 const test_step = addTestStep(b, "dead-strip", opts); 108 109 const obj = addObject(b, opts, .{ .name = "a", .cpp_source_bytes = 110 \\#include <stdio.h> 111 \\int two() { return 2; } 112 \\int live_var1 = 1; 113 \\int live_var2 = two(); 114 \\int dead_var1 = 3; 115 \\int dead_var2 = 4; 116 \\void live_fn1() {} 117 \\void live_fn2() { live_fn1(); } 118 \\void dead_fn1() {} 119 \\void dead_fn2() { dead_fn1(); } 120 \\int main() { 121 \\ printf("%d %d\n", live_var1, live_var2); 122 \\ live_fn2(); 123 \\} 124 }); 125 126 { 127 const exe = addExecutable(b, opts, .{ .name = "no_dead_strip" }); 128 exe.addObject(obj); 129 exe.link_gc_sections = false; 130 131 const check = exe.checkObject(); 132 check.checkInSymtab(); 133 check.checkContains("live_var1"); 134 check.checkInSymtab(); 135 check.checkContains("live_var2"); 136 check.checkInSymtab(); 137 check.checkContains("dead_var1"); 138 check.checkInSymtab(); 139 check.checkContains("dead_var2"); 140 check.checkInSymtab(); 141 check.checkContains("live_fn1"); 142 check.checkInSymtab(); 143 check.checkContains("live_fn2"); 144 check.checkInSymtab(); 145 check.checkContains("dead_fn1"); 146 check.checkInSymtab(); 147 check.checkContains("dead_fn2"); 148 test_step.dependOn(&check.step); 149 150 const run = addRunArtifact(exe); 151 run.expectStdOutEqual("1 2\n"); 152 test_step.dependOn(&run.step); 153 } 154 155 { 156 const exe = addExecutable(b, opts, .{ .name = "yes_dead_strip" }); 157 exe.addObject(obj); 158 exe.link_gc_sections = true; 159 160 const check = exe.checkObject(); 161 check.checkInSymtab(); 162 check.checkContains("live_var1"); 163 check.checkInSymtab(); 164 check.checkContains("live_var2"); 165 check.checkInSymtab(); 166 check.checkNotPresent("dead_var1"); 167 check.checkInSymtab(); 168 check.checkNotPresent("dead_var2"); 169 check.checkInSymtab(); 170 check.checkContains("live_fn1"); 171 check.checkInSymtab(); 172 check.checkContains("live_fn2"); 173 check.checkInSymtab(); 174 check.checkNotPresent("dead_fn1"); 175 check.checkInSymtab(); 176 check.checkNotPresent("dead_fn2"); 177 test_step.dependOn(&check.step); 178 179 const run = addRunArtifact(exe); 180 run.expectStdOutEqual("1 2\n"); 181 test_step.dependOn(&run.step); 182 } 183 184 return test_step; 185 } 186 187 fn testDuplicateDefinitions(b: *Build, opts: Options) *Step { 188 const test_step = addTestStep(b, "duplicate-definitions", opts); 189 190 const obj = addObject(b, opts, .{ .name = "a", .zig_source_bytes = 191 \\var x: usize = 1; 192 \\export fn strong() void { x += 1; } 193 \\export fn weak() void { x += 1; } 194 }); 195 196 const exe = addExecutable(b, opts, .{ .name = "main", .zig_source_bytes = 197 \\var x: usize = 1; 198 \\export fn strong() void { x += 1; } 199 \\comptime { @export(weakImpl, .{ .name = "weak", .linkage = .weak }); } 200 \\fn weakImpl() callconv(.C) void { x += 1; } 201 \\extern fn weak() void; 202 \\pub fn main() void { 203 \\ weak(); 204 \\ strong(); 205 \\} 206 }); 207 exe.addObject(obj); 208 209 expectLinkErrors(exe, test_step, .{ .exact = &.{ 210 "error: duplicate symbol definition: _strong", 211 "note: defined by /?/a.o", 212 "note: defined by /?/main.o", 213 } }); 214 215 return test_step; 216 } 217 218 fn testDeadStripDylibs(b: *Build, opts: Options) *Step { 219 const test_step = addTestStep(b, "dead-strip-dylibs", opts); 220 221 const main_o = addObject(b, opts, .{ .name = "main", .c_source_bytes = 222 \\#include <objc/runtime.h> 223 \\int main() { 224 \\ if (objc_getClass("NSObject") == 0) { 225 \\ return -1; 226 \\ } 227 \\ if (objc_getClass("NSApplication") == 0) { 228 \\ return -2; 229 \\ } 230 \\ return 0; 231 \\} 232 }); 233 234 { 235 const exe = addExecutable(b, opts, .{ .name = "main1" }); 236 exe.addObject(main_o); 237 exe.root_module.linkFramework("Cocoa", .{}); 238 239 const check = exe.checkObject(); 240 check.checkInHeaders(); 241 check.checkExact("cmd LOAD_DYLIB"); 242 check.checkContains("Cocoa"); 243 check.checkInHeaders(); 244 check.checkExact("cmd LOAD_DYLIB"); 245 check.checkContains("libobjc"); 246 test_step.dependOn(&check.step); 247 248 const run = addRunArtifact(exe); 249 run.expectExitCode(0); 250 test_step.dependOn(&run.step); 251 } 252 253 { 254 const exe = addExecutable(b, opts, .{ .name = "main2" }); 255 exe.addObject(main_o); 256 exe.root_module.linkFramework("Cocoa", .{}); 257 exe.dead_strip_dylibs = true; 258 259 const run = addRunArtifact(exe); 260 run.expectExitCode(@as(u8, @bitCast(@as(i8, -2)))); 261 test_step.dependOn(&run.step); 262 } 263 264 return test_step; 265 } 266 267 fn testDylib(b: *Build, opts: Options) *Step { 268 const test_step = addTestStep(b, "dylib", opts); 269 270 const dylib = addSharedLibrary(b, opts, .{ .name = "a", .c_source_bytes = 271 \\#include<stdio.h> 272 \\char world[] = "world"; 273 \\char* hello() { 274 \\ return "Hello"; 275 \\} 276 }); 277 278 const check = dylib.checkObject(); 279 check.checkInHeaders(); 280 check.checkExact("header"); 281 check.checkNotPresent("PIE"); 282 test_step.dependOn(&check.step); 283 284 const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = 285 \\#include<stdio.h> 286 \\char* hello(); 287 \\extern char world[]; 288 \\int main() { 289 \\ printf("%s %s", hello(), world); 290 \\ return 0; 291 \\} 292 }); 293 exe.root_module.linkSystemLibrary("a", .{}); 294 exe.root_module.addLibraryPath(dylib.getEmittedBinDirectory()); 295 exe.root_module.addRPath(dylib.getEmittedBinDirectory()); 296 297 const run = addRunArtifact(exe); 298 run.expectStdOutEqual("Hello world"); 299 test_step.dependOn(&run.step); 300 301 return test_step; 302 } 303 304 fn testDylibVersionTbd(b: *Build, opts: Options) *Step { 305 const test_step = addTestStep(b, "dylib-version-tbd", opts); 306 307 const tbd = tbd: { 308 const wf = WriteFile.create(b); 309 break :tbd wf.add("liba.tbd", 310 \\--- !tapi-tbd 311 \\tbd-version: 4 312 \\targets: [ x86_64-macos, arm64-macos ] 313 \\uuids: 314 \\ - target: x86_64-macos 315 \\ value: DEADBEEF 316 \\ - target: arm64-macos 317 \\ value: BEEFDEAD 318 \\install-name: '@rpath/liba.dylib' 319 \\current-version: 1.2 320 \\exports: 321 \\ - targets: [ x86_64-macos, arm64-macos ] 322 \\ symbols: [ _foo ] 323 ); 324 }; 325 326 const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = "int main() {}" }); 327 exe.root_module.linkSystemLibrary("a", .{}); 328 exe.root_module.addLibraryPath(tbd.dirname()); 329 330 const check = exe.checkObject(); 331 check.checkInHeaders(); 332 check.checkExact("cmd LOAD_DYLIB"); 333 check.checkExact("name @rpath/liba.dylib"); 334 check.checkExact("current version 10200"); 335 test_step.dependOn(&check.step); 336 337 return test_step; 338 } 339 340 fn testEmptyObject(b: *Build, opts: Options) *Step { 341 const test_step = addTestStep(b, "empty-object", opts); 342 343 const empty = addObject(b, opts, .{ .name = "empty", .c_source_bytes = "" }); 344 345 const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = 346 \\#include <stdio.h> 347 \\int main() { 348 \\ printf("Hello world!"); 349 \\} 350 }); 351 exe.addObject(empty); 352 353 const run = addRunArtifact(exe); 354 run.expectStdOutEqual("Hello world!"); 355 test_step.dependOn(&run.step); 356 357 return test_step; 358 } 359 360 fn testEmptyZig(b: *Build, opts: Options) *Step { 361 const test_step = addTestStep(b, "empty-zig", opts); 362 363 const exe = addExecutable(b, opts, .{ .name = "empty", .zig_source_bytes = "pub fn main() void {}" }); 364 365 const run = addRunArtifact(exe); 366 run.expectExitCode(0); 367 test_step.dependOn(&run.step); 368 369 return test_step; 370 } 371 372 fn testEntryPoint(b: *Build, opts: Options) *Step { 373 const test_step = addTestStep(b, "entry-point", opts); 374 375 const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = 376 \\#include<stdio.h> 377 \\int non_main() { 378 \\ printf("%d", 42); 379 \\ return 0; 380 \\} 381 }); 382 exe.entry = .{ .symbol_name = "_non_main" }; 383 384 const run = addRunArtifact(exe); 385 run.expectStdOutEqual("42"); 386 test_step.dependOn(&run.step); 387 388 const check = exe.checkObject(); 389 check.checkInHeaders(); 390 check.checkExact("segname __TEXT"); 391 check.checkExtract("vmaddr {vmaddr}"); 392 check.checkInHeaders(); 393 check.checkExact("cmd MAIN"); 394 check.checkExtract("entryoff {entryoff}"); 395 check.checkInSymtab(); 396 check.checkExtract("{n_value} (__TEXT,__text) external _non_main"); 397 check.checkComputeCompare("vmaddr entryoff +", .{ .op = .eq, .value = .{ .variable = "n_value" } }); 398 test_step.dependOn(&check.step); 399 400 return test_step; 401 } 402 403 fn testEntryPointArchive(b: *Build, opts: Options) *Step { 404 const test_step = addTestStep(b, "entry-point-archive", opts); 405 406 const lib = addStaticLibrary(b, opts, .{ .name = "main", .c_source_bytes = "int main() { return 0; }" }); 407 408 { 409 const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = "" }); 410 exe.root_module.linkSystemLibrary("main", .{}); 411 exe.root_module.addLibraryPath(lib.getEmittedBinDirectory()); 412 413 const run = addRunArtifact(exe); 414 run.expectExitCode(0); 415 test_step.dependOn(&run.step); 416 } 417 418 { 419 const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = "" }); 420 exe.root_module.linkSystemLibrary("main", .{}); 421 exe.root_module.addLibraryPath(lib.getEmittedBinDirectory()); 422 exe.link_gc_sections = true; 423 424 const run = addRunArtifact(exe); 425 run.expectExitCode(0); 426 test_step.dependOn(&run.step); 427 } 428 429 return test_step; 430 } 431 432 fn testEntryPointDylib(b: *Build, opts: Options) *Step { 433 const test_step = addTestStep(b, "entry-point-dylib", opts); 434 435 const dylib = addSharedLibrary(b, opts, .{ .name = "a" }); 436 addCSourceBytes(dylib, 437 \\extern int my_main(); 438 \\int bootstrap() { 439 \\ return my_main(); 440 \\} 441 , &.{}); 442 dylib.linker_allow_shlib_undefined = true; 443 444 const exe = addExecutable(b, opts, .{ .name = "main" }); 445 addCSourceBytes(dylib, 446 \\#include<stdio.h> 447 \\int my_main() { 448 \\ fprintf(stdout, "Hello!\n"); 449 \\ return 0; 450 \\} 451 , &.{}); 452 exe.linkLibrary(dylib); 453 exe.entry = .{ .symbol_name = "_bootstrap" }; 454 exe.forceUndefinedSymbol("_my_main"); 455 456 const check = exe.checkObject(); 457 check.checkInHeaders(); 458 check.checkExact("segname __TEXT"); 459 check.checkExtract("vmaddr {text_vmaddr}"); 460 check.checkInHeaders(); 461 check.checkExact("sectname __stubs"); 462 check.checkExtract("addr {stubs_vmaddr}"); 463 check.checkInHeaders(); 464 check.checkExact("sectname __stubs"); 465 check.checkExtract("size {stubs_vmsize}"); 466 check.checkInHeaders(); 467 check.checkExact("cmd MAIN"); 468 check.checkExtract("entryoff {entryoff}"); 469 check.checkComputeCompare("text_vmaddr entryoff +", .{ 470 .op = .gte, 471 .value = .{ .variable = "stubs_vmaddr" }, // The entrypoint should be a synthetic stub 472 }); 473 check.checkComputeCompare("text_vmaddr entryoff + stubs_vmaddr -", .{ 474 .op = .lt, 475 .value = .{ .variable = "stubs_vmsize" }, // The entrypoint should be a synthetic stub 476 }); 477 test_step.dependOn(&check.step); 478 479 const run = addRunArtifact(exe); 480 run.expectStdOutEqual("Hello!\n"); 481 test_step.dependOn(&run.step); 482 483 return test_step; 484 } 485 486 fn testHeaderpad(b: *Build, opts: Options) *Step { 487 const test_step = addTestStep(b, "headerpad", opts); 488 489 const addExe = struct { 490 fn addExe(bb: *Build, o: Options, name: []const u8) *Compile { 491 const exe = addExecutable(bb, o, .{ 492 .name = name, 493 .c_source_bytes = "int main() { return 0; }", 494 }); 495 exe.root_module.linkFramework("CoreFoundation", .{}); 496 exe.root_module.linkFramework("Foundation", .{}); 497 exe.root_module.linkFramework("Cocoa", .{}); 498 exe.root_module.linkFramework("CoreGraphics", .{}); 499 exe.root_module.linkFramework("CoreHaptics", .{}); 500 exe.root_module.linkFramework("CoreAudio", .{}); 501 exe.root_module.linkFramework("AVFoundation", .{}); 502 exe.root_module.linkFramework("CoreImage", .{}); 503 exe.root_module.linkFramework("CoreLocation", .{}); 504 exe.root_module.linkFramework("CoreML", .{}); 505 exe.root_module.linkFramework("CoreVideo", .{}); 506 exe.root_module.linkFramework("CoreText", .{}); 507 exe.root_module.linkFramework("CryptoKit", .{}); 508 exe.root_module.linkFramework("GameKit", .{}); 509 exe.root_module.linkFramework("SwiftUI", .{}); 510 exe.root_module.linkFramework("StoreKit", .{}); 511 exe.root_module.linkFramework("SpriteKit", .{}); 512 return exe; 513 } 514 }.addExe; 515 516 { 517 const exe = addExe(b, opts, "main1"); 518 exe.headerpad_max_install_names = true; 519 520 const check = exe.checkObject(); 521 check.checkInHeaders(); 522 check.checkExact("sectname __text"); 523 check.checkExtract("offset {offset}"); 524 switch (opts.target.result.cpu.arch) { 525 .aarch64 => check.checkComputeCompare("offset", .{ .op = .gte, .value = .{ .literal = 0x4000 } }), 526 .x86_64 => check.checkComputeCompare("offset", .{ .op = .gte, .value = .{ .literal = 0x1000 } }), 527 else => unreachable, 528 } 529 test_step.dependOn(&check.step); 530 531 const run = addRunArtifact(exe); 532 run.expectExitCode(0); 533 test_step.dependOn(&run.step); 534 } 535 536 { 537 const exe = addExe(b, opts, "main2"); 538 exe.headerpad_size = 0x10000; 539 540 const check = exe.checkObject(); 541 check.checkInHeaders(); 542 check.checkExact("sectname __text"); 543 check.checkExtract("offset {offset}"); 544 check.checkComputeCompare("offset", .{ .op = .gte, .value = .{ .literal = 0x10000 } }); 545 test_step.dependOn(&check.step); 546 547 const run = addRunArtifact(exe); 548 run.expectExitCode(0); 549 test_step.dependOn(&run.step); 550 } 551 552 { 553 const exe = addExe(b, opts, "main3"); 554 exe.headerpad_max_install_names = true; 555 exe.headerpad_size = 0x10000; 556 557 const check = exe.checkObject(); 558 check.checkInHeaders(); 559 check.checkExact("sectname __text"); 560 check.checkExtract("offset {offset}"); 561 check.checkComputeCompare("offset", .{ .op = .gte, .value = .{ .literal = 0x10000 } }); 562 test_step.dependOn(&check.step); 563 564 const run = addRunArtifact(exe); 565 run.expectExitCode(0); 566 test_step.dependOn(&run.step); 567 } 568 569 { 570 const exe = addExe(b, opts, "main4"); 571 exe.headerpad_max_install_names = true; 572 exe.headerpad_size = 0x1000; 573 574 const check = exe.checkObject(); 575 check.checkInHeaders(); 576 check.checkExact("sectname __text"); 577 check.checkExtract("offset {offset}"); 578 switch (opts.target.result.cpu.arch) { 579 .aarch64 => check.checkComputeCompare("offset", .{ .op = .gte, .value = .{ .literal = 0x4000 } }), 580 .x86_64 => check.checkComputeCompare("offset", .{ .op = .gte, .value = .{ .literal = 0x1000 } }), 581 else => unreachable, 582 } 583 test_step.dependOn(&check.step); 584 585 const run = addRunArtifact(exe); 586 run.expectExitCode(0); 587 test_step.dependOn(&run.step); 588 } 589 590 return test_step; 591 } 592 593 // Adapted from https://github.com/llvm/llvm-project/blob/main/lld/test/MachO/weak-header-flags.s 594 fn testHeaderWeakFlags(b: *Build, opts: Options) *Step { 595 const test_step = addTestStep(b, "header-weak-flags", opts); 596 597 const obj1 = addObject(b, opts, .{ .name = "a", .asm_source_bytes = 598 \\.globl _x 599 \\.weak_definition _x 600 \\_x: 601 \\ ret 602 }); 603 604 const lib = addSharedLibrary(b, opts, .{ .name = "a" }); 605 lib.addObject(obj1); 606 607 { 608 const exe = addExecutable(b, opts, .{ .name = "main1", .c_source_bytes = "int main() { return 0; }" }); 609 exe.addObject(obj1); 610 611 const check = exe.checkObject(); 612 check.checkInHeaders(); 613 check.checkExact("header"); 614 check.checkContains("WEAK_DEFINES"); 615 check.checkInHeaders(); 616 check.checkExact("header"); 617 check.checkContains("BINDS_TO_WEAK"); 618 check.checkInExports(); 619 check.checkExtract("[WEAK] {vmaddr} _x"); 620 test_step.dependOn(&check.step); 621 } 622 623 { 624 const obj = addObject(b, opts, .{ .name = "b" }); 625 626 switch (opts.target.result.cpu.arch) { 627 .aarch64 => addAsmSourceBytes(obj, 628 \\.globl _main 629 \\_main: 630 \\ bl _x 631 \\ ret 632 ), 633 .x86_64 => addAsmSourceBytes(obj, 634 \\.globl _main 635 \\_main: 636 \\ callq _x 637 \\ ret 638 ), 639 else => unreachable, 640 } 641 642 const exe = addExecutable(b, opts, .{ .name = "main2" }); 643 exe.linkLibrary(lib); 644 exe.addObject(obj); 645 646 const check = exe.checkObject(); 647 check.checkInHeaders(); 648 check.checkExact("header"); 649 check.checkNotPresent("WEAK_DEFINES"); 650 check.checkInHeaders(); 651 check.checkExact("header"); 652 check.checkContains("BINDS_TO_WEAK"); 653 check.checkInExports(); 654 check.checkNotPresent("[WEAK] {vmaddr} _x"); 655 test_step.dependOn(&check.step); 656 } 657 658 { 659 const exe = addExecutable(b, opts, .{ .name = "main3", .asm_source_bytes = 660 \\.globl _main, _x 661 \\_x: 662 \\ 663 \\_main: 664 \\ ret 665 }); 666 exe.linkLibrary(lib); 667 668 const check = exe.checkObject(); 669 check.checkInHeaders(); 670 check.checkExact("header"); 671 check.checkNotPresent("WEAK_DEFINES"); 672 check.checkInHeaders(); 673 check.checkExact("header"); 674 check.checkNotPresent("BINDS_TO_WEAK"); 675 test_step.dependOn(&check.step); 676 } 677 678 return test_step; 679 } 680 681 fn testHelloC(b: *Build, opts: Options) *Step { 682 const test_step = addTestStep(b, "hello-c", opts); 683 684 const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = 685 \\#include <stdio.h> 686 \\int main() { 687 \\ printf("Hello world!\n"); 688 \\ return 0; 689 \\} 690 }); 691 692 const run = addRunArtifact(exe); 693 run.expectStdOutEqual("Hello world!\n"); 694 test_step.dependOn(&run.step); 695 696 const check = exe.checkObject(); 697 check.checkInHeaders(); 698 check.checkExact("header"); 699 check.checkContains("PIE"); 700 test_step.dependOn(&check.step); 701 702 return test_step; 703 } 704 705 fn testHelloZig(b: *Build, opts: Options) *Step { 706 const test_step = addTestStep(b, "hello-zig", opts); 707 708 const exe = addExecutable(b, opts, .{ .name = "main", .zig_source_bytes = 709 \\const std = @import("std"); 710 \\pub fn main() void { 711 \\ std.io.getStdOut().writer().print("Hello world!\n", .{}) catch unreachable; 712 \\} 713 }); 714 715 const run = addRunArtifact(exe); 716 run.expectStdOutEqual("Hello world!\n"); 717 test_step.dependOn(&run.step); 718 719 return test_step; 720 } 721 722 fn testLargeBss(b: *Build, opts: Options) *Step { 723 const test_step = addTestStep(b, "large-bss", opts); 724 725 // TODO this test used use a 4GB zerofill section but this actually fails and causes every 726 // linker I tried misbehave in different ways. This only happened on arm64. I thought that 727 // maybe S_GB_ZEROFILL section is an answer to this but it doesn't seem supported by dyld 728 // anymore. When I get some free time I will re-investigate this. 729 const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = 730 \\char arr[0x1000000]; 731 \\int main() { 732 \\ return arr[2000]; 733 \\} 734 }); 735 736 const run = addRunArtifact(exe); 737 run.expectExitCode(0); 738 test_step.dependOn(&run.step); 739 740 return test_step; 741 } 742 743 fn testLayout(b: *Build, opts: Options) *Step { 744 const test_step = addTestStep(b, "layout", opts); 745 746 const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = 747 \\#include <stdio.h> 748 \\int main() { 749 \\ printf("Hello world!"); 750 \\ return 0; 751 \\} 752 }); 753 754 const check = exe.checkObject(); 755 check.checkInHeaders(); 756 check.checkExact("cmd SEGMENT_64"); 757 check.checkExact("segname __LINKEDIT"); 758 check.checkExtract("fileoff {fileoff}"); 759 check.checkExtract("filesz {filesz}"); 760 check.checkInHeaders(); 761 check.checkExact("cmd DYLD_INFO_ONLY"); 762 check.checkExtract("rebaseoff {rebaseoff}"); 763 check.checkExtract("rebasesize {rebasesize}"); 764 check.checkExtract("bindoff {bindoff}"); 765 check.checkExtract("bindsize {bindsize}"); 766 check.checkExtract("lazybindoff {lazybindoff}"); 767 check.checkExtract("lazybindsize {lazybindsize}"); 768 check.checkExtract("exportoff {exportoff}"); 769 check.checkExtract("exportsize {exportsize}"); 770 check.checkInHeaders(); 771 check.checkExact("cmd FUNCTION_STARTS"); 772 check.checkExtract("dataoff {fstartoff}"); 773 check.checkExtract("datasize {fstartsize}"); 774 check.checkInHeaders(); 775 check.checkExact("cmd DATA_IN_CODE"); 776 check.checkExtract("dataoff {diceoff}"); 777 check.checkExtract("datasize {dicesize}"); 778 check.checkInHeaders(); 779 check.checkExact("cmd SYMTAB"); 780 check.checkExtract("symoff {symoff}"); 781 check.checkExtract("nsyms {symnsyms}"); 782 check.checkExtract("stroff {stroff}"); 783 check.checkExtract("strsize {strsize}"); 784 check.checkInHeaders(); 785 check.checkExact("cmd DYSYMTAB"); 786 check.checkExtract("indirectsymoff {dysymoff}"); 787 check.checkExtract("nindirectsyms {dysymnsyms}"); 788 789 switch (opts.target.result.cpu.arch) { 790 .aarch64 => { 791 check.checkInHeaders(); 792 check.checkExact("cmd CODE_SIGNATURE"); 793 check.checkExtract("dataoff {codesigoff}"); 794 check.checkExtract("datasize {codesigsize}"); 795 }, 796 .x86_64 => {}, 797 else => unreachable, 798 } 799 800 // DYLD_INFO_ONLY subsections are in order: rebase < bind < lazy < export, 801 // and there are no gaps between them 802 check.checkComputeCompare("rebaseoff rebasesize +", .{ .op = .eq, .value = .{ .variable = "bindoff" } }); 803 check.checkComputeCompare("bindoff bindsize +", .{ .op = .eq, .value = .{ .variable = "lazybindoff" } }); 804 check.checkComputeCompare("lazybindoff lazybindsize +", .{ .op = .eq, .value = .{ .variable = "exportoff" } }); 805 806 // FUNCTION_STARTS directly follows DYLD_INFO_ONLY (no gap) 807 check.checkComputeCompare("exportoff exportsize +", .{ .op = .eq, .value = .{ .variable = "fstartoff" } }); 808 809 // DATA_IN_CODE directly follows FUNCTION_STARTS (no gap) 810 check.checkComputeCompare("fstartoff fstartsize +", .{ .op = .eq, .value = .{ .variable = "diceoff" } }); 811 812 // SYMTAB directly follows DATA_IN_CODE (no gap) 813 check.checkComputeCompare("diceoff dicesize +", .{ .op = .eq, .value = .{ .variable = "symoff" } }); 814 815 // DYSYMTAB directly follows SYMTAB (no gap) 816 check.checkComputeCompare("symnsyms 16 symoff * +", .{ .op = .eq, .value = .{ .variable = "dysymoff" } }); 817 818 // STRTAB follows DYSYMTAB with possible gap 819 check.checkComputeCompare("dysymnsyms 4 dysymoff * +", .{ .op = .lte, .value = .{ .variable = "stroff" } }); 820 821 // all LINKEDIT sections apart from CODE_SIGNATURE are 8-bytes aligned 822 check.checkComputeCompare("rebaseoff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } }); 823 check.checkComputeCompare("bindoff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } }); 824 check.checkComputeCompare("lazybindoff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } }); 825 check.checkComputeCompare("exportoff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } }); 826 check.checkComputeCompare("fstartoff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } }); 827 check.checkComputeCompare("diceoff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } }); 828 check.checkComputeCompare("symoff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } }); 829 check.checkComputeCompare("stroff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } }); 830 check.checkComputeCompare("dysymoff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } }); 831 832 switch (opts.target.result.cpu.arch) { 833 .aarch64 => { 834 // LINKEDIT segment does not extend beyond, or does not include, CODE_SIGNATURE data 835 check.checkComputeCompare("fileoff filesz codesigoff codesigsize + - -", .{ 836 .op = .eq, 837 .value = .{ .literal = 0 }, 838 }); 839 840 // CODE_SIGNATURE data offset is 16-bytes aligned 841 check.checkComputeCompare("codesigoff 16 %", .{ .op = .eq, .value = .{ .literal = 0 } }); 842 }, 843 .x86_64 => { 844 // LINKEDIT segment does not extend beyond, or does not include, strtab data 845 check.checkComputeCompare("fileoff filesz stroff strsize + - -", .{ 846 .op = .eq, 847 .value = .{ .literal = 0 }, 848 }); 849 }, 850 else => unreachable, 851 } 852 853 test_step.dependOn(&check.step); 854 855 const run = addRunArtifact(exe); 856 run.expectStdOutEqual("Hello world!"); 857 test_step.dependOn(&run.step); 858 859 return test_step; 860 } 861 862 fn testLinkDirectlyCppTbd(b: *Build, opts: Options) *Step { 863 const test_step = addTestStep(b, "link-directly-cpp-tbd", opts); 864 865 const sdk = std.zig.system.darwin.getSdk(b.allocator, opts.target.result) orelse 866 @panic("macOS SDK is required to run the test"); 867 868 const exe = addExecutable(b, opts, .{ 869 .name = "main", 870 .cpp_source_bytes = 871 \\#include <new> 872 \\#include <cstdio> 873 \\int main() { 874 \\ int *x = new int; 875 \\ *x = 5; 876 \\ fprintf(stderr, "x: %d\n", *x); 877 \\ delete x; 878 \\} 879 , 880 .cpp_source_flags = &.{ "-nostdlib++", "-nostdinc++" }, 881 }); 882 exe.root_module.addSystemIncludePath(.{ .cwd_relative = b.pathJoin(&.{ sdk, "/usr/include" }) }); 883 exe.root_module.addIncludePath(.{ .cwd_relative = b.pathJoin(&.{ sdk, "/usr/include/c++/v1" }) }); 884 exe.root_module.addObjectFile(.{ .cwd_relative = b.pathJoin(&.{ sdk, "/usr/lib/libc++.tbd" }) }); 885 886 const check = exe.checkObject(); 887 check.checkInSymtab(); 888 check.checkContains("[referenced dynamically] external __mh_execute_header"); 889 test_step.dependOn(&check.step); 890 891 return test_step; 892 } 893 894 fn testLinkingStaticLib(b: *Build, opts: Options) *Step { 895 const test_step = addTestStep(b, "linking-static-lib", opts); 896 897 const obj = addObject(b, opts, .{ 898 .name = "bobj", 899 .zig_source_bytes = "export var bar: i32 = -42;", 900 .strip = true, // TODO for self-hosted, we don't really emit any valid DWARF yet since we only export a global 901 }); 902 903 const lib = addStaticLibrary(b, opts, .{ 904 .name = "alib", 905 .zig_source_bytes = 906 \\export fn foo() i32 { 907 \\ return 42; 908 \\} 909 , 910 }); 911 lib.addObject(obj); 912 913 const exe = addExecutable(b, opts, .{ 914 .name = "testlib", 915 .zig_source_bytes = 916 \\const std = @import("std"); 917 \\extern fn foo() i32; 918 \\extern var bar: i32; 919 \\pub fn main() void { 920 \\ std.debug.print("{d}\n", .{foo() + bar}); 921 \\} 922 , 923 }); 924 exe.linkLibrary(lib); 925 926 const run = addRunArtifact(exe); 927 run.expectStdErrEqual("0\n"); 928 test_step.dependOn(&run.step); 929 930 return test_step; 931 } 932 933 fn testLinksection(b: *Build, opts: Options) *Step { 934 const test_step = addTestStep(b, "linksection", opts); 935 936 const obj = addObject(b, opts, .{ .name = "main", .zig_source_bytes = 937 \\export var test_global: u32 linksection("__DATA,__TestGlobal") = undefined; 938 \\export fn testFn() linksection("__TEXT,__TestFn") callconv(.C) void { 939 \\ testGenericFn("A"); 940 \\} 941 \\fn testGenericFn(comptime suffix: []const u8) linksection("__TEXT,__TestGenFn" ++ suffix) void {} 942 }); 943 944 const check = obj.checkObject(); 945 check.checkInSymtab(); 946 check.checkContains("(__DATA,__TestGlobal) external _test_global"); 947 check.checkInSymtab(); 948 check.checkContains("(__TEXT,__TestFn) external _testFn"); 949 950 if (opts.optimize == .Debug) { 951 check.checkInSymtab(); 952 check.checkContains("(__TEXT,__TestGenFnA) _main.testGenericFn__anon_"); 953 } 954 955 test_step.dependOn(&check.step); 956 957 return test_step; 958 } 959 960 fn testMergeLiteralsX64(b: *Build, opts: Options) *Step { 961 const test_step = addTestStep(b, "merge-literals-x64", opts); 962 963 const a_o = addObject(b, opts, .{ .name = "a", .asm_source_bytes = 964 \\.globl _q1 965 \\.globl _s1 966 \\ 967 \\.align 4 968 \\_q1: 969 \\ lea L._q1(%rip), %rax 970 \\ mov (%rax), %xmm0 971 \\ ret 972 \\ 973 \\.section __TEXT,__cstring,cstring_literals 974 \\l._s1: 975 \\ .asciz "hello" 976 \\ 977 \\.section __TEXT,__literal8,8byte_literals 978 \\.align 8 979 \\L._q1: 980 \\ .double 1.2345 981 \\ 982 \\.section __DATA,__data 983 \\.align 8 984 \\_s1: 985 \\ .quad l._s1 986 }); 987 988 const b_o = addObject(b, opts, .{ .name = "b", .asm_source_bytes = 989 \\.globl _q2 990 \\.globl _s2 991 \\.globl _s3 992 \\ 993 \\.align 4 994 \\_q2: 995 \\ lea L._q2(%rip), %rax 996 \\ mov (%rax), %xmm0 997 \\ ret 998 \\ 999 \\.section __TEXT,__cstring,cstring_literals 1000 \\l._s2: 1001 \\ .asciz "hello" 1002 \\l._s3: 1003 \\ .asciz "world" 1004 \\ 1005 \\.section __TEXT,__literal8,8byte_literals 1006 \\.align 8 1007 \\L._q2: 1008 \\ .double 1.2345 1009 \\ 1010 \\.section __DATA,__data 1011 \\.align 8 1012 \\_s2: 1013 \\ .quad l._s2 1014 \\_s3: 1015 \\ .quad l._s3 1016 }); 1017 1018 const main_o = addObject(b, opts, .{ .name = "main", .c_source_bytes = 1019 \\#include <stdio.h> 1020 \\extern double q1(); 1021 \\extern double q2(); 1022 \\extern const char* s1; 1023 \\extern const char* s2; 1024 \\extern const char* s3; 1025 \\int main() { 1026 \\ printf("%s, %s, %s, %f, %f", s1, s2, s3, q1(), q2()); 1027 \\ return 0; 1028 \\} 1029 }); 1030 1031 const runWithChecks = struct { 1032 fn runWithChecks(step: *Step, exe: *Compile) void { 1033 const run = addRunArtifact(exe); 1034 run.expectStdOutEqual("hello, hello, world, 1.234500, 1.234500"); 1035 step.dependOn(&run.step); 1036 1037 const check = exe.checkObject(); 1038 check.dumpSection("__TEXT,__const"); 1039 check.checkContains("\x8d\x97n\x12\x83\xc0\xf3?"); 1040 check.dumpSection("__TEXT,__cstring"); 1041 check.checkContains("hello\x00world\x00%s, %s, %s, %f, %f\x00"); 1042 step.dependOn(&check.step); 1043 } 1044 }.runWithChecks; 1045 1046 { 1047 const exe = addExecutable(b, opts, .{ .name = "main1" }); 1048 exe.addObject(a_o); 1049 exe.addObject(b_o); 1050 exe.addObject(main_o); 1051 runWithChecks(test_step, exe); 1052 } 1053 1054 { 1055 const exe = addExecutable(b, opts, .{ .name = "main2" }); 1056 exe.addObject(b_o); 1057 exe.addObject(a_o); 1058 exe.addObject(main_o); 1059 runWithChecks(test_step, exe); 1060 } 1061 1062 { 1063 const c_o = addObject(b, opts, .{ .name = "c" }); 1064 c_o.addObject(a_o); 1065 c_o.addObject(b_o); 1066 c_o.addObject(main_o); 1067 1068 const exe = addExecutable(b, opts, .{ .name = "main3" }); 1069 exe.addObject(c_o); 1070 runWithChecks(test_step, exe); 1071 } 1072 1073 return test_step; 1074 } 1075 1076 fn testMergeLiteralsArm64(b: *Build, opts: Options) *Step { 1077 const test_step = addTestStep(b, "merge-literals-arm64", opts); 1078 1079 const a_o = addObject(b, opts, .{ .name = "a", .asm_source_bytes = 1080 \\.globl _q1 1081 \\.globl _s1 1082 \\ 1083 \\.align 4 1084 \\_q1: 1085 \\ adrp x8, L._q1@PAGE 1086 \\ ldr d0, [x8, L._q1@PAGEOFF] 1087 \\ ret 1088 \\ 1089 \\.section __TEXT,__cstring,cstring_literals 1090 \\l._s1: 1091 \\ .asciz "hello" 1092 \\ 1093 \\.section __TEXT,__literal8,8byte_literals 1094 \\.align 8 1095 \\L._q1: 1096 \\ .double 1.2345 1097 \\ 1098 \\.section __DATA,__data 1099 \\.align 8 1100 \\_s1: 1101 \\ .quad l._s1 1102 }); 1103 1104 const b_o = addObject(b, opts, .{ .name = "b", .asm_source_bytes = 1105 \\.globl _q2 1106 \\.globl _s2 1107 \\.globl _s3 1108 \\ 1109 \\.align 4 1110 \\_q2: 1111 \\ adrp x8, L._q2@PAGE 1112 \\ ldr d0, [x8, L._q2@PAGEOFF] 1113 \\ ret 1114 \\ 1115 \\.section __TEXT,__cstring,cstring_literals 1116 \\l._s2: 1117 \\ .asciz "hello" 1118 \\l._s3: 1119 \\ .asciz "world" 1120 \\ 1121 \\.section __TEXT,__literal8,8byte_literals 1122 \\.align 8 1123 \\L._q2: 1124 \\ .double 1.2345 1125 \\ 1126 \\.section __DATA,__data 1127 \\.align 8 1128 \\_s2: 1129 \\ .quad l._s2 1130 \\_s3: 1131 \\ .quad l._s3 1132 }); 1133 1134 const main_o = addObject(b, opts, .{ .name = "main", .c_source_bytes = 1135 \\#include <stdio.h> 1136 \\extern double q1(); 1137 \\extern double q2(); 1138 \\extern const char* s1; 1139 \\extern const char* s2; 1140 \\extern const char* s3; 1141 \\int main() { 1142 \\ printf("%s, %s, %s, %f, %f", s1, s2, s3, q1(), q2()); 1143 \\ return 0; 1144 \\} 1145 }); 1146 1147 const runWithChecks = struct { 1148 fn runWithChecks(step: *Step, exe: *Compile) void { 1149 const run = addRunArtifact(exe); 1150 run.expectStdOutEqual("hello, hello, world, 1.234500, 1.234500"); 1151 step.dependOn(&run.step); 1152 1153 const check = exe.checkObject(); 1154 check.dumpSection("__TEXT,__const"); 1155 check.checkContains("\x8d\x97n\x12\x83\xc0\xf3?"); 1156 check.dumpSection("__TEXT,__cstring"); 1157 check.checkContains("hello\x00world\x00%s, %s, %s, %f, %f\x00"); 1158 step.dependOn(&check.step); 1159 } 1160 }.runWithChecks; 1161 1162 { 1163 const exe = addExecutable(b, opts, .{ .name = "main1" }); 1164 exe.addObject(a_o); 1165 exe.addObject(b_o); 1166 exe.addObject(main_o); 1167 runWithChecks(test_step, exe); 1168 } 1169 1170 { 1171 const exe = addExecutable(b, opts, .{ .name = "main2" }); 1172 exe.addObject(b_o); 1173 exe.addObject(a_o); 1174 exe.addObject(main_o); 1175 runWithChecks(test_step, exe); 1176 } 1177 1178 { 1179 const c_o = addObject(b, opts, .{ .name = "c" }); 1180 c_o.addObject(a_o); 1181 c_o.addObject(b_o); 1182 c_o.addObject(main_o); 1183 1184 const exe = addExecutable(b, opts, .{ .name = "main3" }); 1185 exe.addObject(c_o); 1186 runWithChecks(test_step, exe); 1187 } 1188 1189 return test_step; 1190 } 1191 1192 /// This particular test case will generate invalid machine code that will segfault at runtime. 1193 /// However, this is by design as we want to test that the linker does not panic when linking it 1194 /// which is also the case for the system linker and lld - linking succeeds, runtime segfaults. 1195 /// It should also be mentioned that runtime segfault is not due to the linker but faulty input asm. 1196 fn testMergeLiteralsArm642(b: *Build, opts: Options) *Step { 1197 const test_step = addTestStep(b, "merge-literals-arm64-2", opts); 1198 1199 const a_o = addObject(b, opts, .{ .name = "a", .asm_source_bytes = 1200 \\.globl _q1 1201 \\.globl _s1 1202 \\ 1203 \\.align 4 1204 \\_q1: 1205 \\ adrp x0, L._q1@PAGE 1206 \\ ldr x0, [x0, L._q1@PAGEOFF] 1207 \\ ret 1208 \\ 1209 \\.section __TEXT,__cstring,cstring_literals 1210 \\_s1: 1211 \\ .asciz "hello" 1212 \\ 1213 \\.section __TEXT,__literal8,8byte_literals 1214 \\.align 8 1215 \\L._q1: 1216 \\ .double 1.2345 1217 }); 1218 1219 const b_o = addObject(b, opts, .{ .name = "b", .asm_source_bytes = 1220 \\.globl _q2 1221 \\.globl _s2 1222 \\.globl _s3 1223 \\ 1224 \\.align 4 1225 \\_q2: 1226 \\ adrp x0, L._q2@PAGE 1227 \\ ldr x0, [x0, L._q2@PAGEOFF] 1228 \\ ret 1229 \\ 1230 \\.section __TEXT,__cstring,cstring_literals 1231 \\_s2: 1232 \\ .asciz "hello" 1233 \\_s3: 1234 \\ .asciz "world" 1235 \\ 1236 \\.section __TEXT,__literal8,8byte_literals 1237 \\.align 8 1238 \\L._q2: 1239 \\ .double 1.2345 1240 }); 1241 1242 const main_o = addObject(b, opts, .{ .name = "main", .c_source_bytes = 1243 \\#include <stdio.h> 1244 \\extern double q1(); 1245 \\extern double q2(); 1246 \\extern const char* s1; 1247 \\extern const char* s2; 1248 \\extern const char* s3; 1249 \\int main() { 1250 \\ printf("%s, %s, %s, %f, %f", s1, s2, s3, q1(), q2()); 1251 \\ return 0; 1252 \\} 1253 }); 1254 1255 const exe = addExecutable(b, opts, .{ .name = "main1" }); 1256 exe.addObject(a_o); 1257 exe.addObject(b_o); 1258 exe.addObject(main_o); 1259 1260 const check = exe.checkObject(); 1261 check.dumpSection("__TEXT,__const"); 1262 check.checkContains("\x8d\x97n\x12\x83\xc0\xf3?"); 1263 check.dumpSection("__TEXT,__cstring"); 1264 check.checkContains("hello\x00world\x00%s, %s, %s, %f, %f\x00"); 1265 test_step.dependOn(&check.step); 1266 1267 return test_step; 1268 } 1269 1270 fn testMergeLiteralsAlignment(b: *Build, opts: Options) *Step { 1271 const test_step = addTestStep(b, "merge-literals-alignment", opts); 1272 1273 const a_o = addObject(b, opts, .{ .name = "a", .asm_source_bytes = 1274 \\.globl _s1 1275 \\.globl _s2 1276 \\ 1277 \\.section __TEXT,__cstring,cstring_literals 1278 \\.align 3 1279 \\_s1: 1280 \\ .asciz "str1" 1281 \\_s2: 1282 \\ .asciz "str2" 1283 }); 1284 1285 const b_o = addObject(b, opts, .{ .name = "b", .asm_source_bytes = 1286 \\.globl _s3 1287 \\.globl _s4 1288 \\ 1289 \\.section __TEXT,__cstring,cstring_literals 1290 \\.align 2 1291 \\_s3: 1292 \\ .asciz "str1" 1293 \\_s4: 1294 \\ .asciz "str2" 1295 }); 1296 1297 const main_o = addObject(b, opts, .{ .name = "main", .c_source_bytes = 1298 \\#include <assert.h> 1299 \\#include <stdint.h> 1300 \\#include <stdio.h> 1301 \\extern const char* s1; 1302 \\extern const char* s2; 1303 \\extern const char* s3; 1304 \\extern const char* s4; 1305 \\int main() { 1306 \\ assert((uintptr_t)(&s1) % 8 == 0 && s1 == s3); 1307 \\ assert((uintptr_t)(&s2) % 8 == 0 && s2 == s4); 1308 \\ printf("%s%s%s%s", &s1, &s2, &s3, &s4); 1309 \\ return 0; 1310 \\} 1311 , .c_source_flags = &.{"-Wno-format"} }); 1312 1313 const runWithChecks = struct { 1314 fn runWithChecks(step: *Step, exe: *Compile) void { 1315 const run = addRunArtifact(exe); 1316 run.expectStdOutEqual("str1str2str1str2"); 1317 step.dependOn(&run.step); 1318 1319 const check = exe.checkObject(); 1320 check.dumpSection("__TEXT,__cstring"); 1321 check.checkContains("str1\x00\x00\x00\x00str2\x00"); 1322 check.checkInHeaders(); 1323 check.checkExact("segname __TEXT"); 1324 check.checkExact("sectname __cstring"); 1325 check.checkExact("align 3"); 1326 step.dependOn(&check.step); 1327 } 1328 }.runWithChecks; 1329 1330 { 1331 const exe = addExecutable(b, opts, .{ .name = "main1" }); 1332 exe.addObject(a_o); 1333 exe.addObject(b_o); 1334 exe.addObject(main_o); 1335 runWithChecks(test_step, exe); 1336 } 1337 1338 { 1339 const exe = addExecutable(b, opts, .{ .name = "main2" }); 1340 exe.addObject(b_o); 1341 exe.addObject(a_o); 1342 exe.addObject(main_o); 1343 runWithChecks(test_step, exe); 1344 } 1345 1346 return test_step; 1347 } 1348 1349 fn testMergeLiteralsObjc(b: *Build, opts: Options) *Step { 1350 const test_step = addTestStep(b, "merge-literals-objc", opts); 1351 1352 const main_o = addObject(b, opts, .{ .name = "main", .objc_source_bytes = 1353 \\#import <Foundation/Foundation.h>; 1354 \\ 1355 \\extern void foo(); 1356 \\ 1357 \\int main() { 1358 \\ NSString *thing = @"aaa"; 1359 \\ 1360 \\ SEL sel = @selector(lowercaseString); 1361 \\ NSString *lower = (([thing respondsToSelector:sel]) ? @"YES" : @"NO"); 1362 \\ NSLog (@"Responds to lowercaseString: %@", lower); 1363 \\ if ([thing respondsToSelector:sel]) //(lower == @"YES") 1364 \\ NSLog(@"lowercaseString is: %@", [thing lowercaseString]); 1365 \\ 1366 \\ foo(); 1367 \\} 1368 }); 1369 1370 const a_o = addObject(b, opts, .{ .name = "a", .objc_source_bytes = 1371 \\#import <Foundation/Foundation.h>; 1372 \\ 1373 \\void foo() { 1374 \\ NSString *thing = @"aaa"; 1375 \\ SEL sel = @selector(lowercaseString); 1376 \\ NSString *lower = (([thing respondsToSelector:sel]) ? @"YES" : @"NO"); 1377 \\ NSLog (@"Responds to lowercaseString in foo(): %@", lower); 1378 \\ if ([thing respondsToSelector:sel]) //(lower == @"YES") 1379 \\ NSLog(@"lowercaseString in foo() is: %@", [thing lowercaseString]); 1380 \\ SEL sel2 = @selector(uppercaseString); 1381 \\ NSString *upper = (([thing respondsToSelector:sel2]) ? @"YES" : @"NO"); 1382 \\ NSLog (@"Responds to uppercaseString in foo(): %@", upper); 1383 \\ if ([thing respondsToSelector:sel2]) //(upper == @"YES") 1384 \\ NSLog(@"uppercaseString in foo() is: %@", [thing uppercaseString]); 1385 \\} 1386 }); 1387 1388 const runWithChecks = struct { 1389 fn runWithChecks(step: *Step, exe: *Compile) void { 1390 const builder = step.owner; 1391 const run = addRunArtifact(exe); 1392 run.addCheck(.{ .expect_stderr_match = builder.dupe("Responds to lowercaseString: YES") }); 1393 run.addCheck(.{ .expect_stderr_match = builder.dupe("lowercaseString is: aaa") }); 1394 run.addCheck(.{ .expect_stderr_match = builder.dupe("Responds to lowercaseString in foo(): YES") }); 1395 run.addCheck(.{ .expect_stderr_match = builder.dupe("lowercaseString in foo() is: aaa") }); 1396 run.addCheck(.{ .expect_stderr_match = builder.dupe("Responds to uppercaseString in foo(): YES") }); 1397 run.addCheck(.{ .expect_stderr_match = builder.dupe("uppercaseString in foo() is: AAA") }); 1398 step.dependOn(&run.step); 1399 1400 const check = exe.checkObject(); 1401 check.dumpSection("__TEXT,__objc_methname"); 1402 check.checkContains("lowercaseString\x00"); 1403 check.dumpSection("__TEXT,__objc_methname"); 1404 check.checkContains("uppercaseString\x00"); 1405 step.dependOn(&check.step); 1406 } 1407 }.runWithChecks; 1408 1409 { 1410 const exe = addExecutable(b, opts, .{ .name = "main1" }); 1411 exe.addObject(main_o); 1412 exe.addObject(a_o); 1413 exe.root_module.linkFramework("Foundation", .{}); 1414 runWithChecks(test_step, exe); 1415 } 1416 1417 { 1418 const exe = addExecutable(b, opts, .{ .name = "main2" }); 1419 exe.addObject(a_o); 1420 exe.addObject(main_o); 1421 exe.root_module.linkFramework("Foundation", .{}); 1422 runWithChecks(test_step, exe); 1423 } 1424 1425 { 1426 const b_o = addObject(b, opts, .{ .name = "b" }); 1427 b_o.addObject(a_o); 1428 b_o.addObject(main_o); 1429 1430 const exe = addExecutable(b, opts, .{ .name = "main3" }); 1431 exe.addObject(b_o); 1432 exe.root_module.linkFramework("Foundation", .{}); 1433 runWithChecks(test_step, exe); 1434 } 1435 1436 return test_step; 1437 } 1438 1439 fn testMhExecuteHeader(b: *Build, opts: Options) *Step { 1440 const test_step = addTestStep(b, "mh-execute-header", opts); 1441 1442 const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = "int main() { return 0; }" }); 1443 1444 const check = exe.checkObject(); 1445 check.checkInSymtab(); 1446 check.checkContains("[referenced dynamically] external __mh_execute_header"); 1447 test_step.dependOn(&check.step); 1448 1449 return test_step; 1450 } 1451 1452 fn testNoDeadStrip(b: *Build, opts: Options) *Step { 1453 const test_step = addTestStep(b, "no-dead-strip", opts); 1454 1455 const exe = addExecutable(b, opts, .{ .name = "name", .c_source_bytes = 1456 \\__attribute__((used)) int bogus1 = 0; 1457 \\int bogus2 = 0; 1458 \\int foo = 42; 1459 \\int main() { 1460 \\ return foo - 42; 1461 \\} 1462 }); 1463 exe.link_gc_sections = true; 1464 1465 const check = exe.checkObject(); 1466 check.checkInSymtab(); 1467 check.checkContains("external _bogus1"); 1468 check.checkInSymtab(); 1469 check.checkNotPresent("external _bogus2"); 1470 test_step.dependOn(&check.step); 1471 1472 const run = addRunArtifact(exe); 1473 run.expectExitCode(0); 1474 test_step.dependOn(&run.step); 1475 1476 return test_step; 1477 } 1478 1479 fn testNoExportsDylib(b: *Build, opts: Options) *Step { 1480 const test_step = addTestStep(b, "no-exports-dylib", opts); 1481 1482 const dylib = addSharedLibrary(b, opts, .{ .name = "a", .c_source_bytes = "static void abc() {}" }); 1483 1484 const check = dylib.checkObject(); 1485 check.checkInSymtab(); 1486 check.checkNotPresent("external _abc"); 1487 test_step.dependOn(&check.step); 1488 1489 return test_step; 1490 } 1491 1492 fn testNeededFramework(b: *Build, opts: Options) *Step { 1493 const test_step = addTestStep(b, "needed-framework", opts); 1494 1495 const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = "int main() { return 0; }" }); 1496 exe.root_module.linkFramework("Cocoa", .{ .needed = true }); 1497 exe.dead_strip_dylibs = true; 1498 1499 const check = exe.checkObject(); 1500 check.checkInHeaders(); 1501 check.checkExact("cmd LOAD_DYLIB"); 1502 check.checkContains("Cocoa"); 1503 test_step.dependOn(&check.step); 1504 1505 const run = addRunArtifact(exe); 1506 run.expectExitCode(0); 1507 test_step.dependOn(&run.step); 1508 1509 return test_step; 1510 } 1511 1512 fn testNeededLibrary(b: *Build, opts: Options) *Step { 1513 const test_step = addTestStep(b, "needed-library", opts); 1514 1515 const dylib = addSharedLibrary(b, opts, .{ .name = "a", .c_source_bytes = "int a = 42;" }); 1516 1517 const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = "int main() { return 0; }" }); 1518 exe.root_module.linkSystemLibrary("a", .{ .needed = true }); 1519 exe.root_module.addLibraryPath(dylib.getEmittedBinDirectory()); 1520 exe.root_module.addRPath(dylib.getEmittedBinDirectory()); 1521 exe.dead_strip_dylibs = true; 1522 1523 const check = exe.checkObject(); 1524 check.checkInHeaders(); 1525 check.checkExact("cmd LOAD_DYLIB"); 1526 check.checkContains("liba.dylib"); 1527 test_step.dependOn(&check.step); 1528 1529 const run = addRunArtifact(exe); 1530 run.expectExitCode(0); 1531 test_step.dependOn(&run.step); 1532 1533 return test_step; 1534 } 1535 1536 fn testObjc(b: *Build, opts: Options) *Step { 1537 const test_step = addTestStep(b, "objc", opts); 1538 1539 const lib = addStaticLibrary(b, opts, .{ .name = "a", .objc_source_bytes = 1540 \\#import <Foundation/Foundation.h> 1541 \\@interface Foo : NSObject 1542 \\@end 1543 \\@implementation Foo 1544 \\@end 1545 }); 1546 1547 { 1548 const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = "int main() { return 0; }" }); 1549 exe.root_module.linkSystemLibrary("a", .{}); 1550 exe.root_module.linkFramework("Foundation", .{}); 1551 exe.root_module.addLibraryPath(lib.getEmittedBinDirectory()); 1552 1553 const check = exe.checkObject(); 1554 check.checkInSymtab(); 1555 check.checkNotPresent("_OBJC_"); 1556 test_step.dependOn(&check.step); 1557 1558 const run = addRunArtifact(exe); 1559 run.expectExitCode(0); 1560 test_step.dependOn(&run.step); 1561 } 1562 1563 { 1564 const exe = addExecutable(b, opts, .{ .name = "main2", .c_source_bytes = "int main() { return 0; }" }); 1565 exe.root_module.linkSystemLibrary("a", .{}); 1566 exe.root_module.linkFramework("Foundation", .{}); 1567 exe.root_module.addLibraryPath(lib.getEmittedBinDirectory()); 1568 exe.force_load_objc = true; 1569 1570 const check = exe.checkObject(); 1571 check.checkInSymtab(); 1572 check.checkContains("_OBJC_"); 1573 test_step.dependOn(&check.step); 1574 1575 const run = addRunArtifact(exe); 1576 run.expectExitCode(0); 1577 test_step.dependOn(&run.step); 1578 } 1579 1580 return test_step; 1581 } 1582 1583 fn testObjcpp(b: *Build, opts: Options) *Step { 1584 const test_step = addTestStep(b, "objcpp", opts); 1585 1586 const foo_h = foo_h: { 1587 const wf = WriteFile.create(b); 1588 break :foo_h wf.add("Foo.h", 1589 \\#import <Foundation/Foundation.h> 1590 \\@interface Foo : NSObject 1591 \\- (NSString *)name; 1592 \\@end 1593 ); 1594 }; 1595 1596 const foo_o = addObject(b, opts, .{ .name = "foo", .objcpp_source_bytes = 1597 \\#import "Foo.h" 1598 \\@implementation Foo 1599 \\- (NSString *)name 1600 \\{ 1601 \\ NSString *str = [[NSString alloc] initWithFormat:@"Zig"]; 1602 \\ return str; 1603 \\} 1604 \\@end 1605 }); 1606 foo_o.root_module.addIncludePath(foo_h.dirname()); 1607 foo_o.linkLibCpp(); 1608 1609 const exe = addExecutable(b, opts, .{ .name = "main", .objcpp_source_bytes = 1610 \\#import "Foo.h" 1611 \\#import <assert.h> 1612 \\#include <iostream> 1613 \\int main(int argc, char *argv[]) 1614 \\{ 1615 \\ @autoreleasepool { 1616 \\ Foo *foo = [[Foo alloc] init]; 1617 \\ NSString *result = [foo name]; 1618 \\ std::cout << "Hello from C++ and " << [result UTF8String]; 1619 \\ assert([result isEqualToString:@"Zig"]); 1620 \\ return 0; 1621 \\ } 1622 \\} 1623 }); 1624 exe.root_module.addIncludePath(foo_h.dirname()); 1625 exe.addObject(foo_o); 1626 exe.linkLibCpp(); 1627 exe.root_module.linkFramework("Foundation", .{}); 1628 1629 const run = addRunArtifact(exe); 1630 run.expectStdOutEqual("Hello from C++ and Zig"); 1631 test_step.dependOn(&run.step); 1632 1633 return test_step; 1634 } 1635 1636 fn testPagezeroSize(b: *Build, opts: Options) *Step { 1637 const test_step = addTestStep(b, "pagezero-size", opts); 1638 1639 { 1640 const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = "int main () { return 0; }" }); 1641 exe.pagezero_size = 0x4000; 1642 1643 const check = exe.checkObject(); 1644 check.checkInHeaders(); 1645 check.checkExact("LC 0"); 1646 check.checkExact("segname __PAGEZERO"); 1647 check.checkExact("vmaddr 0"); 1648 check.checkExact("vmsize 4000"); 1649 check.checkInHeaders(); 1650 check.checkExact("segname __TEXT"); 1651 check.checkExact("vmaddr 4000"); 1652 test_step.dependOn(&check.step); 1653 } 1654 1655 { 1656 const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = "int main () { return 0; }" }); 1657 exe.pagezero_size = 0; 1658 1659 const check = exe.checkObject(); 1660 check.checkInHeaders(); 1661 check.checkExact("LC 0"); 1662 check.checkExact("segname __TEXT"); 1663 check.checkExact("vmaddr 0"); 1664 test_step.dependOn(&check.step); 1665 } 1666 1667 return test_step; 1668 } 1669 1670 fn testReexportsZig(b: *Build, opts: Options) *Step { 1671 const test_step = addTestStep(b, "reexports-zig", opts); 1672 1673 const lib = addStaticLibrary(b, opts, .{ .name = "a", .zig_source_bytes = 1674 \\const x: i32 = 42; 1675 \\export fn foo() i32 { 1676 \\ return x; 1677 \\} 1678 \\comptime { 1679 \\ @export(foo, .{ .name = "bar", .linkage = .strong }); 1680 \\} 1681 }); 1682 1683 const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = 1684 \\extern int foo(); 1685 \\extern int bar(); 1686 \\int main() { 1687 \\ return bar() - foo(); 1688 \\} 1689 }); 1690 exe.linkLibrary(lib); 1691 1692 const run = addRunArtifact(exe); 1693 run.expectExitCode(0); 1694 test_step.dependOn(&run.step); 1695 1696 return test_step; 1697 } 1698 1699 fn testRelocatable(b: *Build, opts: Options) *Step { 1700 const test_step = addTestStep(b, "relocatable", opts); 1701 1702 const a_o = addObject(b, opts, .{ .name = "a", .cpp_source_bytes = 1703 \\#include <stdexcept> 1704 \\int try_me() { 1705 \\ throw std::runtime_error("Oh no!"); 1706 \\} 1707 }); 1708 a_o.linkLibCpp(); 1709 1710 const b_o = addObject(b, opts, .{ .name = "b", .cpp_source_bytes = 1711 \\extern int try_me(); 1712 \\int try_again() { 1713 \\ return try_me(); 1714 \\} 1715 }); 1716 1717 const main_o = addObject(b, opts, .{ .name = "main", .cpp_source_bytes = 1718 \\#include <iostream> 1719 \\#include <stdexcept> 1720 \\extern int try_again(); 1721 \\int main() { 1722 \\ try { 1723 \\ try_again(); 1724 \\ } catch (const std::exception &e) { 1725 \\ std::cout << "exception=" << e.what(); 1726 \\ } 1727 \\ return 0; 1728 \\} 1729 }); 1730 main_o.linkLibCpp(); 1731 1732 const exp_stdout = "exception=Oh no!"; 1733 1734 { 1735 const c_o = addObject(b, opts, .{ .name = "c" }); 1736 c_o.addObject(a_o); 1737 c_o.addObject(b_o); 1738 1739 const exe = addExecutable(b, opts, .{ .name = "main1" }); 1740 exe.addObject(main_o); 1741 exe.addObject(c_o); 1742 exe.linkLibCpp(); 1743 1744 const run = addRunArtifact(exe); 1745 run.expectStdOutEqual(exp_stdout); 1746 test_step.dependOn(&run.step); 1747 } 1748 1749 { 1750 const d_o = addObject(b, opts, .{ .name = "d" }); 1751 d_o.addObject(a_o); 1752 d_o.addObject(b_o); 1753 d_o.addObject(main_o); 1754 1755 const exe = addExecutable(b, opts, .{ .name = "main2" }); 1756 exe.addObject(d_o); 1757 exe.linkLibCpp(); 1758 1759 const run = addRunArtifact(exe); 1760 run.expectStdOutEqual(exp_stdout); 1761 test_step.dependOn(&run.step); 1762 } 1763 1764 return test_step; 1765 } 1766 1767 fn testRelocatableZig(b: *Build, opts: Options) *Step { 1768 const test_step = addTestStep(b, "relocatable-zig", opts); 1769 1770 const a_o = addObject(b, opts, .{ .name = "a", .zig_source_bytes = 1771 \\const std = @import("std"); 1772 \\export var foo: i32 = 0; 1773 \\export fn incrFoo() void { 1774 \\ foo += 1; 1775 \\ std.debug.print("incrFoo={d}\n", .{foo}); 1776 \\} 1777 }); 1778 1779 const b_o = addObject(b, opts, .{ .name = "b", .zig_source_bytes = 1780 \\const std = @import("std"); 1781 \\extern var foo: i32; 1782 \\export fn decrFoo() void { 1783 \\ foo -= 1; 1784 \\ std.debug.print("decrFoo={d}\n", .{foo}); 1785 \\} 1786 }); 1787 1788 const main_o = addObject(b, opts, .{ .name = "main", .zig_source_bytes = 1789 \\const std = @import("std"); 1790 \\extern var foo: i32; 1791 \\extern fn incrFoo() void; 1792 \\extern fn decrFoo() void; 1793 \\pub fn main() void { 1794 \\ const init = foo; 1795 \\ incrFoo(); 1796 \\ decrFoo(); 1797 \\ if (init == foo) @panic("Oh no!"); 1798 \\} 1799 }); 1800 1801 const c_o = addObject(b, opts, .{ .name = "c" }); 1802 c_o.addObject(a_o); 1803 c_o.addObject(b_o); 1804 c_o.addObject(main_o); 1805 1806 const exe = addExecutable(b, opts, .{ .name = "main" }); 1807 exe.addObject(c_o); 1808 1809 const run = addRunArtifact(exe); 1810 run.addCheck(.{ .expect_stderr_match = b.dupe("incrFoo=1") }); 1811 run.addCheck(.{ .expect_stderr_match = b.dupe("decrFoo=0") }); 1812 run.addCheck(.{ .expect_stderr_match = b.dupe("panic: Oh no!") }); 1813 test_step.dependOn(&run.step); 1814 1815 return test_step; 1816 } 1817 1818 fn testSearchStrategy(b: *Build, opts: Options) *Step { 1819 const test_step = addTestStep(b, "search-strategy", opts); 1820 1821 const obj = addObject(b, opts, .{ .name = "a", .c_source_bytes = 1822 \\#include<stdio.h> 1823 \\char world[] = "world"; 1824 \\char* hello() { 1825 \\ return "Hello"; 1826 \\} 1827 }); 1828 1829 const liba = addStaticLibrary(b, opts, .{ .name = "a" }); 1830 liba.addObject(obj); 1831 1832 const dylib = addSharedLibrary(b, opts, .{ .name = "a" }); 1833 dylib.addObject(obj); 1834 1835 const main_o = addObject(b, opts, .{ .name = "main", .c_source_bytes = 1836 \\#include<stdio.h> 1837 \\char* hello(); 1838 \\extern char world[]; 1839 \\int main() { 1840 \\ printf("%s %s", hello(), world); 1841 \\ return 0; 1842 \\} 1843 }); 1844 1845 { 1846 const exe = addExecutable(b, opts, .{ .name = "main" }); 1847 exe.addObject(main_o); 1848 exe.root_module.linkSystemLibrary("a", .{ .use_pkg_config = .no, .search_strategy = .mode_first }); 1849 exe.root_module.addLibraryPath(liba.getEmittedBinDirectory()); 1850 exe.root_module.addLibraryPath(dylib.getEmittedBinDirectory()); 1851 exe.root_module.addRPath(dylib.getEmittedBinDirectory()); 1852 1853 const run = addRunArtifact(exe); 1854 run.expectStdOutEqual("Hello world"); 1855 test_step.dependOn(&run.step); 1856 1857 const check = exe.checkObject(); 1858 check.checkInHeaders(); 1859 check.checkExact("cmd LOAD_DYLIB"); 1860 check.checkContains("liba.dylib"); 1861 test_step.dependOn(&check.step); 1862 } 1863 1864 { 1865 const exe = addExecutable(b, opts, .{ .name = "main" }); 1866 exe.addObject(main_o); 1867 exe.root_module.linkSystemLibrary("a", .{ .use_pkg_config = .no, .search_strategy = .paths_first }); 1868 exe.root_module.addLibraryPath(liba.getEmittedBinDirectory()); 1869 exe.root_module.addLibraryPath(dylib.getEmittedBinDirectory()); 1870 exe.root_module.addRPath(dylib.getEmittedBinDirectory()); 1871 1872 const run = addRunArtifact(exe); 1873 run.expectStdOutEqual("Hello world"); 1874 test_step.dependOn(&run.step); 1875 1876 const check = exe.checkObject(); 1877 check.checkInHeaders(); 1878 check.checkExact("cmd LOAD_DYLIB"); 1879 check.checkNotPresent("liba.dylib"); 1880 test_step.dependOn(&check.step); 1881 } 1882 1883 return test_step; 1884 } 1885 1886 fn testSectionBoundarySymbols(b: *Build, opts: Options) *Step { 1887 const test_step = addTestStep(b, "section-boundary-symbols", opts); 1888 1889 const obj1 = addObject(b, opts, .{ 1890 .name = "obj1", 1891 .cpp_source_bytes = 1892 \\constexpr const char* MESSAGE __attribute__((used, section("__DATA_CONST,__message_ptr"))) = "codebase"; 1893 , 1894 }); 1895 1896 const main_o = addObject(b, opts, .{ 1897 .name = "main", 1898 .zig_source_bytes = 1899 \\const std = @import("std"); 1900 \\extern fn interop() ?[*:0]const u8; 1901 \\pub fn main() !void { 1902 \\ std.debug.print("All your {s} are belong to us.\n", .{ 1903 \\ if (interop()) |ptr| std.mem.span(ptr) else "(null)", 1904 \\ }); 1905 \\} 1906 , 1907 }); 1908 1909 { 1910 const obj2 = addObject(b, opts, .{ 1911 .name = "obj2", 1912 .cpp_source_bytes = 1913 \\extern const char* message_pointer __asm("section$start$__DATA_CONST$__message_ptr"); 1914 \\extern "C" const char* interop() { 1915 \\ return message_pointer; 1916 \\} 1917 , 1918 }); 1919 1920 const exe = addExecutable(b, opts, .{ .name = "test" }); 1921 exe.addObject(obj1); 1922 exe.addObject(obj2); 1923 exe.addObject(main_o); 1924 1925 const run = b.addRunArtifact(exe); 1926 run.skip_foreign_checks = true; 1927 run.expectStdErrEqual("All your codebase are belong to us.\n"); 1928 test_step.dependOn(&run.step); 1929 1930 const check = exe.checkObject(); 1931 check.checkInSymtab(); 1932 check.checkNotPresent("external section$start$__DATA_CONST$__message_ptr"); 1933 test_step.dependOn(&check.step); 1934 } 1935 1936 { 1937 const obj3 = addObject(b, opts, .{ 1938 .name = "obj3", 1939 .cpp_source_bytes = 1940 \\extern const char* message_pointer __asm("section$start$__DATA_CONST$__not_present"); 1941 \\extern "C" const char* interop() { 1942 \\ return message_pointer; 1943 \\} 1944 , 1945 }); 1946 1947 const exe = addExecutable(b, opts, .{ .name = "test" }); 1948 exe.addObject(obj1); 1949 exe.addObject(obj3); 1950 exe.addObject(main_o); 1951 1952 const run = b.addRunArtifact(exe); 1953 run.skip_foreign_checks = true; 1954 run.expectStdErrEqual("All your (null) are belong to us.\n"); 1955 test_step.dependOn(&run.step); 1956 1957 const check = exe.checkObject(); 1958 check.checkInSymtab(); 1959 check.checkNotPresent("external section$start$__DATA_CONST$__not_present"); 1960 test_step.dependOn(&check.step); 1961 } 1962 1963 return test_step; 1964 } 1965 1966 fn testSectionBoundarySymbols2(b: *Build, opts: Options) *Step { 1967 const test_step = addTestStep(b, "section-boundary-symbols-2", opts); 1968 1969 const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = 1970 \\#include <stdio.h> 1971 \\struct pair { int a; int b; }; 1972 \\struct pair first __attribute__((section("__DATA,__pairs"))) = { 1, 2 }; 1973 \\struct pair second __attribute__((section("__DATA,__pairs"))) = { 3, 4 }; 1974 \\extern struct pair pairs_start __asm("section$start$__DATA$__pairs"); 1975 \\extern struct pair pairs_end __asm("section$end$__DATA$__pairs"); 1976 \\int main() { 1977 \\ printf("%d,%d\n", first.a, first.b); 1978 \\ printf("%d,%d\n", second.a, second.b); 1979 \\ struct pair* p; 1980 \\ for (p = &pairs_start; p < &pairs_end; p++) { 1981 \\ p->a = 0; 1982 \\ } 1983 \\ printf("%d,%d\n", first.a, first.b); 1984 \\ printf("%d,%d\n", second.a, second.b); 1985 \\ return 0; 1986 \\} 1987 }); 1988 1989 const run = b.addRunArtifact(exe); 1990 run.skip_foreign_checks = true; 1991 run.expectStdOutEqual( 1992 \\1,2 1993 \\3,4 1994 \\0,2 1995 \\0,4 1996 \\ 1997 ); 1998 test_step.dependOn(&run.step); 1999 2000 return test_step; 2001 } 2002 2003 fn testSegmentBoundarySymbols(b: *Build, opts: Options) *Step { 2004 const test_step = addTestStep(b, "segment-boundary-symbols", opts); 2005 2006 const obj1 = addObject(b, opts, .{ .name = "a", .cpp_source_bytes = 2007 \\constexpr const char* MESSAGE __attribute__((used, section("__DATA_CONST_1,__message_ptr"))) = "codebase"; 2008 }); 2009 2010 const main_o = addObject(b, opts, .{ .name = "main", .c_source_bytes = 2011 \\#include <stdio.h> 2012 \\const char* interop(); 2013 \\int main() { 2014 \\ printf("All your %s are belong to us.\n", interop()); 2015 \\ return 0; 2016 \\} 2017 }); 2018 2019 { 2020 const obj2 = addObject(b, opts, .{ .name = "b", .cpp_source_bytes = 2021 \\extern const char* message_pointer __asm("segment$start$__DATA_CONST_1"); 2022 \\extern "C" const char* interop() { 2023 \\ return message_pointer; 2024 \\} 2025 }); 2026 2027 const exe = addExecutable(b, opts, .{ .name = "main" }); 2028 exe.addObject(obj1); 2029 exe.addObject(obj2); 2030 exe.addObject(main_o); 2031 2032 const run = addRunArtifact(exe); 2033 run.expectStdOutEqual("All your codebase are belong to us.\n"); 2034 test_step.dependOn(&run.step); 2035 2036 const check = exe.checkObject(); 2037 check.checkInSymtab(); 2038 check.checkNotPresent("external segment$start$__DATA_CONST_1"); 2039 test_step.dependOn(&check.step); 2040 } 2041 2042 { 2043 const obj2 = addObject(b, opts, .{ .name = "c", .cpp_source_bytes = 2044 \\extern const char* message_pointer __asm("segment$start$__DATA_1"); 2045 \\extern "C" const char* interop() { 2046 \\ return message_pointer; 2047 \\} 2048 }); 2049 2050 const exe = addExecutable(b, opts, .{ .name = "main2" }); 2051 exe.addObject(obj1); 2052 exe.addObject(obj2); 2053 exe.addObject(main_o); 2054 2055 const check = exe.checkObject(); 2056 check.checkInHeaders(); 2057 check.checkExact("cmd SEGMENT_64"); 2058 check.checkExact("segname __DATA_1"); 2059 check.checkExtract("vmsize {vmsize}"); 2060 check.checkExtract("filesz {filesz}"); 2061 check.checkComputeCompare("vmsize", .{ .op = .eq, .value = .{ .literal = 0 } }); 2062 check.checkComputeCompare("filesz", .{ .op = .eq, .value = .{ .literal = 0 } }); 2063 check.checkInSymtab(); 2064 check.checkNotPresent("external segment$start$__DATA_1"); 2065 test_step.dependOn(&check.step); 2066 } 2067 2068 return test_step; 2069 } 2070 2071 fn testSymbolStabs(b: *Build, opts: Options) *Step { 2072 const test_step = addTestStep(b, "symbol-stabs", opts); 2073 2074 const a_o = addObject(b, opts, .{ .name = "a", .c_source_bytes = 2075 \\int foo = 42; 2076 \\int getFoo() { 2077 \\ return foo; 2078 \\} 2079 }); 2080 2081 const b_o = addObject(b, opts, .{ .name = "b", .c_source_bytes = 2082 \\int bar = 24; 2083 \\int getBar() { 2084 \\ return bar; 2085 \\} 2086 }); 2087 2088 const main_o = addObject(b, opts, .{ .name = "main", .c_source_bytes = 2089 \\#include <stdio.h> 2090 \\extern int getFoo(); 2091 \\extern int getBar(); 2092 \\int main() { 2093 \\ printf("foo=%d,bar=%d", getFoo(), getBar()); 2094 \\ return 0; 2095 \\} 2096 }); 2097 2098 const exe = addExecutable(b, opts, .{ .name = "main" }); 2099 exe.addObject(a_o); 2100 exe.addObject(b_o); 2101 exe.addObject(main_o); 2102 2103 const run = addRunArtifact(exe); 2104 run.expectStdOutEqual("foo=42,bar=24"); 2105 test_step.dependOn(&run.step); 2106 2107 const check = exe.checkObject(); 2108 check.checkInSymtab(); 2109 check.checkContains("a.o"); // TODO we really should do a fuzzy search like OSO <ignore>/a.o 2110 check.checkInSymtab(); 2111 check.checkContains("b.o"); 2112 check.checkInSymtab(); 2113 check.checkContains("main.o"); 2114 test_step.dependOn(&check.step); 2115 2116 return test_step; 2117 } 2118 2119 fn testStackSize(b: *Build, opts: Options) *Step { 2120 const test_step = addTestStep(b, "stack-size", opts); 2121 2122 const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = "int main() { return 0; }" }); 2123 exe.stack_size = 0x100000000; 2124 2125 const run = addRunArtifact(exe); 2126 run.expectExitCode(0); 2127 test_step.dependOn(&run.step); 2128 2129 const check = exe.checkObject(); 2130 check.checkInHeaders(); 2131 check.checkExact("cmd MAIN"); 2132 check.checkExact("stacksize 100000000"); 2133 test_step.dependOn(&check.step); 2134 2135 return test_step; 2136 } 2137 2138 fn testTbdv3(b: *Build, opts: Options) *Step { 2139 const test_step = addTestStep(b, "tbdv3", opts); 2140 2141 const dylib = addSharedLibrary(b, opts, .{ .name = "a", .c_source_bytes = "int getFoo() { return 42; }" }); 2142 2143 const tbd = tbd: { 2144 const wf = WriteFile.create(b); 2145 break :tbd wf.add("liba.tbd", 2146 \\--- !tapi-tbd-v3 2147 \\archs: [ arm64, x86_64 ] 2148 \\uuids: [ 'arm64: DEADBEEF', 'x86_64: BEEFDEAD' ] 2149 \\platform: macos 2150 \\install-name: @rpath/liba.dylib 2151 \\current-version: 0 2152 \\exports: 2153 \\ - archs: [ arm64, x86_64 ] 2154 \\ symbols: [ _getFoo ] 2155 ); 2156 }; 2157 2158 const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = 2159 \\#include <stdio.h> 2160 \\int getFoo(); 2161 \\int main() { 2162 \\ return getFoo() - 42; 2163 \\} 2164 }); 2165 exe.root_module.linkSystemLibrary("a", .{}); 2166 exe.root_module.addLibraryPath(tbd.dirname()); 2167 exe.root_module.addRPath(dylib.getEmittedBinDirectory()); 2168 2169 const run = addRunArtifact(exe); 2170 run.expectExitCode(0); 2171 test_step.dependOn(&run.step); 2172 2173 return test_step; 2174 } 2175 2176 fn testTentative(b: *Build, opts: Options) *Step { 2177 const test_step = addTestStep(b, "tentative", opts); 2178 2179 const exe = addExecutable(b, opts, .{ .name = "main" }); 2180 addCSourceBytes(exe, 2181 \\int foo; 2182 \\int bar; 2183 \\int baz = 42; 2184 , &.{"-fcommon"}); 2185 addCSourceBytes(exe, 2186 \\#include<stdio.h> 2187 \\int foo; 2188 \\int bar = 5; 2189 \\int baz; 2190 \\int main() { 2191 \\ printf("%d %d %d\n", foo, bar, baz); 2192 \\} 2193 , &.{"-fcommon"}); 2194 2195 const run = addRunArtifact(exe); 2196 run.expectStdOutEqual("0 5 42\n"); 2197 test_step.dependOn(&run.step); 2198 2199 return test_step; 2200 } 2201 2202 fn testThunks(b: *Build, opts: Options) *Step { 2203 const test_step = addTestStep(b, "thunks", opts); 2204 2205 const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = 2206 \\#include <stdio.h> 2207 \\__attribute__((aligned(0x8000000))) int bar() { 2208 \\ return 42; 2209 \\} 2210 \\int foobar(); 2211 \\int foo() { 2212 \\ return bar() - foobar(); 2213 \\} 2214 \\__attribute__((aligned(0x8000000))) int foobar() { 2215 \\ return 42; 2216 \\} 2217 \\int main() { 2218 \\ printf("bar=%d, foo=%d, foobar=%d", bar(), foo(), foobar()); 2219 \\ return foo(); 2220 \\} 2221 }); 2222 2223 const run = addRunArtifact(exe); 2224 run.expectStdOutEqual("bar=42, foo=0, foobar=42"); 2225 run.expectExitCode(0); 2226 test_step.dependOn(&run.step); 2227 2228 return test_step; 2229 } 2230 2231 fn testTls(b: *Build, opts: Options) *Step { 2232 const test_step = addTestStep(b, "tls", opts); 2233 2234 const dylib = addSharedLibrary(b, opts, .{ .name = "a", .c_source_bytes = 2235 \\_Thread_local int a; 2236 \\int getA() { 2237 \\ return a; 2238 \\} 2239 }); 2240 2241 const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = 2242 \\#include<stdio.h> 2243 \\extern _Thread_local int a; 2244 \\extern int getA(); 2245 \\int getA2() { 2246 \\ return a; 2247 \\} 2248 \\int main() { 2249 \\ a = 2; 2250 \\ printf("%d %d %d", a, getA(), getA2()); 2251 \\ return 0; 2252 \\} 2253 }); 2254 exe.root_module.linkSystemLibrary("a", .{}); 2255 exe.root_module.addLibraryPath(dylib.getEmittedBinDirectory()); 2256 exe.root_module.addRPath(dylib.getEmittedBinDirectory()); 2257 2258 const run = addRunArtifact(exe); 2259 run.expectStdOutEqual("2 2 2"); 2260 test_step.dependOn(&run.step); 2261 2262 return test_step; 2263 } 2264 2265 // https://github.com/ziglang/zig/issues/19221 2266 fn testTlsPointers(b: *Build, opts: Options) *Step { 2267 const test_step = addTestStep(b, "tls-pointers", opts); 2268 2269 const foo_h = foo_h: { 2270 const wf = WriteFile.create(b); 2271 break :foo_h wf.add("foo.h", 2272 \\template<typename just4fun> 2273 \\struct Foo { 2274 \\ 2275 \\public: 2276 \\ static int getVar() { 2277 \\ static int thread_local var = 0; 2278 \\ ++var; 2279 \\ return var; 2280 \\} 2281 \\}; 2282 ); 2283 }; 2284 2285 const bar_o = addObject(b, opts, .{ .name = "bar", .cpp_source_bytes = 2286 \\#include "foo.h" 2287 \\int bar() { 2288 \\ int v1 = Foo<int>::getVar(); 2289 \\ return v1; 2290 \\} 2291 }); 2292 bar_o.root_module.addIncludePath(foo_h.dirname()); 2293 bar_o.linkLibCpp(); 2294 2295 const baz_o = addObject(b, opts, .{ .name = "baz", .cpp_source_bytes = 2296 \\#include "foo.h" 2297 \\int baz() { 2298 \\ int v1 = Foo<unsigned>::getVar(); 2299 \\ return v1; 2300 \\} 2301 }); 2302 baz_o.root_module.addIncludePath(foo_h.dirname()); 2303 baz_o.linkLibCpp(); 2304 2305 const main_o = addObject(b, opts, .{ .name = "main", .cpp_source_bytes = 2306 \\extern int bar(); 2307 \\extern int baz(); 2308 \\int main() { 2309 \\ int v1 = bar(); 2310 \\ int v2 = baz(); 2311 \\ return v1 != v2; 2312 \\} 2313 }); 2314 main_o.root_module.addIncludePath(foo_h.dirname()); 2315 main_o.linkLibCpp(); 2316 2317 const exe = addExecutable(b, opts, .{ .name = "main" }); 2318 exe.addObject(bar_o); 2319 exe.addObject(baz_o); 2320 exe.addObject(main_o); 2321 exe.linkLibCpp(); 2322 2323 const run = addRunArtifact(exe); 2324 run.expectExitCode(0); 2325 test_step.dependOn(&run.step); 2326 2327 return test_step; 2328 } 2329 2330 fn testTlsLargeTbss(b: *Build, opts: Options) *Step { 2331 const test_step = addTestStep(b, "tls-large-tbss", opts); 2332 2333 const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = 2334 \\#include <stdio.h> 2335 \\_Thread_local int x[0x8000]; 2336 \\_Thread_local int y[0x8000]; 2337 \\int main() { 2338 \\ x[0] = 3; 2339 \\ x[0x7fff] = 5; 2340 \\ printf("%d %d %d %d %d %d\n", x[0], x[1], x[0x7fff], y[0], y[1], y[0x7fff]); 2341 \\} 2342 }); 2343 2344 const run = addRunArtifact(exe); 2345 run.expectStdOutEqual("3 0 5 0 0 0\n"); 2346 test_step.dependOn(&run.step); 2347 2348 return test_step; 2349 } 2350 2351 fn testTlsZig(b: *Build, opts: Options) *Step { 2352 const test_step = addTestStep(b, "tls-zig", opts); 2353 2354 const exe = addExecutable(b, opts, .{ .name = "main", .zig_source_bytes = 2355 \\const std = @import("std"); 2356 \\threadlocal var x: i32 = 0; 2357 \\threadlocal var y: i32 = -1; 2358 \\pub fn main() void { 2359 \\ std.io.getStdOut().writer().print("{d} {d}\n", .{x, y}) catch unreachable; 2360 \\ x -= 1; 2361 \\ y += 1; 2362 \\ std.io.getStdOut().writer().print("{d} {d}\n", .{x, y}) catch unreachable; 2363 \\} 2364 }); 2365 2366 const run = addRunArtifact(exe); 2367 run.expectStdOutEqual( 2368 \\0 -1 2369 \\-1 0 2370 \\ 2371 ); 2372 test_step.dependOn(&run.step); 2373 2374 return test_step; 2375 } 2376 2377 fn testTwoLevelNamespace(b: *Build, opts: Options) *Step { 2378 const test_step = addTestStep(b, "two-level-namespace", opts); 2379 2380 const liba = addSharedLibrary(b, opts, .{ .name = "a", .c_source_bytes = 2381 \\#include <stdio.h> 2382 \\int foo = 1; 2383 \\int* ptr_to_foo = &foo; 2384 \\int getFoo() { 2385 \\ return foo; 2386 \\} 2387 \\void printInA() { 2388 \\ printf("liba: getFoo()=%d, ptr_to_foo=%d\n", getFoo(), *ptr_to_foo); 2389 \\} 2390 }); 2391 2392 { 2393 const check = liba.checkObject(); 2394 check.checkInDyldLazyBind(); 2395 check.checkNotPresent("(flat lookup) _getFoo"); 2396 check.checkInIndirectSymtab(); 2397 check.checkNotPresent("_getFoo"); 2398 test_step.dependOn(&check.step); 2399 } 2400 2401 const libb = addSharedLibrary(b, opts, .{ .name = "b", .c_source_bytes = 2402 \\#include <stdio.h> 2403 \\int foo = 2; 2404 \\int* ptr_to_foo = &foo; 2405 \\int getFoo() { 2406 \\ return foo; 2407 \\} 2408 \\void printInB() { 2409 \\ printf("libb: getFoo()=%d, ptr_to_foo=%d\n", getFoo(), *ptr_to_foo); 2410 \\} 2411 }); 2412 2413 { 2414 const check = libb.checkObject(); 2415 check.checkInDyldLazyBind(); 2416 check.checkNotPresent("(flat lookup) _getFoo"); 2417 check.checkInIndirectSymtab(); 2418 check.checkNotPresent("_getFoo"); 2419 test_step.dependOn(&check.step); 2420 } 2421 2422 const main_o = addObject(b, opts, .{ .name = "main", .c_source_bytes = 2423 \\#include <stdio.h> 2424 \\int getFoo(); 2425 \\extern int* ptr_to_foo; 2426 \\void printInA(); 2427 \\void printInB(); 2428 \\int main() { 2429 \\ printf("main: getFoo()=%d, ptr_to_foo=%d\n", getFoo(), *ptr_to_foo); 2430 \\ printInA(); 2431 \\ printInB(); 2432 \\ return 0; 2433 \\} 2434 }); 2435 2436 { 2437 const exe = addExecutable(b, opts, .{ .name = "main1" }); 2438 exe.addObject(main_o); 2439 exe.root_module.linkSystemLibrary("a", .{}); 2440 exe.root_module.linkSystemLibrary("b", .{}); 2441 exe.root_module.addLibraryPath(liba.getEmittedBinDirectory()); 2442 exe.root_module.addLibraryPath(libb.getEmittedBinDirectory()); 2443 exe.root_module.addRPath(liba.getEmittedBinDirectory()); 2444 exe.root_module.addRPath(libb.getEmittedBinDirectory()); 2445 2446 const check = exe.checkObject(); 2447 check.checkInSymtab(); 2448 check.checkExact("(undefined) external _getFoo (from liba)"); 2449 check.checkInSymtab(); 2450 check.checkExact("(undefined) external _printInA (from liba)"); 2451 check.checkInSymtab(); 2452 check.checkExact("(undefined) external _printInB (from libb)"); 2453 test_step.dependOn(&check.step); 2454 2455 const run = addRunArtifact(exe); 2456 run.expectStdOutEqual( 2457 \\main: getFoo()=1, ptr_to_foo=1 2458 \\liba: getFoo()=1, ptr_to_foo=1 2459 \\libb: getFoo()=2, ptr_to_foo=2 2460 \\ 2461 ); 2462 test_step.dependOn(&run.step); 2463 } 2464 2465 { 2466 const exe = addExecutable(b, opts, .{ .name = "main2" }); 2467 exe.addObject(main_o); 2468 exe.root_module.linkSystemLibrary("b", .{}); 2469 exe.root_module.linkSystemLibrary("a", .{}); 2470 exe.root_module.addLibraryPath(liba.getEmittedBinDirectory()); 2471 exe.root_module.addLibraryPath(libb.getEmittedBinDirectory()); 2472 exe.root_module.addRPath(liba.getEmittedBinDirectory()); 2473 exe.root_module.addRPath(libb.getEmittedBinDirectory()); 2474 2475 const check = exe.checkObject(); 2476 check.checkInSymtab(); 2477 check.checkExact("(undefined) external _getFoo (from libb)"); 2478 check.checkInSymtab(); 2479 check.checkExact("(undefined) external _printInA (from liba)"); 2480 check.checkInSymtab(); 2481 check.checkExact("(undefined) external _printInB (from libb)"); 2482 test_step.dependOn(&check.step); 2483 2484 const run = addRunArtifact(exe); 2485 run.expectStdOutEqual( 2486 \\main: getFoo()=2, ptr_to_foo=2 2487 \\liba: getFoo()=1, ptr_to_foo=1 2488 \\libb: getFoo()=2, ptr_to_foo=2 2489 \\ 2490 ); 2491 test_step.dependOn(&run.step); 2492 } 2493 2494 return test_step; 2495 } 2496 2497 fn testUndefinedFlag(b: *Build, opts: Options) *Step { 2498 const test_step = addTestStep(b, "undefined-flag", opts); 2499 2500 const obj = addObject(b, opts, .{ .name = "a", .c_source_bytes = "int foo = 42;" }); 2501 2502 const lib = addStaticLibrary(b, opts, .{ .name = "a" }); 2503 lib.addObject(obj); 2504 2505 const main_o = addObject(b, opts, .{ .name = "main", .c_source_bytes = "int main() { return 0; }" }); 2506 2507 { 2508 const exe = addExecutable(b, opts, .{ .name = "main1" }); 2509 exe.addObject(main_o); 2510 exe.linkLibrary(lib); 2511 exe.forceUndefinedSymbol("_foo"); 2512 2513 const run = addRunArtifact(exe); 2514 run.expectExitCode(0); 2515 test_step.dependOn(&run.step); 2516 2517 const check = exe.checkObject(); 2518 check.checkInSymtab(); 2519 check.checkContains("_foo"); 2520 test_step.dependOn(&check.step); 2521 } 2522 2523 { 2524 const exe = addExecutable(b, opts, .{ .name = "main2" }); 2525 exe.addObject(main_o); 2526 exe.linkLibrary(lib); 2527 exe.forceUndefinedSymbol("_foo"); 2528 exe.link_gc_sections = true; 2529 2530 const run = addRunArtifact(exe); 2531 run.expectExitCode(0); 2532 test_step.dependOn(&run.step); 2533 2534 const check = exe.checkObject(); 2535 check.checkInSymtab(); 2536 check.checkContains("_foo"); 2537 test_step.dependOn(&check.step); 2538 } 2539 2540 { 2541 const exe = addExecutable(b, opts, .{ .name = "main3" }); 2542 exe.addObject(main_o); 2543 exe.addObject(obj); 2544 2545 const run = addRunArtifact(exe); 2546 run.expectExitCode(0); 2547 test_step.dependOn(&run.step); 2548 2549 const check = exe.checkObject(); 2550 check.checkInSymtab(); 2551 check.checkContains("_foo"); 2552 test_step.dependOn(&check.step); 2553 } 2554 2555 { 2556 const exe = addExecutable(b, opts, .{ .name = "main4" }); 2557 exe.addObject(main_o); 2558 exe.addObject(obj); 2559 exe.link_gc_sections = true; 2560 2561 const run = addRunArtifact(exe); 2562 run.expectExitCode(0); 2563 test_step.dependOn(&run.step); 2564 2565 const check = exe.checkObject(); 2566 check.checkInSymtab(); 2567 check.checkNotPresent("_foo"); 2568 test_step.dependOn(&check.step); 2569 } 2570 2571 return test_step; 2572 } 2573 2574 fn testUnresolvedError(b: *Build, opts: Options) *Step { 2575 const test_step = addTestStep(b, "unresolved-error", opts); 2576 2577 const obj = addObject(b, opts, .{ .name = "a", .zig_source_bytes = 2578 \\extern fn foo() i32; 2579 \\export fn bar() i32 { return foo() + 1; } 2580 }); 2581 2582 const exe = addExecutable(b, opts, .{ .name = "main", .zig_source_bytes = 2583 \\const std = @import("std"); 2584 \\extern fn foo() i32; 2585 \\extern fn bar() i32; 2586 \\pub fn main() void { 2587 \\ std.debug.print("foo() + bar() = {d}", .{foo() + bar()}); 2588 \\} 2589 }); 2590 exe.addObject(obj); 2591 2592 // TODO order should match across backends if possible 2593 if (opts.use_llvm) { 2594 expectLinkErrors(exe, test_step, .{ .exact = &.{ 2595 "error: undefined symbol: _foo", 2596 "note: referenced by /?/a.o:_bar", 2597 "note: referenced by /?/main.o:_main.main", 2598 } }); 2599 } else { 2600 expectLinkErrors(exe, test_step, .{ .exact = &.{ 2601 "error: undefined symbol: _foo", 2602 "note: referenced by /?/main.o:_main.main", 2603 "note: referenced by /?/a.o:__TEXT$__text_zig", 2604 } }); 2605 } 2606 2607 return test_step; 2608 } 2609 2610 fn testUnwindInfo(b: *Build, opts: Options) *Step { 2611 const test_step = addTestStep(b, "unwind-info", opts); 2612 2613 const all_h = all_h: { 2614 const wf = WriteFile.create(b); 2615 break :all_h wf.add("all.h", 2616 \\#ifndef ALL 2617 \\#define ALL 2618 \\ 2619 \\#include <cstddef> 2620 \\#include <string> 2621 \\#include <stdexcept> 2622 \\ 2623 \\struct SimpleString { 2624 \\ SimpleString(size_t max_size); 2625 \\ ~SimpleString(); 2626 \\ 2627 \\ void print(const char* tag) const; 2628 \\ bool append_line(const char* x); 2629 \\ 2630 \\private: 2631 \\ size_t max_size; 2632 \\ char* buffer; 2633 \\ size_t length; 2634 \\}; 2635 \\ 2636 \\struct SimpleStringOwner { 2637 \\ SimpleStringOwner(const char* x); 2638 \\ ~SimpleStringOwner(); 2639 \\ 2640 \\private: 2641 \\ SimpleString string; 2642 \\}; 2643 \\ 2644 \\class Error: public std::exception { 2645 \\public: 2646 \\ explicit Error(const char* msg) : msg{ msg } {} 2647 \\ virtual ~Error() noexcept {} 2648 \\ virtual const char* what() const noexcept { 2649 \\ return msg.c_str(); 2650 \\ } 2651 \\ 2652 \\protected: 2653 \\ std::string msg; 2654 \\}; 2655 \\ 2656 \\#endif 2657 ); 2658 }; 2659 2660 const main_o = addObject(b, opts, .{ .name = "main", .cpp_source_bytes = 2661 \\#include "all.h" 2662 \\#include <cstdio> 2663 \\ 2664 \\void fn_c() { 2665 \\ SimpleStringOwner c{ "cccccccccc" }; 2666 \\} 2667 \\ 2668 \\void fn_b() { 2669 \\ SimpleStringOwner b{ "b" }; 2670 \\ fn_c(); 2671 \\} 2672 \\ 2673 \\int main() { 2674 \\ try { 2675 \\ SimpleStringOwner a{ "a" }; 2676 \\ fn_b(); 2677 \\ SimpleStringOwner d{ "d" }; 2678 \\ } catch (const Error& e) { 2679 \\ printf("Error: %s\n", e.what()); 2680 \\ } catch(const std::exception& e) { 2681 \\ printf("Exception: %s\n", e.what()); 2682 \\ } 2683 \\ return 0; 2684 \\} 2685 }); 2686 main_o.root_module.addIncludePath(all_h.dirname()); 2687 main_o.linkLibCpp(); 2688 2689 const simple_string_o = addObject(b, opts, .{ .name = "simple_string", .cpp_source_bytes = 2690 \\#include "all.h" 2691 \\#include <cstdio> 2692 \\#include <cstring> 2693 \\ 2694 \\SimpleString::SimpleString(size_t max_size) 2695 \\: max_size{ max_size }, length{} { 2696 \\ if (max_size == 0) { 2697 \\ throw Error{ "Max size must be at least 1." }; 2698 \\ } 2699 \\ buffer = new char[max_size]; 2700 \\ buffer[0] = 0; 2701 \\} 2702 \\ 2703 \\SimpleString::~SimpleString() { 2704 \\ delete[] buffer; 2705 \\} 2706 \\ 2707 \\void SimpleString::print(const char* tag) const { 2708 \\ printf("%s: %s", tag, buffer); 2709 \\} 2710 \\ 2711 \\bool SimpleString::append_line(const char* x) { 2712 \\ const auto x_len = strlen(x); 2713 \\ if (x_len + length + 2 > max_size) return false; 2714 \\ std::strncpy(buffer + length, x, max_size - length); 2715 \\ length += x_len; 2716 \\ buffer[length++] = '\n'; 2717 \\ buffer[length] = 0; 2718 \\ return true; 2719 \\} 2720 }); 2721 simple_string_o.root_module.addIncludePath(all_h.dirname()); 2722 simple_string_o.linkLibCpp(); 2723 2724 const simple_string_owner_o = addObject(b, opts, .{ .name = "simple_string_owner", .cpp_source_bytes = 2725 \\#include "all.h" 2726 \\ 2727 \\SimpleStringOwner::SimpleStringOwner(const char* x) : string{ 10 } { 2728 \\ if (!string.append_line(x)) { 2729 \\ throw Error{ "Not enough memory!" }; 2730 \\ } 2731 \\ string.print("Constructed"); 2732 \\} 2733 \\ 2734 \\SimpleStringOwner::~SimpleStringOwner() { 2735 \\ string.print("About to destroy"); 2736 \\} 2737 }); 2738 simple_string_owner_o.root_module.addIncludePath(all_h.dirname()); 2739 simple_string_owner_o.linkLibCpp(); 2740 2741 const exp_stdout = 2742 \\Constructed: a 2743 \\Constructed: b 2744 \\About to destroy: b 2745 \\About to destroy: a 2746 \\Error: Not enough memory! 2747 \\ 2748 ; 2749 2750 const exe = addExecutable(b, opts, .{ .name = "main" }); 2751 exe.addObject(main_o); 2752 exe.addObject(simple_string_o); 2753 exe.addObject(simple_string_owner_o); 2754 exe.linkLibCpp(); 2755 2756 const run = addRunArtifact(exe); 2757 run.expectStdOutEqual(exp_stdout); 2758 test_step.dependOn(&run.step); 2759 2760 const check = exe.checkObject(); 2761 check.checkInSymtab(); 2762 check.checkContains("(was private external) ___gxx_personality_v0"); 2763 test_step.dependOn(&check.step); 2764 2765 return test_step; 2766 } 2767 2768 fn testUnwindInfoNoSubsectionsArm64(b: *Build, opts: Options) *Step { 2769 const test_step = addTestStep(b, "unwind-info-no-subsections-arm64", opts); 2770 2771 const a_o = addObject(b, opts, .{ .name = "a", .asm_source_bytes = 2772 \\.globl _foo 2773 \\.align 4 2774 \\_foo: 2775 \\ .cfi_startproc 2776 \\ stp x29, x30, [sp, #-32]! 2777 \\ .cfi_def_cfa_offset 32 2778 \\ .cfi_offset w30, -24 2779 \\ .cfi_offset w29, -32 2780 \\ mov x29, sp 2781 \\ .cfi_def_cfa w29, 32 2782 \\ bl _bar 2783 \\ ldp x29, x30, [sp], #32 2784 \\ .cfi_restore w29 2785 \\ .cfi_restore w30 2786 \\ .cfi_def_cfa_offset 0 2787 \\ ret 2788 \\ .cfi_endproc 2789 \\ 2790 \\.globl _bar 2791 \\.align 4 2792 \\_bar: 2793 \\ .cfi_startproc 2794 \\ sub sp, sp, #32 2795 \\ .cfi_def_cfa_offset -32 2796 \\ stp x29, x30, [sp, #16] 2797 \\ .cfi_offset w30, -24 2798 \\ .cfi_offset w29, -32 2799 \\ mov x29, sp 2800 \\ .cfi_def_cfa w29, 32 2801 \\ mov w0, #4 2802 \\ ldp x29, x30, [sp, #16] 2803 \\ .cfi_restore w29 2804 \\ .cfi_restore w30 2805 \\ add sp, sp, #32 2806 \\ .cfi_def_cfa_offset 0 2807 \\ ret 2808 \\ .cfi_endproc 2809 }); 2810 2811 const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = 2812 \\#include <stdio.h> 2813 \\int foo(); 2814 \\int main() { 2815 \\ printf("%d\n", foo()); 2816 \\ return 0; 2817 \\} 2818 }); 2819 exe.addObject(a_o); 2820 2821 const run = addRunArtifact(exe); 2822 run.expectStdOutEqual("4\n"); 2823 test_step.dependOn(&run.step); 2824 2825 return test_step; 2826 } 2827 2828 fn testUnwindInfoNoSubsectionsX64(b: *Build, opts: Options) *Step { 2829 const test_step = addTestStep(b, "unwind-info-no-subsections-x64", opts); 2830 2831 const a_o = addObject(b, opts, .{ .name = "a", .asm_source_bytes = 2832 \\.globl _foo 2833 \\_foo: 2834 \\ .cfi_startproc 2835 \\ push %rbp 2836 \\ .cfi_def_cfa_offset 8 2837 \\ .cfi_offset %rbp, -8 2838 \\ mov %rsp, %rbp 2839 \\ .cfi_def_cfa_register %rbp 2840 \\ call _bar 2841 \\ pop %rbp 2842 \\ .cfi_restore %rbp 2843 \\ .cfi_def_cfa_offset 0 2844 \\ ret 2845 \\ .cfi_endproc 2846 \\ 2847 \\.globl _bar 2848 \\_bar: 2849 \\ .cfi_startproc 2850 \\ push %rbp 2851 \\ .cfi_def_cfa_offset 8 2852 \\ .cfi_offset %rbp, -8 2853 \\ mov %rsp, %rbp 2854 \\ .cfi_def_cfa_register %rbp 2855 \\ mov $4, %rax 2856 \\ pop %rbp 2857 \\ .cfi_restore %rbp 2858 \\ .cfi_def_cfa_offset 0 2859 \\ ret 2860 \\ .cfi_endproc 2861 }); 2862 2863 const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = 2864 \\#include <stdio.h> 2865 \\int foo(); 2866 \\int main() { 2867 \\ printf("%d\n", foo()); 2868 \\ return 0; 2869 \\} 2870 }); 2871 exe.addObject(a_o); 2872 2873 const run = addRunArtifact(exe); 2874 run.expectStdOutEqual("4\n"); 2875 test_step.dependOn(&run.step); 2876 2877 return test_step; 2878 } 2879 2880 // Adapted from https://github.com/llvm/llvm-project/blob/main/lld/test/MachO/weak-binding.s 2881 fn testWeakBind(b: *Build, opts: Options) *Step { 2882 const test_step = addTestStep(b, "weak-bind", opts); 2883 2884 const lib = addSharedLibrary(b, opts, .{ .name = "foo", .asm_source_bytes = 2885 \\.globl _weak_dysym 2886 \\.weak_definition _weak_dysym 2887 \\_weak_dysym: 2888 \\ .quad 0x1234 2889 \\ 2890 \\.globl _weak_dysym_for_gotpcrel 2891 \\.weak_definition _weak_dysym_for_gotpcrel 2892 \\_weak_dysym_for_gotpcrel: 2893 \\ .quad 0x1234 2894 \\ 2895 \\.globl _weak_dysym_fn 2896 \\.weak_definition _weak_dysym_fn 2897 \\_weak_dysym_fn: 2898 \\ ret 2899 \\ 2900 \\.section __DATA,__thread_vars,thread_local_variables 2901 \\ 2902 \\.globl _weak_dysym_tlv 2903 \\.weak_definition _weak_dysym_tlv 2904 \\_weak_dysym_tlv: 2905 \\ .quad 0x1234 2906 }); 2907 2908 { 2909 const check = lib.checkObject(); 2910 check.checkInExports(); 2911 check.checkExtract("[WEAK] {vmaddr1} _weak_dysym"); 2912 check.checkExtract("[WEAK] {vmaddr2} _weak_dysym_for_gotpcrel"); 2913 check.checkExtract("[WEAK] {vmaddr3} _weak_dysym_fn"); 2914 check.checkExtract("[THREAD_LOCAL, WEAK] {vmaddr4} _weak_dysym_tlv"); 2915 test_step.dependOn(&check.step); 2916 } 2917 2918 const exe = addExecutable(b, opts, .{ .name = "main", .asm_source_bytes = 2919 \\.globl _main, _weak_external, _weak_external_for_gotpcrel, _weak_external_fn 2920 \\.weak_definition _weak_external, _weak_external_for_gotpcrel, _weak_external_fn, _weak_internal, _weak_internal_for_gotpcrel, _weak_internal_fn 2921 \\ 2922 \\_main: 2923 \\ mov _weak_dysym_for_gotpcrel@GOTPCREL(%rip), %rax 2924 \\ mov _weak_external_for_gotpcrel@GOTPCREL(%rip), %rax 2925 \\ mov _weak_internal_for_gotpcrel@GOTPCREL(%rip), %rax 2926 \\ mov _weak_tlv@TLVP(%rip), %rax 2927 \\ mov _weak_dysym_tlv@TLVP(%rip), %rax 2928 \\ mov _weak_internal_tlv@TLVP(%rip), %rax 2929 \\ callq _weak_dysym_fn 2930 \\ callq _weak_external_fn 2931 \\ callq _weak_internal_fn 2932 \\ mov $0, %rax 2933 \\ ret 2934 \\ 2935 \\_weak_external: 2936 \\ .quad 0x1234 2937 \\ 2938 \\_weak_external_for_gotpcrel: 2939 \\ .quad 0x1234 2940 \\ 2941 \\_weak_external_fn: 2942 \\ ret 2943 \\ 2944 \\_weak_internal: 2945 \\ .quad 0x1234 2946 \\ 2947 \\_weak_internal_for_gotpcrel: 2948 \\ .quad 0x1234 2949 \\ 2950 \\_weak_internal_fn: 2951 \\ ret 2952 \\ 2953 \\.data 2954 \\ .quad _weak_dysym 2955 \\ .quad _weak_external + 2 2956 \\ .quad _weak_internal 2957 \\ 2958 \\.tbss _weak_tlv$tlv$init, 4, 2 2959 \\.tbss _weak_internal_tlv$tlv$init, 4, 2 2960 \\ 2961 \\.section __DATA,__thread_vars,thread_local_variables 2962 \\.globl _weak_tlv 2963 \\.weak_definition _weak_tlv, _weak_internal_tlv 2964 \\ 2965 \\_weak_tlv: 2966 \\ .quad __tlv_bootstrap 2967 \\ .quad 0 2968 \\ .quad _weak_tlv$tlv$init 2969 \\ 2970 \\_weak_internal_tlv: 2971 \\ .quad __tlv_bootstrap 2972 \\ .quad 0 2973 \\ .quad _weak_internal_tlv$tlv$init 2974 }); 2975 exe.linkLibrary(lib); 2976 2977 { 2978 const check = exe.checkObject(); 2979 2980 check.checkInExports(); 2981 check.checkExtract("[WEAK] {vmaddr1} _weak_external"); 2982 check.checkExtract("[WEAK] {vmaddr2} _weak_external_for_gotpcrel"); 2983 check.checkExtract("[WEAK] {vmaddr3} _weak_external_fn"); 2984 check.checkExtract("[THREAD_LOCAL, WEAK] {vmaddr4} _weak_tlv"); 2985 2986 check.checkInDyldBind(); 2987 check.checkContains("(libfoo.dylib) _weak_dysym_for_gotpcrel"); 2988 check.checkContains("(libfoo.dylib) _weak_dysym_fn"); 2989 check.checkContains("(libfoo.dylib) _weak_dysym"); 2990 check.checkContains("(libfoo.dylib) _weak_dysym_tlv"); 2991 2992 check.checkInDyldWeakBind(); 2993 check.checkContains("_weak_external_for_gotpcrel"); 2994 check.checkContains("_weak_dysym_for_gotpcrel"); 2995 check.checkContains("_weak_external_fn"); 2996 check.checkContains("_weak_dysym_fn"); 2997 check.checkContains("_weak_dysym"); 2998 check.checkContains("_weak_external"); 2999 check.checkContains("_weak_tlv"); 3000 check.checkContains("_weak_dysym_tlv"); 3001 3002 test_step.dependOn(&check.step); 3003 } 3004 3005 const run = addRunArtifact(exe); 3006 run.expectExitCode(0); 3007 test_step.dependOn(&run.step); 3008 3009 return test_step; 3010 } 3011 3012 fn testWeakFramework(b: *Build, opts: Options) *Step { 3013 const test_step = addTestStep(b, "weak-framework", opts); 3014 3015 const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = "int main() { return 0; }" }); 3016 exe.root_module.linkFramework("Cocoa", .{ .weak = true }); 3017 3018 const run = addRunArtifact(exe); 3019 run.expectExitCode(0); 3020 test_step.dependOn(&run.step); 3021 3022 const check = exe.checkObject(); 3023 check.checkInHeaders(); 3024 check.checkExact("cmd LOAD_WEAK_DYLIB"); 3025 check.checkContains("Cocoa"); 3026 test_step.dependOn(&check.step); 3027 3028 return test_step; 3029 } 3030 3031 fn testWeakLibrary(b: *Build, opts: Options) *Step { 3032 const test_step = addTestStep(b, "weak-library", opts); 3033 3034 const dylib = addSharedLibrary(b, opts, .{ .name = "a", .c_source_bytes = 3035 \\#include<stdio.h> 3036 \\int a = 42; 3037 \\const char* asStr() { 3038 \\ static char str[3]; 3039 \\ sprintf(str, "%d", 42); 3040 \\ return str; 3041 \\} 3042 }); 3043 3044 const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = 3045 \\#include<stdio.h> 3046 \\extern int a; 3047 \\extern const char* asStr(); 3048 \\int main() { 3049 \\ printf("%d %s", a, asStr()); 3050 \\ return 0; 3051 \\} 3052 }); 3053 exe.root_module.linkSystemLibrary("a", .{ .weak = true }); 3054 exe.root_module.addLibraryPath(dylib.getEmittedBinDirectory()); 3055 exe.root_module.addRPath(dylib.getEmittedBinDirectory()); 3056 3057 const check = exe.checkObject(); 3058 check.checkInHeaders(); 3059 check.checkExact("cmd LOAD_WEAK_DYLIB"); 3060 check.checkContains("liba.dylib"); 3061 check.checkInSymtab(); 3062 check.checkExact("(undefined) weakref external _a (from liba)"); 3063 check.checkInSymtab(); 3064 check.checkExact("(undefined) weakref external _asStr (from liba)"); 3065 test_step.dependOn(&check.step); 3066 3067 const run = addRunArtifact(exe); 3068 run.expectStdOutEqual("42 42"); 3069 test_step.dependOn(&run.step); 3070 3071 return test_step; 3072 } 3073 3074 fn testWeakRef(b: *Build, opts: Options) *Step { 3075 const test_step = addTestStep(b, "weak-ref", opts); 3076 3077 const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = 3078 \\#include <stdio.h> 3079 \\#include <sys/_types/_fd_def.h> 3080 \\int main(int argc, char** argv) { 3081 \\ printf("__darwin_check_fd_set_overflow: %p\n", __darwin_check_fd_set_overflow); 3082 \\} 3083 }); 3084 3085 const check = exe.checkObject(); 3086 check.checkInSymtab(); 3087 check.checkExact("(undefined) weakref external ___darwin_check_fd_set_overflow (from libSystem.B)"); 3088 test_step.dependOn(&check.step); 3089 3090 return test_step; 3091 } 3092 3093 fn addTestStep(b: *Build, comptime prefix: []const u8, opts: Options) *Step { 3094 return link.addTestStep(b, "" ++ prefix, opts); 3095 } 3096 3097 const builtin = @import("builtin"); 3098 const addAsmSourceBytes = link.addAsmSourceBytes; 3099 const addCSourceBytes = link.addCSourceBytes; 3100 const addRunArtifact = link.addRunArtifact; 3101 const addObject = link.addObject; 3102 const addExecutable = link.addExecutable; 3103 const addStaticLibrary = link.addStaticLibrary; 3104 const addSharedLibrary = link.addSharedLibrary; 3105 const expectLinkErrors = link.expectLinkErrors; 3106 const link = @import("link.zig"); 3107 const std = @import("std"); 3108 3109 const Build = std.Build; 3110 const BuildOptions = link.BuildOptions; 3111 const Compile = Step.Compile; 3112 const Options = link.Options; 3113 const Step = Build.Step; 3114 const WriteFile = Step.WriteFile;