CMake基礎 #1 - 実行ファイルとライブラリ

Last Edited: 1/21/2025

このブログ記事では、CMakeの基本を紹介します。

DevOps

DevOpsシリーズの最後の記事Linux基礎 #9 - Makefilesでは、 Makeを使用してプロジェクトを自動構築する方法を説明しました。しかし、コードベースが増大し、クロスプラットフォーム互換性が必要になるにつれて、 Makefilesも混雑になりすぎて口付けなくなります。CMakeは無料でクロスプラットフォームのビルドツールで、主にC++用ですが、 Makefilesやその他のビルドツールのスクリプトを自動生成することができます。

CMakeの設定

CMakeを始めるには、Linuxではapt install cmakeを使用してダウンロードします。macOSやWindowsの場合は、 公式サイトを確認し、指示に従ってください。CMakeは、位置されたCMakeLists.txtファイルを解析し、 自動的にビルドスクリプトを生成します。

CMakeLists.txt
cmake_minimum_required(VERSION 3.15)
 
# Project Name, Version, Language (default is C++), etc. 
project(MyProject C)
 
# Naming BINARY (We could have used PROJECT_NAME to set the output binary name to the project's name)
set(BINARY bin)
 
# Create the executables using the specified files
add_executable(${BINARY} main.c LinkedList.c)

ここで、#はコメント用で、大文字はsetで設定する変数や、あらかじめ定義された変数を示します。 cmake -S <source_path> -B <build_path>を実行すると、<source_path>CMakeLists.txtを使用して、 指定した<build_path>に適切なビルドスクリプトやMakefileを生成します。一般的には、 プロジェクトのルートディレクトリの配下に/buildディレクトリを作成し、cmake -S . -B /buildでMakefileを生成します。 そして/buildディレクトリに移動し、Makefileが成功製作されたことを確認します。makeを実行すると実行ファイルが生成され、 ./binで実行できます。

ライブラリの構築

上記の例から、CMakeがMakefilesと比較して構築過程を簡素化することがわかります。CMakeはまた、ソースコードを簡単にライブラリにコンパイルし、 それをメインソースコードにリンクできるようにすることも可能です。例えば、LinkedListディレクトリを構築し、 このディレクトリにLinkedList.hLinkedList.cを含めます。その後、以下のようにライブラリを簡単に構築できます。

LinkedList/CMakeLists.txt
cmake_minimum_required(VERSION 3.15)
 
project(LinkedList C)
 
# Create a library (STATIC by default. We can specify it to be SHARED.)
add_library(LinkedList LinkedList.c)

add_library関数は静的ライブラリlibLinkedList.aを作成します。このライブラリはメインのソースコードに以下のようにリンクできます。

cmake_minimum_required(VERSION 3.15)
 
project(MyProject C)
 
# Add library as subdirectory in `build_path` to run build on library and to reference it
add_subdirectory(LinkedList)
 
add_executable(${PROJECT_NAME} main.c)
 
# Tell where to look for header files not in standard location
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/LinkedList)
 
# Link Libraries
target_link_libraries(${PROJECT_NAME} LinkedList)

add_subdirectoryは、指定したサブディレクトリ(この場合はLinkedList)にあるCMakeLists.txtを利用してLinkedListを自動的にビルドします。 これは静的ライブラリを作成します。target_include_directoriesを使用することで、ヘッダーファイルへのフルパスを指定することなく、 メインソースコードからヘッダーファイルを利用可能にします。さらに、target_link_librariesを使用してライブラリをリンクします。 プロジェクトをより整理するために、以下のようなファイル構造を構築するのが一般的です。

CMakeLists.txt
main.c
LibraryA/
├── CMakeLists.txt
├── src/
│   ├── module1.c
│   └── module2.c
├── include/
│   ├── module1.h
│   └── module2.h

この構造に基づき、以下のようにサブディレクトリのLinkedListを指定してプロジェクトをセットアップできます。

LibraryA/CMakeLists.txt
cmake_minimum_required(VERSION 3.15)
 
project(LibraryA C)
 
# Collect C files from /src
file(GLOB SRC_FILES ${CMAKE_SOURCE_DIR}/LibraryA/src/*.c)
 
add_library(LibraryA STATIC ${SRC_FILES})

プロジェクトのルートディレクトリのCMakeLists.txt

CMakeLists.txt
cmake_minimum_required(VERSION 3.15)
 
project(MyProject C)
 
add_subdirectory(LibraryA)
 
add_executable(${PROJECT_NAME} main.c)
 
target_link_libraries(${PROJECT_NAME} LibraryA)
 
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/LibraryA/include)

他人が作成したライブラリコードやサブモジュールをダウンロードし、上記の手順に従ってライブラリとしてビルドして使用できます。 これにより、サードパーティのコードやカスタムライブラリを大規模なプロジェクトに統合するプロセスが簡素化されます。

実行ファイルとライブラリのインストール

ビルドディレクトリで作成したライブラリを使用する代わりに、マシンにインストールして利用することもできます。 例えば、以下のようにinstallコマンドを使用できます。

LibraryA/CMakeLists.txt
cmake_minimum_required(VERSION 3.15)
 
project(LibraryA C)
 
file(GLOB SRC_FILES ${CMAKE_SOURCE_DIR}/src/*.c)
 
add_library(LibraryA STATIC ${SRC_FILES})
 
# Collect header files from /include
file(GLOB HEADER_FILES ${CMAKE_SOURCE_DIR}/include/*.h)
 
# Set public header property
set_target_properties(LibraryA PROPERTIES PUBLIC_HEADER "${HEADER_FILES}")
 
# Install library to local environment "lib" and header files to "include" 
# (usually /usr/local/lib and /usr/local/include)
install(
     TARGETS LibraryA ARCHIVE DESTINATION lib
     PUBLIC_HEADER DESTINATION include
)

installコマンドのARCHIVE引数は静的ライブラリ用であり、共有または動的ライブラリにはLIBRARYを使用する必要があります。 上記のファイルを使用してsudo make installを実行すると、ライブラリがローカル環境にインストールされ、 同じ環境内のすべての実行ファイルがパスを指定せずにそれを使用できるようになります。 さらに、実行ファイルもインストールすることで、どこからでも実行できるようにすることが可能です。

CMakeLists.txt
cmake_minimum_required(VERSION 3.15)
 
project(MyProject C)
 
add_subdirectory(LibraryA)
 
add_executable(${PROJECT_NAME} main.c)
 
target_link_libraries(${PROJECT_NAME} LibraryA)
 
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/LibraryA/include)
 
# Install executable to local environment "bin" (usually /usr/local/bin)
install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION bin)

上記の構成を使用してsudo make nstallを実行すると、実行ファイルがインストールされ、 MyProjectと入力するだけでどこからでも実行できるようになります。

結論

この記事では、CMakeとは何か、なぜCMakeを使用するのか、CMakeの始め方、 そしてCMakeの基本について説明しました。このCMakeシリーズでは、 (少なくとも私の計画では)少数の記事でCMakeについて必要な知識をほぼすべてカバーする予定です。

リソース