# Developer's guide

## Build

To install from source, you'll need to install Rust and [Cargo][cargo]. Follow
the instructions on the [Rust installation page][install-rust].

You'll also need the version of LLVM specified in the `llvm-ir` dependency in
`Cargo.toml` (LLVM 14, at the time of writing).[^1] Follow the [instructions on
building llvm-sys][llvm-sys] to make it available to Cargo.

Then, get the source:

```bash
git clone https://github.com/GaloisInc/yapall
cd yapall
```

Finally, build everything:

```bash
cargo build --release
```

You can find binaries in `target/release`. Run tests with `cargo test`.

[^1]: When run from the repository root, this command will show you the exact version: `cargo read-manifest | jq '.dependencies|.[]|select(.name|contains("llvm"))|.features|.[0]'`.

[cargo]: https://doc.rust-lang.org/cargo/
[install-rust]: https://www.rust-lang.org/tools/install
[llvm-sys]: https://gitlab.com/taricorp/llvm-sys.rs#build-requirements

### Example: Debian "bookworm"

Here's an end-to-end sequence of commands that installs the build and test
dependencies of yapall on Debian bookworm:
```sh
apt-get update
UBUNTU_NAME="bookworm"
LLVM_MAJOR_VERSION="14"
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
echo "deb http://apt.llvm.org/${UBUNTU_NAME}/ llvm-toolchain-${UBUNTU_NAME}-${LLVM_MAJOR_VERSION} main" | tee /etc/apt/sources.list.d/llvm.list
apt-get -y install --no-install-recommends llvm-${LLVM_MAJOR_VERSION} llvm-${LLVM_MAJOR_VERSION}-dev
apt-get install libpolly-14-dev
apt-get -y install clang-${LLVM_MAJOR_VERSION}
apt-get -y install clang++-${LLVM_MAJOR_VERSION}
```

### Features

See `Cargo.toml` for various build features. `par` enables parallel Ascent.

### PGO

First, build a benchmark program. You'll want this to be as large as possible,
but still small enough to be handled context-sensitively. For example:

```sh
clang++ -emit-llvm -O1 -c -fno-discard-value-names tests/medium/jackson.cpp
```

Then, build the instrumented binary:

```sh
cargo install cargo-pgo
rustup component add llvm-tools-preview
cargo pgo build
```

Collect data:

```sh
target/x86_64-unknown-linux-gnu/release/yapall --contexts 3 --quiet jackson.bc
```

Finally, build and install the optimized binary:

```sh
cargo pgo optimize
mv target/x86_64-unknown-linux-gnu/release/yapall /wherever
```

## Docs

HTML documentation can be built with [mdBook][mdbook]:

```sh
cd doc
mdbook build
```

[mdbook]: https://rust-lang.github.io/mdBook/

## Format

All code should be formatted with [rustfmt][rustfmt]. You can install rustfmt
with [rustup][rustup] like so:

```sh
rustup component add rustfmt
```

and then run it like this:

```sh
cargo fmt
```

[rustfmt]: https://rust-lang.github.io/rustfmt
[rustup]: https://rustup.rs/

## Lint

All code should pass [Clippy][clippy]. You can install Clippy with rustup
like so:

```sh
rustup component add clippy
```

and then run it like this:

```sh
cargo clippy --workspace -- --deny warnings
```

[clippy]: https://doc.rust-lang.org/stable/clippy/

## Profile

### Counts

To see cumulative time taken by each rule:

```sh
cargo install counts
cargo run --quiet --release -- --quiet --tracing --signatures signatures.json irving.bc 2> /tmp/nanos
counts -i -e /tmp/nanos
```

(You may also want to try with `cargo run --features par`.)

To see cumulative tuples generated by each rule:

```sh
cargo install counts
cargo run --quiet --release --features count -- --quiet --signatures signatures.json irving.bc 2> /tmp/nanos
counts -i -e /tmp/nanos
```

### dhat

```sh
cargo build -q --release --features dhat-heap
./target/release/yapall --quiet --signatures signatures.json jackson.bc
```

Then, go to <https://nnethercote.github.io/dh_view/dh_view.html> to upload
`dhat-heap.json`.

### perf

```sh
cargo build -q --release
perf record ./target/release/yapall --signatures signatures.json jackson.bc
```

### Poor Man's Profiler

```sh
cargo build -q --release
./target/release/yapall --signatures signatures.json jackson.bc &
./scripts/poor-mans-profiler.sh 10 > prof.txt
```

### Samply

```sh
cargo install samply
cargo build --profile=profiling
samply record ./target/release/yapall --signatures signatures.json jackson.bc
```

## Test

Running `cargo test` checks whether the pointer analysis correctly handles
various LLVM features. Running `lit tests/pointer/soundness` checks whether the
C test programs are compiling to the intended LLVM bitcode.

## Warnings

Certain warnings are disallowed in the CI build. You can reproduce the behavior
of the CI build by running `cargo check`, `cargo build`, or `cargo test` like
so:

```sh
env RUSTFLAGS="@$PWD/rustc-flags" cargo check
```

Using a flag file for this purpose achieves several objectives:

- It frictionlessly allows code with warnings during local development
- It makes it easy to reproduce the CI build process locally
- It makes it easy to maintain the list of warnings
- It [maintains forward-compatibility][anti-pat] with future rustc warnings
- It ensures the flags are consistent across all crates in the project

This flag file rejects all `rustc` warnings by default, as well as a subset of
[allowed-by-default lints][allowed-by-default]. The goal is to balance 
high-quality, maintainable code with not annoying developers.

To allow a lint in one spot, use:

```rust
#[allow(name_of_lint)]
```

To enable these warnings on a semi-permanent basis, create a [Cargo
configuration file][cargo-conf]:

```sh
mkdir .cargo
printf "[build]\nrustflags = [\"@${PWD}/rustc-flags\"]\n" > .cargo/config.toml
```

[allowed-by-default]: https://doc.rust-lang.org/rustc/lints/listing/allowed-by-default.html
[anti-pat]: https://rust-unofficial.github.io/patterns/anti_patterns/deny-warnings.html#denywarnings
