mirror of
https://github.com/glebarez/go-sqlite.git
synced 2025-10-04 23:42:40 +08:00
switch windows to CRT, throw out old virtual
This commit is contained in:
@@ -1,494 +0,0 @@
|
|||||||
// Copyright 2017 The Sqlite Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package sqlite
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"database/sql"
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
"path/filepath"
|
|
||||||
"runtime"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/cznic/virtual"
|
|
||||||
)
|
|
||||||
|
|
||||||
func caller(s string, va ...interface{}) {
|
|
||||||
if s == "" {
|
|
||||||
s = strings.Repeat("%v ", len(va))
|
|
||||||
}
|
|
||||||
_, fn, fl, _ := runtime.Caller(2)
|
|
||||||
fmt.Fprintf(os.Stderr, "# caller: %s:%d: ", path.Base(fn), fl)
|
|
||||||
fmt.Fprintf(os.Stderr, s, va...)
|
|
||||||
fmt.Fprintln(os.Stderr)
|
|
||||||
_, fn, fl, _ = runtime.Caller(1)
|
|
||||||
fmt.Fprintf(os.Stderr, "# \tcallee: %s:%d: ", path.Base(fn), fl)
|
|
||||||
fmt.Fprintln(os.Stderr)
|
|
||||||
os.Stderr.Sync()
|
|
||||||
}
|
|
||||||
|
|
||||||
func dbg(s string, va ...interface{}) {
|
|
||||||
if s == "" {
|
|
||||||
s = strings.Repeat("%v ", len(va))
|
|
||||||
}
|
|
||||||
_, fn, fl, _ := runtime.Caller(1)
|
|
||||||
fmt.Fprintf(os.Stderr, "# dbg %s:%d: ", path.Base(fn), fl)
|
|
||||||
fmt.Fprintf(os.Stderr, s, va...)
|
|
||||||
fmt.Fprintln(os.Stderr)
|
|
||||||
os.Stderr.Sync()
|
|
||||||
}
|
|
||||||
|
|
||||||
func TODO(...interface{}) string { //TODOOK
|
|
||||||
_, fn, fl, _ := runtime.Caller(1)
|
|
||||||
return fmt.Sprintf("# TODO: %s:%d:\n", path.Base(fn), fl) //TODOOK
|
|
||||||
}
|
|
||||||
|
|
||||||
func use(...interface{}) {}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
use(caller, dbg, TODO) //TODOOK
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
var (
|
|
||||||
// Add "-tags virtual.profile" to the command.
|
|
||||||
profileAll = flag.Bool("profile", false, "")
|
|
||||||
profileFunctions = flag.Bool("profile_functions", false, "")
|
|
||||||
profileInstructions = flag.Bool("profile_instructions", false, "")
|
|
||||||
profileLines = flag.Bool("profile_lines", false, "")
|
|
||||||
profileRate = flag.Int("profile_rate", 1000, "")
|
|
||||||
recsPerSec = flag.Bool("recs_per_sec_as_mbps", false, "Show records per second as MB/s.")
|
|
||||||
)
|
|
||||||
|
|
||||||
func tempDB(t testing.TB) (string, *sql.DB) {
|
|
||||||
dir, err := ioutil.TempDir("", "sqlite-test-")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
db, err := sql.Open(driverName, filepath.Join(dir, "tmp.db"))
|
|
||||||
if err != nil {
|
|
||||||
os.RemoveAll(dir)
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return dir, db
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestScalar(t *testing.T) {
|
|
||||||
dir, db := tempDB(t)
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
db.Close()
|
|
||||||
os.RemoveAll(dir)
|
|
||||||
}()
|
|
||||||
|
|
||||||
t1 := time.Date(2017, 4, 20, 1, 2, 3, 56789, time.UTC)
|
|
||||||
t2 := time.Date(2018, 5, 21, 2, 3, 4, 98765, time.UTC)
|
|
||||||
r, err := db.Exec(`
|
|
||||||
create table t(i int, f double, b bool, s text, t time);
|
|
||||||
insert into t values(12, 3.14, ?, "foo", ?), (34, 2.78, ?, "bar", ?);
|
|
||||||
`,
|
|
||||||
true, t1,
|
|
||||||
false, t2,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
n, err := r.RowsAffected()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if g, e := n, int64(2); g != e {
|
|
||||||
t.Fatal(g, e)
|
|
||||||
}
|
|
||||||
|
|
||||||
rows, err := db.Query("select * from t")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
type rec struct {
|
|
||||||
i int
|
|
||||||
f float64
|
|
||||||
b bool
|
|
||||||
s string
|
|
||||||
t string
|
|
||||||
}
|
|
||||||
var a []rec
|
|
||||||
for rows.Next() {
|
|
||||||
var r rec
|
|
||||||
if err := rows.Scan(&r.i, &r.f, &r.b, &r.s, &r.t); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
a = append(a, r)
|
|
||||||
}
|
|
||||||
if err := rows.Err(); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if g, e := len(a), 2; g != e {
|
|
||||||
t.Fatal(g, e)
|
|
||||||
}
|
|
||||||
|
|
||||||
if g, e := a[0], (rec{12, 3.14, true, "foo", t1.String()}); g != e {
|
|
||||||
t.Fatal(g, e)
|
|
||||||
}
|
|
||||||
|
|
||||||
if g, e := a[1], (rec{34, 2.78, false, "bar", t2.String()}); g != e {
|
|
||||||
t.Fatal(g, e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBlob(t *testing.T) {
|
|
||||||
dir, db := tempDB(t)
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
db.Close()
|
|
||||||
os.RemoveAll(dir)
|
|
||||||
}()
|
|
||||||
|
|
||||||
b1 := []byte(time.Now().String())
|
|
||||||
b2 := []byte("\x00foo\x00bar\x00")
|
|
||||||
if _, err := db.Exec(`
|
|
||||||
create table t(b blob);
|
|
||||||
insert into t values(?), (?);
|
|
||||||
`, b1, b2,
|
|
||||||
); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
rows, err := db.Query("select * from t")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
type rec struct {
|
|
||||||
b []byte
|
|
||||||
}
|
|
||||||
var a []rec
|
|
||||||
for rows.Next() {
|
|
||||||
var r rec
|
|
||||||
if err := rows.Scan(&r.b); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
a = append(a, r)
|
|
||||||
}
|
|
||||||
if err := rows.Err(); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if g, e := len(a), 2; g != e {
|
|
||||||
t.Fatal(g, e)
|
|
||||||
}
|
|
||||||
|
|
||||||
if g, e := a[0].b, b1; !bytes.Equal(g, e) {
|
|
||||||
t.Fatal(g, e)
|
|
||||||
}
|
|
||||||
|
|
||||||
if g, e := a[1].b, b2; !bytes.Equal(g, e) {
|
|
||||||
t.Fatal(g, e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func profile(t testing.TB, d time.Duration, w io.Writer, format string, arg ...interface{}) {
|
|
||||||
rate := vm.ProfileRate
|
|
||||||
if rate == 0 {
|
|
||||||
rate = 1
|
|
||||||
}
|
|
||||||
if len(vm.ProfileFunctions)+len(vm.ProfileLines)+len(vm.ProfileInstructions) != 0 {
|
|
||||||
fmt.Fprintf(w, "# %v\n", os.Args[1:])
|
|
||||||
}
|
|
||||||
if len(vm.ProfileFunctions) != 0 {
|
|
||||||
fmt.Fprintf(w, format, arg...)
|
|
||||||
type u struct {
|
|
||||||
virtual.PCInfo
|
|
||||||
n int
|
|
||||||
}
|
|
||||||
var s int64
|
|
||||||
var a []u
|
|
||||||
var wi int
|
|
||||||
for k, v := range vm.ProfileFunctions {
|
|
||||||
a = append(a, u{k, v})
|
|
||||||
s += int64(v)
|
|
||||||
if n := len(k.Name.String()); n > wi {
|
|
||||||
wi = n
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sort.Slice(a, func(i, j int) bool {
|
|
||||||
if a[i].n < a[j].n {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
if a[i].n > a[j].n {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return a[i].Name < a[j].Name
|
|
||||||
})
|
|
||||||
fmt.Fprintf(w, "---- Profile functions, %v samples in %v, %.3f MIPS, %v/sample\n", s, d, float64(s)/1e6*float64(rate)*float64(time.Second)/float64(d), time.Duration(float64(d)/float64(s)))
|
|
||||||
if x, ok := t.(*testing.B); ok {
|
|
||||||
fmt.Fprintf(w, "\t%v samples/1 [samples/b.N]\n", s/int64(x.N))
|
|
||||||
}
|
|
||||||
var c int64
|
|
||||||
for i := len(a) - 1; i >= 0; i-- {
|
|
||||||
c += int64(a[i].n)
|
|
||||||
fmt.Fprintf(
|
|
||||||
w,
|
|
||||||
"%*v\t%10v%10.2f%%%10.2f%%\n",
|
|
||||||
-wi, a[i].Name, a[i].n,
|
|
||||||
100*float64(a[i].n)/float64(s),
|
|
||||||
100*float64(c)/float64(s),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(vm.ProfileLines) != 0 {
|
|
||||||
fmt.Fprintf(w, format, arg...)
|
|
||||||
type u struct {
|
|
||||||
virtual.PCInfo
|
|
||||||
n int
|
|
||||||
}
|
|
||||||
var s int64
|
|
||||||
var a []u
|
|
||||||
for k, v := range vm.ProfileLines {
|
|
||||||
a = append(a, u{k, v})
|
|
||||||
s += int64(v)
|
|
||||||
}
|
|
||||||
sort.Slice(a, func(i, j int) bool {
|
|
||||||
if a[i].n < a[j].n {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
if a[i].n > a[j].n {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if a[i].Name < a[j].Name {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
if a[i].Name > a[j].Name {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return a[i].Line < a[j].Line
|
|
||||||
})
|
|
||||||
fmt.Fprintf(w, "---- Profile lines, %v samples in %v, %.3f MIPS, %v/sample\n", s, d, float64(s)/1e6*float64(rate)*float64(time.Second)/float64(d), time.Duration(float64(d)/float64(s)))
|
|
||||||
if x, ok := t.(*testing.B); ok {
|
|
||||||
fmt.Fprintf(w, "\t%v samples/1 [samples/b.N]\n", s/int64(x.N))
|
|
||||||
}
|
|
||||||
var c int64
|
|
||||||
for i := len(a) - 1; i >= 0; i-- {
|
|
||||||
c += int64(a[i].n)
|
|
||||||
fmt.Fprintf(
|
|
||||||
w,
|
|
||||||
"%v:%v:\t%10v%10.2f%%%10.2f%%\n",
|
|
||||||
a[i].Name, a[i].Line, a[i].n,
|
|
||||||
100*float64(a[i].n)/float64(s),
|
|
||||||
100*float64(c)/float64(s),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(vm.ProfileInstructions) != 0 {
|
|
||||||
fmt.Fprintf(w, format, arg...)
|
|
||||||
type u struct {
|
|
||||||
virtual.Opcode
|
|
||||||
n int
|
|
||||||
}
|
|
||||||
var s int64
|
|
||||||
var a []u
|
|
||||||
var wi int
|
|
||||||
for k, v := range vm.ProfileInstructions {
|
|
||||||
a = append(a, u{k, v})
|
|
||||||
s += int64(v)
|
|
||||||
if n := len(k.String()); n > wi {
|
|
||||||
wi = n
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sort.Slice(a, func(i, j int) bool {
|
|
||||||
if a[i].n < a[j].n {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
if a[i].n > a[j].n {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return a[i].Opcode < a[j].Opcode
|
|
||||||
})
|
|
||||||
fmt.Fprintf(w, "---- Profile instructions, %v samples in %v, %.3f MIPS, %v/sample\n", s, d, float64(s)/1e6*float64(rate)*float64(time.Second)/float64(d), time.Duration(float64(d)/float64(s)))
|
|
||||||
if x, ok := t.(*testing.B); ok {
|
|
||||||
fmt.Fprintf(w, "\t%v samples/1 [samples/b.N]\n", s/int64(x.N))
|
|
||||||
}
|
|
||||||
var c int64
|
|
||||||
for i := len(a) - 1; i >= 0; i-- {
|
|
||||||
c += int64(a[i].n)
|
|
||||||
fmt.Fprintf(
|
|
||||||
w,
|
|
||||||
"%*s%10v%10.2f%%\t%10.2f%%\n",
|
|
||||||
-wi, a[i].Opcode, a[i].n,
|
|
||||||
100*float64(a[i].n)/float64(s),
|
|
||||||
100*float64(c)/float64(s),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkInsertMemory(b *testing.B) {
|
|
||||||
db, err := sql.Open(driverName, "file::memory:")
|
|
||||||
if err != nil {
|
|
||||||
b.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
db.Close()
|
|
||||||
}()
|
|
||||||
|
|
||||||
if _, err := db.Exec(`
|
|
||||||
create table t(i int);
|
|
||||||
begin;
|
|
||||||
`); err != nil {
|
|
||||||
b.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
s, err := db.Prepare("insert into t values(?)")
|
|
||||||
if err != nil {
|
|
||||||
b.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if *profileAll || *profileFunctions {
|
|
||||||
vm.ProfileFunctions = map[virtual.PCInfo]int{}
|
|
||||||
}
|
|
||||||
if *profileAll || *profileLines {
|
|
||||||
vm.ProfileLines = map[virtual.PCInfo]int{}
|
|
||||||
}
|
|
||||||
if *profileAll || *profileInstructions {
|
|
||||||
vm.ProfileInstructions = map[virtual.Opcode]int{}
|
|
||||||
}
|
|
||||||
vm.ProfileRate = int(*profileRate)
|
|
||||||
t0 := time.Now()
|
|
||||||
b.ResetTimer()
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
if _, err := s.Exec(int64(i)); err != nil {
|
|
||||||
b.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
b.StopTimer()
|
|
||||||
if *recsPerSec {
|
|
||||||
b.SetBytes(1e6)
|
|
||||||
}
|
|
||||||
d := time.Since(t0)
|
|
||||||
if _, err := db.Exec(`commit;`); err != nil {
|
|
||||||
b.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
profile(b, d, os.Stderr, "==== BenchmarkInsertMemory b.N %v\n", b.N)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkNextMemory(b *testing.B) {
|
|
||||||
db, err := sql.Open(driverName, "file::memory:")
|
|
||||||
if err != nil {
|
|
||||||
b.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
db.Close()
|
|
||||||
}()
|
|
||||||
|
|
||||||
if _, err := db.Exec(`
|
|
||||||
create table t(i int);
|
|
||||||
begin;
|
|
||||||
`); err != nil {
|
|
||||||
b.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
s, err := db.Prepare("insert into t values(?)")
|
|
||||||
if err != nil {
|
|
||||||
b.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
defer s.Close()
|
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
if _, err := s.Exec(int64(i)); err != nil {
|
|
||||||
b.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if _, err := db.Exec("commit"); err != nil {
|
|
||||||
b.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
r, err := db.Query("select * from t")
|
|
||||||
if err != nil {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
defer r.Close()
|
|
||||||
|
|
||||||
if *profileAll || *profileFunctions {
|
|
||||||
vm.ProfileFunctions = map[virtual.PCInfo]int{}
|
|
||||||
}
|
|
||||||
if *profileAll || *profileLines {
|
|
||||||
vm.ProfileLines = map[virtual.PCInfo]int{}
|
|
||||||
}
|
|
||||||
if *profileAll || *profileInstructions {
|
|
||||||
vm.ProfileInstructions = map[virtual.Opcode]int{}
|
|
||||||
}
|
|
||||||
vm.ProfileRate = int(*profileRate)
|
|
||||||
t0 := time.Now()
|
|
||||||
b.ResetTimer()
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
if !r.Next() {
|
|
||||||
b.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
b.StopTimer()
|
|
||||||
if *recsPerSec {
|
|
||||||
b.SetBytes(1e6)
|
|
||||||
}
|
|
||||||
d := time.Since(t0)
|
|
||||||
profile(b, d, os.Stderr, "==== BenchmarkNextMemory b.N %v\n", b.N)
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://github.com/cznic/sqlite/issues/11
|
|
||||||
func TestIssue11(t *testing.T) {
|
|
||||||
const N = 6570
|
|
||||||
dir, db := tempDB(t)
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
db.Close()
|
|
||||||
os.RemoveAll(dir)
|
|
||||||
}()
|
|
||||||
|
|
||||||
if _, err := db.Exec(`
|
|
||||||
CREATE TABLE t1 (t INT);
|
|
||||||
BEGIN;
|
|
||||||
`,
|
|
||||||
); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < N; i++ {
|
|
||||||
if _, err := db.Exec("INSERT INTO t1 (t) VALUES (?)", i); err != nil {
|
|
||||||
t.Fatalf("#%v: %v", i, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if _, err := db.Exec("COMMIT;"); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,7 +0,0 @@
|
|||||||
// Copyright 2017 The Sqlite Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
//go:generate go run generator_windows.go
|
|
||||||
|
|
||||||
package sqlite
|
|
@@ -168,6 +168,7 @@ func build(predef string, tus [][]string, opts ...cc.Opt) ([]*cc.TranslationUnit
|
|||||||
cc.EnableEmptyStructs(),
|
cc.EnableEmptyStructs(),
|
||||||
cc.EnableImplicitFuncDef(),
|
cc.EnableImplicitFuncDef(),
|
||||||
cc.EnableNonConstStaticInitExpressions(),
|
cc.EnableNonConstStaticInitExpressions(),
|
||||||
|
cc.EnableWideBitFieldTypes(),
|
||||||
cc.ErrLimit(*errLimit),
|
cc.ErrLimit(*errLimit),
|
||||||
cc.SysIncludePaths([]string{ccir.LibcIncludePath}),
|
cc.SysIncludePaths([]string{ccir.LibcIncludePath}),
|
||||||
}, opts...)...,
|
}, opts...)...,
|
||||||
|
@@ -1,366 +0,0 @@
|
|||||||
// Copyright 2017 The Sqlite Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build ignore
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"compress/gzip"
|
|
||||||
"encoding/gob"
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"go/format"
|
|
||||||
"go/scanner"
|
|
||||||
"go/token"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"runtime"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"log"
|
|
||||||
|
|
||||||
"github.com/cznic/cc"
|
|
||||||
"github.com/cznic/ccir"
|
|
||||||
"github.com/cznic/internal/buffer"
|
|
||||||
"github.com/cznic/ir"
|
|
||||||
"github.com/cznic/strutil"
|
|
||||||
"github.com/cznic/virtual"
|
|
||||||
"github.com/cznic/xc"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
cpp = flag.Bool("cpp", false, "")
|
|
||||||
dict = xc.Dict
|
|
||||||
errLimit = flag.Int("errlimit", 10, "")
|
|
||||||
filter = flag.String("re", "", "")
|
|
||||||
ndebug = flag.Bool("ndebug", false, "")
|
|
||||||
noexec = flag.Bool("noexec", false, "")
|
|
||||||
oLog = flag.Bool("log", false, "")
|
|
||||||
trace = flag.Bool("trc", false, "")
|
|
||||||
yydebug = flag.Int("yydebug", 0, "")
|
|
||||||
)
|
|
||||||
|
|
||||||
func findRepo(s string) string {
|
|
||||||
s = filepath.FromSlash(s)
|
|
||||||
for _, v := range strings.Split(strutil.Gopath(), string(os.PathListSeparator)) {
|
|
||||||
p := filepath.Join(v, "src", s)
|
|
||||||
fi, err := os.Lstat(p)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if fi.IsDir() {
|
|
||||||
wd, err := os.Getwd()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if p, err = filepath.Rel(wd, p); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func errStr(err error) string {
|
|
||||||
switch x := err.(type) {
|
|
||||||
case scanner.ErrorList:
|
|
||||||
if len(x) != 1 {
|
|
||||||
x.RemoveMultiples()
|
|
||||||
}
|
|
||||||
var b bytes.Buffer
|
|
||||||
for i, v := range x {
|
|
||||||
if i != 0 {
|
|
||||||
b.WriteByte('\n')
|
|
||||||
}
|
|
||||||
b.WriteString(v.Error())
|
|
||||||
if i == 9 {
|
|
||||||
fmt.Fprintf(&b, "\n\t... and %v more errors", len(x)-10)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return b.String()
|
|
||||||
default:
|
|
||||||
return err.Error()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func build(predef string, tus [][]string, opts ...cc.Opt) ([]*cc.TranslationUnit, *virtual.Binary) {
|
|
||||||
var b buffer.Bytes
|
|
||||||
var lpos token.Position
|
|
||||||
if *cpp {
|
|
||||||
opts = append(opts, cc.Cpp(func(toks []xc.Token) {
|
|
||||||
if len(toks) != 0 {
|
|
||||||
p := toks[0].Position()
|
|
||||||
if p.Filename != lpos.Filename {
|
|
||||||
fmt.Fprintf(&b, "# %d %q\n", p.Line, p.Filename)
|
|
||||||
}
|
|
||||||
lpos = p
|
|
||||||
}
|
|
||||||
for _, v := range toks {
|
|
||||||
b.WriteString(cc.TokSrc(v))
|
|
||||||
}
|
|
||||||
b.WriteByte('\n')
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
ndbg := ""
|
|
||||||
if *ndebug {
|
|
||||||
ndbg = "#define NDEBUG 1"
|
|
||||||
}
|
|
||||||
var build [][]ir.Object
|
|
||||||
tus = append(tus, []string{ccir.CRT0Path})
|
|
||||||
var asta []*cc.TranslationUnit
|
|
||||||
for _, src := range tus {
|
|
||||||
model, err := ccir.NewModel()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
ast, err := cc.Parse(
|
|
||||||
fmt.Sprintf(`
|
|
||||||
%s
|
|
||||||
#define __arch__ %s
|
|
||||||
#define __os__ %s
|
|
||||||
#include <builtin.h>
|
|
||||||
%s
|
|
||||||
`, ndbg, runtime.GOARCH, runtime.GOOS, predef),
|
|
||||||
src,
|
|
||||||
model,
|
|
||||||
append([]cc.Opt{
|
|
||||||
cc.AllowCompatibleTypedefRedefinitions(),
|
|
||||||
cc.EnableImplicitFuncDef(),
|
|
||||||
cc.EnableNonConstStaticInitExpressions(),
|
|
||||||
cc.EnableWideBitFieldTypes(),
|
|
||||||
cc.ErrLimit(*errLimit),
|
|
||||||
cc.SysIncludePaths([]string{ccir.LibcIncludePath}),
|
|
||||||
}, opts...)...,
|
|
||||||
)
|
|
||||||
if s := b.Bytes(); len(s) != 0 {
|
|
||||||
log.Printf("\n%s", s)
|
|
||||||
b.Close()
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(errStr(err))
|
|
||||||
}
|
|
||||||
|
|
||||||
asta = append(asta, ast)
|
|
||||||
objs, err := ccir.New(ast)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if *oLog {
|
|
||||||
for i, v := range objs {
|
|
||||||
switch x := v.(type) {
|
|
||||||
case *ir.DataDefinition:
|
|
||||||
fmt.Fprintf(&b, "# [%v]: %T %v %v\n", i, x, x.ObjectBase, x.Value)
|
|
||||||
case *ir.FunctionDefinition:
|
|
||||||
fmt.Fprintf(&b, "# [%v]: %T %v %v\n", i, x, x.ObjectBase, x.Arguments)
|
|
||||||
for i, v := range x.Body {
|
|
||||||
fmt.Fprintf(&b, "%#05x\t%v\n", i, v)
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
log.Fatalf("[%v]: %T %v: %v", i, x, x, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for i, v := range objs {
|
|
||||||
if err := v.Verify(); err != nil {
|
|
||||||
switch x := v.(type) {
|
|
||||||
case *ir.FunctionDefinition:
|
|
||||||
fmt.Fprintf(&b, "# [%v, err]: %T %v %v\n", i, x, x.ObjectBase, x.Arguments)
|
|
||||||
for i, v := range x.Body {
|
|
||||||
fmt.Fprintf(&b, "%#05x\t%v\n", i, v)
|
|
||||||
}
|
|
||||||
log.Fatalf("# [%v]: Verify (A): %v\n%s", i, err, b.Bytes())
|
|
||||||
default:
|
|
||||||
log.Fatalf("[%v]: %T %v: %v", i, x, x, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
build = append(build, objs)
|
|
||||||
}
|
|
||||||
|
|
||||||
linked, err := ir.LinkMain(build...)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("ir.LinkMain: %s\n%s", err, b.Bytes())
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, v := range linked {
|
|
||||||
if err := v.Verify(); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bin, err := virtual.LoadMain(linked)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return asta, bin
|
|
||||||
}
|
|
||||||
|
|
||||||
func macros(buf io.Writer, ast *cc.TranslationUnit) {
|
|
||||||
var a []string
|
|
||||||
for k, v := range ast.Macros {
|
|
||||||
if v.Value != nil && v.Type.Kind() != cc.Bool {
|
|
||||||
switch fn := v.DefTok.Position().Filename; {
|
|
||||||
case
|
|
||||||
fn == "builtin.h",
|
|
||||||
fn == "<predefine>",
|
|
||||||
strings.HasPrefix(fn, "predefined_"):
|
|
||||||
// ignore
|
|
||||||
default:
|
|
||||||
a = append(a, string(dict.S(k)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sort.Strings(a)
|
|
||||||
for _, v := range a {
|
|
||||||
m := ast.Macros[dict.SID(v)]
|
|
||||||
if m.Value == nil {
|
|
||||||
log.Fatal("TODO")
|
|
||||||
}
|
|
||||||
|
|
||||||
switch t := m.Type; t.Kind() {
|
|
||||||
case
|
|
||||||
cc.Int, cc.UInt, cc.Long, cc.ULong, cc.LongLong, cc.ULongLong,
|
|
||||||
cc.Float, cc.LongDouble, cc.Bool:
|
|
||||||
fmt.Fprintf(buf, "X%s = %v\n", v, m.Value)
|
|
||||||
case cc.Ptr:
|
|
||||||
switch t := t.Element(); t.Kind() {
|
|
||||||
case cc.Char:
|
|
||||||
fmt.Fprintf(buf, "X%s = %q\n", v, dict.S(int(m.Value.(cc.StringLitID))))
|
|
||||||
default:
|
|
||||||
log.Fatalf("%v", t.Kind())
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
log.Fatalf("%v", t.Kind())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
a = a[:0]
|
|
||||||
for _, v := range ast.Declarations.Identifiers {
|
|
||||||
switch x := v.Node.(type) {
|
|
||||||
case *cc.DirectDeclarator:
|
|
||||||
d := x.TopDeclarator()
|
|
||||||
id, _ := d.Identifier()
|
|
||||||
if x.EnumVal == nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
a = append(a, string(dict.S(id)))
|
|
||||||
default:
|
|
||||||
log.Fatalf("%T", x)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sort.Strings(a)
|
|
||||||
for _, v := range a {
|
|
||||||
dd := ast.Declarations.Identifiers[dict.SID(v)].Node.(*cc.DirectDeclarator)
|
|
||||||
fmt.Fprintf(buf, "X%s = %v\n", v, dd.EnumVal)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
const repo = "sqlite.org/sqlite-amalgamation-3180000/"
|
|
||||||
|
|
||||||
log.SetFlags(log.Lshortfile | log.Lmicroseconds)
|
|
||||||
flag.Parse()
|
|
||||||
pth := findRepo(repo)
|
|
||||||
if pth == "" {
|
|
||||||
log.Fatalf("repository not found: %v", repo)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
asta, bin := build(
|
|
||||||
`
|
|
||||||
//#define SQLITE_DEBUG 1
|
|
||||||
//#define SQLITE_ENABLE_API_ARMOR 1
|
|
||||||
#define SQLITE_ENABLE_MEMSYS5 1
|
|
||||||
#define SQLITE_USE_URI 1
|
|
||||||
`,
|
|
||||||
[][]string{
|
|
||||||
{"main.c"},
|
|
||||||
{filepath.Join(pth, "sqlite3.c")},
|
|
||||||
},
|
|
||||||
cc.EnableAnonymousStructFields(),
|
|
||||||
cc.IncludePaths([]string{pth}),
|
|
||||||
)
|
|
||||||
|
|
||||||
var b0 bytes.Buffer
|
|
||||||
enc := gob.NewEncoder(&b0)
|
|
||||||
if err := enc.Encode(&bin); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var b1 bytes.Buffer
|
|
||||||
comp := gzip.NewWriter(&b1)
|
|
||||||
if _, err := comp.Write(b0.Bytes()); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := comp.Close(); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var b2 buffer.Bytes
|
|
||||||
lic, err := ioutil.ReadFile("SQLITE-LICENSE")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
b2.WriteString(`// Code generated by running "go generate". DO NOT EDIT.
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
`)
|
|
||||||
b2.Write(lic)
|
|
||||||
b2.WriteString(`
|
|
||||||
*/
|
|
||||||
|
|
||||||
package bin
|
|
||||||
|
|
||||||
const (
|
|
||||||
`)
|
|
||||||
macros(&b2, asta[0])
|
|
||||||
b2.WriteString(`
|
|
||||||
Data = "`)
|
|
||||||
b := b1.Bytes()
|
|
||||||
for _, v := range b {
|
|
||||||
switch {
|
|
||||||
case v == '\\':
|
|
||||||
b2.WriteString(`\\`)
|
|
||||||
case v == '"':
|
|
||||||
b2.WriteString(`\"`)
|
|
||||||
case v < ' ', v >= 0x7f:
|
|
||||||
fmt.Fprintf(&b2, `\x%02x`, v)
|
|
||||||
default:
|
|
||||||
b2.WriteByte(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
b2.WriteString(`"
|
|
||||||
)
|
|
||||||
`)
|
|
||||||
b3, err := format.Source(b2.Bytes())
|
|
||||||
if err != nil {
|
|
||||||
b3 = b
|
|
||||||
}
|
|
||||||
os.MkdirAll("internal/bin", 0775)
|
|
||||||
if err := ioutil.WriteFile(fmt.Sprintf("internal/bin/bin_%s_%s.go", runtime.GOOS, runtime.GOARCH), b3, 0664); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("code %#08x, text %#08x, data %#08x, bss %#08x, pc2func %v, pc2line %v, symbols %v, gz %v\n",
|
|
||||||
len(bin.Code), len(bin.Text), len(bin.Data), bin.BSS, len(bin.Functions), len(bin.Lines), len(bin.Sym), b1.Len(),
|
|
||||||
)
|
|
||||||
}
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1406
sqlite_windows.go
1406
sqlite_windows.go
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user