SOLVED. See below for the corrections (labeled FIXED).
I'm having trouble creating a shared library using gcc.
I created a little sample project that closely mirrors the structure of the actual project I'm working on. I've made it available as a tar.gz archive here:
http://209.59.216.197/libtest.tar.gz
FIXED: I've made the fixed version available here:
http://209.59.216.197/libtest_fixed.tar.gz
In this sample project, I have an application (app) that loads a shared library that I wrote (libshared.so) at runtime and calls a function that the shared library defines: function_inside_shared_lib().
In turn, this shared library uses a function defined inside a static library (libstatic.a): function_inside_static_lib().
The problem is when I build the shared library, the symbol "function_inside_shared_lib" does not get exported. I examined the shared library using "nm" and the symbol wasn't there. I am wondering if the command I am using to create the shared library is correct:
g++ -g -ggdb -fPIC -rdynamic -I ../static -c shared.cpp -o shared.o
g++ -g -ggdb -fPIC -rdynamic -shared -L ../static -lstatic -o libshared.so
FIXED: The correct commands are:
g++ -g -ggdb -fPIC -rdynamic -I../static -c shared.cpp -o shared.o
g++ -g -ggdb -fPIC -rdynamic -shared -L../static -o libshared.so shared.o -lstatic
I tried these commands with and without -rdynamic, as well as with and without -fPIC. The results are always the same.
I am using Ubuntu 10.04 (64-bit) with g++ version 4.4.3.
The full sample project follows. (Or you can download the archive using the link at the top of my post).
serg@rodent:~/libtest$ ls
app shared static
Here are the three components:
Component 1: A static library that defines a function called function_inside_static_lib().
This consists of the following:
serg@rodent:~/libtest$ cd static/ serg@rodent:~/libtest/static$ ls static.cpp static.h
static.h
// Header file for the static library
int function_inside_static_lib(int arg1, int arg2);
static.cpp
// Source file for the static library
#include <iostream>
using namespace std;
#include "static.h"
int function_inside_static_lib(int arg1, int arg2)
{
cout << "In function_inside_static_lib()" << endl;
// Return the sum
int result = arg1 + arg2;
return result;
}
Component 2: A shared library that uses the static library and defines a new function.
serg@rodent:~/libtest$ cd shared
serg@rodent:~/libtest/shared$ ls
shared.cpp
shared.cpp
// The shared library only has one source file.
// The shared library uses the static one.
#include "static.h"
#include <iostream>
using namespace std;
int function_inside_shared_lib(int arg1, int arg2)
{
cout << "In function_inside_shared_lib()" << endl;
cout << "Calling function_inside_static_lib()" << endl;
int result = function_inside_static_lib(arg1, arg2);
return result;
}
Component 3: An application that uses the shared library.
serg@rodent:~/libtest$ cd app
serg@rodent:~/libtest/app$ ls
app.cpp
app.cpp
FIXED: Because C++ symbols get mangled, the correct function name to search for is _Z26function_inside_static_libii
instead of function_inside_static_lib
// The application loads the shared library at runtime.
#include <dlfcn.h>
#include <iostream>
using namespace std;
int main(int argc, char **argv)
{
void *handle;
int (*function_inside_shared_lib)(int, int);
char *error;
int arg1 = 3;
int arg2 = 7;
cout << "app: loading the shared library." << endl;
handle = dlopen ("libshared.so", RTLD_LAZY);
if (!handle) {
cout << "Error: Failed to open shared library." << endl;
cout << dlerror() << endl;
return -1;
}
cout << "app: Looking for function_inside_shared_lib" << endl;
// The next line is now FIXED:
function_inside_shared_lib = (int (*)(int, int))dlsym(handle, "_Z26function_inside_static_libii");
if ((error = dlerror()) != NULL) {
cout << "Error: Could not find the function." << endl;
cout << error << endl;
return -1;
}
cout << "app: Calling function_inside_shared_lib(" << arg1 << ", " << arg2 << ")" << endl;
int result = (*function_inside_shared_lib)(arg1, arg2);
cout << "app: The result is " << result << endl;
dlclose(handle);
return 0;
}
Here are the commands I'm using to build all of these components. Note that I want debugging symbols to be available in the final resulting app. Ideally, I want to be able to do a backtrace inside the app and see symbols from both the shared library and the static library.
1: Building the static library. I think I'm fine with this step:
serg@rodent:~/libtest/static$ g++ -g -ggdb -c static.cpp -o static.o # See the FIXED version just below
serg@rodent:~/libtest/static$ ar rcs libstatic.a static.o
serg@rodent:~/libtest/static$ ls
libstatic.a static.cpp static.h static.o
FIXED: The first command above must include -fPIC as well. The correct command is
g++ -g -ggdb -fPIC -c static.cpp -o static.o
2: Building the shared library. I'm pretty sure this is where I'm going wrong.
serg@rodent:~/libtest/shared$ g++ -g -ggdb -fPIC -rdynamic -I ../static -c shared.cpp -o shared.o
serg@rodent:~/libtest/shared$ g++ -g -ggdb -fPIC -rdynamic -shared -L ../static -lstatic -o libshared.so # See just below for FIXED version serg@rodent:~/libtest/shared$ ls
libshared.so shared.cpp shared.o
FIXED: The second command above should be:
g++ -g -ggdb -fPIC -rdynamic -shared -L../static -o libshared.so shared.o -lstatic
At this point, if I run nm to examine the symbols inside libshared.so, I don't see function_inside_shared_lib() anywhere, even with the -a and -D options for nm. (However, I do see it inside shared.o).
EDIT: With the fix above, the symbol appears as _Z26function_inside_shared_libii
.
3: Building the app:
First, copy the shared library into the app folder:
serg@rodent:~/libtest$ cp shared/libshared.so app/
serg@rodent:~/libtest$ cd app
serg@rodent:~/libtest/app$ ls
app.cpp libshared.so
Now compile:
serg@rodent:~/libtest/app$ g++ -g -ggdb -ldl -L. -lshared app.cpp -o app
serg@rodent:~/libtest/app$ ls
app app.cpp libshared.so
If I try to run:
serg@rodent:~/libtest/app$ ./app
app: loading the shared library.
app: Looking for function_inside_shared_lib
Error: Could not find the function.
/home/serg/libtest/app/libshared.so: undefined symbol: function_inside_shared_lib
This makes sense because I could not see function_inside_shared_lib() using nm either, which means I'm probably building the shared library incorrectly in step 2.
How can I fix my command in the second step so that function_inside_shared_lib gets exported correctly?
Also feel free to give me any other advice if you notice that I'm doing anything odd. I'm still a beginner.