| ... | ... | @@ -59,6 +59,7 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step { |
| 59 | 59 | // Exercise linker with LLVM backend |
| 60 | 60 | // musl tests |
| 61 | 61 | elf_step.dependOn(testAbsSymbols(b, .{ .target = musl_target })); |
| 62 | elf_step.dependOn(testComdatElimination(b, .{ .target = musl_target })); |
| 62 | 63 | elf_step.dependOn(testCommonSymbols(b, .{ .target = musl_target })); |
| 63 | 64 | elf_step.dependOn(testCommonSymbolsInArchive(b, .{ .target = musl_target })); |
| 64 | 65 | elf_step.dependOn(testCommentString(b, .{ .target = musl_target })); |
| ... | ... | @@ -368,6 +369,97 @@ fn testCanonicalPlt(b: *Build, opts: Options) *Step { |
| 368 | 369 | return test_step; |
| 369 | 370 | } |
| 370 | 371 | |
| 372 | fn testComdatElimination(b: *Build, opts: Options) *Step { |
| 373 | const test_step = addTestStep(b, "comdat-elimination", opts); |
| 374 | |
| 375 | const a_o = addObject(b, opts, .{ |
| 376 | .name = "a", |
| 377 | .cpp_source_bytes = |
| 378 | \\#include <stdio.h> |
| 379 | \\inline void foo() { |
| 380 | \\ printf("calling foo in a\n"); |
| 381 | \\} |
| 382 | \\void hello() { |
| 383 | \\ foo(); |
| 384 | \\} |
| 385 | , |
| 386 | }); |
| 387 | a_o.linkLibCpp(); |
| 388 | |
| 389 | const main_o = addObject(b, opts, .{ |
| 390 | .name = "main", |
| 391 | .cpp_source_bytes = |
| 392 | \\#include <stdio.h> |
| 393 | \\inline void foo() { |
| 394 | \\ printf("calling foo in main\n"); |
| 395 | \\} |
| 396 | \\void hello(); |
| 397 | \\int main() { |
| 398 | \\ foo(); |
| 399 | \\ hello(); |
| 400 | \\ return 0; |
| 401 | \\} |
| 402 | , |
| 403 | }); |
| 404 | main_o.linkLibCpp(); |
| 405 | |
| 406 | { |
| 407 | const exe = addExecutable(b, opts, .{ |
| 408 | .name = "main1", |
| 409 | }); |
| 410 | exe.addObject(a_o); |
| 411 | exe.addObject(main_o); |
| 412 | exe.linkLibCpp(); |
| 413 | |
| 414 | const run = addRunArtifact(exe); |
| 415 | run.expectStdOutEqual( |
| 416 | \\calling foo in a |
| 417 | \\calling foo in a |
| 418 | \\ |
| 419 | ); |
| 420 | test_step.dependOn(&run.step); |
| 421 | |
| 422 | const check = exe.checkObject(); |
| 423 | check.checkInSymtab(); |
| 424 | // This weird looking double assertion uses the fact that once we find the symbol in |
| 425 | // the symtab, we do not reset the cursor and do subsequent checks from that point onwards. |
| 426 | // If this is the case, and COMDAT elimination works correctly we should only have one instance |
| 427 | // of foo() function. |
| 428 | check.checkContains("_Z3foov"); |
| 429 | check.checkNotPresent("_Z3foov"); |
| 430 | test_step.dependOn(&check.step); |
| 431 | } |
| 432 | |
| 433 | { |
| 434 | const exe = addExecutable(b, opts, .{ |
| 435 | .name = "main2", |
| 436 | }); |
| 437 | exe.addObject(main_o); |
| 438 | exe.addObject(a_o); |
| 439 | exe.linkLibCpp(); |
| 440 | |
| 441 | const run = addRunArtifact(exe); |
| 442 | run.expectStdOutEqual( |
| 443 | \\calling foo in main |
| 444 | \\calling foo in main |
| 445 | \\ |
| 446 | ); |
| 447 | test_step.dependOn(&run.step); |
| 448 | |
| 449 | const check = exe.checkObject(); |
| 450 | check.checkInSymtab(); |
| 451 | // This weird looking double assertion uses the fact that once we find the symbol in |
| 452 | // the symtab, we do not reset the cursor and do subsequent checks from that point onwards. |
| 453 | // If this is the case, and COMDAT elimination works correctly we should only have one instance |
| 454 | // of foo() function. |
| 455 | check.checkContains("_Z3foov"); |
| 456 | check.checkNotPresent("_Z3foov"); |
| 457 | test_step.dependOn(&check.step); |
| 458 | } |
| 459 | |
| 460 | return test_step; |
| 461 | } |
| 462 | |
| 371 | 463 | fn testCommentString(b: *Build, opts: Options) *Step { |
| 372 | 464 | const test_step = addTestStep(b, "comment-string", opts); |
| 373 | 465 | |