Тайные знания: библиотеки для С++
Многие начинающие программисты, уже освоив синтаксис C++, обнаруживают, что нет простого способа как подключить библиотеку, так и собрать программу для другой ОС, или чего хуже, под другим компьютером с той же ОС.
Это проблема отчасти порождается спорной практикой в обучении, когда код учат писать и запускать средствами IDE, таких как Visual Studio, Code::Blocks, и других. Поначалу такой подход работает, но лишь до первой реальной задачи сделать что-то, что запустится не только на вашем компьютере. Тут-то новички и сталкиваются с отсутствием стандартной системы сборки и менеджера зависимостей. После осознания этой сложности, большинство студентов, как правило, переходят на другие языки, попутно тиражируя в индустрии миф о том, что C++ де не кроссплатформенный язык, а вот мой Python/Java/C# — да. Между тем нас окружает множество замечательных кроссплатформенных программ написанных на C++. Если вы обучаетесь C++ и хотите понять как создавать такое ПО, то эта статья для вас.
1. Минутка теории. Получение исполняемого файла всегда и везде, зачем это необходимо?
Если вы читаете эту статью, то наверное, отдалено уже понимаете, что преобразует код компилятор (а склеивает в один исполнямый файл линковщик), но на практике, скорее всего до сих пор не сталкивались с этим, запуская сборку в один исполняемый файл сразу из IDE. Возможно вы вообще не пробовали собрать программу в файл, запуская её красивой зелененькой кнопочкой Run.
Однако и сама IDE, в свою очередь, не собирает и не запускает ваш код, а лишь вызывает специальную программу, которая называется система сборки, или сборщик, который-то и отвечает за сборку проекта и взаимодействие с компилятором и линковщиком.
У Visual Studio, к примеру, сборщиком по умолчанию является MSBuild, а у CLion — CMake. Те дополнительные файлы, которые вы видите, создав новый проект через интерфейс IDE, и являются конфигурацией для системы сборки. Наша задача просто научиться взаимодействовать с ней напрямую. Для этого мы возьмем CMake, потому что в отличие от MSBuild, эта система сборки запускается на большинстве ОС.
Почему надо разобраться в конфигурации системы сборки? Разве мне недостаточно среды, спросите вы? Потому что ваша среда может запуститься не везде, а система сборки гораздо более переносима, с ней вы сможете автоматизировать сборку, использовать контейнеры Docker, сможете оставить в репозитории билд скрипт который соберет ваш код на любом компьютере — ну разве не круто?
2. Пишем конфигурацию сборки самостоятельно
Итак, пришло время выйти из уютного мира в IDE, и вступить на путь уже кроссплатформенной стрельбы себе в ногу. Прежде всего, убедитесь что ваш код использует только стандартные функции С++. Если он вызывает ОС-зависимые API, вроде #include , то рассмотрите чем их можно заменить. После этого воспользуемся следующим шаблоном CMake и создадим новый файл CMakeLists.txt:
cmake_minimum_required(VERSION 3.18) set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) # Подключаем менеджер зависимостей Conan list(APPEND CMAKE_MODULE_PATH $) list(APPEND CMAKE_PREFIX_PATH $) if (NOT EXISTS "$/conan.cmake") message(STATUS "Downloading conan.cmake from https://github.com/conan-io/cmake-conan") file(DOWNLOAD "https://raw.githubusercontent.com/conan-io/cmake-conan/v0.16.1/conan.cmake" "$/conan.cmake" EXPECTED_HASH SHA256=396e16d0f5eabdc6a14afddbcfff62a54a7ee75c6da23f32f7a31bc85db23484 TLS_VERIFY ON) endif () include($/conan.cmake) # Подключаем репозиторий зависимостей https://conan.io conan_add_remote(NAME conan-center INDEX 1 URL https://center.conan.io VERIFY_SSL True) # Скачиваем нужные нам зависимости, например: conan_cmake_configure(REQUIRES catch2/2.13.6 spdlog/1.8.5 threadpool/20140926 simdjson/0.9.6 icu/69.1 GENERATORS cmake_find_package) conan_cmake_autodetect(settings) conan_cmake_install(PATH_OR_REFERENCE . BUILD missing REMOTE conan-center SETTINGS $) # Делаем зависимости видимыми для CMake find_package(Catch2) # фреймворк тестирования find_package(ICU) # работа с юникодом find_package(spdlog) # логирование find_package(simdjson) # парсинг json с помощью simd find_package(ThreadPool) # ThreadPoolExecutor # Подключаем файлы с основным кодом file(GLOB proj_sources src/*.cpp) add_executable(app $) # Линкуем зависимости для основного кода (имена для линковки можно вытащить из описания зависимостей) target_link_libraries(app PRIVATE ThreadPool::ThreadPool spdlog::spdlog simdjson::simdjson ICU::io ICU::i18n ICU::uc ICU::data) # Подключаем файлы с кодом тестов list(FILTER proj_sources EXCLUDE REGEX ".*/Main.cpp$") file(GLOB test_sources test/*.cpp) add_executable(test $ $) # Линкуем зависимости для тестов target_link_libraries(test PRIVATE Catch2::Catch2 ThreadPool::ThreadPool spdlog::spdlog simdjson::simdjson ICU::io ICU::i18n ICU::uc ICU::data)
В этом шаблоне задаётся практически все, что нужно вам для сборки:
- Устанавливается стандарт C++20
- Подключается репозиторий библиотек Conan
- Задается соглашение, что файлы с кодом (.cpp, .h) будут лежать в папке src.
- Задается соглашение, что файлы с кодом для тестов будут лежать в паке test.
- Задаётся соглашение, что точки входа (int main) будут лежать в файлах Main.cpp
Убедитесь что ваш код хранится по этим соглашениям.
В скрипте также сразу подключается для примера несколько библиотек, по аналогии, следуя комментариям, вы можете добавить нужные вам.
Искать их можно тут: conan.io.
3. Как теперь собрать наше приложение в файл?
Мы отказались от кнопочек IDE в пользу более могущественного скрипта. Теперь нам понадобится платформа GCC или LLVM (возможно они уже есть на вашем компьютере), установленная система сборки CMake и менеджер зависимостей Conan. Их легко установить при помощи пакетного менеджера вашей ОС, или вручную, с официальных сайтов.
Откройте терминал в папке, где лежит CMakeLists.txt. Сначала нужно подготовить make-файлы. Воспринимайте это как предварительное действие:
cmake -DCMAKE_BUILD_TYPE=Release -G "Unix Makefiles" -B bin
После этого можно собрать само приложение и тесты:
cmake --build bin --target all
Приложение будет расположено в директории bin в файле под именем app .
Тесты могут быть запущены при помощи отдельного файла test в той же директории.
Вот и всё! Не так уж сложно, правда? Теперь вы можете распространять свое ПО на разные ОС, легко собирать его и подключать библиотеки. Если вы попробовали и что-то не работает, или есть какие-то вопросы, то их можно задать в комментариях под этой статьёй, постараюсь ответить.
После того как вы разберетесь как это делать, можно пользоваться моим project-wizard’ом для создания кроссплатформенных C++ утилит и библиотек в один клик: github.com/demidko
Однако сперва рекомендую попробовать воспроизвести результат самостоятельно, для лучшего понимания, что именно вы делаете, ведь в процессе приходят осознание и навык.
- С++
- кроссплатформенность
- cmake
- как подключить библиотеку C++
- как пользоваться cmake
- cmake инструкция
- как пользоваться conan
- conan инструкция
- Программирование
- C++
- Терминология IT
- Системы сборки
- Учебный процесс в IT
FAQ: Как подключить библиотеку на C/C++? Зачем файлы .h, .lib, .dll?
Этот вопрос довольно часто возникает у начинающих, а также у программистов, которые привыкли работать с языками, имеющими встроенную поддержку импорта из модулей (например, Delphi/Pascal).
В языке C исторически сложилось иначе. Чтобы подключить библиотеку к программе на языке C или C++, нужно выполнить два действия:
- Включить в исходный текст заголовочные файлы библиотеки (.h или .hpp) директивой #include
- Обеспечить, чтобы при сборке программы использовались соответствующие объектные файлы библиотеки (в зависимости от системы они могут иметь расширения .lib, .a, .o, .obj и т.д.) В зависимости от используемого компилятора это делается разными способами, например:
– добавить файл(ы) в проект как объектные;
– в MS Visual Studio: добавить имя файла в Linker->Input->Additional Dependencies (если файл в другом каталоге, путь добавить в Linker->General->Additional Library Directories);
– при использовании make прописать файл в список файлов для линкера (обычно это LIBS= или т.п.).
А если библиотека представлена в исходных текстах, надо просто добавить все нужные .c (.cpp) файлы в проект программы.
Файлы .lib должны быть совместимы с используемым компилятором и ОС. Поэтому к библиотеке может прилагаться несколько наборов файлов для разных сред.
Файлы .dll (динамическая библиотека Windows) не нужно указывать при компиляции, они используются при выполнении программы (о динамических библиотеках см. ниже).
В чём смысл этих действий, зачем нужны все эти разные файлы?
Файл заголовков (.h) нужен для того, чтобы компилятор мог распознать идентификаторы (имена макросов, типов, переменных, функций), которые определены в библиотеке. Специального средства для импорта имён в стандартном C нет, и для этого используется директива препроцессора #include, которая вставляет включаемый файл как исходный текст, как если бы он был написан вместо директивы #include.
В файлах .h идентификаторы объявляются, но не определяются (decalared but not defined), т.е. под переменные не выделяется пространство, а функции не имеют кода. Это достигается использованием ключевого слова extern для переменных, а для функций даются прототипы, например:
/* mylib.h */
extern int mylib_global_variable;
int mylib_function(int x, int y);
Если эти объявления включить через #include, то компилятор сможет скомпилировать .c файл, в котором упоминаются mylib_global_variable и mylib_function, например:
/* myprog.c */
#include «mylib.h»
int main(void)
mylib_global_variable = 1;
return mylib_function(mylib_global_variable, 2);
>
После компиляции получится объектный файл (например, myprog.o), причем в нём эти идентификаторы будут описаны как внешние. Но линкер не сможет собрать такую программу в готовый исполнимый файл, потому что для этих идентификаторов нет определений, т.е. есть имена, но нет «тела».
При попытке собрать программу будет выдано сообщение об ошибке «undefined external».
Теперь нужно, чтобы при сборке программы нашёлся объектный файл, в котором реализованы все эти переменные и функции. Допустим, у нас есть исходный текст библиотеки – например, такой:
/* mylib.c */
int mylib_global_variable = 0;
int mylib_function(int x, int y)
return x + y;
>
Тогда при его компиляции получится объектный файл, который можно соединить с нашей основной программой (включить оба .c файла в проект или makefile), и всё готово.
Если же библиотека уже скомпилирована отдельно, то нужно взять готовые объектные файлы (.lib или .a – это по сути контейнеры объектных файлов) и передать их линкеру.
Это в общих чертах всё, что касается статических библиотек, т.е. таких, код которых попадает в исполнимый файл основной программы.
О динамических библиотеках следует сказать отдельно. Динамическая библиотека отличается тем, что её код хранится в отдельном файле (Windows – .dll, в системах типа GNU/Linux и FreeBSD – .so) и загружается операционной системой при запуске программы, либо самой программой по мере надобности.
Рассмотрим оба способа на примере Windows.
Чтобы подключить динамическую библиотеку с загрузкой при запуске, используются файлы .h и .lib – точно так же, как в случае статической библиотеки. Просто в данном случае .lib файл содержит не сам код, а ссылки на импортируемые функции из DLL, так что после компиляции получается .exe файл, в котором есть ссылки на нужную DLL. Файл .dll при компиляции не нужен, зато нужен при запуске (в каталоге с .exe файлом, в системных каталогах Windows, в каталогах, перечисленных в переменной окружения PATH и т.д.).
Также можно загружать динамическую библиотеку «вручную» функциями LoadLibrary и GetProcAddress. Тогда .lib файл не нужен вообще, а .h включить обычно нужно (чтобы иметь описания типов и констант-макросов), но к функциям обращаться нужно будет не по именам из .h, а через указатели соответствующих типов, например:
/* . */
typedef int (*my_funct_ptr_t)(int, int); /* тип указателя на функцию */
HINSTANCE h_dll;
my_func_ptr_t func;
int x = 1, y = 2, z;
h_dll = LoadLibrary(«mylib.dll»);
if (NULL == h_dll) return MY_ERROR_CANNOT_LOAD_DLL;
func = (my_func_ptr_t)GetProcAddress(h_dll, «mylib_function»);
if (NULL == func) return MY_ERROR_FUNCTION_NOT_FOUND;
z = func(x, y);
/* . */
| Перейти к другим статьям FAQ | Cтатья создана: | 14.08.2014 |
| Последняя редакция: | 04.08.2016 |
Как подключить библиотеку? (visual studio)
Как подключить библиотеку sdl2 к Visual Studio?
помогите пожалуйста проблема такая: хочу подключить библиотеку sdl2 к VS хидеры вроде.
Как подключить библиотеку GDlib к visual studio 2010
Здорова господа! Нужно подключить библиотеку Gdlib к C++, но я некак не найду где скачать саму.
Как подключить библиотеку MPIR к проекту в Visual Studio 2013 express?
Подскажите, пожалуйста, как подключить библиотеку MPIR к проекту в visual studio 2013 express? .
Не могу подключить динамическую библиотеку в visual studio 2015
Кто создавл динамическую библиотеку в visual studio 2015 по вот этому примеру.
7595 / 6418 / 2924
Регистрация: 14.04.2014
Сообщений: 27,946
В свойствах проекта: Дополнительные каталоги включаемых файлов и Дополнительные каталоги библиотек. Это если всё в отдельных каталогах.
Добавлено через 1 минуту
А ещё Дополнительные зависимости.
![]()
8737 / 4315 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
Сообщение от crabik228 
Где хранятся они в студии ?
1.
способ номер один:
поиск любого стандартного заголовка.
например iostream.
найдете его физическое расположение — это и будет расположением стандартных хэдэров
2.
способ номер два:
вводим любую кракозябру.
например:
#include
потом жмакаем по инклюду правым кликом мышки.
и в появившейся менюшке выбираем: «открыть файл».
студия не сможет открыть файл.
потому что его не существует.
зато услужливо покажет все пути по которым пыталась найти его.
выбирайте себе любой из них.
вполне себе сойдет за «путь для стандартных хэдэров».
Сообщение от crabik228 
куда мне закинуть скаченные мною библеотечные файлы что бы я мог их подключить с помощью #include
куда заходите. это совершенно не принципиально.
только не пихайте их к стандартным заголовкам.
признаком хорошего тона считается завести в каталоге проекта папку,
под названием external
куда и складировать все внешние библиотеки.
затем кликайте правым кликом на солюшен проекта,
и в появившемся меню выбирайте properties
откроются свойства проекта.
далее в раздел c/c++
далее в раздел additional include directories
там пропишите путь к вашим инклюдам.
теперь вы указали дополнительный путь
где студия будет искать инклюды.
134 / 47 / 5
Регистрация: 10.01.2017
Сообщений: 1,782
Сообщение от nmcf 
В свойствах проекта: Дополнительные каталоги включаемых файлов и Дополнительные каталоги библиотек. Это если всё в отдельных каталогах.
Добавлено через 1 минуту
А ещё Дополнительные зависимости.
Подскажите пожалуйста, а зачем нужны эти «дополнительные зависимости» ? Какова их роль ?
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
Помогаю со студенческими работами здесь
Как собрать библиотеку GDCM под C++ в Visual Studio?
Добрый день! Подскажите, пожалуйста, мне нужно установить библиотеку GDCM для C++ (работаю в.
Как внедрить графическую библиотеку SDL в Visual Studio 2012
Никогда не внедрял сторонних библиотек в Visual Studio. В инете поискал, но так ничего и не понял.
Как сгенерировать библиотеку dll через visual studio 2013
Скачал архив curl-7.40.0, не знаю что дальше. Как сгенерировать нужную библиотеку через visual.
Как подключить pjsua к проекту Visual Studio?
Хочу подключить библиотеку pjsua к проекту Visual Studio, но за в С++ не особо разбираюсь и не.
Как подключить assembler в С++ (Visual Studio 2010)
Как подключить assembler в С++ (Visual Studio 2010) Возможно нужны какие-то библиотеки подскажите.

Как подключить OpenGL к Visual studio 2013?
Сделал вот так: — Скачал с официального сайта GLUT. — Скопировал папку includes & lib в.
Как установить библиотеку в с

Использование библиотек
В прошлой статье, я рассказывал о том, как создаются библиотеки классов, написанные на C#. Прочитайте ту статью и соберите собственную библиотеку, если Вы не хотите ограничится только теорией в этой статье. В этой статье, я расскажу как использовать уже созданные библиотеки (DLL) в своих программах. И так, к делу!
Давайте создадим новый проект консольного приложения (как создавать проекты консольных приложений, я рассказывал в уроке № 3 базового курса).
А теперь, в окне Visual Studio, в обозревателе решений, ищем группу «Ссылки» и раскрываем её, как показано на рисунке ниже.

Список внешних ссылок нового проекта
А теперь, вызовем контекстное меню на пункте «Ссылки», и выберем в нем «Добавить ссылку», как показано на рисунке ниже.

Добавление ссылки в проект
В появившемся окне, выбираем, в левой области выбираем пункт «Обзор» и в низу окна, нажимаем на кнопку «Обзор», как показано на рисунке ниже.

Загрузка внешней библиотеки
В появившемся окне, перейти в папку, в которое лежит библиотека (DLL) созданная в предыдущей статье (ссылку на которую, я давал ранее), выбрать эту библиотеку и нажать на кнопку «Добавить», как показано на рисунке ниже.

Выбор нужной библиотеки
После чего, нажать на кнопку «OK» в предыдущем окне. В результате, список ссылок проекта, будет пополнен еще одной:

Пополненный список ссылок проекта
Теперь, мы можем использовать в налей программе класс «INIManager» из подключенной библиотеки. Но перед этим, мы должны выполнить еще одну операцию. Рассмотрим фрагмент кода подключенной библиотеки (он остался у нас после предыдущей статьи):
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Runtime.InteropServices; namespace FirstDLL < public class INIManager < //Конструктор, принимающий путь к INI-файлу public INIManager(string aPath)
Обратите внимание на выделенную строку, это объявление пространства имен (namespace), как бы некого контейнера, в котором находится класс «INIManager». И мы не сможем воспользоваться классом, пока не укажем системе что нужно взять во внимание это пространство имен. Т.е. нам нужно подключить пространство имен в нашем проекте. Для этого, добавим строку «using FirstDLL;» в конец блока директив using, который расположен в самом начале основного файла проекта. Подключение нужного пространства имен показано ниже (интересующая строка кода выделена):
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using FirstDLL;
Вот теперь, можно использовать класс из подключенной библиотеки, а сделать это можно написав в методе «Main» такой код:
//Создание объекта, для работы с файлом INIManager manager = new INIManager("C:\\my.ini"); //Получить значение по ключу name из секции main string name = manager.GetPrivateString("main", "name"); //Вывести полученное имя в консоль Console.WriteLine(name); //Записать значение по ключу age в секции main manager.WritePrivateString("main", "age", "21");
Данный код будет работать, при условии наличия файла «my.ini» на диске «C» нашего ПК. Вот такой вот пример работы со внешними библиотеками.