MacOS 迅速上手 Makefile 編譯 C / C++ 工程

前言

本文以實用爲第一目標,將給出一個 MacOSMacOS 編譯 C/CC/C++ 工程的固定模板,以便讀者可以迅速上手!

文章主要如下分爲三部分:

  1. 爲什麼需要 MakefileMakefile
  2. 如何編寫 MakefileMakefile
  3. MacOSMacOS 下編譯 C/CC/C++ 工程的固定模板

如果覺得文章對你有幫助,請點個贊再走!(•̀ᴗ•́)و ̑̑


爲什麼需要 MakefileMakefile

MakefileMakefile 的出現主要是由於在大型的 C/CC/C++ 工程中,經常會出現文件相互依賴的情況。舉個例子,AA 文件調用了 BB 文件中的 類 / 函數,因此我們需要將 A,BA,B 文件統一鏈接在一起形成最終的可執行文件。

正是由於上述情況的存在,使得我們必須將工程中所有文件鏈接在一起,而手工一條一條命令敲又非常費時,因此我們需要 MakefileMakefile,在我們給定編譯順序後自動幫助我們完成編譯。

我們將以下面的三份代碼爲例來介紹在 MacOSMacOS 下使用 MakefileMakefile 的方法。

  • A.cppA.cpp
#include <iostream>
#include "B.h"
using namespace std;

int main() {
    cout << add(1, 2) << endl;
    return 0;
}
  • B.hB.h
#ifndef B_H
#define B_H
    int add(int a, int b);
#endif
  • B.cppB.cpp
#include <iostream>
#include "B.h"

int add(int a, int b) {
    return a + b;
}

由此不難發現,想要讓 A.cppA.cpp 文件能夠正確執行,我們需要將這三個文件統一鏈接在一起!如果一條一條命令輸的話,我們需要依次執行下述命令。

g++ -c A.c
g++ -c B.c
g++ -o main A.o B.o

顯然一條一條命令輸非常麻煩,因此我們需要 MakefileMakefile 來簡化這個過程!


如何編寫 MakefileMakefile

我們以上述的例子爲例,簡要介紹我們的固定模板!

  • 文件結構
    • 兩個大文件夾:buildbuildsrcsrc
    • build:build: 分爲兩個小文件夾,binbinobjectsobjects
      • bin:bin: 放最終的可執行文件
      • objects:objects:srcsrc 中的文件所生成的 .o.o 文件
    • src:src: 工程文件
    • 最外層:MakefileMakefilemainmain(最終可執行文件的鏈接文件)
      在這裏插入圖片描述
  • MakefileMakefile 語法規則
    • $@: 目標文件
    • $^: 所有依賴文件
    • $< 第一個依賴文件
    • 編譯語法規則
      • targets: 文件名,以空格分開,可以使用通配符
      • command: 命令行,如果其不與 targets:prerequisites\text{targets:prerequisites} 在一行,則必須以 TabTab 鍵卡頭,如果和 targets:prerequisites\text{targets:prerequisites} 在一行,則可以用分號作爲分隔
      • prerequisites: 目標所依賴的文件,如果其中某個文件要比目標文件要新,則目標就被認爲是 “過時的”,被認爲是需要重新生成的
      • ref:ref: 《跟我一起寫 Makefile\text{Makefile}
targets: prerequisites
	command
  • 定義變量
    • 文件路徑
    • 編譯命令參數
    • 最終目標文件
dest_dir = build
src_dir = src
obj_dir = $(dest_dir)/objects
bin_dir = $(dest_dir)/bin

CC = g++
RESULT = main
CFLAGS = -Wall -O3 -std=c++14
CFILES = A.cpp B.cpp
ofiles = $(CFILES:%.cpp=$(obj_dir)/%.o)

program = $(bin_dir)/$(RESULT)
$(program): $(ofiles)
  • 產生 .o.o 文件
    • 第一句:輸出編譯信息
    • 第二句:如果不存在路徑上的文件夾,則創建文件夾
    • 第三句:執行 g++ -c xxx.c 命令
# src 中所有 cpp 文件
$(obj_dir)/%.o: $(src_dir)/%.cpp
	@echo ">>> Compiling" $< "<<<"
	@if [ ! -d $(obj_dir) ]; then mkdir -p $(obj_dir); fi;
	$(CC) $(CFLAGS) -c $< -o $@

# src 所有子文件夾中 cpp 文件
$(obj_dir)/%.o: $(src_dir)/*/%.cpp
	@echo ">>> Compiling" $< "<<<"
	@if [ ! -d $(obj_dir) ]; then mkdir -p $(obj_dir); fi;
	$(CC) $(CFLAGS) -c $< -o $@
  • 將所有 .o.o 文件鏈接在一起生成可執行文件,並在最外層生成可執行文件的鏈接文件
    • 第一句:輸出編譯信息
    • 第二句:如果不存在路徑上的文件夾,則創建文件夾
    • 第三句:執行 g++ -o 目標可執行文件 xxx1.o xxx2.o ... 命令
    • 第四句:將目標可執行文件鏈接到最外層
$(bin_dir)/%:
	@echo ">>> Linking" $@ "<<<"
	@if [ ! -d $(bin_dir) ]; then mkdir -p $(bin_dir); fi;
	$(CC) -o $@ $^
	ln -sf $@ $(notdir $@)
  • makemake cleanclean 命令
    • 當我們需要重新編譯時,我們想要快速地刪除上一次編譯所產生的文件
    • 我們可以自定義 makemake cleanclean 命令,實現對上一次編譯生成文件的快速清理
.PHONY: clean
clean:
	rm -rf $(dest_dir)
	rm -f $(RESULT)

MacOSMacOS 下編譯 C/CC/C++ 工程的固定模板

至此,我們實現了一個簡易的編譯 C/CC/C++ 工程的 MakefileMakefile 的固定模板。

每次需要編譯,則先執行 makemake cleanclean,再執行 makemake

CC 工程: gccgccCC++ 工程: gg++

增加需要編譯的文件: 在 CFILES\text{CFILES} 變量後面繼續添加即可

# $@: 目標文件, $^: 所有依賴文件, $<: 第一個依賴文件
# 語法規則:
# 	targets: prerequisites
# 		command
dest_dir = build
src_dir = src
obj_dir = $(dest_dir)/objects
bin_dir = $(dest_dir)/bin

CC = g++
RESULT = main
CFLAGS = -Wall -O3 -std=c++14
CFILES = A.cpp B.cpp
ofiles = $(CFILES:%.cpp=$(obj_dir)/%.o)

program = $(bin_dir)/$(RESULT)
$(program): $(ofiles)

$(bin_dir)/%:
	@echo ">>> Linking" $@ "<<<"
	@if [ ! -d $(bin_dir) ]; then mkdir -p $(bin_dir); fi;
	$(CC) -o $@ $^
	ln -sf $@ $(notdir $@)

$(obj_dir)/%.o: $(src_dir)/%.cpp
	@echo ">>> Compiling" $< "<<<"
	@if [ ! -d $(obj_dir) ]; then mkdir -p $(obj_dir); fi;
	$(CC) $(CFLAGS) -c $< -o $@

$(obj_dir)/%.o: $(src_dir)/*/%.cpp
	@echo ">>> Compiling" $< "<<<"
	@if [ ! -d $(obj_dir) ]; then mkdir -p $(obj_dir); fi;
	$(CC) $(CFLAGS) -c $< -o $@

.PHONY: clean
clean:
	rm -rf $(dest_dir)
	rm -f $(RESULT)

後記

本文的主要目標就是幫助讀者快速迅速上手 MacOSMacOSC/CC/C++ 工程的 MakefileMakefile 文件編寫,因此並沒有太多涉及 MakefileMakefile 的高階用法,有興趣的朋友可以仔細研讀陳皓所寫的《跟我一起寫 Makefile\text{Makefile}》!

技術水平的不斷提高在於不斷實踐,不斷記錄,持續精進!💪💪💪

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章