diff options
Diffstat (limited to 'rust/private/rustc.bzl')
-rw-r--r-- | rust/private/rustc.bzl | 175 |
1 files changed, 95 insertions, 80 deletions
diff --git a/rust/private/rustc.bzl b/rust/private/rustc.bzl index 5c11f762..e1012230 100644 --- a/rust/private/rustc.bzl +++ b/rust/private/rustc.bzl @@ -38,6 +38,7 @@ load( "make_static_lib_symlink", "relativize", ) +load(":utils.bzl", "is_std_dylib") BuildInfo = _BuildInfo @@ -310,18 +311,19 @@ def collect_deps( transitive_link_search_paths.append(dep_info.link_search_path_files) transitive_build_infos.append(dep_info.transitive_build_infos) - - elif cc_info: - # This dependency is a cc_library - transitive_noncrates.append(cc_info.linking_context.linker_inputs) - elif dep_build_info: - if build_info: - fail("Several deps are providing build information, " + - "only one is allowed in the dependencies") - build_info = dep_build_info - transitive_build_infos.append(depset([build_info])) - if build_info.link_search_paths: - transitive_link_search_paths.append(depset([build_info.link_search_paths])) + elif cc_info or dep_build_info: + if cc_info: + # This dependency is a cc_library + transitive_noncrates.append(cc_info.linking_context.linker_inputs) + + if dep_build_info: + if build_info: + fail("Several deps are providing build information, " + + "only one is allowed in the dependencies") + build_info = dep_build_info + transitive_build_infos.append(depset([build_info])) + if build_info.link_search_paths: + transitive_link_search_paths.append(depset([build_info.link_search_paths])) else: fail("rust targets can only depend on rust_library, rust_*_library or cc_library " + "targets.") @@ -390,7 +392,7 @@ def get_cc_user_link_flags(ctx): """ return ctx.fragments.cpp.linkopts -def get_linker_and_args(ctx, attr, crate_type, cc_toolchain, feature_configuration, rpaths, rustdoc = False): +def get_linker_and_args(ctx, attr, crate_type, cc_toolchain, feature_configuration, rpaths, add_flags_for_binary = False): """Gathers cc_common linker information Args: @@ -400,7 +402,7 @@ def get_linker_and_args(ctx, attr, crate_type, cc_toolchain, feature_configurati cc_toolchain (CcToolchain): cc_toolchain for which we are creating build variables. feature_configuration (FeatureConfiguration): Feature configuration to be queried. rpaths (depset): Depset of directories where loader will look for libraries at runtime. - rustdoc (bool, optional): Whether to add "bin" link flags to the command regardless of `crate_type`. + add_flags_for_binary (bool, optional): Whether to add "bin" link flags to the command regardless of `crate_type`. Returns: @@ -411,7 +413,7 @@ def get_linker_and_args(ctx, attr, crate_type, cc_toolchain, feature_configurati """ user_link_flags = get_cc_user_link_flags(ctx) - if crate_type in ("bin") or rustdoc: + if crate_type in ("bin") or add_flags_for_binary: is_linking_dynamic_library = False action_name = CPP_LINK_EXECUTABLE_ACTION_NAME elif crate_type in ("dylib"): @@ -429,7 +431,7 @@ def get_linker_and_args(ctx, attr, crate_type, cc_toolchain, feature_configurati else: fail("Unknown `crate_type`: {}".format(crate_type)) - # Add linkopt's from dependencies. This includes linkopts from transitive + # Add linkopts from dependencies. This includes linkopts from transitive # dependencies since they get merged up. for dep in getattr(attr, "deps", []): if CcInfo in dep and dep[CcInfo].linking_context: @@ -463,13 +465,15 @@ def get_linker_and_args(ctx, attr, crate_type, cc_toolchain, feature_configurati def _process_build_scripts( build_info, dep_info, - compile_inputs): + compile_inputs, + include_link_flags = True): """Gathers the outputs from a target's `cargo_build_script` action. Args: build_info (BuildInfo): The target Build's dependency info. dep_info (DepInfo): The Depinfo provider form the target Crate's set of inputs. compile_inputs (depset): A set of all files that will participate in the build. + include_link_flags (bool, optional): Whether to include flags like `-l` that instruct the linker to search for a library. Returns: tuple: A tuple: A tuple of the following items: @@ -478,7 +482,7 @@ def _process_build_scripts( - (File): An optional path to a generated environment file from a `cargo_build_script` target - (depset[File]): All direct and transitive build flags from the current build info. """ - extra_inputs, out_dir, build_env_file, build_flags_files = _create_extra_input_args(build_info, dep_info) + extra_inputs, out_dir, build_env_file, build_flags_files = _create_extra_input_args(build_info, dep_info, include_link_flags = include_link_flags) compile_inputs = depset(transitive = [extra_inputs, compile_inputs]) return compile_inputs, out_dir, build_env_file, build_flags_files @@ -639,7 +643,8 @@ def collect_inputs( build_info, stamp = False, force_depend_on_objects = False, - experimental_use_cc_common_link = False): + experimental_use_cc_common_link = False, + include_link_flags = True): """Gather's the inputs and required input information for a rustc action Args: @@ -658,7 +663,8 @@ def collect_inputs( force_depend_on_objects (bool, optional): Forces dependencies of this rule to be objects rather than metadata, even for libraries. This is used in rustdoc tests. experimental_use_cc_common_link (bool, optional): Whether rules_rust uses cc_common.link to link - rust binaries. + rust binaries. + include_link_flags (bool, optional): Whether to include flags like `-l` that instruct the linker to search for a library. Returns: tuple: A tuple: A tuple of the following items: @@ -772,11 +778,10 @@ def collect_inputs( # For backwards compatibility, we also check the value of the `rustc_env_files` attribute when # `crate_info.rustc_env_files` is not populated. build_env_files = crate_info.rustc_env_files if crate_info.rustc_env_files else getattr(files, "rustc_env_files", []) - compile_inputs, out_dir, build_env_file, build_flags_files = _process_build_scripts(build_info, dep_info, compile_inputs) + compile_inputs, out_dir, build_env_file, build_flags_files = _process_build_scripts(build_info, dep_info, compile_inputs, include_link_flags = include_link_flags) if build_env_file: build_env_files = [f for f in build_env_files] + [build_env_file] compile_inputs = depset(build_env_files, transitive = [compile_inputs]) - return compile_inputs, out_dir, build_env_files, build_flags_files, linkstamp_outs, ambiguous_libs def construct_arguments( @@ -798,7 +803,8 @@ def construct_arguments( build_flags_files, emit = ["dep-info", "link"], force_all_deps_direct = False, - rustdoc = False, + add_flags_for_binary = False, + include_link_flags = True, stamp = False, remap_path_prefix = "", use_json_output = False, @@ -827,7 +833,8 @@ def construct_arguments( emit (list): Values for the --emit flag to rustc. force_all_deps_direct (bool, optional): Whether to pass the transitive rlibs with --extern to the commandline as opposed to -L. - rustdoc (bool, optional): Whether to add "bin" link flags to the command regardless of `emit` and `crate_type`. + add_flags_for_binary (bool, optional): Whether to add "bin" link flags to the command regardless of `emit` and `crate_type`. + include_link_flags (bool, optional): Whether to include flags like `-l` that instruct the linker to search for a library. stamp (bool, optional): Whether or not workspace status stamping is enabled. For more details see https://docs.bazel.build/versions/main/user-manual.html#flag--stamp remap_path_prefix (str, optional): A value used to remap `${pwd}` to. If set to None, no prefix will be set. @@ -889,23 +896,6 @@ def construct_arguments( if out_dir != None: env["OUT_DIR"] = "${pwd}/" + out_dir - # Handle that the binary name and crate name may be different. - # - # If a target name contains a - then cargo (and rules_rust) will generate a - # crate name with _ instead. Accordingly, rustc will generate a output - # file (executable, or rlib, or whatever) with _ not -. But when cargo - # puts a binary in the target/${config} directory, and sets environment - # variables like `CARGO_BIN_EXE_${binary_name}` it will use the - version - # not the _ version. So we rename the rustc-generated file (with _s) to - # have -s if needed. - emit_with_paths = emit - if crate_info.type == "bin" and crate_info.output != None: - generated_file = crate_info.name + toolchain.binary_ext - src = "/".join([crate_info.output.dirname, generated_file]) - dst = crate_info.output.path - if src != dst: - emit_with_paths = [("link=" + dst if val == "link" else val) for val in emit] - # Arguments for launching rustc from the process wrapper rustc_path = ctx.actions.args() rustc_path.add("--") @@ -974,8 +964,15 @@ def construct_arguments( if remap_path_prefix != None: rustc_flags.add("--remap-path-prefix=${{pwd}}={}".format(remap_path_prefix)) - if emit: - rustc_flags.add_joined(emit_with_paths, format_joined = "--emit=%s", join_with = ",") + emit_without_paths = [] + for kind in emit: + if kind == "link" and crate_info.type == "bin" and crate_info.output != None: + rustc_flags.add(crate_info.output, format = "--emit=link=%s") + else: + emit_without_paths.append(kind) + + if emit_without_paths: + rustc_flags.add_joined(emit_without_paths, format_joined = "--emit=%s", join_with = ",") if error_format != "json": # Color is not compatible with json output. rustc_flags.add("--color=always") @@ -1003,7 +1000,7 @@ def construct_arguments( add_edition_flags(rustc_flags, crate_info) # Link! - if ("link" in emit and crate_info.type not in ["rlib", "lib"]) or rustdoc: + if ("link" in emit and crate_info.type not in ["rlib", "lib"]) or add_flags_for_binary: # Rust's built-in linker can handle linking wasm files. We don't want to attempt to use the cc # linker since it won't understand. compilation_mode = ctx.var["COMPILATION_MODE"] @@ -1014,7 +1011,7 @@ def construct_arguments( else: rpaths = depset() - ld, link_args, link_env = get_linker_and_args(ctx, attr, crate_info.type, cc_toolchain, feature_configuration, rpaths, rustdoc) + ld, link_args, link_env = get_linker_and_args(ctx, attr, crate_info.type, cc_toolchain, feature_configuration, rpaths, add_flags_for_binary = add_flags_for_binary) env.update(link_env) rustc_flags.add(ld, format = "--codegen=linker=%s") @@ -1023,7 +1020,7 @@ def construct_arguments( # Additional context: https://github.com/rust-lang/rust/pull/36574 rustc_flags.add_all(link_args, format_each = "--codegen=link-arg=%s") - _add_native_link_flags(rustc_flags, dep_info, linkstamp_outs, ambiguous_libs, crate_info.type, toolchain, cc_toolchain, feature_configuration, compilation_mode) + _add_native_link_flags(rustc_flags, dep_info, linkstamp_outs, ambiguous_libs, crate_info.type, toolchain, cc_toolchain, feature_configuration, compilation_mode, include_link_flags = include_link_flags) use_metadata = _depend_on_metadata(crate_info, force_depend_on_objects) @@ -1039,6 +1036,9 @@ def construct_arguments( # https://doc.rust-lang.org/rustc/instrument-coverage.html rustc_flags.add("--codegen=instrument-coverage") + if toolchain._experimental_link_std_dylib: + rustc_flags.add("--codegen=prefer-dynamic") + # Make bin crate data deps available to tests. for data in getattr(attr, "data", []): if rust_common.crate_info in data: @@ -1660,19 +1660,20 @@ def add_edition_flags(args, crate): if crate.edition != "2015": args.add(crate.edition, format = "--edition=%s") -def _create_extra_input_args(build_info, dep_info): +def _create_extra_input_args(build_info, dep_info, include_link_flags = True): """Gather additional input arguments from transitive dependencies Args: build_info (BuildInfo): The BuildInfo provider from the target Crate's set of inputs. dep_info (DepInfo): The Depinfo provider form the target Crate's set of inputs. + include_link_flags (bool, optional): Whether to include flags like `-l` that instruct the linker to search for a library. Returns: tuple: A tuple of the following items: - (depset[File]): A list of all build info `OUT_DIR` File objects - (str): The `OUT_DIR` of the current build info - (File): An optional generated environment file from a `cargo_build_script` target - - (depset[File]): All direct and transitive build flag files from the current build info. + - (depset[File]): All direct and transitive build flag files from the current build info to be passed to rustc. """ input_files = [] input_depsets = [] @@ -1690,9 +1691,10 @@ def _create_extra_input_args(build_info, dep_info): build_env_file = build_info.rustc_env if build_info.flags: build_flags_files.append(build_info.flags) - if build_info.link_flags: - build_flags_files.append(build_info.link_flags) - input_files.append(build_info.link_flags) + if build_info.linker_flags and include_link_flags: + build_flags_files.append(build_info.linker_flags) + input_files.append(build_info.linker_flags) + input_depsets.append(build_info.compile_data) return ( @@ -1726,6 +1728,16 @@ def _compute_rpaths(toolchain, output_dir, dep_info, use_pic): for lib in linker_input.libraries if _is_dylib(lib) ] + + # Include std dylib if dylib linkage is enabled + if toolchain._experimental_link_std_dylib: + # TODO: Make toolchain.rust_std to only include libstd.so + # When dylib linkage is enabled, toolchain.rust_std should only need to + # include libstd.so. Hence, no filtering needed. + for file in toolchain.rust_std.to_list(): + if is_std_dylib(file): + dylibs.append(file) + if not dylibs: return depset([]) @@ -1903,8 +1915,8 @@ def _portable_link_flags(lib, use_pic, ambiguous_libs, get_lib_name, for_windows return [] -def _make_link_flags_windows(linker_input_and_use_pic_and_ambiguous_libs, flavor_msvc): - linker_input, use_pic, ambiguous_libs = linker_input_and_use_pic_and_ambiguous_libs +def _make_link_flags_windows(make_link_flags_args, flavor_msvc): + linker_input, use_pic, ambiguous_libs, include_link_flags = make_link_flags_args ret = [] for lib in linker_input.libraries: if lib.alwayslink: @@ -1919,18 +1931,18 @@ def _make_link_flags_windows(linker_input_and_use_pic_and_ambiguous_libs, flavor "-C", "link-arg=-Wl,--no-whole-archive", ]) - else: + elif include_link_flags: ret.extend(_portable_link_flags(lib, use_pic, ambiguous_libs, get_lib_name_for_windows, for_windows = True, flavor_msvc = flavor_msvc)) return ret -def _make_link_flags_windows_msvc(linker_input_and_use_pic_and_ambiguous_libs): - return _make_link_flags_windows(linker_input_and_use_pic_and_ambiguous_libs, flavor_msvc = True) +def _make_link_flags_windows_msvc(make_link_flags_args): + return _make_link_flags_windows(make_link_flags_args, flavor_msvc = True) -def _make_link_flags_windows_gnu(linker_input_and_use_pic_and_ambiguous_libs): - return _make_link_flags_windows(linker_input_and_use_pic_and_ambiguous_libs, flavor_msvc = False) +def _make_link_flags_windows_gnu(make_link_flags_args): + return _make_link_flags_windows(make_link_flags_args, flavor_msvc = False) -def _make_link_flags_darwin(linker_input_and_use_pic_and_ambiguous_libs): - linker_input, use_pic, ambiguous_libs = linker_input_and_use_pic_and_ambiguous_libs +def _make_link_flags_darwin(make_link_flags_args): + linker_input, use_pic, ambiguous_libs, include_link_flags = make_link_flags_args ret = [] for lib in linker_input.libraries: if lib.alwayslink: @@ -1938,12 +1950,12 @@ def _make_link_flags_darwin(linker_input_and_use_pic_and_ambiguous_libs): "-C", ("link-arg=-Wl,-force_load,%s" % get_preferred_artifact(lib, use_pic).path), ]) - else: + elif include_link_flags: ret.extend(_portable_link_flags(lib, use_pic, ambiguous_libs, get_lib_name_default, for_darwin = True)) return ret -def _make_link_flags_default(linker_input_and_use_pic_and_ambiguous_libs): - linker_input, use_pic, ambiguous_libs = linker_input_and_use_pic_and_ambiguous_libs +def _make_link_flags_default(make_link_flags_args): + linker_input, use_pic, ambiguous_libs, include_link_flags = make_link_flags_args ret = [] for lib in linker_input.libraries: if lib.alwayslink: @@ -1955,17 +1967,17 @@ def _make_link_flags_default(linker_input_and_use_pic_and_ambiguous_libs): "-C", "link-arg=-Wl,--no-whole-archive", ]) - else: + elif include_link_flags: ret.extend(_portable_link_flags(lib, use_pic, ambiguous_libs, get_lib_name_default)) return ret -def _libraries_dirnames(linker_input_and_use_pic_and_ambiguous_libs): - link_input, use_pic, _ = linker_input_and_use_pic_and_ambiguous_libs +def _libraries_dirnames(make_link_flags_args): + link_input, use_pic, _, _ = make_link_flags_args # De-duplicate names. return depset([get_preferred_artifact(lib, use_pic).dirname for lib in link_input.libraries]).to_list() -def _add_native_link_flags(args, dep_info, linkstamp_outs, ambiguous_libs, crate_type, toolchain, cc_toolchain, feature_configuration, compilation_mode): +def _add_native_link_flags(args, dep_info, linkstamp_outs, ambiguous_libs, crate_type, toolchain, cc_toolchain, feature_configuration, compilation_mode, include_link_flags = True): """Adds linker flags for all dependencies of the current target. Args: @@ -1978,6 +1990,7 @@ def _add_native_link_flags(args, dep_info, linkstamp_outs, ambiguous_libs, crate cc_toolchain (CcToolchainInfo): The current `cc_toolchain` feature_configuration (FeatureConfiguration): feature configuration to use with cc_toolchain compilation_mode (bool): The compilation mode for this build. + include_link_flags (bool, optional): Whether to include flags like `-l` that instruct the linker to search for a library. """ if crate_type in ["lib", "rlib"]: return @@ -1995,15 +2008,15 @@ def _add_native_link_flags(args, dep_info, linkstamp_outs, ambiguous_libs, crate get_lib_name = get_lib_name_default # TODO(hlopko): Remove depset flattening by using lambdas once we are on >=Bazel 5.0 - args_and_pic_and_ambiguous_libs = [(arg, use_pic, ambiguous_libs) for arg in dep_info.transitive_noncrates.to_list()] - args.add_all(args_and_pic_and_ambiguous_libs, map_each = _libraries_dirnames, uniquify = True, format_each = "-Lnative=%s") + make_link_flags_args = [(arg, use_pic, ambiguous_libs, include_link_flags) for arg in dep_info.transitive_noncrates.to_list()] + args.add_all(make_link_flags_args, map_each = _libraries_dirnames, uniquify = True, format_each = "-Lnative=%s") if ambiguous_libs: # If there are ambiguous libs, the disambiguation symlinks to them are # all created in the same directory. Add it to the library search path. ambiguous_libs_dirname = ambiguous_libs.values()[0].dirname args.add(ambiguous_libs_dirname, format = "-Lnative=%s") - args.add_all(args_and_pic_and_ambiguous_libs, map_each = make_link_flags) + args.add_all(make_link_flags_args, map_each = make_link_flags) args.add_all(linkstamp_outs, before_each = "-C", format_each = "link-args=%s") @@ -2015,11 +2028,12 @@ def _add_native_link_flags(args, dep_info, linkstamp_outs, ambiguous_libs, crate map_each = _get_dirname, format_each = "-Lnative=%s", ) - args.add_all( - cc_toolchain.dynamic_runtime_lib(feature_configuration = feature_configuration), - map_each = get_lib_name, - format_each = "-ldylib=%s", - ) + if include_link_flags: + args.add_all( + cc_toolchain.dynamic_runtime_lib(feature_configuration = feature_configuration), + map_each = get_lib_name, + format_each = "-ldylib=%s", + ) else: # For all other crate types we want to link C++ runtime library statically # (for example libstdc++.a or libc++.a). @@ -2028,11 +2042,12 @@ def _add_native_link_flags(args, dep_info, linkstamp_outs, ambiguous_libs, crate map_each = _get_dirname, format_each = "-Lnative=%s", ) - args.add_all( - cc_toolchain.static_runtime_lib(feature_configuration = feature_configuration), - map_each = get_lib_name, - format_each = "-lstatic=%s", - ) + if include_link_flags: + args.add_all( + cc_toolchain.static_runtime_lib(feature_configuration = feature_configuration), + map_each = get_lib_name, + format_each = "-lstatic=%s", + ) def _get_dirname(file): """A helper function for `_add_native_link_flags`. |