Welcome to Mashykom WebSite



C/C++言語 :MakefileおよびCMakeによるビルド


 コンピュータが実行できる言語はマシン(機械)語と呼ばれるプログラミング言語で書かれたプログラムだけです。それ以外の言語で書かれたプログラムはすべてマシン語に翻訳する必要があります。この翻訳をする方法にコンパイラを使う方法と、インタープリタを使用する方法があります。C/C++で書かれたプログラムはコンパイラを用いてマシン語に翻訳して、コンピュータに実行されます。後者のインタープリタを用いて翻訳をするプログラミング言語として、PythonやJavaScriptなどがあります。

 C++のプログラムを作成するためには、プログラムをコンパイルするコンパイラと、プログラムを書くエディターが必要です。よく知られているコンパイラは以下の通りです。

 独自のエディターを使用することもできますが、統合型開発環境(IDE)を利用することは最も便利は方法です。主要なIDEを以下に挙げます。

 NetBeans IDE は無償のオープンソースソフトウェアで全世界のコミュニティーユーザーと開発者に支援されています。 ユーザーインタフェースは日本語に翻訳されているのでどなたでも簡単に使えます。ダウンロードサイトは こちらです。

 日本語 Eclipse の ディストリビューションサイト、つまり、 Pleiades – Eclipse 日本語化プラグインのサイトは こちらです。 OSDN(オーエスディーエヌ)は、日本の OSS(オープンソースソフトウェア)プロジェクト向けのホスティングサイトです。

 C/C++を書いた時に複数ファイルから実行ファイルを生成するときやライブラリをIncludeする場合、コンパイルのオプションが複雑になります。複雑なオプションを毎回コマンドラインで入力するのではなく、Makefileというコンパイルのオプションルールを記載してmakeコマンドにて実行ファイルを生成すると便利です。まず始めに、Makefileの簡単なルールについて紹介します。次に、クロスプラットフォームで活用されているビルドの方法、CMakeとCMakeList.txtを用いてコンパイルする方法を説明します。

Last updated: 2021.1.10



Makefileを用いたビルドの方法



 ターミナルのシェルプロンプトを用いて、ソースプログラムをコンパイルする方法を説明します。以下のC++プログラムをテキストエディターで作成して、hello.cppとして保存して下さい。


#include <iostream>

int main() {
  std::cout << "Hello, World!\n";
}

ターミナルを開いて、hello.cppファイルと同じディレクトリに移動して、

$g++ -o hello.o hello.cpp

とすると、実行ファイルがhello.oとして生成される。コンパイル後の実行は以下のコマンドを入力します。


$./hello.o

結果は

Hello, World!

と表示されます。

 GNU makeコマンドを使えば、Makefileにあらかじめ記述しておいた手順にしたがって、C/C++などのソースファイルから実行ファイルを自動で生成できます。例えば、単一のC++ソースのhello.cppというファイルをコンパイルする場合は


$ g++ hello.cpp -o hello

と実行するとhelloという実行ファイルが生成されます。これを最も単純なMakefileを使って書くと次のようになります。


hello: hello.cpp  
	g++ -Wall hello.cpp -o hello  #実行コマンド
clean:
	rm -f *.o hello

 Makefileの書式を簡単に説明すると、Ruleとは、上記の hello: や clean: から始まる行からその下のインデントされた行までのブロックのことを指します。各Ruleは ターゲット (target) 、 必須項目 (prereq) 、 実行コマンド (commands) の3つの構成要素で成り立っています。


target: prereq1 prereq2
    commands

 1行目に生成したいターゲットファイル名(例えば、hello): 依存ファイル(hello.cpp)、2行目に生成するための実行コマンド(g++ -Wall hello.cpp -o hello)を記載します。実行コマンドの先頭にはTabを入力する必要があります。-Wallオプションは、全ての警告オプションを結合してくれるもので、一番厳密に文法をチェックします。

 ソースファイルと Makefileを同じディレクトリに配置します。プログラムを構築するには、ターミナルのディレクトリをMakefileと同じディレクトリに移動させて、コマンドプロンプトに次のように入力し make を実行します。


 $ make

 これにより make は Makefile を読み込み、次のように最初のターゲットを構築 します。


 $ make
  g++ -Wall hello.c -o hello

 helloという実行ファイルが生成されます。生成された実行ファイルを消去したい場合は「make clean」と実行すると、rm -f *.o helloのコマンドが実行されます。

 プログラム全体が、相互依存した複数のソースファイルから構成されているケースが一般的です。こうしたソースファイルを効率的にビルドする方法の一つがMakefileを活用することです。以下の例は、2つのソースプログラムからなるコードのコンパイルです。ソースはmain.cpp、および、function.cppから構成されているとします。mainの中で利用したい関数をfunction.cppのなかに記述しています。この時、Makefileは以下のようになります。


