Corvusoft / restbed

Corvusoft's Restbed framework brings asynchronous RESTful functionality to C++14 applications.
http://www.corvusoft.co.uk
Other
1.93k stars 377 forks source link

Builds with Restbed lib fail, with missing OpenSSL symbols galore #521

Closed Stokestack closed 2 years ago

Stokestack commented 2 years ago

I built Restbed according to the (first, non-external libraries) instructions and the process appeared to complete without issue.

But upon attempting to build a test project, it fails with errors like:

[build] /usr/bin/ld: ../lib/librestbed.a(request.cpp.o): in function `asio::detail::posix_tss_ptr_create(unsigned int&)':
[build] request.cpp:(.text._ZN4asio6detail20posix_tss_ptr_createERj[_ZN4asio6detail20posix_tss_ptr_createERj]+0x14): undefined reference to `pthread_key_create'
[build] /usr/bin/ld: ../lib/librestbed.a(request.cpp.o): in function `asio::ssl::detail::openssl_init_base::do_init::~do_init()':
[build] request.cpp:(.text._ZN4asio3ssl6detail17openssl_init_base7do_initD2Ev[_ZN4asio3ssl6detail17openssl_init_base7do_initD5Ev]+0x10): undefined reference to `CONF_modules_unload'

This looks like ASIO and maybe OpenSSL, and there are no other libs in Restbed's distribution directory other than librestbed.*. So... I don't know what the problem is. The ASIO and OpenSSL subdirectories are present and populated under Restbed's dependency directory in the source tree.

LukasWoodtli commented 2 years ago

I think you need to link your test binary with OpenSSL and pthread (and maybe also to ASIO). Something like this:

target_compile_options(${YOUR_TARGET_NAME} PRIVATE -pthread)
target_link_libraries(${YOUR_TARGET_NAME} PRIVATE -pthread)

target_link_libraries(${YOUR_TARGET_NAME} PRIVATE ${ssl_LIBRARY_SHARED})

target_link_libraries(${YOUR_TARGET_NAME} PRIVATE ${crypto_LIBRARY_SHARED})

And maybe analogous for ASIO.

Stokestack commented 2 years ago

Thanks for the reply. I followed the build directions here (for non-external libraries), so I wonder how this works for anyone.

LukasWoodtli commented 2 years ago

In a project of mine, I had to link to pthread. There I disable the use of SSL (for now) so I don't need to link these libraries.

target_link_libraries(${TARGET_NAME}
    PUBLIC
        restbed-shared
        -lpthread)

I'm not sure why it's not working without linking these dependencies. Basically It's there in the CMake project of restbed...

Stokestack commented 2 years ago

Thanks for that reply. I did eventually get it to work, expanding a bit on what you posted above. Somewhere I found a project that was linking against Restbed, so I integrated CMake code from there into mine.

I don't understand why the extra lib linking is necessary either since I would expect all this to be built into the Restbed lib. It would also be nice if this information were included in the Restbed how-to docs, given that it's critical to using the product.

Anyway, here's the whole CMakeLists.txt file for my project that uses Restbed. I have the entire Restbed source tree as a subdirectory, so it's built as a lib and then statically linked into my program.

In this file, restbed_server refers to OpenAPI code generated by the OpenAPI generator for Restbed. So those references are not necessary to make a Restbed project.

cmake_minimum_required(VERSION 3.0.0)
project(YOUR_PROJECT_NAME VERSION 0.1.0)

include(CTest)
enable_testing()

add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/restbed)

file( GLOB_RECURSE API_MODEL_MANIFEST "${CMAKE_CURRENT_SOURCE_DIR}/restbed_server/model/*.cpp" )
add_executable(YOUR_PROJECT_NAME main.cpp
    "${CMAKE_CURRENT_SOURCE_DIR}/restbed_server/api/DefaultApi.cpp"
    ${API_MODEL_MANIFEST})

set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
include(CPack)

target_link_libraries(YOUR_PROJECT_NAME PRIVATE restbed)

target_include_directories(YOUR_PROJECT_NAME PUBLIC include
    "${CMAKE_CURRENT_SOURCE_DIR}/restbed/distribution/include"
    "${CMAKE_CURRENT_SOURCE_DIR}/restbed_server/api"
    "${CMAKE_CURRENT_SOURCE_DIR}/restbed_server/model"
)
message("Restbed include = ${RestbedSourceDir}/distribution/include")

target_link_directories(YOUR_PROJECT_NAME PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/restbed/distribution/library")

target_compile_options(YOUR_PROJECT_NAME PRIVATE -pthread)
target_link_libraries(YOUR_PROJECT_NAME PRIVATE -pthread)

# Set up ASIO
find_path( asio_INCLUDE asio.hpp HINTS "${CMAKE_CURRENT_SOURCE_DIR}/restbed/dependency/asio/asio/include")

if ( asio_INCLUDE )
    set( ASIO_FOUND TRUE )
    set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DASIO_STANDALONE=YES" )

    message( STATUS "${Green}Found ASIO include at: ${asio_INCLUDE}${Reset}" )
else ( )
    message( FATAL_ERROR "${Red}Failed to locate ASIO dependency.${Reset}" )
endif ( )

# Set up OpenSSL
find_library(ssl_LIBRARY ssl)
find_library(crypto_LIBRARY crypto)
find_path( ssl_INCLUDE openssl/ssl.h)

if ( ssl_INCLUDE AND ssl_LIBRARY AND crypto_LIBRARY )
    set( OPENSSL_FOUND TRUE )
    add_definitions( -DBUILD_SSL=TRUE )

    if ( APPLE AND BUILD_SSL )
        set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-declarations" )
    endif( )

    message( STATUS "${Green}Found OpenSSL library at: ${ssl_LIBRARY}${Reset}" )
    message( STATUS "${Green}Found OpenSSL include at: ${ssl_INCLUDE}${Reset}" )
    message( STATUS "${Green}Found Crypto library at: ${crypto_LIBRARY}${Reset}" )
else( )
    message( FATAL_ERROR "${Red}Failed to locate OpenSSL dependency. see restbed/dependency/openssl; ./config shared; make all${Reset}" )
endif( )
Stokestack commented 2 years ago

My test project is basically just one of the provided examples. I get loads of errors after the build command:

/usr/bin/clang++ -g -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.1.sdk -mmacosx-version-min=11.6 -Wl,-search_paths_first -Wl,-headerpad_max_install_names CMakeFiles/Series2Server.dir/main.cpp.o -o Series2Server -L/Users/me/data/series2server/restbed/library -Wl,-rpath,/Users/me/data/series2server/restbed/library -lrestbed -pthread

[build] Undefined symbols for architecture x86_64: [build] "_BIO_ctrl", referenced from: [build] asio::ssl::detail::engine::map_error_code(std::1::error_code&) const in librestbed.a(service_impl.cpp.o) [build] asio::ssl::detail::engine::map_error_code(std::1::error_code&) const in librestbed.a(socket_impl.cpp.o) and so forth...

So I went back to the libssl.a I linked Restbed with, and used nm -u (for undefined symbols) and examined libssl.a. Sure enough, these are among the undefined symbols:

libssl.a(bio_ssl.o): _BIO_callback_ctrl _BIO_clear_flags _BIO_copy_next_retry _BIO_ctrl

So why are they missing?

Stokestack commented 2 years ago

Apparently I had a misconception that the OpenSSL libs would be folded into the Restbed lib. Moving them into my source tree and and adding link directives for them took care of the errors here.