White-Oak / qml-rust

QML (Qt Quick) bindings for Rust language
MIT License
205 stars 18 forks source link

Adjust build_lib.sh for Windows #28

Closed tea-one closed 3 years ago

tea-one commented 7 years ago

I propose to adjust the current build script as it is not usable on Windows systems due to two reasons:

  1. Windows does not natively run .sh scripts unless one has installed the shell via cygwin or activated the linux-shell on Windows 10's developer mode. Still, we could add a batch script to make life easier.

  2. cmake defaults to the MSVCC generator on Windows and calling make consequently results in an error since no make files have been generated. We could either explicitly call cmake -G "Unix Makefiles" .. or run MSVCC's compiler. I haven't tried the latter yet but generating Unix Makefiles works fine on my system with Windows 10. Again, avoiding cygwin and the like would make life a lot easier, though. ;)

White-Oak commented 7 years ago

@leviat thanks for the issue!

I'm really eager to solve well this one. First, it is possible to do different things depending on target in build.rs, so I suppose we should run build_lib.bat to build DOtherSide dependency. Next, I will need your help. I have not tried to build qml-rust on Windows, and I'm not really competent with developing/compiling anything on Windows, but I had some folks add compiling with MSYS for Windows. I guess that's what you talked about in the end: avoiding cygwin and the like would make life a lot easier. I fullfully agree with you and I'm really curious to see how this turns out.

So, what are the requirements for compiling qml-rust and its dependency? I guess, the list goes so:

White-Oak commented 7 years ago

