Skip to content

Commit 6ed3ba3

Browse files
committed
Add executable no_std example
Uses QEMU and the UEFI crate to create a no_std compatible example which can run in CI.
1 parent faed8a0 commit 6ed3ba3

6 files changed

Lines changed: 137 additions & 0 deletions

File tree

.github/workflows/main.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,24 @@ jobs:
125125
# Testing the `no_std` confirmation is done above.
126126
- run: cargo build ${{ matrix.flags }} --target ${{ matrix.target }} --no-default-features --features rust_backend
127127

128+
no_std_example:
129+
name: no_std (Example)
130+
runs-on: ubuntu-latest
131+
strategy:
132+
matrix:
133+
target: [x86_64-unknown-uefi, x86_64-unknown-linux-gnu]
134+
steps:
135+
- uses: actions/checkout@v4
136+
- name: Install Rust
137+
run: rustup update nightly && rustup default nightly
138+
- name: Install Target
139+
run: rustup target add ${{ matrix.target }}
140+
- name: Install QEMU
141+
run: sudo apt update && sudo apt install qemu-system qemu-utils ovmf -y && sudo chmod +x ./examples/no_std/run.uefi.sh
142+
if: matrix.target == 'x86_64-unknown-uefi'
143+
- run: cargo run --target ${{ matrix.target }} --features qemu
144+
working-directory: ./examples/no_std
145+
128146
minimum:
129147
name: Minimum Rust compiler
130148
runs-on: ${{ matrix.os }}

examples/no_std/.cargo/config.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[target.'cfg(all(target_arch = "x86_64", target_os = "uefi"))']
2+
rustflags = ["--cfg", "flate2_unstable_nightly_alloc_io"]
3+
runner = "./run.uefi.sh"

examples/no_std/Cargo.toml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
[package]
2+
name = "flate2_example_no_std"
3+
version = "0.1.0"
4+
edition = "2024"
5+
publish = false
6+
7+
[features]
8+
qemu = ["dep:qemu-exit", "uefi/qemu"]
9+
10+
[dependencies]
11+
log = "0.4"
12+
flate2 = { path = "../../", default-features = false, features = ["rust_backend"] }
13+
14+
[target.'cfg(target_os = "uefi")'.dependencies]
15+
uefi = { version = "0.39.0", features = ["logger", "panic_handler", "global_allocator"] }
16+
qemu-exit = { version = "4", optional = true }
17+
18+
[lints.rust.unexpected_cfgs]
19+
level = "warn"
20+
priority = 0
21+
check-cfg = [
22+
## Enables `no_std` support by using `core::error` and `alloc::io`.
23+
## Requires at least nightly 2026-07-19.
24+
"cfg(flate2_unstable_nightly_alloc_io)",
25+
]

examples/no_std/run.uefi.sh

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
mkdir -p target/esp/efi/boot
2+
cp $1 target/esp/efi/boot/bootx64.efi
3+
qemu-system-x86_64 -device isa-debug-exit,iobase=0xf4,iosize=0x04 \
4+
-drive if=pflash,format=raw,readonly=on,file=/usr/share/OVMF/OVMF_CODE_4M.fd \
5+
-drive if=pflash,format=raw,readonly=on,file=/usr/share/OVMF/OVMF_VARS_4M.fd \
6+
-drive format=raw,file=fat:rw:target/esp \
7+
--nographic
8+
if [ $? -ne 123 ]; then
9+
exit $?
10+
else
11+
exit 0
12+
fi

examples/no_std/src/lib.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#![no_std]
2+
#![cfg_attr(flate2_unstable_nightly_alloc_io, feature(alloc_io))]
3+
4+
extern crate alloc;
5+
6+
cfg_select! {
7+
flate2_unstable_nightly_alloc_io => {
8+
use alloc::io;
9+
use log::info as println;
10+
}
11+
_ => {
12+
extern crate std;
13+
use std::io;
14+
use std::println;
15+
}
16+
}
17+
18+
use alloc::string::String;
19+
use alloc::vec::Vec;
20+
use io::prelude::*;
21+
22+
use flate2::write::GzEncoder;
23+
use flate2::{read, Compression};
24+
25+
// Compress a sample string and print it after transformation.
26+
pub fn main() {
27+
let input = "Hello World";
28+
29+
let mut e = GzEncoder::new(Vec::new(), Compression::default());
30+
e.write_all(input.as_bytes()).unwrap();
31+
let bytes = e.finish().unwrap();
32+
println!("Compressed '{input}' into: {bytes:?}");
33+
34+
let output = decode_reader(bytes).unwrap();
35+
println!("Decompressed into: {output}");
36+
37+
assert_eq!(input, &output);
38+
}
39+
40+
// Uncompresses a Gz-encoded vector of bytes and returns a string or error
41+
// Here &[u8] implements the Read trait
42+
fn decode_reader(bytes: Vec<u8>) -> io::Result<String> {
43+
let mut gz = read::GzDecoder::new(&bytes[..]);
44+
let mut s = String::new();
45+
gz.read_to_string(&mut s)?;
46+
Ok(s)
47+
}

examples/no_std/src/main.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#![cfg_attr(target_os = "uefi", no_main)]
2+
#![no_std]
3+
4+
cfg_select! {
5+
target_os = "uefi" => {
6+
#[uefi::entry]
7+
fn main() -> uefi::Status {
8+
uefi::helpers::init().unwrap();
9+
10+
flate2_example_no_std::main();
11+
12+
cfg_select! {
13+
not(feature = "qemu") => {
14+
uefi::Status::SUCCESS
15+
}
16+
any(target_arch = "x86", target_arch = "x86_64") => {
17+
use qemu_exit::QEMUExit;
18+
let qemu_exit_handle = unsafe { qemu_exit::X86::new(0xF4, 123) };
19+
qemu_exit_handle.exit_success();
20+
}
21+
_ => unimplemented!()
22+
}
23+
}
24+
}
25+
_ => {
26+
extern crate std;
27+
28+
fn main() {
29+
flate2_example_no_std::main();
30+
}
31+
}
32+
}

0 commit comments

Comments
 (0)