CMAKE_DL_LIBS

What is the intended way of using CMAKE_DL_LIBS? Unlike most libraries in CMake, there doesn’t seem to be an imported target for it.

In particular, if I have a library that has an interface dependency on CMAKE_DL_LIBS on Unix-y platforms, but not on Windows, how should I export that target for install? With imported targets, I can find_dependency in my config and use a generator expression to selectively include the target. But this variable will be expanded at configure time which seems wrong (maybe a different unix has a different name for -ldl for some reason).

This variable is just a facility to manage system dynamic loader library in a portable way.

Because this is a system library, there is no need to export it. The variable definition depends on the target system (for example, on windows this variable is empty) so you can use it safely regardless the system you are targeting.

I know I can use it in my project safely. The issue is with exporting a target which takes it as a dependency.

When I use an imported target, a find_package or find_dependency call on the client’s system takes care of filling in correct paths for, eg. PNG::PNG. There’s no genex along the lines of $<DEFER_EXPAND:CMAKE_DL_LIBS> which I could use to keep the expression ${CMAKE_DL_LIBS} from expanding at the time I call target_link_libraries.

Here’s an example of what I mean:

cmake_minimum_required(VERSION 3.16)
project(Example)

find_package(PNG REQUIRED)

add_library(mylib main.cpp)
target_link_libraries(mylib PUBLIC PNG::PNG ${CMAKE_DL_LIBS})

include(GNUInstallDirs)
install(TARGETS mylib EXPORT Example_Targets
        RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
                COMPONENT Example_Runtime
        LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
                COMPONENT Example_Runtime
                NAMELINK_COMPONENT Example_Development
        ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
                COMPONENT Example_Development
        INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})

install(EXPORT Example_Targets
        DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Example"
        NAMESPACE Example::
        FILE Example-Targets.cmake
        COMPONENT Example_Development)

If I then build and install it to a local directory, the file lib/cmake/Example/Example-Targets.cmake contains the lines:

set_target_properties(Example::mylib PROPERTIES
  INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include"
  INTERFACE_LINK_LIBRARIES "PNG::PNG;dl"
)

This is clearly correct for PNG::PNG, but why should this be right for dl? I would have wanted to see (the equivalent of):

INTERFACE_LINK_LIBRARIES "PNG::PNG;${CMAKE_DL_LIBS}"

As per Marc’s comments, the dl library is provided by the system. It’s okay to list such a library as a raw dl to target_link_libraries(), since even when exported/installed, that same library has to be provided by the target system too. I think you might be concerned about a non-problem in this case.

But in the interest of providing choices, if you really want to avoid dl being added to the installed properties, you could try wrapping ${CMAKE_DL_LIBS} in a $<BUILD_INTERFACE:...>. That should prevent it from escaping your local build tree.