簡介
Make 是一個用於構建其他程式或文件的程式。Make 適用於任何具有可能完成或未完成的中間步驟的過程。
Make 不會重新構建已更新的專案。此外,它知道如何構建中間目標。您可以使用 Make 檔案來指示 Make。
Make 程式不止一個。C/C++ 開發人員最常遇到的是 GNU Make。我將首先用示例描述 GNU Make,然後介紹 BSD Make,最後對它們之間的區別進行一些評論。
GNU Make 入門
GNU Make 內建了許多規則。它們被稱為內建規則。讓我們看一個示例,hello.c
1 2 3 4 5 6 7
|
#include <stdio.h>
int main()
{
printf("hello world\n:");
return 0;
}
|
要構建程式,只需鍵入
它會執行
因此,GNU Make 已知道可以從 .c 檔案構建程式,並且知道如何編譯和連結它。
讓我們再試一個,這次包含更多檔案。這次我們需要一個 makefile。GNU Make 檔案可以命名為 GNUmakefile、Makefile 或 makefile。在這些示例中我將使用 GNUmakefile,因為稍後我們將介紹 BSD Make。
calc.c
1 2 3 4 5 6 7 8
|
#include <stdio.h>
#include "engine.h"
int main()
{
printf("%d\n", calc("2+3"));
return 0;
}
|
engine.h
1 2 3
|
#pragma once
int calc(const char* expression);
|
engine.c
1 2 3 4 5 6
|
#include "engine.h"
int calc(const char *expression)
{
return 5;
}
|
GNUmakefile
1 2 3 4 5
|
OBJ = calc.o engine.o
calc: $(OBJ)
$(OBJ): engine.h
|
我們定義了一個宏 OBJ,它包含我們的目標檔案列表。請記住,GNU Make 知道如何從 C 程式建立目標檔案。
接下來,我們告訴 GNU Make 我們的程式 calc 由這些 OBJ 檔案組成。當我們執行 make 時,它會執行
cc -c -o calc.o calc.c
cc -c -o engine.o engine.c
cc calc.o engine.o -o calc |
最後,我們告訴 GNU Make,如果 engine.h 發生更改,我們必須重新編譯目標檔案。這稱為依賴項。
現在,我們來介紹 C++。讓我們定義一個新檔案:calcpp.cc
1 2 3 4 5 6 7 8 9 10 11
|
#include <iostream>
extern "C"
{
#include "engine.h"
}
int main()
{
std::cout << calc("2+3") << std::endl;
return 0;
}
|
這是我們修改後的 GNUmakefile
1 2 3 4 5 6
|
OBJ = calcpp.o engine.o
calc: $(OBJ)
$(LINK.cc) $^ -o $@
$(OBJ): engine.h
|
那麼有什麼改變?我們需要告訴 GNU Make 我們正在連結一個 C++ 程式。我們使用 GNU Make 宏 LINK.cc 來告訴它我們正在連結一個 C++ 程式。
$^ 表示所有依賴項,在此情況下為 calcpp.o 和 engine.o。
$@ 表示我們正在構建的目標,在此情況下為 calc。
當我們執行 make 時,它會執行
c++ -c -o calcpp.o calcpp.cc
c++ calcpp.o engine.o -o calc |
那編譯 engine.c 呢?嗯,我們之前已經編譯過它了,make 知道它不需要重新編譯。
BSD Make
BSD Make 早於 GNU Make,並且它有所不同。BSD Make 沒有很多內建規則。它需要在 make 檔案中被告知很多東西。正如您在上面看到的,GNU Make 知道很多。
BSD Make 知道依賴項和構建這些依賴項的規則,但它沒有所有那些內建的預設規則,因此需要被告知。一個使用 BSD Make 的系統,而不是被告知所有內容,而是提供一組包含檔案,這些檔案定義了在該系統上如何完成事物。例如,在 FreeBSD 上,如果您想編寫程式,則包含 <bsd.prog.mk>。這包含了編譯、安裝、解除安裝、歸檔……開發程式所需的所有規則。
GNU Make 和 BSD Make 的比較
請記住,GNU 是自由軟體基金會的工具集。GNU 的意思是 GNU 不是 Unix。這很重要。當 GNU 專案啟動時,它的目標是提供 Unix 程式的免費可用替代品。並且它們透過新增有用的、一致的行為來改進它們。
BSD Make 只知道依賴項、目標、規則和宏。GNU Make 將內建規則新增到其中,以便為開發人員提供便利。
事實證明,系統的細節是衝突的,並且無法提前知道。BSD Make 透過讓系統定義其引數來處理系統依賴項。GNU Make 的內建規則被證明是不夠的。Auto Tools 專案(AutoConf、AutoMake、LibTools)是為了彌補這一點而開發的。它透過在配置時發現系統來工作,然後生成 makefiles。
我更喜歡 BSD 的解決方案。很明顯,在這個例子中它的設計更好。我發現 BSD 通常都是如此。
示例
此示例使用了 3 個 C++ 原始檔(main.cc、config.cc、dispatch.cc)和 2 個頭檔案(config.hpp、dispatch.hpp)。我沒有新增依賴項,在現實世界中,它們是自動生成的。
GNUmakefile
1 2 3 4 5 6
|
CXXFLAGS = -g
all: goodlistener
goodlistener: main.o config.o dispatch.o
$(LINK.cc) -o $@ $^
|
BSDmakefile
1 2 3 4 5 6 7
|
PROG_CXX = goodlistener
SRCS = main.cc config.cc dispatch.cc
MAN = goodlistener.1
MAKEOBJDIR = work
CXXFLAGS=-g
.include <bsd.prog.mk>
|