skynet学习笔记之makefile

前言

本文解析skynet的makefile执行流程,格式为 “文件名,代码;讲解” 或者 “文件名,讲解,下一行为代码”

流程1:只输入 make 的情况

 1. platform.mk,PLAT ?= none;此时 PLAT 没有设置,所以 none 赋值给 PLAT

 2. platform.mk;MAKE 是 make 程序设置的环境变量,值为 make,此时 PLAT = none,构建 default 这个目标要执行的命令是 make none,由于 default 没有依赖对象,所以直接执行 make none
		default:
			$(MAKE) $(PLAT)
			
 3. platform.mk;随后跳转到 none 这个目标,构建命令就是输出这两行提示,告诉你应该用 make 跟指定平台名,支持 linux freebsd macosx,我们这里就应该使用 make linux
 		none:
	 		@echo "Please do 'make PLATFORM' where PLATFORM is one of these:"
	 		@echo "    $(PLATS)"
 
 4. 因为 none 目标已经执行完成,所以流程结束
 

流程2:输入 make linux


 1. platform.mk,linux : PLAT = linux;直接跳转到构建 linux 的第一个目标处,给 PLAT 赋值为 linux
 
 2. platform.mk,macosx linux : SKYNET_LIBS += -ldl;添加 dlopen 库链接选项
 
 3. platform.mk,linux freebsd : SKYNET_LIBS += -lrt;添加 real_time 库链接选项
 
 4. platform.mk,执行 make all,后面跟上设置的变量值作为后续的编译参数
		linux macosx freebsd :
			$(MAKE) all PLAT=$@ SKYNET_LIBS="$(SKYNET_LIBS)" SHARED="$(SHARED)" EXPORT="$(EXPORT)" MALLOC_STATICLIB="$(MALLOC_STATICLIB)" SKYNET_DEFINES="$(SKYNET_DEFINES)"
			
 5. Makefile,all : jemalloc;第一个 all 目标依赖 jemalloc,先要构建 jemalloc
 
 6. Makefile,jemalloc : $(MALLOC_STATICLIB);目标 jemalloc 依赖 $(MALLOC_STATICLIB),先要构建 $(MALLOC_STATICLIB)
 
 7. Makefile,MALLOC_STATICLIB := $(JEMALLOC_STATICLIB);目标 MALLOC_STATICLIB 依赖 $(JEMALLOC_STATICLIB),先要构建 $(JEMALLOC_STATICLIB)
 
 8. Makefile,依赖 3rd/jemalloc/Makefile,如果不存在,则需要先构建
		 $(JEMALLOC_STATICLIB) : 3rd/jemalloc/Makefile
			cd 3rd/jemalloc && $(MAKE) CC=$(CC)
 
 9. Makefile,这里的管道符是表示 只有在目标不存在的时候,才会检查该管道符后面的依赖项;这里就是说如果 3rd/jemalloc/Makefile 已经存在了,就不需要在再检查 3rd/jemalloc/autogen.sh 是否存在了;因为是第一次编译,所以还没有生成过 3rd/jemalloc/Makefile,则需要检查 3rd/jemalloc/autogen.sh 是否存在,不存在则跳转到 3rd/jemalloc/autogen.sh 目标构建代码
		 3rd/jemalloc/Makefile : | 3rd/jemalloc/autogen.sh
			cd 3rd/jemalloc && ./autogen.sh --with-jemalloc-prefix=je_ --enable-prof 
 
 10. Makefile,下载关联的子库内容,这部分内容不直接打包在 skynet 库中,通过子库的方式存在,方便更新和替换
		 3rd/jemalloc/autogen.sh : 
			git submodule update --init
 
 11. 没有更多的依赖关系了,现在开始回溯执行各个目标的命令: 
 	1. git submodule update --init 执行后,3rd/jemalloc/autogen.sh 文件就有了
 	2. cd 3rd/jemalloc && ./autogen.sh --with-jemalloc-prefix=je_ --enable-prof 执行后,3rd/jemalloc/Makefile 文件就构建好了
 	3. cd 3rd/jemalloc && $(MAKE) CC=$(CC) 执行后,jemalloc 库就编译好了,第一个 all 目标构建完成,可以看到,skynet 提供了内存管理库的编译扩展,所以用 $(MALLOC_STATICLIB) 来间接指向 $(JEMALLOC_STATICLIB),想切换成其他内存管理库,则新加其他内存管理库的构建流程,然后替换 MALLOC_STATICLIB := $(JEMALLOC_STATICLIB) 这里的库变量名字即可,这就是扩展替代修改的设计原则
 
 12. 开始执行第二个 all 目标的构建
 
 13. Makefile,这里用反斜杠表示不换行,即是后续三排代码其实都是冒号后面的依赖内容,而不是命令
	 all : \
	  $(SKYNET_BUILD_PATH)/skynet \
	  $(foreach v, $(CSERVICE), $(CSERVICE_PATH)/$(v).so) \
	  $(foreach v, $(LUA_CLIB), $(LUA_CLIB_PATH)/$(v).so)
	  
 14. 解析第二个 all 目标的第一个依赖 skynet,这是最终生成的执行文件
 
 15. Makefile,依赖有 SKYNET_SRC 定义的引擎层 c 代码文件、lua 源码编译生成的静态库 liblua.a、内存管理静态库(默认是 libjemalloc.a)
		 $(SKYNET_BUILD_PATH)/skynet : $(foreach v, $(SKYNET_SRC), skynet-src/$(v)) $(LUA_LIB) $(MALLOC_STATICLIB)
			$(CC) $(CFLAGS) -o $@ $^ -Iskynet-src -I$(JEMALLOC_INC) $(LDFLAGS) $(EXPORT) $(SKYNET_LIBS) $(SKYNET_DEFINES)
	
	- liblua.a 由命令 cd 3rd/lua && $(MAKE) CC='$(CC) -std=gnu99' $(PLAT) 编译而成
	- libjemalloc.a 由第一个 all 目标的构建而成,先前已经讲了

