Files
Lucas Fernandes NogueiraandLucas Nogueira a7a4451b19 feat(sys): support cross-compiling to Windows with cargo-xwin (#462)
* feat(sys): support cross-compiling to Windows with cargo-xwin

Building `cef-dll-sys` for `x86_64-pc-windows-msvc` from a Linux host with
cargo-xwin failed while compiling `libcef_dll_wrapper` with clang-cl, for
four reasons that are now handled in the build script:

- CEF's CMake clears `CMAKE_CXX_FLAGS` for the Ninja generator, dropping
  the toolchain's `--target` and `/imsvc` include paths. They are now passed
  through `CEF_C_COMPILER_FLAGS`/`CEF_CXX_COMPILER_FLAGS` instead, which CEF
  appends after its own flags.
- clang-cl reports diagnostics that MSVC doesn't (`/MP` is unsupported,
  `-Wmissing-field-initializers`, `-Wundefined-var-template`) and CEF's `/WX`
  turned them into errors. Those are silenced and `/WX-` is appended.
- The Windows SDK import libraries were merged into the wrapper archive
  through `CMAKE_STATIC_LINKER_FLAGS`, which llvm-lib can't do because it
  rejects the XFG hash map member of current import libraries. They are
  now emitted as `cargo::rustc-link-lib` directives for the final link.
- The SDK expects case-insensitive header lookups (`Softpub.h` vs
  `SoftPub.h`). Mismatched headers get a correctly-cased copy in an extra
  include directory under `OUT_DIR`.

The `cc` crate is used to detect clang-cl and to read the target CXXFLAGS,
so this is a no-op for native MSVC builds. A CI job cross-compiles the
`cefsimple` example on ubuntu-latest to keep this working.

* fix(sys): join clang-cl options that take a separate argument

cargo-xwin 0.23 exports the SDK include paths as `/imsvc <dir>` (two
tokens) where 0.19 used `/imsvc<dir>`. CMake de-duplicates compile
options, so every repeated `/imsvc` after the first was dropped and the
bare paths were passed to clang-cl as additional source files:

    clang-cl: error: cannot specify '/Fo...' when compiling multiple source files

Join such option/value pairs into a single token before handing the flags
to CMake, and only add the clang-cl specific flags that aren't already
present so de-duplication has nothing left to remove.

* ci: use LLVM 20 for the Windows cross-compile job

The MSVC STL headers that cargo-xwin downloads now refuse compilers older
than Clang 19 (STL1000), and ubuntu-latest ships Clang 18. Install LLVM 20
from apt.llvm.org and put it first on PATH: cargo-xwin symlinks its
`clang-cl` to the `clang` found there, so only the SDK directory is cached.

* cleanup

---------

Co-authored-by: Lucas Nogueira <lucas@crabnebula.dev>
2026-09-14 10:09:51 -03:00

134 lines
4.9 KiB
Markdown

