I have build a shared library libC.so, and it depends on libA.so and libB.so.
And then I build test.c which using libC.so via the command:
gcc test.c -o test -fPIC -I./ -L./ -lC
It will output error, could not find some symbols which are in libA.so and libB.so.
I know, tt can be build successufully when I add the flags "-lA -lB".
However I could not understood, why can it build successfully via the following command:
gcc test.c -o test -fPIC -I./ -L./ -lC -Wl,-rpath=.
I think your libA.so and libB.so are present in the current directory.
Your providing the linking option -Wl -rpath as your current directory.
So your linker takes the libraries in the current directory and link the symbols.
It is not giving any errors because of the linker options you have specified.
The next doubt you might get is,
I have only specified the directories to search but not specified libraries.
How is the linker is taking libA.so and libB.so libraries also?
But the linker is intelligent and it thinks that you have forgot to include these interdependent libraries (You might not know about interdependency)but you have specified the path to search for all the dependent libraries. So it picks the interdependent libraries.
I think it only works for Interdependency only. All direct libraries should be specified with -l option i think.
Related
Supposing I have main.c main.o libheymath.so in current directory. I want to link them together to generate an executable file. I use command "g++ -o main main.o -L./ -lheymath" to realize that. But I don't know why I should indicate the library directory and name. As far as I know, when I run "./main" the system will load the shared library into memory in specific directories such as /lib and /use/lib and directories specified in LD_LIBRARY_PATH etc. but not what I have indicated. So what's the purpose of "-L./ -lheymath"?
working directory files:
main.c, main.o, libheymath.so
command:
g++ -o main main.o -L./ -lheymath
./main
-L allows to indicates a path where to look to find lib(s) at link time (it is not 'saved' in the produced executable to be reused when you will launch the executable)
-l indicates a lib you want to link with, this allows to check if some symbols are missing or not and to know the list of libs to load when you will launch the executable.
When you link the path of these libs is not saved into the executable because both executable and libs can be moved after the link (and may be installed on an other host)
Note LD_LIBRARY_PATH is used when you start an executable to find the dynamic libs, it is not used when you link objects/libs to make an executable
How can I "register" my library foo.c, compiled to libfoo.so, to link it with -lfoo? Is it by appending its path to LD_LIBRARY_PATH? Is it by running sudo ldconfig?
For curiosity, who do I "register" it with? That is, which application "needs to know" what -lfoo means in order for gcc bar.c -lfoo to work? Is it the bash environment? Is it gcc? Is it the kernel?
Is any of this different for static libraries (eg. libfoo.a)?
If your library is not in a "standard" library directory such as (eg. /usr/local/lib or /usr/lib) then you'll need to tell the compiler it's location -L when you link it -l:
$ gcc -L/home/username/foo -Wall -o test main.c -lfoo
| |
|__ location of libfoo.so or libfoo.a |__ link libfoo.so or libfoo.a
GCC assumes that all libraries start with ‘lib’ and end with .so or .a
(.so is for shared object or shared libraries, and .a is for archive,
or statically linked libraries).
-L is the location to search for libraries linked to your executable
-l links the library to the executable (-lfoo can be translated as "link library libfoo.so")
When using shared libraries sometimes simply linking them is not enough (eg. if the library is not installed in a standard location such as the example shown above). This is where using LD_LIBRARY_PATH, rpath or ldconfig comes into play. Static library paths won't need to be set like shared libraries since they are compiled with the executable.
LD_LIBRARY_PATH
$ export LD_LIBRARY_PATH=/home/username/foo:$LD_LIBRARY_PATH
Exporting this variable informs the run-time linker to look in the specified location for the libfoo.so library that's associated with the executable. LD_LIBRARY_PATH is more or less a temporary, or convenient way of setting a library's location.
rpath
$ gcc -L/home/username/foo -Wl,-rpath=/home/username/foo -Wall -o test main.c -lfoo
rpath works similarly to LD_LIBRARY_PATH (as libraries can reside almost anywhere in userland), however, rpath is linked to the executable at compile time, and sets a "fixed" library location.
ldconfig
Ultimately what might be the best solution is to use ldconfig, which creates the necessary links and cache to the most recent shared libraries found in the standard library locations and ones you can specify. It does require elevated permissions (eg. sudo) to set paths up this way, and should be used with a certain degree of caution.
$ sudo cp /home/username/foo/libfoo.so /usr/local/lib
$ sudo chmod 0755 /usr/local/lib/libfoo.so
This copies the library into /usr/local/lib with permissions set to be readable by everyone.
$ sudo ldconfig
$ ldconfig -p | grep foo
libfoo.so (libc6) => /usr/local/lib/libfoo.so
Then we update the loader cache, and verify the path is set correctly.
$ gcc -Wall -o test main.c -lfoo
By using ldconfig, the -L option, LD_LIBRARY_PATH or rpath now shouldn't be needed.
Additional Information
↳ Shared Libraries With GCC on Linux
I want to build a statically linked application that could use dynamically loadable plugins.
The problem is that I can't get rid of the libc.so dependency.
I'm using musl libc and compiling like
/opt/cross/x86_64-linux-musl/bin/x86_64-linux-musl-gcc -Wl,-E -fPIC -I... -static-libgcc -Wl,-Bstatic -ldl -lc -lgcc source.c -o output_bin foo.a bar.a -Wl,-Bdynamic
readelf -d shows that executable depends on libc.so, so executable doesn't work on other machines without musl libc.
Is it possible to include libc symbols into elf executable and link all external plugins to elf itself, without external .so dependencies? How to achieve this?
Maybe you should try compiling it without the stdlib using -nostdlib parameter.
Can someone help me to figure out this error.
I'm trying to compile a test program and it gives this error
/usr/lib/gcc/x86_64-pc-cygwin/4.8.3/../../../../x86_64-pc-cygwin/bin/ld: cannot find -ltest.
I gave correct path of lib cc test.c -I"./include" -L"./Lib" -ltest, still it is throwing error. Library is present in mentioned folder.
I tried too many things discussed over here but nothing helped me.
On Cygwin you should be able to build a library that generates the appropriate shared object with something like:
gcc -shared -o libtest.so -Wl,--out-implib,libtest.dll.a libtest.c
libtest.c would be the name of your .c file or a list of .c files used to build your library.
This should produce a libtest.dll.a and libtest.so . You use the import library to link your programs to the shared object. So you could compile your application with:
gcc test.c -I./include -LLib/ -ltest
The Lib/libtest.dll.a is a library (import library) that knows how to load the .so file at run-time.
To be more Windows like you could drop the .so suffix and use .dll. So compiling your shared object this way would work too:
gcc -shared -o libtest.dll -Wl,--out-implib,libtest.dll.a libtest.c
And then compile the client(test) as we did above:
gcc test.c -I./include -LLib/ -ltest
Because you compiled the shared object above with -o libtest.dll the import library that is created will now search for libtest.dll instead of libtest.so when your program is executed.
Please note that at run-time Windows searches your path for shared object (or dll). So you will have to move your shared object (or dll) to the directory you are running your application from; or copy your shared object (dll) to somewhere on your path; or add your ./Lib/ directory to your path.
I am running Ubuntu 12.04 and I'm currently working on a project involving C, OpenGL, a teapot and input methods.
The problem started when I decided to have arrow keys as input. I checked to see the key codes for arrow keys but all of the arrows return 0. I looked up how to get this to work and I found conio.h. Unfortunately, it is an old DOS header that is not available for Linux. Then I found a substitute called ncurses.
After installing the necessary libraries, by following the build instructions closely, I #included curses.h in my main.c source. When I first tried to compile using gcc, I got the following errors:
main.o:main.c:function _Key: error: undefined reference to 'stdscr'
main.o:main.c:function _Key: error: undefined reference to 'wgetch'
main.o:main.c:function _Key: error: undefined reference to 'stdscr'
main.o:main.c:function _Key: error: undefined reference to 'wgetch'
I found a fix by adding -lncurses to the makefile like so:
SOURCES=main.c
main: main.o
gcc -lm -lGL -lGLU -lglut -lncurses main.o -o main
main.o: main.c
gcc -lm -lGL -lGLU -lglut -c main.c
But I was greeted by another error:
/usr/bin/ld: error: cannot find -lncurses
As well as the previous errors.
I have spent the last 2 days searching both the Ubuntu forums and StackOverFlow. Any help would be appreciated.
P.S. I don't know if this is important but when I try to run /usr/bin/ld I get this error:
ld: fatal error: no input files
For anyone with the same problem I had: I was missing the 32 bit libraries; I was compiling 32 bit on a 64 bit server which was missing the lib32ncurses5-dev package.
On Ubuntu I simply ran:
sudo apt-get install lib32ncurses5-dev
First off, you should put the libraries after the object file when linking. And not have them at all in the compilation of of the source file.
After that, if ncurses is not installed in a standard search folder you need to point out to the linker where it is, this is done with the -L command line option:
gcc main.o -o main -L/location/of/ncurses -lm -lGL -lGLU -lglut -lncurses
Try installing the ncurses-static package too, if you have only the ncurses-devel package installed in your Ubuntu OS.
If that solves your problem, plus if you add #Joachim's compiling instructions, you are off to a great start.
gcc main.o -o main -L/location/of/ncurses -lm -lGL -lGLU -lglut -lncurses
The linker can't find your shared library in it's search path. If you add the directory where your shared lib is to the LD_LIBRARY_PATH environment variable the linker should find it and be able to link against it. In that case you could omit the -L option to gcc:
gcc main.o -o main -lm -lGL -lGLU -lglut -lncurses
And it should compile fine.
EDIT:
Good to know that apt-get install libncurses5-dev fixes your problem.
FYI.
The LD_LIBRARY_PATH environment variable contains a colon separated list of paths that the linker uses to resolve library dependencies at run time. These paths will be given priority over the standard library paths /lib and /usr/lib. The standard paths will still be searched, but only after the list of paths in LD_LIBRARY_PATH has been exhausted.
The best way to use LD_LIBRARY_PATH is to set it on the command line or script immediately before executing the program. This way you can keep the new LD_LIBRARY_PATH isolated from the rest of your system i.e. local to the current running running instance of shell.
$ export LD_LIBRARY_PATH="/path/to/libncurses/library/directory/:$LD_LIBRARY_PATH"
$ gcc main.o -o main -lm -lGL -lGLU -lglut -lncurses