GitHub Action
Build Optimized Rust Binary
This is a GitHub Action that can be used to build an optimized, lightweight binary (or C library) from a Rust project.
This action is used to build binaries with the following properties:
- Self-Built std: Reduces binary size and improves optimizations.
- Abort on Panic: Reduces binary size. Can be disabled if needed.
- Profile Guided Optimization (PGO): Improves performance by optimizing based on usage patterns.
- Cross-Compilation: Supports cross-compilation using
cross-rs
. - Nightly Rust: Uses the nightly Rust toolchain for building and running.
- Tests and Coverage: Optionally run tests and generate coverage reports using the
devops-rust-test-and-coverage
action.
It can be used to build both binaries and C libraries.
As a single job/step of a workflow:
test-binary-build:
strategy:
matrix:
include:
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
use-pgo: true
use-cross: false
use-tarpaulin: true
- os: ubuntu-latest
target: i686-unknown-linux-gnu
use-pgo: true
use-cross: false
use-tarpaulin: true
- os: ubuntu-latest
target: aarch64-unknown-linux-gnu
use-pgo: false # no native runner
use-cross: true
use-tarpaulin: true
- os: ubuntu-latest
target: armv7-unknown-linux-gnueabihf
use-pgo: false # no native runner
use-cross: true
use-tarpaulin: true
- os: windows-latest
target: x86_64-pc-windows-msvc
use-pgo: true
use-cross: false
use-tarpaulin: true
- os: windows-latest
target: i686-pc-windows-msvc
use-pgo: true
use-cross: false
use-tarpaulin: true
# no native github actions runner or cross-rs image
#- os: windows-latest
# target: aarch64-pc-windows-msvc
# use-pgo: false # no native runner
# use-cross: false
# use-tarpaulin: true
- os: macos-13 # x86
target: x86_64-apple-darwin
use-pgo: true
use-cross: false
use-tarpaulin: true
- os: macos-14 # M1
target: aarch64-apple-darwin
use-pgo: true
use-cross: false
use-tarpaulin: true
runs-on: ${{ matrix.os }}
steps:
- name: Checkout Test Repository
uses: actions/checkout@v4
with:
repository: Sewer56/prs-rs
ref: d08599ed5473616f57d57a0966939e1a5dbda9b4
- name: Test Binary Build
uses: Reloaded-Project/devops-rust-lightweight-binary@v1
with:
target: ${{ matrix.target }}
use-pgo: ${{ matrix.use-pgo }}
use-cross: ${{ matrix.use-cross }}
use-tarpaulin: ${{ matrix.use-tarpaulin }}
rust-project-path: "tools/cli/"
crate-name: "prs-rs-cli"
upload-artifacts: false
run-tests-and-coverage: true
To use this action in your own repository:
- Create a new workflow file (e.g.,
.github/workflows/build-c-library.yml
) in your repository. - Copy the example usage job from above into the new workflow file.
- Customize the input parameters as needed for your project.
Input | Required | Default | Description |
---|---|---|---|
rust-project-path |
No | . |
Path to the Rust project |
pgo-project-path |
No | . |
Path to the Rust project used for gathering PGO data. Can be same or separate project. |
crate-name |
Yes | Name of the Rust crate (used to determine file name) | |
target |
Yes | The target platform for the Rust compiler | |
features |
No | '' |
Comma-separated list of features to include in the build |
no-default-features |
No | false |
Do not include default features in the build |
use-pgo |
No | false |
Use Profile-Guided Optimization [PGO] to build the library. |
pgo-benchmark-name |
No | 'my_benchmark' |
Benchmark name to use with PGO. |
use-cross |
No | false |
Use cross-rs for building. If false, use cargo. |
additional-rustflags |
No | '' |
Additional RUSTFLAGS to pass to the Rust compiler |
upload-artifacts |
No | true |
Upload the built artifacts as a GitHub Actions artifact |
abort-on-panic |
No | true |
Abort immediately on panic. If false, the default panic handler is used. |
build-library |
No | false |
Build a library instead of a binary. |
run-tests-and-coverage |
No | false |
Run tests and coverage using the devops-rust-test-and-coverage action. |
upload-coverage-to-codecov |
No | true |
Uploads coverage to codecov if run-tests-and-coverage is enabled. |
size-optimized-std |
No | false |
Builds std with size optimizations, such as reduced core::fmt footprint. |
additional-std-features |
No | `` | Specify extra build-std features. |
use-tarpaulin |
No | true |
Use tarpaulin for code coverage. If false, code coverage will be disabled. |
Profile-Guided Optimization works by compiling and executing a benchmark whose name and project
can be defined by pgo-benchmark-name
and pgo-project-path
respectively. So you should strive
to keep the benchmark as close to the final usage of your application as possible.
A benchmark for PGO can be defined as follows:
// Regular benchmarks, not PGO
#[cfg(not(feature = "pgo"))]
{
bench_estimate(c);
bench_decompress(c);
bench_compress_file(c);
bench_create_dict(c);
}
// Benchmark with realistic usage patterns for PGO.
#[cfg(feature = "pgo")]
{
generate_pgo_data();
}
Then said profile is used to build the final version of your application.
For PGO to work, the target
platform must be the same as the host that generated the profiling
data. Sometimes you can get away with using cross
to achieve this, for example:
# Host is x86-linux but this seems to work just a-ok!
target: aarch64-unknown-linux-gnu # x64 host to to aarch64 simulated guest
use-pgo: true
use-cross: true
If the process fails, your CI will fail, so do experiment.
To run tests and generate coverage reports as part of the build process, set the
run-tests-and-coverage
input to true
.
This will invoke the devops-rust-test-and-coverage action after the build
step, using the same configuration as the build (e.g., target
, features
, use-cross
, etc.).
The devops-rust-test-and-coverage
action will run tests using either cargo
or cross
,
depending on the use-cross
input. If use-cross
is false
and use-tarpaulin
is true
, it
will also generate a coverage report using Tarpaulin and upload it to Codecov (if upload-coverage
is true
).
If cross
is enabled, use-tarpaulin
is ignored.
To build a library instead of a binary, set the build-library
input to true
.
This is equivalent to setting crate-type = ["cdylib", "staticlib"]
in Cargo.toml
.
When building a library, the generated artifacts will include static libraries (.a
, .lib
)
and dynamic libraries (.so
, .dll
, .dylib
) depending on the target platform.
Find more examples in the tests.
- name: Build C Library
uses: Reloaded-Project/devops-rust-lightweight-binary@v1
with:
rust-project-path: ./rust-project
pgo-project-path: ./pgo-project
crate-name: my-crate
target: x86_64-unknown-linux-gnu
- name: Build C Library
uses: Reloaded-Project/devops-rust-lightweight-binary@v1
with:
crate-name: my-crate
target: x86_64-unknown-linux-gnu
use-cross: true
- name: Build C Library
uses: Reloaded-Project/devops-rust-lightweight-binary@v1
with:
crate-name: my-crate
target: x86_64-unknown-linux-gnu
additional-rustflags: -C opt-level=3
After a successful run, the built artifacts will be available as a downloadable artifact in the GitHub Actions run.
For binary builds, the artifact will be named ${{ inputs.crate-name }}-${{ inputs.target }}-${{ inputs.features }}
.
For library builds, the artifact will be named C-Library-${{ inputs.target }}-${{ inputs.features }}
.
To access the artifacts:
- Navigate to the Actions tab in your repository.
- Click on the workflow run that built the artifacts.
- In the "Artifacts" section, you will find the generated artifacts, which you can download.
Building C libraries from Rust projects can be a complex process, especially when considering different target platforms, compiler flags, and optimizations like PGO.
This action simplifies the process by providing a configurable and reusable workflow that handles the building of C libraries from Rust projects.
Contributions are welcome! If you encounter any issues or have suggestions for improvements, please open an issue or submit a pull request in this repository.
This project is licensed under the MIT License. See the LICENSE file for details.