tor-browser

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

find_std_rlibs.py (5288B)


      1 #!/usr/bin/env/python3
      2 
      3 # Copyright 2021 The Chromium Authors
      4 # Use of this source code is governed by a BSD-style license that can be
      5 # found in the LICENSE file.
      6 
      7 # See BUILD.gn in this directory for an explanation of what this script is for.
      8 
      9 import argparse
     10 import os
     11 import stat
     12 import sys
     13 import shutil
     14 import subprocess
     15 import re
     16 
     17 from collections import defaultdict
     18 
     19 EXPECTED_STDLIB_INPUT_REGEX = re.compile(r"([0-9a-z_]+)(?:-([0-9]+))?$")
     20 RLIB_NAME_REGEX = re.compile(r"lib([0-9a-z_]+)-([0-9a-f]+)\.rlib$")
     21 
     22 
     23 def main():
     24  parser = argparse.ArgumentParser("find_std_rlibs.py")
     25  parser.add_argument("--rust-bin-dir",
     26                      help="Path to Rust binaries",
     27                      required=True),
     28  parser.add_argument("--target", help="Rust target triple", required=False),
     29  parser.add_argument("--output",
     30                      help="Path to rlibs without suffixes",
     31                      required=True)
     32  parser.add_argument("--depfile", help="Path to write depfile", required=True)
     33  parser.add_argument("--depfile-target",
     34                      help="Target to key depfile around",
     35                      required=True)
     36  parser.add_argument("--extra-libs",
     37                      help="List of extra non-libstd sysroot libraries")
     38  parser.add_argument("--rustc-revision",
     39                      help="Not used, just passed from GN to add a dependency"
     40                      " on the rustc version.")
     41  args = parser.parse_args()
     42 
     43  extra_libs = set()
     44  if args.extra_libs:
     45    for lib in args.extra_libs.split(','):
     46      extra_libs.add(lib)
     47 
     48  # Ask rustc where to find the stdlib for this target.
     49  rustc = os.path.join(args.rust_bin_dir, "rustc")
     50  rustc_args = [rustc, "--print", "target-libdir"]
     51  if args.target:
     52    rustc_args.extend(["--target", args.target])
     53  rustlib_dir = subprocess.check_output(rustc_args).rstrip().decode()
     54 
     55  # Copy the rlibs to a predictable location. Whilst we're doing so,
     56  # also write a .d file so that ninja knows it doesn't need to do this
     57  # again unless the source rlibs change.
     58  # Format:
     59  # <output path to>/lib<lib name.rlib>: <path to each Rust stlib rlib>
     60  with open(args.depfile, 'w') as depfile:
     61    # Ninja isn't versatile at understanding depfiles. We have to say that a
     62    # single output depends on all the inputs. We choose any one of the
     63    # output rlibs for that purpose. If any of the input rlibs change, ninja
     64    # will run this script again and we'll copy them all afresh.
     65    depfile.write(
     66        "%s:" % (os.path.join(args.output, "lib%s.rlib" % args.depfile_target)))
     67 
     68    def copy_file(infile, outfile):
     69      depfile.write(f" {infile}")
     70      if (not os.path.exists(outfile)
     71          or os.stat(infile).st_mtime != os.stat(outfile).st_mtime):
     72        if os.path.exists(outfile):
     73          st = os.stat(outfile)
     74          os.chmod(outfile, st.st_mode | stat.S_IWUSR)
     75        shutil.copy(infile, outfile)
     76 
     77    # Each rlib is named "lib<crate_name>-<metadata>.rlib". The metadata
     78    # disambiguates multiple crates of the same name. We want to throw away the
     79    # metadata and use stable names. To do so, we replace the metadata bit with
     80    # a simple number 1, 2, etc. It doesn't matter how we assign these numbers
     81    # as long as it's consistent for a particular set of rlibs.
     82 
     83    # The rlib names present in the Rust distribution, including metadata. We
     84    # sort this list so crates of the same name are ordered by metadata. Also
     85    # filter out names that aren't rlibs.
     86    rlibs_present = [
     87        name for name in os.listdir(rustlib_dir) if name.endswith('.rlib')
     88    ]
     89    rlibs_present.sort()
     90 
     91    # Keep a count of the instances a crate name, so we can disambiguate the
     92    # rlibs with an incrementing number at the end.
     93    rlibs_seen = defaultdict(lambda: 0)
     94 
     95    for f in rlibs_present:
     96      # As standard Rust includes a hash on the end of each filename
     97      # representing certain metadata, to ensure that clients will link
     98      # against the correct version. As gn will be manually passing
     99      # the correct file path to our linker invocations, we don't need
    100      # that, and it would prevent us having the predictable filenames
    101      # which we need for statically computable gn dependency rules.
    102      (crate_name, metadata) = RLIB_NAME_REGEX.match(f).group(1, 2)
    103 
    104      # Use the number of times we've seen this name to disambiguate the output
    105      # filenames. Since we sort the input filenames including the metadata,
    106      # this will be the same every time.
    107      #
    108      # Only append the times seen if it is greater than 1. This allows the
    109      # BUILD.gn file to avoid adding '-1' to every name if there's only one
    110      # version of a particular one.
    111      rlibs_seen[crate_name] += 1
    112      if rlibs_seen[crate_name] == 1:
    113        concise_name = crate_name
    114      else:
    115        concise_name = "%s-%d" % (crate_name, rlibs_seen[crate_name])
    116 
    117      output_filename = f"lib{concise_name}.rlib"
    118 
    119      infile = os.path.join(rustlib_dir, f)
    120      outfile = os.path.join(args.output, output_filename)
    121      copy_file(infile, outfile)
    122 
    123    for f in extra_libs:
    124      infile = os.path.join(rustlib_dir, f)
    125      outfile = os.path.join(args.output, f)
    126      copy_file(infile, outfile)
    127 
    128    depfile.write("\n")
    129 
    130 
    131 if __name__ == '__main__':
    132  sys.exit(main())