Upgrade GYP to r1115
This commit is contained in:
Родитель
f7f8af8420
Коммит
60a9e1e40f
|
@ -13,7 +13,45 @@ import subprocess
|
|||
import sys
|
||||
|
||||
|
||||
def GypTestFormat(title, format, msvs_version=None):
|
||||
if sys.platform in ['win32', 'cygwin']:
|
||||
EXE_SUFFIX = '.exe'
|
||||
else:
|
||||
EXE_SUFFIX = ''
|
||||
|
||||
|
||||
BUILDBOT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
TRUNK_DIR = os.path.dirname(BUILDBOT_DIR)
|
||||
ROOT_DIR = os.path.dirname(TRUNK_DIR)
|
||||
OUT_DIR = os.path.join(TRUNK_DIR, 'out')
|
||||
NINJA_PATH = os.path.join(TRUNK_DIR, 'ninja' + EXE_SUFFIX)
|
||||
NINJA_WORK_DIR = os.path.join(ROOT_DIR, 'ninja_work')
|
||||
|
||||
|
||||
def InstallNinja():
|
||||
"""Install + build ninja.
|
||||
|
||||
Returns:
|
||||
0 for success, 1 for failure.
|
||||
"""
|
||||
print '@@@BUILD_STEP install ninja@@@'
|
||||
# Delete old version if any.
|
||||
try:
|
||||
shutil.rmtree(NINJA_WORK_DIR, ignore_errors=True)
|
||||
except:
|
||||
pass
|
||||
# Sync new copy from git.
|
||||
subprocess.check_call(
|
||||
'git clone https://github.com/martine/ninja.git ' + NINJA_WORK_DIR,
|
||||
shell=True)
|
||||
# Bootstrap.
|
||||
subprocess.check_call('./bootstrap.sh', cwd=NINJA_WORK_DIR, shell=True)
|
||||
# Copy out ninja.
|
||||
shutil.copyfile(os.path.join(NINJA_WORK_DIR, 'ninja' + EXE_SUFFIX),
|
||||
NINJA_PATH)
|
||||
os.chmod(NINJA_PATH, 0777)
|
||||
|
||||
|
||||
def GypTestFormat(title, format=None, msvs_version=None):
|
||||
"""Run the gyp tests for a given format, emitting annotator tags.
|
||||
|
||||
See annotator docs at:
|
||||
|
@ -23,12 +61,27 @@ def GypTestFormat(title, format, msvs_version=None):
|
|||
Returns:
|
||||
0 for sucesss, 1 for failure.
|
||||
"""
|
||||
if not format:
|
||||
format = title
|
||||
|
||||
# Install ninja if needed.
|
||||
# NOTE: as ninja gets installed each time, regressions to ninja can come
|
||||
# either from changes to ninja itself, or changes to gyp.
|
||||
if format == 'ninja':
|
||||
try:
|
||||
InstallNinja()
|
||||
except Exception, e:
|
||||
print '@@@STEP_FAILURE@@@'
|
||||
print str(e)
|
||||
return 1
|
||||
|
||||
print '@@@BUILD_STEP ' + title + '@@@'
|
||||
sys.stdout.flush()
|
||||
buildbot_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
trunk_dir = os.path.dirname(buildbot_dir)
|
||||
root_dir = os.path.dirname(trunk_dir)
|
||||
env = os.environ.copy()
|
||||
# TODO(bradnelson): remove this when this issue is resolved:
|
||||
# http://code.google.com/p/chromium/issues/detail?id=108251
|
||||
if format == 'ninja':
|
||||
env['NOGOLD'] = '1'
|
||||
if msvs_version:
|
||||
env['GYP_MSVS_VERSION'] = msvs_version
|
||||
retcode = subprocess.call(' '.join(
|
||||
|
@ -38,7 +91,7 @@ def GypTestFormat(title, format, msvs_version=None):
|
|||
'--format', format,
|
||||
'--chdir', 'trunk',
|
||||
'--path', '../scons']),
|
||||
cwd=root_dir, env=env, shell=True)
|
||||
cwd=ROOT_DIR, env=env, shell=True)
|
||||
if retcode:
|
||||
# Emit failure tag, and keep going.
|
||||
print '@@@STEP_FAILURE@@@'
|
||||
|
@ -49,17 +102,23 @@ def GypTestFormat(title, format, msvs_version=None):
|
|||
def GypBuild():
|
||||
# Dump out/ directory.
|
||||
print '@@@BUILD_STEP cleanup@@@'
|
||||
print 'Removing out/ ...'
|
||||
shutil.rmtree('out', ignore_errors=True)
|
||||
print 'Removing %s...' % OUT_DIR
|
||||
shutil.rmtree(OUT_DIR, ignore_errors=True)
|
||||
print 'Removing %s...' % NINJA_WORK_DIR
|
||||
shutil.rmtree(NINJA_WORK_DIR, ignore_errors=True)
|
||||
print 'Removing %s...' % NINJA_PATH
|
||||
shutil.rmtree(NINJA_PATH, ignore_errors=True)
|
||||
print 'Done.'
|
||||
|
||||
retcode = 0
|
||||
if sys.platform.startswith('linux'):
|
||||
retcode += GypTestFormat('scons', format='scons')
|
||||
retcode += GypTestFormat('make', format='make')
|
||||
retcode += GypTestFormat('ninja')
|
||||
retcode += GypTestFormat('scons')
|
||||
retcode += GypTestFormat('make')
|
||||
elif sys.platform == 'darwin':
|
||||
retcode += GypTestFormat('xcode', format='xcode')
|
||||
retcode += GypTestFormat('make', format='make')
|
||||
retcode += GypTestFormat('ninja')
|
||||
retcode += GypTestFormat('xcode')
|
||||
retcode += GypTestFormat('make')
|
||||
elif sys.platform == 'win32':
|
||||
retcode += GypTestFormat('msvs-2008', format='msvs', msvs_version='2008')
|
||||
if os.environ['BUILDBOT_BUILDERNAME'] == 'gyp-win64':
|
||||
|
|
|
@ -212,7 +212,7 @@ def main(argv=None):
|
|||
'win32': ['msvs'],
|
||||
'linux2': ['make', 'ninja'],
|
||||
'linux3': ['make', 'ninja'],
|
||||
'darwin': ['make', 'xcode'],
|
||||
'darwin': ['make', 'ninja', 'xcode'],
|
||||
}[sys.platform]
|
||||
|
||||
for format in format_list:
|
||||
|
|
|
@ -344,6 +344,18 @@ def WriteOnDiff(filename):
|
|||
return Writer()
|
||||
|
||||
|
||||
def GetFlavor(params):
|
||||
"""Returns |params.flavor| if it's set, the system's default flavor else."""
|
||||
flavors = {
|
||||
'darwin': 'mac',
|
||||
'sunos5': 'solaris',
|
||||
'freebsd7': 'freebsd',
|
||||
'freebsd8': 'freebsd',
|
||||
}
|
||||
flavor = flavors.get(sys.platform, 'linux')
|
||||
return params.get('flavor', flavor)
|
||||
|
||||
|
||||
# From Alex Martelli,
|
||||
# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52560
|
||||
# ASPN: Python Cookbook: Remove duplicates from a sequence
|
||||
|
|
|
@ -25,21 +25,10 @@ for unused in ['RULE_INPUT_PATH', 'RULE_INPUT_ROOT', 'RULE_INPUT_NAME',
|
|||
generator_default_variables[unused] = ''
|
||||
|
||||
|
||||
def GetFlavor(params):
|
||||
"""Returns |params.flavor| if it's set, the system's default flavor else."""
|
||||
flavors = {
|
||||
'darwin': 'mac',
|
||||
'sunos5': 'solaris',
|
||||
'freebsd7': 'freebsd',
|
||||
'freebsd8': 'freebsd',
|
||||
}
|
||||
flavor = flavors.get(sys.platform, 'linux')
|
||||
return params.get('flavor', flavor)
|
||||
|
||||
|
||||
def CalculateVariables(default_variables, params):
|
||||
generator_flags = params.get('generator_flags', {})
|
||||
default_variables['OS'] = generator_flags.get('os', GetFlavor(params))
|
||||
default_variables['OS'] = generator_flags.get(
|
||||
'os', gyp.common.GetFlavor(params))
|
||||
|
||||
|
||||
def CalculateGeneratorInputInfo(params):
|
||||
|
|
|
@ -55,25 +55,13 @@ generator_supports_multiple_toolsets = True
|
|||
generator_wants_sorted_dependencies = False
|
||||
|
||||
|
||||
def GetFlavor(params):
|
||||
"""Returns |params.flavor| if it's set, the system's default flavor else."""
|
||||
flavors = {
|
||||
'darwin': 'mac',
|
||||
'sunos5': 'solaris',
|
||||
'freebsd7': 'freebsd',
|
||||
'freebsd8': 'freebsd',
|
||||
}
|
||||
flavor = flavors.get(sys.platform, 'linux')
|
||||
return params.get('flavor', flavor)
|
||||
|
||||
|
||||
def CalculateVariables(default_variables, params):
|
||||
"""Calculate additional variables for use in the build (called by gyp)."""
|
||||
cc_target = os.environ.get('CC.target', os.environ.get('CC', 'cc'))
|
||||
default_variables['LINKER_SUPPORTS_ICF'] = \
|
||||
gyp.system_test.TestLinkerSupportsICF(cc_command=cc_target)
|
||||
|
||||
flavor = GetFlavor(params)
|
||||
flavor = gyp.common.GetFlavor(params)
|
||||
if flavor == 'mac':
|
||||
default_variables.setdefault('OS', 'mac')
|
||||
default_variables.setdefault('SHARED_LIB_SUFFIX', '.dylib')
|
||||
|
@ -2722,7 +2710,7 @@ def CopyTool(flavor, out_path):
|
|||
|
||||
def GenerateOutput(target_list, target_dicts, data, params):
|
||||
options = params['options']
|
||||
flavor = GetFlavor(params)
|
||||
flavor = gyp.common.GetFlavor(params)
|
||||
generator_flags = params.get('generator_flags', {})
|
||||
builddir_name = generator_flags.get('output_dir', 'out')
|
||||
android_ndk_version = generator_flags.get('android_ndk_version', None)
|
||||
|
|
|
@ -13,18 +13,15 @@ import sys
|
|||
import gyp.ninja_syntax as ninja_syntax
|
||||
|
||||
generator_default_variables = {
|
||||
'OS': 'linux',
|
||||
|
||||
'EXECUTABLE_PREFIX': '',
|
||||
'EXECUTABLE_SUFFIX': '',
|
||||
'STATIC_LIB_PREFIX': '',
|
||||
'STATIC_LIB_SUFFIX': '.a',
|
||||
'SHARED_LIB_PREFIX': 'lib',
|
||||
'SHARED_LIB_SUFFIX': '.so',
|
||||
|
||||
# Gyp expects the following variables to be expandable by the build
|
||||
# system to the appropriate locations. Ninja prefers paths to be
|
||||
# known at compile time. To resolve this, introduce special
|
||||
# known at gyp time. To resolve this, introduce special
|
||||
# variables starting with $! (which begin with a $ so gyp knows it
|
||||
# should be treated as a path, but is otherwise an invalid
|
||||
# ninja/shell variable) that are passed to gyp here but expanded
|
||||
|
@ -103,7 +100,7 @@ def InvertRelativePath(path):
|
|||
# to the input file name as well as the output target name.
|
||||
|
||||
class NinjaWriter:
|
||||
def __init__(self, target_outputs, base_dir, build_dir, output_file):
|
||||
def __init__(self, target_outputs, base_dir, build_dir, output_file, flavor):
|
||||
"""
|
||||
base_dir: path from source root to directory containing this gyp file,
|
||||
by gyp semantics, all input paths are relative to this
|
||||
|
@ -114,6 +111,7 @@ class NinjaWriter:
|
|||
self.base_dir = base_dir
|
||||
self.build_dir = build_dir
|
||||
self.ninja = ninja_syntax.Writer(output_file)
|
||||
self.flavor = flavor
|
||||
|
||||
# Relative path from build output dir to base dir.
|
||||
self.build_to_base = os.path.join(InvertRelativePath(build_dir), base_dir)
|
||||
|
@ -422,18 +420,32 @@ class NinjaWriter:
|
|||
self.ninja.variable('cc', '$cc_host')
|
||||
self.ninja.variable('cxx', '$cxx_host')
|
||||
|
||||
if self.flavor == 'mac':
|
||||
# TODO(jeremya/thakis): Extract these from XcodeSettings instead.
|
||||
cflags = []
|
||||
cflags_c = []
|
||||
cflags_cc = []
|
||||
cflags_objc = []
|
||||
cflags_objcc = []
|
||||
else:
|
||||
cflags = config.get('cflags', [])
|
||||
cflags_c = config.get('cflags_c', [])
|
||||
cflags_cc = config.get('cflags_cc', [])
|
||||
|
||||
self.WriteVariableList('defines',
|
||||
[QuoteShellArgument(ninja_syntax.escape('-D' + d))
|
||||
for d in config.get('defines', [])])
|
||||
self.WriteVariableList('includes',
|
||||
['-I' + self.GypPathToNinja(i)
|
||||
for i in config.get('include_dirs', [])])
|
||||
self.WriteVariableList('cflags', map(self.ExpandSpecial,
|
||||
config.get('cflags', [])))
|
||||
self.WriteVariableList('cflags_c', map(self.ExpandSpecial,
|
||||
config.get('cflags_c', [])))
|
||||
self.WriteVariableList('cflags_cc', map(self.ExpandSpecial,
|
||||
config.get('cflags_cc', [])))
|
||||
self.WriteVariableList('cflags', map(self.ExpandSpecial, cflags))
|
||||
self.WriteVariableList('cflags_c', map(self.ExpandSpecial, cflags_c))
|
||||
self.WriteVariableList('cflags_cc', map(self.ExpandSpecial, cflags_cc))
|
||||
if self.flavor == 'mac':
|
||||
self.WriteVariableList('cflags_objc', map(self.ExpandSpecial,
|
||||
cflags_objc))
|
||||
self.WriteVariableList('cflags_objcc', map(self.ExpandSpecial,
|
||||
cflags_objcc))
|
||||
self.ninja.newline()
|
||||
outputs = []
|
||||
for source in sources:
|
||||
|
@ -443,6 +455,10 @@ class NinjaWriter:
|
|||
command = 'cxx'
|
||||
elif ext in ('c', 's', 'S'):
|
||||
command = 'cc'
|
||||
elif self.flavor == 'mac' and ext == 'm':
|
||||
command = 'objc'
|
||||
elif self.flavor == 'mac' and ext == 'mm':
|
||||
command = 'objcxx'
|
||||
else:
|
||||
# TODO: should we assert here on unexpected extensions?
|
||||
continue
|
||||
|
@ -498,9 +514,14 @@ class NinjaWriter:
|
|||
command = command_map[spec['type']]
|
||||
|
||||
if output_uses_linker:
|
||||
if self.flavor == 'mac':
|
||||
# TODO(jeremya/thakis): Get this from XcodeSettings.
|
||||
ldflags = []
|
||||
else:
|
||||
ldflags = config.get('ldflags', [])
|
||||
self.WriteVariableList('ldflags',
|
||||
gyp.common.uniquer(map(self.ExpandSpecial,
|
||||
config.get('ldflags', []))))
|
||||
ldflags)))
|
||||
self.WriteVariableList('libs',
|
||||
gyp.common.uniquer(map(self.ExpandSpecial,
|
||||
spec.get('libraries', []))))
|
||||
|
@ -534,6 +555,10 @@ class NinjaWriter:
|
|||
'loadable_module': 'so',
|
||||
'shared_library': 'so',
|
||||
}
|
||||
# TODO(thakis/jeremya): Remove once the mac path name computation is done
|
||||
# by XcodeSettings.
|
||||
if self.flavor == 'mac':
|
||||
DEFAULT_EXTENSION['shared_library'] = 'dylib'
|
||||
extension = spec.get('product_extension',
|
||||
DEFAULT_EXTENSION.get(spec['type'], ''))
|
||||
if extension:
|
||||
|
@ -576,6 +601,10 @@ class NinjaWriter:
|
|||
if self.toolset != 'target':
|
||||
libdir = 'lib/%s' % self.toolset
|
||||
return os.path.join(libdir, filename)
|
||||
# TODO(thakis/jeremya): Remove once the mac path name computation is done
|
||||
# by XcodeSettings.
|
||||
elif spec['type'] == 'static_library' and self.flavor == 'mac':
|
||||
return filename
|
||||
else:
|
||||
return self.GypPathToUniqueOutput(filename, qualified=False)
|
||||
|
||||
|
@ -619,6 +648,32 @@ def CalculateVariables(default_variables, params):
|
|||
default_variables['LINKER_SUPPORTS_ICF'] = \
|
||||
gyp.system_test.TestLinkerSupportsICF(cc_command=cc_target)
|
||||
|
||||
flavor = gyp.common.GetFlavor(params)
|
||||
if flavor == 'mac':
|
||||
default_variables.setdefault('OS', 'mac')
|
||||
default_variables.setdefault('SHARED_LIB_SUFFIX', '.dylib')
|
||||
|
||||
# TODO(jeremya/thakis): Set SHARED_LIB_DIR / LIB_DIR.
|
||||
|
||||
# Copy additional generator configuration data from Xcode, which is shared
|
||||
# by the Mac Ninja generator.
|
||||
import gyp.generator.xcode as xcode_generator
|
||||
global generator_additional_non_configuration_keys
|
||||
generator_additional_non_configuration_keys = getattr(xcode_generator,
|
||||
'generator_additional_non_configuration_keys', [])
|
||||
global generator_additional_path_sections
|
||||
generator_additional_path_sections = getattr(xcode_generator,
|
||||
'generator_additional_path_sections', [])
|
||||
global generator_extra_sources_for_rules
|
||||
generator_extra_sources_for_rules = getattr(xcode_generator,
|
||||
'generator_extra_sources_for_rules', [])
|
||||
else:
|
||||
operating_system = flavor
|
||||
if flavor == 'android':
|
||||
operating_system = 'linux' # Keep this legacy behavior for now.
|
||||
default_variables.setdefault('OS', operating_system)
|
||||
default_variables.setdefault('SHARED_LIB_SUFFIX', '.so')
|
||||
|
||||
|
||||
def OpenOutput(path):
|
||||
"""Open |path| for writing, creating directories if necessary."""
|
||||
|
@ -631,6 +686,7 @@ def OpenOutput(path):
|
|||
|
||||
def GenerateOutput(target_list, target_dicts, data, params):
|
||||
options = params['options']
|
||||
flavor = gyp.common.GetFlavor(params)
|
||||
generator_flags = params.get('generator_flags', {})
|
||||
|
||||
if options.generator_output:
|
||||
|
@ -653,7 +709,13 @@ def GenerateOutput(target_list, target_dicts, data, params):
|
|||
# TODO: compute cc/cxx/ld/etc. by command-line arguments and system tests.
|
||||
master_ninja.variable('cc', os.environ.get('CC', 'gcc'))
|
||||
master_ninja.variable('cxx', os.environ.get('CXX', 'g++'))
|
||||
master_ninja.variable('ld', '$cxx -Wl,--threads -Wl,--thread-count=4')
|
||||
# TODO(bradnelson): remove NOGOLD when this is resolved:
|
||||
# http://code.google.com/p/chromium/issues/detail?id=108251
|
||||
if flavor != 'mac' and not os.environ.get('NOGOLD'):
|
||||
master_ninja.variable('ld', '$cxx -Wl,--threads -Wl,--thread-count=4')
|
||||
else:
|
||||
# TODO(jeremya/thakis): flock
|
||||
master_ninja.variable('ld', '$cxx')
|
||||
master_ninja.variable('cc_host', '$cc')
|
||||
master_ninja.variable('cxx_host', '$cxx')
|
||||
master_ninja.newline()
|
||||
|
@ -670,25 +732,60 @@ def GenerateOutput(target_list, target_dicts, data, params):
|
|||
command=('$cxx -MMD -MF $out.d $defines $includes $cflags $cflags_cc '
|
||||
'-c $in -o $out'),
|
||||
depfile='$out.d')
|
||||
master_ninja.rule(
|
||||
'alink',
|
||||
description='AR $out',
|
||||
command='rm -f $out && ar rcsT $out $in')
|
||||
master_ninja.rule(
|
||||
'solink',
|
||||
description='SOLINK $out',
|
||||
command=('$ld -shared $ldflags -o $out -Wl,-soname=$soname '
|
||||
'-Wl,--whole-archive $in -Wl,--no-whole-archive $libs'))
|
||||
master_ninja.rule(
|
||||
'solink_module',
|
||||
description='SOLINK(module) $out',
|
||||
command=('$ld -shared $ldflags -o $out -Wl,-soname=$soname '
|
||||
'-Wl,--start-group $in -Wl,--end-group $libs'))
|
||||
master_ninja.rule(
|
||||
'link',
|
||||
description='LINK $out',
|
||||
command=('$ld $ldflags -o $out -Wl,-rpath=\$$ORIGIN/lib '
|
||||
'-Wl,--start-group $in -Wl,--end-group $libs'))
|
||||
if flavor != 'mac':
|
||||
master_ninja.rule(
|
||||
'alink',
|
||||
description='AR $out',
|
||||
command='rm -f $out && ar rcsT $out $in')
|
||||
master_ninja.rule(
|
||||
'solink',
|
||||
description='SOLINK $out',
|
||||
command=('$ld -shared $ldflags -o $out -Wl,-soname=$soname '
|
||||
'-Wl,--whole-archive $in -Wl,--no-whole-archive $libs'))
|
||||
master_ninja.rule(
|
||||
'solink_module',
|
||||
description='SOLINK(module) $out',
|
||||
command=('$ld -shared $ldflags -o $out -Wl,-soname=$soname '
|
||||
'-Wl,--start-group $in -Wl,--end-group $libs'))
|
||||
master_ninja.rule(
|
||||
'link',
|
||||
description='LINK $out',
|
||||
command=('$ld $ldflags -o $out -Wl,-rpath=\$$ORIGIN/lib '
|
||||
'-Wl,--start-group $in -Wl,--end-group $libs'))
|
||||
else:
|
||||
master_ninja.rule(
|
||||
'objc',
|
||||
description='OBJC $out',
|
||||
command=('$cc -MMD -MF $out.d $defines $includes $cflags $cflags_c '
|
||||
'$cflags_objc -c $in -o $out'),
|
||||
depfile='$out.d')
|
||||
master_ninja.rule(
|
||||
'objcxx',
|
||||
description='OBJCXX $out',
|
||||
command=('$cxx -MMD -MF $out.d $defines $includes $cflags $cflags_cc '
|
||||
'$cflags_objcc -c $in -o $out'),
|
||||
depfile='$out.d')
|
||||
master_ninja.rule(
|
||||
'alink',
|
||||
description='LIBTOOL-STATIC $out',
|
||||
command='rm -f $out && libtool -static -o $out $in')
|
||||
# TODO(thakis): The solink_module rule is likely wrong. Xcode seems to pass
|
||||
# -bundle -single_module here (for osmesa.so).
|
||||
master_ninja.rule(
|
||||
'solink',
|
||||
description='SOLINK $out',
|
||||
command=('$ld -shared $ldflags -o $out '
|
||||
'$in $libs'))
|
||||
master_ninja.rule(
|
||||
'solink_module',
|
||||
description='SOLINK(module) $out',
|
||||
command=('$ld -shared $ldflags -o $out '
|
||||
'$in $libs'))
|
||||
master_ninja.rule(
|
||||
'link',
|
||||
description='LINK $out',
|
||||
command=('$ld $ldflags -o $out '
|
||||
'$in $libs'))
|
||||
master_ninja.rule(
|
||||
'stamp',
|
||||
description='STAMP $out',
|
||||
|
@ -696,7 +793,7 @@ def GenerateOutput(target_list, target_dicts, data, params):
|
|||
master_ninja.rule(
|
||||
'copy',
|
||||
description='COPY $in $out',
|
||||
command='ln -f $in $out 2>/dev/null || cp -af $in $out')
|
||||
command='ln -f $in $out 2>/dev/null || (rm -rf $out && cp -af $in $out)')
|
||||
master_ninja.newline()
|
||||
|
||||
all_targets = set()
|
||||
|
@ -726,7 +823,8 @@ def GenerateOutput(target_list, target_dicts, data, params):
|
|||
writer = NinjaWriter(target_outputs, base_path, builddir,
|
||||
OpenOutput(os.path.join(options.toplevel_dir,
|
||||
builddir,
|
||||
output_file)))
|
||||
output_file)),
|
||||
flavor)
|
||||
master_ninja.subninja(output_file)
|
||||
|
||||
output, compile_depends = writer.WriteSpec(spec, config)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
||||
# Copyright (c) 2011 Google Inc. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
|
@ -1358,6 +1358,13 @@ class DependencyGraphNode(object):
|
|||
# True) and this target won't be linked.
|
||||
return dependencies
|
||||
|
||||
# Don't traverse 'none' targets if explicitly excluded.
|
||||
if (target_type == 'none' and
|
||||
not targets[self.ref].get('dependencies_traverse', True)):
|
||||
if self.ref not in dependencies:
|
||||
dependencies.append(self.ref)
|
||||
return dependencies
|
||||
|
||||
# Executables and loadable modules are already fully and finally linked.
|
||||
# Nothing else can be a link dependency of them, there can only be
|
||||
# dependencies in the sense that a dependent target might run an
|
||||
|
|
|
@ -10,6 +10,10 @@ use Python.
|
|||
"""
|
||||
|
||||
import textwrap
|
||||
import re
|
||||
|
||||
def escape_spaces(word):
|
||||
return word.replace('$ ','$$ ').replace(' ','$ ')
|
||||
|
||||
class Writer(object):
|
||||
def __init__(self, output, width=78):
|
||||
|
@ -24,29 +28,40 @@ class Writer(object):
|
|||
self.output.write('# ' + line + '\n')
|
||||
|
||||
def variable(self, key, value, indent=0):
|
||||
if value is None:
|
||||
return
|
||||
if isinstance(value, list):
|
||||
value = ' '.join(value)
|
||||
self._line('%s = %s' % (key, value), indent)
|
||||
|
||||
def rule(self, name, command, description=None, depfile=None):
|
||||
def rule(self, name, command, description=None, depfile=None,
|
||||
generator=False):
|
||||
self._line('rule %s' % name)
|
||||
self.variable('command', command, indent=1)
|
||||
if description:
|
||||
self.variable('description', description, indent=1)
|
||||
if depfile:
|
||||
self.variable('depfile', depfile, indent=1)
|
||||
if generator:
|
||||
self.variable('generator', '1', indent=1)
|
||||
|
||||
def build(self, outputs, rule, inputs=None, implicit=None, order_only=None,
|
||||
variables=None):
|
||||
outputs = self._as_list(outputs)
|
||||
all_inputs = self._as_list(inputs)[:]
|
||||
out_outputs = map(escape_spaces, outputs)
|
||||
all_inputs = map(escape_spaces, all_inputs)
|
||||
|
||||
if implicit:
|
||||
implicit = map(escape_spaces, self._as_list(implicit))
|
||||
all_inputs.append('|')
|
||||
all_inputs.extend(self._as_list(implicit))
|
||||
all_inputs.extend(implicit)
|
||||
if order_only:
|
||||
order_only = map(escape_spaces, self._as_list(order_only))
|
||||
all_inputs.append('||')
|
||||
all_inputs.extend(self._as_list(order_only))
|
||||
all_inputs.extend(order_only)
|
||||
|
||||
self._line('build %s: %s %s' % (' '.join(outputs),
|
||||
self._line('build %s: %s %s' % (' '.join(out_outputs),
|
||||
rule,
|
||||
' '.join(all_inputs)))
|
||||
|
||||
|
@ -62,28 +77,52 @@ class Writer(object):
|
|||
def subninja(self, path):
|
||||
self._line('subninja %s' % path)
|
||||
|
||||
def default(self, paths):
|
||||
self._line('default %s' % ' '.join(self._as_list(paths)))
|
||||
|
||||
def _line(self, text, indent=0):
|
||||
"""Write 'text' word-wrapped at self.width characters."""
|
||||
leading_space = ' ' * indent
|
||||
while len(text) > self.width:
|
||||
# The text is too wide; wrap if possible.
|
||||
|
||||
# Find the rightmost space that would obey our width constraint.
|
||||
available_space = self.width - len(leading_space) - len(' $')
|
||||
space = text.rfind(' ', 0, available_space)
|
||||
if space < 0:
|
||||
# No such space; just use the first space we can find.
|
||||
space = text.find(' ', available_space)
|
||||
if space < 0:
|
||||
# Give up on breaking.
|
||||
break
|
||||
self.output.write(leading_space)
|
||||
|
||||
self.output.write(leading_space + text[0:space] + ' $\n')
|
||||
text = text[space+1:]
|
||||
available_space = self.width - len(leading_space) - len(' $')
|
||||
|
||||
# Write as much as we can into this line.
|
||||
done = False
|
||||
written_stuff = False
|
||||
while available_space > 0:
|
||||
space = re.search('((\$\$)+([^$]|^)|[^$]|^) ', text)
|
||||
if space:
|
||||
space_idx = space.start() + 1
|
||||
else:
|
||||
# No spaces left.
|
||||
done = True
|
||||
break
|
||||
|
||||
if space_idx > available_space:
|
||||
# We're out of space.
|
||||
if written_stuff:
|
||||
# See if we can fit it on the next line.
|
||||
break
|
||||
# If we haven't written anything yet on this line, don't
|
||||
# try to wrap.
|
||||
self.output.write(text[0:space_idx] + ' ')
|
||||
written_stuff = True
|
||||
text = text[space_idx+1:]
|
||||
available_space -= space_idx+1
|
||||
|
||||
self.output.write('$\n')
|
||||
|
||||
# Subsequent lines are continuations, so indent them.
|
||||
leading_space = ' ' * (indent+2)
|
||||
|
||||
if done:
|
||||
# No more spaces, so bail.
|
||||
break
|
||||
|
||||
self.output.write(leading_space + text + '\n')
|
||||
|
||||
def _as_list(self, input):
|
||||
|
|
|
@ -11,5 +11,12 @@
|
|||
'b.c',
|
||||
],
|
||||
},
|
||||
{
|
||||
'target_name': 'b3',
|
||||
'type': 'static_library',
|
||||
'sources': [
|
||||
'b3.c',
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
* Copyright (c) 2011 Google Inc. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
int funcB() {
|
||||
return 3;
|
||||
}
|
|
@ -29,7 +29,7 @@ if sys.platform == 'darwin':
|
|||
if test.format == 'xcode':
|
||||
test.built_file_must_not_exist('b', type=test.STATIC_LIB)
|
||||
else:
|
||||
assert test.format == 'make'
|
||||
assert test.format in ('make', 'ninja')
|
||||
test.built_file_must_exist('b', type=test.STATIC_LIB)
|
||||
else:
|
||||
# Make puts the resulting library in a directory matching the input gyp file;
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Copyright (c) 2011 Google Inc. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""
|
||||
Verify that static library dependencies don't traverse none targets, unless
|
||||
explicitly specified.
|
||||
"""
|
||||
|
||||
import TestGyp
|
||||
|
||||
import sys
|
||||
|
||||
test = TestGyp.TestGyp()
|
||||
|
||||
test.run_gyp('none_traversal.gyp')
|
||||
|
||||
test.build('none_traversal.gyp', test.ALL)
|
||||
|
||||
test.run_built_executable('needs_chain', stdout="2\n")
|
||||
test.run_built_executable('doesnt_need_chain', stdout="3\n")
|
||||
|
||||
test.pass_test()
|
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* Copyright (c) 2011 Google Inc. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
extern int funcA();
|
||||
|
||||
int main() {
|
||||
printf("%d\n", funcA());
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
# Copyright (c) 2009 Google Inc. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
{
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'needs_chain',
|
||||
'type': 'executable',
|
||||
'sources': [
|
||||
'a.c',
|
||||
'main.c',
|
||||
],
|
||||
'dependencies': ['chain'],
|
||||
},
|
||||
{
|
||||
'target_name': 'chain',
|
||||
'type': 'none',
|
||||
'dependencies': ['b/b.gyp:b'],
|
||||
},
|
||||
{
|
||||
'target_name': 'doesnt_need_chain',
|
||||
'type': 'executable',
|
||||
'sources': [
|
||||
'main.c',
|
||||
],
|
||||
'dependencies': ['no_chain', 'other_chain'],
|
||||
},
|
||||
{
|
||||
'target_name': 'no_chain',
|
||||
'type': 'none',
|
||||
'sources': [
|
||||
],
|
||||
'dependencies': ['b/b.gyp:b'],
|
||||
'dependencies_traverse': 0,
|
||||
},
|
||||
{
|
||||
'target_name': 'other_chain',
|
||||
'type': 'static_library',
|
||||
'sources': [
|
||||
'a.c',
|
||||
],
|
||||
'dependencies': ['b/b.gyp:b3'],
|
||||
},
|
||||
],
|
||||
}
|
|
@ -449,6 +449,11 @@ class TestGypNinja(TestGypBase):
|
|||
def run_built_executable(self, name, *args, **kw):
|
||||
# Enclosing the name in a list avoids prepending the original dir.
|
||||
program = [self.built_file_path(name, type=self.EXECUTABLE, **kw)]
|
||||
if sys.platform == 'darwin':
|
||||
libdir = os.path.join('out', 'Default', 'lib')
|
||||
if self.configuration:
|
||||
libdir = os.path.join('out', self.configuration, 'lib')
|
||||
os.environ['DYLD_LIBRARY_PATH'] = libdir
|
||||
return self.run(program=program, *args, **kw)
|
||||
|
||||
def built_file_path(self, name, type=None, **kw):
|
||||
|
@ -458,9 +463,10 @@ class TestGypNinja(TestGypBase):
|
|||
result.append(chdir)
|
||||
result.append('out')
|
||||
result.append(self.configuration_dirname())
|
||||
if type in (self.STATIC_LIB,):
|
||||
result.append('obj')
|
||||
elif type in (self.SHARED_LIB,):
|
||||
if type == self.STATIC_LIB:
|
||||
if sys.platform != 'darwin':
|
||||
result.append('obj')
|
||||
elif type == self.SHARED_LIB:
|
||||
result.append('lib')
|
||||
subdir = kw.get('subdir')
|
||||
if subdir:
|
||||
|
@ -469,8 +475,13 @@ class TestGypNinja(TestGypBase):
|
|||
return self.workpath(*result)
|
||||
|
||||
def up_to_date(self, gyp_file, target=None, **kw):
|
||||
kw['stdout'] = "ninja: no work to do.\n"
|
||||
return self.build(gyp_file, target, **kw)
|
||||
result = self.build(gyp_file, target, **kw)
|
||||
if not result:
|
||||
stdout = self.stdout()
|
||||
if 'ninja: no work to do' not in stdout:
|
||||
self.report_not_up_to_date()
|
||||
self.fail_test()
|
||||
return result
|
||||
|
||||
|
||||
class TestGypMSVS(TestGypBase):
|
||||
|
@ -569,7 +580,7 @@ class TestGypMSVS(TestGypBase):
|
|||
'C:\PROGRAM FILES (X86)\MICROSOFT VISUAL STUDIO 10.0\VC\BIN\1033\CLUI.DLL'
|
||||
was modified at 02/21/2011 17:03:30, which is newer than '' which was
|
||||
modified at 01/01/0001 00:00:00.
|
||||
|
||||
|
||||
The workaround is to specify a workdir when instantiating the test, e.g.
|
||||
test = TestGyp.TestGyp(workdir='workarea')
|
||||
"""
|
||||
|
|
Загрузка…
Ссылка в новой задаче