для пользователей GNU / Linux
библиотека динамической загрузки - это механизм, с помощью которого мы можем запускать нашу программу и во время выполнения решать, какую функцию мы хотим использовать. Я думаю, что в некоторых случаях переменная static
также возможна.
Сначала начните с просмотра man 3 dlopen
или посмотрите онлайн
Требуемый заголовочный файл: dlfcn
, и поскольку он не является частью стандарта, вам должен понравиться файл объекта с этой библиотекой: libdl.(so/a)
, и поэтому вам нужно что-то вроде :
gcc yours.c -ldl
тогда у вас есть имя файла a.out
, и вы можете запустить его НО он не работает должным образом, и я объясню почему.
Полный пример:
первый ящик 2 файла func1.c
и func2.c
соответственно. Мы хотим вызывать эти функции во время выполнения.
func.c
int func1(){
return 1;
}
func2.c
const char* func2(){
return "upgrading to version 2";
}
Теперь у нас есть 2 функции, давайте сделаем наши модули:
ALP ❱ gcc -c -fPIC func1.c
ALP ❱ gcc -c -fPIC func2.c
ALP ❱ gcc -o libfunc.so -shared -fPIC func1.o func2.o
для вопросов о -fPIC
=> PIC
Теперь у вас есть dynamic library
имен: libfunc.so
Давайте создадим основную программу (= temp.c
), которая хочет использовать эти функции.
заголовочные файлы
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
и основная программа
int main()
{
// pointer function to func1 and func2
int ( *f1ptr )();
const char* ( *f2ptr )();
// for pointing to the library
void* handle = NULL;
// for saving the error messages
const char* error_message = NULL;
// on error dlopen returns NULL
handle = dlopen( "libfunc.so", RTLD_LAZY );
// check for error, if it is NULL
if( !handle )
{
fprintf( stderr, "dlopen() %s\n", dlerror() );
exit( 1 );
}
/*
according to the header file:
When any of the above functions fails, call this function
to return a string describing the error. Each call resets
the error string so that a following call returns null.
extern char *dlerror (void) __THROW;
*/
// So, reset the error string, of course we no need to do it just for sure
dlerror();
// point to func1
f1ptr = (int (*)()) dlsym( handle, "func1" );
// store the error message to error_message
// because it is reseted if we use it directly
error_message = dlerror();
if( error_message ) // it means if it is not null
{
fprintf( stderr, "dlsym() for func1 %s\n", error_message );
dlclose( handle );
exit( 1 );
}
// point the func2
f2ptr = (const char* (*)()) dlsym( handle, "func2" );
// store the error message to error_message
// because it is reseted if we use it directly
error_message = dlerror();
if( error_message ) // it means if it is not null
{
fprintf( stderr, "dlsym() for func2 %s\n", error_message );
dlclose( handle );
exit( 1 );
}
printf( "func1: %d\n", ( *f1ptr )() );
printf( "func2: %s\n", ( *f2ptr )() );
// unload the library
dlclose( handle );
// the main return value
return 0;
}
Теперь нам просто нужно скомпилировать этот код (= temp.c
), поэтому попробуйте:
ALP ❱ gcc temp.c -ldl
ALP ❱ ./a.out
libfunc.so: cannot open shared object file: No such file or directory
не работает! ПОЧЕМУ легко; потому что наша a.out
программа не знает, где найти соответствующую библиотеку: libfunc.so
и поэтому сообщает нам cannot not open ...
как указать программе (= a.out
) найти ее библиотеку?
- с использованием
ld
linker
- с использованием переменной среды
LD_LIBRARY_PATH
- используя стандартный путь
первый способ, с помощью ld
используйте -Wl,-rpath,
и pwd
и укажите путь в качестве аргумента для него
ALP ❱ gcc temp.c -ldl
ALP ❱ ./a.out
libfunc.so: cannot open shared object file: No such file or directory
ALP ❱ pwd
/home/shu/codeblock/ALP
ALP ❱ gcc temp.c -ldl -Wl,-rpath,/home/shu/codeblock/ALP
ALP ❱ ./a.out
func1: 1
func2: upgrading to version 2
второй способ
ALP ❱ gcc temp.c -ldl
ALP ❱ ./a.out
libfunc.so: cannot open shared object file: No such file or direc
ALP ❱ export LD_LIBRARY_PATH=$PWD
ALP ❱ echo $LD_LIBRARY_PATH
/home/shu/codeblock/ALP
ALP ❱ ./a.out
func1: 1
func2: upgrading to version 2
ALP ❱ export LD_LIBRARY_PATH=
ALP ❱ ./a.out
libfunc.so: cannot open shared object file: No such file or
и третий способ
у вас есть libfunc.so
в вашем текущем пути, поэтому вы можете скопировать его в стандартный путь для библиотек.
ALP $ sudo cp libfunc.so /usr/lib
ALP ❱ gcc temp.c -ldl
ALP ❱ ./a.out
func1: 1
func2: upgrading to version 2
Вы можете удалить его из /usr/lib
и использовать его. Это зависит от вас.
ПРИМЕЧАНИЕ
как узнать, что наш a.out
знает о своем пути?
легко:
ALP ❱ gcc temp.c -ldl -Wl,-rpath,/home/shu/codeblock/ALP
ALP ❱ strings a.out | grep \/
/lib/ld-linux.so.2
/home/shu/codeblock/ALP
как мы можем использовать его в c ++ ?
Пока я знаю, что вы не можете, потому что g++
искажает имена функций, тогда как gcc
не делает, поэтому вы должны использовать: extern "C" int func1();
например.
Подробнее см. Справочные страницы и книги по программированию для Linux.