Proper way to link a static library using GCC - gcc

Why is it that some static libraries (lib*.a) can be linked in the same way that shared libraries (lib*.so) are linked (ld -l switch), but some can not?
I had always been taught that all libraries, static or not, can be linked with -l..., however I've run into one library so far (GLFW), which does nothing but spew "undefined reference" link errors if I attempt to link it this way.
According to the response on this question, the "proper" way to link static libraries is to include them directly, along with my own object files, rather than using -l. And, in the case of the GLFW library, this certainly solves the issue. But every other static library I'm using works just fine when linked with -l.
So:
What could cause this one library to not work when linked rather than included directly? If I knew the cause, maybe I could edit and recompile the library to fix the issue.
Is it true that you're not supposed to link static libraries the same way you link shared libraries? (And if not, why not?)
Is the linker still able to eliminate unused library functions from the output executable when the library is directly included in this way?

Thanks for the replies! Turns out the problem was due to link order. Apparently, if you use a library which in turn has other library dependencies, those other dependencies must be listed after the library, not before as I had been doing. Learned something new!

Have you cared to indicate to GCC the path of your library (using -L) ? By using -l solely, GCC will only be able to link libraries available in standard directories.
-L[path] -l[lib]

The correct way to link a static library is using -l, but that only works if the library can be found on the search path. If it's not then you can add the directory to the list using -L or name the file by name, as you say.
The same is true for shared libraries, actually, although they're more likely to be found, perhaps.

The reason is historical. The "ar" tool was original the file archive tool on PDP11 unix, though it was later replaced entirely by "tar" for that purpose. It stores files (object files, in this case) in a package. And there's a separate extension containing the symbol table for the linker to use. It's possible if you are manually managing files in the archive that the symbol table can get out of date.
The short answer is that you can use the "ranlib" tool on any archive to recreate the symbol table. Try that. More broadly, try to figure out where the corrupt libraries are coming from and fix that.

Related

using my own static/dinamic library: HOW TO compile and link against (the right way to do the things properly)

