summaryrefslogtreecommitdiffstats
path: root/build/moz.configure/bindgen.configure
diff options
context:
space:
mode:
Diffstat (limited to 'build/moz.configure/bindgen.configure')
-rw-r--r--build/moz.configure/bindgen.configure403
1 files changed, 403 insertions, 0 deletions
diff --git a/build/moz.configure/bindgen.configure b/build/moz.configure/bindgen.configure
new file mode 100644
index 0000000000..5ce66fe9af
--- /dev/null
+++ b/build/moz.configure/bindgen.configure
@@ -0,0 +1,403 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+@depends(build_project, "--enable-smoosh")
+def cbindgen_is_needed(build_project, js_enable_smoosh):
+ if build_project != "js":
+ # cbindgen is needed by the style system build and webrender.
+ return True
+
+ # cbindgen is needed by SmooshMonkey.
+ return js_enable_smoosh
+
+
+option(env="CBINDGEN", nargs=1, when=cbindgen_is_needed, help="Path to cbindgen")
+
+
+@imports(_from="textwrap", _import="dedent")
+def check_cbindgen_version(cbindgen, fatal=False):
+ log.debug("trying cbindgen: %s" % cbindgen)
+
+ cbindgen_min_version = Version("0.24.3")
+
+ # cbindgen x.y.z
+ version = Version(check_cmd_output(cbindgen, "--version").strip().split(" ")[1])
+ log.debug("%s has version %s" % (cbindgen, version))
+ if version >= cbindgen_min_version:
+ return True
+ if not fatal:
+ return False
+
+ die(
+ dedent(
+ """\
+ cbindgen version {} is too old. At least version {} is required.
+
+ Please update using 'cargo install cbindgen --force' or running
+ './mach bootstrap', after removing the existing executable located at
+ {}.
+ """.format(
+ version, cbindgen_min_version, cbindgen
+ )
+ )
+ )
+
+
+# Similar behavior to what check_prog does.
+has_cbindgen_input = depends("CBINDGEN", when=cbindgen_is_needed)(lambda x: x)
+bootstrap_cbindgen = depends(cbindgen_is_needed, has_cbindgen_input)(
+ lambda n, i: n and not i
+)
+
+
+@depends_if(
+ "CBINDGEN",
+ bootstrap_search_path("cbindgen", when=bootstrap_cbindgen),
+ rust_search_path,
+ when=cbindgen_is_needed,
+)
+@checking("for cbindgen")
+@imports(_from="textwrap", _import="dedent")
+def cbindgen(cbindgen_override, bootstrap_search_path, rust_search_path):
+ if cbindgen_override:
+ check_cbindgen_version(cbindgen_override[0], fatal=True)
+ return cbindgen_override[0]
+
+ candidates = []
+ for path in bootstrap_search_path + rust_search_path:
+ candidate = find_program("cbindgen", [path])
+ if not candidate:
+ continue
+ if check_cbindgen_version(candidate):
+ return candidate
+ candidates.append(candidate)
+
+ if not candidates:
+ raise FatalCheckError(
+ dedent(
+ """\
+ Cannot find cbindgen. Please run `mach bootstrap`,
+ `cargo install cbindgen`, ensure that `cbindgen` is on your PATH,
+ or point at an executable with `CBINDGEN`.
+ """
+ )
+ )
+ check_cbindgen_version(candidates[0], fatal=True)
+
+
+set_config("CBINDGEN", cbindgen)
+
+# Bindgen can use rustfmt to format Rust file, but it's not required.
+option(env="RUSTFMT", nargs=1, help="Path to the rustfmt program")
+
+rustfmt = check_prog(
+ "RUSTFMT",
+ ["rustfmt"],
+ paths=rust_search_path,
+ input="RUSTFMT",
+ allow_missing=True,
+)
+
+
+option(
+ "--with-libclang-path",
+ nargs=1,
+ help="Absolute path to a directory containing Clang/LLVM libraries for bindgen (version 3.9.x or above)",
+)
+option(
+ "--with-clang-path",
+ nargs=1,
+ help="Absolute path to a Clang binary for bindgen (version 3.9.x or above)",
+)
+
+
+@depends(
+ "--with-clang-path",
+ configure_cache,
+ c_compiler,
+ cxx_compiler,
+ clang_search_path,
+ target,
+ target_sysroot.path,
+ android_version,
+)
+@checking("for clang for bindgen", lambda x: x.path if x else "not found")
+def bindgen_clang_compiler(
+ clang_path,
+ configure_cache,
+ c_compiler,
+ cxx_compiler,
+ clang_search_path,
+ target,
+ sysroot_path,
+ android_version,
+):
+ # When the target compiler is clang, use that, including flags.
+ if cxx_compiler.type == "clang":
+ if clang_path and clang_path[0] not in (
+ c_compiler.compiler,
+ cxx_compiler.compiler,
+ ):
+ die(
+ "--with-clang-path is not valid when the target compiler is %s",
+ cxx_compiler.type,
+ )
+ return namespace(
+ path=cxx_compiler.compiler,
+ flags=cxx_compiler.flags,
+ )
+ # When the target compiler is clang-cl, use clang in the same directory,
+ # and figure the right flags to use.
+ if cxx_compiler.type == "clang-cl":
+ if clang_path and os.path.dirname(clang_path[0]) != os.path.dirname(
+ cxx_compiler.compiler
+ ):
+ die(
+ "--with-clang-path must point to clang in the same directory "
+ "as the target compiler"
+ )
+ if not clang_path:
+ clang_path = [os.path.join(os.path.dirname(cxx_compiler.compiler), "clang")]
+
+ clang_path = find_program(
+ clang_path[0] if clang_path else "clang++", clang_search_path
+ )
+ if not clang_path:
+ return
+ # Hack before bug 1617793: if the compiler is clang-cl, hack the target
+ if cxx_compiler.type == "clang-cl":
+ target = split_triplet("%s-pc-windows-msvc" % target.raw_cpu)
+ flags = []
+ if sysroot_path:
+ flags.extend(("--sysroot", sysroot_path))
+ info = check_compiler(
+ configure_cache, [clang_path] + flags, "C++", target, android_version
+ )
+ # Usually, one check_compiler pass would be enough, but when cross-compiling
+ # and the host and target don't use the same default C++ standard, we don't
+ # get the --std flag, so try again. This is the same thing as valid_compiler()
+ # does in toolchain.configure.
+ if info.flags:
+ flags += info.flags
+ info = check_compiler(
+ configure_cache, [clang_path] + flags, "C++", target, android_version
+ )
+ return namespace(
+ path=clang_path,
+ flags=flags + info.flags,
+ )
+
+
+@depends("--with-libclang-path", bindgen_clang_compiler, host_library_name_info, host)
+@checking("for libclang for bindgen", lambda x: x if x else "not found")
+@imports("glob")
+@imports(_from="os", _import="pathsep")
+@imports(_from="os.path", _import="split", _as="pathsplit")
+@imports("re")
+def bindgen_libclang_path(libclang_path, clang, library_name_info, host):
+ if not clang:
+ if libclang_path:
+ die(
+ "--with-libclang-path is not valid without a clang compiler "
+ "for bindgen"
+ )
+ return
+
+ # Try to ensure that the clang shared library that bindgen is going
+ # to look for is actually present. The files that we search for
+ # mirror the logic in clang-sys/build.rs.
+ libclang_choices = []
+ if host.os == "WINNT":
+ libclang_choices.append("libclang.dll")
+ libclang_choices.append(
+ "%sclang%s" % (library_name_info.dll.prefix, library_name_info.dll.suffix)
+ )
+ if host.kernel == "Linux":
+ libclang_choices.append("libclang.so.*")
+
+ if host.os == "OpenBSD":
+ libclang_choices.append("libclang.so.*.*")
+
+ candidates = []
+ if not libclang_path:
+ # Try to find libclang_path based on clang search dirs.
+ clang_search_dirs = check_cmd_output(clang.path, "-print-search-dirs")
+ for line in clang_search_dirs.splitlines():
+ name, _, value = line.partition(": =")
+ if host.os == "WINNT" and name == "programs":
+ # On Windows, libclang.dll is in bin/ rather than lib/,
+ # so scan the programs search dirs.
+ # To make matters complicated, clang before version 9 uses `:`
+ # separate between paths (and `;` in newer versions)
+ if pathsep in value:
+ candidates.extend(value.split(pathsep))
+ else:
+ for part in value.split(":"):
+ # Assume that if previous "candidate" was of length 1,
+ # it's a drive letter and the current part is the rest of
+ # the corresponding full path.
+ if candidates and len(candidates[-1]) == 1:
+ candidates[-1] += ":" + part
+ else:
+ candidates.append(part)
+ elif host.os != "WINNT" and name == "libraries":
+ # On other platforms, use the directories from the libraries
+ # search dirs that looks like $something/clang/$version.
+ for dir in value.split(pathsep):
+ dir, version = pathsplit(dir)
+ if re.match(r"[0-9.]+", version):
+ dir, name = pathsplit(dir)
+ if name == "clang":
+ candidates.append(dir)
+ else:
+ candidates.append(libclang_path[0])
+
+ for dir in candidates:
+ for pattern in libclang_choices:
+ log.debug('Trying "%s" in "%s"', pattern, dir)
+ libs = glob.glob(os.path.join(dir, pattern))
+ if libs:
+ return libs[0]
+
+
+@depends(bindgen_clang_compiler, bindgen_libclang_path, build_project)
+def bindgen_config_paths(clang, libclang, build_project):
+ # XXX: we want this code to be run for both Gecko and JS, but we don't
+ # necessarily want to force a bindgen/Rust dependency on JS just yet.
+ # Actually, we don't want to force an error if we're not building the
+ # browser generally. We therefore whitelist the projects that require
+ # bindgen facilities at this point and leave it at that.
+ if build_project in ("browser", "mobile/android"):
+ if not clang:
+ die(
+ "Could not find clang to generate run bindings for C/C++. "
+ "Please install the necessary packages, run `mach bootstrap`, "
+ "or use --with-clang-path to give the location of clang."
+ )
+
+ if not libclang:
+ die(
+ "Could not find libclang to generate rust bindings for C/C++. "
+ "Please install the necessary packages, run `mach bootstrap`, "
+ "or use --with-libclang-path to give the path containing it."
+ )
+
+ if clang and libclang:
+ return namespace(
+ libclang=libclang,
+ libclang_path=os.path.dirname(libclang),
+ clang_path=clang.path,
+ clang_flags=clang.flags,
+ )
+
+
+@depends(bindgen_config_paths.libclang, when=bindgen_config_paths)
+@checking("that libclang is new enough", lambda s: "yes" if s else "no")
+@imports(_from="ctypes", _import="CDLL")
+@imports(_from="textwrap", _import="dedent")
+def min_libclang_version(libclang):
+ try:
+ lib = CDLL(libclang)
+ # We want at least 5.0. The API we test below is enough for that.
+ # Just accessing it should throw if not found.
+ fun = lib.clang_getAddressSpace
+ return True
+ except:
+ die(
+ dedent(
+ """\
+ The libclang located at {} is too old (need at least 5.0).
+
+ Please make sure to update it or point to a newer libclang using
+ --with-libclang-path.
+ """.format(
+ libclang
+ )
+ )
+ )
+ return False
+
+
+set_config("MOZ_LIBCLANG_PATH", bindgen_config_paths.libclang_path)
+set_config("MOZ_CLANG_PATH", bindgen_config_paths.clang_path)
+
+
+@depends(
+ target,
+ target_is_unix,
+ cxx_compiler,
+ bindgen_cflags_android,
+ bindgen_config_paths.clang_flags,
+ all_clang_arm_flags,
+)
+def basic_bindgen_cflags(
+ target, is_unix, compiler_info, android_cflags, clang_flags, all_arm_flags
+):
+ args = [
+ "-x",
+ "c++",
+ "-fno-sized-deallocation",
+ "-fno-aligned-new",
+ "-DTRACING=1",
+ "-DIMPL_LIBXUL",
+ "-DMOZILLA_INTERNAL_API",
+ "-DRUST_BINDGEN",
+ ]
+
+ if is_unix:
+ args += ["-DOS_POSIX=1"]
+
+ if target.os == "Android":
+ args += android_cflags
+
+ args += {
+ "Android": ["-DOS_ANDROID=1"],
+ "DragonFly": ["-DOS_BSD=1", "-DOS_DRAGONFLY=1"],
+ "FreeBSD": ["-DOS_BSD=1", "-DOS_FREEBSD=1"],
+ "GNU": ["-DOS_LINUX=1"],
+ "NetBSD": ["-DOS_BSD=1", "-DOS_NETBSD=1"],
+ "OpenBSD": ["-DOS_BSD=1", "-DOS_OPENBSD=1"],
+ "OSX": ["-DOS_MACOSX=1"],
+ "SunOS": ["-DOS_SOLARIS=1"],
+ "WINNT": [
+ "-DOS_WIN=1",
+ "-DWIN32=1",
+ ],
+ }.get(target.os, [])
+
+ if compiler_info.type == "clang-cl":
+ args += [
+ # To enable the builtin __builtin_offsetof so that CRT wouldn't
+ # use reinterpret_cast in offsetof() which is not allowed inside
+ # static_assert().
+ "-D_CRT_USE_BUILTIN_OFFSETOF",
+ # Enable hidden attribute (which is not supported by MSVC and
+ # thus not enabled by default with a MSVC-compatibile build)
+ # to exclude hidden symbols from the generated file.
+ "-DHAVE_VISIBILITY_HIDDEN_ATTRIBUTE=1",
+ ]
+
+ return args + (clang_flags or []) + (all_arm_flags or [])
+
+
+option(
+ env="BINDGEN_CFLAGS",
+ nargs=1,
+ help="Options bindgen should pass to the C/C++ parser",
+)
+
+
+@depends(basic_bindgen_cflags, "BINDGEN_CFLAGS")
+@checking("bindgen cflags", lambda s: s if s else "no")
+def bindgen_cflags(base_flags, extra_flags):
+ flags = base_flags
+ if extra_flags and len(extra_flags):
+ flags += extra_flags[0].split()
+ return " ".join(flags)
+
+
+set_config("BINDGEN_SYSTEM_FLAGS", bindgen_cflags)