Использование CMake с Qt 5

  • Tutorial
image

CMake — это система сборки ПО (точнее генерации файлов управления сборкой), широко используемая с Qt. При создании больших или сложных проектов, выбор CMake будет более предпочтительным, нежели использование qmake. KDE когда-то был переломным моментом в популярности CMake как таковой, после чего свою «лепту» внес Qt 4. В Qt 5 поддержка CMake была значительно улучшена.

Поиск и подключение библиотек Qt 5


Одно из главных изменений при использовании CMake в Qt 5 — это результат увеличенной модульности в самом Qt.

В Qt 4, поиск осуществлялся следующим образом:
find_package (Qt4 COMPONENTS QTCORE QTGUI)

В Qt 5, можно найти все модули, которые Вы хотите использовать, отдельными командами:
find_package (Qt5Widgets)
find_package (Qt5Declarative)
В будущем, возможно, будет способ найти определенные модули в одной команде, но сейчас, в Qt 5, такого вида поиск работать не будет:
find_package(Qt5 COMPONENTS Widgets Declarative)

Сборка проектов Qt 5


После успешного выполнения find_package, пользователям Qt 4 предоставлялась возможность использовать переменные CMake: ${QT_INCLUDES} для установки дополнительных директорий при компиляции и ${QT_LIBRARIES} или ${QT_GUI_LIBRARIES} при линковке.
Так же была возможность использования ${QT_USE_FILE}, для «полуавтоматического» включения необходимых директорий и требуемых define.
С модульной системой Qt 5, переменные теперь будут выглядеть так: ${Qt5Widgets_INCLUDE_DIRS}, ${Qt5Widgets_LIBRARIES}, ${Qt5Declarative_INCLUDE_DIRS}, ${Qt5Declarative_LIBRARIES} и так для каждого используемого модуля.

Это вызывает несовместимость при портировании проекта с Qt 4 в Qt 5. К счастью, это всё легко поправимо.
Сборка в Qt 5 немного сложнее, чем в Qt 4. Одно из различий состоит в том, что в Qt 5 опция configure -reduce-relocations теперь включена по умолчанию. По этой причине, компиляция стала выполняться с опцией -Bsymbolic-functions, которая делает функцию сравнения указателей неэффективной, если не был добавлен флаг -fPIE при сборке исполнимых модулей или -fPIC, при сборке библиотек для позиционно-независимого кода.

Конечно можно сконфигурировать Qt вручную с опцией -no-reduce-relocations и избежать этой проблемы, но возникнут новые проблемы при добавлении компилятору флагов для позиционно-независимого кода, избежать которых можно с помощью CMake:
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}")
Это переменная для каждого модуля, доступного в Qt 5, которая будет расширяться для добавления или -fPIE , или пустой строки, в зависимости от того, как Qt был сконфигурирован. Однако флаг -fPIE предназначен только для исполнимых программ и не должен использоваться для библиотек.
Глобальная установка -fPIC, даже при сборке исполнимых модулей не повлечет сбоев, но эта опция не должна быть первой.
set(CMAKE_CXX_FLAGS "-fPIC")

Вкупе с новыми возможностями в CMake, как например автоматический вызов moc, простая система сборки CMake с использованием Qt 5 будет выглядеть примерно так:
CMakeLists
cmake_minimum_required(2.8.7)
project(hello-world)

# Tell CMake to run moc when necessary:
set(CMAKE_AUTOMOC ON)
# As moc files are generated in the binary dir, tell CMake
# to always look for includes there:
set(CMAKE_INCLUDE_CURRENT_DIR ON)

# Widgets finds its own dependencies (QtGui and QtCore).
find_package(Qt5Widgets REQUIRED)

# The Qt5Widgets_INCLUDES also includes the include directories for
# dependencies QtCore and QtGui
include_directories(${Qt5Widgets_INCLUDES})

# We need add -DQT_WIDGETS_LIB when using QtWidgets in Qt 5.
add_definitions(${Qt5Widgets_DEFINITIONS})

# Executables fail to build with Qt 5 in the default configuration
# without -fPIE. We add that here.
set(CMAKE_CXX_FLAGS "${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}")

add_executable(hello_world main.cpp mainwindow.cpp)

# The Qt5Widgets_LIBRARIES variable also includes QtGui and QtCore
target_link_libraries(hello_world ${Qt5Widgets_LIBRARIES})

Навстречу более современному использованию CMake


Начиная с CMake 2.8.8, мы можем немного улучшить предыдущий вариант следующим образом:
CMakeLists
cmake_minimum_required(2.8.8)
project(hello-world)

