[原創] Cmake初體驗

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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。