.o files vs .a files

40,056

Solution 1

.o files are objects. They are the output of the compiler and input to the linker/librarian.

.a files are archives. They are groups of objects or static libraries and are also input into the linker.

Additional Content

I didn't notice the "examples" part of your question. Generally you will be using a makefile to generate static libraries.

AR = ar 
CC = gcc

objects := hello.o world.o

libby.a: $(objects)
    $(AR) rcu $@ $(objects)

%.o: %.c
    $(CC) $(CFLAGS) -c $< -o $@

This will compile hello.c and world.c into objects and then archive them into library. Depending on the platform, you may also need to run a utility called ranlib to generate the table of contents on the archive.

An interesting side note: .a files are technically archive files and not libraries. They are analogous to zip files without compression though they use a much older file format. The table of contents generated by utilities like ranlib is what makes an archive a library. Java archive files (.jar) are similar in that they are zip files that have some special directory structures created by the Java archiver.

Solution 2

A .o file is the result of compiling a single compilation unit (essentially a source-code file, with associated header files) while a .a file is one or more .o files packaged up as a library.

Solution 3

D Shawley's answer is good, I just wanted to add a couple of points because other answers reflect an incomplete understanding of what's going on.

Keep in mind that archive files (.a) are not restricted to containing object files (.o). They may contain arbitrary files. Not often useful, but see dynamic linker dependenciy info embedded in an archive for a stupid linker trick.

Also notice that object files (.o) are not necessarily the result of a single compilation unit. It is possible to partially link several smaller object files into a single larger file.

http://www.mihaiu.name/2002/library_development_linux/ -- search in this page for "partial"

Solution 4

You can use ar to create .a file (static library) from .o files (object files)

See man ar for details.

Solution 5

There is one more aspect of linking against .a vs .o files: when linking, all .os passed as arguments are included in the final executable, whereas entries from any .a arguments are only included in the linker output if they resolve a symbol dependency in the program.

More specifically, each .a file is an archive comprising multiple .o files. You can think of each .o being an atomic unit of code. If the linker needs a symbol from one of these units, the whole unit gets sucked into the final binary; but none of the others are unless they too are needed.

In contrast, when you pass a .o on the command line, the linker sucks it in because you requested it.

To illustrate this, consider the following example, where we have a static library comprising two objects a.o and b.o. Our program will only reference symbols from a.o. We will compare how the linker treats passing a.o and b.o together, vs. the static library which comprises the same two objects.

// header.hh
#pragma once

void say_hello_a();
void say_hello_b();
// a.cc
#include "header.hh"
#include <iostream>

char hello_a[] = "hello from a";

void say_hello_a()
{
        std::cout << hello_a << '\n';
}
// b.cc
#include "header.hh"
#include <iostream>

char hello_b[] = "hello from b";

void say_hello_b()
{
        std::cout << hello_b << '\n';
}
// main.cc
#include "header.hh"

int main()
{
        say_hello_a();
}

We can compile the code using this Makefile:

.PHONY = compile archive link all clean

all: link

compile:
        @echo ">>> Compiling..."
        g++ -c a.cc b.cc main.cc

archive: compile
        @echo ">>> Archiving..."
        ar crs lib.a a.o b.o

link: archive
        @echo ">>> Linking..."
        g++ -o main_o main.o a.o b.o
        g++ -o main_a main.o lib.a

clean:
        rm *.o *.a main_a main_o

and obtain two executables main_o and main_a that differ in that the contents of a.cc and b.cc where provided through two .os in the first case and through a .a in the second.

Lastly we examine the symbols of the final executables using the nm tool:

$ nm --demangle main_o | grep hello
00000000000011e9 t _GLOBAL__sub_I_hello_a
000000000000126e t _GLOBAL__sub_I_hello_b
0000000000004048 D hello_a
0000000000004058 D hello_b
0000000000001179 T say_hello_a()
00000000000011fe T say_hello_b()
$ nm --demangle main_a | grep hello
00000000000011e9 t _GLOBAL__sub_I_hello_a
0000000000004048 D hello_a
0000000000001179 T say_hello_a()

and observe that main_a is in fact lacking the unneeded symbols from b.o. That is, the linker did not suck in the contents of b.o within the archive lib.a because none of the symbols from b.cc were referenced.

Share:
40,056
Admin
Author by

Admin

Updated on January 27, 2021

Comments

  • Admin
    Admin over 3 years

    What is the difference between these two file types. I see that my C++ app links against both types during the construction of the executable.

    How to build .a files? links, references, and especially examples, are highly appreciated.

  • Shammel Lee
    Shammel Lee over 7 years
    This is on the subject of Make but just thought I'd add, you can also substitute $(objects) on the recipe line ($(AR) rcu $@ $(objects)) of the libby.a target with $< or $^ to reference the first or all prerequisite targets, respectively. This will have the same effect, but also removes the redundancy of specifying $(objects) twice, needing to update the reference in two places if the variable name or prerequisites change, and also happens to be less code.
  • michelson
    michelson over 7 years
    @ShammelLee - I usually avoid $^ since it is a GNU Make extension and not present in either BSD make or in POSIX make. I doesn't matter much since most Linux distros are very much GNU based but the switch of /bin/sh from bash to dash was enough to make me continue to avoid GNU specific extensions.
  • Pacerier
    Pacerier about 7 years
    @D.Shawley, What's a "librarian" all about? Also, are you saying that we can use .a asif it's a .tar?
  • michelson
    michelson about 7 years
    @Pacerier - a librarian usually adds metadata to the archive that makes it a "library" for a specific compile toolchain. As for using .a files as archives, yes you can do exactly that. That's what they were made to do. The tar formats contain more file metadata than the older ar format.