Skip to content

Commit 68695a6

Browse files
committed
Various changes
1 parent 55860d5 commit 68695a6

File tree

1 file changed

+89
-109
lines changed

1 file changed

+89
-109
lines changed

text/0000-erfc-post-build-contexts.md

Lines changed: 89 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,13 @@ cases like `#[test]` (both the built-in one and quickcheck), `#[bench]` (both bu
4242
ones like [criterion]), `examples`, and things like fuzzing. While we may not necessarily rewrite
4343
the built in test/bench/example infra in terms of the new framework, it should be possible to do so.
4444

45-
The main two problems that we need to solve are:
45+
The main two features proposed are:
4646

47-
- Having a nice API for generating custom post-build binaries
48-
- Having good `cargo` integration so that custom tests are at the same level of integration as regular tests as far as build processes are concerned
47+
- An API for crates that generate custom binaries, including
48+
introspection into the target crate.
49+
- A mechanism for `cargo` integration so that custom post-build
50+
contexts are at the same level of integration as `test` or `bench` as
51+
far as build processes are concerned.
4952

5053
[cargo-fuzz]: https://github.com/rust-fuzz/cargo-fuzz
5154
[criterion]: https://github.com/japaric/criterion.rs
@@ -63,15 +66,16 @@ A custom post-build context is essentially a whole-crate procedural
6366
macro that is evaluated after all other macros in the target crate have
6467
been evaluated. It is passed the `TokenStream` for every element in the
6568
target crate that has a set of attributes the post-build context has
66-
registered interest in. Essentially:
69+
registered interest in. For example, to declare a post-build context
70+
called `mytest`:
6771

