GNU/Linux >> Tutoriels Linux >  >> Linux

Fichiers .o vs fichiers .a

.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"


Linux
  1. Renommer les fichiers dans le répertoire ?

  2. Dd :plusieurs fichiers d'entrée ?

  3. Utiliser rsync pour synchroniser les fichiers

  4. Commande Linux ls - Lister les fichiers

  5. Commande mcopy sous Linux

Trouver des fichiers volumineux sous Linux

Commande Rm sous Linux

Afficher les fichiers cachés

Recherche de fichiers dans Ubuntu 22.04

Commande ls sous Linux/UNIX

Comment trouver des fichiers dans Debian