cmake の使い方

cmake の使い方について記載してみたいと思います。

 

 

 

1. ステップ1: 実行ファイルを作成

[概要]

"Hello!" をコンソールへ出力するだけの簡単な実行ファイルを作成する手順を題材に説明します。

 

[環境]

コンパイラ : g++, 13.2.0
OS : Ubuntu, 24.04

 

 

1-1. コマンドラインでビルド

まず 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-2. cmake でビルド

"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 を使って開発している場合、.gitignorebuild/ を登録しておくだけでビルド生成物および中間ファイルなどを全て git の管理対象外とすることができます。

 

 

2. ステップ2: 静的・動的ライブラリを作成

[概要]

ライブラリを作る場合、静的・動的ライブラリ(*.a, *.so)を作成することになります。そして実行ファイルにリンクして使用します。

本章では、静的・動的ライブラリを cmake を使って作成などする手順について記載します。

 

[環境]

コンパイラ : g++, 13.2.0
OS : Ubuntu, 24.04

 

 

2-1. コマンドラインでビルド

下記のようなソースコードを準備します。

前章に good_morning.h, good_morning.cpp 2つのファイルを追加した感じです。

 

ファイル構成

./
 ├ main.cpp
 ├ hello.h
 ├ hello.cpp
 ├ good_morning.hgood_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();
}

 

2-1-1. 静的ライブラリの作成

静的ライブラリを作成後、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!

 

2-1-2. 動的ライブラリの作成

動的ライブラリを作成後、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-2. cmake でビルド

"2-1. コマンドラインでビルド" の内容を cmake を使ってビルドするようにしてみます。

前章と同様にファイル構成に CMakeLists.txt を追加します。

 

ファイル構成

./
 ├ CMakeLists.txt
 ├ main.cpp
 ├ hello.h
 ├ hello.cpp
 ├ good_morning.h
 └ good_morning.cpp

 

2-2-1. 静的ライブラリの作成

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!

 

 

 

2-2-2. 動的ライブラリの作成

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!

 

 

3. ステップ3: サブディレクトリにソースが分散している場合

[概要]

ソフトウェアが大規模になってくると役割毎に保存するフォルダを分けたりします。そういった場合を例に説明します。

 

[環境]

コンパイラ : 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;
}

 

 

3-1. コマンドラインでビルド

さて、これをコマンドラインからビルドしてみます。ルートディレクトリ直下にいるものとし、共有ライブラリを作成して実行ファイルにリンクするやり方で行います。

$ 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-2. cmake でビルド

"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 ライセンスで提供されます。

The MIT License (MIT)

  Copyright 2024 Kinoshita Hidetoshi

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

 


 

参考

 


 

記載

2024-12-15 - 3._ステップ3:_サブディレクトリにソースが分散している場合」を追記
2024-10-29 - 新規作成