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>
59 lines
1.8 KiB
C
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; }
|