Cmake是什么
- cmake是一種自動生成makefile規則的工具,它有一套自己的語法規則來指導生成整個項目源碼的編譯框架。或者你可以把cmake理解成是一種抽象工具,提供了一些封裝好的API接口來給使用者搭建自己需要的編譯框架,它封裝細節,封裝復雜度,指定輸入自動輸出。
Cmake有什么優勢
- 效率優勢,如果你手動編寫makefile和用cmake編寫指導makefile生成,就像匯編之與C語言。
- 學習成本,相對其他自動生成makefile工具(比如Autotools)cmake語法和編譯規則很簡單,核心的內置命令不超過10個,常用的內置命令也不超過20個(強調命令,是因為cmake源文件中所有有效的語句都是命令)。
- 使用廣泛,提到cmake總要帶一下kde,因為kde使cmake名聲大噪,能作為kde這樣的大型軟件項目的編譯構建工具,cmake已經無需在向其他人證明什么,所以用的人比較多,cmake開發團隊維護也比較積極,很多問題在官網的文檔,wiki,郵件列表等等都可以找到答案,同時網絡上也有很多高質量的文章,教程,模板等,在一些開發社區比如stackoverflow上也有一些比較優質的討論,所以使用cmake你注定不會孤獨,不會有局限性,有一大堆優秀的人幫你一起進步:)
- 其他優勢,開源免費,跨平臺(微軟,蘋果,linux都可以使用),速度快。
我為什么要用cmake
- 一句話,提高開發效率,降低開發維護成本。
- 因為項目組用到比較多的開源模塊,而且還會繼續增加相關開源模塊,項目組核心源碼的編譯框架以makefile編寫,所有之前或者后續加進來的模塊既要適配現有的makefile框架,又要根據加進來模塊的makefile規則進行調整和和修改。這樣不僅修改和調整費時又費力,原來的編譯框架沒有為其他模塊的引入預留接口,導致越改越亂,難以維護,在加之makefile一些規則很生澀。
- 我厭倦了每次修改調整都要去溫習一下makefile的一些句法規則。
- 我也不想讓項目組的每個成員都成為makefile編譯專家(makefile學習成本比較高,沒有經常用又容易忘掉)
- 我想用一些比較簡單和易讀的工具來重新構建整個編譯框架,讓后續的維護更簡單,開發只專注業務價值開發,而不用被編譯系統所分心。
一個對比例子
我要把下面的源文件編譯成一個庫
├── include
│ ├── ap.h
│ ├── arena.h
│ ├── arith.h
│ ├── array.h
│ ├── arrayrep.h
│ ├── assert.h
│ ├── atom.h
│ ├── bit.h
│ ├── chan.h
│ ├── except.h
│ ├── fmt.h
│ ├── list.h
│ ├── mem.h
│ ├── mp.h
│ ├── ring.h
│ ├── sem.h
│ ├── seq.h
│ ├── set.h
│ ├── stack.h
│ ├── str.h
│ ├── table.h
│ ├── text.h
│ ├── thread.h
│ └── xp.h
├── LICENSE
├── makefile
└── src
├── ap.c
├── arena.c
├── arith.c
├── array.c
├── assert.c
├── atom.c
├── bit.c
├── chan.c
├── except.c
├── fmt.c
├── libcii.def
├── list.c
├── mem.c
├── memchk.c
├── memcmp.c
├── memmove.c
├── mp.c
├── ring.c
├── seq.c
├── set.c
├── stack.c
├── str.c
├── strncmp.c
├── swtch.s
├── table.c
├── text.c
└── xp.c
原來手寫的makefile編譯規則如下
# $Id: makefile 207 2008-09-30 04:43:42Z drhanson $
A=.a
O=.o
E=
CC=cc
I=include
CFLAGS=-g -I$I
LDFLAGS=-g
LD=cc
AS=as
AR=ar ruv
RANLIB=ranlib
DIFF=diff
RM=rm -f
CUSTOM=custom.mk
EXTRAS=$(BUILDDIR)memcmp$O $(BUILDDIR)memmove$O $(BUILDDIR)strncmp$O
THREADS=$(BUILDDIR)thread$O $(BUILDDIR)swtch$O
include $(CUSTOM)
B=$(BUILDDIR)
OBJS= $Bap$O \
$Barena$O \
$Barith$O \
$Barray$O \
$Bassert$O \
$Batom$O \
$Bbit$O \
$Bchan$O \
$Bexcept$O \
$Bfmt$O \
$Blist$O \
$Bmem$O \
$Bmp$O \
$Bring$O \
$Bseq$O \
$Bset$O \
$Bstack$O \
$Bstr$O \
$Btable$O \
$Btext$O \
$Bxp$O \
all:: $Blibcii$A
$Blibcii$A:: $(OBJS) $(EXTRAS)
$(AR) $@ $(OBJS) $(EXTRAS); $(RANLIB) $@ || true
$Bap$O: src/ap.c; $(CC) $(CFLAGS) -c -o $@ src/ap.c
$Barena$O: src/arena.c; $(CC) $(CFLAGS) -c -o $@ src/arena.c
$Barith$O: src/arith.c; $(CC) $(CFLAGS) -c -o $@ src/arith.c
$Barray$O: src/array.c; $(CC) $(CFLAGS) -c -o $@ src/array.c
$Bassert$O: src/assert.c; $(CC) $(CFLAGS) -c -o $@ src/assert.c
$Batom$O: src/atom.c; $(CC) $(CFLAGS) -c -o $@ src/atom.c
$Bbit$O: src/bit.c; $(CC) $(CFLAGS) -c -o $@ src/bit.c
$Bchan$O: src/chan.c; $(CC) $(CFLAGS) -c -o $@ src/chan.c
$Bexcept$O: src/except.c; $(CC) $(CFLAGS) -c -o $@ src/except.c
$Bfmt$O: src/fmt.c; $(CC) $(CFLAGS) -c -o $@ src/fmt.c
$Blist$O: src/list.c; $(CC) $(CFLAGS) -c -o $@ src/list.c
$Bmem$O: src/mem.c; $(CC) $(CFLAGS) -c -o $@ src/mem.c
$Bmemchk$O: src/memchk.c; $(CC) $(CFLAGS) -c -o $@ src/memchk.c
$Bmp$O: src/mp.c; $(CC) $(CFLAGS) -c -o $@ src/mp.c
$Bring$O: src/ring.c; $(CC) $(CFLAGS) -c -o $@ src/ring.c
$Bseq$O: src/seq.c; $(CC) $(CFLAGS) -c -o $@ src/seq.c
$Bset$O: src/set.c; $(CC) $(CFLAGS) -c -o $@ src/set.c
$Bstack$O: src/stack.c; $(CC) $(CFLAGS) -c -o $@ src/stack.c
$Bstr$O: src/str.c; $(CC) $(CFLAGS) -c -o $@ src/str.c
$Btable$O: src/table.c; $(CC) $(CFLAGS) -c -o $@ src/table.c
$Btext$O: src/text.c; $(CC) $(CFLAGS) -c -o $@ src/text.c
$Bthread$O: src/thread.c; $(CC) $(CFLAGS) -c -o $@ src/thread.c
$Bthread-nt$O: src/thread-nt.c;$(CC) $(CFLAGS) -c -o $@ src/thread-nt.c
$Bxp$O: src/xp.c; $(CC) $(CFLAGS) -c -o $@ src/xp.c
$Bswtch$O: src/swtch.s; $(AS) -o $@ src/swtch.s
$Bmemcmp$O: src/memcmp.c; $(CC) $(CFLAGS) -c -o $@ src/memcmp.c
$Bmemmove$O: src/memmove.c; $(CC) $(CFLAGS) -c -o $@ src/memmove.c
$Bstrncmp$O: src/strncmp.c; $(CC) $(CFLAGS) -c -o $@ src/strncmp.c
$Bdouble$E: $Bdouble$O $Blibcii$A; $(LD) $(LDFLAGS) -o $@ $Bdouble$O $Blibcii$A
$Bcalc$E: $Bcalc$O $Blibcii$A; $(LD) $(LDFLAGS) -o $@ $Bcalc$O $Blibcii$A
$Bids$E: $Bids$O $Blibcii$A; $(LD) $(LDFLAGS) -o $@ $Bids$O $Blibcii$A
$Bmpcalc$E: $Bmpcalc$O $Blibcii$A; $(LD) $(LDFLAGS) -o $@ $Bmpcalc$O $Blibcii$A
$Biref$E: $Biref$O $Blibcii$A; $(LD) $(LDFLAGS) -o $@ $Biref$O $Blibcii$A
$Bkref$E: $Bkref$O $Blibcii$A; $(LD) $(LDFLAGS) -o $@ $Bkref$O $Blibcii$A
$Bidents$E: $Bidents$O $Blibcii$A; $(LD) $(LDFLAGS) -o $@ $Bidents$O $Blibcii$A
$Bwords$E: $Bwords$O $Blibcii$A; $(LD) $(LDFLAGS) -o $@ $Bwords$O $Blibcii$A
$Bbasename$E: $Bbasename$O $Blibcii$A; $(LD) $(LDFLAGS) -o $@ $Bbasename$O $Blibcii$A
$Bdirname$E: $Bbasename$O $Blibcii$A; $(LD) $(LDFLAGS) -o $@ $Bbasename$O $Blibcii$A
$Bwf$E: $Bwf$O $Bgetword$O $Blibcii$A; $(LD) $(LDFLAGS) -o $@ $Bwf$O $Bgetword$O $Blibcii$A
$Bxref$E: $Bxref$O $Bgetword$O $Blibcii$A;$(LD) $(LDFLAGS) -o $@ $Bxref$O $Bgetword$O $Blibcii$A
$Bcref$E: $Bcref$O $Binteger$O $Blibcii$A;$(LD) $(LDFLAGS) -o $@ $Bcref$O $Binteger$O $Blibcii$A
$Bsort$E: $Bsort$O $Blibcii$A; $(LD) $(LDFLAGS) -o $@ $Bsort$O $Blibcii$A
$Bspin$E: $Bspin$O $Blibcii$A; $(LD) $(LDFLAGS) -o $@ $Bspin$O $Blibcii$A
$Bsieve$E: $Bsieve$O $Blibcii$A; $(LD) $(LDFLAGS) -o $@ $Bsieve$O $Blibcii$A
maxalign: $Bmaxalign$E
$Bmaxalign$E
$Bmaxalign$E: misc/maxalign.c
$(CC) -o $@ misc/maxalign.c
clean::
$(RM) $B*$O
$(RM) $(EXAMPLES)
clobber:: clean
$(RM) $Blibcii$A
# DO NOT DELETE THIS LINE -- make depend depends on it.
$Bap$O: $I/assert.h $I/except.h $I/ap.h $I/fmt.h $I/xp.h $I/mem.h
$Barena$O: $I/assert.h $I/except.h $I/arena.h
$Barith$O: $I/arith.h
$Barray$O: $I/assert.h $I/except.h $I/array.h $I/arrayrep.h $I/mem.h
$Bassert$O: $I/assert.h $I/except.h
$Batom$O: $I/atom.h $I/assert.h $I/except.h $I/mem.h
$Bbit$O: $I/assert.h $I/except.h $I/bit.h $I/mem.h
$Bchan$O: $I/assert.h $I/except.h $I/mem.h $I/chan.h $I/sem.h
$Bexcept$O: $I/assert.h $I/except.h
$Bfmt$O: $I/assert.h $I/except.h $I/fmt.h $I/mem.h
$Blist$O: $I/assert.h $I/except.h $I/mem.h $I/list.h
$Bmem$O: $I/assert.h $I/except.h $I/mem.h
$Bmemchk$O: $I/assert.h $I/except.h $I/mem.h
$Bmp$O: $I/assert.h $I/except.h $I/fmt.h $I/mem.h $I/xp.h $I/mp.h
$Bring$O: $I/assert.h $I/except.h $I/ring.h $I/mem.h
$Bseq$O: $I/assert.h $I/except.h $I/seq.h $I/array.h $I/arrayrep.h $I/mem.h
$Bset$O: $I/mem.h $I/except.h $I/assert.h $I/arith.h $I/set.h
$Bstack$O: $I/assert.h $I/except.h $I/mem.h $I/stack.h
$Bstr$O: $I/assert.h $I/except.h $I/fmt.h $I/str.h $I/mem.h
$Btable$O: $I/mem.h $I/except.h $I/assert.h $I/table.h
$Btext$O: $I/assert.h $I/except.h $I/fmt.h $I/text.h $I/mem.h
$Bthread$O: $I/assert.h $I/except.h $I/mem.h $I/thread.h $I/sem.h
$Bthread-nt$O: $I/assert.h $I/except.h $I/mem.h $I/thread.h $I/sem.h
$Bxp$O: $I/assert.h $I/except.h $I/xp.h
我用cmake重寫了一下,關鍵代碼就三行
cmake_minimum_required(VERSION 3.1.0)
project(main)
#編譯規則指定
aux_source_directory(./src DIR_SRCS)
add_library(main ${DIR_SRCS})
target_include_directories(main PRIVATE ./include)
cmake在編寫的效率和簡潔程度上可以說是暴擊makefile