aboutsummaryrefslogtreecommitdiff
path: root/autosetup/sqlite-config.tcl
blob: 1df6e233ff48f12a0fdbff812fa2ea7d891f9cff (plain)
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
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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
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
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
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
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
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
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
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
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
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
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
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
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
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
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
# This file holds functions for autosetup which are specific to the
# sqlite build tree.  They are in this file, instead of auto.def, so
# that they can be reused in the autoconf sub-tree. This file requires
# functions from proj.tcl.

if {[string first " " $autosetup(srcdir)] != -1} {
  user-error "The pathname of the source tree\
              may not contain space characters"
}
if {[string first " " $autosetup(builddir)] != -1} {
  user-error "The pathname of the build directory\
              may not contain space characters"
}
#parray ::autosetup; exit 0
use proj
#
# We want the package version info to be emitted early on, but doing
# so requires a bit of juggling. We have to [use system] for
# --prefix=... to work and to emit the Host/Build system info, but we
# don't want those to interfere with --help output.
define PACKAGE_VERSION [proj-file-content -trim $::autosetup(srcdir)/VERSION]
if {"--help" ni $::argv} {
  msg-result "Configuring SQLite version [get-define PACKAGE_VERSION]"
}
use system ; # Will output "Host System" and "Build System" lines
if {"--help" ni $::argv} {
  proj-tweak-default-env-dirs
  msg-result "Source dir = $::autosetup(srcdir)"
  msg-result "Build dir  = $::autosetup(builddir)"
  use cc cc-db cc-shared cc-lib pkg-config
}

#
# Object for communicating certain config-time state across various
# auto.def-related pieces.
array set sqliteConfig [subst [proj-strip-hash-comments {
  #
  # Gets set by [sqlite-configure] (the main configure script driver).
  build-mode unknown
  #
  # Gets set to 1 when using jimsh for code generation. May affect
  # later decisions.
  use-jim-for-codegen  0
  #
  # Set to 1 when cross-compiling This value may be changed by certain
  # build options, so it's important that config code which checks for
  # cross-compilation uses this var instead of
  # [proj-is-cross-compiling].
  is-cross-compiling [proj-is-cross-compiling]
  #
  # Pass msg-debug=1 to configure to enable obnoxiously loud output
  # from [msg-debug].
  msg-debug-enabled    0
  #
  # Output file for --dump-defines. Intended only for build debugging
  # and not part of the public build interface.
  dump-defines-txt   ./config.defines.txt
  #
  # If not empty then --dump-defines will dump not only
  # (dump-defines-txt) but also a JSON file named after this option's
  # value.
  dump-defines-json  ""

  #
  # The list of feature --flags which the --all flag implies. This
  # requires special handling in a few places.
  #
  all-flag-enables {fts4 fts5 rtree geopoly session}

  #
  # Default value for the --all flag. Can hypothetically be modified
  # by non-canonical builds.
  #
  all-flag-default 0
}]]

