Using a shared library in another shared library
Asked Answered
C

4

12

I am creating a shared library from a class from an example I got here C++ Dynamic Shared Library on Linux. I would like to call another shared library from the shared library created and then use it in the main program. So I have the myclass.so library and I want to call another library say anotherclass.so from the myclass.so library and then use this myclass.so library in the main program. Any idea on how I can do this please.

Chump answered 14/8, 2018 at 11:1 Comment(1)
A library does not use another library as such. You reference the header library of shared library a from library b. They can both be shared. Then, when you link your executable you include both so files in the link stage.Tint
V
34

There is more than one way in which multiple shared libraries may be added to the linkage of a program, if you are building all the libraries, and the program, yourself.

The elementary way is simply to explicitly add all of the libraries to the the linkage of the program, and this is the usual way if you are building only the program and linking libraries built by some other party.

If an object file foo.o in your linkage depends on a library libA.so, then foo.o should precede libA.so in the linkage sequence. Likewise if libA.so depends on libB.so then libA.so should precede libB.so. Here's an illustration.

We'll make a shared library libsquare.so from the files:

square.h

#ifndef SQUARE_H
#define SQUARE_H

double square(double d);

#endif

and

square.cpp

#include <square.h>
#include <cmath>

double square(double d)
{
    return pow(d,2);
}

Notice that the function square calls pow, which is declared in the Standard header <cmath> and defined in the math library, libm.

Compile the source file square.cpp to a position-independent object file square.o:

$ g++ -Wall -fPIC -I. -c square.cpp

Then link square.o into a shared library libsquare.so:

$ g++ -shared -o libsquare.so square.o

Next we'll make another shared library libcube.so from these files:

cube.h

#ifndef CUBE_H
#define CUBE_H

double cube(double d);

#endif

and

cube.cpp

#include <cube.h>
#include <square.h>

double cube(double d)
{
    return square(d) * d;
}

See that the function cube calls square, so libcube.so is going to depend on libsquare.so. Build the library as before:

$ g++ -Wall -fPIC -I. -c cube.cpp
$ g++ -shared -o libcube.so cube.o

We haven't bothered to link libsquare with libcube, even though libcube depends on libsquare, and even though we could have, since we're building libcube. For that matter, we didn't bother to link libm with libsquare. By default the linker will let us link a shared library containing undefined references, and it is perfectly normal. It won't let us link a program with undefined references.

Finally let's make a program, using these libraries, from this file:

main.cpp

#include <cube.h>
#include <iostream>

int main()
{
    std::cout << cube(3) << std::endl;
    return 0;
}

First, compile that source file to main.o:

$ g++ -Wall -I. -c main.cpp

Then link main.o with all three required libraries, making sure to list the linker inputs in dependency order: main.o, libcube.so, libsquare.so, libm.so:

$ g++ -o prog main.o -L. -lcube -lsquare -lm

libm is a system library so there's no need to tell the linker where to look for it. But libcube and libsquare aren't, so we need to tell the linker to look for them in the current directory (.), because that's where they are. -L. does that.

We've successfully linked ./prog, but:

$ ./prog
./prog: error while loading shared libraries: libcube.so: cannot open shared object file: No such file or directory

It doesn't run. That's because the runtime loader doesn't know where to find libcube.so (or libsquare.so, though it didn't get that far).

Normally, when we build shared libraries we then install them in one of the loader's default search directories (the same ones as the linker's default search directories), where they're available to any program, so this wouldn't happen. But I'm not going to install these toy libraries on my system, so as a workaround I'll prompt the loader where to look for them by setting the LD_LIBRARY_PATH in my shell.

$ export LD_LIBRARY_PATH=.
$ ./prog
27

Good. 3 cubed = 27.

Another and better way to link a program with shared libraries that aren't located in standard system library directories is to link the program using the linker's -rpath=DIR option. This will write some information into the executable to tell the loader that it should search for required shared libraries in DIR before it tries the default places.

Let's relink ./prog that way (first deleting the LD_LIBRARY_PATH from the shell so that it's not effective any more):

$ unset LD_LIBRARY_PATH
$ g++ -o prog main.o -L. -lcube -lsquare -lm -Wl,-rpath=.

And rerun:

$ ./prog
27

To use -rpath with g++, prefix it with -Wl, because it's an option for linker, ld, that the g++ frontend doesn't recognise: -Wl tells g++ just to pass the option straight through to ld.

Viguerie answered 14/8, 2018 at 18:22 Comment(0)
P
8

I would like to add some points to the response of @Mike.

As you do not link libcube library with libsquare you are creating a sort of "incomplete library". When I say incomplete, I meant that when you link your application you must link it with both libcube and libsquare even though it does not use any symbol directly from libsquare.

It is better to link libcube directly with libsquare. This link will create the library with a NEEDED entry like:

readelf -d libcube.so
Tag        Type                         Name/Value
0x0000000000000001 (NEEDED)             Shared library: [libsquare.so]

Then when you link your application you can do:

g++ -o prog main.o -L. -lcube 

Although, this will not link because the linker tries to locate the NEEDED library libsquare. You must precise its path by adding -Wl,-rpath-link=. to the linking command:

g++ -o prog main.o -L. -lcube -Wl,-rpath-link=.

Note: For runtime, you must still set LD_LIBRARY_PATH or link with rpath as mentioned by @Mike.

Plaque answered 9/5, 2019 at 20:58 Comment(2)
Тhis is a great addition to the initial explanation. I would only add that the best thing about this approach is that unresolved linkage would result in "shared not found" error rather than only "undefined reference to..." which is by far more informative...Fabien
@Plaque thanks. But what if at the end I want only one big .so library (cube.so) that I send to third party (without libsquare.so)? How can I do that?Phiona
O
0

In your library if you are using any other shared library so simply your library user is also dependent on that library. While creating library you can use -l so the linker have notion for shared library and it will link when required. But when you deliver your library as its dependent on some other library you need to export that too along with your and provide some environment variable or linker flag to load it from specified path (Your exported package). That will not lead any discrepancy other wise if its some standard library function user might get definition from his system's some other library and will lead in disastrous situation.

Opiumism answered 14/8, 2018 at 11:14 Comment(0)
L
0

Simply use the library like you'd use it in any other application. You don't have to link to anotherclass.so, just to myclass.so.

However, you will have to make both libraries (myclass.so and anotherclass.so) available for your later application's runtime. If one of them is missing you'll get runtime errors just like it is with any other application.

Liquor answered 14/8, 2018 at 11:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.