make工程管理器

1 makefile 基本結構

makefile中通常包含如下內容:

  1. 需要由 make 工具創建的目標體(target),通常是目標文件或可執行文件;
  2. 要創建的目標體所依賴的文件(dependency_file);
  3. 創建每個目標體時需要運行的命令(command)
    ,這一行必須以製表符(tab 鍵)開頭。
    格式爲:
    target: dependency_files
    	command /* 該行必須以 TAB 開頭 */

e.g.創建makefile文件。將通過兩個文件hello.chello.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應用程序開發標準教程》作者:華清遠見

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