Показаны сообщения с ярлыком python. Показать все сообщения
Показаны сообщения с ярлыком python. Показать все сообщения

Fuse и Python

1. Вводная

Fuse - это проект, предоставляющий программисту функционал для написания драйвера для произвольной файловой системы. Fuse (в Linux) включает в себя модуль ядра, используемый различными программами для связи с драйвером ФС (который является, по существу, исполняемым файлом).

Стратегия разработки драйвера проста - необходимо реализовать некоторый набор функций с определенными прототипами, указатели на которых передать модулю ядра (с помощью вызова некоторой функции - т.н. fuse_main) - после чего при обращении к ФС будут вызываться именно те функции из драйвера, указатели на которые были переданы в fuse_main. Нетрудно догадаться, что диапазон применения fuse очень и очень широк - с ее помощью можно разработать самые "неожиданные" ФС :-)

Плюсы fuse:
  • Код драйвера ФС выполняется в user-space - сразу исчезают многие проблемы, возникающие при отладке модуля ядра

  • У fuse есть много "привязок" к разным ЯП (кроме C, это еще и Python, например)

  • Простые принципы разработки драйверов (простое API)

  • Стабильность, надежность и защищенность



Подробности разработки драйверов ФС на C/C++ для fuse можно узнать в статье: "Разработка собственной файловой системы с помощью FUSE" (ibm.com Россия).

Однако в этой статье я расскажу, как написать драйвер, используя python.

2. Установка "привязок" к fuse для python

Все просто. Для начала получим исходный код "привязок":

Проследуйте на страницу FUSEWiki - FusePython и выберите понравившийся вам способ загрузки.

Я использовал Mercurial:

hg clone http://mercurial.creo.hu/repos/fuse-python-hg

После загрузки перейдите в каталог с исходниками fuse-python и сделайте:

python setup.py build
su -c 'python setup.py install'


Вы получите модуль fuse, в котором содержаться вся необходимые классы.

3. Небольшой пример

Давайте напишем драйвер для "игрушечной" виртуальной ФС.

В начале - каркас драйвера:
  1. Первым делом мы импортируем нужные модули:

    import os,stat
    import fuse

  2. Теперь необходимо сообщить fuse-python какую ее версию мы используем:

    fuse.fuse_python_api = (0, 2)

  3. Описываем базовый для нашего драйвера класс (он будет наследовать класс fuse.Fuse):

    class simpleFS(fuse.Fuse):
      #функции
      #TODO

  4. Описываем функцию, которая будет "запускать" наш драйвер:

    def runSimpleFS():
      usage='Simple FS ' + fuse.Fuse.fusage
      fs = simpleFS(version="%prog " + fuse.__version__,usage=usage,dash_s_do='setsingle')
      fs.parse(errex=1)
      fs.main()


    Как вы могли заметить, принципиально важными являются вызов конструктора fuse.Fuse (с правильным списком аргументов), вызов fs.parse() и вызов fs.main(). fs.main() это и есть как раз та самая fuse_main. Указатели на функцию в fuse-python подменяются функциями-членами_класса fuse.Fuse.

    Важное замечание: после вызова fs.main() драйверу перестает быть доступной консоль, из которой, собственно, драйвер и был запущен. В частности, теряется связь с STDIN, STDOUT, STDERR - т.е. мы сможем догадаться об исключенях только по результатам работы драйвера.

  5. Вызываем runSimpleFS():

    runSimpleFS()


Каркас готов.

Теперь давайте определимся с тем, что будет представлять из себя наша ФС:
  1. 2 каталога - '/' и '/simple' - оба с правами 0555 и root.root в качестве пользователя.группы_пользователя

  2. 1 файл - '/README' (0444 root.root)


