Как вызвать функцию из статической библиотеки с
Перейти к содержимому

Как вызвать функцию из статической библиотеки с

  • автор:

использовать функцию из библиотеки

предположим, все пути указаны верно. можно ли в своем приложении пользоваться функцией 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.1.5619

Создание статической библиотеки

Author24 — интернет-сервис помощи студентам

Вообщем надо создать статическую библиотеку lib для классов. Классов очень много и они разбиты по хедерам .h . Я создал новый проект в win32 console application и в свойствах указал "статическая библиотека". Далее я добавил в проект все хедеры. Что дальше надо сделать? При компилировании, lib файл не создается. Мне нужно, чтобы при подключении этой библиотеки я смог создать объекты классов, которые находятся в .h. Работаю в MSVC 2010. Помогите пожалуйста руководством. Или ткните ссылкой на годный манул, а то я натыкаюсь только на теоретическую часть, которая мне не помогает разобраться.

94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
Ответы с готовыми решениями:

Создание статической библиотеки в DEV C++
Прошу помочь мне с созданием статической библиотеки в DEV C++. В общем, я попытался создать ее.

Создание статической библиотеки lib
Привет всем решил попробовать создать статическую библиотеку и связать её с каким-нибудь.

Создание статической библиотеки по обработки строк
• Разработать функцию, которая возвращает N правых символов исходной строки. • Разработать.

Создание/компиляция статической .Lib библиотеки С++
Здравствуйте, Пытаюсь разобраться, как вообще создавать или скомпилировать сторонние статические.

Динамические и статические библиотеки.

Начнём с повторения того, что мы уже знаем. Каждый исходный файл транслируется в объектный файл, после чего все объектные файлы линкуются в программу. Но иногда бывает кусок кода, который хочется переиспользовать. Мы могли бы оттранслировать объектные файлы этого куска один раз, после чего сразу с ними компилировать. Но так оказалось, что уже существует механизм сгруппировать объектные файлы вместе, после чего отдать их линковщику. Называется этот механизм.

Статические библиотеки.

// sum.cpp int sum(int a, int b)
// four.cpp #include int sum(int a, int b); int main()
#include int sum(int a, int b); int main()

И мы зачем-то пытаемся вычленить sum.cpp как библиотеку. Тогда сделать надо вот что: Компилируем:

g++ -c sum.cpp -o sum.o ar rcs libsum.a sum.o 

Что тут происходит?

  • ar — сокращение от «archive».
  • rcs — это некоторая магия (читайте man).
  • libsum.a — название библиотеки.

Чтобы скомпилировать каждый из файлов выше с этой библиотекой, делаем так:

g++ four.cpp -lsum -L. -o four g++ five.cpp -lsum -L. -o five 

А что происходит тут?

  • -L говорит, в каком каталоге искать библиотеку (в нашем случае в каталоге . — в текущем).
  • -lsum говорит, что нам нужна библиотека, которая называется libsum.a (т.е. к тому, что идёт после -l спереди приписывается lib», а сзади — «.a»).

Тут больше совершенно ничего интересного, потому что статическая библиотека — набор объектных файлов, а про объектные файлы мы всё знаем. То ли дело.

Динамические библиотеки.

Пусть у вас есть библиотека, которая используется везде вообще. Например, libc. Если она статическая, то код библиотеки есть в каждой из программ. А значит в каждой программе они занимают место и на диске, и в памяти. Чтобы этого избежать, применяют динамические библиотеки.
Идея динамических библиотек в том, что мы ссылаемся как-то на внешнюю библиотечку, а потом на этапе исполнения грузим по надобности её части. Тогда она на диске лежит всего одна, и в память мы можем загрузить её один раз.

Давайте в примере выше сделаем статическую библиотеку динамической:

g++ -fpic -c sum.cpp -o sum.o g++ -shared sum.o -o libsum.so g++ four.cpp -lsum -L. -o four g++ five.cpp -lsum -L. -o five 

