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 будет выглядеть примерно так:
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, мы можем немного улучшить предыдущий вариант следующим образом:
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. Например, в этом фрагменте:
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