Skip to content

Commit e5091c5

Browse files
committed
fix: cef engine: support multi-process and update guix instructions
1 parent bd4ac74 commit e5091c5

9 files changed

Lines changed: 108 additions & 50 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
target
2+
target-cef
23
default

README.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,17 @@ This library supports
2424
- litehtml requires `clang`/`libclang` for building `litehtml-sys`
2525
- Servo requires `fontconfig`, `make`, `cmake`, `clang` (recent version), and `nasm` at build time
2626
- CEF downloads the Chromium Embedded Framework binary (~200-300 MB) at build time; requires subprocess handling (see below)
27-
- CEF on Guix: use `manifest-cef.scm``guix shell -m manifest-cef.scm` then `eval "$(./cef-link-flags.sh)" && CC=gcc cargo run --example webview --no-default-features --features cef`
27+
- CEF on Guix: use `manifest-cef.scm` with FHS emulation:
28+
```sh
29+
guix shell --container --emulate-fhs --network \
30+
--share=$HOME/.cargo --share=$HOME/.cache \
31+
--expose=$XDG_RUNTIME_DIR --expose=/var/run/dbus \
32+
-m manifest-cef.scm -- sh -c \
33+
"XDG_RUNTIME_DIR=$XDG_RUNTIME_DIR WAYLAND_DISPLAY=$WAYLAND_DISPLAY \
34+
DBUS_SESSION_BUS_ADDRESS=$DBUS_SESSION_BUS_ADDRESS \
35+
CARGO_TARGET_DIR=target-cef LD_LIBRARY_PATH=/lib:/lib/nss CC=gcc \
36+
cargo run --example webview --no-default-features --features cef"
37+
```
2838

2939
#### examples:
3040

@@ -109,7 +119,7 @@ Blitz and litehtml are not full browsers — there's no JavaScript, and renderin
109119

110120
### CEF
111121

