Использование библиотек и компонентов
В проектах C++ часто требуется вызывать функции или обращаться к данным в двоичных файлах, таких как статические библиотеки (LIB-файлы), библиотеки DLL, компоненты среды выполнения Windows, компоненты COM или сборки .NET. В этих случаях необходимо настроить проект таким образом, чтобы он мог находить нужные двоичные файлы во время сборки. Конкретный способ сделать это зависит от типа вашего проекта, типа двоичного файла, а также от того, был ли этот двоичный файл собран в том же решении, что и ваш проект.
Использование скачанных библиотек с помощью vcpkg
Если вы хотите использовать скачанную библиотеку с помощью диспетчера пакетов vcpkg, то приведенные ниже инструкции можно пропустить. Дополнительные сведения см. в разделе:
- vcpkg в проектах CMake
- Установка и использование пакетов с CMake в Visual Studio
- vcpkg в проектах MSBuild
- Руководство. Установка и использование пакетов с MSBuild в Visual Studio
Использование статических библиотек
Если проект статической библиотеки был создан в том же решении:
- #include файл заголовка для статической библиотеки с помощью кавычки. В типовом решении путь начинается с ../ . При поиске вы можете использовать предложения технологии IntelliSense.
- Добавьте ссылку на проект статической библиотеки. Щелкните правой кнопкой мыши элемент Ссылки в узле проекта приложения в обозревателе решений и выберите Добавить ссылку.
Если статическая библиотека не входит в состав решения:
- Щелкните правой кнопкой мыши узел проекта приложения в обозревателе решений и выберите Свойства.
- На странице свойств Каталоги VC++ добавьте в раздел Пути библиотек путь к каталогу, который содержит LIB-файл. Затем добавьте в раздел Включаемые каталоги путь к файлам заголовков библиотеки.
- На странице свойств компоновщика > добавьте имя LIB-файла в дополнительные зависимости.
Библиотеки динамической компоновки
Если библиотека DLL была собрана в рамках того же решения, что и приложение, выполните те же действия, что и для статической библиотеки.
Если библиотека DLL не входит в состав решения приложения, вам потребуются DLL-файл, заголовки с прототипами для экспортируемых функций и классов, а также LIB-файл, содержащий необходимую для компоновки информацию.
- Скопируйте DLL-файл в папку выходных данных проекта или другую папку, которая задана в качестве стандартной для поиска библиотек DLL в Windows. Дополнительные сведения см. в разделе «Порядок поиска библиотеки динамических ссылок».
- Выполните шаги с 1 по 3 для статических библиотек, чтобы задать пути к заголовкам и LIB-файлу.
COM-объекты
Если в собственном приложении C++ требуется использовать COM-объект и этот объект зарегистрирован, вам достаточно вызвать функцию CoCreateInstance и передать в нее CLSID объекта. Система выполнит поиск объекта в реестре Windows и загрузит его. В проекте C++/CLI COM-объект можно использовать таким же образом. Кроме того, он может использовать его, добавив ссылку на нее из списка добавления ссылок > COM и используя ее через вызываемую оболочку среды выполнения.
Сборки .NET с компонентами среды выполнения Windows
В проектах универсальной платформы Windows (UWP) или C++/CLI для использования сборок .NET или компонентов среды выполнения Windows можно добавить ссылку на сборку или компонент. В узле Ссылки проекта универсальной платформы Windows (UWP) или C++/CLI представлены ссылки на часто используемые компоненты. Щелкните правой кнопкой мыши узел Ссылки в Обозревателе решений, чтобы открыть диспетчер ссылок и просмотреть доступные в системе компоненты. Нажмите кнопку Обзор, чтобы перейти к папке, в которой находится нужный вам пользовательский компонент. Поскольку сборки .NET и компоненты среды выполнения Windows содержат встроенные сведения о типах, для просмотра их методов и классов можно щелкнуть правой кнопкой мыши и выбрать команду Просмотреть в обозревателе объектов.
Свойства ссылки
Каждый тип ссылки имеет свойства. Свойства можно просмотреть, выбрав ссылку в обозревателе решений и нажав клавиши Alt + ВВОД. Также можно щелкнуть ссылку правой кнопкой мыши и выбрать пункт Свойства. Одни свойства доступны только для чтения, другие можно изменять. Тем не менее обычно эти свойства не требуется изменять вручную.
Свойства ссылки ActiveX
Свойства ссылки ActiveX доступны только для компонентов COM. Данные свойства отображаются только тогда, когда в панели Ссылки выбран компонент COM. Эти свойства нельзя изменить.
- Управление полным путем Отображает путь к каталогу элемента управления, на который указывает ссылка.
- GUID элемента управления Отображает GUID для элемента управления ActiveX.
- Версия элемента управления Отображает версию элемента управления ActiveX, на который указывает ссылка.
- Имя библиотеки типов Отображает имя библиотеки типов, на которую указывает ссылка.
- Средство программы-оболочки Отображает средство, которое используется для создания сборки взаимодействия из указанной библиотеки COM или элемента управления ActiveX.
Свойства ссылки на сборку (C++/CLI)
Свойства ссылки на сборку доступны только для ссылок на сборки .NET Framework в проектах C++/CLI. Данные свойства отображаются только тогда, когда в панели Ссылки выбрана сборка .NET Framework. Эти свойства нельзя изменить.
- Относительный путь Отображает относительный путь от каталога проекта к сборке, на которую указывает ссылка.
Свойства сборки
Следующие свойства доступны для различных типов ссылок. Они позволяют задавать способ построения со ссылками.
- Копировать локальные Указывает, следует ли автоматически копировать сборку, на которую указывает ссылка, в целевое расположение во время сборки.
- Копировать локальные вспомогательные сборки (C++/CLI) Указывает, следует ли автоматически копировать вспомогательные сборки ссылочной сборки в целевое расположение во время сборки. Используется, только если для параметра Копировать локальные задано значение true .
- Выходные данные ссылочной сборки Указывает, что эта сборка используется в процессе сборки. true означает, что эта сборка используется в командной строке компилятора во время выполнения сборки.
Свойства ссылок проектов на проекты
Следующие свойства определяют ссылку проекта на проект из проекта, выбранного в панели Ссылки, на другой проект в том же решении. Дополнительные сведения см. в статье Управление ссылками в проекте.
- Компоновать зависимости библиотек Если это свойство имеет значение True, система проектов установит в зависимом проекте связь с LIB-файлами, создаваемыми независимым проектом. Обычно устанавливается значение True.
- Идентификатор проекта Уникальный идентификатор независимого проекта. Значение свойства — это GUID внутренней системы, который невозможно изменить.
- Использовать входные данные зависимостей библиотек Если это свойство имеет значение False, система проектов не установит в зависимом проекте связь с OBJ-файлами для библиотеки, созданной независимым проектом. Таким образом, это значение отключает инкрементную компоновку. Обычно указывается значение False, так как при наличии множества независимых проектов сборка приложения может занять длительное время.
Свойства ссылки только для чтения (COM и .NET)
Следующие свойства существуют в ссылках на компоненты COM и сборки .NET, и их нельзя изменить.
- Имя сборки Отображает имя сборки для сборки, на которую указывает ссылка.
- Язык и региональные параметры Отображает язык и региональные параметры выбранной ссылки.
- Description Отображает описание выбранной ссылки.
- Полный путь Отображает путь к каталогу сборки, на которую указывает ссылка.
- Identity Для сборок .NET Framework отображает полный путь. Для компонентов COM отображает GUID.
- Подпись Отображает метку ссылки.
- Имя Отображает имя ссылки.
- Токен открытого ключа Отображает токен открытого ключа для идентификации сборки, на которую указывает ссылка.
- Строгое имяtrue , если сборка, на которую указывает ссылка, имеет строгое имя. Сборка со строгим именем имеет уникальную версию.
- Версия Отображает версию сборки, на которую указывает ссылка.
Библиотеки в Си. Сборка программы со статической и динамической библиотеками
Библиотеки позволяют использовать созданный ранее программный код в различных программах. Таким образом, программист может не разрабатывать часть кода для своей программы, а воспользоваться тем, что входит в состав библиотек.
В языке программирования C код библиотек представляет собой функции, размещенные в файлах, которые скомпилированы в объектные файлы, а те, в свою очередь, объединены в библиотеки. В одной библиотеке объединяются функции, решающие определенный тип задач. Например, существует библиотека математических функций.
У каждой библиотеки должен быть свой заголовочный файл, в котором должны быть описаны прототипы (объявления) всех функций, содержащихся в этой библиотеке. С помощью заголовочных файлов вы «сообщаете» вашему программному коду, какие библиотечные функции есть и как их использовать.
При компиляции программы библиотеки подключаются линковщиком, который вызывается gcc . Если программе требуются только стандартные библиотеки, то дополнительных параметров линковщику передавать не надо (есть исключения). Он «знает», где стандартные библиотеки находятся, и подключит их автоматически. Во всех остальных случаях при компиляции программы требуется указать имя библиотеки и ее местоположение.
Библиотеки бывают двух видов — статические и динамические. Код первых при компиляции полностью входит в состав исполняемого файла, что делает программу легко переносимой. Код динамических библиотек не входит в исполняемый файл, последний содержит лишь ссылку на библиотеку. Если динамическая библиотека будет удалена или перемещена в другое место, то программа работать не будет. С другой стороны, использование динамических библиотек позволяет сократить размер исполняемого файла. Также если в памяти находится две программы, использующие одну и туже динамическую библиотеку, то последняя будет загружена в память лишь единожды.
Далее будет описан пример, в котором создается библиотека, после чего используется при создании программы.
Пример создания библиотеки
Допустим, мы хотим создать код, который в дальнейшем планируем использовать в нескольких проектах. Следовательно, нам требуется создать библиотеку. Ее исходный код разместим в двух файлах.
Также у нас будет проект, использующая эту библиотеку. Он тоже будет включать два файла.
В итоге, когда все будет сделано, схема каталогов и файлов будет выглядеть так:
Пусть каталоги library и project находятся в одном общем каталоге, например, домашнем каталоге пользователя. Каталог library содержит каталог source с файлами исходных кодов библиотеки. Также в library будут находиться заголовочный файл (содержащий описания функций библиотеки), статическая ( libmy1.a ) и динамическая ( libmy2.so ) библиотеки. Каталог project будет содержать файлы исходных кодов проекта и заголовочный файл с описанием функций проекта. Также после компиляции с подключением библиотеки здесь будет располагаться исполняемый файл проекта.
В операционных системах GNU/Linux имена файлов библиотек должны иметь префикс «lib», статические библиотеки — расширение *.a , динамические — *.so .
Для компиляции проекта достаточно иметь только одну библиотеку: статическую или динамическую. В образовательных целях мы получим обе и сначала скомпилируем проект со статической библиотекой, потом — с динамической. Статическая и динамическая «разновидности» одной библиотеки по-идее должны называться одинаково (различаются только расширения). Поскольку у нас обе библиотеки будут находиться в одном каталоге, то чтобы быть уверенными, что при компиляции проекта мы используем ту, которую хотим, их названия различны ( libmy1 и libmy2 ).
Исходный код библиотеки
#include void rect(char sign, int w, int h) int i, j; for (i = 0; i w; i++) putchar(sign); putchar('\n'); for (i = 0; i h-2; i++) { for (j = 0; j w; j++) { if (j == 0 putchar('\n'); } for (i = 0; i w; i++) putchar(sign); putchar('\n'); } void diagonals(char sign, int w) putchar('\n'); } }
В файле figure.c содержатся две функции — rect и diagonals . Первая принимает в качестве аргументов символ и два числа и «рисует» на экране с помощью указанного символа прямоугольник заданной ширины и высоты. Вторая функция выводит на экране две диагонали квадрата («рисует» крестик).
#include void text(char *ch) { while (*ch++ != '\0') putchar('*'); putchar('\n'); }
В файле text.c определена единственная функция, принимающая указатель на символ строки. Функция выводит на экране звездочки в количестве, соответствующем длине указанной строки.
void rect(char sign, int width, int height); void diagonals(char sign, int width); void text(char *ch);
Заголовочный файл можно создать в каталоге source , но мы лучше сохраним его там, где будут библиотеки. В данном случае это на уровень выше (каталог library ). Тем самым как бы подчеркивается, что файлы исходных кодов после создания из них библиотеки вообще не нужны пользователям библиотек, они нужны лишь разработчику библиотеки. А вот заголовочный файл библиотеки требуется для ее правильного использования.
Создание статической библиотеки
Статическую библиотеку создать проще, поэтому начнем с нее. Она создается из обычных объектных файлов путем их архивации с помощью утилиты ar .
Все действия, которые описаны ниже выполняются в каталоге library (т.е. туда надо перейти командой cd ). Просмотр содержимого каталога выполняется с помощью команды ls или ls -l .
Получаем объектные файлы:
gcc -c ./source/*.c
В итоге в каталоге library должно наблюдаться следующее:
figures.o mylib.h source text.o
Далее используем утилиту ar для создания статической библиотеки:
ar r libmy1.a *.o
Параметр r позволяет вставить файлы в архив, если архива нет, то он создается. Далее указывается имя архива, после чего перечисляются файлы, из которых архив создается.
Объектные файлы нам не нужны, поэтому их можно удалить:
rm *.o
В итоге содержимое каталога library должно выглядеть так:
libmy1.a mylib.h source
, где libmy1.a — это статическая библиотека.
Создание динамической библиотеки
Объектные файлы для динамической библиотеки компилируются особым образом. Они должны содержать так называемый позиционно-независимый код (position independent code). Наличие такого кода позволяет библиотеке подключаться к программе, когда последняя загружается в память. Это связано с тем, что библиотека и программа не являются единой программой, а значит как угодно могут располагаться в памяти относительно друг друга. Компиляция объектных файлов для динамической библиотеки должна выполняться с опцией -fPIC компилятора gcc :
gcc -c -fPIC source/*.c
В отличие от статической библиотеки динамическую создают при помощи gcc указав опцию -shared :
gcc -shared -o libmy2.so *.o
Использованные объектные файлы можно удалить:
rm *.o
В итоге содержимое каталога library :
libmy1.a libmy2.so mylib.h source
Использование библиотеки в программе
Исходный код программы
Теперь в каталоге project (который у нас находится на одном уровне файловой иерархии с library ) создадим файлы проекта, который будет использовать созданную библиотеку. Поскольку сама программа будет состоять не из одного файла, то придется здесь также создать заголовочный файл.
#include #include "../library/mylib.h" void data(void) { char strs[3][30]; char *prompts[3] = { "Ваше имя: ", "Местонахождение: ", "Пунк прибытия: "}; int i; for (i = 0; i 3; i++) { printf("%s", prompts[i]); fgets(strs[i], 30, stdin); } diagonals('~', 7); for (i = 0; i 3; i++) { printf("%s", prompts[i]); text(strs[i]); } }
Функция data запрашивает у пользователя данные, помещая их в массив strs . Далее вызывает библиотечную функцию diagonals() , которая выводит на экране «крестик». После этого на каждой итерации цикла вызывается библиотечная функция text() , которой передается очередной элемент массива; функция text выводит на экране звездочки в количестве равном длине переданной через указатель строки.
Обратите внимание на то, как подключается заголовочный файл библиотеки: через относительный адрес. Две точки обозначают переход в каталог на уровень выше, т. е. родительский по отношению к project , после чего путь продолжается в каталог library , вложенный в родительский. Можно было бы указать абсолютный путь, например, «/home/pl/c/les22/library/mylib.h». Однако при перемещении каталогов библиотеки и программы на другой компьютер или в другой каталог адрес был бы уже не верным. В случае с относительным адресом требуется лишь сохранять расположение каталогов project и library относительно друг друга.
#include #include "../library/mylib.h" #include "project.h" int main() { rect('-',75,4); data(); rect('+',75,3); }
Здесь два раза вызывается библиотечная функция rect() и один раз функция data() из другого файла проекта. Чтобы сообщить функции main прототип data также подключается заголовочный файл проекта.
Файл project.h содержит всего одну строчку:
void data(void);
Из обоих файлов проекта с исходным кодом надо получить объектные файлы для объединения их потом с файлом библиотеки. Сначала мы получим исполняемый файл, содержащий статическую библиотеку, потом — связанный с динамической библиотекой. Однако с какой бы библиотекой мы не компоновали объектные файлы проекта, компилируются они как для статической, так и динамической библиотеки одинаково:
gcc -c *.c
При этом не забудьте сделать каталог project текущим!
Компиляция проекта со статической библиотекой
Теперь в каталоге project есть два объектных файла: main.o и data.o . Их надо скомпилировать в исполняемый файл project , объединив со статической библиотекой libmy1.a . Делается это с помощью такой команды:
gcc -o project *.o -L../library -lmy1
Начало команды должно быть понятно: опция -o указывает на то, что компилируется исполняемый файл project из объектных файлов.
Помимо объектных файлов проекта в компиляции участвует и библиотека. Об этом свидетельствует вторая часть команды: -L../library -lmy1 . Здесь опция -L указывает на адрес каталога, где находится библиотека, он и следует сразу за ней. После опции -l записывается имя библиотеки, при этом префикс lib и суффикс (неважно .a или .so ) усекаются. Обратите внимание, что после данных опций пробел не ставится.
Опцию -L можно не указывать, если библиотека располагается в стандартных для данной системы каталогах для библиотек. Например, в GNU/Linux это /lib/ , /urs/lib/ и др.
Запустив исполняемый файл project и выполнив программу, мы увидим на экране примерно следующее:
Посмотрим размер файла project :
pl@desk:~/c/les22/project$ ls -l project -rwxrwxr-x 1 pl pl 16352 дек 19 02:02 project
Его размер равен 16352 байт.
Компиляция проекта с динамической библиотекой
Теперь удалим исполняемый файл и получим его уже связанным с динамической библиотекой. Команда компиляции с динамической библиотекой выглядит так (одна команда разбита на две строки с помощью обратного слэша и перехода на новую строку):
gcc -o project *.o \ > -L../library -lmy2 -Wl,-rpath. /library/
Здесь в отличии от команды компиляции со статической библиотеки добавлены опции для линковщика: -Wl,-rpath. /library/ . -Wl ‒ это обращение к линковщику, -rpath ‒ опция линковщика, ../library/ ‒ значение опции. Получается, что в команде мы два раза указываем местоположение библиотеки: один раз с опцией -L , а второй раз с опцией -rpath .
Следует заметить, что если вы скомпилируете программу, используя приведенную команду, то исполняемый файл будет запускаться из командной строки только в том случае, если текущий каталог project . Стоит сменить каталог, будет возникать ошибка из-за того, что динамическая библиотека не будет найдена. Но если скомпилировать программу так:
gcc -o project *.o -L../library -lmy2 \ > -Wl,-rpath,/home/pl/c/library
, т.е. указать для линковщика абсолютный адрес, то программа в данной системе будет запускаться из любого каталога.
Размер исполняемого файла проекта, связанного с динамической библиотекой, будет немного меньше. Если посмотреть на размеры библиотек:
pl@desk:~/c/les22/library$ ls -l libmy* -rw-rw-r-- 1 pl pl 3616 дек 19 00:16 libmy1.a -rwxrwxr-x 1 pl pl 15592 дек 19 00:33 libmy2.so
, то видно, что динамическая больше статической, хотя исполняемый файл проекта со статической библиотекой больше. Это доказывает, что в исполняемом файле, связанном с динамической библиотекой, присутствует лишь ссылка на нее.
Курс с решением задач:
pdf-версия
использовать функцию из библиотеки
предположим, все пути указаны верно. можно ли в своем приложении пользоваться функцией function без динамической подгрузки функции через dlopen ?
#include int main() < ex a; function(a); //
если кому не сложно, то накидайте этот пример и покажите как вызвать функцию без dlopen. не понимаю
Отслеживать
задан 17 дек 2017 в 13:35
2,622 1 1 золотой знак 17 17 серебряных знаков 30 30 бронзовых знаков
Прилинковать include.so
17 дек 2017 в 13:40
прилинковываю, и что дальше?
17 дек 2017 в 13:46
Всё должно работать. Если не работает, то значит прилинковали не правильно. Укажите, как именно вы линкуете и из каких папок запускаете приложение.
17 дек 2017 в 13:52
@VTT, исправил. замечу что в include.h нету объявления функции foo
17 дек 2017 в 14:18
Как вы пытаетесь обратиться к функции не объявив ее? Откуда компилятору знать, что и где искать? И никто не мешает прямо в main() написать прототип Вашей функции.
17 дек 2017 в 20:03
1 ответ 1
Сортировка: Сброс на вариант по умолчанию
alexander@goblin /tmp/foolib $ cat foo.cpp #include int foo () < std::cout alexander@goblin /tmp/foolib $ cat main-foo.cpp int foo (); int main () < return foo(); >alexander@goblin /tmp/foolib $ g++ -shared -fpic -olibfoo.so foo.cpp alexander@goblin /tmp/foolib $ g++ -fpic -o main-foo -L. -lfoo main-foo.cpp alexander@goblin /tmp/foolib $ LD_LIBRARY_PATH=. ./main-foo Hello world from foo!
Отслеживать
ответ дан 18 дек 2017 в 9:08
23.1k 1 1 золотой знак 19 19 серебряных знаков 37 37 бронзовых знаков
да, спасибо, Vladimir подсказал что надо было тупо объявить функцию у себя в main.cpp
18 дек 2017 в 9:28
не заметил скрытые комментарии сначала.
18 дек 2017 в 9:39
- c++
- linux
- dll
-
Важное на Мете
Похожие
Подписаться на ленту
Лента вопроса
Для подписки на ленту скопируйте и вставьте эту ссылку в вашу программу для чтения RSS.
Дизайн сайта / логотип © 2024 Stack Exchange Inc; пользовательские материалы лицензированы в соответствии с CC BY-SA . rev 2024.3.8.5973
Создание статической библиотеки
Библиотека – это пакет кода, который предназначен для повторного использования многими программами. Обычно библиотека C++ состоит из двух частей:
- заголовочный файл, который определяет функциональность, которую библиотека предоставляет (предлагает) программам, использующим ее;
- предварительно скомпилированный двоичный файл, который содержит реализацию этой функциональности, предварительно скомпилированную в машинный код.
Некоторые библиотеки могут быть разделены на несколько файлов и/или иметь несколько файлов заголовков.
Библиотеки предварительно скомпилированы по нескольким причинам:
- Во-первых, поскольку библиотеки меняются редко, их не нужно часто перекомпилировать. Было бы пустой тратой времени перекомпилировать библиотеку каждый раз, когда вы пишете программу, которая ее использует.
- Во-