Подключение внешних библиотек
Рассмотрим пример подключения внешней библиотеки OpenCV и сборку программы в терминале, а также в IDE Visual Studio и CLion, используя разные системы сборки.
OpenCV
Популярная библиотека для работы с изображениями. Будем рассматривать пример подключения библиотеки в программу, написанную на C. Для этого используется OpenCV версии 3.4 (sources), т.к. начиная с версии 4.0 C API было удалено из исходников библиотеки.
Структура баблиотеки выглядит следующим образом:
Общая структура библиотеки может поставляться в виде исходники (sources) + собранная версия библиотеки (build). OpenCV как раз можно скачать в таком варианте.
Mode Name
---- ----
d----- build
d----- sources
-a---- LICENSE.txt
-a---- LICENSE_FFMPEG.txt
-a---- README.md.txtНас интересует собранная версия, поэтому рассмотрим подробнее струкутуру директории build:
Mode Name
---- ----
d----- bin
d----- etc
d----- include
d----- java
d----- python
d----- x64
-a---- LICENSE
-a---- OpenCVConfig-version.cmake
-a---- OpenCVConfig.cmake
-a---- setup_vars_opencv3.cmdЧаще всего в библиотеках/фреймворках встречаются директории include, bin, lib, x86, x64, docs, 3rdparty, samples и прочие.
include
Заголовочные файлы, в которых описаны структуры/макросы/функции
bin
Исполняемые файлы и файлы динамических библиотек
lib
Файлы статических библиотек. Чаще всего внутри содержит директории x86, x64
lib-32 / x64
Чаще всего файлы статических библиотек, собранных под разные битности
docs
Документация
3rdparty
Сторонние библиотеки
samples
Примеры использования
Рассмотрим структуру поддиректорий include, bin, x64
Mode Name
---- ----
d----- opencv
d----- opencv2Mode Name
---- ----
-a---- cv.h
-a---- cv.hpp
-a---- cvaux.h
-a---- cvaux.hpp
-a---- cvwimage.h
-a---- cxcore.h
-a---- cxcore.hpp
-a---- cxeigen.hpp
-a---- cxmisc.h
-a---- highgui.h
-a---- ml.hMode Name
---- ----
d----- calib3d
d----- core
d----- dnn
d----- features2d
d----- flann
d----- highgui
d----- imgcodecs
d----- imgproc
d----- ml
d----- objdetect
d----- photo
d----- shape
d----- stitching
d----- superres
d----- video
d----- videoio
d----- videostab
-a---- calib3d.hpp
-a---- core.hpp
-a---- cvconfig.h
-a---- dnn.hpp
-a---- features2d.hpp
-a---- flann.hpp
-a---- highgui.hpp
-a---- imgcodecs.hpp
-a---- imgproc.hpp
-a---- ml.hpp
-a---- objdetect.hpp
-a---- opencv.hpp
-a---- opencv_modules.hpp
-a---- photo.hpp
-a---- shape.hpp
-a---- stitching.hpp
-a---- superres.hpp
-a---- video.hpp
-a---- videoio.hpp
-a---- videostab.hpp
-a---- world.hppMode Name
---- ----
-a---- imgcodecs.hpp
-a---- imgcodecs_c.h
-a---- ios.hMode Name
---- ----
-a---- opencv_ffmpeg3415_64.dllMode Name
---- ----
d----- vc14
d----- vc15Directory: P:\demo_lib\library\opencv\build\x64\vc15
Mode Name
---- ----
d----- bin
d----- lib
Directory: P:\demo_lib\library\opencv\build\x64\vc15\bin
Mode Name
---- ----
-a---- opencv_annotation.exe
-a---- opencv_createsamples.exe
-a---- opencv_ffmpeg3415_64.dll
-a---- opencv_interactive-calibration.exe
-a---- opencv_traincascade.exe
-a---- opencv_version.exe
-a---- opencv_version_win32.exe
-a---- opencv_visualisation.exe
-a---- opencv_world3415.dll
-a---- opencv_world3415.pdb
-a---- opencv_world3415d.dll
-a---- opencv_world3415d.pdb
Directory: P:\demo_lib\library\opencv\build\x64\vc15\lib
Mode Name
---- ----
-a---- OpenCVConfig-version.cmake
-a---- OpenCVConfig.cmake
-a---- OpenCVModules-debug.cmake
-a---- OpenCVModules-release.cmake
-a---- OpenCVModules.cmake
-a---- opencv_world3415.lib
-a---- opencv_world3415d.libКак можно заметить, заголовочные файлы не обязаны все лежать в одной директории, а могут быть расположенны по разным поддиректориям. Также в OpenCV версии 3 видно, что рядом могут лежать заголовочные с C и C++ API.
В OpenCV исполняемые файлы и файлы динамических библиотек самой OpenCV располагаются не в корневой bin директории. Такое также встречается, когда bin директорий в проекте несколько и в таком случае необходимые файлы динамический библиотек следует искать в директориях x86 и x64. Последняя в сброке OpenCV имеется.
vc14 и vc15 – директории, содержащие сборки под разными версиями Visual Studio. vc15 – сборка под VS 2017 и позднее, vc14 – VS 2015. Структура в директориях идентичная, так что будем рассматривать vc15.
Можно заметить, что и dll, и lib файлы представлены в двух вариациях, отличающихся суффиксом d. В OpenCV файлы библиотек с суффиксом d собраны с сохранением отладочной информации и их следует использовать при сборке программы в debug-конфигурации. Без суффикса – релизная сборка.
В качестве тестовой программы будем использовать код main.c, который позволяет открыть изображение, поданной через аргументы командной строки, в отдельном окне.
#include <stdio.h>
#ifdef OPENCV
#include <opencv/cv.h>
#include <opencv/highgui.h>
#include <opencv2/imgcodecs/imgcodecs_c.h>
#define WINDOW_NAME "Example"
#endif
int main(int argc, char* argv[])
{
printf("sizeof(size_t) = %zu\n", sizeof(size_t));
if (argc != 2)
{
fprintf(stderr, "ERROR! Usage: %s image-file", argv[0]);
return -1;
}
#ifdef OPENCV
IplImage* img = cvLoadImage(argv[1], CV_LOAD_IMAGE_COLOR);
cvNamedWindow(WINDOW_NAME, CV_WINDOW_AUTOSIZE);
cvShowImage(WINDOW_NAME, img);
cvWaitKey(0);
cvReleaseImage(&img);
cvDestroyWindow(WINDOW_NAME);
#endif
return 0;
}OpenCV (vcpkg)
Библиотеку можно установить при помощи пакетных менеджеров, например, vcpkg.
Для установки можно найти интсрукцию на сайте:
vcpkg install opencv3После установки в vcpkg/packages будут располагаться "установленные" (собранные из исходников под ваш таргет) библиотеки с их зависимостями. В названии также отображается битность прилагаемых библиотек.
Дополнительно в логах по окончании установки будет располагаться заклинание для CMake, например:
# opencv3 is compatible with built-in CMake variables. In case of multiple OpenCV version installed, set OpenCV_ROOT *before* the find_package call:
set(OpenCV_ROOT "${VCPKG_INSTALLED_DIR}/x64-windows/share/opencv3")
find_package(OpenCV REQUIRED)Подключение внешних библиотек в терминале
Попробуем собрать программу без указания особых ключей компиляции:
> clang -O2 .\main.c -o main.exeПри запуске программы получим:
> .\main.exe
sizeof(size_t) = 8
ERROR! Usage: ..\cmd_test\main.exe image-file
> .\main.exe "..\chat.png"
sizeof(size_t) - 8Попробуем указать сборку в другую битность (по умолчанию x64; установим x86):
> clang -O2 .\main.c -o main.exe -m32
> .\main.exe
sizeof(size_t) = 4
ERROR! Usage: ..\cmd_test\main.exe image-fileДействительно, программа собрана как 32-битная. Т.к. в нашем распоряжении имеются собранные файлы библиотек только в варианте x64, то в дальнейшем будем собирать программу 64-битную.
Как можно заметить, в коде нигде явно не объявлен макрос OPENCV и соотственно код, связанный с использованием библиотеки был отброшен на этапе препроцессинга.
Объявим макрос OPENCV на этапе сборки программы:
> clang -O2 .\main.c -o main.exe -m64 -D OPENCV
.\main.c:4:10: fatal error: 'opencv/cv.h' file not found
4 | #include <opencv/cv.h>
| ^~~~~~~~~~~~~
1 error generated.Ошибка гласит, что не удалось найти заголовочный файл. Мы не указали include directories, из-за чего на этапе препроцессинга поиск заголовочных файлов проводился только в директориях, заданных по умолчанию (директории компилятора и системные директории).
Исправим это. Примечание: в текущем примере директория opencv лежит относительно main.c по ..\library\opencv.
> clang -O2 .\main.c -o main.exe -m64 -D OPENCV -I "..\library\opencv\build\include\"
main-f71563.o : error LNK2019: unresolved external symbol cvLoadImage referenced in function mainmain-f71563.o : error LNK2019: unresolved external symbol cvNamedWindow referenced in function main
main-f71563.o : error LNK2019: unresolved external symbol cvShowImage referenced in function main
main-f71563.o : error LNK2019: unresolved external symbol cvWaitKey referenced in function main
main-f71563.o : error LNK2019: unresolved external symbol cvReleaseImage referenced in function main
main-f71563.o : error LNK2019: unresolved external symbol cvDestroyWindow referenced in function main
main.exe : fatal error LNK1120: 6 unresolved externals
clang: error: linker command failed with exit code 1120 (use -v to see invocation)Теперь можно заметить, что компиляция прошла успешно, а вот на этапе линковки возникли проблемы unresolved external symbol. Линковщику необходимо указать пути до файлов и сами файлы статических библиотек:
> clang -O2 .\main.c -o main.exe -m64 -D OPENCV -I "..\library\opencv\build\include\" -L "..\library\opencv\build\x64\vc15\lib\" -lopencv_world3416.lib
clang: error: no such file or directory: '.lib'Обратите внимание, если указать имя файла с расширением, то собрать программу не получится.
> clang -O2 .\main.c -o main.exe -m64 -D OPENCV -I "..\library\opencv\build\include\" -L "..\library\opencv\build\x64\vc15\lib\" -lopencv_world3416Ура, никаких ошибок линковки не возникло. Попробуем запустить программу:
> .\main.exe ; "0x"+$LastExitCode.ToString("X")
0xC0000135Теперь ошибка на старте программы. В таких случаях можно запустить программу через явное создание процесса или же из проводника:
> Start-Process .\main.exe ; "0x"+$LastExitCode.ToString("X")
Двойной клик по exe файлу из проводника

