rainwayapp / node-clangffi Goto Github PK
View Code? Open in Web Editor NEWGenerate Typescript FFI bindings for C/C++ libraries using libclang and ffi-napi.
License: MIT License
Generate Typescript FFI bindings for C/C++ libraries using libclang and ffi-napi.
License: MIT License
There is still some inconsistency between what a *Def
stores, and what a *Type
represents. To avoid this, it's probably better to use UnderlyingType
from ref-napi
rather than generating it ourselves. E.g:
type MyStructType = UnderlyingType<typeof MyStructDef>;
instead of
type MyStructType = StructObject<MyStruct>;
since the TS typing and the coerced ref-napi
NamedType
may not align exactly.
The current CI "integration" test is to walk libclang v13 and ensure we find the same types in it each time. This is good for ensuring we can always regenerate libclang-bindings
using libclang-bindings
but probably doesn't need to happen for validation of a PR, given it takes upwards of 15m in CI.
We should instead introduce a smaller integration test(s) that give us similar confidence, but execute much more quickly. Further, rather then just removing the existing one, we could consider instead running that only on check-in to main
(after PR has been merged) for added confidence, but without slowing down the inner loop.
#[repr(u8)]
#[derive(Debug, Display, Copy, Clone, Eq, PartialEq)]
pub enum RainwayChannelMode {
Unreliable = 0,
Reliable = 1,
}
Take this perfectly innocuous looking enum in Rust. It generates this wonderfully correct C/C++ header definition via cbindgen:
enum RainwayChannelMode
#ifdef __cplusplus
: uint8_t
#endif // __cplusplus
{
Unreliable = 0,
Reliable = 1,
};
#ifndef __cplusplus
typedef uint8_t RainwayChannelMode;
#endif // __cplusplus
But then node-clangffi seems to think it is a bit confusing because it ends up generating
export enum RainwayChannelMode {
Unreliable = 0,
Reliable = 1,
}
export type RainwayChannelMode = number;
// ...
export const RainwayChannelModeDef = ref.types.int;
export const RainwayChannelModeDef = ref.types.uint8;
Basically we need the uint8_t
typedef to override the size, but to only keep the enum definition.
https://github.com/google-github-actions/release-please-action/releases/tag/v3.0.0
Most impactfully, this means that release_created
won't currently be set for us, meaning the npm publish won't occur. We could either:
.
so that it gets setWhen we're ready to share this work publicly, we should re-enable the npm publish step here.
If given a header with the following:
typedef void (*MyFunctionPointer)(void);
Then clangffi
will generate:
export type MyFunctionPointer(arg0:) => void;
which is invalid. It should instead generate:
export type MyFunctionPointer() => void;
It should be possible for us to map in comments. We should further evaluate and consider doing so.
It's worth noting that due to how ffi.Library()
works, we won't be able to easily name parameters, which may make some comments fairly confusing.
We should use BigInt
for numbers greater than i32 (e.g. i64
+) in our typings, rather than number
which is what we use today.
Oops! Our recent test addition got included in publishing. We should add tests/
to .npmignore
Today CXTypeKind.CXType_Attributed
isn't well supported. We should be able to get the modified type via the Type
model.
Seems we need a v17 node version that includes nodejs/node#33321 - otherwise we crash (ex: https://github.com/RainwayApp/node-clangffi/runs/4707348089?check_suite_focus=true)
We should include engines
in package.json
to clarify this.
It appears _Bool
is a valid c99 type we should support - https://stackoverflow.com/questions/24602814/bool-data-type-of-c99
We should provide a better error when we cannot load, due to missing or unable to find libclang
.
CD publish to npm has stopped working: https://github.com/RainwayApp/node-clangffi/actions/runs/1685463659
We should provide a way for a user to call clangffi
specifying some flags to define symbols. E.g. -DDEBUG=1
to define DEBUG=1
.
This should work similarly to clang /D <macro=value>
here
Anywhere we accept a symbol filter today we should be able to use wildcards - e.g. time_t
should be able to be time*
if we'd prefer.
when giving --no-prettier
, prettier is still used.
Using set DEBUG=clangffi
to log cli arguments object, it's clear that noPrettier
value is still false
.
Hi,
I am trying to generate bindings for ObjectBox but clangffi keeps crashing with the following error:
clangffi {
clangffi "_": [],
clangffi "lib-path": "/usr/lib/x86_64-linux-gnu/libclang-14.so",
clangffi "libPath": "/usr/lib/x86_64-linux-gnu/libclang-14.so",
clangffi "i": "objectbox.h",
clangffi "input": "objectbox.h",
clangffi "o": "objectbox.ts",
clangffi "output": "objectbox.ts",
clangffi "default-symbols": false,
clangffi "defaultSymbols": false,
clangffi "L": "c",
clangffi "language": "c",
clangffi "I": [],
clangffi "include-directory": [],
clangffi "includeDirectory": [],
clangffi "D": [],
clangffi "define": [],
clangffi "R": [],
clangffi "hard-remap": [],
clangffi "remap": [],
clangffi "hardRemap": [],
clangffi "crlf": false,
clangffi "prettier": true,
clangffi "include": [],
clangffi "include-file": [],
clangffi "includeFile": [],
clangffi "exclude": [],
clangffi "clean-enum-constants": true,
clangffi "cleanEnumConstants": true,
clangffi "$0": "clangffi"
clangffi } +0ms
clangffi:tsgen open(objectbox.ts): begin +0ms
clangffi:tsgen open(objectbox.ts): end +1ms
clangffi:parser skip '__u_char' from '/usr/include/x86_64-linux-gnu/bits/types.h'. +0ms
clangffi:parser skip '__u_short' from '/usr/include/x86_64-linux-gnu/bits/types.h'. +16ms
clangffi:parser skip '__u_int' from '/usr/include/x86_64-linux-gnu/bits/types.h'. +17ms
clangffi:parser skip '__u_long' from '/usr/include/x86_64-linux-gnu/bits/types.h'. +19ms
clangffi:parser skip '__int8_t' from '/usr/include/x86_64-linux-gnu/bits/types.h'. +14ms
clangffi:parser skip '__uint8_t' from '/usr/include/x86_64-linux-gnu/bits/types.h'. +16ms
clangffi:parser skip '__int16_t' from '/usr/include/x86_64-linux-gnu/bits/types.h'. +17ms
clangffi:parser skip '__uint16_t' from '/usr/include/x86_64-linux-gnu/bits/types.h'. +15ms
clangffi:parser skip '__int32_t' from '/usr/include/x86_64-linux-gnu/bits/types.h'. +16ms
clangffi:parser skip '__uint32_t' from '/usr/include/x86_64-linux-gnu/bits/types.h'. +15ms
clangffi:parser skip '__int64_t' from '/usr/include/x86_64-linux-gnu/bits/types.h'. +16ms
clangffi:parser skip '__uint64_t' from '/usr/include/x86_64-linux-gnu/bits/types.h'. +15ms
clangffi:parser skip '__int_least8_t' from '/usr/include/x86_64-linux-gnu/bits/types.h'. +19ms
clangffi:parser skip '__uint_least8_t' from '/usr/include/x86_64-linux-gnu/bits/types.h'. +18ms
clangffi:parser skip '__int_least16_t' from '/usr/include/x86_64-linux-gnu/bits/types.h'. +15ms
clangffi:parser skip '__uint_least16_t' from '/usr/include/x86_64-linux-gnu/bits/types.h'. +16ms
clangffi:parser skip '__int_least32_t' from '/usr/include/x86_64-linux-gnu/bits/types.h'. +14ms
clangffi:parser skip '__uint_least32_t' from '/usr/include/x86_64-linux-gnu/bits/types.h'. +15ms
#
# Fatal error in , line 0
# Check failed: result.second.
#
#
#
#FailureMessage Object: 0x7ffee494ace0
1: 0xb76401 [node]
2: 0x1c09824 V8_Fatal(char const*, ...) [node]
3: 0xfcecd1 v8::internal::GlobalBackingStoreRegistry::Register(std::shared_ptr<v8::internal::BackingStore>) [node]
4: 0xd20518 v8::ArrayBuffer::GetBackingStore() [node]
5: 0xabdc90 napi_get_typedarray_info [node]
6: 0x7f0f95c053ac [/home/thecodrr/.npm/_npx/0a8e200cae307ad8/node_modules/ref-napi/prebuilds/linux-x64/node.napi.node]
7: 0x7f0f95c05b48 [/home/thecodrr/.npm/_npx/0a8e200cae307ad8/node_modules/ref-napi/prebuilds/linux-x64/node.napi.node]
8: 0x7f0f95c07831 [/home/thecodrr/.npm/_npx/0a8e200cae307ad8/node_modules/ref-napi/prebuilds/linux-x64/node.napi.node]
9: 0x7f0f95c0d4ab Napi::details::CallbackData<void (*)(Napi::CallbackInfo const&), void>::Wrapper(napi_env__*, napi_callback_info__*) [/home/thecodrr/.npm/_npx/0a8e200cae307ad8/node_modules/ref-napi/prebuilds/linux-x64/node.napi.node]
10: 0xab45dd [node]
11: 0xd5531e [node]
12: 0xd5673f v8::internal::Builtin_HandleApiCall(int, unsigned long*, v8::internal::Isolate*) [node]
13: 0x15f2199 [node]
Trace/breakpoint trap (core dumped)
I am running the following command:
DEBUG=clangffi* npx clangffi --lib-path /usr/lib/x86_64-linux-gnu/libclang-13.so -i objectbox.h -o objectbox.ts
Node v16.15.1
libclang v13
Header file: https://raw.githubusercontent.com/objectbox/objectbox-c/main/include/objectbox.h
We need to close on what OSS license to use, and then update the following:
license
field, in all projects)README.md
language (in root)We should be able to override the default mapping if need be.
E.g. time_t => long long
How exactly do I need to provide libclang? Is it libclang.so
or a binary named libclang
? I've built LLVM on my system and provided both its libclang.so
and the one in PATH, but I still can't get any more output than what's below. It seems like clangffi
isn't using the libclang I'm providing.
import ffi from "ffi-napi";
import ref, { Pointer as TypedPointer, UnderlyingType } from "ref-napi";
import refStructDi, { StructObject } from "ref-struct-di";
import refArrayDi, { TypedArray } from "ref-array-di";
import refUnionDi from "ref-union-di";
const Struct = refStructDi(ref);
const Union = refUnionDi(ref);
const ArrayType = refArrayDi(ref);
const Pointer = ref.refType;
export function dlopen(libPath: string) {
return ffi.Library(libPath, {});
}
critical
matcher
should be a dependency, not just a dev dependency.
Now that this repo is public, we should move to absolute URLs for links in the README.md
files, so that they work from npm as well.
We should add https://shields.io/ npm status badges to the various readmes before open sourcing.
Currently, a best-effort set of primitives is mapped in tsgen/resolve.ts. However, we should ensure that the list covers all types that ref.types
knows how to represent, which should, by extension, be all valid primitive types.
If you're reading this issue, it might be because a type is missing. To debug, use set DEBUG=clangffi:tsgen:resolve
and look for your type. The output should make it clear if it was resolved as a "builtin" or "unknown" type. If you believe it to be a primitive but it's showing up as "unknown", we need to add it to these lookup
tables.
Sometimes we may wish to use ffi.Callback
to represent a function pointer that's being passed to a native function as a parameter. Today, these types get mapped as ffi.Function
which isn't compatible. We should consider how to support a typed solution that allows either:
ffi.Function
or ffi.Callback
via clangffi
flags or other user config (ideally selection occurs at a function level)A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.