cxx
cxx copied to clipboard
How to add lib.rs to a cxx bin crate package?
I write a simple "hello_cxx" package, it contains ["test.h", "main.rs"] and it compiles ok. but when I add an empty lib.rs to the package, compile failed and the error says: "/home/centos/rust/hello_cxx/src/main.rs:5: undefined reference to `cxxbridge1$new_abc'"
Here is my code: test.h:
#ifndef __TEST_H__
#define __TEST_H__
#include <stdio.h>
void new_abc() {
printf("Just test it");
}
#endif // __TEST_H__
path: "/home/centos/rust/hello_cxx/cpp/test.h
main.rs:
#[cxx::bridge]
mod ffi {
extern "C++" {
include!("test.h");
unsafe fn new_abc();
}
}
fn main() {
unsafe {
ffi::new_abc();
}
}
and build.rs
fn main() -> miette::Result<()> {
let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR was not set");
let manifest_path = std::path::PathBuf::from(manifest_dir);
// This assumes all your C++ bindings are in main.rs
println!("cargo:rerun-if-changed=src/main.rs");
// Define path to resolve #include relative position
let include_paths = vec![
manifest_path.join("cpp"),
];
// Bridge -- cxx
cxx_build::bridge("src/main.rs")
.flag_if_supported("-std=c++14")
.includes(&include_paths)
.compile("cxxbridge-demo");
// Add instructions to link to any C++ libraries you need.
Ok(())
}
From the output, I found that for single bin crate, the "-l static=cxxbridge-demo" options was add to bin crate correctly like this: “Running `CARGO=/home/centos/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/bin/cargo CARGO_CRATE_NAME=hello_cxx ... -l static=cxxbridge-demo ...”
But for both bin and lib crate, the "-l static=cxxbridge-demo" was add to the lib crate only like this:
"Running CARGO=/home/centos/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/bin/cargo CARGO_CRATE_NAME=hello_cxx ... -l static=cxxbridge-demo ..." "Running
CARGO=/home/centos/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/bin/cargo CARGO_BIN_NAME=hello-cxx ... ... "
My build.rs:
fn main() -> miette::Result<()> {
let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR was not set");
let manifest_path = std::path::PathBuf::from(manifest_dir);
// This assumes all your C++ bindings are in main.rs
println!("cargo:rerun-if-changed=src/main.rs");
// Define path to resolve #include relative position
let include_paths = vec![
manifest_path.join("cpp"),
];
// Bridge -- cxx
cxx_build::bridge("src/main.rs")
.flag_if_supported("-std=c++14")
.includes(&include_paths)
.compile("cxxbridge-demo");
// Add instructions to link to any C++ libraries you need.
Ok(())
}
How can I make the cxx-build add the "-l static=cxxbridge-demo" to the BIN CRATE correctly when a lib.rs exists?
and here is my full project: hello_cxx.zip
Finally I move the bridge code into the lib.rs, and change the build.rs from "cxx_build::bridge("src/main.rs")" to "cxx_build::bridge("src/lib.rs")", it works.
It should be a purposely design because there is no way to share if you write your ffi code in bin crate. It should be in lib crate. Am I right?
Add "l static=cxxbridge-demo" to lib crate is not the proper way, it still doesn't work if the cpp code in a extern cpp lib. Is there a rule says that must only one bin crate exist in the package?
see https://github.com/dtolnay/cxx/issues/1195#issuecomment-1473033203 and https://github.com/rust-lang/cargo/issues/8919#issuecomment-735909489
" This is currently expected behavior in Cargo. Cargo links the native libraries to the Rust library but then doesn't link them to the binary, assuming that the Rust library is linked to in the binary. If you add extern crate demo to your src/main.rs does it work? "
They all says "extern crate hello_cxx;". I test and found: It is not necessay. It only works If the lib crate and bin crate are not in same package.
Yes, one native library can only be added to one crate? The limitation seems come from "build.rs" only works for one crate