#
# Copyright 2020 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


# Builds the Tensorflow Lite runtime.
#
# WARNING: This is an experimental that is subject to change.
# This has only been tested on Windows, Linux and macOS.
#
# The following are not currently supported:
# - iOS
# - Micro backend
# - Tests
# - Many features in experimental
# - Host Tools (i.e conversion / analysis tools etc.)

cmake_minimum_required(VERSION 3.15)
if(NOT CMAKE_BUILD_TYPE)
  message(STATUS "Setting build type to Release, for debug builds use"
    "'-DCMAKE_BUILD_TYPE=Debug'.")
  set(CMAKE_BUILD_TYPE "Release")
endif()
set(CMAKE_POSITION_INDEPENDENT_CODE TRUE)
# Double colon in target name means ALIAS or IMPORTED target.
cmake_policy(SET CMP0028 NEW)
# Enable MACOSX_RPATH (@rpath) for built dynamic libraries.
cmake_policy(SET CMP0042 NEW)
project(tensorflow-lite C CXX)

# Check if CMAKE_SYSTEM_PROCESSOR is valid: In L5.10 the system processor is set to cortexa53-crypto, which is not known to tensorflow
# dependencies
if( ${CMAKE_SYSTEM_PROCESSOR} STREQUAL "cortexa53-crypto")
  message(STATUS "Reseting CMAKE_SYSTEM_PROCESSOR to aarch64")
  set(CMAKE_SYSTEM_PROCESSOR "aarch64")
endif()

set(TENSORFLOW_SOURCE_DIR "" CACHE PATH
  "Directory that contains the TensorFlow project"
)
if(NOT TENSORFLOW_SOURCE_DIR)
  get_filename_component(TENSORFLOW_SOURCE_DIR
    "${CMAKE_CURRENT_LIST_DIR}/../../"
    ABSOLUTE
  )
endif()
set(TF_SOURCE_DIR "${TENSORFLOW_SOURCE_DIR}/tensorflow")
set(TFLITE_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}")
set(CMAKE_MODULE_PATH
  "${TFLITE_SOURCE_DIR}/tools/cmake/modules"
  ${CMAKE_MODULE_PATH}
)
set(CMAKE_PREFIX_PATH
  "${TFLITE_SOURCE_DIR}/tools/cmake/modules"
  ${CMAKE_PREFIX_PATH}
)
# b/168750039: To workaround absl module not found error on Android build.
set(absl_DIR ${CMAKE_MODULE_PATH})

option(TFLITE_ENABLE_RUY "Enable experimental RUY integration" OFF)
option(TFLITE_ENABLE_RESOURCE "Enable experimental support for resources" ON)
option(TFLITE_ENABLE_NNAPI "Enable NNAPI (Android only)." ON)
option(TFLITE_ENABLE_MMAP "Enable MMAP (unsupported on Windows)" ON)
option(TFLITE_ENABLE_GPU "Enable GPU" OFF)
option(TFLITE_ENABLE_VX "Enable VX Delegate" OFF)
# This must be enabled when converting from TF models with SELECT_TF_OPS
# enabled.
# https://www.tensorflow.org/lite/guide/ops_select#converting_the_model
# This is currently not supported.
option(TFLITE_ENABLE_FLEX "Enable SELECT_TF_OPS" OFF) # TODO: Add support
option(TFLITE_ENABLE_XNNPACK "Enable XNNPACK backend" ON)
option(TFLITE_BUILD_TESTS "Build unit test" OFF)
option(TFLITE_BUILD_EVALTOOLS "Build TensorFlow Lite evaluation tools" OFF)
option(TFLITE_BUILD_SHARED_LIB "Build shared library instead of static" OFF)

set(CMAKE_CXX_STANDARD 14)  # Some components require C++14.
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(_TFLITE_ENABLE_NNAPI "${TFLITE_ENABLE_NNAPI}")
#if(NOT "${CMAKE_SYSTEM_NAME}" STREQUAL "Android")
#  set(_TFLITE_ENABLE_NNAPI OFF)
#endif()
set(_TFLITE_ENABLE_MMAP "${TFLITE_ENABLE_MMAP}")
if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
  # See https://github.com/tensorflow/tensorflow/blob/\
  # 2b96f3662bd776e277f86997659e61046b56c315/tensorflow/lite/tools/make/\
  # Makefile#L157
  set(_TFLITE_ENABLE_MMAP OFF)
