Tuesday, January 25, 2011

How to Create a Static Library in Linux

Basically libraries are of two types
$ gcc first.c -o first
This gives an executable which is of dynamic type. This can be known by using the tool file.

$ file first
First: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.15, not stripped
$ gcc first.c -o first
$ ls -l
-rwxr-xr-x 1 gvamshi gvamshi 7139 2011-01-23 14:26 first
-rw-r--r-- 1 gvamshi gvamshi 63 2011-01-23 14:26 first.c
-l is the option used with ls for long listing.

We run the executable we obtained above by compilation as follows.
$ ./first
This is Linux 2.6.32

To generate an executable of static type, we use a flag static as shown below.
$ gcc -static first.c -o firststatic
$ ls -l
-rwxr-xr-x 1 gvamshi gvamshi 7139 2011-01-23 14:26 first
-rw-r--r-- 1 gvamshi gvamshi 63 2011-01-23 14:26 first.c
-rwxr-xr-x 1 gvamshi gvamshi 578015 2011-01-23 14:35 firststatic
$ ./firststatic
This is Linux 2.6.32

Here the thing to observe is the size of both executables that is first and firststatic, here the size of firststatic is approximately ten times that of first, this is because the libraries are also loaded into it. As the libraries are loaded with our code then this firststatic can be executed on any machine which is of same architecture and of same linux kernel version even if the machine doesn't have libc libraries, where as the executable first need the libc on the machine to run as the libraries are dynamically linked and are loaded at run time by the tool link-loader. As the libraries are linked dynamically the size of executable first is small. Static executable (firststatic) in now independent of libc library.
Note: In gnu linker by default follow dynamic linking strategy.

Steps In Creating Static Library

Step1: implement the library source. Let us assume there are two files namely one.c and two.c each implementing one function as follows
$ vim one.c
#include <stdio.h>
void fun1(){
    printf("This is function 1\n");
}

$ vim two.c
#include <stdio.h>
void fun2(){
    printf("This is function 2\n");
}


Step2: compile the sources (one.c, two.c) to generate relocatables
$ gcc -c one.c
$ gcc -c two.c
ls -l
total 16
-rw-r--r-- 1 gvamshi gvamshi 66 2011-01-23 14:59 one.c
-rw-r--r-- 1 gvamshi gvamshi 844 2011-01-23 15:01 one.o
-rw-r--r-- 1 gvamshi gvamshi 66 2011-01-23 14:58 two.c
-rw-r--r-- 1 gvamshi gvamshi 844 2011-01-23 15:01 two.o
$

Note: “.a “ is the extension for the static libraries.

Using the archive tool ar we create a static library.

$ ar rcs libmyown.a one.o two.o

- libmyown.a is the own static library to be created. According to the general naming conventions a library should start with “lib” .
- rcs are the options (replace, create, symbol) for more details refer to man pages as follows.
- one.o and two.o are the list of sources to be packed into archive.

The above created static library is position dependent.

$ man ar (this gives description about the usage of ar)
$ info ar (this gives information like an ebook)

To list what all files have gone into archive type use option‘t’ of ar.
$ ar -t libmyown.a
one.o
two.o

you can even view the list of file that are packed into libc.a standard library as follows. To see where libc.a located in your machine use whereis as follows, which gives the path for libc.a
$ whereis libc.a
libc: /usr/lib/libc.so /usr/lib/libc.a /usr/share/man/man7/libc.7.gz

$ ar -t /usr/lib/libc.a init-first.o |more
libc-start.o
sysdep.o
version.o
check_fds.o
libc-tls.o
elf-init.o
dso_handle.o
errno.o
--More--
Now we can ship our library to costumer, along with this we even need to ship the header file to give the function prototypes. Create a header file mylib.h as follows.

$ vim mylib.h
void fun1();
void fun2();

to make use of the library above created write a test application as follows.
$ vim test.c

#include <stdio.h>
#include <mylib.h>

main()
{
    printf("This is test to create own library\n");
    fun1();/*call to function */
    fun2();/*call to function */
}

Now compile the source file as follows.

$ gcc test.c -o test (gives an error)
test.c:2:18: error: mylib.h: No such file or directory

to figure out where the error occurred use the following option
$ gcc -v test.c -o test
v option with gcc, stands for verbose.
the error is because the header files included are searched at the following locations.
/usr/local/include
         /usr/lib/gcc/i486-linux-gnu/4.4.3/include
           /usr/lib/gcc/i486-linux-gnu/4.4.3/include-fixed
           /usr/include
where in our header file exists in the current working directory, and is not in above of the paths, so we have to explicitly say this by using the option I.
$ gcc -I ./ test.c -o test (gives error)
/tmp/ccFPPIsN.o: In function `main':
test.c:(.text+0x16): undefined reference to `fun1'
test.c:(.text+0x1b): undefined reference to `fun2'
collect2: ld returned 1 exit status

Still we end up with the above errors as we missed library, so follow the below step.

$ gcc -I ./ test.c -o teststatic ./libmyown.a
$ ./teststatic
This is test to create own library
This is function 1
This is function 2

Here important thing to note is what ever the executable (teststatic) we generated is not complete static, it is dynamically linked, this can be know by the tool file.

$ file teststatic
teststatic: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.15, not stripped

Therefore to obtain a complete static executable use the -static flag with the above command and check out the type of file as above.

$ gcc -static -I ./ test.c -o test_complete_static ./libmyown.a
$ file test_complete_static
test_complete_static: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, for GNU/Linux 2.6.15, not stripped

One more thing to discuss is, in the above output there is something like “not stripped”. Which means there is some extra information like metadata in the executable. That extra unnecessary information can be removed using the tool strip. After stripping the file check out the earlier and current file sizes.
$ ls -l test_complete_static
-rwxr-xr-x 1 gvamsi gvamsi 578100 2011-01-23 17:14 test_complete_static

$ strip test_complete_static
$ ls -l test_complete_static
-rwxr-xr-x 1 gvamsi gvamsi 515108 2011-01-23 17:15 test_complete_static


                                   

Please leave comment :-)                                                  Queries are at free of cost

10 comments:

  1. ~$ gcc -I ./test1.c -o teststatic ./libmyown.a


    /usr/lib/gcc/i686-linux-gnu/4.6/../../../i386-linux-gnu/crt1.o: In function `_start':
    (.text+0x18): undefined reference to `main'
    collect2: ld returned 1 exit status

    "why this happened sir plz explain"

    ReplyDelete
    Replies
    1. I understand there may be invisible/non-printing characters in your *.c file. This happens when code is copied from a browser and pasted into your &.c file. To see if there are any non-printing characters that is causing compilation issue, please run the below command.
      cat --show-nonprinting test1.c

      If you find any, remove them and re-compile

      Delete
  2. how can I solve this error

    usr/lib/gcc/i686-linux-gnu/4.6/../../../i386-linux-gnu/crt1.o: In function `_start':
    (.text+0x18): undefined reference to `main'
    collect2: ld returned 1 exit status

    ReplyDelete
  3. Simply Superb way of explained the concepts of creating and libraries in linux..... thanks :)

    ReplyDelete
  4. Hi Folks, I have verified this, and its working fine. I see some people making the following mistake, they forget to give space in between "#include" & "< stdio.h >"

    #include< stdio.h > //This is wrong, you see errors when you compile with libmyown.a
    #include < stdio.h >"//This is correct

    Note: There is no space between "<" & "s" and ".h" & ">"

    ReplyDelete