Skip to main content

Your first program

This tutorial has six parts: four build your first ClikaRT program, one serves it, and one deploys it to mobile. Each part is a complete program that compiles and runs on any machine the runtime supports (no accelerator is needed). Core concepts are explained where they first appear. This part links the bundle, prints the version, and makes one tensor.

The C++, C, Kotlin, Go and Rust paths assume the bundle is extracted and CLIKART_BUNDLE_DIR points at it (see Quick install); the Python wheel carries the runtime itself.

The program

main.cpp
#include <cstdio>

#include <ClikaRT/clika_rt.h>

using ClikaRT::DataType;
using ClikaRT::Tensor;
namespace ops = ClikaRT::ops;

int main() {
std::printf("ClikaRT %s\n", ClikaRT::GetVersionInfo().c_str());

// A 2x3 tensor of ones on the CPU (the default device).
const Tensor a = Tensor::ones({2, 3}, DataType::Float32);

// ops:: are free functions returning the value directly.
const Tensor b = ops::add(a, a);

std::printf("a + a =\n%s\n", b.to_string().c_str());

try {
const Tensor bad = ops::matmul(a, Tensor::ones({5, 7}, DataType::Float32));
} catch (const ClikaRT::Error& e) {
std::printf("failed: %s\n", e.what()); // e.status() has the coarse category
}
return 0;
}

Set up, build, run

The setup is where the languages differ.

The CMake side is three lines of substance (the package and one target).

CMakeLists.txt
cmake_minimum_required(VERSION 3.20)
project(hello_clikart LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(ClikaRT CONFIG REQUIRED)

add_executable(hello main.cpp)
target_link_libraries(hello PRIVATE ClikaRT::ClikaRT)
cmake -S . -B build -DClikaRT_DIR="$CLIKART_BUNDLE_DIR/cmake"
cmake --build build
./build/hello
ClikaRT 0.4.6
a + a =
Tensor(shape=[2, 3], dtype=Float32, device=CPU, numel=6, data=[2, 2, 2, 2, 2, 2])
failed: ops::matmul: cannot contract a [2, 3] with b [5, 7]: a's last dim (3) must equal b's dim 0 (5)

The version line proves the runtime loaded, and the tensor prints its shape, dtype, device and values, every element 2. The last line is the failure path, demonstrated at the end of the program and explained below.

One library, one header

The umbrella header ClikaRT/clika_rt.h includes the entire public API (tensors, operators, devices, I/O, the serving runtime). ClikaRT::ClikaRT is the only link target. Nothing else from the bundle enters your build; the accelerator backends are shared libraries the runtime loads on its own at run time (part 3).

Values out, ClikaRT::Error on failure

Every fallible call in the public API (factories like Tensor::ones, operators like ops::add) returns its result directly and raises ClikaRT::Error on failure. There are no output parameters and no error codes to check at each call; a shape mismatch or an unavailable device surfaces as an exception where the call was made:

try {
const Tensor bad = ops::matmul(a, Tensor::ones({5, 7}, DataType::Float32));
} catch (const ClikaRT::Error& e) {
std::printf("failed: %s\n", e.what()); // e.status() has the coarse category
}

Catch it where you can act on it. The programs in this series let a failure terminate the process, the right default for a small batch program. The message names the operation and the values it refused (here the two shapes); the stable, machine-readable channel is the code name, which Handle errors by code covers.

Next: part 2, tensors and the ops:: library properly.