目錄
1.make
1.1 make 命令格式
2.Makefile 核心概念? ?
2.1創建并運行 Makefile步驟
3. Makefile編寫
3.1最基礎Makefile
3.1.1使用默認make命令
?3.1.2使用make -f 命令
3.1.2.1 使用make -f 命令執行默認make操作
3.1.2.2使用 make [ ‐f file ] [ targets ]命令
3.1.2.3使用 make [ ‐f file ] [ targets ]命令,并執行可執行程序
3.1.3 gcc編譯常用組合選項
3.1.4 make 和 make all區別
3.1.4.1?all 是默認目標
3.1.4.2 all 不是默認目標
3.1.4.3 沒有定義?all 命令
3.1.4.3 強制設置 all 為默認目標
3.2多文件編程Makefile-基礎
3.3makefile變量
3.3.1 makefile 變量概述
3.3.2 makefile 的變量分類:
3.3.3 自定義變量語法
3.3.3.1自定義變量makefile多文件編程
3.3.4系統變量
3.3.5預定義變量
3.3.5.1編譯器與工具
3.3.5.2. 編譯選項
3.3.5.3. 文件與目錄
3.3.5.4. 隱式規則中的關鍵變量
3.3.5.5. 常用內置變量
3.3.5.6.程序驗證
4.幾種多文件編程Makefile對應關系
1.make

