catalinaの備忘録

ソフトウェアやハードウェアの備忘録。後で逆引きできるように。

CMakeを使ってmakefileを作る

はじめに

C/C++でプログラミングをしているとmakefileが必要になってきます。

VisualStudioみたいなIDE環境なら自動生成に任せてしまうのですが、Linux環境だとそういうものを使うこと自体が面倒だったりします。

小さなツール群を組み合わせて使っていったほうが後々幸せになれるケースが多いと思ってます。

というわけで、今回はmakefileを自動生成するツールとしてCMakeを試してみます。

総括

とりあえずこういう書き方すればc++11でboostをリンクできますよ的なの。 記事の上のほうに書いておくと私が忘れてしまったときにコピペしやすいので。

cmake_minimum_required(VERSION 3.0)
project(rest_test1)
set(CMAKE_CXX_FLAGS "-std=c++11")
add_executable(rest_test t.cpp)
target_link_libraries(rest_test boost_system)

CMakeの前にautotoolsについて

CMakeの前にmakefileの自動生成について。

まずmkaefileを作るツールというのは昔から存在しています。

歴史的にみると、古くはautotools(ソースコードからパッケージインストールするときにautofonfとかconfigureとかやるアレです)とかがあって、プロジェクトによりますが現役でも充分使えるものです。

https://ja.wikipedia.org/wiki/Autotools

じゃあautotolsでいいのでは?って思いますが、これは入力がm4とシェルの合わせ技になっていて、「ラクしてmakefile書きたい」ってのを満たせません。

makefileをラクして書くとは?

まずmakefileについて。 makefileに書く内容はいろいろありますが、大まかに列挙すると以下のとおりです。

これをラクして書きたいのです。

今のmakefileが不便な理由は、私が$とか<とかの記号や暗黙のルールを覚えられないからです。

記号やルールの意味を調べてmakefileを綺麗に書こうとすると、それだけで時間とられまくるので悲しくなります。

できることなら上記のものを列挙するだけで済ませたいわけです。そしてcmakeならこの目的を達成できます。

CMakeの基本

とりあえずビルドするだけのものです。

cmake_minimum_required(VERSION 3.0)
project(test_project)
add_executable(executable_file test.cpp)

各パラメータの意味は

  • cmake3.0以降
  • test_projectというプロジェクト名
  • executable_fileを生成するための依存関係としてtest.cppというファイルを追加

まずはmakeしてみる

適当にtest.cppを作って動かしてみます。makeするのが目的なので、mainさえあればいいです。

int main()
{
  return 0;
}

cmakeにmakefileを生成させます。centos7環境なのでver3のcmakeはcmake3コマンドになります。

$ cmake3 . 
-- Configuring done
-- Generating done
-- Build files have been written to: /test_project
$ ls Makefile
Makefile

Makefileができたのでmakeしてみます。

$ make
Scanning dependencies of target execfile
[ 50%] Building CXX object CMakeFiles/execfile.dir/t.cpp.o
[100%] Linking CXX executable execfile
[100%] Built target execfile
$ ls execfile -l
-rwxrwxr-x 1 user user  8504 <日付> execfile

実行ファイルができました。簡単ですね。便利ですね。

コンパイルオプションを指定したい

C++の新しい機能を使うにはコンパイルオプションを指定する必要があります。 というわけでオプションを指定します。 このやり方が正しいかどうかよくわかっていないので、もしコピペするときは自己責任でお願いします。

cmakeに次の行を追加します。位置はprojectの後くらいで。

set(CMAKE_CXX_FLAGS "-std=c++11")

これでC++11の記述ができるようになります。とりあえずラムダ、関数戻り値後置記法、auto型を使ってみます。

int main(){
    auto lambdatest = []() -> int {std::cout << "hello world" << std::endl; return 0;};
    return lambdatest();
}
$ cmake3 .
-- Configuring done
-- Generating done
-- Build files have been written to: /test_project
$ make
[ 50%] Linking CXX executable execfile
[100%] Built target execfile
$ ./execfile
hello world

いけました。

これでコンパイル時のオプション指定は何でもできそうです。

リンクオプションを指定したい

C++といえばboostですね。リンクしてみましょう。 ただしboost単体ではアプリっぽいことはできなくてつまらないので、MSのrestsdkをリンクしてみます。

boostは以下のサイトを参考にインストールしておきます。

https://boostjp.github.io/howtobuild.html

MSのrestsdkは次のサイトを参考にインストールしておきます。

https://github.com/Microsoft/cpprestsdk/wiki/How-to-build-for-Linux

