arコマンドはアーカイブファイルを作成するコマンドになります。アーカイブファイルにあるファイルはメンバといいます。arコマンドはC言語などで利用するオブジェクトファイルをまとめたライブラリファイルを作成できるため、バイナリユーティリティとして利用できます。
また、ここで利用するarコマンドはGNU arになります。
arコマンドの構文
arコマンドの基本的な構文
1 |
ar [-]opcode[mod] archive [file...] |
arコマンドのopcodeはコマンドのオプションのように-(ハイフン)をつけて利用できます。
arコマンドはopcodeとarchiveの指定が必須になります。
操作コード(opcode):アーカイブファイルを動作を指定する1文字のコード
修飾子(mod):操作コードの動作を少し変更するコード
アーカイブファイル(archive):アーカイブファイル
ファイルまたはメンバ(file):指定するファイルまたはメンバ
GNU arの場合、操作コードと修飾子の順番を任意に行うことができます。
(例えば、通常: 'ar rc ...'、順番を変更: 'ar cr ...')
操作コードの一覧
操作コード | 動作 |
r | アーカイブにメンバを追加 |
d | アーカイブからメンバを削除 |
t | アーカイブの内容を表示 |
p | アーカイブ内のメンバを標準出力 |
s | アーカイブのインデックスを追加または更新 |
x | アーカイブからメンバを展開 |
q | Quick append アーカイブの最後にメンバを追加 |
m | アーカイブ内のメンバの配置を変更 修飾子なしの場合、アーカイブの最後に移動 修飾子a, b, iで移動する箇所を指定 |
修飾子の一覧
修飾子 | 動作 |
a | アーカイブ内のメンバの後にファイルを追加 |
b | アーカイブ内のメンバの前にファイルを追加 |
c | アーカイブの作成 ただし、この修飾子がなくても基本的にアーカイブは作成されます この修飾子がないときはアーカイブを作成するメッセージが表示されます |
D | deterministic mode ファイルのUID・GID・タイムスタンプがすべてゼロへ設定 |
f | ネイティブのarプログラムとの互換性のためにファイル名を切り捨てます |
i | 修飾子bと同じ |
N | 同名のメンバーが存在する場合にどれを選択するときに使用 |
o | 元々のタイムスタンプを保存 存在しない場合、展開時のタイムスタンプに設定 |
P | アーカイブ内のファイルマッチに絶対パスを使用 他のツールで作成されたアーカイブファイルのために使用 |
s | シンボルテーブルを作成または更新 単独で使用した場合はranlibコマンドと同じ |
S | シンボルテーブルを作成しない |
T | thin archiveを作成 thin archiveはデータの実体がなく、アーカイブのシンボルテーブルとファイルの参照のみを持ちます |
u | 最新のファイルのみを追加 |
U | deterministic modeで操作しない |
v | 詳細モード(操作内容)を表示 |
V | バージョン情報を表示 |
arコマンドの操作コード(opcode)
メンバの追加(r)
操作コードr を用いると指定したアーカイブファイルにメンバを追加できます。アーカイブファイルが存在しない場合は、作成されます。
コマンド例と実行結果
1 2 3 4 5 6 7 8 9 10 11 12 13 |
$ ls file1.o file2.o file3.o $ $ ar r archive.a *.o ar: creating archive.a $ $ ls archive.a file1.o file2.o file3.o $ $ ar t archive.a file1.o file2.o file3.o |
メンバの削除(d)
操作コードd を用いると指定したアーカイブファイルからメンバを削除できます。
コマンド例と実行結果
1 2 3 4 5 6 7 8 9 10 |
$ ar t archive.a file1.o file2.o file3.o $ $ ar d archive.a file2.o $ $ ar t archive.a file1.o file3.o |
アーカイブの内容を確認(t)
操作コードt を用いるとアーカイブファイルの内容を確認できます。
コマンド例と実行結果
1 2 3 4 |
$ ar t archive.a file1.o file2.o file3.o |
アーカイブ内のメンバを標準出力(p)
操作コードp を用いるとアーカイブ内のメンバを標準出力に出力できます。メンバを指定しない場合はすべてのファイルの内容が標準出力に出力されます。
file1.txt
1 |
file1.txt content |
file2.txt
1 |
file2.txt content |
file3.txt
1 |
file3.txt content |
コマンド例と実行結果
1 2 3 4 5 6 7 8 9 10 11 12 |
$ ar t archive.a file1.txt file2.txt file3.txt $ $ ar p archive.a file1.txt file1.txt content $ $ ar p archive.a file1.txt content file2.txt content file3.txt content |
アーカイブのインデックスを追加または更新(s)
操作コードまたは修飾子s を用いるとアーカイブファイルにインデックス(シンボルテーブル)を追加・更新できます。また、操作コードs を用いなくても、アーカイブファイルにオブジェクトファイルを追加するとき、インデックスは基本的に作成されます。
インデックスの確認は'nm -s'コマンドで確認できます。
シンボルテーブルのないアーカイブファイルの作成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
$ ar rS archive.a *.o ar: creating archive.a $ $ nm -s archive.a file1.o: 0000000000000000 T func1 U puts file2.o: 0000000000000000 T func2 U puts file3.o: 0000000000000000 T func3 U puts |
コマンド例と実行結果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
$ ar s archive.a $ $ nm -s archive.a Archive index: func1 in file1.o func2 in file2.o func3 in file3.o file1.o: 0000000000000000 T func1 U puts file2.o: 0000000000000000 T func2 U puts file3.o: 0000000000000000 T func3 U puts |
そのような場合にarコマンドの操作コードs またはranlibコマンドを利用することでアーカイブファイルにインデックスを作成できます。
アーカイブからメンバを展開(x)
操作コードx を用いるとアーカイブファイルからメンバを展開できます。
コマンド例と実行結果
1 2 3 4 5 6 7 8 9 10 11 12 |
$ ls archive.a $ $ ar t archive.a file1.o file2.o file3.o $ $ ar x archive.a file1.o file2.o $ $ ls archive.a file1.o file2.o |
クイックアペンド(q)
操作コードq は通常より高速にアーカイブファイルにメンバを追加します。追加されるメンバはアーカイブファイル内の最後の位置になります。
コマンド例と実行結果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
$ ls archive.a file4.o $ $ ar t archive.a file1.o file2.o file3.o $ $ ar q archive.a file4.o $ $ ar t archive.a file1.o file2.o file3.o file4.o |
アーカイブ内のメンバの配置を変更(m)
操作コードm はアーカイブ内のメンバの配置を変更できます。修飾子を利用しない場合、メンバはアーカイブファイルの最後に移動します。修飾子aまたはb等を用いるとメンバの移動がより詳しく指定できます。
コマンド例と実行結果
1 2 3 4 5 6 7 8 9 10 11 |
$ ar t archive.a file1.o file2.o file3.o $ $ ar m archive.a file2.o $ $ ar t archive.a file1.o file3.o file2.o |
arコマンドの修飾子(mod)
メンバのファイルを追加する位置を指定(a, b)
修飾子a またはb を用いるとアーカイブファイルへファイルを追加する位置を指定できます。
修飾子a を用いるとアーカイブファイル内の指定したメンバの後にファイルが追加されます。
1 2 3 4 5 6 7 |
$ ar ra file2.o archive.a file4.o $ $ ar t archive.a file1.o file2.o file4.o file3.o |
修飾子b を用いるとアーカイブファイル内の指定したメンバの前にファイルが追加されます。また、修飾子iは修飾子b と同じ動作になります。
1 2 3 4 5 6 7 |
$ ar rb file2.o archive.a file4.o $ $ ar t archive.a file1.o file4.o file2.o file3.o |
アーカイブの作成(c)
修飾子c は利用しなくてもアーカイブファイルを作成することができます。修飾子cを利用するとアーカイブファイルを作成したときのメッセージが表示されません。
修飾子cあり
1 2 3 |
$ ar rc archive.a file{1,2,3}.o $ ls archive.a file1.o file2.o file3.o |
修飾子cなし
1 2 3 4 |
$ ar r archive.a file{1,2,3}.o ar: creating archive.a $ ls archive.a file1.o file2.o file3.o |
deterministic mode(D, U)
deterministic modeはアーカイブファイルに保存されるファイルの所有者情報やタイムスタンプがすべてゼロに設定されます。
deterministic modeは修飾子DでONになります。
1 2 3 4 5 6 7 |
$ ar rD archive.a file{1,2,3}.o ar: creating archive.a $ $ ar tv archive.a rw-r--r-- 0/0 1496 Jan 1 09:00 1970 file1.o rw-r--r-- 0/0 1496 Jan 1 09:00 1970 file2.o rw-r--r-- 0/0 1496 Jan 1 09:00 1970 file3.o |
また、deterministic modeは修飾子Uを用いるとOFFになります。
1 2 3 4 5 6 7 |
$ ar rU archive.a file{1,2,3}.o ar: creating archive.a $ $ ar tv archive.a rw-rw-r-- 1000/1000 1496 Jul 15 00:47 2018 file1.o rw-rw-r-- 1000/1000 1496 Jul 15 00:47 2018 file2.o rw-rw-r-- 1000/1000 1496 Jul 15 00:47 2018 file3.o |
元々のタイムスタンプで展開(o)
修飾子oを用いるとアーカイブファイルに保存されるファイルの元々のタイムスタンプで展開できます。修飾子oを利用しなかった時、アーカイブファイル内のメンバを展開すると、展開されたファイルは、展開された時点でのタイムスタンプが設定されます。
コマンド例と実行結果
1 2 3 4 5 6 7 8 9 10 |
$ ar tv archive.a rw-rw-r-- 1000/1000 1496 Jul 15 00:47 2018 file1.o rw-rw-r-- 1000/1000 1496 Jul 15 00:47 2018 file2.o rw-rw-r-- 1000/1000 1496 Jul 15 00:47 2018 file3.o $ $ ar x archive.a file1.o $ ar xo archive.a file2.o $ ls -l file1.o file2.o -rw-rw-r-- 1 ubuntu ubuntu 1496 7月 15 20:03 file1.o -rw-rw-r-- 1 ubuntu ubuntu 1496 7月 15 00:47 file2.o |
シンボルテーブルを作成しない(S)
修飾子Sを利用するとシンボルテーブルを作成せずにアーカイブファイルを作成できます。シンボルテーブルがないライブラリを利用するとコンパイルを行えないかもしれない点に注意が必要になります。
コマンド例
1 |
ar rS archive.a file{1,2,3}.o |
実行結果
1 2 3 4 5 6 7 8 9 10 11 12 13 |
$ nm -s archive.a file1.o: 0000000000000000 T func1 U puts file2.o: 0000000000000000 T func2 U puts file3.o: 0000000000000000 T func3 U puts |
thin archiveを作成(T)
修飾子Tを利用するとthin archiveを作成できます。thin archiveは通常のアーカイブファイルと異なり、メンバの実際のデータを持っていません。thin archiveが持っているのは、シンボルテーブルとメンバになっているファイルの参照になります。参照しているファイルが利用できなくなるとアーカイブファイルとして利用できなくなります。
コマンド例と実行結果
1 2 3 4 5 6 7 8 9 10 |
$ ar rT archive.a file{1,2,3}.o ar: creating archive.a $ ar tv archive.a rw-r--r-- 0/0 1496 Jan 1 09:00 1970 file1.o rw-r--r-- 0/0 1496 Jan 1 09:00 1970 file2.o rw-r--r-- 0/0 1496 Jan 1 09:00 1970 file3.o $ $ rm file1.o $ ar tv archive.a ar: archive.a: Malformed archive |
最新のファイルのみを追加(u)
修飾子uを利用するとアーカイブファイル内のメンバと追加するファイルのタイムスタンプを比較して、ファイルを更新できます。この機能はアーカイブファイルのタイムスタンプを利用する必要があるため、deterministic modeがデフォルトでONならば、修飾子UでOFFにする必要があります。
コマンド例と実行結果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
$ ar rU archive.a file{1,2,3}.o ar: creating archive.a $ $ ar tv archive.a rw-rw-r-- 1000/1000 1496 Jul 15 21:13 2018 file1.o rw-rw-r-- 1000/1000 1496 Jul 15 21:15 2018 file2.o rw-rw-r-- 1000/1000 1496 Jul 15 21:15 2018 file3.o $ $ touch file{2,3}.o $ ar rUuv archive.a file{1,2,3}.o r - file2.o r - file3.o $ $ ar tv archive.a rw-rw-r-- 1000/1000 1496 Jul 15 21:13 2018 file1.o rw-rw-r-- 1000/1000 1496 Jul 15 21:18 2018 file2.o rw-rw-r-- 1000/1000 1496 Jul 15 21:18 2018 file3.o |
詳細モード(v)
修飾子vを用いると操作した内容が表示されます。また、操作コードt と一緒に用いるとファイル名のほかにファイルの情報が表示されます。
コマンド例と実行結果
1 2 3 4 5 6 7 8 9 10 |
$ ar rv archive.a file{1,2,3}.o ar: creating archive.a a - file1.o a - file2.o a - file3.o $ $ ar tv archive.a rw-r--r-- 0/0 1496 Jan 1 09:00 1970 file1.o rw-r--r-- 0/0 1496 Jan 1 09:00 1970 file2.o rw-r--r-- 0/0 1496 Jan 1 09:00 1970 file3.o |
arコマンドの対話モード
arコマンドは-Mオプションを用いると対話モードになります。この対話モードでは、特定の命令を実行することでアーカイブファイルを操作できます。また、スクリプトは標準入力を用いて実行することもできます。
命令の種類
コマンド | 機能 |
CREATE | アーカイブファイルの作成し、対話モードで操作する現在のアーカイブファイルに設定 |
OPEN | アーカイブファイルを開き、対話モードで操作する現在のアーカイブファイルに設定 |
ADDLIB | アーカイブファイルの内容を現在のアーカイブファイルに追加 |
ADDMOD | メンバを追加 |
DELETE | メンバを削除 |
EXTRACT | メンバを展開 |
LIST | 現在のアーカイブファイルの内容を表示 |
REPLACE | 現在のアーカイブファイルでの既存のメンバを、 その既存のメンバに対応するカレントディレクトリのファイルで置き換える |
CLEAR | SAVEコマンドを行うまでの現在のアーカイブファイルの操作内容を取り消す |
SAVE | 現在のアーカイブファイルの変更を保存し、 作成またはオープンしたファイル名でアーカイブファイルを保存 |
END | arコマンドの対話モードを終了 変更を保存していない場合はその変更内容を破棄 |
DIRECTORY | アーカイブファイルの内容を表示 |
VERBOSE | DIRECTORYコマンドでの表示内容を'ar t'形式か'ar tv'形式かで切り替える |
参考:GNU Binary Utilities: ar scripts
コマンド例と実行結果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
$ ls file1.o file2.o file3.o $ $ ar -M AR >create archive.a AR >addmod file1.o file2.o file3.o AR >list Current open archive is tmp-archive.a file1.o file2.o file3.o AR >save AR >open archive.a AR >list Current open archive is tmp-archive.a rw-r--r-- 0/0 1648 Jan 1 09:00 1970 file1.o rw-r--r-- 0/0 1496 Jan 1 09:00 1970 file2.o rw-r--r-- 0/0 1496 Jan 1 09:00 1970 file3.o AR >end $ |
静的ライブラリを利用してコンパイル
gccを利用して、静的ライブラリを利用してコンパイルを行う場合、オプションを用いない場合と-Lオプションや-lオプション等のオプションを用いる場合があります。
オプションを用いない場合
オプションを利用しない場合、単純にソースファイルと一緒にライブラリファイルをコマンドライン引数に指定して、コンパイルします。
libarchive.a(nmコマンドでのシンボルの内容)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
$ nm -s libarchive.a Archive index: func1 in file1.o func2 in file2.o func3 in file3.o file1.o: 0000000000000000 T func1 U puts file2.o: 0000000000000000 T func2 U puts file3.o: 0000000000000000 T func3 U puts |
testlib.c
1 2 3 4 5 6 7 8 9 |
void func1(void); void func2(void); void func3(void); void main(void){ func1(); func2(); func3(); } |
コマンド例と実行結果
1 2 3 4 5 6 7 |
$ ls libarchive.a testlib.c $ gcc testlib.c libarchive.a $ ./a.out func1 func2 func3 |
オプションを用いる場合
-Lオプションは利用するライブラリファイルが存在するディレクトリを指定します。このディレクトリはライブラリファイルを検索するためのディレクトリになります。
-lオプションは利用するライブラリファイルを指定します。ライブラリファイルは基本的に接頭辞に'lib'を、接尾辞に'.a'があるファイルが利用されます。
例えば、'-l archive'を指定した場合は、libarchive.aという名前のファイルが検索されます。
また、最初に':'を付けることでファイル名をそのまま指定することもできます。':'を付けた場合は例えば、'-l:libarchive.a'のように指定します。
コマンド例と実行結果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
$ ls libarchive.a testlib.c $ gcc testlib.c -L. -larchive $ ./a.out func1 func2 func3 $ $ rm a.out $ gcc testlib.c -L. -l:libarchive.a $ ./a.out func1 func2 func3 |
また、ヘッダーファイルを利用する場合、-Iオプションでヘッダファイルを検索するディレクトリを指定できます。
testlib.h
1 2 3 |
void func1(void); void func2(void); void func3(void); |
testlib2.c
1 2 3 4 5 6 7 |
#include <testlib.h> void main(void){ func1(); func2(); func3(); } |
コマンド例と実行結果
1 2 3 4 5 6 7 |
$ ls libarchive.a testlib.h testlib2.c $ gcc -I. -L. testlib2.c -larchive $ ./a.out func1 func2 func3 |
ライブラリファイルを利用しファイルをコンパイルする際の引数の順序について
ライブラリファイルを利用してコンパイルする際、コマンドライン引数にあるファイルや-lオプションの順序によって、ファイルのコンパイルが失敗する場合があります。
失敗例
1 2 3 4 5 6 7 8 9 10 11 12 13 |
$ gcc libarchive.a testlib.c /tmp/ccOR6RwU.o: In function `main': testlib.c:(.text+0x5): undefined reference to `func1' testlib.c:(.text+0xa): undefined reference to `func2' testlib.c:(.text+0xf): undefined reference to `func3' collect2: error: ld returned 1 exit status $ $ gcc -L. -larchive testlib.c /tmp/cc2FxlEM.o: In function `main': testlib.c:(.text+0x5): undefined reference to `func1' testlib.c:(.text+0xa): undefined reference to `func2' testlib.c:(.text+0xf): undefined reference to `func3' collect2: error: ld returned 1 exit status |
コンパイラはコマンドライン引数のファイル(-lオプションで指定しているファイルを含めて)を順番に処理していきます。処理しているファイルに未定義のシンボルがあり、次以降にアーカイブファイルを処理する場合、そのアーカイブファイルを一回検索し、未定義のシンボルに該当するシンボルがあるなら、そのシンボル同士を関連付けます。
そのため、上の失敗例のように先にアーカイブファイルを処理すると未定義のシンボルをうまく関連付けることができません。
なので、ライブラリファイルを利用する場合は、ファイルをコンパイルする順序を少し意識する必要があります。