endif()
# Simplifies inclusion of non-test sources and headers from a directory.
# SOURCE_DIR: Directory to search for files.
# SOURCES_VAR: Variable to append with all matching *.cc and *.h files.
# [FILTER expression0 .. expressionN]:
#   Additional regular expressions to filter the set of matching
#   files. By default, all files ending in "(_test|test_util)\\.(cc|h)" are
#   removed.
# [RECURSE]: Whether to recursively search SOURCE_DIR.
macro(populate_source_vars SOURCE_DIR SOURCES_VAR)
  cmake_parse_arguments(ARGS "RECURSE" "" "FILTER" ${ARGN})
  if(ARGS_RECURSE)
    set(GLOB_OP GLOB_RECURSE)
  else()
    set(GLOB_OP GLOB)
  endif()
  set(DEFAULT_FILE_FILTER ".*(_test|test_util)\\.(c|cc|h)$")
  file(${GLOB_OP} FOUND_SOURCES "${SOURCE_DIR}/*.*")
  list(FILTER FOUND_SOURCES INCLUDE REGEX ".*\\.(c|cc|h)$")
  list(FILTER FOUND_SOURCES EXCLUDE REGEX "${DEFAULT_FILE_FILTER}")
  foreach(FILE_FILTER ${ARGS_FILTER})
    list(FILTER FOUND_SOURCES EXCLUDE REGEX "${FILE_FILTER}")
  endforeach()
  list(APPEND ${SOURCES_VAR} ${FOUND_SOURCES})
endmacro()
# Simplifies inclusion of non-test sources and headers from a directory
# relative to TFLITE_SOURCE_DIR. See populate_source_vars() for the
# description of arguments including and following SOURCES_VAR.
macro(populate_tflite_source_vars RELATIVE_DIR SOURCES_VAR)
  populate_source_vars(
    "${TFLITE_SOURCE_DIR}/${RELATIVE_DIR}" ${SOURCES_VAR} ${ARGN}
  )
endmacro()
# Simplifies inclusion of non-test sources and headers from a directory
# relative to TF_SOURCE_DIR. See populate_source_vars() for the description of
# arguments including and following SOURCES_VAR.
macro(populate_tf_source_vars RELATIVE_DIR SOURCES_VAR)
  populate_source_vars(
    "${TF_SOURCE_DIR}/${RELATIVE_DIR}" ${SOURCES_VAR} ${ARGN}
  )
endmacro()
# Inclusion of test sources from a directory
# SOURCE_DIR: Directory to search for files.
# SOURCES_VAR: Variable to append with all matching *.cc and *.h files.
macro(find_tflite_tests_sources RELATIVE_DIR TEST_SOURCE_VAR)
  file(GLOB _test_sources "${TFLITE_SOURCE_DIR}/${RELATIVE_DIR}/*test.cc")
  list(APPEND ${TEST_SOURCE_VAR} ${_test_sources})
endmacro()
# Simplifies adding a test to compile
# TC_SRC: Test case source file (*_test.cc)
# [PREFIX expr] prefix used for target to avoid duplicates
function(add_unit_test TC_SRC)
  cmake_parse_arguments(ARGS "" "PREFIX" "" ${ARGN})
  if(ARGS_PREFIX)
    set(_prefix "${ARGS_PREFIX}_")
  else()
    set(_prefix "")
  endif()
  get_filename_component(_name ${TC_SRC} NAME_WE)
  set(_target "${_prefix}${_name}")
  message(DEBUG "Adding test: ${_target} (${TC_SRC})")
  add_executable("${_target}" EXCLUDE_FROM_ALL)
  target_sources(
    ${_target}
    PRIVATE
    ${TC_SRC}
    $<TARGET_OBJECTS:tflite_test_utils>
  )
  target_link_libraries(${_target}
      PRIVATE
      tensorflow-lite
      gtest_main
      gmock
      re2
      absl::hashtablez_sampler
      ${CMAKE_DL_LIBS}
  )
  target_compile_options(${_target} PRIVATE "-Wno-narrowing") #kernels/quantize_test
  add_dependencies(tests ${_target})
endfunction()
# Add all unit test from a directory
# RELATIVE_DIR Directory relative to TFLITE_SOURCE_DIR to get tests
function(add_unit_tests RELATIVE_DIR)
  find_tflite_tests_sources(${RELATIVE_DIR} TFLITE_TESTS_SRCS)
  foreach(SRC ${TFLITE_TESTS_SRCS})
    add_unit_test(${SRC} ${ARGN})
  endforeach()
endfunction()

