I'm looking for a way to conditionally compile some code based on whether or not each of two particular symbols are exported and not deprecated by a crate that I depend on.
Your reaction is probably "WTF why would you ever", so let me elaborate. The crate in question is libc
and the symbols in question are ENOATTR
and ENODATA
, OS-level error codes which are only defined by some of the operating systems supported by Rust. libc's policy seems to be that it exports all of the E-codes defined by the target OS but not any of the others. (ENOATTR
is exported as a deprecated alias on some of the OSes where it's not defined, but obviously I don't want to be using deprecated symbols.)
The code that uses these symbols looks like this:
/// Remove the xattr `name` from the file `f`; if it wasn't there in the first
/// place, that's fine.
fn discard_xattr<S: AsRef<OsStr>>(f: &File, name: S) -> io::Result<()> {
f.remove_xattr(name).or_else(|e| {
// Ignore failures due to the attribute not being present.
// There is no ErrorKind for these errors and the low-level error code
// is not consistent among supported operating systems.
cfg_if! {
if #[cfg(...)] {
if e.raw_os_error() == Some(libc::ENOATTR) {
return Ok(());
}
}
if #[cfg(...)] {
if e.raw_os_error() == Some(libc::ENODATA) {
return Ok(());
}
}
}
Err(e)
})
}
And the problem is: what do I write in those #[cfg(...)]
expressions? The only option I seem to have is a any(target_os="a", target_os="b", ...)
sequence that duplicates libc's logic for deciding whether to export these symbols in the first place, but that would be incredibly tedious to work out (since it's not written anything like that inside libc) and would also pretty much force me to have an ==
dependency on a specific patch rev of the libc crate.
Ideally I'd like something that makes this as easy as it is in C:
int discard_xattr(int fd, const char *name) {
if (fremovexattr(fd, name) == 0)
return 0;
#ifdef ENOATTR
if (errno == ENOATTR)
return 0;
#endif
#ifdef ENODATA
if (errno == ENODATA)
return 0;
#endif
return -1;
}