Home | History | Annotate | Download | only in build
      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 argparse
     34 import glob
     35 import gyp_environment
     36 import os
     37 import platform
     38 import shlex
     39 import subprocess
     40 import sys
     41 import vs_toolchain
     42 
     43 script_dir = os.path.dirname(os.path.realpath(__file__))
     44 v8_root = os.path.abspath(os.path.join(script_dir, os.pardir))
     45 
     46 sys.path.insert(0, os.path.join(v8_root, 'build', 'gyp', 'pylib'))
     47 import gyp
     48 
     49 # Add paths so that pymod_do_main(...) can import files.
     50 sys.path.insert(
     51     1, os.path.abspath(os.path.join(v8_root, 'tools', 'generate_shim_headers')))
     52 
     53 
     54 def GetOutputDirectory():
     55   """Returns the output directory that GYP will use."""
     56 
     57   # Handle command line generator flags.
     58   parser = argparse.ArgumentParser()
     59   parser.add_argument('-G', dest='genflags', default=[], action='append')
     60   genflags = parser.parse_known_args()[0].genflags
     61 
     62   # Handle generator flags from the environment.
     63   genflags += shlex.split(os.environ.get('GYP_GENERATOR_FLAGS', ''))
     64 
     65   needle = 'output_dir='
     66   for item in genflags:
     67     if item.startswith(needle):
     68       return item[len(needle):]
     69 
     70   return 'out'
     71 
     72 
     73 def additional_include_files(args=[]):
     74   """
     75   Returns a list of additional (.gypi) files to include, without
     76   duplicating ones that are already specified on the command line.
     77   """
     78   # Determine the include files specified on the command line.
     79   # This doesn't cover all the different option formats you can use,
     80   # but it's mainly intended to avoid duplicating flags on the automatic
     81   # makefile regeneration which only uses this format.
     82   specified_includes = set()
     83   for arg in args:
     84     if arg.startswith('-I') and len(arg) > 2:
     85       specified_includes.add(os.path.realpath(arg[2:]))
     86 
     87   result = []
     88   def AddInclude(path):
     89     if os.path.realpath(path) not in specified_includes:
     90       result.append(path)
     91 
     92   # Always include standalone.gypi
     93   AddInclude(os.path.join(v8_root, 'build', 'standalone.gypi'))
     94 
     95   # Optionally add supplemental .gypi files if present.
     96   supplements = glob.glob(os.path.join(v8_root, '*', 'supplement.gypi'))
     97   for supplement in supplements:
     98     AddInclude(supplement)
     99 
    100   return result
    101 
    102 
    103 def run_gyp(args):
    104   rc = gyp.main(args)
    105 
    106   vs2013_runtime_dll_dirs = vs_toolchain.SetEnvironmentAndGetRuntimeDllDirs()
    107   if vs2013_runtime_dll_dirs:
    108     x64_runtime, x86_runtime = vs2013_runtime_dll_dirs
    109     vs_toolchain.CopyVsRuntimeDlls(
    110       os.path.join(v8_root, GetOutputDirectory()),
    111       (x86_runtime, x64_runtime))
    112 
    113   if rc != 0:
    114     print 'Error running GYP'
    115     sys.exit(rc)
    116 
    117 
    118 if __name__ == '__main__':
    119   args = sys.argv[1:]
    120 
    121   gyp_environment.set_environment()
    122 
    123   # This could give false positives since it doesn't actually do real option
    124   # parsing.  Oh well.
    125   gyp_file_specified = False
    126   for arg in args:
    127     if arg.endswith('.gyp'):
    128       gyp_file_specified = True
    129       break
    130 
    131   # If we didn't get a file, check an env var, and then fall back to
    132   # assuming 'all.gyp' from the same directory as the script.
    133   if not gyp_file_specified:
    134     gyp_file = os.environ.get('V8_GYP_FILE')
    135     if gyp_file:
    136       # Note that V8_GYP_FILE values can't have backslashes as
    137       # path separators even on Windows due to the use of shlex.split().
    138       args.extend(shlex.split(gyp_file))
    139     else:
    140       args.append(os.path.join(script_dir, 'all.gyp'))
    141 
    142   args.extend(['-I' + i for i in additional_include_files(args)])
    143 
    144   # There shouldn't be a circular dependency relationship between .gyp files
    145   args.append('--no-circular-check')
    146 
    147   # Set the GYP DEPTH variable to the root of the V8 project.
    148   args.append('--depth=' + os.path.relpath(v8_root))
    149 
    150   # If V8_GYP_SYNTAX_CHECK is set to 1, it will invoke gyp with --check
    151   # to enfore syntax checking.
    152   syntax_check = os.environ.get('V8_GYP_SYNTAX_CHECK')
    153   if syntax_check and int(syntax_check):
    154     args.append('--check')
    155 
    156   print 'Updating projects from gyp files...'
    157   sys.stdout.flush()
    158 
    159   # Generate for the architectures supported on the given platform.
    160   gyp_args = list(args)
    161   gyp_args.extend(['-D', 'gyp_output_dir=' + GetOutputDirectory()])
    162   gyp_generators = os.environ.get('GYP_GENERATORS', '')
    163   if platform.system() == 'Linux' and gyp_generators != 'ninja':
    164     # Work around for crbug.com/331475.
    165     for f in glob.glob(os.path.join(v8_root, 'out', 'Makefile.*')):
    166       os.unlink(f)
    167     # --generator-output defines where the Makefile goes.
    168     gyp_args.append('--generator-output=out')
    169     # -Goutput_dir defines where the build output goes, relative to the
    170     # Makefile. Set it to . so that the build output doesn't end up in out/out.
    171     gyp_args.append('-Goutput_dir=.')
    172 
    173   gyp_defines = os.environ.get('GYP_DEFINES', '')
    174 
    175   # Automatically turn on crosscompile support for platforms that need it.
    176   if all(('ninja' in gyp_generators,
    177           'OS=android' in gyp_defines,
    178           'GYP_CROSSCOMPILE' not in os.environ)):
    179     os.environ['GYP_CROSSCOMPILE'] = '1'
    180 
    181   run_gyp(gyp_args)
    182