message(STATUS "Fetching keystone (this might take a while)...")
FetchContent_Declare(
    keystone
    GIT_REPOSITORY https://github.com/keystone-engine/keystone
    GIT_TAG        e1547852d9accb9460573eb156fc81645b8e1871
    GIT_SHALLOW    false
)

FetchContent_GetProperties(keystone)
if(NOT keystone_POPULATED)
    FetchContent_Populate(keystone)
endif()

# Do not modify a keystone target that already exists
if(TARGET keystone)
    return()
endif()

file(GLOB_RECURSE SOURCES CONFIGURE_DEPENDS
    ${keystone_SOURCE_DIR}/include/keystone/*.h
    ${keystone_SOURCE_DIR}/llvm/*.cpp
    ${keystone_SOURCE_DIR}/llvm/*.c
)

add_library(keystone ${SOURCES})

# Require C++11 because of keystone's code
set_property(TARGET keystone PROPERTY CXX_STANDARD 11)
set_property(TARGET keystone PROPERTY CXX_STANDARD_REQUIRED ON)

target_include_directories(keystone PUBLIC ${keystone_SOURCE_DIR}/include)

if(NOT BUILD_SHARED_LIBS)
    target_compile_definitions(keystone PUBLIC KEYSTONE_STATIC)
endif()

# Disable warnings on MSVC, as a user of keystone we don't care
if(MSVC)
    target_compile_options(keystone PRIVATE /W0 /wd4244 /wd4267)
endif()

# Add private include directories (both autogenerated and pre-generated) to make the LLVM parts of keystone happy
target_include_directories(keystone PRIVATE
    ${keystone_SOURCE_DIR}/llvm/include
    ${CMAKE_CURRENT_SOURCE_DIR}/include
    ${keystone_BINARY_DIR}/include
)

# Configure all of the various header file fragments LLVM uses which depend on
# configuration variables.
set(LLVM_TARGETS_TO_BUILD AArch64 ARM Hexagon Mips PowerPC Sparc SystemZ X86)
set(LLVM_ENUM_TARGETS "")
set(LLVM_ENUM_ASM_PARSERS "")
foreach(target ${LLVM_TARGETS_TO_BUILD})
    target_compile_definitions(keystone PRIVATE LLVM_ENABLE_ARCH_${target})
    target_include_directories(keystone PRIVATE ${keystone_SOURCE_DIR}/llvm/lib/Target/${target})

    set(LLVM_ENUM_TARGETS "${LLVM_ENUM_TARGETS}LLVM_TARGET(${target})\n")
    set(LLVM_ENUM_ASM_PARSERS "${LLVM_ENUM_ASM_PARSERS}LLVM_ASM_PARSER(${target})\n")
endforeach()

# Produce the target definition files, which provide a way for clients to easily
# include various classes of targets.
configure_file(
    ${keystone_SOURCE_DIR}/llvm/include/llvm/Config/AsmParsers.def.in
    ${keystone_BINARY_DIR}/include/llvm/Config/AsmParsers.def
)
configure_file(
    ${keystone_SOURCE_DIR}/llvm/include/llvm/Config/Targets.def.in
    ${keystone_BINARY_DIR}/include/llvm/Config/Targets.def
)
