Maison >base de données >Redis >Analyse du code source Redis et compréhension approfondie des fichiers Makefile
Cet article parlera de la compilation du code source Redis et analysera le Makefile en détail. J'espère qu'il sera utile à tout le monde !
Pour étudier cet article, vous devez disposer du code source Redis
, et il est préférable de configurer l'environnement de compilation approprié, afin que vous puissiez voir intuitivement le processus d'exécution du Makefile. La version du code source utilisée ici est redis-6.2.1
. [Recommandations associées : Tutoriel vidéo Redis]Redis
源码,且最好搭建起相关的编译环境,这样才能直观地看到Makefile
文件的执行过程。这里使用的源码版本是redis-6.2.1
的。【相关推荐:Redis视频教程】
源代码根目录的Makefile
文件内容如下:
default: all .DEFAULT: cd src && $(MAKE) $@ install: cd src && $(MAKE) $@ .PHONY: install
从代码中可以看出以下几点信息:
default
,该目标没有实际作用,依赖于all
目标all
目标,所以当我们直接使用make
时,首先会调用default
目标,然后调用all
目标,由于all
目标不存在,所以会调用.DEFAULT
目标来替代,在Makefile的执行语句中,$@
代表的就是目标的意思,$(MAKE)
代表的就是make
,所以展开之后的代码如下,读者可以自行编译一下,看看第一条输出语句是否与我们分析的相同cd src && make all
src/
目录,然后调用该目录下的Makefile
文件,区别只在于此时调用的目标变成了install
而已,展开后的代码如下:cd src && make install
.DEFAULT
去,然后去调用子目录下的Makefile
的对应的目标,以clean
为例,代码如下:cd src && make clean
该文件是真正起编译作用的文件,内容比较多,比较杂,而且为了兼容多种编译器里面有不少分支选择语法,我们这里只以Linux
下的gcc
编译器为例去讲解,其余的没区别,就是通过判断语句去改变某些编译参数而已
1、Makefile.dep目标
Makefile
在执行对应的目标之前,会先把非目标的指令给执行了,比如变量赋值、Shell
语句等等,所以我们会发现,Makefile
文件并不会完全按照顺序去执行的
相关代码如下:
NODEPS:=clean distclean # FINAL_CFLAGS里的各个变量原型 STD=-pedantic -DREDIS_STATIC='' WARN=-Wall -W -Wno-missing-field-initializers OPTIMIZATION?=-O2 OPT=$(OPTIMIZATION) DEBUG=-g -ggdb #CFLAGS 根据条件选择的,不重要的参数,忽略 #REDIS_CFLAGS 根据条件选择的,不重要的参数,忽略 FINAL_CFLAGS=$(STD) $(WARN) $(OPT) $(DEBUG) $(CFLAGS) $(REDIS_CFLAGS) REDIS_CC=$(QUIET_CC)$(CC) $(FINAL_CFLAGS) all: $(REDIS_SERVER_NAME) $(REDIS_SENTINEL_NAME) $(REDIS_CLI_NAME) $(REDIS_BENCHMARK_NAME) $(REDIS_CHECK_RDB_NAME) $(REDIS_CHECK_AOF_NAME) @echo "" @echo "Hint: It's a good idea to run 'make test' ;)" @echo "" Makefile.dep: -$(REDIS_CC) -MM *.c > Makefile.dep 2> /dev/null || true ifeq (0, $(words $(findstring $(MAKECMDGOALS), $(NODEPS)))) -include Makefile.dep endif
首先先补充以下几点Makefile
的基础
Makefile
的findstring
函数的使用格式为$(findstring FIND, IN)
,表示在IN
中查找FIND
,如果查找到了就返回FIND
,找不到就返回空Makefile
的words
函数表示统计单词数目,例如$(words, foo bar)
的返回值为"2"
Makefile
的MAKECMDGOALS
变量表示传入的参数(全部)Makefile
的CC
默认值是cc
Makefile
的-MM
是输出一个用于make
的规则,该规则描述了源文件的依赖关系,但是不包含系统头文件
则可以总结出以下几点信息:
all
目标正是我们前一节说到的那个默认的编译目标,但是我们可以自己试着去编译一下,会发现先生成的是Makefile.dep
文件,因为他先执行了最下面那个判断语句,里面调用了Makefile.dep
目标MAKECMDGOALS
的值为all
,不在NODEPS
范围里,所以上面那个ifeq
语句成立,会调用Makefile.dep
目标REDIS_CC
的值由三个变量组成,QUIET_CC
是打印调试信息的,读者可以自己去源码看相关内容,这部分不重要,我们忽略,CC
的值代表的是编译器,FINAL_CFLAGS
里面的值则是编译的一些参数,这些值在上面的代码中都已经摘录出来了Makefile.dep
目标的作用就是生成当前目录下所有以.c
结尾的文件的依赖关系,并写入Makefile.dep
Le contenu du fichier Makefile
dans le répertoire racine du code source est le suivant : acl.o: acl.c server.h fmacros.h config.h solarisfixes.h rio.h sds.h \
connection.h atomicvar.h ../deps/lua/src/lua.h ../deps/lua/src/luaconf.h \
ae.h monotonic.h dict.h mt19937-64.h adlist.h zmalloc.h anet.h ziplist.h \
intset.h version.h util.h latency.h sparkline.h quicklist.h rax.h \
redismodule.h zipmap.h sha1.h endianconv.h crc64.h stream.h listpack.h \
rdb.h sha256.h
adlist.o: adlist.c adlist.h zmalloc.h
ae.o: ae.c ae.h monotonic.h fmacros.h anet.h zmalloc.h config.h \
ae_epoll.c
ae_epoll.o: ae_epoll.c
...
zipmap.o: zipmap.c zmalloc.h endianconv.h config.h
zmalloc.o: zmalloc.c config.h zmalloc.h atomicvar.h
Les informations suivantes peuvent être vues à partir du code : par défaut
. Cet objectif n'a aucun effet réel et repose sur l'objectif all
all.
dans le code, donc lorsque nous utilisons directement make
, la cible default
sera appelée en premier, puis la cible all
target sera appelée. Puisque la cible all
n'existe pas, par conséquent, la cible .DEFAULT
sera appelée à la place dans l'instruction d'exécution du Makefile, $. @
représente la signification de la cible, $(MAKE)
Il représente make
, donc le code développé est le suivant. Les lecteurs peuvent le compiler eux-mêmes pour le voir. si la première instruction de sortie est la même que celle que nous avons analysée.make-prerequisites: @touch $@ ifneq ($(strip $(PREV_FINAL_CFLAGS)), $(strip $(FINAL_CFLAGS))) .make-prerequisites: persist-settings endif ifneq ($(strip $(PREV_FINAL_LDFLAGS)), $(strip $(FINAL_LDFLAGS))) .make-prerequisites: persist-settings endif %.o: %.c .make-prerequisites $(REDIS_CC) -MMD -o $@ -c $<
src/
puis appeler le Makefile dans ce répertoire. La seule différence est que la cible de l'appel devient install, le code développé est le suivant : <p><pre class="brush:js;toolbar:false;"># 假设生成的目标文件为acl.o,则代入可得
acl.o: acl.c .make-prerequisites
$(REDIS_CC) -MMD -o acl.o -c acl.c
# 执行完成后在该目录下会生成一个acl.o文件和acl.d文件</pre></p>
<ul><li>Lorsque le paramètre entrant est autre, l'appel ira vers <code>.DEFAULT
, puis ira dans le sous-répertoire appelant La cible correspondante de <code>Makefile, en prenant clean
comme un exemple, le code est le suivant : REDIS_SERVER_NAME=redis-server$(PROG_SUFFIX) REDIS_SENTINEL_NAME=redis-sentinel$(PROG_SUFFIX) REDIS_CLI_NAME=redis-cli$(PROG_SUFFIX) REDIS_BENCHMARK_NAME=redis-benchmark$(PROG_SUFFIX) REDIS_CHECK_RDB_NAME=redis-check-rdb$(PROG_SUFFIX) REDIS_CHECK_AOF_NAME=redis-check-aof$(PROG_SUFFIX)
gcc
sous Linux
>Le compilateur est pris comme exemple pour expliquer. différence dans le reste. Il s'agit simplement de modifier certains paramètres de compilation via des instructions de jugement🎜🎜🎜🎜1 Makefile.dep target🎜🎜🎜🎜Makefile
exécute les instructions correspondantes avant la cible. sera exécuté en premier, comme l'affectation de variables, les instructions Shell
, etc., nous constaterons donc que le fichier Makefile
ne sera pas complètement en ordre. Le code associé à 🎜. exécuter est la suivante : 🎜REDIS_SERVER_OBJ=adlist.o quicklist.o ae.o anet.o dict.o server.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o pubsub.o multi.o debug.o sort.o intset.o syncio.o cluster.o crc16.o endianconv.o slowlog.o scripting.o bio.o rio.o rand.o memtest.o crcspeed.o crc64.o bitops.o sentinel.o notify.o setproctitle.o blocked.o hyperloglog.o latency.o sparkline.o redis-check-rdb.o redis-check-aof.o geo.o lazyfree.o module.o evict.o expire.o geohash.o geohash_helper.o childinfo.o defrag.o siphash.o rax.o t_stream.o listpack.o localtime.o lolwut.o lolwut5.o lolwut6.o acl.o gopher.o tracking.o connection.o tls.o sha256.o timeout.o setcpuaffinity.o monotonic.o mt19937-64.o REDIS_CLI_OBJ=anet.o adlist.o dict.o redis-cli.o zmalloc.o release.o ae.o crcspeed.o crc64.o siphash.o crc16.o monotonic.o cli_common.o mt19937-64.o REDIS_BENCHMARK_OBJ=ae.o anet.o redis-benchmark.o adlist.o dict.o zmalloc.o release.o crcspeed.o crc64.o siphash.o crc16.o monotonic.o cli_common.o mt19937-64.o DEP = $(REDIS_SERVER_OBJ:%.o=%.d) $(REDIS_CLI_OBJ:%.o=%.d) $(REDIS_BENCHMARK_OBJ:%.o=%.d) -include $(DEP) INSTALL=install REDIS_INSTALL=$(QUIET_INSTALL)$(INSTALL) # redis-server $(REDIS_SERVER_NAME): $(REDIS_SERVER_OBJ) $(REDIS_LD) -o $@ $^ ../deps/hiredis/libhiredis.a ../deps/lua/src/liblua.a $(FINAL_LIBS) # redis-sentinel $(REDIS_SENTINEL_NAME): $(REDIS_SERVER_NAME) $(REDIS_INSTALL) $(REDIS_SERVER_NAME) $(REDIS_SENTINEL_NAME) # redis-check-rdb $(REDIS_CHECK_RDB_NAME): $(REDIS_SERVER_NAME) $(REDIS_INSTALL) $(REDIS_SERVER_NAME) $(REDIS_CHECK_RDB_NAME) # redis-check-aof $(REDIS_CHECK_AOF_NAME): $(REDIS_SERVER_NAME) $(REDIS_INSTALL) $(REDIS_SERVER_NAME) $(REDIS_CHECK_AOF_NAME) # redis-cli $(REDIS_CLI_NAME): $(REDIS_CLI_OBJ) $(REDIS_LD) -o $@ $^ ../deps/hiredis/libhiredis.a ../deps/linenoise/linenoise.o $(FINAL_LIBS) # redis-benchmark $(REDIS_BENCHMARK_NAME): $(REDIS_BENCHMARK_OBJ) $(REDIS_LD) -o $@ $^ ../deps/hiredis/libhiredis.a ../deps/hdr_histogram/hdr_histogram.o $(FINAL_LIBS)🎜Tout d'abord, ajoutez les points suivants sur les bases de <code>Makefile🎜🎜
de <code>Makefile
Le format d'utilisation de la fonction findstring est$(findstring FIND, IN)
, ce qui signifie rechercherFIND
dansIN
. S'il est trouvé, renvoieFIND
, s'il n'est pas trouvé, renvoie vide 🎜- La fonction
words
de <code>Makefile représente le comptage du nombre de mots, par exemple, la valeur de retour de$(words , foo bar)
est"2"
🎜- La variable
MAKECMDGOALS
de <code>Makefile représente les paramètres entrants (Tous) 🎜- La valeur par défaut de
CC
pourMakefile
estcc
🎜- for
Makefile
-MM
make
Cette règle décrit les dépendances des fichiers source, mais n'inclut pas les fichiers d'en-tête système🎜🎜blockquote>🎜Ce qui suit peut être résumé Quelques informations : 🎜all
à l'intérieur est exactement la cible de compilation par défaut que nous avons mentionnée dans la section précédente, mais nous pouvons essayer de la compiler nous-mêmes et nous constaterons que M. Le fichier résultant est Makefile.dep
, car il a d'abord exécuté l'instruction de jugement du bas, qui a appelé la cible Makefile.dep
🎜 La valeur de MAKECMDGOALS
est all
, ce qui n'est pas dans la portée de NODEPS
, donc le ifeq
ci-dessus > est établie et Makefile sera appelé. La valeur de dep
target🎜REDIS_CC
est composée de trois variables QUIET_CC
imprime le débogage. Les lecteurs peuvent accéder au code source pour voir le contenu pertinent. Ici La partie n'est pas importante, nous l'ignorons. La valeur de CC
représente le compilateur, et la valeur dans FINAL_CFLAGS<.> sont quelques paramètres de compilation. Ces valeurs sont déjà dans le code ci-dessus Extrait🎜<li>En résumé, la fonction du goal <code>Makefile.dep
est de générer les dépendances. de tous les fichiers se terminant par .c
dans le répertoire courant et écrivez Dans le fichier Makefile.dep
, le contenu du fichier généré après la compilation est le suivant. Il semble assez compliqué. , mais le contenu à l'intérieur répertorie en fait les fichiers cibles finalement générés par chaque fichier source, et les dépendances requises sont simplement répertoriées🎜🎜all: $(REDIS_SERVER_NAME) $(REDIS_SENTINEL_NAME) $(REDIS_CLI_NAME) $(REDIS_BENCHMARK_NAME) $(REDIS_CHECK_RDB_NAME) $(REDIS_CHECK_AOF_NAME) @echo "" @echo "Hint: It's a good idea to run 'make test' ;)" @echo ""🎜🎜🎜2 La cible générale de génération de fichiers cible🎜🎜🎜🎜 est la suivante :🎜
PREFIX?=/usr/local INSTALL_BIN=$(PREFIX)/bin install: all @mkdir -p $(INSTALL_BIN) $(REDIS_INSTALL) $(REDIS_SERVER_NAME) $(INSTALL_BIN) $(REDIS_INSTALL) $(REDIS_BENCHMARK_NAME) $(INSTALL_BIN) $(REDIS_INSTALL) $(REDIS_CLI_NAME) $(INSTALL_BIN) @ln -sf $(REDIS_SERVER_NAME) $(INSTALL_BIN)/$(REDIS_CHECK_RDB_NAME) @ln -sf $(REDIS_SERVER_NAME) $(INSTALL_BIN)/$(REDIS_CHECK_AOF_NAME) @ln -sf $(REDIS_SERVER_NAME) $(INSTALL_BIN)/$(REDIS_SENTINEL_NAME)🎜. Ce qui suit est une analyse de cette partie du code :🎜🎜
target
,Makefile
中%
表示通配符,所以只要符合格式要求的都可以借助这段代码来生成对应的目标文件.make-prerequisites
没啥用忽略,而REDIS_CC
的值在上一小节有说明了,是用于编译文件的指令gcc
的-MMD
参数与前面说的那个-MM
是基本一致的,只不过这个会将输出内容导入到对应的%.d
文件中Makefile
中$@
表示目标,$<
表示第一个依赖,$^
表示全部依赖target
的作用是依赖于一个源文件,然后根据这个源文件生成对应的目标文件,并且将依赖关系导入到对应的%.d
文件中下面是一个简单的例子:
# 假设生成的目标文件为acl.o,则代入可得 acl.o: acl.c .make-prerequisites $(REDIS_CC) -MMD -o acl.o -c acl.c # 执行完成后在该目录下会生成一个acl.o文件和acl.d文件
3、all目标所依赖的各个子目标的名称设置
PROG_SUFFIX
的值默认为空,可以忽略。这里设置的六个目标名都是会被all
这个目标引用的,从名字可以看出这六个目标是对应着Redis
不同的功能,依次是服务、哨兵、客户端、基础检测、rdf持久化以及aof持久化。
代码如下:
REDIS_SERVER_NAME=redis-server$(PROG_SUFFIX) REDIS_SENTINEL_NAME=redis-sentinel$(PROG_SUFFIX) REDIS_CLI_NAME=redis-cli$(PROG_SUFFIX) REDIS_BENCHMARK_NAME=redis-benchmark$(PROG_SUFFIX) REDIS_CHECK_RDB_NAME=redis-check-rdb$(PROG_SUFFIX) REDIS_CHECK_AOF_NAME=redis-check-aof$(PROG_SUFFIX)
4、all目标所依赖的各个子目标的内容
REDIS_LD
也是一个编译指令,和前面那个REDIS_CC
有点像,只不过这个指定了另外的一些编译参数,比如设置了某些依赖的动态库、静态库的路径,读者有兴趣的话可以去看一下代码,看看REDIS_LD
的详细内容FINAL_LIBS
是一系列动态库链接参数,读者有兴趣可以自行去Makefile
里面查看该变量的内容,限于篇幅原因这里就不展开讲了QUIET_INSTALL
忽略(这个是自定义打印编译信息的),可以看出REDIS_INSTALL
的值其实就是install
,Linux
下的install
命令是用于安装或升级软件或备份数据的,这个命令与cp
类似,但是install
允许你控制目标文件的属性,这里不作深入分析了,有兴趣的读者可以自行查阅相关的介绍install
命令的文章。基本用法为:install src des
,表示将src
文件复制到des
文件去REDIS_SERVER_OBJ=adlist.o quicklist.o ae.o anet.o dict.o server.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o pubsub.o multi.o debug.o sort.o intset.o syncio.o cluster.o crc16.o endianconv.o slowlog.o scripting.o bio.o rio.o rand.o memtest.o crcspeed.o crc64.o bitops.o sentinel.o notify.o setproctitle.o blocked.o hyperloglog.o latency.o sparkline.o redis-check-rdb.o redis-check-aof.o geo.o lazyfree.o module.o evict.o expire.o geohash.o geohash_helper.o childinfo.o defrag.o siphash.o rax.o t_stream.o listpack.o localtime.o lolwut.o lolwut5.o lolwut6.o acl.o gopher.o tracking.o connection.o tls.o sha256.o timeout.o setcpuaffinity.o monotonic.o mt19937-64.o REDIS_CLI_OBJ=anet.o adlist.o dict.o redis-cli.o zmalloc.o release.o ae.o crcspeed.o crc64.o siphash.o crc16.o monotonic.o cli_common.o mt19937-64.o REDIS_BENCHMARK_OBJ=ae.o anet.o redis-benchmark.o adlist.o dict.o zmalloc.o release.o crcspeed.o crc64.o siphash.o crc16.o monotonic.o cli_common.o mt19937-64.o DEP = $(REDIS_SERVER_OBJ:%.o=%.d) $(REDIS_CLI_OBJ:%.o=%.d) $(REDIS_BENCHMARK_OBJ:%.o=%.d) -include $(DEP) INSTALL=install REDIS_INSTALL=$(QUIET_INSTALL)$(INSTALL) # redis-server $(REDIS_SERVER_NAME): $(REDIS_SERVER_OBJ) $(REDIS_LD) -o $@ $^ ../deps/hiredis/libhiredis.a ../deps/lua/src/liblua.a $(FINAL_LIBS) # redis-sentinel $(REDIS_SENTINEL_NAME): $(REDIS_SERVER_NAME) $(REDIS_INSTALL) $(REDIS_SERVER_NAME) $(REDIS_SENTINEL_NAME) # redis-check-rdb $(REDIS_CHECK_RDB_NAME): $(REDIS_SERVER_NAME) $(REDIS_INSTALL) $(REDIS_SERVER_NAME) $(REDIS_CHECK_RDB_NAME) # redis-check-aof $(REDIS_CHECK_AOF_NAME): $(REDIS_SERVER_NAME) $(REDIS_INSTALL) $(REDIS_SERVER_NAME) $(REDIS_CHECK_AOF_NAME) # redis-cli $(REDIS_CLI_NAME): $(REDIS_CLI_OBJ) $(REDIS_LD) -o $@ $^ ../deps/hiredis/libhiredis.a ../deps/linenoise/linenoise.o $(FINAL_LIBS) # redis-benchmark $(REDIS_BENCHMARK_NAME): $(REDIS_BENCHMARK_OBJ) $(REDIS_LD) -o $@ $^ ../deps/hiredis/libhiredis.a ../deps/hdr_histogram/hdr_histogram.o $(FINAL_LIBS)
4.1、REDIS_SERVER_NAME目标
该目标依赖于REDIS_SERVER_OBJ
,而REDIS_SERVER_OBJ
的内容都是一些目标文件(上面代码有给出),这些目标文件最终都会通过3.2小节
介绍的那个target
来生成。可以看到REDIS_SERVER_NAME
这个target
需要使用REDIS_SERVER_OBJ
、…/deps/hiredis/libhiredis.a
、…/deps/lua/src/liblua.a
以及FINAL_LIBS
这些来编译链接生成最终的目标文件,即redis-server
4.2、REDIS_SENTINEL_NAME目标
可以看到REDIS_SENTINEL_NAME
目标很简单,只是简单地使用install
命令复制了REDIS_SERVER_NAME
目标生成的那个文件,即redis-server
,从这里可以知道哨兵服务redis-sentinel
与Redis
服务使用的是同一套代码
4.3、REDIS_CHECK_RDB_NAME目标
和前面的如出一辙,也是简单复制了redis-server
文件到redis-check-rdb
文件去
4.4、REDIS_CHECK_AOF_NAME目标
和前面的如出一辙,也是简单复制了redis-server
文件到redis-check-aof
文件去
4.5、REDIS_CLI_NAME目标
这个就不是简单复制了,而是使用和REDIS_SERVER_NAME
目标相同的方法进行直接编译的,唯一的区别是REDIS_SERVER_NAME
链接了…/deps/lua/src/liblua.a
,而REDIS_CLI_NAME
链接的是…/deps/linenoise/linenoise.o
4.6、REDIS_BENCHMARK_NAME目标
这个也是使用和REDIS_SERVER_NAME
目标相同的方法进行直接编译的,唯一的区别是REDIS_SERVER_NAME
链接了…/deps/lua/src/liblua.a
,而REDIS_BENCHMARK_NAME
链接的是…/deps/hdr_histogram/hdr_histogram.o
5、all目标
经过前面的介绍,all
目标的作用也就一目了然了,最终会生成六个可执行文件,以及输出相应的调试信息
代码如下:
all: $(REDIS_SERVER_NAME) $(REDIS_SENTINEL_NAME) $(REDIS_CLI_NAME) $(REDIS_BENCHMARK_NAME) $(REDIS_CHECK_RDB_NAME) $(REDIS_CHECK_AOF_NAME) @echo "" @echo "Hint: It's a good idea to run 'make test' ;)" @echo ""
6、安装和卸载Redis的目标
6.1、安装Redis的目标
这里逻辑很简单,先创建一个用于存放Redis
可执行文件的文件夹(默认是/usr/local/bin
),然后将REDIS_SERVER_NAME
、REDIS_BENCHMARK_NAME
、REDIS_CLI_NAME
对应的可执行文件复制到/usr/local/bin
中去,这里可以看到前面那几个照葫芦画瓢的文件并没有复制过去,而是直接通过创建软连接的方式去生成对应的可执行文件(内容相同,复制过去浪费空间)
代码如下:
PREFIX?=/usr/local INSTALL_BIN=$(PREFIX)/bin install: all @mkdir -p $(INSTALL_BIN) $(REDIS_INSTALL) $(REDIS_SERVER_NAME) $(INSTALL_BIN) $(REDIS_INSTALL) $(REDIS_BENCHMARK_NAME) $(INSTALL_BIN) $(REDIS_INSTALL) $(REDIS_CLI_NAME) $(INSTALL_BIN) @ln -sf $(REDIS_SERVER_NAME) $(INSTALL_BIN)/$(REDIS_CHECK_RDB_NAME) @ln -sf $(REDIS_SERVER_NAME) $(INSTALL_BIN)/$(REDIS_CHECK_AOF_NAME) @ln -sf $(REDIS_SERVER_NAME) $(INSTALL_BIN)/$(REDIS_SENTINEL_NAME)
6.2、卸载Redis的目标
这里就是删除前面复制的那些文件了,比较简单,就不细讲了
代码如下:
uninstall: rm -f $(INSTALL_BIN)/{$(REDIS_SERVER_NAME),$(REDIS_BENCHMARK_NAME),$(REDIS_CLI_NAME),$(REDIS_CHECK_RDB_NAME),$(REDIS_CHECK_AOF_NAME),$(REDIS_SENTINEL_NAME)}
7、clean和distclean目标
所有Makefile
的clean
或者distclean
目标的作用都是大致相同的,就是删除编译过程中产生的那些中间文件,以及最终编译生成的动态库、静态库、可执行文件等等内容,代码比较简单,就不作过多的分析了
代码如下:
clean: rm -rf $(REDIS_SERVER_NAME) $(REDIS_SENTINEL_NAME) $(REDIS_CLI_NAME) $(REDIS_BENCHMARK_NAME) $(REDIS_CHECK_RDB_NAME) $(REDIS_CHECK_AOF_NAME) *.o *.gcda *.gcno *.gcov redis.info lcov-html Makefile.dep dict-benchmark rm -f $(DEP) .PHONY: clean distclean: clean -(cd ../deps && $(MAKE) distclean) -(rm -f .make-*) .PHONY: distclean
8、test目标
执行完Redis
编译之后,会有一段提示文字我们可以运行make test
测试功能是否正常,从代码中我们可以看出其实不止一个test
目标,还有另一个test-sentinel
目标,这个是测试哨兵服务的。这两个目标分别运行了根目录的runtest
和runtest-sentinel
文件,这两个是脚本文件,里面会继续调用其他脚本来完成整个功能的测试,并输出测试信息到控制台。具体怎么测试的就不分析了,大家有兴趣的可以去看一下。
代码如下:
test: $(REDIS_SERVER_NAME) $(REDIS_CHECK_AOF_NAME) $(REDIS_CLI_NAME) $(REDIS_BENCHMARK_NAME) @(cd ..; ./runtest) test-sentinel: $(REDIS_SENTINEL_NAME) $(REDIS_CLI_NAME) @(cd ..; ./runtest-sentinel)
本文详细地分析了与Redis
编译相关的Makefile
文件,通过学习Makefile
文件里的内容,我们可以更为全面地了解Redis
的编译过程,因为Makefile
文件中将很多编译命令用@
给取消显示了,转而使用它自己特制的编译信息输出给我们看,代码如下:
ifndef V QUIET_CC = @printf ' %b %b\n' $(CCCOLOR)CC$(ENDCOLOR) $(SRCCOLOR)$@$(ENDCOLOR) 1>&2; QUIET_LINK = @printf ' %b %b\n' $(LINKCOLOR)LINK$(ENDCOLOR) $(BINCOLOR)$@$(ENDCOLOR) 1>&2; QUIET_INSTALL = @printf ' %b %b\n' $(LINKCOLOR)INSTALL$(ENDCOLOR) $(BINCOLOR)$@$(ENDCOLOR) 1>&2; endif
所以我们直接去编译的话很多细节会看不到,可以自己尝试修改Makefile
文件,在前面这段代码之前定义V
变量,这样就可以看到完整的编译信息了。修改如下:
V = 'good' ifndef V QUIET_CC = @printf ' %b %b\n' $(CCCOLOR)CC$(ENDCOLOR) $(SRCCOLOR)$@$(ENDCOLOR) 1>&2; QUIET_LINK = @printf ' %b %b\n' $(LINKCOLOR)LINK$(ENDCOLOR) $(BINCOLOR)$@$(ENDCOLOR) 1>&2; QUIET_INSTALL = @printf ' %b %b\n' $(LINKCOLOR)INSTALL$(ENDCOLOR) $(BINCOLOR)$@$(ENDCOLOR) 1>&2; endif
本人之前也写过Nginx
编译相关的文章,下面总结两者的几点区别:
Nginx
使用了大量的Shell
相关的技术,而Redis
则很少使用这些Nginx
跨平台的相关参数是通过配置脚本进行配置的,而Redis
则是直接在Makefile
文件中将这件事给做了,这两者没有什么优劣之分,Nginx
主要是为了可扩展性强才使用那么多配置脚本的,而Redis
基本不用考虑这些,所以简单一点实现就行了Redis
将其一些逻辑都放在了Makefile
文件中了,所以看起来Nginx
最终生成的Makefile
文件要比Redis
简单易懂很多(Nginx
复杂逻辑在那些配置脚本里)Nginx
生成的配置文件足有1000多行,代码量比Redis
的400多行要大很多,因为Nginx
把全部依赖的生成方式全部列举了出来,而Redis
借助了Makefile.dep
、各种%.d
文件来将依赖信息分散到中间文件中去,极大地减少了Makefile
的代码量本文转载自:https://blog.csdn.net/weixin_43798887/article/details/117674538
更多编程相关知识,请访问:编程入门!!
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!