Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

qttypes: Support C++ toolchains on Windows other than MSVC #154

Closed
ratijas opened this issue Jun 26, 2021 · 2 comments · Fixed by #155
Closed

qttypes: Support C++ toolchains on Windows other than MSVC #154

ratijas opened this issue Jun 26, 2021 · 2 comments · Fixed by #155
Labels
A-cross Area: Cross compilation C-bug Category: This is a bug. I-crash Issue: compiler or runtime crashes O-windows-gnu Toolchain: GNU, Operating system: Windows O-windows-msvc Toolchain: MSVC, Operating system: Windows

Comments

@ratijas
Copy link
Collaborator

ratijas commented Jun 26, 2021

Summary

Build.rs script of qttypes assumes that on Windows the toolchain is always MSVC, which leads to linkage errors with e.g. MinGW toolchain.

Description

As discussed in #150, there are lines in qttypes/build.rs which only work for MSVC setup:

let windows_dbg_suffix = if debug && cfg!(target_os = "windows") {
println!("cargo:rustc-link-lib=msvcrtd");
"d"
} else {
""
};

It produces this output:

cargo:rustc-link-lib=msvcrtd
cargo:rustc-link-search=C:/Qt/5.15.2/mingw81_32/lib
cargo:rustc-link-lib=Qt5Cored
cargo:rustc-link-lib=Qt5Guid
cargo:rustc-link-lib=Qt5Widgetsd
cargo:rustc-link-lib=Qt5Quickd
cargo:rustc-link-lib=Qt5Qmld

which instructs cargo to pass to a linked a set of libs specifically built for debugging with MSVC toolchain. Libraries with a d suffix are only shipped with Qt MSVC builds.

Note that since there is an if debug variable check involved in condition, this bug does not happen on --release mode.

Also, I don't think msvcrt/msvcrtd is really needed outside of MSVC ecosystem? Sounds like a compiler's runtime library, similar to compiler-rt in LLVM land.

Steps to reproduce

  1. Use Windows
  2. Do NOT install Visual Studio / MSVC toolchain (or at least hide it from env for now)
  3. Install rustup, add GNU target, say x86_64-pc-windows-gnu or i686-pc-windows-gnu. To avoid passing around --target arguments, default target can be saved in Cargo configuration.
  4. Install Qt with online installer. Make sure to add Qt libs and compiler toolchain built with and for MinGW, matching bitness or Cargo target.
  5. Cargo-build qmetaobject-rs itself or as a part of another project in debug mode (i.e. NOT --release).

Expected result

Everything should be OK.

Actual result

  = note: C:/Qt/Tools/mingw810_32/bin/../lib/gcc/i686-w64-mingw32/8.1.0/../../../../i686-w64-mingw32/bin/ld.exe: cannot find -lmsvcrtd
          C:/Qt/Tools/mingw810_32/bin/../lib/gcc/i686-w64-mingw32/8.1.0/../../../../i686-w64-mingw32/bin/ld.exe: cannot find -lQt5Cored
          C:/Qt/Tools/mingw810_32/bin/../lib/gcc/i686-w64-mingw32/8.1.0/../../../../i686-w64-mingw32/bin/ld.exe: cannot find -lQt5Guid
          C:/Qt/Tools/mingw810_32/bin/../lib/gcc/i686-w64-mingw32/8.1.0/../../../../i686-w64-mingw32/bin/ld.exe: cannot find -lQt5Widgetsd
          C:/Qt/Tools/mingw810_32/bin/../lib/gcc/i686-w64-mingw32/8.1.0/../../../../i686-w64-mingw32/bin/ld.exe: cannot find -lQt5Quickd
          C:/Qt/Tools/mingw810_32/bin/../lib/gcc/i686-w64-mingw32/8.1.0/../../../../i686-w64-mingw32/bin/ld.exe: cannot find -lQt5Qmld
          collect2.exe: error: ld returned 1 exit status

Now what?

Add to qttypes build script a check for current toolchain being used, and only add compiler runtime and d suffix if target is related to MSCV.

Version

My best guess is qmetaobject-rs starting from v0.2. It doesn't happen on published v0.1.4, i.e. before factoring out qttypes into its own crate.

@ratijas ratijas changed the title qttypes: Support C++ toolchains other than MSVC qttypes: Support C++ toolchains on Windows other than MSVC Jun 26, 2021
@ogoffart
Copy link
Member

https://doc.rust-lang.org/reference/conditional-compilation.html#target_env

Maybe we want cfg!(target_env = "msvc")

@ratijas
Copy link
Collaborator Author

ratijas commented Jun 27, 2021

No good. It can be set to "gnu", even though everything else is MSVC, including cargo:rustc-link-search=C:/Qt/5.15.2/msvc2019/lib. Looks like its value is taken from toolchain, not host nor the target.

