-
Notifications
You must be signed in to change notification settings - Fork 23
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
Test if a dependency contains a path or symbol #60
Comments
I think it would be a useful extension here, but I don't know a good way to accomplish it. The crude way would be to add The clean way to add dependency crates would be with |
Tried to mess a bit with autocfg but got blocked by the extern crate autocfg;
use std::process::Command;
use std::process::Output;
fn main() {
// TODO how to get around rustc_private with autocfg
// FIXME temporary solution: rust-script compiles for and runs in the local system? I want to test-compile for the target system or similar
// does rust-script work? (warning: outputs to stdout/stderr)
let status = Command::new("rust-script").arg("--version").status().expect("rust-script is required, running 'cargo install rust-script' in the console should fix this error\n");
if !status.success() {
panic!("rust-script: {}", status);
}
// sanity check: libc::size_t should always exist
assert!(Command::new("rust-script").args(["--dep", "libc", "--expr", "{ let _: libc::size_t = 0; }"]).output().unwrap().status.success());
fn probe_dep_path(dep: &str, path: &str) -> Output {
let expr = format!("{{ use {}; }}", path);
Command::new("rust-script").args(["--dep", dep, "--expr", &expr]).output().unwrap()
}
fn emit_dep_path_cfg(dep: &str, path: &str, cfg: &str) {
if probe_dep_path(dep, path).status.success() {
autocfg::emit(cfg);
}
}
emit_dep_path_cfg("libc", "libc::B76800", "has_libc_B76800");
// ...
} |
I had another go at this and a strategy based on trait AutoCfgExt {
/// Probes if a raw crate can be compiled.
fn probe_raw_crate(&self, name: &str, cargo_toml: &str, lib_rs: &str) -> Result<(), std::io::Error>;
/// Emits cfg if a dependency exposes a specific struct field.
fn emit_dep_has_struct_field(&self, dep: &str, struct_path: &str, field_path: &str, cfg: &str);
/// Emits cfg if a dependency exposes a specific path.
fn emit_dep_has_path(&self, dep: &str, path: &str, cfg: &str);
}
impl AutoCfgExt for autocfg::AutoCfg {
fn probe_raw_crate(&self, name: &str, cargo_toml: &str, lib_rs: &str) -> Result<(), std::io::Error> {
// create crate
let mut crate_path: PathBuf = out_dir();
crate_path.push("probe_raw_crate");
crate_path.push(name);
let src_path = crate_path.join("src");
if !src_path.is_dir() {
std::fs::create_dir_all(&src_path)?;
}
std::fs::write(crate_path.join("Cargo.toml"), cargo_toml)?;
std::fs::write(src_path.join("lib.rs"), lib_rs)?;
// cargo check
let cargo = std::env::var_os("CARGO").expect("cargo");
let mut child = Command::new(cargo).arg("check").current_dir(&crate_path).spawn()?;
match child.wait() {
Ok(status) if status.success() => Ok(()),
Ok(_) => Err(std::io::ErrorKind::Other.into()), // TODO error with failure status code
Err(err) => Err(err),
}
}
fn emit_dep_has_struct_field(&self, dep: &str, struct_path: &str, field_path: &str, cfg: &str) {
let cargo_toml = format!(
r#"
[package]
name = "{cfg}"
edition = "2021"
[workspace]
[dependencies]
{dep}
"#
);
let lib_rs = format!("fn _f(x: &{struct_path}) {{ let _ = x.{field_path}; }}");
autocfg::emit_possibility(cfg);
if self.probe_raw_crate(cfg, &cargo_toml, &lib_rs).is_ok() {
autocfg::emit(cfg);
}
}
fn emit_dep_has_path(&self, dep: &str, path: &str, cfg: &str) {
let cargo_toml = format!(
r#"
[package]
name = "{cfg}"
edition = "2021"
[workspace]
[dependencies]
{dep}
"#
);
let lib_rs = format!("pub use {path};");
autocfg::emit_possibility(cfg);
if self.probe_raw_crate(cfg, &cargo_toml, &lib_rs).is_ok() {
autocfg::emit(cfg);
}
}
}
fn out_dir() -> PathBuf {
std::env::var_os("OUT_DIR").expect("out dir").into()
}
fn main() {
// auto config
let ac = autocfg::new();
let libc = r#"libc = { version = "0.2", features = ["extra_traits"] }"#; // TODO get string from Cargo.toml?
ac.emit_dep_has_struct_field(libc, "libc::tm", "tm_gmtoff", "has_libc_tm_tm_gmtoff");
ac.emit_dep_has_path(libc, "libc::B76800", "has_libc_b76800");
} |
Sorry if this is the wrong crate. This crate is the closest that I could find to the functionality that I need.
I'm porting code from C to rust that has
#if defined(...)
code.The crate
libc
has the symbols I need but I can't find a way to automatically test if they actually exist (within cargo/rust) and do conditional compilation with that. Using '#[cfg(target_os = "...")]' combinations would be very error prone and a huge maintenance burden that I'm not gonna introduce.What I need is something like this for
build.rs
:Is it possible to use or adapt this crate for this use case?
If not, can you point me to any other crate that I can look into?
The text was updated successfully, but these errors were encountered: