Копируем все разделяемые библиотеки (DLL) нужные для запуска программы с помощью CMAKE
В предыдущих статьях для сборки наших программ и библиотек мы использовали GCC, который по умолчанию добавляет к собираемым программам собственные разделяемые библиотеки. Для запуска этих программ, необходимо, чтобы файлы с соответствующими библиотеками были размещены или в папке с исполняемым файлом, либо в системных папках, доступных по пути в переменной PATH.
Сегодня мы рассмотрим автоматическое определение разделяемых библиотек, необходимых для запуска программы, а также их автоматической копирование в соответствующую папку с помощью CMake.
Настройка проекта
Начнем мы с проекта, размещенного в git-репозитории. Мы продолжим настройку проекта из прошлой статьи.
Если папка:
c:\project\colortable_copydllуже существует, переместите или удалите её:
cd c:\projects
rmdir /q/s colortable_copydllМы будем использовать проект из git-репозитория:
cd c:\projects
rmdir /q/s articles_blog_altuninvv_ru
git clone https://gitflic.ru/project/vasiliyaltunin/articles_blog_altuninvv_ru.git --depth 1Скопируем папку с проектом:
xcopy /y/e .\articles_blog_altuninvv_ru\qt6\colorconsole_libgit\ .\colortable_copydll\Оптимизируем проект CMake
Создадим требуемые папки и файлы
cd c:\projects\colortable_copydll
mkdir cmake
type nul > cmake\settings.cmake.in
type nul > cmake\conf.cmake.in
type nul > cmake\git.cmake.in
type nul > cmake\shared_deps.cmake.in
type nul > cmake\targets.cmake.in
type nul > cmake\install.cmake.inОткроем проект:
cd c:\projects\colortable_copydll
code .Изменим файл CMakeLists.txt
cmake_minimum_required(VERSION 3.16)
# Задаем имя проекта
project(colorconsoleapp VERSION 0.1 LANGUAGES CXX)
# Задаем переменные и настройки для использования
include(${PROJECT_SOURCE_DIR}/cmake/settings.cmake.in)
# Настраиваем зависимости и устанавливаем библиотеки из git-репозиториев
include(${PROJECT_SOURCE_DIR}/cmake/git.cmake.in)
# Задаем настройки сборки программы
include(${PROJECT_SOURCE_DIR}/cmake/conf.cmake.in)
# Задаем targets для библиотеки
include(${PROJECT_SOURCE_DIR}/cmake/targets.cmake.in)
# Настраиваем установку разделяемых (shared) библиотек
include(${PROJECT_SOURCE_DIR}/cmake/shared_deps.cmake.in)
# Настраиваем установку проекта
include(${PROJECT_SOURCE_DIR}/cmake/install.cmake.in)В файл cmake\settings.cmake.in добавим:
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Собираем разделяемую версию
set(BUILD_SHARED_LIBS ON CACHE INTERNAL "Build using shared libraries ON/OFF")
message(BUILD_SHARED_LIBS = ${BUILD_SHARED_LIBS})В файл cmake\git.cmake.in добавим:
# Подключаем модуль FetchContent
include(FetchContent)
# Отключаем тихий режим работы FetchContent
set(FETCHCONTENT_QUIET FALSE)
# Задаем настройки для загрузки из git-репозитория
FetchContent_Declare(
colorconsole # Имя target нашей библиотеки, должно совпадать с используемым далее
GIT_REPOSITORY https://gitflic.ru/project/vasiliyaltunin/color-console-library.git # Путь до репозитория
GIT_SHALLOW TRUE # Загружаем только последние коммиты
GIT_PROGRESS TRUE # Отображаем процесс загрузки
USES_TERMINAL_DOWNLOAD TRUE # Отображать прогресс в терминале (только для Ninja)
EXCLUDE_FROM_ALL TRUE # Не устанавливать саму библиотеку при использовании cmake --install
)
# Запускаем загрузку из git-репозитория и подключение библиотеки
FetchContent_MakeAvailable(colorconsole)В файл cmake\conf.cmake.in добавим:
add_executable(${PROJECT_NAME})
include(GNUInstallDirs)В файл cmake\targets.cmake.in добавим:
target_sources(${PROJECT_NAME}
PRIVATE
main.cpp
)
target_link_libraries(${PROJECT_NAME} PRIVATE ccon::colorconsole)В файл cmake\install.cmake.in добавим:
# Копируем разделяемую библиотеку из папки сборки библиотеки в папку сборки нашего проекта
add_custom_command(
TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${colorconsole_BINARY_DIR}/libcolorconsole.dll
${CMAKE_CURRENT_BINARY_DIR}/libcolorconsole.dll)Удалим старую папку build:
rmdir /q/s .\buildЗапустим конфигурирование:
cmake -S . -B buildЗапустим сборку
cmake --build buildЗапустим программу:
.\build\colorconsoleapp.exeВсе работает.
Поиск разделяемых библиотек от которых зависит наш проект
Для поиска разделяемых библиотек, необходимых для запуска программы мы будем использовать встроенный функционал CMake.
В файл cmake\shared_deps.cmake.in добавим:
message("== Shared dependency setup")
# Задаем папку, в которой нужно искать разделяемые библиотеки
set(MY_DEPENDENCY_PATHS C:/msys64/mingw64/bin)
# Преобразуем список в формат CMake
set(DLLS_DIR "${CMAKE_CURRENT_BINARY_DIR}")
# Делаем установленные переменные доступными во время запуска из блока install(CODE
install(CODE "set(MY_DEPENDENCY_PATHS \"${MY_DEPENDENCY_PATHS}\")")
install(CODE "set(DLLS_DIR \"${CMAKE_CURRENT_BINARY_DIR}\")")
# Запускаем на этапе установки программы
install(CODE [[
message("== Searching for shared DLL")
# Находим все файлы с разделяемыми библиотеками, которые нужны для запуска программы
file(GET_RUNTIME_DEPENDENCIES
EXECUTABLES $<TARGET_FILE:colorconsoleapp> # Обязательно должен совпадать с названием проекта
RESOLVED_DEPENDENCIES_VAR DLLS # Список с найденными библиотеками помещаем в переменную DLLS
# DIRECTORIES ${MY_DEPENDENCY_PATHS}
)
message("== Search completed")
]])Проведем реконфигурацию и сборку:
rmdir /q/s .\build
cmake -S . -B build
cmake --build buildЗапустим установку:
cmake --install build --prefix=..\colortableapp-- Install configuration: "Debug"
== Searching for shared DLLПосле продолжительного ожидания, процесс завершиться с ошибкой и будет выведен длинный список библиотек, которые не найдены:
CMake Error at build/cmake_install.cmake:53 (file):
file Could not resolve runtime dependencies:
api-ms-win-core-apiquery-l1-1-0.dll
api-ms-win-core-apiquery-l1-1-1.dll
api-ms-win-core-appcompat-l1-1-0.dll
api-ms-win-core-appcompat-l1-1-1.dll
…
api-ms-win-security-appcontainer-l1-1-0.dll
api-ms-win-security-base-l1-1-0.dll
api-ms-win-security-base-l1-2-0.dll
libstdc++-6.dllДля того, чтобы отфильтровать библиотеки самого Windows добавим новые параметры. Изменим блок:
# Находим все файлы с разделяемыми библиотеками, которые нужны для запуска программы
file(GET_RUNTIME_DEPENDENCIES
EXECUTABLES $<TARGET_FILE:colorconsoleapp> # Обязательно должен совпадать с названием проекта
RESOLVED_DEPENDENCIES_VAR DLLS # Список с найденными библиотеками помещаем в переменную DLLS
PRE_EXCLUDE_REGEXES "^api-ms-" "^ext-ms-"
POST_EXCLUDE_REGEXES ".*system32/.*\\.dll"
)Параметры:
PRE_EXCLUDE_REGEXES "^api-ms-" "^ext-ms-"
POST_EXCLUDE_REGEXES ".*system32/.*\\.dll"Содержат регулярные выражения, помогающие отфильтровать библиотеки Windows.
Запустим конфигурирование и установку:
cmake -S . -B build
cmake --install build --prefix=..\colortableappНа этот раз у нас список сократиться только до одной библиотеки:
-- Install configuration: ""
== Searching for shared DLL
CMake Error at build/cmake_install.cmake:53 (file):
file Could not resolve runtime dependencies:
libstdc++-6.dllНесмотря на то, что данная библиотека доступна по пути в системной переменной PATH, CMake не может её найти, нам нужно прямо указать папку, в которой находится данный файл, для этого изменим блок:
file(GET_RUNTIME_DEPENDENCIES
EXECUTABLES $<TARGET_FILE:colorconsoleapp> # Обязательно должен совпадать с названием проекта
RESOLVED_DEPENDENCIES_VAR DLLS # Список с найденными библиотеками помещаем в переменную DLLS
PRE_EXCLUDE_REGEXES "^api-ms-" "^ext-ms-"
POST_EXCLUDE_REGEXES ".*system32/.*\\.dll"
DIRECTORIES ${MY_DEPENDENCY_PATHS}
)Мы добавили параметр:
DIRECTORIES ${MY_DEPENDENCY_PATHS}Этот параметр указывает в какой папке производить поиск.
Запустим:
cmake -S . -B build
cmake --install build --prefix=..\colortableappНа этот раз процесс завершился без ошибок:
-- Install configuration: "Debug"
== Searching for shared DLL
== Search completedВывод списка найденных разделяемых библиотек
Мы успешно нашли все разделяемые библиотеки, необходимые для запуска программы, давайте выведем их список.
После строки:
message("== Search completed")Добавим:
foreach(DLL ${DLLS})
message("Dependency found: ${DLL}")
endforeach()Запустим конфигурирование и установку:
cmake -S . -B build
cmake --install build --prefix=..\colortableapp-- Install configuration: "Debug"
== Searching for shared DLL
== Search completed
Dependency found: C:/projects/colortable_copydll/build/libcolorconsole.dll
Dependency found: C:/msys64/mingw64/bin/libgcc_s_seh-1.dll
Dependency found: C:/msys64/mingw64/bin/libstdc++-6.dll
Dependency found: C:/msys64/mingw64/bin/libwinpthread-1.dllМы получили список из нескольких .dll файлов
Копирование найденных разделяемых библиотек в папку исполняемым файлом
Изменим блок:
message("== DLL Copying started…")
foreach(DLL ${DLLS})
message("Dependency copied: ${DLL}")
file(COPY ${DLL} DESTINATION ${DLLS_DIR})
endforeach()
message("== DLL Copying finished")Запустим конфигурирование и установку:
cmake -S . -B build
cmake --install build --prefix=..\colortableapp-- Install configuration: "Debug"
== Searching for shared DLL
== Search completed
== DLL Copying started…
Dependency copied: C:/projects/colortable_copydll/build/libcolorconsole.dll
Dependency copied: C:/msys64/mingw64/bin/libgcc_s_seh-1.dll
Dependency copied: C:/msys64/mingw64/bin/libstdc++-6.dll
Dependency copied: C:/msys64/mingw64/bin/libwinpthread-1.dll
== DLL Copying finishedПроверим содержимое папки build:
dir /w C:\projects\colortable_copydll\build\*.dllСодержимое папки C:\projects\colorconsole_libgit\build
libcolorconsole.dll libgcc_s_seh-1.dll libstdc++-6.dll libwinpthread-1.dllЗаключение
Сегодня мы рассмотрели автоматическое определение и копирование разделяемых библиотек, требующихся для программы с помощью CMake:
Произвели оптимизацию конфигурации CMake, разбив её на несколько файлов;
Добавили в конфигурацию код для поиска разделяемых библиотек;
Вывели список этих библиотек;
Настроили копирование разделяемых библиотек в папку с исполняемым файлом.
Добавить комментарий