Add custom repository_rule for fetching toolchains (#107)

* WIP

* Support additional stdlibs for a given toolchain

* Add some docs

* Address review comments

* Perform cleanup, address issue with

* Handle some nits

* Fix a whoops
diff --git a/rust/known_shas.bzl b/rust/known_shas.bzl
index b7331da..47ed24b 100644
--- a/rust/known_shas.bzl
+++ b/rust/known_shas.bzl
@@ -3,27 +3,75 @@
     "2018-07-07/rust-beta-x86_64-apple-darwin": "098a05b3c54529c03ce96bc90faefc46027063773f0ffba17931aba38b897cda",
     "2018-07-07/rust-beta-x86_64-unknown-freebsd": "636744474bddeb5be9bec7954c9b252c6df4020df3edeade26931d76b69ab526",
     "2018-07-07/rust-beta-x86_64-unknown-linux-gnu": "e98a60d6ec24f26f8aacfef5e588cdd7b8d75f08d2ecb73a81d9ffde2dc12095",
+    "2018-07-07/rustc-beta-x86_64-apple-darwin": "8bfd73443125dffde1d55d761f4fb4b318081dbdbb14ba52dea93851024dc35b",
+    "2018-07-07/rustc-beta-x86_64-unknown-freebsd": "7d489a6319b7bcefd0807ec1a3c5bb07fdd0a966bbc74c90fb43ecd045aa9662",
+    "2018-07-07/rustc-beta-x86_64-unknown-linux-gnu": "11caee3c8c73a27e0bf45217cf80c694e923baf86d5ddcc422053435e5702e01",
+    "2018-07-07/rustc-nightly-x86_64-apple-darwin": "b1e1a7d59596d172468604185319f0be220568deb9dbbba2d569852abdb80ec8",
+    "2018-07-07/rustc-nightly-x86_64-unknown-freebsd": "5f23bc9ca20fe677270229988ed3954c374b5ae3d467e1780ccda43d86df5f02",
+    "2018-07-07/rustc-nightly-x86_64-unknown-linux-gnu": "6780a8c6720d774e8ebc626e5e238d35857598ac490a3d2bde80bd6664b783c5",
     "2018-07-07/rust-nightly-x86_64-apple-darwin": "5a4122c36e1f1f00d7ea711b0808c697ecfbb90abc08ced4340c66f298040300",
     "2018-07-07/rust-nightly-x86_64-unknown-freebsd": "8b0ca59fa97f7d2af8d9823eec1ad3e3c90de027ae266dacc8d9699dbd74b66a",
     "2018-07-07/rust-nightly-x86_64-unknown-linux-gnu": "eb0e6a173835994be99e0e31dfc8443543ad4217dc0cbc89fb9c82232d5f3db8",
+    "2018-07-07/rust-std-beta-x86_64-apple-darwin": "2d856e488e87d9ec5e66ffd77e6528d139ada2a9eac2c9ac7b05593678c97c6e",
+    "2018-07-07/rust-std-beta-x86_64-unknown-freebsd": "785bb39558b05c3833c5b7e78c297ce0c5819d6d36a4642b7e369660f124388e",
+    "2018-07-07/rust-std-beta-x86_64-unknown-linux-gnu": "90b0ea04e179ecb89a31524f66f49ada5138b3dbb8862f5586de596df1a6f15a",
+    "2018-07-07/rust-std-nightly-x86_64-apple-darwin": "04b4b9896c5a494a915ee06743a28f61dd63ff4ea03ebc4c6c3f1235de52ebeb",
+    "2018-07-07/rust-std-nightly-x86_64-unknown-freebsd": "4f891a752860679d363f972c9766b2ab8eed3d18f04ed3c38cf1f30cbf01cb64",
+    "2018-07-07/rust-std-nightly-x86_64-unknown-linux-gnu": "6f7d2d9958dc1a900364ea042d2b4cd421c1d4065667d6e82454905fb05bb7fb",
+    "2018-07-08/rustc-nightly-x86_64-apple-darwin": "82d69b7241e22dc57852f523205b397027ef7b8121054b21f9f931584b7bd53c",
+    "2018-07-08/rustc-nightly-x86_64-unknown-freebsd": "663e40ee11d7a618b1adcc1d1e68771ce6a31eee6b442d99fb9691c7d3d3377d",
+    "2018-07-08/rustc-nightly-x86_64-unknown-linux-gnu": "1becc7ef721485b08d798c772d5a2e65d657eac21333607c1200e78b8f1a5162",
     "2018-07-08/rust-nightly-x86_64-apple-darwin": "3cfb0571270a5ab6c69d0fddf89ff05d960411fc345621bcee16802d9a3c5e9a",
     "2018-07-08/rust-nightly-x86_64-unknown-freebsd": "64e21c105b885e4d8fa594180be2634f2c3ba9b6bfb828cc25fda42cabd5277d",
     "2018-07-08/rust-nightly-x86_64-unknown-linux-gnu": "f98e9e23abd3c98f188a9aa5f67495692c77e1747fdf66324dbee5d8720189d7",
+    "2018-07-08/rust-std-nightly-x86_64-apple-darwin": "75066ccb0b565a5f774931201a1a680c85059b5feb9cffe5cee0bf17da012bc8",
+    "2018-07-08/rust-std-nightly-x86_64-unknown-freebsd": "c4ebfdaf994854fd4e55f8f294e53c914ee599738fcdf3c34c1cc94928c0c4a9",
+    "2018-07-08/rust-std-nightly-x86_64-unknown-linux-gnu": "4fd55a5732625cf57a9e0a7de5d10155a02a9cb0e52b23e8e3b9b0089a75acd1",
     "2018-07-09/rust-beta-x86_64-apple-darwin": "88c8cc09021f60241375914a37b8741de414cbfcf1e455d18bdf1621a6caab6d",
     "2018-07-09/rust-beta-x86_64-unknown-freebsd": "23ca8e71a2ecf9e2342c7df5f905558c62f6c691f6b3f000fff8f81eefb006b4",
     "2018-07-09/rust-beta-x86_64-unknown-linux-gnu": "62f5b7fa5d386ccc709f4ed232169b0130de6d432ec18fe49093d3694201bc65",
+    "2018-07-09/rustc-beta-x86_64-apple-darwin": "6c6973c44d1b008a54ed2e27dbe06ec7847667834f6fbae085b634fc39be01f1",
+    "2018-07-09/rustc-beta-x86_64-unknown-freebsd": "b11018ccced1428f428a055497609446b6f8f96cd23bffd343c2fe1f96f3b723",
+    "2018-07-09/rustc-beta-x86_64-unknown-linux-gnu": "4d19adf1cd30203c7ea673f2b4e369f5bed61eaea0fb9d1b705003c959fdf2d3",
+    "2018-07-09/rustc-nightly-x86_64-apple-darwin": "82b90874be2894e1338d62a9eb167c02d83d401130f67fe72b6d5ab01bb6ca63",
+    "2018-07-09/rustc-nightly-x86_64-unknown-freebsd": "6788b84aeacfca583cf6e877527fc4b30f6e3cbe568276b7145e0885604b3266",
+    "2018-07-09/rustc-nightly-x86_64-unknown-linux-gnu": "8a69af90c216b8a0e4c2cb641f63d2998eff7743fcaf7ef1aa113365ee8b1d1c",
     "2018-07-09/rust-nightly-x86_64-apple-darwin": "bfdec1085b33c1018bc64fecbfa0000bfc8c8d74c391d17ac567ec135ab3478f",
     "2018-07-09/rust-nightly-x86_64-unknown-freebsd": "e72d96c471db54f136ad9ae8f6f67d19c3f6402745e587e5f344a3db5b43378c",
     "2018-07-09/rust-nightly-x86_64-unknown-linux-gnu": "420a54694a714892aacb209cfa8078724ee0c345af96a2bccd85bf22a7c6580f",
+    "2018-07-09/rust-std-beta-x86_64-apple-darwin": "b12eafbe4c95c824d83f6bd948203bcee786cb199ec3b4a576f27b59f39b19bb",
+    "2018-07-09/rust-std-beta-x86_64-unknown-freebsd": "e100887a4f7720fe7160782a2bb40e30f5be0544eaf8cc9fc54db6bca9e69a10",
+    "2018-07-09/rust-std-beta-x86_64-unknown-linux-gnu": "244ca0c8f2b4d63d4b15a2ef65eb4aaf735ff8a563ad77c8a963ac433d4ab4d0",
+    "2018-07-09/rust-std-nightly-x86_64-apple-darwin": "251b40205aceb9310af15a39072b006a6ade88e7ab37a0adc355ab3a9008933e",
+    "2018-07-09/rust-std-nightly-x86_64-unknown-freebsd": "c7e23e9e266c4042ecb46001d87e22826fda92ffb0e3d7e425d3a9127d018f81",
+    "2018-07-09/rust-std-nightly-x86_64-unknown-linux-gnu": "2c1338e8c29422047481999713d8169eeca18aed26c0811f48c1960b7bfa30b9",
     "2018-07-10/rust-beta-x86_64-apple-darwin": "efd11e141b5a0daedeee9ba6d05bcd4fde44ab106d768a0d3852adc799b78986",
     "2018-07-10/rust-beta-x86_64-unknown-freebsd": "b43f357cff51690c2b47cf01fca7bc45653117a8928ed6aadc8bfef5bc2d6c72",
     "2018-07-10/rust-beta-x86_64-unknown-linux-gnu": "22db14a5527aa9b17396753bb3c64a84c728fa1e83dbcdd527c5ba1ee057e362",
+    "2018-07-10/rustc-beta-x86_64-apple-darwin": "7af1fcb2c37adacb611f2ddb6d8ad9a808fad6d3c97c9bcb580847dd3d87c5a7",
+    "2018-07-10/rustc-beta-x86_64-unknown-freebsd": "6ed3b079aad9259337f06d49628ddb011eebeffada5037819615f40aeb9ec486",
+    "2018-07-10/rustc-beta-x86_64-unknown-linux-gnu": "306b18b1602985bce7578971af3904f691f197b91eab2d3126fdd679a29de9ae",
+    "2018-07-10/rustc-nightly-x86_64-apple-darwin": "fd5749fe18901956c712be8b6e90cfb1eedf28193c1a3f90903182bc5e28dd38",
+    "2018-07-10/rustc-nightly-x86_64-unknown-freebsd": "75eae623c02be572fd76403b41437460ed7025674073facffbe7ac1148023f2b",
+    "2018-07-10/rustc-nightly-x86_64-unknown-linux-gnu": "eaa3078e699a2afaffe881b10cc3e2d63b3744df69cb1a279a50e35a9ac2530d",
     "2018-07-10/rust-nightly-x86_64-apple-darwin": "40c559e60ae785ad240c1c47c335ac5151d691a57b97b059c7fd9f803447bf78",
     "2018-07-10/rust-nightly-x86_64-unknown-freebsd": "76a8be14262c3f2348b69fb695b918f13a6ba4891d010e99bd5430c8b25defd0",
     "2018-07-10/rust-nightly-x86_64-unknown-linux-gnu": "bb7d3687166b0f1c768f307cd57340df342f7cd38b97ea689b90b8341dce4342",
+    "2018-07-10/rust-std-beta-x86_64-apple-darwin": "a523e9c8efc439519e741fc21ba028920a0e4f81fd5eeb78e6f65635775a7df9",
+    "2018-07-10/rust-std-beta-x86_64-unknown-freebsd": "b8f6dcdde12bd6fa82eacbc685410e6dbdd4892befd1e588a88d34e76de35ca8",
+    "2018-07-10/rust-std-beta-x86_64-unknown-linux-gnu": "0541ee1ace66ca18304aa5822fa42e016751b85e459372d9bd98633204d37173",
+    "2018-07-10/rust-std-nightly-x86_64-apple-darwin": "3d638256c2f4a7d33956a73ea141e8db6e8b5f985c487ba083cded8b02fd2e31",
+    "2018-07-10/rust-std-nightly-x86_64-unknown-freebsd": "056b8c12783c8b51aa86e77a0416dabd7027e8ec5677dd4f9f650134bb6a1a19",
+    "2018-07-10/rust-std-nightly-x86_64-unknown-linux-gnu": "8dbebab5610eba12fde192bdc6623fa70dc41cf69542fadb8fb3b1c5182c82c5",
+    "2018-07-11/rustc-nightly-x86_64-apple-darwin": "930c19558b54d6787edc57770699ac56f7cd9204a92fecaf308b7715de1276af",
+    "2018-07-11/rustc-nightly-x86_64-unknown-freebsd": "dab19e0c9da6dfae7748851b1cb86aca941d4f7ba0b48dbcbe1d47e9858b271e",
+    "2018-07-11/rustc-nightly-x86_64-unknown-linux-gnu": "da06b238742b46a2472dad314026c1603f7cc78a28209773c4aafb5b482fbea2",
     "2018-07-11/rust-nightly-x86_64-apple-darwin": "e2f2974202542b7ee54ef1a24bebc5636142caa749f422bc0caa38834ca7269a",
     "2018-07-11/rust-nightly-x86_64-unknown-freebsd": "4cde673927c0d6360c184a21d2a46911c79bb143a2ef8c3aef119004bca952e4",
     "2018-07-11/rust-nightly-x86_64-unknown-linux-gnu": "c0eedcda1085adc913ad4c945a87db77d5dc5c6e789901c2dc322b76699649b9",
+    "2018-07-11/rust-std-nightly-x86_64-apple-darwin": "85e2404e3a00ee2e307e4b15e474e2557fa622eeac660ad531c826bc99affff2",
+    "2018-07-11/rust-std-nightly-x86_64-unknown-freebsd": "491f7cfc7bae506daa6d675a0f4e4c18470c6b6ebc6f9507b530dd273c327866",
+    "2018-07-11/rust-std-nightly-x86_64-unknown-linux-gnu": "9cdf9b6ea66bc040a3eb2b1218197ca8802f4e334e9e87c0e9b276bce4776882",
     "rust-1.26.0-x86_64-apple-darwin": "38708803c3096b8f101d1919ee2d7e723b0adf1bc1bb986b060973b57d8c7c28",
     "rust-1.26.0-x86_64-unknown-freebsd": "a03cbe097670042c90d18654fbc852c9d473261d61c03d0f745bbaee759780ed",
     "rust-1.26.0-x86_64-unknown-linux-gnu": "13691d7782577fc9f110924b26603ade1990de0b691a3ce2dc324b4a72a64a68",
@@ -39,4 +87,34 @@
     "rust-1.27.1-x86_64-apple-darwin": "475be237962d6aef1038a2faada26fda1e0eaea5d71d6950229a027a9c2bfe08",
     "rust-1.27.1-x86_64-unknown-freebsd": "739d38036c9f08c13bc7425cc5cccd3dd37860fa6e9dfc7bcd9081c8d3c5ccdd",
     "rust-1.27.1-x86_64-unknown-linux-gnu": "435778a837af764da2a7a7fb4d386b7b78516c7dfc732d892858e9a8a539989b",
+    "rustc-1.26.0-x86_64-apple-darwin": "5cb67314656d16cf2a1bdc84213aaaf6afdb5811825c7afba916e2d42d3d641f",
+    "rustc-1.26.0-x86_64-unknown-freebsd": "9499ce5b68d631f8345c387e1f59b21892d97e0acb5650deb61a34719310bd38",
+    "rustc-1.26.0-x86_64-unknown-linux-gnu": "7ca9a30010602aaf2244c376a3cc5baa89429d54da17b8ba1cb0cdfdc846cc61",
+    "rustc-1.26.1-x86_64-apple-darwin": "e5f4291c3709b170fbeb17fab7fae50fe0c626dbdc5c42ddb1f342ea03acbad4",
+    "rustc-1.26.1-x86_64-unknown-freebsd": "dc3dc36010d73349152e6158522e82830fda173007b9299b0a947c90769c54ff",
+    "rustc-1.26.1-x86_64-unknown-linux-gnu": "45bc1c30e0c473c42889f22b182ec6f0b0fc3be0825e1607c64933592486eb2a",
+    "rustc-1.26.2-x86_64-apple-darwin": "5b0a3d94a4fa76ed28859123e35c09a91d7eb8ff65f40ec4c50dfa56ffed8ae5",
+    "rustc-1.26.2-x86_64-unknown-freebsd": "48f20a8dc6bc54c90aae685d0c3fa2caf3677f1c4a4d0c53aee9d15588bd0735",
+    "rustc-1.26.2-x86_64-unknown-linux-gnu": "1ebdafe52b581a63cea217a036fd6e77706d2715ae9cfe10a8c715d753326004",
+    "rustc-1.27.0-x86_64-apple-darwin": "0b00c6971ef524f68b911f621d199e60c339c390b18e12700d55e012b62aa90c",
+    "rustc-1.27.0-x86_64-unknown-freebsd": "24c193213450ffacffebdd1413d77fc3c1ed00049cf1ede2d0f3f370dd86b462",
+    "rustc-1.27.0-x86_64-unknown-linux-gnu": "29f399a1a208ea3f27f21e57f2d832e9d801c397a986aaea17e3a2ddeded6c3c",
+    "rustc-1.27.1-x86_64-apple-darwin": "747f616e07e5da9323a21c1cf9d76b53bb46094a68223d461a7333f26c714f19",
+    "rustc-1.27.1-x86_64-unknown-freebsd": "9b199c21094f996fd9d4b620a5ff2c4bc5b8dab13e96bdf7c113291f601ec944",
+    "rustc-1.27.1-x86_64-unknown-linux-gnu": "a6bf6205b345b854d705d0028a4e7161a0f5b209e464130e7d135fa01a296dc1",
+    "rust-std-1.26.0-x86_64-apple-darwin": "cb5a0114e9e383aa93267868482db84f791124ee4faafdaed08ec6782d000fc2",
+    "rust-std-1.26.0-x86_64-unknown-freebsd": "38cd138eba2ccaff59513d154fec580b6663ca6ef38cd620c348364aa1e11a40",
+    "rust-std-1.26.0-x86_64-unknown-linux-gnu": "e27cb5c21541a500c8df919e15c8d3b002456ebbe573122e7b058cf5b4c3c13a",
+    "rust-std-1.26.1-x86_64-apple-darwin": "d43e06674e645e120af6716e6d0db5771fa8818b5a48fbee9791360086cdec4a",
+    "rust-std-1.26.1-x86_64-unknown-freebsd": "1d63cc1f6dc6dfa2644619cd8c264c3d1be0fe5c44c5454e8ea04bd7beb036fb",
+    "rust-std-1.26.1-x86_64-unknown-linux-gnu": "cc7cec9a121a97e8e23c350305a0e4cd4e3b475fd5a36fa6335a585d3c511f0d",
+    "rust-std-1.26.2-x86_64-apple-darwin": "712a79cd10b96c7119980e535a36595e03c69a360f1541f690c09de858d92723",
+    "rust-std-1.26.2-x86_64-unknown-freebsd": "f54b58bf941d794ee10ab7ee9e1c94a70012073b0ee633ec2be585b1be2e31de",
+    "rust-std-1.26.2-x86_64-unknown-linux-gnu": "91634f05bf2d0a20e627aed08a8450673acecb963869273221de17130540fb26",
+    "rust-std-1.27.0-x86_64-apple-darwin": "15ee6418f9b564618e9c81a6dcd7706a2f8ae5ca24fd1b6d7527c97563a47e57",
+    "rust-std-1.27.0-x86_64-unknown-freebsd": "6e307cc3798b50b37beb9ff43e88b12fb565ddaf051925fffa35bfbeb091d660",
+    "rust-std-1.27.0-x86_64-unknown-linux-gnu": "b8cf36922315ca792929d515327c74b873358a64be4929b2ecfbe23af21e8043",
+    "rust-std-1.27.1-x86_64-apple-darwin": "a521599355e564984e43a63042b1de93dd7cf96730930501f86611dd766384e8",
+    "rust-std-1.27.1-x86_64-unknown-freebsd": "12902b61a4897ade258217f045dfac3fe83d49dd52d1e2250bd94c3a10642b08",
+    "rust-std-1.27.1-x86_64-unknown-linux-gnu": "9a1830b522117d68eeec703b50692093352212e035a46baceea666bb37739c2d",
 }
