Open8

RustでCEFを使う記録(cef-rs)

髙木 祐来髙木 祐来

このスクラップは、RustでChromium(CEF)を使う試みを記録する。

なお、CEF自体の調べてわかった情報は以下にまとめている。
https://zenn.dev/tasuren/scraps/ad7c40bf3d8f1c

RustでのCEF事情

自分が探して見つけたCEFのRust向けラッパープロジェクトは以下。

  • cef-rs
    リポジトリがtauriの組織でホストされている。
  • wew
    WebViewとして使うためのライブラリ。かなり最近。
    JavaScriptでIPCする方法が提供されているっぽい。
  • cef-ui
  • cef
  • rust-cef (アーカイブ済み)

このうち、一番更新頻度が高く、最新のChromiumに対応しているcef-rsをここでは使ってみる。


ちなみに、私が今回cef-rsを使うにあたって学習のために作ったコードは以下でホスト中。
https://github.com/tasuren/cef-sample-rs

髙木 祐来髙木 祐来

RustのCEFバインディング: cef-rs

二年前から今(2025/8/2 現在)も更新が続いている。また、基本的なバインディングは自動生成なため、CEF自体の更新にも追いつきやすいっぽい。
また、tauriの組織でホストされていて、少し信頼性が高い。

https://github.com/tauri-apps/cef-rs

cef-rsの提供するクレート

cef-rsは二つのクレートを提供する。

  • cef: cef-dll-sysのラッパー
    unsafeをあまり使わなくて済む、CEFをRustで円滑に使えるように実装されている。
  • cef-dll-sys: CEFのC言語向けAPIの薄いラッパー
    CEFのC言語向けAPIをそのままRustで使えるようにしただけの、基本的な低レイヤーAPI。
    cefクレートからre-exportされていて、cef::sysからこのクレートを使える。

基本的な使い方

基本的な使い方はリポジトリのREADME.mdに書いてある通り。
どうやら、CEFのライブラリのダウンロードは自動で行われるようだが、サイズが大きいので複数プロジェクトで同じCEFを使う場合に、一つのフォルダに配置したのを使い回すことができるとのこと。これは環境変数で設定できるとREADME.mdで述べられている。

もし前述した環境変数を作る際、環境変数で環境を汚したくない場合、.cargo/config.tomlでCargoに環境変数を設定するのが良さそう。
例:

[env]
CEF_PATH = { value = "パス", force = true }
DYLD_FALLBACK_LIBRARY_PATH = { value = "パス", force = true }
髙木 祐来髙木 祐来

URL集

参考

コントリビュータが作っている、cef-rsを使ったプロジェクト。実装の参考になるかもしれない。

  • 公式サンプル
    • cefsimple
    • osr
      CEFのOff-Screen Rendering機能を使って、winitクレートで作ったウィンドウにWebGPUでCEFの映像をレンダリングする例。osrの略はOff-Screen Renderingの略と思われる。(今はWindows限定?、私はあまりわかっていません。)
  • iced-webview
    GUIライブラリのicedにcef-rsを使ってCEFを埋め込むデモ。Off-Screen Renderingを用いる。
髙木 祐来髙木 祐来

cef-rsでのmacOSビルド

Rustのプロジェクトを動かす時は一般にcargo runで行うのが多いが、Chromiumを使うCEFでは少し事情が異なり、ヘルパーを同梱したバンドル(.appディレクトリ)を作らなければ動かすことができない。
このため、もしcef-rsのプロジェクトを動かす時は、毎回バンドルを作成する必要がある。

cef-rsのリポジトリのexamplesフォルダにある例では、必要な実行ファイルをビルドした後にそれをバンドルにするプログラムがある。
macOSでビルドして動かす場合、README.mdにも書いてある通り、そのバンドルにするプログラムを実行してアプリを作成する必要がある。

このため、バンドルを作成するプログラムとメインプロセスとなるプログラム、そしてヘルパーを動かすプログラムの三つがcef-rsを使うプロジェクトでは必要になるので、三つのクレートが基本的に必要になると思う。
このため、実用するならワークスペースか何かを使うのが良いかも?ただ、これはmacOSでの話で、それ以外は私はまだ知らない。

髙木 祐来髙木 祐来

macOSでドックにアイコンが表示されない

cef-rsのリポジトリにあるcefsimpleのサンプルプログラムの場合、そのままだとドックにアイコンが表示されないため、別のウィンドウを開いたあとウィンドウが見失いがち。Mission Control機能でウィンドウを探せるが、それが不便という場合もある。
追記(2025/8/17): cef-rsのcefsimpleのドックにアイコンが表示されない問題は解決済み。

