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