3

Talking about a Qt 5.3.2 project which is buildt using cmake. This is a calling order problem between UIC execution and target_link_libraries... unfortunately not in that order.

Below this text you will find

1.) a (still functional) excerpt section of my CMakeLists.txt and

2.) an excerpt of the the output of the command 'cmake .'

3.) the output of a following call to 'make' without using the generated headers like 'ui_main.h'.

If (in the source of my library libqt.a) I require 'ui_main.h' the make process crashes not finding the header. Looking at the non-crashing make output shows why:

[..]
Scanning dependencies of target qt
[ 29%] Building CXX object CMakeFiles/qt.dir/home/kochmn/projects/sentinel/src/qt/form_main.cpp.o
[ 35%] Building CXX object CMakeFiles/qt.dir/qt_automoc.cpp.o
Linking CXX static library libqt.a
[..]
[ 52%] Generating ui_main.h
[..]

Make would generate libqt.a before generating the required header file. So I experimented using code like

target_link_libraries(sentinel
  ${Qt5Widgets_LIBRARIES} ${Qt5Gui_LIBRARIES} ${Qt5Core_LIBRARIES})

add_library(optimization "${DIR_SRC}/optimization/linalg.cpp")
add_library(qt "${DIR_SRC}/qt/form_main.cpp")

target_link_libraries(sentinel qt optimization)

to no avail. The question: How can I motivate cmake to first run UIC generating the ui-header files and then compiling my libqt.a?

Appendix

# 2.8.11 instead of 2.8 required for automatic linking to the qtmain.lib
# library if this ever should expand to Windows.
# (http://doc.qt.io/qt-5/cmake-manual.html)
cmake_minimum_required(VERSION 2.8.11)

project(sentinel)

set( CMAKE_AUTOMOC ON )
# CMake uses uic in order to generate header files from .ui forms from designer.
set ( CMAKE AUTOUIC ON )
# Auto-generating functions write their headers into the build directory.
# Hence the build directory should be included.
set( CMAKE_INCLUDE_CURRENT_DIR ON )

#> Getting the Qt essentials. ----------------------------------------
# Widgets finds its own dependencies (QtGui and QtCore).
find_package(Qt5Widgets REQUIRED)

message ("Found Qt5Widgets Version ${Qt5Widgets_VERSION_STRING}")

# All those darling variables are explained here:
# http://doc.qt.io/qt-5/cmake-manual.html
message("Core    FOUND: ${Qt5Core_FOUND}")
message("Gui     FOUND: ${Qt5Gui_FOUND}")
message("Widgets FOUND: ${Qt5Widgets_FOUND}")
message("Core    VERSION: ${Qt5Core_VERSION_STRING}")
message("Gui     VERSION: ${Qt5Gui_VERSION_STRING}")
message("Widgets VERSION: ${Qt5Widgets_VERSION_STRING}")
message("Core    INCLUDE: ${Qt5Core_INCLUDE_DIRS}")
message("Gui     INCLUDE: ${Qt5Gui_INCLUDE_DIRS}")
message("Widgets INCLUDE: ${Qt5Widgets_INCLUDE_DIRS}")
message("Core    LIBRARIES: ${Qt5Core_LIBRARIES}")
message("Gui     LIBRARIES: ${Qt5Gui_LIBRARIES}")
message("Widgets LIBRARIES: ${Qt5Widgets_LIBRARIES}")
message("Core    DEFINITIONS: ${Qt5Core_DEFINITIONS}")
message("Gui     DEFINITIONS: ${Qt5Gui_DEFINITIONS}")
message("Widgets DEFINITIONS: ${Qt5Widgets_DEFINITIONS}")
message("Core    COMPILE_DEFINITIONS: ${Qt5Core_COMPILE_DEFINITIONS}")
message("Gui     COMPILE_DEFINITIONS: ${Qt5Gui_COMPILE_DEFINITIONS}")
message("Widgets COMPILE_DEFINITIONS: ${Qt5Widgets_COMPILE_DEFINITIONS}")
message("Core    EXECUTABLE_COMPILE_FLAGS: ${Qt5Core_EXECUTABLE_COMPILE_FLAGS}")
message("Gui     EXECUTABLE_COMPILE_FLAGS: ${Qt5Gui_EXECUTABLE_COMPILE_FLAGS}")
message("Widgets EXECUTABLE_COMPILE_FLAGS: ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}")

include_directories(
  ${Qt5Widgets_INCLUDE_DIRS} ${Qt5Core_INCLUDE_DIRS} ${Qt5Gui_INCLUDE_DIRS})

add_definitions(${Qt5Widgets_DEFINITIONS})
#add_definitions(${Qt5Core_DEFINITIONS}) # Unnecessary. In Widgets.
#add_definitions(${Qt5Gui_DEFINITIONS})  # Unnecessary. In Widgets.
#< -------------------------------------------------------------------

