Chromium Code Reviews| Index: tools/gn/bootstrap/bootstrap.py | 
| diff --git a/tools/gn/bootstrap/bootstrap.py b/tools/gn/bootstrap/bootstrap.py | 
| index 72ffd6093d22dfa993f523ed425bcec8d3320b02..b2b8835ed7824ef85eb02ba7df2b346f8def03db 100755 | 
| --- a/tools/gn/bootstrap/bootstrap.py | 
| +++ b/tools/gn/bootstrap/bootstrap.py | 
| @@ -29,12 +29,15 @@ BOOTSTRAP_DIR = os.path.dirname(os.path.abspath(__file__)) | 
| GN_ROOT = os.path.dirname(BOOTSTRAP_DIR) | 
| SRC_ROOT = os.path.dirname(os.path.dirname(GN_ROOT)) | 
| +is_win = sys.platform.startswith('win') | 
| is_linux = sys.platform.startswith('linux') | 
| is_mac = sys.platform.startswith('darwin') | 
| is_posix = is_linux or is_mac | 
| def check_call(cmd, **kwargs): | 
| logging.debug('Running: %s', ' '.join(cmd)) | 
| + if cmd and cmd[0].endswith('.py'): | 
| + cmd.insert(0, sys.executable) | 
| subprocess.check_call(cmd, cwd=GN_ROOT, **kwargs) | 
| def mkdir_p(path): | 
| @@ -66,6 +69,10 @@ def run_build(tempdir, options): | 
| temp_gn = os.path.join(tempdir, 'gn') | 
| out_gn = os.path.join(build_root, 'gn') | 
| + if is_win: | 
| + temp_gn += '.exe' | 
| + out_gn += '.exe' | 
| + | 
| if options.no_rebuild: | 
| mkdir_p(build_root) | 
| shutil.copy2(temp_gn, out_gn) | 
| @@ -113,22 +120,33 @@ def main(argv): | 
| return 1 | 
| return 0 | 
| +def write_compiled_message(root_gen_dir, source): | 
| + path = os.path.join(root_gen_dir, os.path.dirname(source)) | 
| + mkdir_p(path) | 
| + check_call([ | 
| + 'mc.exe', | 
| + '-r', path, '-h', path, | 
| + '-u', '-um', | 
| + os.path.join(SRC_ROOT, source), | 
| + ]) | 
| def write_buildflag_header_manually(root_gen_dir, header, flags): | 
| mkdir_p(os.path.join(root_gen_dir, os.path.dirname(header))) | 
| - with tempfile.NamedTemporaryFile() as f: | 
| + | 
| + temp_path = os.path.join(root_gen_dir, header + '.tmp') | 
| 
 
brettw
2016/06/13 18:19:43
I don't understand this change. Was the tempfile p
 
timn
2016/06/13 18:56:30
It "works", but not for our use case here.
write_
 
 | 
