Some weeks ago, under Installing headers the modern way, I posed a question regarding the relationship (or lack thereof) between target_sources(mylib PUBLIC ...)
and install(TARGETS mylib PUBLIC_HEADER ...)
. This is a part of CMake’s current design/evolution that just doesn’t seem especially cohesive.
Well, I recently undertook writing/generating my first CMake package config file. And while I’m at it, hey, let’s make this thing relocatable, too.
Oh, boy.
So, let’s say we have:
target_sources(
mylib
PUBLIC
myfirstpublicheader.h
mysecondpublicheader.h
)
Well, that just won’t do. To satisfy relocatability requirements, the $<INSTALL_INTERFACE:>
generator expression must be used. For each header.
target_sources(
mylib
PUBLIC
$<INSTALL_INTERFACE:myfirstpublicheader.h>
$<INSTALL_INTERFACE:mysecondpublicheader.h>
)
Um, ew. But okay.
Oh, wait… that little bit of code I used to copy the INTERFACE_SOURCES
property to the PUBLIC_HEADER
property?
get_target_property(MYLIB_PUBLIC_HEADERS mylib INTERFACE_SOURCES)
set_target_properties(
mylib
PROPERTIES
PUBLIC_HEADER "${MYLIB_PUBLIC_HEADERS}"
)
Well, after decorating things with $<INSTALL_INTERFACE:>
, my headers aren’t getting installed anymore.
Hm. Okay. Well, it seems that has a perfectly trivial solution: just use the $<BUILD_INTERFACE:>
generator expression:
target_sources(
mylib
PUBLIC
$<INSTALL_INTERFACE:myfirstpublicheader.h>
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/myfirstpublicheader.h>
$<INSTALL_INTERFACE:mysecondpublicheader.h>
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/mysecondpublicheader.h>
)
And now my headers install! Yay!
…
Oh, dear. What have I done? See, I don’t have just a couple of public headers like this contrived example code; I have tens of them, like many, many other moderately-sized C++ projects. And this thing has just exploded.
I am hoping that someone will tell me that I’ve missed a trick here. But failing that, I respectfully suggest that something has gone off the rails with this design.