Linking .a files in Mac OSx - macos

I have added libxxx.a in /usr/lib but when I perform otool -L myproject.so, libxxx.a was not included in the list of libraries. I have also included libxxx.a in my build file so I was thinking that I have successfully added it.
How can I like .a file?
I didn't have a problem with .dylib files though.

otool won't show the static library as they are included within the executable binary (a .dylib in this case). This is because static libraries are a collection of object (.o) files and it's pretty much the same as adding file1.o ... fileN.o to the linker command line and you can't see object files from otool either.
One way to check that your static library is part of the executable (other than it successfully linking) is to use the nm command which lists symbols. Providing the executable binary is not stripped, you would do something like:
$ nm /path/to/libLibrary.dylib | grep aClassOrFunctionInStaticLibrary
and the symbol being searched should have the letter t next to it, to indicate that it's part of the executable text section.
Also as mentioned by #PaulR, /usr/lib is part of the operating system and you should not add files there; use /usr/local/lib instead as /usr/local is designed for site-specific additions to the system and files there will survive an operating system update.

Related

Link multiple object files in gfortran

I have "library" folder with multiple object (.o) files. These files contain subroutines which are not changing from project to project. Each new project uses some of those object files, but not all of them.
Could you please tell me is there any way to tell gfortran to look up that folder for necessary .o files?
I've tried -I and -L options, but no way. When I write .o names directly, it works:gfortran main.for ./library/obj1.o ./library/obj2.o but I have many of .o files and write all of them waste time.
I could write gfortran main.for ./*.o but then main program will be linked with all .o files, but it needs only some of them.
I hoped that something like gfortran main.for -L./library/ will work, but it doesn't.
I use OS X with gcc version 5.1.0.
And I'm pretty sure that I should use makefile for such case
You are confusing object files with static libraries. An object file
is not a static library and the gfortran linker - which is simply
the GNU system linker, invoked by gfortran - will not treat it as such.
You need a static library and you are trying to use object files in lieu.
The linker recognizes an object file by the extension .o. It recognizes
a static library by the extension .a, and it expects the contents of an .a file
to have the form of a static library, not the format of an object file. (So you
cannot make an object file into a static library just by renaming it).
The linker will link into your program every object file that appears on its
commandline, whether or not it is needed. It does not expect you to mention
object files if you don't want them linked. The linker options -L and -l for
locating libraries have no application to object files.
A static library is a fairly simple archive containing some number of
object files, plus a house-keeping header and typically an index of the
public symbols defined in the contained object files.
When the linker encounters a static library on its commandline, it does not
link the entire contents of the library (unless you expressly tell it to). It inspects
the contained object files to determine which, if any, of them contain
definitions for symbols that are as yet undefined at that point in the linkage
of the program. If any object file in the library is found to provide any
of the missing definitions, then that object file is extracted from the library
and linked into the program. Object files in the library that provide no
missing definitions are not linked. Libraries on the commandline are sequentially
inspected in this way until either all the symbols referred to by the program
have definitions in linked object files or there are no more libraries.
If as you say the object files that you are trying to use as libraries are stable
resources that you never have to build for your projects, then you can just make a static
library out of them and link that library with your per-project programs.
To make a static library from object files, use the ar tool.
See man ar.
When you have made your library, say, libsubs.a, and have decided it shall reside
in some directory, /path/to/subs, then you link it with a program by adding
-L/path/to/subs -lsubs
to the commandline in which your program is linked. This will cause the linker
to search for a library called libsubs.a in directory /path/to/subs.
So if you are compiling and linking in a single step, use it like:
gfortran -o myprog myprog.f90 -L/path/to/subs -lsubs
And if you are compiling and linking in distinct steps, use it like:
gfortran -c -o myprog_1st_file.o myprog_1st_file.f90
gfortran -c -o myprog_2nd_file.o myprog_2nd_file.f90
gfortran -o myprog myprog_1st_file.o myprog_2nd_file.o -L/path/to/subs -lsubs
This is how you are supposed to use a set of object file resources of which
different subsets will be required for linkage with different programs: you put
them in a library and link the library.

What does -lfoo link with if both libfoo.a and libfoo.so are on the library path?

Using gcc and gnu ld, I am compiling a binary (a shared object in this case) that depends on a library, let's say libfoo. libfoo comes as both .a and .so files, in the same directory.
Can I know which is being used, the static or the dynamic?
GNU ld on my Linux (Ubuntu 12.10 box) will load the .so file first.
From man ld:
-l namespec
--library=namespec
Add the archive or object file specified by namespec to the list of
files to link. This option may be used any number of times. If
namespec is of the form :filename, ld will search the library path
for a file called filename, otherwise it will search the library
path for a file called libnamespec.a.
On systems which support shared libraries, ld may also search for
files other than libnamespec.a. Specifically, on ELF and SunOS
systems, ld will search a directory for a library called
libnamespec.so before searching for one called libnamespec.a. (By
convention, a ".so" extension indicates a shared library.) Note
that this behavior does not apply to :filename, which always
specifies a file called filename.
gcc (and ld, which it's really running behind the scenes) default to dynamic linking if it's available. You can check the output binary to see which it did, if you want.
If you want to force it to use the static library, you can use the -static link option.

Why is my shared library not found?

I'm trying to compile an example program that links to the shared library produced by Sundown. I'm compiling the program like so.
$ gcc -o sd sundown.c -L. -lsundown
Yet, when I run it I get the following error.
./sd: error while loading shared libraries: libsundown.so: cannot open shared object
file: No such file or directory
The output of ls is.
$ ls
libsundown.so libsundown.so.1 sundown.c sd
Why is the shared library not found by ld?
Short solution:
add . (or whatever it is from your -L flag) to your LD_LIBRARY_PATH. When you run sd, it'll look for libraries in the standard places and the LD_LIBRARY_PATH. Note that since you've added ., this will only work if you run sd from the same directory libsundown.so is in.
I plan on distributing the compiled binary. How can I do so that the library can be distributed without forcing people to edit their LD_LIBRARY_PATH?
You should install libsundown.so in one of the standard places, like /usr/lib or /usr/local/lib. You can do that with an installer or a make file, or something as simple as a INSTALL or README that tells the user to stick the libraries there and ensure the permissions are set to something sensible.
On Centos systems with /usr/lib and /usr/lib64, if you install 64-bit libs manually into /usr/lib then at runtime, the library may not be visible even though at build time it is visible (I used autotools and it was able to find my zopfli library from /usr/lib without any problem). When I execute the my_binary that links to /usr/lib/libzopfli.so.1 I got
libzopfli.so.1 => not found
After moving libzopfly.so.1 from /usr/lib to /usr/lib64, then everything works fine.

GCC linking to a shared object's linker name

Suppose I have:
/usr/lib/libsomething.so.1 on machine A;
/usr/lib/libsomething.so.2 on machine B.
Both machines have /usr/lib/libsomething.so symlinking to their respective libs.
If I link using gcc with -lsomething (or even /usr/lib/libsomething.so) it will follow the symlink, and ldd on machine A produces something like:
libsomething.so.1 => /usr/lib/libsomething.so.1
This means it won't be able to find the library on machine B.
Now I know these are major version number changes and I know they may not be compatible, but I'm willing to take that risk. What I'd like to tell the linker is to look for libsomething.so, and don't follow the symlink so ldd will show
libsomething.so => /usr/lib/libsomething.so.1
on A but
libsomething.so => /usr/lib/libsomething.so.2
on B. And then the loader will follow the symlink to whatever version is there.
Also, I don't want delayed loading with dlopen or anything. I want it to link to the shared object at compile time.
Is this even possible?
Making executable which uses any available version of shared library is, of course, possible.
The problem was that you linked your executable to version-specific soname (libsomething.so.1 and libsomething.so.2). You should have done it with unversioned soname libsomething.so instead.
In order to achieve this, on the build machine you should compile and install library with soname (ELF SONAME) equal to libsomething.so (without version) so that linker can choose this soname while executable is built.
According to the Shared Libraries HOWTO, you can pass required unversioned soname while building the library:
gcc -shared -Wl,-soname,libsomething.so -o libsomething.so.X objectsomething.o
Then, as soon as you install the library and run ldconfig, you have:
symlink /lib/libsomething.so pointing to /lib/libsomething.so.1 on machine A;
symlink /lib/libsomething.so pointing to /lib/libsomething.so.2 on machine B.
The loader (run ldd) will choose unversioned symlinks regardless where it points to:
libsomething.so => /lib/libsomething.so (0xNNNNNNNN) on machine A;
libsomething.so => /lib/libsomething.so (0xNNNNNNNN) on machine B.
Linux dynamic loader (ld.so) resolves libraries based on their soname value written in the executable (ELF NEEDED). The value is copied from library file (ELF SONAME) while building the executable. As long as there is a symlink on the target system matching the soname recorded in the executable, the library pointed by this symlink will be loaded.
Let's run through your setup and show commands to verifing assumptions.
I used Fedora 18 X86_64 for the test and adjusted output to i686 for clarity.
Compile both libsomething.so.1 and libsomething.so.2. Make sure SONAME is set to unversioned libsomething.so:
readelf -a libsomething.so.1 | grep SONAME
0xNNNNNNNN (SONAME) Library soname: [libsomething.so]
readelf -a libsomething.so.2 | grep SONAME
0xNNNNNNNN (SONAME) Library soname: [libsomething.so]
Install the libraries into their respective machines under /lib/ directory. Run ldconfig -v on both machines and verify the output.
ldconfig -v 2>&1 | grep something
libsomething.so -> libsomething.so.1 (changed)
ldconfig -v 2>&1 | grep something
libsomething.so -> libsomething.so.2 (changed)
Compile executable and make sure that it refers to the same soname without version in NEEDED.
readelf -a executable | grep NEEDED
0xNNNNNNNN (NEEDED) Shared library: [libsomething.so]
You executable depends on unversioned libsomething.so now. Copy executable to both machines and run ldd against both copies.
ldd executable
libsomething.so => /lib/libsomething.so (0xNNNNNNNN)
The last output is the same on both machines as the executable was built with soname without version. This makes loader take unversioned symlinks on targets machines. And depending on the machine, the symlink can point to different implementation of the library libsomething.so.1 or libsomething.so.2.
This means it won't be able to find the library on machine B.
And it's not supposed to anyway.
By the very definition of soversions, libsomething.so.2 denotes that the API/ABI is incompatible to libsomething.so.1. Therefore, just adding libsomething.so in the program's table of libraries to be loaded would be factually wrong. The libsomething.so symlink merely serves as a hint to ld as to which soversion to pick by default.
Of whatever file ld actually ended up opening, it will take the DTNAME/SONAME field to encode in the program. If you don't want that, don't equip libsomething with a soname. But it can easily become pain... starting with running into unavailable symbols when trying to run the program.

Questions on GCC linker

Apologize because for the moment I don't have the environment to experiment and sort out the following questions myself:
1) Let's say I have four library files: libmylib_super.a and libmylib_super.so, mylib_dumb.a and mylib_dumb.so. While specifying libraries to link to, what are the differences between the following approaches:
A) -l:libmylib_super.a
B) -llibmylib_super
C) -lmylib_super
D) -lmylib_dumb
2) Definition of -static from man page:
On systems that support dynamic
linking, this prevents linking with
the shared libraries. On other
systems, this option has no effect.
Does this linker option have anything to do with question #1? Or... by any chance will they interfere with each other?
Thanks.
--- edited 2009-12-28 ---
I just got my environment up and experimenting a bit, by linking to Boost date_time library. Say I have three library files: libboost_date_time-mt-d.a, libboost_date_time-mt-d.so.1.41.0, libboost_date_time-mt-d.so -> libboost_date_time-mt-d.so.1.41.0 (sym link).
A.1) -l:libboost_date_time-mt-d.a ==> linking OK, binary works even without the library file.
A.2) -l:libboost_date_time-mt-d.a with -static ==> linking error /usr/bin/ld: cannot find -lm
C.1) -lboost_date_time-mt-d ==> linking OK, binary works but requires the shared library file.
C.2) -lboost_date_time-mt-d with -static ==> linking error /usr/bin/ld: cannot find -lm
Any idea about the error in A.2 and C.2?
Additionally, while running the program in C.1, it seems searching the shared library file with name libboost_date_time-mt-d.so.1.41.0 but not the libboost_date_time-mt-d.so. Wouldn't that be inconvenient if the program is running on a system without the exact version of library? What could be the practical way to handle the version while using shared library?
According to the manual,
A) searches the library path for a file exactly named libmylib_super.a (the search first for a shared library behavior doesn't apply)
B) searches the library path for a file named liblibmylib_super.so first then liblibmylib_super.a or only searches for a file named liblibmylib_super.a if -static is used -- note it's the linker that adds the lib prefix and the file extension
C) searches the library path for a file named libmylib_super.so first then libmylib_super.a or only searches for a file named liblibmylib_super.so if -static is used
D) see C)
Note that B) won't work because it's the linker that should add the lib prefix to the library name.
Note that D) won't work because your mylib_dumb doesn't follow the naming convention.
See the GNU Linker Manual:
-l namespec
--library=namespec
Add the archive or object file specified by namespec to the list of files to link. This option may be used any number of times. If namespec is of the form :filename, ld will search the library path for a file called filename, otherwise it will search the library path for a file called libnamespec.a.
On systems which support shared libraries, ld may also search for files other than libnamespec.a. Specifically, on ELF and SunOS systems, ld will search a directory for a library called libnamespec.so before searching for one called libnamespec.a. (By convention, a .so extension indicates a shared library.) Note that this behavior does not apply to :filename, which always specifies a file called filename.
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.
See the -( option for a way to force the linker to search archives multiple times.
You may list the same archive multiple times on the command line.
This type of archive searching is standard for Unix linkers. However, if you are using ld on AIX, note that it is different from the behaviour of the AIX linker.

Resources