From e55a29f5fd04c32b48dae174cd1ec5f487ecd18d Mon Sep 17 00:00:00 2001 From: stephan Date: Mon, 22 Sep 2025 21:04:24 +0000 Subject: [PATCH] Refactor and simplify the JS API bootstrap steps. FossilOrigin-Name: a4f36fd93738f985d2c757c69eddca092732ce6148af98eb2595f9abe0d4fa44 --- ext/wasm/api/README.md | 2 +- ext/wasm/api/extern-post-js.c-pp.js | 33 +++------- ext/wasm/api/post-js-header.js | 21 ++++-- ext/wasm/api/pre-js.c-pp.js | 4 +- ext/wasm/api/sqlite3-api-cleanup.js | 97 ++++++++++++++-------------- ext/wasm/api/sqlite3-api-prologue.js | 43 ++++++++---- ext/wasm/c-pp.c | 8 +-- manifest | 24 +++---- manifest.uuid | 2 +- 9 files changed, 125 insertions(+), 109 deletions(-) diff --git a/ext/wasm/api/README.md b/ext/wasm/api/README.md index 08d7d593b3..7b5e24cd1a 100644 --- a/ext/wasm/api/README.md +++ b/ext/wasm/api/README.md @@ -148,7 +148,7 @@ build-generated `sqlite3.js` along with `sqlite3-api.js`. most of its work. - **`post-js-header.js`**\ Emscripten-specific header for the `--post-js` input. It opens up, - but does not close, a function. + but does not close, a function used for initializing the library. - (**`sqlite3-api.js`** gets sandwiched between these ↑ two ↓ files.) - **`post-js-footer.js`**\ diff --git a/ext/wasm/api/extern-post-js.c-pp.js b/ext/wasm/api/extern-post-js.c-pp.js index eb5b722cd2..e26e8bef66 100644 --- a/ext/wasm/api/extern-post-js.c-pp.js +++ b/ext/wasm/api/extern-post-js.c-pp.js @@ -64,29 +64,13 @@ const toExportForESM = return originalInit(...args).then((EmscriptenModule)=>{ sIMS.debugModule("sqlite3InitModule() sIMS =",sIMS); sIMS.debugModule("sqlite3InitModule() EmscriptenModule =",EmscriptenModule); - EmscriptenModule.runSQLite3PostLoadInit( - EmscriptenModule /* see post-js-header/footer.js */ + const s = EmscriptenModule.runSQLite3PostLoadInit( + sIMS, + EmscriptenModule /* see post-js-header/footer.js */, + !!ff.__isUnderTest ); - delete EmscriptenModule.runSQLite3PostLoadInit; - const s = EmscriptenModule.sqlite3; - delete EmscriptenModule.sqlite3; - s.scriptInfo = sIMS /* needed by async init below */; - if(ff.__isUnderTest){ - s.__isUnderTest = true; - s.emscripten = EmscriptenModule; -//#if custom-Module.instantiateWasm - const iw = sIMS.instantiateWasm; - if( iw ){ - /* Metadata injected by the custom Module.instantiateWasm() - in pre-js.c-pp.js. */ - s.wasm.module = iw.module; - s.wasm.instance = iw.instance; - s.wasm.imports = iw.imports; - } -//#endif custom-Module.instantiateWasm - } - const rv = s.asyncPostInit(); - delete s.asyncPostInit; + //const rv = s.asyncPostInit(); + //delete s.asyncPostInit; //#if wasmfs if('undefined'!==typeof WorkerGlobalScope && EmscriptenModule['ENVIRONMENT_IS_PTHREAD']){ @@ -99,7 +83,7 @@ const toExportForESM = return EmscriptenModule; } //#endif - return rv; + return s; }).catch((e)=>{ console.error("Exception loading sqlite3 module:",e); throw e; @@ -129,6 +113,9 @@ const toExportForESM = glue... */ if (typeof exports === 'object' && typeof module === 'object'){ module.exports = sqlite3InitModule; + module.exports.default = sqlite3InitModule; + }else if( 'function'===typeof define && define.amd ){ + define([], ()=>sqlite3InitModule); }else if (typeof exports === 'object'){ exports["sqlite3InitModule"] = sqlite3InitModule; } diff --git a/ext/wasm/api/post-js-header.js b/ext/wasm/api/post-js-header.js index 3b988952a2..cdc6b3a38d 100644 --- a/ext/wasm/api/post-js-header.js +++ b/ext/wasm/api/post-js-header.js @@ -1,19 +1,26 @@ /** post-js-header.js is to be prepended to other code to create - post-js.js for use with Emscripten's --post-js flag. This code - requires that it be running in that context. The Emscripten - environment must have been set up already but it will not have - loaded its WASM when the code in this file is run. The function this - file installs will be run after the WASM module is loaded, at which - point the sqlite3 JS API bits will get set up. + post-js.js for use with Emscripten's --post-js flag, so it gets + injected in the earliest stages of sqlite3InitModule(). + + This function wraps the whole SQLite3 library but does not + bootstrap it. + + Running this function will bootstrap the library and return + a Promise to the sqlite3 namespace object. */ -Module.runSQLite3PostLoadInit = function(EmscriptenModule/*the Emscripten-style module object*/){ +Module.runSQLite3PostLoadInit = function( + sqlite3InitScriptInfo /* populated by extern-post-js.c-pp.js */, + EmscriptenModule/*the Emscripten-style module object*/, + sqlite3IsUnderTest +){ /** ^^^ Don't use Module.postRun, as that runs a different time depending on whether this file is built with emcc 3.1.x or 4.0.x. This function name is intentionally obnoxiously verbose to ensure that we don't collide with current and future Emscripten symbol names. */ 'use strict'; + delete EmscriptenModule.runSQLite3PostLoadInit; //console.warn("This is the start of Module.runSQLite3PostLoadInit()"); /* This function will contain at least the following: diff --git a/ext/wasm/api/pre-js.c-pp.js b/ext/wasm/api/pre-js.c-pp.js index 65cbbf6381..364834d8fa 100644 --- a/ext/wasm/api/pre-js.c-pp.js +++ b/ext/wasm/api/pre-js.c-pp.js @@ -17,7 +17,9 @@ const sIMS = globalThis.sqlite3InitModuleState/*from extern-post-js.c-pp.js*/ || Object.assign(Object.create(null),{ - debugModule: ()=>{} + debugModule: ()=>{ + console.warn("globalThis.sqlite3InitModuleState is missing"); + } }); delete globalThis.sqlite3InitModuleState; sIMS.debugModule('pre-js.js sqlite3InitModuleState =',sIMS); diff --git a/ext/wasm/api/sqlite3-api-cleanup.js b/ext/wasm/api/sqlite3-api-cleanup.js index 4035ebdeec..a9e0047055 100644 --- a/ext/wasm/api/sqlite3-api-cleanup.js +++ b/ext/wasm/api/sqlite3-api-cleanup.js @@ -26,56 +26,57 @@ It is run within a context which gives it access to Emscripten's Module object, after sqlite3.wasm is loaded but before sqlite3ApiBootstrap() has been called. + + Because this code resides (after building) inside the function + installed by post-js-header.js, it has access to the */ 'use strict'; -if( 'undefined' !== typeof Module ){ // presumably an Emscripten build - try{ - const SABC = Object.assign( - /** - The WASM-environment-dependent configuration for - sqlite3ApiBootstrap(). - */ - Object.create(null), - globalThis.sqlite3ApiConfig || {}, { - memory: ('undefined'!==typeof wasmMemory) - ? wasmMemory - : Module['wasmMemory'], - exports: ('undefined'!==typeof wasmExports) - ? wasmExports /* emscripten >=3.1.44 */ - : (Object.prototype.hasOwnProperty.call(Module,'wasmExports') - ? Module['wasmExports'] - : Module['asm']/* emscripten <=3.1.43 */) - }, - ); +if( 'undefined' === typeof EmscriptenModule/*from post-js-header.js*/ ){ + console.warn("This is not running in the context of Module.runSQLite3PostLoadInit()"); + throw new Error("sqlite3-api-cleanup.js expects to be running in the "+ + "context of its Emscripten module loader."); +} + +try{ + /* Config options for sqlite3ApiBootstrap(). */ + const bootstrapConfig = Object.assign( + Object.create(null), + globalThis.sqlite3ApiBootstrap.defaultConfig, // default options + globalThis.sqlite3ApiConfig || {}, // optional client-provided options + /** The WASM-environment-dependent configuration for sqlite3ApiBootstrap() */ + { + memory: ('undefined'!==typeof wasmMemory) + ? wasmMemory + : EmscriptenModule['wasmMemory'], + exports: ('undefined'!==typeof wasmExports) + ? wasmExports /* emscripten >=3.1.44 */ + : (Object.prototype.hasOwnProperty.call(EmscriptenModule,'wasmExports') + ? EmscriptenModule['wasmExports'] + : EmscriptenModule['asm']/* emscripten <=3.1.43 */) + } + ); - /** Figure out if this is a 32- or 64-bit WASM build. */ - SABC.wasmPtrIR = 'number'===(typeof SABC.exports.sqlite3_libversion()) - ? 'i32' :'i64'; + /** Figure out if this is a 32- or 64-bit WASM build. */ + bootstrapConfig.wasmPtrIR = + 'number'===(typeof bootstrapConfig.exports.sqlite3_libversion()) + ? 'i32' :'i64'; - /** - For current (2022-08-22) purposes, automatically call - sqlite3ApiBootstrap(). That decision will be revisited at some - point, as we really want client code to be able to call this to - configure certain parts. Clients may modify - globalThis.sqlite3ApiBootstrap.defaultConfig to tweak the default - configuration used by a no-args call to sqlite3ApiBootstrap(), - but must have first loaded their WASM module in order to be - able to provide the necessary configuration state. - */ - //console.warn("globalThis.sqlite3ApiConfig = ",globalThis.sqlite3ApiConfig); - Module.sqlite3 = globalThis.sqlite3ApiBootstrap(SABC) - /* Our customized sqlite3InitModule() in extern-post-js.js needs - this to be able to pass the sqlite3 object off to the - client. */; - delete globalThis.sqlite3ApiBootstrap; - delete globalThis.sqlite3ApiConfig; - }catch(e){ - console.error("sqlite3ApiBootstrap() error:",e); - throw e; - } -}else{ - console.warn("This is not running in an Emscripten module context, so", - "globalThis.sqlite3ApiBootstrap() is _not_ being called due to lack", - "of config info for the WASM environment.", - "It must be called manually."); + /** + For purposes of the Emscripten build, call sqlite3ApiBootstrap(). + Ideally clients should be able to inject their own config here, + but that's not practical in this particular build constellation + because of the order everything happens in. Clients may either + define globalThis.sqlite3ApiConfig or modify + globalThis.sqlite3ApiBootstrap.defaultConfig to tweak the default + configuration used by a no-args call to sqlite3ApiBootstrap(), + but must have first loaded their WASM module in order to be able + to provide the necessary configuration state. + */ + const p = globalThis.sqlite3ApiBootstrap(bootstrapConfig); + delete globalThis.sqlite3ApiBootstrap; + return p; +}catch(e){ + console.error("sqlite3ApiBootstrap() error:",e); + throw e; } +throw new Error("Maintenance required: this line should never be reached"); diff --git a/ext/wasm/api/sqlite3-api-prologue.js b/ext/wasm/api/sqlite3-api-prologue.js index 0754bc82b5..84b421be15 100644 --- a/ext/wasm/api/sqlite3-api-prologue.js +++ b/ext/wasm/api/sqlite3-api-prologue.js @@ -127,17 +127,12 @@ because any changes to them made after that point would have no useful effect. - This function bootstraps only the _synchronous_ pieces of the - library. After calling this, sqlite3.asyncPostInit() must be - called to initialize any async pieces (most notably the - OPFS-related pieces) and should then delete sqlite3.asyncPostInit. - That function is NOT part of the public interface, but is rather a - side-effect of how we need to finalize initialization. If we - include that part of the init from here, this function will need to - return a Promise instead of being synchronous. + This function returns a Promise to the sqlite3 namespace object, + which resolves after the async pieces of the library init are + complete. */ 'use strict'; -globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( +globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap( apiConfig = (globalThis.sqlite3ApiConfig || sqlite3ApiBootstrap.defaultConfig) ){ if(sqlite3ApiBootstrap.sqlite3){ /* already initialized */ @@ -2076,8 +2071,6 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( clients build their own sqlite3.wasm which contains their own C struct types. */ delete sqlite3.StructBinder; - delete sqlite3.scriptInfo; - delete sqlite3.emscripten; } return sqlite3; }; @@ -2122,7 +2115,33 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( } delete sqlite3ApiBootstrap.initializers; sqlite3ApiBootstrap.sqlite3 = sqlite3; - return sqlite3; + delete globalThis.sqlite3ApiBootstrap; + delete globalThis.sqlite3ApiConfig; + sqlite3InitScriptInfo.debugModule( + "sqlite3ApiBootstrap() complete", sqlite3 + ); + sqlite3.scriptInfo /* used by some async init code */ = + sqlite3InitScriptInfo /* from post-js-header.js */; + if( (sqlite3.__isUnderTest = sqlite3IsUnderTest) ){ + sqlite3.config.emscripten = EmscriptenModule; + const iw = sqlite3InitScriptInfo.instantiateWasm; + if( iw ){ + /* Metadata injected by the custom Module.instantiateWasm() + in pre-js.c-pp.js. */ + sqlite3.wasm.module = iw.module; + sqlite3.wasm.instance = iw.instance; + sqlite3.wasm.imports = iw.imports; + } + } + return sqlite3.asyncPostInit().then((s)=>{ + sqlite3InitScriptInfo.debugModule( + "sqlite3.asyncPostInit() complete", sqlite3 + ); + delete s.asyncPostInit; + delete s.scriptInfo; + delete s.emscripten; + return s; + }); }/*sqlite3ApiBootstrap()*/; /** diff --git a/ext/wasm/c-pp.c b/ext/wasm/c-pp.c index 318325e93e..0968a68690 100644 --- a/ext/wasm/c-pp.c +++ b/ext/wasm/c-pp.c @@ -39,13 +39,13 @@ * - `#stderr` outputs its file name, line number, and the remainder ** of that line to stderr. ** -** - `#//` acts as a single-line comment, noting that there must be as +** - `#//` acts as a single-line comment, noting that there must be no ** space after the `//` part because `//` is (despite appearances) ** parsed like a keyword. ** -** Note that "#" above is symbolic. The keyword delimiter is -** configurable and defaults to "##". Define CMPP_DEFAULT_DELIM to a -** string when compiling to define the default at build-time. +** The "#" above is symbolic. The keyword delimiter is configurable +** and defaults to "##". Define CMPP_DEFAULT_DELIM to a string when +** compiling to define the default at build-time. ** ** This preprocessor does no expansion of content except within the ** bounds of its `#keywords`. diff --git a/manifest b/manifest index e398c11887..d0fe8e6887 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Update\sext/wasm/api/README.md\sfor\srecent\schanges. -D 2025-09-22T18:05:10.957 +C Refactor\sand\ssimplify\sthe\sJS\sAPI\sbootstrap\ssteps. +D 2025-09-22T21:04:24.057 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -590,16 +590,16 @@ F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-core e5cf4fa7610a09d51017d75faf50be381 F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-extras cb4fa8842c875b6ee99381523792975c5ebb7371bd27fbd1bd863a43c7f3505a F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-see fb29e62082a658f0d81102488414d422c393c4b20cc2f685b216bc566237957b F ext/wasm/api/EXPORTED_RUNTIME_METHODS.sqlite3-api 1ec3c73e7d66e95529c3c64ac3de2470b0e9e7fbf7a5b41261c367cf4f1b7287 -F ext/wasm/api/README.md 5fc27524cae0851ba577859dc464e432f2de8a633c30927d29e81b6904e699d5 -F ext/wasm/api/extern-post-js.c-pp.js 36181698fa0a8dba6292d0659c8945941f7794d632883bd335c4a7c7d2981555 +F ext/wasm/api/README.md dd7008fb495eabf46541c4422cc396b3705507c80d681e388e02969e3707dd27 +F ext/wasm/api/extern-post-js.c-pp.js d3748c6bbdcef15d8e494e0558aad370b9c24242eb020042b3a73b4950562f5b F ext/wasm/api/extern-pre-js.js cc61c09c7a24a07dbecb4c352453c3985170cec12b4e7e7e7a4d11d43c5c8f41 F ext/wasm/api/post-js-footer.js e617e5f81a907362de152576323155f02d24642e625fc05fb801b86b6a269444 -F ext/wasm/api/post-js-header.js ada7c1efc3f72126cc10c5977dba1813f2b790fafed1a817fdea805d92bd2ae6 -F ext/wasm/api/pre-js.c-pp.js 9926ffc97c1053b5605c1b46ada396d73c07c424dd3e1cd499bbe80dc1f838cb -F ext/wasm/api/sqlite3-api-cleanup.js 9d15f0593628c526a3eee4906a224b59d60f82e765b20c7277ffe109c3da4920 +F ext/wasm/api/post-js-header.js 79d078aec33d93b640a19c574b504d88bb2446432f38e2fbb3bb8e36da436e70 +F ext/wasm/api/pre-js.c-pp.js 664551f490d296e0f4590d3a029787ab0782b9a1fa5954d73bde4fb2c6bfc709 +F ext/wasm/api/sqlite3-api-cleanup.js f91a2afdef19c350bce99784fff20310d4d060520001059822aa36c4ce80dc56 F ext/wasm/api/sqlite3-api-glue.c-pp.js 12f5b36775fab1e7bf5385689fded2b2a9f77360562515e9849acb5e66602e2d F ext/wasm/api/sqlite3-api-oo1.c-pp.js db4c8ebb03bac60db32ce03f8c615b00f4e4ad53e7d5de5e63d2780cba052caa -F ext/wasm/api/sqlite3-api-prologue.js 0daf5f7c6ebbae3c21df19ede17114aad2643b7898f0ea1ae35abbd824b6e6cf +F ext/wasm/api/sqlite3-api-prologue.js 259c72c6a33ba1be2297c568cbc2ad53437d1d4b2613d7772c56a3aa00bf435d F ext/wasm/api/sqlite3-api-worker1.c-pp.js 760191cd13416e6f5adfd9fcc8a97fed5645c9e0a5fbac213a2d4ce2d79a4334 F ext/wasm/api/sqlite3-license-version-header.js 0c807a421f0187e778dc1078f10d2994b915123c1223fe752b60afdcd1263f89 F ext/wasm/api/sqlite3-opfs-async-proxy.js 9654b565b346dc609b75d15337f20acfa7af7d9d558da1afeb9b6d8eaa404966 @@ -614,7 +614,7 @@ F ext/wasm/batch-runner-sahpool.html e9a38fdeb36a13eac7b50241dfe7ae066fe3f51f5c0 F ext/wasm/batch-runner-sahpool.js 54a3ac228e6c4703fe72fb65c897e19156263a51fe9b7e21d2834a45e876aabd F ext/wasm/batch-runner.html 4deeed44fe41496dc6898d9fb17938ea3291f40f4bfb977e29d0cef96fbbe4c8 F ext/wasm/batch-runner.js 05ec254f5dbfe605146d9640b3db17d6ef8c3fbef6aa8396051ca72bb5884e3f -F ext/wasm/c-pp.c cca55c5b55ebd8d29916adbedb0e40baa12caa9a2e8429f812683c308f9b0e9a +F ext/wasm/c-pp.c 75e23ad9ca3a3771e70d401ba79c0bacdf7b2169d1c17f9e2639d81067e5ab95 F ext/wasm/common/SqliteTestUtil.js 7adaeffef757d8708418dc9190f72df22367b531831775804b31598b44f6aa51 F ext/wasm/common/emscripten.css 11bd104b6c0d597c67d40cc8ecc0a60dae2b965151e3b6a37fa5708bac3acd15 F ext/wasm/common/testing.css e97549bab24126c24e0daabfe2de9bb478fb0a69fdb2ddd0a73a992c091aad6f @@ -2175,8 +2175,8 @@ F tool/version-info.c 3b36468a90faf1bbd59c65fd0eb66522d9f941eedd364fabccd7227350 F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7 F tool/warnings.sh 1ad0169b022b280bcaaf94a7fa231591be96b514230ab5c98fbf15cd7df842dd F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 35651d9ab5529da915500fc50ca3833a004d0b7a19d98e8fbf39234d94697aec -R 452146c528c5b88da8bcc9faecddbf7e +P 03b70686939e5f9ad984220a31674c23a1beb19f040c6327f24e23f0378555da +R 6a74008597b5313223f9fb216ce43e56 U stephan -Z 3d212d42a59ec4f93d36bc8b774364d4 +Z 1035784c7ea8d2df82b4b0ed89892087 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index afeb1ac9d5..2b41b0d238 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -03b70686939e5f9ad984220a31674c23a1beb19f040c6327f24e23f0378555da +a4f36fd93738f985d2c757c69eddca092732ce6148af98eb2595f9abe0d4fa44 -- 2.47.3