doc: Split out task tutorail. Add links to sub-tutorials
This commit is contained in:
parent
6caafaa9ea
commit
fd0de8bfd7
1
configure
vendored
1
configure
vendored
@ -508,6 +508,7 @@ do
|
||||
make_dir $h/test/doc-tutorial-ffi
|
||||
make_dir $h/test/doc-tutorial-macros
|
||||
make_dir $h/test/doc-tutorial-borrowed-ptr
|
||||
make_dir $h/test/doc-tutorial-tasks
|
||||
make_dir $h/test/doc-ref
|
||||
done
|
||||
|
||||
|
173
doc/tutorial-tasks.md
Normal file
173
doc/tutorial-tasks.md
Normal file
@ -0,0 +1,173 @@
|
||||
% Tasks and communication in Rust
|
||||
|
||||
Rust supports a system of lightweight tasks, similar to what is found
|
||||
in Erlang or other actor systems. Rust tasks communicate via messages
|
||||
and do not share data. However, it is possible to send data without
|
||||
copying it by making use of [the exchange heap](#unique-boxes), which
|
||||
allow the sending task to release ownership of a value, so that the
|
||||
receiving task can keep on using it.
|
||||
|
||||
> ***Note:*** As Rust evolves, we expect the task API to grow and
|
||||
> change somewhat. The tutorial documents the API as it exists today.
|
||||
|
||||
# Spawning a task
|
||||
|
||||
Spawning a task is done using the various spawn functions in the
|
||||
module `task`. Let's begin with the simplest one, `task::spawn()`:
|
||||
|
||||
~~~~
|
||||
use task::spawn;
|
||||
use io::println;
|
||||
|
||||
let some_value = 22;
|
||||
|
||||
do spawn {
|
||||
println(~"This executes in the child task.");
|
||||
println(fmt!("%d", some_value));
|
||||
}
|
||||
~~~~
|
||||
|
||||
The argument to `task::spawn()` is a [unique
|
||||
closure](#unique-closures) of type `fn~()`, meaning that it takes no
|
||||
arguments and generates no return value. The effect of `task::spawn()`
|
||||
is to fire up a child task that will execute the closure in parallel
|
||||
with the creator.
|
||||
|
||||
# Communication
|
||||
|
||||
Now that we have spawned a child task, it would be nice if we could
|
||||
communicate with it. This is done using *pipes*. Pipes are simply a
|
||||
pair of endpoints, with one for sending messages and another for
|
||||
receiving messages. The easiest way to create a pipe is to use
|
||||
`pipes::stream`. Imagine we wish to perform two expensive
|
||||
computations in parallel. We might write something like:
|
||||
|
||||
~~~~
|
||||
use task::spawn;
|
||||
use pipes::{stream, Port, Chan};
|
||||
|
||||
let (chan, port) = stream();
|
||||
|
||||
do spawn {
|
||||
let result = some_expensive_computation();
|
||||
chan.send(result);
|
||||
}
|
||||
|
||||
some_other_expensive_computation();
|
||||
let result = port.recv();
|
||||
|
||||
# fn some_expensive_computation() -> int { 42 }
|
||||
# fn some_other_expensive_computation() {}
|
||||
~~~~
|
||||
|
||||
Let's walk through this code line-by-line. The first line creates a
|
||||
stream for sending and receiving integers:
|
||||
|
||||
~~~~ {.ignore}
|
||||
# use pipes::stream;
|
||||
let (chan, port) = stream();
|
||||
~~~~
|
||||
|
||||
This port is where we will receive the message from the child task
|
||||
once it is complete. The channel will be used by the child to send a
|
||||
message to the port. The next statement actually spawns the child:
|
||||
|
||||
~~~~
|
||||
# use task::{spawn};
|
||||
# use comm::{Port, Chan};
|
||||
# fn some_expensive_computation() -> int { 42 }
|
||||
# let port = Port();
|
||||
# let chan = port.chan();
|
||||
do spawn {
|
||||
let result = some_expensive_computation();
|
||||
chan.send(result);
|
||||
}
|
||||
~~~~
|
||||
|
||||
This child will perform the expensive computation send the result
|
||||
over the channel. (Under the hood, `chan` was captured by the
|
||||
closure that forms the body of the child task. This capture is
|
||||
allowed because channels are sendable.)
|
||||
|
||||
Finally, the parent continues by performing
|
||||
some other expensive computation and then waiting for the child's result
|
||||
to arrive on the port:
|
||||
|
||||
~~~~
|
||||
# use pipes::{stream, Port, Chan};
|
||||
# fn some_other_expensive_computation() {}
|
||||
# let (chan, port) = stream::<int>();
|
||||
# chan.send(0);
|
||||
some_other_expensive_computation();
|
||||
let result = port.recv();
|
||||
~~~~
|
||||
|
||||
# Creating a task with a bi-directional communication path
|
||||
|
||||
A very common thing to do is to spawn a child task where the parent
|
||||
and child both need to exchange messages with each other. The
|
||||
function `std::comm::DuplexStream()` supports this pattern. We'll
|
||||
look briefly at how it is used.
|
||||
|
||||
To see how `spawn_conversation()` works, we will create a child task
|
||||
that receives `uint` messages, converts them to a string, and sends
|
||||
the string in response. The child terminates when `0` is received.
|
||||
Here is the function that implements the child task:
|
||||
|
||||
~~~~
|
||||
# use std::comm::DuplexStream;
|
||||
# use pipes::{Port, Chan};
|
||||
fn stringifier(channel: &DuplexStream<~str, uint>) {
|
||||
let mut value: uint;
|
||||
loop {
|
||||
value = channel.recv();
|
||||
channel.send(uint::to_str(value, 10u));
|
||||
if value == 0u { break; }
|
||||
}
|
||||
}
|
||||
~~~~
|
||||
|
||||
The implementation of `DuplexStream` supports both sending and
|
||||
receiving. The `stringifier` function takes a `DuplexStream` that can
|
||||
send strings (the first type parameter) and receive `uint` messages
|
||||
(the second type parameter). The body itself simply loops, reading
|
||||
from the channel and then sending its response back. The actual
|
||||
response itself is simply the strified version of the received value,
|
||||
`uint::to_str(value)`.
|
||||
|
||||
Here is the code for the parent task:
|
||||
|
||||
~~~~
|
||||
# use std::comm::DuplexStream;
|
||||
# use pipes::{Port, Chan};
|
||||
# use task::spawn;
|
||||
# fn stringifier(channel: &DuplexStream<~str, uint>) {
|
||||
# let mut value: uint;
|
||||
# loop {
|
||||
# value = channel.recv();
|
||||
# channel.send(uint::to_str(value, 10u));
|
||||
# if value == 0u { break; }
|
||||
# }
|
||||
# }
|
||||
# fn main() {
|
||||
|
||||
let (from_child, to_child) = DuplexStream();
|
||||
|
||||
do spawn || {
|
||||
stringifier(&to_child);
|
||||
};
|
||||
|
||||
from_child.send(22u);
|
||||
assert from_child.recv() == ~"22";
|
||||
|
||||
from_child.send(23u);
|
||||
from_child.send(0u);
|
||||
|
||||
assert from_child.recv() == ~"23";
|
||||
assert from_child.recv() == ~"0";
|
||||
|
||||
# }
|
||||
~~~~
|
||||
|
||||
The parent task first calls `DuplexStream` to create a pair of bidirectional endpoints. It then uses `task::spawn` to create the child task, which captures one end of the communication channel. As a result, both parent
|
||||
and child can send and receive data to and from the other.
|
277
doc/tutorial.md
277
doc/tutorial.md
@ -7,9 +7,11 @@
|
||||
This is a tutorial for the Rust programming language. It assumes the
|
||||
reader is familiar with the basic concepts of programming, and has
|
||||
programmed in one or more other languages before. It will often make
|
||||
comparisons to other languages in the C family. The tutorial covers
|
||||
the whole language, though not with the depth and precision of the
|
||||
[language reference](rust.html).
|
||||
comparisons to other languages in the C family. This tutorial covers
|
||||
the fundamentals of the language, including the syntax, the type
|
||||
system and memory model, and generics.
|
||||
[Additional tutorials](#what-next) cover specific language features in
|
||||
greater depth.
|
||||
|
||||
## Language overview
|
||||
|
||||
@ -2078,257 +2080,30 @@ This makes it possible to rebind a variable without actually mutating
|
||||
it, which is mostly useful for destructuring (which can rebind, but
|
||||
not assign).
|
||||
|
||||
# Tasks
|
||||
# What next?
|
||||
|
||||
Rust supports a system of lightweight tasks, similar to what is found
|
||||
in Erlang or other actor systems. Rust tasks communicate via messages
|
||||
and do not share data. However, it is possible to send data without
|
||||
copying it by making use of [the exchange heap](#unique-boxes), which
|
||||
allow the sending task to release ownership of a value, so that the
|
||||
receiving task can keep on using it.
|
||||
Now that you know the essentials, check out any of the additional
|
||||
tutorials on individual topics.
|
||||
|
||||
> ***Note:*** As Rust evolves, we expect the task API to grow and
|
||||
> change somewhat. The tutorial documents the API as it exists today.
|
||||
* [Borrowed pointers][borrow]
|
||||
* [Tasks and communication][tasks]
|
||||
* [Macros][macros]
|
||||
* [The foreign function interface][ffi]
|
||||
|
||||
## Spawning a task
|
||||
There is further documentation on the [wiki], including articles about
|
||||
[unit testing] in Rust, [documenting][rustdoc] and [packaging][cargo]
|
||||
Rust code, and a discussion of the [attributes] used to apply metada
|
||||
to code.
|
||||
|
||||
Spawning a task is done using the various spawn functions in the
|
||||
module `task`. Let's begin with the simplest one, `task::spawn()`:
|
||||
[borrow]: tutorial-borrowed-ptr.html
|
||||
[tasks]: tutorial-tasks.html
|
||||
[macros]: tutorial-macros.html
|
||||
[ffi]: tutorial-ffi.html
|
||||
|
||||
~~~~
|
||||
use task::spawn;
|
||||
use io::println;
|
||||
[wiki]: https://github.com/mozilla/rust/wiki/Docs
|
||||
[unit testing]: https://github.com/mozilla/rust/wiki/Doc-unit-testing
|
||||
[rustdoc]: https://github.com/mozilla/rust/wiki/Doc-using-rustdoc
|
||||
[cargo]: https://github.com/mozilla/rust/wiki/Doc-using-cargo-to-manage-packages
|
||||
[attributes]: https://github.com/mozilla/rust/wiki/Doc-attributes
|
||||
|
||||
let some_value = 22;
|
||||
|
||||
do spawn {
|
||||
println(~"This executes in the child task.");
|
||||
println(fmt!("%d", some_value));
|
||||
}
|
||||
~~~~
|
||||
|
||||
The argument to `task::spawn()` is a [unique
|
||||
closure](#unique-closures) of type `fn~()`, meaning that it takes no
|
||||
arguments and generates no return value. The effect of `task::spawn()`
|
||||
is to fire up a child task that will execute the closure in parallel
|
||||
with the creator.
|
||||
|
||||
## Communication
|
||||
|
||||
Now that we have spawned a child task, it would be nice if we could
|
||||
communicate with it. This is done using *pipes*. Pipes are simply a
|
||||
pair of endpoints, with one for sending messages and another for
|
||||
receiving messages. The easiest way to create a pipe is to use
|
||||
`pipes::stream`. Imagine we wish to perform two expensive
|
||||
computations in parallel. We might write something like:
|
||||
|
||||
~~~~
|
||||
use task::spawn;
|
||||
use pipes::{stream, Port, Chan};
|
||||
|
||||
let (chan, port) = stream();
|
||||
|
||||
do spawn {
|
||||
let result = some_expensive_computation();
|
||||
chan.send(result);
|
||||
}
|
||||
|
||||
some_other_expensive_computation();
|
||||
let result = port.recv();
|
||||
|
||||
# fn some_expensive_computation() -> int { 42 }
|
||||
# fn some_other_expensive_computation() {}
|
||||
~~~~
|
||||
|
||||
Let's walk through this code line-by-line. The first line creates a
|
||||
stream for sending and receiving integers:
|
||||
|
||||
~~~~ {.ignore}
|
||||
# use pipes::stream;
|
||||
let (chan, port) = stream();
|
||||
~~~~
|
||||
|
||||
This port is where we will receive the message from the child task
|
||||
once it is complete. The channel will be used by the child to send a
|
||||
message to the port. The next statement actually spawns the child:
|
||||
|
||||
~~~~
|
||||
# use task::{spawn};
|
||||
# use comm::{Port, Chan};
|
||||
# fn some_expensive_computation() -> int { 42 }
|
||||
# let port = Port();
|
||||
# let chan = port.chan();
|
||||
do spawn {
|
||||
let result = some_expensive_computation();
|
||||
chan.send(result);
|
||||
}
|
||||
~~~~
|
||||
|
||||
This child will perform the expensive computation send the result
|
||||
over the channel. (Under the hood, `chan` was captured by the
|
||||
closure that forms the body of the child task. This capture is
|
||||
allowed because channels are sendable.)
|
||||
|
||||
Finally, the parent continues by performing
|
||||
some other expensive computation and then waiting for the child's result
|
||||
to arrive on the port:
|
||||
|
||||
~~~~
|
||||
# use pipes::{stream, Port, Chan};
|
||||
# fn some_other_expensive_computation() {}
|
||||
# let (chan, port) = stream::<int>();
|
||||
# chan.send(0);
|
||||
some_other_expensive_computation();
|
||||
let result = port.recv();
|
||||
~~~~
|
||||
|
||||
## Creating a task with a bi-directional communication path
|
||||
|
||||
A very common thing to do is to spawn a child task where the parent
|
||||
and child both need to exchange messages with each other. The
|
||||
function `std::comm::DuplexStream()` supports this pattern. We'll
|
||||
look briefly at how it is used.
|
||||
|
||||
To see how `spawn_conversation()` works, we will create a child task
|
||||
that receives `uint` messages, converts them to a string, and sends
|
||||
the string in response. The child terminates when `0` is received.
|
||||
Here is the function that implements the child task:
|
||||
|
||||
~~~~
|
||||
# use std::comm::DuplexStream;
|
||||
# use pipes::{Port, Chan};
|
||||
fn stringifier(channel: &DuplexStream<~str, uint>) {
|
||||
let mut value: uint;
|
||||
loop {
|
||||
value = channel.recv();
|
||||
channel.send(uint::to_str(value, 10u));
|
||||
if value == 0u { break; }
|
||||
}
|
||||
}
|
||||
~~~~
|
||||
|
||||
The implementation of `DuplexStream` supports both sending and
|
||||
receiving. The `stringifier` function takes a `DuplexStream` that can
|
||||
send strings (the first type parameter) and receive `uint` messages
|
||||
(the second type parameter). The body itself simply loops, reading
|
||||
from the channel and then sending its response back. The actual
|
||||
response itself is simply the strified version of the received value,
|
||||
`uint::to_str(value)`.
|
||||
|
||||
Here is the code for the parent task:
|
||||
|
||||
~~~~
|
||||
# use std::comm::DuplexStream;
|
||||
# use pipes::{Port, Chan};
|
||||
# use task::spawn;
|
||||
# fn stringifier(channel: &DuplexStream<~str, uint>) {
|
||||
# let mut value: uint;
|
||||
# loop {
|
||||
# value = channel.recv();
|
||||
# channel.send(uint::to_str(value, 10u));
|
||||
# if value == 0u { break; }
|
||||
# }
|
||||
# }
|
||||
# fn main() {
|
||||
|
||||
let (from_child, to_child) = DuplexStream();
|
||||
|
||||
do spawn || {
|
||||
stringifier(&to_child);
|
||||
};
|
||||
|
||||
from_child.send(22u);
|
||||
assert from_child.recv() == ~"22";
|
||||
|
||||
from_child.send(23u);
|
||||
from_child.send(0u);
|
||||
|
||||
assert from_child.recv() == ~"23";
|
||||
assert from_child.recv() == ~"0";
|
||||
|
||||
# }
|
||||
~~~~
|
||||
|
||||
The parent task first calls `DuplexStream` to create a pair of bidirectional endpoints. It then uses `task::spawn` to create the child task, which captures one end of the communication channel. As a result, both parent
|
||||
and child can send and receive data to and from the other.
|
||||
|
||||
# Testing
|
||||
|
||||
The Rust language has a facility for testing built into the language.
|
||||
Tests can be interspersed with other code, and annotated with the
|
||||
`#[test]` attribute.
|
||||
|
||||
~~~~{.xfail-test}
|
||||
# // FIXME: xfailed because test_twice is a #[test] function it's not
|
||||
# // getting compiled
|
||||
extern mod std;
|
||||
|
||||
fn twice(x: int) -> int { x + x }
|
||||
|
||||
#[test]
|
||||
fn test_twice() {
|
||||
let mut i = -100;
|
||||
while i < 100 {
|
||||
assert twice(i) == 2 * i;
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
~~~~
|
||||
|
||||
When you compile the program normally, the `test_twice` function will
|
||||
not be included. To compile and run such tests, compile with the
|
||||
`--test` flag, and then run the result:
|
||||
|
||||
~~~~ {.notrust}
|
||||
> rustc --test twice.rs
|
||||
> ./twice
|
||||
running 1 tests
|
||||
test test_twice ... ok
|
||||
result: ok. 1 passed; 0 failed; 0 ignored
|
||||
~~~~
|
||||
|
||||
Or, if we change the file to fail, for example by replacing `x + x`
|
||||
with `x + 1`:
|
||||
|
||||
~~~~ {.notrust}
|
||||
running 1 tests
|
||||
test test_twice ... FAILED
|
||||
failures:
|
||||
test_twice
|
||||
result: FAILED. 0 passed; 1 failed; 0 ignored
|
||||
~~~~
|
||||
|
||||
You can pass a command-line argument to a program compiled with
|
||||
`--test` to run only the tests whose name matches the given string. If
|
||||
we had, for example, test functions `test_twice`, `test_once_1`, and
|
||||
`test_once_2`, running our program with `./twice test_once` would run
|
||||
the latter two, and running it with `./twice test_once_2` would run
|
||||
only the last.
|
||||
|
||||
To indicate that a test is supposed to fail instead of pass, you can
|
||||
give it a `#[should_fail]` attribute.
|
||||
|
||||
~~~~
|
||||
extern mod std;
|
||||
|
||||
fn divide(a: float, b: float) -> float {
|
||||
if b == 0f { fail; }
|
||||
a / b
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_fail]
|
||||
fn divide_by_zero() { divide(1f, 0f); }
|
||||
|
||||
# fn main() { }
|
||||
~~~~
|
||||
|
||||
To disable a test completely, add an `#[ignore]` attribute. Running a
|
||||
test runner (the program compiled with `--test`) with an `--ignored`
|
||||
command-line flag will cause it to also run the tests labelled as
|
||||
ignored.
|
||||
|
||||
A program compiled as a test runner will have the configuration flag
|
||||
`test` defined, so that you can add code that won't be included in a
|
||||
normal compile with the `#[cfg(test)]` attribute (for a full explanation
|
||||
of attributes, see the [language reference](rust.html)).
|
||||
[pound-rust]: http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust
|
||||
|
10
mk/docs.mk
10
mk/docs.mk
@ -113,6 +113,16 @@ doc/tutorial-borrowed-ptr.html: tutorial-borrowed-ptr.md doc/version_info.html d
|
||||
--include-before-body=doc/version_info.html \
|
||||
--output=$@
|
||||
|
||||
DOCS += doc/tutorial-tasks.html
|
||||
doc/tutorial-tasks.html: tutorial-tasks.md doc/version_info.html doc/rust.css
|
||||
@$(call E, pandoc: $@)
|
||||
$(Q)$(CFG_NODE) $(S)doc/prep.js --highlight $< | \
|
||||
$(CFG_PANDOC) --standalone --toc \
|
||||
--section-divs --number-sections \
|
||||
--from=markdown --to=html --css=rust.css \
|
||||
--include-before-body=doc/version_info.html \
|
||||
--output=$@
|
||||
|
||||
endif
|
||||
endif
|
||||
|
||||
|
27
mk/tests.mk
27
mk/tests.mk
@ -179,6 +179,11 @@ doc-tutorial-borrowed-ptr-extract$(1):
|
||||
$$(Q)rm -f $(1)/test/doc-tutorial-borrowed-ptr/*.rs
|
||||
$$(Q)$$(EXTRACT_TESTS) $$(S)doc/tutorial-borrowed-ptr.md $(1)/test/doc-tutorial-borrowed-ptr
|
||||
|
||||
doc-tutorial-tasks-extract$(1):
|
||||
@$$(call E, extract: tutorial-tasks tests)
|
||||
$$(Q)rm -f $(1)/test/doc-tutorial-tasks/*.rs
|
||||
$$(Q)$$(EXTRACT_TESTS) $$(S)doc/tutorial-tasks.md $(1)/test/doc-tutorial-tasks
|
||||
|
||||
doc-ref-extract$(1):
|
||||
@$$(call E, extract: ref tests)
|
||||
$$(Q)rm -f $(1)/test/doc-ref/*.rs
|
||||
@ -229,6 +234,7 @@ check-stage$(1)-T-$(2)-H-$(3): \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-doc-tutorial-ffi \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-doc-tutorial-macros \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-doc-tutorial-borrowed-ptr \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-doc-tutorial-tasks \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-doc-ref
|
||||
|
||||
check-stage$(1)-T-$(2)-H-$(3)-core: \
|
||||
@ -298,6 +304,9 @@ check-stage$(1)-T-$(2)-H-$(3)-doc-tutorial-macros: \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-doc-tutorial-borrowed-ptr: \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-doc-tutorial-borrowed-ptr-dummy
|
||||
|
||||
check-stage$(1)-T-$(2)-H-$(3)-doc-tutorial-tasks: \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-doc-tutorial-tasks-dummy
|
||||
|
||||
check-stage$(1)-T-$(2)-H-$(3)-doc-ref: \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-doc-ref-dummy
|
||||
|
||||
@ -485,6 +494,12 @@ DOC_TUTORIAL_BORROWED_PTR_ARGS$(1)-T-$(2)-H-$(3) := \
|
||||
--build-base $(3)/test/doc-tutorial-borrowed-ptr/ \
|
||||
--mode run-pass
|
||||
|
||||
DOC_TUTORIAL_TASKS_ARGS$(1)-T-$(2)-H-$(3) := \
|
||||
$$(CTEST_COMMON_ARGS$(1)-T-$(2)-H-$(3)) \
|
||||
--src-base $(3)/test/doc-tutorial-tasks/ \
|
||||
--build-base $(3)/test/doc-tutorial-tasks/ \
|
||||
--mode run-pass
|
||||
|
||||
DOC_REF_ARGS$(1)-T-$(2)-H-$(3) := \
|
||||
$$(CTEST_COMMON_ARGS$(1)-T-$(2)-H-$(3)) \
|
||||
--src-base $(3)/test/doc-ref/ \
|
||||
@ -611,6 +626,14 @@ check-stage$(1)-T-$(2)-H-$(3)-doc-tutorial-borrowed-ptr-dummy: \
|
||||
$$(DOC_TUTORIAL_BORROWED_PTR_ARGS$(1)-T-$(2)-H-$(3)) \
|
||||
--logfile tmp/check-stage$(1)-T-$(2)-H-$(3)-doc-tutorial-borrowed-ptr.log
|
||||
|
||||
check-stage$(1)-T-$(2)-H-$(3)-doc-tutorial-tasks-dummy: \
|
||||
$$(TEST_SREQ$(1)_T_$(2)_H_$(3)) \
|
||||
doc-tutorial-tasks-extract$(3)
|
||||
@$$(call E, run doc-tutorial-tasks: $$<)
|
||||
$$(Q)$$(call CFG_RUN_CTEST,$(1),$$<,$(3)) \
|
||||
$$(DOC_TUTORIAL_TASKS_ARGS$(1)-T-$(2)-H-$(3)) \
|
||||
--logfile tmp/check-stage$(1)-T-$(2)-H-$(3)-doc-tutorial-tasks.log
|
||||
|
||||
check-stage$(1)-T-$(2)-H-$(3)-doc-ref-dummy: \
|
||||
$$(TEST_SREQ$(1)_T_$(2)_H_$(3)) \
|
||||
doc-ref-extract$(3)
|
||||
@ -748,6 +771,9 @@ check-stage$(1)-H-$(2)-doc-tutorial-macros: \
|
||||
check-stage$(1)-H-$(2)-doc-tutorial-borrowed-ptr: \
|
||||
$$(foreach target,$$(CFG_TARGET_TRIPLES), \
|
||||
check-stage$(1)-T-$$(target)-H-$(2)-doc-tutorial-borrowed-ptr)
|
||||
check-stage$(1)-H-$(2)-doc-tutorial-tasks: \
|
||||
$$(foreach target,$$(CFG_TARGET_TRIPLES), \
|
||||
check-stage$(1)-T-$$(target)-H-$(2)-doc-tutorial-tasks)
|
||||
check-stage$(1)-H-$(2)-doc-ref: \
|
||||
$$(foreach target,$$(CFG_TARGET_TRIPLES), \
|
||||
check-stage$(1)-T-$$(target)-H-$(2)-doc-ref)
|
||||
@ -859,6 +885,7 @@ check-stage$(1)-doc-tutorial: check-stage$(1)-H-$$(CFG_HOST_TRIPLE)-doc-tutorial
|
||||
check-stage$(1)-doc-tutorial-ffi: check-stage$(1)-H-$$(CFG_HOST_TRIPLE)-doc-tutorial-ffi
|
||||
check-stage$(1)-doc-tutorial-macros: check-stage$(1)-H-$$(CFG_HOST_TRIPLE)-doc-tutorial-macros
|
||||
check-stage$(1)-doc-tutorial-borrowed-ptr: check-stage$(1)-H-$$(CFG_HOST_TRIPLE)-doc-tutorial-borrowed-ptr
|
||||
check-stage$(1)-doc-tutorial-tasks: check-stage$(1)-H-$$(CFG_HOST_TRIPLE)-doc-tutorial-tasks
|
||||
check-stage$(1)-doc-ref: check-stage$(1)-H-$$(CFG_HOST_TRIPLE)-doc-ref
|
||||
|
||||
endef
|
||||
|
Loading…
Reference in New Issue
Block a user