Cmake добавить файл в проект

Обновлено: 05.07.2024

Чтобы установить значение опции, отличное от "по умолчанию", необходимо дописать -DНАЗВАНИЕ_ОПЦИИ=Значение к команде конфигурирования. Команда после этого может выглядеть, например, так:

Чтобы сделать такое действие в CLion, необходимо перейти в: Settings -> CMake -> CMake options.

Если используется Hunter (пакетный менеджер), то прописываются его настройки

На этапе конфигурирования, CMake ожидает файл tools/gate/cmake/HunterGate.cmake .

Если этот файл не существует, возможны 2 варианта:

  • Либо (если используется шаблонный репозиторий) необходимо обновить подмодули:

git submodule update --init --recursive

Дополнительные опции для компилятора (могут отсутствовать)

Подключение зависимых библиотек

Затем осуществляется подключение библиотек, в которых нуждается проект (Boost, GTest, Threads и т.д.)

Указания для Hunter о необходимо коллекционирования указанных пакетов

Указания о том, какие пакеты будут использованы (ожидается их наличие)

CONFIG - ключевое слово, показывающее маску названий конфигурационных файлов.

REQUIRED - обязательность подключения пакета (иначе - ошибка).

Добавление целей сборки

После настройки окружающией среды пишется информация о том, что ожидается получить в результате сборки

Указание директорий с заголовочными файлами

Указание библиотек для линковки

Названия библиотек из Hunter, как правило, имеют вид LibraryName::ComponentName .

Данные о библиотеках из пакета, добавленного через find_package хранятся в переменных. Например, для Threads: $

Для сборки тестирования необходимо наличие:

  1. Добавления пакета googletest (GTest в Hunter)
  2. Цели для сборки исполняемого файла
  3. Линковки gtest_main и gtest (GTest::main и GTest::gtest в Hunter) к цели
  4. Включенного тестирования в конфигурационном файле

Можно добавлять несколько тестовых целей под разными названиями. И даже с использованием разных фреймворков.

Для сборки и выполнения тестирования необходимо выполнить следующую команду (ожидается предварительное конфигурирование):

Пример тела конфигурационного файла с тестированием:

Для удобства в CLion необходимо добавить конфигурацию сборки google test.

Начало конфигурации. Как правило, его трогать не надо.

Далее прописываются цели, которые будут проанализированы на процент покрытия.

Конец конфигурации. Как правило, не надо трогать.

Для начала необходимо настроить окружение. Как правило, это не надо трогать

Далее необходимо указать jobs'ы, которые будет выполнять Travis. Jobs содержит название и команды.

К таким относятся, например, правила для веток и для уведомлений. Например:


В данной статье рассмотрено использование системы сборки CMake, применяемой в колоссальном количестве проектов на C/C++. Строго рекомендуется прочитать первую часть руководства во избежание непонимания синтаксиса языка CMake, явным образом фигурирующего на протяжении всей статьи.

Ниже приведены примеры использования языка CMake, по которым Вам следует попрактиковаться. Экспериментируйте с исходным кодом, меняя существующие команды и добавляя новые. Чтобы запустить данные примеры, установите CMake с официального сайта.

Система сборки CMake представляет из себя оболочку над другими платформенно зависимыми утилитами (например, Ninja или Make). Таким образом, в самом процессе сборки, как бы парадоксально это ни звучало, она непосредственного участия не принимает.

Система сборки CMake принимает на вход файл CMakeLists.txt с описанием правил сборки на формальном языке CMake, а затем генерирует промежуточные и нативные файлы сборки в том же каталоге, принятых на Вашей платформе.

Сгенерированные файлы будут содержать конкретные названия системных утилит, директорий и компиляторов, в то время как команды CMake орудуют лишь абстрактным понятием компилятора и не привязаны к платформенно зависимым инструментам, сильно различающихся на разных операционных системах.

Команда cmake_minimum_required проверяет запущенную версию CMake: если она меньше указанного минимума, то CMake завершает свою работу фатальной ошибкой. Пример, демонстрирующий типичное использование данной команды в начале любого CMake-файла:

Как подметили в комментариях, команда cmake_minimum_required выставляет все флаги совместимости (смотреть cmake_policy ). Некоторые разработчики намеренно выставляют низкую версию CMake, а затем корректируют функционал вручную. Это позволяет одновременно поддерживать древние версии CMake и местами использовать новые возможности.

В начале любого CMakeLists.txt следует задать характеристики проекта командой project для лучшего оформления интегрированными средами и прочими инструментами разработки.

Стоит отметить, что если ключевое слово LANGUAGES опущено, то по умолчанию задаются языки C CXX . Вы также можете отключить указание любых языков путём написания ключевого слова NONE в качестве списка языков или просто оставить пустой список.

Команда include заменяет строку своего вызова кодом заданного файла, действуя аналогично препроцессорной команде include языков C/C++. Этот пример запускает скриптовый файл MyCMakeScript.cmake описанной командой:

Команда add_executable компилирует исполняемый файл с заданным именем из списка исходников. Важно отметить, что окончательное имя файла зависит от целевой платформы (например, <ExecutableName>.exe или просто <ExecutableName> ). Типичный пример вызова данной команды:

Команда add_library компилирует библиотеку с указанным видом и именем из исходников. Важно отметить, что окончательное имя библиотеки зависит от целевой платформы (например, lib<LibraryName>.a или <LibraryName>.lib ). Типичный пример вызова данной команды:

  • Статические библиотеки задаются ключевым словом STATIC вторым аргументом и представляют из себя архивы объектных файлов, связываемых с исполняемыми файлами и другими библиотеками во время компиляции;
  • Динамические библиотеки задаются ключевым словом SHARED вторым аргументом и представляют из себя двоичные библиотеки, загружаемые операционной системой во время выполнения программы;
  • Модульные библиотеки задаются ключевым словом MODULE вторым аргументом и представляют из себя двоичные библиотеки, загружаемые посредством техник выполнения самим исполняемым файлом;
  • Объектные библиотеки задаются ключевым словом OBJECT вторым аргументом и представляют из себя набор объектных файлов, связываемых с исполняемыми файлами и другими библиотеками во время компиляции.

Бывают случаи, требующие многократного добавления исходных файлов к цели. Для этого предусмотрена команда target_sources , способная добавлять исходники к цели множество раз.

Первым аргументом команда target_sources принимает название цели, ранее указанной с помощью команд add_library или add_executable , а последующие аргументы являются списком добавляемых исходных файлов.

Повторяющиеся вызовы команды target_sources добавляют исходные файлы к цели в том порядке, в каком они были вызваны, поэтому нижние два блока кода являются функционально эквивалентными:

Местоположение выходных файлов, сгенерированных командами add_executable и add_library , определяется только на стадии генерации, однако данное правило можно изменить несколькими переменными, определяющими конечное местоположение двоичных файлов:

  • Переменные RUNTIME_OUTPUT_DIRECTORY и RUNTIME_OUTPUT_NAME определяют местоположение целей выполнения;
  • Переменные LIBRARY_OUTPUT_DIRECTORY и LIBRARY_OUTPUT_NAME определяют местоположение библиотек;
  • Переменные ARCHIVE_OUTPUT_DIRECTORY и ARCHIVE_OUTPUT_NAME определяют местоположение архивов.

Исполняемые файлы всегда рассматриваются целями выполнения, статические библиотеки — архивными целями, а модульные библиотеки — библиотечными целями. Для "не-DLL" платформ динамические библиотеки рассматриваются библиотечными целями, а для "DLL-платформ" — целями выполнения. Для объектных библиотек таких переменных не предусмотрено, поскольку такой вид библиотек генерируется в недрах каталога CMakeFiles .

Важно подметить, что "DLL-платформами" считаются все платформы, основанные на Windows, в том числе и Cygwin.

Команда target_link_libraries компонует библиотеку или исполняемый файл с другими предоставляемыми библиотеками. Первым аргументом данная команда принимает название цели, сгенерированной с помощью команд add_executable или add_library , а последующие аргументы представляют собой названия целей библиотек или полные пути к библиотекам. Пример:

