|
7 | 7 | # This script reads the configurations of GN and outputs a config.gypi file that
|
8 | 8 | # will be used to populate process.config.variables.
|
9 | 9 |
|
| 10 | +import argparse |
10 | 11 | import re
|
11 | 12 | import os
|
12 | 13 | import subprocess
|
13 | 14 | import sys
|
14 | 15 |
|
15 |
| -root_dir = os.path.dirname(os.path.dirname(__file__)) |
16 |
| -sys.path.append(os.path.join(root_dir, 'node', 'tools')) |
17 |
| -import getmoduleversion |
| 16 | +sys.path.append(os.path.dirname(__file__)) |
18 | 17 | import getnapibuildversion
|
19 | 18 |
|
| 19 | +# The defines bellow must include all things from the external_v8_defines list |
| 20 | +# in v8/BUILD.gn. |
| 21 | +# TODO(zcbenz): Import from v8_features.json once this change gets into Node: |
| 22 | +# https://chromium-review.googlesource.com/c/v8/v8/+/5040612 |
| 23 | +V8_FEATURE_DEFINES = { |
| 24 | + 'v8_enable_v8_checks': 'V8_ENABLE_CHECKS', |
| 25 | + 'v8_enable_pointer_compression': 'V8_COMPRESS_POINTERS', |
| 26 | + 'v8_enable_pointer_compression_shared_cage': 'V8_COMPRESS_POINTERS_IN_SHARED_CAGE', |
| 27 | + 'v8_enable_31bit_smis_on_64bit_arch': 'V8_31BIT_SMIS_ON_64BIT_ARCH', |
| 28 | + 'v8_enable_zone_compression': 'V8_COMPRESS_ZONES', |
| 29 | + 'v8_enable_sandbox': 'V8_ENABLE_SANDBOX', |
| 30 | + 'v8_deprecation_warnings': 'V8_DEPRECATION_WARNINGS', |
| 31 | + 'v8_imminent_deprecation_warnings': 'V8_IMMINENT_DEPRECATION_WARNINGS', |
| 32 | + 'v8_use_perfetto': 'V8_USE_PERFETTO', |
| 33 | + 'v8_enable_map_packing': 'V8_MAP_PACKING', |
| 34 | + 'tsan': 'V8_IS_TSAN', |
| 35 | + 'v8_enable_conservative_stack_scanning': 'V8_ENABLE_CONSERVATIVE_STACK_SCANNING', |
| 36 | + 'v8_enable_direct_local': 'V8_ENABLE_DIRECT_LOCAL', |
| 37 | +} |
| 38 | + |
| 39 | +# Regex used for parsing results of "gn args". |
20 | 40 | GN_RE = re.compile(r'(\w+)\s+=\s+(.*?)$', re.MULTILINE)
|
21 | 41 |
|
| 42 | +if sys.platform == 'win32': |
| 43 | + GN = 'gn.exe' |
| 44 | +else: |
| 45 | + GN = 'gn' |
| 46 | + |
| 47 | +def bool_to_number(v): |
| 48 | + return 1 if v else 0 |
| 49 | + |
22 | 50 | def bool_string_to_number(v):
|
23 |
| - return 1 if v == 'true' else 0 |
| 51 | + return bool_to_number(v == 'true') |
| 52 | + |
| 53 | +def get_gn_config(out_dir): |
| 54 | + # Read args from GN configurations. |
| 55 | + gn_args = subprocess.check_output( |
| 56 | + [GN, 'args', '--list', '--short', '-C', out_dir]) |
| 57 | + config = dict(re.findall(GN_RE, gn_args.decode())) |
| 58 | + # Get napi_build_version from Node, which is not part of GN args. |
| 59 | + config['napi_build_version'] = getnapibuildversion.get_napi_version() |
| 60 | + return config |
| 61 | + |
| 62 | +def get_v8_config(out_dir, node_gn_path): |
| 63 | + # For args that have default values in V8's GN configurations, we can not rely |
| 64 | + # on the values printed by "gn args", because most of them would be empty |
| 65 | + # strings, and the actual value would depend on the logics in v8/BUILD.gn. |
| 66 | + # So we print out the defines and deduce the feature from them instead. |
| 67 | + node_defines = subprocess.check_output( |
| 68 | + [GN, 'desc', '-C', out_dir, node_gn_path + ":libnode", 'defines']).decode().split('\n') |
| 69 | + v8_config = {} |
| 70 | + for feature, define in V8_FEATURE_DEFINES.items(): |
| 71 | + v8_config[feature] = bool_to_number(define in node_defines) |
| 72 | + return v8_config |
24 | 73 |
|
25 |
| -def translate_config(config): |
26 |
| - return { |
| 74 | +def translate_config(out_dir, config, v8_config): |
| 75 | + config_gypi = { |
27 | 76 | 'target_defaults': {
|
28 | 77 | 'default_configuration':
|
29 | 78 | 'Debug' if config['is_debug'] == 'true' else 'Release',
|
30 | 79 | },
|
31 | 80 | 'variables': {
|
32 | 81 | 'asan': bool_string_to_number(config['is_asan']),
|
| 82 | + 'enable_lto': config['use_thin_lto'], |
| 83 | + 'is_debug': bool_string_to_number(config['is_debug']), |
33 | 84 | 'llvm_version': 13,
|
34 | 85 | 'napi_build_version': config['napi_build_version'],
|
35 | 86 | 'node_builtin_shareable_builtins':
|
36 | 87 | eval(config['node_builtin_shareable_builtins']),
|
37 | 88 | 'node_module_version': int(config['node_module_version']),
|
38 |
| - 'node_shared': bool_string_to_number(config['is_component_build']), |
39 | 89 | 'node_use_openssl': config['node_use_openssl'],
|
40 | 90 | 'node_use_node_code_cache': config['node_use_node_code_cache'],
|
41 | 91 | 'node_use_node_snapshot': config['node_use_node_snapshot'],
|
42 |
| - 'v8_enable_31bit_smis_on_64bit_arch': |
43 |
| - bool_string_to_number(config['v8_enable_31bit_smis_on_64bit_arch']), |
44 |
| - 'v8_enable_pointer_compression': |
45 |
| - bool_string_to_number(config['v8_enable_pointer_compression']), |
46 | 92 | 'v8_enable_i18n_support':
|
47 | 93 | bool_string_to_number(config['v8_enable_i18n_support']),
|
48 | 94 | 'v8_enable_inspector': # this is actually a node misnomer
|
49 | 95 | bool_string_to_number(config['node_enable_inspector']),
|
50 | 96 | 'shlib_suffix': 'dylib' if sys.platform == 'darwin' else 'so',
|
| 97 | + 'tsan': bool_string_to_number(config['is_tsan']), |
| 98 | + # TODO(zcbenz): Shared components are not supported in GN config yet. |
| 99 | + 'node_shared': 'false', |
| 100 | + 'node_shared_brotli': 'false', |
| 101 | + 'node_shared_cares': 'false', |
| 102 | + 'node_shared_http_parser': 'false', |
| 103 | + 'node_shared_libuv': 'false', |
| 104 | + 'node_shared_nghttp2': 'false', |
| 105 | + 'node_shared_nghttp3': 'false', |
| 106 | + 'node_shared_ngtcp2': 'false', |
| 107 | + 'node_shared_openssl': 'false', |
| 108 | + 'node_shared_zlib': 'false', |
51 | 109 | }
|
52 | 110 | }
|
| 111 | + config_gypi['variables'].update(v8_config) |
| 112 | + return config_gypi |
53 | 113 |
|
54 |
| -def main(gn_out_dir, output_file, depfile): |
55 |
| - # Get GN config and parse into a dictionary. |
56 |
| - if sys.platform == 'win32': |
57 |
| - gn = 'gn.exe' |
58 |
| - else: |
59 |
| - gn = 'gn' |
60 |
| - gnconfig = subprocess.check_output( |
61 |
| - [gn, 'args', '--list', '--short', '-C', gn_out_dir]) |
62 |
| - config = dict(re.findall(GN_RE, gnconfig.decode('utf-8'))) |
63 |
| - config['node_module_version'] = getmoduleversion.get_version() |
64 |
| - config['napi_build_version'] = getnapibuildversion.get_napi_version() |
| 114 | +def main(): |
| 115 | + parser = argparse.ArgumentParser( |
| 116 | + description='Generate config.gypi file from GN configurations') |
| 117 | + parser.add_argument('target', help='path to generated config.gypi file') |
| 118 | + parser.add_argument('--out-dir', help='path to the output directory', |
| 119 | + default='out/Release') |
| 120 | + parser.add_argument('--node-gn-path', help='path of the node target in GN', |
| 121 | + default='//node') |
| 122 | + parser.add_argument('--dep-file', help='path to an optional dep file', |
| 123 | + default=None) |
| 124 | + args, unknown_args = parser.parse_known_args() |
| 125 | + |
| 126 | + config = get_gn_config(args.out_dir) |
| 127 | + v8_config = get_v8_config(args.out_dir, args.node_gn_path) |
65 | 128 |
|
66 | 129 | # Write output.
|
67 |
| - with open(output_file, 'w') as f: |
68 |
| - f.write(repr(translate_config(config))) |
| 130 | + with open(args.target, 'w') as f: |
| 131 | + f.write(repr(translate_config(args.out_dir, config, v8_config))) |
69 | 132 |
|
70 | 133 | # Write depfile. Force regenerating config.gypi when GN configs change.
|
71 |
| - with open(depfile, 'w') as f: |
72 |
| - f.write('%s: %s '%(output_file, 'build.ninja')) |
| 134 | + if args.dep_file: |
| 135 | + with open(args.dep_file, 'w') as f: |
| 136 | + f.write('%s: %s '%(args.target, 'build.ninja')) |
73 | 137 |
|
74 | 138 | if __name__ == '__main__':
|
75 |
| - main(sys.argv[1], sys.argv[2], sys.argv[3]) |
| 139 | + main() |
0 commit comments