michael@0: #!/usr/bin/env python michael@0: michael@0: # Copyright (c) 2012 The Chromium Authors. All rights reserved. michael@0: # Use of this source code is governed by a BSD-style license that can be michael@0: # found in the LICENSE file. michael@0: michael@0: # This script is wrapper for Chromium that adds some support for how GYP michael@0: # is invoked by Chromium beyond what can be done in the gclient hooks. michael@0: michael@0: import glob michael@0: import os michael@0: import shlex michael@0: import subprocess michael@0: import sys michael@0: michael@0: script_dir = os.path.dirname(os.path.realpath(__file__)) michael@0: chrome_src = os.path.abspath(os.path.join(script_dir, os.pardir)) michael@0: michael@0: sys.path.insert(0, os.path.join(chrome_src, 'tools', 'gyp', 'pylib')) michael@0: import gyp michael@0: michael@0: # Add paths so that pymod_do_main(...) can import files. michael@0: sys.path.insert(1, os.path.join(chrome_src, 'tools', 'grit')) michael@0: sys.path.insert(1, os.path.join(chrome_src, 'chrome', 'tools', 'build')) michael@0: sys.path.insert(1, os.path.join(chrome_src, 'native_client', 'build')) michael@0: michael@0: michael@0: # On Windows, Psyco shortens warm runs of build/gyp_chromium by about michael@0: # 20 seconds on a z600 machine with 12 GB of RAM, from 90 down to 70 michael@0: # seconds. Conversely, memory usage of build/gyp_chromium with Psyco michael@0: # maxes out at about 158 MB vs. 132 MB without it. michael@0: # michael@0: # Psyco uses native libraries, so we need to load a different michael@0: # installation depending on which OS we are running under. It has not michael@0: # been tested whether using Psyco on our Mac and Linux builds is worth michael@0: # it (the GYP running time is a lot shorter, so the JIT startup cost michael@0: # may not be worth it). michael@0: if sys.platform == 'win32': michael@0: try: michael@0: sys.path.insert(0, os.path.join(chrome_src, 'third_party', 'psyco_win32')) michael@0: import psyco michael@0: except: michael@0: psyco = None michael@0: else: michael@0: psyco = None michael@0: michael@0: def apply_gyp_environment(file_path=None): michael@0: """ michael@0: Reads in a *.gyp_env file and applies the valid keys to os.environ. michael@0: """ michael@0: if not file_path or not os.path.exists(file_path): michael@0: return michael@0: file_contents = open(file_path).read() michael@0: try: michael@0: file_data = eval(file_contents, {'__builtins__': None}, None) michael@0: except SyntaxError, e: michael@0: e.filename = os.path.abspath(file_path) michael@0: raise michael@0: supported_vars = ( 'CC', michael@0: 'CHROMIUM_GYP_FILE', michael@0: 'CHROMIUM_GYP_SYNTAX_CHECK', michael@0: 'CXX', michael@0: 'GYP_DEFINES', michael@0: 'GYP_GENERATOR_FLAGS', michael@0: 'GYP_GENERATOR_OUTPUT', michael@0: 'GYP_GENERATORS', ) michael@0: for var in supported_vars: michael@0: val = file_data.get(var) michael@0: if val: michael@0: if var in os.environ: michael@0: print 'INFO: Environment value for "%s" overrides value in %s.' % ( michael@0: var, os.path.abspath(file_path) michael@0: ) michael@0: else: michael@0: os.environ[var] = val michael@0: michael@0: def additional_include_files(args=[]): michael@0: """ michael@0: Returns a list of additional (.gypi) files to include, without michael@0: duplicating ones that are already specified on the command line. michael@0: """ michael@0: # Determine the include files specified on the command line. michael@0: # This doesn't cover all the different option formats you can use, michael@0: # but it's mainly intended to avoid duplicating flags on the automatic michael@0: # makefile regeneration which only uses this format. michael@0: specified_includes = set() michael@0: for arg in args: michael@0: if arg.startswith('-I') and len(arg) > 2: michael@0: specified_includes.add(os.path.realpath(arg[2:])) michael@0: michael@0: result = [] michael@0: def AddInclude(path): michael@0: if os.path.realpath(path) not in specified_includes: michael@0: result.append(path) michael@0: michael@0: # Always include common.gypi. michael@0: AddInclude(os.path.join(script_dir, 'common.gypi')) michael@0: michael@0: # Optionally add supplemental .gypi files if present. michael@0: supplements = glob.glob(os.path.join(chrome_src, '*', 'supplement.gypi')) michael@0: for supplement in supplements: michael@0: AddInclude(supplement) michael@0: michael@0: return result michael@0: michael@0: if __name__ == '__main__': michael@0: args = sys.argv[1:] michael@0: michael@0: # Use the Psyco JIT if available. michael@0: if psyco: michael@0: psyco.profile() michael@0: print "Enabled Psyco JIT." michael@0: michael@0: # Fall back on hermetic python if we happen to get run under cygwin. michael@0: # TODO(bradnelson): take this out once this issue is fixed: michael@0: # http://code.google.com/p/gyp/issues/detail?id=177 michael@0: if sys.platform == 'cygwin': michael@0: python_dir = os.path.join(chrome_src, 'third_party', 'python_26') michael@0: env = os.environ.copy() michael@0: env['PATH'] = python_dir + os.pathsep + env.get('PATH', '') michael@0: p = subprocess.Popen( michael@0: [os.path.join(python_dir, 'python.exe')] + sys.argv, michael@0: env=env, shell=False) michael@0: p.communicate() michael@0: sys.exit(p.returncode) michael@0: michael@0: if 'SKIP_CHROMIUM_GYP_ENV' not in os.environ: michael@0: # Update the environment based on chromium.gyp_env michael@0: gyp_env_path = os.path.join(os.path.dirname(chrome_src), 'chromium.gyp_env') michael@0: apply_gyp_environment(gyp_env_path) michael@0: michael@0: # This could give false positives since it doesn't actually do real option michael@0: # parsing. Oh well. michael@0: gyp_file_specified = False michael@0: for arg in args: michael@0: if arg.endswith('.gyp'): michael@0: gyp_file_specified = True michael@0: break michael@0: michael@0: # If we didn't get a file, check an env var, and then fall back to michael@0: # assuming 'all.gyp' from the same directory as the script. michael@0: if not gyp_file_specified: michael@0: gyp_file = os.environ.get('CHROMIUM_GYP_FILE') michael@0: if gyp_file: michael@0: # Note that CHROMIUM_GYP_FILE values can't have backslashes as michael@0: # path separators even on Windows due to the use of shlex.split(). michael@0: args.extend(shlex.split(gyp_file)) michael@0: else: michael@0: args.append(os.path.join(script_dir, 'all.gyp')) michael@0: michael@0: args.extend(['-I' + i for i in additional_include_files(args)]) michael@0: michael@0: # There shouldn't be a circular dependency relationship between .gyp files, michael@0: # but in Chromium's .gyp files, on non-Mac platforms, circular relationships michael@0: # currently exist. The check for circular dependencies is currently michael@0: # bypassed on other platforms, but is left enabled on the Mac, where a michael@0: # violation of the rule causes Xcode to misbehave badly. michael@0: # TODO(mark): Find and kill remaining circular dependencies, and remove this michael@0: # option. http://crbug.com/35878. michael@0: # TODO(tc): Fix circular dependencies in ChromiumOS then add linux2 to the michael@0: # list. michael@0: if sys.platform not in ('darwin',): michael@0: args.append('--no-circular-check') michael@0: michael@0: # If CHROMIUM_GYP_SYNTAX_CHECK is set to 1, it will invoke gyp with --check michael@0: # to enfore syntax checking. michael@0: syntax_check = os.environ.get('CHROMIUM_GYP_SYNTAX_CHECK') michael@0: if syntax_check and int(syntax_check): michael@0: args.append('--check') michael@0: michael@0: print 'Updating projects from gyp files...' michael@0: sys.stdout.flush() michael@0: michael@0: # Off we go... michael@0: sys.exit(gyp.main(args))