Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,14 @@ jobs:
submodules: true
- uses: dtolnay/rust-toolchain@nightly
with:
components: rust-src
targets: ${{ matrix.target }}
- name: Check the tag matches the crate version
shell: bash
run: |
version=$(cargo metadata --no-deps --format-version 1 | jq -r '.packages[] | select(.name == "enable-loopback") | .version')
test "v$version" = "$GITHUB_REF_NAME" || { echo "tag $GITHUB_REF_NAME does not match crate version $version"; exit 1; }
- run: cargo build --release --locked --target ${{ matrix.target }}
- run: cargo build --release --locked --target ${{ matrix.target }} -Z build-std=std,panic_abort -Z build-std-features=optimize_for_size
- name: Name the asset and its checksum
shell: bash
run: |
Expand Down
8 changes: 8 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,11 @@ repository = "https://github.com/libnyanpasu/enable-loopback.git"

[profile.dev]
debug = "line-tables-only"

[profile.release]
opt-level = "z"
lto = "fat"
codegen-units = 1
# Native GUI callbacks cannot unwind across the Windows ABI boundary.
panic = "abort"
strip = "symbols"
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,23 @@ cargo run -- --lang zh-cn
If a global Cargo configuration uses a compiler wrapper, set `RUSTC_WRAPPER=`
to bypass it for these commands. Do not change the global configuration.

For a size-optimized release, use the same command as the release workflow:

```sh
cargo build --release --locked --target x86_64-pc-windows-msvc \
-Z build-std=std,panic_abort -Z build-std-features=optimize_for_size
```

Use `aarch64-pc-windows-msvc` for arm64. This requires nightly and `rust-src`
(included in `rust-toolchain.toml`). The executable is in
`target/<target>/release/enableLoopback.exe`. A plain `cargo build --release`
also uses the size profile, but keeps the precompiled standard library and is
slightly larger. Release builds use full LTO, one codegen unit, size optimization,
stripped symbols, and abort on panic; development builds retain unwinding and
line tables. Recoverable application errors still use the existing error dialogs.

See [release size measurements](docs/release-size.md) for the measured tradeoffs.

`enableLoopback.exe [--lang CODE]` opens the GUI. Supported languages:
`en`, `zh-cn`, `zh-tw`, `ja`, `ko`, `ru`; otherwise the system language is used,
with English as the fallback. `manual` skips automatic refresh and `-registry`
Expand Down
56 changes: 56 additions & 0 deletions docs/release-size.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Release executable size

Measured on 2026-10-21 with the locked dependencies, windows-rs submodule
`75c2364d1ba98d4b1fb9a9f28e2a9b0fc067e6e6`, and
`rustc 1.100.0-nightly (a36d05efa 2026-09-09)`, targeting Windows x64 MSVC.
Sizes are the actual uncompressed EXE, including its icon and manifest.

| Configuration | Bytes | MiB | Reduction from baseline |
| --- | ---: | ---: | ---: |
| Original default release profile | 3,802,624 | 3.63 | — |
| Full LTO, one codegen unit, `s`, abort, strip | 1,773,056 | 1.69 | 53.4% |
| Full LTO, one codegen unit, `z`, abort, strip | 1,442,304 | 1.38 | 62.1% |
| Same `z` profile, size-optimized standard library | 1,302,016 | 1.24 | 65.8% |

`z` saves 330,752 bytes compared with `s` in this application. Rebuilding the
standard library saves another 140,288 bytes. These measurements select the
release profile and the release workflow's `build-std` options; they do not
establish an absolute lower bound. Compiler updates and architectures can change
the result.

The original PE contained 2,680,320 bytes of code, 894,976 bytes of read-only data,
and only 55,808 bytes of icon/manifest resources. Optimizing generated code
therefore provided much more benefit than changing the artwork. The implementation
keeps all six languages, the GUI, CLI, and existing runtime deployment model.
No executable packer is used.

Full LTO trades build time for size. Size optimization may trade throughput for
size; interactive behavior was checked, but this is not a performance benchmark.
`panic = "abort"` terminates on programming panics instead of unwinding; it does
not change ordinary `Result` error handling. Native GUI callbacks already cannot
unwind across the Windows ABI. Tests retain the test harness's unwind behavior.
Symbol stripping reduces postmortem debugging information. The additional
standard-library optimization requires nightly's unstable `build-std` support
and `rust-src`; the normal release command remains available without it.

Validation:

- All 52 application tests passed in both development and release profiles.
- `cargo clippy --all-targets --locked -- -D warnings` and application formatting
checks passed.
- ARM64 compilation reached the final link, but this machine has only x64/x86
MSVC build tools and no ARM64 linker. Its EXE size and runtime behavior remain
unverified locally; the release workflow retains both architecture targets.
- The smallest x64 EXE loaded all 136 real AppContainers. Native GUI checks
exercised checkbox edits and counter updates, refresh cancellation and refresh,
dirty-close confirmation and cancellation, and clean close. Firewall exemptions
were compared before/after and were unchanged; Save was never invoked.
- The repository's existing GUI smoke script has stale sort-header expectations
and requests a SelectionItemPattern unavailable on this runtime's rows; the
original baseline fails those checks too. A temporary adapter under
`target/size-study` used the current header names, omitted native selection/sort
assertions, and waited for dialog dismissal animations. Selection and sorting
are covered by the application tests, but were not verified through native UIA.

Reproduce the smallest build with the command in the README. Intermediate x64
EXEs from this investigation are retained locally in `target/size-study/`.
2 changes: 1 addition & 1 deletion rust-toolchain.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[toolchain]
channel = "nightly"
components = ["rustfmt", "clippy"]
components = ["rustfmt", "clippy", "rust-src"]