如何在Linux上容器化编译Rust开发的i686-pc-windows-msvc应用
问题
我正在开发一款目标平台为i686-pc-windows-msvc的Rust Windows应用,该应用通过build.rs文件指定Windows清单,在Windows系统上编译正常。切换到Linux环境后,尝试通过Dockerfile容器化编译流程但未成功。相关信息如下:
项目结构
❯ tree . ├── build.rs ├── Cargo.lock ├── Cargo.toml ├── Dockerfile ├── src │ ├── api.rs │ ├── client.rs │ ├── main.rs │ ├── service.rs │ └── system.rs └── target
Cargo.toml配置
[package] name = "wrapper" version = "0.1.0" edition = "2021" build = "build.rs" [build-dependencies] winresource = "0.1" [dependencies] named-lock = "0.3.0" rand = "0.8.5" reqwest = "0.11.24" tokio = { version = "1.36.0", features = ["rt", "rt-multi-thread"] } winapi = { version = "0.3.9", features = ["processthreadsapi", "securitybaseapi", "winnt", "fileapi", "minwinbase", "iphlpapi", "winsock2", "ws2def"] } windows-service = "0.6.0"
build.rs代码
extern crate winresource; fn main() { let mut res = winresource::WindowsResource::new(); res.set_manifest( r#" <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"> <security> <requestedPrivileges> <requestedExecutionLevel level="requireAdministrator" uiAccess="false"/> </requestedPrivileges> </security> </trustInfo> </assembly> "#, ); res.set_ar_path("i686-w64-mingw32-gcc-ar"); res.set_windres_path("i686-w64-mingw32-windres"); if let Err(error) = res.compile() { eprint!("{error}"); std::process::exit(1); } }
当前Dockerfile内容
FROM archlinux:multilib-devel-20240101.0.204074 RUN pacman -Syu --noconfirm && \ pacman -S --needed --noconfirm rustup mingw-w64 RUN rustup default stable && \ rustup target install i686-pc-windows-msvc WORKDIR /app COPY Cargo.toml Cargo.lock build.rs ./ COPY src ./src RUN cargo build --target i686-pc-windows-msvc RUN cargo build --release --target i686-pc-windows-msvc RUN mkdir -p /app/debug/ && \ cp target/i686-pc-windows-msvc/debug/wrapper.exe /app/debug/ RUN mkdir -p /app/release/ && \ cp target/i686-pc-windows-msvc/release/wrapper.exe /app/release/
编译报错信息
❯ docker build --tag 'wrapper' . [...]Step 7/10 : RUN cargo build --target i686-pc-windows-msvc [...] Compiling wrapper v0.1.0 (/app) The following warnings were emitted during compilation: warning: wrapper@0.1.0: unknown Windows target used for cross-compilation; invoking unprefixed windres error: failed to run custom build command for `wrapper v0.1.0 (/app)` Caused by: process didn't exit successfully: `/app/target/debug/build/wrapper-6dacece8a0e1e7d8/build-script-build` (exit status: 1) --- stdout package.metadata does not exist cargo:warning=unknown Windows target used for cross-compilation; invoking unprefixed windres Selected RC path: '/bin\x64\rc.exe' --- stderr No such file or directory (os error 2) warning: build failed, waiting for other jobs to finish... The command '/bin/sh -c cargo build --target i686-pc-windows-msvc' returned a non-zero code: 101
请问如何修改Dockerfile,使其能正常编译并生成debug和release版本的程序?
解决方案
报错核心原因是:指定的目标平台i686-pc-windows-msvc是MSVC工具链目标,但Linux容器中使用的是MinGW工具链,两者不兼容,导致winresource库错误地尝试调用Windows原生的rc.exe(不存在于Linux环境)。调整为MinGW对应的目标平台即可解决问题,具体修改如下:
修改后的Dockerfile
FROM archlinux:multilib-devel-20240101.0.204074 RUN pacman -Syu --noconfirm && \ pacman -S --needed --noconfirm rustup mingw-w64 RUN rustup default stable && \ # 替换为MinGW对应的32位Windows目标平台 rustup target install i686-pc-windows-gnu WORKDIR /app # 配置Cargo使用MinGW的链接器 ENV CARGO_TARGET_I686_PC_WINDOWS_GNU_LINKER=i686-w64-mingw32-gcc COPY Cargo.toml Cargo.lock build.rs ./ COPY src ./src # 使用MinGW目标平台编译debug版本 RUN cargo build --target i686-pc-windows-gnu # 使用MinGW目标平台编译release版本 RUN cargo build --release --target i686-pc-windows-gnu # 复制debug版本到指定目录 RUN mkdir -p /app/debug/ && \ cp target/i686-pc-windows-gnu/debug/wrapper.exe /app/debug/ # 复制release版本到指定目录 RUN mkdir -p /app/release/ && \ cp target/i686-pc-windows-gnu/release/wrapper.exe /app/release/
关键修改点说明
- 切换目标平台:将
i686-pc-windows-msvc替换为i686-pc-windows-gnu,这是MinGW工具链对应的Windows 32位目标,与容器中安装的mingw-w64工具链完全兼容。 - 指定链接器:通过环境变量
CARGO_TARGET_I686_PC_WINDOWS_GNU_LINKER明确指定MinGW的链接器i686-w64-mingw32-gcc,确保Cargo使用正确的工具链完成编译。 - 调整路径:所有编译命令和文件复制路径都对应修改为新的目标平台目录,保证能正确找到生成的可执行文件。
补充说明
你的build.rs已经正确设置了MinGW的ar和windres路径,切换到gnu目标后,winresource库会自动识别交叉编译环境,使用指定的MinGW工具处理资源清单,不会再尝试调用Windows的rc.exe。
内容的提问来源于stack exchange,提问作者Nayrosk
相关产品推荐
相关产品推荐

