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