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