Skip to content

Commit ca9d78a

Browse files
committed
Use clang driver to compile sqlite3 to wasm
1 parent 842b81c commit ca9d78a

File tree

5 files changed

+86
-89
lines changed

5 files changed

+86
-89
lines changed

sqlite3/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ With wasi in `/usr/share/wasi-sysroot` and the default clang compiler having the
175175
required builtins, you can setup the build with:
176176

177177
```
178-
cmake -S assets/wasm -B .dart_tool/sqlite3_build --toolchain toolchain.cmake
178+
cmake -S assets/wasm -B .dart_tool/sqlite3_build
179179
```
180180

181181
##### macOS
@@ -196,7 +196,7 @@ Replace `clang/18` with the correct directory if you're using a different versio
196196
Then, set up the build with
197197

198198
```
199-
cmake -Dwasi_sysroot=/opt/wasi-sysroot -Dclang=/opt/homebrew/opt/llvm/bin/clang -S assets/wasm -B .dart_tool/sqlite3_build --toolchain toolchain.cmake
199+
cmake -Dwasi_sysroot=/opt/wasi-sysroot -Dclang=/opt/homebrew/opt/llvm/bin/clang -S assets/wasm -B .dart_tool/sqlite3_build
200200
```
201201

202202
#### Building

sqlite3/assets/wasm/CMakeLists.txt

Lines changed: 77 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,97 @@
1-
cmake_minimum_required(VERSION 3.14)
1+
cmake_minimum_required(VERSION 3.24)
2+
23
set(PROJECT_NAME "sqlite3_web")
34
project(${PROJECT_NAME} LANGUAGES C)
45