1.1 make 命令格式
make [ ‐f file ] [ targets ]
2.Makefile 核心概念? ?
作用?:
自動化編譯和鏈接程序,管理項目依賴關系,避免重復編譯未修改的代碼。
?基本結構:
target: dependenciescommand?target?: 生成的目標(如可執行文件、中間文件)
?dependencies?: 生成目標所需的文件或目標
?command?: 生成目標的命令(必須以 Tab 開頭)
2.1創建并運行 Makefile步驟
基本步驟:
- 創建文件:在項目根目錄創建名為 Makefile 的文件(無后綴)。
- 編寫規則:定義目標(如可執行文件)、依賴(如 .c 和 .o 文件)和命令。
- 運行命令:在終端執行 make 或 make <target>。
3. Makefile編寫
?make 命令格式
make [ ‐f file ] [ targets ]
3.1最基礎Makefile
3.1.1使用默認make命令
程序:
main.c
#include <stdio.h>
#include "main.h"int main(int argc, char const *argv[])
{printf("main函數開始\n");printf("ABC = %d abc = %d\n",ABC, abc);return 0;
}
main.h
#define ABC 123
#define abc 456
makefile
main:main.c main.h gcc main.c -o main clean:rm main
makefile內容解釋:
main:main.c main.h //可執行文件main依賴main.c main.h
?? ?gcc main.c -o main //由mian.c 生成可執行文件main
?? ?
clean:
?? ?rm main //執行 make clean 命令,刪除可執行文件main
運行結果:
?3.1.2使用make -f 命令
3.1.2.1 使用make -f 命令執行默認make操作
程序:與3.1.1使用默認make命令一樣。
makefile:與3.1.1使用默認make命令一樣。僅名稱不同。
將可執行文件main刪除,Makefile復制一份,重命名為Makefile1,執行?make -f Makefile1
也可以正常執行make命令。執行結果與默認make命令結果相同。
3.1.2.2使用 make [ ‐f file ] [ targets ]命令
程序:與3.1.1使用默認make命令一樣。
makefile:
test:main.c main.h gcc main.c -o main @echo "=== test ==="clean:rm main @echo "=== clean ==="test1:@echo "=== test1 ==="; # @符號注釋見下面 #echo前使用 @?:在 echo 前添加 @ 符號,可隱藏命令本身的輸出,僅顯示命令的執行結果?
#終端結果: === test1 ===#未使用 @?:命令本身和執行結果都會顯示,
#終端結果: echo "=== test1 ==="
# === test1 ===
# 在 Makefile 中直接寫 @echo "注釋內容" # 注釋內容, 注釋內容會輸出在終端,
# 因為 # 必須出現在行首或通過 ; 分隔
test2:@echo "=== test2 ==="; # @符號注釋見上面
(1)執行??make -f Makefile2 test1 test test2
test1 test test2 為Makefile2中的三個目標文件,執行上述命令,先運行test1里面的運行命令,在運行test運行命令,最后運行test2運行命令。
運行結果:
(2)執行 make -f Makefile2 test1 test2 clean 命令
test1 test2 clean 為Makefile2中的三個目標文件,執行上述命令,先運行test1里面的運行命令,在運行test2運行命令,最后運行clean運行命令。
運行結果:
注意:保證執行 clean命令,確保刪除的文件要存在。
刪除文件不存在運行結果:
3.1.2.3使用 make [ ‐f file ] [ targets ]命令,并執行可執行程序
程序:與3.1.1使用默認make命令一樣。
makefile:
test:main.c main.h gcc main.c -o main @echo "=== test ==="clean:rm main @echo "=== clean ==="test1:@echo "=== test1 ==="; # @符號注釋見下面 #echo前使用 @?:在 echo 前添加 @ 符號,可隱藏命令本身的輸出,僅顯示命令的執行結果?
#終端結果: === test1 ===#未使用 @?:命令本身和執行結果都會顯示,
#終端結果: echo "=== test1 ==="
# === test1 ===
# 在 Makefile 中直接寫 @echo "注釋內容" # 注釋內容, 注釋內容會輸出在終端,
# 因為 # 必須出現在行首或通過 ; 分隔
test2:@echo "=== test2 ==="; # @符號注釋見上面
(1)執行 make -f Makefile2 test1 test2 test;./main 命令
執行Makefile命令后,并運行生成的可執行文件
?(2)執行?make -f Makefile2 test;./main 命令
執行Makefile命令后,并運行生成的可執行文件
3.1.3 gcc編譯常用組合選項
選項 | 作用 | 示例 |
---|---|---|
-o | 指定輸出文件名 | gcc -c main.c -o main.o |
-I | 指定頭文件搜索路徑 | gcc -c main.c -I../include |
-Wall | 啟用所有警告信息 | gcc -c main.c -Wall |
-g | 生成調試信息(用于 GDB) | gcc -c main.c -g |
-O2 | 啟用優化(級別 2) | gcc -c main.c -O2 |
3.1.4 make 和 make all區別
?關鍵總結?
場景 | make ?行為 | make all ?行為 |
---|---|---|
all ?是默認目標 | 執行?all | 執行?all |
all ?不是默認目標 | 執行第一個目標(如?build ) | 執行?all (需存在定義) |
未定義?all | 執行第一個目標 | 報錯 |
強制?.DEFAULT_GOAL=all | 執行?all | 執行?all |
3.1.4.1?all 是默認目標
當 all 是默認目標時,make 和 make all 運行順序,結果相同。
程序:
main.c
#include <stdio.h>int main(int argc, const char *argv[])
{int x = 60;int y = 20;printf("main x= %d y= %d \n", x, y);return 0;
}
makefile
# all 是第一個目標(默認目標)
all:target echo " all開始"target:main.c gcc main.c -o mainecho " main開始"clean:rm main *.o -rf
運行結果:當 all 是默認目標時,make 和 make all 運行順序,結果相同。
(1)make all
(2)make
3.1.4.2 all 不是默認目標
all 不是默認目標,執行make all命令,會先執行 all依賴的命令。
程序:
?main.c
#include <stdio.h>int main(int argc, const char *argv[])
{int x = 60;int y = 20;printf("main x= %d y= %d \n", x, y);return 0;
}
makefile
# 若makefile命名不是 GNUmakefile、makefile、Makefile 中的一個
# 要使用 make -f Makefile名稱,執行make命令# all 不是第一個目標
target:main.c gcc main.c -o mainecho " main開始"all:clean targetecho " all開始"clean:rm main *.o -rf
運行結果:
(1)?首次make 編譯, 執行默認目標 target,編譯 gcc main.c -o main
(2)執行make all命令,會先執行 clean命令? rm main *.o -rf,在編譯gcc main.c -o main
3.1.4.3 沒有定義?all 命令
?main.c
#include <stdio.h>int main(int argc, const char *argv[])
{int x = 60;int y = 20;printf("main x= %d y= %d \n", x, y);return 0;
}
makefile
# 若makefile命名不是 GNUmakefile、makefile、Makefile 中的一個
# 要使用 make -f Makefile名稱,執行make命令target:main.c gcc main.c -o mainecho " main開始"clean:rm main *.o -rf
運行結果:make all運行報錯,make正常運行。
3.1.4.3 強制設置 all 為默認目標
?main.c
#include <stdio.h>int main(int argc, const char *argv[])
{int x = 60;int y = 20;printf("main x= %d y= %d \n", x, y);return 0;
}
makefile
# 若makefile命名不是 GNUmakefile、makefile、Makefile 中的一個
# 要使用 make -f Makefile名稱,執行make命令# 顯式設置 .DEFAULT_GOAL 為 all
.DEFAULT_GOAL = alltarget:main.c gcc main.c -o mainecho " main開始"all:clean targetecho " all開始"clean:rm main *.o -rf
運行結果:強制設置 all 為默認目標,執行make命令,先執行all依賴的語句。
3.2多文件編程Makefile-基礎
main.c
#include "head.h"int main(int argc, const char *argv[])
{int x = 60;int y = 20;printf("%d + %d = %d\n", x, y, sum(x, y));printf("%d - %d = %d\n", x, y, sub(x, y));return 0;
}
sub.c
#include "head.h"int sub(int a, int b)
{return a - b;
}
sum.c
#include "head.h"int sum(int a, int b)
{return a + b;
}
head.h
#ifndef _HEAD_H_
#define _HEAD_H_#include <stdio.h>int sum(int a, int b);
int sub(int a, int b); #endif
Makefile
main:main.o sub.o sum.ogcc main.o sub.o sum.o -o mainmain.o:main.cgcc -c main.c -o main.osub.o:sub.cgcc -c sub.c -o sub.osum.o:sum.cgcc -c sum.c -o sum.oclean:rm *.o main a.out -rf
Makefile語句解釋:
main:main.o sub.o sum.o //可執行文件main依賴于main.o sub.o sum.o
??? gcc main.o sub.o sum.o -o main //gcc 編譯 main.o sub.o sum.o 生成可執行文件main
main.o:main.c //可執行文件main.o依賴于main.c
??? gcc -c main.c -o main.o //gcc 編譯 main.c 生成可執行文件main.o
sub.o:sub.c //可執行文件sub.o依賴于sub.c
??? gcc -c sub.c -o sub.o //gcc 編譯 sub.c 生成可執行文件sub.o
sum.o:sum.c //可執行文件sum.o依賴于sum.c
????????gcc -c sum.c -o sum.o //gcc 編譯 sum.c 生成可執行文件sum.o
clean:
??? rm *.o main a.out -rf //執行 make clean刪除可執行文件,所有.o文件 main a.out
執行順序:
可執行文件main依賴于main.o,main.o又依賴于main.c,先執行gcc -c main.c -o main.o,在執行gcc main.o sub.o sum.o -o main
運行結果:
3.3makefile變量
3.3.1 makefile 變量概述
3.3.2 makefile 的變量分類:
3.3.3 自定義變量語法
常用變量:
定義變量:VAR = value
使用變量:$(VAR)
常用內置變量:
CC:C 編譯器(默認 cc,通常指向 gcc)。
CFLAGS:C 編譯選項(如 -Wall -O2)。
LDFLAGS:鏈接選項(如 -L 指定庫路徑)。
LDLIBS:鏈接庫(如 -lm 表示數學庫)。
3.3.3.1自定義變量makefile多文件編程
程序:
?main.c
#include "head.h"int main(int argc, const char *argv[])
{int x = 60;int y = 20;printf("%d + %d = %d\n", x, y, sum(x, y));printf("%d - %d = %d\n", x, y, sub(x, y));return 0;
}
sub.c
#include "head.h"int sub(int a, int b)
{return a - b;
}
sum.c
#include "head.h"int sum(int a, int b)
{return a + b;
}
head.h
#ifndef _HEAD_H_
#define _HEAD_H_#include <stdio.h>int sum(int a, int b);
int sub(int a, int b); #endif
Makefile
CC=gcc
obj=main
obj1=sub
obj2=sum
OBJS=main.o sub.o sum.o$(obj):$(OBJS)$(CC) $(OBJS) -o $(obj)$(obj).o:$(obj).c$(CC) -c $(obj).c -o $(obj).o$(obj1).o:$(obj1).c$(CC) -c $(obj1).c -o $(obj1).o$(obj2).o:$(obj2).c$(CC) -c $(obj2).c -o $(obj2).oclean:rm *.o $(obj) a.out -rf
Makefile語句解釋:與3.2多文件編程Makefile-基礎,一樣,只是替換為自定義的變量
main:main.o sub.o sum.o //可執行文件main依賴于main.o sub.o sum.o
??? gcc main.o sub.o sum.o -o main //gcc 編譯 main.o sub.o sum.o 生成可執行文件main
main.o:main.c //可執行文件main.o依賴于main.c
??? gcc -c main.c -o main.o //gcc 編譯 main.c 生成可執行文件main.o
sub.o:sub.c //可執行文件sub.o依賴于sub.c
??? gcc -c sub.c -o sub.o //gcc 編譯 sub.c 生成可執行文件sub.o
sum.o:sum.c //可執行文件sum.o依賴于sum.c
????????gcc -c sum.c -o sum.o //gcc 編譯 sum.c 生成可執行文件sum.o
clean:
??? rm *.o main a.out -rf //執行 make clean刪除可執行文件,所有.o文件 main a.out
執行順序:
可執行文件main依賴于main.o,main.o又依賴于main.c,先執行gcc -c main.c -o main.o,在執行gcc main.o sub.o sum.o -o main
運行結果:
3.3.4系統變量
#include <stdio.h>int main(int argc, const char *argv[])
{int x = 60;int y = 20;printf("x = %d y = %d \n", x, y);return 0;
}
Makefile
main:main.cgcc main.c -o main clean:rm main -rfecho $(PWD)echo $(HOME)echo $(HOSTNAME)echo $(MY_SHELL_NUM)

