0

How to create a cmake header-only library that depends on external header files? is close but different.

I have a single-header library, MyHeaderLib. In MyHeaderLib/MyHeader.h I have #include <QString>, so anyone doing #include "MyHeaderLib/MyHeader.h" had better have QString in their path (i.e., Qt5Core to CMake, I think(?)) and it they'll need to link to Qt5Core.

What belongs in my CMakeLists.txt for MyHeaderLib? I have

cmake_minimum_required(VERSION 3.12)

add_library(MyHeaderLib INTERFACE)

target_include_directories(MyHeaderLib include/) 
# (^ Where include/ contains MyHeaderLib/MyHeader.h)

Anything I try with target_link_libraries(MyHeaderLib requires INTERFACE and if I do target_link_libraries(MyHeaderLib INTERFACE Qt5Core) that doesn't suffice.

Ultimately I got it to work as follows, but I don't understand what is going on:

cmake_minimum_required(VERSION 3.12)

find_package(Qt5Core REQUIRED) # <- Can't be Qt5::Core

add_library(MyHeaderLib INTERFACE)

target_include_directories(MyHeaderLib include/) 
# (^ Where include/ contains MyHeaderLib/MyHeader.h)

target_link_libraries(MyHeaderLibrary 
INTERFACE
    Qt5::Core # <- Can't be Qt5Core
)

I gather the targets with :: in them are aliases, but I'm perplexed why it needs to be exactly like this. Furthermore, I can't find add_library(Qt5::Core ALIAS Qt5Core) anywhere. What is going on? Why do I have to find_package(Qt5Core REQUIRED) and not find_package(Qt5::Core REQUIRED) and why can't target_link_libraries take Qt5Core?

Ben
  • 9,184
  • 1
  • 43
  • 56
  • 1
    Thats just how the packages have been declared: https://doc.qt.io/archives/qt-5.10/cmake-manual.html or alternatively https://blog.kitware.com/cmake-finding-qt5-the-right-way/ – Alan Birtles Mar 02 '21 at 19:58
  • By that you mean CMake's built-inn Qt support magically knows that when I look for `Qt5Core` I get `Qt5::Core`? I'm a CMake n00b... If one is an alias for the other, why aren't the two names interchangeable to `find_package` and to `target_link_libraries`? – Ben Mar 02 '21 at 20:06
  • 1
    The `find_package(XYZ ...)` can be entirely different from the target you link to with `target_link_libraries`. In this case, there's a `FindQt5Core.cmake` (or maybe `Qt5CoreConfig.cmake`) which declares the `Qt5::Core` target. They could have written it to declare `Qt5Core`, but they chose to make it `Qt5::Core`. – Justin Mar 02 '21 at 20:14

1 Answers1

1

Packages are responsible for defining targets. The Qt maintainers chose to name the package Qt5Core while deciding to define the Qt5::Core target.

Usually the convention with CMake packages is that a package named package-name will define package-name::package-name with maybe other optional targets or subcomponents of package-name::package-name.

As to answer why Qt don't act like this, look inside Qt5CoreConfig.cmake, you'll see this line:

add_library(Qt5::Core SHARED IMPORTED)

Here you go. The file is named Qt5CoreConfig so it needs find_package(Qt5Core), but the target is under the Qt5 namespace as they choose to define it.

This is maybe because Qt5 Also has a general package which you can use components:

find_package(Qt5 REQUIRED COMPONENTS Core)
# Here Qt5::Core kinda make sense.
Guillaume Racicot
  • 39,621
  • 9
  • 77
  • 141
  • Thank you for clarifying! So the issue is that packages and targets are different things and That `find_package` makes much more sense, visually at least. And it appears to work the same if you write it `find_package(Qt5 COMPONENTS Core REQUIRED)` which reads even more like `find_package(Qt5Core REQUIRED)`. – Ben Mar 02 '21 at 22:04
  • But... how does the existence of `Qt5CoreConfig.cmake` define a package named `Qt5Core`? Is it cmake magic that if I try to `find_package(Foo REQUIRED)` it looks for `FooConfig.cmake` in some path? I'd kind of expect to see an `add_package` command somewhere saying "I'm the Qt5Core package", but that's not a thing, apparently. – Ben Mar 02 '21 at 22:08
  • @Ben yes. Suit yourself in the documentation about [cmake-packages](https://cmake.org/cmake/help/latest/manual/cmake-packages.7.html) and [`find_package`](https://cmake.org/cmake/help/latest/command/find_package.html) – Guillaume Racicot Mar 02 '21 at 23:35
  • @Ben you can add packages using the `install(EXPORT ...` command or by writing the files manually. Well behaving CMake libraries exports their targets. – Guillaume Racicot Mar 02 '21 at 23:37