# Collection of useful functions that are required by PLplot.

# Copyright (C) 2011-2019 Alan W. Irwin
#
# This file is part of PLplot.
#
# PLplot is free software; you can redistribute it and/or modify
# it under the terms of the GNU Library General Public License as published
# by the Free Software Foundation; version 2 of the License.
#
# PLplot is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Library General Public License for more details.
#
# You should have received a copy of the GNU Library General Public License
# along with PLplot; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA

function(list_example_files path device suffix output_list)
  # Return list of files (with ${path}/ prepended to form the full path
  # name for each file) that are generated by plplot-test.sh for a
  # particular device and file suffix corresponding to front-end
  # language.  This list will be used for OUTPUT files of a custom
  # command so that these files will be properly deleted by "make
  # clean".  Thus, it doesn't matter if we miss a few examples or
  # pages that are only implemented for one of the languages.
  # However, if we specify a file that is not generated by
  # plplot-test.sh for the specified device and language, then that
  # custom command is never satisfied and will continue to regenerate
  # the files.  Therefore only specify examples and pages that you
  # _know_ are generated by all language bindings.
  # MAINTENANCE
  set(examples_pages_LIST
    x00:01
    x01:01
    x02:02
    x03:01
    x04:02
    x05:01
    x06:05
    x07:20
    x08:10
    x09:05
    x10:01
    x11:08
    x12:01
    x13:01
    x14:02
    x14a:02
    x15:03
    x16:05
    x17:01
    x18:08
    x19:05
    x20:06
    x21:03
    x22:05
#temporary    x23:16
    x24:01
    x25:08
    x26:02
    x27:20
    x28:05
    x29:10
    x30:02
    x31:01
    # 32 missing deliberately since that only implemented for C
    x33:100
    )

  # This list taken directly from plplot-test.sh.cmake.  Update as needed.
  # MAINTENANCE
  if(
      ${device} STREQUAL "png" OR
      ${device} STREQUAL "pngcairo" OR
      ${device} STREQUAL "epscairo" OR
      ${device} STREQUAL "jpeg" OR
      ${device} STREQUAL "xfig" OR
      ${device} STREQUAL "svg" OR
      ${device} STREQUAL "svgcairo" OR
      ${device} STREQUAL "bmpqt" OR
      ${device} STREQUAL "jpgqt" OR
      ${device} STREQUAL "pngqt" OR
      ${device} STREQUAL "ppmqt" OR
      ${device} STREQUAL "tiffqt" OR
      ${device} STREQUAL "svgqt" OR
      ${device} STREQUAL "epsqt" OR
      ${device} STREQUAL "pdfqt" OR
      ${device} STREQUAL "gif"
      )
    set(familying ON)
  else(
      ${device} STREQUAL "png" OR
      ${device} STREQUAL "pngcairo" OR
      ${device} STREQUAL "epscairo" OR
      ${device} STREQUAL "jpeg" OR
      ${device} STREQUAL "xfig" OR
      ${device} STREQUAL "svg" OR
      ${device} STREQUAL "svgcairo" OR
      ${device} STREQUAL "bmpqt" OR
      ${device} STREQUAL "jpgqt" OR
      ${device} STREQUAL "pngqt" OR
      ${device} STREQUAL "ppmqt" OR
      ${device} STREQUAL "tiffqt" OR
      ${device} STREQUAL "svgqt" OR
      ${device} STREQUAL "epsqt" OR
      ${device} STREQUAL "pdfqt" OR
      ${device} STREQUAL "gif"
      )
    set(familying OFF)
  endif(
    ${device} STREQUAL "png" OR
    ${device} STREQUAL "pngcairo" OR
    ${device} STREQUAL "epscairo" OR
    ${device} STREQUAL "jpeg" OR
    ${device} STREQUAL "xfig" OR
    ${device} STREQUAL "svg" OR
    ${device} STREQUAL "svgcairo" OR
    ${device} STREQUAL "bmpqt" OR
    ${device} STREQUAL "jpgqt" OR
    ${device} STREQUAL "pngqt" OR
    ${device} STREQUAL "ppmqt" OR
    ${device} STREQUAL "tiffqt" OR
    ${device} STREQUAL "svgqt" OR
    ${device} STREQUAL "epsqt" OR
    ${device} STREQUAL "pdfqt" OR
    ${device} STREQUAL "gif"
    )
  set(file_list)

  foreach(example_pages ${examples_pages_LIST})
    string(REGEX REPLACE "^(.*):.*$" "\\1" example ${example_pages})
    string(REGEX REPLACE "^.*:(.*)$" "\\1" pages ${example_pages})
    if(${suffix} STREQUAL "a")
      string(REGEX REPLACE "^x" "xtraditional" traditional_example ${example})
      string(REGEX REPLACE "^x" "xstandard" example ${example})
    else(${suffix} STREQUAL "a")
      set(traditional_example)
    endif(${suffix} STREQUAL "a")
    if(familying)
      foreach(famnum RANGE 1 ${pages})
        if(famnum LESS 10)
          set(famnum 0${famnum})
        endif(famnum LESS 10)
        list(APPEND file_list ${path}/${example}${suffix}${famnum}.${device})
        if(traditional_example)
          list(APPEND file_list ${path}/${traditional_example}${suffix}${famnum}.${device})
        endif(traditional_example)
      endforeach(famnum RANGE 1 ${pages})
    else(familying)
      list(APPEND file_list ${path}/${example}${suffix}.${device})
      if(traditional_example)
        list(APPEND file_list ${path}/${traditional_example}${suffix}.${device})
      endif(traditional_example)
    endif(familying)
    if(NOT ${example} MATCHES "x.*14a")
      list(APPEND file_list ${path}/${example}${suffix}_${device}.txt)
      if(traditional_example)
        list(APPEND file_list ${path}/${traditional_example}${suffix}_${device}.txt)
      endif(traditional_example)
    endif(NOT ${example} MATCHES "x.*14a")
  endforeach(example_pages ${examples_pages_LIST})

  set(${output_list} ${file_list} PARENT_SCOPE)
