This page describes how to build and use the LiteRT Interpreter API library
with [CMake](https://cmake.org/) tool.

> [!NOTE]
> **Note:** To build the LiteRT CompiledModel API, see [Build Compiled Model API with CMake](https://developers.google.com/edge/litert/build/cmake_litert).

The following instructions have been tested on Ubuntu 16.04.3 64-bit PC (AMD64)
, macOS Catalina (x86_64) and Windows 10.

### Step 1. Install CMake tool

It requires CMake 3.16 or higher. On Ubuntu, you can simply run the following
command.

    sudo apt-get install cmake

Or you can follow
[the official cmake installation guide](https://cmake.org/install/)

### Step 2. Clone LiteRT repository

    git clone https://github.com/google-ai-edge/LiteRT.git

### Step 3. Create CMake build directory

    mkdir tflite_build
    cd tflite_build

### Step 4. Run CMake tool with configurations

#### Release build

It generates an optimized release binary by default. If you want to build for
your workstation, simply run the following command.

    cmake ../LiteRT/tflite

#### Debug build

If you need to produce a debug build which has symbol information, you need to
provide the `-DCMAKE_BUILD_TYPE=Debug` option.

    cmake ../LiteRT/tflite -DCMAKE_BUILD_TYPE=Debug

#### Build with kernel unit tests

In order to be able to run kernel tests, you need to provide the
`-DTFLITE_KERNEL_TEST=on` flag. Unit test cross-compilation specifics can be
found in the next subsection.

    cmake ../LiteRT/tflite -DTFLITE_KERNEL_TEST=on

#### Cross-compilation

You can use CMake to build binaries for ARM64 or Android target architectures.

In order to cross-compile the LiteRT Interpreter API, you namely need to provide
the path to the SDK (e.g. ARM64 SDK or NDK in Android's case) with
`-DCMAKE_TOOLCHAIN_FILE` flag.

    cmake -DCMAKE_TOOLCHAIN_FILE=<CMakeToolchainFileLoc> ../LiteRT/tflite

##### Specifics of Android cross-compilation

For Android cross-compilation, you need to install
[Android NDK](https://developer.android.com/ndk) and provide the NDK path with
`-DCMAKE_TOOLCHAIN_FILE` flag mentioned above. You also need to set target ABI
with`-DANDROID_ABI` flag.

    cmake -DCMAKE_TOOLCHAIN_FILE=<NDK path>/build/cmake/android.toolchain.cmake \
      -DANDROID_ABI=arm64-v8a ../LiteRT/tflite

##### Specifics of kernel (unit) tests cross-compilation

Cross-compilation of the unit tests requires flatc compiler for the host
architecture. For this purpose, there is a CMakeLists located in
`tflite/tools/cmake/native_tools/flatbuffers` to build the flatc
compiler with CMake in advance in a separate build directory using the host
toolchain.

    mkdir flatc-native-build && cd flatc-native-build
    cmake ../LiteRT/tflite/tools/cmake/native_tools/flatbuffers
    cmake --build .

It is also possible **to install** the *flatc* to a custom installation location
(e.g. to a directory containing other natively-built tools instead of the CMake
build directory):

    cmake -DCMAKE_INSTALL_PREFIX=<native_tools_dir> ../LiteRT/tflite/tools/cmake/native_tools/flatbuffers
    cmake --build .

For the LiteRT Interpreter API cross-compilation itself, additional parameter
`-DTFLITE_HOST_TOOLS_DIR=<flatc_dir_path>` pointing to the directory containing
the native *flatc* binary needs to be provided along with the
`-DTFLITE_KERNEL_TEST=on` flag mentioned above.

    cmake -DCMAKE_TOOLCHAIN_FILE=${OE_CMAKE_TOOLCHAIN_FILE} -DTFLITE_KERNEL_TEST=on -DTFLITE_HOST_TOOLS_DIR=<flatc_dir_path> ../LiteRT/tflite

##### Cross-compiled kernel (unit) tests launch on target

Unit tests can be run as separate executables or using the CTest utility. As far
as CTest is concerned, if at least one of the parameters
TFLITE_ENABLE_XNNPACK`or`TFLITE_EXTERNAL_DELEGATE\` is enabled for the LiteRT
build, the resulting tests are generated with two different **labels**
(utilizing the same test executable): - *plain* - denoting the tests ones run on
CPU backend - *delegate* - denoting the tests expecting additional launch
arguments used for the used delegate specification

Both `CTestTestfile.cmake` and `run-tests.cmake` (as referred below) are
available in `<build_dir>/kernels`.

Launch of unit tests with CPU backend (provided the `CTestTestfile.cmake` is
present on target in the current directory):

    ctest -L plain

Launch examples of unit tests using delegates (provided the
`CTestTestfile.cmake` as well as `run-tests.cmake` file are present on target in
the current directory):

    cmake -E env TESTS_ARGUMENTS=--use_xnnpack=true ctest -L delegate
    cmake -E env TESTS_ARGUMENTS=--external_delegate_path=<PATH> ctest -L delegate

**A known limitation** of this way of providing additional delegate-related
launch arguments to unit tests is that it effectively supports only those with
an **expected return value of 0**. Different return values will be reported as a
test failure.

#### OpenCL GPU delegate

If your target machine has OpenCL support, you can use
[GPU delegate](https://developers.google.com/edge/litert/performance/gpu) which can
leverage your GPU power.

To configure OpenCL GPU delegate support:

    cmake ../LiteRT/tflite -DTFLITE_ENABLE_GPU=ON

> [!NOTE]
> **Note:** It's experimental. There could be compatibility issues. It's only verified with Android devices and NVidia CUDA OpenCL 1.2.

### Step 5. Build LiteRT Interpreter API

In the `tflite_build` directory,

    cmake --build . -j

> [!NOTE]
> **Note:** This generates a static library `libtensorflow-lite.a` in the current directory but the library isn't self-contained since all the transitive dependencies are not included. To use the library properly, you need to create a CMake project. Please refer the ["Create a CMake project which uses LiteRT Interpreter
> API"](https://developers.google.com/edge/litert/build/cmake#create_a_cmake_project_which_uses_litert_interpreter_api) section.

### Step 6. Build LiteRT Benchmark Tool and Label Image Example (Optional)

In the `tflite_build` directory,

    cmake --build . -j -t benchmark_model

    cmake --build . -j -t label_image

## Available Options to build LiteRT Interpreter API

Here is the list of available options. You can override it with
`-D<option_name>=[ON|OFF]`. For example, `-DTFLITE_ENABLE_XNNPACK=OFF` to
disable XNNPACK which is enabled by default.

| Option Name | Feature | Android | Linux | macOS | Windows |
|---|---|---|---|---|---|
| `TFLITE_ENABLE_GPU` | Enable GPU delegate | OFF | OFF | N/A | N/A |
| `TFLITE_ENABLE_XNNPACK` | Enable XNNPACK delegate | ON | ON | ON | ON |
| `TFLITE_ENABLE_MMAP` | Enable MMAP | ON | ON | ON | N/A |

## Create a CMake project which uses LiteRT Interpreter API

You need to have `add_subdirectory()` for the `tflite` directory of the
LiteRT repository and link `tensorflow-lite` with `target_link_libraries()`.
Here is an example `CMakeLists.txt`.

    cmake_minimum_required(VERSION 3.16)
    project(minimal C CXX)

    set(LITERT_SOURCE_DIR "" CACHE PATH
      "Directory that contains the LiteRT repository")
    if(NOT LITERT_SOURCE_DIR)
      message(FATAL_ERROR "Set LITERT_SOURCE_DIR to the LiteRT repository path")
    endif()

    add_subdirectory(
      "${LITERT_SOURCE_DIR}/tflite"
      "${CMAKE_CURRENT_BINARY_DIR}/tensorflow-lite" EXCLUDE_FROM_ALL)

    add_executable(minimal minimal.cc)
    target_link_libraries(minimal tensorflow-lite)

## Build LiteRT Interpreter API C library

If you want to build the LiteRT Interpreter API shared library for
[C API](https://github.com/google-ai-edge/LiteRT/blob/main/tflite/c/README.md),
follow [step 1](https://developers.google.com/edge/litert/build/cmake#step_1_install_cmake_tool) to
[step 3](https://developers.google.com/edge/litert/build/cmake#step_3_create_cmake_build_directory) first. After that, run the
following commands.

    cmake ../LiteRT/tflite/c
    cmake --build . -j

This command generates the following shared library in the current directory.

> [!NOTE]
> **Note:** On Windows system, you can find the `tensorflowlite_c.dll` under `debug` directory.

| Platform | Library name |
|---|---|
| Linux | `libtensorflowlite_c.so` |
| macOS | `libtensorflowlite_c.dylib` |
| Windows | `tensorflowlite_c.dll` |

> [!NOTE]
> **Note:** You need the public headers (`tflite/c/c_api.h`, `tflite/c/c_api_experimental.h`, `tflite/c/c_api_types.h`, and `tflite/c/common.h`), and the private headers that those public headers include (`tflite/builtin_ops.h`, `tflite/core/c/*.h`, and `tflite/core/async/c/*.h`) to use the generated shared library.