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.
12 import gyp_environment
21 script_dir
= os
.path
.dirname(os
.path
.realpath(__file__
))
22 chrome_src
= os
.path
.abspath(os
.path
.join(script_dir
, os
.pardir
))
24 sys
.path
.insert(0, os
.path
.join(chrome_src
, 'tools', 'gyp', 'pylib'))
27 # Assume this file is in a one-level-deep subdirectory of the source root.
28 SRC_DIR
= os
.path
.dirname(os
.path
.dirname(os
.path
.abspath(__file__
)))
30 # Add paths so that pymod_do_main(...) can import files.
31 sys
.path
.insert(1, os
.path
.join(chrome_src
, 'android_webview', 'tools'))
32 sys
.path
.insert(1, os
.path
.join(chrome_src
, 'build', 'android', 'gyp'))
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
, 'ios', 'chrome', 'tools', 'build'))
36 sys
.path
.insert(1, os
.path
.join(chrome_src
, 'native_client', 'build'))
37 sys
.path
.insert(1, os
.path
.join(chrome_src
, 'native_client_sdk', 'src',
39 sys
.path
.insert(1, os
.path
.join(chrome_src
, 'remoting', 'tools', 'build'))
40 sys
.path
.insert(1, os
.path
.join(chrome_src
, 'third_party', 'liblouis'))
41 sys
.path
.insert(1, os
.path
.join(chrome_src
, 'third_party', 'WebKit',
42 'Source', 'build', 'scripts'))
43 sys
.path
.insert(1, os
.path
.join(chrome_src
, 'tools'))
44 sys
.path
.insert(1, os
.path
.join(chrome_src
, 'tools', 'generate_shim_headers'))
45 sys
.path
.insert(1, os
.path
.join(chrome_src
, 'tools', 'grit'))
47 # On Windows, Psyco shortens warm runs of build/gyp_chromium by about
48 # 20 seconds on a z600 machine with 12 GB of RAM, from 90 down to 70
49 # seconds. Conversely, memory usage of build/gyp_chromium with Psyco
50 # maxes out at about 158 MB vs. 132 MB without it.
52 # Psyco uses native libraries, so we need to load a different
53 # installation depending on which OS we are running under. It has not
54 # been tested whether using Psyco on our Mac and Linux builds is worth
55 # it (the GYP running time is a lot shorter, so the JIT startup cost
56 # may not be worth it).
57 if sys
.platform
== 'win32':
59 sys
.path
.insert(0, os
.path
.join(chrome_src
, 'third_party', 'psyco_win32'))
67 def GetSupplementalFiles():
68 """Returns a list of the supplemental files that are included in all GYP
70 return glob
.glob(os
.path
.join(chrome_src
, '*', 'supplement.gypi'))
73 def ProcessGypDefinesItems(items
):
74 """Converts a list of strings to a list of key-value pairs."""
77 tokens
= item
.split('=', 1)
78 # Some GYP variables have hyphens, which we don't support.
80 result
+= [(tokens
[0], tokens
[1])]
82 # No value supplied, treat it as a boolean and set it. Note that we
83 # use the string '1' here so we have a consistent definition whether
84 # you do 'foo=1' or 'foo'.
85 result
+= [(tokens
[0], '1')]
89 def GetGypVars(supplemental_files
):
90 """Returns a dictionary of all GYP vars."""
91 # Find the .gyp directory in the user's home directory.
92 home_dot_gyp
= os
.environ
.get('GYP_CONFIG_DIR', None)
94 home_dot_gyp
= os
.path
.expanduser(home_dot_gyp
)
97 if sys
.platform
in ('cygwin', 'win32'):
98 home_vars
.append('USERPROFILE')
99 for home_var
in home_vars
:
100 home
= os
.getenv(home_var
)
102 home_dot_gyp
= os
.path
.join(home
, '.gyp')
103 if not os
.path
.exists(home_dot_gyp
):
109 include_gypi
= os
.path
.join(home_dot_gyp
, "include.gypi")
110 if os
.path
.exists(include_gypi
):
111 supplemental_files
+= [include_gypi
]
113 # GYP defines from the supplemental.gypi files.
115 for supplement
in supplemental_files
:
116 with
open(supplement
, 'r') as f
:
118 file_data
= eval(f
.read(), {'__builtins__': None}, None)
119 except SyntaxError, e
:
120 e
.filename
= os
.path
.abspath(supplement
)
122 variables
= file_data
.get('variables', [])
124 supp_items
+= [(v
, str(variables
[v
]))]
126 # GYP defines from the environment.
127 env_items
= ProcessGypDefinesItems(
128 shlex
.split(os
.environ
.get('GYP_DEFINES', '')))
130 # GYP defines from the command line.
131 parser
= argparse
.ArgumentParser()
132 parser
.add_argument('-D', dest
='defines', action
='append', default
=[])
133 cmdline_input_items
= parser
.parse_known_args()[0].defines
134 cmdline_items
= ProcessGypDefinesItems(cmdline_input_items
)
136 vars_dict
= dict(supp_items
+ env_items
+ cmdline_items
)
140 def GetOutputDirectory():
141 """Returns the output directory that GYP will use."""
143 # Handle command line generator flags.
144 parser
= argparse
.ArgumentParser()
145 parser
.add_argument('-G', dest
='genflags', default
=[], action
='append')
146 genflags
= parser
.parse_known_args()[0].genflags
148 # Handle generator flags from the environment.
149 genflags
+= shlex
.split(os
.environ
.get('GYP_GENERATOR_FLAGS', ''))
151 needle
= 'output_dir='
152 for item
in genflags
:
153 if item
.startswith(needle
):
154 return item
[len(needle
):]
159 def additional_include_files(supplemental_files
, args
=[]):
161 Returns a list of additional (.gypi) files to include, without duplicating
162 ones that are already specified on the command line. The list of supplemental
163 include files is passed in as an argument.
165 # Determine the include files specified on the command line.
166 # This doesn't cover all the different option formats you can use,
167 # but it's mainly intended to avoid duplicating flags on the automatic
168 # makefile regeneration which only uses this format.
169 specified_includes
= set()
171 if arg
.startswith('-I') and len(arg
) > 2:
172 specified_includes
.add(os
.path
.realpath(arg
[2:]))
175 def AddInclude(path
):
176 if os
.path
.realpath(path
) not in specified_includes
:
179 if os
.environ
.get('GYP_INCLUDE_FIRST') != None:
180 AddInclude(os
.path
.join(chrome_src
, os
.environ
.get('GYP_INCLUDE_FIRST')))
182 # Always include common.gypi.
183 AddInclude(os
.path
.join(script_dir
, 'common.gypi'))
185 # Optionally add supplemental .gypi files if present.
186 for supplement
in supplemental_files
:
187 AddInclude(supplement
)
189 if os
.environ
.get('GYP_INCLUDE_LAST') != None:
190 AddInclude(os
.path
.join(chrome_src
, os
.environ
.get('GYP_INCLUDE_LAST')))
195 if __name__
== '__main__':
196 # Disabling garbage collection saves about 1 second out of 16 on a Linux
197 # z620 workstation. Since this is a short-lived process it's not a problem to
198 # leak a few cyclyc references in order to spare the CPU cycles for
205 use_analyzer
= len(args
) and args
[0] == '--analyzer'
208 os
.environ
['GYP_GENERATORS'] = 'analyzer'
209 args
.append('-Gconfig_path=' + args
.pop(0))
210 args
.append('-Ganalyzer_output_path=' + args
.pop(0))
212 if int(os
.environ
.get('GYP_CHROMIUM_NO_ACTION', 0)):
213 print 'Skipping gyp_chromium due to GYP_CHROMIUM_NO_ACTION env var.'
216 # Use the Psyco JIT if available.
219 print "Enabled Psyco JIT."
221 # Fall back on hermetic python if we happen to get run under cygwin.
222 # TODO(bradnelson): take this out once this issue is fixed:
223 # http://code.google.com/p/gyp/issues/detail?id=177
224 if sys
.platform
== 'cygwin':
225 import find_depot_tools
226 depot_tools_path
= find_depot_tools
.add_depot_tools_to_path()
227 python_dir
= sorted(glob
.glob(os
.path
.join(depot_tools_path
,
228 'python2*_bin')))[-1]
229 env
= os
.environ
.copy()
230 env
['PATH'] = python_dir
+ os
.pathsep
+ env
.get('PATH', '')
231 cmd
= [os
.path
.join(python_dir
, 'python.exe')] + sys
.argv
232 sys
.exit(subprocess
.call(cmd
, env
=env
))
234 # This could give false positives since it doesn't actually do real option
236 gyp_file_specified
= any(arg
.endswith('.gyp') for arg
in args
)
238 gyp_environment
.SetEnvironment()
240 # If we didn't get a file, check an env var, and then fall back to
241 # assuming 'all.gyp' from the same directory as the script.
242 if not gyp_file_specified
:
243 gyp_file
= os
.environ
.get('CHROMIUM_GYP_FILE')
245 # Note that CHROMIUM_GYP_FILE values can't have backslashes as
246 # path separators even on Windows due to the use of shlex.split().
247 args
.extend(shlex
.split(gyp_file
))
249 args
.append(os
.path
.join(script_dir
, 'all.gyp'))
251 supplemental_includes
= GetSupplementalFiles()
252 gyp_vars_dict
= GetGypVars(supplemental_includes
)
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 iOS, where a violation
257 # 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
262 if gyp_vars_dict
.get('OS') != 'ios':
263 args
.append('--no-circular-check')
265 # libtool on Mac warns about duplicate basenames in static libraries, so
266 # they're disallowed in general by gyp. We are lax on this point, so disable
267 # this check other than on Mac. GN does not use static libraries as heavily,
268 # so over time this restriction will mostly go away anyway, even on Mac.
269 # https://code.google.com/p/gyp/issues/detail?id=384
270 if sys
.platform
!= 'darwin':
271 args
.append('--no-duplicate-basename-check')
273 # We explicitly don't support the make gyp generator (crbug.com/348686). Be
274 # nice and fail here, rather than choking in gyp.
275 if re
.search(r
'(^|,|\s)make($|,|\s)', os
.environ
.get('GYP_GENERATORS', '')):
276 print 'Error: make gyp generator not supported (check GYP_GENERATORS).'
279 # We explicitly don't support the native msvs gyp generator. Be nice and
280 # fail here, rather than generating broken projects.
281 if re
.search(r
'(^|,|\s)msvs($|,|\s)', os
.environ
.get('GYP_GENERATORS', '')):
282 print 'Error: msvs gyp generator not supported (check GYP_GENERATORS).'
283 print 'Did you mean to use the `msvs-ninja` generator?'
286 # If CHROMIUM_GYP_SYNTAX_CHECK is set to 1, it will invoke gyp with --check
287 # to enfore syntax checking.
288 syntax_check
= os
.environ
.get('CHROMIUM_GYP_SYNTAX_CHECK')
289 if syntax_check
and int(syntax_check
):
290 args
.append('--check')
292 # TODO(dmikurube): Remove these checks and messages after a while.
293 if ('linux_use_tcmalloc' in gyp_vars_dict
or
294 'android_use_tcmalloc' in gyp_vars_dict
):
295 print '*****************************************************************'
296 print '"linux_use_tcmalloc" and "android_use_tcmalloc" are deprecated!'
297 print '-----------------------------------------------------------------'
298 print 'You specify "linux_use_tcmalloc" or "android_use_tcmalloc" in'
299 print 'your GYP_DEFINES. Please switch them into "use_allocator" now.'
300 print 'See http://crbug.com/345554 for the details.'
301 print '*****************************************************************'
303 # Automatically turn on crosscompile support for platforms that need it.
304 # (The Chrome OS build sets CC_host / CC_target which implicitly enables
306 if all(('ninja' in os
.environ
.get('GYP_GENERATORS', ''),
307 gyp_vars_dict
.get('OS') in ['android', 'ios'],
308 'GYP_CROSSCOMPILE' not in os
.environ
)):
309 os
.environ
['GYP_CROSSCOMPILE'] = '1'
310 if gyp_vars_dict
.get('OS') == 'android':
311 args
.append('--check')
314 ['-I' + i
for i
in additional_include_files(supplemental_includes
, args
)])
316 args
.extend(['-D', 'gyp_output_dir=' + GetOutputDirectory()])
319 print 'Updating projects from gyp files...'
323 gyp_rc
= gyp
.main(args
)
326 vs2013_runtime_dll_dirs
= vs_toolchain
.SetEnvironmentAndGetRuntimeDllDirs()
327 if vs2013_runtime_dll_dirs
:
328 x64_runtime
, x86_runtime
= vs2013_runtime_dll_dirs
329 vs_toolchain
.CopyVsRuntimeDlls(
330 os
.path
.join(chrome_src
, GetOutputDirectory()),
331 (x86_runtime
, x64_runtime
))