Стоит отметить, что модульные библиотеки не подлежат компоновке с исполняемыми файлами или другими библиотеками, так как они предназначены исключительно для загрузки техниками выполнения.

Как упомянули в комментариях, цели в CMake тоже подвержены ручному манипулированию, однако весьма ограниченному.

Имеется возможность управления свойствами целей, предназначенных для задания процесса сборки проекта. Команда get_target_property присваивает предоставленной переменной значение свойства цели. Данный пример выводит значение свойства C_STANDARD цели MyTarget на экран:

Команда set_target_properties устанавливает указанные свойства целей заданными значениями. Данная команда принимает список целей, для которых будут установлены значения свойств, а затем ключевое слово PROPERTIES , после которого следует список вида <название свойства> <новое значение> :

Пример выше задал цели MyTarget свойства, влияющие на процесс компиляции, а именно: при компиляции цели MyTarget CMake затребует компилятора о использовании стандарта C11. Все известные именования свойств целей перечисляются на этой странице.

Также имеется возможность проверки ранее определённых целей с помощью конструкции if(TARGET <TargetName>) :

Команда add_subdirectory побуждает CMake к незамедлительной обработке указанного файла подпроекта. Пример ниже демонстрирует применение описанного механизма:

В данном примере первым аргументом команды add_subdirectory выступает подпроект subLibrary , а второй аргумент необязателен и информирует CMake о папке, предназначенной для генерируемых файлов включаемого подпроекта (например, CMakeCache.txt и cmake_install.cmake ).

Стоит отметить, что все переменные из родительской области видимости унаследуются добавленным каталогом, а все переменные, определённые и переопределённые в данном каталоге, будут видимы лишь ему (если ключевое слово PARENT_SCOPE не было определено аргументом команды set ). Данную особенность упомянули в комментариях к предыдущей статье.

Команда find_package находит и загружает настройки внешнего проекта. В большинстве случаев она применяется для последующей линковки внешних библиотек, таких как Boost и GSL. Данный пример вызывает описанную команду для поиска библиотеки GSL и последующей линковки:

В приведённом выше примере команда find_package первым аргументом принимает наименование пакета, а затем требуемую версию. Опция REQUIRED требует печати фатальной ошибки и завершении работы CMake, если требуемый пакет не найден. Противоположность — это опция QUIET , требующая CMake продолжать свою работу, даже если пакет не был найден.

Далее исполняемый файл MyExecutable линкуется с библиотекой GSL командой target_link_libraries с помощью переменной GSL::gsl , инкапсулирующей расположение уже скомпилированной GSL.

В конце вызывается команда target_include_directories , информирующая компилятора о расположении заголовочных файлов библиотеки GSL. Обратите внимание на то, что используется переменная GSL_INCLUDE_DIRS , хранящая местоположение описанных мною заголовков (это пример импортированных настроек пакета).

Вам, вероятно, захочеться проверить результат поиска пакета, если Вы указали опцию QUIET . Это можно сделать путём проверки переменной <PackageName>_FOUND , автоматически определяемой после завершения команды find_package . Например, в случае успешного импортирования настроек GSL в Ваш проект, переменная GSL_FOUND обратится в истину.

В общем случае, команда find_package имеет две разновидности запуска: модульную и конфигурационную. Пример выше применял модульную форму. Это означает, что во время вызова команды CMake ищет скриптовый файл вида Find<PackageName>.cmake в директории CMAKE_MODULE_PATH , а затем запускает его и импортирует все необходимые настройки (в данном случае CMake запустила стандартный файл FindGSL.cmake ).

Информировать компилятора о располжении включаемых заголовков можно посредством двух команд: include_directories и target_include_directories . Вы решаете, какую из них использовать, однако стоит учесть некоторые различия между ними (идея предложена в комментариях).

Команда include_directories влияет на область каталога. Это означает, что все директории заголовков, указанные данной командой, будут применяться для всех целей текущего CMakeLists.txt , а также для обрабатываемых подпроектов (смотреть add_subdirectory ).

