crossbind 2.0.0-beta.51 → 2.0.0-beta.52
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/AGENTS.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
## What lives here
|
|
6
6
|
|
|
7
|
-
- `bin.js` — `crossbind`
|
|
7
|
+
- `src/bin.js` — `crossbind` CLI entry; commander commands, target filtering and top-level orchestration.
|
|
8
8
|
- `src/index.js` — public API barrel re-exported as the `crossbind` npm package (`createLib`, `buildWasm`, `state`, `getData`, `isSourceNewer`, …).
|
|
9
9
|
- `src/actions/` — the actual build steps. **Most edits land here.**
|
|
10
10
|
- `src/state/` — config loading + target matrix.
|
|
@@ -18,7 +18,7 @@ Use `docs/CODEMAP.md` (repo root) for "concept → file" lookups before guessing
|
|
|
18
18
|
|
|
19
19
|
Order of operations when a user runs `pnpm crossbind build`:
|
|
20
20
|
|
|
21
|
-
1. **`bin.js`** parses CLI flags, calls `getBuildTargets` to expand the target matrix.
|
|
21
|
+
1. **`src/bin.js`** parses CLI flags, calls `getBuildTargets` to expand the target matrix.
|
|
22
22
|
2. For each target:
|
|
23
23
|
- **`actions/createLib.js`** compiles user C++ to a static lib per platform (cmake/make for wasm/android via Docker; xcodebuild on darwin for iOS). Cache short-circuit when `<output>/prebuilt/<target>/lib` exists, unless `options.force`.
|
|
24
24
|
- **`actions/createXCFramework.js`** combines iOS slices into an `.xcframework` (darwin only).
|
|
@@ -68,9 +68,9 @@ pnpm run ci:linux:build && pnpm run e2e:dev && pnpm run e2e:prod
|
|
|
68
68
|
|
|
69
69
|
Plus, depending on the area:
|
|
70
70
|
|
|
71
|
-
- Touched a new public export → search consumers: `
|
|
71
|
+
- Touched a new public export → search consumers: `rg "from ['\"]crossbind['\"]" plugins examples e2e scripts`.
|
|
72
72
|
- Touched `actions/run.js` (Docker / Xcode shell-out) → smoke a fresh `pnpm crossbind build` against `examples/lib-prebuilt-matrix` (smallest C++ surface).
|
|
73
|
-
- Touched `src/assets/js-runtime/` (browser/node/edge adapters) → at least one
|
|
73
|
+
- Touched `src/assets/js-runtime/` (browser/node/edge adapters) → at least one example per runtime must build and run (`examples/web-vue-vite`, `examples/backend-nodejs-wasm`, `examples/cloud-cloudflare-worker`).
|
|
74
74
|
- Touched `src/assets/js-runtime/adapters/worker-comlink.js` → coverage MUST include embind **instance** methods, not just statics: statics skip embind's `this` conversion, so a statics-only smoke passes while every instance call is broken (this shipped once, as beta.26's "Expected null or instance of X, got an instance of X"). Run the `e2e/web-vite-multithread` e2e (its Counter spec exists for exactly this), and before publishing run gdal3.js's `packages/wasm-test` suite against the packed tarball — it calls every binding, one method at a time.
|
|
75
75
|
- Touched `state/loadConfig.js` defaults → assume blast radius = whole monorepo. Run the full matrix.
|
|
76
76
|
|
|
@@ -88,5 +88,5 @@ Plus, depending on the area:
|
|
|
88
88
|
- `docs/ARCHITECTURE.md` — high-level flow + key abstractions.
|
|
89
89
|
- `docs/CODEMAP.md` — concept → file index.
|
|
90
90
|
- `docs/playbooks/bug-fix.md` — fix workflow.
|
|
91
|
-
- `docs/playbooks/new-
|
|
91
|
+
- `docs/playbooks/new-port.md` — port-authoring workflow (for `ports/`, not this directory).
|
|
92
92
|
- Logger: `src/utils/logger.js` — read this before adding any user-facing output.
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# crossbind
|
|
2
2
|
|
|
3
|
+
## 2.0.0-beta.52
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- A prebuilt library is now rebuilt when its upstream source changes. The cache keyed on existence
|
|
8
|
+
alone, so bumping nativeVersion produced binaries of the previous upstream release while the
|
|
9
|
+
manifest, provenance and licence metadata already named the new one.
|
|
10
|
+
|
|
3
11
|
## 2.0.0-beta.51
|
|
4
12
|
|
|
5
13
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -1,133 +1,348 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
<a href="https://crossbind.dev">
|
|
3
|
-
<
|
|
4
|
-
<img alt="crossbind logo" src="https://crossbind.dev/img/logo.png" height="128">
|
|
5
|
-
</picture>
|
|
3
|
+
<img src="https://raw.githubusercontent.com/crossbind/crossbind/main/landing/public/favicon.svg" alt="crossbind logo" height="96">
|
|
6
4
|
</a>
|
|
5
|
+
|
|
7
6
|
<h1>crossbind</h1>
|
|
8
|
-
|
|
9
|
-
<
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
<
|
|
16
|
-
<
|
|
17
|
-
<
|
|
18
|
-
<
|
|
19
|
-
|
|
20
|
-
|
|
7
|
+
|
|
8
|
+
<p>
|
|
9
|
+
<strong>Import C++ and Rust like JavaScript modules.</strong><br>
|
|
10
|
+
Build, package, and run native libraries across browsers, Node.js, edge
|
|
11
|
+
runtimes, iOS, Android, and WASI.
|
|
12
|
+
</p>
|
|
13
|
+
|
|
14
|
+
<p>
|
|
15
|
+
<a href="https://www.npmjs.com/package/crossbind/v/beta"><img src="https://img.shields.io/npm/v/crossbind/beta?style=flat-square&label=npm%20beta" alt="npm beta version"></a>
|
|
16
|
+
<a href="https://github.com/crossbind/crossbind/actions/workflows/build-linux.yml"><img src="https://img.shields.io/github/actions/workflow/status/crossbind/crossbind/build-linux.yml?branch=main&style=flat-square&label=linux" alt="Linux build status"></a>
|
|
17
|
+
<a href="https://github.com/crossbind/crossbind/blob/main/LICENSE"><img src="https://img.shields.io/github/license/crossbind/crossbind?style=flat-square" alt="MIT license"></a>
|
|
18
|
+
</p>
|
|
19
|
+
|
|
20
|
+
<p>
|
|
21
|
+
<a href="#start-with-a-coding-agent">Coding agents</a>
|
|
22
|
+
· <a href="https://crossbind.dev/guide/">Guide</a>
|
|
23
|
+
· <a href="https://crossbind.dev/guide/quick-start/">Quick start</a>
|
|
24
|
+
· <a href="https://crossbind.dev/guide/packages/">Libraries</a>
|
|
25
|
+
· <a href="https://github.com/crossbind/crossbind/tree/main/examples">Examples</a>
|
|
26
|
+
· <a href="https://github.com/crossbind/crossbind/blob/main/CONTRIBUTING.md">Contributing</a>
|
|
27
|
+
</p>
|
|
21
28
|
</div>
|
|
22
29
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
30
|
+
crossbind makes native libraries as easy to distribute and consume as
|
|
31
|
+
JavaScript packages. A C++ header, an app-local Rust file, or a declared Cargo
|
|
32
|
+
crate becomes an importable module; crossbind generates the binding layer,
|
|
33
|
+
resolves the transitive native dependency graph, and selects the right artifact
|
|
34
|
+
for every target.
|
|
35
|
+
|
|
36
|
+
> **Note** — crossbind 2.0 is currently published on the npm `beta` channel.
|
|
37
|
+
> The commands below use `@beta` deliberately.
|
|
38
|
+
|
|
39
|
+
## Start with a coding agent
|
|
40
|
+
|
|
41
|
+
The shortest path is to give your coding agent the crossbind skill. It inspects
|
|
42
|
+
the existing project, detects the package manager, bundler, target runtime, and
|
|
43
|
+
native sources, checks whether a prebuilt port already exists, wires the right
|
|
44
|
+
integration, and verifies the build.
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
npx skills add https://github.com/crossbind/crossbind/tree/main/agents/skills --global --yes
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Then describe the outcome you want:
|
|
51
|
+
|
|
52
|
+
```text
|
|
53
|
+
Add crossbind to this project so I can call C++ or Rust from JavaScript.
|
|
54
|
+
Inspect the repository, choose the correct integration, make the smallest
|
|
55
|
+
required changes, and verify the build.
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The skill uses the agent's existing filesystem and terminal access; no
|
|
59
|
+
crossbind-specific background service is required. Its behavior and sources of
|
|
60
|
+
truth are documented in the
|
|
61
|
+
[agent guide](https://github.com/crossbind/crossbind/blob/main/docs/agent-overview.md).
|
|
62
|
+
|
|
63
|
+
## Why crossbind
|
|
64
|
+
|
|
65
|
+
The header import is the front door. Underneath it, crossbind provides the
|
|
66
|
+
native library distribution layer for JavaScript runtimes: versioned packages,
|
|
67
|
+
target-specific artifacts, transitive dependencies, build recipes, and runtime
|
|
68
|
+
adapters.
|
|
69
|
+
|
|
70
|
+
- **Target-aware distribution.** A package family can carry WebAssembly, iOS,
|
|
71
|
+
Android, and WASI variants; each build consumes only the artifact valid for
|
|
72
|
+
its platform, architecture, runtime, environment, and build type.
|
|
73
|
+
- **Native dependency resolution.** Package manifests and crossbind configs
|
|
74
|
+
carry the transitive native graph, so prerequisites are built and linked in
|
|
75
|
+
the correct order.
|
|
76
|
+
- **A reproducible package contract.** Port recipes record upstream versions,
|
|
77
|
+
source integrity, licenses, dependencies, and target-specific artifacts.
|
|
78
|
+
- **No hand-written binding glue.** Public functions, classes, methods, enums,
|
|
79
|
+
containers, and supported standard-library types are generated from the
|
|
80
|
+
interface you already own.
|
|
81
|
+
- **C++ and Rust.** Import local native sources, a `cargo:` crate, or a reusable
|
|
82
|
+
native package through the same project.
|
|
83
|
+
- **First-party integrations and ports.** Bundler plugins provide incremental
|
|
84
|
+
builds, while version-pinned ports make libraries such as GDAL, SQLite,
|
|
85
|
+
OpenSSL, GEOS, and PROJ available without rebuilding upstream source.
|
|
86
|
+
|
|
87
|
+
## Quick start
|
|
88
|
+
|
|
89
|
+
Prefer to scaffold and configure the project yourself? You need
|
|
90
|
+
[Node.js 22+](https://nodejs.org/) and
|
|
91
|
+
[Docker](https://www.docker.com/). Docker carries the browser, Android, and
|
|
92
|
+
WASI toolchains and is pulled automatically on the first build. iOS additionally
|
|
93
|
+
requires macOS, CMake 3.28+, Xcode, and CocoaPods.
|
|
94
|
+
|
|
95
|
+
Create a project:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
62
98
|
npm create crossbind@beta
|
|
63
99
|
```
|
|
64
100
|
|
|
65
|
-
|
|
66
|
-
|
|
101
|
+
If you are unsure which template to choose, start with **Web → React → Vite**.
|
|
102
|
+
Then run the commands printed by the scaffolder:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
cd my-app
|
|
106
|
+
npm install
|
|
107
|
+
npm run dev
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
The first native build takes longer because it pulls the toolchain and fills the
|
|
111
|
+
build cache. Later rebuilds are incremental.
|
|
112
|
+
|
|
113
|
+
### Your first native call
|
|
114
|
+
|
|
115
|
+
Put the public C++ interface under `src/native`:
|
|
116
|
+
|
|
117
|
+
```cpp
|
|
118
|
+
// src/native/hello.h
|
|
119
|
+
#pragma once
|
|
120
|
+
#include <string>
|
|
121
|
+
|
|
122
|
+
inline std::string hello(const std::string& name) {
|
|
123
|
+
return "Hello, " + name + "!";
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Import the header from JavaScript and initialize the runtime before the first
|
|
128
|
+
native call:
|
|
129
|
+
|
|
67
130
|
```js
|
|
68
|
-
|
|
131
|
+
// src/main.js
|
|
132
|
+
import { initNative, hello } from './native/hello.h';
|
|
69
133
|
|
|
70
134
|
await initNative();
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
135
|
+
console.log(hello('crossbind'));
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
`initNative()` is exported by every generated native module. One call starts
|
|
139
|
+
the runtime and binds all native modules imported by the application.
|
|
140
|
+
|
|
141
|
+
## Add crossbind to an existing Vite app
|
|
142
|
+
|
|
143
|
+
Install the Vite integration:
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
npm install --save-dev @crossbind/plugin-vite@beta
|
|
74
147
|
```
|
|
75
148
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
149
|
+
Register it in `vite.config.js`:
|
|
150
|
+
|
|
151
|
+
```js
|
|
152
|
+
import { defineConfig } from 'vite';
|
|
153
|
+
import viteCrossbindPlugin from '@crossbind/plugin-vite';
|
|
81
154
|
|
|
82
|
-
|
|
83
|
-
|
|
155
|
+
export default defineConfig({
|
|
156
|
+
plugins: [viteCrossbindPlugin()],
|
|
157
|
+
});
|
|
158
|
+
```
|
|
84
159
|
|
|
85
|
-
|
|
86
|
-
if (number < 0) return -1;
|
|
160
|
+
Add the build-time configuration at the project root:
|
|
87
161
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
162
|
+
```js
|
|
163
|
+
// crossbind.config.js
|
|
164
|
+
export default {
|
|
165
|
+
paths: {
|
|
166
|
+
config: import.meta.url,
|
|
167
|
+
},
|
|
94
168
|
};
|
|
95
169
|
```
|
|
96
170
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
|
112
|
-
|
|
113
|
-
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
171
|
+
You can now add the header and JavaScript import from the quick-start example.
|
|
172
|
+
For React, Vue, Svelte, Webpack, Rspack, Rollup, Metro, and framework-specific
|
|
173
|
+
setups, use the [integration playbooks](https://github.com/crossbind/crossbind/blob/main/docs/playbooks/integration/README.md)
|
|
174
|
+
or start from the closest project in [`examples/`](https://github.com/crossbind/crossbind/tree/main/examples).
|
|
175
|
+
|
|
176
|
+
## How it works
|
|
177
|
+
|
|
178
|
+
```text
|
|
179
|
+
C++ / Rust source header, .rs, or
|
|
180
|
+
or prebuilt port cargo: import
|
|
181
|
+
| |
|
|
182
|
+
v |
|
|
183
|
+
versioned native package graph |
|
|
184
|
+
dependencies + target variants |
|
|
185
|
+
| |
|
|
186
|
+
+-------------------+-------------------+
|
|
187
|
+
|
|
|
188
|
+
v
|
|
189
|
+
target resolution
|
|
190
|
+
+ binding generation
|
|
191
|
+
+ native build and link
|
|
192
|
+
|
|
|
193
|
+
+---------------------+---------------------+
|
|
194
|
+
| | |
|
|
195
|
+
v v v
|
|
196
|
+
browser / Node / edge iOS / Android WASI
|
|
197
|
+
JavaScript + Wasm native library + JSI command component
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
There are two configuration surfaces:
|
|
201
|
+
|
|
202
|
+
| Surface | When it is read | What belongs there |
|
|
203
|
+
| --------------------- | --------------- | -------------------------------------------------------------------------------------- |
|
|
204
|
+
| `crossbind.config.js` | Build time | Native paths, dependencies, target, runtime (`st`/`mt`), output, and compiler settings |
|
|
205
|
+
| `initNative(options)` | Runtime | Worker mode, filesystem behavior, environment, asset resolution, and lifecycle hooks |
|
|
206
|
+
|
|
207
|
+
Do not put runtime options such as `useWorker` in `crossbind.config.js`; they
|
|
208
|
+
only take effect when passed to `initNative(...)`. See the
|
|
209
|
+
[runtime and configuration reference](https://github.com/crossbind/crossbind/blob/main/docs/api/README.md) for the complete
|
|
210
|
+
contract.
|
|
211
|
+
|
|
212
|
+
## Runtimes
|
|
213
|
+
|
|
214
|
+
| Runtime | Output | Important behavior |
|
|
215
|
+
| ------------ | ------------------------------------- | ------------------------------------------------------------------------------------- |
|
|
216
|
+
| Browser | JavaScript loader + WebAssembly | Single-threaded by default; multithreaded builds need COOP/COEP headers in production |
|
|
217
|
+
| Node.js | JavaScript loader + WebAssembly | Supports CommonJS or ESM and reads the host filesystem |
|
|
218
|
+
| Edge | JavaScript loader + WebAssembly | Single-threaded, memory-backed, with no OPFS or nested worker mode |
|
|
219
|
+
| React Native | Native iOS/Android libraries over JSI | No WebAssembly or browser isolation headers |
|
|
220
|
+
| WASI | One `wasm32-wasip3` command component | No JavaScript host; run with a compatible WASI runtime such as wasmtime 47+ |
|
|
221
|
+
|
|
222
|
+
Threading and worker execution are independent choices:
|
|
223
|
+
|
|
224
|
+
- `target.runtime: 'mt'` enables a multithreaded build.
|
|
225
|
+
- `initNative({ useWorker: true })` moves the module into a browser Web Worker.
|
|
226
|
+
- Browser OPFS persistence requires `useWorker: true`.
|
|
227
|
+
- Browser `mt` builds require COOP/COEP response headers in production.
|
|
228
|
+
|
|
229
|
+
Read [Threading and workers](https://github.com/crossbind/crossbind/blob/main/docs/api/threading.md)
|
|
230
|
+
and [Filesystem](https://github.com/crossbind/crossbind/blob/main/docs/api/filesystem.md)
|
|
231
|
+
before enabling those features.
|
|
232
|
+
|
|
233
|
+
## Build integrations
|
|
234
|
+
|
|
235
|
+
| Build tool or runtime | Packages |
|
|
236
|
+
| --------------------- | --------------------------------------------------------------- |
|
|
237
|
+
| Vite | `@crossbind/plugin-vite` |
|
|
238
|
+
| Rollup | `@crossbind/plugin-rollup` |
|
|
239
|
+
| Webpack / Rspack | `@crossbind/plugin-webpack`, `@crossbind/plugin-webpack-loader` |
|
|
240
|
+
| React Native / Metro | `@crossbind/plugin-react-native`, `@crossbind/plugin-metro` |
|
|
241
|
+
| No bundler | `crossbind` CLI |
|
|
242
|
+
|
|
243
|
+
The plugins resolve native imports, generate bridges, trigger builds, watch
|
|
244
|
+
native source directories, and place the produced assets into the application
|
|
245
|
+
bundle. The CLI exposes the same build pipeline for Node.js, edge, library, and
|
|
246
|
+
WASI projects.
|
|
247
|
+
|
|
248
|
+
## Prebuilt libraries and commands
|
|
249
|
+
|
|
250
|
+
The repository contains 16 port families:
|
|
251
|
+
|
|
252
|
+
**cURL · Expat · GDAL · GEOS · GeoTIFF · iconv · libjpeg-turbo · LERC ·
|
|
253
|
+
OpenSSL · PROJ · SpatiaLite · SQLite · libTIFF · WebP · zlib · Zstandard**
|
|
254
|
+
|
|
255
|
+
Each family has target-specific packages. For example, a browser or Node.js
|
|
256
|
+
project uses `@crossbind/port-gdal-wasm`, while mobile and WASI builds use the
|
|
257
|
+
matching `-android`, `-ios`, or `-wasi` variant. Import the variant's
|
|
258
|
+
`crossbind.config.js` into the application's dependency list:
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
npm install @crossbind/port-gdal-wasm@beta
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
```js
|
|
265
|
+
// crossbind.config.js
|
|
266
|
+
import gdal from '@crossbind/port-gdal-wasm/crossbind.config.js';
|
|
267
|
+
|
|
268
|
+
export default {
|
|
269
|
+
dependencies: [gdal],
|
|
270
|
+
paths: {
|
|
271
|
+
config: import.meta.url,
|
|
272
|
+
},
|
|
273
|
+
};
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
The variant declares its transitive native dependency graph, so link order is
|
|
277
|
+
derived automatically. Install and register every platform variant your
|
|
278
|
+
project actually builds. See the [package guide](https://crossbind.dev/guide/packages/)
|
|
279
|
+
and [`ports/README.md`](https://github.com/crossbind/crossbind/blob/main/ports/README.md)
|
|
280
|
+
for the package and license contracts.
|
|
281
|
+
|
|
282
|
+
Some upstream command-line tools are also published as WASI-powered npm
|
|
283
|
+
commands. They require `wasmtime` on `PATH`, but no compiler:
|
|
284
|
+
|
|
285
|
+
```bash
|
|
286
|
+
npm install --global @crossbind/port-gdal-bin-wasi@beta
|
|
287
|
+
gdalinfo-wasi --version
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
## Rust
|
|
291
|
+
|
|
292
|
+
crossbind supports app-local `.rs` files, direct crates.io imports through the
|
|
293
|
+
`cargo:` scheme, and reusable Cargo-backed packages. Rust uses the same
|
|
294
|
+
generated-module and `initNative()` model as C++.
|
|
295
|
+
|
|
296
|
+
A local Rust toolchain is required. WebAssembly multithreading currently needs
|
|
297
|
+
nightly Rust, and WASI command builds do not yet support Rust because there is
|
|
298
|
+
no `wasm32-wasip3` Rust target. Start with the
|
|
299
|
+
[Rust guide](https://github.com/crossbind/crossbind/blob/main/docs/api/rust.md)
|
|
300
|
+
for the supported type surface and configuration.
|
|
301
|
+
|
|
302
|
+
## Documentation
|
|
303
|
+
|
|
304
|
+
- [Guide](https://crossbind.dev/guide/) — product concepts, quick start,
|
|
305
|
+
runtimes, bundlers, bindings, packages, and troubleshooting.
|
|
306
|
+
- [Runtime and configuration API](https://github.com/crossbind/crossbind/blob/main/docs/api/README.md)
|
|
307
|
+
— canonical build-time and runtime behavior.
|
|
308
|
+
- [Integration playbooks](https://github.com/crossbind/crossbind/blob/main/docs/playbooks/integration/README.md)
|
|
309
|
+
— Vite, Webpack/Rspack, Rollup, Node.js, edge, React Native, and more.
|
|
310
|
+
- [Examples](https://github.com/crossbind/crossbind/tree/main/examples) —
|
|
311
|
+
runnable reference applications and library templates.
|
|
312
|
+
- [Architecture](https://github.com/crossbind/crossbind/blob/main/docs/ARCHITECTURE.md)
|
|
313
|
+
and [codemap](https://github.com/crossbind/crossbind/blob/main/docs/CODEMAP.md)
|
|
314
|
+
— how the monorepo is organized and where each subsystem lives.
|
|
315
|
+
- [Troubleshooting](https://github.com/crossbind/crossbind/blob/main/docs/api/troubleshooting.md)
|
|
316
|
+
— common errors and their standard fixes.
|
|
317
|
+
- [Changelog](https://github.com/crossbind/crossbind/blob/main/CHANGELOG.md) —
|
|
318
|
+
release history.
|
|
319
|
+
|
|
320
|
+
## Contributing
|
|
321
|
+
|
|
322
|
+
This is a pnpm monorepo. To work on crossbind itself:
|
|
323
|
+
|
|
324
|
+
```bash
|
|
325
|
+
git clone https://github.com/crossbind/crossbind.git
|
|
326
|
+
cd crossbind
|
|
327
|
+
pnpm install
|
|
328
|
+
pnpm run doctor
|
|
329
|
+
pnpm test
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
Use a package filter for day-to-day builds; the full native matrix is
|
|
333
|
+
intentionally expensive. Read
|
|
334
|
+
[CONTRIBUTING.md](https://github.com/crossbind/crossbind/blob/main/CONTRIBUTING.md)
|
|
335
|
+
for the repository layout, validation matrix, coding conventions, and
|
|
336
|
+
pull-request process.
|
|
337
|
+
|
|
338
|
+
## Support
|
|
339
|
+
|
|
340
|
+
- Ask usage questions in [GitHub Discussions](https://github.com/crossbind/crossbind/discussions).
|
|
341
|
+
- Report reproducible bugs in [GitHub Issues](https://github.com/crossbind/crossbind/issues).
|
|
129
342
|
|
|
130
343
|
## License
|
|
131
|
-
[MIT](https://github.com/crossbind/crossbind/blob/main/LICENSE)
|
|
132
344
|
|
|
133
|
-
|
|
345
|
+
crossbind is available under the
|
|
346
|
+
[MIT License](https://github.com/crossbind/crossbind/blob/main/LICENSE).
|
|
347
|
+
|
|
348
|
+
Copyright © 2026 Buğra Sarı
|
package/package.json
CHANGED
package/src/actions/buildLib.js
CHANGED
|
@@ -6,6 +6,7 @@ import { getBuildTargets, getFilteredTargetSpec } from './target.js';
|
|
|
6
6
|
import state from '../state/index.js';
|
|
7
7
|
import logger from '../utils/logger.js';
|
|
8
8
|
import findFiles from '../utils/findFiles.js';
|
|
9
|
+
import { getSourceFingerprint, isSourceFingerprintStale, writeSourceFingerprint } from '../utils/sourceFingerprint.js';
|
|
9
10
|
|
|
10
11
|
export default function buildLib(targetParams, options = {}) {
|
|
11
12
|
let isChanged = false;
|
|
@@ -19,8 +20,13 @@ export default function buildLib(targetParams, options = {}) {
|
|
|
19
20
|
// Cargo re-enters the build unconditionally: cargo is the incremental cache, and the
|
|
20
21
|
// existence-only skip below would keep serving a stale staged staticlib after source edits.
|
|
21
22
|
const isCargo = state.config.export?.type === 'cargo';
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
const libdir = `${state.config.paths.output}/prebuilt/${target.path}`;
|
|
24
|
+
const sourceFingerprint = getSourceFingerprint(state.config);
|
|
25
|
+
const sourceChanged = isSourceFingerprintStale(libdir, sourceFingerprint);
|
|
26
|
+
if (isCargo || sourceChanged || !fs.existsSync(`${libdir}/lib`)) {
|
|
27
|
+
// createLib caches on existence too, so re-entering is not enough: a stale stamp means
|
|
28
|
+
// the lib on disk came from a different upstream release and has to be rebuilt.
|
|
29
|
+
createLib(target, 'Source', { buildSource: true, force: sourceChanged });
|
|
24
30
|
|
|
25
31
|
const modules = [];
|
|
26
32
|
state.config.paths.module.forEach((modulePath) => {
|
|
@@ -34,6 +40,7 @@ export default function buildLib(targetParams, options = {}) {
|
|
|
34
40
|
const fileName = modulePath.split('/').at(-1);
|
|
35
41
|
fs.copyFileSync(modulePath, `${state.config.paths.output}/prebuilt/${target.path}/swig/${fileName}`);
|
|
36
42
|
});
|
|
43
|
+
writeSourceFingerprint(libdir, sourceFingerprint);
|
|
37
44
|
isChanged = true;
|
|
38
45
|
} else {
|
|
39
46
|
// The skip is existence-only; without this warning a source edit is served stale silently.
|
|
@@ -79,7 +86,7 @@ export default function buildLib(targetParams, options = {}) {
|
|
|
79
86
|
: `-Wl,-u,_crossbind_keep_${l}`)).join(' ');
|
|
80
87
|
ldFlags = `, 'OTHER_LDFLAGS' => '${flags}'`;
|
|
81
88
|
}
|
|
82
|
-
const distPodSpecContent = fs.readFileSync(`${state.config.paths.cli}/assets/packaging/crossbind-
|
|
89
|
+
const distPodSpecContent = fs.readFileSync(`${state.config.paths.cli}/assets/packaging/crossbind-port.podspec`, { encoding: 'utf8', flag: 'r' })
|
|
83
90
|
// module_name must be a valid C99 identifier (pod names may carry dashes).
|
|
84
91
|
.replace('___PROJECT_MODULE_NAME___', state.config.general.name.replace(/[^a-zA-Z0-9_]/g, '_'))
|
|
85
92
|
.replaceAll('___PROJECT_NAME___', state.config.general.name)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import { getContentHash } from './hash.js';
|
|
3
|
+
|
|
4
|
+
// The prebuilt-lib cache in buildLib is existence-only, so a nativeVersion or recipe-sha256 bump
|
|
5
|
+
// would otherwise be served from the previous build - shipping the old upstream under the new
|
|
6
|
+
// version, with provenance and licence metadata already claiming the new one.
|
|
7
|
+
export const SOURCE_FINGERPRINT_FILE = 'crossbind-source.fingerprint';
|
|
8
|
+
|
|
9
|
+
export function getSourceFingerprint(config) {
|
|
10
|
+
const nativeVersion = config?.package?.nativeVersion || null;
|
|
11
|
+
const sha256 = config?.build?.sha256 || null;
|
|
12
|
+
// Packages that build from local sources pin neither; they keep the existence-only behaviour.
|
|
13
|
+
if (!nativeVersion && !sha256) return null;
|
|
14
|
+
return getContentHash(JSON.stringify({ nativeVersion, sha256 }));
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function isSourceFingerprintStale(libdir, fingerprint) {
|
|
18
|
+
if (!fingerprint) return false;
|
|
19
|
+
const file = `${libdir}/${SOURCE_FINGERPRINT_FILE}`;
|
|
20
|
+
return !fs.existsSync(file) || fs.readFileSync(file, { encoding: 'utf8' }) !== fingerprint;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function writeSourceFingerprint(libdir, fingerprint) {
|
|
24
|
+
if (!fingerprint) return;
|
|
25
|
+
fs.mkdirSync(libdir, { recursive: true });
|
|
26
|
+
fs.writeFileSync(`${libdir}/${SOURCE_FINGERPRINT_FILE}`, fingerprint);
|
|
27
|
+
}
|
|
File without changes
|