function(get_properties_list VAR)
  # Get all propreties that currently executing cmake supports
  execute_process(
    COMMAND "${CMAKE_COMMAND}" "--help-property-list"
    OUTPUT_VARIABLE _cmake_property_list_output
  )
  # Convert command output into a CMake list
  string(REGEX REPLACE ";" "\\\;" _cmake_property_list_output "${_cmake_property_list_output}")
  string(REGEX REPLACE "\n" ";" _cmake_property_list_output "${_cmake_property_list_output}")

  unset(_cmake_property_list)
  foreach(_cmake_property_name ${_cmake_property_list_output})
    string(REPLACE "<CONFIG>" "${CMAKE_BUILD_TYPE}" _cmake_property_name ${_cmake_property_name})
    # Fix https://stackoverflow.com/questions/32197663/how-can-i-remove-the-the-location-property-may-not-be-read-from-target-error-i
    if(_cmake_property_name STREQUAL "LOCATION" OR _cmake_property_name MATCHES "^LOCATION_" OR _cmake_property_name MATCHES "_LOCATION$")
        continue()
    endif()
    list(APPEND _cmake_property_list "${_cmake_property_name}")
  endforeach(_cmake_property_name)
  list(REMOVE_DUPLICATES _cmake_property_list)
  set(${VAR} ${_cmake_property_list} PARENT_SCOPE)
endfunction(get_properties_list)

function(print_target_properties TARGET)
  if(NOT TARGET "${TARGET}")
    message(WARNING "Unknown target: ${TARGET}")
    return()
  endif(NOT TARGET "${TARGET}")
  message(STATUS "Propties of target: ${TARGET}")
  get_properties_list(_cmake_property_list)
  set(_cmake_target_has_any_property 0)
  foreach(_cmake_property_name ${_cmake_property_list})
    get_target_property(_cmake_property_value "${TARGET}" ${_cmake_property_name})
    if(_cmake_property_value)
      set(_cmake_target_has_any_property 1)
      message(STATUS "  ${_cmake_property_name}: ${_cmake_property_value}")
    endif(_cmake_property_value)
  endforeach(_cmake_property_name)
  if(NOT _cmake_target_has_any_property)
    message(STATUS "Target has no properties")
  endif(NOT _cmake_target_has_any_property)
endfunction(print_target_properties)

function(get_target_archive_name RESULT_VAR TARGET)
  if(NOT TARGET "${TARGET}")
    message(WARNING "Unknown target: ${TARGET}")
    unset(${RESULT_VAR} PARENT_SCOPE)
    return()
  endif(NOT TARGET "${TARGET}")

  unset(_target_out_name)
  # Check NAME property
  get_target_property(_tmp_val "${TARGET}" NAME)
  if(_tmp_val)
    set(_target_out_name "${_tmp_val}")
  endif(_tmp_val)

  # Check OUTPUT_NAME property
  get_target_property(_tmp_val "${TARGET}" OUTPUT_NAME)
  if(_tmp_val)
    set(_target_out_name "${_tmp_val}")
  endif(_tmp_val)
  # Check OUTPUT_NAME_<CONFIG> property
  get_target_property(_tmp_val "${TARGET}" "OUTPUT_NAME_${CMAKE_BUILD_TYPE}")
  if(_tmp_val)
    set(_target_out_name "${_tmp_val}")
  endif(_tmp_val)

  # Check ARCHIVE_OUTPUT_NAME
  get_target_property(_tmp_val "${TARGET}" ARCHIVE_OUTPUT_NAME)
  if(_tmp_val)
    set(_target_out_name "${_tmp_val}")
  endif(_tmp_val)
  # Check ARCHIVE_OUTPUT_NAME_<CONFIG>
  get_target_property(_tmp_val "${TARGET}" "ARCHIVE_OUTPUT_NAME_${CMAKE_BUILD_TYPE}")
  if(_tmp_val)
    set(_target_out_name "${_tmp_val}")
  endif(_tmp_val)

  set(${RESULT_VAR} "${_target_out_name}" PARENT_SCOPE)
endfunction(get_target_archive_name)

