summaryrefslogtreecommitdiffstats
path: root/build/cargo-linker
blob: 898e21d482fa4bb38a0ea1e7c17c85722bff1b86 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#!/usr/bin/env python3

# If you want to use a custom linker with Cargo, Cargo requires that you
# specify it in Cargo.toml or via the matching environment variable.
# Passing extra options to the linker is possible with Cargo via
# RUSTFLAGS='-C link-args', but testing showed that doing this reliably
# was difficult.
#
# Our solution to these problems is to use this wrapper script.  We pass
# in the LD and the LDFLAGS to use via environment variables.
#
# * MOZ_CARGO_WRAP_LD is equivalent to CC on Unix-y platforms, and CC
#   frequently has additional arguments in addition to the compiler
#   itself.
#
# * MOZ_CARGO_WRAP_LDFLAGS contains space-separated arguments to pass,
#   and not quoting it ensures that each of those arguments is passed
#   as a separate argument to the actual LD.
#
# * In rare cases, we also need MOZ_CARGO_WRAP_LD_CXX, which is the
#   equivalent of CXX, when linking C++ code. Usually, this should
#   simply work by the use of CC and -lstdc++ (added by cc-rs).
#   However, in the case of sanitizer runtimes, there is a separate
#   runtime for C and C++ and linking C++ code with the C runtime can
#   fail if the requested feature is in the C++ runtime only (bug 1747298).

import os
import sys

# This is not necessarily run with a virtualenv python, so add
# the necessary directory for the shellutil module.
base_dir = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
sys.path.insert(0, os.path.join(base_dir, "python", "mozbuild"))
from mozbuild.shellutil import split


SANITIZERS = {
    "asan": "address",
    "hwasan": "hwaddress",
    "lsan": "leak",
    "msan": "memory",
    "tsan": "thread",
}

use_clang_sanitizer = os.environ.get("MOZ_CLANG_NEWER_THAN_RUSTC_LLVM")
wrap_ld = os.environ["MOZ_CARGO_WRAP_LD"]
args = split(os.environ["MOZ_CARGO_WRAP_LDFLAGS"])
for arg in sys.argv[1:]:
    if arg in ["-lc++", "-lstdc++"]:
        wrap_ld = os.environ["MOZ_CARGO_WRAP_LD_CXX"]
    elif use_clang_sanitizer and arg.endswith("san.a"):
        # When clang is newer than rustc's LLVM, we replace rust's sanitizer
        # runtimes with clang's.
        filename = os.path.basename(arg)
        prefix, dot, suffix = filename[:-2].rpartition(".")
        if (
            prefix.startswith("librustc-")
            and prefix.endswith("_rt") and dot == "."
        ):
            args.append(f"-fsanitize={SANITIZERS[suffix]}")
            continue
    args.append(arg)

wrap_ld = split(wrap_ld)
os.execvp(wrap_ld[0], wrap_ld + args)