C extensions with 2:¶
Build one C library and call its functions from PeachQ using 2:. You'll add two
numbers, sum a vector and let C call a q function twice. If you already use 2:
in q, this example shows the familiar loading expression and object interface in
a complete build-and-run session.
The three C entry points return 5, 6.5 and 700. The last is 7 * 10 * 10, calculated
by a q callback invoked from C. See the dynamic-load reference
and C API reference for signatures;
this guide walks through their use. For C functions taking native values such as
double rather than K objects, see FFI.
Build the extension¶
The commands below use Bash, curl, tar and GCC on Linux x86-64 with glibc.
Start in a fresh directory.
Requires the Linux glibc build
This integration loads a shared library. Use PeachQ's Linux glibc build, available as the DuckDB/glibc download. The standard static Linux build cannot load shared libraries.
mkdir peachq-c-demo && cd peachq-c-demo
curl -fL https://peachq.org/download/peachq-linux-x64-duckdb.tar.gz -o peachq.tar.gz
tar -xzf peachq.tar.gz
curl -fL https://raw.githubusercontent.com/KxSystems/kdb/master/c/c/k.h -o k.h
Create add.c with these three functions. You can also save the
downloadable C source, supplied under its
MIT licence.
#include "k.h"
K add(K x, K y) {
if (x->t != -KJ || y->t != -KJ) return krr("type");
return kj(x->j + y->j);
}
K total(K x) {
if (x->t != KF) return krr("type");
F s = 0;
for (J i = 0; i < x->n; i++) s += kF(x)[i];
return kf(s);
}
K twice(K f, K x) {
return k(0, "{x x y}", r1(f), r1(x), (K)0);
}
Compile it, then start PeachQ in the same directory:
gcc -shared -fPIC -DKXVER=3 add.c -o add.so
./q -q
-shared produces a shared library, -fPIC makes its code position-independent,
and KXVER=3 selects the header's 64-bit object layout. There is no q library to
link: the running PeachQ executable supplies the C API symbols when it loads
add.so.
Load and call a C function¶
At the q prompt:
The left operand names the library; omitting the suffix uses .so on Linux.
The pair on the right gives the exported C function name and its argument count:
add takes two K arguments. The returned function supports projection and
each, just like the q functions you already use:
Inside add, -KJ means a long atom and x->j reads its value. The constructor
kj allocates the long atom returned to q. The type checks run before either
value is read, so add[2;3.5] reports 'type rather than treating a float as a
long. krr("type") creates that error.
These small arithmetic examples assume ordinary finite values. They do not implement q's null, infinity or integer-overflow rules.
Pass a vector to C¶
total accepts a float vector, identified by the positive type tag KF. Its
length is x->n, and kF(x)[i] reads the element at index i. The loop sums
those elements into a C double (F), then kf returns a float atom to q.
The literal 1 2 3.5 is a float vector because it contains a float. An all-long
vector such as 1 2 3 fails this function's type check; use 1 2 3f when you
want float input.
Call q from C¶
k(0, "{x x y}", ..., (K)0) evaluates the q expression in the current process.
Here x is the function {x*10} and y is 7. Read {x x y} as
{x[x[y]]}: the inner call produces 70, and the outer call produces 700.
The terminating (K)0 ends the C argument list.
Incoming K arguments are borrowed. k() consumes the references passed to it,
so r1(f) and r1(x) acquire references for that call without giving away the
caller's references. The result of k() is returned directly to q. For other
extensions, return a newly allocated object or r1(x) if returning an incoming
argument; use r0 only to release references you own.
This callback uses handle 0. PeachQ's extension entry point currently rejects
a non-zero handle with 'nyi; use q's IPC facilities
for remote requests.
Bring an existing extension¶
The example demonstrates loading, projection, vector input and a q callback
using the k.h interface. Before using another extension:
- Match the operating system, architecture and header layout. The build above
targets Linux x86-64 with
KXVER=3. - Inspect exports with
nm -D --defined-only myext.soand dependencies withnm -u myext.so. C++ entry points needextern "C"to keep the names used by2:. - Check code that reads object headers directly. In particular, do not assume
raw reference counts match kdb+/q; prefer the
r1andr0ownership operations. - Run the extension's own tests, including errors, object lifetimes and callbacks. Successful use of this example does not establish compatibility for every C API call.
Restart PeachQ after rebuilding a loaded .so, so the next session uses the new
library. An error naming the entry point usually means the library opened but
that function was not found; inspect the exported names first.
Thanks¶
Thanks to Michael Keenan for the initial code and core idea behind PeachQ's
2: support.