GNU/Linux >> Znalost Linux >  >> Linux

.o soubory vs. .a soubory

.o soubory jsou objekty. Jsou výstupem kompilátoru a vstupem pro linker/knihovník.

.a soubory jsou archivy. Jsou to skupiny objektů nebo statické knihovny a jsou také vstupem do linkeru.

Další obsah

Nevšiml jsem si části "příklady" vaší otázky. Obecně budete ke generování statických knihoven používat makefile.

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]

Tím se zkompiluje hello.c a world.c do objektů a poté je archivovat do knihovny. V závislosti na platformě může být nutné spustit nástroj s názvem ranlib vygenerovat obsah archivu.

Zajímavá vedlejší poznámka:.a soubory jsou technicky archivační soubory a ne knihovny. Jsou analogické souborům zip bez komprese, ačkoli používají mnohem starší formát souboru. Obsah generovaný nástroji jako ranlib je to, co dělá archiv knihovnou . Archivní soubory Java (.jar ) jsou podobné v tom, že se jedná o soubory zip, které mají některé speciální adresářové struktury vytvořené archivátorem Java.


Propojení proti .a má ještě jeden aspekt vs .o soubory:při propojování všech .o s předané jako argumenty jsou zahrnuty do konečného spustitelného souboru, zatímco položky z libovolného .a argumenty jsou zahrnuty do výstupu linkeru pouze v případě, že řeší závislost na symbolech v programu.

Přesněji řečeno, každý .a soubor je archiv obsahující více .o soubory. Můžete si vzpomenout na každý .o být atomovou jednotkou kódu. Pokud linker potřebuje symbol z jedné z těchto jednotek, celá jednotka se nasaje do konečné binární soustavy; ale žádný z ostatních není, pokud nejsou také potřeba.

Naproti tomu, když předáte .o na příkazovém řádku to linker nasaje, protože jste si to vyžádali.

Abychom to ilustrovali, zvažte následující příklad, kde máme statickou knihovnu obsahující dva objekty a.o a b.o . Náš program bude odkazovat pouze na symboly z a.o . Porovnáme, jak linker zachází s předáním a.o a b.o společně ve srovnání se statickou knihovnou, která obsahuje dva stejné objekty.

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

Kód můžeme zkompilovat pomocí tohoto 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

a získejte dva spustitelné soubory main_o a main_a které se liší tím, že obsah a.cc a b.cc pokud jsou poskytovány prostřednictvím dvou .o s v prvním případě a prostřednictvím .a ve druhém.

Nakonec prozkoumáme symboly finálních spustitelných souborů pomocí nm nástroj:

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

a všimněte si, že main_a ve skutečnosti postrádá nepotřebné symboly z b.o . To znamená, že linker nenasál obsah b.o v archivu lib.a protože žádný ze symbolů z b.cc byly odkazovány.


Soubor .o je výsledkem kompilace jedné kompilační jednotky (v podstatě souboru zdrojového kódu s přidruženými soubory záhlaví), zatímco soubor .a je jeden nebo více souborů .o zabalených jako knihovna.


D Shawleyho odpověď je dobrá, jen jsem chtěl přidat pár bodů, protože ostatní odpovědi odrážejí neúplné pochopení toho, co se děje.

Mějte na paměti, že archivní soubory (.a) nejsou omezeny na to, že obsahují objektové soubory (.o). Mohou obsahovat libovolné soubory. Není to často užitečné, ale podívejte se na informace o závislosti na dynamickém linkeru vložené v archivu, kde najdete hloupý trik s linkerem.

Všimněte si také, že objektové soubory (.o) nemusí být nutně výsledkem jedné kompilační jednotky. Je možné částečně propojit několik menších objektových souborů do jednoho většího souboru.

http://www.mihaiu.name/2002/library_development_linux/ -- hledejte na této stránce výraz "částečné"


Linux
  1. Zálohovat konfigurační soubory

  2. Grep:Vyčerpaná paměť?

  3. Přejmenovat soubory v adresáři?

  1. Dd:Více vstupních souborů?

  2. Soubory protokolu Linux

  3. Použití rsync k synchronizaci souborů

  1. Vložit soubory bez oddělovače?

  2. Příkaz mcopy v Linuxu

  3. wc gzip soubory?