250 lines
11 KiB
Python
250 lines
11 KiB
Python
# 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.
|
|
|
|
# Rules for mapping requirements to options
|
|
|
|
load(
|
|
"@prelude//linking:link_info.bzl",
|
|
"LinkStyle",
|
|
"Linkage", # @unused Used as a type
|
|
)
|
|
load("@prelude//utils:utils.bzl", "expect")
|
|
|
|
# --crate-type=
|
|
# Excludes `lib` because we want to explicitly choose the library flavour
|
|
CrateType = enum(
|
|
# Binary
|
|
"bin",
|
|
# Rust linkage
|
|
"rlib",
|
|
"dylib",
|
|
"proc-macro",
|
|
# Native linkage
|
|
"cdylib",
|
|
"staticlib",
|
|
)
|
|
|
|
# Crate type is intended for consumption by Rust code
|
|
def crate_type_rust_linkage(crate_type: CrateType.type) -> bool.type:
|
|
return crate_type.value in ("rlib", "dylib", "proc-macro")
|
|
|
|
# Crate type is intended for native linkage (eg C++)
|
|
def crate_type_native_linkage(crate_type: CrateType.type) -> bool.type:
|
|
return crate_type.value in ("cdylib", "staticlib")
|
|
|
|
# Crate type which invokes the linker
|
|
def crate_type_linked(crate_type: CrateType.type) -> bool.type:
|
|
return crate_type.value in ("bin", "dylib", "proc-macro", "cdylib")
|
|
|
|
# Crate type which should include transitive deps
|
|
def crate_type_transitive_deps(crate_type: CrateType.type) -> bool.type:
|
|
return crate_type.value in ("rlib", "dylib", "staticlib") # not sure about staticlib
|
|
|
|
# Crate type which should always need codegen
|
|
def crate_type_codegen(crate_type: CrateType.type) -> bool.type:
|
|
return crate_type_linked(crate_type) or crate_type_native_linkage(crate_type)
|
|
|
|
# -Crelocation-model= from --print relocation-models
|
|
RelocModel = enum(
|
|
# Common
|
|
"static",
|
|
"pic",
|
|
# Various obscure types
|
|
"dynamic-no-pic",
|
|
"ropi",
|
|
"rwpi",
|
|
"ropi-rwpi",
|
|
"default",
|
|
)
|
|
|
|
# --emit=
|
|
Emit = enum(
|
|
"asm",
|
|
"llvm-bc",
|
|
"llvm-ir",
|
|
"obj",
|
|
"metadata",
|
|
"link",
|
|
"dep-info",
|
|
"mir",
|
|
"save-analysis", # pseudo emit alias for metadata + -Zsave-analysis
|
|
"expand", # pseudo emit alias for -Zunpretty=expanded
|
|
)
|
|
|
|
# Emitting this artifact generates code
|
|
def emit_needs_codegen(emit: Emit.type) -> bool.type:
|
|
return emit.value in ("asm", "llvm-bc", "llvm-ir", "obj", "link", "mir")
|
|
|
|
BuildParams = record(
|
|
crate_type = field(CrateType.type),
|
|
reloc_model = field(RelocModel.type),
|
|
dep_link_style = field(LinkStyle.type), # what link_style to use for dependencies
|
|
# XXX This needs to be OS-specific
|
|
prefix = field(str.type),
|
|
suffix = field(str.type),
|
|
)
|
|
|
|
RustcFlags = record(
|
|
crate_type = field(CrateType.type),
|
|
reloc_model = field(RelocModel.type),
|
|
dep_link_style = field(LinkStyle.type),
|
|
)
|
|
|
|
# Filenames used for various emitted forms
|
|
# `None` for a prefix or suffix means use the build_param version
|
|
_EMIT_PREFIX_SUFFIX = {
|
|
Emit("asm"): ("", ".s"),
|
|
Emit("llvm-bc"): ("", ".bc"),
|
|
Emit("llvm-ir"): ("", ".ll"),
|
|
Emit("obj"): ("", ".o"),
|
|
Emit("metadata"): ("lib", ".rmeta"), # even binaries get called 'libfoo.rmeta'
|
|
Emit("link"): (None, None), # crate type and reloc model dependent
|
|
Emit("dep-info"): ("", ".d"),
|
|
Emit("mir"): (None, ".mir"),
|
|
Emit("expand"): (None, ".rs"),
|
|
Emit("save-analysis"): (None, ".json"),
|
|
}
|
|
|
|
# Return the filename for a particular emitted artifact type
|
|
def output_filename(cratename: str.type, emit: Emit.type, buildparams: BuildParams.type, extra: [str.type, None] = None) -> str.type:
|
|
epfx, esfx = _EMIT_PREFIX_SUFFIX[emit]
|
|
prefix = epfx if epfx != None else buildparams.prefix
|
|
suffix = esfx if esfx != None else buildparams.suffix
|
|
return prefix + cratename + (extra or "") + suffix
|
|
|
|
# Rule type - 'binary' also covers 'test'
|
|
RuleType = enum("binary", "library")
|
|
|
|
# What language we're generating artifacts to be linked with
|
|
LinkageLang = enum("rust", "c++")
|
|
|
|
_BINARY_SHARED = 0
|
|
_BINARY_PIE = 1
|
|
_BINARY_NON_PIE = 2
|
|
_NATIVE_LINKABLE_SHARED_OBJECT = 3
|
|
_RUST_DYLIB_SHARED = 4
|
|
_RUST_PROC_MACRO = 5
|
|
_RUST_STATIC_PIC_LIBRARY = 6
|
|
_RUST_STATIC_NON_PIC_LIBRARY = 7
|
|
_NATIVE_LINKABLE_STATIC_PIC = 8
|
|
_NATIVE_LINKABLE_STATIC_NON_PIC = 9
|
|
|
|
# FIXME: This isn't right! We should be using the target platform, rather than host_info.
|
|
# On Windows the GNU linker emits .exe/.dll, while on Linux it emits nothing/.so, use this variable to switch.
|
|
#
|
|
# At the moment we don't have anything working on Windows, so trying to get cross-compiling working is a step
|
|
# further than we want to take. But this will need cleaning up for Windows hosts to be able to cross-compile.
|
|
_FIXME_IS_WINDOWS = host_info().os.is_windows
|
|
|
|
def _executable_prefix_suffix(platform):
|
|
return {
|
|
"darwin": ("", ""),
|
|
"gnu": ("", ".exe") if _FIXME_IS_WINDOWS else ("", ""),
|
|
"windows": ("", ".exe"),
|
|
}[platform]
|
|
|
|
def _library_prefix_suffix(platform):
|
|
return {
|
|
"darwin": ("lib", ".dylib"),
|
|
"gnu": ("", ".dll") if _FIXME_IS_WINDOWS else ("lib", ".so"),
|
|
"windows": ("", ".dll"),
|
|
}[platform]
|
|
|
|
_BUILD_PARAMS = {
|
|
_BINARY_SHARED: (RustcFlags(crate_type = CrateType("bin"), reloc_model = RelocModel("pic"), dep_link_style = LinkStyle("shared")), _executable_prefix_suffix),
|
|
_BINARY_PIE: (RustcFlags(crate_type = CrateType("bin"), reloc_model = RelocModel("pic"), dep_link_style = LinkStyle("static_pic")), _executable_prefix_suffix),
|
|
_BINARY_NON_PIE: (RustcFlags(crate_type = CrateType("bin"), reloc_model = RelocModel("static"), dep_link_style = LinkStyle("static")), _executable_prefix_suffix),
|
|
_NATIVE_LINKABLE_SHARED_OBJECT: (RustcFlags(crate_type = CrateType("cdylib"), reloc_model = RelocModel("pic"), dep_link_style = LinkStyle("shared")), _library_prefix_suffix),
|
|
_RUST_DYLIB_SHARED: (RustcFlags(crate_type = CrateType("dylib"), reloc_model = RelocModel("pic"), dep_link_style = LinkStyle("shared")), _library_prefix_suffix),
|
|
_RUST_PROC_MACRO: (RustcFlags(crate_type = CrateType("proc-macro"), reloc_model = RelocModel("pic"), dep_link_style = LinkStyle("static_pic")), _library_prefix_suffix),
|
|
_RUST_STATIC_PIC_LIBRARY: (RustcFlags(crate_type = CrateType("rlib"), reloc_model = RelocModel("pic"), dep_link_style = LinkStyle("static_pic")), lambda _: ("lib", ".rlib")),
|
|
_RUST_STATIC_NON_PIC_LIBRARY: (RustcFlags(crate_type = CrateType("rlib"), reloc_model = RelocModel("static"), dep_link_style = LinkStyle("static")), lambda _: ("lib", ".rlib")),
|
|
_NATIVE_LINKABLE_STATIC_PIC: (RustcFlags(crate_type = CrateType("staticlib"), reloc_model = RelocModel("pic"), dep_link_style = LinkStyle("static_pic")), lambda _: ("lib", "_pic.a")),
|
|
_NATIVE_LINKABLE_STATIC_NON_PIC: (RustcFlags(crate_type = CrateType("staticlib"), reloc_model = RelocModel("static"), dep_link_style = LinkStyle("static")), lambda _: ("lib", ".a")),
|
|
}
|
|
|
|
_INPUTS = {
|
|
# Binary, shared
|
|
("binary", False, "shared", "any", "rust"): _BINARY_SHARED,
|
|
("binary", False, "shared", "shared", "rust"): _BINARY_SHARED,
|
|
("binary", False, "shared", "static", "rust"): _BINARY_SHARED,
|
|
# Binary, PIE
|
|
("binary", False, "static_pic", "any", "rust"): _BINARY_PIE,
|
|
("binary", False, "static_pic", "shared", "rust"): _BINARY_PIE,
|
|
("binary", False, "static_pic", "static", "rust"): _BINARY_PIE,
|
|
# Binary, non-PIE
|
|
("binary", False, "static", "any", "rust"): _BINARY_NON_PIE,
|
|
("binary", False, "static", "shared", "rust"): _BINARY_NON_PIE,
|
|
("binary", False, "static", "static", "rust"): _BINARY_NON_PIE,
|
|
# Native linkable shared object
|
|
("library", False, "shared", "any", "c++"): _NATIVE_LINKABLE_SHARED_OBJECT,
|
|
("library", False, "shared", "shared", "c++"): _NATIVE_LINKABLE_SHARED_OBJECT,
|
|
("library", False, "static", "shared", "c++"): _NATIVE_LINKABLE_SHARED_OBJECT,
|
|
("library", False, "static_pic", "shared", "c++"): _NATIVE_LINKABLE_SHARED_OBJECT,
|
|
# Rust dylib shared object
|
|
("library", False, "shared", "any", "rust"): _RUST_DYLIB_SHARED,
|
|
("library", False, "shared", "shared", "rust"): _RUST_DYLIB_SHARED,
|
|
("library", False, "static", "shared", "rust"): _RUST_DYLIB_SHARED,
|
|
("library", False, "static_pic", "shared", "rust"): _RUST_DYLIB_SHARED,
|
|
# Rust proc-macro
|
|
("library", True, "shared", "any", "rust"): _RUST_PROC_MACRO,
|
|
("library", True, "shared", "shared", "rust"): _RUST_PROC_MACRO,
|
|
("library", True, "shared", "static", "rust"): _RUST_PROC_MACRO,
|
|
("library", True, "static", "any", "rust"): _RUST_PROC_MACRO,
|
|
("library", True, "static", "shared", "rust"): _RUST_PROC_MACRO,
|
|
("library", True, "static", "static", "rust"): _RUST_PROC_MACRO,
|
|
("library", True, "static_pic", "any", "rust"): _RUST_PROC_MACRO,
|
|
("library", True, "static_pic", "shared", "rust"): _RUST_PROC_MACRO,
|
|
("library", True, "static_pic", "static", "rust"): _RUST_PROC_MACRO,
|
|
# Rust static_pic library
|
|
("library", False, "shared", "static", "rust"): _RUST_STATIC_PIC_LIBRARY,
|
|
("library", False, "static_pic", "any", "rust"): _RUST_STATIC_PIC_LIBRARY,
|
|
("library", False, "static_pic", "static", "rust"): _RUST_STATIC_PIC_LIBRARY,
|
|
# Rust static (non-pic) library
|
|
("library", False, "static", "any", "rust"): _RUST_STATIC_NON_PIC_LIBRARY,
|
|
("library", False, "static", "static", "rust"): _RUST_STATIC_NON_PIC_LIBRARY,
|
|
# Native linkable static_pic
|
|
("library", False, "shared", "static", "c++"): _NATIVE_LINKABLE_STATIC_PIC,
|
|
("library", False, "static_pic", "any", "c++"): _NATIVE_LINKABLE_STATIC_PIC,
|
|
("library", False, "static_pic", "static", "c++"): _NATIVE_LINKABLE_STATIC_PIC,
|
|
# Native linkable static non-pic
|
|
("library", False, "static", "any", "c++"): _NATIVE_LINKABLE_STATIC_NON_PIC,
|
|
("library", False, "static", "static", "c++"): _NATIVE_LINKABLE_STATIC_NON_PIC,
|
|
}
|
|
|
|
# Compute crate type, relocation model and name mapping given what rule we're building,
|
|
# whether its a proc-macro, linkage information and language.
|
|
def build_params(
|
|
rule: RuleType.type,
|
|
proc_macro: bool.type,
|
|
link_style: LinkStyle.type,
|
|
preferred_linkage: Linkage.type,
|
|
lang: LinkageLang.type,
|
|
linker_type: str.type) -> BuildParams.type:
|
|
input = (rule.value, proc_macro, link_style.value, preferred_linkage.value, lang.value)
|
|
|
|
expect(
|
|
input in _INPUTS,
|
|
"missing case for rule_type={} proc_macro={} link_style={} preferred_linkage={} lang={}",
|
|
rule,
|
|
proc_macro,
|
|
link_style,
|
|
preferred_linkage,
|
|
lang,
|
|
)
|
|
|
|
build_kind_key = _INPUTS[input]
|
|
(flags, platform_to_affix) = _BUILD_PARAMS[build_kind_key]
|
|
(prefix, suffix) = platform_to_affix(linker_type)
|
|
|
|
return BuildParams(
|
|
crate_type = flags.crate_type,
|
|
reloc_model = flags.reloc_model,
|
|
dep_link_style = flags.dep_link_style,
|
|
prefix = prefix,
|
|
suffix = suffix,
|
|
)
|