このドックに表示されない問題は、アプリバンドル同梱するInfo.plistというアプリの設定ファイルの、LSUIElementというキーの値を0にすることで問題は解決する。
このため、ソースコードでいうところのここの値を0にすれば良い。
それと、どうやらこれは、ヘルパーのみ1にするのが正しいっぽい。cef-rsじゃなくてCEFのcefsimpleだとそうなっている。 でも全部0でも動くが、たまにヘルパーのアイコンがドックに現れるので、ヘルパーの時だけ1にするのがやっぱり良さそう。

LSUIElement自体の詳細:
https://zenn.dev/function/articles/eae61e3038de8f

髙木 祐来髙木 祐来

macOSで標準出力を見る方法

cargo runで普通に実行すれば、当たり前だが実行したターミナルで標準出力が見れる。ただ、macOS向けのバンドルとなると、普通のやり方では標準出力が見えずクラッシュ時のログが見れない。

これに関しては、以下で詳細を述べている。
https://zenn.dev/link/comments/df65f31b8cbc5a

髙木 祐来髙木 祐来

デバッグ方法について

cef-rsにおけるlldbといったツールによるデバッグは、cef-rsのREADME通りにやる場合、CEF側でクラッシュした場合に原因究明が困難になる場合がある。なぜなら、cef-rsの説明通りの使用は、CEFのリリースビルドを用いるためである。

CEFのリリースビルドを用いると関数などの名前(シンボル)がマングリング(別の名前に変化)した後になってしまったりと、デバッグ時にどこで何が起きたかなどがわかりづらくなる。

ちょっとした用途などではデバッグはなくても済むかもしれないが、たまにパニックもなしにクラッシュしてしまう場合がある。これはCEFを適切に使用しなかった場合に起こりうる。こういう時に何が起きたのかを追跡しやすいようには、CEFのデバッグビルドを用いる必要がある。

CEFのデバッグビルドを使う

最初に述べた通り、cef-rsのREADME通りにセットアップをすると、CEFのリリースビルドが使われる。これは、cef-rsが用意したビルドをダウンロードして展開するexport-cef-dirコマンドがリリースビルドのみに対応しているためである。

そこで、デバッグビルドを使いたい場合は、自分でダウンロードする必要がある。
ダウンロードはここから自分の使っているcef-rsが対応しているバージョンのStandard Distributionをダウンロードすればいい。

macOSでの手順(他OSはやったことないので、一部参考):

  1. プラットフォームを選択(WindowsやMacOSなど)
  2. Version Filterを使って、cef-rsの対応バージョンと一致するバージョンを検索
    検索後、見つからない場合"Show All Builds"で一覧を表示して探す。
    この時、同じバージョンでもコミットが別ということがありえる。そこは注意。
  3. Standard Distributionとその横にあるsha1をダウンロード
  4. ダウンロードできたら、sha1ファイルにあるハッシュと圧縮ファイルの名前をメモしておく
  5. Standard Distributionのダウンロードと解凍が終わったら、そこから以下を取り出して適当なフォルダに入れる
  • cmake
  • include
  • libcef_dll
  • symbols
  • CMakeLists.txt
  • Debug/Chromium Embedded Framework.framework
    ※これは、Debugの中からChromium Embedded Framework.frameworkを取り出す。Debug フォルダはいらない。
  1. ↑を入れたフォルダにarchive.jsonを作って以下のように設定(必要ない?)
{
  "type": "standard",
  "name": "Standard Distributionの圧縮ファイルの名前",
  "sha1": "Standard Distributionの横のsha1の中身"
}
  1. 5を入れたフォルダのパスを使ってcef-rsのREADMEにある環境変数CEF_PATH等に設定

デバッグでシンボル名がunnamedになる

この問題については、cef-rsとは関係ないので以下で説明。
https://zenn.dev/link/comments/b6945f3c7df14b

デバッグビルドを使った方が良いか

CEFとChromiumは、適切に起動しているか、適切に動作しているかを確認する仕組みを実装している。このチェックによりバグをわかりやすくしたり、未然に防ぐことができる。そしてそのチェックはデバッグ時のみ動くもの(DCHECK)が多々ある。例えば、適切にシャットダウン処理がされていない場合に、適切にシャットダウンがされているかを確認するDCHECKで処理が終了し、シャットダウンが適切ではないと気付ける等。

このため、ある程度堅牢に作りたい場合、ミスで謎のクラッシュに悩まされたくない場合、デバッグビルドを使うのが好ましい。cef-rsの開発者的には、デバッグビルドを使う方が便利な場合があるとのことで、将来的にはexport-cef-dirコマンドでデバッグビルドを用意できるようにするっぽい。[1]

脚注
  1. https://github.com/tauri-apps/cef-rs/issues/181#issuecomment-3191734322 ↩︎