tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

BUILD.gn (14821B)


      1 # Copyright 2021 The Chromium Authors
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 
      5 # This file provides the Rust standard library for GN targets.
      6 #
      7 # For Rust targets, it either copies a prebuilt stdlib or builds a stdlib, and
      8 # then points rustc to it with `--sysroot`.
      9 #
     10 # When linking it ensures the libraries (and their C library dependencies) are
     11 # part of the linker line. If Rust drives the linking, this is redundant but if
     12 # Clang drives the linking it is required.
     13 #
     14 # Part of the standard library provided here is "remap_alloc" which maps
     15 # allocator functions to PartitionAlloc when `use_partition_alloc_as_malloc` is
     16 # true, so that Rust and C++ use the same allocator backend.
     17 
     18 import("//chromium/build/buildflag_header.gni")
     19 import("//chromium/build/config/compiler/compiler.gni")
     20 import("//chromium/build/config/coverage/coverage.gni")
     21 import("//chromium/build/config/rust.gni")
     22 import("//chromium/build/config/sanitizers/sanitizers.gni")
     23 
     24 rust_allocator_uses_partition_alloc = false
     25 if (build_with_chromium) {
     26   import("//base/allocator/partition_allocator/partition_alloc.gni")
     27   rust_allocator_uses_partition_alloc = use_partition_alloc_as_malloc
     28 }
     29 
     30 buildflag_header("buildflags") {
     31   header = "buildflags.h"
     32   flags = [
     33     "RUST_ALLOCATOR_USES_PARTITION_ALLOC=$rust_allocator_uses_partition_alloc",
     34   ]
     35   visibility = [ ":*" ]
     36 }
     37 
     38 if (toolchain_has_rust) {
     39   # If clang performs the link step, we need to provide the allocator symbols
     40   # that are normally injected by rustc during linking.
     41   #
     42   # We also "happen to" use this to redirect allocations to PartitionAlloc,
     43   # though that would be better done through a #[global_allocator] crate (see
     44   # above).
     45   source_set("remap_alloc") {
     46     public_deps = []
     47     if (rust_allocator_uses_partition_alloc) {
     48       public_deps += [ "//base/allocator/partition_allocator:partition_alloc" ]
     49     }
     50     deps = [ ":buildflags" ]
     51     sources = [
     52       # `alias.*`, `compiler_specific.h`, and `immediate_crash.*` have been
     53       # copied from `//base`.
     54       # TODO(crbug.com/40279749): Avoid duplication / reuse code.
     55       "alias.cc",
     56       "alias.h",
     57       "compiler_specific.h",
     58       "immediate_crash.h",
     59       "remap_alloc.cc",
     60     ]
     61   }
     62 
     63   # List of Rust stdlib rlibs which are present in the official Rust toolchain
     64   # we are using from the Android team. This is usually a version or two behind
     65   # nightly. Generally this matches the toolchain we build ourselves, but if
     66   # they differ, append or remove libraries based on the
     67   # `use_chromium_rust_toolchain` GN variable.
     68   #
     69   # If the build fails due to missing symbols, it would be because of a missing
     70   # library that needs to be added here in a newer stdlib.
     71   stdlib_files = [
     72     "std",  # List first because it makes depfiles more debuggable (see below)
     73     "alloc",
     74     "cfg_if",
     75     "compiler_builtins",
     76     "core",
     77     "getopts",
     78     "hashbrown",
     79     "panic_abort",
     80     "panic_unwind",
     81     "rustc_demangle",
     82     "std_detect",
     83     "test",
     84     "unicode_width",
     85     "unwind",
     86   ]
     87 
     88   if (!is_win) {
     89     # These are no longer present in the Windows toolchain.
     90     stdlib_files += [
     91       "addr2line",
     92       "adler2",
     93       "gimli",
     94       "libc",
     95       "memchr",
     96       "miniz_oxide",
     97       "object",
     98     ]
     99   }
    100 
    101   if (toolchain_for_rust_host_build_tools) {
    102     # When building proc macros, include the proc_macro crate in what should be
    103     # copied with find_stdlib. Otherwise it is not copied since it will be
    104     # unused.
    105     stdlib_files += [ "proc_macro" ]
    106   }
    107 
    108   # Different Rust toolchains may add or remove files relative to the above
    109   # list. That can be specified in gn args for anyone using (for instance)
    110   # nightly or some other experimental toolchain, prior to it becoming official.
    111   stdlib_files -= removed_rust_stdlib_libs
    112   stdlib_files += added_rust_stdlib_libs
    113 
    114   # rlib files which are distributed alongside Rust's prebuilt stdlib, but we
    115   # don't need to pass to the C++ linker because they're used for specialized
    116   # purposes.
    117   skip_stdlib_files = [
    118     "profiler_builtins",
    119     "rustc_std_workspace_alloc",
    120     "rustc_std_workspace_core",
    121     "rustc_std_workspace_std",
    122   ]
    123 
    124   config("stdlib_dependent_libs") {
    125     # TODO(crbug.com/40264561): These should really be `libs`, however that
    126     # breaks. Normally, we specify lib files with the `.lib` suffix but
    127     # then when rustc links an EXE, it invokes lld-link with `.lib.lib`
    128     # instead.
    129     #
    130     # Omitting the `.lib` suffix breaks linking as well, when clang drives
    131     # the linking step of a C++ EXE that depends on Rust.
    132     if (is_win) {
    133       # The libc crate tries to link in the Windows CRT, but we specify the CRT
    134       # library ourselves in //build/config/win:dynamic_crt and
    135       # //build/config/win:static_crt because Rustc does not allow us to specify
    136       # using the debug CRT: https://github.com/rust-lang/rust/issues/39016
    137       #
    138       # As such, we have disabled all #[link] directives from the libc crate,
    139       # and we need to add any non-CRT libs here.
    140       ldflags = [ "legacy_stdio_definitions.lib" ]
    141     }
    142   }
    143   config("stdlib_public_dependent_libs") {
    144     # TODO(crbug.com/40264561): These should really be `libs`, however that
    145     # breaks. Normally, we specify lib files with the `.lib` suffix but
    146     # then when rustc links an EXE, it invokes lld-link with `.lib.lib`
    147     # instead.
    148     #
    149     # Omitting the `.lib` suffix breaks linking as well, when clang drives
    150     # the linking step of a C++ EXE that depends on Rust.
    151     if (is_win) {
    152       # These libs provide functions that are used by the stdlib. Rust crates
    153       # will try to link them in with #[link] directives. However these don't
    154       # get propagated to the linker if Rust isn't driving the linking (a C++
    155       # target that depends on a Rust rlib). So these need to be specified
    156       # explicitly.
    157       ldflags = [
    158         "advapi32.lib",
    159         "bcrypt.lib",
    160         "kernel32.lib",
    161         "ntdll.lib",
    162         "synchronization.lib",
    163         "userenv.lib",
    164         "ws2_32.lib",
    165       ]
    166     }
    167 
    168     # From rust/library/std/src/sys/unix/mod.rs.
    169     #
    170     # libs = [ "System" ] (meaning /usr/lib/libSystem.B.dylib) is intentionally
    171     # omitted here on Apple platforms, because the linker driver is responsible
    172     # for adding it, much like libc on most other POSIX platforms. It can be
    173     # ordering-sensitive, and including it here can alter its order relative to
    174     # other libraries. https://crbug.com/367764848 is an example of a bug caused
    175     # by specifying libSystem too early.
    176     #
    177     # TODO(danakj): We should generate this list somehow when building or
    178     # rolling the Rust toolchain?
    179     if (is_android) {
    180       libs = [ "dl" ]
    181     } else if (target_os == "freebsd") {
    182       libs = [
    183         "execinfo",
    184         "pthread",
    185       ]
    186     } else if (target_os == "netbsd") {
    187       libs = [
    188         "rt",
    189         "pthread",
    190       ]
    191     } else if (is_ios) {
    192       libs = [ "objc" ]
    193       frameworks = [
    194         "Security.framework",
    195         "Foundation.framework",
    196       ]
    197     } else if (is_fuchsia) {
    198       libs = [
    199         "zircon",
    200         "fdio",
    201       ]
    202     }
    203   }
    204 
    205   # Construct sysroots for rustc invocations to better control what libraries
    206   # are linked. We have two: one with copied prebuilt libraries, and one with
    207   # our locally-built std. Both reside in root_out_dir: we must only have one of
    208   # each per GN toolchain anyway.
    209 
    210   sysroot_lib_subdir = "lib/rustlib/$rust_abi_target/lib"
    211 
    212   if (!rust_prebuilt_stdlib) {
    213     local_rustc_sysroot = "$root_out_dir/local_rustc_sysroot"
    214 
    215     # All std targets starting with core build with our sysroot. It starts empty
    216     # and is incrementally built. The directory must exist at the start.
    217     generated_file("empty_sysroot_for_std_build") {
    218       outputs = [ "$local_rustc_sysroot/$sysroot_lib_subdir/.empty" ]
    219       contents = ""
    220       visibility = [ ":*" ]
    221     }
    222 
    223     # Target to be depended on by std build targets. Creates the initially empty
    224     # sysroot.
    225     group("std_build_deps") {
    226       deps = [ ":empty_sysroot_for_std_build" ]
    227       public_configs = [ ":local_stdlib_sysroot" ]
    228       visibility = [ "rules:*" ]
    229     }
    230 
    231     profiler_builtins_crates = [
    232       "core",
    233       "compiler_builtins",
    234       "profiler_builtins",
    235     ]
    236 
    237     # When using instrumentation, profiler_builtins and its deps must be built
    238     # before other std crates. Other crates depend on this target so they are
    239     # built in the right order.
    240     group("profiler_builtins_group") {
    241       deps = []
    242       foreach(libname, profiler_builtins_crates) {
    243         deps += [ "rules:$libname" ]
    244       }
    245       visibility = [ "rules:*" ]
    246     }
    247 
    248     config("local_stdlib_sysroot") {
    249       sysroot = rebase_path(local_rustc_sysroot, root_build_dir)
    250       rustflags = [ "--sysroot=$sysroot" ]
    251       visibility = [ ":*" ]
    252     }
    253 
    254     # Builds and links against the Rust stdlib. Both Rust and C++ targets should
    255     # depend on this, as it provides the path to the library and includes the
    256     # allocator hooks.
    257     group("std") {
    258       assert(toolchain_has_rust,
    259              "Some C++ target is depending on Rust code even though " +
    260                  "toolchain_has_rust=false. Usually this would mean" +
    261                  "a NaCl target is depending on Rust, as there's no Rust " +
    262                  "toolchain targetting NaCl.")
    263       all_dependent_configs = [
    264         ":stdlib_public_dependent_libs",
    265         ":local_stdlib_sysroot",
    266         ":stdlib_dependent_libs",
    267       ]
    268       deps = []
    269       foreach(libname, stdlib_files + skip_stdlib_files) {
    270         deps += [ "rules:$libname" ]
    271       }
    272 
    273       public_deps = [ ":remap_alloc" ]
    274     }
    275   } else {
    276     action("find_stdlib") {
    277       # Collect prebuilt Rust libraries from toolchain package and copy to a
    278       # known location.
    279       #
    280       # The Rust toolchain contains prebuilt rlibs for the standard library and
    281       # its dependencies. However, they have unstable names: an unpredictable
    282       # metadata hash is appended to the known crate name.
    283       #
    284       # We must depend on these rlibs explicitly when rustc is not in charge of
    285       # linking. However, it is difficult to construct GN rules to do so when
    286       # the names can't be known statically.
    287       #
    288       # This action copies the prebuilt rlibs to a known location, removing the
    289       # metadata part of the name. In the process it verifies we have all the
    290       # libraries we expect and none that we don't. A depfile is generated so
    291       # this step is re-run when any libraries change. The action script
    292       # additionally verifies rustc matches the expected version, which is
    293       # unrelated but this is a convenient place to do so.
    294       #
    295       # The action refers to `stdlib_files`, `skip_stdlib_files`, and the
    296       # associated //build/config/rust.gni vars `removed_rust_stdlib_libs` and
    297       # `added_rust_stdlib_libs` for which rlib files to expect.
    298       # `extra_sysroot_libs` is also used to copy non-std libs, if any.
    299       script = "find_std_rlibs.py"
    300       depfile = "$target_out_dir/stdlib.d"
    301       out_libdir = rebase_path(target_out_dir, root_build_dir)
    302       out_depfile = rebase_path(depfile, root_build_dir)
    303 
    304       # For the rustc sysroot we must include even the rlibs we don't pass to
    305       # the C++ linker.
    306       all_stdlibs_to_copy = stdlib_files + skip_stdlib_files
    307       args = [
    308         "--rust-bin-dir",
    309         rebase_path("${rust_sysroot}/bin", root_build_dir),
    310         "--output",
    311         out_libdir,
    312         "--depfile",
    313         out_depfile,
    314 
    315         # Due to limitations in Ninja's handling of .d files, we have to pick
    316         # *the first* of our outputs. To make diagnostics more obviously
    317         # related to the Rust standard library, we ensure libstd.rlib is first.
    318         "--depfile-target",
    319         stdlib_files[0],
    320 
    321         # Create a dependency on the rustc version so this action is re-run when
    322         # it changes. This argument is not actually read by the script.
    323         "--rustc-revision",
    324         rustc_revision,
    325       ]
    326 
    327       if (extra_sysroot_libs != []) {
    328         args += [
    329           "--extra-libs",
    330           string_join(",", extra_sysroot_libs),
    331         ]
    332       }
    333 
    334       args += [
    335         "--target",
    336         rust_abi_target,
    337       ]
    338 
    339       outputs = []
    340       foreach(lib, all_stdlibs_to_copy) {
    341         outputs += [ "$target_out_dir/lib$lib.rlib" ]
    342       }
    343       foreach(lib, extra_sysroot_libs) {
    344         outputs += [ "$target_out_dir/$lib" ]
    345       }
    346 
    347       visibility = [ ":*" ]
    348     }
    349 
    350     prebuilt_rustc_sysroot = "$root_out_dir/prebuilt_rustc_sysroot"
    351     copy("prebuilt_rustc_copy_to_sysroot") {
    352       assert(enable_rust,
    353              "Some C++ target is including Rust code even though " +
    354                  "enable_rust=false")
    355       deps = [ ":find_stdlib" ]
    356       sources = get_target_outputs(":find_stdlib")
    357       outputs =
    358           [ "$prebuilt_rustc_sysroot/$sysroot_lib_subdir/{{source_file_part}}" ]
    359 
    360       visibility = [ ":*" ]
    361     }
    362 
    363     config("prebuilt_stdlib_sysroot") {
    364       # Match the output directory of :prebuilt_rustc_copy_to_sysroot
    365       sysroot = rebase_path(prebuilt_rustc_sysroot, root_build_dir)
    366       rustflags = [ "--sysroot=$sysroot" ]
    367       visibility = [ ":*" ]
    368     }
    369 
    370     config("prebuilt_stdlib_libs") {
    371       ldflags = []
    372       lib_dir = rebase_path("$prebuilt_rustc_sysroot/$sysroot_lib_subdir",
    373                             root_build_dir)
    374 
    375       # We're unable to make these files regular gn dependencies because
    376       # they're prebuilt. Instead, we'll pass them in the ldflags. This doesn't
    377       # work for all types of build because ldflags propagate differently from
    378       # actual dependencies and therefore can end up in different targets from
    379       # the remap_alloc.cc above. For example, in a component build, we might
    380       # apply the remap_alloc.cc file and these ldlags to shared object A,
    381       # while shared object B (that depends upon A) might get only the ldflags
    382       # but not remap_alloc.cc, and thus the build will fail. There is
    383       # currently no known solution to this for the prebuilt stdlib - this
    384       # problem does not apply with configurations where we build the stdlib
    385       # ourselves, which is what we'll use in production.
    386       foreach(lib, stdlib_files) {
    387         this_file = "$lib_dir/lib$lib.rlib"
    388         ldflags += [ this_file ]
    389       }
    390       visibility = [ ":*" ]
    391     }
    392 
    393     group("std") {
    394       all_dependent_configs = [
    395         ":prebuilt_stdlib_libs",
    396         ":stdlib_public_dependent_libs",
    397       ]
    398       deps = [ ":prebuilt_rustc_copy_to_sysroot" ]
    399 
    400       # The host builds tools toolchain supports Rust only and does not use
    401       # the allocator remapping to point it to PartitionAlloc.
    402       if (!toolchain_for_rust_host_build_tools) {
    403         deps += [ ":remap_alloc" ]
    404       }
    405     }
    406   }
    407 }