开发者

Building a shared library using gcc [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center. Closed 10 years ago.

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.


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.


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'.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