Linking problem when trying to cross-compile a qt application using cmake - c++

I'm currently switching the build system of my Qt application from qmake to cmake. While trying to cross-compile for Windows with MinGW (static Qt build), I came across a strange problem I cannot explain:
CMakeLists.txt:
project(noble)
cmake_minimum_required(VERSION 2.8.5)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
find_package(Boost COMPONENTS program_options thread REQUIRED)
find_package(Qt4 REQUIRED QtCore QtGui)
find_package(BLAS REQUIRED)
find_package(LAPACK REQUIRED)
find_package(Armadillo)
find_package(Qwt6 REQUIRED)
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR})
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR})
include(${QT_USE_FILE})
set(LIBRARIES
${Qwt6_Qt4_LIBRARY}
${QT_QTCORE_LIBRARY}
${QT_QTGUI_LIBRARY}
${Boost_LIBRARIES}
${BLAS_LIBRARIES}
${LAPACK_LIBRARIES}
)
set(DEFINITIONS
${QT_DEFINITIONS}
${BLAS_LINKER_FLAGS}
${LAPACK_LINKER_FLAGS}
-DBOOST_THREAD_USE_LIB
)
add_subdirectory(src)
add_subdirectory(plugins)
src/CMakeLists.txt:
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(noble_SOURCES
#file names...
)
set(noble_HEADERS
#file names...
)
set(noble_FORMS
#file names...
)
QT4_WRAP_UI(noble_FORMS_HEADERS ${noble_FORMS})
QT4_WRAP_CPP(noble_HEADERS_MOC ${noble_HEADERS})
include_directories(
${Boost_INCLUDE_DIRS}
${ARMADILLO_INCLUDE_DIRS}
${Qwt6_INCLUDE_DIR}
)
add_definitions(${DEFINITIONS})
add_executable(noble
${noble_SOURCES}
${noble_HEADERS_MOC}
${noble_FORMS_HEADERS}
)
target_link_libraries(noble
${LIBRARIES}
-lQtGui -lQtCore
-ljpeg -lpng -ltiff -lmng -lz -limm32 -llcms -lwinmm
-fopenmp
)
I am now trying to get rid of the manually set compiler flags right in the end. If I omit the -lQtGui -lQtCore I get a whole bunch of undefined references like
/home/mjung/Programme/mingw-cross-env-2.21/usr/lib/gcc/i686-pc-mingw32/4.6.0/../../../../i686-pc-mingw32/lib/libQtGui.a(qapplication.o):qapplication.cpp:(.text+0x2340): undefined reference to `QBasicTimer::stop()'
If i keep these flags, the program compiles fine.
The strange thing now is the following:
cmake's g++ call with -lQtGui -lQtCore flags:
/home/mjung/Programme/mingw-cross-env-2.21/usr/bin/i686-pc-mingw32-g++
-Wl,--whole-archive
CMakeFiles/noble.dir/objects.a
-Wl,--no-whole-archive
-o ../noble.exe
-Wl,--out-implib,../libnoble.dll.a
-Wl,--major-image-version,0,--minor-image-version,0
/home/mjung/Programme/windows_builds/usr/lib/libqwt.a
-Wl,-Bstatic
-lQtCore -lQtGui
-lboost_program_options-mt
-lboost_thread-mt
-Wl,-Bdynamic
/home/mjung/Programme/windows_builds/usr/lib/libblas.a
/home/mjung/Programme/windows_builds/usr/lib/liblapack.a
/home/mjung/Programme/windows_builds/usr/lib/libblas.a
-lQtGui -lQtCore
-ljpeg -lpng -ltiff -lmng -lz -limm32 -llcms -lwinmm
-fopenmp
/home/mjung/Programme/windows_builds/usr/lib/liblapack.a
-lQtGui -lQtCore
-ljpeg -lpng -ltiff -lmng -lz -limm32 -llcms -lwinmm
-lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32
cmake's g++ call without -lQtGui -lQtCore flags:
/home/mjung/Programme/mingw-cross-env-2.21/usr/bin/i686-pc-mingw32-g++
-Wl,--whole-archive
CMakeFiles/noble.dir/objects.a
-Wl,--no-whole-archive
-o ../noble.exe
-Wl,--out-implib,../libnoble.dll.a
-Wl,--major-image-version,0,--minor-image-version,0
/home/mjung/Programme/windows_builds/usr/lib/libqwt.a
-Wl,-Bstatic
-lQtCore -lQtGui
-lboost_program_options-mt
-lboost_thread-mt
-Wl,-Bdynamic
/home/mjung/Programme/windows_builds/usr/lib/libblas.a
/home/mjung/Programme/windows_builds/usr/lib/liblapack.a
/home/mjung/Programme/windows_builds/usr/lib/libblas.a
-ljpeg -lpng -ltiff -lmng -lz -limm32 -llcms -lwinmm
-fopenmp
/home/mjung/Programme/windows_builds/usr/lib/liblapack.a
-ljpeg -lpng -ltiff -lmng -lz -limm32 -llcms -lwinmm
-lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32
Even if I do not set the compiler flags manually the FindQt4.cmake script still sets them. But this doesn't seem to be enough. I absolutely don't understand why it makes a difference if the flags are set once automatically, or three times, if I add them manually. Does this have something to do with the order of the flags?
Do you have any ideas? Any help is appreciated.
UPDATE:
Nevermind...
I just changed the order of the libraries from
set(LIBRARIES
${Qwt6_Qt4_LIBRARY}
${QT_QTCORE_LIBRARY}
${QT_QTGUI_LIBRARY}
${Boost_LIBRARIES}
${BLAS_LIBRARIES}
${LAPACK_LIBRARIES}
)
to
set(LIBRARIES
${Qwt6_Qt4_LIBRARY}
${QT_QTGUI_LIBRARY}
${QT_QTCORE_LIBRARY}
${Boost_LIBRARIES}
${BLAS_LIBRARIES}
${LAPACK_LIBRARIES}
)
I do not quite understand why it has to be this way round, but now it works...
PS: I would have posted this as an answer, but I am not allowed to do so yet, due to lack of reputation.

Many architectures do a single pass through the library list when linking. i.e. If you have an undefined symbol, a library that's later in the link list must define it. The linker won't search 'backwards' through the library list to resolve the symbol.
In this case, QtGui has a dependency on QtCore. QtCore therefore must appear after QtGui in the link list.
The easiest way around this is to use the ${QT_LIBRARIES} cmake variable that gets magically defined when you do the FIND_PACKAGE(Qt4...). It has all the relevant Qt libs in the right order for the link.
FindQt4 CMake documentation

Related

How to resolve the circular dependency problem between freetype and harfbuzz libraries?

I am currently trying to compile a static C++ application on Linux for Windows. I am using the x86_64-w64-mingw32.static-g++ compiler and used mxe to install the static 64bit versions of the libraries sdl2, sdl2_image, sdl2_ttf and boost. I keep running into these errors, and I think it has something to do with the circular dependency between freetype and harfbuzz:
/home/user/.mxe/usr/bin/x86_64-w64-mingw32.static-ld: /home/user/.mxe/usr/lib/gcc/x86_64-w64-mingw32.static/11.2.0/../../../../x86_64-w64-mingw32.static/lib/../lib/libharfbuzz.a(libharfbuzz_la-hb-ft.o):hb-ft.cc:(.text+0x11fd): undefined reference to `FT_Get_MM_Var'
/home/user/.mxe/usr/bin/x86_64-w64-mingw32.static-ld: /home/user/.mxe/usr/lib/gcc/x86_64-w64-mingw32.static/11.2.0/../../../../x86_64-w64-mingw32.static/lib/../lib/libharfbuzz.a(libharfbuzz_la-hb-ft.o):hb-ft.cc:(.text+0x126b): undefined reference to `FT_Get_Var_Blend_Coordinates'
/home/user/.mxe/usr/bin/x86_64-w64-mingw32.static-ld: /home/user/.mxe/usr/lib/gcc/x86_64-w64-mingw32.static/11.2.0/../../../../x86_64-w64-mingw32.static/lib/../lib/libharfbuzz.a(libharfbuzz_la-hb-ft.o):hb-ft.cc:(.text+0x1366): undefined reference to `FT_Done_MM_Var'
/home/user/.mxe/usr/bin/x86_64-w64-mingw32.static-ld: /home/user/.mxe/usr/lib/gcc/x86_64-w64-mingw32.static/11.2.0/../../../../x86_64-w64-mingw32.static/lib/../lib/libharfbuzz.a(libharfbuzz_la-hb-ft.o):hb-ft.cc:(.text+0x1676): undefined reference to `FT_Set_Var_Blend_Coordinates'
This is the part of my Makefile in which I add the libraries:
WIN_STATIC_LIB = -lmingw32 -lSDL2main -lSDL2 -lSDL2_image -lSDL2_ttf -lfreetype -lfontconfig -lcairo -lharfbuzz -lbz2 -lstdc++ -lm -ldinput8 -ldxguid -ldxerr8 -luser32 -lgdi32 -lwinmm -limm32 -lole32 -loleaut32 -lshell32 -lversion -luuid -lsetupapi -lwebp -lpng -lz -ljpeg -lSDL2_test -lsamplerate

Lib SDL C++ Why wont my app compile with -static and libc

I am trying to learn how to use SDL and I've been trying to get my app to run on other systems. when I try to compile using g++ -I src/include -L src/lib -o main main.cpp -lmingw32 -lSDL2main -lSDL2 -static-libgcc -static-libstdc++ -static I get a massive bunch of SDL errors saying undefined and the app doesn't finish compiling. However when running without -static it will compile but not include libc. How would I fix this issue while still being able to run on other systems without them installed?
I am also using MinGW-w64 for GCC
You're missing some flags. Running pkg-config --libs --static sdl2 will tell you the right flags.
If you don't have pkg-config installed (you could get it from MSYS2), you can look up the flags manually in the file called sdl2.pc, which is shipped with SDL2.
For me this command prints -L/mingw64/lib -lSDL2main -lmingw32 -lSDL2main -lSDL2 -mwindows -lmingw32 -ldinput8 -lshell32 -lsetupapi -ladvapi32 -luuid -lversion -loleaut32 -lole32 -limm32 -lwinmm -lgdi32 -luser32 -lm -Wl,--no-undefined -lmingw32 -lSDL2main -lSDL2 -mwindows.
You also need -static, even though it doesn't appear in the output. You can remove -static-libgcc -static-libstdc++, since they're implied by -static.

The exe file build through cmake throws an error on another computer. (missing dll error)

On the computer where it was built, it runs fine, but on other computers an error saying that the DLL could not be found appears.
this is my CMakeLists.txt file:
find_package(SDL2 REQUIRED)
find_library(SDL_MIXER_LIBRARY
NAMES SDL2_mixer
HINTS
ENV SDLMIXERDIR
ENV SDLDIR
PATH_SUFFIXES lib
)
target_link_libraries(SpaceCadetPinball SDL2::SDL2 SDL2_mixer)
target_compile_options(SpaceCadetPinball PUBLIC -lmingw64 -lSDL2main -lSDL2 -lSDL2_mixer -mwindows -lm -ldinput8 -ldxguid -ldxerr8 -luser32 -lgdi32 -lwinmm -limm32 -lole32 -loleaut32 -lshell32 -lversion -luuid -static-libgcc)
error list:
SDL2_mixer.dll
libstdc++-6.dll
libwinpthread-1.dll
libgcc_s_seh-1.dll
How do I build these as static libraries so that I can use them on other machines?

Hundreds of "undefined reference" errors when linking Qt application

I am trying to cross-compile a Qt application for Windows using mingw-w64 on Linux. Everything compiles smoothly until the linking stage; I'm getting hundreds of "undefined reference" errors having to do with Qt libraries. Here is a sample: http://pastebin.com/b20Ede7a
Here's my .pro file:
TEMPLATE = app
TARGET = myApp
DEPENDPATH += . res src
QT += core gui
CONFIG += static
isEmpty(TTS_ENGINE) {
TTS_ENGINE = flite
}
QMAKE_CXX = i686-w64-mingw32.static-g++
QMAKE_LD = i686-w64-mingw32.static-ld
QMAKE_CXXFLAGS += -std=c++0x -ggdb -DWINDOWS
QMAKE_LIBDIR += /opt/mxe/usr/i686-w64-mingw32.static/qt/lib /opt/mxe/usr/i686-w64-mingw32.static/lib
QMAKE_LIBS += -lSDL2_image -lSDL2_mixer -lpng -lz -ljpeg -lwebp -ltiff -lfreetype -lSDL2_ttf -llua `sdl2-config --libs` -lgif -lfontconfig -lm
INCLUDEPATH += . src /opt/mxe/usr/i686-w64-mingw32.static/qt/include /opt/mxe/usr/i686-w64-mingw32.static/include /opt/mxe/usr/i686-w64-mingw32.static/include/freetype2
# Input
HEADERS += bunch/of/headers
FORMS += res/desc.ui
RESOURCES += res/desc.res
SOURCES += bunch/of/sources
What could be the cause of this problem? I am using static Qt4 from MXE.
Edit: Also, here is the output of i686-w64-mingw32.static-g++ -v:
Using built-in specs.
COLLECT_GCC=/opt/mxe/usr/bin/i686-w64-mingw32.static-g++
COLLECT_LTO_WRAPPER=/opt/mxe/usr/libexec/gcc/i686-w64-mingw32.static/4.9.2/lto-wrapper
Target: i686-w64-mingw32.static
Configured with: /opt/mxe/tmp-gcc-i686-w64-mingw32.static/gcc-4.9.2/configure --target=i686-w64-mingw32.static --build=i686-pc-linux-gnu --prefix=/opt/mxe/usr --libdir=/opt/mxe/usr/lib --enable-languages=c,c++,objc,fortran --enable-version-specific-runtime-libs --with-gcc --with-gnu-ld --with-gnu-as --disable-nls --disable-shared --disable-multilib --without-x --disable-win32-registry --enable-threads=win32 --disable-libgomp --with-cloog=/opt/mxe/usr --with-gmp=/opt/mxe/usr --with-isl=/opt/mxe/usr --with-mpc=/opt/mxe/usr --with-mpfr=/opt/mxe/usr --with-as=/opt/mxe/usr/bin/i686-w64-mingw32.static-as --with-ld=/opt/mxe/usr/bin/i686-w64-mingw32.static-ld --with-nm=/opt/mxe/usr/bin/i686-w64-mingw32.static-nm
Thread model: win32
gcc version 4.9.2 (GCC)
And the failing link command (sorry about the single line):
i686-w64-mingw32.static-g++ -Wl,-s -mthreads -Wl,-subsystem,windows -o release/descend.exe object_script.descend.Release -L'/opt/mxe/usr/i686-w64-mingw32.static/qt/lib' -L'/opt/mxe/usr/i686-w64-mingw32.static/lib' -L'/opt/mxe/usr/i686-w64-mingw32.static/qt/lib' -lSDL2_image -lSDL2_mixer -lwebp -lfreetype -lSDL2_ttf -llua `sdl2-config --libs` -lgif -lfontconfig -lflite_cmu_us_kal -lflite_cmu_time_awb -lflite_cmu_us_kal16 -lflite_cmu_us_awb -lflite_cmu_us_rms -lflite_cmu_us_slt -lflite_usenglish -lflite_cmu_indic_lang -lflite_cmu_grapheme_lang -lflite_cmulex -lflite_cmu_indic_lex -lflite_cmu_grapheme_lex -lflite -lmingw32 -lqtmain -lQtGui -lgdi32 -lcomdlg32 -loleaut32 -limm32 -lwinmm -lwinspool -lmsimg32 -lmng -llcms2 -lm -ltiff -llzma -ljpeg -lQtCore -lpng -lole32 -luuid -lws2_32 -ladvapi32 -lshell32 -luser32 -lkernel32 -lz
I think your libQtCore.a archive is compiled using a different version of g++. Currently it is trying to use it from the following path at the link step:
/opt/mxe/usr/i686-w64-mingw32.static/qt/lib/libQtCore.a
If you do not mean to use this version, then specify the path to libQtCore.a at the link step (that is compiled using the same version of gcc).

Can link against a dll using CMake but not qmake

I want to build a simple Qt project on Windows which consists of one main.cpp file and a dll.
I have no problems with building it using CMake:
project(app)
cmake_minimum_required(VERSION 2.6.0)
find_package(Qt4 REQUIRED QtCore QtGui QtXml)
...
add_executable(app main.cpp)
target_link_libraries(app ${QT_LIBRARIES} my_dll.dll)
Then I try to build it using qmake:
...
SOURCES += main.cpp
win32:{
LIBS += -L"my_dll.dll"
}
In this case the build fails and I get linker errors like undefined reference to 'my_function#8', where my_function is a function in my_dll.dll.
When I open my_dll.dll with Dependency Walker I can see that all function names are not decorated. I don't know why qmake tries to resolve function names with '#8' at the end.
This is what CMake writes to the log on linking:
C:\MinGW\bin\g++.exe -g -Wl,--whole-archive CMakeFiles\app.dir/objects.a -Wl,--no-whole-archive -o app.exe -Wl,--out-implib,libapp.dll.a -Wl,--major-image-version,0,--minor-image-version,0 C:\QT\2010.02.1\qt\lib\libQtGuid4.a C:\QT\2010.02.1\qt\lib\libQtXmld4.a C:\QT\2010.02.1\qt\lib\libQtCored4.a -l,my_dll -lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32
Also it gives some warnings:
Warning: resolving _my_fucntion#8 by linking to _my_function
Use --enable-stdcall-fixup to disable these warnings
Use --disable-stdcall-fixup to disable these fixups
And this is what qmake says:
g++ -enable-stdcall-fixup -Wl,-enable-auto-import -Wl,-enable-runtime-pseudo-reloc -mthreads -Wl -o debug/aap1.exe debug/main.o -L'c:/Qt/2010.02.1/qt/lib' -lmingw32 -lqtmaind -Lmy_dll.dll -lQtXmld4 -lQtGuid4 -lQtCored4
How can I build my project using qmake?