Redis源码在windows下的成功编译(附cmake工程配置)

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: Redis源码在windows下的成功编译(附cmake工程配置)

缘由


windows下的redis有现成的安装包,这也是别人打包好并推荐的方式。


也可以自己编译打包一份来用,或者对某部分进行定制化的修改(windows下的redis不是很稳,存在一些问题)。为了更好的使用redis,分析Redis 源码是很有必要。特别是对数据结构和算法的学习,这是很好的例子,比lecode刷题有趣。


把源码fork下来,然后加入cmake项目工程编译打包生成程exe可执行程序。中间遇到一些问题,这里总结记录下。在msvs目录里有vstudio的工程配置,能够直接一键编译,习惯vstudio的可以略过。构建目标是redis-server.exe,其他的如redis-cli.exe则需单独构建。



以服务方式启动:


./redis-server.exe  --service-install redis.windows-service.conf


源码地址


项目源码下载地址:


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


这个错,还是需稍微改动下源码,把redis-3.0\deps\jemalloc-win\src中的utils.c中的:


JEMALLOC_EXPORT void    (*je_malloc_message)(void *, const char *s)


去掉那个JEMALLOC_EXPORT。最后编译全部ok啦。


最后在编译成功的目录里运行下看看是否正常:




可以看到是成功跑起来了。


最后附上完整的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博客


CMake语法—命令list - kaizen - 博客园


读懂Redis源码,我总结了这7点心得


Redis Sentinel 源码:Redis的高可用模型分析 - 知乎


Redis源码剖析--内存分配_ZeeCoder的博客-CSDN博客


Redis底层详解(三) 内存管理_英雄哪里出来的博客-CSDN博客


https://blog.csdn.net/whereisherofrom/category_9282660.html


详解Redis源码中的部分快速排序算法(pqsort.c)_果冻虾仁的博客-CSDN博客_redis 排序算法

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
2月前
|
NoSQL Redis 数据安全/隐私保护
Redis 最流行的图形化界面下载及使用超详细教程(带安装包)! redis windows客户端下载
文章提供了Redis最流行的图形化界面工具Another Redis Desktop Manager的下载及使用教程,包括如何下载、解压、连接Redis服务器以及使用控制台和查看数据类型详细信息。
192 6
Redis 最流行的图形化界面下载及使用超详细教程(带安装包)! redis windows客户端下载
|
2月前
|
NoSQL Redis 数据库
Redis 图形化界面下载及使用超详细教程(带安装包)! redis windows下客户端下载
文章提供了Redis图形化界面工具的下载及使用教程,包括如何连接本地Redis服务器、操作键值对、查看日志和使用命令行等功能。
191 0
Redis 图形化界面下载及使用超详细教程(带安装包)! redis windows下客户端下载
|
1月前
|
存储 负载均衡 Java
如何配置Windows主机MPIO多路径访问存储系统
Windows主机多路径(MPIO)是一种技术,用于在客户端计算机上配置多个路径到存储设备,以提高数据访问的可靠性和性能。本文以Windows2012 R2版本为例介绍如何在客户端主机和存储系统配置多路径访问。
98 13
如何配置Windows主机MPIO多路径访问存储系统
|
1月前
|
NoSQL Linux PHP
如何在不同操作系统上安装 Redis 服务器,包括 Linux 和 Windows 的具体步骤
本文介绍了如何在不同操作系统上安装 Redis 服务器,包括 Linux 和 Windows 的具体步骤。接着,对比了两种常用的 PHP Redis 客户端扩展:PhpRedis 和 Predis,详细说明了它们的安装方法及优缺点。最后,提供了使用 PhpRedis 和 Predis 在 PHP 中连接 Redis 服务器及进行字符串、列表、集合和哈希等数据类型的基本操作示例。
64 4
|
1月前
|
Dart 搜索推荐 IDE
Windows下Zed编辑器配置Dart环境
本文介绍了Dart编程语言及其主要框架Flutter的优势,并推荐使用轻量级编辑器Zed进行Dart开发。详细步骤包括Dart环境的安装与配置,Zed编辑器的安装与个性化设置,以及如何在Zed中编写并运行Dart的HelloWorld程序。通过自定义任务实现Dart文件的快速运行,提高了开发效率。
|
1月前
|
监控 安全 网络安全
Windows Server管理:配置与管理技巧
Windows Server管理:配置与管理技巧
87 3
|
2月前
|
缓存 NoSQL Ubuntu
大数据-39 Redis 高并发分布式缓存 Ubuntu源码编译安装 云服务器 启动并测试 redis-server redis-cli
大数据-39 Redis 高并发分布式缓存 Ubuntu源码编译安装 云服务器 启动并测试 redis-server redis-cli
65 3
|
2月前
|
存储 Linux 编译器
cmake的单目录和多目录的使用(Linux和Windows)
本文介绍了在Windows和Linux平台上使用CMake构建单目录和多目录项目的步骤,包括如何配置CMakeLists.txt文件以及如何生成和使用可执行文件、库文件。
61 2
|
2月前
|
NoSQL Redis 数据库
Redis Windows版下载,带安装包
文章提供了Windows版Redis的下载和安装指南,包括如何解压、启动Redis服务以及连接到Redis数据库。
1095 0
Redis Windows版下载,带安装包
|
2月前
|
弹性计算 关系型数据库 数据安全/隐私保护
阿里云国际版如何配置Windows服务器的虚拟内存
阿里云国际版如何配置Windows服务器的虚拟内存