MakefileでビルドしていたソースツリーをCMakeLists.txtに置き換えます。
Table of Contents
1 MakefileとCMakeLists.txt
CMakeLists.txtはconfigure + Makefileとほぼ同等です。Unixの場合、cmakeコマンドでCMakeLists.txtからMakefileを生成します。このMakefileはインクルードファイルの更新時のソースコードの再ビルドや、makeの並列実行にも対応できています。その一報で記述量がMakefileと変わらないので導入を検討してみると良いでしょう。
2 Makefileのソースツリー
以下の様なソースツリーを使います。
$ tree . ├── include │ └── hello.h ├── lib │ ├── hello.cpp │ └── Makefile ├── Makefile └── src ├── main.cpp └── Makefile 3 directories, 6 files
2.1 トップディレクトリのMakefile
トップディレクトリのMakefileは以下のとおりです。
- ビルド処理はlibディレクトリとsrcディレクトリのMakefileに任せます。ただし、srcディレクトリでlibディレクトリのライブラリを参照するので、先にlibディレクトリが実行されるようにします。
LIBNAME := libexample.a PROGNAME := example export LIBNAME export PROGNAME all: lib $(MAKE) -C src lib: $(MAKE) -C lib clean: $(MAKE) -C lib clean $(MAKE) -C src clean .PHONY: lib
2.2 ライブラリを作成するMakefile
libディレクトリのMakefileは以下のとおりです。
- .cppのソースコードからオブジェクトを割り出し、arコマンドでオブジェクトをlibexample.aにします。暗黙のルールでオブジェクトは自動的にコンパイルされます。
- .dファイルにオブジェクトと.dファイルの依存関係を記述しておき、ヘッダファイルの更新等で自動的にビルドが実行されるようにします。ただし、cleanの時には.dファイルを生成しないようにします。
CXXFLAGS := -I../include -I. SRC := $(wildcard *.cpp) OBJ := $(patsubst %.cpp,%.o,$(SRC)) DEP := $(patsubst %.cpp,%.d,$(SRC)) all: $(LIBNAME) clean: $(RM) $(DEP) $(OBJ) $(LIBNAME) %.d: %.cpp $(CXX) -MM $(CXXFLAGS) $< | sed 's/\($*\)\.o[ :]*/\1.o $@ : /g' > $@ ifneq ($(filter clean,$(MAKECMDGOALS)),clean) -include $(DEP) endif $(LIBNAME): $(OBJ) $(AR) rc $@ $(OBJ)
2.3 ライブラリを参照するMakefile
srcディレクトリのMakefileは以下のとおりです。
- .cppのソースコードからオブジェクトを割り出し、c++コマンドでオブジェクトをexampleにコンパイルします。暗黙のルールでオブジェクトは自動的にコンパイルされます。
- .dファイルについては先ほどと同様です。
CXXFLAGS = -I../include -I. SRC := $(wildcard *.cpp) DEP := $(patsubst %.cpp,%.d,$(SRC)) OBJ := $(patsubst %.cpp,%.o,$(SRC)) all: $(PROGNAME) $(PROGNAME): $(OBJ) ../lib/$(LIBNAME) $(CXX) $(CXXFLAGS) $^ -o $@ %.d: %.cpp $(CXX) -MM $(CXXFLAGS) $< | sed 's/\($*\)\.o[ :]*/\1.o $@ : /g' > $@ ifneq ($(filter clean,$(MAKECMDGOALS)),clean) -include $(DEP) endif clean: $(RM) $(DEP) $(OBJ) $(PROGNAME)
2.4 Makefileでビルド
makeを実行します。
$ make /Applications/Xcode.app/Contents/Developer/usr/bin/make -C lib c++ -MM -I../include -I. hello.cpp | sed 's/\(hello\)\.o[ :]*/\1.o hello.d : /g' > hello.d c++ -I../include -I. -c -o hello.o hello.cpp ar rc libexample.a hello.o /Applications/Xcode.app/Contents/Developer/usr/bin/make -C src c++ -MM -I../include -I. main.cpp | sed 's/\(main\)\.o[ :]*/\1.o main.d : /g' > main.d c++ -I../include -I. -c -o main.o main.cpp c++ -I../include -I. main.o ../lib/libexample.a -o example
3 CMakeLists.txtのソースツリー
以下の様なソースツリーを使います。
$ tree . ├── CMakeLists.txt ├── include │ └── hello.h ├── lib │ ├── CMakeLists.txt │ └── hello.cpp └── src ├── CMakeLists.txt └── main.cpp 3 directories, 6 files
3.1 トップディレクトリのCMakeLists.txt
トップディレクトリのCMakeLists.txtは以下のとおりです。
- cmakeはソースツリー外にビルド環境を整えることが可能です(様々なファイルが生成されるのでソースツリー外でcmakeを実行したほうが良い)。CMAKE_SOURCE_DIRとCMAKE_BINARY_DIRを比較して、ソースツリー内ではcmakeを実行できないようにします。
- add_subdirectoryでlibディレクトリとsrcディレクトリを追加します。ディレクトリ間の依存関係は記述しません。srcディレクトリのCMakeLists.txtにてtarget_link_librariesを使うことで、ビルドの依存関係が自動的に決まります。
if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR}) message(FATAL_ERROR "DO NOT BUILD in-tree.") endif() cmake_minimum_required (VERSION 2.8.11) project(example) add_subdirectory(lib) add_subdirectory(src)
3.2 ライブラリを作成するCMakeLists.txt
libディレクトリのCMakeLists.txtは以下のとおりです。
- AUX_SOURCE_DIRECTORYでカレントソースディレクトリにあるソースコードをsourceという変数に格納します。
- add_libraryでsource変数に格納されたソースコードからlibexampleという名前のライブラリを作成します。このままだとliblibexample.aというファイル名になってしまうので、set_target_propertiesでlibexample.aという名前に変更します。
- target_include_directoriesで他から参照できるようにライブラリを公開します。
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}) AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} source) # Use libexample for avoiding conflicts with add_executable(example). # And rename liblibexample.a to libexample.a add_library(libexample ${source}) set_target_properties(libexample PROPERTIES OUTPUT_NAME "example") target_include_directories(libexample PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
3.3 ライブラリを参照するCMakeLists.txt
srcディレクトリのCMakeLists.txtは以下のとおりです。
- AUX_SOURCE_DIRECTORYでカレントソースディレクトリにあるソースコードをsourceという変数に格納します。
- add_executableでsource変数に格納されたソースコードからexampleという名前のバイナリを作成します。ファイル名はexampleです。
- target_link_librariesでlibexampleという名前のライブラリを参照します(このlibexampleはファイル名ではなく、target_include_directoriesで指定した名前です)。
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}) AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} source) add_executable(example ${source}) target_link_libraries(example LINK_PUBLIC libexample)
3.4 CMakeLists.txtでビルド
cmakeを実行してMakefileを作成してからmakeを実行します。ソースコードが変更された場合はmakeを実行すればソースコードがビルドされます。CMakeLists.txtが変更された場合はcmakeを再実行する必要があります。
$ ls cmake-tree CMakeLists.txt include lib src $ mkdir cmake-tree.build $ cd cmake-tree.build $ cmake ../cmake-tree -G 'Unix Makefiles' $ make [ 50%] Building CXX object lib/CMakeFiles/libexample.dir/hello.cpp.o Linking CXX static library libexample.a [ 50%] Built target libexample [100%] Building CXX object src/CMakeFiles/example.dir/main.cpp.o Linking CXX executable example