Что значат все консольные опции тут, уже пояснить намного сложнее, и мы поясним их в следующем параграфе.
А пока обратим внимание на то, что когда мы запустим four или five, нам на этапе исполнения скажут, что библиотека libsum.so не найдена. Хотя, казалось бы, вот она рядом лежит. Дело в том, что по умолчанию Linux ищет библиотеки только по системным путям. (Windows ищет и в текущей директории.) Чтобы проверить, от каких библиотек зависит ваша программа, запустите ldd ./four, и вам скажут, что нужна libsum.so, но её нет.

Есть два способа поправить сию оказию:

Первый — явно при запуске прописывать путь до библиотек.
Для этого существует переменная окружения LD_LIBRARY_PATH , если присвоить ей точку, всё сработает

LD_LIBRARY_PATH=. ./four 

Если вам нужно несколько путей, разделяйте их двоеточиями.

Второй — записать в саму программу, где искать библиотеки.
Это можно посмотреть при помощи objdump в секции Dynamic Section , где есть RUNPATH . Чтобы записать туда что надо, делается вот что:

g++ four.cpp -lsum -L. -Wl,-rpath= -o four 

-Wl говорит, что опцию после него (т.е. -rpath) надо передать линковщику. Линковщику эта опция говорит, что в тот самый RUNPATH надо записать тот путь, который вы попросили.
А какой надо просить? Не «.» ведь, потому что это путь, из которого вы запускаете программу, а не то место, где сама программа.
И тут вам на помощи приходит псевдо-путь $ORIGIN , который и ссылается на место программы. Используя его Вы можете свободно написать что-нибудь по типу -rpath='$ORIGIN/../lib/'.

Впрочем, есть ещё и третий путь — использовать CMake, который будет делать всю грязную работу за вас, если написать ему команду add_library .

Кстати, в Windows это работает иначе. В-нулевых, динамическая библиотека там называется не shared object, а dynamic load library. Во-первых, DLL-ки сразу же ищутся в текущем каталоге. Во-вторых, чтобы понять, что вы ссылаетесь на динамическую библиотеку, в Linux вы пишете -L. -lsum, а в Windows компиляция DLL создаёт вам специальный .lib-файл, который называется import-библиотекой, и с которым вы компилируете вашу программу, чтобы она сама поняла, откуда какие функции брать.

Причины нестандартной компиляции динамических библиотек.

g++ -fpic -c sum.cpp -o sum.o g++ -shared sum.o -o libsum.so 

Нас интересуют магические слова -fpic и -shared. Зачем на как-то особенно компилировать динамические библиотеки?

А дело вот в чём — при запуске программы, она первая загружается в адресное пространство, и она сама может выбрать, куда ей хочется. Динамические библиотеки такого же по понятным причинам позволить себе не могут. Возникает вопрос — и что теперь? А то, что при наличии глобальных переменных, мы не можем впаять им фиксированные адреса.

Есть путь, которым пошли разработчики архитектуры PowerPC: адреса динамической библиотеки считаются относительно некоторого регистра. И тут жить можно, разве что вам нужно правильно задавать этот регистр, когда обращаетесь к разным библиотекам, и не менять его, если обращаетесь к библиотечной функции из другой функции той же библиотеки. Сложно, но жить можно.

Самый простой способ жить с динамическими библиотеками был у Microsoft на 32-битной Windows. У каждой библиотеки был base-address — то куда библиотеке хочется загрузиться. Если там свободно — туда она и загружается, а если нет, то библиотеку загружают туда, где есть место, а в специальной отдельной секции (.reloc) хранится список адресов, которые надо исправить. Разумеется, в случае релокаций умирает переиспользование библиотеки, но Windows вам же полностью предоставляют, там можно расположить системные библиотеки так, как хочется, поэтому в проприетарных системах всё будет хорошо.

В Linux же это реализовано следующим образом. Смотрите как можем:

 call next next: pop ABX lea EAX, [EBX + (myvar - next)] 

Тут идея в том, что мы записываем адрес текущей команды на стек, потом берём его со стека, а дальше вместо того, чтобы писать абсолютный адрес переменной myvar , пишем относительный.
Относительный адрес позволяет нам обращаться к ней, если мы не знаем, в какое место памяти будет загружена библиотека, что нам и надо.

Вообще мы не очень хорошо написали (процессор не любит непарные call и pop ), поэтому обычно это выглядит так:

get_pc: mov EBX, [ESP] ret get_variable: call get_pc next: lea EAX, [EBX + (myvar - next)] 

Этот код называется position-independent code, и ключ -fpic именно генерацией такого кода и занимается. Вопрос — почему для этого не сделали специальную инструкцию? А вот сделали, но в 64-битном режиме. Всё что с квадратными скобками стало уметь обращаться в память начиная со смещения текущей инструкции. И называется это RIP-relative positioning.

GOT/IAT. PLT.

В итоге мы имеем кусок данных, который можно загрузить и исполнять. Но на самом деле библиотека — это же не сферический код в вакууме, она хочет вызывать какие-то функции.

Например, библиотека для работы с JSON хочет делать fopen . То есть нужно подружить библиотеки друг с другом. Самый простой вариант — когда мы делаем call , в файл мы кладём нулевой адрес, а в секцию релокаций записываем, что вместо него нужно положить fopen , после чего при запуске динамический загрузчик всё разложит по местам. То есть то же самое, что с линковщиком. Почему так не делают? Потому что мы от' mmap 'или нашу библиотеку, а в ней дырки. И во все места дырок нужно что-то подставить. И опять вы не можете записать библиотеку в память один раз, что вам очень хочется.

Поэтому вместо этого просто заводят табличку со смещениями, и теперь все call 'ы обращаются туда, и туда же динамический загрузчик подставляет истинные адреса функций. Эта таблица в Linux называется global offset table, а в Windows — import address table.

Но на самом деле есть ещё проблема. Давайте посмотрим, что происходит, когда мы делаем

void foo(); void bar()

Как мы обсуждали, тут будет call и пустой адрес (до линковки пустой). А что будет, если foo — это внешняя функция из какой-то библиотеки? Тогда надо бы вместо простого call 'а сделать call qword [got_foo] . Но есть проблема — мы узнаём, откуда эта функция, только на этапе линковки, а компилировать надо раньше. Поэтому компилятор call foo , а потом, если это было неправильно, просто создаёт свою функцию foo , которая является прослойкой для jmp qword [got_foo] . Такие заглушки, которые просто совершают безусловный переход по глобальной таблице смещений имеют название. В Linux их называют PLT (procedure linkage table), а в Windows как-то по-другому.

Но в Linux PLT используется ещё для одной цели. Рассмотрим, скажем, LibreOffice, в котором сотни динамических библиотек с тысячами функций в каждой. Поэтому заполнение GOT — это долго. И нам не хочется смотреть, где лежит каждая функция, после чего записывать её в таблицу. Поэтому эту операцию сделали ленивой:
GOT заполняется специальными заглушками, которые динамически ищут в хэш-таблице настоящий адрес функции, после чего записывают его в GOT вместо себя, и вызывают эту функцию, чтобы она отработала. В Microsoft по-умолчанию отложенная загрузка не используется, но его можно включить (delayed DLL loading или как-то так называется). Это фича загрузчика, а не самой Windows, и делает эта фича примерно то же самое. Однако есть разница. В Linux отсутствие библиотеки не позволяет запустить программу. В Windows же библиотека подгружается при первом вызове функции оттуда, что, по их словам, сделано чтобы вы могли за' if 'ать ситуацию, когда библиотеки нет.

Офф-топ на тему «Как страшно жить».

Поговорим про изменение so-файлов. Давайте возьмём и во время работы программы поменяем библиотечку на диске, втупую вписав туда другой текст. Результат поразителен — работа программы также изменится. Почему? Мы же, вроде как, исполняем библиотеку из оперативки, а не с диска. А дело в том, как работает copy-on-write в операционных системах. Когда вы пишете в некоторую страницу, вам копируют её. Но когда кто-то извне пишет в страницу, вам не дают копию старых данных. С исполняемым файлом такое не прокатывает, кстати. Это потому, что вашу программу загружает ядро, и оно может запретить изменять бинарники, а библиотеку загружает ваша программа, которая такого механизма не имеет.

