#------------------------------------------------------------------------------#
# Copyright 2024 Kitware, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#------------------------------------------------------------------------------#

# Install headers
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/
  DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
  FILES_MATCHING PATTERN "*.h"
)
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/
  DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
  FILES_MATCHING PATTERN "*.inl"
)

# Realm runtime
list(APPEND REALM_SRC
  realm/realm_c.h
  realm/transfer/lowlevel_disk.cc
  realm/transfer/address_list.h            realm/transfer/address_list.cc
  realm/transfer/channel.h                 realm/transfer/channel.cc
  realm/transfer/channel_disk.h            realm/transfer/channel_disk.cc
  realm/transfer/transfer.h                realm/transfer/transfer.cc
  realm/transfer/lowlevel_dma.h            realm/transfer/lowlevel_dma.cc
  realm/transfer/ib_memory.h               realm/transfer/ib_memory.cc
  realm/deppart/byfield.h                  realm/deppart/byfield.cc
  realm/deppart/deppart_config.h
  realm/deppart/image.h
  realm/deppart/inst_helper.h
  realm/deppart/partitions.h               realm/deppart/partitions.cc
  realm/deppart/preimage.h
  realm/deppart/rectlist.h
  realm/deppart/rectlist.inl
  realm/deppart/setops.h                   realm/deppart/setops.cc
  realm/deppart/sparsity_impl.h            realm/deppart/sparsity_impl.cc
  realm/deppart/sparsity_impl.inl
  realm/atomics.h           realm/atomics.inl
  realm/bgwork.h            realm/bgwork.cc
  realm/event_impl.h        realm/event_impl.cc
  realm/event_impl.inl
  realm/faults.h            realm/faults.cc
  realm/faults.inl
  realm/idx_impl.h          realm/idx_impl.cc
  realm/inst_impl.h         realm/inst_impl.cc
  realm/inst_layout.h       realm/inst_layout.inl
  realm/inst_layout.cc
  realm/interval_tree.h     realm/interval_tree.inl
  realm/machine_impl.h      realm/machine_impl.cc
  realm/mem_impl.h          realm/mem_impl.cc
  realm/metadata.h          realm/metadata.cc
  realm/module.h            realm/module.cc
  realm/module_config.h     realm/module_config.inl realm/module_config.cc
  realm/nodeset.h           realm/nodeset.inl      realm/nodeset.cc
  realm/numa/numa_module.h  realm/numa/numa_module.cc
  realm/numa/numasysif.h    realm/numa/numasysif.cc
  realm/operation.h         realm/operation.cc
  realm/operation.inl
  realm/proc_impl.h         realm/proc_impl.cc
  realm/procset/procset_module.h realm/procset/procset_module.cc
  realm/repl_heap.h         realm/repl_heap.cc
  realm/rsrv_impl.h         realm/rsrv_impl.cc
  realm/runtime_impl.h      realm/runtime_impl.cc
  realm/sampling_impl.h     realm/sampling_impl.cc
  realm/subgraph_impl.h     realm/subgraph_impl.cc
  realm/tasks.h             realm/tasks.cc
  realm/threads.h           realm/threads.cc
  realm/threads.inl
  realm/shm.h               realm/shm.cc
)

if(Legion_USE_CUDA)
  list(APPEND REALM_SRC
    realm/cuda/cuda_module.h    realm/cuda/cuda_module.cc
    realm/cuda/cuda_module.inl
    realm/cuda/cuda_internal.h  realm/cuda/cuda_internal.cc
    realm/cuda/cuda_access.h    realm/cuda/cuda_access.cc
  )
  list(APPEND REALM_CUDA_SRC
    realm/cuda/cuda_memcpy.cu
  )
  if(REALM_USE_CUDART_HIJACK)
    list(APPEND REALM_SRC
      realm/cuda/cudart_hijack.h
    )
  endif()
endif()

if(Legion_USE_HIP)
  list(APPEND REALM_SRC
    realm/hip/hip_module.h    realm/hip/hip_module.cc
    realm/hip/hip_module.inl
    realm/hip/hip_internal.h  realm/hip/hip_internal.cc
    realm/hip/hip_access.h    realm/hip/hip_access.cc
    realm/hip/hiphijack_api.h
  )
  if(REALM_USE_HIP_HIJACK)
    list(APPEND REALM_SRC
      realm/hip/hip_hijack.h
    )
  endif()
endif()

if(Legion_USE_LLVM)
  list(APPEND REALM_SRC
    realm/llvmjit/llvmjit.h
    realm/llvmjit/llvmjit.inl
    realm/llvmjit/llvmjit_internal.h  realm/llvmjit/llvmjit_internal.cc
    realm/llvmjit/llvmjit_module.h    realm/llvmjit/llvmjit_module.cc
  )
endif()

if(Legion_USE_HDF5)
  list(APPEND REALM_SRC
    realm/hdf5/hdf5_module.h realm/hdf5/hdf5_module.cc
    realm/hdf5/hdf5_internal.h realm/hdf5/hdf5_internal.cc
    realm/hdf5/hdf5_access.h   realm/hdf5/hdf5_access.inl
    realm/hdf5/hdf5_access.cc
  )
endif()

if (Legion_USE_OpenMP)
  list(APPEND REALM_SRC
    realm/openmp/openmp_module.h realm/openmp/openmp_module.cc
    realm/openmp/openmp_internal.h
  )
  if(NOT Legion_OpenMP_SYSTEM_RUNTIME)
    list(APPEND REALM_SRC
      realm/openmp/openmp_threadpool.h realm/openmp/openmp_threadpool.cc
      realm/openmp/openmp_threadpool.inl
      realm/openmp/openmp_api.cc
    )
  endif()
endif()

if (Legion_USE_Python)
  list(APPEND REALM_SRC
    realm/python/python_module.h realm/python/python_module.cc
    realm/python/python_source.h realm/python/python_source.cc
    realm/python/python_source.inl
    realm/python/python_internal.h
  )
endif()

if(REALM_USE_GASNET1)
  list(APPEND REALM_SRC
    realm/gasnet1/gasnet1_module.h
    realm/gasnet1/gasnet1_module.cc
    realm/gasnet1/gasnetmsg.h
    realm/gasnet1/gasnetmsg.cc
  )
endif()

if(REALM_USE_GASNETEX)
  list(APPEND REALM_SRC
    realm/gasnetex/gasnetex_module.h
    realm/gasnetex/gasnetex_module.cc
    realm/gasnetex/gasnetex_internal.h
    realm/gasnetex/gasnetex_internal.cc
  )
  if (NOT REALM_USE_GASNETEX_WRAPPER OR Legion_ENABLE_TESTING)
    # If we're not using the wrapper (i.e. not dynamically loading it)
    # or we need it for testing, we need to build it
    set(LEGION_SOURCE_DIR "${PROJECT_SOURCE_DIR}")
    set(GEX_WRAPPER_BUILD_SHARED ${REALM_USE_GASNETEX_WRAPPER})
    set(GEX_DEBUG ${DEBUG_REALM})
    set(GEX_NO_INSTALL NOT ${REALM_USE_GASNETEX_WRAPPER})
    add_subdirectory(realm/gasnetex/gasnetex_wrapper EXCLUDE_FROM_ALL)
  endif()
endif()

if(REALM_USE_MPI)
  list(APPEND REALM_SRC
    realm/mpi/mpi_module.h
    realm/mpi/mpi_module.cc
    realm/mpi/am_mpi.h
    realm/mpi/am_mpi.cc
  )
endif()

if(REALM_USE_NVTX)
  list(APPEND REALM_SRC
    realm/nvtx.h
    realm/nvtx.cc
  )
endif()

if(REALM_USE_UCX)
  list(APPEND REALM_SRC
    realm/ucx/ucp_utils.h
    realm/ucx/ucp_dyn_load.h
    realm/ucx/ucp_module.h
    realm/ucx/ucp_module.cc
    realm/ucx/ucp_internal.h
    realm/ucx/ucp_internal.cc
    realm/ucx/ucp_context.h
    realm/ucx/ucp_context.cc
    realm/ucx/mpool.h
    realm/ucx/mpool.cc
    realm/ucx/spinlock.h
    realm/ucx/bootstrap/bootstrap.h
    realm/ucx/bootstrap/bootstrap.cc
    realm/ucx/bootstrap/bootstrap_loader.h
    realm/ucx/bootstrap/bootstrap_loader.cc
    realm/ucx/bootstrap/bootstrap_internal.h
    realm/ucx/bootstrap/bootstrap_util.h
  )
endif()

list(APPEND REALM_SRC
  realm.h
  realm/activemsg.h realm/activemsg.cc
  realm/network.h          realm/network.cc
  realm/bytearray.h
  realm/bytearray.inl
  realm/circ_queue.h
  realm/circ_queue.inl
  realm/cmdline.h          realm/cmdline.cc
  realm/cmdline.inl
  realm/codedesc.h         realm/codedesc.cc
  realm/codedesc.inl
  realm/custom_serdez.h
  realm/custom_serdez.inl
  realm/dynamic_table.h
  realm/dynamic_table.inl
  realm/event.h
  realm/id.h
  realm/id.inl
  realm/indexspace.h
  realm/instance.h
  realm/logging.h          realm/logging.cc
  realm/logging.inl
  realm/machine.h
  realm/machine.inl
  realm/memory.h
  realm/mutex.h     realm/mutex.inl     realm/mutex.cc
  realm/pri_queue.h
  realm/pri_queue.inl
  realm/processor.h
  realm/processor.inl
  realm/profiling.h        realm/profiling.cc
  realm/profiling.inl
  realm/realm_config.h
  realm/redop.h
  realm/reservation.h
  realm/reservation.inl
  realm/runtime.h
  realm/sampling.h
  realm/sampling.inl
  realm/serialize.h
  realm/serialize.inl
  realm/subgraph.h
  realm/subgraph.inl
  realm/timers.h           realm/timers.cc
  realm/timers.inl
  realm/utils.h            realm/utils.cc
)

# generate per-dimension object files for deppart stuff
foreach(INST_N1 RANGE 1 ${REALM_MAX_DIM})
  foreach(INST_N2 RANGE 1 ${REALM_MAX_DIM})
    foreach(SRCFILE realm/deppart/image realm/deppart/preimage realm/deppart/byfield)
      # use cmake's configure_file for a portable way of creating wrapper
      #  source files
      configure_file(${PROJECT_SOURCE_DIR}/cmake/deppart_tmpl.cc.in ${SRCFILE}_${INST_N1}_${INST_N2}.cc)
      list(APPEND REALM_SRC ${SRCFILE}_${INST_N1}_${INST_N2}.cc)
    endforeach()
  endforeach()
endforeach()

if(Legion_USE_CUDA)

  add_library(realm_cuda_fatbin OBJECT ${REALM_CUDA_SRC})
  #TODO(apryakhin): Enable with cmake 3.27
  #set_property(TARGET realm_cuda_fatbin PROPERTY CUDA_FATBIN_COMPILATION ON)
  target_compile_options(realm_cuda_fatbin PRIVATE $<$<COMPILE_LANG_AND_ID:CUDA,NVIDIA>:
                         -Xcudafe=--diag_suppress=boolean_controlling_expr_is_constant
                         --fatbin>)
  target_compile_definitions(realm_cuda_fatbin PRIVATE "CUDA_FATBIN_COMPILATION")

  target_include_directories(realm_cuda_fatbin
                     PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
                             ${PROJECT_BINARY_DIR}/runtime)

  set_target_cuda_standard(realm_cuda_fatbin STANDARD ${Legion_CUDA_STANDARD})
  set_target_cuda_architectures(realm_cuda_fatbin ARCHITECTURES ${Legion_CUDA_ARCH})
  set_target_cuda_warnings_and_errors(realm_cuda_fatbin WARN_AS_ERROR ${Legion_BUILD_WARN_AS_ERROR})

  set(realm_fatbin_cc "${CMAKE_CURRENT_BINARY_DIR}/realm_fatbin.cc")

  add_custom_command(
    OUTPUT "${realm_fatbin_cc}"
    COMMAND ${CMAKE_COMMAND}
      "-DVAR_NAME=realm_fatbin"
      "-DDEFINES_HEADER=realm/realm_config.h"
      "-DIN_FILE=$<TARGET_OBJECTS:realm_cuda_fatbin>"
      "-DOUT_FILE=${realm_fatbin_cc}"
      -P ${PROJECT_SOURCE_DIR}/cmake/bin2c.cmake
    VERBATIM
    WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
    DEPENDS $<TARGET_OBJECTS:realm_cuda_fatbin>
    COMMENT "Embedding binary objects $<TARGET_OBJECTS:realm_cuda_fatbin> -> ${realm_fatbin_cc}"
  )

  # Add a direct dependency on realm_fatbin.cc in order to force a rebuild as realm_fatbin.cc changes
  list(APPEND REALM_SRC ${realm_fatbin_cc})
endif()

find_package(Threads REQUIRED)
cmake_policy(SET CMP0063 NEW) # visibility controls in all builds
add_library(RealmRuntime ${REALM_SRC})
add_library(RealmStatic STATIC EXCLUDE_FROM_ALL ${REALM_SRC}) # static library for realm unit test

if(TARGET realm_cuda_fatbin)
  add_dependencies(RealmRuntime realm_cuda_fatbin)
  # HACK: to avoid compiling two realm_cuda_fatbin concurrent, which causes errors
  #  we create a control dependency between dynamic and static realm library, such that they will be built in order
  add_dependencies(RealmStatic RealmRuntime)
endif()

add_library(Legion::RealmRuntime ALIAS RealmRuntime)
target_compile_options(RealmRuntime PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${CXX_BUILD_WARNING_FLAGS}>)

add_library(Legion::RealmStatic ALIAS RealmStatic)
target_compile_options(RealmStatic PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${CXX_BUILD_WARNING_FLAGS}>)

# turn on warnings about partially-overloaded methods, if supported
check_cxx_compiler_flag("-Woverloaded-virtual" COMPILER_SUPORTS_OVERLOADED_VIRTUAL_WARNING)
if(COMPILER_SUPORTS_OVERLOADED_VIRTUAL_WARNING)
  target_compile_options(RealmRuntime PRIVATE "-Woverloaded-virtual")
endif()

if(COMPILER_SUPPORTS_DEFCHECK)
  # use the cxx_defcheck wrapper to make sure realm_defines.h is included
  #  any place it needs to be
  target_compile_options(RealmRuntime PRIVATE $<$<COMPILE_LANGUAGE:CXX>:--defcheck;realm_defines.h>)
endif()
if(REALM_USE_LIBDL)
  target_link_libraries(RealmRuntime PRIVATE ${CMAKE_DL_LIBS})
  if(APPLE)
    target_link_libraries(RealmRuntime PRIVATE "-undefined dynamic_lookup")
  endif()
endif()
target_link_libraries(RealmRuntime PRIVATE ${CMAKE_THREAD_LIBS_INIT})
if(UNIX AND NOT APPLE)
  target_link_libraries(RealmRuntime PRIVATE rt)
  target_link_libraries(RealmStatic PRIVATE rt)
endif()
set_target_properties(RealmRuntime PROPERTIES POSITION_INDEPENDENT_CODE ON)
set_target_properties(RealmRuntime PROPERTIES SOVERSION ${SOVERSION})
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
  set_property(TARGET RealmRuntime APPEND PROPERTY BUILD_RPATH "\$ORIGIN")
  set_property(TARGET RealmRuntime APPEND PROPERTY INSTALL_RPATH "\$ORIGIN")
elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
  set_property(TARGET RealmRuntime APPEND PROPERTY BUILD_RPATH "@loader_path")
  set_property(TARGET RealmRuntime APPEND PROPERTY INSTALL_RPATH "@loader_path")
endif ()

if(Legion_USE_Python)
  # Realm dlopens libpython.so, so we need to add the directory that contains it
  # to BUILD_RPATH, otherwise build/lib/librealm.so's dlopen will not find it.
  # We're assuming that libpython.so will be found in the same dir as librealm.so
  # after installation, so no need to update INSTALL_RPATH.
  get_filename_component(PYTHON_LIB_DIR "${Python3_LIBRARIES}" DIRECTORY)
  set_property(TARGET RealmRuntime APPEND PROPERTY BUILD_RPATH "${PYTHON_LIB_DIR}")
endif ()

if(REALM_LIMIT_SYMBOL_VISIBILITY)
  set_target_properties(RealmRuntime PROPERTIES CXX_VISIBILITY_PRESET hidden)
  set_target_properties(RealmRuntime PROPERTIES VISIBILITY_INLINES_HIDDEN 1)
  set_target_properties(RealmStatic PROPERTIES CXX_VISIBILITY_PRESET hidden)
  set_target_properties(RealmStatic PROPERTIES VISIBILITY_INLINES_HIDDEN 1)
endif()

if(Legion_USE_PAPI)
  target_include_directories(RealmRuntime PRIVATE ${PAPI_INCLUDE_DIRS})
  target_link_libraries(RealmRuntime PUBLIC ${PAPI_LIBRARIES})
endif()

if(Legion_USE_HWLOC)
  target_link_libraries(RealmRuntime PRIVATE HWLOC::HWLOC)
endif()

if(REALM_USE_GASNET1 OR REALM_USE_GASNETEX)
  if (REALM_USE_GASNET1 OR NOT REALM_USE_GASNETEX_WRAPPER)
    find_package(GASNet)
    if (NOT GASNet_FOUND AND Legion_EMBED_GASNet)
      set(GASNet_BUILD_SHARED ${BUILD_SHARED_LIBS})
      include(${PROJECT_SOURCE_DIR}/cmake/FetchAndBuildGASNet.cmake)
      find_package(GASNet REQUIRED)
    elseif (NOT GASNet_FOUND)
      message(FATAL_ERROR "Unable to find GASNet")
    endif ()
  endif()

  # cmake won't include GASNet::GASNet in the exported link libraries
  #  because we're doing a shared build, so force that
  if(NOT REALM_USE_GASNETEX_WRAPPER AND REALM_USE_GASNETEX)
    target_link_libraries(RealmRuntime PRIVATE $<LINK_ONLY:realm_gex_wrapper_objs>)
    install(TARGETS realm_gex_wrapper_objs EXPORT LegionTargets)
  elseif(NOT REALM_USE_GASNETEX_WRAPPER)
    target_link_libraries(RealmRuntime PRIVATE GASNet::GASNet)
    if (BUILD_SHARED_LIBS)
      target_link_libraries(RealmRuntime INTERFACE $<LINK_ONLY:GASNet::GASNet>)
    endif()
  elseif (Legion_ENABLE_TESTING)
    set_target_properties(realm_gex_wrapper PROPERTIES EXCLUDE_FROM_ALL FALSE)
  endif()

  # Skip installing gasnet extra libraries if we're using the gasnetex wrapper
  if (NOT REALM_USE_GASNETEX_WRAPPER)
    if(BUILD_SHARED_LIBS)
      # get the list of libraries and filter only those that are not in the
      #  (gasnet) install dir - the gasnet ones are sucked into librealm.so
      get_target_property(gasnet_ext_libs GASNet::${GASNet_CONDUIT}-par INTERFACE_LINK_LIBRARIES)
      list(FILTER gasnet_ext_libs EXCLUDE REGEX "^${GASNet_INSTALL_DIR}")
      set(GASNET_LINK_LIBRARIES_FOR_INSTALL ${gasnet_ext_libs} PARENT_SCOPE)
    elseif()
      # get the list of libraries and filter out those that are not in the
      #  (gasnet) install dir
      get_target_property(gasnet_all_libs GASNet::${GASNet_CONDUIT}-par INTERFACE_LINK_LIBRARIES)
      set(gasnet_libs "${gasnet_all_libs}")
      list(FILTER gasnet_libs INCLUDE REGEX "^${GASNet_INSTALL_DIR}")
      set(gasnet_installed_libs ${gasnet_libs})
      string(REGEX REPLACE "${GASNet_INSTALL_DIR}/([^/;]*/)*" "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/" gasnet_installed_libs "${gasnet_all_libs}")
      install(FILES ${gasnet_libs} DESTINATION ${CMAKE_INSTALL_LIBDIR})
      set(GASNET_LINK_LIBRARIES_FOR_INSTALL ${gasnet_installed_libs} PARENT_SCOPE)
    endif()
  endif()
endif()

if(REALM_USE_MPI)
  target_link_libraries(RealmRuntime PRIVATE MPI::MPI_CXX)
endif()

if(REALM_USE_UCX)
  target_include_directories(RealmRuntime PRIVATE ${UCX_INCLUDE_DIRS})
  if(NOT REALM_UCX_DYNAMIC_LOAD)
    target_link_libraries(RealmRuntime PRIVATE ucx::ucp)
  endif()
  # build the MPI bootstrap plugin
  add_library(realm_ucp_bootstrap_mpi MODULE
    realm/ucx/bootstrap/bootstrap_mpi.c)
  target_include_directories(realm_ucp_bootstrap_mpi PRIVATE
    ${CMAKE_CURRENT_SOURCE_DIR}
    ${PROJECT_BINARY_DIR}/runtime)
  target_link_libraries(realm_ucp_bootstrap_mpi PRIVATE MPI::MPI_C)
  set_target_properties(realm_ucp_bootstrap_mpi PROPERTIES PREFIX "")
  install(TARGETS realm_ucp_bootstrap_mpi LIBRARY
      DESTINATION ${CMAKE_INSTALL_LIBDIR})
endif()

if(Legion_USE_LLVM)
  if(Legion_LINK_LLVM_LIBS)
    target_link_libraries(RealmRuntime PRIVATE LLVM::LLVM)
    target_link_libraries(RealmStatic PRIVATE LLVM::LLVM)
  else()
    # even if we dont link, we still need the LLVM include directories
    get_target_property(llvm_incdir LLVM::LLVM INTERFACE_INCLUDE_DIRECTORIES)
    target_include_directories(RealmRuntime PRIVATE ${llvm_incdir})
    target_include_directories(RealmStatic PRIVATE ${llvm_incdir})
  endif()
endif()

if(Legion_USE_CUDA)
  if(REALM_USE_CUDART_HIJACK)
    if(Legion_USE_Kokkos)
      # we need kokkos to depend on the hijack without creating a circular
      # dependency, so put it in an object library - this works only on newer
      # cmakes, but we already need cmake 3.13 for Kokkos, so this is ok
      add_library(realm_cudarthijack OBJECT
        realm/cuda/cudart_hijack.cc
        realm/cuda/cudart_hijack.h)
      set_target_properties(realm_cudarthijack PROPERTIES POSITION_INDEPENDENT_CODE ON)
      if(REALM_LIMIT_SYMBOL_VISIBILITY)
        set_target_properties(realm_cudarthijack PROPERTIES CXX_VISIBILITY_PRESET hidden)
        set_target_properties(realm_cudarthijack PROPERTIES VISIBILITY_INLINES_HIDDEN 1)
      endif()
      target_link_libraries(realm_cudarthijack PRIVATE CUDA::toolkit)
      target_include_directories(realm_cudarthijack
                         PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
                                 ${PROJECT_BINARY_DIR}/runtime)
      target_link_libraries(RealmRuntime PRIVATE realm_cudarthijack)
      target_link_libraries(RealmStatic PRIVATE realm_cudarthijack)
      install(TARGETS realm_cudarthijack EXPORT LegionTargets)
    else()
      # without Kokkos interop, we can just add the hijack directly
      target_sources(RealmRuntime PRIVATE realm/cuda/cudart_hijack.cc)
    endif()
  else()
    if(REALM_CUDA_DYNAMIC_LOAD)
      target_link_libraries(RealmRuntime INTERFACE CUDA::cudart)
      target_link_libraries(RealmStatic INTERFACE CUDA::cudart)
    else()
      target_link_libraries(RealmRuntime INTERFACE CUDA::cudart_static)
      target_link_libraries(RealmStatic INTERFACE CUDA::cudart_static)
    endif()
  endif()

  target_link_libraries(RealmRuntime PUBLIC CUDA::toolkit)
  target_link_libraries(RealmStatic PUBLIC CUDA::toolkit)
  # Advertise our driver link to Realm consumers while ensuring libcuda.so isn't in Realm's RPATH
  target_link_libraries(RealmRuntime INTERFACE CUDA::cuda_driver)
  target_link_libraries(RealmStatic INTERFACE CUDA::cuda_driver)
  # for backwards compatibility in applications
  target_compile_definitions(RealmRuntime INTERFACE USE_CUDA)
  target_compile_definitions(RealmStatic INTERFACE USE_CUDA)

  set_target_cuda_standard(RealmRuntime STANDARD ${Legion_CUDA_STANDARD})
  set_target_cuda_architectures(RealmRuntime ARCHITECTURES ${Legion_CUDA_ARCH})
  set_target_cuda_standard(RealmStatic STANDARD ${Legion_CUDA_STANDARD})
  set_target_cuda_architectures(RealmStatic ARCHITECTURES ${Legion_CUDA_ARCH})

  # build cuda hook library
  add_library(realm_cuhook SHARED
    realm/cuda/cuda_hook.cc)
  set_target_properties(realm_cuhook PROPERTIES POSITION_INDEPENDENT_CODE ON)
  if(REALM_LIMIT_SYMBOL_VISIBILITY)
    set_target_properties(realm_cuhook PROPERTIES CXX_VISIBILITY_PRESET hidden)
    set_target_properties(realm_cuhook PROPERTIES VISIBILITY_INLINES_HIDDEN 1)
  endif()
  target_include_directories(realm_cuhook PRIVATE
                            ${CMAKE_CURRENT_SOURCE_DIR}
                            ${PROJECT_BINARY_DIR}/runtime)
  target_link_libraries(realm_cuhook PUBLIC CUDA::toolkit)
  add_dependencies(RealmRuntime realm_cuhook)
  install(TARGETS realm_cuhook EXPORT LegionTargets)
endif()

if(Legion_USE_HIP)
  if (Legion_HIP_TARGET STREQUAL "CUDA")
    if(REALM_USE_HIP_HIJACK)
      target_sources(RealmRuntime PRIVATE realm/hip/hip_hijack.cc)
    endif()

    target_link_libraries(RealmRuntime PUBLIC CUDA::toolkit)
    # Advertise our driver link to Realm consumers while ensuring libcuda.so isn't in Realm's RPATH
    target_link_libraries(RealmRuntime INTERFACE CUDA::cuda_driver)
    target_include_directories(RealmRuntime PRIVATE ${HIP_ROOT_DIR}/include)
    # for backwards compatibility in applications
    target_compile_definitions(RealmRuntime INTERFACE USE_HIP)

    target_compile_definitions(RealmRuntime PRIVATE __HIP_PLATFORM_NVIDIA__)
  endif()

  if (Legion_HIP_TARGET STREQUAL "ROCM")
    if(REALM_USE_HIP_HIJACK)
      target_sources(RealmRuntime PRIVATE realm/hip/hip_hijack.cc)
    endif()

    set(HIP_LIBRARIES ${HIP_ROOT_DIR}/lib/libamdhip64.so)
    target_include_directories(RealmRuntime PRIVATE ${HIP_INCLUDE_DIRS})
    target_link_libraries(RealmRuntime PRIVATE ${HIP_LIBRARIES})
    # for backwards compatibility in applications
    target_compile_definitions(RealmRuntime INTERFACE USE_HIP)

    target_compile_definitions(RealmRuntime PRIVATE __HIP_PLATFORM_AMD__)
  endif()
endif()

# fetches a specified property list from the target, performs per-element
#  replacement of the items in the list, and then write the list back to
#  the target's property
# importantly, this works on properies of imported targets...
macro(edit_target_property tgtname propname pattern replacement)
  get_property(has_prop TARGET ${tgtname} PROPERTY ${propname} SET)
  if(has_prop)
    get_property(prop_list TARGET ${tgtname} PROPERTY ${propname})
    if(NOT "${replacement}" STREQUAL "")
      list(TRANSFORM prop_list REPLACE ${pattern} ${replacement})
    else()
      list(FILTER prop_list EXCLUDE REGEX ${pattern})
    endif()
    set_property(TARGET ${tgtname} PROPERTY ${propname} "${prop_list}")
  endif()
endmacro()

if(Legion_USE_Kokkos)
  # realm/kokkos_interop.cc needs to be compiled like a kokkos application, so
  #  get kokkos' compile options, include dirs - do this by creating a subtarget
  #  that can import Kokkos::kokkoscore

  # unfortunately, building like Kokkos means using Kokkos' choice of C++
  #  compiler, and cmake really doesn't want to make that easy - we have to
  #  do the build as a custom command and construct the entire command line
  #  ourselves

  # start with compile options exported by kokkos, but we have to parse the
  #  generator expressions ourselves...
  get_property(kokkos_compile_options TARGET Kokkos::kokkoscore PROPERTY INTERFACE_COMPILE_OPTIONS)
  string(REGEX REPLACE "\\$<\\$<COMPILE_LANGUAGE:CXX>:([^<>]*)>" \\1 kokkos_compile_options "${kokkos_compile_options}")
  string(REGEX REPLACE "\\$<\\$<COMPILE_LANGUAGE:.+>:([^<>]*)>" "" kokkos_compile_options "${kokkos_compile_options}")

  # also do kokkos' compile features (or at least the one we understand)
  get_property(kokkos_compile_features TARGET Kokkos::kokkoscore PROPERTY INTERFACE_COMPILE_FEATURES)
  foreach(feature IN LISTS kokkos_compile_features)
    if(feature MATCHES "cxx_std_([0-9]+)")
      list(APPEND kokkos_compile_options "-std=c++${CMAKE_MATCH_1}")
    else()
      message(WARNING "unrecognized Kokkos compile feature: ${feature}")
    endif()
  endforeach()

  # now add on our own cxx flags, dealing with the whole strings vs lists thing
  set(cxx_flags_as_list ${CMAKE_CXX_FLAGS} -fPIC ${CXX_BUILD_WARNING_FLAGS})
  if(CMAKE_BUILD_TYPE STREQUAL "Debug")
    string(APPEND cxx_flags_as_list " ${CMAKE_CXX_FLAGS_DEBUG}")
  endif()
  if(CMAKE_BUILD_TYPE STREQUAL "Release")
    string(APPEND cxx_flags_as_list " ${CMAKE_CXX_FLAGS_RELEASE}")
  endif()
  separate_arguments(cxx_flags_as_list)
  list(APPEND kokkos_compile_options ${cxx_flags_as_list})

  # next up is include directories...
  get_property(kokkos_include_dirs
               TARGET Kokkos::kokkoscore
               PROPERTY INTERFACE_INCLUDE_DIRECTORIES)
  list(TRANSFORM kokkos_include_dirs PREPEND "-I")
  list(APPEND kokkos_compile_options ${kokkos_include_dirs}
                                     "-I${CMAKE_CURRENT_SOURCE_DIR}"
                                     "-I${PROJECT_BINARY_DIR}/runtime")

  if(REALM_LIMIT_SYMBOL_VISIBILITY)
    # control symbol visibility
    list(APPEND kokkos_compile_options "-fvisibility=hidden" "-fvisibility-inlines-hidden")
  endif()

  if(Legion_USE_OpenMP AND (Kokkos_VERSION_MAJOR GREATER_EQUAL 4))
    # hack the kokkos_compile_options because -Xcompiler and -fopenmp are no longer
    #   added by INTERFACE_COMPILE_OPTIONS, so we will added them ourselved
    if(Legion_USE_CUDA)
      list(APPEND kokkos_compile_options "-Xcompiler")
      message(STATUS "Looking ${kokkos_compile_options}")
    endif()
    list(APPEND kokkos_compile_options "${OpenMP_CXX_FLAGS}")
  endif()

  # and then finally, tell clang (if it is clang) where to find CUDA
  if(Legion_USE_CUDA AND (KOKKOS_CXX_COMPILER MATCHES ".*clang.*"))
    list(APPEND kokkos_compile_options "--cuda-path=${CUDAToolkit_LIBRARY_ROOT}")
  endif()

  # now define our custom build command
  add_custom_command(OUTPUT realm_kokkos_interop.cc.o
                     COMMAND ${KOKKOS_CXX_COMPILER}
                             ${kokkos_compile_options}
                             -c ${CMAKE_CURRENT_SOURCE_DIR}/realm/kokkos_interop.cc
                             -o ${CMAKE_CURRENT_BINARY_DIR}/realm_kokkos_interop.cc.o
                     IMPLICIT_DEPENDS CXX ${CMAKE_CURRENT_SOURCE_DIR}/realm/kokkos_interop.cc
                     VERBATIM)

  # add our object file to the realm library
  target_sources(RealmRuntime PRIVATE
                 ${CMAKE_CURRENT_BINARY_DIR}/realm_kokkos_interop.cc.o)

  # and add kokkos libraries to our exported library requirements
  set_property(TARGET RealmRuntime APPEND
    PROPERTY INTERFACE_LINK_LIBRARIES "\$<LINK_ONLY:Kokkos::kokkoscore>")

  # if Kokkos' CUDA target is enabled, and we're performing runtime hijack,
  #  rewrite Kokkos' cudart dependency to be on Realm instead
  if(Kokkos_ENABLE_CUDA AND Legion_HIJACK_CUDART)
    edit_target_property(Kokkos::CUDA INTERFACE_LINK_LIBRARIES .*cudart.* realm_cudarthijack)
  endif()

  # similarly, if Kokkos' OpenMP target is enabled but we're using Realm's
  #  OpenMP runtime implementation, remove anything mentioning openmp from
  #  the exported link options (don't mess with compile options though)
  if(Kokkos_ENABLE_OPENMP AND Legion_USE_OpenMP AND NOT Legion_OpenMP_SYSTEM_RUNTIME)
    edit_target_property(Kokkos::kokkoscore INTERFACE_LINK_OPTIONS .*openmp.* "")
    edit_target_property(Kokkos::kokkoscontainers INTERFACE_LINK_OPTIONS .*openmp.* "")
  endif()
endif()

if(Legion_USE_HDF5)
  target_include_directories(RealmRuntime PRIVATE ${HDF5_INCLUDE_DIRS})
  target_link_libraries(RealmRuntime PRIVATE ${HDF5_LIBRARIES})
  # for backwards compatibility in applications
  target_compile_definitions(RealmRuntime INTERFACE USE_HDF)
endif()

if(Legion_USE_OpenMP)
  # only include -fopenmp (or equivalent) if we're using the
  #  system omp runtime libs
  if(Legion_OpenMP_SYSTEM_RUNTIME)
    target_link_libraries(RealmRuntime PUBLIC OpenMP::OpenMP_CXX)
  endif()
endif()

if(REALM_USE_NVTX)
  target_link_libraries(RealmRuntime PRIVATE CUDA::nvtx3)
endif()

if(Legion_BACKTRACE_USE_LIBDW)
  target_include_directories(RealmRuntime PRIVATE ${LIBDW_INCLUDE_DIR})
  target_link_libraries(RealmRuntime PRIVATE ${LIBDW_LIBRARY})
  target_include_directories(RealmStatic PRIVATE ${LIBDW_INCLUDE_DIR})
  target_link_libraries(RealmStatic PRIVATE ${LIBDW_LIBRARY})
endif()

set_target_properties(RealmRuntime PROPERTIES OUTPUT_NAME "realm${INSTALL_SUFFIX}")
set_target_properties(RealmStatic PROPERTIES OUTPUT_NAME "realm${INSTALL_SUFFIX}_static")

target_include_directories(RealmRuntime
  INTERFACE
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
    $<INSTALL_INTERFACE:include>
  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}

  # Include paths for generated header files.
  INTERFACE
    $<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/runtime>
  PRIVATE
    ${PROJECT_BINARY_DIR}/runtime
)

target_include_directories(RealmStatic
  INTERFACE
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
    $<INSTALL_INTERFACE:include>
  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}

  # Include paths for generated header files.
  INTERFACE
    $<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/runtime>
  PRIVATE
    ${PROJECT_BINARY_DIR}/runtime
)

install(TARGETS RealmRuntime EXPORT LegionTargets
  LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
  ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)

# Mapper objects
list(APPEND MAPPER_SRC
  mappers/default_mapper.h     mappers/default_mapper.cc
  mappers/default_mapper.inl
  mappers/mapping_utilities.h  mappers/mapping_utilities.cc
  mappers/shim_mapper.h        mappers/shim_mapper.cc
  mappers/test_mapper.h        mappers/test_mapper.cc
  mappers/null_mapper.h        mappers/null_mapper.cc
  mappers/replay_mapper.h      mappers/replay_mapper.cc
  mappers/debug_mapper.h       mappers/debug_mapper.cc
  mappers/wrapper_mapper.h     mappers/wrapper_mapper.cc
  mappers/forwarding_mapper.h  mappers/forwarding_mapper.cc
  mappers/logging_wrapper.h    mappers/logging_wrapper.cc
)

# Legion runtime
list(APPEND LEGION_SRC
  legion.h
  legion/bitmask.h
  legion/garbage_collection.h             legion/garbage_collection.cc
  legion/index_space_value.h              legion/index_space_value.cc
  legion/legion_allocation.h
  legion/legion_analysis.h                legion/legion_analysis.cc
  legion/legion_c.h                       legion/legion_c.cc
  legion/legion_config.h
  legion/legion_constraint.h              legion/legion_constraint.cc
  legion/legion_context.h                 legion/legion_context.cc
  legion/legion_c_util.h
  legion/legion.cc
  legion/legion.inl
  legion/legion_domain.h
  legion/legion_domain.inl
  legion/legion_instances.h               legion/legion_instances.cc
  legion/legion_mapping.h                 legion/legion_mapping.cc
  legion/legion_ops.h                     legion/legion_ops.cc
  legion/legion_profiling.h               legion/legion_profiling.cc
  legion/legion_profiling_serializer.h    legion/legion_profiling_serializer.cc
  legion/legion_profiling_version.h
  legion/legion_replication.h             legion/legion_replication.cc
  legion/legion_spy.h                     legion/legion_spy.cc
  legion/legion_tasks.h                   legion/legion_tasks.cc
  legion/legion_trace.h                   legion/legion_trace.cc
  legion/legion_types.h
  legion/legion_utilities.h
  legion/legion_views.h                   legion/legion_views.cc
  legion/legion_redop.h                   legion/legion_redop.cc
  legion/mapper_manager.h                 legion/mapper_manager.cc
  legion/region_tree.h                    legion/region_tree.cc
  legion/runtime.h                        legion/runtime.cc
)

if(Legion_USE_HIP)
  list(APPEND LEGION_SRC hip_cuda_compat/hip_cuda.h)
endif()

if(Legion_REDOP_HALF)
  list(APPEND LEGION_SRC mathtypes/half.h)
endif()

if(Legion_REDOP_COMPLEX)
  list(APPEND LEGION_SRC mathtypes/complex.h)
endif()

if(Legion_USE_CUDA)
  list(APPEND LEGION_SRC
    legion/legion_redop.cu
  )
endif()

if(Legion_USE_HIP)
  list(APPEND LEGION_HIP_SRC
    legion/legion_redop.cu
  )
endif()

# generate per-dimension object files for deppart stuff
foreach(INST_N1 RANGE 1 ${LEGION_MAX_DIM})
  # use cmake's configure_file for a portable way of creating wrapper
  #  source files
  set(SRCFILE legion/region_tree)
  configure_file(${PROJECT_SOURCE_DIR}/cmake/deppart_tmpl.cc.in ${SRCFILE}_${INST_N1}.cc)
  list(APPEND LEGION_SRC ${SRCFILE}_${INST_N1}.cc)

  foreach(INST_N2 RANGE 1 ${LEGION_MAX_DIM})
    configure_file(${PROJECT_SOURCE_DIR}/cmake/deppart_tmpl.cc.in ${SRCFILE}_${INST_N1}_${INST_N2}.cc)
    list(APPEND LEGION_SRC ${SRCFILE}_${INST_N1}_${INST_N2}.cc)
  endforeach()
  unset(SRCFILE)
endforeach()

# Legion Fortran
if(Legion_USE_Fortran)
  list(APPEND LEGION_FORTRAN_SRC
    legion/legion_f_types.f90
    legion/legion_f_c_interface.f90
    legion/legion_f.f90
  )
endif()

# HACK: completely separating the Legion and Realm cmake stuff will take
#  a while, so just exclude LegionRuntime from the "all" target for the
#  Realm-only case for now
if(Legion_BUILD_REALM_ONLY)
  set(EXCLUDE_LEGION EXCLUDE_FROM_ALL)
endif()

add_library(LegionRuntime ${EXCLUDE_LEGION} ${MAPPER_SRC} ${LEGION_SRC} ${LEGION_FORTRAN_SRC})
add_library(Legion::LegionRuntime ALIAS LegionRuntime)

# Add CUDA-specific properties
if(Legion_USE_CUDA)
  target_compile_options(LegionRuntime PRIVATE $<$<COMPILE_LANG_AND_ID:CUDA,NVIDIA>:
                         -Xcudafe=--diag_suppress=boolean_controlling_expr_is_constant>)

  set_target_cuda_warnings_and_errors(LegionRuntime WARN_AS_ERROR ${Legion_BUILD_WARN_AS_ERROR})

  if(Legion_REDOP_COMPLEX)
    # libcudacxx is required for complex reductions; let cmake find it.
    # By including this before the CUDA headers we make sure the libcudacxx
    # installation we pass to cmake will take priority against whatever version
    # is bundled with CUDA.
    find_package(libcudacxx CONFIG)
    if(libcudacxx_FOUND)
      if(${LIBCUDACXX_VERSION} VERSION_LESS "1.8.0")
        # cuda::std::complex started working properly in libcudacxx 1.8.0
        message(FATAL_ERROR "Legion_REDOP_COMPLEX requires libcudacxx >= 1.8.0 (found ${LIBCUDACXX_VERSION})")
      endif()
      target_link_libraries(LegionRuntime PUBLIC libcudacxx::libcudacxx)
    else()
      # If we can't find a standalone libcudacxx then don't do anything and just
      # let the build pick up the version that comes bundled with CUDA. But make
      # sure CUDA is recent enough to include a libcudacxx with a working
      # implementation of cuda::std::complex.
      if(${CUDAToolkit_VERSION} VERSION_LESS "11.7")
        message(FATAL_ERROR "Legion_REDOP_COMPLEX requires CUDA >= 11.7 (found ${CUDAToolkit_VERSION}) or libcudacxx >= 1.8.0")
      endif()
    endif()
    # complex reduction ops bring in a public dependency on cuda headers
    target_link_libraries(LegionRuntime PUBLIC CUDA::toolkit)
  endif()

  set_target_cuda_standard(LegionRuntime STANDARD ${Legion_CUDA_STANDARD})
  set_target_cuda_architectures(LegionRuntime ARCHITECTURES ${Legion_CUDA_ARCH})
endif()

if(Legion_USE_HIP)
  if(Legion_HIP_TARGET STREQUAL "CUDA")
    target_sources(LegionRuntime PRIVATE ${LEGION_HIP_SRC})
    target_compile_options(LegionRuntime PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:
                           -Xcudafe=--diag_suppress=boolean_controlling_expr_is_constant>)
    target_include_directories(LegionRuntime PRIVATE ${HIP_ROOT_DIR}/include)
    # complex reduction ops bring in a public dependency on cuda headers
    if(Legion_REDOP_COMPLEX)
      target_link_libraries(LegionRuntime PUBLIC CUDA::toolkit)
      target_compile_definitions(LegionRuntime PUBLIC __HIP_PLATFORM_NVIDIA__)
    endif()
  elseif(Legion_HIP_TARGET STREQUAL "ROCM")
    set(HIP_LIBRARIES ${HIP_ROOT_DIR}/lib/libamdhip64.so)
    set_source_files_properties(${LEGION_HIP_SRC} PROPERTIES HIP_SOURCE_PROPERTY_FORMAT 1)
    hip_compile(LEGION_HIP_OBJS ${LEGION_HIP_SRC} HIPCC_OPTIONS
      ${HIPCC_FLAGS}
      ${HIP_GENCODE}
      -I ${CMAKE_CURRENT_SOURCE_DIR}
      -I ${CMAKE_CURRENT_SOURCE_DIR}/legion
      -I ${PROJECT_BINARY_DIR}/runtime
      -fPIC
      DEBUG -g
      RELEASE -O2
      RELWITHDEBINFO -g -O2)
    target_sources(LegionRuntime PRIVATE ${LEGION_HIP_OBJS})
    target_link_libraries(LegionRuntime PUBLIC ${HIP_LIBRARIES})

    # complex reduction ops bring in a public dependency on hip thrust headers
    if(Legion_REDOP_COMPLEX)
      # set thrust package
      # please download thrust from https://github.com/ROCmSoftwarePlatform/Thrust
      if(NOT DEFINED THRUST_PATH)
        set(THRUST_PATH $ENV{THRUST_PATH} CACHE PATH "Path to where Thrust has been installed")
      endif()
      target_include_directories(LegionRuntime PUBLIC ${HIP_INCLUDE_DIRS})
      target_compile_definitions(LegionRuntime PUBLIC __HIP_PLATFORM_AMD__)
    else()
      target_include_directories(LegionRuntime PRIVATE ${HIP_INCLUDE_DIRS})
      target_compile_definitions(LegionRuntime PRIVATE __HIP_PLATFORM_AMD__)
    endif()
  endif()
endif()

target_link_libraries(LegionRuntime PUBLIC RealmRuntime)
if(Legion_USE_ZLIB)
  target_link_libraries(LegionRuntime PRIVATE ZLIB::ZLIB)
endif()
set_target_properties(LegionRuntime PROPERTIES POSITION_INDEPENDENT_CODE ON)
set_target_properties(LegionRuntime PROPERTIES OUTPUT_NAME "legion${INSTALL_SUFFIX}")
set_target_properties(LegionRuntime PROPERTIES SOVERSION ${SOVERSION})
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
  target_link_libraries(LegionRuntime PUBLIC atomic)
  set_property(TARGET LegionRuntime APPEND PROPERTY BUILD_RPATH "\$ORIGIN")
  set_property(TARGET LegionRuntime APPEND PROPERTY INSTALL_RPATH "\$ORIGIN")
elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
  set_property(TARGET LegionRuntime APPEND PROPERTY BUILD_RPATH "@loader_path")
  set_property(TARGET LegionRuntime APPEND PROPERTY INSTALL_RPATH "@loader_path")
endif ()

target_compile_options(LegionRuntime PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${CXX_BUILD_WARNING_FLAGS}>)
if(COMPILER_SUPPORTS_DEFCHECK)
  # use the cxx_defcheck wrapper to make sure legion_defines.h is included
  #  any place it needs to be
  target_compile_options(LegionRuntime PRIVATE $<$<COMPILE_LANGUAGE:CXX>:--defcheck;legion_defines.h>)
endif()

# compiler options' check for realm
check_cxx_compiler_flag("-Wdeprecated" COMPILER_SUPPORTS_CXX_WDEPRECATED)
if(COMPILER_SUPPORTS_CXX_WDEPRECATED)
  target_compile_options(RealmRuntime PRIVATE -Wdeprecated)
endif()
check_cxx_compiler_flag("-Wformat-pedantic" COMPILER_SUPPORTS_CXX_FORMAT_PEDENTIC)
if(COMPILER_SUPPORTS_CXX_FORMAT_PEDENTIC)
  target_compile_options(RealmRuntime PRIVATE -Wformat-pedantic)
endif()



target_include_directories(LegionRuntime
  INTERFACE
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/mappers>
    $<INSTALL_INTERFACE:include>
    $<INSTALL_INTERFACE:include/mappers>
  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}

  # Include paths for generated header files.
  INTERFACE
    $<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/runtime>
  PRIVATE
    ${PROJECT_BINARY_DIR}/runtime
)

install(TARGETS LegionRuntime EXPORT LegionTargets
  LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
  ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)

add_library(Legion INTERFACE)
set_target_properties(Legion PROPERTIES
  INTERFACE_LINK_LIBRARIES LegionRuntime
)
add_library(Realm INTERFACE)
set_target_properties(Realm PROPERTIES
  INTERFACE_LINK_LIBRARIES RealmRuntime
)
install(TARGETS Legion Realm EXPORT LegionTargets)

if (Legion_BUILD_DOCS)
  set(DOXYGEN_STRIP_FROM_INC_PATH ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
  set(DOXYGEN_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/legion_docs)
  set(DOXYGEN_PROJECT_NAME "Legion")
  set(DOXYGEN_PROJECT_NUMBER ${LEGION_VERSION})
  configure_file(${CMAKE_SOURCE_DIR}/doxygen/selectversion.js.in ${CMAKE_BINARY_DIR}/legion_docs/selectversion.js @ONLY)
  # TODO(mbauer): Annotate and or list all public legion headers
  doxygen_add_docs(LegionDocs
      ${CMAKE_CURRENT_SOURCE_DIR}/legion.h
      ${CMAKE_CURRENT_SOURCE_DIR}/legion
      ${CMAKE_CURRENT_BINARY_DIR}/legion_defines.h
      COMMENT "Generating Legion Documentation" ALL)

  set(DOXYGEN_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/realm_docs)
  set(DOXYGEN_PROJECT_NAME "Realm")
  set(DOXYGEN_PROJECT_NUMBER ${REALM_VERSION})
  set(DOXYGEN_INCLUDE_PATH ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
  set(DOXYGEN_FILE_PATTERNS "*.h")
  configure_file(${CMAKE_SOURCE_DIR}/doxygen/selectversion.js.in ${CMAKE_BINARY_DIR}/realm_docs/selectversion.js @ONLY)
  if (NOT DOXYGEN_INTERNAL_DOCS)
    # TODO(cperry): Remove this when we properly annotate all public and headers
    set(DOXYGEN_EXCLUDE_SYMBOLS "Realm::*Impl" "Realm::*Internal" "std::*" "*::detail::*")
    set(DOXYGEN_EXCLUDE_PATTERNS "*_internal.h")
  else()
    list(APPEND DOXYGEN_FILE_PATTERNS "*.inl" "*.cc" "*.c")
  endif()
  doxygen_add_docs(RealmDocs
      ${CMAKE_CURRENT_SOURCE_DIR}/realm.h
      ${CMAKE_CURRENT_SOURCE_DIR}/realm
      ${CMAKE_CURRENT_BINARY_DIR}/realm_defines.h
      COMMENT "Generating Realm Documentation" ALL)

  install(DIRECTORY "${CMAKE_BINARY_DIR}/legion_docs/html/" DESTINATION "${CMAKE_INSTALL_DOCDIR}/Legion/${LEGION_VERSION}" COMPONENT Legion_doc)
  install(DIRECTORY "${CMAKE_BINARY_DIR}/realm_docs/html/" DESTINATION "${CMAKE_INSTALL_DOCDIR}/Realm/${REALM_VERSION}" COMPONENT Realm_doc)
  install(FILES "${CMAKE_BINARY_DIR}/realm_docs/selectversion.js" "${CMAKE_SOURCE_DIR}/doxygen/dropdown.css" DESTINATION "${CMAKE_INSTALL_DOCDIR}/Realm" COMPONENT Realm_doc)
  install(FILES "${CMAKE_BINARY_DIR}/legion_docs/selectversion.js" "${CMAKE_SOURCE_DIR}/doxygen/dropdown.css" DESTINATION "${CMAKE_INSTALL_DOCDIR}/Legion" COMPONENT Legion_doc)
endif ()