# Find TensorFlow Lite dependencies.
find_package(absl REQUIRED)
find_package(eigen REQUIRED)
find_package(farmhash REQUIRED)
find_package(fft2d REQUIRED)
find_package(flatbuffers REQUIRED)
find_package(gemmlowp REQUIRED)
find_package(neon2sse REQUIRED)
find_package(ruy REQUIRED)
if(TFLITE_BUILD_TESTS)
  find_package(GoogleTest)
  find_package(re2)
  add_custom_target(tests ALL)
endif()
# Generate TensorFlow Lite FlatBuffer code.
# We used to have an actual compilation logic with flatc but decided to use
# schema_generated.h since flatc doesn't work with cross compilation.
set(TFLITE_FLATBUFFERS_SCHEMA_DIR "${TFLITE_SOURCE_DIR}/schema")
set(TF_TARGET_PRIVATE_OPTIONS "")
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang$")
  # TensorFlow uses a heap of deprecated proto fields so surpress these
  # warnings until they're fixed.
  list(APPEND TF_TARGET_PRIVATE_OPTIONS "-Wno-deprecated-declarations")
endif()
# Additional compiler flags used when compiling TF Lite.
set(TFLITE_TARGET_PUBLIC_OPTIONS "")
set(TFLITE_TARGET_PRIVATE_OPTIONS "")
# Additional library dependencies based upon enabled features.
set(TFLITE_TARGET_DEPENDENCIES "")
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang$")
  # TFLite uses deprecated methods in neon2sse which generates a huge number of
  # warnings so surpress these until they're fixed.
  list(APPEND TFLITE_TARGET_PRIVATE_OPTIONS "-Wno-deprecated-declarations")
endif()
if(CMAKE_SYSTEM_NAME MATCHES "Windows")
  # Use NOMINMAX to disable the min / max macros in windows.h as they break
  # use of std::min std::max.
  # Use NOGDI to ERROR macro which breaks TensorFlow logging.
  list(APPEND TFLITE_TARGET_PRIVATE_OPTIONS "-DNOMINMAX" "-DNOGDI")
  # lite/kernels/conv.cc has more than 64k sections so enable /bigobj to
  # support compilation with MSVC2015.
  if(MSVC)
    list(APPEND TFLITE_TARGET_PRIVATE_OPTIONS "/bigobj")
  elseif(CMAKE_COMPILER_IS_GNUCXX)
    list(APPEND TFLITE_TARGET_PRIVATE_OPTIONS "-Wa,-mbig-obj")
  endif()
endif()
if(CMAKE_SYSTEM_NAME MATCHES "Android")
  find_library(ANDROID_LOG_LIB log)
endif()

# Build a list of source files to compile into the TF Lite library.
populate_tflite_source_vars("." TFLITE_SRCS FILTER "tflite_with_xnnpack.(c|cc|h)$")
if(_TFLITE_ENABLE_MMAP)
  list(FILTER TFLITE_SRCS EXCLUDE REGEX ".*mmap_allocation_disabled\\.cc$")
else()
  list(FILTER TFLITE_SRCS EXCLUDE REGEX ".*mmap_allocation\\.cc$")
endif()
if(NOT "${CMAKE_SYSTEM_NAME}" STREQUAL "Android")
  list(FILTER TFLITE_SRCS EXCLUDE REGEX ".*minimal_logging_android\\.cc$")
endif()
if(NOT "${CMAKE_SYSTEM_NAME}" STREQUAL "iOS")
  list(FILTER TFLITE_SRCS EXCLUDE REGEX ".*minimal_logging_ios\\.cc$")
endif()
populate_tflite_source_vars("core" TFLITE_CORE_SRCS)
populate_tflite_source_vars("core/api" TFLITE_CORE_API_SRCS)
populate_tflite_source_vars("c" TFLITE_C_SRCS)
populate_tflite_source_vars("delegates" TFLITE_DELEGATES_SRCS)
if(TFLITE_ENABLE_FLEX)
  message(FATAL_ERROR "TF Lite Flex delegate is currently not supported.")
  populate_tflite_source_vars("delegates/flex" TFLITE_DELEGATES_FLEX_SRCS)
  list(APPEND TFLITE_TARGET_DEPENDENCIES
    absl::inlined_vector
    absl::optional
    absl::type_traits
  )
