• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1from __future__ import print_function
2
3import json
4import sys
5import errno
6import argparse
7import os
8import pprint
9import re
10import shlex
11import subprocess
12import shutil
13import bz2
14import io
15from pathlib import Path
16
17from distutils.version import StrictVersion
18
19# If not run from node/, cd to node/.
20os.chdir(Path(__file__).parent)
21
22original_argv = sys.argv[1:]
23
24# gcc and g++ as defaults matches what GYP's Makefile generator does,
25# except on OS X.
26CC = os.environ.get('CC', 'cc' if sys.platform == 'darwin' else 'gcc')
27CXX = os.environ.get('CXX', 'c++' if sys.platform == 'darwin' else 'g++')
28
29tools_path = Path('tools')
30
31sys.path.insert(0, str(tools_path / 'gyp' / 'pylib'))
32from gyp.common import GetFlavor
33
34# imports in tools/configure.d
35sys.path.insert(0, str(tools_path / 'configure.d'))
36import nodedownload
37
38# imports in tools/
39sys.path.insert(0, 'tools')
40import getmoduleversion
41import getnapibuildversion
42import getsharedopensslhasquic
43from gyp_node import run_gyp
44from utils import SearchFiles
45
46# parse our options
47parser = argparse.ArgumentParser()
48
49valid_os = ('win', 'mac', 'solaris', 'freebsd', 'openbsd', 'linux',
50            'android', 'aix', 'cloudabi', 'os400', 'ios')
51valid_arch = ('arm', 'arm64', 'ia32', 'mips', 'mipsel', 'mips64el', 'ppc',
52              'ppc64', 'x64', 'x86', 'x86_64', 's390x', 'riscv64', 'loong64')
53valid_arm_float_abi = ('soft', 'softfp', 'hard')
54valid_arm_fpu = ('vfp', 'vfpv3', 'vfpv3-d16', 'neon')
55valid_mips_arch = ('loongson', 'r1', 'r2', 'r6', 'rx')
56valid_mips_fpu = ('fp32', 'fp64', 'fpxx')
57valid_mips_float_abi = ('soft', 'hard')
58valid_intl_modes = ('none', 'small-icu', 'full-icu', 'system-icu')
59icu_versions = json.loads((tools_path / 'icu' / 'icu_versions.json').read_text(encoding='utf-8'))
60
61shareable_builtins = {'cjs_module_lexer/lexer': 'deps/cjs-module-lexer/lexer.js',
62                     'cjs_module_lexer/dist/lexer': 'deps/cjs-module-lexer/dist/lexer.js',
63                     'undici/undici': 'deps/undici/undici.js'
64}
65
66# create option groups
67shared_optgroup = parser.add_argument_group("Shared libraries",
68    "Flags that allows you to control whether you want to build against "
69    "built-in dependencies or its shared representations. If necessary, "
70    "provide multiple libraries with comma.")
71static_optgroup = parser.add_argument_group("Static libraries",
72    "Flags that allows you to control whether you want to build against "
73    "additional static libraries.")
74intl_optgroup = parser.add_argument_group("Internationalization",
75    "Flags that lets you enable i18n features in Node.js as well as which "
76    "library you want to build against.")
77http2_optgroup = parser.add_argument_group("HTTP2",
78    "Flags that allows you to control HTTP2 features in Node.js")
79shared_builtin_optgroup = parser.add_argument_group("Shared builtins",
80    "Flags that allows you to control whether you want to build against "
81    "internal builtins or shared files.")
82
83# Options should be in alphabetical order but keep --prefix at the top,
84# that's arguably the one people will be looking for most.
85parser.add_argument('--prefix',
86    action='store',
87    dest='prefix',
88    default='/usr/local',
89    help='select the install prefix [default: %(default)s]')
90
91parser.add_argument('--coverage',
92    action='store_true',
93    dest='coverage',
94    default=None,
95    help='Build node with code coverage enabled')
96
97parser.add_argument('--debug',
98    action='store_true',
99    dest='debug',
100    default=None,
101    help='also build debug build')
102
103parser.add_argument('--debug-node',
104    action='store_true',
105    dest='debug_node',
106    default=None,
107    help='build the Node.js part of the binary with debugging symbols')
108
109parser.add_argument('--dest-cpu',
110    action='store',
111    dest='dest_cpu',
112    choices=valid_arch,
113    help=f"CPU architecture to build for ({', '.join(valid_arch)})")
114
115parser.add_argument('--cross-compiling',
116    action='store_true',
117    dest='cross_compiling',
118    default=None,
119    help='force build to be considered as cross compiled')
120parser.add_argument('--no-cross-compiling',
121    action='store_false',
122    dest='cross_compiling',
123    default=None,
124    help='force build to be considered as NOT cross compiled')
125
126parser.add_argument('--dest-os',
127    action='store',
128    dest='dest_os',
129    choices=valid_os,
130    help=f"operating system to build for ({', '.join(valid_os)})")
131
132parser.add_argument('--error-on-warn',
133    action='store_true',
134    dest='error_on_warn',
135    default=None,
136    help='Turn compiler warnings into errors for node core sources.')
137
138parser.add_argument('--gdb',
139    action='store_true',
140    dest='gdb',
141    default=None,
142    help='add gdb support')
143
144parser.add_argument('--no-ifaddrs',
145    action='store_true',
146    dest='no_ifaddrs',
147    default=None,
148    help='use on deprecated SunOS systems that do not support ifaddrs.h')
149
150parser.add_argument('--disable-single-executable-application',
151    action='store_true',
152    dest='disable_single_executable_application',
153    default=None,
154    help='Disable Single Executable Application support.')
155
156parser.add_argument("--fully-static",
157    action="store_true",
158    dest="fully_static",
159    default=None,
160    help="Generate an executable without external dynamic libraries. This "
161         "will not work on OSX when using the default compilation environment")
162
163parser.add_argument("--partly-static",
164    action="store_true",
165    dest="partly_static",
166    default=None,
167    help="Generate an executable with libgcc and libstdc++ libraries. This "
168         "will not work on OSX when using the default compilation environment")
169
170parser.add_argument("--enable-vtune-profiling",
171    action="store_true",
172    dest="enable_vtune_profiling",
173    help="Enable profiling support for Intel VTune profiler to profile "
174         "JavaScript code executed in Node.js. This feature is only available "
175         "for x32, x86, and x64 architectures.")
176
177parser.add_argument("--enable-pgo-generate",
178    action="store_true",
179    dest="enable_pgo_generate",
180    default=None,
181    help="Enable profiling with pgo of a binary. This feature is only available "
182         "on linux with gcc and g++ 5.4.1 or newer.")
183
184parser.add_argument("--enable-pgo-use",
185    action="store_true",
186    dest="enable_pgo_use",
187    default=None,
188    help="Enable use of the profile generated with --enable-pgo-generate. This "
189         "feature is only available on linux with gcc and g++ 5.4.1 or newer.")
190
191parser.add_argument("--enable-lto",
192    action="store_true",
193    dest="enable_lto",
194    default=None,
195    help="Enable compiling with lto of a binary. This feature is only available "
196         "with gcc 5.4.1+ or clang 3.9.1+.")
197
198parser.add_argument("--link-module",
199    action="append",
200    dest="linked_module",
201    help="Path to a JS file to be bundled in the binary as a builtin. "
202         "This module will be referenced by path without extension; "
203         "e.g. /root/x/y.js will be referenced via require('root/x/y'). "
204         "Can be used multiple times")
205
206parser.add_argument("--openssl-conf-name",
207    action="store",
208    dest="openssl_conf_name",
209    default='nodejs_conf',
210    help="The OpenSSL config appname (config section name) used by Node.js")
211
212parser.add_argument('--openssl-default-cipher-list',
213    action='store',
214    dest='openssl_default_cipher_list',
215    help='Use the specified cipher list as the default cipher list')
216
217parser.add_argument("--openssl-no-asm",
218    action="store_true",
219    dest="openssl_no_asm",
220    default=None,
221    help="Do not build optimized assembly for OpenSSL")
222
223parser.add_argument('--openssl-is-fips',
224    action='store_true',
225    dest='openssl_is_fips',
226    default=None,
227    help='specifies that the OpenSSL library is FIPS compatible')
228
229parser.add_argument('--openssl-use-def-ca-store',
230    action='store_true',
231    dest='use_openssl_ca_store',
232    default=None,
233    help='Use OpenSSL supplied CA store instead of compiled-in Mozilla CA copy.')
234
235parser.add_argument('--openssl-system-ca-path',
236    action='store',
237    dest='openssl_system_ca_path',
238    help='Use the specified path to system CA (PEM format) in addition to '
239         'the OpenSSL supplied CA store or compiled-in Mozilla CA copy.')
240
241parser.add_argument('--experimental-http-parser',
242    action='store_true',
243    dest='experimental_http_parser',
244    default=None,
245    help='(no-op)')
246
247shared_optgroup.add_argument('--shared-http-parser',
248    action='store_true',
249    dest='shared_http_parser',
250    default=None,
251    help='link to a shared http_parser DLL instead of static linking')
252
253shared_optgroup.add_argument('--shared-http-parser-includes',
254    action='store',
255    dest='shared_http_parser_includes',
256    help='directory containing http_parser header files')
257
258shared_optgroup.add_argument('--shared-http-parser-libname',
259    action='store',
260    dest='shared_http_parser_libname',
261    default='http_parser',
262    help='alternative lib name to link to [default: %(default)s]')
263
264shared_optgroup.add_argument('--shared-http-parser-libpath',
265    action='store',
266    dest='shared_http_parser_libpath',
267    help='a directory to search for the shared http_parser DLL')
268
269shared_optgroup.add_argument('--shared-libuv',
270    action='store_true',
271    dest='shared_libuv',
272    default=None,
273    help='link to a shared libuv DLL instead of static linking')
274
275shared_optgroup.add_argument('--shared-libuv-includes',
276    action='store',
277    dest='shared_libuv_includes',
278    help='directory containing libuv header files')
279
280shared_optgroup.add_argument('--shared-libuv-libname',
281    action='store',
282    dest='shared_libuv_libname',
283    default='uv',
284    help='alternative lib name to link to [default: %(default)s]')
285
286shared_optgroup.add_argument('--shared-libuv-libpath',
287    action='store',
288    dest='shared_libuv_libpath',
289    help='a directory to search for the shared libuv DLL')
290
291shared_optgroup.add_argument('--shared-nghttp2',
292    action='store_true',
293    dest='shared_nghttp2',
294    default=None,
295    help='link to a shared nghttp2 DLL instead of static linking')
296
297shared_optgroup.add_argument('--shared-nghttp2-includes',
298    action='store',
299    dest='shared_nghttp2_includes',
300    help='directory containing nghttp2 header files')
301
302shared_optgroup.add_argument('--shared-nghttp2-libname',
303    action='store',
304    dest='shared_nghttp2_libname',
305    default='nghttp2',
306    help='alternative lib name to link to [default: %(default)s]')
307
308shared_optgroup.add_argument('--shared-nghttp2-libpath',
309    action='store',
310    dest='shared_nghttp2_libpath',
311    help='a directory to search for the shared nghttp2 DLLs')
312
313shared_optgroup.add_argument('--shared-nghttp3',
314    action='store_true',
315    dest='shared_nghttp3',
316    default=None,
317    help='link to a shared nghttp3 DLL instead of static linking')
318
319shared_optgroup.add_argument('--shared-nghttp3-includes',
320    action='store',
321    dest='shared_nghttp3_includes',
322    help='directory containing nghttp3 header files')
323
324shared_optgroup.add_argument('--shared-nghttp3-libname',
325    action='store',
326    dest='shared_nghttp3_libname',
327    default='nghttp3',
328    help='alternative lib name to link to [default: %(default)s]')
329
330shared_optgroup.add_argument('--shared-nghttp3-libpath',
331    action='store',
332    dest='shared_nghttp3_libpath',
333    help='a directory to search for the shared nghttp3 DLLs')
334
335shared_optgroup.add_argument('--shared-ngtcp2',
336    action='store_true',
337    dest='shared_ngtcp2',
338    default=None,
339    help='link to a shared ngtcp2 DLL instead of static linking')
340
341shared_optgroup.add_argument('--shared-ngtcp2-includes',
342    action='store',
343    dest='shared_ngtcp2_includes',
344    help='directory containing ngtcp2 header files')
345
346shared_optgroup.add_argument('--shared-ngtcp2-libname',
347    action='store',
348    dest='shared_ngtcp2_libname',
349    default='ngtcp2',
350    help='alternative lib name to link to [default: %(default)s]')
351
352shared_optgroup.add_argument('--shared-ngtcp2-libpath',
353    action='store',
354    dest='shared_ngtcp2_libpath',
355    help='a directory to search for the shared tcp2 DLLs')
356
357shared_optgroup.add_argument('--shared-openssl',
358    action='store_true',
359    dest='shared_openssl',
360    default=None,
361    help='link to a shared OpenSSl DLL instead of static linking')
362
363shared_optgroup.add_argument('--shared-openssl-includes',
364    action='store',
365    dest='shared_openssl_includes',
366    help='directory containing OpenSSL header files')
367
368shared_optgroup.add_argument('--shared-openssl-libname',
369    action='store',
370    dest='shared_openssl_libname',
371    default='crypto,ssl',
372    help='alternative lib name to link to [default: %(default)s]')
373
374shared_optgroup.add_argument('--shared-openssl-libpath',
375    action='store',
376    dest='shared_openssl_libpath',
377    help='a directory to search for the shared OpenSSL DLLs')
378
379shared_optgroup.add_argument('--shared-zlib',
380    action='store_true',
381    dest='shared_zlib',
382    default=None,
383    help='link to a shared zlib DLL instead of static linking')
384
385shared_optgroup.add_argument('--shared-zlib-includes',
386    action='store',
387    dest='shared_zlib_includes',
388    help='directory containing zlib header files')
389
390shared_optgroup.add_argument('--shared-zlib-libname',
391    action='store',
392    dest='shared_zlib_libname',
393    default='z',
394    help='alternative lib name to link to [default: %(default)s]')
395
396shared_optgroup.add_argument('--shared-zlib-libpath',
397    action='store',
398    dest='shared_zlib_libpath',
399    help='a directory to search for the shared zlib DLL')
400
401shared_optgroup.add_argument('--shared-brotli',
402    action='store_true',
403    dest='shared_brotli',
404    default=None,
405    help='link to a shared brotli DLL instead of static linking')
406
407shared_optgroup.add_argument('--shared-brotli-includes',
408    action='store',
409    dest='shared_brotli_includes',
410    help='directory containing brotli header files')
411
412shared_optgroup.add_argument('--shared-brotli-libname',
413    action='store',
414    dest='shared_brotli_libname',
415    default='brotlidec,brotlienc',
416    help='alternative lib name to link to [default: %(default)s]')
417
418shared_optgroup.add_argument('--shared-brotli-libpath',
419    action='store',
420    dest='shared_brotli_libpath',
421    help='a directory to search for the shared brotli DLL')
422
423shared_optgroup.add_argument('--shared-cares',
424    action='store_true',
425    dest='shared_cares',
426    default=None,
427    help='link to a shared cares DLL instead of static linking')
428
429shared_optgroup.add_argument('--shared-cares-includes',
430    action='store',
431    dest='shared_cares_includes',
432    help='directory containing cares header files')
433
434shared_optgroup.add_argument('--shared-cares-libname',
435    action='store',
436    dest='shared_cares_libname',
437    default='cares',
438    help='alternative lib name to link to [default: %(default)s]')
439
440shared_optgroup.add_argument('--shared-cares-libpath',
441    action='store',
442    dest='shared_cares_libpath',
443    help='a directory to search for the shared cares DLL')
444
445parser.add_argument_group(shared_optgroup)
446
447for builtin in shareable_builtins:
448  builtin_id = 'shared_builtin_' + builtin + '_path'
449  shared_builtin_optgroup.add_argument('--shared-builtin-' + builtin + '-path',
450    action='store',
451    dest='node_shared_builtin_' + builtin.replace('/', '_') + '_path',
452    help='Path to shared file for ' + builtin + ' builtin. '
453         'Will be used instead of bundled version at runtime')
454
455parser.add_argument_group(shared_builtin_optgroup)
456
457static_optgroup.add_argument('--static-zoslib-gyp',
458    action='store',
459    dest='static_zoslib_gyp',
460    help='path to zoslib.gyp file for includes and to link to static zoslib library')
461
462parser.add_argument_group(static_optgroup)
463
464parser.add_argument('--systemtap-includes',
465    action='store',
466    dest='systemtap_includes',
467    help='directory containing systemtap header files')
468
469parser.add_argument('--tag',
470    action='store',
471    dest='tag',
472    help='custom build tag')
473
474parser.add_argument('--release-urlbase',
475    action='store',
476    dest='release_urlbase',
477    help='Provide a custom URL prefix for the `process.release` properties '
478         '`sourceUrl` and `headersUrl`. When compiling a release build, this '
479         'will default to https://nodejs.org/download/release/')
480
481parser.add_argument('--enable-d8',
482    action='store_true',
483    dest='enable_d8',
484    default=None,
485    help=argparse.SUPPRESS)  # Unsupported, undocumented.
486
487parser.add_argument('--enable-trace-maps',
488    action='store_true',
489    dest='trace_maps',
490    default=None,
491    help='Enable the --trace-maps flag in V8 (use at your own risk)')
492
493parser.add_argument('--experimental-enable-pointer-compression',
494    action='store_true',
495    dest='enable_pointer_compression',
496    default=None,
497    help='[Experimental] Enable V8 pointer compression (limits max heap to 4GB and breaks ABI compatibility)')
498
499parser.add_argument('--disable-shared-readonly-heap',
500    action='store_true',
501    dest='disable_shared_ro_heap',
502    default=None,
503    help='Disable the shared read-only heap feature in V8')
504
505parser.add_argument('--v8-options',
506    action='store',
507    dest='v8_options',
508    help='v8 options to pass, see `node --v8-options` for examples.')
509
510parser.add_argument('--with-ossfuzz',
511    action='store_true',
512    dest='ossfuzz',
513    default=None,
514    help='Enables building of fuzzers. This command should be run in an OSS-Fuzz Docker image.')
515
516parser.add_argument('--with-arm-float-abi',
517    action='store',
518    dest='arm_float_abi',
519    choices=valid_arm_float_abi,
520    help=f"specifies which floating-point ABI to use ({', '.join(valid_arm_float_abi)}).")
521
522parser.add_argument('--with-arm-fpu',
523    action='store',
524    dest='arm_fpu',
525    choices=valid_arm_fpu,
526    help=f"ARM FPU mode ({', '.join(valid_arm_fpu)}) [default: %(default)s]")
527
528parser.add_argument('--with-mips-arch-variant',
529    action='store',
530    dest='mips_arch_variant',
531    default='r2',
532    choices=valid_mips_arch,
533    help=f"MIPS arch variant ({', '.join(valid_mips_arch)}) [default: %(default)s]")
534
535parser.add_argument('--with-mips-fpu-mode',
536    action='store',
537    dest='mips_fpu_mode',
538    default='fp32',
539    choices=valid_mips_fpu,
540    help=f"MIPS FPU mode ({', '.join(valid_mips_fpu)}) [default: %(default)s]")
541
542parser.add_argument('--with-mips-float-abi',
543    action='store',
544    dest='mips_float_abi',
545    default='hard',
546    choices=valid_mips_float_abi,
547    help=f"MIPS floating-point ABI ({', '.join(valid_mips_float_abi)}) [default: %(default)s]")
548
549parser.add_argument('--with-dtrace',
550    action='store_true',
551    dest='with_dtrace',
552    default=None,
553    help='build with DTrace (default is true on sunos and darwin)')
554
555parser.add_argument('--with-etw',
556    action='store_true',
557    dest='with_etw',
558    default=None,
559    help='build with ETW (default is true on Windows)')
560
561parser.add_argument('--use-largepages',
562    action='store_true',
563    dest='node_use_large_pages',
564    default=None,
565    help='This option has no effect. --use-largepages is now a runtime option.')
566
567parser.add_argument('--use-largepages-script-lld',
568    action='store_true',
569    dest='node_use_large_pages_script_lld',
570    default=None,
571    help='This option has no effect. --use-largepages is now a runtime option.')
572
573parser.add_argument('--use-section-ordering-file',
574    action='store',
575    dest='node_section_ordering_info',
576    default='',
577    help='Pass a section ordering file to the linker. This requires that ' +
578         'Node.js be linked using the gold linker. The gold linker must have ' +
579         'version 1.2 or greater.')
580
581intl_optgroup.add_argument('--with-intl',
582    action='store',
583    dest='with_intl',
584    default='full-icu',
585    choices=valid_intl_modes,
586    help=f"Intl mode (valid choices: {', '.join(valid_intl_modes)}) [default: %(default)s]")
587
588intl_optgroup.add_argument('--without-intl',
589    action='store_const',
590    dest='with_intl',
591    const='none',
592    help='Disable Intl, same as --with-intl=none')
593
594intl_optgroup.add_argument('--with-icu-path',
595    action='store',
596    dest='with_icu_path',
597    help='Path to icu.gyp (ICU i18n, Chromium version only.)')
598
599icu_default_locales='root,en'
600
601intl_optgroup.add_argument('--with-icu-locales',
602    action='store',
603    dest='with_icu_locales',
604    default=icu_default_locales,
605    help='Comma-separated list of locales for "small-icu". "root" is assumed. '
606        '[default: %(default)s]')
607
608intl_optgroup.add_argument('--with-icu-source',
609    action='store',
610    dest='with_icu_source',
611    help='Intl mode: optional local path to icu/ dir, or path/URL of '
612        'the icu4c source archive. '
613        f"v{icu_versions['minimum_icu']}.x or later recommended.")
614
615intl_optgroup.add_argument('--with-icu-default-data-dir',
616    action='store',
617    dest='with_icu_default_data_dir',
618    help='Path to the icuXXdt{lb}.dat file. If unspecified, ICU data will '
619         'only be read if the NODE_ICU_DATA environment variable or the '
620         '--icu-data-dir runtime argument is used. This option has effect '
621         'only when Node.js is built with --with-intl=small-icu.')
622
623parser.add_argument('--with-ltcg',
624    action='store_true',
625    dest='with_ltcg',
626    default=None,
627    help='Use Link Time Code Generation. This feature is only available on Windows.')
628
629parser.add_argument('--without-node-snapshot',
630    action='store_true',
631    dest='without_node_snapshot',
632    default=None,
633    help='Turn off V8 snapshot integration. Currently experimental.')
634
635parser.add_argument('--without-node-code-cache',
636    action='store_true',
637    dest='without_node_code_cache',
638    default=None,
639    help='Turn off V8 Code cache integration.')
640
641intl_optgroup.add_argument('--download',
642    action='store',
643    dest='download_list',
644    help=nodedownload.help())
645
646intl_optgroup.add_argument('--download-path',
647    action='store',
648    dest='download_path',
649    default='deps',
650    help='Download directory [default: %(default)s]')
651
652parser.add_argument_group(intl_optgroup)
653
654parser.add_argument('--debug-lib',
655    action='store_true',
656    dest='node_debug_lib',
657    default=None,
658    help='build lib with DCHECK macros')
659
660http2_optgroup.add_argument('--debug-nghttp2',
661    action='store_true',
662    dest='debug_nghttp2',
663    default=None,
664    help='build nghttp2 with DEBUGBUILD (default is false)')
665
666parser.add_argument_group(http2_optgroup)
667
668parser.add_argument('--without-dtrace',
669    action='store_true',
670    dest='without_dtrace',
671    default=None,
672    help='build without DTrace')
673
674parser.add_argument('--without-etw',
675    action='store_true',
676    dest='without_etw',
677    default=None,
678    help='build without ETW')
679
680parser.add_argument('--without-npm',
681    action='store_true',
682    dest='without_npm',
683    default=None,
684    help='do not install the bundled npm (package manager)')
685
686parser.add_argument('--without-corepack',
687    action='store_true',
688    dest='without_corepack',
689    default=None,
690    help='do not install the bundled Corepack')
691
692# Dummy option for backwards compatibility
693parser.add_argument('--without-report',
694    action='store_true',
695    dest='unused_without_report',
696    default=None,
697    help=argparse.SUPPRESS)
698
699parser.add_argument('--with-snapshot',
700    action='store_true',
701    dest='unused_with_snapshot',
702    default=None,
703    help=argparse.SUPPRESS)
704
705parser.add_argument('--without-snapshot',
706    action='store_true',
707    dest='unused_without_snapshot',
708    default=None,
709    help=argparse.SUPPRESS)
710
711parser.add_argument('--without-siphash',
712    action='store_true',
713    dest='without_siphash',
714    default=None,
715    help=argparse.SUPPRESS)
716
717# End dummy list.
718
719parser.add_argument('--without-ssl',
720    action='store_true',
721    dest='without_ssl',
722    default=None,
723    help='build without SSL (disables crypto, https, inspector, etc.)')
724
725parser.add_argument('--without-node-options',
726    action='store_true',
727    dest='without_node_options',
728    default=None,
729    help='build without NODE_OPTIONS support')
730
731parser.add_argument('--ninja',
732    action='store_true',
733    dest='use_ninja',
734    default=None,
735    help='generate build files for use with Ninja')
736
737parser.add_argument('--enable-asan',
738    action='store_true',
739    dest='enable_asan',
740    default=None,
741    help='compile for Address Sanitizer to find memory bugs')
742
743parser.add_argument('--enable-static',
744    action='store_true',
745    dest='enable_static',
746    default=None,
747    help='build as static library')
748
749parser.add_argument('--no-browser-globals',
750    action='store_true',
751    dest='no_browser_globals',
752    default=None,
753    help='do not export browser globals like setTimeout, console, etc. ' +
754         '(This mode is deprecated and not officially supported for regular ' +
755         'applications)')
756
757parser.add_argument('--without-inspector',
758    action='store_true',
759    dest='without_inspector',
760    default=None,
761    help='disable the V8 inspector protocol')
762
763parser.add_argument('--shared',
764    action='store_true',
765    dest='shared',
766    default=None,
767    help='compile shared library for embedding node in another project. ' +
768         '(This mode is not officially supported for regular applications)')
769
770parser.add_argument('--libdir',
771    action='store',
772    dest='libdir',
773    default='lib',
774    help='a directory to install the shared library into relative to the '
775         'prefix. This is a no-op if --shared is not specified. ' +
776         '(This mode is not officially supported for regular applications)')
777
778parser.add_argument('--without-v8-platform',
779    action='store_true',
780    dest='without_v8_platform',
781    default=False,
782    help='do not initialize v8 platform during node.js startup. ' +
783         '(This mode is not officially supported for regular applications)')
784
785parser.add_argument('--without-bundled-v8',
786    action='store_true',
787    dest='without_bundled_v8',
788    default=False,
789    help='do not use V8 includes from the bundled deps folder. ' +
790         '(This mode is not officially supported for regular applications)')
791
792parser.add_argument('--verbose',
793    action='store_true',
794    dest='verbose',
795    default=False,
796    help='get more output from this script')
797
798parser.add_argument('--v8-non-optimized-debug',
799    action='store_true',
800    dest='v8_non_optimized_debug',
801    default=False,
802    help='compile V8 with minimal optimizations and with runtime checks')
803
804parser.add_argument('--v8-with-dchecks',
805    action='store_true',
806    dest='v8_with_dchecks',
807    default=False,
808    help='compile V8 with debug checks and runtime debugging features enabled')
809
810parser.add_argument('--v8-lite-mode',
811    action='store_true',
812    dest='v8_lite_mode',
813    default=False,
814    help='compile V8 in lite mode for constrained environments (lowers V8 '+
815         'memory footprint, but also implies no just-in-time compilation ' +
816         'support, thus much slower execution)')
817
818parser.add_argument('--v8-enable-object-print',
819    action='store_true',
820    dest='v8_enable_object_print',
821    default=True,
822    help='compile V8 with auxiliary functions for native debuggers')
823
824parser.add_argument('--v8-disable-object-print',
825    action='store_true',
826    dest='v8_disable_object_print',
827    default=False,
828    help='disable the V8 auxiliary functions for native debuggers')
829
830parser.add_argument('--v8-enable-hugepage',
831    action='store_true',
832    dest='v8_enable_hugepage',
833    default=None,
834    help='Enable V8 transparent hugepage support. This feature is only '+
835         'available on Linux platform.')
836
837parser.add_argument('--v8-enable-short-builtin-calls',
838    action='store_true',
839    dest='v8_enable_short_builtin_calls',
840    default=None,
841    help='Enable V8 short builtin calls support. This feature is enabled '+
842         'on x86_64 platform by default.')
843
844parser.add_argument('--v8-enable-snapshot-compression',
845    action='store_true',
846    dest='v8_enable_snapshot_compression',
847    default=None,
848    help='Enable the built-in snapshot compression in V8.')
849
850parser.add_argument('--node-builtin-modules-path',
851    action='store',
852    dest='node_builtin_modules_path',
853    default=False,
854    help='node will load builtin modules from disk instead of from binary')
855
856parser.add_argument('--node-snapshot-main',
857    action='store',
858    dest='node_snapshot_main',
859    default=None,
860    help='Run a file when building the embedded snapshot. Currently ' +
861         'experimental.')
862
863# Create compile_commands.json in out/Debug and out/Release.
864parser.add_argument('-C',
865    action='store_true',
866    dest='compile_commands_json',
867    default=None,
868    help=argparse.SUPPRESS)
869
870(options, args) = parser.parse_known_args()
871
872# Expand ~ in the install prefix now, it gets written to multiple files.
873options.prefix = str(Path(options.prefix or '').expanduser())
874
875# set up auto-download list
876auto_downloads = nodedownload.parse(options.download_list)
877
878
879def error(msg):
880  prefix = '\033[1m\033[31mERROR\033[0m' if os.isatty(1) else 'ERROR'
881  print(f'{prefix}: {msg}')
882  sys.exit(1)
883
884def warn(msg):
885  warn.warned = True
886  prefix = '\033[1m\033[93mWARNING\033[0m' if os.isatty(1) else 'WARNING'
887  print(f'{prefix}: {msg}')
888
889# track if warnings occurred
890warn.warned = False
891
892def info(msg):
893  prefix = '\033[1m\033[32mINFO\033[0m' if os.isatty(1) else 'INFO'
894  print(f'{prefix}: {msg}')
895
896def print_verbose(x):
897  if not options.verbose:
898    return
899  if isinstance(x, str):
900    print(x)
901  else:
902    pprint.pprint(x, indent=2)
903
904def b(value):
905  """Returns the string 'true' if value is truthy, 'false' otherwise."""
906  return 'true' if value else 'false'
907
908def B(value):
909  """Returns 1 if value is truthy, 0 otherwise."""
910  return 1 if value else 0
911
912def to_utf8(s):
913  return s if isinstance(s, str) else s.decode("utf-8")
914
915def pkg_config(pkg):
916  """Run pkg-config on the specified package
917  Returns ("-l flags", "-I flags", "-L flags", "version")
918  otherwise (None, None, None, None)"""
919  pkg_config = os.environ.get('PKG_CONFIG', 'pkg-config')
920  args = []  # Print pkg-config warnings on first round.
921  retval = []
922  for flag in ['--libs-only-l', '--cflags-only-I',
923               '--libs-only-L', '--modversion']:
924    args += [flag]
925    if isinstance(pkg, list):
926      args += pkg
927    else:
928      args += [pkg]
929    try:
930      proc = subprocess.Popen(shlex.split(pkg_config) + args,
931                              stdout=subprocess.PIPE)
932      with proc:
933        val = to_utf8(proc.communicate()[0]).strip()
934    except OSError as e:
935      if e.errno != errno.ENOENT:
936        raise e  # Unexpected error.
937      return (None, None, None, None)  # No pkg-config/pkgconf installed.
938    retval.append(val)
939    args = ['--silence-errors']
940  return tuple(retval)
941
942
943def try_check_compiler(cc, lang):
944  try:
945    proc = subprocess.Popen(shlex.split(cc) + ['-E', '-P', '-x', lang, '-'],
946                            stdin=subprocess.PIPE, stdout=subprocess.PIPE)
947  except OSError:
948    return (False, False, '', '')
949
950  with proc:
951    proc.stdin.write(b'__clang__ __GNUC__ __GNUC_MINOR__ __GNUC_PATCHLEVEL__ '
952                     b'__clang_major__ __clang_minor__ __clang_patchlevel__')
953
954    if sys.platform == 'zos':
955      values = (to_utf8(proc.communicate()[0]).split('\n')[-2].split() + ['0'] * 7)[0:7]
956    else:
957      values = (to_utf8(proc.communicate()[0]).split() + ['0'] * 7)[0:7]
958
959  is_clang = values[0] == '1'
960  gcc_version = tuple(map(int, values[1:1+3]))
961  clang_version = tuple(map(int, values[4:4+3])) if is_clang else None
962
963  return (True, is_clang, clang_version, gcc_version)
964
965
966#
967# The version of asm compiler is needed for building openssl asm files.
968# See deps/openssl/openssl.gypi for detail.
969# Commands and regular expressions to obtain its version number are taken from
970# https://github.com/openssl/openssl/blob/OpenSSL_1_0_2-stable/crypto/sha/asm/sha512-x86_64.pl#L112-L129
971#
972def get_version_helper(cc, regexp):
973  try:
974    proc = subprocess.Popen(shlex.split(cc) + ['-v'], stdin=subprocess.PIPE,
975                            stderr=subprocess.PIPE, stdout=subprocess.PIPE)
976  except OSError:
977    error('''No acceptable C compiler found!
978
979       Please make sure you have a C compiler installed on your system and/or
980       consider adjusting the CC environment variable if you installed
981       it in a non-standard prefix.''')
982
983  with proc:
984    match = re.search(regexp, to_utf8(proc.communicate()[1]))
985
986  return match.group(2) if match else '0.0'
987
988def get_nasm_version(asm):
989  try:
990    proc = subprocess.Popen(shlex.split(asm) + ['-v'],
991                            stdin=subprocess.PIPE, stderr=subprocess.PIPE,
992                            stdout=subprocess.PIPE)
993  except OSError:
994    warn('''No acceptable ASM compiler found!
995         Please make sure you have installed NASM from https://www.nasm.us
996         and refer BUILDING.md.''')
997    return '0.0'
998
999  with proc:
1000    match = re.match(r"NASM version ([2-9]\.[0-9][0-9]+)",
1001                     to_utf8(proc.communicate()[0]))
1002
1003  return match.group(1) if match else '0.0'
1004
1005def get_llvm_version(cc):
1006  return get_version_helper(
1007    cc, r"(^(?:.+ )?clang version|based on LLVM) ([0-9]+\.[0-9]+)")
1008
1009def get_xcode_version(cc):
1010  return get_version_helper(
1011    cc, r"(^Apple (?:clang|LLVM) version) ([0-9]+\.[0-9]+)")
1012
1013def get_gas_version(cc):
1014  try:
1015    custom_env = os.environ.copy()
1016    custom_env["LC_ALL"] = "C"
1017    proc = subprocess.Popen(shlex.split(cc) + ['-Wa,-v', '-c', '-o',
1018                                               '/dev/null', '-x',
1019                                               'assembler',  '/dev/null'],
1020                            stdin=subprocess.PIPE, stderr=subprocess.PIPE,
1021                            stdout=subprocess.PIPE, env=custom_env)
1022  except OSError:
1023    error('''No acceptable C compiler found!
1024
1025       Please make sure you have a C compiler installed on your system and/or
1026       consider adjusting the CC environment variable if you installed
1027       it in a non-standard prefix.''')
1028
1029  with proc:
1030    gas_ret = to_utf8(proc.communicate()[1])
1031
1032  match = re.match(r"GNU assembler version ([2-9]\.[0-9]+)", gas_ret)
1033
1034  if match:
1035    return match.group(1)
1036
1037  warn(f'Could not recognize `gas`: {gas_ret}')
1038  return '0.0'
1039
1040# Note: Apple clang self-reports as clang 4.2.0 and gcc 4.2.1.  It passes
1041# the version check more by accident than anything else but a more rigorous
1042# check involves checking the build number against an allowlist.  I'm not
1043# quite prepared to go that far yet.
1044def check_compiler(o):
1045  if sys.platform == 'win32':
1046    o['variables']['llvm_version'] = '0.0'
1047    if not options.openssl_no_asm and options.dest_cpu in ('x86', 'x64'):
1048      nasm_version = get_nasm_version('nasm')
1049      o['variables']['nasm_version'] = nasm_version
1050      if nasm_version == '0.0':
1051        o['variables']['openssl_no_asm'] = 1
1052    return
1053
1054  ok, is_clang, clang_version, gcc_version = try_check_compiler(CXX, 'c++')
1055  version_str = ".".join(map(str, clang_version if is_clang else gcc_version))
1056  print_verbose(f"Detected {'clang ' if is_clang else ''}C++ compiler (CXX={CXX}) version: {version_str}")
1057  if not ok:
1058    warn(f'failed to autodetect C++ compiler version (CXX={CXX})')
1059  elif clang_version < (8, 0, 0) if is_clang else gcc_version < (8, 3, 0):
1060    warn(f'C++ compiler (CXX={CXX}, {version_str}) too old, need g++ 8.3.0 or clang++ 8.0.0')
1061
1062  ok, is_clang, clang_version, gcc_version = try_check_compiler(CC, 'c')
1063  version_str = ".".join(map(str, clang_version if is_clang else gcc_version))
1064  print_verbose(f"Detected {'clang ' if is_clang else ''}C compiler (CC={CC}) version: {version_str}")
1065  if not ok:
1066    warn(f'failed to autodetect C compiler version (CC={CC})')
1067  elif not is_clang and gcc_version < (4, 2, 0):
1068    # clang 3.2 is a little white lie because any clang version will probably
1069    # do for the C bits.  However, we might as well encourage people to upgrade
1070    # to a version that is not completely ancient.
1071    warn(f'C compiler (CC={CC}, {version_str}) too old, need gcc 4.2 or clang 3.2')
1072
1073  o['variables']['llvm_version'] = get_llvm_version(CC) if is_clang else '0.0'
1074
1075  # Need xcode_version or gas_version when openssl asm files are compiled.
1076  if options.without_ssl or options.openssl_no_asm or options.shared_openssl:
1077    return
1078
1079  if is_clang:
1080    if sys.platform == 'darwin':
1081      o['variables']['xcode_version'] = get_xcode_version(CC)
1082  else:
1083    o['variables']['gas_version'] = get_gas_version(CC)
1084
1085
1086def cc_macros(cc=None):
1087  """Checks predefined macros using the C compiler command."""
1088
1089  try:
1090    p = subprocess.Popen(shlex.split(cc or CC) + ['-dM', '-E', '-'],
1091                         stdin=subprocess.PIPE,
1092                         stdout=subprocess.PIPE,
1093                         stderr=subprocess.PIPE)
1094  except OSError:
1095    error('''No acceptable C compiler found!
1096
1097       Please make sure you have a C compiler installed on your system and/or
1098       consider adjusting the CC environment variable if you installed
1099       it in a non-standard prefix.''')
1100
1101  with p:
1102    p.stdin.write(b'\n')
1103    out = to_utf8(p.communicate()[0]).split('\n')
1104
1105  k = {}
1106  for line in out:
1107    lst = shlex.split(line)
1108    if len(lst) > 2:
1109      key = lst[1]
1110      val = lst[2]
1111      k[key] = val
1112  return k
1113
1114
1115def is_arch_armv7():
1116  """Check for ARMv7 instructions"""
1117  cc_macros_cache = cc_macros()
1118  return cc_macros_cache.get('__ARM_ARCH') == '7'
1119
1120
1121def is_arch_armv6():
1122  """Check for ARMv6 instructions"""
1123  cc_macros_cache = cc_macros()
1124  return cc_macros_cache.get('__ARM_ARCH') == '6'
1125
1126
1127def is_arm_hard_float_abi():
1128  """Check for hardfloat or softfloat eabi on ARM"""
1129  # GCC versions 4.6 and above define __ARM_PCS or __ARM_PCS_VFP to specify
1130  # the Floating Point ABI used (PCS stands for Procedure Call Standard).
1131  # We use these as well as a couple of other defines to statically determine
1132  # what FP ABI used.
1133
1134  return '__ARM_PCS_VFP' in cc_macros()
1135
1136
1137def host_arch_cc():
1138  """Host architecture check using the CC command."""
1139
1140  if sys.platform.startswith('zos'):
1141    return 's390x'
1142  k = cc_macros(os.environ.get('CC_host'))
1143
1144  matchup = {
1145    '__aarch64__' : 'arm64',
1146    '__arm__'     : 'arm',
1147    '__i386__'    : 'ia32',
1148    '__MIPSEL__'  : 'mipsel',
1149    '__mips__'    : 'mips',
1150    '__PPC64__'   : 'ppc64',
1151    '__PPC__'     : 'ppc64',
1152    '__x86_64__'  : 'x64',
1153    '__s390x__'   : 's390x',
1154    '__riscv'     : 'riscv',
1155    '__loongarch64': 'loong64',
1156  }
1157
1158  rtn = 'ia32' # default
1159
1160  for key, value in matchup.items():
1161    if k.get(key, 0) and k[key] != '0':
1162      rtn = value
1163      break
1164
1165  if rtn == 'mipsel' and '_LP64' in k:
1166    rtn = 'mips64el'
1167
1168  if rtn == 'riscv':
1169    if k['__riscv_xlen'] == '64':
1170      rtn = 'riscv64'
1171    else:
1172      rtn = 'riscv32'
1173
1174  return rtn
1175
1176
1177def host_arch_win():
1178  """Host architecture check using environ vars (better way to do this?)"""
1179
1180  observed_arch = os.environ.get('PROCESSOR_ARCHITECTURE', 'x86')
1181  arch = os.environ.get('PROCESSOR_ARCHITEW6432', observed_arch)
1182
1183  matchup = {
1184    'AMD64'  : 'x64',
1185    'x86'    : 'ia32',
1186    'arm'    : 'arm',
1187    'mips'   : 'mips',
1188    'ARM64'  : 'arm64'
1189  }
1190
1191  return matchup.get(arch, 'ia32')
1192
1193
1194def configure_arm(o):
1195  if options.arm_float_abi:
1196    arm_float_abi = options.arm_float_abi
1197  elif is_arm_hard_float_abi():
1198    arm_float_abi = 'hard'
1199  else:
1200    arm_float_abi = 'default'
1201
1202  arm_fpu = 'vfp'
1203
1204  if is_arch_armv7():
1205    arm_fpu = 'vfpv3'
1206    o['variables']['arm_version'] = '7'
1207  else:
1208    o['variables']['arm_version'] = '6' if is_arch_armv6() else 'default'
1209
1210  o['variables']['arm_thumb'] = 0      # -marm
1211  o['variables']['arm_float_abi'] = arm_float_abi
1212
1213  if options.dest_os == 'android':
1214    arm_fpu = 'vfpv3'
1215    o['variables']['arm_version'] = '7'
1216
1217  o['variables']['arm_fpu'] = options.arm_fpu or arm_fpu
1218
1219
1220def configure_mips(o, target_arch):
1221  can_use_fpu_instructions = options.mips_float_abi != 'soft'
1222  o['variables']['v8_can_use_fpu_instructions'] = b(can_use_fpu_instructions)
1223  o['variables']['v8_use_mips_abi_hardfloat'] = b(can_use_fpu_instructions)
1224  o['variables']['mips_arch_variant'] = options.mips_arch_variant
1225  o['variables']['mips_fpu_mode'] = options.mips_fpu_mode
1226  host_byteorder = 'little' if target_arch in ('mipsel', 'mips64el') else 'big'
1227  o['variables']['v8_host_byteorder'] = host_byteorder
1228
1229def configure_zos(o):
1230  o['variables']['node_static_zoslib'] = b(True)
1231  if options.static_zoslib_gyp:
1232    # Apply to all Node.js components for now
1233    o['variables']['zoslib_include_dir'] = Path(options.static_zoslib_gyp).parent + '/include'
1234    o['include_dirs'] += [o['variables']['zoslib_include_dir']]
1235  else:
1236    raise Exception('--static-zoslib-gyp=<path to zoslib.gyp file> is required.')
1237
1238def clang_version_ge(version_checked):
1239  for compiler in [(CC, 'c'), (CXX, 'c++')]:
1240    _, is_clang, clang_version, _1 = (
1241      try_check_compiler(compiler[0], compiler[1])
1242    )
1243    if is_clang and clang_version >= version_checked:
1244      return True
1245  return False
1246
1247def gcc_version_ge(version_checked):
1248  for compiler in [(CC, 'c'), (CXX, 'c++')]:
1249    _, is_clang, _1, gcc_version = (
1250      try_check_compiler(compiler[0], compiler[1])
1251    )
1252    if is_clang or gcc_version < version_checked:
1253      return False
1254  return True
1255
1256def configure_node_lib_files(o):
1257  o['variables']['node_library_files'] = SearchFiles('lib', 'js')
1258
1259def configure_node(o):
1260  if options.dest_os == 'android':
1261    o['variables']['OS'] = 'android'
1262  o['variables']['node_prefix'] = options.prefix
1263  o['variables']['node_install_npm'] = b(not options.without_npm)
1264  o['variables']['node_install_corepack'] = b(not options.without_corepack)
1265  o['variables']['debug_node'] = b(options.debug_node)
1266  o['default_configuration'] = 'Debug' if options.debug else 'Release'
1267  o['variables']['error_on_warn'] = b(options.error_on_warn)
1268
1269  host_arch = host_arch_win() if os.name == 'nt' else host_arch_cc()
1270  target_arch = options.dest_cpu or host_arch
1271  # ia32 is preferred by the build tools (GYP) over x86 even if we prefer the latter
1272  # the Makefile resets this to x86 afterward
1273  if target_arch == 'x86':
1274    target_arch = 'ia32'
1275  # x86_64 is common across linuxes, allow it as an alias for x64
1276  if target_arch == 'x86_64':
1277    target_arch = 'x64'
1278  o['variables']['host_arch'] = host_arch
1279  o['variables']['target_arch'] = target_arch
1280  o['variables']['node_byteorder'] = sys.byteorder
1281
1282  cross_compiling = (options.cross_compiling
1283                     if options.cross_compiling is not None
1284                     else target_arch != host_arch)
1285  if cross_compiling:
1286    os.environ['GYP_CROSSCOMPILE'] = "1"
1287  if options.unused_without_snapshot:
1288    warn('building --without-snapshot is no longer possible')
1289
1290  o['variables']['want_separate_host_toolset'] = int(cross_compiling)
1291
1292  # Enable branch protection for arm64
1293  if target_arch == 'arm64':
1294    o['cflags']+=['-msign-return-address=all']
1295    o['variables']['arm_fpu'] = options.arm_fpu or 'neon'
1296
1297  if options.node_snapshot_main is not None:
1298    if options.shared:
1299      # This should be possible to fix, but we will need to refactor the
1300      # libnode target to avoid building it twice.
1301      error('--node-snapshot-main is incompatible with --shared')
1302    if options.without_node_snapshot:
1303      error('--node-snapshot-main is incompatible with ' +
1304            '--without-node-snapshot')
1305    if cross_compiling:
1306      error('--node-snapshot-main is incompatible with cross compilation')
1307    o['variables']['node_snapshot_main'] = options.node_snapshot_main
1308
1309  if options.without_node_snapshot or options.node_builtin_modules_path:
1310    o['variables']['node_use_node_snapshot'] = 'false'
1311  else:
1312    o['variables']['node_use_node_snapshot'] = b(
1313      not cross_compiling and not options.shared)
1314
1315  if options.without_node_code_cache or options.without_node_snapshot or options.node_builtin_modules_path:
1316    o['variables']['node_use_node_code_cache'] = 'false'
1317  else:
1318    # TODO(refack): fix this when implementing embedded code-cache when cross-compiling.
1319    o['variables']['node_use_node_code_cache'] = b(
1320      not cross_compiling and not options.shared)
1321
1322  if target_arch == 'arm':
1323    configure_arm(o)
1324  elif target_arch in ('mips', 'mipsel', 'mips64el'):
1325    configure_mips(o, target_arch)
1326  elif sys.platform == 'zos':
1327    configure_zos(o)
1328
1329  if flavor in ('aix', 'os400'):
1330    o['variables']['node_target_type'] = 'static_library'
1331
1332  if target_arch in ('x86', 'x64', 'ia32', 'x32'):
1333    o['variables']['node_enable_v8_vtunejit'] = b(options.enable_vtune_profiling)
1334  elif options.enable_vtune_profiling:
1335    raise Exception(
1336       'The VTune profiler for JavaScript is only supported on x32, x86, and x64 '
1337       'architectures.')
1338  else:
1339    o['variables']['node_enable_v8_vtunejit'] = 'false'
1340
1341  if flavor != 'linux' and (options.enable_pgo_generate or options.enable_pgo_use):
1342    raise Exception(
1343      'The pgo option is supported only on linux.')
1344
1345  if flavor == 'linux':
1346    if options.enable_pgo_generate or options.enable_pgo_use:
1347      version_checked = (5, 4, 1)
1348      if not gcc_version_ge(version_checked):
1349        version_checked_str = ".".join(map(str, version_checked))
1350        raise Exception(
1351          'The options --enable-pgo-generate and --enable-pgo-use '
1352          f'are supported for gcc and gxx {version_checked_str} or newer only.')
1353
1354    if options.enable_pgo_generate and options.enable_pgo_use:
1355      raise Exception(
1356        'Only one of the --enable-pgo-generate or --enable-pgo-use options '
1357        'can be specified at a time. You would like to use '
1358        '--enable-pgo-generate first, profile node, and then recompile '
1359        'with --enable-pgo-use')
1360
1361  o['variables']['enable_pgo_generate'] = b(options.enable_pgo_generate)
1362  o['variables']['enable_pgo_use']      = b(options.enable_pgo_use)
1363
1364  if flavor == 'win' and (options.enable_lto):
1365    raise Exception(
1366      'Use Link Time Code Generation instead.')
1367
1368  if options.enable_lto:
1369    gcc_version_checked = (5, 4, 1)
1370    clang_version_checked = (3, 9, 1)
1371    if not gcc_version_ge(gcc_version_checked) and not clang_version_ge(clang_version_checked):
1372      gcc_version_checked_str = ".".join(map(str, gcc_version_checked))
1373      clang_version_checked_str = ".".join(map(str, clang_version_checked))
1374      raise Exception(
1375        f'The option --enable-lto is supported for gcc {gcc_version_checked_str}+'
1376        f'or clang {clang_version_checked_str}+ only.')
1377
1378  o['variables']['enable_lto'] = b(options.enable_lto)
1379
1380  if flavor in ('solaris', 'mac', 'linux', 'freebsd'):
1381    use_dtrace = not options.without_dtrace
1382    # Don't enable by default on linux and freebsd
1383    if flavor in ('linux', 'freebsd'):
1384      use_dtrace = options.with_dtrace
1385
1386    if flavor == 'linux':
1387      if options.systemtap_includes:
1388        o['include_dirs'] += [options.systemtap_includes]
1389    o['variables']['node_use_dtrace'] = b(use_dtrace)
1390  elif options.with_dtrace:
1391    raise Exception(
1392       'DTrace is currently only supported on SunOS, MacOS or Linux systems.')
1393  else:
1394    o['variables']['node_use_dtrace'] = 'false'
1395
1396  if options.node_use_large_pages or options.node_use_large_pages_script_lld:
1397    warn('''The `--use-largepages` and `--use-largepages-script-lld` options
1398         have no effect during build time. Support for mapping to large pages is
1399         now a runtime option of Node.js. Run `node --use-largepages` or add
1400         `--use-largepages` to the `NODE_OPTIONS` environment variable once
1401         Node.js is built to enable mapping to large pages.''')
1402
1403  if options.no_ifaddrs:
1404    o['defines'] += ['SUNOS_NO_IFADDRS']
1405
1406  o['variables']['single_executable_application'] = b(not options.disable_single_executable_application)
1407  if options.disable_single_executable_application:
1408    o['defines'] += ['DISABLE_SINGLE_EXECUTABLE_APPLICATION']
1409
1410  # By default, enable ETW on Windows.
1411  if flavor == 'win':
1412    o['variables']['node_use_etw'] = b(not options.without_etw)
1413  elif options.with_etw:
1414    raise Exception('ETW is only supported on Windows.')
1415  else:
1416    o['variables']['node_use_etw'] = 'false'
1417
1418  o['variables']['node_with_ltcg'] = b(options.with_ltcg)
1419  if flavor != 'win' and options.with_ltcg:
1420    raise Exception('Link Time Code Generation is only supported on Windows.')
1421
1422  if options.tag:
1423    o['variables']['node_tag'] = '-' + options.tag
1424  else:
1425    o['variables']['node_tag'] = ''
1426
1427  o['variables']['node_release_urlbase'] = options.release_urlbase or ''
1428
1429  if options.v8_options:
1430    o['variables']['node_v8_options'] = options.v8_options.replace('"', '\\"')
1431
1432  if options.enable_static:
1433    o['variables']['node_target_type'] = 'static_library'
1434
1435  o['variables']['node_debug_lib'] = b(options.node_debug_lib)
1436
1437  if options.debug_nghttp2:
1438    o['variables']['debug_nghttp2'] = 1
1439  else:
1440    o['variables']['debug_nghttp2'] = 'false'
1441
1442  o['variables']['node_no_browser_globals'] = b(options.no_browser_globals)
1443
1444  o['variables']['node_shared'] = b(options.shared)
1445  o['variables']['libdir'] = options.libdir
1446  node_module_version = getmoduleversion.get_version()
1447
1448  if options.dest_os == 'android':
1449    shlib_suffix = 'so'
1450  elif sys.platform == 'darwin':
1451    shlib_suffix = '%s.dylib'
1452  elif sys.platform.startswith('aix'):
1453    shlib_suffix = '%s.a'
1454  elif sys.platform == 'os400':
1455    shlib_suffix = '%s.a'
1456  elif sys.platform.startswith('zos'):
1457    shlib_suffix = '%s.x'
1458  else:
1459    shlib_suffix = 'so'
1460  if '%s' in shlib_suffix:
1461    shlib_suffix %= node_module_version
1462
1463  o['variables']['node_module_version'] = int(node_module_version)
1464  o['variables']['shlib_suffix'] = shlib_suffix
1465
1466  if options.linked_module:
1467    o['variables']['linked_module_files'] = options.linked_module
1468
1469  o['variables']['asan'] = int(options.enable_asan or 0)
1470
1471  if options.coverage:
1472    o['variables']['coverage'] = 'true'
1473  else:
1474    o['variables']['coverage'] = 'false'
1475
1476  if options.shared:
1477    o['variables']['node_target_type'] = 'shared_library'
1478  elif options.enable_static:
1479    o['variables']['node_target_type'] = 'static_library'
1480  else:
1481    o['variables']['node_target_type'] = 'executable'
1482
1483  if options.node_builtin_modules_path:
1484    print('Warning! Loading builtin modules from disk is for development')
1485    o['variables']['node_builtin_modules_path'] = options.node_builtin_modules_path
1486
1487def configure_napi(output):
1488  version = getnapibuildversion.get_napi_version()
1489  output['variables']['napi_build_version'] = version
1490
1491def configure_library(lib, output, pkgname=None):
1492  shared_lib = 'shared_' + lib
1493  output['variables']['node_' + shared_lib] = b(getattr(options, shared_lib))
1494
1495  if getattr(options, shared_lib):
1496    (pkg_libs, pkg_cflags, pkg_libpath, _) = pkg_config(pkgname or lib)
1497
1498    if options.__dict__[shared_lib + '_includes']:
1499      output['include_dirs'] += [options.__dict__[shared_lib + '_includes']]
1500    elif pkg_cflags:
1501      stripped_flags = [flag.strip() for flag in pkg_cflags.split('-I')]
1502      output['include_dirs'] += [flag for flag in stripped_flags if flag]
1503
1504    # libpath needs to be provided ahead libraries
1505    if options.__dict__[shared_lib + '_libpath']:
1506      if flavor == 'win':
1507        if 'msvs_settings' not in output:
1508          output['msvs_settings'] = { 'VCLinkerTool': { 'AdditionalOptions': [] } }
1509        output['msvs_settings']['VCLinkerTool']['AdditionalOptions'] += [
1510          f"/LIBPATH:{options.__dict__[shared_lib + '_libpath']}"]
1511      else:
1512        output['libraries'] += [
1513            f"-L{options.__dict__[shared_lib + '_libpath']}"]
1514    elif pkg_libpath:
1515      output['libraries'] += [pkg_libpath]
1516
1517    default_libs = getattr(options, shared_lib + '_libname')
1518    default_libs = [f'-l{l}' for l in default_libs.split(',')]
1519
1520    if default_libs:
1521      output['libraries'] += default_libs
1522    elif pkg_libs:
1523      output['libraries'] += pkg_libs.split()
1524
1525
1526def configure_v8(o):
1527  o['variables']['v8_enable_webassembly'] = 0 if options.v8_lite_mode else 1
1528  o['variables']['v8_enable_javascript_promise_hooks'] = 1
1529  o['variables']['v8_enable_lite_mode'] = 1 if options.v8_lite_mode else 0
1530  o['variables']['v8_enable_gdbjit'] = 1 if options.gdb else 0
1531  o['variables']['v8_no_strict_aliasing'] = 1  # Work around compiler bugs.
1532  o['variables']['v8_optimized_debug'] = 0 if options.v8_non_optimized_debug else 1
1533  o['variables']['dcheck_always_on'] = 1 if options.v8_with_dchecks else 0
1534  o['variables']['v8_enable_object_print'] = 0 if options.v8_disable_object_print else 1
1535  o['variables']['v8_random_seed'] = 0  # Use a random seed for hash tables.
1536  o['variables']['v8_promise_internal_field_count'] = 1 # Add internal field to promises for async hooks.
1537  o['variables']['v8_use_siphash'] = 0 if options.without_siphash else 1
1538  o['variables']['v8_enable_pointer_compression'] = 1 if options.enable_pointer_compression else 0
1539  o['variables']['v8_enable_31bit_smis_on_64bit_arch'] = 1 if options.enable_pointer_compression else 0
1540  o['variables']['v8_enable_shared_ro_heap'] = 0 if options.enable_pointer_compression or options.disable_shared_ro_heap else 1
1541  o['variables']['v8_trace_maps'] = 1 if options.trace_maps else 0
1542  o['variables']['node_use_v8_platform'] = b(not options.without_v8_platform)
1543  o['variables']['node_use_bundled_v8'] = b(not options.without_bundled_v8)
1544  o['variables']['force_dynamic_crt'] = 1 if options.shared else 0
1545  o['variables']['node_enable_d8'] = b(options.enable_d8)
1546  if options.enable_d8:
1547    o['variables']['test_isolation_mode'] = 'noop'  # Needed by d8.gyp.
1548  if options.without_bundled_v8 and options.enable_d8:
1549    raise Exception('--enable-d8 is incompatible with --without-bundled-v8.')
1550  if options.static_zoslib_gyp:
1551    o['variables']['static_zoslib_gyp'] = options.static_zoslib_gyp
1552  if flavor != 'linux' and options.v8_enable_hugepage:
1553    raise Exception('--v8-enable-hugepage is supported only on linux.')
1554  o['variables']['v8_enable_hugepage'] = 1 if options.v8_enable_hugepage else 0
1555  if options.v8_enable_short_builtin_calls or o['variables']['target_arch'] == 'x64':
1556    o['variables']['v8_enable_short_builtin_calls'] = 1
1557  if options.v8_enable_snapshot_compression:
1558    o['variables']['v8_enable_snapshot_compression'] = 1
1559  if options.v8_enable_object_print and options.v8_disable_object_print:
1560    raise Exception(
1561        'Only one of the --v8-enable-object-print or --v8-disable-object-print options '
1562        'can be specified at a time.')
1563
1564def configure_openssl(o):
1565  variables = o['variables']
1566  variables['node_use_openssl'] = b(not options.without_ssl)
1567  variables['node_shared_openssl'] = b(options.shared_openssl)
1568  variables['node_shared_ngtcp2'] = b(options.shared_ngtcp2)
1569  variables['node_shared_nghttp3'] = b(options.shared_nghttp3)
1570  variables['openssl_is_fips'] = b(options.openssl_is_fips)
1571  variables['node_fipsinstall'] = b(False)
1572
1573  if options.openssl_no_asm:
1574    variables['openssl_no_asm'] = 1
1575
1576  o['defines'] += ['NODE_OPENSSL_CONF_NAME=' + options.openssl_conf_name]
1577
1578  if options.without_ssl:
1579    def without_ssl_error(option):
1580      error(f'--without-ssl is incompatible with {option}')
1581    if options.shared_openssl:
1582      without_ssl_error('--shared-openssl')
1583    if options.openssl_no_asm:
1584      without_ssl_error('--openssl-no-asm')
1585    if options.openssl_is_fips:
1586      without_ssl_error('--openssl-is-fips')
1587    if options.openssl_default_cipher_list:
1588      without_ssl_error('--openssl-default-cipher-list')
1589    return
1590
1591  if options.use_openssl_ca_store:
1592    o['defines'] += ['NODE_OPENSSL_CERT_STORE']
1593  if options.openssl_system_ca_path:
1594    variables['openssl_system_ca_path'] = options.openssl_system_ca_path
1595  variables['node_without_node_options'] = b(options.without_node_options)
1596  if options.without_node_options:
1597      o['defines'] += ['NODE_WITHOUT_NODE_OPTIONS']
1598  if options.openssl_default_cipher_list:
1599    variables['openssl_default_cipher_list'] = \
1600            options.openssl_default_cipher_list
1601
1602  if not options.shared_openssl and not options.openssl_no_asm:
1603    is_x86 = 'x64' in variables['target_arch'] or 'ia32' in variables['target_arch']
1604
1605    # supported asm compiler for AVX2. See https://github.com/openssl/openssl/
1606    # blob/OpenSSL_1_1_0-stable/crypto/modes/asm/aesni-gcm-x86_64.pl#L52-L69
1607    openssl110_asm_supported = \
1608      ('gas_version' in variables and StrictVersion(variables['gas_version']) >= StrictVersion('2.23')) or \
1609      ('xcode_version' in variables and StrictVersion(variables['xcode_version']) >= StrictVersion('5.0')) or \
1610      ('llvm_version' in variables and StrictVersion(variables['llvm_version']) >= StrictVersion('3.3')) or \
1611      ('nasm_version' in variables and StrictVersion(variables['nasm_version']) >= StrictVersion('2.10'))
1612
1613    if is_x86 and not openssl110_asm_supported:
1614      error('''Did not find a new enough assembler, install one or build with
1615       --openssl-no-asm.
1616       Please refer to BUILDING.md''')
1617
1618  elif options.openssl_no_asm:
1619    warn('''--openssl-no-asm will result in binaries that do not take advantage
1620         of modern CPU cryptographic instructions and will therefore be slower.
1621         Please refer to BUILDING.md''')
1622
1623  if options.openssl_no_asm and options.shared_openssl:
1624    error('--openssl-no-asm is incompatible with --shared-openssl')
1625
1626  if options.openssl_is_fips:
1627    o['defines'] += ['OPENSSL_FIPS']
1628
1629  if options.openssl_is_fips and not options.shared_openssl:
1630    variables['node_fipsinstall'] = b(True)
1631
1632  if options.shared_openssl:
1633    has_quic = getsharedopensslhasquic.get_has_quic(options.__dict__['shared_openssl_includes'])
1634  else:
1635    has_quic = getsharedopensslhasquic.get_has_quic('deps/openssl/openssl/include')
1636
1637  variables['openssl_quic'] = b(has_quic)
1638  if has_quic:
1639    o['defines'] += ['NODE_OPENSSL_HAS_QUIC']
1640
1641  configure_library('openssl', o)
1642
1643
1644def configure_static(o):
1645  if options.fully_static or options.partly_static:
1646    if flavor == 'mac':
1647      warn("Generation of static executable will not work on OSX "
1648            "when using the default compilation environment")
1649      return
1650
1651    if options.fully_static:
1652      o['libraries'] += ['-static']
1653    elif options.partly_static:
1654      o['libraries'] += ['-static-libgcc', '-static-libstdc++']
1655      if options.enable_asan:
1656        o['libraries'] += ['-static-libasan']
1657
1658
1659def write(filename, data):
1660  print_verbose(f'creating {filename}')
1661  with Path(filename).open(mode='w+', encoding='utf-8') as f:
1662    f.write(data)
1663
1664do_not_edit = '# Do not edit. Generated by the configure script.\n'
1665
1666def glob_to_var(dir_base, dir_sub, patch_dir):
1667  file_list = []
1668  dir_all = f'{dir_base}/{dir_sub}'
1669  files = os.walk(dir_all)
1670  for ent in files:
1671    (_, _1, files) = ent
1672    for file in files:
1673      if file.endswith(('.cpp', '.c', '.h')):
1674        # srcfile uses "slash" as dir separator as its output is consumed by gyp
1675        srcfile = f'{dir_sub}/{file}'
1676        if patch_dir:
1677          patchfile = Path(dir_base, patch_dir, file)
1678          if patchfile.is_file():
1679            srcfile = f'{patch_dir}/{file}'
1680            info(f'Using floating patch "{patchfile}" from "{dir_base}"')
1681        file_list.append(srcfile)
1682    break
1683  return file_list
1684
1685def configure_intl(o):
1686  def icu_download(path):
1687    depFile = tools_path / 'icu' / 'current_ver.dep'
1688    icus = json.loads(depFile.read_text(encoding='utf-8'))
1689    # download ICU, if needed
1690    if not os.access(options.download_path, os.W_OK):
1691      error('''Cannot write to desired download path.
1692        Either create it or verify permissions.''')
1693    attemptdownload = nodedownload.candownload(auto_downloads, "icu")
1694    for icu in icus:
1695      url = icu['url']
1696      (expectHash, hashAlgo, allAlgos) = nodedownload.findHash(icu)
1697      if not expectHash:
1698        error(f'''Could not find a hash to verify ICU download.
1699          {depFile} may be incorrect.
1700          For the entry {url},
1701          Expected one of these keys: {' '.join(allAlgos)}''')
1702      local = url.split('/')[-1]
1703      targetfile = Path(options.download_path, local)
1704      if not targetfile.is_file():
1705        if attemptdownload:
1706          nodedownload.retrievefile(url, targetfile)
1707      else:
1708        print(f'Re-using existing {targetfile}')
1709      if targetfile.is_file():
1710        print(f'Checking file integrity with {hashAlgo}:\r')
1711        gotHash = nodedownload.checkHash(targetfile, hashAlgo)
1712        print(f'{hashAlgo}:      {gotHash}  {targetfile}')
1713        if expectHash == gotHash:
1714          return targetfile
1715
1716        warn(f'Expected: {expectHash}      *MISMATCH*')
1717        warn(f'\n ** Corrupted ZIP? Delete {targetfile} to retry download.\n')
1718    return None
1719  icu_config = {
1720    'variables': {}
1721  }
1722  icu_config_name = 'icu_config.gypi'
1723
1724  # write an empty file to start with
1725  write(icu_config_name, do_not_edit +
1726        pprint.pformat(icu_config, indent=2, width=1024) + '\n')
1727
1728  # always set icu_small, node.gyp depends on it being defined.
1729  o['variables']['icu_small'] = b(False)
1730
1731  # prevent data override
1732  o['defines'] += ['ICU_NO_USER_DATA_OVERRIDE']
1733
1734  with_intl = options.with_intl
1735  with_icu_source = options.with_icu_source
1736  have_icu_path = bool(options.with_icu_path)
1737  if have_icu_path and with_intl != 'none':
1738    error('Cannot specify both --with-icu-path and --with-intl')
1739  elif have_icu_path:
1740    # Chromium .gyp mode: --with-icu-path
1741    o['variables']['v8_enable_i18n_support'] = 1
1742    # use the .gyp given
1743    o['variables']['icu_gyp_path'] = options.with_icu_path
1744    return
1745
1746  # --with-intl=<with_intl>
1747  # set the default
1748  if with_intl in (None, 'none'):
1749    o['variables']['v8_enable_i18n_support'] = 0
1750    return  # no Intl
1751
1752  if with_intl == 'small-icu':
1753    # small ICU (English only)
1754    o['variables']['v8_enable_i18n_support'] = 1
1755    o['variables']['icu_small'] = b(True)
1756    locs = set(options.with_icu_locales.split(','))
1757    locs.add('root')  # must have root
1758    o['variables']['icu_locales'] = ','.join(str(loc) for loc in sorted(locs))
1759    # We will check a bit later if we can use the canned deps/icu-small
1760    o['variables']['icu_default_data'] = options.with_icu_default_data_dir or ''
1761  elif with_intl == 'full-icu':
1762    # full ICU
1763    o['variables']['v8_enable_i18n_support'] = 1
1764  elif with_intl == 'system-icu':
1765    # ICU from pkg-config.
1766    o['variables']['v8_enable_i18n_support'] = 1
1767    pkgicu = pkg_config('icu-i18n')
1768    if not pkgicu[0]:
1769      error('''Could not load pkg-config data for "icu-i18n".
1770       See above errors or the README.md.''')
1771    (libs, cflags, libpath, icuversion) = pkgicu
1772    icu_ver_major = icuversion.split('.')[0]
1773    o['variables']['icu_ver_major'] = icu_ver_major
1774    if int(icu_ver_major) < icu_versions['minimum_icu']:
1775      error(f"icu4c v{icuversion} is too old, v{icu_versions['minimum_icu']}.x or later is required.")
1776    # libpath provides linker path which may contain spaces
1777    if libpath:
1778      o['libraries'] += [libpath]
1779    # safe to split, cannot contain spaces
1780    o['libraries'] += libs.split()
1781    if cflags:
1782      stripped_flags = [flag.strip() for flag in cflags.split('-I')]
1783      o['include_dirs'] += [flag for flag in stripped_flags if flag]
1784    # use the "system" .gyp
1785    o['variables']['icu_gyp_path'] = 'tools/icu/icu-system.gyp'
1786    return
1787
1788  # this is just the 'deps' dir. Used for unpacking.
1789  icu_parent_path = 'deps'
1790
1791  # The full path to the ICU source directory. Should not include './'.
1792  icu_deps_path = 'deps/icu'
1793  icu_full_path = icu_deps_path
1794
1795  # icu-tmp is used to download and unpack the ICU tarball.
1796  icu_tmp_path = Path(icu_parent_path, 'icu-tmp')
1797
1798  # canned ICU. see tools/icu/README.md to update.
1799  canned_icu_dir = 'deps/icu-small'
1800
1801  # use the README to verify what the canned ICU is
1802  canned_icu_path = Path(canned_icu_dir)
1803  canned_is_full = (canned_icu_path / 'README-FULL-ICU.txt').is_file()
1804  canned_is_small = (canned_icu_path / 'README-SMALL-ICU.txt').is_file()
1805  if canned_is_small:
1806    warn(f'Ignoring {canned_icu_dir} - in-repo small icu is no longer supported.')
1807
1808  # We can use 'deps/icu-small' - pre-canned ICU *iff*
1809  # - canned_is_full AND
1810  # - with_icu_source is unset (i.e. no other ICU was specified)
1811  #
1812  # This is *roughly* equivalent to
1813  # $ configure --with-intl=full-icu --with-icu-source=deps/icu-small
1814  # .. Except that we avoid copying icu-small over to deps/icu.
1815  # In this default case, deps/icu is ignored, although make clean will
1816  # still harmlessly remove deps/icu.
1817
1818  if (not with_icu_source) and canned_is_full:
1819    # OK- we can use the canned ICU.
1820    icu_full_path = canned_icu_dir
1821    icu_config['variables']['icu_full_canned'] = 1
1822  # --with-icu-source processing
1823  # now, check that they didn't pass --with-icu-source=deps/icu
1824  elif with_icu_source and Path(icu_full_path).resolve() == Path(with_icu_source).resolve():
1825    warn(f'Ignoring redundant --with-icu-source={with_icu_source}')
1826    with_icu_source = None
1827  # if with_icu_source is still set, try to use it.
1828  if with_icu_source:
1829    if Path(icu_full_path).is_dir():
1830      print(f'Deleting old ICU source: {icu_full_path}')
1831      shutil.rmtree(icu_full_path)
1832    # now, what path was given?
1833    if Path(with_icu_source).is_dir():
1834      # it's a path. Copy it.
1835      print(f'{with_icu_source} -> {icu_full_path}')
1836      shutil.copytree(with_icu_source, icu_full_path)
1837    else:
1838      # could be file or URL.
1839      # Set up temporary area
1840      if Path(icu_tmp_path).is_dir():
1841        shutil.rmtree(icu_tmp_path)
1842      icu_tmp_path.mkdir()
1843      icu_tarball = None
1844      if Path(with_icu_source).is_file():
1845        # it's a file. Try to unpack it.
1846        icu_tarball = with_icu_source
1847      else:
1848        # Can we download it?
1849        local = icu_tmp_path / with_icu_source.split('/')[-1]  # local part
1850        icu_tarball = nodedownload.retrievefile(with_icu_source, local)
1851      # continue with "icu_tarball"
1852      nodedownload.unpack(icu_tarball, icu_tmp_path)
1853      # Did it unpack correctly? Should contain 'icu'
1854      tmp_icu = icu_tmp_path / 'icu'
1855      if tmp_icu.is_dir():
1856        tmp_icu.rename(icu_full_path)
1857        shutil.rmtree(icu_tmp_path)
1858      else:
1859        shutil.rmtree(icu_tmp_path)
1860        error(f'--with-icu-source={with_icu_source} did not result in an "icu" dir.')
1861
1862  # ICU mode. (icu-generic.gyp)
1863  o['variables']['icu_gyp_path'] = 'tools/icu/icu-generic.gyp'
1864  # ICU source dir relative to tools/icu (for .gyp file)
1865  o['variables']['icu_path'] = icu_full_path
1866  if not Path(icu_full_path).is_dir():
1867    # can we download (or find) a zipfile?
1868    localzip = icu_download(icu_full_path)
1869    if localzip:
1870      nodedownload.unpack(localzip, icu_parent_path)
1871    else:
1872      warn(f"* ECMA-402 (Intl) support didn't find ICU in {icu_full_path}..")
1873  if not Path(icu_full_path).is_dir():
1874    error(f'''Cannot build Intl without ICU in {icu_full_path}.
1875       Fix, or disable with "--with-intl=none"''')
1876  else:
1877    print_verbose(f'* Using ICU in {icu_full_path}')
1878  # Now, what version of ICU is it? We just need the "major", such as 54.
1879  # uvernum.h contains it as a #define.
1880  uvernum_h = Path(icu_full_path, 'source', 'common', 'unicode', 'uvernum.h')
1881  if not uvernum_h.is_file():
1882    error(f'Could not load {uvernum_h} - is ICU installed?')
1883  icu_ver_major = None
1884  matchVerExp = r'^\s*#define\s+U_ICU_VERSION_SHORT\s+"([^"]*)".*'
1885  match_version = re.compile(matchVerExp)
1886  with io.open(uvernum_h, encoding='utf8') as in_file:
1887    for line in in_file:
1888      m = match_version.match(line)
1889      if m:
1890        icu_ver_major = str(m.group(1))
1891  if not icu_ver_major:
1892    error(f'Could not read U_ICU_VERSION_SHORT version from {uvernum_h}')
1893  elif int(icu_ver_major) < icu_versions['minimum_icu']:
1894    error(f"icu4c v{icu_ver_major}.x is too old, v{icu_versions['minimum_icu']}.x or later is required.")
1895  icu_endianness = sys.byteorder[0]
1896  o['variables']['icu_ver_major'] = icu_ver_major
1897  o['variables']['icu_endianness'] = icu_endianness
1898  icu_data_file_l = f'icudt{icu_ver_major}l.dat' # LE filename
1899  icu_data_file = f'icudt{icu_ver_major}{icu_endianness}.dat'
1900  # relative to configure
1901  icu_data_path = Path(icu_full_path, 'source', 'data', 'in', icu_data_file_l) # LE
1902  compressed_data = f'{icu_data_path}.bz2'
1903  if not icu_data_path.is_file() and Path(compressed_data).is_file():
1904    # unpack. deps/icu is a temporary path
1905    if icu_tmp_path.is_dir():
1906      shutil.rmtree(icu_tmp_path)
1907    icu_tmp_path.mkdir()
1908    icu_data_path = icu_tmp_path / icu_data_file_l
1909    with icu_data_path.open(mode='wb') as outf:
1910        inf = bz2.BZ2File(compressed_data, 'rb')
1911        try:
1912          shutil.copyfileobj(inf, outf)
1913        finally:
1914          inf.close()
1915    # Now, proceed..
1916
1917  # relative to dep..
1918  icu_data_in = Path('..', '..', icu_data_path)
1919  if not icu_data_path.is_file() and icu_endianness != 'l':
1920    # use host endianness
1921    icu_data_path = Path(icu_full_path, 'source', 'data', 'in', icu_data_file) # will be generated
1922  if not icu_data_path.is_file():
1923    # .. and we're not about to build it from .gyp!
1924    error(f'''ICU prebuilt data file {icu_data_path} does not exist.
1925       See the README.md.''')
1926
1927  # this is the input '.dat' file to use .. icudt*.dat
1928  # may be little-endian if from a icu-project.org tarball
1929  o['variables']['icu_data_in'] = str(icu_data_in)
1930
1931  # map from variable name to subdirs
1932  icu_src = {
1933    'stubdata': 'stubdata',
1934    'common': 'common',
1935    'i18n': 'i18n',
1936    'tools': 'tools/toolutil',
1937    'genccode': 'tools/genccode',
1938    'genrb': 'tools/genrb',
1939    'icupkg': 'tools/icupkg',
1940  }
1941  # this creates a variable icu_src_XXX for each of the subdirs
1942  # with a list of the src files to use
1943  for key, value in icu_src.items():
1944    var  = f'icu_src_{key}'
1945    path = f'../../{icu_full_path}/source/{value}'
1946    icu_config['variables'][var] = glob_to_var('tools/icu', path, f'patches/{icu_ver_major}/source/{value}')
1947  # calculate platform-specific genccode args
1948  # print("platform %s, flavor %s" % (sys.platform, flavor))
1949  # if sys.platform == 'darwin':
1950  #   shlib_suffix = '%s.dylib'
1951  # elif sys.platform.startswith('aix'):
1952  #   shlib_suffix = '%s.a'
1953  # else:
1954  #   shlib_suffix = 'so.%s'
1955  if flavor == 'win':
1956    icu_config['variables']['icu_asm_ext'] = 'obj'
1957    icu_config['variables']['icu_asm_opts'] = [ '-o ' ]
1958  elif with_intl == 'small-icu' or options.cross_compiling:
1959    icu_config['variables']['icu_asm_ext'] = 'c'
1960    icu_config['variables']['icu_asm_opts'] = []
1961  elif flavor == 'mac':
1962    icu_config['variables']['icu_asm_ext'] = 'S'
1963    icu_config['variables']['icu_asm_opts'] = [ '-a', 'gcc-darwin' ]
1964  elif sys.platform == 'os400':
1965    icu_config['variables']['icu_asm_ext'] = 'S'
1966    icu_config['variables']['icu_asm_opts'] = [ '-a', 'xlc' ]
1967  elif sys.platform.startswith('aix'):
1968    icu_config['variables']['icu_asm_ext'] = 'S'
1969    icu_config['variables']['icu_asm_opts'] = [ '-a', 'xlc' ]
1970  elif sys.platform == 'zos':
1971    icu_config['variables']['icu_asm_ext'] = 'S'
1972    icu_config['variables']['icu_asm_opts'] = [ '-a', 'zos' ]
1973  else:
1974    # assume GCC-compatible asm is OK
1975    icu_config['variables']['icu_asm_ext'] = 'S'
1976    icu_config['variables']['icu_asm_opts'] = [ '-a', 'gcc' ]
1977
1978  # write updated icu_config.gypi with a bunch of paths
1979  write(icu_config_name, do_not_edit +
1980        pprint.pformat(icu_config, indent=2, width=1024) + '\n')
1981  return  # end of configure_intl
1982
1983def configure_inspector(o):
1984  disable_inspector = (options.without_inspector or
1985                       options.without_ssl)
1986  o['variables']['v8_enable_inspector'] = 0 if disable_inspector else 1
1987
1988def configure_section_file(o):
1989  try:
1990    proc = subprocess.Popen(['ld.gold'] + ['-v'], stdin = subprocess.PIPE,
1991                            stdout = subprocess.PIPE, stderr = subprocess.PIPE)
1992  except OSError:
1993    if options.node_section_ordering_info != "":
1994      warn('''No acceptable ld.gold linker found!''')
1995    return 0
1996
1997  with proc:
1998    match = re.match(r"^GNU gold.*([0-9]+)\.([0-9]+)$",
1999                     proc.communicate()[0].decode("utf-8"))
2000
2001  if match:
2002    gold_major_version = match.group(1)
2003    gold_minor_version = match.group(2)
2004    if int(gold_major_version) == 1 and int(gold_minor_version) <= 1:
2005      error('''GNU gold version must be greater than 1.2 in order to use section
2006            reordering''')
2007
2008  if options.node_section_ordering_info != "":
2009    o['variables']['node_section_ordering_info'] = os.path.realpath(
2010      str(options.node_section_ordering_info))
2011  else:
2012    o['variables']['node_section_ordering_info'] = ""
2013
2014def make_bin_override():
2015  if sys.platform == 'win32':
2016    raise Exception('make_bin_override should not be called on win32.')
2017  # If the system python is not the python we are running (which should be
2018  # python 3), then create a directory with a symlink called `python` to our
2019  # sys.executable. This directory will be prefixed to the PATH, so that
2020  # other tools that shell out to `python` will use the appropriate python
2021
2022  which_python = shutil.which('python')
2023  if (which_python and
2024      os.path.realpath(which_python) == os.path.realpath(sys.executable)):
2025    return
2026
2027  bin_override = Path('out', 'tools', 'bin').resolve()
2028  try:
2029    bin_override.mkdir(parents=True)
2030  except OSError as e:
2031    if e.errno != errno.EEXIST:
2032      raise e
2033
2034  python_link = bin_override / 'python'
2035  try:
2036    python_link.unlink()
2037  except OSError as e:
2038    if e.errno != errno.ENOENT:
2039      raise e
2040  os.symlink(sys.executable, python_link)
2041
2042  # We need to set the environment right now so that when gyp (in run_gyp)
2043  # shells out, it finds the right python (specifically at
2044  # https://github.com/nodejs/node/blob/d82e107/deps/v8/gypfiles/toolchain.gypi#L43)
2045  os.environ['PATH'] = str(bin_override) + ':' + os.environ['PATH']
2046
2047  return bin_override
2048
2049output = {
2050  'variables': {},
2051  'include_dirs': [],
2052  'libraries': [],
2053  'defines': [],
2054  'cflags': [],
2055}
2056
2057# Print a warning when the compiler is too old.
2058check_compiler(output)
2059
2060# determine the "flavor" (operating system) we're building for,
2061# leveraging gyp's GetFlavor function
2062flavor_params = {}
2063if options.dest_os:
2064  flavor_params['flavor'] = options.dest_os
2065flavor = GetFlavor(flavor_params)
2066
2067configure_node(output)
2068configure_node_lib_files(output)
2069configure_napi(output)
2070configure_library('zlib', output)
2071configure_library('http_parser', output)
2072configure_library('libuv', output)
2073configure_library('brotli', output, pkgname=['libbrotlidec', 'libbrotlienc'])
2074configure_library('cares', output, pkgname='libcares')
2075configure_library('nghttp2', output, pkgname='libnghttp2')
2076configure_library('nghttp3', output, pkgname='libnghttp3')
2077configure_library('ngtcp2', output, pkgname='libngtcp2')
2078configure_v8(output)
2079configure_openssl(output)
2080configure_intl(output)
2081configure_static(output)
2082configure_inspector(output)
2083configure_section_file(output)
2084
2085# configure shareable builtins
2086output['variables']['node_builtin_shareable_builtins'] = []
2087for builtin, value in shareable_builtins.items():
2088  builtin_id = 'node_shared_builtin_' + builtin.replace('/', '_') + '_path'
2089  if getattr(options, builtin_id):
2090    output['defines'] += [builtin_id.upper() + '=' + getattr(options, builtin_id)]
2091  else:
2092    output['variables']['node_builtin_shareable_builtins'] += [value]
2093
2094# Forward OSS-Fuzz settings
2095output['variables']['ossfuzz'] = b(options.ossfuzz)
2096
2097# variables should be a root level element,
2098# move everything else to target_defaults
2099variables = output['variables']
2100del output['variables']
2101variables['is_debug'] = B(options.debug)
2102
2103# make_global_settings should be a root level element too
2104if 'make_global_settings' in output:
2105  make_global_settings = output['make_global_settings']
2106  del output['make_global_settings']
2107else:
2108  make_global_settings = False
2109
2110output = {
2111  'variables': variables,
2112  'target_defaults': output,
2113}
2114if make_global_settings:
2115  output['make_global_settings'] = make_global_settings
2116
2117print_verbose(output)
2118
2119write('config.gypi', do_not_edit +
2120      pprint.pformat(output, indent=2, width=1024) + '\n')
2121
2122write('config.status', '#!/bin/sh\nset -x\nexec ./configure ' +
2123      ' '.join([shlex.quote(arg) for arg in original_argv]) + '\n')
2124Path('config.status').chmod(0o775)
2125
2126
2127config = {
2128  'BUILDTYPE': 'Debug' if options.debug else 'Release',
2129  'NODE_TARGET_TYPE': variables['node_target_type'],
2130}
2131
2132# Not needed for trivial case. Useless when it's a win32 path.
2133if sys.executable != 'python' and ':\\' not in sys.executable:
2134  config['PYTHON'] = sys.executable
2135
2136if options.prefix:
2137  config['PREFIX'] = options.prefix
2138
2139if options.use_ninja:
2140  config['BUILD_WITH'] = 'ninja'
2141
2142# On Windows there is another find.exe in C:\Windows\System32
2143if sys.platform == 'win32':
2144  config['FIND'] = '/usr/bin/find'
2145
2146config_lines = ['='.join((k,v)) for k,v in config.items()]
2147# Add a blank string to get a blank line at the end.
2148config_lines += ['']
2149config_str = '\n'.join(config_lines)
2150
2151# On Windows there's no reason to search for a different python binary.
2152bin_override = None if sys.platform == 'win32' else make_bin_override()
2153if bin_override:
2154  config_str = 'export PATH:=' + str(bin_override) + ':$(PATH)\n' + config_str
2155
2156write('config.mk', do_not_edit + config_str)
2157
2158
2159
2160gyp_args = ['--no-parallel', '-Dconfiguring_node=1']
2161gyp_args += ['-Dbuild_type=' + config['BUILDTYPE']]
2162
2163if options.use_ninja:
2164  gyp_args += ['-f', 'ninja-' + flavor]
2165elif flavor == 'win' and sys.platform != 'msys':
2166  gyp_args += ['-f', 'msvs', '-G', 'msvs_version=auto']
2167else:
2168  gyp_args += ['-f', 'make-' + flavor]
2169
2170if options.compile_commands_json:
2171  gyp_args += ['-f', 'compile_commands_json']
2172  os.path.islink('./compile_commands.json') and os.unlink('./compile_commands.json')
2173  os.symlink('./out/' + config['BUILDTYPE'] + '/compile_commands.json', './compile_commands.json')
2174
2175# override the variable `python` defined in common.gypi
2176if bin_override is not None:
2177  gyp_args += ['-Dpython=' + sys.executable]
2178
2179# pass the leftover non-whitespace positional arguments to GYP
2180gyp_args += [arg for arg in args if not str.isspace(arg)]
2181
2182if warn.warned and not options.verbose:
2183  warn('warnings were emitted in the configure phase')
2184
2185print_verbose("running: \n    " + " ".join(['python', 'tools/gyp_node.py'] + gyp_args))
2186run_gyp(gyp_args)
2187info('configure completed successfully')
2188