1 #!/usr/bin/env python 2 # 3 # Copyright 2012 the V8 project authors. All rights reserved. 4 # Redistribution and use in source and binary forms, with or without 5 # modification, are permitted provided that the following conditions are 6 # met: 7 # 8 # * Redistributions of source code must retain the above copyright 9 # notice, this list of conditions and the following disclaimer. 10 # * Redistributions in binary form must reproduce the above 11 # copyright notice, this list of conditions and the following 12 # disclaimer in the documentation and/or other materials provided 13 # with the distribution. 14 # * Neither the name of Google Inc. nor the names of its 15 # contributors may be used to endorse or promote products derived 16 # from this software without specific prior written permission. 17 # 18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 30 # This script is wrapper for V8 that adds some support for how GYP 31 # is invoked by V8 beyond what can be done in the gclient hooks. 32 33 import glob 34 import os 35 import platform 36 import shlex 37 import subprocess 38 import sys 39 40 script_dir = os.path.dirname(os.path.realpath(__file__)) 41 v8_root = os.path.abspath(os.path.join(script_dir, os.pardir)) 42 43 sys.path.insert(0, os.path.join(v8_root, 'build', 'gyp', 'pylib')) 44 import gyp 45 46 # Add paths so that pymod_do_main(...) can import files. 47 sys.path.insert( 48 1, os.path.abspath(os.path.join(v8_root, 'tools', 'generate_shim_headers'))) 49 50 51 def apply_gyp_environment(file_path=None): 52 """ 53 Reads in a *.gyp_env file and applies the valid keys to os.environ. 54 """ 55 if not file_path or not os.path.exists(file_path): 56 return 57 file_contents = open(file_path).read() 58 try: 59 file_data = eval(file_contents, {'__builtins__': None}, None) 60 except SyntaxError, e: 61 e.filename = os.path.abspath(file_path) 62 raise 63 supported_vars = ( 'V8_GYP_FILE', 64 'V8_GYP_SYNTAX_CHECK', 65 'GYP_DEFINES', 66 'GYP_GENERATOR_FLAGS', 67 'GYP_GENERATOR_OUTPUT', ) 68 for var in supported_vars: 69 val = file_data.get(var) 70 if val: 71 if var in os.environ: 72 print 'INFO: Environment value for "%s" overrides value in %s.' % ( 73 var, os.path.abspath(file_path) 74 ) 75 else: 76 os.environ[var] = val 77 78 79 def additional_include_files(args=[]): 80 """ 81 Returns a list of additional (.gypi) files to include, without 82 duplicating ones that are already specified on the command line. 83 """ 84 # Determine the include files specified on the command line. 85 # This doesn't cover all the different option formats you can use, 86 # but it's mainly intended to avoid duplicating flags on the automatic 87 # makefile regeneration which only uses this format. 88 specified_includes = set() 89 for arg in args: 90 if arg.startswith('-I') and len(arg) > 2: 91 specified_includes.add(os.path.realpath(arg[2:])) 92 93 result = [] 94 def AddInclude(path): 95 if os.path.realpath(path) not in specified_includes: 96 result.append(path) 97 98 # Always include standalone.gypi 99 AddInclude(os.path.join(v8_root, 'build', 'standalone.gypi')) 100 101 # Optionally add supplemental .gypi files if present. 102 supplements = glob.glob(os.path.join(v8_root, '*', 'supplement.gypi')) 103 for supplement in supplements: 104 AddInclude(supplement) 105 106 return result 107 108 109 def run_gyp(args): 110 rc = gyp.main(args) 111 112 # Check for landmines (reasons to clobber the build). This must be run here, 113 # rather than a separate runhooks step so that any environment modifications 114 # from above are picked up. 115 print 'Running build/landmines.py...' 116 subprocess.check_call( 117 [sys.executable, os.path.join(script_dir, 'landmines.py')]) 118 119 if rc != 0: 120 print 'Error running GYP' 121 sys.exit(rc) 122 123 124 if __name__ == '__main__': 125 args = sys.argv[1:] 126 127 if 'SKIP_V8_GYP_ENV' not in os.environ: 128 # Update the environment based on v8.gyp_env 129 gyp_env_path = os.path.join(os.path.dirname(v8_root), 'v8.gyp_env') 130 apply_gyp_environment(gyp_env_path) 131 132 # This could give false positives since it doesn't actually do real option 133 # parsing. Oh well. 134 gyp_file_specified = False 135 for arg in args: 136 if arg.endswith('.gyp'): 137 gyp_file_specified = True 138 break 139 140 # If we didn't get a file, check an env var, and then fall back to 141 # assuming 'all.gyp' from the same directory as the script. 142 if not gyp_file_specified: 143 gyp_file = os.environ.get('V8_GYP_FILE') 144 if gyp_file: 145 # Note that V8_GYP_FILE values can't have backslashes as 146 # path separators even on Windows due to the use of shlex.split(). 147 args.extend(shlex.split(gyp_file)) 148 else: 149 args.append(os.path.join(script_dir, 'all.gyp')) 150 151 args.extend(['-I' + i for i in additional_include_files(args)]) 152 153 # There shouldn't be a circular dependency relationship between .gyp files 154 args.append('--no-circular-check') 155 156 # Set the GYP DEPTH variable to the root of the V8 project. 157 args.append('--depth=' + os.path.relpath(v8_root)) 158 159 # If V8_GYP_SYNTAX_CHECK is set to 1, it will invoke gyp with --check 160 # to enfore syntax checking. 161 syntax_check = os.environ.get('V8_GYP_SYNTAX_CHECK') 162 if syntax_check and int(syntax_check): 163 args.append('--check') 164 165 print 'Updating projects from gyp files...' 166 sys.stdout.flush() 167 168 # Generate for the architectures supported on the given platform. 169 gyp_args = list(args) 170 gyp_generators = os.environ.get('GYP_GENERATORS') 171 if platform.system() == 'Linux' and gyp_generators != 'ninja': 172 # Work around for crbug.com/331475. 173 for f in glob.glob(os.path.join(v8_root, 'out', 'Makefile.*')): 174 os.unlink(f) 175 # --generator-output defines where the Makefile goes. 176 gyp_args.append('--generator-output=out') 177 # -Goutput_dir defines where the build output goes, relative to the 178 # Makefile. Set it to . so that the build output doesn't end up in out/out. 179 gyp_args.append('-Goutput_dir=.') 180 run_gyp(gyp_args) 181