6872
```rust
6973
extern crate proc_macro;
7074
use proc_macro::TokenStream;
7175

7276
// attributes() is optional
73-
#[post_build_context(test, attributes(foo, bar))]
74-
pub fn like_todays_test(items: &[AnnotatedItem]) -> TokenStream {
77+
#[post_build_context(attributes(foo, bar))]
78+
pub fn mytest(items: &[AnnotatedItem]) -> TokenStream {
7579
// ...
7680
}
7781
```
@@ -87,24 +91,28 @@ struct AnnotatedItem
8791
}
8892
```
8993

90-
`items` here contains an `AnnotatedItem` for every element in the
94+
`items` here contains an `AnnotatedItem` for every item in the
9195
target crate that has one of the attributes declared in `attributes`
92-
along with attributes sharing the name of the context (`test`, here).
96+
along with attributes sharing the name of the context (`mytest`, here).
9397

9498
A post-build context could declare that it reacts to multiple different
9599
attributes, in which case it would get all items with any of the
96100
listed attributes. These items be modules, functions, structs,
97101
statics, or whatever else the post-build context wants to support. Note
98102
that the post-build context function can only see all the annotated
99103
items, not modify them; modification would have to happen with regular
100-
procedural macros The returned `TokenStream` will become the `main()`
101-
when this post-build context is used.
104+
procedural macros. The returned `TokenStream` must declare the `main()`
105+
that is to become the entry-point for the binary produced when this
106+
post-build context is used.
102107

103108
Because this procedural macro is only loaded when it is used as the
104-
post-build context, the `#[test]` annotation should probably be kept
105-
behind `#[cfg(test)]` so that you don't get unknown attribute warnings
106-
whilst loading. (We could change this by asking attributes to be
107-
registered in Cargo.toml, but we don't find this necessary)
109+
post-build context, the `#[mytest]` annotation should probably be kept
110+
behind `#[cfg(mytest)]` (which is automatically set when the `mytest`
111+
context is used) so that you don't get unknown attribute warnings
112+
whilst loading, and to avoid conflicts with other post-build contexts
113+
that may use the same attributes. (We could change this by asking
114+
attributes to be registered in Cargo.toml, but we don't find this
115+
necessary)
108116

109117
## Cargo integration
110118

@@ -118,87 +126,76 @@ these are named according to the name of their `#[post_build_context]`
118126
function.
119127

120128
Crates which define a post-build context must have an `post-build-context = true`
121-
key.
129+
key in their `Cargo.toml`. It can also specify
122130

123-
For crates that wish to *use* a custom post-build context, they do so by
124-
defining a new post-build context under a new `post-build` section in
125-
their `Cargo.toml`:
131+
```rust
132+
single-target = true # false by default
133+
```
134+
135+
`single-target` indicates that only a single target can be run with this
136+
context at once (some tools, like cargo-fuzz, run forever, and so it
137+
does not make sense to specify multiple targets).
138+
139+
Crates that wish to *use* a custom post-build context, do so by defining
140+
a new post-build context under a new `build-context` section in their
141+
`Cargo.toml`:
126142

127143
```toml
128144
[post-build.context.fuzz]
129145
provider = { rust-fuzz = "1.0" }
130-
folder = "fuzz/"
131-
specify-single-target = true # false by default
146+
folders = ["fuzz/"]
132147
```
133148

134-
This defines a post-build context named `fuzz`, which uses the
149+
This defines an post-build context named `fuzz`, which uses the
135150
implementation provided by the `rust-fuzz` crate. When run, it will be
136-
applies to all files in the `fuzz` directory. `specify-single-target`
137-
addresses whether it must be run with a single target. If true, you will
138-
be forced to run `cargo post-build foobar --test foo`. This is useful for cases
139-
like `cargo-fuzz` where running tests on everything isn't possible.
140-
141-
By default, the following contexts are defined:
151+
applied to all files in the `fuzz` directory. By default, the following
152+
contexts are defined:
142153

143154
```toml
144155
[post-build.context.test]
145156
provider = { test = "1.0", context = "test" }
146-
folder = "tests/"
157+
folders = ["tests/"]
147158

148159
[post-build.context.bench]
149160
provider = { test = "1.0", context = "bench" }
150-
folder = ["benchmarks/", "morebenchmarks/"]
161+
folders = ["benchmarks/"]
151162
```
152163

164+
There's also an `example` context defined that just runs the `main()` of
165+
any files given.
166+
153167
These can be overridden by a crate's `Cargo.toml`. The `context`
154168
property is used to disambiguate when a single crate has multiple
155169
functions tagged `#[post_build_context]` (if we were using the example
156-
post-build provider further up, we'd give `like_todays_test` here).
170+
post-build context further up as a provider, we'd give `mytest` here).
157171
`test` here is `libtest`, though note that it could be maintained
158172
out-of-tree, and shipped with rustup.
159173

160-
To invoke a particular post-build context, a user invokes `cargo post-build
174+
To invoke a particular post-build context, a user invokes `cargo context
161175
<context>`. `cargo test` and `cargo bench` are aliases for `cargo
162-
post-build test` and `cargo post-build bench` respectively. Any additional
176+
context test` and `cargo context bench` respectively. Any additional
163177
arguments are passed to the post-build context binary. By convention, the
164-
first position argument should allow filtering which
165-
test/benchmarks/etc. are run.
166-
167-
168-
By default, the crate has an implicit "test", "bench", and "example" context that use the default libtest stuff.
169-
(example is a no-op context that just runs stuff). However, declaring a context with the name `test`
170-
will replace the existing `test` context. In case you wish to supplement the context, use a different
171-
name.
178+
first position argument should allow filtering which targets
179+
(tests/benchmarks/etc.) are run.
172180

173-
By default, `cargo test` will run doctests and the `test` and `examples` context. This can be customized:
181+
To run multiple contexts at once, a crate can declare post-build context
182+
*sets*. One such example is the `test` post-build context set, which
183+
will run doctests and the `test` and `examples` context. This can be
184+
customized:
174185

175186
```toml
176187
[post-build.set.test]
177188
contexts = [test, quickcheck, examples]
178189
```
179190

180-
This means that `cargo test` will, aside from doctests, run `cargo post-build test`, `cargo post-build quickcheck`,
181-
and `cargo post-build examples` (and similar stuff for `cargo bench`). It is not possible to make `cargo test`
182-
_not_ run doctests.
183-
184-
There are currently only two custom post-build sets (test and bench).
185-
186-
Custom test targets can be declared via `[[post-build.target]]`
187-
188-
```toml
189-
[[post-build.target]]
190-
context = fuzz
191-
path = "foo.rs"
192-
name = "foo"
193-
```
194-
195-
`[[test]]` is an alias for `[[post-build.target]] context = test` (same goes for `[[bench]]` and `[[example]]`).
196-
197-
198-
The generated test binary should be able to take one identifier argument, used for narrowing down what tests to run.
199-
I.e. `cargo test --kind quickcheck my_test_fn` will build the test(s) and call them with `./testbinary my_test_fn`.
200-
Typically, this argument is used to filter tests further; test harnesses should try to use it for the same purpose.
191+
This means that `cargo test` will, aside from doctests, run `cargo
192+
context test`, `cargo context quickcheck`, and `cargo context examples`
193+
(and similar stuff for `cargo bench`). It is not possible to make `cargo
194+
test` _not_ run doctests. If both a context and a set exists with a
195+
given name, the set takes precedence.
201196

197+
`[[test]]` and `[[example]]` in a crate's `Cargo.toml` add files to the
198+
`test` and `example` contexts respectively.
202199

203200
## To be designed
204201

@@ -213,11 +210,6 @@ like json output and whatnot.
213210

214211
@killercup is working on a proposal for this which I will try to work in.
215212

216-
### Configuration
217-
218-
Currently we have `cfg(test)` and `cfg(bench)`. Should `cfg(test)` be applied to all? Should `cfg(nameofharness)`
219-
be used instead? Ideally we'd have a way when declaring a framework to declare what cfgs it should be built with.
220-
221213
# Drawbacks
222214
[drawbacks]: #drawbacks
223215

@@ -231,15 +223,18 @@ be used instead? Ideally we'd have a way when declaring a framework to declare w
231223
# Rationale and alternatives
232224
[alternatives]: #alternatives
233225

234-
We should either do this or stabilize the existing bencher.
226+
We could stabilize `#[bench]` and extend libtest with setup/teardown and
227+
other requested features. This would complicate the in-tree libtest,
228+
introduce a barrier for community contributions, and discourage other
229+
forms of testing or benchmarking.
235230

236231
## Alternative procedural macro
237232

238233
An alternative proposal was to expose an extremely general whole-crate proc macro:
239234

240235
```rust
241-
#[post_build_context(test, attributes(foo, bar))]
242-
pub fn context(crate: TokenStream) -> TokenStream {
236+
#[post_build_context(attributes(foo, bar))]
237+
pub fn mytest(crate: TokenStream) -> TokenStream {
243238
// ...
244239
}
245240
```
@@ -264,7 +259,7 @@ It also lets crates like `cargo-fuzz` introduce things like a `#![no_main]` attr
264259
other antics.
265260

266261
Finally, it handles the "profiling framework" case as mentioned in the motivation. On the other hand,
267-
these tools usually operate at a differeny layer of abstraction so it might not be necessary.
262+
these tools usually operate at a different layer of abstraction so it might not be necessary.
268263

269264
A major drawback of this proposal is that it is very general, and perhaps too powerful. We're currently using the
270265
more focused API in the eRFC, and may switch to this during experimentation if a pressing need crops up.
@@ -304,9 +299,9 @@ there's consensus on some of these we can move them into the main RFC.
304299

305300
Documentation tests are somewhat special, in that they cannot easily be
306301
expressed as `TokenStream` manipulations. In the first instance, the
307-
right thing to do is probably to have an implicitly defined execution
308-
context called `doctest` which is included in the execution context set
309-
`test` by default.
302+
right thing to do is probably to have an implicitly defined post-build
303+
context called `doctest` which is included in the post-build context set
304+
`test` by default (as proposed above).
310305

311306
Another argument for punting on doctests is that they are intended to
312307
demonstrate code that the user of a library would write. They're there
@@ -317,12 +312,12 @@ less sense to have different "ways" of running them.
317312

318313
Today, `cargo test` takes a number of flags such as `--lib`, `--test
319314
foo`, and `--doc`. As it would be a breaking change to change these,
320-
cargo should recognize them and map to the appropriate execution
315+
cargo should recognize them and map to the appropriate post-build
321316
contexts.
322317

323-
Currently, `cargo test` lets you pick a single testing target via `--test`,
318+
Furthermore, `cargo test` lets you pick a single testing target via `--test`,
324319
and `cargo bench` via `--bench`. We'll need to create an agnostic flag
325-
for `cargo post-build` (we cannot use `--target` because it is already used for
320+
for `cargo context` (we cannot use `--target` because it is already used for
326321
the target architecture, and `--test` is too specific for tests). `--post-build-target`
327322
is one rather verbose suggestion.
328323

@@ -333,30 +328,31 @@ stuff so that if test harnesses desire, they can use the same output
333328
formatting as a regular test. This also provides a centralized location
334329
to standardize things like json output and whatnot.
335330

336-
## Configuration
331+
## Namespacing
337332

338-
Currently we have `cfg(test)` and `cfg(bench)`. Should `cfg(test)` be
339-
applied to all? Should `cfg(post_build_context)` be used instead?
340-
Ideally we'd have a way when declaring a post-build context to declare
341-
what cfgs it should be built with.
333+
Currently, two post-build contexts can both declare interest in the same
334+
attributes. How do we deal with collisions (e.g., most test crates will
335+
want the attribute `#[test]`). Do we namespace the attributes by the
336+
context name (e.g., `#[mytest::test]`)? Do we require them to be behind
337+
`#[cfg(mytest)]`?
342338

343339
## Runtime dependencies and flags
344340

345-
The generated harness itself may have some dependencies. Currently there's
346-
no way for the post-build context to specify this. One proposal is for the crate
347-
to specify _runtime_ dependencies of the post-build context via:
341+
The code generated by the post-build context may itself have dependencies.
342+
Currently there's no way for the post-build context to specify this. One
343+
proposal is for the crate to specify _runtime_ dependencies of the
344+
post-build context via:
348345

349346
```toml
350-
[post-build.dependencies]
347+
[context-dependencies]
351348
libfuzzer-sys = ...
352349
```
353350

354-
If a crate is currently running this post-build context, its dev-dependencies
355-
will be semver-merged with the post-build-context.dependencies.
356-
357-
However, this may not be strictly necessary. Custom derives have
358-
a similar problem and they solve it by just asking users to import the correct
359-
crate and keep it in their dev-dependencies.
351+
If a crate is currently running this post-build context, its
352+
dev-dependencies will be semver-merged with the post-build context's
353+
`context-dependencies`. However, this may not be strictly necessary.
354+
Custom derives have a similar problem and they solve it by just asking
355+
users to import the correct crate.
360356

361357
## Naming
362358

@@ -378,7 +374,7 @@ This could be done in the Cargo.toml as:
378374

379375
```toml
380376
[post-build.defaults]
381-
folder = "tests/"
377+
folders = ["tests/"]
382378
set = "test" # will automatically be added to the `test` set
383379
```
384380

@@ -393,21 +389,5 @@ If this RFC lands and [RFC 2287] is rejected, we should probably try to stabiliz
393389
`test::black_box` in some form (maybe `mem::black_box` and `mem::clobber` as detailed
394390
in [this amendment]).
395391

396-
397-
398392
[RFC 2287]: https://github.com/rust-lang/rfcs/pull/2287
399393
[this amendment]: https://github.com/Manishearth/rfcs/pull/1
400-
401-
## Specify-single-target
402-
403-
`specify-single-target = true` probably should be specified by the execution context itself, not the
404-
consumer. It's also questionable if it's necessary -- cargo-fuzz is going to need a wrapper script
405-
anyway, so it's fine if the CLI isn't as ergonomic for that use case.
406-
407-
If we do `post-build.defaults` it would just make sense to include that there.
408-
409-
410-
411-
412-
413-

0 commit comments

Comments
 (0)