endif()
if(TFLITE_ENABLE_GPU)
  find_package(opencl_headers REQUIRED)
  find_package(vulkan_headers REQUIRED)
  populate_tflite_source_vars(
    "delegates/gpu/cl" TFLITE_DELEGATES_GPU_CL_SRCS
    FILTER "(_test|gl_interop|egl_sync)\\.(cc|h)$"
  )
  populate_tflite_source_vars(
    "delegates/gpu/cl/kernels" TFLITE_DELEGATES_GPU_CL_KERNELS_SRCS
    FILTER "(_test)\\.(cc|h)$"
  )
  populate_tflite_source_vars(
    "delegates/gpu/cl/kernels/special"
    TFLITE_DELEGATES_GPU_CL_KERNELS_SPECIAL_SRCS
    FILTER "(_test)\\.(cc|h)$"
  )
  populate_tflite_source_vars(
    "delegates/gpu/cl/selectors" TFLITE_DELEGATES_GPU_CL_SELECTORS_SRCS
    FILTER "(_test)\\.(cc|h)$"
  )
  populate_tflite_source_vars(
    "delegates/gpu/common" TFLITE_DELEGATES_GPU_COMMON_SRCS
    FILTER "(_test)\\.(cc|h)$"
  )
  populate_tflite_source_vars(
    "delegates/gpu/common/default" TFLITE_DELEGATES_GPU_COMMON_DEFAULT_SRCS
    FILTER "(_test)\\.(cc|h)$"
  )
  populate_tflite_source_vars(
    "delegates/gpu/common/memory_management"
    TFLITE_DELEGATES_GPU_COMMON_MEMORY_MANAGEMENT_SRCS
    FILTER "(_test)\\.(cc|h)$"
  )
  populate_tflite_source_vars(
    "delegates/gpu/common/transformations"
    TFLITE_DELEGATES_GPU_COMMON_TRANSFORMATIONS_SRCS
    FILTER "(_test)\\.(cc|h)$"
  )
  list(APPEND TFLITE_DELEGATES_GPU_SRCS
    ${TFLITE_SOURCE_DIR}/delegates/gpu/api.cc
    ${TFLITE_SOURCE_DIR}/delegates/gpu/delegate.cc
    ${TFLITE_DELEGATES_GPU_CL_SRCS}
    ${TFLITE_DELEGATES_GPU_CL_KERNELS_SRCS}
    ${TFLITE_DELEGATES_GPU_CL_KERNELS_SPECIAL_SRCS}
    ${TFLITE_DELEGATES_GPU_CL_SELECTORS_SRCS}
    ${TFLITE_SOURCE_DIR}/delegates/gpu/cl/selectors/default/default_selector.cc
    ${TFLITE_DELEGATES_GPU_COMMON_SRCS}
    ${TFLITE_DELEGATES_GPU_COMMON_DEFAULT_SRCS}
    ${TFLITE_DELEGATES_GPU_COMMON_MEMORY_MANAGEMENT_SRCS}
    ${TFLITE_DELEGATES_GPU_COMMON_TRANSFORMATIONS_SRCS}
  )
  list(APPEND TFLITE_TARGET_PUBLIC_OPTIONS "-DCL_DELEGATE_NO_GL" "-DEGL_NO_X11")
  list(APPEND TFLITE_TARGET_DEPENDENCIES
    absl::any
    absl::flat_hash_map
  )
endif()
if(_TFLITE_ENABLE_NNAPI)
  populate_tflite_source_vars("delegates/nnapi"
    TFLITE_DELEGATES_NNAPI_SRCS
    FILTER "(_test_list|_disabled)\\.(cc|h)$"
  )
  populate_tflite_source_vars(
    "nnapi" TFLITE_NNAPI_SRCS FILTER "(_disabled)\\.(cc|h)$"
  )
  list(APPEND TFLITE_TARGET_PUBLIC_OPTIONS "-DNNAPI_VERBOSE_VALIDATION")
  if(TFLITE_BUILD_TESTS)
    list(APPEND TFLITE_UNIT_TEST_UTIL_SRCS "${TFLITE_SOURCE_DIR}/tools/delegates/nnapi_delegate_provider.cc")
    list(APPEND TFLITE_UNIT_TEST_UTIL_SRCS "${TFLITE_SOURCE_DIR}/tools/delegates/default_execution_provider.cc")
    add_unit_tests("delegates/nnapi" PREFIX "nnapi")
    add_unit_tests("nnapi" PREFIX "nnapi")
  endif()
else()
  set(TFLITE_DELEGATES_NNAPI_SRCS
    "${TFLITE_SOURCE_DIR}/delegates/nnapi/nnapi_delegate_disabled.cc"
  )
  set(TFLITE_NNAPI_SRCS
    "${TFLITE_SOURCE_DIR}/nnapi/nnapi_implementation_disabled.cc"
  )
