Rex is a small Rust project that packs a target binary together with its dynamic libraries, extra binaries and files into a single executable. The runtime extracts the embedded payload at execution time and runs the target program using a suitable loader (glibc or musl) when available.
- Language: Rust
- License: MIT
- Packaging output: a single executable file containing the runtime + compressed
.tarpayload appended to it - Bundle internal directory name convention:
<target_binary_name>_bundle/
main.rs— CLI entrypoint. Detects whether the executable is a runtime (contains a payload) or is being run as the builder. Usesclapfor the CLI.generator.rs— The packer/generator that creates the staging directory, copies binaries/libs/files, creates a tar and compresses it (zstd), and appends the payload and metadata to the runtime executable.runtime.rs— The runtime that scans the running executable for the metadata marker extracts the payload to a temporary directory, adjusts environment variables and executes the embedded binary.
- Rust toolchain (stable). Tested with modern Rust toolchains.
- Unix-like environment (Linux) for
ldddependency detection and loader handling. lddshould be available for best automatic dependency detection.
cargo build --release
# binary: target/release/rexRun rex (the built binary) as a generator to create a bundle:
# minimal: specify target binary
./rex --target-binary ./myapp
# typical full command
./rex \
--target-binary ./myapp \
--compression-level 19 \
--extra-libs /usr/lib/x86_64-linux-gnu/libexample.so \
--extra-bins ./helpers ./tools \
--additional-files config.json README.mdThe generator will produce myapp.Rex (target file base name + .Rex).
When the generated bundle runs and contains payload, the runtime inspects arguments. The runtime supports:
--rex-help— prints a short help message.--rex-extract— extracts the embedded bundle into the current working directory.
If no runtime flag is given, the runtime will extract to a temporary directory and execute the embedded binary automatically.
Inside the compressed .tar payload the generator creates a directory named
<target>_bundle with this layout:
<target>_bundle/
├─ bins/ # helper/extras copied here
├─ libs/ # shared libraries, and loader (ld-linux or ld-musl)
├─ <target> # the target binary copied at the bundle root
└─ [other files] # additional files or folders copied to the bundle root
The runtime expects exactly this layout and looks up the active bundle
using the target name provided in the appended metadata.
- The generator attempts to copy a system loader into
libs/(ld-linux or ld-musl) if found on the build machine. - The runtime chooses the loader from the extracted
libs/(ld-linux-x86-64.so.2orld-musl-x86_64.so.1) and invokes it with--library-path <libs> <target>so the target binary runs using the bundled libraries. - The
PATHenvironment variable is temporarily prefixed with the extractedbins/directory so helper tools inbinscan be resolved.
- The generator uses
lddoutput to detect dynamic dependencies automatically; iflddis unavailable or fails, it warns and proceeds (you can pass--extra-libsto include libraries manually). - The generator copies the system loader into
libs/(if found) to improve portability of the bundle. - Temporary files used during packaging are cleaned up after the bundle is produced.
- The runtime extracts to a temporary directory by default, but
--rex-extractwrites to the current working directory and prints progress messages.
# 1) Build the tool
cargo build --release
# 2) Package your app
./target/release/rex --target-binary ./target/release/myapp --compression-level 19
# 3) Run the bundle
./myapp.RexOr extract files manually to inspect contents:
./myapp.Rex --rex-extract
# this extracts into the current directory into 'myapp_bundle/' (or similar) depending on the target nameThis project is licensed under the MIT License. See the LICENSE file for more details.
