はじめに
この記事は長野高専 Advent Calendar 2021の25日目の記事です。
改めてこんにちは、しゅんです。3日目ぶりの投稿です。当初は書く予定がありませんでしたが、アドベントカレンダーなのに25日に記事がないのもさみしいので投稿します。
さて皆さんはC言語でプログラミングをするとき、どのようにソースコードのビルドを行っていますか?C言語を学校で習った方はgcc
コマンドでビルドを行っているかもしれません。しかしgcc
コマンドのみを使用した場合、ソースコードが複数あった場合や多数のコンパイラオプションを使用しているときに非常にコマンドが長くなったり複数のコマンドを実行する必要があったりします。
今回はこれらの煩雑な作業を軽減することができるCMakeを紹介します。CMakeを用いてビルドの効率を上げ、開発速度を上げていきましょう!
CMakeとは
Wikipediaにはこのように書いてあります。
CMakeは、コンパイラに依存しないビルド自動化のためのフリーソフトウェアであり、様々なオペレーティングシステムで動作させることができる。CMakeは階層化ディレクトリや複数のライブラリを利用するアプリケーションをサポートするよう設計されている。実際のビルドにおいては、make、Xcode、Visual Studioのようなネイティブのビルド環境が利用される。CMake自身は最小限の依存関係を持つよう設計されており、ビルドするにはC++コンパイラのみを必要とする。
ここに書いてあるようにCMakeはビルド自動化のためのソフトウェアです。実はCMake自体はビルドを行いません。実際にビルドする場合はCMakeによって作られたビルド環境を使用してビルドを行います。make
コマンドやVisual Studio
は聞いたことがある人も多いと思います。しかしこれらのビルド環境は特定のプラットフォームのみのサポートのことが多く、多数のOSに対応させることは難しいです。そこでCMakeというマルチプラットフォームなソフトウェアを使用することによってそれぞれのビルド環境の差異を吸収し、簡単にビルド環境のマルチプラットフォーム化ができます。
CMakeによるビルドの流れ
まずCMakeにはCMakeLists.txt
というファイルが必要です。このファイルにはどのようなファイルをコンパイルするかやライブラリ、オプションなどの各種設定を記述します。
CMakeLists.txt
を書いたらcmake
コマンドを使用してビルド環境を構築します。このときどのようなビルド環境を使用するかを設定することができ、make
やNinja
、Visual Studio
など様々なビルド環境を選択することができます。私の手元のmacOS環境では以下のビルド環境が使用できるようです。
$ cmake -G
CMake Error: No generator specified for -G
Generators
* Unix Makefiles = Generates standard UNIX makefiles.
Ninja = Generates build.ninja files.
Ninja Multi-Config = Generates build-<Config>.ninja files.
Watcom WMake = Generates Watcom WMake makefiles.
Xcode = Generate Xcode project files.
CodeBlocks - Ninja = Generates CodeBlocks project files.
CodeBlocks - Unix Makefiles = Generates CodeBlocks project files.
CodeLite - Ninja = Generates CodeLite project files.
CodeLite - Unix Makefiles = Generates CodeLite project files.
Eclipse CDT4 - Ninja = Generates Eclipse CDT 4.0 project files.
Eclipse CDT4 - Unix Makefiles= Generates Eclipse CDT 4.0 project files.
Kate - Ninja = Generates Kate project files.
Kate - Unix Makefiles = Generates Kate project files.
Sublime Text 2 - Ninja = Generates Sublime Text 2 project files.
Sublime Text 2 - Unix Makefiles
= Generates Sublime Text 2 project files.
ビルド環境ができれば後は好みのビルド環境のコマンドを使用してビルドを行えます。また、cmake
コマンド自体にもビルドのコマンドがあり、それぞれのビルド環境専用のコマンドを実行しなくともビルドすることができます。
CMakeのインストール
CMakeは各OSのパッケージマネージャにてインストールすることができます。Windowsの場合はscoopを使用してインストールすることもできますし、公式サイトからダウンロードすることも可能です。
CMakeを使ってみる
それではCMakeを使ってみましょう。今回は単純な3ファイル構成のプロジェクトを使用して解説します。先にソースコード全文を掲載します。
#pragma once
int add(int, int);
#include "add.h"
int add(int x, int y) { return x + y; }
#include <stdio.h>
#include "add.h"
int main(void) {
int x = 3;
int y = 5;
printf("%d + %d = %d\n", x, y, add(x, y));
return 0;
}
それではCMakeLists.txt
を作りましょう。
cmake_minimum_required(VERSION 3.1)
project(hello-cmake LANGUAGES C)
add_executable(main main.c add.c)
cmake_minimum_required
はこのCMakeLists.txt
が必要としているCMakeのバージョンを指定します。あまり新しい文法を使わないのであれば3.1
あたりを指定しておけば問題ありません。
project
はプロジェクト名や使用する言語、バージョンなどのプロジェクト全体の設定を行います。
hello-cmake
がプロジェクト名、LANGUAGES C
が言語の指定です。詳細なオプションに関しては公式リファレンスを参照してください。
add_executable
で実行形式ファイルのビルドを設定します。はじめの名前が出力ファイル名、後がソースコードのパス名です。add_executable
や後に紹介するadd_library
などで設定するビルド対象のことをCMakeではターゲットと言います。複数のターゲットがある場合、CMakeでビルドするときにターゲットを絞ってビルドすることが可能になります。
CMakeLists.txt
ができたら後はビルドするだけです。先程も言いましたが、CMake自体はビルドを行わないため、まずビルドツリーを構築する必要があります。
cmake <CMakeLists.txtが存在するディレクトリパス>
でビルドツリーを構築できます。デフォルトではワーキングディレクトリ上にビルドツリーを構築するのでcmake .
みたいにするとソースコードがある場所にビルドツリーができてしまいやり直したいときなどに非常に面倒です。そこでbuild/
のようなディレクトリを追加で作り、そこにビルドツリーを構築しましょう。CMakeの-B
オプションを使用することでビルドツリーの構築先を指定できるため、cmake . -B build
というように実行するのがおすすめです。
$ cmake . -B build
-- The C compiler identification is AppleClang 13.0.0.13000029
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /Library/Developer/CommandLineTools/usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /Users/shun_shobon/tmp/hello-cmake/build
このとき-G
オプションでビルド環境の指定をできます。macOSやLinuxではデフォルトでUnix Makefiles
が使用されますが、Ninjaなどが使用したい場合はお好みで設定してください。
ビルドツリーが構築できたらあとはビルドするだけです。ビルドはビルドツリー上でビルド環境独自のコマンドを入力してもビルドできますし、CMake上からもビルドできます。CMake上でビルドする場合はcmake --build <ビルドツリーへのパス>
でビルドできます。
$ cmake --build build
[ 33%] Building C object CMakeFiles/main.dir/main.c.o
[ 66%] Building C object CMakeFiles/main.dir/add.c.o
[100%] Linking C executable main
[100%] Built target main
なお、デフォルトではターゲット全てがビルドされますが、特定のターゲットのみにしたい場合は-t <ターゲット名>
で行えます。
ビルド成果物はビルドツリー下に生成されるのでお好みで実行してください。
$ ./build/main
3 + 5 = 8
コンパイルオプションを設定する
コンパイルオプションを設定したい場合はadd_compile_options
を使用します。
cmake_minimum_required(VERSION 3.1)
project(hello-cmake LANGUAGES C)
add_compile_options(-Wall -O3)
add_executable(main main.c add.c)
ライブラリを作る
複数の実行ファイルがある場合、いちいちadd_executable
の後にソースコードを並べるのは効率が悪いです。add_library
を使えばライブラリを作成することができ、target_link_libraries
で各種ターゲットにライブラリをリンクできます。
cmake_minimum_required(VERSION 3.1)
project(hello-cmake LANGUAGES C)
add_compile_options(-Wall -O3)
add_library(add add.c)
add_executable(main main.c)
target_link_libraries(main add)
終わりに
CMakeを使えばプラットフォームに依存しないビルド環境を作ることができ、保守性も高まります。CMakeLists.txt
のコマンドは非常に多く、今回はその一部を紹介しましたが、公式リファレンスに詳細が載っているため詳しく見たい方はそちらを参照してください。公式チュートリアルには多数のユースケースに向けたチュートリアルがあるためこちらを見ることもおすすめします。