# Utility functions to work with accumulated lists of sources.
#
#==========================================================================
#
# sourcelist_to_parent
#
# Arguments:
#    source_list_name - Name of list to send.
#
# Expands relative paths to absolute locations in the source list, then
# copies the value of the list to the list with the same name in the parent
# scope.
#
#==========================================================================
#
# extract_sources
#
# Arguments:
#    sources_needed - Base names of sources required for a target.
#    all_sources - Absolute locations of available source files.
#    source_list_name - Absolute locations of sources to build the target.
#
# Scans through a list of all source files, selects files with the
# requested names, and *appends* them to an output list. If there is more
# than one file with the same name, the *last* match is selected.
#
# This allows you to simulate Makefile idioms that choose from multiple
# versions of a file, based on the order in which they are encountered.
#
#==========================================================================
#
# declare_generated_dependencies.
#
# Arguments:
#    target - The target that needs to depend on generated files.
#    generated_list - The generated source code files the target requires.
#
# Ensures that generated sources in a different directory are produced
# before compiling and linking the target. This is done by assuming that
# each generated source file corresponds to an existing target. For
# instance, a file called "foo.F90" would be generated by a target called
# "generate_foo". The input target can then be made to depend on each of
# the "generate" targets.
#
# This is unnecessary when source code generation occurs in the directory
# where the target was added. However, CMake does not propagate information
# about source code generation to parent directories, so the intermediate
# "generate" targets must be created to enforce generation in the correct
# order.
#
#==========================================================================

#==========================================================================
# Copyright (c) 2013-2014, University Corporation for Atmospheric Research
#
# This software is distributed under a two-clause BSD license, with no
# warranties, express or implied. See the accompanying LICENSE file for
# details.
#==========================================================================

# For each relative path in ${file_list}, prepend ${base_directory} to make
# an absolute path, and put result in list named by ${new_list_name}.
function(expand_relative_paths file_list base_directory new_list_name)

  unset(${new_list_name})
  foreach(file IN LISTS file_list)
    if(IS_ABSOLUTE "${file}")
      set(new_file "${file}")
    else()
      set(new_file "${base_directory}/${file}")
    endif()
    list(APPEND ${new_list_name} "${new_file}")
  endforeach()

  set(${new_list_name} "${${new_list_name}}" PARENT_SCOPE)

endfunction(expand_relative_paths)

# Expand relative paths in a named source list, and export to parent scope.
# The idea here is to communicate the list between a directory added with
# add_subdirectory, and the directory above it.
macro(sourcelist_to_parent source_list_name)
  expand_relative_paths("${${source_list_name}}"
    ${CMAKE_CURRENT_SOURCE_DIR} ${source_list_name})
  set(${source_list_name} "${${source_list_name}}" PARENT_SCOPE)
endmacro(sourcelist_to_parent)

# Find an absolute file path in ${all_sources} for each base name in
# ${sources_needed}, and append found paths to the list named by
# ${source_list_name}.
function(extract_sources sources_needed all_sources source_list_name)

  foreach(needed_source IN LISTS sources_needed)

    set(source_match source-NOTFOUND)

    foreach(source IN LISTS all_sources)
      get_filename_component(basename ${source} NAME)
      if(${basename} STREQUAL ${needed_source})
        set(source_match ${source})
      endif()
    endforeach()

    if(NOT source_match)
      message(FATAL_ERROR
        "Source file not found: ${needed_source}
After searching in list: ${${all_sources}}")
    endif()

    list(APPEND ${source_list_name} ${source_match})

  endforeach()

  set(${source_list_name} "${${source_list_name}}" PARENT_SCOPE)

endfunction(extract_sources)

# Handles dependencies between files generated in one directory and a
# target in another.
# Given a target and a list of files, sets the GENERATED property for each
# file, and makes the target depend on a custom target generated from the
# extensionless base file name. (E.g. for /path/to/foo.F90, it will assume
# that it is generated by a custom target called generate_foo).
function(declare_generated_dependencies target generated_list)
  foreach(file IN LISTS generated_list)

    set_source_files_properties(${file} PROPERTIES GENERATED 1)

    get_filename_component(stripped_name ${file} NAME_WE)

    add_dependencies(${target} generate_${stripped_name})

  endforeach()
endfunction(declare_generated_dependencies)
