failed to open icon
主线位置:启动主线第一步,编译期的
generate_context!。它在展开时把默认窗口图标解码成 RGBA 写进OUT_DIR,生成Image::new(include_bytes!(..), 宽, 高)(见 generate_context! 的「图标、包信息和 Info.plist」)。图标读不到或格式不对,宏就 panic,错误落在generate_context!()那一行。
flowchart TB
start["generate_context!"] --> tgt{"目标是 Windows"}
tgt -->|是| res["用 tauri-build 嵌的资源图标"]
tgt -->|否| pick{"bundle.icon 里有 .png"}
pick -->|有| first["第一个 .png"]
pick -->|没有| deflt["icons/icon.png"]
first --> load["读文件 解码"]
deflt --> load
load -->|读不到| e1["failed to open icon"]
load -->|不是 RGBA| e2["is not RGBA"]
load -->|成功| okn["Image::new 嵌入"]
本页实验 crate 是 pit1-icon:由模板 base 复制,依次改 icons/ 和配置里的 bundle.icon,cargo build --offline --features tauri/custom-protocol。M2 Max、macOS 27、rustc 1.99.0,tauri 2.12.5。
现象
一:没有 icons/icon.png
error: proc macro panicked
--> src/main.rs:20:10
|
20 | .run(tauri::generate_context!())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: message: failed to open icon ~/exp-tauri/pit1-icon/icons/icon.png: No such file or directory (os error 2)
error: could not compile `pit1-icon` (bin "pit1-icon") due to 1 previous error
二:有,但是 RGB 的
用 Python 写一张 32×32、颜色类型 2(RGB,没有 alpha)的 PNG,file 认作「PNG image data, 32 x 32, 8-bit/color RGB, non-interlaced」,放到 icons/icon.png:
error: proc macro panicked
--> src/main.rs:20:10
|
20 | .run(tauri::generate_context!())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: message: icon ~/exp-tauri/pit1-icon/icons/icon.png is not RGBA
error: could not compile `pit1-icon` (bin "pit1-icon") due to 1 previous error
三:配了图标,可是没有 PNG
icons/icon.png 仍然不存在,配置里写上打包用的两种图标:
"bundle": { "icon": ["icons/icon.icns", "icons/icon.ico"] }
error: proc macro panicked
= help: message: failed to open icon ~/exp-tauri/pit1-icon/icons/icon.png: No such file or directory (os error 2)
error: could not compile `pit1-icon` (bin "pit1-icon") due to 1 previous error
(这一段只保留了 grep 出的三行。)报错里的路径还是 icons/icon.png:配置里列出的两个文件一个都没被看。
出处
context_codegen 里选默认窗口图标的分支:Windows 目标生成 default_window_icon_from_app_icon_resource(),运行时从 tauri-build 编进可执行文件的资源里取;其他目标调 find_icon,条件是「以 .png 结尾」,默认值 icons/icon.png:
fn find_icon(
config: &Config,
config_parent: &Path,
predicate: impl Fn(&&String) -> bool,
default: &str,
) -> PathBuf {
let icon_path = config
.bundle
.icon
.iter()
.find(predicate)
.map(AsRef::as_ref)
.unwrap_or(default);
config_parent.join(icon_path)
}
它不检查文件在不在:情形三里 bundle.icon 没有 .png,find 落空,返回默认路径。路径相对于配置文件所在的目录,不是 crate 根目录(配置不在 crate 根目录时的后果见 generate_context! 读的不是你指定的配置文件)。
拿到路径之后,CachedIcon::new_png 读文件、用 png crate 解码,两处 panic! 就是上面的两条消息:
pub fn new_png(root: &TokenStream, icon: &Path) -> EmbeddedAssetsResult<Self> {
let buf = Self::open(icon);
let decoder = png::Decoder::new(Cursor::new(&buf));
let mut reader = decoder
.read_info()
.unwrap_or_else(|e| panic!("failed to read icon {}: {}", icon.display(), e));
if reader.output_color_type().0 != png::ColorType::Rgba {
panic!("icon {} is not RGBA", icon.display());
}
open 里是 panic!("failed to open icon {}: {}", ..)。这里用 panic! 而不是返回错误,所以 rustc 报的是「proc macro panicked」,消息在 help: message: 后面。
#6712(提交标题「feat(core): early panic if the PNG icon is not RGBA, closes #6706」)首次发布于 tauri 1.4.0(tauri-codegen 1.4.0),tauri-codegen 的 CHANGELOG 原文:「Early panic if the PNG icon is not RGBA.」它加的就是这句 panic!,当时写在 tauri-codegen 的 context.rs 里,现在在 image.rs。生成的 Image::new(include_bytes!(..), 宽, 高) 把字节一律当 RGBA 用,所以在宏展开时挡下别的颜色类型。
开发模式(没有 custom-protocol)的 macOS 构建还会多读一次图标:app_icon 先找 bundle.icon 里的 .icns,没有再按上面的规则找 .png,原样嵌进二进制(见 开发模式启动后 bus error 退出)。所以只放 .icns 的项目在开发模式下也一样需要那张 PNG:窗口图标那一次读取先失败。
修法
放一张 RGBA 的 PNG,并让 find_icon 能找到它:要么就叫 icons/icon.png,要么在 bundle.icon 里列出来。pit1-icon 删掉 icons/icon.png,把模板的图标改名为 icons/app.png,配置写:
"bundle": { "icon": ["icons/app.png"] }
构建通过,运行:
REPORT greet=hello, rie origin=tauri://localhost
打包时还需要 .icns(macOS)和 .ico(Windows),一起列在 bundle.icon 里,顺序无关:窗口图标只取第一个 .png,macOS 开发模式只取第一个 .icns。tauri icon 命令能从一张大图生成整套图标,本卷不讲 CLI。
怎么确认没中招
file icons/icon.png(或bundle.icon里第一个.png)显示的颜色类型应该是 RGBA,比如「8-bit/color RGBA」。bundle.icon里至少有一个.png,或者icons/icon.png存在;路径相对于配置文件所在目录。- Windows 目标走资源图标这条路,要的是
.ico(tauri-build默认找bundle.icon里的.ico,再找icons/icon.ico,见WindowsAttributes::window_icon_path的文档注释)。本页没在 Windows 上实测。
小结
- 非 Windows 目标上,
generate_context!在编译期读bundle.icon里第一个.png,没有就读icons/icon.png,路径相对于配置文件所在目录。 - 文件不存在:「failed to open icon ...」;不是 RGBA:「icon ... is not RGBA」;都是过程宏 panic,报错落在
generate_context!()上。 - 只列
.icns、.ico不够,窗口图标要一张 RGBA 的 PNG。