- Подключение динамической библиотеки c linux
- 3.2. Пример статической библиотеки
- 3.3. Пример совместно используемой библиотеки
- Салимóненко Дмитрий Александрович
- Информация
- Операционные системы
- Задание 6: Создание статических и динамических библиотек
- Введение
- Исходные коды библиотек
- Статические библиотеки
- Динамические библиотеки
- 1. «Обычное» подключение динамических библиотек
- 2. Динамическая подгрузка динамических библиотек через системный вызов dlopen()
- Минимизируем объем библиотеки утилитой strip
Подключение динамической библиотеки c linux
Как уже неоднократно упоминалось в предыдущей главе, библиотека — это набор скомпонованных особым образом объектных файлов. Библиотеки подключаются к основной программе во время линковки. По способу компоновки библиотеки подразделяют на архивы (статические библиотеки, static libraries) и совместно используемые (динамические библиотеки, shared libraries). В Linux, кроме того, есть механизмы динамической подгрузки библиотек. Суть динамической подгрузки состоит в том, что запущенная программа может по собственному усмотрению подключить к себе какую-либо библиотеку. Благодаря этой возможности создаются программы с подключаемыми плагинами, такие как XMMS. В этой главе мы не будем рассматривать динамическую подгрузку, а остановимся на классическом использовании статических и динамических библиотек.
С точки зрения модели КИС, библиотека — это сервер. Библиотеки несут в себе одну важную мысль: возможность использовать одни и те же механизмы в разных программах. В Linux библиотеки используются повсеместно, поскольку это очень удобный способ «не изобретать велосипеды». Даже ядро Linux в каком-то смысле представляет собой библиотеку механизмов, называемых системными вызовами.
Статическая библиотека — это просто архив объектных файлов, который подключается к программе во время линковки. Эффект такой же, как если бы вы подключали каждый из файлов отдельно.
В отличие от статических библиотек, код совместно используемых (динамических) библиотек не включается в бинарник. Вместо этого в бинарник включается только ссылка на библиотеку.
Рассмотрим преимущества и недостатки статических и совместно используемых библиотек. Статические библиотеки делают программу более автономной: программа, скомпонованная со статической библиотекой может запускаться на любом компьютере, не требуя наличия этой библиотеки (она уже «внутри» бинарника). Программа, скомпонованная с динамической библиотекой, требует наличия этой библиотеки на том компьютере, где она запускается, поскольку в бинарнике не код, а ссылка на код библиотеки. Не смотря на такую зависимость, динамические библиотеки обладают двумя существенными преимуществами. Во-первых, бинарник, скомпонованный с совместно используемой библиотекой меньше размером, чем такой же бинарник, с подключенной к нему статической библиотекой (статически скомпонованный бинарник). Во-вторых, любая модернизация динамической библиотеки, отражается на всех программах, использующих ее. Таким образом, если некоторую библиотеку foo используют 10 программ, то исправление какой-нибудь ошибки в foo или любое другое улучшение библиотеки автоматически улучшает все программы, которые используют эту библиотеку. Именно поэтому динамические библиотеки называют совместно используемыми. Чтобы применить изменения, внесенные в статическую библиотеку, нужно пересобрать все 10 программ.
В Linux статические библиотеки обычно имеют расширение .a (Archive), а совместно используемые библиотеки имеют расширение .so (Shared Object). Хранятся библиотеки, как правило, в каталогах /lib и /usr/lib. В случае иного расположения (относится только к совместно используемым библиотекам), приходится немного «подшаманить», чтобы программа запустилась.
3.2. Пример статической библиотеки
Теперь давайте создадим свою собственную библиотеку, располагающую двумя функциями: h_world() и g_world(), которые выводят на экран «Hello World» и «Goodbye World» соответственно. Начнем со статической библиотеки.
Начнем с интерфейса. Создадим файл world.h: Здесь просто объявлены функции, которые будут использоваться.
Теперь надо реализовать серверы. Создадим файл h_world.c: Теперь создадим файл g_world.c, содержащий реализацию функции g_world(): Можно было бы с таким же успехом уместить обе функции в одном файле (hello.c, например), однако для наглядности мы разнесли код на два файла.
Теперь создадим файл main.c. Это клиент, который будет пользоваться услугами сервера:
Теперь напишем сценарий для make. Для этого создаем Makefile: Не забывайте ставить табуляции перед каждым правилом в целевых связках.
Осталось только проверить, работает ли программа и разобраться, что же мы такое сделали:
Итак, в приведенном примере появились три новые вещи: опции -l и -L компилятора, а также команда ar. Начнем с последней. Как вы уже догадались, команда ar создает статическую библиотеку (архив). В нашем случае два объектных файла объединяются в один файл libworld.a. В Linux практически все библиотеки имеют префикс lib.
Как уже говорилось, компилятор gcc сам вызывает линковщик, когда это нужно. Опция -l, переданная компилятору, обрабатывается и посылается линковщику для того, чтобы тот подключил к бинарнику библиотеку. Как вы уже заметили, у имени библиотеки «обрублены» префикс и суффикс. Это делается для того, чтобы создать «видимое безразличие» между статическими и динамическими библиотеками. Но об этом речь пойдет в других главах книги. Сейчас важно знать лишь то, что и библиотека libfoo.so и библиотека libfoo.a подключаются к проекту опцией -lfoo. В нашем случае libworld.a «урезалось» до -lworld.
Опция -L указывает линковщику, где ему искать библиотеку. В случае, если библиотека располагается в каталоге /lib или /usr/lib, то вопрос отпадает сам собой и опция -L не требуется. В нашем случае библиотека находится в репозитории (в текущем каталоге). По умолчанию линковщик не просматривает текущий каталог в поиске библиотеки, поэтому опция -L. (точка означает текущий каталог) необходима.
3.3. Пример совместно используемой библиотеки
Для того, чтобы создать и использовать динамическую (совместно используемую) библиотеку, достаточно переделать в нашем проекте Makefile.
Внешне ничего не изменилось: программа компилируется, запускается и выполняет те же самые действия, что и в предыдущем случае. Изменилась внутренняя суть, которая играет для программиста первоочередную роль. Рассмотрим все по порядку.
Правило для сборки binary теперь содержит пугающую опцию -Wl,-rpath,. Ничего страшного тут нет. Как уже неоднократно говорилось, компилятор gcc сам вызывает линковщик ld, когда это надо и передает ему нужные параметры сборки, избавляя нас от ненужной платформенно-зависимой волокиты. Но иногда мы все-таки должны вмешаться в этот процесс и передать линковщику «свою» опцию. Для этого используется опция компилятора -Wl,option,optargs. Расшифровываю: передать линковщику (-Wl) опцию option с аргументами optargs. В нашем случае мы передаем линковщику опцию -rpath с аргументом . (точка, текущий каталог). Возникает вопрос: что означает опция -rpath? Как уже говорилось, линковщик ищет библиотеки в определенных местах; обычно это каталоги /lib и /usr/lib, иногда /usr/local/lib. Опция -rpath просто добавляет к этому списку еще один каталог. В нашем случае это текущий каталог. Без указания опции -rpath, линковщик «молча» соберет программу, но при запуске нас будет ждать сюрприз: программа не запустится из-за отсутствия библиотеки. Попробуйте убрать опцию -Wl,-rpath,. из Makefile и пересоберите проект. При попытке запуска программа binary завершится с кодом возврата 127 (о кодах возврата будет рассказано в последующих главах). То же самое произойдет, если вызвать программу из другого каталога. Верните обратно -Wl,-rpath. пересоберите проект, поднимитесь на уровень выше командой cd .. и попробуйте запустить бинарник командой world/binary. Ничего не получится, поскольку в новом текущем каталоге библиотеки нет.
Есть один способ не передавать линковщику дополнительных опций при помощи -Wl — это использование переменной окружения LD_LIBRARY_PATH. В последующих главах мы будем подробно касаться темы окружения (environment). Сейчас лишь скажу, что у каждого пользователя есть так называемое окружение (environment) представляющее собой набор пар ПЕРЕМЕННАЯ=ЗНАЧЕНИЕ, используемых программами. Чтобы посмотреть окружение, достаточно набрать команду env. Чтобы добавить в окружение переменную, достаточно набрать export ПЕРЕМЕННАЯ=ЗНАЧЕНИЕ, а чтобы удалить переменную из окружения, надо набрать export -n ПЕРЕМЕННАЯ. Будьте внимательны: export — это внутреннаяя команда оболочки BASH; в других оболочках (csh, ksh, . ) используются другие команды для работы с окружением. Переменная окружения LD_LIBRARY_PATH содержит список дополнительных «мест», разделенных двоеточиеями, где линковщих должен искать библиотеку.
Не смотря на наличие двух механизмов передачи информации о нестандартном расположении библиотек, лучше помещать библиотеки в конечных проектах в /lib и в /usr/lib. Допускается расположение библиотек в подкаталоги /usr/lib и в /usr/local/lib (с указанем -Wl,-rpath). Но заставлять конечного пользователя устанавливать LD_LIBRARY_PATH почти всегда является плохим стилем программирования.
Следующая немаловажная деталь — это процесс создания самой библиотеки. Статические библиотеки создаются при помощи архиватора ar, а совместно используемые — при помощи gcc с опцией -shared. В данном случае gcc опять же вызывает линковщик, но не для сборки бинарника, а для создания динамической библиотеки.
Источник
Салимóненко Дмитрий Александрович
Информация
Операционные системы
Задание 6: Создание статических и динамических библиотек
Введение
Библиотеки в Linux бывают статическими и динамическими. В моих методических указаниях, учебных пособиях, вроде бы, изложена информация на этот счет. В частности, изложен порядок создания и сборки программ, содержащих библиотеки, даны соответствующие команды для bash . Команды содержат незначительные ошибки с целью, чтобы студент проявил самостоятельность, воспользовался поиском в интернете и устранил бы их.
По способу компоновки библиотеки подразделяют на архивы (статические библиотеки, static libraries ) и совместно используемые (динамические библиотеки, shared libraries ). В Linux, кроме того, есть механизмы динамической подгрузки библиотек. Суть динамической подгрузки состоит в том, что запущенная программа может по собственному усмотрению подключить к себе какую-либо библиотеку. Об этом всем пойдет речь ниже.
Статическая библиотека — это просто архив объектных файлов, который подключается к программе во время линковки (сборки). Эффект тот же самый, как если бы вы подключали каждый из файлов отдельно, не делая из них библиотеку.
В отличие от статических библиотек, код совместно используемых (динамических) библиотек не включается в исполняемый (бинарный) файл. Вместо этого в нем присутствует только ссылка на библиотеку.
В Linux статические библиотеки обычно имеют расширение .a (Archive) , а совместно используемые библиотеки имеют расширение .so (Shared Object). Хранятся библиотеки, как правило, в каталогах /lib и /usr/lib .
Подключаемые библиотеки необходимо перечислять после имени ссылающегося на них файла.
В соответствии с соглашениями FHS (Filesystem Hierarchy Standard) в системе должны быть два (как минимум) каталога для хранения файлов библиотек:
/lib — здесь собраны основные библиотеки дистрибутива, необходимые для работы программ из /bin и /sbin ;
/usr/lib — здесь хранятся библиотеки необходимые прикладным программам из /usr/bin и /usr/sbin ;
Соответствующие библиотекам заголовочные файлы должны находиться в каталоге /usr/include .
/usr/local/lib — здесь должны находиться библиотеки, развернутые пользователем самостоятельно, минуя систему управления пакетами (не входящие в состав дистрибутива). Например в этом каталоге по умолчанию окажутся библиотеки скомпилированные из исходников (программы установленные из исходников будут размещены в /usr/local/bin и /usr/local/sbin , разумеется речь идет о бинарных дистрибутивах). Заголовочные файлы библиотек в этом случае будут помещены в /usr/local/include .
Исходные коды библиотек
Давайте создадим пару библиотек, которые будем потом подключать разными способами:
Т.е. это – обычные функции типа «Hello World».
Затем рассмотрим код главной программы main.c :
Далее посмотрим, каким образом из двух вышеприведенных программ сделать библиотеку и использовать ее для работы главной программы main .
Статические библиотеки
Для компиляции статической библиотеки лучше всего использовать Makefile , так как придется вводить несколько строчек в консоли:
# Makefile for static library
- binary : main.o libworld.a
- [TAB] gcc -o main main.o -L. -lmain -I.
- main.o : main.c
- [TAB] gcc -c main.c
- libmain.a : function1.o function2.o
- [TAB] ar cr libmain.a function1.o function2.o
- function1.o : function1.c
- [TAB] gcc -c function1.c
- function2.o : function2.c
- [TAB] gcc -c function2.c
- clean :
- [TAB] rm -f *.o *.a main
Описание используемых опций приведено ниже. Запускаем программу:
Все должно работать.
Чтобы избежать повторного включения одного и того же кода (одних и тех же библиотек) в разных модулях проекта, используются директивы #ifndef, #define, #endif .
1. Заголовочный файл
Заголовочный файл может иметь следующий вид:
- /* main.h */
- void function1 (void);
- void function2 (void);
Чтобы подключить его к программе main.c , в ней между строчками 4 и 5 следует написать:
2. Объявление библиотечных функций в теле программы main.c
Для этого строчки
- void function1 (void);
- void function2 (void);
следует указать в теле программы main.c между строчками 4 и 5.
Этот способ использовать нецелесообразно, так как легко запутаться и не указать все используемые функции. А если библиотек будет много, то может получиться вообще неразбериха. Поэтому лучше использовать первый способ.
Динамические библиотеки
Динамическая библиотека, в отличие от статической, не присоединяется к исполняемому файлу (программе). Использование динамических библиотек в Linux возможно разными способами. Общим среди них является то, что программа должна содержать в себе вызовы таких библиотек (точки входа). Рассмотрим здесь варианты.
Пути для поиска библиотек назначаются:
Чаще всего системные библиотеки находятся в каталогах /lib и /usr/lib , поэтому два этих каталога просматриваются автоматически.
В книгах пишут, что, типа того, другие каталоги задаются одной или несколькими опциями -L в командной строке. Например, по следующей команде компоновщик будет просматривать текущий каталог и каталог с именем /home/Desktop/lib для поиска любой библиотеки, не обнаруженной в пути поиска по умолчанию:
gcc -L. -L/home/Desktop/lib hello.о
Однако, у меня в Ubuntu 16 такой способ именно для динамических библиотек не заработал, при запуске компилятор не может обнаружить динамическую библиотеку.
Также пишут, что компоновщик сначала проводит поиск разделяемых библиотек, а затем уже статических (если при сборке библиотека указывается как -lmain , а не как libmain.a или libmain.so ).
1. «Обычное» подключение динамических библиотек
Рассмотрим теперь Makefile для компиляции и создания динамической библиотеки:
# Makefile for dynamic library (1) project (usual use)
- main1 : main1.o libmain1.so
- # [TAB] gcc -o main1 main1.o -L. -lmain1 -Wl,-rpath,.
- [TAB] gcc -o main1 main1.o libmain1.so -Wl,-rpath,.
- main1.o : main1.c
- [TAB] gcc -c main1.c
- libmain1.so : function1.o function2.o
- [TAB] gcc -shared -o libmain1.so function1.o function2.o
- function1.o : function1.c
- [TAB] gcc -c -fPIC function1.c
- function2.o : function2.c
- [TAB] gcc -c -fPIC function2.c
- clean :
- [TAB] rm -f *.o *.so main1
Внимание: между -Wl , и -rpath,. пробела НЕТ. Т.е. пишется слитно: « Wl,-rpath,. ».
И еще раз: сборку динамической библиотеки с объектным файлом main1.o можно проводить разными способами, указывая либо полное имя библиотеки:
либо сокращенное с опцией -l (нежелательно, см. выше):
Если все вышесказанное было выполнено правильно, в результате запуска программы main1 в консоли получится что-то вроде:
- Testing Function1:
- LOADED Function 1 worked.
- Testing Function2:
- LOADED Function 2 worked.
2. Динамическая подгрузка динамических библиотек через системный вызов dlopen()
Второй вариант вызова динамических библиотек — проще. Суть динамической подгрузки состоит в том, что запущенная программа может по собственному усмотрению подключить к себе какую-либо (динамическую) библиотеку. Благодаря этой возможности создаются программы с подключаемыми плагинами, такие как XMMS. Для этого используется функция dlopen() .
Как и выше, из двух процедур-функций function1.c и function2.c следует сделать объектные файлы (с расширением .о ), а затем скомпилировать их в динамическую библиотеку. Можно делать это по очереди (используя три последовательные команды, как в вышеприведенном Makefile ), а можно и сразу одной командой:
gcc -fpic -shared function1.c function2.c -o libFunc1_Func2.so
Если компиляция пройдет успешно, в текущем каталоге появится файл libFunc1_Func2.so . Это и есть динамическая библиотека.
Далее рассмотрим главную функцию, которая, собственно, и будет подгружать эту динамическую библиотеку и вызывать имеющиеся в ней функции function1() и function2() :
Как видим, при той же самой функциональности ее исходный код несколько усложнился – добавились строчки, обрабатывающие динамическую подгрузку библиотеки.
Компилировать следует так:
gcc main2.c -ldl -o main2 -Wl,-rpath,.
Таким образом, состав файлов проекта:
Запускаем — как обычно:
Здесь использован вызов dlopen() , который загружает в память динамическую (разделяемую) библиотеку (если она еще не загружена) и возвращает идентификатор, используемый для адресации к ее функциям. Вызов dlsym() возвращает адреса функций, которые потом могут вызываться, как будто бы они находятся в главной программе main .
Функция dlclose() отсоединяет ( detache ) главную (текущую) программу от загруженной разделяемой библиотеки (что ОЧЕНЬ удобно, если необходимо минимизировать объем используемой оперативной памяти). Отметим, что если к динамической библиотеке не присоединено больше ни одной программы, то она выгружается из памяти.
Функция dlerror() возвращает строку описания ошибки, произошедшей при последнем вызове одной из функций dlopen() , dlclose(), dlsym() . При отсутствии ошибок dlerror() возвращает значение NULL .
Второй аргумент вызова функции dlopen() — флаг способа динамической загрузки библиотеки. Он может иметь следующие значения. При значении RTLD_NOW все функции библиотеки сразу загружаются в память и после этого становятся доступными для вызова. При значении флага RTLD_LAZY загрузка каждой функции задерживается до тех пор, пока ее имя не будет передано функции dlsym() . Каждое из двух этих значений флага может быть соединено с помощью ключевого слова OR со значением RTLD_GLOBAL . При этом все внешние вызовы загружаемой динамической библиотеки разрешаются вызовом функций из других динамических библиотек. Последние при этом также загружаются в (оперативную) память компьютера.
Таким образом, динамическая подгрузка динамических библиотек дает очень удобные возможности по их использованию. Чтобы это продемонстрировать, попробуем немного «испортить» ситуацию: изменим имя динамической библиотеки на
Попытавшись запустить программу main, видим, что библиотека libFunc1_Func2.so не найдена, в консоли будет что-то типа:
dlopen: libFunc1_Func2.so: cannot open shared object file: No such file or directory
Это и понятно – ведь мы изменили имя исходной динамической библиотеки. Как поправить ситуацию? Легко. Надо всего-навсего изменить имя этой библиотеки в программе main2.c (см. строчку 11) и заново ее откомпилировать. Итак:
11. LIB_so = dlopen ( «libFunc1_Func2_X.so» , RTLD_LAZY );
Компилируем и получаем то же, что и раньше:
- Testing Function1:
- LOADED Function 1 worked.
- Testing Function2:
- LOADED Function 2 worked.
Понятно, что вместо libFunc1_Func2_X.so вполне можно было указать имя какой-нибудь другой динамической библиотеки или даже использовать параметр типа argv[] , в который будет поступать имя библиотеки, вводимое в консоли при запуске программы. Таким образом, данный способ (динамической подгрузки) дает очень даже удобные и легкие возможности по использованию библиотек в собственных программах: достаточно лишь указать их имена и затем подгрузить при помощи функции dlopen() . После чего останется лишь вызывать содержащиеся в библиотеках функции.
Обратите внимание: в отличие от первого варианта, здесь, при динамической подгрузке, НЕТ НЕОБХОДИМОСТИ собирать динамическую библиотеку вместе с объектным файлом программы main2.o – в отличие от первого варианта («обычной» компиляции динамической библиотеки).
Минимизируем объем библиотеки утилитой strip
Эта утилита позволяет снизить объем объектных файлов, равно как и модулей библиотек за счет удаления из них отладочной информации.
strip libmain1.so -o libmain1_MIN.so
Данная команда создаст библиотеку libmain1_MIN.so . Ее объем у меня составил, к примеру, 6152 байтов, тогда как объем исходной библиотеки ( libmain1.so ) составляет 8192 байтов. Как видим, разница – существенная. Однако, это целесообразно делать только тогда, когда программа уже полностью отлажена и компилируется в чистовую.
Если нужно удалить отладочную информацию из самого исходного файла, не создавая новый, тогда можно использовать команду
Через пробел можно добавить еще другие объектные файлы (в том числе и библиотеки), которые следует минимизировать по объему. Кстати, не стоит пытаться минимизировать при помощи этой утилиты статическую библиотеку. Скорее всего, она будет после этого испорчена.
Вывод списка зависимостей, связанных с динамическими библиотеками при помощи утилиты ldd
1. Попробуйте выполнить (для статической библиотеки):
Примерно вот что получится:
- linux-vdso.so.1 => (0x00007ffc9bb33000)
- libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f5f14039000)
- /lib64/ld-linux-x86-64.so.2 (0x00007f5f14403000)
Т.е. есть лишь зависимости, связанные с системными библиотеками Linux. Самой же статической библиотеки, естественно, нет, так как она вошла в состав исполняемого файла. Кстати, с целью убедиться в этом (косвенно), неплохо бы сравнить объемы файлов. Для чего посмотрите, сколько байтов занимают объектные файлы function1.o, function2.o, main.o, libmain.a , просуммируйте и сравните с объемом исполняемого файла main. У меня получилось примерно следующее.
Сумма байтов в указанных четырех файлах:
1528 + 1392 + 3140 + 1792 = 7852 байта.
Объем исполняемого файла:
Таким образом, объемы получились сравнимыми, правда, объем исполняемого файла – несколько выше. Скорее всего, за счет наличия разного рода управляющей информации, определения адресов расположения присоединенных к нему функций и т.д.
2. Теперь выполняем (для динамической библиотеки, скомпилированной по первому варианту):
Получится что-то вроде:
- linux-vdso.so.1 => (0x00007ffca1599000)
- libmain1.so => ./libmain1.so (0x00007fca4fb7d000)
- libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fca4f7b3000)
- /lib64/ld-linux-x86-64.so.2 (0x00007fca4fd7f000)
Как видим, во второй строчке идет наша библиотека libmain1.so , указан ее начальный виртуальный адрес. Т.е., по сути, нет ничего необычного.
3. А затем попробуйте выполнить
В результате получим:
- linux-vdso.so.1 => (0x00007ffce59fb000)
- libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fadc5e65000)
- libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fadc5a9b000)
- /lib64/ld-linux-x86-64.so.2 (0x00007fadc6069000)
Любопытно, что при динамической подгрузке в перечне зависимостей нет библиотеки libFunc1_Func2.so , упомянутой в исходном коде main2.c . А почему? См. выше. Потому, что мы эту библиотеку не собирали вместе главной функцией, а лишь сделали ее динамическую подгрузку. Поэтому компилятор и не включил эту библиотеку в перечень зависимостей. Вместо нее фигурирует системная библиотека libdl.so.2 . Для подключения этой библиотеки и используется опция -ldl .
Итак, еще раз: второй вариант использует динамическую подгрузку динамической библиотеки. Тогда как первый вариант можно было бы условно назвать «статическим» подключением динамической библиотеки.
Основные опции компилятора gcc, использующиеся для компиляции библиотек
Команда аr создает статическую библиотеку (архив). В данном случае два объектных файла объединяются в один файл libmain.a .
Опция -I , переданная компилятору, обрабатывается и посылается линковщику для того, чтобы тот подключил к бинарному файлу библиотеку.
Опция -L. указывает линковщику, где ему искать библиотеку. В случае, если библиотекa располагается в каталоге /lib или /usr/lib , то вопрос отпадает сам собой и опция -L. не требуется. В нашем же случае библиотека находится в репозитории (в текущем каталоге). По умолчанию линковщик не просматривает текущий каталог в поиске библиотеки, поэтому опция -L. (точка означает, как обычно, текущий каталог) необходима (для статических библиотек).
Опция -l используется для реализации ссылок на библиотеки, которые существуют в каталогах, указанных в параметрах -L . Эти каталоги также появляются в LD_LIBRARY_PATH . Таким образом, получается преобразование имен библиотек:
Опция -static указывает линковщику использовать только статические версии всех необходимых приложению библиотек:
gcc -static -o main main.o -L. -lmain
Опция -shared вызывает линковщик, только не для сборки исполняемого файла, а для создания динамической библиотеки.
Опция -fPIC генерирует позиционно-независимый код для динамических библиотек (если используется опция -shared).
Опция -fpic создает более эффективный код (если поддерживается платформой компилятора).
Опция -Wl, используется для передачи линковщику (сборщику) каких-либо своих (дополнительных) опций. Например, так можно передать путь к библиотеке.
Опция -rpath,. необходима для указания линковщику пути к библиотеке (в данном случае – текущий каталог). Передается при помощи опции -Wl,
Опция -fPIC ( -fpic ) при компиляции function1.c и function2.c сообщает компилятору, что объектные файлы, полученные в результате компиляции должны содержать позиционно-независимый код (PIC — Position Independent Code), который используется в динамических библиотеках. В таком коде используются не абсолютные (фиксированные) виртуальные позиции (адреса), а относительные (плавающие), что позволяет корректно использовать динамическую библиотеку, размещенную практически с любого виртуального адреса.
Опция -ldl означает компоновку с библиотекой libdl .
Опция -f (для команды rm ) означает, что не будет запрашиваться подтверждений, будет удаляться все, что возможно.
Опция -o создает выходной исполняемый файл (т.е. создает и объектные файлы и их сборку в бинарный файл).
Опция -c создает объектные файлы, не собирая их в исполняемый файл (т.е. только компиляция, без линкования).
Опции -Wall -Wextra позволяет компилятору выводить все предупреждения. Эту опцию целесообразно использовать всегда, чтобы генерировать наиболее безошибочный код.
С уважением, Салимоненко Д.А.
Этот сайт адаптирован (в целях соответствия современным нормам) для просмотра на устройствах с шириной экрана не менее 200 пикселей. Но, все-таки, я рекомендую просматривать его с компьютера через кабельный интернет или, хотя бы, через USB-модем, удаленный на расстояние не менее 5. 7 метров от пользователя. Я не рекомендую пользоваться модемами, встроенными в компьютер, телефон и т.п. Берегите свое здоровье и психику от СВЧ-излучения)).
Источник