# cef-rs
Use CEF in Rust.
## Supported Targets
| Target | Linux | macOS | Windows |
| ------ | ----- | ----- | ------- |
| x86_64 | ✅ | ✅ | ✅ |
| ARM64 | ✅ | ✅ | ✅ |
## Usage
### Nix (on Linux)
If you are using Nix on Linux with the `nixpkgs` channel configured, you can take advantage of the `cef-binary` package to share the CEF binaries across your system. Just set the `NIX_CEF_BINARY` environment variable before running any of these `cargo` commands.
```sh
export NIX_CEF_BINARY=1
```
You can still run `export-cef-dir` and set the `CEF_PATH` environment variable if you prefer, e.g., for build output caching, but it is not necessary. If you combine `NIX_CEF_BINARY` with `export-cef-dir`, even `export-cef-dir` will use Nix instead of directly downloading the CEF binaries.
### Install Shared CEF Binaries
This step is optional, but it will make all other builds of the `cef` crate much faster (when not using `NIX_CEF_BINARY`). If you don't do this, the `cef-dll-sys` crate `build.rs` script will download and extract the same files under its `OUT_DIR` directory. You should repeat this step each time you upgrade to a new version of the `cef` crate.
#### Linux or macOS:
```sh
cargo run -p export-cef-dir -- --force $HOME/.local/share/cef
```
#### Windows (using PowerShell)
```pwsh
cargo run -p export-cef-dir -- --force $env:USERPROFILE/.local/share/cef
```
### Set Environment Variables
#### Linux
```sh
export CEF_PATH="$HOME/.local/share/cef"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$CEF_PATH"
```
#### macOS
```sh
export CEF_PATH="$HOME/.local/share/cef"
export DYLD_FALLBACK_LIBRARY_PATH="$DYLD_FALLBACK_LIBRARY_PATH:$CEF_PATH:$CEF_PATH/Chromium Embedded Framework.framework/Libraries"
```
#### Windows (using PowerShell)
```pwsh
$env:CEF_PATH="$env:USERPROFILE/.local/share/cef"
$env:PATH="$env:PATH;$env:CEF_PATH"
```
### Run the `cefsimple` Example
This command should work with each platform:
```sh
cargo run --bin bundle-cef-app -- cefsimple -o target/bundle
```
You can configure the name of the macOS helper in the `Cargo.toml` file, as well as a resource directory that will be copied into the bundle in a platform-appropriate location:
```toml
[package.metadata.cef.bundle]
helper_name = "cefsimple_helper"
resources_path = "resources"
```
#### Linux
There's an extra `--release` flag to build a much smaller bundle on Linux:
```sh
cargo run --bin bundle-cef-app -- cefsimple -o target/bundle --release
./target/bundle/cefsimple.exe
```
#### macOS
The macOS utility creates an application bundle directory at the target location, you can run it with the `open` command:
```sh
cargo run --bin bundle-cef-app -- cefsimple -o target/bundle
open target/bundle/cefsimple.app
```
On macOS, the `bundle-cef-app` utility also supports several additional bundle options, most of which default to the name of the application (e.g. `cefsimple`):
```
Usage: bundle-cef-app [OPTIONS] <NAME>
Arguments:
<NAME>
Options:
-o, --output <OUTPUT>
-i, --identifier <IDENTIFIER>
-d, --display-name <DISPLAY_NAME>
-r, --region <REGION> [default: English]
-v, --version <VERSION> [default: 1.0.0]
-h, --help Print help
```
#### Windows (using PowerShell)
The Windows utility supports the `--release` flag, but it makes much less difference in the binary size than on Linux. It also does not copy the resources directory to the bundle, because the preferred mechanism on Windows is to link binary resources directly into the executable.
However, the utility will emit an executable manifest file, and if the `sandbox` feature is enabled, it will build the DLL (cdylib) target instead of the executable (bin) target, and copy that with a renamed `bootstrap.exe` file to the bundle directory, so you can run it from there directly:
```pwsh
cargo run --bin bundle-cef-app -- cefsimple -o ./target/bundle
./target/bundle/cefsimple.exe
```
### Cross-compiling to Windows
The `cef-dll-sys` crate can be cross-compiled to `x86_64-pc-windows-msvc` from Linux with [cargo-xwin](https://github.com/rust-cross/cargo-xwin), which downloads the Windows SDK and sets up a `clang-cl` toolchain for both Rust and CMake. Install `clang`, `lld`, `llvm` and `ninja` from your package manager (the MSVC STL headers require Clang 19 or newer; on Ubuntu 24.04 use [apt.llvm.org](https://apt.llvm.org/)), then:
```sh
rustup target add x86_64-pc-windows-msvc
cargo install cargo-xwin
cargo xwin build --target x86_64-pc-windows-msvc
```
The `libcef_dll_wrapper` static library is built with `clang-cl` and the CEF runtime files are copied next to the output binaries, exactly like a native Windows build. The `CEF_PATH` environment variable works the same way as well: the Windows CEF binaries are downloaded into their own `cef_windows_x86_64` directory next to the host ones.
## Contributing
Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details.