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 $@  $<

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

-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的

下面就是需要生成一个临时文件,这个文件就是

$@.$$$$,  
$$$$会返回当前的运行的shell的进程号,就是说明这个文件不会与其他的重复,没什么具体的意义,保证不会覆盖而已。

-MM就是查找依存项

下面使用sed表达式进行搜索搜索部分是\($(notdir$*)*\) 其中 \(\代表正则表达式的分组。.o[ :]*表示工作目标文件之后可能会有一个或者多个空格或者冒号。后面是要替换的.o文件放在OBJ_DIR目录下面,最后查找到所有的依赖之后就将它保存在$@之中,最后删掉$@.$$$$

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

-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 \

猜你喜欢

转载自blog.csdn.net/weixin_42427338/article/details/85461730
今日推荐