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