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.
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
.
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.
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.
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.
© 2022 - 2024 — McMap. All rights reserved.