cmake/dependencies.cmake (99 lines of code) (raw):
# from http://stackoverflow.com/questions/34637980/cmake-sort-a-list-of-target-considering-their-dependencies
define_property(TARGET PROPERTY LINK_LIBRARIES_ALL
BRIEF_DOCS "List of all targets, linked to this one"
FULL_DOCS "List of all targets, linked to this one"
)
# Compute list of all target links (direct and indirect) for given library
# Result is stored in LINK_LIBRARIES_ALL target property.
function(compute_links lib)
if(${lib}_IN_PROGRESS)
message(FATAL_ERROR "Circular dependency for library '${lib}'")
endif()
#check if target is an alias and use that
get_property(aliased_target TARGET "${lib}" PROPERTY ALIASED_TARGET)
if(NOT "${aliased_target}" STREQUAL "")
set(lib "${aliased_target}")
endif()
#interface libraries cannot be set
get_target_property(target_type ${lib} TYPE)
if ("INTERFACE_LIBRARY" STREQUAL ${target_type})
message(STATUS "SKIPPING:" ${lib})
return()
endif()
# Immediately return if output property is already set.
get_property(complete TARGET ${lib} PROPERTY LINK_LIBRARIES_ALL SET)
if(complete)
return()
endif()
# Initialize output property.
set_property(TARGET ${lib} PROPERTY LINK_LIBRARIES_ALL "")
set(${lib}_IN_PROGRESS 1) # Prevent recursion for the same lib
get_target_property(links ${lib} LINK_LIBRARIES)
if(NOT links)
return() # Do not iterate over `-NOTFOUND` value in case of absence of the property.
endif()
# For each direct link append it and its links
foreach(link ${links})
if(TARGET ${link}) # Collect only target links
compute_links(${link})
#interface libraries cannot be set
get_target_property(target_type ${link} TYPE)
if ("INTERFACE_LIBRARY" STREQUAL ${target_type})
message(STATUS "SKIPPING:" ${link})
continue()
endif()
get_target_property(link_links_all ${link} LINK_LIBRARIES_ALL)
set_property(TARGET ${lib} APPEND PROPERTY
LINK_LIBRARIES_ALL ${link} ${link_links_all}
)
elseif(link MATCHES "$<")
message(STATUS "Library '${lib}' uses link '${link}'.")
message(FATAL_ERROR "Algorithm doesn't work with generator expressions.")
endif()
endforeach(link ${links})
# Remove duplicates
get_target_property(links_all ${lib} LINK_LIBRARIES_ALL)
list(REMOVE_DUPLICATES links_all)
set_property(TARGET ${lib} PROPERTY LINK_LIBRARIES_ALL ${links_all})
endfunction()
# Sort given list of targets, so for any target its links come before the target itself.
#
# Uses selection sort (stable).
function(sort_links targets_list)
# Special case of empty input list. Further code assumes list to be non-empty.
if(NOT ${targets_list})
return()
endif()
foreach(link ${${targets_list}})
compute_links(${link})
endforeach()
set(output_list)
set(current_input_list ${${targets_list}})
list(LENGTH current_input_list current_len)
while(NOT current_len EQUAL 1)
# Assume first element as minimal
list(GET current_input_list 0 min_elem)
set(min_index 0)
get_target_property(min_links ${min_elem} LINK_LIBRARIES_ALL)
# Check that given element is actually minimal
set(index 0)
foreach(link ${current_input_list})
if(index) # First iteration should always fail, so skip it.
list(FIND min_links ${link} find_index)
if(NOT find_index EQUAL "-1")
# Choose linked library as new minimal element.
set(min_elem ${link})
set(min_index ${index})
get_target_property(min_links ${min_elem} LINK_LIBRARIES_ALL)
endif(NOT find_index EQUAL "-1")
endif()
math(EXPR index "${index}+1")
endforeach(link ${current_input_list})
# Move minimal element from the input list to the output one.
list(APPEND output_list ${min_elem})
list(REMOVE_AT current_input_list ${min_index})
math(EXPR current_len "${current_len}-1")
endwhile()
# Directly append the only element in the current input list to the resulted variable.
set(${targets_list} ${output_list} ${current_input_list} PARENT_SCOPE)
endfunction(sort_links)