Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to link stdc++ for example when building rust library #1206

Open
mjforan opened this issue Sep 15, 2024 · 9 comments
Open

Unable to link stdc++ for example when building rust library #1206

mjforan opened this issue Sep 15, 2024 · 9 comments

Comments

@mjforan
Copy link

mjforan commented Sep 15, 2024

Problem: cc is unable to find stdc++ when building an example for a library crate.

✅ works: binary crate, call c++ from example


lib_x/
  src/
    main.rs
  examples/
    test.cpp            #include <iostream>
    lib_x_example.rs    call function in test.cpp

✅ works: library crate, call c++ from library


lib_x/
  src/
    test.cpp            #include <iostream>
    lib.rs              call function in test.cpp
  examples/
    lib_x_example.rs    call function in lib.rs

❌ does not work: library crate, call c++ from example


lib_x/
  src/
    lib.rs
  examples/
    test.cpp            #include <iostream>
    lib_x_example.rs    call function in test.cpp

build.rs:

  println!("cargo:rerun-if-changed=examples/test.cpp");
  cc::Build::new()
  .cpp(true)
  .file("examples/test.cpp")
  .cpp_link_stdlib("stdc++")
  .compile("test_cpp");

Error output:

error: linking with `cc` failed: exit status: 1
  |
  = note: LC_ALL="C" PATH="/home/mjforan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/bin:/home/mjforan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/bin:/home/mjforan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/bin:/home/mjforan/.cargo/bin:/home/mjforan/.local/bin:/usr/local/cuda-11.6/bin:/home/mjforan/.local/bin:/usr/local/cuda-11.6/bin:/home/mjforan/.local/bin:/home/mjforan/.local/bin:/usr/local/cuda-11.6/bin:/home/mjforan/anaconda3/bin:/home/mjforan/anaconda3/condabin:/home/mjforan/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/snap/bin" VSLANG="1033" "cc" "-m64" "/tmp/rustcUr3FJl/symbols.o" "/home/mjforan/lib_x/target/release/examples/lib_x_example-06693f701c91b976.lib_x_example.a5b620fa4eee2b6-cgu.0.rcgu.o" "/home/mjforan/lib_x/target/release/examples/lib_x_example-06693f701c91b976.e6xnw6b1lbeu1tod6egd8g1j6.rcgu.o" "-Wl,--as-needed" "-L" "/home/mjforan/lib_x/target/release/deps" "-L" "/home/mjforan/lib_x/target/release/build/lib_x-e4aaea58acf14dea/out" "-L" "/home/mjforan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-Wl,-Bdynamic" "-ltest_cpp" "-Wl,-Bstatic" "/home/mjforan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd-1c4b19562077c20d.rlib" "/home/mjforan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libpanic_unwind-85a631ebc91746e0.rlib" "/home/mjforan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libobject-fdace1a0b4cda412.rlib" "/home/mjforan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libmemchr-e5c28d21823e9a85.rlib" "/home/mjforan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libaddr2line-1e0edbcd516a8cce.rlib" "/home/mjforan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libgimli-77a1dc5e8fb357d6.rlib" "/home/mjforan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_demangle-8c9d2edb6dff139f.rlib" "/home/mjforan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd_detect-ecadd85ae8bacc0c.rlib" "/home/mjforan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libhashbrown-67895a0c8dd8130b.rlib" "/home/mjforan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_std_workspace_alloc-5b4263e767961458.rlib" "/home/mjforan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libminiz_oxide-4f03d5a171522141.rlib" "/home/mjforan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libadler-9e4e8543de06315e.rlib" "/home/mjforan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libunwind-7fc51dfce9c057eb.rlib" "/home/mjforan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcfg_if-7ec98a9b1cc1792f.rlib" "/home/mjforan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/liblibc-2f9b4333f6d32438.rlib" "/home/mjforan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/liballoc-b6fe0262c36c500a.rlib" "/home/mjforan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_std_workspace_core-2a862c0b1c86f483.rlib" "/home/mjforan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcore-500f37ee5bcf0ffe.rlib" "/home/mjforan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcompiler_builtins-06dfbf1de02fde3b.rlib" "-Wl,-Bdynamic" "-lgcc_s" "-lutil" "-lrt" "-lpthread" "-lm" "-ldl" "-lc" "-Wl,--eh-frame-hdr" "-Wl,-z,noexecstack" "-L" "/home/mjforan/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-o" "/home/mjforan/lib_x/target/release/examples/lib_x_example-06693f701c91b976" "-Wl,--gc-sections" "-pie" "-Wl,-z,relro,-z,now" "-Wl,-O1" "-Wl,--strip-debug" "-nodefaultlibs"
  = note: /usr/bin/ld: /home/mjforan/lib_x/target/release/build/lib_x-e4aaea58acf14dea/out/libtest_cpp.a(b688d06bea1307b6-test.o): in function `test_cpp':
          test.cpp:(.text.test_cpp+0x19): undefined reference to `std::cout'
          /usr/bin/ld: test.cpp:(.text.test_cpp+0x21): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long)'
          /usr/bin/ld: test.cpp:(.text.test_cpp+0x47): undefined reference to `std::ostream::put(char)'
          /usr/bin/ld: test.cpp:(.text.test_cpp+0x64): undefined reference to `std::ctype<char>::_M_widen_init() const'
          /usr/bin/ld: test.cpp:(.text.test_cpp+0x89): undefined reference to `std::__throw_bad_cast()'
          /usr/bin/ld: test.cpp:(.text.test_cpp+0x55): undefined reference to `std::ostream::flush()'
          collect2: error: ld returned 1 exit status
          
  = note: some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified
  = note: use the `-l` flag to specify native libraries to link
  = note: use the `cargo:rustc-link-lib` directive to specify the native libraries to link with Cargo (see https://doc.rust-lang.org/cargo/reference/build-scripts.html#rustc-link-lib)

error: could not compile `lib_x` (example "lib_x_example") due to 1 previous error

Environment: Raspberry Pi OS (aarch64) and Ubuntu 24.04 (amd64) with fresh install of Rust: cargo 1.81.0, cc="1.1.18"

I have tried setting various options in build.rs such as manually specifying the path to /lib/aarch64-linux-gnu/libstdc++.so.6

@NobodyXu
Copy link
Collaborator

Sorry I don't understand how you are calling std::cout, can you provide the code please?

Just including the header file won't work, and linking with stdc++ also won't work.

C++ ABI is different from rust with its own name demangles so that it can support function overloading.

@mjforan
Copy link
Author

mjforan commented Sep 15, 2024

test.cpp

#include <iostream>
extern "C" void test_cpp() {
    std::cout<<"hello"<<std::endl;
}

lib_x_example.rs

#[link(name = "test_cpp")]
extern { fn test_cpp(); }

pub fn main() {
    unsafe {test_cpp();}
}

@NobodyXu
Copy link
Collaborator

Thanks.

And can you also show me the build.rs ?

Because you would need it to be put in the workspace, not in src or examples, but in the workspace .

Only when it's in there, it would be automatically picked up by cargo, and run by cargo to compile and link the c++ file.

@mjforan
Copy link
Author

mjforan commented Sep 15, 2024

Yes, build.rs is in the workspace, as well as Cargo.toml, Cargo.lock, and the target directory. I left them out of the initial issue for simplicity. The relevant section of build.rs is listed above.

@NobodyXu
Copy link
Collaborator

Thanks.

I think you would have to define

#[link(name = "test_cpp")]
pub extern { fn test_cpp(); }

in the lib.rs, when you compile and link with an external library, you usually define the API of the external library in the library itself.

@mjforan
Copy link
Author

mjforan commented Sep 15, 2024

That does not work. The example still fails to compile.

@NobodyXu
Copy link
Collaborator

Can you remove

.cpp_link_stdlib("stdc++")

I think using the default libstdc++ might work.

@mjforan
Copy link
Author

mjforan commented Sep 15, 2024

No, that value is correct for my platform. Removing it does not help.
https://docs.rs/cc/latest/cc/struct.Build.html#method.cpp_link_stdlib
https://docs.rs/cc/latest/cc/#c-support

Would you mind reproducing on your end? It seems you are just taking guesses here and I have already tried these things.

Another clue: when I wrap the c++ function in my lib.rs and call that method from my example, then I am also able to use the c++ function directly in my example.

@NobodyXu
Copy link
Collaborator

Would you mind reproducing on your end? It seems you are just taking guesses here and I have already tried these things.

Sorry I don't have access to my computer for now.

Another clue: when I wrap the c++ function in my lib.rs and call that method from my example, then I am also able to use the c++ function directly in my example.

Yes, that's pretty much how most crates use cc and external crates.

Creates bindings for it in rust library crate, then call the library crate.

I think the error you experience might be due to how rust links crates.

AFAIK, cargo does a linking per crate to produce rlib, so if the external library function isn't used in the library crate, it might strip out the unused linkage to stdc++.

Since rlib isn't stablised and mostly internal to cargo, there isn't much documentation on it.

For that particular behavior, it might be faster to ask on rust's official zulip in t-cargo channel

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants