Linux 動的ライブラリ/静的ライブラリ/共有ライブラリ 備忘録
ライブラリの命名規則
-
ライブラリには特別な命名規則があります。
foo
というライブラリはlibfoo.so
またはlibfoo.a
というファイル名が期待されます。
ライブラリをリンクする場合、-l
オプションにライブラリ名を指定します。gcc ... -lfoo ...
ライブラリを作成する場合、
libfoo.so
またはlibfoo.a
というファイル名で作成する必要があります。
動的ライブラリの作成
-
ソースファイルをコンパイルしてオブジェクトファイルを作成します。この時、位置非依存コード(position-independent code)の
-fPIC
オプションを指定します。gcc -c -fPIC some_file.c
オブジェクトファイルの名前は、元のソースコードと同じファイル名で拡張子
.o
となります。 -
オブジェクトファイルから共有ライブラリをリンクします。
gcc -shared -o libfoo.so.x.y -Wl,-soname,libfoo.so.x some_file.o
リンク時に使用する
x
はメジャーバージョン。y
はマイナーバージョンとなります。 -
libfoo.so.x.y
ファイルを、システムのダイナミックリンカーが見つけることができる適切な場所にコピーしてください。cp libfoo.so.x.y /usr/local/lib
ldconfig
コマンドはダイナミックリンカーの構成および実行時のライブラリ解決を行います。ldconfig
が検索する共有ライブラリのパスは/etc/ld.so.conf
で確認できます。 -
soname
のメカニズムに対応したシンボリックリンクを作成します。ln -s libfoo.so.x.y libfoo.so.x ln -s libfoo.so.x libfoo.so
静的ライブラリの作成
-
GCCで中間オブジェクトファイルを作成します。
gcc -c source_file.c ...
必要に応じて、さらにソースファイルを追加してください。出来上がったオブジェクトファイルは、ファイル名は同じですが、ファイル名の拡張子は.oになります。
-
binutils
パッケージのar
ツールを使用して、オブジェクトファイルを静的ライブラリ(アーカイブ)にします。ar rcs libfoo.a source_file.o ...
libfoo.a
ファイルが作成されます。 -
静的ライブラリファイルを適切なディレクトリにコピーします。
静的ライブラリをリンクする場合、GCCはファイル名の拡張子
.a
から、ライブラリが静的リンク用のアーカイブであることを自動的に認識します。gcc ... -lfoo ...
共有ライブラリの一覧
ldconfig
コマンドの-p
オプションで、現在キャッシュに格納されているディレクトリとライブラリ候補を一覧で表示できます。
$ ldconfig -p
870 libs found in cache `/etc/ld.so.cache'
libzvbi.so.0 (libc6,x86-64) => /lib/x86_64-linux-gnu/libzvbi.so.0
libzvbi-chains.so.0 (libc6,x86-64) => /lib/x86_64-linux-gnu/libzvbi-chains.so.0
libzstd.so.1 (libc6,x86-64) => /lib/x86_64-linux-gnu/libzstd.so.1
libz.so.1 (libc6,x86-64) => /lib/x86_64-linux-gnu/libz.so.1
libz.so (libc6,x86-64) => /lib/x86_64-linux-gnu/libz.so
libyaml-0.so.2 (libc6,x86-64) => /lib/x86_64-linux-gnu/libyaml-0.so.2
libx265.so.179 (libc6,x86-64) => /lib/x86_64-linux-gnu/libx265.so.179
libx264.so.155 (libc6,x86-64) => /lib/x86_64-linux-gnu/libx264.so.155
...
オブジェクトファイルの情報表示
objdump
コマンドの-x
オプションで、表示可能な全てのヘッダー情報を表示します。
-
.so
ファイルの場合
$ objdump -x /usr/lib/x86_64-linux-gnu/libjpeg.so
/usr/lib/x86_64-linux-gnu/libjpeg.so: file format elf64-x86-64
/usr/lib/x86_64-linux-gnu/libjpeg.so
architecture: i386:x86-64, flags 0x00000150:
...
Dynamic Section:
NEEDED libc.so.6
SONAME libjpeg.so.8
...
SYMBOL TABLE:
no symbols
...
-
.a
ファイルの場合
$ objdump -x /usr/lib/x86_64-linux-gnu/libjpeg.a
In archive /usr/lib/x86_64-linux-gnu/libjpeg.a:
jcapimin.c.o: file format elf64-x86-64
rw-r--r-- 0/0 3800 Jan 1 09:00 1970 jcapimin.c.o
architecture: i386:x86-64, flags 0x00000011:
HAS_RELOC, HAS_SYMS
start address 0x0000000000000000
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000496 0000000000000000 0000000000000000 00000040 2**4
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
1 .data 00000000 0000000000000000 0000000000000000 000004d6 2**0
CONTENTS, ALLOC, LOAD, DATA
2 .bss 00000000 0000000000000000 0000000000000000 000004d6 2**0
ALLOC
3 .rodata.cst8 00000008 0000000000000000 0000000000000000 000004d8 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
4 .note.GNU-stack 00000000 0000000000000000 0000000000000000 000004e0 2**0
CONTENTS, READONLY
5 .note.gnu.property 00000020 0000000000000000 0000000000000000 000004e0 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
6 .eh_frame 00000148 0000000000000000 0000000000000000 00000500 2**3
CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
SYMBOL TABLE:
0000000000000000 l d .text 0000000000000000 .text
0000000000000000 l .rodata.cst8 0000000000000000 .LC0
0000000000000000 l d .data 0000000000000000 .data
0000000000000000 l d .bss 0000000000000000 .bss
0000000000000000 l d .rodata.cst8 0000000000000000 .rodata.cst8
0000000000000000 l d .note.GNU-stack 0000000000000000 .note.GNU-stack
0000000000000000 l d .note.gnu.property 0000000000000000 .note.gnu.property
0000000000000000 l d .eh_frame 0000000000000000 .eh_frame
0000000000000000 g F .text 0000000000000191 jpeg_CreateCompress
0000000000000000 *UND* 0000000000000000 _GLOBAL_OFFSET_TABLE_
0000000000000000 *UND* 0000000000000000 jinit_memory_mgr
0000000000000000 *UND* 0000000000000000 jpeg_natural_order
00000000000001a0 g F .text 0000000000000009 jpeg_destroy_compress
0000000000000000 *UND* 0000000000000000 jpeg_destroy
00000000000001b0 g F .text 0000000000000009 jpeg_abort_compress
0000000000000000 *UND* 0000000000000000 jpeg_abort
00000000000001c0 g F .text 000000000000005b jpeg_suppress_tables
0000000000000220 g F .text 0000000000000108 jpeg_finish_compress
0000000000000330 g F .text 0000000000000095 jpeg_write_marker
00000000000003d0 g F .text 0000000000000055 jpeg_write_m_header
0000000000000430 g F .text 000000000000000e jpeg_write_m_byte
0000000000000440 g F .text 0000000000000056 jpeg_write_tables
0000000000000000 *UND* 0000000000000000 jinit_marker_writer
...
オブジェクトファイルのシンボル一覧
nm
コマンドでオブジェクトファイルのシンボル一覧を確認できます。
-
.so
ファイルの場合
$ nm /usr/lib/x86_64-linux-gnu/libjpeg.so
nm: /usr/lib/x86_64-linux-gnu/libjpeg.so: no symbols
-
.a
ファイルの場合
$ nm /usr/lib/x86_64-linux-gnu/libjpeg.a
jcapimin.c.o:
0000000000000000 r .LC0
U _GLOBAL_OFFSET_TABLE_
U jinit_marker_writer
U jinit_memory_mgr
0000000000000000 T jpeg_CreateCompress
U jpeg_abort
00000000000001b0 T jpeg_abort_compress
U jpeg_destroy
00000000000001a0 T jpeg_destroy_compress
0000000000000220 T jpeg_finish_compress
U jpeg_natural_order
00000000000001c0 T jpeg_suppress_tables
0000000000000430 T jpeg_write_m_byte
00000000000003d0 T jpeg_write_m_header
0000000000000330 T jpeg_write_marker
0000000000000440 T jpeg_write_tables
...
共有ライブラリ
共有ライブラリの.so
ファイルと.a
ファイルには、それぞれ異なる役割があります。.so
ファイルには関連する動的リンクの情報があります。.a
ファイルにはリンクに必要なシンボルテーブルがあります。
-
.so
ファイルの場合
...
Dynamic Section:
NEEDED libc.so.6
SONAME libjpeg.so.8
...
SYMBOL TABLE:
no symbols
...
-
.a
ファイルの場合
...
jcapimin.c.o:
...
0000000000000000 T jpeg_CreateCompress
...
...
GLOBAL(void)
jpeg_CreateCompress(j_compress_ptr cinfo, int version, size_t structsize)
{
...
}
...
共有ライブラリのリンク
-
コンパイル時のオプションに、共有ライブラリの指定がない場合、エラーになります。
$ gcc foo.c -o foo.out /usr/bin/ld: /tmp/cc2ZAaOQ.o: in function `main': test.c:(.text+0x2e): undefined reference to `jpeg_CreateCompress' collect2: error: ld returned 1 exit status
-
.so
ファイルの場合
gcc foo.c /usr/lib/x86_64-linux-gnu/libjpeg.so -o foo.out
-
.a
ファイルの場合
gcc foo.c /usr/lib/x86_64-linux-gnu/libjpeg.a -o foo.out
共有ライブラリの依存関係がない場合、
.so
ファイルまたは.a
ファイルでコンパイルできます。 -
-
複数の共有ライブラリに依存する場合、
.a
ファイルではコンパイルできません。共有ライブラリの依存関係を解決する必要があります。$ gcc foo.c /usr/lib/x86_64-linux-gnu/libavformat.a -o foo.out /usr/bin/ld: /usr/lib/x86_64-linux-gnu/libavformat.a(avienc.o): in function `avi_add_ientry': (.text+0x1d9): undefined reference to `av_realloc_f' /usr/bin/ld: (.text+0x20e): undefined reference to `av_malloc' /usr/bin/ld: /usr/lib/x86_64-linux-gnu/libavformat.a(avienc.o): in function `avi_write_counters': (.text+0x56b): undefined reference to `av_log' /usr/bin/ld: /usr/lib/x86_64-linux-gnu/libavformat.a(avienc.o): in function `update_odml_entry': ...
-
複数の共有ライブラリに依存する場合、
.so
ファイルをコンパイルオプションに含めると解決できます。gcc foo.c /usr/lib/x86_64-linux-gnu/libavformat.so -o foo.out
-
コンパイル時、
-l
オプションにライブラリ名を指定することで、同様にコンパイルできます。gcc foo.c -lavformat -o foo.out
コンパイル時の依存関係をpkg-config
で解決する
-
pkg-config
はインストールされたライブラリに関するメタデータを返します。-
--cflags
オプション
$ pkg-config --cflags libavformat -I/usr/include/x86_64-linux-gnu
-
--libs
オプション
$ pkg-config --libs libavformat -lavformat
-
-
コンパイル時の依存関係を
pkg-config
コマンドで解決する方法です。gcc foo.c $(pkg-config --cflags --libs libavformat) -o foo.out
-
pkg-config
は/usr/lib/pkgconfig
等を検索し、.pc
ファイルに記録されたライブラリに関するメタデータを返します。以下のようにメタデータは定義されています。$ cat /usr/lib/x86_64-linux-gnu/pkgconfig/libavformat.pc prefix=/usr exec_prefix=${prefix} libdir=/usr/lib/x86_64-linux-gnu includedir=/usr/include/x86_64-linux-gnu Name: libavformat Description: FFmpeg container format library Version: 58.29.100 Requires: Requires.private: libavcodec >= 58.54.100, libswresample >= 3.5.100, libavutil >= 56.31.100 Conflicts: Libs: -L${libdir} -lavformat Libs.private: -lm -lxml2 -lbz2 -lgme -lstdc++ -lopenmpt -lstdc++ -lchromaprint -lbluray -lz -lgnutls -lssh -ldl Cflags: -I${includedir}