1#!/usr/bin/tclsh
2#
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
6#
7#      make target_source
8#
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".
16#
17# After the "tsrc" directory has been created and populated, run
18# this script:
19#
20#      tclsh mksqlite3c.tcl --srcdir $SRC
21#
22# The amalgamated SQLite code will be written into sqlite3.c
23#
24
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.
28#
29set addstatic 1
30set linemacros 0
31set useapicall 0
32for {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"
42  }
43}
44set in [open tsrc/sqlite3.h]
45set cnt 0
46set VERSION ?????
47while {![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
52}
53close $in
54
55# Open the output file and write a header comment at the beginning
56# of the file.
57#
58set out [open sqlite3.c w]
59# Force the output to use unix line endings, even on Windows.
60fconfigure $out -translation lf
61set today [clock format [clock seconds] -format "%Y-%m-%d %H:%M:%S UTC" -gmt 1]
62puts $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.
71**
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.
81*/
82#define SQLITE_CORE 1
83#define SQLITE_AMALGAMATION 1}]
84if {$addstatic} {
85  puts $out \
86{#ifndef SQLITE_PRIVATE
87# define SQLITE_PRIVATE static
88#endif}
89}
90
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.
94#
95foreach hdr {
96   crypto.h
97   sqlcipher.h
98   btree.h
99   btreeInt.h
100   fts3.h
101   fts3Int.h
102   fts3_hash.h
103   fts3_tokenizer.h
104   hash.h
105   hwtime.h
106   keywordhash.h
107   msvc.h
108   mutex.h
109   opcodes.h
110   os_common.h
111   os_setup.h
112   os_win.h
113   os.h
114   pager.h
115   parse.h
116   pcache.h
117   pragma.h
118   rtree.h
119   sqlite3session.h
120   sqlite3.h
121   sqlite3ext.h
122   sqlite3rbu.h
123   sqliteicu.h
124   sqliteInt.h
125   sqliteLimit.h
126   vdbe.h
127   vdbeInt.h
128   vxworks.h
129   wal.h
130   whereInt.h
131} {
132  set available_hdr($hdr) 1
133}
134set available_hdr(sqliteInt.h) 0
135set available_hdr(sqlite3session.h) 0
136
137# These headers should be copied into the amalgamation without modifying any
138# of their function declarations or definitions.
139set varonly_hdr(sqlite3.h) 1
140
141# These are the functions that accept a variable number of arguments.  They
142# always need to use the "cdecl" calling convention even when another calling
143# convention (e.g. "stcall") is being used for the rest of the library.
144set cdecllist {
145  sqlite3_config
146  sqlite3_db_config
147  sqlite3_log
148  sqlite3_mprintf
149  sqlite3_snprintf
150  sqlite3_test_control
151  sqlite3_vtab_config
152}
153
154# 78 stars used for comment formatting.
155set s78 \
156{*****************************************************************************}
157
158# Insert a comment into the code
159#
160proc section_comment {text} {
161  global out s78
162  set n [string length $text]
163  set nstar [expr {60 - $n}]
164  set stars [string range $s78 0 $nstar]
165  puts $out "/************** $text $stars/"
166}
167
168# Read the source file named $filename and write it into the
169# sqlite3.c output file.  If any #include statements are seen,
170# process them appropriately.
171#
172proc copy_file {filename} {
173  global seen_hdr available_hdr varonly_hdr cdecllist out
174  global addstatic linemacros useapicall
175  set ln 0
176  set tail [file tail $filename]
177  section_comment "Begin file $tail"
178  if {$linemacros} {puts $out "#line 1 \"$filename\""}
179  set in [open $filename r]
180  set varpattern {^[a-zA-Z][a-zA-Z_0-9 *]+(sqlite3[_a-zA-Z0-9]+)(\[|;| =)}
181  set declpattern {([a-zA-Z][a-zA-Z_0-9 ]+ \**)(sqlite3[_a-zA-Z0-9]+)(\(.*)}
182  if {[file extension $filename]==".h"} {
183    set declpattern " *$declpattern"
184  }
185  set declpattern ^$declpattern\$
186  while {![eof $in]} {
187    set line [gets $in]
188    incr ln
189    if {[regexp {^\s*#\s*include\s+["<]([^">]+)[">]} $line all hdr]} {
190      if {[info exists available_hdr($hdr)]} {
191        if {$available_hdr($hdr)} {
192          if {$hdr!="os_common.h" && $hdr!="hwtime.h"} {
193            set available_hdr($hdr) 0
194          }
195          section_comment "Include $hdr in the middle of $tail"
196          copy_file tsrc/$hdr
197          section_comment "Continuing where we left off in $tail"
198          if {$linemacros} {puts $out "#line [expr {$ln+1}] \"$filename\""}
199        } else {
200          # Comment out the entire line, replacing any nested comment
201          # begin/end markers with the harmless substring "**".
202          puts $out "/* [string map [list /* ** */ **] $line] */"
203        }
204      } elseif {![info exists seen_hdr($hdr)]} {
205        if {![regexp {/\*\s+amalgamator:\s+dontcache\s+\*/} $line]} {
206          set seen_hdr($hdr) 1
207        }
208        puts $out $line
209      } elseif {[regexp {/\*\s+amalgamator:\s+keep\s+\*/} $line]} {
210        # This include file must be kept because there was a "keep"
211        # directive inside of a line comment.
212        puts $out $line
213      } else {
214        # Comment out the entire line, replacing any nested comment
215        # begin/end markers with the harmless substring "**".
216        puts $out "/* [string map [list /* ** */ **] $line] */"
217      }
218    } elseif {[regexp {^#ifdef __cplusplus} $line]} {
219      puts $out "#if 0"
220    } elseif {!$linemacros && [regexp {^#line} $line]} {
221      # Skip #line directives.
222    } elseif {$addstatic
223               && ![regexp {^(static|typedef|SQLITE_PRIVATE)} $line]} {
224      # Skip adding the SQLITE_PRIVATE or SQLITE_API keyword before
225      # functions if this header file does not need it.
226      if {![info exists varonly_hdr($tail)]
227       && [regexp $declpattern $line all rettype funcname rest]} {
228        regsub {^SQLITE_API } $line {} line
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 " "
236          }
237          if {$useapicall} {
238            if {[lsearch -exact $cdecllist $funcname] >= 0} {
239              append line SQLITE_CDECL " "
240            } else {
241              append line SQLITE_APICALL " "
242            }
243          }
244          append line $funcname $rest
245          puts $out $line
246        } else {
247          puts $out "SQLITE_PRIVATE $line"
248        }
249      } elseif {[regexp $varpattern $line all varname]} {
250          # Add the SQLITE_PRIVATE before variable declarations or
251          # definitions for internal use
252          regsub {^SQLITE_API } $line {} line
253          if {![regexp {^sqlite3_} $varname]} {
254            regsub {^extern } $line {} line
255            puts $out "SQLITE_PRIVATE $line"
256          } else {
257            if {[regexp {const char sqlite3_version\[\];} $line]} {
258              set line {const char sqlite3_version[] = SQLITE_VERSION;}
259            }
260            regsub {^SQLITE_EXTERN } $line {} line
261            puts $out "SQLITE_API $line"
262          }
263      } elseif {[regexp {^(SQLITE_EXTERN )?void \(\*sqlite3IoTrace\)} $line]} {
264        regsub {^SQLITE_API } $line {} line
265        regsub {^SQLITE_EXTERN } $line {} line
266        puts $out $line
267      } elseif {[regexp {^void \(\*sqlite3Os} $line]} {
268        regsub {^SQLITE_API } $line {} line
269        puts $out "SQLITE_PRIVATE $line"
270      } else {
271        puts $out $line
272      }
273    } else {
274      puts $out $line
275    }
276  }
277  close $in
278  section_comment "End of $tail"
279}
280
281
282# Process the source files.  Process files containing commonly
283# used subroutines first in order to help the compiler find
284# inlining opportunities.
285#
286
287foreach file {
288   ctime.c
289   sqliteInt.h
290
291   crypto.c
292   crypto_impl.c
293   crypto_libtomcrypt.c
294   crypto_openssl.c
295   crypto_cc.c
296
297   global.c
298   status.c
299   date.c
300   os.c
301
302   fault.c
303   mem0.c
304   mem1.c
305   mem2.c
306   mem3.c
307   mem5.c
308   mutex.c
309   mutex_noop.c
310   mutex_unix.c
311   mutex_w32.c
312   malloc.c
313   printf.c
314   treeview.c
315   random.c
316   threads.c
317   utf.c
318   util.c
319   hash.c
320   opcodes.c
321
322   os_unix.c
323   os_win.c
324
325   bitvec.c
326   pcache.c
327   pcache1.c
328   rowset.c
329   pager.c
330   wal.c
331
332   btmutex.c
333   btree.c
334   backup.c
335
336   vdbemem.c
337   vdbeaux.c
338   vdbeapi.c
339   vdbetrace.c
340   vdbe.c
341   vdbeblob.c
342   vdbesort.c
343   memjournal.c
344
345   walker.c
346   resolve.c
347   expr.c
348   alter.c
349   analyze.c
350   attach.c
351   auth.c
352   build.c
353   callback.c
354   delete.c
355   func.c
356   fkey.c
357   insert.c
358   legacy.c
359   loadext.c
360   pragma.c
361   prepare.c
362   select.c
363   table.c
364   trigger.c
365   update.c
366   vacuum.c
367   vtab.c
368   wherecode.c
369   whereexpr.c
370   where.c
371
372   parse.c
373
374   tokenize.c
375   complete.c
376
377   main.c
378   notify.c
379
380   fts3.c
381   fts3_aux.c
382   fts3_expr.c
383   fts3_hash.c
384   fts3_porter.c
385   fts3_tokenizer.c
386   fts3_tokenizer1.c
387   fts3_tokenize_vtab.c
388   fts3_write.c
389   fts3_snippet.c
390   fts3_unicode.c
391   fts3_unicode2.c
392
393   rtree.c
394   icu.c
395
396   fts3_icu.c
397   sqlite3rbu.c
398   dbstat.c
399   sqlite3session.c
400   json1.c
401   fts5.c
402   stmt.c
403} {
404  copy_file tsrc/$file
405}
406
407close $out
408