이 글에서는 Redis 소스 코드 컴파일과 Makefile에 대해 자세히 설명하겠습니다. 모든 분들께 도움이 되길 바랍니다!
이 글을 공부하려면 Redis
소스코드가 있어야 하며, Makefile 파일입니다. 여기에 사용된 소스 코드 버전은 redis-6.2.1
입니다. [관련 권장사항: Redis 동영상 튜토리얼]Redis
源码,且最好搭建起相关的编译环境,这样才能直观地看到Makefile
文件的执行过程。这里使用的源码版本是redis-6.2.1
的。【相关推荐:Redis视频教程】
Makefile文件详解
源代码根目录的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
- install目标和前面的类似,最终也是进去
src/
目录,然后调用该目录下的Makefile
文件,区别只在于此时调用的目标变成了install
而已,展开后的代码如下:
cd src && make install
- 当传入参数是其他是,调用的都会转到
.DEFAULT
去,然后去调用子目录下的Makefile
的对应的目标,以clean
为例,代码如下:
cd src && make clean
src/Makefile文件详解
该文件是真正起编译作用的文件,内容比较多,比较杂,而且为了兼容多种编译器里面有不少分支选择语法,我们这里只以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
Makefile 파일 상세 설명
소스코드 루트 디렉터리에 있는 Makefile
파일의 내용은 다음과 같습니다. 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
코드에서 확인할 수 있는 정보는 다음과 같습니다. 기본값
입니다. 이 목표는 실제 효과가 없으며 all
목표에 의존합니다.
all은 없습니다.
목표가 코드에 있으므로 make
를 직접 사용할 때 기본
대상이 먼저 호출된 다음 all
이 호출됩니다. all
타겟이 존재하지 않으므로 Makefile의 실행문에서 .DEFAULT
타겟이 대신 호출됩니다. @는 타겟의 의미를 나타내고, $(MAKE)
는 make
를 나타내므로 확장된 코드는 다음과 같이 독자가 직접 컴파일하여 볼 수 있습니다. 첫 번째 출력 문이 우리가 분석한 것과 동일.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/
디렉터리로 이동한 다음 유일한 차이점은 호출 대상이install
이 되고 확장된 코드는 다음과 같습니다.# 假设生成的目标文件为acl.o,则代入可得 acl.o: acl.c .make-prerequisites $(REDIS_CC) -MMD -o acl.o -c acl.c # 执行完成后在该目录下会生成一个acl.o文件和acl.d文件
- 들어오는 매개변수가 다른 경우 호출은
.DEFAULT
로 이동한 다음 호출 하위 디렉터리로 이동합니다. 해당 대상Makefile
,clean
가져오기 예를 들어 코드는 다음과 같습니다.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)
🎜src/Makefile 파일 상세 설명🎜
🎜이 파일은 실제로 컴파일 역할을 하는 파일들이 내용이 많고 복잡합니다. 다양한 컴파일러와 호환되도록 많은 분기 선택 구문이 있습니다. 여기서는Linux
에서gcc
만 사용하여 설명합니다. 나머지는 그냥 판단문을 통해 특정 컴파일 매개변수만 변경하면 됩니다🎜🎜🎜🎜1. Makefile.dep target🎜🎜🎜🎜Makefile
은 타겟 이전에, 타겟이 아닌 것을 실행하고 있습니다. 변수 할당,Shell
문 등과 같은 명령이 먼저 실행되므로Makefile
파일이 완전히 순서대로 정렬되지는 않음을 알 수 있습니다. 🎜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)
🎜먼저Makefile
🎜🎜-
of <code>Makefile
의 기본 사항에 대해 다음 사항을 추가합니다. code> findstring 함수의 사용 형식은$(findstring FIND, IN)
입니다. 이는IN
에서FIND
를 검색한다는 의미입니다. > 발견되면FIND
를 반환하고, 발견되지 않으면 빈 값을 반환합니다. 🎜 -
Makefile
의words
함수는 통계적인 단어 수를 나타냅니다. 예를 들어$(words , foo bar)
의 반환 값은"2"
🎜 -
의 <code>MAKECMDGOALS
변수입니다. Makefile은 들어오는 매개변수(모두)를 나타냅니다. 🎜 -
Makefile
에 대한CC
의 기본값은cc
🎜 - 입니다.
for <code>Makefile
-MM은make
에 대한 규칙을 출력합니다. 이 규칙은 소스 파일의 종속성을 설명하지만 시스템 헤더 파일은 포함하지 않습니다🎜🎜🎜다음을 요약할 수 있습니다. 일부 정보: 🎜- 내부의
all
대상은 정확히 이전 섹션에서 언급한 기본 컴파일 대상이지만 컴파일을 시도해 볼 수 있습니다. Mr. 결과 파일은Makefile.dep
입니다. 이는Makefile.dep
target🎜 - 을 호출하는 하단 판단 문을 먼저 실행했기 때문입니다. 현재
MAKECMDGOALS
의 값은all
이고 이는NODEPS
범위에 포함되지 않으므로 위의ifeq
code> 문이 설정되고Makefile이 호출됩니다
target🎜 -
REDIS_CC
는 세 가지 변수로 구성됩니다. 디버깅 정보를 보려면 소스 코드로 이동하세요. 여기에서 해당 부분은 중요하지 않으므로CC
값은 컴파일러를 나타내고FINAL_CFLAGS의 값은 무시합니다.
는 컴파일의 일부 매개변수입니다. 이 값은 이미 위의 코드에 있습니다.🎜 - 요약하면
Makefile.dep
목표의 기능은 현재 디렉터리에서.c
로 끝나는 모든 파일의 dependency를 작성하고Makefile.dep
파일에서 컴파일 후 생성된 파일의 내용은 다음과 같습니다. 지저분하지만, 그 안에 있는 내용에는 실제로 각 소스 파일에서 최종적으로 생성된 대상 파일이 나열되어 있으며 필요한 종속성만 나열되어 있습니다🎜🎜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. 일반적인 대상 파일 생성 대상🎜🎜🎜🎜코드는 다음과 같습니다.🎜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)
🎜다음은 코드의 이 부분을 분석한 것입니다.🎜🎜- 这部分是通用的根据源文件生成目标文件的
target
,Makefile
中%
表示通配符,所以只要符合格式要求的都可以借助这段代码来生成对应的目标文件 -
.make-prerequisites
没啥用忽略,而REDIS_CC
的值在上一小节有说明了,是用于编译文件的指令 -
gcc
的-MMD
参数与前面说的那个-MM
是基本一致的,只不过这个会将输出内容导入到对应的%.d
文件中 -
Makefile
中$@
表示目标,$表示第一个依赖,<code>$^
表示全部依赖 - 综上,这个
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
更多编程相关知识,请访问:编程入门!!
- 这部分是通用的根据源文件生成目标文件的
- 내부의
-
- 들어오는 매개변수가 다른 경우 호출은
위 내용은 Redis 소스 코드 분석 및 Makefile 파일에 대한 심층적인 이해의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