diff --git a/rust/repositories.bzl b/rust/repositories.bzl
index df57887..46267ef 100644
--- a/rust/repositories.bzl
+++ b/rust/repositories.bzl
@@ -1,37 +1,68 @@
 load(":known_shas.bzl", "FILE_KEY_TO_SHA")
 load(":triple_mappings.bzl", "triple_to_system", "triple_to_constraint_set", "system_to_binary_ext", "system_to_dylib_ext", "system_to_staticlib_ext")
 
-def generic_build_file(target_triple):
-    """Emits a BUILD file suitable to the provided target_triple."""
+DEFAULT_TOOLCHAIN_NAME_PREFIX = "toolchain_for"
+
+def _check_version_valid(version, iso_date, param_prefix = ""):
+    """Verifies that the provided rust version and iso_date make sense."""
+
+    if not version and iso_date:
+        fail("{param_prefix}iso_date must be paired with a {param_prefix}version".format(param_prefix = param_prefix))
+
+    if version in ("beta", "nightly") and not iso_date:
+        fail("{param_prefix}iso_date must be specified if version is 'beta' or 'nightly'".format(param_prefix = param_prefix))
+
+    if version not in ("beta", "nightly") and iso_date:
+        print("{param_prefix}iso_date is ineffective if an exact version is specified".format(param_prefix = param_prefix))
+
+def serialized_constraint_set_from_triple(target_triple):
+    constraint_set = triple_to_constraint_set(target_triple)
+    constraint_set_strs = []
+    for constraint in constraint_set:
+        constraint_set_strs.append("\"{}\"".format(constraint))
+    return "[{}]".format(", ".join(constraint_set_strs))
+
+def BUILD_for_compiler(target_triple):
+    """Emits a BUILD file the compiler .tar.gz."""
 
     system = triple_to_system(target_triple)
