# Installation

> NumKong for C

With CMake `FetchContent`:

```cmake
include(FetchContent)

FetchContent_Declare(
    numkong
    GIT_REPOSITORY https://github.com/ashvardanian/NumKong.git
    GIT_SHALLOW TRUE
)
FetchContent_MakeAvailable(numkong)

target_link_libraries(my_target PRIVATE numkong::header) # or numkong::static, numkong::shared
```

Vendored:

```cmake
add_subdirectory(external/NumKong)
target_link_libraries(my_target PRIVATE numkong::header) # or numkong::static, numkong::shared
```

`numkong::static` and `numkong::shared` exist when `NUMKONG_BUILD_SHARED` is on, the default only for a top-level build.
An installed NumKong provides the same targets through `find_package(numkong CONFIG REQUIRED)`.

By default the headers declare every public function and the library defines it, each kernel once, in the unit of its capability.
`numkong::header` sets `NUMKONG_HEADER_ONLY=1` instead: every kernel compiles into your translation unit, and every dispatch point and finder returns `nk_missing_library_k`, so a header-only build calls a capability's kernel, like `nk_dot_f32_haswell`, directly.

### Building and Cross-Compiling

The build enforces C99 for the C layer and C++20 for the C++ layer.
[CONTRIBUTING.md](https://github.com/ashvardanian/NumKong/blob/main/CONTRIBUTING.md#building) lists the CMake presets and options, and [its cross-compilation section](https://github.com/ashvardanian/NumKong/blob/main/CONTRIBUTING.md#cross-compilation) the toolchain files in `cmake/` with a recipe for each target.
A translation unit linking `numkong::static` or `numkong::shared` sees declarations only, while `numkong::header` defines `NUMKONG_HEADER_ONLY=1` and compiles the kernels inline.
The library compiles every capability whose probe in `probes/` compiles, each scoped to its kernels by target pragmas, and dispatches between them by runtime detection.
LASX and POWER9 scope that way only under GCC 15 or newer; Clang's intrinsics headers stay closed without `-mlasx` or `-mcpu=power9`.
Header-only units enable the capabilities their own flags name.

`#include <numkong/types.h>`

## NUMKONG_CONSTEXPR

Internal helper that callers can fold at compile time, and that CUDA kernels can call through `--expt-relaxed-constexpr`.

```c
#define NUMKONG_CONSTEXPR NUMKONG_MAYBE_UNUSED_ NUMKONG_C_INLINE_
```

It is `constexpr` from C++20.

## NUMKONG_API

Compiles every kernel into this translation unit and stubs every dispatch point and finder with [`nk_missing_library_k`](https://www.unum.cloud/docs/numkong/c/quickstart.md#nk_missing_library_k), instead of linking them from the NumKong library.

```c
#define NUMKONG_API
```

Every public function: header-inline in header-only builds, otherwise defined once in the library. Windows DLLs export every symbol through CMake, so no import or export spelling.

## NUMKONG_DEBUG

Debug builds check the library's invariants with `nk_assert_`, defaulting from `DEBUG` or `_DEBUG`.

```c
#define NUMKONG_DEBUG 0
```

## NUMKONG_ALLOW_ISA_REDIRECT

Allow SIMD kernels to redirect small inputs to serial implementations.

```c
#define NUMKONG_ALLOW_ISA_REDIRECT 1
```

Enabled by default for production use. Tests and benchmarks may disable this to isolate SIMD path behavior.

## NUMKONG_MULTIVERSIONED

0 folds each dispatch table to its best kernel; 1, the default, keeps every compiled one.

```c
#define NUMKONG_MULTIVERSIONED 1
```

## NUMKONG_NULL

[`NUMKONG_NULL`](#NUMKONG_NULL), analogous to `NULL`, so headers need not pull in `<stddef.h>`.

```c
#define NUMKONG_NULL ((void *)0)
```

`__null` gives better null-pointer diagnostics where the compiler provides it. The `nullptr` branch matters for MSVC C++: unlike C, it forbids a `void *` arm in a typed conditional, so `(void *)0` there fails to compile.

## NUMKONG_NATIVE_F16

Half-precision (16-bit) IEEE 754 float.

```c
#define NUMKONG_NATIVE_F16 0
```

Layout: sign(1) + exponent(5) + mantissa(10), bias=15. Range: ±65 504, epsilon at 1.0 ≈ 9.77×10⁻⁴. 30 722 of 63 488 finite values (48.4%) in [−1, +1].

- `unsigned short` by default, on every compiler and architecture.
- `NUMKONG_NATIVE_F16=1`: `__fp16` on Arm, `_Float16` elsewhere.The type crosses the exported ABI by value — [`nk_f16_sqrt_best`](https://www.unum.cloud/docs/numkong/c/scalar-types.md#nk_f16_sqrt_best), [`nk_f16_order_best`](https://www.unum.cloud/docs/numkong/c/scalar-types.md#nk_f16_order_best) — and a native half is passed in a different register class than `unsigned short`. Deriving it from `-march`, as this once did, let each consumer reach its own answer: Swift's header import sees a native half on Apple silicon while the C sources it links were built `unsigned short`, and `rust/scalar.rs` binds `u16` outright. Enabling it is a decision for a whole build, never for one translation unit, so the default cannot depend on flags.

## NUMKONG_NATIVE_BF16

BFloat16 (16-bit) float — truncated IEEE 754 single-precision.

```c
#define NUMKONG_NATIVE_BF16 0
```

Layout: sign(1) + exponent(8) + mantissa(7), bias=127. Same dynamic range as f32, epsilon ≈ 7.81×10⁻³. 32 514 of 65 280 finite values (49.8%) in [−1, +1]. Wider range than f16 but lower precision.

- `unsigned short` by default, on every compiler and architecture.
- `NUMKONG_NATIVE_BF16=1`: `__bf16` on GCC and Clang. See `nk_f16_t` for why this is opt-in.The compilers have added `__bf16` support in compliance with the x86-64 psABI spec. The motivation for this new special type is summed up as:

"Currently @c __bfloat16 is a typedef of short, which creates a problem where the compiler does
not raise any alarms if it is used to add, subtract, multiply or divide, but the result of the
calculation is actually meaningless. To solve this problem, a real scalar type @c __Bfloat16
needs to be introduced. It is mainly used for intrinsics, not available for C standard
operators. @c __Bfloat16 will also be used for movement like passing parameter, load and store,
vector initialization, vector shuffle, and etc. It creates a need for a corresponding psABI."

Warnings: Apple Clang has hard time with bf16.

See also: Writing ARM64 code for Apple platforms: [https://developer.apple.com/documentation/xcode/writing-arm64-code-for-apple-platforms](https://developer.apple.com/documentation/xcode/writing-arm64-code-for-apple-platforms)

See also: Apple Developer Forums thread on bf16: [https://forums.developer.apple.com/forums/thread/726201](https://forums.developer.apple.com/forums/thread/726201)

See also: GCC and LLVM bf16 support on Phoronix: [https://www.phoronix.com/news/GCC-LLVM-bf16-BFloat16-Type](https://www.phoronix.com/news/GCC-LLVM-bf16-BFloat16-Type)

