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
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
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.
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?
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).
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?