########################################################################
# Processes all configure --flags for this build, run build-specific
# config checks, then finalize the configure process. $buildMode must
# be one of (canonical, autoconf), and others may be added in the
# future. After bootstrapping, $configScript is eval'd in the caller's
# scope, then post-configuration finalization is run. $configScript is
# intended to hold configure code which is specific to the given
# $buildMode, with the caveat that _some_ build-specific code is
# encapsulated in the configuration finalization step.
#
# The intent is that all (or almost all) build-mode-specific
# configuration goes inside the $configScript argument to this
# function, and that an auto.def file contains only two commands:
#
#  use sqlite-config
#  sqlite-configure BUILD_NAME { build-specific configure script }
#
# There are snippets of build-mode-specific decision-making in
# [sqlite-configure-finalize]
proc sqlite-configure {buildMode configScript} {
  proj-assert {$::sqliteConfig(build-mode) eq "unknown"} \
    "sqlite-configure must not be called more than once"
  set allBuildModes {canonical autoconf}
  if {$buildMode ni $allBuildModes} {
    user-error "Invalid build mode: $buildMode. Expecting one of: $allBuildModes"
  }
  if {$::sqliteConfig(all-flag-default)} {
    set allFlagHelp "Disable these extensions: $::sqliteConfig(all-flag-enables)"
  } else {
    set allFlagHelp "Enable these extensions: $::sqliteConfig(all-flag-enables)"
  }

  set ::sqliteConfig(build-mode) $buildMode
  ########################################################################
  # A gentle introduction to flags handling in autosetup
  #
  # Reference: https://msteveb.github.io/autosetup/developer/
  #
  # All configure flags must be described in an 'options' call. The
  # general syntax is:
  #
  #  FLAG => {Help text}
  #
  # Where FLAG can have any of the following formats:
  #
  #   boolopt            => "a boolean option which defaults to disabled"
  #   boolopt2=1         => "a boolean option which defaults to enabled"
  #   stringopt:         => "an option which takes an argument, e.g. --stringopt=value"
  #   stringopt:DESCR    => As for stringopt: with a description for the value
  #   stringopt2:=value  => "an option where the argument is optional and defaults to 'value'"
  #   optalias booltopt3 => "a boolean with a hidden alias. --optalias is not shown in --help"
  #
  # Autosetup does no small amount of specialized handling for flags,
  # especially booleans. Each bool-type --FLAG implicitly gets
  # --enable-FLAG and --disable-FLAG forms. That can lead lead to some
  # confusion when writing help text. For example:
  #
  #   options { json=1 {Disable JSON functions} }
  #
  # The reason the help text says "disable" is because a boolean option
  # which defaults to true is, in the --help text, rendered as:
  #
  #   --disable-json          Disable JSON functions
  #
  # Whereas a bool flag which defaults to false will instead render as:
  #
  #   --enable-FLAG
  #
  # Non-boolean flags, in contrast, use the names specifically given to
  # them in the [options] invocation. e.g. "with-tcl" is the --with-tcl
  # flag.
  #
  # Fetching values for flags:
  #
  #   booleans: use one of:
  #     - [opt-bool FLAG] is autosetup's built-in command for this, but we
  #       have some convenience variants:
  #     - [proj-opt-truthy FLAG]
  #     - [proj-opt-if-truthy FLAG {THEN} {ELSE}]
  #
  #   Non-boolean (i.e. string) flags:
  #     - [opt-val FLAG ?default?]
  #     - [opt-str ...] - see the docs in ./autosetup/autosetup
  #
  # [proj-opt-was-provided] can be used to determine whether a flag was
  # explicitly provided, which is often useful for distinguishing from
  # the case of a default value.
  ########################################################################
  set allFlags {
    # Structure: a list of M {Z} pairs, where M is a descriptive
    # option group name  and Z is a list of X Y pairs. X is a list of
    # $buildMode name(s) to which the Y flags apply, or {*} to apply
    # to all builds. Y is a {block} in the form expected by
    # autosetup's [options] command.  Each block which is applicable
    # to $buildMode is appended to a new list before that list is
    # passed on to [options]. The order of each Y and sub-Y is
    # retained, which is significant for rendering of --help.

    # When writing {help text blocks}, be aware that:
    #
    # A) autosetup formats them differently if the {block} starts with
    # a newline: it starts left-aligned, directly under the --flag, and
    # the rest of the block is pasted verbatim rather than
    # pretty-printed.
    #
    # B) Vars and commands are NOT expanded, but we use a [subst] call
    # below which will replace (only) var refs.

    # Options for how to build the library
    build-modes {
      {canonical autoconf} {
        shared=1             => {Disable build of shared library}
        static=1             => {Disable build of static library}
      }
      {canonical} {
        amalgamation=1       => {Disable the amalgamation and instead build all files separately}
      }
    }

    # Library-level features and defaults
    lib-features {
      {*} {
        threadsafe=1         => {Disable mutexing}
        with-tempstore:=no   => {Use an in-RAM database for temporary tables: never,no,yes,always}
        load-extension=1     => {Disable loading of external extensions}
        # ^^^ one of the downstream custom builds overrides the load-extension default to 0, which
        # confuses the --help text generator. https://github.com/msteveb/autosetup/issues/77
        math=1               => {Disable math functions}
        json=1               => {Disable JSON functions}
        memsys5              => {Enable MEMSYS5}
        memsys3              => {Enable MEMSYS3}
        fts3                 => {Enable the FTS3 extension}
        fts4                 => {Enable the FTS4 extension}
        fts5                 => {Enable the FTS5 extension}
        update-limit         => {Enable the UPDATE/DELETE LIMIT clause}
        geopoly              => {Enable the GEOPOLY extension}
        rtree                => {Enable the RTREE extension}
        session              => {Enable the SESSION extension}
        all=$::sqliteConfig(all-flag-default) => {$allFlagHelp}
        largefile=1
          => {This legacy flag has no effect on the library but may influence
              the generated sqlite_cfg.h by adding #define HAVE_LFS}
      }
    }

    # Options for TCL support
    tcl {
      {canonical} {
        tcl=1
          => {Disable components which require TCL, including all tests.
              This tree requires TCL for code generation but can use the in-tree
              copy of autosetup/jimsh0.c for that. The SQLite TCL extension and the
              test code require a canonical tclsh.}
      }
      {canonical} {
        with-tcl:DIR
          => {Directory containing tclConfig.sh or a directory one level up from
              that, from which we can derive a directory containing tclConfig.sh.
              A dir name of "prefix" is equivalent to the directory specified by
              the --prefix flag.}
        with-tclsh:PATH
          => {Full pathname of tclsh to use.  It is used for (A) trying to find
              tclConfig.sh and (B) all TCL-based code generation.  Warning: if
              its containing dir has multiple tclsh versions, it may select the
              wrong tclConfig.sh!}
      }
      {canonical} {
        static-tclsqlite3=0
          => {Statically-link tclsqlite3. This only works if TCL support is
              enabled and all requisite libraries are available in
              static form. Note that glibc is unable to fully statically
              link certain libraries required by tclsqlite3, so this won't
              work on most Linux environments.}
      }
    }

    # Options for line-editing modes for the CLI shell
    line-editing {
      {canonical autoconf} {
        readline=1
          => {Disable readline support}
        # --with-readline-lib is a backwards-compatible alias for
        # --with-readline-ldflags
        with-readline-lib:
        with-readline-ldflags:=auto
          => {Readline LDFLAGS, e.g. -lreadline -lncurses}
        # --with-readline-inc is a backwards-compatible alias for
        # --with-readline-cflags.
        with-readline-inc:
        with-readline-cflags:=auto
          => {Readline CFLAGS, e.g. -I/path/to/includes}
        with-readline-header:PATH
          => {Full path to readline.h, from which --with-readline-cflags will be derived}
        with-linenoise:DIR
          => {Source directory for linenoise.c and linenoise.h}
        editline=0
          => {Enable BSD editline support}
      }
    }

    # Options for ICU: International Components for Unicode
    icu {
      {*} {
        with-icu-ldflags:LDFLAGS
          => {Enable SQLITE_ENABLE_ICU and add the given linker flags for the
              ICU libraries. e.g. on Ubuntu systems, try '-licui18n -licuuc -licudata'.}
        with-icu-cflags:CFLAGS
          => {Apply extra CFLAGS/CPPFLAGS necessary for building with ICU.
              e.g. -I/usr/local/include}
        with-icu-config:=auto
          => {Enable SQLITE_ENABLE_ICU. Value must be one of: auto, pkg-config,
              /path/to/icu-config}
        icu-collations=0
          => {Enable SQLITE_ENABLE_ICU_COLLATIONS. Requires --with-icu-ldflags=...
              or --with-icu-config}
      }
    }

    # Options for exotic/alternative build modes
    alternative-builds {
      {canonical autoconf} {
        with-wasi-sdk:=/opt/wasi-sdk
          => {Top-most dir of the wasi-sdk for a WASI build}
      }

      {*} {
        # Note that --static-cli-shell has a completely different
        # meaning from --static-shell in the autoconf build!
        # --[disable-]static-shell is a legacy flag which we can't
        # remove without breaking downstream builds.
        static-cli-shell=0
          => {Statically-link the sqlite3 CLI shell.
              This only works if the requisite libraries are all available in
              static form.}
      }

      {canonical} {
        static-shells=0
          => {Shorthand for --static-cli-shell --static-tclsqlite3}

        with-emsdk:=auto
          => {Top-most dir of the Emscripten SDK installation.
              Needed only by ext/wasm. Default=EMSDK env var.}

        amalgamation-extra-src:FILES
          => {Space-separated list of soure files to append as-is to the resulting
              sqlite3.c amalgamation file. May be provided multiple times.}
      }
    }

    # Options primarily for downstream packagers/package maintainers
    packaging {
      {autoconf} {
        # --disable-static-shell: https://sqlite.org/forum/forumpost/cc219ee704
        # Note that this has a different meaning from --static-cli-shell in the
        # canonical build!
        static-shell=1
          => {Link the sqlite3 shell app against the DLL instead of embedding sqlite3.c}
      }
      {canonical autoconf} {
        # A potential TODO without a current use case:
        #rpath=1 => {Disable use of the rpath linker flag}
        # soname: https://sqlite.org/src/forumpost/5a3b44f510df8ded
        soname:=legacy
          => {SONAME for libsqlite3.so. "none", or not using this flag, sets no
              soname. "legacy" sets it to its historical value of
              libsqlite3.so.0.  A value matching the glob "libsqlite3.*" sets
              it to that literal value. Any other value is assumed to be a
              suffix which gets applied to "libsqlite3.so.",
              e.g. --soname=9.10 equates to "libsqlite3.so.9.10".}
        # dll-basename: https://sqlite.org/forum/forumpost/828fdfe904
        dll-basename:=auto
          => {Specifies the base name of the resulting DLL file.
              If not provided, "libsqlite3" is usually assumed but on some platforms
              a platform-dependent default is used. On some platforms this flag
              gets automatically enabled if it is not provided. Use "default" to
              explicitly disable platform-dependent activation on such systems.}
        # out-implib: https://sqlite.org/forum/forumpost/0c7fc097b2
        out-implib:=auto
          => {Enable use of --out-implib linker flag to generate an
              "import library" for the DLL. The output's base name is
              specified by this flag's value, with "auto" meaning to figure
              out a name automatically. On some platforms this flag gets
              automatically enabled if it is not provided. Use "none" to
              explicitly disable this feature on such platforms.}
      }
    }

    # Options mostly for sqlite's own development
    developer {
      {*} {
        # Note that using the --debug/--enable-debug flag here
        # requires patching autosetup/autosetup to rename its builtin
        # --debug to --autosetup-debug. See details in
        # autosetup/README.md#patching.
        with-debug=0
        debug=0
          => {Enable debug build flags. This option will impact performance by
              as much as 4x, as it includes large numbers of assert()s in
              performance-critical loops.  Never use --debug for production
              builds.}
        scanstatus
          => {Enable the SQLITE_ENABLE_STMT_SCANSTATUS feature flag}
      }
      {canonical} {
        dev
          => {Enable dev-mode build: automatically enables certain other flags}
        test-status
          => {Enable status of tests}
        gcov=0
          => {Enable coverage testing using gcov}
        linemacros
          => {Enable #line macros in the amalgamation}
        dynlink-tools
          => {Dynamically link libsqlite3 to certain tools which normally statically embed it}
        asan-fsanitize:=auto
          => {Comma- or space-separated list of -fsanitize flags for use with the
              fuzzcheck-asan tool. Only those which the compiler claims to support
              will actually be used. May be provided multiple times.}
      }
      {*} {
        dump-defines=0
          => {Dump autosetup defines to $::sqliteConfig(dump-defines-txt)
              (for build debugging)}
      }
    }
  }; # $allFlags

  set allFlags [proj-strip-hash-comments $allFlags]
  # ^^^ lappend of [sqlite-custom-flags] introduces weirdness if
  # we delay [proj-strip-hash-comments] until after that.


  ########################################################################
  # sqlite-custom.tcl is intended only for vendor-branch-specific
  # customization.  See autosetup/README.md#branch-customization for
  # details.
  if {[file exists $::autosetup(libdir)/sqlite-custom.tcl]} {
    uplevel 1 {source $::autosetup(libdir)/sqlite-custom.tcl}
  }

  if {[llength [info proc sqlite-custom-flags]] > 0} {
    # sqlite-custom-flags is assumed to be imported via
    # autosetup/sqlite-custom.tcl.
    set scf [sqlite-custom-flags]
    if {"" ne $scf} {
      lappend allFlags sqlite-custom-flags $scf
    }
  }

  # Filter allFlags to create the set of [options] legal for this build
  foreach {group XY} [subst -nobackslashes -nocommands $allFlags] {
    foreach {X Y} $XY {
      if { $buildMode in $X || "*" in $X } {
        options-add $Y
      }
    }
  }
  #lappend opts "soname:=duplicateEntry => {x}"; #just testing
  if {[catch {options {}} msg xopts]} {
    # Workaround for <https://github.com/msteveb/autosetup/issues/73>
    # where [options] behaves oddly on _some_ TCL builds when it's
    # called from deeper than the global scope.
    dict incr xopts -level
    return {*}$xopts $msg
  }
  sqlite-configure-phase1 $buildMode
  uplevel 1 $configScript
  sqlite-configure-finalize
}; # sqlite-configure

########################################################################
# Runs "phase 1" of the configure process: after initial --flags
# handling but before the build-specific parts are run. $buildMode
# must be the mode which was passed to [sqlite-configure].
proc sqlite-configure-phase1 {buildMode} {
  define PACKAGE_NAME sqlite
  define PACKAGE_URL {https://sqlite.org}
  define PACKAGE_BUGREPORT [get-define PACKAGE_URL]/forum
  define PACKAGE_STRING "[get-define PACKAGE_NAME] [get-define PACKAGE_VERSION]"
  proj-xfer-options-aliases {
    # Carry values from hidden --flag aliases over to their canonical
    # flag forms. This list must include only options which are common
    # to all build modes supported by [sqlite-configure].
    with-readline-inc => with-readline-cflags
    with-readline-lib => with-readline-ldflags
    with-debug => debug
  }
  set ::sqliteConfig(msg-debug-enabled) [proj-val-truthy [get-env msg-debug 0]]
  proc-debug "msg-debug is enabled"
  proj-setup-autoreconfig SQLITE_AUTORECONFIG
  proj-file-extensions
  if {".exe" eq [get-define TARGET_EXEEXT]} {
    define SQLITE_OS_UNIX 0
    define SQLITE_OS_WIN 1
  } else {
    define SQLITE_OS_UNIX 1
    define SQLITE_OS_WIN 0
  }
  sqlite-setup-default-cflags
  define HAVE_LFS 0
  if {[opt-bool largefile]} {
    #
    # Insofar as we can determine HAVE_LFS has no effect on the
    # library.  Perhaps it did back in the early 2000's. The
    # --enable/disable-largefile flag is retained because it's
    # harmless, but it doesn't do anything useful. It does have
    # visible side-effects, though: the generated sqlite_cfg.h may (or
    # may not) define HAVE_LFS.
    cc-check-lfs
  }
  set srcdir $::autosetup(srcdir)
  proj-dot-ins-append $srcdir/Makefile.in
  if {[file exists $srcdir/sqlite3.pc.in]} {
    proj-dot-ins-append $srcdir/sqlite3.pc.in
  }
}; # sqlite-configure-phase1

########################################################################
# Performs late-stage config steps common to all supported
# $::sqliteConfig(build-mode) values.
proc sqlite-configure-finalize {} {
  sqlite-handle-rpath
  sqlite-handle-soname
  sqlite-handle-threadsafe
  sqlite-handle-tempstore
  sqlite-handle-load-extension
  sqlite-handle-math
  sqlite-handle-icu
  if {[proj-opt-exists readline]} {
    sqlite-handle-line-editing
  }
  if {[proj-opt-exists shared]} {
    proj-define-for-opt shared ENABLE_LIB_SHARED "Build shared library?"
  }
  if {[proj-opt-exists static]} {
    if {![proj-define-for-opt static ENABLE_LIB_STATIC "Build static library?"]} {
      # This notice really only applies to the canonical build...
      proj-indented-notice {
        NOTICE: static lib build may be implicitly re-activated by
        other components, e.g. some test apps.
      }
    }
  }
  sqlite-handle-env-quirks
  sqlite-handle-common-feature-flags
  sqlite-finalize-feature-flags
  sqlite-process-dot-in-files; # do not [define] anything after this
  sqlite-dump-defines
}

########################################################################
# Internal config-time debugging output routine. It generates no
# output unless msg-debug=1 is passed to the configure script.
proc msg-debug {msg} {
  if {$::sqliteConfig(msg-debug-enabled)} {
    puts stderr [proj-bold "** DEBUG: $msg"]
  }
}
########################################################################
# A [msg-debug] proxy which prepends the name of the current proc to
# the debug message. It is not legal to call this from the global
# scope.
proc proc-debug {msg} {
  msg-debug "\[[proj-scope 1]\]: $msg"
}

define OPT_FEATURE_FLAGS {} ; # -DSQLITE_OMIT/ENABLE flags.
define OPT_SHELL {}         ; # Feature-related CFLAGS for the sqlite3 CLI app
########################################################################
# Adds $args, if not empty, to OPT_FEATURE_FLAGS.  If the first arg is
# -shell then it strips that arg and passes the remaining args the
# sqlite-add-shell-opt in addition to adding them to
# OPT_FEATURE_FLAGS. This is intended only for holding
# -DSQLITE_ENABLE/OMIT/... flags, but that is not enforced here.
proc sqlite-add-feature-flag {args} {
  set shell ""
  if {"-shell" eq [lindex $args 0]} {
    set args [lassign $args shell]
  }
  if {"" ne $args} {
    if {"" ne $shell} {
      sqlite-add-shell-opt {*}$args
    }
    define-append OPT_FEATURE_FLAGS {*}$args
  }
}

########################################################################
# Appends $args, if not empty, to OPT_SHELL.
proc sqlite-add-shell-opt {args} {
  if {"" ne $args} {
    define-append OPT_SHELL {*}$args
  }
}

########################################################################
# Check for log(3) in libm and die with an error if it is not
# found. $featureName should be the feature name which requires that
# function (it's used only in error messages). defines LDFLAGS_MATH to
# the required linker flags (which may be empty even if the math APIs
# are found, depending on the OS).
proc sqlite-affirm-have-math {featureName} {
  if {"" eq [get-define LDFLAGS_MATH ""]} {
    if {![msg-quiet proj-check-function-in-lib log m]} {
      user-error "Missing math APIs for $featureName"
    }
    set lfl [get-define lib_log ""]
    undefine lib_log
    if {"" ne $lfl} {
      user-notice "Forcing requirement of $lfl for $featureName"
    }
    define LDFLAGS_MATH $lfl
  }
}

########################################################################
# Run checks for required binaries, like ld and ar. In the canonical
# build this must come before [sqlite-handle-wasi-sdk].
proc sqlite-check-common-bins {} {
  cc-check-tools ld ar ; # must come before [sqlite-handle-wasi-sdk]
  if {"" eq [proj-bin-define install]} {
    proj-warn "Cannot find install binary, so 'make install' will not work."
    define BIN_INSTALL false
  }
}

########################################################################
# Run checks for system-level includes and libs which are common to
# both the canonical build and the "autoconf" bundle.
#
# For the canonical build this must come after
# [sqlite-handle-wasi-sdk], as that function may change the
# environment in ways which affect this.
proc sqlite-check-common-system-deps {} {
  # Check for needed/wanted data types
  cc-with {-includes stdint.h} \
    {cc-check-types int8_t int16_t int32_t int64_t intptr_t \
       uint8_t uint16_t uint32_t uint64_t uintptr_t}

  # Check for needed/wanted functions
  cc-check-functions gmtime_r isnan localtime_r localtime_s \
    malloc_usable_size strchrnul usleep utime pread pread64 pwrite pwrite64

  apply {{} {
    set ldrt ""
    # Collapse funcs from librt into LDFLAGS_RT.
    # Some systems (ex: SunOS) require -lrt in order to use nanosleep
    foreach func {fdatasync nanosleep} {
      if {[proj-check-function-in-lib $func rt]} {
        set ldrt [get-define lib_${func} ""]
        undefine lib_${func}
        if {"" ne $ldrt} {
          break
        }
      }
    }
    define LDFLAGS_RT $ldrt
  }}

  # Check for needed/wanted headers
  cc-check-includes \
    sys/types.h sys/stat.h dlfcn.h unistd.h \
    stdlib.h malloc.h memory.h \
    string.h strings.h \
    inttypes.h

  if {[cc-check-includes zlib.h] && [proj-check-function-in-lib deflate z]} {
    # TODO? port over the more sophisticated zlib search from the fossil auto.def
    define HAVE_ZLIB 1
    define LDFLAGS_ZLIB -lz
    sqlite-add-shell-opt -DSQLITE_HAVE_ZLIB=1
  } else {
    define HAVE_ZLIB 0
    define LDFLAGS_ZLIB ""
  }
}

########################################################################
# Move -DSQLITE_OMIT... and -DSQLITE_ENABLE... flags from CFLAGS and
# CPPFLAGS to OPT_FEATURE_FLAGS and remove them from BUILD_CFLAGS.
proc sqlite-munge-cflags {} {
  # Move CFLAGS and CPPFLAGS entries matching -DSQLITE_OMIT* and
  # -DSQLITE_ENABLE* to OPT_FEATURE_FLAGS. This behavior is derived
  # from the legacy build and was missing the 3.48.0 release (the
  # initial Autosetup port).
  # https://sqlite.org/forum/forumpost/9801e54665afd728
  #
  # Handling of CPPFLAGS, as well as removing ENABLE/OMIT from
  # CFLAGS/CPPFLAGS, was missing in the 3.49.0 release as well.
  #
  # If any configure flags for features are in conflict with
  # CFLAGS/CPPFLAGS-specified feature flags, all bets are off.  There
  # are no guarantees about which one will take precedence.
  foreach flagDef {CFLAGS CPPFLAGS} {
    set tmp ""
    foreach cf [get-define $flagDef ""] {
      switch -glob -- $cf {
        -DSQLITE_OMIT* -
        -DSQLITE_ENABLE* {
          sqlite-add-feature-flag $cf
        }
        default {
          lappend tmp $cf
        }
      }
    }
    define $flagDef $tmp
  }

  # Strip all SQLITE_ENABLE/OMIT flags from BUILD_CFLAGS,
  # for compatibility with the legacy build.
  set tmp ""
  foreach cf [get-define BUILD_CFLAGS ""] {
    switch -glob -- $cf {
      -DSQLITE_OMIT* -
      -DSQLITE_ENABLE* {}
      default {
        lappend tmp $cf
      }
    }
  }
  define BUILD_CFLAGS $tmp
}

#########################################################################
# Set up the default CFLAGS and BUILD_CFLAGS values.
proc sqlite-setup-default-cflags {} {
  ########################################################################
  # We differentiate between two C compilers: the one used for binaries
  # which are to run on the build system (in autosetup it's called
  # CC_FOR_BUILD and in Makefile.in it's $(B.cc)) and the one used for
  # compiling binaries for the target system (CC a.k.a. $(T.cc)).
  # Normally they're the same, but they will differ when
  # cross-compiling.
  #
  # When cross-compiling we default to not using the -g flag, based on a
  # /chat discussion prompted by
  # https://sqlite.org/forum/forumpost/9a67df63eda9925c
  set defaultCFlags {-O2}
  if {!$::sqliteConfig(is-cross-compiling)} {
    lappend defaultCFlags -g
  }
  define CFLAGS [proj-get-env CFLAGS $defaultCFlags]
  # BUILD_CFLAGS is the CFLAGS for CC_FOR_BUILD.
  define BUILD_CFLAGS [proj-get-env BUILD_CFLAGS {-g}]
  sqlite-munge-cflags
}

########################################################################
# Handle various SQLITE_ENABLE/OMIT_... feature flags.
proc sqlite-handle-common-feature-flags {} {
  msg-result "Feature flags..."
  if {![opt-bool all]} {
    # Special handling for --disable-all
    foreach flag $::sqliteConfig(all-flag-enables) {
      if {![proj-opt-was-provided $flag]} {
        proj-opt-set $flag 0
      }
    }
  }
  foreach {boolFlag featureFlag ifSetEvalThis} [proj-strip-hash-comments {
    all         {} {
      # The 'all' option must be first in this list.  This impl makes
      # an effort to only apply flags which the user did not already
      # apply, so that combinations like (--all --disable-geopoly)
      # will indeed disable geopoly. There are corner cases where
      # flags which depend on each other will behave in non-intuitive
      # ways:
      #
      # --all --disable-rtree
      #
      # Will NOT disable geopoly, though geopoly depends on rtree.
      # The --geopoly flag, though, will automatically re-enable
      # --rtree, so --disable-rtree won't actually disable anything in
      # that case.
      foreach k $::sqliteConfig(all-flag-enables) {
        if {![proj-opt-was-provided $k]} {
          proj-opt-set $k 1
        }
      }
    }
    fts3         -DSQLITE_ENABLE_FTS3    {sqlite-affirm-have-math fts3}
    fts4         -DSQLITE_ENABLE_FTS4    {sqlite-affirm-have-math fts4}
    fts5         -DSQLITE_ENABLE_FTS5    {sqlite-affirm-have-math fts5}
    geopoly      -DSQLITE_ENABLE_GEOPOLY {proj-opt-set rtree}
    rtree        -DSQLITE_ENABLE_RTREE   {}
    session      {-DSQLITE_ENABLE_SESSION -DSQLITE_ENABLE_PREUPDATE_HOOK} {}
    update-limit -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT {}
    memsys5      -DSQLITE_ENABLE_MEMSYS5 {}
    memsys3      {} {
      if {[opt-bool memsys5]} {
        proj-warn "not enabling memsys3 because memsys5 is enabled."
        expr 0
      } else {
        sqlite-add-feature-flag -DSQLITE_ENABLE_MEMSYS3
      }
    }
    scanstatus     -DSQLITE_ENABLE_STMT_SCANSTATUS {}
  }] {
    if {$boolFlag ni $::autosetup(options)} {
      # Skip flags which are in the canonical build but not
      # the autoconf bundle.
      continue
    }
    proj-if-opt-truthy $boolFlag {
      sqlite-add-feature-flag $featureFlag
      if {0 != [eval $ifSetEvalThis] && "all" ne $boolFlag} {
        msg-result "  + $boolFlag"
      }
    } {
      if {"all" ne $boolFlag} {
        msg-result "  - $boolFlag"
      }
    }
  }
  ########################################################################
  # Invert the above loop's logic for some SQLITE_OMIT_...  cases. If
  # config option $boolFlag is false, [sqlite-add-feature-flag
  # $featureFlag], where $featureFlag is intended to be
  # -DSQLITE_OMIT_...
  foreach {boolFlag featureFlag} {
    json        -DSQLITE_OMIT_JSON
  } {
    if {[proj-opt-truthy $boolFlag]} {
      msg-result "  + $boolFlag"
    } else {
      sqlite-add-feature-flag $featureFlag
      msg-result "  - $boolFlag"
    }
  }
}

#########################################################################
# Remove duplicates from the final feature flag sets and show them to
# the user.
proc sqlite-finalize-feature-flags {} {
  set oFF [get-define OPT_FEATURE_FLAGS]
  if {"" ne $oFF} {
    define OPT_FEATURE_FLAGS [lsort -unique $oFF]
    msg-result "Library feature flags: [get-define OPT_FEATURE_FLAGS]"
  }
  set oFF [get-define OPT_SHELL]
  if {"" ne $oFF} {
    define OPT_SHELL [lsort -unique $oFF]
    msg-result "Shell options: [get-define OPT_SHELL]"
  }
  if {"" ne [set extraSrc [get-define AMALGAMATION_EXTRA_SRC ""]]} {
    proj-assert {"canonical" eq $::sqliteConfig(build-mode)}
    msg-result "Appending source files to amalgamation: $extraSrc"
  }
  if {[lsearch [get-define TARGET_DEBUG ""] -DSQLITE_DEBUG=1] > -1} {
    msg-result "Note: this is a debug build, so performance will suffer."
  }
}

########################################################################
# Checks for the --debug flag and [define]s TARGET_DEBUG based on
# that.  TARGET_DEBUG is unused in the autoconf build but that is
# arguably a bug.
proc sqlite-handle-debug {} {
  msg-checking "SQLITE_DEBUG build? "
  proj-if-opt-truthy debug {
    define TARGET_DEBUG {-g -DSQLITE_DEBUG=1 -O0 -Wall}
    sqlite-add-feature-flag -DSQLITE_ENABLE_SELECTTRACE -DSQLITE_ENABLE_WHERETRACE
    proj-opt-set memsys5
    msg-result yes
  } {
    define TARGET_DEBUG {-DNDEBUG}
    msg-result no
  }
}

########################################################################
# "soname" for libsqlite3.so. See discussion at:
# https://sqlite.org/src/forumpost/5a3b44f510df8ded
proc sqlite-handle-soname {} {
  define LDFLAGS_LIBSQLITE3_SONAME ""
  if {[proj-opt-was-provided soname]} {
    set soname [join [opt-val soname] ""]
  } else {
    # Enabling soname breaks linking for the --dynlink-tools feature,
    # and this project has no direct use for soname, so default to
    # none. Package maintainers, on the other hand, like to have an
    # soname.
    set soname none
  }
  switch -exact -- $soname {
    none - "" { return 0 }
    legacy    { set soname libsqlite3.so.0 }
    default {
      if {[string match libsqlite3.* $soname]} {
        # use it as-is
      } else {
        # Assume it's a suffix
        set soname "libsqlite3.so.${soname}"
      }
    }
  }
  proc-debug "soname=$soname"
  if {[proj-check-soname $soname]} {
    define LDFLAGS_LIBSQLITE3_SONAME [get-define LDFLAGS_SONAME_PREFIX]$soname
    msg-result "Setting SONAME using: [get-define LDFLAGS_LIBSQLITE3_SONAME]"
  } elseif {[proj-opt-was-provided soname]} {
    # --soname was explicitly requested but not available, so fail fatally
    proj-fatal "This environment does not support SONAME."
  } else {
    # --soname was not explicitly requested but not available, so just warn
    msg-result "This environment does not support SONAME."
  }
}

########################################################################
# If --enable-threadsafe is set, this adds -DSQLITE_THREADSAFE=1 to
# OPT_FEATURE_FLAGS and sets LDFLAGS_PTHREAD to the linker flags
# needed for linking pthread (possibly an empty string). If
# --enable-threadsafe is not set, adds -DSQLITE_THREADSAFE=0 to
# OPT_FEATURE_FLAGS and sets LDFLAGS_PTHREAD to an empty string.
proc sqlite-handle-threadsafe {} {
  msg-checking "Support threadsafe operation? "
  define LDFLAGS_PTHREAD ""
  set enable 0
  proj-if-opt-truthy threadsafe {
    msg-result "Checking for libs..."
    if {[proj-check-function-in-lib pthread_create pthread]
        && [proj-check-function-in-lib pthread_mutexattr_init pthread]} {
      set enable 1
      define LDFLAGS_PTHREAD [get-define lib_pthread_create]
      undefine lib_pthread_create
      undefine lib_pthread_mutexattr_init
    } elseif {[proj-opt-was-provided threadsafe]} {
      user-error "Missing required pthread libraries. Use --disable-threadsafe to disable this check."
    } else {
      msg-result "pthread support not detected"
    }
    # Recall that LDFLAGS_PTHREAD might be empty even if pthreads if
    # found because it's in -lc on some platforms.
  } {
    msg-result "Disabled using --disable-threadsafe"
  }
  sqlite-add-feature-flag -DSQLITE_THREADSAFE=${enable}
  return $enable
}

########################################################################
# Handles the --with-tempstore flag.
#
# The test fixture likes to set SQLITE_TEMP_STORE on its own, so do
# not set that feature flag unless it was explicitly provided to the
# configure script.
proc sqlite-handle-tempstore {} {
  if {[proj-opt-was-provided with-tempstore]} {
    set ts [opt-val with-tempstore no]
    set tsn 1
    msg-checking "Use an in-RAM database for temporary tables? "
    switch -exact -- $ts {
      never  { set tsn 0 }
      no     { set tsn 1 }
      yes    { set tsn 2 }
      always { set tsn 3 }
      default {
        user-error "Invalid --with-tempstore value '$ts'. Use one of: never, no, yes, always"
      }
    }
    msg-result $ts
    sqlite-add-feature-flag -DSQLITE_TEMP_STORE=$tsn
  }
}

########################################################################
# Check for the Emscripten SDK for building the web-based wasm
# components.  The core lib and tools do not require this but ext/wasm
# does. Most of the work is done via [proj-check-emsdk], then this
# function adds the following defines:
#
# - EMCC_WRAPPER = "" or top-srcdir/tool/emcc.sh
# - BIN_WASM_OPT = "" or path to wasm-opt
# - BIN_WASM_STRIP = "" or path to wasm-strip
#
# Noting that:
#
# 1) Not finding the SDK is not fatal at this level, nor is failure to
#    find one of the related binaries.
#
# 2) wasm-strip is part of the wabt package:
#
#   https://github.com/WebAssembly/wabt
#
# and this project requires it for production-mode builds but not dev
# builds.
#
proc sqlite-handle-emsdk {} {
  define EMCC_WRAPPER ""
  define BIN_WASM_STRIP ""
  define BIN_WASM_OPT ""
  set srcdir $::autosetup(srcdir)
  if {$srcdir ne $::autosetup(builddir)} {
    # The EMSDK pieces require writing to the original source tree
    # even when doing an out-of-tree build. The ext/wasm pieces do not
    # support an out-of-tree build so we treat that case as if EMSDK
    # were not found.
    msg-result "Out-of tree build: not checking for EMSDK."
    return
  }
  set emccSh $srcdir/tool/emcc.sh
  set extWasmConfig $srcdir/ext/wasm/config.make
  if {![get-define HAVE_WASI_SDK] && [proj-check-emsdk]} {
    define EMCC_WRAPPER $emccSh
    set emsdkHome [get-define EMSDK_HOME ""]
    proj-assert {"" ne $emsdkHome}
    #define EMCC_WRAPPER ""; # just for testing
    proj-bin-define wasm-strip
    proj-bin-define bash; # ext/wasm/GNUmakefile requires bash
    if {[file-isexec $emsdkHome/upstream/bin/wasm-opt]} {
      define BIN_WASM_OPT $emsdkHome/upstream/bin/wasm-opt
    } else {
      # Maybe there's a copy in the path?
      proj-bin-define wasm-opt BIN_WASM_OPT
    }
    proj-dot-ins-append $emccSh.in $emccSh {
      catch {exec chmod u+x $dotInsOut}
    }
    proj-dot-ins-append $extWasmConfig.in $extWasmConfig
  } else {
    define EMCC_WRAPPER ""
    file delete -force -- $emccSh $extWasmConfig
  }
}

########################################################################
# Internal helper for [sqlite-check-line-editing]. Returns a list of
# potential locations under which readline.h might be found.
#
# On some environments this function may perform extra work to help
# sqlite-check-line-editing figure out how to find libreadline and
# friends. It will communicate those results via means other than the
# result value, e.g. by modifying configure --flags.
proc sqlite-get-readline-dir-list {} {
  # Historical note: the dirs list, except for the inclusion of
  # $prefix and some platform-specific dirs, originates from the
  # legacy configure script
  set dirs [list [get-define prefix]]
  switch -glob -- [get-define host] {
    *-linux-android {
      # Possibly termux
      lappend dirs /data/data/com.termux/files/usr
    }
    *-mingw32 {
      lappend dirs /mingw32 /mingw
    }
    *-mingw64 {
      lappend dirs /mingw64 /mingw
    }
    *-haiku {
      lappend dirs /boot/system/develop/headers
      if {[opt-val with-readline-ldflags] in {auto ""}} {
        # If the user did not supply their own --with-readline-ldflags
        # value, hijack that flag to inject options which are known to
        # work on a default Haiku installation.
        if {"" ne [glob -nocomplain /boot/system/lib/libreadline*]} {
          proj-opt-set with-readline-ldflags {-L/boot/system/lib -lreadline}
        }
      }
    }
  }
  lappend dirs /usr /usr/local /usr/local/readline /usr/contrib
  set rv {}
  foreach d $dirs {
    if {[file isdir $d]} {lappend rv $d}
  }
  #proc-debug "dirs=$rv"
  return $rv
}

########################################################################
# sqlite-check-line-editing jumps through proverbial hoops to try to
# find a working line-editing library, setting:
#
#   - HAVE_READLINE to 0 or 1
#   - HAVE_LINENOISE to 0, 1, or 2
#   - HAVE_EDITLINE to 0 or 1
#
# Only one of ^^^ those will be set to non-0.
#
#   - LDFLAGS_READLINE = linker flags or empty string
#
#   - CFLAGS_READLINE = compilation flags for clients or empty string.
#
# Note that LDFLAGS_READLINE and CFLAGS_READLINE may refer to
# linenoise or editline, not necessarily libreadline.  In some cases
# it will set HAVE_READLINE=1 when it's really using editline, for
# reasons described in this function's comments.
#
# Returns a string describing which line-editing approach to use, or
# "none" if no option is available.
#
# Order of checks:
#
#  1) --with-linenoise trumps all others and skips all of the
#     complexities involved with the remaining options.
#
#  2) --editline trumps --readline
#
#  3) --disable-readline trumps --readline
#
#  4) Default to automatic search for optional readline
#
#  5) Try to find readline or editline. If it's not found AND the
#     corresponding --FEATURE flag was explicitly given, fail fatally,
#     else fail silently.
proc sqlite-check-line-editing {} {
  msg-result "Checking for line-editing capability..."
  define HAVE_READLINE 0
  define HAVE_LINENOISE 0
  define HAVE_EDITLINE 0
  define LDFLAGS_READLINE ""
  define CFLAGS_READLINE ""
  set failIfNotFound 0 ; # Gets set to 1 for explicit --FEATURE requests
                         # so that we know whether to fail fatally or not
                         # if the library is not found.
  set libsForReadline {readline edit} ; # -l<LIB> names to check for readline().
                                        # The libedit check changes this.
  set editLibName "readline" ; # "readline" or "editline"
  set editLibDef "HAVE_READLINE" ; # "HAVE_READLINE" or "HAVE_EDITLINE"
  set dirLn [opt-val with-linenoise]
  if {"" ne $dirLn} {
    # Use linenoise from a copy of its sources (not a library)...
    if {![file isdir $dirLn]} {
      proj-fatal "--with-linenoise value is not a directory"
    }
    set lnH $dirLn/linenoise.h
    if {![file exists $lnH] } {
      proj-fatal "Cannot find linenoise.h in $dirLn"
    }
    set lnC ""
    set lnCOpts {linenoise-ship.c linenoise.c}
    foreach f $lnCOpts {
      if {[file exists $dirLn/$f]} {
        set lnC $dirLn/$f
        break;
      }
    }
    if {"" eq $lnC} {
      proj-fatal "Cannot find any of $lnCOpts in $dirLn"
    }
    set flavor ""
    set lnVal [proj-which-linenoise $lnH]
    switch -- $lnVal {
      1 { set flavor "antirez" }
      2 { set flavor "msteveb" }
      default {
        proj-fatal "Cannot determine the flavor of linenoise from $lnH"
      }
    }
    define CFLAGS_READLINE "-I$dirLn $lnC"
    define HAVE_LINENOISE $lnVal
    sqlite-add-shell-opt -DHAVE_LINENOISE=$lnVal
    if {$::sqliteConfig(use-jim-for-codegen) && 2 == $lnVal} {
      define-append CFLAGS_JIMSH -DUSE_LINENOISE [get-define CFLAGS_READLINE]
      user-notice "Adding linenoise support to jimsh."
    }
    return "linenoise ($flavor)"
  } elseif {[opt-bool editline]} {
    # libedit mimics libreadline and on some systems does not have its
    # own header installed (instead, that of libreadline is used).
    #
    # shell.c historically expects HAVE_EDITLINE to be set for
    # libedit, but it then expects to see <editline/readline.h>, which
    # some system's don't actually have despite having libedit.  If we
    # end up finding <editline/readline.h> below, we will use
    # -DHAVE_EDITLINE=1, else we will use -DHAVE_READLINE=1. In either
    # case, we will link against libedit.
    set failIfNotFound 1
    set libsForReadline {edit}
    set editLibName editline
  } elseif {![opt-bool readline]} {
    msg-result "Readline support explicitly disabled with --disable-readline"
    return "none"
  } elseif {[proj-opt-was-provided readline]} {
    # If an explicit --[enable-]readline was used, fail if it's not
    # found, else treat the feature as optional.
    set failIfNotFound 1
  }

  # Transform with-readline-header=X to with-readline-cflags=-I...
  set v [opt-val with-readline-header]
  proj-opt-set with-readline-header ""
  if {"" ne $v} {
    if {"auto" eq $v} {
      proj-opt-set with-readline-cflags auto
    } else {
      set v [file dirname $v]
      if {[string match */readline $v]} {
        # Special case: if the path includes .../readline/readline.h,
        # set the -I to one dir up from that because our sources
        # #include <readline/readline.h> or <editline/readline.h>.
        set v [file dirname $v]
      }
      proj-opt-set with-readline-cflags "-I$v"
    }
  }

  # Look for readline.h
  set rlInc [opt-val with-readline-cflags auto]
  if {"auto" eq $rlInc} {
    set rlInc ""
    if {$::sqliteConfig(is-cross-compiling)} {
      # ^^^ this check is derived from the legacy configure script.
      proj-warn "Skipping check for readline.h because we're cross-compiling."
    } else {
      set dirs [sqlite-get-readline-dir-list]
      set subdirs [list \
                     include/$editLibName \
                     readline]
      if {"editline" eq $editLibName} {
        lappend subdirs include/readline
        # ^^^ editline, on some systems, does not have its own header,
        # and uses libreadline's header.
      }
      lappend subdirs include
      set rlInc [proj-search-for-header-dir readline.h \
                   -dirs $dirs -subdirs $subdirs]
      #proc-debug "rlInc=$rlInc"
      if {"" ne $rlInc} {
        if {[string match */readline $rlInc]} {
          set rlInc [file dirname $rlInc]; # CLI shell: #include <readline/readline.h>
        } elseif {[string match */editline $rlInc]} {
          set editLibDef HAVE_EDITLINE
          set rlInc [file dirname $rlInc]; # CLI shell: #include <editline/readline.h>
        }
        set rlInc "-I${rlInc}"
      }
    }
  } elseif {"" ne $rlInc && ![string match *-I* $rlInc]} {
    proj-fatal "Argument to --with-readline-cflags is intended to be CFLAGS and contain -I..."
  }

  # If readline.h was found/specified, look for lib(readline|edit)...
  #
  # This is not quite straightforward because both libreadline and
  # libedit typically require some other library which (according to
  # legacy autotools-generated tests) provides tgetent(3). On some
  # systems that's built into libreadline/edit, on some (most?) its in
  # lib[n]curses, and on some it's in libtermcap.
  set rlLib ""
  if {"" ne $rlInc} {
    set rlLib [opt-val with-readline-ldflags]
    #proc-debug "rlLib=$rlLib"
    if {$rlLib in {auto ""}} {
      set rlLib ""
      set libTerm ""
      if {[proj-check-function-in-lib tgetent "$editLibName ncurses curses termcap"]} {
        # ^^^ that libs list comes from the legacy configure script ^^^
        set libTerm [get-define lib_tgetent]
        undefine lib_tgetent
      }
      if {$editLibName eq $libTerm} {
        set rlLib $libTerm
      } elseif {[proj-check-function-in-lib readline $libsForReadline $libTerm]} {
        set rlLib [get-define lib_readline]
        lappend rlLib $libTerm
        undefine lib_readline
      }
    }
  }

  # If we found a library, configure the build to use it...
  if {"" ne $rlLib} {
    if {"editline" eq $editLibName && "HAVE_READLINE" eq $editLibDef} {
      # Alert the user that, despite outward appearances, we won't be
      # linking to the GPL'd libreadline. Presumably that distinction is
      # significant for those using --editline.
      proj-indented-notice {
        NOTE: the local libedit uses <readline/readline.h> so we
        will compile with -DHAVE_READLINE=1 but will link with
        libedit.
      }
    }
    set rlLib [join $rlLib]
    set rlInc [join $rlInc]
    define LDFLAGS_READLINE $rlLib
    define CFLAGS_READLINE $rlInc
    proj-assert {$editLibDef in {HAVE_READLINE HAVE_EDITLINE}}
    proj-assert {$editLibName in {readline editline}}
    sqlite-add-shell-opt -D${editLibDef}=1
    msg-result "Using $editLibName flags: $rlInc $rlLib"
    # Check whether rl_completion_matches() has a signature we can use
    # and disable that sub-feature if it doesn't.
    if {![cctest \
            -cflags "$rlInc -D${editLibDef}" -libs $rlLib -nooutput 1 -source {
             #include <stdio.h>
             #ifdef HAVE_EDITLINE
             #include <editline/readline.h>
             #else
             #include <readline/readline.h>
             #endif
             static char * rcg(const char *z, int i){(void)z; (void)i; return 0;}
             int main(void) {
               char ** x = rl_completion_matches("one", rcg);
               (void)x;
               return 0;
             }
           }]} {
      proj-warn "readline-style completion disabled due to rl_completion_matches() signature mismatch"
      sqlite-add-shell-opt -DSQLITE_OMIT_READLINE_COMPLETION
    }
    return $editLibName
  }

  if {$failIfNotFound} {
    proj-fatal "Explicit --$editLibName failed to find a matching library."
  }
  return "none"
}; # sqlite-check-line-editing

########################################################################
# Runs sqlite-check-line-editing and adds a message around it. In the
# canonical build this must not be called before
# sqlite-determine-codegen-tcl for reasons now lost to history (and
# might not still be applicable).
proc sqlite-handle-line-editing {} {
  msg-result "Line-editing support for the sqlite3 shell: [sqlite-check-line-editing]"
}


########################################################################
# ICU - International Components for Unicode
#
# Handles these flags:
#
#  --with-icu-ldflags=LDFLAGS
#  --with-icu-cflags=CFLAGS
#  --with-icu-config[=auto | pkg-config | /path/to/icu-config]
#  --enable-icu-collations
#
# --with-icu-config values:
#
#   - auto: use the first one of (pkg-config, icu-config) found on the
#     system.
#   - pkg-config: use only pkg-config to determine flags
#   - /path/to/icu-config: use that to determine flags
#
# If --with-icu-config is used as neither pkg-config nor icu-config
# are found, fail fatally.
#
# If both --with-icu-ldflags and --with-icu-config are provided, they
# are cumulative.  If neither are provided, icu-collations is not
# honored and a warning is emitted if it is provided.
#
# Design note: though we could automatically enable ICU if the
# icu-config binary or (pkg-config icu-io) are found, we specifically
# do not. ICU is always an opt-in feature.
proc sqlite-handle-icu {} {
  define LDFLAGS_ICU [join [opt-val with-icu-ldflags ""]]
  define CFLAGS_ICU [join [opt-val with-icu-cflags ""]]
  if {[proj-opt-was-provided with-icu-config]} {
    msg-result "Checking for ICU support..."
    set icuConfigBin [opt-val with-icu-config]
    set tryIcuConfigBin 1; # set to 0 if we end up using pkg-config
    if {$icuConfigBin in {auto pkg-config}} {
      if {[pkg-config-init 0] && [pkg-config icu-io]} {
        # Maintenance reminder: historical docs say to use both of
        # (icu-io, icu-uc). icu-uc lacks a required lib and icu-io has
        # all of them on tested OSes.
        set tryIcuConfigBin 0
        define LDFLAGS_ICU [get-define PKG_ICU_IO_LDFLAGS]
        define-append LDFLAGS_ICU [get-define PKG_ICU_IO_LIBS]
        define CFLAGS_ICU [get-define PKG_ICU_IO_CFLAGS]
      } elseif {"pkg-config" eq $icuConfigBin} {
        proj-fatal "pkg-config cannot find package icu-io"
      } else {
        proj-assert {"auto" eq $icuConfigBin}
      }
    }
    if {$tryIcuConfigBin} {
      if {"auto" eq $icuConfigBin} {
        set icuConfigBin [proj-first-bin-of \
                            /usr/local/bin/icu-config \
                            /usr/bin/icu-config]
        if {"" eq $icuConfigBin} {
          proj-indented-notice -error {
            --with-icu-config=auto cannot find (pkg-config icu-io) or icu-config binary.
            On Ubuntu-like systems try:
            --with-icu-ldflags='-licui18n -licuuc -licudata'
          }
        }
      }
      if {[file-isexec $icuConfigBin]} {
        set x [exec $icuConfigBin --ldflags]
        if {"" eq $x} {
          proj-indented-notice -error \
            [subst {
              $icuConfigBin --ldflags returned no data.
              On Ubuntu-like systems try:
              --with-icu-ldflags='-licui18n -licuuc -licudata'
            }]
        }
        define-append LDFLAGS_ICU $x
        set x [exec $icuConfigBin --cppflags]
        define-append CFLAGS_ICU $x
      } else {
        proj-fatal "--with-icu-config=$icuConfigBin does not refer to an executable"
      }
    }
  }
  set ldflags [define LDFLAGS_ICU [string trim [get-define LDFLAGS_ICU]]]
  set cflags [define CFLAGS_ICU [string trim [get-define CFLAGS_ICU]]]
  if {"" ne $ldflags} {
    sqlite-add-feature-flag -shell -DSQLITE_ENABLE_ICU
    msg-result "Enabling ICU support with flags: $ldflags $cflags"
    if {[opt-bool icu-collations]} {
      msg-result "Enabling ICU collations."
      sqlite-add-feature-flag -shell -DSQLITE_ENABLE_ICU_COLLATIONS
      # Recall that shell.c builds with sqlite3.c except in the case
      # of --disable-static-shell, a combination we do not
      # specifically attempt to account for.
    }
  } elseif {[opt-bool icu-collations]} {
    proj-warn "ignoring --enable-icu-collations because neither --with-icu-ldflags nor --with-icu-config provided any linker flags"
  } else {
    msg-result "ICU support is disabled."
  }
}; # sqlite-handle-icu


########################################################################
# Handles the --enable-load-extension flag. Returns 1 if the support
# is enabled, else 0. If support for that feature is not found, a
# fatal error is triggered if --enable-load-extension is explicitly
# provided, else a loud warning is instead emitted. If
# --disable-load-extension is used, no check is performed.
#
# Makes the following environment changes:
#
# - defines LDFLAGS_DLOPEN to any linker flags needed for this
#   feature.  It may legally be empty on some systems where dlopen()
#   is in libc.
#
# - If the feature is not available, adds
#   -DSQLITE_OMIT_LOAD_EXTENSION=1 to the feature flags list.
proc sqlite-handle-load-extension {} {
  define LDFLAGS_DLOPEN ""
  set found 0
  proj-if-opt-truthy load-extension {
    set found [proj-check-function-in-lib dlopen dl]
    if {$found} {
      define LDFLAGS_DLOPEN [get-define lib_dlopen]
      undefine lib_dlopen
    } else {
      if {[proj-opt-was-provided load-extension]} {
        # Explicit --enable-load-extension: fail if not found
        proj-indented-notice -error {
          --enable-load-extension was provided but dlopen()
          not found. Use --disable-load-extension to bypass this
          check.
        }
      } else {
        # It was implicitly enabled: warn if not found
        proj-indented-notice {
          WARNING: dlopen() not found, so loadable module support will
          be disabled. Use --disable-load-extension to bypass this
          check.
        }
      }
    }
  }
  if {$found} {
    msg-result "Loadable extension support enabled."
  } else {
    msg-result "Disabling loadable extension support. Use --enable-load-extension to enable them."
    sqlite-add-feature-flag -DSQLITE_OMIT_LOAD_EXTENSION=1
  }
  return $found
}

########################################################################
# Handles the --enable-math flag.
proc sqlite-handle-math {} {
  proj-if-opt-truthy math {
    if {![proj-check-function-in-lib ceil m]} {
      user-error "Cannot find libm functions. Use --disable-math to bypass this."
    }
    define LDFLAGS_MATH [get-define lib_ceil]
    undefine lib_ceil
    sqlite-add-feature-flag -DSQLITE_ENABLE_MATH_FUNCTIONS
    msg-result "Enabling math SQL functions"
  } {
    define LDFLAGS_MATH ""
    msg-result "Disabling math SQL functions"
  }
}

########################################################################
# If this OS looks like a Mac, checks for the Mac-specific
# -current_version and -compatibility_version linker flags. Defines
# LDFLAGS_MAC_CVERSION to an empty string and returns 0 if they're not
# supported, else defines that to the linker flags and returns 1.
#
# We don't check this on non-Macs because this whole thing is a
# libtool compatibility kludge to account for a version stamp which
# libtool applied only on Mac platforms.
#
# Based on https://sqlite.org/forum/forumpost/9dfd5b8fd525a5d7.
proc sqlite-handle-mac-cversion {} {
  define LDFLAGS_MAC_CVERSION ""
  set rc 0
  if {[proj-looks-like-mac]} {
    cc-with {-link 1} {
      # These version numbers are historical libtool-defined values, not
      # library-defined ones
      if {[cc-check-flags "-Wl,-current_version,9.6.0"]
          && [cc-check-flags "-Wl,-compatibility_version,9.0.0"]} {
        define LDFLAGS_MAC_CVERSION "-Wl,-compatibility_version,9.0.0 -Wl,-current_version,9.6.0"
        set rc 1
      } elseif {[cc-check-flags "-compatibility_version 9.0.0"]
                && [cc-check-flags "-current_version 9.6.0"]} {
        define LDFLAGS_MAC_CVERSION "-compatibility_version 9.0.0 -current_version 9.6.0"
        set rc 1
      }
    }
  }
  return $rc
}

########################################################################
# If this is a Mac platform, check for support for
# -Wl,-install_name,...  and, if it's available, define
# LDFLAGS_MAC_INSTALL_NAME to a variant of that string which is
# intended to expand at make-time, else set LDFLAGS_MAC_INSTALL_NAME
# to an empty string.
#
# https://sqlite.org/forum/forumpost/5651662b8875ec0a
proc sqlite-handle-mac-install-name {} {
  define LDFLAGS_MAC_INSTALL_NAME ""; # {-Wl,-install_name,"$(install-dir.lib)/$(libsqlite3.DLL)"}
  set rc 0
  if {[proj-looks-like-mac]} {
    cc-with {-link 1} {
      if {[cc-check-flags "-Wl,-install_name,/usr/local/lib/libsqlite3.dylib"]} {
        define LDFLAGS_MAC_INSTALL_NAME {-Wl,-install_name,"$(install-dir.lib)/$(libsqlite3.DLL)"}
        set rc 1
      }
    }
  }
  return $rc
}

########################################################################
# Handles the --dll-basename configure flag. [define]'s
# SQLITE_DLL_BASENAME to the DLL's preferred base name (minus
# extension). If --dll-basename is not provided (or programmatically
# set - see [sqlite-handle-env-quirks]) then this is always
# "libsqlite3", otherwise it may use a different value based on the
# value of [get-define host].
proc sqlite-handle-dll-basename {} {
  if {[proj-opt-was-provided dll-basename]} {
    set dn [join [opt-val dll-basename] ""]
    if {$dn in {none default}} { set dn libsqlite3 }
  } else {
    set dn libsqlite3
  }
  if {$dn in {auto ""}} {
    switch -glob -- [get-define host] {
      *-*-cygwin  { set dn cygsqlite3-0 }
      *-*-ming*   { set dn libsqlite3-0 }
      *-*-msys    { set dn msys-sqlite3-0 }
      default     { set dn libsqlite3 }
    }
  }
  define SQLITE_DLL_BASENAME $dn
}

########################################################################
# [define]s LDFLAGS_OUT_IMPLIB to either an empty string or to a
# -Wl,... flag for the platform-specific --out-implib flag, which is
# used for building an "import library .dll.a" file on some platforms
# (e.g. msys2, mingw). SQLITE_OUT_IMPLIB is defined to the name of the
# import lib or an empty string. Returns 1 if supported, else 0.
#
# The name of the import library is [define]d in SQLITE_OUT_IMPLIB.
#
# If the configure flag --out-implib is not used (or programmatically
# set) then this simply sets the above-listed defines to empty strings
# (but see [sqlite-handle-env-quirks]).  If that flag is used but the
# capability is not available, a fatal error is triggered.
#
# This feature is specifically opt-in because it's supported on far
# more platforms than actually need it and enabling it causes creation
# of libsqlite3.so.a files which are unnecessary in most environments.
#
# Added in response to: https://sqlite.org/forum/forumpost/0c7fc097b2
#
# Platform notes:
#
# - cygwin sqlite packages historically install no .dll.a file.
#
# - msys2 and mingw sqlite packages historically install
#   /usr/lib/libsqlite3.dll.a despite the DLL being in
#   /usr/bin.
proc sqlite-handle-out-implib {} {
  define LDFLAGS_OUT_IMPLIB ""
  define SQLITE_OUT_IMPLIB ""
  set rc 0
  if {[proj-opt-was-provided out-implib]} {
    set olBaseName [join [opt-val out-implib] ""]
    if {$olBaseName in {auto ""}} {
      set olBaseName "libsqlite3" ;# [get-define SQLITE_DLL_BASENAME]
      # Based on discussions with mingw/msys users, the import lib
      # should always be called libsqlite3.dll.a even on platforms
      # which rename libsqlite3.dll to something else.
    }
    if {$olBaseName ne "none"} {
      cc-with {-link 1} {
        set dll "${olBaseName}[get-define TARGET_DLLEXT]"
        set flags [proj-cc-check-Wl-flag --out-implib ${dll}.a]
        if {"" ne $flags} {
          define LDFLAGS_OUT_IMPLIB $flags
          define SQLITE_OUT_IMPLIB ${dll}.a
          set rc 1
        }
      }
      if {!$rc} {
        user-error "--out-implib is not supported on this platform"
      }
    }
  }
  return $rc
}

########################################################################
# If the given platform identifier (defaulting to [get-define host])
# appears to be one of the Unix-on-Windows environments, returns a
# brief symbolic name for that environment, else returns an empty
# string.
#
# It does not distinguish between msys and msys2, returning msys for
# both. The build does not, as of this writing, specifically support
# msys v1. Similarly, this function returns "mingw" for both "mingw32"
# and "mingw64".
proc sqlite-env-is-unix-on-windows {{envTuple ""}} {
  if {"" eq $envTuple} {
    set envTuple [get-define host]
  }
  set name ""
  switch -glob -- $envTuple {
    *-*-cygwin { set name cygwin }
    *-*-ming*  { set name mingw }
    *-*-msys   { set name msys }
  }
  return $name
}

########################################################################
# Performs various tweaks to the build which are only relevant on
# certain platforms, e.g. Mac and "Unix on Windows" platforms (msys2,
# cygwin, ...).
#
# 1) DLL installation:
#
# [define]s SQLITE_DLL_INSTALL_RULES to a symbolic name suffix for a
# set of "make install" rules to use for installation of the DLL
# deliverable. The makefile is tasked with providing rules named
# install-dll-NAME which runs the installation for that set, as well
# as providing a rule named install-dll which resolves to
# install-dll-NAME (perhaps indirectly, depending on whether the DLL
# is (de)activated).
#
# The default value is "unix-generic".
#
# 2) --out-implib:
#
# On platforms where an "import library" is conventionally used but
# --out-implib was not explicitly used, automatically add that flag.
# This conventionally applies only to the "Unix on Windows"
# environments like msys and cygwin.
#
# 3) --dll-basename:
#
# On the same platforms addressed by --out-implib, if --dll-basename
# is not explicitly specified, --dll-basename=auto is implied.
proc sqlite-handle-env-quirks {} {
  set instName unix-generic; # name of installation rules set
  set autoDll 0; # true if --out-implib/--dll-basename should be implied
  set host [get-define host]
  switch -glob -- $host {
    *apple* -
    *darwin*    { set instName darwin }
    default {
      set x [sqlite-env-is-unix-on-windows $host]
      if {"" ne $x} {
        set instName $x
        set autoDll 1
      }
    }
  }
  define SQLITE_DLL_INSTALL_RULES $instName
  if {$autoDll} {
    if {![proj-opt-was-provided out-implib]} {
      # Imply --out-implib=auto
      proj-indented-notice [subst -nocommands -nobackslashes {
        NOTICE: auto-enabling --out-implib for environment [$host].
        Use --out-implib=none to disable this special case
        or --out-implib=auto to squelch this notice.
      }]
      proj-opt-set out-implib auto
    }
    if {![proj-opt-was-provided dll-basename]} {
      # Imply --dll-basename=auto
      proj-indented-notice [subst -nocommands -nobackslashes {
        NOTICE: auto-enabling --dll-basename for environment [$host].
        Use --dll-basename=default to disable this special case
        or --dll-basename=auto to squelch this notice.
      }]
      proj-opt-set dll-basename auto
    }
  }
  sqlite-handle-dll-basename
  sqlite-handle-out-implib
  sqlite-handle-mac-cversion
  sqlite-handle-mac-install-name
  if {[llength [info proc sqlite-custom-handle-flags]] > 0} {
    # sqlite-custom-handle-flags is assumed to be imported via a
    # client-specific import: autosetup/sqlite-custom.tcl.
    sqlite-custom-handle-flags
  }
}

########################################################################
# Perform some late-stage work and generate the configure-process
# output file(s).
proc sqlite-process-dot-in-files {} {
  ########################################################################
  # "Re-export" the autoconf-conventional --XYZdir flags into something
  # which is more easily overridable from a make invocation. See the docs
  # for [proj-remap-autoconf-dir-vars] for the explanation of why.
  #
  # We do this late in the config process, immediately before we export
  # the Makefile and other generated files, so that configure tests
  # which make make use of the autotools-conventional flags
  # (e.g. [proj-check-rpath]) may do so before we "mangle" them here.
  proj-remap-autoconf-dir-vars

  proj-dot-ins-process -validate
  make-config-header sqlite_cfg.h \
    -bare {SIZEOF_* HAVE_DECL_*} \
    -none {HAVE_CFLAG_* LDFLAGS_* SH_* SQLITE_AUTORECONFIG
      TARGET_* USE_GCOV TCL_*} \
    -auto {HAVE_* PACKAGE_*} \
    -none *
  proj-touch sqlite_cfg.h ; # help avoid frequent unnecessary @SQLITE_AUTORECONFIG@
}

########################################################################
# Handle --with-wasi-sdk[=DIR]
#
# This must be run relatively early on because it may change the
# toolchain and disable a number of config options. However, in the
# canonical build this must come after [sqlite-check-common-bins].
proc sqlite-handle-wasi-sdk {} {
  set wasiSdkDir [opt-val with-wasi-sdk] ; # ??? [lindex [opt-val with-wasi-sdk] end]
  define HAVE_WASI_SDK 0
  if {$wasiSdkDir eq ""} {
    return 0
  } elseif {$::sqliteConfig(is-cross-compiling)} {
    proj-fatal "Cannot combine --with-wasi-sdk with cross-compilation"
  }
  msg-result "Checking WASI SDK directory \[$wasiSdkDir]... "
  proj-affirm-files-exist -v {*}[prefix "$wasiSdkDir/bin/" {clang wasm-ld ar}]
  define HAVE_WASI_SDK 1
  define WASI_SDK_DIR $wasiSdkDir
  # Disable numerous options which we know either can't work or are
  # not useful in this build...
  msg-result "Using wasi-sdk clang. Disabling CLI shell and modifying config flags:"
  # Boolean (--enable-/--disable-) flags which must be switched off:
  foreach opt {
    dynlink-tools
    editline
    gcov
    icu-collations
    load-extension
    readline
    shared
    tcl
    threadsafe
  } {
    if {[proj-opt-exists $opt] && [opt-bool $opt]} {
      # -^^^^ not all builds define all of these flags
      msg-result "  --disable-$opt"
      proj-opt-set $opt 0
    }
  }
  # Non-boolean flags which need to be cleared:
  foreach opt {
    with-emsdk
    with-icu-config
    with-icu-ldflags
    with-icu-cflags
    with-linenoise
    with-tcl
  } {
    if {[proj-opt-was-provided $opt]} {
      msg-result "  removing --$opt"
      proj-opt-set $opt ""
    }
  }
  # Remember that we now have a discrepancy between
  # $::sqliteConfig(is-cross-compiling) and [proj-is-cross-compiling].
  set ::sqliteConfig(is-cross-compiling) 1

  #
  # Changing --host and --target have no effect here except to
  # possibly cause confusion. Autosetup has finished processing them
  # by this point.
  #
  #  host_alias=wasm32-wasi
  #  target=wasm32-wasi
  #
  # Merely changing CC, LD, and AR to the wasi-sdk's is enough to get
  # sqlite3.o building in WASM format.
  #
  define CC "${wasiSdkDir}/bin/clang"
  define LD "${wasiSdkDir}/bin/wasm-ld"
  define AR "${wasiSdkDir}/bin/ar"
  #define STRIP "${wasiSdkDir}/bin/strip"
  return 1
}; # sqlite-handle-wasi-sdk

########################################################################
# TCL...
#
# sqlite-check-tcl performs most of the --with-tcl and --with-tclsh
# handling. Some related bits and pieces are performed before and
# after that function is called.
#
# Important [define]'d vars:
#
#  - HAVE_TCL indicates whether we have a tclsh suitable for building
#    the TCL SQLite extension and, by extension, the testing
#    infrastructure. This must only be 1 for environments where
#    tclConfig.sh can be found.
#
#  - TCLSH_CMD is the path to the canonical tclsh or "". It never
#    refers to jimtcl.
#
#  - TCL_CONFIG_SH is the path to tclConfig.sh or "".
#
#  - TCLLIBDIR is the dir to which libtclsqlite3 gets installed.
#
#  - BTCLSH = the path to the tcl interpreter used for in-tree code
#    generation.  It may be jimtcl or the canonical tclsh but may not
#    be empty - this tree requires TCL to generated numerous
#    components.
#
# If --tcl or --with-tcl are provided but no TCL is found, this
# function fails fatally. If they are not explicitly provided then
# failure to find TCL is not fatal but a loud warning will be emitted.
#
proc sqlite-check-tcl {} {
  define TCLSH_CMD false ; # Significant is that it exits with non-0
  define HAVE_TCL 0      ; # Will be enabled via --tcl or a successful search
  define TCLLIBDIR ""    ; # Installation dir for TCL extension lib
  define TCL_CONFIG_SH ""; # full path to tclConfig.sh

  # Clear out all vars which would harvest from tclConfig.sh so that
  # the late-config validation of @VARS@ works even if --disable-tcl
  # is used.
  proj-tclConfig-sh-to-autosetup ""

  file delete -force ".tclenv.sh"; # ensure no stale state from previous configures.
  if {![opt-bool tcl]} {
    proj-indented-notice {
      NOTE: TCL is disabled via --disable-tcl. This means that none
      of the TCL-based components will be built, including tests
      and sqlite3_analyzer.
    }
    return
  }
  # TODO: document the steps this is taking.
  set srcdir $::autosetup(srcdir)
  msg-result "Checking for a suitable tcl... "
  proj-assert [proj-opt-truthy tcl]
  set use_tcl 1
  set with_tclsh [opt-val with-tclsh]
  set with_tcl [opt-val with-tcl]
  if {"prefix" eq $with_tcl} {
    set with_tcl [get-define prefix]
  }
  proc-debug "use_tcl ${use_tcl}"
  proc-debug "with_tclsh=${with_tclsh}"
  proc-debug "with_tcl=$with_tcl"
  if {"" eq $with_tclsh && "" eq $with_tcl} {
    # If neither --with-tclsh nor --with-tcl are provided, try to find
    # a workable tclsh.
    set with_tclsh [proj-first-bin-of tclsh9.1 tclsh9.0 tclsh8.6 tclsh]
    proc-debug "with_tclsh=${with_tclsh}"
  }

  set doConfigLookup 1 ; # set to 0 to test the tclConfig.sh-not-found cases
  if {"" ne $with_tclsh} {
    # --with-tclsh was provided or found above. Validate it and use it
    # to trump any value passed via --with-tcl=DIR.
    if {![file-isexec $with_tclsh]} {
      proj-fatal "TCL shell $with_tclsh is not executable"
    } else {
      define TCLSH_CMD $with_tclsh
      #msg-result "Using tclsh: $with_tclsh"
    }
    if {$doConfigLookup &&
        [catch {exec $with_tclsh $::autosetup(libdir)/find_tclconfig.tcl} result] == 0} {
      set with_tcl $result
    }
    if {"" ne $with_tcl && [file isdir $with_tcl]} {
      msg-result "$with_tclsh recommends the tclConfig.sh from $with_tcl"
    } else {
      proj-warn "$with_tclsh is unable to recommend a tclConfig.sh"
      set use_tcl 0
    }
  }
  set cfg ""
  set tclSubdirs {tcl9.1 tcl9.0 tcl8.6 lib}
  while {$use_tcl} {
    if {"" ne $with_tcl} {
      # Ensure that we can find tclConfig.sh under ${with_tcl}/...
      if {$doConfigLookup} {
        if {[file readable "${with_tcl}/tclConfig.sh"]} {
          set cfg "${with_tcl}/tclConfig.sh"
        } else {
          foreach i $tclSubdirs {
            if {[file readable "${with_tcl}/$i/tclConfig.sh"]} {
              set cfg "${with_tcl}/$i/tclConfig.sh"
              break
            }
          }
        }
      }
      if {"" eq $cfg} {
        proj-fatal "No tclConfig.sh found under ${with_tcl}"
      }
    } else {
      # If we have not yet found a tclConfig.sh file, look in $libdir
      # which is set automatically by autosetup or via the --prefix
      # command-line option.  See
      # https://sqlite.org/forum/forumpost/e04e693439a22457
      set libdir [get-define libdir]
      if {[file readable "${libdir}/tclConfig.sh"]} {
        set cfg "${libdir}/tclConfig.sh"
      } else {
        foreach i $tclSubdirs {
          if {[file readable "${libdir}/$i/tclConfig.sh"]} {
            set cfg "${libdir}/$i/tclConfig.sh"
            break
          }
        }
      }
      if {![file readable $cfg]} {
        break
      }
    }
    msg-result "Using tclConfig.sh: $cfg"
    break
  }
  define TCL_CONFIG_SH $cfg
  # Export a subset of tclConfig.sh to the current TCL-space.  If $cfg
  # is an empty string, this emits empty-string entries for the
  # various options we're interested in.
  proj-tclConfig-sh-to-autosetup $cfg

  if {"" eq $with_tclsh && $cfg ne ""} {
    # We have tclConfig.sh but no tclsh. Attempt to locate a tclsh
    # based on info from tclConfig.sh.
    set tclExecPrefix [get-define TCL_EXEC_PREFIX]
    proj-assert {"" ne $tclExecPrefix}
    set tryThese [list \
                    $tclExecPrefix/bin/tclsh[get-define TCL_VERSION] \
                    $tclExecPrefix/bin/tclsh ]
    foreach trySh $tryThese {
      if {[file-isexec $trySh]} {
        set with_tclsh $trySh
        break
      }
    }
    if {![file-isexec $with_tclsh]} {
      proj-warn "Cannot find a usable tclsh (tried: $tryThese)
    }
  }
  define TCLSH_CMD $with_tclsh
  if {$use_tcl} {
    # Set up the TCLLIBDIR
    #
    # 2024-10-28: calculation of TCLLIBDIR is now done via the shell
    # in main.mk (search it for T.tcl.env.sh) so that
    # static/hand-written makefiles which import main.mk do not have
    # to define that before importing main.mk. Even so, we export
    # TCLLIBDIR from here, which will cause the canonical makefile to
    # use this one rather than to re-calculate it at make-time.
    set tcllibdir [get-env TCLLIBDIR ""]
    if {"" eq $tcllibdir} {
      # Attempt to extract TCLLIBDIR from TCL's $auto_path
      if {"" ne $with_tclsh &&
          [catch {exec echo "puts stdout \$auto_path" | "$with_tclsh"} result] == 0} {
        foreach i $result {
          if {[file isdir $i]} {
            set tcllibdir $i/sqlite3
            break
          }
        }
      } else {
        proj-warn "Cannot determine TCLLIBDIR."
        # The makefile will fail fatally in this case if a target is
        # invoked which requires TCLLIBDIR.
      }
    }
    #if {"" ne $tcllibdir} { msg-result "TCLLIBDIR = ${tcllibdir}"; }
    define TCLLIBDIR $tcllibdir
  }; # find TCLLIBDIR

  if {[file-isexec $with_tclsh]} {
    msg-result "Using tclsh: $with_tclsh"
    if {$cfg ne ""} {
      define HAVE_TCL 1
    } else {
      proj-warn "Found tclsh but no tclConfig.sh."
    }
  }
  show-notices
  # If TCL is not found: if it was explicitly requested then fail
  # fatally, else just emit a warning. If we can find the APIs needed
  # to generate a working JimTCL then that will suffice for build-time
  # TCL purposes (see: proc sqlite-determine-codegen-tcl).
  if {![get-define HAVE_TCL] &&
      ([proj-opt-was-provided tcl] || [proj-opt-was-provided with-tcl])} {
    proj-fatal "TCL support was requested but no tclConfig.sh could be found."
  }
  if {"" eq $cfg} {
    proj-assert {0 == [get-define HAVE_TCL]}
    proj-indented-notice {
      WARNING: Cannot find a usable tclConfig.sh file.  Use
      --with-tcl=DIR to specify a directory where tclConfig.sh can be
      found.  SQLite does not use TCL internally, but some optional
      components require TCL, including tests and sqlite3_analyzer.
    }
  }
}; # sqlite-check-tcl

########################################################################
# sqlite-determine-codegen-tcl checks which TCL to use as a code
# generator.  By default, prefer jimsh simply because we have it
# in-tree (it's part of autosetup) unless --with-tclsh=X is used, in
# which case prefer X.
#
# Returns the human-readable name of the TCL it selects. Fails fatally
# if it cannot detect a TCL appropriate for code generation.
#
# Defines:
#
#   - BTCLSH = the TCL shell used for code generation. It may set this
#     to an unexpanded makefile var name.
#
#   - CFLAGS_JIMSH = any flags needed for buildng a BTCLSH-compatible
#     jimsh. The defaults may be passed on to configure as
#     CFLAGS_JIMSH=...
proc sqlite-determine-codegen-tcl {} {
  msg-result "Checking for TCL to use for code generation... "
  define CFLAGS_JIMSH [proj-get-env CFLAGS_JIMSH {-O1}]
  set cgtcl [opt-val with-tclsh jimsh]
  if {"jimsh" ne $cgtcl} {
    # When --with-tclsh=X is used, use that for all TCL purposes,
    # including in-tree code generation, per developer request.
    define BTCLSH "\$(TCLSH_CMD)"
    return $cgtcl
  }
  set flagsToRestore {CC CFLAGS AS_CFLAGS CPPFLAGS AS_CPPFLAGS LDFLAGS LINKFLAGS LIBS CROSS}
  define-push $flagsToRestore {
    # We have to swap CC to CC_FOR_BUILD for purposes of the various
    # [cc-...] tests below. Recall that --with-wasi-sdk may have
    # swapped out CC with one which is not appropriate for this block.
    # Per consulation with autosetup's creator, doing this properly
    # requires us to [define-push] the whole $flagsToRestore list
    # (plus a few others which are not relevant in this tree).
    #
    # These will get set to their previous values at the end of this
    # block.
    foreach flag $flagsToRestore {define $flag ""}
    define CC [get-define CC_FOR_BUILD]
    # These headers are technically optional for JimTCL but necessary if
    # we want to use it for code generation:
    set sysh [cc-check-includes dirent.h sys/time.h]
    # jimsh0.c hard-codes #define's for HAVE_DIRENT_H and
    # HAVE_SYS_TIME_H on the platforms it supports, so we do not
    # need to add -D... flags for those. We check for them here only
    # so that we can avoid the situation that we later, at
    # make-time, try to compile jimsh but it then fails due to
    # missing headers (i.e. fail earlier rather than later).
    if {$sysh && [cc-check-functions realpath]} {
      define-append CFLAGS_JIMSH -DHAVE_REALPATH
      define BTCLSH "\$(JIMSH)"
      set ::sqliteConfig(use-jim-for-codegen) 1
    } elseif {$sysh && [cc-check-functions _fullpath]} {
      # _fullpath() is a Windows API. It's not entirely clear
      # whether we need to add {-DHAVE_SYS_TIME_H -DHAVE_DIRENT_H}
      # to CFLAGS_JIMSH in this case. On MinGW32 we definitely do
      # not want to because it already hard-codes them. On _MSC_VER
      # builds it does not.
      define-append CFLAGS_JIMSH -DHAVE__FULLPATH
      define BTCLSH "\$(JIMSH)"
      set ::sqliteConfig(use-jim-for-codegen) 1
    } elseif {[file-isexec [get-define TCLSH_CMD]]} {
      set cgtcl [get-define TCLSH_CMD]
      define BTCLSH "\$(TCLSH_CMD)"
    } else {
      # One last-ditch effort to find TCLSH_CMD: use info from
      # tclConfig.sh to try to find a tclsh
      if {"" eq [get-define TCLSH_CMD]} {
        set tpre [get-define TCL_EXEC_PREFIX]
        if {"" ne $tpre} {
          set tv [get-define TCL_VERSION]
          if {[file-isexec "${tpre}/bin/tclsh${tv}"]} {
            define TCLSH_CMD "${tpre}/bin/tclsh${tv}"
          } elseif {[file-isexec "${tpre}/bin/tclsh"]} {
            define TCLSH_CMD "${tpre}/bin/tclsh"
          }
        }
      }
      set cgtcl [get-define TCLSH_CMD]
      if {![file-isexec $cgtcl]} {
        proj-fatal "Cannot find a tclsh to use for code generation."
      }
      define BTCLSH "\$(TCLSH_CMD)"
    }
  }; # /define-push $flagsToRestore
  return $cgtcl
}; # sqlite-determine-codegen-tcl

########################################################################
# Runs sqlite-check-tcl and, if this is the canonical build,
# sqlite-determine-codegen-tcl.
proc sqlite-handle-tcl {} {
  sqlite-check-tcl
  if {"canonical" eq $::sqliteConfig(build-mode)} {
    msg-result "TCL for code generation: [sqlite-determine-codegen-tcl]"
  }
}

########################################################################
# Handle the --enable/disable-rpath flag.
proc sqlite-handle-rpath {} {
  proj-check-rpath
  # autosetup/cc-shared.tcl sets the rpath flag definition in
  # [get-define SH_LINKRPATH], but it does so on a per-platform basis
  # rather than as a compiler check. Though we should do a proper
  # compiler check (as proj-check-rpath does), we may want to consider
  # adopting its approach of clearing the rpath flags for environments
  # for which sqlite-env-is-unix-on-windows returns a non-empty
  # string.

#  if {[proj-opt-truthy rpath]} {
#    proj-check-rpath
#  } else {
#    msg-result "Disabling use of rpath."
#    define LDFLAGS_RPATH ""
#  }
}

########################################################################
# If the --dump-defines configure flag is provided then emit a list of
# all [define] values to config.defines.txt, else do nothing.
proc sqlite-dump-defines {} {
  proj-if-opt-truthy dump-defines {
    make-config-header $::sqliteConfig(dump-defines-txt) \
      -bare {SQLITE_OS* SQLITE_DEBUG USE_*} \
      -str {BIN_* CC LD AR LDFLAG* OPT_*} \
      -auto {*}
    # achtung: ^^^^ whichever SQLITE_OS_foo flag which is set to 0 will
    # get _undefined_ here unless it's part of the -bare set.
    if {"" ne $::sqliteConfig(dump-defines-json)} {
      msg-result "--dump-defines is creating $::sqliteConfig(dump-defines-json)"
      ########################################################################
      # Dump config-defines.json...
      # Demonstrate (mis?)handling of spaces in JSON-export array values:
      # define-append OPT_FOO.list {"-DFOO=bar baz" -DBAR="baz barre"}
      define OPT_FEATURE_FLAGS.list [get-define OPT_FEATURE_FLAGS]
      define OPT_SHELL.list [get-define OPT_SHELL]
      set dumpDefsOpt {
        -bare {SIZEOF_* HAVE_DECL_*}
        -none {HAVE_CFLAG_* LDFLAGS_* SH_* SQLITE_AUTORECONFIG TARGET_* USE_GCOV TCL_*}
        -array {*.list}
        -auto {OPT_* PACKAGE_* HAVE_*}
      }
#      if {$::sqliteConfig(dump-defines-json-include-lowercase)} {
#        lappend dumpDefsOpt -none {lib_*} ; # remnants from proj-check-function-in-lib and friends
#        lappend dumpDefsOpt -auto {[a-z]*}
#      }
      lappend dumpDefsOpt -none *
      proj-dump-defs-json $::sqliteConfig(dump-defines-json) {*}$dumpDefsOpt
      undefine OPT_FEATURE_FLAGS.list
      undefine OPT_SHELL.list
    }
  }
}