SQLite

Changes On Branch js-bundler-friendly
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Changes In Branch js-bundler-friendly Excluding Merge-Ins

This is equivalent to a diff from bdfd72a083 to 6a5c4f6b19

2023-01-28
04:20
Add JS bundler-friendly JS build. Minor test code cleanups. (check-in: 24d3a53dea user: stephan tags: trunk)
2023-01-27
20:25
Update ext/wasm/README-dist.txt for the bundler-friendly build. (Closed-Leaf check-in: 6a5c4f6b19 user: stephan tags: js-bundler-friendly)
19:56
Add a feature idea note to DB.exec(), derived from a forum discussion. (check-in: 792f43209c user: stephan tags: js-bundler-friendly)
05:17
Cherrypick [fa784101775b7|emscripten ticket #18609 workaround] into trunk. (check-in: 9a26fae545 user: stephan tags: trunk)
01:33
Beginnings of a bundler-friendly build of sqlite3.mjs. Not yet ready for downstream testing. (check-in: 4271bf5f41 user: stephan tags: js-bundler-friendly)
2023-01-26
20:08
End-of-line whitespace cleanups and doc typo fixes. No code changes. (check-in: bdfd72a083 user: stephan tags: trunk)
18:16
Have some RBU tests run as part of veryquick.test/testrunner.tcl. (check-in: f51406e3bf user: dan tags: trunk)

Changes to ext/wasm/GNUmakefile.
33
34
35
36
37
38
39









40
41
42
43
44
45
46
47
48
49
50
51







52
53
54
55
56
57
58
#
# - Emscripten SDK: https://emscripten.org/docs/getting_started/downloads.html
# - The bash shell
# - GNU make, GNU sed, GNU awk, GNU grep (all in the $PATH)
# - wasm-strip for release builds: https://github.com/WebAssembly/wabt
# - InfoZip for 'dist' zip file
########################################################################









SHELL := $(shell which bash 2>/dev/null)
MAKEFILE := $(lastword $(MAKEFILE_LIST))
CLEAN_FILES :=
DISTCLEAN_FILES := ./--dummy--
default: all
release: oz

# Emscripten SDK home dir and related binaries...
EMSDK_HOME ?= $(word 1,$(wildcard $(HOME)/emsdk $(HOME)/src/emsdk))
emcc.bin ?= $(word 1,$(wildcard $(EMSDK_HOME)/upstream/emscripten/emcc) $(shell which emcc))
ifeq (,$(emcc.bin))
  $(error Cannot find emcc.)







endif

wasm-strip ?= $(shell which wasm-strip 2>/dev/null)
ifeq (,$(filter clean,$(MAKECMDGOALS)))
ifeq (,$(wasm-strip))
  $(info WARNING: *******************************************************************)
  $(info WARNING: builds using -O2/-O3/-Os/-Oz will minify WASM-exported names,)







>
>
>
>
>
>
>
>
>












>
>
>
>
>
>
>







33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#
# - Emscripten SDK: https://emscripten.org/docs/getting_started/downloads.html
# - The bash shell
# - GNU make, GNU sed, GNU awk, GNU grep (all in the $PATH)
# - wasm-strip for release builds: https://github.com/WebAssembly/wabt
# - InfoZip for 'dist' zip file
########################################################################
#
# Significant TODOs for this build include, but are not necessarily
# limited to:
#
# 1) Consolidate the code generation for sqlite3*.*js into a script
#    which generates the makefile code, rather than using $(call) and
#    $(eval), or at least centralize the setup of the numerous vars
#    related to each build variant (vanilla, esm, bundler-friendly).
#
SHELL := $(shell which bash 2>/dev/null)
MAKEFILE := $(lastword $(MAKEFILE_LIST))
CLEAN_FILES :=
DISTCLEAN_FILES := ./--dummy--
default: all
release: oz

# Emscripten SDK home dir and related binaries...
EMSDK_HOME ?= $(word 1,$(wildcard $(HOME)/emsdk $(HOME)/src/emsdk))
emcc.bin ?= $(word 1,$(wildcard $(EMSDK_HOME)/upstream/emscripten/emcc) $(shell which emcc))
ifeq (,$(emcc.bin))
  $(error Cannot find emcc.)
endif
emcc.version := $(shell "$(emcc.bin)" --version | sed -n 1p \
                  | sed -e 's/^.* \([3-9][^ ]*\) .*$$/\1/;')
ifeq (,$(emcc.version))
  $(warning Cannot determine emcc version. This might unduly impact build flags.)
else
  $(info using emcc version [$(emcc.version)])
endif

wasm-strip ?= $(shell which wasm-strip 2>/dev/null)
ifeq (,$(filter clean,$(MAKECMDGOALS)))
ifeq (,$(wasm-strip))
  $(info WARNING: *******************************************************************)
  $(info WARNING: builds using -O2/-O3/-Os/-Oz will minify WASM-exported names,)
224
225
226
227
228
229
230

231
232
233
234
235
236
237
# $3 = optional c-pp -D... flags
$(2): $(1) $$(MAKEFILE) $$(bin.c-pp)
	$$(bin.c-pp) -f $(1) -o $$@ $(3)
CLEAN_FILES += $(2)
endef
c-pp.D.vanilla ?=
c-pp.D.esm ?= -Dtarget=es6-module

# /end C-PP.FILTER
########################################################################


# cflags.common = C compiler flags for all builds
cflags.common :=  -I. -I.. -I$(dir.top)
# emcc.WASM_BIGINT = 1 for BigInt (C int64) support, else 0.  The API







>







240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
# $3 = optional c-pp -D... flags
$(2): $(1) $$(MAKEFILE) $$(bin.c-pp)
	$$(bin.c-pp) -f $(1) -o $$@ $(3)
CLEAN_FILES += $(2)
endef
c-pp.D.vanilla ?=
c-pp.D.esm ?= -Dtarget=es6-module
c-pp.D.bundler-friendly ?= -Dtarget=es6-module -Dtarget=es6-bundler-friendly
# /end C-PP.FILTER
########################################################################


# cflags.common = C compiler flags for all builds
cflags.common :=  -I. -I.. -I$(dir.top)
# emcc.WASM_BIGINT = 1 for BigInt (C int64) support, else 0.  The API
351
352
353
354
355
356
357

358
359

360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387

388
389
390
391

392
393
394

395
396
397
398
399
400
401
402
403
404
405
406
407

408
409
410
411
412
413
414

415
416

417
418
419
420
421
422
423
424
425
426
427
428
429
430




431
432
433
434
435
436
437
438


439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
#
# We build $(sqlite3-api.js) and $(sqlite3-api.mjs) "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 := $(dir.dout)/sqlite3-api.js
sqlite3-api.mjs := $(dir.dout)/sqlite3-api.mjs

$(eval $(call C-PP.FILTER, $(sqlite3-api.js.in), $(sqlite3-api.js)))
$(eval $(call C-PP.FILTER, $(sqlite3-api.js.in), $(sqlite3-api.mjs), $(c-pp.D.esm)))

all: $(sqlite3-api.js) $(sqlite3-api.mjs)

$(sqlite3-api-build-version.js): $(bin.version-info) $(MAKEFILE)
	@echo "Making $@..."
	@{ \
  echo 'self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){'; \
	echo -n '  sqlite3.version = '; \
  $(bin.version-info) --json; \
  echo ';'; \
	echo '});'; \
  } > $@
$(sqlite3-license-version.js): $(sqlite3.h) $(sqlite3-license-version-header.js) \
  $(MAKEFILE)
	@echo "Making $@..."; { \
    cat $(sqlite3-license-version-header.js); \
    echo '/*'; \
    echo '** This code was built from sqlite3 version...'; \
    echo "** "; \
    awk -e '/define SQLITE_VERSION/{$$1=""; print "**" $$0}' \
        -e '/define SQLITE_SOURCE_ID/{$$1=""; print "**" $$0}' $(sqlite3.h); \
    echo '*/'; \
   } > $@

########################################################################
# --post-js and --pre-js are emcc flags we use to append/prepend JS to
# the generated emscripten module file. The following rules generate
# various versions of those files for the vanilla and ESM builds.
pre-js.js.in := $(dir.api)/pre-js.c-pp.js

pre-js.js.esm := $(dir.tmp)/pre-js.esm.js
pre-js.js.vanilla := $(dir.tmp)/pre-js.vanilla.js
$(eval $(call C-PP.FILTER,$(pre-js.js.in),$(pre-js.js.vanilla),$(c-pp.D.vanilla)))
$(eval $(call C-PP.FILTER,$(pre-js.js.in),$(pre-js.js.esm),$(c-pp.D.esm)))

post-js.js.in := $(dir.tmp)/post-js.c-pp.js
post-js.js.vanilla := $(dir.tmp)/post-js.vanilla.js
post-js.js.esm := $(dir.tmp)/post-js.esm.js

post-jses.js := \
  $(dir.api)/post-js-header.js \
  $(sqlite3-api.js.in) \
  $(dir.api)/post-js-footer.js
$(post-js.js.in): $(post-jses.js) $(MAKEFILE)
	@echo "Making $@..."
	@for i in $(post-jses.js); do \
		echo "/* BEGIN FILE: $$i */"; \
		cat $$i; \
		echo "/* END FILE: $$i */"; \
	done > $@
$(eval $(call C-PP.FILTER,$(post-js.js.in),$(post-js.js.vanilla),$(c-pp.D.vanilla)))
$(eval $(call C-PP.FILTER,$(post-js.js.in),$(post-js.js.esm),$(c-pp.D.esm)))


# extern-post-js* and extern-pre-js* are files for use with
# Emscripten's --extern-pre-js and --extern-post-js flags.  These
# rules make different copies for the vanilla and ESM builds.
extern-post-js.js.in := $(dir.api)/extern-post-js.c-pp.js
extern-post-js.js.vanilla := $(dir.tmp)/extern-post-js.vanilla.js
extern-post-js.js.esm := $(dir.tmp)/extern-post-js.esm.js

$(eval $(call C-PP.FILTER,$(extern-post-js.js.in),$(extern-post-js.js.vanilla),$(c-pp.D.vanilla)))
$(eval $(call C-PP.FILTER,$(extern-post-js.js.in),$(extern-post-js.js.esm),$(c-pp.D.esm)))

extern-pre-js.js := $(dir.api)/extern-pre-js.js

# Emscripten flags for --[extern-][pre|post]-js=... for the
# various builds.
pre-post-common.flags := \
  --extern-pre-js=$(sqlite3-license-version.js)
pre-post-common.flags.vanilla := \
  $(pre-post-common.flags) \
  --post-js=$(post-js.js.vanilla) \
  --extern-post-js=$(extern-post-js.js.vanilla)
pre-post-common.flags.esm := \
  $(pre-post-common.flags) \
  --post-js=$(post-js.js.esm) \
  --extern-post-js=$(extern-post-js.js.esm)





# pre-post-jses.deps.* = a list of dependencies for the
# --[extern-][pre/post]-js files.
pre-post-jses.deps.common := $(extern-pre-js.js) $(sqlite3-license-version.js)
pre-post-jses.deps.vanilla := $(pre-post-jses.deps.common) \
  $(post-js.js.vanilla) $(extern-post-js.js.vanilla)
pre-post-jses.deps.esm := $(pre-post-jses.deps.common) \
  $(post-js.js.esm) $(extern-post-js.js.esm)



########################################################################
# call-make-pre-js is a $(call)able which creates rules for
# pre-js-$(1).js. $1 = the base name of the JS file on whose behalf
# this pre-js is for. $2 is the build mode: one of (vanilla, esm).
# This sets up --[extern-][pre/post]-js flags in
# $(pre-post-$(1).flags.$(2)) and dependencies in
# $(pre-post-$(1).deps.$(2)).
define call-make-pre-js
pre-post-$(1).flags.$(2) ?=
$$(dir.tmp)/pre-js-$(1)-$(2).js: $$(pre-js.js.$(2)) $$(MAKEFILE)
	cp $$(pre-js.js.$(2)) $$@
	@if [ sqlite3-wasmfs = $(1) ]; then \
		echo "delete Module[xNameOfInstantiateWasm] /*for WASMFS build*/;"; \
	elif [ sqlite3 != $(1) ]; then \







>


>
|
















|










>

|


>



>













>







>


>














>
>
>
>








>
>




|
|
|
|







368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
#
# We build $(sqlite3-api.js) and $(sqlite3-api.mjs) "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 := $(dir.dout)/sqlite3-api.js
sqlite3-api.mjs := $(dir.dout)/sqlite3-api.mjs
sqlite3-api-bundler-friendly.mjs := $(dir.dout)/sqlite3-api-bundler-friendly.mjs
$(eval $(call C-PP.FILTER, $(sqlite3-api.js.in), $(sqlite3-api.js)))
$(eval $(call C-PP.FILTER, $(sqlite3-api.js.in), $(sqlite3-api.mjs), $(c-pp.D.esm)))
$(eval $(call C-PP.FILTER, $(sqlite3-api.js.in), $(sqlite3-api-bundler-friendly.mjs), $(c-pp.D.bundler-friendly)))
all: $(sqlite3-api.js) $(sqlite3-api.mjs) $(sqlite3-api-bundler-friendly.mjs)

$(sqlite3-api-build-version.js): $(bin.version-info) $(MAKEFILE)
	@echo "Making $@..."
	@{ \
  echo 'self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){'; \
	echo -n '  sqlite3.version = '; \
  $(bin.version-info) --json; \
  echo ';'; \
	echo '});'; \
  } > $@
$(sqlite3-license-version.js): $(sqlite3.h) $(sqlite3-license-version-header.js) \
  $(MAKEFILE)
	@echo "Making $@..."; { \
    cat $(sqlite3-license-version-header.js); \
    echo '/*'; \
    echo '** This code was built from sqlite3 version...'; \
    echo "**"; \
    awk -e '/define SQLITE_VERSION/{$$1=""; print "**" $$0}' \
        -e '/define SQLITE_SOURCE_ID/{$$1=""; print "**" $$0}' $(sqlite3.h); \
    echo '*/'; \
   } > $@

########################################################################
# --post-js and --pre-js are emcc flags we use to append/prepend JS to
# the generated emscripten module file. The following rules generate
# various versions of those files for the vanilla and ESM builds.
pre-js.js.in := $(dir.api)/pre-js.c-pp.js
pre-js.js.vanilla := $(dir.tmp)/pre-js.vanilla.js
pre-js.js.esm := $(dir.tmp)/pre-js.esm.js
pre-js.js.bundler-friendly := $(dir.tmp)/pre-js.bundler-friendly.js
$(eval $(call C-PP.FILTER,$(pre-js.js.in),$(pre-js.js.vanilla),$(c-pp.D.vanilla)))
$(eval $(call C-PP.FILTER,$(pre-js.js.in),$(pre-js.js.esm),$(c-pp.D.esm)))
$(eval $(call C-PP.FILTER,$(pre-js.js.in),$(pre-js.js.bundler-friendly),$(c-pp.D.bundler-friendly)))
post-js.js.in := $(dir.tmp)/post-js.c-pp.js
post-js.js.vanilla := $(dir.tmp)/post-js.vanilla.js
post-js.js.esm := $(dir.tmp)/post-js.esm.js
post-js.js.bundler-friendly := $(dir.tmp)/post-js.bundler-friendly.js
post-jses.js := \
  $(dir.api)/post-js-header.js \
  $(sqlite3-api.js.in) \
  $(dir.api)/post-js-footer.js
$(post-js.js.in): $(post-jses.js) $(MAKEFILE)
	@echo "Making $@..."
	@for i in $(post-jses.js); do \
		echo "/* BEGIN FILE: $$i */"; \
		cat $$i; \
		echo "/* END FILE: $$i */"; \
	done > $@
$(eval $(call C-PP.FILTER,$(post-js.js.in),$(post-js.js.vanilla),$(c-pp.D.vanilla)))
$(eval $(call C-PP.FILTER,$(post-js.js.in),$(post-js.js.esm),$(c-pp.D.esm)))
$(eval $(call C-PP.FILTER,$(post-js.js.in),$(post-js.js.bundler-friendly),$(c-pp.D.bundler-friendly)))

# extern-post-js* and extern-pre-js* are files for use with
# Emscripten's --extern-pre-js and --extern-post-js flags.  These
# rules make different copies for the vanilla and ESM builds.
extern-post-js.js.in := $(dir.api)/extern-post-js.c-pp.js
extern-post-js.js.vanilla := $(dir.tmp)/extern-post-js.vanilla.js
extern-post-js.js.esm := $(dir.tmp)/extern-post-js.esm.js
extern-post-js.js.bundler-friendly := $(dir.tmp)/extern-post-js.bundler-friendly.js
$(eval $(call C-PP.FILTER,$(extern-post-js.js.in),$(extern-post-js.js.vanilla),$(c-pp.D.vanilla)))
$(eval $(call C-PP.FILTER,$(extern-post-js.js.in),$(extern-post-js.js.esm),$(c-pp.D.esm)))
$(eval $(call C-PP.FILTER,$(extern-post-js.js.in),$(extern-post-js.js.bundler-friendly),$(c-pp.D.bundler-friendly)))
extern-pre-js.js := $(dir.api)/extern-pre-js.js

# Emscripten flags for --[extern-][pre|post]-js=... for the
# various builds.
pre-post-common.flags := \
  --extern-pre-js=$(sqlite3-license-version.js)
pre-post-common.flags.vanilla := \
  $(pre-post-common.flags) \
  --post-js=$(post-js.js.vanilla) \
  --extern-post-js=$(extern-post-js.js.vanilla)
pre-post-common.flags.esm := \
  $(pre-post-common.flags) \
  --post-js=$(post-js.js.esm) \
  --extern-post-js=$(extern-post-js.js.esm)
pre-post-common.flags.bundler-friendly := \
  $(pre-post-common.flags) \
  --post-js=$(post-js.js.bundler-friendly) \
  --extern-post-js=$(extern-post-js.js.bundler-friendly)

# pre-post-jses.deps.* = a list of dependencies for the
# --[extern-][pre/post]-js files.
pre-post-jses.deps.common := $(extern-pre-js.js) $(sqlite3-license-version.js)
pre-post-jses.deps.vanilla := $(pre-post-jses.deps.common) \
  $(post-js.js.vanilla) $(extern-post-js.js.vanilla)
pre-post-jses.deps.esm := $(pre-post-jses.deps.common) \
  $(post-js.js.esm) $(extern-post-js.js.esm)
pre-post-jses.deps.bundler-friendly := $(pre-post-jses.deps.common) \
  $(post-js.js.bundler-friendly) $(extern-post-js.js.bundler-friendly)

########################################################################
# call-make-pre-js is a $(call)able which creates rules for
# pre-js-$(1).js. $1 = the base name of the JS file on whose behalf
# this pre-js is for (one of: sqlite3, sqlite3-wasm). $2 is the build
# mode: one of (vanilla, esm, bundler-friendly).  This sets up
# --[extern-][pre/post]-js flags in $(pre-post-$(1).flags.$(2)) and
# dependencies in $(pre-post-$(1).deps.$(2)).
define call-make-pre-js
pre-post-$(1).flags.$(2) ?=
$$(dir.tmp)/pre-js-$(1)-$(2).js: $$(pre-js.js.$(2)) $$(MAKEFILE)
	cp $$(pre-js.js.$(2)) $$@
	@if [ sqlite3-wasmfs = $(1) ]; then \
		echo "delete Module[xNameOfInstantiateWasm] /*for WASMFS build*/;"; \
	elif [ sqlite3 != $(1) ]; then \
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497







498
499
500
501
502
503
504

########################################################################
# emcc flags for .c/.o.
emcc.cflags :=
emcc.cflags += -std=c99 -fPIC
# -------------^^^^^^^^ we need c99 for $(sqlite3-wasm.c).
emcc.cflags += -I. -I$(dir.top)

########################################################################
# emcc flags specific to building .js/.wasm files...
emcc.jsflags := -fPIC
emcc.jsflags += --minify 0
emcc.jsflags += --no-entry
emcc.jsflags += -sWASM_BIGINT=$(emcc.WASM_BIGINT)
emcc.jsflags += -sMODULARIZE
emcc.jsflags += -sSTRICT_JS
emcc.jsflags += -sDYNAMIC_EXECUTION=0
emcc.jsflags += -sNO_POLYFILL
emcc.jsflags += -sEXPORTED_FUNCTIONS=@$(EXPORTED_FUNCTIONS.api)
emcc.exportedRuntimeMethods := \
    -sEXPORTED_RUNTIME_METHODS=wasmMemory
    # wasmMemory ==> required by our code for use with -sIMPORTED_MEMORY
emcc.jsflags += $(emcc.exportedRuntimeMethods)
emcc.jsflags += -sUSE_CLOSURE_COMPILER=0
emcc.jsflags += -sIMPORTED_MEMORY







emcc.environment := -sENVIRONMENT=web,worker
########################################################################
# -sINITIAL_MEMORY: How much memory we need to start with is governed
# at least in part by whether -sALLOW_MEMORY_GROWTH is enabled. If so,
# we can start with less. If not, we need as much as we'll ever
# possibly use (which, of course, we can't know for sure).  Note,
# however, that speedtest1 shows that performance for even moderate







<







<









>
>
>
>
>
>
>







504
505
506
507
508
509
510

511
512
513
514
515
516
517

518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540

########################################################################
# emcc flags for .c/.o.
emcc.cflags :=
emcc.cflags += -std=c99 -fPIC
# -------------^^^^^^^^ we need c99 for $(sqlite3-wasm.c).
emcc.cflags += -I. -I$(dir.top)

########################################################################
# emcc flags specific to building .js/.wasm files...
emcc.jsflags := -fPIC
emcc.jsflags += --minify 0
emcc.jsflags += --no-entry
emcc.jsflags += -sWASM_BIGINT=$(emcc.WASM_BIGINT)
emcc.jsflags += -sMODULARIZE

emcc.jsflags += -sDYNAMIC_EXECUTION=0
emcc.jsflags += -sNO_POLYFILL
emcc.jsflags += -sEXPORTED_FUNCTIONS=@$(EXPORTED_FUNCTIONS.api)
emcc.exportedRuntimeMethods := \
    -sEXPORTED_RUNTIME_METHODS=wasmMemory
    # wasmMemory ==> required by our code for use with -sIMPORTED_MEMORY
emcc.jsflags += $(emcc.exportedRuntimeMethods)
emcc.jsflags += -sUSE_CLOSURE_COMPILER=0
emcc.jsflags += -sIMPORTED_MEMORY
ifeq (3.1.31,$(emcc.version))
  emcc.jsflags += -sSTRICT_JS=0
  $(warning Disabling -sSTRICT_JS for emcc $(emcc.version): \
     https://github.com/emscripten-core/emscripten/issues/18610)
else
  emcc.jsflags += -sSTRICT_JS=1
endif
emcc.environment := -sENVIRONMENT=web,worker
########################################################################
# -sINITIAL_MEMORY: How much memory we need to start with is governed
# at least in part by whether -sALLOW_MEMORY_GROWTH is enabled. If so,
# we can start with less. If not, we need as much as we'll ever
# possibly use (which, of course, we can't know for sure).  Note,
# however, that speedtest1 shows that performance for even moderate
591
592
593
594
595
596
597

598
599
600
601
602
603
604
605
606
607
608
609

610
611
612
613

614
615
616

617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633

634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650





651
652
653
654
655
656

657
658
659


660
661
662
663
664
665
666
667
668
669



670

671
672
673

674
675
676
677
678
679
680
# cannot wasm-strip the binary before it gets encoded into the JS
# file. The result is that the generated JS file is, because of the
# -g3 debugging info, _huge_.
########################################################################

sqlite3.js := $(dir.dout)/sqlite3.js
sqlite3.mjs := $(dir.dout)/sqlite3.mjs

# Undocumented Emscripten feature: if the target file extension is
# "mjs", it defaults to ES6 module builds:
# https://github.com/emscripten-core/emscripten/issues/14383
sqlite3.wasm := $(dir.dout)/sqlite3.wasm
sqlite3-wasm.c := $(dir.api)/sqlite3-wasm.c
# sqlite3-wasm.o vs sqlite3-wasm.c: building against the latter
# (predictably) results in a slightly faster binary, but we're close
# enough to the target speed requirements that the 500ms makes a
# difference. Thus we build all binaries against sqlite3-wasm.c
# instead of building a shared copy of sqlite3-wasm.o.
$(eval $(call call-make-pre-js,sqlite3,vanilla))
$(eval $(call call-make-pre-js,sqlite3,esm))

$(sqlite3.js) $(sqlite3.mjs): $(MAKEFILE) $(sqlite3-wasm.c) \
    $(EXPORTED_FUNCTIONS.api)
$(sqlite3.js):  $(pre-post-sqlite3.deps.vanilla)
$(sqlite3.mjs): $(pre-post-sqlite3.deps.esm)

########################################################################
# SQLITE3.xJS.RECIPE = the $(call)able recipe body for $(sqlite3.js)
# and $(sqlite3.mjs). $1 = one of (vanilla, esm).

#
# Reminder for ESM builds: even if we use -sEXPORT_ES6=0, emcc _still_
# adds:
#
#   export default $(sqlite3.js.init-func);
#
# when building *.mjs, which is bad because we need to export an
# overwritten version of that function and cannot "export default"
# twice. Because of this, we have to sed $(sqlite3.mjs) to remove the
# _first_ instance (only) of /^export default/.
#
# Upstream RFE:
# https://github.com/emscripten-core/emscripten/issues/18237
########################################################################
# SQLITE3.xJS.EXPORT-DEFAULT is part of SQLITE3[-WASMFS].xJS.RECIPE,
# factored into a separate piece to avoid code duplication. $1 is
# the build mode: one of (vanilla, esm).

define SQLITE3.xJS.ESM-EXPORT-DEFAULT
if [ esm = $(1) ]; then \
		echo "Fragile workaround for an Emscripten annoyance. See SQLITE3.xJS.RECIPE."; \
		sed -i -e '0,/^export default/{/^export default/d;}' $@ || exit $$?; \
		if ! grep -q '^export default' $@; then \
			echo "Cannot find export default." 1>&2; \
			exit 1; \
		fi; \
fi
endef
define SQLITE3.xJS.RECIPE
	@echo "Building $@ ..."
	$(emcc.bin) -o $@ $(emcc_opt_full) $(emcc.flags) \
    $(emcc.jsflags) \
    $(pre-post-sqlite3.flags.$(1)) $(emcc.flags.sqlite3.$(1)) \
    $(cflags.common) $(SQLITE_OPT) $(sqlite3-wasm.c)
	@$(call SQLITE3.xJS.ESM-EXPORT-DEFAULT,$(1))





	chmod -x $(sqlite3.wasm)
	$(maybe-wasm-strip) $(sqlite3.wasm)
	@ls -la $@ $(sqlite3.wasm)
endef
emcc.flags.sqlite3.vanilla :=
emcc.flags.sqlite3.esm := -sEXPORT_ES6 -sUSE_ES6_IMPORT_META

$(sqlite3.js):
	$(call SQLITE3.xJS.RECIPE,vanilla)
$(sqlite3.mjs):


	$(call SQLITE3.xJS.RECIPE,esm)
########################################################################
# We have to ensure that we do not build both $(sqlite3.js) and
# $(sqlite3.mjs) in parallel because both result in the creation of
# $(sqlite3.wasm). We have no(?) way to build just the .mjs file
# without also building the .wasm file. i.e.  we're building
# $(sqlite3.wasm) twice, but that's apparently unavoidable (and
# harmless, just a waste of build time).
$(sqlite3.wasm): $(sqlite3.js)
$(sqlite3.mjs): $(sqlite3.js)



CLEAN_FILES += $(sqlite3.js) $(sqlite3.mjs) $(sqlite3.wasm)

all: $(sqlite3.js) $(sqlite3.mjs)
quick: $(sqlite3.js)
quick: $(sqlite3.mjs) # for the sake of the snapshot build

# End main $(sqlite3.js) build
########################################################################

########################################################################
# batch-runner.js is part of one of the test apps which reads in SQL
# dumps generated by $(speedtest1) and executes them.
dir.sql := sql







>












>
|
|


>


|
>








|
|





|
|
>

|














|
>
>
>
>
>






>

|

>
>
|





|
|


>
>
>
|
>
|


>







627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
# cannot wasm-strip the binary before it gets encoded into the JS
# file. The result is that the generated JS file is, because of the
# -g3 debugging info, _huge_.
########################################################################

sqlite3.js := $(dir.dout)/sqlite3.js
sqlite3.mjs := $(dir.dout)/sqlite3.mjs
sqlite3-bundler-friendly.mjs := $(dir.dout)/sqlite3-bundler-friendly.mjs
# Undocumented Emscripten feature: if the target file extension is
# "mjs", it defaults to ES6 module builds:
# https://github.com/emscripten-core/emscripten/issues/14383
sqlite3.wasm := $(dir.dout)/sqlite3.wasm
sqlite3-wasm.c := $(dir.api)/sqlite3-wasm.c
# sqlite3-wasm.o vs sqlite3-wasm.c: building against the latter
# (predictably) results in a slightly faster binary, but we're close
# enough to the target speed requirements that the 500ms makes a
# difference. Thus we build all binaries against sqlite3-wasm.c
# instead of building a shared copy of sqlite3-wasm.o.
$(eval $(call call-make-pre-js,sqlite3,vanilla))
$(eval $(call call-make-pre-js,sqlite3,esm))
$(eval $(call call-make-pre-js,sqlite3,bundler-friendly))
$(sqlite3.js) $(sqlite3.mjs) $(sqlite3-bundler-friendly.mjs): \
    $(MAKEFILE) $(sqlite3-wasm.c) $(EXPORTED_FUNCTIONS.api)
$(sqlite3.js):  $(pre-post-sqlite3.deps.vanilla)
$(sqlite3.mjs): $(pre-post-sqlite3.deps.esm)
$(sqlite3-bundler-friendly.mjs): $(pre-post-sqlite3.deps.bundler-friendly)
########################################################################
# SQLITE3.xJS.RECIPE = the $(call)able recipe body for $(sqlite3.js)
# and $(sqlite3.mjs). $1 = one of (vanilla, esm). $2 must be 1 for
# ES6-style builds, 0 for other builds.
#
# Reminder for ESM builds: even if we use -sEXPORT_ES6=0, emcc _still_
# adds:
#
#   export default $(sqlite3.js.init-func);
#
# when building *.mjs, which is bad because we need to export an
# overwritten version of that function and cannot "export default"
# twice. Because of this, we have to sed *.mjs to remove the _first_
# instance (only) of /^export default/.
#
# Upstream RFE:
# https://github.com/emscripten-core/emscripten/issues/18237
########################################################################
# SQLITE3.xJS.EXPORT-DEFAULT is part of SQLITE3[-WASMFS].xJS.RECIPE,
# factored into a separate piece to avoid code duplication. $1 is 1 if
# the build mode needs this workaround (esm, bundler-friendly) and 0
# if not (vanilla).
define SQLITE3.xJS.ESM-EXPORT-DEFAULT
if [ x1 = x$(1) ]; then \
		echo "Fragile workaround for an Emscripten annoyance. See SQLITE3.xJS.RECIPE."; \
		sed -i -e '0,/^export default/{/^export default/d;}' $@ || exit $$?; \
		if ! grep -q '^export default' $@; then \
			echo "Cannot find export default." 1>&2; \
			exit 1; \
		fi; \
fi
endef
define SQLITE3.xJS.RECIPE
	@echo "Building $@ ..."
	$(emcc.bin) -o $@ $(emcc_opt_full) $(emcc.flags) \
    $(emcc.jsflags) \
    $(pre-post-sqlite3.flags.$(1)) $(emcc.flags.sqlite3.$(1)) \
    $(cflags.common) $(SQLITE_OPT) $(sqlite3-wasm.c)
	@$(call SQLITE3.xJS.ESM-EXPORT-DEFAULT,$(2))
	@if [ bundler-friendly = $(1) ]; then \
		echo "Patching sqlite3-bundler-friendly.js for sqlite3.wasm..."; \
		rm -f $(dir.dout)/sqlite3-bundler-friendly.wasm; \
		sed -i -e 's/sqlite3-bundler-friendly.wasm/sqlite3.wasm/g' $@ || exit $$?; \
	fi
	chmod -x $(sqlite3.wasm)
	$(maybe-wasm-strip) $(sqlite3.wasm)
	@ls -la $@ $(sqlite3.wasm)
endef
emcc.flags.sqlite3.vanilla :=
emcc.flags.sqlite3.esm := -sEXPORT_ES6 -sUSE_ES6_IMPORT_META
emcc.flags.sqlite3.bundler-friendly := $(emcc.flags.sqlite3.esm)
$(sqlite3.js):
	$(call SQLITE3.xJS.RECIPE,vanilla,0)
$(sqlite3.mjs):
	$(call SQLITE3.xJS.RECIPE,esm,1)
$(sqlite3-bundler-friendly.mjs):
	$(call SQLITE3.xJS.RECIPE,bundler-friendly,1)
########################################################################
# We have to ensure that we do not build both $(sqlite3.js) and
# $(sqlite3.mjs) in parallel because both result in the creation of
# $(sqlite3.wasm). We have no(?) way to build just the .mjs file
# without also building the .wasm file. i.e.  we're building
# $(sqlite3.wasm) multiple times, but that's apparently unavoidable
# (and harmless, just a waste of build time).
$(sqlite3.wasm): $(sqlite3.js)
$(sqlite3.mjs): $(sqlite3.js)
$(sqlite3-bundler-friendly.mjs): $(sqlite3.mjs)
# maintenance reminder: the deps on ^^^ must all be such that they are
# never built in parallel.
CLEAN_FILES += $(sqlite3.js) $(sqlite3.mjs) $(sqlite3-bundler-friendly.mjs) \
    $(sqlite3.wasm)
all: $(sqlite3.js) $(sqlite3.mjs) $(sqlite3-bundler-friendly.mjs)
quick: $(sqlite3.js)
quick: $(sqlite3.mjs) # for the sake of the snapshot build
quick: $(sqlite3-bundler-friendly.mjs) # for the sake of the snapshot build
# End main $(sqlite3.js) build
########################################################################

########################################################################
# batch-runner.js is part of one of the test apps which reads in SQL
# dumps generated by $(speedtest1) and executes them.
dir.sql := sql
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792


793
794
795
796
797
798
799
#
# 1) Load sqlite3 in the main UI thread of a conventional script.
# 2) Load sqlite3 in a conventional Worker thread.
# 3) Load sqlite3 as an ES6 module (ESM) in the main thread.
# 4) Load sqlite3 as an ESM worker. (Not all browsers support this.)
#
# To that end, we require two separate builds of tester1.js:
# 
#  tester1.js: cases 1 and 2
#  tester1.mjs: cases 3 and 4
#
# To create those, we filter tester1.c-pp.js with $(bin.c-pp)...
$(eval $(call C-PP.FILTER,tester1.c-pp.js,tester1.js))
$(eval $(call C-PP.FILTER,tester1.c-pp.js,tester1.mjs,$(c-pp.D.esm)))
$(eval $(call C-PP.FILTER,tester1.c-pp.html,tester1.html))
$(eval $(call C-PP.FILTER,tester1.c-pp.html,tester1-esm.html,$(c-pp.D.esm)))
tester1: tester1.js tester1.mjs tester1.html tester1-esm.html


all quick: tester1

########################################################################
# Convenience rules to rebuild with various -Ox levels. Much
# experimentation shows -O2 to be the clear winner in terms of speed.
# Note that build times with anything higher than -O0 are somewhat
# painful.







|









>
>







830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
#
# 1) Load sqlite3 in the main UI thread of a conventional script.
# 2) Load sqlite3 in a conventional Worker thread.
# 3) Load sqlite3 as an ES6 module (ESM) in the main thread.
# 4) Load sqlite3 as an ESM worker. (Not all browsers support this.)
#
# To that end, we require two separate builds of tester1.js:
#
#  tester1.js: cases 1 and 2
#  tester1.mjs: cases 3 and 4
#
# To create those, we filter tester1.c-pp.js with $(bin.c-pp)...
$(eval $(call C-PP.FILTER,tester1.c-pp.js,tester1.js))
$(eval $(call C-PP.FILTER,tester1.c-pp.js,tester1.mjs,$(c-pp.D.esm)))
$(eval $(call C-PP.FILTER,tester1.c-pp.html,tester1.html))
$(eval $(call C-PP.FILTER,tester1.c-pp.html,tester1-esm.html,$(c-pp.D.esm)))
tester1: tester1.js tester1.mjs tester1.html tester1-esm.html
# Note that we do not include $(sqlite3-bundler-friendly.mjs) in this
# because bundlers are client-specific.
all quick: tester1

########################################################################
# Convenience rules to rebuild with various -Ox levels. Much
# experimentation shows -O2 to be the clear winner in terms of speed.
# Note that build times with anything higher than -O0 are somewhat
# painful.
Changes to ext/wasm/README-dist.txt.
1
2
3
4
5
6
7

8

9

10











11



12
13
14
15
16
17
18



19
20
21
22
23
This is the README for the sqlite3 WASM/JS distribution.

Main project page: https://sqlite.org

Documentation: https://sqlite.org/wasm

This archive contains the sqlite3.js, sqlite3.mjs, and sqlite3.wasm

files which make up the sqlite3 WASM/JS build.



The jswasm directory contains the core sqlite3 deliverables and the











top-level directory contains demonstration and test applications.




Browsers will not serve WASM files from file:// URLs, so the demo/test
apps require a web server and that server must include the following
headers in its response when serving the files:

    Cross-Origin-Opener-Policy: same-origin
    Cross-Origin-Embedder-Policy: require-corp




One simple way to get the demo apps up and running on Unix-style
systems is to install althttpd (https://sqlite.org/althttpd) and run:

    althttpd --enable-sab --page index.html






|
>
|
>

>
|
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>

|
|
|



>
>
>





1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
This is the README for the sqlite3 WASM/JS distribution.

Main project page: https://sqlite.org

Documentation: https://sqlite.org/wasm

This archive contains the following deliverables for the WASM/JS
build:

- jswasm/sqlite3.js is the canonical "vanilla JS" version.

- jswasm/sqlite3.mjs is the same but in ES6 module form

- jswasm/sqlite3-bundler-friendly.mjs is the same as the ES6 module
  with small tweaks to make it compatible with "bundler" tools
  commonly seen in node.js-based projects.

- jswasm/sqlite3.wasm is the binary WASM file imported by all of the
  above-listed JS files.

- The jswasm directory additionally contains a number of supplemental
  JS files which cannot be bundled directly with the main JS files
  but are necessary for certain usages.

- The top-level directory contains various demonstration and test
  applications for sqlite3.js and sqlite3.mjs.
  sqlite3-bundler-friendly.mjs requires client-side build tools to make
  use of and is not demonstrated here.

Browsers will not serve WASM files from file:// URLs, so the test and
demonstration apps require a web server and that server must include
the following headers in its response when serving the files:

    Cross-Origin-Opener-Policy: same-origin
    Cross-Origin-Embedder-Policy: require-corp

The core library will function without those headers but certain
features, most notably OPFS storage, will not be available.

One simple way to get the demo apps up and running on Unix-style
systems is to install althttpd (https://sqlite.org/althttpd) and run:

    althttpd --enable-sab --page index.html
Changes to ext/wasm/api/extern-post-js.c-pp.js.
41
42
43
44
45
46
47




48

49
50



51
52
53

54
55
56
57
58
59
60
61
62
     into the global scope and delete it when sqlite3InitModule()
     is called.
  */
  const initModuleState = self.sqlite3InitModuleState = Object.assign(Object.create(null),{
    moduleScript: self?.document?.currentScript,
    isWorker: ('undefined' !== typeof WorkerGlobalScope),
    location: self.location,




    urlParams: new URL(self.location.href).searchParams

  });
  initModuleState.debugModule =



    (new URL(self.location.href).searchParams).has('sqlite3.debugModule')
    ? (...args)=>console.warn('sqlite3.debugModule:',...args)
    : ()=>{};


  if(initModuleState.urlParams.has('sqlite3.dir')){
    initModuleState.sqlite3Dir = initModuleState.urlParams.get('sqlite3.dir') +'/';
  }else if(initModuleState.moduleScript){
    const li = initModuleState.moduleScript.src.split('/');
    li.pop();
    initModuleState.sqlite3Dir = li.join('/') + '/';
  }








>
>
>
>
|
>


>
>
>
|


>

|







41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
     into the global scope and delete it when sqlite3InitModule()
     is called.
  */
  const initModuleState = self.sqlite3InitModuleState = Object.assign(Object.create(null),{
    moduleScript: self?.document?.currentScript,
    isWorker: ('undefined' !== typeof WorkerGlobalScope),
    location: self.location,
    urlParams:
//#if target=es6-bundler-friendly
    undefined
//#else
    new URL(self.location.href).searchParams
//#endif
  });
  initModuleState.debugModule =
//#if target=es6-bundler-friendly
  ()=>{}
//#else
  (new URL(self.location.href).searchParams).has('sqlite3.debugModule')
    ? (...args)=>console.warn('sqlite3.debugModule:',...args)
    : ()=>{};
//#endif

  if(initModuleState.urlParams && initModuleState.urlParams.has('sqlite3.dir')){
    initModuleState.sqlite3Dir = initModuleState.urlParams.get('sqlite3.dir') +'/';
  }else if(initModuleState.moduleScript){
    const li = initModuleState.moduleScript.src.split('/');
    li.pop();
    initModuleState.sqlite3Dir = li.join('/') + '/';
  }

101
102
103
104
105
106
107




108
109
110
111
112
113
114
115
116

117
118
119
120
121
    console.warn("Replaced sqlite3InitModule()");
    console.warn("self.location.href =",self.location.href);
    if('undefined' !== typeof document){
      console.warn("document.currentScript.src =",
                   document?.currentScript?.src);
    }
  }




  /* Replace the various module exports performed by the Emscripten
     glue... */
  if (typeof exports === 'object' && typeof module === 'object'){
    module.exports = sqlite3InitModule;
  }else if (typeof exports === 'object'){
    exports["sqlite3InitModule"] = sqlite3InitModule;
  }
  /* AMD modules get injected in a way we cannot override,
     so we can't handle those here. */

  return self.sqlite3InitModule /* required for ESM */;
})();
//#if target=es6-module
export default toExportForES6;
//#endif







>
>
>
>









>





110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
    console.warn("Replaced sqlite3InitModule()");
    console.warn("self.location.href =",self.location.href);
    if('undefined' !== typeof document){
      console.warn("document.currentScript.src =",
                   document?.currentScript?.src);
    }
  }
