Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Building a shared library using gcc [closed]

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.

like image 495
Sergey K Avatar asked Aug 27 '10 22:08

Sergey K


People also ask

What is a shared library GCC?

Programs can be linked against libraries either at compile time or at run time. An advantage of linking at run time is that a single copy of the library can be shared between many programs, both on disc and in memory. Libraries suitable for use in this way are known as shared libraries.

Which option of GCC compiler provides the linking with shared libraries?

6. Which option of GCC compiler provides the linking with shared libraries? Explanation: None.

Which of the following options is necessary to create a shared library?

The -shared or -dynamiclib option is required to create a shared library. The name of the source file is octagon.


2 Answers

There's a few errors here:

libshared.so is empty

Your Makefile doesn't actually link in the shared.o , it just creates an empty shared library. Change

g++ -g -ggdb -fPIC -rdynamic -shared -Lstatic -lstatic -o shared/libshared.so 

to

g++ -g -ggdb -fPIC -rdynamic -shared -Lstatic -o shared/libshared.so shared/shared.o -lstatic

The -lstatic have to come after shared/shared.o as you have to specify static libraries in reverse order of their dependencies.

-fPIC is needed on all object files in a shared library

You create a shared library that links in a static library. That static library also have to be compiled with -fPIC, otherwise you're creating a shared library where some parts of it cannot be relocated. Change

g++ -g -ggdb -c static/static.cpp -o static/static.o

to

g++ -fPIC -g -ggdb -c static/static.cpp -o static/static.o

C++ symbols get mangled

As you're creating a shared library from C++ code, function names and similar gets mangeled This means there is no function name matching the string "function_inside_static_lib" which you try to dynamically load. run nm on the static library, you'll see it's actually named "_Z26function_inside_static_libii" . You can run nm -C to pretty print C++ names.

This means your code in app.cpp have to be:

 function_inside_shared_lib = (int (*)(int, int))dlsym(handle, "_Z26function_inside_static_libii");

This is one of the reasons it's often preferrable to export functions from shared objects using C instead of C++ if you want to dynamically (dlopen) fetch something from a shared library. The C++ name mangling have in the past varied from compiler to compiler, though these days they seem to have all agreed to a standard that won't be changing. With C it's simpler, and the symbols in the shared library will be the same as you gave them in your source code.

like image 181
nos Avatar answered Nov 14 '22 19:11

nos


So, in step 2 you don't specify shared.o. So, instead of:

g++ -g -ggdb -fPIC -rdynamic -shared -L ../static -lstatic -o libshared.so

You should do:

g++ -g -ggdb -fPIC -rdynamic -shared -L ../static shared.o -lstatic -o libshared.so

Also it is important that shared.o is before -lstatic. Otherwise the linker will not find the function and let it 'undefined'.

like image 28
vladmihaisima Avatar answered Nov 14 '22 19:11

vladmihaisima