1
votes

I am working on a larger C++ library that is using CMake and depends on Qt. We moved from Qt4 to Qt5 and now I encounter a problem when using our lib in an upstream project. As a minimal working example demonstrating the problem please have a look at this repo:

https://github.com/philthiel/cmake_qt5_upstream

It contains two separate CMake projects:

  • MyLIB: a tiny library that uses QString from Qt5::Core.

    It generates and installs package configuration files MyLIBConfig.cmake, MyLIBConfigVersion.cmake, and MyLIBTargets.cmake in order to be searchable by CMake find_package()

  • MyAPP: a tiny executable depending on MyLIB

    The project uses find_package(MyLIB) and creates an executable that uses MyLIB


The problem is that CMake gives me the following error message when configuring the MyAPP project:

CMake Error at CMakeLists.txt:11 (add_executable):
   Target "MyAPP" links to target "Qt5::Core" but the target was not found.
   Perhaps a find_package() call is missing for an IMPORTED target, or an
   ALIAS target is missing?

The reason for this behaviour is that in the automatically generated MyLIBTargets.cmake file the INTERFACE_LINK_LIBRARIES entry for Qt5 Core is the Qt5::Core symbol. Using Qt4, the absolute path to the Qt core lib was specified here.


Now, I simply can resolve this by using

find_package(Qt5Core 5.X REQUIRED) 

in the MyAPP project.

However, I would like to know if this is the intended/generic way to go, i.e. requesting upstream projects of our lib to search for the required transitive Qt5 dependencies themselves, or if I probably misuse CMake here and need to change my configuration procedure?

The CMake docu on package file generation

https://cmake.org/cmake/help/v3.0/manual/cmake-packages.7.html

mentions that macros can be provided by the package configuration files to upstream. Maybe this would be the correct place to search for imported targets like Qt5 and break upstream configuration runs when these dependencies are not found?

Best, Philipp

1

1 Answers

1
votes

[edit of the edit] Full Source Example

You need to deliver a CMake config file for your project, and probably the ConfigFile should be generated via CMake itself (because you cannot know for shure where the user will install your software).

Tip, use the ECM cmake modules to ease the creation of that:

 find_package(ECM REQUIRED NO_MODULE)
 include(CMakePackageConfigHelpers)

 ecm_setup_version(${PROJECT_VERSION}
    VARIABLE_PREFIX ATCORE
    VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/atcore_version.h"
    PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KF5AtCoreConfigVersion.cmake"
    SOVERSION 1
)

 configure_package_config_file("${CMAKE_CURRENT_SOURCE_DIR}/KF5AtCoreConfig.cmake.in"
                               "${CMAKE_CURRENT_BINARY_DIR}/KF5AtCoreConfig.cmake"
                          INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR}
  )

and the KF5AtCoreConfig.cmake.in:

@PACKAGE_INIT@

find_dependency(Qt5Widgets "@REQUIRED_QT_VERSION@")
find_dependency(Qt5SerialPort "@REQUIRED_QT_VERSION@")
find_dependency(KF5Solid "@KF5_DEP_VERSION@")

include("${CMAKE_CURRENT_LIST_DIR}/KF5AtCoreTargets.cmake")

This will generate the correct FindYourSortware.cmake with all your dependencies.

[edit] Better explanation on what's going on. If you are providing a library that will use Qt, and that would also need to find the Qt5 library before compilling the user's source, you need to provide yourself a FindYourLibrary.cmake code, that would call

 find_package(Qt5 REQUIRED COMPONENTS Core Gui Widgets Whatever)

Now, if it's your executable that needs to be linked, use the Components instead of the way you are doing it now.

find_package(Qt5 REQUIRED COMPONENTS Core)

then you link your library with

 target_link_libraries(YourTarget Qt5::Core)