1 #!/usr/bin/env python 2 3 # Copyright (c) 2011 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 Chromium 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 shlex 13 import subprocess 14 import sys 15 16 script_dir = os.path.dirname(__file__) 17 chrome_src = os.path.abspath(os.path.join(script_dir, os.pardir)) 18 19 sys.path.insert(0, os.path.join(chrome_src, 'tools', 'gyp', 'pylib')) 20 import gyp 21 22 # On Windows, Psyco shortens warm runs of build/gyp_chromium by about 23 # 20 seconds on a z600 machine with 12 GB of RAM, from 90 down to 70 24 # seconds. Conversely, memory usage of build/gyp_chromium with Psyco 25 # maxes out at about 158 MB vs. 132 MB without it. 26 # 27 # Psyco uses native libraries, so we need to load a different 28 # installation depending on which OS we are running under. It has not 29 # been tested whether using Psyco on our Mac and Linux builds is worth 30 # it (the GYP running time is a lot shorter, so the JIT startup cost 31 # may not be worth it). 32 if sys.platform == 'win32': 33 try: 34 sys.path.insert(0, os.path.join(chrome_src, 'third_party', 'psyco_win32')) 35 import psyco 36 except: 37 psyco = None 38 else: 39 psyco = None 40 41 def apply_gyp_environment(file_path=None): 42 """ 43 Reads in a *.gyp_env file and applies the valid keys to os.environ. 44 """ 45 if not file_path or not os.path.exists(file_path): 46 return 47 file_contents = open(file_path).read() 48 try: 49 file_data = eval(file_contents, {'__builtins__': None}, None) 50 except SyntaxError, e: 51 e.filename = os.path.abspath(file_path) 52 raise 53 supported_vars = ( 'CHROMIUM_GYP_FILE', 54 'CHROMIUM_GYP_SYNTAX_CHECK', 55 'GYP_DEFINES', 56 'GYP_GENERATOR_FLAGS', 57 'GYP_GENERATOR_OUTPUT', ) 58 for var in supported_vars: 59 val = file_data.get(var) 60 if val: 61 if var in os.environ: 62 print 'INFO: Environment value for "%s" overrides value in %s.' % ( 63 var, os.path.abspath(file_path) 64 ) 65 else: 66 os.environ[var] = val 67 68 def additional_include_files(args=[]): 69 """ 70 Returns a list of additional (.gypi) files to include, without 71 duplicating ones that are already specified on the command line. 72 """ 73 # Determine the include files specified on the command line. 74 # This doesn't cover all the different option formats you can use, 75 # but it's mainly intended to avoid duplicating flags on the automatic 76 # makefile regeneration which only uses this format. 77 specified_includes = set() 78 for arg in args: 79 if arg.startswith('-I') and len(arg) > 2: 80 specified_includes.add(os.path.realpath(arg[2:])) 81 82 result = [] 83 def AddInclude(path): 84 if os.path.realpath(path) not in specified_includes: 85 result.append(path) 86 87 # Always include common.gypi & features_override.gypi 88 AddInclude(os.path.join(script_dir, 'common.gypi')) 89 AddInclude(os.path.join(script_dir, 'features_override.gypi')) 90 91 # Optionally add supplemental .gypi files if present. 92 supplements = glob.glob(os.path.join(chrome_src, '*', 'supplement.gypi')) 93 for supplement in supplements: 94 AddInclude(supplement) 95 96 return result 97 98 if __name__ == '__main__': 99 args = sys.argv[1:] 100 101 # Use the Psyco JIT if available. 102 if psyco: 103 psyco.profile() 104 print "Enabled Psyco JIT." 105 106 # Fall back on hermetic python if we happen to get run under cygwin. 107 # TODO(bradnelson): take this out once this issue is fixed: 108 # http://code.google.com/p/gyp/issues/detail?id=177 109 if sys.platform == 'cygwin': 110 python_dir = os.path.join(chrome_src, 'third_party', 'python_26') 111 env = os.environ.copy() 112 env['PATH'] = python_dir + os.pathsep + env.get('PATH', '') 113 p = subprocess.Popen( 114 [os.path.join(python_dir, 'python.exe')] + sys.argv, 115 env=env, shell=False) 116 p.communicate() 117 sys.exit(p.returncode) 118 119 if 'SKIP_CHROMIUM_GYP_ENV' not in os.environ: 120 # Update the environment based on chromium.gyp_env 121 gyp_env_path = os.path.join(os.path.dirname(chrome_src), 'chromium.gyp_env') 122 apply_gyp_environment(gyp_env_path) 123 124 # This could give false positives since it doesn't actually do real option 125 # parsing. Oh well. 126 gyp_file_specified = False 127 for arg in args: 128 if arg.endswith('.gyp'): 129 gyp_file_specified = True 130 break 131 132 # If we didn't get a file, check an env var, and then fall back to 133 # assuming 'all.gyp' from the same directory as the script. 134 if not gyp_file_specified: 135 gyp_file = os.environ.get('CHROMIUM_GYP_FILE') 136 if gyp_file: 137 # Note that CHROMIUM_GYP_FILE values can't have backslashes as 138 # path separators even on Windows due to the use of shlex.split(). 139 args.extend(shlex.split(gyp_file)) 140 else: 141 args.append(os.path.join(script_dir, 'all.gyp')) 142 143 args.extend(['-I' + i for i in additional_include_files(args)]) 144 145 # There shouldn't be a circular dependency relationship between .gyp files, 146 # but in Chromium's .gyp files, on non-Mac platforms, circular relationships 147 # currently exist. The check for circular dependencies is currently 148 # bypassed on other platforms, but is left enabled on the Mac, where a 149 # violation of the rule causes Xcode to misbehave badly. 150 # TODO(mark): Find and kill remaining circular dependencies, and remove this 151 # option. http://crbug.com/35878. 152 # TODO(tc): Fix circular dependencies in ChromiumOS then add linux2 to the 153 # list. 154 if sys.platform not in ('darwin',): 155 args.append('--no-circular-check') 156 157 # If CHROMIUM_GYP_SYNTAX_CHECK is set to 1, it will invoke gyp with --check 158 # to enfore syntax checking. 159 syntax_check = os.environ.get('CHROMIUM_GYP_SYNTAX_CHECK') 160 if syntax_check and int(syntax_check): 161 args.append('--check') 162 163 print 'Updating projects from gyp files...' 164 sys.stdout.flush() 165 166 # Off we go... 167 sys.exit(gyp.main(args)) 168