Upstream version 7.36.149.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_helper
26 import landmine_utils
27 import vs_toolchain
28
29 # Assume this file is in a one-level-deep subdirectory of the source root.
30 SRC_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
31
32 # Add paths so that pymod_do_main(...) can import files.
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, 'native_client', 'build'))
38 sys.path.insert(1, os.path.join(chrome_src, 'native_client_sdk', 'src',
39     'build_tools'))
40 sys.path.insert(1, os.path.join(chrome_src, 'remoting', 'tools', 'build'))
41 sys.path.insert(1, os.path.join(chrome_src, 'third_party', 'liblouis'))
42 sys.path.insert(1, os.path.join(chrome_src, 'third_party', 'WebKit',
43     'Source', 'build', 'scripts'))
44
45 # On Windows, Psyco shortens warm runs of build/gyp_chromium by about
46 # 20 seconds on a z600 machine with 12 GB of RAM, from 90 down to 70
47 # seconds.  Conversely, memory usage of build/gyp_chromium with Psyco
48 # maxes out at about 158 MB vs. 132 MB without it.
49 #
50 # Psyco uses native libraries, so we need to load a different
51 # installation depending on which OS we are running under. It has not
52 # been tested whether using Psyco on our Mac and Linux builds is worth
53 # it (the GYP running time is a lot shorter, so the JIT startup cost
54 # may not be worth it).
55 if sys.platform == 'win32':
56   try:
57     sys.path.insert(0, os.path.join(chrome_src, 'third_party', 'psyco_win32'))
58     import psyco
59   except:
60     psyco = None
61 else:
62   psyco = None
63
64
65 def GetSupplementalFiles():
66   """Returns a list of the supplemental files that are included in all GYP
67   sources."""
68   return glob.glob(os.path.join(chrome_src, '*', 'supplement.gypi'))
69
70
71 def ProcessGypDefinesItems(items):
72   """Converts a list of strings to a list of key-value pairs."""
73   result = []
74   for item in items:
75     tokens = item.split('=', 1)
76     # Some GYP variables have hyphens, which we don't support.
77     if len(tokens) == 2:
78       result += [(tokens[0], tokens[1])]
79     else:
80       # No value supplied, treat it as a boolean and set it. Note that we
81       # use the string '1' here so we have a consistent definition whether
82       # you do 'foo=1' or 'foo'.
83       result += [(tokens[0], '1')]
84   return result
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 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):]
150
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):]
156
157   return "out"
158
159
160 def additional_include_files(supplemental_files, args=[]):
161   """
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.
165   """
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:]))
174
175   result = []
176   def AddInclude(path):
177     if os.path.realpath(path) not in specified_includes:
178       result.append(path)
179
180   # Include xwalk common.gypi to effect chromium source tree.
181   AddInclude(os.path.join(xwalk_dir, 'build', 'common.gypi'))
182
183   # Always include common.gypi.
184   AddInclude(os.path.join(chrome_src, 'build', 'common.gypi'))
185
186   # Optionally add supplemental .gypi files if present.
187   for supplement in supplemental_files:
188     AddInclude(supplement)
189
190   return result
191
192
193 if __name__ == '__main__':
194   args = sys.argv[1:]
195
196   if int(os.environ.get('GYP_CHROMIUM_NO_ACTION', 0)):
197     print 'Skipping gyp_chromium due to GYP_CHROMIUM_NO_ACTION env var.'
198     sys.exit(0)
199
200   # Support external media types capability such as MP4/MP3.
201   args = list(set(args))
202   delist = []
203   ip_media_codecs = False # Default: no third-party codecs be build in.
204   for arg in args:
205     if arg.startswith('-Dproprietary_codecs') or arg.startswith('-Dffmpeg_branding'):
206       continue
207     elif arg == '-Dmediacodecs_EULA=1':
208       ip_media_codecs = True  # Exception: mediacodecs_EULA be enabled.
209     else:
210       delist.append(arg)
211
212   args = delist
213   args.append('-Dproprietary_codecs=1')
214
215   # Triggering media playback dynamically with third-party codecs by owner.
216   if ip_media_codecs == True:
217       args.append('-Dffmpeg_branding=Chrome')
218
219   # Use the Psyco JIT if available.
220   if psyco:
221     psyco.profile()
222     print "Enabled Psyco JIT."
223
224   # Fall back on hermetic python if we happen to get run under cygwin.
225   # TODO(bradnelson): take this out once this issue is fixed:
226   #    http://code.google.com/p/gyp/issues/detail?id=177
227   if sys.platform == 'cygwin':
228     import find_depot_tools
229     depot_tools_path = find_depot_tools.add_depot_tools_to_path()
230     python_dir = sorted(glob.glob(os.path.join(depot_tools_path,
231                                                'python2*_bin')))[-1]
232     env = os.environ.copy()
233     env['PATH'] = python_dir + os.pathsep + env.get('PATH', '')
234     p = subprocess.Popen(
235        [os.path.join(python_dir, 'python.exe')] + sys.argv,
236        env=env, shell=False)
237     p.communicate()
238     sys.exit(p.returncode)
239
240   gyp_helper.apply_chromium_gyp_env()
241
242   # This could give false positives since it doesn't actually do real option
243   # parsing.  Oh well.
244   gyp_file_specified = False
245   for arg in args:
246     if arg.endswith('.gyp'):
247       gyp_file_specified = True
248       break
249
250   # If we didn't get a file, check an env var, and then fall back to
251   # assuming 'all.gyp' from the same directory as the script.
252   if not gyp_file_specified:
253     gyp_file = os.environ.get('CHROMIUM_GYP_FILE')
254     if gyp_file:
255       # Note that CHROMIUM_GYP_FILE values can't have backslashes as
256       # path separators even on Windows due to the use of shlex.split().
257       args.extend(shlex.split(gyp_file))
258     else:
259       args.append(os.path.join(xwalk_dir, 'xwalk.gyp'))
260
261   # There shouldn't be a circular dependency relationship between .gyp files,
262   # but in Chromium's .gyp files, on non-Mac platforms, circular relationships
263   # currently exist.  The check for circular dependencies is currently
264   # bypassed on other platforms, but is left enabled on the Mac, where a
265   # violation of the rule causes Xcode to misbehave badly.
266   # TODO(mark): Find and kill remaining circular dependencies, and remove this
267   # option.  http://crbug.com/35878.
268   # TODO(tc): Fix circular dependencies in ChromiumOS then add linux2 to the
269   # list.
270   # TODO(tmpsantos): Make runtime a proper module and enable the circular check
271   # back for Mac.
272   args.append('--no-circular-check')
273
274   # We explicitly don't support the make gyp generator (crbug.com/348686). Be
275   # nice and fail here, rather than choking in gyp.
276   if re.search(r'(^|,|\s)make($|,|\s)', os.environ.get('GYP_GENERATORS', '')):
277     print 'Error: make gyp generator not supported (check GYP_GENERATORS).'
278     sys.exit(1)
279
280   # Default to ninja on linux and windows, but only if no generator has
281   # explicitly been set.
282   # Also default to ninja on mac, but only when not building chrome/ios.
283   # . -f / --format has precedence over the env var, no need to check for it
284   # . set the env var only if it hasn't been set yet
285   # . chromium.gyp_env has been applied to os.environ at this point already
286   if sys.platform.startswith(('linux', 'win', 'freebsd')) and \
287       not os.environ.get('GYP_GENERATORS'):
288     os.environ['GYP_GENERATORS'] = 'ninja'
289   elif sys.platform == 'darwin' and not os.environ.get('GYP_GENERATORS') and \
290       not 'OS=ios' in os.environ.get('GYP_DEFINES', []):
291     os.environ['GYP_GENERATORS'] = 'ninja'
292
293   vs2013_runtime_dll_dirs = vs_toolchain.SetEnvironmentAndGetRuntimeDllDirs()
294
295   # If CHROMIUM_GYP_SYNTAX_CHECK is set to 1, it will invoke gyp with --check
296   # to enfore syntax checking.
297   syntax_check = os.environ.get('CHROMIUM_GYP_SYNTAX_CHECK')
298   if syntax_check and int(syntax_check):
299     args.append('--check')
300
301   supplemental_includes = GetSupplementalFiles()
302   gyp_vars_dict = GetGypVars(supplemental_includes)
303
304   # Automatically turn on crosscompile support for platforms that need it.
305   # (The Chrome OS build sets CC_host / CC_target which implicitly enables
306   # this mode.)
307   if all(('ninja' in os.environ.get('GYP_GENERATORS', ''),
308           gyp_vars_dict.get('OS') in ['android', 'ios'],
309           'GYP_CROSSCOMPILE' not in os.environ)):
310     os.environ['GYP_CROSSCOMPILE'] = '1'
311   if gyp_vars_dict.get('OS') == 'android':
312     args.append('--check')
313
314   args.extend(
315       ['-I' + i for i in additional_include_files(supplemental_includes, args)])
316
317   args.extend(['-D', 'gyp_output_dir=' + GetOutputDirectory()])
318
319   # Enable Web Audio by default on Android x86
320   if gyp_vars_dict.get('OS') == 'android':
321     args.append('-Duse_openmax_dl_fft=1')
322
323   # Enable Aura by default on all platforms except Android
324   if gyp_vars_dict.get('OS') != 'android' and gyp_vars_dict.get('OS') != 'mac':
325     args.append('-Duse_aura=1')
326
327   if gyp_vars_dict.get('OS') == 'android':
328     args.append('-Dnotifications=1')
329     args.append('-Drelease_unwind_tables=0')
330
331   print 'Updating projects from gyp files...'
332   sys.stdout.flush()
333
334   # Off we go...
335   gyp_rc = gyp.main(args)
336
337   # Check for landmines (reasons to clobber the build). This must be run here,
338   # rather than a separate runhooks step so that any environment modifications
339   # from above are picked up.
340   print 'Running build/landmines.py...'
341   subprocess.check_call(
342       [sys.executable, os.path.join(chrome_src, 'build/landmines.py')])
343
344   if vs2013_runtime_dll_dirs:
345     x64_runtime, x86_runtime = vs2013_runtime_dll_dirs
346     vs_toolchain.CopyVsRuntimeDlls(
347         os.path.join(chrome_src, GetOutputDirectory()),
348         (x86_runtime, x64_runtime))
349
350   sys.exit(gyp_rc)