Linuxで動的ライブラリと実行ファイルの作成についての記事を以下で記載した。
https://qiita.com/miyo4/items/6515f7511d6830096a9f
具体的なサンプルを以下で示す。
以下の手順は、すべて同一ディレクトリで行っています。
ソースファイルの準備
以下の5つのファイルを準備する。
# ls -l
-rw-r--r-- 1 root root 101 6月 1 17:07 A.c
-rw-r--r-- 1 root root 12 6月 1 19:15 A.h
-rw-r--r-- 1 root root 101 6月 1 17:10 B.c
-rw-r--r-- 1 root root 12 6月 1 17:09 B.h
-rw-r--r-- 1 root root 105 6月 1 17:40 main.c
void A();
#include <stdio.h>
#include "A.h"
void A() {
int num = 10;
printf("inside A, num = %d\n", num);
}
void B();
#include <stdio.h>
#include "B.h"
void B() {
int num = 10;
printf("inside B, num = %d\n", num);
}
#include <stdio.h>
#include "A.h"
#include "B.h"
void main(){
printf("This is main.\n");
A();
B();
}
動的ライブラリの作成
コンパイル
# gcc -fPIC -c A.c
# gcc -fPIC -c B.c
# ls -l
-rw-r--r-- 1 root root 101 6月 1 17:07 A.c
-rw-r--r-- 1 root root 12 6月 1 19:15 A.h
-rw-r--r-- 1 root root 1568 6月 1 18:26 A.o ←オブジェクトファイルを作成完了
-rw-r--r-- 1 root root 101 6月 1 17:10 B.c
-rw-r--r-- 1 root root 12 6月 1 17:09 B.h
-rw-r--r-- 1 root root 1568 6月 1 18:27 B.o ←オブジェクトファイルを作成完了
-rw-r--r-- 1 root root 105 6月 1 17:40 main.c
・A.h、B.h のincludeを "" で囲っているため、ヘッダファイルの検索パスとしてカレントディレクトリが自動で追加されているので-I
オプションの指定は不要だが、<>
の場合は-I
が必要になる。
動的ライブラリ作成(リンク)
# gcc -shared -o libA.so A.o
# gcc -shared -o libB.so B.o
# ls -l
-rw-r--r-- 1 root root 101 6月 1 17:07 A.c
-rw-r--r-- 1 root root 12 6月 1 19:15 A.h
-rw-r--r-- 1 root root 1568 6月 1 18:26 A.o
-rw-r--r-- 1 root root 101 6月 1 17:10 B.c
-rw-r--r-- 1 root root 12 6月 1 17:09 B.h
-rw-r--r-- 1 root root 1568 6月 1 18:27 B.o
-rwxr-xr-x 1 root root 8024 6月 1 18:27 libA.so ←動的ライブラリを作成完了
-rwxr-xr-x 1 root root 8024 6月 1 18:27 libB.so ←動的ライブラリを作成完了
-rw-r--r-- 1 root root 105 6月 1 17:40 main.c
動的ライブラリを利用する実行ファイルの作成
コンパイル
# gcc -c main.c
# ls -l
-rw-r--r-- 1 root root 101 6月 1 17:07 A.c
-rw-r--r-- 1 root root 12 6月 1 19:15 A.h
-rw-r--r-- 1 root root 1568 6月 1 18:26 A.o
-rw-r--r-- 1 root root 101 6月 1 17:10 B.c
-rw-r--r-- 1 root root 12 6月 1 17:09 B.h
-rw-r--r-- 1 root root 1568 6月 1 18:27 B.o
-rwxr-xr-x 1 root root 8024 6月 1 18:27 libA.so
-rwxr-xr-x 1 root root 8024 6月 1 18:27 libB.so
-rw-r--r-- 1 root root 105 6月 1 17:40 main.c
-rw-r--r-- 1 root root 1608 6月 1 19:15 main.o ←オブジェクトファイルを作成完了
・A.h
とB.h
のinclude定義を""
で囲っているため、ヘッダファイルの検索パスとしてカレントディレクトリが自動で追加されているため-I
オプションは不要だが、<>
で囲っている場合は-I
が必要になる。
実行ファイル作成(リンク)
# gcc -o main main.o -L. -lA -lB
# ls -l
-rw-r--r-- 1 root root 101 6月 1 17:07 A.c
-rw-r--r-- 1 root root 12 6月 1 19:15 A.h
-rw-r--r-- 1 root root 1568 6月 1 18:26 A.o
-rw-r--r-- 1 root root 101 6月 1 17:10 B.c
-rw-r--r-- 1 root root 12 6月 1 17:09 B.h
-rw-r--r-- 1 root root 1568 6月 1 18:27 B.o
-rwxr-xr-x 1 root root 8024 6月 1 18:27 libA.so
-rwxr-xr-x 1 root root 8024 6月 1 18:27 libB.so
-rwxr-xr-x 1 root root 8464 6月 1 19:16 main ←実行ファイルの作成完了
-rw-r--r-- 1 root root 105 6月 1 17:40 main.c
-rw-r--r-- 1 root root 1608 6月 1 19:15 main.o
実行ファイルが作成できました。
もし、共有ライブラリがリンク時に見つからない場合は以下のようなエラーが出力されます。
# gcc -o main main.o
main.o: 関数 `main' 内:
main.c:(.text+0x14): `A' に対する定義されていない参照です
main.c:(.text+0x1e): `B' に対する定義されていない参照です
collect2: エラー: ld はステータス 1 で終了しました
では、いよいよ実行ファイルを実行してみます。
実行ファイルmain
を実行すると、共有ライブラリlibA.so
が見つからないと怒られました。
# ./main
./main: error while loading shared libraries: libA.so: cannot open shared object file: No such file or directory
原因は、共有ライブラリlibA.so
とlibB.so
がカレントディレクトリに存在するが、ファイル実行時の標準のライブラリ検索パスにカレントディレクトリが含まれていないからです。この場合、環境変数LD_LIBRARY_PATHにカレントディレクトリを追加することで解決できる。
# export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
# ./main
This is main.
inside A, num = 10
inside B, num = 10
おまけ。
作成した実行ファイルの依存するライブラリを確認するとlibA.so
とlibB.so
が必要なことが分かります。
[root@rhel79 libtest]# ldd ./main
linux-vdso.so.1 => (0x00007ffc075f8000)
libA.so (0x00007fb0304d6000)
libB.so (0x00007fb0302d4000)
libc.so.6 => /lib64/libc.so.6 (0x00007fb02ff06000)
/lib64/ld-linux-x86-64.so.2 (0x00007fb0306d8000)
次に、動的ライブラリlibA.so
に含まれるシンボルを確認してみるとA
が含まれていることが分かります。
[root@rhel79 libtest]# nm libA.so
00000000000006a5 T A
0000000000200e18 d _DYNAMIC
0000000000201000 d _GLOBAL_OFFSET_TABLE_
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
w _Jv_RegisterClasses
0000000000000768 r __FRAME_END__
00000000000006ec r __GNU_EH_FRAME_HDR
0000000000200e08 d __JCR_END__
0000000000200e08 d __JCR_LIST__
0000000000201030 d __TMC_END__
0000000000201030 B __bss_start
w __cxa_finalize@@GLIBC_2.2.5
0000000000000630 t __do_global_dtors_aux
0000000000200e00 t __do_global_dtors_aux_fini_array_entry
0000000000200e10 d __dso_handle
0000000000200df8 t __frame_dummy_init_array_entry
w __gmon_start__
0000000000201030 D _edata
0000000000201038 B _end
00000000000006cc T _fini
0000000000000558 T _init
0000000000201030 b completed.6355
00000000000005c0 t deregister_tm_clones
0000000000000670 t frame_dummy
U printf@@GLIBC_2.2.5
00000000000005f0 t register_tm_clones
確認環境は Red Hat Enterprise Linux 7.9 です。
以上です。