Кстати, изменение и перекомпиляция — разные вещи. И если вы во время работы программы перекомпилируете библиотеку, она не обновится. Связано это с тем, что перекомпилированная библиотека — это новый файл, а не старый. По сути вы удалили старую библиотеку и создали новую, вместо того, чтобы библиотеку изменить. А в Linux пока кто-то имеет доступ к файлу, файл не удаляется до конца. И поэтому в вашей программе всё ещё есть та самая библиотека, которую вы загружали (а не новая).

Детали работы с динамическими библиотеками в Windows.

Никто не удивиться, что набор

 call foo@PLT foo@PLT: jmp qword [got_foo] 

не очень эффективен (три обращения в память вместо одного). Поэтому в Windows есть спецификатор __declspec(dllimport) , который сразу вместо call 000000 и замены нулей на foo@plt вставляет call qword [got_foo] .

Ещё в Windows есть такая штука как .def-файл — линковщик экспортирует из вашей DLL-ки только то, что нужно, и в .def-файле указывается, что именно. Это хорошо работает в C, где имена символов и имена функций совпадают, но не очень хорошо в C++, где вам придётся писать сложные декорируемые имена. Поэтому есть второй вариант — написать на самой функции __declspec(dllexport) .

И вроде бы всё хорошо, вы метите функции, которые экспортируете как __declspec(dllexport) , которые импортируете — как __declspec(dllimport) и всё классно работает. Но есть проблема: вы и в библиотеке, и в коде, который её использует, подключаете один заголовочный файл, где объявлена функция. И непонятно, что там писать: __declspec(dllexport) или __declspec(dllimport) . Для этого заводится специальный макрос под каждую библиотеку, которым отличают, саму DLL вы компилируете или кого-то с её использованием.

Есть ещё одна проблема. Непонятно, что делать с глобальными переменными. Там проблема ещё более страшная: вы сначала читаете адрес переменной из GOT (извините, IAT), а потом по полученному адресу обращаетесь. Тут уже никакую функцию-прослойку не написать, увы. Поэтому если вы не пометите глобальную переменную как __declspec(dllimport) , тот тут вы уже точно совсем проиграете, у вас линковка не получится.

А ещё реализация DLL в Windows нарушает правила языка: если вы напишете inline -функцию в заголовочном файле. Она просто откопируется в каждую библиотеку, где вы этот заголовок подключился. С этим вы ничего не сделаете, тут вы просто проиграли.

Детали работы с динамическими библиотеками в Linux.

Если вы думаете, что в Windows проблемы с динамическими библиотеками, потому что Windows — какашка, то сильно заблуждаетесь, потому что в Linux нюансов тоже выше крыши.

Итак, мем первый и основной — interposition. Есть такая переменная окружения, как LD_PRELOAD . Она завставляет динамический загрузчик сначала обшарить в поисках динамических библиотек то, что вы в LD_PRELOAD написали, а уже потом смотреть какие-нибудь RUNPATH 'ы и всё остальное. В частности, так можно подменить аллокатор (и мы так и делали, когда экспериментировали с mmap 'ом и munmap 'ом). Такая подмена и называется interposition. Теперь что же у него, собственно, за нюансы есть.

int sum(int a, int b) < return a + b; >int test(int x, int y)

Тут при обычной компиляции вторая функция просто вернёт свой второй аргумент. А при компиляции с -fpic, вы сможете подменить sum , а значит оптимизации не будет. Чтобы это пофиксить, можно пометить sum как static (тогда эта функция будет у вас только внутри файла, а значит его не поменять извне) или как inline (потому что inline полагается на ODR, а значит функция должна быть везде одинаковой). Но есть ещё способ.
Linux по-умолчанию считает, что все функции торчат наружу (т.е. как __declspec(dllexport) в Windows). А можно их пометить, как не торчащие наружу, а нужные только для текущей компилируемой программы/библиотеки: __attribute__((visibility("hidden"))) .