В обоих случаях удаётся найти сообщение об ошибке – не найден файл динамической библиотеки.
В таком случае есть 2 варианта:
Скопировать
.dll-файл рядом сexe-файлом.Добавить директорию, в которой лежит необходимый
.dll-файл в переменные окружения. В таком случае не нужно каждый раз копироватьdllкexe-файлу.
В этом примере подложим dll файл к exe:

При запуске видно, что всё открылось успешно и в консоли также видно данные, выводимые в программе.

Подключение внешних библиотек в системе сборки MSBuild (Visual Studio)
Система сборки MSBuild имеет консольный и пользовательский графический интерфейс. Рассмотрим настройку через графический интерфейс в среде разработки Visual Studio.
Добавим готовый файл main.c из начального примера в проект.

Все параметры и данные для сборки настраиваются через свойства решений и проектов в IDE Vusial Studio. Если в решении несколько проектов, то системе сборки MSBuild можно задать правила и порядок сборки проектов, что может быть полезно, если имеется зависимость между проектами в решении.
В нашем случае будет 1 проект в 1 решении и далее мы будем рассматривать только настройки проекта (ПКМ по проекту – Properties).
В первую очередь настоятельно рекомендуется установить общие для всех конфигураций и платформ настройки, установив Configurations и Platforms в All. Затем уже устанавливать параметры, различные для конфигураций и платформ. Это сильно сэкономит времени и нервов :)
В первой вкладке General можно настроить используемый toolset, название выходного файла, стандарт языка и пр.

