# Copyright (c) 2007-2018 Hartmut Kaiser
# Copyright (c) 2011-2014 Thomas Heller
# Copyright (c) 2007-2008 Chirag Dekate
# Copyright (c)      2011 Bryce Lelbach
# Copyright (c)      2011 Vinay C Amatya
# Copyright (c)      2013 Jeroen Habraken
# Copyright (c) 2014-2016 Andreas Schaefer
# Copyright (c) 2017      Abhimanyu Rawat
# Copyright (c) 2017      Google
# Copyright (c) 2017      Taeguk Kwon
#
# Distributed under the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

# We require at least CMake V3.3.2
cmake_minimum_required(VERSION 3.3.2 FATAL_ERROR)

if (HPX_WITH_CUDA AND CMAKE_VERSION VERSION_LESS 3.9)
  message(FATAL_ERROR "CUDA support requires at least CMake 3.9.")
endif()

# Overrides must go before the project() statement, otherwise they are ignored.

################################################################################
# C++ overrides
################################################################################
set(CMAKE_USER_MAKE_RULES_OVERRIDE_CXX
    "${CMAKE_CURRENT_SOURCE_DIR}/cmake/HPX_CXXOverrides.cmake")

################################################################################
# Fortran overrides
################################################################################
set(CMAKE_USER_MAKE_RULES_OVERRIDE_Fortran
    "${CMAKE_CURRENT_SOURCE_DIR}/cmake/HPX_FortranOverrides.cmake")

################################################################################
# Build type (needs to be handled before project command below)
################################################################################
if(NOT CMAKE_BUILD_TYPE)
  set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Configuration type (one of Debug, RelWithDebInfo, Release, MinSizeRel)" FORCE)
endif()

################################################################################
# project metadata
################################################################################
project(HPX CXX C)

set(HPX_MAJOR_VERSION 1)
set(HPX_MINOR_VERSION 2)
set(HPX_PATCH_LEVEL   1)
set(HPX_VERSION "${HPX_MAJOR_VERSION}.${HPX_MINOR_VERSION}.${HPX_PATCH_LEVEL}")
set(HPX_LIBRARY_VERSION "${HPX_VERSION}")
set(HPX_SOVERSION ${HPX_MAJOR_VERSION})
set(HPX_PACKAGE_NAME HPX)

set_property(GLOBAL PROPERTY USE_FOLDERS ON)

################################################################################
# CMake configuration
################################################################################
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake")

include(GNUInstallDirs)
include(HPX_Utils)

# explicitly set certain policies
cmake_policy(VERSION 3.3.2)
hpx_set_cmake_policy(CMP0042 NEW)
if(${CMAKE_VERSION} VERSION_LESS "3.11.0")
  # the old behavior not supported for newer cmake versions anymore
  hpx_set_cmake_policy(CMP0054 OLD)
endif()
hpx_set_cmake_policy(CMP0060 NEW)

# We save the passed compiler flag to a special variable. This is needed for our
# build system unit tests. Some flags might influence the created symbols
# (_GLIBCXX_DEBUG i look at you)
set(CMAKE_CXX_FLAGS_SAFE ${CMAKE_CXX_FLAGS})

include(CheckCXXCompilerFlag)
include(CMakeDependentOption)

# include additional macro definitions
include(HPX_ExportTargets)
include(HPX_Libraries)
include(HPX_LibraryDir)
include(HPX_AddConfigTest)
include(HPX_AddDefinitions)
include(HPX_CreateSymbolicLink)

hpx_force_out_of_tree_build("This project requires an out-of-source-tree build. See README.rst. Clean your CMake cache and CMakeFiles if this message persists.")

if(NOT HPX_CMAKE_LOGLEVEL)
  set(HPX_CMAKE_LOGLEVEL "WARN")
endif()

# print initial diagnostics
hpx_info("CMake version: " ${CMAKE_VERSION})
hpx_info("HPX version: " ${HPX_VERSION})

################################################################################
# Fortran compiler detection
#
hpx_option(HPX_WITH_FORTRAN
  BOOL
  "Enable or disable the compilation of Fortran examples using HPX"
  OFF ADVANCED)

if (HPX_WITH_FORTRAN)
  include(HPX_FortranCompiler)
endif()

################################################################################

################################################################################
# Setup platform for which HPX should be compiled for.
#
include(HPX_SetPlatform)
if("${HPX_PLATFORM_UC}" STREQUAL "ANDROID")
  unset(HPX_LIBRARY_VERSION)
  unset(HPX_SOVERSION)
endif()

# Adjust a couple of build-system settings, if HPX is to be built using vcpkg
if(MSVC)
  set(_with_vcpkg_default OFF)
  if(VCPKG_TOOLCHAIN)
    set(_with_vcpkg_default ON)
  endif()
  hpx_option(HPX_WITH_VCPKG BOOL
    "Build HPX in the context of the vcpkg build and configuration tool (default: OFF)."
    ${_with_vcpkg_default} ADVANCED)
  if(HPX_WITH_VCPKG)
    hpx_add_config_define(HPX_HAVE_VCPKG)
  endif()

  hpx_option(HPX_WITH_VS_STARTUP_PROJECT STRING
    "Define the startup project for the HPX solution (default: ALL_BUILD)."
    "ALL_BUILD" ADVANCED)
  if(HPX_WITH_VS_STARTUP_PROJECT)
    set(VS_STARTUP_PROJECT ${HPX_WITH_VS_STARTUP_PROJECT})
  endif()
endif()

################################################################################

################################################################################
# Set our build options cache variables which are customizable by users
#

hpx_option(HPX_WITH_DEPRECATION_WARNINGS
  BOOL "Enable warnings for deprecated facilities. (default: ON)"
  ON ADVANCED)
if(HPX_WITH_DEPRECATION_WARNINGS)
  hpx_add_config_define(HPX_HAVE_DEPRECATION_WARNINGS)
endif()

## Generic build options
set(DEFAULT_MALLOC "system")
if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
  set(DEFAULT_MALLOC "tcmalloc")
#    set(DEFAULT_MALLOC "jemalloc")
endif()

if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
  set(HPX_WITH_STACKOVERFLOW_DETECTION_DEFAULT OFF)
  string(TOUPPER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE_UC)
  if("${CMAKE_BUILD_TYPE_UC}" STREQUAL "DEBUG")
    set(HPX_WITH_STACKOVERFLOW_DETECTION_DEFAULT ON)
  endif()
  hpx_option(HPX_WITH_STACKOVERFLOW_DETECTION
    BOOL
    "Enable stackoverflow detection for HPX threads/coroutines. (default: OFF, debug: ON)"
    ${HPX_WITH_STACKOVERFLOW_DETECTION_DEFAULT} ADVANCED)
  if(HPX_WITH_STACKOVERFLOW_DETECTION)
    hpx_add_config_define(HPX_HAVE_STACKOVERFLOW_DETECTION)
  endif()
endif()

hpx_option(HPX_WITH_MALLOC
  STRING
  "Define which allocator should be linked in. Options are: system, tcmalloc, jemalloc, tbbmalloc, and custom (default is: tcmalloc)"
  ${DEFAULT_MALLOC}
  STRINGS "system;tcmalloc;jemalloc;tbbmalloc;custom")

# On some systems jemalloc requires an explicit prefix for the API functions
# (i.e. 'malloc' is called 'je_malloc', etc.)
if(${HPX_WITH_MALLOC} STREQUAL "jemalloc")
  if(MSVC)
    set(HPX_WITH_JEMALLOC_PREFIX_DEFAULT "je_")
  else()
    set(HPX_WITH_JEMALLOC_PREFIX_DEFAULT "<none>")
  endif()
  hpx_option(HPX_WITH_JEMALLOC_PREFIX
    STRING
    "Optional naming prefix for jemalloc API functions"
    ${HPX_WITH_JEMALLOC_PREFIX_DEFAULT}
    ADVANCED)
endif()

# Logging configuration
hpx_option(HPX_WITH_LOGGING BOOL
  "Build HPX with logging enabled (default: ON)."
  ON ADVANCED)

hpx_option(HPX_WITH_FAULT_TOLERANCE BOOL
  "Build HPX to tolerate failures of nodes, i.e. ignore errors in active communication channels (default: OFF)"
  OFF ADVANCED)
if(HPX_WITH_FAULT_TOLERANCE)
  hpx_add_config_define(HPX_HAVE_FAULT_TOLERANCE)
endif()

if(HPX_WITH_LOGGING)
  hpx_add_config_define(HPX_HAVE_LOGGING)
endif()

## Compiler related build options
hpx_option(HPX_WITH_GCC_VERSION_CHECK BOOL
  "Don't ignore version reported by gcc (default: ON)"
  ON ADVANCED)

hpx_option(HPX_WITH_DEFAULT_TARGETS BOOL
  "Associate the core HPX library with the default build target (default: ON)."
  ON ADVANCED CATEGORY "Build Targets")

hpx_option(HPX_WITH_COMPILER_WARNINGS BOOL
  "Enable compiler warnings (default: ON)"
  ON ADVANCED)

hpx_option(HPX_WITH_EXECUTABLE_PREFIX STRING
	"Executable prefix (default none), 'hpx_' useful for system install."
  "" CATEGORY "Build Targets")

hpx_option(HPX_WITH_DOCUMENTATION BOOL
  "Build the HPX documentation (default OFF)."
  OFF CATEGORY "Build Targets")

if(MSVC)
  hpx_option(HPX_WITH_PSEUDO_DEPENDENCIES BOOL
    "Force creating pseudo targets and pseudo dependencies (default OFF)."
    OFF CATEGORY "Build Targets")
else()
  hpx_option(HPX_WITH_PSEUDO_DEPENDENCIES BOOL
    "Force creating pseudo targets and pseudo dependencies (default ON)."
    ON CATEGORY "Build Targets")
endif()

hpx_option(HPX_WITH_DYNAMIC_HPX_MAIN BOOL
  "Enable dynamic overload of system ``main()`` (Linux only, default: ON)"
  ON ADVANCED)
if(HPX_WITH_DYNAMIC_HPX_MAIN)
  hpx_add_config_cond_define(HPX_HAVE_DYNAMIC_HPX_MAIN 1)
endif()

################################################################################
# Some platforms do not support dynamic linking. Enable this to link all
# libraries statically. This also changes some of the internals of HPX related
# to how components are loaded.
################################################################################
hpx_option(HPX_WITH_STATIC_LINKING BOOL
  "Compile HPX statically linked libraries (Default: OFF)" OFF ADVANCED)
if(HPX_WITH_STATIC_LINKING)
  hpx_add_config_define(HPX_HAVE_STATIC_LINKING)
  set(hpx_library_link_mode STATIC)
  set(CMAKE_SHARED_LIBS OFF)
  set(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES})

  if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
    hpx_option(HPX_WITH_STATIC_EXE_LINKING BOOL
      "Compile HPX statically linked executables (Default: OFF)" OFF ADVANCED)

    if(HPX_WITH_STATIC_EXE_LINKING)
      set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static")
    endif()
  endif()
else()
  set(hpx_library_link_mode SHARED)
endif()

################################################################################

