xref: /sqlite-3.40.0/tool/mksqlite3c.tcl (revision 2ca62cb1)
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   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
129} {
130  set available_hdr($hdr) 1
131}
132set available_hdr(sqliteInt.h) 0
133set available_hdr(sqlite3session.h) 0
134
135# These headers should be copied into the amalgamation without modifying any
136# of their function declarations or definitions.
137set varonly_hdr(sqlite3.h) 1
138
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.
142set 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
150}
151
152# 78 stars used for comment formatting.
153set s78 \
154{*****************************************************************************}
155
156# Insert a comment into the code
157#
158proc 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/"
164}
165
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.
169#
170proc 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"
182  }
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
192          }
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] */"
201        }
202      } elseif {![info exists seen_hdr($hdr)]} {
203        if {![regexp {/\*\s+amalgamator:\s+dontcache\s+\*/} $line]} {
204          set seen_hdr($hdr) 1
205        }
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] */"
215      }
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        # Add the SQLITE_PRIVATE or SQLITE_API keyword before functions.
228        # so that linkage can be modified at compile-time.
229        if {[regexp {^sqlite3[a-z]*_} $funcname]} {
230          set line SQLITE_API
231          append line " " [string trim $rettype]
232          if {[string index $rettype end] ne "*"} {
233            append line " "
234          }
235          if {$useapicall} {
236            if {[lsearch -exact $cdecllist $funcname] >= 0} {
237              append line SQLITE_CDECL " "
238            } else {
239              append line SQLITE_APICALL " "
240            }
241          }
242          append line $funcname $rest
243          puts $out $line
244        } else {
245          puts $out "SQLITE_PRIVATE $line"
246        }
247      } elseif {[regexp $varpattern $line all varname]} {
248          # Add the SQLITE_PRIVATE before variable declarations or
249          # definitions for internal use
250          regsub {^SQLITE_API } $line {} line
251          if {![regexp {^sqlite3_} $varname]} {
252            regsub {^extern } $line {} line
253            puts $out "SQLITE_PRIVATE $line"
254          } else {
255            if {[regexp {const char sqlite3_version\[\];} $line]} {
256              set line {const char sqlite3_version[] = SQLITE_VERSION;}
257            }
258            regsub {^SQLITE_EXTERN } $line {} line
259            puts $out "SQLITE_API $line"
260          }
261      } elseif {[regexp {^(SQLITE_EXTERN )?void \(\*sqlite3IoTrace\)} $line]} {
262        regsub {^SQLITE_API } $line {} line
263        regsub {^SQLITE_EXTERN } $line {} line
264        puts $out $line
265      } elseif {[regexp {^void \(\*sqlite3Os} $line]} {
266        regsub {^SQLITE_API } $line {} line
267        puts $out "SQLITE_PRIVATE $line"
268      } else {
269        puts $out $line
270      }
271    } else {
272      puts $out $line
273    }
274  }
275  close $in
276  section_comment "End of $tail"
277}
278
279
280# Process the source files.  Process files containing commonly
281# used subroutines first in order to help the compiler find
282# inlining opportunities.
283#
284foreach file {
285   ctime.c
286   sqliteInt.h
287
288   global.c
289   status.c
290   date.c
291   os.c
292
293   fault.c
294   mem0.c
295   mem1.c
296   mem2.c
297   mem3.c
298   mem5.c
299   mutex.c
300   mutex_noop.c
301   mutex_unix.c
302   mutex_w32.c
303   malloc.c
304   printf.c
305   treeview.c
306   random.c
307   threads.c
308   utf.c
309   util.c
310   hash.c
311   opcodes.c
312
313   os_unix.c
314   os_win.c
315
316   bitvec.c
317   pcache.c
318   pcache1.c
319   rowset.c
320   pager.c
321   wal.c
322
323   btmutex.c
324   btree.c
325   backup.c
326
327   vdbemem.c
328   vdbeaux.c
329   vdbeapi.c
330   vdbetrace.c
331   vdbe.c
332   vdbeblob.c
333   vdbesort.c
334   memjournal.c
335
336   walker.c
337   resolve.c
338   expr.c
339   alter.c
340   analyze.c
341   attach.c
342   auth.c
343   build.c
344   callback.c
345   delete.c
346   func.c
347   fkey.c
348   insert.c
349   legacy.c
350   loadext.c
351   pragma.c
352   prepare.c
353   select.c
354   table.c
355   trigger.c
356   update.c
357   vacuum.c
358   vtab.c
359   wherecode.c
360   whereexpr.c
361   where.c
362
363   parse.c
364
365   tokenize.c
366   complete.c
367
368   main.c
369   notify.c
370
371   fts3.c
372   fts3_aux.c
373   fts3_expr.c
374   fts3_hash.c
375   fts3_porter.c
376   fts3_tokenizer.c
377   fts3_tokenizer1.c
378   fts3_tokenize_vtab.c
379   fts3_write.c
380   fts3_snippet.c
381   fts3_unicode.c
382   fts3_unicode2.c
383
384   rtree.c
385   icu.c
386   fts3_icu.c
387   sqlite3rbu.c
388   dbstat.c
389   sqlite3session.c
390   json1.c
391   fts5.c
392   stmts.c
393} {
394  copy_file tsrc/$file
395}
396
397close $out
398