set (DEBUG 1)
set (SENTINEL_NAME "Sentinel GL")
set (SENTINEL_VERSION_MAJOR "0")
set (SENTINEL_VERSION_MINOR "1")
set (SENTINEL_VERSION "${SENTINEL_VERSION_MAJOR}.${SENTINEL_VERSION_MINOR}")

## Compiler flags
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}")
#  ${Qt5Core_EXECUTABLE_COMPILE_FLAGS} ${Qt5Gui_EXECUTABLE_COMPILE_FLAGS} #<-- redundant.

if(CMAKE_COMPILER_IS_GNUCXX)
  message("Using GnuCXX compiler.")
  add_definitions("-O0 -std=c++0x -lSOIL -llapacke -lblas")
endif()

if (DEBUG MATCHES 1)
  message("\nBuilding DEBUG build.")
  add_definitions(-Wall)
  set(CMAKE_BUILD_TYPE Debug)
endif()

set(DIR_BASE "${PROJECT_SOURCE_DIR}/..")
set(DIR_SRC "${PROJECT_SOURCE_DIR}/../src")
set(DIR_RES "${PROJECT_SOURCE_DIR}/../resources")
set(DIR_BUILD "${PROJECT_SOURCE_DIR}/../build")

# Generated using uic FormMain.ui > ui_FormMain.h
set(qt_H
  "${DIR_BUILD}/ui_main.h" "${DIR_BUILD}/ui_dialog_setup_game.h")
# Generated using the trusty QtDesigner.
set(qt_UI
  "${DIR_SRC}/ui/main.ui" "${DIR_SRC}/ui/dialog_setup_game.ui")
# My own hand-written XML describing the internal resources.
set(qt_QRC "${DIR_RES}/application.qrc")

# generate rules for building source files that moc generates
QT5_WRAP_CPP(qt_H_MOC ${qt_H})
# generate rules for building header files from the ui files
QT5_WRAP_UI(qt_UI_H ${qt_UI})
# Resource Handling. QRC: "Qt Resource Collection"
QT5_ADD_RESOURCES(qt_RCCS ${qt_QRC})
# btw.: rcc generates a C program from ./resources/application.qrc
# However, this is not needed. cmake sees to that. :-)
#< -------------------------------------------------------------------

include_directories("${DIR_SRC}/include" "${PROJECT_SOURCE_DIR}")

add_executable(sentinel "${DIR_SRC}/sentinel.cpp" ${qt_H_MOC} ${qt_UI_H} ${qt_RCCS})

# Available modules are listed here: http://doc.qt.io/qt-5/qtmodules.html
#   find /usr/lib/x86_64-linux-gnu/cmake -iname "*.cmake*" | less
# Note: http://stackoverflow.com/questions/20266235/cmake-error-qglwidget-no-such-file-or-directory
qt5_use_modules(sentinel Widgets Gui Core)

add_library(optimization "${DIR_SRC}/optimization/linalg.cpp")
add_library(qt "${DIR_SRC}/qt/form_main.cpp")

target_link_libraries(sentinel
  ${Qt5Widgets_LIBRARIES} ${Qt5Gui_LIBRARIES} ${Qt5Core_LIBRARIES}
  qt optimization
)

kochmn@Ulyss:~/projects/sentinel/build$ cmake .
-- The C compiler identification is GNU 4.9.2
-- The CXX compiler identification is GNU 4.9.2
-- 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
-- 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
Found Qt5Widgets Version 5.3.2
Core    FOUND: 1
Gui     FOUND: 1
Widgets FOUND: 1
Core    VERSION: 5.3.2
Gui     VERSION: 5.3.2
Widgets VERSION: 5.3.2
Core    INCLUDE: /usr/include/x86_64-linux-gnu/qt5/;/usr/include/x86_64-linux-gnu/qt5/QtCore;/usr/lib/x86_64-linux-gnu/qt5//mkspecs/linux-g++-64
Gui     INCLUDE: /usr/include/x86_64-linux-gnu/qt5/;/usr/include/x86_64-linux-gnu/qt5/QtGui;/usr/include/x86_64-linux-gnu/qt5/QtCore;/usr/lib/x86_64-linux-gnu/qt5//mkspecs/linux-g++-64
Widgets INCLUDE: /usr/include/x86_64-linux-gnu/qt5/;/usr/include/x86_64-linux-gnu/qt5/QtWidgets;/usr/include/x86_64-linux-gnu/qt5/QtGui;/usr/include/x86_64-linux-gnu/qt5/QtCore;/usr/lib/x86_64-linux-gnu/qt5//mkspecs/linux-g++-64
Core    LIBRARIES: Qt5::Core
Gui     LIBRARIES: Qt5::Gui
Widgets LIBRARIES: Qt5::Widgets
Core    DEFINITIONS: -DQT_CORE_LIB
Gui     DEFINITIONS: -DQT_GUI_LIB;-DQT_CORE_LIB
Widgets DEFINITIONS: -DQT_WIDGETS_LIB;-DQT_GUI_LIB;-DQT_CORE_LIB
Core    COMPILE_DEFINITIONS: QT_CORE_LIB
Gui     COMPILE_DEFINITIONS: QT_GUI_LIB;QT_CORE_LIB
Widgets COMPILE_DEFINITIONS: QT_WIDGETS_LIB;QT_GUI_LIB;QT_CORE_LIB
Core    EXECUTABLE_COMPILE_FLAGS: -fPIE
Gui     EXECUTABLE_COMPILE_FLAGS: -fPIE
Widgets EXECUTABLE_COMPILE_FLAGS: -fPIE
Using GnuCXX compiler.

