Suppose I have a third party library called somelib.a on a Mac running Mountain Lion with Xcode 4.4 installed. I want to get a dynamic library out of it called somelib.dylib. An appropriate Linux command would be:
g++ -fpic -shared -Wl,-whole-archive somelib.a -Wl,-no-whole-archive -o somelib.so
where -whole-archive and -no-whole-archive are passed to the linker.
When I do the equivalent for Mac:
g++ -fpic -shared -Wl,-whole-archive somelib.a -Wl,-no-whole-archive -o somelib.dylib
ld fails with an error:
ld: unknown option: -whole-archive
It seems that the ld on OSX is different from GNU ld. How do I have to modify above command so I will get the desired result?
Thank you in advance!
I found out the solution to my problem:
g++ -fpic -shared -Wl,-force_load somelib.a -o somelib.dylib
The required argument is -force_load:
Which needs to be followed by a single library you wanna ensure gets loaded.
I mean, it needs to be repeated for each library (unlike -noall_load approach, which wrapped them).
For example, -Wl,-force_load libYetAnotherFile.a (where -Wl, part is only required because we don't pass parameter directly to linker).
Note that Old answer (before edit) was using -noall_load instead, but nowadays that causes a linker error (as -noall_load has been removed, was obsolete previously).
Note: A link for the documentation of the OSX ld linker.
http://www.unix.com/man-page/osx/1/ld/
I know it is late to give an answer for this, but I do not have enough reputation to make a comment on #hanslovsky answer.
However, it helps me a lot to have the docs of the options too.
It helps what the options do exactly, and that other options the ld linker also has.
So I just wanted to share with others who finds linking an issue.
UPDATE:
After the comment from #GhostCat I have decided to expand my answer.
The docs for -all_load is:
-all_load
Loads all members of static archive libraries.
So it loads for all static libraries that you note.
If you want something similar to --whole-archive and --no-whole-archive, then you need to use -force_load and -noall_load.
-force_load "path_to_archive"
Loads all members of the specified static archive library. Note: -
all_load forces all members of all archives to be loaded.
This option allows you to target a specific archive.
-noall_load
This is the default. This option is obsolete.
Then you can define which libraries to fully load with -force_load and then later turn it off again with -noall_load.
According to the ld manual, -noall_load is the default and is ignored. (If you use it, you get an error message: ld: warning: option -noall_load is obsolete and being ignored)
Apparently the way to get -all_load to apply to only one library is as follows:
-Wl,-force_load,somelib.a
Related
I am trying to build a project on Mac OS X using clang and it fails on linking step with ld: unknown option: --no-undefined, which is meant to built with gcc.
What's the clang equivalent for this option? (Please, don't advise to use gcc instead of clang.)
Also, a more generic question, is there any resource where one can find some kind of a "mapping" between gcc and clang (linker) options differences?
Thank you.
OS X uses a different linker. As #rubenvb points out, it's probably the one from Apple's binutils. If you run man ld, and search for "undefined", you will find this option:
-undefined treatment
Specifies how undefined symbols are to be treated. Options are: error, warning, suppress, or dynamic_lookup. The default is error.
So, replace -Wl,--no-undefined with -Wl,-undefined,error. Also, use the Force, Luke.
This is strange because I was able to get the error below to go away by removing the reference to libm.
gcc -o example example.o -Wl -L/home/kensey/cdev/lib -L/usr/lib/x86_64-linux-gnu -lmysqlclient -lpthread -lz -L/usr/lib/x86_64-linux-gnu -lm -lrt -ldl -lcdev -L/home/kensey/www.tools/gplot-lib -lgplot -L/home/kensey/www.tools/gd1_3ret -lgd -lxml2 -lcurl
/usr/bin/ld: /home/kensey/www.tools/gplot-lib/libgplot.a(set.o): undefined reference to symbol 'floor##GLIBC_2.2.5'
/usr/bin/ld: note: 'floor##GLIBC_2.2.5' is defined in DSO /usr/lib/x86_64-linux-gnu/libm.so so try adding it to the linker command line
/usr/lib/x86_64-linux-gnu/libm.so: could not read symbols: Invalid operation
collect2: ld returned 1 exit status
So, if I remove the -lm part of the command, I do not get the error. However, I wonder if anyone knows as to why removing a reference to a library that is needed would fix this. How does the linker know which library to look in? Also - is there a way to query a built executable and say 'which library did you resolve the reference to 'floor'? obviously, there is something going on that I don't understand, and that bothers me...
The explanation to what's happening is very simple:
Your libgplot.a depends on libm.so, yet the order of -lm and -lgplot on the link line is wrong.
The order of libraries on the link line does matter. In general, system libraries (-lpthread, -lm, -lrt, -ldl) should follow everything else on the link line.
When you remove -lm from the link line, libm.so.6 is still pulled into the link by some other library that appears later on the link line (libgd, libxml2 or libcurl) because that library depends on libm.so.6. But now libm.so.6 is in correct place on the link line, and so everything works.
if I put -lm at the end of the link command, listing it as the last library, I do not get the error.
That confirms above explanation.
I've solved the same problem with export LDFLAGS="$LDFLAGS -lm"
Perhaps, your library search paths (/usr/local/lib/ or /usr/lib/, ...) do not contain 64bit libm so gcc cannot locate it if you specify with l flag. If you only specify only the directory it looks like it can find the right one. So you can try:
LD_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu
and use -lm
Hard to tell. Because there are custom library directories in the command line it's conceivable that -lm links an incompatible alternative version. Without -lm the linker could pull in another version of it because it's needed by one of the libraries you link.
To make sure strace both invocations and see where libm.so is coming from in both cases.
BTW, -Wl switch seems to do nothing and -L/usr/lib/x86_64-linux-gnu is mentioned twice.
Just to add to the list of answers, http://fedoraproject.org/wiki/UnderstandingDSOLinkChange It is informative. It isn't relevant to the question asked above, but, the explanation relates to the error message /usr/bin/ld: note: 'some_reference' is defined in DSO some.so so try adding it to the linker command line
One explanation could be:
It's possibly there is a weakly linked function foo defined outside of libm that is replaced by a strongly linked version of foo defined inside libm, and it is this strongly linked version that calls the undefined function.
This would explain how adding a library can cause an undefined function error.
I just ran into a similar problem; I remember that the order of the libraries did not matter (at least not in the cases I worked with) in the past for gcc. In this question here somebody noticed that the behaviour seems to have changed between 4.4 and 4.5 .
In my case, I got rid of the error message by doing the linking at:
g++ -Wl,--copy-dt-needed-entries [options] [libraries] [object files] -o executable-file
I faced the similar issue because I had manually updated the dev toolchain on my centOS machine to solve a VScode Remote dependency and was linking C++ library with c code.
In my case, I solved this by adding in the Makefile:
LDFLAG=-Wl,--copy-dt-needed-entries
I also pointed my gcc to the version I wanted (After updating toolchain, gcc pointed to the toolchain : /opt/rh/devtoolset-2/root/usr/bin/gcc)
CC=\usr\bin\gcc which is (gcc version 4.4.7)
Use this:
administrator#administrator-Veriton-M200-H81:~/ishan$ gcc polyscanline1.cpp -lglut -lGLU -lGL -lm
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.)
and sorry for my not really good english. I'll try my best :)
I am trying to compile a addin for my Casio graphic calculator in C. This works without problems when using the official SDK. Because it is only available for Windows, I want to use gcc.
So I got sh-rtems-gcc and it's binutils from macports and tried to compile my program according to this instructions. I copy-pasted the described addin.ld and crt0.s and placed my main.c and libfxsys.a (from the same guys as the instructions mentioned above) in the same directory. The sub-dir include contains fxsys' headers. I verified the presence of all the functions of the library in the .a file with nm.
When using this command for compilation:
sh-rtems-gcc-4.2.3 -m3 -mb -nostdlib -I./include -c crt0.s main.c
Everything works fine. But then im trying to link:
sh-rtems-gcc-4.2.3 -m3 -mb -nostdlib -L. -o myaddin.elf -Taddin.ld crt0.o main.o -lfxsys
and get the following error:
main.o: In function `__main':
main.c:(.text+0x248): undefined reference to `_Bdisp_AllClr_VRAM'
...
... (--- cut 16 other errors in the same format ---)
...
main.c:(.text+0x360): undefined reference to `_Sleep'
./libfxsys.a(locate.o): In function `_locate':
locate.c:(.text+0x28): undefined reference to `_locate_OS'
collect2: ld gab 1 als Ende-Status zurück
All the missing symbols are in the libfxsys.a. I have verified this with nm.
I have already played with the positions of the library in the command, as this is often mentioned as a source of failure in other posts found in google, but without success. I also tried adding and removing the -lgcc option that is used in the above mentioned instructions, without success.
My Host-Machine is a Intel Mac, OS X 10.6
Because I have no idea how to solve this problem, and get to compile my program, I have to ask: What am I doing wrong? How can I compile my program without using the SDK?
Thanks in advance,
xythobuz
Edit:
I have also tried linking with:
sh-rtems-ld -EB -L. -o myaddin.elf -Taddin.ld crt0.o --start-group main.o libfxsys.a --end-group
But it produces the same output as above.
I can't say the exact problem, but would investigate like this:
Find the library that contains the missing symbols. Use nm to see symbol names
Once you know which library contains the symbols make sure you're linking to it, and in the correct order. Try using recursive symbol resolution options -( -) with your linker.
I am trying to link an application with multiple static libraries in GCC.
There are two libraries that cause problems. Libsupport provides a terminal for the application. It relies on libcpu to provide a serial link, timing and syncronisation. Libcpu relies on libsupport to provide queueing for serial data and more.
If I specify libsupport first when linking libcpu cannot be linked with the queue functions. Is I specify libcpu first lib support can not link the serial link (and more) functions.
It looks like GCC parses a library only once and discard any unused objects.
Can I ask gcc to parse libraries multiple times or to include all objects?
gcc ... -lsupport -lcpu -lsupport -lcpu
-> Each mention of a library will cause resolution of libraries that came before it (but not necessarily ones specified afterwards), which is why you may need to specify more "-lsupport -lcpu" in future.
Alternatively, try --start-group -lsupport -lcpu --end-group once.
Here is detailed explanation of why either repeating libraries or using --start/--end-group is required in this situation.
You can normally specify a library more than once to get around this kind of problem, e.g.
$ gcc ... -lsupport -lcpu -lsupport ...
Note that --start-group / --end-group are linker options which are unknown to the compiler, so if you use gcc / g++ for linking, you should specify them as:
gcc ... -Wl,--start-group -lsupport -lcpu -Wl,--end-group
Otherwise you will get:
gcc.exe: error: unrecognized command-line option '--start-group'
gcc.exe: error: unrecognized command-line option '--end-group'