C++服务框架

一、服务框架初步

1. 目录结构规划(make编译)

注意:不管是目录还是文件,文件名一律不要带空格和用中文,最好的方式:字母、数字、下划线

规定项目的主目录,例如:nginx

  1. include目录:专门存放各种头文件
  2. app目录:放主应用程序.c(main()函数所在的文件)以及一些比较核心的文件。
    2.1 link_obj:临时目录,会存放临时的.o文件,这个目录不手动创建,后续makefile脚本来创建。
    2.2 dep:临时目录,会存放临时的.d开头的依赖文件,依赖文件能够告知系统哪些相关的文件发生变化,需要重新编译;后续makefile脚本来创建。
    2.3 nginx.c:主文件,main()入口函数文件
    2.4 ngx_conf.c,普通的源码文件,和主文件关系密切,又不值得单独放在一个目录。
  3. misc目录:专门放各种不好归类的1到多个.c文件。
  4. net目录:专门存放网络处理相关文件。
  5. proc目录:专门处理进程相关文件。
  6. signal目录:专门存放信号处理相关文件。

Linux 下查看目录结构命令:

tree	//如果没安装 就 sudo apt install tree

在这里插入图片描述

2. 编译工具make的使用概述(编译出可执行文件)

在这里插入图片描述
每个.c生成一个.o,多个.c就生成多个.o,最终这些.o被链接到一起,生成一个可执行文件。

  1. 我们要借助make命令来编译:能够编译,链接。。。最后生成可执行文件,大型项目一般由make来做。
  2. make命令的工作原理,就是去当前目录读取一个makefile的文件(文本文件),根据makefile文件里的规则(依赖关系)把源代码编译成可执行文件。有类似工具autotools自动生成makefile.
  3. makefile文件:文本文件,utf8编码格式,没有扩展名,一般放在根目录下【也可根据需要放在子目录下】
  • 规划一下makefile文件的编写,nginx目录下会放三个文件:
  1. makefile:是编译项目的入口脚本,编译项目从这里开始,起总体控制作用。
  2. config.mk:配置脚本,被makefile文件包含;单独分离出来是为了应付一些可变的东西。
  3. common.mk:最重要最核心的编译脚本,定义makefile的编译规则、依赖规则等,通用性很强,并且各个子目录中都用到这个文件,来实现对应子目录下的.c文件的编译。
  • 每个子目录下下(app,signal)都有一个叫makefile的文件,每个这个makefile文件,都会包含根目录下的common.mk从而实现这个子目录下的.c文件的编译。
  • 其他规划:
  1. /app/link_obj:临时目录,存放.o目标文件。
  2. /app/dep:存放.d开头的依赖关系文件。

3. makefile脚本用法介绍

  1. 编译项目,生成可执行文件 make、make clean
    在这里插入图片描述

4. makefile脚本具体实现

makefile文件编写
4.1目录
在这里插入图片描述
4.2 makefile 代码
注: 带 #行 的 全是注释,不是代码~~~

include config.mk
all:
#-C是指定目录
#make -C signal   

#可执行文件应该放最后
#make -C app      

#用shell命令for搞,shell里边的变量用两个$
	@for dir in $(BUILD_DIR); \
	do \
		make -C $$dir; \
	done


clean:
#-rf:删除文件夹,强制删除
	rm -rf app/link_obj app/dep nginx
	rm -rf signal/ *. gch app/ * .gch

4.3 config.mk 代码

#定义项目编译的根目录,通过export把某个变量声明为全局的[其他文件中可以用],这里获取当前这个文件所在的路径作为根目录;
#BUILD_ROOT = /mnt/hgfs/linux/nginx
export BUILD_ROOT = $(shell pwd)

#定义头文件的路径变量
export INCLUDE_PATH = $(BUILD_ROOT)/_include

#定义我们要编译的目录
BUILD_DIR = $(BUILD_ROOT)/signal/ \
			$(BUILD_ROOT)/app/ 

#编译时是否生成调试信息。GNU调试器可以利用该信息
export DEBUG = true

4.4 common.mk 代码

#.PHONY:all clean 

ifeq ($(DEBUG),true)
#-g是生成调试信息。GNU调试器可以利用该信息
CC = gcc -g
VERSION = debug
else
CC = gcc
VERSION = release
endif

#CC = gcc
# $(wildcard *.c)表示扫描当前目录下所有.c文件
#SRCS = nginx.c ngx_conf.c
SRCS = $(wildcard *.c)

#OBJS = nginx.o ngx_conf.o  这么一个一个增加.o太麻烦,下行换一种写法:把字符串中的.c替换为.o
OBJS = $(SRCS:.c=.o)

#把字符串中的.c替换为.d
#DEPS = nginx.d ngx_conf.d
DEPS = $(SRCS:.c=.d)

#可以指定BIN文件的位置,addprefix是增加前缀函数
#BIN = /mnt/hgfs/linux/nginx
BIN := $(addprefix $(BUILD_ROOT)/,$(BIN))

#定义存放ojb文件的目录,目录统一到一个位置才方便后续链接,不然整到各个子目录去,不好链接
#注意下边这个字符串,末尾不要有空格等否则会语法错误 
LINK_OBJ_DIR = $(BUILD_ROOT)/app/link_obj
DEP_DIR = $(BUILD_ROOT)/app/dep

