| """A module defining Rust link time optimization (lto) rules""" |
| |
| load("//rust/private:utils.bzl", "is_exec_configuration") |
| |
| _LTO_MODES = [ |
| # Do nothing, let the user manually handle LTO. |
| "manual", |
| # Default. No mode has been explicitly set, rustc will do "thin local" LTO |
| # between the codegen units of a single crate. |
| "unspecified", |
| # LTO has been explicitly turned "off". |
| "off", |
| # Perform "thin" LTO. This is similar to "fat" but takes significantly less |
| # time to run, but provides similar performance improvements. |
| # |
| # See: <http://blog.llvm.org/2016/06/thinlto-scalable-and-incremental-lto.html> |
| "thin", |
| # Perform "fat"/full LTO. |
| "fat", |
| ] |
| |
| RustLtoInfo = provider( |
| doc = "A provider describing the link time optimization setting.", |
| fields = {"mode": "string: The LTO mode specified via a build setting."}, |
| ) |
| |
| def _rust_lto_flag_impl(ctx): |
| value = ctx.build_setting_value |
| |
| if value not in _LTO_MODES: |
| msg = "{NAME} build setting allowed to take values [{VALUES}], but was set to: {ACTUAL}".format( |
| NAME = ctx.label, |
| VALUES = ", ".join(["'{}'".format(m) for m in _LTO_MODES]), |
| ACTUAL = value, |
| ) |
| fail(msg) |
| |
| return RustLtoInfo(mode = value) |
| |
| rust_lto_flag = rule( |
| doc = "A build setting which specifies the link time optimization mode used when building Rust code. Allowed values are: ".format(_LTO_MODES), |
| implementation = _rust_lto_flag_impl, |
| build_setting = config.string(flag = True), |
| ) |
| |
| def _determine_lto_object_format(ctx, toolchain, crate_info): |
| """Determines if we should run LTO and what bitcode should get included in a built artifact. |
| |
| Args: |
| ctx (ctx): The calling rule's context object. |
| toolchain (rust_toolchain): The current target's `rust_toolchain`. |
| crate_info (CrateInfo): The CrateInfo provider of the target crate. |
| |
| Returns: |
| string: Returns one of only_object, only_bitcode, object_and_bitcode. |
| """ |
| |
| # Even if LTO is enabled don't use it for actions being built in the exec |
| # configuration, e.g. build scripts and proc-macros. This mimics Cargo. |
| if is_exec_configuration(ctx): |
| return "only_object" |
| |
| mode = toolchain.lto.mode |
| |
| if mode in ["off", "unspecified"]: |
| return "only_object" |
| |
| perform_linking = crate_info.type in ["bin", "staticlib", "cdylib"] |
| is_dynamic = crate_info.type in ["dylib", "cdylib", "proc-macro"] |
| needs_object = perform_linking or is_dynamic |
| |
| # At this point we know LTO is enabled, otherwise we would have returned above. |
| |
| if not needs_object: |
| # If we're building an 'rlib' and LTO is enabled, then we can skip |
| # generating object files entirely. |
| return "only_bitcode" |
| elif crate_info.type in ["dylib", "proc-macro"]: |
| # If we're a dylib and we're running LTO, then only emit object code |
| # because 'rustc' doesn't currently support LTO with dylibs. |
| # proc-macros do not benefit from LTO, and cannot be dynamically linked with LTO. |
| return "only_object" |
| else: |
| return "object_and_bitcode" |
| |
| def construct_lto_arguments(ctx, toolchain, crate_info): |
| """Returns a list of 'rustc' flags to configure link time optimization. |
| |
| Args: |
| ctx (ctx): The calling rule's context object. |
| toolchain (rust_toolchain): The current target's `rust_toolchain`. |
| crate_info (CrateInfo): The CrateInfo provider of the target crate. |
| |
| Returns: |
| list: A list of strings that are valid flags for 'rustc'. |
| """ |
| mode = toolchain.lto.mode |
| |
| # The user is handling LTO on their own, don't add any arguments. |
| if mode == "manual": |
| return [] |
| |
| format = _determine_lto_object_format(ctx, toolchain, crate_info) |
| args = [] |
| |
| # proc-macros do not benefit from LTO, and cannot be dynamically linked with LTO. |
| if mode in ["thin", "fat", "off"] and not is_exec_configuration(ctx) and crate_info.type != "proc-macro": |
| args.append("lto={}".format(mode)) |
| |
| if format == "object_and_bitcode": |
| # Embedding LLVM bitcode in object files is `rustc's` default. |
| args.extend([]) |
| elif format == "only_object": |
| args.extend(["embed-bitcode=no"]) |
| elif format == "only_bitcode": |
| args.extend(["linker-plugin-lto"]) |
| else: |
| fail("unrecognized LTO object format {}".format(format)) |
| |
| return ["-C{}".format(arg) for arg in args] |