From 4eb82ec1fe39eff42aa5b1b4246fd941183abe6a Mon Sep 17 00:00:00 2001 From: David Chen Date: Thu, 24 Sep 2015 09:24:24 +0000 Subject: Add rust_docs rule Additional updates to Rust rules: * Consolidate BUILD files for Rust distribution. * Prevent rust_binary from depending directly on cc_library. * Update Rust version to 1.3.0 RELNOTES: [rust] Add rust_docs rule for generating rustdoc. -- MOS_MIGRATED_REVID=103827592 --- WORKSPACE | 12 +- examples/rust/hello_lib/BUILD | 7 +- examples/rust/hello_lib/src/greeter.rs | 31 +++ examples/rust/hello_world/BUILD | 7 +- tools/build_rules/rust/BUILD | 8 + tools/build_rules/rust/README.md | 77 +++++- tools/build_rules/rust/rust-darwin-x86_64.BUILD | 29 --- tools/build_rules/rust/rust-linux-x86_64.BUILD | 29 --- tools/build_rules/rust/rust.BUILD | 57 +++++ tools/build_rules/rust/rust.WORKSPACE | 12 +- tools/build_rules/rust/rust.bzl | 315 ++++++++++++++++++------ 11 files changed, 433 insertions(+), 151 deletions(-) delete mode 100644 tools/build_rules/rust/rust-darwin-x86_64.BUILD delete mode 100644 tools/build_rules/rust/rust-linux-x86_64.BUILD create mode 100644 tools/build_rules/rust/rust.BUILD diff --git a/WORKSPACE b/WORKSPACE index 6f2df12186..b3aebe8e76 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -44,16 +44,16 @@ maven_jar( new_http_archive( name = "rust-linux-x86_64", - url = "https://static.rust-lang.org/dist/rust-1.2.0-x86_64-unknown-linux-gnu.tar.gz", - sha256 = "2311420052e06b3e698ce892924ec40890a8ff0499902e7fc5350733187a1531", - build_file = "tools/build_rules/rust/rust-linux-x86_64.BUILD", + 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", ) new_http_archive( name = "rust-darwin-x86_64", - url = "https://static.rust-lang.org/dist/rust-1.2.0-x86_64-apple-darwin.tar.gz", - sha256 = "0d471e672fac5a450ae5507b335fda2efc0b22ea9fb7f215c6a9c466dafa2661", - build_file = "tools/build_rules/rust/rust-darwin-x86_64.BUILD", + 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", ) # In order to run the Android integration tests, uncomment these rules, point diff --git a/examples/rust/hello_lib/BUILD b/examples/rust/hello_lib/BUILD index 64cc935b27..a075f8b168 100644 --- a/examples/rust/hello_lib/BUILD +++ b/examples/rust/hello_lib/BUILD @@ -1,6 +1,6 @@ package(default_visibility = ["//visibility:public"]) -load("/tools/build_rules/rust/rust", "rust_library", "rust_test") +load("/tools/build_rules/rust/rust", "rust_library", "rust_docs", "rust_test") rust_library( name = "hello_lib", @@ -10,6 +10,11 @@ rust_library( ], ) +rust_docs( + name = "hello_lib_docs", + dep = ":hello_lib", +) + rust_test( name = "greeting", srcs = ["tests/greeting.rs"], diff --git a/examples/rust/hello_lib/src/greeter.rs b/examples/rust/hello_lib/src/greeter.rs index be59ff888d..2a4a2f1d3f 100644 --- a/examples/rust/hello_lib/src/greeter.rs +++ b/examples/rust/hello_lib/src/greeter.rs @@ -12,19 +12,50 @@ // See the License for the specific language governing permissions and // limitations under the License. +/// Object that displays a greeting. pub struct Greeter { greeting: String, } +/// Implementation of Greeter. impl Greeter { + /// Constructs a new `Greeter`. + /// + /// # Examples + /// + /// ``` + /// use hello_lib::greeter; + /// + /// let greeter = Greeter::new("Hello"); + /// ``` pub fn new(greeting: &str) -> Greeter { Greeter { greeting: greeting.to_string(), } } + /// Returns the greeting as a string. + /// + /// # Examples + /// + /// ``` + /// use hello_lib::greeter; + /// + /// let greeter = Greeter::new("Hello"); + /// let greeting = greeter.greeting("World"); + /// ``` pub fn greeting(&self, thing: &str) -> String { format!("{} {}", &self.greeting, thing) } + /// Prints the greeting. + /// + /// # Examples + /// + /// ``` + /// use hello_lib::greeter; + /// + /// let greeter = Greeter::new("Hello"); + /// greeter.greet("World"); + /// ``` pub fn greet(&self, thing: &str) { println!("{} {}", &self.greeting, thing); } diff --git a/examples/rust/hello_world/BUILD b/examples/rust/hello_world/BUILD index e774dcc835..ccd87f1b93 100644 --- a/examples/rust/hello_world/BUILD +++ b/examples/rust/hello_world/BUILD @@ -1,9 +1,14 @@ package(default_visibility = ["//visibility:public"]) -load("/tools/build_rules/rust/rust", "rust_binary") +load("/tools/build_rules/rust/rust", "rust_binary", "rust_docs") rust_binary( name = "hello_world", srcs = ["src/main.rs"], deps = ["//examples/rust/hello_lib"], ) + +rust_docs( + name = "hello_world_docs", + dep = ":hello_world", +) diff --git a/tools/build_rules/rust/BUILD b/tools/build_rules/rust/BUILD index e212a3160e..78d2ee6223 100644 --- a/tools/build_rules/rust/BUILD +++ b/tools/build_rules/rust/BUILD @@ -32,6 +32,14 @@ filegroup( }), ) +filegroup( + name = "rustdoc", + srcs = select({ + ":darwin": ["@rust-darwin-x86_64//:rustdoc"], + ":k8": ["@rust-linux-x86_64//:rustdoc"], + }), +) + filegroup( name = "rustlib", srcs = select({ diff --git a/tools/build_rules/rust/README.md b/tools/build_rules/rust/README.md index c82179d08b..536c10f837 100644 --- a/tools/build_rules/rust/README.md +++ b/tools/build_rules/rust/README.md @@ -10,6 +10,7 @@ These build rules are used for building [Rust][rust] projects with Bazel. * [`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/ @@ -320,7 +321,9 @@ Hello world ### `rust_test` -`rust_test(name, srcs, deps, data, crate_features, rustc_flags)` +```python +rust_test(name, srcs, deps, data, crate_features, rustc_flags) +``` @@ -402,18 +405,82 @@ Hello world
+ +### `rust_docs` + +```python +rust_docs(name, dep, markdown_css, html_in_header, html_before_content, html_after_content) +``` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributeDescription
name + Name, required +

A unique name for this rule.

+
dep + Label, required +

The label of the target to generate code documentation for.

+

+ rust_docs can generate HTML code documentation for the + source files of rust_library or rust_binary + targets. +

+
markdown_css + List of Labels, optional +

+ CSS files to include via <link> in a rendered + Markdown file. +

+
html_in_header + Label, optional +

File to add to <head>.

+
html_before_content + Label, optional +

File to add in <body>, before content.

+
html_after_content + Label, optional +

File to add in <body>, after content.

+
+ ## Roadmap ### Near-term roadmap -* Implement `rust_bench_test` rule for running benchmarks. * 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. -* Implement `rust_doc` rule for generating [rustdoc][rustdoc] documentation. - -[rustdoc]: https://doc.rust-lang.org/book/documentation.html#about-rustdoc ### Longer-term roadmap diff --git a/tools/build_rules/rust/rust-darwin-x86_64.BUILD b/tools/build_rules/rust/rust-darwin-x86_64.BUILD deleted file mode 100644 index cc7aaadd2f..0000000000 --- a/tools/build_rules/rust/rust-darwin-x86_64.BUILD +++ /dev/null @@ -1,29 +0,0 @@ -BASE_DIR = "rust-1.2.0-x86_64-apple-darwin/" - -filegroup( - name = "rustc", - srcs = [BASE_DIR + "rustc/bin/rustc"], - visibility = ["//visibility:public"], -) - -filegroup( - name = "rustc_lib", - srcs = glob([BASE_DIR + "rustc/lib/*.dylib"]), - visibility = ["//visibility:public"], -) - -filegroup( - name = "rustdoc", - srcs = [BASE_DIR + "rustc/bin/rustdoc"], - visibility = ["//visibility:public"], -) - -filegroup( - name = "rustlib", - srcs = glob([ - BASE_DIR + "rustc/lib/rustlib/x86_64-apple-darwin/lib/*.rlib", - BASE_DIR + "rustc/lib/rustlib/x86_64-apple-darwin/lib/*.dylib", - BASE_DIR + "rustc/lib/rustlib/x86_64-apple-darwin/lib/*.a", - ]), - visibility = ["//visibility:public"], -) diff --git a/tools/build_rules/rust/rust-linux-x86_64.BUILD b/tools/build_rules/rust/rust-linux-x86_64.BUILD deleted file mode 100644 index 7d4a7e3478..0000000000 --- a/tools/build_rules/rust/rust-linux-x86_64.BUILD +++ /dev/null @@ -1,29 +0,0 @@ -BASE_DIR = "rust-1.2.0-x86_64-unknown-linux-gnu/" - -filegroup( - name = "rustc", - srcs = [BASE_DIR + "rustc/bin/rustc"], - visibility = ["//visibility:public"], -) - -filegroup( - name = "rustc_lib", - srcs = glob([BASE_DIR + "rustc/lib/*.so"]), - visibility = ["//visibility:public"], -) - -filegroup( - name = "rustdoc", - srcs = [BASE_DIR + "rustc/bin/rustdoc"], - visibility = ["//visibility:public"], -) - -filegroup( - name = "rustlib", - srcs = glob([ - BASE_DIR + "rustc/lib/rustlib/x86_64-unknown-linux-gnu/lib/*.rlib", - BASE_DIR + "rustc/lib/rustlib/x86_64-unknown-linux-gnu/lib/*.so", - BASE_DIR + "rustc/lib/rustlib/x86_64-unknown-linux-gnu/lib/*.a", - ]), - visibility = ["//visibility:public"], -) diff --git a/tools/build_rules/rust/rust.BUILD b/tools/build_rules/rust/rust.BUILD new file mode 100644 index 0000000000..576f8b868b --- /dev/null +++ b/tools/build_rules/rust/rust.BUILD @@ -0,0 +1,57 @@ +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"}, +) + +config_setting( + name = "k8", + values = {"host_cpu": "k8"}, +) + +filegroup( + name = "rustc", + srcs = select({ + ":darwin": [DARWIN_BASE_DIR + "rustc/bin/rustc"], + ":k8": [LINUX_BASE_DIR + "rustc/bin/rustc"], + }), + visibility = ["//visibility:public"], +) + +filegroup( + name = "rustc_lib", + srcs = select({ + ":darwin": glob([DARWIN_BASE_DIR + "rustc/lib/*.dylib"]), + ":k8": glob([LINUX_BASE_DIR + "rustc/lib/*.so"]), + }), + visibility = ["//visibility:public"], +) + +filegroup( + name = "rustdoc", + srcs = select({ + ":darwin": [DARWIN_BASE_DIR + "rustc/bin/rustdoc"], + ":k8": [LINUX_BASE_DIR + "rustc/bin/rustdoc"], + }), + visibility = ["//visibility:public"], +) + +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", + ]), + ":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", + ]), + }), + visibility = ["//visibility:public"], +) diff --git a/tools/build_rules/rust/rust.WORKSPACE b/tools/build_rules/rust/rust.WORKSPACE index 4086ce80be..c93deb4917 100644 --- a/tools/build_rules/rust/rust.WORKSPACE +++ b/tools/build_rules/rust/rust.WORKSPACE @@ -1,13 +1,13 @@ new_http_archive( name = "rust-linux-x86_64", - url = "https://static.rust-lang.org/dist/rust-1.2.0-x86_64-unknown-linux-gnu.tar.gz", - sha256 = "2311420052e06b3e698ce892924ec40890a8ff0499902e7fc5350733187a1531", - build_file = "tools/build_rules/rust/rust-linux-x86_64.BUILD", + 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", ) new_http_archive( name = "rust-darwin-x86_64", - url = "https://static.rust-lang.org/dist/rust-1.2.0-x86_64-apple-darwin.tar.gz", - sha256 = "0d471e672fac5a450ae5507b335fda2efc0b22ea9fb7f215c6a9c466dafa2661", - build_file = "tools/build_rules/rust/rust-darwin-x86_64.BUILD", + 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", ) diff --git a/tools/build_rules/rust/rust.bzl b/tools/build_rules/rust/rust.bzl index 943c6c73a3..ace888949c 100644 --- a/tools/build_rules/rust/rust.bzl +++ b/tools/build_rules/rust/rust.bzl @@ -12,13 +12,19 @@ # See the License for the specific language governing permissions and # limitations under the License. +"""Rust rules for Bazel""" + RUST_FILETYPE = FileType([".rs"]) A_FILETYPE = FileType([".a"]) +# Used by rust_docs +HTML_MD_FILETYPE = FileType([".html", ".md"]) +CSS_FILETYPE = FileType([".css"]) + +ZIP_PATH = "/usr/bin/zip" + def _relative(src_path, dest_path): - """ - Returns the relative path from src_path to dest_path - """ + """Returns the relative path from src_path to dest_path.""" src_parts = src_path.split("/") dest_parts = dest_path.split("/") n = 0 @@ -45,11 +51,25 @@ def _create_setup_cmd(lib, deps_dir): deps_dir + "/" + lib.basename + "\n" ) -# TODO(dzc): rust_binary should not be able to depend on cc_library -def _setup_deps(deps, name, working_dir): +def _setup_deps(deps, name, working_dir, is_library=False): """ Walks through dependencies and constructs the necessary commands for linking to all the necessary dependencies. + + Args: + deps: List of Labels containing deps from ctx.attr.deps. + name: Name of the current target. + working_dir: The output directory for the current target's outputs. + is_library: True the current target is a rust_library target, False + otherwise. + + Returns: + Returns a struct containing the following fields: + libs: + transitive_libs: + setup_cmd: + search_flags: + link_flags: """ deps_dir = working_dir + "/" + name + ".deps" setup_cmd = ["rm -rf " + deps_dir + "; mkdir " + deps_dir + "\n"] @@ -63,21 +83,21 @@ def _setup_deps(deps, name, working_dir): link_flags = [] for dep in deps: if hasattr(dep, "rust_lib"): + # This dependency is a rust_library libs += [dep.rust_lib] - transitive_libs += [dep.rust_lib] - symlinked_libs += [dep.rust_lib] + transitive_libs += [dep.rust_lib] + dep.transitive_libs + symlinked_libs += [dep.rust_lib] + dep.transitive_libs link_flags += [( "--extern " + dep.label.name + "=" + deps_dir + "/" + dep.rust_lib.basename )] has_rlib = True - if hasattr(dep, "transitive_libs"): - transitive_libs += dep.transitive_libs - symlinked_libs += dep.transitive_libs + elif hasattr(dep, "cc"): + if not is_library: + fail("Only rust_library targets can depend on cc_library") - # If this rule depends on a cc_library - if hasattr(dep, "cc"): + # This dependency is a cc_library native_libs = A_FILETYPE.filter(dep.cc.libs) libs += native_libs transitive_libs += native_libs @@ -85,22 +105,26 @@ def _setup_deps(deps, name, working_dir): link_flags += ["-l static=" + dep.label.name] has_native = True + else: + fail(("rust_library" if is_library else "rust_binary and rust_test") + + " targets can only depend on rust_library " + + ("or cc_library " if is_library else "") + "targets") + for symlinked_lib in symlinked_libs: setup_cmd += [_create_setup_cmd(symlinked_lib, deps_dir)] search_flags = [] if has_rlib: - search_flags += ["-L dependency=" + deps_dir] + search_flags += ["-L dependency=%s" % deps_dir] if has_native: - search_flags += ["-L native=" + deps_dir] + search_flags += ["-L native=%s" % deps_dir] return struct( libs = list(libs), transitive_libs = list(transitive_libs), setup_cmd = setup_cmd, search_flags = search_flags, - link_flags = link_flags, - ) + link_flags = link_flags) def _get_features_flags(features): """ @@ -109,19 +133,37 @@ def _get_features_flags(features): """ features_flags = [] for feature in features: - features_flags += [" --cfg feature=\\\"" + feature + "\\\""] + features_flags += ["--cfg feature=\\\"%s\\\"" % feature] return features_flags +def _rust_toolchain(ctx): + return struct( + rustc_path = ctx.file._rustc.path, + rustc_lib_path = ctx.files._rustc_lib[0].dirname, + 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=[]): - """ - Builds the rustc command + """Builds the rustc command. + + Constructs the rustc command used to build the current target. + + 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") + 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. """ # Paths to the Rust compiler and standard libraries. - rustc_path = ctx.file._rustc.path - rustc_lib_path = ctx.files._rustc_lib[0].dirname - rustlib_path = ctx.files._rustlib[0].dirname + toolchain = _rust_toolchain(ctx) # Paths to cc (for linker) and ar cpp_fragment = ctx.fragments.cpp @@ -141,46 +183,49 @@ def _build_rustc_command(ctx, crate_type, src, output_dir, depinfo, return " ".join([ "set -e;", " ".join(depinfo.setup_cmd), - "LD_LIBRARY_PATH=" + rustc_lib_path, - "DYLD_LIBRARY_PATH=" + rustc_lib_path, - rustc_path + " " + src, - "--crate-name " + ctx.label.name, - "--crate-type " + crate_type, - "-g", + "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=" + rustlib_path, + "-L all=%s" % toolchain.rustlib_path, " ".join(extra_flags), " ".join(features_flags), - "--out-dir " + output_dir, + "--out-dir %s" % output_dir, "--emit=dep-info,link", " ".join(depinfo.search_flags), " ".join(depinfo.link_flags), " ".join(ctx.attr.rustc_flags), ]) +def _find_crate_root_src(srcs, file_names=["lib.rs"]): + """Finds the source file for the crate root.""" + for src in srcs: + if src.basename in file_names: + return src.path + fail("No %s source file found." % " or ".join(file_names), "srcs") + def _rust_library_impl(ctx): """ Implementation for rust_library Skylark rule. """ # Find lib.rs - srcs = ctx.files.srcs - lib_rs = None - crate_name_rs = ctx.label.name + ".rs" - for src in srcs: - if src.basename == "lib.rs" or src.basename == crate_name_rs: - lib_rs = src.path - - if not lib_rs: - fail("No lib.rs or source file matching crate name found.") + lib_rs = _find_crate_root_src(ctx.files.srcs) # Output library rust_lib = ctx.outputs.rust_lib output_dir = rust_lib.dirname # Dependencies - depinfo = _setup_deps(ctx.attr.deps, ctx.label.name, output_dir) + depinfo = _setup_deps(ctx.attr.deps, + ctx.label.name, + output_dir, + is_library=True) # Build rustc command cmd = _build_rustc_command( @@ -191,64 +236,74 @@ def _rust_library_impl(ctx): depinfo = depinfo) # Compile action. + compile_inputs = ( + ctx.files.srcs + + ctx.files.data + + depinfo.libs + + [ctx.file._rustc] + + ctx.files._rustc_lib + + ctx.files._rustlib) + ctx.action( - inputs = srcs + ctx.files.data + depinfo.libs + [ctx.file._rustc] + - ctx.files._rustc_lib + ctx.files._rustlib, + inputs = compile_inputs, outputs = [rust_lib], mnemonic = 'Rustc', command = cmd, use_default_shell_env = True, - progress_message = "Compiling Rust library " + ctx.label.name - ) + progress_message = ("Compiling Rust library %s (%d files)" + % (ctx.label.name, len(ctx.files.srcs)))) return struct( files = set([rust_lib]), + rust_srcs = ctx.files.srcs, + rust_deps = ctx.attr.deps, transitive_libs = depinfo.transitive_libs, - rust_lib = rust_lib, - ) + rust_lib = rust_lib) def _rust_binary_impl_common(ctx, extra_flags = []): - """ - Implementation for rust_binary Skylark rule. - """ + """Implementation for rust_binary Skylark rule.""" # Find main.rs. - srcs = ctx.files.srcs - main_rs = None - crate_name_rs = ctx.label.name + ".rs" - for src in srcs: - if src.basename == "main.rs" or src.basename == crate_name_rs: - main_rs = src.path - - if not main_rs: - fail("No main.rs or source file matching crate name found.") + main_rs = _find_crate_root_src(ctx.files.srcs, ["main.rs"]) # Output binary rust_binary = ctx.outputs.executable output_dir = rust_binary.dirname # Dependencies - depinfo = _setup_deps(ctx.attr.deps, ctx.label.name, output_dir) + depinfo = _setup_deps(ctx.attr.deps, + ctx.label.name, + output_dir, + is_library=False) # Build rustc command. - cmd = _build_rustc_command( - ctx = ctx, - crate_type = "bin", - src = main_rs, - output_dir = output_dir, - depinfo = depinfo, - extra_flags = extra_flags) + cmd = _build_rustc_command(ctx = ctx, + crate_type = "bin", + src = main_rs, + output_dir = output_dir, + depinfo = depinfo, + extra_flags = extra_flags) # Compile action. + compile_inputs = ( + ctx.files.srcs + + ctx.files.data + + depinfo.libs + + [ctx.file._rustc] + + ctx.files._rustc_lib + + ctx.files._rustlib) + ctx.action( - inputs = srcs + ctx.files.data + depinfo.libs + [ctx.file._rustc] + - ctx.files._rustc_lib + ctx.files._rustlib, + inputs = compile_inputs, outputs = [rust_binary], mnemonic = 'Rustc', command = cmd, use_default_shell_env = True, - progress_message = "Compiling Rust binary " + ctx.label.name - ) + progress_message = ("Compiling Rust binary %s (%d files)" + % (ctx.label.name, len(ctx.files.srcs)))) + + return struct(rust_srcs = ctx.files.srcs, + rust_deps = ctx.attr.deps) def _rust_binary_impl(ctx): """ @@ -258,16 +313,101 @@ def _rust_binary_impl(ctx): def _rust_test_impl(ctx): """ - Implementation for rust_test Skylark rule. + Implementation for rust_test and rust_bench_test Skylark rules. """ return _rust_binary_impl_common(ctx, ["--test"]) +def _build_rustdoc_flags(ctx): + """Collects the rustdoc flags.""" + doc_flags = [] + doc_flags += [ + "--markdown-css %s" % css.path for css in ctx.files.markdown_css] + if hasattr(ctx.file, "html_in_header"): + doc_flags += ["--html-in-header %s" % ctx.file.html_in_header.path] + if hasattr(ctx.file, "html_before_content"): + doc_flags += ["--html-before-content %s" % + ctx.file.html_before_content.path] + if hasattr(ctx.file, "html_after_content"): + doc_flags += ["--html-after-content %s"] + return doc_flags + +def _rust_docs_impl(ctx): + """Implementation of the rust_docs 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) + + # Find lib.rs + lib_rs = _find_crate_root_src(target.srcs, ["lib.rs", "main.rs"]) + + # Dependencies + output_dir = rust_doc_zip.dirname + depinfo = _setup_deps(target.deps, + target.name, + output_dir, + is_library=False) + + # Rustdoc flags. + doc_flags = _build_rustdoc_flags(ctx) + + # Build rustdoc command. + toolchain = _rust_toolchain(ctx) + docs_dir = rust_doc_zip.dirname + "/_rust_docs" + doc_cmd = " ".join( + ["set -e"] + + depinfo.setup_cmd + [ + "rm -rf %s;" % docs_dir, + "mkdir %s;" % docs_dir, + "LD_LIBRARY_PATH=%s" % toolchain.rustc_lib_path, + "DYLD_LIBRARY_PATH=%s" % toolchain.rustc_lib_path, + toolchain.rustdoc_path, + lib_rs, + "--crate-name %s" % target.name, + "-L all=%s" % toolchain.rustlib_path, + "-o %s" % docs_dir, + ] + + doc_flags + + depinfo.search_flags + + depinfo.link_flags + [ + "&&", + "(cd %s" % docs_dir, + "&&", + ZIP_PATH, + "-qR", + rust_doc_zip.basename, + "$(find . -type f) )", + "&&", + "mv %s/%s %s" % (docs_dir, rust_doc_zip.basename, rust_doc_zip.path), + ]) + + # Rustdoc action + rustdoc_inputs = (target.srcs + + depinfo.libs + + [ctx.file._rustdoc] + + ctx.files._rustc_lib + + ctx.files._rustlib) + + ctx.action( + inputs = rustdoc_inputs, + outputs = [rust_doc_zip], + mnemonic = 'Rustdoc', + command = doc_cmd, + use_default_shell_env = True, + progress_message = ("Generating rustdoc for %s (%d files)" + % (target.name, len(target.srcs)))) + _rust_common_attrs = { "srcs": attr.label_list(allow_files = RUST_FILETYPE), "data": attr.label_list(allow_files = True, cfg = DATA_CFG), "deps": attr.label_list(), "crate_features": attr.string_list(), "rustc_flags": attr.string_list(), +} + +_rust_toolchain_attrs = { "_rustc": attr.label( default = Label("//tools/build_rules/rust:rustc"), executable = True, @@ -275,11 +415,15 @@ _rust_common_attrs = { "_rustc_lib": attr.label( default = Label("//tools/build_rules/rust:rustc_lib")), "_rustlib": attr.label(default = Label("//tools/build_rules/rust:rustlib")), + "_rustdoc": attr.label( + default = Label("//tools/build_rules/rust:rustdoc"), + executable = True, + single_file = True), } rust_library = rule( _rust_library_impl, - attrs = _rust_common_attrs, + attrs = _rust_common_attrs + _rust_toolchain_attrs, outputs = { "rust_lib": "lib%{name}.rlib", }, @@ -289,15 +433,38 @@ rust_library = rule( rust_binary = rule( _rust_binary_impl, executable = True, - attrs = _rust_common_attrs, + attrs = _rust_common_attrs + _rust_toolchain_attrs, fragments = ["cpp"], ) rust_test = rule( _rust_test_impl, executable = True, - attrs = _rust_common_attrs, + attrs = _rust_common_attrs + _rust_toolchain_attrs, test = True, fragments = ["cpp"], ) +rust_bench_test = rule( + _rust_test_impl, + executable = True, + attrs = _rust_common_attrs + _rust_toolchain_attrs, + test = True, + fragments = ["cpp"], +) + +_rust_doc_attrs = { + "dep": attr.label(mandatory = True), + "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, + attrs = _rust_doc_attrs + _rust_toolchain_attrs, + outputs = { + "rust_doc_zip": "%{name}-docs.zip", + }, +) -- cgit v1.2.3