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 8It is done by first building it manually in a temporary directory, then building 9it with its own BUILD.gn to the final destination. 10""" 11 12import contextlib 13import logging 14import optparse 15import os 16import shutil 17import subprocess 18import sys 19import tempfile 20 21BOOTSTRAP_DIR = os.path.dirname(os.path.abspath(__file__)) 22GN_ROOT = os.path.dirname(BOOTSTRAP_DIR) 23SRC_ROOT = os.path.dirname(os.path.dirname(GN_ROOT)) 24 25 26def is_linux(): 27 return sys.platform.startswith('linux') 28 29 30def check_call(cmd, **kwargs): 31 logging.debug('Running: %s', ' '.join(cmd)) 32 subprocess.check_call(cmd, cwd=GN_ROOT, **kwargs) 33 34 35@contextlib.contextmanager 36def scoped_tempdir(): 37 path = tempfile.mkdtemp() 38 try: 39 yield path 40 finally: 41 shutil.rmtree(path) 42 43 44def main(argv): 45 parser = optparse.OptionParser(description=sys.modules[__name__].__doc__) 46 parser.add_option('-d', '--debug', action='store_true', 47 help='Do a debug build. Defaults to release build.') 48 parser.add_option('-o', '--output', 49 help='place output in PATH', metavar='PATH') 50 parser.add_option('-v', '--verbose', action='store_true', 51 help='Log more details') 52 options, args = parser.parse_args(argv) 53 54 if args: 55 parser.error('Unrecognized command line arguments: %s.' % ', '.join(args)) 56 57 logging.basicConfig(level=logging.DEBUG if options.verbose else logging.ERROR) 58 59 if options.debug: 60 build_rel = os.path.join('out', 'Debug') 61 else: 62 build_rel = os.path.join('out', 'Release') 63 build_root = os.path.join(SRC_ROOT, build_rel) 64 65 try: 66 with scoped_tempdir() as tempdir: 67 print 'Building gn manually in a temporary directory for bootstrapping...' 68 build_gn_with_ninja_manually(tempdir) 69 70 print 'Building gn using itself to %s...' % build_rel 71 build_gn_with_gn(os.path.join(tempdir, 'gn'), build_rel, options.debug) 72 73 if options.output: 74 # Preserve the executable permission bit. 75 shutil.copy2(os.path.join(build_root, 'gn'), options.output) 76 except subprocess.CalledProcessError as e: 77 print >> sys.stderr, str(e) 78 return 1 79 return 0 80 81 82def build_gn_with_ninja_manually(tempdir): 83 write_ninja(os.path.join(tempdir, 'build.ninja')) 84 check_call(['ninja', '-C', tempdir, 'gn']) 85 86 87def write_ninja(path): 88 cflags = os.environ.get('CFLAGS', '').split() 89 ldflags = os.environ.get('LDFLAGS', '').split() 90 include_dirs = [SRC_ROOT] 91 libs = [] 92 93 static_libraries = { 94 'base': {'sources': [], 'tool': 'cxx'}, 95 'dynamic_annotations': {'sources': [], 'tool': 'cc'}, 96 'gn': {'sources': [], 'tool': 'cxx'}, 97 } 98 99 for name in os.listdir(GN_ROOT): 100 if not name.endswith('.cc'): 101 continue 102 if name.endswith('_unittest.cc'): 103 continue 104 if name in ['generate_test_gn_data.cc']: 105 continue 106 full_path = os.path.join(GN_ROOT, name) 107 static_libraries['gn']['sources'].append( 108 os.path.relpath(full_path, SRC_ROOT)) 109 110 static_libraries['dynamic_annotations']['sources'].extend([ 111 'base/third_party/dynamic_annotations/dynamic_annotations.c', 112 ]) 113 static_libraries['base']['sources'].extend([ 114 'base/at_exit.cc', 115 'base/atomicops_internals_x86_gcc.cc', 116 'base/base_paths.cc', 117 'base/base_switches.cc', 118 'base/callback_internal.cc', 119 'base/command_line.cc', 120 'base/debug/alias.cc', 121 'base/debug/stack_trace.cc', 122 'base/debug/trace_event_impl.cc', 123 'base/debug/trace_event_impl_constants.cc', 124 'base/debug/trace_event_memory.cc', 125 'base/debug/trace_event_synthetic_delay.cc', 126 'base/environment.cc', 127 'base/file_util.cc', 128 'base/files/file.cc', 129 'base/files/file_enumerator.cc', 130 'base/files/file_path.cc', 131 'base/files/file_path_constants.cc', 132 'base/files/scoped_file.cc', 133 'base/json/json_parser.cc', 134 'base/json/json_reader.cc', 135 'base/json/json_string_value_serializer.cc', 136 'base/json/json_writer.cc', 137 'base/json/string_escape.cc', 138 'base/lazy_instance.cc', 139 'base/location.cc', 140 'base/logging.cc', 141 'base/memory/ref_counted.cc', 142 'base/memory/ref_counted_memory.cc', 143 'base/memory/singleton.cc', 144 'base/memory/weak_ptr.cc', 145 'base/message_loop/incoming_task_queue.cc', 146 'base/message_loop/message_loop.cc', 147 'base/message_loop/message_loop_proxy.cc', 148 'base/message_loop/message_loop_proxy_impl.cc', 149 'base/message_loop/message_pump.cc', 150 'base/message_loop/message_pump_default.cc', 151 'base/metrics/bucket_ranges.cc', 152 'base/metrics/histogram.cc', 153 'base/metrics/histogram_base.cc', 154 'base/metrics/histogram_samples.cc', 155 'base/metrics/sample_map.cc', 156 'base/metrics/sample_vector.cc', 157 'base/metrics/sparse_histogram.cc', 158 'base/metrics/statistics_recorder.cc', 159 'base/path_service.cc', 160 'base/pending_task.cc', 161 'base/pickle.cc', 162 'base/process/kill.cc', 163 'base/process/process_iterator.cc', 164 'base/process/process_metrics.cc', 165 'base/profiler/alternate_timer.cc', 166 'base/profiler/tracked_time.cc', 167 'base/run_loop.cc', 168 'base/sequence_checker_impl.cc', 169 'base/sequenced_task_runner.cc', 170 'base/strings/string16.cc', 171 'base/strings/string_number_conversions.cc', 172 'base/strings/string_piece.cc', 173 'base/strings/string_split.cc', 174 'base/strings/string_util.cc', 175 'base/strings/string_util_constants.cc', 176 'base/strings/stringprintf.cc', 177 'base/strings/utf_string_conversion_utils.cc', 178 'base/strings/utf_string_conversions.cc', 179 'base/synchronization/cancellation_flag.cc', 180 'base/synchronization/lock.cc', 181 'base/sys_info.cc', 182 'base/task_runner.cc', 183 'base/third_party/dmg_fp/dtoa_wrapper.cc', 184 'base/third_party/dmg_fp/g_fmt.cc', 185 'base/third_party/icu/icu_utf.cc', 186 'base/third_party/nspr/prtime.cc', 187 'base/thread_task_runner_handle.cc', 188 'base/threading/non_thread_safe_impl.cc', 189 'base/threading/post_task_and_reply_impl.cc', 190 'base/threading/sequenced_worker_pool.cc', 191 'base/threading/simple_thread.cc', 192 'base/threading/thread_checker_impl.cc', 193 'base/threading/thread_collision_warner.cc', 194 'base/threading/thread_id_name_manager.cc', 195 'base/threading/thread_local_storage.cc', 196 'base/threading/thread_restrictions.cc', 197 'base/time/time.cc', 198 'base/timer/elapsed_timer.cc', 199 'base/timer/timer.cc', 200 'base/tracked_objects.cc', 201 'base/tracking_info.cc', 202 'base/values.cc', 203 'base/vlog.cc', 204 ]) 205 206 if is_linux(): 207 static_libraries['libevent'] = { 208 'sources': [ 209 'third_party/libevent/buffer.c', 210 'third_party/libevent/epoll.c', 211 'third_party/libevent/evbuffer.c', 212 'third_party/libevent/evdns.c', 213 'third_party/libevent/event.c', 214 'third_party/libevent/event_tagging.c', 215 'third_party/libevent/evrpc.c', 216 'third_party/libevent/evutil.c', 217 'third_party/libevent/http.c', 218 'third_party/libevent/log.c', 219 'third_party/libevent/poll.c', 220 'third_party/libevent/select.c', 221 'third_party/libevent/signal.c', 222 'third_party/libevent/strlcpy.c', 223 ], 224 'tool': 'cc', 225 'include_dirs': [ 226 os.path.join(SRC_ROOT, 'third_party', 'libevent', 'linux') 227 ], 228 'cflags': cflags + ['-DHAVE_CONFIG_H'], 229 } 230 static_libraries['xdg_user_dirs'] = { 231 'sources': [ 232 'base/third_party/xdg_user_dirs/xdg_user_dir_lookup.cc', 233 ], 234 'tool': 'cxx', 235 } 236 static_libraries['base']['sources'].extend([ 237 'base/base_paths_posix.cc', 238 'base/debug/debugger_posix.cc', 239 'base/debug/stack_trace_posix.cc', 240 'base/file_util_posix.cc', 241 'base/files/file_enumerator_posix.cc', 242 'base/files/file_posix.cc', 243 'base/message_loop/message_pump_glib.cc', 244 'base/message_loop/message_pump_libevent.cc', 245 'base/nix/xdg_util.cc', 246 'base/posix/file_descriptor_shuffle.cc', 247 'base/process/internal_linux.cc', 248 'base/process/kill_posix.cc', 249 'base/process/process_handle_linux.cc', 250 'base/process/process_handle_posix.cc', 251 'base/process/process_iterator_linux.cc', 252 'base/process/process_linux.cc', 253 'base/process/process_metrics_linux.cc', 254 'base/process/process_metrics_posix.cc', 255 'base/process/process_posix.cc', 256 'base/safe_strerror_posix.cc', 257 'base/strings/sys_string_conversions_posix.cc', 258 'base/synchronization/condition_variable_posix.cc', 259 'base/synchronization/lock_impl_posix.cc', 260 'base/synchronization/waitable_event_posix.cc', 261 'base/sys_info_linux.cc', 262 'base/sys_info_posix.cc', 263 'base/threading/platform_thread_linux.cc', 264 'base/threading/platform_thread_posix.cc', 265 'base/threading/thread_local_posix.cc', 266 'base/threading/thread_local_storage_posix.cc', 267 'base/time/time_posix.cc', 268 ]) 269 270 cflags.extend(['-O2', '-pthread', '-pipe']) 271 272 static_libraries['base'].setdefault('cflags', []).extend( 273 subprocess.check_output( 274 ['pkg-config', 'gtk+-2.0', 'x11', '--cflags']).split()) 275 ldflags.extend(['-pthread']) 276 ldflags.extend(subprocess.check_output( 277 ['pkg-config', 'gtk+-2.0', 'x11', 278 '--libs-only-L', '--libs-only-other']).split()) 279 libs.extend(subprocess.check_output( 280 ['pkg-config', 'gtk+-2.0', 'x11', '--libs-only-l']).split()) 281 282 with open(os.path.join(GN_ROOT, 'bootstrap', 'build.ninja.template')) as f: 283 ninja_template = f.read() 284 285 def src_to_obj(path): 286 return '%s' % os.path.splitext(path)[0] + '.o' 287 288 ninja_lines = [] 289 for library, settings in static_libraries.iteritems(): 290 for src_file in settings['sources']: 291 ninja_lines.extend([ 292 'build %s: %s %s' % (src_to_obj(src_file), 293 settings['tool'], 294 os.path.join(SRC_ROOT, src_file)), 295 ' includes = %s' % ' '.join( 296 ['-I' + dirname for dirname in 297 include_dirs + settings.get('include_dirs', [])]), 298 ' cflags = %s' % ' '.join(cflags + settings.get('cflags', [])), 299 ]) 300 301 ninja_lines.append('build %s.a: alink_thin %s' % ( 302 library, 303 ' '.join([src_to_obj(src_file) for src_file in settings['sources']]))) 304 305 ninja_lines.extend([ 306 'build gn: link %s' % ( 307 ' '.join(['%s.a' % library for library in static_libraries])), 308 ' ld = $ldxx', 309 ' ldflags = %s' % ' '.join(ldflags), 310 ' libs = %s' % ' '.join(libs), 311 '', # Make sure the file ends with a newline. 312 ]) 313 314 with open(path, 'w') as f: 315 f.write(ninja_template + '\n'.join(ninja_lines)) 316 317 318def build_gn_with_gn(temp_gn, build_dir, debug): 319 cmd = [temp_gn, 'gen', build_dir] 320 if not debug: 321 cmd.append('--args=is_debug=false') 322 check_call(cmd) 323 check_call(['ninja', '-C', build_dir, 'gn']) 324 if not debug: 325 check_call(['strip', os.path.join(build_dir, 'gn')]) 326 327 328if __name__ == '__main__': 329 sys.exit(main(sys.argv[1:])) 330