How do I compile a static library

10,616

Solution 1

You can use the program ar to create static libraries using the following syntax:

 ar rcs my_library.a file1.o file2.o

So, in your case:

$(PROJECT): $(OBJECTS)
     ar rcs $(PROJECT) $(OBJECTS)

You can find an explanation of the options on the man page, but basically:

  • r says insert the given object files in to the archive (replacing any older versions of the same thing)
  • c says create the archive if it isn't already there (normally this happens anyway, but this option suppresses the warning).
  • s says to write an object-file index into the archive.

Solution 2

Well, this is confusing; but I think that the libtool -o $(PROJECT) -static $(OBJECTS) line (also mentioned in objective c - Combine static libraries) comes from Mac; and apparently the libtool there is NOT the same as the one on Linux:

libtool or ar & ranlib - idevgames forums:

I was using libtool to create a static library on OS X because that's what Xcode was doing, which seems to work fine. Then I go over to Linux and it chokes on my libtool command saying "libtool: unrecognized option '-o'". Looking at them, it seems like libtool on OS X and libtool on Linux are two completely different programs. ...
Followup: Yes, it appears that libtool on Linux is indeed glibtool on OS X. I get essentially the same output when doing "glibtool --help" on OS X as "libtool --help" on Linux.

Ok, that explains the difference - but still doesn't explain how -o can be an unrecognized option, when I've just seen it run from a Makefile on Linux! So I found this:

bug-libtool mailing list (2001): Re: bug in libtool?

You need to set the mode before the mode options:

$ libtool --mode=link --help
Usage: libtool [OPTION]... --mode=link LINK-COMMAND...

Oh dear... now what makes it especially confusing, is this note in libtool --mode=link --help:

$ libtool --mode=link --help
Usage: libtool [OPTION]... --mode=link LINK-COMMAND...
...

LINK-COMMAND is a command using the C compiler that you would use to create
a program from several object files.

The following components of LINK-COMMAND are treated specially: ...
  -all-static       do not do any dynamic linking at all ...
  -o OUTPUT-FILE    create OUTPUT-FILE from the specified objects ...
  -static           do not do any dynamic linking of uninstalled libtool libraries