//#ifnot target=es6-module
// Emscripten does not inject these module-loader bits in ES6 module
// build and including them here breaks JS bundlers, so elide them
// from ES6 builds.
  /* Replace the various module exports performed by the Emscripten
     glue... */
  if (typeof exports === 'object' && typeof module === 'object'){
    module.exports = sqlite3InitModule;
  }else if (typeof exports === 'object'){
    exports["sqlite3InitModule"] = sqlite3InitModule;
  }
  /* AMD modules get injected in a way we cannot override,
     so we can't handle those here. */
//#endif // !target=es6-module
  return self.sqlite3InitModule /* required for ESM */;
})();
//#if target=es6-module
export default toExportForES6;
//#endif
Changes to ext/wasm/api/pre-js.c-pp.js.
1
2
3
4
5
6
7
8
9



10
11
12

13
14
15
16
17
18
19
/**
   BEGIN FILE: api/pre-js.js

   This file is intended to be prepended to the sqlite3.js build using
   Emscripten's --pre-js=THIS_FILE flag (or equivalent).
*/

// See notes in extern-post-js.js
const sqlite3InitModuleState = self.sqlite3InitModuleState || Object.create(null);



delete self.sqlite3InitModuleState;
sqlite3InitModuleState.debugModule('self.location =',self.location);


