Feature-based conditional compilation?


#1

I’ve gotten rustc and cargo working on (Oracle) Solaris recently, thanks very much to some pointers from @vojtechkral and the work done by @nbaksalyar, and am looking at what it would take to make it part of the product.

The high-level thing that I seem to be running into is that what support there is in Rust and various crates for Solaris is targeted at Illumos, which is hardly surprising. But a handful of differences have come up, including a libc API difference in getpwuid_r(), and a lack of flock(). I’m currently sharing the x86_64-sun-solaris triple, which means there’s no way (that I know of) to conditionally compile against Oracle Solaris vs Illumos.

So the question is, what to do about that. The most straightforward path might be to introduce a new vendor/OS combination to distinguish the two. But it occurred to me that just because these particular differences exist now, they might not always – Solaris could add flock() at some point, and then we’d want to distinguish between the Solaris that had it and the Solaris that didn’t.

We could do that by having conditions specific to OS versions, but that seems like an unsupportable rathole. Since the real underlying conditions here are the presence or absence of features, it seems to me that something similar to autoconf’s feature testing is a better direction. Would there be any stomach for something like that, or is there a better architecture that I should consider?


#2

Autoconf style testing is possible in a Cargo build script - they can emit cfgs that the main crate will be built with. That approach is a bit unfortunate in that it fails when cross compiling, though.


#3

Of course, that thought occurred to me a few minutes after posting (the build script page on doc.crates.io doesn’t really cover how you’d make that happen, but I’m sure I could figure it out), and that should work for the flock() change I made to fs2. But I’m not sure how it would work for the change to libstd (and the corresponding one to liblibc) as part of the rustc build.

And yeah, it would also be nice to preserve the ability to cross-compile.


#4

For supporting multiple versions of an OS we typically fall back to runtime detection with ideally “optimized caching”. This certainly isn’t always easy to implement, but it gets the job done! In general though we do like to add #[cfg] for various pieces of a platform if it makes sense (e.g. musl vs gnu).

I do think that feature detection makes sense mostly in build scripts, but I’ve also always been wary of it because it means you have to compile on the least common denominator machine rather than a super new machine that produces compatible binaries (which is sometimes quite a pain).

Some examples of runtime detection include:


#5

weak! seems like a nifty macro, but I’m not sure how to use it, other than copying its implementation. Is it available outside of std::sys::unix? Presumably its result could be cached for performance-sensitive applications.

And while that helps for flock(), which is missing on Solaris (but not Illumos), I don’t see how to use any of these symbol-finding mechanisms to get around getpwuid_r() having a different function signature on Illumos than on other platforms. The symbol will be found, but nothing about it tells me which underlying implementation is available. The only safe way I can think of to detect that is to write a C program, autoconf style, to check the signature against the C headers (which I did get working for the flock() case). The only runtime way I can think of is to find a file whose existence (or contents) determines whether the running OS is Illumos or Solaris, but that feels incredibly skeezy to me.

Perhaps there are other ideas I’m missing?


#6

Well, or just have separate dedicated triples to distinguish Solaris and Illumos: <arch>-sun-solaris and <arch>-unknown-illumos or something.


#7

I think this is the best way to do it.

Previously discussed here: Building rustc on Solaris