A single-file, self-extracting executable packer for Windows. It bundles a folder
of files into one .exe that, when run, decompresses everything to a temporary
directory, launches a configured entry point, waits for it to finish, and cleans up
after itself.
Typical use: ship an application plus all its loose dependencies (DLLs, data files,
a setup script, etc.) as a single portable .exe.
The project builds two binaries from one crate:
| Binary | Source | Role |
|---|---|---|
pack |
src/bin/pack.rs | Compresses packer_files/ into data.bin. |
stub |
src/main.rs | The self-extractor. Embeds data.bin and runs it. |
The build is a two-step process because the stub embeds the payload at compile time:
- Pack —
packwalks the input directory, brotli-compresses every file in parallel (with an MD5 digest per file), and writes them intodata.binin the binary format documented in src/format.rs. - Compile —
stubpulls indata.binviainclude_bytes!, so it must be built afterdata.binexists. At runtime the stub verifies each file's MD5, extracts to%TEMP%\exe_packer_run, launches the entry point, waits for it to close, and then removes the temp directory once no extracted files are still locked.
The final .exe is renamed to <name>.exe from the config and requests
administrator elevation (set in build.rs).
- Windows (uses the Win32 manifest,
cmd, andwinres— this is Windows-only). - Rust toolchain with the
x86_64-pc-windows-msvctarget (install via rustup). assets/logo.ico(optional) — build.rs embeds this as the exe icon. If it's missing, the build generates a plain placeholder icon automatically (and prints a warning), so a fresh clone builds without extra setup. Drop in your ownassets/logo.icofor a custom icon.
-
Create the input folder and drop in everything you want to bundle:
packer_files/ run.exe some.dll data/config.json -
(Optional) Add an icon at
assets/logo.ico. If you skip this, a placeholder icon is generated automatically at build time. -
Configure packer.toml:
name = "Application" # output exe name + version info + SmartScreen name entry_point = "run.exe" # the file (relative to packer_files/) to launch brotli_level = 11 # 0-11, higher = smaller + slower input_dir = "packer_files" output = "data.bin" show_console = true # true = show a window, false = run hidden (GUI apps) powershell = "windows" # host for a .ps1 entry point: "windows" (5.1) or "pwsh" (7+)
-
Build. Run the interactive menu:
build.bator directly:
powershell -ExecutionPolicy Bypass -File build.ps1Choose Full Build to pack and compile in one go. The finished
Application.exe(named aftername) is written to the project root.
If you'd rather skip the menu:
cargo run --bin pack # step 1: writes data.bin
cargo build --release --bin stub # step 2: compiles the self-extractorThe stub lands at target/release/stub.exe; rename/copy it as you like.
build.ps1 provides a small keyboard-driven menu:
- Build Type — Full Build / Pack Only / Compile Only
- Profile — Release / Dev
- Clean — Build / Clean + Build
- C show config, E edit config, F open
packer_files, R reset name/entry_point/show_console, Q quit
All settings live in packer.toml:
| Key | Default | Meaning |
|---|---|---|
name |
Application |
Output exe filename, embedded product/version info. |
entry_point |
run.exe |
File launched after extraction (relative to input_dir). Can be an .exe, .bat, or .ps1. |
brotli_level |
11 |
Brotli quality, 0–11. |
input_dir |
packer_files |
Folder whose contents get bundled. |
output |
data.bin |
Intermediate payload path. |
show_console |
true |
true shows a terminal window (CLI apps/scripts); false runs the entry point hidden with no window (GUI apps/scripts). |
powershell |
windows |
Which host runs a .ps1 entry point: windows = Windows PowerShell 5.1 (powershell.exe), pwsh = PowerShell 7+ (pwsh.exe). Ignored for .exe/.bat. |
.exe— launched directly..bat/.cmd— run throughcmd..ps1— run through<host> -ExecutionPolicy Bypass -File, so PowerShell scripts work as a first-class entry point (double-clicking a.ps1normally opens an editor instead of running it — the stub handles this for you). Thepowershellsetting picks the host:windowsfor Windows PowerShell 5.1 orpwshfor PowerShell 7+. Usepwshif your script relies on 7+ syntax or modules — but notepwsh.exeisn't installed by default, so the target machine must have it.
Use show_console = false for a .ps1 (or .exe) that puts up its own GUI, so no
PowerShell/console window flashes behind it. Keep it true for console scripts whose
output you want to see. Because this setting is baked into the stub at compile time,
changing it requires recompiling (Full Build or Compile Only).
- The stub (the extractor itself) always runs hidden and requires
administrator elevation. Whether the launched entry point shows a window is
controlled by
show_console. - Extraction target:
%TEMP%\exe_packer_run. - A log is written to
%TEMP%\exe_packer_stub.logon every run — check it first if a packed exe misbehaves (it records extraction, the resolved entry point, passed arguments, exit code, and cleanup). - Arguments passed to the packed exe are forwarded to the entry point.
- Cleanup waits (polling up to 12 hours) until no extracted
.exe/.dll/.sysfiles are still locked, so the temp dir isn't removed out from under a running app.
src/main.rs stub / self-extractor (the runtime)
src/bin/pack.rs packer (builds data.bin)
src/format.rs shared data.bin binary format + parser
build.rs embeds icon, version info, admin manifest
build.ps1 interactive build menu
build.bat launches build.ps1
packer.toml configuration
pack_bin.py reference Python packer (extra: partial/merge/list modes)
pack_bin.py is a standalone Python implementation of the same format. It isn't part
of the Rust build, but it's handy for inspecting a bin (python pack_bin.py --list data.bin) or for advanced workflows like caching dependencies separately and merging
partials.
packer_files/, assets/, and data.bin are gitignored — they're
user-supplied payload, not source. To produce a working packed exe you'll:
- create
packer_files/with at least one file, and - run a pack (or a Full Build) to generate
data.bin.
assets/logo.ico is optional — if absent, a placeholder icon is generated at build
time. A Full Build does both the pack and the compile in one step.