.o
ファイルはオブジェクトです。これらはコンパイラの出力であり、リンカー/ライブラリアンへの入力です。
.a
ファイルはアーカイブです。それらはオブジェクトまたは静的ライブラリのグループであり、リンカーへの入力でもあります。
追加コンテンツ
あなたの質問の「例」の部分に気づきませんでした。一般に、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]
これは hello.c
をコンパイルします と world.c
オブジェクトに変換し、ライブラリにアーカイブします。プラットフォームによっては、ranlib
というユーティリティも実行する必要がある場合があります。 アーカイブの目次を生成します。
興味深い補足:.a
ファイルは技術的にアーカイブ ファイルです ライブラリではありません。はるかに古いファイル形式を使用しますが、圧縮なしの zip ファイルに似ています。 ranlib
などのユーティリティによって生成された目次 アーカイブを ライブラリ にするのは . Java アーカイブ ファイル (.jar
) は、Java アーカイバによって作成された特別なディレクトリ構造を持つ zip ファイルであるという点で似ています。
.a
に対するリンクには、もう 1 つの側面があります。 vs .o
ファイル:リンク時、すべて .o
引数として渡された s は最終的な実行可能ファイルに含まれますが、 .a
からのエントリは 引数は、プログラム内のシンボルの依存関係を解決する場合にのみリンカー出力に含まれます。
より具体的には、各 .a
ファイルは複数の .o
からなるアーカイブです ファイル。 .o
ごとに考えることができます コードの原子単位であること。リンカーがこれらのユニットのいずれかからのシンボルを必要とする場合、ユニット全体が最終的なバイナリに吸い込まれます。
対照的に、 .o
を渡すと、 コマンド ラインでは、要求されたためにリンカがそれを吸い込みます。
これを説明するために、次の例を考えてみましょう。ここでは、2 つのオブジェクト a.o
で構成される静的ライブラリがあります。 と b.o
.私たちのプログラムは a.o
からのシンボルのみを参照します .リンカが a.o
を渡す方法を比較します および b.o
対、同じ 2 つのオブジェクトで構成される静的ライブラリ。
// 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();
}
この 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
2 つの実行可能ファイル main_o
を取得します。 と main_a
a.cc
の内容が異なる点で異なります と b.cc
2 つの .o
を通じて提供される場合 s 最初のケースで .a
を介して
最後に、nm
を使用して最終的な実行可能ファイルのシンボルを調べます ツール:
$ 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()
main_a
であることを確認します 実際、b.o
の不要なシンボルが欠けています .つまり、リンカーは b.o
の内容を吸い込んでいませんでした。 アーカイブ lib.a
内 b.cc
のシンボルがないため
.o ファイルは単一のコンパイル ユニット (基本的には関連するヘッダー ファイルを含むソース コード ファイル) をコンパイルした結果であり、.a ファイルはライブラリとしてパッケージ化された 1 つ以上の .o ファイルです。
D Shawley の回答は良いです。他の回答は何が起こっているのかについての不完全な理解を反映しているため、いくつかの点を追加したかっただけです。
アーカイブ ファイル (.a) は、オブジェクト ファイル (.o) を含むものに限定されないことに注意してください。任意のファイルが含まれている可能性があります。あまり役に立ちませんが、アーカイブに埋め込まれた動的リンカーの依存関係情報を参照して、ばかげたリンカーのトリックを確認してください。
また、オブジェクト ファイル (.o) は、必ずしも単一のコンパイル ユニットの結果ではないことに注意してください。いくつかの小さなオブジェクト ファイルを 1 つの大きなファイルに部分的にリンクすることができます。
http://www.mihaiu.name/2002/library_development_linux/ -- このページで「部分的」を検索