Open jlarmstrongiv opened 7 months ago
That's good to know! Another related issue I am solving is the lack of Doxygen support for TypeScript. Maybe we should provide both binding.gyp and prebuilt, as well as TypeScript + JavaScript?
I guess I was overzealous on files[] part of the package.json. Will fix.
It is odd since there should be a pre-built binary for linux-arm64
I did cross compile it so maybe i did something wrong
Oh, they are the same size, so definitely not right.
:tada: This issue has been resolved in version 2.10.4 :tada:
The release is available on GitHub release
Your semantic-release bot :package::rocket:
I will try it as soon as 2.10.4 is released on npm 😄
@jlarmstrongiv, sadly, the build fails. @sroussey, would you be able to double-check the cross-compilation commands? I am also looking to extend cross-compilation in Rust as well (for #378).
I will try it as soon as 2.10.4 is released on npm 😄
Try npm install @sroussey/usearch
as a test.
bash-5.2# npm install @sroussey/usearch
added 5 packages, and audited 6 packages in 6s
found 0 vulnerabilities
The install passed! Haven’t tried running sample code yet though
@jlarmstrongiv, sadly, the build fails. @sroussey, would you be able to double-check the cross-compilation commands? I am also looking to extend cross-compilation in Rust as well (for #378).
Might remove the cross compile for now while I do more investigation.
How is it going, @sroussey? How should I change the CI for builds to pass?
I’m home a bit today, so I’ll comment out that section until I have a working version.
See https://github.com/unum-cloud/usearch/commit/c6fb87574f0410cd50b4939b856b1cdbacec42cc
It has what i think is the fix, but I am not setup to test it.
So farther down I have it skip the cross compiling.
I have a docker setup on x86_64 but I can't get it to compile normally, so I can't test cross compiling.
@ashvardanian Have any idea how i set things up wrong?
root@6a1e9ab171d0:/usr/usearch# uname -a
Linux 6a1e9ab171d0 6.4.16-linuxkit #1 SMP PREEMPT Thu Nov 16 10:49:20 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
apt install -y cmake build-essential libjemalloc-dev libomp-dev gcc-12 g++-12
apt install -y gcc-aarch64-linux-gnu binutils-aarch64-linux-gnu g++-aarch64-linux-gnu
root@6a1e9ab171d0:/usr/usearch# git submodule
0a92994d729ff76a58f692d3028ca1b64b145d91 fp16 (heads/master)
127ead1da7c39957b30a50dd85e74814edb022d6 simsimd (v4.2.2)
c2848c1ba777c541af2903501f3d6344d711638b stringzilla (v3.7.0)
Works fine on MacOS though.
The _ph
suffixes are for half-precision. GCC 12 must support it. You download it, but seems like you are not using it, @sroussey 🤷
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-12 60 --slave /usr/bin/g++ g++ /usr/bin/g++-12
fixed it, thanks.
cross compile says it goes fine, but it doesn't contain a build
Oh, it did build it:
root@6a1e9ab171d0:/usr/usearch# file build/Release/obj.target/usearch.node
build/Release/obj.target/usearch.node: ELF 64-bit LSB shared object, ARM aarch64, version 1 (GNU/Linux), dynamically linked, BuildID[sha1]=c0650f24bd82a89cca3a4a773455913f2477a789, not stripped
It just didn't get moved over. I wonder if a strip issue.
Indeed, something went wrong with strip. Manually works though. I can work around this...
@jlarmstrongiv is the issue resolved now?
Hmm, I get errors that:
Error: src/usearch.ts(11,5): error TS2322: Type '"cos"' is not assignable to type 'MetricKind'.
Error: src/usearch.ts(13,5): error TS2322: Type '"f32"' is not assignable to type 'ScalarKind'.
Did the types change?
Fixed the types… testing
It seems my bundling for usearch does not work with the new package structure. I am using https://www.npmjs.com/package/@vercel/ncc, I wonder why that would break and not detect the usearch.node
file anymore
Uncaught Exception {
"errorType": "Error",
"errorMessage": "Could not find native build for usearch",
"stack": [
"Error: Could not find native build for usearch",
" at getBuildDir (/opt/nodejs/node_modules/usearch/index.js:1080:15)",
" at getBuildDir (/opt/nodejs/node_modules/usearch/index.js:1081:12)",
" at getBuildDir (/opt/nodejs/node_modules/usearch/index.js:1081:12)",
" at getBuildDir (/opt/nodejs/node_modules/usearch/index.js:1081:12)",
" at getBuildDir (/opt/nodejs/node_modules/usearch/index.js:1081:12)",
" at 128 (/opt/nodejs/node_modules/usearch/index.js:605:48)",
" at __nccwpck_require__ (/opt/nodejs/node_modules/usearch/index.js:1117:43)",
" at /opt/nodejs/node_modules/usearch/index.js:1137:37",
" at Object.<anonymous> (/opt/nodejs/node_modules/usearch/index.js:1140:12)",
" at Module._compile (node:internal/modules/cjs/loader:1376:14)"
]
}
These tools are not smart enough to deal with .node or .wasm files (generally). They will require extra steps on your side.
Oh, and if it has something like "external" you might use that. Bun can make a single file as well, and it has something like that. I use externals for transformers.js since it has wasm files.
@sroussey 64-bit Arm is a popular platform. We should make sure it works fine there. Any other ways we can improve our cross-compilation scripts?
I think it compiles fine now. This is a separate issue of bundling.
I’ll look at the package.json
as well as try using esbuild
bundle and see if that works (it also supports .node
files)
The package https://www.npmjs.com/package/@vercel/ncc handles bundling with .node
files, and worked with usearch
before 2.10.x
. Example: usearcharm64nodejs20__2_9_2.zip
If it can’t be bundled, it can’t be used in serverless like AWS Lambda.
I think @vercel/ncc
is failing because the way the bindings import has changed from something bundlers can analyze:
const compiled = require('bindings')('usearch');
To dynamic code that bundlers can’t analyze:
const compiled: Compiled = build(getBuildDir(getDirName()));
interface Compiled {
CompiledIndex: CompiledIndex;
exactSearch(
dataset: VectorOrMatrix,
queries: VectorOrMatrix,
dimensions: number,
count: number,
metric: MetricKind
): CompiledSearchResult;
}
function getBuildDir(dir: string) {
if (existsSync(path.join(dir, "build"))) return dir;
if (existsSync(path.join(dir, "prebuilds"))) return dir;
if (path.basename(dir) === ".next") {
// special case for next.js on custom node (not vercel)
const sideways = path.join(dir, "..", "node_modules", "usearch");
if (existsSync(sideways)) return getBuildDir(sideways);
}
if (dir === "/") throw new Error("Could not find native build for usearch");
return getBuildDir(path.join(dir, ".."));
}
function getDirName() {
try {
if (__dirname) return __dirname;
} catch (e) { }
return getRoot(getFileName());
}
@sroussey is it possible to use the previous import syntax with the bindings?
In the meantime, I will try to see if esbuild
bundling works
Note to self, add "./package.json": "./package.json"
back to package.json
field exports
Yeah, prebuilt binaries have a different algorithm to find the binary, since there are several.
Have you tried --external ?
At any rate, I don't use aws lambda, but if you give me some steps to reproduce locally, I'll have a look.
Sure, the easiest way to locally reproduce without getting docker involved is:
mkdir usearch-bundle
cd usearch-bundle
npm init -y
npm install usearch@2.11.1
To get the entrypoint, run node -p "require.resolve('usearch')"
or just run the commands below:
Then, try bundling with @vercel/ncc
(using --external
doesn’t make sense in this case, because our goal is to bundle usearch
, not skip it):
npx --yes @vercel/ncc build node_modules/usearch/javascript/dist/cjs/usearch.js -o ncc-usearch-bundled --debug
or with esbuild
:
npx --yes esbuild node_modules/usearch/javascript/dist/cjs/usearch.js --bundle --outdir=esbuild-usearch-bundled --loader:.node=file --platform=node
Bundling works great with many other native addons that have prebuilds, such as:
better-sqlite3
let addon;
if (nativeBinding == null) {
addon = DEFAULT_ADDON || (DEFAULT_ADDON = require('bindings')('better_sqlite3.node'));
} else if (typeof nativeBinding === 'string') {
// See <https://webpack.js.org/api/module-variables/#__non_webpack_require__-webpack-specific>
const requireFunc = typeof __non_webpack_require__ === 'function' ? __non_webpack_require__ : require;
addon = requireFunc(path.resolve(nativeBinding).replace(/(\.node)?$/, '.node'));
} else {
// See <https://github.com/WiseLibs/better-sqlite3/issues/972>
addon = nativeBinding;
}
duckdb
var binary = require('@mapbox/node-pre-gyp');
var path = require('path');
var binding_path = binary.find(path.resolve(path.join(__dirname,'../package.json')));
var binding = require(binding_path);
module.exports = exports = binding;
- `hnswlib-node`
```js
const addon = require('bindings')('addon');
module.exports = addon;
@tensorflow/tfjs-node
It should be possible to add prebuilds without breaking bundling. @sroussey hopefully some of those package examples can be inspiration. I’ll look at it more, but I’m not familiar enough with prebuilds
and node-gyp
to immediately see what the solution is.
One thing I notice with better-sqlite3
, duckdb
, and @tensorflow/tfjs-node
is that they don’t download the binaries for all platforms on install—they install the correct binary for the particular platform (named the same package-name.node
file) at a well-known location for common libraries like bindings
or @mapbox/node-pre-gyp
to find.
Great! I'll have a look.
Hopefully one of them uses prebuildify. I think the sqlite one (based on my poor memory) relies on a lifecycle script to download a prebuilt binary, and for security reasons people are moving away from having some deep dependency run arbitrary code on install on your machine (and another reason for dev containers). Bun, for example, does not run them.
I remember having issues since typescript doesn't have __dirname etc. I know some better ways around that now however.
I am not sure if I broke something, but potentially after these cosmetic changes the Windows CI failed. @sroussey I think it might be a good ide to deconvolute the build commands for MacOS, Linux, and Windows, similar to how I do for other platforms in release.yml
? I am also curious, why are we excluding those targets:
matrix:
arch:
- x64
- x86
os:
- macos-latest
- ubuntu-latest
- windows-latest
exclude:
- arch: x86
os: macos-latest
- arch: x86
os: ubuntu-latest
Those can cross compile, so faster to do it that way.
Also, I don't think GitHub has arm64 for those.
cosmetic changes
Maybe a red herring? It uses windows-latest
so maybe that changed instead?
Looking at the changeset, I cannot see why the error would come up. You might try branching that off and do a force push of the last known good and see if that now fails.
Then, try bundling with
@vercel/ncc
(using--external
doesn’t make sense in this case, because our goal is to bundleusearch
, not skip it):
Yeah, kinda. bundling and packaging are kinda being used interchangeably. A clearer way to think of it is that bundling is like inlining code (this is kinda sorta how the bundle ends up as one file), and packaging is taking this bundle and other assets and doing something with them. So external, kinda-sorta meaning don't inline, not so much don't include. I say kinda-sorta, because this is not C and linking and standard ABIs, etc., as things are much more... fluid... in the JS space, so every tool goes its own way.
Then, try bundling with
@vercel/ncc
(using--external
doesn’t make sense in this case, because our goal is to bundleusearch
, not skip it):npx --yes @vercel/ncc build node_modules/usearch/javascript/dist/cjs/usearch.js -o ncc-usearch-bundled --debug
OK, what should I expect? I get
❯ npx --yes @vercel/ncc build node_modules/usearch/javascript/dist/cjs/usearch.js -o ncc-usearch-bundled --debug
ncc: Version 0.38.1
ncc: Compiling file index.js into CJS
Skipping asset emission of /Users/steve/Code/usearch-bundle/package.json for /Users/steve/Code/usearch-bundle/node_modules/bindings/bindings.js as it is outside the package base /Users/steve/Code/usearch-bundle/node_modules/bindings
41kB ncc-usearch-bundled/index.js
41kB [304ms] - ncc 0.38.1
These don't include prebuilt binaries (you won't find a .node file among them):
https://www.npmjs.com/package/better-sqlite3?activeTab=code https://www.npmjs.com/package/duckdb?activeTab=code https://www.npmjs.com/package/hnswlib-node?activeTab=code https://www.npmjs.com/package/@tensorflow/tfjs-node?activeTab=code
As opposed to usearch:
https://www.npmjs.com/package/usearch?activeTab=code
Frustrating.
Anyhow, I will look at ncc source code for ncc and see what they are doing for .node files.
OK, what should I expect? I get
That looks about right (I don’t remember the package.json
warning). Though, before 2.10.x, it also included the .node file in the output
These don't include prebuilt binaries (you won't find a .node file among them):
Perhaps not in the npm package, but sometimes they are stored in github releases or other cache locations
Anyhow, I will look at ncc source code for ncc and see what they are doing for .node files.
Thank you for checking! I look forward to being able to use usearch again
Perhaps not in the npm package, but sometimes they are stored in github releases or other cache locations
Yeah... unfortunately that means having an install script run.
Thank you for checking! I look forward to being able to use usearch again
Oh, you should be able to just copy theprebuilds
folder over, right? People usually do this with webpack.
From the ncc dev: "We specifically include support for bindings and node-pre-gyp". I am pretty sure they don't anticipate multiple architectures. But I'll see what they do.
Or this:
❯ npx --yes @vercel/ncc build test.js -o ncc-usearch-bundled --debug --external usearch
ncc: Version 0.38.1
ncc: Compiling file index.js into CJS
2kB ncc-usearch-bundled/index.js
2kB [113ms] - ncc 0.38.1
❯ cp -rp node_modules/usearch ncc-usearch-bundled
❯ node ncc-usearch-bundled/index.js
Index {}
That will contain some extra files though (all the stuff to build it)
Describe the bug
NPM install fails on arm64 linux. I presume it couldn’t find a new prebuilt binary (exciting new feature from @sroussey), and fell back to compiling from scratch, which it can no longer do because the source and gyp files have been removed from the npm package.
Steps to reproduce
On an arm64 machine, run
Inside the container, run
View the error:
Expected behavior
NPM install to work with the
linux-arm64
prebuildsRegardless, it’s important for falling back to compiling from scratch with
node-gyp
to continue to work.USearch version
2.10.x
Operating System
Amazon Linux 2023
Hardware architecture
Arm
Which interface are you using?
Other bindings
Contact Details
Ping me in Discord
Is there an existing issue for this?
Code of Conduct