| + with open(temp_path, 'w') as f: | 
| f.write('--flags') | 
| for name,value in flags.items(): | 
| f.write(' ' + name + '=' + value) | 
| - f.flush() | 
| - check_call([ | 
| - os.path.join(SRC_ROOT, 'build', 'write_buildflag_header.py'), | 
| - '--output', header, | 
| - '--gen-dir', root_gen_dir, | 
| - '--definitions', f.name, | 
| - ]) | 
| + check_call([ | 
| + os.path.join(SRC_ROOT, 'build', 'write_buildflag_header.py'), | 
| + '--output', header, | 
| + '--gen-dir', root_gen_dir, | 
| + '--definitions', temp_path, | 
| + ]) | 
| + os.remove(temp_path) | 
| def build_gn_with_ninja_manually(tempdir, options): | 
| root_gen_dir = os.path.join(tempdir, 'gen') | 
| @@ -150,19 +168,125 @@ def build_gn_with_ninja_manually(tempdir, options): | 
| 'default' | 
| ]) | 
| - write_ninja(os.path.join(tempdir, 'build.ninja'), root_gen_dir, options) | 
| + if is_win: | 
| + write_buildflag_header_manually(root_gen_dir, 'base/win/base_features.h', | 
| + {'SINGLE_MODULE_MODE_HANDLE_VERIFIER': 'true'}) | 
| + | 
| + write_compiled_message(root_gen_dir, | 
| + 'base/trace_event/etw_manifest/chrome_events_win.man') | 
| + | 
| + write_gn_ninja(os.path.join(tempdir, 'build.ninja'), | 
| + root_gen_dir, options) | 
| cmd = ['ninja', '-C', tempdir] | 
| if options.verbose: | 
| cmd.append('-v') | 
| - cmd.append('gn') | 
| + | 
| + if is_win: | 
| + cmd.append('gn.exe') | 
| + else: | 
| + cmd.append('gn') | 
| + | 
| check_call(cmd) | 
| -def write_ninja(path, root_gen_dir, options): | 
| - cc = os.environ.get('CC', '') | 
| - cxx = os.environ.get('CXX', '') | 
| +def write_ninja(path, static_libraries, executables, | 
| + cc, cxx, ar, ld, | 
| + cflags=[], cflags_cc=[], ldflags=[], | 
| + include_dirs=[], solibs=[]): | 
| + ninja_header_lines = [ | 
| + 'cc = ' + cc, | 
| + 'cxx = ' + cxx, | 
| + 'ar = ' + ar, | 
| + 'ld = ' + ld, | 
| + '', | 
| + ] | 
| + | 
| + if is_win: | 
| + template_filename = 'build_vs.ninja.template' | 
| + elif is_mac: | 
| + template_filename = 'build_mac.ninja.template' | 
| + else: | 
| + template_filename = 'build.ninja.template' | 
| + | 
| + with open(os.path.join(GN_ROOT, 'bootstrap', template_filename)) as f: | 
| + ninja_template = f.read() | 
| + | 
| + if is_win: | 
| + executable_ext = '.exe' | 
| + library_ext = '.lib' | 
| + object_ext = '.obj' | 
| + else: | 
| + executable_ext = '' | 
| + library_ext = '.a' | 
| + object_ext = '.o' | 
| + | 
| + def escape_path_ninja(path): | 
| + return path.replace('$ ', '$$ ').replace(' ', '$ ').replace(':', '$:') | 
| + | 
| + def src_to_obj(path): | 
| + return escape_path_ninja('%s' % os.path.splitext(path)[0] + object_ext) | 
| + | 
| + def library_to_a(library): | 
| + return '%s%s' % (library, library_ext) | 
| + | 
| + ninja_lines = [] | 
| + def build_source(src_file, settings): | 
| + ninja_lines.extend([ | 
| + 'build %s: %s %s' % (src_to_obj(src_file), | 
| + settings['tool'], | 
| + escape_path_ninja( | 
| + os.path.join(SRC_ROOT, src_file))), | 
| + ' includes = %s' % ' '.join( | 
| + ['-I' + escape_path_ninja(dirname) for dirname in | 
| + include_dirs + settings.get('include_dirs', [])]), | 
| + ' cflags = %s' % ' '.join(cflags + settings.get('cflags', [])), | 
| + ' cflags_cc = %s' % | 
| + ' '.join(cflags_cc + settings.get('cflags_cc', [])), | 
| + ]) | 
| + | 
| + for library, settings in static_libraries.iteritems(): | 
| + for src_file in settings['sources']: | 
| + build_source(src_file, settings) | 
| + | 
| + ninja_lines.append('build %s: alink_thin %s' % ( | 
| + library_to_a(library), | 
| + ' '.join([src_to_obj(src_file) for src_file in settings['sources']]))) | 
| + | 
| + for executable, settings in executables.iteritems(): | 
| + for src_file in settings['sources']: | 
| + build_source(src_file, settings) | 
| + | 
| + ninja_lines.extend([ | 
| + 'build %s%s: link %s | %s' % ( | 
| + executable, executable_ext, | 
| + ' '.join([src_to_obj(src_file) for src_file in settings['sources']]), | 
| + ' '.join([library_to_a(library) for library in settings['libs']])), | 
| + ' ldflags = %s' % ' '.join(ldflags), | 
| + ' solibs = %s' % ' '.join(solibs), | 
| + ' libs = %s' % ' '.join( | 
| + [library_to_a(library) for library in settings['libs']]), | 
| + ]) | 
| + | 
| + ninja_lines.append('') # Make sure the file ends with a newline. | 
| + | 
| + with open(path, 'w') as f: | 
| + f.write('\n'.join(ninja_header_lines)) | 
| + f.write(ninja_template) | 
| + f.write('\n'.join(ninja_lines)) | 
| + | 
| +def write_gn_ninja(path, root_gen_dir, options): | 
| 
 
brettw
2016/06/13 18:19:43
I don't understand the new distinction you're maki
 
timn
2016/06/13 18:56:30
write_ninja is just a helper method that does the
 
 | 
| + if is_win: | 
| + cc = os.environ.get('CC', 'cl.exe') | 
| + cxx = os.environ.get('CXX', 'cl.exe') | 
| + ld = os.environ.get('LD', 'link.exe') | 
| + ar = os.environ.get('AR', 'lib.exe') | 
| + else: | 
| + cc = os.environ.get('CC', 'cc') | 
| + cxx = os.environ.get('CXX', 'c++') | 
| + ld = os.environ.get('LD', cxx) | 
| + ar = os.environ.get('AR', 'ar') | 
| + | 
| cflags = os.environ.get('CFLAGS', '').split() | 
| cflags_cc = os.environ.get('CXXFLAGS', '').split() | 
| - ld = os.environ.get('LD', cxx) | 
| ldflags = os.environ.get('LDFLAGS', '').split() | 
| include_dirs = [root_gen_dir, SRC_ROOT] | 
| libs = [] | 
| @@ -179,16 +303,43 @@ def write_ninja(path, root_gen_dir, options): | 
| cflags.extend([ | 
| '-D_FILE_OFFSET_BITS=64', | 
| + '-D__STDC_CONSTANT_MACROS', '-D__STDC_FORMAT_MACROS', | 
| '-pthread', | 
| '-pipe', | 
| '-fno-exceptions' | 
| ]) | 
| cflags_cc.extend(['-std=c++11', '-Wno-c++11-narrowing']) | 
| + elif is_win: | 
| + if not options.debug: | 
| + cflags.extend(['/Ox', '/DNDEBUG', '/GL']) | 
| + ldflags.extend(['/LTCG', '/OPT:REF', '/OPT:ICF']) | 
| + | 
| + cflags.extend([ | 
| + '/FS', | 
| + '/Gy', | 
| + '/W3', '/wd4244', | 
| + '/Zi', | 
| + '/DWIN32_LEAN_AND_MEAN', '/DNOMINMAX', | 
| + '/D_CRT_SECURE_NO_DEPRECATE', '/D_SCL_SECURE_NO_DEPRECATE', | 
| + '/D_WIN32_WINNT=0x0A00', '/DWINVER=0x0A00', | 
| + '/DUNICODE', '/D_UNICODE', | 
| + ]) | 
| + cflags_cc.extend([ | 
| + '/GR-', | 
| + '/D_HAS_EXCEPTIONS=0', | 
| + ]) | 
| + # TODO(tim): Support for 64bit builds? | 
| + ldflags.extend(['/MACHINE:x86', '/DEBUG']) | 
| static_libraries = { | 
| 'base': {'sources': [], 'tool': 'cxx', 'include_dirs': []}, | 
| 'dynamic_annotations': {'sources': [], 'tool': 'cc', 'include_dirs': []}, | 
| - 'gn': {'sources': [], 'tool': 'cxx', 'include_dirs': []}, | 
| + 'gn_lib': {'sources': [], 'tool': 'cxx', 'include_dirs': []}, | 
| + } | 
| + | 
| + executables = { | 
| + 'gn': {'sources': ['tools/gn/gn_main.cc'], | 
| + 'tool': 'cxx', 'include_dirs': [], 'libs': []}, | 
| } | 
| for name in os.listdir(GN_ROOT): | 
| @@ -198,8 +349,10 @@ def write_ninja(path, root_gen_dir, options): | 
| continue | 
| if name == 'run_all_unittests.cc': | 
| continue | 
| + if name == 'gn_main.cc': | 
| + continue | 
| full_path = os.path.join(GN_ROOT, name) | 
| - static_libraries['gn']['sources'].append( | 
| + static_libraries['gn_lib']['sources'].append( | 
| os.path.relpath(full_path, SRC_ROOT)) | 
| static_libraries['dynamic_annotations']['sources'].extend([ | 
| @@ -272,7 +425,6 @@ def write_ninja(path, root_gen_dir, options): | 
| 'base/sequenced_task_runner.cc', | 
| 'base/sha1.cc', | 
| 'base/strings/pattern.cc', | 
| - 'base/strings/string16.cc', | 
| 'base/strings/string_number_conversions.cc', | 
| 'base/strings/string_piece.cc', | 
| 'base/strings/string_split.cc', | 
| @@ -352,6 +504,7 @@ def write_ninja(path, root_gen_dir, options): | 
| 'base/process/process_handle_posix.cc', | 
| 'base/process/process_metrics_posix.cc', | 
| 'base/process/process_posix.cc', | 
| + 'base/strings/string16.cc', | 
| 'base/synchronization/condition_variable_posix.cc', | 
| 'base/synchronization/lock_impl_posix.cc', | 
| 'base/synchronization/read_write_lock_posix.cc', | 
| @@ -386,9 +539,8 @@ def write_ninja(path, root_gen_dir, options): | 
| 'cflags': cflags + ['-DHAVE_CONFIG_H'], | 
| } | 
| - | 
| if is_linux: | 
| - libs.extend(['-lrt']) | 
| + libs.extend(['-lrt', '-latomic']) | 
| ldflags.extend(['-pthread']) | 
| static_libraries['xdg_user_dirs'] = { | 
| @@ -454,65 +606,105 @@ def write_ninja(path, root_gen_dir, options): | 
| 'base/third_party/libevent/kqueue.c', | 
| ]) | 
| - | 
| - if is_mac: | 
| - template_filename = 'build_mac.ninja.template' | 
| - else: | 
| - template_filename = 'build.ninja.template' | 
| - | 
| - with open(os.path.join(GN_ROOT, 'bootstrap', template_filename)) as f: | 
| - ninja_template = f.read() | 
| - | 
| - def src_to_obj(path): | 
| - return '%s' % os.path.splitext(path)[0] + '.o' | 
| - | 
| - ninja_lines = [] | 
| - for library, settings in static_libraries.iteritems(): | 
| - for src_file in settings['sources']: | 
| - ninja_lines.extend([ | 
| - 'build %s: %s %s' % (src_to_obj(src_file), | 
| - settings['tool'], | 
| - os.path.join(SRC_ROOT, src_file)), | 
| - ' includes = %s' % ' '.join( | 
| - ['-I' + dirname for dirname in | 
| - include_dirs + settings.get('include_dirs', [])]), | 
| - ' cflags = %s' % ' '.join(cflags + settings.get('cflags', [])), | 
| - ' cflags_cc = %s' % | 
| - ' '.join(cflags_cc + settings.get('cflags_cc', [])), | 
| - ]) | 
| - if cc: | 
| - ninja_lines.append(' cc = %s' % cc) | 
| - if cxx: | 
| - ninja_lines.append(' cxx = %s' % cxx) | 
| - | 
| - ninja_lines.append('build %s.a: alink_thin %s' % ( | 
| - library, | 
| - ' '.join([src_to_obj(src_file) for src_file in settings['sources']]))) | 
| - | 
| - if is_mac: | 
| libs.extend([ | 
| '-framework', 'AppKit', | 
| '-framework', 'CoreFoundation', | 
| '-framework', 'Foundation', | 
| '-framework', 'Security', | 
| - ]); | 
| + ]) | 
| - ninja_lines.extend([ | 
| - 'build gn: link %s' % ( | 
| - ' '.join(['%s.a' % library for library in static_libraries])), | 
| - ' ldflags = %s' % ' '.join(ldflags), | 
| - ' libs = %s' % ' '.join(libs), | 
| - ]) | 
| - if ld: | 
| - ninja_lines.append(' ld = %s' % ld) | 
| - else: | 
| - ninja_lines.append(' ld = $ldxx') | 
| + if is_win: | 
| + static_libraries['base']['sources'].extend([ | 
| + 'base/base_paths_win.cc', | 
| + 'base/cpu.cc', | 
| + 'base/debug/close_handle_hook_win.cc', | 
| + 'base/debug/debugger.cc', | 
| + 'base/debug/debugger_win.cc', | 
| + 'base/debug/profiler.cc', | 
| + 'base/debug/stack_trace_win.cc', | 
| + 'base/file_version_info_win.cc', | 
| + 'base/files/file_enumerator_win.cc', | 
| + 'base/files/file_path_watcher_win.cc', | 
| + 'base/files/file_util_win.cc', | 
| + 'base/files/file_win.cc', | 
| + 'base/files/memory_mapped_file_win.cc', | 
| + 'base/logging_win.cc', | 
| + 'base/memory/memory_pressure_monitor_win.cc', | 
| + 'base/memory/shared_memory_handle_win.cc', | 
| + 'base/memory/shared_memory_win.cc', | 
| + 'base/message_loop/message_pump_win.cc', | 
| + 'base/native_library_win.cc', | 
| + 'base/power_monitor/power_monitor_device_source_win.cc', | 
| + 'base/process/kill_win.cc', | 
| + 'base/process/launch_win.cc', | 
| + 'base/process/memory_win.cc', | 
| + 'base/process/process_handle_win.cc', | 
| + 'base/process/process_info_win.cc', | 
| + 'base/process/process_iterator_win.cc', | 
| + 'base/process/process_metrics_win.cc', | 
| + 'base/process/process_win.cc', | 
| + 'base/profiler/native_stack_sampler_win.cc', | 
| + 'base/profiler/win32_stack_frame_unwinder.cc', | 
| + 'base/rand_util.cc', | 
| + 'base/rand_util_win.cc', | 
| + 'base/strings/sys_string_conversions_win.cc', | 
| + 'base/sync_socket_win.cc', | 
| + 'base/synchronization/condition_variable_win.cc', | 
| + 'base/synchronization/lock_impl_win.cc', | 
| + 'base/synchronization/read_write_lock_win.cc', | 
| + 'base/synchronization/waitable_event_watcher_win.cc', | 
| + 'base/synchronization/waitable_event_win.cc', | 
| + 'base/sys_info_win.cc', | 
| + 'base/threading/platform_thread_win.cc', | 
| + 'base/threading/thread_local_storage_win.cc', | 
| + 'base/threading/thread_local_win.cc', | 
| + 'base/threading/worker_pool_win.cc', | 
| + 'base/time/time_win.cc', | 
| + 'base/timer/hi_res_timer_manager_win.cc', | 
| + 'base/trace_event/heap_profiler_allocation_register_win.cc', | 
| + 'base/trace_event/trace_event_etw_export_win.cc', | 
| + 'base/trace_event/winheap_dump_provider_win.cc', | 
| + 'base/win/enum_variant.cc', | 
| + 'base/win/event_trace_controller.cc', | 
| + 'base/win/event_trace_provider.cc', | 
| + 'base/win/i18n.cc', | 
| + 'base/win/iat_patch_function.cc', | 
| + 'base/win/iunknown_impl.cc', | 
| + 'base/win/message_window.cc', | 
| + 'base/win/object_watcher.cc', | 
| + 'base/win/pe_image.cc', | 
| + 'base/win/process_startup_helper.cc', | 
| + 'base/win/registry.cc', | 
| + 'base/win/resource_util.cc', | 
| + 'base/win/scoped_bstr.cc', | 
| + 'base/win/scoped_handle.cc', | 
| + 'base/win/scoped_process_information.cc', | 
| + 'base/win/scoped_variant.cc', | 
| + 'base/win/shortcut.cc', | 
| + 'base/win/startup_information.cc', | 
| + 'base/win/wait_chain.cc', | 
| + 'base/win/win_util.cc', | 
| + 'base/win/windows_version.cc', | 
| + 'base/win/wrapped_window_proc.cc', | 
| + ]) | 
| - ninja_lines.append('') # Make sure the file ends with a newline. | 
| + libs.extend([ | 
| + 'kernel32.lib', | 
| + 'user32.lib', | 
| + 'shell32.lib', | 
| + 'ole32.lib', | 
| + 'winmm.lib', | 
| + 'ws2_32.lib', | 
| + 'userenv.lib', | 
| + 'version.lib', | 
| + 'dbghelp.lib', | 
| + ]) | 
| - with open(path, 'w') as f: | 
| - f.write(ninja_template + '\n'.join(ninja_lines)) | 
| + # we just build static libraries that GN needs | 
| + executables['gn']['libs'].extend(static_libraries.keys()) | 
| + write_ninja(path, static_libraries, executables, cc, cxx, ar, ld, | 
| + cflags, cflags_cc, ldflags, include_dirs, libs) | 
| def build_gn_with_gn(temp_gn, build_dir, options): | 
| gn_gen_args = options.gn_gen_args or '' | 
| @@ -527,7 +719,7 @@ def build_gn_with_gn(temp_gn, build_dir, options): | 
| cmd.append('gn') | 
| check_call(cmd) | 
| - if not options.debug: | 
| + if not options.debug and not is_win: | 
| check_call(['strip', os.path.join(build_dir, 'gn')]) |