set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR arm)
set(CMAKE_CROSSCOMPILING 1)

if(NOT TOOLCHAIN_ROOT)
    set(TOOLCHAIN_ROOT ${CMAKE_CURRENT_LIST_DIR}/..)
endif()

set(TOOLCHAIN_LLVM_BIN ${TOOLCHAIN_ROOT}/bin)

set(TOOLCHAIN_TARGET_TRIPLE armv7em-none-eabi)
set(TOOLCHAIN_TARGET_FLAGS "--target=${TOOLCHAIN_TARGET_TRIPLE}")
set(TOOLCHAIN_CPU_FLAGS "-mcpu=cortex-m4 -mfpu=fpv4-sp-d16")
set(TOOLCHAIN_ABI_FLAGS "-mthumb -mabi=aapcs -mfloat-abi=hard")

set(CMAKE_SYSROOT ${TOOLCHAIN_ROOT}/armv7em-none-eabi/cortex-m4f)

set(TOOLCHAIN_C_INCLUDE_DIRS ${CMAKE_SYSROOT}/include)
set(TOOLCHAIN_CXX_INCLUDE_DIRS ${TOOLCHAIN_ROOT}/include/c++/v1/)
set(TOOLCHAIN_C_LIBRARY_DIRS ${CMAKE_SYSROOT}/lib ${TOOLCHAIN_ROOT}/lib ${TOOLCHAIN_ROOT}/lib/baremetal)
set(TOOLCHAIN_CXX_LIBRARY_DIRS)

# TODO: How to add CXX directories only to CXX compilation?
include_directories(SYSTEM ${TOOLCHAIN_C_INCLUDE_DIRS} ${TOOLCHAIN_CXX_INCLUDE_DIRS})
link_directories(${TOOLCHAIN_C_LIBRARY_DIRS} ${TOOLCHAIN_CXX_LIBRARY_DIRS})

set(CMAKE_C_COMPILER ${TOOLCHAIN_LLVM_BIN}/clang)
set(CMAKE_ASM_COMPILER ${TOOLCHAIN_LLVM_BIN}/clang)
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_LLVM_BIN}/clang++)

set(CMAKE_AR ${TOOLCHAIN_LLVM_BIN}/llvm-ar)
set(CMAKE_NM ${TOOLCHAIN_LLVM_BIN}/llvm-nm)
set(CMAKE_RANLIB ${TOOLCHAIN_LLVM_BIN}/llvm-ranlib)
set(CMAKE_READELF ${TOOLCHAIN_LLVM_BIN}/llvm-readelf)
set(CMAKE_SIZE_UTIL ${TOOLCHAIN_LLVM_BIN}/llvm-size)
set(CMAKE_OBJCOPY ${TOOLCHAIN_LLVM_BIN}/llvm-objcopy) # llvm-objcopy cannot create intel hex
set(CMAKE_OBJCOPY_NO_SUPPORT_FOR_INTEL_HEX TRUE)

set(CMAKE_C_FLAGS "${TOOLCHAIN_CPU_FLAGS} ${TOOLCHAIN_ABI_FLAGS}")
set(CMAKE_ASM_FLAGS "${CMAKE_C_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS}")

#set(CMAKE_EXE_LINKER_FLAGS "${TOOLCHAIN_TARGET_TRIPLE}")

#set(CMAKE_C_LINKER ${TOOLCHAIN_LLVM_BIN}/ld.lld)
#set(CMAKE_ASM_LINKER ${TOOLCHAIN_LLVM_BIN}/ld.lld)
#set(CMAKE_CXX_LINKER ${TOOLCHAIN_LLVM_BIN}/ld.lld)

if(TRUE)
    # It seems `link_directories` does not survive across the `project(...)` call.
    # The only way I managed to get those system link directories in
    # was by patching the link command itself.
    list(JOIN TOOLCHAIN_C_LIBRARY_DIRS " -L"  SYSTEM_LINKER_PATH_FLAGS)

    set(CMAKE_C_LINK_EXECUTABLE
        "<CMAKE_C_COMPILER> -L${SYSTEM_LINKER_PATH_FLAGS} <FLAGS> <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <OBJECTS>  -o <TARGET> <LINK_LIBRARIES>"
    )
    set(CMAKE_C_LINK_EXECUTABLE
        "<CMAKE_ASM_COMPILER> -L${SYSTEM_LINKER_PATH_FLAGS} <FLAGS> <CMAKE_ASM_LINK_FLAGS> <LINK_FLAGS> <OBJECTS>  -o <TARGET> <LINK_LIBRARIES>"
    )
    set(CMAKE_CXX_LINK_EXECUTABLE
        "<CMAKE_CXX_COMPILER> -L${SYSTEM_LINKER_PATH_FLAGS} <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS>  -o <TARGET> <LINK_LIBRARIES>"
    )
endif()

# Unfortunately, the target triplet is only applied when CMake knows that the compiler supports it.
# However, CMake only knows what compiler it has after the compiler tests.
# Without the triplet, the compiler tests fail.
if(FALSE)
    set(CMAKE_C_COMPILER_TARGET ${TOOLCHAIN_TARGET_TRIPLE})
    set(CMAKE_ASM_COMPILER_TARGET ${TOOLCHAIN_TARGET_TRIPLE})
    set(CMAKE_CXX_COMPILER_TARGET ${TOOLCHAIN_TARGET_TRIPLE})
else()
    set(CMAKE_C_FLAGS "${TOOLCHAIN_TARGET_FLAGS} ${CMAKE_C_FLAGS}")
    set(CMAKE_ASM_FLAGS "${TOOLCHAIN_TARGET_FLAGS} ${CMAKE_ASM_FLAGS}")
    set(CMAKE_CXX_FLAGS "${TOOLCHAIN_TARGET_FLAGS} ${CMAKE_CXX_FLAGS}")
endif()

set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)

set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)

message(STATUS "Loaded ARMv7em toolchain at ${TOOLCHAIN_ROOT}")
