- Linux make include directories
- Footnotes
- include_directories¶
- Linux make include directories
- Структура CMakeLists.txt
- Автогенерация проекта для Visual Studio (Windows)
- Зависимости между библиотеками и приложениями
- Выбор стандарта и диалекта C++
- Функции в CMake
- Добавление исходников к цели с target_sources
- Интерфейс к утилитам командной строки
- Функция find_package
- Полное руководство по CMake. Часть вторая: Система сборки
- Введение
- Запуск CMake
- Принцип работы
- Проверка версии CMake
- Оформление проекта
- Запуск скриптовых файлов
- Компиляция исполняемых файлов
- Компиляция библиотек
- Добавление исходников к цели
- Генерируемые файлы
- Компоновка с библиотеками
- Работа с целями
- Добавление подпроектов
- Поиск пакетов
- Способы включения заголовков
- Установка проекта
- Наглядный пример проекта
- Заключение
Linux make include directories
The include directive tells make to suspend reading the current makefile and read one or more other makefiles before continuing. The directive is a line in the makefile that looks like this:
filenames can contain shell file name patterns. If filenames is empty, nothing is included and no error is printed.
Extra spaces are allowed and ignored at the beginning of the line, but the first character must not be a tab (or the value of .RECIPEPREFIX )—if the line begins with a tab, it will be considered a recipe line. Whitespace is required between include and the file names, and between file names; extra whitespace is ignored there and at the end of the directive. A comment starting with ‘ # ’ is allowed at the end of the line. If the file names contain any variable or function references, they are expanded. See How to Use Variables.
For example, if you have three .mk files, a.mk , b.mk , and c.mk , and $(bar) expands to bish bash , then the following expression
is equivalent to
When make processes an include directive, it suspends reading of the containing makefile and reads from each listed file in turn. When that is finished, make resumes reading the makefile in which the directive appears.
One occasion for using include directives is when several programs, handled by individual makefiles in various directories, need to use a common set of variable definitions (see Setting Variables) or pattern rules (see Defining and Redefining Pattern Rules).
Another such occasion is when you want to generate prerequisites from source files automatically; the prerequisites can be put in a file that is included by the main makefile. This practice is generally cleaner than that of somehow appending the prerequisites to the end of the main makefile as has been traditionally done with other versions of make . See Automatic Prerequisites.
If the specified name does not start with a slash, and the file is not found in the current directory, several other directories are searched. First, any directories you have specified with the ‘ -I ’ or ‘ —include-dir ’ option are searched (see Summary of Options). Then the following directories (if they exist) are searched, in this order: prefix /include (normally /usr/local/include 1 ) /usr/gnu/include , /usr/local/include , /usr/include .
If an included makefile cannot be found in any of these directories, a warning message is generated, but it is not an immediately fatal error; processing of the makefile containing the include continues. Once it has finished reading makefiles, make will try to remake any that are out of date or don’t exist. See How Makefiles Are Remade. Only after it has tried to find a way to remake a makefile and failed, will make diagnose the missing makefile as a fatal error.
If you want make to simply ignore a makefile which does not exist or cannot be remade, with no error message, use the -include directive instead of include , like this:
This acts like include in every way except that there is no error (not even a warning) if any of the filenames (or any prerequisites of any of the filenames ) do not exist or cannot be remade.
For compatibility with some other make implementations, sinclude is another name for -include .
Footnotes
GNU Make compiled for MS-DOS and MS-Windows behaves as if prefix has been defined to be the root of the DJGPP tree hierarchy.
Источник
include_directories¶
Add include directories to the build.
Add the given directories to those the compiler uses to search for include files. Relative paths are interpreted as relative to the current source directory.
The include directories are added to the INCLUDE_DIRECTORIES directory property for the current CMakeLists file. They are also added to the INCLUDE_DIRECTORIES target property for each target in the current CMakeLists file. The target property values are the ones used by the generators.
By default the directories specified are appended onto the current list of directories. This default behavior can be changed by setting CMAKE_INCLUDE_DIRECTORIES_BEFORE to ON . By using AFTER or BEFORE explicitly, you can select between appending and prepending, independent of the default.
If the SYSTEM option is given, the compiler will be told the directories are meant as system include directories on some platforms. Signalling this setting might achieve effects such as the compiler skipping warnings, or these fixed-install system files not being considered in dependency calculations — see compiler docs.
Arguments to include_directories may use «generator expressions» with the syntax «$ «. See the cmake-generator-expressions(7) manual for available expressions. See the cmake-buildsystem(7) manual for more on defining buildsystem properties.
Prefer the target_include_directories() command to add include directories to individual targets and optionally propagate/export them to dependents.
Источник
Linux make include directories
На первом шаге проект нужно сконфигурировать, то есть создать финальный скрипт сборки, запустив cmake в будущем каталоге сборки.
На втором шаге нужно запустить финальный скрипт. Не вызывайте make ! Утилита cmake сделает это сама:
Структура CMakeLists.txt
В начале главного файла CMakeLists.txt ставят метаинформацию о минимальной версии CMake и названии проекта:
Затем следует список инструкций, служащих для вычисления различных переменных, создания целей сборки, подключения проектов из подкаталогов и так далее. Например, подключить дополнительный CMakeLists.txt из подкаталога можно так:
Целью может стать исполняемый файл, собираемый из исходного кода
Целью также может быть библиотека, статическая или динамическая.
Автогенерация проекта для Visual Studio (Windows)
Если используется Visual C++, то путь немного другой: на шаге конфигурирования создаётся проект для Visual Studio, который затем можно собрать из IDE либо так же из командной строки.
Созданный проект Visual Studio нельзя изменять и использовать постоянно, потому что при генерации проекта используются абсолютные пути и другие неприемлемые для постоянной работы вещи.
Если проект был сконфигурирован успешно, то в каталоге ../myapp-build появятся автоматически сгенерированный BUILD_ALL.sln и проекты для Visual Studio. Их можно открыть к IDE, либо собрать из командной строки с помощью cmake. Названия опций говорят сами за себя:
Зависимости между библиотеками и приложениями
Не используйте директивы include_directories , add_definitions , add_compile_options ! Они меняют глобальные настройки для всех целей, это создаёт проблемы при масштабировании.
- Используйте target_link_libraries для добавления статических и динамических библиотек, от которых зависит цель
- Используйте target_include_directories вместо include_directories для добавления путей поиска заголовков, от которых зависит цель
- Используйте target_compile_definitions вместо add_definitions для добавления макросов, с которыми собирается цель
- Используйте target_compile_options для добавления специфичных флагов компилятора, с которыми собирается цель
Вы можете выбирать область видимости настройки:
- PUBLIC делает настройку видимой для текущей цели и для всех зависящих от неё целей
- PRIVATE делает настройку видимой только для текущей цели
- INTERFACE делает настройку видимой только для всех зависящих от неё целей
Пример использования областей видимости:
Схема зависимостей условного проекта:
Выбор стандарта и диалекта C++
Для настройки стандарта и флагов языка C++ не добавляйте флаги напрямую!
В CMake версии 3.8+ вы можете прямо потребовать включить нужный стандарт:
В CMake версии до 3.7 включительно можно использовать set_target_properties (если не работает, то у вас слишком старый CMake):
Для разработчиков библиотек есть более тонкий контроль над возможностями языка:
Функции в CMake
CMake позволяет объявлять функции командами function(name) / endfunction() и макросы командами macro(name) / endmacro() . Предпочитайте функции, а не макросы, т.к. у функций есть своя область видимости переменных, а у макросов — нет.
Добавление исходников к цели с target_sources
Лучше добавлять специфичные исходники с помощью target_sources, а не с помощью дополнительных переменных.
Интерфейс к утилитам командной строки
Функция find_package
Функция find_package принимает имя библиотеки как аргумент и обращается к CMake, чтобы найти скрипт для настройки переменных данной библиотеки. В итоге при сборке либо возникает ошибка из-за того что пакет не найден, либо добавляются переменные, хранящие пути поиска заголовков, имена библиотек для компоновщика и другие параметры.
Пример подключения Boost, вызывающего встроенный в CMake скрипт FindBoost:
Пример подключения библиотеки Bullet с помощью встроенного скрипта FindBullet и компоновки с приложением my_app:
Источник
Полное руководство по CMake. Часть вторая: Система сборки
Введение
В данной статье рассмотрено использование системы сборки CMake, применяемой в колоссальном количестве проектов на C/C++. Строго рекомендуется прочитать первую часть руководства во избежание непонимания синтаксиса языка CMake, явным образом фигурирующего на протяжении всей статьи.
Запуск CMake
Ниже приведены примеры использования языка CMake, по которым Вам следует попрактиковаться. Экспериментируйте с исходным кодом, меняя существующие команды и добавляя новые. Чтобы запустить данные примеры, установите CMake с официального сайта.
Принцип работы
Система сборки CMake представляет из себя оболочку над другими платформенно зависимыми утилитами (например, Ninja или Make). Таким образом, в самом процессе сборки, как бы парадоксально это ни звучало, она непосредственного участия не принимает.
Система сборки CMake принимает на вход файл CMakeLists.txt с описанием правил сборки на формальном языке CMake, а затем генерирует промежуточные и нативные файлы сборки в том же каталоге, принятых на Вашей платформе.
Сгенерированные файлы будут содержать конкретные названия системных утилит, директорий и компиляторов, в то время как команды 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 описанной командой:
В данном примере, первое сообщение уведомит о том, что переменная TEST_VARIABLE ещё не определена, однако если скрипт MyCMakeScript.cmake определит данную переменную, то второе сообщение уже будет информировать о новом значении тестовой переменной. Таким образом, скриптовый файл, включаемый командой include , не создаёт собственной области видимости, о чём упомянули в комментариях к предыдущей статье.
Компиляция исполняемых файлов
Команда add_executable компилирует исполняемый файл с заданным именем из списка исходников. Важно отметить, что окончательное имя файла зависит от целевой платформы (например, .exe или просто ). Типичный пример вызова данной команды:
Компиляция библиотек
Команда add_library компилирует библиотеку с указанным видом и именем из исходников. Важно отметить, что окончательное имя библиотеки зависит от целевой платформы (например, 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 ) :
Добавление подпроектов
Команда 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 . Это можно сделать путём проверки переменной
_FOUND , автоматически определяемой после завершения команды find_package . Например, в случае успешного импортирования настроек GSL в Ваш проект, переменная GSL_FOUND обратится в истину.
В общем случае, команда find_package имеет две разновидности запуска: модульную и конфигурационную. Пример выше применял модульную форму. Это означает, что во время вызова команды CMake ищет скриптовый файл вида Find
.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 и выйдет через неделю. До скорых встреч!
Источник