Руководство CMake. Шаг 2. Добавление библиотеки

Добавлено 5 апреля 2023 в 21:41

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

Руководство CMake. Шаг 2. Добавление библиотеки

Упражнение 1. Создание библиотеки

Чтобы добавить библиотеку в CMake, используйте команду add_library() и укажите, какие исходные файлы должны составлять эту библиотеку.

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

Как только библиотека создана, она подключается к нашей исполняемой цели с помощью команд target_include_directories() и target_link_libraries().

Цель

Добавить и использовать библиотеку.

Полезные ресурсы

Редактируемые файлы

  • CMakeLists.txt
  • tutorial.cxx
  • MathFunctions/CMakeLists.txt

С чего начать

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

Для этого урока мы поместим библиотеку в подкаталог MathFunctions. Этот каталог уже содержит заголовочный файл MathFunctions.h и исходный файл mysqrt.cxx. Нам не нужно будет изменять ни один из этих файлов. В исходном файле есть одна функция, mysqrt, которая обеспечивает функционал, аналогичный функции sqrt компилятора.

В каталоге Help/guide/tutorial/Step2 начните с TODO 1 и завершите TODO 6.

Сначала добавьте одну строку CMakeLists.txt в подкаталоге MathFunctions.

Затем отредактируйте CMakeLists.txt верхнего уровня.

И в конце используйте недавно созданную библиотеку MathFunctions в tutorial.cxx.

Сборка и запуск

Запустите исполняемый файл cmake или cmake-gui, чтобы настроить проект, а затем собрать его с помощью выбранного инструмента сборки.

Ниже показано, как это выглядит из командной строки:

mkdir Step2_build
cd Step2_build
cmake ../Step2
cmake --build .

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

Решение

В файле CMakeLists.txt в каталоге MathFunctions мы создаем целевую библиотеку с именем MathFunctions с помощью add_library(). Исходный файл библиотеки передается в качестве аргумента функции add_library(). Это выглядит как следующая строка:

TODO 1

MathFunctions/CMakeLists.txt

add_library(MathFunctions mysqrt.cxx)

Чтобы использовать новую библиотеку, добавим вызов add_subdirectory() в файл CMakeLists.txt верхнего уровня, чтобы библиотека была собрана.

TODO 2

CMakeLists.txt

add_subdirectory(MathFunctions)

Затем новая цель библиотеки связывается с исполняемой целью с помощью target_link_libraries().

TODO 3

CMakeLists.txt

target_link_libraries(Tutorial PUBLIC MathFunctions)

Наконец, нам нужно указать расположение заголовочного файла библиотеки. Измените target_include_directories(), чтобы добавить подкаталог MathFunctions в качестве включаемого каталога, чтобы можно было найти заголовочный файл MathFunctions.h.

TODO 4

CMakeLists.txt

target_include_directories(Tutorial PUBLIC
                          "${PROJECT_BINARY_DIR}"
                          "${PROJECT_SOURCE_DIR}/MathFunctions"
                          )

Теперь воспользуемся нашей библиотекой. В tutorial.cxx включите MathFunctions.h:

TODO 5

tutorial.cxx

#include "MathFunctions.h"

Наконец, замените вызов sqrt нашей библиотечной функцией mysqrt.

TODO 6

tutorial.cxx

const double outputValue = mysqrt(inputValue);

Упражнение 2. Делаем нашу библиотеку необязательной

Теперь давайте сделаем библиотеку MathFunctions необязательной. Хотя для данного руководства в этом нет необходимости, для больших проектов это обычное дело.

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

Цель

Добавить возможность сборки без MathFunctions.

Полезные ресурсы

Редактируемые файлы

  • CMakeLists.txt
  • tutorial.cxx
  • TutorialConfig.h.in

С чего начать

Начните с файлов, полученных в упражнении 1. Выполните TODO 7TODO 13.

Сначала создайте переменную USE_MYMATH с помощью команды option() в файле CMakeLists.txt верхнего уровня. В том же файле используйте этот параметр, чтобы определить, следует ли создавать и использовать библиотеку MathFunctions.

Затем обновите tutorial.cxx и TutorialConfig.h.in, чтобы использовать USE_MYMATH.

Сборка и запуск

Поскольку наш каталог сборки уже был настроен в упражнении 1, мы можем пересобрать его, просто вызвав следующие команды:

cd ../Step2_build
cmake --build .

Затем запустите исполняемый файл Tutorial для нескольких чисел, чтобы убедиться, что он все еще правильно работает.