3.3.5預定義變量
$@ 目標名
$< 依賴文件列表中的第一個文件
$^ 依賴文件列表中除去重復文件的部分
AR 歸檔維護程序的程序名,默認值為 ar
ARFLAGS 歸檔維護程序的選項
AS 匯編程序的名稱,默認值為 as
ASFLAGS 匯編程序的選項
CC C 編譯器的名稱,默認值為 cc
CFLAGS C 編譯器的選項
CPP C 預編譯器的名稱,默認值為$(CC) -E
CPPFLAGS C 預編譯的選項
CXX C++編譯器的名稱,默認值為 g++
CXXFLAGS C++編譯器的選項
3.3.5.1編譯器與工具
變量名 | 默認值 | 描述 | 示例用法 |
---|---|---|---|
CC | cc | C 編譯器 | CC = gcc |
CXX | g++ | C++ 編譯器 | CXX = clang++ |
AR | ar | 靜態庫打包工具 | AR = ar rcs |
AS | as | 匯編器 | AS = nasm |
LD | ld | 鏈接器 | LD = lld |
3.3.5.2. 編譯選項
變量名 | 描述 | 默認值 | 示例用法 |
---|---|---|---|
CFLAGS | C 編譯選項 | 空 | CFLAGS = -O2 -Wall |
CXXFLAGS | C++ 編譯選項 | 空 | CXXFLAGS = -std=c++17 |
CPPFLAGS | 預處理選項(C/C++通用) | 空 | CPPFLAGS = -Iinclude |
LDFLAGS | 鏈接器選項(如庫路徑) | 空 | LDFLAGS = -Llib |
LDLIBS | 鏈接的庫(如?-lm ) | 空 | LDLIBS = -lpthread |
3.3.5.3. 文件與目錄
變量名 | 描述 | 默認值 | 示例用法 |
---|---|---|---|
MAKEFILE_LIST | 當前 Makefile 文件名列表 | 自動生成 | 用于條件判斷 |
VPATH | 搜索源文件的目錄列表 | 空 | VPATH = src:lib |
SRC | 自定義源文件變量 | 無 | SRC = main.c utils.c |
OBJ | 自定義目標文件變量 | 無 | OBJ = $(SRC:.c=.o) |
3.3.5.4. 隱式規則中的關鍵變量
Make 根據文件后綴自動推導編譯規則,以下變量控制隱式規則行為:
變量名 | 描述 | 默認命令 | 示例覆蓋 |
---|---|---|---|
COMPILE.c | C 文件編譯命令 | $(CC) $(CFLAGS) $(CPPFLAGS) -c | COMPILE.c = $(CC) -O3 |
LINK.c | C 程序鏈接命令 | $(CC) $(CFLAGS) $(LDFLAGS) | LINK.c = $(CC) -flto |
3.3.5.5. 常用內置變量
變量名 | 描述 | 示例值 |
---|---|---|
MAKE | 當前 Make 命令路徑 | /usr/bin/make |
MAKECMDGOALS | 用戶指定的目標列表 | all clean |
CURDIR | 當前工作目錄 | /home/user/project |
3.3.5.6.程序驗證
?程序:
?main.c
#include "head.h"int main(int argc, const char *argv[])
{int x = 60;int y = 20;printf("%d + %d = %d\n", x, y, sum(x, y));printf("%d - %d = %d\n", x, y, sub(x, y));return 0;
}
sub.c
#include "head.h"int sub(int a, int b)
{return a - b;
}
sum.c
#include "head.h"int sum(int a, int b)
{return a + b;
}
head.h
#ifndef _HEAD_H_
#define _HEAD_H_#include <stdio.h>int sum(int a, int b);
int sub(int a, int b); #endif
Makefile
CC=gcc
obj=main
obj1=sub
obj2=sum
OBJ=main.o sub.o sum.o
CFLAGS=-Wall -O2
# -Wall警告相關, -O2:優化選項,兼顧編譯速度和性能$(obj):$(OBJ)$(CC) $^ -o $@$(obj).o:$(obj).c$(CC) $(CFLAGS) -c $< -o $@$(obj1).o:$(obj1).c$(CC) $(CFLAGS) -c $< -o $@$(obj2).o:$(obj2).c$(CC) $(CFLAGS) -c $< -o $@clean:rm *.o $(obj) a.out -rf
Makefile語句解釋:
與3.3.3 自定義變量語法,一樣,只是替換為預定義的變量。表達式的區別見4.幾種多文件編程Makefile對應關系。
運行結果:
注:Makefile更精簡表達式
Makefile1
CC=gcc
obj=main
OBJ=main.o sub.o sum.o
CFLAGS=-Wall -g$(obj):$(OBJ)$(CC) $^ -o $@%*.o:%*.c #使用通配符匹配,所有.c文件都去執行下面的命令$(CC) $(CFLAGS) -c $< -o $@clean:rm *.o $(obj) a.out -rf
運行結果:與上述Makefile運行結果相同
(1)先在終端執行?make clean (2)終端執行 make -f Makefile1?
4.幾種多文件編程Makefile對應關系
多文件編程Makefile最基礎、自定義變量、預定義變量對應關系。
每一行為幾種方法相同結果,不同格式的變量表達式。