---
title: Your first program
sidebar_label: 1. Your first program
description: "Link the bundle, print the version, make your first tensor, and meet the error model."
---

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++ and Kotlin paths assume the bundle is extracted and `CLIKART_BUNDLE_DIR` points at it (see [Quick install](../installation.md)); the Python wheel carries the runtime itself.

Every program here runs compute, so every one of them needs a license credential. `CLIKA_RT_LICENSE` in the environment carries it to the C++ and Kotlin programs and to Python, and `clikart-license-init` stores it once per user account instead; [License the runtime](../../how-to/license-the-runtime.mdx) is the contract. Python has one extra rule, in its tab below.

## The program

<LangTabs>

<LangTab value="cpp">

```cpp title="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;
}
```

</LangTab>

<LangTab value="python">

```python title="main.py"
import clika_runtime as crt


def main() -> None:
    print(f"ClikaRT {crt.version()}")

    # A 2x3 tensor of ones on the CPU (the default device). Factories take
    # the shape directly; float32 is the default dtype.
    a = crt.ones(2, 3)

    # Operators read as math; every result is a new tensor.
    b = a + a

    print(f"a + a =\n{b}")

    try:
        bad = a @ crt.ones(5, 7)
    except RuntimeError as e:
        print(f"failed: {e}")  # the message ends in the machine-readable [code: NAME]


if __name__ == "__main__":
    main()
```

</LangTab>

<LangTab value="kotlin">

```kotlin title="Main.kt"
import io.clika.runtime.ClikaRt
import io.clika.runtime.ClikaRtException
import io.clika.runtime.Ops
import io.clika.runtime.Tensors

fun main() {
    ClikaRt.load()
    println("ClikaRT ${ClikaRt.version()}")

    // A 2x3 tensor of ones on the CPU (the default placement); float32 is
    // the default dtype.
    val a = Tensors.ones(longArrayOf(2, 3))

    // Every operator is one function of Ops. It returns a fresh tensor and
    // leaves its operands live; a tensor is AutoCloseable, so release the
    // ones you named, or scope them with `use`.
    val b = Ops.add(a, a)

    println("a + a =\n${b.summary()}")

    try {
        Tensors.ones(longArrayOf(5, 7)).use { bad -> Ops.matmul(a, bad) }
    } catch (e: ClikaRtException) {
        println("failed: ${e.message}")  // e.codeName is the machine channel, e.status the category
    }
    b.release()
    a.release()
}
```

</LangTab>

</LangTabs>

## Set up, build, run

The setup is where the languages differ.

<LangTabs>

<LangTab value="cpp">

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

```cmake title="CMakeLists.txt"
cmake_minimum_required(VERSION 3.19)
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)
```

```bash
cmake -S . -B build -DClikaRT_DIR="$CLIKART_BUNDLE_DIR/cmake"
cmake --build build
./build/hello
```

</LangTab>

<LangTab value="python">

