# Updates the <content> of the give <file> if the content changed.
function(_update_file file content)
    set(old_content "")
    if(EXISTS "${file}")
        file(READ "${file}" old_content)
    endif()
    if(NOT old_content STREQUAL content)
        file(WRITE "${file}" "${content}")
    endif()
endfunction()

# Globbing of source files, using a workaround that allows CMake to rebuild when
# new files are added/removed.
#
#       glob_sources(<output_variable> [<globbing-expressions>...])
#
# The given <output_variable> will also be used as the filename for the auto-
# generated cmake sources list (which is used as a dependency, allowing rebuilds
# on source adds/removes).
#
# A second output_variable named `<output_variable>_DEP` will also be created,
# and should be used as a dependency for all other targets which use the globbed
# sources.
#
# For example:
#
#       glob_sources(SOURCES *.cpp)
#       glob_sources(HEADERS *.h)
#
#       // `SOURCES.cmake` and `HEADERS.cmake` will be created and updated, and
#       // they should be added to source control to trigger rebuilds for all
#       // collaborators.
#
#       // When using ${SOURCES} or ${HEADERS}, a dependency should be specified
#       // so that they can be rebuilt when needed, e.g.:
#       add_library(some_lib ${SOURCES})
#       add_dependencies(some_lib ${SOURCES_DEP}).
#
function(glob_sources output_variable)
    file(GLOB_RECURSE sources RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" ${ARGN})
    list(REMOVE_DUPLICATES sources)
    list(SORT sources)

    set(sources_file "${CMAKE_CURRENT_SOURCE_DIR}/${output_variable}.cmake")
    list(APPEND sources PARENT_SCOPE)
    string(REPLACE ";" "\n    " content "${sources}")
    set(content "set(\n    ${output_variable}\n    ${content}\n)\n")
    set(content "# automatically generated by `glob_sources()`\n${content}")
    _update_file(${sources_file} "${content}")

    file(RELATIVE_PATH dep_target "${CMAKE_SOURCE_DIR}" "${sources_file}")
    string(REPLACE "/" "-" dep_target "${dep_target}")
    set(${output_variable}_DEP "${dep_target}" PARENT_SCOPE)
    add_custom_target(
        "${dep_target}"
        COMMAND ${CMAKE_COMMAND} -E touch "${sources_file}"
        BYPRODUCTS "${sources_file}"
    )

    include(${sources_file})
endfunction()
