天天看點

Makefile編寫規則

make是一個指令工具,它解釋Makefile 中的指令規則。在makefile檔案中描述了整個工程所有檔案的編譯順序、編譯規則。makefile 有自己的書寫格式、關鍵字、函數。像C 語言有自己的格式、關鍵字和函數一樣。而且在makefile 中可以使用系統shell所提供的任何指令來完成想要的工作。makefile(在其它的系統上可能是另外的檔案名)在絕大多數的IDE 開發環境中都在使用,已經成為一種工程的編譯方法。

.o字尾檔案:編譯生成的中間代碼檔案;

.a字尾檔案:靜态庫檔案,編譯的時候會合到可執行程式中,檔案比較大;

.so字尾檔案:動态庫檔案,隻是一個指向,不會合到可執行程式中,當要調用函數庫的時候才使用;

一、Makefile的規則

  目标 : 需要的條件 (注意冒号兩邊有空格)

  指令   (注意前面用tab鍵開頭)

解釋一下:

  1. 目标可以是一個或多個,可以是Object File,也可以是執行檔案,甚至可以是一個标簽。

  2. 需要的條件就是生成目标所需要的檔案或目标

  3. 指令就是生成目标所需要執行的腳本

二、make是如何工作

 在預設的方式下,也就是我們隻輸入make指令。

1、make會在目前目錄下找名字叫“Makefile”或“makefile”的檔案。

2、如果找到,它會找檔案中的第一個目标檔案(target),并把這個檔案作為最終的目标檔案。

3、如果目标檔案不存在,或是目标檔案所依賴的後面的 .o 檔案的檔案更新時間比目标檔案更新時間早,則就會執行後面所定義的指令來重新生成目标檔案。

4、如果目标檔案所依賴的.o檔案也不存在,那麼make會在目前檔案中找目标為.o檔案的依賴性,如果找到則再根據那一個規則生成.o檔案。

5、make會生成目标檔案對應的.o 檔案,然後再用 .o 檔案生成執行檔案。

三、常用變量和符号

$+

:所有的依賴檔案,以空格分開,并以出現的先後為序,可能包含重複的依賴檔案。

$?

:所有的依賴檔案,以空格分開,這些依賴檔案的修改日期比目标的建立日期晚。

$^

:所有的依賴檔案,以空格分開,不包含重複的依賴檔案。

$<

:第一個依賴檔案的名稱。

$@

:目标的完整名稱。

$*

:不包含擴充名的目标檔案名稱。

$%

:如果目标是歸檔成員,則該變量表示目标的歸檔成員名稱

@echo

:這個指令是輸出一行字元串。

四、常用編譯項說明

-I:指定頭檔案搜尋的路徑

-L:連接配接需要的庫檔案路徑

–l:連接配接需要的庫檔案(比如:libpthread.so寫作 –lpthread)

# :注釋符号

\ :如果一行太長,我們可以通過 符号 \ 來進行換行

-c:意味着産生object檔案

五、字尾規則

.SUFFIXES:.cpp .hpp .c .h .o .so .ec .C .sqc

制定新的字尾規則。

(%.c:%.sqc),(%.o:%.c)

即規則行為。就是将所有.sqc轉為.c,.c再轉為.o。

.c.o:

等價于

%.o:%.c

六、make編譯

1.編譯可執行程式

假設主函數

main.c

中調用的有3個檔案

file1.c, file2.c, file3.cpp

和3個頭檔案

file1.h, file2.h, file3.h

注意$(CC) 等前的縮進才用tab按鍵,不能采用空格替代。

main.c内容如下:

#include "file1.h"
#include "file2.h"
#include "file3.h"
int main()
{
    //這裡有N多代碼調用file1 file2 file3中方法

    return ;
}
           

makefile檔案内容:

TARGET =  main

CC =  g++ 
CCFLAGS =  -g -Wall

#依賴庫檔案
LIB =  -lpthread

#目前目錄和CPPINC目錄下查找原檔案
CPPINC = /usr/include
INC = -I. -I$(CPPINC)

#建立執行檔案路徑
BIN_DIR = ./bin/
$(shell mkdir -p ${BIN_DIR})

all : $(TARGET)
main: main.o file1.o file2.o file3.o
    $(CC) $(CCFLAGS) -o $@ $^ $(INC) $(LIB) 

