Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / tools / gn / bootstrap / bootstrap.py
1 #!/usr/bin/env python
2 # Copyright 2014 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5
6 """Bootstraps gn.
7
8 It is done by first building it manually in a temporary directory, then building
9 it with its own BUILD.gn to the final destination.
10 """
11
12 import contextlib
13 import errno
14 import logging
15 import optparse
16 import os
17 import shutil
18 import subprocess
19 import sys
20 import tempfile
21
22 BOOTSTRAP_DIR = os.path.dirname(os.path.abspath(__file__))
23 GN_ROOT = os.path.dirname(BOOTSTRAP_DIR)
24 SRC_ROOT = os.path.dirname(os.path.dirname(GN_ROOT))
25
26 is_linux = sys.platform.startswith('linux')
27 is_mac = sys.platform.startswith('darwin')
28 is_posix = is_linux or is_mac
29
30 def check_call(cmd, **kwargs):
31   logging.debug('Running: %s', ' '.join(cmd))
32   subprocess.check_call(cmd, cwd=GN_ROOT, **kwargs)
33
34 def mkdir_p(path):
35   try:
36     os.makedirs(path)
37   except OSError as e:
38     if e.errno == errno.EEXIST and os.path.isdir(path):
39       pass
40     else: raise
41
42 @contextlib.contextmanager
43 def scoped_tempdir():
44   path = tempfile.mkdtemp()
45   try:
46     yield path
47   finally:
48     shutil.rmtree(path)
49
50
51 def main(argv):
52   parser = optparse.OptionParser(description=sys.modules[__name__].__doc__)
53   parser.add_option('-d', '--debug', action='store_true',
54                     help='Do a debug build. Defaults to release build.')
55   parser.add_option('-o', '--output',
56                     help='place output in PATH', metavar='PATH')
57   parser.add_option('-s', '--no-rebuild', action='store_true',
58                     help='Do not rebuild GN with GN.')
59   parser.add_option('-v', '--verbose', action='store_true',
60                     help='Log more details')
61   options, args = parser.parse_args(argv)
62
63   if args:
64     parser.error('Unrecognized command line arguments: %s.' % ', '.join(args))
65
66   logging.basicConfig(level=logging.DEBUG if options.verbose else logging.ERROR)
67
68   if options.debug:
69     build_rel = os.path.join('out', 'Debug')
70   else:
71     build_rel = os.path.join('out', 'Release')
72   build_root = os.path.join(SRC_ROOT, build_rel)
73
74   try:
75     with scoped_tempdir() as tempdir:
76       print 'Building gn manually in a temporary directory for bootstrapping...'
77       build_gn_with_ninja_manually(tempdir, options)
78       temp_gn = os.path.join(tempdir, 'gn')
79       out_gn = os.path.join(build_root, 'gn')
80
81       if options.no_rebuild:
82         mkdir_p(build_root)
83         shutil.copy2(temp_gn, out_gn)
84       else:
85         print 'Building gn using itself to %s...' % build_rel
86         build_gn_with_gn(temp_gn, build_rel, options)
87
88       if options.output:
89         # Preserve the executable permission bit.
90         shutil.copy2(out_gn, options.output)
91   except subprocess.CalledProcessError as e:
92     print >> sys.stderr, str(e)
93     return 1
94   return 0
95
96
97 def build_gn_with_ninja_manually(tempdir, options):
98   write_ninja(os.path.join(tempdir, 'build.ninja'), options)
99   cmd = ['ninja', '-C', tempdir]
100   if options.verbose:
101     cmd.append('-v')
102   cmd.append('gn')
103   check_call(cmd)
104
105 def write_ninja(path, options):
106   cc = os.environ.get('CC', '')
107   cxx = os.environ.get('CXX', '')
108   cflags = os.environ.get('CFLAGS', '').split()
109   cflags_cc = os.environ.get('CXXFLAGS', '').split()
110   ld = os.environ.get('LD', cxx)
111   ldflags = os.environ.get('LDFLAGS', '').split()
112   include_dirs = [SRC_ROOT]
113   libs = []
114
115   if is_posix:
116     if options.debug:
117       cflags.extend(['-O0', '-g'])
118     else:
119       cflags.extend(['-O2', '-g0'])
120
121     cflags.extend(['-D_FILE_OFFSET_BITS=64', '-pthread', '-pipe'])
122     cflags_cc.extend(['-std=gnu++11', '-Wno-c++11-narrowing'])
123
124   static_libraries = {
125       'base': {'sources': [], 'tool': 'cxx'},
126       'dynamic_annotations': {'sources': [], 'tool': 'cc'},
127       'gn': {'sources': [], 'tool': 'cxx'},
128   }
129
130   for name in os.listdir(GN_ROOT):
131     if not name.endswith('.cc'):
132       continue
133     if name.endswith('_unittest.cc'):
134       continue
135     if name in ['generate_test_gn_data.cc', 'run_all_unittests.cc']:
136       continue
137     full_path = os.path.join(GN_ROOT, name)
138     static_libraries['gn']['sources'].append(
139         os.path.relpath(full_path, SRC_ROOT))
140
141   static_libraries['dynamic_annotations']['sources'].extend([
142       'base/third_party/dynamic_annotations/dynamic_annotations.c',
143   ])
144   static_libraries['base']['sources'].extend([
145       'base/at_exit.cc',
146       'base/atomicops_internals_x86_gcc.cc',
147       'base/base_paths.cc',
148       'base/base_switches.cc',
149       'base/callback_internal.cc',
150       'base/command_line.cc',
151       'base/debug/alias.cc',
152       'base/debug/stack_trace.cc',
153       'base/debug/task_annotator.cc',
154       'base/debug/trace_event_impl.cc',
155       'base/debug/trace_event_impl_constants.cc',
156       'base/debug/trace_event_memory.cc',
157       'base/debug/trace_event_synthetic_delay.cc',
158       'base/environment.cc',
159       'base/files/file.cc',
160       'base/files/file_enumerator.cc',
161       'base/files/file_path.cc',
162       'base/files/file_path_constants.cc',
163       'base/files/file_util.cc',
164       'base/files/scoped_file.cc',
165       'base/json/json_parser.cc',
166       'base/json/json_reader.cc',
167       'base/json/json_string_value_serializer.cc',
168       'base/json/json_writer.cc',
169       'base/json/string_escape.cc',
170       'base/lazy_instance.cc',
171       'base/location.cc',
172       'base/logging.cc',
173       'base/memory/ref_counted.cc',
174       'base/memory/ref_counted_memory.cc',
175       'base/memory/singleton.cc',
176       'base/memory/weak_ptr.cc',
177       'base/message_loop/incoming_task_queue.cc',
178       'base/message_loop/message_loop.cc',
179       'base/message_loop/message_loop_proxy.cc',
180       'base/message_loop/message_loop_proxy_impl.cc',
181       'base/message_loop/message_pump.cc',
182       'base/message_loop/message_pump_default.cc',
183       'base/metrics/bucket_ranges.cc',
184       'base/metrics/histogram.cc',
185       'base/metrics/histogram_base.cc',
186       'base/metrics/histogram_samples.cc',
187       'base/metrics/sample_map.cc',
188       'base/metrics/sample_vector.cc',
189       'base/metrics/sparse_histogram.cc',
190       'base/metrics/statistics_recorder.cc',
191       'base/path_service.cc',
192       'base/pending_task.cc',
193       'base/pickle.cc',
194       'base/process/kill.cc',
195       'base/process/process_iterator.cc',
196       'base/process/process_metrics.cc',
197       'base/profiler/alternate_timer.cc',
198       'base/profiler/tracked_time.cc',
199       'base/run_loop.cc',
200       'base/sequence_checker_impl.cc',
201       'base/sequenced_task_runner.cc',
202       'base/strings/string16.cc',
203       'base/strings/string_number_conversions.cc',
204       'base/strings/string_piece.cc',
205       'base/strings/string_split.cc',
206       'base/strings/string_util.cc',
207       'base/strings/string_util_constants.cc',
208       'base/strings/stringprintf.cc',
209       'base/strings/utf_string_conversion_utils.cc',
210       'base/strings/utf_string_conversions.cc',
211       'base/synchronization/cancellation_flag.cc',
212       'base/synchronization/lock.cc',
213       'base/sys_info.cc',
214       'base/task_runner.cc',
215       'base/third_party/dmg_fp/dtoa_wrapper.cc',
216       'base/third_party/dmg_fp/g_fmt.cc',
217       'base/third_party/icu/icu_utf.cc',
218       'base/third_party/nspr/prtime.cc',
219       'base/thread_task_runner_handle.cc',
220       'base/threading/non_thread_safe_impl.cc',
221       'base/threading/post_task_and_reply_impl.cc',
222       'base/threading/sequenced_worker_pool.cc',
223       'base/threading/simple_thread.cc',
224       'base/threading/thread_checker_impl.cc',
225       'base/threading/thread_collision_warner.cc',
226       'base/threading/thread_id_name_manager.cc',
227       'base/threading/thread_local_storage.cc',
228       'base/threading/thread_restrictions.cc',
229       'base/time/time.cc',
230       'base/timer/elapsed_timer.cc',
231       'base/timer/timer.cc',
232       'base/tracked_objects.cc',
233       'base/tracking_info.cc',
234       'base/values.cc',
235       'base/vlog.cc',
236   ])
237
238   if is_posix:
239     static_libraries['base']['sources'].extend([
240         'base/base_paths_posix.cc',
241         'base/debug/debugger_posix.cc',
242         'base/debug/stack_trace_posix.cc',
243         'base/files/file_enumerator_posix.cc',
244         'base/files/file_posix.cc',
245         'base/files/file_util_posix.cc',
246         'base/message_loop/message_pump_libevent.cc',
247         'base/posix/file_descriptor_shuffle.cc',
248         'base/process/kill_posix.cc',
249         'base/process/process_handle_posix.cc',
250         'base/process/process_metrics_posix.cc',
251         'base/process/process_posix.cc',
252         'base/safe_strerror_posix.cc',
253         'base/synchronization/condition_variable_posix.cc',
254         'base/synchronization/lock_impl_posix.cc',
255         'base/synchronization/waitable_event_posix.cc',
256         'base/sys_info_posix.cc',
257         'base/threading/platform_thread_posix.cc',
258         'base/threading/thread_local_posix.cc',
259         'base/threading/thread_local_storage_posix.cc',
260         'base/time/time_posix.cc',
261     ])
262     static_libraries['libevent'] = {
263         'sources': [
264             'third_party/libevent/buffer.c',
265             'third_party/libevent/evbuffer.c',
266             'third_party/libevent/evdns.c',
267             'third_party/libevent/event.c',
268             'third_party/libevent/event_tagging.c',
269             'third_party/libevent/evrpc.c',
270             'third_party/libevent/evutil.c',
271             'third_party/libevent/http.c',
272             'third_party/libevent/log.c',
273             'third_party/libevent/poll.c',
274             'third_party/libevent/select.c',
275             'third_party/libevent/signal.c',
276             'third_party/libevent/strlcpy.c',
277         ],
278         'tool': 'cc',
279         'include_dirs': [],
280         'cflags': cflags + ['-DHAVE_CONFIG_H'],
281     }
282
283
284   if is_linux:
285     libs.extend(['-lrt'])
286     ldflags.extend(['-pthread'])
287
288     static_libraries['xdg_user_dirs'] = {
289         'sources': [
290             'base/third_party/xdg_user_dirs/xdg_user_dir_lookup.cc',
291         ],
292         'tool': 'cxx',
293     }
294     static_libraries['base']['sources'].extend([
295         'base/nix/xdg_util.cc',
296         'base/process/internal_linux.cc',
297         'base/process/process_handle_linux.cc',
298         'base/process/process_iterator_linux.cc',
299         'base/process/process_linux.cc',
300         'base/process/process_metrics_linux.cc',
301         'base/strings/sys_string_conversions_posix.cc',
302         'base/sys_info_linux.cc',
303         'base/threading/platform_thread_linux.cc',
304     ])
305     static_libraries['libevent']['include_dirs'].extend([
306         os.path.join(SRC_ROOT, 'third_party', 'libevent', 'linux')
307     ])
308     static_libraries['libevent']['sources'].extend([
309         'third_party/libevent/epoll.c',
310     ])
311
312
313   if is_mac:
314     static_libraries['base']['sources'].extend([
315         'base/base_paths_mac.mm',
316         'base/files/file_util_mac.mm',
317         'base/mac/bundle_locations.mm',
318         'base/mac/foundation_util.mm',
319         'base/mac/mach_logging.cc',
320         'base/mac/scoped_mach_port.cc',
321         'base/mac/scoped_nsautorelease_pool.mm',
322         'base/message_loop/message_pump_mac.mm',
323         'base/process/process_handle_mac.cc',
324         'base/process/process_iterator_mac.cc',
325         'base/strings/sys_string_conversions_mac.mm',
326         'base/time/time_mac.cc',
327         'base/threading/platform_thread_mac.mm',
328     ])
329     static_libraries['libevent']['include_dirs'].extend([
330         os.path.join(SRC_ROOT, 'third_party', 'libevent', 'mac')
331     ])
332     static_libraries['libevent']['sources'].extend([
333         'third_party/libevent/kqueue.c',
334     ])
335
336
337   if is_mac:
338     template_filename = 'build_mac.ninja.template'
339   else:
340     template_filename = 'build.ninja.template'
341
342   with open(os.path.join(GN_ROOT, 'bootstrap', template_filename)) as f:
343     ninja_template = f.read()
344
345   def src_to_obj(path):
346     return '%s' % os.path.splitext(path)[0] + '.o'
347
348   ninja_lines = []
349   for library, settings in static_libraries.iteritems():
350     for src_file in settings['sources']:
351       ninja_lines.extend([
352           'build %s: %s %s' % (src_to_obj(src_file),
353                                settings['tool'],
354                                os.path.join(SRC_ROOT, src_file)),
355           '  includes = %s' % ' '.join(
356               ['-I' + dirname for dirname in
357                include_dirs + settings.get('include_dirs', [])]),
358           '  cflags = %s' % ' '.join(cflags + settings.get('cflags', [])),
359           '  cflags_cc = %s' %
360               ' '.join(cflags_cc + settings.get('cflags_cc', [])),
361       ])
362       if cc:
363         ninja_lines.append('  cc = %s' % cc)
364       if cxx:
365         ninja_lines.append('  cxx = %s' % cxx)
366
367     ninja_lines.append('build %s.a: alink_thin %s' % (
368         library,
369         ' '.join([src_to_obj(src_file) for src_file in settings['sources']])))
370
371   if is_mac:
372     libs.extend([
373         '-framework', 'AppKit',
374         '-framework', 'CoreFoundation',
375         '-framework', 'Foundation',
376         '-framework', 'Security',
377     ]);
378
379   ninja_lines.extend([
380       'build gn: link %s' % (
381           ' '.join(['%s.a' % library for library in static_libraries])),
382       '  ldflags = %s' % ' '.join(ldflags),
383       '  libs = %s' % ' '.join(libs),
384   ])
385   if ld:
386     ninja_lines.append('  ld = %s' % ld)
387   else:
388     ninja_lines.append('  ld = $ldxx')
389
390   ninja_lines.append('')  # Make sure the file ends with a newline.
391
392   with open(path, 'w') as f:
393     f.write(ninja_template + '\n'.join(ninja_lines))
394
395
396 def build_gn_with_gn(temp_gn, build_dir, options):
397   cmd = [temp_gn, 'gen', build_dir]
398   if not options.debug:
399     cmd.append('--args=is_debug=false')
400   check_call(cmd)
401
402   cmd = ['ninja', '-C', build_dir]
403   if options.verbose:
404     cmd.append('-v')
405   cmd.append('gn')
406   check_call(cmd)
407
408   if not debug:
409     check_call(['strip', os.path.join(build_dir, 'gn')])
410
411
412 if __name__ == '__main__':
413   sys.exit(main(sys.argv[1:]))