I have developed a library using Rust which exposes a function to be used by a C program which returns the library version based in Cargo metadata.
This is the function:
#[no_mangle]
pub extern "C" fn get_version() -> *const libc::c_char {
// Get Cargo metadata
let metadata = cargo_metadata::MetadataCommand::new()
.exec()
.expect("Failed to get Cargo metadata");
let root = metadata.root_package().unwrap();
let version = root.version.to_string();
return CString::new(version).unwrap().into_raw();
}
This is the Cargo.toml file (simplified):
[package]
name = "acme"
version = "0.1.0"
edition = "2021"
[dependencies]
...
libc = "0.2"
cargo_metadata = "0.18.1"
[lib]
crate-type=["staticlib"]
I generate the library using cargo build --release
, which produces a binary file named libacme.a
which I copy into my /usr/local/lib
directory (so my C compiler can link properly my C program using it).
So far, so good.
I can compile and link my C program without problems but when I run it I get this error:
thread '<unnamed>' panicked at src/lib.rs:376:10:
Failed to get Cargo metadata: CargoMetadata { stderr: "error: could not find `Cargo.toml` in `/home/fermin/src/mycproject` or any parent directory\n" }
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
fatal runtime error: failed to initiate panic, error 5
Abort
I understand this is due to the current approach expects to get the version at runtime, from the Cargo.toml file. But I don't have a Cargo.toml file at this point (I only have the statically linked libacme.a
binary file).
Is there any way of solving this problem (e.g. implement get_version()
in a way the version number gets included in the static library)?
Cargo sets the CARGO_PKG_VERSION
environment variable for compiled crates, and you can retrieve its value using env!()
. You can even create a constant &CStr
:
use core::ffi::CStr;
#[no_mangle]
pub extern "C" fn get_version() -> *const libc::c_char {
const VERSION: &CStr =
match CStr::from_bytes_with_nul(concat!(env!("CARGO_PKG_VERSION"), "\0").as_bytes()) {
Ok(version) => version,
Err(_) => panic!("package version contains null bytes??"),
};
VERSION.as_ptr()
}