Теперь давайте изменим значение USE_MYMATH на OFF. Самый простой способ – использовать cmake-gui или ccmake, если вы находитесь в терминале. Или, наоборот, если вы хотите изменить параметр из командной строки, попробуйте:

cmake ../Step2 -DUSE_MYMATH=OFF

Теперь пересоберите код следующей командой:

cmake --build .

Затем снова запустите исполняемый файл, чтобы убедиться, что он всё еще работает с параметром USE_MYMATH, установленным на OFF. Какая функция дает лучшие результаты, sqrt или mysqrt?

Решение

Первый шаг – добавить параметр в файл CMakeLists.txt верхнего уровня. Этот параметр будет отображаться в cmake-gui и ccmake со значением по умолчанию ON, которое может быть изменено пользователем.

TODO 7

CMakeLists.txt

option(USE_MYMATH "Use tutorial provided math implementation" ON)

Затем сделайте сборку и компоновку библиотеки MathFunctions условной.

Начните с создания списка необязательных целевых библиотек для нашего проекта с помощью list(). На данный момент это только MathFunctions. Назовем наш список EXTRA_LIBS.

Точно так же нам нужно создать list() для необязательных включений, которые мы назовем EXTRA_INCLUDES. В этом списке мы добавим путь к заголовочному файлу, необходимому для нашей библиотеки.

Затем создайте оператор if(), который проверяет значение USE_MYMATH. Внутри блока if() поместите команду add_subdirectory() из упражнения 1 с дополнительными командами list().

Когда USE_MYMATH установлена в ON, списки будут сгенерированы и добавлены в наш проект. Когда USE_MYMATH установлена в OFF, списки остаются пустыми. С помощью этой стратегии мы позволяем пользователям переключать USE_MYMATH, чтобы управлять библиотекой, используемой в сборке.

Файл CMakeLists.txt верхнего уровня теперь будет выглядеть следующим образом:

TODO 8

CMakeLists.txt

if(USE_MYMATH)
  add_subdirectory(MathFunctions)
  list(APPEND EXTRA_LIBS MathFunctions)
  list(APPEND EXTRA_INCLUDES "${PROJECT_SOURCE_DIR}/MathFunctions")
endif()

Теперь, когда у нас есть эти два списка, нам нужно обновить target_link_libraries() и target_include_directories(). Изменить их достаточно просто.

Для target_link_libraries() мы заменяем записанные имена библиотек на EXTRA_LIBS. Это выглядит следующим образом:

TODO 9

CMakeLists.txt

target_link_libraries(Tutorial PUBLIC ${EXTRA_LIBS})

Затем делаем то же самое с target_include_directories() и EXTRA_INCLUDES.

TODO 10

CMakeLists.txt

target_include_directories(Tutorial PUBLIC
                           "${PROJECT_BINARY_DIR}"
                           ${EXTRA_INCLUDES}
                           )

Обратите внимание, что это классический подход при работе со многими компонентами. Современный подход мы рассмотрим в шаге 3 данного руководства.

Соответствующие изменения в исходном коде довольно просты. Во-первых, в tutorial.cxx мы включаем заголовок MathFunctions.h, если определена USE_MYMATH.

TODO 11

tutorial.cxx

#ifdef USE_MYMATH
#  include "MathFunctions.h"
#endif

Затем в том же файле мы делаем так, чтобы USE_MYMATH контролировала, какая функция квадратного корня используется:

TODO 12

tutorial.cxx

#ifdef USE_MYMATH
  const double outputValue = mysqrt(inputValue);
#else
  const double outputValue = sqrt(inputValue);
#endif

Поскольку исходный код теперь требует USE_MYMATH, мы можем добавить её в TutorialConfig.h.in с помощью следующей строки:

TODO 13

TutorialConfig.h.in

#cmakedefine USE_MYMATH

С этими изменениями наша библиотека теперь совершенно необязательна для тех, кто ее создает и использует.

Бонусный вопрос

Почему важно сконфигурировать TutorialConfig.h.in после добавления параметра USE_MYMATH? Что произойдет, если мы перевернем их местами?

Мы конфигурируем его после, потому что TutorialConfig.h.in использует значение USE_MYMATH. Если мы сконфигурируем этот файл перед вызовом option(), мы не будем использовать ожидаемое значение USE_MYMATH.

Теги

C++ / CppCMakeАвтоматизация сборкиПрограммированиеСистема сборкиСтатическая библиотека

На сайте работает сервис комментирования DISQUS, который позволяет вам оставлять комментарии на множестве сайтов, имея лишь один аккаунт на Disqus.com.

В случае комментирования в качестве гостя (без регистрации на disqus.com) для публикации комментария требуется время на премодерацию.