cmake_minimum_required(VERSION 3.16)
project(tobi VERSION 0.1.0 LANGUAGES C)

option(TOBI_WERROR "Build with warnings as errors" ON)
option(TOBI_SAN "Build with AddressSanitizer and UndefinedBehaviorSanitizer" OFF)
option(TOBI_FZ "Build fuzz smoke target" ON)
option(TOBI_LIBFUZZER "Build LLVM libFuzzer target" OFF)

set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS OFF)

set(TOBI_COMMON
    src/rd.c src/p.c src/op.c src/nm.c src/ir.c src/cf.c src/dc.c
    src/da.c src/dg.c src/js.c src/mem.c src/str.c)

add_library(tobilib ${TOBI_COMMON})
target_include_directories(tobilib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src)
target_compile_definitions(tobilib PUBLIC _POSIX_C_SOURCE=200809L)

add_executable(tobi src/main.c)
target_link_libraries(tobi PRIVATE tobilib)

set(TOBI_WARN -Wall -Wextra -Wpedantic)
if(TOBI_WERROR)
  list(APPEND TOBI_WARN -Werror)
endif()
target_compile_options(tobilib PRIVATE ${TOBI_WARN})
target_compile_options(tobi PRIVATE ${TOBI_WARN})

if(TOBI_SAN)
  set(SAN_FLAGS -fsanitize=address,undefined -fno-omit-frame-pointer)
  target_compile_definitions(tobilib PUBLIC TOBI_SAN_BUILD=1)
  target_compile_options(tobilib PRIVATE ${SAN_FLAGS})
  target_compile_options(tobi PRIVATE ${SAN_FLAGS})
  target_link_options(tobi PRIVATE ${SAN_FLAGS})
  target_link_options(tobilib INTERFACE ${SAN_FLAGS})
endif()

enable_testing()

add_executable(tobi_test
    test/main.c test/t_rd.c test/t_nm.c test/t_p.c test/t_ir.c
    test/t_cf.c test/t_da.c test/t_dc.c test/t_js.c test/t_bad.c test/t_cli.c
    test/t_prod.c test/t_corpus.c test/t_snap.c)
target_link_libraries(tobi_test PRIVATE tobilib)
target_compile_options(tobi_test PRIVATE ${TOBI_WARN})
target_compile_definitions(tobi_test PRIVATE
    TOBI_BIN="$<TARGET_FILE:tobi>"
    TOBI_SRC_DIR="${CMAKE_CURRENT_SOURCE_DIR}")
if(TOBI_SAN)
  target_compile_options(tobi_test PRIVATE ${SAN_FLAGS})
  target_link_options(tobi_test PRIVATE ${SAN_FLAGS})
endif()

foreach(t rd nm p ir cf da dc js bad cli prod corpus snap)
  add_test(NAME ${t} COMMAND tobi_test ${t})
endforeach()

if(TOBI_FZ)
  add_executable(fz fuzz/fz.c)
  target_link_libraries(fz PRIVATE tobilib)
  target_compile_options(fz PRIVATE ${TOBI_WARN})
  target_compile_definitions(fz PRIVATE TOBI_SRC_DIR="${CMAKE_CURRENT_SOURCE_DIR}")
  if(TOBI_SAN)
    target_compile_options(fz PRIVATE ${SAN_FLAGS})
    target_link_options(fz PRIVATE ${SAN_FLAGS})
  endif()
endif()

if(TOBI_LIBFUZZER)
  set(LIBFUZZER_COMPILE_FLAGS -fsanitize=fuzzer-no-link,address,undefined -fno-omit-frame-pointer)
  target_compile_definitions(tobilib PUBLIC TOBI_SAN_BUILD=1)
  target_compile_options(tobilib PRIVATE ${LIBFUZZER_COMPILE_FLAGS})
  add_executable(fz_llvm fuzz/lf.c)
  target_link_libraries(fz_llvm PRIVATE tobilib)
  target_compile_options(fz_llvm PRIVATE ${TOBI_WARN} -fsanitize=fuzzer,address,undefined -fno-omit-frame-pointer)
  target_link_options(fz_llvm PRIVATE -fsanitize=fuzzer,address,undefined -fno-omit-frame-pointer)
endif()