Реализация нашего класса:

  1. Конструктор. В нем принципиально важно вызвать конструктор базового класса со всеми переданными в конструктор simpleFS аргументами (а self.README - содержимое файла '/README'):

    def __init__(self, *args, **kw):
      fuse.Fuse.__init__(self, *args, **kw)
      self.README = 'This is simple FS\n'

  2. Пользовательские действия с ФС (системные вызовы и прочее). На каждой такой функции в fuse.Fuse стоит "заглушка". Нам остается только переопределить нужные нам функции:


    # getattr вызывается при получении информации об объекте ФС. Например, при использовании команды ls

    def getattr(self, path):
      # В объекте fuse.Stat() вернем интересующую информацию
      st = fuse.Stat()
      # "Режим" - права доступа, тип объекта
      st.st_mode = 0
      # Номер inode
      st.st_ino = 0
      st.st_dev = 0
      # Количество ссылок на объект
      st.st_nlink = 0
      # ID владельца объекта
      st.st_uid = 0
      # ID группы владельца объекта
      st.st_gid = 0
      # Размер объекта
      st.st_size = 0
      # Временные штампы
      st.st_atime = 0
      st.st_mtime = 0
      st.st_ctime = 0
      if path == '/' or path == '/simple':
        # Каталоги
        st.st_mode = stat.S_IFDIR | 0755
        st.st_nlink = 3
      elif path == '/README':
        # Файлы
        st.st_mode = stat.S_IFREG | 0444
        st.st_nlink = 1
        st.st_size = len(self.README)
      else:
        # path не существует
        return -errno.ENOENT
      return st

    # readdir вызывается при попытке просмотра содержимого каталога. Например, при использовании ls

    def readdir(self, path, offset):
      # В каждом каталоге есть '.' и '..'
      yield fuse.Direntry('.')
      yield fuse.Direntry('..')
      if path == '/':
        # Кроме того, в '/' есть еще и 'README' и 'simple'
        yield fuse.Direntry('README')
        yield fuse.Direntry('simple')

    # open вызывается при попытки открыть файл. Мы должны проверить флаги доступа - наш единственный файл '/README' доступен только на чтение

    def open(self, path, flags):
      if path != '/README':
        return -errno.ENOENT
      accmode = os.O_RDONLY | os.O_WRONLY | os.O_RDWR
      if (flags & accmode) != os.O_RDONLY:
        # Ошибка доступа
        return -errno.EACCES

    # read вызывается при попытки прочитать данные из файла
    # offset - смещение в читаемом файле
    # size - размер считываемого ("запрощенного") блока
    # read возвращает считанные символы

    def read(self, path, size, offset):
      if path != '/README':
        return -errno.ENOENT
      slen = len(self.README)
      if offset < slen:
        if offset + size > slen:
          size = slen - offset
        buf = self.README[offset:offset+size]
      else:
        buf = ''
      return buf

    # statfs вызывается в ответ на запрос информации о ФС

    def statfs(self):
      # Вернем информацию в объекте класса fuse.StatVfs
      st = fuse.StatVfs()
      # Размер блока
      st.f_bsize = 1024
      st.f_frsize = 1024
      st.f_bfree = 0
      st.f_bavail = 0
      # Количество файлов
      st.f_files = 2
      # Количество блоков
      # Если f_blocks == 0, то 'df' не включит ФС в свой список - понадобится сделать 'df -a'
      st.f_blocks = 4
      st.f_ffree = 0
      st.f_favail = 0
      st.f_namelen = 255
      return st


Вот и все. Драйвер готов (исходный код драйвера лежит здесь).

Проверка:

mkdir smpfs
python simplefs.py smpfs
ls -la smpfs/
ls -la smpfs/simple
cat smpfs/README
df
su -c 'umount smpfs'


Заметьте, что первым параметром в скрипт передается точка монтирования (каталог 'smpfs' в нашем случае).

В случае, если этого примера вам показалось мало - посмотрите в каталог 'example' дистрибутива fuse-python. Там есть кое-что интересное.

4. Почитать



5. BashOrgFS

Здесь лежит моя поделка на заданную тему. bash.org.ru представлен в виде файловой системы.

Монтировать так:

./bashorg ТОЧКА_МОНТИРОВАНИЯ.

Заранее - это просто пример. Используйте на свой страх и риск. Предварительно читайте README ;-)

6. За сим все. Успехов!

Мелочи

random_watching.py, о котором я писал здесь, мною был сегодня обновлен. Пофиксены два мелких бага.

Написал небольшую программку - позволяет просмотреть все видеофайлы в указанной дирректории с помощью xine. Изюминка в том, что программа обрабатывает также некоторый oldlist - файлы, которые прописаны в oldlist, исключаются из списка воспроизведения.

-----------------------------------------------------------------------