На самом деле атрибут visibility может принимать несколько различных значений ( "default" , "hidden" , "internal" , "protected" ), где пользоваться сто́ит только вторым, потому что первый и так по-умолчанию, третий заставляет ехать все адреса, а четвёртый добавляет дополнительные аллокации.
При этом также есть различные ключи компиляции (типа -B symbolic), которые тем или иным образом немного меняют поведение, и пояснить разницу между ними всеми вам могут только избранные. И каждый из них может поменять вам поведение так, что вы легко выстрелите себе в ногу. То есть глобально в Linux поведение по умолчанию делаем вам хорошо, но, возможно, немного неоптимизированно, а когда вы начинаете использовать опции, вы погружаетесь в такую бездну, что ускорение заставляет вас очень много думать. Причём замедление от динамических библиотек может быть достаточно сильным: если взять компилятор clang-LLVM и компилировать при помощи его ядро Linux’а, то в зависимости от того, сложен ли clang-LLVM в один большой файл или разбит по библиотечкам, время компиляции отличается на треть. Поэтому ключи использовать придётся.
Один из самых безопасных из них — -fno-semantic-interposition. Это не то же самое, что и -fno-interposition потому, что бинарнику всё равно можно дать LD_PRELOAD , однако в нашем случае функция test будет оптимизирована.
Ещё один полезный ключ — -fno-plt. Он по сути вешает оптимизацию такую же, как __declspec(dllimport) , но на весь файл, поэтому функции, написанные в нём же, замедляются. Чтобы не замедлялись — visibility("hidden") . Вообще всё это детально и подробно рассказано не будет, если вам интересно, гуглите и читайте/смотрите по теме.
Впрочем, всякие -fno-plt и прочие штуки нужны нам тогда и только тогда, когда мы не включили linking-time оптимизации. В GCC все наборы ключей нафиг не нужны, если включить -flto. Так что в перспективе -flto и -fno-semantic-interposition — это единственное, что вам может быть нужно. Но только в перспективе.

Больше примеров

Ниже приведены примеры всех трех подходов. (статические, общие и динамически загружаеые библиотеки). Файл libhello.c это обычная библиотека с libhello.h в качестве заголовка. Файл demo_use.c просто вызывает библиотеку. За ними следуют комментированные скрипты (script_static и scrypt_dynamic), показывая, как использовать библиотеку в качестве статической и общей библиотеки. Далее следует demo_dynamic.c и script_dynamic, которые показывают как использовать общие библиотеки в качестве динамически загружаемых библиотек.

