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中,否則會出現找不到動态庫檔案。
增加方法如下:
下載下傳示範代碼