/**
   This custom locateFile() tries to figure out where to load `path`
   from. The intent is to provide a way for foo/bar/X.js loaded from a
   Worker constructor or importScripts() to be able to resolve
   foo/bar/X.wasm (in the latter case, with some help):

   1) If URL param named the same as `path` is set, it is returned.








|
>
>
>



>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
   BEGIN FILE: api/pre-js.js

   This file is intended to be prepended to the sqlite3.js build using
   Emscripten's --pre-js=THIS_FILE flag (or equivalent).
*/

// See notes in extern-post-js.js
const sqlite3InitModuleState = self.sqlite3InitModuleState
      || Object.assign(Object.create(null),{
        debugModule: ()=>{}
      });
delete self.sqlite3InitModuleState;
sqlite3InitModuleState.debugModule('self.location =',self.location);

//#ifnot target=es6-bundler-friendly
/**
   This custom locateFile() tries to figure out where to load `path`
   from. The intent is to provide a way for foo/bar/X.js loaded from a
   Worker constructor or importScripts() to be able to resolve
   foo/bar/X.wasm (in the latter case, with some help):

   1) If URL param named the same as `path` is set, it is returned.
47
48
49
50
51
52
53
54
55

56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
  sqlite3InitModuleState.debugModule(
    "locateFile(",arguments[0], ',', arguments[1],")",
    'sqlite3InitModuleState.scriptDir =',this.scriptDir,
    'up.entries() =',Array.from(up.entries()),
    "result =", theFile
  );
  return theFile;
//#endif /* SQLITE_JS_EMS */
}.bind(sqlite3InitModuleState);


