Problem
The icp-dev-env-rust image cannot build Rust canisters that have C/C++ FFI dependencies (e.g. secp256k1, ring, openssl) when cross-compiling to wasm32-unknown-unknown.
The root cause is that the cc Rust crate — used internally by secp256k1-sys and similar — selects clang as the C compiler when targeting wasm32-unknown-unknown. gcc has no wasm32 backend, so clang is required. The current image has neither clang nor llvm-ar installed.
Current Dockerfile
FROM rust:1.95.0-slim-bookworm
RUN apt-get -yq update && apt-get -yq upgrade && apt-get -yqq install --no-install-recommends \
curl ca-certificates git jq make libdbus-1-3 && \
apt-get autoremove -y && apt-get clean && rm -rf /var/lib/apt/lists/*
# ^^^^^^^^^^^^^^^^^^^
# Package lists are wiped after install (standard slim image practice).
# Any subsequent apt-get install in CI requires apt-get update first.
RUN rustup target add wasm32-unknown-unknown
Observed error
When running cargo build --target wasm32-unknown-unknown --release inside the container for any crate with a C dependency (bitcoin, secp256k1, ring, etc.):
error occurred in cc-rs: failed to find tool "clang": No such file or directory (os error 2)
Important: The @dfinity/rust icp-cli recipe runs cargo build --target wasm32-unknown-unknown --release verbatim with no C toolchain setup. So icp build and icp deploy fail identically for affected canisters.
Real-world impact
Discovered while migrating rust/threshold-schnorr in dfinity/examples to icp-cli. The canister uses bitcoin = "0.32" (pulls in secp256k1-sys). Neither cargo build nor icp build/icp deploy work in the container without clang.
Affected: any canister using bitcoin, secp256k1, k256, p256, ring, or any crate with a C build script targeting wasm32.
Current workaround
Add an explicit step before any build in affected CI workflows:
- name: Install clang
run: apt-get update && apt-get install -y --no-install-recommends clang
apt-get update is required because the slim image wipes /var/lib/apt/lists/*. This adds ~30-60 s per CI job and must be repeated in every workflow.
Proposed fix
Add clang to the apt install step in rust/Dockerfile:
RUN apt-get -yq update && apt-get -yq upgrade && apt-get -yqq install --no-install-recommends \
curl ca-certificates git jq make libdbus-1-3 clang && \
apt-get autoremove -y && apt-get clean && rm -rf /var/lib/apt/lists/*
On Debian Bookworm, clang installs the current default LLVM release and creates /usr/bin/clang. No version pinning needed.
Tradeoff: ~80 MB image size increase. Once in the image, no per-workflow overhead, and all cargo and icp-cli workflows work uniformly for any Rust canister.
Problem
The
icp-dev-env-rustimage cannot build Rust canisters that have C/C++ FFI dependencies (e.g.secp256k1,ring,openssl) when cross-compiling towasm32-unknown-unknown.The root cause is that the
ccRust crate — used internally bysecp256k1-sysand similar — selects clang as the C compiler when targetingwasm32-unknown-unknown. gcc has no wasm32 backend, so clang is required. The current image has neitherclangnorllvm-arinstalled.Current Dockerfile
Observed error
When running
cargo build --target wasm32-unknown-unknown --releaseinside the container for any crate with a C dependency (bitcoin,secp256k1,ring, etc.):Important: The
@dfinity/rusticp-cli recipe runscargo build --target wasm32-unknown-unknown --releaseverbatim with no C toolchain setup. Soicp buildandicp deployfail identically for affected canisters.Real-world impact
Discovered while migrating
rust/threshold-schnorrindfinity/examplesto icp-cli. The canister usesbitcoin = "0.32"(pulls insecp256k1-sys). Neithercargo buildnoricp build/icp deploywork in the container without clang.Affected: any canister using
bitcoin,secp256k1,k256,p256,ring, or any crate with a C build script targeting wasm32.Current workaround
Add an explicit step before any build in affected CI workflows:
apt-get updateis required because the slim image wipes/var/lib/apt/lists/*. This adds ~30-60 s per CI job and must be repeated in every workflow.Proposed fix
Add
clangto the apt install step inrust/Dockerfile:RUN apt-get -yq update && apt-get -yq upgrade && apt-get -yqq install --no-install-recommends \ curl ca-certificates git jq make libdbus-1-3 clang && \ apt-get autoremove -y && apt-get clean && rm -rf /var/lib/apt/lists/*On Debian Bookworm,
clanginstalls the current default LLVM release and creates/usr/bin/clang. No version pinning needed.Tradeoff: ~80 MB image size increase. Once in the image, no per-workflow overhead, and all cargo and icp-cli workflows work uniformly for any Rust canister.