diff --git a/tools/gyp/buildbot/buildbot_run.py b/tools/gyp/buildbot/buildbot_run.py index df1cc8ad5e..a8531258b2 100755 --- a/tools/gyp/buildbot/buildbot_run.py +++ b/tools/gyp/buildbot/buildbot_run.py @@ -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': diff --git a/tools/gyp/gyptest.py b/tools/gyp/gyptest.py index 0cf38b15c5..e8bf482d99 100755 --- a/tools/gyp/gyptest.py +++ b/tools/gyp/gyptest.py @@ -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: diff --git a/tools/gyp/pylib/gyp/common.py b/tools/gyp/pylib/gyp/common.py index b44b0956f7..97594cd5d6 100644 --- a/tools/gyp/pylib/gyp/common.py +++ b/tools/gyp/pylib/gyp/common.py @@ -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 diff --git a/tools/gyp/pylib/gyp/generator/dump_dependency_json.py b/tools/gyp/pylib/gyp/generator/dump_dependency_json.py index ada1d35b07..1e0900a231 100644 --- a/tools/gyp/pylib/gyp/generator/dump_dependency_json.py +++ b/tools/gyp/pylib/gyp/generator/dump_dependency_json.py @@ -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): diff --git a/tools/gyp/pylib/gyp/generator/make.py b/tools/gyp/pylib/gyp/generator/make.py index 31c016e4c8..87ad79a675 100644 --- a/tools/gyp/pylib/gyp/generator/make.py +++ b/tools/gyp/pylib/gyp/generator/make.py @@ -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) diff --git a/tools/gyp/pylib/gyp/generator/ninja.py b/tools/gyp/pylib/gyp/generator/ninja.py index b307da650d..193f295a55 100644 --- a/tools/gyp/pylib/gyp/generator/ninja.py +++ b/tools/gyp/pylib/gyp/generator/ninja.py @@ -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) diff --git a/tools/gyp/pylib/gyp/input.py b/tools/gyp/pylib/gyp/input.py index ef30efa4da..19a16288cd 100644 --- a/tools/gyp/pylib/gyp/input.py +++ b/tools/gyp/pylib/gyp/input.py @@ -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 diff --git a/tools/gyp/pylib/gyp/ninja_syntax.py b/tools/gyp/pylib/gyp/ninja_syntax.py index d4776fb236..35cda05707 100644 --- a/tools/gyp/pylib/gyp/ninja_syntax.py +++ b/tools/gyp/pylib/gyp/ninja_syntax.py @@ -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): diff --git a/tools/gyp/test/dependencies/b/b.gyp b/tools/gyp/test/dependencies/b/b.gyp index f09e1ff13c..893dc64d65 100755 --- a/tools/gyp/test/dependencies/b/b.gyp +++ b/tools/gyp/test/dependencies/b/b.gyp @@ -11,5 +11,12 @@ 'b.c', ], }, + { + 'target_name': 'b3', + 'type': 'static_library', + 'sources': [ + 'b3.c', + ], + }, ], } diff --git a/tools/gyp/test/dependencies/b/b3.c b/tools/gyp/test/dependencies/b/b3.c new file mode 100755 index 0000000000..287f67ff31 --- /dev/null +++ b/tools/gyp/test/dependencies/b/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; +} diff --git a/tools/gyp/test/dependencies/gyptest-lib-only.py b/tools/gyp/test/dependencies/gyptest-lib-only.py index 4355d578ae..02159f5f15 100755 --- a/tools/gyp/test/dependencies/gyptest-lib-only.py +++ b/tools/gyp/test/dependencies/gyptest-lib-only.py @@ -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; diff --git a/tools/gyp/test/dependencies/gyptest-none-traversal.py b/tools/gyp/test/dependencies/gyptest-none-traversal.py new file mode 100755 index 0000000000..c09063dad3 --- /dev/null +++ b/tools/gyp/test/dependencies/gyptest-none-traversal.py @@ -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() diff --git a/tools/gyp/test/dependencies/main.c b/tools/gyp/test/dependencies/main.c new file mode 100644 index 0000000000..185bd482f2 --- /dev/null +++ b/tools/gyp/test/dependencies/main.c @@ -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 + +extern int funcA(); + +int main() { + printf("%d\n", funcA()); + return 0; +} diff --git a/tools/gyp/test/dependencies/none_traversal.gyp b/tools/gyp/test/dependencies/none_traversal.gyp new file mode 100755 index 0000000000..3d8ab30aff --- /dev/null +++ b/tools/gyp/test/dependencies/none_traversal.gyp @@ -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'], + }, + ], +} diff --git a/tools/gyp/test/lib/TestGyp.py b/tools/gyp/test/lib/TestGyp.py index a65c3e2440..2b4b0db967 100644 --- a/tools/gyp/test/lib/TestGyp.py +++ b/tools/gyp/test/lib/TestGyp.py @@ -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') """