c++cmakecmake-modules

How to Create Packages with CMake


.
+-- MyPack
|   +-- Lib1
|   |   +-- include
|   |   |   +-- Lib1.h
|   |   +-- src
|   |   |   +-- Lib2.cpp
|   |   +-- CMakeLists.txt
|   +-- Lib2
|   |   +-- include
|   |   |   +-- Lib2.h
|   |   +-- src
|   |   |   +-- Lib2.cpp
|   |   +-- CMakeLists.txt
|   +-- CMakeLists.txt
+-- SubProject1
|   +-- CMakeLists.txt
+-- SubProject2
|   +-- CMakeLists.txt
+-- CMakeLists.txt

Hi all.

I'm new to CMake and I'm trying to obtain something like the following. Considering the above directory tree of my C++ project:

I have a directory (let's say "MyPack") that contains several subdirectories (Lib1, Lib2...) and each one represents a C++ Library that I wrote.

How can I setup everything so I can write find_package(MyPack)in the other subprojects?

Every subproject is a stand-alone project, and does not depend on other subprojects, but just on libraries in "MyPack".


Solution

  • Your drawing is a bit confusing because there is a CMakeLists.txt after Lib2 which belongs to no folder... Anyway: is MyPack

    in the 2nd case:

    The top directory CMakeLists.txt gives you access to targets of Lib1 and Lib2 that you can use in SubProject1 and SubProject2 if you have something like this:

    project(MyPack)
    add_subdirectory(Lib1) # Building Lib1
    add_subdirectory(Lib2) # Building Lib2
    add_subdirectory(SubProject1) # you can use Lib1 & Lib2 targets here
    add_subdirectory(SubProject2) # you can use Lib1 & Lib2 targets here
    

    If it is the 1st case, MyPack is only Lib1 and Lib2 :

    Using find_package(MyPack) means that you need to create a Config file and install() your project:

    project(MyPack)
    add_subdirectory(Lib1)
    add_subdirectory(Lib2)
    

    in Lib1/CMakeLists.txt:

    add_library(lib1 "")
    add_library(MyPack::lib1 ALIAS lib1)
    [...]
    include(GNUInstallDirs)
    install( 
      TARGETS lib1
      EXPORT MyPackTargets
      ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
      )
    

    in Lib2/CMakeLists.txt:

    add_library(lib2 "")
    add_library(MyPack::lib2 ALIAS lib2)
    [...]
    include(GNUInstallDirs)
    install( 
      TARGETS lib2
      EXPORT MyPackTargets
      ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
      )
    

    Now you have lib1 and lib2 in the export MyPackTargets. You have to install that export as well.

    anywhere after above:

    install(
      EXPORT MyPackTargets
      DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MyPack
      NAMESPACE MyPack::
      FILE MyPackTargets.cmake # Not sure if this is still needed
      )
    
    include(CMakePackageConfigHelpers)
    configure_package_config_file( 
      "Config.cmake.in" 
      "MyPackConfig.cmake"
      INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MyPack
      PATH_VARS
        CMAKE_INSTALL_LIBDIR
      )
    
    write_basic_package_version_file(
      ${CMAKE_CURRENT_BINARY_DIR}/MyPackConfigVersion.cmake
      VERSION 1.0.0
      COMPATIBILITY SameMajorVersion
      )
    
    ### Install Config and ConfigVersion files
    install(
      FILES "${CMAKE_CURRENT_BINARY_DIR}/MyPackConfig.cmake"
            "${CMAKE_CURRENT_BINARY_DIR}/MyPackConfigVersion.cmake"
      DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/MyPack"
      )
    
    

    create a file Config.cmake.in with:

    @PACKAGE_INIT@
    include( "${CMAKE_CURRENT_LIST_DIR}/MyPackTargets.cmake" )
    

    Now if you build and install your project MyPack, find_package(MyPack) from other project should find it and import the targets you've created.

    Here is some documentation: https://cmake.org/cmake/help/latest/module/CMakePackageConfigHelpers.html

    https://blog.kitware.com/cmake-superbuilds-git-submodules/