ludic/packages/ludic.nativeecho/native/shim/nativeecho.c
Orkuncakilkaya 5d3a799e33 feat(pkg): phase 15 - a package can carry a native library
native "<target>" "<path>" in a package's package.ludic; the compiler records the libraries of
every package a program imports and writes them into the IR (; ludic-native:), so ludicc -o,
ludic build, ludic test and ludic bundle all link one list. macOS: an rpath to the package and to
Contents/Frameworks, where ludic bundle copies and signs each library and drops the build
machine's rpath. Windows: the import library, the .dll copied beside the exe (--natives-out for
the bundle). tools/native/lib.sh builds from a pinned, checksummed source with clang on both
machines; ludic.nativeecho is the worked example; the shim rules are in packages/README.md.
Linked at build time rather than dlopen (docs/PACKAGES.md says why). Reseeded.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 23:35:45 +03:00

59 lines
1.8 KiB
C

/* nativeecho - the shape every shim in packages/ has (packages/README.md, "Native libraries"):
int, long, float and opaque handles cross; no struct by value, no callback into Ludic. What a
library would report through a callback is recorded here and drained after the call returns. */
#include <stdint.h>
#if defined(_WIN32)
#define NE_API __declspec(dllexport)
#else
#define NE_API __attribute__((visibility("default")))
#endif
#define NE_CAP 64
static int ne_kinds[NE_CAP];
static float ne_values[NE_CAP];
static int ne_count = 0;
static int ne_lost = 0;
/* the sum of n floats the package owns */
NE_API float ne_sum(const float *xs, int n) {
float s = 0.0f;
for (int i = 0; i < n; i++) s += xs[i];
return s;
}
/* what a callback would have reported: kept until drained, counted as lost past the cap */
NE_API int ne_record(int kind, float value) {
if (ne_count >= NE_CAP) { ne_lost++; return -1; }
ne_kinds[ne_count] = kind;
ne_values[ne_count] = value;
ne_count++;
return 0;
}
/* a library's work that "calls back" once per element over a threshold */
NE_API int ne_scan(const float *xs, int n, float over) {
int hits = 0;
for (int i = 0; i < n; i++) {
if (xs[i] > over) { ne_record(i, xs[i]); hits++; }
}
return hits;
}
/* copy up to cap pending records into two slices the package owns; returns how many */
NE_API int ne_drain(int *kinds, float *values, int cap) {
int n = ne_count < cap ? ne_count : cap;
for (int i = 0; i < n; i++) { kinds[i] = ne_kinds[i]; values[i] = ne_values[i]; }
for (int i = n; i < ne_count; i++) {
ne_kinds[i - n] = ne_kinds[i];
ne_values[i - n] = ne_values[i];
}
ne_count -= n;
return n;
}
NE_API int ne_lost_count(void) { return ne_lost; }
/* a 64-bit value round trip: handles and counts wider than 32 bits cross as long */
NE_API int64_t ne_twice(int64_t x) { return x * 2; }