現時点でのrestsdkはCMake3以上が必要でboostも必要になります。

手元の環境ではインストールが終わるとパスも通っていたので、ライブラリのファイル名を指定するだけでOKでした。

CMakeLists.txtに追記します。 また、以降は出力ファイル名はrest_testとなるよう変更しています。

restsdkと、その依存ライブラリをリンク指定します。

target_link_libraries(rest_test boost_system)
target_link_libraries(rest_test crypto)
target_link_libraries(rest_test ssl)
target_link_libraries(rest_test cpprest)

makeしてみます。

$ cmake3 .
-- Configuring done
-- Generating done
-- Build files have been written to: /test_project
$ make
[ 50%] Linking CXX executable execfile
[100%] Built target execfile

ライブラリが正しくリンクできているか見てみます。

$ ldd rest_test
        linux-vdso.so.1 =>  (0x00007ffe3fbdd000)
        libboost_system.so.1.55.0 => /usr/local/lib/libboost_system.so.1.55.0 (0x00007f9cffc02000)
        libcrypto.so.10 => /lib64/libcrypto.so.10 (0x00007f9cff773000)
        libssl.so.10 => /lib64/libssl.so.10 (0x00007f9cff501000)
        libcpprest.so.2.10 => /usr/local/lib/libcpprest.so.2.10 (0x00007f9cfe832000)
        libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007f9cfe529000)
        libm.so.6 => /lib64/libm.so.6 (0x00007f9cfe227000)
        libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f9cfe011000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f9cfdc4f000)
        librt.so.1 => /lib64/librt.so.1 (0x00007f9cfda47000)
        libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f9cfd82b000)
        libdl.so.2 => /lib64/libdl.so.2 (0x00007f9cfd626000)
        libz.so.1 => /lib64/libz.so.1 (0x00007f9cfd410000)
        libgssapi_krb5.so.2 => /lib64/libgssapi_krb5.so.2 (0x00007f9cfd1c3000)
        libkrb5.so.3 => /lib64/libkrb5.so.3 (0x00007f9cfceda000)
        libcom_err.so.2 => /lib64/libcom_err.so.2 (0x00007f9cfccd6000)
        libk5crypto.so.3 => /lib64/libk5crypto.so.3 (0x00007f9cfcaa3000)
        libboost_random.so.1.55.0 => /usr/local/lib/libboost_random.so.1.55.0 (0x00007f9cfc89f000)
        libboost_thread.so.1.55.0 => /usr/local/lib/libboost_thread.so.1.55.0 (0x00007f9cfc687000)
        libboost_filesystem.so.1.55.0 => /usr/local/lib/libboost_filesystem.so.1.55.0 (0x00007f9cfc470000)
        libboost_chrono.so.1.55.0 => /usr/local/lib/libboost_chrono.so.1.55.0 (0x00007f9cfc268000)
        libboost_atomic.so.1.55.0 => /usr/local/lib/libboost_atomic.so.1.55.0 (0x00007f9cfc066000)
        libboost_date_time.so.1.55.0 => /usr/local/lib/libboost_date_time.so.1.55.0 (0x00007f9cfbe55000)
        libboost_regex.so.1.55.0 => /usr/local/lib/libboost_regex.so.1.55.0 (0x00007f9cfbb46000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f9cffe07000)
        libkrb5support.so.0 => /lib64/libkrb5support.so.0 (0x00007f9cfb938000)
        libkeyutils.so.1 => /lib64/libkeyutils.so.1 (0x00007f9cfb733000)
        libresolv.so.2 => /lib64/libresolv.so.2 (0x00007f9cfb519000)
        libicuuc.so.50 => /lib64/libicuuc.so.50 (0x00007f9cfb19f000)
        libicui18n.so.50 => /lib64/libicui18n.so.50 (0x00007f9cfada0000)
        libicudata.so.50 => /lib64/libicudata.so.50 (0x00007f9cf97cc000)
        libselinux.so.1 => /lib64/libselinux.so.1 (0x00007f9cf95a4000)
        libpcre.so.1 => /lib64/libpcre.so.1 (0x00007f9cf9342000)

よさそうです。

トラブルシューティング

期待したオプションが入っているかどうかは、CMakeFiles以下にmakeに関するものがごっそり入っているので、grepかけてあげればだいたい出てきます。

ちょっとだけいじって試したいってときはここを直接変更すれば試せたりしますが推奨できません。 cmakeで上書きされるので、変更した結果を正しく反映するにはCmakeLists.txtを変更する必要があるためです。

感想と今後の展望

CMake便利です。今後もどんどん使っていこうと思います。