The wheel carries the runtime and its backends; the bundle is not needed on this path. [Get ClikaRT](../get-clikart.mdx#python-wheels) has the wheel to download (on Linux, the flavor follows your NVIDIA driver) and the install command. `numpy` is the array bridge for building tensors from Python data (optional by design, and these pages use it).

```bash
pip install ./clika_runtime-<version>-<cpython>-<platform>.whl
pip install numpy
export CLIKA_RT_LICENSE=CLIKA1-...
python main.py
```

`import clika_runtime` loads the runtime, so `CLIKA_RT_LICENSE` has to be set before the import runs. A shell `export` does that. From inside the program, assign `os.environ["CLIKA_RT_LICENSE"]` above the import. The wheel also installs `clikart-license-init` as a console script, which stores the credential once per user account and drops the variable entirely.

</LangTab>

<LangTab value="kotlin">

{/* CERTIFICATION: the Kotlin arm follows the release's Kotlin artifact (clika-runtime-maven-<version>.zip)
and the tutorial's gradle project beside the programs, both of the pinned release. */}

The Kotlin artifact, `clika-runtime-maven-0.6.4.zip`, extracts to a Maven repository directory that the gradle project names through the `clikaRtMavenRepo` property; it ships the Kotlin API and its JNI bridge. `libClikaRT.so` comes from the bundle, so run the JVM with `-Djava.library.path` pointing at the bundle's `lib` directory.

```kotlin title="build.gradle.kts"
// examples/kotlin/tutorial: the Kotlin programs of the getting-started
// tutorial, one file per chapter (NN_<chapter>.kt), built for a desktop JVM
// against the release's Kotlin artifact, io.clika:clika-runtime (the
// extracted clika-runtime-maven-<version>.zip, named to settings.gradle.kts
// by -PclikaRtMavenRepo=<dir>). At run time ClikaRt loads two libraries:
// libClikaRT.so by name from java.library.path, a runtime distribution's
// lib/, and the JNI bridge libclika_rt_jni.so from the artifact's own jar
// (its native/<platform>/ entry, extracted at start):
//
//   gradle installDist -PclikaRtMavenRepo=<maven dir>
//   java -Djava.library.path=<dist>/lib -cp 'build/install/tutorial/lib/*' _01_your_first_programKt
//
// or in one step (CLIKA_RT_LIB_DIR in the environment names <dist>/lib too):
//
//   gradle run -Pchapter=01_your_first_program -PclikaRtMavenRepo=<maven dir> -PclikaRtLibDir=<dist>/lib
//
// 06_deploy_to_mobile.kt is the Android chapter's Kotlin half: it compiles
// here and has no main to run.
plugins {
    kotlin("jvm") version "2.3.0"
    application
}

java {
    toolchain {
        languageVersion.set(JavaLanguageVersion.of(17))
    }
}

// One compilation: the chapter files beside this build script. Each chapter's
// top-level main lands in its own class, named after the file
// (01_your_first_program.kt -> _01_your_first_programKt).
sourceSets {
    main {
        kotlin.setSrcDirs(listOf(layout.projectDirectory))
        kotlin.include("??_*.kt")
    }
}

dependencies {
    // The runtime's Kotlin API, the release's artifact (its version read from the repository directory).
    implementation("io.clika:clika-runtime:${project.extra["clikaRtVersion"]}")
}

val chapter = providers.gradleProperty("chapter").orElse("01_your_first_program")
val clikaRtLibDir = providers.gradleProperty("clikaRtLibDir")
    .orElse(providers.environmentVariable("CLIKA_RT_LIB_DIR"))
    .orElse("")

application {
    mainClass.set(chapter.map { "_${it}Kt" })
}

tasks.named<JavaExec>("run") {
    workingDir = projectDir
    doFirst {
        if (clikaRtLibDir.get().isEmpty()) {
            throw GradleException("name the runtime distribution's lib/: -PclikaRtLibDir=<dist>/lib or CLIKA_RT_LIB_DIR")
        }
    }
    systemProperty("java.library.path", clikaRtLibDir.get())
}
```

```bash
gradle run -Pchapter=01_your_first_program -PclikaRtMavenRepo="$PWD/clika-runtime-maven-0.6.4" -PclikaRtLibDir="$CLIKART_BUNDLE_DIR/lib"
```

</LangTab>

</LangTabs>

```text
ClikaRT 0.6.4
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](03-devices-and-async.mdx)).

## 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:

<LangTabs>

<LangTab value="cpp">

```cpp
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
}
```

</LangTab>

<LangTab value="python">

```python
try:
    bad = a @ crt.ones(5, 7)
except RuntimeError as e:
    print(f"failed: {e}")  # the message ends in the machine-readable [code: NAME]
```

</LangTab>

<LangTab value="kotlin">

```kotlin
try {
    Tensors.ones(longArrayOf(5, 7)).use { bad -> Ops.matmul(a, bad) }
} catch (e: ClikaRtException) {
    println("failed: ${e.message}")  // e.codeName is the machine channel, e.status the category
}
```

</LangTab>

</LangTabs>

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](../../how-to/handle-errors-by-code.mdx) covers.

Next: [part 2](02-tensors-and-operators.mdx), tensors and the `ops::` library properly.