redisisclassifiedasanoSqldatabaseBecauseItuseSakey-valuedatamodelinsteadofThraditionalRelationalDatabasemodel.Itoffersspeedandflexibility, makingIdealforreal-timeApplicationsandcaching, butitmaynotbesuitableforscenariosrequiringstrictaintetaintetaintetaintetaintetaintetaintegry

Redis는 데이터를 캐싱하여 분산 잠금 및 데이터 지속성을 구현하여 응용 프로그램 성능 및 확장 성을 향상시킵니다. 1) 캐시 데이터 : Redis를 사용하여 데이터 액세스 속도를 향상시키기 위해 자주 액세스하는 데이터를 캐시합니다. 2) 분산 잠금 : Redis를 사용하여 분산 된 잠금 장치를 구현하여 분산 환경에서 작동의 보안을 보장합니다. 3) 데이터 지속성 : 데이터 손실을 방지하기위한 RDB 및 AOF 메커니즘을 통한 데이터 보안을 보장합니다.

Redis의 데이터 모델 및 구조에는 5 가지 주요 유형이 포함됩니다. 1. 문자열 : 텍스트 또는 이진 데이터를 저장하는 데 사용되며 원자 연산을 지원합니다. 2. 목록 : 정렬 된 요소 컬렉션, 대기열 및 스택에 적합합니다. 세트 : 세트 작동을 지원하는 비 순차 고유 요소 세트. 4. 순서 세트 (SortedSet) : 순위에 적합한 점수가있는 고유 한 요소 세트. 5. 해시 테이블 (HASH) : 객체를 저장하는 데 적합한 키 값 쌍 모음.

