I have written a small code that I want to compile with a combination of static and dynamic libs. The code uses functions from hdf5 and exodusII (a specialist CAE lib) as well as math, and of course good-old stdio.
To make the binary highly portable, I wanted to link hdf5 and exodusII statically into the code, but leave math and libc as shared, so that the code is optimised on different platforms.
I cannot work out what the correct method is to compile something like this. I already have tried:
gcc -lm -lc -fPIC test1.c /usr/lib/libexodus.a /usr/lib/libhdf5.a -Wl,-pie
This gives the error:
/usr/lib64/crt1.o: relocation R_X86_64_32S against '__libc_csu_fini' can not be used when making a shared object; recompile with -fPIC
/usr/lib64/crt1.o: could not read symbols: Bad value
I have also tried:
gcc -c test1.c (WORKS!)
ld /usr/lib/libhdf5.a /usr/lib/libexodus.a -lm -lc test1.o
Which gives a warning of not being able to find an entry symbol _start followed by a whole lot of undefined reference errors to the libexodus functions in test1.c. (I have checked libexodus.a with nm, and the functions being reported do actually exist in the archive.
I would really appreciate a hand in this. I am not overly experienced in using static libs, but for this application, I think it is the best choice, so long as I can work out a reliable way of compiling and linking.
The error was in the linking order. I have now learned that the linking order works like babushka dolls where the library at the top of the dependency tree comes first, and the most general library comes last.
For future reference, in the end, the working build command was as follows:
gcc test1.c -lexodus -lnetcdf -lhdf5_hl -hdf5 -lcurl -ldl -lm
What I don't really understand is that when I had built the exodus library as a shared library, I only had to link against the shared library, and the dependency libraries (-lnetcdf -lhdf5_hl -lhdf5 -lcurl) were not specified; however, with the static compilation of the exact same library, I now need to link all the libraries explicitly.
If someone has an answer to this behaviour, it would be helpful for my understanding and very appreciated, but as I can continue coding with this current build method, it is not an urgent matter.
Related
I have inherited a Makefile which builds a .so file. It is linking with -lcrypto from OpenSSL on Ubuntu with gcc 4.7.4. Critically, it is NOT linking with -lssl nor -ldl, and when I run nm -g thelib.so, it only has the ~15 symbols from openssl crypto. However, they are all U (undefined).
I'm refactoring the Makefile on another Ubuntu machine. When I link with -lcrypto, it fails due to undefined symbols needed from dl. When I add linking to -ldl, those errors go away and linking succeeds. However, my .so file is 1.5 MB bigger than the original, and there are at least a hundred symbols related to SSL, which are all T (defined), which seem to indicate that -lssl is happening implicitly somehow.
While it would seem prudent and good that they are all defined in my case, I need to figure out how to produce the same result just as it is.
So, my question is, how does one get GCC to allow the linking of a .so file and accept undefined references? I've compared our commands, and there are little differences which I've tried to eliminate, but nothing seems to work. I read that it might be related to -Wl,--no-as-needed, but i'm using that. Here's my linker flags.
g++ -shared -o mylib.so myobjs.o -fPIC -lstdc++ -lm -z defs -Wl,-soname,mylib -Wl,--no-as-needed -lpthread -lcrypto -lz
On the other system (the one with the larger result), OpenSSL has apparently not been built as a shared object, only as a static library (but maybe as PIC, so that you can link the result into a shared object). You will have to install the packages that provide the shared object and the corresponding .so symbolic link.
I'm attempting to do a release of some software and am currently working through a script for the build process. I'm stuck on something I never thought I would be, statically linking LAPACK on x86_64 linux. During configuration AC_SEARCH_LIB([main],[lapack]) works, but compilation of the lapack units do not work, for example undefiend reference to 'dsyev_' --no lapack/blas routine goes unnoticed.
I've confirmed I have the libraries installed and even compiled them myself with the appropriate options to make them static with the same results.
Here is an example I had used in my first experience with LAPACK a few years ago that works dynamically, but not statically: http://pastebin.com/cMm3wcwF
The two methods I'm using to compile are the following,
gcc -llapack -o eigen eigen.c
gcc -static -llapack -o eigen eigen.c
Your linking order is wrong. Link libraries after the code that requires them, not before. Like this:
gcc -o eigen eigen.c -llapack
gcc -static -o eigen eigen.c -llapack
That should resolve the linkage problems.
To answer the subsequent question why this works, the GNU ld documentation say this:
It makes a difference where in the command you write this option; the
linker searches and processes libraries and object files in the order
they are specified. Thus, foo.o -lz bar.o' searches libraryz' after
file foo.o but before bar.o. If bar.o refers to functions in `z',
those functions may not be loaded.
........
Normally the files found this way are library files—archive files
whose members are object files. The linker handles an archive file by
scanning through it for members which define symbols that have so far
been referenced but not defined. But if the file that is found is an
ordinary object file, it is linked in the usual fashion.
ie. the linker is going to make one pass through a file looking for unresolved symbols, and it follows files in the order you provide them (ie. "left to right"). If you have not yet specified a dependency when a file is read, the linker will not be able to satisfy the dependency. Every object in the link list is parsed only once.
Note also that GNU ld can do reordering in cases where circular dependencies are detected when linking shared libraries or object files. But static libraries are only parsed for unknown symbols once.
i just compiled chironfs on my new ubuntu 12.10 server and got the following error:
gcc -Wall -W -Wmissing-prototypes -g -O2 -DFUSE_USE_VERSION=25 -D_FILE_OFFSET_BITS=64 -I/usr/local/include -g -O2 -lm -lfuse -o chironfs chironfs.o chiron-conf.o chirondbg.o chironfn.o
chironfs.o: In function `chiron_init':
/root/chironfs-1.1.1/src/chironfs.c:2000: undefined reference to `pthread_create'
chironfs.o: In function `get_rights_by_name':
/root/chironfs-1.1.1/src/chironfs.c:452: undefined reference to `fuse_get_context'
the pthread error tells me that -lpthread is missing, but the fuse error is kinda weird cause -lfuse is being used
i found a solution here which suggests to put libraries after object files
so i removed -lfuse and added -lfuse -lpthread at the very end of the line
now it compiles without an error and it seems that this is the way it should be: library after object files
my question is:
why is the parameter order relevant for gcc/ld? i tought gcc just parses the params like every other application and may forward the necessary params to ld or such
in general: anyone knows facts or tips for gcc parameter ordering and maybe a bit background
information about why it is needed this way?
thanks
The order of objects and libraries is relevant to the linker (called implicitly by the compiler when creating an executable). When the linker, in its left-to-right scan, finds a use of a name it doesn't know about it starts looking for a definition from that point on. If a definition passes by, it doesn't remember it for later use.
GCC itself passes parameters to ld in relatively transparent fashion
Your question really is about how ld linker works. For simplicity and to handle circular references without infinite loops, it passes through the list of libraries only once, resolving references. So if your reference occurs somewhere and it hasn't seen the library that contains it yet then it's just an error.
Also please read this discussion, where this question is discussed in greater details.
I have a C project using several object files that needs to be linked in a specific order to find all needed symbols.
For example this command works fine (lib2.o depends on lib1.o etc.)
gcc -o my_app main.o lib1.o lib2.o lib3.o -lm
but
gcc -o my_app main.o lib3.o lib2.o lib1.o -lm
ends with undefined reference to `my_variable' errors.
This is a known behavior and can be solved for example by adding these objects to GROUP section in a linker script.
Now I'd like to share these object as a static library with my colleagues. So...
ar -rcs mylib.a lib1.o lib2.o lib3.o
gcc -o my_app main.o mylib.a -lm
Unfortunately this gives the same undefined reference errors like the specifying the objects in incorrect order.
I have not found any linker or archiver options to make it working and also no solution by googling even if I think that this problem should be relatively common.
Do please anybody know a solution?
regards
Jan
This might be a link order problem. When the GNU linker sees a library, it discards all symbols that it doesn't need. It also does that in the sequential order form left to right.
Recent versions of gcc/ld default to linking with --as-needed flag.
This means if you write -lmylib.a before the C file the library will automatically get excluded (the order matters when testing if things are "needed" like this)
You can fix this with either:
gcc -L. -o example example.c -lmylib.a
gcc -L. -Wl,--no-as-needed -o example example.c -lmylib.a
The latter of which passes --no-as-needed to the linker, which would cause the library to still be linked, even if you didn't call any function external from it.
Your error implies that the problem is in one of your lib?.o files [lib{later}.o depends on lib{earlier}.o]
How did you manage to compile them?
Were there any compilation warnings?
It has been a while since I used C, but I think that you will need to include dependent libraries within the library that has the dependency - this may be the reason why you can't find too many references to the problem, because it does not really exist.
I am trying to link a C++ module using GCC, essentially like this:
gcc -c hello.c
g++ -c world.cpp
gcc -ohello -lstdc++ hello.o world.o
Note that I use -lstdc++ to link the C++ module in, so that I can use gcc instead of g++. The problem is that I'm getting the error:
undefined reference to `operator new(unsigned long)'
(Assuming that world.cpp contains at least one call to new.)
This error is fixed if I put -lstdc++ at the end of the linker line, like this:
gcc -ohello hello.o world.o -lstdc++
I am aware that this question has been asked many times here, but I have a special requirement. I am not directly calling GCC. I am using a build system for a different programming language (Mercury) which is calling GCC on my behalf, and I can't easily modify the way it calls GCC (though I can specify additional libraries using the LDFLAGS environment variable). So I have two additional requirements:
I cannot use g++ to link (only gcc) -- that is why I am doing the -lstdc++ trick above rather than simply linking with g++).
I don't think that I can control the order of the linker commands -- Mercury will put the .o files on the command-line after any libraries.
I understand the basic reason why the order is important, but what is baffling me is why did this break now? I just updated to Ubuntu 11.10 / GCC 4.6.1. I have been successfully compiling this program for years using precisely the above technique (putting -lstdc++ first). Only now has this error come up. An unrelated program of mine links against OpenGL using -lgl and that too broke when I upgraded and I had to move -lgl to the end of the command-line. I'm probably going to discover that dozens of my programs no longer compile. Why did this change? Is there something wrong with my new system or is that the way it is now? Note that these are ordinary shared libraries, not statically linked.
Is there anything I can do to make GCC go back to the old way, where the order of libraries doesn't matter? Is there any other way I can convince GCC to link libstdc++ properly without moving it after the .o files on the command-line?
If Mercury puts object files after libraries, Mercury is broken. Libraries belong after object files - always. You may sometimes get away with the reverse order, but not reliably. (Static libraries must go after the object files that reference symbols in the static library. Sometimes, a linker will note the symbols defined by a shared library even when none of the symbols are used; sometimes, the linker will only note the shared library symbols if the shared library provides at least one symbol.)