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

в 13:50, , рубрики: cmake, qt, Qt 5, Qt Software, Программирование, метки: , ,
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.

Автор: Renzo

Источник

Поделиться

* - обязательные к заполнению поля