Index: ext/wasm/GNUmakefile ================================================================== --- ext/wasm/GNUmakefile +++ ext/wasm/GNUmakefile @@ -35,10 +35,19 @@ # - The bash shell # - GNU make, GNU sed, GNU awk, GNU grep (all in the $PATH) # - wasm-strip for release builds: https://github.com/WebAssembly/wabt # - InfoZip for 'dist' zip file ######################################################################## +# +# Significant TODOs for this build include, but are not necessarily +# limited to: +# +# 1) Consolidate the code generation for sqlite3*.*js into a script +# which generates the makefile code, rather than using $(call) and +# $(eval), or at least centralize the setup of the numerous vars +# related to each build variant (vanilla, esm, bundler-friendly). +# SHELL := $(shell which bash 2>/dev/null) MAKEFILE := $(lastword $(MAKEFILE_LIST)) CLEAN_FILES := DISTCLEAN_FILES := ./--dummy-- default: all @@ -47,10 +56,17 @@ # Emscripten SDK home dir and related binaries... EMSDK_HOME ?= $(word 1,$(wildcard $(HOME)/emsdk $(HOME)/src/emsdk)) emcc.bin ?= $(word 1,$(wildcard $(EMSDK_HOME)/upstream/emscripten/emcc) $(shell which emcc)) ifeq (,$(emcc.bin)) $(error Cannot find emcc.) +endif +emcc.version := $(shell "$(emcc.bin)" --version | sed -n 1p \ + | sed -e 's/^.* \([3-9][^ ]*\) .*$$/\1/;') +ifeq (,$(emcc.version)) + $(warning Cannot determine emcc version. This might unduly impact build flags.) +else + $(info using emcc version [$(emcc.version)]) endif wasm-strip ?= $(shell which wasm-strip 2>/dev/null) ifeq (,$(filter clean,$(MAKECMDGOALS))) ifeq (,$(wasm-strip)) @@ -226,10 +242,11 @@ $$(bin.c-pp) -f $(1) -o $$@ $(3) CLEAN_FILES += $(2) endef c-pp.D.vanilla ?= c-pp.D.esm ?= -Dtarget=es6-module +c-pp.D.bundler-friendly ?= -Dtarget=es6-module -Dtarget=es6-bundler-friendly # /end C-PP.FILTER ######################################################################## # cflags.common = C compiler flags for all builds @@ -353,13 +370,15 @@ # and because it might be a useful point of experimentation for some # clients, but the above-described caveat may well make them unusable # for real-life clients. sqlite3-api.js := $(dir.dout)/sqlite3-api.js sqlite3-api.mjs := $(dir.dout)/sqlite3-api.mjs +sqlite3-api-bundler-friendly.mjs := $(dir.dout)/sqlite3-api-bundler-friendly.mjs $(eval $(call C-PP.FILTER, $(sqlite3-api.js.in), $(sqlite3-api.js))) $(eval $(call C-PP.FILTER, $(sqlite3-api.js.in), $(sqlite3-api.mjs), $(c-pp.D.esm))) -all: $(sqlite3-api.js) $(sqlite3-api.mjs) +$(eval $(call C-PP.FILTER, $(sqlite3-api.js.in), $(sqlite3-api-bundler-friendly.mjs), $(c-pp.D.bundler-friendly))) +all: $(sqlite3-api.js) $(sqlite3-api.mjs) $(sqlite3-api-bundler-friendly.mjs) $(sqlite3-api-build-version.js): $(bin.version-info) $(MAKEFILE) @echo "Making $@..." @{ \ echo 'self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){'; \ @@ -372,11 +391,11 @@ $(MAKEFILE) @echo "Making $@..."; { \ cat $(sqlite3-license-version-header.js); \ echo '/*'; \ echo '** This code was built from sqlite3 version...'; \ - echo "** "; \ + echo "**"; \ awk -e '/define SQLITE_VERSION/{$$1=""; print "**" $$0}' \ -e '/define SQLITE_SOURCE_ID/{$$1=""; print "**" $$0}' $(sqlite3.h); \ echo '*/'; \ } > $@ @@ -383,17 +402,20 @@ ######################################################################## # --post-js and --pre-js are emcc flags we use to append/prepend JS to # the generated emscripten module file. The following rules generate # various versions of those files for the vanilla and ESM builds. pre-js.js.in := $(dir.api)/pre-js.c-pp.js -pre-js.js.esm := $(dir.tmp)/pre-js.esm.js pre-js.js.vanilla := $(dir.tmp)/pre-js.vanilla.js +pre-js.js.esm := $(dir.tmp)/pre-js.esm.js +pre-js.js.bundler-friendly := $(dir.tmp)/pre-js.bundler-friendly.js $(eval $(call C-PP.FILTER,$(pre-js.js.in),$(pre-js.js.vanilla),$(c-pp.D.vanilla))) $(eval $(call C-PP.FILTER,$(pre-js.js.in),$(pre-js.js.esm),$(c-pp.D.esm))) +$(eval $(call C-PP.FILTER,$(pre-js.js.in),$(pre-js.js.bundler-friendly),$(c-pp.D.bundler-friendly))) post-js.js.in := $(dir.tmp)/post-js.c-pp.js post-js.js.vanilla := $(dir.tmp)/post-js.vanilla.js post-js.js.esm := $(dir.tmp)/post-js.esm.js +post-js.js.bundler-friendly := $(dir.tmp)/post-js.bundler-friendly.js post-jses.js := \ $(dir.api)/post-js-header.js \ $(sqlite3-api.js.in) \ $(dir.api)/post-js-footer.js $(post-js.js.in): $(post-jses.js) $(MAKEFILE) @@ -403,19 +425,22 @@ cat $$i; \ echo "/* END FILE: $$i */"; \ done > $@ $(eval $(call C-PP.FILTER,$(post-js.js.in),$(post-js.js.vanilla),$(c-pp.D.vanilla))) $(eval $(call C-PP.FILTER,$(post-js.js.in),$(post-js.js.esm),$(c-pp.D.esm))) +$(eval $(call C-PP.FILTER,$(post-js.js.in),$(post-js.js.bundler-friendly),$(c-pp.D.bundler-friendly))) # extern-post-js* and extern-pre-js* are files for use with # Emscripten's --extern-pre-js and --extern-post-js flags. These # rules make different copies for the vanilla and ESM builds. extern-post-js.js.in := $(dir.api)/extern-post-js.c-pp.js extern-post-js.js.vanilla := $(dir.tmp)/extern-post-js.vanilla.js extern-post-js.js.esm := $(dir.tmp)/extern-post-js.esm.js +extern-post-js.js.bundler-friendly := $(dir.tmp)/extern-post-js.bundler-friendly.js $(eval $(call C-PP.FILTER,$(extern-post-js.js.in),$(extern-post-js.js.vanilla),$(c-pp.D.vanilla))) $(eval $(call C-PP.FILTER,$(extern-post-js.js.in),$(extern-post-js.js.esm),$(c-pp.D.esm))) +$(eval $(call C-PP.FILTER,$(extern-post-js.js.in),$(extern-post-js.js.bundler-friendly),$(c-pp.D.bundler-friendly))) extern-pre-js.js := $(dir.api)/extern-pre-js.js # Emscripten flags for --[extern-][pre|post]-js=... for the # various builds. pre-post-common.flags := \ @@ -426,26 +451,32 @@ --extern-post-js=$(extern-post-js.js.vanilla) pre-post-common.flags.esm := \ $(pre-post-common.flags) \ --post-js=$(post-js.js.esm) \ --extern-post-js=$(extern-post-js.js.esm) +pre-post-common.flags.bundler-friendly := \ + $(pre-post-common.flags) \ + --post-js=$(post-js.js.bundler-friendly) \ + --extern-post-js=$(extern-post-js.js.bundler-friendly) # pre-post-jses.deps.* = a list of dependencies for the # --[extern-][pre/post]-js files. pre-post-jses.deps.common := $(extern-pre-js.js) $(sqlite3-license-version.js) pre-post-jses.deps.vanilla := $(pre-post-jses.deps.common) \ $(post-js.js.vanilla) $(extern-post-js.js.vanilla) pre-post-jses.deps.esm := $(pre-post-jses.deps.common) \ $(post-js.js.esm) $(extern-post-js.js.esm) +pre-post-jses.deps.bundler-friendly := $(pre-post-jses.deps.common) \ + $(post-js.js.bundler-friendly) $(extern-post-js.js.bundler-friendly) ######################################################################## # call-make-pre-js is a $(call)able which creates rules for # pre-js-$(1).js. $1 = the base name of the JS file on whose behalf -# this pre-js is for. $2 is the build mode: one of (vanilla, esm). -# This sets up --[extern-][pre/post]-js flags in -# $(pre-post-$(1).flags.$(2)) and dependencies in -# $(pre-post-$(1).deps.$(2)). +# this pre-js is for (one of: sqlite3, sqlite3-wasm). $2 is the build +# mode: one of (vanilla, esm, bundler-friendly). This sets up +# --[extern-][pre/post]-js flags in $(pre-post-$(1).flags.$(2)) and +# dependencies in $(pre-post-$(1).deps.$(2)). define call-make-pre-js pre-post-$(1).flags.$(2) ?= $$(dir.tmp)/pre-js-$(1)-$(2).js: $$(pre-js.js.$(2)) $$(MAKEFILE) cp $$(pre-js.js.$(2)) $$@ @if [ sqlite3-wasmfs = $(1) ]; then \ @@ -475,28 +506,33 @@ # emcc flags for .c/.o. emcc.cflags := emcc.cflags += -std=c99 -fPIC # -------------^^^^^^^^ we need c99 for $(sqlite3-wasm.c). emcc.cflags += -I. -I$(dir.top) - ######################################################################## # emcc flags specific to building .js/.wasm files... emcc.jsflags := -fPIC emcc.jsflags += --minify 0 emcc.jsflags += --no-entry emcc.jsflags += -sWASM_BIGINT=$(emcc.WASM_BIGINT) emcc.jsflags += -sMODULARIZE -emcc.jsflags += -sSTRICT_JS emcc.jsflags += -sDYNAMIC_EXECUTION=0 emcc.jsflags += -sNO_POLYFILL emcc.jsflags += -sEXPORTED_FUNCTIONS=@$(EXPORTED_FUNCTIONS.api) emcc.exportedRuntimeMethods := \ -sEXPORTED_RUNTIME_METHODS=wasmMemory # wasmMemory ==> required by our code for use with -sIMPORTED_MEMORY emcc.jsflags += $(emcc.exportedRuntimeMethods) emcc.jsflags += -sUSE_CLOSURE_COMPILER=0 emcc.jsflags += -sIMPORTED_MEMORY +ifeq (3.1.31,$(emcc.version)) + emcc.jsflags += -sSTRICT_JS=0 + $(warning Disabling -sSTRICT_JS for emcc $(emcc.version): \ + https://github.com/emscripten-core/emscripten/issues/18610) +else + emcc.jsflags += -sSTRICT_JS=1 +endif emcc.environment := -sENVIRONMENT=web,worker ######################################################################## # -sINITIAL_MEMORY: How much memory we need to start with is governed # at least in part by whether -sALLOW_MEMORY_GROWTH is enabled. If so, # we can start with less. If not, we need as much as we'll ever @@ -593,10 +629,11 @@ # -g3 debugging info, _huge_. ######################################################################## sqlite3.js := $(dir.dout)/sqlite3.js sqlite3.mjs := $(dir.dout)/sqlite3.mjs +sqlite3-bundler-friendly.mjs := $(dir.dout)/sqlite3-bundler-friendly.mjs # Undocumented Emscripten feature: if the target file extension is # "mjs", it defaults to ES6 module builds: # https://github.com/emscripten-core/emscripten/issues/14383 sqlite3.wasm := $(dir.dout)/sqlite3.wasm sqlite3-wasm.c := $(dir.api)/sqlite3-wasm.c @@ -605,36 +642,40 @@ # enough to the target speed requirements that the 500ms makes a # difference. Thus we build all binaries against sqlite3-wasm.c # instead of building a shared copy of sqlite3-wasm.o. $(eval $(call call-make-pre-js,sqlite3,vanilla)) $(eval $(call call-make-pre-js,sqlite3,esm)) -$(sqlite3.js) $(sqlite3.mjs): $(MAKEFILE) $(sqlite3-wasm.c) \ - $(EXPORTED_FUNCTIONS.api) +$(eval $(call call-make-pre-js,sqlite3,bundler-friendly)) +$(sqlite3.js) $(sqlite3.mjs) $(sqlite3-bundler-friendly.mjs): \ + $(MAKEFILE) $(sqlite3-wasm.c) $(EXPORTED_FUNCTIONS.api) $(sqlite3.js): $(pre-post-sqlite3.deps.vanilla) $(sqlite3.mjs): $(pre-post-sqlite3.deps.esm) +$(sqlite3-bundler-friendly.mjs): $(pre-post-sqlite3.deps.bundler-friendly) ######################################################################## # SQLITE3.xJS.RECIPE = the $(call)able recipe body for $(sqlite3.js) -# and $(sqlite3.mjs). $1 = one of (vanilla, esm). +# and $(sqlite3.mjs). $1 = one of (vanilla, esm). $2 must be 1 for +# ES6-style builds, 0 for other builds. # # Reminder for ESM builds: even if we use -sEXPORT_ES6=0, emcc _still_ # adds: # # export default $(sqlite3.js.init-func); # # when building *.mjs, which is bad because we need to export an # overwritten version of that function and cannot "export default" -# twice. Because of this, we have to sed $(sqlite3.mjs) to remove the -# _first_ instance (only) of /^export default/. +# twice. Because of this, we have to sed *.mjs to remove the _first_ +# instance (only) of /^export default/. # # Upstream RFE: # https://github.com/emscripten-core/emscripten/issues/18237 ######################################################################## # SQLITE3.xJS.EXPORT-DEFAULT is part of SQLITE3[-WASMFS].xJS.RECIPE, -# factored into a separate piece to avoid code duplication. $1 is -# the build mode: one of (vanilla, esm). +# factored into a separate piece to avoid code duplication. $1 is 1 if +# the build mode needs this workaround (esm, bundler-friendly) and 0 +# if not (vanilla). define SQLITE3.xJS.ESM-EXPORT-DEFAULT -if [ esm = $(1) ]; then \ +if [ x1 = x$(1) ]; then \ echo "Fragile workaround for an Emscripten annoyance. See SQLITE3.xJS.RECIPE."; \ sed -i -e '0,/^export default/{/^export default/d;}' $@ || exit $$?; \ if ! grep -q '^export default' $@; then \ echo "Cannot find export default." 1>&2; \ exit 1; \ @@ -645,34 +686,47 @@ @echo "Building $@ ..." $(emcc.bin) -o $@ $(emcc_opt_full) $(emcc.flags) \ $(emcc.jsflags) \ $(pre-post-sqlite3.flags.$(1)) $(emcc.flags.sqlite3.$(1)) \ $(cflags.common) $(SQLITE_OPT) $(sqlite3-wasm.c) - @$(call SQLITE3.xJS.ESM-EXPORT-DEFAULT,$(1)) + @$(call SQLITE3.xJS.ESM-EXPORT-DEFAULT,$(2)) + @if [ bundler-friendly = $(1) ]; then \ + echo "Patching sqlite3-bundler-friendly.js for sqlite3.wasm..."; \ + rm -f $(dir.dout)/sqlite3-bundler-friendly.wasm; \ + sed -i -e 's/sqlite3-bundler-friendly.wasm/sqlite3.wasm/g' $@ || exit $$?; \ + fi chmod -x $(sqlite3.wasm) $(maybe-wasm-strip) $(sqlite3.wasm) @ls -la $@ $(sqlite3.wasm) endef emcc.flags.sqlite3.vanilla := emcc.flags.sqlite3.esm := -sEXPORT_ES6 -sUSE_ES6_IMPORT_META +emcc.flags.sqlite3.bundler-friendly := $(emcc.flags.sqlite3.esm) $(sqlite3.js): - $(call SQLITE3.xJS.RECIPE,vanilla) + $(call SQLITE3.xJS.RECIPE,vanilla,0) $(sqlite3.mjs): - $(call SQLITE3.xJS.RECIPE,esm) + $(call SQLITE3.xJS.RECIPE,esm,1) +$(sqlite3-bundler-friendly.mjs): + $(call SQLITE3.xJS.RECIPE,bundler-friendly,1) ######################################################################## # We have to ensure that we do not build both $(sqlite3.js) and # $(sqlite3.mjs) in parallel because both result in the creation of # $(sqlite3.wasm). We have no(?) way to build just the .mjs file # without also building the .wasm file. i.e. we're building -# $(sqlite3.wasm) twice, but that's apparently unavoidable (and -# harmless, just a waste of build time). +# $(sqlite3.wasm) multiple times, but that's apparently unavoidable +# (and harmless, just a waste of build time). $(sqlite3.wasm): $(sqlite3.js) $(sqlite3.mjs): $(sqlite3.js) -CLEAN_FILES += $(sqlite3.js) $(sqlite3.mjs) $(sqlite3.wasm) -all: $(sqlite3.js) $(sqlite3.mjs) +$(sqlite3-bundler-friendly.mjs): $(sqlite3.mjs) +# maintenance reminder: the deps on ^^^ must all be such that they are +# never built in parallel. +CLEAN_FILES += $(sqlite3.js) $(sqlite3.mjs) $(sqlite3-bundler-friendly.mjs) \ + $(sqlite3.wasm) +all: $(sqlite3.js) $(sqlite3.mjs) $(sqlite3-bundler-friendly.mjs) quick: $(sqlite3.js) quick: $(sqlite3.mjs) # for the sake of the snapshot build +quick: $(sqlite3-bundler-friendly.mjs) # for the sake of the snapshot build # End main $(sqlite3.js) build ######################################################################## ######################################################################## # batch-runner.js is part of one of the test apps which reads in SQL @@ -778,20 +832,22 @@ # 2) Load sqlite3 in a conventional Worker thread. # 3) Load sqlite3 as an ES6 module (ESM) in the main thread. # 4) Load sqlite3 as an ESM worker. (Not all browsers support this.) # # To that end, we require two separate builds of tester1.js: -# +# # tester1.js: cases 1 and 2 # tester1.mjs: cases 3 and 4 # # To create those, we filter tester1.c-pp.js with $(bin.c-pp)... $(eval $(call C-PP.FILTER,tester1.c-pp.js,tester1.js)) $(eval $(call C-PP.FILTER,tester1.c-pp.js,tester1.mjs,$(c-pp.D.esm))) $(eval $(call C-PP.FILTER,tester1.c-pp.html,tester1.html)) $(eval $(call C-PP.FILTER,tester1.c-pp.html,tester1-esm.html,$(c-pp.D.esm))) tester1: tester1.js tester1.mjs tester1.html tester1-esm.html +# Note that we do not include $(sqlite3-bundler-friendly.mjs) in this +# because bundlers are client-specific. all quick: tester1 ######################################################################## # Convenience rules to rebuild with various -Ox levels. Much # experimentation shows -O2 to be the clear winner in terms of speed. Index: ext/wasm/README-dist.txt ================================================================== --- ext/wasm/README-dist.txt +++ ext/wasm/README-dist.txt @@ -2,22 +2,42 @@ Main project page: https://sqlite.org Documentation: https://sqlite.org/wasm -This archive contains the sqlite3.js, sqlite3.mjs, and sqlite3.wasm -files which make up the sqlite3 WASM/JS build. - -The jswasm directory contains the core sqlite3 deliverables and the -top-level directory contains demonstration and test applications. - -Browsers will not serve WASM files from file:// URLs, so the demo/test -apps require a web server and that server must include the following -headers in its response when serving the files: +This archive contains the following deliverables for the WASM/JS +build: + +- jswasm/sqlite3.js is the canonical "vanilla JS" version. + +- jswasm/sqlite3.mjs is the same but in ES6 module form + +- jswasm/sqlite3-bundler-friendly.mjs is the same as the ES6 module + with small tweaks to make it compatible with "bundler" tools + commonly seen in node.js-based projects. + +- jswasm/sqlite3.wasm is the binary WASM file imported by all of the + above-listed JS files. + +- The jswasm directory additionally contains a number of supplemental + JS files which cannot be bundled directly with the main JS files + but are necessary for certain usages. + +- The top-level directory contains various demonstration and test + applications for sqlite3.js and sqlite3.mjs. + sqlite3-bundler-friendly.mjs requires client-side build tools to make + use of and is not demonstrated here. + +Browsers will not serve WASM files from file:// URLs, so the test and +demonstration apps require a web server and that server must include +the following headers in its response when serving the files: Cross-Origin-Opener-Policy: same-origin Cross-Origin-Embedder-Policy: require-corp + +The core library will function without those headers but certain +features, most notably OPFS storage, will not be available. One simple way to get the demo apps up and running on Unix-style systems is to install althttpd (https://sqlite.org/althttpd) and run: althttpd --enable-sab --page index.html Index: ext/wasm/api/extern-post-js.c-pp.js ================================================================== --- ext/wasm/api/extern-post-js.c-pp.js +++ ext/wasm/api/extern-post-js.c-pp.js @@ -43,18 +43,27 @@ */ const initModuleState = self.sqlite3InitModuleState = Object.assign(Object.create(null),{ moduleScript: self?.document?.currentScript, isWorker: ('undefined' !== typeof WorkerGlobalScope), location: self.location, - urlParams: new URL(self.location.href).searchParams + urlParams: +//#if target=es6-bundler-friendly + undefined +//#else + new URL(self.location.href).searchParams +//#endif }); initModuleState.debugModule = - (new URL(self.location.href).searchParams).has('sqlite3.debugModule') +//#if target=es6-bundler-friendly + ()=>{} +//#else + (new URL(self.location.href).searchParams).has('sqlite3.debugModule') ? (...args)=>console.warn('sqlite3.debugModule:',...args) : ()=>{}; +//#endif - if(initModuleState.urlParams.has('sqlite3.dir')){ + if(initModuleState.urlParams && initModuleState.urlParams.has('sqlite3.dir')){ initModuleState.sqlite3Dir = initModuleState.urlParams.get('sqlite3.dir') +'/'; }else if(initModuleState.moduleScript){ const li = initModuleState.moduleScript.src.split('/'); li.pop(); initModuleState.sqlite3Dir = li.join('/') + '/'; @@ -103,19 +112,24 @@ if('undefined' !== typeof document){ console.warn("document.currentScript.src =", document?.currentScript?.src); } } +//#ifnot target=es6-module +// Emscripten does not inject these module-loader bits in ES6 module +// build and including them here breaks JS bundlers, so elide them +// from ES6 builds. /* Replace the various module exports performed by the Emscripten glue... */ if (typeof exports === 'object' && typeof module === 'object'){ module.exports = sqlite3InitModule; }else if (typeof exports === 'object'){ exports["sqlite3InitModule"] = sqlite3InitModule; } /* AMD modules get injected in a way we cannot override, so we can't handle those here. */ +//#endif // !target=es6-module return self.sqlite3InitModule /* required for ESM */; })(); //#if target=es6-module export default toExportForES6; //#endif Index: ext/wasm/api/pre-js.c-pp.js ================================================================== --- ext/wasm/api/pre-js.c-pp.js +++ ext/wasm/api/pre-js.c-pp.js @@ -4,14 +4,18 @@ This file is intended to be prepended to the sqlite3.js build using Emscripten's --pre-js=THIS_FILE flag (or equivalent). */ // See notes in extern-post-js.js -const sqlite3InitModuleState = self.sqlite3InitModuleState || Object.create(null); +const sqlite3InitModuleState = self.sqlite3InitModuleState + || Object.assign(Object.create(null),{ + debugModule: ()=>{} + }); delete self.sqlite3InitModuleState; sqlite3InitModuleState.debugModule('self.location =',self.location); +//#ifnot target=es6-bundler-friendly /** This custom locateFile() tries to figure out where to load `path` from. The intent is to provide a way for foo/bar/X.js loaded from a Worker constructor or importScripts() to be able to resolve foo/bar/X.wasm (in the latter case, with some help): @@ -49,22 +53,23 @@ 'sqlite3InitModuleState.scriptDir =',this.scriptDir, 'up.entries() =',Array.from(up.entries()), "result =", theFile ); return theFile; -//#endif /* SQLITE_JS_EMS */ +//#endif //target=es6-module }.bind(sqlite3InitModuleState); +//#endif //ifnot target=es6-bundler-friendly /** Bug warning: a custom Module.instantiateWasm() does not work in WASMFS builds: https://github.com/emscripten-core/emscripten/issues/17951 In such builds we must disable this. */ -const xNameOfInstantiateWasm = true +const xNameOfInstantiateWasm = false ? 'instantiateWasm' : 'emscripten-bug-17951'; Module[xNameOfInstantiateWasm] = function callee(imports,onSuccess){ imports.env.foo = function(){}; const uri = Module.locateFile( Index: ext/wasm/api/sqlite3-api-oo1.js ================================================================== --- ext/wasm/api/sqlite3-api-oo1.js +++ ext/wasm/api/sqlite3-api-oo1.js @@ -181,11 +181,11 @@ postInitSql(this, sqlite3); }else if(postInitSql){ checkSqlite3Rc( pDb, capi.sqlite3_exec(pDb, postInitSql, 0, 0, 0) ); - } + } }catch(e){ this.close(); throw e; } }; @@ -788,10 +788,13 @@ parameters (as it does now). The 2nd would act on the next such statement, etc. - `callback` and `resultRows`: permit an array entries with semantics similar to those described for `bind` above. + + - If passed neither a callback nor returnValue but is passed a + rowMode, default to returning the result set. */ exec: function(/*(sql [,obj]) || (obj)*/){ affirmDbOpen(this); const arg = parseExecArgs(this, arguments); Index: ext/wasm/api/sqlite3-api-worker1.js ================================================================== --- ext/wasm/api/sqlite3-api-worker1.js +++ ext/wasm/api/sqlite3-api-worker1.js @@ -1,6 +1,6 @@ -/* +/** 2022-07-22 The author disclaims copyright to this source code. In place of a legal notice, here is a blessing: @@ -8,16 +8,16 @@ * May you find forgiveness for yourself and forgive others. * May you share freely, never taking more than you give. *********************************************************************** - This file implements the initializer for the sqlite3 "Worker API - #1", a very basic DB access API intended to be scripted from a main - window thread via Worker-style messages. Because of limitations in - that type of communication, this API is minimalistic and only - capable of serving relatively basic DB requests (e.g. it cannot - process nested query loops concurrently). + This file implements the initializer for SQLite's "Worker API #1", a + very basic DB access API intended to be scripted from a main window + thread via Worker-style messages. Because of limitations in that + type of communication, this API is minimalistic and only capable of + serving relatively basic DB requests (e.g. it cannot process nested + query loops concurrently). This file requires that the core C-style sqlite3 API and OO API #1 have been loaded. */ Index: ext/wasm/api/sqlite3-vfs-opfs.c-pp.js ================================================================== --- ext/wasm/api/sqlite3-vfs-opfs.c-pp.js +++ ext/wasm/api/sqlite3-vfs-opfs.c-pp.js @@ -98,17 +98,24 @@ ); } if(!options || 'object'!==typeof options){ options = Object.create(null); } - const urlParams = new URL(self.location.href).searchParams; - if(undefined===options.verbose){ - options.verbose = urlParams.has('opfs-verbose') - ? (+urlParams.get('opfs-verbose') || 2) : 1; - } - if(undefined===options.sanityChecks){ - options.sanityChecks = urlParams.has('opfs-sanity-check'); + const urlParams = +//#if target=es6-bundler-friendly + undefined; +//#else + new URL(self.location.href).searchParams; +//#endif + if(urlParams){ + if(undefined===options.verbose){ + options.verbose = urlParams.has('opfs-verbose') + ? (+urlParams.get('opfs-verbose') || 2) : 1; + } + if(undefined===options.sanityChecks){ + options.sanityChecks = urlParams.has('opfs-sanity-check'); + } } if(undefined===options.proxyUri){ options.proxyUri = callee.defaultProxyUri; } @@ -196,11 +203,13 @@ const promiseReject = function(err){ opfsVfs.dispose(); return promiseReject_(err); }; const W = -//#if target=es6-module +//#if target=es6-bundler-friendly + new Worker(new URL("sqlite3-opfs-async-proxy.js", import.meta.url)); +//#elif target=es6-module new Worker(new URL(options.proxyUri, import.meta.url)); //#else new Worker(options.proxyUri); //#endif W._originalOnError = W.onerror /* will be restored later */; Index: ext/wasm/api/sqlite3-worker1-promiser.js ================================================================== --- ext/wasm/api/sqlite3-worker1-promiser.js +++ ext/wasm/api/sqlite3-worker1-promiser.js @@ -236,10 +236,13 @@ return p; }; }/*sqlite3Worker1Promiser()*/; self.sqlite3Worker1Promiser.defaultConfig = { worker: function(){ +//#if target=es6-bundler-friendly + return new Worker("sqlite3-worker1.js"); +//#else let theJs = "sqlite3-worker1.js"; if(this.currentScript){ const src = this.currentScript.src.split('/'); src.pop(); theJs = src.join('/')+'/' + theJs; @@ -250,10 +253,11 @@ if(urlParams.has('sqlite3.dir')){ theJs = urlParams.get('sqlite3.dir') + '/' + theJs; } } return new Worker(theJs + self.location.search); +//#endif }.bind({ currentScript: self?.document?.currentScript }), onerror: (...args)=>console.error('worker1 promiser error',...args) }; Index: ext/wasm/api/sqlite3-worker1.js ================================================================== --- ext/wasm/api/sqlite3-worker1.js +++ ext/wasm/api/sqlite3-worker1.js @@ -31,16 +31,20 @@ - `sqlite3.dir`, if set, treats the given directory name as the directory from which `sqlite3.js` will be loaded. */ "use strict"; (()=>{ +//#if target=es6-bundler-friendly + importScripts('sqlite3.js'); +//#else const urlParams = new URL(self.location.href).searchParams; let theJs = 'sqlite3.js'; if(urlParams.has('sqlite3.dir')){ theJs = urlParams.get('sqlite3.dir') + '/' + theJs; } //console.warn("worker1 theJs =",theJs); importScripts(theJs); +//#endif sqlite3InitModule().then((sqlite3)=>{ sqlite3.initWorker1API(); }); })(); Index: ext/wasm/c-pp.c ================================================================== --- ext/wasm/c-pp.c +++ ext/wasm/c-pp.c @@ -49,14 +49,14 @@ ** This preprocessor does no expansion of content except within the ** bounds of its `#keywords`. ** ** Design note: this code makes use of sqlite3. Though not _strictly_ ** needed in order to implement it, this tool was specifically created -** for potential use with the sqlite3 project's own JavaScript code, -** so there's no reason not to make use of it to do some of the heavy -** lifting. It does not require any cutting-edge sqlite3 features and -** should be usable with any version which supports `WITHOUT ROWID`. +** for use with the sqlite3 project's own JavaScript code, so there's +** no reason not to make use of it to do some of the heavy lifting. It +** does not require any cutting-edge sqlite3 features and should be +** usable with any version which supports `WITHOUT ROWID`. ** ** Author(s): ** ** - Stephan Beal */ @@ -601,22 +601,13 @@ va_start(va, zFmt); g_stderrv(zFmt, va); va_end(va); } -#if 0 -void cmpp_t_outf(CmppTokenizer * t, char const *zFmt, ...){ - if(!CT_skip(t)){ - va_list va; - va_start(va, zFmt); - vfprintf(g.out.pFile, zFmt, va); - va_end(va); - } -} -#endif - void cmpp_t_out(CmppTokenizer * t, void const *z, unsigned int n){ + g_debug(3,("CT_skipLevel() ?= %d\n",CT_skipLevel(t))); + g_debug(3,("CT_skip() ?= %d\n",CT_skip(t))); if(!CT_skip(t)){ if(1!=fwrite(z, n, 1, g.out.pFile)){ int const err = errno; fatal("fwrite() output failed with errno #%d", err); } @@ -629,22 +620,32 @@ if(t->level.ndx+1 == (unsigned)CmppLevel_Max){ fatal("%sif nesting level is too deep. Max=%d\n", g.zDelim, CmppLevel_Max); } pPrev = &CT_level(t); + g_debug(3,("push from tokenizer level=%u flags=%04x\n", t->level.ndx, pPrev->flags)); p = &t->level.stack[++t->level.ndx]; *p = CmppLevel_empty; p->token = t->token; p->flags = (CmppLevel_F_INHERIT_MASK & pPrev->flags); if(CLvl_skip(pPrev)) p->flags |= CmppLevel_F_ELIDE; + g_debug(3,("push to tokenizer level=%u flags=%04x\n", t->level.ndx, p->flags)); } void CmppLevel_pop(CmppTokenizer * const t){ if(!t->level.ndx){ fatal("Internal error: CmppLevel_pop() at the top of the stack"); } + g_debug(3,("pop from tokenizer level=%u, flags=%04x skipLevel?=%d\n", t->level.ndx, + t->level.stack[t->level.ndx].flags, CT_skipLevel(t))); + g_debug(3,("CT_skipLevel() ?= %d\n",CT_skipLevel(t))); + g_debug(3,("CT_skip() ?= %d\n",CT_skip(t))); t->level.stack[t->level.ndx--] = CmppLevel_empty; + g_debug(3,("pop to tokenizer level=%u, flags=%04x\n", t->level.ndx, + t->level.stack[t->level.ndx].flags)); + g_debug(3,("CT_skipLevel() ?= %d\n",CT_skipLevel(t))); + g_debug(3,("CT_skip() ?= %d\n",CT_skip(t))); } CmppLevel * CmppLevel_get(CmppTokenizer * const t){ return &t->level.stack[t->level.ndx]; } @@ -774,11 +775,11 @@ rc = 1; }else{ assert(SQLITE_DONE==rc); rc = 0; } - g_debug(1,("define has [%s] = %d\n",zName, rc)); + g_debug(1,("defined [%s] ?= %d\n",zName, rc)); sqlite3_clear_bindings(g.stmt.defHas); sqlite3_reset(g.stmt.defHas); return rc; } @@ -1218,14 +1219,15 @@ } buul = db_define_has((char const *)t->args.argv[1]); if(TT_IfNot==pKw->ttype || TT_ElifNot==pKw->ttype) buul = !buul; if(buul){ CT_pstate(t) = tmpState = TS_IfPassed; - CT_skipLevel(t) = 0; + CT_skipLevel(t) = 0; }else{ CT_pstate(t) = TS_If /* also for TT_IfNot, TT_Elif, TT_ElifNot */; CT_skipLevel(t) = 1; + g_debug(3,("setting CT_skipLevel = 1 @ level %d\n", t->level.ndx)); } if(TT_If==pKw->ttype || TT_IfNot==pKw->ttype){ unsigned const lvlIf = t->level.ndx; CmppToken const lvlToken = CT_level(t).token; while(cmpp_next_keyword_line(t)){ @@ -1232,14 +1234,17 @@ cmpp_process_keyword(t); if(lvlIf > t->level.ndx){ assert(TT_EndIf == t->token.ttype); break; } +#if 0 if(TS_IfPassed==tmpState){ tmpState = TS_Start; t->level.stack[lvlIf].flags |= CmppLevel_F_ELIDE; + g_debug(1,("Setting ELIDE for TS_IfPassed @ lv %d (lvlIf=%d)\n", t->level.ndx, lvlIf)); } +#endif } if(lvlIf <= t->level.ndx){ cmpp_kwd__err_prefix(pKw, t, NULL); fatal("Input ended inside an unterminated %sif " "opened at [%s] line %u", Index: ext/wasm/dist.make ================================================================== --- ext/wasm/dist.make +++ ext/wasm/dist.make @@ -82,10 +82,12 @@ @cp -p $(dist.jswasm.extras) $(dist-dir.jswasm) @$(bin.stripccomments) -k -k < $(sqlite3.js) \ > $(dist-dir.jswasm)/$(notdir $(sqlite3.js)) @$(bin.stripccomments) -k -k < $(sqlite3.mjs) \ > $(dist-dir.jswasm)/$(notdir $(sqlite3.mjs)) + @$(bin.stripccomments) -k -k < $(sqlite3-bundler-friendly.mjs) \ + > $(dist-dir.jswasm)/$(notdir $(sqlite3-bundler-friendly.mjs)) @cp -p $(dist.common.extras) $(dist-dir.common) @set -e; \ vnum=$$($(bin.version-info) --download-version); \ vdir=$(dist-name-prefix)-$$vnum; \ arczip=$$vdir.zip; \