1 簡介
Makefile是用來完成構(gòu)建距贷,編譯整個工程文件的工具柄冲。所以,Makefile定義了一系列的規(guī)則忠蝗,按照這個規(guī)則现横,即可生成可執(zhí)行文件或者中間文件等等。擴展開來什湘,與Makefile功能相似的工具有cmake,scons等等长赞。
在執(zhí)行make命令的時候,會在當前目錄下按順序查找文件名為"GNUmakefile"闽撤,"makefile"得哆,"Makefile"的文件。
1.1 參考資料
1.官方手冊:鏈接 (make 4.2版本)
2.從網(wǎng)絡上下載的Makefile教程:鏈接
3.簡單的Makefile文件編寫介紹:鏈接
1.2 環(huán)境
我使用的Make工具版本為:
CPU等信息如下:
系統(tǒng)為64位的哟旗。
我使用的代碼編輯工具為bluefish贩据。
需要額外安裝的工具為:
$ sudo apt-get install tree
2 開始編寫
2.1 示例
先看一個簡單的示例:
首先,我編寫兩個文件闸餐,一個是main.c饱亮,一個是Makefile文件,內(nèi)容分別如下:
main.c文件內(nèi)容:
#include <stdio.h>
static void main_show()
{
printf("---main show---\r\n");
}
int main(int argc,char *argv[])
{
main_show();
return 0;
}
Makefile內(nèi)容:
target:main.o
gcc -o target main.o
main.o:main.c
# gcc -c -o main.o main.c
gcc -c main.c
clean:
rm *.o target -rf
將它們保存在同一目錄位置下舍沙,然后執(zhí)行:
$ make
通過這個示例近上,我們需要簡單的知道幾點:
1.Makefile的基本規(guī)則:
target(目標):prerequisites(依賴)
command(命令)
目標:
可以是可執(zhí)行文件,也可以僅僅是一個標簽而已拂铡。
依賴:
也就是要生成目標所需要的文件壹无。
命令:
也就是執(zhí)行make需要執(zhí)行的命令葱绒。
上面所列出了的內(nèi)容,如果構(gòu)成了一個整體斗锭,這也叫顯示規(guī)則地淀。
2.makefile的注釋是使用'#'。
3.make執(zhí)行的時機是依賴文件比目標文件新岖是。
4.Makefile中的command(命令)帮毁,需要以Tab開始。
2.2 進一步的示例
main.c程序如下所示:
#include <stdio.h>
static void main_show()
{
printf("---main show---\r\n");
}
int main(int argc,char *argv[])
{
main_show();
return 0;
}
Makefile文件格式如下:
CC = gcc
target:main.o
$(CC) -o target main.o
main.o:main.c
# gcc -c -o main.o main.c
# gcc -c main.c
clean:
rm *.o target -rf
@echo "---make end---"
這里面所要說的就只要三個知識點:
1.自動推導豺撑,我們使用'#'注釋了gcc -c上的編譯內(nèi)容烈疚,然而,make中的自動推導前硫,還是會執(zhí)行注釋中的內(nèi)容胞得。
2.makefile中的變量,從上面的例子中屹电,可以看到阶剑,引用變量的值,需要使用$危号。
這里所使用的推導牧愁,也叫隱式規(guī)則。
3.在rm文件的時候外莲,使用了-rf標識猪半,這里是標識就算沒有文件,也不要在控制臺上報錯偷线,我們也可以將rm改為'-rm'磨确。這里對于inclulde <makefile>也是適用的,也就是說声邦,在當前目錄乏奥、/usr/local/bin、/usr/include等都未找到'makefile'文件的情況下亥曹,可以忽略致命錯誤邓了,繼續(xù)執(zhí)行下去。
4.可以適用@echo回顯內(nèi)容媳瞪,這對于我們調(diào)試一些makefile中的命令是很有幫助的骗炉,相當于我們在調(diào)試程序的時候使用printf。
2.3 自動化變量
自動化變量需要掌握的有幾個蛇受,分別為:$@ 句葵、$<、$^ 。
$@:
表示規(guī)則的目標文件名笼呆。
$<:
表示規(guī)則的第一個依賴文件名熊响。
$^:
表示規(guī)則的所有依賴文件列表。
我們在同一目錄下诗赌,建立三個文件,一個是main.c秸弛,一個是main_a.c铭若,一個是Makefile文件。
main.c內(nèi)容如下:
#include <stdio.h>
static void main_show()
{
printf("---main show---\r\n");
}
int main(int argc,char *argv[])
{
main_show();
main_a_show();
return 0;
}
main_a.c內(nèi)容為:
#include <stdio.h>
void main_a_show()
{
printf("---main_a_show---\r\n");
}
Makefile內(nèi)容為:
CC = gcc
requires = main.o main_a.o
target:$(requires)
$(CC) -o target $^
$(requires):%.o:%.c
$(CC) -c $< -o $@
clean:
rm *.o target -rf
@echo "---make end---"
從這個makefile中提煉出來的規(guī)則是:
target(目標):target-pattern(目標模式):prereq-patterns(依賴模式)
commands(命令)
當然可以簡化為:
target-pattern(目標模式):prereq-patterns(依賴模式)
commands(命令)
上面使用的方式递览,我們稱為靜態(tài)模式規(guī)則叼屠。
2.4 自動生成依賴關(guān)系
這比較適用于那些需要根據(jù)條件,自己尋找相應的.h文件的情況绞铃。做一個簡單的說明镜雨,比如新建一個main_a.h文件,里面定義一個#define MAIN_A 4儿捧,但是在makefile中并不做多余的說明荚坞,那么第一次編譯,然后獲取結(jié)果菲盾,是能夠得到正確的結(jié)果的颓影,但是,如果我們修改main.c文件的內(nèi)容懒鉴,然后修改main_a.h的內(nèi)容诡挂,將4改為5,再次執(zhí)行整個文件临谱,會發(fā)現(xiàn)打印的值仍然是4璃俗,這就與實際情況相悖。歸根結(jié)底悉默,我們需要讓makefile自動去推斷有哪些.h文件城豁,然后更新之后,也需要重新做出更改麦牺。
這里就需要了解一個選項'-M'
如下圖所示的適用方法:
2.5 Makefile中的函數(shù)
包括filter钮蛛,wildcard,patsubst等函數(shù)剖膳,以及sed魏颓,tr,grep等linux工具函數(shù)的配合使用:
貼上一個包含多個.c文件的文件夾下的Makefile:
CC = arm-linux-gnueabihf-gcc
CFLAGS = -lpthread -lm
FILES = $(wildcard *.c)
OBJS = $(patsubst %.c,%.o,$(FILES))
TARGET = socket
$(TARGET):$(OBJS)
$(CC) -o $@ $^ $(CFLAGS)
clean:
-rm *.o -rf
在該文件生效后吱晒,會在該目錄下生成一個socket的可執(zhí)行程序甸饱。
接著這個來說,如果我們的目錄下有很多的文件夾,文件夾下有很多的C文件叹话,這個時候有一個笨方法偷遗,也是一個比較簡單的方法,就是一個個文件加進去即可驼壶。
比如氏豌,我有一個文件夾,文件夾下有兩個文件热凹,分別為spi.c和spi.h泵喘,文件夾為spi,如下圖所示的結(jié)構(gòu)(.o暫時不用看):
我們可以寫的一個很笨的Makefile如下所示:
CC = arm-linux-gnueabihf-gcc
CFLAGS = -lpthread -lm
TARGET = socket
OBJS = $(patsubst %.c,%.o, $(wildcard *.c))
$(TARGET):$(OBJS) spi/spi.o
$(CC) -o $@ $^ $(CFLAGS)
clean:
rm $(TARGET) *.o
按照這個思路般妙,我們繼續(xù)做(使用sed,awk,tr,grep等等字符串操作命令)
首先我們需要提取出目錄纪铺。
這個比較簡單,我們使用如下命令即可:
wityuan@ubuntu:~/Desktop/A20_driver/socket_spi_bak$ ls -l | grep '^d'
drwxrwxr-x 2 wityuan wityuan 4096 9月 12 21:54 spi
wityuan@ubuntu:~/Desktop/A20_driver/socket_spi_bak$
現(xiàn)在我們所要做的就是將spi提取出來碟渺。
按照上面的字符串格式鲜锚,我們可以按照空格將字符串進行分割,spi剛好是第九個部分苫拍。
所以使用awk的正則表達進行切分芜繁。
$ ls -l | grep "^d" | awk '/ /{print $9}'
最終,提取文件夾的Makefile測試程序可以如下操作:
DIRS = $(shell ls -l | grep '^d' | awk '/ /{if($$9 != "test") print $$9}')
file:
@echo $(DIRS)
在這個思路的指導下怯疤,我寫出的一個Makefile如下:
CURRENT_DIR = $(shell pwd)
DIRS = $(shell ls -l | grep '^d' | awk '/ /{if($$9 != "test") print $$9}')
DIRS_FILE = $(foreach v,$(DIRS),-I $(CURRENT_DIR)/$v)
CC = arm-linux-gnueabihf-gcc
CFLAGS = -lpthread -lm -I $(CURRENT_DIR) $(DIRS_FILE)
TARGET = socket
OBJS = $(patsubst %.c,%.o, $(wildcard *.c))
DIRS_C = $(patsubst %.c,%.o,$(wildcard $(DIRS)/*.c))
$(TARGET):$(OBJS) $(DIRS_C)
$(CC) -o $@ $^ $(CFLAGS)
clean:
rm $(TARGET) *.o
其中DIRS_C目前支持1個文件夾浆洗。
解釋如下:
假若有一個文件夾,為spi集峦。則DIRS=spi伏社,DIRS_FILE為所有的類似DIRS文件。
2.6 待續(xù)塔淤。
http://www.cnblogs.com/Shirlies/p/4282182.html
3 學習開源項目的Makefile編寫
3.1 OSC
該源碼在官方上看起來已經(jīng)不好找了摘昌。
資源鏈接地址: 點我下載
這份源碼的Makefile最為簡單。