Awesome
Cosmopolitan Libc and Rust
Note: the executables built using Cosmo and Rust do not work across the operating systems supported by Cosmopolitan Libc, because Rust decides system constants like
EINVAL
at compile-time (see https://github.com/ahgamut/rust-ape-example/issues/3), based on the operating system provided in the compilation target. Thus, I expect the fat binaries built here will only work onx86-64-linux
andaarch64-linux
. Very well, perhaps in the future we can find a way to have system constants asextern
values in Rust, like how I did it for C.
This repository contains a simple Hello world!
example in the Rust
programming language, that builds with Cosmopolitan Libc. Now it also
includes all the example snippets I could scrape from Rust By Example,
and it builds around 175 example programs, including those that use Rust's
std::thread
and std::sync::Arc
.
ripgrep
builds with Cosmopolitan Libc -- check it out here.
To build this repo you need a recent version of the Cosmopolitan Libc monorepo,
and bash
because I wrote a simple filter script.
I created a custom compilation target for Rust, called
x86_64-unknown-linux-cosmo
, to provide a build process that uses the
Cosmopolitan Libc amalgamation and cargo
. I followed the documentation in the
Rust Embedonomicon to create the target.
An alternative method to build APEs with Rust would be to avoid cargo
, just
use rustc
or equivalent compiler to generate .o
files, and then write a
shell script that does the linking with the expected flags. I have not tried
this method.
Building a Rust APE with the std
crate
- Download the Cosmopolitan Libc repo and build the toolchain:
git clone https://github.com/jart/cosmopolitan
cd cosmopolitan
make -j MODE= toolchain
make -j MODE=aarch64 toolchain
export COSMO=$(realpath ./)
cd ..
mkdir cosmos
export COSMOS=$(realpath ./cosmos)
$COSMO/bin/cosmocc --update
Then clone this repo
git clone https://github.com/ahgamut/rust-ape-example
cd rust-ape-example
- Download the necessary host toolchain and source code for Rust:
# I was on Debian 11, so I did this
rustup toolchain install nightly-x86_64-unknown-linux-gnu
rustup component add rust-src --toolchain nightly-x86_64-unknown-linux-gnu
# on Alpine Linux, you may need to do
rustup toolchain install nightly-x86_64-unknown-linux-musl
rustup component add rust-src --toolchain nightly-x86_64-unknown-linux-musl
For reference, this worked when I tried it for nightly-x86_64-linux-gnu
and:
- the Rust binaries on October 10 2023
- run
cargo build
to get the debug executables. This uses a bash script that removes unnecessary linker arguments.
export ARCH=x86_64
cargo +nightly build --target=./x86_64-unknown-linux-cosmo.json
export ARCH=aarch64
cargo +nightly build --target=./aarch64-unknown-linux-cosmo.json
- run
apelink
on the debug binaries to obtain the fat APE:
# look at the built debug binaries
ls ./target/x86_64-unknown-linux-cosmo/debug/*.com.dbg
ls ./target/aarch64-unknown-linux-cosmo/debug/*.com.dbg
# apelink
MODE=
MODE_AARCH64=aarch64
APELINK=$COSMO/o/tool/build/apelink.com
apelinkpls () {
OUTPUT="$1"
OUTPUT_X86_64="$2"
OUTPUT_AARCH64="$3"
"$APELINK" -l "$COSMO/o/$MODE/ape/ape.elf" \
-l "$COSMO/o/$MODE_AARCH64/ape/ape.elf" \
-M "$COSMO/ape/ape-m1.c" \
-o "$OUTPUT" \
"$OUTPUT_X86_64" \
"$OUTPUT_AARCH64"
}
apelinkpls ./hello.com\
./target/x86_64-unknown-linux-cosmo/debug/hello.com.dbg\
./target/aarch64-unknown-linux-cosmo/debug/hello.com.dbg
# run the APE
./hello.com
Now we have Actually Portable Executables built with Rust! I also built a few
more executables using the code from Rust By Example, and an APE that
doesn't use the std
crate. There might some edge cases that I haven't noticed,
so clone/fork the repo and try it out!
TODOs
- figure out build config to avoid using
libunwind
The std
crate relies on
backtrace
, which depends on
libunwind
in the default builds for
unix. To work around this, cosmopolitan.a
currently has stubs for the
functions that backtrace
relies on. However, it might be easier to provide a
build flag in Cargo.toml
to use the noop
module of backtrace
.
A small change needs to be submitted to the source code of backtrace
(in the
cfg_if!
here)
to allow choosing noop
when building as part of the std
crate. This
conditional compilation flag should be accessible when building the std
crate
either via Cargo.toml
or something like -Z use-std-backtrace-noop
in the
build command.