對於在Linux下編程來說,編寫一個好的Makefile是非常重要的,寫好了可以給編譯帶來極大的便利。而網上對於多目錄下Makefile的編寫講解的非常少, 有很多都不能達到目的。這裏參考了網上一篇Makefile,它是針對C語言的,寫的挺不錯。我將它改了一下,用於編譯C++的Makefile。
參考鏈接在這裏
https://blog.csdn.net/xiaoluoshan/article/details/78639961
1. 我的目錄結構
>> common-存放一些公共的頭文件。
>> debug-存放bin目錄和obj目錄,bin存放編譯的最終可執行文件,obj存放生成的目錄文件。
>> entity-存放實體的定義,包括頭.h和.cpp文件。
>> include-存放項目的頭文件。
>> network-存放socket通訊的封裝。
>> protocols-協議解析的封裝。
>> src-程序源文件,包括main函數實現在這裏。
2. 最外層Makefile的編寫,目錄結構如圖:
Makefile內容如下:
注意標紅的地方,由於項目用到了c++11標準的一些東西,故加這個選項:-std=c++11。另外注意一下最後標紅的這行的選項順序。另外特別注意,如果最外層目錄下有自己的目錄不進入編譯搜索,一定要使用awk排除排,否則編譯會報錯而中斷。這一句:
SUBDIRS=$(shell ls -l | grep ^d | awk '{if($$9 != "debug") print $$9}')
如果有多個目錄要排除,這裏要加入排除的其它目錄,這裏僅排除debug目錄。
3. debug目錄Makefile編寫,目錄結構如圖:
Makefile內容如下:
這裏我用到了libevent庫以及多線程,所以加入了編譯選項-levent –lpthread選項。
4. protocols目錄Makefile.
由於其會引用外部頭文件,所以Makefile中要加入包含路徑,這樣在程序代碼中可以不用包括頭文件的路徑。Makefile文件格式如下:
注意這裏,我加入了自己的頭文件路徑。再看代碼調用的頭文件引用:
#include "DataEntity.h"
引用了實體定義,不用帶路徑。
5. 其它目錄Makefile
其它目錄Makefile就基本都一樣了,需要引用頭文件就加入路徑,其它項都一樣:
6. 最後是一些Makefile編寫注意混淆的地方。
(1)Makefile中的 符號 $@, $^, $< 的意思:
$@ 表示目標文件
$^ 表示所有的依賴文件
$< 表示第一個依賴文件
$? 表示比目標還要新的依賴文件列表
(2)wildcard、notdir、patsubst的意思:
wildcard : 擴展通配符
notdir : 去除路徑
patsubst :替換通配符
g++ *.o -o $@ -lpthread -levent
注意,指定鏈接成目標文件格式,.o目標文件一定要在前面,中間-o,最後纔是最終生成的目標文件,位置不要調返了,否則編譯不通過。
(3) g++鏈接選項
-l+庫名,表示鏈接庫,如-lpthread表示鏈接pthread庫,前面要加路徑.
-levent表示需要連接libevent庫。
-l 參數就是用來指定程序要鏈接的庫,-l參數緊接着就是庫名。
-L 參數跟着的是庫文件所在的目錄名。
-i (小寫l) 編譯程序到系統默認路進搜索,如果找不到,到當前目錄,如果當前目錄找不到,則到LD_LIBRARY_PATH等環境變量置頂的路進去查找,如果還找不到,那麼編譯程序提示找不到庫。