I'm trying to compile a sample LLVM program. The linker step uses this command.
llvm-config-3.2 --ldflags --libs
That results in the following command.
g++ -o bin/Debug/test-llvm obj/Debug/main.o -L/usr/lib/llvm-3.2/lib -lpthread -lffi -ldl -lm (a boat load of LLVM libraries here)
However, it fails to link. I get errors like this.
undefined reference to ffi_type_float
So, I added -lffi and -ldl to the end.
g++ -o bin/Debug/test-llvm obj/Debug/main.o -L/usr/lib/llvm-3.2/lib -lpthread -lffi -ldl -lm (a boat load of LLVM libraries here) -lffi -ldl
So, yes, they show up TWICE in the command... but it works this way. Why? They are clearly referenced earlier in the arguments.
One or more of the libraries appearing on the command line after -lffi and -ldl refer to symbol(s) defined in one of those libraries. But the linker has already finished scanning libffi and libdl and does not rescan them for these symbols. This circular dependency can be resolved by forcing the linker to scan those libraries again by re-listing their names at the end of the list.
A more scalable solution is to use --start-group archives --end-group option to list the libraries to link to. Quoting from the man page:
-( archives -)
--start-group archives --end-group
The archives should be a list of archive files. They may be either explicit file names, or -l options.
The specified archives are searched repeatedly until no new undefined references are created. Normally, an archive is searched
only once in the order that it is specified on the command line. If a
symbol in that archive is needed to resolve an undefined symbol
referred to by an object in an archive that appears later on the
command line, the linker would not be able to resolve that reference.
By grouping the archives, they all be searched repeatedly until all
possible references are resolved.
Using this option has a significant performance cost. It is best to use it only when there are unavoidable circular references between
two or more archives.
So your command line would look like this:
g++ -o bin/Debug/test-llvm obj/Debug/main.o -L/usr/lib/llvm-3.2/lib --start-group -lpthread -lffi -ldl -lm ... --end-group
Ah, I found the solution. Swapping the flags didn't actually change the order. I had to break it out into two separate calls.
llvm-config-3.2 --libs
llvm-config-3.2 --ldflags
And yeah, this is technically answered in that other question: Why does the order in which libraries are linked sometimes cause errors in GCC?
I still just think this question is relevant because doing what the docs told me to do led me into danger. :(
Why do I have to link these libraries twice
Because the order of archive libraries on command line matters, and yours is wrong.
Related
I found a lot of similar problems, but I was not able to apply any given solution for me. A few months ago, I worked on a project using the boost library. I compiled simply in the command line, as described on the boost website.
g++ -I pathToBoost file.cpp -o file -lboost_system -lboost_filesystem
The two required linkings to boost_system and boost_filesystem were also done. This worked perfectly, but now suddenly an error occurs when i tried to compile it again.
/usr/bin/ld: /tmp/ccM2BzEo.o: in function `boost::system::generic_category()':
file.cpp:(.text._ZN5boost6system16generic_categoryEv[_ZN5boost6system16generic_categoryEv]+0x7):
undefined reference to `boost::system::detail::generic_category_instance'
Well, it seems to me that there is an error linking the boost_system library. Since the same thing worked before, is a problem with the compiler possible?
I used
Boost 1.68.0
g++ (GCC) 8.2.1
ManjaroLinux 18.0.3
I hope that somebody can help me here and that I was not just too stupid to see a solution in another thread.
Greetings!
The order of libraries in linker command line is important. boost_filesystem depends on boost_system, hence the fix:
-lboost_filesystem -lboost_system
Alternatively, you can surround the list of libraries with --start-group and --end-group to make the linker re-scan the libraries multiple times until it either fails or resolves all symbols, so that no specific ordering of libraries in the command line is necessary. However, it may take longer to link. E.g.:
g++ -I pathToBoost file.cpp -o file -Wl,--start-group -lboost_system -lboost_filesystem -Wl,--end-group
Since you specify -I pathToBoost you also need to specify -L<path-to-boost-libs> -Wl,-rpath=<path-to-boost-libs>. Otherwise it uses headers from one version of boost from pathToBoost, but links wrong libraries from your system boost.
I am in the process of making a basic role-playing game. I want to include the Boost libraries statically so that the people who run my game do not need to have them. I researched and looked-up that all you have to do is add -static to the command-line compile, so my command is like this:
$ g++ -static -o karthas *.o -lncurses -lmenu -lboost_system -lboost_filesystem
But apparently the -static is affecting ncurses. I am getting a whole bunch of errors, most of which are undefined reference to 'SP'.
Is it possible to just do a static link to Boost and not ncurses? How would I go about doing that?
You can choose which libraries will be linked statically and which will be linked dynamically by putting either -Wl,-static or -Wl,-Bdynamic before their name.
For example, with:
g++ -o karthas *.o -Wl,-static -lmenu -lboost_system -lboost_filesystem -Wl,-Bdynamic -lncurses
The menu, boost_system and boost_filesystem libraries will be linked statically and ncurses dynamically.
(But you can also distribute the boost dlls with your executable, and not link anything statically).
But looking at this, it seems that you are not alone, either that, or I found your issue. But this, might have your solution, either way, good luck.
Btw, some boost libraries are little more than inline functions that are imported when included in the file.
I'm writing a small C program that uses librt. I'm quite surprised that the program won't compile if I place the link flag at the start instead of at the end:
At the moment, to compile the program I do:
gcc -o prog prog.c -lrt -std=gnu99
If I were to do the following, it will fail to find the functions in librt:
gcc -std=gnu99 -lrt -o prog prog.c
Yet, this works with other libraries. I found the issue when attempting to use a simple Makefile. make actually compiled prog.c without liking first (using -c flag) and then did the linking.
This is the Makefile:
CC = gcc
CFLAGS = -std=gnu99
LIBS= -lrt
LDFLAGS := -lrt
prog: prog.o
$(CC) -o prog prog.c -lrt -std=gnu99
The output I would get when typing make would be:
gcc -std=gnu99 -c -o prog.o prog.c
gcc -lrt prog.o -o prog
prog.o: In function `main':
prog.c:(.text+0xe6): undefined reference to `clock_gettime'
prog.c:(.text+0x2fc): undefined reference to `clock_gettime'
collect2: ld returned 1 exit status
make: *** [buff] Error 1
I have now crafted a Makefile that puts the linking at the end of the gcc line, however I'm puzzled why it doesn't work if the linking flag is at the start.
I would appreciate if anybody can explain this to me. Thanks.
As the linker processes each module (be it a library or a object file), it attempts to resolve each undefined symbol while potentially adding to its list of undefined symbols. When it gets to the end of the list of modules, it either has resolved all undefined symbols and is successful or it reports undefined symbols.
In your case, when it processed librt, it had no undefined symbols. Processing proc resulted in clock_gettime being an undefined symbol. gcc will not go back and look in librt for the undefined symbols.
For that reason, you should always have your code first, followed by your libraries, followed by platform provided libraries.
Hope this helps.
From the ld (the GNU linker) documentation (http://sourceware.org/binutils/docs/ld/Options.html#Options):
The linker will search an archive only once, at the location where it is specified on the command line. If the archive defines a symbol which was undefined in some object which appeared before the archive on the command line, the linker will include the appropriate file(s) from the archive. However, an undefined symbol in an object appearing later on the command line will not cause the linker to search the archive again.
So if you specify the library too early, the linker will scan it, but not find anything of interest. Then the linker moves on to the object file produced by the compiler and finds references that need to be resolved, but it has already scanned the library and won't bother looking there again.
I'm trying to load a shared library (plugin) I was provided (closed source) with dlopen under a Linux ARM platform. I'm trying to load this way:
void* handle = dlopen(<library_path>/<library_name>, RTLD_NOW);
The result is a failure with this message:
Failed to load <library_path>/<library_name>: undefined symbol: <symbol_name>.
I tried to look inside the library with nm, but it seems the lib was stripped, no symbol could be found. I also tried using readelf -s, and, in fact, I got this result:
12663: 00000000 0 NOTYPE GLOBAL DEFAULT UND <symbol_name>
By reading around, I get that readelf -s returns all the symbols, including those symbols defined in libraries referenced by it.
The answers to this question are not completely clear to me: is this a symbol which is supposed to be in the library and which is not there because it was compiled the wrong way or is this a symbol I'm supposed find somewhere else? The output of readelf -d seems to suggest I'm providing all the needed shared libraries. May this error be related to a mistake in the way I'm compiling my executable or is this something not related to the loader?
Also, I read about the meaning of each column, but those values are quite strange. How do you interpret that symbol description? Why is address 0? Why is type NOTYPE?
undefined symbol: X means always that X should be exported from one of loaded libraries, but it's not. You should find out in which library requested symbol is and link to it.
You should know that this message is always result of problem with library, it's not fault. Library should know how to get all it's symbols. If it doesn't you can link your executable to required library so when you load your plugin, requested symbol is already known.
This error might have more complex reason. In case when both plugin and main app are linking to library, then attempts to link it might end with undefined symbols anyway. This might happen if main app and plugin are using different version of library (namely plugin uses newer one). Then at the point of loading plugin older version is already loaded, so loader assumes everything is ok, but newer version might contain new symbols. If plugin uses them, you will get undefined symbol errors.
This problem appears also if the order of the static libraries in the linking command is wrong for the app. The Unix ld linker requires that the library which implements a function is specified after the library which refers the function.
I got this trouble when I was trying to build libtesseract shared library taking libz library from a custom location (not a standard libz from the host, but manually built from source as well). I have put an example below:
Wrong linking order (-lz before -llept):
$ g++ -fPIC -DPIC -shared -nostdlib /usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/5/crtbeginS.o -Wl,--whole-archive ....(some libs) -Wl,--no-whole-archive -L/home/build/jenkins/workspace/tesseract/zlib/bin/lib -L/home/build/jenkins/workspace/tesseract/leptonica/bin/lib -L/usr/lib/gcc/x86_64-linux-gnu/5 -L/usr/lib/x86_64-linux-gnu -lz -llept -lstdc++ -lm -lc -lgcc_s /usr/lib/gcc/x86_64-linux-gnu/5/crtendS.o /usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crtn.o -g -O2 -Wl,-soname -Wl,libtesseract.so.4 -o .libs/libtesseract.so.4.0.1
Check with "nm -D":
$ nm -D .libs/libtesseract.so.4.0.1 | grep deflateInit
U deflateInit_
Check with "dlopen":
Cannot load ./tesseract/src/api/.libs/libtesseract.so.4.0.1 (./tesseract/src/api/.libs/libtesseract.so.4.0.1: undefined symbol: deflateInit_)
It happens because the linker is processing in the loop all static libraries passed in the command line and skipping those which are not used by any of the preceeding ones. Since on the moment of checking of libz.a the linker sees that all of already checked libraries do not use any function from libz.a the linker just "forgets" libz.a.
Proper linking order (-lz after -llept):
$ g++ -fPIC -DPIC -shared -nostdlib /usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/5/crtbeginS.o -Wl,--whole-archive ....(some libs) -Wl,--no-whole-archive -L/home/build/jenkins/workspace/tesseract/zlib/bin/lib -L/home/build/jenkins/workspace/tesseract/leptonica/bin/lib -L/usr/lib/gcc/x86_64-linux-gnu/5 -L/usr/lib/x86_64-linux-gnu -llept -lz -lstdc++ -lm -lc -lgcc_s /usr/lib/gcc/x86_64-linux-gnu/5/crtendS.o /usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crtn.o -g -O2 -Wl,-soname -Wl,libtesseract.so.4 -o .libs/libtesseract.so.4.0.1
Check with "nm -D":
$ nm -D .libs/libtesseract.so.4.0.1 | grep deflateInit
000000000041fb5b T deflateInit_
000000000041fba3 T deflateInit2_
"dlopen" did not show this error this time.
I'm trying to link to a static library, libcovis.a. Everything looks fine but I still have
undefined reference to `CoViG_PublicDemo::MoInS::reset()'
I checked that the name exists in the library
$nm libcovis.a | grep reset
...
_ZN16CoViG_PublicDemo5MoInS5resetEv
...
I'm using linking arguments -L/path/to/libcovis.a -lcovis
What am I doing wrong ?
Edit:
The error might be something else, if do
gcc main.cpp -I/usr/include/opencv -I/usr/include/cairo -I../../Source -o slam -rdynamic -lGLU -lGL -lSM -lICE -lX11 -lXext -lglut -lXi -lxml2 -lboost_filesystem-mt -llapack -lblas -lcv -lcxcore -lcvaux -lhighgui -lcairo ../../Source/libcovis.a ../../Source/contrib/gnuplot_i/libcovis_contrib_gnuplot_i.a -lgl2ps
It works !
But when I'm in KDevelop using cmake, I doesn't work anymore. I use
CMAKE_EXE_LINKER_FLAGS:STRING=-rdynamic -lGLU -lGL -lSM -lICE -lX11 -lXext -lglut -lXi -lxml2 -lboost_filesystem-mt -llapack -lblas -lcv -lcxcore -lcvaux -lhighgui -lcairo /usr/local/src/CoViS-0.0.0-1/Source/libcovis.a /usr/local/src/CoViS-0.0.0-1/Source/contrib/gnuplot_i/libcovis_contrib_gnuplot_i.a -lgl2ps
CMAKE_CXX_FLAGS:STRING=-I/usr/local/src/CoViS-0.0.0-1/Source -I/usr/include/opencv -I/usr/include/cairo
The only difference I can see is that the paths are absolute and not relative, but if he couldn't find the libs, he would say it...
There are two different issues there, the first of which is the simplest, you have used the wrong compiler options. The -L option tells the linker to also look in the directory when looking for a library. The -l tells it to link the specific library. To link you would then use:
g++ -o test test.o -L/path/to -lcovis
or
g++ -o test test.o -l/path/to/libcovis.a
To force static linking if the same library is present as a dynamic library in the same directory.
The second potential issue is that the order of static libraries in the linker command line does matter, so that might also be an issue if there is a dependency on different static libs.
g++ -o test tests.o -ldependent -lprovider
The linker will process the libraries in order as they are in the command line, and from each static lib it will only pull those symbols that are required (with as much information as the linker has at that time). In the command line above, the linker will extract from dependent the symbols it needs for test.o, and that might in turn add new undefined symbols to the program (the dependencies of dependent). When it processes provider it will fill in those symbols. If the order was reversed in the command line, the symbols that are required by dependent but not by test.o would not be added to the executable, as the linker does not know that those symbols will be needed when processing provider.
Should the arguments be like -L/path/to/ -lcovis?
Besides, object files should be placed before libs, for example
g++ obj1.o obj2.o -L/path/to/ -lcovis.
If you see the link succeeding in one context but not another, I suspect the problem may be caused by the order in which the link operation is executed as the linker will discard symbols in a library if they're not needed at the point in which the library is referenced.
Here is a link explaining: http://www.network-theory.co.uk/docs/gccintro/gccintro_18.html
I've run into similar situations in the past the linking order was found to be the cause of the problem.