build: do not rely on gn_helpers in GN build

PR-URL: https://github.com/nodejs/node/pull/51439
Reviewed-By: Yagiz Nizipli <yagiz.nizipli@sentry.io>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
This commit is contained in:
Cheng Zhao
2024-01-12 08:46:57 +09:00
parent b1468d21ee
commit f04abdbe3d
2 changed files with 110 additions and 20 deletions

View File

@@ -2,7 +2,7 @@
# building official binaries.
# Please edit the gyp files if you are making changes to build system.
import("//node/node.gni")
import("../../node.gni")
# The actual configurations are put inside a template in unofficial.gni to
# prevent accidental edits from contributors.

View File

@@ -102,29 +102,119 @@ the input will be replaced with "bar":
from __future__ import absolute_import
from __future__ import print_function
from optparse import OptionParser
import os
import sys
# Look for standalone GN distribution.
def FindGNPath():
for i in os.environ['PATH'].split(os.pathsep):
if i.rstrip(os.sep).endswith('gn'):
return i
return None
# This function is copied from build/gn_helpers.py in Chromium.
def ToGNString(value, pretty=False):
"""Returns a stringified GN equivalent of a Python value.
Args:
value: The Python value to convert.
pretty: Whether to pretty print. If true, then non-empty lists are rendered
recursively with one item per line, with indents. Otherwise lists are
rendered without new line.
Returns:
The stringified GN equivalent to |value|.
Raises:
ValueError: |value| cannot be printed to GN.
"""
# Emits all output tokens without intervening whitespaces.
def GenerateTokens(v, level):
if isinstance(v, str):
yield '"' + ''.join(TranslateToGnChars(v)) + '"'
elif isinstance(v, bool):
yield 'true' if v else 'false'
elif isinstance(v, int):
yield str(v)
elif isinstance(v, list):
yield '['
for i, item in enumerate(v):
if i > 0:
yield ','
for tok in GenerateTokens(item, level + 1):
yield tok
yield ']'
elif isinstance(v, dict):
if level > 0:
yield '{'
for key in sorted(v):
if not isinstance(key, str):
raise ValueError('Dictionary key is not a string.')
if not key or key[0].isdigit() or not key.replace('_', '').isalnum():
raise ValueError('Dictionary key is not a valid GN identifier.')
yield key # No quotations.
yield '='
for tok in GenerateTokens(v[key], level + 1):
yield tok
if level > 0:
yield '}'
else: # Not supporting float: Add only when needed.
raise ValueError('Unsupported type when printing to GN.')
can_start = lambda tok: tok and tok not in ',}]='
can_end = lambda tok: tok and tok not in ',{[='
# Adds whitespaces, trying to keep everything (except dicts) in 1 line.
def PlainGlue(gen):
prev_tok = None
for i, tok in enumerate(gen):
if i > 0:
if can_end(prev_tok) and can_start(tok):
yield '\n' # New dict item.
elif prev_tok == '[' and tok == ']':
yield ' ' # Special case for [].
elif tok != ',':
yield ' '
yield tok
prev_tok = tok
# Adds whitespaces so non-empty lists can span multiple lines, with indent.
def PrettyGlue(gen):
prev_tok = None
level = 0
for i, tok in enumerate(gen):
if i > 0:
if can_end(prev_tok) and can_start(tok):
yield '\n' + ' ' * level # New dict item.
elif tok == '=' or prev_tok in '=':
yield ' ' # Separator before and after '=', on same line.
if tok in ']}':
level -= 1
# Exclude '[]' and '{}' cases.
if int(prev_tok == '[') + int(tok == ']') == 1 or \
int(prev_tok == '{') + int(tok == '}') == 1:
yield '\n' + ' ' * level
yield tok
if tok in '[{':
level += 1
if tok == ',':
yield '\n' + ' ' * level
prev_tok = tok
token_gen = GenerateTokens(value, 0)
ret = ''.join((PrettyGlue if pretty else PlainGlue)(token_gen))
# Add terminating '\n' for dict |value| or multi-line output.
if isinstance(value, dict) or '\n' in ret:
return ret + '\n'
return ret
try:
# May already be in the import path.
import gn_helpers
except ImportError:
# Add src/build to import path.
src_dir = os.path.abspath(os.path.join(os.path.dirname(__file__),
os.pardir, os.pardir))
sys.path.append(os.path.join(src_dir, 'build'))
if FindGNPath():
sys.path.append(os.path.join(FindGNPath(), 'build'))
import gn_helpers
def TranslateToGnChars(s):
for code in s.encode('utf-8'):
if code in (34, 36, 92): # For '"', '$', or '\\'.
yield '\\' + chr(code)
elif 32 <= code < 127:
yield chr(code)
else:
yield '$0x%02X' % code
def LoadPythonDictionary(path):
@@ -234,7 +324,7 @@ def main():
else:
gn_dict[gn_key] = data[key]
print(gn_helpers.ToGNString(DeduplicateLists(gn_dict)))
print(ToGNString(DeduplicateLists(gn_dict)))
if __name__ == '__main__':
try: