Get read-only SHM file tests passing on Win32.
[sqlite.git] / tool / mksqlite3c.tcl
blob8ea3e81c91c3d22cc8886587bbfc9c1ec6d04dd5
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 # These are the header files used by SQLite. The first time any of these
92 # files are seen in a #include statement in the C code, include the complete
93 # text of the file in-line. The file only needs to be included once.
95 foreach hdr {
96 btree.h
97 btreeInt.h
98 fts3.h
99 fts3Int.h
100 fts3_hash.h
101 fts3_tokenizer.h
102 hash.h
103 hwtime.h
104 keywordhash.h
105 msvc.h
106 mutex.h
107 opcodes.h
108 os_common.h
109 os_setup.h
110 os_win.h
111 os.h
112 pager.h
113 parse.h
114 pcache.h
115 pragma.h
116 rtree.h
117 sqlite3session.h
118 sqlite3.h
119 sqlite3ext.h
120 sqlite3rbu.h
121 sqliteicu.h
122 sqliteInt.h
123 sqliteLimit.h
124 vdbe.h
125 vdbeInt.h
126 vxworks.h
127 wal.h
128 whereInt.h
130 set available_hdr($hdr) 1
132 set available_hdr(sqliteInt.h) 0
133 set available_hdr(sqlite3session.h) 0
135 # These headers should be copied into the amalgamation without modifying any
136 # of their function declarations or definitions.
137 set varonly_hdr(sqlite3.h) 1
139 # These are the functions that accept a variable number of arguments. They
140 # always need to use the "cdecl" calling convention even when another calling
141 # convention (e.g. "stcall") is being used for the rest of the library.
142 set cdecllist {
143 sqlite3_config
144 sqlite3_db_config
145 sqlite3_log
146 sqlite3_mprintf
147 sqlite3_snprintf
148 sqlite3_test_control
149 sqlite3_vtab_config
152 # 78 stars used for comment formatting.
153 set s78 \
154 {*****************************************************************************}
156 # Insert a comment into the code
158 proc section_comment {text} {
159 global out s78
160 set n [string length $text]
161 set nstar [expr {60 - $n}]
162 set stars [string range $s78 0 $nstar]
163 puts $out "/************** $text $stars/"
166 # Read the source file named $filename and write it into the
167 # sqlite3.c output file. If any #include statements are seen,
168 # process them appropriately.
170 proc copy_file {filename} {
171 global seen_hdr available_hdr varonly_hdr cdecllist out
172 global addstatic linemacros useapicall
173 set ln 0
174 set tail [file tail $filename]
175 section_comment "Begin file $tail"
176 if {$linemacros} {puts $out "#line 1 \"$filename\""}
177 set in [open $filename r]
178 set varpattern {^[a-zA-Z][a-zA-Z_0-9 *]+(sqlite3[_a-zA-Z0-9]+)(\[|;| =)}
179 set declpattern {([a-zA-Z][a-zA-Z_0-9 ]+ \**)(sqlite3[_a-zA-Z0-9]+)(\(.*)}
180 if {[file extension $filename]==".h"} {
181 set declpattern " *$declpattern"
183 set declpattern ^$declpattern\$
184 while {![eof $in]} {
185 set line [gets $in]
186 incr ln
187 if {[regexp {^\s*#\s*include\s+["<]([^">]+)[">]} $line all hdr]} {
188 if {[info exists available_hdr($hdr)]} {
189 if {$available_hdr($hdr)} {
190 if {$hdr!="os_common.h" && $hdr!="hwtime.h"} {
191 set available_hdr($hdr) 0
193 section_comment "Include $hdr in the middle of $tail"
194 copy_file tsrc/$hdr
195 section_comment "Continuing where we left off in $tail"
196 if {$linemacros} {puts $out "#line [expr {$ln+1}] \"$filename\""}
197 } else {
198 # Comment out the entire line, replacing any nested comment
199 # begin/end markers with the harmless substring "**".
200 puts $out "/* [string map [list /* ** */ **] $line] */"
202 } elseif {![info exists seen_hdr($hdr)]} {
203 if {![regexp {/\*\s+amalgamator:\s+dontcache\s+\*/} $line]} {
204 set seen_hdr($hdr) 1
206 puts $out $line
207 } elseif {[regexp {/\*\s+amalgamator:\s+keep\s+\*/} $line]} {
208 # This include file must be kept because there was a "keep"
209 # directive inside of a line comment.
210 puts $out $line
211 } else {
212 # Comment out the entire line, replacing any nested comment
213 # begin/end markers with the harmless substring "**".
214 puts $out "/* [string map [list /* ** */ **] $line] */"
216 } elseif {[regexp {^#ifdef __cplusplus} $line]} {
217 puts $out "#if 0"
218 } elseif {!$linemacros && [regexp {^#line} $line]} {
219 # Skip #line directives.
220 } elseif {$addstatic
221 && ![regexp {^(static|typedef|SQLITE_PRIVATE)} $line]} {
222 # Skip adding the SQLITE_PRIVATE or SQLITE_API keyword before
223 # functions if this header file does not need it.
224 if {![info exists varonly_hdr($tail)]
225 && [regexp $declpattern $line all rettype funcname rest]} {
226 regsub {^SQLITE_API } $line {} line
227 regsub {^SQLITE_API } $rettype {} rettype
229 # Add the SQLITE_PRIVATE or SQLITE_API keyword before functions.
230 # so that linkage can be modified at compile-time.
231 if {[regexp {^sqlite3[a-z]*_} $funcname]} {
232 set line SQLITE_API
233 append line " " [string trim $rettype]
234 if {[string index $rettype end] ne "*"} {
235 append line " "
237 if {$useapicall} {
238 if {[lsearch -exact $cdecllist $funcname] >= 0} {
239 append line SQLITE_CDECL " "
240 } else {
241 append line SQLITE_APICALL " "
244 append line $funcname $rest
245 if {$funcname=="sqlite3_sourceid" && !$linemacros} {
246 # The sqlite3_sourceid() routine is synthesized at the end of
247 # the amalgamation
248 puts $out "/* $line */"
249 } else {
250 puts $out $line
252 } else {
253 puts $out "SQLITE_PRIVATE $line"
255 } elseif {[regexp $varpattern $line all varname]} {
256 # Add the SQLITE_PRIVATE before variable declarations or
257 # definitions for internal use
258 regsub {^SQLITE_API } $line {} line
259 if {![regexp {^sqlite3_} $varname]} {
260 regsub {^extern } $line {} line
261 puts $out "SQLITE_PRIVATE $line"
262 } else {
263 if {[regexp {const char sqlite3_version\[\];} $line]} {
264 set line {const char sqlite3_version[] = SQLITE_VERSION;}
266 regsub {^SQLITE_EXTERN } $line {} line
267 puts $out "SQLITE_API $line"
269 } elseif {[regexp {^(SQLITE_EXTERN )?void \(\*sqlite3IoTrace\)} $line]} {
270 regsub {^SQLITE_API } $line {} line
271 regsub {^SQLITE_EXTERN } $line {} line
272 puts $out $line
273 } elseif {[regexp {^void \(\*sqlite3Os} $line]} {
274 regsub {^SQLITE_API } $line {} line
275 puts $out "SQLITE_PRIVATE $line"
276 } else {
277 puts $out $line
279 } else {
280 puts $out $line
283 close $in
284 section_comment "End of $tail"
288 # Process the source files. Process files containing commonly
289 # used subroutines first in order to help the compiler find
290 # inlining opportunities.
292 foreach file {
293 ctime.c
294 sqliteInt.h
296 global.c
297 status.c
298 date.c
299 os.c
301 fault.c
302 mem0.c
303 mem1.c
304 mem2.c
305 mem3.c
306 mem5.c
307 mutex.c
308 mutex_noop.c
309 mutex_unix.c
310 mutex_w32.c
311 malloc.c
312 printf.c
313 treeview.c
314 random.c
315 threads.c
316 utf.c
317 util.c
318 hash.c
319 opcodes.c
321 os_unix.c
322 os_win.c
324 bitvec.c
325 pcache.c
326 pcache1.c
327 rowset.c
328 pager.c
329 wal.c
331 btmutex.c
332 btree.c
333 backup.c
335 vdbemem.c
336 vdbeaux.c
337 vdbeapi.c
338 vdbetrace.c
339 vdbe.c
340 vdbeblob.c
341 vdbesort.c
342 memjournal.c
344 walker.c
345 resolve.c
346 expr.c
347 alter.c
348 analyze.c
349 attach.c
350 auth.c
351 build.c
352 callback.c
353 delete.c
354 func.c
355 fkey.c
356 insert.c
357 legacy.c
358 loadext.c
359 pragma.c
360 prepare.c
361 select.c
362 table.c
363 trigger.c
364 update.c
365 vacuum.c
366 vtab.c
367 wherecode.c
368 whereexpr.c
369 where.c
371 parse.c
373 tokenize.c
374 complete.c
376 main.c
377 notify.c
379 fts3.c
380 fts3_aux.c
381 fts3_expr.c
382 fts3_hash.c
383 fts3_porter.c
384 fts3_tokenizer.c
385 fts3_tokenizer1.c
386 fts3_tokenize_vtab.c
387 fts3_write.c
388 fts3_snippet.c
389 fts3_unicode.c
390 fts3_unicode2.c
392 rtree.c
393 icu.c
394 fts3_icu.c
395 sqlite3rbu.c
396 dbstat.c
397 dbpage.c
398 sqlite3session.c
399 json1.c
400 fts5.c
401 stmt.c
403 copy_file tsrc/$file
406 # Synthesize an alternative sqlite3_sourceid() implementation that
407 # that tries to detects changes in the amalgamation source text
408 # and modify returns a modified source-id if changes are detected.
410 # The only detection mechanism we have is the __LINE__ macro. So only
411 # edits that changes the number of lines of source code are detected.
413 if {!$linemacros} {
414 flush $out
415 set in2 [open sqlite3.c]
416 set cnt 0
417 set oldsrcid {}
418 while {![eof $in2]} {
419 incr cnt
420 gets $in2 line
421 if {[regexp {^#define SQLITE_SOURCE_ID } $line]} {set oldsrcid $line}
423 close $in2
424 regsub {[0-9a-flt]{4}"} $oldsrcid {alt2"} oldsrcid
425 puts $out \
426 "#if __LINE__!=[expr {$cnt+0}]
427 #undef SQLITE_SOURCE_ID
428 $oldsrcid
429 #endif
430 /* Return the source-id for this library */
431 SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }"
433 puts $out \
434 "/************************** End of sqlite3.c ******************************/"
436 close $out