Skip to content

C Quick Start

Get the library, build a small program against it three ways, and run it. The commands below are the tested ones — copy them as they are.

Get the library

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

Don't have jbx yet?

Install it once, then run the command below:

. <(curl -sSL https://just-buildit.github.io/get-jb.sh)

It lands in $HOME/.local/bin and the leading . puts that on PATH for this shell. Details: Get jbx.

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

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

The consumer

Save this as app.c in an empty folder; the commands below build that file. It is the FFT example plus one optional streaming call. dp_pub_*/dp_sub_* live in the optional libdoppler_stream, and publishing needs a running NATS broker; drop that call and the _stream bits below for a core-only app (then the whole link line is libdoppler.a -lm -lpthread):

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

#include <doppler/fft/fft_core.h>  /* core:   libdoppler          */
#include <doppler/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 */

  dp_fft_state_t *fft = dp_fft_create (1024, -1, 1);
  dp_fft_execute_cf32 (fft, in, 1024, out, 1024);
  dp_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; they build the same program, so use whichever matches your build system.

PREFIX="$HOME/.local/doppler"
cc app.c -I "$PREFIX/include" \
   "$PREFIX/lib/libdoppler_stream.a" \
   "$PREFIX/lib/libdoppler.a" \
   -lm -lpthread -o app

Save as CMakeLists.txt next to app.c:

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)

then, from that folder:

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) \
   -Wl,-rpath,"$(pkg-config --variable=libdir doppler_stream)" -lm -o app

The cc face is static and self-contained. The CMake and pkg-config faces link the shared libraries in $PREFIX/lib, which is not on the system loader path, so each records where they are in the executable (an rpath): CMake does it for you, and the pkg-config command says it with -Wl,-rpath. That is what lets ./app run as built. (After a .deb/.rpm install the library is already on the loader path, so the flag is unnecessary there, and harmless.) If you move the binary off this machine, or delete the prefix, set LD_LIBRARY_PATH (DYLD_LIBRARY_PATH on macOS) or re-link.

Next steps