Exporting and importing CMake packages with find_package

This tutorial shows how to export a CMake library to a package and import it from a different project using the find_package() command. This works faster as referencing the library project’s directory using the add_subdirectory() command, as the exporting mechanism allows precisely selecting which targets to export. We will use Visual Studio to create a basic library project for Raspberry Pi with a cross-compiler, export it to a package and import it from another project.

  1. Follow this tutorial to create a basic CMake library for Raspberry Pi and import it manually via add_subdirectory().
  2. Now we will change the library project to be exported to a package. Add the following lines to the CMakeLists.txt file that defines the library:
    set(INSTALL_CMAKE_DIR c:/Packages/DemoLibraryClient)
    install(FILES public/PublicHeader.h DESTINATION ${INSTALL_CMAKE_DIR}/public)
    install(TARGETS CMakeLibraryDemo DESTINATION ${INSTALL_CMAKE_DIR} EXPORT FindCMakeLibraryDemo)
    install(EXPORT FindCMakeLibraryDemo DESTINATION ${INSTALL_CMAKE_DIR})

    The lines above instruct CMake to install the PublicHeader.h file and the CMakeLibraryDemo target to the c:/Packages/DemoLibraryClient directory. It also configures CMake to generate a FindCMakeLibraryDemo.cmake file (EXPORT statement in the install TARGETS command) that will add the CMakeLibraryDemo target as an imported target to any project that includes this file. This mechanism will be used later when we import our package.

  3. If you try building the project now, CMake will show the following error:
      CMake Error in CMakeLists.txt:
      Target "CMakeLibraryDemo" INTERFACE_INCLUDE_DIRECTORIES property contains
      path:
     
        "C:/projects/CMakeLibraryDemo/public"
     
      which is prefixed in the source directory.

    ifaceThis happens because CMake detects that the public include directory (that will be added to targets from other projects importing our library) resides inside the source directory (exporting a project to a package should break all ties to the original location of the source files so that they could be safely deleted).

  4. We can fix this by using the CMake generator expressions. Replace the target_include_directories(CMakeLibraryDemo PUBLIC public) line with this:
    target_include_directories(CMakeLibraryDemo PUBLIC 
        $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/public>  
        $<INSTALL_INTERFACE:${INSTALL_CMAKE_DIR}/public>)

    This syntax tells CMake to use a directory inside the source tree when building the package and use the directory under the installation directory (where we installed PublicHeader.h using INSTALL FILES command) while handling exporting.

  5. Now the build should succeed:26-export
  6. You can generate the package by right-clicking on libCMakeLibraryDemo.so in Solution Explorer and selecting “Install Target(s)”:27-install
  7. CMake will create the c:/Packages/DemoLibraryClient directory and install the necessary files there:28-installed
  8. Open the installation directory with Explorer and check its contents:29-folderIt should normally contain the library (.so file), the Find<Package name>.cmake file and the public directory with the public header (created via the INSTALL FILES command).
  9. Now we will create another CMake project that will import the package. Use the VisualGDB Linux Project Wizard to do that:30-client3
  10. Insert the following line in the CMakeLists.txt file of the new project:
    find_package(CMakeLibraryDemo REQUIRED)

    If you try building it now, CMake will complain that FindCMakeLibraryDemo.cmake file must be located in CMAKE_MODULE_PATH:31-nopkg

  11. You can fix this by adding “c:\Packages\DemoLibraryClient” to the “Extra module directories” field on the CMake Project Settings page of VisualGDB Project Properties for your project:32-modules
  12. Now CMake will find the package and build the project, however running it will result in an error: the libCMakeLibraryDemo.so file will not be found:33-nolib
  13. This happens because the libraries imported from packages are assumed to be already installed on the target in a directory where the application can find them. If you have previously tested tested out the library as a part of this tutorial, it should be already deployed to /tmp/MyLibraryDemo. Simply add this directory to SOLIB_SEARCH_PATH and executable will be able to locate it:34-path
  14. If you want to debug the library sources while debugging your application, add the “set solib-search-path <directory with the .so file on the Windows machine> to the gdb startup commands (when importing the project via add_subdirectory() and adding a reference, VisualGDB would do this automatically):35-solib
  15. Now the library will get loaded and the breakpoints inside its functions will work as well:bkpt