endfunction(list_example_files)

# CMake-2.6.x duplicates this list so work around that bug by removing
# those duplicates.
if(CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES)
  list(REMOVE_DUPLICATES CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES)
endif(CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES)

# Filter all CMAKE_<LANG>_IMPLICIT_LINK_DIRECTORIES list elements from
# a list, where ${rpath} is the name of the list, and ${${rpath}} is
# the actual list.
# Note, this function uses variables that are only defined after
# languages have been enabled but according to the documentation the
# logic is only invoked when the function is invoked so this should be
# OK _if care is used that this function is invoked only after the
# languages have been enabled_.  C is enabled immediately so that will
# serve most purposes, but CXX and Fortran are enabled later so if you
# want those special system locations removed (unlikely but possible)
# then you are going to have to be somewhat more careful when this
# function is invoked.

function(filter_rpath rpath)
  #message("DEBUG: ${rpath} = ${${rpath}}")
  set(internal_rpath ${${rpath}})
  if(internal_rpath)
    # Remove duplicates and empty elements.
    list(REMOVE_DUPLICATES internal_rpath)
    list(REMOVE_ITEM internal_rpath "")
    set(directories_to_be_removed
      ${CMAKE_C_IMPLICIT_LINK_DIRECTORIES}
      ${CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES}
      ${CMAKE_Fortran_IMPLICIT_LINK_DIRECTORIES}
      )

    if(directories_to_be_removed)
      list(REMOVE_DUPLICATES directories_to_be_removed)
    endif(directories_to_be_removed)

    if(directories_to_be_removed)
      list(REMOVE_ITEM internal_rpath ${directories_to_be_removed})
    endif(directories_to_be_removed)
  endif(internal_rpath)
  #message("DEBUG: (filtered) ${rpath} = ${internal_rpath}")
  set(${rpath} ${internal_rpath} PARENT_SCOPE)
endfunction(filter_rpath)

# First argument is a variable corresponding to a list of rpath locations which gets updated
# in the parent scope.
# Second argument is a string containing a semicolon-delimited list of dependent libraries
# whose INSTALL_RPATH properties are to be added to the rpath list for the transitive rpath case.
function(process_rpath rpath tll_arguments)
  #message("DEBUG: ${rpath} = ${${rpath}}")
  set(internal_rpath ${${rpath}})
  if(internal_rpath)
    if(NOT "${tll_arguments}" STREQUAL "" AND NOT (NON_TRANSITIVE_RPATH AND BUILD_SHARED_LIBS))
      foreach(tll_argument ${tll_arguments})
	if(tll_argument MATCHES "${PROJECT_NAMESPACE}")
	  get_target_property(transitive_lib_install_rpath ${tll_argument} INSTALL_RPATH)
	  if(transitive_lib_install_rpath)
	    list(APPEND internal_rpath ${transitive_lib_install_rpath})
	  endif(transitive_lib_install_rpath)
	endif(tll_argument MATCHES "${PROJECT_NAMESPACE}")
      endforeach(tll_argument ${tll_arguments})
    endif(NOT "${tll_arguments}" STREQUAL "" AND NOT (NON_TRANSITIVE_RPATH AND BUILD_SHARED_LIBS))
  endif(internal_rpath)
  #message("DEBUG: (transitive?) ${rpath} = ${internal_rpath}")
  filter_rpath(internal_rpath)
  #message("DEBUG: (filtered and transitive?) ${rpath} = ${internal_rpath}")
  set(${rpath} ${internal_rpath} PARENT_SCOPE)
endfunction(process_rpath rpath tll_arguments)

if(MINGW)
  # Useful function to convert Windows list of semicolon-delimited
  # PATHs to the equivalent list of MSYS PATHs (exactly like the
  # colon-delimited Unix list of PATHs except the driver letters are
  # specified as the initial one-character component of each of the
  # PATHs).  For example, this function will transform the Windows
  # list of PATHs, "z:\path1;c:\path2" to "/z/path1:/c/path2".
  function(determine_msys_path MSYS_PATH NATIVE_PATH)
    #message(STATUS "NATIVE_PATH = ${NATIVE_PATH}")
    string(REGEX REPLACE "^\([a-zA-z]\):" "/\\1" PATH  "${NATIVE_PATH}")
    string(REGEX REPLACE ";\([a-zA-z]\):" ";/\\1" PATH  "${PATH}")
    string(REGEX REPLACE ";" ":" PATH  "${PATH}")
    file(TO_CMAKE_PATH "${PATH}" PATH)
    #message(STATUS "MSYS_PATH = ${PATH}")
    set(${MSYS_PATH} ${PATH} PARENT_SCOPE)
  endfunction(determine_msys_path)
endif(MINGW)

function(configure_file_generate)
  # Configure files that contain both normal items
  # to configure (referenced as ${VAR} or @VAR@) as well as
  # generator expressions (referenced as $<...>).
  # The arguments of this function have exactly the
  # same syntax and meaning as configure_file.

  list(GET ARGV 0 input_file)
  list(GET ARGV 1 output_file)
  set(configure_file_generate_suffix "_cf_only")
  set(intermediate_file ${output_file}${configure_file_generate_suffix})

  # Locally modify ARGV so that output file for configure file is
  # redirected to intermediate_file.
  list(REMOVE_AT ARGV 1)
  list(INSERT ARGV 1 ${intermediate_file})

  # Configure all but generator expressions.
  configure_file(${ARGV})

  # Configure generator expressions.
  # N.B. these ${output_file} results will only be available
  # at generate time.
  file(GENERATE
    OUTPUT ${output_file}
    INPUT ${intermediate_file}
    )
endfunction(configure_file_generate)

function(configure_executable_build executable executable_src tll_arguments lib_install_rpath install_dir)
  # Configure the build of executables and corresponding namespaced
  # ALIAS executables in a uniform way that supports the appropriate
  # writeable or read-only prefixes for all target names that are generated.
  #
  # This function should be duplicated for the PLplot, ephcom, and
  # te_gen software projects and should only be used for those
  # executables that are both built in the build tree AND namespaced
  # installed (not built) in the install tree.

  # executable contains a string corresponding to the target name of an executable.

  # executable_src contains a list of source files for the executable.

  # tll_arguments contains a quoted list of arguments for target_link_libraries
  # for the executable.  If tll_arguments evaluates to a false value (e.g.,
  # an empty string), then target_link_libraries will not be called.

  # lib_install_rpath contains a quoted list of rpath directories.  If
  # lib_install_rpath evaluates to a false value, (e.g., an empty string)
  # then the INSTALL_RPATH property of the target will not be set.

  # install_dir contains the install location of the executable.

  # N.B. Actual arguments used for calls to configure_executable_build
  # are values (e.g., lists are expressed as "a;b;c") and NOT
  # variables.  Therefore, only one level of dereferencing required to
  # access the argument values.

  #message(STATUS "DEBUG: executable = ${executable}")
  #message(STATUS "DEBUG: executable_src = ${executable_src}")
  #message(STATUS "DEBUG: tll_arguments = ${tll_arguments}")

  # Sanity checks on values of argument variables:
  if("${executable}" STREQUAL "")
    message(FATAL_ERROR "configure_executable_build: executable is empty when it should be a executable target name")
  endif("${executable}" STREQUAL "")

  if("${executable_src}" STREQUAL "")
    message(FATAL_ERROR "configure_executable_build: executable_src is empty when it should be a list of executable source files for the ${executable} executable")
  endif("${executable_src}" STREQUAL "")

  # Sanity check that the external variable PROJECT_NAMESPACE has been set correctly.
  if(NOT "${PROJECT_NAMESPACE}" MATCHES ".*::$")
    message(FATAL_ERROR "configure_executable_build:PROJECT_NAMESPACE = ${PROJECT_NAMESPACE} does not have the correct trailing \"::\"")
  endif(NOT "${PROJECT_NAMESPACE}" MATCHES ".*::$")

  set(original_executable ${executable})
  set(executable ${WRITEABLE_TARGET}${executable})
  add_executable(${executable} ${executable_src})
  # Create equivalent namespaced ALIAS executable to be used whenever
  # the executable target is read only.
  add_executable(${PROJECT_NAMESPACE}${original_executable} ALIAS ${executable})

  if(NOT "${tll_arguments}" STREQUAL "")
    if(NON_TRANSITIVE)
      target_link_libraries(${executable} PRIVATE ${tll_arguments})
    else(NON_TRANSITIVE)
      target_link_libraries(${executable} PUBLIC ${tll_arguments})
    endif(NON_TRANSITIVE)
  endif(NOT "${tll_arguments}" STREQUAL "")

  if(BUILD_SHARED_LIBS)
    set_target_properties(${executable}
      PROPERTIES
      COMPILE_DEFINITIONS "USINGDLL"
      )
  endif(BUILD_SHARED_LIBS)

  if(USE_RPATH)
    process_rpath(lib_install_rpath "${tll_arguments}")
    #message(STATUS "DEBUG: transitive lib_install_rpath = ${lib_install_rpath} for original_executable = ${original_executable}")
    if(lib_install_rpath)
      set_target_properties(
        ${executable}
        PROPERTIES
        INSTALL_RPATH "${lib_install_rpath}"
        )
    endif(lib_install_rpath)
  else(USE_RPATH)
    # INSTALL_NAME_DIR property ignored on all platforms other than Mac OS X.
    # Also, this Mac OS X property is only set when rpath is
    # not used (because otherwise it would supersede
    # rpath).
    set_target_properties(
      ${executable}
      PROPERTIES
      INSTALL_NAME_DIR "${install_dir}"
      )
  endif(USE_RPATH)

  configure_target_install(${executable} ${install_dir})