Toolset – набор инструментов платформы, состоящий из компилятора C++ (cl.exe) и компоновщика (link.exe), а также стандартных библиотек C/C++.

По умолчанию будет доступен 1 toolset той VS, которая была установлена (например 2022). Через Visual Studio Installer можно поставить toolset более ранних VS, а также поставить clang (LLVM-Clang на скрине). Помимо этого компилятор Intel имеет интеграцию в VS и после установки также будет доступен в выпадающем списке.
Target name – имя выходного файла. Аналог -o у clang-а.
Стандарт языка позволяет явно задать под какой стандарт будет собираться программа. аналог -std= у clang-а.
Во вкладке Отладка можно настроить рабочую директорию и аргументы командной строки.

Рабочая директория – директория, относительно которой будет вестить поиск файлов. По умолчанию - каталог, содержащий файл проекта. Когда программа собирается из терминала, то рабочая директория – та, в которой вы находитесь в терминале.
На скриншотах выше вы могли заметить значения вида $(ProjectDir) и пр. Это макросы VS, которые будут раскрываться при сборке программы. Во что раскрываются макросы можно посмотреть при редактированнии полей:

Попробуем собрать и запустить нашу программу в Release x64 и Debug x86.


Переключение между конфигурациями происходит достаточно просто через опции на верхней панели среды разработки.
Однако как в случае со сборкой в терминале мы видим, что код OpenCV не был задействован, т.к. мы не указали полезных данных для среды разработки про OpenCV.
В первую очередь посмотрим на подсказки самой среды разработки:

