cmake_minimum_required(VERSION 3.26)
project(corehost)

include(../../../eng/native/configurepaths.cmake)
include(${CLR_ENG_NATIVE_DIR}/configurecompiler.cmake)

set(COREHOST_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}")

option(CLR_CMAKE_BUILD_HOST_PRODUCT "Build host product components" ON)
option(CLR_CMAKE_BUILD_HOST_TESTS "Build host test components" OFF)

if (MSVC)
    # Host components don't try to handle asynchronous exceptions
    set_property(DIRECTORY PROPERTY CLR_EH_OPTION /EHsc)

    # Explicitly re-enable warnings about declaration hiding (currently disabled by configurecompiler.cmake)
    add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:/we4456>) # declaration of 'identifier' hides previous local declaration
    add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:/we4457>) # declaration of 'identifier' hides function parameter
    add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:/we4458>) # declaration of 'identifier' hides class member
    add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:/we4459>) # declaration of 'identifier' hides global declaration
elseif (CMAKE_CXX_COMPILER_ID MATCHES GNU)
    # Prevents libc from calling pthread_cond_destroy on static objects in
    # dlopen()'ed library which we dlclose() in pal::unload_library.
    add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-fno-use-cxa-atexit>)
endif()

set(CMAKE_INCLUDE_CURRENT_DIR ON)
include_directories(${CMAKE_CURRENT_BINARY_DIR})
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
include_directories(${CLR_ARTIFACTS_OBJ_DIR}) # Generated version files

if (NOT ${CLR_SINGLE_FILE_HOST_ONLY})
    if("${CLI_CMAKE_COMMIT_HASH}" STREQUAL "")
        message(FATAL_ERROR "Commit hash needs to be specified to build the host")
    endif()
endif()

if("${CLI_CMAKE_FALLBACK_OS}" STREQUAL "")
    message(FATAL_ERROR "Fallback rid needs to be specified to build the host")
endif()

if("${CLI_CMAKE_FALLBACK_OS}" STREQUAL "${CLR_CMAKE_TARGET_OS}")
    add_compile_definitions(FALLBACK_OS_IS_SAME_AS_TARGET_OS)
endif()

string(TOUPPER "${CLR_CMAKE_TARGET_ARCH}" CLR_CMAKE_TARGET_ARCH_UPPER)

# Find support libraries that we need if they're present on the system.
find_library(PTHREAD_LIB pthread)

# Prefer libatomic.a over libatomic.so.
set(_current_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
list(PREPEND CMAKE_FIND_LIBRARY_SUFFIXES .a)
find_library(ATOMIC_SUPPORT_LIB atomic)
set(CMAKE_FIND_LIBRARY_SUFFIXES ${_current_CMAKE_FIND_LIBRARY_SUFFIXES})
unset(_current_CMAKE_FIND_LIBRARY_SUFFIXES)

configure_file(configure.h.in ${CMAKE_CURRENT_BINARY_DIR}/configure.h)

# add_version_info_to_target(targetName [resourceDirName])
function(add_version_info_to_target targetName)
    set(RESOURCE_INCLUDE_DIR ${targetName})
    if (${ARGC} GREATER 1)
        set(RESOURCE_INCLUDE_DIR ${ARGV1})
    endif()

    if (CLR_CMAKE_TARGET_WIN32)
        target_sources(${targetName} PRIVATE ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/native.rc)
        set_property(SOURCE ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/native.rc
            TARGET_DIRECTORY ${targetName}
            APPEND PROPERTY INCLUDE_DIRECTORIES
            ${CLI_CMAKE_RESOURCE_DIR}/${RESOURCE_INCLUDE_DIR})
    else()
        target_sources(${targetName} PRIVATE ${VERSION_FILE_PATH})
    endif()
endfunction()

# This is required to map a symbol reference to a matching definition local to the module (.so)
# containing the reference instead of using definitions from other modules.
if(CLR_CMAKE_TARGET_LINUX OR CLR_CMAKE_TARGET_SUNOS)
    add_link_options(LINKER:-Bsymbolic)
endif()

if(NOT CLR_CMAKE_TARGET_BROWSER AND NOT CLR_CMAKE_TARGET_WASI)
    add_library(fxr_resolver INTERFACE)
    target_sources(fxr_resolver INTERFACE fxr_resolver.c)
    target_include_directories(fxr_resolver INTERFACE fxr)

    add_compile_definitions(RAPIDJSON_HAS_CXX17)

    if ((NOT DEFINED CLR_CMAKE_USE_SYSTEM_RAPIDJSON) OR (NOT CLR_CMAKE_USE_SYSTEM_RAPIDJSON))
        include_directories(${CLR_SRC_NATIVE_DIR}/external/)
    endif()

    add_subdirectory(${CLR_SRC_NATIVE_DIR}/minipal minipal)

    # minipal_objects is embedded into static libraries we ship for external
    # consumption (libnethost, libhostfxr), so LTCG must be disabled to ensure
    # that non-MSVC toolchains can work with them.
    set_target_properties(minipal_objects PROPERTIES INTERPROCEDURAL_OPTIMIZATION OFF)
    if (MSVC)
        # Embed debug info in the object files (/Z7). CMake does not assign a
        # compile PDB to OBJECT libraries, so the objects archived into the shipped
        # libnethost/libhostfxr would otherwise reference an absent vc140.pdb,
        # producing LNK4099 for consumers.
        set_target_properties(minipal_objects PROPERTIES MSVC_DEBUG_INFORMATION_FORMAT Embedded)
    endif()

    add_subdirectory(hostcommon)
    add_subdirectory(hostmisc)
    add_subdirectory(nethost)

    if(CLR_CMAKE_BUILD_HOST_PRODUCT)
        add_subdirectory(fxr)
        add_subdirectory(hostpolicy)
        add_subdirectory(apphost)
        add_subdirectory(dotnet)
    endif()
    if(CLR_CMAKE_BUILD_HOST_TESTS)
        add_subdirectory(test)
    endif()
elseif(CLR_CMAKE_TARGET_BROWSER)
    add_subdirectory(hostmisc)
    add_subdirectory(browserhost)
else() # CLR_CMAKE_TARGET_WASI
    # The wasi host is self-contained (shares the corerun pal header, no hostmisc dependency).
    add_subdirectory(wasihost)
endif()

# If there's a dynamic ASAN runtime, then install it in the directories where we put our executables.
if (NOT "${ASAN_RUNTIME}" STREQUAL "")
    if(CLR_CMAKE_BUILD_HOST_PRODUCT)
        install(FILES ${ASAN_RUNTIME} DESTINATION corehost)
    endif()
    if(CLR_CMAKE_BUILD_HOST_TESTS)
        install(FILES ${ASAN_RUNTIME} DESTINATION corehost_test)
    endif()
endif()

if(CLR_CMAKE_HOST_WIN32)
    add_subdirectory(ijwhost)
    if(CLR_CMAKE_BUILD_HOST_PRODUCT)
        add_subdirectory(comhost)
    endif()
endif()
