loentar / ngrest

Fast and easy C++ RESTful WebServices framework
Apache License 2.0
464 stars 93 forks source link

Linking static vs. shared external libraries in ngrest build #70

Open jjmccollum opened 4 years ago

jjmccollum commented 4 years ago

I'm having trouble getting ngrest build to complete successfully. The service I'd like to build and deploy has two external dependencies: the MySQL C++ Connector 8.0 with the X DevAPI (https://dev.mysql.com/doc/dev/connector-cpp/8.0/devapi_ref.html), and a smaller library of my own (I'll call it dep for reference).

Based on the previous discussion I've seen on the Google Groups page, I know that I should incorporate external libraries like these in the PROJECT\SERVICE\CMakeLists.txt script. For MySQL, I've added a FindMYSQL.cmake script parallel to CMakeLists.txt, and I invoke this script to set the appropriate MYSQL_INCLUDE_DIR and MYSQL_LIBRARY variables. For the other library, I have added it in a lib subdirectory of the service (parallel to src), and I build its library by calling add_subdirectory in the script. Based on the Google Groups discussions, I also know that the include directories and libraries should be added as the final arguments of the include_directories and target_link_libraries calls for the service at the end of the script. I have done all of this in my CMakeLists.txt script.

One thing I've noticed is that if I don't specify that the dep library should be built as a shared library rather than a static library, I get a series of multiple definition errors. I imagine that this is because the library for the service itself has the CMake target build type MODULE, which, to the best of my knowledge, is very similar to SHARED, and linking static libraries into a shared library is generally discouraged. And in fact, if I set BUILD_SHARED_LIBS to ON before I build the dep library, then these errors go away. Am I correct that any external libraries incorporated into an ngrest service will need to be shared libraries rather than static ones?

I'm also getting a lot of undefined reference errors for MySQL, and since I'm only linking to this library rather than building it, I'm not sure what I'm doing wrong or how I can fix it. My FindMYSQL.cmake script correctly locates the include directory and the mysqlcppconn8.lib library that implements the X DevAPI, but is CMake trying to link to this static library rather than the DLL that it should be using in this case? Any help would be appreciated.

In case it matters, I am testing this out on Windows 10. I'm aware of the ngrest-db library, and I'm keeping it in mind as an option, but my immediate preference would be to get a basic service running using ngrest alone if possible.

jjmccollum commented 4 years ago

In addition, if I remove the ngrest dependency and change the service's .cpp file into an executable script (which I'll call app.cpp for convenience), then everything builds successfully. Here is the top-level CMakeLists.txt:

cmake_minimum_required(VERSION 3.0)
# Set the project name and version:
project(my-project
    VERSION 1.0
    DESCRIPTION "Example project based on ngrest service"
    LANGUAGES C CXX)

# Set warning and optimization flags:
set(WARNING_FLAGS "-Wall")
if(NOT MSVC)
    set(CMAKE_CXX_FLAGS_DEBUG "-ggdb")
    set(CMAKE_CXX_FLAGS_RELEASE "-O3")
endif()

# Only do these if this is the main project, and not if it is included through add_subdirectory:
if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
    set(CMAKE_CXX_STANDARD 11)
    set(CMAKE_CXX_STANDARD_REQUIRED ON)
    set(CMAKE_CXX_EXTENSIONS OFF)
endif()

# Set build options and locations if they have not been set already:
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS YES CACHE BOOL "Export all symbols")
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib CACHE PATH "Path to build archive directory")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib CACHE PATH "Path to build library directory")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin CACHE PATH "Path to build runtime directory")

# Find the MySQL header directory (MYSQL_INCLUDE_DIR) and library (MYSQL_LIBRARY):
set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
find_package(MYSQL REQUIRED)
# Build the dep library:
add_subdirectory(lib/dep)
# Add the executable, located in the scripts directory:
add_subdirectory(scripts)

And here is the CMakeLists.txt in scripts:

# Add all executable scripts to be generated:
add_executable(app app.cpp)

# Point the executables to their include directories:
target_include_directories(app PUBLIC ${MYSQL_INCLUDE_DIR})

# Link the build targets to external libraries:
target_link_libraries(app ${MYSQL_LIBRARY} dep)

Again, this builds successfully, and the executable works as expected, regardless of whether or not I specify -DBUILD_SHARED_LIBS=ON as a command-line argument to cmake.