From 6c03a326a86ee839aeffaad30b9111c21e0e2308 Mon Sep 17 00:00:00 2001 From: Vladimir Kruzhkov Date: Sun, 29 Sep 2024 14:44:25 +0300 Subject: [PATCH] handle typedef with postfix struct name; bunAllocArray hepler added --- .gitignore | 3 +++ .npmignore | 4 ++++ .vscode/launch.json | 18 ++++++++++++++ README.md | 2 ++ bun.lockb | Bin 2840 -> 3873 bytes package.json | 11 +++++---- src/clang.ts | 4 ++++ src/gen.ts | 8 +++++++ src/parser.ts | 14 ++++++++++- test.h | 6 +++++ test.ts | 57 ++++++++++++++++++++++++++++++++++++++++++++ 11 files changed, 121 insertions(+), 6 deletions(-) create mode 100644 .vscode/launch.json create mode 100644 test.h create mode 100644 test.ts diff --git a/.gitignore b/.gitignore index eaa46a0..c4f253f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,11 @@ generate-wgpu-bindings_cache_*.json +test-bindings_cache_*.json generate-bindings_tmp_exec example.ts lib bindings_cache_* +test_out.ts + # Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore diff --git a/.npmignore b/.npmignore index 7ee2d90..8773019 100644 --- a/.npmignore +++ b/.npmignore @@ -1,5 +1,9 @@ node_modules generate-wgpu-bindings_cache_*.json +test-bindings_cache_*.json generate-bindings_tmp_exec example.ts src +test.h +test.ts +.vscode diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..72fdd8e --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,18 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "bun", + "internalConsoleOptions": "neverOpen", + "request": "launch", + "name": "Debug File", + "program": "test.ts", + "cwd": "${workspaceFolder}", + "stopOnEntry": false, + "watchMode": true + } + ] +} diff --git a/README.md b/README.md index c766e5a..c6f0851 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,8 @@ Will exec `clang` to get ast and type infos, so it should be available in PATH. Feel free to write an issue with your header file, so I could tweak this package. +Tested on clang13 & bun 1.0.2 (upper versions requests macos update, goodbye bun) + ## Install ``` diff --git a/bun.lockb b/bun.lockb index cf0d6d958e66d42b79ec8d3ee528eed0d12696c6..82d8b728218f94f14466060e923f3e2aa9fd67a0 100755 GIT binary patch literal 3873 zcmeHKYfuwc6izUJMnOb$DpQ9*BV)mA9wZPTJgn3yMXUHis8C*;5C{ooH@sRE1g8|W zfUiM1Q!&D*Rj1PW8WF2dP%BU$sAH>6RTQgeU%rY8J$JJgq9c!S{NazDnVYls-t&F? z?Y(F3p1k8OHc>`#qE;^^^_hZ1lb#Pvq%$O?skJ&%q&67S6KGMUgm1&)aNe??{g;j6 z+g3n|7Bo1KuBRQPBad5>4 zKOa0y=9$5x@ec5#z;Enl9AX$;RgH%*{L+_UKiR!o7a_^N|7oYDrO5e?N0~TgwddX- z{}BdN)9uKL+ASx`b2g=((Y`poX;R)4?-gVs7x<7>3N0T0N;<|49|j%J$XHrWGzZ68 zMm$@+AONirGB;?xpc}=YhH-E?pkaI*LLD2DNJcxXA`Q3fC^(l8Xm_!Ph^0Y4r<_Rx4k0YePNR{|dCw}Y{< z&~PRWMuYKp0j~l)(vI$p#|Oisd6Xxp0Yxts=|Fw-EXa^YeWVL{{6b(4L$8UadvrIt z!D}`y$HHq(&HKY#K7We08~<7BiT2yeFDTQ3yq@M4nB;dhuM8}1zqKLxf>)R-ex1YD z#sGKcmzaV`mIP~pI{oaDCi&^SC(1>}h*PG|Oq-U1AMDn!yM)*AYx%SPui*}X% zQs!T~QMBjswOgM=9j%q?fboGabaq8Q-RaU&#?;Y>T+0$#Dh3yOdy>+3? z+e1~AW|zz@8B=|wHng>*^!Tr9VjeBH%>6tzKJ$pf_;I_|j!A!T_Lqo!$IMbm_B z(lRSvl#keWC$G<18PnJts8F=oPYm$No%C=H>CEUy1T~`pf z&~;hk-%BE*RSrM8`(&BjwyRvGHbmt`s5d$mtaq(H?|NqEg!<$z;q=|dO00OT-(TJn z!*8debZuc|h*_5!=H!rl(X@6{*TL*v#}D{>5A7LoJ+__KqA4_< z+iAMtBR!qIzAMGtg2b`rbkTCIt4iO-LvMt~`Gozeh_Ze+Uj_d^<~6OrHuh9+XFXp< z8IuUDo}v?UIs(^P#5^NO1`A{o0j13)4eBWZxgbHO)#wdsOZCv*V=<%(e@}3J;66Gx z@wWwgC${*Iu%53n`N)ESy`TFa4s=c;Zgl=2Zp4M&!FZOVaEM$8gTHZz7x7_k%zJ?4 zGNWP+jIa7w<{N8L!dm$DYLq^|7P#)ib(<46PC-Zr2~#yP6(OD(-aCV9Ok5+{aO0$a zk#RV<>cmx}4OdD?37J2KgX>OQH`;KQDhUN4m2k|U6ji9Wl7tzVgpkSzWe3clnibca zFry%3zJ&ZG7%%j|U@yV=5>kH<_b0n561IeTK6xlIJ(DyN?`PAbQJ67w$`;kViHi@?6h#_=G4`w=e~voh@l`lP(6baO z70uji$L@Gm#TRTr3AqIOB<*jTIOxxWTCEjnNIjjCK~hOZZ3Z36T#8{Xg{Cv80I}Fe zYP1w>%pvp{>8TW9FlxkoL1GaK6`?JWN(fq$i+T*j0Px-z7R|&n95R2z!O~|@?1kQt zOb$S26$OMSSY+94sT{GH^vT*J?VzHp!+^%RD`HYafyf4zkwpPIixM%ZC>t6EY3`LS tBm4+P_yG5^R`;S4iWVB(KcKz`z5fmuys0@x0ULGGDbpN4qsO zsrpU&*$$!CN)tawFfva5$ZS7(0wV{L7QZTiVCF|QV? zzo>05$~=2b*Yljx6FcKMxBi{d2zBni?ES@xv} z1s=aOZIaeS`K)(OUfc?O^YUTGvik+witZZy_YRw+%)$R}=eIz~#g?H9!m`KdM)4tF0vyW1W$Ko}r(q7C+BlZ zs=yL3XTHs`SAny3167&o8JX#sFf4$kn+F_|*KoT`e#dPjB?mMTl-gS?OwTY@@ck12 zx(NgtxF%ci7z!tq=INGH7Niz~iR7Zpf|ALOd>)gh@Jdg<$s-{H@{C?ddX)oMUOz8C pB^AmnFP_9FJ$XH^2&2K|3A}2P^?3zY4E2mGCp+^7PJYNf0|1xF6b%3X diff --git a/package.json b/package.json index 5fc155d..a5ecdd9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bun-ffi-gen", - "version": "1.1.2", + "version": "1.1.3", "module": "lib/index.ts", "description": "FFI bindings generator for Bun", "type": "module", @@ -29,11 +29,12 @@ "url": "git+https://github.com/Morglod/bun-ffi-gen.git" }, "devDependencies": { - "typescript": "^5.0.0", - "bun-types": "^1.0.33" + "typescript": "^5.0.0" }, "peerDependencies": { - "typescript": "^5.0.0", - "bun-types": "^1.0.33" + "typescript": "^5.0.0" + }, + "dependencies": { + "@types/bun": "^1.0.2" } } \ No newline at end of file diff --git a/src/clang.ts b/src/clang.ts index 17b754e..f9ff5a3 100644 --- a/src/clang.ts +++ b/src/clang.ts @@ -97,6 +97,8 @@ export function clangGetSizeOf(headerPath: string, cTypeName: string, cache?: Cl return cache.sizeOf[cacheName]; } + logInfo(`clangGetSizeOf "${cTypeName}"`); + const code = ` #include "${headerPath}" #include @@ -118,6 +120,8 @@ export function clangGetOffsetOf(headerPath: string, cTypeName: string, fieldNam return cache.offsetOf[cacheName]; } + logInfo(`clangGetOffsetOf "${cTypeName}"."${fieldName}"`); + const code = ` #include "${headerPath}" #include diff --git a/src/gen.ts b/src/gen.ts index 396bafa..380324d 100644 --- a/src/gen.ts +++ b/src/gen.ts @@ -196,6 +196,14 @@ export function bunReadArray(from: Pointer | TypedArrayPtr, offset: number return out; } +export function bunAllocArray(cTypeSize: number, items: T[], itemWriter: (item: T, buffer: Buffer, offset: number) => void): TypedArrayPtr { + const buf = Buffer.alloc(cTypeSize * items.length); + for (let i = 0; i < items.length; ++i) { + itemWriter(items[i], buf, i * cTypeSize); + } + return buf as TypedArrayPtr; +} + export function alloc_CString(str: string) { return new BunCString(bunPtr(Buffer.from(str + "\\0")) as any); } diff --git a/src/parser.ts b/src/parser.ts index 08687db..5a642cb 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -367,7 +367,19 @@ export function parseClangAst(astJson: any[], headerFilePath: string, clangTypeI // struct if (statement.kind === "RecordDecl") { - const name = statement.name; + let name = statement.name; + + // handle case for typedef struct {} NAME; + if (!name) { + const nextStmt = astJson[statementIndex + 1]; + if (nextStmt && nextStmt.kind === "TypedefDecl" && nextStmt.inner?.[0]?.ownedTagDecl.id === statement.id) { + name = nextStmt.name; + statementIndex++; + } else { + logInfo("found RecordDecl without name at ", statement.loc); + continue; + } + } if (!statement.inner) { continue; diff --git a/test.h b/test.h new file mode 100644 index 0000000..213699d --- /dev/null +++ b/test.h @@ -0,0 +1,6 @@ +typedef struct { + int a; + int b; +} Foo; + +int sum(Foo* f); diff --git a/test.ts b/test.ts new file mode 100644 index 0000000..22251d6 --- /dev/null +++ b/test.ts @@ -0,0 +1,57 @@ +import { ClangTypeInfoCache, clangGetAstJson, CodeGen, parseClangAst, clangClean, addIncludeDir } from "./src"; +import { LogLevel, setLogLevel } from "./src/log"; +import path from "path"; + +const HEADER_PATH = "./test.h"; +const TYPE_CACHE_PATH = "./test-bindings_cache"; + +setLogLevel(LogLevel.verbose); + +// add include dirs for clang +addIncludeDir(path.resolve("my_include_dir")); + +// get header ast from clang +const wgpuAst = await clangGetAstJson(HEADER_PATH); + +// create clang types cache (for sizeof / offsetof) +const clangTypeInfoCache = await ClangTypeInfoCache.create(TYPE_CACHE_PATH); + +// parse ast +const result = parseClangAst(wgpuAst, HEADER_PATH, clangTypeInfoCache); + +// update clang cache +await clangTypeInfoCache.save(); + +// prepare code generation +const codeGen = new CodeGen({ + // see more options below + funcSymbolsImportLibPathCode(out) { + out.push(` + let _LIB_PATH: string = ""; + + if (process.platform == "darwin") { + _LIB_PATH = + import.meta.dir + + "/../wgpu/libwgpu_native.dylib"; + } else { + throw new Error("not supported wgpu bindings platform"); + } + `); + + return "_LIB_PATH"; + }, +}); + +codeGen.generateAll(result); + +if (codeGen.failedSymbols.size) { + console.log("ffi failed for:"); + console.log(Array.from(codeGen.failedSymbols)); +} + +// write output +codeGen.writeToFile("./test_out.ts"); + +// cleanup +await clangTypeInfoCache.save(); +await clangClean();