天天看點

MakeFile由淺入深

經過長時間學習linux Makefile,于是和大家分享一下,看完本文你肯定有不少收獲,希望本文能教會你更多東西。

  假設我們有一個程式由5個檔案組成,源代碼如下:

  

  #include "mytool1.h"

  #include "mytool2.h"

  int main()

  {

  mytool1_print("hello mytool1!");

  mytool2_print("hello mytool2!");

  return 0;

  }

  

  #include "mytool1.h"

  #include

  void mytool1_print(char *print_str)

  {

  printf("This is mytool1 print : %s ", print_str);

  }

  

  #ifndef _MYTOOL_1_H

  #define _MYTOOL_1_H

  void mytool1_print(char *print_str);

  #endif

  

  #include "mytool2.h"

  #include

  void mytool2_print(char *print_str)

  {

  printf("This is mytool2 print : %s ", print_str);

  }

  

  #ifndef _MYTOOL_2_H

  #define _MYTOOL_2_H

  void mytool2_print(char *print_str);

  #endif

  首先了解一下make和linux Makefile。GNU make是一個工程管理器,它可以管理較多的檔案。我所使用的RedHat 9.0的make版本為GNU Make version 3.79.1。使用make的最大好處就是實作了“自動化編譯”。如果有一個上百個檔案的代碼構成的項目,其中一個或者幾個檔案進行了修改,make就能夠自動識别更新了的檔案代碼,不需要輸入冗長的指令行就可以完成最後的編譯工作。make執行時,自動尋找Makefile(makefile)檔案,然後執行編譯工作。是以我們需要編寫Makefile檔案,這樣可以提高實際項目的工作效率。

  在一個linux Makefile中通常包含下面内容:

  1、需要由make工具建立的目标體(target),通常是目标檔案或可執行檔案。

  2、要建立的目标體所依賴的檔案(dependency_file)。

  3、建立每個目标體時需要運作的指令(command)。

  格式如下:

  target:dependency_files

  command

  target:規則的目标。通常是程式中間或者最後需要生成的檔案名,可以是.o檔案、也可以是最後的可執行程式的檔案名。另外,目标也可以是一個make執行的動作的名稱,如目标“clean”,這樣的目标稱為“僞目标”。dependency_files:規則的依賴。生成規則目标所需要的檔案名清單。通常一個目标依賴于一個或者多個檔案。

  command:規則的指令行。是make程式所有執行的動作(任意的shell指令或者可在shell下執行的程式)一個規則可以有多個指令行,每一條指令占一行。注意:每一個指令行必須以[Tab]字元開始,[Tab]字元告訴make此行是一個指令行。make按照指令完成相應的動作。這也是書寫Makefile中容易産生,而且比較隐蔽的錯誤。指令就是在任何一個目标的依賴檔案發生變化後重建目标的動作描述。一個目标可以沒有依賴而隻有動作(指定的指令)。比如Makefile中的目标“clean”,此目标沒有依賴,隻有指令。它所指定的指令用來删除make過程産生的中間檔案(清理工作)。

  在Makefile中“規則”就是描述在什麼情況下、如何重建規則的目标檔案,通正常則中包括了目标的依賴關系(目标的依賴檔案)和重建目标的指令。make執行重建目标的指令,來建立或者重建規則的目标(此目标檔案也可以是觸發這個規則的上一個規則中的依賴檔案)。規則包含了目标和依賴的關系以及更新目标所要求的指令。

  Makefile中可以包含除規則以外的部分。一個最簡單的Makefile可能隻包含規則描述。規則在有些Makefile中可能看起來非常複雜,但是無論規則的書寫是多麼的複雜,它都符合規則的基本格式。

  下面就可以寫出第一個Makefile了。

  main:main.o mytool1.o mytool2.o

  gcc -o main main.o mytool1.o mytool2.o

  main.o:main.c mytool1.h mytool2.h

  gcc -c main.c

  mytool1.o:mytool1.c mytool1.h

  gcc -c mytool1.c

  mytool2.o:mytool2.c mytool2.h

  gcc -c mytool2.c

  clean:

  rm -f *.o main

  在shell提示符下輸入make,執行顯示:

  gcc -c main.c

  gcc -c mytool1.c

  gcc -c mytool2.c

  gcc -o main main.o mytool1.o mytool2.o

  執行結果如下:

  [[email protected] makefile-easy]$ ./main

  This is mytool1 print : hello mytool1!

  This is mytool2 print : hello mytool2!

  這隻是最為初級的Makefile,現在來對這個Makefile進行改進。

  改進一:使用變量

  一般在書寫Makefile時,各部分變量引用的格式如下:

  1. make變量(Mak1. make變量(Makefile中定義的或者是make的環境變量)的引用使用“$(VAR)”格式,無論“VAR”是單字元變量名還是多字元變量名。

  2. 出現在規則指令行中shell變量(一般為執行指令過程中的臨時變量,它不屬于Makefile變量,而是一個shell變量)引用使用shell的“$tmp”格式。

  3. 對出現在指令行中的make變量同樣使用“$(CMDVAR)” 格式來引用。

  OBJ=main.o mytool1.o mytool2.o

  make:$(OBJ)

  gcc -o main $(OBJ)

  main.o:main.c mytool1.h mytool2.h

  gcc -c main.c

  mytool1.o:mytool1.c mytool1.h

  gcc -c mytool1.c

  mytool2.o:mytool2.c mytool2.h

  gcc -c mytool2.c

  clean:

  rm -f main $(OBJ)

  改進二:使用自動推導

  讓make自動推導,隻要make看到一個.o檔案,它就會自動的把對應的.c檔案加到依賴檔案中,并且gcc -c .c也會被推導出來,是以Makefile就簡化了。

  CC = gcc

  OBJ = main.o mytool1.o mytool2.o

  make: $(OBJ)

  $(CC) -o main $(OBJ)

  main.o: mytool1.h mytool2.h

  mytool1.o: mytool1.h

  mytool2.o: mytool2.h

  .PHONY: clean

  clean:

  rm -f main $(OBJ)

  改進三:自動變量($^ $< $@)的應用

  Makefile 有三個非常有用的變量,分别是$@、$^、$<。代表的意義分别是:

  [email protected]目标檔案,

  $^--所有的依賴檔案,

  $<--第一個依賴檔案。

  CC = gcc

  OBJ = main.o mytool1.o mytool2.o

  main: $(OBJ)

  $(CC) -o $@ $^

  main.o: main.c mytool1.h mytool2.h

  $(CC) -c $<

  mytool1.o: mytool1.c mytool1.h

  $(CC) -c $<

  mytool2.o: mytool2.c mytool2.h

  $(CC) -c $<

  .PHONY: clean

  clean:

  rm -f main $(OBJ)

  這些是最為初級的知識,現在至少可以減少編譯時的工作量。細節方面的東西還需要在以後的工作和學習中不斷的總結,不斷的深化了解。可以 參考GNU Make手冊,這裡講解的比較全面。

繼續閱讀