endif()
if(TFLITE_ENABLE_XNNPACK)
  set(CMAKE_ASM_FLAGS "" CACHE STRING "ASM flags" FORCE)
  find_package(xnnpack REQUIRED)
  populate_tflite_source_vars("delegates/xnnpack"
    TFLITE_DELEGATES_XNNPACK_SRCS
    FILTER ".*(_test|_tester)\\.(cc|h)"
  )
  list(APPEND TFLITE_TARGET_DEPENDENCIES
    XNNPACK
  )
  if(TFLITE_BUILD_TESTS)
    file(GLOB _tmp "${TFLITE_SOURCE_DIR}/delegates/xnnpack/*tester.cc")
    list(APPEND TFLITE_UNIT_TEST_UTIL_SRCS ${_tmp})
    list(APPEND TFLITE_UNIT_TEST_UTIL_SRCS "${TFLITE_SOURCE_DIR}/tools/delegates/xnnpack_delegate_provider.cc")
    list(APPEND TFLITE_UNIT_TEST_UTIL_SRCS "${TFLITE_SOURCE_DIR}/tools/delegates/default_execution_provider.cc")
    add_unit_tests("delegates/xnnpack" PREFIX "xnnpack")
  endif()
endif()
if (TFLITE_ENABLE_RESOURCE)
  populate_tflite_source_vars("experimental/resource"
    TFLITE_EXPERIMENTAL_RESOURCE_SRCS
  )
endif()
populate_tflite_source_vars("experimental/ruy"
  TFLITE_EXPERIMENTAL_RUY_SRCS
  FILTER
  ".*(test(_fast|_slow|_special_specs))\\.(cc|h)$"
  ".*(benchmark|tune_tool|example)\\.(cc|h)$"
)
populate_tflite_source_vars("experimental/ruy/profiler"
  TFLITE_EXPERIMENTAL_RUY_PROFILER_SRCS
  FILTER ".*(test|test_instrumented_library)\\.(cc|h)$"
)
if(TFLITE_ENABLE_RUY)
  list(APPEND TFLITE_TARGET_PUBLIC_OPTIONS "-DTFLITE_WITH_RUY")
endif()

if(TFLITE_ENABLE_VX)
  include(${CMAKE_SOURCE_DIR}/delegates/vx-delegate/CMakeLists.txt)
  list(APPEND TFLITE_TARGET_PUBLIC_OPTIONS ${TFLITE_DELEGATES_VX_PUBLIC_OPTIONS})
  list(APPEND TFLITE_TARGET_DEPENDENCIES ${TFLITE_DELEGATES_VX_DEPENDENCIES})
endif()
populate_tflite_source_vars("kernels"
  TFLITE_KERNEL_SRCS
  FILTER ".*(_test_util_internal|test_main)\\.(cc|h)"
)
populate_tflite_source_vars("kernels/internal" TFLITE_KERNEL_INTERNAL_SRCS)
populate_tflite_source_vars("kernels/internal/optimized"
  TFLITE_KERNEL_INTERNAL_OPT_SRCS
)
populate_tflite_source_vars("kernels/internal/optimized/integer_ops"
  TFLITE_KERNEL_INTERNAL_OPT_INTEGER_OPS_SRCS
)
populate_tflite_source_vars("kernels/internal/optimized/sparse_ops"
  TFLITE_KERNEL_INTERNAL_OPT_SPARSE_OPS_SRCS
)
populate_tflite_source_vars("kernels/internal/reference"
  TFLITE_KERNEL_INTERNAL_REF_SRCS
)
populate_tflite_source_vars("kernels/internal/reference/integer_ops"
  TFLITE_KERNEL_INTERNAL_REF_INTEGER_OPS_SRCS
)
populate_tflite_source_vars("kernels/internal/reference/sparse_ops"
  TFLITE_KERNEL_INTERNAL_REF_SPARSE_OPS_SRCS
)
set(TFLITE_PROFILER_SRCS ${TFLITE_SOURCE_DIR}/profiling/platform_profiler.cc)
if(CMAKE_SYSTEM_NAME MATCHES "Android")
  list(APPEND TFLITE_PROFILER_SRCS
    ${TFLITE_SOURCE_DIR}/profiling/atrace_profiler.cc
  )
endif()

list(APPEND TFLITE_CMD_LINE_TOOLS_SRCS
    ${TFLITE_SOURCE_DIR}/tools/command_line_flags.cc
    ${TFLITE_SOURCE_DIR}/tools/tool_params.cc
)
# Common include directories
set(TFLITE_INCLUDE_DIRS
  "${TENSORFLOW_SOURCE_DIR}"
  "${TFLITE_FLATBUFFERS_SCHEMA_DIR}"
)
include_directories(
  BEFORE
    ${TFLITE_INCLUDE_DIRS}
)