Вышел ATI Catalyst 8.7. Уже скачал и сейчас буду тестировать. Очень надеюсь на исправленные баги с lock/unlock'ами экрана и завершении сессии.

random_watching.py

Написал небольшую программку - позволяет просмотреть все видеофайлы в указанной дирректории с помощью xine. Изюминка в том, что программа обрабатывает также некоторый oldlist - файлы, которые прописаны в oldlist, исключаются из списка воспроизведения.

Скачивать здесь (кстати, Яndex.Диск рулит).

Зависимости: Python, libmagic (сделайте обязательно симлинк по имени libmagic.so)

Мелочи для python

import os

os.path.abspath(filename)      -    Получить абсолютный путь для filename

os.path.exists(filename)     -    Проверить, существует ли файл с именем filename

Определяем тип файла в Python

Работаем с помощью magic-последовательностей. Определение происходит с помощью libmagic.so (библиотека для C, заголовочный файл - magic.h, почитайте также "man libmagic"). Используем библиотеку с помощью ctypes.cdll.

Вот такой вот класс:


import ctypes

class CMagic:
   __mgc = None
   __cookie = None

   def __init__(self):
     #Загружаем libmagic.so
     self.__mgc = ctypes.cdll.LoadLibrary("libmagic.so")
     #Создаем новый cookie (требуется для
     #работы с magic-последовательностями)
     #0x10 | 0x400 = MAGIC_MIME (константа
     #декларируется в magic.h)
     self.__cookie = self.__mgc.magic_open(0x10 | 0x400)
     #Загружаем в __cookie
     #/etc/file/magic.mime (т.к. указано None)
     self.__mgc.magic_load(self.__cookie, None)

   def __del__(self):
     #Закрываем __cookie
     self.__mgc.magic_close(self.__cookie)

   def getMType(self,filename):
     #Получаем информацию о файле
     result = self.__mgc.magic_file(self.__cookie,filename)
     #magic_file возвращает const char*,
     #mimetype.value - это строка по указателю
     mimetype = ctypes.c_char_p(result)
     rez = mimetype.value
     return rez

   def is_video(self,filename):
     #Проверяем, является ли файл
     #- видео файлом
     mime = self.getMType(filename)
     if mime.count("video"):
       return 1
     return 0

Статические и динамические библиотеки в Linux

Статические и динамические библиотеки в Linux


Здравствуйте.

Сегодня мы поговорим о библиотеках в Linux (подозреваю также, что многие описанные здесь вещи возможны и в других *nix-операционных системах, но это требует проверки :-) ).

Мы рассмотрим:

1) Статические библиотеки (создание с помощью Assembler, C/C++; подключение и использование в программах на Assembler,C/C++);
2) Динамические библиотеки (создание с помощью Assembler, C/C++; подключение и использование в программах на C/C++l, Python).

----------------------------------------------------------------------------------------------------------------

Часть 1.

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

1) Статическая библиотека - это такая библиотека, которая связывается (линкуется) с программой в момент компиляции оной. При этом объектный код библиотеки помещается в исполняемый файл программы. С этой точки зрения статическая библиотека похожа на исходный код программы, с которой она связывается, за исключением того, что библиотека компилируется "кем-то еще" и программист, использующий библиотеку, имеет дело исключительно только с результатом этой компиляции.

В Linux, как правило, файл-статическая_библиотека имеет расширение ".a"

2) Статические библиотеки на языке C.

Исходный код библиотеки:

######################
#include <stdio.h>

extern int hello()
{
printf("Hello world! I'm static library\n");
return 0;
};

######################

Сохраните его в файле 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 - создать статическую библиотеку, если та еще не существует.

Проиндексируем функции внутри библиотеки для более быстрой линковки:

ranlib libMY_STATIC.a

Итак, мы получили статическую библиотеку libMY_STATIC.a.

Теперь попытаемся использовать библиотеку в нашей программе:

Исходный текст программы (C):

######################
#include <stdio.h>

int main()
{
int x = hello();
printf("Return code: %d\n",x);
return 0;
}

######################

Сохраните его в файле program1.c

Способы связывания библиотеки и программы:

- Скомпилируем и слинкуем (в том числе с нашей библиотекой) нашу программу:

gcc program1.c libMY_STATIC.a

(предполагается, что в качестве аргумента gcc будут переданы полные пути (!) к вашим библиотекам)