Файл libhello.c
/* libhello.c - демонстрация использования библиотеки. */ #include void hello(void)
Файл libhello.h
/* libhello.h - демонстрация использования библиотеки. */ void hello(void);
Файл demo_use.c
/* demo_use.c -- демонстрация непосредственного использования процедуры "hello" */ #include "libhello.h" int main(void)
Файл script_static
#!/bin/sh # Пример статической библиотеки # Создание объектного файла статической библиотеки, # libhello-static.o. Я использую имя libhello-static, # чтобы четко отличать примеры статических и динамических # библиотек, но вам нет необходимости использовать "-static" # в именах ваших объектных файлов или статических библиотек. gcc -Wall -g -c -o libhello-static.o libhello.c # Создание статической библиотеки. ar rcs libhello-static.a libhello-static.o # В этом месте мы можем просто копировать libhello-static.a # куда-либо еще, чтобы использовать ее. # С целью демонстрации, мы просто сохраним библиотеку # в текущем каталоге. # Компиляция файла программы demo_use. gcc -Wall -g -c demo_use.c -o demo_use.o # Создание программы demo_use; -L. добавляет директорию "." в поиск # библиотек на время создания программы. Обратите внимение, что эта # команда приводит к тому, что соответствующий объектный файл в # libhello-static.a включается в файл demo_use_static. gcc -g -o demo_use_static demo_use.o -L. -lhello-static # Запуск программы. ./demo_use_static
Файл script_shared
#!/bin/sh # Пример общей библиотеки # Создание объектного файла общей библиотеки, libhello.o. gcc -fPIC -Wall -g -c libhello.c # Создание общей библиотеки. # Используем -lc для компоновки с библиотекой C, # т.к. libhello зависит от библиотеки C. gcc -g -shared -Wl,-soname,libhello.so.0 \ -o libhello.so.0.0 libhello.o -lc # Здесь мы можем просто скопировать libhello.so.0.0 # в любую директорию, например /usr/local/lib. # Теперь нам нужно вызвать ldconfig # для настройки символических ссылок. # Настройка soname. Мы можем просто выполнить: # ln -sf libhello.so.0.0 libhello.so.0 # но давайте позволим ldconfig разобраться с этим. /sbin/ldconfig -n . # Настройка имени для компоновщика. # В более сложных условиях, нам необходимо убедиться, # имеется ли существующее имя для компоновщика, и если # это так, проверить, должно ли оно остаться или нет. ln -sf libhello.so.0 libhello.so # Компиляция файла программы demo_use. gcc -Wall -g -c demo_use.c -o demo_use.o # Создание программы demo_use. # -L. добавляет директорию "." в поиск # библиотек на время создания программы; # заметьте, что это не означает, что "." # будет находиться в списке директорий для поиска # библиотек во время исполнения. gcc -g -o demo_use demo_use.o -L. -lhello # Исполнение программы. Обратите внимание, # что нам необходимо сказать программе, где # находится общая библиотека, используя LD_LIBRARY_PATH. LD_LIBRARY_PATH="." ./demo_use
Файл demo_dynamic.c
/* demo_dynamic.c -- демонстрирует динамическую загрузку и использование процедуры "hello" */ /* dlfcn.h требуется для процедур, динамически загружающих библиотеку */ #include #include #include /* Обратите внимание, что мы не должны включать "libhello.h". Однако, нам необходимо указать нечто похожее; мы должны указать тип, который будет хранить значение, которое мы собираемся получить из dlsym(). */ /* Тип "simple_demo_function" описывает функцию, которая не принимает аргументов и не возвращает значения: */ typedef void (*simple_demo_function)(void); int main(void) < const char *error; void *module; simple_demo_function demo_function; /* Загрузка линамически загружаемой библиотеки */ module = dlopen("libhello.so", RTLD_LAZY); if (!module) < fprintf(stderr, "Couldn't open libhello.so: %s\n", dlerror()); exit(1); >/* Получение символа */ dlerror(); demo_function = dlsym(module, "hello"); if ((error = dlerror())) < fprintf(stderr, "Couldn't find hello: %s\n", error); exit(1); >/* Вызов функции из DL библиотеки */ (*demo_function)(); /* Все сделано, закрываем библиотеку */ dlclose(module); return 0; >
Файл script_dynamic
#!/bin/sh # Пример динамически загружаемой библиотеки # Предполагаем, что libhello.so и другие необходимые файлы # уже созданы (смотрите пример динамически загружаемой библиотеки). # Компиляция программы demo_dynamic в объектный файл. gcc -Wall -g -c demo_dynamic.c # Создание программы demo_use. # Обратите внимание, что нам не нужно указывать, # где искать DL библиотеки, так как единственная специальная # библиотека, используемая программой, не будет загружена до # запуска программы. Однако, нам необходима опция -ldl, # чтобы включить библиотеку, которая загружает DL библиотеки. gcc -g -o demo_dynamic demo_dynamic.o -ldl # Запуск программы. Обратите внимание, # что нам необходимо сказать программе, где # находится общая библиотека, используя LD_LIBRARY_PATH. LD_LIBRARY_PATH="." ./demo_dynamic

Этот раздел является переводом руководства Program Library HOWTO

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *