C++ と CMake 入門 その1

注意

  • メモ感覚の記述(言い切り、タメ口)
  • 雑な解釈(本人も完全に理解していない素人)

C++、CMake 入門

 C++ と CMake について勉強しようと思ったので、ここに記録を書く。C++ とは、C言語オブジェクト指向を足したプログラミング言語である。 早速書いてみようと思う。作業環境は以下の通り。

 OS が2つもある理由はお互い併用しているからである。また仕様が大体同じというのもある。
 まずは作業スペースを作ろう。名前はなんでもいいが、わかりやすくしたいので作業スペース(ディレクトリ名)を cpp_ws とする

mkdir ~/cpp_ws
cd ~/cpp_ws

 これで作業スペースの作成は完了である。

hello.cpp を作ろう

nano の使い方

 VimVScode、gedit など、テキストエディタの種類はたくさんあるが、今回は厳選して nano を使おうと思う。 単純に僕が nano が好きだからである。これをみてあなたも nano 信者になってくれると嬉しい。
 さて、本題に入る前に nano の使用方法について説明するわけだが、デフォルトの nano を使うのは正直いけすかない。 というのも、デフォルトの nano は絶望的に使い勝手が悪い。しかし、nano は自分自身で自由にカスタマイズができる。 カスタマイズの仕方は至って簡単である。以下の手順に沿って作業を進めてもらいたい。

1. nanorc をホームディレクトリに作成する

 nanorc とは nano の設定を行うコンフィグファイル の一種である。nanorc は nano の コンフィグディレクト にすでに用意されているが、 ホームディレクトリに自作の nanorc を追加で作成することで、自作 nanorc に記述した設定も反映させることができる。自作 nanorc の作成は以下の通りに行う。
 touch コマンドで先にファイルを作成してもいいのだが、紹介が面倒なので nano コマンドで直接 nanorc を生成することにする。 nanorc ファイルは 必ず隠しファイルとして設定しなければならない 。そうじゃないと反映されない。

nano ~/.nanorc

 すると、下のような nano エディタがターミナル内に表示される。

 これが何も設定されていない素の nano である。

2. nanorc に設定を記述する

 ここに以下のテキストをコピペして貼り付けよう。

# 行番号を表示するように設定
set linenumbers
# タブ(インデントサイズ)を半角 4 マス分に設定
set tabsize 4
# インデントが全てスペースとして認識するよう設定
set tabstospaces
# インデントの状態を自動で補助してくれるように設定
set auttoindent
# nanon エディタ終了時に自動でファイルを保存してくれるように設定
set tempfile
# マウスカーソルでの操作を有効にする
set mouse
# スクロールをスムーズにするように設定
set smooth
# nano に用意されているシンタックスハイライトを全て反映させる(Ubuntu の方はこれをかく。macOS の方は書かないで。)
include "/usr/share/nano/*"
# nano に用意されているシンタックスハイライトを全て反映させる(macOS の方はこれをかく。Ubuntu の方は書かないで)
include "/usr/local/opt/nano/share/nano/*"

 これを nanorc にコピペしたら、Control + X を押したのちに、Yキー を押す。すると元のターミナルに戻る。

3. 確認

 試しにもう一度以下のコマンドを実行して、nanorc を nano でみてみよう

nano ~/.nanorc

 すると、設定を記述した内容の通り、行番号が設定され、マウスで任意の行をクリックすると、 カーソルが指定の場所に移動してくれるようになっているのがわかるだろう。このように、nano は他の CUI エディタと比べて直感的に操作できるのがいい。 画像は少し内容が異なるが、これは自分が他にもいろいろカスタマイズしているからである。

本題に戻る

 本題に戻っで、hello.cpp を作ってみよう。cpp_ws に移動して、hello.cpp を作成しよう。

cd ~/cpp_ws
nano hello.cpp

 hello.cpp では、文字列を標準出力するプログラムを記述する。記述量はそこまで多くはない。早速完成形を見せると、こんな感じである。

//hello.cpp
#include <iostream>
using namespace std;

int main()
{
    cout << "hello" << endl;
}

 一つ一つ説明しよう。

//hello.cpp

 これは コメント文 である。ただ「このプログラムは hello.cpp だよ」とコメントを打っているだけなのでプログラムには一切関係ない。 C++ でコメントを記述するときは、必ず // が必要である。

#include <iostream>

 python をやっている人からすると、これこそコメント文に見えるかもしれないが、これは 標準出力するのに必要なブツを持ってこい という命令文(コード)である。クセで # をつけ忘れないようにしよう。

using namespace std;

 これは std を省略するぞ。というコードである。今は意味を知らなくていい。以下の

#include <iostream>
using namespace std;

 は今後ほぼ毎回入力する羽目になるので、とりあえず C++ ではこの2行は冒頭必ず書く と覚えてほしい。

int main()

 これは メイン関数 を定義するぞ。というコードである。C++ はこのメイン関数内に記述されたコードをはじめに読み取る。 そのためこれも必ず書かなければならない。ちなみに下の行にある

{
    処理部分
}

 もメイン関数の一部である。要は括弧内にプログラムを書くよってことである。改行している理由は見やすくするため。これから長いコードを書く際に 便利である。

    cout << "hello" << endl;

 次はメイン関数内に記述されたこの処理について解説する。cout とは、画面のことである。"Hello" は文字列である。endl は改行を意味する。 つまり、このコードを意味は、

    画面に "Hello" という文字列を、改行して出力しろ

という意味となる。末尾の ; は必ずかこう。これは C 言語の類の共通ルールらしい。よく書き忘れるので注意しよう。
 以上の説明をもとに、この hello.cpp のワークフローを説明すると以下のようになる。

// hello.cpp
標準出力に関する情報を持ってくる
stdライブラリをデフォルトで使用するよ

メイン関数を定義する () 
{
    画面に "Hello" を改行して出力する
}

 描き終わったら Control + X で保存 & nano を終了しよう。

コンパイルする

 プログラミング言語というのは様々な種類があり、 機械が認識する言語(マシン語)を人間でも理解できるように記述できる言語 である。そんな数多くある言語のうちが、今回みている C++ である。さて、パソコンはこの C++ のファイルを直接みても理解することはできない。 マシン語というのは 0 と 1 しか表現するものがないのだ。
 コンパイルとは 人間が理解できるプログラミング言語マシン語に翻訳する作業 である。C++ ファイルをコンパイルする方法はいろいろあるが、 あえて CMake を使ったコンパイル方法を説明する。

CMakeLists.txt を作る

 CMake とは、C++ などのプログラミング言語コンパイルする コンパイラ の一種である。ROS などでよく活用されている。CMake を使ってコンパイルするには、 どんなファイルをどのような方法でコンパイルするか というメニュー表を作ってあげなければならない。そんなメニュー表が CMakeLists.txt である。txt ファイルだが専用の特殊ファイルとして認識される。 nano で CMakeLists.txt を作成しよう。気をつけてほしいのが、C, M, L は大文字なので、ファイル名を間違えないようにしよう。

nano CMakeLists.txt

 nano を開いておいてなんだが、もう一つターミナつを開いて、以下のコマンドを実行して cmake のバージョンを確認しよう。

cmake --version

 すると、こんな感じにバージョンが返される。

cmake version 3.24.2

CMake suite maintained and supported by Kitware (kitware.com/cmake).

 バージョンは使用しているパソコンによって異なるので、このバージョン番号を覚えてほしい。
 CMakeList の nano 編集画面に戻って、以下のコードを最初にコピペしよう。

cmake_minimum_required(VERSION )

 この VERSION の横に先ほど確認した cmake のバージョンを記述してほしい。もし cmake のバージョンが 3.24.2 だったら、このように記述する

cmake_minimum_required(VERSION 3.24.2)

 そしたら、project と使用言語を指定する。project とは、ようはこの作業ディレクトリ、cpp_ws のことを言う。そして使用言語は、今回使用している C++ である。 しかし、CMakeList では C++ のことを CXX と表すので、以下のコードを続けて書こう

project(cpp_ws CXX)

 次に、実行ファイルとコンパイルするファイルを設定する。コンパイルされたプログラムは CPU によって処理される前に一旦データとして命令データが保存される。 この保存データを実行ファイルとして保存するのだ。実行ファイルは好きな名前でいい。今回は例として run_hello とする。
 あ、そうそうその実行ファイルとコンパイルするファイルを指定するコードの書き方は以下の通りである。

add_executable(実行ファイル コンパイルするプログラムの名前)

 今回は hello.cpp と言うプログラムファイルを run_hello としてコンパイルしたいので、以下のように書く。 カンマ( , )で区切るとエラーになるので気をつけよう

add_executable(run_hello hello.cpp)

 これで CMakeList の記述は完了である。全体を見るとこのようになる。

cmake_minimum_required(VERSION <cmake のバージョン>)
project(cpp_ws CXX)
add_executable(run_hello hello.cpp)

 これらの意味をまとめると、

cmake(コンパイルするときに使うツールの)バージョンは <cmake --version で確認したバージョン>を指定するよ
コンパイル対象のディレクトリは cppp_ws で C++ のプログラムファイルをコンパイルするよ
そのコンパイルするファイルは hello.cpp で、run_hello と言う名前の実行ファイルを生成するよ。

 となる。かけたら Control + X で保存 & nano を終了しよう。

build ディレクトリを作る

 CMakeList を作成したら、build ディレクトリを作ろう。これは普通に以下のコマンドで build ディレクトリを作るだけ。

mkdir build

 作ったら build ディレクトリに移動しよう。

cd build

コンパイル作業の開始

 build ディレクトリに移動したら、以下のコマンドを実行して、cmake を行う。

cmake ..

 これは 今いるディレクトリより前の階層のディレクトリを cmake する と言う意味である。cmake は CMakeLists.txt を認識すると、その中に書かれている 注文に沿ったコンパイル作業を行う。
 cmake を実行したと言うことは、料理で言うところの注文(CMakeLists.txt)に沿って料理をした(コンパイルした)だけであり、注文したお客さん(あなた) に料理(実行ファイル)がまだ来ていない。と言うわけで、make コマンドを使って料理を持ってこさせよう。この実行ファイルを呼び出すことを ビルド と言う。
 ビルドをする際は、build ディレクトリで以下のコマンドを実行する

make

 すると以下のように実行ファイルが CMakeList.txt を参考に組み立てられる。

[ 50%] Building CXX object CMakeFiles/run_hello.dir/hello_world.cpp.o
[100%] Linking CXX executable run_hello
[100%] Built target run_hello

 終わるとコンパイルとビルドは成功である。

実行

 build ディレクトリを ls コマンドで見てみよう。するとこんなファイルとディレクトリがあるのがわかる。

$ ls
CMakeCache.txt       CMakeFiles/          Makefile             cmake_install.cmake  run_hello*

 この中に、先ほど実行ファイル名として指定した run_hello がある。これをターミナルで指定して実行すると、C++ で記述した hello.cpp が実行される。

./run_hello

 上記のようにカレントディレクトリを指定しないと、認識されないので気をつけよう。
 実行すると、以下のように hello が出力される

$ ./run_hello
hello

 これであなたは C++ で文字列を標準出力する方法と cmake を使ってプログラムをコンパイル、ビルドする方法を学んだ。