И запустим:

./a.out

На выходе получим:

Hello world! I'm static library
Return code: 0


Отлично!

- Скомпилируйте с помощью команды:

gcc program1.c -L. -lMY_STATIC -o a1.out

Смысл аргументов:

-L - путь к каталогу, содержащему наши библиотек (используйте "-L -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.

Итак, имеем вот такую программу:

######################
#include <stdio.h>

int main()
{
printf("Hello world!\n");
return 0;
};

######################

Сохраните ее в файле program2.c

Скомпилируйте ее и запустите:

gcc program2.c
./a.out


Я получил:

Hello world!


Отлично.

Я привел этот пример, чтобы показать действительно возможность оптимизации программы с помощью библиотеки на Assembler'е. Вы можете заметить, что вызов printf в main() не оптимален, т.к. printf, по крайней мере, один раз использует цикл while для поиска вхождений конструкций "%..." в строку. Это не оптимально, т.к. очевидно, что таковых символов у нас нет. Оптимизируем нашу программу с помощью библиотеки на Assebmler'е:

######################
.text
.globl my_printf

my_printf:
movl $4,%eax
xorl %ebx,%ebx
incl %ebx
movl $hw,%ecx
movl $hw_e,%edx
int $0x80
xorl %eax,%eax
ret

.data
hw:
.string "Hello world!\012"
hw_e = . - hw

######################

Сохраните исходный код библиотеки в файле 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):

######################
#include <stdio.h>

int my_printf();

int main()
{
int x = my_printf();
return 0;
}

######################

Сохраните текст программы в файле program3.c

Заметьте, я добавил прототип библиотечной функции для удобства.

Скомпилируем и слинкуем программу с библиотекой, после чего запустим программу на выполнение:

gcc program3.c static2.a
./a.out


На выходе получим:

Hello world!


* Принцип линкования статических библиотек с программами на Assembler'е аналогичен принципу для программ на C. Просто, когда будете использовать статические библиотеки в Assembler'е, помните о соглашениях C по передаче аргументов в функцию и возвращению результата.

4) Статические библиотеки на языке C++.

Принцип создания аналогичен статическим библиотекам на C, но перед каждой экспортируемой функцией не забывайте добавлять:

extern "C"

(экспортировать как функцию на C - т.е. без расширения имен).

* Кстати, используйте g++ вместо gcc, если захотите протестировать приведенные выше примеры.

Подключение к вашей программе аналогично подключению к программе, написанной на C, за исключением необходимости явно добавлять к тексту программы прототипы импортируемых функций в следующем виде:

extern "C" PROTOTYPE

Где PROTOTYPE - прототип импортируемой функции.

* При подключении статических библиотек на C++ к программе на C сопряжено с некоторыми трудностями - т.к. при компиляции и линковки программы необходимо будет также вручную подключить системные библиотеки для реализации функционала, предоставляемого библиотекой Standart C++ сверх того, что предоставляет библиотека Standart C.

----------------------------------------------------------------------------------------------------------------

Часть 2.

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

1) Динамическая библиотека - библиотека, подключаемая к программе в момент выполнения. Это означает, что при создании библиотеки производится не только ее компиляция, но и линковка с другими, нужными ей, библиотеками (!).

Динамические библиотеки полезны в случаях, если:
- Важно не перекомпилировать всю программу, а только перекомпилировать ту часть, которая реализует определенные функции - тогда эти функции выносятся в динамическую библиотеку;
- Важно использовать в программах на C библиотеки, подготовленные на C++ и при этом избежать лишних трудностей с линковкой программы;
- Кроме того, динамические библиотеки позволяют экономить место на жестком диске и в оперативной памяти, если одна и таже библиотека используется несколькими программами.

В Linux, обычно, динамические библиотеки имеют расширение ".so".

2) Подготовим исходный код динамической библиотеки (пример на C++).

Исходный код динамической библиотеки по принципам создания ничем (!) не отличается от исходного кода статических библиотек.

Здесь мы подготовим некоторый пример, который в дальнейшем будем использовать повсеместно во всей части 2.

Итак, исходный код библиотеки (C++):

######################
#include <iostream>
using namespace std;

#include <dynamic.h>

extern "C" int hello()
{
cout<<"Hello world!\n I'm function hello()"<<endl;
return 0;
}

