version_check

A zero-dependency Rust crate for checking the installed or running rustc's version, release channel, and release date directly from build scripts.

Library
Cargo
v0.9.5
54stars
MIT OR Apache-2.0

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
28/100Needs Attention
Development Activity0
Maintenance0
Community40
Maturity60
Momentum12

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
74/100Good
Architecture78
Code Quality82
Innovation70
Learning Curve65

version_check is a tiny, dependency-free Rust crate that answers one narrow but frequently-needed question: what version, release channel, and release date is the rustc compiler that will build this crate? It works by shelling out to rustc --verbose --version (respecting the RUSTC environment variable), parsing the output with plain string operations, and exposing the result through simple boolean-returning helpers like is_min_version(), is_min_date(), and is_feature_flaggable(), or through the Version, Channel, and Date structs directly via triple().

Because it adds zero transitive dependencies and compiles all the way back to Rust 1.0.0, it’s a common choice as a [build-dependencies] entry in build.rs scripts that need to conditionally enable a cfg flag based on compiler capabilities — for example, gating a question_mark_operator feature or a nightly-only API behind a minimum rustc version check, without pulling in a heavier crate like rustc_version.

What You Get

  • One-line boolean checks — is_min_version(), is_max_version(), is_exact_version() for semantic version comparisons against the running rustc
  • Date-based checks — is_min_date(), is_max_date(), is_exact_date() for comparing against the compiler’s release date (YYYY-MM-DD)
  • Channel detection — Channel::read() reports whether the compiler is stable, beta, nightly, or dev, with is_feature_flaggable() and supports_feature() helpers for nightly-only feature gating
  • Batched reads — triple() fetches Version, Channel, and Date in a single rustc invocation instead of three separate process spawns
  • Zero dependencies and Rust 1.0.0+ compatibility, keeping it safe to add to any crate’s build-dependency graph without bloating the dependency tree

Common Use Cases

  • Gating a cfg flag in build.rs when a feature (like the question-mark operator) is only available above a specific rustc version
  • Detecting whether the current toolchain is nightly/dev so a crate can opt into unstable feature flags only when they’re actually supported
  • Checking whether the installed rustc predates a known compiler bug or missing stdlib API before enabling a workaround
  • Emitting compiler-version-gated rustc-cfg directives from build scripts of crates that need to support a wide range of Rust versions

Under The Hood

Architecture version_check is a flat, single-purpose Rust crate structured as four modules (lib.rs, version.rs, channel.rs, date.rs) with no external dependencies. lib.rs owns the public API surface (triple(), is_min_version(), is_min_date(), supports_feature(), etc.) and the shared rustc-invocation logic, which shells out to rustc —version —verbose via std::process::Command and parses stdout with plain string splitting and pattern matching rather than a formal parser. version.rs, channel.rs, and date.rs each define one small struct (Version packs major/minor/patch into a single comparable u64) with a read() constructor that reuses the shared shell-out call and a parse() function for caller-supplied strings. Modules are wired together purely through pub use re-exports at the crate root rather than trait abstractions, and the failure mode is uniform: every step returns Option, so a missing or unparseable rustc invocation collapses to None rather than panicking. The one point of fragility is the shared shell-out parser — if rustc’s —verbose —version output format changes unexpectedly, every public function silently degrades to None rather than erroring loudly.

Tech Stack The crate declares no dependencies in Cargo.toml and targets compatibility back to Rust 1.0.0, which shows in code choices like the deprecated trim_right/trim_left methods guarded behind an explicit #![allow(deprecated)]. It has no runtime dependencies and is consumed almost exclusively as a build-dependency from another crate’s build.rs, where its only integration surface is the OS process and stdout text of the rustc binary (or the path given via the RUSTC environment variable). Testing uses Rust’s built-in #[test] harness with no external test framework, and the crate ships fixture files under static/ capturing real rustc —version output across dozens of historical stable releases for its compatibility tests. CI runs via GitHub Actions, with a legacy Travis config retained alongside it.

Code Quality Tests live in a #[cfg(test)] module using declarative macros to table-drive parsing assertions against dozens of real rustc version strings, including edge cases like warning-prefixed output and distro-patched version strings, plus a dedicated compatibility test that replays fixtures for every stable Rust release from 1.0 through 1.50. Error handling is uniformly Option-based — every fallible step (process spawn, UTF-8 decode, string parse) collapses through chained .ok()/.and_then() calls into None, so there’s no panic path in the public API. Public functions carry extensive doc-comments with runnable example code for nearly every entry point, and naming is consistent throughout. The #![allow(deprecated)] annotation is a deliberate compatibility tradeoff for supporting ancient Rust versions, not a sign of neglect.

API Design The public API is built around one narrow calling convention — build.rs scripts — and optimizes hard for it: every function returns a simple bool wrapped in Option, so a caller can write a single line like rustc::is_min_version("1.13.0").unwrap_or(false) with no setup and no transitive dependencies pulled into the build graph. The triple() function reads version, channel, and date in one process spawn instead of three redundant ones for callers who need more than one attribute. Doc comments front-load runnable examples for every function, and the crate-level documentation includes an explicit caveat section on the risks of gating on unstable compiler features — genuinely useful API-level guidance rather than a bare reference. The design isn’t algorithmically novel, but committing to zero dependencies and one small conceptual surface (Version/Channel/Date plus boolean helpers) is a well-executed choice for this niche.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search