Building DEBUG build.

Sentinel GL -- C++ Project V 0.1.

(c) Markus-Hermann Koch, mhk@markuskoch.eu, 2015/04/28-?

Primary directory is /home/kochmn/projects/sentinel/build
System is Linux
Generating configuration header: "/home/kochmn/projects/sentinel/build/../build/mhk_cmake_config.h"
-- Configuring done
-- Generating done
-- Build files have been written to: /home/kochmn/projects/sentinel/build

kochmn@Ulyss:~/projects/sentinel/build$ make 
Scanning dependencies of target optimization_automoc
[  5%] Automatic moc for target optimization
[  5%] Built target optimization_automoc
Scanning dependencies of target optimization
[ 11%] Building CXX object CMakeFiles/optimization.dir/home/kochmn/projects/sentinel/src/optimization/linalg.cpp.o
[ 17%] Building CXX object CMakeFiles/optimization.dir/optimization_automoc.cpp.o
Linking CXX static library liboptimization.a
[ 17%] Built target optimization
Scanning dependencies of target qt_automoc
[ 23%] Automatic moc for target qt
[ 23%] Built target qt_automoc
Scanning dependencies of target qt
[ 29%] Building CXX object CMakeFiles/qt.dir/home/kochmn/projects/sentinel/src/qt/form_main.cpp.o
[ 35%] Building CXX object CMakeFiles/qt.dir/qt_automoc.cpp.o
Linking CXX static library libqt.a
[ 35%] Built target qt
Scanning dependencies of target sentinel_automoc
[ 41%] Automatic moc for target sentinel
[ 41%] Built target sentinel_automoc
[ 47%] Generating qrc_application.cpp
[ 52%] Generating ui_main.h
[ 58%] Generating moc_ui_main.cpp
/home/kochmn/projects/sentinel/build/ui_main.h:0: Note: No relevant classes found. No output generated.
[ 64%] Generating ui_dialog_setup_game.h
[ 70%] Generating moc_ui_dialog_setup_game.cpp
/home/kochmn/projects/sentinel/build/ui_dialog_setup_game.h:0: Note: No relevant classes found. No output generated.
Scanning dependencies of target sentinel
[ 76%] Building CXX object CMakeFiles/sentinel.dir/home/kochmn/projects/sentinel/src/sentinel.cpp.o
[ 82%] Building CXX object CMakeFiles/sentinel.dir/moc_ui_main.cpp.o
[ 88%] Building CXX object CMakeFiles/sentinel.dir/moc_ui_dialog_setup_game.cpp.o
[ 94%] Building CXX object CMakeFiles/sentinel.dir/qrc_application.cpp.o
[100%] Building CXX object CMakeFiles/sentinel.dir/sentinel_automoc.cpp.o
Linking CXX executable sentinel
[100%] Built target sentinel
Markus-Hermann
  • 789
  • 11
  • 24

1 Answers1

3

CMake generation order is computed from dependencies between files and targets. If your qt library depends on headers generated from .ui files, then you have to add ${qt_UI_H} in inputs of target qt:

QT5_WRAP_UI(qt_UI_H ${qt_UI})
[...]
add_library(qt "${DIR_SRC}/qt/form_main.cpp" ${qt_UI_H})

And CMake should normally execute UIC on .ui files before compiling libqt

By the way using target_link_libraries only set dependencies between targets at link time. At compile time, the normal behavior is "All source files should be found". In your case, some headers are generated, so setting these headers as input of a target ensures that the macro which generates them (QT5_WRAP_UI) will be executed before the compilation of the target.

Antwane
  • 20,760
  • 7
  • 51
  • 84
  • This actually works! Adding ${qt_UI_H} did the trick. I am baffled that cmake is intelligent enough to determine that now UIC needs to be called first. But apparently it is! In any case: Thanks for your speedy help! :-) – Markus-Hermann Apr 30 '15 at 13:26
  • CMake is a powerful tool. Sometimes capricious, but useful ;) – Antwane Apr 30 '15 at 13:30