LXF109:CMake

Материал из Linuxformat.

Перейти к: навигация, поиск
Новая серия! Кросс-платформенная система сборки для ваших приложений

Содержание

Собираясь в путь

CMake
ЧАСТЬ 1 Система сборки – неизменный спутник любого разработчика. К счастью, сегодня уже не обязательно вникать во все тонкости M4Андрей Боровский представляет CMake!

Вот вам мой вариант теста для настоящего программиста: что неприятнее всего не найти? Кредитку, которой только что расплачивался в ресторане, телефон прекрасной девушки, с которой вчера познакомился в метро, или файл сборки проекта для той системы, в которой работаешь? Разумеется, ни одна из этих проблем не стоит того, чтобы делать из нее трагедию. Даже если кто-то сумеет воспользоваться вашей карточкой, деньги, скорее всего, удастся вернуть, потеря случайного телефонного номера тоже не повод для грусти – кто знает, может оно и к лучшему, а отсутствующий в исходниках файл можно восстановить, при условии, что вы понимаете структуру проекта и у вас под рукой есть подходящие утилиты.

Традиционно программисты, работающие в Linux (да и других Unix-системах) используют для сборки программ инструментарий GNU build system или Autotools (состоящий из утилит autoconf, automake, libtool, gnulib). Именно с его помощью создаются знакомые всем нам сценарии configure, которые и генерируют make-файлы для сборки приложения. Система GNU build system настолько тесно связана с историей Linux и других открытых проектов, что «мантра» configure && make && make install рассматривается некоторыми Unix-программистами как единственно верный способ установки ПО. К недостаткам Autotools можно отнести ее ориентацию на инструментарий разработчика GNU (GNU make, GCC и т.п.), который очень популярен на открытых Unix-платформах, но мало распространен в других средах. Стремяcь заполнить этот пробел, разработчики из компании Kitware создали свой собственный вариант кросс-платформенного генератора сборочных файлов – CMake (Cross-platform Make).

Система CMake выбрана в качестве стандартного средства сборки KDE 4, и уже по одной этой причине заслуживает нашего внимания. Но у нее есть и собственные достоинства. Прежде всего, CMake является по-настоящему кросс-платформенным генератором проектов, позволяющим создавать их единые описания для Linux, других Unix-систем (включая Mac OS X) и Windows. Остановимся на этом подробнее. Важное отличие Windows от Linux (с точки зрения разработчика) заключается в отсутствии единого стандарта сборочных файлов. Microsoft Visual Studio использует свои файлы проектов, C++ Builder – свои, MinGW – свои. Преимущество CMake в том,что эта система способна генерировать «родные» сборочные файлы для всех перечисленных средств разработки (как и для многих других). Кроме того, CMake стремится максимально использовать фирменные средства генерации сборочных файлов – например, для проектов Qt применяется qmake. Вдобавок CMake обладает интеллектуальной системой поиска инструментов сборки и библиотек на конкретной платформе (интроспекция) и автоматического конфигурирования. Благодаря этому она сама устанавливает многие параметры сборочных файлов, которые в других случаях приходится задавать вручную. Например, в ОС Linux CMake найдет директорию, где находится требуемый программе набор виджетов, а под Windows вам не придется указывать ей, где установлены Visual Studio или C++ Builder. Все это делает пакет CMake весьма простым и удобным в использовании.

Хотя в этих статьях мы будем рассматривать работу CMake в основном на примере программ, написанных на C++, она может пригодиться и тем, кто пишет на Java (и даже Fortran).

Схематично работу CMake можно описать следующим образом: вначале создается файл CMakeLists.txt, в котором описываются параметры сборки (расположение исходных текстов, требуемые внешние модули, цели сборки). Далее этот файл передается утилите cmake. Результатом ее работы является файл, содержащий инструкции сборки приложения для конкретной платформы (make-файл GNU make, файл проекта Visual Studio и т.д.). Суть идеи заключается в том, что описание процесса сборки в файле CMakeLists.txt абстрагировано как от конкретных особенностей отдельных систем (расположение файлов, возможности компиляторов), так и целых платформ. Читая общее описание процесса сборки из файла CMakeLists.txt, программа cmake создает файл инструкций сборки, учитывающий специфику конкретной системы.

Как же CMake удается быть такой «умной»? В ее основе лежит мощный скриптовый язык, который используется как в файлах CMakeLists.txt, так и в специальных сценариях – модулях. Именно в модулях реализованы такие функции CMake, как поиск файлов и проверка возможностей системы. Файлы модулей расположены в поддиректории Modules каталога cmake. Их можно разделить на три категории. Одна группа модулей предназначена для настройки работы системы на конкретной платформе (Linux, Winodws, Mac OS, BeOS и т.д.), вторая обеспечивает интеллектуальный поиск средств разработки и различных вспомогательных утилит, а также провер- ку их возможностей, а третья разыскивает библиотеки, требуемые отдельным программам, и определяет их параметры.

