I have developed a shared library B.so, which depends on A.so.
When I write a program test.exe using B.so, but there is a compile error, it said that some symbols(the symbols are in A.so) not found.
My build line:
gcc test.c -o test.exe -fPIC -I./ -L./ -lB
Do we have a method that, how to build test.exe successfully,but not link A.so.
how to build test.exe successfully,but not link A.so.
There are at least two method:
export a proper LD_LIBRARY_PATH
export LD_LIBRARY_PATH=/path/to/A
gcc ... -lB
using ld option -rpath (discovered by the asker #iceKing himself)
gcc -Wl,-rpath=/path/to/A ...
In both case, ld will automatically search for libraries depended by these libraries list explicitly.
Related
I am having issues linking a library (termbox) when compiling. I get the error:
make: *** No rule to make target `termbox.h', needed by `test.o'. Stop.
Makefile:
edit: test.o
gcc -Wall -o edit test.o
test.o: test.c termbox/src/termbox.h
gcc -Wall -c test.c -ltermbox/src
Include:
#include "termbox/src/termbox.h"
I have also tried using the compiled library but ran into similar issues. Do I have to use some sort of combination of specifying the header file and the location of the compiled library?
The directory of my termbox folder is in the same directory as test.c.
Thanks!
You have managed to compile and include the header file for the library, but you did not yet tell the compiler where the code (definitions) are - i.e. you did not tell it to link in the library yet.
You will need to do that next, this is done in a similar way to telling the linker what files to link, but with some extra syntax. It appears to be a static library (.a suffix) so you can link like this:
test.o: test.c termbox/src/termbox.h
gcc -Wall -c test.c -Itermbox/src -Lsrc -ltermbox
Where -L... specifies where libraries can be found and -l... specifies the library name to link to minus the lib prefix and the .a or .so suffix. Also note that order is important, so leave the library linkage at the end.
More on library linking order here
UPDATE
Sorry I added the linking to the wrong line! - here is the updated answer:
# The linker stage
edit: test.o
gcc -Wall -o edit test.o -Lsrc -ltermbox
# Compile stage
test.o: test.c termbox/src/termbox.h
gcc -Wall -c test.c -ltermbox/src
I am trying to create a conda package that includes c code that have to compile with -lz. However, when the package is building, ld cannot find zlib even though I provide it with any paths possible.
As I understand, conda creates almost empty environment, and then fills it with necessary libraries and tools. It also installs zlib, so that there is zlib.h in $BUILD_PREFIX/include/ and libz.so, libz.a in $BUILD_PREFIX/lib.
Compilation itself looks like
$BUILD_PREFIX/bin/x86_64-conda_cos6-linux-gnu-cc -fPIC -g -Wall -O2 -Wc++-compat main.o -o <name> -L. -l<name> -lm -lz -lpthread
x86_64-conda_cos6-linux-gnu-cc is gcc version 7.3.0, and it calls ld defined here as $BUILD_PREFIX/bin/x86_64-conda_cos6-linux-gnu-ld. Then ld falls with an error cannot find -lz.
I tried using
export C_INCLUDE_PATH="$BUILD_PREFIX/include"
export LIBRARY_PATH="$BUILD_PREFIX/lib"
export LD_LIBRARY_PATH="$BUILD_PREFIX/lib"
export LD_PRELOAD="$BUILD_PREFIX/lib/libz.so"
in any combinations, but that did not work.
Are there any other ways to show ld path to the library?
I am using GNU g++ 4.9.2 compiler both on Solaris and Linux.
On Solaris platform, to create a shared library from a source file (a.c), I use the following command:
g++ -G a.c -o a
a becomes a shared library
a.c contains the following code:
void libfn1()
{
}
If I try not to use -G option i.e. compile as:
g++ a.c -o a
It gets a linker error: Undefined Symbol main
But, on Linux, if I do the same thing: it says:
g++: error: unrecognized command line option -G
How to create a shared library on Linux? What is the g++ option for that?
The g++ documentation says this:
These additional options are available on System V Release 4 for
compatibility with other compilers on those systems:
-G Create a shared object. It is recommended that -symbolic or -shared be
used instead.
Normally you want to generate position independent code too, for a shared library, with the -fPIC flag.
So you'd want to run:
g++ -fPIC -shared a.c -o liba.so
The process to create a shared library on a Linux system is a bit different.
Shared libraries on Linux are .so (for "shared object") files, not .g.
You do it like this:
First, you need to generate position-independent code from your C++ source. That is so your library works from wherever it is called. To do that, you should use g++'s -fPIC flag.
So, for each source file you want to be included in your library, you should only compile it to position-independent code. We'll handle linking later.
For each source file:
g++ -c -fPIC file.cpp
(The -c flag tells g++ "compile, don't link").
for each file.cpp, g++ will generate file.o, an object file containing position-independent code.
To then build the object files into a shared library, you should use
g++ -o -shared myLibrary.so {all_object_files}
So if you have file1.o, file2.o and file3.o, the command would be:
g++ -shared -o myLibrary.so file1.o file2.o file3.o
Of course, if you have a lot of files this can get pretty tedious, so you should write a Makefile to automate this process for you! Here's an example:
myLibrary.so: file1.o file2.o file3.o
$(CXX) -shared $^ -o $#
file1.o file2.o file3.o : CXXFLAGS+=-fPIC
a.so defines function A(), b.so defines function B() and calls A() that is defined in a.so. b.so is linked to a.so as below
gcc -fPIC -shared B.c -o libb.so -la
Now I created a binary which is calling B() that is defined in b.so
gcc mybin.c -o mybin -lb
gcc is checking for every symbol in b.so and throws error saying A() is not defined.
gcc mybin.c -o mybin -lb -la
The above works but I had to link mybin with a.so even though it is not directly related to a.so. My requirement is that if b.so is properly linked with a.so, linking mybin with just b.so should work.
Is this possible ??
When linking the executable the linker wants to know that the libraries needed by libb.so exist so it can check they resolve any undefined references in libb.so
The linker looks for the required libraries in the usual places, so if that wouldn't find liba.so then you can tell the linker where to look by using LD_LIBRARY_PATH as shown by another answer, or by using the linker option that exists specifically for this purpose, -rpath-link
gcc mybin.c -o mybin -lb -Wl,-rpath-link=.
(The -Wl, prefix is how you tell GCC to pass an option to the linker, which is needed for linker options that GCC doesn't know about directly.)
Alternatively, you can tell the linker to allow undefined symbols in libb.so in which case it doesn't try to find liba.so to resolve the reference to A(), and trusts that you'll link correctly and ensure the library is available at run-time. That is done with the --allow-shlib-undefined option:
gcc mybin.c -o mybin -lb -Wl,--allow-shlib-undefined
However, it's generally better to let the linker check that all symbols are defined, and tell it how to find the required libraries, as it finds real problems sooner.
The -rpath-link option only tells the linker where to look for additional shared libraries, it has no visible effect on the linked executable (i.e. it doesn't record the path to the library in the executable anywhere). Another alternative is to create libb.so so that it contains the knowledge of how to find liba.so embedded within it. That is done with the -rpath linker option, e.g. if liba.so is in /some/path you could do:
gcc -fPIC -shared B.c -o libb.so -la -Wl,-rpath=/some/path
This puts a DT_RPATH tag in libb.so and the linker will use that to find its dependencies:
readelf -d libb.so | fgrep RPATH
0x000000000000000f (RPATH) Library rpath: [/some/path]
Now you can link the executable without needing any knowledge of liba.so, the linker will see that libb.so needs liba.so and will use the RPATH to find it:
gcc mybin.c -o mybin -lb
This works fine if the path /some/path/liba.so is fixed, but it might not be true that the library is found in the same location during development and after your executable is deployed. In that case you can still use -rpath-link for the executable to tell the linker where to look for it during linking, and rely on the RPATH to find it at run-time. Or you can use the special string $ORIGIN in the RPATH which the dynamic linker expands to the location of the object containing the RPATH, e.g. if liba.so and libb.so are always in the same directory, you can link libb.so like this (note the quotes to prevent the shell expanding $ORIGIN):
gcc -fPIC -shared B.c -o libb.so -la '-Wl,-rpath=$ORIGIN'
readelf -d libb.so | fgrep RPATH
0x000000000000000f (RPATH) Library rpath: [$ORIGIN]
The missing bit was the LD_LIBRARY_PATH:
export LD_LIBRARY_PATH=.
gcc -fPIC -shared a.c -o liba.so
gcc -fPIC -shared b.c -o libb.so -la
gcc mybin.c -o mybin -lb -L.
The reason -L does not work seems it that this flag it used to « Add directory dir to the list of directories to be searched for -l » , see the GCC doc. And libba.so is not specified in a -l.
Here are the steps:
gcc -fPIC -shared a.c -o liba.so
gcc -fPIC -shared b.c -o libb.so
gcc mybin.c -o mybin -lb -la -L. # -L to look for the directory to load .so files
Then make sure you do:
export LD_LIBRARY_PATH=<your_directory>
You need to have liba.so and libb.so mentioned in gcc mybin.c -o mybin -lb -la -L. as the function A() needs to be loaded at runtime. b.so IS NOT LINKED with a.so. Linking happens that runtime in shared library. They are compiled and any reference to functions or extern variables are not resolved.
If you want to include b.so but not a.so then compile the b as static library thereby it loads a into its binary. And then when you compile mybin you will only need b.lib
I have got the object-file from source code using MinGW.
But on linking:
ld -o test.exe test.o
I get errors, for example the following:
undefined reference to printf
First, why are you using ld directly?
The following is an excerpt from the "GCC and Make" tutorial found at http://www3.ntu.edu.sg/home/ehchua/programming/cpp/gcc_make.html.
Compile and Link Separately
The above command compile the source file into object file and link with other object files (system library) into executable in one step. You may separate compile and link in two steps as follows:
// Compile-only with -c option
> g++ -c -Wall -g Hello.cpp
// Link object file(s) into an executable
> g++ -g -o Hello.exe Hello.o
Note g++ (you can substitute gcc if you are using C and not C++) is used both for compiling and linking. ld is not used at all.
The benefit of using g++ or gcc to link is that it will link with default libraries, such as the one you need to link with for printf, automatically.
To link with other libraries, you specify the library name with the -l parameter, as in -lmylib.
We can view commands ran by compiler via command
c99 -v test.o
We'll get some text. All after string which contains "COLLECT_CGG_OPTIONS" will be arguments of ld.
But size of executable file is much more then size of file got by previous way.