hpx_option(HPX_WITH_EXAMPLES BOOL "Build the HPX examples (default ON)" ON CATEGORY "Build Targets")
hpx_option(HPX_WITH_TESTS BOOL "Build the HPX tests (default ON)" ON CATEGORY "Build Targets")
hpx_option(HPX_WITH_TESTS_BENCHMARKS BOOL "Build HPX benchmark tests (default: ON)" ON ADVANCED CATEGORY "Build Targets")
hpx_option(HPX_WITH_TESTS_REGRESSIONS BOOL "Build HPX regression tests (default: ON)" ON ADVANCED CATEGORY "Build Targets")
hpx_option(HPX_WITH_TESTS_UNIT BOOL "Build HPX unit tests (default: ON)" ON ADVANCED CATEGORY "Build Targets")
hpx_option(HPX_WITH_TESTS_HEADERS BOOL "Build HPX header tests (default: OFF)" OFF ADVANCED CATEGORY "Build Targets")
hpx_option(HPX_WITH_TESTS_EXTERNAL_BUILD BOOL "Build external cmake build tests (default: ON)" ON ADVANCED CATEGORY "Build Targets")
hpx_option(HPX_WITH_TESTS_EXAMPLES BOOL "Add HPX examples as tests (default: ON)" ON ADVANCED CATEGORY "Build Targets")
hpx_option(HPX_WITH_TOOLS BOOL "Build HPX tools (default: OFF)" OFF ADVANCED CATEGORY "Build Targets")
hpx_option(HPX_WITH_RUNTIME BOOL "Build HPX runtime (default: ON)" ON ADVANCED CATEGORY "Build Targets")

hpx_option(HPX_WITH_COMPILE_ONLY_TESTS BOOL
  "Create build system support for compile time only HPX tests (default ON)"
  ON CATEGORY "Build Targets")
hpx_option(HPX_WITH_FAIL_COMPILE_TESTS BOOL
  "Create build system support for fail compile HPX tests (default ON)"
  ON CATEGORY "Build Targets")

# Enable IO-counters on linux systems only
set(HPX_WITH_IO_COUNTERS_DEFAULT OFF)
if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
  set(HPX_WITH_IO_COUNTERS_DEFAULT ON)
endif()

hpx_option(HPX_WITH_IO_COUNTERS BOOL
  "Build HPX runtime (default: ${HPX_WITH_IO_COUNTERS_DEFAULT})"
  ${HPX_WITH_IO_COUNTERS_DEFAULT} ADVANCED CATEGORY "Build Targets")
if(HPX_WITH_IO_COUNTERS)
  hpx_add_config_define(HPX_HAVE_IO_COUNTERS)
endif()

set(HPX_FULL_RPATH_DEFAULT ON)
if(APPLE OR WIN32)
  set(HPX_FULL_RPATH_DEFAULT OFF)
endif()
hpx_option(HPX_WITH_FULL_RPATH BOOL
  "Build and link HPX libraries and executables with full RPATHs (default: ${HPX_FULL_RPATH_DEFAULT})"
  ${HPX_FULL_RPATH_DEFAULT} ADVANCED)

################################################################################
# HPX Compute configuration
################################################################################
hpx_option(HPX_WITH_CUDA BOOL
  "Enable CUDA support (default: OFF)" OFF ADVANCED)
hpx_option(HPX_WITH_CUDA_CLANG BOOL
  "Use clang to compile CUDA code (default: OFF)" OFF ADVANCED)
if(HPX_WITH_CUDA)
  find_package(CUDA REQUIRED)
  set(HPX_WITH_COMPUTE On)
  hpx_add_config_define(HPX_HAVE_CUDA)
  hpx_add_config_define(HPX_HAVE_COMPUTE)
  if(NOT HPX_WITH_CUDA_ARCH)
    hpx_info("HPX_WITH_CUDA_ARCH has not been defined, default value is sm_20")
    set(HPX_WITH_CUDA_ARCH sm_20)
  endif()
  foreach(arch ${HPX_WITH_CUDA_ARCH})
    string(REGEX MATCHALL "sm_[0-9][0-9]" arch ${arch})
    if(NOT arch)
      hpx_error("Each architecture defined in HPX_WITH_CUDA_ARCH should be a list of items, each of the form sm_XX")
    endif()
    string(APPEND HPX_CUDA_CLANG_FLAGS " --cuda-gpu-arch=${arch}")
  endforeach()
  string(REGEX REPLACE ";" " " HPX_WITH_CUDA_ARCH_INFO "${HPX_WITH_CUDA_ARCH}")
  # keywords for target_link_libraries (cuda)
  set(CUDA_LINK_LIBRARIES_KEYWORD "PRIVATE")
endif()
# keywords for target_link_libraries (hpx)
set(HPX_TLL_PUBLIC "PUBLIC")
set(HPX_TLL_PRIVATE "PRIVATE")
if(HPX_WITH_CUDA_CLANG AND NOT (CMAKE_CXX_COMPILER_ID STREQUAL "Clang"))
  hpx_error("To use Cuda Clang, please select Clang as your default C++ compiler")
endif()
hpx_option(HPX_WITH_HCC BOOL
  "Enable hcc support (default: OFF)" OFF ADVANCED)
hpx_option(HPX_WITH_SYCL BOOL
  "Enable sycl support (default: OFF)" OFF ADVANCED)

################################################################################
# HPX datapar configuration
################################################################################
hpx_option(HPX_WITH_DATAPAR_VC BOOL
  "Enable data parallel algorithm support using the external Vc library (default: OFF)" OFF ADVANCED)
if(HPX_WITH_DATAPAR_VC)
  hpx_option(HPX_WITH_DATAPAR_VC_NO_LIBRARY BOOL
    "Don't link with the Vc static library (default: OFF)" OFF ADVANCED)
endif()
hpx_option(HPX_WITH_DATAPAR_BOOST_SIMD BOOL
  "Enable data parallel algorithm support using the external Boost.SIMD library (default: OFF)" OFF ADVANCED)

if(HPX_WITH_DATAPAR_VC AND HPX_WITH_DATAPAR_BOOST_SIMD)
  hpx_error("Please select only one of the supported external vectorization libraries (HPX_WITH_DATAPAR_VC or HPX_WITH_DATAPAR_BOOST_SIMD)")
endif()

if(HPX_WITH_DATAPAR_VC)
  include(HPX_SetupVc)
endif()
if(HPX_WITH_DATAPAR_BOOST_SIMD)
  include(HPX_SetupBoostSIMD)
endif()
if((NOT HPX_WITH_DATAPAR_VC) AND (NOT HPX_WITH_DATAPAR_BOOST_SIMD))
  hpx_info("No vectorization library configured")
else()
  set(HPX_WITH_DATAPAR ON)
endif()

################################################################################
# Native TLS configuration
################################################################################
set(HPX_WITH_NATIVE_TLS_DEFAULT ON)
if(APPLE)
  set(HPX_WITH_NATIVE_TLS_DEFAULT ${HPX_WITH_CXX11_THREAD_LOCAL})
endif()
hpx_option(HPX_WITH_NATIVE_TLS BOOL
  "Use native TLS support if available (default: ${HPX_WITH_NATIVE_TLS_DEFAULT})"
  ${HPX_WITH_NATIVE_TLS_DEFAULT} ADVANCED)
if(HPX_WITH_NATIVE_TLS)
  hpx_info("Native TLS is enabled.")
  hpx_add_config_define(HPX_HAVE_NATIVE_TLS)
else()
  hpx_info("Native TLS is disabled.")
endif()

################################################################################
# Threadlevel Nice option
################################################################################
hpx_option(HPX_WITH_NICE_THREADLEVEL BOOL
  "Set HPX worker threads to have high NICE level (may impact performance) (default: OFF)"
  OFF ADVANCED)
if(HPX_WITH_NICE_THREADLEVEL)
  hpx_info("Nice threadlevel is enabled.")
  hpx_add_config_define(HPX_HAVE_NICE_THREADLEVEL)
else()
  hpx_info("Nice threadlevel is disabled.")
endif()

################################################################################
# Utility configuration
################################################################################
set(HPX_HIDDEN_VISIBILITY_DEFAULT ON)
if(CMAKE_COMPILER_IS_GNUCXX)
  if("${HPX_PLATFORM_UC}" STREQUAL "ANDROID")
    set(HPX_HIDDEN_VISIBILITY_DEFAULT OFF)
  endif()
endif()
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
  set(HPX_HIDDEN_VISIBILITY_DEFAULT OFF)
endif()
if(APPLE)
  set(HPX_HIDDEN_VISIBILITY_DEFAULT OFF)
endif()

hpx_option(HPX_WITH_HIDDEN_VISIBILITY BOOL
  "Use -fvisibility=hidden for builds on platforms which support it (default ${HPX_HIDDEN_VISIBILITY_DEFAULT})"
  ${HPX_HIDDEN_VISIBILITY_DEFAULT}
  ADVANCED)

hpx_option(HPX_WITH_AUTOMATIC_SERIALIZATION_REGISTRATION BOOL
  "Use automatic serialization registration for actions and functions. This affects compatibility between HPX applications compiled with different compilers (default ON)"
  ON
  ADVANCED)
if(HPX_WITH_AUTOMATIC_SERIALIZATION_REGISTRATION)
  hpx_add_config_define(HPX_HAVE_AUTOMATIC_SERIALIZATION_REGISTRATION)
endif()

hpx_option(HPX_WITH_ZERO_COPY_SERIALIZATION_THRESHOLD STRING
  "The threshhold in bytes to when perform zero copy optimizations (default: 128)"
  "128"
  ADVANCED)
hpx_add_config_define(HPX_ZERO_COPY_SERIALIZATION_THRESHOLD ${HPX_WITH_ZERO_COPY_SERIALIZATION_THRESHOLD})

hpx_option(HPX_WITH_DISABLED_SIGNAL_EXCEPTION_HANDLERS BOOL
  "Disables the mechanism that produces debug output for caught signals and unhandled exceptions (default: OFF)"
  OFF
  ADVANCED)
if(HPX_WITH_DISABLED_SIGNAL_EXCEPTION_HANDLERS)
  hpx_add_config_define(HPX_HAVE_DISABLED_SIGNAL_EXCEPTION_HANDLERS)
endif()

## Thread Manager related build options

set(HPX_MAX_CPU_COUNT_DEFAULT "64")
hpx_option(HPX_WITH_MAX_CPU_COUNT STRING
  "HPX applications will not use more that this number of OS-Threads (default: ${HPX_MAX_CPU_COUNT_DEFAULT})"
  ${HPX_MAX_CPU_COUNT_DEFAULT}
  CATEGORY "Thread Manager" ADVANCED)
hpx_add_config_define(HPX_HAVE_MAX_CPU_COUNT ${HPX_WITH_MAX_CPU_COUNT})

set(HPX_MAX_NUMA_DOMAIN_COUNT_DEFAULT "4")
hpx_option(HPX_WITH_MAX_NUMA_DOMAIN_COUNT STRING
  "HPX applications will not run on machines with more NUMA domains (default: ${HPX_MAX_NUMA_DOMAIN_COUNT_DEFAULT})"
  ${HPX_MAX_NUMA_DOMAIN_COUNT_DEFAULT}
  CATEGORY "Thread Manager" ADVANCED)
hpx_add_config_define(HPX_HAVE_MAX_NUMA_DOMAIN_COUNT ${HPX_WITH_MAX_NUMA_DOMAIN_COUNT})

set(HPX_MORE_THAN_64_THREADS_DEFAULT OFF)
if(HPX_WITH_MAX_CPU_COUNT GREATER 64)
  set(HPX_MORE_THAN_64_THREADS_DEFAULT ON)
endif()
hpx_option(HPX_WITH_MORE_THAN_64_THREADS BOOL
  "HPX applications will be able to run on more than 64 cores (default: ${HPX_MORE_THAN_64_THREADS_DEFAULT})"
  ${HPX_MORE_THAN_64_THREADS_DEFAULT}
  CATEGORY "Thread Manager" ADVANCED)
if(HPX_WITH_MORE_THAN_64_THREADS)
  hpx_add_config_define(HPX_HAVE_MORE_THAN_64_THREADS)
endif()

hpx_option(HPX_WITH_THREAD_STACK_MMAP BOOL
  "Use mmap for stack allocation on appropriate platforms"
  ON
  CATEGORY "Thread Manager" ADVANCED)

hpx_option(HPX_WITH_THREAD_MANAGER_IDLE_BACKOFF BOOL
  "HPX scheduler threads do exponential backoff on idle queues (default: ON)"
  ON
  CATEGORY "Thread Manager" ADVANCED)

hpx_option(HPX_WITH_STACKTRACES BOOL
  "Attach backtraces to HPX exceptions (default: ON)"
  ON
  CATEGORY "Thread Manager" ADVANCED)

hpx_option(HPX_WITH_THREAD_BACKTRACE_ON_SUSPENSION BOOL
  "Enable thread stack back trace being captured on suspension (default: OFF)"
  OFF
  CATEGORY "Thread Manager" ADVANCED)

if(HPX_WITH_STACKTRACES OR HPX_WITH_THREAD_BACKTRACE_ON_SUSPENSION)
  hpx_info("Stack traces are enabled.")
  hpx_add_config_define(HPX_HAVE_STACKTRACES)
  if(WIN32)
    hpx_libraries(dbghelp)
  endif()

  hpx_option(HPX_WITH_THREAD_BACKTRACE_DEPTH STRING
    "Thread stack back trace depth being captured (default: 5)"
    "5"
    CATEGORY "Thread Manager" ADVANCED)
  hpx_add_config_define(HPX_HAVE_THREAD_BACKTRACE_DEPTH
    ${HPX_WITH_THREAD_BACKTRACE_DEPTH})
endif()

if(HPX_WITH_THREAD_BACKTRACE_ON_SUSPENSION)
  hpx_add_config_define(HPX_HAVE_THREAD_BACKTRACE_ON_SUSPENSION)

  hpx_option(HPX_WITH_THREAD_FULLBACKTRACE_ON_SUSPENSION BOOL
    "Enable thread stack back trace being captured on suspension (default: OFF)"
    OFF
    CATEGORY "Thread Manager" ADVANCED)
  if(HPX_WITH_THREAD_FULLBACKTRACE_ON_SUSPENSION)
    hpx_add_config_define(HPX_HAVE_THREAD_FULLBACKTRACE_ON_SUSPENSION)
  endif()
endif()

hpx_option(HPX_WITH_THREAD_TARGET_ADDRESS BOOL
  "Enable storing target address in thread for NUMA awareness (default: OFF)"
  OFF CATEGORY "Thread Manager" ADVANCED)

if(HPX_WITH_THREAD_TARGET_ADDRESS)
  hpx_add_config_define(HPX_HAVE_THREAD_TARGET_ADDRESS)
endif()

hpx_option(HPX_WITH_THREAD_QUEUE_WAITTIME BOOL
  "Enable collecting queue wait times for threads (default: OFF)"
  OFF CATEGORY "Thread Manager" ADVANCED)

if(HPX_WITH_THREAD_QUEUE_WAITTIME)
  hpx_add_config_define(HPX_HAVE_THREAD_QUEUE_WAITTIME)
endif()

hpx_option(HPX_WITH_THREAD_IDLE_RATES BOOL
  "Enable measuring the percentage of overhead times spent in the scheduler (default: OFF)"
  OFF CATEGORY "Thread Manager" ADVANCED)

hpx_option(HPX_WITH_THREAD_CREATION_AND_CLEANUP_RATES BOOL
  "Enable measuring thread creation and cleanup times (default: OFF)"
  OFF CATEGORY "Thread Manager" ADVANCED)

if(HPX_WITH_THREAD_IDLE_RATES)
  hpx_add_config_define(HPX_HAVE_THREAD_IDLE_RATES)
  if(HPX_WITH_THREAD_CREATION_AND_CLEANUP_RATES)
    hpx_add_config_define(HPX_HAVE_THREAD_CREATION_AND_CLEANUP_RATES)
  endif()
endif()

hpx_option(HPX_WITH_THREAD_CUMULATIVE_COUNTS BOOL
  "Enable keeping track of cumulative thread counts in the schedulers (default: ON)"
  ON CATEGORY "Thread Manager" ADVANCED)

if(HPX_WITH_THREAD_CUMULATIVE_COUNTS)
  hpx_add_config_define(HPX_HAVE_THREAD_CUMULATIVE_COUNTS)
endif()

hpx_option(HPX_WITH_THREAD_STEALING_COUNTS BOOL
  "Enable keeping track of counts of thread stealing incidents in the schedulers (default: ON)"
  ON CATEGORY "Thread Manager" ADVANCED)

if(HPX_WITH_THREAD_STEALING_COUNTS)
  hpx_add_config_define(HPX_HAVE_THREAD_STEALING_COUNTS)
endif()

hpx_option(HPX_WITH_THREAD_LOCAL_STORAGE BOOL
  "Enable thread local storage for all HPX threads (default: OFF)"
  OFF CATEGORY "Thread Manager" ADVANCED)

if(HPX_WITH_THREAD_LOCAL_STORAGE)
  hpx_add_config_define(HPX_HAVE_THREAD_LOCAL_STORAGE)
endif()

hpx_option(HPX_WITH_SCHEDULER_LOCAL_STORAGE BOOL
  "Enable scheduler local storage for all HPX schedulers (default: OFF)"
  OFF CATEGORY "Thread Manager" ADVANCED)

if(HPX_WITH_SCHEDULER_LOCAL_STORAGE)
  hpx_add_config_define(HPX_HAVE_SCHEDULER_LOCAL_STORAGE)
endif()

# Count number of terminated threads before forcefully cleaning up all of
# them. Note: terminated threads are cleaned up either when this number is
# reached for a particular thread queue or if the HPX_BUSY_LOOP_COUNT_MAX is
# reached, which will clean up the terminated threads for _all_ thread queues.
hpx_option(HPX_SCHEDULER_MAX_TERMINATED_THREADS STRING
  "Maximum number of terminated threads collected before those are cleaned up (default: 100)"
  "100" CATEGORY "Thread Manager" ADVANCED)

hpx_add_config_define(HPX_SCHEDULER_MAX_TERMINATED_THREADS
  ${HPX_SCHEDULER_MAX_TERMINATED_THREADS})

hpx_option(HPX_WITH_SWAP_CONTEXT_EMULATION BOOL
  "Emulate SwapContext API for coroutines (default: OFF)"
  OFF CATEGORY "Thread Manager" ADVANCED)

hpx_option(HPX_WITH_SPINLOCK_DEADLOCK_DETECTION BOOL
  "Enable spinlock deadlock detection (default: OFF)"
  OFF CATEGORY "Thread Manager" ADVANCED)

if(HPX_WITH_SPINLOCK_DEADLOCK_DETECTION)
  hpx_add_config_define(HPX_HAVE_SPINLOCK_DEADLOCK_DETECTION)
endif()

## Profiling related build options
hpx_option(HPX_WITH_APEX BOOL
  "Enable APEX instrumentation support." OFF CATEGORY "Profiling")
if(HPX_WITH_APEX)
  hpx_add_config_define(HPX_HAVE_APEX)   # tell HPX that we use APEX
  hpx_option(HPX_WITH_APEX_NO_UPDATE BOOL
    "Do not update code from remote APEX repository." OFF CATEGORY "Profiling")
  hpx_option(HPX_WITH_APEX_TAG STRING
    "APEX repository tag or branch" "v2.0.1" CATEGORY "Profiling")
endif()
hpx_option(HPX_WITH_PAPI BOOL
  "Enable the PAPI based performance counter." OFF CATEGORY "Profiling")
if(HPX_WITH_PAPI)
  hpx_add_config_define(HPX_HAVE_PAPI)
endif()
hpx_option(HPX_WITH_GOOGLE_PERFTOOLS BOOL
  "Enable Google Perftools instrumentation support." OFF CATEGORY "Profiling")
if(HPX_WITH_GOOGLE_PERFTOOLS)
  hpx_add_config_define(HPX_HAVE_GOOGLE_PERFTOOLS)
endif()

hpx_option(HPX_WITH_ITTNOTIFY BOOL
  "Enable Amplifier (ITT) instrumentation support." OFF CATEGORY "Profiling")
################################################################################
# enable OpenMP emulation
################################################################################
hpx_option(HPX_WITH_HPXMP BOOL
  "Enable hpxMP OpenMP emulation." OFF CATEGORY "OpenMP")
if(HPX_WITH_HPXMP)
  if(NOT MSVC AND (("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
	OR ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")))
    hpx_option(HPX_WITH_HPXMP_NO_UPDATE BOOL
      "Do not update code from remote hpxMP repository." OFF CATEGORY "OpenMP")
  else()
    hpx_warn("hpxMP can be used only when compiling with clang or gcc")
    set(HPX_WITH_HPXMP OFF)
  endif()
endif()

################################################################################
# Scheduler configuration
################################################################################
hpx_option(HPX_WITH_THREAD_SCHEDULERS STRING
  "Which thread schedulers are built. Options are: all, abp-priority, local, static-priority, static, shared-priority. For multiple enabled schedulers, separate with a semicolon (default: all)"
  "all"
  CATEGORY "Thread Manager" ADVANCED)

string(TOUPPER ${HPX_WITH_THREAD_SCHEDULERS} HPX_WITH_THREAD_SCHEDULERS_UC)
foreach(_scheduler ${HPX_WITH_THREAD_SCHEDULERS_UC})
  if(_scheduler STREQUAL "ALL")
    set(_all On)
    set(HPX_WITH_ALL_SCHEDULERS ON CACHE INTERNAL "")
  endif()
  if(_scheduler STREQUAL "ABP-PRIORITY" OR _all)
    hpx_add_config_define(HPX_HAVE_ABP_SCHEDULER)
    set(HPX_WITH_ABP_SCHEDULER ON CACHE INTERNAL "")
  endif()
  if(_scheduler STREQUAL "LOCAL" OR _all)
    hpx_add_config_define(HPX_HAVE_LOCAL_SCHEDULER)
    set(HPX_WITH_LOCAL_SCHEDULER ON CACHE INTERNAL "")
  endif()
  if(_scheduler STREQUAL "STATIC-PRIORITY" OR _all)
    hpx_add_config_define(HPX_HAVE_STATIC_PRIORITY_SCHEDULER)
    set(HPX_WITH_STATIC_PRIORITY_SCHEDULER ON CACHE INTERNAL "")
  endif()
  if(_scheduler STREQUAL "STATIC" OR _all)
    hpx_add_config_define(HPX_HAVE_STATIC_SCHEDULER)
    set(HPX_WITH_STATIC_SCHEDULER ON CACHE INTERNAL "")
  endif()
  if(_scheduler STREQUAL "SHARED-PRIORITY" OR _all)
    hpx_add_config_define(HPX_HAVE_SHARED_PRIORITY_SCHEDULER)
    set(HPX_WITH_SHARED_PRIORITY_SCHEDULER ON CACHE INTERNAL "")
  endif()
  unset(_all)
endforeach()

## Experimental settings
hpx_option(HPX_WITH_IO_POOL BOOL
  "Disable internal IO thread pool, do not change if not absolutely necessary (default: ON)"
  ON CATEGORY "Thread Manager" ADVANCED)
if(HPX_WITH_IO_POOL)
  hpx_add_config_define(HPX_HAVE_IO_POOL)
endif()

hpx_option(HPX_WITH_TIMER_POOL BOOL
  "Disable internal timer thread pool, do not change if not absolutely necessary (default: ON)"
  ON CATEGORY "Thread Manager" ADVANCED)
if(HPX_WITH_TIMER_POOL)
  hpx_add_config_define(HPX_HAVE_TIMER_POOL)
endif()

## AGAS related build options
hpx_option(HPX_WITH_AGAS_DUMP_REFCNT_ENTRIES BOOL
  "Enable dumps of the AGAS refcnt tables to logs (default: OFF)"
  OFF CATEGORY "AGAS" ADVANCED)
if(HPX_WITH_AGAS_DUMP_REFCNT_ENTRIES)
  hpx_add_config_define(HPX_HAVE_AGAS_DUMP_REFCNT_ENTRIES)
endif()

# Should networking be supported?
hpx_option(HPX_WITH_NETWORKING BOOL
  "Enable support for networking and multi-node runs (default: ON)"
  ON CATEGORY "Parcelport")
if(HPX_WITH_NETWORKING)
  hpx_add_config_define(HPX_HAVE_NETWORKING)

  ## Parcelport related build options
  set(_parcel_profiling_default OFF)
  if(HPX_WITH_APEX)
    set(_parcel_profiling_default ON)
  endif()

  hpx_option(HPX_WITH_PARCEL_PROFILING BOOL
    "Enable profiling data for parcels"
    ${_parcel_profiling_default} CATEGORY "Parcelport" ADVANCED)

  if(HPX_WITH_PARCEL_PROFILING)
    hpx_add_config_define(HPX_HAVE_PARCEL_PROFILING)
  endif()

  ## Parcelport related build options
  hpx_option(HPX_WITH_PARCELPORT_LIBFABRIC BOOL
    "Enable the libfabric based parcelport. This is currently an experimental feature"
    OFF CATEGORY "Parcelport" ADVANCED)
  hpx_option(HPX_WITH_PARCELPORT_VERBS BOOL
    "Enable the ibverbs based parcelport. This is currently an experimental feature"
    OFF CATEGORY "Parcelport" ADVANCED)
  hpx_option(HPX_WITH_PARCELPORT_MPI BOOL
    "Enable the MPI based parcelport."
    OFF CATEGORY "Parcelport")
  hpx_option(HPX_WITH_PARCELPORT_TCP BOOL
    "Enable the TCP based parcelport."
    ON CATEGORY "Parcelport")
  hpx_option(HPX_WITH_PARCELPORT_ACTION_COUNTERS BOOL
    "Enable performance counters reporting parcelport statistics on a per-action basis."
    OFF CATEGORY "Parcelport")
  if(HPX_WITH_PARCELPORT_ACTION_COUNTERS)
    hpx_add_config_define(HPX_HAVE_PARCELPORT_ACTION_COUNTERS)
  endif()

  ## mpi parcelport settings
  hpx_option(HPX_WITH_PARCELPORT_MPI_ENV STRING
    "List of environment variables checked to detect MPI (default: MV2_COMM_WORLD_RANK;PMI_RANK;OMPI_COMM_WORLD_SIZE;ALPS_APP_PE)."
    "MV2_COMM_WORLD_RANK;PMI_RANK;OMPI_COMM_WORLD_SIZE;ALPS_APP_PE" CATEGORY "Parcelport" ADVANCED)
  hpx_option(HPX_WITH_PARCELPORT_MPI_MULTITHREADED BOOL
    "Turn on MPI multithreading support (default: ON)."
    ON CATEGORY "Parcelport" ADVANCED)
endif()

## External libraries/frameworks used by sme of the examples and benchmarks
hpx_option(HPX_WITH_EXAMPLES_OPENMP BOOL
  "Enable examples requiring OpenMP support (default: OFF)." OFF
  CATEGORY "Build Targets" ADVANCED)
if(HPX_WITH_EXAMPLES_OPENMP)
  find_package(OpenMP)
  if(NOT OPENMP_FOUND)
    set(HPX_WITH_EXAMPLES_OPENMP OFF)
  endif()
endif()
hpx_option(HPX_WITH_EXAMPLES_TBB BOOL
  "Enable examples requiring TBB support (default: OFF)." OFF
  CATEGORY "Build Targets" ADVANCED)
if(HPX_WITH_EXAMPLES_TBB)
  find_package(TBB)
  if(NOT TBB_FOUND)
    set(HPX_WITH_EXAMPLES_TBB OFF)
  endif()
endif()
hpx_option(HPX_WITH_EXAMPLES_QTHREADS BOOL
  "Enable examples requiring QThreads support (default: OFF)." OFF
  CATEGORY "Build Targets" ADVANCED)
if(HPX_WITH_EXAMPLES_QTHREADS)
  find_package(QThreads)
  if(NOT QTHREADS_FOUND)
    set(HPX_WITH_EXAMPLES_QTHREADS OFF)
  endif()
endif()
hpx_option(HPX_WITH_EXAMPLES_HDF5 BOOL
  "Enable examples requiring HDF5 support (default: OFF)." OFF
  CATEGORY "Build Targets" ADVANCED)
if(HPX_WITH_EXAMPLES_HDF5)
  find_package(HDF5 COMPONENTS CXX)
  if(NOT HDF5_FOUND)
    set(HPX_WITH_EXAMPLES_HDF5 OFF)
  endif()
endif()

# Disabling the Qt example on BG/Q as GUIs don't make sense there anyways
if(NOT "${HPX_PLATFORM_UC}" STREQUAL "BLUEGENEQ")
  hpx_option(HPX_WITH_EXAMPLES_QT4 BOOL
    "Enable examples requiring Qt4 support (default: OFF)." OFF
    CATEGORY "Build Targets" ADVANCED)
  if(HPX_WITH_EXAMPLES_QT4)
    find_package(Qt4)
    if(NOT QT4_FOUND)
      set(HPX_WITH_EXAMPLES_QT4 OFF)
    endif()
  endif()
endif()

## Debugging related build options
hpx_option(HPX_WITH_VALGRIND BOOL "Enable Valgrind instrumentation support."
  OFF CATEGORY "Debugging")

hpx_option(HPX_WITH_VERIFY_LOCKS BOOL
  "Enable lock verification code (default: OFF, implicitly enabled in debug builds)"
  OFF
  CATEGORY "Debugging" ADVANCED)
hpx_option(HPX_WITH_VERIFY_LOCKS_GLOBALLY BOOL
  "Enable global lock verification code (default: OFF, implicitly enabled in debug builds)"
  OFF
  CATEGORY "Debugging" ADVANCED)
hpx_option(HPX_WITH_VERIFY_LOCKS_BACKTRACE BOOL
  "Enable thread stack back trace being captured on lock registration (to be used in combination with HPX_WITH_VERIFY_LOCKS=ON, default: OFF)"
  OFF
  CATEGORY "Debugging" ADVANCED)
hpx_option(HPX_WITH_THREAD_DEBUG_INFO BOOL
  "Enable thread debugging information (default: OFF, implicitly enabled in debug builds)"
  OFF
  CATEGORY "Debugging" ADVANCED)
hpx_option(HPX_WITH_THREAD_GUARD_PAGE BOOL
  "Enable thread guard page (default: ON)"
  ON
  CATEGORY "Debugging" ADVANCED)

if(HPX_WITH_VERIFY_LOCKS)
  hpx_add_config_define(HPX_HAVE_VERIFY_LOCKS)
  if(HPX_WITH_VERIFY_LOCKS_BACKTRACE)
    hpx_add_config_define(HPX_HAVE_VERIFY_LOCKS_BACKTRACE)
  endif()
endif()
if(HPX_WITH_VERIFY_LOCKS_GLOBALLY)
  hpx_add_config_define(HPX_HAVE_VERIFY_LOCKS_GLOBALLY)
endif()

# Additional debug support
if(NOT WIN32 AND HPX_WITH_THREAD_GUARD_PAGE)
  hpx_add_config_define(HPX_HAVE_THREAD_GUARD_PAGE)
endif()

if(NOT WIN32 AND HPX_WITH_THREAD_STACK_MMAP)
  hpx_add_config_define(HPX_HAVE_THREAD_STACK_MMAP)
endif()

if(HPX_WITH_THREAD_MANAGER_IDLE_BACKOFF)
  hpx_add_config_define(HPX_HAVE_THREAD_MANAGER_IDLE_BACKOFF)
endif()

hpx_option(HPX_WITH_THREAD_DESCRIPTION_FULL BOOL
  "Use function address for thread description (default: OFF)"
  OFF
  CATEGORY "Debugging" ADVANCED)

hpx_option(HPX_WITH_ATTACH_DEBUGGER_ON_TEST_FAILURE BOOL
  "Break the debugger if a test has failed  (default: OFF)"
  OFF
  CATEGORY "Debugging" ADVANCED)
if(HPX_WITH_ATTACH_DEBUGGER_ON_TEST_FAILURE)
  hpx_add_config_define(HPX_HAVE_ATTACH_DEBUGGER_ON_TEST_FAILURE)
endif()

# If APEX is defined, the action timers need thread debug info.
if(HPX_WITH_APEX)
    hpx_add_config_define(HPX_HAVE_THREAD_DESCRIPTION)
    if(HPX_WITH_THREAD_DESCRIPTION_FULL)
      hpx_add_config_define(HPX_HAVE_THREAD_DESCRIPTION_FULL)
    endif()
endif()

if(HPX_WITH_THREAD_DEBUG_INFO)
  hpx_add_config_define(HPX_HAVE_THREAD_PARENT_REFERENCE)
  hpx_add_config_define(HPX_HAVE_THREAD_PHASE_INFORMATION)
  hpx_add_config_define(HPX_HAVE_THREAD_DESCRIPTION)
  hpx_add_config_define(HPX_HAVE_THREAD_DEADLOCK_DETECTION)
  if(HPX_WITH_THREAD_DESCRIPTION_FULL)
    hpx_add_config_define(HPX_HAVE_THREAD_DESCRIPTION_FULL)
  endif()
endif()

# run hpx_main on all localities by default
hpx_option(HPX_WITH_RUN_MAIN_EVERYWHERE BOOL "Run hpx_main by default on all localities (default: OFF)." OFF ADVANCED)
if(HPX_WITH_RUN_MAIN_EVERYWHERE)
  hpx_add_config_define(HPX_HAVE_RUN_MAIN_EVERYWHERE)
endif()

if(HPX_WITH_NETWORKING)
  # Options for our plugins
  hpx_option(HPX_WITH_COMPRESSION_BZIP2 BOOL
    "Enable bzip2 compression for parcel data (default: OFF)." OFF ADVANCED)
  hpx_option(HPX_WITH_COMPRESSION_SNAPPY BOOL
    "Enable snappy compression for parcel data (default: OFF)." OFF ADVANCED)
  hpx_option(HPX_WITH_COMPRESSION_ZLIB BOOL
    "Enable zlib compression for parcel data (default: OFF)." OFF ADVANCED)

  # Parcel coalescing is used by the main HPX library, enable it always
  hpx_option(HPX_WITH_PARCEL_COALESCING BOOL
    "Enable the parcel coalescing plugin (default: ON)." ON ADVANCED)
  if(HPX_WITH_PARCEL_COALESCING)
    hpx_add_config_define(HPX_HAVE_PARCEL_COALESCING)
    # Adaptive parcel coalescing related metrics counters are enabled only if both
    # parcel coalescing plugin and thread idle rate counters are enabled.
      if(HPX_WITH_THREAD_IDLE_RATES)
        hpx_option(HPX_WITH_BACKGROUND_THREAD_COUNTERS BOOL
           "Enable performance counters related to adaptive parcel coalescing (default: OFF)." OFF ADVANCED)
        if(HPX_WITH_BACKGROUND_THREAD_COUNTERS)
          hpx_add_config_define(HPX_HAVE_BACKGROUND_THREAD_COUNTERS)
        endif()
       endif()
  endif()
endif()

# Developer tools
hpx_option(HPX_WITH_VIM_YCM BOOL
  "Generate HPX completion file for VIM YouCompleteMe plugin"
  OFF ADVANCED)

################################################################################
# Backwards compatibility options (edit for each release)

# HPX_WITH_QUEUE_COMPATIBILITY: introduced in V1.1.0
hpx_option(HPX_WITH_QUEUE_COMPATIBILITY BOOL
    "Enable old style queue components in API (default: OFF)"
    OFF ADVANCED)
if(HPX_WITH_QUEUE_COMPATIBILITY)
  hpx_add_config_define(HPX_HAVE_QUEUE_COMPATIBILITY)
endif()

# HPX_WITH_SCOPED_UNLOCK_COMPATIBILITY: introduced in V1.1.0
hpx_option(HPX_WITH_SCOPED_UNLOCK_COMPATIBILITY BOOL
    "Enable backwards compatibility for scoped_unlock utility (default: OFF)"
    OFF ADVANCED)
if(HPX_WITH_SCOPED_UNLOCK_COMPATIBILITY)
  hpx_add_config_define(HPX_HAVE_SCOPED_UNLOCK_COMPATIBILITY)
endif()

# BADBAD: This enables an overload of swap which is necessary to work around the
#         problems caused by zip_iterator not being a real random access iterator.
#         Dereferencing zip_iterator does not yield a true reference but
#         only a temporary tuple holding true references.
#
# A real fix for this problem is proposed in PR0022R0
# (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0022r0.html)
#
hpx_option(HPX_WITH_TUPLE_RVALUE_SWAP BOOL
  "Enable swapping of rvalue tuples (needed for parallel::sort_by_key, default: ON)."
  ON CATEGORY "Utility" ADVANCED)
if(HPX_WITH_TUPLE_RVALUE_SWAP)
  hpx_add_config_define(HPX_HAVE_TUPLE_RVALUE_SWAP)
endif()

# HPX_WITH_INCLUSIVE_SCAN_COMPATIBILITY: introduced in V1.1.0
hpx_option(HPX_WITH_INCLUSIVE_SCAN_COMPATIBILITY BOOL
    "Enable old overloads for inclusive_scan (default: ON)"
    ON ADVANCED)
if(HPX_WITH_INCLUSIVE_SCAN_COMPATIBILITY)
  hpx_add_config_define(HPX_HAVE_INCLUSIVE_SCAN_COMPATIBILITY)
endif()

# HPX_WITH_ALGORITHM_INPUT_ITERATOR_SUPPORT: introduced in V1.1.0
hpx_option(HPX_WITH_ALGORITHM_INPUT_ITERATOR_SUPPORT BOOL
    "Enable weaker (non-conforming) iterator requirements for parallel algorithms (default: OFF)"
    OFF ADVANCED)
if(HPX_WITH_ALGORITHM_INPUT_ITERATOR_SUPPORT)
  hpx_add_config_define(HPX_HAVE_ALGORITHM_INPUT_ITERATOR_SUPPORT)
endif()

# HPX_WITH_UNWRAPPED_COMPATIBILITY: introduced in V1.1.0
hpx_option(HPX_WITH_UNWRAPPED_COMPATIBILITY BOOL
    "Enable the deprecated unwrapped function (default: ON)"
    ON ADVANCED)
if(HPX_WITH_UNWRAPPED_COMPATIBILITY)
  hpx_add_config_define(HPX_HAVE_UNWRAPPED_COMPATIBILITY)
endif()

################################################################################
# Set basic search paths for HPX
################################################################################
include_directories("${PROJECT_SOURCE_DIR}")
link_directories(${CMAKE_BINARY_DIR}/lib)

################################################################################
# Check for compiler compatibility
#

# Check if the selected compiler versions are supposed to work with our codebase
if(CMAKE_COMPILER_IS_GNUCXX AND HPX_WITH_GCC_VERSION_CHECK)
  if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9)
    hpx_error("GCC 4.9 or higher is required. Specify HPX_GCC_VERSION_CHECK=OFF to ignore this error.")
  endif()
endif()

if(MSVC)
  if(NOT (MSVC14))
    hpx_error("MSVC x64 2015 or higher is required.")
  elseif(NOT CMAKE_CL_64)
    hpx_warn("MSVC (32Bit) will compile but will fail running larger applications because of limitations in the Windows OS.")
  endif()
endif()

# Setup platform specific compiler options and check for compatible compilers
if("${HPX_PLATFORM_UC}" STREQUAL "NATIVE")
  hpx_info("Compiling with the native toolset")
elseif("${HPX_PLATFORM_UC}" STREQUAL "ANDROID")
  hpx_info("Compiling for Android devices")
elseif("${HPX_PLATFORM_UC}" STREQUAL "XEONPHI")
  hpx_info("Compiling for Intel Xeon Phi devices")
  if(NOT ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel"))
    hpx_error("HPX on the MIC can only be compiled with the Intel compiler.")
  endif()
elseif("${HPX_PLATFORM_UC}" STREQUAL "BLUEGENEQ")
  if(NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
    hpx_error("HPX on the BG/Q can only be compiled with bgclang")
  endif()
  hpx_info("Compiling for BlueGene/Q")
endif()

if((MSVC14 AND CMAKE_CL_64) OR ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang"))
  hpx_option(HPX_WITH_AWAIT BOOL
      "Enable the use of experimental co_await functionality"
      OFF ADVANCED CATEGORY "LCOs")
  if(HPX_WITH_AWAIT)
    hpx_add_config_define(HPX_HAVE_AWAIT)

    hpx_option(HPX_WITH_EMULATE_COROUTINE_SUPPORT_LIBRARY BOOL
        "Use hpx/util/await_traits.hpp instead of <experimental/coroutine>"
        OFF ADVANCED CATEGORY "LCOs")

    if(HPX_WITH_EMULATE_COROUTINE_SUPPORT_LIBRARY)
      hpx_add_config_define(HPX_HAVE_EMULATE_COROUTINE_SUPPORT_LIBRARY)
    endif()

    if(MSVC14 AND CMAKE_CL_64)
      hpx_add_target_compile_option(-await PUBLIC)
    endif()

    if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
      hpx_add_target_compile_option(-Xclang -fcoroutines-ts PUBLIC)
    endif()
  endif()
endif()

################################################################################

################################################################################
# Add necessary compiler flags. Flags added here include flags to disable/enable
# certain warnings, enabling C++11 mode and disabling asserts. Setting of
# optimization flags is not handled here and is left to the responsibility of
# the user to avoid conflicts in the resulting binaries

hpx_add_target_compile_definition(_DEBUG PUBLIC CONFIGURATIONS Debug)
hpx_add_target_compile_definition(DEBUG PUBLIC CONFIGURATIONS Debug)
hpx_add_target_compile_definition(HPX_DISABLE_ASSERTS PUBLIC
  CONFIGURATIONS Release RelWithDebInfo MinSizeRelease)
hpx_add_target_compile_definition(BOOST_DISABLE_ASSERTS PUBLIC
  CONFIGURATIONS Release RelWithDebInfo MinSizeRelease)

# Make sure we compile in proper C++xx mode (MSVC uses it automatically)
include(HPX_DetectCppDialect)
hpx_detect_cpp_dialect()

################################################################################
# CUDA features
################################################################################
if(HPX_WITH_CUDA)
  hpx_info("HPX_WITH_CUDA_ARCH has been set with values: ${HPX_WITH_CUDA_ARCH_INFO}")
  if(NOT HPX_WITH_CUDA_CLANG)
    hpx_libraries(cudadevrt)
    if(NOT MSVC)
      hpx_library_dir(${CUDA_TOOLKIT_ROOT_DIR}/lib64)
      link_directories(${CUDA_TOOLKIT_ROOT_DIR}/lib64)
      #set(CUDA_NVCC_FLAGS_DEBUG ${CUDA_NVCC_FLAGS_DEBUG};-D_DEBUG;-O0;-g;-G)
      #set(CUDA_NVCC_FLAGS_RELWITHDEBINFO ${CUDA_NVCC_FLAGS_RELWITHDEBINFO};-DNDEBUG;-O3;-g)
      #set(CUDA_NVCC_FLAGS_MINSIZEREL ${CUDA_NVCC_FLAGS_MINSIZEREL};-DNDEBUG;-O1)
      #set(CUDA_NVCC_FLAGS_RELEASE ${CUDA_NVCC_FLAGS_RELEASE};-DNDEBUG;-O3)
      set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS};-w)
    else()
      set(CUDA_PROPAGATE_HOST_FLAGS OFF)
      hpx_library_dir(${CUDA_TOOLKIT_ROOT_DIR}/lib/x64)
      link_directories(${CUDA_TOOLKIT_ROOT_DIR}/lib/x64)
      set(CUDA_NVCC_FLAGS_DEBUG ${CUDA_NVCC_FLAGS_DEBUG};-D_DEBUG;-O0;-g;-G;-Xcompiler=-MDd;-Xcompiler=-Od;-Xcompiler=-Zi;-Xcompiler=-bigobj)
      set(CUDA_NVCC_FLAGS_RELWITHDEBINFO ${CUDA_NVCC_FLAGS_RELWITHDEBINFO};-DNDEBUG;-O2;-g;-Xcompiler=-MD,-O2,-Zi;-Xcompiler=-bigobj)
      set(CUDA_NVCC_FLAGS_MINSIZEREL ${CUDA_NVCC_FLAGS_MINSIZEREL};-DNDEBUG;-O1;-Xcompiler=-MD,-O1;-Xcompiler=-bigobj)
      set(CUDA_NVCC_FLAGS_RELEASE ${CUDA_NVCC_FLAGS_RELEASE};-DNDEBUG;-O2;-Xcompiler=-MD,-Ox;-Xcompiler=-bigobj)
    endif()
    set(CUDA_SEPARABLE_COMPILATION ON)
    foreach(arch ${HPX_WITH_CUDA_ARCH})
      string(REPLACE "sm_" "" arch ${arch})
      set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS};-gencode=arch=compute_${arch},code=sm_${arch})
    endforeach()
    set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS};${CXX_FLAG})
    set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS};--expt-relaxed-constexpr)
    set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS};--expt-extended-lambda)
    set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS};--default-stream per-thread)
    set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS};-lcudadevrt)
    set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS};-rdc=true)
  else()
    hpx_add_target_compile_option(-DBOOST_THREAD_USES_MOVE PUBLIC)
    hpx_add_target_compile_option(--cuda-path=${CUDA_TOOLKIT_ROOT_DIR} PUBLIC)
    hpx_libraries(cudart)
    hpx_library_dir(${CUDA_TOOLKIT_ROOT_DIR}/lib64)
    link_directories(${CUDA_TOOLKIT_ROOT_DIR}/lib64)
  endif()
