|
|
Subscribe / Log in / New account

Status report on optional Rust in FreeBSD support

Shawn Webb has published a status report on work to provide basic support in FreeBSD for userland components written in Rust.

We introduced a new BSD makefile, located at share/mk/bsd.rust.mk, that enables building a Rust application during buildworld. As of this writing, we only support building and installing Rust applications. Supporting library crates is planned (we would like to be able to build/install library crates that expose an FFI, like for C/C++ compatibility). Normal library crates build and install just fine. Support for cdylib Rust library crates specifically is what's missing, but is desired and planned.

We do NOT currently support Rust in the kernel. Kernel support requires more work that we deemed out-of-scope for this initial proof-of-concept/work-in-progress patchset. We also do NOT support building multiple programs in the same BSD Makefile (like with bsd.progs.mk), though that is also a desired feature.

LWN covered a discussion about including Rust in the FreeBSD base system in August 2024.



to post comments

Mixing base rust and upstream cargo...

Posted May 22, 2025 8:14 UTC (Thu) by rsidd (subscriber, #2582) [Link] (16 responses)

The previous discussion included a post by Poul-Henning Kamp describing the problems including perl in base previously caused, basically by making it difficult to tap into the larger Perl ecosystem or even to keep Perl up-to-date, and he worried that the same could happen for rust. In fact even though Linux doesn't have the same "base system" concept, the same is true of python on linux systems -- you have two packaging systems, Ubuntu's (say) and PIP, and they don't play nicely together. Often packages I need are not on Ubuntu's repos or are out of date, and the only sane way to run them is in a virtual environment (python's venv, or something like coda).

It wasn't clear to me how the FreeBSD folks are planning to resolve this issue. PHK's suggestion was moving to a package-based base system, but I am not sure it will solve this problem -- can you mix and match cargo and FreeBSD packages? And how are Linux systems doing this? I am not a Rust or FreeBSD user. On Python on Linux (Ubuntu) this is a real problem. I also use Julia where I install everything from upstream, which is ok since it's not a part of the base install.

Packaging homochirality: don't mix the mirror worlds

Posted May 22, 2025 9:22 UTC (Thu) by tux3 (subscriber, #101245) [Link] (4 responses)

The sane way to do things is not unlike Python. The Python advice is to always install non-system packages in virtualenvs, so that you minimize the interaction between the two worlds as much as possible. You can't break your system, and you also don't try to use system packages as dependencies of a non-system package.

I would recommend the same. The base system should probably bite the bullet and rebuild everything it needs for its own use, in a way that works well with the system. But we can't let the system install interact with a language package manager. I'm not aware of any example where this has worked well. You don't want your car's left and right wheels steering independently: at some point they stop being perfectly aligned and everyone suffers for it.

The default pip behavior has improved, and now most users receive warnings when they try to break the barrier.
The default Rust cargo behavior only uses the system when it needs C dependencies, it otherwise ignores the system Rust install.

Packaging homochirality: don't mix the mirror worlds

Posted May 22, 2025 15:33 UTC (Thu) by geofft (subscriber, #59789) [Link] (3 responses)

If Rust and Cargo are not yet in base, there's an opportunity here for FreeBSD to do something to improve the situation compared to where we ended up for Python (which, I think, phk advocated for): don't expose rustc and cargo on the user-facing $PATH.

Treat the versions of rustc and cargo as implementation details of building code in Rust for FreeBSD. bsd.rust.mk already sets variables with paths, but it defaults them to /usr/local/bin - put them somewhere else, like /usr/local/libexec/rust-toolchain. Then a user is free to install rustc and cargo in whatever way they want (into /usr/local/bin, if they desire, but also more likely via rustup into their home directory) and you can be confident that neither of the two use cases, end-user use of Rust as an actual tool vs. build system use of Rust in order to build end-user-facing tools, will not conflict with each other.

In the spec that improved the situation in Python (and effectively canonized the advice to use virtualenvs), we called out this general problem of toolchains having a dual purpose and two masters: https://peps.python.org/pep-0668/#motivation

Unfortunately the migration away from having an OS-provided python3 command in those OSes that currently provide it is very difficult (and some people had gotten used to influencing the behavior of OS packages by doing sudo pip install, e.g., plugins for Ansible), so if you can do it from day one, you'll be in a much better spot.

On a personal note, many years ago my way of dealing with Python was only ever using dependencies packaged in the OS and never touching pip. By the time of that document my way was using virtualenvs. Now my way is to use uv, which brings its own build of Python that is wholly separate from the OS, and for bonus points is much newer (and I've ended up as one of the maintainers of those Python builds). In some sense this is a huge change in approach, but in another sense it isn't: it's about rigorously picking one world and staying entirely in it. (And now there are increasingly active discussions about how you package C dependencies for Python apps in a way that is independent of the OS, too, which feels like the right approach for the same reasons.)

Packaging homochirality: don't mix the mirror worlds

Posted May 24, 2025 19:25 UTC (Sat) by rsidd (subscriber, #2582) [Link] (2 responses)

This makes sense -- not exposing the system-required rust to the user's path.

For python, venvs make sense if you're the only user. If it's a multi-user system and if the admin needs to make a package available to users, it's a real pain.

Packaging homochirality: don't mix the mirror worlds

Posted May 24, 2025 19:45 UTC (Sat) by geofft (subscriber, #59789) [Link] (1 responses)

If the goal is to make a command (a piece of software) that happens to be written in Python accessible to users, the admin can make a venv in a world-readable location like /opt or /usr/local/, and symlink the command in the bin/ directory from a directory on all users' PATH.

If the goal is to make a managed environment available to users to run their own Python code, they can do the same thing and tell users where the venv is and/or make a wrapper command e.g. /usr/local/bin/python-for-xyz-purpose -> /usr/local/share/venv-for-xyz-purpose/bin/python.

I've done both of these professionally. At a past job we used dh-virtualenv (packaged in upstream Debian for ~15 years), which is a nice tool for creating a venv and installing packages (which can come from PyPI) and distributing it as a Debian package. More recently I made a command "python3-with-stuff" on the user default PATH that ran a non-OS Python install with a venv providing of useful libraries for our environment (requests and requests-kerberos, elasticsearch, a few wrappers around those for doing the right thing for internal auth, some internally-written libraries, etc.), and that approach seemed to be pretty popular.

If the thing you want to make available to users is specifically a package (i.e. a library, which users who are Python developers can use with any environment), I think you want to approach this in the form of setting up an internal package repository that users can install things from, because without --system-site-packages you don't have a way to get that into users' environments (and with --system-site-packages they get too much). Also, users might want to use another version of Python than the one you built it for, etc. You don't have to make an actual repository served over HTTP (though that might be easier for a large site); if all your users have access to the same filesystem, you can make a directory with packages and tell users to use pip --find-links, or even configure that by default in /etc/pip.conf.

Packaging homochirality: don't mix the mirror worlds

Posted May 25, 2025 18:59 UTC (Sun) by rsidd (subscriber, #2582) [Link]

Thanks for the very detailed answers. Also, while I had come across uv earlier, I didn't realize it is being recommended these days as the best solution. (I have made my peace with pip and venv for now; I really dislike conda.)

Base

Posted May 22, 2025 12:09 UTC (Thu) by tialaramex (subscriber, #21167) [Link] (9 responses)

Package base makes it easier to hide the reality that the choice to have C++ in FreeBSD Base has incurred the same ecosystem price as for Perl but not under the control of their committers. Instead of widespread package management C++ tends to shove things into its standard library, and this has reached silly proportions. C++ 26 lands the entire BLAS, an impressively complicated full blown unit system (not just a "distance" type which knows how to convert between miles and metres, but "width" being distinct from "length" so that area can't be erroneously calculated width x width for example) and not one but two distinct approaches to the lock-free reclamation problem plus their infrastructure (Hazard pointers and Read Copy Update) as well as new container types and the usual suite of new algorithms etc. Very little is removed, some things are changed, a great deal is added.

If you'd tried to sell all this stuff as "necessary" for Rust, or Perl, or whatever, PHK would be screaming about how it's unsustainable, but in C++ they have no choice.

Base

Posted May 23, 2025 14:30 UTC (Fri) by nix (subscriber, #2304) [Link] (8 responses)

It's not much of a "choice": without C++ they don't have LLVM or Clang and they don't have GCC.

(And, honestly, while the standard C++ library is getting fairly hefty, its external dependencies aren't too onerous, and that's what matters here -- and its ABI is stable, even though this incurs endless pain for the standard C++ library maintainers. And a hefty standard library is *useful*.)

Base

Posted May 26, 2025 5:22 UTC (Mon) by jrtc27 (subscriber, #107748) [Link] (7 responses)

It's worth pointing out that, on FreeBSD, libc++ is still smaller than libc (just under half the size in fact). (Yes, that's glossing over the fact that much of libc++ is templates in headers that aren't instantiated unless used, but still, you don't pay for those unless you use them.)

Base

Posted May 26, 2025 18:28 UTC (Mon) by comex (subscriber, #71521) [Link] (1 responses)

libc++ depends on libc, so that's a bit of an apples-and-oranges comparison.

But I suppose it still demonstrates that the added overhead isn't too high.

Base

Posted May 28, 2025 21:59 UTC (Wed) by jrtc27 (subscriber, #107748) [Link]

Yes, the point was to contextualise the size of libc++ in a wider system and show it's not taking a disproportionate amount of the space.

Base

Posted May 27, 2025 7:24 UTC (Tue) by tialaramex (subscriber, #21167) [Link] (4 responses)

So, other than the actual library, which you didn't count because "you don't pay for those unless you use them" it's smaller ?

That would have been true for the Perl too and of course it would be true for most languages so long as you decide you're "not paying" for code you didn't use.

Base

Posted May 27, 2025 19:48 UTC (Tue) by nix (subscriber, #2304) [Link] (2 responses)

No, it's smaller *including* the actual library (the header templates).

Base

Posted May 28, 2025 16:14 UTC (Wed) by tialaramex (subscriber, #21167) [Link]

Thanks, that wasn't at all what I understood from your original claim.

I guess we'll see how much bigger this gets before (if ever) FreeBSD decides maybe their policy makes no actual sense.

Base

Posted May 28, 2025 21:57 UTC (Wed) by jrtc27 (subscriber, #107748) [Link]

I wasn't including size of the actual header files on disk, because I wasn't for libc; this is just the .so files. But in terms of header files, /usr/include/c++ is a bit under a third the total size of /usr/include on FreeBSD. Yes, I realise that's comparing against not just libc but all system headers, but the point is not to be some highly-scientific comparison but instead to give helpful comparison points that illustrate it's not a bloated behemoth taking up all your disk space.

Base

Posted May 28, 2025 22:16 UTC (Wed) by jrtc27 (subscriber, #107748) [Link]

Ignoring the subtleties of native modules, for interpreted languages, the standard library implementation has to be present in full on any machine that wishes to run code written in that language. For compiled code, only the compiled bits need to be; anything that's in header files only needs to be present on the developer's machine at compile time.

For reference, /usr/lib/x86_64-linux-gnu/perl-base on an Ubuntu 22.04 system is 5.5M on its own, and the parts of /usr/share/perl/5.34.0 from perl-modules-5.34 is a whole 16.3M, which doesn't even include all the pre-compiled native modules. /lib/libc++.so.1 on an amd64 FreeBSD 14.2-RELEASE-p3 system is 970K, and /usr/include/c++ on that same system is 7.3M, so in total under half the size of Ubuntu's perl-modules-5.34 alone.

Mixing base rust and upstream cargo...

Posted May 25, 2025 22:49 UTC (Sun) by Vorpal (guest, #136011) [Link]

Caveat: I haven't touched freebsd for over two decades, but I do regularly code in Rust (on Linux).

Unlike Python, rust only need dependencies when compiling. This is because Rust doesn't have a stable ABI (other than the C ABI for interacting with C code), so everything must be linked statically.

Also, unlike Python, Rust uses a declarative build configuration and a lock file with hashes of all dependencies (recursively). This eliminates the risk of incompatible dependencies, especially as the Rust ecosystem is strictly semver and you can have separate semver versions of a dependency at once (so lib a and lib b depending on different incompatible versions of lib c just works, as long as you don't try to move data between the two versions of the same library, which will be a compile time error).

Rust compiler versions for developers are generally handled with the "rustup " tool, which handles multiplexing separate versions of the compiler. Unlike venv in python, this would just be a config file in your project directory, and no actual venv needs to be built. It is just about selecting the right version.

Or rather it is about selecting a sufficiently new version. Unlike Python, Rust does not break backwards compatibility (except if necessary for security or soundness fixes). So almost every project uses "most recent stable version" for building with a "minimum supported version" as well (that is generally tested by CI). The compiler is smart enough to warn if you try to use an API older than your minimum supported version, but that doesn't (yet?) apply to dependencies (so you could start depending on a version of a dependency that doesn't work on your minimum rust version).

That said, not everything is unicorns and rainbows. If you want to vendor all dependencies as separate packages (like Debian does) you are in for a painful time. Also, debian for some reason don't want to package multiple major versions of a Rust dependency side by side. For whatever reason.

Overall though, it should be much less painful than this would be for Perl or Python.

I would actually (for general purpose coding) recommend using the most recent stable version of Rust, rather than some LTS version Debian or other packages. Becuse Rust tends to be very stable, and the regressions that do happen are very niche. How is this done? The rust project has a tool called crater that builds and test every public piece of rust code, and they use this to check that they don't introduce breaking changes or regressions.


Copyright © 2025, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds