aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar David Chen <dzc@google.com>2015-10-05 12:21:32 +0000
committerGravatar Damien Martin-Guillerez <dmarting@google.com>2015-10-05 15:16:40 +0000
commitab141f8d1035eb30bbb9dc09d89ea6a3ba83cc0f (patch)
tree587e9401adeb385d3d859a3c4458b7d7945f2674
parent73ee6215490ed957c13c8dbe03814b039d6ddd5c (diff)
[rust] Add rust_bench_test and rust_doc_test rules and improve usability of rust_test rule.
* Add rust_bench_test rule to run benchmark tests * Add rust_doc_test rule to run Rust documentation tests. * Enable rust_test and rust_bench_test to depend directly on a rust_library target. * Rename rust_docs rule to rust_doc for consistency. RELNOTES: [rust] Add rust_bench_test and rust_doc_test rules and improve usability of rust_test tule. -- MOS_MIGRATED_REVID=104648497
-rw-r--r--WORKSPACE2
-rw-r--r--examples/rust/fibonacci/BUILD36
-rw-r--r--examples/rust/fibonacci/benches/fibonacci_bench.rs25
-rw-r--r--examples/rust/fibonacci/src/lib.rs48
-rw-r--r--examples/rust/hello_lib/BUILD26
-rw-r--r--examples/rust/hello_lib/src/greeter.rs11
-rw-r--r--examples/rust/hello_world/BUILD6
-rw-r--r--tools/build_rules/rust/README.md719
-rw-r--r--tools/build_rules/rust/rust.BUILD28
-rw-r--r--tools/build_rules/rust/rust.bzl263
10 files changed, 973 insertions, 191 deletions
diff --git a/WORKSPACE b/WORKSPACE
index b3aebe8e76..f9d107a03c 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -47,6 +47,7 @@ new_http_archive(
url = "https://static.rust-lang.org/dist/rust-1.3.0-x86_64-unknown-linux-gnu.tar.gz",
sha256 = "fa755b6331ff7554e6e8545ee20af7897b0adc65f471dd24ae8a467a944755b4",
build_file = "tools/build_rules/rust/rust.BUILD",
+ strip_prefix = "rust-1.3.0-x86_64-unknown-linux-gnu",
)
new_http_archive(
@@ -54,6 +55,7 @@ new_http_archive(
url = "https://static.rust-lang.org/dist/rust-1.3.0-x86_64-apple-darwin.tar.gz",
sha256 = "bfeac876e22cc5fe63a250644ce1a6f3892c13a5461131a881419bd06fcb2011",
build_file = "tools/build_rules/rust/rust.BUILD",
+ strip_prefix = "rust-1.3.0-x86_64-apple-darwin",
)
# In order to run the Android integration tests, uncomment these rules, point
diff --git a/examples/rust/fibonacci/BUILD b/examples/rust/fibonacci/BUILD
new file mode 100644
index 0000000000..a29e2123ba
--- /dev/null
+++ b/examples/rust/fibonacci/BUILD
@@ -0,0 +1,36 @@
+package(default_visibility = ["//visibility:public"])
+
+load(
+ "/tools/build_rules/rust/rust",
+ "rust_library",
+ "rust_test",
+ "rust_bench_test",
+ "rust_doc",
+ "rust_doc_test",
+)
+
+rust_library(
+ name = "fibonacci",
+ srcs = ["src/lib.rs"],
+)
+
+rust_test(
+ name = "fibonacci_test",
+ deps = [":fibonacci"],
+)
+
+rust_bench_test(
+ name = "fibonacci_bench",
+ srcs = ["benches/fibonacci_bench.rs"],
+ deps = [":fibonacci"],
+)
+
+rust_doc(
+ name = "fibonacci_doc",
+ dep = ":fibonacci",
+)
+
+rust_doc_test(
+ name = "fibonacci_doc_test",
+ dep = ":fibonacci",
+)
diff --git a/examples/rust/fibonacci/benches/fibonacci_bench.rs b/examples/rust/fibonacci/benches/fibonacci_bench.rs
new file mode 100644
index 0000000000..80aa1a84ce
--- /dev/null
+++ b/examples/rust/fibonacci/benches/fibonacci_bench.rs
@@ -0,0 +1,25 @@
+// Copyright 2015 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#![feature(test)]
+
+extern crate test;
+extern crate fibonacci;
+
+use test::Bencher;
+
+#[bench]
+fn bench_fibonacci(b: &mut Bencher) {
+ b.iter(|| fibonacci::fibonacci(40));
+}
diff --git a/examples/rust/fibonacci/src/lib.rs b/examples/rust/fibonacci/src/lib.rs
new file mode 100644
index 0000000000..d8ae6e3fca
--- /dev/null
+++ b/examples/rust/fibonacci/src/lib.rs
@@ -0,0 +1,48 @@
+// Copyright 2015 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/// Returns the nth Fibonacci number.
+///
+/// # Examples
+///
+/// ```
+/// fibonacci::fibonacci(5)
+/// ```
+pub fn fibonacci(n: u64) -> u64 {
+ if n < 2 {
+ return n;
+ }
+ let mut n1: u64 = 0;
+ let mut n2: u64 = 1;
+ for _ in 1..n {
+ let sum = n1 + n2;
+ n1 = n2;
+ n2 = sum;
+ }
+ n2
+}
+
+#[cfg(test)]
+mod test {
+ use super::fibonacci;
+
+ #[test]
+ fn test_fibonacci() {
+ let numbers : Vec<u64> =
+ vec![0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144];
+ for (i, number) in numbers.iter().enumerate() {
+ assert_eq!(*number, fibonacci(i as u64));
+ }
+ }
+}
diff --git a/examples/rust/hello_lib/BUILD b/examples/rust/hello_lib/BUILD
index a075f8b168..90941e6a42 100644
--- a/examples/rust/hello_lib/BUILD
+++ b/examples/rust/hello_lib/BUILD
@@ -1,6 +1,12 @@
package(default_visibility = ["//visibility:public"])
-load("/tools/build_rules/rust/rust", "rust_library", "rust_docs", "rust_test")
+load(
+ "/tools/build_rules/rust/rust",
+ "rust_library",
+ "rust_test",
+ "rust_doc",
+ "rust_doc_test",
+)
rust_library(
name = "hello_lib",
@@ -10,13 +16,23 @@ rust_library(
],
)
-rust_docs(
- name = "hello_lib_docs",
- dep = ":hello_lib",
+rust_test(
+ name = "hello_lib_test",
+ deps = [":hello_lib"],
)
rust_test(
- name = "greeting",
+ name = "greeting_test",
srcs = ["tests/greeting.rs"],
deps = [":hello_lib"],
)
+
+rust_doc(
+ name = "hello_lib_doc",
+ dep = ":hello_lib",
+)
+
+rust_doc_test(
+ name = "hello_lib_doc_test",
+ dep = ":hello_lib",
+)
diff --git a/examples/rust/hello_lib/src/greeter.rs b/examples/rust/hello_lib/src/greeter.rs
index 2a7d7153b9..bf332e4bd1 100644
--- a/examples/rust/hello_lib/src/greeter.rs
+++ b/examples/rust/hello_lib/src/greeter.rs
@@ -60,3 +60,14 @@ impl Greeter {
println!("{} {}", &self.greeting, thing);
}
}
+
+#[cfg(test)]
+mod test {
+ use super::Greeter;
+
+ #[test]
+ fn test_greeting() {
+ let hello = Greeter::new("Hi");
+ assert_eq!("Hi Rust", hello.greeting("Rust"));
+ }
+}
diff --git a/examples/rust/hello_world/BUILD b/examples/rust/hello_world/BUILD
index ccd87f1b93..1f5365675b 100644
--- a/examples/rust/hello_world/BUILD
+++ b/examples/rust/hello_world/BUILD
@@ -1,6 +1,6 @@
package(default_visibility = ["//visibility:public"])
-load("/tools/build_rules/rust/rust", "rust_binary", "rust_docs")
+load("/tools/build_rules/rust/rust", "rust_binary", "rust_doc")
rust_binary(
name = "hello_world",
@@ -8,7 +8,7 @@ rust_binary(
deps = ["//examples/rust/hello_lib"],
)
-rust_docs(
- name = "hello_world_docs",
+rust_doc(
+ name = "hello_world_doc",
dep = ":hello_world",
)
diff --git a/tools/build_rules/rust/README.md b/tools/build_rules/rust/README.md
index 536c10f837..a040ad306f 100644
--- a/tools/build_rules/rust/README.md
+++ b/tools/build_rules/rust/README.md
@@ -1,18 +1,16 @@
# Rust Rules for Bazel
+* [`rust_library`](#rust_library)
+* [`rust_binary`](#rust_binary)
+* [`rust_test`](#rust_test)
+* [`rust_bench_test`](#rust_bench_test)
+* [`rust_doc`](#rust_doc)
+* [`rust_doc_test`](#rust_doc_test)
+
## Overview
These build rules are used for building [Rust][rust] projects with Bazel.
-* [Setup](#setup)
-* [Basic Example](#basic-example)
-* [Build Rule Reference](#reference)
- * [`rust_library`](#reference-rust_library)
- * [`rust_binary`](#reference-rust_binary)
- * [`rust_test`](#reference-rust_test)
- * [`rust_docs`](#reference-rust_docs)
-* [Roadmap](#roadmap)
-
[rust]: http://www.rust-lang.org/
<a name="setup"></a>
@@ -21,8 +19,121 @@ These build rules are used for building [Rust][rust] projects with Bazel.
To use the Rust rules, simply copy the contents of `rust.WORKSPACE` to your
`WORKSPACE` file.
-<a name="basic-example"></a>
-## Basic Example
+<a name="roadmap"></a>
+## Roadmap
+
+* Add `rust_toolchain` rule to make it easy to use a custom Rust toolchain.
+* Add tool for taking `Cargo.toml` and generating a `WORKSPACE` file with
+ workspace rules for pulling external dependencies.
+* Improve expressiveness of features and support for [Cargo's feature
+ groups](http://doc.crates.io/manifest.html#the-[features]-section).
+* Add `cargo_crate` workspace rule for pulling crates from
+ [Cargo](https://crates.io/).
+
+<a name="rust_library"></a>
+## rust_library
+
+```python
+rust_library(name, srcs, deps, data, crate_features, rustc_flags)
+```
+
+<table>
+ <thead>
+ <tr>
+ <th>Attribute</th>
+ <th>Description</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td><code>name</code></td>
+ <td>
+ <code>Name, required</code>
+ <p>A unique name for this rule.</p>
+ <p>
+ This name will also be used as the name of the library crate built by
+ this rule.
+ </p>
+ </td>
+ </tr>
+ <tr>
+ <td><code>srcs</code></td>
+ <td>
+ <code>List of labels, required</code>
+ <p>List of Rust <code>.rs</code> source files used to build the
+ library.</p>
+ <p>
+ If <code>srcs</code> contains more than one file, then there must be
+ a file either named <code>lib.rs</code>. Otherwise,
+ <code>crate_root</code> must be set to the source file that is the
+ root of the crate to be passed to <code>rustc</code> to build this
+ crate.
+ </p>
+ </td>
+ </tr>
+ <tr>
+ <td><code>crate_root</code></td>
+ <td>
+ <code>Label, optional</code>
+ <p>
+ The file that will be passed to <code>rustc</code> to be used for
+ building this crate.
+ </p>
+ <p>
+ If <code>crate_root</code> is not set, then this rule will look for
+ a <code>lib.rs</code> file or the single file in <code>srcs</code>
+ if <code>srcs</code> contains only one file.
+ </p>
+ </td>
+ </td>
+ <tr>
+ <td><code>deps</code></td>
+ <td>
+ <code>List of labels, optional</code>
+ <p>List of other libraries to be linked to this library target.</p>
+ <p>
+ These can be either other <code>rust_library</code> targets or
+ <code>cc_library</code> targets if linking a native library.
+ </p>
+ </td>
+ </tr>
+ <tr>
+ <td><code>data</code></td>
+ <td>
+ <code>List of labels, optional</code>
+ <p>List of files used by this rule at runtime.</p>
+ <p>
+ This attribute can be used to specify any data files that are embedded
+ into the library, such as via the
+ <a href="https://doc.rust-lang.org/std/macro.include_str!.html target="_blank"><code>include_str!</code></a>
+ macro.
+ </p>
+ </td>
+ </tr>
+ <tr>
+ <td><code>crate_features</code></td>
+ <td>
+ <code>List of strings, optional</code>
+ <p>List of features to enable for this crate.</p>
+ <p>
+ Features are defined in the code using the
+ <code>#[cfg(feature = "foo")]</code> configuration option. The
+ features listed here will be passed to <code>rustc</code> with
+ <code>--cfg feature="${feature_name}"</code> flags.
+ </p>
+ </td>
+ </tr>
+ <tr>
+ <td><code>rustc_flags</code></td>
+ <td>
+ <code>List of strings, optional</code>
+ <p>List of compiler flags passed to <code>rustc</code>.</p>
+ </td>
+ </tr>
+ </tbody>
+</table>
+
+### Example
Suppose you have the following directory structure for a simple Rust library
crate:
@@ -88,69 +199,13 @@ Target //examples/rust/hello_lib:hello_lib up-to-date:
INFO: Elapsed time: 1.245s, Critical Path: 1.01s
```
-Now, let's add a binary crate that uses the `hello_lib` library. The directory
-structure now looks like the following:
+<a name="rust_binary"></a>
+## rust_binary
```
-[workspace]/
- WORKSPACE
- hello_lib/
- BUILD
- src/
- greeter.rs
- lib.rs
- hello_world/
- BUILD
- src/
- main.rs
+rust_binary(name, srcs, deps, data, crate_features, rustc_flags)
```
-`hello_world/src/main.rs`:
-
-```rust
-extern crate hello_lib;
-
-use hello_lib::greeter;
-
-fn main() {
- let hello = greeter::Greeter::new("Hello");
- hello.greet("world");
-}
-```
-
-`hello_world/BUILD`:
-
-```python
-load("/tools/build_rules/rust/rust", "rust_binary")
-
-rust_binary(
- name = "hello_world",
- srcs = ["src/main.rs"],
- deps = ["//hello_lib"],
-)
-```
-
-Build and run `hello_world`:
-
-```
-$ bazel run //hello_world
-INFO: Found 1 target...
-Target //examples/rust/hello_world:hello_world up-to-date:
- bazel-bin/examples/rust/hello_world/hello_world
-INFO: Elapsed time: 1.308s, Critical Path: 1.22s
-
-INFO: Running command line: bazel-bin/examples/rust/hello_world/hello_world
-Hello world
-```
-
-<a name="reference"></a>
-## Build Rule Reference
-
-<a name="reference-rust_library"></a>
-### `rust_library`
-
-`rust_library(name, srcs, deps, data, crate_features, rustc_flags)`
-
<table>
<thead>
<tr>
@@ -165,7 +220,7 @@ Hello world
<code>Name, required</code>
<p>A unique name for this rule.</p>
<p>
- This name will also be used as the name of the library crate built by
+ This name will also be used as the name of the binary crate built by
this rule.
</p>
</td>
@@ -175,24 +230,38 @@ Hello world
<td>
<code>List of labels, required</code>
<p>List of Rust <code>.rs</code> source files used to build the
- library.</p>
+ binary.</p>
<p>
- There must be a file either named <code>lib.rs</code> or with a name
- matching the name of this crate. For example, if the name of a given
- rule is <code>foo</code>, then there must be a file named
- <code>lib.rs</code> or <code>foo.rs</code> in <code>srcs</code>.
- This file will be passed to <code>rustc</code> as the crate root.
+ If <code>srcs</code> contains more than one file, then there must be
+ a file either named <code>main.rs</code>. Otherwise,
+ <code>crate_root</code> must be set to the source file that is the
+ root of the crate to be passed to <code>rustc</code> to build this
+ crate.
</p>
</td>
</tr>
<tr>
+ <td><code>crate_root</code></td>
+ <td>
+ <code>Label, optional</code>
+ <p>
+ The file that will be passed to <code>rustc</code> to be used for
+ building this crate.
+ </p>
+ <p>
+ If <code>crate_root</code> is not set, then this rule will look for
+ a <code>main.rs</code> file or the single file in <code>srcs</code>
+ if <code>srcs</code> contains only one file.
+ </p>
+ </td>
+ </td>
+ <tr>
<td><code>deps</code></td>
<td>
<code>List of labels, optional</code>
<p>List of other libraries to be linked to this library target.</p>
<p>
- These can be either other <code>rust_library</code> targets or
- <code>cc_library</code> targets if linking a native library.
+ These must be <code>rust_library</code> targets.
</p>
</td>
</tr>
@@ -232,10 +301,98 @@ Hello world
</tbody>
</table>
-<a name="reference-rust_binary"></a>
-### `rust_binary`
+### Example
+
+Suppose you have the following directory structure for a Rust project with a
+library crate, `hello_lib`, and a binary crate, `hello_world` that uses the
+`hello_lib` library:
+
+```
+[workspace]/
+ WORKSPACE
+ hello_lib/
+ BUILD
+ src/
+ lib.rs
+ hello_world/
+ BUILD
+ src/
+ main.rs
+```
+
+`hello_lib/src/lib.rs`:
+
+```rust
+pub struct Greeter {
+ greeting: String,
+}
+
+impl Greeter {
+ pub fn new(greeting: &str) -> Greeter {
+ Greeter { greeting: greeting.to_string(), }
+ }
+
+ pub fn greet(&self, thing: &str) {
+ println!("{} {}", &self.greeting, thing);
+ }
+}
+```
+
+`hello_lib/BUILD`:
+
+```python
+package(default_visibility = ["//visibility:public"])
+
+load("/tools/build_rules/rust/rust", "rust_library")
+
+rust_library(
+ name = "hello_lib",
+ srcs = ["src/lib.rs"],
+)
+```
+
+`hello_world/src/main.rs`:
+
+```rust
+extern crate hello_lib;
+
+fn main() {
+ let hello = hello_lib::Greeter::new("Hello");
+ hello.greet("world");
+}
+```
+
+`hello_world/BUILD`:
+
+```python
+load("/tools/build_rules/rust/rust", "rust_binary")
+
+rust_binary(
+ name = "hello_world",
+ srcs = ["src/main.rs"],
+ deps = ["//hello_lib"],
+)
+```
+
+Build and run `hello_world`:
-`rust_binary(name, srcs, deps, data, crate_features, rustc_flags)`
+```
+$ bazel run //hello_world
+INFO: Found 1 target...
+Target //examples/rust/hello_world:hello_world up-to-date:
+ bazel-bin/examples/rust/hello_world/hello_world
+INFO: Elapsed time: 1.308s, Critical Path: 1.22s
+
+INFO: Running command line: bazel-bin/examples/rust/hello_world/hello_world
+Hello world
+```
+
+<a name="rust_test"></a>
+## rust_test
+
+```python
+rust_test(name, srcs, deps, data, crate_features, rustc_flags)
+```
<table>
<thead>
@@ -251,8 +408,8 @@ Hello world
<code>Name, required</code>
<p>A unique name for this rule.</p>
<p>
- This name will also be used as the name of the binary crate built by
- this rule.
+ This name will also be used as the name of the binary test crate
+ built by this rule.
</p>
</td>
</tr>
@@ -261,22 +418,36 @@ Hello world
<td>
<code>List of labels, required</code>
<p>List of Rust <code>.rs</code> source files used to build the
- binary.</p>
+ library.</p>
<p>
- There must be a file either named <code>main.rs</code> or with a name
- matching the name of this crate that contains the <code>main</code>
- function. For example, if the name of a given
- rule is <code>foo</code>, then there must be a file named
- <code>main.rs</code> or <code>foo.rs</code> in <code>srcs</code>.
- This file will be passed to <code>rustc</code> as the crate root.
+ If <code>srcs</code> contains more than one file, then there must be
+ a file either named <code>lib.rs</code>. Otherwise,
+ <code>crate_root</code> must be set to the source file that is the
+ root of the crate to be passed to <code>rustc</code> to build this
+ crate.
</p>
</td>
</tr>
<tr>
+ <td><code>crate_root</code></td>
+ <td>
+ <code>Label, optional</code>
+ <p>
+ The file that will be passed to <code>rustc</code> to be used for
+ building this crate.
+ </p>
+ <p>
+ If <code>crate_root</code> is not set, then this rule will look for
+ a <code>lib.rs</code> file or the single file in <code>srcs</code>
+ if <code>srcs</code> contains only one file.
+ </p>
+ </td>
+ </td>
+ <tr>
<td><code>deps</code></td>
<td>
<code>List of labels, optional</code>
- <p>List of other libraries to be linked to this library target.</p>
+ <p>List of other libraries to be linked to this test target.</p>
<p>
These must be <code>rust_library</code> targets.
</p>
@@ -318,13 +489,146 @@ Hello world
</tbody>
</table>
-<a name="reference-rust_test"></a>
-### `rust_test`
+### Example
+
+Suppose you have the following directory structure for a Rust library crate
+with unit test code in the library sources:
+
+```
+[workspace]/
+ WORKSPACE
+ hello_lib/
+ BUILD
+ src/
+ lib.rs
+```
+
+`hello_lib/src/lib.rs`:
+
+```rust
+pub struct Greeter {
+ greeting: String,
+}
+
+impl Greeter {
+ pub fn new(greeting: &str) -> Greeter {
+ Greeter { greeting: greeting.to_string(), }
+ }
+
+ pub fn greet(&self, thing: &str) {
+ println!("{} {}", &self.greeting, thing);
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::Greeter;
+
+ #[test]
+ fn test_greeting() {
+ let hello = Greeter::new("Hi");
+ assert_eq!("Hi Rust", hello.greeting("Rust"));
+ }
+}
+```
+
+To build and run the tests, simply add a `rust_test` rule with no `srcs` and
+only depends on the `hello_lib` `rust_library` target:
+
+`hello_lib/BUILD`:
```python
-rust_test(name, srcs, deps, data, crate_features, rustc_flags)
+package(default_visibility = ["//visibility:public"])
+
+load("/tools/build_rules/rust/rust", "rust_library", "rust_test")
+
+rust_library(
+ name = "hello_lib",
+ srcs = ["src/lib.rs"],
+)
+
+rust_test(
+ name = "hello_lib_test",
+ deps = [":hello_lib"],
+)
+```
+
+Run the test with `bazel build //hello_lib:hello_lib_test`.
+
+### Example: `test` directory
+
+Integration tests that live in the [`tests` directory][int-tests], they are
+essentially built as separate crates. Suppose you have the following directory
+structure where `greeting.rs` is an integration test for the `hello_lib`
+library crate:
+
+[int-tests]: http://doc.rust-lang.org/book/testing.html#the-tests-directory
+
+```
+[workspace]/
+ WORKSPACE
+ hello_lib/
+ BUILD
+ src/
+ lib.rs
+ tests/
+ greeting.rs
+```
+
+`hello_lib/tests/greeting.rs`:
+
+```rust
+extern crate hello_lib;
+
+use hello_lib;
+
+#[test]
+fn test_greeting() {
+ let hello = greeter::Greeter::new("Hello");
+ assert_eq!("Hello world", hello.greeting("world"));
+}
+```
+
+To build the `greeting.rs` integration test, simply add a `rust_test` target
+with `greeting.rs` in `srcs` and a dependency on the `hello_lib` target:
+
+`hello_lib/BUILD`:
+
+```python
+package(default_visibility = ["//visibility:public"])
+
+load("/tools/build_rules/rust/rust", "rust_library", "rust_test")
+
+rust_library(
+ name = "hello_lib",
+ srcs = ["src/lib.rs"],
+)
+
+rust_test(
+ name = "greeting_test",
+ srcs = ["tests/greeting.rs"],
+ deps = [":hello_lib"],
+)
+```
+
+Run the test with `bazel build //hello_lib:hello_lib_test`.
+
+<a name="rust_bench_test"></a>
+## rust_bench_test
+
+```python
+rust_bench_test(name, srcs, deps, data, crate_features, rustc_flags)
```
+**Warning**: This rule is currently experimental. [Rust Benchmark
+tests][rust-bench] require the `Bencher` interface in the unstable `libtest`
+crate, which is behind the `test` unstable feature gate. As a result, using
+this rule would require using a nightly binary release of Rust. A
+`rust_toolchain` rule will be added in the [near future](#roadmap) to make it
+easy to use a custom Rust toolchain, such as a nightly release.
+
+[rust-bench]: https://doc.rust-lang.org/book/benchmark-tests.html
+
<table>
<thead>
<tr>
@@ -351,15 +655,30 @@ rust_test(name, srcs, deps, data, crate_features, rustc_flags)
<p>List of Rust <code>.rs</code> source files used to build the
library.</p>
<p>
- There must be a file either with a name matching the name of this
- test. For example, if the name of a <code>rust_test</code> rule is
- <code>foo</code>, then there must be a file named <code>foo.rs</code>
- in <code>srcs</code>. This file will be passed to <code>rustc</code>
- as the crate root.
+ If <code>srcs</code> contains more than one file, then there must be
+ a file either named <code>lib.rs</code>. Otherwise,
+ <code>crate_root</code> must be set to the source file that is the
+ root of the crate to be passed to <code>rustc</code> to build this
+ crate.
</p>
</td>
</tr>
<tr>
+ <td><code>crate_root</code></td>
+ <td>
+ <code>Label, optional</code>
+ <p>
+ The file that will be passed to <code>rustc</code> to be used for
+ building this crate.
+ </p>
+ <p>
+ If <code>crate_root</code> is not set, then this rule will look for
+ a <code>lib.rs</code> file or the single file in <code>srcs</code>
+ if <code>srcs</code> contains only one file.
+ </p>
+ </td>
+ </td>
+ <tr>
<td><code>deps</code></td>
<td>
<code>List of labels, optional</code>
@@ -405,11 +724,84 @@ rust_test(name, srcs, deps, data, crate_features, rustc_flags)
</tbody>
</table>
-<a name="reference-rust_docs"></a>
-### `rust_docs`
+### Example
+
+Suppose you have the following directory structure for a Rust project with a
+library crate, `fibonacci` with benchmarks under the `benches/` directory:
+
+```
+[workspace]/
+ WORKSPACE
+ fibonacci/
+ BUILD
+ src/
+ lib.rs
+ benches/
+ fibonacci_bench.rs
+```
+
+`fibonacci/src/lib.rs`:
+
+```rust
+pub fn fibonacci(n: u64) -> u64 {
+ if n < 2 {
+ return n;
+ }
+ let mut n1: u64 = 0;
+ let mut n2: u64 = 1;
+ for _ in 1..n {
+ let sum = n1 + n2;
+ n1 = n2;
+ n2 = sum;
+ }
+ n2
+}
+```
+
+`fibonacci/benches/fibonacci_bench.rs`:
+
+```rust
+#![feature(test)]
+
+extern crate test;
+extern crate fibonacci;
+
+use test::Bencher;
+
+#[bench]
+fn bench_fibonacci(b: &mut Bencher) {
+ b.iter(|| fibonacci::fibonacci(40));
+}
+```
+
+To build the benchmark test, simply add a `rust_bench_test` target:
+
+`fibonacci/BUILD`:
+
+```python
+package(default_visibility = ["//visibility:public"])
+
+load("/tools/build_rules/rust/rust", "rust_library", "rust_bench_test")
+
+rust_library(
+ name = "fibonacci",
+ srcs = ["src/lib.rs"],
+)
+
+rust_bench_test(
+ name = "fibonacci_bench",
+ srcs = ["benches/fibonacci_bench.rs"],
+ deps = [":fibonacci"],
+)
+```
+
+Run the benchmark test using: `bazel build //fibonacci:fibonacci_bench`.
+
+<a name="rust_doc"></a>
+## rust_doc
```python
-rust_docs(name, dep, markdown_css, html_in_header, html_before_content, html_after_content)
+rust_doc(name, dep, markdown_css, html_in_header, html_before_content, html_after_content)
```
<table>
@@ -433,7 +825,7 @@ rust_docs(name, dep, markdown_css, html_in_header, html_before_content, html_aft
<code>Label, required</code>
<p>The label of the target to generate code documentation for.</p>
<p>
- <code>rust_docs</code> can generate HTML code documentation for the
+ <code>rust_doc</code> can generate HTML code documentation for the
source files of <code>rust_library</code> or <code>rust_binary</code>
targets.
</p>
@@ -473,20 +865,113 @@ rust_docs(name, dep, markdown_css, html_in_header, html_before_content, html_aft
</tbody>
</table>
-<a name="#roadmap"></a>
-## Roadmap
+### Example
+
+Suppose you have the following directory structure for a Rust library crate:
+
+```
+[workspace]/
+ WORKSPACE
+ hello_lib/
+ BUILD
+ src/
+ lib.rs
+```
-### Near-term roadmap
+To build [`rustdoc`][rustdoc] documentation for the `hello_lib` crate, define
+a `rust_doc` rule that depends on the the `hello_lib` `rust_library` target:
-* Enable `rust_test` to depend solely on a `rust_library` since many projects
- intermix `#[test]` methods in implementation source.
-* Improve documentation with more detailed examples.
+[rustdoc]: https://doc.rust-lang.org/book/documentation.html
-### Longer-term roadmap
+```python
+package(default_visibility = ["//visibility:public"])
-* Add tool for taking `Cargo.toml` and generating a `WORKSPACE` file with
- workspace rules for pulling external dependencies.
-* Improve expressiveness of features and support for [Cargo's feature
- groups](http://doc.crates.io/manifest.html#the-[features]-section).
-* Add `cargo_crate` workspace rule for pulling crates from
- [Cargo](https://crates.io/).
+load("/tools/build_rules/rust/rust", "rust_library", "rust_doc")
+
+rust_library(
+ name = "hello_lib",
+ srcs = ["src/lib.rs"],
+)
+
+rust_doc(
+ name = "hello_lib_doc",
+ dep = ":hello_lib",
+)
+```
+
+Running `bazel build //hello_lib:hello_lib_doc` will build a zip file containing
+the documentation for the `hello_lib` library crate generated by `rustdoc`.
+
+<a name="rust_doc_test"></a>
+### `rust_doc_test`
+
+```python
+rust_doc_test(name, dep)
+```
+
+<table>
+ <thead>
+ <tr>
+ <th>Attribute</th>
+ <th>Description</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td><code>name</code></td>
+ <td>
+ <code>Name, required</code>
+ <p>A unique name for this rule.</p>
+ </td>
+ </tr>
+ <tr>
+ <td><code>dep</code></td>
+ <td>
+ <code>Label, required</code>
+ <p>The label of the target to run documentation tests for.</p>
+ <p>
+ <code>rust_doc_test</code> can run documentation tests for the
+ source files of <code>rust_library</code> or <code>rust_binary</code>
+ targets.
+ </p>
+ </td>
+ </tr>
+ </tbody>
+</table>
+
+### Example
+
+Suppose you have the following directory structure for a Rust library crate:
+
+```
+[workspace]/
+ WORKSPACE
+ hello_lib/
+ BUILD
+ src/
+ lib.rs
+```
+
+To run [documentation tests][doc-test] for the `hello_lib` crate, define a
+`rust_doc_test` target that depends on the `hello_lib` `rust_library` target:
+
+[doc-test]: https://doc.rust-lang.org/book/documentation.html#documentation-as-tests
+
+```python
+package(default_visibility = ["//visibility:public"])
+
+load("/tools/build_rules/rust/rust", "rust_library", "rust_doc_test")
+
+rust_library(
+ name = "hello_lib",
+ srcs = ["src/lib.rs"],
+)
+
+rust_doc_test(
+ name = "hello_lib_doc_test",
+ dep = ":hello_lib",
+)
+```
+
+Running `bazel test //hello_lib:hello_lib_doc_test` will run all documentation
+tests for the `hello_lib` library crate.
diff --git a/tools/build_rules/rust/rust.BUILD b/tools/build_rules/rust/rust.BUILD
index 576f8b868b..8a0e469b57 100644
--- a/tools/build_rules/rust/rust.BUILD
+++ b/tools/build_rules/rust/rust.BUILD
@@ -1,7 +1,3 @@
-RUST_VERSION = "1.3.0"
-LINUX_BASE_DIR = "rust-%s-x86_64-unknown-linux-gnu/" % RUST_VERSION
-DARWIN_BASE_DIR = "rust-%s-x86_64-apple-darwin/" % RUST_VERSION
-
config_setting(
name = "darwin",
values = {"host_cpu": "darwin"},
@@ -15,8 +11,8 @@ config_setting(
filegroup(
name = "rustc",
srcs = select({
- ":darwin": [DARWIN_BASE_DIR + "rustc/bin/rustc"],
- ":k8": [LINUX_BASE_DIR + "rustc/bin/rustc"],
+ ":darwin": ["rustc/bin/rustc"],
+ ":k8": ["rustc/bin/rustc"],
}),
visibility = ["//visibility:public"],
)
@@ -24,8 +20,8 @@ filegroup(
filegroup(
name = "rustc_lib",
srcs = select({
- ":darwin": glob([DARWIN_BASE_DIR + "rustc/lib/*.dylib"]),
- ":k8": glob([LINUX_BASE_DIR + "rustc/lib/*.so"]),
+ ":darwin": glob(["rustc/lib/*.dylib"]),
+ ":k8": glob(["rustc/lib/*.so"]),
}),
visibility = ["//visibility:public"],
)
@@ -33,8 +29,8 @@ filegroup(
filegroup(
name = "rustdoc",
srcs = select({
- ":darwin": [DARWIN_BASE_DIR + "rustc/bin/rustdoc"],
- ":k8": [LINUX_BASE_DIR + "rustc/bin/rustdoc"],
+ ":darwin": ["rustc/bin/rustdoc"],
+ ":k8": ["rustc/bin/rustdoc"],
}),
visibility = ["//visibility:public"],
)
@@ -43,14 +39,14 @@ filegroup(
name = "rustlib",
srcs = select({
":darwin": glob([
- DARWIN_BASE_DIR + "rustc/lib/rustlib/x86_64-apple-darwin/lib/*.rlib",
- DARWIN_BASE_DIR + "rustc/lib/rustlib/x86_64-apple-darwin/lib/*.dylib",
- DARWIN_BASE_DIR + "rustc/lib/rustlib/x86_64-apple-darwin/lib/*.a",
+ "rustc/lib/rustlib/x86_64-apple-darwin/lib/*.rlib",
+ "rustc/lib/rustlib/x86_64-apple-darwin/lib/*.dylib",
+ "rustc/lib/rustlib/x86_64-apple-darwin/lib/*.a",
]),
":k8": glob([
- LINUX_BASE_DIR + "rustc/lib/rustlib/x86_64-unknown-linux-gnu/lib/*.rlib",
- LINUX_BASE_DIR + "rustc/lib/rustlib/x86_64-unknown-linux-gnu/lib/*.so",
- LINUX_BASE_DIR + "rustc/lib/rustlib/x86_64-unknown-linux-gnu/lib/*.a",
+ "rustc/lib/rustlib/x86_64-unknown-linux-gnu/lib/*.rlib",
+ "rustc/lib/rustlib/x86_64-unknown-linux-gnu/lib/*.so",
+ "rustc/lib/rustlib/x86_64-unknown-linux-gnu/lib/*.a",
]),
}),
visibility = ["//visibility:public"],
diff --git a/tools/build_rules/rust/rust.bzl b/tools/build_rules/rust/rust.bzl
index 69a54b1a12..5dc3c0b132 100644
--- a/tools/build_rules/rust/rust.bzl
+++ b/tools/build_rules/rust/rust.bzl
@@ -17,7 +17,9 @@
RUST_FILETYPE = FileType([".rs"])
A_FILETYPE = FileType([".a"])
-# Used by rust_docs
+LIBRARY_CRATE_TYPES = ["lib", "rlib", "dylib", "staticlib"]
+
+# Used by rust_doc
HTML_MD_FILETYPE = FileType([".html", ".md"])
CSS_FILETYPE = FileType([".css"])
@@ -143,8 +145,8 @@ def _rust_toolchain(ctx):
rustlib_path = ctx.files._rustlib[0].dirname,
rustdoc_path = ctx.file._rustdoc.path)
-def _build_rustc_command(ctx, crate_type, src, output_dir, depinfo,
- extra_flags=[]):
+def _build_rustc_command(ctx, crate_name, crate_type, src, output_dir,
+ depinfo, rust_flags=[]):
"""Builds the rustc command.
Constructs the rustc command used to build the current target.
@@ -152,11 +154,10 @@ def _build_rustc_command(ctx, crate_type, src, output_dir, depinfo,
Args:
ctx: The ctx object for the current target.
crate_type: The type of crate to build ("lib" or "bin")
- src: The path to the crate root source file ("lib.rs" or "main.rs")
+ src: The File object for crate root source file ("lib.rs" or "main.rs")
output_dir: The output directory for the target.
depinfo: Struct containing information about dependencies as returned by
_setup_deps
- extra_flags: Additional command line flags.
Return:
String containing the rustc command.
@@ -180,42 +181,61 @@ def _build_rustc_command(ctx, crate_type, src, output_dir, depinfo,
# Construct features flags
features_flags = _get_features_flags(ctx.attr.crate_features)
- return " ".join([
- "set -e;",
- " ".join(depinfo.setup_cmd),
- "LD_LIBRARY_PATH=%s" % toolchain.rustc_lib_path,
- "DYLD_LIBRARY_PATH=%s" % toolchain.rustc_lib_path,
- toolchain.rustc_path,
- src,
- "--crate-name %s" % ctx.label.name,
- "--crate-type %s" % crate_type,
- "-C opt-level=3",
- "--codegen ar=%s" % ar,
- "--codegen linker=%s" % cc,
- "-L all=%s" % toolchain.rustlib_path,
- " ".join(extra_flags),
- " ".join(features_flags),
- "--out-dir %s" % output_dir,
- "--emit=dep-info,link",
- " ".join(depinfo.search_flags),
- " ".join(depinfo.link_flags),
- " ".join(ctx.attr.rustc_flags),
- ])
+ return " ".join(
+ ["set -e;"] +
+ depinfo.setup_cmd +
+ [
+ "LD_LIBRARY_PATH=%s" % toolchain.rustc_lib_path,
+ "DYLD_LIBRARY_PATH=%s" % toolchain.rustc_lib_path,
+ toolchain.rustc_path,
+ src.path,
+ "--crate-name %s" % crate_name,
+ "--crate-type %s" % crate_type,
+ "-C opt-level=3",
+ "--codegen ar=%s" % ar,
+ "--codegen linker=%s" % cc,
+ "-L all=%s" % toolchain.rustlib_path,
+ "--out-dir %s" % output_dir,
+ "--emit=dep-info,link",
+ ] +
+ features_flags +
+ rust_flags +
+ depinfo.search_flags +
+ depinfo.link_flags +
+ ctx.attr.rustc_flags)
def _find_crate_root_src(srcs, file_names=["lib.rs"]):
"""Finds the source file for the crate root."""
+ if len(srcs) == 1:
+ return srcs[0]
for src in srcs:
if src.basename in file_names:
- return src.path
+ return src
fail("No %s source file found." % " or ".join(file_names), "srcs")
+def _crate_root_src(ctx, file_names=["lib.rs"]):
+ if ctx.file.crate_root == None:
+ return _find_crate_root_src(ctx.files.srcs, file_names)
+ else:
+ return ctx.file.crate_root
+
def _rust_library_impl(ctx):
"""
Implementation for rust_library Skylark rule.
"""
# Find lib.rs
- lib_rs = _find_crate_root_src(ctx.files.srcs)
+ lib_rs = _crate_root_src(ctx)
+
+ # Validate crate_type
+ crate_type = ""
+ if ctx.attr.crate_type != "":
+ if ctx.attr.crate_type not in LIBRARY_CRATE_TYPES:
+ fail("Invalid crate_type for rust_library. Allowed crate types are: %s"
+ % " ".join(LIBRARY_CRATE_TYPES), "crate_type")
+ crate_type += ctx.attr.crate_type
+ else:
+ crate_type += "lib"
# Output library
rust_lib = ctx.outputs.rust_lib
@@ -230,7 +250,8 @@ def _rust_library_impl(ctx):
# Build rustc command
cmd = _build_rustc_command(
ctx = ctx,
- crate_type = "lib",
+ crate_name = ctx.label.name,
+ crate_type = crate_type,
src = lib_rs,
output_dir = output_dir,
depinfo = depinfo)
@@ -240,6 +261,7 @@ def _rust_library_impl(ctx):
ctx.files.srcs +
ctx.files.data +
depinfo.libs +
+ depinfo.transitive_libs +
[ctx.file._rustc] +
ctx.files._rustc_lib +
ctx.files._rustlib)
@@ -255,16 +277,18 @@ def _rust_library_impl(ctx):
return struct(
files = set([rust_lib]),
+ crate_type = crate_type,
+ crate_root = lib_rs,
rust_srcs = ctx.files.srcs,
rust_deps = ctx.attr.deps,
transitive_libs = depinfo.transitive_libs,
rust_lib = rust_lib)
-def _rust_binary_impl_common(ctx, extra_flags = []):
+def _rust_binary_impl(ctx):
"""Implementation for rust_binary Skylark rule."""
# Find main.rs.
- main_rs = _find_crate_root_src(ctx.files.srcs, ["main.rs"])
+ main_rs = _crate_root_src(ctx, ["main.rs"])
# Output binary
rust_binary = ctx.outputs.executable
@@ -278,17 +302,18 @@ def _rust_binary_impl_common(ctx, extra_flags = []):
# Build rustc command.
cmd = _build_rustc_command(ctx = ctx,
+ crate_name = ctx.label.name,
crate_type = "bin",
src = main_rs,
output_dir = output_dir,
- depinfo = depinfo,
- extra_flags = extra_flags)
+ depinfo = depinfo)
# Compile action.
compile_inputs = (
ctx.files.srcs +
ctx.files.data +
depinfo.libs +
+ depinfo.transitive_libs +
[ctx.file._rustc] +
ctx.files._rustc_lib +
ctx.files._rustlib)
@@ -303,19 +328,89 @@ def _rust_binary_impl_common(ctx, extra_flags = []):
% (ctx.label.name, len(ctx.files.srcs))))
return struct(rust_srcs = ctx.files.srcs,
+ crate_root = main_rs,
rust_deps = ctx.attr.deps)
-def _rust_binary_impl(ctx):
- """
- Implementation for rust_binary Skylark rule.
+def _rust_test_common(ctx, test_binary):
+ """Builds a Rust test binary.
+
+ Args:
+ ctx: The ctx object for the current target.
+ test_binary: The File object for the test binary.
"""
- return _rust_binary_impl_common(ctx)
+ output_dir = test_binary.dirname
+
+ if len(ctx.attr.deps) == 1 and len(ctx.files.srcs) == 0:
+ # Target has a single dependency but no srcs. Build the test binary using
+ # the dependency's srcs.
+ dep = ctx.attr.deps[0]
+ crate_type = dep.crate_type if hasattr(dep, "crate_type") else "bin"
+ target = struct(name = dep.label.name,
+ srcs = dep.rust_srcs,
+ deps = dep.rust_deps,
+ crate_root = dep.crate_root,
+ crate_type = crate_type)
+ else:
+ # Target is a standalone crate. Build the test binary as its own crate.
+ target = struct(name = ctx.label.name,
+ srcs = ctx.files.srcs,
+ deps = ctx.attr.deps,
+ crate_root = _crate_root_src(ctx),
+ crate_type = "lib")
+
+ # Get information about dependencies
+ depinfo = _setup_deps(target.deps,
+ target.name,
+ output_dir,
+ is_library=False)
+
+ cmd = _build_rustc_command(ctx = ctx,
+ crate_name = test_binary.basename,
+ crate_type = target.crate_type,
+ src = target.crate_root,
+ output_dir = output_dir,
+ depinfo = depinfo,
+ rust_flags = ["--test"])
+
+ compile_inputs = (target.srcs +
+ depinfo.libs +
+ depinfo.transitive_libs +
+ [ctx.file._rustc] +
+ ctx.files._rustc_lib +
+ ctx.files._rustlib)
+
+ ctx.action(
+ inputs = compile_inputs,
+ outputs = [test_binary],
+ mnemonic = "RustcTest",
+ command = cmd,
+ use_default_shell_env = True,
+ progress_message = ("Compiling Rust test %s (%d files)"
+ % (ctx.label.name, len(target.srcs))))
def _rust_test_impl(ctx):
"""
- Implementation for rust_test and rust_bench_test Skylark rules.
+ Implementation for rust_test Skylark rule.
"""
- return _rust_binary_impl_common(ctx, ["--test"])
+ _rust_test_common(ctx, ctx.outputs.executable)
+
+def _rust_bench_test_impl(ctx):
+ """Implementation for the rust_bench_test Skylark rule."""
+ rust_bench_test = ctx.outputs.executable
+ test_binary = ctx.new_file(ctx.configuration.bin_dir,
+ "%s_bin" % rust_bench_test.basename)
+ _rust_test_common(ctx, test_binary)
+
+ ctx.file_action(
+ output = rust_bench_test,
+ content = " ".join([
+ "#!/bin/bash\n",
+ "set -e\n",
+ "%s --bench\n" % test_binary.short_path]),
+ executable = True)
+
+ runfiles = ctx.runfiles(files = [test_binary], collect_data = True)
+ return struct(runfiles = runfiles)
def _build_rustdoc_flags(ctx):
"""Collects the rustdoc flags."""
@@ -331,19 +426,21 @@ def _build_rustdoc_flags(ctx):
doc_flags += ["--html-after-content %s"]
return doc_flags
-def _rust_docs_impl(ctx):
- """Implementation of the rust_docs rule."""
+def _rust_doc_impl(ctx):
+ """Implementation of the rust_doc rule."""
rust_doc_zip = ctx.outputs.rust_doc_zip
# Gather attributes about the rust_library target to generated rustdocs for.
target = struct(name = ctx.attr.dep.label.name,
srcs = ctx.attr.dep.rust_srcs,
- deps = ctx.attr.dep.rust_deps)
+ deps = ctx.attr.dep.rust_deps,
+ crate_root = ctx.attr.dep.crate_root)
# Find lib.rs
- lib_rs = _find_crate_root_src(target.srcs, ["lib.rs", "main.rs"])
+ lib_rs = (_find_crate_root_src(target.srcs, ["lib.rs", "main.rs"])
+ if target.crate_root == None else target.crate_root)
- # Dependencies
+ # Get information about dependencies
output_dir = rust_doc_zip.dirname
depinfo = _setup_deps(target.deps,
target.name,
@@ -364,7 +461,7 @@ def _rust_docs_impl(ctx):
"LD_LIBRARY_PATH=%s" % toolchain.rustc_lib_path,
"DYLD_LIBRARY_PATH=%s" % toolchain.rustc_lib_path,
toolchain.rustdoc_path,
- lib_rs,
+ lib_rs.path,
"--crate-name %s" % target.name,
"-L all=%s" % toolchain.rustlib_path,
"-o %s" % docs_dir,
@@ -399,8 +496,60 @@ def _rust_docs_impl(ctx):
progress_message = ("Generating rustdoc for %s (%d files)"
% (target.name, len(target.srcs))))
+def _rust_doc_test_impl(ctx):
+ """Implementation for the rust_doc_test rule."""
+ rust_doc_test = ctx.outputs.executable
+
+ # Gather attributes about the rust_library target to generated rustdocs for.
+ target = struct(name = ctx.attr.dep.label.name,
+ srcs = ctx.attr.dep.rust_srcs,
+ deps = ctx.attr.dep.rust_deps,
+ crate_root = ctx.attr.dep.crate_root)
+
+ # Find lib.rs
+ lib_rs = (_find_crate_root_src(target.srcs, ["lib.rs", "main.rs"])
+ if target.crate_root == None else target.crate_root)
+
+ # Get information about dependencies
+ depinfo = _setup_deps(target.deps,
+ target.name,
+ working_dir=".",
+ is_library=False)
+
+ # Construct rustdoc test command, which will be written to a shell script
+ # to be executed to run the test.
+ toolchain = _rust_toolchain(ctx)
+ doc_test_cmd = " ".join(
+ ["#!/bin/bash\n"] +
+ ["set -e\n"] +
+ depinfo.setup_cmd +
+ [
+ "LD_LIBRARY_PATH=%s" % toolchain.rustc_lib_path,
+ "DYLD_LIBRARY_PATH=%s" % toolchain.rustc_lib_path,
+ toolchain.rustdoc_path,
+ lib_rs.path,
+ ] +
+ depinfo.search_flags +
+ depinfo.link_flags)
+
+ ctx.file_action(output = rust_doc_test,
+ content = doc_test_cmd,
+ executable = True)
+
+ doc_test_inputs = (target.srcs +
+ depinfo.libs +
+ depinfo.transitive_libs +
+ [ctx.file._rustdoc] +
+ ctx.files._rustc_lib +
+ ctx.files._rustlib)
+
+ runfiles = ctx.runfiles(files = doc_test_inputs, collect_data = True)
+ return struct(runfiles = runfiles)
+
_rust_common_attrs = {
"srcs": attr.label_list(allow_files = RUST_FILETYPE),
+ "crate_root": attr.label(allow_files = RUST_FILETYPE,
+ single_file = True),
"data": attr.label_list(allow_files = True, cfg = DATA_CFG),
"deps": attr.label_list(),
"crate_features": attr.string_list(),
@@ -421,9 +570,13 @@ _rust_toolchain_attrs = {
single_file = True),
}
+_rust_library_attrs = _rust_common_attrs + {
+ "crate_type": attr.string(),
+}
+
rust_library = rule(
_rust_library_impl,
- attrs = _rust_common_attrs + _rust_toolchain_attrs,
+ attrs = _rust_library_attrs + _rust_toolchain_attrs,
outputs = {
"rust_lib": "lib%{name}.rlib",
},
@@ -446,25 +599,35 @@ rust_test = rule(
)
rust_bench_test = rule(
- _rust_test_impl,
+ _rust_bench_test_impl,
executable = True,
attrs = _rust_common_attrs + _rust_toolchain_attrs,
test = True,
fragments = ["cpp"],
)
-_rust_doc_attrs = {
+_rust_doc_common_attrs = {
"dep": attr.label(mandatory = True),
+}
+
+_rust_doc_attrs = _rust_doc_common_attrs + {
"markdown_css": attr.label_list(allow_files = CSS_FILETYPE),
"html_in_header": attr.label(allow_files = HTML_MD_FILETYPE),
"html_before_content": attr.label(allow_files = HTML_MD_FILETYPE),
"html_after_content": attr.label(allow_files = HTML_MD_FILETYPE),
}
-rust_docs = rule(
- _rust_docs_impl,
+rust_doc = rule(
+ _rust_doc_impl,
attrs = _rust_doc_attrs + _rust_toolchain_attrs,
outputs = {
"rust_doc_zip": "%{name}-docs.zip",
},
)
+
+rust_doc_test = rule(
+ _rust_doc_test_impl,
+ attrs = _rust_doc_common_attrs + _rust_toolchain_attrs,
+ executable = True,
+ test = True,
+)