Tuesday, February 2, 2010

Linker flags

Here is a post about making static libraries and linking to them. Thanks to help from SO users.

Suppose we start with something one step up from "Hello world." We want to use the C math library. We do something like this in test.c:


#include <math.h>
#include <stdio.h>

main() {
printf("Hello World!\n");
float x = sqrt(M_PI);
printf("%3.2f\n", M_PI);
printf("%3.2f\n", sqrt(M_PI));
return 0;
}


The math library defines constants like M_PI and functions like sqrt. It works:


$ gcc test.c -o test
$ ./test
Hello World!
3.14
1.77


Now, we want to define our own function for doing square roots. We have our own super-duper code in mymath.c. (I should've done Newton's method or something, but I was in a hurry):

float mysqrt(float n) { return 10.2; }

and mymath.h:

float mysqrt(float n);

We add an appropriate call in test.c:

printf("%3.2f\n", mysqrt(M_PI));

As long as all files are in the same directory, everything is fine:


$ gcc test.c mymath.c -o test
$ ./test
Hello World!
3.14
1.77
10.20


Now, suppose we want to package this "new" math into a library...There's a convention (an important one) that libraries should be called libmymath. So, in this case, we can first compile mymath.c into mymath.o (without linking), and then make it into the library. Finally, we do ran on it:


$ gcc -c mymath.c
$ ar r libmymath.a mymath.o
ar: creating archive libmymath.a
$ ranlib libmymath.a


It works:


$ gcc test.c -o test libmymath.a
$ ./test
Hello World!
3.14
1.77
10.20


Next, we wish to move our library into a central location---let's make it a subdirectory /temp/mylibs:


$ ls ~/Desktop/temp/mylibs
libmymath.a


Now, we can compile test.c, but we can't link it without giving the linker more info:


$ gcc -c test.c
$ gcc test.c libmymath.a
i686-apple-darwin10-gcc-4.2.1: libmymath.a: No such file or directory


We can pass the path directly to let the linker know where to look for our library. This works:


gcc test.c -o test /Users/telliott_admin/Desktop/temp/mylibs/libmymath.a


Now the question is whether we can make it shorter?


gcc test.c -o test -L./mylibs -lmymath


This works, but is apparently considered bad form. The flags of interest here are I, L, and l.


-L    
add a new library search path
-lx
This option tells the linker to search for libx.dylib or libx.a in the library search path. If string x is of the form y.o, then that file is searched for in the same places, but without prepending `lib' or appending `.a' or `.dylib' to the filename.
-I
Is a compiler flag to add a search path


So for example, we can move the header file to the subdirectory /temp/myheaders and do:


gcc test.c -o test -I./myheaders -L./mylibs -lmymath


I'm lucky they didn't tell me RTFM! It is actually fairly clearly explained