if(${TFLITE_BUILD_SHARED_LIB})
  set(LIB_TYPE "SHARED")
endif()

list(APPEND TFLITE_PROFILING_SRCS
  ${TF_SOURCE_DIR}/core/util/stats_calculator.cc
  ${TFLITE_SOURCE_DIR}/profiling/memory_info.cc
  ${TFLITE_SOURCE_DIR}/profiling/profile_summarizer.cc
  ${TFLITE_SOURCE_DIR}/profiling/profile_summary_formatter.cc
  ${TFLITE_SOURCE_DIR}/profiling/time.cc
  ${TFLITE_SOURCE_DIR}/tools/delegates/default_execution_provider.cc
  ${TFLITE_SOURCE_DIR}/tools/evaluation/utils.cc
  ${TFLITE_SOURCE_DIR}/tools/optimize/sparsity/format_converter.cc
)

# TFLite library
add_library(tensorflow-lite ${LIB_TYPE}
  ${TFLITE_CORE_API_SRCS}
  ${TFLITE_CORE_SRCS}
  ${TFLITE_C_SRCS}
  ${TFLITE_DELEGATES_FLEX_SRCS}
  ${TFLITE_DELEGATES_GPU_SRCS}
  ${TFLITE_DELEGATES_NNAPI_SRCS}
  ${TFLITE_DELEGATES_SRCS}
  ${TFLITE_DELEGATES_XNNPACK_SRCS}
  ${TFLITE_DELEGATES_VX_SRCS}
  ${TFLITE_EXPERIMENTAL_RESOURCE_SRCS}
  ${TFLITE_EXPERIMENTAL_RUY_PROFILER_SRCS}
  ${TFLITE_EXPERIMENTAL_RUY_SRCS}
  ${TFLITE_KERNEL_INTERNAL_OPT_INTEGER_OPS_SRCS}
  ${TFLITE_KERNEL_INTERNAL_OPT_SPARSE_OPS_SRCS}
  ${TFLITE_KERNEL_INTERNAL_OPT_SRCS}
  ${TFLITE_KERNEL_INTERNAL_REF_INTEGER_OPS_SRCS}
  ${TFLITE_KERNEL_INTERNAL_REF_SPARSE_OPS_SRCS}
  ${TFLITE_KERNEL_INTERNAL_REF_SRCS}
  ${TFLITE_KERNEL_INTERNAL_SRCS}
  ${TFLITE_KERNEL_SRCS}
  ${TFLITE_NNAPI_SRCS}
  ${TFLITE_SRCS}
  ${TFLITE_PROFILER_SRCS}
  ${TFLITE_PROFILING_SRCS}
  ${TFLITE_SOURCE_DIR}/schema/schema_utils.cc
  ${TFLITE_SOURCE_DIR}/tools/optimize/sparsity/format_converter.cc
  ${TFLITE_CMD_LINE_TOOLS_SRCS}
)
set_target_properties(tensorflow-lite
    PROPERTIES
        VERSION 2.4.1
        SOVERSION  2.4.1
)
target_include_directories(tensorflow-lite
  PUBLIC
    ${TFLITE_INCLUDE_DIRS}
)
target_link_libraries(tensorflow-lite
  PUBLIC
    Eigen3::Eigen
    NEON_2_SSE
    absl::flags
    absl::hash
    absl::status
    absl::strings
    absl::synchronization
    absl::variant
    farmhash
    fft2d_fftsg2d
    flatbuffers
    gemmlowp
    ruy
    ${TFLITE_TARGET_DEPENDENCIES}
)
target_compile_options(tensorflow-lite
  PUBLIC ${TFLITE_TARGET_PUBLIC_OPTIONS}
  PRIVATE ${TFLITE_TARGET_PRIVATE_OPTIONS}
)
add_library(tensorflow::tensorflowlite ALIAS tensorflow-lite)

# Benchmark Tool
populate_source_vars("${TFLITE_SOURCE_DIR}/tools/benchmark"
  TFLITE_BENCHMARK_SRCS
  FILTER "(_test|_plus_flex_main|_performance_options.*)\\.cc$"
)

list(APPEND TFLITE_BENCHMARK_LIBS
  tensorflow-lite
  ${CMAKE_DL_LIBS}
)

# TODO(b/171007016): Enable performance options on Windows.
if(NOT "${CMAKE_SYSTEM_NAME}" STREQUAL "Windows")
  list(APPEND TFLITE_BENCHMARK_SRCS
    ${TFLITE_SOURCE_DIR}/tools/benchmark/benchmark_performance_options.cc
  )
endif()