-    return """filegroup(
+    return """
+load("@io_bazel_rules_rust//rust:toolchain.bzl", "rust_toolchain")
+
+filegroup(
     name = "rustc",
-    srcs = ["rustc/bin/rustc{binary_ext}"],
+    srcs = ["bin/rustc{binary_ext}"],
     visibility = ["//visibility:public"],
 )
 
 filegroup(
     name = "rustc_lib",
-    srcs = glob(["rustc/lib/*.{dylib_ext}"]),
+    srcs = glob(["lib/*{dylib_ext}"]),
     visibility = ["//visibility:public"],
 )
 
 filegroup(
     name = "rustdoc",
-    srcs = ["rustc/bin/rustdoc{binary_ext}"],
+    srcs = ["bin/rustdoc{binary_ext}"],
     visibility = ["//visibility:public"],
 )
+""".format(
+        binary_ext = system_to_binary_ext(system),
+        staticlib_ext = system_to_staticlib_ext(system),
+        dylib_ext = system_to_dylib_ext(system),
+    )
 
+def BUILD_for_stdlib(target_triple):
+    """Emits a BUILD file the stdlib .tar.gz."""
+
+    system = triple_to_system(target_triple)
+    return """
 filegroup(
-    name = "rust_lib",
+    name = "rust_lib-{target_triple}",
     srcs = glob([
-        "rust-std-{target_triple}/lib/rustlib/{target_triple}/lib/*.rlib",
-        "rust-std-{target_triple}/lib/rustlib/{target_triple}/lib/*.{dylib_ext}",
-        "rust-std-{target_triple}/lib/rustlib/{target_triple}/lib/*.{staticlib_ext}",
-        "rustc/lib/rustlib/{target_triple}/lib/*.rlib",
-        "rustc/lib/rustlib/{target_triple}/lib/*.{dylib_ext}",
-        "rustc/lib/rustlib/{target_triple}/lib/*.{staticlib_ext}",
+        "lib/rustlib/{target_triple}/lib/*.rlib",
+        "lib/rustlib/{target_triple}/lib/*{dylib_ext}",
+        "lib/rustlib/{target_triple}/lib/*{staticlib_ext}",
     ]),
     visibility = ["//visibility:public"],
 )
