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-noext.tcl
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   btree.h
97   btreeInt.h
98   hash.h
99   hwtime.h
100   keywordhash.h
101   msvc.h
102   mutex.h
103   opcodes.h
104   os_common.h
105   os_setup.h
106   os_win.h
107   os.h
108   pager.h
109   parse.h
110   pcache.h
111   pragma.h
112   sqlite3.h
113   sqlite3ext.h
114   sqliteicu.h
115   sqliteInt.h
116   sqliteLimit.h
117   vdbe.h
118   vdbeInt.h
119   vxworks.h
120   wal.h
121   whereInt.h
122} {
123  set available_hdr($hdr) 1
124}
125set available_hdr(sqliteInt.h) 0
126
127# These headers should be copied into the amalgamation without modifying any
128# of their function declarations or definitions.
129set varonly_hdr(sqlite3.h) 1
130
131# These are the functions that accept a variable number of arguments.  They
132# always need to use the "cdecl" calling convention even when another calling
133# convention (e.g. "stcall") is being used for the rest of the library.
134set cdecllist {
135  sqlite3_config
136  sqlite3_db_config
137  sqlite3_log
138  sqlite3_mprintf
139  sqlite3_snprintf
140  sqlite3_test_control
141  sqlite3_vtab_config
142}
143
144# 78 stars used for comment formatting.
145set s78 \
146{*****************************************************************************}
147
148# Insert a comment into the code
149#
150proc section_comment {text} {
151  global out s78
152  set n [string length $text]
153  set nstar [expr {60 - $n}]
154  set stars [string range $s78 0 $nstar]
155  puts $out "/************** $text $stars/"
156}
157
158# Read the source file named $filename and write it into the
159# sqlite3.c output file.  If any #include statements are seen,
160# process them appropriately.
161#
162proc copy_file {filename} {
163  global seen_hdr available_hdr varonly_hdr cdecllist out
164  global addstatic linemacros useapicall
165  set ln 0
166  set tail [file tail $filename]
167  section_comment "Begin file $tail"
168  if {$linemacros} {puts $out "#line 1 \"$filename\""}
169  set in [open $filename r]
170  set varpattern {^[a-zA-Z][a-zA-Z_0-9 *]+(sqlite3[_a-zA-Z0-9]+)(\[|;| =)}
171  set declpattern {([a-zA-Z][a-zA-Z_0-9 ]+ \**)(sqlite3[_a-zA-Z0-9]+)(\(.*)}
172  if {[file extension $filename]==".h"} {
173    set declpattern " *$declpattern"
174  }
175  set declpattern ^$declpattern\$
176  while {![eof $in]} {
177    set line [gets $in]
178    incr ln
179    if {[regexp {^\s*#\s*include\s+["<]([^">]+)[">]} $line all hdr]} {
180      if {[info exists available_hdr($hdr)]} {
181        if {$available_hdr($hdr)} {
182          if {$hdr!="os_common.h" && $hdr!="hwtime.h"} {
183            set available_hdr($hdr) 0
184          }
185          section_comment "Include $hdr in the middle of $tail"
186          copy_file tsrc/$hdr
187          section_comment "Continuing where we left off in $tail"
188          if {$linemacros} {puts $out "#line [expr {$ln+1}] \"$filename\""}
189        } else {
190          # Comment out the entire line, replacing any nested comment
191          # begin/end markers with the harmless substring "**".
192          puts $out "/* [string map [list /* ** */ **] $line] */"
193        }
194      } elseif {![info exists seen_hdr($hdr)]} {
195        if {![regexp {/\*\s+amalgamator:\s+dontcache\s+\*/} $line]} {
196          set seen_hdr($hdr) 1
197        }
198        puts $out $line
199      } elseif {[regexp {/\*\s+amalgamator:\s+keep\s+\*/} $line]} {
200        # This include file must be kept because there was a "keep"
201        # directive inside of a line comment.
202        puts $out $line
203      } else {
204        # Comment out the entire line, replacing any nested comment
205        # begin/end markers with the harmless substring "**".
206        puts $out "/* [string map [list /* ** */ **] $line] */"
207      }
208    } elseif {[regexp {^#ifdef __cplusplus} $line]} {
209      puts $out "#if 0"
210    } elseif {!$linemacros && [regexp {^#line} $line]} {
211      # Skip #line directives.
212    } elseif {$addstatic
213               && ![regexp {^(static|typedef|SQLITE_PRIVATE)} $line]} {
214      # Skip adding the SQLITE_PRIVATE or SQLITE_API keyword before
215      # functions if this header file does not need it.
216      if {![info exists varonly_hdr($tail)]
217       && [regexp $declpattern $line all rettype funcname rest]} {
218        regsub {^SQLITE_API } $line {} line
219        # Add the SQLITE_PRIVATE or SQLITE_API keyword before functions.
220        # so that linkage can be modified at compile-time.
221        if {[regexp {^sqlite3[a-z]*_} $funcname]} {
222          set line SQLITE_API
223          append line " " [string trim $rettype]
224          if {[string index $rettype end] ne "*"} {
225            append line " "
226          }
227          if {$useapicall} {
228            if {[lsearch -exact $cdecllist $funcname] >= 0} {
229              append line SQLITE_CDECL " "
230            } else {
231              append line SQLITE_APICALL " "
232            }
233          }
234          append line $funcname $rest
235          puts $out $line
236        } else {
237          puts $out "SQLITE_PRIVATE $line"
238        }
239      } elseif {[regexp $varpattern $line all varname]} {
240          # Add the SQLITE_PRIVATE before variable declarations or
241          # definitions for internal use
242          regsub {^SQLITE_API } $line {} line
243          if {![regexp {^sqlite3_} $varname]} {
244            regsub {^extern } $line {} line
245            puts $out "SQLITE_PRIVATE $line"
246          } else {
247            if {[regexp {const char sqlite3_version\[\];} $line]} {
248              set line {const char sqlite3_version[] = SQLITE_VERSION;}
249            }
250            regsub {^SQLITE_EXTERN } $line {} line
251            puts $out "SQLITE_API $line"
252          }
253      } elseif {[regexp {^(SQLITE_EXTERN )?void \(\*sqlite3IoTrace\)} $line]} {
254        regsub {^SQLITE_API } $line {} line
255        regsub {^SQLITE_EXTERN } $line {} line
256        puts $out $line
257      } elseif {[regexp {^void \(\*sqlite3Os} $line]} {
258        regsub {^SQLITE_API } $line {} line
259        puts $out "SQLITE_PRIVATE $line"
260      } else {
261        puts $out $line
262      }
263    } else {
264      puts $out $line
265    }
266  }
267  close $in
268  section_comment "End of $tail"
269}
270
271
272# Process the source files.  Process files containing commonly
273# used subroutines first in order to help the compiler find
274# inlining opportunities.
275#
276foreach file {
277   sqliteInt.h
278
279   global.c
280   ctime.c
281   status.c
282   date.c
283   os.c
284
285   fault.c
286   mem0.c
287   mem1.c
288   mem2.c
289   mem3.c
290   mem5.c
291   mutex.c
292   mutex_noop.c
293   mutex_unix.c
294   mutex_w32.c
295   malloc.c
296   printf.c
297   treeview.c
298   random.c
299   threads.c
300   utf.c
301   util.c
302   hash.c
303   opcodes.c
304
305   os_unix.c
306   os_win.c
307
308   bitvec.c
309   pcache.c
310   pcache1.c
311   rowset.c
312   pager.c
313   wal.c
314
315   btmutex.c
316   btree.c
317   backup.c
318
319   vdbemem.c
320   vdbeaux.c
321   vdbeapi.c
322   vdbetrace.c
323   vdbe.c
324   vdbeblob.c
325   vdbesort.c
326   memjournal.c
327
328   walker.c
329   resolve.c
330   expr.c
331   alter.c
332   analyze.c
333   attach.c
334   auth.c
335   build.c
336   callback.c
337   delete.c
338   func.c
339   fkey.c
340   insert.c
341   legacy.c
342   loadext.c
343   pragma.c
344   prepare.c
345   select.c
346   table.c
347   trigger.c
348   update.c
349   vacuum.c
350   vtab.c
351   wherecode.c
352   whereexpr.c
353   where.c
354   window.c
355
356   parse.c
357
358   tokenize.c
359   complete.c
360
361   main.c
362   notify.c
363} {
364  copy_file tsrc/$file
365}
366
367close $out
368