Cross building for windows fail at linking

Hello here,

I would like to compile my game for Windows. I'm totally new about Windows compilations.

I'm trying to use the cross tool to cross compile from linux. After installed it with cargo install cross --git https://github.com/cross-rs/cross I try a first cross compilation with cross build --target x86_64-pc-windows-gnu (Note I'm not sure about which target to choose for my Windows users ...).

Cross compile fail on the following :

error: failed to run custom build command for `zmq-sys v0.11.0`

Caused by:
  process didn't exit successfully: `/target/debug/build/zmq-sys-ee90d7adf4209fad/build-script-main` (exit status: 101)
  --- stdout
  cargo:rerun-if-env-changed=LIBZMQ_NO_PKG_CONFIG
  [...]
  cargo:rerun-if-env-changed=PKG_CONFIG_SYSROOT_DIR

  --- stderr
  thread 'main' panicked at 'Unable to locate libzmq:
  `"pkg-config" "--libs" "--cflags" "libzmq" "libzmq >= 4.1"` did not exit successfully: exit status: 1
  error: could not find system library 'libzmq' required by the 'zmq-sys' crate

  --- stderr
  Package libzmq was not found in the pkg-config search path.
  Perhaps you should add the directory containing `libzmq.pc'
  to the PKG_CONFIG_PATH environment variable
  No package 'libzmq' found
  Package libzmq was not found in the pkg-config search path.
  Perhaps you should add the directory containing `libzmq.pc'
  to the PKG_CONFIG_PATH environment variable
  No package 'libzmq' found
  ', /home/bastiensevajol/.cargo/registry/src/github.com-1ecc6299db9ec823/zmq-sys-0.11.0/build/pkg_config.rs:26:17
  note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
warning: build failed, waiting for other jobs to finish...

That's because my game depends on zmq crate.

My questions are :

  • For a beginner, use cross tool is a good idea ?
  • x86_64-pc-windows-gnu target is a correct choice ?
  • I would like to extend the cross used docker image and build one from it by adding libzmq. But, I'm compiling for Windows, can I install it (in the image) like if was on linux or it is a "Windows" installation ?

Thanks for the brave readers of my question ! :slight_smile:

I have a minimal reproduction steps about this. Dockerfile (to build cross compilation image) :

FROM rust:latest 

RUN apt-get update && apt-get upgrade -y
RUN apt-get install -y g++-mingw-w64-x86-64 libudev-dev libzmq3-dev

RUN rustup target add x86_64-pc-windows-gnu
RUN rustup toolchain install --force-non-host stable-x86_64-pc-windows-gnu

WORKDIR /app
# This permit to pkg-config to found zmq
ENV PKG_CONFIG_SYSROOT_DIR=/usr/x86_64-w64-mingw32/
CMD ["cargo", "build", "--target", "x86_64-pc-windows-gnu"]

Which I build with docker build . -t mycrossimage.

Minimal rust Cargo.toml and main.rsfile :

echo "[package]\nname = \"demo\"\nversion = \"0.1.0\"\nedition = \"2021\"\n[dependencies]\nzmq = \"0.9.0\"" > Cargo.toml && mkdir -p src && echo 'use zmq; fn main() {}' > src/main.rs

Produce this error at compilation docker run --rm -v $(pwd):/app mycrossimage:latest :

error: linking with `x86_64-w64-mingw32-gcc` failed: exit status:
[...]
  = note: /usr/bin/x86_64-w64-mingw32-ld: cannot find -lzmq
      collect2: error: ld returned 1 exit status

I tried some configuration found on the web without success :frowning:

I'd say yes, as it generally makes cross-compilation easier than setting up your own toolchain (i.e. takes care of adding the right linker and sets up a basic development environment). Doing this in a Docker container makes it portable and usable in CI, so even better.

Probably, as setting up the msvc target looks much more complicated than using MinGW.

When you take a look at the Dockerfile for the x86_64-pc-windows-gnu target, you'll see that it is based on Ubuntu 20.04. So all Linux.

Now to your error (that your linker can't link to libzmq). That is because installing libzmq3-dev adds libzmq only for your target architecture, not for your cross-compilation MinGW setup. So apt-get install libzmq3-dev won't work. There is no mingw-w64-libzmq3 (or some other name) package I could find, so I assume you have to build libzmq from source, using your MinGW compiler.

2 Likes

I think it might be easier (and faster) to use github actions in this case:

name: rustbuild
on: [push, pull_request]

jobs:
  build-msys-mingw64:
    runs-on: windows-latest
    defaults:
      run:
        shell: msys2 {0}
    steps:
      - uses: actions/checkout@v2
      - uses: msys2/setup-msys2@v2
        with:
          msystem: MINGW64
          update: true
          install: git mingw-w64-x86_64-cc mingw-w64-x86_64-rust mingw-w64-x86_64-zeromq --needed
      - name: CI-Build
        run: cargo build --release
      - name: Upload a Build Artifact
        uses: actions/upload-artifact@v2
        with:
          name: mygame
          path: target/release/mygame.exe

This uses the packaged mingw rustc which is currently at 1.66 stable.

Note I'm not sure about which target to choose for my Windows users

In general both targets (msvc and gnu) run natively on Windows. The pain point is that if a package in your dependencies somehow requires libstdc++, then your game will get the dreaded libstdc++6.dll was not found dialog!

Statically linking libstdc++ for windows-gnu requires the static_nobundle unstable feature currently.

You might also want to try the CLANG64 msystem which uses the msvc abi. The package prefix is mingw-w64-clang-x86_64- so mingw-w64-clang-x86_64-zeromq.

3 Likes

Hello @jofas ,

Okay, thank you a lot for these explanations. I will now try to know how to build zmq with MinGW.

Hello @MoAlyousef ,

Thank you a lot for this GitHub Actions example. I tried it, and it is working (I just had to add mingw-w64-x86_64-pkg-config package).