How to Archive With POSIX ar

Published on 2021-07-26 00:47:00+02:00, last modified on 2021-07-26 17:09:00+02:00

Let's continue last POSIX archiving guide from the very spot we finished. Today, we'll deal with just one tool. Very peculiar one, because it's more of a development utility than an archiver with portable format. In fact, it doesn't have a defined format at all. More than that, POSIX acknowledges that several incompatible formats are known and that they don't care. User can usually count on one implementation to support archives created on another machine using the same implementation, so it's not that bad.

It's time to stop pretending that ar does not exist and learn how to use it.

Now then, when exactly do we want to use ar? Luckily, that's simple to answer. ar is used to create libraries of object files that are meant to be later linked against. In other words, it creates static libraries. In order to do it, ar maintains a symbol table. As long as at least one of the archived files is an object file, ar is obliged to do it completely automatically. However, usability of the archive for the linker is only guaranteed if all of the files are objects.

To create an empty archive:

$ ar -r archive.a

Now, that's not very useful. Luckily for us, option -r actually means "replace or add" and accepts any number of paths after the archive name:

$ ar -r archive.a file_a.o file_b.o ../../file_c.o

Assuming, that all of these files are present, they'll all be added to a new archive. If the archive.a already happens to exist, then files that are already occurring in it will get replaced. If not, then files will get appended.

To list contents of the symbol table, so the contents of the archive, use:

$ ar -t archive.a

Nice! Notice, that the file_c.o was added directly, without any additional path - just basename of the file. This will happen to every single file added to the archive. While adding files with same names you need to be cautious about it. Consider modifying our archive.a by:

$ echo "Aloha!" > ../file_c.o
$ ar -r archive.a ../file_c.o

This will overwrite our current file_c.o with one that says "Aloha!". This could be problematic, but it's generally easy to avoid and there are additional options that allow to do some shenanigans with the archive. Refer to your friendly manual or standard itself.

palm tree

You probably won't need to extract files from the archive, simply because you put it together so that the linker uses it and not yourself, usually in a variation of one of the following ways. All depending on what tool is used as linker and if the archive is available to it through its search paths:

$ cc -l:archive.a main.o -o main
$ ld main.o archive.a -o main

Still, if you need to extract files, you can extract them from library in two ways. First one uses -x option:

$ ar -x archive.a

This simply extracts all of the files from the archive directly into current directory. Keep in mind that the paths are not remembered, only the basenames are. Using those basenames you can also extract selected files from the archive:

$ ar -x archive.a file_c.o
$ cat file_c.o

The other way of extracting is closer to cpio. By using -p option content of selected files or the entire archive will be printed out to standard output:

$ ar -p archive.a file_c.o

Just note that if you specify multiple files to output, they will get concatenated.

And that's about it regarding basic ar usage. Quite a few sources will probably recommend that you always run -s option in every single operation you perform, in order to regenerate symbol table. However, that's not required at all, ar should be able to deal with it without any input from the user. The only case in which it is actually viable is after the archive was stripped. Otherwise, this suggestion is almost always useless.

If you are interested in precise management, then there are couple of options that will help i.a., -d for removal, -u for restricted updates, or -p for unchecked appending. But again, in normal usage, you probably won't need them as -r will deal with almost anything a Makefile will need.