四时宝库

程序员的知识宝库

手把手教你用CLion调试Redis5源码

前言

源码面前,了无秘密。而研究源码最有效的方式就是Debug。能够在现代的IDE里面调试程序无异于如虎添翼,能够帮助阅读者更快更有效的学习源码。依稀记得当初在gdb下面调试Redis源码的黑暗时期(gdb强大但是使用不是很方便)。

本文记录使用CLion编译调试Redis5源码的过程。

过程

CLion使用CMake作为其编译系统,利用CMake的配置文件CMakeLists.txt创建编辑器本身的代码环境。

所以在用CLion打开Redis的源码目录之后,需要添加相应的CMakeLists.txt文件(下载下来的Redis5源码默认是不包含相应的CMakeLists.txt文件)。

当前源码的代码结构如下:


添加CMakeLists.txt

1.在hiredis根目录下面添加CMakeLists.txt文件,内容如下:

add_library(hiredis STATIC
 hiredis.c
 net.c
 dict.c
 sds.c
 async.c
 read.c
 )

2.在linenoise根目录下面添加CMakeLists.txt文件,内容如下:

add_library(linenoise linenoise.c)

3.在lua根目录下面添加CMakeLists.txt文件,内容如下:

set(LUA_SRC
 src/lapi.c src/lcode.c src/ldebug.c src/ldo.c src/ldump.c src/lfunc.c 
 src/lgc.c src/llex.c src/lmem.c
 src/lobject.c src/lopcodes.c src/lparser.c src/lstate.c src/lstring.c
 src/ltable.c src/ltm.c
 src/lundump.c src/lvm.c src/lzio.c src/strbuf.c src/fpconv.c
 src/lauxlib.c src/lbaselib.c src/ldblib.c src/liolib.c src/lmathlib.c
 src/loslib.c src/ltablib.c
 src/lstrlib.c src/loadlib.c src/linit.c src/lua_cjson.c 
 src/lua_struct.c
 src/lua_cmsgpack.c
 src/lua_bit.c
 )
add_library(lua STATIC ${LUA_SRC})

4.在deps根目录下面添加CMakeLists.txt文件,内容如下:

add_subdirectory(hiredis)
add_subdirectory(linenoise)
add_subdirectory(lua)

5.在src/modules根目录下面添加CMakeLists.txt文件,内容如下:

cmake_minimum_required(VERSION 3.9)
set(CMAKE_BUILD_TYPE "Debug")
add_library(helloworld SHARED helloworld.c)
set_target_properties(helloworld PROPERTIES PREFIX "" SUFFIX ".so")
add_library(hellotype SHARED hellotype.c)
set_target_properties(hellotype PROPERTIES PREFIX "" SUFFIX ".so")
add_library(helloblock SHARED helloblock.c)
set_target_properties(helloblock PROPERTIES PREFIX "" SUFFIX ".so")
add_library(testmodule SHARED testmodule.c)
set_target_properties(testmodule PROPERTIES PREFIX "" SUFFIX ".so")

6.在redis

cmake_minimum_required(VERSION 3.0 FATAL_ERROR)
project(redis VERSION 4.0)
set(CMAKE_BUILD_TYPE "Debug")
get_filename_component(REDIS_ROOT "${CMAKE_CURRENT_SOURCE_DIR}" ABSOLUTE)
add_subdirectory(deps)
add_subdirectory(src/modules)
set(SRC_SERVER_TMP
 src/adlist.c
 src/ae.c
 src/anet.c
 src/ae_kqueue.c
 src/dict.c
 src/sds.c
 src/zmalloc.c
 src/lzf_c.c
 src/lzf_d.c
 src/pqsort.c
 src/zipmap.c
 src/sha1.c
 src/ziplist.c
 src/release.c
 src/networking.c
 src/util.c
 src/object.c
 src/db.c
 src/replication.c
 src/rdb.c
 src/t_string.c
 src/t_list.c
 src/t_set.c
 src/t_zset.c
 src/evict.c
 src/defrag.c
 src/module.c
 src/quicklist.c
 src/expire.c
 src/childinfo.c
 src/redis-check-aof.c
 src/redis-check-rdb.c
 src/lazyfree.c
 src/geohash.c
 src/rax.c
 src/geohash_helper.c
 src/siphash.c
 src/geo.c
 src/t_hash.c
 src/config.c
 src/aof.c
 src/pubsub.c
 src/multi.c
 src/debug.c
 src/sort.c
 src/intset.c
 src/syncio.c
 src/cluster.c
 src/crc16.c
 src/endianconv.c
 src/slowlog.c
 src/scripting.c
 src/bio.c
 src/rio.c
 src/rand.c
 src/memtest.c
 src/crc64.c
 src/bitops.c
 src/sentinel.c
 src/notify.c
 src/setproctitle.c
 src/blocked.c
 src/hyperloglog.c
 src/latency.c
 src/sparkline.c
 src/t_stream.c
 src/lolwut.c
 src/lolwut5.c
 src/listpack.c
 src/localtime.c
 )