#編譯所有.cpp檔案為.o檔案
.cpp.o: 
    @echo $<
    $(CC) $(CCFLAGS) -c -o $@ $< 
    #$(CC) $(CCFLAGS)  -c -o $*.o $*.cpp $(INC) $(LIB)

#編譯所有.c檔案為.o檔案
.c.o:
    @echo $<
    $(CC) $(CCFLAGS) -c -o $@ $< 
    #$(CC)  $(CCFLAGS) -c -o $*.o $*.c  $(INC) $(LIB)
clean: 
    - rm -f *.o   $(TARGET)
           

2.編譯靜态庫

編譯生成靜态庫

libfiletest.a

并調用在

main.c

中調用

CC =  g++ 
CCFLAGS =  -g -Wall
#生成靜态庫檔案指令
AR = ar rc

#依賴庫檔案
LIB =  -lpthread

#目前目錄和CPPINC目錄下查找原檔案
CPPINC = /usr/include
INC = -I. -I$(CPPINC)

#調用shell腳本,建立靜态庫檔案和執行檔案目錄
LIB_DIR = ./lib/
BIN_DIR = ./bin/
$(shell mkdir -p ${LIB_DIR})
$(shell mkdir -p ${BIN_DIR})

#靜态庫檔案變量
LIB_OBJECT = libfiletest.a
BIN_OBJECT = main

TEST_LIB = -L./lib -lfiletest

all:$(LIB_OBJECT) $(BIN_OBJECT)

$(LIB_OBJECT):file1.o file2.o file3.o
    $(AR) $@ $^
    #将生成的檔案移動到對應的檔案夾
    mv $(LIB_OBJECT) $(LIB_DIR)

$(BIN_OBJECT): main.o
    $(CC) $(CCFLAGS) -o $@ $^ $(TEST_LIB)
    mv $(BIN_OBJECT) $(BIN_DIR)

#編譯所有.cpp檔案為.o檔案
.cpp.o: 
    @echo $<
    $(CC) $(CCFLAGS) -c -o $@ $< 
    #$(CC) $(CCFLAGS)  -c -o $*.o $*.cpp $(INC) $(LIB)

#編譯所有.c檔案為.o檔案
.c.o:
    @echo $<
    $(CC) $(CCFLAGS) -c -o $@ $< 
    #$(CC)  $(CCFLAGS) -c -o $*.o $*.c  $(INC) $(LIB)
clean: 
    - rm -f *.o   $(LIB_DIR)$(LIB_OBJECT) $(BIN_DIR)$(BIN_OBJECT)
           

3.編譯so動态庫

CC =  g++ 
CCFLAGS =  -g -Wall

SHARED = -shared -o
FPIC = -fPIC -c

#依賴庫檔案
LIB =  -lpthread

#目前目錄和CPPINC目錄下查找原檔案
CPPINC = /usr/include
INC = -I. -I$(CPPINC)

#調用shell腳本,建立動态庫檔案和執行檔案目錄
LIB_DIR = ./lib/
BIN_DIR = ./bin/
$(shell mkdir -p ${LIB_DIR})
$(shell mkdir -p ${BIN_DIR})

#動态庫檔案變量
LIB_OBJECT = libfiletest.so
BIN_OBJECT = main

TEST_LIB = -L./lib/ -lfiletest

all:$(LIB_OBJECT) $(BIN_OBJECT)
OBJECT =file1.o file2.o file3.o
SRC_OBJECT =file1.c file2.c file3.cpp
H_OBJECT = file1.h file2.h file3.h

$(LIB_OBJECT):$(OBJECT)
    $(CC) $(CCFLAGS) $(SHARED) -fPIC -o $@ $^
    mv $(LIB_OBJECT) $(LIB_DIR)

$(OBJECT):$(SRC_OBJECT) $(H_OBJECT)
    $(CC) $(FPIC) $(SRC_OBJECT)

$(BIN_OBJECT): main.o
    $(CC) $(CCFLAGS) -o $@ $^ $(TEST_LIB)
    mv $(BIN_OBJECT) $(BIN_DIR)

main.o: main.c
    $(CC) $(CCFLAGS) -c $^
clean: 
    - rm -f *.o   $(LIB_DIR)$(LIB_OBJECT) $(BIN_DIR)$(BIN_OBJECT)
           

注意生成動态庫後調用動态庫時需要将動态庫的路徑增加到LD_LIBRARY_PATH中,否則會出現找不到動态庫檔案。

增加方法如下:

下載下傳示範代碼