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