Makefile
s(make
)とCMakeLists.txt
(cmake
)のサンプルコードがあり、どちらも同じことを行うのかと思っていました(唯一の違いは1つはmake
で、もう1つはcmake
で書かれています。
「cmake vs make」を探してみましたが、コードの比較は見つかりませんでした。単純な場合であっても、違いを理解することは本当に役立ちます。
次のMakefileは、ソースprog1.c, prog2.c, prog3.c and main.c
からprog
という名前の実行可能ファイルをビルドします。 prog
はlibmystatlib.a
およびlibmydynlib.so
に対してリンクされており、どちらもソースからビルドされます。さらに、prog
はlibstuff.a
のライブラリstuff/lib
とstuff/include
のヘッダーを使用します。 Makefileはデフォルトでリリースターゲットをビルドしますが、デバッグターゲットも提供します。
#Makefile
CC = gcc
CPP = g++
RANLIB = ar rcs
RELEASE = -c -O3
DEBUG = -c -g -D_DEBUG
INCDIR = -I./stuff/include
LIBDIR = -L./stuff/lib -L.
LIBS = -lstuff -lmystatlib -lmydynlib
CFLAGS = $(RELEASE)
PROGOBJS = prog1.o prog2.o prog3.o
prog: main.o $(PROGOBJS) mystatlib mydynlib
$(CC) main.o $(PROGOBJS) $(LIBDIR) $(LIBS) -o prog
debug: CFLAGS=$(DEBUG)
debug: prog
mystatlib: mystatlib.o
$(RANLIB) libmystatlib.a mystatlib.o
mydynlib: mydynlib.o
$(CPP) -shared mydynlib.o -o libmydynlib.so
%.o: %.c
$(CC) $(CFLAGS) $(INCDIR) $< -o $@
%.o: %.cpp
$(CPP) $(CFLAGS) $(INCDIR) -fPIC $< -o $@
Makefileとの類似点を強調するコメントを付けて、(ほぼ)まったく同じことを行うCMakeLists.txt
を次に示します。
#CMakeLists.txt
cmake_minimum_required(VERSION 2.8) # stuff not directly
project(example) # related to building
include_directories(${CMAKE_SOURCE_DIR}/stuff/include) # -I flags for compiler
link_directories(${CMAKE_SOURCE_DIR}/stuff/lib) # -L flags for linker
set(PROGSRC prog1.c prog2.c prog3.c) # define variable
add_executable(prog main.c ${PROGSRC}) # define executable target prog, specify sources
target_link_libraries(prog mystatlib mydynlib stuff) # -l flags for linking prog target
add_library(mystatlib STATIC mystatlib.c) # define static library target mystatlib, specify sources
add_library(mydynlib SHARED mydynlib.cpp) # define shared library target mydynlib, specify sources
#extra flags for linking mydynlib
set_target_properties(mydynlib PROPERTIES POSITION_INDEPENDENT_CODE TRUE)
#alternatively:
#set_target_properties(mydynlib PROPERTIES COMPILE_FLAGS "-fPIC")
この簡単な例では、最も重要な違いは次のとおりです。
CMakeは、どのコンパイラをどの種類のソースに使用するかを認識します。また、各タイプのターゲットに対して正しいコマンドシーケンスを呼び出します。したがって、$(CC)...、$(RANLIB)...などのコマンドの明示的な指定はありません。
ヘッダーファイルやライブラリなどのインクルードを処理する通常のコンパイラ/リンカーフラグはすべて、プラットフォームに依存しない/ビルドシステムに依存しないコマンドに置き換えられます。
デバッグフラグは、変数CMAKE_BUILD_TYPEを「Debug」に設定するか、プログラムの呼び出し時にCMakeに渡すことで含まれます:cmake -DCMAKE_BUILD_TYPE:STRING=Debug
。
CMakeは、プラットフォームに依存しない '-fPIC'フラグ(POSITION_INDEPENDENT_CODEプロパティを使用)およびその他多くのオプションも提供します。それでも、Makefileだけでなく(COMPILE_FLAGS
および同様のプロパティを使用して)CMakeでも、より不明瞭な設定を手動で実装できます。もちろん、OpenGLのようなサードパーティのライブラリが移植可能な方法で含まれると、CMakeは本当に輝き始めます。
Makefileを使用する場合、ビルドプロセスには1つのステップがあります。つまり、コマンドラインでmake
と入力します。 CMakeには2つのステップがあります。最初に、ビルド環境をセットアップする必要があります(ビルドディレクトリにcmake <source_dir>
と入力するか、GUIクライアントを実行します)。これにより、選択したビルドシステムに応じて、Makefileまたは同等のものが作成されます(例:UnixのmakeまたはVC++またはWindowsのMinGW + Msys)。ビルドシステムは、パラメーターとしてCMakeに渡すことができます。ただし、CMakeは、システム構成に応じて適切なデフォルトの選択を行います。次に、選択したビルドシステムで実際のビルドを実行します。
ソースとビルド手順は https://github.com/rhoelzel/make_cmake で入手できます。
ビルドシステムとしてCMakeを使用するソフトウェアを入手してください(例として選択できるオープンソースプロジェクトがたくさんあります)。ソースコードを取得し、CMakeを使用して構成します。結果のメイクファイルを読んで楽しんでください。
これらのツールは1対1でマッピングされないことに注意してください。最も明らかな違いは、CMakeは異なるファイル(Cヘッダーとソースファイルなど)間の依存関係をスキャンするのに対して、makeはメイクファイルの作成者にそれを任せることです。
この質問がCMakeList.txt
ファイルのMakefile
出力のサンプルに関するものである場合は、cmake-backendソースを確認して、そのようなMakefile
を生成してください。それが@Robertoの返信に追加されていない場合、詳細を非表示にして簡単にしようとしています。
Make
はルールとレシピ用の柔軟なツールですが、CMake
は構成機能も追加する抽象化レイヤーです。
私のプレーンCMakeLists.txt
は次のようになります。
cmake_minimum_required(VERSION 2.8)
project(example)
file(GLOB testapp_SOURCES *.cc)
add_executable(testapp ${testapp_SOURCES})
CMake
はhow
を非表示にし、ビルドを実行できることに注意してください。 what
のみが入力および出力であると指定しました。
CMakeLists.txt
には、cmake
で定義される関数呼び出しのリストが含まれます。
Makefile
では、functions
の代わりにrules and recipes
が使用されます。 function
のような機能に加えて、rules and recipes
は連鎖を提供します。私のミニマルなMakefile
は次のようになります。
-include "executable.mk"
TARGETS=testapp.bin
all:${TARGETS}
executable.mk
は次のようになりますが、
SOURCES=$(wildcard *.cpp)
OBJECTS=$(SOURCES:.cpp=.o)
DEPS=$(SOURCES:.cpp=.d)
%.bin:$(OBJECTS)
$(CC) $(CFLAGS) -o $@ $^ $(LFLAGS) $(LIBS)
.PHONY: all clean
clean:
$(RM) $(OBJECTS) $(DEPS) $(TARGETS)
-include $(DEPS)
スクラッチから始めて、次のようなMakefile
で始めます。
all: testapp.bin
testapp.bin:sourcea.o sourcb.o
$(CC) $(CFLAGS) -o $@ $^ $(LFLAGS) $(LIBS)
.PHONY: all clean
clean:
$(RM) $(OBJECTS) testapp.bin
このスニペットは here から取得して変更しました。いくつかの暗黙の規則がこのファイルに追加されており、makefile-documentationにあることに注意してください。ここでは、いくつかの暗黙的な変数も関連しています。
Makefile
は、ビルドを実行できるrecipe
を示す詳細how
を提供することに注意してください。 executable.mk
を記述して、詳細を1つのファイルに定義しておくことができます。そのようにして、前に示したように、メイクファイルを減らすことができます。
CMake
およびMake
の内部変数少し高度になったので、CMake
で次のようなコンパイラフラグを設定できます。
set(CMAKE_C_FLAGS "-Wall")
CMakeCache.txt
ファイルのCMake
デフォルト変数の詳細をご覧ください。上記のCMake
コードは、以下のMake
コードと同等です。
CFLAGS = -Wall
CFLAGS
はMake
の内部変数であることに注意してください。同様に、CMAKE_C_FLAGS
はCMake
の内部変数です。
関数を使用してcmake
で実行できます。
target_include_directories(testapp PRIVATE "myincludes")
list(APPEND testapp_LIBRARIES
mytest mylibrarypath
)
target_link_libraries(testapp ${testapp_LIBRARIES})
次のような行を追加して、インクルードとライブラリを追加できます。
INCLUDES += -Imyincludes
LIBS += -Lmylibrarypath -lmytest
上記のこの行は、自動生成ツールまたはpkg-configから生成できます。 (ただし、Makefileは自動設定ツールに依存しません)
通常、config.h
関数を使用すると、auto-config
ツールと同様に、いくつかのconfigure_file
ファイルを生成できます。カスタム関数を作成するより多くのトリックを行うことが可能です。最後に、次のような設定を選択できます。
cmake --build . --config "Release"
option
関数を使用して、構成可能なオプションを追加することができます。
何らかのデバッグフラグを付けてコンパイルする必要がある場合は、make
のように呼び出すことができます。
make CXXFLAGS=NDEBUG
内部変数Makefile-rules
とCMake-functions
は比較のための良い出発点であり、さらに掘り下げて幸運だと思います。