modern cmake file structure

I am trying to convert an existing cmake project to use some of the more modern cmake patterns and generate the correct Config.cmake files to be imported by another project

I have the following file structure in the one I want to update

./zoo/
    cmake/
        *.cmake.in
    libzoo/
        bind/
            CMakeLists.txt
            *.cpp
            *.h
            *etc.
        include/
            *.h
            libzoo/
              *.hpp
        src/
            *.cpp
        test/
            CMakeLists.txt
        CMakeLists.txt
    App/
         src/
         include/
         CMakeLists.txt

Issues:

  1. In the original code everything built and ran fine, but now I am getting errors saying that the APP can’t find the guile include headers now. How do I properly connect and inherit the header dependencies? I think its that modern cmake is more explicit, but I don’t know what I am missing.

Do I need to re-include the headers? meaning the app does not inherit the includes from the library?

target_include_directories(App
  PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
         $<INSTALL_INTERFACE:${CMAKE_INSTALL_PREFIX}/include>
         ${Boost_INCLUDE_DIRS}
         ${PNG_INCLUDE_DIR}
         ${EIGEN_INCLUDE_DIRS}
         ${GUILE_INCLUDE_DIRS}
)

  1. I want to be able to export a ZooConfig.cmake such that it can be found with find_package and would include libzoo, zoo-guile, and the App. There appears to be many paths, but I am having a hard time finding information out there that makes cohesive sense, and am really confused at this point.

The dependency chain is as follows:

  • build a shared library from the source in libzoo/src with the header files in libzoo/include which depend on Boost, Eigen, PNG, and Threads called libzoo.
add_library(zoo SHARED
    ${zoo_sources}
)

add_library(zoo::core ALIAS zoo)


target_include_directories(zoo
  PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
         $<INSTALL_INTERFACE:${CMAKE_INSTALL_PREFIX}/include>
         ${Boost_INCLUDE_DIRS}
         ${PNG_INCLUDE_DIR}
         ${EIGEN_INCLUDE_DIRS}
)

set(LIBS ${PNG_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} )
target_link_libraries(zoo PRIVATE ${LIBS})

set_target_properties(five
   PROPERTIES
   CXX_STANDARD "${ZOO_CXX_STANDARD}"
   CXX_STANDARD_REQUIRED "YES"
   CXX_EXTENSION "NO"
   INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/lib
)

install(
  TARGETS zoo 
  EXPORT LibZooTargets
  RUNTIME DESTINATION ${ZOO_INSTALL_BIN_DIR}
  LIBRARY DESTINATION ${ZOO_INSTALL_LIB_DIR}
  ARCHIVE DESTINATION ${ZOO_INSTALL_LIB_DIR}
)

install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/
        DESTINATION ${ZOO_INSTALL_INCLUDE_DIR}
        FILES_MATCHING
          PATTERN "*.h"
          PATTERN "*.hpp"
)

if (BUILD_TESTS)
  add_subdirectory(test)
endif(BUILD_TESTS)

if (BUILD_GUILE_BINDINGS AND GUILE_FOUND)
    add_subdirectory(bind)
endif(BUILD_GUILE_BINDINGS AND GUILE_FOUND)

  • build the test suite which depends on libzoo
set(SRCS ${test_srcs} )

set(LIBS zoo ${CMAKE_THREAD_LIBS_INIT} )

if (BUILD_GUILE_BINDINGS AND GUILE_FOUND)
    set(SRCS ${SRCS} guile.cpp)
    set(LIBS ${LIBS} zoo-guile)
endif(BUILD_GUILE_BINDINGS AND GUILE_FOUND)

add_executable(libzoo-test ${SRCS})

target_link_libraries(libzoo-test ${LIBS})
target_include_directories(libzoo-test PRIVATE .)

  • build a guile binding library from /libproject/bind called zoo-guile depends on libzoo
ADD_CUSTOM_COMMAND(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/bundle.cpp
    COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/bundle.cmake
    DEPENDS libzoo-guile.cpp shapes.scm csg.scm transforms.scm text.scm util.scm vec.scm
            sandbox.scm ${CMAKE_CURRENT_SOURCE_DIR}/bundle.cmake)

