Add a `cargo_dep_env` rule for setting build.rs environment variables (#1415)

From the docs:
> A rule for generating variables for dependent `cargo_build_script`s
> without a build script. This is useful for using Bazel rules instead
> of a build script, while also generating configuration information
> for build scripts which depend on this crate.
diff --git a/cargo/cargo_build_script.bzl b/cargo/cargo_build_script.bzl
index d53c6e1..dfd4fd0 100644
--- a/cargo/cargo_build_script.bzl
+++ b/cargo/cargo_build_script.bzl
@@ -5,6 +5,9 @@
 load("//rust:defs.bzl", "rust_binary", "rust_common")
 
 # buildifier: disable=bzl-visibility
+load("//rust/private:providers.bzl", _DepInfo = "DepInfo")
+
+# buildifier: disable=bzl-visibility
 load("//rust/private:rustc.bzl", "BuildInfo", "get_compilation_mode_opts", "get_linker_and_args")
 
 # buildifier: disable=bzl-visibility
@@ -435,3 +438,61 @@
     if name.endswith("_build_script"):
         return name[:-len("_build_script")]
     return name
+
+def _cargo_dep_env_implementation(ctx):
+    empty_file = ctx.actions.declare_file(ctx.label.name + ".empty_file")
+    empty_dir = ctx.actions.declare_directory(ctx.label.name + ".empty_dir")
+    ctx.actions.write(
+        output = empty_file,
+        content = "",
+    )
+    ctx.actions.run(
+        outputs = [empty_dir],
+        executable = "true",
+    )
+    return [
+        DefaultInfo(files = depset(ctx.files.src)),
+        BuildInfo(
+            dep_env = empty_file,
+            flags = empty_file,
+            link_flags = empty_file,
+            link_search_paths = empty_file,
+            out_dir = empty_dir,
+            rustc_env = empty_file,
+        ),
+        _DepInfo(
+            dep_env = ctx.file.src,
+            direct_crates = depset(),
+            link_search_path_files = depset(),
+            transitive_build_infos = depset(),
+            transitive_crate_outputs = depset(),
+            transitive_crates = depset(),
+            transitive_noncrates = depset(),
+        ),
+    ]
+
+cargo_dep_env = rule(
+    implementation = _cargo_dep_env_implementation,
+    doc = (
+        "A rule for generating variables for dependent `cargo_build_script`s " +
+        "without a build script. This is useful for using Bazel rules instead " +
+        "of a build script, while also generating configuration information " +
+        "for build scripts which depend on this crate."
+    ),
+    attrs = {
+        "src": attr.label(
+            doc = dedent("""\
+                File containing additional environment variables to set for build scripts of direct dependencies.
+
+                This has the same effect as a `cargo_build_script` which prints
+                `cargo:VAR=VALUE` lines, but without requiring a build script.
+
+                This files should  contain a single variable per line, of format
+                `NAME=value`, and newlines may be included in a value by ending a
+                line with a trailing back-slash (`\\\\`).
+            """),
+            allow_single_file = True,
+            mandatory = True,
+        ),
+    },
+)
diff --git a/test/dep_env/BUILD.bazel b/test/dep_env/BUILD.bazel
new file mode 100644
index 0000000..64addcd
--- /dev/null
+++ b/test/dep_env/BUILD.bazel
@@ -0,0 +1,51 @@
+"""Tests for passing configuration to cargo_build_script rules"""
+
+load("//cargo:cargo_build_script.bzl", "cargo_build_script", "cargo_dep_env")
+load("//rust:defs.bzl", "rust_binary", "rust_library")
+
+cargo_build_script(
+    name = "set_a_build",
+    srcs = ["set_a.rs"],
+    edition = "2018",
+    links = "X",
+)
+
+rust_library(
+    name = "set_a",
+    srcs = ["empty.rs"],
+    edition = "2018",
+    deps = [":set_a_build"],
+)
+
+cargo_dep_env(
+    name = "set_b",
+    src = "set_b.env",
+)
+
+cargo_build_script(
+    name = "read_a",
+    srcs = ["read_a.rs"],
+    edition = "2018",
+    deps = [":set_a"],
+)
+
+cargo_build_script(
+    name = "read_b",
+    srcs = ["read_b.rs"],
+    edition = "2018",
+    deps = [":set_b"],
+)
+
+rust_binary(
+    name = "build_read_a",
+    srcs = ["empty_main.rs"],
+    edition = "2018",
+    deps = [":read_a"],
+)
+
+rust_binary(
+    name = "build_read_b",
+    srcs = ["empty_main.rs"],
+    edition = "2018",
+    deps = [":read_b"],
+)
diff --git a/test/dep_env/empty.rs b/test/dep_env/empty.rs
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/test/dep_env/empty.rs
@@ -0,0 +1 @@
+
diff --git a/test/dep_env/empty_main.rs b/test/dep_env/empty_main.rs
new file mode 100644
index 0000000..f328e4d
--- /dev/null
+++ b/test/dep_env/empty_main.rs
@@ -0,0 +1 @@
+fn main() {}
diff --git a/test/dep_env/read_a.rs b/test/dep_env/read_a.rs
new file mode 100644
index 0000000..8775f81
--- /dev/null
+++ b/test/dep_env/read_a.rs
@@ -0,0 +1,5 @@
+use std::env::var;
+
+fn main() {
+    assert_eq!(var("DEP_X_A").unwrap(), "a_value");
+}
diff --git a/test/dep_env/read_b.rs b/test/dep_env/read_b.rs
new file mode 100644
index 0000000..b63db42
--- /dev/null
+++ b/test/dep_env/read_b.rs
@@ -0,0 +1,5 @@
+use std::env::var;
+
+fn main() {
+    assert_eq!(var("DEP_Y_B").unwrap(), "b_value");
+}
diff --git a/test/dep_env/set_a.rs b/test/dep_env/set_a.rs
new file mode 100644
index 0000000..7e8082a
--- /dev/null
+++ b/test/dep_env/set_a.rs
@@ -0,0 +1,3 @@
+fn main() {
+    println!("cargo:A=a_value");
+}
diff --git a/test/dep_env/set_b.env b/test/dep_env/set_b.env
new file mode 100644
index 0000000..4657007
--- /dev/null
+++ b/test/dep_env/set_b.env
@@ -0,0 +1 @@
+DEP_Y_B=b_value