Статья
Версия для печати
Обсудить на форуме
Совместно используемые библиотеки в C под Linux для начинающих.


Для начала напишем два файлика test.c и app.c:

Листинг test.c
Код: (C)
int f()
{
        return 3;
}

Листинг app.c
Код: (C)
int main()
{
return f();
}

Конечно можно всё сразу собрать и всё зарабоет. Но мы пойдем другим путём берём компилируем test.c в test.o.

$ gcc -c -o test.o test.c

Опция -c значит скомпилировать не соберая. Теперь делаем из test.o библиотечку статическую. Выполняем вот эту команду.

$ ar cr libtest.a test.o test1.o test2.o

Файлы test1.o и test2.o я вписал просто показать, что можно собрать некий архив объектных файлов ("архив" это второе название статической библиотеки). Заметьте, что у слова тест появился префикс lib и окончание поменяли с .o на .a . Команда опции команды ar означают: c не ругатся если надо создать файл; r запихать в архив файлы или заменить существующие.

Попробуем это всё собрать.

$ gcc -c -o app.o app.c
$ gcc -o app -L. -ltest app.o
app.o(.text+0x11): In function 'main':: undefined reference to 'f'
collect2: ld returned. 1 exit status


Спрашиваете, что буквально за фигня. Отвечаю: компоновщик смотрит свои параметры слева на право и когда он доходит до app.o он "думает", что libtest.a ему нафиг не нужна никто её не пользует, отсюды вывод надо поставить app.o сразу после app и всё заработает. Проверяем.

$ gcc -o app app.o -L. -ltest

Работает. Далее надо проверить работает ли наш файлик app который мы собрали.

$ ./app
$ echo $?
3
$


Работает, как не странно! Опять на счет опций -L. значит искать библиотеки сначала в директории указанной после -L в нашем случае у нас стоит там точка значит в дериктории. где мы находимся. Опция -ltest как раз и значит использовать библиотеку libtest.

С этим надеюсь ясно. Тепер переходим к совместно используемым библиотекам(динамически подключаемым). Эти библиотеки похожы на архивы, но гдавное отличие в том, что вместо кода из библиотеки в программу включается ссылка на библиотеку.
Для создания библиотеки составляющие её файлы надо собрать использую опцию -fPIC (Position-Independent Code):

$ gcc -c -fPIC test.c

Теперь соберём библиотеку:

$ gcc -shared -fPIC -o libtest.so test.o test1.o test2.o

Опция -shared заставляет компоновщик создать именно совместно используемую библиотеку. Заново собераем нашу программу:

$ gcc -o app app.o -L. -ltest

Теперь выполним команду:

$ ldd app
libtest.so =› not found
libc.so.6 =› /lib/tls/libc.so.6 (0x42000000)
/lib/ld-linux.so.2 =› /lib/ld-linux.so.2 (0x40000000)


Эта команда нам показывает используемые библиотеки. Как видите нашу библиотечку программа не нашла. А всё потому что в файл помещается только имя библиотеки, а не путь к ней и при запуске библиотека ищется только в стандартных каталогах /lib и /usr/lib. При попытке запустить программу получаем сообщение о том, что не найдена библиотека. Первое решение проблемы установить переменную окружения LD_LIBRARY_PATH

$ export LD_LIBRARY_PATH=/home/logrus/Documents/test:/usr/local/lib

Выполнив эту команду мы сообщили ситеме, что библиотеки могут хранится еще и в директориях /home/logrus/Documents/test и /usr/local/lib .
Другое решение использование при компиляции опции -Wl,-rpath примерно так:

$ gcc -o app app.o -L. -ltest -Wl,-rpath,/home/logrus/Documents/test

В этом случае в вашем приложении будет прописан полный путь до библиотеки.
У вас наверняка возник вопрос, а что, если у меня есть оба вариата библиотеки и .a и .so? В этом случае если компоновщик обнаруживает обе библиотеки, то он выберет динамическую, если не указано иначе. Иначе это использовать опцию -static.
Рекомендую всё это срочно протестировать! Набивать текста не много.
Если вам захочится использовать математические функции, которые не входят в состав libc (стандартаня библиотека C) автоматически подключаемой к вашей программе (это если вы этого не заметили в результатах работы комады ldd), то компилируем так:

# gcc -o compute compute.c -lm

При компоновке програм на C++ к вашей программе подключается библиотека libstdc++.

Часто библиотеки связаны между собой.
Например соберем такую штуку:

Листинг testtiff.c
Код: (C)
#include <stdio.h>
#include <tiffio.h>

int main (int argc, char** argv)
{
        TIFF* tiff;
        tiff = TIFFOpen (argv[1], "r");
        TIFFClose(tiff);
        return 0;
}

При компилляции используем флаг -ltiff

$ gcc -o tifftest tifftest.c -ltiff

Посмотрим что нам выдаст ldd.

$ ldd tifftest
libtiff.so.3 =› /usr/lib/libtiff.so.3 (0x40022000)
libc.so.6 =› /lib/tls/libc.so.6 (0x42000000)
libjpeg.so.62 =› /usr/lib/libjpeg.so.62 (0x40063000)
libz.so.1 =› /usr/lib/libz.so.1 (0x40082000)
/lib/ld-linux.so.2 =› /lib/ld-linux.so.2 (0x40000000)


Это говорит нам о том, что динимические библиотеки зависят от друг друга и что эти библиотеки также подключены. Посмотри и запешите или запомните разменр исполняемого файла tifftest.
Соберем его со статическими библиотеками.

$ gcc -static -o tifftest tifftest.c -ltiff

/usr/local/lib/libtiff.a(tif_luv.o)(.text+0xf74): In function `LogL16toY':
../libtiff/tif_luv.c:657: undefined reference to `exp'
/usr/local/lib/libtiff.a(tif_luv.o)(.text+0x1014): In function `LogL16fromY':
../libtiff/tif_luv.c:672: undefined reference to `log'
/usr/local/lib/libtiff.a(tif_luv.o)(.text+0x1036):../libtiff/tif_luv.c:672: undefined reference to `log'
/usr/local/lib/libtiff.a(tif_luv.o)(.text+0x10b8):../libtiff/tif_luv.c:674: undefined reference to `log'
/usr/local/lib/libtiff.a(tif_luv.o)(.text+0x10e8):../libtiff/tif_luv.c:674: undefined reference to `log'
/usr/local/lib/libtiff.a(tif_luv.o)(.text+0x1467): In function `LogL10toY':
../libtiff/tif_luv.c:736: undefined reference to `exp'
/usr/local/lib/libtiff.a(tif_luv.o)(.text+0x14cd): In function `LogL10fromY':
../libtiff/tif_luv.c:750: undefined reference to `log'
/usr/local/lib/libtiff.a(tif_luv.o)(.text+0x14ef):../libtiff/tif_luv.c:750: undefined reference to `log'
collect2: ld returned 1 exit status


Ну как красиво? Это из-за того, что статические библиотеки не могут ссылаться друг на друга. Значит нам надо вручною указать все необходимые библиотеки.

$ gcc -static -o tifftest tifftest.c -ltiff -ljpeg -lz -lm

Проверьте размер исполняемого файла. Ну как впечатляет? Проверьте подключеныль динамические библиотеки.
И на последок. Допустим есть ситуация когда библиотеки циклически зависят друг от друга, т.е. libtest1.a зависит от libtest2.a, а libtest2.a зависит от libtest1.a тогда просто следует сделать например так:

$ gcc -o app app.o -ltest1 -ltest2 -ltest1

Пока всё! ;)


Автор: LogRus
Версия для печати
Обсудить на форуме