最近在自己从头实现一个服务器。 慢慢把它做成符合mmorpg使用。做一个非hello world工程,第一件事就是makefile了。
这里是地址:
https://github.com/enjolras1205/my_server/blob/master/my_server/Makefile
服务器echo功能都还没有,源码就先不放上来了。只有一个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:
通过调用shell,或者内置的函数。
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) $@.tmp; $(CXX) -E -MM $(CXXFLAGS) $(INCLUDES) $(filter %.cpp,$^) > $@.tmp; sed ‘s,\(.*\)\.o[:]*,$(BUILD_DIR)/\1.o $@:,g‘<$@.tmp > $@; $(RM) $@.tmp
通过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 <iostream>" > Pre_Header.h vim main.cpp,内容如下: #include "Pre_Header.h" int main() { std::cout<<"hello world"<<std::endl; return 0; }敲入make即可在build目录下生成名为my_server的hello world程序。