# Tell CMake to run moc when necessary:
set(CMAKE_AUTOMOC ON)
# As moc files are generated in the binary dir, tell CMake
# to always look for includes there:
set(CMAKE_INCLUDE_CURRENT_DIR ON)

# Widgets finds its own dependencies.
find_package(Qt5Widgets REQUIRED)

add_executable(hello_world main.cpp mainwindow.cpp)

qt5_use_modules(hello_world Widgets)


Функция CMake qt5_use_modules инкапсулирует всю установку, необходимую для использования Qt. Она может использоваться с несколькими аргументами сразу для краткости, например:
qt5_use_modules(hello_world Widgets Declarative)
Для qmake это эквивалентно следующему:
TARGET = hello_world
QT += widgets declarative

Все свойства находятся в области видимости конкретной используемой целевой функции, вместо того, чтобы быть в области видимости CMakeLists. Например, в этом фрагменте:
CMakeList
add_executable(hello_world main.cpp mainwindow.cpp)
add_library(hello_library lib.cpp)
add_executable(hello_coretest test.cpp)

find_package(Qt5Widgets)

qt5_use_package(hello_world Widgets)
qt5_use_package(hello_library Core)
qt5_use_package(hello_coretest Test)

т.к. все параметры находятся в области видимости цели (исполняемый модуль или библиотека), с которой они работают, -fPIE не используется при построении библиотеки hello_library и -DQT_GUI_LIB не используется при построении hello_coretest.
Это гораздо более рациональный способ писать систему сборки на CMake.

Детали реализации


Одна из функций CMake, с которой многие разработчики, использовавшие его, знакомы, является Find-файл. Идея состоит в том, чтобы написать Find-файл для каждой зависимости Вашего проекта или использовать уже какой-то существующий Find-файл. CMake сам предоставляет большой набор Find-файлов.
Один из Find-файлов, предоставленных CMake — это файл FindQt4.cmake. Этот файл берет на себя ответственность за поиск Qt в системе, чтобы Вы могли просто вызвать:
find_package(Qt4)

Этот Find-файл делает доступными переменные ${QT_INCLUDES} и ${QT_QTGUI_LIBRARIES}. Одним из недостатков этого файла является то, что он мог устареть. Например, когда вышел Qt 4.6 в декабре 2009, он включал новый модуль QtMultimedia. Поддержки этого модуля не было аж до CMake 2.8.2, вышедшего в июне 2010.

Поиск Qt 5 происходит несколько иначе. Кроме возможности найти зависимости, используя Find-файл, CMake также в состоянии считывает файлы, обеспечивающие зависимости для определения местоположения библиотек и заголовочных файлов. Такие файлы называются файлами конфигурации, и обычно они генерируются самим CMake.

Сборка Qt 5 так же сгенерирует эти конфигурационные файлы CMake, но при этом не появятся зависимости от CMake.
Основное преимущество этого — то, что функции (и модули) Qt, которые могут использоваться с CMake, не будут зависеть от используемой версии CMake. Все модули Qt Essentials и Qt Addons создадут свой собственный файл конфигурации CMake, и функции, предоставляемые модулями, будут сразу доступны через макросы и переменные CMake.

Оригинал статьи: www.kdab.com/using-cmake-with-qt-5
Метки:
  • +13
  • 34,4k
  • 5
Поделиться публикацией
Похожие публикации
Комментарии 5
  • +1
    Я так понимаю, перевод этой статьи?
    Надо такие вещи помечать как перевод и указывать оригинал.
    • +2
      Очень огорчился, что стало крайне сложно написать файл проекта для сборки одновременно с qt4 и qt5. В результате решил вообще отказаться от cmake в пользу qbs и qmake.
      • 0
        Геморроя добавляет, конечно, но это пишется один раз, потом просто используется.
        К стати, в оригинальной статье есть ссылка на пример сборки с Qt5 существующих проектов на Qt4. Вы то её наверняка видели, но может еще кого заинтересует.
        • +1
          К стати, было бы очень интересно посмотреть как это решается на qbs.
          • 0
            Там один и тот же код занимается и Qt4 и Qt5, просто чуть различается список модулей, а в cmake' же так не получается, плюс не очевидно как заставить его юзать cmake файлы от именно того самого qmake'а той самой сборки Qt которая нужна. Скрипты сборки от Qt5 для qmake от Qt4 не годятся, в итоге самое нормальное, что я видел, это толстый костыль, который инкапсулировал qt5_use_modules(hello_world Widgets) и превращал его в qt_use_modules(hello_world Widgets) с выбором версии.
            Но всё равно это проблемы, геморрой на ровном месте и трудноловимые косяки.

        Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.