1. 程式人生 > >Makefile分目錄編寫遇到的問題以及解決方法

Makefile分目錄編寫遇到的問題以及解決方法

最近在做boost相關的服務端開發,感覺程式多了之後資料夾裡面很亂,就想著把他們分在不同的資料夾裡面,這樣看起來也很舒服,而且也不會很low,畢竟要上傳到github上儲存版本。給別人看也方便許多。

多目錄的Makefile網上有許多教程大多類似,但是實際上應用的時候還是遇見了許多問題。

首先就是從src目錄裡面搜尋cpp檔案,在include目錄下面放標頭檔案。找到相應objs目錄下的.o檔案,最後編譯出來我們的主程式下面上我的程式碼。

CXX = g++


#src obj dep 檔案的查詢/生成路徑

SRC_DIR =  src

OBJ_DIR =  objs

DEPS_DIR = deps


#對cpp檔案 標頭檔案進行查詢

SRC  = $(wildcard $(SRC_DIR)/*.cpp)

LIBS =  -lpthread  -lboost_system

OBJS = $(addprefix $(OBJ_DIR)/,$(patsubst %.cpp,%.o,$(notdir $(SRC))))

DEPS =  $(addprefix $(DEPS_DIR)/,$(patsubst %.cpp,%.d,$(notdir $(SRC))))

#MySql編譯時需要的依賴

SQL_DEPENDS =  `mysql_config  --cflags  --libs`

BOOST_LIB_DIR = /home/mjf/lib/lib

BOOST_INCLUDE_DIR = /home/mjf/lib/include

HEADER_DIR =  -I ./include   -I/usr/include/mysql  -I$(BOOST_INCLUDE_DIR)

CXXFLAG = $(HEADER_DIR)  -o2  -g  -Wall  -std=c++11

#目標
TARGET = myserver


$(TARGET):$(OBJS)
	$(CXX)  -g  $^   $(SQL_DEPENDS)  -o $(TARGET) $(LIBS)  -L$(BOOST_LIB_DIR)

#@在makefile裡面表達的是解析shell命令 fi表示結束吧和if搭配?
$(OBJ_DIR)/%.o:$(SRC_DIR)/%.cpp
	@if [ ! -d $(OBJ_DIR) ]; then mkdir -p $(OBJ_DIR); fi; \
	$(CXX)  -c   $(HEADER_DIR)  $(SQL_DEPENDS)  $(LIBS)  -o 
[email protected]
$< $(DEPS_DIR)/%.d:$(SRC_DIR)/%.cpp @if [ ! -d $(DEFS_DIR) ]; then mkdir -p $(DEFS_DIR); fi; \ set -e;rm -f [email protected];\ $(CXX) -MM $(CXXFLAG) $< > [email protected]$$$$ ;\ sed 's,\($(notdir$*)\)\.o[ :]*,$(OBJ_DIR$*)\[email protected] : ,g' <
[email protected]
$$$$ > [email protected];\ rm -f [email protected]$$$$ -include $(DEPS) $(OBJS): .PHONY:clean clean: rm -f $(TARGET) rm -f $(OBJ_DIR)/*

下面就對上面的這段makefile解釋一下吧

  • addprefix指令是在後一項的前面加上字首,比如說 addprefix(he,llo.h) 其實就等於 hello.h
  • notdir把展開的檔案的路徑去掉,只顯示檔名而不包含其路徑資訊
  • patsubst進行替換的指令,替換的內容就是將.cpp檔案替換成相應相應的.d檔案,當然這個.cpp檔案的替換範圍是在 SRC裡面規定的。
  • wildcard是進行萬用字元匹配的函式,因為在makefile裡面萬用字元都被用了賦予了其他的含義,所以要在makefile裡面使用萬用字元匹配的話就需要使用到wildcard 搜尋 SRC_DIR/下所有cpp檔案
SRC  = $(wildcard $(SRC_DIR)/*.cpp)

LIBS =  -lpthread  -lboost_system

OBJS = $(addprefix $(OBJ_DIR)/,$(patsubst %.cpp,%.o,$(notdir $(SRC))))

DEPS =  $(addprefix $(DEPS_DIR)/,$(patsubst %.cpp,%.d,$(notdir $(SRC))))

下面的編譯內容以及指令

首先我們得知道為什麼需要編譯這個.d檔案,這個檔案是做什麼的。

根據GNU Make專案管理第二章規則的內容來看。我們可以使用makefile自動產生依存關係的功能,gcc -M指令會幫助我們檢視某一個檔案的依存有哪些,但是手動新增會給我們帶來麻煩,我們為每一個檔案生成它的依存關係,並且把它放入相應的d檔案之中。

所以為它建立一個工作目標,這樣make就會知道cpp檔案改變了,這時候就要更新.d檔案。那麼下面的的程式碼怎麼解釋?

首先就是 在建立.d檔案之前使用shell指令檢查一下要生成的檔案存不存在。@表示提醒make後面的指令是shell的

下面就是需要生成一個臨時檔案,這個檔案就是

[email protected]$$$$,  
$$$$會返回當前的執行的shell的程序號,就是說明這個檔案不會與其他的重複,沒什麼具體的意義,保證不會覆蓋而已。

-MM就是查詢依存項

下面使用sed表示式進行搜尋搜尋部分是\($(notdir$*)*\) 其中 \(\代表正則表示式的分組。.o[ :]*表示工作目標檔案之後可能會有一個或者多個空格或者冒號。後面是要替換的.o檔案放在OBJ_DIR目錄下面,最後查詢到所有的依賴之後就將它儲存在[email protected]之中,最後刪掉[email protected]$$$$

$(DEPS_DIR)/%.d:$(SRC_DIR)/%.cpp
	@if [ ! -d $(DEFS_DIR) ]; then mkdir -p $(DEFS_DIR); fi; \
	set  -e;rm -f [email protected];\
   $(CXX)  -MM  $(CXXFLAG)   $<  > [email protected]$$$$ ;\
	sed  's,\($(notdir$*)\)\.o[ :]*,$(OBJ_DIR$*)\[email protected] : ,g' <  [email protected]$$$$  >  [email protected];\
	rm -f [email protected]$$$$

-include $(DEPS)

遇到問題:之前遇到過.o檔案生成到根目錄下去了,後來發現是我的變數$(OBJ_DIR )後面有個空格就直接變成了 /%.o

還有出現過更新標頭檔案之後make沒有反應,查了一波發現.d檔案也沒有更新。所以最後在sed那裡都加上了路徑避免了問

 

我貼一下d檔案裡面大致有什麼東西好了,就是這種類似的路徑和依賴

service_main.o: src/service_main.cpp include/server_main.h \
 /home/mjf/lib/include/boost/asio.hpp \
 /home/mjf/lib/include/boost/asio/async_result.hpp \
 /home/mjf/lib/include/boost/asio/detail/config.hpp \
 /home/mjf/lib/include/boost/config.hpp \
 /home/mjf/lib/include/boost/config/user.hpp \