Видно, что фрагмент кода в main() показывается тусклым. Так среда разработки подсказывает, что этот код не будет исполняться – либо код недостижим, либо будет отброшен на этапе препроцессинга. Второй вариант как раз характеризует наш случай.
Если укажем preprocessor defines, то картина изменится:

Теперь IDE явно подсказывает, что код будет исполняться, но про сами макросы и функции из OpenCV ничего не известно.
Укажем include directories:

В разделе C/C++/general помимо include directories можно изменить ключ компиляции warning levels для отлавливания большего числа предупреждений и нужно отключить SDL checks для наступления счастья.
Теперь при попытке сборки ожидаемо будут возникать ошибки линковки:
Build started at 16:33...
1>------ Build started: Project: OPENCV_VSProject, Configuration: Release x64 ------
1>main.c
1>main.obj : error LNK2001: unresolved external symbol cvWaitKey
1>main.obj : error LNK2001: unresolved external symbol cvReleaseImage
1>main.obj : error LNK2001: unresolved external symbol cvLoadImage
1>main.obj : error LNK2001: unresolved external symbol cvDestroyWindow
1>main.obj : error LNK2001: unresolved external symbol cvShowImage
1>main.obj : error LNK2001: unresolved external symbol cvNamedWindow
1>..\OPENCV_VSProject\x64\Release\OPENCV_VSProject.exe : fatal error LNK1120: 6 unresolved externals
1>Done building project "OPENCV_VSProject.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
========== Build completed at 16:33 and took 00.281 seconds ==========Которые исправим указанием файлов статических бибилотек и директорий, где они расположены. Обратите внимание, что здесь мы явно указываем платформу x64, т.к. собрана библиотека у нас только в этом варианте; а при задании файла мы не забудем для сборки в debug указать debug-версию библиотеки, а для release – release-файл.



Теперь сборка будет проходить успешно:
Build started at 16:38...
1>------ Build started: Project: OPENCV_VSProject, Configuration: Release x64 ------
1>Generating code
1>1 of 5 functions (20.0%) were compiled, the rest were copied from previous compilation.
1> 0 functions were new in current compilation
1> 0 functions had inline decision re-evaluated but remain unchanged
1>Finished generating code
1>OPENCV_VSProject.vcxproj -> ..\OPENCV_VSProject\x64\Release\OPENCV_VSProject.exe
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
========== Build completed at 16:38 and took 00.311 seconds ==========А для корректного старта необходимо в корень проекта или к exe-файлам подложить dll файлы (подсказка: в корень проекта проще).
Подключение внешних библиотек в системе сборки CMake (Visual Studio)
Visual Studio 2022 поддерживает CMake и позволяет писать CMake-проекты.
Также помимо запуска под Windows есть возможность настроить запуск под WSL (есл установлен) или же настроить запуск с удаленного хоста.

По умолчанию создано несколько стандартных конфигураций сборки программы:

