You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+44-101
Original file line number
Diff line number
Diff line change
@@ -56,15 +56,18 @@ By default, we test the following pairings:
56
56
In theory other implementations aren't *too bad* to add. You just need to:
57
57
58
58
* Add an implementation of abis::AbiImpl
59
-
* Specify the name, language, and source-file extension
60
-
* Specify supported calling conventions
61
-
* Specify how to generate a caller from a signature
62
-
* Specify how to generate a callee from a signature
59
+
* Specify the language and source-file extension
60
+
* Specify how to generate source for a caller from a signature
61
+
* Specify how to generate source for a callee from a signature
63
62
* Specify how to compile a source file to a static lib
64
63
* Register it in the `abi_impls` map in `fn main`
65
64
* (Optional) Register what you want it paired with by default in `DEFAULT_TEST_PAIRS`
66
65
* i.e. (ABI_IMPL_YOU, ABI_IMPL_CC) will have the harness test you calling into C
67
66
67
+
The bulk of the work is specifying how to generate source code, which can be done
68
+
incrementally by return UnimplementedError to indicate unsupported features. This
69
+
is totally fine, all the backends have places where they give up!
70
+
68
71
See the Test Harness section below for details on how to use it.
69
72
70
73
@@ -83,98 +86,37 @@ Windows Conventions:
83
86
* cdecl
84
87
* fastcall
85
88
* stdcall
86
-
*~~vectorcall~~ (code is there, but disabled due to linking issues)
87
-
88
-
Any test which specifies the "All" will implicitly combinatorically generate every known convention.
89
-
"Nonsensical" situations like stdcall on linux are the responsibility of the AbiImpls to identify and disable.
89
+
* vectorcall
90
90
91
91
92
92
## Types
93
93
94
-
The test format support for the following types/concepts:
95
-
96
-
* fixed-width integer types (uint8_t and friends)
97
-
* float/double
98
-
* bool
99
-
* structs
100
-
* c-like enums
101
-
* c-like untagged unions
102
-
* rust-like tagged unions
103
-
* opaque pointers (void\*)
104
-
* pass-by-ref (still checks the pointee's layout, and not the address)
105
-
* arrays (including multi-dimensional arrays, although C often requires arrays to be wrapped in pass-by-ref)
94
+
The abi-cafe typesystem is [defined by kdl-script](https://github.com/Gankra/abi-cafe/blob/main/kdl-script/README.md#types), see those docs for details, but, we basically support most of the types you could define/use in core Rust.
106
95
107
96
108
97
# Adding Tests
109
98
110
-
The default suite of tests can be found in `/include/tests/`
99
+
Tests are specified as [kdl-script](https://github.com/Gankra/abi-cafe/blob/main/kdl-script/README.md) files, which are basically C header files, but with a custom syntax that avoids us tying our hands to any particular language/semantics. The syntax will feel fairly familiar to Rust programmers.
111
100
112
-
There are two kinds of tests: `.kdl` ("normal") and `.procgen.kdl` ("procgen").
101
+
The default suite of tests can be [found in `/include/tests/`](https://github.com/Gankra/abi-cafe/tree/main/include/tests), which is statically embedded in abi-cafe's binary. You don't need to register the test anywhere, we will just try to parse every file in the tests directory.
113
102
114
-
The latter is sugar for the former, where you just define a type with the same name of the file (so `MetersU32.procgen.kdl`is expected to define a type named `MetersU32`), and we generate a battery of types/functions that stress it out.
103
+
There are two kinds of tests: `.kdl` ("[normal](https://github.com/Gankra/abi-cafe/tree/main/include/tests/normal)") and `.procgen.kdl`("[procgen](https://github.com/Gankra/abi-cafe/tree/main/include/tests/procgen)").
115
104
116
-
Tests are specified as [kdl-script](https://github.com/ron-rs/ron) files in the test/ directory, because it's more compact than JSON, has comments, and is more reliable with large integers. Because C is in some sense the "lingua franca" of FFI that everyone has to deal with, we prefer using C types in these definitions.
117
-
118
-
You don't need to register the test anywhere, we will just try to parse every file in that directory.
119
-
120
-
The "default" workflow is to handwrite a ron file, and the testing framework will handle generating the actual code implementating that interface (example: structs.ron). Generated impls will be output to the generated_impls dir for debugging. Build artifacts will get dumped in target/temp/ if you want to debug those too.
121
-
122
-
Example:
123
-
124
-
```rust
125
-
Test(
126
-
// name of this set of tests
127
-
name:"examples",
128
-
// generate tests for the following function signatures
129
-
funcs: [
130
-
(
131
-
// base function/subtest name (but also subtest name)
132
-
name:"some_prims",
133
-
// what calling conventions to generate this test for
134
-
// (All = do them all, a good default)
135
-
conventions: [All],
136
-
// args
137
-
inputs: [
138
-
Int(c_int32_t(5)),
139
-
Int(c_uint64_t(0x123_abc)),
140
-
]
141
-
// return value
142
-
output:Some(Bool(true)),
143
-
),
144
-
(
145
-
name:"some_structs",
146
-
conventions: [All],
147
-
inputs: [
148
-
Int(c_int32_t(5)),
149
-
// Struct decls are implicit in usage.
150
-
// All structs with the same name must match!
151
-
Struct("MyStruct", [
152
-
Int(c_uint8_t(0xf1)),
153
-
Float(c_double(1234.23)),
154
-
]),
155
-
Struct("MyStruct", [
156
-
Int(c_uint8_t(0x1)),
157
-
Float(c_double(0.23)),
158
-
]),
159
-
],
160
-
// no return (void)
161
-
output:None,
162
-
),
163
-
]
164
-
)
165
-
```
166
-
167
-
However, you have two "power user" options available:
105
+
The latter is sugar for the former, where you just define a type with the same name of the file (so `MetersU32.procgen.kdl` is expected to define a type named `MetersU32`), and we generate a battery of types/functions that stress it out.
168
106
169
-
* Generate the ron itself with generate_procedural_tests in main.rs (example: ui128.ron). This is good for bruteforcing a bunch of different combinations if you just want to make sure a type/feature generally works in many different situations.
107
+
Suggested Examples:
170
108
171
-
* Use the "Handwritten" convention and manually provide the implementations (example: opaque_example.ron). This lets you basically do *anything* without the testing framework having to understand your calling convention or type/feature. Manual impls go in handwritten_impls and use the same naming/structure as generated_impls.
109
+
*[simple.kdl](https://github.com/Gankra/abi-cafe/blob/main/include/tests/normal/simple.kdl) - a little example of a "normal" test with explicitly defined functions to test
110
+
*[SimpleStruct.procgen.kdl](https://github.com/Gankra/abi-cafe/blob/main/include/tests/procgen/struct/SimpleStruct.procgen.kdl) - similar to simple.kdl, but procgen
111
+
*[MetersU32.procgen.kdl](https://github.com/Gankra/abi-cafe/blob/main/include/tests/procgen/pun/MetersU32.procgen.kdl) - an example of a ["pun type"](https://github.com/Gankra/abi-cafe/tree/main/kdl-script#pun-types), where different languages use different definitions
112
+
*[IntrusiveList.procgen.kdl](https://github.com/Gankra/abi-cafe/blob/main/include/tests/procgen/fancy/IntrusiveList.procgen.kdl) - an example of how we can procgen tests for self-referential types and tagged unions
113
+
*[i8.procgen.kdl](https://github.com/Gankra/abi-cafe/blob/main/include/tests/procgen/primitive/i8.procgen.kdl) - ok this one isn't instructive it's just funny that it can be a blank file because i8 is builtin so all the info needed is in the filename
172
114
173
115
174
116
175
117
# The Test Harness
176
118
177
-
Implementation details of dylib test harness are split up between main.rs and the contents of the top-level harness/ directory. The contents of harness/ include:
119
+
Implementation details of dylib test harness are split up between [src/harness/run.rs](https://github.com/Gankra/abi-cafe/blob/main/src/harness/run.rs) and the contents of the top-level [/include/harness/](https://github.com/Gankra/abi-cafe/blob/main/include/harness/). The contents of /include/harness/ are:
178
120
179
121
* "headers" for the testing framework for each language
180
122
* harness.rs, which defines the entry-point for the test and sets up all the global callbacks/pointers. This is linked with the callee and caller to create the final dylib.
@@ -183,50 +125,50 @@ Ideally you shouldn't have to worry about *how* the callbacks work, so I'll just
0 commit comments