Команда target_include_directories влияет лишь на указанную первым аргументом цель, а на другие цели никакого воздействия не оказывается. Пример ниже демонстрирует разницу между этими двумя командами:

В комментариях упомянуто, что в современных проектах применение команд include_directories и link_libraries является нежелательным. Альтернатива — это команды target_include_directories и target_link_libraries , действующие лишь на конкретные цели, а не на всю текущую область видимости.

Команда install генерирует установочные правила для Вашего проекта. Данная команда способна работать с целями, файлами, папками и многим другим. Сперва рассмотрим установку целей.

Для установки целей необходимо первым аргументом описанной функции передать ключевое слово TARGETS , за которым должен следовать список устанавливаемых целей, а затем ключевое слово DESTINATION с расположением каталога, в который установятся указанные цели. Данный пример демонстрирует типичную установку целей:

Процесс описания установки файлов аналогичен, за тем исключением, что вместо ключевого слова TARGETS следует указать FILES . Пример, демонстрирующий установку файлов:

Процесс описания установки папок аналогичен, за тем исключением, что вместо ключевого слова FILES следует указать DIRECTORY . Важно подметить, что при установке будет копироваться всё содержимое папки, а не только её название. Пример установки папок выглядит следующим образом:

После завершения обработки CMake всех Ваших файлов Вы можете выполнить установку всех описанных объектов командой sudo checkinstall (если CMake генерирует Makefile ), или же выполнить данное действие интегрированной средой разработки, поддерживающей CMake.

Данное руководство было бы неполным без демонстрации реального примера использования системы сборки CMake. Рассмотрим схему простого проекта, использующего CMake в качестве единственной системы сборки:

Главный файл сборки CMakeLists.txt описывает компиляцию всей программы: сперва происходит вызов команды add_executable , компилирующей исполняемый файл, затем вызывается команда add_subdirectory , побуждающая обработку подпроекта, и наконец, исполняемый файл линкуется с собранной библиотекой:

Файл core/CMakeLists.txt вызывается главным файлом сборки и компилирует статическую библиотеку MyProgramCore , предназначенную для линковки с исполняемым файлом:

После череды команд cmake . && make && sudo checkinstall работа системы сборки CMake завершается успешно. Первая команда запускает обработку файла CMakeLists.txt в корневом каталоге проекта, вторая команда окончательно компилирует необходимые двоичные файлы, а третья команда устанавливает скомпонованный исполняемый файл MyProgram в систему.

Теперь Вы способны писать свои и понимать чужие CMake-файлы, а подробно прочитать про остальные механизмы Вы можете на официальном сайте.

Следующая статья данного руководства будет посвящена тестированию и созданию пакетов с помощью CMake и выйдет через неделю. До скорых встреч!

Я рассматриваю возможность переключения кроссплатформенного проекта с отдельных систем управления сборками в Visual C ++, XCode и make-файлах на CMake.

Одна важная функция, которая мне нужна, - это автоматическое добавление всех файлов в каталоге к цели. Хотя это легко сделать с помощью make, это нелегко сделать с помощью Visual C ++ и XCode (поправьте меня, если я ошибаюсь). Возможно ли сделать это непосредственно в CMake? Как?

