mirror of
https://github.com/ncruces/go-sqlite3.git
synced 2026-01-12 05:59:14 +00:00
Refactor CREATE parser. (#111)
This commit is contained in:
@@ -7,7 +7,7 @@ ROOT=../
|
||||
BINARYEN="$ROOT/tools/binaryen-version_117/bin"
|
||||
WASI_SDK="$ROOT/tools/wasi-sdk-22.0/bin"
|
||||
|
||||
"$WASI_SDK/clang" --target=wasm32-wasi -std=c17 -flto -g0 -O2 \
|
||||
"$WASI_SDK/clang" --target=wasm32-wasi -std=c23 -flto -g0 -O2 \
|
||||
-Wall -Wextra -Wno-unused-parameter -Wno-unused-function \
|
||||
-o sqlite3.wasm "$ROOT/sqlite3/main.c" \
|
||||
-I"$ROOT/sqlite3" \
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package csv
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"strings"
|
||||
|
||||
"github.com/ncruces/go-sqlite3/util/vtabutil"
|
||||
@@ -22,12 +21,10 @@ func getColumnAffinities(schema string) ([]affinity, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer tab.Close()
|
||||
|
||||
types := make([]affinity, tab.NumColumns())
|
||||
for i := range types {
|
||||
col := tab.Column(i)
|
||||
types[i] = getAffinity(col.Type())
|
||||
types := make([]affinity, len(tab.Columns))
|
||||
for i, col := range tab.Columns {
|
||||
types[i] = getAffinity(col.Type)
|
||||
}
|
||||
return types, nil
|
||||
}
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
package csv
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"testing"
|
||||
)
|
||||
import "testing"
|
||||
|
||||
func Test_getAffinity(t *testing.T) {
|
||||
tests := []struct {
|
||||
|
||||
61
util/vtabutil/const.go
Normal file
61
util/vtabutil/const.go
Normal file
@@ -0,0 +1,61 @@
|
||||
package vtabutil
|
||||
|
||||
const (
|
||||
_NONE = iota
|
||||
_MEMORY
|
||||
_SYNTAX
|
||||
_UNSUPPORTEDSQL
|
||||
)
|
||||
|
||||
type ConflictClause uint32
|
||||
|
||||
const (
|
||||
CONFLICT_NONE ConflictClause = iota
|
||||
CONFLICT_ROLLBACK
|
||||
CONFLICT_ABORT
|
||||
CONFLICT_FAIL
|
||||
CONFLICT_IGNORE
|
||||
CONFLICT_REPLACE
|
||||
)
|
||||
|
||||
type OrderClause uint32
|
||||
|
||||
const (
|
||||
ORDER_NONE OrderClause = iota
|
||||
ORDER_ASC
|
||||
ORDER_DESC
|
||||
)
|
||||
|
||||
type FKAction uint32
|
||||
|
||||
const (
|
||||
FKACTION_NONE FKAction = iota
|
||||
FKACTION_SETNULL
|
||||
FKACTION_SETDEFAULT
|
||||
FKACTION_CASCADE
|
||||
FKACTION_RESTRICT
|
||||
FKACTION_NOACTION
|
||||
)
|
||||
|
||||
type FKDefType uint32
|
||||
|
||||
const (
|
||||
DEFTYPE_NONE FKDefType = iota
|
||||
DEFTYPE_DEFERRABLE
|
||||
DEFTYPE_DEFERRABLE_INITIALLY_DEFERRED
|
||||
DEFTYPE_DEFERRABLE_INITIALLY_IMMEDIATE
|
||||
DEFTYPE_NOTDEFERRABLE
|
||||
DEFTYPE_NOTDEFERRABLE_INITIALLY_DEFERRED
|
||||
DEFTYPE_NOTDEFERRABLE_INITIALLY_IMMEDIATE
|
||||
)
|
||||
|
||||
type StatementType uint32
|
||||
|
||||
const (
|
||||
CREATE_UNKNOWN StatementType = iota
|
||||
CREATE_TABLE
|
||||
ALTER_RENAME_TABLE
|
||||
ALTER_RENAME_COLUMN
|
||||
ALTER_ADD_COLUMN
|
||||
ALTER_DROP_COLUMN
|
||||
)
|
||||
@@ -12,60 +12,50 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
_NONE = iota
|
||||
_MEMORY
|
||||
_SYNTAX
|
||||
_UNSUPPORTEDSQL
|
||||
|
||||
codeptr = 4
|
||||
baseptr = 8
|
||||
errp = 4
|
||||
sqlp = 8
|
||||
)
|
||||
|
||||
var (
|
||||
//go:embed parse/sql3parse_table.wasm
|
||||
binary []byte
|
||||
ctx context.Context
|
||||
once sync.Once
|
||||
runtime wazero.Runtime
|
||||
module wazero.CompiledModule
|
||||
binary []byte
|
||||
once sync.Once
|
||||
runtime wazero.Runtime
|
||||
compiled wazero.CompiledModule
|
||||
)
|
||||
|
||||
// Table holds metadata about a table.
|
||||
type Table struct {
|
||||
mod api.Module
|
||||
ptr uint32
|
||||
sql string
|
||||
}
|
||||
|
||||
// Parse parses a [CREATE] or [ALTER TABLE] command.
|
||||
//
|
||||
// [CREATE]: https://sqlite.org/lang_createtable.html
|
||||
// [ALTER TABLE]: https://sqlite.org/lang_altertable.html
|
||||
func Parse(sql string) (_ *Table, err error) {
|
||||
once.Do(func() {
|
||||
ctx = context.Background()
|
||||
cfg := wazero.NewRuntimeConfigInterpreter().WithDebugInfoEnabled(false)
|
||||
ctx := context.Background()
|
||||
cfg := wazero.NewRuntimeConfigInterpreter()
|
||||
runtime = wazero.NewRuntimeWithConfig(ctx, cfg)
|
||||
module, err = runtime.CompileModule(ctx, binary)
|
||||
compiled, err = runtime.CompileModule(ctx, binary)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mod, err := runtime.InstantiateModule(ctx, module, wazero.NewModuleConfig().WithName(""))
|
||||
ctx := context.Background()
|
||||
mod, err := runtime.InstantiateModule(ctx, compiled, wazero.NewModuleConfig().WithName(""))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer mod.Close(ctx)
|
||||
|
||||
if buf, ok := mod.Memory().Read(baseptr, uint32(len(sql))); ok {
|
||||
if buf, ok := mod.Memory().Read(sqlp, uint32(len(sql))); ok {
|
||||
copy(buf, sql)
|
||||
}
|
||||
r, err := mod.ExportedFunction("sql3parse_table").Call(ctx, baseptr, uint64(len(sql)), codeptr)
|
||||
|
||||
r, err := mod.ExportedFunction("sql3parse_table").Call(ctx, sqlp, uint64(len(sql)), errp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c, _ := mod.Memory().ReadUint32Le(codeptr)
|
||||
c, _ := mod.Memory().ReadUint32Le(errp)
|
||||
switch c {
|
||||
case _MEMORY:
|
||||
panic(util.OOMErr)
|
||||
@@ -74,68 +64,146 @@ func Parse(sql string) (_ *Table, err error) {
|
||||
case _UNSUPPORTEDSQL:
|
||||
return nil, util.ErrorString("sql3parse: unsupported SQL")
|
||||
}
|
||||
if r[0] == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
return &Table{
|
||||
sql: sql,
|
||||
mod: mod,
|
||||
ptr: uint32(r[0]),
|
||||
}, nil
|
||||
|
||||
var tab Table
|
||||
tab.load(mod, uint32(r[0]), sql)
|
||||
return &tab, nil
|
||||
}
|
||||
|
||||
// Close closes a table handle.
|
||||
func (t *Table) Close() error {
|
||||
mod := t.mod
|
||||
t.mod = nil
|
||||
return mod.Close(ctx)
|
||||
// Table holds metadata about a table.
|
||||
type Table struct {
|
||||
Name string
|
||||
Schema string
|
||||
Comment string
|
||||
IsTemporary bool
|
||||
IsIfNotExists bool
|
||||
IsWithoutRowID bool
|
||||
IsStrict bool
|
||||
Columns []Column
|
||||
Type StatementType
|
||||
CurrentName string
|
||||
NewName string
|
||||
}
|
||||
|
||||
// NumColumns returns the number of columns of the table.
|
||||
func (t *Table) NumColumns() int {
|
||||
r, err := t.mod.ExportedFunction("sql3table_num_columns").Call(ctx, uint64(t.ptr))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return int(int32(r[0]))
|
||||
}
|
||||
func (t *Table) load(mod api.Module, ptr uint32, sql string) {
|
||||
t.Name = loadString(mod, ptr+0, sql)
|
||||
t.Schema = loadString(mod, ptr+8, sql)
|
||||
t.Comment = loadString(mod, ptr+16, sql)
|
||||
|
||||
// Column returns data for the ith column of the table.
|
||||
//
|
||||
// https://sqlite.org/lang_createtable.html#column_definitions
|
||||
func (t *Table) Column(i int) Column {
|
||||
r, err := t.mod.ExportedFunction("sql3table_get_column").Call(ctx, uint64(t.ptr), uint64(i))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return Column{
|
||||
tab: t,
|
||||
ptr: uint32(r[0]),
|
||||
}
|
||||
}
|
||||
t.IsTemporary = loadBool(mod, ptr+24)
|
||||
t.IsIfNotExists = loadBool(mod, ptr+25)
|
||||
t.IsWithoutRowID = loadBool(mod, ptr+26)
|
||||
t.IsStrict = loadBool(mod, ptr+27)
|
||||
|
||||
func (t *Table) string(ptr uint32) string {
|
||||
if ptr == 0 {
|
||||
return ""
|
||||
}
|
||||
off, _ := t.mod.Memory().ReadUint32Le(ptr + 0)
|
||||
len, _ := t.mod.Memory().ReadUint32Le(ptr + 4)
|
||||
return t.sql[off-baseptr : off+len-baseptr]
|
||||
t.Columns = loadSlice(mod, ptr+28, func(ptr uint32, res *Column) {
|
||||
p, _ := mod.Memory().ReadUint32Le(ptr)
|
||||
res.load(mod, p, sql)
|
||||
})
|
||||
|
||||
t.Type = loadEnum[StatementType](mod, ptr+44)
|
||||
t.CurrentName = loadString(mod, ptr+48, sql)
|
||||
t.NewName = loadString(mod, ptr+56, sql)
|
||||
}
|
||||
|
||||
// Column holds metadata about a column.
|
||||
type Column struct {
|
||||
tab *Table
|
||||
ptr uint32
|
||||
Name string
|
||||
Type string
|
||||
Length string
|
||||
ConstraintName string
|
||||
Comment string
|
||||
IsPrimaryKey bool
|
||||
IsAutoIncrement bool
|
||||
IsNotNull bool
|
||||
IsUnique bool
|
||||
PKOrder OrderClause
|
||||
PKConflictClause ConflictClause
|
||||
NotNullConflictClause ConflictClause
|
||||
UniqueConflictClause ConflictClause
|
||||
CheckExpr string
|
||||
DefaultExpr string
|
||||
CollateName string
|
||||
ForeignKeyClause *ForeignKey
|
||||
}
|
||||
|
||||
// Type returns the declared type of a column.
|
||||
//
|
||||
// https://sqlite.org/lang_createtable.html#column_data_types
|
||||
func (c Column) Type() string {
|
||||
r, err := c.tab.mod.ExportedFunction("sql3column_type").Call(ctx, uint64(c.ptr))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
func (c *Column) load(mod api.Module, ptr uint32, sql string) {
|
||||
c.Name = loadString(mod, ptr+0, sql)
|
||||
c.Type = loadString(mod, ptr+8, sql)
|
||||
c.Length = loadString(mod, ptr+16, sql)
|
||||
c.ConstraintName = loadString(mod, ptr+24, sql)
|
||||
c.Comment = loadString(mod, ptr+32, sql)
|
||||
|
||||
c.IsPrimaryKey = loadBool(mod, ptr+40)
|
||||
c.IsAutoIncrement = loadBool(mod, ptr+41)
|
||||
c.IsNotNull = loadBool(mod, ptr+42)
|
||||
c.IsUnique = loadBool(mod, ptr+43)
|
||||
|
||||
c.PKOrder = loadEnum[OrderClause](mod, ptr+44)
|
||||
c.PKConflictClause = loadEnum[ConflictClause](mod, ptr+48)
|
||||
c.NotNullConflictClause = loadEnum[ConflictClause](mod, ptr+52)
|
||||
c.UniqueConflictClause = loadEnum[ConflictClause](mod, ptr+56)
|
||||
|
||||
c.CheckExpr = loadString(mod, ptr+60, sql)
|
||||
c.DefaultExpr = loadString(mod, ptr+68, sql)
|
||||
c.CollateName = loadString(mod, ptr+76, sql)
|
||||
|
||||
if ptr, _ := mod.Memory().ReadUint32Le(ptr + 84); ptr != 0 {
|
||||
c.ForeignKeyClause = &ForeignKey{}
|
||||
c.ForeignKeyClause.load(mod, ptr, sql)
|
||||
}
|
||||
return c.tab.string(uint32(r[0]))
|
||||
}
|
||||
|
||||
type ForeignKey struct {
|
||||
Table string
|
||||
Columns []string
|
||||
OnDelete FKAction
|
||||
OnUpdate FKAction
|
||||
Match string
|
||||
Deferrable FKDefType
|
||||
}
|
||||
|
||||
func (f *ForeignKey) load(mod api.Module, ptr uint32, sql string) {
|
||||
f.Table = loadString(mod, ptr+0, sql)
|
||||
|
||||
f.Columns = loadSlice(mod, ptr+8, func(ptr uint32, res *string) {
|
||||
*res = loadString(mod, ptr, sql)
|
||||
})
|
||||
|
||||
f.OnDelete = loadEnum[FKAction](mod, ptr+16)
|
||||
f.OnUpdate = loadEnum[FKAction](mod, ptr+20)
|
||||
f.Match = loadString(mod, ptr+24, sql)
|
||||
f.Deferrable = loadEnum[FKDefType](mod, ptr+32)
|
||||
}
|
||||
|
||||
func loadString(mod api.Module, ptr uint32, sql string) string {
|
||||
off, _ := mod.Memory().ReadUint32Le(ptr + 0)
|
||||
if off == 0 {
|
||||
return ""
|
||||
}
|
||||
len, _ := mod.Memory().ReadUint32Le(ptr + 4)
|
||||
return sql[off-sqlp : off+len-sqlp]
|
||||
}
|
||||
|
||||
func loadSlice[T any](mod api.Module, ptr uint32, fn func(uint32, *T)) []T {
|
||||
ref, _ := mod.Memory().ReadUint32Le(ptr + 4)
|
||||
if ref == 0 {
|
||||
return nil
|
||||
}
|
||||
len, _ := mod.Memory().ReadUint32Le(ptr + 0)
|
||||
res := make([]T, len)
|
||||
for i := range res {
|
||||
fn(ref, &res[i])
|
||||
ref += 4
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func loadEnum[T ~uint32](mod api.Module, ptr uint32) T {
|
||||
val, _ := mod.Memory().ReadUint32Le(ptr)
|
||||
return T(val)
|
||||
}
|
||||
|
||||
func loadBool(mod api.Module, ptr uint32) bool {
|
||||
val, _ := mod.Memory().ReadByte(ptr)
|
||||
return val != 0
|
||||
}
|
||||
|
||||
@@ -7,9 +7,8 @@ ROOT=../../../
|
||||
BINARYEN="$ROOT/tools/binaryen-version_117/bin"
|
||||
WASI_SDK="$ROOT/tools/wasi-sdk-22.0/bin"
|
||||
|
||||
"$WASI_SDK/clang" --target=wasm32-wasi -std=c17 -flto -g0 -Oz \
|
||||
-Wall -Wextra -Wno-unused-parameter -Wno-unused-function \
|
||||
-o sql3parse_table.wasm sql3parse_table.c \
|
||||
"$WASI_SDK/clang" --target=wasm32-wasi -std=c23 -flto -g0 -Oz \
|
||||
-Wall -Wextra -o sql3parse_table.wasm main.c \
|
||||
-mexec-model=reactor \
|
||||
-msimd128 -mmutable-globals -mmultivalue \
|
||||
-mbulk-memory -mreference-types \
|
||||
@@ -17,11 +16,11 @@ WASI_SDK="$ROOT/tools/wasi-sdk-22.0/bin"
|
||||
-fno-stack-protector -fno-stack-clash-protection \
|
||||
-Wl,--stack-first \
|
||||
-Wl,--import-undefined \
|
||||
$(awk '{print "-Wl,--export="$0}' exports.txt)
|
||||
-Wl,--export=sql3parse_table
|
||||
|
||||
trap 'rm -f sql3parse_table.tmp' EXIT
|
||||
"$BINARYEN/wasm-ctor-eval" -g -c _initialize sql3parse_table.wasm -o sql3parse_table.tmp
|
||||
"$BINARYEN/wasm-opt" -g --strip --strip-producers -c -Oz \
|
||||
"$BINARYEN/wasm-ctor-eval" -c _initialize sql3parse_table.wasm -o sql3parse_table.tmp
|
||||
"$BINARYEN/wasm-opt" --strip --strip-debug --strip-producers -c -Oz \
|
||||
sql3parse_table.tmp -o sql3parse_table.wasm \
|
||||
--enable-simd --enable-mutable-globals --enable-multivalue \
|
||||
--enable-bulk-memory --enable-reference-types \
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
sql3parse_table
|
||||
sql3table_get_column
|
||||
sql3table_num_columns
|
||||
sql3column_type
|
||||
42
util/vtabutil/parse/main.c
Normal file
42
util/vtabutil/parse/main.c
Normal file
@@ -0,0 +1,42 @@
|
||||
#include <stddef.h>
|
||||
|
||||
#include "sql3parse_table.c"
|
||||
|
||||
static_assert(offsetof(sql3table, name) == 0, "Unexpected offset");
|
||||
static_assert(offsetof(sql3table, schema) == 8, "Unexpected offset");
|
||||
static_assert(offsetof(sql3table, comment) == 16, "Unexpected offset");
|
||||
static_assert(offsetof(sql3table, is_temporary) == 24, "Unexpected offset");
|
||||
static_assert(offsetof(sql3table, is_ifnotexists) == 25, "Unexpected offset");
|
||||
static_assert(offsetof(sql3table, is_withoutrowid) == 26, "Unexpected offset");
|
||||
static_assert(offsetof(sql3table, is_strict) == 27, "Unexpected offset");
|
||||
static_assert(offsetof(sql3table, num_columns) == 28, "Unexpected offset");
|
||||
static_assert(offsetof(sql3table, columns) == 32, "Unexpected offset");
|
||||
static_assert(offsetof(sql3table, type) == 44, "Unexpected offset");
|
||||
static_assert(offsetof(sql3table, current_name) == 48, "Unexpected offset");
|
||||
static_assert(offsetof(sql3table, new_name) == 56, "Unexpected offset");
|
||||
|
||||
static_assert(offsetof(sql3column, name) == 0, "Unexpected offset");
|
||||
static_assert(offsetof(sql3column, type) == 8, "Unexpected offset");
|
||||
static_assert(offsetof(sql3column, length) == 16, "Unexpected offset");
|
||||
static_assert(offsetof(sql3column, constraint_name) == 24, "Unexpected offset");
|
||||
static_assert(offsetof(sql3column, comment) == 32, "Unexpected offset");
|
||||
static_assert(offsetof(sql3column, is_primarykey) == 40, "Unexpected offset");
|
||||
static_assert(offsetof(sql3column, is_autoincrement) == 41, "Unexpected offset");
|
||||
static_assert(offsetof(sql3column, is_notnull) == 42, "Unexpected offset");
|
||||
static_assert(offsetof(sql3column, is_unique) == 43, "Unexpected offset");
|
||||
static_assert(offsetof(sql3column, pk_order) == 44, "Unexpected offset");
|
||||
static_assert(offsetof(sql3column, pk_conflictclause) == 48, "Unexpected offset");
|
||||
static_assert(offsetof(sql3column, notnull_conflictclause) == 52, "Unexpected offset");
|
||||
static_assert(offsetof(sql3column, unique_conflictclause) == 56, "Unexpected offset");
|
||||
static_assert(offsetof(sql3column, check_expr) == 60, "Unexpected offset");
|
||||
static_assert(offsetof(sql3column, default_expr) == 68, "Unexpected offset");
|
||||
static_assert(offsetof(sql3column, collate_name) == 76, "Unexpected offset");
|
||||
static_assert(offsetof(sql3column, foreignkey_clause) == 84, "Unexpected offset");
|
||||
|
||||
static_assert(offsetof(sql3foreignkey, table) == 0, "Unexpected offset");
|
||||
static_assert(offsetof(sql3foreignkey, num_columns) == 8, "Unexpected offset");
|
||||
static_assert(offsetof(sql3foreignkey, column_name) == 12, "Unexpected offset");
|
||||
static_assert(offsetof(sql3foreignkey, on_delete) == 16, "Unexpected offset");
|
||||
static_assert(offsetof(sql3foreignkey, on_update) == 20, "Unexpected offset");
|
||||
static_assert(offsetof(sql3foreignkey, match) == 24, "Unexpected offset");
|
||||
static_assert(offsetof(sql3foreignkey, deferrable) == 32, "Unexpected offset");
|
||||
Binary file not shown.
31
util/vtabutil/parse_test.go
Normal file
31
util/vtabutil/parse_test.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package vtabutil_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/ncruces/go-sqlite3/util/vtabutil"
|
||||
)
|
||||
|
||||
func TestParse(t *testing.T) {
|
||||
tab, err := vtabutil.Parse(`CREATE TABLE child(x REFERENCES parent)`)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if got := tab.Name; got != "child" {
|
||||
t.Errorf("got %s, want child", got)
|
||||
}
|
||||
if got := len(tab.Columns); got != 1 {
|
||||
t.Errorf("got %d, want 1", got)
|
||||
}
|
||||
|
||||
col := tab.Columns[0]
|
||||
if got := col.Name; got != "x" {
|
||||
t.Errorf("got %s, want x", got)
|
||||
}
|
||||
|
||||
fk := col.ForeignKeyClause
|
||||
if got := fk.Table; got != "parent" {
|
||||
t.Errorf("got %s, want parent", got)
|
||||
}
|
||||
}
|
||||
2
vfs/tests/mptest/testdata/build.sh
vendored
2
vfs/tests/mptest/testdata/build.sh
vendored
@@ -7,7 +7,7 @@ ROOT=../../../../
|
||||
BINARYEN="$ROOT/tools/binaryen-version_117/bin"
|
||||
WASI_SDK="$ROOT/tools/wasi-sdk-22.0/bin"
|
||||
|
||||
"$WASI_SDK/clang" --target=wasm32-wasi -std=c17 -flto -g0 -O2 \
|
||||
"$WASI_SDK/clang" --target=wasm32-wasi -std=c23 -flto -g0 -O2 \
|
||||
-o mptest.wasm main.c \
|
||||
-I"$ROOT/sqlite3" \
|
||||
-msimd128 -mmutable-globals \
|
||||
|
||||
2
vfs/tests/speedtest1/testdata/build.sh
vendored
2
vfs/tests/speedtest1/testdata/build.sh
vendored
@@ -7,7 +7,7 @@ ROOT=../../../../
|
||||
BINARYEN="$ROOT/tools/binaryen-version_117/bin"
|
||||
WASI_SDK="$ROOT/tools/wasi-sdk-22.0/bin"
|
||||
|
||||
"$WASI_SDK/clang" --target=wasm32-wasi -std=c17 -flto -g0 -O2 \
|
||||
"$WASI_SDK/clang" --target=wasm32-wasi -std=c23 -flto -g0 -O2 \
|
||||
-o speedtest1.wasm main.c \
|
||||
-I"$ROOT/sqlite3" \
|
||||
-msimd128 -mmutable-globals \
|
||||
|
||||
Reference in New Issue
Block a user