-
Notifications
You must be signed in to change notification settings - Fork 20
How to start development
This document is intended to help later developers become quickly familiar with the project development process.
Our project is organized in the Cargo Workspace,
It contains two packages.
-
proot-rs
The main part of the project, which is the entry point for the proot-rs application -
loader-shim
A simple loader program that is used when translating the execve() function. The package is compiled separately into a static executable as part of the proot-rs executable.
Our project is built using the cargo
tool, so you must first install the Rust development kit.
To simplify the build, we also use cargo-make
to manage the build scripts. cargo-make
is very similar to make
. Makefile.toml
is our build script file. You can install cargo-make
with the following commands:
# Install stable rust toolchain
rustup toolchain install stable
# Install cargo-make
cargo +stable install --force cargo-make
Note: We recommend using the stable toolchain to install
cargo-make
in order to avoid installation failures
If you want to cross-compile proot-rs
for other platforms, I recommend using cross
to avoid some weird and complicated linker configuration (especially when compiling for the Android platform).
You can use the following command to install cross
cargo install cross
To build the full proot-rs
, directly run:
cargo make build
The command basically consists of the following steps:
- Run
cargo build
onloader-shim
package to compile the loader executable. - Copy the loader executable
loader-shim
toproot-rs/src/kernel/execve/loader-shim
- Run
cargo build
onproot-rs
package to build the final executable.
If you just want to build loader-shim
, run.
cargo make build-loader
If you want to build the release version (which usually means executable size optimization and speed optimization) instead of the debug version, you can append the --profile=production
flag to these commands above.
Note: This
--profile
option comes fromcargo-make
, which has a different meaning than theprofile
in cargo. And it is processed bycargo-make
and will not be passed tocargo
.
Cross-compiling to these targets is currently supported:
- x86_64-unknown-linux-musl
- x86_64-unknown-linux-gnu
- x86_64-linux-android
- i686-unknown-linux-musl
- i686-unknown-linux-gnu
- i686-linux-android
- armv7-unknown-linux-musleabihf
- armv7-unknown-linux-gnueabihf
- arm-linux-androideabi
- aarch64-unknown-linux-musl
- aarch64-unknown-linux-gnu
- aarch64-linux-android
If you want to build proot-rs for other platforms, use the -CARGO_BUILD_TARGET
environment variable.
For example, to compile to a 32-bit arm platform Linux device, and using glibc as dynamic linker.
-
First you need to install the appropriate
target
for the current rust toolchain.rustup target add armv7-unknown-linux-gnueabihf
-
Additional steps for the Android targets
If you are compiling to the Android platform, you will also need to install the NDK in your environment. you can download a copy from here and unzip it.
In addition, you need to configure the appropriate linker path in
.cargo/config.toml
. Since we have already configured the appropriate linker name in.cargo/config.toml
, you only need to add<path-to-ndk-dir>/toolchains/llvm/prebuilt/linux-x86_64/bin/
to thePATH
.Of course, for people who want to keep their
PATH
clean, you can manually modify.cargo/config.toml
. For example, if you are buildingarm-linux-androideabi
you can write[target.arm-linux-androideabi] linker = "<path-to-ndk-dir>/toolchains/llvm/prebuilt/linux-x86_64/bin/armv7a-linux-androideabi21-clang"
-
Compile.
CARGO_BUILD_TARGET=armv7-unknown-linux-gnueabihf cargo make build
Note: This command may fail for compiling to some targets because the linker reports some error. In this case, you may need to install an additional gcc/ clang toolchain on your computer, and specify the appropriate linker path in the
.cargo/config.toml
file
A better way to do cross-compilation is to use cross
, which saves you the trouble of manually managing targets and configuring the NDK. cross
relies on docker to run, so you need to install docker and start the docker daemon first.
We also integrate cross
in the build script, which you can turn on with USE_CROSS=true
.
For example, if you want to to cross-compile to arm-linux-androideabi
, you can directly run
USE_CROSS=true CARGO_BUILD_TARGET=arm-linux-androideabi cargo make build
Build and run proot-rs
:
cargo make run -- "<args-of-proot-rs>"
Build and run release version of proot-rs
:
cargo make run --profile=production -- "<args-of-proot-rs>"
Typically, we need to specify a new rootfs path for testing proot-rs.
This script provided below can be used to create one:
# This will create a busybox-based temporary rootfs at ./rootfs/
bash scripts/mkrootfs.sh
Start running unit tests:
cargo make unit-test
Note: Add the option
--profile=production
if you want to test a release build of proot-rs
By default, By default, ./rootfs/
will be used as the root filesystem for testing purposes. But you can set the environment variable PROOT_TEST_ROOTFS
to change this behavior.
export PROOT_TEST_ROOTFS="<absolute-path-to-a-rootfs>"
For the section on running integration tests, please read the Integration Testing documentation
Note that while we can cross-compile to several different targets, we are not currently able to run tests for other targets. This is because cross
relies on user-mode qemu
to provide this cross-platform testing capability. But qemu
cannot emulate ptrace()
, which means that it is not possible to run any programs that rely on ptrace()
in user-mode qemu
, nor can proot-rs
.
We use git hooks to check files staged for commit to ensure the consistency of Rust code style.
Before you start, please run the following command to setup git hooks:
git config core.hooksPath .githooks
To format code manually:
cargo fmt
Our project uses a lot of third-party libraries, and here are some of the common ones
-
libc
: Officially provided by rust, an FFI binding to the libc library on the platform. -
nix
: This library provides bindings to the APIs on the *nix platform, and is more Rust-friendly thanlibc
above. -
sc
: This library provides a list of system calls, supports many platforms, and provides a way to launch primitive system calls. -
nc
: This library provides a more Rust-friendly wrapper thansc
, but the project is not well-developed, so it is currently only used in unit tests for now.