1 makefile 基本結構
makefile
中通常包含如下內容:
- 需要由
make
工具創建的目標體(target
),通常是目標文件或可執行文件; - 要創建的目標體所依賴的文件(
dependency_file
); - 創建每個目標體時需要運行的命令(
command
)
,這一行必須以製表符(tab
鍵)開頭。
格式爲:
target: dependency_files
command /* 該行必須以 TAB 開頭 */
e.g.
創建makefile
文件。將通過兩個文件hello.c
和hello.h
創建目標文件hello.o
。
#The simplest example
hello.o: hello.c hello.h
gcc –c hello.c –o hello.o
執行make
<linux> make hello.o
gcc -c hello.c -o hello.o
<linux> ls
hello.c hello.h hello.o makefile
2 makefile 變量
變量是在 makefile
中定義的名字,用來代替一個文本字符串,該文本字符串稱爲該變量的值。在具體要求下,這些值可以代替目標體、依賴文件、命令以及 makefile
文件中其他部分。在 makefile
中的變量定義有兩種方式:一種是遞歸展開方式,另一種是簡單方式。
遞歸展開方式定義的變量是在引用該變量時進行替換的,即如果該變量包含了對其他變量的引用,則在引用該變量時一次性將內嵌的變量全部展開,雖然這種類型的變量能夠很好地完成用戶的指令,但是它也有嚴重的缺點,如不能在變量後追加內容(因爲語句:CFLAGS = $(CFLAGS) -O
在變量擴展過程中可能導致無窮循環)。
爲了避免上述問題,簡單擴展型變量的值在定義處展開,並且只展開一次,因此它不包含任何對其他變量的引用,從而消除變量的嵌套引用。
遞歸展開方式的定義格式爲:VAR=var
。
簡單擴展方式的定義格式爲:VAR:=var
。
make
中的變量使用均使用的格式爲:$(VAR)
。
e.g.
準備文件:
my.h
/* my.h */
#include <stdio.h>
#include <stdlib.h>
test.c
/*test.c*/
#include "my.h"
int main(int argc, char *argv[])
{
int x,i, n = 0;
sscanf(argv[1], "%d", &x);
sum(x);
for(i = 1; i<= x; i++)
{
n += i;
}
printf("The sum of 1-%d is %d \n", x, n);
}
sum.c
/* sum.c */
#include "my.h"
int sum(int m)
{
int i, n = 0;
for (i = 1; i <= m; i++)
{
n += i;
printf("The sum of 1-%d is %d\n", i, n);
}
}
makefile
CC = gcc
CFLAGS1 = -fPIC -Wall -c
CFLAGS2 = -shared -o
LIBSO = -lsum
LIBSONAME = libsum
OP1 = sum
MAIN = test
SODIR = /lib
all : $(MAIN).c $(LIBSONAME).so $(OP1).o
$(CC) -o $(MAIN) $(MAIN).c -L . $(LIBSO)
rm $(OP1).o
$(LIBSONAME).so : $(OP1).o
$(CC) $(CFLAGS2) $(LIBSONAME).so $(OP1).o
sudo mv $(LIBSONAME).so $(SODIR)
$(OP1).o : $(OP1).c
$(CC) $(CFLAGS1) $(OP1).c
clean:
sudo rm $(SODIR)/$(LIBSONAME).so
rm $(MAIN)
鍵入命令及終端反饋
<linux> ls
makefile my.h sum.c test.c
<linux> make all
gcc -fPIC -Wall -c sum.c
sum.c: In function ‘sum’:
sum.c:13:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
gcc -shared -o libsum.so sum.o
sudo mv libsum.so /lib
gcc -o test test.c -L . -lsum
test.c: In function ‘main’:
test.c:8:3: warning: implicit declaration of function ‘sum’ [-Wimplicit-function-declaration]
sum(x);
^~~
rm sum.o
<linux> ./test 5
The sum of 1-1 is 1
The sum of 1-2 is 3
The sum of 1-3 is 6
The sum of 1-4 is 10
The sum of 1-5 is 15
The sum of 1-5 is 15
<linux> make clean
sudo rm /lib/libsum.so
rm test
makefile 中常見的變量
makefile
中常見的預定義變量
預定義變量 | 含義 |
---|---|
AR | 庫文件維護程序的名稱,默認值爲 ar |
AS | 彙編程序的名稱,默認值爲 as |
CC | C 編譯器的名稱,默認值爲 cc |
CPP | C 預編譯器的名稱,默認值爲$(CC) –E |
CXX | C++ 編譯器的名稱,默認值爲 g++ |
FC | Fortran 編譯器的名稱,默認值爲 f77 |
RM | 文件刪除程序的名稱,默認值爲 rm –f |
ARFLAGS | 庫文件維護程序的選項,無默認值 |
ASFLAGS | 彙編程序的選項,無默認值 |
CFLAGS | C 編譯器的選項,無默認值 |
CPPFLAGS | C 預編譯的選項,無默認值 |
CXXFLAGS | C++ 編譯器的選項,無默認值 |
FFLAGS | Fortran 編譯器的選項,無默認值 |
makefile
中常見的自動變量
自 動 變 量 | 含義 |
---|---|
$* | 不包含擴展名的目標文件名稱 |
$+ | 所有的依賴文件,以空格分開,並以出現的先後爲序,可能包含重複的依賴文件 |
$< | 第一個依賴文件的名稱 |
$? | 所有時間戳比目標文件晚的依賴文件,並以空格分開 |
$@ | 目標文件的完整名稱 |
$^ | 所有不重複的依賴文件,以空格分開 |
$% | 如果目標是歸檔成員,則該變量表示目標的歸檔成員名稱 |
通過自動變量改寫後的makefile
文件
CC = gcc
CFLAGS1 = -fPIC -Wall -c
CFLAGS2 = -shared -o
LIBSO = -lsum
LIBSONAME = libsum
OP1 = sum
MAIN = test
SODIR = /lib
all : $(MAIN).c $(LIBSONAME).so $(OP1).o
$(CC) -o $(MAIN) $< -L . $(LIBSO)
rm $(OP1).o
$(LIBSONAME).so : $(OP1).o
$(CC) $(CFLAGS2) $(LIBSONAME).so $<
sudo mv $(LIBSONAME).so $(SODIR)
$(OP1).o : $(OP1).c
$(CC) $(CFLAGS1) $<
clean:
sudo rm $(SODIR)/$(LIBSONAME).so
rm $(MAIN)
3 makefile 規則
3.1 隱式規則
makefile
中常見隱式規則目錄
對應語言後綴名 | 隱式規則 |
---|---|
C 編譯:.c 變爲.o | $(CC) –c $(CPPFLAGS) $(CFLAGS) |
C++編譯:.cc 或.C 變爲.o | $(CXX) -c $(CPPFLAGS) $(CXXFLAGS) |
Pascal 編譯:.p 變爲.o | $(PC) -c $(PFLAGS) |
Fortran 編譯:.r 變爲-o | $(FC) -c $(FFLAGS) |
通過隱式規則改寫後的makefile
文件
CC = gcc
CFLAGS1 = -fPIC -Wall -c
CFLAGS2 = -shared -o
LIBSO = -lsum
LIBSONAME = libsum
OP1 = sum
MAIN = test
SODIR = /lib
all : $(MAIN).c $(LIBSONAME).so $(OP1).o
$(CC) -o $(MAIN) $< -L . $(LIBSO)
rm $(OP1).o
$(LIBSONAME).so : $(OP1).o
$(CC) $(CFLAGS2) $(LIBSONAME).so $<
sudo mv $(LIBSONAME).so $(SODIR)
$(CC) $(CFLAGS1) $<
clean:
sudo rm $(SODIR)/$(LIBSONAME).so
rm $(MAIN)
3.2 模式規則
模式規則是用來定義相同處理規則的多個文件的。它不同於隱式規則,隱式規則僅僅能夠用 make
默認的
變量來進行操作,而模式規則還能引入用戶自定義變量,爲多個文件建立相同的規則,從而簡化 makefile
的編寫。
通過模式規則改寫後的makefile
文件
CC = gcc
CFLAGS1 = -fPIC -Wall -c
CFLAGS2 = -shared -o
LIBSO = -lsum
LIBSONAME = libsum
OP1 = sum
MAIN = test
SODIR = /lib
all : $(MAIN).c $(LIBSONAME).so $(OP1).o
$(CC) -o $(MAIN) $< -L . $(LIBSO)
rm $(OP1).o
$(LIBSONAME).so : $(OP1).o
$(CC) $(CFLAGS2) $(LIBSONAME).so $<
sudo mv $(LIBSONAME).so $(SODIR)
%.o : %.c
$(CC) $(CFLAGS1) $<
clean:
sudo rm $(SODIR)/$(LIBSONAME).so
rm $(MAIN)
4 make 管理器的使用
make
的命令行選項
命 令 格 式 | 含義 |
---|---|
-C dir | 讀入指定目錄下的 makefile |
-f file | 讀入當前目錄下的 file 文件作爲 makefile |
-I | 忽略所有的命令執行錯誤 |
-I dir | 指定被包含的 makefile 所在目錄 |
-n | 只打印要執行的命令,但不執行這些命令 |
-p | 顯示 make 變量數據庫和隱含規則 |
-s | 在執行命令時不顯示命令 |
-w | 如果 make 在執行過程中改變目錄,則打印當前目錄名 |
文章目錄
參考:《嵌入式Linux應用程序開發標準教程》作者:華清遠見