1. 程式人生 > >Makefile和Cmake的聯絡與區別

Makefile和Cmake的聯絡與區別

CMake是一種跨平臺編譯工具,比make更為高階,使用起來要方便得多。CMake主要是編寫CMakeLists.txt檔案,然後用cmake命令將CMakeLists.txt檔案轉化為make所需要的makefile檔案,最後用make命令編譯原始碼生成可執行程式或共享庫(so(shared object)).它的作用和qt的qmake是相似的。

 

C/C++程式設計師肯定離不開Makefile和Cmake,因為如果對這兩個工具不熟悉,那麼你就不是一個合格的C/C++程式設計師。本文對Makefile和Cmake,及它們的使用進行了詳細的介紹,本文的目錄如下:

一、Makefile詳解

    1.1 Makefile語法
    1.2 Makefile示例

二、Cmake詳解

    2.1 Cmake語法
    2.2 Cmake示例

 

一、Makefile詳解

    Makefile描述了整個工程的編譯、連線等規則,makefile定義了一些列規則來指定,哪些檔案需要編譯以及如何編譯、需要建立哪些庫檔案以及如何建立這些庫檔案、如何產生我們想要的可執行檔案。使用Makefile,整個工程都可以完全自動化編譯。而且Makefile 可以有效的減少編譯和連線的程式,只編譯和連線那些修改的檔案。

1.1  Makefile語法

1.1.1
      Makefile包含了五個重要的東西:顯示規則、隱晦規則、變數定義、檔案指示和註釋。
          1. 顯示規則:顯示規則說明了,如何生成一個或多個目標。這是由Makefile指出要生成的檔案和檔案依賴的檔案。
          2. 隱晦規則:基於Makefile的自動推導功能
          3. 變數的定義:一般是字串
          4. 檔案指示:一般是在Makefile中引用另外一個makefile檔案;根據某些規則指定Makefile中有效的部分;多行
          5. 註釋:#指示註釋

      Makefile有三個非常重要的變數:[email protected]、$^、$#,它們的含義如下:
          [email protected]    ---目標檔案
          $^      ---所有依賴檔案
          $<      ---第一個依賴檔案
          .PHONY  ---偽目標檔案

      Makefile的執行過程如下:

          1. 在當前目錄下尋找Makefile或makefile。
          2. 找到第一個檔案中的第一個目標檔案,和目標檔案依賴的.o檔案。
          3. 如果.o檔案不存在,或是後面.o檔案比target檔案更新,那麼它就會執行後面的語句來生成這個檔案。
          4. 最後makefile會根據.o檔案依賴的.h和.c檔案生成.o檔案。

1.1.2

      注意:
           1. clean不要放在target前面。
           2. -rm edit  $(objects)  忽略某些檔案的問題。
           3. Makefile中的命令,必須以[Tab]鍵分割。檔案之間最好使用空格分割。
           4. -I 或 --include-dir 引數,那麼make就會在這些目錄下去尋找。
           5. -L 相當於load lib dir, -lfb303  相當於libfb303.so

1.1.3 g++編譯命令:
           1. -g  相當於debug
           2. -Wall 相當於忽略warnning
           3. -O1~3 相當於優化級別
           4. -lpthread多執行緒
           5. -j8 多執行緒編譯
           6. -D相當於巨集定義,-D_YUQIANG,那麼#ifdef _YUQIANG就是True的。

1.2  Makefile示例

 

[cpp] view plain copy

  1. CC = gcc  
  2. RM = rm  
  3.   
  4. CFLAGS += -D _YUQIANG  
  5. TARGETS := myapp  
  6. all:$(TARGETS)  
  7.   
  8. $(TARGETS):main.c  
  9. $(CC) $(CFLAGS) $^ -o [email protected]  
  10.   
  11. clean:  
  12. -$(RM) -f *.o  
  13. -$(RM) -f $(TARGETS)  


 

 

二、CMake詳解

   CMake是一個誇平臺的安裝(編譯)工具,可以簡單的語句描述所有平臺的安裝(編譯過程)。它能輸出各種各樣的makefile或者project檔案,能測試編譯器所支援的c++特性,類似UNIX下的automake。