Это возможно. Например, с file(GLOB :

Обратите внимание, что это требует повторного запуска вручную, cmake если исходный файл добавлен или удален, поскольку сгенерированная система сборки не знает, когда запросить CMake для регенерации, и выполнение этого при каждой сборке увеличит время сборки.

Альтернативой ручному повторному запуску cmake является прикосновение к файлу CMakeLists.txt перед запуском make. > «Мы не рекомендуем использовать GLOB для сбора списка исходных файлов из дерева исходных текстов. Если файл CMakeLists.txt не изменяется при добавлении или удалении источника, то сгенерированная система сборки не может знать, когда попросить CMake сгенерировать заново». Это больше не рекомендуется в документах CMAKE3.7, связанных с Hand1Cloud

Ответ Клейста, конечно, работает, но есть важное предостережение:

Когда вы пишете Makefile вручную, вы можете сгенерировать SRCS переменную, используя функцию для выбора всех .cpp и .h файлов. Если исходный файл добавлен позже, повторный запуск make включит его.

Тем не менее, CMake (с такой командой file(GLOB . ) ) явно генерирует список файлов и помещает его в автоматически сгенерированный Makefile . Если у вас есть новый исходный файл, вам нужно будет заново сгенерировать его Makefile путем повторного запуска cmake .

редактировать: не нужно удалять Makefile.

Нельзя просто перезапустить cmake, что должно удалить / изменить устаревший Makefile? Этот комментарий хорош, но он "стандартный", верно? Аскер уже использует cmake, поэтому предположение, что make может быть «умнее», не так уж полезно. Так есть ли способ добавить новые исходные файлы, а затем собрать без повторного запуска cmake?

Расширение для ответа @Kleist :

Так как CMake 3.12 дополнительные опции CONFIGURE_DEPENDS будет поддерживаться с помощью команд file(GLOB) и file(GLOB_RECURSE) . С помощью этой опции нет нет потребности в вручную повторно запустить CMake после добавления / удаления исходного файла в каталоге - CMake будет повторно запускаться автоматически на следующий строительный проект.

Однако опция CONFIGURE_DEPENDS подразумевает, что соответствующий каталог будет перепроверяться при каждом запросе сборки , поэтому процесс сборки будет занимать больше времени, чем без CONFIGURE_DEPENDS .

Даже с доступной опцией CONFIGURE_DEPENDS, документация CMake по-прежнему не рекомендует использовать file(GLOB) или file(GLOB_RECURSE) собирать источники.

«Документация CMake все еще не рекомендует использовать file(GLOB) или file(GLOB_RECURSE) собирать источники» Что они тогда рекомендуют? Используя что-то еще, чтобы собрать источники или вручную перечислить каждый отдельный исходный файл? @Thomas: они рекомендуют вручную перечислять каждый исходный файл. Этот ответ дает отличное объяснение рекомендации.

Так почему бы не использовать powershell для создания списка исходных файлов для вас. Посмотрите на этот скрипт

CMake — кроссплатформенная автоматизированная система сборки проектов. Непосредственно сборкой она не занимается, а только генерирует Makefile, который потом будет выполнен утилитой make.

CMake может проверять наличие необходимых библиотек и подключать их, собирать проекты под разными компиляторами и операционными системами. Т.е. у вас есть куча кода и файлик, содержащий информацию для cmake, и чтобы скомпилить это дело где-нибудь еще, вам нужно просто запустить там cmake, который сделает всё сам. Удобно, полезно, просто.

Если нет желания/времени/сил читать весь туториал и Вы используете какой-нибудь QtCreator (или любая другая IDE, умеющая работать с cmake), то:

  • Создайте в IDE проект под cmake
  • Найдите в папке с проектом CMakeFiles.txt
  • Пробегитесь глазами по туториалу, соотнося его с вашим CMakeFiles.txt

Про подключение библиотек рекомендуется все-таки прочитать целиком.

Предположим, у Вас есть исходничек "test.cpp" (// а если нет?)(А если нет, то CMake тебе трогать рано). Для начала нужно создать файлик для cmake, который обычно называют "CMakeLists.txt", и написать туда вот это:

Теперь запускаем (из консоли) в этой папке команду "cmake CMakeLists.txt" (аргументом можно передавать не только файл, но и директорию, в которой он лежит, тогда cmake найдет его сам).

cmake будет использовать переданный (или найденный) файл проекта (тот самый CMakeLists.txt), и в текущей директории будет создавать проект. Проект - это много-много файлов и директорий (примечание: поэтому лучше запускать cmake из другой директории, чтобы можно было, например, быстро удалить все бинарники), из которых нас больше всего интересует Makefile.

Makefile - это файл, нужный для утилиты make. Именно она запускает компиляторы, линковщики и прочие радости. Запускаем make в каталоге сборки (т.е. там же, где Вы запускали cmake). В консоли вылезет примерно такой текст:

А у Вас в папочке появится исполняемый файл "test". Запустите, убедитесь, что это действительно то, что ожидается от компиляции файла "test.cpp".

Поразбираемся с различными возможностями cmake.

Указывайте высокую минимальную версию CMake. Если используемая версия cmake меньше 2.6, он не захочет работать. Писать эту команду всегда - хороший стиль (cmake будет пыхтеть и обижаться, если вы не укажете версию, но собирать всё равно всё будет).

Указывает, что этот cmake-файл является корневым для некоторого проекта. С проектами связаны определенные переменные и поведение cmake (читайте документацию).

В cmake можно создавать текстовые переменные. Команда

запишет в переменную "VARIABLE" значение "The variable's value". Чтобы где-либо использовать значение этой переменной, нужно написать $.

Чтобы добавить к переменной некий текст, можно сделать так:

Как видите, использовать значение можно и внутри кавычек. Переменные активно используются различными библиотеками - для установки флагов, параметров сборки/линковки и прочих вкусностей, об этом чуть-чуть попозже.

Пример коше'гного проекта со списком сорцов в отдельной переменной:

Эта команда добавит к флагам, используемым при сборке c++-кода, флаги -std=c++11 и -Wall.

Кто не знает: "-std=c++11" включает в gcc поддержку стандарта c++11, "-Wall" говорит gcc выводить все предупреждения (очень советую, помогает отловить много глупых багов и писать аккуратный код).

Если ваша версия GCC меньше, чем 4.7.0, вместо -std=c++11 нужно использовать -std=c++0x.

В GCC 4.8.0 появился флаг -std=c++1y, в котором начинают реализовывать фичи следующего стандарта.

Надеюсь, и это понятно.

Научимся искать и подключать библиотеки при помощи cmake на примере Boost. Для начала установим переменные для буста:

Итак, мы установили флаги. Давайте найдем буст!

Допустим, нам нужны компоненты буста под названием chrono (библиотека для работы со временем) и filesystem (библиотека для работы с файловой системой):

Win, будут искаться только нужные библиотеки, и их расположение будет записано в переменную Boost_LIBRARIES.

Опция "REQUIRED" говорит о том, что библиотека необходима проекту. Без нее cmake решит, что отсутствие данной библиотеки - не так уж и страшно, и будет собирать дальше.

Добавим директории с хедерами буста для поиска в них хедеров:

Итак, осталось найденные библиотеки подключить к исполняемому файлу.

В качестве библиотек нужно указать пути к необходимым собранным библиотекам. cmake нашел указанные нами библиотеки и записал в переменную, чем мы и пользуемся.

Заметим, что эту команду нужно вызывать после того, как создан target сборки (через add_executable).

Итак, полный пример использования всего этого. У нас есть некая директория (отныне считаем ее "/sources"), и в ней лежат исходники

В корне "/" лежит файл "/CMakeLists.txt":

Если Вам что-то в нём не понятно - перечитайте соответствующую информацию выше.

Создаем директорию "/build" (не "/sources/build"), переходим в нее, запускаем в ней "cmake ..". ".." - метка родительской директории. cmake возьмет из нее наш CMakeLists.txt и по нему создаст проект в папке "/build". Чтобы проект собрать, запускаем "make" в той же папке "/build".

Таким образом, в корне у нас есть:

  • CMakeLists.txt
  • директория с исходниками
  • каталог сборки

Все разделено, автоматизировано и удобно.

Пусть в ./ лежит основной проект, а в ./subdir мы хотим сделать либу, а в ./build построить проект.

В ./build запускаем "cmake .. && make" и получаем собранный проект.

Интеграция с cmake у QtCreator не очень тесная, тем не менее, работать с ним можно.

Создаем новый проект без использования Qt, выбираем "Проект на С++ с использованием CMake". Создастся дефолтный файл сборки, который просто добавляет все исходники в директории проекта и компилирует их в один бинарник.

Читайте также: