Как известно, новичку сложно получить какую-либо полезную информацию о CMake. До сих пор я видел несколько руководств о том, как создать какой-нибудь очень простой проект или другой. Однако ни одно из них не объясняет причины, лежащие в основе чего-либо, что в них показано, всегда оставляя много дыр, которые нужно заполнить.
Что вызов CMake на через CMakeLists значит ? Он должен вызываться один раз для каждого дерева сборки или как? Как использовать разные настройки для каждой сборки, если все они используют один и тот же файл CMakeLists.txt из одного источника? Почему для каждого подкаталога нужен собственный файл CMakeLists? Имеет ли смысл использовать CMake в файле CMakeLists.txt, отличном от того, который находится в корне проекта? Если да, то в каких случаях? В чем разница между указанием того, как создать исполняемый файл или библиотеку из файла CMakeLists в их собственном подкаталоге, и указанием этого в файле CMakeLists в корне всех источников? Могу ли я сделать проект для Eclipse и другой для Visual Studio, просто изменив -G
параметр при вызове CMake? Это вообще то, как это используется?
Ни одно из руководств, страниц документации или вопросов / ответов, которые я видел до сих пор, не дает полезного понимания того, как использовать CMake. Примеры просто не полны. Какие бы уроки я ни читал, мне кажется, что я упускаю что-то важное.
Новички в CMake, такие как я, задают много вопросов, которые не задают этого в явной форме, но делают очевидным тот факт, что мы, как новички, понятия не имеем, что делать с CMake или что с этим делать.
Ответы:
Для чего нужен CMake?
Согласно Википедии:
С CMake вам больше не нужно поддерживать отдельные настройки, специфичные для вашей среды компиляции / сборки. У вас есть одна конфигурация, которая работает во многих средах.
CMake может генерировать решение Microsoft Visual Studio, проект Eclipse или лабиринт Makefile из одних и тех же файлов, ничего не меняя в них.
Имея множество каталогов с кодом в них, CMake управляет всеми зависимостями, порядками сборки и другими задачами, которые необходимо выполнить вашему проекту перед его компиляцией. На самом деле он ничего НЕ компилирует. Чтобы использовать CMake, вы должны указать ему (используя файлы конфигурации, называемые CMakeLists.txt), какие исполняемые файлы вам нужно скомпилировать, с какими библиотеками они связаны, какие каталоги есть в вашем проекте и что внутри них, а также любые детали, такие как флаги. или что-нибудь еще, что вам нужно (CMake довольно мощный).
Если все настроено правильно, вы затем используете CMake для создания всех файлов, которые необходимы вашей «родной среде сборки» для выполнения своей работы. В Linux по умолчанию это Makefiles. Итак, как только вы запустите CMake, он создаст кучу файлов для собственного использования плюс несколько файлов
Makefile
. Все, что вам нужно делать после этого, это набирать "make" в консоли из корневой папки каждый раз, когда вы заканчиваете редактировать свой код, и бац, создается скомпилированный и связанный исполняемый файл.Как работает CMake? Что оно делает?
Вот пример настройки проекта, который я буду использовать повсюду:
Содержимое каждого файла показано и обсуждается позже.
CMake настраивает ваш проект в соответствии с корнем
CMakeLists.txt
вашего проекта и делает это в любом каталоге, из которого вы запускалиcmake
в консоли. Выполнение этого из папки, которая не является корнем вашего проекта, создает так называемую сборку вне исходного кода , что означает, что файлы, созданные во время компиляции (файлы obj, файлы lib, исполняемые файлы, вы знаете), будут помещены в указанную папку , хранятся отдельно от фактического кода. Это помогает уменьшить беспорядок и предпочтительнее по другим причинам, которые я не буду обсуждать.Я не знаю, что произойдет, если вы выполните что-
cmake
либо, кроме корневогоCMakeLists.txt
.В этом примере, поскольку я хочу, чтобы все это помещалось в
build/
папку, сначала мне нужно перейти туда, а затем передать CMake каталог, в котором находится кореньCMakeLists.txt
.По умолчанию это все настраивается с использованием Makefiles, как я уже сказал. Вот как теперь должна выглядеть папка сборки:
Что это за файлы? Единственное, о чем вам нужно беспокоиться, - это Makefile и папки проекта .
Обратите внимание , что
src/
иlib/
папку. Они были созданы, потому чтоsimple/CMakeLists.txt
указывает на них с помощью командыadd_subdirectory(<folder>)
. Эта команда указывает CMake искать в указанной папке другойCMakeLists.txt
файл и выполнять этот сценарий, поэтому в каждом подкаталоге, добавленном таким образом, должен бытьCMakeLists.txt
файл внутри. В этом проектеsimple/src/CMakeLists.txt
описывается, как создать фактический исполняемый файл, иsimple/lib/CMakeLists.txt
описано, как построить библиотеку. Каждая цель, которуюCMakeLists.txt
описывает a, будет по умолчанию помещена в свой подкаталог в дереве сборки. Итак, после быстрогов консоли, выполненной из
build/
, добавляются некоторые файлы:Проект построен, и исполняемый файл готов к выполнению. Что вы делаете, если хотите, чтобы исполняемые файлы помещались в определенную папку? Установите соответствующую переменную CMake или измените свойства конкретной цели . Подробнее о переменных CMake позже.
Как мне сообщить CMake, как построить мой проект?
Вот объяснение содержимого каждого файла в исходном каталоге:
simple/CMakeLists.txt
:Минимальная требуемая версия всегда должна быть установлена в соответствии с предупреждением, которое CMake выдает, когда вы этого не сделаете. Используйте любую вашу версию CMake.
Имя вашего проекта может быть использовано позже и намекает на то, что вы можете управлять более чем одним проектом из одних и тех же файлов CMake. Но я не буду углубляться в это.
Как упоминалось ранее,
add_subdirectory()
добавляет папку в проект, что означает, что CMake ожидаетCMakeLists.txt
, что у нее будет внутренняя часть, которую он затем запустит перед продолжением. Кстати, если у вас есть определенная функция CMake, вы можете использовать ее из другихCMakeLists.txt
подкаталогов, но вы должны определить ее перед использованием,add_subdirectory()
иначе она ее не найдет. Однако CMake лучше разбирается в библиотеках, так что это, вероятно, единственный раз, когда вы столкнетесь с подобной проблемой.simple/lib/CMakeLists.txt
:Чтобы создать свою собственную библиотеку, вы даете ей имя, а затем перечисляете все файлы, из которых она построена. Просто. Если бы
foo.cxx
для компиляции требовался другой файл , вы бы вместо этого написалиadd_library(TestLib TestLib.cxx foo.cxx)
. Это также работает, например, с файлами в других каталогахadd_library(TestLib TestLib.cxx ${CMAKE_SOURCE_DIR}/foo.cxx)
. Подробнее о переменной CMAKE_SOURCE_DIR позже.Еще одна вещь, которую вы можете сделать с этим, - указать, что вам нужна общая библиотека. Пример:
add_library(TestLib SHARED TestLib.cxx)
. Не бойтесь, именно здесь CMake упрощает вашу жизнь. Независимо от того, является ли он общим или нет, теперь все, что вам нужно обработать для использования библиотеки, созданной таким образом, - это имя, которое вы дали ей здесь. Имя этой библиотеки теперь TestLib, и вы можете ссылаться на нее из любой точки проекта. CMake найдет это.Есть ли лучший способ перечислить зависимости? Однозначно да . Подробнее об этом см. Ниже.
simple/lib/TestLib.cxx
:simple/lib/TestLib.h
:simple/src/CMakeLists.txt
:Команда
add_executable()
работает точно так жеadd_library()
, за исключением, конечно, вместо нее исполняемого файла. На этот исполняемый файл теперь можно ссылаться как на цель для таких вещей, какtarget_link_libraries()
. Поскольку в tutorial.cxx используется код из библиотеки TestLib, вы указываете на это CMake, как показано.Точно так же любые файлы .h, # включенные любыми источниками
add_executable()
, находящимися не в том же каталоге, что и источник, должны быть добавлены каким-то образом. Если бы неtarget_include_directories()
команда,lib/TestLib.h
она не была бы найдена при компиляции Tutorial, поэтому всяlib/
папка добавляется в каталоги include для поиска #includes. Вы также можете увидеть команду,include_directories()
которая действует аналогичным образом, за исключением того, что вам не нужно указывать цель, поскольку она полностью устанавливает ее глобально для всех исполняемых файлов. Еще раз объясню CMAKE_SOURCE_DIR позже.simple/src/tutorial.cxx
:Обратите внимание на то, как включен файл «TestLib.h». Нет необходимости указывать полный путь: CMake позаботится обо всем этом за кулисами благодаря
target_include_directories()
.Технически говоря, в таком простом дереве исходных текстов вы можете обойтись без
CMakeLists.txt
s подlib/
иsrc/
и просто добавив что-то вродеadd_executable(Tutorial src/tutorial.cxx)
tosimple/CMakeLists.txt
. Это зависит от вас и потребностей вашего проекта.Что еще мне нужно знать, чтобы правильно использовать CMake?
(AKA темы, относящиеся к вашему пониманию)
Поиск и использование пакетов : ответ на этот вопрос объясняет это лучше, чем я когда-либо мог.
Объявление переменных и функций, использование потока управления и т . Д.: Ознакомьтесь с этим руководством, которое объясняет основы того, что может предложить CMake, а также является хорошим введением в целом.
Переменные CMake : их много, поэтому далее следует краткий курс, который направит вас на верный путь. Вики CMake - хорошее место для получения более подробной информации о переменных и, якобы, других вещах.
Вы можете изменить некоторые переменные, не перестраивая дерево сборки. Используйте для этого ccmake (он редактирует
CMakeCache.txt
файл). Не забудьте выполнитьc
onfigure, когда закончите с изменениями, а затемg
установите make-файлы с обновленной конфигурацией.Прочтите ранее упомянутый учебник, чтобы узнать об использовании переменных, но короче:
set(<variable name> value)
для изменения или создания переменной.${<variable name>}
использовать это.CMAKE_SOURCE_DIR
: Корневой каталог источника. В предыдущем примере это всегда равно/simple
CMAKE_BINARY_DIR
: Корневой каталог сборки. В предыдущем примере это равноsimple/build/
, но если вы запустилиcmake simple/
из такой папки, какfoo/bar/etc/
, тогда все ссылки наCMAKE_BINARY_DIR
в этом дереве сборки станут/foo/bar/etc
.CMAKE_CURRENT_SOURCE_DIR
: Каталог, в котором находится текущийCMakeLists.txt
. Это означает, что он меняется повсюду: печать его изsimple/CMakeLists.txt
выходов/simple
и печать изsimple/src/CMakeLists.txt
выходов/simple/src
.CMAKE_CURRENT_BINARY_DIR
: Вы поняли. Этот путь будет зависеть не только от папки, в которой находится сборка, но и от текущегоCMakeLists.txt
местоположения скрипта.Почему это важно? Очевидно, что исходных файлов не будет в дереве сборки. Если вы попробуете что-то подобное
target_include_directories(Tutorial PUBLIC ../lib)
в предыдущем примере, этот путь будет относиться к дереву сборки, то есть это будет похоже на запись${CMAKE_BINARY_DIR}/lib
, которая будет смотреть внутрьsimple/build/lib/
. Там нет файлов .h; максимум найдешьlibTestLib.a
. Вы хотите${CMAKE_SOURCE_DIR}/lib
вместо этого.CMAKE_CXX_FLAGS
: Флаги для передачи компилятору, в данном случае компилятору C ++. Также стоит отметить,CMAKE_CXX_FLAGS_DEBUG
что будет использоваться вместо него, еслиCMAKE_BUILD_TYPE
установлено значение DEBUG. Есть еще такие; проверьте вики CMake .CMAKE_RUNTIME_OUTPUT_DIRECTORY
: Сообщите CMake, куда поместить все исполняемые файлы при сборке. Это глобальная настройка. Вы можете, например, установить егоbin/
и все аккуратно разместить там.EXECUTABLE_OUTPUT_PATH
похожа, но устарела, если вы наткнетесь на нее.CMAKE_LIBRARY_OUTPUT_DIRECTORY
: Точно так же глобальная настройка, указывающая CMake, где разместить все файлы библиотеки.Свойства цели : вы можете установить свойства, которые влияют только на одну цель, будь то исполняемый файл или библиотека (или архив ... вы поняли). Вот хороший пример того, как его использовать (с
set_target_properties()
.Есть ли простой способ автоматически добавлять источники к цели? Используйте GLOB, чтобы перечислить все в данном каталоге под одной и той же переменной. Пример синтаксиса
FILE(GLOB <variable name> <directory>/*.cxx)
.Можете ли вы указать разные типы сборки? Да, хотя я не уверен в том, как это работает или в каких ограничениях. Вероятно, это требует некоторого if / then'ning, но CMake действительно предлагает некоторую базовую поддержку без настройки чего-либо, например, значения по умолчанию для
CMAKE_CXX_FLAGS_DEBUG
. Вы можете установить тип сборки изCMakeLists.txt
файла черезset(CMAKE_BUILD_TYPE <type>)
или, например, вызвав CMake из консоли с соответствующими флагамиcmake -DCMAKE_BUILD_TYPE=Debug
.Есть ли хорошие примеры проектов, использующих CMake? В Википедии есть список проектов с открытым исходным кодом, использующих CMake, если вы хотите в него разобраться. В этом отношении онлайн-руководства были для меня не чем иным, как разочарованием, однако в этом вопросе о переполнении стека есть довольно крутая и простая для понимания настройка CMake. Стоит посмотреть.
Использование переменных из CMake в вашем коде : Вот быстрый и грязный пример (адаптированный из другого учебника ):
simple/CMakeLists.txt
:simple/TutorialConfig.h.in
:Полученный файл , сгенерированный CMake,
simple/src/TutorialConfig.h
:С умным их использованием вы можете делать такие крутые вещи, как отключение библиотеки и тому подобное. Я действительно рекомендую взглянуть на это руководство, так как есть несколько более продвинутых вещей, которые рано или поздно обязательно будут очень полезны в более крупных проектах.
Во всем остальном Stack Overflow изобилует конкретными вопросами и краткими ответами, что отлично подходит для всех, кроме непосвященных.
источник
make
в bash для создания своего проекта.