######################

Сохраните приведенный код в файле dynamic.cpp.

* Кстати, внутри динамической библиотеки вы можете описать следующие функции:
void _init() - будет вызвана при инициализации динамической библиотеки (загрузки ее в память);
void _fini() - будет вызвана при выгрузке из памяти динамической библиотеки.

3) Компиляция и линковка динамических библиотек.

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

Получим файл с объектным кодом:

g++ -fPIC -c dynamic.cpp -o dynamic.o

(используйте gcc для программ на С и Assembler'е)

Здесь:

-fPIC - использовать относительную адресацию в переходах подпрограмм - во избежание конфликтов при динамическом связывании

А теперь из объектного файла получим библиотеку:

g++ -shared -olibdynamic.so dynamic.o

(используйте gcc для программ на С и Assembler'е)

libdynamic.so - имя результирующей библиотеки;
-shared - предписывает создать динамическую (т.е. "разделяемую") библиотеку.

* Именуйте динамические библиотеки следующим способом:

libNAME.so

Это традиция ;-)

Итак, на выходе мы имеем libdynamic.so - нашу динамическую библиотеку.

4) Использование динамической библиотеки в программе на C/C++.

- Связывание с библиотекой во время компиляции программы (C/C++):

------ Подготовим исходный код нашей программы:

(С)

######################

int main()
{
int x = hello();
printf("Return code: %x\n",x);
return 0;
}

######################

Сохраните его в файле Dprogram1.c

ИЛИ

(С++)

######################
#include <stdio.h>

extern "C" int hello();

int main()
{
int x = hello();
printf("Return code: %x\n",x);
return 0;
}

######################

Сохраните его в файле Dprogram1.cpp

(единственное отличие, как вы можете заметить, в ключевом слове extern - см. часть 1 пункт 4)

------ Теперь добьемся того, чтобы система смогла найти нашу библиотеку. Поместим libdynamic.so в один из каталогов:

из списка:

echo $LD_LIBRARY_PATH
/lib
/usr/lib


или из списка:

cat /etc/ld.so.conf
и выполните потом "ldconfig"

------ И, наконец, скомпилируем программу и слинкуем ее с библиотекой:

gcc ИСХОДНИК -lИМЯ_БИБЛИОТЕКИ -o РЕЗУЛЬТИРУЮЩИЙ_БИНАРИК

В нашем случае: gcc Dprogram1.c -L/home/amv/c/libs/ -ldynamic

(используйте g++ для программы на C++)

Запустим на исполнение полученный файл:

./a.out

В итоге должно получится:

Hello world!
I'm function hello()
Return code: 0


- Связывание с библиотекой во время исполнения программы (C/C++):

Разумеется, предыдущий пример неплох. Однако бывает необходимо подключать библиотеку во время выполнения программы. Для этого можно использовать функционал из заголовочного файла .

Исходный код примера (C):

######################
#include <dlfcn.h>
#include <stdio.h>

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++)

Запустим на исполнение полученный файл:

./a.out

В итоге должно получится:

Hello world!
I'm function hello()
Return code: 0


* Важно! Нет необходимости помещать библиотеку в один из специальных каталогов, модифицировать переменные окружения и выполнять "ldconfig"

- Использование динамической библиотеки в программе на Python:

Все предельно просто.

------ Поместим libdynamic.so в один из каталогов:

из списка:

echo $LD_LIBRARY_PATH
/lib
/usr/lib


или из списка:

cat /etc/ld.so.conf
и выполните потом "ldconfig"

------ python:

Исходный текст программы на python'е:

######################
#!/usr/bin/python
import ctypes

dl = ctypes.cdll.LoadLibrary("libdynamic.so")
dl.hello()

######################

Модуль ctypes входит в стандартную поставку модулей python версии 2.5 и выше.

----------------------------------------------------------------------------------------------------------------

Фуф. Мы проделали довольно большую работу, но ведь это только верхушка айсберга.

P.S. Я намерено пропустил тему "Perl и динамические библиотеки" - сейчас мне просто лениво разбирать свои старые примеры. Могу только сказать, что за динамические библиотеки в Perl ведает модуль DynaLoader (и не только он), который является, по сути, оболочкой для dlfcn.h. Почитайте perldoc DynaLoader ;-)

UPDATE: 25.07.2008