roll ANGLE w/ GN update
ANGLE switched their .gypi files to .gni files this commit,
so we need to make a small tweak to update our ANGLE build.
This removes the last use of gypi_to_gn.py, and in turn gn_helpers.py.
CQ_INCLUDE_TRYBOTS=skia.primary:Build-Debian9-Clang-x86_64-Release-ANGLE;skia.primary:Perf-Win10-Clang-AlphaR2-GPU-RadeonR9M470X-x86_64-Debug-All-ANGLE;skia.primary:Perf-Win10-Clang-NUC5i7RYH-GPU-IntelIris6100-x86_64-Debug-All-ANGLE;skia.primary:Perf-Win10-Clang-NUC6i5SYK-GPU-IntelIris540-x86_64-Debug-All-ANGLE;skia.primary:Perf-Win10-Clang-NUCD34010WYKH-GPU-IntelHD4400-x86_64-Debug-All-ANGLE;skia.primary:Perf-Win10-Clang-ShuttleC-GPU-GTX960-x86_64-Debug-All-ANGLE;skia.primary:Test-Win10-Clang-AlphaR2-GPU-RadeonR9M470X-x86_64-Debug-All-ANGLE;skia.primary:Test-Win10-Clang-NUC6i5SYK-GPU-IntelIris540-x86_64-Debug-All-ANGLE;skia.primary:Test-Win10-Clang-NUCD34010WYKH-GPU-IntelHD4400-x86_64-Debug-All-ANGLE;skia.primary:Test-Win10-Clang-ShuttleC-GPU-GTX960-x86_64-Debug-All-ANGLE
Change-Id: I76c8a667e7c5c27dc4cd18ba0d932bfc2de38cf9
Reviewed-on: https://skia-review.googlesource.com/150541
Reviewed-by: Stephan Altmueller <stephana@google.com>
Commit-Queue: Mike Klein <mtklein@google.com>
diff --git a/DEPS b/DEPS
index 4d25609..e296b00 100644
--- a/DEPS
+++ b/DEPS
@@ -7,7 +7,7 @@
deps = {
"buildtools" : "https://chromium.googlesource.com/chromium/buildtools.git@505de88083136eefd056e5ee4ca0f01fe9b33de8",
"common" : "https://skia.googlesource.com/common.git@9737551d7a52c3db3262db5856e6bcd62c462b92",
- "third_party/externals/angle2" : "https://chromium.googlesource.com/angle/angle.git@1e1b731a98955fb4fe9cd5a17887e2abcdb283d5",
+ "third_party/externals/angle2" : "https://chromium.googlesource.com/angle/angle.git@ddc41208c15ffd9aae99e3ac6c9d59a09df914d9",
"third_party/externals/dng_sdk" : "https://android.googlesource.com/platform/external/dng_sdk.git@96443b262250c390b0caefbf3eed8463ba35ecae",
"third_party/externals/egl-registry" : "https://skia.googlesource.com/external/github.com/KhronosGroup/EGL-Registry@a0bca08de07c7d7651047bedc0b653cfaaa4f2ae",
"third_party/externals/expat" : "https://android.googlesource.com/platform/external/expat.git@android-6.0.1_r55",
diff --git a/gn/gn_helpers.py b/gn/gn_helpers.py
deleted file mode 100644
index fb94d54..0000000
--- a/gn/gn_helpers.py
+++ /dev/null
@@ -1,351 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Helper functions useful when writing scripts that integrate with GN.
-
-The main functions are ToGNString and FromGNString which convert between
-serialized GN veriables and Python variables.
-
-To use in a random python file in the build:
-
- import os
- import sys
-
- sys.path.append(os.path.join(os.path.dirname(__file__),
- os.pardir, os.pardir, "build"))
- import gn_helpers
-
-Where the sequence of parameters to join is the relative path from your source
-file to the build directory."""
-
-class GNException(Exception):
- pass
-
-
-def ToGNString(value, allow_dicts = True):
- """Returns a stringified GN equivalent of the Python value.
-
- allow_dicts indicates if this function will allow converting dictionaries
- to GN scopes. This is only possible at the top level, you can't nest a
- GN scope in a list, so this should be set to False for recursive calls."""
- if isinstance(value, basestring):
- if value.find('\n') >= 0:
- raise GNException("Trying to print a string with a newline in it.")
- return '"' + \
- value.replace('\\', '\\\\').replace('"', '\\"').replace('$', '\\$') + \
- '"'
-
- if isinstance(value, unicode):
- return ToGNString(value.encode('utf-8'))
-
- if isinstance(value, bool):
- if value:
- return "true"
- return "false"
-
- if isinstance(value, list):
- return '[ %s ]' % ', '.join(ToGNString(v) for v in value)
-
- if isinstance(value, dict):
- if not allow_dicts:
- raise GNException("Attempting to recursively print a dictionary.")
- result = ""
- for key in sorted(value):
- if not isinstance(key, basestring):
- raise GNException("Dictionary key is not a string.")
- result += "%s = %s\n" % (key, ToGNString(value[key], False))
- return result
-
- if isinstance(value, int):
- return str(value)
-
- raise GNException("Unsupported type when printing to GN.")
-
-
-def FromGNString(input_):
- """Converts the input string from a GN serialized value to Python values.
-
- For details on supported types see GNValueParser.Parse() below.
-
- If your GN script did:
- something = [ "file1", "file2" ]
- args = [ "--values=$something" ]
- The command line would look something like:
- --values="[ \"file1\", \"file2\" ]"
- Which when interpreted as a command line gives the value:
- [ "file1", "file2" ]
-
- You can parse this into a Python list using GN rules with:
- input_values = FromGNValues(options.values)
- Although the Python 'ast' module will parse many forms of such input, it
- will not handle GN escaping properly, nor GN booleans. You should use this
- function instead.
-
-
- A NOTE ON STRING HANDLING:
-
- If you just pass a string on the command line to your Python script, or use
- string interpolation on a string variable, the strings will not be quoted:
- str = "asdf"
- args = [ str, "--value=$str" ]
- Will yield the command line:
- asdf --value=asdf
- The unquoted asdf string will not be valid input to this function, which
- accepts only quoted strings like GN scripts. In such cases, you can just use
- the Python string literal directly.
-
- The main use cases for this is for other types, in particular lists. When
- using string interpolation on a list (as in the top example) the embedded
- strings will be quoted and escaped according to GN rules so the list can be
- re-parsed to get the same result."""
- parser = GNValueParser(input_)
- return parser.Parse()
-
-
-def FromGNArgs(input_):
- """Converts a string with a bunch of gn arg assignments into a Python dict.
-
- Given a whitespace-separated list of
-
- <ident> = (integer | string | boolean | <list of the former>)
-
- gn assignments, this returns a Python dict, i.e.:
-
- FromGNArgs("foo=true\nbar=1\n") -> { 'foo': True, 'bar': 1 }.
-
- Only simple types and lists supported; variables, structs, calls
- and other, more complicated things are not.
-
- This routine is meant to handle only the simple sorts of values that
- arise in parsing --args.
- """
- parser = GNValueParser(input_)
- return parser.ParseArgs()
-
-
-def UnescapeGNString(value):
- """Given a string with GN escaping, returns the unescaped string.
-
- Be careful not to feed with input from a Python parsing function like
- 'ast' because it will do Python unescaping, which will be incorrect when
- fed into the GN unescaper."""
- result = ''
- i = 0
- while i < len(value):
- if value[i] == '\\':
- if i < len(value) - 1:
- next_char = value[i + 1]
- if next_char in ('$', '"', '\\'):
- # These are the escaped characters GN supports.
- result += next_char
- i += 1
- else:
- # Any other backslash is a literal.
- result += '\\'
- else:
- result += value[i]
- i += 1
- return result
-
-
-def _IsDigitOrMinus(char):
- return char in "-0123456789"
-
-
-class GNValueParser(object):
- """Duplicates GN parsing of values and converts to Python types.
-
- Normally you would use the wrapper function FromGNValue() below.
-
- If you expect input as a specific type, you can also call one of the Parse*
- functions directly. All functions throw GNException on invalid input. """
- def __init__(self, string):
- self.input = string
- self.cur = 0
-
- def IsDone(self):
- return self.cur == len(self.input)
-
- def ConsumeWhitespace(self):
- while not self.IsDone() and self.input[self.cur] in ' \t\n':
- self.cur += 1
-
- def Parse(self):
- """Converts a string representing a printed GN value to the Python type.
-
- See additional usage notes on FromGNString above.
-
- - GN booleans ('true', 'false') will be converted to Python booleans.
-
- - GN numbers ('123') will be converted to Python numbers.
-
- - GN strings (double-quoted as in '"asdf"') will be converted to Python
- strings with GN escaping rules. GN string interpolation (embedded
- variables preceeded by $) are not supported and will be returned as
- literals.
-
- - GN lists ('[1, "asdf", 3]') will be converted to Python lists.
-
- - GN scopes ('{ ... }') are not supported."""
- result = self._ParseAllowTrailing()
- self.ConsumeWhitespace()
- if not self.IsDone():
- raise GNException("Trailing input after parsing:\n " +
- self.input[self.cur:])
- return result
-
- def ParseArgs(self):
- """Converts a whitespace-separated list of ident=literals to a dict.
-
- See additional usage notes on FromGNArgs, above.
- """
- d = {}
-
- self.ConsumeWhitespace()
- while not self.IsDone():
- ident = self._ParseIdent()
- self.ConsumeWhitespace()
- if self.input[self.cur] != '=':
- raise GNException("Unexpected token: " + self.input[self.cur:])
- self.cur += 1
- self.ConsumeWhitespace()
- val = self._ParseAllowTrailing()
- self.ConsumeWhitespace()
- d[ident] = val
-
- return d
-
- def _ParseAllowTrailing(self):
- """Internal version of Parse that doesn't check for trailing stuff."""
- self.ConsumeWhitespace()
- if self.IsDone():
- raise GNException("Expected input to parse.")
-
- next_char = self.input[self.cur]
- if next_char == '[':
- return self.ParseList()
- elif _IsDigitOrMinus(next_char):
- return self.ParseNumber()
- elif next_char == '"':
- return self.ParseString()
- elif self._ConstantFollows('true'):
- return True
- elif self._ConstantFollows('false'):
- return False
- else:
- raise GNException("Unexpected token: " + self.input[self.cur:])
-
- def _ParseIdent(self):
- id_ = ''
-
- next_char = self.input[self.cur]
- if not next_char.isalpha() and not next_char=='_':
- raise GNException("Expected an identifier: " + self.input[self.cur:])
-
- id_ += next_char
- self.cur += 1
-
- next_char = self.input[self.cur]
- while next_char.isalpha() or next_char.isdigit() or next_char=='_':
- id_ += next_char
- self.cur += 1
- next_char = self.input[self.cur]
-
- return id_
-
- def ParseNumber(self):
- self.ConsumeWhitespace()
- if self.IsDone():
- raise GNException('Expected number but got nothing.')
-
- begin = self.cur
-
- # The first character can include a negative sign.
- if not self.IsDone() and _IsDigitOrMinus(self.input[self.cur]):
- self.cur += 1
- while not self.IsDone() and self.input[self.cur].isdigit():
- self.cur += 1
-
- number_string = self.input[begin:self.cur]
- if not len(number_string) or number_string == '-':
- raise GNException("Not a valid number.")
- return int(number_string)
-
- def ParseString(self):
- self.ConsumeWhitespace()
- if self.IsDone():
- raise GNException('Expected string but got nothing.')
-
- if self.input[self.cur] != '"':
- raise GNException('Expected string beginning in a " but got:\n ' +
- self.input[self.cur:])
- self.cur += 1 # Skip over quote.
-
- begin = self.cur
- while not self.IsDone() and self.input[self.cur] != '"':
- if self.input[self.cur] == '\\':
- self.cur += 1 # Skip over the backslash.
- if self.IsDone():
- raise GNException("String ends in a backslash in:\n " +
- self.input)
- self.cur += 1
-
- if self.IsDone():
- raise GNException('Unterminated string:\n ' + self.input[begin:])
-
- end = self.cur
- self.cur += 1 # Consume trailing ".
-
- return UnescapeGNString(self.input[begin:end])
-
- def ParseList(self):
- self.ConsumeWhitespace()
- if self.IsDone():
- raise GNException('Expected list but got nothing.')
-
- # Skip over opening '['.
- if self.input[self.cur] != '[':
- raise GNException("Expected [ for list but got:\n " +
- self.input[self.cur:])
- self.cur += 1
- self.ConsumeWhitespace()
- if self.IsDone():
- raise GNException("Unterminated list:\n " + self.input)
-
- list_result = []
- previous_had_trailing_comma = True
- while not self.IsDone():
- if self.input[self.cur] == ']':
- self.cur += 1 # Skip over ']'.
- return list_result
-
- if not previous_had_trailing_comma:
- raise GNException("List items not separated by comma.")
-
- list_result += [ self._ParseAllowTrailing() ]
- self.ConsumeWhitespace()
- if self.IsDone():
- break
-
- # Consume comma if there is one.
- previous_had_trailing_comma = self.input[self.cur] == ','
- if previous_had_trailing_comma:
- # Consume comma.
- self.cur += 1
- self.ConsumeWhitespace()
-
- raise GNException("Unterminated list:\n " + self.input)
-
- def _ConstantFollows(self, constant):
- """Returns true if the given constant follows immediately at the current
- location in the input. If it does, the text is consumed and the function
- returns true. Otherwise, returns false and the current position is
- unchanged."""
- end = self.cur + len(constant)
- if end > len(self.input):
- return False # Not enough room.
- if self.input[self.cur:end] == constant:
- self.cur = end
- return True
- return False
diff --git a/gn/gypi_to_gn.py b/gn/gypi_to_gn.py
deleted file mode 100755
index c4f31ae..0000000
--- a/gn/gypi_to_gn.py
+++ /dev/null
@@ -1,193 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Converts a given gypi file to a python scope and writes the result to stdout.
-
-USING THIS SCRIPT IN CHROMIUM
-
-Forking Python to run this script in the middle of GN is slow, especially on
-Windows, and it makes both the GYP and GN files harder to follow. You can't
-use "git grep" to find files in the GN build any more, and tracking everything
-in GYP down requires a level of indirection. Any calls will have to be removed
-and cleaned up once the GYP-to-GN transition is complete.
-
-As a result, we only use this script when the list of files is large and
-frequently-changing. In these cases, having one canonical list outweights the
-downsides.
-
-As of this writing, the GN build is basically complete. It's likely that all
-large and frequently changing targets where this is appropriate use this
-mechanism already. And since we hope to turn down the GYP build soon, the time
-horizon is also relatively short. As a result, it is likely that no additional
-uses of this script should every be added to the build. During this later part
-of the transition period, we should be focusing more and more on the absolute
-readability of the GN build.
-
-
-HOW TO USE
-
-It is assumed that the file contains a toplevel dictionary, and this script
-will return that dictionary as a GN "scope" (see example below). This script
-does not know anything about GYP and it will not expand variables or execute
-conditions.
-
-It will strip conditions blocks.
-
-A variables block at the top level will be flattened so that the variables
-appear in the root dictionary. This way they can be returned to the GN code.
-
-Say your_file.gypi looked like this:
- {
- 'sources': [ 'a.cc', 'b.cc' ],
- 'defines': [ 'ENABLE_DOOM_MELON' ],
- }
-
-You would call it like this:
- gypi_values = exec_script("//build/gypi_to_gn.py",
- [ rebase_path("your_file.gypi") ],
- "scope",
- [ "your_file.gypi" ])
-
-Notes:
- - The rebase_path call converts the gypi file from being relative to the
- current build file to being system absolute for calling the script, which
- will have a different current directory than this file.
-
- - The "scope" parameter tells GN to interpret the result as a series of GN
- variable assignments.
-
- - The last file argument to exec_script tells GN that the given file is a
- dependency of the build so Ninja can automatically re-run GN if the file
- changes.
-
-Read the values into a target like this:
- component("mycomponent") {
- sources = gypi_values.sources
- defines = gypi_values.defines
- }
-
-Sometimes your .gypi file will include paths relative to a different
-directory than the current .gn file. In this case, you can rebase them to
-be relative to the current directory.
- sources = rebase_path(gypi_values.sources, ".",
- "//path/gypi/input/values/are/relative/to")
-
-This script will tolerate a 'variables' in the toplevel dictionary or not. If
-the toplevel dictionary just contains one item called 'variables', it will be
-collapsed away and the result will be the contents of that dictinoary. Some
-.gypi files are written with or without this, depending on how they expect to
-be embedded into a .gyp file.
-
-This script also has the ability to replace certain substrings in the input.
-Generally this is used to emulate GYP variable expansion. If you passed the
-argument "--replace=<(foo)=bar" then all instances of "<(foo)" in strings in
-the input will be replaced with "bar":
-
- gypi_values = exec_script("//build/gypi_to_gn.py",
- [ rebase_path("your_file.gypi"),
- "--replace=<(foo)=bar"],
- "scope",
- [ "your_file.gypi" ])
-
-"""
-
-import gn_helpers
-from optparse import OptionParser
-import sys
-
-def LoadPythonDictionary(path):
- file_string = open(path).read()
- try:
- file_data = eval(file_string, {'__builtins__': None}, None)
- except SyntaxError, e:
- e.filename = path
- raise
- except Exception, e:
- raise Exception("Unexpected error while reading %s: %s" % (path, str(e)))
-
- assert isinstance(file_data, dict), "%s does not eval to a dictionary" % path
-
- # Flatten any variables to the top level.
- if 'variables' in file_data:
- file_data.update(file_data['variables'])
- del file_data['variables']
-
- # Strip all elements that this script can't process.
- elements_to_strip = [
- 'conditions',
- 'target_conditions',
- 'targets',
- 'includes',
- 'actions',
- ]
- for element in elements_to_strip:
- if element in file_data:
- del file_data[element]
-
- return file_data
-
-
-def ReplaceSubstrings(values, search_for, replace_with):
- """Recursively replaces substrings in a value.
-
- Replaces all substrings of the "search_for" with "repace_with" for all
- strings occurring in "values". This is done by recursively iterating into
- lists as well as the keys and values of dictionaries."""
- if isinstance(values, str):
- return values.replace(search_for, replace_with)
-
- if isinstance(values, list):
- return [ReplaceSubstrings(v, search_for, replace_with) for v in values]
-
- if isinstance(values, dict):
- # For dictionaries, do the search for both the key and values.
- result = {}
- for key, value in values.items():
- new_key = ReplaceSubstrings(key, search_for, replace_with)
- new_value = ReplaceSubstrings(value, search_for, replace_with)
- result[new_key] = new_value
- return result
-
- # Assume everything else is unchanged.
- return values
-
-def main():
- parser = OptionParser()
- parser.add_option("-r", "--replace", action="append",
- help="Replaces substrings. If passed a=b, replaces all substrs a with b.")
- (options, args) = parser.parse_args()
-
- if len(args) != 1:
- raise Exception("Need one argument which is the .gypi file to read.")
-
- data = LoadPythonDictionary(args[0])
- if options.replace:
- # Do replacements for all specified patterns.
- for replace in options.replace:
- split = replace.split('=')
- # Allow "foo=" to replace with nothing.
- if len(split) == 1:
- split.append('')
- assert len(split) == 2, "Replacement must be of the form 'key=value'."
- data = ReplaceSubstrings(data, split[0], split[1])
-
- # Sometimes .gypi files use the GYP syntax with percents at the end of the
- # variable name (to indicate not to overwrite a previously-defined value):
- # 'foo%': 'bar',
- # Convert these to regular variables.
- for key in data:
- if len(key) > 1 and key[len(key) - 1] == '%':
- data[key[:-1]] = data[key]
- del data[key]
-
- print gn_helpers.ToGNString(data)
-
-if __name__ == '__main__':
- try:
- main()
- except Exception, e:
- print str(e)
- sys.exit(1)
diff --git a/third_party/angle2/BUILD.gn b/third_party/angle2/BUILD.gn
index d36626d..752cf0b 100644
--- a/third_party/angle2/BUILD.gn
+++ b/third_party/angle2/BUILD.gn
@@ -9,6 +9,8 @@
angle_root = "../externals/angle2"
import("../third_party.gni")
+import("$angle_root/src/compiler.gni")
+import("$angle_root/src/libGLESv2.gni")
third_party("angle2") {
public_include_dirs = [ "$angle_root/include" ]
@@ -18,16 +20,6 @@
]
}
-compiler_gypi = exec_script("//gn/gypi_to_gn.py",
- [ rebase_path("$angle_root/src/compiler.gypi") ],
- "scope",
- [])
-
-gles_gypi = exec_script("//gn/gypi_to_gn.py",
- [ rebase_path("$angle_root/src/libGLESv2.gypi") ],
- "scope",
- [])
-
config("common") {
defines = [
"ANGLE_ENABLE_ESSL",
@@ -93,14 +85,11 @@
]
libs = []
sources = rebase_path(
- compiler_gypi.angle_preprocessor_sources +
- compiler_gypi.angle_translator_sources +
- compiler_gypi.angle_translator_essl_sources +
- compiler_gypi.angle_translator_glsl_sources +
- compiler_gypi.angle_translator_hlsl_sources +
- gles_gypi.libangle_sources + gles_gypi.libangle_common_sources +
- gles_gypi.libangle_image_util_sources +
- gles_gypi.libglesv2_sources + gles_gypi.libangle_gl_sources,
+ angle_preprocessor_sources + angle_translator_sources +
+ angle_translator_essl_sources + angle_translator_glsl_sources +
+ angle_translator_hlsl_sources + libangle_sources +
+ libangle_common_sources + libangle_image_util_sources +
+ libglesv2_sources + libangle_gl_sources,
".",
"$angle_root/src")
if (is_win) {
@@ -112,23 +101,21 @@
"Xi",
"Xext",
]
- sources += rebase_path(gles_gypi.libangle_gl_glx_sources +
- gles_gypi.libangle_common_linux_sources,
- ".",
- "$angle_root/src") +
- [ "$angle_root/src/third_party/libXNVCtrl/NVCtrl.c" ]
+ sources +=
+ rebase_path(libangle_gl_glx_sources + libangle_common_linux_sources,
+ ".",
+ "$angle_root/src") +
+ [ "$angle_root/src/third_party/libXNVCtrl/NVCtrl.c" ]
} else if (is_win) {
defines += [
# TODO: ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES
]
- sources += rebase_path(gles_gypi.libangle_gl_wgl_sources +
- gles_gypi.libangle_d3d_shared_sources +
- gles_gypi.libangle_d3d9_sources +
- gles_gypi.libangle_d3d11_sources +
- gles_gypi.libangle_d3d11_win32_sources +
- gles_gypi.libangle_common_win_sources,
- ".",
- "$angle_root/src")
+ sources += rebase_path(
+ libangle_gl_wgl_sources + libangle_d3d_shared_sources +
+ libangle_d3d9_sources + libangle_d3d11_sources +
+ libangle_d3d11_win32_sources + libangle_common_win_sources,
+ ".",
+ "$angle_root/src")
libs += [
"d3d9.lib",
"dxguid.lib",
@@ -148,7 +135,7 @@
deps = [
":libGLESv2",
]
- sources = rebase_path(gles_gypi.libegl_sources, ".", "$angle_root/src")
+ sources = rebase_path(libegl_sources, ".", "$angle_root/src")
if (is_win) {
sources += [ "$angle_root/src/libEGL/libEGL.def" ]
}