UIC binding and ordering in CMake Qt project

Talking about a Qt 5.3.2 project that is built using cmake. This is the issue of calling the call between the execution of the UIC and target_link_libraries ... unfortunately not in that order.

Below this text you will find

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

2.) excerpt from the 'cmake.' Command output

3.) the output of the next call to "make" without using generated headers such as "ui_main.h".

If (in my libqt.a source), I require 'ui_main.h' to make the process crash without 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 will generate libqt.a before generating the required header file. So I experimented with 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. Question: how can I motivate cmake to first launch the UIC by generating the ui-header files and then compile the libqt.a file?

application

# 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

      

+3


source to share


1 answer


The CMake generation order is calculated from the dependencies between files and targets. If your qt library depends on headers generated from .ui files, then you should add the ${qt_UI_H}

target to the inputs 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, when used target_link_libraries

, dependencies are established between targets at connection time . At compile time, the normal behavior is "All source files must be found". In your case, some headers are generated, so setting those headers as the input to the target ensures that the macro that generates them (QT5_WRAP_UI) is executed before the target is compiled.

+3


source







All Articles