web-dev-qa-db-ja.com

Cmake vs makeサンプルコード?

Makefiles(make)とCMakeLists.txtcmake)のサンプルコードがあり、どちらも同じことを行うのかと思っていました(唯一の違いは1つはmakeで、もう1つはcmakeで書かれています。

「cmake vs make」を探してみましたが、コードの比較は見つかりませんでした。単純な場合であっても、違いを理解することは本当に役立ちます。

107
jlo

次のMakefileは、ソースprog1.c, prog2.c, prog3.c and main.cからprogという名前の実行可能ファイルをビルドします。 proglibmystatlib.aおよびlibmydynlib.soに対してリンクされており、どちらもソースからビルドされます。さらに、proglibstuff.aのライブラリstuff/libstuff/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 で入手できます。

111
Roberto

ビルドシステムとしてCMakeを使用するソフトウェアを入手してください(例として選択できるオープンソースプロジェクトがたくさんあります)。ソースコードを取得し、CMakeを使用して構成します。結果のメイクファイルを読んで楽しんでください。

これらのツールは1対1でマッピングされないことに注意してください。最も明らかな違いは、CMakeは異なるファイル(Cヘッダーとソースファイルなど)間の依存関係をスキャンするのに対して、makeはメイクファイルの作成者にそれを任せることです。

この質問がCMakeList.txtファイルのMakefile出力のサンプルに関するものである場合は、cmake-backendソースを確認して、そのようなMakefileを生成してください。それが@Robertoの返信に追加されていない場合、詳細を非表示にして簡単にしようとしています。

CMake機能

Makeはルールとレシピ用の柔軟なツールですが、CMakeは構成機能も追加する抽象化レイヤーです。

私のプレーンCMakeLists.txtは次のようになります。

cmake_minimum_required(VERSION 2.8)
project(example)
file(GLOB testapp_SOURCES *.cc)
add_executable(testapp ${testapp_SOURCES})

CMakehowを非表示にし、ビルドを実行できることに注意してください。 whatのみが入力および出力であると指定しました。

CMakeLists.txtには、cmakeで定義される関数呼び出しのリストが含まれます。

(CMake関数)Vs Makeルール

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

CFLAGSMakeの内部変数であることに注意してください。同様に、CMAKE_C_FLAGSCMakeの内部変数です。

cMakeにインクルードとライブラリパスを追加する

関数を使用してcmakeで実行できます。

target_include_directories(testapp PRIVATE "myincludes")
list(APPEND testapp_LIBRARIES
    mytest mylibrarypath
)
target_link_libraries(testapp ${testapp_LIBRARIES})

Makeでのインクルードとライブラリパスの追加

次のような行を追加して、インクルードとライブラリを追加できます。

INCLUDES += -Imyincludes
LIBS += -Lmylibrarypath -lmytest

上記のこの行は、自動生成ツールまたはpkg-configから生成できます。 (ただし、Makefileは自動設定ツールに依存しません)

CMake configure/tweek

通常、config.h関数を使用すると、auto-configツールと同様に、いくつかのconfigure_fileファイルを生成できます。カスタム関数を作成するより多くのトリックを行うことが可能です。最後に、次のような設定を選択できます。

cmake --build . --config "Release"

option関数を使用して、構成可能なオプションを追加することができます。

Makefile configure/Tweak

何らかのデバッグフラグを付けてコンパイルする必要がある場合は、makeのように呼び出すことができます。

make CXXFLAGS=NDEBUG

内部変数Makefile-rulesCMake-functionsは比較のための良い出発点であり、さらに掘り下げて幸運だと思います。

4
shuva