{"_id":"@can1357/sbffi","_rev":"1-c838ca5028181c7626db8587578ead34","name":"@can1357/sbffi","dist-tags":{"latest":"1.0.4"},"versions":{"1.0.4":{"name":"@can1357/sbffi","version":"1.0.4","description":"Dynamic C function calls from JS, powered by dyncall.","main":"lib/index.js","scripts":{"install":"prebuild-install -t 5 -r napi || npm run build","build":"prebuild -t 5 -r napi --backend cmake-js","bench":"node test/bench.js","test":"eslint . && node test/test.js","clean":"rm -rf build prebuilds","test-ci":"npm run test && npm run bench"},"repository":{"type":"git","url":"git+ssh://git@github.com/can1357/sbffi.git"},"keywords":["dyncall","ffi","c","native","addon","dynamic","function"],"author":{"name":"Bryan English","email":"bryan@bryanenglish.com"},"license":"MIT","bugs":{"url":"https://github.com/can1357/sbffi/issues"},"homepage":"https://github.com/can1357/sbffi#readme","dependencies":{"prebuild-install":"^5.3.4"},"devDependencies":{"cmake-js":"^6.1.0","eslint":"^7.1.0","eslint-config-standard":"^14.1.1","eslint-plugin-import":"^2.20.2","eslint-plugin-node":"^11.1.0","eslint-plugin-promise":"^4.2.1","eslint-plugin-standard":"^4.0.1","ffi-napi":"^3.0.1","pitesti":"^3.0.0","prebuild":"^10.0.0","require-wat":"^2.0.2"},"binary":{"napi_versions":[5]},"gitHead":"9dd0e83065450eea691a2a5cb2224dc3d99c824e","_id":"@can1357/sbffi@1.0.4","_nodeVersion":"16.3.0","_npmVersion":"7.18.1","dist":{"integrity":"sha512-rQh2hija3gTMbKOeGeTw+tuGWRSTNpkU/NL41dkjbU9tgxvkY3dCA3g/NQ6KrJ4NIF4goNE4HckktVoYJjKnjA==","shasum":"6f3d586a40cecd241e6939eb7138357c39210b42","tarball":"https://registry.npmjs.org/@can1357/sbffi/-/sbffi-1.0.4.tgz","fileCount":623,"unpackedSize":2721370,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgzeT4CRA9TVsSAnZWagAAFOQQAJ85Vgj91EEyOvnZT9MI\nTTIla0Q3uu0WXNvystZXgq+0MfVYyNrUCcaTgczF5sz69wlUIMTwxcRm4nd2\nJo4rVp9S4hRvAMZ37UgrHbNBlB0SRVq9B0FAzDwQMUirP5DUiaQFPW8Ax9Ml\n9sVCsKnYYuvTogyMstUVGoydy7xVPzqKocRvlmPtYe7MQB/RzttxoBjobWfn\n0RyvzdI9u5A8WjmHb3uF4WRsACxbJKn5ejQaQhfbg9ZR/jaIq++8W3Ez8Lvq\nqbRixoh4Au6L0oOG/EVouHV/EDGqxxXHGkrf1fkala/SQ7Pn6Mi5hjmhp1td\nho9F22zTLLz178MNt08ErvfuR8zwRUA/rnM7RsldLhZDz0DkP8ekGQ3Jgm3q\nUuGM/um6d5mW3XpQX2TdH7l4RKVOPgUM/4SWAOcS3VIhizzgMrWbiENYuzjE\nKQbDC0nTtfzSgbD0Z0cIOWro9VhS1adJI/wVeJXVSMkv+H8fJwQvGN4xU4J4\nqWqn2UuoM1a6TNmnhRAKv0GSoW8iur/nGAZ1jWaa7hr/Vb5b9QP/4QqvSGaJ\ncFquqYHEL7YGBbfIC3Cu558CscM8h50TM24DAK+UVi4HyjA3Li3D85dBVdFd\nDYNMSFHN9QCaNxhKONU5s+wtgH3SCIgrogJRa9L1tUHMs0muFPkhsElJ7p51\nIdYJ\r\n=yZ0I\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIA7hqNqj7Q6ieON3jxgoYNJmvTvECqT0KWajHZKhOfZDAiEAnpskwU7PZgM+PEAI7LOn/Zm0Onx/OKTZabfY6ROfY78="}]},"_npmUser":{"name":"can1357","email":"can.boluk89@gmail.com"},"directories":{},"maintainers":[{"name":"can1357","email":"can.boluk89@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/sbffi_1.0.4_1624106231602_0.43477250917512933"},"_hasShrinkwrap":false}},"time":{"created":"2021-06-19T12:37:11.521Z","1.0.4":"2021-06-19T12:37:11.852Z","modified":"2022-04-04T21:35:33.283Z"},"maintainers":[{"name":"can1357","email":"can.boluk89@gmail.com"}],"description":"Dynamic C function calls from JS, powered by dyncall.","homepage":"https://github.com/can1357/sbffi#readme","keywords":["dyncall","ffi","c","native","addon","dynamic","function"],"repository":{"type":"git","url":"git+ssh://git@github.com/can1357/sbffi.git"},"author":{"name":"Bryan English","email":"bryan@bryanenglish.com"},"bugs":{"url":"https://github.com/can1357/sbffi/issues"},"license":"MIT","readme":"# sbffi\r\n\r\nA super-quick [FFI](https://en.wikipedia.org/wiki/Foreign_function_interface)\r\nfor Node.js.\r\n\r\n[`dyncall`](https://dyncall.org/) is used to make dynamic calls to native\r\nfunctions. In order to avoid some cost of translating JavaScript values into raw\r\nC types, a shared buffer is used for both arguments and return values. Writing\r\nvalues to a buffer turns out to be quite a bit faster than unpacking them in\r\nnative code.\r\n\r\n## Usage\r\n\r\n**`sbffi.getNativeFunction(pathToSharedLibrary, functionName, returnType, [argType1, argType2, ...])`**\r\n\r\nAll the arguments are strings. The types must be standard C types. See the\r\n**Types** section below for details. When functions take 64-bit types, the\r\nparameters must be passed as BigInts. 64-bit return values will also be\r\nBigInts.\r\n\r\n```c\r\n// adder.c: some C library compiled to libadder.so\r\n\r\nuint32_t add(uint32_t a, uint32_t b) {\r\n  return a + b;\r\n}\r\n```\r\n\r\n```js\r\n// index.js\r\n\r\nconst { getNativeFunction } = require('sbffi');\r\n\r\nconst libPath = '/path/to/libadder.so';\r\nconst add = getNativeFunction(libPath, 'add', 'uint32_t', ['uint32_t', 'uint32_t']);\r\n\r\nconst result = add(23, 34);\r\n// 57\r\n```\r\n\r\nTo specify a callback, identify it in the arguments array as `[cbReturnType,\r\n[cbArgTyp1, cbArgType2, ...]]`.\r\n\r\n### Types\r\n\r\nThe following types are supported:\r\n\r\n* `(u)int[8|16|32|64]_t`\r\n* `bool`\r\n* `(unsigned) char`\r\n* `(unsigned) short`\r\n* `(unsigned) int`\r\n* `(unsigned) long`\r\n* `(unsigned) long long`\r\n* `float`\r\n* `double`\r\n* `size_t`\r\n\r\n128-bit types are not yet supported, and while this list may grow over time, for\r\nnow other types can be used if they're aliases of the above types.\r\n\r\nSee the section below about pointers.\r\n\r\n### Pointers\r\n\r\nPointers are currently assumed to be 64-bit, and can be passed to native\r\nfunctions by specifying the type as `pointer` or referring to any other type\r\nwith an asterisk in the string, for example: `uint8_t *`.\r\n\r\nYou can put raw data into a Buffer, and then get a pointer to the start of that\r\nbuffer with:\r\n\r\n**`const bufferPointer = sbffi.getBufferPointer(buffer);`**\r\n\r\nArrays and strings must be passed as pointers.\r\n\r\n### Structs\r\n\r\nFor now, `sbfffi` doesn't have any built-in support for structs. That being\r\nsaid, there are some helpful libraries like\r\n[`shared-structs`](https://www.npmjs.com/package/shared-structs) and\r\n[`ref-napi`](https://www.npmjs.com/package/ref-napi) (and its family of\r\nmodules). As long as you can build up a C struct into a Buffer, you can pass\r\npointers to them into C functions. Non-pointer struct arguments or return values\r\nare not supported.\r\n\r\n## Development\r\n\r\nUsing a non-release version of `sbffi` requires that\r\n[`cmake`](https://cmake.org/) is installed in order to compile the native\r\naddon.\r\n\r\n## Benchmarks\r\n\r\nA simple benchmark can be run with `npm run bench`. This will test calling a\r\nsimple adding function from the test library using the following techniques:\r\n\r\n* **`ffi-napi`**: A successor to `node-ffi` compatible with modern versions of\r\n  Node.js.\r\n* **`sbffi`**: This library.\r\n* **`napi-addon`**: A very simple/normal Node.js addon using NAPI in C.\r\n* **`napi-addon-sb`**: A NAPI addon using the same shared-buffer technique as\r\n  `sbffi`, but with a hard-coded function call, rather than a dynamic/FFI call.\r\n* **`wasm`**: The adding function compiled to WebAssembly.\r\n* **`js`**: Re-implementing the function in plain JavaScript.\r\n\r\nEach function will be called 100000 times, in 5 repetitions, timed with\r\n`console.time()`. Here are the results on my machine (2019 Lenovo X1 Extreme,\r\nrunning Ubuntu, Node v12):\r\n\r\n```\r\nffi-napi: 1103.680ms\r\nsbffi: 39.981ms\r\nnapi-addon: 8.214ms\r\nnapi-addon-sb: 6.795ms\r\nwasm: 2.802ms\r\njs: 2.644ms\r\n---\r\nffi-napi: 1128.388ms\r\nsbffi: 97.446ms\r\nnapi-addon: 3.631ms\r\nnapi-addon-sb: 3.308ms\r\nwasm: 0.918ms\r\njs: 0.045ms\r\n---\r\nffi-napi: 1419.159ms\r\nsbffi: 29.797ms\r\nnapi-addon: 3.946ms\r\nnapi-addon-sb: 3.717ms\r\nwasm: 0.871ms\r\njs: 0.090ms\r\n---\r\nffi-napi: 1285.210ms\r\nsbffi: 73.335ms\r\nnapi-addon: 4.618ms\r\nnapi-addon-sb: 3.651ms\r\nwasm: 0.930ms\r\njs: 0.096ms\r\n---\r\nffi-napi: 772.013ms\r\nsbffi: 29.467ms\r\nnapi-addon: 3.790ms\r\nnapi-addon-sb: 3.352ms\r\nwasm: 0.847ms\r\njs: 0.087ms\r\n---\r\n```\r\n\r\nOf course, YMMV.\r\n\r\n## Contributing\r\n\r\nPlease see [CONTRIBUTING.md](./CONTRIBUTING.md),\r\n[CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) and [TODO.md](./TODO.md).\r\n\r\n## License\r\n\r\nPlease see [LICENSE.txt](./LICENSE.txt).\r\n","readmeFilename":"README.md"}