Bug 1869043 add a main thread record of track audio outputs r=padenot
[gecko.git] / build / moz.configure / compile-checks.configure
blobd40a6b40af45a82864ded4e95cfc8f01575ed068
1 # -*- Mode: python; c-basic-offset: 4; 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 # Generates a test program and attempts to compile it. In case of failure, the
9 # resulting check will return None. If the test program succeeds, it will return
10 # the output of the test program.
11 # - `includes` are the includes (as file names) that will appear at the top of
12 #   the generated test program.
13 # - `body` is the code that will appear in the main function of the generated
14 #   test program. `return 0;` is appended to the function body automatically.
15 # - `language` is the language selection, so that the appropriate compiler is
16 #   used.
17 # - `flags` are the flags to be passed to the compiler, in addition to `-c`.
18 # - `check_msg` is the message to be printed to accompany compiling the test
19 #   program.
20 @template
21 def try_compile(
22     includes=None,
23     body="",
24     language="C++",
25     flags=None,
26     check_msg=None,
27     when=None,
28     onerror=lambda: None,
30     compiler = {
31         "C": c_compiler,
32         "C++": cxx_compiler,
33     }[language]
35     return compiler.try_compile(
36         includes, body, flags, check_msg, when=when, onerror=onerror
37     )
40 # Checks for the presence of the given header on the target system by compiling
41 # a test program including that header. The return value of the template is a
42 # check function returning True if the header is present, and None if it is not.
43 # The value of this check function is also used to set a variable (with set_define)
44 # corresponding to the checked header. For instance, HAVE_MALLOC_H will be set in
45 # defines if check_header if called with 'malloc.h' as input and malloc.h is
46 # present on the target.
47 # - `header` is the header, as a file name, to check for.
48 # - `language` is the language selection, so that the appropriate compiler is
49 #   used.
50 # - `flags` are the flags to be passed to the compiler, in addition to `-c`.
51 # - `includes` are additional includes, as file names, to appear before the
52 #   header checked for.
53 # - `when` is a depends function that if present will make performing the check
54 #   conditional on the value of that function.
55 @template
56 def check_header(
57     header, language="C++", flags=None, includes=None, when=None, onerror=lambda: None
59     if when is None:
60         when = always
62     if includes:
63         includes = includes[:]
64     else:
65         includes = []
66     includes.append(header)
68     have_header = try_compile(
69         includes=includes,
70         language=language,
71         flags=flags,
72         check_msg="for %s" % header,
73         when=when,
74         onerror=onerror,
75     )
76     header_var = "HAVE_%s" % (
77         header.upper().replace("-", "_").replace("/", "_").replace(".", "_")
78     )
79     set_define(header_var, have_header)
80     return have_header
83 # A convenience wrapper for check_header for checking multiple headers.
84 # returns an array of the resulting checks in order corresponding to the
85 # provided headers.
86 # - `headers` are the headers to be checked.
87 # - `kwargs` are keyword arguments passed verbatim to check_header.
90 @template
91 def check_headers(*headers, **kwargs):
92     checks = []
93     for header in headers:
94         checks.append(check_header(header, **kwargs))
95     return checks
98 @depends(linker_ldflags, target.kernel)
99 def check_symbol_flags(linker_ldflags, kernel):
100     if kernel == "WINNT":
101         # The build doesn't use the compiler to link things as of writing,
102         # but some compilation checks do. When using clang-cl, the only
103         # linker we really support is lld.link, but clang-cl defaults to
104         # link.exe (even when cross-compiling). So we force the use of
105         # lld.link for the linkage checks.
106         return ["-fuse-ld=lld"]
107     return linker_ldflags
110 # Checks for the presence of the given symbol on the target system by compiling
111 # a test program. The return value of the template is a check function
112 # returning True if the symbol can be found, and None if it is not.
113 @template
114 def check_symbol(symbol, language="C", flags=None, when=None, onerror=lambda: None):
115     if when is None:
116         when = always
118     compiler, extern_c = {
119         "C": (c_compiler, ""),
120         "C++": (cxx_compiler, 'extern "C" '),
121     }[language]
123     # Stolen from autoconf 2.13 ; might be irrelevant now, but it doesn't hurt to
124     # keep using a char return type.
125     comment = [
126         "/* Override any gcc2 internal prototype to avoid an error.  */",
127         "/* We use char because int might match the return type of a gcc2",
128         "    builtin and then its argument prototype would still apply.  */",
129     ]
131     if flags:
133         @depends(check_symbol_flags, dependable(flags))
134         def flags(base_flags, extra_flags):
135             if base_flags and extra_flags:
136                 return base_flags + list(extra_flags)
137             if extra_flags:
138                 return extra_flags
139             return base_flags
141     else:
142         flags = check_symbol_flags
144     return compiler.try_run(
145         header=comment + ["%schar %s();" % (extern_c, symbol)],
146         body="%s();" % symbol,
147         flags=flags,
148         check_msg="for %s" % symbol,
149         when=when,
150         onerror=onerror,
151     )
154 # Determine whether to add a given flag to the given lists of flags for C or
155 # C++ compilation.
156 # - `flag` is the flag to test
157 # - `flags_collection` is a @depends function for a namespace of lists of
158 #    C/C++ compiler flags to add to.
159 # - `test_flags` is a list of flags to pass to the compiler instead of merely
160 #   passing `flag`. This is especially useful for checking warning flags. If
161 #   this list is empty, `flag` will be passed on its own.
162 # - `compiler` (optional) is the compiler to test against (c_compiler or
163 #   cxx_compiler, from toolchain.configure). When omitted, both compilers
164 #   are tested; the list of flags added to is dependent on the compiler tested.
165 # - `when` (optional) is a @depends function or option name conditioning
166 #   when the warning flag is wanted.
167 # - `check`, when not set, skips checking whether the flag is supported and
168 #   adds it to the list of flags unconditionally.
169 @template
170 def check_and_add_flags(
171     flag, flags_collection, test_flags, compiler=None, when=None, check=True
173     if compiler is not None:
174         compilers = (compiler,)
175     else:
176         compilers = (c_compiler, cxx_compiler)
178     if when is None:
179         when = always
181     results = []
183     if test_flags:
184         flags = test_flags
185     else:
186         flags = [flag]
188     for c in compilers:
189         assert c in {c_compiler, cxx_compiler, host_c_compiler, host_cxx_compiler}
190         lang, list_of_flags = {
191             c_compiler: ("C", flags_collection.cflags),
192             cxx_compiler: ("C++", flags_collection.cxxflags),
193             host_c_compiler: ("host C", flags_collection.host_cflags),
194             host_cxx_compiler: ("host C++", flags_collection.host_cxxflags),
195         }[c]
197         result = when
199         if check:
201             @depends(c, dependable(flags))
202             def flags(c, flags):
203                 # Don't error out just because clang complains about other things.
204                 if c.type in ("clang", "clang-cl"):
205                     flags += ["-Wno-error=unused-command-line-argument"]
207                 return flags
209             result = c.try_compile(
210                 flags=flags,
211                 when=result,
212                 check_msg="whether the %s compiler supports %s" % (lang, flag),
213             )
215         @depends(result, list_of_flags)
216         def maybe_add_flag(result, list_of_flags):
217             if result:
218                 list_of_flags.append(flag)
220         results.append(result)
222     return tuple(results)
225 @dependable
226 def warnings_flags():
227     return namespace(cflags=[], cxxflags=[], host_cflags=[], host_cxxflags=[])
230 # Tests whether GCC or clang support the given warning flag, and if it is,
231 # add it to the list of warning flags for the build.
232 # - `warning` is the warning flag (e.g. -Wfoo)
233 # - `compiler` (optional) is the compiler to test against (c_compiler or
234 #   cxx_compiler, from toolchain.configure). When omitted, both compilers
235 #   are tested.
236 # - `when` (optional) is a @depends function or option name conditioning
237 #   when the warning flag is wanted.
238 # - `check`, when not set, skips checking whether the flag is supported and
239 #   adds it to the list of warning flags unconditionally. This is only meant
240 #   for add_warning().
241 @template
242 def check_and_add_warning(warning, compiler=None, when=None, check=True):
243     # GCC and clang will fail if given an unknown warning option like
244     # -Wfoobar. But later versions won't fail if given an unknown negated
245     # warning option like -Wno-foobar. So when we are checking for support
246     # of a negated warning option, we actually test the positive form, but
247     # add the negated form to the flags variable.
248     if warning.startswith("-Wno-") and not warning.startswith("-Wno-error="):
249         flags = ["-Werror", "-W" + warning[5:]]
250     elif warning.startswith("-Werror="):
251         flags = [warning]
252     else:
253         flags = ["-Werror", warning]
255     return check_and_add_flags(
256         warning, warnings_flags, flags, compiler=compiler, when=when, check=check
257     )
260 # Add the given warning to the list of warning flags for the build.
261 # - `warning` is the warning flag (e.g. -Wfoo)
262 # - `compiler` (optional) is the compiler to add the flag for (c_compiler or
263 #   cxx_compiler, from toolchain.configure). When omitted, the warning flag
264 #   is added for both compilers.
265 # - `when` (optional) is a @depends function or option name conditioning
266 #   when the warning flag is wanted.
269 @template
270 def add_warning(warning, compiler=None, when=None):
271     check_and_add_warning(warning, compiler, when, check=False)
274 # Like the warning checks above, but for general compilation flags.
275 @dependable
276 def compilation_flags():
277     return namespace(cflags=[], cxxflags=[], host_cflags=[], host_cxxflags=[])
280 # Tests whether GCC or clang support the given compilation flag; if the flag
281 # is supported, add it to the list of compilation flags for the build.
282 # - `flag` is the flag to test
283 # - `compiler` (optional) is the compiler to test against (c_compiler or
284 #   cxx_compiler, from toolchain.configure). When omitted, both compilers
285 #   are tested.
286 # - `when` (optional) is a @depends function or option name conditioning
287 #   when the warning flag is wanted.
288 # - `check`, when not set, skips checking whether the flag is supported and
289 #   adds it to the list of flags unconditionally. This is only meant for
290 #   add_flag().
291 @template
292 def check_and_add_flag(flag, compiler=None, when=None, check=True):
293     flags = ["-Werror", flag]
295     return check_and_add_flags(
296         flag, compilation_flags, flags, compiler=compiler, when=when, check=check
297     )
300 # Add the given flag to the list of flags for the build.
301 # - `flag` is the flag (e.g. -fno-sized-deallocation)
302 # - `compiler` (optional) is the compiler to add the flag for (c_compiler or
303 #   cxx_compiler, from toolchain.configure). When omitted, the flag is added
304 #   for both compilers.
305 # - `when` (optional) is a @depends function or option name conditioning
306 #   when the flag is wanted.
307 @template
308 def add_flag(warning, compiler=None, when=None):
309     check_and_add_flag(warning, compiler, when, check=False)