c++cmakeboostincludeheader-files

How to hide macro usage from an output shared library


I'm trying to write a C++ logging library. It uses boost::log mainly for the BOOST_LOG_SEV macro. I can use my library without an issue like LOG(debug) << "Test message". Here is my public header.

include/logger.hpp

#include "config.hpp"

#define BOOST_LOG_DYN_LINK 1

#include <boost/log/sinks.hpp>
#include <boost/log/sources/global_logger_storage.hpp>
#include <boost/log/sources/severity_channel_logger.hpp>
#include <boost/log/trivial.hpp>

BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(logger, boost::log::sources::severity_channel_logger<severity_level>)

BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", severity_level)

#define LOG(severity) BOOST_LOG_SEV(logger::get(), severity)

class LoggerImpl;  // forward declaration

namespace Logger {

  void init(const Config &config);

  inline std::unique_ptr<LoggerImpl> mImpl;  // private implementation

}

Since I'm using the BOOST_LOG_SEV macro and performing some boost configurations, I need to include boost headers in my public header. But, this causes me to need to publicly link the boost dependency with my output shared library (liblogger.so). And consequently, libraries use liblogger as a dependency and need to link with boost::log as well. How can I hide boost dependencies from public my header without affecting my library's usage?

I tried to move the BOOST_LOG_SEV macro usage and all boost includes into the private implementation but it didn't work since I cannot capture the character stream given to the LOG(severity) << macro.

EDIT: CMakeLists.txt

set(PROJECT_NAME "Logger")
set(LIBRARY_NAME ${PROJECT_NAME})
string(TOLOWER ${PROJECT_NAME} LOWERCASE_PROJECT_NAME)

project(${PROJECT_NAME}
    VERSION ${VERSION}
    DESCRIPTION "Logging library"
)

add_subdirectory(include)
add_subdirectory(src)

set(Boost_USE_STATIC_LIBS OFF)
find_package(Boost 1.54 COMPONENTS log log_setup REQUIRED)

set(LIBRARIES
    ${Boost_LIBRARIES}
    pthread
    stdc++fs
)

add_library(${LIBRARY_NAME}
    SHARED
    ${CXX_SOURCES}
    ${CXX_HEADERS}
)

set(INCLUDE_DIRS
    "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
    "$<INSTALL_INTERFACE:include>")

target_include_directories(${LIBRARY_NAME} PUBLIC ${INCLUDE_DIRS})

target_link_libraries(${LIBRARY_NAME}
    PUBLIC
    ${LIBRARIES}
)

set_target_properties(${PROJECT_NAME}
    PROPERTIES
    SKIP_BUILD_RPATH 1
    VERSION ${PROJECT_VERSION}
    SOVERSION ${PROJECT_VERSION_MAJOR}
    OUTPUT_NAME ${LOWERCASE_PROJECT_NAME}
)

install(TARGETS ${PROJECT_NAME}
    EXPORT "${PROJECT_NAME}Targets"
    LIBRARY
    DESTINATION ${CMAKE_INSTALL_LIBDIR}
    COMPONENT libraries
)

install(FILES
    "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
    "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
    DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
    COMPONENT headers
)

install(EXPORT ${PROJECT_NAME}Targets
    NAMESPACE ${PROJECT_NAME}::
    DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
    COMPONENT headers
)

Solution

  • After reading the comment I managed to solve the problem by adding include(CMakeFindDependencyMacro) and a find_dependency call into the config file used by configure_package_config_file.

    @PACKAGE_INIT@
    
    include(CMakeFindDependencyMacro)
    find_dependency(Boost 1.54 COMPONENTS log log_setup REQUIRED)
    
    include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
    check_required_components(@PROJECT_NAME@)
    

    Now, the libraries use liblogger as dependency are no longer need to call find_package(Boost ... ) explicitly.