GNU/Linux >> Linux Esercitazione >  >> Linux

File .o vs file .a

.o i file sono oggetti. Sono l'output del compilatore e l'input per il linker/librarian.

.a i file sono archivi. Sono gruppi di oggetti o librerie statiche e vengono anch'essi immessi nel linker.

Contenuti aggiuntivi

Non ho notato la parte "esempi" della tua domanda. Generalmente utilizzerai un makefile per generare librerie statiche.

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]

Questo compilerà hello.c e world.c in oggetti e quindi archiviarli nella libreria. A seconda della piattaforma, potrebbe anche essere necessario eseguire un'utilità chiamata ranlib per generare il sommario sull'archivio.

Un'interessante nota a margine:.a i file sono tecnicamente file di archivio e non librerie. Sono analoghi ai file zip senza compressione sebbene utilizzino un formato di file molto più vecchio. Il sommario generato da utilità come ranlib è ciò che rende un archivio una biblioteca . File di archivio Java (.jar ) sono simili in quanto sono file zip che hanno alcune strutture di directory speciali create dall'archiviatore Java.


C'è un altro aspetto del collegamento contro .a contro .o files:durante il collegamento, tutti .o s passati come argomenti sono inclusi nell'eseguibile finale, mentre le voci da qualsiasi .a gli argomenti sono inclusi nell'output del linker solo se risolvono una dipendenza da simbolo nel programma.

Più specificamente, ogni .a file è un archivio che comprende più .o File. Puoi pensare a ogni .o essere un'unità atomica di codice. Se il linker necessita di un simbolo da una di queste unità, l'intera unità viene risucchiata nel binario finale; ma nessuno degli altri lo è a meno che anche loro non siano necessari.

Al contrario, quando passi un .o sulla riga di comando, il linker lo risucchia perché lo hai richiesto.

Per illustrare questo, si consideri l'esempio seguente, in cui abbiamo una libreria statica che comprende due oggetti a.o e b.o . Il nostro programma farà riferimento solo ai simboli di a.o . Confronteremo come il linker tratta il passaggio a.o e b.o insieme, rispetto alla libreria statica che comprende gli stessi due oggetti.

// 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();
}

Possiamo compilare il codice usando questo 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

e ottenere due eseguibili main_o e main_a che differiscono nel contenuto di a.cc e b.cc dove previsto attraverso due .o s nel primo caso e attraverso un .a nella seconda.

Infine esaminiamo i simboli degli eseguibili finali utilizzando il nm strumento:

$ 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()

e osserva che main_a mancano infatti i simboli non necessari da b.o . Cioè, il linker non ha risucchiato il contenuto di b.o all'interno dell'archivio lib.a perché nessuno dei simboli di b.cc sono stati referenziati.


Un file .o è il risultato della compilazione di una singola unità di compilazione (essenzialmente un file di codice sorgente, con file di intestazione associati) mentre un file .a è uno o più file .o impacchettati come una libreria.


La risposta di D Shawley è buona, volevo solo aggiungere un paio di punti perché altre risposte riflettono una comprensione incompleta di cosa sta succedendo.

Tieni presente che i file di archivio (.a) non sono limitati a contenere file oggetto (.o). Possono contenere file arbitrari. Non spesso utile, ma vedi le informazioni sulle dipendenze del linker dinamico incorporate in un archivio per uno stupido trucco del linker.

Si noti inoltre che i file oggetto (.o) non sono necessariamente il risultato di una singola unità di compilazione. È possibile collegare parzialmente diversi file oggetto più piccoli in un singolo file più grande.

http://www.mihaiu.name/2002/library_development_linux/ -- cerca in questa pagina "parziale"


Linux
  1. File di configurazione di backup

  2. Incolla i file senza delimitatore?

  3. Grep:Memoria esaurita?

  4. Rinominare i file nella directory?

  5. Trova i file più grandi in modo ricorsivo?

Trova file di grandi dimensioni in Linux

Comando Rm in Linux

Mostra file nascosti

Trovare file in Ubuntu 22.04

comando ls in Linux/UNIX

Come trovare file in Debian