aboutsummaryrefslogtreecommitdiff
path: root/ext/wasm
diff options
context:
space:
mode:
Diffstat (limited to 'ext/wasm')
-rw-r--r--ext/wasm/GNUmakefile339
-rw-r--r--ext/wasm/api/sqlite3-api-oo1.c-pp.js331
-rw-r--r--ext/wasm/api/sqlite3-api-worker1.c-pp.js13
-rw-r--r--ext/wasm/api/sqlite3-wasm.c1
-rw-r--r--ext/wasm/api/sqlite3-worker1-promiser.c-pp.js19
-rw-r--r--ext/wasm/common/whwasmutil.js32
-rw-r--r--ext/wasm/config.make.in13
-rw-r--r--ext/wasm/dist.make32
-rw-r--r--ext/wasm/fiddle.make45
-rw-r--r--ext/wasm/fiddle/fiddle-worker.js9
-rw-r--r--ext/wasm/fiddle/fiddle.js60
-rw-r--r--ext/wasm/fiddle/index.html89
-rw-r--r--ext/wasm/mkwasmbuilds.c347
-rw-r--r--ext/wasm/speedtest1.html7
-rw-r--r--ext/wasm/tester1.c-pp.js106
-rw-r--r--ext/wasm/wasmfs.make46
16 files changed, 964 insertions, 525 deletions
diff --git a/ext/wasm/GNUmakefile b/ext/wasm/GNUmakefile
index 0ae814c2d..5cd0aa66a 100644
--- a/ext/wasm/GNUmakefile
+++ b/ext/wasm/GNUmakefile
@@ -39,10 +39,11 @@
########################################################################
default: all
#default: quick
-MAKEFILE := $(lastword $(MAKEFILE_LIST))
-CLEAN_FILES :=
-DISTCLEAN_FILES := config.make
-MAKING_CLEAN := $(if $(filter %clean,$(MAKECMDGOALS)),1,0)
+MAKEFILE = $(lastword $(MAKEFILE_LIST))
+MAKEFILE.fiddle = fiddle.make
+CLEAN_FILES =
+DISTCLEAN_FILES = config.make
+MAKING_CLEAN = $(if $(filter %clean,$(MAKECMDGOALS)),1,0)
.PHONY: clean distclean
clean:
-rm -f $(CLEAN_FILES)
@@ -53,17 +54,17 @@ distclean: clean
########################################################################
# Special-case builds for which we require certain pre-conditions
# which, if not met, may cause warnings or fatal errors in the build.
-# This also affects the default optimization level flags. Note that
-# the fiddle targets are in this list because they are used for
-# generating sqlite.org/fiddle.
-OPTIMIZED_TARGETS := dist snapshot fiddle fiddle.debug
+# This also affects the default optimization level flags. The fiddle
+# targets are in this list because they are used for generating
+# sqlite.org/fiddle.
+OPTIMIZED_TARGETS = dist snapshot fiddle fiddle.debug
ifeq (1,$(MAKING_CLEAN))
- bin.wasm-strip := echo "not stripping"
- bin.wasm-opt := irrelevant
- bin.emcc := irrelevant
- bin.bash := irrelevant
- emcc.version := unknown
+ bin.wasm-strip = echo "not stripping"
+ bin.wasm-opt = irrelevant
+ bin.emcc = irrelevant
+ bin.bash = irrelevant
+ emcc.version = unknown
else
# Include config.make and perform some bootstrapping...
ifeq (,$(wildcard ./config.make))
@@ -76,7 +77,7 @@ else
ifeq (,$(bin.emcc))
$(error Configure script did not find emcc)
endif
- emcc.version := $(shell $(bin.emcc) --version | sed -n 1p | sed -e 's/^.* \([3-9][^ ]*\) .*$$/\1/;')
+ emcc.version = $(shell $(bin.emcc) --version | sed -n 1p | sed -e 's/^.* \([3-9][^ ]*\) .*$$/\1/;')
$(info using emcc version [$(emcc.version)])
ifeq (,$(bin.wasm-strip))
####################################################################
@@ -98,7 +99,7 @@ else
ifneq (,$(filter $(OPTIMIZED_TARGETS),$(MAKECMDGOALS)))
$(error Cannot make release-quality binary because wasm-strip is not available.)
endif
- bin.wasm-strip := echo "not wasm-stripping"
+ bin.wasm-strip = echo "not wasm-stripping"
endif
ifeq (,$(filter $(OPTIMIZED_TARGETS),$(MAKECMDGOALS)))
$(info ==============================================================)
@@ -108,7 +109,7 @@ else
endif
endif
# ^^^ end of are-we-MAKING_CLEAN
-maybe-wasm-strip := $(bin.wasm-strip)
+maybe-wasm-strip = $(bin.wasm-strip)
########################################################################
# JS_BUILD_NAMES exists for documentation purposes only. It enumerates
@@ -118,7 +119,7 @@ maybe-wasm-strip := $(bin.wasm-strip)
#
# - sqlite3-wasmfs = WASMFS-capable library build
#
-JS_BUILD_NAMES := sqlite3 sqlite3-wasmfs
+JS_BUILD_NAMES = sqlite3 sqlite3-wasmfs
########################################################################
# JS_BUILD_MODES exists for documentation purposes only. It enumerates
@@ -140,31 +141,31 @@ JS_BUILD_NAMES := sqlite3 sqlite3-wasmfs
# that persistent storage (OPFS) is not available in these builds.
# These builds are UNTESTED and UNSUPPORTED!
#
-JS_BUILD_MODES := vanilla esm bunder-friendly node
+JS_BUILD_MODES = vanilla esm bunder-friendly node
########################################################################
# dir.top = the top dir of the canonical build tree, where
# sqlite3.[ch] live.
-dir.top := ../..
+dir.top = ../..
# Maintenance reminder: some Emscripten flags require absolute paths
# but we want relative paths for most stuff simply to reduce
# noise. The $(abspath...) GNU make function can transform relative
# paths to absolute.
-dir.wasm := $(patsubst %/,%,$(dir $(MAKEFILE)))
-dir.api := api
-dir.jacc := jaccwabyt
-dir.common := common
-dir.fiddle := fiddle
-dir.fiddle-debug := fiddle-debug
-dir.tool := $(dir.top)/tool
+dir.wasm = $(patsubst %/,%,$(dir $(MAKEFILE)))
+dir.api = api
+dir.jacc = jaccwabyt
+dir.common = common
+dir.fiddle = fiddle
+dir.fiddle-debug = fiddle-debug
+dir.tool = $(dir.top)/tool
# dir.dout = output dir for deliverables
-dir.dout := $(dir.wasm)/jswasm
+dir.dout = $(dir.wasm)/jswasm
# dir.tmp = output dir for intermediary build files, as opposed to
# end-user deliverables.
-dir.tmp := $(dir.wasm)/bld
-dir.wasmfs := $(dir.dout)
+dir.tmp = $(dir.wasm)/bld
+dir.wasmfs = $(dir.dout)
-MKDIR.bld := $(dir.tmp)
+MKDIR.bld = $(dir.tmp)
$(MKDIR.bld):
@mkdir -p $@ $(dir.dout)
@@ -188,17 +189,17 @@ CLEAN_FILES += *~ $(dir.jacc)/*~ $(dir.api)/*~ $(dir.common)/*~ $(dir.fiddle)/*~
# $(sqlite3.canonical.c) must point to the sqlite3.c in
# the sqlite3 canonical source tree, as that source file
# is required for certain utility and test code.
-sqlite3.canonical.c := $(dir.top)/sqlite3.c
+sqlite3.canonical.c = $(dir.top)/sqlite3.c
sqlite3.c ?= $(firstword $(wildcard $(dir.top)/sqlite3-see.c) $(sqlite3.canonical.c))
-sqlite3.h := $(dir.top)/sqlite3.h
+sqlite3.h = $(dir.top)/sqlite3.h
ifeq (1,$(MAKING_CLEAN))
- SQLITE_C_IS_SEE := 0
+ SQLITE_C_IS_SEE = 0
else
ifeq (,$(shell grep sqlite3_activate_see $(sqlite3.c)))
- SQLITE_C_IS_SEE := 0
+ SQLITE_C_IS_SEE = 0
else
- SQLITE_C_IS_SEE := 1
+ SQLITE_C_IS_SEE = 1
$(info This is an SEE build)
endif
endif
@@ -216,19 +217,19 @@ $(sqlite3.c): $(sqlite3.h)
# barebones=1 disables all "extraneous" stuff from sqlite3-wasm.c, the
# goal being to create a WASM file with only the core APIs.
ifeq (1,$(barebones))
- wasm-bare-bones := 1
+ wasm-bare-bones = 1
$(info ==============================================================)
$(info == This is a bare-bones build. It trades away features for)
$(info == a smaller .wasm file.)
$(info ==============================================================)
else
- wasm-bare-bones := 0
+ wasm-bare-bones = 0
endif
# undefine barebones # relatively new gmake feature, not ubiquitous
# Common options for building sqlite3-wasm.c and speedtest1.c.
# Explicit ENABLEs...
-SQLITE_OPT.common := \
+SQLITE_OPT.common = \
-DSQLITE_THREADSAFE=0 \
-DSQLITE_TEMP_STORE=2 \
-DSQLITE_ENABLE_MATH_FUNCTIONS \
@@ -249,7 +250,7 @@ SQLITE_OPT.common := \
SQLITE_OPT.common += -DSQLITE_WASM_ENABLE_C_TESTS
# Extra flags for full-featured builds...
-SQLITE_OPT.full-featured := \
+SQLITE_OPT.full-featured = \
-DSQLITE_ENABLE_BYTECODE_VTAB \
-DSQLITE_ENABLE_DBPAGE_VTAB \
-DSQLITE_ENABLE_DBSTAT_VTAB \
@@ -265,12 +266,12 @@ SQLITE_OPT.full-featured := \
ifeq (0,$(wasm-bare-bones))
# The so-called canonical build is full-featured:
- SQLITE_OPT := \
+ SQLITE_OPT = \
$(SQLITE_OPT.common) \
$(SQLITE_OPT.full-featured)
else
# The so-called bare-bones build is exactly that:
- SQLITE_OPT := \
+ SQLITE_OPT = \
$(SQLITE_OPT.common) \
-DSQLITE_WASM_BARE_BONES
# SQLITE_WASM_BARE_BONES tells sqlite3-wasm.c to explicitly omit
@@ -345,10 +346,10 @@ endif
# See example_extra_init.c for an example implementation.
########################################################################
sqlite3_wasm_extra_init.c ?= $(wildcard sqlite3_wasm_extra_init.c)
-cflags.wasm_extra_init :=
+cflags.wasm_extra_init =
ifneq (,$(sqlite3_wasm_extra_init.c))
$(info Enabling SQLITE_EXTRA_INIT via $(sqlite3_wasm_extra_init.c).)
- cflags.wasm_extra_init := -DSQLITE_WASM_EXTRA_INIT
+ cflags.wasm_extra_init = -DSQLITE_WASM_EXTRA_INIT
endif
#########################################################################
@@ -362,7 +363,7 @@ endif
# end result is that the generated JS files may have static version
# info from $(bin.version-info) which differ from their runtime-emitted
# version info (e.g. from sqlite3_libversion()).
-bin.version-info := $(dir.top)/version-info
+bin.version-info = $(dir.top)/version-info
.NOTPARALLEL: $(bin.version-info)
$(bin.version-info): $(dir.tool)/version-info.c $(sqlite3.h) $(dir.top)/Makefile
$(MAKE) -C $(dir.top) version-info
@@ -373,7 +374,7 @@ $(bin.version-info): $(dir.tool)/version-info.c $(sqlite3.h) $(dir.top)/Makefile
# don't need for all builds. That app's -k flag is of particular
# importance here, as it allows us to retain the opening comment
# block(s), which contain the license header and version info.
-bin.stripccomments := $(dir.tool)/stripccomments
+bin.stripccomments = $(dir.tool)/stripccomments
$(bin.stripccomments): $(bin.stripccomments).c $(MAKEFILE)
$(CC) -o $@ $<
DISTCLEAN_FILES += $(bin.stripccomments)
@@ -410,7 +411,7 @@ DISTCLEAN_FILES += $(bin.stripccomments)
#
# -D... flags which should be included in all invocations should be
# appended to $(SQLITE.CALL.C-PP.FILTER.global).
-bin.c-pp := ./c-pp
+bin.c-pp = ./c-pp
$(bin.c-pp): c-pp.c $(sqlite3.c) # $(MAKEFILE)
$(CC) -O0 -o $@ c-pp.c $(sqlite3.c) '-DCMPP_DEFAULT_DELIM="//#"' -I$(dir.top) \
-DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_UTF16 \
@@ -429,13 +430,13 @@ define SQLITE.CALL.C-PP.FILTER
$(2): $(1) $$(MAKEFILE_LIST) $$(bin.c-pp)
@mkdir -p $$(dir $$@)
$$(bin.c-pp) -f $(1) -o $$@ $(3) $(SQLITE.CALL.C-PP.FILTER.global)
-#CLEAN_FILES += $(2)
+CLEAN_FILES += $(2)
endef
# /end SQLITE.CALL.C-PP.FILTER
########################################################################
# cflags.common = C compiler flags for all builds
-cflags.common := -I. -I$(dir $(sqlite3.c))
+cflags.common = -I. -I$(dir $(sqlite3.c))
# emcc.WASM_BIGINT = 1 for BigInt (C int64) support, else 0. The API
# disables certain features if BigInt is not enabled and such builds
# _are not tested_ on any regular basis.
@@ -456,9 +457,24 @@ else
emcc_opt ?= -Oz
endif
+# Our JS code installs bindings of each sqlite3_...() WASM export. The
+# generated Emscripten JS file does the same using its own framework,
+# but we don't use those results and can speed up lib init, and reduce
+# memory cost a bit, by stripping them out. Emscripten-side changes
+# can "break" this, causing this to be a no-op, but the worst that can
+# happen in that case is that it doesn't actually strip anything,
+# leading to slightly larger JS files.
+#
+# This snippet is intended to be used in makefile targets which
+# generate an Emscripten module and where $@ is the module's .js/.mjs
+# file.
+SQLITE.strip-createExportWrapper = \
+ sed -i -e '/^.*= \(_sqlite3\|_fiddle\)[^=]* = createExportWrapper/d' $@ || exit; \
+ echo '(Probably) stripped out extraneous createExportWrapper() parts.'
+
# When passing emcc_opt from the CLI, += and re-assignment have no
# effect, so emcc_opt+=-g3 doesn't work. So...
-emcc_opt_full := $(emcc_opt) -g3
+emcc_opt_full = $(emcc_opt) -g3
# ^^^ ALWAYS use -g3. See below for why.
#
# ^^^ -flto improves runtime speed at -O0 considerably but doubles
@@ -489,31 +505,28 @@ emcc_opt_full := $(emcc_opt) -g3
########################################################################
# EXPORTED_FUNCTIONS.* = files for use with Emscripten's
# -sEXPORTED_FUNCTION flag.
-EXPORTED_FUNCTIONS.api.core := $(dir.api)/EXPORTED_FUNCTIONS.sqlite3-core
-EXPORTED_FUNCTIONS.api.in := $(EXPORTED_FUNCTIONS.api.core)
+EXPORTED_FUNCTIONS.api.core = $(dir.api)/EXPORTED_FUNCTIONS.sqlite3-core
+EXPORTED_FUNCTIONS.api.in = $(EXPORTED_FUNCTIONS.api.core)
ifeq (1,$(SQLITE_C_IS_SEE))
EXPORTED_FUNCTIONS.api.in += $(dir.api)/EXPORTED_FUNCTIONS.sqlite3-see
endif
ifeq (0,$(wasm-bare-bones))
EXPORTED_FUNCTIONS.api.in += $(dir.api)/EXPORTED_FUNCTIONS.sqlite3-extras
endif
-EXPORTED_FUNCTIONS.api := $(dir.tmp)/EXPORTED_FUNCTIONS.api
+EXPORTED_FUNCTIONS.api = $(dir.tmp)/EXPORTED_FUNCTIONS.api
$(EXPORTED_FUNCTIONS.api): $(MKDIR.bld) $(EXPORTED_FUNCTIONS.api.in) $(sqlite3.c) $(MAKEFILE)
cat $(EXPORTED_FUNCTIONS.api.in) > $@
########################################################################
# sqlite3-license-version.js = generated JS file with the license
# header and version info.
-sqlite3-license-version.js := $(dir.tmp)/sqlite3-license-version.js
-# sqlite3-license-version-header.js = JS file containing only the
-# license header.
-sqlite3-license-version-header.js := $(dir.api)/sqlite3-license-version-header.js
+sqlite3-license-version.js = $(dir.tmp)/sqlite3-license-version.js
# sqlite3-api-build-version.js = generated JS file which populates the
# sqlite3.version object using $(bin.version-info).
-sqlite3-api-build-version.js := $(dir.tmp)/sqlite3-api-build-version.js
+sqlite3-api-build-version.js = $(dir.tmp)/sqlite3-api-build-version.js
# sqlite3-api.jses = the list of JS files which make up
# $(sqlite3-api.js.in), in the order they need to be assembled.
-sqlite3-api.jses := $(sqlite3-license-version.js)
+sqlite3-api.jses = $(sqlite3-license-version.js)
# sqlite3-api-prologue.js: initial bootstrapping bits:
sqlite3-api.jses += $(dir.api)/sqlite3-api-prologue.js
# whwhasm.js and jaccwabyt.js: Low-level utils, mostly replacing
@@ -547,13 +560,13 @@ sqlite3-api.jses += $(dir.api)/sqlite3-api-cleanup.js
# SOAP.js is an external API file which is part of our distribution
# but not part of the sqlite3-api.js amalgamation. It's a component of
# the first OPFS VFS and necessarily an external file.
-SOAP.js := $(dir.api)/sqlite3-opfs-async-proxy.js
-SOAP.js.bld := $(dir.dout)/$(notdir $(SOAP.js))
+SOAP.js = $(dir.api)/sqlite3-opfs-async-proxy.js
+SOAP.js.bld = $(dir.dout)/$(notdir $(SOAP.js))
#
# $(sqlite3-api.ext.jses) = API-related files which are standalone files,
# not part of the amalgamation.
#
-sqlite3-api.ext.jses := $(SOAP.js.bld)
+sqlite3-api.ext.jses = $(SOAP.js.bld)
$(SOAP.js.bld): $(SOAP.js)
cp $< $@
@@ -573,17 +586,12 @@ $(SOAP.js.bld): $(SOAP.js)
# Sidebar: some of the imports are used soley by the Emscripten glue,
# which the sqlite3 JS code does not rely on.
#
-# We build $(sqlite3-api*.*) "because we can" 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.in = the generated sqlite3-api.js before it gets
+# sqlite3-api.js.in = the amalgamated sqlite3-api.js before it gets
# preprocessed. It contains all of $(sqlite3-api.jses) but none of the
# Emscripten-specific headers and footers.
-sqlite3-api.js.in := $(dir.tmp)/sqlite3-api.c-pp.js
+sqlite3-api.js.in = $(dir.tmp)/sqlite3-api.c-pp.js
$(sqlite3-api.js.in): $(MKDIR.bld) $(sqlite3-api.jses) $(MAKEFILE)
- @echo "Making $@..."
+ @echo "Making $@ ..."
@for i in $(sqlite3-api.jses); do \
echo "/* BEGIN FILE: $$i */"; \
cat $$i; \
@@ -592,7 +600,7 @@ $(sqlite3-api.js.in): $(MKDIR.bld) $(sqlite3-api.jses) $(MAKEFILE)
########################################################################
# emcc flags for .c/.o/.wasm/.js.
-emcc.flags :=
+emcc.flags =
ifeq (1,$(emcc.verbose))
emcc.flags += -v
# -v is _very_ loud but also informative about what it's doing
@@ -601,22 +609,22 @@ endif
########################################################################
# emcc flags for .c/.o.
-emcc.cflags :=
+emcc.cflags =
emcc.cflags += -std=c99 -fPIC
# -------------^^^^^^^^ we need c99 for $(sqlite3-wasm.c), primarily
# for variadic macros and snprintf() to implement
-# sqlite3_wasm_enum_json().
+# sqlite3__wasm_enum_json().
emcc.cflags += -I. -I$(dir.top)
########################################################################
# emcc flags specific to building .js/.wasm files...
-emcc.jsflags := -fPIC
+emcc.jsflags = -fPIC
emcc.jsflags += --no-entry
emcc.jsflags += -sWASM_BIGINT=$(emcc.WASM_BIGINT)
emcc.jsflags += -sMODULARIZE
emcc.jsflags += -sDYNAMIC_EXECUTION=0
emcc.jsflags += -sNO_POLYFILL
emcc.jsflags += -sEXPORTED_FUNCTIONS=@$(EXPORTED_FUNCTIONS.api)
-emcc.exportedRuntimeMethods := \
+emcc.exportedRuntimeMethods = \
-sEXPORTED_RUNTIME_METHODS=wasmMemory
# wasmMemory ==> required by our code for use with -sIMPORTED_MEMORY
# Emscripten 4.0.7 (2025-04-15) stops exporting HEAP* by default.
@@ -641,10 +649,10 @@ emcc.jsflags += -sSTRICT_JS=0
# tools should be installing, e.g. __syscall_geteuid32
# -sENVIRONMENT values for the various build modes:
-emcc.environment.vanilla := web,worker
-emcc.environment.bundler-friendly := $(emcc.environment.vanilla)
-emcc.environment.esm := $(emcc.environment.vanilla)
-emcc.environment.node := node
+emcc.environment.vanilla = web,worker
+emcc.environment.bundler-friendly = $(emcc.environment.vanilla)
+emcc.environment.esm = $(emcc.environment.vanilla)
+emcc.environment.node = node
# Note that adding ",node" to the list for the other builds causes
# Emscripten to generate code which confuses node: it cannot reliably
# determine whether the build is for a browser or for node.
@@ -666,12 +674,12 @@ emcc.environment.node := node
# supported in all configurations (#21071)."
# https://github.com/emscripten-core/emscripten/blob/main/ChangeLog.md
emcc.jsflags += -sALLOW_MEMORY_GROWTH
-emcc.INITIAL_MEMORY.128 := 134217728
-emcc.INITIAL_MEMORY.96 := 100663296
-emcc.INITIAL_MEMORY.64 := 67108864
-emcc.INITIAL_MEMORY.32 := 33554432
-emcc.INITIAL_MEMORY.16 := 16777216
-emcc.INITIAL_MEMORY.8 := 8388608
+emcc.INITIAL_MEMORY.128 = 134217728
+emcc.INITIAL_MEMORY.96 = 100663296
+emcc.INITIAL_MEMORY.64 = 67108864
+emcc.INITIAL_MEMORY.32 = 33554432
+emcc.INITIAL_MEMORY.16 = 16777216
+emcc.INITIAL_MEMORY.8 = 8388608
emcc.INITIAL_MEMORY ?= 16
ifeq (,$(emcc.INITIAL_MEMORY.$(emcc.INITIAL_MEMORY)))
$(error emcc.INITIAL_MEMORY must be one of: 8, 16, 32, 64, 96, 128 (megabytes))
@@ -704,7 +712,7 @@ emcc.jsflags += -sSTACK_SIZE=512KB
# symbols: we cannot "delete" the Emscripten-defined
# $(sqlite3.js.init-func) from vanilla builds (as opposed to ESM
# builds) because it's declared with "var".
-sqlite3.js.init-func := sqlite3InitModule
+sqlite3.js.init-func = sqlite3InitModule
emcc.jsflags += -sEXPORT_NAME=$(sqlite3.js.init-func)
emcc.jsflags += -sGLOBAL_BASE=4096 # HYPOTHETICALLY keep func table indexes from overlapping w/ heap addr.
#emcc.jsflags += -sSTRICT # fails due to missing __syscall_...()
@@ -772,17 +780,17 @@ $(sqlite3-api-build-version.js): $(MKDIR.bld) $(bin.version-info) $(MAKEFILE)
#
# Maintenance reminder: there are awk binaries out there which do not
# support -e SCRIPT.
-$(sqlite3-license-version.js): $(MKDIR.bld) $(sqlite3.h) $(sqlite3-license-version-header.js) \
- $(MAKEFILE)
+$(sqlite3-license-version.js): $(MKDIR.bld) $(sqlite3.h) \
+ $(dir.api)/sqlite3-license-version-header.js $(MAKEFILE)
@echo "Making $@..."; { \
- cat $(sqlite3-license-version-header.js); \
+ cat $(dir.api)/sqlite3-license-version-header.js; \
echo '/*'; \
echo '** This code was built from sqlite3 version...'; \
echo "**"; \
awk '/define SQLITE_VERSION/{$$1=""; print "**" $$0}' $(sqlite3.h); \
awk '/define SQLITE_SOURCE_ID/{$$1=""; print "**" $$0}' $(sqlite3.h); \
echo "**"; \
- echo "** Using the Emscripten SDK version $(emcc.version)."; \
+ echo "** with the help of Emscripten SDK version $(emcc.version)."; \
echo '*/'; \
} > $@
@@ -794,9 +802,9 @@ $(sqlite3-license-version.js): $(MKDIR.bld) $(sqlite3.h) $(sqlite3-license-versi
# --post-js injects code which runs after the WASM module is loaded
# and includes the entirety of the library plus some
# Emscripten-specific post-bootstrapping code.
-pre-js.js.in := $(dir.api)/pre-js.c-pp.js
-post-js.js.in := $(dir.tmp)/post-js.c-pp.js
-post-jses.js := \
+pre-js.js.in = $(dir.api)/pre-js.c-pp.js
+post-js.js.in = $(dir.tmp)/post-js.c-pp.js
+post-jses.js = \
$(dir.api)/post-js-header.js \
$(sqlite3-api.js.in) \
$(dir.api)/post-js-footer.js
@@ -812,10 +820,10 @@ $(post-js.js.in): $(MKDIR.bld) $(post-jses.js) $(MAKEFILE)
# 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
-sqlite3-wasm.cfiles := $(sqlite3-wasm.c) $(sqlite3_wasm_extra_init.c)
-sqlite3-wasmfs.cfiles := $(sqlite3-wasm.cfiles)
+sqlite3.wasm = $(dir.dout)/sqlite3.wasm
+sqlite3-wasm.c = $(dir.api)/sqlite3-wasm.c
+sqlite3-wasm.cfiles = $(sqlite3-wasm.c) $(sqlite3_wasm_extra_init.c)
+sqlite3-wasmfs.cfiles = $(sqlite3-wasm.cfiles)
# sqlite3-wasm.o vs sqlite3-wasm.c: building against the latter
# (predictably) results in a slightly faster binary. We're close
# enough to the target speed requirements that the 500ms makes a
@@ -860,17 +868,9 @@ if [ x1 = x$(1) ]; then \
fi
endef
-sqlite3-api.js := $(dir.dout)/sqlite3-api.js
-sqlite3.js := $(dir.dout)/sqlite3.js
-sqlite3-api.mjs := $(dir.dout)/sqlite3-api.mjs
-sqlite3.mjs := $(dir.dout)/sqlite3.mjs
-sqlite3-api-bundler-friendly.mjs := $(dir.dout)/sqlite3-api-bundler-friendly.mjs
-sqlite3-bundler-friendly.mjs := $(dir.dout)/sqlite3-bundler-friendly.mjs
-sqlite3-api-node.mjs := $(dir.dout)/sqlite3-api-node.mjs
-sqlite3-node.mjs := $(dir.dout)/sqlite3-node.mjs
-sqlite3-api-wasmfs.mjs := $(dir.tmp)/sqlite3-api-wasmfs.mjs
-sqlite3-wasmfs.mjs := $(dir.wasmfs)/sqlite3-wasmfs.mjs
-EXPORTED_FUNCTIONS.fiddle := $(dir.tmp)/EXPORTED_FUNCTIONS.fiddle
+sqlite3.js = $(dir.dout)/sqlite3.js
+sqlite3.mjs = $(dir.dout)/sqlite3.mjs
+EXPORTED_FUNCTIONS.fiddle = $(dir.tmp)/EXPORTED_FUNCTIONS.fiddle
# The various -D... values used by *.c-pp.js include:
#
@@ -904,24 +904,10 @@ EXPORTED_FUNCTIONS.fiddle := $(dir.tmp)/EXPORTED_FUNCTIONS.fiddle
# build time).
$(sqlite3.wasm): $(sqlite3.js)
$(sqlite3.mjs): $(sqlite3.js)
-$(sqlite3-bundler-friendly.mjs): $(sqlite3.mjs)
-$(sqlite3-node.mjs): $(sqlite3.mjs)
+$(dir.dout)/sqlite3-bundler-friendly.mjs: $(sqlite3.mjs)
+$(dir.dout)/sqlite3-node.mjs: $(sqlite3.mjs)
#CLEAN_FILES += $(sqlite3.wasm)
-########################################################################
-# We need separate copies of certain supplementary JS files for the
-# bundler-friendly build. Concretely, any supplemental JS files which
-# themselves use importScripts() or Workers or URL() constructors
-# which refer to other in-tree (m)JS files require a bundler-friendly
-# copy.
-sqlite3-worker1.js.in := $(dir.api)/sqlite3-worker1.c-pp.js
-sqlite3-worker1-promiser.js.in := $(dir.api)/sqlite3-worker1-promiser.c-pp.js
-sqlite3-worker1.js := $(dir.dout)/sqlite3-worker1.js
-sqlite3-worker1-promiser.js := $(dir.dout)/sqlite3-worker1-promiser.js
-sqlite3-worker1-promiser.mjs := $(dir.dout)/sqlite3-worker1-promiser.mjs
-sqlite3-worker1-bundler-friendly.mjs := $(dir.dout)/sqlite3-worker1-bundler-friendly.mjs
-sqlite3-worker1-promiser-bundler-friendly.js := $(dir.dout)/sqlite3-worker1-promiser-bundler-friendly.js
-
ifneq (1,$(MAKING_CLEAN))
# This block MUST come between the above definitions of
# sqlite3-...js/mjs and the $(eval) calls below this block which use
@@ -934,7 +920,10 @@ ifneq (1,$(MAKING_CLEAN))
# the $ references in those languages made it just as illegible as the
# native makefile code. Somewhat surprisingly, moving that code generation
# to C makes it slightly less illegible than the previous 3 options.
-bin.mkwb := ./mkwasmbuilds
+#
+# Maintenance note: the various $(c-pp.D.XYZ) vars are defined in this
+# step.
+bin.mkwb = ./mkwasmbuilds
$(bin.mkwb): $(bin.mkwb).c $(MAKEFILE)
$(CC) -o $@ $<
DISTCLEAN_FILES += $(bin.mkwb)
@@ -946,45 +935,60 @@ DISTCLEAN_FILES += $(bin.mkwb)
endif
DISTCLEAN_FILES += .wasmbuilds.make
-$(eval $(call SQLITE.CALL.C-PP.FILTER,$(sqlite3-worker1.js.in),$(sqlite3-worker1.js)))
-$(eval $(call SQLITE.CALL.C-PP.FILTER,$(sqlite3-worker1.js.in),$(sqlite3-worker1-bundler-friendly.mjs),\
+########################################################################
+# We need separate copies of certain supplementary JS files for the
+# bundler-friendly build. Concretely, any supplemental JS files which
+# themselves use importScripts() or Workers or URL() constructors
+# which refer to other in-tree (m)JS files require a bundler-friendly
+# copy. Bundler-friendly builds replace certain references to string
+# vars/expressions with string literals, as bundler tools are static
+# code analyzers and cannot cope with the former.
+#
+# Most of what follows is the generation of those copies.
+$(eval $(call SQLITE.CALL.C-PP.FILTER,$(dir.api)/sqlite3-worker1.c-pp.js,\
+ $(dir.dout)/sqlite3-worker1.js))
+$(eval $(call SQLITE.CALL.C-PP.FILTER,$(dir.api)/sqlite3-worker1.c-pp.js,\
+ $(dir.dout)/sqlite3-worker1-bundler-friendly.mjs,\
$(c-pp.D.sqlite3-bundler-friendly)))
-$(eval $(call SQLITE.CALL.C-PP.FILTER,$(sqlite3-worker1-promiser.js.in),$(sqlite3-worker1-promiser.js)))
-$(eval $(call SQLITE.CALL.C-PP.FILTER,$(sqlite3-worker1-promiser.js.in),\
- $(sqlite3-worker1-promiser-bundler-friendly.js),\
+$(eval $(call SQLITE.CALL.C-PP.FILTER,$(dir.api)/sqlite3-worker1-promiser.c-pp.js,\
+ $(dir.dout)/sqlite3-worker1-promiser.js))
+$(eval $(call SQLITE.CALL.C-PP.FILTER,$(dir.api)/sqlite3-worker1-promiser.c-pp.js,\
+ $(dir.dout)/sqlite3-worker1-promiser-bundler-friendly.js,\
$(c-pp.D.sqlite3-bundler-friendly)))
-$(eval $(call SQLITE.CALL.C-PP.FILTER,$(sqlite3-worker1-promiser.js.in),$(sqlite3-worker1-promiser.mjs),\
+$(eval $(call SQLITE.CALL.C-PP.FILTER,$(dir.api)/sqlite3-worker1-promiser.c-pp.js,\
+ $(dir.dout)/sqlite3-worker1-promiser.mjs,\
-Dtarget=es6-module -Dtarget=es6-bundler-friendly))
-$(sqlite3-bundler-friendly.mjs): $(sqlite3-worker1-bundler-friendly.mjs) \
- $(sqlite3-worker1-promiser-bundler-friendly.js)
$(eval $(call SQLITE.CALL.C-PP.FILTER,demo-worker1-promiser.c-pp.js,demo-worker1-promiser.js))
$(eval $(call SQLITE.CALL.C-PP.FILTER,demo-worker1-promiser.c-pp.js,demo-worker1-promiser.mjs,\
-Dtarget=es6-module))
$(eval $(call SQLITE.CALL.C-PP.FILTER,demo-worker1-promiser.c-pp.html,demo-worker1-promiser.html))
$(eval $(call SQLITE.CALL.C-PP.FILTER,demo-worker1-promiser.c-pp.html,demo-worker1-promiser-esm.html,\
-Dtarget=es6-module))
-all: $(sqlite3-worker1.js) \
- $(sqlite3-worker1-promiser.js) $(sqlite3-worker1-promiser.mjs)
-demo-worker1-promiser.html: $(sqlite3-worker1-promiser.js) demo-worker1-promiser.js
+$(dir.dout)/sqlite3-bundler-friendly.mjs: \
+ $(dir.dout)/sqlite3-worker1-bundler-friendly.mjs \
+ $(dir.dout)/sqlite3-worker1-promiser-bundler-friendly.js
+
+demo-worker1-promiser.html: $(dir.dout)/sqlite3-worker1-promiser.js demo-worker1-promiser.js
demo-worker1-promiser-esm.html: $(sqlite3-worker1-promiser.mjs) demo-worker1-promiser.mjs
all: demo-worker1-promiser.html demo-worker1-promiser-esm.html
sqlite3-api.ext.jses += \
- $(sqlite3-worker1-promiser.mjs) \
- $(sqlite3-worker1-bundler-friendly.mjs) \
- $(sqlite3-worker1.js)
+ $(dir.dout)/sqlite3-worker1-promiser.mjs \
+ $(dir.dout)/sqlite3-worker1-promiser.js \
+ $(dir.dout)/sqlite3-worker1-bundler-friendly.mjs \
+ $(dir.dout)/sqlite3-worker1.js
all quick: $(sqlite3-api.ext.jses)
q: quick
########################################################################
# batch-runner.js is part of one of the test apps which reads in SQL
# dumps generated by $(speedtest1) and executes them.
-dir.sql := sql
-speedtest1 := ../../speedtest1
-speedtest1.c := ../../test/speedtest1.c
-speedtest1.sql := $(dir.sql)/speedtest1.sql
-speedtest1.cliflags := --size 10 --big-transactions
+dir.sql = sql
+speedtest1 = ../../speedtest1
+speedtest1.c = ../../test/speedtest1.c
+speedtest1.sql = $(dir.sql)/speedtest1.sql
+speedtest1.cliflags = --size 10 --big-transactions
$(speedtest1):
$(MAKE) -C ../.. speedtest1
$(speedtest1.sql): $(speedtest1) $(MAKEFILE)
@@ -1005,8 +1009,8 @@ batch: batch-runner.list
#
# emcc.speedtest1.common = emcc flags used by multiple builds of speedtest1
# emcc.speedtest1 = emcc flags used by main build of speedtest1
-emcc.speedtest1.common := $(emcc_opt_full)
-emcc.speedtest1 := -I. -I$(dir $(sqlite3.canonical.c))
+emcc.speedtest1.common = $(emcc_opt_full)
+emcc.speedtest1 = -I. -I$(dir $(sqlite3.canonical.c))
emcc.speedtest1 += -sENVIRONMENT=web
emcc.speedtest1 += -sALLOW_MEMORY_GROWTH
emcc.speedtest1 += -sINITIAL_MEMORY=$(emcc.INITIAL_MEMORY.$(emcc.INITIAL_MEMORY))
@@ -1019,7 +1023,7 @@ emcc.speedtest1.common += -Wno-limited-postlink-optimizations
emcc.speedtest1.common += -Wno-unused-main
# ^^^^ -Wno-unused-main is for emcc 3.1.52+. speedtest1 has a wasm_main() which is
# exported and called by the JS code.
-EXPORTED_FUNCTIONS.speedtest1 := $(abspath $(dir.tmp)/EXPORTED_FUNCTIONS.speedtest1)
+EXPORTED_FUNCTIONS.speedtest1 = $(abspath $(dir.tmp)/EXPORTED_FUNCTIONS.speedtest1)
emcc.speedtest1.common += -sSTACK_SIZE=512KB
emcc.speedtest1.common += -sEXPORTED_FUNCTIONS=@$(EXPORTED_FUNCTIONS.speedtest1)
emcc.speedtest1.common += $(emcc.exportedRuntimeMethods)
@@ -1028,8 +1032,8 @@ emcc.speedtest1.common += -sDYNAMIC_EXECUTION=0
emcc.speedtest1.common += --minify 0
emcc.speedtest1.common += -sEXPORT_NAME=$(sqlite3.js.init-func)
emcc.speedtest1.common += -sWASM_BIGINT=$(emcc.WASM_BIGINT)
-speedtest1.exit-runtime0 := -sEXIT_RUNTIME=0
-speedtest1.exit-runtime1 := -sEXIT_RUNTIME=1
+speedtest1.exit-runtime0 = -sEXIT_RUNTIME=0
+speedtest1.exit-runtime1 = -sEXIT_RUNTIME=1
# Re -sEXIT_RUNTIME=1 vs 0: if it's 1 and speedtest1 crashes, we get
# this error from emscripten:
#
@@ -1050,10 +1054,9 @@ speedtest1.exit-runtime1 := -sEXIT_RUNTIME=1
$(EXPORTED_FUNCTIONS.speedtest1): $(MKDIR.bld) $(EXPORTED_FUNCTIONS.api.core)
@echo "Making $@ ..."
@{ echo _wasm_main; cat $(EXPORTED_FUNCTIONS.api.core); } > $@
-speedtest1.js := $(dir.dout)/speedtest1.js
-speedtest1.wasm := $(dir.dout)/speedtest1.wasm
-emcc.flags.speedtest1-vanilla := $(cflags.common) -DSQLITE_SPEEDTEST1_WASM
-speedtest1.cfiles := $(speedtest1.c) $(sqlite3-wasm.c)
+speedtest1.js = $(dir.dout)/speedtest1.js
+emcc.flags.speedtest1-vanilla = $(cflags.common) -DSQLITE_SPEEDTEST1_WASM
+speedtest1.cfiles = $(speedtest1.c) $(sqlite3-wasm.c)
$(speedtest1.js): $(MAKEFILE) $(speedtest1.cfiles) \
$(pre-post-speedtest1-vanilla.deps) \
$(EXPORTED_FUNCTIONS.speedtest1)
@@ -1067,14 +1070,13 @@ $(speedtest1.js): $(MAKEFILE) $(speedtest1.cfiles) \
-USQLITE_C -DSQLITE_C=$(sqlite3.canonical.c) \
$(speedtest1.exit-runtime0) \
-o $@ $(speedtest1.cfiles) -lm
- $(maybe-wasm-strip) $(speedtest1.wasm)
- sed -i -e '/^var _sqlite3.*createExportWrapper/d' $@
- chmod -x $(speedtest1.wasm)
- ls -la $@ $(speedtest1.wasm)
+ @chmod -x $(basename $@).wasm
+ @$(maybe-wasm-strip) $(basename $@).wasm
+ @$(SQLITE.strip-createExportWrapper)
+ @ls -la $@ $(speedtest1.wasm)
speedtest1: $(speedtest1.js)
all: speedtest1
-#CLEAN_FILES += $(speedtest1.js) $(speedtest1.wasm)
# end speedtest1.js
########################################################################
@@ -1099,7 +1101,7 @@ $(eval $(call SQLITE.CALL.C-PP.FILTER,tester1.c-pp.js,tester1.mjs,$(c-pp.D.sqlit
$(eval $(call SQLITE.CALL.C-PP.FILTER,tester1.c-pp.html,tester1.html))
$(eval $(call SQLITE.CALL.C-PP.FILTER,tester1.c-pp.html,tester1-esm.html,$(c-pp.D.sqlite3-esm)))
tester1: tester1.js tester1.mjs tester1.html tester1-esm.html
-# Note that we do not include $(sqlite3-bundler-friendly.mjs) in this
+# Note that we do not include $(dir.dout)/sqlite3-bundler-friendly.mjs in this
# because bundlers are client-specific.
all quick: tester1
quick: $(sqlite3.js)
@@ -1111,7 +1113,7 @@ quick: $(sqlite3.js)
# painful.
.PHONY: o0 o1 o2 o3 os oz
-emcc-opt-extra :=
+emcc-opt-extra =
#ifeq (1,$(wasm-bare-bones))
#emcc-opt-extra += -flto
# ^^^^ -flto can have a considerably performance boost at -O0 but
@@ -1139,7 +1141,7 @@ oz: clean
# Sub-makes...
# sqlite.org/fiddle application...
-include fiddle.make
+include $(MAKEFILE.fiddle)
# Only add wasmfs if wasmfs.enable=1 or we're running (dist)clean
ifneq (,$(filter wasmfs,$(MAKECMDGOALS)))
@@ -1157,16 +1159,17 @@ ifeq (1,$(wasmfs.enable))
# little benefit.
#
########################################################################
-# Some platforms do not support the WASMFS build. Raspberry Pi OS is one
-# of them. As such platforms are discovered, add their (uname -m) name
-# to PLATFORMS_WITH_NO_WASMFS to exclude the wasmfs build parts.
-PLATFORMS_WITH_NO_WASMFS := aarch64 # add any others here
-THIS_ARCH := $(shell /usr/bin/uname -m)
+# Some platforms do not support the WASMFS build. Raspberry Pi OS is
+# one of them (or was when that comment was initially written). As
+# such platforms are discovered, add their (uname -m) name to
+# PLATFORMS_WITH_NO_WASMFS to exclude the wasmfs build parts.
+PLATFORMS_WITH_NO_WASMFS = aarch64 # add any others here
+THIS_ARCH = $(shell /usr/bin/uname -m)
ifneq (,$(filter $(THIS_ARCH),$(PLATFORMS_WITH_NO_WASMFS)))
$(info This platform does not support the WASMFS build.)
-HAVE_WASMFS := 0
+HAVE_WASMFS = 0
else
-HAVE_WASMFS := 1
+HAVE_WASMFS = 1
include wasmfs.make
endif
endif
@@ -1204,7 +1207,7 @@ update-docs:
echo "Pass wasm.docs.home=/path/to/wasm/docs/checkout or edit this makefile to suit."; \
exit 127
else
-wasm.docs.jswasm := $(wasm.docs.home)/jswasm
+wasm.docs.jswasm = $(wasm.docs.home)/jswasm
update-docs: $(bin.stripccomments) $(sqlite3.js) $(sqlite3.wasm)
@echo "Copying files to the /wasm docs. Be sure to use an -Oz build for this!"
cp $(sqlite3.wasm) $(wasm.docs.jswasm)/.
diff --git a/ext/wasm/api/sqlite3-api-oo1.c-pp.js b/ext/wasm/api/sqlite3-api-oo1.c-pp.js
index 06f916002..8663dcdde 100644
--- a/ext/wasm/api/sqlite3-api-oo1.c-pp.js
+++ b/ext/wasm/api/sqlite3-api-oo1.c-pp.js
@@ -13,7 +13,7 @@
This file contains the so-called OO #1 API wrapper for the sqlite3
WASM build. It requires that sqlite3-api-glue.js has already run
- and it installs its deliverable as globalThis.sqlite3.oo1.
+ and it installs its deliverable as sqlite3.oo1.
*/
globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
const toss3 = (...args)=>{throw new sqlite3.SQLite3Error(...args)};
@@ -38,6 +38,21 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
*/
const __ptrMap = new WeakMap();
/**
+ A Set of oo1.DB or oo1.Stmt objects which are proxies for
+ (sqlite3*) resp. (sqlite3_stmt*) pointers which themselves are
+ owned elsewhere. Objects in this Set do not own their underlying
+ handle and that handle must be guaranteed (by the client) to
+ outlive the proxy. DB.close()/Stmt.finalize() methods will remove
+ the object from this Set _instead_ of closing/finalizing the
+ pointer. These proxies are primarily intended as a way to briefly
+ wrap an (sqlite3[_stmt]*) object as an oo1.DB/Stmt without taking
+ over ownership, to take advantage of simplifies usage compared to
+ the C API while not imposing any change of ownership.
+
+ See DB.wrapHandle() and Stmt.wrapHandle().
+ */
+ const __doesNotOwnHandle = new Set();
+ /**
Map of DB instances to objects, each object being a map of Stmt
wasm pointers to Stmt objects.
*/
@@ -234,73 +249,89 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
};
}
const opt = ctor.normalizeArgs(...args);
- let fn = opt.filename, vfsName = opt.vfs, flagsStr = opt.flags;
- if(('string'!==typeof fn && 'number'!==typeof fn)
- || 'string'!==typeof flagsStr
- || (vfsName && ('string'!==typeof vfsName && 'number'!==typeof vfsName))){
- sqlite3.config.error("Invalid DB ctor args",opt,arguments);
- toss3("Invalid arguments for DB constructor.");
- }
- let fnJs = ('number'===typeof fn) ? wasm.cstrToJs(fn) : fn;
- const vfsCheck = ctor._name2vfs[fnJs];
- if(vfsCheck){
- vfsName = vfsCheck.vfs;
- fn = fnJs = vfsCheck.filename(fnJs);
- }
- let pDb, oflags = 0;
- if( flagsStr.indexOf('c')>=0 ){
- oflags |= capi.SQLITE_OPEN_CREATE | capi.SQLITE_OPEN_READWRITE;
- }
- if( flagsStr.indexOf('w')>=0 ) oflags |= capi.SQLITE_OPEN_READWRITE;
- if( 0===oflags ) oflags |= capi.SQLITE_OPEN_READONLY;
- oflags |= capi.SQLITE_OPEN_EXRESCODE;
- const stack = wasm.pstack.pointer;
- try {
- const pPtr = wasm.pstack.allocPtr() /* output (sqlite3**) arg */;
- let rc = capi.sqlite3_open_v2(fn, pPtr, oflags, vfsName || 0);
- pDb = wasm.peekPtr(pPtr);
- checkSqlite3Rc(pDb, rc);
- capi.sqlite3_extended_result_codes(pDb, 1);
- if(flagsStr.indexOf('t')>=0){
- capi.sqlite3_trace_v2(pDb, capi.SQLITE_TRACE_STMT,
- __dbTraceToConsole, pDb);
+ //sqlite3.config.debug("DB ctor",opt);
+ let pDb;
+ if( (pDb = opt['sqlite3*']) ){
+ /* This property ^^^^^ is very specifically NOT DOCUMENTED and
+ NOT part of the public API. This is a back door for functions
+ like DB.wrapDbHandle(). */
+ //sqlite3.config.debug("creating proxy db from",opt);
+ if( !opt['sqlite3*:takeOwnership'] ){
+ /* This is object does not own its handle. */
+ __doesNotOwnHandle.add(this);
}
- }catch( e ){
- if( pDb ) capi.sqlite3_close_v2(pDb);
- throw e;
- }finally{
- wasm.pstack.restore(stack);
+ this.filename = capi.sqlite3_db_filename(pDb,'main');
+ }else{
+ let fn = opt.filename, vfsName = opt.vfs, flagsStr = opt.flags;
+ if(('string'!==typeof fn && 'number'!==typeof fn)
+ || 'string'!==typeof flagsStr
+ || (vfsName && ('string'!==typeof vfsName && 'number'!==typeof vfsName))){
+ sqlite3.config.error("Invalid DB ctor args",opt,arguments);
+ toss3("Invalid arguments for DB constructor.");
+ }
+ let fnJs = ('number'===typeof fn) ? wasm.cstrToJs(fn) : fn;
+ const vfsCheck = ctor._name2vfs[fnJs];
+ if(vfsCheck){
+ vfsName = vfsCheck.vfs;
+ fn = fnJs = vfsCheck.filename(fnJs);
+ }
+ let oflags = 0;
+ if( flagsStr.indexOf('c')>=0 ){
+ oflags |= capi.SQLITE_OPEN_CREATE | capi.SQLITE_OPEN_READWRITE;
+ }
+ if( flagsStr.indexOf('w')>=0 ) oflags |= capi.SQLITE_OPEN_READWRITE;
+ if( 0===oflags ) oflags |= capi.SQLITE_OPEN_READONLY;
+ oflags |= capi.SQLITE_OPEN_EXRESCODE;
+ const stack = wasm.pstack.pointer;
+ try {
+ const pPtr = wasm.pstack.allocPtr() /* output (sqlite3**) arg */;
+ let rc = capi.sqlite3_open_v2(fn, pPtr, oflags, vfsName || 0);
+ pDb = wasm.peekPtr(pPtr);
+ checkSqlite3Rc(pDb, rc);
+ capi.sqlite3_extended_result_codes(pDb, 1);
+ if(flagsStr.indexOf('t')>=0){
+ capi.sqlite3_trace_v2(pDb, capi.SQLITE_TRACE_STMT,
+ __dbTraceToConsole, pDb);
+ }
+ }catch( e ){
+ if( pDb ) capi.sqlite3_close_v2(pDb);
+ throw e;
+ }finally{
+ wasm.pstack.restore(stack);
+ }
+ this.filename = fnJs;
}
- this.filename = fnJs;
__ptrMap.set(this, pDb);
__stmtMap.set(this, Object.create(null));
- try{
+ if( !opt['sqlite3*'] ){
+ try{
//#if enable-see
- dbCtorApplySEEKey(this,opt);
+ dbCtorApplySEEKey(this,opt);
//#endif
- // Check for per-VFS post-open SQL/callback...
- const pVfs = capi.sqlite3_js_db_vfs(pDb)
- || toss3("Internal error: cannot get VFS for new db handle.");
- const postInitSql = __vfsPostOpenCallback[pVfs];
- if(postInitSql){
- /**
- Reminder: if this db is encrypted and the client did _not_ pass
- in the key, any init code will fail, causing the ctor to throw.
- We don't actually know whether the db is encrypted, so we cannot
- sensibly apply any heuristics which skip the init code only for
- encrypted databases for which no key has yet been supplied.
- */
- if(postInitSql instanceof Function){
- postInitSql(this, sqlite3);
- }else{
- checkSqlite3Rc(
- pDb, capi.sqlite3_exec(pDb, postInitSql, 0, 0, 0)
- );
+ // Check for per-VFS post-open SQL/callback...
+ const pVfs = capi.sqlite3_js_db_vfs(pDb)
+ || toss3("Internal error: cannot get VFS for new db handle.");
+ const postInitSql = __vfsPostOpenCallback[pVfs];
+ if(postInitSql){
+ /**
+ Reminder: if this db is encrypted and the client did _not_ pass
+ in the key, any init code will fail, causing the ctor to throw.
+ We don't actually know whether the db is encrypted, so we cannot
+ sensibly apply any heuristics which skip the init code only for
+ encrypted databases for which no key has yet been supplied.
+ */
+ if(postInitSql instanceof Function){
+ postInitSql(this, sqlite3);
+ }else{
+ checkSqlite3Rc(
+ pDb, capi.sqlite3_exec(pDb, postInitSql, 0, 0, 0)
+ );
+ }
}
+ }catch(e){
+ this.close();
+ throw e;
}
- }catch(e){
- this.close();
- throw e;
}
};
@@ -403,7 +434,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
- `vfs`: the VFS fname
//#if enable-see
-
SEE-capable builds optionally support ONE of the following
additional options:
@@ -429,7 +459,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
is supplied and the database is encrypted, execution of the
post-initialization SQL will fail, causing the constructor to
throw.
-
//#endif enable-see
The `filename` and `vfs` arguments may be either JS strings or
@@ -457,8 +486,8 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
/**
Internal-use enum for mapping JS types to DB-bindable types.
These do not (and need not) line up with the SQLITE_type
- values. All values in this enum must be truthy and distinct
- but they need not be numbers.
+ values. All values in this enum must be truthy and (mostly)
+ distinct but they need not be numbers.
*/
const BindTypes = {
null: 1,
@@ -467,7 +496,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
boolean: 4,
blob: 5
};
- BindTypes['undefined'] == BindTypes.null;
if(wasm.bigIntEnabled){
BindTypes.bigint = BindTypes.number;
}
@@ -486,26 +514,30 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
- `db`: the DB object which created the statement.
- `columnCount`: the number of result columns in the query, or 0
- for queries which cannot return results. This property is a proxy
- for sqlite3_column_count() and its use in loops should be avoided
- because of the call overhead associated with that. The
- `columnCount` is not cached when the Stmt is created because a
- schema change made via a separate db connection between this
- statement's preparation and when it is stepped may invalidate it.
+ for queries which cannot return results. This property is a
+ read-only proxy for sqlite3_column_count() and its use in loops
+ should be avoided because of the call overhead associated with
+ that. The `columnCount` is not cached when the Stmt is created
+ because a schema change made between this statement's preparation
+ and when it is stepped may invalidate it.
- - `parameterCount`: the number of bindable parameters in the query.
+ - `parameterCount`: the number of bindable parameters in the
+ query. Like `columnCount`, this property is ready-only and is a
+ proxy for a C API call.
As a general rule, most methods of this class will throw if
called on an instance which has been finalized. For brevity's
sake, the method docs do not all repeat this warning.
*/
- const Stmt = function(){
+ const Stmt = function(/*oo1db, stmtPtr, BindTypes [,takeOwnership=true] */){
if(BindTypes!==arguments[2]){
toss3(capi.SQLITE_MISUSE, "Do not call the Stmt constructor directly. Use DB.prepare().");
}
this.db = arguments[0];
__ptrMap.set(this, arguments[1]);
- this.parameterCount = capi.sqlite3_bind_parameter_count(this.pointer);
+ if( arguments.length>3 && !arguments[3] ){
+ __doesNotOwnHandle.add(this);
+ }
};
/** Throws if the given DB has been closed, else it is returned. */
@@ -698,10 +730,10 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
},
/**
Finalizes all open statements and closes this database
- connection. This is a no-op if the db has already been
- closed. After calling close(), `this.pointer` will resolve to
- `undefined`, so that can be used to check whether the db
- instance is still opened.
+ connection (with one exception noted below). This is a no-op if
+ the db has already been closed. After calling close(),
+ `this.pointer` will resolve to `undefined`, and that can be
+ used to check whether the db instance is still opened.
If this.onclose.before is a function then it is called before
any close-related cleanup.
@@ -721,14 +753,19 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
all, will never trigger close(), so onclose handlers are not a
reliable way to implement close-time cleanup or maintenance of
a db.
+
+ If this instance was created using DB.wrapHandle() and does not
+ own this.pointer then it does not close the db handle but it
+ does perform all other work, such as calling onclose callbacks
+ and disassociating this object from this.pointer.
*/
close: function(){
- if(this.pointer){
+ const pDb = this.pointer;
+ if(pDb){
if(this.onclose && (this.onclose.before instanceof Function)){
try{this.onclose.before(this)}
catch(e){/*ignore*/}
}
- const pDb = this.pointer;
Object.keys(__stmtMap.get(this)).forEach((k,s)=>{
if(s && s.pointer){
try{s.finalize()}
@@ -737,7 +774,9 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
});
__ptrMap.delete(this);
__stmtMap.delete(this);
- capi.sqlite3_close_v2(pDb);
+ if( !__doesNotOwnHandle.delete(this) ){
+ capi.sqlite3_close_v2(pDb);
+ }
if(this.onclose && (this.onclose.after instanceof Function)){
try{this.onclose.after(this)}
catch(e){/*ignore*/}
@@ -1450,9 +1489,63 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
*/
checkRc: function(resultCode){
return checkSqlite3Rc(this, resultCode);
- }
+ },
}/*DB.prototype*/;
+ /**
+ Returns a new oo1.DB instance which wraps the given (sqlite3*)
+ WASM pointer, optionally with or without taking over ownership of
+ that pointer.
+
+ The first argument must be either a non-NULL (sqlite3*) WASM
+ pointer.
+
+ The second argument, defaulting to false, specifies ownership of
+ the first argument. If it is truthy, the returned object will
+ pass that pointer to sqlite3_close() when its close() method is
+ called, otherwise it will not.
+
+ Throws if pDb is not a non-0 WASM pointer.
+
+ The caller MUST GUARANTEE that the passed-in handle will outlive
+ the returned object, i.e. that it will not be closed. If it is closed,
+ this object will hold a stale pointer and results are undefined.
+
+ Aside from its lifetime, the proxy is to be treated as any other
+ DB instance, including the requirement of calling close() on
+ it. close() will free up internal resources owned by the proxy
+ and disassociate the proxy from that handle but will not
+ actually close the proxied db handle unless this function is
+ passed a thruthy second argument.
+
+ To stress:
+
+ - DO NOT call sqlite3_close() (or similar) on the being-proxied
+ pointer while a proxy is active.
+
+ - ALWAYS eventually call close() on the returned object. If the
+ proxy does not own the underlying handle then its MUST be
+ closed BEFORE the being-proxied handle is closed.
+
+ Design notes:
+
+ - wrapHandle() "could" accept a DB object instance as its first
+ argument and proxy thatDb.pointer but there is currently no use
+ case where doing so would be useful, so it does not allow
+ that. That restriction may be lifted in a future version.
+ */
+ DB.wrapHandle = function(pDb, takeOwnership=false){
+ if( !pDb || !wasm.isPtr(pDb) ){
+ throw new sqlite3.SQLite3Error(capi.SQLITE_MISUSE,
+ "Argument must be a WASM sqlite3 pointer");
+ }
+ return new DB({
+ /* This ctor call style is very specifically internal-use-only.
+ It is not documented and may change at any time. */
+ "sqlite3*": pDb,
+ "sqlite3*:takeOwnership": !!takeOwnership
+ });
+ };
/** Throws if the given Stmt has been finalized, else stmt is
returned. */
@@ -1474,8 +1567,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
case BindTypes.string:
return t;
case BindTypes.bigint:
- if(wasm.bigIntEnabled) return t;
- /* else fall through */
+ return wasm.bigIntEnabled ? t : undefined;
default:
return util.isBindableTypedArray(v) ? BindTypes.blob : undefined;
}
@@ -1641,12 +1733,19 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
This method always throws if called when it is illegal to do
so. Namely, when triggered via a per-row callback handler of a
DB.exec() call.
+
+ If Stmt does not own its underlying (sqlite3_stmt*) (see
+ Stmt.wrapHandle()) then this function will not pass it to
+ sqlite3_finalize().
*/
finalize: function(){
- if(this.pointer){
+ const ptr = this.pointer;
+ if(ptr){
affirmNotLockedByExec(this,'finalize()');
- const rc = capi.sqlite3_finalize(this.pointer);
- delete __stmtMap.get(this.db)[this.pointer];
+ const rc = (__doesNotOwnHandle.delete(this)
+ ? 0
+ : capi.sqlite3_finalize(ptr));
+ delete __stmtMap.get(this.db)[ptr];
__ptrMap.delete(this);
__execLock.delete(this);
__stmtMayGet.delete(this);
@@ -2134,6 +2233,64 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
set: ()=>toss3("The columnCount property is read-only.")
});
+ Object.defineProperty(Stmt.prototype, 'parameterCount', {
+ enumerable: false,
+ get: function(){return capi.sqlite3_bind_parameter_count(this.pointer)},
+ set: ()=>toss3("The parameterCount property is read-only.")
+ });
+
+ /**
+ The Stmt counterpart of oo1.DB.wrapHandle(), this creates a Stmt
+ instance which wraps a WASM (sqlite3_stmt*) in the oo1 API,
+ optionally with or without taking over ownership of that pointer.
+
+ The first argument must be an oo1.DB instance[^1].
+
+ The second argument must be a valid WASM (sqlite3_stmt*), as
+ produced by sqlite3_prepare_v2() and sqlite3_prepare_v3().
+
+ The third argument, defaulting to false, specifies whether the
+ returned Stmt object takes over ownership of the underlying
+ (sqlite3_stmt*). If true, the returned object's finalize() method
+ will finalize that handle, else it will not. If it is false,
+ ownership of pStmt is unchanged and pStmt MUST outlive the
+ returned object or results are undefined.
+
+ This function throws if the arguments are invalid. On success it
+ returns a new Stmt object which wraps the given statement
+ pointer.
+
+ Like all Stmt objects, the finalize() method must eventually be
+ called on the returned object to free up internal resources,
+ regardless of whether this function's third argument is true or
+ not.
+
+ [^1]: The first argument cannot be a (sqlite3*) because the
+ resulting Stmt object requires a parent DB object. It is not yet
+ determined whether it would be of general benefit to refactor the
+ DB/Stmt pair internals to communicate in terms of the underlying
+ (sqlite3*) rather than a DB object. If so, we could laxen the
+ first argument's requirement and allow an (sqlite3*). Because
+ DB.wrapHandle() enables multiple DB objects to proxy the same
+ (sqlite3*), we cannot unambiguously translate the first arugment
+ from (sqlite3*) to DB instances for us with this function's first
+ argument.
+ */
+ Stmt.wrapHandle = function(oo1db, pStmt, takeOwnership=false){
+ let ctor = Stmt;
+ if( !(oo1db instanceof DB) || !oo1db.pointer ){
+ throw new sqlite3.SQLite3Error(sqlite3.SQLITE_MISUSE,
+ "First argument must be an opened "+
+ "sqlite3.oo1.DB instance");
+ }
+ if( !pStmt || !wasm.isPtr(pStmt) ){
+ throw new sqlite3.SQLite3Error(sqlite3.SQLITE_MISUSE,
+ "Second argument must be a WASM "+
+ "sqlite3_stmt pointer");
+ }
+ return new Stmt(oo1db, pStmt, BindTypes, !!takeOwnership);
+ }
+
/** The OO API's public namespace. */
sqlite3.oo1 = {
DB,
diff --git a/ext/wasm/api/sqlite3-api-worker1.c-pp.js b/ext/wasm/api/sqlite3-api-worker1.c-pp.js
index 5e088f438..55ad16185 100644
--- a/ext/wasm/api/sqlite3-api-worker1.c-pp.js
+++ b/ext/wasm/api/sqlite3-api-worker1.c-pp.js
@@ -385,10 +385,19 @@ sqlite3.initWorker1API = function(){
const getDbId = function(db){
let id = wState.idMap.get(db);
if(id) return id;
- id = 'db#'+(++wState.idSeq)+'@'+db.pointer;
+ id = 'db#'+(++wState.idSeq)+':'+
+ Math.floor(Math.random() * 100000000)+':'+
+ Math.floor(Math.random() * 100000000);
/** ^^^ can't simply use db.pointer b/c closing/opening may re-use
the same address, which could map pending messages to a wrong
- instance. */
+ instance.
+
+ 2025-07: https://github.com/sqlite/sqlite-wasm/issues/113
+ demonstrates that two Worker1s can end up with the same IDs,
+ despite using different instances of the library, so we need
+ to add some randomness to the IDs instead of relying on the
+ pointer addresses.
+ */
wState.idMap.set(db, id);
return id;
};
diff --git a/ext/wasm/api/sqlite3-wasm.c b/ext/wasm/api/sqlite3-wasm.c
index ee8a10209..574684ce9 100644
--- a/ext/wasm/api/sqlite3-wasm.c
+++ b/ext/wasm/api/sqlite3-wasm.c
@@ -939,6 +939,7 @@ const char * sqlite3__wasm_enum_json(void){
DefInt(SQLITE_INNOCUOUS);
DefInt(SQLITE_SUBTYPE);
DefInt(SQLITE_RESULT_SUBTYPE);
+ DefInt(SQLITE_SELFORDER1);
} _DefGroup;
DefGroup(version) {
diff --git a/ext/wasm/api/sqlite3-worker1-promiser.c-pp.js b/ext/wasm/api/sqlite3-worker1-promiser.c-pp.js
index c043fd148..2edabe3e6 100644
--- a/ext/wasm/api/sqlite3-worker1-promiser.c-pp.js
+++ b/ext/wasm/api/sqlite3-worker1-promiser.c-pp.js
@@ -130,12 +130,10 @@
Notable shortcomings:
- - This API was not designed with ES6 modules in mind. Neither Firefox
- nor Safari support, as of March 2023, the {type:"module"} flag to the
- Worker constructor, so that particular usage is not something we're going
- to target for the time being:
-
- https://developer.mozilla.org/en-US/docs/Web/API/Worker/Worker
+ - "v1" of this this API is not suitable for use as an ESM module
+ because ESM worker modules were not widely supported when it was
+ developed. For use as an ESM module, see the "v2" interface later
+ on in this file.
*/
globalThis.sqlite3Worker1Promiser = function callee(config = callee.defaultConfig){
// Inspired by: https://stackoverflow.com/a/52439530
@@ -296,7 +294,7 @@ globalThis.sqlite3Worker1Promiser.defaultConfig = {
after calling the original function and will reject if that
function throws.
*/
-sqlite3Worker1Promiser.v2 = function(config){
+globalThis.sqlite3Worker1Promiser.v2 = function callee(config = callee.defaultConfig){
let oldFunc;
if( 'function' == typeof config ){
oldFunc = config;
@@ -326,11 +324,14 @@ sqlite3Worker1Promiser.v2 = function(config){
}
return p;
}.bind({
- /* We do this because clients are
- recommended to delete globalThis.sqlite3Worker1Promiser. */
+ /* We do this because clients are recommended to delete
+ globalThis.sqlite3Worker1Promiser. */
original: sqlite3Worker1Promiser
});
+globalThis.sqlite3Worker1Promiser.v2.defaultConfig =
+ globalThis.sqlite3Worker1Promiser.defaultConfig;
+
//#if target=es6-module
/**
When built as a module, we export sqlite3Worker1Promiser.v2()
diff --git a/ext/wasm/common/whwasmutil.js b/ext/wasm/common/whwasmutil.js
index b4d8f691b..e85669579 100644
--- a/ext/wasm/common/whwasmutil.js
+++ b/ext/wasm/common/whwasmutil.js
@@ -1773,10 +1773,10 @@ globalThis.WhWasmUtilInstaller = function(target){
does not have a stable interface. */
xArg.FuncPtrAdapter.warnOnUse = false;
- /** If true, convertArg() will FuncPtrAdapter.debugOut() when it
- (un)installs a function binding to/from WASM. Note that
- deinstallation of bindScope=transient bindings happens
- via scopedAllocPop() so will not be output. */
+ /** If true, convertArg() will call FuncPtrAdapter.debugOut() when
+ it (un)installs a function binding to/from WASM. Note that
+ deinstallation of bindScope=transient bindings happens via
+ scopedAllocPop() so will not be output. */
xArg.FuncPtrAdapter.debugFuncInstall = false;
/** Function used for debug output. */
@@ -1827,9 +1827,8 @@ globalThis.WhWasmUtilInstaller = function(target){
The first argument must be one of:
- A JavaScript function.
- - The name of a WASM-exported function. In the latter case xGet()
- is used to fetch the exported function, which throws if it's not
- found.
+ - The name of a WASM-exported function. xGet() is used to fetch
+ the exported function, which throws if it's not found.
- A pointer into the indirect function table. e.g. a pointer
returned from target.installFunction().
@@ -1874,9 +1873,6 @@ globalThis.WhWasmUtilInstaller = function(target){
which convert their argument to an integer and truncate it to
the given bit length.
- - `N*` (args): a type name in the form `N*`, where N is a numeric
- type name, is treated the same as WASM pointer.
-
- `*` and `pointer` (args): are assumed to be WASM pointer values
and are returned coerced to an appropriately-sized pointer
value (i32 or i64). Non-numeric values will coerce to 0 and
@@ -1887,7 +1883,15 @@ globalThis.WhWasmUtilInstaller = function(target){
WASM pointer numeric type.
- `**` (args): is simply a descriptive alias for the WASM pointer
- type. It's primarily intended to mark output-pointer arguments.
+ type. It's primarily intended to mark output-pointer arguments,
+ noting that JS's view of WASM does not distinguish between
+ pointers and pointers-to-pointers, so all such interpretation
+ of `**`, as distinct from `*`, necessarily happens at the
+ client level.
+
+ - `NumType*` (args): a type name in this form, where T is
+ the name of a numeric mapping, e.g. 'int16' or 'double',
+ is treated like `*`.
- `i64` (args and results): passes the value to BigInt() to
convert it to an int64. Only available if bigIntEnabled is
@@ -1916,7 +1920,7 @@ globalThis.WhWasmUtilInstaller = function(target){
UTF-8-encoded C-string to pass to the exported function,
cleaning it up before the wrapper returns. If a long-lived
C-string pointer is required, that requires client-side code
- to create the string, then pass its pointer to the function.
+ to create the string then pass its pointer to the function.
- Else the arg is assumed to be a pointer to a string the
client has already allocated and it's passed on as
@@ -2091,8 +2095,8 @@ globalThis.WhWasmUtilInstaller = function(target){
easily convert, e.g., to C-strings, and have them cleaned up
automatically before the wrapper returns to the caller. Likewise,
if a _result_ adapter uses scoped allocation, the result will be
- freed before because they would be freed before the wrapper
- returns, leading to chaos and undefined behavior.
+ freed before the wrapper returns, leading to chaos and undefined
+ behavior.
Except when called as a getter, this function returns itself.
*/
diff --git a/ext/wasm/config.make.in b/ext/wasm/config.make.in
index f30baac3f..4c8d7893b 100644
--- a/ext/wasm/config.make.in
+++ b/ext/wasm/config.make.in
@@ -1,15 +1,16 @@
-# Gets filtered by the configure script
+# config.make.in gets filtered by the top-most configure script to
+# create config.make.
bin.bash = @BIN_BASH@
bin.emcc = @EMCC_WRAPPER@
bin.wasm-strip = @BIN_WASM_STRIP@
bin.wasm-opt = @BIN_WASM_OPT@
-SHELL := $(bin.bash)
+SHELL = $(bin.bash)
# The following overrides can be uncommented to test various
# validation and if/else branches the makefile code:
#
-#bin.bash :=
-#bin.emcc :=
-#bin.wasm-strip :=
-#bin.wasm-opt :=
+#bin.bash =
+#bin.emcc =
+#bin.wasm-strip =
+#bin.wasm-opt =
diff --git a/ext/wasm/dist.make b/ext/wasm/dist.make
index 60699ff5c..176972fd7 100644
--- a/ext/wasm/dist.make
+++ b/ext/wasm/dist.make
@@ -11,7 +11,7 @@
# distinctly different zip file and top directory name to distinguish
# them from release builds.
#######################################################################
-MAKEFILE.dist := $(lastword $(MAKEFILE_LIST))
+MAKEFILE.dist = $(lastword $(MAKEFILE_LIST))
########################################################################
# Chicken/egg situation: we need $(bin.version-info) to get the
@@ -20,16 +20,16 @@ MAKEFILE.dist := $(lastword $(MAKEFILE_LIST))
# have to use a temporary name for the archive until we can get
# that binary built.
ifeq (1,$(SQLITE_C_IS_SEE))
-dist-name-extra := -see
+dist-name-extra = -see
else
-dist-name-extra :=
+dist-name-extra =
endif
ifeq (,$(filter snapshot,$(MAKECMDGOALS)))
-dist-name-prefix := sqlite-wasm$(dist-name-extra)
+dist-name-prefix = sqlite-wasm$(dist-name-extra)
else
-dist-name-prefix := sqlite-wasm$(dist-name-extra)-snapshot-$(shell /usr/bin/date +%Y%m%d)
+dist-name-prefix = sqlite-wasm$(dist-name-extra)-snapshot-$(shell /usr/bin/date +%Y%m%d)
endif
-dist-name := $(dist-name-prefix)-TEMP
+dist-name = $(dist-name-prefix)-TEMP
########################################################################
# dist.build must be the name of a target which triggers the build of
@@ -45,10 +45,10 @@ dist-name := $(dist-name-prefix)-TEMP
# reason not to.
dist.build ?= oz
-dist-dir.top := $(dist-name)
-dist-dir.jswasm := $(dist-dir.top)/$(notdir $(dir.dout))
-dist-dir.common := $(dist-dir.top)/common
-dist.top.extras := \
+dist-dir.top = $(dist-name)
+dist-dir.jswasm = $(dist-dir.top)/$(notdir $(dir.dout))
+dist-dir.common = $(dist-dir.top)/common
+dist.top.extras = \
demo-123.html demo-123-worker.html demo-123.js \
tester1.html tester1-worker.html tester1-esm.html \
tester1.js tester1.mjs \
@@ -56,9 +56,9 @@ dist.top.extras := \
demo-worker1.html demo-worker1.js \
demo-worker1-promiser.html demo-worker1-promiser.js \
demo-worker1-promiser-esm.html demo-worker1-promiser.mjs
-dist.jswasm.extras := $(sqlite3.wasm) \
+dist.jswasm.extras = $(sqlite3.wasm) \
$(sqlite3-api.ext.jses)
-dist.common.extras := \
+dist.common.extras = \
$(wildcard $(dir.common)/*.css) \
$(dir.common)/SqliteTestUtil.js
@@ -77,12 +77,12 @@ $(bin.stripccomments) $(2) < $(1) > $(dist-dir.jswasm)/$(notdir $(1)) || exit;
endef
# STRIP_K1.js = list of JS files which need to be passed through
# $(bin.stripcomments) with a single -k flag.
-STRIP_K1.js := $(sqlite3-worker1.js) $(sqlite3-worker1-promiser.js) \
+STRIP_K1.js = $(sqlite3-worker1.js) $(sqlite3-worker1-promiser.js) \
$(sqlite3-worker1-bundler-friendly.js) \
$(sqlite3-api.ext.jses)
# STRIP_K2.js = list of JS files which need to be passed through
# $(bin.stripcomments) with two -k flags.
-STRIP_K2.js := $(sqlite3.js) $(sqlite3.mjs) \
+STRIP_K2.js = $(sqlite3.js) $(sqlite3.mjs) \
$(sqlite3-bundler-friendly.mjs) $(sqlite3-node.mjs)
########################################################################
# dist: create the end-user deliverable archive.
@@ -104,8 +104,8 @@ STRIP_K2.js := $(sqlite3.js) $(sqlite3.mjs) \
# to know that it's in a regex or string literal. Because of that,
# comment-stripping is currently disabled, which means the builds will
# be significantly larger than before.
-#apply_comment_stripper := false
-apply_comment_stripper := true
+#apply_comment_stripper = false
+apply_comment_stripper = true
# ^^^ shell command true or false
dist: \
$(bin.stripccomments) $(bin.version-info) \
diff --git a/ext/wasm/fiddle.make b/ext/wasm/fiddle.make
index 5b1eb5e77..6bdf44195 100644
--- a/ext/wasm/fiddle.make
+++ b/ext/wasm/fiddle.make
@@ -3,13 +3,12 @@
#
# Intended to include'd by ./GNUmakefile.
#######################################################################
-MAKEFILE.fiddle := $(lastword $(MAKEFILE_LIST))
########################################################################
# shell.c and its build flags...
ifneq (1,$(MAKING_CLEAN))
- make-np-0 := make -C $(dir.top) -n -p
- make-np-1 := sed -e 's/(TOP)/(dir.top)/g'
+ make-np-0 = make -C $(dir.top) -n -p
+ make-np-1 = sed -e 's/(TOP)/(dir.top)/g'
# Extract SHELL_OPT and SHELL_DEP from the top-most makefile and import
# them as vars here...
$(eval $(shell $(make-np-0) | grep -e '^SHELL_OPT ' | $(make-np-1)))
@@ -27,7 +26,7 @@ endif
# /shell.c
########################################################################
-EXPORTED_FUNCTIONS.fiddle := $(dir.tmp)/EXPORTED_FUNCTIONS.fiddle
+EXPORTED_FUNCTIONS.fiddle = $(dir.tmp)/EXPORTED_FUNCTIONS.fiddle
fiddle.emcc-flags = \
$(emcc.cflags) $(emcc_opt_full) \
--minify 0 \
@@ -52,12 +51,12 @@ fiddle.emcc-flags = \
# Flags specifically for debug builds of fiddle. Performance suffers
# greatly in debug builds.
-fiddle.emcc-flags.debug := $(fiddle.emcc-flags) \
+fiddle.emcc-flags.debug = $(fiddle.emcc-flags) \
-DSQLITE_DEBUG \
-DSQLITE_ENABLE_SELECTTRACE \
-DSQLITE_ENABLE_WHERETRACE
-fiddle.EXPORTED_FUNCTIONS.in := \
+fiddle.EXPORTED_FUNCTIONS.in = \
EXPORTED_FUNCTIONS.fiddle.in \
$(dir.api)/EXPORTED_FUNCTIONS.sqlite3-core \
$(dir.api)/EXPORTED_FUNCTIONS.sqlite3-extras
@@ -66,10 +65,7 @@ $(EXPORTED_FUNCTIONS.fiddle): $(MKDIR.bld) $(fiddle.EXPORTED_FUNCTIONS.in) \
$(MAKEFILE.fiddle)
sort -u $(fiddle.EXPORTED_FUNCTIONS.in) > $@
-fiddle.cses := $(dir.top)/shell.c $(sqlite3-wasm.c)
-
-fiddle: $(fiddle-module.js) $(fiddle-module.js.debug)
-fiddle.debug: $(fiddle-module.js.debug)
+fiddle.cses = $(dir.top)/shell.c $(sqlite3-wasm.c)
clean: clean-fiddle
clean-fiddle:
@@ -83,10 +79,9 @@ clean-fiddle:
all: fiddle
########################################################################
-# fiddle_remote is the remote destination for the fiddle app. It
-# must be a [user@]HOST:/path for rsync.
-# Note that the target "should probably" contain a symlink of
-# index.html -> fiddle.html.
+# fiddle_remote is the remote destination for the fiddle app. It must
+# be a [user@]HOST:/path for rsync. The target "should probably"
+# contain a symlink of index.html -> fiddle.html.
fiddle_remote ?=
ifeq (,$(fiddle_remote))
ifneq (,$(wildcard /home/stephan))
@@ -153,11 +148,6 @@ push-fiddle: fiddle
# because certain execution environments disallow those constructs.
# This flag is not strictly necessary, however.
#
-# -sWASM_BIGINT is UNTESTED but "should" allow the int64-using C APIs
-# to work with JS/wasm, insofar as the JS environment supports the
-# BigInt type. That support requires an extremely recent browser:
-# Safari didn't get that support until late 2020.
-#
# --no-entry: for compiling library code with no main(). If this is
# not supplied and the code has a main(), it is called as part of the
# module init process. Note that main() is #if'd out of shell.c
@@ -179,14 +169,15 @@ push-fiddle: fiddle
# minification makes little difference in terms of overall
# distributable size.
#
-# --minify 0: disables minification of the generated JS code,
-# regardless of optimization level. Minification of the JS has
-# minimal overall effect in the larger scheme of things and results
-# in JS files which can neither be edited nor viewed as text files in
-# Fossil (which flags them as binary because of their extreme line
-# lengths). Interestingly, whether or not the comments in the
-# generated JS file get stripped is unaffected by this setting and
-# depends entirely on the optimization level. Higher optimization
+# --minify 0: supposedly disables minification of the generated JS
+# code, regardless of optimization level, but that's not quite true:
+# search the main makefile for wasm-strip for details. Minification
+# of the JS has minimal overall effect in the larger scheme of things
+# and results in JS files which can neither be edited nor viewed as
+# text files in Fossil (which flags them as binary because of their
+# extreme line lengths). Interestingly, whether or not the comments
+# in the generated JS file get stripped is unaffected by this setting
+# and depends entirely on the optimization level. Higher optimization
# levels reduce the size of the JS considerably even without
# minification.
#
diff --git a/ext/wasm/fiddle/fiddle-worker.js b/ext/wasm/fiddle/fiddle-worker.js
index 27d915eb2..9c6cddb0f 100644
--- a/ext/wasm/fiddle/fiddle-worker.js
+++ b/ext/wasm/fiddle/fiddle-worker.js
@@ -163,9 +163,11 @@
fiddleModule.isDead = true;
return false;
}
- stdout("SQLite version", capi.sqlite3_libversion(),
- capi.sqlite3_sourceid().substr(0,19));
- stdout('Welcome to the "fiddle" shell.');
+ wMsg('sqlite-version', {
+ lib: capi.sqlite3_libversion(),
+ srcId: capi.sqlite3_sourceid()
+ });
+ stdout('Welcome to the "fiddle" shell. Tap the About button for more info.');
if(capi.sqlite3_vfs_find("opfs")){
stdout("\nOPFS is available. To open a persistent db, use:\n\n",
" .open file:name?vfs=opfs\n\nbut note that some",
@@ -281,6 +283,7 @@
stderr("'open' expects {buffer:Uint8Array} containing an uploaded db.");
return;
}
+ buffer.set([1,1], 18)/*force db out of WAL mode*/;
const fn = (
opt.filename
? opt.filename.split(/[/\\]/).pop().replace('"','_')
diff --git a/ext/wasm/fiddle/fiddle.js b/ext/wasm/fiddle/fiddle.js
index f0a89f25d..45ef69326 100644
--- a/ext/wasm/fiddle/fiddle.js
+++ b/ext/wasm/fiddle/fiddle.js
@@ -329,6 +329,21 @@
SF.worker = new Worker('fiddle-worker.js'+self.location.search);
SF.worker.onmessage = (ev)=>SF.runMsgHandlers(ev.data);
SF.addMsgHandler(['stdout', 'stderr'], (ev)=>SF.echo(ev.data));
+ SF.addMsgHandler('sqlite-version', (ev)=>{
+ const v = ev.data;
+ const a = E('#sqlite-version-link');
+ const li = v.srcId.split(' ')/*DATE TIME HASH*/;
+ a.setAttribute('href',
+ //'https://sqlite.org/src/timeline/?c='+li[2].substr(0,20)
+ 'https://sqlite.org/src/info/'+li[2].substr(0,20)
+ );
+ a.setAttribute('target', '_blank');
+ a.innerText = [
+ v.lib,
+ v.srcId.substr(0,34)
+ ].join(' ');
+ SF.echo("SQLite version",a.innerText);
+ });
/* querySelectorAll() proxy */
const EAll = function(/*[element=document,] cssSelector*/){
@@ -391,6 +406,19 @@
self.onSFLoaded();
});
+ /** Toggle the "About" view on and off. */
+ SF.toggleAbout = function(){
+ if( document.body.classList.toggle('about') ){
+ this.eAbout.classList.remove('hidden');
+ SF.eMainView.classList.add('hidden');
+ }else{
+ this.eAbout.classList.add('hidden');
+ SF.eMainView.classList.remove('hidden');
+ }
+ }.bind({
+ eAbout: E("#view-about")
+ });
+
/**
Performs all app initialization which must wait until after the
worker module is loaded. This function removes itself when it's
@@ -400,7 +428,16 @@
delete this.onSFLoaded;
// Unhide all elements which start out hidden
EAll('.initially-hidden').forEach((e)=>e.classList.remove('initially-hidden'));
+ SF.eMainView = EAll('.app-view:not(.hidden)')[0]
+ /** The main view widget. Initially the first non-hidden
+ .app-view element. */;
+ if( (new URL(self.location.href).searchParams).has('about') ){
+ SF.toggleAbout() /* for use while editing the About page */;
+ }
E('#btn-reset').addEventListener('click',()=>SF.resetDb());
+ EAll('#btn-about, #btn-about-close').forEach((e)=>{
+ e.addEventListener('click',()=>SF.toggleAbout())
+ });
const taInput = E('#input');
const btnClearIn = E('#btn-clear');
const selectExamples = E('#select-examples');
@@ -792,28 +829,33 @@
//SF.echo(null/*clear any output generated by the init process*/);
if(window.jQuery && window.jQuery.terminal){
/* Set up the terminal-style view... */
- const eTerm = window.jQuery('#view-terminal').empty();
- SF.jqTerm = eTerm.terminal(SF.dbExec.bind(SF),{
+ const eTerm = E('#view-terminal');
+ const jqeTerm = window.jQuery(eTerm).empty();
+ SF.jqTerm = jqeTerm.terminal(SF.dbExec.bind(SF),{
prompt: 'sqlite> ',
greetings: false /* note that the docs incorrectly call this 'greeting' */
});
/* Set up a button to toggle the views... */
- const head = E('header#titlebar');
+ const head = E('#titlebar-buttons');
const btnToggleView = document.createElement('button');
btnToggleView.appendChild(document.createTextNode("Toggle View"));
head.appendChild(btnToggleView);
+ const eOthers = EAll('.app-view:not(#view-terminal)');
+ const eOtherMain = E('#view-split');
btnToggleView.addEventListener('click',function f(){
- EAll('.app-view').forEach(e=>e.classList.toggle('hidden'));
+ document.body.classList.remove('about');
if(document.body.classList.toggle('terminal-mode')){
- ForceResizeKludge();
+ eOthers.forEach((e)=>e.classList.add('hidden'));
+ SF.eMainView = eTerm;
+ }else{
+ eTerm.classList.add('hidden');
+ SF.eMainView = eOtherMain;
}
+ SF.eMainView.classList.remove('hidden');
+ ForceResizeKludge();
}, false);
btnToggleView.click()/*default to terminal view*/;
}
- SF.echo('This experimental app is provided in the hope that it',
- 'may prove interesting or useful but is not an officially',
- 'supported deliverable of the sqlite project. It is subject to',
- 'any number of changes or outright removal at any time.\n');
const urlParams = new URL(self.location.href).searchParams;
SF.dbExec(urlParams.get('sql') || null);
delete ForceResizeKludge.$disabled;
diff --git a/ext/wasm/fiddle/index.html b/ext/wasm/fiddle/index.html
index ca6788ef0..019612954 100644
--- a/ext/wasm/fiddle/index.html
+++ b/ext/wasm/fiddle/index.html
@@ -5,16 +5,27 @@
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>SQLite3 Fiddle</title>
<link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon">
- <!-- to add a toggleable terminal-style view, uncomment the following
- two lines and ensure that these files are on the web server. -->
+ <!--
+ To add a terminal-style view using jquery.terminal[^1],
+ uncomment the following two HTML lines and ensure that these
+ files are on the web server.
+
+ jquery-bundle.min.js is a concatenation of jquery.min.js from
+ [^2] and jquery.terminal.min.js from [^1].
+ jquery.terminal.min.css is from [^1].
+
+ [^1]: https://github.com/jcubic/jquery.terminal
+ [^2]: https://jquery.com
+ -->
<!--script src="jqterm/jqterm-bundle.min.js"></script>
- <link rel="stylesheet" href="jqterm/jquery.terminal.min.css"/-->
+ <link rel="stylesheet" href="jqterm/jquery.terminal.min.css"-->
<style>
/* The following styles are for app-level use. */
:root {
--sqlite-blue: #044a64;
- --textarea-color1: #044a64;
+ --textarea-color1: #000 /*044a64 is nice too*/;
--textarea-color2: white;
+ --size: 1.25 /* used by jqterm to calculate font size and the default is too tiny.*/;
}
textarea {
font-family: monospace;
@@ -170,6 +181,17 @@
display: flex;
flex-direction: column-reverse;
}
+ #view-about {
+ flex: auto;
+ overflow: auto;
+ }
+ #view-about h1:first-child {
+ display: flex;
+ }
+ #view-about h1:first-child > button {
+ align-self: center;
+ margin-left: 1em;
+ }
/* emcscript-related styling, used during the module load/intialization processes... */
.emscripten { padding-right: 0; margin-left: auto; margin-right: auto; display: block; }
@@ -200,8 +222,11 @@
<body>
<header id='titlebar'>
<span>SQLite3 Fiddle</span>
- <span class='powered-by'>Powered by
- <a href='https://sqlite.org'>SQLite3</a></span>
+ <span id='titlebar-buttons'>
+ <span class='powered-by'>Powered by
+ <a href='https://sqlite.org'>SQLite3</a></span>
+ <button id='btn-about'>About...</button>
+ </span>
</header>
<!-- emscripten bits -->
<figure id="module-spinner">
@@ -215,7 +240,7 @@
</figure>
<div class="emscripten" id="module-status">Downloading...</div>
<div class="emscripten">
- <progress value="0" max="100" id="module-progress" hidden='1'></progress>
+ <progress value="0" max="100" id="module-progress" hidden='1'></progress>
</div><!-- /emscripten bits -->
<div id='view-terminal' class='app-view hidden initially-hidden'>
@@ -295,8 +320,54 @@
<div><textarea id="output" readonly
placeholder="Shell output."></textarea></div>
</fieldset>
- </div>
+ </div><!-- #main-wrapper -->
</div> <!-- #view-split -->
- <script src="fiddle.js"></script>
+
+<div class='hidden app-view' id='view-about'>
+ <h1>About SQLite Fiddle <button id='btn-about-close'>close</button></h1>
+
+ <p>Fiddle is a JavaScript application wrapping a <a href='https://webassembly.org'>WebAssembly</a>
+ build of <a href="https://sqlite.org/cli.html">the SQLite CLI shell</a>, slightly
+ modified to account for browser-based user input. Aside from the different layout,
+ it works just like the CLI shell. This copy was built with SQLite version
+ <a id='sqlite-version-link'></a>.
+ </p>
+
+ <p>This app is provided in the hope that it may prove interesting or useful
+ but it is not an officially-supported deliverable of the SQLite project.
+ It is subject to any number of changes or outright removal at any time.
+ That said, for as long as it's online we do respond to support requests
+ in <a href="https://sqlite.org/forum">the SQLite forum</a>.
+ </p>
+
+ <p>This app runs on your device. After loading, it does not interact
+ with the remote server at all. Similarly, this app does not use any
+ HTTP cookies.</p>
+
+ <p>Fiddle databases are transient in-memory databases unless they
+ specifically use a persistent storage option (if available, help
+ text in the SQL result output area will indicate how to use
+ persistent storage when this app starts up).
+ </p>
+
+ <h1>Usage Summary</h1>
+
+ <ul>
+ <li>Input can be run with either the Run button or tapping one of
+ Ctrl-enter or Shift-enter from within the text input field.
+ If a portion of the input field is selected, only that portion will be run.
+ </li>
+ <li>The various toggle checkboxes can be used to tweak the layout.
+ Those toggles are persistent if the JS environment allows it.</li>
+ <li>Databases can be imported and exported using the buttons in
+ the Options toolbar. No specific limit for imported database
+ sizes is imposed, but large databases may cause it to fail with
+ an out-of-memory error.</li>
+ <!--li></li-->
+ </ul>
+
+</div><!-- #view-about -->
+
+<script src="fiddle.js"></script>
</body>
</html>
diff --git a/ext/wasm/mkwasmbuilds.c b/ext/wasm/mkwasmbuilds.c
index 8aa29c0fe..d33a10c01 100644
--- a/ext/wasm/mkwasmbuilds.c
+++ b/ext/wasm/mkwasmbuilds.c
@@ -11,18 +11,17 @@
*************************************************************************
**
** This app's single purpose is to emit parts of the Makefile code for
-** building sqlite3's WASM build. The main motivation is to generate
-** code which "can" be created via GNU Make's eval command but is
+** sqlite3's canonical WASM build. The main motivation is to generate
+** code which "could" be created via GNU Make's eval command but is
** highly illegible when constructed that way. Attempts to write this
-** app in Bash and TCL have suffered from the problem that both
-** require escaping $ symbols, making the resulting script code as
-** illegible as the eval spaghetti we want to get away from. Writing
-** it in C is, somewhat surprisingly, _slightly_ less illegible than
-** writing it in bash, tcl, or native Make code.
+** app in Bash and TCL have suffered from the problem that those
+** languages require escaping $ symbols, making the resulting script
+** code as illegible as the eval spaghetti we want to get away
+** from. Maintaining it in C is, somewhat surprisingly, _slightly_
+** less illegible than writing it in bash, tcl, or native Make code.
**
** The emitted makefile code is not standalone - it depends on
** variables and $(call)able functions from the main makefile.
-**
*/
#undef NDEBUG
@@ -33,38 +32,145 @@
#define pf printf
#define ps puts
-/* Very common printf() args combo. */
-#define zNM zName, zMode
/*
-** Valid names for the zName arguments.
+** Valid build names. Each build is a combination of one of these and
+** one of JS_BUILD_MODES, but only certain combinations are legal.
+** This macro and JS_BUILD_MODES exist solely for documentation
+** purposes: they are not expanded into code anywhere.
*/
#define JS_BUILD_NAMES sqlite3 sqlite3-wasmfs
/*
-** Valid names for the zMode arguments of the "sqlite3" build. For the
-** "sqlite3-wasmfs" build, only "esm" (ES6 Module) is legal.
+** Valid build modes. For the "sqlite3-wasmfs" build, only "esm" (ES6
+** Module) is legal.
*/
#define JS_BUILD_MODES vanilla esm bundler-friendly node
-/* Separator to help eyeballs find the different sections */
+
+/* Separator to help eyeballs find the different output sections */
static const char * zBanner =
"\n########################################################################\n";
/*
+** Flags for use with BuildDef::flags and the 3rd argument to
+** mk_pre_post().
+**
+** Maintenance reminder: do not combine flags within this enum,
+** e.g. LIBMODE_BUNDLER_FRIENDLY=0x02|LIBMODE_ESM, as that will lead
+** to breakage in some of the flag checks.
+*/
+enum LibModeFlags {
+ /* Indicates an ESM module build. */
+ LIBMODE_ESM = 0x01,
+ /* Indicates a "bundler-friendly" build mode. */
+ LIBMODE_BUNDLER_FRIENDLY = 0x02,
+ /* Indicates that this build is unsupported. Such builds are not
+ ** added to the 'all' target. The unsupported builds exist primarily
+ ** for experimentation's sake. */
+ LIBMODE_UNSUPPORTED = 0x04,
+ /* Indicates a node.js-for-node.js build (untested and
+ ** unsupported). */
+ LIBMODE_NODEJS = 0x08,
+ /* Indicates a wasmfs build (untested and unsupported). */
+ LIBMODE_WASMFS = 0x10
+};
+
+/*
+** Info needed for building one combination of JS_BUILD_NAMES and
+** JS_BUILD_MODE, noting that only a subset of those combinations are
+** legal/sensical.
+*/
+struct BuildDef {
+ const char *zName; /* Name from JS_BUILD_NAMES */
+ const char *zMode; /* Name from JS_BUILD_MODES */
+ int flags; /* Flags from LibModeFlags */
+ const char *zJsOut; /* Name of generated sqlite3.js/.mjs */
+ /* TODO: dynamically determine zJsOut based on zName, zMode, and
+ flags. */
+ const char *zCmppD; /* Extra -D... flags for c-pp */
+ const char *zEmcc; /* Extra flags for emcc */
+};
+typedef struct BuildDef BuildDef;
+
+/*
+** The set of WASM builds for the library (as opposed to the apps
+** (fiddle, speedtest1)). This array must end with an empty sentinel
+** entry. Their order is mostly insignificant, but some makefile vars
+** used by some builds are set up by prior builds. Because of that,
+** the (sqlite3, vanilla), (sqlite3, esm), and (sqlite3,
+** bundler-friendly) builds should be defined first (in that order).
+*/
+const BuildDef aBuildDefs[] = {
+ {/* Core build */
+ "sqlite3", "vanilla", 0, "$(sqlite3.js)", 0, 0},
+
+ {/* Core ESM */
+ "sqlite3", "esm", LIBMODE_ESM, "$(sqlite3.mjs)",
+ "-Dtarget=es6-module", 0},
+
+ {/* Core bundler-friendly build. Untested and "not really"
+ ** supported, but required by the downstream npm subproject.
+ ** Testing these would require special-purpose node-based tools and
+ ** custom test apps. Or we can pass them off as-is to the npm
+ ** subproject and they spot failures pretty quickly ;). */
+ "sqlite3", "bundler-friendly",
+ LIBMODE_BUNDLER_FRIENDLY | LIBMODE_ESM,
+ "$(dir.dout)/sqlite3-bundler-friendly.mjs",
+ "$(c-pp.D.sqlite3-esm) -Dtarget=es6-bundler-friendly", 0},
+
+ {/* node.js mode. Untested and unsupported. */
+ "sqlite3", "node", LIBMODE_UNSUPPORTED | LIBMODE_NODEJS,
+ "$(dir.dout)/sqlite3-node.mjs",
+ "$(c-pp.D.sqlite3-bundler-friendly) -Dtarget=node", 0},
+
+ {/* Wasmfs build. Fully unsupported and largely untested. */
+ "sqlite3-wasmfs", "esm" ,
+ LIBMODE_UNSUPPORTED | LIBMODE_WASMFS | LIBMODE_ESM,
+ "$(dir.wasmfs)/sqlite3-wasmfs.mjs",
+ "$(c-pp.D.sqlite3-bundler-friendly) -Dwasmfs",
+ "-sEXPORT_ES6 -sUSE_ES6_IMPORT_META"},
+
+ {/*End-of-list sentinel*/0,0,0,0,0,0}
+};
+
+/*
** Emits common vars needed by the rest of the emitted code (but not
** needed by makefile code outside of these generated pieces).
*/
static void mk_prologue(void){
+ /* A 0-terminated list of makefile vars which we expect to have been
+ ** set up by this point in the build process. */
+ char const * aRequiredVars[] = {
+ "dir.top",
+ "dir.api", "dir.dout", "dir.tmp",
+ "sqlite3-license-version.js",
+ "MAKEFILE", "MAKEFILE_LIST",
+ /* Fiddle... */
+ "dir.fiddle", "dir.fiddle-debug",
+ "MAKEFILE.fiddle",
+ "EXPORTED_FUNCTIONS.fiddle",
+ /*"just-testing",*/
+ 0
+ };
+ char const * zVar;
+ int i;
+ pf("%s# Build setup sanity checks...\n", zBanner);
+ for( i = 0; (zVar = aRequiredVars[i]); ++i ){
+ pf("ifeq (,$(%s))\n", zVar);
+ pf(" $(error build process error: expecting make var $$(%s) to "
+ "have been set up by now)\n", zVar);
+ ps("endif");
+ }
pf("%s", zBanner);
ps("# extern-post-js* and extern-pre-js* are files for use with");
ps("# Emscripten's --extern-pre-js and --extern-post-js flags.");
- ps("extern-pre-js.js := $(dir.api)/extern-pre-js.js");
- ps("extern-post-js.js.in := $(dir.api)/extern-post-js.c-pp.js");
+ ps("extern-pre-js.js = $(dir.api)/extern-pre-js.js");
+ ps("extern-post-js.js.in = $(dir.api)/extern-post-js.c-pp.js");
ps("# Emscripten flags for --[extern-][pre|post]-js=... for the");
ps("# various builds.");
- ps("pre-post-common.flags := --extern-pre-js=$(sqlite3-license-version.js)");
- ps("# pre-post-jses.deps.* = a list of dependencies for the");
- ps("# --[extern-][pre/post]-js files.");
- ps("pre-post-jses.deps.common := $(extern-pre-js.js) $(sqlite3-license-version.js)");
+ ps("pre-post-common.flags = --extern-pre-js=$(sqlite3-license-version.js)");
+ ps("# pre-post-jses.deps.* = a list of dependencies for the\n"
+ "# --[extern-][pre/post]-js files.");
+ ps("pre-post-jses.deps.common = $(extern-pre-js.js) $(sqlite3-license-version.js)");
{
/* SQLITE.CALL.WASM-OPT = shell code to run $(1) (source wasm file
@@ -127,7 +233,7 @@ static void mk_prologue(void){
"\t\techo -n 'After wasm-opt: '; \\\n"
"\t\tls -l $(1); \\\n"
"\telse \\\n"
- "\t\techo 'WARNING: ignoring wasm-opt failure'; \\\n"
+ "\t\techo 'WARNING: ignoring wasm-opt failure for $(1)'; \\\n"
"\tfi\n",
zOptFlags
);
@@ -137,52 +243,32 @@ static void mk_prologue(void){
}
/*
-** Flags for use with the 3rd argument to mk_pre_post() and
-** mk_lib_mode().
-**
-** Maintenance reminder: do not combine flags within this enum,
-** e.g. LIBMODE_BUNDLER_FRIENDLY=0x02|LIBMODE_ESM, as that will lead
-** to breakage in some of the flag checks.
-*/
-enum LibModeFlags {
- /* Indicates an ESM module build. */
- LIBMODE_ESM = 0x01,
- /* Indicates a "bundler-friendly" build mode. */
- LIBMODE_BUNDLER_FRIENDLY = 0x02,
- /* Indicates to _not_ add this build to the 'all' target. */
- LIBMODE_DONT_ADD_TO_ALL = 0x04,
- /* Indicates a node.js-for-node.js build (untested and
- ** unsupported). */
- LIBMODE_NODEJS = 0x08,
- /* Indicates a wasmfs build (untested and unsupported). */
- LIBMODE_WASMFS = 0x10
-};
-
-/*
** Emits makefile code for setting up values for the --pre-js=FILE,
** --post-js=FILE, and --extern-post-js=FILE emcc flags, as well as
** populating those files.
*/
static void mk_pre_post(const char *zName /* build name */,
const char *zMode /* build mode */,
- int flags /* LIBMODE_... mask */,
const char *zCmppD /* optional -D flags for c-pp for the
** --pre/--post-js files. */){
+/* Very common printf() args combo. */
+#define zNM zName, zMode
+
pf("%s# Begin --pre/--post flags for %s-%s\n", zBanner, zNM);
- pf("c-pp.D.%s-%s := %s\n", zNM, zCmppD ? zCmppD : "");
+ pf("c-pp.D.%s-%s = %s\n", zNM, zCmppD ? zCmppD : "");
pf("pre-post-%s-%s.flags ?=\n", zNM);
/* --pre-js=... */
- pf("pre-js.js.%s-%s := $(dir.tmp)/pre-js.%s-%s.js\n",
+ pf("pre-js.js.%s-%s = $(dir.tmp)/pre-js.%s-%s.js\n",
zNM, zNM);
- pf("$(pre-js.js.%s-%s): $(MAKEFILE_LIST)\n", zNM);
+ pf("$(pre-js.js.%s-%s): $(MAKEFILE_LIST) $(sqlite3-license-version.js)\n", zNM);
#if 1
pf("$(eval $(call SQLITE.CALL.C-PP.FILTER,$(pre-js.js.in),$(pre-js.js.%s-%s),"
"$(c-pp.D.%s-%s)))\n", zNM, zNM);
#else
/* This part is needed if/when we re-enable the custom
** Module.instantiateModule() impl in api/pre-js.c-pp.js. */
- pf("pre-js.js.%s-%s.intermediary := $(dir.tmp)/pre-js.%s-%s.intermediary.js\n",
+ pf("pre-js.js.%s-%s.intermediary = $(dir.tmp)/pre-js.%s-%s.intermediary.js\n",
zNM, zNM);
pf("$(eval $(call SQLITE.CALL.C-PP.FILTER,$(pre-js.js.in),$(pre-js.js.%s-%s.intermediary),"
"$(c-pp.D.%s-%s) -Dcustom-Module.instantiateModule))\n", zNM, zNM);
@@ -200,17 +286,17 @@ static void mk_pre_post(const char *zName /* build name */,
#endif
/* --post-js=... */
- pf("post-js.js.%s-%s := $(dir.tmp)/post-js.%s-%s.js\n", zNM, zNM);
+ pf("post-js.js.%s-%s = $(dir.tmp)/post-js.%s-%s.js\n", zNM, zNM);
pf("$(eval $(call SQLITE.CALL.C-PP.FILTER,$(post-js.js.in),"
"$(post-js.js.%s-%s),$(c-pp.D.%s-%s)))\n", zNM, zNM);
/* --extern-post-js=... */
- pf("extern-post-js.js.%s-%s := $(dir.tmp)/extern-post-js.%s-%s.js\n", zNM, zNM);
+ pf("extern-post-js.js.%s-%s = $(dir.tmp)/extern-post-js.%s-%s.js\n", zNM, zNM);
pf("$(eval $(call SQLITE.CALL.C-PP.FILTER,$(extern-post-js.js.in),$(extern-post-js.js.%s-%s),"
"$(c-pp.D.%s-%s)))\n", zNM, zNM);
/* Combined flags for use with emcc... */
- pf("pre-post-common.flags.%s-%s := "
+ pf("pre-post-common.flags.%s-%s = "
"$(pre-post-common.flags) "
"--post-js=$(post-js.js.%s-%s) "
"--extern-post-js=$(extern-post-js.js.%s-%s)\n", zNM, zNM, zNM);
@@ -219,30 +305,29 @@ static void mk_pre_post(const char *zName /* build name */,
"--pre-js=$(pre-js.js.%s-%s)\n", zNM, zNM, zNM);
/* Set up deps... */
- pf("pre-post-jses.%s-%s.deps := $(pre-post-jses.deps.common) "
+ pf("pre-post-jses.%s-%s.deps = $(pre-post-jses.deps.common) "
"$(post-js.js.%s-%s) $(extern-post-js.js.%s-%s)\n",
zNM, zNM, zNM);
- pf("pre-post-%s-%s.deps := $(pre-post-jses.%s-%s.deps) $(dir.tmp)/pre-js.%s-%s.js\n",
+ pf("pre-post-%s-%s.deps = $(pre-post-jses.%s-%s.deps) $(dir.tmp)/pre-js.%s-%s.js\n",
zNM, zNM, zNM);
pf("# End --pre/--post flags for %s-%s%s", zNM, zBanner);
+#undef zNM
}
/*
** Emits rules for the fiddle builds.
-**
*/
-static void mk_fiddle(){
+static void mk_fiddle(void){
int i = 0;
- mk_pre_post("fiddle-module","vanilla", 0, 0);
+ mk_pre_post("fiddle-module","vanilla", 0);
for( ; i < 2; ++i ){
+ /* 0==normal, 1==debug */
const char *zTail = i ? ".debug" : "";
const char *zDir = i ? "$(dir.fiddle-debug)" : "$(dir.fiddle)";
pf("%s# Begin fiddle%s\n", zBanner, zTail);
- pf("fiddle-module.js%s := %s/fiddle-module.js\n", zTail, zDir);
- pf("fiddle-module.wasm%s := "
- "$(subst .js,.wasm,$(fiddle-module.js%s))\n", zTail, zTail);
+ pf("fiddle-module.js%s = %s/fiddle-module.js\n", zTail, zDir);
pf("$(fiddle-module.js%s):%s $(MAKEFILE_LIST) $(MAKEFILE.fiddle) "
"$(EXPORTED_FUNCTIONS.fiddle) "
"$(fiddle.cses) $(pre-post-fiddle-module-vanilla.deps) "
@@ -254,7 +339,9 @@ static void mk_fiddle(){
pf("\t$(bin.emcc) -o $@ $(fiddle.emcc-flags%s) "
"$(pre-post-fiddle-module-vanilla.flags) $(fiddle.cses)\n",
zTail);
- pf("\t$(maybe-wasm-strip) $(fiddle-module.wasm%s)\n", zTail);
+ ps("\t@chmod -x $(basename $@).wasm");
+ ps("\t@$(maybe-wasm-strip) $(basename $@).wasm");
+ ps("\t@$(SQLITE.strip-createExportWrapper)");
pf("\t@cp -p $(SOAP.js) $(dir $@)\n");
if( 1==i ){/*fiddle.debug*/
pf("\tcp -p $(dir.fiddle)/index.html "
@@ -263,13 +350,13 @@ static void mk_fiddle(){
"$(dir $@)\n");
}
pf("\t@for i in %s/*.*js %s/*.html %s/*.wasm; do \\\n"
- "\t\ttest -f $${i} || continue; \\\n"
+ "\t\ttest -f $${i} || continue; \\\n"
"\t\tgzip < $${i} > $${i}.gz; \\\n"
"\tdone\n", zDir, zDir, zDir);
if( 0==i ){
ps("fiddle: $(fiddle-module.js)");
}else{
- ps("fiddle-debug: $(fiddle-module-debug.js)");
+ ps("fiddle-debug: $(fiddle-module.js.debug)");
}
pf("# End fiddle%s%s", zTail, zBanner);
}
@@ -280,138 +367,110 @@ static void mk_fiddle(){
** by the combination of zName and zMode, each of which must be values
** from JS_BUILD_NAMES resp. JS_BUILD_MODES.
*/
-static void mk_lib_mode(const char *zName /* build name */,
- const char *zMode /* build mode */,
- int flags /* LIBMODE_... mask */,
- const char *zApiJsOut /* name of generated sqlite3-api.js/.mjs */,
- const char *zJsOut /* name of generated sqlite3.js/.mjs */,
- const char *zCmppD /* extra -D flags for c-pp */,
- const char *zEmcc /* extra flags for emcc */){
+static void mk_lib_mode(const BuildDef * pB){
const char * zWasmOut = "$(basename $@).wasm"
/* The various targets named X.js or X.mjs (zJsOut) also generate
** X.wasm, and we need that part of the name to perform some
** post-processing after Emscripten generates X.wasm. */;
- assert( zName );
- assert( zMode );
- assert( zApiJsOut );
- assert( zJsOut );
- if( !zCmppD ) zCmppD = "";
- if( !zEmcc ) zEmcc = "";
+ assert( pB->zName );
+ assert( pB->zMode );
+ assert( pB->zJsOut );
+/* Very common printf() args combo. */
+#define zNM pB->zName, pB->zMode
- pf("%s# Begin build [%s-%s]\n", zBanner, zNM);
- pf("# zApiJsOut=%s\n# zJsOut=%s\n# zCmppD=%s\n", zApiJsOut, zJsOut, zCmppD);
- pf("$(info Setting up build [%s-%s]: %s)\n", zNM, zJsOut);
- mk_pre_post(zNM, flags, zCmppD);
+ pf("%s# Begin build [%s-%s]. flags=0x%02x\n", zBanner, zNM, pB->flags);
+ pf("# zJsOut=%s\n# zCmppD=%s\n", pB->zJsOut,
+ pB->zCmppD ? pB->zCmppD : "<none>");
+ pf("$(info Setting up build [%s-%s]: %s)\n", zNM, pB->zJsOut);
+ mk_pre_post(zNM, pB->zCmppD);
pf("\nemcc.flags.%s.%s ?=\n", zNM);
- if( zEmcc[0] ){
- pf("emcc.flags.%s.%s += %s\n", zNM, zEmcc);
+ if( pB->zEmcc && pB->zEmcc[0] ){
+ pf("emcc.flags.%s.%s += %s\n", zNM, pB->zEmcc);
}
- pf("$(eval $(call SQLITE.CALL.C-PP.FILTER, $(sqlite3-api.js.in), %s, %s))\n",
- zApiJsOut, zCmppD);
- /* target zJsOut */
- pf("%s: %s $(MAKEFILE_LIST) $(sqlite3-wasm.cfiles) $(EXPORTED_FUNCTIONS.api) "
+ /* target pB->zJsOut */
+ pf("%s: $(MAKEFILE_LIST) $(sqlite3-wasm.cfiles) $(EXPORTED_FUNCTIONS.api) "
"$(pre-post-%s-%s.deps) "
"$(sqlite3-api.ext.jses)"
/* ^^^ maintenance reminder: we set these as deps so that they
- get copied into place early. That allows the developer to
- reload the base-most test pages while the later-stage builds
- are still compiling, which is especially helpful when running
- builds with long build times (like -Oz). */
+ ** get copied into place early. That allows the developer to
+ ** reload the base-most test pages while the later-stage builds
+ ** are still compiling, which is especially helpful when running
+ ** builds with long build times (like -Oz). */
"\n",
- zJsOut, zApiJsOut, zNM);
+ pB->zJsOut, zNM);
pf("\t@echo \"Building $@ ...\"\n");
+ if( LIBMODE_UNSUPPORTED & pB->flags ){
+ ps("\t@echo 'ACHTUNG: $@ is an unsupported build. "
+ "Use at your own risk.'");
+ }
pf("\t$(bin.emcc) -o $@ $(emcc_opt_full) $(emcc.flags) \\\n");
- pf("\t\t$(emcc.jsflags) -sENVIRONMENT=$(emcc.environment.%s) \\\n", zMode);
+ pf("\t\t$(emcc.jsflags) -sENVIRONMENT=$(emcc.environment.%s) \\\n",
+ pB->zMode);
pf("\t\t$(pre-post-%s-%s.flags) \\\n", zNM);
- pf("\t\t$(emcc.flags.%s) $(emcc.flags.%s.%s) \\\n", zName, zNM);
+ pf("\t\t$(emcc.flags.%s) $(emcc.flags.%s.%s) \\\n", pB->zName, zNM);
pf("\t\t$(cflags.common) $(SQLITE_OPT) \\\n"
"\t\t$(cflags.%s) $(cflags.%s.%s) \\\n"
- "\t\t$(cflags.wasm_extra_init) $(sqlite3-wasm.cfiles)\n", zName, zNM);
- if( (LIBMODE_ESM & flags) || (LIBMODE_NODEJS & flags) ){
+ "\t\t$(cflags.wasm_extra_init) $(sqlite3-wasm.cfiles)\n", pB->zName, zNM);
+ if( (LIBMODE_ESM & pB->flags) || (LIBMODE_NODEJS & pB->flags) ){
/* TODO? Replace this $(call) with the corresponding makefile
** code. OTOH, we also use this $(call) in the speedtest1-wasmfs
** build, which is not part of the rules emitted by this
** program. */
pf("\t@$(call SQLITE.CALL.xJS.ESM-EXPORT-DEFAULT,1,%d)\n",
- (LIBMODE_WASMFS & flags) ? 1 : 0);
+ (LIBMODE_WASMFS & pB->flags) ? 1 : 0);
}
- pf("\t@chmod -x %s; \\\n"
- "\t\t$(maybe-wasm-strip) %s;\n",
- zWasmOut, zWasmOut);
+ pf("\t@chmod -x %s\n", zWasmOut);
+ pf("\t@$(maybe-wasm-strip) %s\n", zWasmOut);
pf("\t@$(call SQLITE.CALL.WASM-OPT,%s)\n", zWasmOut);
- pf("\t@sed -i -e '/^var _sqlite3.*createExportWrapper/d' %s || exit; \\\n"
- /* ^^^^^^ reminder: Mac/BSD sed has no -i flag */
- "\t\techo 'Stripped out createExportWrapper() parts.'\n",
- zJsOut) /* Our JS code installs bindings of each WASM export. The
- generated Emscripten JS file does the same using its
- own framework, but we don't use those results and can
- speed up lib init, and reduce memory cost
- considerably, by stripping them out. */;
+ ps("\t@$(SQLITE.strip-createExportWrapper)");
/*
- ** The above $(bin.emcc) call will write zJsOut and will create a
- ** like-named .wasm file (zWasmOut). That .wasm file name gets
- ** hard-coded into zJsOut so we need to, for some cases, patch
- ** zJsOut to use the name sqlite3.wasm instead. Note that the
+ ** The above $(bin.emcc) call will write pB->zJsOut, a.k.a. $@, and
+ ** will create a like-named .wasm file (zWasmOut). That .wasm file
+ ** name gets hard-coded into $@ so we need to, for some cases, patch
+ ** zJsOut to use the name sqlite3.wasm instead. Note that the
** resulting .wasm file is identical for all builds for which zEmcc
** is empty.
*/
- if( (LIBMODE_BUNDLER_FRIENDLY & flags)
- || (LIBMODE_NODEJS & flags) ){
- pf("\t@echo 'Patching $@ for %s.wasm...'; \\\n", zName);
+ if( (LIBMODE_BUNDLER_FRIENDLY & pB->flags) ){
+ pf("\t@echo 'Patching $@ for %s.wasm...'; \\\n", pB->zName);
pf("\t\trm -f %s; \\\n", zWasmOut);
pf("\t\tsed -i -e 's/%s-%s.wasm/%s.wasm/g' $@ || exit;\n",
- /* ^^^^^^ reminder: Mac/BSD sed has no -i flag */
- zNM, zName);
+ /* ^^^^^^ reminder: Mac/BSD sed has no -i flag but this
+ ** build process explicitly requires a Linux system. */
+ zNM, pB->zName);
pf("\t@ls -la $@\n");
- if( LIBMODE_BUNDLER_FRIENDLY & flags ){
+ if( LIBMODE_BUNDLER_FRIENDLY & pB->flags ){
/* Avoid a 3rd occurrence of the bug fixed by 65798c09a00662a3,
** which was (in two cases) caused by makefile refactoring and
** not recognized until after a release was made with the broken
- ** sqlite3-bundler-friendly.mjs: */
+ ** sqlite3-bundler-friendly.mjs (which is used by the npm
+ ** subproject but is otherwise untested/unsupported): */
pf("\t@if grep -e '^ *importScripts(' $@; "
"then echo 'ERROR: bug fixed in 65798c09a00662a3 has re-appeared'; "
"exit 1; fi;\n");
}
-
}else{
pf("\t@ls -la %s $@\n", zWasmOut);
}
- if( 0==(LIBMODE_DONT_ADD_TO_ALL & flags) ){
- pf("all: %s\n", zJsOut);
+ if( 0==(LIBMODE_UNSUPPORTED & pB->flags) ){
+ pf("all: %s\n", pB->zJsOut);
}
pf("# End build [%s-%s]%s", zNM, zBanner);
+#undef zNM
}
int main(void){
int rc = 0;
+ const BuildDef *pB = &aBuildDefs[0];
pf("# What follows was GENERATED by %s. Edit at your own risk.\n", __FILE__);
mk_prologue();
- mk_lib_mode("sqlite3", "vanilla", 0,
- "$(sqlite3-api.js)", "$(sqlite3.js)", 0, 0);
- mk_lib_mode("sqlite3", "esm", LIBMODE_ESM,
- "$(sqlite3-api.mjs)", "$(sqlite3.mjs)",
- "-Dtarget=es6-module", 0);
- mk_lib_mode("sqlite3", "bundler-friendly",
- LIBMODE_BUNDLER_FRIENDLY | LIBMODE_ESM,
- "$(sqlite3-api-bundler-friendly.mjs)",
- "$(sqlite3-bundler-friendly.mjs)",
- "$(c-pp.D.sqlite3-esm) -Dtarget=es6-bundler-friendly", 0);
- mk_lib_mode("sqlite3" , "node",
- LIBMODE_NODEJS | LIBMODE_DONT_ADD_TO_ALL,
- "$(sqlite3-api-node.mjs)", "$(sqlite3-node.mjs)",
- "$(c-pp.D.sqlite3-bundler-friendly) -Dtarget=node", 0);
- mk_lib_mode("sqlite3-wasmfs", "esm" ,
- LIBMODE_WASMFS | LIBMODE_ESM | LIBMODE_DONT_ADD_TO_ALL,
- /* The sqlite3-wasmfs build is optional and needs to be invoked
- ** conditionally using info we don't have here. */
- "$(sqlite3-api-wasmfs.mjs)", "$(sqlite3-wasmfs.mjs)",
- "$(c-pp.D.sqlite3-bundler-friendly) -Dwasmfs",
- "-sEXPORT_ES6 -sUSE_ES6_IMPORT_META");
-
+ for( ; pB->zName; ++pB ){
+ mk_lib_mode( pB );
+ }
mk_fiddle();
- mk_pre_post("speedtest1","vanilla", 0, 0);
- mk_pre_post("speedtest1-wasmfs","esm", 0,
+ mk_pre_post("speedtest1","vanilla", 0);
+ mk_pre_post("speedtest1-wasmfs","esm",
"$(c-pp.D.sqlite3-bundler-friendly) -Dwasmfs");
return rc;
}
diff --git a/ext/wasm/speedtest1.html b/ext/wasm/speedtest1.html
index 3bad62006..a841c7fa0 100644
--- a/ext/wasm/speedtest1.html
+++ b/ext/wasm/speedtest1.html
@@ -23,11 +23,10 @@
</figure>
<div class="emscripten" id="module-status">Downloading...</div>
<div class="emscripten">
- <progress value="0" max="100" id="module-progress" hidden='1'></progress>
+ <progress value="0" max="100" id="module-progress" hidden='1'></progress>
</div><!-- /emscripten bits -->
<div class='warning'>This page starts running the main exe when it loads, which will
- block the UI until it finishes! Adding UI controls to manually configure and start it
- are TODO.</div>
+ block the UI until it finishes!</div>
</div>
<div class='warning'>Achtung: running it with the dev tools open may
<em>drastically</em> slow it down. For faster results, keep the dev
@@ -118,7 +117,7 @@
argv.push("--vfs", vfs);
log2('',"Using VFS:",vfs);
if('kvvfs' === vfs){
- forceSize = 2 /* 5 uses approx. 4.96mb */;
+ forceSize = 2 /* >2 is too big as of mid-2025 */;
dbFile = 'session';
log2('warning',"kvvfs VFS: forcing --size",forceSize,
"and filename '"+dbFile+"'.");
diff --git a/ext/wasm/tester1.c-pp.js b/ext/wasm/tester1.c-pp.js
index 5b94c7c05..dd70024ab 100644
--- a/ext/wasm/tester1.c-pp.js
+++ b/ext/wasm/tester1.c-pp.js
@@ -41,7 +41,7 @@
ES6 worker module build:
- ./c-pp -f tester1.c-pp.js -o tester1-esm.js -Dtarget=es6-module
+ ./c-pp -f tester1.c-pp.js -o tester1-esm.mjs -Dtarget=es6-module
*/
//#if target=es6-module
import {default as sqlite3InitModule} from './jswasm/sqlite3.mjs';
@@ -221,7 +221,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
else if(filter instanceof Function) pass = filter(err);
else if('string' === typeof filter) pass = (err.message === filter);
if(!pass){
- throw new Error(msg || ("Filter rejected this exception: "+err.message));
+ throw new Error(msg || ("Filter rejected this exception: <<"+err.message+">>"));
}
return this;
},
@@ -1209,6 +1209,104 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
}
}
})
+
+ ////////////////////////////////////////////////////////////////////
+ .t({
+ name: "oo1.DB/Stmt.wrapDbHandle()",
+ test: function(sqlite3){
+ /* Maintenance reminder: this function is early in the list to
+ demonstrate that the wrappers for this.db created by this
+ function do not interfere with downstream tests, e.g. by
+ closing this.db.pointer. */
+ //sqlite3.config.debug("Proxying",this.db);
+ const misuseMsg = "SQLITE_MISUSE: Argument must be a WASM sqlite3 pointer";
+ T.mustThrowMatching(()=>sqlite3.oo1.DB.wrapHandle(this.db), misuseMsg)
+ .mustThrowMatching(()=>sqlite3.oo1.DB.wrapHandle(0), misuseMsg);
+ let dw = sqlite3.oo1.DB.wrapHandle(this.db.pointer);
+ //sqlite3.config.debug('dw',dw);
+ T.assert( dw, '!!dw' )
+ .assert( dw instanceof sqlite3.oo1.DB, 'dw is-a oo1.DB' )
+ .assert( dw.pointer, 'dw.pointer' )
+ .assert( dw.pointer === this.db.pointer, 'dw.pointer===db.pointer' )
+ .assert( dw.filename === this.db.filename, 'dw.filename===db.filename' );
+
+ T.assert( dw === dw.exec("select 1") );
+ let q;
+ try {
+ q = dw.prepare("select 1");
+ T.assert( q.step() )
+ .assert( !q.step() );
+ }finally{
+ if( q ) q.finalize();
+ }
+ dw.close();
+ T.assert( !dw.pointer )
+ .assert( this.db === this.db.exec("select 1") );
+ dw = undefined;
+
+ let pDb = 0, pStmt = 0;
+ const stack = wasm.pstack.pointer;
+ try {
+ const ppOut = wasm.pstack.allocPtr();
+ T.assert( 0===wasm.peekPtr(ppOut) );
+ let rc = capi.sqlite3_open_v2( ":memory:", ppOut,
+ capi.SQLITE_OPEN_CREATE
+ | capi.SQLITE_OPEN_READWRITE,
+ 0);
+ T.assert( 0===rc, 'open_v2()' );
+ pDb = wasm.peekPtr(ppOut);
+ wasm.pokePtr(ppOut, 0);
+ T.assert( pDb>0, 'pDb>0' );
+ const pTmp = pDb;
+ dw = sqlite3.oo1.DB.wrapHandle(pDb, true);
+ pDb = 0;
+ //sqlite3.config.debug("dw",dw);
+ T.assert( pTmp===dw.pointer, 'pDb===dw.pointer' );
+ T.assert( dw.filename === "", "dw.filename == "+dw.filename );
+ let q = dw.prepare("select 1");
+ try {
+ T.assert( q.step(), "step()" );
+ T.assert( !q.step(), "!step()" );
+ }finally{
+ q.finalize();
+ q = undefined;
+ }
+ T.assert( dw===dw.exec("select 1") );
+ dw.affirmOpen();
+ const select1 = "select 1";
+ rc = capi.sqlite3_prepare_v2( dw, select1, -1, ppOut, 0 );
+ T.assert( 0===rc, 'prepare_v2() rc='+rc );
+ pStmt = wasm.peekPtr(ppOut);
+ T.assert( pStmt && wasm.isPtr(pStmt), 'pStmt is valid?' );
+ try {
+ //log( "capi.sqlite3_sql() =",capi.sqlite3_sql(pStmt));
+ T.assert( select1 === capi.sqlite3_sql(pStmt), 'SQL mismatch' );
+ q = sqlite3.oo1.Stmt.wrapHandle(dw, pStmt, false);
+ //log("q@"+pStmt+" does not own handle");
+ T.assert( q.step(), "step()" )
+ .assert( !q.step(), "!step()" );
+ q.finalize();
+ q = undefined;
+ T.assert( select1 === capi.sqlite3_sql(pStmt), 'SQL mismatch'
+ /* This will fail if we've mismanaged pStmt's lifetime */);
+ q = sqlite3.oo1.Stmt.wrapHandle(dw, pStmt, true);
+ pStmt = 0;
+ q.reset();
+ T.assert( q.step(), "step()" )
+ .assert( !q.step(), "!step()" );
+ }finally{
+ if( pStmt ) capi.sqlite3_finalize(pStmt)
+ if( q ) q.finalize();
+ }
+
+ }finally{
+ wasm.pstack.restore(stack);
+ if( pDb ){ capi.sqlite3_close_v2(pDb); }
+ else if( dw ){ dw.close(); }
+ }
+ }
+ })/*oo1.DB/Stmt.wrapHandle()*/
+
////////////////////////////////////////////////////////////////////
.t('sqlite3_db_config() and sqlite3_db_status()', function(sqlite3){
let rc = capi.sqlite3_db_config(this.db, capi.SQLITE_DBCONFIG_LEGACY_ALTER_TABLE, 0, 0);
@@ -1268,6 +1366,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
/columnCount property is read-only/)
.assert(1===st.columnCount)
.assert(0===st.parameterCount)
+ .assert(0===capi.sqlite3_bind_parameter_count(st))
.mustThrow(()=>st.bind(1,null))
.assert(true===st.step())
.assert(3 === st.get(0))
@@ -1490,6 +1589,8 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
let st = db.prepare("update t set b=:b where a='blob'");
try {
T.assert(0===st.columnCount)
+ .assert(1===st.parameterCount)
+ .assert(1===capi.sqlite3_bind_parameter_count(st))
.assert( false===st.isReadOnly() );
const ndx = st.getParamIndex(':b');
T.assert(1===ndx);
@@ -3329,6 +3430,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
db.exec("create table t(a)");
const stmt = db.prepare("insert into t(a) values($a)");
T.assert( 1===capi.sqlite3_bind_parameter_count(stmt) )
+ .assert( 1===stmt.parameterCount )
.assert( 1===capi.sqlite3_bind_parameter_index(stmt, "$a") )
.assert( 0===capi.sqlite3_bind_parameter_index(stmt, ":a") )
.assert( 1===stmt.getParamIndex("$a") )
diff --git a/ext/wasm/wasmfs.make b/ext/wasm/wasmfs.make
index 2c6fa35bd..0d1fb4043 100644
--- a/ext/wasm/wasmfs.make
+++ b/ext/wasm/wasmfs.make
@@ -5,31 +5,28 @@
# sqlite3.wasm. It is intended to be "include"d from the main
# GNUMakefile.
########################################################################
-MAKEFILE.wasmfs := $(lastword $(MAKEFILE_LIST))
+MAKEFILE.wasmfs = $(lastword $(MAKEFILE_LIST))
# ensure that the following message starts on line 10 or higher for proper
# $(warning) alignment!
ifneq (1,$(MAKING_CLEAN))
$(warning !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!)
- $(warning !! The WASMFS build is not well-supported. WASMFS is a proverbial)
- $(warning !! moving target, sometimes changing in incompatible ways between)
- $(warning !! Emscripten versions. This build is provided for adventurous folks)
- $(warning !! and is not a supported deliverable of the SQLite project.)
+ $(warning !! The WASMFS build is unsupported. Use at your own risk.
$(warning !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!)
endif
-sqlite3-wasmfs.js := $(dir.wasmfs)/sqlite3-wasmfs.js
-sqlite3-wasmfs.wasm := $(dir.wasmfs)/sqlite3-wasmfs.wasm
+sqlite3-wasmfs.js = $(dir.wasmfs)/sqlite3-wasmfs.js
+sqlite3-wasmfs.wasm = $(dir.wasmfs)/sqlite3-wasmfs.wasm
########################################################################
# emcc flags for .c/.o.
-cflags.sqlite3-wasmfs :=
+cflags.sqlite3-wasmfs =
cflags.sqlite3-wasmfs += -std=c99 -fPIC
cflags.sqlite3-wasmfs += -pthread
cflags.sqlite3-wasmfs += -DSQLITE_ENABLE_WASMFS
########################################################################
# emcc flags specific to building the final .js/.wasm file...
-emcc.flags.sqlite3-wasmfs :=
+emcc.flags.sqlite3-wasmfs =
emcc.flags.sqlite3-wasmfs += \
-sEXPORTED_RUNTIME_METHODS=wasmMemory
# wasmMemory ==> for -sIMPORTED_MEMORY
@@ -43,7 +40,7 @@ emcc.flags.sqlite3-wasmfs += -Wno-limited-postlink-optimizations
emcc.flags.sqlite3-wasmfs += -sMEMORY64=0
emcc.flags.sqlite3-wasmfs += -sINITIAL_MEMORY=$(emcc.INITIAL_MEMORY.128)
# ^^^^ 64MB is not enough for WASMFS/OPFS test runs using batch-runner.js
-sqlite3-wasmfs.fsflags := -pthread -sWASMFS \
+sqlite3-wasmfs.fsflags = -pthread -sWASMFS \
-sPTHREAD_POOL_SIZE=1 \
-sERROR_ON_UNDEFINED_SYMBOLS=0 -sLLD_REPORT_UNDEFINED
# ^^^^^ why undefined symbols are necessary for the wasmfs build is anyone's guess.
@@ -53,10 +50,9 @@ emcc.flags.sqlite3-wasmfs += -sALLOW_MEMORY_GROWTH=0
# USE_PTHREADS + ALLOW_MEMORY_GROWTH may run non-wasm code slowly,
# see https://github.com/WebAssembly/design/issues/1271 [-Wpthreads-mem-growth]
# And, indeed, it runs slowly if memory is permitted to grow.
-#emcc.flags.sqlite3-wasmfs.vanilla :=
-#emcc.flags.sqlite3-wasmfs.esm := -sEXPORT_ES6 -sUSE_ES6_IMPORT_META
-all: $(sqlite3-wasmfs.mjs)
-$(sqlite3-wasmfs.js) $(sqlite3-wasmfs.mjs): $(MAKEFILE.wasmfs)
+#emcc.flags.sqlite3-wasmfs.vanilla =
+#emcc.flags.sqlite3-wasmfs.esm = -sEXPORT_ES6 -sUSE_ES6_IMPORT_META
+$(sqlite3-wasmfs.js) $(dir.wasmfs)/sqlite3-wasmfs.mjs: $(MAKEFILE.wasmfs)
########################################################################
# Build quirk: we cannot build BOTH .js and .mjs with our current
# build infrastructure because the supplemental *.worker.js files get
@@ -68,31 +64,31 @@ $(sqlite3-wasmfs.js) $(sqlite3-wasmfs.mjs): $(MAKEFILE.wasmfs)
# names is that it means that the corresponding .wasm file is also
# built/saved multiple times. It is likely that anyone wanting to use
# WASMFS will want an ES6 module, so that's what we build here.
-wasmfs.build.ext := mjs
-$(sqlite3-wasmfs.js) $(sqlite3-wasmfs.mjs): $(SOAP.js.bld)
+wasmfs.build.ext = mjs
+$(sqlite3-wasmfs.js) $(dir.wasmfs)/sqlite3-wasmfs.mjs: $(SOAP.js.bld)
ifeq (js,$(wasmfs.build.ext))
$(sqlite3-wasmfs.wasm): $(sqlite3-wasmfs.js)
wasmfs: $(sqlite3-wasmfs.js)
else
- $(sqlite3-wasmfs.wasm): $(sqlite3-wasmfs.mjs)
- wasmfs: $(sqlite3-wasmfs.mjs)
+ $(sqlite3-wasmfs.wasm): $(dir.wasmfs)/sqlite3-wasmfs.mjs
+ wasmfs: $(dir.wasmfs)/sqlite3-wasmfs.mjs
endif
+all: wasmfs
########################################################################
# speedtest1 for wasmfs.
-speedtest1-wasmfs.mjs := $(dir.wasmfs)/speedtest1-wasmfs.mjs
-speedtest1-wasmfs.wasm := $(subst .mjs,.wasm,$(speedtest1-wasmfs.mjs))
-emcc.flags.speedtest1-wasmfs := $(sqlite3-wasmfs.fsflags)
+speedtest1-wasmfs.mjs = $(dir.wasmfs)/speedtest1-wasmfs.mjs
+speedtest1-wasmfs.wasm = $(subst .mjs,.wasm,$(speedtest1-wasmfs.mjs))
+emcc.flags.speedtest1-wasmfs = $(sqlite3-wasmfs.fsflags)
emcc.flags.speedtest1-wasmfs += $(SQLITE_OPT)
emcc.flags.speedtest1-wasmfs += -sALLOW_MEMORY_GROWTH=0
emcc.flags.speedtest1-wasmfs += -sINITIAL_MEMORY=$(emcc.INITIAL_MEMORY.128)
-#$(eval $(call call-make-pre-js,speedtest1-wasmfs,ems))
+#$(info speedtest DEPS=pre-post-sqlite3-wasmfs-esm.deps=$(pre-post-sqlite3-wasmfs-esm.deps))
$(speedtest1-wasmfs.mjs): $(speedtest1.cfiles) $(sqlite3-wasmfs.js) \
- $(MAKEFILE) $(MAKEFILE.wasmfs) \
- $(pre-post-sqlite3-wasmfs-esm.deps) \
+ $(MAKEFILE) $(MAKEFILE.wasmfs) $(pre-post-sqlite3-wasmfs-esm.deps) \
$(EXPORTED_FUNCTIONS.speedtest1)
@echo "Building $@ ..."
- $(emcc.bin) \
+ $(bin.emcc) \
$(pre-post-sqlite3-wasmfs-esm.flags) \
$(cflags.common) \
$(cflags.sqlite3-wasmfs) \