skynet源码分析 make

skynet源码分析 make

前言

本文的版本选择的是skynet v1.4.0。编译skynet不可以避免的就是make。

本文就具体看看make相关的实现。

关于make可以参考 阮一峰的网络日志

另外本文只涉及最上层的Makefile,对于子目录下的Makefile就不做分析了。

附录是一些GCC的参数。

正文

当我们在skynet目录下执行make linux实际上我们就是在执行 Makefile里的命令。在该文件的首行有该语句:

include platform.mk

platform.mk

逻辑大致如下:

  1. 判断是否有传入正确的平台linux freebsd macosx。如果没有,打印错误信息退出:

    wyw@DESKTOP-GJ20UDC:~/skynet$ make
    make none
    make[1]: Entering directory '/home/wyw/skynet'
    Please do 'make PLATFORM' where PLATFORM is one of these:
       linux freebsd macosx
    make[1]: Leaving directory '/home/wyw/skynet'
    

    如果传入了错误的平台,会有类似的打印:

    wyw@DESKTOP-GJ20UDC:~/skynet$ make l
    make: *** No rule to make target 'l'.  Stop.
    
  2. 根据不同的平台设定不同的变量,这里设置的变量会在Makefile中使用到。例如make linux。执行到最后命令如下:

    # make all PLAT=linux SKYNET_LIBS="-lpthread -lm -ldl -lrt" SHARED="-fPIC --shared" EXPORT="-Wl,-E" MALLOC_STATICLIB="" SKYNET_DEFINES=""
    $(MAKE) all PLAT=$@ SKYNET_LIBS="$(SKYNET_LIBS)" SHARED="$(SHARED)" EXPORT="$(EXPORT)" MALLOC_STATICLIB="$(MALLOC_STATICLIB)" SKYNET_DEFINES="$(SKYNET_DEFINES)"
    

Makefile

回归到Makefile,在include后设置了一些平台相关的值。并且是执行make all

逻辑大致如下:

  1. 生成jemalloc
  2. 生成skynet相关的部分

jemalloc

Jemalloc 是一款内存分配器,与其它内存分配器相比,它最大的优势在于多线程情况下的高性能以及内存碎片的减少。

阅读skynet项目中的README.md。其中有句话是这样的:

For Linux, install autoconf first for jemalloc

其原因在稍后我们再揭晓,先来分析Makefile。

起始语句:

# 定义变量MALLOC_STATICLIB
JEMALLOC_STATICLIB := 3rd/jemalloc/lib/libjemalloc_pic.a
MALLOC_STATICLIB := $(JEMALLOC_STATICLIB)

all : jemalloc
# 声明伪目标 jemalloc update3rd
.PHONY : jemalloc update3rd
# 伪目标前提是 $(MALLOC_STATICLIB)
jemalloc : $(MALLOC_STATICLIB)
# 前提是先生成 3rd/jemalloc/Makefile,后执行命令cd 3rd/jemalloc && $(MAKE) CC=$(CC)
# 这一步的make 中需要用到 AUTOCONF := /usr/bin/autoconf
$(JEMALLOC_STATICLIB) : 3rd/jemalloc/Makefile
	cd 3rd/jemalloc && $(MAKE) CC=$(CC) 
# 生成3rd/jemalloc/Makefile  order-only先决条件 从git拉取模块

3rd/jemalloc/Makefile : | 3rd/jemalloc/autogen.sh
	# 执行autogen.sh
	cd 3rd/jemalloc && ./autogen.sh --with-jemalloc-prefix=je_ --enable-prof

3rd/jemalloc/autogen.sh :
	git submodule update --init

skynet

这部分的内容就比较多,先是一些变量的定义。

CSERVICE = snlua logger gate harbor
LUA_CLIB = skynet \
  client \
  bson md5 sproto lpeg $(TLS_MODULE)

LUA_CLIB_SKYNET = \
  lua-skynet.c lua-seri.c \
  lua-socket.c \
  lua-mongo.c \
  lua-netpack.c \
  lua-memory.c \
  lua-multicast.c \
  lua-cluster.c \
  lua-crypt.c lsha1.c \
  lua-sharedata.c \
  lua-stm.c \
  lua-debugchannel.c \
  lua-datasheet.c \
  lua-sharetable.c \
  \

SKYNET_SRC = skynet_main.c skynet_handle.c skynet_module.c skynet_mq.c \
  skynet_server.c skynet_start.c skynet_timer.c skynet_error.c \
  skynet_harbor.c skynet_env.c skynet_monitor.c skynet_socket.c socket_server.c \
  malloc_hook.c skynet_daemon.c skynet_log.c

然后是入口 all:

先分析all中的第1句:

all : \
  $(SKYNET_BUILD_PATH)/skynet \
  
LUA_LIB ?= $(LUA_STATICLIB) 

