Use cargo check -Zbuild-std instead of cargo miri setup

This should be more reliable (not building with `cfg(miri)` and more
accurately knowing whether a target supports std).

Known targets affected by this change:
- cygwin: should now build since it only breaks in `cfg(miri)`
- i686-pc-nto-qnx700: officially doesn't support std

closes #4
This commit is contained in:
nora 2025-07-05 14:21:26 +02:00
parent 0be7b4c981
commit df486c20f8
7 changed files with 85 additions and 68 deletions

View file

@ -61,7 +61,11 @@ pub async fn background_builder(db: Db) -> Result<()> {
loop {
if let Err(err) = background_builder_inner(&db).await {
error!("error in background builder: {err}");
error!(
?err,
"error in background builder, waiting for an hour before retrying: {err}"
);
tokio::time::sleep(Duration::from_secs(3600)).await;
}
}
}
@ -145,20 +149,7 @@ async fn install_toolchain(toolchain: &Toolchain, mode: BuildMode) -> Result<()>
if !result.status.success() {
bail!("rustup failed: {:?}", String::from_utf8(result.stderr));
}
if mode == BuildMode::MiriStd {
let result = Command::new("rustup")
.arg("component")
.arg("add")
.arg("miri")
.arg("--toolchain")
.arg(&toolchain.0)
.output()
.await
.wrap_err("failed to spawn rustup")?;
if !result.status.success() {
bail!("rustup failed: {:?}", String::from_utf8(result.stderr));
}
}
Ok(())
}
@ -289,23 +280,24 @@ async fn build_target(
) -> Result<BuildResult> {
let mut rustflags = None;
let output = match mode {
let init = Command::new("cargo")
.args(["init", "--lib", "--name", "target-test"])
.current_dir(tmpdir)
.output()
.await
.wrap_err("spawning cargo init")?;
if !init.status.success() {
bail!("init failed: {}", String::from_utf8(init.stderr)?);
}
let librs = tmpdir.join("src").join("lib.rs");
std::fs::write(&librs, "#![no_std]\n")
.wrap_err_with(|| format!("writing to {}", librs.display()))?;
let mut cmd = Command::new("cargo");
match mode {
BuildMode::Core => {
let init = Command::new("cargo")
.args(["init", "--lib", "--name", "target-test"])
.current_dir(tmpdir)
.output()
.await
.wrap_err("spawning cargo init")?;
if !init.status.success() {
bail!("init failed: {}", String::from_utf8(init.stderr)?);
}
let librs = tmpdir.join("src").join("lib.rs");
std::fs::write(&librs, "#![no_std]\n")
.wrap_err_with(|| format!("writing to {}", librs.display()))?;
let mut cmd = Command::new("cargo");
cmd.arg(format!("+{toolchain}"))
.args(["build", "-Zbuild-std=core", "--release"])
.args(["--target", target]);
@ -319,23 +311,20 @@ async fn build_target(
cmd.env("RUSTFLAGS", &flags);
rustflags = Some(flags);
}
cmd.current_dir(tmpdir)
.output()
.await
.wrap_err("spawning cargo build")?
}
BuildMode::MiriStd => Command::new("cargo")
.arg(format!("+{toolchain}"))
.args(["miri", "setup"])
.args(["--target", target])
.current_dir(tmpdir)
.env("MIRI_SYSROOT", tmpdir)
.output()
.await
.wrap_err("spawning cargo build")?,
BuildMode::Std => {
cmd.arg(format!("+{toolchain}"))
.args(["check", "-Zbuild-std"])
.args(["--target", target]);
}
};
let output = cmd
.current_dir(tmpdir)
.output()
.await
.wrap_err("spawning cargo build")?;
let stderr = String::from_utf8(output.stderr).wrap_err("cargo stderr utf8")?;
let status = if output.status.success() {

View file

@ -14,26 +14,25 @@ pub struct Db {
pub static MIGRATOR: Migrator = sqlx::migrate!();
#[derive(Debug, Clone, Copy, sqlx::Type, Serialize, Deserialize, PartialEq, Eq, Hash)]
#[derive(Debug, Clone, Copy, sqlx::Type, Serialize, PartialEq, Eq, Hash)]
#[sqlx(rename_all = "kebab-case")]
#[serde(rename_all = "kebab-case")]
pub enum BuildMode {
/// `-Zbuild-std=core`
/// `build -Zbuild-std=core`
Core,
/// `cargo miri setup`
MiriStd,
/// `check -Zbuild-std`
Std,
}
impl Display for BuildMode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Core => f.write_str("core"),
Self::MiriStd => f.write_str("miri-std"),
Self::Std => f.write_str("std"),
}
}
}
#[derive(sqlx::FromRow, Serialize, Deserialize, Clone)]
#[derive(sqlx::FromRow, Serialize, Clone)]
pub struct BuildInfo {
pub nightly: String,
pub target: String,
@ -41,7 +40,7 @@ pub struct BuildInfo {
pub mode: BuildMode,
}
#[derive(Clone, sqlx::FromRow, Serialize, Deserialize)]
#[derive(Clone, sqlx::FromRow, Serialize)]
pub struct FullBuildInfo {
pub nightly: String,
pub target: String,

View file

@ -44,7 +44,7 @@ impl Nightlies {
self.all
.iter()
.flat_map(|nightly| [(nightly, BuildMode::Core), (nightly, BuildMode::MiriStd)])
.flat_map(|nightly| [(nightly, BuildMode::Core), (nightly, BuildMode::Std)])
.find(|(nightly, mode)| {
!already_finished.contains(&FinishedNightly {
nightly: (*nightly).to_owned(),

View file

@ -34,11 +34,33 @@ pub async fn webserver(db: Db) -> Result<()> {
axum::serve(listener, app).await.wrap_err("failed to serve")
}
#[derive(Debug, Clone, Copy)]
pub struct LegacyBuildMode(BuildMode);
impl<'de> serde::Deserialize<'de> for LegacyBuildMode {
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
match s.as_str() {
"core" => Ok(LegacyBuildMode(BuildMode::Core)),
"std" => Ok(LegacyBuildMode(BuildMode::Std)),
// This mode used to be called "miri-std" but it has been renamed to "std" using build-std.
// Allow the old value to keep links working but map it to std.
"miri-std" => Ok(LegacyBuildMode(BuildMode::Std)),
_ => Err(serde::de::Error::custom(format!(
"invalid build mode, expected 'core', 'std', or 'miri-std'"
))),
}
}
}
#[derive(Deserialize)]
struct BuildQuery {
nightly: String,
target: String,
mode: Option<BuildMode>,
mode: Option<LegacyBuildMode>,
}
async fn web_build(State(state): State<AppState>, Query(query): Query<BuildQuery>) -> Response {
@ -63,7 +85,7 @@ async fn web_build(State(state): State<AppState>, Query(query): Query<BuildQuery
.build_status_full(
&query.nightly,
&query.target,
query.mode.unwrap_or(BuildMode::Core),
query.mode.map(|mode| mode.0).unwrap_or(BuildMode::Core),
)
.await
{
@ -132,8 +154,8 @@ async fn web_target(State(state): State<AppState>, Query(query): Query<TargetQue
.max_by_key(|elem| elem.nightly.clone());
let status = match (latest_core, latest_miri) {
(Some(core), Some(miri)) => {
if core.status == Status::Error || miri.status == Status::Error {
(Some(core), Some(std)) => {
if core.status == Status::Error || std.status == Status::Error {
Status::Error
} else {
Status::Pass
@ -150,7 +172,7 @@ async fn web_target(State(state): State<AppState>, Query(query): Query<TargetQue
let v = builds_grouped.entry(build.nightly.clone()).or_default();
match build.mode {
BuildMode::Core => v.0 = Some(build),
BuildMode::MiriStd => v.1 = Some(build),
BuildMode::Std => v.1 = Some(build),
}
}
@ -213,7 +235,7 @@ async fn web_nightly(State(state): State<AppState>, Query(query): Query<NightlyQ
let v = builds_grouped.entry(build.target.clone()).or_default();
match build.mode {
BuildMode::Core => v.0 = Some(build.clone()),
BuildMode::MiriStd => v.1 = Some(build.clone()),
BuildMode::Std => v.1 = Some(build.clone()),
}
}
@ -223,7 +245,7 @@ async fn web_nightly(State(state): State<AppState>, Query(query): Query<NightlyQ
if build.status == Status::Error {
match build.mode {
BuildMode::Core => core_failures += 1,
BuildMode::MiriStd => std_failures += 1,
BuildMode::Std => std_failures += 1,
}
}
}
@ -244,7 +266,7 @@ async fn web_nightly(State(state): State<AppState>, Query(query): Query<NightlyQ
.and_then(|info| info.broken_error.clone());
let std_broken = info
.iter()
.find(|info| info.mode == BuildMode::MiriStd && info.is_broken)
.find(|info| info.mode == BuildMode::Std && info.is_broken)
.and_then(|info| info.broken_error.clone());
let page = NightlyPage {