Using modern APIs in Rust on FreeBSD
tldr; should the Rust ecosystem ditch FreeBSD 10 compat for new code? Rust uses FFI to talk to the OS's C library. That makes cross-compiling a breeze. Unfortunately, it also fossilizes the ABI. FreeBSD's libc makes careful use of ELF symbol versioning. That's how we were able to change ino_t to 64-bits while maintaining backwards-compatibility with old binaries, for example. But the Rust toolchain isn't able to take advantage. Right now, the toolchain uses a FreeBSD 10 ABI, and the libc crate (which virtually all crates depend on) uses a FreeBSD 11 ABI. That means, for example, that no crate can use: * The offset field in a struct dirent * 64-bit nlink_t * 64-bit ino_t * No NOTE_ABSTIME with kevent * filesystem and mountpoint names in statfs(2) limited to 88 characters Until somebody fixes that hard problem, the easy thing for Rust to do would be to drop support for EoL versions. FreeBSD 10 has been EoL for nearly 3 years, and FreeBSD 11 will be EoL in a few days. I for one think that it would be fine for new Rust toolchains and libc releases to drop support for FreeBSD 10 and 11. People who need to build for old releases can easily get old toolchains from rustup, or even from old Ports snapshots. But the Rust core developers are conservative, and don't want to upset users of a platform that many of them don't understand. Do you agree with me? If so (or even if you don't), make some noise on this Github issue! Give the Rust core team the confidence they need to move forward. https://github.com/rust-lang/rust/issues/89058 -Alan
Re: Using modern APIs in Rust on FreeBSD
On Wed, Sep 22, 2021 at 6:08 AM Alan Somers wrote: > tldr; should the Rust ecosystem ditch FreeBSD 10 compat for new code? > > Rust uses FFI to talk to the OS's C library. That makes cross-compiling a > breeze. Unfortunately, it also fossilizes the ABI. FreeBSD's libc makes > careful use of ELF symbol versioning. That's how we were able to change > ino_t to 64-bits while maintaining backwards-compatibility with old > binaries, for example. But the Rust toolchain isn't able to take > advantage. Right now, the toolchain uses a FreeBSD 10 ABI, and the libc > crate (which virtually all crates depend on) uses a FreeBSD 11 ABI. > How exactly is the ABI fossilized? If Rust's FFI uses run-time dynamic linking, it should be able to use dlvsym() to access the correct version of libc symbols. Damjan
Re: Using modern APIs in Rust on FreeBSD
On Wed, Sep 22, 2021 at 06:27:09AM +0200, Damjan Jovanovic wrote: > On Wed, Sep 22, 2021 at 6:08 AM Alan Somers wrote: > > > tldr; should the Rust ecosystem ditch FreeBSD 10 compat for new code? > > > > Rust uses FFI to talk to the OS's C library. That makes cross-compiling a > > breeze. Unfortunately, it also fossilizes the ABI. FreeBSD's libc makes > > careful use of ELF symbol versioning. That's how we were able to change > > ino_t to 64-bits while maintaining backwards-compatibility with old > > binaries, for example. But the Rust toolchain isn't able to take > > advantage. Right now, the toolchain uses a FreeBSD 10 ABI, and the libc > > crate (which virtually all crates depend on) uses a FreeBSD 11 ABI. > > > > How exactly is the ABI fossilized? If Rust's FFI uses run-time dynamic > linking, it should be able to use dlvsym() to access the correct version of > libc symbols. No, FFI does not use dynamic linking in dynamic sense, i.e. it does not utilize dlopen/dlsym. Rust directly calls into extern "C" functions, and this is quite useful feature, because using dlsym for everything you need from system libraries is beyond the pain point. Rust can link to specific version of the symbol, and libc uses this feature, like this: #[cfg_attr(all(target_os = "freebsd", freebsd11), link_name = "statfs@FBSD_1.0")] pub fn statfs(path: *const ::c_char, buf: *mut statfs) -> ::c_int; There it requests pre-ino64 statfs(). More, libc already has configurations for freebsd11 and later, as can be seen from the citation above. And I see nothing that would prevent libc from defining freebsd11 and freebsd12 variants of struct stat, struct statfs, struct dirent, and so on. That said, I definitely do not want spend (more) time on this. Due to the way libc is structured, to make an impression that definitions are shared between different *BSDs, it is extremely painful to add new bindings and not break other BSDs. I tried something as simple as adding missing MNT_XXX constants for mnt_flags and gave up after full day when I realized that I have to test on Net/Open/DragonflyBSD as well.