# 'cc -g -O2 -Wall -I3rd/lua  -o skynet skynet-src/skynet_main.c skynet-src/skynet_handle.c skynet-src/skynet_module.c skynet-src/skynet_mq.c skynet-src/skynet_server.c skynet-src/skynet_start.c skynet-src/skynet_timer.c skynet-src/skynet_error.c skynet-src/skynet_harbor.c skynet-src/skynet_env.c skynet-src/skynet_monitor.c skynet-src/skynet_socket.c skynet-src/socket_server.c skynet-src/malloc_hook.c skynet-src/skynet_daemon.c skynet-src/skynet_log.c 3rd/lua/liblua.a 3rd/jemalloc/lib/libjemalloc_pic.a -Iskynet-src -I3rd/jemalloc/include/jemalloc  -Wl,-E -lpthread -lm -ldl -lrt '
# 先决条件中skynet-src下的文件是已经存在的,$(LUA_LIB) 在下文中定义,$(MALLOC_STATICLIB)在前文中已经定义
$(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)
	
# 执行3rd/lua下的Makefile
$(LUA_STATICLIB) :
	cd 3rd/lua && $(MAKE) CC='$(CC) -std=gnu99' $(PLAT)

  

接着看,all中的第2句:

all:   $(foreach v, $(CSERVICE), $(CSERVICE_PATH)/$(v).so) \

$(LUA_CLIB_PATH) :
	mkdir $(LUA_CLIB_PATH)

$(CSERVICE_PATH) :
	mkdir $(CSERVICE_PATH)

# 定义了模板
define CSERVICE_TEMP
  $$(CSERVICE_PATH)/$(1).so : service-src/service_$(1).c | $$(CSERVICE_PATH)
	$$(CC) $$(CFLAGS) $$(SHARED) $$< -o $$@ -Iskynet-src
endef	

# https://www.gnu.org/software/make/manual/make.html#Eval-Function
# such as: cc -g -O2 -Wall -I3rd/lua  -fPIC --shared service-src/service_snlua.c -o cservice/snlua.so -Iskynet-src
$(foreach v, $(CSERVICE), $(eval $(call CSERVICE_TEMP,$(v))))

all中的第3句,对应的是lua的三方库:

all : $(foreach v, $(LUA_CLIB), $(LUA_CLIB_PATH)/$(v).so) $(LUA_CLIB_PATH)/skynet.so : $(addprefix lualib-src/,$(LUA_CLIB_SKYNET)) | $(LUA_CLIB_PATH)	$(CC) $(CFLAGS) $(SHARED) $^ -o $@ -Iskynet-src -Iservice-src -Ilualib-src$(LUA_CLIB_PATH)/bson.so : lualib-src/lua-bson.c | $(LUA_CLIB_PATH)	$(CC) $(CFLAGS) $(SHARED) -Iskynet-src $^ -o $@$(LUA_CLIB_PATH)/md5.so : 3rd/lua-md5/md5.c 3rd/lua-md5/md5lib.c 3rd/lua-md5/compat-5.2.c | $(LUA_CLIB_PATH)	$(CC) $(CFLAGS) $(SHARED) -I3rd/lua-md5 $^ -o $@ $(LUA_CLIB_PATH)/client.so : lualib-src/lua-clientsocket.c lualib-src/lua-crypt.c lualib-src/lsha1.c | $(LUA_CLIB_PATH)	$(CC) $(CFLAGS) $(SHARED) $^ -o $@ -lpthread$(LUA_CLIB_PATH)/sproto.so : lualib-src/sproto/sproto.c lualib-src/sproto/lsproto.c | $(LUA_CLIB_PATH)	$(CC) $(CFLAGS) $(SHARED) -Ilualib-src/sproto $^ -o $@ $(LUA_CLIB_PATH)/ltls.so : lualib-src/ltls.c | $(LUA_CLIB_PATH)	$(CC) $(CFLAGS) $(SHARED) -Iskynet-src -L$(TLS_LIB) -I$(TLS_INC) $^ -o $@ -lssl$(LUA_CLIB_PATH)/lpeg.so : 3rd/lpeg/lpcap.c 3rd/lpeg/lpcode.c 3rd/lpeg/lpprint.c 3rd/lpeg/lptree.c 3rd/lpeg/lpvm.c | $(LUA_CLIB_PATH)	$(CC) $(CFLAGS) $(SHARED) -I3rd/lpeg $^ -o $@ 

附录

gcc相关参数:

选项 解释
-g 生成调试信息。GNU 调试器可利用该信息。
-O 或 -O1 优化生成代码。
-O2 进一步优化。
-Wall 生成所有警告信息。
-I( i 的大写) 指定头文件路径(相对路径或觉得路径,建议相对路径)
-Wl,option 此选项传递 option 给连接程序; 如果 option 中间有逗号, 就将 option 分成多个选项, 然 后传递给会连接程序。
-E 只运行 C 预编译器。
-lpthread 链接线程库,可以是自己编译的库
-lm 编译的时候,链接数学库
-ldl 链接显式加载动态库的动态函数库
-lrt 链接实时库(real time)
-l (L的小写) 指定需要链接的库的名字(链接 libc.a :-lc 链接动态库:libc.so : -lc 注意:-l后面直接添加库名省区“lib”和“.so”或“.a” )
-o 制定目标名称, 默认的时候, gcc 编译出来的文件是 a.out

猜你喜欢

转载自blog.csdn.net/sayWhat_sayHello/article/details/119046183