前言
驅動、內核等大型工程包含眾多 .c .h 檔案,如果手動一個個去編譯這些檔案是不現實的,通常的做法是使用 make 命令進行自動化編譯,make 命令執行時,需要 makefile 檔案,以告訴 make 命令需要怎樣去編譯和鏈接程式,
不過這些大型工程的 makefile 檔案往往不止一個,且常常分散在各個層級,如果編譯時報錯,除錯起來就比較麻煩了,聯想到 C 語言 Debug 的方法,通常是在出現問題的陳述句前面添加列印,來判斷變數的值是否符合預期,陳述句是否被執行等等,那么在 Makefile 中有沒有類似的 Debug 方法呢?
控制 make 的函式
答案是有的,那就是控制 make 的函式(Functions That Control Make),
make 提供了一些函式,可以檢測 makefile 的運行時資訊,來控制 make 的運行,
- info 函式
$(info <text ..>)
功能:列印資訊
- error 函式
$(error <text ...>)
功能:產生一個致命的錯誤,終止 make 運行,<text …> 是錯誤資訊,
- warning 函式
$(warning <text ...>)
功能:這個函式很像 error 函式,只是它并不會讓 make 退出,只是輸出一段警告資訊,而 make 繼續執行,
案例分析
期望:config.mk 作為 Makefile 的組態檔,ARM = y 表明想編譯出 ARM 架構程式,即用 arm-linux-gcc 進行編譯,但是執行后,make 并沒有按照預期使用 arm-linux-gcc 進行編譯,而是使用默認的 cc 進行編譯,問題出在哪呢?
先看代碼
$ tree
.
├── config.mk
├── hello.c
└── Makefile
config.mk
ARM = y
Makefile
include config.mk
ifeq ($(ARM), y)
CC = arm-linux-gcc
endif
all:
$(CC) hello.c
hello.c
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
printf("hello world\n");
return EXIT_SUCCESS;
}
執行 make
$ make
cc hello.c
看到執行結果,很顯然 CC 沒有被正確賦值為 arm-linux-gcc,難道 ifeq ($(ARM), y) 條件不成立?測驗一下
include config.mk
ifeq ($(ARM), y)
111
CC = arm-linux-gcc
endif
all:
$(CC) hello.c
在 ifeq ($(ARM), y) 下面加入錯誤陳述句 111,結果執行沒有報錯,說明 ifeq ($(ARM), y) 條件確實是不成立的,但是我已經包含了 config.mk 這個檔案了啊,而且 config.mk 里面定義了變數 ARM,并且賦值了 y,為什么 ifeq ($(ARM), y) 條件就是不成立呢?百思不得其解!!
這時候就可以啟用我們的 make 除錯方法了,先上 info 函式
include config.mk
$(info "ARM=$(ARM)")
ifeq ($(ARM), y)
111
CC = arm-linux-gcc
endif
all:
$(CC) hello.c
執行
$ make
"ARM=y "
cc hello.c
原來 y 后面多了一個空格,導致條件判斷不通過,可以看到,使用 info 函式進行 make 列印除錯,可以快速定位問題,
其實這里 ifeq ($(ARM), y) 的寫法不好,更好的寫法是 ifeq ($(strip $(ARM)), y),這樣,即便在 y 前后有空格,strip 函式也會幫助我們去除,增強腳本的健壯性,
include config.mk
$(info "ARM=$(ARM)")
ifeq ($(strip $(ARM)), y)
CC = arm-linux-gcc
endif
all:
$(CC) hello.c
運行
$ make
"ARM=y "
arm-linux-gcc hello.c
可以看到,即便 y 后面有空格,由于使用 strip 函式的作用,幫我們把空格去除了,ifeq ($(strip $(ARM)), y) 條件也就成立了,最終使用了 arm-linux-gcc 進行編譯,
回過頭來,這一切還是要歸功于 info 函式給我們除錯 make 帶來的便利性,才能有后面我們的解決方案和優化方案,
除了 info 函式,我們還可以使用 warning 函式,它比 info 函式列印更多的資訊:檔案名稱和行號,
不過上述兩個函式只能列印除錯資訊,并不能控制 make 的運行,我們在 make 大型工程時,可能 make 流程已經不符合我們的預設了,但是 make 還在繼續執行,這時我們只能手動停止,然后向上滾動 log 查找出錯位置,其實我們可以有更好的方法,那就是使用 error 函式,它可以讓 make 停止在你想要停止的位置,方便迅速定位問題,比如上面示例中,我們想要使用 arm-linux-gcc 進行編譯,如果 CC 沒能被正確賦值為 arm-linux-gcc,我們就讓 make 報錯停止下來,
include config.mk
# $(info "ARM=$(ARM)")
# $(error "ARM=$(ARM)")
$(warning "ARM=$(ARM)")
ifeq ($(ARM), y)
CC = arm-linux-gcc
else
$(error "ARM=$(ARM)")
endif
all:
$(CC) hello.c
運行
$ make
Makefile:5: "ARM=y "
Makefile:10: *** "ARM=y ", 停止,
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/323048.html
標籤:其他