/**
   Bug warning: a custom Module.instantiateWasm() does not work
   in WASMFS builds:

   https://github.com/emscripten-core/emscripten/issues/17951

   In such builds we must disable this.
*/
const xNameOfInstantiateWasm = true
      ? 'instantiateWasm'
      : 'emscripten-bug-17951';
Module[xNameOfInstantiateWasm] = function callee(imports,onSuccess){
  imports.env.foo = function(){};
  const uri = Module.locateFile(
    callee.uri, (
      ('undefined'===typeof scriptDirectory/*var defined by Emscripten glue*/)







|

>









|







51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
  sqlite3InitModuleState.debugModule(
    "locateFile(",arguments[0], ',', arguments[1],")",
    'sqlite3InitModuleState.scriptDir =',this.scriptDir,
    'up.entries() =',Array.from(up.entries()),
    "result =", theFile
  );
  return theFile;
//#endif //target=es6-module
}.bind(sqlite3InitModuleState);
//#endif //ifnot target=es6-bundler-friendly

/**
   Bug warning: a custom Module.instantiateWasm() does not work
   in WASMFS builds:

   https://github.com/emscripten-core/emscripten/issues/17951

   In such builds we must disable this.
*/
const xNameOfInstantiateWasm = false
      ? 'instantiateWasm'
      : 'emscripten-bug-17951';
Module[xNameOfInstantiateWasm] = function callee(imports,onSuccess){
  imports.env.foo = function(){};
  const uri = Module.locateFile(
    callee.uri, (
      ('undefined'===typeof scriptDirectory/*var defined by Emscripten glue*/)
Changes to ext/wasm/api/sqlite3-api-oo1.js.
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
      const postInitSql = __vfsPostOpenSql[pVfs];
      if(postInitSql instanceof Function){
        postInitSql(this, sqlite3);
      }else if(postInitSql){
        checkSqlite3Rc(
          pDb, capi.sqlite3_exec(pDb, postInitSql, 0, 0, 0)
        );
      }      
    }catch(e){
      this.close();
      throw e;
    }
  };

  /**







|







179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
      const postInitSql = __vfsPostOpenSql[pVfs];
      if(postInitSql instanceof Function){
        postInitSql(this, sqlite3);
      }else if(postInitSql){
        checkSqlite3Rc(
          pDb, capi.sqlite3_exec(pDb, postInitSql, 0, 0, 0)
        );
      }
    }catch(e){
      this.close();
      throw e;
    }
  };

  /**
786
787
788
789
790
791
792



793
794
795
796
797
798
799
       - `bind`: permit an array of arrays/objects to bind. The first
       sub-array would act on the first statement which has bindable
       parameters (as it does now). The 2nd would act on the next such
       statement, etc.

       - `callback` and `resultRows`: permit an array entries with
       semantics similar to those described for `bind` above.




    */
    exec: function(/*(sql [,obj]) || (obj)*/){
      affirmDbOpen(this);
      const arg = parseExecArgs(this, arguments);
      if(!arg.sql){
        return toss3("exec() requires an SQL string.");







>
>
>







786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
       - `bind`: permit an array of arrays/objects to bind. The first
       sub-array would act on the first statement which has bindable
       parameters (as it does now). The 2nd would act on the next such
       statement, etc.

       - `callback` and `resultRows`: permit an array entries with
       semantics similar to those described for `bind` above.

       - If passed neither a callback nor returnValue but is passed a
         rowMode, default to returning the result set.

    */
    exec: function(/*(sql [,obj]) || (obj)*/){
      affirmDbOpen(this);
      const arg = parseExecArgs(this, arguments);
      if(!arg.sql){
        return toss3("exec() requires an SQL string.");
Changes to ext/wasm/api/sqlite3-api-worker1.js.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/*
  2022-07-22

  The author disclaims copyright to this source code.  In place of a
  legal notice, here is a blessing:

  *   May you do good and not evil.
  *   May you find forgiveness for yourself and forgive others.
  *   May you share freely, never taking more than you give.

  ***********************************************************************

  This file implements the initializer for the sqlite3 "Worker API
  #1", a very basic DB access API intended to be scripted from a main
  window thread via Worker-style messages. Because of limitations in
  that type of communication, this API is minimalistic and only
  capable of serving relatively basic DB requests (e.g. it cannot
  process nested query loops concurrently).

  This file requires that the core C-style sqlite3 API and OO API #1
  have been loaded.
*/

/**
  sqlite3.initWorker1API() implements a Worker-based wrapper around
|











|
|
|
|
|
|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
  2022-07-22

  The author disclaims copyright to this source code.  In place of a
  legal notice, here is a blessing:

  *   May you do good and not evil.
  *   May you find forgiveness for yourself and forgive others.
  *   May you share freely, never taking more than you give.

  ***********************************************************************

  This file implements the initializer for SQLite's "Worker API #1", a
  very basic DB access API intended to be scripted from a main window
  thread via Worker-style messages. Because of limitations in that
  type of communication, this API is minimalistic and only capable of
  serving relatively basic DB requests (e.g. it cannot process nested
  query loops concurrently).

  This file requires that the core C-style sqlite3 API and OO API #1
  have been loaded.
*/

/**
  sqlite3.initWorker1API() implements a Worker-based wrapper around
Changes to ext/wasm/api/sqlite3-vfs-opfs.c-pp.js.
96
97
98
99
100
101
102




103


104
105
106
107
108
109

110
111
112
113
114
115
116
    return Promise.reject(
      new Error("Missing required OPFS APIs.")
    );
  }
  if(!options || 'object'!==typeof options){
    options = Object.create(null);
  }




  const urlParams = new URL(self.location.href).searchParams;


  if(undefined===options.verbose){
    options.verbose = urlParams.has('opfs-verbose')
      ? (+urlParams.get('opfs-verbose') || 2) : 1;
  }
  if(undefined===options.sanityChecks){
    options.sanityChecks = urlParams.has('opfs-sanity-check');

  }
  if(undefined===options.proxyUri){
    options.proxyUri = callee.defaultProxyUri;
  }

  //console.warn("OPFS options =",options,self.location);








>
>
>
>
|
>
>
|
|
|
|
|
|
>







96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
    return Promise.reject(
      new Error("Missing required OPFS APIs.")
    );
  }
  if(!options || 'object'!==typeof options){
    options = Object.create(null);
  }
  const urlParams =
//#if target=es6-bundler-friendly
        undefined;
//#else
        new URL(self.location.href).searchParams;
//#endif
  if(urlParams){
    if(undefined===options.verbose){
      options.verbose = urlParams.has('opfs-verbose')
        ? (+urlParams.get('opfs-verbose') || 2) : 1;
    }
    if(undefined===options.sanityChecks){
      options.sanityChecks = urlParams.has('opfs-sanity-check');
    }
  }
  if(undefined===options.proxyUri){
    options.proxyUri = callee.defaultProxyUri;
  }

  //console.warn("OPFS options =",options,self.location);

194
195
196
197
198
199
200
201


202
203
204
205
206
207
208
    const opfsVfs = new sqlite3_vfs();
    const opfsIoMethods = new sqlite3_io_methods();
    const promiseReject = function(err){
      opfsVfs.dispose();
      return promiseReject_(err);
    };
    const W =
//#if target=es6-module


    new Worker(new URL(options.proxyUri, import.meta.url));
//#else
    new Worker(options.proxyUri);
//#endif
    W._originalOnError = W.onerror /* will be restored later */;
    W.onerror = function(err){
      // The error object doesn't contain any useful info when the







|
>
>







201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
    const opfsVfs = new sqlite3_vfs();
    const opfsIoMethods = new sqlite3_io_methods();
    const promiseReject = function(err){
      opfsVfs.dispose();
      return promiseReject_(err);
    };
    const W =
//#if target=es6-bundler-friendly
    new Worker(new URL("sqlite3-opfs-async-proxy.js", import.meta.url));
//#elif target=es6-module
    new Worker(new URL(options.proxyUri, import.meta.url));
//#else
    new Worker(options.proxyUri);
//#endif
    W._originalOnError = W.onerror /* will be restored later */;
    W.onerror = function(err){
      // The error object doesn't contain any useful info when the
Changes to ext/wasm/api/sqlite3-worker1-promiser.js.
234
235
236
237
238
239
240



241
242
243
244
245
246
247
248
249
250
251
252
253
254

255
256
257
258
259
    });
    if(rowCallbackId) p = p.finally(()=>delete handlerMap[rowCallbackId]);
    return p;
  };
}/*sqlite3Worker1Promiser()*/;
self.sqlite3Worker1Promiser.defaultConfig = {
  worker: function(){



    let theJs = "sqlite3-worker1.js";
    if(this.currentScript){
      const src = this.currentScript.src.split('/');
      src.pop();
      theJs = src.join('/')+'/' + theJs;
      //console.warn("promiser currentScript, theJs =",this.currentScript,theJs);
    }else{
      //console.warn("promiser self.location =",self.location);
      const urlParams = new URL(self.location.href).searchParams;
      if(urlParams.has('sqlite3.dir')){
        theJs = urlParams.get('sqlite3.dir') + '/' + theJs;
      }
    }
    return new Worker(theJs + self.location.search);

  }.bind({
    currentScript: self?.document?.currentScript
  }),
  onerror: (...args)=>console.error('worker1 promiser error',...args)
};







>
>
>














>





234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
    });
    if(rowCallbackId) p = p.finally(()=>delete handlerMap[rowCallbackId]);
    return p;
  };
}/*sqlite3Worker1Promiser()*/;
self.sqlite3Worker1Promiser.defaultConfig = {
  worker: function(){
//#if target=es6-bundler-friendly
    return new Worker("sqlite3-worker1.js");
//#else
    let theJs = "sqlite3-worker1.js";
    if(this.currentScript){
      const src = this.currentScript.src.split('/');
      src.pop();
      theJs = src.join('/')+'/' + theJs;
      //console.warn("promiser currentScript, theJs =",this.currentScript,theJs);
    }else{
      //console.warn("promiser self.location =",self.location);
      const urlParams = new URL(self.location.href).searchParams;
      if(urlParams.has('sqlite3.dir')){
        theJs = urlParams.get('sqlite3.dir') + '/' + theJs;
      }
    }
    return new Worker(theJs + self.location.search);
//#endif
  }.bind({
    currentScript: self?.document?.currentScript
  }),
  onerror: (...args)=>console.error('worker1 promiser error',...args)
};
Changes to ext/wasm/api/sqlite3-worker1.js.
29
30
31
32
33
34
35



36
37
38
39
40
41
42

43
44
45
46
  This file accepts a URL arguments to adjust how it loads sqlite3.js:

  - `sqlite3.dir`, if set, treats the given directory name as the
    directory from which `sqlite3.js` will be loaded.
*/
"use strict";
(()=>{



  const urlParams = new URL(self.location.href).searchParams;
  let theJs = 'sqlite3.js';
  if(urlParams.has('sqlite3.dir')){
    theJs = urlParams.get('sqlite3.dir') + '/' + theJs;
  }
  //console.warn("worker1 theJs =",theJs);
  importScripts(theJs);

  sqlite3InitModule().then((sqlite3)=>{
    sqlite3.initWorker1API();
  });
})();







>
>
>







>




29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
  This file accepts a URL arguments to adjust how it loads sqlite3.js:

  - `sqlite3.dir`, if set, treats the given directory name as the
    directory from which `sqlite3.js` will be loaded.
*/
"use strict";
(()=>{
//#if target=es6-bundler-friendly
  importScripts('sqlite3.js');
//#else
  const urlParams = new URL(self.location.href).searchParams;
  let theJs = 'sqlite3.js';
  if(urlParams.has('sqlite3.dir')){
    theJs = urlParams.get('sqlite3.dir') + '/' + theJs;
  }
  //console.warn("worker1 theJs =",theJs);
  importScripts(theJs);
//#endif
  sqlite3InitModule().then((sqlite3)=>{
    sqlite3.initWorker1API();
  });
})();
Changes to ext/wasm/c-pp.c.
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
** string when compiling to define the default at build-time.
**
** This preprocessor does no expansion of content except within the
** bounds of its `#keywords`.
**
** Design note: this code makes use of sqlite3. Though not _strictly_
** needed in order to implement it, this tool was specifically created
** for potential use with the sqlite3 project's own JavaScript code,
** so there's no reason not to make use of it to do some of the heavy
** lifting. It does not require any cutting-edge sqlite3 features and
** should be usable with any version which supports `WITHOUT ROWID`.
**
** Author(s):
**
** - Stephan Beal <https://wanderinghorse.net/home/stephan/>
*/

#include <stdlib.h>







|
|
|
|







47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
** string when compiling to define the default at build-time.
**
** This preprocessor does no expansion of content except within the
** bounds of its `#keywords`.
**
** Design note: this code makes use of sqlite3. Though not _strictly_
** needed in order to implement it, this tool was specifically created
** for use with the sqlite3 project's own JavaScript code, so there's
** no reason not to make use of it to do some of the heavy lifting. It
** does not require any cutting-edge sqlite3 features and should be
** usable with any version which supports `WITHOUT ROWID`.
**
** Author(s):
**
** - Stephan Beal <https://wanderinghorse.net/home/stephan/>
*/

#include <stdlib.h>
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617


618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633

634
635
636
637
638

639
640
641
642
643
644




645




646
647
648
649
650
651
652
void g_stderr(char const *zFmt, ...){
  va_list va;
  va_start(va, zFmt);
  g_stderrv(zFmt, va);
  va_end(va);
}

#if 0
void cmpp_t_outf(CmppTokenizer * t, char const *zFmt, ...){
  if(!CT_skip(t)){
    va_list va;
    va_start(va, zFmt);
    vfprintf(g.out.pFile, zFmt, va);
    va_end(va);
  }
}
#endif

void cmpp_t_out(CmppTokenizer * t, void const *z, unsigned int n){


  if(!CT_skip(t)){
    if(1!=fwrite(z, n, 1, g.out.pFile)){
      int const err = errno;
      fatal("fwrite() output failed with errno #%d", err);
    }
  }
}

void CmppLevel_push(CmppTokenizer * const t){
  CmppLevel * pPrev;
  CmppLevel * p;
  if(t->level.ndx+1 == (unsigned)CmppLevel_Max){
    fatal("%sif nesting level is too deep. Max=%d\n",
          g.zDelim, CmppLevel_Max);
  }
  pPrev = &CT_level(t);

  p = &t->level.stack[++t->level.ndx];
  *p = CmppLevel_empty;
  p->token = t->token;
  p->flags = (CmppLevel_F_INHERIT_MASK & pPrev->flags);
  if(CLvl_skip(pPrev)) p->flags |= CmppLevel_F_ELIDE;

}

void CmppLevel_pop(CmppTokenizer * const t){
  if(!t->level.ndx){
    fatal("Internal error: CmppLevel_pop() at the top of the stack");
  }




  t->level.stack[t->level.ndx--] = CmppLevel_empty;




}

CmppLevel * CmppLevel_get(CmppTokenizer * const t){
  return &t->level.stack[t->level.ndx];
}









<
<
<
<
<
<
<
<
<
<
<

>
>
















>





>






>
>
>
>

>
>
>
>







599
600
601
602
603
604
605











606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
void g_stderr(char const *zFmt, ...){
  va_list va;
  va_start(va, zFmt);
  g_stderrv(zFmt, va);
  va_end(va);
}












void cmpp_t_out(CmppTokenizer * t, void const *z, unsigned int n){
  g_debug(3,("CT_skipLevel() ?= %d\n",CT_skipLevel(t)));
  g_debug(3,("CT_skip() ?= %d\n",CT_skip(t)));
  if(!CT_skip(t)){
    if(1!=fwrite(z, n, 1, g.out.pFile)){
      int const err = errno;
      fatal("fwrite() output failed with errno #%d", err);
    }
  }
}

void CmppLevel_push(CmppTokenizer * const t){
  CmppLevel * pPrev;
  CmppLevel * p;
  if(t->level.ndx+1 == (unsigned)CmppLevel_Max){
    fatal("%sif nesting level is too deep. Max=%d\n",
          g.zDelim, CmppLevel_Max);
  }
  pPrev = &CT_level(t);
  g_debug(3,("push from tokenizer level=%u flags=%04x\n", t->level.ndx, pPrev->flags));
  p = &t->level.stack[++t->level.ndx];
  *p = CmppLevel_empty;
  p->token = t->token;
  p->flags = (CmppLevel_F_INHERIT_MASK & pPrev->flags);
  if(CLvl_skip(pPrev)) p->flags |= CmppLevel_F_ELIDE;
  g_debug(3,("push to tokenizer level=%u flags=%04x\n", t->level.ndx, p->flags));
}

void CmppLevel_pop(CmppTokenizer * const t){
  if(!t->level.ndx){
    fatal("Internal error: CmppLevel_pop() at the top of the stack");
  }
  g_debug(3,("pop from tokenizer level=%u, flags=%04x skipLevel?=%d\n", t->level.ndx,
             t->level.stack[t->level.ndx].flags, CT_skipLevel(t)));
  g_debug(3,("CT_skipLevel() ?= %d\n",CT_skipLevel(t)));
  g_debug(3,("CT_skip() ?= %d\n",CT_skip(t)));
  t->level.stack[t->level.ndx--] = CmppLevel_empty;
  g_debug(3,("pop to tokenizer level=%u, flags=%04x\n", t->level.ndx,
             t->level.stack[t->level.ndx].flags));
  g_debug(3,("CT_skipLevel() ?= %d\n",CT_skipLevel(t)));
  g_debug(3,("CT_skip() ?= %d\n",CT_skip(t)));
}

CmppLevel * CmppLevel_get(CmppTokenizer * const t){
  return &t->level.stack[t->level.ndx];
}


772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
  rc = db_step(g.stmt.defHas);
  if(SQLITE_ROW == rc){
    rc = 1;
  }else{
    assert(SQLITE_DONE==rc);
    rc = 0;
  }
  g_debug(1,("define has [%s] = %d\n",zName, rc));
  sqlite3_clear_bindings(g.stmt.defHas);
  sqlite3_reset(g.stmt.defHas);
  return rc;
}


