共有ライブラリの作成と利用方法

Unix/Linuxにおける共有ライブラリの作成と利用方法を解説します。この記事は、分割コンパイル手法を理解していることが前提です。

共有ライブラリとは

共有ライブラリとは、実行ファイル生成時に、静的にリンクせず、実行時に、リンク可能なオブジェクトファイルのことです。共有ライブラリは、リンク時にリンクすることが可能で、かつ、実行時に読み込むこともできます。拡張子は「.so」です。

ここで解説する、共有ライブラリは、UNIX/Linuxの仕組みであって、MacやWindowsの仕組みではないことに注意してください。Macの場合は、拡張子が異なります。Windowsには、DLL(ダイナミックリンクライブラリ)という似た仕組みがありますが、UNIX/Linuxの共有ライブラリとは異なります。

共有ライブラリの作成方法

共有ライブラリを作成するには「-shared」オプションを指定します。一般的には、「-fPIC」を指定して位置独立コードとして作成します。

オブジェクトファイル生成する手順に、「-shared」と「-fPIC」オプションを追加して、以下のようにします。

# 通常のコンパイル - オブジェクトファイルの作成
gcc -Iinclude -c -o mylib1.o src/mylib1.c

# 共有ライブラリの作成
gcc -Iinclude -c -shared -fPIC -o mylib1.so src/mylib1.c

共有ライブラリを作成してリンクする

この手順は分割コンパイル手法で使った手順を流用できます。ライブラリを共有ライブラリとして作成します。

アプリケーションのソースファイル

アプリケーションのソースファイル「myapp.c」です。

myapp.c

#include <stdio.h>

#include "mylib1.h"
#include "mylib2.h"

int main(void) {
  
  mylib1_print();
  mylib2_print();
}

ライブラリのヘッダファイル

ライブラリのヘッダファイル「mylib1.h」と「mylib2.h」です。

mylib1.h

#ifndef MYLIB1_H
#define MYLIB1_H

void mylib1_print (void);

#endif

mylib2.h

#ifndef MYLIB2_H
#define MYLIB2_H

void mylib2_print (void);

#endif

ライブラリのソースファイル

ライブラリのソースファイル「mylib1.c」と「mylib2.c」です。

mylib1.c

#include <stdio.h>

#include "mylib1.h"

void mylib1_print (void) {
  printf("mylib1_print\n");
}

mylib2.c

#include <stdio.h>

#include "mylib2.h"

void mylib2_print (void) {
  printf("mylib2_print\n");
}

コンパイル

アプリケーションのソースファイルと、共有ライブラリのソースファイルを、それぞれコンパイルします。ヘッダファイルの場所をオプション「-I」で指定します。「-shared」と「-fPIC」オプションを使って、共有ライブラリを作成します。

gcc -Iinclude -c -o myapp.o src/myapp.c
gcc -Iinclude -c -shared -fPIC -o mylib1.so src/mylib1.c
gcc -Iinclude -c -shared -fPIC -o mylib2.so src/mylib2.c

リンク - 実行ファイルの作成

リンクして実行ファイルを作成します。関数名などのシンボルが、実体に結びつけられます。

gcc -o myapp myapp.o mylib1.so mylib2.so

実行

実行ファイルを実行してみましょう。

./myapp

出力結果です。

mylib1_print
mylib2_print

共有ライブラリを作成して、実行ファイルを作成するときに、リンクする方法をマスターしました。

実行時に共有ライブラリを読み込んで、関数を実行するには?

実行時に共有ライブラリを読み込んで、関数を実行する手順だけを公開します。

1. dlopen関数で、共有ライブラリをオープンします。

2. dlsymで関数名を指定して、関数ポインタを取得します。

3. 関数ポインタから関数を実行します。

共有ライブラリに含まれている関数名などのシンボルを知るには?

共有ライブラリに含まれている関数名などのシンボルを知るには「nm」コマンドを使用します。「name」の略のようです。

nm mylib1.so

出力結果です。

                 U _GLOBAL_OFFSET_TABLE_
0000000000000000 T mylib1_print
                 U puts

nmコマンドは、共有ライブラリだけでなく、実行ファイルやオブジェクトファイルにも使えます。

共有ライブラリの検索

共有ライブラリは、衝突を回避する仕組みを持っています。共有ライブラリは、ファイル名を直接してししなくても「-L」オプションで、共有ライブラリの検索ディレクトリを指定できます。ライブラリ名は「lib」で始まっている必要があります。

共有ライブラリの検索ディレクトリに、共有ライブラリを配置すれば、「-l」オプションで指定された、最初に見つかった共有ライブラリを利用します。「-l」オプションでは、先頭の「lib」と「.so」を省略します。

共有ライブラリ

/foo/lib/libmylib1.so

共有ライブラリのリンク

gcc -o myapp myapp.o -L /foo/lib -l mylib1

関連情報