endfunction(configure_executable_build executable executable_src tll_arguments lib_install_rpath install_dir)

function(configure_library_build library library_type library_src tll_arguments lib_install_rpath)
  # Configure the build of libraries (including modules and swig
  # modules) and corresponding namespaced ALIAS libraries in a uniform
  # way that supports the appropriate writeable or read-only prefixes
  # for all target names that are generated.
  #
  # This function should be duplicated for the PLplot, ephcom, and
  # te_gen software projects and should only be used for those
  # libraries that are both built in the build tree AND namespaced
  # installed (not built) in the install tree.

  # library contains a string corresponding to the target name of a library.

  # library_type should be one of
  # * empty string (in which case the library is one of SHARED or STATIC
  #   depending on the value of BUILD_SHARED_LIBS)
  # * SHARED (the library is built as a shared library)
  # * STATIC (the library is built as a static library)
  # * MODULE (the library is built as a dll)
  # * <language> (where [case-insensitive] language is one of the languages supported by
  # * swig, and library is built as a swig module.

  # library_src contains a list of source files for the library.

  # tll_arguments contains a quoted list of arguments for (swig|target)_link_libraries
  # for the library.  If tll_arguments evaluates to a false value (e.g.,
  # an empty string), then (swig|target)_link_libraries will not be called.

  # lib_install_rpath contains a quoted list of rpath directories.  If
  # lib_install_rpath evaluates to a false value, (e.g., an empty string)
  # then the INSTALL_RPATH property of the target will not be set.

  # N.B. there are two additional optional arguments which are the following:

  # The first optional argument contains a string corresponding to the
  # full pathname of the installation directory which defaults to
  # ${LIB_DIR}.  This is used to help set the target property
  # INSTALL_NAME_DIR.  It is also optionally passed on for the call to
  # configure_target_install.

  # The second optional argument contains a list of
  # semicolon-separated install permissions in a string for the module
  # or executable that is optionally passed on for the call to
  # configure_target_install.

  # N.B. Actual arguments used for calls to
  # configure_library_build are values (e.g., lists are
  # expressed as "a;b;c") and NOT variables.  Therefore, only one
  # level of dereferencing required to access the argument values.

  #message(STATUS "DEBUG: library = ${library}")
  #message(STATUS "DEBUG: library_src = ${library_src}")
  #message(STATUS "DEBUG: tll_arguments = ${tll_arguments}")

  # Global variables which must be defined
  #message(STATUS "DEBUG: BUILD_SHARED_LIBS = ${BUILD_SHARED_LIBS}")
  #message(STATUS "DEBUG: NON_TRANSITIVE = ${NON_TRANSITIVE}")
  #message(STATUS "DEBUG: ${library}_SOVERSION = ${${library}_SOVERSION}")
  #message(STATUS "DEBUG: ${library}_VERSION = ${${library}_VERSION}")
  #message(STATUS "DEBUG: CMAKE_INSTALL_LIBDIR = ${CMAKE_INSTALL_LIBDIR}")
  #message(STATUS "DEBUG: USE_RPATH = ${USE_RPATH}")

  # Sanity checks on values of argument variables:
  if("${library}" STREQUAL "")
    message(FATAL_ERROR "configure_library_build: library is empty when it should be a library target name")
  endif("${library}" STREQUAL "")

  if("${library_type}" STREQUAL "")
    # If "${library_type}" is an empty string, then the library is built as static
    # or shared depending on BUILD_SHARED_LIBS, and a swig module build is NOT
    # being configured.
    if(BUILD_SHARED_LIBS)
      set(library_type SHARED)
    else(BUILD_SHARED_LIBS)
      set(library_type STATIC)
    endif(BUILD_SHARED_LIBS)
    set(if_swig_module OFF)
  elseif("${library_type}" STREQUAL "STATIC" OR "${library_type}" STREQUAL "SHARED" OR "${library_type}" STREQUAL "MODULE")
    # For these cases a swig module build is NOT being configured.
    set(if_swig_module OFF)
  else("${library_type}" STREQUAL "")
    # Assume the caller is trying to configure a build of a swig module by
    # specifying the swig language as "${library_type}" (with any case).
    set(if_swig_module ON)
    # Lower case language used from now on.
    string(TOLOWER "${library_type}" language)
  endif("${library_type}" STREQUAL "")

  if("${library_src}" STREQUAL "")
    message(FATAL_ERROR "configure_library_build: library_src is empty when it should be a list of library source files for the ${library} library")
  endif("${library_src}" STREQUAL "")

  # Sanity check that the external variable PROJECT_NAMESPACE has been set correctly.
  if(NOT "${PROJECT_NAMESPACE}" MATCHES ".*::$")
    message(FATAL_ERROR "configure_library_build:PROJECT_NAMESPACE = ${PROJECT_NAMESPACE} does not have the correct trailing \"::\"")
  endif(NOT "${PROJECT_NAMESPACE}" MATCHES ".*::$")

  # Sanity check that all relevant external variables not checked
  # above have been DEFINED.
  set(variables_list)
  list(APPEND variables_list
    NON_TRANSITIVE
    )

  set(original_library ${library})
  set(library ${WRITEABLE_TARGET}${library})
  if(if_swig_module)
    foreach(variable ${variables_list})
      if(NOT DEFINED ${variable})
	message(FATAL_ERROR "configure_library_build: (external) ${variable} = NOT DEFINED")
      endif(NOT DEFINED ${variable})
    endforeach(variable ${variables_list})
    swig_add_library(${library} LANGUAGE "${language}" TYPE MODULE SOURCES ${library_src})
    # Propagate value of this variable (set in swig_add_library macro) to calling environment.
    # Example:
    # original_library = plplotc
    # library = ${WRITEABLE_TARGET}plplotc
    # ${SWIG_MODULE_${library}_REAL_NAME} = _${WRITEABLE_TARGET}plplotc
    # ${SWIG_MODULE_${library}_UNPREFIXED_REAL_NAME} = _plplotc
    if(WRITEABLE_TARGET)
      string(REGEX REPLACE "${WRITEABLE_TARGET}" "" SWIG_MODULE_${library}_UNPREFIXED_REAL_NAME ${SWIG_MODULE_${library}_REAL_NAME})
    else(WRITEABLE_TARGET)
      set(SWIG_MODULE_${library}_UNPREFIXED_REAL_NAME ${SWIG_MODULE_${library}_REAL_NAME})
    endif(WRITEABLE_TARGET)

    # SWIG_MODULE_plplotc_REAL_NAME (in parent scope) = _${WRITEABLE_TARGET}plplotc

    set(SWIG_MODULE_${original_library}_REAL_NAME ${SWIG_MODULE_${library}_REAL_NAME} PARENT_SCOPE)
    # Create equivalent namespaced ALIAS library to be used whenever
    # the library target is read only.
    #message(STATUS "DEBUG: swig_alias_name = ${PROJECT_NAMESPACE}${SWIG_MODULE_${library}_UNPREFIXED_REAL_NAME}")
    add_library(${PROJECT_NAMESPACE}${SWIG_MODULE_${library}_UNPREFIXED_REAL_NAME} ALIAS ${SWIG_MODULE_${library}_REAL_NAME})

    if(NOT "${tll_arguments}" STREQUAL "")
      if(NON_TRANSITIVE)
	target_link_libraries(${SWIG_MODULE_${library}_REAL_NAME} PRIVATE ${tll_arguments})
      else(NON_TRANSITIVE)
	target_link_libraries(${SWIG_MODULE_${library}_REAL_NAME} PUBLIC ${tll_arguments})
      endif(NON_TRANSITIVE)
    endif(NOT "${tll_arguments}" STREQUAL "")

    set_target_properties(
      ${SWIG_MODULE_${library}_REAL_NAME}
      PROPERTIES
      COMPILE_DEFINITIONS "USINGDLL"
      )

    if(USE_RPATH)
      process_rpath(lib_install_rpath "${tll_arguments}")
      #message(STATUS "DEBUG: transitive lib_install_rpath = ${lib_install_rpath} for original_library = ${original_library}")
      if(lib_install_rpath)
        set_target_properties(
          ${SWIG_MODULE_${library}_REAL_NAME}
          PROPERTIES
          INSTALL_RPATH "${lib_install_rpath}"
          )
      endif(lib_install_rpath)
    else(USE_RPATH)
      # INSTALL_NAME_DIR property ignored on all platforms other than Mac OS X.
      # Also, this Mac OS X property is only set when rpath is
      # not used (because otherwise it would supersede
      # rpath).
      if(ARGC GREATER 5)
	set(install_name_dir ${ARGV5})
      else(ARGC GREATER 5)
	set(install_name_dir ${LIB_DIR})
      endif(ARGC GREATER 5)
      set_target_properties(
        ${SWIG_MODULE_${library}_REAL_NAME}
        PROPERTIES
        INSTALL_NAME_DIR "${install_name_dir}"
        )
    endif(USE_RPATH)

    if(ARGC EQUAL 6)
      configure_target_install(${SWIG_MODULE_${library}_REAL_NAME} ${ARGV5})
    elseif(ARGC EQUAL 7)
      configure_target_install(${SWIG_MODULE_${library}_REAL_NAME} ${ARGV5} "${ARGV6}")
    else(ARGC EQUAL 6)
      message(FATAL_ERROR "configure_library_build called with number of arguments not equal to 6 or 7 for library_type = ${library_type}")
    endif(ARGC EQUAL 6)

  else(if_swig_module)
    if("${library_type}" STREQUAL "SHARED")
      list(APPEND variables_list
	${original_library}_SOVERSION
	${original_library}_VERSION
	CMAKE_INSTALL_LIBDIR
	USE_RPATH
	)
    endif("${library_type}" STREQUAL "SHARED")

    foreach(variable ${variables_list})
      if(NOT DEFINED ${variable})
	message(FATAL_ERROR "configure_library_build: (external) ${variable} = NOT DEFINED")
      endif(NOT DEFINED ${variable})
    endforeach(variable ${variables_list})

    add_library(${library} ${library_type} ${library_src})
    # Create equivalent namespaced ALIAS library to be used whenever
    # the library target is read only.
    add_library(${PROJECT_NAMESPACE}${original_library} ALIAS ${library})

    if(NOT "${tll_arguments}" STREQUAL "")
      if(NON_TRANSITIVE)
	target_link_libraries(${library} PRIVATE ${tll_arguments})
      else(NON_TRANSITIVE)
	target_link_libraries(${library} PUBLIC ${tll_arguments})
      endif(NON_TRANSITIVE)
    endif(NOT "${tll_arguments}" STREQUAL "")

    # Set library target properties
    if(USE_RPATH)
      process_rpath(lib_install_rpath "${tll_arguments}")
      #message(STATUS "DEBUG: transitive lib_install_rpath = ${lib_install_rpath} for original_library = ${original_library}")
      if(lib_install_rpath)
        set_target_properties(
          ${library}
          PROPERTIES
          INSTALL_RPATH "${lib_install_rpath}"
          )
      endif(lib_install_rpath)
    else(USE_RPATH)
      # INSTALL_NAME_DIR property ignored on all platforms other than Mac OS X.
      # Also, this Mac OS X property is only set when rpath is
      # not used (because otherwise it would supersede
      # rpath).
      if(ARGC GREATER 5)
	set(install_name_dir ${ARGV5})
      else(ARGC GREATER 5)
	set(install_name_dir ${LIB_DIR})
      endif(ARGC GREATER 5)
      set_target_properties(
        ${library}
        PROPERTIES
        INSTALL_NAME_DIR "${install_name_dir}"
        )
    endif(USE_RPATH)

    if("${library_type}" STREQUAL "SHARED")
      set_target_properties(
	${library}
	PROPERTIES
	COMPILE_DEFINITIONS "USINGDLL"
	SOVERSION ${${original_library}_SOVERSION}
	VERSION ${${original_library}_VERSION}
	)
    elseif("${library_type}" STREQUAL "MODULE")
      set_target_properties(
	${library}
	PROPERTIES
	COMPILE_DEFINITIONS "USINGDLL"
	)
    elseif("${library_type}" STREQUAL "STATIC")
      set_target_properties(
	${library}
	PROPERTIES
	# This allows static library builds to be linked by shared libraries.
	POSITION_INDEPENDENT_CODE ON
	)
    endif("${library_type}" STREQUAL "SHARED")

    if(ARGC EQUAL 5 AND ("${library_type}" STREQUAL "SHARED" OR "${library_type}" STREQUAL "STATIC"))
      configure_target_install(${library})
    elseif(ARGC EQUAL 6 AND "${library_type}" STREQUAL "MODULE")
      configure_target_install(${library} ${ARGV5})
    elseif(ARGC EQUAL 7 AND "${library_type}" STREQUAL "MODULE")
      configure_target_install(${library} ${ARGV5} "${ARGV6}")
    else(ARGC EQUAL 5)
      message(FATAL_ERROR "configure_library_build called with too many arguments for library_type = ${library_type}")
    endif(ARGC EQUAL 5 AND ("${library_type}" STREQUAL "SHARED" OR "${library_type}" STREQUAL "STATIC"))
  endif(if_swig_module)
