# - Print CMake and OS distribution version
#

function (system_info DISTRO)
  message (STATUS "CMake version: ${CMAKE_VERSION}")
  if (CMAKE_SYSTEM MATCHES "Linux")
    distro_name (DISTRO_NAME)
    set(DISTRO ${DISTRO_NAME} PARENT_SCOPE)
    message (STATUS "Linux distribution: ${DISTRO_NAME}")
  elseif (CMAKE_SYSTEM MATCHES "Darwin")
    sw_vers (OS_VERSION)
    message (STATUS "${OS_VERSION}")
  else (CMAKE_SYSTEM MATCHES "Linux")
    message (STATUS "Operating system: ${CMAKE_SYSTEM}")
    endif (CMAKE_SYSTEM MATCHES "Linux")

  target_architecture (TARGET_CPU)
  message (STATUS "Target architecture: ${TARGET_CPU}")
endfunction (system_info)

function (sw_vers varname)
  # query operating system for information
  exec_program (sw_vers OUTPUT_VARIABLE _vers)
  # split multi-line into various fields
  string (REPLACE "\n" ";" _vers "${_vers}")
  string (REPLACE ":" ";" _vers "${_vers}")
  # get the various fields
  list (GET _vers 1 _prod_name)
  list (GET _vers 3 _prod_vers)
  list (GET _vers 5 _prod_build)
  # remove extraneous whitespace
  string (STRIP "${_prod_name}" _prod_name)
  string (STRIP "${_prod_vers}" _prod_vers)
  string (STRIP "${_prod_build}" _prod_build)
  # assemble result variable
  set (${varname} "${_prod_name} version: ${_prod_vers} (${_prod_build})" PARENT_SCOPE)
endfunction (sw_vers varname)

# probe various system files that may be found
function (distro_name varname)
  file (GLOB has_os_release /etc/os-release)
  file (GLOB has_lsb_release /etc/lsb-release)
  file (GLOB has_sys_release /etc/system-release)
  file (GLOB has_redhat_release /etc/redhat-release)
  set (_descr)
  # start with /etc/os-release,
  # see <http://0pointer.de/blog/projects/os-release.html>
  if (NOT has_os_release STREQUAL "")
  read_release (PRETTY_NAME FROM /etc/os-release INTO _descr)
  # previous "standard", used on older Ubuntu and Debian
  elseif (NOT has_lsb_release STREQUAL "")
  read_release (DISTRIB_DESCRIPTION FROM /etc/lsb-release INTO _descr)
  endif (NOT has_os_release STREQUAL "")
  # RHEL/CentOS etc. has just a text-file
  if (NOT _descr)
  if (NOT has_sys_release STREQUAL "")
    file (READ /etc/system-release _descr)
  elseif (NOT has_redhat_release STREQUAL "")
    file (READ /etc/redhat-release _descr)
  else (NOT has_sys_release STREQUAL "")
    # no yet known release file found
    set (_descr "unknown")
  endif (NOT has_sys_release STREQUAL "")
  endif (NOT _descr)
  # return from function (into appropriate variable)
  string (STRIP "${_descr}" _descr)
  set (${varname} "${_descr}" PARENT_SCOPE)
endfunction (distro_name varname)

# read property from the newer /etc/os-release
function (read_release valuename FROM filename INTO varname)
  file (STRINGS ${filename} _distrib
  REGEX "^${valuename}="
  )
  string (REGEX REPLACE
  "^${valuename}=\"?\(.*\)" "\\1" ${varname} "${_distrib}"
  )
  # remove trailing quote that got globbed by the wildcard (greedy match)
  string (REGEX REPLACE
  "\"$" "" ${varname} "${${varname}}"
  )
  set (${varname} "${${varname}}" PARENT_SCOPE)
endfunction (read_release valuename FROM filename INTO varname)