set(SRC_SERVER src/server.c ${SRC_SERVER_TMP})
set(SRC_CLI
 src/anet.c
 src/sds.c
 src/adlist.c
 src/redis-cli.c
 src/zmalloc.c
 src/release.c
 src/anet.c
 src/ae.c
 src/crc64.c
 )
set(EXECUTABLE_OUTPUT_PATH src)
link_directories(deps/linenoise/ deps/lua/src deps/hiredis)
add_executable(redis-server ${SRC_SERVER})
target_include_directories(redis-server
 PRIVATE ${REDIS_ROOT}/deps/linenoise
 PRIVATE ${REDIS_ROOT}/deps/hiredis
 PRIVATE ${REDIS_ROOT}/deps/lua/src)
target_link_libraries(redis-server
 PRIVATE pthread
 PRIVATE m
 PRIVATE lua
 PRIVATE linenoise
 PRIVATE hiredis)
add_executable(redis-cli ${SRC_CLI})
target_include_directories(redis-cli
 PRIVATE ${REDIS_ROOT}/deps/linenoise
 PRIVATE ${REDIS_ROOT}/deps/hiredis
 PRIVATE ${REDIS_ROOT}/deps/lua/src)
target_link_libraries(redis-cli
 PRIVATE pthread
 PRIVATE m
 PRIVATE linenoise
 PRIVATE hiredis
 )

解决报错

在添加完CMakeLists.txt文件之后,CLion会自动进行编译源码,编译完成之后,代码就可以debug了,选中redis-server,点击旁边的运行或者调试按钮:

此时有可能会报错:

/Users/didi/Desktop/temp/redis/src/ae_kqueue.c:41:24: error: unknown type name 'aeEventLoop'
static int aeApiCreate(aeEventLoop *eventLoop) {
 ^
/Users/didi/Desktop/temp/redis/src/ae_kqueue.c:42:25: warning: implicit declaration of function 'zmalloc' is invalid in C99 [-Wimplicit-function-declaration]
 aeApiState *state = zmalloc(sizeof(aeApiState));
 ^
[ 44%] Building C object CMakeFiles/redis-server.dir/src/dict.c.o
/Users/didi/Desktop/temp/redis/src/ae_kqueue.c:42:17: warning: incompatible integer to pointer conversion initializing 'aeApiState *' (aka 'struct aeApiState *') with an expression of type 'int' [-Wint-conversion]
 aeApiState *state = zmalloc(sizeof(aeApiState));
 ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Users/didi/Desktop/temp/redis/src/ae_kqueue.c:47:9: warning: implicit declaration of function 'zfree' is invalid in C99 [-Wimplicit-function-declaration]
 zfree(state);
 ^
/Users/didi/Desktop/temp/redis/src/ae_kqueue.c:52:9: warning: implicit declaration of function 'zfree' is invalid in C99 [-Wimplicit-function-declaration]
 zfree(state->events);
 ^
/Users/didi/Desktop/temp/redis/src/ae_kqueue.c:60:24: error: unknown type name 'aeEventLoop'

这个时候只需要点击进入ae_kqueue.c文件中,添加下面两个头文件:

#include "ae.h"
#include "zmalloc.h"

此时重新点击运行(调试)按钮,继续报错:

/Users/didi/Desktop/temp/redis/src/release.c:36:10: fatal error: 'release.h' file not found
#include "release.h"
 ^~~~~~~~~~~
1 error generated.
make[3]: *** [CMakeFiles/redis-server.dir/src/release.c.o] Error 1
make[3]: *** Waiting for unfinished jobs....
[ 48%] Building C object CMakeFiles/redis-server.dir/src/networking.c.o
make[2]: *** [CMakeFiles/redis-server.dir/all] Error 2

找不到release.h头文件,此时只需要切换到src目录下执行mkreleasehdr.sh脚本即可:

? redis pwd
/Users/didi/Desktop/temp/redis
? redis ls 
CMakeLists.txt cmake-build-debug deps src tests utils
? redis cd src 
? src sh mkreleasehdr.sh 
? src

此时再重新运行(调试),出现如下熟悉的画面,


表示成功在CLion环境中运行Redis5,接下来可以开始随心所欲的研究Redis5的源码了。

其他

Redis之所以高性能,其中一个原因就是它采用了IO多路复用技术,该技术在不同的操作系统上的实现是不一样的,因此对应着Redis源码中的不同源文件:Mac上的是ae_kqueue.c文件,Linux系统上对应的是ae_epoll.c或者ae_select.c文件。

本文演示的是在Mac系统下的操作过程,如果是在Linux系统中,则需要把redis根目录下的CMakeLists.txt文件中的src/ae_kqueue.c替换成src/ae_select.c或者src/ae_epoll.c文件。

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言
    友情链接