This is my setup right now:

  • PATH points to C:/Qt/5.15.2/msvc2019/{lib,bin}
  • Windows 10 SDK and C++ build tools installed (Docs for Windows/MSVC toolchain: which workloads/components to install? rust-lang/rustup#2809)
  • rustup:
    • Default host: x86_64-pc-windows-msvc
    • toolchain: stable-x86_64-pc-windows-gnu (default)
    • target: i686-pc-windows-msvc
  • Settings up dev env by executing these lines in cmd.exe consecutively:
    • "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Auxiliary\Build\vcvars32.bat"
    • "C:\Qt\5.15.2\msvc2019\bin\qtenv2.bat"
    • "C:\Program Files\PowerShell\7\pwsh.exe"
    • (needless to say, I'm launching new Windows Terminal with PowerShell profile just to type cmd, paste those lines and dive into another PowerShell session)

As you can see, I've been through some MS s**t this weekend. But at least certainly learned something new...

Still, qttypes build script produces this output:

TARGET = Some("i686-pc-windows-msvc")
HOST = Some("x86_64-pc-windows-gnu")
DEBUG = Some("true")
running: "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools\\VC\\Tools\\MSVC\\14.29.30037\\bin\\HostX64\\x86\\cl.exe" "-nologo" "-MD" "-Z7" "-Brepro" "-I" "C:\\Users\\ratijas\\projects\\qmetaobject-rs\\qttypes" "-I" "C:/Qt/5.15.2/msvc2019/include" "-W4" "-FoC:\\Users\\ratijas\\projects\\qmetaobject-rs\\target\\i686-pc-windows-msvc\\debug\\build\\qttypes-6b4ec5005a66d071\\out\\rust_cpp\\cpp_closures.o" "-c" "C:\\Users\\ratijas\\projects\\qmetaobject-rs\\target\\i686-pc-windows-msvc\\debug\\build\\qttypes-6b4ec5005a66d071\\out\\rust_cpp\\cpp_closures.cpp"
cpp_closures.cpp
running: "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools\\VC\\Tools\\MSVC\\14.29.30037\\bin\\HostX64\\x86\\lib.exe" "-out:C:\\Users\\ratijas\\projects\\qmetaobject-rs\\target\\i686-pc-windows-msvc\\debug\\build\\qttypes-6b4ec5005a66d071\\out\\librust_cpp_generated.a" "-nologo" "C:\\Users\\ratijas\\projects\\qmetaobject-rs\\target\\i686-pc-windows-msvc\\debug\\build\\qttypes-6b4ec5005a66d071\\out\\rust_cpp\\cpp_closures.o"
exit code: 0
cargo:rustc-link-lib=static=rust_cpp_generated
cargo:rustc-link-search=native=C:\Users\ratijas\projects\qmetaobject-rs\target\i686-pc-windows-msvc\debug\build\qttypes-6b4ec5005a66d071\out
cargo:VERSION=5.15.2
cargo:LIBRARY_PATH=C:/Qt/5.15.2/msvc2019/lib
cargo:INCLUDE_PATH=C:/Qt/5.15.2/msvc2019/include
cargo:FOUND=1
cargo:rustc-link-search=C:/Qt/5.15.2/msvc2019/lib
cargo:rustc-link-lib=Qt5Core
cargo:rustc-link-lib=Qt5Gui
cargo:rustc-link-lib=Qt5Widgets
cargo:rustc-link-lib=Qt5Quick
cargo:rustc-link-lib=Qt5Qml
cargo:rustc-link-lib=Qt5WebEngine
cargo:rerun-if-changed=src/lib.rs

Not bad, and even compiles and runs. But is definitely not what we expected. I print-debugged the cfg!(target_env = "...") value, and turned out it is really set to "gnu". Uhh...

Oh, wait, i know why! It's because build scripts are special. They are being built as a binaries for the target platform of a host. Hence the target env matches my toolchain. Easy.

What we need instead are Environment variables Cargo sets for build scripts, namely CARGO_CFG_TARGET_ENV.

And... boom! Tetris for Jeff. We got our d's back — but only when they're needed:

TARGET = Some("i686-pc-windows-msvc")
HOST = Some("x86_64-pc-windows-gnu")
DEBUG = Some("true")
cargo:VERSION=5.15.2
cargo:LIBRARY_PATH=C:/Qt/5.15.2/msvc2019/lib
cargo:INCLUDE_PATH=C:/Qt/5.15.2/msvc2019/include
cargo:FOUND=1
cargo:rustc-link-lib=msvcrtd
cargo:rustc-link-search=C:/Qt/5.15.2/msvc2019/lib
cargo:rustc-link-lib=Qt5Cored
cargo:rustc-link-lib=Qt5Guid
...

Todo example with debug libs

ratijas added a commit that referenced this issue Jun 27, 2021
Simple cfg!(target_* = "...") doesn't work in build scripts the way it
does in crate's code, because build scripts are being compiled for the
toolchain's target triple -- not the default-host nor the cargo's
eventual target. Instead, such configuration should be loaded from
provided environment variables at run-time.

While initially trying to fix linkage issues for Windows + MinGW target
(first reported by @stuartZhang in #150), I came to realize in the
process that cfg!(target_os = ...), although being used only for OS X
at this moment, is likely screwed up in the same way (except, who would
ever cross-compile to or from Mac, and why?)

https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts

Fixes #154
ogoffart pushed a commit that referenced this issue Jun 27, 2021
Simple cfg!(target_* = "...") doesn't work in build scripts the way it
does in crate's code, because build scripts are being compiled for the
toolchain's target triple -- not the default-host nor the cargo's
eventual target. Instead, such configuration should be loaded from
provided environment variables at run-time.

While initially trying to fix linkage issues for Windows + MinGW target
(first reported by @stuartZhang in #150), I came to realize in the
process that cfg!(target_os = ...), although being used only for OS X
at this moment, is likely screwed up in the same way (except, who would
ever cross-compile to or from Mac, and why?)

https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts

Fixes #154
@ratijas ratijas added A-cross Area: Cross compilation C-bug Category: This is a bug. I-crash Issue: compiler or runtime crashes O-windows-gnu Toolchain: GNU, Operating system: Windows O-windows-msvc Toolchain: MSVC, Operating system: Windows labels Jun 30, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-cross Area: Cross compilation C-bug Category: This is a bug. I-crash Issue: compiler or runtime crashes O-windows-gnu Toolchain: GNU, Operating system: Windows O-windows-msvc Toolchain: MSVC, Operating system: Windows
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants