Содержание
Введение
1 Компиляцияпрограмм на языке C/C++
2Компиляция нескольких файлов
3Создание библиотек объектных файлов
3.1Библиотеки объектных файлов
3.2Создание статической библиотеки
3.3Создание динамической библиотеки
3.4Использование динамических библиотек
4Создание динамических библиотек
4.1Функции работы с динамическими библиотеками
4.2Создание динамической библиотеки для решения системы линейных уравнений
Выводы
Списокиспользованной литературы
Введение
Простые программы обычно состоят из одного исходногофайла. Но если программы становится большой, ее рекомендуется их разбивать накуски, которые функционально ограничены и закончены. Так как процесс правки при большом исходном тексте становится сложным и поиск небольшой ошибки можетповлечь за собой вынужденное «изучение» кода заново. Также большойфайл программы увеличивает время компиляции.
Но если каждая функциябудет содержаться в отдельном файле, то таких файлов может оказаться десяткиили даже сотни. Управлять таким количеством файлов очень сложно. Для этого былпридуман механизм создания библиотек объектных файлов.
Библиотека объектных файлов- это файл содержащий несколько объектных файлов, которые будут использоватьсявместе в стадии линковки программы. Библиотека содержит символьный индекс,который состоит из названий функций и переменных и т.д., которые содержатся вбиблиотеке. Это позволяет ускорить процесс линковки программы, так как поискфункций и переменных в объектных файлах библиотеки происходит намного быстрее,чем поиск в наборе указанных объектных файлов.
Поэтому использованиебиблиотеки позволяет компактно хранить все требуемые объектные файлы в одномместе, и при этом значительно повысить скорость компиляции.
В курсовой работеприведены примеры создания и использования статических и динамическихбиблиотек. Д разработано несколько простых динамических библиотек (возведение числав степень и решение системы линейных уравнений)
1 Компиляцияпрограмм на языке C/C++
Компилятор превращает кодпрограммы на «человеческом» языке в объектный код понятныйкомпьютеру. Компиляторов под Linux существует много, практически длякаждого распространенного языка. Большинство самых востребованных компилятороввходит в набор GNU Compiler Collection, известных под названием GCC(http://gcc.gnu.org/).
Изначально аббревиатура GCCимела смысл GNU C Compiler, но в апреле 1999 года сообщество GNU решиловзять на себя более сложную миссию и начать создание компиляторов для новыхязыков с новыми методами оптимизации, поддержкой новых платформ, улучшенных runtime-библиотеки других изменений (http://gcc.gnu.org/gccmission.html). Поэтому сегодня коллекциясодержит в себе компиляторы для языков C, C++, Objective C, Chill, Fortran,Ada и Java, как библиотеки для этих языков (libstdc++, libgcj,...).
Компиляция программпроизводится командой:
gcc
После этого, если процесскомпиляции пройдет успешно, то вы получите загружаемый файл a.out, запуститькоторый можно командой:
./a.out
Для примера давайтенапишем маленькую простейшую программку:
#include
int main(){
printf("[http://linux.firststeps.ru]\n");
printf(«Ourfirst program for Linux.\n»);
return 0;
};
2 Компиляциянескольких файлов
Обычно простые программысостоят из одного исходного файла. Дело обстоит несколько сложнее, если этапрограмма становится большой. При работе с такой программой может возникнутьнесколько достаточно серьезных проблем:
Файл, становясь большим,увеличивает время компиляции, и малейшие изменения в исходном текстеавтоматически вынуждают тратить время программиста на перекомпиляцию программы.
Если над программойработает много человек, то практически невозможно отследить сделанныеизменения.
Процесс правки и самоориентирование при большом исходном тексте становится сложным и поиск небольшойошибки может повлечь за собой вынужденное «изучение» кода заново.
Это далеко не всепробемы, которые могут возникнуть при наличии программы «монстра».Поэтому при разработке программ рекомендуется их разбивать на куски, которыефункционально ограничены и закончены. В этом значительно помогает сам язык C++,предоставляя свой богатый синтаксис.
Для того, чтобы вынестифункцию или переменную в отдельный файл надо перед ней поставитьзарезервированное слово extern. Для примера создадим программу из несколькихфайлов. Сначала создадим главную программу, в которой будут две внешниепроцедуры. Назовем этот файл main.c:
#include
// описываем функцию f1()как внешнюю
extern int f1();
// описываем функцию f2()как внешнюю
extern intf2();
int main()
{
int n1, n2;
n1 = f1();
n2 = f2();
printf(«f1()= %d\n»,n1);
printf(«f2()= %d\n»,n2);
return 0;
}
Теперь создаем два файла,каждый из которых будет содержать полное определение внешней функции из главнойпрограммы. Файлы назовем f1.c и f2.c:
// файл f1.c
int f1()
{
return 2;
}
// файл f2.c
int f2()
{
return 10;
}
После этого процесскомпиляции программы с помощью gcc будет выглядеть несколько иначе отописанного в первой главе «Компиляция программ на языке C/C++».
Компилировать можно всефайлы одновременно одной командой, перечисляя составные файлы через пробелпосле ключа -c:
gcc -c main.cf1.c f2.c
Или каждый файл вотдельности:
gcc -c f1.c
gcc -c f2.c
gcc -c main.c
В результате работыкомпилятора мы получим три отдельных объектных файла:
main.o
f1.o
f2.o
Чтобы их собрать в одинфайл с помощью gcc надо использовать ключ -o, при этом линкерсоберет все файлы в один:
gcc main.of1.o f2.o -o rezult
В результате вызоваполученной программы rezult командой:
./rezult
На экране появитсярезультат работы:
olya:~#./rezult
f1() = 2
f2() = 10
olya:~#
Теперь, если мы изменимкакую-то из процедур, например f1():
int f1()
{
return 25;
}
То компилировать занововсе файлы не придется, а понадобится лишь скомпилировать измененный файл исобрать результирующий файл из кусков:
olya:~# gcc -c f1.c
olya:~# gcc main.o f1.o f2.o-o rezult2
olya:~#./rezult2
f1() = 25
f2() = 10
olya:~#
Таким образом можносоздавать большие проекты, которые больше не будут отнимать много времени накомпиляцию и поиск ошибок. Однако нужно помнить, что не стоит также черезчурразбивать программу, иначе у нас получится несколько десятков файлов, вкоторых рано или поздно можно запутаться. Можно найти «золотуюсередину», например в отдельные файлы помещать те функции или классы, скоторыми нам приходится больше всего работать при отладке. После того, какфункция будет окончательно отлажена, ее вполне можно перенести в более крупныйфайл.
3 Создание библиотек объектных файлов
3.1Библиотеки объектных файлов
В прошлом разделекурсовой работы мы создавали объектные файлы. Естественно, если каждая функциябудет содержаться в отдельном файле, то таких файлов может оказаться десяткиили даже сотни. Управлять таким количеством файлов очень сложно. Для этого былпридуман механизм создания библиотек объектных файлов.
Библиотека объектныхфайлов — это файлсодержащий несколько объектных файлов, которые будут использоваться вместе встадии линковки программы. Нормальная библиотека содержит символьный индекс,который состоит из названий функций и переменных и т.д., которые содержатся вбиблиотеке. Это позволяет ускорить процесс линковки программы, так как поискфункций и переменных в объектных файлах библиотеки происходит намного быстрее,чем поиск в наборе указанных объектных файлов. Поэтому использование библиотекипозволяет компактно хранить все требуемые объектные файлы в одном месте, и приэтом значительно повысить скорость компиляции.
Объектные библиотеки поспособу использования разделяются на два вида:
· Статические библиотеки
· Динамические библиотеки
Статическая библиотека — это коллекция объектных файлов,которые присоединяются к программе во время линковки программы. Таким образомстатические библиотеки используются только при созданиии программы. Потом вработе самой программы они не принимают участие, в отличие от динамическихбиблиотек.
Динамическаябиблиотека — этосозданная специальным образом библиотека, которая присоединяется крезультирующей программе в два этапа. Первый этап, это естественно этапкомпиляции. На этом этапе линковщик встраивает в программу описания требуемыхфункций и переменных, которые присутствуют в библиотеке. Сами объектные файлыиз библиотеки не присоединяются к программе. Присоединение этих объектныхфайлов(кодов функций) осуществляет системный динамический загрузчик во времязапуска программы. Загрузчик проверяет все библиотеки прилинкованные спрограмме на наличие требуемых объектных файлов, затем загружает их в память иприсоединяет их в копии запущенной программы, находящейся в памяти.
Сложный процесс загрузкидинамических библиотек замедляет запуск программы, но у него есть существунный,даже можно сказать неоценимый плюс — если другая запускаемая программалинкована с этой же загруженной динамической библиотекой, то она используеттуже копию библиотеки. Это означает, что требуется гораздо меньше памяти для запусканескольких программ, сами загрузочные файлы меньше по размеру, что экономитместо на дисках.
Однако если Вымодифицируете динамическую библиотеку и попытаетесь ее использовать при запускепрограммы, то если загрузчик обнаружит уже загруженную старую библиотеку онбудет упорно использовать ее функции. При этом Вы так и не сможете загрузитьновую версию библиотеки. Но есть пути решения этой проблемы, и их мы рассмотримпозже.
3.2Создание статической библиотеки
Для создания статическихбиблиотек существует специальная простая программа называемая ar (сокр.от archiver — архиватор). Она используется для создания, модификации ипросмотра объектных файлов в статических библиотеках, которые вдействительности представляют из себя простые архивы.
Создадим из файлов f1.cи f2.c отдельную библиотеку.
// файл f1.c
int f1()
{
return 2;
}
// файл f2.c
int f2()
{
return 10;
}
Для начала компилируемэти файлы:
olya:~# gcc -cf1.c f2.c
В результате получим, какобычно, два файла — f1.o и f2.o. Для того, чтобы создатьбиблиотеку из объектых файлов надо вызвать программу ar со следующимипараметрами:
ar rc libимя_библиотеки.a[список_*.o_файлов]
Допустим наша библиотекабудет называться fs, тогда команда запишется в виде:
olya:~# ar rc libfs.a f1.o f2.o
В результате получим файлlibfs.a, в котором будут лежать копии объектых файлов f1.o и f2.o.Если файл библиотеки уже существует, то архиватор будет анализироватьсодержимое архива, он добавит новые объектные файлы и заменит старыеобновленными версиями. Опция c заставляет создавать (от create) библиотеку,если ее нет, а опция r (от replace) заменяет старые объектные файлы новымиверсиями.
Пока у нас есть лишьархивный файл libfs.a. Чтобы из него сделать полноценную библиотекуобъектных файлов надо добавить к этому архиву индекс символов, т.е. списоквложенных в библиотеку функций и переменных, чтобы линковка происходилабыстрее. Далается это командой:
ranlib libимя_библиотеки.a
Программа ranlibдобавит индекс к архиву и получится полноценная статическая библиотекаобъектных файлов. Стоит отметить, что на некоторых системах программа arавтоматически создает индекс, и использование ranlib не имеет никакогоэффекта. Но тут надо быть осторожным при атоматической компиляции библиотеки спомощью файлов makefile, если не использовать утилиту ranlib, товозможно на каких-то системах библиотеки будут создаваться не верно ипотеряется независимость от платформы. Так что возьмем за правило тот факт, чтоутилиту ranlib надо запускать в любом случае, даже если он нее нетникакого эффекта.
Для компиляции нашегоосновного файла main.c надо сообщить компилятору, что надо использоватьбиблиотеки. Чтобы компилятор знал где искать библиотеки ему надо сообщитькаталог, в котором они содержатся и список этих билиотек. Каталог сбиблиотеками указывается ключом -L, в нашем случае библиотека находитсяв текущем каталоге, значит путь до нее будет в виде точки (-L.).Используемые библиотеки перечисляются через ключ -l, после которого указываетсяназвание библиотеки без префикса lib и окончания .a. В нашемслучае этот ключ будет выглядеть, как -lfs. Теперь все одной командой:
olya:~# gcc -c main.c
olya:~# gcc main.o -L.-lfs -o rezult
Или можно чуть короче:
olya:~# gcc main.c -L. -lfs -o rezult
Заметьте, что компиляторунужны библиотеки на этапе создания конечного файла, т.е. линковки. В первомслучае процесс компиляции совершается первой командой, а сборка файла второйкомандой. Если же мы попытаемся подсунуть библиотеку на этапе компиляции, тополучим вежливый ответ:
olya:~# gcc -cmain.c -L. -lfs
gcc: -lfs:linker input file unused since linking not done
Что означает, что файлыбиблиотек не нужны, до процесса линковки. Данная команда создаст лишь файл main.o,который в итоге потом придется собирать отдельно.
3.3 Создание динамической библиотеки
Как мы уже говорилось вкурсовой работе, динамические библиотеки немного лучше статических, но ихиспользование более сложное. И не из-за того, что процесс загрузки программызамедляется. Проблемы начинаются уже на этапе компиляции.
Для начала стоит сказать,что объектный файл создаваемый нашим проверенным способом вовсе не подходит длядинамических библиотек. Связано это с тем, что все объектные файлы создаваемыеобычным образом не имеют представления о том в какие адреса памяти будетзагружена использующая их программа. Несколько различных программ могутиспользовать одну библиотеку, и каждая из них располагается в различномадресном пространстве. Поэтому требуется, чтобы переходы в функциях библиотеки(операции goto на ассемблере) использовали не абсолютную адресацию, аотносительную. То есть генерируемый компилятором код должен быть независимым отадресов, такая технология получила название PIC — Position Independent Code.В компиляторе gcc данная возможность включается ключом -fPIC.
Теперь компилированиенаших файлов будет иметь вид:
olya:~# gcc-fPIC -c f1.c
olya:~# gcc-fPIC -c f2.c
Динамическая библиотекаэто уже не архивный файл, а настоящая загружаемая программа, поэтому созданиемдинамических библиотек занимается сам компилятор gcc. Для того, чтобысоздать динамическую библиотеку надо использовать ключ -shared:
olya:~# gcc-shared -o libfsdyn.so f1.o f2.o
В результате получимдинамическую библиотеку libfsdyn.so, которая по моей задумке будетдинамической версией библиотеки libfs.a, что видно из названия :)Теперь, чтобы компилировать результирующий файл с использованием динамическойбиблиотеки нам надо собрать файл командой:
olya:~# gcc -с main.с
olya:~# gcc main.o -L.-lfsdyn -o rezultdyn
Если теперь Вы сравнитефайлы, полученные при использовании статической и динамической библиотеки, тоувидите, что их размеры отличаются. В данном случае файл созданный сдинамической библиотекой занимает чуть больше места, но это лишь от того, чтопрограмма используемая нами совершенно примитивная и львиную долю там занимаетспециальный код для использования динамических возможностей. В реальныхусловиях, когда используются очень большие функции размер программы сиспользованием динамической библиотеки значительно меньше.
На этом фокусы некончаются, если Вы сейчас попробуете запустить файлrezultdyn, тополучите ошибку:
olya:~#./rezultdyn
./rezultdyn:error in loading shared libraries: libfsdyn.so: cannot open
shared objectfile: No such file or directory
olya:~#
Это сообщение выдаетдинамический линковщик. Он просто не может найти файл нашей динамическойбиблиотеки. Дело в том, что загрузчик ищет файлы динамических библиотек визвестных ему директориях, а наша директория ему не известна. Но это мы чутьотложим, потому что это достаточно сложный вопрос.
А сейчас стоит поговоритьеще об одном моменте использования библиотек. Мы специально динамическуюбиблиотеку с названием fsdyn, чтобы она отличалась от названиястатической библиотеки fs. Дело в том, что если у Вас две библиотекистатическая и динамическая с одинаковыми названиями, то есть libfs.a и libfs.so,то компилятор всегда будет использовать динамическую библиотеку.
Связано это с тем, что включе -l задается часть имени библиотеки, а префикс lib иокончание .a или .so приставляет сам компилятор. Так вот алгоритмработы компилятора таков, что если есть динамическая библиотека, то онаиспользуется по умолчанию. Статическая же библиотека используется когдакомпилятор не может обнаружить файл .so этой библиотеки. Во всей имеющейсяу меня документации пишется, что если использовать ключ -static, томожно насильно заставить компилятор использовать статическую библиотеку.Отлично, попробуем…
olya:~# gcc-staticmain.o -L. -lfs -o rez1
Результирующий файл rez1получается размером в 900 Кб. После применения программы strip размер ееуменьшается до 200 Кб, но это же не сравнить с тем, что наша первая статическаякомпиляция давала программу размером 10 Кб. А связано это с тем, что любаяпрограмма написанная на C/C++ в Linux использует стандартнуюбиблиотеку «C» library, которая содержит в себе определениятаких функций, как printf(), write() и всех остальных. Этабиблиотека линкуется к файлу как динамическая, чтобы все программы написанныена C++ могли использовать единожды загруженные функции. Ну, а приуказании ключа -static компилятор делает линковку libc статической,поэтому размер кода увеличивается на все 200 Кб.
3.4Использование динамических библиотек
В прошлый раз мы с Вамиобнаружили, что запуск программ, скомпилированных вместе с динамическимибиблиотеками, вызывает ошибку:
olya:~#./rezultdyn
./rezultdyn:error in loading shared libraries: libfsdyn.so: cannot open
shared objectfile: No such file or directoryolya:/#
Это сообщение выдаетзагрузчик динамических библиотек(динамический линковщик — dynamic linker),который в нашем случае не может обнаружить библиотеку libfsdyn.so. Длянастройки динамического линковщика существует ряд программ.
Первая программаназывается ldd. Она выдает на экран список динамических библиотекиспользуемых в программе и их местоположение. В качестве параметра ейсообщается название обследуемой программы. Давайте попробуем использовать еедля нашей программы rezultdyn:
olya:~# lddrezultdyn
libfsdyn.so => not found
libc.so.6=> /lib/libc.so.6 (0x40016000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
olya:~#
Как видите все правильно.Программа использует три библиотеки:
libc.so.6 — стандартную библиотеку функцийязыка C++.
ld-linux.so.2 — библиотеку динамической линковкипрограмм ELF формата.
libfsdyn.so — нашу динамическую библиотекуфункций.
Нашу библиотеку она найтине может. И правильно! Динамический линковщик ищет библиотеки только визвестных ему каталогах, а каталог нашей программы ему явно не известен.
Для того, чтобы добавитьнашу директорию с библиотекой в список известных директорий надоподредактировать файл /etc/ld.so.conf. Например, у меня этот файлсостоит из таких строк:
olya:~# cat/etc/ld.so.conf
/usr/X11R6/lib
/usr/i386-slackware-linux/lib
/usr/i386-slackware-linux-gnulibc1/lib
/usr/i386-slackware-linux-gnuaout/lib
olya:~#
Во всех этих директориихранятся всеми используемые библиотеки. В этом списке нет лишь одной директории— /lib, которая сама по себе не нуждается в описании, так как онаявляется главной. Получается, что наша библиотека станет «заметной»,если поместить ее в один их этих каталогов, либо отдельно описать в отдельномкаталоге. Давайте для теста опишем, добавим строку в конец файла ld.so.conf:
/root
У меня этот файлнаходится в домашнем каталога пользователя root, у Вас он может быть в другомместе. Теперь после этого динамический линковщик будет знать где можно найтинаш файл, но после изменения конфигурационного файла ld.so.conf необходимо,чтобы система перечитала настройки заново. Это делает программа ldconfig.Пробуем запустить нашу программу:
olya:~# ldconfig
olya:~# ./rezultdyn
f1() = 25
f2() = 10
olya:~#
Как видите всезаработало. Если теперь удалить добавленную нами строку и снова запустите ldconfig,то данные о расположении нашей библиотеки исчезнут и будет появляться тажесамая ошибка.
Но описанный метод влияетна всю систему в целом и требует доступа администратора системы, т.е. root.А если Вы простой пользователь без сверх возможностей ?!
Для такого случая естьдругое безболезненное решение. Это использование специальной переменной среды LD_LIBRARY_PATH,в которой перечисляются все каталоги содержащие пользовательские динамическиебиблиотеки. Для того, чтобы установить эту переменную в командной среде bashнадо набрать всего несколько команд. Для начала посмотрим есть ли у нас такаяпеременная среды:
olya:~# echo$LD_LIBRARY_PATH
У меня в ответ выводитсяпустая строка, означающая, что такой переменной среды нет. Устанавливается онаследующим образом:
olya:~# LD_LIBRARY_PATH=/root
olya:~# export LD_LIBRARY_PATH
После этого программаrezultdyn будет прекрасно работать. В случае, если в системе эта переменнаясреды уже уставновлена, то, чтобы не испортить ее значение, надо новый каталогприбавить к старому значению. Делается это другойкомандой:
olya:~#LD_LIBRARY_PATH=/root:${LD_LIBRARY_PATH}
olya:~# exportLD_LIBRARY_PATH
Если обнулить этупеременную, то снова библиотека перестанет работать:
olya:~#LD_LIBRARY_PATH=""
olya:~# exportLD_LIBRARY_PATH
olya:~#./rezultdyn
./rezultdyn:error in loading shared libraries: libfsdyn.so: cannot open
shared objectfile: No such file or directory
olya:~#
Также параллельно можнозайти в систему под другим пользователем или даже тем же самым, но если просмотретьзначение LD_LIBRARY_PATH, то увидим ее прежнее значение. Это означает,что два разных пользователя Linux не могут влиять на работу друг друга,а это и есть самое главное хорошее отличие систем Unix от большинствадругих систем.
4 Создание динамических библиотек
4.1Функции работы с динамическими библиотеками
Оказывается, чтоиспользовать динамические библиотеки можно не только в начале загрузки, но и впроцессе самой работы программы. Программа сама может вызывать любые функции избиблиотеки, когда ей захочется. Для этого всего-лишь надо использоватьбиблиотеку dl, которая позволяет линковать библиотеки «налету». Она управляет загрузкой динамических библиотек, вызовом функций изних и выгрузкой после конца работы.
Для использования функцийпрограммной работы с динамическими библиотеками необходимо подключитьзаголовочный файл:
#include
Чтобы вызывать какие-тофункции из динамической библиотеки сначала надо открыть эту библиотеку (можносказать «загрузить»). Открывается она функцией:
void *dlopen(const char *filename, int flag);
Параметр filenameсодержит путь до требуемой библиотеки, а параметр flag задает некоторыеспецифические флаги для работы. Функция возвращает указатель на загруженнуюбиблиотеку. В случае любой ошибки возвращается указатель NULL. В такомслучае тест ошибки понятный человеку можно получить с помощью функции dlerror().Пока мы не будем задумываться над этим, и я приведу стандартный код дляоткрытия библиотеки:
void*library_handler;
//......
//загрузка библиотеки
library_handler= dlopen("/path/to/the/library.so",RTLD_LAZY);
if (!library_handler){
//если ошибка, то вывестиее на экран
fprintf(stderr,«dlopen()error: %s\n», dlerror());
exit(1); // в случаеошибки можно, например, закончить работу программы
};
После этого можноработать с библиотекой. А работа эта заключается в получении адреса требуемойфункции из библиотеки. Получить адрес функции или переменной можно по ее именис помощью функции:
void*dlsym(void *handle, char *symbol);
Для этой функциитребуется адрес загруженной библиотеки handle, полученный при открытии функциейdlopen(). Требуемая функция или переменная задается своим именем в переменнойsymbol.
Закрывается библиотекафункцией:
dlclose(void *handle);
При закрытии библиотекидинамический линковщик проверяет счетчик количества открытий библиотеки, и еслиона была открыта несколькими программами одновременно, то она не выгружается дотех пор, пока все программы не закроют эту библиотеку.
Для примера создадимпрограмму, которая в качестве параметра получает название функции, которую онабудет использовать в работе. Например, это будут математические функциивозведения в степень. Создадим сначала динамическую библиотеку. Пишем ее код:
doublepower2(double x){
return x*x;
};
doublepower3(double x){
return x*x*x;
};
doublepower4(double x){
returnpower2(x)*power2(x);
};
//......
Сохраняем его в файл lib.cи создаем динамическую библиотеку libpowers.so следующими командами:
olya:~# gcc-fPIC -c lib.c
olya:~# gcc-shared lib.o -o libpowers.so
Теперь создаем основнуюпрограмму в файле main.c:
#include
/* заголовочный файл дляработы с динамическими библиотеками */
#include
int main(intargc, char* argv[]){
void*ext_library;// хандлер внешнейбиблиотеки
double value=0;//значение для теста
double(*powerfunc)(double x);// переменная для хранения адреса функции
//загрузка библиотеки
ext_library =dlopen("/root/libpowers.so",RTLD_LAZY);
if (!ext_library){
//если ошибка, то вывестиее на экран
fprintf(stderr,«dlopen()error: %s\n», dlerror());
return 1;
};
//загружаем из библиотекитребуемую процедуру
powerfunc =dlsym(ext_library, argv[1]);
value=3.0;
//выводим результат работы процедуры
printf("%s(%f)= %f\n",argv[1],value,(*powerfunc)(value));
//закрываем библиотеку
dlclose(ext_library);
};
Код главной программыготов. Требуется его откомпилировать с использованием библиотеки dl:
olya:~# gccmain.c -o main -ldl
Получим программный файлmain, который можно тестировать. Наша программа должна возводить значение 3.0 втребуемую нами степень, которая задается названием функции. Давайте попробуем:
olya:~# ./mainpower2
power2(3.000000)= 9.000000
olya:~# ./mainpower3
power3(3.000000)= 27.000000
olya:~# ./mainpower4
power4(3.000000)= 81.000000
olya:~#
Мы используем функции,зная лишь их название. Представьте открывающиеся возможности для программ, наоснове этого метода можно создавать плагины для программ, модернизироватькакие-то части, добавлять новые возможности и многое другое.
4.2 Создание динамической библиотеки для решения системылинейных уравнений
Вкачестве примера использования динамических библиотек напишем программу длярешения системы линейных уравнений.
Пустьсистема имеет вид:
a11*x1+a12*x2=b1;
a21*x1+a22*x2=b2;
Решениеэтой системы находим через обратную матрицу A-1.
A*X=B
X=A-1*B
/>; />; />;
/>;
Программа в качествепараметров принимает значение коефициентов системы и название функции, которуюона использует.
Создадим динамическуюбиблиотеку:
Так как функциявозвращает два результата x1 и x2 в программе будем использоватьструктуру.
«mytype.h»:
struct DPair {
doublefirst;
doublesecond;
};
Struct DPair (*powerfunc)(double,double,double,double,double,double);
«libsysur.c»:
#include«mytype.h»
struct DPairsys2(double a11, double a12,double a21, double a22,double b1, double b2){
//nahodimopredelitel sistemy
structDPair dPair;
doubleopr=a11*a22-a12*a21;
if(opr!=0) {
doubleao11=a22; double ao12=-a21;
doubleao21=-a12; double ao22=a11;
dPair.first=(ao11*b1+ao21*b2)/opr;
dPair.second=(ao12*b1+ao22*b2)/opr;
}
returndPair;
}
Создаем динамическуюбиблиотеку libsysur.so следующими командами:
bash-3.00# gcc-fPIC -c libsysur.c
bash-3.00# gcc-shared libsysur.o -o libsysur.so
Создаем основнуюпрограмму:
«sysur.c»:
#include
#include
#include«mytype.h»
int main(intargc, char* argv[]){
void*ext_library; //хандлервнешней функции
doublea11;double a12; double a21; double a22;
double b1;double b2;
double(*powerfunc)(double a11,double a12, double a21, double a22,double b1, doubleb2);//переменная, для хранения адреса функции
//загрузка библиотеки
ext_library=dlopen("/root/dynamik/libsysur.so",RTLD_LAZY);
if (!ext_library){
//если ошибка,вывести на экран
fprintf(stderr,«dlopen()error: %s\n», dlerror());
return1;
};
//загружаем избиблиотеки требуемую процедуру
powerfunc=dlsym(ext_library, argv[1]); //получаем адрес требуемой функции
//ext_library-адресзагруженной библ.
//argv-требуемая функция или переменная
printf(«Vveditea11 a12 :»);
scanf("%lf%lf",&a11,&a12);
printf(«Vvedite a21 a22 :»);
scanf("%lf %lf",&a21,&a22);
printf(«Vvedite b1, b2 :»);
scanf("%lf %lf",&b1,&b2);
struct DPairsq=(*powerfunc)(a11,a12,a21,a22,b1,b2);
printf(«x1=%lf\n,x2=%d\lf»,sq.first,sq.second);
//выводим результатработы процедуры
//закрываем библиотеку
dlclose(ext_library);
};
Компилируем код главной программы:
bash -3.00# gcc sysur.c -osysur -ldl
Выводы
В курсовой работе былирассмотрены рассмотрены вопросы разработки статических и динамическихбиблиотек на языке программирования С/C++ в операционных системах UNIX.
Использование библиотекипозволяет компактно хранить все требуемые объектные файлы в одном месте, и приэтом значительно повысить скорость компиляции.
Объектные библиотеки поспособу использования разделяются на статические и динамические библиотеки
Статическая библиотека — это коллекция объектных файлов,которые присоединяются к программе во время линковки программы. В работе самойпрограммы статические библиотеки они не принимают участие, в отличие отдинамических библиотек.
В динамическойбиблиотеке объектныефайлы из библиотеки не присоединяются к программе. Присоединение этих объектныхфайлов осуществляет системный динамический загрузчик во время запускапрограммы. Загрузчик проверяет все библиотеки прилинкованные с программе наналичие требуемых объектных файлов, затем загружает их в память и присоединяетих в копии запущенной программы, находящейся в памяти.
Динамические библиотекинемного лучше статических, но их использование более сложное. Так какдинамическая библиотека это уже не архивный файл, а настоящая загружаемаяпрограмма
Список использованийлитературы
1. http://club.shelek.com/
2. http://helpsite.narod.ru/
3. http://myforum.net.ua/index.php?
4. http://ishodniki.ru/
5. Робин Бурк и др. Unixдля системных администраторов.Энциклопедия пользователя. — Киев 1998. — 864с.