typeart_find_llvm_progs(TYPEART_FILECHECK_EXEC "FileCheck-${LLVM_VERSION_MAJOR};FileCheck" ABORT_IF_MISSING)

find_package(Python3 COMPONENTS Interpreter)

if(LLVM_EXTERNAL_LIT)
  cmake_path(GET LLVM_EXTERNAL_LIT PARENT_PATH LLVM_EXTERNAL_LIT_DIR)
endif()

typeart_find_llvm_progs(TYPEART_LIT_EXEC
  "llvm-lit;lit;lit.py"
  HINTS ${LLVM_EXTERNAL_LIT_DIR} /usr/lib/llvm-${LLVM_VERSION_MAJOR} /usr/lib/llvm /usr/bin /usr/local/bin /opt/local/bin
  ABORT_IF_MISSING
)

# add_subdirectory(compat)

macro(pythonize_bool truth_var var)
  if(${truth_var})
    set(${var} True)
  else()
    set(${var} False)
  endif()
endmacro()

function(typeart_configure_lit_site input output)
  # This function provides an automatic way to 'configure'-like generate a file
  # based on a set of common and custom variables, specifically targeting the
  # variables needed for the 'lit.site.cfg' files. This function bundles the
  # common variables that any Lit instance is likely to need, and custom
  # variables can be passed in.

  set(TYPEARTPASS_PROJECT_DIR ${PROJECT_SOURCE_DIR})
  set(TYPEARTPASS_BINARY_DIR ${CMAKE_BINARY_DIR})
  set(TYPEARTPASS_SCRIPT_DIR ${CMAKE_BINARY_DIR}/scripts)
  set(TYPEARTPASS_LIBRARY_DIR ${CMAKE_BINARY_DIR}/lib/passes)
  set(TYPEARTPASS_BASE_LIBRARY_DIR ${CMAKE_BINARY_DIR}/lib)
  set(TYPEARTPASS_RT_DIR ${CMAKE_BINARY_DIR}/lib/runtime)
  set(TYPEARTPASS_PROFILE_FILE ${TYPEART_PROFILE_DIR}/lit-code-%p.profraw)

  pythonize_bool(TYPEART_SOFTCOUNTERS TYPEARTPASS_SOFTCOUNTER)

  pythonize_bool(OPENMP_FOUND TYPEARTPASS_OPENMP)
  pythonize_bool(Threads_FOUND TYPEARTPASS_THREADS)
  pythonize_bool(TYPEART_DISABLE_THREAD_SAFETY TYPEARTPASS_THREAD_UNSAFE)

  pythonize_bool(MPI_C_FOUND TYPEARTPASS_MPI_C)
  pythonize_bool(MPI_CXX_FOUND TYPEARTPASS_MPI_CXX)

  pythonize_bool(TYPEART_TSAN TYPEARTPASS_TSAN)
  pythonize_bool(TYPEART_ASAN TYPEARTPASS_ASAN)
  pythonize_bool(TYPEART_UBSAN TYPEARTPASS_UBSAN)

  set(TYPEART_COVERAGE False)
  if(TYPEART_CODE_COVERAGE OR TYPEART_LLVM_CODE_COVERAGE)
    set(TYPEART_COVERAGE True)
  endif()

  set(TYPEART_USE_NEW_PM True)
  set(TYPEART_OPT_EXEC "${CMAKE_BINARY_DIR}/scripts/opt-shim")

  pythonize_bool(TYPEART_USE_LEGACY_WRAPPER TYPEARTPASS_LEGACY_WRAPPER)

  set(LIT_SITE_CFG_IN_HEADER
      "## Autogenerated by TypeART generation from ${input}\n## Do not edit!"
  )

  typeart_target_generate_file(${input} ${output})
endfunction()

typeart_add_format_target(typeart-format-tests
  "Formats project test source files"
  TARGETS *.c *.cpp *.h
)

typeart_configure_lit_site(
  ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
  ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
)

function(typeart_add_lit_testsuite target comment)
  cmake_parse_arguments(ARG "" "" "PARAMS;DEPENDS;ARGS" ${ARGN})

  foreach(param ${ARG_PARAMS})
    list(APPEND TEST_PARAMS --param ${param})
  endforeach()

  add_custom_target(${target}
    COMMAND ${TYPEART_LIT_EXEC} ${ARG_ARGS} ${TEST_PARAMS} ${ARG_UNPARSED_ARGUMENTS}
    COMMENT "${comment}"
    USES_TERMINAL
  )

  if (ARG_DEPENDS)
    add_dependencies(${target} ${ARG_DEPENDS})
  endif()
endfunction()

function(typeart_add_lit_target)
  cmake_parse_arguments(ARG "" "" "SUITES;WORKERS" ${ARGN})

  foreach(suite workers IN ZIP_LISTS ARG_SUITES ARG_WORKERS)
    if("${suite}" STREQUAL "all")
      set(SUITE_PATH ${CMAKE_CURRENT_SOURCE_DIR})
      set(TARGET_NAME check-typeart)
    else()
      if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${suite})
        continue()
      endif()
      set(SUITE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/${suite})
      set(TARGET_NAME check-typeart-${suite})
    endif()

    if(NOT EXISTS ${SUITE_PATH})
      message(WARNING "Could not find suitable lit test target at ${SUITE_PATH}")
      continue()
    endif()

    typeart_add_lit_testsuite(${TARGET_NAME}
      "Running the lit suite TypeART::${suite}"
      ${SUITE_PATH}
      ARGS --show-unsupported -v -j ${workers}
      PARAMS typeartpass_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
      DEPENDS ${TYPEART_TEST_DEPENDS}
    )
  endforeach()
endfunction()

set(TYPEART_TEST_DEPENDS
  typeart::TransformPass
  typeart::Runtime
  typeart::Types
)

include(ProcessorCount)
ProcessorCount(NUM_CPU)
if(NUM_CPU EQUAL 0)
  set(NUM_CPU 1)
elseif(NUM_CPU GREATER_EQUAL 8)
  set(NUM_CPU 8)
endif()

set(TYPEART_SUITES
  all
  pass
  runtime
  script
  typemapping
  staging
)

set(TYPEART_SUITES_WORKERS
  1
  ${NUM_CPU}
  1
  1
  ${NUM_CPU}
  1
)

typeart_add_lit_target(SUITES ${TYPEART_SUITES} WORKERS ${TYPEART_SUITES_WORKERS})

add_test(
  NAME typeart-lit-suite
  COMMAND
    ${TYPEART_LIT_EXEC} -j 1 --param
    typeartpass_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
    ${CMAKE_CURRENT_SOURCE_DIR}
)

if(TYPEART_TEST_CONFIGURE_IDE)
  function(add_test_target_ide target header sources compile_std linker_language)
    if(NOT sources)
      return()
    endif()

    add_executable(${target} EXCLUDE_FROM_ALL ${header} ${sources})

    target_include_directories(
      ${target} PRIVATE ${PROJECT_SOURCE_DIR}/lib/typelib
                        ${PROJECT_SOURCE_DIR}/lib/runtime
                        ${PROJECT_SOURCE_DIR}
    )
    target_compile_features(${target} PUBLIC ${compile_std})
    set_target_properties(${target} PROPERTIES LINKER_LANGUAGE ${linker_language})
  endfunction()

  file(GLOB_RECURSE TYPEART_CXX_TESTS CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
  file(GLOB_RECURSE TYPEART_CC_TESTS CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/*.c)
  file(GLOB_RECURSE TYPEART_HEADER_TESTS CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/*.h)

  add_test_target_ide(typeart_cxx_test_objects
    "${TYPEART_HEADER_TESTS}" "${TYPEART_CXX_TESTS}"
    cxx_std_17 CXX
  )
  add_test_target_ide(typeart_cc_test_objects
    "${TYPEART_HEADER_TESTS}" "${TYPEART_CC_TESTS}"
    c_std_99 C
  )
endif()
