tor-browser

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

bindgen.configure (12736B)


      1 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
      2 # vim: set filetype=python:
      3 # This Source Code Form is subject to the terms of the Mozilla Public
      4 # License, v. 2.0. If a copy of the MPL was not distributed with this
      5 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
      6 
      7 
      8 option(env="CBINDGEN", nargs=1, help="Path to cbindgen")
      9 
     10 
     11 @imports(_from="textwrap", _import="dedent")
     12 def check_cbindgen_version(cbindgen, fatal=False):
     13     log.debug("trying cbindgen: %s" % cbindgen)
     14 
     15     cbindgen_min_version = Version("0.29.1")
     16 
     17     # cbindgen x.y.z
     18     version = Version(check_cmd_output(cbindgen, "--version").strip().split(" ")[1])
     19     log.debug("%s has version %s" % (cbindgen, version))
     20     if version >= cbindgen_min_version:
     21         return True
     22     if not fatal:
     23         return False
     24 
     25     die(
     26         dedent(
     27             """\
     28     cbindgen version {} is too old. At least version {} is required.
     29 
     30     Please update using 'cargo install cbindgen --force' or running
     31     './mach bootstrap', after removing the existing executable located at
     32     {}.
     33     """.format(
     34                 version, cbindgen_min_version, cbindgen
     35             )
     36         )
     37     )
     38 
     39 
     40 # Similar behavior to what check_prog does.
     41 has_cbindgen_input = depends("CBINDGEN")(lambda x: x)
     42 bootstrap_cbindgen = depends(has_cbindgen_input)(lambda i: not i)
     43 
     44 
     45 @depends_if(
     46     "CBINDGEN",
     47     bootstrap_search_path("cbindgen", when=bootstrap_cbindgen),
     48     rust_search_path,
     49 )
     50 @checking("for cbindgen")
     51 @imports(_from="textwrap", _import="dedent")
     52 def cbindgen(cbindgen_override, bootstrap_search_path, rust_search_path):
     53     if cbindgen_override:
     54         check_cbindgen_version(cbindgen_override[0], fatal=True)
     55         return cbindgen_override[0]
     56 
     57     candidates = []
     58     for path in bootstrap_search_path + rust_search_path:
     59         candidate = find_program("cbindgen", [path])
     60         if not candidate:
     61             continue
     62         if check_cbindgen_version(candidate):
     63             return candidate
     64         candidates.append(candidate)
     65 
     66     if not candidates:
     67         raise FatalCheckError(
     68             dedent(
     69                 """\
     70         Cannot find cbindgen. Please run `mach bootstrap`,
     71         `cargo install cbindgen`, ensure that `cbindgen` is on your PATH,
     72         or point at an executable with `CBINDGEN`.
     73         """
     74             )
     75         )
     76     check_cbindgen_version(candidates[0], fatal=True)
     77 
     78 
     79 set_config("CBINDGEN", cbindgen)
     80 
     81 # Bindgen can use rustfmt to format Rust file, but it's not required.
     82 option(env="RUSTFMT", nargs=1, help="Path to the rustfmt program")
     83 
     84 rustfmt = check_prog(
     85     "RUSTFMT",
     86     ["rustfmt"],
     87     paths=rust_search_path,
     88     input="RUSTFMT",
     89     allow_missing=True,
     90 )
     91 
     92 
     93 option(
     94     "--with-libclang-path",
     95     nargs=1,
     96     help="Absolute path to a directory containing Clang/LLVM libraries for bindgen (version 3.9.x or above)",
     97 )
     98 option(
     99     "--with-clang-path",
    100     nargs=1,
    101     help="Absolute path to a Clang binary for bindgen (version 3.9.x or above)",
    102 )
    103 
    104 
    105 @depends(
    106     "--with-clang-path",
    107     configure_cache,
    108     c_compiler,
    109     cxx_compiler,
    110     clang_search_path,
    111     target,
    112     target_sysroot.path,
    113     android_version,
    114 )
    115 @checking("for clang for bindgen", lambda x: x.path if x else "not found")
    116 def bindgen_clang_compiler(
    117     clang_path,
    118     configure_cache,
    119     c_compiler,
    120     cxx_compiler,
    121     clang_search_path,
    122     target,
    123     sysroot_path,
    124     android_version,
    125 ):
    126     # When the target compiler is clang, use that, including flags.
    127     if cxx_compiler.type == "clang":
    128         if clang_path and clang_path[0] not in (
    129             c_compiler.compiler,
    130             cxx_compiler.compiler,
    131         ):
    132             die(
    133                 "--with-clang-path is not valid when the target compiler is %s",
    134                 cxx_compiler.type,
    135             )
    136         return namespace(
    137             path=cxx_compiler.compiler,
    138             flags=cxx_compiler.flags,
    139         )
    140     # When the target compiler is clang-cl, use clang in the same directory,
    141     # and figure the right flags to use.
    142     if cxx_compiler.type == "clang-cl":
    143         if clang_path and os.path.dirname(clang_path[0]) != os.path.dirname(
    144             cxx_compiler.compiler
    145         ):
    146             die(
    147                 "--with-clang-path must point to clang in the same directory "
    148                 "as the target compiler"
    149             )
    150         if not clang_path:
    151             clang_path = [os.path.join(os.path.dirname(cxx_compiler.compiler), "clang")]
    152 
    153     clang_path = find_program(
    154         clang_path[0] if clang_path else "clang++", clang_search_path
    155     )
    156     if not clang_path:
    157         return
    158     # Hack before bug 1617793: if the compiler is clang-cl, hack the target
    159     if cxx_compiler.type == "clang-cl":
    160         target = split_triplet("%s-pc-windows-msvc" % target.raw_cpu)
    161     flags = []
    162     if sysroot_path:
    163         flags.extend(("--sysroot", sysroot_path))
    164     info = check_compiler(
    165         configure_cache, [clang_path] + flags, "C++", target, android_version
    166     )
    167     # Usually, one check_compiler pass would be enough, but when cross-compiling
    168     # and the host and target don't use the same default C++ standard, we don't
    169     # get the --std flag, so try again. This is the same thing as valid_compiler()
    170     # does in toolchain.configure.
    171     if info.flags:
    172         flags += info.flags
    173         info = check_compiler(
    174             configure_cache, [clang_path] + flags, "C++", target, android_version
    175         )
    176     return namespace(
    177         path=clang_path,
    178         flags=flags + info.flags,
    179     )
    180 
    181 
    182 @depends("--with-libclang-path", bindgen_clang_compiler, host_library_name_info, host)
    183 @checking("for libclang for bindgen", lambda x: x if x else "not found")
    184 @imports("glob")
    185 @imports(_from="os", _import="pathsep")
    186 @imports(_from="os.path", _import="split", _as="pathsplit")
    187 @imports("re")
    188 def bindgen_libclang_path(libclang_path, clang, library_name_info, host):
    189     if not clang:
    190         if libclang_path:
    191             die(
    192                 "--with-libclang-path is not valid without a clang compiler "
    193                 "for bindgen"
    194             )
    195         return
    196 
    197     # Try to ensure that the clang shared library that bindgen is going
    198     # to look for is actually present.  The files that we search for
    199     # mirror the logic in clang-sys/build.rs.
    200     libclang_choices = []
    201     if host.os == "WINNT":
    202         libclang_choices.append("libclang.dll")
    203     libclang_choices.append(
    204         "%sclang%s" % (library_name_info.dll.prefix, library_name_info.dll.suffix)
    205     )
    206     if host.kernel == "Linux":
    207         libclang_choices.append("libclang.so.*")
    208 
    209     if host.os == "OpenBSD":
    210         libclang_choices.append("libclang.so.*.*")
    211 
    212     candidates = []
    213     if not libclang_path:
    214         # Try to find libclang_path based on clang search dirs.
    215         clang_search_dirs = check_cmd_output(clang.path, "-print-search-dirs")
    216         for line in clang_search_dirs.splitlines():
    217             name, _, value = line.partition(": =")
    218             if host.os == "WINNT" and name == "programs":
    219                 # On Windows, libclang.dll is in bin/ rather than lib/,
    220                 # so scan the programs search dirs.
    221                 # To make matters complicated, clang before version 9 uses `:`
    222                 # separate between paths (and `;` in newer versions)
    223                 if pathsep in value:
    224                     candidates.extend(value.split(pathsep))
    225                 else:
    226                     for part in value.split(":"):
    227                         # Assume that if previous "candidate" was of length 1,
    228                         # it's a drive letter and the current part is the rest of
    229                         # the corresponding full path.
    230                         if candidates and len(candidates[-1]) == 1:
    231                             candidates[-1] += ":" + part
    232                         else:
    233                             candidates.append(part)
    234             elif host.os != "WINNT" and name == "libraries":
    235                 # On other platforms, use the directories from the libraries
    236                 # search dirs that looks like $something/clang/$version.
    237                 for dir in value.split(pathsep):
    238                     dir, version = pathsplit(dir)
    239                     if re.match(r"[0-9.]+", version):
    240                         dir, name = pathsplit(dir)
    241                         if name == "clang":
    242                             candidates.append(dir)
    243     else:
    244         candidates.append(libclang_path[0])
    245 
    246     for dir in candidates:
    247         for pattern in libclang_choices:
    248             log.debug('Trying "%s" in "%s"', pattern, dir)
    249             libs = glob.glob(os.path.join(dir, pattern))
    250             if libs:
    251                 return libs[0]
    252 
    253 
    254 @depends(bindgen_clang_compiler, bindgen_libclang_path, build_project)
    255 def bindgen_config_paths(clang, libclang, build_project):
    256     # XXX: we want this code to be run for both Gecko and JS, but we don't
    257     # necessarily want to force a bindgen/Rust dependency on JS just yet.
    258     # Actually, we don't want to force an error if we're not building the
    259     # browser generally.  We therefore whitelist the projects that require
    260     # bindgen facilities at this point and leave it at that.
    261     if build_project in ("browser", "mobile/android"):
    262         if not clang:
    263             die(
    264                 "Could not find clang to generate run bindings for C/C++. "
    265                 "Please install the necessary packages, run `mach bootstrap`, "
    266                 "or use --with-clang-path to give the location of clang."
    267             )
    268 
    269         if not libclang:
    270             die(
    271                 "Could not find libclang to generate rust bindings for C/C++. "
    272                 "Please install the necessary packages, run `mach bootstrap`, "
    273                 "or use --with-libclang-path to give the path containing it."
    274             )
    275 
    276     if clang and libclang:
    277         return namespace(
    278             libclang=libclang,
    279             libclang_path=os.path.dirname(libclang),
    280             clang_path=clang.path,
    281             clang_flags=clang.flags,
    282         )
    283 
    284 
    285 @depends(bindgen_config_paths.libclang, when=bindgen_config_paths)
    286 @checking("that libclang is new enough", lambda s: "yes" if s else "no")
    287 @imports(_from="__builtin__", _import="Exception")
    288 @imports(_from="ctypes", _import="CDLL")
    289 @imports(_from="textwrap", _import="dedent")
    290 def min_libclang_version(libclang):
    291     try:
    292         lib = CDLL(libclang)
    293         # We want at least 5.0. The API we test below is enough for that.
    294         # Just accessing it should throw if not found.
    295         fun = lib.clang_getAddressSpace
    296         return True
    297     except Exception as e:
    298         log.debug(e)
    299         die(
    300             dedent(
    301                 """\
    302         The libclang located at {} is too old (need at least 5.0).
    303 
    304         Please make sure to update it or point to a newer libclang using
    305         --with-libclang-path.
    306         """.format(
    307                     libclang
    308                 )
    309             )
    310         )
    311         return False
    312 
    313 
    314 set_config("MOZ_LIBCLANG_PATH", bindgen_config_paths.libclang_path)
    315 set_config("MOZ_CLANG_PATH", bindgen_config_paths.clang_path)
    316 
    317 
    318 @depends(
    319     target,
    320     cxx_compiler,
    321     bindgen_cflags_android,
    322     bindgen_config_paths.clang_flags,
    323     all_clang_arm_flags,
    324 )
    325 def basic_bindgen_cflags(
    326     target, compiler_info, android_cflags, clang_flags, all_arm_flags
    327 ):
    328     args = [
    329         "-x",
    330         "c++",
    331         "-fno-sized-deallocation",
    332         "-fno-aligned-new",
    333         "-DTRACING=1",
    334         "-DIMPL_LIBXUL",
    335         "-DMOZILLA_INTERNAL_API",
    336         "-DRUST_BINDGEN",
    337     ]
    338 
    339     if target.os == "Android":
    340         args += android_cflags
    341 
    342     args += {
    343         "WINNT": [
    344             "-DWIN32=1",
    345         ],
    346     }.get(target.os, [])
    347 
    348     if compiler_info.type == "clang-cl":
    349         args += [
    350             # To enable the builtin __builtin_offsetof so that CRT wouldn't
    351             # use reinterpret_cast in offsetof() which is not allowed inside
    352             # static_assert().
    353             "-D_CRT_USE_BUILTIN_OFFSETOF",
    354             # Enable hidden attribute (which is not supported by MSVC and
    355             # thus not enabled by default with a MSVC-compatibile build)
    356             # to exclude hidden symbols from the generated file.
    357             "-DHAVE_VISIBILITY_HIDDEN_ATTRIBUTE=1",
    358         ]
    359 
    360     return args + (clang_flags or []) + (all_arm_flags or [])
    361 
    362 
    363 option(
    364     env="BINDGEN_CFLAGS",
    365     nargs=1,
    366     help="Options bindgen should pass to the C/C++ parser",
    367 )
    368 
    369 
    370 @depends(basic_bindgen_cflags, "BINDGEN_CFLAGS")
    371 @checking("bindgen cflags", lambda s: s if s else "no")
    372 def bindgen_cflags(base_flags, extra_flags):
    373     flags = base_flags
    374     if extra_flags and len(extra_flags):
    375         flags += extra_flags[0].split()
    376     return flags
    377 
    378 
    379 set_config("BINDGEN_SYSTEM_FLAGS", bindgen_cflags)