2
\$\begingroup\$

I needed to set some global data (logging handler, base path, etc) across all libraries/targets (internally managed). A manual system of InitLib1 which calls all InitLibX of its dependencies would work, but this seemed error prone to me.

So I came up with the following system

InitLib.hpp

#include <memory>

namespace Setup
{
    // Data used for initialization not relevant for this question
    struct Data;

    /** A type intended to map libraries onto the cpp type system, for use as template parameters */
    struct LibraryName {
            char const value[ 128 ];
    };
    
    /* DO NOT expose this function directly */
    template< LibraryName paLibraryName = CURRENT_LIBRARY_CMAKE >
    void Initialize( std::shared_ptr< Data > inData );

    /* DO NOT expose this function directly */
    template< LibraryName paLibraryName = CURRENT_LIBRARY_CMAKE >
    Data const & GetData();
}

InitLib.cpp

#include "InitLib.hpp"

#include <cstdlib>
#include <iostream>
#include <string>

static std::shared_ptr< Setup::Data > gData;

namespace
{
    template< auto... Ts >
    void InitializeDependencies( std::shared_ptr< Setup::Data > inData )
    {
        ( ( Setup::Initialize< Ts >( inData ) ), ... );
    }
}

template<>
CURRENT_LIBRARY_EXPORT_SYMBOL_CMAKE void
Setup::Initialize< CURRENT_LIBRARY >( std::shared_ptr< Setup::Data > inData )
{
    std::string libraryName = CURRENT_LIBRARY_CMAKE.value; 

    if( inData == nullptr ) {
        std::cerr << "Library " << libraryName << " must be initialized with actual data\n";
        std::abort();
    }

    if( gData != nullptr and gData != inData ) {
        std::cout << "Library " << libraryName << " is being initialized with mismatched data\n";
        std::abort();
    }
    
    if( gData == inData ) return; // library already initialized

    gData = inData;

    InitializeDependencies< CURRENT_LIBRARY_DEPENDENCIES_CMAKE >( std::move( inData ) );
};

template<>
Setup::Data const &
Setup::GetData< CURRENT_LIBRARY_CMAKE >()
{
    return *gData;
}

CMakeLists.txt

add_library( "Setup_InitLib" INTERFACE )

target_sources(
    "Setup_InitLib"
    INTERFACE
        FILE_SET "HEADERS"
        BASE_DIRS "${CURRENT_INCLUDE_FOLDER}"
        FILES "InitLib.hpp"
)
target_sources(
    "Setup_InitLib"
    INTERFACE
        "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/Source/InitLib.cpp>"
        "$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/src/Setup/Source/InitLib.cpp>"
)
set_property(
    TARGET "Setup_InitLib" 
    APPEND PROPERTY "TRANSITIVE_LINK_PROPERTIES" "SETUP_LIBRARY_ID"
)

target_compile_definitions(
    "Setup_InitLib"
    INTERFACE
        "CURRENT_LIBRARY_DEPENDENCIES_CMAKE=$<JOIN:$<TARGET_PROPERTY:SETUP_LIBRARY_ID>,$<COMMA>>"
)


function(add_library_init_code in_target in_export_symbol)
    target_link_libraries("${in_target}" PRIVATE "Setup_InitLib")
    set_property(TARGET "${in_target}" PROPERTY "SETUP_LIBRARY_NAME" "${in_target}")
    set(local_library_id "Setup::LibraryName{\"$<TARGET_PROPERTY:${in_target},SETUP_LIBRARY_NAME>\"}")
    set_property(TARGET "${in_target}" PROPERTY "INTERFACE_SETUP_LIBRARY_ID" "${local_library_id}")
    set_property(
        TARGET "${in_target}" 
        APPEND PROPERTY "EXPORT_PROPERTIES" "SETUP_LIBRARY_NAME;SETUP_LIBRARY_ID"
    )
    target_compile_definitions(
        "${in_target}"
        PRIVATE
            "CURRENT_LIBRARY_EXPORT_SYMBOL_CMAKE=${in_export_symbol}"
            "CURRENT_LIBRARY_CMAKE=${local_library_id}"
    )
    source_group("Inherited Sources" FILES "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Source/InitLib.cpp")
endfunction()

Usage:

in CMake: just add add_library_init_code after defining you target. in Cpp: any top level starting code should just call Setup::Initialize() afterwards each library can access the same data using Setup::GetData().

Questions:

  • Any way of making gData const?
  • General remarks
  • Weird edge cases
\$\endgroup\$

0

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.