main: main.o function.o
	g++ -Wall -o main main.o function.o 
function.o: function.cpp
	g++ -Wall -c function.cpp 
main.o: main.cpp
	g++ -Wall -c main.cpp
clean:
	rm -f *.o main

 最初のルールのコマンド行に「 g++ -Wall main.cpp print.cpp -o hello」 と記述すると、コンパイルの実行が毎回両方のファイルに適用されてしまいます。片方のファイルだけを修正したい時もあります。この理由から、上記の例のように各生成ファイル毎に記述を分離するのが一般的です。

 シンボルを使ったMakefileの例を以下に示します。


CC = g++
CFLAGS = -g -Wall

ALL: main.o function.o
	$(CC) $(CFLAGS) -o main main.o function.o

main.o: main.cpp
	$(CC) $(CFLAGS) -o main.o -c main.cpp

function.o: function.cpp sub.h
	$(CC) $(CFLAGS) -o function.o -c function.cpp

 function.cppのなかでヘッダファイル sub.h を使用しています。オブジェクトファイル main.oとfunction.oを-cフラグで別々に生成してから、ALLの処理でリンクしています。make コマンドを実行すると


cpp $ make
g++ -g -Wall -o main.o -c main.cpp
g++ -g -Wall -o function.o -c function.cpp
g++ -g -Wall -o main main.o function.o

となります。mainという実行ファイルが作成されます。./main とコマンドを打つと実行ファイルが結果を表示します。

 Makefile の使用法についてよく知りたい人は、GNU make の公式マニュアルを参照ください。また、少し古いですが、 GNU make の参考書(Robert Mecklenburg 著、矢吹 道郎 監訳、菊池 彰 訳)の pdf が https://www.oreilly.co.jp/library/4873112699/からダウンロードできます。


CMakeを用いたビルドの方法



 C++のコンパイラはOSに依存して複数のコンパイラが存在しています。標準C++ライブラリだけを使ったソースコードであればどのコンパイラでもビルドすることができますが、コンパイラのオプションなどの仕様が異なります。CMakeではCMakeLists.txtという設定ファイルを作成しておけば、そこからCMakeがサポートする任意の実行ファイルを作成することができます。 つまりOSに依存せず、どの開発環境でもプロジェクトをビルドできるようになります。CMakeはクロスプラットフォームなC++プロジェクトを開発するために欠かせないツールとなっています。

CMakeは、公式サイトのダウンロードページからインストーラーをダウンロードできます。コマンドラインから、 cmake --version と入力すると、インストールされているバージョンがわかります。

CMakeを用いてコンパイルする時の設定ファイルが、CMakeLists.txtです。cmakeコマンドを実行すると、この設定ファイルに従って、各OSに対応したMakefileが生成される仕組みになっています。ビルドしたいソースコードのあるディレクトリに、CMakeLists.txtファイルを作成します。例えば、上記のhello.cppというソースファイルから、実行ファイルmainを生成するためのプロジェクトは、以下のように書きます。


cmake_minimum_required(VERSION 3.1)
project(hello_world CXX)
add_executable(main hello.cpp)

実は最後の行だけ書いておけば一応動くのですが、最低限やっておきたいという設定がこの3行です。1行目のcmake_minimum_required(VERSION 3.1)はCMakeのバージョンを指定するコマンドです。バージョンの確認に加えて暗黙的にcmake_policyコマンドを呼び出し、このCMakeLists.txtをCMake 3.1の仕様で解析するように設定が行われます。

2行目のproject(hello_world CXX)はプロジェクト名(hello_world)とプロジェクトで使用するプログラム言語(CXX)を指定しています。この言語の指定がなくても正常に作動します。ここで定義したプロジェクト名は、Xcodeのプロジェクトファイル名に使われます。

3行目のadd_executable(main hello.cpp)はビルドする実行ファイル名とそれを構成するソースファイルを指定しています。 「hello.cppを使ってmainという名前の実行ファイルを作成する」という設定になります。

 cmakeは、カレントディレクトリに生成物やキャッシュ等を色々と生成するため、ディレクトリを汚します。この理由から、「build」のようなディレクトリを作成し、そこへ移動してから、一つ上のディレクトリを渡してcmakeを実行します。


$ mkdir build 
$ cd build 
build $ cmake .. 

 ..の部分はCMakeLists.txtがあるディレクトリを指定しています。以下のようにコンソールに表示されて、Cmake が終わります。


-- The CXX compiler identification is AppleClang 11.0.0.11000033
-- Check for working CXX compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++
-- Check for working CXX compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /Users/koichi/cpp/cpp-cmake/build

buildディレクトリの中にMakefileなどのプロジェクトファイルとその他の必要なファイルが生成されているはずです。

 最後に、


(build)$ make .

とコマンドを打てば実行ファイル main.o が作成されます。.の部分はConfigureとGenerateを実行したフォルダつまりbuildフォルダを指定しています。このコマンドの入力後

Scanning dependencies of target main
[ 50%] Building CXX object CMakeFiles/main.dir/hello.cpp.o
[100%] Linking CXX executable main
[100%] Built target main

となって、ビルドが完成します。生成されたファイルを見てみると


build $ ls
CMakeCache.txt		Makefile		main
CMakeFiles		cmake_install.cmake

 となっています。実行ファイルのmain、CMakeFilesディレクトリ、および、Makefileファイルなどが作成されています。


build $ ./main


と入力すれば、mainファイルが実行できます。「Hello, World!」と表示されます。

 ソースファイルが複数になるケースでは、add_executableの記述内で、hello.cppの後にそのファイル名を追加することになります。例えば、main.cpp, func1.cpp, func2.cpp, sub.hという複数のソースプログラムの時、


cmake_minimum_required(VERSION 3.1)
project(Myproject CXX)
add_executable(Main main.cpp func1.cpp func2.cpp)

と記述します。ヘッダ sub.h の依存関係はcmakeが勝手に解決してくれます。

 cmakeは広範に普及しているツールですが、日本語マニュアルの情報は乏しいです。cmakeの英文マニュアルはcmake.orgのサイトから入手できます。

 CMakeにIDE(XcodeやVisual Studioなど)のプロジェクトファイルを生成させる方が便利なことが多いです。CMakeにはbuild system generatorを指定するオプション -G があります。Xcodeを活用するときは、以下のようにオプションを設定します。


$ mkdir build 
$ cd build 
build $ cmake .. -G Xcode 

 以下のような経緯をたどります。


-- The CXX compiler identification is AppleClang 11.0.0.11000033
-- Check for working CXX compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++
-- Check for working CXX compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /Users/koichi/cpp/cpp-xcode/cpp-cmake/build

build $ ls
CMakeCache.txt		CMakeScripts		hello_world.xcodeproj
CMakeFiles		cmake_install.cmake

 Xcodeのプロジェクトが作成されています。しかし、Xcode 12.1 以降では、この方法ではエラーが出ます。Xcode を起動して、プロジェクトを新規に作成する方がベターです。この方法を簡単に説明します。

 Xcode を起動し、「Create a new Xcode project」をクリックして開きます。「macOS」->「Command Line Tool」を選び、「next」に行きます。「product name」に適当なファイル名を書き込んで、「Language」で C++を選択します。新しい画面が登場して、エディターに、開始用のHello World コードが書かれています。この main.cpp コードの内容を消去して、自らのプログラムをコピペして、書き入れます。

 左上にある三角形の実行ボタンをクリックします。すると、成功すれば、「Build Succeeded」と出て、結果が表示されます。

 複数のソースコードがあるケースでは、[File] -> [Add Files to "..."] とクリックして、[options] で追加したいファイルを選択して、[add]をクリックします。



このページの先頭に戻る

C++ 言語入門のページに戻る

トップ・ページに行く