-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathffi.nimble
More file actions
187 lines (162 loc) · 8.07 KB
/
Copy pathffi.nimble
File metadata and controls
187 lines (162 loc) · 8.07 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
# ffi.nimble
version = "0.2.0"
author = "Institute of Free Technology"
description = "FFI framework with custom header generation"
license = "MIT or Apache License 2.0"
packageName = "ffi"
requires "nim >= 2.2.4"
requires "chronos"
requires "chronicles"
requires "taskpools"
requires "cbor_serialization"
const nimFlagsOrc = "--mm:orc -d:chronicles_log_level=WARN"
const nimFlagsRefc = "--mm:refc -d:chronicles_log_level=WARN"
import std/[algorithm, os, strutils]
proc discoverUnitTests(): seq[string] =
# `listFiles` returns both .nim sources and any compiled binaries left in
# the dir from prior local runs — filter to .nim so we don't run a test
# twice (and don't try to `nim c -r` a stale binary).
var names: seq[string] = @[]
for path in listFiles(thisDir() / "tests/unit"):
if path.endsWith(".nim"):
let name = path.extractFilename.changeFileExt("")
if name.startsWith("test_"):
names.add(name)
names.sort()
return names
let unitTests = discoverUnitTests()
proc runOrQuit(cmd: string) =
# Workaround for newer nimble (shipping with Nim 2.2.10+) printing the
# OSError from a failed `exec` but exiting 0, which causes CI to report
# green on actual build/test failures. Echo the command first so the log
# makes clear which step failed.
try:
exec cmd
except OSError as e:
echo "command failed: ", cmd
echo "error: ", e.msg
quit(QuitFailure)
proc sanFlags(san: string): string =
# Each --passC / --passL adds one literal flag to the C compiler / linker
# invocation — avoids any quoting ambiguity that arises from putting
# space-separated flags inside a single --passC argument.
#
# `asan-ubsan` enables LeakSanitizer too: ASan includes LSan, so leaks are
# reported when ASAN_OPTIONS=detect_leaks=1 (set by the sanitizer CI job).
case san
of "none", "":
""
of "asan-ubsan":
" --passC:-fsanitize=address,undefined" & " --passC:-fno-sanitize-recover=all" &
" --passC:-fno-omit-frame-pointer" & " --passC:-g" &
" --passL:-fsanitize=address,undefined"
of "tsan":
" --passC:-fsanitize=thread" & " --passC:-fno-omit-frame-pointer" & " --passC:-g" &
" --passC:-O1" & " --passL:-fsanitize=thread"
else:
raise newException(ValueError, "unknown NIM_FFI_SAN: " & san)
task buildffi, "Compile the library":
exec "nim c " & nimFlagsOrc & " --app:lib --noMain ffi.nim"
task test, "Run all tests under --mm:orc and --mm:refc":
for flags in [nimFlagsOrc, nimFlagsRefc]:
for t in unitTests:
exec "nim c -r " & flags & " tests/unit/" & t & ".nim"
task test_alloc, "Run alloc unit tests under --mm:orc and --mm:refc":
exec "nim c -r " & nimFlagsOrc & " tests/unit/test_alloc.nim"
exec "nim c -r " & nimFlagsRefc & " tests/unit/test_alloc.nim"
task test_ffi, "Run FFI context integration tests under --mm:orc and --mm:refc":
exec "nim c -r " & nimFlagsOrc & " tests/unit/test_ffi_context.nim"
exec "nim c -r " & nimFlagsRefc & " tests/unit/test_ffi_context.nim"
task test_serial, "Run CBOR codec unit tests":
exec "nim c -r " & nimFlagsOrc & " tests/unit/test_serial.nim"
exec "nim c -r " & nimFlagsRefc & " tests/unit/test_serial.nim"
task test_cpp_e2e, "Build and run the C++ end-to-end tests for the timer example":
# Regenerate the C++ bindings so the suite always runs against fresh codegen.
runOrQuit "nimble genbindings_cpp"
runOrQuit "nimble genbindings_cpp_echo"
runOrQuit "cmake -S tests/e2e/cpp -B tests/e2e/cpp/build"
runOrQuit "cmake --build tests/e2e/cpp/build --config Debug"
# `-C Debug` is required on Windows multi-config generators because
# gtest_discover_tests(PRE_TEST) loads per-config include files; harmless on
# single-config generators (Make/Ninja) on Linux/macOS.
runOrQuit "ctest --test-dir tests/e2e/cpp/build --output-on-failure -C Debug"
task test_sanitized,
"Run all unit tests under a sanitizer (NIM_FFI_SAN) and mm (NIM_FFI_MM)":
let san = getEnv("NIM_FFI_SAN", "none")
let mm = getEnv("NIM_FFI_MM", "")
let extra = sanFlags(san)
let modes =
if mm == "orc":
@[nimFlagsOrc]
elif mm == "refc":
@[nimFlagsRefc]
else:
@[nimFlagsOrc, nimFlagsRefc]
if san == "tsan":
let suppPath = thisDir() & "/tsan.supp"
let existing = getEnv("TSAN_OPTIONS")
if existing == "":
putEnv("TSAN_OPTIONS", "suppressions=" & suppPath)
elif "suppressions=" notin existing:
putEnv("TSAN_OPTIONS", existing & ":suppressions=" & suppPath)
for flags in modes:
for t in unitTests:
exec "nim c -r " & flags & extra & " tests/unit/" & t & ".nim"
task test_cpp_e2e_sanitized,
"Build and run the C++ e2e tests with a sanitizer (NIM_FFI_SAN) and mm (NIM_FFI_MM)":
let mm = getEnv("NIM_FFI_MM", "orc")
let san = getEnv("NIM_FFI_SAN", "none")
runOrQuit "nimble genbindings_cpp"
runOrQuit "nimble genbindings_cpp_echo"
runOrQuit "cmake -S tests/e2e/cpp -B tests/e2e/cpp/build" & " -DNIM_FFI_MM=" & mm &
" -DNIM_FFI_SANITIZER=" & san
runOrQuit "cmake --build tests/e2e/cpp/build --config Debug -j"
runOrQuit "ctest --test-dir tests/e2e/cpp/build --output-on-failure -C Debug"
task genbindings_example, "Generate Rust bindings for the timer example":
exec "nim c " & nimFlagsOrc &
" --app:lib --noMain --nimMainPrefix:libmy_timer -d:ffiGenBindings -o:/dev/null examples/timer/timer.nim"
exec "nim c " & nimFlagsRefc &
" --app:lib --noMain --nimMainPrefix:libmy_timer -d:ffiGenBindings -o:/dev/null examples/timer/timer.nim"
task genbindings_rust, "Generate Rust bindings for the timer example":
exec "nim c " & nimFlagsOrc & " --app:lib --noMain --nimMainPrefix:libmy_timer" &
" -d:ffiGenBindings -d:targetLang=rust" &
" -d:ffiOutputDir=examples/timer/rust_bindings" & " -d:ffiSrcPath=../timer.nim" &
" -o:/dev/null examples/timer/timer.nim"
exec "nim c " & nimFlagsRefc & " --app:lib --noMain --nimMainPrefix:libmy_timer" &
" -d:ffiGenBindings -d:targetLang=rust" &
" -d:ffiOutputDir=examples/timer/rust_bindings" & " -d:ffiSrcPath=../timer.nim" &
" -o:/dev/null examples/timer/timer.nim"
task genbindings_cddl, "Generate CDDL schema for the timer example":
exec "nim c " & nimFlagsOrc & " --app:lib --noMain --nimMainPrefix:libtimer" &
" -d:ffiGenBindings -d:targetLang=cddl" &
" -d:ffiOutputDir=examples/timer/cddl_bindings" & " -d:ffiSrcPath=../timer.nim" &
" -o:/dev/null examples/timer/timer.nim"
task genbindings_cpp, "Generate C++ bindings for the timer example":
exec "nim c " & nimFlagsOrc & " --app:lib --noMain --nimMainPrefix:libmy_timer" &
" -d:ffiGenBindings -d:targetLang=cpp" &
" -d:ffiOutputDir=examples/timer/cpp_bindings" & " -d:ffiSrcPath=../timer.nim" &
" -o:/dev/null examples/timer/timer.nim"
exec "nim c " & nimFlagsRefc & " --app:lib --noMain --nimMainPrefix:libmy_timer" &
" -d:ffiGenBindings -d:targetLang=cpp" &
" -d:ffiOutputDir=examples/timer/cpp_bindings" & " -d:ffiSrcPath=../timer.nim" &
" -o:/dev/null examples/timer/timer.nim"
task genbindings_cpp_echo, "Generate C++ bindings for the echo example":
exec "nim c " & nimFlagsOrc & " --app:lib --noMain --nimMainPrefix:libecho" &
" -d:ffiGenBindings -d:targetLang=cpp" &
" -d:ffiOutputDir=examples/echo/cpp_bindings" & " -d:ffiSrcPath=../echo.nim" &
" -o:/dev/null examples/echo/echo.nim"
exec "nim c " & nimFlagsRefc & " --app:lib --noMain --nimMainPrefix:libecho" &
" -d:ffiGenBindings -d:targetLang=cpp" &
" -d:ffiOutputDir=examples/echo/cpp_bindings" & " -d:ffiSrcPath=../echo.nim" &
" -o:/dev/null examples/echo/echo.nim"
task check_bindings_rust, "Verify checked-in Rust bindings match Nim source":
exec "nimble genbindings_rust"
exec "git diff --exit-code --" & " examples/timer/rust_bindings/Cargo.toml" &
" examples/timer/rust_bindings/build.rs" & " examples/timer/rust_bindings/src"
task check_bindings_cpp, "Verify checked-in C++ bindings match Nim source":
exec "nimble genbindings_cpp"
exec "git diff --exit-code --" & " examples/timer/cpp_bindings/my_timer.hpp" &
" examples/timer/cpp_bindings/CMakeLists.txt"
task check_bindings, "Verify all checked-in example bindings match Nim source":
exec "nimble check_bindings_rust"
exec "nimble check_bindings_cpp"