3
votes

There are various ways to cross-compile to Raspberry Pi, and there are also solutions posted for cross-compiling Qt or opencv.

However, I couldn't find any solution to cross-compile a program with Qt which also uses opencv.

I tried the following, using debian on a 64-bit PC:

  • I compiled and set up Qt as a cross-compiler to ARM7, using this tutorial. It didn't work without issues though, here is an answer I posted which solved it for me. I can now run my Qt programs with graphical GUI on the Raspberry Pi (although only full-screen, but that's a completely different issue)

  • I followed the guide on the official opencv website to build opencv. It failed with No CMAKE_CXX_COMPILER could be found.

  • Knowing from experience (I used Qt with opencv both on Windows and Linux) that Qt and opencv work together only if both are compiled with the same compiler, I tried to use the same cross-compiler for opencv which I used successfully to compile Qt: gcc-4.7-linaro-rpi-gnueabihf

  • I specified the gnueabihf I previously used to compile Qt, as the compiler:

I created the directory ~/opt/opencv_build_arm7/ and in it, I tried:

sudo cmake -DCMAKE_CXX_COMPILER=/home/<user>/opt/gcc-4.7-linaro-rpi-gnueabihf/bin/arm-linux-gnueabihf-g++ -DCMAKE_C_COMPILER=/home/<user>/opt/gcc-4.7-linaro-rpi-gnueabihf/bin/arm-linux-gnueabihf-gcc -DCMAKE_TOOLCHAIN_FILE=/usr/dev/opencv/platforms/linux/arm-gnueabi.toolchain.cmake /usr/dev/opencv/

(Where the downloaded opencv sources were in /usr/dev/opencv/ which I recently used successfully to compile opencv for an x64 platform, using the g++ compiler which came with my Qt installation.) Note, that <user> is the username for the current session, in case other beginners might try these methods in the future.

This failed with the following error (where <user> is my username)

CMake Error at /usr/share/cmake-3.0/Modules/CMakeTestCXXCompiler.cmake:54 (message): The C++ compiler
"/home//opt/gcc-4.7-linaro-rpi-gnueabihf/bin/arm-linux-gnueabihf-g++" is not able to compile a simple test program.

It fails with the following output :

Change Dir: /home//temp/CMakeFiles/CMakeTmp

Run Build Command:"/usr/bin/make" "cmTryCompileExec117178613/fast"

/usr/bin/make -f CMakeFiles/cmTryCompileExec117178613.dir/build.make CMakeFiles/cmTryCompileExec117178613.dir/build

make1: Entering directory '/home//temp/CMakeFiles/CMakeTmp'

/usr/bin/cmake -E cmake_progress_report
/home//temp/CMakeFiles/CMakeTmp/CMakeFiles 1

Building CXX object
CMakeFiles/cmTryCompileExec117178613.dir/testCXXCompiler.cxx.o

/home//opt/gcc-4.7-linaro-rpi-gnueabihf/bin/arm-linux-gnueabihf-g++ -mthumb -fdata-sections -Wa,--noexecstack -fsigned-char -Wno-psabi -mthumb -fdata-sections -Wa,--noexecstack -fsigned-char -Wno-psabi -o CMakeFiles/cmTryCompileExec117178613.dir/testCXXCompiler.cxx.o -c /home//temp/CMakeFiles/CMakeTmp/testCXXCompiler.cxx

/home//temp/CMakeFiles/CMakeTmp/testCXXCompiler.cxx: In function ‘int main()’:

/home//temp/CMakeFiles/CMakeTmp/testCXXCompiler.cxx:4:10: sorry, unimplemented: Thumb-1 hard-float VFP ABI

CMakeFiles/cmTryCompileExec117178613.dir/build.make:57: recipe for target
'CMakeFiles/cmTryCompileExec117178613.dir/testCXXCompiler.cxx.o' failed

make1: ***
[CMakeFiles/cmTryCompileExec117178613.dir/testCXXCompiler.cxx.o] Error 1

make1: Leaving directory '/home//temp/CMakeFiles/CMakeTmp'

Makefile:118: recipe for target 'cmTryCompileExec117178613/fast' failed

make: *** [cmTryCompileExec117178613/fast] Error 2

I specified an absolute path for the compiler, but even if I don't specify it, and just add it to my $PATH, it still has the same problem.

export PATH=$PATH:/home/<user>/opt/gcc-4.7-linaro-rpi-gnueabihf/bin/

sudo cmake -DCMAKE_TOOLCHAIN_FILE=/usr/dev/opencv/platforms/linux/arm-gnueabi.toolchain.cmake /usr/dev/opencv/