@@ -42,98 +73,320 @@
         target_triple = target_triple,
     )
 
-def BUILD_for_toolchain(name, target_triple):
-    """Emits a toolchain declaration for an existing toolchain workspace."""
+def BUILD_for_rust_toolchain(workspace_name, name, exec_triple, target_triple):
+    """Emits a toolchain declaration to match an existing compiler and stdlib.
+
+    Args:
+      workspace_name: The name of the workspace that this toolchain resides in
+      name: The name of the toolchain declaration
+      exec_triple: The rust-style target that this compiler runs on
+      target_triple: The rust-style target triple of the tool
+    """
 
     system = triple_to_system(target_triple)
-    constraint_set = triple_to_constraint_set(target_triple)
 
-    constraint_set_strs = []
-    for constraint in constraint_set:
-        constraint_set_strs.append("\"{}\"".format(constraint))
-
-    constraint_sets_serialized = "[{}]".format(", ".join(constraint_set_strs))
-
-    return """toolchain(
-    name = "{toolchain_name}",
-    exec_compatible_with = {constraint_sets_serialized},
-    target_compatible_with = {constraint_sets_serialized},
-    toolchain = ":{toolchain_name}_impl",
-    toolchain_type = "@io_bazel_rules_rust//rust:toolchain",
-)
-
+    return """
 rust_toolchain(
     name = "{toolchain_name}_impl",
-    rust_doc = "@{toolchain_workspace_name}//:rustdoc",
-    rust_lib = ["@{toolchain_workspace_name}//:rust_lib"],
-    rustc = "@{toolchain_workspace_name}//:rustc",
-    rustc_lib = ["@{toolchain_workspace_name}//:rustc_lib"],
+    rust_doc = "@{workspace_name}//:rustdoc",
+    rust_lib = ["@{workspace_name}//:rust_lib-{target_triple}"],
+    rustc = "@{workspace_name}//:rustc",
+    rustc_lib = ["@{workspace_name}//:rustc_lib"],
     staticlib_ext = "{staticlib_ext}",
     dylib_ext = "{dylib_ext}",
     os = "{system}",
+    exec_triple = "{exec_triple}",
+    target_triple = "{target_triple}",
     visibility = ["//visibility:public"],
 )
 """.format(
         toolchain_name = name,
-        toolchain_workspace_name = name.replace("-", "_"),
+        workspace_name = workspace_name,
         staticlib_ext = system_to_staticlib_ext(system),
         dylib_ext = system_to_dylib_ext(system),
         system = system,
-        constraint_sets_serialized = constraint_sets_serialized,
+        exec_triple = exec_triple,
+        target_triple = target_triple,
     )
 
-def _default_toolchains():
-    all_toolchains = [
-        ("rust-linux-x86_64", "x86_64-unknown-linux-gnu"),
-        ("rust-darwin-x86_64", "x86_64-apple-darwin"),
-        ("rust-freebsd-x86_64", "x86_64-unknown-freebsd"),
-    ]
-
-    all_toolchain_BUILDs = []
-    for toolchain in all_toolchains:
-        all_toolchain_BUILDs.append(BUILD_for_toolchain(toolchain[0], toolchain[1]))
-
+def BUILD_for_toolchain(name, parent_workspace_name, exec_triple, target_triple):
     return """
