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 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
60 else: | 60 else: |
61 psyco = None | 61 psyco = None |
62 | 62 |
63 | 63 |
64 def GetSupplementalFiles(): | 64 def GetSupplementalFiles(): |
65 """Returns a list of the supplemental files that are included in all GYP | 65 """Returns a list of the supplemental files that are included in all GYP |
66 sources.""" | 66 sources.""" |
67 return glob.glob(os.path.join(chrome_src, '*', 'supplement.gypi')) | 67 return glob.glob(os.path.join(chrome_src, '*', 'supplement.gypi')) |
68 | 68 |
69 | 69 |
70 def FormatKeyForGN(key): | |
71 """Returns the given GYP key reformatted for GN. | |
72 | |
73 GYP dictionary keys can be almost anything, but in GN they are identifiers | |
74 and must follow the same rules. This reformats such keys to be valid GN | |
75 identifiers.""" | |
76 return ''.join([c if c in string.ascii_letters else '_' for c in key]) | |
77 | |
78 | |
79 def EscapeStringForGN(s): | |
80 """Converts a string to a GN string literal.""" | |
81 for old, new in [('\\', '\\\\'), ('$', '\\$'), ('"', '\\"')]: | |
82 s = s.replace(old, new) | |
83 return '"' + s + '"' | |
84 | |
85 | |
86 def ProcessGypDefinesItems(items): | |
87 """Converts a list of strings to a list of key-value pairs.""" | |
88 result = [] | |
89 for item in items: | |
90 tokens = item.split('=', 1) | |
91 # Some GYP variables have hyphens, which we don't support. | |
92 key = FormatKeyForGN(tokens[0]) | |
93 if len(tokens) == 2: | |
94 result += [(key, tokens[1])] | |
95 else: | |
96 # No value supplied, treat it as a boolean and set it. Note that we | |
97 # use the string '1' here so we have a consistent definition whether | |
98 # you do 'foo=1' or 'foo'. | |
99 result += [(key, '1')] | |
100 return result | |
101 | |
102 | |
103 def GetGypVarsForGN(supplemental_files): | |
104 """Returns a dictionary of all GYP vars that we will be passing to GN.""" | |
105 # Find the .gyp directory in the user's home directory. | |
106 home_dot_gyp = os.environ.get('GYP_CONFIG_DIR', None) | |
107 if home_dot_gyp: | |
108 home_dot_gyp = os.path.expanduser(home_dot_gyp) | |
109 if not home_dot_gyp: | |
110 home_vars = ['HOME'] | |
111 if sys.platform in ('cygwin', 'win32'): | |
112 home_vars.append('USERPROFILE') | |
113 for home_var in home_vars: | |
114 home = os.getenv(home_var) | |
115 if home != None: | |
116 home_dot_gyp = os.path.join(home, '.gyp') | |
117 if not os.path.exists(home_dot_gyp): | |
118 home_dot_gyp = None | |
119 else: | |
120 break | |
121 | |
122 if home_dot_gyp: | |
123 include_gypi = os.path.join(home_dot_gyp, "include.gypi") | |
124 if os.path.exists(include_gypi): | |
125 supplemental_files += [include_gypi] | |
126 | |
127 # GYP defines from the supplemental.gypi files. | |
128 supp_items = [] | |
129 for supplement in supplemental_files: | |
130 with open(supplement, 'r') as f: | |
131 try: | |
132 file_data = eval(f.read(), {'__builtins__': None}, None) | |
133 except SyntaxError, e: | |
134 e.filename = os.path.abspath(supplement) | |
135 raise | |
136 variables = file_data.get('variables', []) | |
137 for v in variables: | |
138 supp_items += [(FormatKeyForGN(v), str(variables[v]))] | |
139 | |
140 # GYP defines from the environment. | |
141 env_items = ProcessGypDefinesItems( | |
142 shlex.split(os.environ.get('GYP_DEFINES', ''))) | |
143 | |
144 # GYP defines from the command line. We can't use optparse since we want | |
145 # to ignore all arguments other than "-D". | |
146 cmdline_input_items = [] | |
147 for i in range(len(sys.argv))[1:]: | |
148 if sys.argv[i].startswith('-D'): | |
149 if sys.argv[i] == '-D' and i + 1 < len(sys.argv): | |
150 cmdline_input_items += [sys.argv[i + 1]] | |
151 elif len(sys.argv[i]) > 2: | |
152 cmdline_input_items += [sys.argv[i][2:]] | |
153 cmdline_items = ProcessGypDefinesItems(cmdline_input_items) | |
154 | |
155 vars_dict = dict(supp_items + env_items + cmdline_items) | |
156 # It's not possible to set a default value for cpu_arch in GN, so do it here | |
157 # for now (http://crbug.com/344767). | |
158 if vars_dict.get('OS') == 'android' and not 'target_arch' in vars_dict: | |
159 vars_dict['target_arch'] = 'arm' | |
160 return vars_dict | |
161 | |
162 | |
163 def GetOutputDirectory(): | 70 def GetOutputDirectory(): |
164 """Returns the output directory that GYP will use.""" | 71 """Returns the output directory that GYP will use.""" |
165 # GYP generator flags from the command line. We can't use optparse since we | 72 # GYP generator flags from the command line. We can't use optparse since we |
166 # want to ignore all arguments other than "-G". | 73 # want to ignore all arguments other than "-G". |
167 needle = '-Goutput_dir=' | 74 needle = '-Goutput_dir=' |
168 cmdline_input_items = [] | 75 cmdline_input_items = [] |
169 for item in sys.argv[1:]: | 76 for item in sys.argv[1:]: |
170 if item.startswith(needle): | 77 if item.startswith(needle): |
171 return item[len(needle):] | 78 return item[len(needle):] |
172 | 79 |
173 env_items = shlex.split(os.environ.get('GYP_GENERATOR_FLAGS', '')) | 80 env_items = shlex.split(os.environ.get('GYP_GENERATOR_FLAGS', '')) |
174 needle = 'output_dir=' | 81 needle = 'output_dir=' |
175 for item in env_items: | 82 for item in env_items: |
176 if item.startswith(needle): | 83 if item.startswith(needle): |
177 return item[len(needle):] | 84 return item[len(needle):] |
178 | 85 |
179 return "out" | 86 return "out" |
180 | 87 |
181 | 88 |
182 def GetArgsStringForGN(vars_dict): | |
183 """Returns the args to pass to GN. | |
184 Based on a subset of the GYP variables that have been rewritten a bit.""" | |
185 gn_args = '' | |
186 | |
187 # Note: These are the additional flags passed to various builds by builders | |
188 # on the main waterfall. We'll probably need to add these at some point: | |
189 # mac_strip_release=1 http://crbug.com/330301 | |
190 # linux_dump_symbols=0 http://crbug.com/330300 | |
191 # host_os=linux Probably can skip, GN knows the host OS. | |
192 # order_text_section=<path> http://crbug.com/330299 | |
193 # chromium_win_pch=0 http://crbug.com/297678 | |
194 # chromium_ios_signing=0 http://crbug.com/330302 | |
195 # use_allocator=tcmalloc http://crbug.com/330303, 345554 | |
196 # release_extra_flags=... http://crbug.com/330305 | |
197 | |
198 # These tuples of (key, value, gn_arg_string) use the gn_arg_string for | |
199 # gn when the key is set to the given value in the GYP arguments. | |
200 remap_cases = [ | |
201 ('android_webview_build', '1', 'is_android_webview_build=true'), | |
202 ('branding', 'Chrome', 'is_chrome_branded=true'), | |
203 ('build_for_tool', 'drmemory', 'disable_iterator_debugging=true'), | |
204 ('build_for_tool', 'tsan', 'disable_iterator_debugging=true'), | |
205 ('buildtype', 'Official', 'is_official_build=true'), | |
206 ('component', 'shared_library', 'is_component_build=true'), | |
207 ('clang', '1', 'is_clang=true'), | |
208 ('clang_use_chrome_plugins', '0', 'clang_use_chrome_plugins=false'), | |
209 ('disable_glibcxx_debug', '1', 'disable_iterator_debugging=true'), | |
210 ('enable_mdns', '0', 'enable_mdns=false'), | |
211 ('enable_mdns', '1', 'enable_mdns=true'), | |
212 ('enable_plugins', '0', 'enable_plugins=false'), | |
213 ('enable_plugins', '1', 'enable_plugins=true'), | |
214 ('target_arch', 'ia32', 'cpu_arch="x86"'), | |
215 ('target_arch', 'x64', 'cpu_arch="x64" force_win64=true'), | |
216 ('target_arch', 'arm', 'cpu_arch="arm"'), | |
217 ('target_arch', 'mipsel', 'cpu_arch="mipsel"'), | |
218 ('fastbuild', '0', 'symbol_level=2'), | |
219 ('fastbuild', '1', 'symbol_level=1'), | |
220 ('fastbuild', '2', 'symbol_level=0'), | |
221 ('OS', 'ios', 'os="ios"'), | |
222 ('OS', 'android', 'os="android"'), | |
223 ('chromeos', '1', 'os="chromeos"'), | |
224 ('use_aura', '1', 'use_aura=true'), | |
225 ('use_goma', '1', 'use_goma=true'), | |
226 ('use_openssl', '0', 'use_openssl=false'), | |
227 ('use_openssl', '1', 'use_openssl=true'), | |
228 ('asan', '1', 'is_asan=true'), | |
229 ('lsan', '1', 'is_lsan=true'), | |
230 ('msan', '1', 'is_msan=true'), | |
231 ('tsan', '1', 'is_tsan=true'), | |
232 ] | |
233 for i in remap_cases: | |
234 if i[0] in vars_dict and vars_dict[i[0]] == i[1]: | |
235 gn_args += ' ' + i[2] | |
236 | |
237 # These string arguments get passed directly as GN strings. | |
238 for v in ['android_src', 'arm_float_abi', 'ios_deployment_target', | |
239 'ios_sdk_path', 'windows_sdk_path']: | |
240 if v in vars_dict: | |
241 gn_args += ' ' + v + '=' + EscapeStringForGN(vars_dict[v]) | |
242 | |
243 # gomadir is renamed goma_dir in the GN build. | |
244 if 'gomadir' in vars_dict: | |
245 gn_args += ' goma_dir=%s' % EscapeStringForGN(vars_dict['gomadir']) | |
246 | |
247 # Set the "use_ios_simulator" flag if the ios_sdk_path is set. | |
248 if 'ios_sdk_path' in vars_dict: | |
249 if os.path.basename(vars_dict['ios_sdk_path']).lower().startswith( | |
250 'iphonesimulator'): | |
251 gn_args += ' use_ios_simulator=true' | |
252 else: | |
253 gn_args += ' use_ios_simulator=false' | |
254 | |
255 # These arguments get passed directly as integers (avoiding the quoting and | |
256 # escaping of the string ones above). | |
257 for v in ['arm_version']: | |
258 if v in vars_dict: | |
259 gn_args += ' %s=%s' % (v, vars_dict[v]) | |
260 | |
261 # Some other flags come from GYP environment variables. | |
262 gyp_msvs_version = os.environ.get('GYP_MSVS_VERSION', '') | |
263 if gyp_msvs_version: | |
264 gn_args += ' visual_studio_version=' + EscapeStringForGN(gyp_msvs_version) | |
265 gyp_msvs_override_path = os.environ.get('GYP_MSVS_OVERRIDE_PATH', '') | |
266 if gyp_msvs_override_path: | |
267 gn_args += ' visual_studio_path=' + \ | |
268 EscapeStringForGN(gyp_msvs_override_path) | |
269 | |
270 # Set the GYP flag so BUILD files know they're being invoked in GYP mode. | |
271 gn_args += ' is_gyp=true' | |
272 | |
273 gyp_outdir = GetOutputDirectory() | |
274 gn_args += ' gyp_output_dir=\"%s\"' % gyp_outdir | |
275 | |
276 return gn_args.strip() | |
277 | |
278 | |
279 def additional_include_files(supplemental_files, args=[]): | 89 def additional_include_files(supplemental_files, args=[]): |
280 """ | 90 """ |
281 Returns a list of additional (.gypi) files to include, without duplicating | 91 Returns a list of additional (.gypi) files to include, without duplicating |
282 ones that are already specified on the command line. The list of supplemental | 92 ones that are already specified on the command line. The list of supplemental |
283 include files is passed in as an argument. | 93 include files is passed in as an argument. |
284 """ | 94 """ |
285 # Determine the include files specified on the command line. | 95 # Determine the include files specified on the command line. |
286 # This doesn't cover all the different option formats you can use, | 96 # This doesn't cover all the different option formats you can use, |
287 # but it's mainly intended to avoid duplicating flags on the automatic | 97 # but it's mainly intended to avoid duplicating flags on the automatic |
288 # makefile regeneration which only uses this format. | 98 # makefile regeneration which only uses this format. |
(...skipping 10 matching lines...) Expand all Loading... | |
299 # Always include common.gypi. | 109 # Always include common.gypi. |
300 AddInclude(os.path.join(script_dir, 'common.gypi')) | 110 AddInclude(os.path.join(script_dir, 'common.gypi')) |
301 | 111 |
302 # Optionally add supplemental .gypi files if present. | 112 # Optionally add supplemental .gypi files if present. |
303 for supplement in supplemental_files: | 113 for supplement in supplemental_files: |
304 AddInclude(supplement) | 114 AddInclude(supplement) |
305 | 115 |
306 return result | 116 return result |
307 | 117 |
308 | 118 |
309 def RunGN(vars_dict): | |
310 """Runs GN, returning True if it succeeded, printing an error and returning | |
311 false if not.""" | |
312 | |
313 # The binaries in platform-specific subdirectories in src/tools/gn/bin. | |
314 gnpath = SRC_DIR + '/tools/gn/bin/' | |
315 if sys.platform in ('cygwin', 'win32'): | |
316 gnpath += 'win/gn.exe' | |
317 elif sys.platform.startswith('linux'): | |
318 # On Linux we have 32-bit and 64-bit versions. | |
319 if subprocess.check_output(["getconf", "LONG_BIT"]).find("64") >= 0: | |
320 gnpath += 'linux/gn' | |
321 else: | |
322 gnpath += 'linux/gn32' | |
323 elif sys.platform == 'darwin': | |
324 gnpath += 'mac/gn' | |
325 else: | |
326 print 'Unknown platform for GN: ', sys.platform | |
327 return False | |
328 | |
329 print 'Generating gyp files from GN...' | |
330 | |
331 # Need to pass both the source root (the bots don't run this command from | |
332 # within the source tree) as well as set the is_gyp value so the BUILD files | |
333 # to know they're being run under GYP. | |
334 args = [gnpath, 'gyp', '-q', | |
335 '--root=' + chrome_src, | |
336 '--args=' + GetArgsStringForGN(vars_dict), | |
337 '--output=//' + GetOutputDirectory() + '/gn_build/'] | |
338 return subprocess.call(args) == 0 | |
339 | |
340 | |
341 def GetDesiredVsToolchainHashes(): | 119 def GetDesiredVsToolchainHashes(): |
342 """Load a list of SHA1s corresponding to the toolchains that we want installed | 120 """Load a list of SHA1s corresponding to the toolchains that we want installed |
343 to build with.""" | 121 to build with.""" |
344 sha1path = os.path.join(script_dir, 'toolchain_vs2013.hash') | 122 sha1path = os.path.join(script_dir, 'toolchain_vs2013.hash') |
345 with open(sha1path, 'rb') as f: | 123 with open(sha1path, 'rb') as f: |
346 return f.read().strip().splitlines() | 124 return f.read().strip().splitlines() |
347 | 125 |
348 | 126 |
349 def DownloadVsToolChain(): | 127 def DownloadVsToolChain(): |
350 """Download the Visual Studio toolchain on Windows. | 128 """Download the Visual Studio toolchain on Windows. |
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
533 | 311 |
534 vs2013_runtime_dll_dirs = DownloadVsToolChain() | 312 vs2013_runtime_dll_dirs = DownloadVsToolChain() |
535 | 313 |
536 # If CHROMIUM_GYP_SYNTAX_CHECK is set to 1, it will invoke gyp with --check | 314 # If CHROMIUM_GYP_SYNTAX_CHECK is set to 1, it will invoke gyp with --check |
537 # to enfore syntax checking. | 315 # to enfore syntax checking. |
538 syntax_check = os.environ.get('CHROMIUM_GYP_SYNTAX_CHECK') | 316 syntax_check = os.environ.get('CHROMIUM_GYP_SYNTAX_CHECK') |
539 if syntax_check and int(syntax_check): | 317 if syntax_check and int(syntax_check): |
540 args.append('--check') | 318 args.append('--check') |
541 | 319 |
542 supplemental_includes = GetSupplementalFiles() | 320 supplemental_includes = GetSupplementalFiles() |
543 gn_vars_dict = GetGypVarsForGN(supplemental_includes) | |
544 | 321 |
545 # Automatically turn on crosscompile support for platforms that need it. | 322 # Automatically turn on crosscompile support for platforms that need it. |
546 # (The Chrome OS build sets CC_host / CC_target which implicitly enables | 323 # (The Chrome OS build sets CC_host / CC_target which implicitly enables |
547 # this mode.) | 324 # this mode.) |
548 if all(('ninja' in os.environ.get('GYP_GENERATORS', ''), | 325 if all(('ninja' in os.environ.get('GYP_GENERATORS', ''), |
549 gn_vars_dict.get('OS') in ['android', 'ios'], | 326 gn_vars_dict.get('OS') in ['android', 'ios'], |
brettw
2014/03/18 18:30:16
Help! I don't know what to do about this line of c
Nico
2014/03/19 11:04:59
sgtm as short-term thing. Medium-term, file a bug
| |
550 'GYP_CROSSCOMPILE' not in os.environ)): | 327 'GYP_CROSSCOMPILE' not in os.environ)): |
551 os.environ['GYP_CROSSCOMPILE'] = '1' | 328 os.environ['GYP_CROSSCOMPILE'] = '1' |
552 | 329 |
553 # TODO(brettw) bug 350974 either turn back on GN or delete all of this code. | |
554 #if not RunGN(gn_vars_dict): | |
555 # sys.exit(1) | |
556 args.extend( | 330 args.extend( |
557 ['-I' + i for i in additional_include_files(supplemental_includes, args)]) | 331 ['-I' + i for i in additional_include_files(supplemental_includes, args)]) |
558 | 332 |
559 args.extend(['-D', 'gyp_output_dir=' + GetOutputDirectory()]) | 333 args.extend(['-D', 'gyp_output_dir=' + GetOutputDirectory()]) |
560 | 334 |
561 print 'Updating projects from gyp files...' | 335 print 'Updating projects from gyp files...' |
562 sys.stdout.flush() | 336 sys.stdout.flush() |
563 | 337 |
564 # Off we go... | 338 # Off we go... |
565 gyp_rc = gyp.main(args) | 339 gyp_rc = gyp.main(args) |
566 | 340 |
567 # Check for landmines (reasons to clobber the build). This must be run here, | 341 # Check for landmines (reasons to clobber the build). This must be run here, |
568 # rather than a separate runhooks step so that any environment modifications | 342 # rather than a separate runhooks step so that any environment modifications |
569 # from above are picked up. | 343 # from above are picked up. |
570 print 'Running build/landmines.py...' | 344 print 'Running build/landmines.py...' |
571 subprocess.check_call( | 345 subprocess.check_call( |
572 [sys.executable, os.path.join(script_dir, 'landmines.py')]) | 346 [sys.executable, os.path.join(script_dir, 'landmines.py')]) |
573 | 347 |
574 if vs2013_runtime_dll_dirs: | 348 if vs2013_runtime_dll_dirs: |
575 x64_runtime, x86_runtime = vs2013_runtime_dll_dirs | 349 x64_runtime, x86_runtime = vs2013_runtime_dll_dirs |
576 CopyVsRuntimeDlls(os.path.join(chrome_src, GetOutputDirectory()), | 350 CopyVsRuntimeDlls(os.path.join(chrome_src, GetOutputDirectory()), |
577 (x86_runtime, x64_runtime)) | 351 (x86_runtime, x64_runtime)) |
578 | 352 |
579 sys.exit(gyp_rc) | 353 sys.exit(gyp_rc) |
OLD | NEW |