• Redis6.2.6源码CLion编译调试


    准备工作

    C语言的运行和构建工具介绍

    C语言是编译型语言,需要编译生成.o的目标文件,然后用链接器连接目标代码才能生成可执行文件,Windows下就是生成.exe文件。如果文件之间互相依赖,则需要把所有源文件都编译才可运行。

    然而大型项目中,源文件非常多,需要使用make工具来批量编译源文件,通过编写规则文件Makefile来告诉make工具如何进行编译,但是Makefile文件是强依赖平台的,在Linux上的Makefile文件并不能在Widnwos上面跑,而且大型项目的Makefile文件的编写也会非常复杂。

    redis项目是基于Makefile的,而且基于Linux平台,所以要想在Windows上面编译运行,还需要借助另外一个工具cmake

    cmake工具是用来自动生成跨平台Makefile文件的工具,用来生成跨平台的Makefile,同时避免复杂的Makefile编写过程。

    同样的,cmake工具相应的需要编写CMakeLists.txt规则来告诉cmake工具如何生成Makefile文件。

    Windows平台安装cygwin

    cygwin工具可以在window平台上运行Linux上面的命令等,方便编译和运行,而且该工具能让我们使用很多Linux的强大命令。下载地址: https://cygwin.com/install.html。64位Windows下载setup-x86_64.exe。下载之后直接双击安装,步骤如下:

    下一步 -> 选择下载源(install from Internet) -> 选择安装跟目录 -> 选择本地包路径 -> 选择网络连接(Direct Connection) -> 选择下载镜像 -> 选择需要安装的包 -> 下一步。

    可以搜索安装包,然后在Skip一列点击选择安装最新稳定版本,本次需要安装的包如下,可以按需安装其他包:

    • wget: 通过http或者ftp下载文件
    • gcc-core: GNU编译工具集(C,OpenMP)
    • gcc-g++: GNU编译工具集(C++)
    • make: GNU构建工具
    • cmake: 跨平台makefile生成工具
    • gdb: GNU调试工具
    • binutils: GNU编译和连接工具

    为了方便使用cygwin中的命令,还需要将其bin目录添加到系统环境变量,添加环境变量的方法如下:

    我的电脑右键 -> 选择属性 -> 高级系统设置 -> 高级tab -> 环境变量 -> 系统变量中Path双击 -> 新建一条填入cygwin安装bin目录。

    如果有需要,可以安装包管理工具apt-cyg,类似于Linux上的apt-get或者yum等,方便安装和管理包,直接从github: https://github.com/transcode-open/apt-cyg下载zip,解压后将其中的apt-cyg文件放到刚才安装的cygwin根目录下的bin目录中即可。

    安装CLion并设置编译运行环境

    然后安装运行IDE,本次使用Jetbrains全家桶中的CLion进行源码调试和阅读,由于Clion自带的MinGW会有些库缺失问题,所以还行需要设置使用cygwin作为编译运行环境。

    文件 -> 设置 -> Build, Execution, Deployment -> Add Cygwin -> Toolset那一栏选择cygwin安装目录。

    Redis6.0调试CLion配置cygwin

    导入redis源码和配置

    redis官方源码地址为: https://github.com/redis/redis,可以fork到自己的仓库,然后基于自己仓库的代码进行修改,这个可以把一些注释提交方便后续查看,也可以直接下载release里面的稳定版本的源码。这儿下载最新发布版本https://github.com/redis/redis/archive/refs/tags/6.2.6.zip

    下载redis源码之后,在CLion中选择 文件 -> 打开,选择下载好的源码文件夹,CLion会自动识别项目。

    注意一定要选择CMake项目,否则以Makefile方式加载项目进入后,添加CMakeLists文件是不能构建的,此时右键CMakeLists.txt没有Load CMake Project的选项,如果加载的方式错了,则需要推出CLion,然后把redis根目录下的.idea文件全部删掉,再重新加载。

    配置CMakeLists.txt文件

    由于redis是基于Linux上的Makefile,所以Windows上需要配置CMakeLists.txt使用cmake工具编译运行。github上已经有人尝试编写CMakeLists.txt文件,项目地址为: https://github.com/LHRchina/redis。本文也是参考该项目的CMakeLists.txt文件,然后把缺少的库补上成功编译运行的。

    redis根目录下配置CMakeLists.txt,文件内容如下:

    cmake_minimum_required(VERSION 3.0 FATAL_ERROR)
    project(redis VERSION 6.0)
    #set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/")
    set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/../src)
    message(CMAKE_RUNTIME_OUTPUT_DIRECTORY is:${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
    #if (NOT CMAKE_BUILD_TYPE)
    message(STATUS "No build type defined; defaulting to 'Debug'")
    set(CMAKE_BUILD_TYPE "Debug" CACHE STRING
            "The type of build. Possible values are: Debug, Release,
    RelWithDebInfo and MinSizeRel.")
    
    #endif()
    message(STATUS "Host is: ${CMAKE_HOST_SYSTEM}. Build target is:
    ${CMAKE_SYSTEM}")
    get_filename_component(REDIS_ROOT "${CMAKE_CURRENT_SOURCE_DIR}" ABSOLUTE)
    message(STATUS "Project root directory is: ${REDIS_ROOT}")
    # Just for debugging when handling a new platform.
    if (false)
        message("C++ compiler supports these language features:")
        foreach (i ${CMAKE_CXX_COMPILE_FEATURES})
            message(" ${i}")
        endforeach ()
    endif ()
    message(STATUS "Generating release.h...")
    execute_process(
            COMMAND sh -c ./mkreleasehdr.sh
            WORKING_DIRECTORY ${REDIS_ROOT}/src/
    )
    add_subdirectory(deps)
    add_subdirectory(src/modules)
    set(SRC_SERVER_TMP
            src/crcspeed.c
            src/crcspeed.h
            src/sha256.c
            src/sha256.h
            src/connection.c
            src/connection.h
            src/acl.c
            src/timeout.c
            src/tracking.c
            src/tls.c
            src/adlist.c
            src/ae.c
            src/anet.c
            # windows屏蔽掉下面两个文件,mac系统不需要屏蔽,这两个是mac环境多路复用的库
            # /usr/local/include/event.h
            # src/ae_kqueue.c
            src/mt19937-64.c
            src/mt19937-64.h
            src/monotonic.c
            src/monotonic.h
            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/lolwut.h
            src/lolwut5.c
            src/lolwut6.c
            src/listpack.c
            src/localtime.c
            src/gopher.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/ae.c
            src/crc64.c
            src/crc16.c
            src/dict.c
            src/siphash.c
            )
    if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
        # better not to work with jemalloc
    endif()
    set(EXECUTABLE_OUTPUT_PATH src)
    add_executable(redis-server ${SRC_SERVER})
    add_executable(redis-cli ${SRC_CLI})
    set_property(TARGET redis-server PROPERTY C_STANDARD 99)
    set_property(TARGET redis-server PROPERTY CXX_STANDARD 11)
    set_property(TARGET redis-server PROPERTY CXX_STANDARD_REQUIRED ON)
    set_property(TARGET redis-cli PROPERTY C_STANDARD 99)
    set_property(TARGET redis-cli PROPERTY CXX_STANDARD 11)
    set_property(TARGET redis-cli PROPERTY CXX_STANDARD_REQUIRED ON)
    target_include_directories(redis-server
            PRIVATE ${REDIS_ROOT}/deps/hiredis
            PRIVATE ${REDIS_ROOT}/deps/linenoise
            PRIVATE ${REDIS_ROOT}/deps/lua/src
            )
    target_include_directories(redis-cli
            PRIVATE ${REDIS_ROOT}/deps/hiredis
            PRIVATE ${REDIS_ROOT}/deps/linenoise
            PRIVATE ${REDIS_ROOT}/deps/lua/src
            )
    target_link_libraries(redis-server
            PRIVATE pthread
            PRIVATE m
            PRIVATE lua
            PRIVATE linenoise
            PRIVATE hiredis
            )
    target_link_libraries(redis-cli
            PRIVATE pthread
            PRIVATE m
            PRIVATE linenoise
            PRIVATE hiredis
            )
    link_directories(deps/hiredis/ deps/linenoise/ diredeps/lua/src)
    install(TARGETS redis-server
            RUNTIME DESTINATION bin
            )
    #set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -c")
    

    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")
    

    deps目录下配置CMakeLists.txt,文件内容如下:

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

    deps/hiredis目录下配置CMakeLists.txt,文件内容如下:

    CMAKE_MINIMUM_REQUIRED(VERSION 3.4.0)
    INCLUDE(GNUInstallDirs)
    PROJECT(hiredis)
    
    OPTION(ENABLE_SSL "Build hiredis_ssl for SSL support" OFF)
    OPTION(DISABLE_TESTS "If tests should be compiled or not" OFF)
    OPTION(ENABLE_SSL_TESTS, "Should we test SSL connections" OFF)
    
    MACRO(getVersionBit name)
        SET(VERSION_REGEX "^#define ${name} (.+)$")
        FILE(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/hiredis.h"
                VERSION_BIT REGEX ${VERSION_REGEX})
        STRING(REGEX REPLACE ${VERSION_REGEX} "\\1" ${name} "${VERSION_BIT}")
    ENDMACRO(getVersionBit)
    
    getVersionBit(HIREDIS_MAJOR)
    getVersionBit(HIREDIS_MINOR)
    getVersionBit(HIREDIS_PATCH)
    getVersionBit(HIREDIS_SONAME)
    SET(VERSION "${HIREDIS_MAJOR}.${HIREDIS_MINOR}.${HIREDIS_PATCH}")
    MESSAGE("Detected version: ${VERSION}")
    
    PROJECT(hiredis VERSION "${VERSION}")
    
    SET(ENABLE_EXAMPLES OFF CACHE BOOL "Enable building hiredis examples")
    
    SET(hiredis_sources
            alloc.c
            async.c
            dict.c
            hiredis.c
            net.c
            read.c
            sds.c
            sockcompat.c)
    
    SET(hiredis_sources ${hiredis_sources})
    
    IF(WIN32)
        ADD_COMPILE_DEFINITIONS(_CRT_SECURE_NO_WARNINGS WIN32_LEAN_AND_MEAN)
    ENDIF()
    
    ADD_LIBRARY(hiredis SHARED ${hiredis_sources})
    
    SET_TARGET_PROPERTIES(hiredis
            PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS TRUE
            VERSION "${HIREDIS_SONAME}")
    IF(WIN32 OR MINGW)
        TARGET_LINK_LIBRARIES(hiredis PRIVATE ws2_32)
    ENDIF()
    
    TARGET_INCLUDE_DIRECTORIES(hiredis PUBLIC $<INSTALL_INTERFACE:.> $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)
    
    CONFIGURE_FILE(hiredis.pc.in hiredis.pc @ONLY)
    
    INSTALL(TARGETS hiredis
            EXPORT hiredis-targets
            RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
            LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
            ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
    
    INSTALL(FILES hiredis.h read.h sds.h async.h alloc.h
            DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hiredis)
    
    INSTALL(DIRECTORY adapters
            DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hiredis)
    
    INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/hiredis.pc
            DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
    
    export(EXPORT hiredis-targets
            FILE "${CMAKE_CURRENT_BINARY_DIR}/hiredis-targets.cmake"
            NAMESPACE hiredis::)
    
    SET(CMAKE_CONF_INSTALL_DIR share/hiredis)
    SET(INCLUDE_INSTALL_DIR include)
    include(CMakePackageConfigHelpers)
    configure_package_config_file(hiredis-config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/hiredis-config.cmake
            INSTALL_DESTINATION ${CMAKE_CONF_INSTALL_DIR}
            PATH_VARS INCLUDE_INSTALL_DIR)
    
    INSTALL(EXPORT hiredis-targets
            FILE hiredis-targets.cmake
            NAMESPACE hiredis::
            DESTINATION ${CMAKE_CONF_INSTALL_DIR})
    
    INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/hiredis-config.cmake
            DESTINATION ${CMAKE_CONF_INSTALL_DIR})
    
    
    IF(ENABLE_SSL)
        IF (NOT OPENSSL_ROOT_DIR)
            IF (APPLE)
                SET(OPENSSL_ROOT_DIR "/usr/local/opt/openssl")
            ENDIF()
        ENDIF()
        FIND_PACKAGE(OpenSSL REQUIRED)
        SET(hiredis_ssl_sources
                ssl.c)
        ADD_LIBRARY(hiredis_ssl SHARED
                ${hiredis_ssl_sources})
    
        IF (APPLE)
            SET_PROPERTY(TARGET hiredis_ssl PROPERTY LINK_FLAGS "-Wl,-undefined -Wl,dynamic_lookup")
        ENDIF()
    
        SET_TARGET_PROPERTIES(hiredis_ssl
                PROPERTIES
                WINDOWS_EXPORT_ALL_SYMBOLS TRUE
                VERSION "${HIREDIS_SONAME}")
    
        TARGET_INCLUDE_DIRECTORIES(hiredis_ssl PRIVATE "${OPENSSL_INCLUDE_DIR}")
        TARGET_LINK_LIBRARIES(hiredis_ssl PRIVATE ${OPENSSL_LIBRARIES})
        IF (WIN32 OR MINGW)
            TARGET_LINK_LIBRARIES(hiredis_ssl PRIVATE hiredis)
        ENDIF()
        CONFIGURE_FILE(hiredis_ssl.pc.in hiredis_ssl.pc @ONLY)
    
        INSTALL(TARGETS hiredis_ssl
                EXPORT hiredis_ssl-targets
                RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
                LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
                ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
    
        INSTALL(FILES hiredis_ssl.h
                DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hiredis)
    
        INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/hiredis_ssl.pc
                DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
    
        export(EXPORT hiredis_ssl-targets
                FILE "${CMAKE_CURRENT_BINARY_DIR}/hiredis_ssl-targets.cmake"
                NAMESPACE hiredis::)
    
        SET(CMAKE_CONF_INSTALL_DIR share/hiredis_ssl)
        configure_package_config_file(hiredis_ssl-config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/hiredis_ssl-config.cmake
                INSTALL_DESTINATION ${CMAKE_CONF_INSTALL_DIR}
                PATH_VARS INCLUDE_INSTALL_DIR)
    
        INSTALL(EXPORT hiredis_ssl-targets
                FILE hiredis_ssl-targets.cmake
                NAMESPACE hiredis::
                DESTINATION ${CMAKE_CONF_INSTALL_DIR})
    
        INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/hiredis_ssl-config.cmake
                DESTINATION ${CMAKE_CONF_INSTALL_DIR})
    ENDIF()
    
    IF(NOT DISABLE_TESTS)
        ENABLE_TESTING()
        ADD_EXECUTABLE(hiredis-test test.c)
        IF(ENABLE_SSL_TESTS)
            ADD_DEFINITIONS(-DHIREDIS_TEST_SSL=1)
            TARGET_LINK_LIBRARIES(hiredis-test hiredis hiredis_ssl)
        ELSE()
            TARGET_LINK_LIBRARIES(hiredis-test hiredis)
        ENDIF()
        ADD_TEST(NAME hiredis-test
                COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/test.sh)
    ENDIF()
    
    # Add examples
    IF(ENABLE_EXAMPLES)
        ADD_SUBDIRECTORY(examples)
    ENDIF(ENABLE_EXAMPLES)
    

    deps/linenoise目录下配置CMakeLists.txt,文件内容如下:

    add_library(linenoise linenoise.c)
    

    deps/lua目录下配置CMakeLists.txt,文件内容如下:

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

    配置完之后,右键点击根目录下的CMakeLists.txt,选择Reload CMake Project。此时右上角会出现redis-server|Debug的运行选项,点击调试可以运行redis-server

    redis6.0调试CLion运行示意图

    运行后可以通过一些redis客户端工具连接进行测试。

    报错问题汇总

    如果使用的是其他版本的redis,则需要根据编译运行信息调整上面的CMakeLists.txt文件,相应的调整配置,一般是缺失编译文件或者多余代码。

    编译报错error: unknown type name 'Dl_info'

    首次编译的时候会遇到编译错误:

    FAILED: CMakeFiles/redis-server.dir/src/debug.c.o 
    /cygdrive/g/Projects/Git_Projects/redis-6.2.6/src/debug.c: In function 'dumpX86Calls':
    /cygdrive/g/Projects/Git_Projects/redis-6.2.6/src/debug.c:1753:5: error: unknown type name 'Dl_info'
    

    没有类型D1_info,因为这是一个调试文件,然后其中的函数没有调用,我的解决办法是把相关的函数注释掉。主要是src/debug.c文件中的dumpX86Calls函数和dumpCodeAroundEIP两个函数注释掉就可以了。

    启动报错Address already in use

    启动的时候报错端口被占用,redis-server默认使用6379端口,要去报该端口没有被占用才行,获取可以添加运行参数或者配置文件使用其他端口。

  • 相关阅读:
    前向传播与反向传播
    卷积运算
    使用GUI工具Portainer.io管控Docker容器
    NextCloud: 打造自己的网盘
    金融危机和经济危机有什么不同
    【转载】Windows环境的Workflow神器:AutoHotkey
    Lua常用模块
    Lua基本语法
    区分 IaaS、SaaS 和 PaaS
    【笔记】流畅的Python
  • 原文地址:https://www.cnblogs.com/youyoui/p/16028653.html
Copyright © 2020-2023  润新知