C++入門/Link

柴田祐樹,東京都立大学,情報科学科

ここではLink(リンク)について説明する.ここで言うリンクとは,複数のプログラムを束ねて一つのプログラムとする処理のことである.想像しやすい例として,プログラムを複数のファイルに分けて書くことが挙げられる.まずはこの複数ファイルの例を見ていこう.以下のファイルを取得して,同じ階層に配置する.

このファイルをそれぞれコンパイルしてリンクするまでのコマンドは次のとおりである.

コンパイルとリンクを実行した例 hiroki@hiroki-home:~/git/cpp$ g++ -c link1.cpp -o link1.o hiroki@hiroki-home:~/git/cpp$ g++ -I./ -c link-main.cpp -o link-main.o hiroki@hiroki-home:~/git/cpp$ g++ link-main.o link1.o -o link hiroki@hiroki-home:~/git/cpp$ ./link this is linkTest

以下にそれぞれのファイルを示す.

link1.hpp #pragma once void linkTest();
link1.cpp #include <iostream> void linkTest(){ std::cout << "this is linkTest\n"; }
link-main.cpp #include <iostream> #include <link1.hpp> int main(){ linkTest(); return 0; }

C++において,機械語はすべて.cppの拡張子を持ったファイルから生成されることとなっている.さらに,A.cppがあるとき,別のファイルB.cppからA.cpp中の要素を使うためには,関数の宣言が記載されたファイルをA.hppとして用意し,そちらを参照することとなっている.A.cppの中の要素を使うのにA.cppではなく,A.hppを使うというのが少し変わっている点であろう.

hppの方には普通関数や変数の名前しか記載しない.その中身,例えば関数の処理内容などは記載しない.具体的に,を見ればこれがわかる.このファイルにはvoid linkTest()と言う関数が宣言されているが,その定義内容はlink1.cppへ記載されている.このようにして,コンパイル時にはどの関数や変数を使うかだけ把握しておき,実際の知り内容はリンクを行うときに各必要な場所へ埋め込まれることとなっている.g++ では -c を指定することで,コンパイルのみを行い,リンクは行わない動作とすることができる.本節以前で -c をしていなかったのは,コンパイルとリンクを一度に行うことを指定していたことになる.-c を指定して生成したファイルは基本的に機械語からなるが,リンクのための情報もいくらか含んでいるため,完全な機械ごとは異なる.これをオブジェクトファイルと呼ぶ.

次にの実行例を用いながら具体的に説明する.この例では,はじめにlink1.cppとlink-main.cppをコンパイルしてオブジェクトファイルを生成している.ただし,link-main.cppからはlink1.cppの内容を使うため,のlink-main.cpp中2行目でincludeによりlink1.hppを使うことを指定している.加えて,このコードをコンパイルするとき,link1.hppの存在する階層を指定しなければならない.これを行うのが,オプション-Iである.オプション-Iは,直後に(空白を入れずに)記載された階層にincludeに指定されたファイルが存在することをコンパイラに伝えるためのものであり,これを指定しない場合でincludeでhppファイルを指定した場合はコンパイルに失敗する.

必要なコードが記載されたcppのオブジェクトファイルをすべて生成した後,最後に,それらをすべてg++に指定しているのが3行目のコマンドである.指定する順序は結果に影響を与えない.コンパイラはこれらオブジェクトファイルの中から関数mainを探し出し,そこから実行するように調整を行う.その結果出力されるのが機械語となる.出力ファイル名はオプション-oにより指定可能で,ここでは,linkとしている.4行目で実行した後,意図した結果を得られていることを確認できる.この出力を行うコードは,link-main.cppには存在せず,link-main.cppから呼び出された関数linkTestがたしかにlink1.cppのものであることを確認できる.ちなみに,関数mainが複数のファイルに定義されている,あるいは一つも定義されていない場合,コンパイルに失敗する.これはプログラムを開始するべき場所をコンパイラが判断できないためである.

iostream などC++の標準の関数は,-Iでhppファイルの場所を指定せずとも,g++にはじめから場所が登録されているため問題はない.いつもiostreamを使っているなら,これを毎回コンパイルせずとも画面出力が行えることから,このリンクの仕組みの利便性がわかるだろう.もしリンクの仕組みがなければ,iostreamをコンパイルするために毎回別の手続きとコンパイルの時間が余計に必要となる.例えば,それは普通少なくとも数分かかるものとなり,繰り返し行う速やかな検証の妨げになることであろう.