aw: Ensure fallback tick unsets |block_invalidates_|
[chromium-blink-merge.git] / build / gyp_chromium
blobb8fe82dc5cba08e34c16e772e9bf7d9196fe5b27
1 #!/usr/bin/env python
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
5 # found in the LICENSE file.
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.
10 import glob
11 import gyp_environment
12 import os
13 import re
14 import shlex
15 import subprocess
16 import string
17 import sys
18 import vs_toolchain
20 script_dir = os.path.dirname(os.path.realpath(__file__))
21 chrome_src = os.path.abspath(os.path.join(script_dir, os.pardir))
23 sys.path.insert(0, os.path.join(chrome_src, 'tools', 'gyp', 'pylib'))
24 import gyp
26 # Assume this file is in a one-level-deep subdirectory of the source root.
27 SRC_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
29 # Add paths so that pymod_do_main(...) can import files.
30 sys.path.insert(1, os.path.join(chrome_src, 'tools'))
31 sys.path.insert(1, os.path.join(chrome_src, 'tools', 'generate_shim_headers'))
32 sys.path.insert(1, os.path.join(chrome_src, 'tools', 'grit'))
33 sys.path.insert(1, os.path.join(chrome_src, 'chrome', 'tools', 'build'))
34 sys.path.insert(1, os.path.join(chrome_src, 'chromecast', 'tools', 'build'))
35 sys.path.insert(1, os.path.join(chrome_src, 'native_client', 'build'))
36 sys.path.insert(1, os.path.join(chrome_src, 'native_client_sdk', 'src',
37 'build_tools'))
38 sys.path.insert(1, os.path.join(chrome_src, 'remoting', 'tools', 'build'))
39 sys.path.insert(1, os.path.join(chrome_src, 'third_party', 'liblouis'))
40 sys.path.insert(1, os.path.join(chrome_src, 'third_party', 'WebKit',
41 'Source', 'build', 'scripts'))
43 # On Windows, Psyco shortens warm runs of build/gyp_chromium by about
44 # 20 seconds on a z600 machine with 12 GB of RAM, from 90 down to 70
45 # seconds. Conversely, memory usage of build/gyp_chromium with Psyco
46 # maxes out at about 158 MB vs. 132 MB without it.
48 # Psyco uses native libraries, so we need to load a different
49 # installation depending on which OS we are running under. It has not
50 # been tested whether using Psyco on our Mac and Linux builds is worth
51 # it (the GYP running time is a lot shorter, so the JIT startup cost
52 # may not be worth it).
53 if sys.platform == 'win32':
54 try:
55 sys.path.insert(0, os.path.join(chrome_src, 'third_party', 'psyco_win32'))
56 import psyco
57 except:
58 psyco = None
59 else:
60 psyco = None
63 def GetSupplementalFiles():
64 """Returns a list of the supplemental files that are included in all GYP
65 sources."""
66 return glob.glob(os.path.join(chrome_src, '*', 'supplement.gypi'))
69 def ProcessGypDefinesItems(items):
70 """Converts a list of strings to a list of key-value pairs."""
71 result = []
72 for item in items:
73 tokens = item.split('=', 1)
74 # Some GYP variables have hyphens, which we don't support.
75 if len(tokens) == 2:
76 result += [(tokens[0], tokens[1])]
77 else:
78 # No value supplied, treat it as a boolean and set it. Note that we
79 # use the string '1' here so we have a consistent definition whether
80 # you do 'foo=1' or 'foo'.
81 result += [(tokens[0], '1')]
82 return result
85 def GetGypVars(supplemental_files):
86 """Returns a dictionary of all GYP vars."""
87 # Find the .gyp directory in the user's home directory.
88 home_dot_gyp = os.environ.get('GYP_CONFIG_DIR', None)
89 if home_dot_gyp:
90 home_dot_gyp = os.path.expanduser(home_dot_gyp)
91 if not home_dot_gyp:
92 home_vars = ['HOME']
93 if sys.platform in ('cygwin', 'win32'):
94 home_vars.append('USERPROFILE')
95 for home_var in home_vars:
96 home = os.getenv(home_var)
97 if home != None:
98 home_dot_gyp = os.path.join(home, '.gyp')
99 if not os.path.exists(home_dot_gyp):
100 home_dot_gyp = None
101 else:
102 break
104 if home_dot_gyp:
105 include_gypi = os.path.join(home_dot_gyp, "include.gypi")
106 if os.path.exists(include_gypi):
107 supplemental_files += [include_gypi]
109 # GYP defines from the supplemental.gypi files.
110 supp_items = []
111 for supplement in supplemental_files:
112 with open(supplement, 'r') as f:
113 try:
114 file_data = eval(f.read(), {'__builtins__': None}, None)
115 except SyntaxError, e:
116 e.filename = os.path.abspath(supplement)
117 raise
118 variables = file_data.get('variables', [])
119 for v in variables:
120 supp_items += [(v, str(variables[v]))]
122 # GYP defines from the environment.
123 env_items = ProcessGypDefinesItems(
124 shlex.split(os.environ.get('GYP_DEFINES', '')))
126 # GYP defines from the command line. We can't use optparse since we want
127 # to ignore all arguments other than "-D".
128 cmdline_input_items = []
129 for i in range(len(sys.argv))[1:]:
130 if sys.argv[i].startswith('-D'):
131 if sys.argv[i] == '-D' and i + 1 < len(sys.argv):
132 cmdline_input_items += [sys.argv[i + 1]]
133 elif len(sys.argv[i]) > 2:
134 cmdline_input_items += [sys.argv[i][2:]]
135 cmdline_items = ProcessGypDefinesItems(cmdline_input_items)
137 vars_dict = dict(supp_items + env_items + cmdline_items)
138 return vars_dict
141 def GetOutputDirectory():
142 """Returns the output directory that GYP will use."""
143 # GYP generator flags from the command line. We can't use optparse since we
144 # want to ignore all arguments other than "-G".
145 needle = '-Goutput_dir='
146 cmdline_input_items = []
147 for item in sys.argv[1:]:
148 if item.startswith(needle):
149 return item[len(needle):]
151 env_items = shlex.split(os.environ.get('GYP_GENERATOR_FLAGS', ''))
152 needle = 'output_dir='
153 for item in env_items:
154 if item.startswith(needle):
155 return item[len(needle):]
157 return "out"
160 def additional_include_files(supplemental_files, args=[]):
162 Returns a list of additional (.gypi) files to include, without duplicating
163 ones that are already specified on the command line. The list of supplemental
164 include files is passed in as an argument.
166 # Determine the include files specified on the command line.
167 # This doesn't cover all the different option formats you can use,
168 # but it's mainly intended to avoid duplicating flags on the automatic
169 # makefile regeneration which only uses this format.
170 specified_includes = set()
171 for arg in args:
172 if arg.startswith('-I') and len(arg) > 2:
173 specified_includes.add(os.path.realpath(arg[2:]))
175 result = []
176 def AddInclude(path):
177 if os.path.realpath(path) not in specified_includes:
178 result.append(path)
180 # Always include common.gypi.
181 AddInclude(os.path.join(script_dir, 'common.gypi'))
183 # Optionally add supplemental .gypi files if present.
184 for supplement in supplemental_files:
185 AddInclude(supplement)
187 return result
190 if __name__ == '__main__':
191 # Disabling garbage collection saves about 1 second out of 16 on a Linux
192 # z620 workstation. Since this is a short-lived process it's not a problem to
193 # leak a few cyclyc references in order to spare the CPU cycles for
194 # scanning the heap.
195 import gc
196 gc.disable()
198 args = sys.argv[1:]
200 use_analyzer = len(args) and args[0] == '--analyzer'
201 if use_analyzer:
202 args.pop(0)
203 os.environ['GYP_GENERATORS'] = 'analyzer'
204 args.append('-Gconfig_path=' + args.pop(0))
205 args.append('-Ganalyzer_output_path=' + args.pop(0))
207 if int(os.environ.get('GYP_CHROMIUM_NO_ACTION', 0)):
208 print 'Skipping gyp_chromium due to GYP_CHROMIUM_NO_ACTION env var.'
209 sys.exit(0)
211 # Use the Psyco JIT if available.
212 if psyco:
213 psyco.profile()
214 print "Enabled Psyco JIT."
216 # Fall back on hermetic python if we happen to get run under cygwin.
217 # TODO(bradnelson): take this out once this issue is fixed:
218 # http://code.google.com/p/gyp/issues/detail?id=177
219 if sys.platform == 'cygwin':
220 import find_depot_tools
221 depot_tools_path = find_depot_tools.add_depot_tools_to_path()
222 python_dir = sorted(glob.glob(os.path.join(depot_tools_path,
223 'python2*_bin')))[-1]
224 env = os.environ.copy()
225 env['PATH'] = python_dir + os.pathsep + env.get('PATH', '')
226 p = subprocess.Popen(
227 [os.path.join(python_dir, 'python.exe')] + sys.argv,
228 env=env, shell=False)
229 p.communicate()
230 sys.exit(p.returncode)
232 # This could give false positives since it doesn't actually do real option
233 # parsing. Oh well.
234 gyp_file_specified = False
235 for arg in args:
236 if arg.endswith('.gyp'):
237 gyp_file_specified = True
238 break
240 gyp_environment.SetEnvironment()
242 # If we didn't get a file, check an env var, and then fall back to
243 # assuming 'all.gyp' from the same directory as the script.
244 if not gyp_file_specified:
245 gyp_file = os.environ.get('CHROMIUM_GYP_FILE')
246 if gyp_file:
247 # Note that CHROMIUM_GYP_FILE values can't have backslashes as
248 # path separators even on Windows due to the use of shlex.split().
249 args.extend(shlex.split(gyp_file))
250 else:
251 args.append(os.path.join(script_dir, 'all.gyp'))
253 # There shouldn't be a circular dependency relationship between .gyp files,
254 # but in Chromium's .gyp files, on non-Mac platforms, circular relationships
255 # currently exist. The check for circular dependencies is currently
256 # bypassed on other platforms, but is left enabled on the Mac, where a
257 # violation of the rule causes Xcode to misbehave badly.
258 # TODO(mark): Find and kill remaining circular dependencies, and remove this
259 # option. http://crbug.com/35878.
260 # TODO(tc): Fix circular dependencies in ChromiumOS then add linux2 to the
261 # list.
262 if sys.platform not in ('darwin',):
263 args.append('--no-circular-check')
265 # We explicitly don't support the make gyp generator (crbug.com/348686). Be
266 # nice and fail here, rather than choking in gyp.
267 if re.search(r'(^|,|\s)make($|,|\s)', os.environ.get('GYP_GENERATORS', '')):
268 print 'Error: make gyp generator not supported (check GYP_GENERATORS).'
269 sys.exit(1)
271 # If CHROMIUM_GYP_SYNTAX_CHECK is set to 1, it will invoke gyp with --check
272 # to enfore syntax checking.
273 syntax_check = os.environ.get('CHROMIUM_GYP_SYNTAX_CHECK')
274 if syntax_check and int(syntax_check):
275 args.append('--check')
277 supplemental_includes = GetSupplementalFiles()
278 gyp_vars_dict = GetGypVars(supplemental_includes)
280 # TODO(dmikurube): Remove these checks and messages after a while.
281 if ('linux_use_tcmalloc' in gyp_vars_dict or
282 'android_use_tcmalloc' in gyp_vars_dict):
283 print '*****************************************************************'
284 print '"linux_use_tcmalloc" and "android_use_tcmalloc" are deprecated!'
285 print '-----------------------------------------------------------------'
286 print 'You specify "linux_use_tcmalloc" or "android_use_tcmalloc" in'
287 print 'your GYP_DEFINES. Please switch them into "use_allocator" now.'
288 print 'See http://crbug.com/345554 for the details.'
289 print '*****************************************************************'
291 # Automatically turn on crosscompile support for platforms that need it.
292 # (The Chrome OS build sets CC_host / CC_target which implicitly enables
293 # this mode.)
294 if all(('ninja' in os.environ.get('GYP_GENERATORS', ''),
295 gyp_vars_dict.get('OS') in ['android', 'ios'],
296 'GYP_CROSSCOMPILE' not in os.environ)):
297 os.environ['GYP_CROSSCOMPILE'] = '1'
298 if gyp_vars_dict.get('OS') == 'android':
299 args.append('--check')
301 args.extend(
302 ['-I' + i for i in additional_include_files(supplemental_includes, args)])
304 args.extend(['-D', 'gyp_output_dir=' + GetOutputDirectory()])
306 if not use_analyzer:
307 print 'Updating projects from gyp files...'
308 sys.stdout.flush()
310 # Off we go...
311 gyp_rc = gyp.main(args)
313 if not use_analyzer:
314 vs2013_runtime_dll_dirs = vs_toolchain.SetEnvironmentAndGetRuntimeDllDirs()
315 if vs2013_runtime_dll_dirs:
316 x64_runtime, x86_runtime = vs2013_runtime_dll_dirs
317 vs_toolchain.CopyVsRuntimeDlls(
318 os.path.join(chrome_src, GetOutputDirectory()),
319 (x86_runtime, x64_runtime))
321 sys.exit(gyp_rc)