Article directory
Skynet source code analysis make
foreword
The version of this article is skynet v1.4.0. The inevitable thing to compile skynet is make.
This article will specifically look at the implementation of make.
About make, you can refer to Ruan Yifeng's weblog .
In addition, this article only involves the top-level Makefile, and does not analyze the Makefile in the subdirectory.
The appendix is some parameters of GCC.
text
When we execute in the skynet directory, make linux
we are actually executing Makefile
the commands in it. In the first line of the file there is this statement:
include platform.mk
platform.mk
The logic is roughly as follows:
-
Determine whether the correct platform is passed in
linux freebsd macosx
. If not, exit with an error message: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'
If the wrong platform is passed in, there will be a similar print:
wyw@DESKTOP-GJ20UDC:~/skynet$ make l make: *** No rule to make target 'l'. Stop.
-
Different variables are set according to different platforms, and the variables set here will be used in the Makefile. eg
make linux
. Execution to the last command is as follows:# 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
Returning to Makefile, some platform-related values are set after include. And it is executed make all
.
The logic is roughly as follows:
- Generate jemalloc
- Generate skynet related parts
jemalloc
Jemalloc is a memory allocator. Compared with other memory allocators, its biggest advantage lies in its high performance in multi-threaded situations and the reduction of memory fragmentation.
Read the README.md in the skynet project. There is a sentence like this:
For Linux, install autoconf first for jemalloc
The reason will be revealed later, let's analyze the Makefile first.
Start statement:
# 定义变量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
There is more content in this part, first the definition of some variables.
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
Then there is the entry all:
First analyze the first sentence in all:
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)
Next, look at the second sentence in all:
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))))
The third sentence in all corresponds to the tripartite library of 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 $@
appendix
gcc related parameters:
options | explain |
---|---|
-g | Generate debug information. The GNU debugger can use this information. |
-O or -O1 | Optimize generated code. |
-O2 | advanced optimization. |
-Wall | Generate all warning messages. |
-I ( uppercase i ) | Specify the header file path (relative path or felt path, relative path is recommended) |
-Wl,option | This option passes option to the linker; if there is a comma in the option, the option is split into multiple options, and then passed to the linker. |
-E | Only run the C precompiler. |
-lpthread | Link the thread library, which can be a library compiled by yourself |
-lm | When compiling, link the math library |
-ldl | Linking a dynamic function library that explicitly loads a dynamic library |
-lrt | Link real time library (real time) |
-l (lowercase L) | Specify the name of the library to be linked (link libc.a: -lc link dynamic library: libc.so: -lc Note: add the library name "lib" and ".so" or ".a" directly after -l) |
-o | Specify the target name. By default, the file compiled by gcc is a.out |