if(TFLITE_ENABLE_XNNPACK)
  list(APPEND TFLITE_BENCHMARK_SRCS
    ${TFLITE_SOURCE_DIR}/tools/delegates/xnnpack_delegate_provider.cc
  )
else()
  set(TFLITE_BENCHMARK_CC_OPTIONS "-DTFLITE_WITHOUT_XNNPACK")
endif()  # TFLITE_ENABLE_XNNPACK

#if(CMAKE_SYSTEM_NAME MATCHES "Android")
  if(_TFLITE_ENABLE_NNAPI)
    list(APPEND TFLITE_BENCHMARK_SRCS
      ${TFLITE_SOURCE_DIR}/tools/delegates/nnapi_delegate_provider.cc
    )
  endif()  # _TFLITE_ENABLE_NNAPI
  list(APPEND TFLITE_BENCHMARK_LIBS
    ${ANDROID_LOG_LIB}
    absl::strings
  )
#endif()  # Android

if(TFLITE_ENABLE_GPU)
  list(APPEND TFLITE_BENCHMARK_SRCS
    ${TFLITE_SOURCE_DIR}/tools/delegates/gpu_delegate_provider.cc
  )
endif()  # TFLITE_ENABLE_GPU

if(TFLITE_ENABLE_VX)
  list(APPEND TFLITE_BENCHMARK_SRCS
    ${TFLITE_SOURCE_DIR}/tools/delegates/vx_delegate_provider.cc
  )
endif()

add_executable(benchmark_model
  ${TFLITE_BENCHMARK_SRCS}
)
target_compile_options(benchmark_model
  PRIVATE
    ${TFLITE_BENCHMARK_CC_OPTIONS}
)
target_link_libraries(benchmark_model
    ${TFLITE_BENCHMARK_LIBS}
)

# label_image tool
list(APPEND TFLITE_LABEL_IMAGE_SRCS
    ${TFLITE_SOURCE_DIR}/examples/label_image/bitmap_helpers.cc
    ${TFLITE_SOURCE_DIR}/examples/label_image/label_image.cc
    ${TFLITE_SOURCE_DIR}/tools/evaluation/utils.cc
)

add_executable(label_image
  ${TFLITE_CMD_LINE_TOOLS_SRCS}
  ${TFLITE_LABEL_IMAGE_SRCS}
)

target_compile_options(label_image
  PRIVATE
  ${TFLITE_BENCHMARK_CC_OPTIONS}
)

target_link_libraries(label_image
  ${TFLITE_BENCHMARK_LIBS}
)

# unit test dependencies
if(TFLITE_BUILD_TESTS)
    file(GLOB UTILS_SRC "${TFLITE_SOURCE_DIR}/kernels/*test_util.cc")
    file(GLOB DELEGATE_UTILS_SRC "${TFLITE_SOURCE_DIR}/delegates/utils/dummy_delegate/*.cc")
    list(APPEND TFLITE_UNIT_TEST_UTIL_SRCS 
        ${TFLITE_SOURCE_DIR}/tools/versioning/op_version.cc 
        ${TFLITE_SOURCE_DIR}/kernels/internal/test_util.cc 
        ${TFLITE_SOURCE_DIR}/kernels/acceleration_test_util_internal.cc 
        ${TFLITE_SOURCE_DIR}/delegates/utils/simple_delegate.cc 
        ${TFLITE_SOURCE_DIR}/delegates/utils.cc 
        ${TFLITE_SOURCE_DIR}/delegates/interpreter_utils.cc 
        ${TFLITE_SOURCE_DIR}/delegates/nnapi/acceleration_test_list.cc 
        ${TFLITE_SOURCE_DIR}/delegates/nnapi/acceleration_test_util.cc 
        ${TFLITE_SOURCE_DIR}/tools/evaluation/utils.cc 
        ${TFLITE_SOURCE_DIR}/tools/optimize/model_utils.cc 
        ${TFLITE_SOURCE_DIR}/tools/optimize/quantization_utils.cc 
        ${TFLITE_SOURCE_DIR}/tools/optimize/operator_property.cc 
        ${TF_SOURCE_DIR}/core/platform/default/logging.cc 
        ${TF_SOURCE_DIR}/core/platform/default/env_time.cc
    )
    list(APPEND TFLITE_UNIT_TEST_UTIL_SRCS ${UTILS_SRC})
    list(APPEND TFLITE_UNIT_TEST_UTIL_SRCS ${DELEGATE_UTILS_SRC})
    list(APPEND TFLITE_UNIT_TEST_UTIL_SRCS ${TFLITE_CMD_LINE_TOOLS_SRCS})
    add_library(tflite_test_utils OBJECT EXCLUDE_FROM_ALL ${TFLITE_UNIT_TEST_UTIL_SRCS} )
    target_link_libraries(tflite_test_utils PUBLIC tensorflow-lite)
