Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(102)

Side by Side Diff: tools/gypi_to_gn.py

Issue 2996903002: [infra] Translate _sources.gypi files to _sources.gni files (Closed)
Patch Set: Fix script Created 3 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « tools/build.py ('k') | tools/ninja.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 #!/usr/bin/env python
2 # Copyright 2014 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5
6 """Converts given gypi files to a python scope and writes the result to stdout.
7
8 It is assumed that the files contain a toplevel dictionary, and this script
9 will return that dictionary as a GN "scope" (see example below). This script
10 does not know anything about GYP and it will not expand variables or execute
11 conditions.
12
13 It will strip conditions blocks.
14
15 A variables block at the top level will be flattened so that the variables
16 appear in the root dictionary. This way they can be returned to the GN code.
17
18 Say your_file.gypi looked like this:
19 {
20 'sources': [ 'a.cc', 'b.cc' ],
21 'defines': [ 'ENABLE_DOOM_MELON' ],
22 }
23
24 You would call it like this:
25 gypi_files = [ "your_file.gypi", "your_other_file.gypi" ]
26 gypi_values = exec_script("//build/gypi_to_gn.py",
27 [ rebase_path(gypi_files) ],
28 "scope",
29 [ gypi_files ])
30
31 Notes:
32 - The rebase_path call converts the gypi file from being relative to the
33 current build file to being system absolute for calling the script, which
34 will have a different current directory than this file.
35
36 - The "scope" parameter tells GN to interpret the result as a series of GN
37 variable assignments.
38
39 - The last file argument to exec_script tells GN that the given file is a
40 dependency of the build so Ninja can automatically re-run GN if the file
41 changes.
42
43 Read the values into a target like this:
44 component("mycomponent") {
45 sources = gypi_values.your_file_sources
46 defines = gypi_values.your_file_defines
47 }
48
49 Sometimes your .gypi file will include paths relative to a different
50 directory than the current .gn file. In this case, you can rebase them to
51 be relative to the current directory.
52 sources = rebase_path(gypi_values.your_files_sources, ".",
53 "//path/gypi/input/values/are/relative/to")
54
55 This script will tolerate a 'variables' in the toplevel dictionary or not. If
56 the toplevel dictionary just contains one item called 'variables', it will be
57 collapsed away and the result will be the contents of that dictinoary. Some
58 .gypi files are written with or without this, depending on how they expect to
59 be embedded into a .gyp file.
60
61 This script also has the ability to replace certain substrings in the input.
62 Generally this is used to emulate GYP variable expansion. If you passed the
63 argument "--replace=<(foo)=bar" then all instances of "<(foo)" in strings in
64 the input will be replaced with "bar":
65
66 gypi_values = exec_script("//build/gypi_to_gn.py",
67 [ rebase_path("your_file.gypi"),
68 "--replace=<(foo)=bar"],
69 "scope",
70 [ "your_file.gypi" ])
71
72 """
73
74 import gn_helpers
75 from optparse import OptionParser
76 import sys
77 import os.path
78
79 def LoadPythonDictionary(path):
80 file_string = open(path).read()
81 try:
82 file_data = eval(file_string, {'__builtins__': None}, None)
83 except SyntaxError, e:
84 e.filename = path
85 raise
86 except Exception, e:
87 raise Exception("Unexpected error while reading %s: %s" % (path, str(e)))
88
89 assert isinstance(file_data, dict), "%s does not eval to a dictionary" % path
90
91 # Flatten any variables to the top level.
92 if 'variables' in file_data:
93 file_data.update(file_data['variables'])
94 del file_data['variables']
95
96 # Strip any conditions.
97 if 'conditions' in file_data:
98 del file_data['conditions']
99 if 'target_conditions' in file_data:
100 del file_data['target_conditions']
101
102 # Strip targets in the toplevel, since some files define these and we can't
103 # slurp them in.
104 if 'targets' in file_data:
105 del file_data['targets']
106
107 return file_data
108
109
110 def KeepOnly(values, filters):
111 """Recursively filters out strings not ending in "f" from "values"""
112
113 if isinstance(values, list):
114 return [v for v in values if v.endswith(tuple(filters))]
115
116 if isinstance(values, dict):
117 result = {}
118 for key, value in values.items():
119 new_key = KeepOnly(key, filters)
120 new_value = KeepOnly(value, filters)
121 result[new_key] = new_value
122 return result
123
124 return values
125
126 def main():
127 parser = OptionParser()
128 parser.add_option("-k", "--keep_only", default = [], action="append",
129 help="Keeps only files ending with the listed strings.")
130 parser.add_option("--prefix", action="store_true",
131 help="Prefix variables with base name")
132 (options, args) = parser.parse_args()
133
134 if len(args) < 1:
135 raise Exception("Need at least one .gypi file to read.")
136
137 data = {}
138
139 for gypi in args:
140 gypi_data = LoadPythonDictionary(gypi)
141
142 if options.keep_only != []:
143 gypi_data = KeepOnly(gypi_data, options.keep_only)
144
145 # Sometimes .gypi files use the GYP syntax with percents at the end of the
146 # variable name (to indicate not to overwrite a previously-defined value):
147 # 'foo%': 'bar',
148 # Convert these to regular variables.
149 for key in gypi_data:
150 if len(key) > 1 and key[len(key) - 1] == '%':
151 gypi_data[key[:-1]] = gypi_data[key]
152 del gypi_data[key]
153 gypi_name = os.path.basename(gypi)[:-len(".gypi")]
154 for key in gypi_data:
155 if options.prefix:
156 # Prefix all variables from this gypi file with the name to disambiguate
157 data[gypi_name + "_" + key] = gypi_data[key]
158 elif key in data:
159 for entry in gypi_data[key]:
160 data[key].append(entry)
161 else:
162 data[key] = gypi_data[key]
163
164 print gn_helpers.ToGNString(data)
165
166 if __name__ == '__main__':
167 try:
168 main()
169 except Exception, e:
170 print str(e)
171 sys.exit(1)
OLDNEW
« no previous file with comments | « tools/build.py ('k') | tools/ninja.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698