significantly expand logging of error conditions
[sqlcipher.git] / tool / mksqlite3c.tcl
blob878764de92883f46c3bc5c76f7af5dd414ff8147
1 #!/usr/bin/tclsh
3 # To build a single huge source file holding all of SQLite (or at
4 # least the core components - the test harness, shell, and TCL
5 # interface are omitted.) first do
7 # make target_source
9 # The make target above moves all of the source code files into
10 # a subdirectory named "tsrc". (This script expects to find the files
11 # there and will not work if they are not found.) There are a few
12 # generated C code files that are also added to the tsrc directory.
13 # For example, the "parse.c" and "parse.h" files to implement the
14 # the parser are derived from "parse.y" using lemon. And the
15 # "keywordhash.h" files is generated by a program named "mkkeywordhash".
17 # After the "tsrc" directory has been created and populated, run
18 # this script:
20 # tclsh mksqlite3c.tcl --srcdir $SRC
22 # The amalgamated SQLite code will be written into sqlite3.c
25 # Begin by reading the "sqlite3.h" header file. Extract the version number
26 # from in this file. The version number is needed to generate the header
27 # comment of the amalgamation.
29 set addstatic 1
30 set linemacros 0
31 set useapicall 0
32 for {set i 0} {$i<[llength $argv]} {incr i} {
33 set x [lindex $argv $i]
34 if {[regexp {^-+nostatic$} $x]} {
35 set addstatic 0
36 } elseif {[regexp {^-+linemacros} $x]} {
37 set linemacros 1
38 } elseif {[regexp {^-+useapicall} $x]} {
39 set useapicall 1
40 } else {
41 error "unknown command-line option: $x"
44 set in [open tsrc/sqlite3.h]
45 set cnt 0
46 set VERSION ?????
47 while {![eof $in]} {
48 set line [gets $in]
49 if {$line=="" && [eof $in]} break
50 incr cnt
51 regexp {#define\s+SQLITE_VERSION\s+"(.*)"} $line all VERSION
53 close $in
55 # Open the output file and write a header comment at the beginning
56 # of the file.
58 set out [open sqlite3.c w]
59 # Force the output to use unix line endings, even on Windows.
60 fconfigure $out -translation lf
61 set today [clock format [clock seconds] -format "%Y-%m-%d %H:%M:%S UTC" -gmt 1]
62 puts $out [subst \
63 {/******************************************************************************
64 ** This file is an amalgamation of many separate C source files from SQLite
65 ** version $VERSION. By combining all the individual C code files into this
66 ** single large file, the entire code can be compiled as a single translation
67 ** unit. This allows many compilers to do optimizations that would not be
68 ** possible if the files were compiled separately. Performance improvements
69 ** of 5% or more are commonly seen when SQLite is compiled as a single
70 ** translation unit.
72 ** This file is all you need to compile SQLite. To use SQLite in other
73 ** programs, you need this file and the "sqlite3.h" header file that defines
74 ** the programming interface to the SQLite library. (If you do not have
75 ** the "sqlite3.h" header file at hand, you will find a copy embedded within
76 ** the text of this file. Search for "Begin file sqlite3.h" to find the start
77 ** of the embedded sqlite3.h header file.) Additional code files may be needed
78 ** if you want a wrapper to interface SQLite with your choice of programming
79 ** language. The code for the "sqlite3" command-line shell is also in a
80 ** separate file. This file contains only code for the core SQLite library.
82 #define SQLITE_CORE 1
83 #define SQLITE_AMALGAMATION 1}]
84 if {$addstatic} {
85 puts $out \
86 {#ifndef SQLITE_PRIVATE
87 # define SQLITE_PRIVATE static
88 #endif}
91 # Examine the parse.c file. If it contains lines of the form:
93 # "#ifndef SQLITE_ENABLE_UPDATE_LIMIT
95 # then set the SQLITE_UDL_CAPABLE_PARSER flag in the amalgamation.
97 set in [open tsrc/parse.c]
98 if {[regexp {ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT} [read $in]]} {
99 puts $out "#define SQLITE_UDL_CAPABLE_PARSER 1"
101 close $in
103 # These are the header files used by SQLite. The first time any of these
104 # files are seen in a #include statement in the C code, include the complete
105 # text of the file in-line. The file only needs to be included once.
107 foreach hdr {
108 crypto.h
109 sqlcipher.h
110 btree.h
111 btreeInt.h
112 fts3.h
113 fts3Int.h
114 fts3_hash.h
115 fts3_tokenizer.h
116 geopoly.c
117 hash.h
118 hwtime.h
119 keywordhash.h
120 msvc.h
121 mutex.h
122 opcodes.h
123 os_common.h
124 os_setup.h
125 os_win.h
126 os.h
127 pager.h
128 parse.h
129 pcache.h
130 pragma.h
131 rtree.h
132 sqlite3session.h
133 sqlite3.h
134 sqlite3ext.h
135 sqlite3rbu.h
136 sqliteicu.h
137 sqliteInt.h
138 sqliteLimit.h
139 vdbe.h
140 vdbeInt.h
141 vxworks.h
142 wal.h
143 whereInt.h
145 set available_hdr($hdr) 1
147 set available_hdr(sqliteInt.h) 0
148 set available_hdr(sqlite3session.h) 0
150 # These headers should be copied into the amalgamation without modifying any
151 # of their function declarations or definitions.
152 set varonly_hdr(sqlite3.h) 1
154 # These are the functions that accept a variable number of arguments. They
155 # always need to use the "cdecl" calling convention even when another calling
156 # convention (e.g. "stcall") is being used for the rest of the library.
157 set cdecllist {
158 sqlite3_config
159 sqlite3_db_config
160 sqlite3_log
161 sqlite3_mprintf
162 sqlite3_snprintf
163 sqlite3_test_control
164 sqlite3_vtab_config
167 # 78 stars used for comment formatting.
168 set s78 \
169 {*****************************************************************************}
171 # Insert a comment into the code
173 proc section_comment {text} {
174 global out s78
175 set n [string length $text]
176 set nstar [expr {60 - $n}]
177 set stars [string range $s78 0 $nstar]
178 puts $out "/************** $text $stars/"
181 # Read the source file named $filename and write it into the
182 # sqlite3.c output file. If any #include statements are seen,
183 # process them appropriately.
185 proc copy_file {filename} {
186 global seen_hdr available_hdr varonly_hdr cdecllist out
187 global addstatic linemacros useapicall
188 set ln 0
189 set tail [file tail $filename]
190 section_comment "Begin file $tail"
191 if {$linemacros} {puts $out "#line 1 \"$filename\""}
192 set in [open $filename r]
193 set varpattern {^[a-zA-Z][a-zA-Z_0-9 *]+(sqlite3[_a-zA-Z0-9]+)(\[|;| =)}
194 set declpattern {([a-zA-Z][a-zA-Z_0-9 ]+ \**)(sqlite3[_a-zA-Z0-9]+)(\(.*)}
195 if {[file extension $filename]==".h"} {
196 set declpattern " *$declpattern"
198 set declpattern ^$declpattern\$
199 while {![eof $in]} {
200 set line [string trimright [gets $in]]
201 incr ln
202 if {[regexp {^\s*#\s*include\s+["<]([^">]+)[">]} $line all hdr]} {
203 if {[info exists available_hdr($hdr)]} {
204 if {$available_hdr($hdr)} {
205 if {$hdr!="os_common.h" && $hdr!="hwtime.h"} {
206 set available_hdr($hdr) 0
208 section_comment "Include $hdr in the middle of $tail"
209 copy_file tsrc/$hdr
210 section_comment "Continuing where we left off in $tail"
211 if {$linemacros} {puts $out "#line [expr {$ln+1}] \"$filename\""}
212 } else {
213 # Comment out the entire line, replacing any nested comment
214 # begin/end markers with the harmless substring "**".
215 puts $out "/* [string map [list /* ** */ **] $line] */"
217 } elseif {![info exists seen_hdr($hdr)]} {
218 if {![regexp {/\*\s+amalgamator:\s+dontcache\s+\*/} $line]} {
219 set seen_hdr($hdr) 1
221 puts $out $line
222 } elseif {[regexp {/\*\s+amalgamator:\s+keep\s+\*/} $line]} {
223 # This include file must be kept because there was a "keep"
224 # directive inside of a line comment.
225 puts $out $line
226 } else {
227 # Comment out the entire line, replacing any nested comment
228 # begin/end markers with the harmless substring "**".
229 puts $out "/* [string map [list /* ** */ **] $line] */"
231 } elseif {[regexp {^#ifdef __cplusplus} $line]} {
232 puts $out "#if 0"
233 } elseif {!$linemacros && [regexp {^#line} $line]} {
234 # Skip #line directives.
235 } elseif {$addstatic
236 && ![regexp {^(static|typedef|SQLITE_PRIVATE)} $line]} {
237 # Skip adding the SQLITE_PRIVATE or SQLITE_API keyword before
238 # functions if this header file does not need it.
239 if {![info exists varonly_hdr($tail)]
240 && [regexp $declpattern $line all rettype funcname rest]} {
241 regsub {^SQLITE_API } $line {} line
242 regsub {^SQLITE_API } $rettype {} rettype
244 # Add the SQLITE_PRIVATE or SQLITE_API keyword before functions.
245 # so that linkage can be modified at compile-time.
246 if {[regexp {^sqlite3[a-z]*_} $funcname]} {
247 set line SQLITE_API
248 append line " " [string trim $rettype]
249 if {[string index $rettype end] ne "*"} {
250 append line " "
252 if {$useapicall} {
253 if {[lsearch -exact $cdecllist $funcname] >= 0} {
254 append line SQLITE_CDECL " "
255 } else {
256 append line SQLITE_APICALL " "
259 append line $funcname $rest
260 if {$funcname=="sqlite3_sourceid" && !$linemacros} {
261 # The sqlite3_sourceid() routine is synthesized at the end of
262 # the amalgamation
263 puts $out "/* $line */"
264 } else {
265 puts $out $line
267 } else {
268 puts $out "SQLITE_PRIVATE $line"
270 } elseif {[regexp $varpattern $line all varname]} {
271 # Add the SQLITE_PRIVATE before variable declarations or
272 # definitions for internal use
273 regsub {^SQLITE_API } $line {} line
274 if {![regexp {^sqlite3_} $varname]} {
275 regsub {^extern } $line {} line
276 puts $out "SQLITE_PRIVATE $line"
277 } else {
278 if {[regexp {const char sqlite3_version\[\];} $line]} {
279 set line {const char sqlite3_version[] = SQLITE_VERSION;}
281 regsub {^SQLITE_EXTERN } $line {} line
282 puts $out "SQLITE_API $line"
284 } elseif {[regexp {^(SQLITE_EXTERN )?void \(\*sqlite3IoTrace\)} $line]} {
285 regsub {^SQLITE_API } $line {} line
286 regsub {^SQLITE_EXTERN } $line {} line
287 puts $out $line
288 } elseif {[regexp {^void \(\*sqlite3Os} $line]} {
289 regsub {^SQLITE_API } $line {} line
290 puts $out "SQLITE_PRIVATE $line"
291 } else {
292 puts $out $line
294 } else {
295 puts $out $line
298 close $in
299 section_comment "End of $tail"
303 # Process the source files. Process files containing commonly
304 # used subroutines first in order to help the compiler find
305 # inlining opportunities.
308 foreach file {
309 ctime.c
310 sqliteInt.h
312 crypto.c
313 crypto_impl.c
314 crypto_libtomcrypt.c
315 crypto_nss.c
316 crypto_openssl.c
317 crypto_cc.c
319 global.c
320 status.c
321 date.c
322 os.c
324 fault.c
325 mem0.c
326 mem1.c
327 mem2.c
328 mem3.c
329 mem5.c
330 mutex.c
331 mutex_noop.c
332 mutex_unix.c
333 mutex_w32.c
334 malloc.c
335 printf.c
336 treeview.c
337 random.c
338 threads.c
339 utf.c
340 util.c
341 hash.c
342 opcodes.c
344 os_unix.c
345 os_win.c
346 memdb.c
348 bitvec.c
349 pcache.c
350 pcache1.c
351 rowset.c
352 pager.c
353 wal.c
355 btmutex.c
356 btree.c
357 backup.c
359 vdbemem.c
360 vdbeaux.c
361 vdbeapi.c
362 vdbetrace.c
363 vdbe.c
364 vdbeblob.c
365 vdbesort.c
366 vdbevtab.c
367 memjournal.c
369 walker.c
370 resolve.c
371 expr.c
372 alter.c
373 analyze.c
374 attach.c
375 auth.c
376 build.c
377 callback.c
378 delete.c
379 func.c
380 fkey.c
381 insert.c
382 legacy.c
383 loadext.c
384 pragma.c
385 prepare.c
386 select.c
387 table.c
388 trigger.c
389 update.c
390 upsert.c
391 vacuum.c
392 vtab.c
393 wherecode.c
394 whereexpr.c
395 where.c
396 window.c
398 parse.c
400 tokenize.c
401 complete.c
403 main.c
404 notify.c
406 fts3.c
407 fts3_aux.c
408 fts3_expr.c
409 fts3_hash.c
410 fts3_porter.c
411 fts3_tokenizer.c
412 fts3_tokenizer1.c
413 fts3_tokenize_vtab.c
414 fts3_write.c
415 fts3_snippet.c
416 fts3_unicode.c
417 fts3_unicode2.c
419 json1.c
420 rtree.c
421 icu.c
423 fts3_icu.c
424 sqlite3rbu.c
425 dbstat.c
426 dbpage.c
427 sqlite3session.c
428 fts5.c
429 stmt.c
431 copy_file tsrc/$file
434 # Synthesize an alternative sqlite3_sourceid() implementation that
435 # that tries to detects changes in the amalgamation source text
436 # and modify returns a modified source-id if changes are detected.
438 # The only detection mechanism we have is the __LINE__ macro. So only
439 # edits that changes the number of lines of source code are detected.
441 if {!$linemacros} {
442 flush $out
443 set in2 [open sqlite3.c]
444 set cnt 0
445 set oldsrcid {}
446 while {![eof $in2]} {
447 incr cnt
448 gets $in2 line
449 if {[regexp {^#define SQLITE_SOURCE_ID } $line]} {set oldsrcid $line}
451 close $in2
452 regsub {[0-9a-flt]{4}"} $oldsrcid {alt2"} oldsrcid
453 puts $out \
454 "#if __LINE__!=[expr {$cnt+0}]
455 #undef SQLITE_SOURCE_ID
456 $oldsrcid
457 #endif
458 /* Return the source-id for this library */
459 SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }"
461 puts $out \
462 "/************************** End of sqlite3.c ******************************/"
464 close $out