mksqlite3c.tcl 14 KB

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