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