Access export target name list variables

When cmake generates file export_target_nameTargets.cmake (as a result of install(TARGETS myprojecttargets EXPORT export_target_name) install(EXPORT export_target_name …) ) it writes
set(_targetsDefined)
set(_targetsNotDefined)
set(_expectedTargets)
foreach(_expectedTarget … target1 target2…targetn)

list(APPEND _expectedTargets ${_expectedTarget})
if(NOT TARGET ${_expectedTarget})
list(APPEND _targetsNotDefined ${_expectedTarget})
endforeach()

unset(_targetsDefined)
unset(_targetsNotDefined)
unset(_expectedTargets)

Could you please advise on how to get these lists _expectedTarget (and _targetsNotDefined,_expectedTargets) into the myprojectConfig.cmake configuration file which is being generated by cmake from template myprojectConfig.cmake.in and retrieved by consuming project via find_package(myproject). Can new variable be put into myprojectConfig.cmake with such list or unset() statements be blocked in myprojectConfig.cmake? Note I don’t want to track every target installed by individual sub-projects in my code since cmake already tracks them via these lists for better maintainability.

Second question: cmake writes lines into export_target_nameTargets.cmake
…Create imported target targetx
add_library(targetx INTERFACE IMPORTED)
Why is the INTERFACE attribute added here by cmake? What difference will it make comparing to just IMPORTED? Are there any additional properties that could be set or get for “INTERFACE IMPORTED” target comparing to IMPORTED or INTERFACE target?

An INTERFACE library is a header only library .

That may be used with target_link_libraries(...) to use the defines, include path, compiler options, … of this interface library.

And may be exported to be imported from another project later.

Than it is an INTERFACE IMPORTED an can be used again target_link_libraries(...)

Perherps this may help: https://cmake.org/cmake/help/latest/guide/importing-exporting/index.html?highlight=components#id1

Thanks for your feedback. Definition for INTERFACE library does not limit it to only “header-only” library although it might be most common use of INTERFACE library : INTERFACE Library. I am able to build with normal external library which is added as an INTERFACE add_library(…INTERFACE…) library but I have to install its binary files (.so,etc) using install(DIRECTORY…) besides install(TARGETS…)
So are you suggesting that the definition is not complete and actually cmake does not support any property setting to indicate location of library files (.so|.a|.dll…) ?
The use of combined properties " INTERFACE IMPORTED" is still not quite clear as if I export library as INTERFACE (without IMPORTED) I am able to add it as either add_library(… IMPORTED …) or as add_library(…INTERFACE…) in consuming project.
The cmake documentation indicates at the endof INTERFACE library section " An INTERFACE Imported Target may also be created with this signature." which means INTERFACE IMPORTED would have same properties as INTERFACE library which has GLOB visibility, but then it also says " It may be referenced like any target built within the project" . “Any” target means target that has LOCATION property storing path to .so|.a… files. However this section mixes in definition of IMPORTED library which has its own separate section and makes this paragraph confusing.

cmake distinguish if an INTERFACE is imported oder a build library.
At least wenn you want to install your target.

see Using a header only library with FetchContents while build a static lib

you may add logic in your myprojectConfig.cmake

It is often even necessary:

bash-3.2$ head -50 *
==> SyslogTargets.cmake <==
add_library(Syslog::syslog INTERFACE IMPORTED)
# -- DISABLED: syslog is part of clib.
# set_property(TARGET Syslog::syslog PROPERTY INTERFACE_LINK_LIBRARIES "-lsyslog")

==> SystemdTargets.cmake <==
add_library(Systemd::systemd INTERFACE IMPORTED)
set_property(TARGET Systemd::systemd PROPERTY INTERFACE_LINK_LIBRARIES "-lsystemd")
# -- HINT: Existance of systemd-library is NOT CHECKED.

==> project-config.cmake.in <==
@PACKAGE_INIT@

get_filename_component(Syslog_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
get_filename_component(Systemd_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
include(CMakeFindDependencyMacro)

find_dependency(spdlog @SPDLOG_MIN_VERSION@ CONFIG)
find_dependency(fmt @FMT_MIN_VERSION@ CONFIG)

if(@SIMPLELOG_USE_BACKEND_SYSLOG@)
    include("${Syslog_CMAKE_DIR}/SyslogTargets.cmake")
endif()

if(@SIMPLELOG_USE_BACKEND_SYSTEMD@)
    include("${Syslog_CMAKE_DIR}/SystemdTargets.cmake")
endif()

include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAMESPACE@Targets.cmake")
bash-3.2$ 

I think you meant INTERFACE IMPORTED library is different from INTERFACE which is being built by the project and if it is just INTERFACE, then it is built, while INTERFACE IMPORTED attribute tells cmake it is external, right?. Then, let say library, is being built as normal with .so|.a|dll|dll.a objects / files and added as INTERFACE.
How in this case LOCATION could be specified for these objects?
When cmake distinguish these 2 types, it sets target property different. is there a way to see what are the differences?

I think you meant myprojectConfig.cmake.in file and you use different naming convention for config template as you also have " ```
project-config.cmake.in

I assume ```
SyslogTargets.cmake and SystemdTargets.cmake are NOT cmake -generated export name target lists despite the naming convention for auto-generated files bc  they are included by project-config.cmake.in (while ..Targets.cmake automatically included into  myprojectConfig.cmake)
``` therefore I am not clear how could adding logic to myprojectConfig.cmake.in as per "may add logic in your myprojectConfig.cmake" could affect  these files.

@yisseamake

Note I don’t want to track every target installed by individual sub-projects in my code since cmake already tracks them via these lists for better maintainability.

I do not understand your intention or the reason?
IMHO it is not necessary to know this details. Cmake does it right!

see cxx.simplelog/CMakeLists.txt at 71ef4a96f6e13df6d0c1d2eca6965049f94d3f2e · ClausKlein/cxx.simplelog · GitHub

this was added from me

This logic was created by PackageProject.cmake:

include(CMakeFindDependencyMacro)

string(REGEX MATCHALL "[^;]+" SEPARATE_DEPENDENCIES "fmt 7.1.3; spdlog 1.8.2")

foreach(dependency ${SEPARATE_DEPENDENCIES})
  string(REPLACE " " ";" args "${dependency}")
  find_dependency(${args})
endforeach()

include("${CMAKE_CURRENT_LIST_DIR}/GreeterTargets.cmake")
check_required_components("Greeter")

RE: @ClausKlein :

I do not understand your intention or the reason?

The cmake does write correct list of targets into myprojectTargets.cmake file. This file is autogenerated so it is not possible to make modification to this file and remove unset lines: unset(_targetsDefined) unset(_targetsNotDefined) unset(_expectedTargets)
Therefore the variables I need to use in myprojectConfig.cmake/myprojectConfig.cmake.in are not accessible. This is the question I posted, on how to get such access or more generally get the list of targets (_targetsDefined, etc listed in foreach () statement ) useable in myprojectConfig.cmake/myprojectConfig.cmake.in without tracking every target that is added in myriads of sub-projects of a project. cmake gets the list in the foreach(_expectedTarget … target1 target2…targetn) statement and potentially there could be a property or variable this list is obtained from (I checked cmake cache and did not find one).
The reason why to use such list(s) is as the following: print custom warning message to the user about each target imported, warn them that certain targets are imported and they should not import them directly, check versions and address conflicts if they arise with custom warning text rather than frequently meaningless cmake own error/warning.
Thanks for the example, but the cxx.simplelog/CMakeLists.txt shows statements that trigger cmake to create …Targets.cmake file but do not address this question

1 Like