The compiler itself is found correctly, if I type

arm-linux-gnueabihf-g++ -v

it is found successfully:

Using built-in specs. COLLECT_GCC=./arm-linux-gnueabihf-c++ COLLECT_LTO_WRAPPER=/home/vszabi/opt/gcc-4.7-linaro-rpi-gnueabihf/bin/../libexec/gcc/arm-linux-gnueabihf/4.7.2/lto-wrapper Target: arm-linux-gnueabihf Configured with: /opt/dev/src/crosstool-ng/crosstool-ng-linaro-1.13.1-2012.07-20120720/builds/arm-linux-gnueabihf-linux/.build/src/gcc-linaro-4.7-2012.07/configure --build=i686-build_pc-linux-gnu --host=i686-build_pc-linux-gnu --target=arm-linux-gnueabihf --prefix=/opt/dev/src/crosstool-ng/crosstool-ng-linaro-1.13.1-2012.07-20120720/builds/arm-linux-gnueabihf-linux/install --with-sysroot=/opt/dev/src/crosstool-ng/crosstool-ng-linaro-1.13.1-2012.07-20120720/builds/arm-linux-gnueabihf-linux/install/arm-linux-gnueabihf/libc --enable-languages=c,c++,fortran --enable-multilib --with-arch=armv6zk --with-tune=arm1176jzf-s --with-fpu=vfp --with-float=hard --with-pkgversion='crosstool-NG linaro-1.13.1-2012.07-20120720 - Linaro GCC 2012.07' --with-bugurl=https://bugs.launchpad.net/gcc-linaro --enable-__cxa_atexit --enable-libmudflap --enable-libgomp --enable-libssp --with-gmp=/opt/dev/src/crosstool-ng/crosstool-ng-linaro-1.13.1-2012.07-20120720/builds/arm-linux-gnueabihf-linux/.build/arm-linux-gnueabihf/build/static --with-mpfr=/opt/dev/src/crosstool-ng/crosstool-ng-linaro-1.13.1-2012.07-20120720/builds/arm-linux-gnueabihf-linux/.build/arm-linux-gnueabihf/build/static --with-mpc=/opt/dev/src/crosstool-ng/crosstool-ng-linaro-1.13.1-2012.07-20120720/builds/arm-linux-gnueabihf-linux/.build/arm-linux-gnueabihf/build/static --with-ppl=/opt/dev/src/crosstool-ng/crosstool-ng-linaro-1.13.1-2012.07-20120720/builds/arm-linux-gnueabihf-linux/.build/arm-linux-gnueabihf/build/static --with-cloog=/opt/dev/src/crosstool-ng/crosstool-ng-linaro-1.13.1-2012.07-20120720/builds/arm-linux-gnueabihf-linux/.build/arm-linux-gnueabihf/build/static --with-libelf=/opt/dev/src/crosstool-ng/crosstool-ng-linaro-1.13.1-2012.07-20120720/builds/arm-linux-gnueabihf-linux/.build/arm-linux-gnueabihf/build/static --with-host-libstdcxx='-L/opt/dev/src/crosstool-ng/crosstool-ng-linaro-1.13.1-2012.07-20120720/builds/arm-linux-gnueabihf-linux/.build/arm-linux-gnueabihf/build/static/lib -lpwl' --enable-threads=posix --disable-libstdcxx-pch --enable-linker-build-id --enable-gold --with-local-prefix=/opt/dev/src/crosstool-ng/crosstool-ng-linaro-1.13.1-2012.07-20120720/builds/arm-linux-gnueabihf-linux/install/arm-linux-gnueabihf/libc --enable-c99 --enable-long-long Thread model: posix gcc version 4.7.2 20120701 (prerelease) (crosstool-NG linaro-1.13.1-2012.07-20120720 - Linaro GCC 2012.07)

What could I try next? Opening the gui version of cmake with opencv/platforms/linux/arm-gnueabi.toolchain.cmake shows very few options (only ARM_LINUX_SYSROOT, CMAKE_BUILD_TYPE, CMAKE_CONFIGURATION_TYPES, CMAKE_INSTALL_PREFIX, GCC_COMPILER_VERSION and LIBRARY_OUTPUT_PATH_ROOT, but none of the BUILD_opencv_xyz with which I can disable individual packages), much fewer than the case when I built opencv for an x86 or x64 platform.

I'm afraid that searching for a different compiler might cause issues with Qt, because as far as I know, for opencv to work within Qt, it has to be compiled with the same compiler as what is used both to build the Qt libraries and build my program. Whenever I tried it in the past without being careful that these 3 things (Qt libs, opencv, my program) need to be compiled with the same compiler, I always experienced weird crashes either as soon as I included any opencv header, or whenever I called any function from opencv.

