Skip to content

C Quick Start

Everything on this page is executed in CI — the consumer program and all three build commands are included from the very files the release smoke runs on linux-x86_64, linux-aarch64, and macos-arm64.

Get the library

No toolchain needed — jbx get-doppler grabs the pre-built release tarball (headers + libdoppler.a/.so + the optional stream component):

jbx get-doppler                          # extracts to $HOME/.local/doppler

Other routes (manual tarball, custom prefixes, system install, building from source): Install → C Library.

The consumer

Any main.c works; this is the one CI builds — the FFT example plus one optional streaming call. dp_pub_*/dp_sub_* live in the optional libdoppler_stream; drop that call and the _stream bits below for a core-only app (then the whole link line is libdoppler.a -lm):

#include <complex.h>
#include <stdio.h>

#include <fft/fft_core.h>  /* core:   libdoppler          */
#include <stream/stream.h> /* stream: libdoppler_stream   */

int
main (void)
{
  /* core — the homepage FFT example, checksummed */
  float complex in[1024] = { 0 };
  float complex out[1024];
  for (int i = 0; i < 1024; i++)
    in[i] = (i % 8 == 0) ? 1.0f : 0.0f; /* impulse train */

  fft_state_t *fft = fft_create (1024, -1, 1);
  fft_execute_cf32 (fft, in, 1024, out, 1024);
  fft_destroy (fft);

  double acc = 0.0;
  for (int i = 0; i < 1024; i++)
    acc += cabsf (out[i]);
  printf ("fft checksum: %.1f\n", acc);

  /* stream — dp_pub_* lives in libdoppler_stream; linking this call is
     the point of the exercise.  A live broker is optional here. */
  dp_pub_t *tx = dp_pub_create ("nats://127.0.0.1:4222/smoke", CF64);
  printf ("stream: %s\n", tx ? "connected" : "linked, no broker");
  if (tx)
    dp_pub_destroy (tx);
  return 0;
}

Compile it — three ways

Set the prefix once (wherever jbx get-doppler extracted), then pick any face. All three are built and diffed against each other in CI: the three binaries must produce identical output.

PREFIX="$HOME/.local/doppler"
cc app.c -I "$PREFIX/include" \
   "$PREFIX/lib/libdoppler_stream.a" \
   "$PREFIX/lib/libdoppler.a" \
   -lm -lpthread -o app
cmake_minimum_required(VERSION 3.16)
project(app C)

# Point CMake at the install prefix: -DCMAKE_PREFIX_PATH=<prefix>
find_package(doppler REQUIRED)

add_executable(app app.c)
target_link_libraries(app PRIVATE doppler::doppler)
# Using dp_pub_*/dp_sub_*? Add the optional stream component:
target_link_libraries(app PRIVATE doppler::stream)
cmake -B build -DCMAKE_PREFIX_PATH="$PREFIX"
cmake --build build
export PKG_CONFIG_PATH="$PREFIX/lib/pkgconfig"
cc app.c $(pkg-config --cflags --libs doppler_stream) -lm -o app

The CMake and pkg-config faces link the shared libraries by default — add $PREFIX/lib to the loader path (LD_LIBRARY_PATH, or an rpath) to run outside the prefix. The cc face is static and self-contained.

Next steps