C++ による共有ライブラリの作成
このページは,C++ 言語で共有ライブラリを作成する方法を勉強したときのノートです,
素材は,端末に「Hello world.」と出力する定番のプログラムです.
このページは,ライブラリの勉強としては C++ による動的ライブラリの作成や Autotools を使ったライブラリのビルドシステムに発展します.実践的なプログラミングとしては分子モデリングライブラリ libbuilcule の基礎になっています.
インフォメーション
目次(ページ内リンク)
- 定番の実行ファイル:端末に「Hello world.」と出力するプログラムを作成します
- 共有ライブラリ作成のための予備知識
- 共有ライブラリの作成:端末に「Hello world.」と出力する機能をグローバル関数とし,それを共有ライブラリ(プログラムの起動時に読み込まれるライブラリ)とします
- 共有ライブラリの利用:作成した共有ライブラリを利用する実行ファイルを作成します
参考にしている主なページ
- Linux JF (Japanese FAQ) Project にある Program Library HOWTO:C 言語を使ったライブラリ作成法.「3. 共有ライブラリ」
Debian パッケージ
このページは,Debian GNU/Linux バージョン 13 "trixie" で作成しました.
インストールしている主なパッケージを示します.
| パッケージ名(バージョン) | 注 |
| g++ (14.2.0) | GNU C++ コンパイラ(このページ改定開始前にインストール済みでした) |
| make-doc (4.4.1) | パッケージ化されたドキュメント.HTML ファイルが /usr/share/doc/make-doc/make.html/ にインストールされました |
定番の実行ファイル
プログラミング入門の定番,端末に 「Hello World.」 と出力する実行ファイル hello を作成します,
後で Makefile も手作りしてみます,
ソースコード
下は実行ファイル hello のソースファイル main.cc です,
main.cc
#include <iostream>
int main() {
std::cout << "Hello World." << std::endl;
return 0;
}
ビルドとインストール
ここでの作業は単純で,端末にコマンドを 3 行入力するだけです,
なお,ここではコンパイルとリンクを合わせてビルドと言います,
ソースファイル main.cc をコンパイルして,オブジェクトファイル main.o を作成します,
$ g++ -c main.cc
オブジェクトファイル main.o をリンク(ここでは main.o しかありませんが,一般に,複数のオブジェクトファイルやライブラリと)して実行ファイル hello を生成します,
$ g++ -o hello main.o
実行ファイル hello を /usr/local/bin/ にインストールします,これはスーパーユーザー権限で.
$ sudo install -s hello /usr/local/bin/
実行
端末に
$ ./hello
と入力したら,
Hello World.
と表示されました,どうやら成功したようです,
共有ライブラリ作成のための予備知識
共有ライブラリは,プログラムの一部を独立させて名前をつけて別ディレクトリに置いたものです.それゆえ,
- 異なるバージョンのライブラリを共存させること
- 異なるプログラムから同じライブラリを利用すること
が可能です,
言い換えると,これらを実現するためには,共有ライブラリのバージョンやインストールされたパスを管理したうえで,実行ファイルと適切にリンクしてやる必要があります,
これらの処理は,共有ライブラリのファイル名と ldconfig コマンドでおこないます,
予備知識その 1:共有ライブラリのファイル名
Linux を扱い始めると,語幹が同じで語尾が異なるだけのライブラリファイル (lib□□□.so.△△△ というやつ) が出てくるので戸惑います,
似た名前のファイルが多数存在するのは,シンボリックリンクを作成して,一つのライブラリ(== ファイル)にいろいろな名前を与えているためです,
シンボリックリンクを利用してバージョンごとに語尾の番号を変えれば,異なるバージョンのライブラリを共存させることが可能になります,
Program Library HOWTO の「3. 共有ライブラリ」では,共有ライブラリに与える名前として,主として次に記す 3 個が説明されています,
- real name:"lib" + "ライブラリ名" + ".so" + ".バージョン番号" + ".マイナー番号" + ".リリース番号"
- soname:"lib" + "ライブラリ名" + ".so" + ".バージョン番号"
- linker name:"lib" + "ライブラリ名" + ".so"
real name が実際のファイルの名前で,他は real name へのシンボリックリンクです,
マイナー番号とリリース番号は,どのバージョンのライブラリがインストールされているかを正確に示すもので,設定管理に役立つとのことです,
同じものを別の表現で書くと,
- linker name:"lib" + "ライブラリ名" + ".so"
- soname:"linker name" + ".バージョン番号"
- real name:"soname" + ".マイナー番号" + ".リリース番号"
予備知識その 2:ldconfig コマンド
ldconfig の機能として,「3. 共有ライブラリ」では下の 2 点が挙げられています,
- 既に存在するファイルを調べ,real name へのシンボリックリンクとして soname 群を作成します
- 既に存在するファイルを調べ,キャッシュファイル /etc/ld.so.cache も作成します
「既に存在するファイル」を検索するパスは,/etc/ld.so.conf 以下に記述されています.
ライブラリをインストールする際や,ライブラリを未設定の検索パスにインストールするときに,
ライブラリのパスを /etc/ld.so.conf 以下に記述したり,シェルの設定ファイル(.bashrc など)に記述し,
$ sudo ldconfig
を実行しますが,これは上述の作業を行っているわけです.
この作業により,プログラムの実行時にライブラリを利用できるようになります.
linker name に関する説明を抜粋しておきます,
「ldconfig は linker name を作成しません,これは,古いライブラリをリンクしたい場合を想定しているからです,
通常,この作成作業はライブラリインストール時におこない,単純に,「最新の」soname もしくは最新の real name へのシンボリックリンクとして linker name を作成します,
ほとんどの場合において,ライブラリを更新したら,リンク時にそれを自動的に利用したいと思うでしょうから,soname へのシンボリックリンクとして linker name を作っておくことをお勧めします,」
キャッシュファイル /etc/ld.so.cache はバイナリファイルです.
ldconfig コマンドには,この内容を表示するオプションもあります.すなわち,
$ sudo ldconfig -p
で内容が端末に標準出力されます.下はその末尾です.
libAvogadroCalc.so.1 (libc6,x86-64) => /lib/x86_64-linux-gnu/libAvogadroCalc.so.1
ld-linux-x86-64.so.2 (libc6,x86-64) => /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
Cache generated by: ldconfig (Debian GLIBC 2.36-9+deb12u7) stable release version 2.36