Unexpected behavior of TARGET_RUNTIME_DLLS when mixing STATIC, SHARED, PUBLIC, PRIVATE libraries

I’m running into some unexpected behavior when using the TARGET_RUNTIME_DLLS generator expression, and I’m wondering if this is something that I’m just not understand properly or if its an unhandled edge case that I should raise an issue for.

I have narrowed it down to the following minimal example:

cmake_minimum_required(VERSION 3.21)



add_library(dll_2 SHARED dll_2.cpp)

add_library(lib STATIC lib.cpp)
target_link_libraries(lib PRIVATE dll_2)

add_library(dll_1 SHARED dll_1.cpp)
target_link_libraries(dll_1 PRIVATE lib) # making this PUBLIC fixes the dll listing

add_executable(executable main.cpp)
target_link_libraries(executable PRIVATE dll_1)

add_custom_target(executable _dlls
    COMMAND "${CMAKE_COMMAND}" -E echo "$<TARGET_RUNTIME_DLLS:executable >"

With these dependencies dll_2 is not shown in the list of TARGET_RUNTIME_DLLS for the executable. Changing the dependency so that the dependency on lib is PUBLIC “fixes” this behavior, but doing so is undesirable as it also exposes other details that should remain private. It is my understanding that the PUBLIC/PRIVATE relationship is a compile- and link-time concept, so I was not expecting it to affect a runtime feature in this manner.

Is the behavior I’m seeing expected, or should I raise an issue for this?

After reading the documentation I think this should work. I’d open an issue.

I agree, an issue seems warranted.

Cc: @kyle.edwards