add_library(zoo-guile SHARED ${CMAKE_CURRENT_BINARY_DIR}/bundle.cpp)

add_library(zoo::guile ALIAS zoo-guile)

add_dependencies(zoo-guile zoo)
target_link_libraries(zoo-guile zoo ${GUILE_LIBRARIES})

target_include_directories(zoo-guile
  PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
         $<INSTALL_INTERFACE:${CMAKE_INSTALL_PREFIX}/include>
         ${GUILE_INCLUDE_DIRS}
)

set_target_properties(zoo-guile
   PROPERTIES
   CXX_STANDARD "${FIVE_CXX_STANDARD}"
   CXX_STANDARD_REQUIRED "YES"
   CXX_EXTENSION "NO"
   INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/lib
)

install(
  TARGETS zoo-guile 
  EXPORT LibZooTargets
  RUNTIME DESTINATION ${ZOO_INSTALL_BIN_DIR}
  LIBRARY DESTINATION ${ZOO_INSTALL_LIB_DIR}
  ARCHIVE DESTINATION ${ZOO_INSTALL_LIB_DIR}
  )

install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
        DESTINATION ${ZOO_INSTALL_INCLUDE_DIR}
        FILES_MATCHING
        PATTERN "*.h"
)

  • build the App in which depends on zoo-guile in App directory.
# Instruct CMake to run moc, uic, and rrc automatically when needed.
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)

# Find the Qt libraries
find_package(Qt5Core REQUIRED)
find_package(Qt5Widgets REQUIRED)
find_package(Qt5OpenGL REQUIRED)
find_package(Qt5Network REQUIRED)
find_package(Qt5Concurrent REQUIRED)

set(SRCS ${app_srcs})
set(QOBJECTS ${Qobj_srcs})

add_executable(App ${SRCS} ${QOBJECTS})
install(TARGETS App DESTINATION bin RENAME app)

target_include_directories(App
  PUBLIC 
        $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
         $<INSTALL_INTERFACE:${CMAKE_INSTALL_PREFIX}/include>
)

target_link_libraries(App
  PUBLIC
    zoo-guile
    Qt5::Widgets
    Qt5::Gui
    Qt5::OpenGL
    Qt5::Concurrent
    ${EXTRA_LIBS}
)

set_target_properties(App
   PROPERTIES
   CXX_STANDARD "${ZOO_CXX_STANDARD}"
   CXX_STANDARD_REQUIRED "YES"
   CXX_EXTENSION "NO"
   INSTALL_RPATH ${ZOO_INSTALL_LIB_DIR}
)

install(
  TARGETS App 
  EXPORT LibZooTargets
  RUNTIME DESTINATION ${ZOO_INSTALL_BIN_DIR}
  LIBRARY DESTINATION ${ZOO_INSTALL_LIB_DIR}
  ARCHIVE DESTINATION ${ZOO_INSTALL_LIB_DIR}
)
  • Export the targets to a Config.cmake file from the project level CMakeLists.txt
#Skipping all the variable setting
 
add_subdirectory(libzoo)

This makes sense up until here when I try to export the target stuff

if(BUILD_APP AND GUILE_FOUND AND Qt5Core_FOUND)
    add_subdirectory(App)
endif(BUILD_APP AND GUILE_FOUND AND Qt5Core_FOUND)

include(CMakePackageConfigHelpers)
write_basic_package_version_file(
    LibZooConfigVersion.cmake
    VERSION ${ZOO_VERSION}
    COMPATIBILITY AnyNewerVersion
)

install(EXPORT LibZooTargets
        DESTINATION ${ZOO_CMAKE_INSTALL_DIR}
)

configure_package_config_file(
	"cmake/LibZooConfig.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/LibZooConfig.cmake"
	INSTALL_DESTINATION ${ZOO_CMAKE_INSTALL_DIR}
)

install(FILES "${CMAKE_CURRENT_BINARY_DIR}/LibZooConfig.cmake"
        DESTINATION ${ZOO_CMAKE_INSTALL_DIR}
)

I corrected one issue: I didn’t have the flag on to build the bindings…

:man_facepalming:

still having trouble with the installation config part.

It appears I got it working.