手動建立makefile簡單實例解析!

假設我們有一個程序由5個文件組成,源代碼如下:

/*main.c*/

#include 
"mytool1.h"
#include 
"mytool2.h"

int main()
{
        mytool1_print(
"hello mytool1!");
        mytool2_print(
"hello mytool2!");
        
return 0;
}

  

/*mytool1.c*/

#include 
"mytool1.h"
#include 
<stdio.h>

void mytool1_print(char *print_str)
{
        printf(
"This is mytool1 print : %s ",print_str);
}

 

/*mytool1.h*/

#ifndef _MYTOOL_1_H
#define _MYTOOL_1_H
        
void mytool1_print(char *print_str);
#endif

 

/*mytool2.c*/

#include 
"mytool2.h"
#include 
<stdio.h>

void mytool2_print(char *print_str)
{
        printf(
"This is mytool2 print : %s ",print_str);
}

 

/*mytool2.h*/

#ifndef _MYTOOL_2_H
#define _MYTOOL_2_H
        
void mytool2_print(char *print_str);
#endif

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

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

1、需要由make工具創建的目標體(target),通常是目標文件或可執行文件。
2、要創建的目標體所依賴的文件(dependency_file)。
3、創建每個目標體時需要運行的命令(command)。

格式如下:

 target:dependency_files
<TAB>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 
-*.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

執行結果如下:

[armlinux@lqm makefile-easy]$ ./main
This 
is mytool1 print : hello mytool1!
This 
is mytool2 print : hello mytool2!

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

改進一:使用變量

一般在書寫Makefile時,各部分變量引用的格式如下:
1. 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 有三個非常有用的變量,分別是$@、$^、$<。代表的意義分別是:
$@--目標文件,
$^--所有的依賴文件,
$<--第一個依賴文件。

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手冊,這裏講解的比較全面。


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