function(get_target_output_name RESULT_VAR TARGET)
  if(NOT TARGET "${TARGET}")
    message(WARNING "Unknown target: ${TARGET}")
    unset(${RESULT_VAR} PARENT_SCOPE)
    return()
  endif(NOT TARGET "${TARGET}")

  unset(_target_out_name)
  # Check NAME property
  get_target_property(_tmp_val "${TARGET}" NAME)
  if(_tmp_val)
    set(_target_out_name "${_tmp_val}")
  endif(_tmp_val)

  # Check OUTPUT_NAME property
  get_target_property(_tmp_val "${TARGET}" OUTPUT_NAME)
  if(_tmp_val)
    set(_target_out_name "${_tmp_val}")
  endif(_tmp_val)
  # Check OUTPUT_NAME_<CONFIG> property
  get_target_property(_tmp_val "${TARGET}" "OUTPUT_NAME_${CMAKE_BUILD_TYPE}")
  if(_tmp_val)
    set(_target_out_name "${_tmp_val}")
  endif(_tmp_val)

  get_target_property(_target_type "${TARGET}" TYPE)
  if(NOT _target_type)
    message(WARNING "No value for TYPE property of target ${TARGET}")
    unset(${RESULT_VAR} PARENT_SCOPE)
    return()
  elseif(_target_type STREQUAL "STATIC_LIBRARY")
    # Check ARCHIVE_OUTPUT_NAME property
    get_target_property(_tmp_val "${TARGET}" ARCHIVE_OUTPUT_NAME)
    if(_tmp_val)
      set(_target_out_name "${_tmp_val}")
    endif(_tmp_val)
    # Check ARCHIVE_OUTPUT_DIRECTORY_<CONFIG> property
    get_target_property(_tmp_val "${TARGET}" "ARCHIVE_OUTPUT_NAME_${CMAKE_BUILD_TYPE}")
    if(_tmp_val)
      set(_target_out_name "${_tmp_val}")
    endif(_tmp_val)
  elseif(_target_type STREQUAL "SHARED_LIBRARY")
    # Check LIBRARY_OUTPUT_NAME property
    get_target_property(_tmp_val "${TARGET}" LIBRARY_OUTPUT_NAME)
    if(_tmp_val)
      set(_target_out_name "${_tmp_val}")
    endif(_tmp_val)
    # Check LIBRARY_OUTPUT_NAME_<CONFIG> property
    get_target_property(_tmp_val "${TARGET}" "LIBRARY_OUTPUT_NAME_${CMAKE_BUILD_TYPE}")
    if(_tmp_val)
      set(_target_out_name "${_tmp_val}")
    endif(_tmp_val)
  elseif(_target_type STREQUAL "EXECUTABLE")
    # Check RUNTIME_OUTPUT_NAME property
    get_target_property(_tmp_val "${TARGET}" RUNTIME_OUTPUT_NAME)
    if(_tmp_val)
      set(_target_out_name "${_tmp_val}")
    endif(_tmp_val)
    # Check RUNTIME_OUTPUT_NAME_<CONFIG> property
    get_target_property(_tmp_val "${TARGET}" "RUNTIME_OUTPUT_NAME_${CMAKE_BUILD_TYPE}")
    if(_tmp_val)
      set(_target_out_name "${_tmp_val}")
    endif(_tmp_val)
  else()
    message(WARNING "Invalid value for TYPE property of target ${TARGET}: ${_target_type}")
    unset(${RESULT_VAR} PARENT_SCOPE)
    return()
  endif(NOT _target_type)
  set(${RESULT_VAR} "${_target_out_name}" PARENT_SCOPE)
endfunction(get_target_output_name)

function(get_target_archive_directory RESULT_VAR TARGET)
  if(NOT TARGET "${TARGET}")
    message(WARNING "Unknown target: ${TARGET}")
    unset(${RESULT_VAR} PARENT_SCOPE)
    return()
  endif(NOT TARGET "${TARGET}")

  unset(_target_out_dir)
  # Check BINARY_DIR property
  get_target_property(_tmp_val "${TARGET}" BINARY_DIR)
  if(_tmp_val)
    set(_target_out_dir "${_tmp_val}")
  endif(_tmp_val)

  # Check ARCHIVE_OUTPUT_DIRECTORY
  get_target_property(_tmp_val "${TARGET}" ARCHIVE_OUTPUT_DIRECTORY)
  if(_tmp_val)
    set(_target_out_dir "${_tmp_val}")
  endif(_tmp_val)
  # Check ARCHIVE_OUTPUT_DIRECTORY_<CONFIG>
  get_target_property(_tmp_val "${TARGET}" "ARCHIVE_OUTPUT_DIRECTORY_${CMAKE_BUILD_TYPE}")
  if(_tmp_val)
    set(_target_out_dir "${_tmp_val}")
  endif(_tmp_val)

  set(${RESULT_VAR} "${_target_out_dir}" PARENT_SCOPE)
endfunction(get_target_archive_directory)