# the following code is adapted from commit f7467762 of the code at
# <https://github.com/petroules/solar-cmake/blob/master/TargetArch.cmake>
# which is Copyright (c) 2012 Petroules Corporation, and which at the
# time of download (2013-04-07 12:30 CET) is made available with a BSD license.
#
# it attempts to compile a program which detects the architecture from the
# preprocessor symbols and communicate this back to us through an error message(!)
function (target_architecture output_var)
  # OS X is capable of building for *several* architectures at once in
  # the Mach-O binary, and there is a variable that tells us which those
  # are, but they may be in any order, so they must be normalized
  if (APPLE AND CMAKE_OSX_ARCHITECTURES)
  # detect each of the possible candidates as a separate flag
  set (osx_arch_list i386 x86_64)
  foreach (osx_arch IN ITEMS ${CMAKE_OSX_ARCHITECTURES})
    foreach (candidate IN LISTS osx_arch_list)
    if ("${osx_arch}" STREQUAL "${candidate}")
      set (osx_arch_${candidate} TRUE)
    endif ("${osx_arch}" STREQUAL "${candidate}")
    endforeach (candidate)
  endforeach (osx_arch)

  # add all architectures back in normalized order
  foreach (candidate IN LISTS osx_arch_list)
    if (osx_arch_${candidate})
    list (APPEND ARCH ${candidate})
    endif (osx_arch_${candidate})
  endforeach (candidate)

  else (APPLE AND CMAKE_OSX_ARCHITECTURES)
  # use the preprocessor defines to determine which target architectures
  # that are available
  set (arch_c_src "
    #if defined(__arm__) || defined(__TARGET_ARCH_ARM)
    #  if defined(__ARM_ARCH_7__) \\
       || defined(__ARM_ARCH_7A__) \\
       || defined(__ARM_ARCH_7R__) \\
       || defined(__ARM_ARCH_7M__) \\
       || (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 7)
    #    error cmake_ARCH armv7
    #  elif defined(__ARM_ARCH_6__) \\
         || defined(__ARM_ARCH_6J__) \\
         || defined(__ARM_ARCH_6T2__) \\
         || defined(__ARM_ARCH_6Z__) \\
         || defined(__ARM_ARCH_6K__) \\
         || defined(__ARM_ARCH_6ZK__) \\
         || defined(__ARM_ARCH_6M__) \\
         || (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 6)
    #    error cmake_ARCH armv6
    #  elif defined(__ARM_ARCH_5TEJ__) \\
        || (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 5)
    #    error cmake_ARCH armv5
    #  else
    #    error cmake_ARCH arm
    #  endif
    #elif defined(__i386) \\
         || defined(__i386__) \\
         || defined(_M_IX86)
    #  error cmake_ARCH i386
    #elif defined(__x86_64) \\
         || defined(__x86_64__) \\
         || defined(__amd64) \\
         || defined(_M_X64)
    #  error cmake_ARCH x86_64
    #elif defined(__ia64) \\
         || defined(__ia64__) \\
         || defined(_M_IA64)
    #  error cmake_ARCH ia64
    #elif defined(__ppc__) \\
         || defined(__ppc) \\
         || defined(__powerpc__) \\
       || defined(_ARCH_COM) \\
         || defined(_ARCH_PWR) \\
         || defined(_ARCH_PPC) \\
       || defined(_M_MPPC) \\
         || defined(_M_PPC)
    #  if defined(__ppc64__) \\
         || defined(__powerpc64__) \\
         || defined(__64BIT__)
    #    error cmake_ARCH ppc64
    #  else
    #    error cmake_ARCH ppc
    #  endif
    #else
    #  error cmake_ARCH unknown
    #endif
    ")

  # write a temporary program that can be compiled to get the result
  set (tmp_dir "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp")
  set (arch_c "${tmp_dir}/arch.c")
  file (WRITE "${arch_c}" "${arch_c_src}")
  try_compile (
    compile_result_unused
    "${tmp_dir}"
    "${arch_c}"
    CMAKE_FLAGS CMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES}
    OUTPUT_VARIABLE ARCH
    )

    # parse the architecture name from the compiler output
    string (REGEX MATCH "cmake_ARCH ([a-zA-Z0-9_]+)" ARCH "${ARCH}")

    # get rid of the value marker leaving just the architecture name
    string (REPLACE "cmake_ARCH " "" ARCH "${ARCH}")

    # if we are compiling with an unknown architecture this variable should
    # already be set to "unknown" but in the case that it's empty (i.e. due
    # to a typo in the code), then set it to unknown
    if (NOT ARCH)
      set (ARCH "unknown")
    endif()
  endif()

  set (${output_var} "${ARCH}" PARENT_SCOPE)
endfunction()