# Building Crosvm on Linux

This page describes how to build and develop crosvm on linux. If you are targeting ChromeOS, please
see [Integration](../integration/index.md)

## Checking out

Obtain the source code via git clone.

```sh
git clone https://chromium.googlesource.com/crosvm/crosvm
```

## Setting up the development environment

Crosvm uses submodules to manage external dependencies. Initialize them via:

```sh
git submodule update --init
```

It is recommended to enable automatic recursive operations to keep the submodules in sync with the
main repository (but do not push them, as that can conflict with `repo`):

```sh
git config submodule.recurse true
git config push.recurseSubmodules no
```

Crosvm development best works on Debian derivatives. We provide a script to install the necessary
packages on Debian, Ubuntu or gLinux:

```sh
./tools/install-deps
```

For other systems, please see below for instructions on
[Using the development container](#using-the-development-container).

### Using the development container

We provide a Debian container with the required packages installed. With
[Podman](https://podman.io/getting-started/installation) or
[Docker](https://docs.docker.com/get-docker/) installed, it can be started with:

```sh
./tools/dev_container
```

The container image is big and may take a while to download when first used. **Once started, you can
follow all instructions in this document within the container shell.**

Instead of using the interactive shell, commands to execute can be provided directly:

```sh
./tools/dev_container cargo build
```

Note: The container and build artifacts are preserved between calls to `./tools/dev_container`. If
you wish to start fresh, use the `--clean` flag.

## Building a binary

If you simply want to try crosvm, run `cargo build`. Then the executable is generated at
`./target/debug/crosvm`. In case you are using development container, the executable will be inside
the dev container at `/scratch/cargo_target/debug/crosvm`.

Now you can move to [Example Usage](../running_crosvm/example_usage.md).

If you want to enable [additional features](../running_crosvm/features.md), use the `--features`
flag. (e.g. `cargo build --features=gdb`)

## Development

### Running all tests

Crosvm's integration tests have special requirements for execution (see
[Testing](../testing/index.md)), so we use a special test runner. By default it will only execute
unit tests:

```sh
./tools/run_tests
```

To execute integration tests as well, you need to specify a device-under-test (DUT). The most
reliable option is to use the built-in VM for testing:

```sh
./tools/run_tests --dut=vm
```

However, you can also use your local host directly. Your mileage may vary depending on your host
kernel version and permissions.

```sh
./tools/run_tests --dut=host
```

Since we have some architecture-dependent code, we also have the option of running unit tests for
aarch64, armhf, riscv64, and windows (mingw64). These will use an emulator to execute (QEMU or
wine):

```sh
./tools/run_tests --platform=aarch64
./tools/run_tests --platform=armhf
./tools/run_tests --platform=riscv64
./tools/run_tests --platform=mingw64
```

When working on a machine that does not support cross-compilation (e.g. gLinux), you can use the dev
container to build and run the tests.

```sh
./tools/dev_container ./tools/run_tests --platform=aarch64
```

### Presubmit checks

To verify changes before submitting, use the `presubmit` script. To ensure the toolchains for all
platforms are available, it is recommended to run it inside the dev container.

```sh
./tools/dev_container ./tools/presubmit
```

This will run clippy, formatters and runs all tests for all platforms. The same checks will also be
run by our CI system before changes are merged into `main`.

See `tools/presumit -h` for details on various options for selecting which checks should be run to
trade off speed and accuracy.

## Cross-compilation

Crosvm is built and tested on x86, aarch64, armhf, and riscv64. Your system needs some setup work to
be able to cross-compile for other architectures, hence it is recommended to use the
[development container](#using-the-development-container), which will have everything configured.

Note: Cross-compilation is **not supported on gLinux**. Please use the development container.

### Enable foreign architectures

Your host needs to be set up to allow installation of foreign architecture packages.

On Debian this is as easy as:

```sh
sudo dpkg --add-architecture arm64
sudo dpkg --add-architecture armhf
sudo dpkg --add-architecture riscv64
sudo apt update
```

On ubuntu this is a little harder and needs some
[manual modifications](https://askubuntu.com/questions/430705/how-to-use-apt-get-to-download-multi-arch-library)
of APT sources.

With that enabled, the following scripts will install the needed packages:

```sh
./tools/install-aarch64-deps
./tools/install-armhf-deps
./tools/install-riscv64-deps
```

### Configuring wine and mingw64

Crosvm is also compiled and tested on windows. Some limited testing can be done with mingw64 and
wine on linux machines. Use the provided setup script to install the needed dependencies.

```sh
./tools/install-mingw64-deps
```

### Configure cargo for cross-compilation

Cargo requries additional configuration to support cross-compilation. You can copy the provided
example config to your cargo configuration:

```sh
cat .cargo/config.debian.toml >> ${CARGO_HOME:-~/.cargo}/config.toml
```

**Note**

In case of cross-compilation, crosvm executable would be at `./target/debug/<target>/crosvm`. If
cross-compiling inside development container, the executable would be inside dev container at
`/scratch/cargo_target/<target>/debug/crosvm`.

e.g For aarch64, `target` will be `aarch64-unknown-linux-gnu` and you can build using

```sh
cargo build --target aarch64-unknown-linux-gnu
```

## Known issues

- Devices can't be jailed if `/var/empty` doesn't exist. `sudo mkdir -p /var/empty` to work around
  this for now.
- You need read/write permissions for `/dev/kvm` to run tests or other crosvm instances. Usually
  it's owned by the `kvm` group, so `sudo usermod -a -G kvm $USER` and then log out and back in
  again to fix this.
- Some other features (networking) require `CAP_NET_ADMIN` so those usually need to be run as root.
