Skip to main content
Glama
cargo_buildscript.bzl8.4 kB
# Copyright (c) Meta Platforms, Inc. and affiliates. # # This source code is licensed under both the MIT license found in the # LICENSE-MIT file in the root directory of this source tree and the Apache # License, Version 2.0 found in the LICENSE-APACHE file in the root directory # of this source tree. # Cargo build script runner compatible with Reindeer-generated targets. # # Use this reindeer.toml configuration to refer to this rule: # # [buck] # buckfile_imports = """ # load("@prelude//rust:cargo_buildscript.bzl", "buildscript_run") # """ # # # optional (this matches the default rule name): # buildscript_genrule = "buildscript_run" # load("@prelude//decls:common.bzl", "buck") load("@prelude//decls:toolchains_common.bzl", "toolchains_common") load("@prelude//os_lookup:defs.bzl", "Os", "OsLookup") load("@prelude//rust:rust_toolchain.bzl", "RustToolchainInfo") load("@prelude//rust:targets.bzl", "targets") load("@prelude//utils:cmd_script.bzl", "cmd_script") load(":build.bzl", "dependency_args") load(":build_params.bzl", "MetadataKind") load(":context.bzl", "DepCollectionContext") load( ":link_info.bzl", "DEFAULT_STATIC_LINK_STRATEGY", "RustProcMacroPlugin", "gather_explicit_sysroot_deps", "resolve_rust_deps_inner", ) load(":rust_toolchain.bzl", "PanicRuntime") def _make_rustc_shim(ctx: AnalysisContext, cwd: Artifact) -> cmd_args: # Build scripts expect to receive a `rustc` which "just works." However, # our rustc sometimes has no sysroot available, so we need to make a shim # which supplies the sysroot deps if necessary toolchain_info = ctx.attrs._rust_toolchain[RustToolchainInfo] explicit_sysroot_deps = toolchain_info.explicit_sysroot_deps if explicit_sysroot_deps: dep_ctx = DepCollectionContext( advanced_unstable_linking = False, include_doc_deps = False, is_proc_macro = False, explicit_sysroot_deps = explicit_sysroot_deps, panic_runtime = PanicRuntime("unwind"), # not actually used ) deps = gather_explicit_sysroot_deps(dep_ctx) deps = resolve_rust_deps_inner(ctx, deps) dep_args, _ = dependency_args( ctx = ctx, compile_ctx = None, toolchain_info = toolchain_info, deps = deps, subdir = "any", dep_link_strategy = DEFAULT_STATIC_LINK_STRATEGY, dep_metadata_kind = MetadataKind("full"), is_rustdoc_test = False, ) null_path = "nul" if ctx.attrs._exec_os_type[OsLookup].os == Os("windows") else "/dev/null" dep_args = cmd_args("--sysroot=" + null_path, dep_args, relative_to = cwd) dep_file, _ = ctx.actions.write("rustc_dep_file", dep_args, allow_args = True) sysroot_args = cmd_args("@", dep_file, delimiter = "", hidden = dep_args) else: sysroot_args = cmd_args() shim = cmd_script( ctx = ctx, name = "__rustc_shim", cmd = cmd_args(toolchain_info.compiler, sysroot_args, relative_to = cwd), language = ctx.attrs._exec_os_type[OsLookup].script, ) return cmd_args(shim, relative_to = cwd) def _cargo_buildscript_impl(ctx: AnalysisContext) -> list[Provider]: toolchain_info = ctx.attrs._rust_toolchain[RustToolchainInfo] cwd = ctx.actions.declare_output("cwd", dir = True) out_dir = ctx.actions.declare_output("OUT_DIR", dir = True) rustc_flags = ctx.actions.declare_output("rustc_flags") if ctx.attrs.manifest_dir != None: manifest_dir = ctx.attrs.manifest_dir[DefaultInfo].default_outputs[0] else: manifest_dir = ctx.actions.symlinked_dir("manifest_dir", ctx.attrs.filegroup_for_manifest_dir) cmd = [ ctx.attrs.runner[RunInfo], cmd_args("--buildscript=", ctx.attrs.buildscript[RunInfo], delimiter = ""), cmd_args("--rustc-cfg=", ctx.attrs.rustc_cfg[DefaultInfo].default_outputs[0], delimiter = ""), cmd_args("--manifest-dir=", manifest_dir, delimiter = ""), cmd_args("--create-cwd=", cwd.as_output(), delimiter = ""), cmd_args("--outfile=", rustc_flags.as_output(), delimiter = ""), ] # See https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts env = {} env["CARGO"] = "/bin/false" env["CARGO_PKG_NAME"] = ctx.attrs.package_name env["CARGO_PKG_VERSION"] = ctx.attrs.version env["OUT_DIR"] = out_dir.as_output() env["RUSTC"] = _make_rustc_shim(ctx, cwd) env["RUSTC_LINKER"] = "/bin/false" env["RUST_BACKTRACE"] = "1" if toolchain_info.rustc_target_triple: env["TARGET"] = toolchain_info.rustc_target_triple else: cmd.append(cmd_args("--rustc-host-tuple=", ctx.attrs.rustc_host_tuple[DefaultInfo].default_outputs[0], delimiter = "")) # \037 == \x1f == the magic delimiter specified in the environment variable # reference above. env["CARGO_ENCODED_RUSTFLAGS"] = cmd_args(toolchain_info.rustc_flags, delimiter = "\037") host_triple = targets.exec_triple(ctx) if host_triple: env["HOST"] = host_triple for feature in ctx.attrs.features: upper_feature = feature.upper().replace("-", "_") env["CARGO_FEATURE_{}".format(upper_feature)] = "1" # Environment variables specified in the target's attributes get priority # over all the above. for k, v in ctx.attrs.env.items(): env[k] = cmd_args(v, relative_to = cwd) ctx.actions.run( cmd, env = env, category = "buildscript", ) return [DefaultInfo( default_output = None, sub_targets = { "out_dir": [DefaultInfo(default_output = out_dir)], "rustc_flags": [DefaultInfo(default_output = rustc_flags)], }, )] _cargo_buildscript_rule = rule( impl = _cargo_buildscript_impl, attrs = { "buildscript": attrs.exec_dep(providers = [RunInfo]), "env": attrs.dict(key = attrs.string(), value = attrs.arg()), "features": attrs.list(attrs.string()), "filegroup_for_manifest_dir": attrs.option(attrs.dict(key = attrs.string(), value = attrs.source()), default = None), "manifest_dir": attrs.option(attrs.dep(), default = None), "package_name": attrs.string(), "runner": attrs.default_only(attrs.exec_dep(providers = [RunInfo], default = "prelude//rust/tools:buildscript_run")), # *IMPORTANT* rustc_cfg must be a `dep` and not an `exec_dep` because # we want the `rustc --cfg` for the target platform, not the exec platform. "rustc_cfg": attrs.dep(default = "prelude//rust/tools:rustc_cfg"), "rustc_host_tuple": attrs.dep(default = "prelude//rust/tools:rustc_host_tuple"), "version": attrs.string(), "_exec_os_type": buck.exec_os_type_arg(), "_rust_toolchain": toolchains_common.rust(), }, # Always empty, but needed to prevent errors uses_plugins = [RustProcMacroPlugin], ) def buildscript_run( name, buildscript_rule, package_name, version, features = [], env = {}, # path to crate's directory in source tree, e.g. "vendor/serde-1.0.100" local_manifest_dir = None, # target or subtarget containing crate, e.g. ":serde.git[serde]" manifest_dir = None, **kwargs): if manifest_dir == None and local_manifest_dir == None: existing_filegroup_name = "{}-{}.crate".format(package_name, version) if rule_exists(existing_filegroup_name): manifest_dir = ":{}".format(existing_filegroup_name) else: local_manifest_dir = "vendor/{}-{}".format(package_name, version) filegroup_for_manifest_dir = None if local_manifest_dir != None: prefix_with_trailing_slash = "{}/".format(local_manifest_dir) filegroup_for_manifest_dir = { path.removeprefix(prefix_with_trailing_slash): path for path in glob(["{}/**".format(local_manifest_dir)]) } _cargo_buildscript_rule( name = name, buildscript = buildscript_rule, package_name = package_name, version = version, features = features, env = env, filegroup_for_manifest_dir = filegroup_for_manifest_dir, manifest_dir = manifest_dir, **kwargs )

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/systeminit/si'

If you have feedback or need assistance with the MCP directory API, please join our Discord server