Build Optimized Rust Binary
ActionsTags
(2)A GitHub Action for building optimized, lightweight Rust binaries and C libraries.
Uses nightly Rust and nightly-only features to minimize binary size and maximize performance:
- Self-Built std: Smaller binaries, better optimizations.
- Abort on Panic: Smaller binaries. (Can be disabled)
- Profile Guided Optimization (PGO): Optimizes based on runtime usage patterns.
- Cross-Compilation: Via
cross-rs. - Tests and Coverage: Optional, via
devops-rust-test-and-coverageaction.
As a single job/step of a workflow:
build:
strategy:
matrix:
include:
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
use-pgo: true
use-cross: false
- os: windows-latest
target: x86_64-pc-windows-msvc
use-pgo: true
use-cross: false
- os: macos-latest
target: aarch64-apple-darwin
use-pgo: true
use-cross: false
- os: ubuntu-latest
target: aarch64-unknown-linux-gnu
use-pgo: false # no native runner
use-cross: true
runs-on: ${{ matrix.os }}
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Build Binary
uses: Reloaded-Project/devops-rust-lightweight-binary@v1
with:
target: ${{ matrix.target }}
crate-name: "my-crate"
use-pgo: ${{ matrix.use-pgo }}
use-cross: ${{ matrix.use-cross }}Tip
Adjust rust-project-path and workspace-path (if using cargo workspaces) if your project is not in the root folder ..
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 |
workspace-path |
No | . |
Workspace folder where target directory is. Uses rust-project-path if not set. |
build-library |
No | false |
Build a library instead of a binary. |
target |
Yes | The target platform for the Rust compiler | |
features |
No | '' |
Comma-separated list of features to include in the build |
artifact-prefix |
No | '' |
Prefix for artifact names. Combined with target/features to form final name (e.g., MyApp -> MyApp-linux-x64). If empty, no prefix is used. |
run-tests-and-coverage |
No | false |
Run tests and coverage using the devops-rust-test-and-coverage action. |
use-cache |
No | true |
Enable or disable the build cache using Swatinem/rust-cache. |
| Input | Required | Default | Description |
|---|---|---|---|
no-default-features |
No | false |
Do not include default features in the build |
rust-toolchain |
No | nightly |
The Rust toolchain to use. Can be nightly or a specific nightly version (e.g., nightly-2025-09-18). |
use-cross |
No | false |
Use cross-rs for building. If false, use cargo. |
| Input | Required | Default | Description |
|---|---|---|---|
use-pgo |
No | false |
Use Profile-Guided Optimization [PGO] to build the library. |
pgo-project-path |
No | . |
Path to the Rust project used for gathering PGO data. Can be same or separate project. |
pgo-benchmark-name |
No | 'my_benchmark' |
Benchmark name to use with PGO. |
abort-on-panic |
No | true |
Abort immediately on panic. If false, the default panic handler is used. |
size-optimized-std |
No | false |
Builds std with size optimizations, such as reduced core::fmt footprint. |
| Input | Required | Default | Description |
|---|---|---|---|
upload-artifacts |
No | true |
Upload the built artifacts as a GitHub Actions artifact |
upload-symbols-separately |
No | true |
Upload debug symbol files (.pdb, .dwp, .dSYM) as separate artifacts instead of bundling with main artifacts |
use-friendly-target-names |
No | true |
Transform target triples to user-friendly names (e.g., x86_64-unknown-linux-gnu -> linux-x64) in artifact names. |
artifact-name-exclude-features |
No | c-exports,bench,nightly |
Comma-separated list of features to exclude from artifact names. Features are still built but not included in artifact names. Set to empty string to include all. |
| Input | Required | Default | Description |
|---|---|---|---|
additional-rustflags |
No | '' |
Additional RUSTFLAGS to pass to the Rust compiler |
additional-rustc-args |
No | '' |
Additional arguments to pass directly to rustc |
additional-std-features |
No | `` | Specify extra build-std features. |
These parameters are only used when run-tests-and-coverage is enabled and are passed directly to the devops-rust-test-and-coverage action:
| Input | Required | Default | Description |
|---|---|---|---|
upload-coverage-to-codecov |
No | true |
Whether to upload coverage to Codecov |
codecov-token |
No | Codecov token for uploading coverage | |
use-tarpaulin |
No | true |
Whether to use Tarpaulin for code coverage. If false, only runs tests. |
use-binstall |
No | true |
Whether to use cargo-binstall for installing components like tarpaulin. If false, uses cargo install. |
install-binstall |
No | true |
Whether to install cargo-binstall. If false, assumes it is already available in the environment. |
additional-test-args |
No | '' |
Additional arguments passed directly to the cargo test command. |
additional-tarpaulin-args |
No | '' |
Additional arguments passed directly to the cargo tarpaulin command. |
codecov-flags |
No | 'unittests' |
Flags to pass to Codecov for organizing coverage reports. |
codecov-name |
No | 'codecov-umbrella' |
Custom defined name for the coverage upload. |
Note: The following parameters are used by both this action AND passed through to the test action: target, features, no-default-features, use-cross.
Note: Stable and beta toolchains are not supported due to required nightly features. Only nightly and specific nightly versions (e.g.,
nightly-2025-09-18) are supported.
PGO compiles and runs a benchmark (configured via pgo-benchmark-name and pgo-project-path) to collect runtime data, then uses that profile to optimize the final build. Keep the benchmark close to real usage patterns:
#[cfg(not(feature = "pgo"))]
{
// Regular benchmarks, unrealistic for profiling, exclude
bench_estimate(c);
bench_decompress(c);
}
#[cfg(feature = "pgo")]
{
// Realistic usage patterns for PGO
generate_pgo_data();
}PGO requires the target platform to match the host. With use-cross: true, cross-compilation may work:
target: aarch64-unknown-linux-gnu # x64 host to aarch64 simulated guest
use-pgo: true
use-cross: trueIf the process fails, your CI will fail, so experiment to find what works.
Set run-tests-and-coverage: true to run tests and generate coverage after the build.
This invokes devops-rust-test-and-coverage with the same configuration (target, features, use-cross, etc.).
- Tests run via
cargoorcross(based onuse-cross) - Coverage via Tarpaulin when
use-tarpaulin: true(ignored ifuse-cross: true)
Set build-library: true to build a library instead of a binary (equivalent to crate-type = ["cdylib", "staticlib"]).
Artifacts include static (.a, .lib) and dynamic (.so, .dll, .dylib) libraries depending on target.
Find more examples in the tests.
- 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
additional-rustc-args: --all-features- name: Build C Library with Specific Nightly
uses: Reloaded-Project/devops-rust-lightweight-binary@v1
with:
crate-name: my-crate
target: x86_64-unknown-linux-gnu
rust-toolchain: nightly-2025-09-18Tip
The best approach depends on whether your builds share the same settings.
When building multiple crates within a workspace with the same settings, use a single job. Shared dependencies are compiled once and reused:
- name: Build API Crate
uses: Reloaded-Project/devops-rust-lightweight-binary@v1
with:
rust-project-path: projects/api-crate
crate-name: api-crate
target: x86_64-unknown-linux-gnu
use-cache: true # first step: restore cache
install-binstall: true # default
- name: Build CLI Crate
uses: Reloaded-Project/devops-rust-lightweight-binary@v1
with:
rust-project-path: projects/cli-crate
crate-name: cli-crate
target: x86_64-unknown-linux-gnu
use-cache: false # subsequent steps: disable to avoid duplicate save
install-binstall: false # already installed aboveNote
Only enable use-cache on the first step. The cache is restored at the start and saved after the job completes.
Same applies to install-binstall - only install once per job.
When building crates with different settings, use separate jobs to avoid cache conflicts:
jobs:
build-standard:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: Reloaded-Project/devops-rust-lightweight-binary@v1
with:
crate-name: my-crate
target: x86_64-unknown-linux-gnu
features: ""
build-with-simd:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: Reloaded-Project/devops-rust-lightweight-binary@v1
with:
crate-name: my-crate
target: x86_64-unknown-linux-gnu
features: "simd,avx2"Building these in a single job would cause cache conflicts since both use the same target but different features.
After a successful run, the built artifacts will be available as a downloadable artifact in the GitHub Actions run.
Artifact names follow the pattern: {artifact-prefix}-{target}[-features] or {target}[-features] when no prefix is set.
| Scenario | Example Name |
|---|---|
| No prefix, friendly names | linux-x64, windows-arm64 |
With prefix MyApp |
MyApp-linux-x64, MyApp-windows-arm64 |
With features simd,avx2 |
linux-x64-simd,avx2 |
| With prefix and features | MyApp-linux-x64-simd,avx2 |
When use-friendly-target-names is enabled (default), the target triple is replaced with a
user-friendly platform identifier (e.g., x86_64-unknown-linux-gnu becomes linux-x64,
aarch64-apple-darwin becomes macos-arm64). Unmapped targets fall back to the raw target triple.
Use artifact-name-exclude-features to exclude specific features from artifact names while still building them.
This is useful when features are already distinguished by artifact-prefix (e.g., C library builds).
| Features | Exclude List | Resulting Suffix |
|---|---|---|
c-exports |
c-exports |
(none) |
c-exports,simd |
c-exports |
-simd |
foo,bar |
foo,bar |
(none) |
bar,foo |
foo,bar |
(none) |
The default exclusion is c-exports, which is commonly redundant for C library builds in Reloaded projects;
where often the prefix is something like c-library. To include all features in names, set to an empty string "".
When upload-symbols-separately is enabled (default), debug symbols are uploaded as separate artifacts
with a .symbols suffix:
- Main artifact:
MyApp-linux-x64 - Symbol artifact:
MyApp-linux-x64.symbols
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.
| Input | Required | Default | Description |
|---|---|---|---|
crate-name |
No | '' |
Name of the Rust crate/package. Used for cache key and artifact directory. |
The crate-name parameter is still used for:
- Cache key: When provided, it helps create unique cache keys for your builds
- Artifact directory: Used in the
ARTIFACT_OUT_DIRpath construction
However, using crate-name for artifact naming is deprecated. Please use artifact-prefix instead.
For backwards compatibility, if crate-name is set and artifact-prefix is not provided, the legacy
naming behaviour is used:
- Binary artifacts:
{crate-name}-{target}[-features] - Library artifacts:
C-Library-{crate-name}-{target}[-features]
A deprecation warning will appear in the workflow logs when this legacy behaviour is triggered.
Migration: Replace crate-name: my-crate with artifact-prefix: my-crate for binaries, or
artifact-prefix: C-Library-my-crate for libraries to maintain the same artifact names.
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.
Build Optimized Rust Binary is not certified by GitHub. It is provided by a third-party and is governed by separate terms of service, privacy policy, and support documentation.