1

1 Answers

3
votes

The tutorial at http://docs.opencv.org/doc/tutorials/introduction/crosscompilation/arm_crosscompile_with_cmake.html seems to be either wrong or out of date.

Downloading the source of opencv 3.0, the opencv/platforms/linux/arm-gnueabi.toolchain.cmake seems to be insufficiently configured for the Raspberry Pi.

Configure

Visiting the workgroup page of the creators of the arm-linux-gnueabihf toolchain, it seems that for the ARM7 in the Raspberry Pi to be supported, the following options have to be passed to the compiler: -mcpu=cortex-a7 -mfloat-abi=hard -mfpu=vfpv4

So, we have to edit the opencv/platforms/linux/arm-gnueabi.toolchain.cmake file and change

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mthumb -fdata-sections -Wa,--noexecstack -fsigned-char -Wno-psabi")
set(CMAKE_C_FLAGS   "${CMAKE_C_FLAGS} -mthumb -fdata-sections -Wa,--noexecstack -fsigned-char -Wno-psabi")

to

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mthumb -fdata-sections -Wa,--noexecstack -fsigned-char -Wno-psabi -mcpu=cortex-a7 -mfloat-abi=hard -mfpu=vfpv4")
set(CMAKE_C_FLAGS   "${CMAKE_C_FLAGS} -mthumb -fdata-sections -Wa,--noexecstack -fsigned-char -Wno-psabi -mcpu=cortex-a7 -mfloat-abi=hard -mfpu=vfpv4")

running cmake again, the configuration was successfully completed!

Make

During the building process, if the following error appears

CMakeFiles/opencv_core.dir/src/rand.cpp.o: relocation R_ARM_THM_MOVW_ABS_NC against `a local symbol' can not be used when making a shared object; recompile with -fPIC CMakeFiles/opencv_core.dir/src/rand.cpp.o: could not read symbols: Bad value

just add the -fPIC flag to the CMAKE_C_FLAGS and CMAKE_CXX_FLAGS in the cmake file and run make again.

Deployement

Using Qt Creator to deploy, just set up the headers and libraries in your .pro file, for example:

INCLUDEPATH += <your build dir>/install/include/opencv2/
INCLUDEPATH += <your build dir>/install/include/
LIBS += -L  "<your build dir>/install/lib/"
LIBS += -lopencv_calib3d
LIBS += -lopencv_core
#... and so on

You also have to copy the compiled libraries (found in <your build dir>/install/lib/) to the Raspberry Pi. Using a USB stick might mess up the symlinks, so I would recommend using scp to copy the files.

If you are relatively new to Linux (just as myself), don't forget that executables don't automatically look into their own folders for dynamic libraries as they did in Windows.

Therefore you should either copy the libraries to a place which is usually searched for them (like /usr/local/bin) or update your LD_LIBRARY_PATH accordingly.

For a quick and dirty test, to see if everything works, you might copy the libraries into the same folder where your executable is deployed, and run it by using

$ LD_LIBRARY_PATH=. ./your_program

Testing

Opencv should work now in your Qt program on the Raspberry Pi.

Unless my google-fu is very weak, this might be the first documented case of running a Qt GUI application on a Raspberry Pi with opencv working in it. :)

However, note that there might still be some issues with window management. Trying to open an opencv window, for example, cv::namedWindow("image"); might fail with the following error:

OpenCV Error: Unspecified error (The function is not implemented. Rebuild the library with Windows, GTK+ 2.x or Carbon support. If you are on Ubuntu or Debian, install libgtk2.0-dev and pkg-config, then re-run cmake or configure script) in cvNamedWindow, file /usr/dev/opencv/modules/highgui/src/window.cpp, line 516 terminate called after throwing an instance of 'cv::Exception' what(): /usr/dev/opencv/modules/highgui/src/window.cpp:516: error: (-2) The function is not implemented. Rebuild the library with Windows, GTK+ 2.x or Carbon support. If you are on Ubuntu or Debian, install libgtk2.0-dev and pkg-config, then re-run cmake or configure script in function cvNamedWindow

I guess we should do as it says, but cvNamedWindow is not very useful in a Qt GUI application, as it's usually only required for debugging. Therefore if the image has to be shown in your application, converting it to QImage might be better anyway than opening up an independent window.

However, everything else seems to work, I managed to successfully run complicated image matching algorithms on the Raspberry Pi.

(... will update if I find a good solution for running the Qt application in a window and using cvNamedWindow)