From cb0628ba2149c0efb15726705983ccf57a073f38 Mon Sep 17 00:00:00 2001 From: xintaofei Date: Wed, 21 Oct 2026 10:20:53 +0800 Subject: [PATCH 1/3] ci(test): build the lib's unit tests on their own first on macOS The macOS runners have 3 cores and 7 GB of memory, and cargo test compiled codeg_lib twice at once: the rlib the bins and integration tests link, and the lib's own unit-test build, each several GB on its own. The desktop and server cells spent most of their time in swap, compiling for about 47 and 25 minutes against 8 and 4 on Linux. On macOS those two cells now build the unit tests first with cargo test --no-run, so the cargo test that follows finds them fresh and compiles the rlib alone. What gets tested is unchanged. --- .github/workflows/test.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6f6b778478..ad43c67806 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -87,6 +87,9 @@ jobs: # under `tests/`. Without the flag those items are physically # uncompiled, so integration tests would fail to link. cargo_args: "--features test-utils" + # macOS builds the lib's unit tests on their own first; see + # "Unit-test build on its own (macOS)". + lib_test_args: "--features test-utils --lib" # Desktop clippy must lint integration tests too, so it picks up # `--all-targets`. test-utils is already on, so tests compile. clippy_args: "--all-targets --features test-utils" @@ -96,6 +99,7 @@ jobs: # integration tests for `cargo test`, so `test-utils` is not # required here. cargo_args: "--no-default-features --features server-bin --bin codeg-server --lib" + lib_test_args: "--no-default-features --features server-bin --lib" # Server clippy intentionally skips `--all-targets`: integration # tests are already linted in the desktop cells, and pulling # them in here would force `test-utils` (a test-only feature) @@ -146,6 +150,21 @@ jobs: mkdir -p out printf '\n' > out/index.html + - name: Unit-test build on its own (macOS) + # The macOS runners have 3 cores and 7 GB of memory. `cargo test` + # compiles codeg_lib twice, the rlib that the bins and integration + # tests link and the lib's own unit-test build, each several GB on its + # own; side by side they push the desktop and server cells deep into + # swap. With the unit tests built first, the `cargo test` below finds + # them fresh and compiles the rlib alone. It has to be a `cargo test` + # build: only test builds turn on the dev-dependencies' features + # (tokio's `test-util`), so a lib from `cargo build` is not one + # `cargo test` reuses. The cli cell builds only the unit tests, and + # Linux and Windows fit both at once. + if: runner.os == 'macOS' && matrix.lib_test_args + working-directory: src-tauri + run: cargo test ${{ matrix.lib_test_args }} --no-run + - name: cargo test # Windows desktop test binaries link the Tauri runtime and can fail at # process load on GitHub-hosted runners before Rust tests start. Keep From 08b97779dba584b912358268dff811ffe4cfe8ce Mon Sep 17 00:00:00 2001 From: xintaofei Date: Wed, 21 Oct 2026 11:46:29 +0800 Subject: [PATCH 2/3] ci(test): build the unit tests first only in the macOS server cell In this PR's first run the macOS server job took 15.6 minutes instead of 30, but the desktop job got slower, 62 minutes instead of 59: its cargo test built the unit tests again. Tauri's generate_context! writes its embedded assets into the build script's out dir during the crate's first compile, after that compile started, so the next cargo run takes them for changes, and a CI job always starts without them. Alone, the desktop unit-test build still took 18 minutes, so that cell is back to how it was. --- .github/workflows/test.yml | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ad43c67806..11f8e7e596 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -87,9 +87,6 @@ jobs: # under `tests/`. Without the flag those items are physically # uncompiled, so integration tests would fail to link. cargo_args: "--features test-utils" - # macOS builds the lib's unit tests on their own first; see - # "Unit-test build on its own (macOS)". - lib_test_args: "--features test-utils --lib" # Desktop clippy must lint integration tests too, so it picks up # `--all-targets`. test-utils is already on, so tests compile. clippy_args: "--all-targets --features test-utils" @@ -99,6 +96,8 @@ jobs: # integration tests for `cargo test`, so `test-utils` is not # required here. cargo_args: "--no-default-features --features server-bin --bin codeg-server --lib" + # macOS builds the lib's unit tests on their own first; see + # "Unit-test build on its own (macOS)". lib_test_args: "--no-default-features --features server-bin --lib" # Server clippy intentionally skips `--all-targets`: integration # tests are already linted in the desktop cells, and pulling @@ -152,15 +151,20 @@ jobs: - name: Unit-test build on its own (macOS) # The macOS runners have 3 cores and 7 GB of memory. `cargo test` - # compiles codeg_lib twice, the rlib that the bins and integration - # tests link and the lib's own unit-test build, each several GB on its - # own; side by side they push the desktop and server cells deep into - # swap. With the unit tests built first, the `cargo test` below finds - # them fresh and compiles the rlib alone. It has to be a `cargo test` - # build: only test builds turn on the dev-dependencies' features - # (tokio's `test-util`), so a lib from `cargo build` is not one - # `cargo test` reuses. The cli cell builds only the unit tests, and - # Linux and Windows fit both at once. + # compiles codeg_lib twice, the rlib that the bins link and the lib's + # own unit-test build, each several GB on its own; side by side they + # push the server cell deep into swap. With the unit tests built + # first, the `cargo test` below finds them fresh and compiles the + # rlib alone. It has to be a `cargo test` build: only test builds turn + # on the dev-dependencies' features (tokio's `test-util`), so a lib + # from `cargo build` is not one `cargo test` reuses. + # + # Not the desktop cell. Tauri's `generate_context!` writes its + # embedded assets into the build script's out dir during the crate's + # first compile, after that compile started, so the next cargo run + # takes them for changes and builds the unit tests again. Alone, the + # desktop unit-test build still took 18 minutes. The cli cell builds + # only the unit tests, and Linux and Windows fit both at once. if: runner.os == 'macOS' && matrix.lib_test_args working-directory: src-tauri run: cargo test ${{ matrix.lib_test_args }} --no-run From a1f93e7dc1c96c18195de839f14393d5f3f1c852 Mon Sep 17 00:00:00 2001 From: xintaofei Date: Wed, 21 Oct 2026 11:46:29 +0800 Subject: [PATCH 3/3] fix(build): stop rewriting sidecar placeholders on every build ensure_sidecar_placeholder watched each sidecar path and wrote the 0-byte placeholder again on every run. Cargo counts a watched file as changed when it is newer than the start of the build script's last run, so wherever the sidecars were placeholders (CI, a fresh clone, a worktree that runs cargo directly), every cargo invocation reran the script and rebuilt every target of the crate, with nothing changed. An existing placeholder is now left alone, and a new one is dated back to 1970. The warning still shows on every build: cargo replays it when the script does not rerun. --- src-tauri/build.rs | 61 +++++++++++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 25 deletions(-) diff --git a/src-tauri/build.rs b/src-tauri/build.rs index 83bad86789..e8c175198f 100644 --- a/src-tauri/build.rs +++ b/src-tauri/build.rs @@ -73,11 +73,20 @@ fn fingerprint_helper_sources() { /// /// If you ever bypass those wrappers (e.g. invoking the Tauri CLI directly /// without beforeBuildCommand) you'd ship the placeholder, so emit a -/// cargo:warning that surfaces in any compile log to make that loud. +/// cargo:warning that surfaces in any compile log to make that loud. Cargo +/// replays it on builds that do not rerun this script. +/// +/// The placeholder is watched (`rerun-if-changed`), so that the real sidecar +/// landing reruns this script, and cargo counts a watched file as changed +/// when it is newer than the start of the script's last run. A placeholder +/// that already exists is therefore left alone, and a new one is dated back +/// to 1970: writing it during the run would make the next build rerun the +/// script, and rebuild every target of the crate after it, every time. #[cfg(feature = "tauri-runtime")] fn ensure_sidecar_placeholder() { use std::fs; use std::path::PathBuf; + use std::time::SystemTime; let triple = std::env::var("TARGET").unwrap_or_default(); if triple.is_empty() { @@ -95,32 +104,34 @@ fn ensure_sidecar_placeholder() { println!("cargo:rerun-if-changed={}", path.display()); - let needs_placeholder = match fs::metadata(&path) { - Ok(meta) => meta.len() == 0, - Err(_) => true, - }; - - if needs_placeholder { - if let Err(e) = fs::create_dir_all(&dir) { - panic!("failed to create {}: {e}", dir.display()); - } - if let Err(e) = fs::write(&path, b"") { - panic!( - "failed to write sidecar placeholder {}: {e}", - path.display() - ); - } - #[cfg(unix)] - { - use std::os::unix::fs::PermissionsExt; - let _ = fs::set_permissions(&path, fs::Permissions::from_mode(0o755)); + match fs::metadata(&path) { + Ok(meta) if meta.len() > 0 => continue, + Ok(_) => {} + Err(_) => { + if let Err(e) = fs::create_dir_all(&dir) { + panic!("failed to create {}: {e}", dir.display()); + } + let placeholder = match fs::File::create(&path) { + Ok(file) => file, + Err(e) => panic!( + "failed to write sidecar placeholder {}: {e}", + path.display() + ), + }; + // Should this fail, the next build reruns the script once. + let _ = placeholder.set_modified(SystemTime::UNIX_EPOCH); + #[cfg(unix)] + { + use std::os::unix::fs::PermissionsExt; + let _ = fs::set_permissions(&path, fs::Permissions::from_mode(0o755)); + } } - println!( - "cargo:warning={name} sidecar missing at {}; wrote 0-byte placeholder. \ - Run `pnpm tauri:prepare-sidecars` before `tauri build` to ship a working binary.", - path.display() - ); } + println!( + "cargo:warning={name} sidecar at {} is a 0-byte placeholder. \ + Run `pnpm tauri:prepare-sidecars` before `tauri build` to ship a working binary.", + path.display() + ); } }