Увы, но информация собрана по кусочкам из интернета.
В случае с qmake, nmake такого вопроса не стоит вообще, т.к. официальной документации вполне хватает.
После знакомства с CMake, можно сказать что QMake проще, но не очень таки гибок для сборки.
CMake сложнее, чем QMake. Он скорее даже скриптовый язык программирования.
QMake интересен своей простотой, однако при очень уж "кроссплатформенной разработки" для разных устройств и операционных систем и разных инструментов сборки(toolchain) CMake становится более гибок. Возможна подобная сложная система сборки возможна и для QMake, а возможно и нет.
Ещё так сложилось, что у CMake:
1. Гораздо больше шаблонной кодагенерации в нативные проектные файлы чем у QMake
2. Позволяет создавать кастомные цели
3. На нём можно делать кросс-компиляцию
4. Разработчики библиотек почти что дефакто делают возможность подцепить их библиотеки через cmake find_package.
[1] Описание cmake 2.8.1 http://www.cmake.org/cmake/help/v2.8.11/cmake.html
[2] Описание cmake 3.2 http://www.cmake.org/cmake/help/v3.2/
[3] Полезные CMake переменные http://www.cmake.org/Wiki/CMake_Useful_Variables
http://www.cmake.org/Wiki/CMake_Useful_Variables/Logging_Useful_Variables
[4] CMake wiki https://cmake.org/Wiki/CMake
[5] Стороннее вики описание по поводу команды find_package http://wiki.icub.org/wiki/CMake_and_FIND_PACKAGE
[6] CMake wiki описание по поводу find_package https://cmake.org/Wiki/CMake:How_To_Find_Libraries
[7] Описание CMake http://www.paraview.org/Wiki/CMake
[8] EClipse and Cmake http://www.paraview.org/Wiki/CMake:Eclipse
[9] Cтатья про CMake http://procplusplus.blogspot.ru/2011/06/cmake-1.html
[10] Cтатья про CMake http://knzsoft.blogspot.ru/2012/04/cmakelisttxt.html
[11] Описание с сайта ubuntu гораздо полнее чем cmake --help http://manpages.ubuntu.com/manpages/lucid/man1/cmake.1.html
[12] Описание по командам CMake http://www.cmake.org/cmake/help/v2.8.11/cmake.html#section_Commands
[13] CMake презентация http://www.elpauer.org/stuff/learning_cmake.pdf
[14] CMake презентация http://ilcsoft.desy.de/portal/e279/e346/infoboxContent560/CMake_Tutorial.pdf
[15] CMake презентация http://www.slideshare.net/DanielPfeifer1/cmake-48475415
[16] CMake презентация http://www.elpauer.org/stuff/learning_cmake.pdf
[17] howto по cmake http://mathnathan.com/2010/07/getting-started-with-cmake/
[18] cmake commands http://www.cmake.org/cmake/help/cmake2.6docs.html#section_Commands
[19] cmake and qt http://www.devexp.ru/2010/01/cmake-i-qt/
[20] cmake policies https://cmake.org/cmake/help/v3.0/manual/cmake-policies.7.html
[21] cmake Faq https://cmake.org/Wiki/CMake_FAQ
[22] cmake build system https://cmake.org/cmake/help/v3.9/manual/cmake-buildsystem.7.html?highlight=interface
[23] rpath https://cmake.org/Wiki/CMake_RPATH_handling
кроссплатформенная система сборки. Каждый CMakeLists.txt система сборки
наследсвенное отношение между конфигурациями
автоматическая последовательность сборки
много настроек по умолчанию
для линковки не следует использовать #pragma comment (lib, xxx.lib). CMake этого не поймёт - он не заглядывает в код.
У CMake
Команды - регистро-независимые
Имена переменных - регистро-зависимые
Директория, которая производит бинарный выходной файл - проект.
Поддиректория - подпроект.
Подпроект - наследует родительскую конфигурацию. Таким образом не надо изменять конфигурацию каждого проекта в отдельности, она наследуется.
Важное, что директория с инлудниками - не совсем является проектом, т.к. не производит бинарников
При сборке существует 4-е цели:
Debug
Release
Release Optimize
Release With symbols
Source tree - исходники + CMakeLists.txt
Binary Tree - это все генерируемые файлы как бинарники так и проектные файлы для конкретных сред. Для одного source tree можно иметь несколько binary tree.
CMakeLists.txt - параметры проекта, "описание" построения. Уникален для проекта, где проект как указано выше - это что-то вроде директории
CMakeModules.cmake - файл с описанием того, что будет произведено в том файле который его заинклудит для настройки окружения по использованию какого-либо проекта FindZLIB.cmake, FindQt4.cmake
# - комментарий
;list;of different;vars
include <CMakeXXX.cmake> - включение текста другого скрипта. Поддерживает модуль, или файл. Аналогичен команде препроцессора C.
Поиск файлов происходит по путям из переменной CMAKE_MODULE_PATH
https://cmake.org/cmake/help/v3.0/command/include.html
find_package(wxWidgets REQUIRED) -- "make searches for a file called Find<package>.cmake in the CMAKE_MODULE_PATH followed by the CMake installation.".
Для этой команды есть два режима: “Module” mode and “Config" (NO_MODULE).
Последний (Config) более продвинутый, и более хитрый -- https://cmake.org/cmake/help/v3.0/command/find_package.html
#Установка значений немного отличается от bash стиля
set(xxx value)
#Чтение почти также как и в bash стиле, но без фигурных скобок следующая конструкция не допускается
${xxx}
#Работа с переменными-списками
The list subcommands APPEND, INSERT, REMOVE_AT, REMOVE_ITEM, REMOVE_DUPLICATES, REVERSE and SORT may create new values for the list within the current CMake variable scope.
Similar to the SET command, the LIST command creates new variable values in the current scope
list(APPEND SRC ${PROJECT_SOURCE_DIR}/append_file.cpp)
list(APPEND src newItem) equal to SET(src ${src} newItem)
#list cmds
set(A 123 123)
set(A ${A} 456)
list(APPEND A 90)
list(APPEND A 91)
message(STATUS ${A})
Если нужно получить значение переменной окружения, для которой не существует переменной-двойника в CMake, можно воспользоваться конструкцией
$ENV{ИМЯ_ПЕРЕМЕННОЙ},
Например: $ENV{SHELL}, $ENV{WINDIR}
message() – служит, чтобы выводить различные сообщения во время генерации файлов проекта.
Первым аргументом команды является тип сообщения:
SEND_ERROR обработка текущего файла CMakeLists.txt завершается.
FATAL_ERROR приводит к завершению работы CMake.
STATUS не влияет на генерацию файлов проекта. Просто распечатывает данные.
# environmaent vars
message(STATUS $ENV{WINDIR})
CMAKE_SYSTEM_NAME -- содержит короткое имя системы (например, Linux или Windows).
CMAKE_SYSTEM_VERSION -- содержится номер версии системы (для Linux - версия ядра).
# if else endif секции
if (WIN32)
include (CMakeWin.cmake)
endif (WIN32)
В секции можно использовать переменные которые созданы пользователем, так и встроенными WIN32, UNIX.
Переменная UNIX обозначает все Unix-платформы.
if() else() elseif() реализуют условные переходы в файле мета-проекта. Каждой команде if() должна соответствовать команда endif(),
аргумент которой должен совпадать с аргументом команд if() и else() (этого требует документация по CMake).
Если переменной не присвоено значение, или присвоено одно из значений:
N, NO, OFF, FALSE, NOTFOUND, -NOTFOUND -- значение этой переменной интерпретируется как False, иначе True.
Логическое значение переменной может быть инвертировано с помощью оператора NOT.
Для сравнения числовых значений используются операторы EQUAL (равно), GREATER (больше), LESS (меньше).
Для сравнения строковых значений используются, соответственно, операторы STREQUAL, STRGREATER и STRLESS.
Оператор MATCHES сравнивает значения переменных и регулярные выражения.
Их надо использовать именно как бинарные операторы, а не как функции. Т.е. они записываются в блоке if в как:
"left argument EQUAL right argument".
Для того чтобы определить, присвоено ли переменной какое-либо значение, можно воспользоваться оператором DEFINED:
if(DEFINED variable)
Итерация по списку:
set(A "123" "asd")
set(A "123;asd")
foreach(f ${A})
message(STATUS ${f})
endforeach(f)
http://www.cmake.org/cmake/help/v3.0/command/foreach.html
1. Переходим в директорию где будет binary tree
2. Запускаем, указав имя генератора и путь до проекта
cmake -G "Visual Studio 11" "./../demo"
cmake -G "Unix Makefiles" "./../demo/"
cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX=./ --builddir=. "./../demo/"
cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX=./ -DCMAKE_BUILD_TYPE=Debug --builddir=. "./../demo/"
CMAKE_BUILD_TYPE - его возможные значения это DEBUG|RELEASE|RELWITHDEBINFO|MINSIZEREL
Дополнительные проекты для студии:
ZERO_CHECK - этот проект следует запустить после изменений в CMakeList.txt файлах
ALL_BUILD - собрать все проекты (build all)
INSTALL - инсталляция бинарей в указанные папки
Небольшие нюансы для Linux:
use CMAKE_BUILD_TYPE to separate your debug/release setting, and use to build such that
cmake --build . --config Release
cmake --build . --config Debug
Опции CMake
-D записать в кэш CMake переменную и ее значение. cmake . -DTESTVAR:BOOL=1
-U удаление из кэша переменных, имена которых соответствуют регулярному выражению
-G указать имя генератора файлов проекта
cmake --system-information -- распечатывает информацию о CMake и проекте
cmake --help-command-list -- получить список команд по которым можно получить справку
cmake --help-command CMD -- получить справку по команде CMD
cmake --help-commands -- распечатывает справку по всем командам cmake.
cmake --help-module CheckIncludeFile -- справка по модулю
cmake --help-modules -- распечатывает справку по всем cmake модулям
cmake --build . -- находясь в binary tree эта команда приведёт к запуску сборки проекта.
1. Открыть проект CMakeLists.txt в QtCreator
2. Указать параметры -DCMAKE_INSTALL_PREFIX=./ --builddir=.
3. Создать конфигурацию сборки. Указать для неё цели all, install
4. Настроить директорию запуска из install директории
5. QtCreator рядом с CMakeLists.txt создаёт CMakeLists.txt.user
6. Под виндоус для сборки используется http://qt-project.org/wiki/jom
jom is a clone of nmake to support the execution of multiple independent commands in parallel.
It basically adds the -j command-line flag similar to GNU make.
According to MSDN, http://msdn.microsoft.com/en-us/library/afyyse50%28VS.71%29.aspx there's no such option for 'nmake'.
It is possible to get parallel compiles using the /MP option with the VC++ command line compiler.
7. Во время первого запуска создаётся CMakeCache.txt файл
Загрузить расширение CMake.
find_package(wxWidgets REQUIRED)
# В результате загрузки расширения CMake через команду становятся доступны специальные переменные.
# Для CMake доступно около 130 подобных стандартных модулей, и ещё больше в интернете
CMakeCache.txt
хранит закешированные опции CMake и создаётся cmake-ом в нём содержатся записи типа
// Комментарий
ИМЯ[:ТИП]=ЗНАЧЕНИЕ
При запуске cmake можно указать путь до этого файла если он имеется через cmake -C <file>
http://www.cmake.org/runningcmake/ -- что такое CMakeCache.txt. По сути - хранилище путей системных библиотек.
Проверка инклуд файлов
Модуль CheckIncludeFile экспортирует check_include_file()
check_include_file() первый параметр имя заголовочного файла, второй – имя переменной, в которой будет сохранен результат.
check_include_file("GL/glx.h" HAVE_GLX_H)
См. check_symbol_exists, check_include_files_cxx, check_library_exists, check_function_exists,
FindPackageHandleStandardArgs
find_path(INCLUDE_DIR lib.h HINTS ${INCLUDE_HINT}) - поиск файла с указанием подсказок поисковому алгоритму
Создание файла конфигурации
check_include_file_cxx("GL/glx.h" HAVE_GLX_H)
set (NUM_VAR 16)
configure_file(config.h.in config.h)
Содержимое config.h.in:
#cmakedefine HAVE_GLX_H
#define NUM_VAR ${NUM_VAR}
"#cmakedefine VAR will be replaced with either #define VAR or /* #undef VAR */depending on the setting of VAR in CMake." https://cmake.org/pipermail/cmake/2011-March/043464.html
При конфигурировани происходит замена переменных типа ${VARIABLE} или @VARIABLE@ упомянутых в конфигурационном файле
Добавление переменных в CMakeCache.txt из скрипта
# Если в CMakeCache есть такая переменная заиспользовать переменную из кеша, если же переменной в кеше нет то создать таковую со значением 123
set(mylibrary_src_test 123 CACHE FILEPATH "")
FILEPATH = File chooser dialog PATH = Directory chooser dialog STRING = Arbitrary string BOOL = Boolean ON/OFF checkbox INTERNAL = No GUI entry (used for persistent variables)
# Переписать или создать переменную в CMakeCache.txt с именем mylibrary_src_test
set(mylibrary_src_test 123 CACHE FILEPATH "" FORCE)
Перевести space-separated имена в имена разделённый точкой с запятой
SEPARATE_ARGUMENTS
SEPARATE_ARGUMENTS(B "123;123")
message(STATUS ${B})
Добавление проекта
Установка предустановленных переменных из найденного пакета
Добавление цели в проекте
add_subdirectory -- добавление подпроекта в главный проект
add_library (STATIC, SHARED, MODULE, INTERFACE)
BUILD_SHARED_LIBS определяет поведение add_library
Следующими командами можно так же пользоваться для создания алиасов на библиотеки:
add_library(foo 1.cpp 2.cpp)
add_library(my::foo ALIAS foo)
Без использования алиасов нужно использовать target_link_libraries и add_dependencies
Когда-то с алиасами дёргать add_dependencies не требовалось.
Однако на данный момент всё таки target_link_libraries расставляет dependency самостоятельно.
"If it is created within the project and ordering dependency will automatically be added" (from documentation)
Подстройка конкретных вещей для конкретного проекта
Специальные keywords для target_*:
http://www.cmake.org/cmake/help/v3.0/manual/cmake-buildsystem.7.html#transitive-usage-requirements
PRIVATE -- установка касается только для этой цели
PUBLIC -- установка касается для этой цели и целей которые линкуются с этим проектом
INTERFACE -- установка касается только для целей которые линкуются с этим проектом
Работа с макросами
ADD_DEFINITIONS (считается устаревшим механизмом, см. target_compile_definitions)
Опции компилятора
CMAKE_C_FLAGS (считается устаревшим механизмом, см. target_compile_options)
CMAKE_CXX_FLAGS
Для отображения хедеров в VS требуется добавить заголовочные файлы в список исходников
SET(wakeup_SRCS ${wakeup_SRCS} wakeup.h)
Как указать конфигурацию сборки
SET(CMAKE_BUILD_TYPE Debug)
Так же можно указать и через comand line "cmake -DCMAKE_BUILD_TYPE=Release ../trunk"
Кастомная линковка для дебаг и не дебаг версии
TARGET_LINK_LIBRARIES(wakeup RELEASE ${wakeup_path})
TARGET_LINK_LIBRARIES(wakeupd DEBUG ${wakeup_path})
Для добавления путей для поиска библиотек требуется вызвать target_link_directories.html, которая ведёт себя как "-L"
Добавить пути до хедеров
Пример install команды, дёргаемой по make install
INSTALL(TARGETS clock wakeup RUNTIME DESTINATION bin LIBRARY DESTINATION lib)
Добавление новой пользовательской цели
ADD_CUSTOM_TARGET -- добавить цель, но сорсы всегда считаются out of date
ADD_CUSTOM_COMMAND -- добавить цель, но проверка того что сорсы стали out of date производится
Дёрг стороннего процесса
EXECUTE_PROCESS
Модуль загрузки разделяемой библиотеки XXX должен
- Записать в переменные XXX_INCLUDE_DIR или XXX_INCLUDE_DIRS пути до заголовочных файлов библиотеки
- Записать в XXX_LIBRARIES пути до файл библиотек, которые требуются подключить
- Записать XXX_DEFINITIONS - дополнительные флаги для компилятора при компиляции файлов использующие библиотеку
- После установок вызвать find_package_handle_standard_args(MyLib DEFAULT_MSG MYLIB_LIBRARIES MYLIB_INCLUDE_DIR)
Эта команда в том числе выставит XXX_FOUND если все аргументы команды find_package_handle_standard_args являются действительными.
Помимо пакета CMake компания Kitware выпускает еще несколько полезных пакетов, в том числе CPack – средство создания дистрибутивов.
Включить в проект include(CPack). Есть важный момент - все переменные специализированные для конкретного паковщика должны быть определены для этого include-а
Можно сконфигурить поведение CPack задав переменные перед вызовом include(CPack).
CPACK_BINARY_DEB, CPACK_BINARY_RPM, CPACK_BINARY_TGZ, CPACK_BINARY_STGZ - тип пакета. На платформе Windows для создания двоичных пакетов можно использовать Nullsoft NSIS.
CPACK_INSTALL_PREFIX – переменная, в которой сохраняется полное имя корневой директории для установки проекта
CPACK_PACKAGE_DESCRIPTION_FILE – путь к файлу с развернутым описанием собираемого пакета
CPACK_PACKAGE_FILE_NAME – основа имени файла пакета.
CPACK_PACKAGE_VENDOR – имя сборщика пакета.
CPACK_PACKAGE_VERSION_MAJOR, CPACK_PACKAGE_VERSION_MINOR, CPACK_PACKAGE_VERSION_RELEASE - версия пакета
CPACK_RESOURCE_FILE_LICENSE – путь к файлу с текстом лицензии.
CPACK_RESOURCE_FILE_README – путь к файлу README.
CPACK_SYSTEM_NAME – имя системы
Так же можно находясь в bin-tree вызвать генераторы пакетов.
cpack -G ZIP -C Release -R "1.1.1"
cpack -G NSIS -C Release -R "1.1.1"
Правда не все опции поддерживаются через команд-лайн.
cmake -E make_directory bbb -- выполнить команду cmake в интерактивном режиме
cmake --build build --target mylib --config Release --clean-first -- запуск системы сборки из cmake
cmake -P sctripFileName.txt -- выполнение последовательности команд из файла, файл не обязан быть валидным CMakeLists.txt файлом
https://cmake.org/cmake/help/v3.3/manual/cmake-properties.7.html -- свойства которые можно установить через set_property
set(CMAKE_VERBOSE_MAKEFILE on) -- будут выводиться лог выполняемых команд