Add tests for the new code on this branch.
[sqlite.git] / tool / mksqlite3c.tcl
blob53fa59ac7aa614fde09180de31a24b6a8da19972
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
22 # The amalgamated SQLite code will be written into sqlite3.c
25 set help {Usage: tclsh mksqlite3c.tcl <options>
26 where <options> is zero or more of the following with these effects:
27 --nostatic => Do not generate with compile-time modifiable linkage.
28 --linemacros=? => Emit #line directives into output or not. (? = 1 or 0)
29 --useapicall => Prepend functions with SQLITE_APICALL or SQLITE_CDECL.
30 --srcdir $SRC => Specify the directory containing constituent sources.
31 --help => See this.
32 The value setting options default to --linemacros=1 and '--srcdir tsrc' .
35 # Begin by reading the "sqlite3.h" header file. Extract the version number
36 # from in this file. The version number is needed to generate the header
37 # comment of the amalgamation.
40 set addstatic 1
41 set linemacros 0
42 set useapicall 0
43 set enable_recover 0
44 set srcdir tsrc
46 for {set i 0} {$i<[llength $argv]} {incr i} {
47 set x [lindex $argv $i]
48 if {[regexp {^-?-enable-recover$} $x]} {
49 set enable_recover 1
50 } elseif {[regexp {^-?-nostatic$} $x]} {
51 set addstatic 0
52 } elseif {[regexp {^-?-linemacros(?:=([01]))?$} $x ma ulm]} {
53 if {$ulm == ""} {set ulm 1}
54 set linemacros $ulm
55 } elseif {[regexp {^-?-useapicall$} $x]} {
56 set useapicall 1
57 } elseif {[regexp {^-?-srcdir$} $x]} {
58 incr i
59 if {$i==[llength $argv]} {
60 error "No argument following $x"
62 set srcdir [lindex $argv $i]
63 } elseif {[regexp {^-?-((help)|\?)$} $x]} {
64 puts $help
65 exit 0
66 } else {
67 error "unknown command-line option: $x"
70 set in [open $srcdir/sqlite3.h]
71 set cnt 0
72 set VERSION ?????
73 while {![eof $in]} {
74 set line [gets $in]
75 if {$line=="" && [eof $in]} break
76 incr cnt
77 regexp {#define\s+SQLITE_VERSION\s+"(.*)"} $line all VERSION
79 close $in
81 # Open the output file and write a header comment at the beginning
82 # of the file.
84 set fname sqlite3.c
85 if {$enable_recover} { set fname sqlite3r.c }
86 set out [open $fname w]
87 # Force the output to use unix line endings, even on Windows.
88 fconfigure $out -translation lf
89 set today [clock format [clock seconds] -format "%Y-%m-%d %H:%M:%S UTC" -gmt 1]
90 puts $out [subst \
91 {/******************************************************************************
92 ** This file is an amalgamation of many separate C source files from SQLite
93 ** version $VERSION. By combining all the individual C code files into this
94 ** single large file, the entire code can be compiled as a single translation
95 ** unit. This allows many compilers to do optimizations that would not be
96 ** possible if the files were compiled separately. Performance improvements
97 ** of 5% or more are commonly seen when SQLite is compiled as a single
98 ** translation unit.
100 ** This file is all you need to compile SQLite. To use SQLite in other
101 ** programs, you need this file and the "sqlite3.h" header file that defines
102 ** the programming interface to the SQLite library. (If you do not have
103 ** the "sqlite3.h" header file at hand, you will find a copy embedded within
104 ** the text of this file. Search for "Begin file sqlite3.h" to find the start
105 ** of the embedded sqlite3.h header file.) Additional code files may be needed
106 ** if you want a wrapper to interface SQLite with your choice of programming
107 ** language. The code for the "sqlite3" command-line shell is also in a
108 ** separate file. This file contains only code for the core SQLite library.
109 **}]
110 set srcroot [file dirname [file dirname [info script]]]
111 if {$tcl_platform(platform)=="windows"} {
112 set vsrcprog src-verify.exe
113 } else {
114 set vsrcprog ./src-verify
116 if {[file executable $vsrcprog] && [file readable $srcroot/manifest]} {
117 set res [string trim [split [exec $vsrcprog -x $srcroot]] \n]
118 puts $out "** The content in this amalgamation comes from Fossil check-in"
119 puts -nonewline $out "** [string range [lindex $res 0] 0 35]"
120 if {[llength $res]==1} {
121 puts $out "."
122 } else {
123 puts $out " with changes in files:\n**"
124 foreach f [lrange $res 1 end] {
125 puts $out "** $f"
128 } else {
129 puts $out "** The origin of the sources used to build this amalgamation"
130 puts $out "** is unknown."
132 puts $out [subst {*/
133 #define SQLITE_CORE 1
134 #define SQLITE_AMALGAMATION 1}]
135 if {$addstatic} {
136 puts $out \
137 {#ifndef SQLITE_PRIVATE
138 # define SQLITE_PRIVATE static
139 #endif}
142 # Examine the parse.c file. If it contains lines of the form:
144 # "#ifndef SQLITE_ENABLE_UPDATE_LIMIT
146 # then set the SQLITE_UDL_CAPABLE_PARSER flag in the amalgamation.
148 set in [open $srcdir/parse.c]
149 if {[regexp {ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT} [read $in]]} {
150 puts $out "#define SQLITE_UDL_CAPABLE_PARSER 1"
152 close $in
154 # These are the header files used by SQLite. The first time any of these
155 # files are seen in a #include statement in the C code, include the complete
156 # text of the file in-line. The file only needs to be included once.
158 foreach hdr {
159 btree.h
160 btreeInt.h
161 fts3.h
162 fts3Int.h
163 fts3_hash.h
164 fts3_tokenizer.h
165 geopoly.c
166 hash.h
167 hwtime.h
168 keywordhash.h
169 msvc.h
170 mutex.h
171 opcodes.h
172 os_common.h
173 os_setup.h
174 os_win.h
175 os.h
176 pager.h
177 parse.h
178 pcache.h
179 pragma.h
180 rtree.h
181 sqlite3session.h
182 sqlite3.h
183 sqlite3ext.h
184 sqlite3rbu.h
185 sqliteicu.h
186 sqliteInt.h
187 sqliteLimit.h
188 vdbe.h
189 vdbeInt.h
190 vxworks.h
191 wal.h
192 whereInt.h
193 sqlite3recover.h
195 set available_hdr($hdr) 1
197 set available_hdr(sqliteInt.h) 0
198 set available_hdr(os_common.h) 0
199 set available_hdr(sqlite3session.h) 0
201 # These headers should be copied into the amalgamation without modifying any
202 # of their function declarations or definitions.
203 set varonly_hdr(sqlite3.h) 1
205 # These are the functions that accept a variable number of arguments. They
206 # always need to use the "cdecl" calling convention even when another calling
207 # convention (e.g. "stcall") is being used for the rest of the library.
208 set cdecllist {
209 sqlite3_config
210 sqlite3_db_config
211 sqlite3_log
212 sqlite3_mprintf
213 sqlite3_snprintf
214 sqlite3_test_control
215 sqlite3_vtab_config
218 # 78 stars used for comment formatting.
219 set s78 \
220 {*****************************************************************************}
222 # Insert a comment into the code
224 proc section_comment {text} {
225 global out s78
226 set n [string length $text]
227 set nstar [expr {60 - $n}]
228 set stars [string range $s78 0 $nstar]
229 puts $out "/************** $text $stars/"
232 # Read the source file named $filename and write it into the
233 # sqlite3.c output file. If any #include statements are seen,
234 # process them appropriately.
236 proc copy_file {filename} {
237 global seen_hdr available_hdr varonly_hdr cdecllist out
238 global addstatic linemacros useapicall srcdir
239 set ln 0
240 set tail [file tail $filename]
241 section_comment "Begin file $tail"
242 if {$linemacros} {puts $out "#line 1 \"$filename\""}
243 set in [open $filename r]
244 set varpattern {^[a-zA-Z][a-zA-Z_0-9 *]+(sqlite3[_a-zA-Z0-9]+)(\[|;| =)}
245 set declpattern {([a-zA-Z][a-zA-Z_0-9 ]+ \**)(sqlite3[_a-zA-Z0-9]+)(\(.*)}
246 if {[file extension $filename]==".h"} {
247 set declpattern " *$declpattern"
249 set declpattern ^$declpattern\$
250 while {![eof $in]} {
251 set line [string trimright [gets $in]]
252 incr ln
253 if {[regexp {^\s*#\s*include\s+["<]([^">]+)[">]} $line all hdr]} {
254 if {[info exists available_hdr($hdr)]} {
255 if {$available_hdr($hdr)} {
256 set available_hdr($hdr) 0
257 section_comment "Include $hdr in the middle of $tail"
258 copy_file $srcdir/$hdr
259 section_comment "Continuing where we left off in $tail"
260 if {$linemacros} {puts $out "#line [expr {$ln+1}] \"$filename\""}
261 } else {
262 # Comment out the entire line, replacing any nested comment
263 # begin/end markers with the harmless substring "**".
264 puts $out "/* [string map [list /* ** */ **] $line] */"
266 } elseif {![info exists seen_hdr($hdr)]} {
267 if {![regexp {/\*\s+amalgamator:\s+dontcache\s+\*/} $line]} {
268 set seen_hdr($hdr) 1
270 puts $out $line
271 } elseif {[regexp {/\*\s+amalgamator:\s+keep\s+\*/} $line]} {
272 # This include file must be kept because there was a "keep"
273 # directive inside of a line comment.
274 puts $out $line
275 } else {
276 # Comment out the entire line, replacing any nested comment
277 # begin/end markers with the harmless substring "**".
278 puts $out "/* [string map [list /* ** */ **] $line] */"
280 } elseif {[regexp {^#ifdef __cplusplus} $line]} {
281 puts $out "#if 0"
282 } elseif {!$linemacros && [regexp {^#line} $line]} {
283 # Skip #line directives.
284 } elseif {$addstatic
285 && ![regexp {^(static|typedef|SQLITE_PRIVATE)} $line]} {
286 # Skip adding the SQLITE_PRIVATE or SQLITE_API keyword before
287 # functions if this header file does not need it.
288 if {![info exists varonly_hdr($tail)]
289 && [regexp $declpattern $line all rettype funcname rest]} {
290 regsub {^SQLITE_API } $line {} line
291 regsub {^SQLITE_API } $rettype {} rettype
293 # Add the SQLITE_PRIVATE or SQLITE_API keyword before functions.
294 # so that linkage can be modified at compile-time.
295 if {[regexp {^sqlite3[a-z]*_} $funcname]} {
296 set line SQLITE_API
297 append line " " [string trim $rettype]
298 if {[string index $rettype end] ne "*"} {
299 append line " "
301 if {$useapicall} {
302 if {[lsearch -exact $cdecllist $funcname] >= 0} {
303 append line SQLITE_CDECL " "
304 } else {
305 append line SQLITE_APICALL " "
308 append line $funcname $rest
309 if {$funcname=="sqlite3_sourceid"} {
310 # The sqlite3_sourceid() routine is synthesized at the end of
311 # the amalgamation
312 puts $out "/* $line */"
313 } else {
314 puts $out $line
316 } else {
317 puts $out "SQLITE_PRIVATE $line"
319 } elseif {[regexp $varpattern $line all varname]} {
320 # Add the SQLITE_PRIVATE before variable declarations or
321 # definitions for internal use
322 regsub {^SQLITE_API } $line {} line
323 if {![regexp {^sqlite3_} $varname]
324 && ![regexp {^sqlite3Show[A-Z]} $varname]} {
325 regsub {^extern } $line {} line
326 puts $out "SQLITE_PRIVATE $line"
327 } else {
328 if {[regexp {const char sqlite3_version\[\];} $line]} {
329 set line {const char sqlite3_version[] = SQLITE_VERSION;}
331 regsub {^SQLITE_EXTERN } $line {} line
332 puts $out "SQLITE_API $line"
334 } elseif {[regexp {^(SQLITE_EXTERN )?void \(\*sqlite3IoTrace\)} $line]} {
335 regsub {^SQLITE_API } $line {} line
336 regsub {^SQLITE_EXTERN } $line {} line
337 puts $out $line
338 } elseif {[regexp {^void \(\*sqlite3Os} $line]} {
339 regsub {^SQLITE_API } $line {} line
340 puts $out "SQLITE_PRIVATE $line"
341 } else {
342 puts $out $line
344 } else {
345 puts $out $line
348 close $in
349 section_comment "End of $tail"
353 # Process the source files. Process files containing commonly
354 # used subroutines first in order to help the compiler find
355 # inlining opportunities.
357 set flist {
358 sqliteInt.h
359 os_common.h
360 ctime.c
362 global.c
363 status.c
364 date.c
365 os.c
367 fault.c
368 mem0.c
369 mem1.c
370 mem2.c
371 mem3.c
372 mem5.c
373 mutex.c
374 mutex_noop.c
375 mutex_unix.c
376 mutex_w32.c
377 malloc.c
378 printf.c
379 treeview.c
380 random.c
381 threads.c
382 utf.c
383 util.c
384 hash.c
385 opcodes.c
387 os_kv.c
388 os_unix.c
389 os_win.c
390 memdb.c
392 bitvec.c
393 pcache.c
394 pcache1.c
395 rowset.c
396 pager.c
397 wal.c
399 btmutex.c
400 btree.c
401 backup.c
403 vdbemem.c
404 vdbeaux.c
405 vdbeapi.c
406 vdbetrace.c
407 vdbe.c
408 vdbeblob.c
409 vdbesort.c
410 vdbevtab.c
411 memjournal.c
413 walker.c
414 resolve.c
415 expr.c
416 alter.c
417 analyze.c
418 attach.c
419 auth.c
420 build.c
421 callback.c
422 delete.c
423 func.c
424 fkey.c
425 insert.c
426 legacy.c
427 loadext.c
428 pragma.c
429 prepare.c
430 select.c
431 table.c
432 trigger.c
433 update.c
434 upsert.c
435 vacuum.c
436 vtab.c
437 wherecode.c
438 whereexpr.c
439 where.c
440 window.c
442 parse.c
444 tokenize.c
445 complete.c
447 main.c
448 notify.c
450 fts3.c
451 fts3_aux.c
452 fts3_expr.c
453 fts3_hash.c
454 fts3_porter.c
455 fts3_tokenizer.c
456 fts3_tokenizer1.c
457 fts3_tokenize_vtab.c
458 fts3_write.c
459 fts3_snippet.c
460 fts3_unicode.c
461 fts3_unicode2.c
463 json.c
464 rtree.c
465 icu.c
466 fts3_icu.c
467 sqlite3rbu.c
468 dbstat.c
469 dbpage.c
470 sqlite3session.c
471 fts5.c
472 stmt.c
474 if {$enable_recover} {
475 lappend flist sqlite3recover.c dbdata.c
477 foreach file $flist {
478 copy_file $srcdir/$file
481 puts $out \
482 "/* Return the source-id for this library */
483 SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }"
485 puts $out \
486 "/************************** End of sqlite3.c ******************************/"
488 close $out