Why doesn't g++ link with the dynamic library I create? - c++

I've been trying to make some applications which all rely on the same library, and dynamic libraries were my first thought: So I began writing the "Library":
/* ThinFS.h */
class FileSystem {
public:
static void create_container(string file_name); //Creates a new container
};
/* ThinFS.cpp */
#include "ThinFS.h"
void FileSystem::create_container(string file_name) {
cout<<"Seems like I am going to create a new file called "<<file_name.c_str()<<endl;
}
I then compile the "Library"
g++ -shared -fPIC FileSystem.cpp -o ThinFS.o
I then quickly wrote a file that uses the Library:
#include "ThinFS.h"
int main() {
FileSystem::create_container("foo");
return (42);
}
I then tried to compile that with
g++ main.cpp -L. -lThinFS
But it won't compile with the following error:
/usr/bin/ld: cannot find -lThinFS
collect2: ld returned 1 exit status
I think I'm missing something very obvious, please help me :)

-lfoo looks for a library called libfoo.a (static) or libfoo.so (shared) in the current library path, so to create the library, you need to use g++ -shared -fPIC FileSystem.cpp -o libThinFS.so

You can use
g++ main.cpp -L. -l:ThinFS
The use of "colon" will use the library name as it is, rather requiring a prefix of "lib"

the name of the output file should be libThinFS.so, e.g.
g++ -shared -fPIC FileSystem.cpp -o libThinFS.so

The result of g++ -shared -fPIC FileSystem.cpp is not an object file, so it should not end with .o. Also, shared libraries should be named libXXX.so. Rename the library and it will work.

Check out this article.
http://www.yolinux.com/TUTORIALS/LibraryArchives-StaticAndDynamic.html
A good resource on how to build different types of libraries. It also describes how and where to use them.

Related

Using a shared library in another shared library

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.

Why one definition rule (ODR) is not honoured by g++ in this case ? .

As you see, there are multiple definitions of testfn symbol while linking, but the linker takes the first occurence (in linking order) and ignores the other occurances in other libraries.
This probably is the way how the linker works.
But Is there any way to enforce linker to flag error on seeing multiple symbols in different linked libraries ? Or any other options to catch such duplicate definitions ?
Content of test1.h:
#ifndef TEST1
#define TEST1
void testfn();
#endif
Content of test1.cpp
#include "test1.h"
#include <iostream>
using namespace std;
void testfn()
{
cout << "file1" << endl;
}
Content of test.h:
#ifndef TEST
#define TEST
void testfn();
#endif
Content of test.cpp:
#include "test.h"
#include <iostream>
using namespace std;
void testfn()
{
cout << "file" << endl;
}
Content of main.cpp:
#include "test.h"
#include "test1.h"
int main()
{
testfn();
return 0;
}
Created a shared libraries.
g++ -fPIC -shared libtest1.so test1.cpp
g++ -fPIC -shared libtest.so test.cpp
Created executable with library order#1
g++ -o main main.cpp -ltest -ltest1
Created executable with library order#2
g++ -o main1 main.cpp -ltest1 -ltest
Ouput of main
./main
file
Ouput of main1
./main1
file1
First of all, it is honoring the ODR, by only taking one of the methods out of the library. And that's just the way shared libraries work.
If you want to see the compiler complain about this, link them all together, without the library step.
g++ -o main1 main.cpp test1.cpp test.cpp
So your question becomes, "How do I tell if I have two libraries which both contain a indentifier with the same name?" Keep in mind that this is often not a problem and sometimes done intentionally. I'd suggest running the library tool (I'm not familiar with the g++ toolset) to get listing of the libraries, and run DIFF of them.
I don't see a way to get GNU ld to complain about multiple symbol definitions across shared libraries. However, if normal static library archives are involved, you might be able to use the --whole-archive/--no-whole-archive set of options to get what you want:
For example, after building libtest.a and libtest1.a instead of the shared library versions, I get no errors with the following link commands:
$ g++ -o main main.cpp -ltest1 -ltest -L.
$ ./main
file1
$ g++ -o main main.cpp -ltest -ltest1 -L.
$ ./main
file
But do get errors for the following:
$ g++ -o main main.cpp -Wl,--whole-archive -ltest1 -ltest -Wl,--no-whole-archive -L.
./libtest.a(test.o): In function `testfn()':
test.cpp:(.text+0x0): multiple definition of `testfn()'
./libtest1.a(test1.o):test1.cpp:(.text+0x0): first defined here
collect2: ld returned 1 exit status
I'm not sure you would want to use --whole-archive for release builds - maybe only as a sanity check for possibly name conflicts (I think that using --whole-archive normally will increase the size of your binary for no good reason).
Also, as mentioned before, this seems to have no effect on shared libraries.

Link error with my own C++ library