void db_define_rm(const char * zKey){







|







773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
  rc = db_step(g.stmt.defHas);
  if(SQLITE_ROW == rc){
    rc = 1;
  }else{
    assert(SQLITE_DONE==rc);
    rc = 0;
  }
  g_debug(1,("defined [%s] ?= %d\n",zName, rc));
  sqlite3_clear_bindings(g.stmt.defHas);
  sqlite3_reset(g.stmt.defHas);
  return rc;
}


void db_define_rm(const char * zKey){
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226

1227
1228
1229
1230
1231
1232
1233
1234
1235
1236

1237
1238
1239

1240

1241
1242
1243
1244
1245
1246
1247
      cmpp_kwd__misuse(pKw, t, "Unpexected keyword token type");
      break;
  }
  buul = db_define_has((char const *)t->args.argv[1]);
  if(TT_IfNot==pKw->ttype || TT_ElifNot==pKw->ttype) buul = !buul;
  if(buul){
    CT_pstate(t) = tmpState = TS_IfPassed;
    CT_skipLevel(t) = 0;    
  }else{
    CT_pstate(t) = TS_If /* also for TT_IfNot, TT_Elif, TT_ElifNot */;
    CT_skipLevel(t) = 1;

  }
  if(TT_If==pKw->ttype || TT_IfNot==pKw->ttype){
    unsigned const lvlIf = t->level.ndx;
    CmppToken const lvlToken = CT_level(t).token;
    while(cmpp_next_keyword_line(t)){
      cmpp_process_keyword(t);
      if(lvlIf > t->level.ndx){
        assert(TT_EndIf == t->token.ttype);
        break;
      }

      if(TS_IfPassed==tmpState){
        tmpState = TS_Start;
        t->level.stack[lvlIf].flags |= CmppLevel_F_ELIDE;

      }

    }
    if(lvlIf <= t->level.ndx){
      cmpp_kwd__err_prefix(pKw, t, NULL);
      fatal("Input ended inside an unterminated %sif "
            "opened at [%s] line %u",
            g.zDelim, t->zName, lvlToken.lineNo);
    }







|



>










>



>

>







1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
      cmpp_kwd__misuse(pKw, t, "Unpexected keyword token type");
      break;
  }
  buul = db_define_has((char const *)t->args.argv[1]);
  if(TT_IfNot==pKw->ttype || TT_ElifNot==pKw->ttype) buul = !buul;
  if(buul){
    CT_pstate(t) = tmpState = TS_IfPassed;
    CT_skipLevel(t) = 0;
  }else{
    CT_pstate(t) = TS_If /* also for TT_IfNot, TT_Elif, TT_ElifNot */;
    CT_skipLevel(t) = 1;
    g_debug(3,("setting CT_skipLevel = 1 @ level %d\n", t->level.ndx));
  }
  if(TT_If==pKw->ttype || TT_IfNot==pKw->ttype){
    unsigned const lvlIf = t->level.ndx;
    CmppToken const lvlToken = CT_level(t).token;
    while(cmpp_next_keyword_line(t)){
      cmpp_process_keyword(t);
      if(lvlIf > t->level.ndx){
        assert(TT_EndIf == t->token.ttype);
        break;
      }
#if 0
      if(TS_IfPassed==tmpState){
        tmpState = TS_Start;
        t->level.stack[lvlIf].flags |= CmppLevel_F_ELIDE;
        g_debug(1,("Setting ELIDE for TS_IfPassed @ lv %d (lvlIf=%d)\n", t->level.ndx, lvlIf));
      }
#endif
    }
    if(lvlIf <= t->level.ndx){
      cmpp_kwd__err_prefix(pKw, t, NULL);
      fatal("Input ended inside an unterminated %sif "
            "opened at [%s] line %u",
            g.zDelim, t->zName, lvlToken.lineNo);
    }
Changes to ext/wasm/dist.make.
80
81
82
83
84
85
86


87
88
89
90
91
92
93
	@cp -p README-dist.txt $(dist-dir.top)/README.txt
	@cp -p index-dist.html $(dist-dir.top)/index.html
	@cp -p $(dist.jswasm.extras) $(dist-dir.jswasm)
	@$(bin.stripccomments) -k -k < $(sqlite3.js) \
		> $(dist-dir.jswasm)/$(notdir $(sqlite3.js))
	@$(bin.stripccomments) -k -k < $(sqlite3.mjs) \
		> $(dist-dir.jswasm)/$(notdir $(sqlite3.mjs))


	@cp -p $(dist.common.extras) $(dist-dir.common)
	@set -e; \
		vnum=$$($(bin.version-info) --download-version); \
		vdir=$(dist-name-prefix)-$$vnum; \
		arczip=$$vdir.zip; \
		echo "Making $$arczip ..."; \
		rm -fr $$arczip $$vdir; \







>
>







80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
	@cp -p README-dist.txt $(dist-dir.top)/README.txt
	@cp -p index-dist.html $(dist-dir.top)/index.html
	@cp -p $(dist.jswasm.extras) $(dist-dir.jswasm)
	@$(bin.stripccomments) -k -k < $(sqlite3.js) \
		> $(dist-dir.jswasm)/$(notdir $(sqlite3.js))
	@$(bin.stripccomments) -k -k < $(sqlite3.mjs) \
		> $(dist-dir.jswasm)/$(notdir $(sqlite3.mjs))
	@$(bin.stripccomments) -k -k < $(sqlite3-bundler-friendly.mjs) \
		> $(dist-dir.jswasm)/$(notdir $(sqlite3-bundler-friendly.mjs))
	@cp -p $(dist.common.extras) $(dist-dir.common)
	@set -e; \
		vnum=$$($(bin.version-info) --download-version); \
		vdir=$(dist-name-prefix)-$$vnum; \
		arczip=$$vdir.zip; \
		echo "Making $$arczip ..."; \
		rm -fr $$arczip $$vdir; \