How would one go about loading compiled C code at run time, and then calling functions within it? Not like simply calling exec().
EDIT: The the program loading the
dynamic loading library is a mechanism that with the help of that, we can run our program, and at run time, decide what function, we want to use. I think in some cases static variable is possible as well.
First start with seeing man 3 dlopen or see it online
The header file that is required is: dlfcn and since this is not part of the standard you should like it to your object file with this library: libdl.(so/a) and therefore you need something like:
gcc yours.c -ldl
then you have a file name a.out and you can run it BUT it does not work properly and I will explain it why.
A complete example:
first crate 2 files func1.c and func2.c respectively. We want to call these functions at runtime.
func.c
int func1(){
return 1;
}
func2.c
const char* func2(){
return "upgrading to version 2";
}
Now we have 2 functions, let's make our modules:
ALP ❱ gcc -c -fPIC func1.c
ALP ❱ gcc -c -fPIC func2.c
ALP ❱ gcc -o libfunc.so -shared -fPIC func1.o func2.o
for inquiring mind about -fPIC => PIC
Now you have a dynamic library names: libfunc.so
Let's create the main program (= temp.c) that wants to use those functions.
header files
#include
#include
#include
and the main program
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;
}
Now we just need to compile the this code (= temp.c), thus try:
ALP ❱ gcc temp.c -ldl
ALP ❱ ./a.out
libfunc.so: cannot open shared object file: No such file or directory
It does not work! WHY easy; because our a.out program does not know where to find the related library: libfunc.so and therefore it tells us cannot not open ...
how to tell the program (= a.out) to find its library?
ld linkerLD_LIBRARY_PATHfirst way, with help of ld
use -Wl,-rpath, and pwd and put the path as a argument for it
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
second way
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
and third way
you have libfunc.so in you current path, thus you can copy it into a standard path for libraries.
ALP $ sudo cp libfunc.so /usr/lib
ALP ❱ gcc temp.c -ldl
ALP ❱ ./a.out
func1: 1
func2: upgrading to version 2
you can remove it from /usr/lib and use it. It is up to you.
NOTE
how to find out that our a.out knows about its path?
easy:
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
how we can use it in c++?
As long as I know you cannot because g++ mangles the function names whereas gcc does not thus you should use: extern "C" int func1(); for example.
For any more details see man pages and Linux programing books.