Try   HackMD

【軟體開發】CMake & Makefile

何謂 Makefile

在軟體開發中,make 是一個工具程式,藉由由讀取一個叫做 makefile 的檔案,自動化建構軟體。 make 是linux中的命令工具,它可以用來解析 Makefile 中的指令。 Makefile 則是一份用於管理和自動化編譯流程的配置文件,它明確指定計算機如何編譯、連結程式碼,並在大型專案中通過設計的規則顯著提升效率,減少不必要的編譯時間。

  • make 可以解決相依性問題
  • 透過撰寫規則,減少編譯時間,減少重複編譯過程,只需編譯有修改的
  • 可以透過 makefile 來掌握程式碼架構

image

Makefile Workflow

執行make時,會執行以下內容

  1. make後會去當前目錄尋找makefile或者GNUmakefile的檔案
  2. makefile的文件中找到第一個目標文件(target),作為最終得目標文件

Makefile Content

  1. 顯示規則
    表示如何生成一個或多個目標文件
  2. 隱式規則
    簡略地書寫Makefile的規則,規則中有.o的檔案會自動把.c也加入到依賴關係中
  3. 變數定義
    類似C語言的define,將變數置換到引用的位置上
  4. 文件指示
  5. 註釋與換行
    Makefile中只有行註釋,用#符號,換行則是/

Makefile Syntax

target: 目標檔1 目標檔2
<tab>gcc -o 目標執行檔案 目標檔1 目標檔2
  • 目標(Target)
    一個目標檔,可以是object檔案,也可以是執行檔,也可是一個標籤
  • 依賴(Dependecy, Prerequisites)
    要產生的目標檔中,所需要的相依性檔案
  • 命令(Command)
    建立專案時所需要的shell的指令
  • target與相依檔案(目標檔案)之間需要以:隔開
  • 行首必須要有<tab>,不能是空白
  • Makefile是由很多相依性項目(dependencies)和法則(rules)所組成
    • 相依性項目(dependencies):描述target,產生該檔案相關的原始碼檔案
    • 法則(rules): 則是說明如何根據相依性檔案,來建立目標檔
  • 相依性項目(dependency)
    ​​​​myapp: main.o 2.o 3.o
    ​​​​main.o: main.c a.h
    ​​​​2.o: 2.c a.h b.h
    ​​​​3.o: 3.c b.h c.h
    
    • myappmain.o2.o3.o相關
    • main.omain.ca.h相關,依此類推
  • 變數定義
    • =: 進行變數賦值動作,並以$(name)使用
    • :=: 會覆蓋之前變數的值
    • ?=: 如果變數有值的話pass,沒有則進行賦值
    • +=: 這個就是串接了
  • 萬用字元
    %為萬用字元的語法,代表所有可能的字串,例如%.c代表所以suffix為.c的子串
    ​​​​CC = gcc
    ​​​​OBJS = a.o b.o c.o
    
    ​​​​all: test
    
    ​​​​%.o: %.c
    ​​​​  $(CC) -c -o $@ $<
    
    ​​​​test: $(OBJS)
    ​​​​  $(CC) -o $@ $^
    
  • 自動化變數
    能夠化簡語法的一種方法,如果今天檔案有300多種,這樣寫太累了,就讓makefile自動推導
    • $@:表示目前的target
    • $^:代表目前相依性的項目的所有東西
    • $<:代表目前相依性的項目的第一個東西,gcc只能編譯.c,不能編譯.h
    • $?: TODO: 代補充

CMake

CMake 是一個跨平台的建構系統(Build System),用於軟體的建置、測試和包裝。CMake 會依照你撰寫的腳本產生平台上原生建置系統的設定檔(例如:Makefile),再使用原生建置系統編譯你的專案,CMake 的設計目標是簡化跨平台開發,讓開發者能夠以統一的方式生成不同作業系統上的建構檔案(如 Makefile、Visual Studio 專案檔案等)。

CMake Flow

建置流程

  1. 配置CMake快取(Configure Step)
  2. 產生原生建置系統的設定檔(Generate Step)
  3. 編譯並執行(Compile Step)

CMake 語法

CMake由命令式腳本語言組成,以命令組成,每個命令以括號內包裹參數

命令(參數1 參數2 ...)

指定最低版本

cmake_minimum_required(VERSION 3.10)
  • 定義運行 cmake 版本

專案名稱

project(ProjectName VERSION 1.0)
  • project()
    命令設定專案名稱,並可選指定版本號

添加可執行文件

add_executable(MyMain main.cpp)
  • add_executable()
    用於生成可執行文件

尋找外部套件

find_package(OpenGL REQUIRED)
target_link_libraries(MyMain PRIVATE OpenGL::GL)

產生 Compile Commands

產生一個名為 compile_commands.json 的檔案,裡面詳細記錄了每個 .cpp/.cu 檔案的實際編譯指令(包含 include path、定義、flags 等)

set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

Reference