2023-11-02 03:27:51 +00:00
|
|
|
# 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
|
2023-11-02 03:29:57 +00:00
|
|
|
> compile-time](https://github.com/search?q=repo%3Arust-lang%2Flibc%20EINVAL&type=code)
|
|
|
|
> (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 on `x86-64-linux` and `aarch64-linux`. Very
|
|
|
|
> well, perhaps in the future we can find a way to have system constants as
|
|
|
|
> `extern` values in Rust, like how [I did it for
|
2023-11-02 03:27:51 +00:00
|
|
|
> C](https://github.com/ahgamut/gcc/tree/portcosmo-11.2).
|
2022-06-21 07:09:00 +00:00
|
|
|
|
|
|
|
This repository contains a simple `Hello world!` example in the [Rust][rust]
|
2022-09-07 13:10:41 +00:00
|
|
|
programming language, that builds with [Cosmopolitan Libc][cosmo]. Now it also
|
|
|
|
includes all the example snippets I could scrape from [Rust By Example][rbe],
|
2022-09-12 12:09:34 +00:00
|
|
|
and it builds around 175 example programs, including those that use Rust's
|
|
|
|
`std::thread` and `std::sync::Arc`.
|
2022-09-07 13:10:41 +00:00
|
|
|
|
2022-09-12 12:09:34 +00:00
|
|
|
> `ripgrep` builds with Cosmopolitan Libc -- check it out
|
|
|
|
> [here](https://github.com/ahgamut/ripgrep/tree/cosmopolitan).
|
2022-09-07 13:10:41 +00:00
|
|
|
|
|
|
|
|
2023-10-10 13:15:47 +00:00
|
|
|
To build this repo you need a recent version of the Cosmopolitan Libc monorepo,
|
|
|
|
and `bash` because I wrote a simple filter script.
|
2022-06-21 07:09:00 +00:00
|
|
|
|
|
|
|
I created a [custom compilation target][custom-target] for Rust, called
|
2022-06-21 09:56:16 +00:00
|
|
|
`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][custom-embed] to create the target.
|
2022-06-21 07:09:00 +00:00
|
|
|
|
|
|
|
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.
|
|
|
|
|
2022-06-22 17:09:06 +00:00
|
|
|
## Building a Rust APE with the `std` crate
|
2022-06-21 07:09:00 +00:00
|
|
|
|
2023-10-10 13:15:47 +00:00
|
|
|
1. Download the Cosmopolitan Libc repo and build the toolchain:
|
2022-06-21 07:09:00 +00:00
|
|
|
|
|
|
|
```bash
|
2023-10-10 13:15:47 +00:00
|
|
|
git clone https://github.com/jart/cosmopolitan
|
|
|
|
cd cosmopolitan
|
|
|
|
make -j MODE= toolchain
|
|
|
|
make -j MODE=aarch64 toolchain
|
|
|
|
export COSMO=$(realpath ./)
|
|
|
|
cd ..
|
2023-10-10 14:46:35 +00:00
|
|
|
mkdir cosmos
|
|
|
|
export COSMOS=$(realpath ./cosmos)
|
|
|
|
$COSMO/bin/cosmocc --update
|
2022-06-21 07:09:00 +00:00
|
|
|
```
|
|
|
|
|
2023-10-10 13:15:47 +00:00
|
|
|
Then clone this repo
|
|
|
|
|
|
|
|
```bash
|
|
|
|
git clone https://github.com/ahgamut/rust-ape-example
|
|
|
|
cd rust-ape-example
|
|
|
|
```
|
2022-06-22 17:09:06 +00:00
|
|
|
|
|
|
|
2. Download the necessary host toolchain and source code for Rust:
|
2022-06-21 07:09:00 +00:00
|
|
|
|
|
|
|
```bash
|
2022-06-22 17:09:06 +00:00
|
|
|
# I was on Debian 11, so I did this
|
2022-06-21 07:09:00 +00:00
|
|
|
rustup toolchain install nightly-x86_64-unknown-linux-gnu
|
|
|
|
rustup component add rust-src --toolchain nightly-x86_64-unknown-linux-gnu
|
2022-06-21 09:56:16 +00:00
|
|
|
# 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
|
2022-06-21 07:09:00 +00:00
|
|
|
```
|
|
|
|
|
2022-06-26 12:54:58 +00:00
|
|
|
For reference, this worked when I tried it for `nightly-x86_64-linux-gnu` and:
|
|
|
|
|
2023-10-10 13:15:47 +00:00
|
|
|
* the Rust binaries on October 10 2023
|
2022-06-22 17:09:06 +00:00
|
|
|
|
2023-10-10 13:15:47 +00:00
|
|
|
3. run `cargo build` to get the debug executables. This uses a bash script that
|
|
|
|
removes unnecessary linker arguments.
|
2022-06-21 07:09:00 +00:00
|
|
|
|
|
|
|
```bash
|
2023-10-10 13:15:47 +00:00
|
|
|
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
|
2022-06-22 17:09:06 +00:00
|
|
|
```
|
|
|
|
|
|
|
|
|
2023-10-10 13:15:47 +00:00
|
|
|
4. run `apelink` on the debug binaries to obtain the fat APE:
|
2022-06-21 07:09:00 +00:00
|
|
|
|
|
|
|
```bash
|
2022-06-30 18:14:05 +00:00
|
|
|
# look at the built debug binaries
|
|
|
|
ls ./target/x86_64-unknown-linux-cosmo/debug/*.com.dbg
|
2023-10-10 14:46:35 +00:00
|
|
|
ls ./target/aarch64-unknown-linux-cosmo/debug/*.com.dbg
|
2023-10-10 13:15:47 +00:00
|
|
|
|
|
|
|
# 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\
|
2023-10-10 14:46:35 +00:00
|
|
|
./target/x86_64-unknown-linux-cosmo/debug/hello.com.dbg\
|
|
|
|
./target/aarch64-unknown-linux-cosmo/debug/hello.com.dbg
|
2023-10-10 13:15:47 +00:00
|
|
|
|
2022-06-22 17:09:06 +00:00
|
|
|
# run the APE
|
2023-10-10 13:15:47 +00:00
|
|
|
./hello.com
|
2022-06-21 07:09:00 +00:00
|
|
|
```
|
|
|
|
|
2022-06-26 14:53:21 +00:00
|
|
|
Now we have Actually Portable Executables built with Rust! I also built a few
|
|
|
|
more executables using the code from [Rust By Example][rbe], 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!
|
2022-06-21 07:09:00 +00:00
|
|
|
|
2022-06-22 17:09:06 +00:00
|
|
|
## TODOs
|
2022-06-21 07:09:00 +00:00
|
|
|
|
2022-06-22 17:09:06 +00:00
|
|
|
- [ ] figure out build config to avoid using `libunwind`
|
2022-06-21 07:09:00 +00:00
|
|
|
|
2022-06-22 17:09:06 +00:00
|
|
|
The `std` crate relies on
|
|
|
|
[`backtrace`](https://github.com/rust-lang/backtrace-rs), which depends on
|
|
|
|
[`libunwind`](https://github.com/libunwind/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`.
|
2022-06-21 07:09:00 +00:00
|
|
|
|
2022-06-22 17:09:06 +00:00
|
|
|
A small change needs to be submitted to the source code of `backtrace` (in the
|
|
|
|
`cfg_if!`
|
|
|
|
[here](https://github.com/rust-lang/backtrace-rs/blob/4e5a3f72929f152752d5659e95bb15c8f6b41eff/src/backtrace/mod.rs#L128))
|
|
|
|
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.
|
2022-06-21 07:09:00 +00:00
|
|
|
|
2022-06-22 17:09:06 +00:00
|
|
|
[without-std-branch]: https://github.com/ahgamut/rust-ape-example/tree/without-std
|
2022-06-21 07:09:00 +00:00
|
|
|
[rust]: https://rust-lang.org
|
2022-06-26 14:53:21 +00:00
|
|
|
[rbe]: https://doc.rust-lang.org/rust-by-example/
|
2022-06-21 07:09:00 +00:00
|
|
|
[cosmo]: https://github.com/jart/cosmopolitan
|
2022-09-12 12:09:34 +00:00
|
|
|
[cosmo-nightly]: https://github.com/jart/cosmopolitan/commit/b69f3d2488dbaf9dcc541e699f5b7c09fbf046e0
|
2022-06-21 07:09:00 +00:00
|
|
|
[amalg-download]: https://justine.lol/cosmopolitan/download.html
|
|
|
|
[custom-target]: https://doc.rust-lang.org/rustc/targets/custom.html
|
|
|
|
[custom-embed]: https://docs.rust-embedded.org/embedonomicon/custom-target.html
|