6+
set(triple wasm32-unknown-wasi)
7+
set(wasi_sysroot "/usr/share/wasi-sysroot" CACHE PATH "Path to wasi sysroot")
8+
set(clang "clang" CACHE FILEPATH "Path to wasm-capable clang executable")
9+
510
include(FetchContent)
6-
if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.24.0")
7-
# cmake 3.24.0 added the `DOWNLOAD_EXTRACT_TIMESTAMP` and prints an ugly warning when
8-
# the default is used, so override it to the recommended behavior.
9-
# We can't really ask users to use a cmake that recent, so there's this if here.
10-
FetchContent_Declare(
11+
12+
FetchContent_Declare(
1113
sqlite3
1214
# NOTE: When changing this, also update `test/wasm/sqlite3_test.dart`
1315
URL https://sqlite.org/2024/sqlite-autoconf-3460000.tar.gz
1416
DOWNLOAD_EXTRACT_TIMESTAMP NEW
17+
)
18+
19+
FetchContent_MakeAvailable(sqlite3)
20+
21+
file(DOWNLOAD https://raw.githubusercontent.com/sqlite/sqlite/master/src/test_vfstrace.c "${CMAKE_BINARY_DIR}/vfstrace.c")
22+
23+
# Generate symbols we need to export from the sqlite3.wasm build
24+
add_custom_command(
25+
OUTPUT required_symbols.txt
26+
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../../
27+
COMMAND dart run tool/wasm_symbols.dart ${CMAKE_CURRENT_BINARY_DIR}/required_symbols.txt
28+
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/../../tool/wasm_symbols.dart
29+
VERBATIM
30+
)
31+
add_custom_target(required_symbols DEPENDS required_symbols.txt)
32+
33+
macro(base_sqlite3_target name debug)
34+
set(clang_output ${name}.clang.wasm)
35+
set(init_output ${name}.init.wasm)
36+
set(output ${init_output})
37+
38+
set(sources
39+
${CMAKE_CURRENT_SOURCE_DIR}/os_web.c
40+
${CMAKE_CURRENT_SOURCE_DIR}/helpers.c
41+
${sqlite3_SOURCE_DIR}/sqlite3.c
1542
)
16-
else()
17-
FetchContent_Declare(
18-
sqlite3
19-
# NOTE: When changing this, also update `test/wasm/sqlite3_test.dart`
20-
URL https://sqlite.org/2024/sqlite-autoconf-3460000.tar.gz
43+
set(flags -Wall -Wextra -Wno-unused-parameter -Wno-unused-function)
44+
45+
if(${debug})
46+
list(APPEND sources "${CMAKE_BINARY_DIR}/vfstrace.c")
47+
list(APPEND flags "-g" "-DDEBUG")
48+
else()
49+
list(APPEND flags "-Oz" "-DNDEBUG" "-flto")
50+
endif()
51+
52+
add_custom_command(
53+
OUTPUT ${clang_output}
54+
COMMAND ${clang} --target=${triple} -std=c23
55+
${flags}
56+
-o ${clang_output}
57+
-I ${PROJECT_SOURCE_DIR} -I ${sqlite3_SOURCE_DIR}
58+
-D_HAVE_SQLITE_CONFIG_H
59+
-mcpu=generic
60+
-mexec-model=reactor
61+
-fno-stack-protector -fno-stack-clash-protection
62+
-Wl,--import-memory
63+
--sysroot /usr/share/wasi-sysroot
64+
${sources}
65+
@${CMAKE_CURRENT_BINARY_DIR}/required_symbols.txt
66+
DEPENDS ${sources} required_symbols
67+
VERBATIM
2168
)
22-
endif()
2369

24-
FetchContent_MakeAvailable(sqlite3)
70+
add_custom_command(
71+
OUTPUT ${init_output}
72+
COMMAND wasm-ctor-eval -c _initialize ${clang_output} -o ${init_output}
73+
VERBATIM
74+
DEPENDS ${clang_output}
75+
)
2576

26-
set(wasm_visibility "__attribute__((visibility(\"default\")))")
77+
if(NOT ${debug})
78+
set(output ${name}.wasm)
2779

28-
macro(base_sqlite3_target name)
29-
add_executable(${name}
30-
"${sqlite3_SOURCE_DIR}/sqlite3.c"
31-
os_web.c
32-
helpers.c
80+
add_custom_command(
81+
OUTPUT ${output}
82+
COMMAND wasm-opt --strip --strip-producers -c -O4 ${init_output} -o ${output}
83+
VERBATIM
84+
DEPENDS ${init_output}
3385
)
86+
endif()
3487

35-
target_link_options(${name} PRIVATE -mexec-model=reactor -mcpu=generic -Wl,--import-memory -Wl,--no-entry -Wl,--export-dynamic)
36-
target_compile_options(${name} PRIVATE -std=c23 -mcpu=generic)
37-
target_include_directories(${name} PRIVATE "${PROJECT_SOURCE_DIR}/")
38-
target_include_directories(${name} PRIVATE ${sqlite3_SOURCE_DIR})
39-
target_compile_definitions(${name} PRIVATE
40-
_HAVE_SQLITE_CONFIG_H
41-
SQLITE_API=${wasm_visibility}
42-
)
43-
set_property(TARGET ${name} PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE)
88+
add_custom_target(${name} DEPENDS ${output})
4489
endmacro()
4590

46-
base_sqlite3_target(sqlite3_debug)
47-
file(DOWNLOAD https://raw.githubusercontent.com/sqlite/sqlite/master/src/test_vfstrace.c "${CMAKE_BINARY_DIR}/vfstrace.c")
48-
target_sources(sqlite3_debug PRIVATE "${CMAKE_BINARY_DIR}/vfstrace.c")
49-
target_compile_options(sqlite3_debug PRIVATE -g)
50-
target_compile_definitions(sqlite3_debug PRIVATE SQLITE_ENABLE_VFSTRACE SQLITE_ENABLE_API_ARMOR)
51-
set_target_properties(sqlite3_debug PROPERTIES OUTPUT_NAME "sqlite3" SUFFIX ".debug.wasm")
52-
53-
base_sqlite3_target(sqlite3_opt)
54-
target_compile_options(sqlite3_opt PRIVATE -Oz)
55-
set_target_properties(sqlite3_opt PROPERTIES OUTPUT_NAME "sqlite3" SUFFIX ".tmp.wasm")
56-
add_custom_command(TARGET sqlite3_opt POST_BUILD
57-
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../../
58-
COMMAND dart run tool/wasm_dce.dart ${CMAKE_CURRENT_BINARY_DIR}/sqlite3.tmp.wasm ${CMAKE_CURRENT_BINARY_DIR}/sqlite3.dce.wasm
59-
COMMAND wasm-opt ${CMAKE_CURRENT_BINARY_DIR}/sqlite3.dce.wasm -O4 -o ${CMAKE_CURRENT_BINARY_DIR}/sqlite3.wasm
60-
)
91+
base_sqlite3_target(sqlite3_debug true)
92+
base_sqlite3_target(sqlite3_opt false)
6193

6294
add_custom_target(output)
63-
add_custom_command(TARGET output COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/sqlite3.wasm ${PROJECT_SOURCE_DIR}/../../example/web/sqlite3.wasm)
64-
add_custom_command(TARGET output COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/sqlite3.debug.wasm ${PROJECT_SOURCE_DIR}/../../example/web/sqlite3.debug.wasm)
95+
add_custom_command(TARGET output COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/sqlite3_opt.wasm ${PROJECT_SOURCE_DIR}/../../example/web/sqlite3.wasm)
96+
add_custom_command(TARGET output COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/sqlite3_debug.init.wasm ${PROJECT_SOURCE_DIR}/../../example/web/sqlite3.debug.wasm)
6597
add_dependencies(output sqlite3_debug sqlite3_opt)

sqlite3/assets/wasm/toolchain.cmake

Lines changed: 0 additions & 10 deletions
This file was deleted.

sqlite3/example/custom_wasm_build/build.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,8 @@ fn main() {
77
env::var("WASI_SYSROOT").unwrap_or_else(|_| "/usr/share/wasi-sysroot".to_string());
88

99
let cmake_dir = Config::new("../../assets/wasm/")
10-
.configure_arg("--toolchain")
11-
.configure_arg(std::fs::canonicalize("../../assets/wasm/toolchain.cmake").unwrap())
1210
.define("wasi_sysroot", &sysroot)
11+
.define("CMAKE_C_COMPILER_WORKS", "1")
1312
.build_target("sqlite3_opt_lib")
1413
.build_target("help") // We only need the sources
1514
.build();

sqlite3/tool/wasm_dce.dart renamed to sqlite3/tool/wasm_symbols.dart

Lines changed: 6 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,21 @@
1-
import 'dart:convert';
21
import 'dart:io';
32

43
import 'package:analyzer/dart/analysis/utilities.dart';
54
import 'package:analyzer/dart/ast/visitor.dart';
65
import 'package:analyzer/src/dart/ast/ast.dart';
76

8-
void main(List<String> args) async {
9-
if (args.length != 2) {
10-
print(
11-
'Removes elements from a WASM file that are not accessed by the Dart bindings.');
12-
print('Usage: dart run tool/wasm_dce.dart in.wasm out.wasm');
13-
exit(1);
14-
}
15-
7+
/// Writes flags for clang that will `-Wl,--export` all symbols used by the
8+
/// `sqlite3` Dart package.
9+
void main(List<String> args) {
1610
final file = File('lib/src/wasm/wasm_interop.dart');
1711
final ast = parseString(content: file.readAsStringSync(), path: file.path);
1812

1913
final finder = _FindUsedSymbols();
2014
ast.unit.accept(finder);
2115

22-
final list = File('.dart_tool/used_wasm_symbols.json');
23-
list.writeAsStringSync(json.encode([
24-
for (final entry in finder.symbols)
25-
{
26-
'name': '_$entry',
27-
'export': entry,
28-
'root': true,
29-
}
30-
]));
31-
32-
final process = await Process.start(
33-
'wasm-metadce',
34-
[
35-
args[0],
36-
'--graph-file=${list.path}',
37-
'--output',
38-
args[1],
39-
],
40-
mode: ProcessStartMode.inheritStdio,
41-
);
42-
exit(await process.exitCode);
16+
final output = File(args[0]);
17+
output.writeAsStringSync(
18+
finder.symbols.map((e) => '-Wl,--export=$e').join(' '));
4319
}
4420

4521
class _FindUsedSymbols extends RecursiveAstVisitor<void> {

0 commit comments

Comments
 (0)