# Copyright (c) 2007-2019 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
#
# SPDX-License-Identifier: BSL-1.0
# 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.6.3
cmake_minimum_required(VERSION 3.6.3 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_VERSION_MAJOR 1)
set(HPX_VERSION_MINOR 4)
set(HPX_VERSION_SUBMINOR 0)
set(HPX_VERSION_DATE 20200115)
set(HPX_VERSION_TAG "")

set(HPX_VERSION "${HPX_VERSION_MAJOR}.${HPX_VERSION_MINOR}.${HPX_VERSION_SUBMINOR}")
set(HPX_LIBRARY_VERSION "${HPX_VERSION}")
set(HPX_SOVERSION ${HPX_VERSION_MAJOR})
set(HPX_PACKAGE_NAME HPX)
# To keep track of the hpx_root when other subprojects are declared
set(HPX_SOURCE_DIR "${PROJECT_SOURCE_DIR}")
set(HPX_BINARY_DIR "${PROJECT_BINARY_DIR}")

set_property(GLOBAL PROPERTY USE_FOLDERS ON)

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

# To fix the windows link bug (need to be included only once!)
include(HPX_FilterLibrariesMSVC)

include(GNUInstallDirs)
include(HPX_Utils)

# explicitly set certain policies
cmake_policy(VERSION 3.6.3)
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)

# If we have a cmake version older than 3.12, we can't rely on CONFIGURE_DEPENDS
if(${CMAKE_VERSION} VERSION_LESS "3.12")
  set(DO_CONFIGURE_DEPENDS)
else()
  set(DO_CONFIGURE_DEPENDS CONFIGURE_DEPENDS)
endif()

# 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_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}")

################################################################################
# reset cached variables that need to be re-filled
unset(HPX_COMPONENTS CACHE)
unset(HPX_EXPORT_TARGETS CACHE)
unset(HPX_EXPORT_MODULES_TARGETS CACHE)
unset(HPX_LIBS CACHE)
unset(HPX_STATIC_PARCELPORT_PLUGINS CACHE)

################################################################################
# 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")
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, mimalloc, tbbmalloc, and custom (default is: tcmalloc)"
  ${DEFAULT_MALLOC}
  STRINGS "system;tcmalloc;jemalloc;mimalloc;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_COMPILER_WARNINGS_AS_ERRORS BOOL
  "Turn compiler warnings into errors (default: OFF)"
  OFF 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(HPX_WITH_DOCUMENTATION)
  set(valid_output_formats html singlehtml latexpdf man)
  hpx_option(HPX_WITH_DOCUMENTATION_OUTPUT_FORMATS STRING
    "List of documentation output formats to generate. Valid options are ${valid_output_formats}. Multiple values can be separated with semicolons. (default html)."
    "html" CATEGORY "Build Targets")

  foreach(output_format ${HPX_WITH_DOCUMENTATION_OUTPUT_FORMATS})
    if(NOT ${output_format} IN_LIST valid_output_formats)
      hpx_error("${output_format} is not a valid value for HPX_WITH_DOCUMENTATION_OUTPUT_FORMATS. Valid output format are: ${valid_output_formats}.")
    endif()
  endforeach()
endif()

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_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")

  # disable all tests if HPX_WITH_TESTS=OFF
if(NOT HPX_WITH_TESTS)
  hpx_set_option(HPX_WITH_TESTS_BENCHMARKS VALUE OFF FORCE)
  hpx_set_option(HPX_WITH_TESTS_REGRESSIONS VALUE OFF FORCE)
  hpx_set_option(HPX_WITH_TESTS_UNIT VALUE OFF FORCE)
  hpx_set_option(HPX_WITH_TESTS_HEADERS VALUE OFF FORCE)
  hpx_set_option(HPX_WITH_TESTS_EXTERNAL_BUILD VALUE OFF FORCE)
  hpx_set_option(HPX_WITH_TESTS_EXAMPLES VALUE OFF FORCE)
endif()

# 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
  "Enable IO counters (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)
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()

if(HPX_WITH_DATAPAR_VC)
  hpx_warn("Vc support is deprecated. This option will be removed in a future release. It will be replaced with SIMD support from the C++ standard library")
  include(HPX_SetupVc)
endif()
if(NOT HPX_WITH_DATAPAR_VC)
  hpx_info("No vectorization library configured")
else()
  hpx_option(HPX_WITH_DATAPAR BOOL
    "Enable data parallel algorithm support (default: ON)" ON ADVANCED)
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 (empty string means dynamic) (default: ${HPX_MAX_CPU_COUNT_DEFAULT})"
  "${HPX_MAX_CPU_COUNT_DEFAULT}"
  CATEGORY "Thread Manager" ADVANCED)
if(HPX_WITH_MAX_CPU_COUNT)
  hpx_add_config_define(HPX_HAVE_MAX_CPU_COUNT ${HPX_WITH_MAX_CPU_COUNT})
endif()
if((NOT HPX_WITH_MAX_CPU_COUNT) OR (HPX_WITH_MAX_CPU_COUNT GREATER 64))
  hpx_add_config_define(HPX_HAVE_MORE_THAN_64_THREADS)
endif()

set(HPX_MAX_NUMA_DOMAIN_COUNT_DEFAULT "8")
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})

# Deprecated in 1.4.0
hpx_option(HPX_WITH_MORE_THAN_64_THREADS BOOL
  "HPX applications will be able to run on more than 64 cores (This variable is deprecated. The value is derived from HPX_WITH_MAX_CPU_COUNT instead.)"
  "" CATEGORY "Thread Manager" ADVANCED)
if(HPX_WITH_MORE_THAN_64_THREADS)
  hpx_warn("HPX_WITH_MORE_THAN_64_THREADS is deprecated. Instead use HPX_WITH_MAX_CPU_COUNT directly. If HPX_WITH_MAX_CPU_COUNT is greater than 64, or empty, HPX_HAVE_MORE_THAN_64_THREADS will be automatically set.")
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)

# We create a target to contain libraries like rt, dl etc. in order to remove
# global variables
add_library(hpx_base_libraries INTERFACE)

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)
    target_link_libraries(hpx_base_libraries INTERFACE 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: OFF)"
  OFF CATEGORY "Thread Manager" ADVANCED)

if(HPX_WITH_THREAD_STEALING_COUNTS)
  hpx_add_config_define(HPX_HAVE_THREAD_STEALING_COUNTS)
endif()

hpx_option(HPX_WITH_COROUTINE_COUNTERS BOOL
  "Enable keeping track of coroutine creation and rebind counts (default: OFF)"
   OFF CATEGORY "Thread Manager" ADVANCED)
if(HPX_WITH_COROUTINE_COUNTERS)
  hpx_add_config_define(HPX_HAVE_COROUTINE_COUNTERS)
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()

hpx_option(HPX_WITH_SPINLOCK_POOL_NUM STRING
  "Number of elements a spinlock pool manages (default: 128)"
  128 CATEGORY "Thread Manager" ADVANCED)

hpx_add_config_define(HPX_HAVE_SPINLOCK_POOL_NUM ${HPX_WITH_SPINLOCK_POOL_NUM})

# Deprecated in 1.4.0
hpx_option(HPX_SCHEDULER_MAX_TERMINATED_THREADS STRING
  "[Deprecated] Maximum number of terminated threads collected before those are cleaned up (default: 100)"
  "0" CATEGORY "Thread Manager" ADVANCED)

if(HPX_SCHEDULER_MAX_TERMINATED_THREADS GREATER 0)
  hpx_warn("HPX_SCHEDULER_MAX_TERMINATED_THREADS is deprecated and will be removed in a future release. Use the configuration option hpx.thread_queue.max_terminated_threads instead to set the value.")
  hpx_add_config_define(HPX_THREAD_QUEUE_MAX_TERMINATED_THREADS
    ${HPX_SCHEDULER_MAX_TERMINATED_THREADS})
endif()

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.1.7" 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")
    hpx_option(HPX_WITH_HPXMP_TAG STRING
      "hpxMP repository tag or branch" "v0.3.0" 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 and #define in global defines.hpp
  hpx_option(HPX_WITH_PARCELPORT_LIBFABRIC BOOL
    "Enable the libfabric based parcelport. This is currently an experimental feature"
    OFF CATEGORY "Parcelport" ADVANCED)
  if (HPX_WITH_PARCELPORT_LIBFABRIC)
    hpx_add_config_define(HPX_HAVE_PARCELPORT_LIBFABRIC)
  endif()

  hpx_option(HPX_WITH_PARCELPORT_VERBS BOOL
    "Enable the ibverbs based parcelport. This is currently an experimental feature"
    OFF CATEGORY "Parcelport" ADVANCED)
  if (HPX_WITH_PARCELPORT_VERBS)
    hpx_warn("The verbs parcelport is deprecated. Please use the MPI or libfabric parcelports instead.")
    hpx_add_config_define(HPX_HAVE_PARCELPORT_VERBS)
  endif()

  hpx_option(HPX_WITH_PARCELPORT_MPI BOOL
    "Enable the MPI based parcelport."
    OFF CATEGORY "Parcelport")
  if(HPX_WITH_PARCELPORT_MPI)
    hpx_add_config_define(HPX_HAVE_PARCELPORT_MPI)
    if(MSVC)
      # FIXME: add OpenMPI specific flag here for now as the hpx_add_compile_flag()
      # below does not add the extra options to the top level directory
      hpx_add_config_define(OMPI_IMPORTS)
    endif()
  endif()

  hpx_option(HPX_WITH_PARCELPORT_TCP BOOL
    "Enable the TCP based parcelport."
    ON CATEGORY "Parcelport")
  if(HPX_WITH_PARCELPORT_TCP)
    hpx_add_config_define(HPX_HAVE_PARCELPORT_TCP)
  endif()
  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;PMIX_RANK)."
    "MV2_COMM_WORLD_RANK;PMI_RANK;OMPI_COMM_WORLD_SIZE;ALPS_APP_PE;PMIX_RANK" CATEGORY "Parcelport" ADVANCED)
  if(HPX_WITH_PARCELPORT_MPI)
    # This list is to detect whether we run inside an mpi environment.
    # If one of those environment variables is set, the MPI parcelport
    # is enabled by default.
    # PMI_RANK: Intel MPI and MVAPICH2
    # OMPI_COMM_WORLD_SIZE: OpenMPI starting at version 1.3
    if(HPX_WITH_PARCELPORT_MPI_ENV)
      string(REPLACE ";" "," hpx_parcelport_mpi_env_ "${HPX_WITH_PARCELPORT_MPI_ENV}")
      hpx_add_config_define(HPX_HAVE_PARCELPORT_MPI_ENV "\"${hpx_parcelport_mpi_env_}\"")
    endif()
  endif()

  hpx_option(HPX_WITH_PARCELPORT_MPI_MULTITHREADED BOOL
    "Turn on MPI multithreading support (default: ON)."
    ON CATEGORY "Parcelport" ADVANCED)
  if(HPX_WITH_PARCELPORT_MPI)
    if(HPX_WITH_PARCELPORT_MPI_MULTITHREADED)
      hpx_add_config_define(HPX_HAVE_PARCELPORT_MPI_MULTITHREADED)
    endif()
  endif()

endif(HPX_WITH_NETWORKING)

## 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)
  enable_language(Fortran)
  find_package(HDF5 COMPONENTS CXX Fortran)
  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_SANITIZERS BOOL "Configure with sanitizer 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()

hpx_option(HPX_WITH_TESTS_DEBUG_LOG BOOL
  "Turn on debug logs (--hpx:debug-hpx-log) for tests (default: OFF)"
  OFF
  CATEGORY "Debugging" ADVANCED)

hpx_option(HPX_WITH_TESTS_DEBUG_LOG_DESTINATION STRING
  "Destination for test debug logs (default: cout)"
  "cout"
  CATEGORY "Debugging" ADVANCED)

# 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)

# 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_ACTION_BASE_COMPATIBILITY: introduced in V1.4.0
hpx_option(HPX_WITH_ACTION_BASE_COMPATIBILITY BOOL
    "Enable deprecated action bases (default: ON)"
    ON ADVANCED)
if(HPX_WITH_ACTION_BASE_COMPATIBILITY)
  hpx_add_config_define(HPX_HAVE_ACTION_BASE_COMPATIBILITY)
endif()

# HPX_WITH_REGISTER_THREAD_COMPATIBILITY: introduced in V1.4.0
hpx_option(HPX_WITH_REGISTER_THREAD_COMPATIBILITY BOOL
    "Enable deprecated register_thread/work functions in the hpx::applier namespace (default: ON)"
    ON ADVANCED)
if(HPX_WITH_REGISTER_THREAD_COMPATIBILITY)
  hpx_add_config_define(HPX_HAVE_REGISTER_THREAD_COMPATIBILITY)
endif()

################################################################################
# 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 5.0)
    hpx_error("GCC 5.0 or higher is required. Specify HPX_GCC_VERSION_CHECK=OFF to ignore this error.")
  endif()
endif()

if(MSVC)
  if(MSVC_VERSION LESS 1900)
    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(((MSVC_VERSION GREATER_EQUAL 1900) 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((MSVC_VERSION GREATER_EQUAL 1900) 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()

################################################################################
# Some special handling of the compilation is need on build infrastructure for
# generating packages for target architecture, see issue #3575

hpx_option(HPX_WITH_BUILD_BINARY_PACKAGE BOOL
  "Build HPX on the build infrastructure on any LINUX distribution (default: OFF)."
  OFF ADVANCED)

################################################################################
# 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()

# 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()

################################################################################
# Set configuration option to use Boost.Context or not. This depends on the
# platform.
set(__use_generic_coroutine_context OFF)
if(APPLE)
  set(__use_generic_coroutine_context ON)
endif()
if("${HPX_PLATFORM_UC}" STREQUAL "BLUEGENEQ")
  set(__use_generic_coroutine_context ON)
endif()
hpx_option(HPX_WITH_GENERIC_CONTEXT_COROUTINES BOOL
  "Use Boost.Context as the underlying coroutines context switch implementation."
  ${__use_generic_coroutine_context} ADVANCED)

################################################################################
# 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)
      target_link_libraries(hpx_base_libraries INTERFACE atomic)
    endif()
  endif()

  if(HPX_HAVE_LIBSUPCPP)
    target_link_libraries(hpx_base_libraries INTERFACE supc++)
  endif()

  if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
    target_link_libraries(hpx_base_libraries INTERFACE dl)
  endif()

  if(NOT APPLE AND NOT ("${HPX_PLATFORM_UC}" STREQUAL "ANDROID"))
    target_link_libraries(hpx_base_libraries INTERFACE rt)
  endif()

  if("${HPX_PLATFORM_UC}" STREQUAL "ANDROID")
    target_link_libraries(hpx_base_libraries INTERFACE log)
  endif()

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

if(WIN32)
  if(MSVC)
    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)

    # /RTC1 is incompatible with /await
    if(NOT HPX_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(MSVC_VERSION GREATER_EQUAL 1900)
      # 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)

      # Update 8 requires to set _ENABLE_EXTENDED_ALIGNED_STORAGE for it to
      # compile atomics
      hpx_add_config_cond_define(_ENABLE_EXTENDED_ALIGNED_STORAGE)

      # Make sure that __cplusplus is properly defined
      hpx_add_target_compile_option(-Zc:__cplusplus)
    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()

  target_link_libraries(hpx_base_libraries INTERFACE 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)

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

    # Boost.Lockfree triggers 'warning C4307: '+' : integral constant overflow'
    # which is benign
    hpx_add_compile_flag(-wd4307)

    # object allocated on the heap may not be aligned
    hpx_add_compile_flag(-wd4316)

    # 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()

    if(HPX_WITH_DATAPAR_VC)
      # unary minus operator applied to unsigned type, result still unsigned
      hpx_add_compile_flag(-wd4146)

      # '<=': signed/unsigned mismatch
      hpx_add_compile_flag(-wd4018)

      # 'return': conversion from 'short' to 'Vc_1::schar', possible loss of data
      hpx_add_compile_flag(-wd4244)
    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()

# Configure compiler warnings as errors
if(HPX_WITH_COMPILER_WARNINGS_AS_ERRORS)
  if(MSVC)
    hpx_add_compile_flag(-WX LANGUAGES C CXX Fortran)
  else()
    hpx_add_compile_flag_if_available(-Werror LANGUAGES CXX C Fortran)
  endif()
endif()

# Diagnostics
if(MSVC)
  # Display full paths in diagnostics
  hpx_add_compile_flag(-FC LANGUAGES C CXX)
  if(CMAKE_CL_64)
    set(__target_arch "x86_64")
  else()
    set(__target_arch "x86")
  endif()
  hpx_info("Architecture detected: ${__target_arch}")
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)
    target_link_libraries(hpx_base_libraries INTERFACE psapi WS2_32 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()

  set(__has_timestamp_support OFF)
  include(TargetArch)

  target_architecture(__target_arch)
  if("${__target_arch}" STREQUAL "i386" OR
     "${__target_arch}" STREQUAL "ix86" OR
     "${__target_arch}" STREQUAL "x86_64" OR
     "${__target_arch}" STREQUAL "ia64")

      # 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)

      # One can not assume if RDTSCP is available on the hardware
      # of the build infrastructure, that it will be available on
      # all potential target hardware, see Issue  #3575
      if(NOT ${HPX_WITH_BUILD_BINARY_PACKAGE})

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

      endif()
      if(HPX_WITH_RDTSC OR HPX_WITH_RDTSCP)
        set(__has_timestamp_support ON)
      endif()
  elseif("${__target_arch}" STREQUAL "arm" OR
         "${__target_arch}" STREQUAL "armv5" OR
         "${__target_arch}" STREQUAL "armv6" OR
         "${__target_arch}" STREQUAL "armv7")
    set(__has_timestamp_support ON)
  elseif("${__target_arch}" STREQUAL "ppc" OR
         "${__target_arch}" STREQUAL "ppc64")
    set(__has_timestamp_support ON)
  elseif("${__target_arch}" STREQUAL "bgq")
    set(__has_timestamp_support ON)
  elseif("${__target_arch}" STREQUAL "s390x")
    set(__has_timestamp_support ON)
  endif()

  hpx_info("Architecture detected: ${__target_arch}")
  if(NOT __has_timestamp_support)
    hpx_warn("No timestamp support is available; some performance counters may report incorrect results")
  endif()
endif()

# store target architecture for later use
set(HPX_WITH_TARGET_ARCHITECTURE ${__target_arch} CACHE INTERNAL "" FORCE)

# Compatibility with using Boost.ProgramOptions, introduced in V1.4.0
hpx_option(HPX_PROGRAM_OPTIONS_WITH_BOOST_PROGRAM_OPTIONS_COMPATIBILITY
  BOOL "Enable Boost.ProgramOptions compatibility. (default: ON)"
  ON ADVANCED CATEGORY "Modules")

# Compatibility with using Boost.FileSystem, introduced in V1.4.0
set(__filesystem_compatibility_default ON)
if(HPX_WITH_CXX17_FILESYSTEM)
  set(__filesystem_compatibility_default OFF)
endif()
hpx_option(HPX_FILESYSTEM_WITH_BOOST_FILESYSTEM_COMPATIBILITY
  BOOL "Enable Boost.FileSystem compatibility. (default: ${__filesystem_compatibility_default})"
  ${__filesystem_compatibility_default} ADVANCED CATEGORY "Modules")

################################################################################
# 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.

# Setup our required Boost libraries.
include(HPX_SetupBoost)
include(HPX_SetupBoostFilesystem)
include(HPX_SetupBoostIostreams)
include(HPX_SetupBoostProgramOptions)
# Find all allocators which are currently supported.
include(HPX_SetupAllocator)
include(HPX_SetupHwloc)

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

# Setup packages and subprojects
include(HPX_SetupCUDA) # CUDA needs to come before Apex, to have cuda_add_library available
include(HPX_SetupApex)
include(HPX_SetupPapi)
include(HPX_SetupHpxmp)
include(HPX_SetupGooglePerfTools)
include(HPX_SetupValgrind)
# Setup plugins
# (set here cause if we include it inside plugins, it will not be defined in
# src/CMakeLists.txt where we call add_static_parcelports)
include(HPX_SetupMPI)

if(HPX_WITH_SANITIZERS)
  hpx_add_config_define(HPX_HAVE_SANITIZERS)
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()
  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 "${PROJECT_BINARY_DIR}")
endif()


################################################################################
# search path configuration
################################################################################
if(HPX_WITH_FULL_RPATH)
  include(HPX_SetFullRPATH)
endif()

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

hpx_include(SetOutputPaths)

################################################################################
# Add custom targets for tests
################################################################################
if (HPX_WITH_TESTS)
  add_hpx_pseudo_target(tests)
  if (HPX_WITH_TESTS_UNIT)
    add_hpx_pseudo_target(tests.unit)
    add_hpx_pseudo_dependencies(tests tests.unit)
  endif()
  if (HPX_WITH_TESTS_REGRESSIONS)
    add_hpx_pseudo_target(tests.regressions)
    add_hpx_pseudo_dependencies(tests tests.regressions)
  endif()
  if (HPX_WITH_TESTS_BENCHMARKS)
    add_hpx_pseudo_target(tests.performance)
    add_hpx_pseudo_dependencies(tests tests.performance)
  endif()
  if (HPX_WITH_TESTS_HEADERS)
    add_hpx_pseudo_target(tests.headers)
    add_hpx_pseudo_dependencies(tests tests.headers)
  endif()
  if (HPX_WITH_EXAMPLES AND HPX_WITH_TESTS_EXAMPLES)
    add_hpx_pseudo_target(tests.examples)
    add_hpx_pseudo_dependencies(tests tests.examples)
  endif()

  enable_testing()
  include(CTest)
endif()

if(HPX_WITH_EXAMPLES)
  add_hpx_pseudo_target(examples)
endif()

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

################################################################################
# Set up dummy compiler flags target
################################################################################
include(HPX_CompilerFlagsTarget)

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()

################################################################################
# Add libraries
################################################################################
add_subdirectory(libs)

################################################################################
# Add core dependency
################################################################################
add_hpx_pseudo_target(core)

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

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

################################################################################
# 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 core configuration
################################################################################
add_subdirectory(src)

################################################################################
# Add components
################################################################################
add_subdirectory(components)

###############################################################################
# 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()

  # pseudo_target added above
  add_subdirectory(tests)
endif()

if(HPX_WITH_EXAMPLES)
  add_subdirectory(examples)
endif()

if(HPX_WITH_DOCUMENTATION)
  add_subdirectory(docs)
endif()

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

################################################################################
# installation instructions
################################################################################
install(
  FILES "${PROJECT_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 "${PROJECT_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
#       "${PROJECT_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 PROJECT_BINARY_DIR
#       execute_process(
#         COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${script}" "${script_name}"
#   WORKING_DIRECTORY "${PROJECT_BINARY_DIR}/python/scripts")
#
#       execute_process(
#         COMMAND "${CMAKE_COMMAND}" -E create_symlink "${script_name}" "${script_name_we}"
#   WORKING_DIRECTORY "${PROJECT_BINARY_DIR}/python/scripts")
#
#       install(FILES "${PROJECT_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 "${PROJECT_BINARY_DIR}/python" )
#   #make symlink, so that we have intact hpx symlink in PROJECT_BINARY_DIR
#   execute_process(COMMAND "${CMAKE_COMMAND}" -E create_symlink "${PROJECT_SOURCE_DIR}/python/hpx"
#     "hpx-${HPX_VERSION}" WORKING_DIRECTORY "${PROJECT_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 "${PROJECT_BINARY_DIR}/python")
#   install(DIRECTORY "${PROJECT_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(
    FILES "${PROJECT_SOURCE_DIR}/docs/index.html"
    DESTINATION ${CMAKE_INSTALL_DATADIR}/hpx/
    COMPONENT docs)

  if("html" IN_LIST HPX_WITH_DOCUMENTATION_OUTPUT_FORMATS)
    install(
      DIRECTORY "${PROJECT_BINARY_DIR}/share/hpx/docs/html/"
      DESTINATION ${CMAKE_INSTALL_DATADIR}/hpx/docs/html
      COMPONENT docs
      PATTERN "*.buildinfo" EXCLUDE)
  endif()

  if("singlehtml" IN_LIST HPX_WITH_DOCUMENTATION_OUTPUT_FORMATS)
    install(
      DIRECTORY "${PROJECT_BINARY_DIR}/share/hpx/docs/singlehtml/"
      DESTINATION ${CMAKE_INSTALL_DATADIR}/hpx/docs/singlehtml
      COMPONENT docs
      PATTERN "*.buildinfo" EXCLUDE)
  endif()

  if("latexpdf" IN_LIST HPX_WITH_DOCUMENTATION_OUTPUT_FORMATS)
    install(
      FILES "${PROJECT_BINARY_DIR}/share/hpx/docs/latexpdf/latex/HPX.pdf"
      DESTINATION ${CMAKE_INSTALL_DATADIR}/hpx/docs/pdf/
      COMPONENT docs)
  endif()

  if("man" IN_LIST HPX_WITH_DOCUMENTATION_OUTPUT_FORMATS)
    install(
      FILES "${PROJECT_BINARY_DIR}/share/hpx/docs/man/hpx.1"
      DESTINATION ${CMAKE_INSTALL_MANDIR}/
      COMPONENT docs)
  endif()
endif()

if(HPX_WITH_VIM_YCM)
  set(build_dir_file ${PROJECT_BINARY_DIR}/.ycm_extra_conf.py)
  set(source_dir_file ${PROJECT_SOURCE_DIR}/.ycm_extra_conf.py)
  configure_file(${PROJECT_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 = ['${PROJECT_SOURCE_DIR}/*']\"")
endif()

################################################################################
# Add rpm packaging

hpx_option(HPX_WITH_RPM
  BOOL
  "Enable or disable the generation of rpm packages"
OFF ADVANCED)

if(HPX_WITH_RPM)
add_subdirectory(cmake/packaging/rpm)
endif()

################################################################################
# print overall configuration summary
include(HPX_PrintSummary)
create_configuration_summary("Configuration summary:\n--" "hpx")

include(HPX_ExportTargets)
# Modules can't link to this if not exported
install(TARGETS hpx_base_libraries EXPORT HPXTargets
  LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
  ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
  COMPONENT hpx_base_libraries
)
hpx_export_targets(hpx_base_libraries)

################################################################################
# store cache vars and their values in order for them to be forwarded to the
# projects (needs to be before the HPX_GeneratePackage call)
include(HPX_ForwardCacheVariables)

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

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