I'm developing an application in Rust for Windows (the target is: i686-pc-windows-msvc
), this application has particular requirements: it uses a build.rs
file to specify the Windows manifest.
Compilation worked fine on Windows, but I had to switch to Linux for this project.
Here's the project:
❯ 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"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[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);
}
}
I therefore tried to containerize the compilation process via a Dockerfile, but without success.
Here's my 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/
Here's my output :
❯ 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: [email protected]: 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
How can I get my Dockerfile
to compile properly and return both versions of the program (debug
and release
)?
The winres
crate does not support cross-compiling (see https://github.com/mxre/winres/issues/42).
Your options are:
build.rs
which calls into winres
when building on a non-Windows platform, using conditional compilation. This may not be an option in your case, if your application will not function correctly without the manifest.winresource
fork, which does support cross-compilation if you have mingw-w64
installed. Note that you won't be able to target i686-pc-windows-msvc
from a Linux container, because the MSVC toolchain is only available on Windows. You'll need to use the i686-pc-windows-gnu
target instead. In fact, the message cargo:warning=unknown Windows target used for cross-compilation; invoking unprefixed windres
comes from winresource
not supporting i686-pc-windows-msvc
when cross-compiling.