1 Maintaining Autosetup in the SQLite Tree 2 ======================================================================== 3 4 This document provides some tips and reminders for the SQLite 5 developers regarding using and maintaining the [Autosetup][]-based 6 build infrastructure. It is not an [Autosetup][] reference. 7 8 **Table of Contents**: 9 10 - [Autosetup API Reference](#apiref) 11 - [API Tips](#apitips) 12 - [Ensuring TCL Compatibility](#tclcompat) 13 - [Design Conventions](#conventions) 14 - Symbolic Names of Feature Flags 15 - Do Not Update Global Shared State 16 - [Updating Autosetup](#updating) 17 - ***[Patching Autosetup for Project-local changes](#patching)*** 18 - [Branch-specific Customization](#branch-customization) 19 20 21 ------------------------------------------------------------------------ 22 23 <a name="apiref"></a> 24 Autosetup API Reference 25 ======================================================================== 26 27 The Autosetup API is quite extensive and can be read either in 28 the [files in the `autosetup` dir](/dir/autosetup) or using: 29 30 > 31 ``` 32 $ ./configure --reference | less 33 ``` 34 35 That will include any docs from any TCL files in the `./autosetup` dir 36 which contain certain (simple) markup defined by autosetup. 37 38 This project's own configuration-related TCL code is spread across the 39 following files: 40 41 - [proj.tcl][]: project-agnostic utility code for autosetup-driven 42 projects. This file is designed to be shared between this project, 43 other projects managed under the SQLite/Hwaci umbrella 44 (e.g. Fossil), and personal projects of SQLite's developers. It is 45 essentially an amalgamation of a decade's worth of autosetup-related 46 utility code. 47 - [sqlite-config.tcl][]: utility code which is too project-specific 48 for `proj.tcl`. We split this out of `auto.def` so that it can be 49 used by both `auto.def` and... 50 - [auto.def][]: the primary driver for the `./configure` process. 51 When we talk about "the configure script," we're technically 52 referring to this file, though it actually contains very little 53 of the TCL code. 54 - [autoconf/auto.def][]: the main driver script for the "autoconf" 55 bundle's configure script. It is essentially a slightly trimmed-down 56 version of the main `auto.def` file. The `autoconf` dir was ported 57 from the Autotools to Autosetup in the 3.49.0 dev cycle but retains 58 the "autoconf" name to minimize downstream disruption. 59 60 61 <a name="apitips"></a> 62 Autosetup API Tips 63 ======================================================================== 64 65 This section briefly covers only APIs which are frequently useful in 66 day-to-day maintenance and might not be immediately recognized as such 67 from a casual perusal of the relevant TCL files. The complete docs of 68 those with `proj-` prefix can be found in [proj.tcl][] and those with 69 an `sqlite-` prefix are in [sqlite-config.tcl][]. The others are part 70 of Autosetup's core packages and are scattered around [the TCL files 71 in ./autosetup](/dir/autosetup). 72 73 In (mostly) alphabetical order: 74 75 - **`file-isexec filename`**\ 76 Should be used in place of `[file executable]`, as it will also 77 check for `${filename}.exe` on Windows platforms. However, on such 78 platforms it also assumes that _any_ existing file is executable. 79 80 - **`get-env VAR ?default?`**\ 81 Will fetch an "environment variable" from the first of either: (1) a 82 KEY=VALUE passed to the configure script or (2) the system's 83 environment variables. Not to be confused with `getenv`, which only 84 does the latter and is rarely, if ever, useful in this tree. 85 - **`proj-get-env VAR ?default?`**\ 86 Works like `get-env` but will, if that function finds no match, 87 look for a file named `./.env-$VAR` and, if found, return its 88 trimmed contents. This can be used, e.g., to set a developer's 89 local preferences for the default `CFLAGS`.\ 90 Tip: adding `-O0` to `.env-CFLAGS` reduces rebuild times 91 considerably at the cost of performance in `make devtest` and the 92 like. 93 94 - **`proj-fatal msg`**\ 95 Emits `$msg` to stderr and exits with non-zero. Its differences from 96 autosetup's `user-error` are purely cosmetic. 97 98 - **`proj-if-opt-truthy flag thenScript ?elseScript?`**\ 99 Evals `thenScript` if the given `--flag` is truthy, else it 100 evals the optional `elseScript`. 101 102 - **`proj-indented-notice ?-error? ?-notice? msg`**\ 103 Breaks its `msg` argument into lines, trims them, and emits them 104 with consistent indentation. Exactly how it emits depends on the 105 flags passed to it (or not), as covered in its docs. This will stick 106 out starkly from normal output and is intended to be used only for 107 important notices. 108 109 - **`proj-opt-truthy flag`**\ 110 Returns 1 if `--flag`'s value is "truthy," i.e. one of (1, on, 111 enabled, yes, true). 112 113 - **`proj-opt-was-provided FLAG`**\ 114 Returns 1 if `--FLAG` was explicitly provided to configure, 115 else 0. This distinction can be used to determine, e.g., whether 116 `--with-readline` was provided or whether we're searching for 117 readline by default. In the former case, failure to find it should 118 be treated as fatal, where in the latter case it's not.\ 119 Unlike most functions which deal with `--flags`, this one does not 120 validate that `$FLAG` is a registered flag so will not fail fatally 121 if `$FLAG` is not registered as an Autosetup option. 122 123 - **`proj-val-truthy value`**\ 124 Returns 1 if `$value` is "truthy," See `proj-opt-truthy` for the definition 125 of "truthy." 126 127 - **`proj-warn msg`**\ 128 Emits `$msg` to stderr. Closely-related is autosetup's `user-notice` 129 (described below). 130 131 - **`sqlite-add-feature-flag ?-shell? FLAG...`**\ 132 Adds the given feature flag to the CFLAGS which are specific to 133 building libsqlite3. It's intended to be passed one or more 134 `-DSQLITE_ENABLE_...`, or similar, flags. If the `-shell` flag is 135 used then it also passes its arguments to 136 `sqlite-add-shell-opt`. This is a no-op if `FLAG` is not provided or 137 is empty. 138 139 - **`sqlite-add-shell-opt FLAG...`**\ 140 The shell-specific counterpart of `sqlite-add-feature-flag` which 141 only adds the given flag(s) to the CLI-shell-specific CFLAGS. 142 143 - **`sqlite-configure BUILD-NAME {script}`**\ 144 This is where all configure `--flags` are defined for all known 145 build modes ("canonical" or "autoconf"). After processing all flags, 146 this function runs `$script`, which contains the build-mode-specific 147 configuration bits, and then runs any finalization bits which are 148 common to all build modes. The `auto.def` files are intended to contain 149 exactly two commands: 150 `use sqlite-config; sqlite-configure BUILD-NAME {script}` 151 152 - **`user-notice msg`**\ 153 Queues `$msg` to be sent to stderr, but does not emit it until 154 either `show-notices` is called or the next time autosetup would 155 output something (it internally calls `show-notices`). This can be 156 used to generate warnings between a "checking for..." message and 157 its resulting "yes/no/whatever" message in such a way as to not 158 spoil the layout of such messages. 159 160 161 <a name="tclcompat"></a> 162 Ensuring TCL Compatibility 163 ======================================================================== 164 165 One of the significant benefits of using Autosetup is that (A) this 166 project uses many TCL scripts in the build process and (B) Autosetup 167 comes with a TCL interpreter named [JimTCL][]. 168 169 It is important that any TCL files used by the configure process and 170 makefiles remain compatible with both [JimTCL][] and the canonical 171 TCL. Though JimTCL has outstanding compatibility with canonical TCL, 172 it does have a few corners with incompatibilities, e.g. regular 173 expressions. If a script runs in JimTCL without using any 174 JimTCL-specific features, then it's a certainty that it will run in 175 canonical TCL as well. The opposite, however, is not _always_ the 176 case. 177 178 When [`./configure`](/file/configure) is run, it goes through a 179 bootstrapping process to find a suitable TCL with which to run the 180 autosetup framework. The first step involves [finding or building a 181 TCL shell](/file/autosetup/autosetup-find-tclsh). That will first 182 search for an available `tclsh` (under several common names, 183 e.g. `tclsh8.6`) before falling back to compiling the copy of 184 `jimsh0.c` included in the source tree. i.e. it will prefer to use a 185 system-installed TCL for running the configure script. Once it finds 186 (or builds) a TCL shell, it then runs [a sanity test to ensure that 187 the shell is suitable](/file/autosetup/autosetup-test-tclsh) before 188 using it to run the main autosetup app. 189 190 There are two simple ways to ensure that running of the configure 191 process uses JimTCL instead of the canonical `tclsh`, and either 192 approach provides equally high assurances about configure script 193 compatibility across TCL implementations: 194 195 1. Build on a system with no `tclsh` installed in the `$PATH`. In that 196 case, the configure process will fall back to building the in-tree 197 copy of JimTCL. 198 199 2. Manually build `./jimsh0` in the top of the checkout with:\ 200 `cc -o jimsh0 autosetup/jimsh0.c`\ 201 With that in place, the configure script will prefer to use that 202 before looking for a system-level `tclsh`. Be aware, though, that 203 `make distclean` will remove that file. 204 205 **Note that `./jimsh0` is distinctly different from the `./jimsh`** 206 which gets built for code-generation purposes. The latter requires 207 non-default build flags to enable features which are 208 platform-dependent, most notably to make its `[file normalize]` work. 209 This means, for example, that the configure script and its utility 210 APIs must not use `[file normalize]`, but autosetup provides a 211 TCL-only implementation of `[file-normalize]` (note the dash) for 212 portable use in the configure script. Contrariwise, code-generation 213 scripts invoked via `make` may use `[file normalize]`, as they'll use 214 `./jimsh` or `tclsh` instead of `./jimsh0`. 215 216 217 Known TCL Incompatibilities 218 ------------------------------------------------------------------------ 219 220 A summary of known incompatibilities in JimTCL 221 222 - **CRNL line endings**: prior to 2025-02-05 `fconfigure -translation ...` 223 was a no-op in JimTCL, and it emits CRNL line endings by default on 224 Windows. Since then, it supports `-translation binary`, which is 225 close enough to `-translation lf` for our purposes. When working 226 with files using the `open` command, it is important to use mode 227 `"rb"` or `"wb"`, as appropriate, so that the output does not get 228 CRNL-mangled on Windows. 229 230 - **`file copy`** does not support multiple source files. See 231 [](/info/61f18c96183867fe) for a workaround. 232 233 - **Regular expressions**: 234 235 - Patterns treat `\nnn` octal values as back-references (which it 236 does not support). Those can be reformulated as demonstrated in 237 [](/info/aeac23359bb681c0). 238 239 - `regsub` does not support the `\y` flag. A workaround is demonstrated 240 in [](/info/c2e5dd791cce3ec4). 241 242 243 <a name="conventions"></a> 244 Design Conventions 245 ======================================================================== 246 247 This section describes the motivations for the most glaring of the 248 build's design decisions, in particular how they deviate from 249 historical, or even widely-conventional, practices. 250 251 Symbolic Names of Feature Flags 252 ------------------------------------------------------------------------ 253 254 Historically, the project's makefile has exclusively used 255 `UPPER_UNDERSCORE` form for makefile variables. This build, however, 256 primarily uses `X.y` format, where `X` is often a category label, 257 e.g. `CFLAGS`, and `y` is the specific instance of that category, 258 e.g. `CFLAGS.readline`. 259 260 When the configure script exports flags for consumption by filtered 261 files, e.g. [Makefile.in][] and the generated 262 `sqlite_cfg.h`, it does so in the more conventional `X_Y` form because 263 those flags get exported as as C `#define`s to `sqlite_cfg.h`, where 264 dots are not permitted. 265 266 The `X.y` convention is used in the makefiles primarily because the 267 person who did the initial port finds that considerably easier on the 268 eyes and fingers. In practice, the `X_Y` form of such exports is used 269 exactly once in [Makefile.in][], where it's translated from `@X_Y@` 270 into into `X.y` form for consumption by [Makefile.in][] and 271 [main.mk][]. For example: 272 273 > 274 ``` 275 LDFLAGS.shobj = @SHOBJ_LDFLAGS@ 276 LDFLAGS.zlib = @LDFLAGS_ZLIB@ 277 LDFLAGS.math = @LDFLAGS_MATH@ 278 ``` 279 280 (That first one is defined by autosetup, and thus applies "LDFLAGS" as 281 the suffix rather than the prefix. Which is more legible is a matter 282 of taste, for which there is no accounting.) 283 284 285 Do Not Update Global Shared State 286 ------------------------------------------------------------------------ 287 288 In both the legacy Autotools-driven build and common Autosetup usage, 289 feature tests performed by the configure script may amend global flags 290 such as `LIBS`, `LDFLAGS`, and `CFLAGS`[^as-cflags]. That's 291 appropriate for a makefile which builds a single deliverable, but less 292 so for makefiles which produce multiple deliverables. Drawbacks of 293 that approach include: 294 295 - It's unlikely that every single deliverable will require the same 296 core set of those flags. 297 - It can be difficult to determine the origin of any given change to 298 that global state because those changes are hidden behind voodoo 299 performed outside the immediate visibility of the configure script's 300 maintainer. 301 - It can force the maintainers of the configure script to place tests 302 in a specific order so that the resulting flags get applied at 303 the correct time and/or in the correct order.\ 304 (A real-life example: before the approach described below was taken 305 to collecting build-time flags, the test for `-rpath` had to come 306 _after_ the test for zlib because the results of the `-rpath` test 307 implicitly modified global state which broke the zlib feature 308 test. Because the feature tests no longer (intentionally) modify 309 shared global state, that is not an issue.) 310 311 In this build, cases where feature tests modify global state in such a 312 way that it may impact later feature tests are either (A) very 313 intentionally defined to do so (e.g. the `--with-wasi-sdk` flag has 314 invasive side-effects) or (B) are oversights (i.e. bugs). 315 316 This tree's [configure script][auto.def], [utility APIs][proj.tcl], 317 [Makefile.in][], and [main.mk][] therefore strive to separate the 318 results of any given feature test into its own well-defined 319 variables. For example: 320 321 - The linker flags for zlib are exported from the configure script as 322 `LDFLAGS_ZLIB`, which [Makefile.in][] and [main.mk][] then expose as 323 `LDFLAGS.zlib`. 324 - `CFLAGS_READLINE` (a.k.a. `CFLAGS.readline`) contains the `CFLAGS` 325 needed for including `libreadline`, `libedit`, or `linenoise`, and 326 `LDFLAGS_READLINE` (a.k.a. `LDFLAGS.readline`) is its link-time 327 counterpart. 328 329 It is then up to the Makefile to apply and order the flags however is 330 appropriate. 331 332 At the end of the configure script, the global `CFLAGS` _ideally_ 333 holds only flags which are either relevant to all targets or, failing 334 that, will have no unintended side-effects on any targets. That said: 335 clients frequently pass custom `CFLAGS` to `./configure` or `make` to 336 set library-level feature toggles, e.g. `-DSQLITE_OMIT_FOO`, in which 337 case there is no practical way to avoid "polluting" the builds of 338 arbitrary makefile targets with those. _C'est la vie._ 339 340 341 [^as-cflags]: But see this article for a detailed discussion of how 342 autosetup currently deals specifically with CFLAGS: 343 <https://msteveb.github.io/autosetup/articles/handling-cflags/> 344 345 346 <a name="updating"></a> 347 Updating Autosetup 348 ======================================================================== 349 350 Updating autosetup is, more often than not, painless. It requires having 351 a checked-out copy of [the autosetup git repository][autosetup-git]: 352 353 > 354 ``` 355 $ git clone https://github.com/msteveb/autosetup 356 $ cd autosetup 357 # Or, if it's already checked out: 358 $ git pull 359 ``` 360 361 Then, from the top-most directory of an SQLite checkout: 362 363 > 364 ``` 365 $ /path/to/autosetup-checkout/autosetup --install . 366 $ fossil status # show the modified files 367 ``` 368 369 Unless the upgrade made any incompatible changes (which is exceedingly 370 rare), that's all there is to it. After that's done, **apply a patch 371 for the change described in the following section**, test the 372 configure process, and check it in. 373 374 <a name="patching"></a> 375 Patching Autosetup for Project-local Changes 376 ------------------------------------------------------------------------ 377 378 The autosetup files require the following patches after updating 379 from their upstream sources: 380 381 ### `--debug` flag 382 383 Autosetup reserves the flag name **`--debug`** for its own purposes, 384 and its own special handling of `--enable-...` flags makes `--debug` 385 an alias for `--enable-debug`. As this project has a long history of 386 using `--enable-debug`, we patch autosetup to use the name 387 `--autosetup-debug` in place of `--debug`. That requires (as of this 388 writing) four small edits in 389 [/autosetup/autosetup](/file/autosetup/autosetup), as demonstrated in 390 [check-in 3296c8d3](/info/3296c8d3). 391 392 If autosetup is upgraded and this patch is _not_ applied the invoking 393 `./configure` will fail loudly because of the declaration of the 394 `debug` flag in `auto.def` - duplicated flags are not permitted. 395 396 ### Fail on `malloc()` error 397 398 See [check-in 72c8a5b94cdf5d](/info/72c8a5b94cdf5d). 399 400 401 <a name="branch-customization"></a> 402 Branch-specific Customization 403 ======================================================================== 404 405 Certain vendor-specific branches require slight configure script 406 customization. Rather than editing `sqlite-config.tcl` for this, 407 which frequently leads to merge conflicts, the following approach 408 is recommended: 409 410 In the vendor-specific branch, create a file named 411 `autosetup/sqlite-custom.tcl`. 412 413 That file should contain the following content... 414 415 If flag customization is required, add: 416 417 > 418 ``` 419 proc sqlite-custom-flags {} { 420 # If any existing --flags require different default values 421 # then call: 422 options-defaults { 423 flag-name new-default-value 424 ... 425 } 426 # ^^^ That will replace the default value but will not update 427 # the --help text, which may lead to some confusion: 428 # https://github.com/msteveb/autosetup/issues/77 429 430 return { 431 {*} { 432 new-flag-name => {Help text} 433 ... 434 } 435 }; #see below 436 } 437 ``` 438 439 That function must return either an empty string or a list in the form 440 used internally by [sqlite-config.tcl][]'s `sqlite-configure`. 441 442 Next, define: 443 444 > 445 ``` 446 proc sqlite-custom-handle-flags {} { 447 ... do any custom flag handling here ... 448 } 449 ``` 450 451 That function, if defined, will be called relatively late in the 452 configure process, before any filtered files are generated but after 453 all other significant processing. 454 455 456 [Autosetup]: https://msteveb.github.io/autosetup/ 457 [auto.def]: /file/auto.def 458 [autoconf/auto.def]: /file/autoconf/auto.def 459 [autosetup-git]: https://github.com/msteveb/autosetup 460 [proj.tcl]: /file/autosetup/proj.tcl 461 [sqlite-config.tcl]: /file/autosetup/sqlite-config.tcl 462 [Makefile.in]: /file/Makefile.in 463 [main.mk]: /file/main.mk 464 [JimTCL]: https://msteveb.github.io/jimtcl/ 465