轉載於: http://blog.sina.com.cn/s/blog_87c063060101ky45.html
1.關於GCC怎么樣自動生成‘依賴’.網上有很多版本,有使用“正則法則”實現的,也有其他方法實現的.
筆者通過比較,覺得最簡單的還是Linux內核里面的規則最簡單.
2.在GCC的命令行加一條這樣的語句就OK了.
-Wp,-MD,drivers/leds/.XXX.o.d (其中drivers/leds/.XXX.o.d為依賴文件,里面記錄了很多依賴信息)
3.就這么簡單,來舉個例子.Linux內核的一條命令
cmd_drivers/leds/led-core.o := arm-linux-gcc -Wp,-MD,drivers/leds/.led-core.o.d
-nostdinc -isystem /work/tools/gcc-3.4.5-glibc-2.3.6/lib/gcc/arm-linux/3.4.5/include
-D__KERNEL__ -Iinclude -include include/linux/autoconf.h
-mlittle-endian
-Wall -Wundef -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing
-fno-common -Os -marm -fno-omit-frame-pointer
-mapcs -mno-sched-prolog -mapcs-32 -mno-thumb-interwork
-D__LINUX_ARM_ARCH__=4 -march=armv4t -mtune=arm9tdmi -malignment-traps -msoft-float
-Uarm -fno-omit-frame-pointer -fno-optimize-sibling-calls
-g -Wdeclaration-after-statement
-D"KBUILD_STR(s)=\#s" -D"KBUILD_BASENAME=KBUILD_STR(led_core)"
-D"KBUILD_MODNAME=KBUILD_STR(led_core)"
-c -o drivers/leds/led-core.o drivers/leds/led-core.c
4.自己來舉個例子吧!
①四個文件:def.h hello.c main.c Makefile
②四個文件的內容分別為
def.h:
#ifndef __DEF_H
#define __DEF_H
#define A 5
void hello();
#endif //__DEF_H
hello.c:
#include<stdio.h>
#include"def.h"
void hello()
{
printf("hello world!\n");
printf("A = %d\n",A);
}
main.c:
#include<stdio.h>
#include"def.h"
int main(void)
{
hello();
return 0;
}
Makefile:
PHONY := test
CROSS_COMPILE =
CC = $(CROSS_COMPILE)gcc
CFLAGS := -Wall -Werror -O2 -g
LDFLAGS =
test: hello.o main.o
$(CC) $(LDFLAGS) -o $@ $^
%.o : %.c
$(CC) $(CFLAGS) -c -o $@ $<
clean:
rm *.o test .*.d
③現象
在終端輸入命令:make
gcc -Wall -Werror -O2 -g -c -o hello.o hello.c
gcc -Wall -Werror -O2 -g -c -o main.o main.c
gcc -o test hello.o main.o
運行:./test
④來修改一個文件,把def.h當中的 #define A 5 改為 #define A 10 然后再make一下.
make: `test' is up to date.
⑥來修改一下Makefile
PHONY := test
CROSS_COMPILE =
CC = $(CROSS_COMPILE)gcc
CFLAGS := -Wall -Werror -O2 -g
LDFLAGS =
test: hello.o main.o
$(CC) $(LDFLAGS) -o $@ $^
dep_file = .$@.d (特別注意:這里只能用 = ,也就是遞歸展開 ,而不能用 := ,進行直接展開)
<讀者可以修改觀察一下現象,就可以知道 遞歸展開 = 與 直接展開 := 的區別了,可以感性認識一下二者的區別.>
%.o : %.c
$(CC) $(CFLAGS) -Wp,-MD,$(dep_file) -c -o $@ $<
clean:
rm *.o test .*.d
再來 make 一下:
提示: make: `test' is up to date.
那么,make clean 之后,再來make看看:
提示信息:
gcc -Wall -Werror -O2 -g -Wp,-MD,.hello.o.d -c -o hello.o hello.c
gcc -Wall -Werror -O2 -g -Wp,-MD,.main.o.d -c -o main.o main.c
gcc -o test hello.o main.o
執行一下看看:./test
hello world!
A = 10
用ls -al 命令看看: 確實生成了“依賴文件”
.hello.o.d
.main.o.d
⑦再一次修改def.h試試:
把def.h當中的 #define A 10 改為 #define A 20 然后再make一下.
make: `test' is up to date.
明明已經生成依賴文件了,為什么make還會提示,說沒有更新呢?(后面我們用:時間軸更新 來說明)
筆者也折騰了一陣,后來發現,是“依賴文件”沒有"被包含"進Makefile,導致make的“時間軸”沒有更新.
⑧再來修改Makefile:
在Makefile里面加這么一句: include .*.o.d 表示包含所以的 .d文件(依賴文件).
注意:有的需要寫成這種形式 -include .*.o.d
再一次make:
提示信息:
gcc -Wall -Werror -O2 -g -Wp,-MD,.hello.o.d -c -o hello.o hello.c
gcc -Wall -Werror -O2 -g -Wp,-MD,.main.o.d -c -o main.o main.c
gcc -o test hello.o main.o
果然成功了.
再來執行一下: ./test
hello world!
A = 20
5.總結
在Makefile中,“依賴關系”也是一個比較重要的規則,尤其是“自動生成依賴”.這里筆者舉了個簡單的例子加以說明.對於Linux,尤其是這種內容,講起來會比較抽象,盡量自己多去舉幾個例子,去實踐實踐,結果很快就可以出來了,也可以加深理解!
6.補充
關於,在Makefile中, include 與 -include 的區別
通過試驗,筆者得出 include 與 -include 存在着用法上的區別,而且內核的Makefile當中,也同時出現過這兩種情況.
在上個實驗當中, 用 include.*.o.d 出現了如下錯誤提示:
Makefile:31: .*.o.d: No such file or directory
make: *** No rule to make target `.*.o.d'. Stop.
而用 -include .*.o.d 卻解決了問題
在網上找了一篇文章:http://blog.csdn.net/xiaozhi_su/article/details/4202779
指示符“include”、“-include”和“sinclude”
如果指示符“include”指定的文件不是以斜線開始(絕對路徑,如/usr/src/Makefile...),而且當前目錄下也不存在此文件;make將根據文件名試圖在以下幾個目錄下查找:
首先,查找使用命令行選項“-I”或者“--include-dir”指定的目錄,如果找到指定的文件,則使用這個文件;
否則,繼續依此搜索以下幾個目錄(如果其存在):“/usr/gnu/include”、“/usr/local/include”和“/usr/include”。
當在這些目錄下都沒有找到“include”指定的文件時,make將會提示一個包含文件未找到的告警提示,但是不會立刻退出。而是繼續處理Makefile的后續內容。當完成讀取整個Makefile后,make將試圖使用規則來創建通過指示符“include”指定的但未找到的文件,當不能創建它時(沒有創建這個文件的規則),make將提示致命錯誤並退出。會輸出類似如下錯誤提示:
Makefile:錯誤的行數:未找到文件名:提示信息(No such file or directory)
Make: *** No rule to make target ‘<filename>’. Stop
通常我們在Makefile中可使用“-include”來代替“include”,來忽略由於包含文件不存在或者無法創建時的錯誤提示(“-”的意思是告訴make,忽略此操作的錯誤。make繼續執行)。像下邊那樣:
-include FILENAMES...
使用這種方式時,當所要包含的文件不存在時不會有錯誤提示、make也不會退出;除此之外,和第一種方式效果相同。以下是這兩種方式的比較:
使用“include FILENAMES...”,make程序處理時,如果“FILENAMES”列表中的任何一個文件不能正常讀取而且不存在一個創建此文件的規則時make程序將會提示錯誤並退出。
使用“-include FILENAMES...”的情況是,當所包含的文件不存在或者不存在一個規則去創建它,make程序會繼續執行,只有真正由於不能正確完成終極目標的重建時(某些必需的目標無法在當前已讀取的makefile文件內容中找到正確的重建規則),才會提示致命錯誤並退出。
為了和其它的make程序進行兼容。也可以使用“sinclude”來代替“-include”(GNU所支持的方式)。