Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write cmake modules for "boost-like" multi-component library?

I'm currently writing a c++ library, that has several "sub libraries", like for example the boost library.

Let's name the library "TestLib" and the sub libraries "Base" and "Ext", where Base contains come basic stuff, that doesn't depend an any other sub library. Ext however depends on some classes of Base.

Each "sub library" should compile into a separate .a or .so file, but they all should share a namespace (TestLib). Now i'm aiming to write clean cmake scripts in order to achieve this goal.

In the end i want to be able to do something like this in cmake:

find_package(TestLib 0.1 REQUIRED COMPONENTS Base Ext)

or

target_link_libraries(someapplication
PUBLIC
    TestLib::Base
)

I have put each "sub library" in a separate git repository and added them as submodules in a new repository that has only a CMakeLists.txt that just calls add_subdirectory on each of the repos.

Most of the cmake stuff i achieved, i got from this awesome tutorial at https://pabloariasal.github.io/

And the Base part works as intended (which is no wonder, since it doesn't depend on anything else).

But my problems come with the Ext part. In order for this to compile, i have to link against the Base library, which shouldn't be to hard, and with some trial and error i am sure that i will get it to work.

But i want to do it the right way.

My approach was to

find_package(TestLib COMPONENTS Base)

in the CMakeLists.txt of TestLib.Ext. But this cant be found since it has no TestLibConfig.cmake.

Which makes sense, but i don't know what to put in this file.

I tried to provide some code that exactly describes my problem, but since this would be too much to post here, i created a github for this purpose:

https://github.com/PowerSupplyTopologies/TestLib

This should contain all the relevant code.

This could be trivial to some of you, but i bet there are more people that could benefit from this approach.

Thank you in advance for any of your thoughts.

EDIT:

The library creation in the CMakeLists.txt of Base is:

set(TARGET_NAME testlibbase)

add_library(${TARGET_NAME}
    src/ClassA.cpp
    src/ClassB.cpp
)

#Add an alias so that library can be used inside the build tree, e.g.     when testing
add_library(TestLib::${TARGET_NAME} ALIAS ${TARGET_NAME})

and

set(INSTALL_CONFIGDIR ${CMAKE_INSTALL_LIBDIR}/cmake/TestLib)

install(TARGETS ${TARGET_NAME}
    EXPORT ${TARGET_NAME}-targets
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)

#This is required so that the exported target has the name JSONUtils and not  jsonutils
set_target_properties(${TARGET_NAME} PROPERTIES EXPORT_NAME Base)

install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})

#Export the targets to a script
install(EXPORT ${TARGET_NAME}-targets
  FILE
    TestLibBaseTargets.cmake
  NAMESPACE
    TestLib::
  DESTINATION
    ${INSTALL_CONFIGDIR}
)

#Create a ConfigVersion.cmake file
include(CMakePackageConfigHelpers)
write_basic_package_version_file(
    ${CMAKE_CURRENT_BINARY_DIR}/TestLibBaseConfigVersion.cmake
    VERSION ${PROJECT_VERSION}
    COMPATIBILITY AnyNewerVersion
)

configure_package_config_file(${CMAKE_CURRENT_LIST_DIR}/cmake  /TestLibBaseConfig.cmake.in
    ${CMAKE_CURRENT_BINARY_DIR}/TestLibBaseConfig.cmake
    INSTALL_DESTINATION ${INSTALL_CONFIGDIR}
)

#Install the config, configversion and custom find modules
install(FILES
    ${CMAKE_CURRENT_BINARY_DIR}/TestLibBaseConfig.cmake
    ${CMAKE_CURRENT_BINARY_DIR}/TestLibBaseConfigVersion.cmake
    DESTINATION ${INSTALL_CONFIGDIR}
)

##############################################
## Exporting from the build tree

export(EXPORT ${TARGET_NAME}-targets FILE ${CMAKE_CURRENT_BINARY_DIR}/TestLibBaseTargets.cmake NAMESPACE TestLib::)

and of Ext:

set(TARGET_NAME testlibext)

add_library(${TARGET_NAME}
    src/ClassC.cpp
)

#Add an alias so that library can be used inside the build tree, e.g. when   testing
add_library(TestLib::${TARGET_NAME} ALIAS ${TARGET_NAME})
like image 895
PowerSupplyTopologies Avatar asked Apr 29 '19 14:04

PowerSupplyTopologies


1 Answers

In your meta project TestLib you can create a TestLibConfig.cmake file like described in the CMake documentation.

TestLibConfig.cmake:

set(_supported_components Base Ext)

foreach(_comp ${Test_FIND_COMPONENTS})
  if (NOT ";${_supported_components};" MATCHES _comp)
    set(TestLib_FOUND False)
    set(TestLib_NOT_FOUND_MESSAGE "Unsupported component: ${_comp}")
  endif()
  include("${CMAKE_CURRENT_LIST_DIR}/TestLib${_comp}Targets.cmake")
endforeach()

ref: https://cmake.org/cmake/help/latest/manual/cmake-packages.7.html#creating-a-package-configuration-file

like image 88
Mizux Avatar answered Nov 10 '22 04:11

Mizux