Преобразуем проект C++ в библиотеку с помощью CMake. Библиотеки С++ и CMake. Часть 1
Сегодня мы создадим библиотеку C++, а для для настройки проекта используем CMake.
В прошлой статье - мы создали класс ColorConsole. При написании консольных приложений для Windows он может быть очень полезен, но каждый раз копировать исходный код библиотеки в каждый новый проект не очень удобно.
Создадим копию папки нашего проекта из прошлой статьи – https://blog.altuninvv.ru/яп/c/вывод-цветного-текста-в-консоль-на-с
cd c:\projects
xcopy colorconsole colorconsolelib\ /s /e /hУдалим ненужные файлы и папки
cd colorconsolelib
del main.cpp
rmdir /S /Q buildСоздадим новые файлы и папки:
mkdir cmake
type nul > cmake/colorconsole-config.cmake.inСоздадим папку для исходного кода и перенесем файлы:
mkdir src
move *.cpp src\
move *.h src\Такой подход довольно удобен, так как позволяет отделить программный код от прочих файлов и предотвращает превращения корневой папки в мешанину из исходного кода, документации и файлов настроек CMake.
Откроем новую папку в vscode:
code .Добавляем пространство имен
В C++ существует механизм пространства имен. Его использование позволяет избежать ситуации, когда, например, два программиста выбрали для своих классов или функций одинаковые имена. И когда их код попадает в проект, линковщик не может разобраться что и с чем связывать, и просто выдает ошибку.
При использовании пространства имён такой ситуации не случится, и даже если в проекте встретятся классы с одинаковыми именами, достаточно перед именем будет указать пространство имен!
В нашей библиотеке мы будем использовать пространство имен:
cconЭто сокращение от:
C ConsoleДобавим в colorconsole.h перед:
class ColorConsoleстроки:
namespace ccon
{И в самый конец файла, перед:
#endifДобавим:
}Добавим в colorconsole.cpp перед:
ColorConsole::ColorConsole()строки:
namespace ccon
{И в самый конец файла:
}Добавляем внешний заголовочный файл
Внешний заголовочный файл это еще одна из особенностей библиотек CMake.
На самом деле их использование оправдано и полезно. При сборке проекта используется заголовочный файл находящийся в папке src. Для пользователей автор библиотеки может подготовить специальную версию, содержащую только необходимые для пользователей функции и классы и более подробную документацию.
Создадим папку для заголовочных файлов и скопируем заголовок:
mkdir include
copy src\*.h include\CMakeFiles.txt для библиотеки C++
Для правильного создания библиотеки на с использованием Cmake необходимо,чтобы полученный проект соответствовал множеству условий. Это и структура папок и наличие в соответствующих папках файлов заголовков и файлов с настройками для CMake.
Приведенный ниже файл содержит минимальный набор инструкций для создания библиотеки CMake отвечающей современным требованиям. В будущих статьях мы будем его модернизировать, когда будем рассматривать создание динамической библиотеки и преобразовывать нашу библиотеку в кроссплатформенную!
Создавая этот файл я старался сделать его максимально универсальным. Вы можете легко поменять имя библиотеки и пространство имён. При желании можно объединить три переменные в одну, так как в трех из них содержится одно и тоже имя, но я специально оставил место для маневра, если в будущем потребуется более точная настройка!
Заменим содержимое файла CMakeFiles.txt:
cmake_minimum_required(VERSION 3.14)
# Имя оно же target проекта, его описание и язык
project(colorconsole
VERSION 0.1.0
DESCRIPTION "Библиотека для вывода цветного текста в консоль"
LANGUAGES CXX)
### Инициализация
# Требования к версии C++ и поддержки стандарта
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Загружаем данные о путях до папок в которые установлены библиотеки C++
include(GNUInstallDirs)
# Задаем переменные для использования
# Задаем пространство имен
set("MAIN_NAMESPACE" "ccon")
set("PROJECT_NAMESPACE" "colorconsole")
# Префикс который используется для файлов конфигурации cmake
set("MY_CMAKE_PREFIX" "colorconsole")
# Имя файла для библиотеки к нему автоматически будет добавлено lib
set("MY_LIB_OUTPUT_NAME" "colorconsole")
# Задаем путь для установки CMake-файлов проекта
set("COLORCONSOLE_INSTALL_CMAKEDIR" "${CMAKE_INSTALL_LIBDIR}/cmake/${MY_CMAKE_PREFIX}" CACHE STRING
"Install path for colorconsole package-related CMake files"
)
# Имена файлов, содержащие исходный код библиотеки
set(sources
src/colorconsole.cpp
src/colorconsole.h
)
# Имя файла с настройками для статической сборки библиотеки
set(targets_file "${MY_CMAKE_PREFIX}-static-targets.cmake")
### Основная часть
# Инициализируем проект как библиотеку
add_library(${PROJECT_NAME})
# Инициализируем пространство имен и алиас
add_library(${MAIN_NAMESPACE}::${PROJECT_NAMESPACE} ALIAS ${PROJECT_NAME})
# Загружаем модули CMake
include(GenerateExportHeader)
include(CMakePackageConfigHelpers)
# Добавляем файлы с исходным кодом к нашему проекту
target_sources(${PROJECT_NAME} PRIVATE ${sources})
# Добавляем папку src к нашему проекту
target_include_directories(${PROJECT_NAME}
PRIVATE
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>"
)
# Если библиотека используется как папка, открываем доступ к заголовочным файлам
target_include_directories(${PROJECT_NAME}
PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
)
# Создаем файл конфигурации и указываем папку для его установки
configure_package_config_file(cmake/${MY_CMAKE_PREFIX}-config.cmake.in colorconsole-config.cmake
INSTALL_DESTINATION "${COLORCONSOLE_INSTALL_CMAKEDIR}"
)
# Создаем файл конфигурации с указанием версии нашей библиотеки и указываем папку для его установки
write_basic_package_version_file(${MY_CMAKE_PREFIX}-config-version.cmake
COMPATIBILITY SameMajorVersion
VERSION ${PACKAGE_VERSION}
)
# Создаем правила для установки проекта
install(TARGETS ${PROJECT_NAME}
EXPORT lib_export
INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
)
# Указываем что нужно скопировать содержимое каталога ./include и что это заголовочные файлы
install(DIRECTORY include/
TYPE INCLUDE
)
# Создаем правила установки файла *-static-targets.cmake
install(EXPORT lib_export
FILE "${targets_file}"
DESTINATION "${COLORCONSOLE_INSTALL_CMAKEDIR}"
NAMESPACE "${MAIN_NAMESPACE}::"
)
# Создаем правила для установки файлов *-config.cmake и *-config-version.cmake
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/${MY_CMAKE_PREFIX}-config.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/${MY_CMAKE_PREFIX}-config-version.cmake"
DESTINATION "${COLORCONSOLE_INSTALL_CMAKEDIR}"
)
# Имя файла библиотеки. К нему автоматически будет добавлено lib
set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME "${MY_LIB_OUTPUT_NAME}")Нажмем F1
Введем
CMakeВыберем
CMake: Select a KitИ выберем строку начинающуюся с:
GCC 15Обратите внимание, мы создали пустой файл:
cmake/colorconsole-config.cmake.inДанный файл в будущем будет содержать инструкции CMake для сборки статической и динамической версий библиотеки, но в данный момент он нам не нужен. Мы оставляем его как заглушку на будущее.
Запустим конфигурирование проекта, я буду использовать консоль, вы можете использовать панель CMake в VSCode:
В терминале запустим конфигурирование
cmake -S . -B buildЗапустим сборку
cmake --build build[ 50%] Building CXX object CMakeFiles/colorconsole.dir/src/colorconsole.cpp.obj
[100%] Linking CXX static library libcolorconsole.a
[100%] Built target colorconsoleСборка успешна, будет создана папка build, а в ней файл с нашей библиотекой:
libcolorconsole.aУстановка библиотеки
Перед использованием библиотеку нужно установить.
Всего есть три способа установки:
1. Установка в отдельную папку
2. Установка в системную папку
3. Установка в папку проекта, который будет использовать библиотеку
Сегодня мы рассмотрим установку в папку проекта.
Подготовка проекта к установке библиотеки
Прежде чем продолжить, давайте очистим старый проект из статьи - https://blog.altuninvv.ru/яп/c/вывод-цветного-текста-в-консоль-на-с от лишнего кода, папок и файлов.
Вернемся к нашему проекту в консоли cmd введем:
cd c:\projects\colorconsoleУдалим ненужные файлы:
del colorconsole.cpp colorconsole.hЧтобы нам проще было возвращаться к чистому проекту создадим локальный репозиторий git.
В cmd запустим:
cd c:\projects\colorconsole
git initСоздадим файл:
type nul > .gitignoreДобавим в него строки:
build/
.vscode/Запустим в консоли cmd:
git add .
git commit -m "v1"[master (root-commit) a070120] v1
3 files changed, 85 insertions(+)
create mode 100644 .gitignore
create mode 100644 CMakeLists.txt
create mode 100644 main.cppБыл создан первый коммит и наши изменения были зафиксированы в репозитории git, теперь при необходимости мы можем всегда вернуться к чистому проекту!
Добавляем библиотеку в наш проект
Самый простой способ подключить библиотеку к нашему проекту это добавить папку с библиотекой в папку нашего проекта. Этот способ лучше всего использовать при разработке самой библиотеки или если вам очень важно использовать фиксированную версию библиотеки по тем или иным причинам, например по причине обратной совместимости.
В следующих статьях мы рассмотрим обычный способ установки и использования библиотеки, при котором в отдельную папку устанавливаются заголовочные файлы, файл .a и файлы .cmake.
Создадим папку lib:
mkdir c:\projects\colorconsole\libСкопируем папку с библиотекой в эту папку:
xcopy c:\projects\colorconsolelib c:\projects\colorconsole\lib\colorconsolelib\ /s /e /hОткроем проект вVSCode:
cd c:\projects\colorconsole
code .Изменим содержимое CMakeFiles.txt:
cmake_minimum_required(VERSION 3.16)
project(colorconsoleapp VERSION 0.1 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_executable(${PROJECT_NAME})
target_sources(${PROJECT_NAME}
PRIVATE
main.cpp
)
include(GNUInstallDirs)
target_link_libraries(${PROJECT_NAME} ccon::colorconsole)
add_subdirectory(lib/colorconsolelib)Здесь мы просто включаем папку lib/colorconsolelib в наш проект и добавляем указания для CMake, что наш проект нужно собрать с библиотекой:
ccon::colorconsoleТак как в папке библиотеки уже есть специально сформированный для этих целей файл CMakeLists.txt то и со сборкой проблем не возникнет.
Прежде чем продолжить удалим из папки с библиотекой папку build:
del /F /Q c:\projects\colorconsole\lib\colorconsolelib\buildОна больше не понадобится, так как сборка всех необходимых компонентов будет происходить в папке build нашего проекта.
Запустим конфигурирование:
cmake -S . -B build-- Building for: Ninja
-- The CXX compiler identification is GNU 15.1.0
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: C:/msys64/mingw64/bin/c++.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done (1.1s)
-- Generating done (0.0s)
-- Build files have been written to c:/projects/colorconsole/buildЗапустим сборку:
cmake --build buildПолучим много ошибок:
C:/projects/colorconsole/main.cpp: In function 'int main(int, char**)':
C:/projects/colorconsole/main.cpp:7:5: error: 'ColorConsole' has not been declared
7 | ColorConsole::init();
| ^~~~~~~~~~~~
C:/projects/colorconsole/main.cpp:8:5: error: 'ColorConsole' has not been declared
8 | ColorConsole::setConsStdOutColor(4);
| ^~~~~~~~~~~~
C:/projects/colorconsole/main.cpp:11:5: error: 'ColorConsole' has not been declared
11 | ColorConsole::setConsStdOutColor(ColorConsole::DARK_GREEN);
| ^~~~~~~~~~~~Все от того, что мы забыли добавить пространство имен к имени класса. Мы можем поступить проще и объявить использование имени класса:
ccon::ColorConsole Из пространства имен ccon.
Для этого в файл main.cpp перед:
int main(int argc, char *argv[])Добавим:
using ccon::ColorConsole;Запустим сборку:
cmake --build build[build] [ 25%] Building CXX object lib/colorconsolelib/CMakeFiles/colorconsolelib.dir/src/colorconsole.cpp.obj
[build] [ 50%] Linking CXX static library libcolorconsole.a
[build] [ 50%] Built target colorconsolelib
[build] [ 75%] Building CXX object CMakeFiles/colorconsole.dir/main.cpp.obj
[build] [100%] Linking CXX executable colorconsole.exe
[build] [100%] Built target colorconsole
[driver] Build completed: 00:00:05.363
[build] Build finished with exit code 0Обратите внимание, сборка нашей библиотеки произведена автоматически при сборке основного проекта. В папке сборки появилась папка:
build\lib\colorconsolelib\С файлом нашей библиотеки:
libcolorconsole.aТак же хочу обратить ваше внимание, что несмотря на том, что библиотека расположена в папке:
C:\projects\colorconsole\lib\colorconsolelibА заголовочный файл colorconsole.h в папке:
C:\projects\colorconsole\lib\colorconsolelib\includeНам не пришлось менять пути к заголовочному файлу:
#include "colorconsole.h"Всё потому, что CMake и расширения для VSCode автоматически, на основании настроек в файлах CMakeLists.txt библиотеки и нашего проекта, нашли и подключили все нужные папки!
Запустим проект:
Результат тот же. Но теперь у нас в программе используется библиотека.
Такой подход очень удобен для разработки самой библиотеки, так как у вас всегда есть доступ к любому файлу библиотеки, так как она является подпапкой основного проекта.
Откроем файл colorconsole.cpp
И внесем изменения в метод:
void ColorConsole::emptyLine()
{
ColorConsole::setConsStdErrDefColor();
std::cout << "{}" << std::endl;
}Таким образом в конце строк мы будем добавлять {}
Запустим проект:
Как видите, всё очень просто. Вы можете вносить изменения в саму библиотеку, а в проект добавлять код для тестирования самой библиотеки.
Заключение
Сегодня мы рассмотрели создание библиотеки C++ с использованием CMake:
Создали папку с копией проекта colorconsole;
Удалили ненужные папки и файлы;
Создали дополнительные файлы и папки и перенесли исходный код в папку src;
Добавили в исходный код пространство имен ccon;
Добавили папку с внешним заголовочным файлом;
Создали файл CMakeFiles.txt для нашей библиотеки;
Установили нашу библиотеку как папку в проект colorconsole удалив исходный код класса;
Собрали проект и внесли изменения для корректного использования библиотеки.
Добавить комментарий