This is my first time trying to make a simple library. I worked in Ubuntu 12.04 with g++ 4.6.3. Here is the problem:
[[mylib.cpp]]
#include<sqlite3.h>
void Mylib::blahblah() {...}
void Mylib::evenmoreblah() {...}
...
[[mylib.h]]
#include <...>
class Mylib {
...
};
Then I made the lib by:
gcc -c -Wall -fpic mylib.cpp
gcc -shared -o libmylib.so mylib.o
I used the library in a single test.cpp which contains only the main(). I put libmylib.so in ./libdir, and compiled by using:
g++ -g test.cpp -o test -lpthread -L/usr/local/lib -lsqlite3 -L./libdir -lmylib
The error I got:
./libdir/libmylib.so: undefined reference to `sqlite3_close'
./libdir/libmylib.so: undefined reference to `sqlite3_exec'
./libdir/libmylib.so: undefined reference to `sqlite3_free'
./libdir/libmylib.so: undefined reference to `sqlite3_open'
You could link -lsqlite3 into your shared library with
gcc -shared mylib.o -o libmylib.so -lsqlite3
If you do that, you don't need to explicitly link -lsqlite3 to your program, but that won't harm.
and the order of linking arguments for your program is important:
g++ -Wall -g test.cpp -o mytest \
-L./libdir -lmylib -L/usr/local/lib -lsqlite3 -lpthread
it should go from higher-level libraries to lower-level (i.e. system) ones. And don't forget -Wall to get almost all warnings from the compiler, which is very useful.
Read the Program Library HowTo.
PS. Don't call your program test which is a shell builtin (and the standard /usr/bin/test). Use some other name.
If your library make references to sqlite3, you should link sqlite after linking your library :
g++ -g test.cpp -o test -lpthread -L/usr/local/lib -L./libdir -lmylib -lsqlite3
Otherwise ld won't find anything useful in libsqlite3 before linking your library and won't be able to find the requested symbols after that.
Since your library uses sqlite3, you need to add that AFTER your own library in the linker command. I think you could add it to the linking of your shared library too, but not certain.
The linker resolves libraries and their references in the order you list them, so the order is important.

How to force gcc to link an unused static library

I have a program and a static library:
// main.cpp
int main() {}
// mylib.cpp
#include <iostream>
struct S {
S() { std::cout << "Hello World\n";}
};
S s;
I want to link the static library (libmylib.a) to the program object (main.o), although the latter does not use any symbol of the former directly.
The following commands do not seem to the job with g++ 4.7. They will run without any errors or warnings, but apparently libmylib.a will not be linked:
g++ -o program main.o -Wl,--no-as-needed /path/to/libmylib.a
or
g++ -o program main.o -L/path/to/ -Wl,--no-as-needed -lmylib
Do you have any better ideas?
Use --whole-archive linker option.
Libraries that come after it in the command line will not have unreferenced symbols discarded. You can resume normal linking behaviour by adding --no-whole-archive after these libraries.
In your example, the command will be:
g++ -o program main.o -Wl,--whole-archive /path/to/libmylib.a
In general, it will be:
g++ -o program main.o \
-Wl,--whole-archive -lmylib \
-Wl,--no-whole-archive -llib1 -llib2
The original suggestion was "close":
How to force gcc to link unreferenced, static C++ objects from a library
Try this: -Wl,--whole-archive -lyourlib
I like the other answers better, but here is another "solution".
Use the ar command to extract all the .o files from the archive.
cd mylib ; ar x /path/to/libmylib.a
Then add all those .o files to the linker command
g++ -o program main.o mylib/*.o
If there is a specific function in the static library that is stripped by the linker as unused, but you really need it (one common example is JNI_OnLoad() function), you can force the linker to keep it (and naturally, all code that is called from this function). Add -u JNI_OnLoad to your link command.

How to resolve linker error "cannot find -lgcc_s"

I have 3 tiny files which I use to make a static library and an app:
test.h
#ifndef TEST_H
#define TEST_H
class Test
{
public:
Test();
};
extern Test* gpTest;
#endif
test.cpp
#include "test.h"
Test::Test()
{
gpTest = this;
}
Test test;
main.cpp
#include "test.h"
#include <iostream>
using namespace std;
Test* gpTest = NULL;
int main()
{
return 0;
}
BUILD
g++ -c test.cpp -o test.o
ar cr test.a test.o
g++ -c main.cpp -o main.o
g++ main.o -o app -Wl,--whole-archive -L/home/dumindara/intest/test.a -Wl,-no--whole-archive
ERROR (linking step)
/usr/lib64/gcc/x86_64-suse-linux/4.3/../../../../x86_64-suse-linux/bin/ld: cannot find -lgcc_s
collect2: ld returned 1 exit status
I tried everything: using -static-libgcc and linking to static libstdc++. Can't get this to work. It is all due to --whole-archive flag. But I can't do without it.
You have a typo. -no--whole-archive should be --no-whole-archive. Fixing the typo fixes the linker error.
I think -- is the problem here:
-Wl,-no--whole-archive
Try with
-Wl,-no-whole-archive
edit
About not seeing the test symbol in your app with nm app: I think you don't need -L since you give full path and name of test.a - do either
-Wl,--whole-archive -L/home/dumindara/intest/ -ltest -Wl,-no-whole-archive
or
-Wl,--whole-archive /home/dumindara/intest/test.a -Wl,-no-whole-archive
With regards to the comments so far: just drop the -Wl option
entirely. Let g++ do its thing.
As for not finding the symbol test with nm, why would you expect
anything else? You don't use it, your program doesn't need it,
so it isn't pulled in. (If for some reason you need to include
an object file which isn't referenced, e.g. because static
initializers will make it visible, then specify the object
file---don't put it in a library, which is the standard way of
saying don't include it unless needed.)
--
James Kanze
whole-archive works, you are just not linking the lib. The correct thing to do is :
ar cr libtest.a test.o
and link with
-Wl,--whole-archive -L/home/dumindara/intest/ -ltest
Just a note: whole-archive only works with static libraries (.a) not with shared libraries (.so) is my experience.