function(get_target_output_directory RESULT_VAR TARGET)
  if(NOT TARGET "${TARGET}")
    message(WARNING "Unknown target: ${TARGET}")
    unset(${RESULT_VAR} PARENT_SCOPE)
    return()
  endif(NOT TARGET "${TARGET}")

  unset(_target_out_dir)
  # Check BINARY_DIR property
  get_target_property(_tmp_val "${TARGET}" BINARY_DIR)
  if(_tmp_val)
    set(_target_out_dir "${_tmp_val}")
  endif(_tmp_val)

  get_target_property(_target_type "${TARGET}" TYPE)
  if(NOT _target_type)
    message(WARNING "No value for TYPE property of target ${TARGET}")
    unset(${RESULT_VAR} PARENT_SCOPE)
    return()
  elseif(_target_type STREQUAL "STATIC_LIBRARY")
    # Check ARCHIVE_OUTPUT_DIRECTORY property
    get_target_property(_tmp_val "${TARGET}" ARCHIVE_OUTPUT_DIRECTORY)
    if(_tmp_val)
      set(_target_out_dir "${_tmp_val}")
    endif(_tmp_val)
    # Check ARCHIVE_OUTPUT_DIRECTORY_<CONFIG> property
    get_target_property(_tmp_val "${TARGET}" "ARCHIVE_OUTPUT_DIRECTORY_${CMAKE_BUILD_TYPE}")
    if(_tmp_val)
      set(_target_out_dir "${_tmp_val}")
    endif(_tmp_val)
  elseif(_target_type STREQUAL "SHARED_LIBRARY")
    # Check LIBRARY_OUTPUT_DIRECTORY property
    get_target_property(_tmp_val "${TARGET}" LIBRARY_OUTPUT_DIRECTORY)
    if(_tmp_val)
      set(_target_out_dir "${_tmp_val}")
    endif(_tmp_val)
    # Check LIBRARY_OUTPUT_DIRECTORY_<CONFIG> property
    get_target_property(_tmp_val "${TARGET}" "LIBRARY_OUTPUT_DIRECTORY_${CMAKE_BUILD_TYPE}")
    if(_tmp_val)
      set(_target_out_dir "${_tmp_val}")
    endif(_tmp_val)
  elseif(_target_type STREQUAL "EXECUTABLE")
    # Check RUNTIME_OUTPUT_DIRECTORY property
    get_target_property(_tmp_val "${TARGET}" RUNTIME_OUTPUT_DIRECTORY)
    if(_tmp_val)
      set(_target_out_dir "${_tmp_val}")
    endif(_tmp_val)
    # Check RUNTIME_OUTPUT_DIRECTORY_<CONFIG> property
    get_target_property(_tmp_val "${TARGET}" "RUNTIME_OUTPUT_DIRECTORY_${CMAKE_BUILD_TYPE}")
    if(_tmp_val)
      set(_target_out_dir "${_tmp_val}")
    endif(_tmp_val)
  else()
    message(WARNING "Invalid value for TYPE property of target ${TARGET}: ${_target_type}")
    unset(${RESULT_VAR} PARENT_SCOPE)
    return()
  endif(NOT _target_type)
  set(${RESULT_VAR} "${_target_out_dir}" PARENT_SCOPE)
endfunction(get_target_output_directory)

function(get_target_archive_filename RESULT_VAR TARGET)
  get_target_archive_name(_target_out_name "${TARGET}")
  set(${RESULT_VAR} "${CMAKE_STATIC_LIBRARY_PREFIX}${_target_out_name}${CMAKE_STATIC_LIBRARY_SUFFIX}" PARENT_SCOPE)
endfunction(get_target_archive_filename)

function(get_target_output_filename RESULT_VAR TARGET)
  unset(_target_out_filename)
  get_target_output_name(_target_out_name "${TARGET}")
  get_target_property(_target_type "${TARGET}" TYPE)
  if(NOT _target_type)
    message(WARNING "No value for TYPE property of target ${TARGET}")
    unset(${RESULT_VAR} PARENT_SCOPE)
    return()
  elseif(_target_type STREQUAL "STATIC_LIBRARY")
    set(_target_out_filename "${CMAKE_STATIC_LIBRARY_PREFIX}${_target_out_name}${CMAKE_STATIC_LIBRARY_SUFFIX}")
  elseif(_target_type STREQUAL "SHARED_LIBRARY")
    set(_target_out_filename "${CMAKE_SHARED_LIBRARY_PREFIX}${_target_out_name}${CMAKE_SHARED_LIBRARY_SUFFIX}")
  elseif(_target_type STREQUAL "EXECUTABLE")
    set(_target_out_filename "${_target_out_name}${CMAKE_EXECUTABLE_SUFFIX}")
  else()
    message(WARNING "Invalid value for TYPE property of target ${TARGET}: ${_target_type}")
    unset(${RESULT_VAR} PARENT_SCOPE)
    return()
  endif(NOT _target_type)
  set(${RESULT_VAR} "${_target_out_filename}" PARENT_SCOPE)
endfunction(get_target_output_filename)

function(get_target_archive_fullpath RESULT_VAR TARGET)
  get_target_archive_directory(_target_out_dir "${TARGET}")
  get_target_archive_filename(_target_out_name "${TARGET}")
  if(_target_out_dir)
    set(${RESULT_VAR} "${_target_out_dir}/${_target_out_name}" PARENT_SCOPE)
  else()
    set(${RESULT_VAR} "${_target_out_name}" PARENT_SCOPE)
  endif(_target_out_dir)
endfunction(get_target_archive_fullpath)

function(get_target_output_fullpath RESULT_VAR TARGET)
  get_target_output_directory(_target_out_dir "${TARGET}")
  get_target_output_filename(_target_out_name "${TARGET}")
  if(_target_out_dir)
    set(${RESULT_VAR} "${_target_out_dir}/${_target_out_name}" PARENT_SCOPE)
  else()
    set(${RESULT_VAR} "${_target_out_name}" PARENT_SCOPE)
  endif(_target_out_dir)
endfunction(get_target_output_fullpath)
