一文掌握MAKEFILE和GCC

CC :=g++
LD :=g++
SRCDIR := src
BUILDDIR := build
TARGET :=bin/target

SRCEXT:=cpp
SOURCES:=$(shell find $(SRCDIR) -type f -name *.$(SRCEXT))
OBJECTS:=$(patsubst $(SRCDIR)/%, $(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.o))
DEP:=$(OBJECTS:%.o=%.d)
CFLAGS:= 
LDFLAGS:= 
INC:= -I include

$(TARGET):$(OBJECTS)
    @echo "Linking..."
    @echo "$(LD) $^ -o $(TARGET) $(LIB)"
    $(LD) -o $(TARGET)  $^ $(LDFLAGS) 

-include $(DEP)
$(BUILDDIR)/%.o: $(SRCDIR)/%.$(SRCEXT)
    @mkdir -p $(sort $(dir $(OBJECTS)))
    @echo "$(CC) $(CFLAGS) $(INC) -c -o $@ $<"
    $(CC) $(CFLAGS) $(INC) -MM -MT $@ -MF $(patsubst %.o, %.d, $@) $<
    $(CC) $(CFLAGS) $(INC) -c -o $@ $<

    #$(CC) $(CFLAGS)  -MMD -c -o $@ $<
clean:
    @echo "cleaning...";
    @echo "$(RM) -r $(BUILDDIR) $(TARGET)";
    $(RM) -r $(BUILDDIR) $(TARGET)
.PHONY:clean


├── bin
│   ├── target
│ 
├── build
│   ├── main.d
│   ├── main.o
│   ├── code.d
│   └── code.o
├── include
│   └── code.hpp
├── makefile
├── src
    ├── main.cpp
    └── code.cpp

-k:它的作用是讓make命令在發現錯誤時仍然繼續執行,而不是在檢測到第一個錯誤時就停下來。
-n:它的作用是讓make命令輸出將要執行的操作步驟,而不真正執行這些操作
-f :它的作用是告訴make命令將哪個文件作爲makefile文件。如果未使用這個選項,標準版本的make

= 是最基本的賦值,makefile展開後最終的值
:= 是覆蓋之前的值,決定於它在makefile中的位置當前值
?= 是如果沒有被賦值過就賦予等號後面的值
+= 是添加等號後面的值


.PHONY是一個僞目標,可以防止在Makefile中定義的只執行命令的目標和工作目錄下的實際文件出現名字衝突,
    另一種是提交執行makefile時的效率
    當一個目標被聲明爲僞目標後,make在執行此規則時不會試圖去查找隱含規則來創建這個目標
訪問shell內變量兩個$$,訪問makefile變量需要加$()或者${}
執行shell兩種方式$(shell find $(SRCDIR), `find $(SRCDIR)`
echo:會在shell中顯示echo這條命令和這條命令的輸出結果
@echo:不會在shell中顯示echo這條命令,但是會顯示命令的輸出結果
加上“-”,即使這條命令出錯,makefile也會繼續執行後續命令的

make -C subdir

make -C /lib/modules/`uname -r`/build M=`pwd`/drivers/net/usb obj-m=GobiNet.o modules

make -C /usr/src/linux M=/usr/src/linux/drivers/net/ethernet/intel/igb modules

* :表示目標文件的名稱,不包含目標文件的擴展名。
+ :表示所有的依賴文件,這些依賴文件之間以空格分開,按照出現的先後爲順序,其中可能包含重複的依賴文件。
< :表示依賴項中第一個依賴文件的名稱
? :依賴項中,所有目標文件時間戳晚的文件(表示修改過),依賴文件間以空格分開
@ :目標項中目標文件的名稱
^ :依賴項中,所有不重複的依賴文件,以空格分開

shell環境下:

$$: 代表shell本進程的PID(Process ID)
$?: 最後運行結束的進程的結束碼(返回值)
$*: 所有的的參數列表,以"$1 $2 ...$n"的形式表示
$@: 所有的參數列表,以"$1" "$2" ..."$n"的形式表示
$#: 所有參數的個數
$0: 運行程序的文件名

Shell腳本在target裏纔有效,其它地方都被忽略掉了
把每一行Shell腳本當作一個獨立的單元
make在調用Shell之前先進行預處理,即展開所有Makefile的變量和函數。這些變量和函數都以$開頭
make預處理時,所有以$開頭的,它都不會放過。要想引用Shell自己的變量,應該以$$開頭。
另外要注意,Shell自己的變量是不需要括號的

main:main.o code1.o code2.o
gcc -o main main.o code1.o code2.o
main.o:main.c code1.h code2.h
gcc -c main.c
code1.o:code1.c code1.h
gcc -c code1.c
code2.o:code2.c code2.h
gcc -c code2.c

main:main.o code1.o code2.o
gcc -o $@ $^
.c.o:
gcc -c $<
這個規則表示所有的 .o文件都是依賴與相應的.c文件的


-E: 預處理,主要是進行宏展開等步驟,生成的文件微test.i
gcc -E test.c

-S: 編譯,生成彙編代碼,生成的文件爲test.S
gcc -S test.c

-c: 彙編:生成機器碼,生成的文件未test.o
gcc -c test.c

(-o): 鏈接:生成可執行文件
gcc test.c (-o test)

-I後面緊跟着用戶設定的編譯器頭文件查找路徑
-L後面緊跟着用戶設定的編譯器庫文件查找路徑
-Wall,打開gcc的所有警告。
-W選項類似-Wall,會顯示警告,但是隻顯示編譯器認爲會出現錯誤的警告
-Werror,它要求gcc將所有的警告當成錯誤進行處理。
-D,其意義是添加宏定義

1、wildcard : 擴展通配符
    src=$(wildcard *.c ./sub/*.c)
    wildcard把 指定目錄 ./ 和 ./sub/ 下的所有後綴是c的文件全部展開。
2、notdir : 去除路徑
    dir=$(notdir $(src))
3、patsubst :替換通配符
    $(patsubst <pattern>,<replacement>,<text> ) 
    $(patsubst %.c,%.o,$(dir) )
    patsubst把$(dir)中的變量符合後綴是.c的全部替換成.o,
4、    foo := a.o b.o c.o;
    bar := $(foo:.o=.c)
    將變量“foo”以空格分開的值中的所有的字的尾字符“o”替換爲“c”,其他部分不變。

    
1、“=”    make會將整個makefile展開後,再決定變量的值。也就是說,變量的值將會是整個makefile中最後被指定的值。
            x = foo
            y = $(x) bar
            x = xyz
        在上例中,y的值將會是 xyz bar ,而不是 foo bar 。

2、“:=”    表示變量的值決定於它在makefile中的位置,而不是整個makefile展開後的最終值。
            x := foo
            y := $(x) bar
            x := xyz
        在上例中,y的值將會是 foo bar ,而不是 xyz bar 了。

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