endfunction(configure_library_build library library_type library_src tll_arguments lib_install_rpath)

function(configure_target_install target)
  # configure the install of targets and their export data.
  #
  # This function should be duplicated for the PLplot, ephcom, and
  # te_gen software projects and should only be used for those targets
  # (libraries, shared objects, and executables) that are both built
  # in the build tree AND namespaced installed (not built) in the
  # install tree.

  # target contains a string corresponding to the target name

  # Optional second argument contains a string corresponding to the full pathname
  # of the installation directory for a module or executable.

  # Optional third argument contains a list of semicolon-separated install permissions in a string for the module or executable.

  # If the call to configure_target_install only has one argument, the target is a library
  # with known locations where everything needs to be installed.

  # message(STATUS "DEBUG: ARGC = ${ARGC}")
  # message(STATUS "DEBUG: ARGV0 = ${ARGV0}")
  # message(STATUS "DEBUG: ARGV1 = ${ARGV1}")
  # message(STATUS "DEBUG: ARGV2 = ${ARGV2}")

  if(ARGC GREATER 1)
    # Target is a module or executable with ${ARGV1} the install location.
    if(ARGC EQUAL 2)
      install(TARGETS ${target}
	EXPORT export_${target}
	DESTINATION ${ARGV1}
	)
    elseif(ARGC EQUAL 3)
      install(TARGETS ${target}
	EXPORT export_${target}
	DESTINATION ${ARGV1}
	PERMISSIONS ${ARGV2}
	)
    else(ARGC EQUAL 2)
      message(FATAL_ERROR "configure_target_install called with too many arguments")
    endif(ARGC EQUAL 2)
  else(ARGC GREATER 1)
    # Target is a library with the three known install locations used below.
    install(TARGETS ${target}
      EXPORT export_${target}
      ARCHIVE DESTINATION ${LIB_DIR}
      LIBRARY DESTINATION ${LIB_DIR}
      RUNTIME DESTINATION ${BIN_DIR}
      )
  endif(ARGC GREATER 1)

  # Install associated export files
  install(EXPORT export_${target} DESTINATION ${LIB_DIR}/cmake/plplot NAMESPACE ${PROJECT_NAMESPACE})

  # Append to the file that contains logic to include the export files created by the above
  # install(EXPORT...) logic
  file(APPEND ${CMAKE_BINARY_DIR}/plplot_exports.cmake
    "include(\${CMAKE_CURRENT_LIST_DIR}/export_${target}.cmake OPTIONAL)
")

endfunction(configure_target_install target install_dir)
