cmake の使い方について記載してみたいと思います。
"Hello!" をコンソールへ出力するだけの簡単な実行ファイルを作成する手順を題材に説明します。
コンパイラ : | g++, | 13.2.0 |
OS : | Ubuntu, | 24.04 |
まず g++ コンパイラを使ったビルドの基本を確認します。
下記のようなソースコードを準備します。
ファイル構成
./ ├ main.cpp ├ hello.h └ hello.cpp
[main.cpp]
#include "hello.h" int main() { hello(); }
[hello.h]
#ifndef HELLO_H #define HELLO_H void hello(); #endif
[hello.cpp]
#include <iostream> #include "hello.h" void hello() { std::cout << "Hello!" << std::endl; }
上記ソースコード3つを準備できたら、下記コマンドを入力してビルドします。
$ g++ -c main.cpp hello.cpp $ g++ -o start_cmake.out main.o hello.o
この start_cmake.out を実行すれば Hello! を出力します。
$ ./start_cmake.out Hello!
"1-1. コマンドラインでビルド" の内容を cmake を使ってビルドするようにしてみます。
CMakeLists.txt を以下のように作成します。
[CMakeLists.txt]
# CMake のバージョンを設定 cmake_minimum_required(VERSION 3.13) # プロジェクト名と使用する言語を設定 project(start_cmake CXX) # start_cmake.out という実行ファイルを main.cpp と hello.cpp から作成 add_executable(start_cmake.out main.cpp hello.cpp)
CMakeLists.txt ファイルを追加後のディレクトリの中身は以下のようになります。
ファイル構成
./ ├ CMakeLists.txt ├ main.cpp ├ hello.h └ hello.cpp
cmake を使ってビルドするときは、次のようにソースディレクトリとは別にビルド専用のディレクトリを作成し、その中でビルドします。慣習的に build というフォルダを作成する場合が多いように思います。
ビルドおよびビルド生成物を実行するまで一連の操作を以下に示します。
$ mkdir build $ cd build $ cmake .. -- The CXX compiler identification is GNU 13.2.0 -- Detecting CXX compiler ABI info -- Detecting CXX compiler ABI info - done -- Check for working CXX compiler: /usr/bin/c++ - skipped -- Detecting CXX compile features -- Detecting CXX compile features - done -- Configuring done (0.6s) -- Generating done (0.0s) -- Build files have been written to: /home/hoge/build $ make [ 33%] Building CXX object CMakeFiles/start_cmake.out.dir/main.cpp.o [ 66%] Building CXX object CMakeFiles/start_cmake.out.dir/hello.cpp.o [100%] Linking CXX executable start_cmake.out [100%] Built target start_cmake.out $ ./start_cmake.out Hello!
cmake を使った場合、ビルド結果は全て build ディレクトリ内に保存されているため、build ディレクトリを削除するだけで容易に元の状態に戻すことができます。これは out-of-source ビルドと呼ばれています。また git を使って開発している場合、.gitignore に build/ を登録しておくだけでビルド生成物および中間ファイルなどを全て git の管理対象外とすることができます。
ライブラリを作る場合、静的・動的ライブラリ(*.a, *.so)を作成することになります。そして実行ファイルにリンクして使用します。
本章では、静的・動的ライブラリを cmake を使って作成などする手順について記載します。
コンパイラ : | g++, | 13.2.0 |
OS : | Ubuntu, | 24.04 |
下記のようなソースコードを準備します。
前章に good_morning.h, good_morning.cpp 2つのファイルを追加した感じです。
ファイル構成
./ ├ main.cpp ├ hello.h ├ hello.cpp ├ good_morning.h └ good_morning.cpp
[good_morning.h]
#ifndef GOOD_MORNING_H #define GOOD_MORNING_H void good_morning(); #endif
[good_morning.cpp]
#include <iostream> #include "good_morning.h" void good_morning() { std::cout << "Good morning!" << std::endl; }
main.cpp を次のように変更します。
[main.cpp]
#include "hello.h" #include "good_morning.h" int main() { hello(); good_morning(); }
静的ライブラリを作成後、main.cpp をコンパイルして静的ライブラリとリンクします。
$ g++ -c hello.cpp good_morning.cpp # hello.o, good_morning.o を作成 $ ar rvs libgreetings.a hello.o good_morning.o # 静的ライブラリ(libgreetings.a)を作成 $ g++ -o start_cmake.out main.cpp -lgreetings -L. # main.cpp をコンパイルして libgreetings.a とリンク
生成したファイル start_cmake.out を実行すれば下記のように出力します。
$ ./start_cmake.out Hello! Good morning!
動的ライブラリを作成後、main.cpp をコンパイルして動的ライブラリとリンクします。
$ g++ -fPIC -c hello.cpp good_morning.cpp # hello.o, good_morning.o を作成 $ g++ -shared hello.o good_morning.o -o libgreetings.so # 静的ライブラリ(libgreetings.so)を作成 $ g++ -o start_cmake.out main.cpp -lgreetings -L. -Xlinker -rpath -Xlinker . # mmain.cpp をコンパイルして libgreetings.so とリンク
生成したファイル start_cmake.out を実行すれば下記のように出力します。
$ ./start_cmake.out Hello! Good morning!
"2-1. コマンドラインでビルド" の内容を cmake を使ってビルドするようにしてみます。
前章と同様にファイル構成に CMakeLists.txt を追加します。
ファイル構成
./ ├ CMakeLists.txt ├ main.cpp ├ hello.h ├ hello.cpp ├ good_morning.h └ good_morning.cpp
CMakeLists.txt を以下のように作成します。
[CMakeLists.txt]
cmake_minimum_required(VERSION 3.13) project(start_cmake CXX) # 静的ライブラリlibgreetings.aを作成 add_library(greetings STATIC hello.cpp good_morning.cpp) # start_cmake.outという実行ファイルをmain.cppから作成 add_executable(start_cmake.out main.cpp) # start_cmake.outを作成する際にlibgreetings.aをリンク target_link_libraries(start_cmake.out greetings)
CMakeを使ってビルドする場合、静的・共有ライブラリを作成するときの違いはたったの一語(STATIC/SHARED)です。
add_library(greetings [SHARED|STATIC] hello.cpp good_morning.cpp)
ビルドおよびビルド生成物を実行するまで一連の操作を以下に示します。
$ mkdir build $ cd build/ $ cmake .. -- The CXX compiler identification is GNU 13.2.0 -- Detecting CXX compiler ABI info -- Detecting CXX compiler ABI info - done -- Check for working CXX compiler: /usr/bin/c++ - skipped -- Detecting CXX compile features -- Detecting CXX compile features - done -- Configuring done (0.6s) -- Generating done (0.0s) -- Build files have been written to: /home/hoge/build $ make [ 20%] Building CXX object CMakeFiles/greetings.dir/hello.cpp.o [ 40%] Building CXX object CMakeFiles/greetings.dir/good_morning.cpp.o [ 60%] Linking CXX static library libgreetings.a [ 60%] Built target greetings [ 80%] Building CXX object CMakeFiles/start_cmake.out.dir/main.cpp.o [100%] Linking CXX executable start_cmake.out [100%] Built target start_cmake.out $ ./start_cmake.out Hello! Good morning!
CMakeLists.txt を以下のように作成します。
[CMakeLists.txt]
cmake_minimum_required(VERSION 3.13) project(start_cmake CXX) # 動的ライブラリlibgreetings.soを作成 add_library(greetings SHARED hello.cpp good_morning.cpp) # start_cmake.outという実行ファイルをmain.cppから作成 add_executable(start_cmake.out main.cpp) # start_cmake.outを作成する際にlibgreetings.soをリンク target_link_libraries(start_cmake.out greetings)
CMakeを使ってビルドする場合、静的・共有ライブラリを作成するときの違いはたったの一語(STATIC/SHARED)です。
add_library(greetings [SHARED|STATIC] hello.cpp good_morning.cpp)
ビルドおよびビルド生成物を実行するまで一連の操作を以下に示します。
$ mkdir build $ cd build/ $ cmake .. -- The CXX compiler identification is GNU 13.2.0 -- Detecting CXX compiler ABI info -- Detecting CXX compiler ABI info - done -- Check for working CXX compiler: /usr/bin/c++ - skipped -- Detecting CXX compile features -- Detecting CXX compile features - done -- Configuring done (0.6s) -- Generating done (0.0s) -- Build files have been written to: /home/hoge/build $ make [ 20%] Building CXX object CMakeFiles/greetings.dir/hello.cpp.o [ 40%] Building CXX object CMakeFiles/greetings.dir/good_morning.cpp.o [ 60%] Linking CXX shared library libgreetings.so [ 60%] Built target greetings [ 80%] Building CXX object CMakeFiles/start_cmake.out.dir/main.cpp.o [100%] Linking CXX executable start_cmake.out [100%] Built target start_cmake.out $ ./start_cmake.out Hello! Good morning!
ソフトウェアが大規模になってくると役割毎に保存するフォルダを分けたりします。そういった場合を例に説明します。
コンパイラ : | g++, | 13.2.0 |
OS : | Ubuntu, | 24.04 |
下記のようなフォルダおよびファイル構成を例に説明します。ファイル内容は前章と同じです。
ファイル構成
./ ├ include/ │├ hello.h │└ good_morning.h ├ source/ │├ hello.cpp │└ good_morning.cpp └ main/ └ main.cpp
[main.cpp]
#include "hello.h" #include "good_morning.h" int main() { hello(); good_morning(); }
[hello.h]
#ifndef HELLO_H #define HELLO_H void hello(); #endif
[hello.cpp]
#include <iostream> #include "hello.h" void hello() { std::cout << "Hello!" << std::endl; }
[good_morning.h]
#ifndef GOOD_MORNING_H #define GOOD_MORNING_H void good_morning(); #endif
[good_morning.cpp]
#include <iostream> #include "good_morning.h" void good_morning() { std::cout << "Good morning!" << std::endl; }
さて、これをコマンドラインからビルドしてみます。ルートディレクトリ直下にいるものとし、共有ライブラリを作成して実行ファイルにリンクするやり方で行います。
$ cd source/ $ g++ -fPIC -c hello.cpp good_morning.cpp -I../include $ g++ -shared *.o -o libgreetings.so $ cd ../main/ $ g++ main.cpp -o main.out -I../include -L../source -lgreetings -Xlinker -rpath -Xlinker ../source
今回は -L オプションに加えて -I オプションでインクルードファイルを探すディレクトリを指定する必要があります。前章で -I オプションが必要なかったのは、カレントディレクトリはデフォルトでインクルードファイルを探す場所として認識されるからです。
上記コマンドを実行後のフォルダ構成は下図のようになります。
./ ├ include/ │├ hello.h │└ good_morning.h ├ source/ │├ hello.cpp │├ hello.o │├ good_morning.cpp │├ good_morning.o │└ libgreetings.so └ main/ ├ main.cpp └ main.out
生成したファイル main.out を実行すれば下記のように出力します。
$ ./main.out Hello! Good morning!
"3-1. コマンドラインでビルド" の内容を cmake を使ってビルドできるようにします。
ファイル構成を下図のようにします。CMakeLists.txt をルートおよび source/、main/ の3か所に追加します。
ファイル構成
./ ├ CMakeLists.txt ├ include/ │├ hello.h │└ good_morning.h ├ source/ │├ CMakeLists.txt │├ hello.cpp │└ good_morning.cpp └ main/ ├ CMakeLists.txt └ main.cpp
ルートディレクトリにある CMakeLists.txt ではサブディレクトリの登録をします。
[./CMakeLists.txt]
cmake_minimum_required(VERSION 3.13) project(greetings CXX) # サブディレクトリを登録 add_subdirectory(source) add_subdirectory(main)
/source/CMakeLists.txt および /main/CMakeLists.txt ではそれぞれのディレクトリにあるファイルのコンパイル方法を指定します。
[./source/CMakeLists.txt]
add_library( greetings SHARED hello.cpp good_morning.cpp ) # greetingライブラリのインクルードディレクトリを教えてあげる # PROJECT_SOURCE_DIRはこのプロジェクトのルートディレクトリの絶対パス target_include_directories( greetings PUBLIC ${PROJECT_SOURCE_DIR}/include )
[./main/CMakeLists.txt]
add_executable(main.out main.cpp) # main.outをコンパイルする際にgreetingsをリンクする target_link_libraries(main.out greetings)
以上で準備を完了しました。
cmake を使った場合のいつもの手順でビルドします。下記ではビルド結果 main.out の実行まで一連の操作とコンソール出力の例を例示します。
$ mkdir build $ cd build $ cmake .. -- The CXX compiler identification is GNU 13.2.0 -- Detecting CXX compiler ABI info -- Detecting CXX compiler ABI info - done -- Check for working CXX compiler: /usr/bin/c++ - skipped -- Detecting CXX compile features -- Detecting CXX compile features - done -- Configuring done (0.6s) -- Generating done (0.0s) -- Build files have been written to: /home/foo//step_03/build $ make [ 20%] Building CXX object source/CMakeFiles/greetings.dir/hello.cpp.o [ 40%] Building CXX object source/CMakeFiles/greetings.dir/good_morning.cpp.o [ 60%] Linking CXX shared library libgreetings.so [ 60%] Built target greetings [ 80%] Building CXX object main/CMakeFiles/main.out.dir/main.cpp.o [100%] Linking CXX executable main.out [100%] Built target main.out $ ./main/main.out Hello! Good morning!
以上で完了です。
本ページの情報は、特記無い限り下記 MIT ライセンスで提供されます。
2024-12-15 | - | 「3._ステップ3:_サブディレクトリにソースが分散している場合」を追記 |
2024-10-29 | - | 新規作成 |