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