Cmake vs makeサンプルコード?


117

いずれのサンプルのコードがあった場合、私は思っていたMakefileS( make)とは、CMakeLists.txtcmake)の両方が(唯一の違いは、1がで書かれているということで同じことを行うことmakeや、他の中cmake)。

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


20
+1これは良い質問です。私が始めていたとき、cmakeこれも欲しかった。しかし、私はあなたがそれを見つけることができないと思います。あなたがのようにcmake振る舞おうとするとmake、あなたは真剣に自分を狂わせるでしょう。ゼロから始めるのが一番です。ささいなことはmakeにかなり関与してcmakeおり、その逆も同様です。
アーネストフリードマンヒル

1
@ ErnestFriedman-Hill、詳細はありますか?それでmakecmakeそれらは非常に異なっているため、競合するツールではなく、補完的なツールと見なす必要があります。
Ehtesh Choudhury 2013

2
@Shurane-cmake自体は何もビルドしません。Makefile(およびその他の同様のビルドスクリプト)を作成し、それを実行します。したがって、cmakeファイルを書き込むときは常に、生成時にコマンドを適用するか、ビルド時にコマンドを適用するかを検討する必要があります。ビルド時にワイルドカードファイルセットをコピーするなどの一部のアクションcp *.x $(OUTDIR)は、Makefileに書き込む" "に比べて非常に複雑です。おそらく、私にとって最も不愉快な部分は、生成されたMakefileが完全に移植性がなく柔軟性に欠けるということです(続き)
Ernest Friedman-Hill

1
(続き)cmakeを再実行してMakefileを再生成しないと、同じマシン上でソースディレクトリを移動することさえできません。したがって、選択はcmakeとmakeの間ではなく、移植可能なMakefileを自分で作成するか、またはcmakeを使用して各ビルドマシンで移植性のないMakefileを生成することです(WindowsでCygwinまたはmingwを使用できることを考えると、前者の方が一般的に簡単です。 )
アーネストフリードマンヒル

1
良い質問ですが、どちらのツールも異なる問題を解決しようとするため、具体的な答えはありません。cmakeは、プログラムのビルド方法に関する情報を取得して、プログラムをビルドするメイクファイルを生成します。したがって、cmakeは抽象的なビルドルールを備えた言語であり、gnu makeは有向非巡回グラフトラバーサルでプログラムを実行する依存関係解決です。
Alex

回答:


118

次のMakefileはprog、ソースから指定された実行可能ファイルをビルドします prog1.c, prog2.c, prog3.c and main.cprogリンクされているlibmystatlib.alibmydynlib.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 $@ 

ここでCMakeLists.txtのMakefileとの類似性を強調するためにいくつかのコメントで、(ほぼ)正確に同じことをその:

#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は、(POSITION_INDEPENDENT_CODEプロパティを介して)'-fPIC'フラグやその他多くのプラットフォームに依存しない組み込みも提供します。それでも、CMakeだけでなく、Makefileでも手動で(COMPILE_FLAGS および同様のプロパティを使用して)よりあいまいな設定を実装できます。もちろん、サードパーティのライブラリ(OpenGLなど)が移植可能な方法で含まれている場合、CMakeは本当に輝き始めます。

  • Makefileを使用する場合、つまり makeコマンドラインで入力する場合、ビルドプロセスには1つのステップがあります。CMakeの場合、2つのステップがあります。最初に、ビルド環境をセットアップする必要があります(cmake <source_dir>ビルドディレクトリに入力するか、GUIクライアントを実行して)。これにより、選択したビルドシステムに応じて、Makefileまたは同等のものが作成されます(たとえば、UnixまたはVC ++ではmake、WindowsではMinGW + Msys)。ビルドシステムをパラメーターとしてCMakeに渡すことができます。ただし、CMakeはシステム構成に応じて適切なデフォルトの選択を行います。次に、選択したビルドシステムで実際のビルドを実行します。

ソースおよびビルド手順は、https://github.com/rhoelzel/make_cmakeで入手できます


3
Makefileは過度に複雑ではありませんか?CPPFLAGS代わりにを使用することによりINCDIR、組み込みのルールを使用することができ、コンパイラの明示的な呼び出しは冗長になります。同様に、arの処理についても、組み込みのルールでそれをカバーできます。また、なぜ明示的に設定CPPCCますか?これらはmake、によって既に適切な値に設定されており、事前定義された変数です。makeまた、どの種類のソースにどのコンパイラを使用するかを認識するため、組み込みのルールは多数あります。
Christian Hujer、2015

1
そして、これらの変数の多くはでは:=なくで割り当てられるべきです=
Christian Hujer、2015

1
説明を見ると、cmakeより匹敵するautomakeよりもmake
ivan_pozdeev

提供されるMakefileは、3/4行に減らすことができます。のINCLUDES代わりに指定する必要がありますINCDIR。%.o:%。cルールは必要ありません。
shuva 2018年

6

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

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


4

この質問がファイルのサンプルMakefile出力に関するものである場合はCMakeList.txt、cmake-backendソースを確認して、そのようなものを1つ生成してください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})

ビルドをCMake隠すhowことができることに注意してください。what入力と出力のみを指定しました。

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

(CMake関数)Vs Makeルール

では代わりに使用されています。のような機能に加えて、チェーンを提供します。私のミニマリズムは次のようになります、Makefilerules and recipesfunctionsfunctionrules and recipesMakefile

-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

ここからこのスニペットを取得して変更しました。makefile-documentationにあるこのファイルに暗黙のルールがいくつか追加されていることに注意してください。いくつかの暗黙的な変数もここで関連しています。

これMakefileは、ビルドが実行できることrecipeを示す詳細を提供することに注意してくださいhowexecutable.mk詳細を1つのファイルに定義して保持するように書き込むことができます。このようにして、前に示したようにmakefileを削減できます。

CMakeおよびの内部変数Make

少し進んでCMake、次のようなコンパイラフラグを設定できます。

set(CMAKE_C_FLAGS "-Wall")

ファイル内のCMakeデフォルト変数の詳細を確認してくださいCMakeCache.txtCMake上記のコードは、と等価となりMake、次のコード

CFLAGS = -Wall

はのCFLAGS内部変数であることに注意してください。Make同様に、CMAKE_C_FLAGSは内部変数ですCMake

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

上記のこの行は、auto-genツールまたはpkg-configから生成できることに注意してください。(Makefileはauto-configツールに依存していません)

CMake構成/週

通常、関数を使用してconfig.hauto-configツールと同じようにファイルを生成できconfigure_fileます。カスタム関数を書くより多くのトリックを行うことが可能です。最後に、次のような構成を選択できます。

cmake --build . --config "Release"

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

Makefile構成/調整

なんらかのデバッグフラグでコンパイルする必要がある場合は、makelike を呼び出すことができます。

make CXXFLAGS=NDEBUG

私は内部変数を考えて、Makefile-rulesそしてCMake-functionsより多くの掘削と比較して、幸運のための良いスタートです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.