(Note: I have a Windows machine, so I'm not talking about cross-compiling, but about a direct compiling on Windows (: )

tea-one commented 7 years ago

Well, I kind of sent an unfinished reply and then deleted it without copying the content... so here again 😄

Thanks for taking on this issue! I work both on Linux and on Windows but fixing os-specific dependencies might not really be my forte. My current compilation of qml-rust runs up to the linking phase where it crashes because of missing dependencies. But let's start from the beginning. 😉

Requirements (probably not complete):

It probably suffices to have the Qt and VS versions match but that's what currently works for me.

Compiling

To compile DOtherSide from the Windows command line cmd, we can run:

cmake -G "Visual Studio 12 2013 Win64" ..
"c:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" amd64
msbuild.exe Project.sln 

This will generate the project files for VS, set some environment variables for VS compilation and then build the project. We probably should forward target parameters like DEBUG and RELEASE to msbuild.exe. I couldn't check if it correctly integrates into the build process of qml-rust yet since sh can't run the batch file in the second line. Gonna try to come up with a batch script for building and validate that.

Linking

Qt

So currently I compile DOtherSide with Unix Makefiles and cygwin. To correctly link the Qt libraries, I also made some adjustments in build.rs:

// On Linux and Windows, libraries are named "Qt5Core", not "QtCore" as on OSX
let linux_qt_lib_ver = if target.contains("linux") || target.contains("windows") { "5" }
                        else  { "" };

// On windows include qt folder
if cfg!(target_os = "windows") {
    println!("cargo:rustc-link-search=native=C:/Qt/5.6/msvc2013_64/lib");
}

The second half is quite ugly. If there was a way to retrieve the library path from the cmake process before, that would be a lot nicer and less error prone. The building process will just fail at this point when another Qt version is used or if it has been installed somewhere else.

C++ std libraries

This is the part where it fails at my end right now. We include stdc++ libraries without some proper black magic to retrieve the right files and put them into the right places. The "right" way would be to use the Visual Studio C++ libraries I guess. The linking process somewhere already links to msvcrt.lib which is the runtime library for Visual Studio C. Its C++ companion would be msvcrp.lib, I guess. However, I couldn't test it yet because I haven't adjusted the building process to compile DOtherSide with Visual Studio until now.

So well, that's my current status. If you have any nifty ideas how to improve the ugly workarounds, that would be great!

tea-one commented 7 years ago

Just wanted to give a quick update: As we have to make sure that we use the same VS version as for Qt, I just opted for fixing it to the VS 12 version. However, explicitly specifying a linker in Cargo omits its setup for some environmental variables and it fails to properly link the build-script. The current workaround would be to just call C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin\amd64\vcvars64.bat to setup the variables but I don't want every project which relies on this library to have to call the batch file from the command line. So well, I'm gonna look into this issue the next few days and hope that people on the Cargo project can tell how to setup the correct variables. 🤞

White-Oak commented 7 years ago

I really don't like the way paths are hardcoded, but I guess, that's what we have

tea-one commented 7 years ago

I can rewrite the hardcoded paths for Visual Studio in the build-script because there are some env-vars for that. There are two problems left, though:

Currently, the only way to find the correct Qt folders is to rely on the user to provide them. I don't know how to handle this neatly, though. Even Cmake needs to know the path to the Qt root folder in order to find its modules. (This is done by setting the CMAKE_PREFIX_PATH or include it into PATH.) A more elegant solution would be to have the user pass the Qt path to the build-script as an argument. However, I have no clue how to do that. So I guess we opt for the "user sets the CMAKE_PREFIX_PATH"?😕

Second, I haven't got it to work with VS 14 yet. So there's still the hardcoded linking part in the cargo config. Gonna see into it the next days unless you know a reason why it wouldn't work with. :)

White-Oak commented 7 years ago

I think it's okay to depend on CMAKE_PREFIX_PATH. Just need to make a note about that in README, I guess.

White-Oak commented 7 years ago

@leviat I'm not sure you haven't discovered this, but there are env variables set by Visual Studio such as VS140COMNTOOLS that points to C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\Tools\ so something like "$ENV{VS110COMNTOOLS}../../VC/vcvarsall.bat" is possible in cmake files

tea-one commented 7 years ago

Thanks, that's what I meant when I said I could rewrite the hardcoded paths for VS in the build scripts. However, the problem was with the cargo config. We can't use env vars there but have to specify the linker in it unless we get the project to work on all VS versions. It doesn't run on VS 14 right now and to be honest, I don't have a clue why 😕

White-Oak commented 7 years ago

@leviat well, I just built it on VS 14. I had problems with 64-bit Qt (5.8) though, being able to build only with 32-bit Qt (5.7) version.

tea-one commented 7 years ago

New suggestion. Instead of trying to automagically call the right VS version, we do the following:

  1. The user has to make sure, he selects the right VS and Qt version by setting the right env-vars. For example by calling:

    set CMAKE_PREFIX_PATH=C:\Qt\5.4\msvc2013_64_opengl
    "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" amd64

    Specifying link.exe in the project cargo config as linker should default to the one made public by the above call.

  2. The build-script does not know which VS version the user has chosen but we need to pass that to CMake to compile DOtherSide with the same linker. One solution could be to introduce some empty features to the cargo.toml which solely have the purpose of telling the build script which VS version has been made public to the environment. The user would then call cargo for example with $ cargo build --features "vs12"

That should get rid of all the current hard-coded stuff and let the user handle all the versioning stuff by hand.

flanfly commented 7 years ago

Hello everybody,

I hacked together a simple build.rs script to build DOtherSide using the cmake crate: #30. I tested it on Windows 10 w/ MSVC 14.0, OS X El Capitain w/ clang 8 and GNU/Linux w/ g++ 4.9.

I'm not an expert on Windows but AFAIK CMake finds the environment variables itself w/o any user interaction. At least on my test machine it worked outside of the Visual Studio Bash. I did not have any linker problems mentioned by @leviat.

tea-one commented 7 years ago

@flanfly CMake certainly is able to access the env-vars itself. However, on Windows, Qt does not set any by default. The easiest way to fix that is to either temporarily set the env-var CMAKE_PREFIX_PATH to the Qt folder or just any other like you did with QTDir.

The script will work for you since you have VS 14 and the corresponding Qt version. However, it is not uncommon to have more than one Visual Studio on Windows and to use an older one, e.g. VS 12, due to other library dependencies. In that case, your script can not been used since it will default to VS 14.

Generally, I think we should use your code as a basis to improve on. Adding DOtherSide as a git-submodule is a nice overall improvement and using the CMake crate makes a lot of ugly script code obsolete. As it is now, it lacks the option to specify the correct VS version, though.

flanfly commented 7 years ago

I see. The build script checks the QTDIR env-var for the Qt 5 SDK. If this fails it defaults to C:\Qt\5.7\mscv_2015_64 which is the current SDK version on Windows. If this fails also you get an error message telling you to set QTDIR.

CMake indeed uses the latest MSVC it finds. I added some code so you can change this behavior by setting the generator you want in CMAKE_GENERATOR.

White-Oak commented 7 years ago

@leviat do we consider it fixed with #30, or there is still work to be done?

I guess, one should state in the README about building process.

tea-one commented 7 years ago

Hmm.. I tried to set QTDIR and compile it but I get the following error message:

error: failed to run custom build command for qml v0.0.9 (file:///C:/Users/User/Documents/Rust%20Projects/qml-rust) process didn't exit successfully: C:\Users\User\Documents\Rust Projects\qml-rust\target\debug\build\qml-3b0a72a2d15dcaad\build-script-build (exit code: 101) --- stderr CMake Warning: Manually-specified variables were not used by the project:

CMAKE_BUILD_TYPE

thread 'main' panicked at ' command did not execute successfully, got: exit code: 1

build script failed, must exit now', C:\Users\User.cargo\registry\src\github.com-1ecc6299db9ec823\cmake-0.1.20\src\lib.rs:573 stack backtrace: 0: 0x7ff7e301e2c8 - std::panicking::default_hook::{{closure}} at C:\bot\slave\nightly-dist-rustc-win-msvc-64\build\src\libstd\panicking.rs:356 1: 0x7ff7e301d7d4 - std::panicking::default_hook at C:\bot\slave\nightly-dist-rustc-win-msvc-64\build\src\libstd\panicking.rs:367 2: 0x7ff7e30210ad - std::panicking::rust_panic_with_hook at C:\bot\slave\nightly-dist-rustc-win-msvc-64\build\src\libstd\panicking.rs:555 3: 0x7ff7e3020f48 - std::panicking::begin_panic at C:\bot\slave\nightly-dist-rustc-win-msvc-64\build\src\libstd\panicking.rs:517 4: 0x7ff7e3020e64 - std::panicking::begin_panic_fmt at C:\bot\slave\nightly-dist-rustc-win-msvc-64\build\src\libstd\panicking.rs:501 5: 0x7ff7e2fc7acc - cmake::fail at C:\Users\User.cargo\registry\src\github.com-1ecc6299db9ec823\cmake-0.1.20\src\lib.rs:573 6: 0x7ff7e2fc72db - cmake::run at C:\Users\User.cargo\registry\src\github.com-1ecc6299db9ec823\cmake-0.1.20\src\lib.rs:554 7: 0x7ff7e2fc3fb6 - cmake::Config::build at C:\Users\User.cargo\registry\src\github.com-1ecc6299db9ec823\cmake-0.1.20\src\lib.rs:433 8: 0x7ff7e2fa45e9 - build_script_build::build_dos at C:\Users\User\Documents\Rust Projects\qml-rust\build.rs:10 9: 0x7ff7e2fa518a - build_script_build::main at C:\Users\User\Documents\Rust Projects\qml-rust\build.rs:136 10: 0x7ff7e3022471 - panic_unwind::__rust_maybe_catch_panic at C:\bot\slave\nightly-dist-rustc-win-msvc-64\build\src\libpanic_unwind\lib.rs:98 11: 0x7ff7e302169a - std::rt::lang_start at C:\bot\slave\nightly-dist-rustc-win-msvc-64\build\src\libstd\rt.rs:51 12: 0x7ff7e2fa536b - main 13: 0x7ff7e3029367 - __scrt_common_main_seh at f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl:264 14: 0x7ff938f78363 - BaseThreadInitThunk

Anyone got a clue what happened here?

flanfly commented 7 years ago

@leviat, what cmake version do you use?

tea-one commented 7 years ago

@flanfly I'm working with CMake 3.7.1 😕