[Linux]動的ライブラリと実行ファイル作成のサンプル

Linuxで動的ライブラリと実行ファイルの作成についての記事を以下で記載した。
https://qiita.com/miyo4/items/6515f7511d6830096a9f

具体的なサンプルを以下で示す。
以下の手順は、すべて同一ディレクトリで行っています。

# ソースファイルの準備
以下の5つのファイルを準備する。
```shell
# 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
```
```c:A.h
void A();
```
```c:A.c
#include <stdio.h>
#include "A.h"
void A() {
        int num = 10;
        printf("inside A, num = %d\n", num);
}
```
```c:B.h
void B();
```
```c:B.c
#include <stdio.h>
#include "B.h"
void B() {
        int num = 10;
        printf("inside B, num = %d\n", num);
}
```
```c:main.c
#include <stdio.h>
#include "A.h"
#include "B.h"
void main(){
        printf("This is main.\n");
        A();
        B();
}
```

# 動的ライブラリの作成
## コンパイル
```shell
# 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`が必要になる。

## 動的ライブラリ作成（リンク）
```shell
# 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
```

# 動的ライブラリを利用する実行ファイルの作成
## コンパイル
```shell
# 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`が必要になる。

## 実行ファイル作成（リンク）
```shell
# 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
```
実行ファイルが作成できました。
もし、共有ライブラリがリンク時に見つからない場合は以下のようなエラーが出力されます。
```shell
# gcc -o main main.o
main.o: 関数 `main' 内:
main.c:(.text+0x14): `A' に対する定義されていない参照です
main.c:(.text+0x1e): `B' に対する定義されていない参照です
collect2: エラー: ld はステータス 1 で終了しました
```

では、いよいよ実行ファイルを実行してみます。
実行ファイル`main`を実行すると、共有ライブラリ`libA.so`が見つからないと怒られました。
```shell
# ./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にカレントディレクトリを追加することで解決できる。
```:shell
# export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
# ./main
This is main.
inside A, num = 10
inside B, num = 10
```

おまけ。
作成した実行ファイルの依存するライブラリを確認すると`libA.so`と`libB.so`が必要なことが分かります。
```shell
[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`が含まれていることが分かります。
```shell
[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 です。
以上です。