OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 | 2 |
3 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 3 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
4 # Use of this source code is governed by a BSD-style license that can be | 4 # Use of this source code is governed by a BSD-style license that can be |
5 # found in the LICENSE file. | 5 # found in the LICENSE file. |
6 | 6 |
7 # This script is wrapper for Chromium that adds some support for how GYP | 7 # This script is wrapper for Chromium that adds some support for how GYP |
8 # is invoked by Chromium beyond what can be done in the gclient hooks. | 8 # is invoked by Chromium beyond what can be done in the gclient hooks. |
9 | 9 |
10 import glob | 10 import glob |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
57 else: | 57 else: |
58 psyco = None | 58 psyco = None |
59 | 59 |
60 | 60 |
61 def GetSupplementalFiles(): | 61 def GetSupplementalFiles(): |
62 """Returns a list of the supplemental files that are included in all GYP | 62 """Returns a list of the supplemental files that are included in all GYP |
63 sources.""" | 63 sources.""" |
64 return glob.glob(os.path.join(chrome_src, '*', 'supplement.gypi')) | 64 return glob.glob(os.path.join(chrome_src, '*', 'supplement.gypi')) |
65 | 65 |
66 | 66 |
67 def FormatKeyForGN(key): | |
68 """Returns the given GYP key reformatted for GN. | |
69 | |
70 GYP dictionary keys can be almost anything, but in GN they are identifiers | |
71 and must follow the same rules. This reformats such keys to be valid GN | |
72 identifiers.""" | |
73 return ''.join([c if c in string.ascii_letters else '_' for c in key]) | |
74 | |
75 | |
76 def EscapeStringForGN(s): | |
77 """Converts a string to a GN string literal.""" | |
78 for old, new in [('\\', '\\\\'), ('$', '\\$'), ('"', '\\"')]: | |
79 s = s.replace(old, new) | |
80 return '"' + s + '"' | |
81 | |
82 | |
83 def ProcessGypDefinesItems(items): | 67 def ProcessGypDefinesItems(items): |
84 """Converts a list of strings to a list of key-value pairs.""" | 68 """Converts a list of strings to a list of key-value pairs.""" |
85 result = [] | 69 result = [] |
86 for item in items: | 70 for item in items: |
87 tokens = item.split('=', 1) | 71 tokens = item.split('=', 1) |
88 # Some GYP variables have hyphens, which we don't support. | 72 # Some GYP variables have hyphens, which we don't support. |
89 key = FormatKeyForGN(tokens[0]) | |
90 if len(tokens) == 2: | 73 if len(tokens) == 2: |
91 result += [(key, tokens[1])] | 74 result += [(tokens[0], tokens[1])] |
92 else: | 75 else: |
93 # No value supplied, treat it as a boolean and set it. Note that we | 76 # No value supplied, treat it as a boolean and set it. Note that we |
94 # use the string '1' here so we have a consistent definition whether | 77 # use the string '1' here so we have a consistent definition whether |
95 # you do 'foo=1' or 'foo'. | 78 # you do 'foo=1' or 'foo'. |
96 result += [(key, '1')] | 79 result += [(tokens[0], '1')] |
97 return result | 80 return result |
98 | 81 |
99 | 82 |
100 def GetGypVarsForGN(supplemental_files): | 83 def GetGypVars(supplemental_files): |
101 """Returns a dictionary of all GYP vars that we will be passing to GN.""" | 84 """Returns a dictionary of all GYP vars.""" |
102 # Find the .gyp directory in the user's home directory. | 85 # Find the .gyp directory in the user's home directory. |
103 home_dot_gyp = os.environ.get('GYP_CONFIG_DIR', None) | 86 home_dot_gyp = os.environ.get('GYP_CONFIG_DIR', None) |
104 if home_dot_gyp: | 87 if home_dot_gyp: |
105 home_dot_gyp = os.path.expanduser(home_dot_gyp) | 88 home_dot_gyp = os.path.expanduser(home_dot_gyp) |
106 if not home_dot_gyp: | 89 if not home_dot_gyp: |
107 home_vars = ['HOME'] | 90 home_vars = ['HOME'] |
108 if sys.platform in ('cygwin', 'win32'): | 91 if sys.platform in ('cygwin', 'win32'): |
109 home_vars.append('USERPROFILE') | 92 home_vars.append('USERPROFILE') |
110 for home_var in home_vars: | 93 for home_var in home_vars: |
111 home = os.getenv(home_var) | 94 home = os.getenv(home_var) |
(...skipping 13 matching lines...) Expand all Loading... |
125 supp_items = [] | 108 supp_items = [] |
126 for supplement in supplemental_files: | 109 for supplement in supplemental_files: |
127 with open(supplement, 'r') as f: | 110 with open(supplement, 'r') as f: |
128 try: | 111 try: |
129 file_data = eval(f.read(), {'__builtins__': None}, None) | 112 file_data = eval(f.read(), {'__builtins__': None}, None) |
130 except SyntaxError, e: | 113 except SyntaxError, e: |
131 e.filename = os.path.abspath(supplement) | 114 e.filename = os.path.abspath(supplement) |
132 raise | 115 raise |
133 variables = file_data.get('variables', []) | 116 variables = file_data.get('variables', []) |
134 for v in variables: | 117 for v in variables: |
135 supp_items += [(FormatKeyForGN(v), str(variables[v]))] | 118 supp_items += [(v, str(variables[v]))] |
136 | 119 |
137 # GYP defines from the environment. | 120 # GYP defines from the environment. |
138 env_items = ProcessGypDefinesItems( | 121 env_items = ProcessGypDefinesItems( |
139 shlex.split(os.environ.get('GYP_DEFINES', ''))) | 122 shlex.split(os.environ.get('GYP_DEFINES', ''))) |
140 | 123 |
141 # GYP defines from the command line. We can't use optparse since we want | 124 # GYP defines from the command line. We can't use optparse since we want |
142 # to ignore all arguments other than "-D". | 125 # to ignore all arguments other than "-D". |
143 cmdline_input_items = [] | 126 cmdline_input_items = [] |
144 for i in range(len(sys.argv))[1:]: | 127 for i in range(len(sys.argv))[1:]: |
145 if sys.argv[i].startswith('-D'): | 128 if sys.argv[i].startswith('-D'): |
146 if sys.argv[i] == '-D' and i + 1 < len(sys.argv): | 129 if sys.argv[i] == '-D' and i + 1 < len(sys.argv): |
147 cmdline_input_items += [sys.argv[i + 1]] | 130 cmdline_input_items += [sys.argv[i + 1]] |
148 elif len(sys.argv[i]) > 2: | 131 elif len(sys.argv[i]) > 2: |
149 cmdline_input_items += [sys.argv[i][2:]] | 132 cmdline_input_items += [sys.argv[i][2:]] |
150 cmdline_items = ProcessGypDefinesItems(cmdline_input_items) | 133 cmdline_items = ProcessGypDefinesItems(cmdline_input_items) |
151 | 134 |
152 vars_dict = dict(supp_items + env_items + cmdline_items) | 135 vars_dict = dict(supp_items + env_items + cmdline_items) |
153 # It's not possible to set a default value for cpu_arch in GN, so do it here | |
154 # for now (http://crbug.com/344767). | |
155 if vars_dict.get('OS') == 'android' and not 'target_arch' in vars_dict: | |
156 vars_dict['target_arch'] = 'arm' | |
157 return vars_dict | 136 return vars_dict |
158 | 137 |
159 | 138 |
160 def GetOutputDirectory(): | 139 def GetOutputDirectory(): |
161 """Returns the output directory that GYP will use.""" | 140 """Returns the output directory that GYP will use.""" |
162 # GYP generator flags from the command line. We can't use optparse since we | 141 # GYP generator flags from the command line. We can't use optparse since we |
163 # want to ignore all arguments other than "-G". | 142 # want to ignore all arguments other than "-G". |
164 needle = '-Goutput_dir=' | 143 needle = '-Goutput_dir=' |
165 cmdline_input_items = [] | 144 cmdline_input_items = [] |
166 for item in sys.argv[1:]: | 145 for item in sys.argv[1:]: |
167 if item.startswith(needle): | 146 if item.startswith(needle): |
168 return item[len(needle):] | 147 return item[len(needle):] |
169 | 148 |
170 env_items = shlex.split(os.environ.get('GYP_GENERATOR_FLAGS', '')) | 149 env_items = shlex.split(os.environ.get('GYP_GENERATOR_FLAGS', '')) |
171 needle = 'output_dir=' | 150 needle = 'output_dir=' |
172 for item in env_items: | 151 for item in env_items: |
173 if item.startswith(needle): | 152 if item.startswith(needle): |
174 return item[len(needle):] | 153 return item[len(needle):] |
175 | 154 |
176 return "out" | 155 return "out" |
177 | 156 |
178 | 157 |
179 def GetArgsStringForGN(vars_dict): | |
180 """Returns the args to pass to GN. | |
181 Based on a subset of the GYP variables that have been rewritten a bit.""" | |
182 gn_args = '' | |
183 | |
184 # Note: These are the additional flags passed to various builds by builders | |
185 # on the main waterfall. We'll probably need to add these at some point: | |
186 # mac_strip_release=1 http://crbug.com/330301 | |
187 # linux_dump_symbols=0 http://crbug.com/330300 | |
188 # host_os=linux Probably can skip, GN knows the host OS. | |
189 # order_text_section=<path> http://crbug.com/330299 | |
190 # chromium_win_pch=0 http://crbug.com/297678 | |
191 # chromium_ios_signing=0 http://crbug.com/330302 | |
192 # use_allocator=tcmalloc http://crbug.com/330303, 345554 | |
193 # release_extra_flags=... http://crbug.com/330305 | |
194 | |
195 # These tuples of (key, value, gn_arg_string) use the gn_arg_string for | |
196 # gn when the key is set to the given value in the GYP arguments. | |
197 remap_cases = [ | |
198 ('android_webview_build', '1', 'is_android_webview_build=true'), | |
199 ('branding', 'Chrome', 'is_chrome_branded=true'), | |
200 ('build_for_tool', 'drmemory', 'disable_iterator_debugging=true'), | |
201 ('build_for_tool', 'tsan', 'disable_iterator_debugging=true'), | |
202 ('buildtype', 'Official', 'is_official_build=true'), | |
203 ('component', 'shared_library', 'is_component_build=true'), | |
204 ('clang', '1', 'is_clang=true'), | |
205 ('clang_use_chrome_plugins', '0', 'clang_use_chrome_plugins=false'), | |
206 ('disable_glibcxx_debug', '1', 'disable_iterator_debugging=true'), | |
207 ('enable_mdns', '0', 'enable_mdns=false'), | |
208 ('enable_mdns', '1', 'enable_mdns=true'), | |
209 ('enable_plugins', '0', 'enable_plugins=false'), | |
210 ('enable_plugins', '1', 'enable_plugins=true'), | |
211 ('target_arch', 'ia32', 'cpu_arch="x86"'), | |
212 ('target_arch', 'x64', 'cpu_arch="x64" force_win64=true'), | |
213 ('target_arch', 'arm', 'cpu_arch="arm"'), | |
214 ('target_arch', 'mipsel', 'cpu_arch="mipsel"'), | |
215 ('fastbuild', '0', 'symbol_level=2'), | |
216 ('fastbuild', '1', 'symbol_level=1'), | |
217 ('fastbuild', '2', 'symbol_level=0'), | |
218 ('OS', 'ios', 'os="ios"'), | |
219 ('OS', 'android', 'os="android"'), | |
220 ('chromeos', '1', 'os="chromeos"'), | |
221 ('use_aura', '1', 'use_aura=true'), | |
222 ('use_goma', '1', 'use_goma=true'), | |
223 ('use_openssl', '0', 'use_openssl=false'), | |
224 ('use_openssl', '1', 'use_openssl=true'), | |
225 ('asan', '1', 'is_asan=true'), | |
226 ('lsan', '1', 'is_lsan=true'), | |
227 ('msan', '1', 'is_msan=true'), | |
228 ('tsan', '1', 'is_tsan=true'), | |
229 ] | |
230 for i in remap_cases: | |
231 if i[0] in vars_dict and vars_dict[i[0]] == i[1]: | |
232 gn_args += ' ' + i[2] | |
233 | |
234 # These string arguments get passed directly as GN strings. | |
235 for v in ['android_src', 'arm_float_abi', 'ios_deployment_target', | |
236 'ios_sdk_path', 'windows_sdk_path']: | |
237 if v in vars_dict: | |
238 gn_args += ' ' + v + '=' + EscapeStringForGN(vars_dict[v]) | |
239 | |
240 # gomadir is renamed goma_dir in the GN build. | |
241 if 'gomadir' in vars_dict: | |
242 gn_args += ' goma_dir=%s' % EscapeStringForGN(vars_dict['gomadir']) | |
243 | |
244 # Set the "use_ios_simulator" flag if the ios_sdk_path is set. | |
245 if 'ios_sdk_path' in vars_dict: | |
246 if os.path.basename(vars_dict['ios_sdk_path']).lower().startswith( | |
247 'iphonesimulator'): | |
248 gn_args += ' use_ios_simulator=true' | |
249 else: | |
250 gn_args += ' use_ios_simulator=false' | |
251 | |
252 # These arguments get passed directly as integers (avoiding the quoting and | |
253 # escaping of the string ones above). | |
254 for v in ['arm_version']: | |
255 if v in vars_dict: | |
256 gn_args += ' %s=%s' % (v, vars_dict[v]) | |
257 | |
258 # Some other flags come from GYP environment variables. | |
259 gyp_msvs_version = os.environ.get('GYP_MSVS_VERSION', '') | |
260 if gyp_msvs_version: | |
261 gn_args += ' visual_studio_version=' + EscapeStringForGN(gyp_msvs_version) | |
262 gyp_msvs_override_path = os.environ.get('GYP_MSVS_OVERRIDE_PATH', '') | |
263 if gyp_msvs_override_path: | |
264 gn_args += ' visual_studio_path=' + \ | |
265 EscapeStringForGN(gyp_msvs_override_path) | |
266 | |
267 # Set the GYP flag so BUILD files know they're being invoked in GYP mode. | |
268 gn_args += ' is_gyp=true' | |
269 | |
270 gyp_outdir = GetOutputDirectory() | |
271 gn_args += ' gyp_output_dir=\"%s\"' % gyp_outdir | |
272 | |
273 return gn_args.strip() | |
274 | |
275 | |
276 def additional_include_files(supplemental_files, args=[]): | 158 def additional_include_files(supplemental_files, args=[]): |
277 """ | 159 """ |
278 Returns a list of additional (.gypi) files to include, without duplicating | 160 Returns a list of additional (.gypi) files to include, without duplicating |
279 ones that are already specified on the command line. The list of supplemental | 161 ones that are already specified on the command line. The list of supplemental |
280 include files is passed in as an argument. | 162 include files is passed in as an argument. |
281 """ | 163 """ |
282 # Determine the include files specified on the command line. | 164 # Determine the include files specified on the command line. |
283 # This doesn't cover all the different option formats you can use, | 165 # This doesn't cover all the different option formats you can use, |
284 # but it's mainly intended to avoid duplicating flags on the automatic | 166 # but it's mainly intended to avoid duplicating flags on the automatic |
285 # makefile regeneration which only uses this format. | 167 # makefile regeneration which only uses this format. |
(...skipping 10 matching lines...) Expand all Loading... |
296 # Always include common.gypi. | 178 # Always include common.gypi. |
297 AddInclude(os.path.join(script_dir, 'common.gypi')) | 179 AddInclude(os.path.join(script_dir, 'common.gypi')) |
298 | 180 |
299 # Optionally add supplemental .gypi files if present. | 181 # Optionally add supplemental .gypi files if present. |
300 for supplement in supplemental_files: | 182 for supplement in supplemental_files: |
301 AddInclude(supplement) | 183 AddInclude(supplement) |
302 | 184 |
303 return result | 185 return result |
304 | 186 |
305 | 187 |
306 def RunGN(vars_dict): | |
307 """Runs GN, returning True if it succeeded, printing an error and returning | |
308 false if not.""" | |
309 | |
310 # The binaries in platform-specific subdirectories in src/tools/gn/bin. | |
311 gnpath = SRC_DIR + '/tools/gn/bin/' | |
312 if sys.platform in ('cygwin', 'win32'): | |
313 gnpath += 'win/gn.exe' | |
314 elif sys.platform.startswith('linux'): | |
315 # On Linux we have 32-bit and 64-bit versions. | |
316 if subprocess.check_output(["getconf", "LONG_BIT"]).find("64") >= 0: | |
317 gnpath += 'linux/gn' | |
318 else: | |
319 gnpath += 'linux/gn32' | |
320 elif sys.platform == 'darwin': | |
321 gnpath += 'mac/gn' | |
322 else: | |
323 print 'Unknown platform for GN: ', sys.platform | |
324 return False | |
325 | |
326 print 'Generating gyp files from GN...' | |
327 | |
328 # Need to pass both the source root (the bots don't run this command from | |
329 # within the source tree) as well as set the is_gyp value so the BUILD files | |
330 # to know they're being run under GYP. | |
331 args = [gnpath, 'gyp', '-q', | |
332 '--root=' + chrome_src, | |
333 '--args=' + GetArgsStringForGN(vars_dict), | |
334 '--output=//' + GetOutputDirectory() + '/gn_build/'] | |
335 return subprocess.call(args) == 0 | |
336 | |
337 | |
338 if __name__ == '__main__': | 188 if __name__ == '__main__': |
339 args = sys.argv[1:] | 189 args = sys.argv[1:] |
340 | 190 |
341 if int(os.environ.get('GYP_CHROMIUM_NO_ACTION', 0)): | 191 if int(os.environ.get('GYP_CHROMIUM_NO_ACTION', 0)): |
342 print 'Skipping gyp_chromium due to GYP_CHROMIUM_NO_ACTION env var.' | 192 print 'Skipping gyp_chromium due to GYP_CHROMIUM_NO_ACTION env var.' |
343 sys.exit(0) | 193 sys.exit(0) |
344 | 194 |
345 # Use the Psyco JIT if available. | 195 # Use the Psyco JIT if available. |
346 if psyco: | 196 if psyco: |
347 psyco.profile() | 197 psyco.profile() |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
417 | 267 |
418 vs2013_runtime_dll_dirs = vs_toolchain.DownloadVsToolchain() | 268 vs2013_runtime_dll_dirs = vs_toolchain.DownloadVsToolchain() |
419 | 269 |
420 # If CHROMIUM_GYP_SYNTAX_CHECK is set to 1, it will invoke gyp with --check | 270 # If CHROMIUM_GYP_SYNTAX_CHECK is set to 1, it will invoke gyp with --check |
421 # to enfore syntax checking. | 271 # to enfore syntax checking. |
422 syntax_check = os.environ.get('CHROMIUM_GYP_SYNTAX_CHECK') | 272 syntax_check = os.environ.get('CHROMIUM_GYP_SYNTAX_CHECK') |
423 if syntax_check and int(syntax_check): | 273 if syntax_check and int(syntax_check): |
424 args.append('--check') | 274 args.append('--check') |
425 | 275 |
426 supplemental_includes = GetSupplementalFiles() | 276 supplemental_includes = GetSupplementalFiles() |
427 gn_vars_dict = GetGypVarsForGN(supplemental_includes) | 277 gyp_vars_dict = GetGypVars(supplemental_includes) |
428 | 278 |
429 # Automatically turn on crosscompile support for platforms that need it. | 279 # Automatically turn on crosscompile support for platforms that need it. |
430 # (The Chrome OS build sets CC_host / CC_target which implicitly enables | 280 # (The Chrome OS build sets CC_host / CC_target which implicitly enables |
431 # this mode.) | 281 # this mode.) |
432 if all(('ninja' in os.environ.get('GYP_GENERATORS', ''), | 282 if all(('ninja' in os.environ.get('GYP_GENERATORS', ''), |
433 gn_vars_dict.get('OS') in ['android', 'ios'], | 283 gyp_vars_dict.get('OS') in ['android', 'ios'], |
434 'GYP_CROSSCOMPILE' not in os.environ)): | 284 'GYP_CROSSCOMPILE' not in os.environ)): |
435 os.environ['GYP_CROSSCOMPILE'] = '1' | 285 os.environ['GYP_CROSSCOMPILE'] = '1' |
436 | 286 |
437 # TODO(brettw) bug 350974 either turn back on GN or delete all of this code. | |
438 #if not RunGN(gn_vars_dict): | |
439 # sys.exit(1) | |
440 args.extend( | 287 args.extend( |
441 ['-I' + i for i in additional_include_files(supplemental_includes, args)]) | 288 ['-I' + i for i in additional_include_files(supplemental_includes, args)]) |
442 | 289 |
443 args.extend(['-D', 'gyp_output_dir=' + GetOutputDirectory()]) | 290 args.extend(['-D', 'gyp_output_dir=' + GetOutputDirectory()]) |
444 | 291 |
445 print 'Updating projects from gyp files...' | 292 print 'Updating projects from gyp files...' |
446 sys.stdout.flush() | 293 sys.stdout.flush() |
447 | 294 |
448 # Off we go... | 295 # Off we go... |
449 gyp_rc = gyp.main(args) | 296 gyp_rc = gyp.main(args) |
450 | 297 |
451 # Check for landmines (reasons to clobber the build). This must be run here, | 298 # Check for landmines (reasons to clobber the build). This must be run here, |
452 # rather than a separate runhooks step so that any environment modifications | 299 # rather than a separate runhooks step so that any environment modifications |
453 # from above are picked up. | 300 # from above are picked up. |
454 print 'Running build/landmines.py...' | 301 print 'Running build/landmines.py...' |
455 subprocess.check_call( | 302 subprocess.check_call( |
456 [sys.executable, os.path.join(script_dir, 'landmines.py')]) | 303 [sys.executable, os.path.join(script_dir, 'landmines.py')]) |
457 | 304 |
458 if vs2013_runtime_dll_dirs: | 305 if vs2013_runtime_dll_dirs: |
459 x64_runtime, x86_runtime = vs2013_runtime_dll_dirs | 306 x64_runtime, x86_runtime = vs2013_runtime_dll_dirs |
460 vs_toolchain.CopyVsRuntimeDlls( | 307 vs_toolchain.CopyVsRuntimeDlls( |
461 os.path.join(chrome_src, GetOutputDirectory()), | 308 os.path.join(chrome_src, GetOutputDirectory()), |
462 (x86_runtime, x64_runtime)) | 309 (x86_runtime, x64_runtime)) |
463 | 310 |
464 sys.exit(gyp_rc) | 311 sys.exit(gyp_rc) |
OLD | NEW |