endif()

# Store option value passed by an user for HPX_WITH_CXX14_RETURN_TYPE_DEDUCTION.
if(HPX_WITH_CXX14_RETURN_TYPE_DEDUCTION)
  set(HPX_WITH_CXX14_RETURN_TYPE_DEDUCTION_ADVANCED )
  set(HPX_WITH_CXX14_RETURN_TYPE_DEDUCTION_GIVEN ON)
else()
  set(HPX_WITH_CXX14_RETURN_TYPE_DEDUCTION_ADVANCED ADVANCED)
  set(HPX_WITH_CXX14_RETURN_TYPE_DEDUCTION_GIVEN OFF)
endif()

################################################################################
# C++ feature tests
################################################################################
include(HPX_PerformCxxFeatureTests)
hpx_perform_cxx_feature_tests()

# Exceptional handling for non-clang CUDA.
if(HPX_WITH_CXX14_RETURN_TYPE_DEDUCTION)
  if(HPX_WITH_CUDA AND NOT HPX_WITH_CUDA_CLANG)
    # means using default value (given value).
    unset(HPX_WITH_CXX14_RETURN_TYPE_DEDUCTION)
  endif()
endif()

# HPX_WITH_CXX14_RETURN_TYPE_DEDUCTION
# Default value is used only when HPX_WITH_CXX14_RETURN_TYPE_DEDUCTION is not defined.
hpx_option(HPX_WITH_CXX14_RETURN_TYPE_DEDUCTION BOOL
  "Enable the use of auto as a return value in some places. Overriding this flag is only necessary if the C++ compiler is not standard compliant, e.g. nvcc."
  ${HPX_WITH_CXX14_RETURN_TYPE_DEDUCTION_GIVEN}
  ${HPX_WITH_CXX14_RETURN_TYPE_DEDUCTION_ADVANCED})
if(HPX_WITH_CXX14_RETURN_TYPE_DEDUCTION)
  hpx_add_config_define(HPX_HAVE_CXX14_RETURN_TYPE_DEDUCTION)
endif()

# HPX_WITH_THREAD_COMPATIBILITY
hpx_option(HPX_WITH_THREAD_COMPATIBILITY BOOL
    "Use a compatibility implementation of std::thread, i.e. fall back to Boost.Thread (default: OFF)"
    OFF ADVANCED)
if(HPX_WITH_THREAD_COMPATIBILITY)
  hpx_add_config_define(HPX_HAVE_THREAD_COMPATIBILITY)
else()
  if(NOT HPX_WITH_CXX11_THREAD)
    hpx_error("HPX needs support for C++11 std::thread which is not available on this platform. Please enable HPX_WITH_THREAD_COMPATIBILITY to use Boost.Thread instead.")
  endif()
endif()

################################################################################
# check for miscellaneous things
################################################################################

hpx_check_for_mm_prefetch(
  DEFINITIONS HPX_HAVE_MM_PREFETCH)

hpx_check_for_stable_inplace_merge(
  DEFINITIONS HPX_HAVE_STABLE_INPLACE_MERGE)

if(NOT HPX_WITH_STABLE_INPLACE_MERGE)
  hpx_warn("The standard library you are using (libc++ version < 6) does not have a stable inplace_merge implementation.")
endif()

################################################################################
# Check for misc system headers
################################################################################

hpx_check_for_unistd_h(
  DEFINITIONS HPX_HAVE_UNISTD_H)

if(NOT WIN32)
  ##############################################################################
  # Macro definitions for system headers
  ##############################################################################
  add_definitions(-D_GNU_SOURCE)
  if(APPLE)
    hpx_add_config_define(BOOST_HAS_INT128)
  endif()

  ##############################################################################
  # System libraries
  ##############################################################################
  if(NOT MSVC)
    hpx_add_compile_flag_if_available(-pthread)
    if(HPX_HAVE_LIBATOMIC)
      hpx_libraries(atomic)
    endif()
  endif()

  if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
    hpx_libraries(dl)
  endif()

  if(NOT APPLE AND NOT ("${HPX_PLATFORM_UC}" STREQUAL "ANDROID"))
    hpx_libraries(rt)
  endif()

  if("${HPX_PLATFORM_UC}" STREQUAL "ANDROID")
    hpx_libraries(log)
  endif()

  if(APPLE)
    hpx_add_compile_flag_if_available(-ftemplate-depth=256 LANGUAGES CXX)
  endif()
endif()

if(WIN32)
  if(MSVC)
    enable_language(ASM_MASM)

    hpx_add_target_compile_option(-Ox PUBLIC CONFIGURATIONS Release)

    # even VS2017 has an ICE when compiling with -Ob2
    hpx_add_target_compile_option(-Ob1 PUBLIC CONFIGURATIONS Release)

    if(NOT HPX_WITH_AWAIT)
      # /RTC1 is incompatible with /await
      hpx_add_target_compile_option(/RTC1 PUBLIC CONFIGURATIONS Debug)
    else()
      hpx_remove_target_compile_option(/RTC1 PUBLIC CONFIGURATIONS Debug)
    endif()

    # VS2012 and above has a special flag for improving the debug experience by
    # adding more symbol information to the build (-d2Zi)
    hpx_add_target_compile_option(-d2Zi+ PUBLIC CONFIGURATIONS RelWithDebInfo)

    # VS2013 and above know how to do link time constant data segment folding
    # VS2013 update 2 and above know how to remove debug information for
    #     non-referenced functions and data (-Zc:inline)
    hpx_add_target_compile_option(-Zc:inline PUBLIC)
    hpx_add_target_compile_option(-Gw PUBLIC
      CONFIGURATIONS Release RelWithDebInfo MinSizeRelease)
    hpx_add_target_compile_option(-Zo PUBLIC CONFIGURATIONS RelWithDebInfo)
    if(HPX_WITH_DATAPAR_VC)
      hpx_add_target_compile_option(-std:c++latest PUBLIC)
      hpx_add_config_cond_define(_HAS_AUTO_PTR_ETC 1)
    endif()

    # Exceptions
    hpx_add_target_compile_option(-EHsc)
    if(MSVC14)
      # assume conforming (throwing) operator new implementations
      hpx_add_target_compile_option(-Zc:throwingNew PUBLIC)

      # enable faster linking (requires VS2015 Update1)
      # disabled for now as this flag crashes debugger
      # hpx_remove_link_flag(/debug CONFIGURATIONS Debug)
      # hpx_add_link_flag(/debug:fastlink CONFIGURATIONS Debug)

      # Update 2 requires to set _ENABLE_ATOMIC_ALIGNMENT_FIX for it to compile
      # atomics
      hpx_add_config_cond_define(_ENABLE_ATOMIC_ALIGNMENT_FIX)

      # Update 3 allows to flag rvalue misuses and enforces strict string const-
      # qualification conformance
      hpx_add_target_compile_option(-Zc:rvalueCast PUBLIC)
      hpx_add_target_compile_option(-Zc:strictStrings PUBLIC)
    endif()

    # Runtime type information
    hpx_add_target_compile_option(-GR PUBLIC)
    # Multiprocessor build
    hpx_add_target_compile_option(-MP PUBLIC)
    # Increase the maximum size of object file sections
    hpx_add_target_compile_option(-bigobj PUBLIC)
  endif()

  hpx_libraries(psapi shlwapi)

  ##############################################################################
  # Macro definitions for system headers
  ##############################################################################
  add_definitions(-D_WINDOWS)
  add_definitions(-D_WIN32)
  hpx_add_config_cond_define(_WIN32_WINNT 0x0601)
  hpx_add_config_cond_define(_SCL_SECURE_NO_WARNINGS)
  hpx_add_config_cond_define(_CRT_SECURE_NO_WARNINGS)
  hpx_add_config_cond_define(_SCL_SECURE_NO_DEPRECATE)
  hpx_add_config_cond_define(_CRT_SECURE_NO_DEPRECATE)
  hpx_add_config_cond_define(_CRT_NONSTDC_NO_WARNINGS)
  hpx_add_config_cond_define(_WINSOCK_DEPRECATED_NO_WARNINGS)
  hpx_add_config_cond_define(_CRT_NON_CONFORMING_SWPRINTFS)
  hpx_add_config_cond_define(_SILENCE_FPOS_SEEKPOS_DEPRECATION_WARNING)

  ##############################################################################
  # Boost
  ##############################################################################

  hpx_add_config_cond_define(BOOST_USE_WINDOWS_H)
  if (NOT Boost_USE_STATIC_LIBS)
    hpx_add_config_cond_define(BOOST_SERIALIZATION_DYN_LINK)
  endif()
  if(NOT CMAKE_CL_64)
    hpx_add_config_cond_define(BOOST_NO_ALIGNMENT)
  endif()
  if(NOT HPX_WITH_GENERIC_CONTEXT_COROUTINES)
    hpx_add_config_define(HPX_HAVE_FIBER_BASED_COROUTINES)
  endif()
  hpx_add_config_cond_define(PSAPI_VERSION 1)
endif()

# Configure Warnings
if(HPX_WITH_COMPILER_WARNINGS)
  if(MSVC) # Adding special warning settings for the MSVC compiler ...
    hpx_add_compile_flag(-W3 LANGUAGES C CXX)
    # According to the ifort Windows manual, W3 isn't supported
    hpx_add_compile_flag(-W1 LANGUAGES Fortran)
    # Boost.Lockfree triggers 'warning C4307: '+' : integral constant overflow'
    # which is benign
    hpx_add_compile_flag(-wd4307)

    # MSVC2012/2013 are overeager to report 'qualifier applied to function type
    # has no meaning; ignored'
    hpx_add_compile_flag(-wd4180)

    # max symbol length exceeded
    hpx_add_compile_flag(-wd4503)

    # 'int': forcing value to bool 'true' or 'false' (performance warning)
    hpx_add_compile_flag(-wd4800)

    # vcpkg enables the /utf-8 option which causes (benign) warnings in the
    # Spirit headers
    if(HPX_WITH_VCPKG)
      # The file contains a character starting at offset ... that is illegal in
      # the current source character set
      hpx_add_compile_flag(-wd4828)
    endif()

  else() # Trial and error approach for any other compiler ...
    hpx_add_compile_flag_if_available(-Wall LANGUAGES CXX C Fortran)
    hpx_add_compile_flag_if_available(-Wextra LANGUAGES CXX C Fortran)
    # This is a new warning popping up from the boost headers with no particular meaning
    hpx_add_compile_flag_if_available(-Wno-unused-local-typedefs LANGUAGES CXX C Fortran)
    hpx_add_compile_flag_if_available(-Wno-strict-aliasing LANGUAGES CXX C Fortran)
    hpx_add_compile_flag_if_available(-Wno-sign-promo LANGUAGES CXX)
    hpx_add_compile_flag_if_available(-Wno-attributes LANGUAGES CXX)
    hpx_add_compile_flag_if_available(-Wno-cast-align LANGUAGES CXX)

    # These are usually benign and can't be suppressed because of
    # interface requirements
    hpx_add_compile_flag_if_available(-Wno-unused-parameter)

    # Be extra strict about format checks
    # Boost.Logging is built on fprintf, sadly
    hpx_add_compile_flag_if_available(-Wformat=2)
    hpx_add_compile_flag_if_available(-Wno-format-nonliteral)

    # Self initialization is dangerous
    hpx_add_compile_flag_if_available(-Winit-self)

    # For portability
    hpx_add_compile_flag_if_available(-Wdouble-promotion)

    # Warn about casting that violates qualifiers or alignment
    hpx_add_compile_flag_if_available(-Wcast-qual)
    if(NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
      # Clang is overeager in reporting cast alignment problems in Boost
      hpx_add_compile_flag_if_available(-Wcast-align)
    endif()

    hpx_add_compile_flag_if_available(-Werror=trampolines)
    hpx_add_compile_flag_if_available(-Werror=parentheses)
    hpx_add_compile_flag_if_available(-Werror=reorder)
    hpx_add_compile_flag_if_available(-Werror=return-type)
    hpx_add_compile_flag_if_available(-Werror=sequence-point)
    hpx_add_compile_flag_if_available(-Werror=uninitialized)
    hpx_add_compile_flag_if_available(-Werror=format)
    hpx_add_compile_flag_if_available(-Werror=missing-braces)
    hpx_add_compile_flag_if_available(-Werror=sign-compare)
  endif()
endif()

# Diagnostics
if(MSVC)
  # Display full paths in diagnostics
  hpx_add_compile_flag(-FC LANGUAGES C CXX)
else()
  # Show the flags that toggle each warning
  hpx_add_compile_flag_if_available(-fdiagnostics-show-option LANGUAGES CXX C Fortran)

  # VLAs are a GNU extensions that we forbid as they are not supported on MSVC
  hpx_add_compile_flag_if_available(-Werror=vla)
  # No return statement in a non-void function can lead to garbage return values
  # in GCC.
  hpx_add_compile_flag_if_available(-Werror=return-type LANGUAGES CXX C)

  # We get false positives all over the place with this.
  if(CMAKE_COMPILER_IS_GNUCXX)
    hpx_add_compile_flag_if_available(-Wno-unused-but-set-parameter LANGUAGES CXX C)
    hpx_add_compile_flag_if_available(-Wno-unused-but-set-variable LANGUAGES CXX C)
    # Uninitialized variables are bad, earlier compilers issue spurious warnings
    hpx_add_compile_flag_if_available(-Werror=uninitialized LANGUAGES CXX C)
    hpx_add_compile_flag_if_available(-Wno-unused-local-typedefs LANGUAGES CXX C)
    # -Werror=maybe-uninitialized leads to false positives.
    hpx_add_compile_flag_if_available(-Wno-maybe-uninitialized LANGUAGES CXX C)
  endif()

  # Silence warning about __sync_fetch_and_nand changing semantics
  hpx_add_compile_flag_if_available(-Wno-sync-nand LANGUAGES CXX C)

  # Silence warnings about deleting polymorphic objects with non-virtual dtors.
  # These come from within Boost.
  if(CMAKE_COMPILER_IS_GNUCXX)
    hpx_add_compile_flag_if_available(-Wno-delete-non-virtual-dtor LANGUAGES CXX)
  endif()

  # Check if our libraries have unresolved symbols
  #if(NOT APPLE AND NOT HPX_WITH_APEX)
  if(NOT APPLE AND NOT WIN32 AND NOT HPX_WITH_SANITIZERS)
    hpx_add_link_flag_if_available(-Wl,-z,defs TARGETS SHARED EXE)
  endif()
  if(WIN32)
    hpx_libraries(WS2_32)
    hpx_libraries(mswsock)
  endif()

  if("${HPX_PLATFORM_UC}" STREQUAL "BLUEGENEQ")
    hpx_add_compile_flag_if_available(-Wno-deprecated-register LANGUAGES CXX C)
  endif()

  if(HPX_WITH_HIDDEN_VISIBILITY)
    hpx_add_compile_flag_if_available(-fvisibility=hidden LANGUAGES CXX C Fortran)
    hpx_add_link_flag_if_available(-fvisibility=hidden TARGETS SHARED EXE)
    hpx_add_config_define(HPX_HAVE_ELF_HIDDEN_VISIBILITY)
    hpx_add_config_define(HPX_HAVE_COROUTINE_GCC_HIDDEN_VISIBILITY)
    hpx_add_config_define(HPX_HAVE_PLUGIN_GCC_HIDDEN_VISIBILITY)
  endif()

  if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
    hpx_add_compile_flag_if_available(-Wno-cast-align)
  endif()

  if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel")
    # Disable the following warnings:
    # #1170: invalid redeclaration of nested class
    hpx_add_compile_flag_if_available(-wd1170)
    # #858: type qualifier on return type is meaningless
    hpx_add_compile_flag_if_available(-wd858)
    # #1098: the qualifier on this friend declaration is ignored
    hpx_add_compile_flag_if_available(-wd1098)
    # #488: template parameter not used in declaring the parameter type
    hpx_add_compile_flag_if_available(-wd488)
    # #2203: cast discards qualifiers from target type (needed for mvapich2
    #        mpi header)
    hpx_add_compile_flag_if_available(-wd2203)
    # #2536: cannot specify explicit initializer for arrays
    hpx_add_compile_flag_if_available(-wd2536)
  endif()

  # rdtsc is an x86 instruction that reads the value of a CPU time stamp
  # counter. rdtscp is an extension to rdtsc. The difference is that rdtscp is
  # a serializing instruction.
  hpx_cpuid("rdtsc" HPX_WITH_RDTSC
    DEFINITIONS HPX_HAVE_RDTSC)

  # XeonPhi's do not support RDTSCP
  if(NOT ("${HPX_PLATFORM_UC}" STREQUAL "XEONPHI"))
    hpx_cpuid("rdtscp" HPX_WITH_RDTSCP
      DEFINITIONS HPX_HAVE_RDTSCP)
  endif()

  if(NOT HPX_WITH_RDTSC AND NOT HPX_WITH_RDTSCP)
    hpx_warn("Neither rdtsc nor rdtscp is available; some performance counters may report incorrect results")
  endif()
endif()

################################################################################

################################################################################
# Find Our dependencies:
#   These are all dependencies needed to build the core library. Dependencies
#   that are only needed by plugins, examples or tests should be found
#   seperately in the appropriate subdirectory.
# When a package is found, the necessary include paths are set, and the libraries
# are added to the HPX_LIBRARIES variables

# Setting up our required Boost libraries. This will find all required boost
# libraries and add possibly needed boost headers shipped with the hpx source
include(HPX_SetupBoost)

# Find all allocators which are currently supported.
include(HPX_SetupAllocator)

# convey selected allocator type to the build configuration
hpx_add_config_define(HPX_HAVE_MALLOC "\"${HPX_WITH_MALLOC}\"")
if(${HPX_WITH_MALLOC} STREQUAL "jemalloc")
  if(NOT ("${HPX_WITH_JEMALLOC_PREFIX}" STREQUAL "<none>") AND
     NOT ("${HPX_WITH_JEMALLOC_PREFIX}x" STREQUAL "x"))
    hpx_add_config_define(HPX_HAVE_JEMALLOC_PREFIX ${HPX_WITH_JEMALLOC_PREFIX})
    hpx_add_config_define(HPX_HAVE_INTERNAL_ALLOCATOR)
  endif()
endif()

find_package(Hwloc)
if(NOT HWLOC_FOUND)
  hpx_error("Hwloc could not be found, please specify HWLOC_ROOT to point to the correct location")
endif()
hpx_libraries(${HWLOC_LIBRARIES})
include_directories(${HWLOC_INCLUDE_DIR})

################################################################################
# Enable integration with Intel Amplifier
################################################################################
if((NOT HPX_WITH_APEX) AND HPX_WITH_ITTNOTIFY)
  find_package(Amplifier)
  if(NOT AMPLIFIER_FOUND)
    hpx_error("Intel Amplifier could not be found and HPX_WITH_ITTNOTIFY=On, please specify AMPLIFIER_ROOT to point to the root of your Amplifier installation")
  endif()
  hpx_libraries(${AMPLIFIER_LIBRARIES})
  include_directories(${AMPLIFIER_INCLUDE_DIR})
  hpx_add_config_define(HPX_HAVE_ITTNOTIFY 1)
  hpx_add_config_define(HPX_HAVE_THREAD_DESCRIPTION)
endif()

################################################################################
# Enable integration with Apex event counters
################################################################################

# reset external source lists
add_hpx_library_sources_noglob(hpx_external)
add_hpx_library_headers_noglob(hpx_external)

if(HPX_WITH_APEX)
  set(_hpx_apex_no_update)
  if(HPX_WITH_APEX_NO_UPDATE)
    set(_hpx_apex_no_update NO_UPDATE)
  endif()
  set(_hpx_apex_tag "v2.1.0")
  if(HPX_WITH_APEX_TAG)
    message("Overriding APEX git tag ${_hpx_apex_tag} with ${HPX_WITH_APEX_TAG}")
    set(_hpx_apex_tag ${HPX_WITH_APEX_TAG})
  endif()

  # We want to track parent dependencies
  hpx_add_config_define(HPX_HAVE_THREAD_PARENT_REFERENCE)
  # handle APEX library
  include(GitExternal)
  git_external(apex
    https://github.com/khuck/xpress-apex.git
    ${_hpx_apex_tag}
    ${_hpx_apex_no_update}
    VERBOSE)

  LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/apex/cmake/Modules")
  add_subdirectory(apex/src/apex)
  if(NOT APEX_FOUND)
    hpx_error("Apex could not be found and HPX_WITH_APEX=On")
  endif()
  if(AMPLIFIER_FOUND)
    hpx_error("AMPLIFIER_FOUND has been set. Please disable the use of the Intel Amplifier (WITH_AMPLIFIER=Off) in order to use Apex")
  endif()

  include_directories(${APEX_SOURCE_DIR})
  set(HPX_ADDITIONAL_PRIVATE_RUNTIME_DEPENDENCIES
      ${HPX_ADDITIONAL_PRIVATE_RUNTIME_DEPENDENCIES} apex_lib)
  if(APEX_WITH_MSR)
    set(HPX_ADDITIONAL_PRIVATE_RUNTIME_DEPENDENCIES
        ${HPX_ADDITIONAL_PRIVATE_RUNTIME_DEPENDENCIES} -L${MSR_ROOT}/lib -lmsr)
  endif()
  if(APEX_WITH_ACTIVEHARMONY)
    set(HPX_ADDITIONAL_PRIVATE_RUNTIME_DEPENDENCIES
        ${HPX_ADDITIONAL_PRIVATE_RUNTIME_DEPENDENCIES} -L${ACTIVEHARMONY_ROOT}/lib -lharmony)
  endif()
  if(APEX_WITH_OTF2)
    set(HPX_ADDITIONAL_PRIVATE_RUNTIME_DEPENDENCIES
        ${HPX_ADDITIONAL_PRIVATE_RUNTIME_DEPENDENCIES} -L${OTF2_ROOT}/lib -lotf2)
  endif()

  # handle optional ITTNotify library
  if(HPX_WITH_ITTNOTIFY)
    add_subdirectory(apex/src/ITTNotify)
    if(NOT ITTNOTIFY_FOUND)
      hpx_error("ITTNotify could not be found and HPX_WITH_ITTNOTIFY=On")
    endif()
    include_directories(${ITTNOTIFY_SOURCE_DIR})
    hpx_add_config_define(HPX_HAVE_ITTNOTIFY 1)
    set(HPX_ADDITIONAL_PRIVATE_RUNTIME_DEPENDENCIES
        ${HPX_ADDITIONAL_PRIVATE_RUNTIME_DEPENDENCIES} ittnotify_lib)
  endif()
endif()

if(HPX_WITH_HPXMP)

  # hpxMP requires ASM support
  enable_language(ASM)
  set(CMAKE_ASM_FLAGS "${CFLAGS} -x assembler-with-cpp")

  set(_hpxmp_no_update)
  if(HPX_WITH_HPXMP_NO_UPDATE)
    set(_hpxmp_no_update NO_UPDATE)
  endif()
  set(_hpx_hpxmp_tag "v0.1.0")
  if(HPX_WITH_HPXMP_TAG)
    message("Overriding hpxMP git tag ${_hpx_hpxmp_tag} with ${HPX_WITH_HPXMP_TAG}")
    set(_hpx_hpxmp_tag ${HPX_WITH_HPXMP_TAG})
  endif()

  # handle hpxMP library
  include(GitExternal)
  git_external(hpxmp
    https://github.com/STEllAR-GROUP/hpxMP.git
    ${_hpx_hpxmp_tag}
    ${_hpxmp_no_update}
    VERBOSE)

  add_subdirectory(hpxmp)

  # make sure thread-local storage is supported
  hpx_add_config_define(HPX_HAVE_THREAD_LOCAL_STORAGE)
endif()

if(HPX_WITH_GOOGLE_PERFTOOLS)
  find_package(GooglePerftools)
  if(NOT GOOGLE_PERFTOOLS_FOUND)
    hpx_error("Google Perftools could not be found and HPX_WITH_GOOGLE_PERFTOOLS=On, please specify GOOGLE_PERFTOOLS to point to the root of your Google Perftools installation")
  endif()
  hpx_libraries(${GOOGLE_PERFTOOLS_LIBRARIES})
  include_directories(${GOOGLE_PERFTOOLS_INCLUDE_DIR})
endif()

if(HPX_WITH_VALGRIND)
  find_package(Valgrind)
  if(NOT VALGRIND_FOUND)
    hpx_error("Valgrind could not be found and HPX_WITH_VALGRIND=On, please specify VALGRIND_ROOT to point to the root of your Valgrind installation")
  endif()
  include_directories(${VALGRIND_INCLUDE_DIR})
  hpx_add_config_define(HPX_HAVE_VALGRIND)
endif()

if(HPX_WITH_VIM_YCM)
  SET(CMAKE_EXPORT_COMPILE_COMMANDS ON)
endif()

################################################################################
# Check Build Options based on the found dependencies. We also check for errors
# with incompatible options with the currently selected platform.
#

if(HPX_WITH_GENERIC_CONTEXT_COROUTINES)
  # Check if we can use generic coroutine contexts without any problems
  if(NOT Boost_CONTEXT_FOUND)
    hpx_error("The usage of Boost.Context was selected but Boost.Context was not found.")
  endif()
  if("${HPX_PLATFORM_UC}" STREQUAL "BLUEGENEQ")
    if(Boost_VERSION LESS 105600)
      hpx_error("On BlueGene/Q, Boost.Context can only be used with a Boost >=1.56")
    endif()
  endif()
  hpx_add_config_define(HPX_HAVE_GENERIC_CONTEXT_COROUTINES)
endif()

################################################################################
# Emulation of SwapContext on Windows
################################################################################
if(WIN32)
  if(HPX_WITH_SWAP_CONTEXT_EMULATION)
    if(NOT CMAKE_ASM_MASM_COMPILER)
      hpx_error("SwitchToFiber emulation can not be enabled. The masm compiler could not be found. Try setting the ASM_MASM environment variable to the assembler executable (ml.exe/ml64.exe) or disable the emulation by setting HPX_WITH_SWAP_CONTEXT_EMULATION to Off")
    else()
      hpx_info("SwitchToFiber emulation is enabled, using compiler: '${CMAKE_ASM_MASM_COMPILER}'")
      hpx_add_config_define(HPX_HAVE_SWAP_CONTEXT_EMULATION)
    endif()
  endif()
endif()

################################################################################

################################################################################
# HPX_PREFIX
# The prefix is the default search path for HPX plugins
################################################################################
if("${HPX_PLATFORM_UC}" STREQUAL "ANDROID")
  set(HPX_PREFIX "lib")
  set(HPX_BUILD_PREFIX "lib")
else()
  set(HPX_PREFIX "${CMAKE_INSTALL_PREFIX}")
  set(HPX_BUILD_PREFIX "${CMAKE_BINARY_DIR}")
endif()


################################################################################
# search path configuration
################################################################################
if(HPX_WITH_FULL_RPATH)
  hpx_include(SetFullRPATH)
endif()
###############################################################################

################################################################################
# Git commit detection
################################################################################
include(HPX_GitCommit)
hpx_add_config_define(HPX_HAVE_GIT_COMMIT "\"${HPX_WITH_GIT_COMMIT}\"")

hpx_include(SetOutputPaths)
##############################################################################

################################################################################
# Provide a macro for generating config headers
################################################################################
macro(generate_config_defines_header TARGET_DIRECTORY)
  # Generate a defines.hpp to be used in the build directory ...
  set(HPX_DEFINES_PREFIX ${HPX_BUILD_PREFIX})
  write_config_defines_file(
    TEMPLATE "${PROJECT_SOURCE_DIR}/cmake/templates/config_defines.hpp.in"
    NAMESPACE default
    FILENAME "${TARGET_DIRECTORY}/hpx/config/defines.hpp")
endmacro()

################################################################################
# Set basic search paths for the generated HPX headers
################################################################################
include_directories("${CMAKE_BINARY_DIR}")

################################################################################
# Configure compression and other plugins
################################################################################
set(HPX_STATIC_PARCELPORT_PLUGINS "" CACHE INTERNAL "" FORCE)
add_hpx_pseudo_target(plugins)
add_subdirectory(plugins)

if(HPX_WITH_COMPRESSION_BZIP2)
  hpx_add_config_define(HPX_HAVE_COMPRESSION_BZIP2)
endif()
if(HPX_WITH_COMPRESSION_SNAPPY)
  hpx_add_config_define(HPX_HAVE_COMPRESSION_SNAPPY)
endif()
if(HPX_WITH_COMPRESSION_ZLIB)
  hpx_add_config_define(HPX_HAVE_COMPRESSION_ZLIB)
endif()

################################################################################
# Documentation toolchain (Sphinx, Doxygen, Breathe)
################################################################################
hpx_include(Documentation)

# Debug library postfix
set(CMAKE_DEBUG_POSTFIX "d")
set(HPX_DEBUG_POSTFIX "d")

################################################################################
# Target specification
################################################################################
# Recurse into some subdirectories. This does not actually cause another cmake
# executable to run. The same process will walk through the project's entire
# directory structure.
if(HPX_WITH_TOOLS)
  add_hpx_pseudo_target(tools)
  add_subdirectory(tools)
endif()

add_hpx_pseudo_target(core)
add_subdirectory(src)

###############################################################################
# Tests
###############################################################################
if(HPX_WITH_TESTS)
  find_package(PythonInterp)

  if(NOT PYTHONINTERP_FOUND)
    hpx_warn("A python interpreter could not be found. The test suite can not be run automatically.")
  endif()

  add_hpx_pseudo_target(tests)

  enable_testing()
  include(CTest)

  include_directories(tests)
  add_subdirectory(tests)
endif()

if(HPX_WITH_EXAMPLES)
  add_hpx_pseudo_target(examples)
  include_directories(examples)
  add_subdirectory(examples)
endif()

if(HPX_WITH_RUNTIME)
  add_hpx_pseudo_target(runtime)
  add_subdirectory(runtime)
endif()

if(HPX_WITH_DOCUMENTATION)
  add_subdirectory(docs)
endif()

###############################################################################
# Activate plugins
###############################################################################
add_plugin_modules()

################################################################################
# Configure the header to include all compile definitions
################################################################################
generate_config_defines_header(${CMAKE_BINARY_DIR})

# Generate a defines.hpp to be used in the install directory ...
set(HPX_DEFINES_PREFIX ${HPX_PREFIX})
write_config_defines_file(
  TEMPLATE "${PROJECT_SOURCE_DIR}/cmake/templates/config_defines.hpp.in"
  NAMESPACE default
  FILENAME "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/hpx/config/defines.hpp")

# Configure hpxrun.py
configure_file("${PROJECT_SOURCE_DIR}/cmake/templates/hpxrun.py.in"
               "${CMAKE_BINARY_DIR}/bin/hpxrun.py"
               @ONLY)

################################################################################
# installation instructions
################################################################################
install(
  FILES "${CMAKE_BINARY_DIR}/bin/hpxrun.py"
  DESTINATION ${CMAKE_INSTALL_BINDIR}
  COMPONENT core
  PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE
  GROUP_READ GROUP_EXECUTE
  WORLD_READ WORLD_EXECUTE)

install( # install all hpx header files
  DIRECTORY hpx/
  DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hpx
  COMPONENT core
  FILES_MATCHING PATTERN "*.hpp"
  PATTERN ".git" EXCLUDE
  PATTERN "CMakeFiles" EXCLUDE
  PATTERN "CTestFiles" EXCLUDE)

# Install all HPX header that have been configured using various
# cmake options
install(
  DIRECTORY "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/hpx/"
  DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hpx
  COMPONENT core
  FILES_MATCHING PATTERN "*.hpp"
  PATTERN ".git" EXCLUDE
  PATTERN "CMakeFiles" EXCLUDE
  PATTERN "CTestFiles" EXCLUDE)

install( # Install all HPX cmake utility files
  DIRECTORY cmake/
  DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${HPX_PACKAGE_NAME}
  COMPONENT core
  PATTERN "templates" EXCLUDE
  PATTERN "packaging" EXCLUDE
  PATTERN ".git" EXCLUDE)

install( # Install HPX Python scripts
  DIRECTORY python/scripts/
  DESTINATION ${CMAKE_INSTALL_BINDIR}
  FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE
                   GROUP_READ GROUP_EXECUTE
                   WORLD_READ WORLD_EXECUTE
  COMPONENT core
  FILES_MATCHING PATTERN "*.py"
  PATTERN ".git" EXCLUDE)

#   if(UNIX)
#     file(GLOB scripts "${PROJECT_SOURCE_DIR}/python/scripts/*.py")
#     execute_process(COMMAND "${CMAKE_COMMAND}" -E make_directory
#       "${CMAKE_BINARY_DIR}/python/scripts" )
#     foreach(script ${scripts})
#       get_filename_component(script_name ${script} NAME)
#       get_filename_component(script_name_we ${script} NAME_WE)
#
#       #make copy, so that we have intact symlink in CMAKE_BINARY_DIR
#       execute_process(
#         COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${script}" "${script_name}"
#   WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/python/scripts")
#
#       execute_process(
#         COMMAND "${CMAKE_COMMAND}" -E create_symlink "${script_name}" "${script_name_we}"
#   WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/python/scripts")
#
#       install(FILES "${CMAKE_BINARY_DIR}/python/scripts/${script_name_we}" DESTINATION "${CMAKE_INSTALL_BINDIR}")
#     endforeach()
#   endif()
#
#   install( # Install HPX Python module (TODO: this is a temporary hack)
#     DIRECTORY python/hpx
#     DESTINATION ${CMAKE_INSTALL_DATADIR}/hpx-${HPX_VERSION}/python
#     COMPONENT core
#     FILES_MATCHING PATTERN "*.py"
#     PATTERN ".git" EXCLUDE)
#
#   execute_process(COMMAND "${CMAKE_COMMAND}" -E make_directory "${CMAKE_BINARY_DIR}/python" )
#   #make symlink, so that we have intact hpx symlink in CMAKE_BINARY_DIR
#   execute_process(COMMAND "${CMAKE_COMMAND}" -E create_symlink "${PROJECT_SOURCE_DIR}/python/hpx"
#     "hpx-${HPX_VERSION}" WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/python")
#   # create a symlink in share pointing to the latest HPX installation
#   execute_process(COMMAND "${CMAKE_COMMAND}" -E create_symlink "hpx-${HPX_VERSION}" "hpx" WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/python")
#   install(DIRECTORY "${CMAKE_BINARY_DIR}/python/hpx" DESTINATION "${CMAKE_INSTALL_DATADIR}")

if("${HPX_PLATFORM_UC}" STREQUAL "XEONPHI")
  # FIXME: push changes upstream
  install(
    DIRECTORY external/asio/boost
    DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hpx/external
    COMPONENT core
    FILES_MATCHING PATTERN "*.hpp"
    PATTERN ".git" EXCLUDE)
endif()

install(
  FILES "${PROJECT_SOURCE_DIR}/LICENSE_1_0.txt"
  DESTINATION ${CMAKE_INSTALL_DATADIR}/hpx
  COMPONENT license)

if(HPX_WITH_DOCUMENTATION)
  # Install HPX documentation files
  install(
    FILES "${PROJECT_SOURCE_DIR}/docs/index.html"
    DESTINATION ${CMAKE_INSTALL_DATADIR}/hpx/
    COMPONENT docs)

  install(
    DIRECTORY "${CMAKE_BINARY_DIR}/share/hpx/docs/html/"
    DESTINATION ${CMAKE_INSTALL_DATADIR}/hpx/docs/html
    COMPONENT docs
    PATTERN ".git" EXCLUDE)
endif()

if(HPX_WITH_VIM_YCM)
  set(build_dir_file ${CMAKE_BINARY_DIR}/.ycm_extra_conf.py)
  set(source_dir_file ${CMAKE_SOURCE_DIR}/.ycm_extra_conf.py)
  configure_file(${CMAKE_SOURCE_DIR}/tools/vim/.ycm_extra_conf.py
               ${build_dir_file} @ONLY)
  add_custom_target(
    configure_ycm
    COMMAND ${CMAKE_COMMAND} -E copy ${build_dir_file} ${source_dir_file}
    COMMENT "Copying YCM config file to source directory"
    VERBATIM
  )
  hpx_info("VIM YouCompleteMe: run 'make configure_ycm' to copy config file to source directory and enable support in YCM. To enable automatic loading of configure file, add to your .vimrc option: \"let g:ycm_extra_conf_globlist = ['${CMAKE_SOURCE_DIR}/*']\"")
endif()

################################################################################
# print overall configuration summary
include(HPX_PrintSummary)

################################################################################
# External build system support (FindHPX.cmake and pkg-config).
################################################################################

include(HPX_GeneratePackage)

message("")
message("HPX will be installed to ${CMAKE_INSTALL_PREFIX}")
message("")
