複数のオブジェクトファイルやライブラリを結合して1つの実行ファイルを生成するプログラム。
リンカ(連携編集プログラム)とは、コンパイルで生成された複数のオブジェクトファイルやライブラリを結合し、1つの実行ファイルを作るプログラムです。コンパイル(=ソースコードを機械語に翻訳すること)は、ファイルごとにバラバラの機械語の断片(オブジェクトファイル)を作るだけなので、それらをつなぐリンカが必要になります。
身近な例で考えると、プラモデルの組み立てに似ています。胴体・腕・脚といった部品(オブジェクトファイル)を別々に作っただけでは動くロボットになりません。すべてを正しく組み付けて1体にする工程が、リンカの仕事にあたります。
上のツールで▶ボタンを押すと、バラバラのオブジェクトファイルとライブラリが集められ、参照がつながり、最後に1つの実行ファイルが完成するまでの流れを確認できます。
結合の中心となる作業が外部参照の解決です。外部参照とは、別ファイルにある関数や変数を呼び出している箇所のことです。
たとえば main.o の中に「calc という関数を呼ぶ」と書いてあっても、その calc 本体は別の calc.o の中にあります。リンカはこの呼び出しを成立させるために次のことを行います。
・関数の所在を探す:呼びたい関数がどのファイルのどこにあるかを特定する
・アドレスを書き込む:呼び出し先のアドレス(=メモリ上の番地)を呼び出し箇所に埋め込む
・1つにまとめる:各ファイルの機械語を並べ直し、ずれた位置に合わせてアドレスを調整する
これは電話帳で相手の番号を調べてつなぐ作業に似ています。「田中さんに電話したい」と思っても番号を知らなければかけられません。リンカが全員の番号を調べ終えることで、はじめてプログラム全体が正しく連携できるようになります。
ライブラリの結びつけ方には、静的リンクと動的リンクの2種類があります。タイミングと組み込み方が違います。
・静的リンク:ビルド時にライブラリを実行ファイルへ組み込む
・動的リンク:実行時にライブラリを読み込む
| 項目 | 静的リンク | 動的リンク |
|---|---|---|
| 組み込む時点 | ビルド時 | 実行時 |
| 実行ファイルの大きさ | 大きい(中に含む) | 小さい(外部にある) |
| ライブラリ更新 | 作り直しが必要 | 差し替えだけで反映 |
静的リンクはお弁当を全部詰めて持ち歩くイメージです。1つで完結して動きますが、荷物(実行ファイル)は重くなります。動的リンクは現地の食堂を使うイメージです。荷物は軽い反面、その食堂(共有ライブラリ)が現地になければ動きません。多くのOSでは、よく使うライブラリを動的リンクで共有して、メモリやディスクを節約しています。
プログラムが動くまでには、「コンパイラ → リンカ → ローダ」という3段階があります。リンカは、その中の2段階目で活躍します。
なぜリンカが必要なのか、を順を追って理解しましょう。
・コンパイラ(=ソースコードを機械語に翻訳するプログラム)は、ファイル1つずつをバラバラに翻訳します。たとえば main.c だけを翻訳して main.o(=オブジェクトファイル)を作ります。
・でも main.o の中に「別ファイルにある関数を呼ぶ」と書いてあっても、コンパイル時点ではその関数の場所が分かりません。
・そこでリンカが登場します。すべての .o ファイルとライブラリを集め、呼び出し先を特定してひとつにつなぎ、動かせる実行ファイルを完成させます。
上の図のように、リンカはプログラム製造の「組み立て工程」にあたります。部品(オブジェクトファイル)が完成していても組み立てなければ動かない──リンカはその「組み立て役」です。
ライブラリとは、よく使う関数や処理をまとめておいた「部品集」です。たとえば「平方根を計算したい」とき、その計算式を自分で書く必要はなく、数学ライブラリの sqrt() という関数を呼び出せば済みます。
なぜライブラリとリンカがセットで語られるのか。ライブラリは別ファイルとして存在するため、コンパイルの段階では「どこにあるか」が分かりません。リンカが実行ファイルを作るときに、必要なライブラリを探し出し、自分のプログラムに組み込む(リンク)というのがリンカの重要な仕事の一つです。
・静的ライブラリ(=あらかじめ作られた部品集ファイル):ビルド時にリンカが実行ファイルへ組み込む
・共有ライブラリ(動的ライブラリ):実行ファイルには含めず、実行時に読み込む
身近な例では、料理レシピ集(ライブラリ)に似ています。オムライスを作るとき「卵の溶き方」を毎回考えずにレシピ集から参照します。リンカは「どのレシピを使うか」を確認し、必要なページだけ料理の手順書(実行ファイル)に貼り付ける係です。