rust-qt / ritual

Use C++ libraries from Rust
Apache License 2.0
1.22k stars 49 forks source link

Cross-compiler support #87

Open melshuber opened 4 years ago

melshuber commented 4 years ago

Hi,

I'd like to use Rust QT bindings for an embedded target. The build host is an x86, the target is an aarch64 architecture. However I can't figure out how to cross compile the qt bindings crate.

I suppose it has something to with the c_lib part which is part of each crate generated by ritual. From my build logs I see that the host compiler instead of the target is used for c_lib. I think this is because cmake does not get setup for cross-compiling during this build step.

Further, it might be necessecary to re-generate my own crates to match the qt-version used on the cross target and not the host (https://github.com/rust-qt/ritual#generating-qt-crates).

What is the preferred way to select the sysroot/cross toolchain in ritual?

By the way, I am using buildroot.

The missing include file (see log below) is present int the sysroot of the target (but not on the host).

Thanks for your help

$> PATH="<path-to-dev-dir>/devel/build/br2/host/bin:<path-to-dev-dir>/devel/build/br2/host/sbin:<path-to-home>/.cargo/bin:<path-to-home>/.cargo/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games" \
SYSROOT=<path-to-dev-dir>/devel/build/br2/host/aarch64-buildroot-linux-gnu/sysroot \
PKG_CONFIG_ALLOW_CROSS=1 \
CARGO_HOME=<path-to-dev-dir>/devel/build/br2/host/share/cargo \
cargo build --release --target=aarch64-unknown-linux-gnu --manifest-path=<path-to-dev-dir>/devel/build/br2/build/qt-examples-custom/Cargo.toml --verbose -j1

[...]

error: failed to run custom build command for `qt_gui v0.3.0`

Caused by:
  process didn't exit successfully: `<path-to-dev-dir>/devel/build/br2/build/qt-examples-custom/target/release/build/qt_gui-2731c6cc43cc56ed/build-script-build` (exit code: 1)
--- stdout
-- The C compiler identification is GNU 8.3.0
-- The CXX compiler identification is GNU 8.3.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done

[...]

-- RITUAL_âINCLUDE_PATH=<path-to-dev-dir>/devel/build/br2/host/aarch64-buildroot-linux-gnu/sysroot/usr/include/qt5;<path-to-dev-dir>/devel/build/br2/host/aarch64-buildroot-linux\
-gnu/sysroot/usr/include/qt5/QtGui;<path-to-dev-dir>/devel/build/br2/host/aarch64-buildroot-linux-gnu/sysroot/usr/include/qt5/QtCore
-- RITUAL_LIBRARY_PATH=<path-to-dev-dir>/devel/build/br2/host/aarch64-buildroot-linux-gnu/sysroot/usr/lib
-- RITUAL_LIBRARY_TYPE=STATIC
-- RITUAL_LINKED_LIBS=Qt5Gui;Qt5Core
-- RITUAL_CPP_LIB_VERSION=51202
-- RITUAL_COMPILER_FLAGS=-std=gnu++11 -fPIC
-- Configuring done
-- Generating done
-- Build files have been written to: <path-to-dev-dir>/devel/build/br2/build/qt-examples-custom/target/aarch64-unknown-linux-gnu/release/build/qt_gui-15ef8cd72196cd53/out/c_lib_build
/usr/bin/make -f CMakeFiles/Makefile2 clean

[...]

/usr/bin/c++  -DQT_GUI_C_LIBRARY -DQT_NO_VERSION_TAGGING -DRITUAL_CPP_LIB_VERSION=51202 -I<path-to-dev-dir>/devel/build/br2/build/qt-examples-custom/target/aarch64-unknown-linux-gnu/releas
e/build/qt_gui-15ef8cd72196cd53/out/c_lib_build/sized_types_autogen/include -I<path-to-dev-dir>/devel/build/br2/host/share/cargo/registry/src/github.com-1ecc6299db9ec823/qt_gui-0.3.0/c_lib
 -I<path-to-dev-dir>/devel/build/br2/build/qt-examples-custom/target/aarch64-unknown-linux-gnu/release/build/qt_gui-15ef8cd72196cd53/out/c_lib_build -I<path-to-dev-dir>/devel/bu
ild/br2/host/aarch64-buildroot-linux-gnu/sysroot/usr/include/qt5 -I<path-to-dev-dir>/devel/build/br2/host/aarch64-buildroot-linux-gnu/sysroot/usr/include/qt5/QtGui -I<path-to-home>/cherry
/cobra/devel/build/br2/host/aarch64-buildroot-linux-gnu/sysroot/usr/include/qt5/QtCore  -Wall -Wextra -Wno-deprecated-declarations -Werror=return-type -std=gnu++11 -fPIC -O3 -DNDEBUG   -o CMakeFiles/
sized_types.dir/sized_types.cxx.o -c <path-to-dev-dir>/devel/build/br2/host/share/cargo/registry/src/github.com-1ecc6299db9ec823/qt_gui-0.3.0/c_lib/sized_types.cxx
make[2]: Leaving directory '<path-to-dev-dir>/devel/build/br2/build/qt-examples-custom/target/aarch64-unknown-linux-gnu/release/build/qt_gui-15ef8cd72196cd53/out/c_lib_build'
make[1]: Leaving directory '<path-to-dev-dir>/devel/build/br2/build/qt-examples-custom/target/aarch64-unknown-linux-gnu/release/build/qt_gui-15ef8cd72196cd53/out/c_lib_build'
--- stderr
In file included from <path-to-dev-dir>/devel/build/br2/host/aarch64-buildroot-linux-gnu/sysroot/usr/include/qt5/QtGui/QtGui:45,
                 from <path-to-dev-dir>/devel/build/br2/host/share/cargo/registry/src/github.com-1ecc6299db9ec823/qt_gui-0.3.0/c_lib/sized_types.cxx:1:
<path-to-dev-dir>/devel/build/br2/host/aarch64-buildroot-linux-gnu/sysroot/usr/include/qt5/QtGui/qopengl.h:105:13: fatal error: GLES3/gl32.h: No such file or directory
 #   include <GLES3/gl32.h>
             ^~~~~~~~~~~~~~
compilation terminated.
make[2]: *** [CMakeFiles/sized_types.dir/build.make:66: CMakeFiles/sized_types.dir/sized_types.cxx.o] Error 1
make[1]: *** [CMakeFiles/Makefile2:71: CMakeFiles/sized_types.dir/all] Error 2
make: *** [Makefile:133: all] Error 2
Error:
   command failed with exit code: 2: "cmake" "--build" "." "--" "-j1" "install"
Riateche commented 4 years ago

Hi,

Ritual doesn't currently support any kind of cross-compilation. It seems that you need to configure the cmake project properly to do a cross-compilation of the c_lib glue library. I didn't try that, but google says you should pass -DCMAKE_TOOLCHAIN_FILE=... option to cmake and make sure your toolchain file specifies the compilers correctly.

There is no option to do this through ritual's API, but you can hack around it. The relevant code executed by the build script is here. You can clone the repository and add your cmake variable (CMAKE_TOOLCHAIN_FILE) to the actual_cmake_vars vector. Then, tell cargo to use the patched version of ritual_common by specifying the local path to it in the Cargo.toml file of your project:

[patch.crates-io.ritual_common]
path = "..."

If this turns out to be working, we'll make a more convenient way to pass this variable.

Further, it might be necessecary to re-generate my own crates to match the qt-version used on the cross target and not the host

The generated crates are able to use various Qt versions, as long as they are not too old (currently, 5.9 is the oldest supported version). Hopefully you'll be able to use the published crates.

The compiler error indicates that Qt tries to use GLES (GL for Embedded Systems) which is not available on desktops. This is correct, and the error should be fixed when cross-compilation is properly configured for c_lib.

melshuber commented 4 years ago

Look as very valuable input to me, I will try this on the weekend.

melshuber commented 4 years ago

Hi,

after adopting your suggestion into ritual_common, I managed to build a cross _clib (aarch64 in my case).

However, the executable sized_types is also included in the same CMakelists.txt, therefore I get a cross compiled version of this binary as well and the build fails when executing the file.

--- stderr
Error:
 failed to run command: "<path-to-dev-dir>/examples/target/aarch64-unknown-linux-gnu/debug/build/qt_core-d0b4448b3452fb09/out/c_lib_install/sized_types"
   Exec format error (os error 8)

I also checked sized_types.cxx in the cargo registry. It looks like, those are only c++ files with an empty main() that include Qt header.

Whats up with this binary and why are the executing? Where is the rule that executes it?

thx

Riateche commented 4 years ago

sized_types is a mechanism to request size and alignment of stack-allocated types on the current platform. Stack-allocated types turned out to be problematic in multiple ways, so they are turned off now. That's why the main() function is empty. It's not decided yet if we remove the functionality completely or leave it as an opt-in mechanism for bindings developers.

The build script calls this binary here. You can patch ritual_build to remove the get_command_output call, but create_file should be kept so that the crate still compiles.

The proper fix for that issue would be either not to call sized_types if it's empty or simply remove the feature entirely.