-load("@io_bazel_rules_rust//rust:toolchain.bzl", "rust_toolchain")
-
-{all_toolchain_BUILDs}
-""".format(all_toolchain_BUILDs = "\n".join(all_toolchain_BUILDs))
-
-# Eventually with better toolchain hosting options we could load only one of these, not both.
-def rust_repositories():
-    native.new_http_archive(
-        name = "rust_linux_x86_64",
-        url = "https://static.rust-lang.org/dist/rust-1.26.1-x86_64-unknown-linux-gnu.tar.gz",
-        strip_prefix = "rust-1.26.1-x86_64-unknown-linux-gnu",
-        sha256 = FILE_KEY_TO_SHA.get("rust-1.26.1-x86_64-unknown-linux-gnu") or "",
-        build_file_content = generic_build_file("x86_64-unknown-linux-gnu"),
+toolchain(
+    name = "{name}",
+    exec_compatible_with = {exec_constraint_sets_serialized},
+    target_compatible_with = {target_constraint_sets_serialized},
+    toolchain = "@{parent_workspace_name}//:{name}_impl",
+    toolchain_type = "@io_bazel_rules_rust//rust:toolchain",
+)
+""".format(
+        name = name,
+        exec_constraint_sets_serialized = serialized_constraint_set_from_triple(exec_triple),
+        target_constraint_sets_serialized = serialized_constraint_set_from_triple(target_triple),
+        parent_workspace_name = parent_workspace_name,
     )
 