16. 解析第二个 all 目标的第二个依赖 $(foreach v, $(CSERVICE), $(CSERVICE_PATH)/$(v).so) ,即是 c 服务模块所在的动态库文件,cservice/*.so

17. Makefile,定义 CSERVICE_TEMP 函数来构建单个 c 服务模块的 .so 库文件
	define CSERVICE_TEMP
  $$(CSERVICE_PATH)/$(1).so : service-src/service_$(1).c | $$(CSERVICE_PATH)
	$$(CC) $$(CFLAGS) $$(SHARED) $$< -o $$@ -Iskynet-src
endef

18. Makefile,遍历 CSERVICE = snlua logger gate harbor 定义的 c 服务名,作为参数传给 CSERVICE_TEMP 函数,通过 eval 函数,展开每个服务库的构建代码到 makefile 文件中,然后在 make 执行时构建完成 cservice/*.so
	 $(foreach v, $(CSERVICE), $(eval $(call CSERVICE_TEMP,$(v))))

19. 解析第二个 all 目标的第三个依赖 $(foreach v, $(LUA_CLIB), $(LUA_CLIB_PATH)/$(v).so),即是 skynet 为支持 lua 服务提供的一些 c 代码编写的动态库文件,luaclib/*.so

20. Makefile,依次编译这些 lua 库,他们的使用方式是在 lua 服务中,require "库名.core"
	- $(LUA_CLIB_PATH)/skynet.so :
	- $(LUA_CLIB_PATH)/bson.so :
	- $(LUA_CLIB_PATH)/md5.so 
	- $(LUA_CLIB_PATH)/client.so :
	- $(LUA_CLIB_PATH)/sproto.so :
	- $(LUA_CLIB_PATH)/ltls.so :
	- $(LUA_CLIB_PATH)/lpeg.so :

21. 到此,skynet 的编译流程全部结束。

结语

总览 skynet 的 makefile 编译目标是:

  • 构建框架引擎执行文件 skynet,依赖内存管理库 libjemalloc.a
  • 构建 c 服务模块所在的动态库 cservice/xxx.so,例如 cservice/logger.so
  • 构建为支持 lua 服务提供的一系列 c 动态库 luaclib/xxx.so,例如 luaclib/skynet.so

skynet 并没有将这两种动态库链接到执行文件 skynet 中,而是通过代码中需要用到的时候动态加载:

  • skynet_module.c 中加载 c 服务模块时,通过系统调用 dlopen 来加载 cservice/*.so
  • lua 代码中加载 c 动态库时,通过 require xxx.core 来加载 luaclib/*.so,详细流程可见 skynet学习笔记之require xxx.core

你可能感兴趣的:(skynet,linux,lua,开发语言,c语言)