最近在自己从头实现一个服务器。 慢慢把它做成符合mmorpg使用。做一个非hello world工程,第一件事就是makefile了。
这里是地址:
https://github.com/enjolras1205/my_server/blob/master/my_server/Makefile
此makefile的好处如下:
1、维护简单,文件、目录变动无需更改makefile:可作新makefile模板使用。
2、使用了预编译头,能加快编译速度。
我对makefile的理解很简单:目标的依赖关系与目标创建规则。
列一下此前在makefile使用上遇到过的槛,希望看到这篇文章的人不再遇到:
1、如何将中间文件输入到一个指定的目录。
2、如何遍历目录获得构建的目标。
3、如何生成依赖关系。
问题1:
通过改变目标文件创建规则,这样目标文件就放到BUILD_DIR目录下了。
# object file create rule
$(BUILD_DIR)/%.o: %.cpp $(PCH)
$(CXX) -c $(CXXFLAGS) $(INCLUDES) $< -o $@
问题2:
DIRS=$(shell find ./src -type d)
HEADERS=$(foreach dir_var,$(DIRS),$(wildcard $(dir_var)/*.h))
HEADER_DIRS=$(sort $(dir $(HEADERS)))
SRCS=$(foreach dir_var,$(DIRS),$(wildcard $(dir_var)/*.cpp))
SRC_DIRS=$(sort $(dir $(SRCS)))
OBJS=$(patsubst %.cpp,$(BUILD_DIR)/%.o,$(notdir $(SRCS)))
DEPS=$(patsubst %.o,%.d,$(OBJS))
INCLUDES=$(foreach dir_var,$(DIRS), -I $(dir_var))
第一行:通过find命令获得了src目录下的所有目录。
第二行:通过wildcard与foreach配合使用,遍历获得了所有的头文件。
第三行:dir获得目录,sort去重,得到了头文件目录。
第六行:通过patsubst字符串操作,得到了目标文件集合。
makefile内置函数的使用可以翻阅http://www.gnu.org/software/make/manual/make.pdf最后面的Index of Concepts。
问题3:
# depend file create rule
$(BUILD_DIR)/%.d: %.cpp
@echo "making $@"
@set -e; \
$(RM) [email protected]; \
$(CXX) -E -MM $(CXXFLAGS) $(INCLUDES) $(filter %.cpp,$^) > [email protected]; \
sed 's,\(.*\)\.o[:]*,$(BUILD_DIR)/\1.o $@:,g'<[email protected] > $@; \
$(RM) [email protected]
通过g++ -MM生成了依赖的非系统头文件,然后通过sed的字符串处理,生成了类似下面的内容。值得注意的是,依赖文件也对这些文件存在依赖,否则,这些文件改动时,依赖文件不会重新生成。导致依赖关系没有更新,编译出错误的程序。
./build/Acceptor_Func.o build/Acceptor_Func.d: src/utility/acceptor/Acceptor_Func.cpp \
src/utility/log/Log.h src/utility/builder/Singleton.h \
src/utility/thread/Thr_Mutex.h src/Pre_Header.h \
src/utility/thread/Thr_Mutex_Guard.h src/utility/thread/Thr_Mutex.h \
src/utility/builder/Repo_Factory.h src/utility/builder/Singleton.h \
src/utility/reactor/Reactor.h src/utility/builder/Obj_Pool.h \
src/utility/reactor/Svc.h src/utility/reactor/Event.h \
src/utility/sock/Sock_IO.h src/utility/sock/Sock.h \
src/utility/sock/IPC_SAP.h src/define/Define.h
另一个值得注意的是include前面的减号。
-include $(DEPS)
相较于不加减号,当依赖文件不存在时,makefile会用上面的依赖文件生成规则生成新的依赖文件再include。
最后:如何使用
mkdir src
cd src/
echo "#include " > Pre_Header.h
vim main.cpp,内容如下:
#include "Pre_Header.h"
int main()
{
std::cout<<"hello world"<
敲入make即可在build目录下生成名为my_server的hello world程序。