x11: Remove MessagePumpObserver.
[chromium-blink-merge.git] / build / gyp_chromium
blob3ac81c045f7a98e9d3f880db682bd07ee8ade39c
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_helper
12 import os
13 import shlex
14 import subprocess
15 import string
16 import sys
17 import vs_toolchain
19 script_dir = os.path.dirname(os.path.realpath(__file__))
20 chrome_src = os.path.abspath(os.path.join(script_dir, os.pardir))
22 sys.path.insert(0, os.path.join(chrome_src, 'tools', 'gyp', 'pylib'))
23 import gyp
25 # Assume this file is in a one-level-deep subdirectory of the source root.
26 SRC_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
28 # Add paths so that pymod_do_main(...) can import files.
29 sys.path.insert(1, os.path.join(chrome_src, 'tools'))
30 sys.path.insert(1, os.path.join(chrome_src, 'tools', 'generate_shim_headers'))
31 sys.path.insert(1, os.path.join(chrome_src, 'tools', 'grit'))
32 sys.path.insert(1, os.path.join(chrome_src, 'chrome', 'tools', 'build'))
33 sys.path.insert(1, os.path.join(chrome_src, 'native_client', 'build'))
34 sys.path.insert(1, os.path.join(chrome_src, 'native_client_sdk', 'src',
35 'build_tools'))
36 sys.path.insert(1, os.path.join(chrome_src, 'remoting', 'tools', 'build'))
37 sys.path.insert(1, os.path.join(chrome_src, 'third_party', 'liblouis'))
38 sys.path.insert(1, os.path.join(chrome_src, 'third_party', 'WebKit',
39 'Source', 'build', 'scripts'))
41 # On Windows, Psyco shortens warm runs of build/gyp_chromium by about
42 # 20 seconds on a z600 machine with 12 GB of RAM, from 90 down to 70
43 # seconds. Conversely, memory usage of build/gyp_chromium with Psyco
44 # maxes out at about 158 MB vs. 132 MB without it.
46 # Psyco uses native libraries, so we need to load a different
47 # installation depending on which OS we are running under. It has not
48 # been tested whether using Psyco on our Mac and Linux builds is worth
49 # it (the GYP running time is a lot shorter, so the JIT startup cost
50 # may not be worth it).
51 if sys.platform == 'win32':
52 try:
53 sys.path.insert(0, os.path.join(chrome_src, 'third_party', 'psyco_win32'))
54 import psyco
55 except:
56 psyco = None
57 else:
58 psyco = None
61 def GetSupplementalFiles():
62 """Returns a list of the supplemental files that are included in all GYP
63 sources."""
64 return glob.glob(os.path.join(chrome_src, '*', 'supplement.gypi'))
67 def ProcessGypDefinesItems(items):
68 """Converts a list of strings to a list of key-value pairs."""
69 result = []
70 for item in items:
71 tokens = item.split('=', 1)
72 # Some GYP variables have hyphens, which we don't support.
73 if len(tokens) == 2:
74 result += [(tokens[0], tokens[1])]
75 else:
76 # No value supplied, treat it as a boolean and set it. Note that we
77 # use the string '1' here so we have a consistent definition whether
78 # you do 'foo=1' or 'foo'.
79 result += [(tokens[0], '1')]
80 return result
83 def GetGypVars(supplemental_files):
84 """Returns a dictionary of all GYP vars."""
85 # Find the .gyp directory in the user's home directory.
86 home_dot_gyp = os.environ.get('GYP_CONFIG_DIR', None)
87 if home_dot_gyp:
88 home_dot_gyp = os.path.expanduser(home_dot_gyp)
89 if not home_dot_gyp:
90 home_vars = ['HOME']
91 if sys.platform in ('cygwin', 'win32'):
92 home_vars.append('USERPROFILE')
93 for home_var in home_vars:
94 home = os.getenv(home_var)
95 if home != None:
96 home_dot_gyp = os.path.join(home, '.gyp')
97 if not os.path.exists(home_dot_gyp):
98 home_dot_gyp = None
99 else:
100 break
102 if home_dot_gyp:
103 include_gypi = os.path.join(home_dot_gyp, "include.gypi")
104 if os.path.exists(include_gypi):
105 supplemental_files += [include_gypi]
107 # GYP defines from the supplemental.gypi files.
108 supp_items = []
109 for supplement in supplemental_files:
110 with open(supplement, 'r') as f:
111 try:
112 file_data = eval(f.read(), {'__builtins__': None}, None)
113 except SyntaxError, e:
114 e.filename = os.path.abspath(supplement)
115 raise
116 variables = file_data.get('variables', [])
117 for v in variables:
118 supp_items += [(v, str(variables[v]))]
120 # GYP defines from the environment.
121 env_items = ProcessGypDefinesItems(
122 shlex.split(os.environ.get('GYP_DEFINES', '')))
124 # GYP defines from the command line. We can't use optparse since we want
125 # to ignore all arguments other than "-D".
126 cmdline_input_items = []
127 for i in range(len(sys.argv))[1:]:
128 if sys.argv[i].startswith('-D'):
129 if sys.argv[i] == '-D' and i + 1 < len(sys.argv):
130 cmdline_input_items += [sys.argv[i + 1]]
131 elif len(sys.argv[i]) > 2:
132 cmdline_input_items += [sys.argv[i][2:]]
133 cmdline_items = ProcessGypDefinesItems(cmdline_input_items)
135 vars_dict = dict(supp_items + env_items + cmdline_items)
136 return vars_dict
139 def GetOutputDirectory():
140 """Returns the output directory that GYP will use."""
141 # GYP generator flags from the command line. We can't use optparse since we
142 # want to ignore all arguments other than "-G".
143 needle = '-Goutput_dir='
144 cmdline_input_items = []
145 for item in sys.argv[1:]:
146 if item.startswith(needle):
147 return item[len(needle):]
149 env_items = shlex.split(os.environ.get('GYP_GENERATOR_FLAGS', ''))
150 needle = 'output_dir='
151 for item in env_items:
152 if item.startswith(needle):
153 return item[len(needle):]
155 return "out"
158 def additional_include_files(supplemental_files, args=[]):
160 Returns a list of additional (.gypi) files to include, without duplicating
161 ones that are already specified on the command line. The list of supplemental
162 include files is passed in as an argument.
164 # Determine the include files specified on the command line.
165 # This doesn't cover all the different option formats you can use,
166 # but it's mainly intended to avoid duplicating flags on the automatic
167 # makefile regeneration which only uses this format.
168 specified_includes = set()
169 for arg in args:
170 if arg.startswith('-I') and len(arg) > 2:
171 specified_includes.add(os.path.realpath(arg[2:]))
173 result = []
174 def AddInclude(path):
175 if os.path.realpath(path) not in specified_includes:
176 result.append(path)
178 # Always include common.gypi.
179 AddInclude(os.path.join(script_dir, 'common.gypi'))
181 # Optionally add supplemental .gypi files if present.
182 for supplement in supplemental_files:
183 AddInclude(supplement)
185 return result
188 if __name__ == '__main__':
189 args = sys.argv[1:]
191 if int(os.environ.get('GYP_CHROMIUM_NO_ACTION', 0)):
192 print 'Skipping gyp_chromium due to GYP_CHROMIUM_NO_ACTION env var.'
193 sys.exit(0)
195 # Use the Psyco JIT if available.
196 if psyco:
197 psyco.profile()
198 print "Enabled Psyco JIT."
200 # Fall back on hermetic python if we happen to get run under cygwin.
201 # TODO(bradnelson): take this out once this issue is fixed:
202 # http://code.google.com/p/gyp/issues/detail?id=177
203 if sys.platform == 'cygwin':
204 import find_depot_tools
205 depot_tools_path = find_depot_tools.add_depot_tools_to_path()
206 python_dir = sorted(glob.glob(os.path.join(depot_tools_path,
207 'python2*_bin')))[-1]
208 env = os.environ.copy()
209 env['PATH'] = python_dir + os.pathsep + env.get('PATH', '')
210 p = subprocess.Popen(
211 [os.path.join(python_dir, 'python.exe')] + sys.argv,
212 env=env, shell=False)
213 p.communicate()
214 sys.exit(p.returncode)
216 gyp_helper.apply_chromium_gyp_env()
218 # This could give false positives since it doesn't actually do real option
219 # parsing. Oh well.
220 gyp_file_specified = False
221 for arg in args:
222 if arg.endswith('.gyp'):
223 gyp_file_specified = True
224 break
226 # If we didn't get a file, check an env var, and then fall back to
227 # assuming 'all.gyp' from the same directory as the script.
228 if not gyp_file_specified:
229 gyp_file = os.environ.get('CHROMIUM_GYP_FILE')
230 if gyp_file:
231 # Note that CHROMIUM_GYP_FILE values can't have backslashes as
232 # path separators even on Windows due to the use of shlex.split().
233 args.extend(shlex.split(gyp_file))
234 else:
235 args.append(os.path.join(script_dir, 'all.gyp'))
237 # There shouldn't be a circular dependency relationship between .gyp files,
238 # but in Chromium's .gyp files, on non-Mac platforms, circular relationships
239 # currently exist. The check for circular dependencies is currently
240 # bypassed on other platforms, but is left enabled on the Mac, where a
241 # violation of the rule causes Xcode to misbehave badly.
242 # TODO(mark): Find and kill remaining circular dependencies, and remove this
243 # option. http://crbug.com/35878.
244 # TODO(tc): Fix circular dependencies in ChromiumOS then add linux2 to the
245 # list.
246 if sys.platform not in ('darwin',):
247 args.append('--no-circular-check')
249 # We explicitly don't support the make gyp generator (crbug.com/348686). Be
250 # nice and fail here, rather than choking in gyp.
251 if 'make' in os.environ.get('GYP_GENERATORS', ''):
252 print 'Error: make gyp generator not supported (check GYP_GENERATORS).'
253 sys.exit(1)
255 # Default to ninja on linux and windows, but only if no generator has
256 # explicitly been set.
257 # Also default to ninja on mac, but only when not building chrome/ios.
258 # . -f / --format has precedence over the env var, no need to check for it
259 # . set the env var only if it hasn't been set yet
260 # . chromium.gyp_env has been applied to os.environ at this point already
261 if sys.platform.startswith(('linux', 'win', 'freebsd')) and \
262 not os.environ.get('GYP_GENERATORS'):
263 os.environ['GYP_GENERATORS'] = 'ninja'
264 elif sys.platform == 'darwin' and not os.environ.get('GYP_GENERATORS') and \
265 not 'OS=ios' in os.environ.get('GYP_DEFINES', []):
266 os.environ['GYP_GENERATORS'] = 'ninja'
268 vs2013_runtime_dll_dirs = vs_toolchain.SetEnvironmentAndGetRuntimeDllDirs()
270 # If CHROMIUM_GYP_SYNTAX_CHECK is set to 1, it will invoke gyp with --check
271 # to enfore syntax checking.
272 syntax_check = os.environ.get('CHROMIUM_GYP_SYNTAX_CHECK')
273 if syntax_check and int(syntax_check):
274 args.append('--check')
276 supplemental_includes = GetSupplementalFiles()
277 gyp_vars_dict = GetGypVars(supplemental_includes)
279 # Automatically turn on crosscompile support for platforms that need it.
280 # (The Chrome OS build sets CC_host / CC_target which implicitly enables
281 # this mode.)
282 if all(('ninja' in os.environ.get('GYP_GENERATORS', ''),
283 gyp_vars_dict.get('OS') in ['android', 'ios'],
284 'GYP_CROSSCOMPILE' not in os.environ)):
285 os.environ['GYP_CROSSCOMPILE'] = '1'
286 if gyp_vars_dict.get('OS') == 'android':
287 args.append('--check')
289 args.extend(
290 ['-I' + i for i in additional_include_files(supplemental_includes, args)])
292 args.extend(['-D', 'gyp_output_dir=' + GetOutputDirectory()])
294 print 'Updating projects from gyp files...'
295 sys.stdout.flush()
297 # Off we go...
298 gyp_rc = gyp.main(args)
300 # Check for landmines (reasons to clobber the build). This must be run here,
301 # rather than a separate runhooks step so that any environment modifications
302 # from above are picked up.
303 print 'Running build/landmines.py...'
304 subprocess.check_call(
305 [sys.executable, os.path.join(script_dir, 'landmines.py')])
307 if vs2013_runtime_dll_dirs:
308 x64_runtime, x86_runtime = vs2013_runtime_dll_dirs
309 vs_toolchain.CopyVsRuntimeDlls(
310 os.path.join(chrome_src, GetOutputDirectory()),
311 (x86_runtime, x64_runtime))
313 sys.exit(gyp_rc)