Redis의 데이터베이스 방법에는 메모리 인 데이터베이스 및 키 값 저장소가 포함됩니다. 1) Redis는 메모리에 데이터를 저장하고 빠르게 읽고 쓰고 있습니다. 2) 키 값 쌍을 사용하여 데이터를 저장하고 캐시 및 NOSQL 데이터베이스에 적합한 목록, 컬렉션, 해시 테이블 및 주문 컬렉션과 같은 복잡한 데이터 구조를 지원합니다.

Redis는 빠른 성능, 풍부한 데이터 구조, 고 가용성 및 확장 성, 지속성 기능 및 광범위한 생태계 지원을 제공하기 때문에 강력한 데이터베이스 솔루션입니다. 1) 매우 빠른 성능 : Redis의 데이터는 메모리에 저장되며 동시성이 높고 대기 시간이 낮은 응용 프로그램에 적합한 빠른 읽기 및 쓰기 속도를 가지고 있습니다. 2) 풍부한 데이터 구조 : 다양한 시나리오에 적합한 목록, 컬렉션 등과 같은 여러 데이터 유형을 지원합니다. 3) 고 가용성 및 확장 성 : 마스터 슬레이브 복제 및 클러스터 모드를 지원하여 고 가용성 및 수평 확장 성을 달성합니다. 4) 지속성 및 데이터 보안 : 데이터 지속성은 RDB 및 AOF를 통해 달성되어 데이터 무결성 및 신뢰성을 보장합니다. 5) 광범위한 생태계 및 지역 사회 지원 : 거대한 생태계와 활동적인 커뮤니티,

Redis의 주요 기능에는 속도, 유연성 및 풍부한 데이터 구조 지원이 포함됩니다. 1) 속도 : Redis는 메모리 내 데이터베이스이며, 읽기 및 쓰기 작업은 거의 순간적이며 캐시 및 세션 관리에 적합합니다. 2) 유연성 : 복잡한 데이터 처리에 적합한 문자열, 목록, 컬렉션 등과 같은 여러 데이터 구조를 지원합니다. 3) 데이터 구조 지원 : 다양한 비즈니스 요구에 적합한 문자열, 목록, 컬렉션, 해시 테이블 등을 제공합니다.

Redis의 핵심 기능은 고성능 인 메모리 데이터 저장 및 처리 시스템입니다. 1) 고속 데이터 액세스 : Redis는 메모리에 데이터를 저장하고 마이크로 초 수준 읽기 및 쓰기 속도를 제공합니다. 2) 풍부한 데이터 구조 : 문자열, 목록, 컬렉션 등을 지원하며 다양한 응용 프로그램 시나리오에 적응합니다. 3) 지속성 : RDB 및 AOF를 통해 디스크에 데이터를 지속하십시오. 4) 구독 게시 : 메시지 대기열 또는 실시간 통신 시스템에서 사용할 수 있습니다.

Redis는 다음을 포함하여 다양한 데이터 구조를 지원합니다. 1. String, 단일 값 데이터 저장에 적합합니다. 2. 큐 및 스택에 적합한 목록; 3. 비면성 데이터 저장에 사용되는 세트; 4. 순서, 순위 목록 및 우선 순위 대기열에 적합한 순서 세트; 5. 해시 테이블, 객체 또는 구조화 된 데이터를 저장하는 데 적합합니다.


핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

SublimeText3 Linux 새 버전
SublimeText3 Linux 최신 버전

에디트플러스 중국어 크랙 버전
작은 크기, 구문 강조, 코드 프롬프트 기능을 지원하지 않음

PhpStorm 맥 버전
최신(2018.2.1) 전문 PHP 통합 개발 도구

MinGW - Windows용 미니멀리스트 GNU
이 프로젝트는 osdn.net/projects/mingw로 마이그레이션되는 중입니다. 계속해서 그곳에서 우리를 팔로우할 수 있습니다. MinGW: GCC(GNU Compiler Collection)의 기본 Windows 포트로, 기본 Windows 애플리케이션을 구축하기 위한 무료 배포 가능 가져오기 라이브러리 및 헤더 파일로 C99 기능을 지원하는 MSVC 런타임에 대한 확장이 포함되어 있습니다. 모든 MinGW 소프트웨어는 64비트 Windows 플랫폼에서 실행될 수 있습니다.

ZendStudio 13.5.1 맥
강력한 PHP 통합 개발 환경
