| Fetch rustc the way buck can ship it, from what DotSlash already pins 8cf1b33 nandi 19d ago | 1 | # A Rust toolchain whose compiler is a dependency rather than a name. |
| 2 | # |
| 3 | # The prelude's system_rust_toolchain hands RustToolchainInfo |
| 4 | # `RunInfo(args = ["rustc"])` — a bare string. Nothing about the compiler is an |
| 5 | # input to any action, so nothing about it reaches the action's cache digest, |
| 6 | # and there is nothing for a remote worker to materialise. Both of this repo's |
| 7 | # problems come from that one line: a shared cache cannot tell two compilers |
| 8 | # apart, and remote execution has no compiler to run. |
| 9 | # |
| 10 | # Here the dist tarball is a dep. cmd_args carries the archive's directory into |
| 11 | # every rustc invocation, so buck knows the action depends on it. |
| 12 | load("@prelude//rust:rust_toolchain.bzl", "PanicRuntime", "RustToolchainInfo") |
| 13 | |
| 14 | def _hermetic_rust_toolchain_impl(ctx): |
| 15 | dist = ctx.attrs.dist[DefaultInfo].default_outputs[0] |
| 16 | |
| 17 | # The dist tarball keeps its components in sibling directories, so the |
| 18 | # compiler's default sysroot (rustc/) holds no libstd — it lives under |
| 19 | # rust-std-<triple>/. The same stitching scripts/rustc does by hand, said |
| 20 | # to buck instead. The compiler's own codegen libraries are found by rpath, |
| 21 | # relative to the binary, so only the sysroot has to be named. |
| 22 | # rustc goes through a wrapper because the sysroot cannot travel any other |
| 23 | # way: rustc_flags takes plain strings, so an artifact path cannot be put |
| 24 | # there, and putting --sysroot on the compiler unconditionally breaks |
| 25 | # buck's own rustc_cfg action, which passes an empty one. Both the wrapper |
| 26 | # and the tarball are inputs, which is the point. |
| 27 | wrapper = ctx.attrs.wrapper[DefaultInfo].default_outputs[0] |
| 28 | compiler = cmd_args(wrapper, dist, ctx.attrs.rustc_target_triple) |
| 29 | rustdoc = cmd_args(dist, format = "{}/rustc/bin/rustdoc") |
| 30 | |
| 31 | return [ |
| 32 | DefaultInfo(), |
| 33 | RustToolchainInfo( |
| 34 | allow_lints = ctx.attrs.allow_lints, |
| 35 | clippy_driver = RunInfo(args = cmd_args(dist, format = "{}/clippy/bin/clippy-driver")), |
| 36 | clippy_toml = None, |
| 37 | compiler = RunInfo(args = compiler), |
| 38 | default_edition = ctx.attrs.default_edition, |
| 39 | panic_runtime = PanicRuntime("unwind"), |
| 40 | deny_lints = ctx.attrs.deny_lints, |
| 41 | doctests = ctx.attrs.doctests, |
| 42 | nightly_features = ctx.attrs.nightly_features, |
| 43 | report_unused_deps = ctx.attrs.report_unused_deps, |
| 44 | rustc_binary_flags = ctx.attrs.rustc_binary_flags, |
| 45 | rustc_flags = ctx.attrs.rustc_flags, |
| 46 | rustc_target_triple = ctx.attrs.rustc_target_triple, |
| 47 | rustc_test_flags = ctx.attrs.rustc_test_flags, |
| 48 | rustdoc = RunInfo(args = rustdoc), |
| 49 | rustdoc_flags = ctx.attrs.rustdoc_flags, |
| 50 | warn_lints = ctx.attrs.warn_lints, |
| 51 | ), |
| 52 | ] |
| 53 | |
| 54 | hermetic_rust_toolchain = rule( |
| 55 | impl = _hermetic_rust_toolchain_impl, |
| 56 | attrs = { |
| 57 | "allow_lints": attrs.list(attrs.string(), default = []), |
| 58 | "default_edition": attrs.option(attrs.string(), default = None), |
| 59 | "deny_lints": attrs.list(attrs.string(), default = []), |
| 60 | "dist": attrs.dep(providers = [DefaultInfo]), |
| 61 | "wrapper": attrs.dep(providers = [DefaultInfo]), |
| 62 | "doctests": attrs.bool(default = False), |
| 63 | "nightly_features": attrs.bool(default = True), |
| 64 | "report_unused_deps": attrs.bool(default = False), |
| 65 | "rustc_binary_flags": attrs.list(attrs.arg(), default = []), |
| 66 | "rustc_flags": attrs.list(attrs.arg(), default = []), |
| 67 | "rustc_target_triple": attrs.string(), |
| 68 | "rustc_test_flags": attrs.list(attrs.arg(), default = []), |
| 69 | "rustdoc_flags": attrs.list(attrs.arg(), default = []), |
| 70 | "warn_lints": attrs.list(attrs.string(), default = []), |
| 71 | }, |
| 72 | is_toolchain_rule = True, |
| 73 | ) |
| Make the C toolchain a dependency too, so zig travels with the action 6391496 nandi 19d ago | 74 | |
| 75 | # A C toolchain whose tools are dependencies rather than names. |
| 76 | # |
| 77 | # The prelude's system_cxx_toolchain cannot be made hermetic: it takes its |
| 78 | # tools as plain strings, so nothing it names becomes an input, and it |
| 79 | # hardcodes nm/objcopy/objdump/ranlib/strip as bare PATH lookups regardless of |
| 80 | # what is passed. This is the same construction with zig behind every tool that |
| 81 | # this graph actually runs. |
| 82 | load("@prelude//cxx:cxx_toolchain_types.bzl", "BinaryUtilitiesInfo", "CCompilerInfo", "CxxCompilerInfo", "CxxInternalTools", "CxxPlatformInfo", "CxxToolchainInfo", "DepTrackingMode", "LinkerInfo", "LinkerType", "PicBehavior", "RuntimeDependencyHandling", "ShlibInterfacesMode") |
| 83 | load("@prelude//cxx:headers.bzl", "HeaderMode") |
| 84 | load("@prelude//linking:link_info.bzl", "LinkOrdering", "LinkStyle") |
| 85 | load("@prelude//linking:lto.bzl", "LtoMode") |
| 86 | |
| 87 | def _hermetic_cxx_toolchain_impl(ctx: AnalysisContext): |
| 88 | dist = ctx.attrs.dist[DefaultInfo].default_outputs[0] |
| 89 | wrapper = ctx.attrs.wrapper[DefaultInfo].default_outputs[0] |
| 90 | |
| 91 | def zig(mode): |
| 92 | return RunInfo(args = cmd_args(wrapper, dist, mode)) |
| 93 | |
| 94 | cc = zig("cc") |
| 95 | |
| 96 | return [ |
| 97 | DefaultInfo(), |
| 98 | CxxToolchainInfo( |
| 99 | internal_tools = ctx.attrs.internal_tools[CxxInternalTools], |
| 100 | linker_info = LinkerInfo( |
| 101 | linker = cc, |
| 102 | linker_flags = ["-fuse-ld=lld"] + ctx.attrs.link_flags, |
| 103 | post_linker_flags = [], |
| 104 | archiver = zig("ar"), |
| 105 | archiver_type = "gnu", |
| 106 | archiver_supports_argfiles = True, |
| 107 | generate_linker_maps = False, |
| 108 | lto_mode = LtoMode("none"), |
| 109 | type = LinkerType("gnu"), |
| 110 | link_binaries_locally = True, |
| 111 | link_libraries_locally = True, |
| 112 | archive_objects_locally = True, |
| 113 | use_archiver_flags = True, |
| 114 | static_dep_runtime_ld_flags = [], |
| 115 | static_pic_dep_runtime_ld_flags = [], |
| 116 | shared_dep_runtime_ld_flags = [], |
| 117 | independent_shlib_interface_linker_flags = [], |
| 118 | shlib_interfaces = ShlibInterfacesMode("disabled"), |
| 119 | link_style = LinkStyle(ctx.attrs.link_style), |
| 120 | link_weight = 1, |
| 121 | binary_extension = "", |
| 122 | object_file_extension = "o", |
| 123 | shared_library_name_default_prefix = "lib", |
| 124 | shared_library_name_format = "{}.so", |
| 125 | shared_library_versioned_name_format = "{}.so.{}", |
| 126 | static_library_extension = "a", |
| 127 | force_full_hybrid_if_capable = False, |
| 128 | is_pdb_generated = False, |
| 129 | link_ordering = ctx.attrs.link_ordering, |
| 130 | ), |
| 131 | bolt_enabled = False, |
| 132 | # zig carries ar, ranlib and objcopy and nothing else. nm, objdump |
| 133 | # and strip stay bare names: this graph never reaches them — shared |
| 134 | # library interfaces are disabled and nothing is stripped — and a |
| 135 | # build that did would need an llvm dist fetched alongside zig |
| 136 | # rather than a PATH lookup that happens to work. |
| 137 | binary_utilities_info = BinaryUtilitiesInfo( |
| 138 | nm = RunInfo(args = ["nm"]), |
| 139 | objcopy = zig("objcopy"), |
| 140 | objdump = RunInfo(args = ["objdump"]), |
| 141 | ranlib = zig("ranlib"), |
| 142 | strip = RunInfo(args = ["strip"]), |
| 143 | dwp = None, |
| 144 | bolt_msdk = None, |
| 145 | ), |
| 146 | cxx_compiler_info = CxxCompilerInfo( |
| 147 | compiler = zig("c++"), |
| 148 | preprocessor_flags = [], |
| 149 | compiler_flags = ctx.attrs.cxx_flags, |
| 150 | compiler_type = "clang", |
| 151 | ), |
| 152 | c_compiler_info = CCompilerInfo( |
| 153 | compiler = cc, |
| 154 | preprocessor_flags = [], |
| 155 | compiler_flags = ctx.attrs.c_flags, |
| 156 | compiler_type = "clang", |
| 157 | ), |
| 158 | as_compiler_info = CCompilerInfo( |
| 159 | compiler = cc, |
| 160 | compiler_type = "clang", |
| 161 | ), |
| 162 | asm_compiler_info = CCompilerInfo( |
| 163 | compiler = cc, |
| 164 | compiler_type = "clang", |
| 165 | ), |
| 166 | header_mode = HeaderMode("symlink_tree_only"), |
| 167 | cpp_dep_tracking_mode = DepTrackingMode("show_headers"), |
| 168 | pic_behavior = PicBehavior("supported"), |
| 169 | llvm_link = None, |
| 170 | use_dep_files = True, |
| 171 | runtime_dependency_handling = RuntimeDependencyHandling("no_symlink"), |
| 172 | ), |
| 173 | CxxPlatformInfo(name = "x86_64"), |
| 174 | ] |
| 175 | |
| 176 | hermetic_cxx_toolchain = rule( |
| 177 | impl = _hermetic_cxx_toolchain_impl, |
| 178 | attrs = { |
| 179 | "c_flags": attrs.list(attrs.arg(), default = []), |
| 180 | "cxx_flags": attrs.list(attrs.arg(), default = []), |
| 181 | "dist": attrs.dep(providers = [DefaultInfo]), |
| 182 | "internal_tools": attrs.default_only(attrs.dep(providers = [CxxInternalTools], default = "prelude//cxx/tools:internal_tools")), |
| 183 | "link_flags": attrs.list(attrs.arg(), default = []), |
| 184 | "link_ordering": attrs.option(attrs.enum(LinkOrdering.values()), default = None), |
| 185 | "link_style": attrs.string(default = "shared"), |
| 186 | "wrapper": attrs.dep(providers = [DefaultInfo]), |
| 187 | }, |
| 188 | is_toolchain_rule = True, |
| 189 | ) |