#-p是递归创建目录,没有就创建,有就不需要创建了
$(shell mkdir -p $(LINK_OBJ_DIR))
$(shell mkdir -p $(DEP_DIR))

#我们要把目标文件生成到上述目标文件目录去,利用函数addprefix增加个前缀
#处理后形如 /mnt/hgfs/linux/nginx/app/link_obj/ngx_signal2.o /mnt/hgfs/linux/nginx/app/link_obj/ngx_signal.o
# := 在解析阶段直接赋值常量字符串【立即展开】,而 = 在运行阶段,实际使用变量时再进行求值【延迟展开】
# /mnt/hgfs/linux/nginx/app/link_obj/nginx.o   /mnt/hgfs/linux/nginx/app/link_obj/ngx_conf.o 
OBJS := $(addprefix $(LINK_OBJ_DIR)/,$(OBJS))
DEPS := $(addprefix $(DEP_DIR)/,$(DEPS))

#找到目录中的所有.o文件(编译出来的)
LINK_OBJ = $(wildcard $(LINK_OBJ_DIR)/*.o)
#因为构建依赖关系时app目录下这个.o文件还没构建出来,所以LINK_OBJ是缺少这个.o的,我们 要把这个.o文件加进来
LINK_OBJ += $(OBJS)

#-------------------------------------------------------------------------------------------------------
#make找第一个目标开始执行[每个目标[就是我们要生成的东西],其实都是定义一种依赖关系],目标的格式为:
#目标:目标依赖【可以省略】
#	要执行的命令【可以省略】
#如下这行会是开始执行的入口,执行就找到依赖项$(BIN)去执行了,同时,这里也依赖了$(DEPS),这样就会生成很多.d文件了
all:$(DEPS) $(OBJS) $(BIN)

#这里是诸多.d文件被包含进来,每个.d文件里都记录着一个.o文件所依赖哪些.c和.h文件。内容诸如 nginx.o: nginx.c ngx_func.h
#我们做这个的最终目的说白了是,即便.h被修改了,也要让make重新编译我们的工程,否则,你修改了.h,make不会重新编译,那不行的
#有必要先判断这些文件是否存在,不然make可能会报一些.d文件找不到
ifneq ("$(wildcard $(DEPS))","")   #如果不为空,$(wildcard)是函数【获取匹配模式文件名】,这里 用于比较是否为""
include $(DEPS)  
endif

#----------------------------------------------------------------1begin------------------
#$(BIN):$(OBJS)
$(BIN):$(LINK_OBJ)
	@echo "------------------------build $(VERSION) mode--------------------------------!!!"

#一些变量:$@:目标,     $^:所有目标依赖
# gcc -o 是生成可执行文件
	$(CC) -o $@ $^

#----------------------------------------------------------------1end-------------------


#----------------------------------------------------------------2begin-----------------
#%.o:%.c
$(LINK_OBJ_DIR)/%.o:%.c
# gcc -c是生成.o目标文件   -I可以指定头文件的路径
#如下不排除有其他字符串,所以从其中专门把.c过滤出来 
#$(CC) -o $@ -c $^
	$(CC) -I$(INCLUDE_PATH) -o $@ -c $(filter %.c,$^)
#----------------------------------------------------------------2end-------------------



#----------------------------------------------------------------3begin-----------------
#我们现在希望当修改一个.h时,也能够让make自动重新编译我们的项目,所以,我们需要指明让.o依赖于.h文件
#那一个.o依赖于哪些.h文件,我们可以用“gcc -MM c程序文件名” 来获得这些依赖信息并重定向保存到.d文件中
#.d文件中的内容可能形如:nginx.o: nginx.c ngx_func.h
#%.d:%.c
$(DEP_DIR)/%.d:%.c
#gcc -MM $^ > $@
#.d文件中的内容形如:nginx.o: nginx.c ngx_func.h ../signal/ngx_signal.h,但现在的问题是我们的.o文件已经放到了专门的目录
# 所以我们要正确指明.o文件路径这样,对应的.h,.c修改后,make时才能发现,这里需要用到sed文本处理工具和一些正则表达式语法,不必深究
#gcc -MM $^ | sed 's,\(.*\)\.o[ :]*,$(LINK_OBJ_DIR)/\1.o:,g' > $@
#echo 中 -n表示后续追加不换行
	echo -n $(LINK_OBJ_DIR)/ > $@
#	gcc -MM $^ | sed 's/^/$(LINK_OBJ_DIR)&/g' > $@
#  >>表示追加
	gcc -I$(INCLUDE_PATH) -MM $^ >> $@

#上行处理后,.d文件中内容应该就如:/mnt/hgfs/linux/nginx/app/link_obj/nginx.o: nginx.c ngx_func.h ../signal/ngx_signal.h

#----------------------------------------------------------------4begin-----------------



#----------------------------------------------------------------nbegin-----------------
#clean:			
#rm 的-f参数是不提示强制删除
#可能gcc会产生.gch这个优化编译速度文件
#	rm -f $(BIN) $(OBJS) $(DEPS) *.gch
#----------------------------------------------------------------nend------------------
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值