endif()

if(TFLITE_BUILD_TESTS)
  add_unit_tests(".")
  add_unit_tests("c")
  add_unit_tests("delegates" PREFIX "delegates")
  add_unit_tests("kernels" PREFIX "kernels")
endif()

if(TFLITE_BUILD_EVALTOOLS)
    populate_tflite_source_vars("tools/evaluation/stages" TFLITE_EVALUATION_STAGES_SRCS RECURSE)
    populate_tflite_source_vars("tools/evaluation/proto" TFLITE_EVALUATION_PROTO_SRCS)
    
    list(APPEND TFLITE_EVALUATION_BINARY_SRCS
        ${TF_SOURCE_DIR}/core/platform/default/logging.cc
        ${TF_SOURCE_DIR}/core/platform/default/env_time.cc
        ${TF_SOURCE_DIR}/core/lib/jpeg/jpeg_mem.cc
        ${TF_SOURCE_DIR}/core/lib/jpeg/jpeg_handle.cc
        ${TFLITE_SOURCE_DIR}/profiling/time.cc
        ${TFLITE_SOURCE_DIR}/tools/evaluation/utils.cc
        ${TFLITE_SOURCE_DIR}/tools/evaluation/evaluation_delegate_provider.cc
        ${TFLITE_SOURCE_DIR}/tools/evaluation/tasks/task_executor_main.cc
        ${TFLITE_SOURCE_DIR}/tools/evaluation/tasks/task_executor.cc
        ${TFLITE_SOURCE_DIR}/tools/delegates/default_execution_provider.cc
    )
    list(APPEND TFLITE_EVALUATION_BINARY_SRCS ${TFLITE_CMD_LINE_TOOLS_SRCS})
    list(APPEND TFLITE_EVALUATION_BINARY_SRCS ${TFLITE_EVALUATION_STAGES_SRCS})
    list(APPEND TFLITE_EVALUATION_BINARY_SRCS ${TFLITE_EVALUATION_PROTO_SRCS})
    if(TFLITE_ENABLE_NNAPI)
        list(APPEND TFLITE_EVALUATION_BINARY_SRCS ${TFLITE_SOURCE_DIR}/tools/delegates/nnapi_delegate_provider.cc)
    endif()
    if(TFLITE_ENABLE_XNNPACK)
        list(APPEND TFLITE_EVALUATION_BINARY_SRCS ${TFLITE_SOURCE_DIR}/tools/delegates/xnnpack_delegate_provider.cc)
    endif()


    add_executable(coco_object_detection_run_eval
        ${TFLITE_SOURCE_DIR}/tools/evaluation/tasks/coco_object_detection/run_eval.cc
        ${TFLITE_EVALUATION_BINARY_SRCS}
    )

    add_executable(imagenet_image_classification_run_eval
        ${TFLITE_SOURCE_DIR}/tools/evaluation/tasks/imagenet_image_classification/run_eval.cc
        ${TFLITE_EVALUATION_BINARY_SRCS}
    )

    add_executable(inference_diff_run_eval
        ${TFLITE_SOURCE_DIR}/tools/evaluation/tasks/inference_diff/run_eval.cc
        ${TFLITE_EVALUATION_BINARY_SRCS}
    )
    list(APPEND EVALTOOLS
        coco_object_detection_run_eval
        imagenet_image_classification_run_eval
        inference_diff_run_eval
    )
    unset(TFLITE_PROTOBUF_LIB CACHE)
    find_library(TFLITE_PROTOBUF_LIB
        "libprotobuf.so.20.0.2")
    if(NOT TFLITE_PROTOBUF_LIB)
        message(FATAL_ERROR "Protobuf Library not found!")
    endif()
    message("Protobuf library: ${TFLITE_PROTOBUF_LIB}")

    foreach(evaltool ${EVALTOOLS})
        target_include_directories(${evaltool}
            PUBLIC
                "${CMAKE_SYSROOT}/usr/include/tensorflow-protobuf")
        target_link_libraries(${evaltool}
            tensorflow-lite
            ${TFLITE_BENCHMARK_LIBS}
            absl::base
            absl::strings
            absl::flat_hash_map
            ${TFLITE_PROTOBUF_LIB}
            "-ljpeg"
        )
        target_compile_options(${evaltool}
            PRIVATE
            ${TFLITE_BENCHMARK_CC_OPTIONS})
    endforeach()
endif()

