.o
les fichiers sont des objets. Ils sont la sortie du compilateur et l'entrée de l'éditeur de liens/bibliothécaire.
.a
les fichiers sont des archives. Ce sont des groupes d'objets ou des bibliothèques statiques et sont également entrés dans l'éditeur de liens.
Contenu supplémentaire
Je n'ai pas remarqué la partie "exemples" de votre question. Généralement, vous utiliserez un makefile pour générer des bibliothèques statiques.
AR = ar
CC = gcc
objects := hello.o world.o
libby.a: $(objects)
$(AR) rcu [email protected] $(objects)
%.o: %.c
$(CC) $(CFLAGS) -c $< -o [email protected]
Cela compilera hello.c
et world.c
en objets, puis les archiver dans la bibliothèque. Selon la plate-forme, vous devrez peut-être également exécuter un utilitaire appelé ranlib
pour générer la table des matières sur l'archive.
Une remarque intéressante :.a
les fichiers sont techniquement des fichiers d'archives et non des bibliothèques. Ils sont analogues aux fichiers zip sans compression bien qu'ils utilisent un format de fichier beaucoup plus ancien. La table des matières générée par des utilitaires comme ranlib
est ce qui fait d'une archive une bibliothèque . Fichiers d'archives Java (.jar
) sont similaires en ce sens qu'il s'agit de fichiers zip dotés de structures de répertoires spéciales créées par l'archiveur Java.
Il y a un autre aspect de la liaison avec .a
contre .o
fichiers :lors de la liaison, tous les .o
s passés comme arguments sont inclus dans l'exécutable final, alors que les entrées de n'importe quel .a
les arguments ne sont inclus dans la sortie de l'éditeur de liens que s'ils résolvent une dépendance de symbole dans le programme.
Plus précisément, chaque .a
le fichier est une archive composée de plusieurs .o
des dossiers. Vous pouvez penser à chaque .o
étant une unité atomique de code. Si l'éditeur de liens a besoin d'un symbole de l'une de ces unités, l'unité entière est aspirée dans le binaire final ; mais aucun des autres ne l'est à moins qu'ils ne soient également nécessaires.
En revanche, lorsque vous passez un .o
sur la ligne de commande, l'éditeur de liens l'aspire parce que vous l'avez demandé.
Pour illustrer cela, considérons l'exemple suivant, où nous avons une bibliothèque statique composée de deux objets a.o
et b.o
. Notre programme ne référencera que les symboles de a.o
. Nous allons comparer la façon dont l'éditeur de liens traite le passage de a.o
et b.o
ensemble, par rapport à la bibliothèque statique qui comprend les deux mêmes objets.
// 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();
}
Nous pouvons compiler le code en utilisant ce 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
et obtenir deux exécutables main_o
et main_a
qui diffèrent en ce que le contenu de a.cc
et b.cc
lorsqu'il est fourni par deux .o
s dans le premier cas et par un .a
dans la seconde.
Enfin, nous examinons les symboles des exécutables finaux en utilisant le nm
outil :
$ 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()
et observez que main_a
manque en fait les symboles inutiles de b.o
. Autrement dit, l'éditeur de liens n'a pas aspiré le contenu de b.o
dans l'archive lib.a
car aucun des symboles de b.cc
ont été référencés.
Un fichier .o est le résultat de la compilation d'une seule unité de compilation (essentiellement un fichier de code source, avec des fichiers d'en-tête associés) tandis qu'un fichier .a est un ou plusieurs fichiers .o regroupés sous forme de bibliothèque.
La réponse de D Shawley est bonne, je voulais juste ajouter quelques points car d'autres réponses reflètent une compréhension incomplète de ce qui se passe.
Gardez à l'esprit que les fichiers d'archive (.a) ne sont pas limités à contenir des fichiers objet (.o). Ils peuvent contenir des fichiers arbitraires. Pas souvent utile, mais consultez les informations de dépendance de l'éditeur de liens dynamique intégrées dans une archive pour une astuce stupide de l'éditeur de liens.
Notez également que les fichiers objets (.o) ne sont pas nécessairement le résultat d'une seule unité de compilation. Il est possible de lier partiellement plusieurs fichiers d'objets plus petits en un seul fichier plus volumineux.
http://www.mihaiu.name/2002/library_development_linux/ -- recherchez dans cette page "partial"