-    native.new_http_archive(
-        name = "rust_darwin_x86_64",
-        url = "https://static.rust-lang.org/dist/rust-1.26.1-x86_64-apple-darwin.tar.gz",
-        strip_prefix = "rust-1.26.1-x86_64-apple-darwin",
-        sha256 = FILE_KEY_TO_SHA.get("rust-1.26.1-x86_64-apple-darwin") or "",
-        build_file_content = generic_build_file("x86_64-apple-darwin"),
+def produce_tool_suburl(tool_name, target_triple, version, iso_date = None):
+    """Produces a fully qualified Rust tool name for URL
+
+    Args:
+      tool_name: The name of the tool per static.rust-lang.org
+      target_triple: The rust-style target triple of the tool
+      version: The version of the tool among "nightly", "beta', or an exact version.
+      iso_date: The date of the tool (or None, if the version is a specific version).
+    """
+
+    if iso_date:
+        return "{}/{}-{}-{}".format(iso_date, tool_name, version, target_triple)
+    else:
+        return "{}-{}-{}".format(tool_name, version, target_triple)
+
+def produce_tool_path(tool_name, target_triple, version):
+    """Produces a qualified Rust tool name
+
+    Args:
+      tool_name: The name of the tool per static.rust-lang.org
+      target_triple: The rust-style target triple of the tool
+      version: The version of the tool among "nightly", "beta', or an exact version.
+    """
+
+    return "{}-{}-{}".format(tool_name, version, target_triple)
+
+def load_arbitrary_tool(ctx, tool_name, param_prefix, tool_subdirectory, version, iso_date, target_triple):
+    """Loads a Rust tool, downloads, and extracts into the common workspace.
+
+    This function sources the tool from the Rust-lang static file server. The index is available
+    at: https://static.rust-lang.org/dist/index.html
+
+    Args:
+      ctx: A repository_ctx (no attrs required).
+      tool_name: The name of the given tool per the archive naming.
+      param_prefix: The name of the versioning param if the repository rule supports multiple tools.
+      tool_subdirectory: The subdirectory of the tool files (wo level below the root directory of
+                         the archive. The root directory of the archive is expected to match
+                         $TOOL_NAME-$VERSION-$TARGET_TRIPLE.
+      version: The version of the tool among "nightly", "beta', or an exact version.
+      iso_date: The date of the tool (or None, if the version is a specific version).
+      target_triple: The rust-style target triple of the tool
+    """
+
+    _check_version_valid(version, iso_date, param_prefix)
+
+    # N.B. See https://static.rust-lang.org/dist/index.html to find the tool_suburl for a given
+    # tool.
+    tool_suburl = produce_tool_suburl(tool_name, target_triple, version, iso_date)
+    url = "https://static.rust-lang.org/dist/{}.tar.gz".format(tool_suburl)
+
+    tool_path = produce_tool_path(tool_name, target_triple, version)
+    ctx.download_and_extract(
+        url,
+        output = "",
+        sha256 = FILE_KEY_TO_SHA.get(tool_suburl) or "",
+        stripPrefix = "{}/{}".format(tool_path, tool_subdirectory),
     )
 
-    native.new_http_archive(
-        name = "rust_freebsd_x86_64",
-        url = "https://static.rust-lang.org/dist/rust-1.26.1-x86_64-unknown-freebsd.tar.gz",
-        strip_prefix = "rust-1.26.1-x86_64-unknown-freebsd",
-        sha256 = FILE_KEY_TO_SHA.get("rust-1.26.1-x86_64-unknown-freebsd") or "",
-        build_file_content = generic_build_file("x86_64-unknown-freebsd"),
+def _load_rust_compiler(ctx):
+    """Loads a rust compiler and yields corresponding BUILD for it
+
+    Args:
+      ctx: A repository_ctx.
+    Returns:
+      The BUILD file contents for this compiler and compiler library
+    """
+
+    target_triple = ctx.attr.exec_triple
+    load_arbitrary_tool(
+        ctx,
+        iso_date = ctx.attr.iso_date,
+        param_prefix = "rustc_",
+        target_triple = target_triple,
+        tool_name = "rustc",
+        tool_subdirectory = "rustc",
+        version = ctx.attr.version,
     )
 
-    native.new_local_repository(
-        name = "rust_default_toolchains",
-        path = ".",
-        build_file_content = _default_toolchains(),
+    compiler_BUILD = BUILD_for_compiler(target_triple)
+
+    return compiler_BUILD
+
+def _load_rust_stdlib(ctx, target_triple):
+    """Loads a rust standard library and yields corresponding BUILD for it
+
+    Args:
+      ctx: A repository_ctx.
+      target_triple: The rust-style target triple of the tool
+    Returns:
+      The BUILD file contents for this stdlib, and a toolchain decl to match
+    """
+
+    load_arbitrary_tool(
+        ctx,
+        iso_date = ctx.attr.iso_date,
+        param_prefix = "rust-std_",
+        target_triple = target_triple,
+        tool_name = "rust-std",
+        tool_subdirectory = "rust-std-{}".format(target_triple),
+        version = ctx.attr.version,
     )
 
+    toolchain_prefix = ctx.attr.toolchain_name_prefix or DEFAULT_TOOLCHAIN_NAME_PREFIX
+    stdlib_BUILD = BUILD_for_stdlib(target_triple)
+    toolchain_BUILD = BUILD_for_rust_toolchain(
+        name = "{toolchain_prefix}_{target_triple}".format(
+            toolchain_prefix = toolchain_prefix,
+            target_triple = target_triple,
+        ),
+        exec_triple = ctx.attr.exec_triple,
+        target_triple = target_triple,
+        workspace_name = ctx.attr.name,
+    )
+
+    return stdlib_BUILD + toolchain_BUILD
+
+def _rust_toolchain_repository_impl(ctx):
+    """The implementation of the rust toolchain repository rule."""
+
+    _check_version_valid(ctx.attr.version, ctx.attr.iso_date)
+
+    BUILD_components = [_load_rust_compiler(ctx)]
+    for target_triple in [ctx.attr.exec_triple] + ctx.attr.extra_target_triples:
+        BUILD_components.append(_load_rust_stdlib(ctx, target_triple))
+
+    ctx.file("WORKSPACE", "")
+    ctx.file("BUILD", "\n".join(BUILD_components))
+
+def _rust_toolchain_repository_proxy_impl(ctx):
+    BUILD_components = []
+    for target_triple in [ctx.attr.exec_triple] + ctx.attr.extra_target_triples:
+        BUILD_components.append(BUILD_for_toolchain(
+            name = "{toolchain_prefix}_{target_triple}".format(
+                toolchain_prefix = ctx.attr.toolchain_name_prefix,
+                target_triple = target_triple,
+            ),
+            exec_triple = ctx.attr.exec_triple,
+            parent_workspace_name = ctx.attr.parent_workspace_name,
+            target_triple = target_triple,
+        ))
+
+    ctx.file("WORKSPACE", "")
+    ctx.file("BUILD", "\n".join(BUILD_components))
+
+"""Composes a single workspace containing the toolchain components for compiling on a given
+platform to a series of target platforms.
+
+A given instance of this rule should be accompanied by a rust_toolchain_repository_proxy
+invocation to declare its toolchains to Bazel; the indirection allows separating toolchain
+selection from toolchain fetching
+
+Args:
+  name: A unique name for this rule
+  exec_triple: The Rust-style target triple for the compilation platform
+  extra_target_triples: The Rust-style triples for extra compilation targets
+  toolchain_name_prefix: The per-target prefix expected for the rust_toolchain declarations
+  version: The version of the tool among "nightly", "beta', or an exact version.
+  iso_date: The date of the tool (or None, if the version is a specific version).
+"""
+
+rust_toolchain_repository = repository_rule(
+    attrs = {
+        "version": attr.string(mandatory = True),
+        "iso_date": attr.string(),
+        "exec_triple": attr.string(mandatory = True),
+        "extra_target_triples": attr.string_list(),
+        "toolchain_name_prefix": attr.string(),
+    },
+    implementation = _rust_toolchain_repository_impl,
+)
+
+"""Generates a toolchain-bearing repository that declares the toolchains from some other
+rust_toolchain_repository.
+
+Args:
+  name: A unique name for this rule
+  parent_workspace_name: The name of the other rust_toolchain_repository
+  exec_triple: The Rust-style target triple for the compilation platform
+  extra_target_triples: The Rust-style triples for extra compilation targets
+  toolchain_name_prefix: The per-target prefix expected for the rust_toolchain declarations in the
+                         parent workspace.
+"""
+
+rust_toolchain_repository_proxy = repository_rule(
+    attrs = {
+        "parent_workspace_name": attr.string(mandatory = True),
+        "exec_triple": attr.string(mandatory = True),
+        "extra_target_triples": attr.string_list(),
+        "toolchain_name_prefix": attr.string(),
+    },
+    implementation = _rust_toolchain_repository_proxy_impl,
+)
+
+def rust_repository_set(name, version, exec_triple, extra_target_triples, iso_date = None):
+    """Assembles a remote repository for the given toolchain params, produces a proxy repository
+    to contain the toolchain declaration, and registers the toolchains.
+
+    N.B. A "proxy repository" is needed to allow for registering the toolchain (with constraints)
+    without actually downloading the toolchain.
+
+    Args:
+      name: The name of the generated repository
+      version: The version of the tool among "nightly", "beta', or an exact version.
+      iso_date: The date of the tool (or None, if the version is a specific version).
+      exec_triple: The Rust-style target that this compiler runs on
+      extra_target_triples: Additional rust-style targets that this set of toolchains
+                            should support.
+    """
+
+    rust_toolchain_repository(
+        name = name,
+        exec_triple = exec_triple,
+        extra_target_triples = extra_target_triples,
+        iso_date = iso_date,
+        toolchain_name_prefix = DEFAULT_TOOLCHAIN_NAME_PREFIX,
+        version = version,
+    )
+
+    rust_toolchain_repository_proxy(
+        name = name + "_toolchains",
+        exec_triple = exec_triple,
+        extra_target_triples = extra_target_triples,
+        parent_workspace_name = name,
+        toolchain_name_prefix = DEFAULT_TOOLCHAIN_NAME_PREFIX,
+    )
+
+    all_toolchain_names = []
+    for target_triple in [exec_triple] + extra_target_triples:
+        all_toolchain_names.append("@{name}_toolchains//:{toolchain_name_prefix}_{triple}".format(
+            name = name,
+            toolchain_name_prefix = DEFAULT_TOOLCHAIN_NAME_PREFIX,
+            triple = target_triple,
+        ))
+
     # Register toolchains
-    native.register_toolchains(
-        "@rust_default_toolchains//:rust-linux-x86_64",
-        "@rust_default_toolchains//:rust-darwin-x86_64",
-        "@rust_default_toolchains//:rust-freebsd-x86_64",
+    native.register_toolchains(*all_toolchain_names)
+
+def rust_repositories():
+    """Emits a default set of toolchains for Linux, OSX, and Freebsd
+
+    Skip this macro and call the `rust_repository_set` macros directly if you need a compiler for
+    other hosts or for additional target triples.
+    """
+
+    rust_repository_set(
+        name = "rust_linux_x86_64",
+        exec_triple = "x86_64-unknown-linux-gnu",
+        extra_target_triples = [],
+        version = "1.26.1",
+    )
+
+    rust_repository_set(
+        name = "rust_darwin_x86_64",
+        exec_triple = "x86_64-apple-darwin",
+        extra_target_triples = [],
+        version = "1.26.1",
+    )
+
+    rust_repository_set(
+        name = "rust_freebsd_x86_64",
+        exec_triple = "x86_64-unknown-freebsd",
+        extra_target_triples = [],
+        version = "1.26.1",
     )
diff --git a/rust/toolchain.bzl b/rust/toolchain.bzl
index 58d31fa..cbdefd8 100644
--- a/rust/toolchain.bzl
+++ b/rust/toolchain.bzl
@@ -247,6 +247,8 @@
         "staticlib_ext": attr.string(mandatory = True),
         "dylib_ext": attr.string(mandatory = True),
         "os": attr.string(mandatory = True),
+        "exec_triple": attr.string(),
+        "target_triple": attr.string(),
         "_crosstool": attr.label(
             default = Label("//tools/defaults:crosstool"),
         ),
diff --git a/util/fetch_shas_TOOLS.txt b/util/fetch_shas_TOOLS.txt
index 871732e..8c6cfce 100644
--- a/util/fetch_shas_TOOLS.txt
+++ b/util/fetch_shas_TOOLS.txt
@@ -1 +1,3 @@
 rust
+rustc
+rust-std