Sorry for this newbie question.
Context:
I have just created my own library (using CMake):
libmyownsomething.a <--- static version of the compiled library
libmyownsomething.so <--- dinamic version of the same library
libmyownsomething.h <--- the header file to be included in other project
Questions:
Where is the right place where the files should be placed? ( I guest /usr/local/include/ and /usr/local/lib/
How to compile other lib/projects against this one by inserting only #include <myownsomething.h> and a right flag LDFLAGS=-lmyownsomething?
To be able to link agains your library with just -lmyownsomething, you need to have libmyownsomething.so (or .a, for static linking) in one of the directories you linker searches by default.
I found this in texinfo documentation for GNU ld (library search path in linker script):
'SEARCH_DIR(PATH)'
The 'SEARCH_DIR' command adds PATH to the list of paths where 'ld'
looks for archive libraries. Using 'SEARCH_DIR(PATH)' is exactly
like using '-L PATH' on the command line
Now, GNU ld (ld.bfd to be precise) uses a default linker script, which can be obtained with --verbose. Let's see what search dirs there are by default (on my system, anyways -- that might well depend on configuration; if you are going to distribute your library, you probably want to make the most portable choice):
$ ld --verbose |& grep SEARCH_DIR
SEARCH_DIR("/usr/x86_64-pc-linux-gnu/lib64"); SEARCH_DIR("/usr/lib"); SEARCH_DIR("/usr/local/lib"); SEARCH_DIR("/usr/x86_64-pc-linux-gnu/lib");
To answer the question about #includeing files, you need to consult the compiler documentation, or perhaps the POSIX standard. (However, I'd recommend either going with the simplest choices -- see below -- or providing a configurable way to install your files e.g. with --prefix build time option. Then the user/packager can decide the best place to put them for themselves. But nothing keeps you from providing sane defaults. Same goes for libraries, but I tried to address that part of the question exactly how it was asked.)
Generally, this stuff varies from system to system, but they usually follow the Filesystem Hierarchy Standard. I think, /usr/include and /usr/lib is the safest choice. Another good practice is using e.g. pkgconf mechanism.
Hope this helps. I really should have asked about your use-case first: who are you going to distribute your software to, and how? Anyway, be sure to post comments. Also, I wonder if this is Stackoverflow material; perhaps it needs moving some place else.

How can I tell why my program requires a specific shared library?

I'm working on an OS X application using a third-party framework. This framework is distributed both as shared objects and static objects. For my purposes, I want to use the static objects because I can't rely on the presence of the library on other systems.
However, when I build the application with Xcode, something decides it needs the shared objects, and when I run it, dyld tells me off before I even get to my program:
dyld: Library not loaded: /usr/local/lib/libshared.dylib
  Referenced from: /Users/me/Library/Developer/Xcode/snip/Application.app/Contents/MacOS/Application
  Reason: image not found
I ran otool -L on the executable, and sure enough, it tried to link against the shared objects (which aren't even installed on my system). However, when I ran it on the thirty-some .a files that I link against, none of them indicated any dependency on them.
Apple's ld -v is just a tad verbose: it displays the library search paths but doesn't produce any other kind of useful output.
How can I find what tried to link against the shared objects?
otool -L does list the libraries against which any object links.
This specific instance was caused by an Xcode bug (known as rdar://2725744 to the ones blessed with Apple bug database access, and not fixed as of Xcode 6.1.1) where if you try to link against a .a static library with Xcode but there's a .dylib (or .so) dynamic library with the same name in the same directory, the linker will pick the dynamic one.
When you instruct Xcode to link against a static library (say /some/path/to/my/libFooBar.a), it adds -L/some/path/to/my -lFooBar to the linker invocation. However, with it, ld first searches for a dynamic library called libFooBar.dylib, and it will fall back to the static library only if it can't find the dynamic one.
If you added the framework is listed in the "Build Phases" of "Link Binary with Libraries" and it has the setting of "Required" that could explain why the launch fails.
Try changing the setting to "Optional". Then if nothing uses the framework, it should launch fine. (If something tries to use the framework, but fails to check for it first, it might crash.)

How does gcc/ld find zlib.so?

I've used zlib for ages and never thought about the fact that it is named slightly unconventionally. While most libraries on Linux follow the naming convention of lib<name>.so for shared objects and lib<name>.a for archives, zlib is named zlib.so/zlib.a. My question is: how does gcc/ld know to look for zlib.so when I use -lz as a link flag?
I understand that for linking, gcc invokes ld, which searches for libraries in certain default paths and any path specified with -L, and it appends the lib and .so or .a. parts as necessary. Oddly, gcc's manual page for linking options only mentions that the linker can find archives; there is no mention of the .so extension. The man page for ld at least mentions both extensions, but still only mentions searching by prepending lib to the specified library name. How does ld know to add the lib after the z for zlib? I've never seen this happen to another library.
gcc has several different methods for linking libraries, shared or static. If you specify -lz, gcc is going to look for libz.so (possibly with some version bits between the libz and the .so, but the important part is the file name will start with libz and end with .so), or for libz.a (again, possibly with version info) if you are compiling statically, or as a fallback if the shared library does not exist. If you specify -lzlib it will look for libzlib.so (which is not the standard name - the package is often named zlib, but the library itself is libz). Another way of linking would be to not use the -l<lib> option, and just specify /path/to/zlib.so or -L /path/to zlib.so (or zlib.a if you want). In this case, the library doesn't have to have the lib prefix, but you would have to explicitly provide any version info, unless provisions are made for a symbolic link or something similar to provide the literal name zlib.so.
Applications can also load shared libraries at runtime via dlopen() and it's other associated functions, in which case the library can also be named whatever you want it to be (this doesn't work for static libraries, of course).
So, if the library you are looking at is actually called zlib.so, then it is not being found by gcc ... -lz, unless it just happens to be a symbolic link to libz.so (or vice versa, in which case gcc is really just using libz.so, which happens to have the same content as your zlib.so). However gcc might be using it if the build process explicitly names the library in the link stage (not using -l<lib>) or if your application loads it via dlopen() (but in that case, it's not really linked to your program - it's just loaded at run time).

Problem with linking in gcc

I am compiling a program in which a header file is defined in multiple places. Contents of each of the header file is different, though the variable names are the same internal members within the structures are different .
Now at the linking time it is picking up from a library file which belongs to a different header not the one which is used during compilation. Due to this I get an error at link time.
Since there are so many libraries with the same name I don't know which library is being picked up. I have lot of oems and other customized libraries which are part of this build.
I checked out the options in gcc which talks about selecting different library files to be included. But no where I am able to see an option which talks about which libraries are being picked up the linker.
If the linker is able to find more than one library file name, then which does the linker pick up is something which I am not able to understand. I don't want to specify any path, rather I want to understand how the linker is resolving the multiple libraries that it is able to locate. I tried putting -v option, but that doesn't list out the path from which the gcc picks up the library.
I am using gcc on linux.
Any help in this regard is highly appreciated.
Regards,
Chitra
Passing -Wl,-t to gcc will tell ld to dump which files it's reading.

Static code on Solaris?

Question:
Why were static libraries /usr/lib/*.a dropped from Solaris 10?
So it is NOT possible to generate statically-linked object?
Dynamically-linked compilation, is the only option?
You can still create your own *.a libraries and link to them, but the system libraries will always be dynamically linked.
See: this post from blogs.oracle.com
If you pass the right flags to the linker, then you can create a static library or application. However, why would you want to? Static libraries are a pain to provide fixes for.
It's a wise decision. The static linking idea does not really work well. Thats why LSB (Linux Standard Base) Project also forbids static linking. Compatibility moved away from system calls to a higher level in the last two decades.
Can't say I've ever gone looking for them, but did you check the "additional options" (or whatever they call it) CD/DVD? I remember it had other random "missing" things...

Resources