问题
I am having a hard time figuring out how to install PUBLIC
headers specified in target_sources().
It appears that target_sources()
is somewhat of a mystery for anything other than adding private sources to an executable.
After reading a lot of material, where especially this blog entry was helpful, I managed to understand & bypass the issue with target_sources()
and PUBLIC files. A CMakeLists.txt
in one of the many subdirectories of my C++ library project looks like this:
target_sources(mylib
PRIVATE
foo.cpp
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/foo.hpp>
$<INSTALL_INTERFACE:foo.hpp>
)
This allows me to successfully build the library. However, upon installation, the header file(s) listed in the PUBLIC
section of target_sources()
are never installed.
My installation looks like this:
install(
TARGETS
mylib
EXPORT mylib-targets
LIBRARY
DESTINATION ${CMAKE_INSTALL_LIBDIR}
COMPONENT lib
ARCHIVE
DESTINATION ${CMAKE_INSTALL_LIBDIR}
COMPONENT lib
RUNTIME
DESTINATION ${CMAKE_INSTALL_BINDIR}
COMPONENT bin
INCLUDES
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/mylib
However, this doesn't install any of the headers. This stackoverflow answer mentions the use of PUBLIC_HEADER but reading the documentation doesn't give me the feeling that that is relevant in my case.
Question: What is the proper way of installing PUBLIC
or INTERFACE
headers using install()
?
Background: My goal is to have a separate CMakeLists.txt
in every subdirectory of my source tree. Each of these lists is supposed to use target_sources()
to add PRIVATE
and PUBLIC
files to the build. All PUBLIC
(and INTERFACE
) sources should be installed during installation.
回答1:
PUBLIC
section of target_sources
command has nothing common with public headers installed with PUBLIC_HEADER
option of install
command.
The headers you want to treat as public for your library should be listed in PUBLIC_HEADER property for the target.
Documentation for install(TARGETS) has a nice example of setting and installing private headers. In your case this would be:
# This defines `foo.hpp` located in the current source directory as a 'public header'.
set_target_properties(mylib PROPERTIES PUBLIC_HEADER foo.hpp)
# This install public headers among with the library.
install(
TARGETS
mylib
PUBLIC_HEADER
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/mylib
# ... other options
)
See also that related question: How to configure CMakeLists.txt to install public headers of a shared library?.
Note also, that INCLUDES
and PUBLIC_HEADERS
clauses for install(TARGETS)
command are different things:
INCLUDES
specifies include directory for the installed libraryPUBLIC_HEADERS
specifies directory where all target's public headers will be copied upon installation.
E.g. if you want your header file to be used via
#include <mylib/foo.h>
then you need provide following options for install()
command:
PUBLIC_HEADER
# The header will be places at ${CMAKE_INSTALL_INCLUDEDIR}/mylib/foo.h
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/mylib
INCLUDES
# This directory will be used as include directory.
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
So <include-directory>
joined (via /
) with the relative path in #include<>
directive will give absolute path to the header file.
来源:https://stackoverflow.com/questions/60736689/cmake-target-sources-and-install