...
All other options (arguments beginning with `-') are ignored.

Every other argument is treated as a filename.  Files ending in `.la' are
treated as uninstalled libtool libraries, other files are standard or library
object files.
...
If OUTPUT-FILE ends in `.a' or `.lib', then a standard library is created
using `ar' and `ranlib', or on Windows using `lib'.

So - if I have to specify a LINK-COMMAND - and at the same time, I specify an OUTPUT-FILE which ends in .a; which command should then run, LINK-COMMAND - or the ar+ranlib that extension .a specifies? Well - here's a terminal snippet, just testing the bash script logic of libtool - without any compilation (though an empty archive does get created):

$ libtool -o test.a
libtool: unrecognized option `-o'
libtool: Try `libtool --help' for more information.

$ libtool --mode=link -o test.a
libtool: link: unrecognized option `-o'
libtool: link: Try `libtool --help' for more information.

$ libtool --mode=link gcc -o test.a
libtool: link: ar cru test.a
libtool: link: ranlib test.a

$ libtool --mode=link ar -o test.a
libtool: link: unable to infer tagged configuration
libtool: link: specify a tag with `--tag'

$ cat $(which libtool) | grep "^# ### BEGIN LIBTOOL TAG CONFIG:"
# ### BEGIN LIBTOOL TAG CONFIG: disable-shared
# ### BEGIN LIBTOOL TAG CONFIG: disable-static
# ### BEGIN LIBTOOL TAG CONFIG: CXX
# ### BEGIN LIBTOOL TAG CONFIG: F77
# ### BEGIN LIBTOOL TAG CONFIG: FC
# ### BEGIN LIBTOOL TAG CONFIG: GCJ
# ### BEGIN LIBTOOL TAG CONFIG: RC
# ### BEGIN LIBTOOL TAG CONFIG: BINCC
# ### BEGIN LIBTOOL TAG CONFIG: BINCXX

## CC tag is not listed, but it will (eventually) be accepted:

$ libtool --mode=link ar --tag CC -o test.a
libtool: link: unable to infer tagged configuration
libtool: link: specify a tag with `--tag'

$ libtool --mode=link --tag CC ar -o test.a
libtool: link: ar cru test.a
libtool: link: ranlib test.a

$ libtool --tag=CC --mode=link ar -o test.a
libtool: link: ar cru test.a
libtool: link: ranlib test.a

$ libtool --tag=XX --mode=link ar -o test.a
libtool: ignoring unknown tag XX
libtool: link: ar cru test.a
libtool: link: ranlib test.a

$ libtool --tag=XX --mode=link whatevar -o test.a
libtool: ignoring unknown tag XX
libtool: link: ar cru test.a 
libtool: link: ranlib test.a

$ ls -la test.a 
-rw-r--r-- 1 user user 8 2013-04-17 23:12 test.a

So - not only do you have to specify a --mode, but if this mode is link, you MUST specify SOME sort of an argument (LINK-COMMAND) referring to a tool; BUT that LINK-COMMAND argument doesn't even need to exist as a real program - because you must specify an output file anyway; and if that output file ends on .a, it will enforce use of ar/ranlib anyways.

Also, should you have a problem with a tag - simply move the --tag argument before the LINK-COMMAND argument - and you can force libtool to run with a non-existing tag and a non-existing LINK-COMMAND (where it's operation is specified solely by the extension .a of the output file) - as long as the arguments are entered in the proper order for the libtool syntax; which I must admit isn't really documented in the script itself.


But to come back to the Mac libtool -o $(PROJECT) -static $(OBJECTS) line, which would combine static libraries; if you try to do the same with proper static library .a files, you will notice that libtool pushes the .a archives as such in the output archive, not their constituent object files - so this output is not a valid ELF object anymore; here is an example of a corresponding Linux libtool line, with two proper library files I've generated:

$ readelf --syms libmy1.a
File: libmy1.a(my1.o)
Symbol table '.symtab' contains 11 entries:
...
$ readelf --syms libmy2.a
File: libmy2.a(my2.o)
Symbol table '.symtab' contains 12 entries:
...
$ libtool --mode=link --tag=CC ar -o libtest.a -static libmy1.a libmy2.a 
libtool: link: ar cru libtest.a libmy1.a libmy2.a 
libtool: link: ranlib libtest.a

$ readelf --syms libtest.a
readelf: Error: Not an ELF file - it has the wrong magic bytes at the start
readelf: Error: libtest.a(libmy1.a): Failed to read file header
readelf: Error: Not an ELF file - it has the wrong magic bytes at the start
readelf: Error: libtest.a(libmy2.a): Failed to read file header

So, as the accepted answer says - on Linux, use ar manually to unpack and pack again, to combine static libraries.

Hope this helps someone,
Cheers!

Solution 3

Either use libtool or don't. If you're going to use it, then you should compile the individual files with libtool --mode=compile as well as linking with libtool --mode=link. If you're not going to use libtool, then your link should be done with gcc also, as pointed out in another answer. Also, have you tried man libtool?

Solution 4

The following commands will build your static library:

$gcc -c file1.c -o libfile.o
$ar rcs libfile.a libfile.o
Share:
10,616
pythonic
Author by

pythonic

Updated on June 04, 2022

Comments

  • pythonic
    pythonic almost 2 years

    I am trying to compile a static library. I followed the steps which were given in an answer to this question but it is not working. Following is my makefile.

    PROJECT = lq.a
    OBJECTS = dlmalloc.o queue.o.o
    CFLAGS  = -o -Wall -pedantic
    
    all: $(PROJECT)
    
    .c.o:
        gcc -c $(CFLAGS) $<
    
    $(PROJECT): $(OBJECTS)
        libtool -o  $(PROJECT) -static $(OBJECTS)
    

    And I get the following error.

    libtool: unrecognized option `-o'
    

    What is the correct way of writing this makefile?