По умолчанию все проекты CMake в VS создаются как C++-проекты и при необходимости необходимо самостоятельно изменить в свойствах проекта язык с C++ (CXX) на C.
Свойства проекта представлены в виде CMakeLists.txt файла:
# CMakeList.txt : CMake project for OPENCV_CmakeProject, include source and define
# project specific logic here.
#
cmake_minimum_required (VERSION 3.8)
# Enable Hot Reload for MSVC compilers if supported.
if (POLICY CMP0141)
cmake_policy(SET CMP0141 NEW)
set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<IF:$<AND:$<C_COMPILER_ID:MSVC>,$<CXX_COMPILER_ID:MSVC>>,$<$<CONFIG:Debug,RelWithDebInfo>:EditAndContinue>,$<$<CONFIG:Debug,RelWithDebInfo>:ProgramDatabase>>")
endif()
add_executable(OPENCV_CmakeProject OPENCV_CmakeProject.c)Для дальнейшей работы рекомендуется удалить из проекта автосгенерированные исходники и прописать CMakeLists.txt самостоятельно. В случаи использования OpenCV также рекомендуется убрать весь if (POLICY CMP0141) ... endif().
После объявления минимально подходящей версии CMake следует явно указать переменную проекта (версия проекта опциональна):
project(OPENCV_CmakeProject VERSION 0.1)Укажем явно, что мы хотим собирать проект под C17 и, например, что поддержка этого стандарта нам необходима для сборки (более ранние версии не подойдут):
set(CMAKE_C_STANDART 17)
set(CMAKE_C_STANDART_REQUIRED True)Дополним его необходимыми сведениями про OpenCV.
Заведём для примера переменную, содержащую все файлы проекта, которые будут подаваться на компиляцию
set(SOURCES "OPENCV_CmakeProject.c")Укажем макрос
add_definitions(-DOPENCV)Дополним ключи компиляции по умолчанию ключом про уровень предупреждений (по умолчанию
/W3, терминология компилятора MSVC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W4")Укажем include directories (здесь и далее полагаем, что OpenCV лежит рядом с нашим проектом)
include_directories("../library/opencv/build/include")Укажем при сборке в
x64library directories (32-битной версии библиотеки у нас нет, поэтому не будем рассматривать данную ветку)
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
link_directories("../library/opencv/build/x64/vc15/lib")
endif()Модифицируем аргументы конструкции
add_executable
add_executable(OPENCV_CmakeProject ${SOURCES})Дополним сведения о файлах статических библиотек
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
if (CMAKE_BUILD_TYPE EQUAL "Debug")
target_link_libraries(OPENCV_CmakeProject "opencv_world3415d.lib")
els()
target_link_libraries(OPENCV_CmakeProject "opencv_world3415.lib")
endif()
endif()CMAKE_BUILD_TYPE нам известен из файла CMakePresets.json, в котором указаны компилтор и подсистема сборки (по умолчанию Ninja), а также переменные каждой конфигурации, которые можно смело использовать в CMakeLists.txt.
Примечение: при изменении CMakeLists.txt они автоматически сохраняются и сразу происходит регенерация кеша сборки:

Там содержаться логи регенерации с ошибками (если они есть). В противном случае будет CMake generation finished.. Из полезного: Command line:, в которой можно посмотреть параметры, с которым вас по итогу собирают, и Working directory: – рабочая директория проекта (та, где лежит сформированный выходной файл).
Чтобы задать аргументы командной строки необходимо:
Переключить отображение в
Solution ExplorerнаProject View

Перейти в
Add Debug Configurations(ПКМ по проекту)

Прописать параметры
currentDir(WorkingDirectory) иargs(command-line arguments) в открывшемсяlaunch.json:
{
"version": "0.2.1",
"defaults": {},
"configurations": [
{
"type": "default",
"project": "CMakeLists.txt",
"projectTarget": "OPENCV_CmakeProject.exe",
"name": "OPENCV_CmakeProject.exe",
+ "currentDir": ".",
+ "args": [
"../chat.png"
]
}
]
}После проделанных манипуляций при указании на верхней панели конфигураций x64 Release и x64 Debug будет собираться программа, запускаться с переданным аргументом и показываться картинка на экране, а приx86 Release и x86 Debug – ошибка линковки.
Подключение внешних библиотек в системе сборки CMake (CLion)
Сам файл CMakeLists.txt почти ничем не будет отличаться, за исключением:
cmake_minimum_required (VERSION 3.8)вероятно будет более новой версии# Enable Hot Reload for MSVC compilers if supported.и связанный с этим комментариемifбудет отсутствоватьфлаги компиляции следует указывать те, которые нужны для используемого
toolchain– еслиtoolchainне VS, то/W4можно заменить на-Wall -Wextra -Wpedantic
Подробнее про toolchain в CLion: clang-clion
Last updated