Redis源码在windows下的成功编译(附cmake工程配置)
Posted 特立独行的猫a
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis源码在windows下的成功编译(附cmake工程配置)相关的知识,希望对你有一定的参考价值。
缘由
windows下的redis有现成的安装包,但这也是别人打包好的。其实完全可以自己编译打包一份来用,或者对某部分进行定制化的修改(windows下的redis不是很稳定,存在一些问题)。工作原因需要对源码进行研究,另外也是为了更好的使用redis。读 Redis 源码是很有必要,特别是对数据结构和算法的学习,这是很好的例子,比lecode刷题有意思。
首先就是先把源码fork下来,然后加入cmake项目工程编译打包生成程exe可执行程序。只有自己能够打包编译才方便研究。中间遇到一些问题,这里总结记录下。后续计划进行一些源码分析相关的总结。
源码地址
项目源码下载地址:
https://github.com/microsoftarchive/redis
起初以为很简单的把源码路径和头文件加载进来就行了,结果编译遇到N多错误。
目录结构
主要是src和deps目录。
源码地图
感谢网上众多网友的分享总结,这里贴出别人画出的思维导图。看代码不能一头插进去困在了某个细节,那会导致一叶障目不见森林。好的办法是先理清脉络结构,知道那一块儿是做什么用的,然后再有针对性的下手。先整体后细节特别重要。
重点就是先把复杂代码的主逻辑搞清楚,知道涉及的每个方法完成了什么事,心里要先搭建一个简单的「框架」,等有了框架之后,我们再去给框架填充「细节」。
如何高效读源码
分享下网友总结的高效的方法,在此表示感谢。文末有文章链接。
阅读源码的经验心得,总结一下这 7 个步骤。
1、找到地图:
拿到项目代码后,提前梳理整个项目结构,知晓整个项目的模块划分,以及对应的代码文件。
2、前置知识准备:
提前掌握项目中用到的前置知识,比如数据结构、操作系统原理、网络协议、网络 IO 模型、编程语言语法等等。
3、从基础模块开始读:
从最底层的基础模块开始入手,先掌握了这些模块,之后基于它们构建的模块读起来会更加高效。
4、找到核心主线:
找到整个项目中最核心的主线逻辑,以此为目标,了解各模块为了完成这个功能,是如何协作和组织的。
5、先整体后细节:
对于复杂函数,不要上来就陷入细节,前期阅读只需了解这个函数大致做了什么事情,建立框架,等搭建起框架之后,再去填充细节。
6、先主线后支线:
整个主线逻辑清晰之后,再去延伸阅读支线逻辑,因为支线逻辑肯定是服务主线逻辑的,读完主线后再去读这些支线,也会变得更简单。
7、查漏补缺:
在工作中遇到具体问题,带着这些实际的问题出发再次去读源码,进行查漏补缺,填补之前读源码时没有注意到的地方。
cmake工程配置
仅把代码和头文件包含进去不行,有好几处需要修改一下。这里总结下编译遇到的问题。
修改一,由于官方的redis是运行在linux上的,那么windows上的redis肯定是经过适配的。(比如linux下的fork进程(备份机制在fork进程执行),在windows下是使用win32的api进行模拟)
因此cmake的源码包含路径里,需把几个linux下才能用到的文件排除掉。这些文件有:
list(REMOVE_ITEM SRC_FILES $FILE_PATH/ae_kqueue.c)
list(REMOVE_ITEM SRC_FILES $FILE_PATH/ae_epoll.c)
list(REMOVE_ITEM SRC_FILES $FILE_PATH/ae_evport.c)
list(REMOVE_ITEM SRC_FILES $FILE_PATH/ae_select.c)
另外,我只单独编译redis-server.exe,那么redis-cli.exe相关的文件也需要排除掉。
list(REMOVE_ITEM SRC_FILES $FILE_PATH/redis-cli.c)
list(REMOVE_ITEM SRC_FILES $FILE_PATH/redis-benchmark.c)
加载进来相关的所有源文件和头文件:
#################### set include path ####################
set(SRC_PATH
$CMAKE_CURRENT_SOURCE_DIR/src
$CMAKE_CURRENT_SOURCE_DIR/src/Win32_Interop
$CMAKE_CURRENT_SOURCE_DIR/deps/jemalloc-win/src
$CMAKE_CURRENT_SOURCE_DIR/deps/lua/src
$CMAKE_CURRENT_SOURCE_DIR/deps/hiredis
)
include_directories(
$SRC_PATH
$CMAKE_CURRENT_SOURCE_DIR/deps/lua/src
$CMAKE_CURRENT_SOURCE_DIR/deps/hiredis
$CMAKE_CURRENT_SOURCE_DIR/deps/hiredis/adapters
$CMAKE_CURRENT_SOURCE_DIR/deps/jemalloc-win/include
)
注意的是要包含全,且只包含用到的不要漏掉了,不该包含的不要包含。redis-server.exe里用到了一些第三方的依赖,如lua,jemalloc-win内存分配机制。特别说明的是,源码里微软实现的那个DLMALLOC,代码就有问题,所以这里一定要启用USE_JEMALLOC这个宏定义。
还需要移除掉包含的文件有:
#过滤不相关的源文件
set(FILE_PATH $CMAKE_CURRENT_SOURCE_DIR/src)
set(HREDIS_FILE_PATH $CMAKE_CURRENT_SOURCE_DIR/deps/hiredis)
set(LUA_FILE_PATH $CMAKE_CURRENT_SOURCE_DIR/deps/lua/src)
list(REMOVE_ITEM SRC_FILES $FILE_PATH/ae_kqueue.c)
list(REMOVE_ITEM SRC_FILES $FILE_PATH/ae_epoll.c)
list(REMOVE_ITEM SRC_FILES $FILE_PATH/ae_evport.c)
list(REMOVE_ITEM SRC_FILES $FILE_PATH/ae_select.c)
list(REMOVE_ITEM SRC_FILES $FILE_PATH/redis-cli.c)
list(REMOVE_ITEM SRC_FILES $FILE_PATH/redis-benchmark.c)
list(REMOVE_ITEM SRC_FILES $FILE_PATH/redis-check-aof.c)
list(REMOVE_ITEM SRC_FILES $FILE_PATH/redis-check-dump.c)
list(REMOVE_ITEM SRC_FILES $HREDIS_FILE_PATH/test.c)
list(REMOVE_ITEM SRC_FILES $HREDIS_FILE_PATH/sds.c)
list(REMOVE_ITEM SRC_FILES $LUA_FILE_PATH/lua.c)
list(REMOVE_ITEM SRC_FILES $LUA_FILE_PATH/luac.c)
还有_off_t重定义问题,因为微软团队发现redis在Posix体系下,off_t被定义成64位,而在windows下被sys\\types.h文件定义成32位,所以windows团队就在工程属性里定义了_OFF_T_DEFINED ,使32位的不生效,用自己定义在文件的,所以我们需要在自已的工程中,也进行同样的操作。
add_definitions(
-D_OFF_T_DEFINED
-DUSE_JEMALLOC
-D_WIN64
)
这其中还报的有其他神奇的错,
如:ae_wsiocp.c.obj : error LNK2005: removeMatchFromList already defined in ae.c.obj
这太奇怪了吧,全局搜了下removeMatchFromList这个函数也只在ae_wsiocp.c里有。ae.c里面真的没有啊,为啥?本不想轻易动源码的,无奈,在removeMatchFromList函数前加个static 这一关通过了。
还剩最后一个错:
util.c.obj : error LNK2001: unresolved external symbol __imp_je_malloc_message
最后附上完整的cmake工程模板配置:
cmake_minimum_required(VERSION 3.12)
project(redis-server VERSION 0.0.1)
set(CMAKE_CXX_STANDARD 11)
#################### QT dependencies ####################
#set(CMAKE_CXX_STANDARD 11)
#set(CMAKE_AUTOMOC ON)
#set(CMAKE_AUTORCC ON)
#set(CMAKE_AUTOUIC ON)
#set(QT_VERSION 5)
#set(REQUIRED_LIBS Core)
#set(REQUIRED_LIBS_QUALIFIED Qt5::Core)
#################### set output directory ####################
set(BUILD_DIR $CMAKE_CURRENT_SOURCE_DIR/build)
set(LIB_DIR $BUILD_DIR/Release)
set(LIB_FIX)
if (CMAKE_BUILD_TYPE MATCHES "Debug")
set(LIB_DIR $BUILD_DIR/Debug)
set(LIB_FIX _d)
endif ()
get_filename_component(ABSOLUTE_PATH $LIB_DIR ABSOLUTE)
set(LIB_DIR $ABSOLUTE_PATH)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY $LIB_DIR/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY $LIB_DIR/lib)
set(CMAKE_PDB_OUTPUT_DIRECTORY $LIB_DIR/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY $LIB_DIR/lib)
set(LIB_DIR_FIX $LIB_DIR/bin)
option(USE_VS_BUILD "use visual studio build." OFF)
if (USE_VS_BUILD)
set(LIB_DIR_FIX $LIB_DIR/bin/Debug)
endif ()
#################### set include path ####################
set(SRC_PATH
$CMAKE_CURRENT_SOURCE_DIR/src
$CMAKE_CURRENT_SOURCE_DIR/src/Win32_Interop
$CMAKE_CURRENT_SOURCE_DIR/deps/jemalloc-win/src
$CMAKE_CURRENT_SOURCE_DIR/deps/lua/src
$CMAKE_CURRENT_SOURCE_DIR/deps/hiredis
)
include_directories(
$SRC_PATH
$CMAKE_CURRENT_SOURCE_DIR/deps/lua/src
$CMAKE_CURRENT_SOURCE_DIR/deps/hiredis
$CMAKE_CURRENT_SOURCE_DIR/deps/hiredis/adapter
$CMAKE_CURRENT_SOURCE_DIR/deps/jemalloc-win/include
)
add_definitions(
-D_OFF_T_DEFINED
-DUSE_JEMALLOC
)
#################### scan source files ####################
foreach (path $SRC_PATH)
aux_source_directory($path SRC_FILES)
endforeach ()
#message(STATUS $SRC_FILES)
#过滤不相关的源文件
set(FILE_PATH $CMAKE_CURRENT_SOURCE_DIR/src)
set(HREDIS_FILE_PATH $CMAKE_CURRENT_SOURCE_DIR/deps/hiredis)
set(LUA_FILE_PATH $CMAKE_CURRENT_SOURCE_DIR/deps/lua/src)
list(REMOVE_ITEM SRC_FILES $FILE_PATH/ae_kqueue.c)
list(REMOVE_ITEM SRC_FILES $FILE_PATH/ae_epoll.c)
list(REMOVE_ITEM SRC_FILES $FILE_PATH/ae_evport.c)
list(REMOVE_ITEM SRC_FILES $FILE_PATH/ae_select.c)
list(REMOVE_ITEM SRC_FILES $FILE_PATH/redis-cli.c)
list(REMOVE_ITEM SRC_FILES $FILE_PATH/redis-benchmark.c)
list(REMOVE_ITEM SRC_FILES $FILE_PATH/redis-check-aof.c)
list(REMOVE_ITEM SRC_FILES $FILE_PATH/redis-check-dump.c)
list(REMOVE_ITEM SRC_FILES $HREDIS_FILE_PATH/test.c)
list(REMOVE_ITEM SRC_FILES $HREDIS_FILE_PATH/sds.c)
list(REMOVE_ITEM SRC_FILES $LUA_FILE_PATH/lua.c)
list(REMOVE_ITEM SRC_FILES $LUA_FILE_PATH/luac.c)
#################### version config ####################
#configure_file($BUILD_DIR/../include/version.h.in $CMAKE_CURRENT_BINARY_DIR/plugin_version.h)
#include_directories($CMAKE_CURRENT_BINARY_DIR)
#if (MSVC)
# set(MY_VERSIONINFO_RC "$CMAKE_CURRENT_BINARY_DIR/VersionInfo.rc")
# configure_file("$CMAKE_CURRENT_SOURCE_DIR/resource.rc.in"
# "$MY_VERSIONINFO_RC")
#endif ()
#add_library($PROJECT_NAME SHARED $SRC_FILES $MY_VERSIONINFO_RC)
#add_executable($PROJECT_NAME WIN32 $SRC_FILES)
add_executable($PROJECT_NAME $SRC_FILES)
#################### set target properties ####################
set_target_properties($PROJECT_NAME PROPERTIES DEBUG_POSTFIX _d)
#################### set target dependencies ####################
#find_package(GTest CONFIG REQUIRED)
#find_package(Qt$QT_VERSION COMPONENTS $REQUIRED_LIBS REQUIRED)
#set(LOGGING_LIB $LIB_DIR/lib/Logging$LIB_FIX.lib)
#set(REDIS_CLIENT_LIB $LIB_DIR/lib/RedisClient$LIB_FIX.lib)
set(THIRD_LIBS
#$LOGGING_LIB
#$REDIS_CLIENT_LIB
)
#target_link_options($PROJECT_NAME PRIVATE -mwindows)
target_link_libraries($PROJECT_NAME PRIVATE $THIRD_LIBS)
引用
Windows版Redis3.2.100中_off_t重定义问题解决_ysdonet的博客-CSDN博客_off_t 重定义
Redis 3.0源码分析-内存分配zmalloc_肥叔菌的博客-CSDN博客
Redis Sentinel 源码:Redis的高可用模型分析 - 知乎
Redis源码剖析--内存分配_ZeeCoder的博客-CSDN博客
Redis底层详解(三) 内存管理_英雄哪里出来的博客-CSDN博客
https://blog.csdn.net/whereisherofrom/category_9282660.html
详解Redis源码中的部分快速排序算法(pqsort.c)_果冻虾仁的博客-CSDN博客_redis 排序算法
超强干货来袭 云风专访:近40年码龄,通宵达旦的技术人生以上是关于Redis源码在windows下的成功编译(附cmake工程配置)的主要内容,如果未能解决你的问题,请参考以下文章