Skip to content

build: reduce overall build times - #93

Merged
tycho merged 5 commits into
mainfrom
steven/faster-build
Jul 24, 2026
Merged

build: reduce overall build times#93
tycho merged 5 commits into
mainfrom
steven/faster-build

Conversation

@tycho

@tycho tycho commented Jul 24, 2026

Copy link
Copy Markdown
Member

This PR is a set of build-script (build.rs) improvements that make libscap-bindings compile faster and pull in far less on the host -- with the biggest real-world win being where this crate sits on the critical path of a larger build.

Why this matters beyond a standalone cargo build

The headline change drops the aws-lc-* build-dependencies (via reqwest -> ureq). In the protect build, aws-lc-sys (a heavy C library) was a critical-path dependency: it had to compile before libscap-bindings could finish, which in turn blocked everything downstream of libscap-bindings. So the payoff isn't just the ~1,500-line Cargo.lock shrink you see here -- it's a pipelining effect: removing aws-lc-* unblocks this crate and its dependents earlier in the graph, which a lone cargo build of libscap-bindings won't reveal.

Changes

  • Drop the async/aws-lc build-dep stack (reqwest -> ureq). The build script only needs one blocking HTTPS GET for the bpftool archive. reqwest dragged in tokio/hyper/quinn and (via rustls' default provider) aws-lc-rs + aws-lc-sys. Switching to ureq (rustls + ring, bundled webpki roots) removes aws-lc-sys from the build graph entirely. cargo audit over build-deps goes 8 -> 5 advisories. Download stays SHA256-verified.

  • Fetch only the pinned libscap commit instead of a full clone. Init an empty repo and fetch --depth=1 the pinned SHA (~4MB vs ~44MB, still content-addressed / cryptographically pinned). Clone phase ~5.8s -> ~1.4s cold, ~10x less transfer. Failed fetches now clean up so retries start fresh.

  • Route launcher-bypassing compiles through sccache; parallelize libbpf. The modern_bpf eBPF objects and the libbpf ExternalProject previously never saw CMAKE_C_COMPILER_LAUNCHER (and libbpf built -j1). Shim scripts now wrap clang/cc so those 191 compiles hit the cache, and libbpf builds -j$NUM_JOBS. cmake phase ~16.8s -> ~8s (warm sccache).

  • Overlap the bpftool download with the git fetch. These are independent network ops; the ~9.6MB bpftool download now runs on a background thread, hiding ~1s behind the fetch. Checksum verification unchanged.

  • Stop emitting the clang AST during bindgen. A leftover debugging aid that dumped the full AST to build output -- ~1.4s -> ~0.25s on the largest bindgen pass, and removes megabytes of noise. Generated bindings unchanged.

tycho added 5 commits July 23, 2026 17:46
The build script cloned the entire falcosecurity/libs repository (~44MB
of pack data) only to immediately check out one pinned SHA. Fetch just
that commit instead (~4MB): init an empty repo, `fetch --depth=1` the
pinned SHA, and detach onto FETCH_HEAD. Fetching by SHA is
content-addressed, so the checked-out tree is still cryptographically
pinned by LIBSCAP_CHECKOUT_SHA; this is also the pre-git-2.49 spelling
of `git clone --revision=<sha>`, which not all runners and cross images
ship yet.

A failed fetch now also removes the partially-initialized repo
directory, so a retry starts clean instead of building whatever
half-state a previous attempt left in OUT_DIR (the old code could even
build the wrong ref if the clone succeeded but the checkout failed).

Measured on my dev box (cross build inside protect): the clone phase of
the build script drops from ~5.8s to ~1.4s cold; the transfer shrinks
about 10x regardless of network conditions.

Signed-off-by: Steven Noonan <steven@edera.dev>
… libbpf

CMake-generated compile rules honor CMAKE_C_COMPILER_LAUNCHER
(sccache/ccache), but two libscap build steps never see it:

- the modern_bpf eBPF objects are compiled by ${MODERN_CLANG_EXE}
  inside add_custom_command rules, which don't apply launchers
- libbpf builds via an ExternalProject BUILD_COMMAND that invokes raw
  `make` with an unwrapped CC; raw `make` also can't inherit the
  jobserver, so libbpf built single-threaded ("jobserver unavailable:
  using -j1")

When a launcher is configured, write two one-line shim scripts into
OUT_DIR that exec the launcher around clang and cc, point
MODERN_CLANG_EXE at the clang shim (a user-provided MODERN_CLANG_EXE
still wins: the shim wraps it rather than replacing it), and patch the
checked-out libbpf.cmake BUILD_COMMAND to use `make -j$NUM_JOBS` with
CC set to the cc shim. The -j fix applies even without a launcher, and
if a future libscap bump changes the module text the patch degrades to
a cargo:warning instead of breaking the build.

Measured on my dev box (cross build inside protect, warm sccache):
sccache compile requests go from 124 to 320 for one cold build-script
run - the 191 previously-invisible libbpf and eBPF compiles now hit the
cache - taking the libbpf target from ~3.6s to ~1.3s, the eBPF objects
from ~5.4s to ~2.6s, and the whole cmake phase from ~16.8s to ~8s.  The
first build after this change pays one-time cache-population misses.

Signed-off-by: Steven Noonan <steven@edera.dev>
The bpftool release archive download (~9.6MB) ran serially after the
git fetch, but the two are independent network operations. Split
fetch_bpftool() into spawn_bpftool_download(), which starts the
download on a background thread (skipped when a previously downloaded
archive with a good checksum is already present), and
install_bpftool(), which lands the verified bytes and extracts the
binary after the fetch completes. Checksum verification is unchanged:
the archive is still validated against the pinned sha256 before
anything is written or extracted.

Measured on my dev machine (cross build inside protect): hides
essentially the whole ~1s bpftool download behind the git fetch on
a cold build-script run; more on slower networks.

Signed-off-by: Steven Noonan <steven@edera.dev>
The full bindings pass had emit_clang_ast() enabled, a bindgen
debugging aid that dumps the entire parsed clang AST for inc/libscap.h
to the build script's stdout. That's pure overhead in normal builds:
extra work in the largest of the three bindgen passes (~1.4s on my dev
box, versus ~0.25s for each of the two filtered passes) and megabytes
of noise captured into cargo's build output file. The generated
bindings are unaffected.

Signed-off-by: Steven Noonan <steven@edera.dev>
The build script only needs a single blocking HTTPS GET to fetch the
bpftool release, but reqwest dragged an entire async stack — tokio, hyper,
quinn — into build-dependencies, and since reqwest 0.13 defaults its rustls
provider to aws-lc-rs, the heavy aws-lc-sys C library too. That whole
subgraph was compiled on the host purely to run this build script.

Switch to ureq with rustls + ring and bundled webpki roots
(default-features off, "rustls" feature only). It is synchronous (no async
runtime), uses ring instead of aws-lc-rs (aws-lc-sys leaves the
build-dependency graph entirely), and bundles webpki roots so certificate
validation does not depend on a system trust store in the build
environment. The download remains SHA256-verified against the pinned
per-arch checksum, so TLS here is defense in depth.

ureq's read_to_vec() caps the body at 10 MiB by default and the bpftool
tarball is already 10.0 MiB, so the limit is raised to 64 MiB explicitly.

cargo audit over the build-dependency tree improves from 8 advisories to 5:
the quinn-proto (x2) and rand advisories go away with the async/QUIC stack,
and the remaining bytes + rustls-webpki advisories are unchanged from the
reqwest tree (same rustls 0.23 stack) and awaiting upstream fixes.

Signed-off-by: Steven Noonan <steven@edera.dev>
@tycho
tycho marked this pull request as ready for review July 24, 2026 08:23
@tycho
tycho requested review from azenla and bleggett July 24, 2026 08:23
Comment thread Cargo.lock

@bleggett bleggett Jul 24, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

jesus, no kidding did that reduce the dep count. ty!

@tycho
tycho merged commit 540ee53 into main Jul 24, 2026
5 checks passed
@tycho
tycho deleted the steven/faster-build branch July 24, 2026 15:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants