Понедельник, 15.09.2025 19:00

Копируем все разделяемые библиотеки (DLL) нужные для запуска программы с помощью CMAKE

Копируем все разделяемые библиотеки (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, разбив её на несколько файлов;

Добавили в конфигурацию код для поиска разделяемых библиотек;

Вывели список этих библиотек;

Настроили копирование разделяемых библиотек в папку с исполняемым файлом.

Категория C++
Теги Cpp CMAKE

Добавить комментарий

Простой текст

  • HTML-теги не обрабатываются и показываются как обычный текст
  • Строки и абзацы переносятся автоматически.
  • Адреса веб-страниц и email-адреса преобразовываются в ссылки автоматически.
Просмотров: 165