112-
- **Single-process mode** — runs all Chromium threads in one process (`--single-process`). CEF's multi-process model requires resources (`.pak`, `icudtl.dat`, GL libs) to be discoverable by subprocesses, which is fragile on non-FHS systems (Guix, Nix). Single-process avoids this. `cef_subprocess_check()` is still available for multi-process setups.
122+
- **Multi-process mode**CEF runs with standard multi-process architecture (renderer, GPU, utility subprocesses). On non-FHS systems (Guix, Nix), use an FHS-emulated container (`guix shell --container --emulate-fhs`) so subprocesses can find `.pak` resources, `icudtl.dat`, and shared libraries at standard paths. Call `cef_subprocess_check()` at the top of `main()`.
113123
- **Large runtime** — ships ~200-300 MB of Chromium binaries alongside your application.
114124
- **Not Rust-native** — C++ under the hood, Rust bindings via [cef-rs](https://github.com/tauri-apps/cef-rs).
115125
- **CEF binary download** — the `cef-dll-sys` build script downloads the CEF binary distribution at build time.

build.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,37 @@
11
fn main() {
22
println!("cargo:rerun-if-changed=build.rs");
33
println!("cargo:rerun-if-changed=Cargo.lock");
4+
5+
// When the cef feature is enabled, add the CEF distribution directory
6+
// to the binary's RPATH so libcef.so can be found at runtime without
7+
// requiring LD_LIBRARY_PATH.
8+
if std::env::var("CARGO_FEATURE_CEF").is_ok() {
9+
if let Ok(out_dir) = std::env::var("OUT_DIR") {
10+
let build_dir = std::path::Path::new(&out_dir)
11+
.ancestors()
12+
.find(|p| p.file_name().map_or(false, |n| n == "build"));
13+
14+
if let Some(build_dir) = build_dir {
15+
if let Ok(entries) = std::fs::read_dir(build_dir) {
16+
for entry in entries.flatten() {
17+
let name = entry.file_name();
18+
if name.to_string_lossy().starts_with("cef-dll-sys-") {
19+
let cef_dir = entry.path().join("out").join(format!(
20+
"cef_{}_{}",
21+
std::env::consts::OS,
22+
std::env::consts::ARCH
23+
));
24+
if cef_dir.exists() {
25+
println!(
26+
"cargo:rustc-link-arg=-Wl,-rpath,{}",
27+
cef_dir.display()
28+
);
29+
break;
30+
}
31+
}
32+
}
33+
}
34+
}
35+
}
36+
}
437
}

cef-link-flags.sh

Lines changed: 0 additions & 30 deletions
This file was deleted.

examples/embedded_webview.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ type Engine = iced_webview::Litehtml;
2323
static URL: &str = "https://docs.rs/iced/latest/iced/index.html";
2424

2525
fn main() -> iced::Result {
26+
#[cfg(feature = "cef")]
27+
if iced_webview::cef_subprocess_check() {
28+
return Ok(());
29+
}
30+
2631
iced::application(App::new, App::update, App::view)
2732
.title("An embedded web view")
2833
.subscription(App::subscription)

examples/multi_webview.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ static URL1: &str = "https://docs.rs/iced/latest/iced/index.html";
2727
static URL2: &str = "https://github.com/franzos/iced_webview_v2";
2828

2929
fn main() -> iced::Result {
30+
#[cfg(feature = "cef")]
31+
if iced_webview::cef_subprocess_check() {
32+
return Ok(());
33+
}
34+
3035
iced::application(App::new, App::update, App::view)
3136
.title("An multi webview application")
3237
.subscription(App::subscription)

examples/webview.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ type Engine = iced_webview::Litehtml;
1919
static URL: &str = "https://docs.rs/iced/latest/iced/index.html";
2020

2121
fn main() -> iced::Result {
22+
#[cfg(feature = "cef")]
23+
if iced_webview::cef_subprocess_check() {
24+
return Ok(());
25+
}
26+
2227
iced::application(App::new, App::update, App::view)
2328
.title("Web view")
2429
.subscription(App::subscription)

manifest-cef.scm

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,24 @@
1-
;; Guix manifest for building with the CEF engine.
1+
;; Guix manifest for building and running with the CEF engine.
22
;;
3-
;; CEF's libcef.so links against many system libraries (GTK, NSS, ALSA, etc.)
4-
;; that live in package-specific store paths. This manifest collects them and
5-
;; exposes their lib dirs via LIBRARY_PATH so the linker can resolve them.
3+
;; Uses --container --emulate-fhs to create an FHS-compatible environment
4+
;; so CEF subprocesses can find .pak resources, icudtl.dat, and shared
5+
;; libraries at standard paths (/usr/lib, /usr/share, etc.).
66
;;
7-
;; Usage:
8-
;; guix shell -m manifest-cef.scm
9-
;; eval "$(./cef-link-flags.sh)"
10-
;; CC=gcc cargo run --example webview --no-default-features --features cef
7+
;; Build and run:
8+
;;
9+
;; guix shell --container --emulate-fhs --network \
10+
;; --share=$HOME/.cargo --share=$HOME/.cache \
11+
;; --expose=$XDG_RUNTIME_DIR --expose=/var/run/dbus \
12+
;; -m manifest-cef.scm -- sh -c \
13+
;; "XDG_RUNTIME_DIR=$XDG_RUNTIME_DIR WAYLAND_DISPLAY=$WAYLAND_DISPLAY \
14+
;; DBUS_SESSION_BUS_ADDRESS=$DBUS_SESSION_BUS_ADDRESS \
15+
;; CARGO_TARGET_DIR=target-cef LD_LIBRARY_PATH=/lib:/lib/nss CC=gcc \
16+
;; cargo run --example webview --no-default-features --features cef"
17+
;;
18+
;; CARGO_TARGET_DIR — separate target dir; host-built binaries won't run
19+
;; inside the FHS container (different dynamic linker).
20+
;; LD_LIBRARY_PATH — gcc-toolchain's linker doesn't search /lib by default;
21+
;; NSS puts .so files in /lib/nss/.
1122

1223
(use-modules (guix packages)
1324
(guix search-paths)
@@ -16,6 +27,7 @@
1627
(gnu packages commencement)
1728
(gnu packages tls)
1829
(gnu packages base)
30+
(gnu packages bash)
1931
(gnu packages llvm)
2032
(gnu packages pkg-config)
2133
(gnu packages freedesktop)
@@ -55,6 +67,10 @@
5567
gdb
5668
openssl-with-dir
5769

70+
;; container essentials
71+
bash
72+
coreutils
73+
5874
;; shared deps (also in manifest.scm)
5975
wayland
6076
wayland-protocols

src/engines/cef_engine.rs

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ struct SharedState {
2727
scale_factor: f32,
2828
}
2929

30-
// -- CEF App handler (single-process + disable GPU for OSR) --
30+
// -- CEF App handler --
3131

3232
wrap_app! {
3333
struct OsrApp;
@@ -39,14 +39,22 @@ wrap_app! {
3939
command_line: Option<&mut CommandLine>,
4040
) {
4141
if let Some(cmd) = command_line {
42-
// Run everything in a single process. CEF's multi-process
43-
// model requires resources (.pak, icudtl.dat, GL libs) to
44-
// be discoverable by subprocesses, which is fragile on
45-
// non-FHS systems (Guix, Nix). Single-process avoids this.
46-
cmd.append_switch(Some(&CefString::from("single-process")));
47-
// Disable hardware GPU — OSR delivers pixels via on_paint.
42+
// CEF defaults to X11. When WAYLAND_DISPLAY is set, tell
43+
// Chromium's ozone layer to use the Wayland backend.
44+
if std::env::var("WAYLAND_DISPLAY").is_ok() {
45+
cmd.append_switch_with_value(
46+
Some(&CefString::from("ozone-platform")),
47+
Some(&CefString::from("wayland")),
48+
);
49+
}
50+
51+
// OSR delivers pixels via on_paint() — GPU compositing
52+
// inside CEF isn't needed. Disable it and run any
53+
// remaining GL calls in-process so the GPU subprocess
54+
// doesn't need real driver access (containers, Flatpak).
4855
cmd.append_switch(Some(&CefString::from("disable-gpu")));
4956
cmd.append_switch(Some(&CefString::from("disable-gpu-compositing")));
57+
cmd.append_switch(Some(&CefString::from("in-process-gpu")));
5058
}
5159
}
5260
}
@@ -195,9 +203,14 @@ struct CefView {
195203
///
196204
/// ## Subprocess requirement
197205
///
198-
/// CEF launches helper sub-processes using the same binary. Call
199-
/// [`cef_subprocess_check`] at the very top of `main()` — if it returns
200-
/// `true`, the process is a CEF subprocess and should exit immediately.
206+
/// CEF uses multi-process mode — helper sub-processes (renderer, GPU,
207+
/// utility) are spawned from the same binary. Call [`cef_subprocess_check`]
208+
/// at the very top of `main()` — if it returns `true`, the process is a
209+
/// CEF subprocess and should exit immediately.
210+
///
211+
/// On non-FHS systems (Guix, Nix), run inside an FHS-emulated container
212+
/// so subprocesses can discover `.pak` resources, `icudtl.dat`, and shared
213+
/// libraries at standard paths.
201214
///
202215
/// ```rust,ignore
203216
/// fn main() -> iced::Result {

0 commit comments

Comments
 (0)