| … | … | @@ -78,10 +78,37 @@ console.log(`bundle demands ${want.size} addon(s)`) |
| 78 | 78 | |
| 79 | 79 | for await (const _ of link(root, { hosts, out })) { /* bare-link stages the superset */ } |
| 80 | 80 | |
| 81 | // ⛔ VERIFY THE ABIs WE SHIP, NOT WHATEVER DIRECTORIES EXIST. This loop used to check every directory |
| 82 | // under `out`, and `out` lives in node_modules, which the CI copies wholesale from the live checkout — |
| 83 | // so it still holds armeabi-v7a/x86/x86_64 from before the arm64-only decision (62 .so each). Staging |
| 84 | // only refreshes arm64, so the moment a demanded addon's version CHANGED, the stale dirs no longer had |
| 85 | // the file under its new name and the build failed on three ABIs this APK does not contain: |
| 86 | // |
| 87 | // DEMANDED BUT NOT STAGED: armeabi-v7a/libbare-dns.2.2.0.so, x86/…, x86_64/… |
| 88 | // |
| 89 | // (bare-link names prebuilds lib<name>.<version>.so, so a dependency bump renames the file — which is |
| 90 | // what turned dormant leftovers into a build failure on the bare-dns 2.1.4 → 2.2.0 upgrade.) |
| 91 | // |
| 92 | // abiFilters keeps those ABIs out of the APK regardless, so a missing .so there cannot dlopen-fail on |
| 93 | // any device we ship to. Checking them was asserting on leftovers, not on the build. |
| 94 | const ABI_FOR_HOST = { |
| 95 | 'android-arm64': 'arm64-v8a', |
| 96 | 'android-arm': 'armeabi-v7a', |
| 97 | 'android-ia32': 'x86', |
| 98 | 'android-x64': 'x86_64' |
| 99 | } |
| 100 | const shipped = new Set(hosts.map((h) => ABI_FOR_HOST[h] || h)) |
| 101 | |
| 81 | 102 | // Report the split per ABI and verify the contract. Only .so files are considered — bare-kit also |
| 82 | 103 | // consumes *.classes.jar from this dir. |
| 83 | 104 | const missing = [] |
| 84 | 105 | |
| 106 | // A shipped ABI with no directory at all is the failure this check exists for, and an empty `out` |
| 107 | // would otherwise pass silently — the loop below would simply iterate over nothing. |
| 108 | for (const abi of shipped) { |
| 109 | if (!fs.existsSync(path.join(out, abi))) missing.push(`${abi}/ (nothing staged for a shipped ABI)`) |
| 110 | } |
| 111 | |
| 85 | 112 | for (const abi of fs.readdirSync(out)) { |
| 86 | 113 | const abiDir = path.join(out, abi) |
| 87 | 114 | if (!fs.statSync(abiDir).isDirectory()) continue |
| … | … | @@ -102,11 +129,13 @@ for (const abi of fs.readdirSync(out)) { |
| 102 | 129 | // arm64 APK entries. Quote the APK delta, not this, when reporting size wins. |
| 103 | 130 | console.log( |
| 104 | 131 | ` ${abi}: ${present.size}/${want.size} demanded staged, ` + |
| 105 | | `${excess} excess excluded at packaging (${(excessBytes / 1048576).toFixed(1)} MB on disk, pre-strip)` |
| 132 | `${excess} excess excluded at packaging (${(excessBytes / 1048576).toFixed(1)} MB on disk, pre-strip)` + |
| 133 | (shipped.has(abi) ? '' : ' — NOT SHIPPED (abiFilters), not verified') |
| 106 | 134 | ) |
| 107 | 135 | |
| 108 | 136 | // A demanded addon with no staged .so is a dlopen failure at runtime, on a device, with no |
| 109 | | // build-time signal. Fail here instead. |
| 137 | // build-time signal. Fail here instead — but only for an ABI that reaches a device. |
| 138 | if (!shipped.has(abi)) continue |
| 110 | 139 | for (const w of want) if (!present.has(w)) missing.push(`${abi}/${w}`) |
| 111 | 140 | } |
| 112 | 141 | |