It's referring to a header-only library whose sources you don't control or are found in another build tree / in the system. Will most commonly be created in a Find module or CMake package config module.
Like other imported targets, and unlike non-imported targets, it doesn't have to be (and indeed cannot be) install()-ed if it appears in the INTERFACE_LINK_LIBRARIES property of an install()ed target transitively; instead, the resulting package will need to find_dependency the package.
What is an INTERFACE IMPORTED library in CMake and what are its uses? - Stack Overflow
How can I combine INTERFACE libraries with shared libraries?
[question] How to use cmake interface library with target sources?
Create & link interface library with cmake - Windows - Swift Forums
Videos
Per target_link_libraries :
The
PUBLIC,PRIVATEandINTERFACEkeywords can be used to specify both the linkdependencies and the link interface in one command. Libraries and targets following
PUBLICare linked to, and are made part of the link interface. Libraries andtargets following
PRIVATEare linked to, but are not made part of the link interface.Libraries following
INTERFACEare appended to the link interface and are not usedfor linking
<target>.
I am not understanding what is being meant by "the link interface". Is anyone able to explain it to me?
Thanks
try this:
cmake_minimum_required(VERSION 3.7)
project(mylib VERSION 0.1 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 14)
#add_compile_options(-Wa -aslh)
# Define the library target
add_library(mylib INTERFACE)
target_include_directories(mylib INTERFACE
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)
include(CMakePackageConfigHelpers)
write_basic_package_version_file(
"${PROJECT_BINARY_DIR}/mylibConfigVersion.cmake"
VERSION 0.1
COMPATIBILITY AnyNewerVersion
)
install(TARGETS mylib
EXPORT mylibTargets
LIBRARY DESTINATION lib COMPONENT Runtime
ARCHIVE DESTINATION lib COMPONENT Development
RUNTIME DESTINATION bin COMPONENT Runtime
PUBLIC_HEADER DESTINATION include COMPONENT Development
BUNDLE DESTINATION bin COMPONENT Runtime
)
include(CMakePackageConfigHelpers)
configure_package_config_file(
"${PROJECT_SOURCE_DIR}/cmake/mylibConfig.cmake.in"
"${PROJECT_BINARY_DIR}/mylibConfig.cmake"
INSTALL_DESTINATION lib/cmake/mylib
)
install(EXPORT mylibTargets DESTINATION lib/cmake/mylib)
install(FILES "${PROJECT_BINARY_DIR}/mylibConfigVersion.cmake"
"${PROJECT_BINARY_DIR}/mylibConfig.cmake"
DESTINATION lib/cmake/mylib)
install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/ DESTINATION include)
add_executable(mytest test/basic_checks.cpp)
target_link_libraries(mytest mylib)
the content of cmake/mylibConfig.cmake.in should only be this
@PACKAGE_INIT@
include("${CMAKE_CURRENT_LIST_DIR}/mylibTargets.cmake")
check_required_components("@PROJECT_NAME@")
if you do all of this, not only that it makes your header-only library 'installable', but it also makes it 'findable'. users will be able to import your library like so:
find_package(mylib CONFIG REQUIRED)
target_link_libraries(MyApp mylib) # installed include/ path automatically added
In my case the headers were contained in multiple sub directories and I simply wanted to map them to the install directory and preserve the relative file structure. I gathered from reading here that file sets are the preferred way to do this since cmake version 3.23.
This is the code I used to build the library...
cmake_minimum_required(VERSION 3.23.1)
include_guard(GLOBAL)
project(headerlib-proj VERSION 0.0.0 LANGUAGES C)
include(CMakePackageConfigHelpers)
include(GNUInstallDirs)
add_library(mylib INTERFACE)
target_include_directories(mylib
INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
target_sources(mylib
INTERFACE FILE_SET HEADERS
BASE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}
FILES myHeader.h)
install(TARGETS mylib
EXPORT mylibTargets
FILE_SET HEADERS DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/mylib)
install(EXPORT mylibTargets
FILE mylibConfig.cmake
NAMESPACE MyNamespace::
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/mylib)
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/mylibConfig.cmake
${CMAKE_CURRENT_BINARY_DIR}/mylibTargetsVersion.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/mylib)
export(EXPORT mylibTargets
FILE ${CMAKE_CURRENT_BINARY_DIR}/mylibConfig.cmake
NAMESPACE MyNamespace::)
configure_package_config_file(
${CMAKE_CURRENT_SOURCE_DIR}/mylibConfig.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/mylibConfig.cmake
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/mylib)
write_basic_package_version_file(
${PROJECT_BINARY_DIR}/mylibTargetsVersion.cmake
VERSION 1.0.0
COMPATIBILITY SameMajorVersion)
And the client...
cmake_minimum_required(VERSION 3.23)
project(master-proj LANGUAGES CXX)
find_package(mylib CONFIG REQUIRED)
add_executable(myProgram)
target_link_libraries(myProgram PRIVATE MyNamespace::mylib)
target_sources(myProgram PRIVATE main.cpp)
If you are creating a shared library and your source cpp files #include the headers of another library (Say, QtNetwork for example), but your header files don't include QtNetwork headers, then QtNetwork is a PRIVATE dependency.
If your source files and your headers include the headers of another library, then it is a PUBLIC dependency.
If your header files other than your source files include the headers of another library, then it is an INTERFACE dependency.
Other build properties of PUBLIC and INTERFACE dependencies are propagated to consuming libraries. http://www.cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html#transitive-usage-requirements
@steveire accepted answer is great. I just wanted to add a table to quickly see the difference:
.-----------.------------------.----------------.
| | Linked by target | Link interface |
:-----------+------------------+----------------:
| PUBLIC | X | X |
:-----------+------------------+----------------:
| PRIVATE | X | |
:-----------+------------------+----------------:
| INTERFACE | | X |
'-----------'------------------'----------------'
- Linked by target: libraries included in target sources (not a dependency for projects linking the library).
- Link interface: libraries included in target public headers (dependencies for projects linking the library).
When you create an imported target, you're telling CMake: I have this { static library | shared library | module library | executable } already built in this location on disk. I want to be able to treat it just like a target built by my own buildsystem, so take note that when I say ImportedTargetName, it should refer to that binary on disk (with the associated import lib if applicable, and so on).
When you create an interface library, you're telling CMake: I have this set of properties (include directories etc.) which clients can use, so if they "link" to my interface library, please propagate these properties to them.
The fundamental difference is that interface libraries are not backed by anything on disk, they're just a set of requirements/properties. You can set the INTERFACE_LINK_LIBRARIES property on an interface library if you really want to, but that's not really what they were designed for. They're to encapsulate client-consumable properties, and make sense primarily for things like header-only libraries in C++.
Also notice that an interface library is a library—there's no such thing as an interface executable, but you can indeed have imported executables. E.g. a package config file for Bison could define an imported target for the Bison executable, and your project could then use it for custom commands:
# In Bison package config file:
add_executable(Bison IMPORTED)
set_property(TARGET Bison PROPERTY IMPORTED_LOCATION ...)
# In your project:
find_package(Bison)
add_custom_command(
OUTPUT parser.c
COMMAND Bison tab.y -o parser.c
DEPENDS tab.y
...
)
(Bison is used just as an example of something you might want to use in custom commands, and the command line is probably not right for it).
It seems like there is a lot of overlap. Say you have a shared library and headers on disk and you want to make it available so that bits of your CMake can do this
target_link_libraries(my_target foo)
and automatically link with it and get the necessary include directories.
You can do it either like this:
find_package(Foo)
add_library(foo SHARED IMPORTED)
set_target_properties(foo PROPERTIES
IMPORTED_LOCATION ${FOO_LIBRARIES} # The DLL, .so or .dylib
INTERFACE_INCLUDE_DIRECTORIES ${FOO_INCLUDE_DIR}
INTERFACE_COMPILE_DEFINITIONS "ENABLE_FOO"
)
Or like this:
add_library(foo INTERFACE)
target_link_libraries(foo INTERFACE ${FOO_LIBRARIES})
target_include_directories(foo INTERFACE ${FOO_INCLUDE_DIR})
target_compile_definitions(foo INTERFACE "-DENABLE_FOO")
They both work and behave identically as far as I can tell. There is even an 'imported interface library' available via add_library(foo INTERFACE IMPORTED) though that didn't seem to work and I have no idea what it is for.
Frankly the docs don't really explain which you should use for libraries, and I'm afraid I don't find Angew's "that's not really what they were designed for" very compelling.
I guess use either. I think the interface library is easier to understand and more consistent with the use of INTERFACE properties from internal libraries.