Важную роль в работе CMake играют также файлы шаблонов для генерации различных файлов сборки. Поскольку файлы модулей и шаблонов отделены от самой утилиты cmake и написаны на том же языке сценариев, что и файлы описания сборки, расширить возможности CMake очень просто. CMake 2.6 поставляется с тремя сотнями модулей, которые адаптируют пакет для работы с множеством разных инструментов, начиная с компиляторов C++ и Fortran и интерпретаторов Perl и Python и заканчивая такими библиотеками, как OpenSceneGraph, SDL, Qt 4 и wxWidgets. Файлы модулей поставляются не только с дистрибутивами CMake, но и вместе с некоторыми библиотеками, разработчики которых уже заинтересованы в поддержке CMake.

Хотя основные преимущества CMake связаны с кроссплатформенностью, что и отражено в названии пакета, простота работы с различными библиотеками может сделать CMake полезным и для Linux-проектов, которые не предполагают переноса на другие платформы. Благодаря CMake вы получаете простой и стандартный способ сборки приложений, использующих Qt, KDE, GTK+, wxWidgets...

Приступая к работе

Все примеры, рассмотренные в этих статьях, ориентированы на CMake 2.6 и выше (актуальная на момент написания статьи версия – 2.6.1). Если у вас установлена более ранняя версия CMake, обновите ее – это несложно (скачать дистрибутив можно с сайта http://www.cmake.org, он также есть и на LXFDVD). Хотя изложенный здесь материал ориентирован в основном на Linux-программиста, мы не будем пренебрегать кросс-платформенностью CMake, так что если вы все еще пользуетесь ОС из Редмонда, рекомендуется установить CMake и на нее тоже. Для изучения всех возможностей CMake мы воспользуемся кросс-платформенным набором виджетов wxWidgets (последнюю версию оного я тоже рекомендую установить на все интересующие вас платформы с сайта http://wxwidgets.org, см. также LXF98-99).

Если вы никогда не программировали с wxWidgets и не намерены делать этого впредь, могу вас успокоить – мы и не будем заниматься программированием с wxWidgets. Мы изучаем систему сборки программ, а не их написания, поэтому в качестве учебного материала нам вполне подойдут многочисленные примеры, входящие в состав дистрибутива wxWidgets. Поскольку мы практически не будем касаться их внутренней начинки, почти все наши рекомендации и инструкции можно рассматривать как универсальные, применимые при работе с любой другой библиотекой виджетов. Нашим основным средством разработки будет, естественно, GCC, а в обзоре переноса проектов под Windows мы рассмотрим (очень бегло) сборку проектов с помощью Visual Studio и C++ Builder.

Первый пример

В директории samples дистрибутива wxWidgets найдите поддиректорию minimal. Она содержит минимальный пример приложения wxWidgets. Здесь также находятся файлы сборки приложения на все случаи жизни; а вот CMakeLists.txt среди них нет. Давайте исправим это упущение! Ниже приводится исходный текст файла CMakeLists.txt (который вы найдете на диске) для приложения minimal. Чтобы упростить работу, мы разместим его в той же директории, что и исходные тексты приложения.

project(minimal)
cmake_minimum_required(VERSION 2.6)
set(wxWidgets_USE_LIBS base core)
find_package(wxWidgets REQUIRED)
include(${wxWidgets_USE_FILE})
set(minimal_SRCS minimal.cpp)
if(WIN32)
set(minimal_SRCS ${minimal_SRCS} minimal.rc)
endif(WIN32)
add_executable(minimal WIN32 ${minimal_SRCS})
target_link_libraries(minimal ${wxWidgets_LIBRARIES})

Рис. 1 Рис. 1. Make-файлы CMake в консоли Linux.

Те, кому сразу не терпится попробовать, могут скомандовать в директории minimal

cmake ./

после чего вызывать make. Процесс сборки с помощью make-файла, сгенерированного CMake, выглядит довольно красочно (рис. 1).

После окончания процесса можно скомандовать

minimal

и посмотреть на работу программы, которую мы не написали, но собрали (рис. 2).

Рис. 2Рис. 2. Приложение wxWidgets под Linux.

Прежде чем разбирать этот пример, рассмотрим кратко структуру языка сценариев CMake. На протяжении всех последующих статей мы, в основном, будем заниматься его изучением. Элементы языка сценариев CMake можно разделить на три категории: переменные, свойства и команды. Переменные играют в проектах CMake такую же важную роль, как и в файлах make. Настройка параметров сборки проекта выполняется, как правило, путем присвоения им различных значений. С помощью свойств проект CMake получает сведения о состоянии системы, для которой генерируются сборочные файлы. Свойства можно рассматривать как переменные, доступные только для чтения. Значения свойств устанавливаются средой CMake. Команды, как вы, конечно, догадались, выполняют различные действия с переменными и свойствами CMake и управляют процессом генерации сборочных файлов. Важной особенностью языка CMake является его расширяемость. Модули CMake, о которых говорилось выше, позволяют определять новые переменные, свойства и команды. Именно благодаря расширяемости языка CMake этот пакет может использоваться для сборки столь разных проектов.

Перейдем теперь к рассмотрению файла CMakeLists.txt. Описание сборки начинается с команды project().

Команда project() задает имя проекта, а также позволяет указать (в виде необязательного параметра) язык программирования. В качестве имени проекта мы взяли название компилируемой программы (это не обязательное правило CMake, но так удобнее). Язык программирования (С, CXX, Java) можно опустить. В этом случае CMake попробует «угадать» его по расширениям файлов исходных текстов. Команда project() – не просто элемент оформления файла CMakeLists.txt. Помимо прочего, она определяет переменные projectname_SOURCE_DIR и projectname_BINARY_DIR. Как нетрудно догадаться, последние содержат имена директории исходных тестов (обычно тот же каталог, где расположен файл CMakeLists.txt) и директории, в которой будет сохранен результат сборки. Файлы программ по умолчанию собираются в той же директории, где расположен файл CMakeLists.txt, а файлы библиотек – в поддиректории lib этого каталога.

Команда cmake_minimum_required() позволяет задать минимальный номер версии CMake, требуемый для сборки проекта. Она не является обязательной, но весьма полезна, если файл CMakeLists.txt использует возможности, появившиеся в последней версии CMake, которая пока что есть не у всех. Если установленная в системе версия CMake не соответствует минимальным требованиям файла CMakeLists.txt, будет выдано сообщение об ошибке.

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

 set(wxWidgets_USE_LIBS base core)

мы присваиваем переменной wxWidgets_USE_LIBS (которая должна содержать список требуемых программе модулей wxWidgets) значения base и core. Переменные CMake можно использовать рекурсивно, то есть добавлять новые значения к списку уже имеющихся, как например, в строке

 set(minimal_SRCS ${minimal_SRCS} minimal.rc)

где к значениям переменной minimal_SRCS добавляется еще одно. Обратите внимание на конструкцию ${имя_переменной}. Она возвращает значение переменной с указанным именем (без символа $ и фигурных скобок CMake «не понял» бы, что тут имеется в виду имя переменной). Правила использования имен и значений переменных в CMake похожи на правила для переменных окружения в сценариях оболочки.

Команда find_package() – одна из важнейших в CMake. В следующей статье мы остановимся на ней подробнее; сейчас скажем только, что find_package() загружает расширения CMake. В нашем примере загружается расширение wxWidgets, предназначенное для генерации файлов сборки программ, использующих wxWidgets. Важно подчеркнуть, что команда find_package() не ищет сами библиотеки, она только загружает расширение CMake. Поиск библиотек, определение их версий и прочие действия, связанные с библиотеками, выполняет загруженное расширение. Естественно, что поскольку система CMake сама не выполняет сборку приложений, библиотеками она «интересуется» лишь с точки зрения генерации инструкций для сборочных файлов. В нашем примере команда find_package() вызывается с опцией REQUIRED. Тем самым мы указываем CMake, что если расширение для работы с wxWidgets не найдено, генерация файлов, необходимых для сборки приложения, выполняться не может.

Команда add_executable() относится к числу тех, что устанавливают цели сборки. Собственно, она указывает, что ею является исполняемый файл программы. Если бы мы собирали библиотеку, следовало бы использовать команду add_library(). Команда add_executable() позволяет указать имя собираемого файла и связать с ним исходные тексты. Обратите внимание на опцию WIN32, переданную команде add_executable(). Ее потребовалось упомянуть для того, чтобы на платформе Windows создавались файлы сборки графического приложения (а не консольного, как это будет по умолчанию). В Linux нет принципиальной разницы между структурой исполняемого файла графической и консольной программы (в Windows – есть, интересующихся читателей отсылаю к соответствующей литературе). Как же отреагирует CMake для Linux на присутствие опции WIN32? Правильный ответ – никак, пакет ее просто проигнорирует. Помимо файлов программ и библиотек, в проектах CMake можно задавать и другие цели, например, установку и упаковку приложений.

Последняя команда файла, target_link_libraries(), указывает CMake, какие инструкции следует добавить в сборочный файл для подключения к проекту сторонних библиотек. Первый ее аргумент – цель, определенная выше командой add_executable() (вообще говоря, целей сборки может быть несколько), далее идет список внешних библиотек, в которых она нуждается. В нашем примере он хранится в переменной wxWidgets_LIBRARIES, определенной в расширении wxWidgets. На содержимое переменной wxWidgets_LIBRARIES влияет переменная wxWidgets_USE_LIBS, вот почему значение ей следует присвоить до обращения к команде find_package().

А что в Windows?

Рис. 3Рис. 3. CMake GUI для Windows.

Наш файл CMakeLists.txt уже содержит некоторые элементы, которые пригодятся при генерации сборочных файлов под Windows. Тем не менее, на этой платформе нас ждут некоторые сложности. Вызваны они тем, что файловая система в Windows гораздо более хаотична, чем в Linux. В Unix-системах существуют устойчивые традиции касательно того, где должны быть расположены те или иные файлы. Например, файлы разделяемых библиотек следует искать (и устанавливать) в директориях /lib, /usr/lib, /usr/local/lib. В Windows путаницы гораздо больше. Файлы тех же разделяемых библиотек могут располагаться либо в системных каталогах Windows, либо в собственных каталогах программ. В дополнение к этому файловая система Windows не имеет общего корня, как это принято в Unix- системах. Все эти особенности приводят к тому, что под Windows пакету CMake гораздо труднее найти места расположения требуемых библиотек. Принимая во внимание этот факт, а также то, что консоль в Windows гораздо менее популярна, разработчики CMake для Windows добавили в пакет специальную утилиту с графическим интерфейсом (рис. 3).

Главная задача CMake GUI – генерация файлов сборки приложения для различных сред, используемых на платформе Windows. Попутно эта утилита позволяет присвоить значения некоторым переменным CMake, которые сам пакет определить не смог (или «не уверен» в их правильности). Отметим, что эти дополнительные настройки влияют на получаемые в результате генерации файлы сборки, но не влияют на содержимое самого файла CMakeLists.txt.

Рис. 4Рис. 4. Консольная сборка под Windows выглядит почти так же, как и под Linux. Вот она, кросс-платформенность!

Создание файлов сборки с помощью CMake GUI состоит из двух этапов: настройки и собственно генерации. Первая операция выполняется по команде Configure, вторая – по команде Generate. В процессе конфигурации утилита позволяет вам выбрать среду разработки из довольно внушительного списка и настроить значения «сомнительных» переменных. В процессе генерации утилита может выявить синтаксические ошибки в файле CMakeLists.txt. Если в качестве целевой среды сборки выбрана Visual Studio, CMake для Windows генерирует файл ALL_BUILD.vcproj. Если же целью является компилятор Borland C++, в результате создается make-файл для консольной версии компилятора (рис. 4).

Выполнив сборку, мы получаем то же приложение, что и под Linux.

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

Где найти документацию

Общее описание синтаксиса языка CMake можно найти в Интернете на странице http://cmake.org/HTML/Documentation.html. Там же есть ссылка на бумажную книгу Кена Мартина [Ken Martin] и Билла Хоффмана [Bill Hoffman], «Mastering CMake» (актуальное издание – четвертое, на русском языке не выходило). Что касается расширений CMake, описания многих из них входят в стандартную документацию. Описания остальных расширений следует искать на сайтах тех проектов, для которых они предназначены.

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

Интересно отметить, что очень подробная справка по командам CMake включена прямо в исполняемый файл утилиты: наберите cmake --help-full | less, и вы поймете, что мы имеем в виду.

С большой буквы или с маленькой?

Язык CMake обладает частичной регистронезависимостью. Имена команд нечувствительны к регистру (IF(), If(), if() и iF() – одно и то же), в то время как имена свойств и переменных – чувствительны. В связи с регистронезависимостью имен команд возникает вопрос, как правильнее писать – с большой буквы, с маленькой или полностью заглавными буквами. Разные авторы пишут по-разному (в документации CMake имена команд пишутся полностью строчными буквами, а во многих файлах CMake, написанных самими разработчиками – заглавными). Лично я пишу имена команд с маленькой буквы, и буду следовать этому принципу в статьях данной серии.

Личные инструменты
  • Купить электронную версию
  • Подписаться на бумажную версию