AOG Poston
a software engineer

Why Drogon isnt Compiling With Hiredis.
by AOGPoston on 04/17/24

Background Info

While writing a websocket server in Drogon, I ran into an issue. It looked something like this.

$ sh build_app_server.sh

20240417 01:39:10.020173 UTC 9775072 FATAL
Redis is not supported by drogon, please install the hiredis library first. - RedisClientManagerSkipped.cc:40
build_app_server.sh: line 6: 6631 Abort trap: 6 ./tot_app_server
aogposton@Amons-MacBook-Pro tot %

Here what I tried that you might try, and what fixed the problem.

Installed Hiredis

The most obvious solution is to install Hiredis. Its a c client for Redis and is well documented.

On mac using brew:

brew install hiredis

Simple enough, but didn't work. My Drogon project threw the same error.

Added Hiredis to CmakeLists.txt

With Hiredis on my computer now, perhaps including hired into my CMake will inform Drogon that Hiredis is available to use. The tricky part is is that since I used Homebrew I'll have to tell CMake to check Homebrew's directories for headers.

include_directories(/opt/homebrew/include/hiredis/)
link_directories(/opt/homebrew/lib/)

find_package(hiredis REQUIRED)

target_link_libraries(
  ${PROJECT_NAME}
  PRIVATE Drogon::Drogon
  PUBLIC hiredis)

This also didn't work for me.

Download Drogon and compile from source

When I downloaded Drogon I used Homebrew or vcpkg. So, I though maybe the version I got from that source did not have the necessary CMake files to include Hiredis, or Drogon had to be recompiled with Hiredis on my machine to completely work with Hiredis.

git clone [email protected]:drogonframework/drogon.git

cd drogon
sudo sh build.sh

After building and installing the Drogon library again, progress was made. However now I was getting another error:

add_library cannot create imported target "hiredis" because another
[cmake] target with the same name already exists.

But why?

Alter the findhiredis.cmake file in the library

So, after fiddling around with this thing for a few hours disabling the add_library line and trying to add library a different way, I decided to hunt down the cmake file responsible for linking Drogon and Hiredis and see if it was causing the issue.

Since I installed Drogon again, it was now located at /usr/local/lib/cmake/Drogon/FindHiredis.cmake. With the file opened I noticed a boolean expression not being set to false.

Below is the cmake file in its entirety. In this file, the Hiredis_FOUND variable never becomes false. So, the new error I was getting about Hiredis being included twice and preventing compilation was because the findhiredis.cmake file wasn't evaluating properly.

if (HIREDIS_INCLUDE_DIRS AND HIREDIS_LIBRARIES)
    set(HIREDIS_FIND_QUIETLY TRUE)
    set(Hiredis_FOUND TRUE)
else ()
    find_path(
            HIREDIS_INCLUDE_DIR
            NAMES hiredis/hiredis.h
            HINTS ${HIREDIS_ROOT_DIR}
            PATH_SUFFIXES include)

    find_library(
            HIREDIS_LIBRARY
            NAMES hiredis
            HINTS ${HIREDIS_ROOT_DIR}
            PATH_SUFFIXES ${CMAKE_INSTALL_LIBDIR})

    set(HIREDIS_INCLUDE_DIRS ${HIREDIS_INCLUDE_DIR})
    set(HIREDIS_LIBRARIES ${HIREDIS_LIBRARY})

    include(FindPackageHandleStandardArgs)
    find_package_handle_standard_args(
            Hiredis DEFAULT_MSG HIREDIS_LIBRARY HIREDIS_INCLUDE_DIR)

    mark_as_advanced(HIREDIS_LIBRARY HIREDIS_INCLUDE_DIR)
endif ()

if(Hiredis_FOUND)
    add_library(Hiredis_lib INTERFACE IMPORTED)
    set_target_properties(Hiredis_lib
            PROPERTIES INTERFACE_INCLUDE_DIRECTORIES
            "${HIREDIS_INCLUDE_DIRS}"
            INTERFACE_LINK_LIBRARIES
            "${HIREDIS_LIBRARIES}")
endif(Hiredis_FOUND)

This led to the solution.

Change the FindHiredis.cmake file

In my opinion this file is written oddly, but who am I to judge the fastest http library? So I took everything in the if(hiredis_found) statement and placed it inside the if block of the first if statement.

That way, if Hiredis is not found, it wont add the library at this stage of compilation.


if(HIREDIS_INCLUDE_DIRS AND HIREDIS_LIBRARIES)
  set(HIREDIS_FIND_QUIETLY TRUE)
  set(Hiredis_FOUND TRUE)

  message(${Hiredis_FOUND})
  add_library(Hiredis_lib INTERFACE IMPORTED)
  set_target_properties(
    Hiredis_lib
    PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${HIREDIS_INCLUDE_DIRS}"
               INTERFACE_LINK_LIBRARIES "${HIREDIS_LIBRARIES}")
else()
  set(Hiredis_FOUND FALSE)
  find_path(
    HIREDIS_INCLUDE_DIR
    NAMES hiredis/hiredis.h
    HINTS ${HIREDIS_ROOT_DIR}
    PATH_SUFFIXES include)

  find_library(
    HIREDIS_LIBRARY
    NAMES hiredis
    HINTS ${HIREDIS_ROOT_DIR}
    PATH_SUFFIXES ${CMAKE_INSTALL_LIBDIR})

  set(HIREDIS_INCLUDE_DIRS ${HIREDIS_INCLUDE_DIR})
  set(HIREDIS_LIBRARIES ${HIREDIS_LIBRARY})

  include(FindPackageHandleStandardArgs)
  find_package_handle_standard_args(Hiredis DEFAULT_MSG HIREDIS_LIBRARY
                                    HIREDIS_INCLUDE_DIR)

  message("else")

  message(${Hiredis_FOUND})
  mark_as_advanced(HIREDIS_LIBRARY HIREDIS_INCLUDE_DIR)
endif()

And that solved the problem for me.

Feel free to reach out for help.