Что такое linux dynamic
В прошлый раз мы с Вами обнаружили, что запуск программ, скомпилированных вместе с динамическими библиотеками, вызывает ошибку:
Это сообщение выдает загрузчик динамических библиотек(динамический линковщик — dynamic linker), который в нашем случае не может обнаружить библиотеку libfsdyn.so. Для настройки динамического линковщика существует ряд программ.
Первая программа называется ldd. Она выдает на экран список динамических библиотек используемых в программе и их местоположение. В качестве параметра ей сообщается название обследуемой программы. Давайте попробуем использовать ее для нашей программы rezultdyn:
Как видите все правильно. Программа использует три библиотеки:
- libc.so.6 — стандартную библиотеку функций языка C++.
- ld-linux.so.2 — библиотеку динамической линковки программ ELF формата.
- libfsdyn.so — нашу динамическую библиотеку функций.
Нашу библиотеку она найти не может. И правильно! Динамический линковщик ищет библиотеки только в известных ему каталогах, а каталог нашей программы ему явно не известен.
Для того, чтобы добавить нашу директорию с библиотекой в список известных директорий надо подредактировать файл /etc/ld.so.conf. Например, у меня этот файл состоит из таких строк:
Во всех этих директории хранятся всеми используемые библиотеки. В этом списке нет лишь одной директории — /lib, которая сама по себе не нуждается в описании, так как она является главной. Получается, что наша библиотека станет «заметной», если поместить ее в один их этих каталогов, либо отдельно описать в отдельном каталоге. Давайте для теста опишем, добавим строку в конец файла ld.so.conf:
У меня этот файл валяется в домашнем каталога пользователя root, у Вас он может быть в другом месте. Теперь после этого динамический линковщик будет знать где можно найти наш файл, но после изменения конфигурационного файла ld.so.conf необходимо, чтобы система перечитала настройки заново. Это делает программа ldconfig. Пробуем запустить нашу программу:
Как видите все заработало 🙂 Если теперь Вы удалите добавленную нами строку и снова запустите ldconfig, то данные о расположении нашей библиотеки исчезнут и будет появляться таже самая ошибка.
Но описанный метод влияет на всю систему в целом и требует доступа администратора системы, т.е. root. А если Вы простой пользователь без сверх возможностей ?!
Для такого случая есть другое безболезненное решение. Это использование специальной переменной среды LD_LIBRARY_PATH, в которой перечисляются все каталоги содержащие пользовательские динамические библиотеки. Для того, чтобы установить эту переменную в командной среде bash надо набрать всего несколько команд. Для начала посмотрим есть ли у нас такая переменная среды:
У меня в ответ выводится пустая строка, означающая, что такой переменной среды нет. Устанавливается она следующим образом:
После этого программа rezultdyn будет прекрасно работать. В случае, если у Вас в системе эта переменная среды уже уставновлена, то, чтобы не испортить ее значение, надо новый каталог прибавить к старому значению. Делается это другой командой:
Если Вы обнулите эту переменную, то снова библиотека перестанет работать:
Вы также параллельно можете зайти в систему под другим пользователем или даже тем же самым, но если Вы захотите просмотреть значение LD_LIBRARY_PATH, то увидите ее прежнее значение. Это означает, что два разных пользователя Linux не могут влиять на работу друг друга, а это и есть самое главное хорошее отличие систем Unix от большинства других систем.
Источник
Dynamic в C#: рецепты использования
Это заключительная часть цикла про Dynamic Language Runtime. Предыдущие статьи:
- Подробно о dynamic: подковерные игры компилятора, утечка памяти, нюансы производительности. В этой статье подробно рассматривается кэш DLR и важные для разработчика моменты, с ним связанные.
- Грокаем DLR. Общий обзор технологии, препарирование DynamicMetaObject и небольшая инструкция о том, как создать собственный динамический класс.
В этой небольшой заметке мы наконец разберем основные случаи использования dynamic в реальной жизни: когда без него не обойтись и когда он может существенно облегчить существование.
Когда без dynamic не обойтись
Таких случаев нет. Всегда можно написать аналогичный по функционалу код в статическом стиле, разница лишь в удобстве чтения и объеме кода. Например, при работе с COM-объектами вместо dynamic можно использовать рефлексию.
Когда dynamic полезен
Работа с COM-объектами
В первую очередь это, конечно же, работа с COM-объектами, ради которой всё это и затевалось. Сравните код, получившийся при помощи dynamic и при помощи рефлексии:
Как правило, для работы с COM-объектами через рефлексию приходится создавать развесистые классы с обертками под каждый метод/свойство. Есть и менее очевидные плюшки типа возможности не заполнять ненужные вам параметры (обязательные с точки зрения COM-объекта) при вызове метода через dynamic.
Работа с конфигами
Ещё один хрестоматийный пример — работа с конфигами, например с XML. Без dynamic:
Разумеется, для этого нужно реализовать свой динамический класс. В качестве альтернативы первому листингу можно написать класс, который будет работать примерно так:
Но, согласитесь, это выглядит гораздо менее изящно, чем через dynamic.
Работа с внешними ресурсами
Предыдущий пункт можно обобщить на любые действия с внешними ресурсами. У нас всегда есть две альтернативы: использование dynamic для получения кода в нативном C# стиле либо статическая типизация с «магическими строками». Давайте рассмотрим пример с REST API запросом. С dynamic можно написать так:
Где наш динамический класс по запросу свойства отправит запрос вида
Затем десериализует его и вернем нам уже готовый к целевому использованию массив кошек. Без dynamic это будет выглядеть примерно так:
Замена рефлексии
В предыдущем примере у вас мог возникнуть вопрос: почему в одном случае мы десериализуем возвращаемое значение к конкретному типу, а в другом — нет? Дело в том, что в статической типизации нам нужно явно привести объекты к типу Cat для работы с ними. В случае же dynamic, достаточно десериализовать JSON в массив объектов внутри нашего динамического класса и вернуть из него object[], поскольку dynamic берёт на себя работу с рефлексией. Приведу два примера того, как это работает:
Тот же самый принцип, что и при работе с COM-объектами.
Visitor
С помощью dynamic можно очень элегантно реализовать этот паттерн. Вместо тысячи слов:
Теперь при передаче объекта типа Sword в метод DoSomeWork будет вызван метод InternalDoSomeWork(Sword item).
Выводы
Плюсы использования dynamic:
- Можно использовать для быстрого прототипирования: в большинстве случаев уменьшается количество бойлерплейт кода
- Как правило улучшает читаемость и эстетичность (за счет перехода от «магических строк» к нативному стилю языка) кода
- Несмотря на распространенное мнение, благодаря механизмам кэширования существенного оверхеда по производительности в общем случае не возникает
Минусы использования dynamic:
- Есть неочевидные нюансы, связанные с памятью и производительностью
- При поддержке и чтении таких динамических классов нужно хорошо понимать, что вообще происходит
- Программист лишается проверки типов и всех гарантий работоспособности, предоставляемых компилятором
Заключение
На мой взгляд, наибольший профит от использования dynamic разработчик получит в следующих ситуациях:
- При прототипировании
- В небольших/домашних проектах, где цена ошибки невысока
- В небольших по объему кода утилитах, не подразумевающих длительное время работы. Если ваша утилита исполняется в худшем случае несколько секунд, задумываться об утечках памяти и снижении производительности обычно нет нужды
Как минимум спорным выглядит использование dynamic в сложных проектах с объемной базой кода, — здесь лучше потратить время на написание статических оберток, сведя таким образом количество неочевидных моментов к минимуму.
Если вы работаете с COM-объектами или доменами в сервисах/продуктах, подразумевающих длительное непрерывное время работы — лучше dynamic не использовать, несмотря на то, что именно для таких случаев он и создавался. Даже если вы досконально знаете что и как делать и никогда не допускаете ошибок, рано или поздно может прийти новый разработчик, который этого не знает. Итогом, скорее всего, будет трудновычислимая утечка памяти.
Источник
Блог радиста
Блог о Linux в частности и Open Source в общем, о программировании и немного о M$ Windows
Статические и динамические библиотеки в Linux
Статические и динамические библиотеки в Linux
Сегодня мы поговорим о библиотеках в Linux (подозреваю также, что многие описанные здесь вещи возможны и в других *nix-операционных системах, но это требует проверки 🙂 ).
1) Статические библиотеки (создание с помощью Assembler, C/C++; подключение и использование в программах на Assembler,C/C++);
2) Динамические библиотеки (создание с помощью Assembler, C/C++; подключение и использование в программах на C/C++l, Python).
1) Статическая библиотека — это такая библиотека, которая связывается (линкуется) с программой в момент компиляции оной. При этом объектный код библиотеки помещается в исполняемый файл программы. С этой точки зрения статическая библиотека похожа на исходный код программы, с которой она связывается, за исключением того, что библиотека компилируется «кем-то еще» и программист, использующий библиотеку, имеет дело исключительно только с результатом этой компиляции.
В Linux, как правило, файл-статическая_библиотека имеет расширение «.a»
2) Статические библиотеки на языке C.
Исходный код библиотеки:
Сохраните его в файле static.c
Ключевое слово extern необходимо для того, чтобы функция была видна в программе.
Теперь скомпилируем (! без линковки) библиотеку:
gcc -c static.c -o static.o
(на выходе имеем файл static.o, содержащий объектный код нашей библиотеки)
ar rc libMY_STATIC.a static.o
ar упаковывает несколько (! Это важно. Дело не ограничивается только одним объектным файлом) объектных файлов в одну статическую библиотеку. Статическая библиотека имеет расширение «.a», при этом ее название должно начинаться с «lib» (дань традиции).
Параметры ar:
r — предписывает заменять старые версии объектных файлов новыми — необходим для переупаковки библиотеки;
c — создать статическую библиотеку, если та еще не существует.
Проиндексируем функции внутри библиотеки для более быстрой линковки:
Итак, мы получили статическую библиотеку libMY_STATIC.a.
Теперь попытаемся использовать библиотеку в нашей программе:
Исходный текст программы (C):
Сохраните его в файле program1.c
Способы связывания библиотеки и программы:
— Скомпилируем и слинкуем (в том числе с нашей библиотекой) нашу программу:
gcc program1.c libMY_STATIC.a
(предполагается, что в качестве аргумента gcc будут переданы полные пути (!) к вашим библиотекам)
На выходе получим:
Hello world! I’m static library
Return code: 0
— Скомпилируйте с помощью команды:
gcc program1.c -L. -lMY_STATIC -o a1.out
— путь к каталогу, содержащему наши библиотек (используйте «-L
— название нашей библиотеки (это важно — название (!), а не имя файла — собственно, если библиотека имеет своим именем «libBLABLABLA.a», то ее названием будет «BLABLABLA» — т.е. имя без приставки «lib» и расширения «.a») (для нескольких библиотек используйте «-l -l . «)
Запустите файл a1.out на выполнение и удостовертесь, что результаты те же, что и в предыдущем пункте.
— Видоизменим предыдущий способ — уберем аргументы «-L»:
В начале проверим значение переменной LD_LIBRARY_PATH и содержимое файла /etc/ld.so.conf:
echo $LD_LIBRARY_PATH ; cat /etc/ld.so.conf
На экране появился некоторый список каталогов — это те каталоги, в которых система ищет библиотеки при их линковке с программой (еще к таким каталогам относятся:
/lib
/usr/lib
. Поместите libMY_STATIC.a в один из этих каталогов:
(Я, к примеру, засуну нашу библиотеку в каталог /usr/lib):
su -c ‘cp libMY_STATIC.a /usr/lib’
(в Ubuntu — sudo cp libMY_STATIC.a /usr/lib )
ldconfig
(ldconfig обновляет кеш данных о библиотеках линковщика)
Теперь скомпилируем и запустим нашу программу:
gcc program1.c -lMY_STATIC -o a2.out
./a2.out
Hello world! I’m static library
Return code: 0
Бинго! Кстати, таким вот способом вы можете подключать к своей программе любые статические библиотеки из приведенных выше каталогов.
* Бывает полезно определить все прототипы функций библиотеки в некотором заголовочном файле, который будет потом включаться в вашу программу. Это не обязательно, но удобно.
3) Статические библиотеки на языке Assembler.
Представьте, что вам необходимо оптимизировать выполнение некоторых действий в вашей программе. Разумеется, вы может применить ключевое слово asm (если пишите программу на C/C++), но лучшим решением будет создание оптимизированной вами библиотеки на языке Assembler и подключение ее к вашей программе. Давайте попробуем:
*Кстати, углубляться в процесс компиляции библиотеки и ее линковки с вашей программой я не буду (!). Этот процесс идентичен полностью (!) тому же процессу для библиотек, написанных на языке C.
Итак, имеем вот такую программу:
Сохраните ее в файле program2.c
Скомпилируйте ее и запустите:
Я привел этот пример, чтобы показать действительно возможность оптимизации программы с помощью библиотеки на Assembler’е. Вы можете заметить, что вызов printf в main() не оптимален, т.к. printf, по крайней мере, один раз использует цикл while для поиска вхождений конструкций «%. » в строку. Это не оптимально, т.к. очевидно, что таковых символов у нас нет. Оптимизируем нашу программу с помощью библиотеки на Assebmler’е:
my_printf:
movl $4,%eax
xorl %ebx,%ebx
incl %ebx
movl $hw,%ecx
movl $hw_e,%edx
int $0x80
xorl %eax,%eax
ret
Сохраните исходный код библиотеки в файле static2.s
Это AT&T наречие Assembler’а.
.globl my_printf — «my_printf» описывается как глобальная (видимая в других объектных файлах) последовательность
my_printf: — начало описание функции my_printf
movl $4,%eax — поместим 4 в eax (4 — номер системного вызова write)
xorl %ebx,%ebx и incl %ebx — поместим в ebx единицу — номер STDOUT
movl $message,%ecx — в ecx запишем адрес начала сообщения
movl $message_l,%edx — в edx поместим адрес конца сообщения
int $0x80 — произведем системный вызов write
xorl %eax,%eax — в eax — код возврата (0)
ret — вернемся в вызывающую процедуру
.data — секция данных (разумеется, мы могли бы передавать выводимую строку как параметр, но тогда вычисление ее конца потребовало бы от нас дополнительных усилий, что, согласитесь, лениво 🙂 )
Теперь получим библиотеку:
gcc -c static2.s -o static2.o
ar rc static2.a static2.o
ranlib static2.a
На выходе имеем статическую библиотеку static2.a
Теперь напишем программу, использующую эту статическую библиотеку (язык C):
Сохраните текст программы в файле program3.c
Заметьте, я добавил прототип библиотечной функции для удобства.
Скомпилируем и слинкуем программу с библиотекой, после чего запустим программу на выполнение:
gcc program3.c static2.a
./a.out
На выходе получим:
* Принцип линкования статических библиотек с программами на Assembler’е аналогичен принципу для программ на C. Просто, когда будете использовать статические библиотеки в Assembler’е, помните о соглашениях C по передаче аргументов в функцию и возвращению результата.
4) Статические библиотеки на языке C++.
Принцип создания аналогичен статическим библиотекам на C, но перед каждой экспортируемой функцией не забывайте добавлять:
(экспортировать как функцию на C — т.е. без расширения имен).
* Кстати, используйте g++ вместо gcc, если захотите протестировать приведенные выше примеры.
Подключение к вашей программе аналогично подключению к программе, написанной на C, за исключением необходимости явно добавлять к тексту программы прототипы импортируемых функций в следующем виде:
extern «C» PROTOTYPE
Где PROTOTYPE — прототип импортируемой функции.
* При подключении статических библиотек на C++ к программе на C сопряжено с некоторыми трудностями — т.к. при компиляции и линковки программы необходимо будет также вручную подключить системные библиотеки для реализации функционала, предоставляемого библиотекой Standart C++ сверх того, что предоставляет библиотека Standart C.
Динамические библиотеки (shared).
1) Динамическая библиотека — библиотека, подключаемая к программе в момент выполнения. Это означает, что при создании библиотеки производится не только ее компиляция, но и линковка с другими, нужными ей, библиотеками (!).
Динамические библиотеки полезны в случаях, если:
— Важно не перекомпилировать всю программу, а только перекомпилировать ту часть, которая реализует определенные функции — тогда эти функции выносятся в динамическую библиотеку;
— Важно использовать в программах на C библиотеки, подготовленные на C++ и при этом избежать лишних трудностей с линковкой программы;
— Кроме того, динамические библиотеки позволяют экономить место на жестком диске и в оперативной памяти, если одна и таже библиотека используется несколькими программами.
В Linux, обычно, динамические библиотеки имеют расширение «.so».
2) Подготовим исходный код динамической библиотеки (пример на C++).
Исходный код динамической библиотеки по принципам создания ничем (!) не отличается от исходного кода статических библиотек.
Здесь мы подготовим некоторый пример, который в дальнейшем будем использовать повсеместно во всей части 2.
Итак, исходный код библиотеки (C++):
extern «C» int hello()
<
cout 3) Компиляция и линковка динамических библиотек.
Давайте получим динамическую библиотеку:
Получим файл с объектным кодом:
g++ -fPIC -c dynamic.cpp -o dynamic.o
(используйте gcc для программ на С и Assembler’е)
-fPIC — использовать относительную адресацию в переходах подпрограмм — во избежание конфликтов при динамическом связывании
А теперь из объектного файла получим библиотеку:
g++ -shared -olibdynamic.so dynamic.o
(используйте gcc для программ на С и Assembler’е)
libdynamic.so — имя результирующей библиотеки;
-shared — предписывает создать динамическую (т.е. «разделяемую») библиотеку.
* Именуйте динамические библиотеки следующим способом:
Итак, на выходе мы имеем libdynamic.so — нашу динамическую библиотеку.
4) Использование динамической библиотеки в программе на C/C++.
— Связывание с библиотекой во время компиляции программы (C/C++):
—— Подготовим исходный код нашей программы:
Сохраните его в файле Dprogram1.c
extern «C» int hello();
Сохраните его в файле Dprogram1.cpp
(единственное отличие, как вы можете заметить, в ключевом слове extern — см. часть 1 пункт 4)
—— Теперь добьемся того, чтобы система смогла найти нашу библиотеку. Поместим libdynamic.so в один из каталогов:
cat /etc/ld.so.conf
и выполните потом » ldconfig «
—— И, наконец, скомпилируем программу и слинкуем ее с библиотекой:
gcc ИСХОДНИК -lИМЯ_БИБЛИОТЕКИ -o РЕЗУЛЬТИРУЮЩИЙ_БИНАРИК
В нашем случае: gcc Dprogram1.c -L/home/amv/c/libs/ -ldynamic
(используйте g++ для программы на C++)
Запустим на исполнение полученный файл:
В итоге должно получится:
— Связывание с библиотекой во время исполнения программы (C/C++):
Разумеется, предыдущий пример неплох. Однако бывает необходимо подключать библиотеку во время выполнения программы. Для этого можно использовать функционал из заголовочного файла .
Исходный код примера (C):
int main()
<
void *handle = dlopen(«libdynamic.so»,RTLD_LAZY);
int(*fun)(void) = dlsym(handle,»hello»);
int x = (*fun)();
dlclose(handle);
printf(«Return code: %d\n»,x);
return 0;
>;
######################
Сохраните его в файле Dprogram2.c
В dlfcn.h определены следующие функции:
void* dlopen(«PATH_AND_NAME»,FLAG) — загружает в память динамическую библиотеку с полным именем PATH_AND_NAME и возвращает ее описатель (HANDLE) (NULL в случае неудачи). FLAG — флаги, описанные в «man dlopen»;
void* dlsym(HANDLE,»NAME») — возвращает указатель на функцию/переменную, импортируемую из библиотеки;
int dlclose(HANDLE) — выгружает библиотеку из памяти;
const char *dlerror() — получить сообщение о последней возникшей ошибке (NULL — если ошибок не произошло с момента последнего вызова dlerror).
* Посмотрите на досуге вот этот перевод «man dlopen»: Привет, OpenNET
gcc -ldl Dprogram2.c
(используйте g++ для программы на C++)
Запустим на исполнение полученный файл:
В итоге должно получится:
* Важно! Нет необходимости помещать библиотеку в один из специальных каталогов, модифицировать переменные окружения и выполнять «ldconfig»
— Использование динамической библиотеки в программе на Python:
Все предельно просто.
—— Поместим libdynamic.so в один из каталогов:
cat /etc/ld.so.conf
и выполните потом «ldconfig»
Исходный текст программы на python’е:
Модуль ctypes входит в стандартную поставку модулей python версии 2.5 и выше.
Фуф. Мы проделали довольно большую работу, но ведь это только верхушка айсберга.
Источник