Skip to content

Whole archive modifier for native libraries is not propagated to final output. #88085

Closed

Description

With the additional of RFC 2951 (tracking: #81490, implementation: #83507), linking modifiers such as +whole-archive are now possible to use for native libraries. However, +whole-archive is not propagated to the final output of the build. I've minimally reproduced this issue as best I could here. It can probably be minimized more with raw calls to rustc, but I'm not familiar enough to do so right now.

Essentially, I have a static library which provides constructor and destructor functions which must be included in the final output.

I tried this code:

foo.c

#include <stdio.h>
void __attribute__((constructor)) construct();
void __attribute__((destructor)) destruct();
void construct()
{
    printf("Constructor.\n");
}
void destruct()
{
    printf("Destructor.\n");
}

build.rs

fn main() {
    cc::Build::new()
        .file("src/foo.c")
        .cargo_metadata(false)
        .static_flag(true)
        .compile("foo");
    println!(
        "cargo:rustc-link-search=native={}",
        std::env::var("OUT_DIR").unwrap()
    );
    println!("cargo:rustc-link-lib=static:+whole-archive=foo");
}

lib.rs

pub fn it_linked() {}

main.rs

fn main() {
    indirect::it_linked();
    println!("Hello, indirect!");
}

I expected to see this happen:

$ RUSTFLAGS="-Z unstable-options" cargo run --bin indirect
   Compiling cc v1.0.69
   Compiling direct v0.1.0 (/home/gcoakes/Documents/Source/minimal-whole-archive/indirect)
    Finished dev [unoptimized + debuginfo] target(s) in 1.73s
     Running `target/debug/indirect`
Constructor.
Hello, indirect!
Destructor.
$ nm target/debug/indirect | grep 'construct\|destruct'
0000000000007ab5 T construct
0000000000007acc T destruct

Instead, this happened:

$ RUSTFLAGS="-Z unstable-options" cargo run --bin indirect
   Compiling indirect v0.1.0 (/home/gcoakes/Documents/Source/minimal-whole-archive/indirect)
    Finished dev [unoptimized + debuginfo] target(s) in 0.68s
     Running `target/debug/indirect`
Hello, indirect!
$ nm target/debug/indirect | grep 'construct\|destruct'

Resolution

I've done a bit of code inspection to determine where the linking issue actually is. I think it comes down to the link_upstream closure in rustc_codegen_ssa::src::back::link::add_upstream_rust_crates::add_static_crate. It should be adjusted to inspect the crates native libraries and determine if any of them have +whole-archive. If one or more do, then it should run link_whole_rlib on the crate's rlib instead of link_rlib.

Meta

rustc --version --verbose:

rustc 1.56.0-nightly (8007b506a 2021-08-14)
binary: rustc
commit-hash: 8007b506ac5da629f223b755f5a5391edd5f6d01
commit-date: 2021-08-14
host: x86_64-unknown-linux-gnu
release: 1.56.0-nightly
LLVM version: 12.0.1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Labels

    C-bugCategory: This is a bug.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions