function(target_add_flag_c target flag link public)
  include(CheckCCompilerFlag)

  string(REPLACE "=" "_" flag_name ${flag})

  if (${link})
    set(CMAKE_REQUIRED_LINK_OPTIONS "-${flag}")
  endif()

  check_c_compiler_flag("-${flag}" "C_HAS_FLAG_${flag_name}")
  if (C_HAS_FLAG_${flag_name})
    if (${public})
      target_compile_options(${target} PUBLIC $<$<COMPILE_LANGUAGE:C>:-${flag}>)
      if (${link})
        target_link_options(${target} PUBLIC $<$<COMPILE_LANGUAGE:C>:-${flag}>)
      endif()
    else()
      target_compile_options(${target} PRIVATE $<$<COMPILE_LANGUAGE:C>:-${flag}>)
      if (${link})
        target_link_options(${target} PRIVATE $<$<COMPILE_LANGUAGE:C>:-${flag}>)
      endif()
    endif()
  endif()

  set(CMAKE_REQUIRED_LINK_OPTIONS "")
endfunction()

function(target_add_flag_cxx target flag link public)
  include(CheckCXXCompilerFlag)

  string(REPLACE "=" "_" flag_name ${flag})

  if (${link})
    set(CMAKE_REQUIRED_LINK_OPTIONS "-${flag}")
  endif()

  check_cxx_compiler_flag("-${flag}" "CXX_HAS_FLAG_${flag_name}")
  if (CXX_HAS_FLAG_${flag_name})
    if (${public})
      target_compile_options(${target} PUBLIC $<$<COMPILE_LANGUAGE:CXX>:-${flag}>)
      if (${link})
        target_link_options(${target} PUBLIC $<$<COMPILE_LANGUAGE:CXX>:-${flag}>)
      endif()
    else()
      target_compile_options(${target} PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-${flag}>)
      if (${link})
        target_link_options(${target} PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-${flag}>)
      endif()
    endif()
  endif()

  set(CMAKE_REQUIRED_LINK_OPTIONS "")
endfunction()

function(target_add_flag target flag link public)
  get_property(languages GLOBAL PROPERTY ENABLED_LANGUAGES)
  if ("C" IN_LIST languages)
    target_add_flag_c(${target} "${flag}" ${link} ${public})
  endif()
  if ("CXX" IN_LIST languages)
    target_add_flag_cxx(${target} "${flag}" ${link} ${public})
  endif()
endfunction()

function(target_add_flags_c target flags link public)
  foreach(flag ${flags})
    target_add_flag_c(${target} "${flag}" ${link} ${public})
  endforeach()
endfunction()

function(target_add_flags_cxx target flags link public)
  foreach(flag ${flags})
    target_add_flag_cxx(${target} "${flag}" ${link} ${public})
  endforeach()
endfunction()

function(target_add_flags target flags link public)
  foreach(flag ${flags})
    target_add_flag(${target} "${flag}" ${link} ${public})
  endforeach()
endfunction()