2.1 Cmake語法

     1.  project name 

          PROJECT( project name )

     2. 標頭檔案路徑
          INCLUDE_DIRECTORIES( include )

     3. 設定環境變數的值
          SET( TEST_DIR ${DIR_SRCS})

     4. 設定外部庫
          SET(LIBRARIES libm.so)

     5. 設定可執行檔案路徑
          ADD_EXECUTABLE( ../bin/bin ${TEST_DIR})

     6. 設定連結庫
          TARGET_LINK_LIBRARIES(../bin/bin ${LIBRARIES})

     7. 設定程式碼子目錄
         ADD_SUBDIRECTORY

2.2 CMake示例

 

[cpp] view plain copy

  1. #project name  
  2. PROJECT(test_math)  
  3. #head file path  
  4. INCLUDE_DIRECTORIES(  
  5. include  
  6. )  
  7. #source directory  
  8. AUX_SOURCE_DIRECTORY(src DIR_SRCS)  
  9. #set environment variable  
  10. SET(TEST_MATH  
  11. ${DIR_SRCS}  
  12. )  
  13. #set extern libraries  
  14. SET(LIBRARIES  
  15. libm.so  
  16. )  
  17. #add executable file  
  18. ADD_EXECUTABLE(../bin/bin ${TEST_MATH})  
  19. #add link library  
  20. TARGET_LINK_LIBRARIES(../bin/bin ${LIBRARIES}  

 

1.CMake編譯原理

CMake是一種跨平臺編譯工具,比make更為高階,使用起來要方便得多。CMake主要是編寫CMakeLists.txt檔案,然後用cmake命令將CMakeLists.txt檔案轉化為make所需要的makefile檔案,最後用make命令編譯原始碼生成可執行程式或共享庫(so(shared object))。因此CMake的編譯基本就兩個步驟:

1. cmake   
  指向CMakeLists.txt所在的目錄,例如cmake .. 表示CMakeLists.txt在當前目錄的上一級目錄。cmake後會生成很多編譯的中間檔案以及makefile檔案,所以一般建議新建一個新的目錄,專門用來編譯,
mkdir
 build
cd build
cmake ..

make

2. make
根據生成makefile檔案,編譯程式。

2.使用Cmake編譯程式

我們編寫一個關於開平方的C/C++程式專案,即b= sqrt(a),以此理解整個CMake編譯的過程。

a.準備程式檔案

檔案目錄結構如下:

.
├── build
├── CMakeLists.txt
├── include
│   └── b.h
└── src
    ├── b.c
    └── main.c

b.編寫CMakeLists.txt

接下來編寫CMakeLists.txt檔案,該檔案放在和src,include的同級目錄,實際方哪裡都可以,只要裡面編寫的路徑能夠正確指向就好了。CMakeLists.txt檔案,如下所示:

 1
 #1
.cmake verson,指定cmake版本 

 2
 cmake_minimum_required(VERSION 3.2
)

 3
 
 4
 #2
.project name,指定專案的名稱,一般和專案的資料夾名稱對應

 5
 PROJECT(test_sqrt)

 6
 
 7
 #3
.head
 file
 path,標頭檔案目錄

 8
 INCLUDE_DIRECTORIES(

 9
 include

10
 )

11
 
12
 #4
.source directory,原始檔目錄

13
 AUX_SOURCE_DIRECTORY(src DIR_SRCS)

14
 
15
 #5
.set environment variable,設定環境變數,編譯用到的原始檔全部都要放到這裡,否則編譯能夠通過,但是執行的時候會出現各種問題,比如"
symbol lookup error xxxxx , undefined symbol
"

16
 SET(TEST_MATH

17
 ${DIR_SRCS}

18
 )

19
 
20
 #6
.add executable file
,新增要編譯的可執行檔案

21
 ADD_EXECUTABLE(${PROJECT_NAME} ${TEST_MATH})

22
 
23
 #7
.add link library,新增可執行檔案所需要的庫,比如我們用到了libm.so(命名規則:lib+name+.so),就新增該庫的名稱

24
 TARGET_LINK_LIBRARIES(${PROJECT_NAME} m)

 CMakeLists.txt主要包含以上的7個步驟,具體的意義,請閱讀相應的註釋。

c.編譯和執行程式

準備好了以上的所有材料,接下來,就可以編譯了,由於編譯中出現許多中間的檔案,因此最好新建一個獨立的目錄build,在該目錄下進行編譯,編譯步驟如下所示:

mkdir
 build
cd build
cmake ..

make

操作後,在build下生成的目錄結構如下:

├── build
│   ├── CMakeCache.txt
│   ├── CMakeFiles
│   │   ├── 
3.2
.2

│   │   │   ├── CMakeCCompiler.cmake
│   │   │   ├── CMakeCXXCompiler.cmake
│   │   │   ├── CMakeDetermineCompilerABI_C.bin
│   │   │   ├── CMakeDetermineCompilerABI_CXX.bin
│   │   │   ├── CMakeSystem.cmake
│   │   │   ├── CompilerIdC
│   │   │   │   ├── a.out
│   │   │   │   └── CMakeCCompilerId.c
│   │   │   └── CompilerIdCXX
│   │   │       ├── a.out
│   │   │       └── CMakeCXXCompilerId.
cpp

│   │   ├── cmake.check_cache
│   │   ├── CMakeDirectoryInformation.cmake
│   │   ├── CMakeOutput.log
│   │   ├── CMakeTmp
│   │   ├── feature_tests.bin
│   │   ├── feature_tests.c
│   │   ├── feature_tests.cxx
│   │   ├── Makefile2
│   │   ├── Makefile.cmake
│   │   ├── progress.marks
│   │   ├── TargetDirectories.txt
│   │   └── test_sqrt.
dir

│   │       ├── build.
make

│   │       ├── C.includecache
│   │       ├── cmake_clean.cmake
│   │       ├── DependInfo.cmake
│   │       ├── depend.internal
│   │       ├── depend.
make

│   │       ├── flags.
make

│   │       ├── link.txt
│   │       ├── progress.
make

│   │       └── src
│   │           ├── b.c.o
│   │           └── main.c.o
│   ├── cmake_install.cmake
│   ├── Makefile
│   └── test_sqrt
├── CMakeLists.txt
├── include
│   └── b.h
└── src
    ├── b.c
    └── main.c

注意在build的目錄下生成了一個可執行的檔案test_sqrt,執行獲取結果如下:

命令:
./test_sqrt 
結果:
input a:
49.000000

sqrt result:
7.000000

 

參考文獻:
1.  Linux  Makefile教程: http://blog.csdn.net/liang13664759/article/details/1771246
2. CMake 學習二: http://blog.sina.com.cn/s/blog_53b7ddf00101mjp5.html
3. CMake基本用法: http://blog.sina.com.cn/s/blog_68409a2801019bm7.html

 

 

1.gcc是GNU Compiler Collection(就是GNU編譯器套件),也可以簡單認為是編譯器,它可以編譯很多種程式語言(括C、C++、Objective-C、Fortran、Java等等)。

2.當你的程式只有一個原始檔時,直接就可以用gcc命令編譯它。

3.但是當你的程式包含很多個原始檔時,用gcc命令逐個去編譯時,你就很容易混亂而且工作量大

4.所以出現了make工具
make工具可以看成是一個智慧的批處理工具,它本身並沒有編譯和連結的功能,而是用類似於批處理的方式—通過呼叫makefile檔案中使用者指定的命令來進行編譯和連結的。

5.makefile是什麼?簡單的說就像一首歌的樂譜,make工具就像指揮家,指揮家根據樂譜指揮整個樂團怎麼樣演奏,make工具就根據makefile中的命令進行編譯和連結的。

6.makefile命令中就包含了呼叫gcc(也可以是別的編譯器)去編譯某個原始檔的命令。

7.makefile在一些簡單的工程完全可以人工手下,但是當工程非常大的時候,手寫makefile也是非常麻煩的,如果換了個平臺makefile又要重新修改。

8.這時候就出現了Cmake這個工具,cmake就可以更加簡單的生成makefile檔案給上面那個make用。當然cmake還有其他功能,就是可以跨平臺生成對應平臺能用的makefile,你不用再自己去修改了。

9.可是cmake根據什麼生成makefile呢?它又要根據一個叫CMakeLists.txt檔案(學名:組態檔)去生成makefile。

10.到最後CMakeLists.txt檔案誰寫啊?親,是你自己手寫的。

11.當然如果你用IDE,類似VS這些一般它都能幫你弄好了,你只需要按一下那個三角形

12.cmake是make maker,生成各種可以直接控制編譯過程的控制器的配置檔案,比如makefile、各種IDE的配置檔案。
13.make是一個簡單的通過檔案時間戳控制自動過程、處理依賴關係的軟體,這個自動過程可以是編譯一個專案。