.o-Dateien vs. .a-Dateien

Lesezeit: 6 Minuten

Was ist der Unterschied zwischen diesen beiden Dateitypen. Ich sehe, dass meine C++-App während der Erstellung der ausführbaren Datei mit beiden Typen verknüpft wird.

Wie erstellt man .a-Dateien? Links, Referenzen und insbesondere Beispiele sind sehr willkommen.

Benutzeravatar von D.Shawley
D. Shawley

.o Dateien sind Objekte. Sie sind die Ausgabe des Compilers und die Eingabe für den Linker/Bibliothekar.

.a Dateien sind Archive. Sie sind Gruppen von Objekten oder statische Bibliotheken und werden auch in den Linker eingegeben.

Zusätzlicher Inhalt

Ich habe den Teil “Beispiele” Ihrer Frage nicht bemerkt. Im Allgemeinen werden Sie ein Makefile verwenden, um statische Bibliotheken zu generieren.

AR = ar 
CC = gcc

objects := hello.o world.o

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

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

Dies wird kompiliert hello.c und world.c in Objekte und archivieren sie dann in der Bibliothek. Je nach Plattform müssen Sie möglicherweise auch ein Dienstprogramm namens ausführen ranlib zum Generieren des Inhaltsverzeichnisses des Archivs.

Eine interessante Randnotiz: .a Dateien sind technisch Archivdateien und keine Bibliotheken. Sie sind analog zu ZIP-Dateien ohne Komprimierung, obwohl sie ein viel älteres Dateiformat verwenden. Das Inhaltsverzeichnis, das von Dienstprogrammen wie generiert wird ranlib macht ein Archiv zu einem Bibliothek. Java-Archivdateien (.jar) sind insofern ähnlich, als es sich um ZIP-Dateien handelt, die einige spezielle Verzeichnisstrukturen haben, die vom Java-Archivierer erstellt wurden.

  • Dies ist zum Thema Make, aber ich dachte nur, ich würde hinzufügen, Sie können auch ersetzen $(objects) in der Rezeptzeile ($(AR) rcu $@ $(objects)) des libby.a Ziel mit $< oder $^ um auf das erste bzw. alle vorausgesetzten Ziele zu verweisen. Dies hat den gleichen Effekt, entfernt aber auch die Redundanz der Angabe $(objects) zweimal, die Referenz muss an zwei Stellen aktualisiert werden, wenn sich der Variablenname oder die Voraussetzungen ändern, und es ist auch weniger Code erforderlich.

    – Shamel Lee

    26. Januar 2017 um 8:34 Uhr

  • @ShammelLee – Ich vermeide es normalerweise $^ da es sich um eine GNU Make-Erweiterung handelt und in beiden nicht vorhanden ist BSD machen oder hinein POSIX machen. Es spielt keine große Rolle, da die meisten Linux-Distributionen sehr stark GNU-basiert sind, aber der Schalter aus /bin/sh von Bash zu Dash reichte aus, um mich weiterhin dazu zu bringen, GNU-spezifische Erweiterungen zu vermeiden.

    – D. Shawley

    28. Januar 2017 um 22:11 Uhr

  • @D.Shawley, worum geht es bei einem “Bibliothekar”? Sagen Sie auch, dass wir verwenden können .a als wäre es ein .tar?

    – Schrittmacher

    3. März 2017 um 18:34 Uhr


  • @Pacerier – ein Bibliothekar fügt dem Archiv normalerweise Metadaten hinzu, die es zu einer “Bibliothek” für eine bestimmte Kompilierungs-Toolchain machen. Was die Verwendung betrifft .a Dateien als Archive, ja, genau das können Sie tun. Dafür wurden sie gemacht. Das tar Formate enthalten mehr Dateimetadaten als die älteren ar Format.

    – D. Shawley

    4. März 2017 um 12:55 Uhr

Eine .o-Datei ist das Ergebnis der Kompilierung einer einzelnen Kompilierungseinheit (im Wesentlichen eine Quellcodedatei mit zugehörigen Header-Dateien), während eine .a-Datei aus einer oder mehreren .o-Dateien besteht, die als Bibliothek gepackt sind.

Benutzeravatar von bstpierre
bstpierre

D Shawleys Antwort ist gut, ich wollte nur ein paar Punkte hinzufügen, weil andere Antworten ein unvollständiges Verständnis dessen widerspiegeln, was vor sich geht.

Beachten Sie, dass Archivdateien (.a) nicht darauf beschränkt sind, Objektdateien (.o) zu enthalten. Sie können beliebige Dateien enthalten. Nicht oft nützlich, aber siehe dynamische Linker-Abhängigkeitsinformationen, die in ein Archiv eingebettet sind, um einen dummen Linker-Trick zu finden.

Beachten Sie auch, dass Objektdateien (.o) nicht unbedingt das Ergebnis einer einzelnen Kompilierungseinheit sind. Es ist möglich, mehrere kleinere Objektdateien teilweise zu einer einzigen größeren Datei zu verknüpfen.

http://www.mihaiu.name/2002/library_development_linux/ — suchen Sie auf dieser Seite nach “teilweise”

Benutzeravatar von Tom Böhmer
Tom Böhmer

Es gibt noch einen weiteren Aspekt des Linkens gegen .a vs .o Dateien: beim Verlinken alle .os, die als Argumente übergeben werden, sind in der endgültigen ausführbaren Datei enthalten, wohingegen Einträge von any .a Argumente werden nur dann in die Ausgabe des Linkers aufgenommen, wenn sie eine Symbolabhängigkeit im Programm auflösen.

Genauer gesagt, jeder .a Datei ist ein Archiv, das aus mehreren besteht .o Dateien. Sie können an jeden denken .o eine atomare Codeeinheit sein. Wenn der Linker ein Symbol von einer dieser Einheiten benötigt, wird die gesamte Einheit in die endgültige Binärdatei gesaugt; aber keine der anderen sind es, es sei denn, sie werden auch benötigt.

Im Gegensatz dazu, wenn Sie a passieren .o In der Befehlszeile saugt der Linker es ein, weil Sie es angefordert haben.

Betrachten Sie zur Veranschaulichung das folgende Beispiel, in dem wir eine statische Bibliothek haben, die zwei Objekte umfasst a.o und b.o. Unser Programm referenziert nur Symbole von a.o. Wir werden vergleichen, wie der Linker das Passieren behandelt a.o und b.o zusammen, im Vergleich zur statischen Bibliothek, die dieselben zwei Objekte umfasst.

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

Wir können den Code mit diesem Makefile kompilieren:

.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

und erhalten Sie zwei ausführbare Dateien main_o und main_a die sich darin unterscheiden, dass der Inhalt von a.cc und b.cc wo durch zwei bereitgestellt .os im ersten Fall und durch a .a in dieser Sekunde.

Zuletzt untersuchen wir die Symbole der endgültigen ausführbaren Dateien mit der nm Werkzeug:

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

und beobachte das main_a Es fehlen nämlich die nicht benötigten Symbole aus b.o. Das heißt, der Linker hat sich die Inhalte nicht zu eigen gemacht b.o innerhalb des Archivs lib.a weil keines der Symbole aus b.cc verwiesen wurden.

Sie können verwenden ar erschaffen .a Datei (statische Bibliothek) aus .o Dateien (Objektdateien)

Sehen man ar für Details.

Benutzeravatar von TWA
TWA

Ich glaube, eine .a-Datei ist ein Archiv, das mehrere Objektdateien enthalten kann.

1416040cookie-check.o-Dateien vs. .a-Dateien

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy