Linuxの静的リンクとは?ライブラリを静的に結合する方法を初心者向けに解説
生徒
「Linuxの静的リンクって、ファイル同士をつなぐシンボリックリンクと同じものですか?」
先生
「名前にリンクと付きますが意味は別です。静的リンクは、プログラムを作るときに必要なライブラリのコードを実行ファイルへ結合する仕組みです。」
生徒
「ライブラリを実行ファイルへ入れておくと、どんな利点があるんですか?」
先生
「実行時に外部の共有ライブラリへ依存しにくくなるのが特徴です。静的ライブラリとの関係や動的リンクとの違いも含めて順番に見ていきましょう。」
Linuxを初めて学ぶ人や、 OS・プロセス・メモリ管理・仮想マシン・コンテナの仕組みを図解で理解したい人におすすめの定番書籍です。
試して理解 Linuxのしくみを見る※ Amazonアソシエイト広告リンク
1. Linuxの静的リンクとは?
Linuxの読み方はLinux(リナックス)です。静的リンクの読み方は静的リンク(セイテキリンク)で、英語ではstatic linking(スタティックリンキング)といいます。静的リンクとは、プログラムを実行できる形へ仕上げるときに、必要なライブラリやオブジェクトファイルのコードを実行ファイル側へ結合する方法です。
プログラムでは、画面へ文字を表示する処理や計算処理などをすべて一から作るのではなく、あらかじめ用意されたライブラリを利用することがあります。ライブラリの読み方はlibrary(ライブラリ)で、再利用できる処理をまとめた部品集のようなものです。静的リンクでは、その部品のうち必要な部分をビルド時に実行ファイルへ取り込みます。
ビルドの読み方はbuild(ビルド)で、ソースコードをコンパイルし、必要な部品を結び付けて実行ファイルなどを作る一連の作業を意味します。初心者の方は、家具を完成させる前に必要な部品を全部組み付けておくイメージで考えるとわかりやすいでしょう。完成後は、組み付けた部品を外から毎回借りなくても使える状態になります。
静的リンクは、ファイルへのショートカットを作るシンボリックリンクとは別の概念です。ここでのリンクは、プログラムの部品を結合して実行ファイルを作る処理を指します。
2. コンパイルとリンクの違いを理解する
静的リンクを理解するには、コンパイルとリンクの違いを知っておくことが大切です。コンパイルの読み方はcompile(コンパイル)で、人が書いたソースコードをコンピュータが扱いやすい形へ変換する処理です。C言語では、コンパイルによってオブジェクトファイルを作ることがあります。
オブジェクトファイルの読み方はobject file(オブジェクトファイル)です。LinuxのC言語開発では、拡張子が.oのファイルをよく使います。オブジェクトファイルだけでは、必要な関数が別のファイルやライブラリにある場合、そのまま実行できません。そこでリンカが複数の部品を結び付けます。
リンカの読み方はlinker(リンカ)です。リンカは、オブジェクトファイルとライブラリに含まれる必要なコードを結び付け、最終的な実行ファイルを作ります。静的リンクという言葉は、このリンク処理の段階でライブラリのコードを取り込むことを表しています。
LinuxでC言語を扱うときによく使われるGCCの読み方はGCC(ジーシーシー)です。GCCを使うと、コンパイルからリンクまでを一つのコマンドで行うこともできます。処理を分けて考えると、静的リンクがどの段階で行われているのか理解しやすくなります。
3. 静的リンクと動的リンクの違い
静的リンクと対になる考え方として、動的リンクがあります。動的リンクの読み方は動的リンク(ドウテキリンク)で、英語ではdynamic linking(ダイナミックリンキング)といいます。どちらもプログラムからライブラリの機能を利用するための方法ですが、ライブラリのコードをどのように扱うかが異なります。
静的リンクでは、リンク時に必要なコードを実行ファイルへ取り込みます。一方、動的リンクでは、実行時に外部の共有ライブラリを利用します。共有ライブラリの読み方は共有ライブラリ(キョウユウライブラリ)です。Linuxでは.soという拡張子の共有ライブラリをよく見かけます。
静的リンクされた実行ファイルは、必要なコードを自分の中に持つため、特定の共有ライブラリが実行環境にないことで起動できなくなる問題を減らせる場合があります。その代わり、コードを取り込む分だけ実行ファイルのサイズが大きくなりやすくなります。
動的リンクでは、複数のプログラムが同じ共有ライブラリを利用できるため、同じコードを各実行ファイルへ入れずに済みます。また共有ライブラリを更新することで修正を反映できる場合があります。どちらかが常に優れているわけではなく、配布方法、容量、更新方法、実行環境などに合わせて選びます。
4. GCCで通常の動的リンクを確認する方法
まず、通常の方法で小さなC言語プログラムを作って動作を確認してみましょう。一般的なLinux環境では、特別な指定をしないでGCCから実行ファイルを作ると、標準ライブラリなどを動的に利用する形になることがあります。
printf '#include <stdio.h>\nint main(void){printf("Hello Linux\\n");return 0;}\n' > hello.c
gcc hello.c -o hello
./hello
Hello Linux
作成した実行ファイルがどの共有ライブラリを利用しているか調べるときは、lddコマンドが便利です。lddの読み方はldd(エルディーディー)です。実行ファイルが必要とする共有ライブラリの一覧を確認できます。
ldd ./hello
linux-vdso.so.1
libc.so.6 => /lib64/libc.so.6
/lib64/ld-linux-x86-64.so.2
この例にあるlibc.so.6のようなファイルが共有ライブラリです。実際の表示内容やパスは、Ubuntu、Debian、AlmaLinuxなどのLinuxディストリビューションやCPUの種類によって異なります。ディストリビューションの読み方はdistribution(ディストリビューション)です。
lddで複数の共有ライブラリが表示される実行ファイルは、それらを実行時に利用します。この状態と静的リンクされた実行ファイルを比較すると、両者の違いをつかみやすくなります。
5. gcc -staticでライブラリを静的にリンクする方法
GCCで利用可能なライブラリを静的にリンクした実行ファイルを作りたい場合は、-staticオプションを利用できます。staticの読み方はstatic(スタティック)です。この指定によって、リンカへ静的リンクを行うよう指示します。
gcc -static hello.c -o hello-static
./hello-static
Hello Linux
ただし、このコマンドはすべてのLinux環境で必ず成功するわけではありません。静的リンクを行うには、利用するライブラリの静的版がシステムへ用意されている必要があります。必要な開発用パッケージや静的ライブラリが入っていない場合は、リンク時にエラーになることがあります。
作成された実行ファイルの種類を確認したい場合は、fileコマンドを利用できます。fileの読み方はfile(ファイル)です。
file ./hello-static
./hello-static: ELF 64-bit LSB executable, x86-64, statically linked
表示例にあるstatically linkedは、静的リンクされた実行ファイルであることを示します。実際の表示はLinux環境やCPUによって異なります。また、静的リンクしたからといって、あらゆるLinux環境で必ず同じように動くとは限りません。CPUの種類やカーネルとの関係など、ほかの条件もあります。
6. 静的ライブラリを作ってリンクする基本の流れ
静的リンクでは、自分で作成した静的ライブラリを利用することもできます。静的ライブラリの読み方は静的ライブラリ(セイテキライブラリ)で、LinuxのC言語開発では.aという拡張子がよく使われます。
次の例では、足し算を行う関数をコンパイルしてオブジェクトファイルを作り、それをarコマンドで静的ライブラリへまとめます。arの読み方はar(アール)です。
printf 'int add(int a, int b){return a + b;}\n' > add.c
gcc -c add.c -o add.o
ar rcs libcalc.a add.o
ar t libcalc.a
add.o
gcc -cは、リンク処理までは行わず、オブジェクトファイルを作る指定です。続くar rcsでadd.oをlibcalc.aへまとめています。ar tを使うと、静的ライブラリに含まれているオブジェクトファイルを確認できます。
libcalc.aという名前では、先頭のlibがライブラリであることを表す慣習として使われています。末尾の.aは、静的ライブラリでよく使われる拡張子です。Linuxのライブラリファイルを調べるときにも、この名前の付け方を知っていると役立ちます。
7. 自作の静的ライブラリを実行ファイルへ結合する方法
作成したlibcalc.aは、別のプログラムをリンクするときに指定できます。次の例では、静的ライブラリに含まれているadd関数を使って計算結果を表示します。
printf '#include <stdio.h>\nint add(int, int);\nint main(void){printf("%d\\n", add(10, 20));return 0;}\n' > main.c
gcc main.c ./libcalc.a -o calc-app
./calc-app
30
この例ではlibcalc.aを直接指定しているため、自作した静的ライブラリの必要なコードがリンク時に実行ファイルへ取り込まれます。完成したcalc-appを実行するときに、元のlibcalc.aを毎回読み込むわけではありません。
ここで注意したいのは、この例では自作したlibcalc.aを静的に結合していますが、C言語の標準ライブラリなどまで必ずすべて静的リンクされるとは限らない点です。実行ファイル全体を可能な範囲で静的リンクしたい場合は、前に説明した-staticなどの指定を使います。
この違いを理解すると、「一部のライブラリだけを静的に結合する場合」と「実行ファイル全体を静的リンクする場合」を区別できるようになります。
8. 静的リンクのメリットとデメリット
静的リンクの代表的なメリットは、実行時の共有ライブラリへの依存を減らしやすいことです。必要なコードが実行ファイルへ組み込まれるため、配布先に同じ共有ライブラリが存在しなくても動作させやすい場合があります。小さなコマンドラインツールや、外部ライブラリへの依存を減らしたいプログラムで役立つことがあります。
一方、静的リンクではライブラリのコードが実行ファイルへ取り込まれるため、ファイルサイズが大きくなりやすいという特徴があります。複数のプログラムが同じ静的ライブラリを利用すると、それぞれの実行ファイルに同じようなコードが含まれることもあります。
また、静的に組み込んだライブラリに不具合やセキュリティ上の問題が見つかった場合、共有ライブラリだけを更新しても、すでに作成済みの静的リンクされた実行ファイルへ修正が自動的に反映されるわけではありません。新しいライブラリを使って再びビルドし直す必要があります。
そのため、静的リンクは単純に「動的リンクより安全」「必ず高速」と考えるのではなく、配布しやすさ、ファイル容量、更新方法、セキュリティ対応、実行環境を考えて使い分けることが大切です。
9. Linux初心者が静的リンクで覚えておきたいポイント
Linuxの静的リンクを学ぶときは、ソースコード、コンパイル、オブジェクトファイル、静的ライブラリ、リンク、実行ファイルという流れをつなげて理解するとわかりやすくなります。ソースコードをコンパイルするとオブジェクトファイルが作られ、リンカが必要なライブラリのコードと結び付けて実行ファイルを作ります。そのリンク処理で必要なコードを実行ファイル側へ取り込むのが静的リンクです。
静的ライブラリと静的リンクは名前が似ていますが、同じ意味ではありません。静的ライブラリは再利用するコードをまとめた.a形式などのファイルで、静的リンクはそのライブラリに含まれるコードを実行ファイルへ結び付ける処理です。この二つを区別できると、Linuxのプログラム開発やライブラリ管理について理解しやすくなります。
また、静的リンクとシンボリックリンクも別の概念です。シンボリックリンクはファイルやディレクトリの参照先を示す仕組みですが、静的リンクはプログラムを作る工程でコードを結合する仕組みです。Linuxでは同じリンクという言葉が異なる意味で使われるため、何を結び付けているのかを見ることが重要です。
初心者のうちは、まずgccで通常の実行ファイルを作り、lddで共有ライブラリを確認し、次にgcc -staticや自作の.aファイルを使ったリンクを試すと違いを体験できます。実際にコマンドを実行してファイルサイズやfileの表示も比較すると、静的リンクの特徴がさらに理解しやすくなります。
Linuxの静的リンクは、ライブラリの必要なコードをリンク時に実行ファイルへ結合する仕組みです。静的ライブラリ、動的リンク、共有ライブラリ、コンパイル、リンカの関係を一緒に学ぶと、Linuxでプログラムが実行ファイルになるまでの流れを理解しやすくなります。