--- a/media/webrtc/trunk/tools/gyp/AUTHORS
+++ b/media/webrtc/trunk/tools/gyp/AUTHORS
@@ -1,6 +1,13 @@
# Names should be added to this file like so:
# Name or Organization <email address>
Google Inc.
+Bloomberg Finance L.P.
+Yandex LLC
+
Steven Knight <knight@baldmt.com>
Ryan Norton <rnorton10@gmail.com>
+David J. Sankel <david@sankelsoftware.com>
+Eric N. Vander Weele <ericvw@gmail.com>
+Tom Freudenberg <th.freudenberg@gmail.com>
+Julien Brianceau <jbriance@cisco.com>
--- a/media/webrtc/trunk/tools/gyp/DEPS
+++ b/media/webrtc/trunk/tools/gyp/DEPS
@@ -1,26 +1,23 @@
# DEPS file for gclient use in buildbot execution of gyp tests.
#
# (You don't need to use gclient for normal GYP development work.)
vars = {
- "chrome_trunk": "http://src.chromium.org/svn/trunk",
- "googlecode_url": "http://%s.googlecode.com/svn",
+ "chromium_git": "https://chromium.googlesource.com/",
}
deps = {
- "scons":
- Var("chrome_trunk") + "/src/third_party/scons@44099",
}
deps_os = {
"win": {
"third_party/cygwin":
- Var("chrome_trunk") + "/deps/third_party/cygwin@66844",
+ Var("chromium_git") + "chromium/deps/cygwin@4fbd5b9",
"third_party/python_26":
- Var("chrome_trunk") + "/tools/third_party/python_26@89111",
+ Var("chromium_git") + "chromium/deps/python_26@5bb4080",
"src/third_party/pefile":
- (Var("googlecode_url") % "pefile") + "/trunk@63",
+ Var("chromium_git") + "external/pefile@72c6ae4",
},
}
deleted file mode 100644
--- a/media/webrtc/trunk/tools/gyp/MANIFEST
+++ /dev/null
@@ -1,21 +0,0 @@
-setup.py
-gyp
-LICENSE
-AUTHORS
-pylib/gyp/MSVSNew.py
-pylib/gyp/MSVSProject.py
-pylib/gyp/MSVSToolFile.py
-pylib/gyp/MSVSUserFile.py
-pylib/gyp/MSVSVersion.py
-pylib/gyp/SCons.py
-pylib/gyp/__init__.py
-pylib/gyp/common.py
-pylib/gyp/input.py
-pylib/gyp/xcodeproj_file.py
-pylib/gyp/generator/__init__.py
-pylib/gyp/generator/gypd.py
-pylib/gyp/generator/gypsh.py
-pylib/gyp/generator/make.py
-pylib/gyp/generator/msvs.py
-pylib/gyp/generator/scons.py
-pylib/gyp/generator/xcode.py
--- a/media/webrtc/trunk/tools/gyp/PRESUBMIT.py
+++ b/media/webrtc/trunk/tools/gyp/PRESUBMIT.py
@@ -11,57 +11,64 @@ for more details about the presubmit API
PYLINT_BLACKLIST = [
# TODO: fix me.
# From SCons, not done in google style.
'test/lib/TestCmd.py',
'test/lib/TestCommon.py',
'test/lib/TestGyp.py',
- # Needs style fix.
- 'pylib/gyp/generator/scons.py',
- 'pylib/gyp/generator/xcode.py',
]
PYLINT_DISABLED_WARNINGS = [
# TODO: fix me.
# Many tests include modules they don't use.
'W0611',
+ # Possible unbalanced tuple unpacking with sequence.
+ 'W0632',
+ # Attempting to unpack a non-sequence.
+ 'W0633',
# Include order doesn't properly include local files?
'F0401',
# Some use of built-in names.
'W0622',
# Some unused variables.
'W0612',
# Operator not preceded/followed by space.
'C0323',
'C0322',
# Unnecessary semicolon.
'W0301',
# Unused argument.
'W0613',
# String has no effect (docstring in wrong place).
'W0105',
+ # map/filter on lambda could be replaced by comprehension.
+ 'W0110',
+ # Use of eval.
+ 'W0123',
# Comma not followed by space.
'C0324',
# Access to a protected member.
'W0212',
# Bad indent.
'W0311',
# Line too long.
'C0301',
# Undefined variable.
'E0602',
# Not exception type specified.
'W0702',
# No member of that name.
'E1101',
# Dangerous default {}.
'W0102',
+ # Cyclic import.
+ 'R0401',
# Others, too many to sort.
'W0201', 'W0232', 'E1103', 'W0621', 'W0108', 'W0223', 'W0231',
'R0201', 'E0101', 'C0321',
# ************* Module copy
# W0104:427,12:_test.odict.__setitem__: Statement seems to have no effect
'W0104',
]
@@ -70,40 +77,61 @@ def CheckChangeOnUpload(input_api, outpu
report = []
report.extend(input_api.canned_checks.PanProjectChecks(
input_api, output_api))
return report
def CheckChangeOnCommit(input_api, output_api):
report = []
+
+ # Accept any year number from 2009 to the current year.
+ current_year = int(input_api.time.strftime('%Y'))
+ allowed_years = (str(s) for s in reversed(xrange(2009, current_year + 1)))
+ years_re = '(' + '|'.join(allowed_years) + ')'
+
+ # The (c) is deprecated, but tolerate it until it's removed from all files.
license = (
- r'.*? Copyright \(c\) %(year)s Google Inc\. All rights reserved\.\n'
+ r'.*? Copyright (\(c\) )?%(year)s Google Inc\. All rights reserved\.\n'
r'.*? Use of this source code is governed by a BSD-style license that '
r'can be\n'
r'.*? found in the LICENSE file\.\n'
) % {
- 'year': input_api.time.strftime('%Y'),
+ 'year': years_re,
}
report.extend(input_api.canned_checks.PanProjectChecks(
input_api, output_api, license_header=license))
report.extend(input_api.canned_checks.CheckTreeIsOpen(
input_api, output_api,
'http://gyp-status.appspot.com/status',
'http://gyp-status.appspot.com/current'))
+ import os
import sys
old_sys_path = sys.path
try:
sys.path = ['pylib', 'test/lib'] + sys.path
+ blacklist = PYLINT_BLACKLIST
+ if sys.platform == 'win32':
+ blacklist = [os.path.normpath(x).replace('\\', '\\\\')
+ for x in PYLINT_BLACKLIST]
report.extend(input_api.canned_checks.RunPylint(
input_api,
output_api,
- black_list=PYLINT_BLACKLIST,
+ black_list=blacklist,
disabled_warnings=PYLINT_DISABLED_WARNINGS))
finally:
sys.path = old_sys_path
return report
-def GetPreferredTrySlaves():
- return ['gyp-win32', 'gyp-win64', 'gyp-linux', 'gyp-mac']
+TRYBOTS = [
+ 'linux_try',
+ 'mac_try',
+ 'win_try',
+]
+
+
+def GetPreferredTryMasters(_, change):
+ return {
+ 'client.gyp': { t: set(['defaulttests']) for t in TRYBOTS },
+ }
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/README.md
@@ -0,0 +1,4 @@
+GYP can Generate Your Projects.
+===================================
+
+Documents are available at [gyp.gsrc.io](https://gyp.gsrc.io), or you can check out ```md-pages``` branch to read those documents offline.
--- a/media/webrtc/trunk/tools/gyp/buildbot/buildbot_run.py
+++ b/media/webrtc/trunk/tools/gyp/buildbot/buildbot_run.py
@@ -1,65 +1,97 @@
#!/usr/bin/env python
# Copyright (c) 2012 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.
-
"""Argument-less script to select what to run on the buildbots."""
-
import os
import shutil
import subprocess
import sys
-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)
+CMAKE_DIR = os.path.join(ROOT_DIR, 'cmake')
+CMAKE_BIN_DIR = os.path.join(CMAKE_DIR, 'bin')
OUT_DIR = os.path.join(TRUNK_DIR, 'out')
-def GypTestFormat(title, format=None, msvs_version=None):
+def CallSubProcess(*args, **kwargs):
+ """Wrapper around subprocess.call which treats errors as build exceptions."""
+ with open(os.devnull) as devnull_fd:
+ retcode = subprocess.call(stdin=devnull_fd, *args, **kwargs)
+ if retcode != 0:
+ print '@@@STEP_EXCEPTION@@@'
+ sys.exit(1)
+
+
+def PrepareCmake():
+ """Build CMake 2.8.8 since the version in Precise is 2.8.7."""
+ if os.environ['BUILDBOT_CLOBBER'] == '1':
+ print '@@@BUILD_STEP Clobber CMake checkout@@@'
+ shutil.rmtree(CMAKE_DIR)
+
+ # We always build CMake 2.8.8, so no need to do anything
+ # if the directory already exists.
+ if os.path.isdir(CMAKE_DIR):
+ return
+
+ print '@@@BUILD_STEP Initialize CMake checkout@@@'
+ os.mkdir(CMAKE_DIR)
+
+ print '@@@BUILD_STEP Sync CMake@@@'
+ CallSubProcess(
+ ['git', 'clone',
+ '--depth', '1',
+ '--single-branch',
+ '--branch', 'v2.8.8',
+ '--',
+ 'git://cmake.org/cmake.git',
+ CMAKE_DIR],
+ cwd=CMAKE_DIR)
+
+ print '@@@BUILD_STEP Build CMake@@@'
+ CallSubProcess(
+ ['/bin/bash', 'bootstrap', '--prefix=%s' % CMAKE_DIR],
+ cwd=CMAKE_DIR)
+
+ CallSubProcess( ['make', 'cmake'], cwd=CMAKE_DIR)
+
+
+def GypTestFormat(title, format=None, msvs_version=None, tests=[]):
"""Run the gyp tests for a given format, emitting annotator tags.
See annotator docs at:
https://sites.google.com/a/chromium.org/dev/developers/testing/chromium-build-infrastructure/buildbot-annotations
Args:
format: gyp format to test.
Returns:
0 for sucesss, 1 for failure.
"""
if not format:
format = title
print '@@@BUILD_STEP ' + title + '@@@'
sys.stdout.flush()
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(
- [sys.executable, 'trunk/gyptest.py',
+ command = ' '.join(
+ [sys.executable, 'gyp/gyptest.py',
'--all',
'--passed',
'--format', format,
- '--chdir', 'trunk',
- '--path', '../scons']),
- cwd=ROOT_DIR, env=env, shell=True)
+ '--path', CMAKE_BIN_DIR,
+ '--chdir', 'gyp'] + tests)
+ retcode = subprocess.call(command, cwd=ROOT_DIR, env=env, shell=True)
if retcode:
# Emit failure tag, and keep going.
print '@@@STEP_FAILURE@@@'
return 1
return 0
def GypBuild():
@@ -67,27 +99,33 @@ def GypBuild():
print '@@@BUILD_STEP cleanup@@@'
print 'Removing %s...' % OUT_DIR
shutil.rmtree(OUT_DIR, ignore_errors=True)
print 'Done.'
retcode = 0
if sys.platform.startswith('linux'):
retcode += GypTestFormat('ninja')
- retcode += GypTestFormat('scons')
retcode += GypTestFormat('make')
+ PrepareCmake()
+ retcode += GypTestFormat('cmake')
elif sys.platform == 'darwin':
retcode += GypTestFormat('ninja')
retcode += GypTestFormat('xcode')
retcode += GypTestFormat('make')
elif sys.platform == 'win32':
retcode += GypTestFormat('ninja')
- retcode += GypTestFormat('msvs-2008', format='msvs', msvs_version='2008')
if os.environ['BUILDBOT_BUILDERNAME'] == 'gyp-win64':
- retcode += GypTestFormat('msvs-2010', format='msvs', msvs_version='2010')
+ retcode += GypTestFormat('msvs-ninja-2013', format='msvs-ninja',
+ msvs_version='2013',
+ tests=[
+ r'test\generator-output\gyptest-actions.py',
+ r'test\generator-output\gyptest-relocate.py',
+ r'test\generator-output\gyptest-rules.py'])
+ retcode += GypTestFormat('msvs-2013', format='msvs', msvs_version='2013')
else:
raise Exception('Unknown platform')
if retcode:
# TODO(bradnelson): once the annotator supports a postscript (section for
# after the build proper that could be used for cumulative failures),
# use that instead of this. This isolates the final return value so
# that it isn't misattributed to the last stage.
print '@@@BUILD_STEP failures@@@'
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/buildbot/commit_queue/OWNERS
@@ -0,0 +1,6 @@
+set noparent
+bradnelson@chromium.org
+bradnelson@google.com
+iannucci@chromium.org
+scottmg@chromium.org
+thakis@chromium.org
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/buildbot/commit_queue/README
@@ -0,0 +1,3 @@
+cq_config.json describes the trybots that must pass in order
+to land a change through the commit queue.
+Comments are here as the file is strictly JSON.
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/buildbot/commit_queue/cq_config.json
@@ -0,0 +1,15 @@
+{
+ "trybots": {
+ "launched": {
+ "tryserver.nacl": {
+ "gyp-presubmit": ["defaulttests"],
+ "gyp-linux": ["defaulttests"],
+ "gyp-mac": ["defaulttests"],
+ "gyp-win32": ["defaulttests"],
+ "gyp-win64": ["defaulttests"]
+ }
+ },
+ "triggered": {
+ }
+ }
+}
--- a/media/webrtc/trunk/tools/gyp/codereview.settings
+++ b/media/webrtc/trunk/tools/gyp/codereview.settings
@@ -1,10 +1,10 @@
# This file is used by gcl to get repository specific information.
CODE_REVIEW_SERVER: codereview.chromium.org
CC_LIST: gyp-developer@googlegroups.com
-VIEW_VC: http://code.google.com/p/gyp/source/detail?r=
-TRY_ON_UPLOAD: True
+VIEW_VC: https://chromium.googlesource.com/external/gyp/+/
+TRY_ON_UPLOAD: False
TRYSERVER_PROJECT: gyp
-TRYSERVER_PATCHLEVEL: 0
-TRYSERVER_ROOT: trunk
+TRYSERVER_PATCHLEVEL: 1
+TRYSERVER_ROOT: gyp
TRYSERVER_SVN_URL: svn://svn.chromium.org/chrome-try/try-nacl
-
+PROJECT: gyp
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/data/win/large-pdb-shim.cc
@@ -0,0 +1,12 @@
+// Copyright (c) 2013 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.
+
+// This file is used to generate an empty .pdb -- with a 4KB pagesize -- that is
+// then used during the final link for modules that have large PDBs. Otherwise,
+// the linker will generate a pdb with a page size of 1KB, which imposes a limit
+// of 1GB on the .pdb. By generating an initial empty .pdb with the compiler
+// (rather than the linker), this limit is avoided. With this in place PDBs may
+// grow to 2GB.
+//
+// This file is referenced by the msvs_large_pdb mechanism in MSVSUtil.py.
--- a/media/webrtc/trunk/tools/gyp/gyp
+++ b/media/webrtc/trunk/tools/gyp/gyp
@@ -1,18 +1,8 @@
-#!/usr/bin/env python
-
-# Copyright (c) 2009 Google Inc. All rights reserved.
+#!/bin/sh
+# Copyright 2013 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import sys
-
-# TODO(mark): sys.path manipulation is some temporary testing stuff.
-try:
- import gyp
-except ImportError, e:
- import os.path
- sys.path.append(os.path.join(os.path.dirname(sys.argv[0]), 'pylib'))
- import gyp
-
-if __name__ == '__main__':
- sys.exit(gyp.main(sys.argv[1:]))
+set -e
+base=$(dirname "$0")
+exec python "${base}/gyp_main.py" "$@"
--- a/media/webrtc/trunk/tools/gyp/gyp.bat
+++ b/media/webrtc/trunk/tools/gyp/gyp.bat
@@ -1,5 +1,5 @@
@rem Copyright (c) 2009 Google Inc. All rights reserved.
@rem Use of this source code is governed by a BSD-style license that can be
@rem found in the LICENSE file.
-@python "%~dp0/gyp" %*
+@python "%~dp0gyp_main.py" %*
deleted file mode 100644
--- a/media/webrtc/trunk/tools/gyp/gyp_dummy.c
+++ /dev/null
@@ -1,7 +0,0 @@
-/* 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. */
-
-int main() {
- return 0;
-}
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/gyp_main.py
@@ -0,0 +1,16 @@
+#!/usr/bin/env python
+
+# 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.
+
+import os
+import sys
+
+# Make sure we're using the version of pylib in this repo, not one installed
+# elsewhere on the system.
+sys.path.insert(0, os.path.join(os.path.dirname(sys.argv[0]), 'pylib'))
+import gyp
+
+if __name__ == '__main__':
+ sys.exit(gyp.script_main())
--- a/media/webrtc/trunk/tools/gyp/gyptest.py
+++ b/media/webrtc/trunk/tools/gyp/gyptest.py
@@ -8,17 +8,17 @@
gyptest.py -- test runner for GYP tests.
"""
import os
import optparse
import subprocess
import sys
-class CommandRunner:
+class CommandRunner(object):
"""
Executor class for commands, including "commands" implemented by
Python functions.
"""
verbose = True
active = True
def __init__(self, dictionary={}):
@@ -112,38 +112,41 @@ class CommandRunner:
Runs a single command, displaying it first.
"""
if display is None:
display = command
self.display(display)
return self.execute(command, stdout, stderr)
-class Unbuffered:
+class Unbuffered(object):
def __init__(self, fp):
self.fp = fp
def write(self, arg):
self.fp.write(arg)
self.fp.flush()
def __getattr__(self, attr):
return getattr(self.fp, attr)
sys.stdout = Unbuffered(sys.stdout)
sys.stderr = Unbuffered(sys.stderr)
+def is_test_name(f):
+ return f.startswith('gyptest') and f.endswith('.py')
+
+
def find_all_gyptest_files(directory):
- result = []
- for root, dirs, files in os.walk(directory):
- if '.svn' in dirs:
- dirs.remove('.svn')
- result.extend([ os.path.join(root, f) for f in files
- if f.startswith('gyptest') and f.endswith('.py') ])
- result.sort()
- return result
+ result = []
+ for root, dirs, files in os.walk(directory):
+ if '.svn' in dirs:
+ dirs.remove('.svn')
+ result.extend([ os.path.join(root, f) for f in files if is_test_name(f) ])
+ result.sort()
+ return result
def main(argv=None):
if argv is None:
argv = sys.argv
usage = "gyptest.py [-ahlnq] [-f formats] [test ...]"
parser = optparse.OptionParser(usage=usage)
@@ -168,29 +171,32 @@ def main(argv=None):
opts, args = parser.parse_args(argv[1:])
if opts.chdir:
os.chdir(opts.chdir)
if opts.path:
extra_path = [os.path.abspath(p) for p in opts.path]
extra_path = os.pathsep.join(extra_path)
- os.environ['PATH'] += os.pathsep + extra_path
+ os.environ['PATH'] = extra_path + os.pathsep + os.environ['PATH']
if not args:
if not opts.all:
sys.stderr.write('Specify -a to get all tests.\n')
return 1
args = ['test']
tests = []
for arg in args:
if os.path.isdir(arg):
tests.extend(find_all_gyptest_files(os.path.normpath(arg)))
else:
+ if not is_test_name(os.path.basename(arg)):
+ print >>sys.stderr, arg, 'is not a valid gyp test name.'
+ sys.exit(1)
tests.append(arg)
if opts.list:
for test in tests:
print test
sys.exit(0)
CommandRunner.verbose = not opts.quiet
@@ -205,23 +211,25 @@ def main(argv=None):
failed = []
no_result = []
if opts.format:
format_list = opts.format.split(',')
else:
# TODO: not duplicate this mapping from pylib/gyp/__init__.py
format_list = {
+ 'aix5': ['make'],
'freebsd7': ['make'],
'freebsd8': ['make'],
+ 'openbsd5': ['make'],
'cygwin': ['msvs'],
'win32': ['msvs', 'ninja'],
'linux2': ['make', 'ninja'],
'linux3': ['make', 'ninja'],
- 'darwin': ['make', 'ninja', 'xcode'],
+ 'darwin': ['make', 'ninja', 'xcode', 'xcode-ninja'],
}[sys.platform]
for format in format_list:
os.environ['TESTGYP_FORMAT'] = format
if not opts.quiet:
sys.stdout.write('TESTGYP_FORMAT=%s\n' % format)
gyp_options = []
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/MSVSNew.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/MSVSNew.py
@@ -1,13 +1,13 @@
# Copyright (c) 2012 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.
-"""New implementation of Visual Studio project generation for SCons."""
+"""New implementation of Visual Studio project generation."""
import os
import random
import gyp.common
# hashlib is supplied as of Python 2.5 as the replacement interface for md5
# and other secure hashes. In 2.6, md5 is deprecated. Import hashlib if
@@ -167,17 +167,17 @@ class MSVSProject(MSVSSolutionEntry):
return self.guid
def set_msbuild_toolset(self, msbuild_toolset):
self.msbuild_toolset = msbuild_toolset
#------------------------------------------------------------------------------
-class MSVSSolution:
+class MSVSSolution(object):
"""Visual Studio solution."""
def __init__(self, path, version, entries=None, variants=None,
websiteProperties=True):
"""Initializes the solution.
Args:
path: Path to solution file.
@@ -320,20 +320,21 @@ class MSVSSolution:
# TODO(rspangler): Should be able to configure this stuff too (though I've
# never seen this be any different)
f.write('\tGlobalSection(SolutionProperties) = preSolution\r\n')
f.write('\t\tHideSolutionNode = FALSE\r\n')
f.write('\tEndGlobalSection\r\n')
# Folder mappings
- # TODO(rspangler): Should omit this section if there are no folders
- f.write('\tGlobalSection(NestedProjects) = preSolution\r\n')
- for e in all_entries:
- if not isinstance(e, MSVSFolder):
- continue # Does not apply to projects, only folders
- for subentry in e.entries:
- f.write('\t\t%s = %s\r\n' % (subentry.get_guid(), e.get_guid()))
- f.write('\tEndGlobalSection\r\n')
+ # Omit this section if there are no folders
+ if any([e.entries for e in all_entries if isinstance(e, MSVSFolder)]):
+ f.write('\tGlobalSection(NestedProjects) = preSolution\r\n')
+ for e in all_entries:
+ if not isinstance(e, MSVSFolder):
+ continue # Does not apply to projects, only folders
+ for subentry in e.entries:
+ f.write('\t\t%s = %s\r\n' % (subentry.get_guid(), e.get_guid()))
+ f.write('\tEndGlobalSection\r\n')
f.write('EndGlobal\r\n')
f.close()
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/MSVSSettings.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/MSVSSettings.py
@@ -1,13 +1,13 @@
# Copyright (c) 2012 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.
-"""Code to validate and convert settings of the Microsoft build tools.
+r"""Code to validate and convert settings of the Microsoft build tools.
This file contains code to validate and convert settings of the Microsoft
build tools. The function ConvertToMSBuildSettings(), ValidateMSVSSettings(),
and ValidateMSBuildSettings() are the entry points.
This file was created by comparing the projects created by Visual Studio 2008
and Visual Studio 2010 for all available settings through the user interface.
The MSBuild schemas were also considered. They are typically found in the
@@ -309,17 +309,24 @@ def _MSVSOnly(tool, name, setting_type):
def _MSBuildOnly(tool, name, setting_type):
"""Defines a setting that is only found in MSBuild.
Args:
tool: a dictionary that gives the names of the tool for MSVS and MSBuild.
name: the name of the setting.
setting_type: the type of this setting.
"""
+
+ def _Translate(value, msbuild_settings):
+ # Let msbuild-only properties get translated as-is from msvs_settings.
+ tool_settings = msbuild_settings.setdefault(tool.msbuild_name, {})
+ tool_settings[name] = value
+
_msbuild_validators[tool.msbuild_name][name] = setting_type.ValidateMSBuild
+ _msvs_to_msbuild_converters[tool.msvs_name][name] = _Translate
def _ConvertedToAdditionalOption(tool, msvs_name, flag):
"""Defines a setting that's handled via a command line option in MSBuild.
Args:
tool: a dictionary that gives the names of the tool for MSVS and MSBuild.
msvs_name: the name of the MSVS setting that if 'true' becomes a flag
@@ -362,16 +369,45 @@ def _CustomGeneratePreprocessedFile(tool
_msvs_to_msbuild_converters[tool.msvs_name][msvs_name] = _Translate
fix_vc_macro_slashes_regex_list = ('IntDir', 'OutDir')
fix_vc_macro_slashes_regex = re.compile(
r'(\$\((?:%s)\))(?:[\\/]+)' % "|".join(fix_vc_macro_slashes_regex_list)
)
+# Regular expression to detect keys that were generated by exclusion lists
+_EXCLUDED_SUFFIX_RE = re.compile('^(.*)_excluded$')
+
+
+def _ValidateExclusionSetting(setting, settings, error_msg, stderr=sys.stderr):
+ """Verify that 'setting' is valid if it is generated from an exclusion list.
+
+ If the setting appears to be generated from an exclusion list, the root name
+ is checked.
+
+ Args:
+ setting: A string that is the setting name to validate
+ settings: A dictionary where the keys are valid settings
+ error_msg: The message to emit in the event of error
+ stderr: The stream receiving the error messages.
+ """
+ # This may be unrecognized because it's an exclusion list. If the
+ # setting name has the _excluded suffix, then check the root name.
+ unrecognized = True
+ m = re.match(_EXCLUDED_SUFFIX_RE, setting)
+ if m:
+ root_setting = m.group(1)
+ unrecognized = root_setting not in settings
+
+ if unrecognized:
+ # We don't know this setting. Give a warning.
+ print >> stderr, error_msg
+
+
def FixVCMacroSlashes(s):
"""Replace macros which have excessive following slashes.
These macros are known to have a built-in trailing slash. Furthermore, many
scripts hiccup on processing paths with extra slashes in the middle.
This list is probably not exhaustive. Add as needed.
"""
@@ -383,21 +419,21 @@ def FixVCMacroSlashes(s):
def ConvertVCMacrosToMSBuild(s):
"""Convert the the MSVS macros found in the string to the MSBuild equivalent.
This list is probably not exhaustive. Add as needed.
"""
if '$' in s:
replace_map = {
'$(ConfigurationName)': '$(Configuration)',
- '$(InputDir)': '%(RootDir)%(Directory)',
+ '$(InputDir)': '%(RelativeDir)',
'$(InputExt)': '%(Extension)',
'$(InputFileName)': '%(Filename)%(Extension)',
'$(InputName)': '%(Filename)',
- '$(InputPath)': '%(FullPath)',
+ '$(InputPath)': '%(Identity)',
'$(ParentName)': '$(ProjectFileName)',
'$(PlatformName)': '$(Platform)',
'$(SafeInputName)': '%(Filename)',
}
for old, new in replace_map.iteritems():
s = s.replace(old, new)
s = FixVCMacroSlashes(s)
return s
@@ -424,20 +460,22 @@ def ConvertToMSBuildSettings(msvs_settin
if msvs_setting in msvs_tool:
# Invoke the translation function.
try:
msvs_tool[msvs_setting](msvs_value, msbuild_settings)
except ValueError, e:
print >> stderr, ('Warning: while converting %s/%s to MSBuild, '
'%s' % (msvs_tool_name, msvs_setting, e))
else:
- # We don't know this setting. Give a warning.
- print >> stderr, ('Warning: unrecognized setting %s/%s '
- 'while converting to MSBuild.' %
- (msvs_tool_name, msvs_setting))
+ _ValidateExclusionSetting(msvs_setting,
+ msvs_tool,
+ ('Warning: unrecognized setting %s/%s '
+ 'while converting to MSBuild.' %
+ (msvs_tool_name, msvs_setting)),
+ stderr)
else:
print >> stderr, ('Warning: unrecognized tool %s while converting to '
'MSBuild.' % msvs_tool_name)
return msbuild_settings
def ValidateMSVSSettings(settings, stderr=sys.stderr):
"""Validates that the names of the settings are valid for MSVS.
@@ -478,37 +516,43 @@ def _ValidateSettings(validators, settin
for setting, value in settings[tool_name].iteritems():
if setting in tool_validators:
try:
tool_validators[setting](value)
except ValueError, e:
print >> stderr, ('Warning: for %s/%s, %s' %
(tool_name, setting, e))
else:
- print >> stderr, ('Warning: unrecognized setting %s/%s' %
- (tool_name, setting))
+ _ValidateExclusionSetting(setting,
+ tool_validators,
+ ('Warning: unrecognized setting %s/%s' %
+ (tool_name, setting)),
+ stderr)
+
else:
print >> stderr, ('Warning: unrecognized tool %s' % tool_name)
# MSVS and MBuild names of the tools.
_compile = _Tool('VCCLCompilerTool', 'ClCompile')
_link = _Tool('VCLinkerTool', 'Link')
_midl = _Tool('VCMIDLTool', 'Midl')
_rc = _Tool('VCResourceCompilerTool', 'ResourceCompile')
_lib = _Tool('VCLibrarianTool', 'Lib')
_manifest = _Tool('VCManifestTool', 'Manifest')
+_masm = _Tool('MASM', 'MASM')
_AddTool(_compile)
_AddTool(_link)
_AddTool(_midl)
_AddTool(_rc)
_AddTool(_lib)
_AddTool(_manifest)
+_AddTool(_masm)
# Add sections only found in the MSBuild settings.
_msbuild_validators[''] = {}
_msbuild_validators['ProjectReference'] = {}
_msbuild_validators['ManifestResourceCompile'] = {}
# Descriptions of the compiler options, i.e. VCCLCompilerTool in MSVS and
# ClCompile in MSBuild.
# See "c:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\1033\cl.xml" for
@@ -543,16 +587,17 @@ def _ValidateSettings(validators, settin
_Same(_compile, 'StringPooling', _boolean) # /GF
_Same(_compile, 'SuppressStartupBanner', _boolean) # /nologo
_Same(_compile, 'TreatWChar_tAsBuiltInType', _boolean) # /Zc:wchar_t
_Same(_compile, 'UndefineAllPreprocessorDefinitions', _boolean) # /u
_Same(_compile, 'UndefinePreprocessorDefinitions', _string_list) # /U
_Same(_compile, 'UseFullPaths', _boolean) # /FC
_Same(_compile, 'WholeProgramOptimization', _boolean) # /GL
_Same(_compile, 'XMLDocumentationFileName', _file_name)
+_Same(_compile, 'CompileAsWinRT', _boolean) # /ZW
_Same(_compile, 'AssemblerOutput',
_Enumeration(['NoListing',
'AssemblyCode', # /FA
'All', # /FAcs
'AssemblyAndMachineCode', # /FAc
'AssemblyAndSourceCode'])) # /FAs
_Same(_compile, 'BasicRuntimeChecks',
@@ -562,31 +607,37 @@ def _ValidateSettings(validators, settin
'EnableFastChecks'])) # /RTC1
_Same(_compile, 'BrowseInformation',
_Enumeration(['false',
'true', # /FR
'true'])) # /Fr
_Same(_compile, 'CallingConvention',
_Enumeration(['Cdecl', # /Gd
'FastCall', # /Gr
- 'StdCall'])) # /Gz
+ 'StdCall', # /Gz
+ 'VectorCall'])) # /Gv
_Same(_compile, 'CompileAs',
_Enumeration(['Default',
'CompileAsC', # /TC
'CompileAsCpp'])) # /TP
_Same(_compile, 'DebugInformationFormat',
_Enumeration(['', # Disabled
'OldStyle', # /Z7
None,
'ProgramDatabase', # /Zi
'EditAndContinue'])) # /ZI
_Same(_compile, 'EnableEnhancedInstructionSet',
_Enumeration(['NotSet',
'StreamingSIMDExtensions', # /arch:SSE
- 'StreamingSIMDExtensions2'])) # /arch:SSE2
+ 'StreamingSIMDExtensions2', # /arch:SSE2
+ 'AdvancedVectorExtensions', # /arch:AVX (vs2012+)
+ 'NoExtensions', # /arch:IA32 (vs2012+)
+ # This one only exists in the new msbuild format.
+ 'AdvancedVectorExtensions2', # /arch:AVX2 (vs2013r2+)
+ ]))
_Same(_compile, 'ErrorReporting',
_Enumeration(['None', # /errorReport:none
'Prompt', # /errorReport:prompt
'Queue'], # /errorReport:queue
new=['Send'])) # /errorReport:send"
_Same(_compile, 'ExceptionHandling',
_Enumeration(['false',
'Sync', # /EHsc
@@ -653,20 +704,17 @@ def _ValidateSettings(validators, settin
# MSVS options not found in MSBuild.
_MSVSOnly(_compile, 'Detect64BitPortabilityProblems', _boolean)
_MSVSOnly(_compile, 'UseUnicodeResponseFiles', _boolean)
# MSBuild options not found in MSVS.
_MSBuildOnly(_compile, 'BuildingInIDE', _boolean)
_MSBuildOnly(_compile, 'CompileAsManaged',
_Enumeration([], new=['false',
- 'true', # /clr
- 'Pure', # /clr:pure
- 'Safe', # /clr:safe
- 'OldSyntax'])) # /clr:oldSyntax
+ 'true'])) # /clr
_MSBuildOnly(_compile, 'CreateHotpatchableImage', _boolean) # /hotpatch
_MSBuildOnly(_compile, 'MultiProcessorCompilation', _boolean) # /MP
_MSBuildOnly(_compile, 'PreprocessOutputPath', _string) # /Fi
_MSBuildOnly(_compile, 'ProcessorNumber', _integer) # the number of processors
_MSBuildOnly(_compile, 'TrackerLogDirectory', _folder_name)
_MSBuildOnly(_compile, 'TreatSpecificWarningsAsErrors', _string_list) # /we
_MSBuildOnly(_compile, 'UseUnicodeForAssemblerListing', _boolean) # /FAu
@@ -807,16 +855,18 @@ def _ValidateSettings(validators, settin
'LinkVerboseSAFESEH', # /VERBOSE:SAFESEH
'LinkVerboseCLR'])) # /VERBOSE:CLR
_Same(_link, 'SubSystem', _subsystem_enumeration)
_Same(_link, 'TargetMachine', _target_machine_enumeration)
_Same(_link, 'UACExecutionLevel',
_Enumeration(['AsInvoker', # /level='asInvoker'
'HighestAvailable', # /level='highestAvailable'
'RequireAdministrator'])) # /level='requireAdministrator'
+_Same(_link, 'MinimumRequiredVersion', _string)
+_Same(_link, 'TreatLinkerWarningAsErrors', _boolean) # /WX
# Options found in MSVS that have been renamed in MSBuild.
_Renamed(_link, 'ErrorReporting', 'LinkErrorReporting',
_Enumeration(['NoErrorReport', # /ERRORREPORT:NONE
'PromptImmediately', # /ERRORREPORT:PROMPT
'QueueForNextLogin'], # /ERRORREPORT:QUEUE
new=['SendErrorReport'])) # /ERRORREPORT:SEND
@@ -829,29 +879,25 @@ def _ValidateSettings(validators, settin
_Moved(_link, 'IgnoreImportLibrary', '', _boolean)
_Moved(_link, 'LinkIncremental', '', _newly_boolean)
_Moved(_link, 'LinkLibraryDependencies', 'ProjectReference', _boolean)
_Moved(_link, 'UseLibraryDependencyInputs', 'ProjectReference', _boolean)
# MSVS options not found in MSBuild.
_MSVSOnly(_link, 'OptimizeForWindows98', _newly_boolean)
_MSVSOnly(_link, 'UseUnicodeResponseFiles', _boolean)
-# TODO(jeanluc) I don't think these are genuine settings but byproducts of Gyp.
-_MSVSOnly(_link, 'AdditionalLibraryDirectories_excluded', _folder_list)
# MSBuild options not found in MSVS.
_MSBuildOnly(_link, 'BuildingInIDE', _boolean)
_MSBuildOnly(_link, 'ImageHasSafeExceptionHandlers', _boolean) # /SAFESEH
_MSBuildOnly(_link, 'LinkDLL', _boolean) # /DLL Visible='false'
_MSBuildOnly(_link, 'LinkStatus', _boolean) # /LTCG:STATUS
_MSBuildOnly(_link, 'PreventDllBinding', _boolean) # /ALLOWBIND
_MSBuildOnly(_link, 'SupportNobindOfDelayLoadedDLL', _boolean) # /DELAY:NOBIND
_MSBuildOnly(_link, 'TrackerLogDirectory', _folder_name)
-_MSBuildOnly(_link, 'TreatLinkerWarningAsErrors', _boolean) # /WX
-_MSBuildOnly(_link, 'MinimumRequiredVersion', _string)
_MSBuildOnly(_link, 'MSDOSStubFileName', _file_name) # /STUB Visible='false'
_MSBuildOnly(_link, 'SectionAlignment', _integer) # /ALIGN
_MSBuildOnly(_link, 'SpecifySectionAttributes', _string) # /SECTION
_MSBuildOnly(_link, 'ForceFileOutput',
_Enumeration([], new=['Enabled', # /FORCE
# /FORCE:MULTIPLE
'MultiplyDefinedSymbolOnly',
'UndefinedSymbolOnly'])) # /FORCE:UNRESOLVED
@@ -975,35 +1021,32 @@ def _ValidateSettings(validators, settin
_Same(_lib, 'ForceSymbolReferences', _string) # /INCLUDE
_Same(_lib, 'IgnoreAllDefaultLibraries', _boolean) # /NODEFAULTLIB
_Same(_lib, 'IgnoreSpecificDefaultLibraries', _file_list) # /NODEFAULTLIB
_Same(_lib, 'ModuleDefinitionFile', _file_name) # /DEF
_Same(_lib, 'OutputFile', _file_name) # /OUT
_Same(_lib, 'SuppressStartupBanner', _boolean) # /NOLOGO
_Same(_lib, 'UseUnicodeResponseFiles', _boolean)
_Same(_lib, 'LinkTimeCodeGeneration', _boolean) # /LTCG
+_Same(_lib, 'TargetMachine', _target_machine_enumeration)
# TODO(jeanluc) _link defines the same value that gets moved to
# ProjectReference. We may want to validate that they are consistent.
_Moved(_lib, 'LinkLibraryDependencies', 'ProjectReference', _boolean)
-# TODO(jeanluc) I don't think these are genuine settings but byproducts of Gyp.
-_MSVSOnly(_lib, 'AdditionalLibraryDirectories_excluded', _folder_list)
-
_MSBuildOnly(_lib, 'DisplayLibrary', _string) # /LIST Visible='false'
_MSBuildOnly(_lib, 'ErrorReporting',
_Enumeration([], new=['PromptImmediately', # /ERRORREPORT:PROMPT
'QueueForNextLogin', # /ERRORREPORT:QUEUE
'SendErrorReport', # /ERRORREPORT:SEND
'NoErrorReport'])) # /ERRORREPORT:NONE
_MSBuildOnly(_lib, 'MinimumRequiredVersion', _string)
_MSBuildOnly(_lib, 'Name', _file_name) # /NAME
_MSBuildOnly(_lib, 'RemoveObjects', _file_list) # /REMOVE
_MSBuildOnly(_lib, 'SubSystem', _subsystem_enumeration)
-_MSBuildOnly(_lib, 'TargetMachine', _target_machine_enumeration)
_MSBuildOnly(_lib, 'TrackerLogDirectory', _folder_name)
_MSBuildOnly(_lib, 'TreatLibWarningAsErrors', _boolean) # /WX
_MSBuildOnly(_lib, 'Verbose', _boolean)
# Directives for converting VCManifestTool to Mt.
# See "c:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\1033\mt.xml" for
# the schema of the MSBuild Lib settings.
@@ -1039,8 +1082,16 @@ def _ValidateSettings(validators, settin
# MSBuild options not found in MSVS.
_MSBuildOnly(_manifest, 'EnableDPIAwareness', _boolean)
_MSBuildOnly(_manifest, 'GenerateCategoryTags', _boolean) # /category
_MSBuildOnly(_manifest, 'ManifestFromManagedAssembly',
_file_name) # /managedassemblyname
_MSBuildOnly(_manifest, 'OutputResourceManifests', _string) # /outputresource
_MSBuildOnly(_manifest, 'SuppressDependencyElement', _boolean) # /nodependency
_MSBuildOnly(_manifest, 'TrackerLogDirectory', _folder_name)
+
+
+# Directives for MASM.
+# See "$(VCTargetsPath)\BuildCustomizations\masm.xml" for the schema of the
+# MSBuild MASM settings.
+
+# Options that have the same name in MSVS and MSBuild.
+_Same(_masm, 'UseSafeExceptionHandlers', _boolean) # /safeseh
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/MSVSSettings_test.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/MSVSSettings_test.py
@@ -104,16 +104,17 @@ class TestSequenceFunctions(unittest.Tes
'UseUnicodeResponseFiles': 'true',
'WarnAsError': 'true',
'WarningLevel': '1',
'WholeProgramOptimization': 'true',
'XMLDocumentationFileName': 'a_file_name',
'ZZXYZ': 'bogus'},
'VCLinkerTool': {
'AdditionalDependencies': 'file1;file2',
+ 'AdditionalDependencies_excluded': 'file3',
'AdditionalLibraryDirectories': 'folder1;folder2',
'AdditionalManifestDependencies': 'file1;file2',
'AdditionalOptions': 'a string1',
'AddModuleNamesToAssembly': 'file1;file2',
'AllowIsolation': 'true',
'AssemblyDebug': '2',
'AssemblyLinkResource': 'file1;file2',
'BaseAddress': 'a string1',
@@ -261,17 +262,17 @@ class TestSequenceFunctions(unittest.Tes
'VerboseOutput': 'true'}},
self.stderr)
self._ExpectedWarnings([
'Warning: for VCCLCompilerTool/BasicRuntimeChecks, '
'index value (5) not in expected range [0, 4)',
'Warning: for VCCLCompilerTool/BrowseInformation, '
"invalid literal for int() with base 10: 'fdkslj'",
'Warning: for VCCLCompilerTool/CallingConvention, '
- 'index value (-1) not in expected range [0, 3)',
+ 'index value (-1) not in expected range [0, 4)',
'Warning: for VCCLCompilerTool/DebugInformationFormat, '
'converted value for 2 not specified.',
'Warning: unrecognized setting VCCLCompilerTool/Enableprefast',
'Warning: unrecognized setting VCCLCompilerTool/ZZXYZ',
'Warning: for VCLinkerTool/TargetMachine, '
'converted value for 2 not specified.',
'Warning: unrecognized setting VCMIDLTool/notgood',
'Warning: unrecognized setting VCResourceCompilerTool/notgood2',
@@ -290,17 +291,17 @@ class TestSequenceFunctions(unittest.Tes
'AssemblerOutput': 'NoListing',
'BasicRuntimeChecks': 'StackFrameRuntimeCheck',
'BrowseInformation': 'false',
'BrowseInformationFile': 'a_file_name',
'BufferSecurityCheck': 'true',
'BuildingInIDE': 'true',
'CallingConvention': 'Cdecl',
'CompileAs': 'CompileAsC',
- 'CompileAsManaged': 'Pure',
+ 'CompileAsManaged': 'true',
'CreateHotpatchableImage': 'true',
'DebugInformationFormat': 'ProgramDatabase',
'DisableLanguageExtensions': 'true',
'DisableSpecificWarnings': 'string1;string2',
'EnableEnhancedInstructionSet': 'StreamingSIMDExtensions',
'EnableFiberSafeOptimizations': 'true',
'EnablePREfast': 'true',
'Enableprefast': 'bogus',
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/MSVSUtil.py
@@ -0,0 +1,271 @@
+# Copyright (c) 2013 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.
+
+"""Utility functions shared amongst the Windows generators."""
+
+import copy
+import os
+
+
+# A dictionary mapping supported target types to extensions.
+TARGET_TYPE_EXT = {
+ 'executable': 'exe',
+ 'loadable_module': 'dll',
+ 'shared_library': 'dll',
+ 'static_library': 'lib',
+ 'windows_driver': 'sys',
+}
+
+
+def _GetLargePdbShimCcPath():
+ """Returns the path of the large_pdb_shim.cc file."""
+ this_dir = os.path.abspath(os.path.dirname(__file__))
+ src_dir = os.path.abspath(os.path.join(this_dir, '..', '..'))
+ win_data_dir = os.path.join(src_dir, 'data', 'win')
+ large_pdb_shim_cc = os.path.join(win_data_dir, 'large-pdb-shim.cc')
+ return large_pdb_shim_cc
+
+
+def _DeepCopySomeKeys(in_dict, keys):
+ """Performs a partial deep-copy on |in_dict|, only copying the keys in |keys|.
+
+ Arguments:
+ in_dict: The dictionary to copy.
+ keys: The keys to be copied. If a key is in this list and doesn't exist in
+ |in_dict| this is not an error.
+ Returns:
+ The partially deep-copied dictionary.
+ """
+ d = {}
+ for key in keys:
+ if key not in in_dict:
+ continue
+ d[key] = copy.deepcopy(in_dict[key])
+ return d
+
+
+def _SuffixName(name, suffix):
+ """Add a suffix to the end of a target.
+
+ Arguments:
+ name: name of the target (foo#target)
+ suffix: the suffix to be added
+ Returns:
+ Target name with suffix added (foo_suffix#target)
+ """
+ parts = name.rsplit('#', 1)
+ parts[0] = '%s_%s' % (parts[0], suffix)
+ return '#'.join(parts)
+
+
+def _ShardName(name, number):
+ """Add a shard number to the end of a target.
+
+ Arguments:
+ name: name of the target (foo#target)
+ number: shard number
+ Returns:
+ Target name with shard added (foo_1#target)
+ """
+ return _SuffixName(name, str(number))
+
+
+def ShardTargets(target_list, target_dicts):
+ """Shard some targets apart to work around the linkers limits.
+
+ Arguments:
+ target_list: List of target pairs: 'base/base.gyp:base'.
+ target_dicts: Dict of target properties keyed on target pair.
+ Returns:
+ Tuple of the new sharded versions of the inputs.
+ """
+ # Gather the targets to shard, and how many pieces.
+ targets_to_shard = {}
+ for t in target_dicts:
+ shards = int(target_dicts[t].get('msvs_shard', 0))
+ if shards:
+ targets_to_shard[t] = shards
+ # Shard target_list.
+ new_target_list = []
+ for t in target_list:
+ if t in targets_to_shard:
+ for i in range(targets_to_shard[t]):
+ new_target_list.append(_ShardName(t, i))
+ else:
+ new_target_list.append(t)
+ # Shard target_dict.
+ new_target_dicts = {}
+ for t in target_dicts:
+ if t in targets_to_shard:
+ for i in range(targets_to_shard[t]):
+ name = _ShardName(t, i)
+ new_target_dicts[name] = copy.copy(target_dicts[t])
+ new_target_dicts[name]['target_name'] = _ShardName(
+ new_target_dicts[name]['target_name'], i)
+ sources = new_target_dicts[name].get('sources', [])
+ new_sources = []
+ for pos in range(i, len(sources), targets_to_shard[t]):
+ new_sources.append(sources[pos])
+ new_target_dicts[name]['sources'] = new_sources
+ else:
+ new_target_dicts[t] = target_dicts[t]
+ # Shard dependencies.
+ for t in sorted(new_target_dicts):
+ for deptype in ('dependencies', 'dependencies_original'):
+ dependencies = copy.copy(new_target_dicts[t].get(deptype, []))
+ new_dependencies = []
+ for d in dependencies:
+ if d in targets_to_shard:
+ for i in range(targets_to_shard[d]):
+ new_dependencies.append(_ShardName(d, i))
+ else:
+ new_dependencies.append(d)
+ new_target_dicts[t][deptype] = new_dependencies
+
+ return (new_target_list, new_target_dicts)
+
+
+def _GetPdbPath(target_dict, config_name, vars):
+ """Returns the path to the PDB file that will be generated by a given
+ configuration.
+
+ The lookup proceeds as follows:
+ - Look for an explicit path in the VCLinkerTool configuration block.
+ - Look for an 'msvs_large_pdb_path' variable.
+ - Use '<(PRODUCT_DIR)/<(product_name).(exe|dll).pdb' if 'product_name' is
+ specified.
+ - Use '<(PRODUCT_DIR)/<(target_name).(exe|dll).pdb'.
+
+ Arguments:
+ target_dict: The target dictionary to be searched.
+ config_name: The name of the configuration of interest.
+ vars: A dictionary of common GYP variables with generator-specific values.
+ Returns:
+ The path of the corresponding PDB file.
+ """
+ config = target_dict['configurations'][config_name]
+ msvs = config.setdefault('msvs_settings', {})
+
+ linker = msvs.get('VCLinkerTool', {})
+
+ pdb_path = linker.get('ProgramDatabaseFile')
+ if pdb_path:
+ return pdb_path
+
+ variables = target_dict.get('variables', {})
+ pdb_path = variables.get('msvs_large_pdb_path', None)
+ if pdb_path:
+ return pdb_path
+
+
+ pdb_base = target_dict.get('product_name', target_dict['target_name'])
+ pdb_base = '%s.%s.pdb' % (pdb_base, TARGET_TYPE_EXT[target_dict['type']])
+ pdb_path = vars['PRODUCT_DIR'] + '/' + pdb_base
+
+ return pdb_path
+
+
+def InsertLargePdbShims(target_list, target_dicts, vars):
+ """Insert a shim target that forces the linker to use 4KB pagesize PDBs.
+
+ This is a workaround for targets with PDBs greater than 1GB in size, the
+ limit for the 1KB pagesize PDBs created by the linker by default.
+
+ Arguments:
+ target_list: List of target pairs: 'base/base.gyp:base'.
+ target_dicts: Dict of target properties keyed on target pair.
+ vars: A dictionary of common GYP variables with generator-specific values.
+ Returns:
+ Tuple of the shimmed version of the inputs.
+ """
+ # Determine which targets need shimming.
+ targets_to_shim = []
+ for t in target_dicts:
+ target_dict = target_dicts[t]
+
+ # We only want to shim targets that have msvs_large_pdb enabled.
+ if not int(target_dict.get('msvs_large_pdb', 0)):
+ continue
+ # This is intended for executable, shared_library and loadable_module
+ # targets where every configuration is set up to produce a PDB output.
+ # If any of these conditions is not true then the shim logic will fail
+ # below.
+ targets_to_shim.append(t)
+
+ large_pdb_shim_cc = _GetLargePdbShimCcPath()
+
+ for t in targets_to_shim:
+ target_dict = target_dicts[t]
+ target_name = target_dict.get('target_name')
+
+ base_dict = _DeepCopySomeKeys(target_dict,
+ ['configurations', 'default_configuration', 'toolset'])
+
+ # This is the dict for copying the source file (part of the GYP tree)
+ # to the intermediate directory of the project. This is necessary because
+ # we can't always build a relative path to the shim source file (on Windows
+ # GYP and the project may be on different drives), and Ninja hates absolute
+ # paths (it ends up generating the .obj and .obj.d alongside the source
+ # file, polluting GYPs tree).
+ copy_suffix = 'large_pdb_copy'
+ copy_target_name = target_name + '_' + copy_suffix
+ full_copy_target_name = _SuffixName(t, copy_suffix)
+ shim_cc_basename = os.path.basename(large_pdb_shim_cc)
+ shim_cc_dir = vars['SHARED_INTERMEDIATE_DIR'] + '/' + copy_target_name
+ shim_cc_path = shim_cc_dir + '/' + shim_cc_basename
+ copy_dict = copy.deepcopy(base_dict)
+ copy_dict['target_name'] = copy_target_name
+ copy_dict['type'] = 'none'
+ copy_dict['sources'] = [ large_pdb_shim_cc ]
+ copy_dict['copies'] = [{
+ 'destination': shim_cc_dir,
+ 'files': [ large_pdb_shim_cc ]
+ }]
+
+ # This is the dict for the PDB generating shim target. It depends on the
+ # copy target.
+ shim_suffix = 'large_pdb_shim'
+ shim_target_name = target_name + '_' + shim_suffix
+ full_shim_target_name = _SuffixName(t, shim_suffix)
+ shim_dict = copy.deepcopy(base_dict)
+ shim_dict['target_name'] = shim_target_name
+ shim_dict['type'] = 'static_library'
+ shim_dict['sources'] = [ shim_cc_path ]
+ shim_dict['dependencies'] = [ full_copy_target_name ]
+
+ # Set up the shim to output its PDB to the same location as the final linker
+ # target.
+ for config_name, config in shim_dict.get('configurations').iteritems():
+ pdb_path = _GetPdbPath(target_dict, config_name, vars)
+
+ # A few keys that we don't want to propagate.
+ for key in ['msvs_precompiled_header', 'msvs_precompiled_source', 'test']:
+ config.pop(key, None)
+
+ msvs = config.setdefault('msvs_settings', {})
+
+ # Update the compiler directives in the shim target.
+ compiler = msvs.setdefault('VCCLCompilerTool', {})
+ compiler['DebugInformationFormat'] = '3'
+ compiler['ProgramDataBaseFileName'] = pdb_path
+
+ # Set the explicit PDB path in the appropriate configuration of the
+ # original target.
+ config = target_dict['configurations'][config_name]
+ msvs = config.setdefault('msvs_settings', {})
+ linker = msvs.setdefault('VCLinkerTool', {})
+ linker['GenerateDebugInformation'] = 'true'
+ linker['ProgramDatabaseFile'] = pdb_path
+
+ # Add the new targets. They must go to the beginning of the list so that
+ # the dependency generation works as expected in ninja.
+ target_list.insert(0, full_copy_target_name)
+ target_list.insert(0, full_shim_target_name)
+ target_dicts[full_copy_target_name] = copy_dict
+ target_dicts[full_shim_target_name] = shim_dict
+
+ # Update the original target to depend on the shim target.
+ target_dict.setdefault('dependencies', []).append(full_shim_target_name)
+
+ return (target_list, target_dicts)
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/MSVSVersion.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/MSVSVersion.py
@@ -1,20 +1,21 @@
-# Copyright (c) 2012 Google Inc. All rights reserved.
+# Copyright (c) 2013 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.
"""Handle version information related to Visual Stuio."""
import errno
import os
import re
import subprocess
import sys
import gyp
+import glob
class VisualStudioVersion(object):
"""Information regarding a version of Visual Studio."""
def __init__(self, short_name, description,
solution_version, project_version, flat_sln, uses_vcxproj,
path, sdk_based, default_toolset=None):
@@ -62,44 +63,64 @@ class VisualStudioVersion(object):
"""Returns the path to a given compiler tool. """
return os.path.normpath(os.path.join(self.path, "VC/bin", tool))
def DefaultToolset(self):
"""Returns the msbuild toolset version that will be used in the absence
of a user override."""
return self.default_toolset
- def SetupScript(self, target_arch):
+ def _SetupScriptInternal(self, target_arch):
"""Returns a command (with arguments) to be used to set up the
environment."""
- # Check if we are running in the SDK command line environment and use
- # the setup script from the SDK if so. |target_arch| should be either
- # 'x86' or 'x64'.
+ # If WindowsSDKDir is set and SetEnv.Cmd exists then we are using the
+ # depot_tools build tools and should run SetEnv.Cmd to set up the
+ # environment. The check for WindowsSDKDir alone is not sufficient because
+ # this is set by running vcvarsall.bat.
assert target_arch in ('x86', 'x64')
sdk_dir = os.environ.get('WindowsSDKDir')
- if self.sdk_based and sdk_dir:
- return [os.path.normpath(os.path.join(sdk_dir, 'Bin/SetEnv.Cmd')),
- '/' + target_arch]
+ if sdk_dir:
+ setup_path = os.path.normpath(os.path.join(sdk_dir, 'Bin/SetEnv.Cmd'))
+ if self.sdk_based and sdk_dir and os.path.exists(setup_path):
+ return [setup_path, '/' + target_arch]
else:
# We don't use VC/vcvarsall.bat for x86 because vcvarsall calls
# vcvars32, which it can only find if VS??COMNTOOLS is set, which it
# isn't always.
if target_arch == 'x86':
+ if self.short_name >= '2013' and self.short_name[-1] != 'e' and (
+ os.environ.get('PROCESSOR_ARCHITECTURE') == 'AMD64' or
+ os.environ.get('PROCESSOR_ARCHITEW6432') == 'AMD64'):
+ # VS2013 and later, non-Express have a x64-x86 cross that we want
+ # to prefer.
+ return [os.path.normpath(
+ os.path.join(self.path, 'VC/vcvarsall.bat')), 'amd64_x86']
+ # Otherwise, the standard x86 compiler.
return [os.path.normpath(
os.path.join(self.path, 'Common7/Tools/vsvars32.bat'))]
else:
assert target_arch == 'x64'
arg = 'x86_amd64'
- if (os.environ.get('PROCESSOR_ARCHITECTURE') == 'AMD64' or
+ # Use the 64-on-64 compiler if we're not using an express
+ # edition and we're running on a 64bit OS.
+ if self.short_name[-1] != 'e' and (
+ os.environ.get('PROCESSOR_ARCHITECTURE') == 'AMD64' or
os.environ.get('PROCESSOR_ARCHITEW6432') == 'AMD64'):
- # Use the 64-on-64 compiler if we can.
arg = 'amd64'
return [os.path.normpath(
os.path.join(self.path, 'VC/vcvarsall.bat')), arg]
+ def SetupScript(self, target_arch):
+ script_data = self._SetupScriptInternal(target_arch)
+ script_path = script_data[0]
+ if not os.path.exists(script_path):
+ raise Exception('%s is missing - make sure VC++ tools are installed.' %
+ script_path)
+ return script_data
+
def _RegistryQueryBase(sysdir, key, value):
"""Use reg.exe to read a particular key.
While ideally we might use the win32 module, we would like gyp to be
python neutral, so for instance cygwin python lacks this module.
Arguments:
@@ -123,17 +144,17 @@ def _RegistryQueryBase(sysdir, key, valu
text = p.communicate()[0]
# Check return code from reg.exe; officially 0==success and 1==error
if p.returncode:
return None
return text
def _RegistryQuery(key, value=None):
- """Use reg.exe to read a particular key through _RegistryQueryBase.
+ r"""Use reg.exe to read a particular key through _RegistryQueryBase.
First tries to launch from %WinDir%\Sysnative to avoid WoW64 redirection. If
that fails, it falls back to System32. Sysnative is available on Vista and
up and available on Windows Server 2003 and XP through KB patch 942589. Note
that Sysnative will always fail if using 64-bit python due to it being a
virtual directory and System32 will work correctly in the first place.
KB 942589 - http://support.microsoft.com/kb/942589/en-us.
@@ -150,58 +171,103 @@ def _RegistryQuery(key, value=None):
except OSError, e:
if e.errno == errno.ENOENT:
text = _RegistryQueryBase('System32', key, value)
else:
raise
return text
+def _RegistryGetValueUsingWinReg(key, value):
+ """Use the _winreg module to obtain the value of a registry key.
+
+ Args:
+ key: The registry key.
+ value: The particular registry value to read.
+ Return:
+ contents of the registry key's value, or None on failure. Throws
+ ImportError if _winreg is unavailable.
+ """
+ import _winreg
+ try:
+ root, subkey = key.split('\\', 1)
+ assert root == 'HKLM' # Only need HKLM for now.
+ with _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, subkey) as hkey:
+ return _winreg.QueryValueEx(hkey, value)[0]
+ except WindowsError:
+ return None
+
+
def _RegistryGetValue(key, value):
- """Use reg.exe to obtain the value of a registry key.
+ """Use _winreg or reg.exe to obtain the value of a registry key.
+
+ Using _winreg is preferable because it solves an issue on some corporate
+ environments where access to reg.exe is locked down. However, we still need
+ to fallback to reg.exe for the case where the _winreg module is not available
+ (for example in cygwin python).
Args:
key: The registry key.
value: The particular registry value to read.
Return:
contents of the registry key's value, or None on failure.
"""
+ try:
+ return _RegistryGetValueUsingWinReg(key, value)
+ except ImportError:
+ pass
+
+ # Fallback to reg.exe if we fail to import _winreg.
text = _RegistryQuery(key, value)
if not text:
return None
# Extract value.
match = re.search(r'REG_\w+\s+([^\r]+)\r\n', text)
if not match:
return None
return match.group(1)
-def _RegistryKeyExists(key):
- """Use reg.exe to see if a key exists.
-
- Args:
- key: The registry key to check.
- Return:
- True if the key exists
- """
- if not _RegistryQuery(key):
- return False
- return True
-
-
def _CreateVersion(name, path, sdk_based=False):
"""Sets up MSVS project generation.
Setup is based off the GYP_MSVS_VERSION environment variable or whatever is
autodetected if GYP_MSVS_VERSION is not explicitly specified. If a version is
passed in that doesn't match a value in versions python will throw a error.
"""
if path:
path = os.path.normpath(path)
versions = {
+ '2015': VisualStudioVersion('2015',
+ 'Visual Studio 2015',
+ solution_version='12.00',
+ project_version='14.0',
+ flat_sln=False,
+ uses_vcxproj=True,
+ path=path,
+ sdk_based=sdk_based,
+ default_toolset='v140'),
+ '2013': VisualStudioVersion('2013',
+ 'Visual Studio 2013',
+ solution_version='13.00',
+ project_version='12.0',
+ flat_sln=False,
+ uses_vcxproj=True,
+ path=path,
+ sdk_based=sdk_based,
+ default_toolset='v120'),
+ '2013e': VisualStudioVersion('2013e',
+ 'Visual Studio 2013',
+ solution_version='13.00',
+ project_version='12.0',
+ flat_sln=True,
+ uses_vcxproj=True,
+ path=path,
+ sdk_based=sdk_based,
+ default_toolset='v120'),
'2012': VisualStudioVersion('2012',
'Visual Studio 2012',
solution_version='12.00',
project_version='4.0',
flat_sln=False,
uses_vcxproj=True,
path=path,
sdk_based=sdk_based,
@@ -219,17 +285,17 @@ def _CreateVersion(name, path, sdk_based
'Visual Studio 2010',
solution_version='11.00',
project_version='4.0',
flat_sln=False,
uses_vcxproj=True,
path=path,
sdk_based=sdk_based),
'2010e': VisualStudioVersion('2010e',
- 'Visual Studio 2010',
+ 'Visual C++ Express 2010',
solution_version='11.00',
project_version='4.0',
flat_sln=True,
uses_vcxproj=True,
path=path,
sdk_based=sdk_based),
'2008': VisualStudioVersion('2008',
'Visual Studio 2008',
@@ -283,84 +349,105 @@ def _DetectVisualStudioVersions(versions
usage preference.
Base this on the registry and a quick check if devenv.exe exists.
Only versions 8-10 are considered.
Possibilities are:
2005(e) - Visual Studio 2005 (8)
2008(e) - Visual Studio 2008 (9)
2010(e) - Visual Studio 2010 (10)
2012(e) - Visual Studio 2012 (11)
+ 2013(e) - Visual Studio 2013 (12)
+ 2015 - Visual Studio 2015 (14)
Where (e) is e for express editions of MSVS and blank otherwise.
"""
version_to_year = {
- '8.0': '2005', '9.0': '2008', '10.0': '2010', '11.0': '2012'}
+ '8.0': '2005',
+ '9.0': '2008',
+ '10.0': '2010',
+ '11.0': '2012',
+ '12.0': '2013',
+ '14.0': '2015',
+ }
versions = []
for version in versions_to_check:
# Old method of searching for which VS version is installed
# We don't use the 2010-encouraged-way because we also want to get the
# path to the binaries, which it doesn't offer.
keys = [r'HKLM\Software\Microsoft\VisualStudio\%s' % version,
r'HKLM\Software\Wow6432Node\Microsoft\VisualStudio\%s' % version,
r'HKLM\Software\Microsoft\VCExpress\%s' % version,
r'HKLM\Software\Wow6432Node\Microsoft\VCExpress\%s' % version]
for index in range(len(keys)):
path = _RegistryGetValue(keys[index], 'InstallDir')
if not path:
continue
path = _ConvertToCygpath(path)
# Check for full.
full_path = os.path.join(path, 'devenv.exe')
- express_path = os.path.join(path, 'vcexpress.exe')
+ express_path = os.path.join(path, '*express.exe')
if not force_express and os.path.exists(full_path):
# Add this one.
versions.append(_CreateVersion(version_to_year[version],
os.path.join(path, '..', '..')))
# Check for express.
- elif os.path.exists(express_path):
+ elif glob.glob(express_path):
# Add this one.
versions.append(_CreateVersion(version_to_year[version] + 'e',
os.path.join(path, '..', '..')))
# The old method above does not work when only SDK is installed.
keys = [r'HKLM\Software\Microsoft\VisualStudio\SxS\VC7',
r'HKLM\Software\Wow6432Node\Microsoft\VisualStudio\SxS\VC7']
for index in range(len(keys)):
path = _RegistryGetValue(keys[index], version)
if not path:
continue
path = _ConvertToCygpath(path)
- versions.append(_CreateVersion(version_to_year[version] + 'e',
- os.path.join(path, '..'), sdk_based=True))
+ if version != '14.0': # There is no Express edition for 2015.
+ versions.append(_CreateVersion(version_to_year[version] + 'e',
+ os.path.join(path, '..'), sdk_based=True))
return versions
-def SelectVisualStudioVersion(version='auto'):
+def SelectVisualStudioVersion(version='auto', allow_fallback=True):
"""Select which version of Visual Studio projects to generate.
Arguments:
version: Hook to allow caller to force a particular version (vs auto).
Returns:
An object representing a visual studio project format version.
"""
# In auto mode, check environment variable for override.
if version == 'auto':
version = os.environ.get('GYP_MSVS_VERSION', 'auto')
version_map = {
- 'auto': ('10.0', '9.0', '8.0', '11.0'),
+ 'auto': ('14.0', '12.0', '10.0', '9.0', '8.0', '11.0'),
'2005': ('8.0',),
'2005e': ('8.0',),
'2008': ('9.0',),
'2008e': ('9.0',),
'2010': ('10.0',),
'2010e': ('10.0',),
'2012': ('11.0',),
'2012e': ('11.0',),
+ '2013': ('12.0',),
+ '2013e': ('12.0',),
+ '2015': ('14.0',),
}
+ override_path = os.environ.get('GYP_MSVS_OVERRIDE_PATH')
+ if override_path:
+ msvs_version = os.environ.get('GYP_MSVS_VERSION')
+ if not msvs_version:
+ raise ValueError('GYP_MSVS_OVERRIDE_PATH requires GYP_MSVS_VERSION to be '
+ 'set to a particular version (e.g. 2010e).')
+ return _CreateVersion(msvs_version, override_path, sdk_based=True)
version = str(version)
versions = _DetectVisualStudioVersions(version_map[version], 'e' in version)
if not versions:
+ if not allow_fallback:
+ raise ValueError('Could not locate Visual Studio installation.')
if version == 'auto':
# Default to 2005 if we couldn't find anything
return _CreateVersion('2005', None)
else:
return _CreateVersion(version, None)
return versions[0]
deleted file mode 100644
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/SCons.py
+++ /dev/null
@@ -1,199 +0,0 @@
-# Copyright (c) 2012 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.
-
-"""
-SCons generator.
-
-This contains class definitions and supporting functions for generating
-pieces of SCons files for the different types of GYP targets.
-"""
-
-import os
-
-
-def WriteList(fp, list, prefix='',
- separator=',\n ',
- preamble=None,
- postamble=None):
- fp.write(preamble or '')
- fp.write((separator or ' ').join([prefix + l for l in list]))
- fp.write(postamble or '')
-
-
-class TargetBase(object):
- """
- Base class for a SCons representation of a GYP target.
- """
- is_ignored = False
- target_prefix = ''
- target_suffix = ''
- def __init__(self, spec):
- self.spec = spec
- def full_product_name(self):
- """
- Returns the full name of the product being built:
-
- * Uses 'product_name' if it's set, else prefix + 'target_name'.
- * Prepends 'product_dir' if set.
- * Appends SCons suffix variables for the target type (or
- product_extension).
- """
- suffix = self.target_suffix
- product_extension = self.spec.get('product_extension')
- if product_extension:
- suffix = '.' + product_extension
- prefix = self.spec.get('product_prefix', self.target_prefix)
- name = self.spec['target_name']
- name = prefix + self.spec.get('product_name', name) + suffix
- product_dir = self.spec.get('product_dir')
- if product_dir:
- name = os.path.join(product_dir, name)
- else:
- name = os.path.join(self.out_dir, name)
- return name
-
- def write_input_files(self, fp):
- """
- Writes the definition of the input files (sources).
- """
- sources = self.spec.get('sources')
- if not sources:
- fp.write('\ninput_files = []\n')
- return
- preamble = '\ninput_files = [\n '
- postamble = ',\n]\n'
- WriteList(fp, map(repr, sources), preamble=preamble, postamble=postamble)
-
- def builder_call(self):
- """
- Returns the actual SCons builder call to build this target.
- """
- name = self.full_product_name()
- return 'env.%s(env.File(%r), input_files)' % (self.builder_name, name)
- def write_target(self, fp, src_dir='', pre=''):
- """
- Writes the lines necessary to build this target.
- """
- fp.write('\n' + pre)
- fp.write('_outputs = %s\n' % self.builder_call())
- fp.write('target_files.extend(_outputs)\n')
-
-
-class NoneTarget(TargetBase):
- """
- A GYP target type of 'none', implicitly or explicitly.
- """
- def write_target(self, fp, src_dir='', pre=''):
- fp.write('\ntarget_files.extend(input_files)\n')
-
-
-class SettingsTarget(TargetBase):
- """
- A GYP target type of 'settings'.
- """
- is_ignored = True
-
-
-compilable_sources_template = """
-_result = []
-for infile in input_files:
- if env.compilable(infile):
- if (type(infile) == type('')
- and (infile.startswith(%(src_dir)r)
- or not os.path.isabs(env.subst(infile)))):
- # Force files below the build directory by replacing all '..'
- # elements in the path with '__':
- base, ext = os.path.splitext(os.path.normpath(infile))
- base = [d == '..' and '__' or d for d in base.split('/')]
- base = os.path.join(*base)
- object = '${OBJ_DIR}/${COMPONENT_NAME}/${TARGET_NAME}/' + base
- if not infile.startswith(%(src_dir)r):
- infile = %(src_dir)r + infile
- infile = env.%(name)s(object, infile)[0]
- else:
- infile = env.%(name)s(infile)[0]
- _result.append(infile)
-input_files = _result
-"""
-
-class CompilableSourcesTargetBase(TargetBase):
- """
- An abstract base class for targets that compile their source files.
-
- We explicitly transform compilable files into object files,
- even though SCons could infer that for us, because we want
- to control where the object file ends up. (The implicit rules
- in SCons always put the object file next to the source file.)
- """
- intermediate_builder_name = None
- def write_target(self, fp, src_dir='', pre=''):
- if self.intermediate_builder_name is None:
- raise NotImplementedError
- if src_dir and not src_dir.endswith('/'):
- src_dir += '/'
- variables = {
- 'src_dir': src_dir,
- 'name': self.intermediate_builder_name,
- }
- fp.write(compilable_sources_template % variables)
- super(CompilableSourcesTargetBase, self).write_target(fp)
-
-
-class ProgramTarget(CompilableSourcesTargetBase):
- """
- A GYP target type of 'executable'.
- """
- builder_name = 'GypProgram'
- intermediate_builder_name = 'StaticObject'
- target_prefix = '${PROGPREFIX}'
- target_suffix = '${PROGSUFFIX}'
- out_dir = '${TOP_BUILDDIR}'
-
-
-class StaticLibraryTarget(CompilableSourcesTargetBase):
- """
- A GYP target type of 'static_library'.
- """
- builder_name = 'GypStaticLibrary'
- intermediate_builder_name = 'StaticObject'
- target_prefix = '${LIBPREFIX}'
- target_suffix = '${LIBSUFFIX}'
- out_dir = '${LIB_DIR}'
-
-
-class SharedLibraryTarget(CompilableSourcesTargetBase):
- """
- A GYP target type of 'shared_library'.
- """
- builder_name = 'GypSharedLibrary'
- intermediate_builder_name = 'SharedObject'
- target_prefix = '${SHLIBPREFIX}'
- target_suffix = '${SHLIBSUFFIX}'
- out_dir = '${LIB_DIR}'
-
-
-class LoadableModuleTarget(CompilableSourcesTargetBase):
- """
- A GYP target type of 'loadable_module'.
- """
- builder_name = 'GypLoadableModule'
- intermediate_builder_name = 'SharedObject'
- target_prefix = '${SHLIBPREFIX}'
- target_suffix = '${SHLIBSUFFIX}'
- out_dir = '${TOP_BUILDDIR}'
-
-
-TargetMap = {
- None : NoneTarget,
- 'none' : NoneTarget,
- 'settings' : SettingsTarget,
- 'executable' : ProgramTarget,
- 'static_library' : StaticLibraryTarget,
- 'shared_library' : SharedLibraryTarget,
- 'loadable_module' : LoadableModuleTarget,
-}
-
-
-def Target(spec):
- return TargetMap[spec.get('type')](spec)
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/__init__.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/__init__.py
@@ -18,63 +18,62 @@ from gyp.common import GypError
debug = {}
# List of "official" debug modes, but you can use anything you like.
DEBUG_GENERAL = 'general'
DEBUG_VARIABLES = 'variables'
DEBUG_INCLUDES = 'includes'
-def DebugOutput(mode, message):
- if 'all' in gyp.debug.keys() or mode in gyp.debug.keys():
+def DebugOutput(mode, message, *args):
+ if 'all' in gyp.debug or mode in gyp.debug:
ctx = ('unknown', 0, 'unknown')
try:
f = traceback.extract_stack(limit=2)
if f:
ctx = f[0][:3]
except:
pass
+ if args:
+ message %= args
print '%s:%s:%d:%s %s' % (mode.upper(), os.path.basename(ctx[0]),
ctx[1], ctx[2], message)
def FindBuildFiles():
extension = '.gyp'
files = os.listdir(os.getcwd())
build_files = []
for file in files:
if file.endswith(extension):
build_files.append(file)
return build_files
def Load(build_files, format, default_variables={},
includes=[], depth='.', params=None, check=False,
- circular_check=True):
+ circular_check=True, duplicate_basename_check=True):
"""
Loads one or more specified build files.
default_variables and includes will be copied before use.
Returns the generator for the specified format and the
data returned by loading the specified build files.
"""
if params is None:
params = {}
- flavor = None
if '-' in format:
format, params['flavor'] = format.split('-', 1)
default_variables = copy.copy(default_variables)
# Default variables provided by this program and its modules should be
# named WITH_CAPITAL_LETTERS to provide a distinct "best practice" namespace,
# avoiding collisions with user and automatic variables.
default_variables['GENERATOR'] = format
-
- # Provide a PYTHON value to run sub-commands with the same python
- default_variables['PYTHON'] = sys.executable
+ default_variables['GENERATOR_FLAVOR'] = params.get('flavor', '')
# Format can be a custom python file, or by default the name of a module
# within gyp.generator.
if format.endswith('.py'):
generator_name = os.path.splitext(format)[0]
path, generator_name = os.path.split(generator_name)
# Make sure the path to the custom generator is in sys.path
@@ -102,39 +101,38 @@ def Load(build_files, format, default_va
# the params it will receive in the output phase.
if getattr(generator, 'CalculateGeneratorInputInfo', None):
generator.CalculateGeneratorInputInfo(params)
# Fetch the generator specific info that gets fed to input, we use getattr
# so we can default things and the generators only have to provide what
# they need.
generator_input_info = {
- 'generator_wants_absolute_build_file_paths':
- getattr(generator, 'generator_wants_absolute_build_file_paths', False),
- 'generator_handles_variants':
- getattr(generator, 'generator_handles_variants', False),
'non_configuration_keys':
getattr(generator, 'generator_additional_non_configuration_keys', []),
'path_sections':
getattr(generator, 'generator_additional_path_sections', []),
'extra_sources_for_rules':
getattr(generator, 'generator_extra_sources_for_rules', []),
'generator_supports_multiple_toolsets':
getattr(generator, 'generator_supports_multiple_toolsets', False),
'generator_wants_static_library_dependencies_adjusted':
getattr(generator,
'generator_wants_static_library_dependencies_adjusted', True),
'generator_wants_sorted_dependencies':
getattr(generator, 'generator_wants_sorted_dependencies', False),
+ 'generator_filelist_paths':
+ getattr(generator, 'generator_filelist_paths', None),
}
# Process the input specific to this generator.
result = gyp.input.Load(build_files, default_variables, includes[:],
depth, generator_input_info, check, circular_check,
- params['parallel'])
+ duplicate_basename_check,
+ params['parallel'], params['root_targets'])
return [generator] + result
def NameValueListToDict(name_value_list):
"""
Takes an array of strings of the form 'NAME=VALUE' and creates a dictionary
of the pairs. If a string is simply NAME, then the value in the dictionary
is set to True. If VALUE can be converted to an integer, it is.
"""
@@ -279,126 +277,148 @@ class RegeneratableOptionParser(optparse
return values, args
def gyp_main(args):
my_name = os.path.basename(sys.argv[0])
parser = RegeneratableOptionParser()
usage = 'usage: %s [options ...] [build_file ...]'
parser.set_usage(usage.replace('%s', '%prog'))
- parser.add_option('-D', dest='defines', action='append', metavar='VAR=VAL',
- env_name='GYP_DEFINES',
- help='sets variable VAR to value VAL')
- parser.add_option('-f', '--format', dest='formats', action='append',
- env_name='GYP_GENERATORS', regenerate=False,
- help='output formats to generate')
- parser.add_option('--msvs-version', dest='msvs_version',
- regenerate=False,
- help='Deprecated; use -G msvs_version=MSVS_VERSION instead')
- parser.add_option('-I', '--include', dest='includes', action='append',
- metavar='INCLUDE', type='path',
- help='files to include in all loaded .gyp files')
- parser.add_option('--depth', dest='depth', metavar='PATH', type='path',
- help='set DEPTH gyp variable to a relative path to PATH')
+ parser.add_option('--build', dest='configs', action='append',
+ help='configuration for build after project generation')
+ parser.add_option('--check', dest='check', action='store_true',
+ help='check format of gyp files')
+ parser.add_option('--config-dir', dest='config_dir', action='store',
+ env_name='GYP_CONFIG_DIR', default=None,
+ help='The location for configuration files like '
+ 'include.gypi.')
parser.add_option('-d', '--debug', dest='debug', metavar='DEBUGMODE',
action='append', default=[], help='turn on a debugging '
'mode for debugging GYP. Supported modes are "variables", '
'"includes" and "general" or "all" for all of them.')
- parser.add_option('-S', '--suffix', dest='suffix', default='',
- help='suffix to add to generated files')
+ parser.add_option('-D', dest='defines', action='append', metavar='VAR=VAL',
+ env_name='GYP_DEFINES',
+ help='sets variable VAR to value VAL')
+ parser.add_option('--depth', dest='depth', metavar='PATH', type='path',
+ help='set DEPTH gyp variable to a relative path to PATH')
+ parser.add_option('-f', '--format', dest='formats', action='append',
+ env_name='GYP_GENERATORS', regenerate=False,
+ help='output formats to generate')
parser.add_option('-G', dest='generator_flags', action='append', default=[],
metavar='FLAG=VAL', env_name='GYP_GENERATOR_FLAGS',
help='sets generator flag FLAG to VAL')
parser.add_option('--generator-output', dest='generator_output',
action='store', default=None, metavar='DIR', type='path',
env_name='GYP_GENERATOR_OUTPUT',
help='puts generated build files under DIR')
parser.add_option('--ignore-environment', dest='use_environment',
action='store_false', default=True, regenerate=False,
help='do not read options from environment variables')
- parser.add_option('--check', dest='check', action='store_true',
- help='check format of gyp files')
- parser.add_option('--parallel', action='store_true',
- env_name='GYP_PARALLEL',
- help='Use multiprocessing for speed (experimental)')
- parser.add_option('--toplevel-dir', dest='toplevel_dir', action='store',
- default=None, metavar='DIR', type='path',
- help='directory to use as the root of the source tree')
- parser.add_option('--build', dest='configs', action='append',
- help='configuration for build after project generation')
+ parser.add_option('-I', '--include', dest='includes', action='append',
+ metavar='INCLUDE', type='path',
+ help='files to include in all loaded .gyp files')
# --no-circular-check disables the check for circular relationships between
# .gyp files. These relationships should not exist, but they've only been
# observed to be harmful with the Xcode generator. Chromium's .gyp files
# currently have some circular relationships on non-Mac platforms, so this
# option allows the strict behavior to be used on Macs and the lenient
# behavior to be used elsewhere.
# TODO(mark): Remove this option when http://crbug.com/35878 is fixed.
parser.add_option('--no-circular-check', dest='circular_check',
action='store_false', default=True, regenerate=False,
help="don't check for circular relationships between files")
-
- # We read a few things from ~/.gyp, so set up a var for that.
- home_vars = ['HOME']
- if sys.platform in ('cygwin', 'win32'):
- home_vars.append('USERPROFILE')
- home = None
- home_dot_gyp = None
- for home_var in home_vars:
- home = os.getenv(home_var)
- if home != None:
- home_dot_gyp = os.path.join(home, '.gyp')
- if not os.path.exists(home_dot_gyp):
- home_dot_gyp = None
- else:
- break
-
- # TODO(thomasvl): add support for ~/.gyp/defaults
+ # --no-duplicate-basename-check disables the check for duplicate basenames
+ # in a static_library/shared_library project. Visual C++ 2008 generator
+ # doesn't support this configuration. Libtool on Mac also generates warnings
+ # when duplicate basenames are passed into Make generator on Mac.
+ # TODO(yukawa): Remove this option when these legacy generators are
+ # deprecated.
+ parser.add_option('--no-duplicate-basename-check',
+ dest='duplicate_basename_check', action='store_false',
+ default=True, regenerate=False,
+ help="don't check for duplicate basenames")
+ parser.add_option('--no-parallel', action='store_true', default=False,
+ help='Disable multiprocessing')
+ parser.add_option('-S', '--suffix', dest='suffix', default='',
+ help='suffix to add to generated files')
+ parser.add_option('--toplevel-dir', dest='toplevel_dir', action='store',
+ default=None, metavar='DIR', type='path',
+ help='directory to use as the root of the source tree')
+ parser.add_option('-R', '--root-target', dest='root_targets',
+ action='append', metavar='TARGET',
+ help='include only TARGET and its deep dependencies')
options, build_files_arg = parser.parse_args(args)
build_files = build_files_arg
+ # Set up the configuration directory (defaults to ~/.gyp)
+ if not options.config_dir:
+ home = None
+ home_dot_gyp = None
+ if options.use_environment:
+ home_dot_gyp = os.environ.get('GYP_CONFIG_DIR', None)
+ if home_dot_gyp:
+ home_dot_gyp = os.path.expanduser(home_dot_gyp)
+
+ if not home_dot_gyp:
+ home_vars = ['HOME']
+ if sys.platform in ('cygwin', 'win32'):
+ home_vars.append('USERPROFILE')
+ for home_var in home_vars:
+ home = os.getenv(home_var)
+ if home != None:
+ home_dot_gyp = os.path.join(home, '.gyp')
+ if not os.path.exists(home_dot_gyp):
+ home_dot_gyp = None
+ else:
+ break
+ else:
+ home_dot_gyp = os.path.expanduser(options.config_dir)
+
+ if home_dot_gyp and not os.path.exists(home_dot_gyp):
+ home_dot_gyp = None
+
if not options.formats:
# If no format was given on the command line, then check the env variable.
generate_formats = []
if options.use_environment:
generate_formats = os.environ.get('GYP_GENERATORS', [])
if generate_formats:
- generate_formats = re.split('[\s,]', generate_formats)
+ generate_formats = re.split(r'[\s,]', generate_formats)
if generate_formats:
options.formats = generate_formats
else:
# Nothing in the variable, default based on platform.
if sys.platform == 'darwin':
options.formats = ['xcode']
elif sys.platform in ('win32', 'cygwin'):
options.formats = ['msvs']
else:
options.formats = ['make']
if not options.generator_output and options.use_environment:
g_o = os.environ.get('GYP_GENERATOR_OUTPUT')
if g_o:
options.generator_output = g_o
- if not options.parallel and options.use_environment:
- options.parallel = bool(os.environ.get('GYP_PARALLEL'))
+ options.parallel = not options.no_parallel
for mode in options.debug:
gyp.debug[mode] = 1
# Do an extra check to avoid work when we're not debugging.
- if DEBUG_GENERAL in gyp.debug.keys():
+ if DEBUG_GENERAL in gyp.debug:
DebugOutput(DEBUG_GENERAL, 'running with these options:')
for option, value in sorted(options.__dict__.items()):
if option[0] == '_':
continue
if isinstance(value, basestring):
- DebugOutput(DEBUG_GENERAL, " %s: '%s'" % (option, value))
+ DebugOutput(DEBUG_GENERAL, " %s: '%s'", option, value)
else:
- DebugOutput(DEBUG_GENERAL, " %s: %s" % (option, str(value)))
+ DebugOutput(DEBUG_GENERAL, " %s: %s", option, value)
if not build_files:
build_files = FindBuildFiles()
if not build_files:
raise GypError((usage + '\n\n%s: error: no build_file') %
(my_name, my_name))
# TODO(mark): Chromium-specific hack!
@@ -438,19 +458,19 @@ def gyp_main(args):
# variable's value so that it can't be overridden by anything else.
cmdline_default_variables = {}
defines = []
if options.use_environment:
defines += ShlexEnv('GYP_DEFINES')
if options.defines:
defines += options.defines
cmdline_default_variables = NameValueListToDict(defines)
- if DEBUG_GENERAL in gyp.debug.keys():
+ if DEBUG_GENERAL in gyp.debug:
DebugOutput(DEBUG_GENERAL,
- "cmdline_default_variables: %s" % cmdline_default_variables)
+ "cmdline_default_variables: %s", cmdline_default_variables)
# Set up includes.
includes = []
# If ~/.gyp/include.gypi exists, it'll be forcibly included into every
# .gyp file that's loaded, before anything else is included.
if home_dot_gyp != None:
default_include = os.path.join(home_dot_gyp, 'include.gypi')
@@ -466,45 +486,37 @@ def gyp_main(args):
# are global across all generator runs.
gen_flags = []
if options.use_environment:
gen_flags += ShlexEnv('GYP_GENERATOR_FLAGS')
if options.generator_flags:
gen_flags += options.generator_flags
generator_flags = NameValueListToDict(gen_flags)
if DEBUG_GENERAL in gyp.debug.keys():
- DebugOutput(DEBUG_GENERAL, "generator_flags: %s" % generator_flags)
-
- # TODO: Remove this and the option after we've gotten folks to move to the
- # generator flag.
- if options.msvs_version:
- print >>sys.stderr, \
- 'DEPRECATED: Use generator flag (-G msvs_version=' + \
- options.msvs_version + ') instead of --msvs-version=' + \
- options.msvs_version
- generator_flags['msvs_version'] = options.msvs_version
+ DebugOutput(DEBUG_GENERAL, "generator_flags: %s", generator_flags)
# Generate all requested formats (use a set in case we got one format request
# twice)
for format in set(options.formats):
params = {'options': options,
'build_files': build_files,
'generator_flags': generator_flags,
'cwd': os.getcwd(),
'build_files_arg': build_files_arg,
'gyp_binary': sys.argv[0],
'home_dot_gyp': home_dot_gyp,
- 'parallel': options.parallel}
+ 'parallel': options.parallel,
+ 'root_targets': options.root_targets,
+ 'target_arch': cmdline_default_variables.get('target_arch', '')}
# Start with the default variables from the command line.
- [generator, flat_list, targets, data] = Load(build_files, format,
- cmdline_default_variables,
- includes, options.depth,
- params, options.check,
- options.circular_check)
+ [generator, flat_list, targets, data] = Load(
+ build_files, format, cmdline_default_variables, includes, options.depth,
+ params, options.check, options.circular_check,
+ options.duplicate_basename_check)
# TODO(mark): Pass |data| for now because the generator needs a list of
# build files that came in. In the future, maybe it should just accept
# a list, and not the whole data dict.
# NOTE: flat_list is the flattened dependency graph specifying the order
# that targets may be built. Build systems that operate serially or that
# need to have dependencies defined before dependents reference them should
# generate targets in the order specified in flat_list.
@@ -523,10 +535,14 @@ def gyp_main(args):
def main(args):
try:
return gyp_main(args)
except GypError, e:
sys.stderr.write("gyp: %s\n" % e)
return 1
+# NOTE: setuptools generated console_scripts calls function with no arguments
+def script_main():
+ return main(sys.argv[1:])
+
if __name__ == '__main__':
- sys.exit(main(sys.argv[1:]))
+ sys.exit(script_main())
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/common.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/common.py
@@ -1,14 +1,15 @@
# Copyright (c) 2012 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.
from __future__ import with_statement
+import collections
import errno
import filecmp
import os.path
import re
import tempfile
import sys
@@ -39,16 +40,24 @@ def ExceptionAppend(e, msg):
if not e.args:
e.args = (msg,)
elif len(e.args) == 1:
e.args = (str(e.args[0]) + ' ' + msg,)
else:
e.args = (str(e.args[0]) + ' ' + msg,) + e.args[1:]
+def FindQualifiedTargets(target, qualified_list):
+ """
+ Given a list of qualified targets, return the qualified targets for the
+ specified |target|.
+ """
+ return [t for t in qualified_list if ParseQualifiedTarget(t)[1] == target]
+
+
def ParseQualifiedTarget(target):
# Splits a qualified target into a build file, target name and toolset.
# NOTE: rsplit is used to disambiguate the Windows drive letter separator.
target_split = target.rsplit(':', 1)
if len(target_split) == 2:
[build_file, target] = target_split
else:
@@ -117,24 +126,38 @@ def QualifiedTarget(build_file, target,
# /path/to/file.gyp:target_name#toolset
fully_qualified = build_file + ':' + target
if toolset:
fully_qualified = fully_qualified + '#' + toolset
return fully_qualified
@memoize
-def RelativePath(path, relative_to):
+def RelativePath(path, relative_to, follow_path_symlink=True):
# Assuming both |path| and |relative_to| are relative to the current
# directory, returns a relative path that identifies path relative to
# relative_to.
+ # If |follow_symlink_path| is true (default) and |path| is a symlink, then
+ # this method returns a path to the real file represented by |path|. If it is
+ # false, this method returns a path to the symlink. If |path| is not a
+ # symlink, this option has no effect.
- # Convert to absolute (and therefore normalized paths).
- path = os.path.abspath(path)
- relative_to = os.path.abspath(relative_to)
+ # Convert to normalized (and therefore absolute paths).
+ if follow_path_symlink:
+ path = os.path.realpath(path)
+ else:
+ path = os.path.abspath(path)
+ relative_to = os.path.realpath(relative_to)
+
+ # On Windows, we can't create a relative path to a different drive, so just
+ # use the absolute path.
+ if sys.platform == 'win32':
+ if (os.path.splitdrive(path)[0].lower() !=
+ os.path.splitdrive(relative_to)[0].lower()):
+ return path
# Split the paths into components.
path_split = path.split(os.path.sep)
relative_to_split = relative_to.split(os.path.sep)
# Determine how much of the prefix the two paths share.
prefix_len = len(os.path.commonprefix([path_split, relative_to_split]))
@@ -146,16 +169,30 @@ def RelativePath(path, relative_to):
if len(relative_split) == 0:
# The paths were the same.
return ''
# Turn it back into a string and we're done.
return os.path.join(*relative_split)
+@memoize
+def InvertRelativePath(path, toplevel_dir=None):
+ """Given a path like foo/bar that is relative to toplevel_dir, return
+ the inverse relative path back to the toplevel_dir.
+
+ E.g. os.path.normpath(os.path.join(path, InvertRelativePath(path)))
+ should always produce the empty string, unless the path contains symlinks.
+ """
+ if not path:
+ return path
+ toplevel_dir = '.' if toplevel_dir is None else toplevel_dir
+ return RelativePath(toplevel_dir, os.path.join(toplevel_dir, path))
+
+
def FixIfRelativePath(path, relative_to):
# Like RelativePath but returns |path| unchanged if it is absolute.
if os.path.isabs(path):
return path
return RelativePath(path, relative_to)
def UnrelativePath(path, relative_to):
@@ -294,17 +331,17 @@ def WriteOnDiff(filename):
Arguments:
filename: name of the file to potentially write to.
Returns:
A file like object which will write to temporary file and only overwrite
the target if it differs (on close).
"""
- class Writer:
+ class Writer(object):
"""Wrapper around file which only covers the target if it differs."""
def __init__(self):
# Pick temporary file.
tmp_fd, self.tmp_path = tempfile.mkstemp(
suffix='.tmp',
prefix=os.path.split(filename)[1] + '.gyp.',
dir=os.path.split(filename)[0])
try:
@@ -357,54 +394,82 @@ def WriteOnDiff(filename):
except Exception:
# Don't leave turds behind.
os.unlink(self.tmp_path)
raise
return Writer()
+def EnsureDirExists(path):
+ """Make sure the directory for |path| exists."""
+ try:
+ os.makedirs(os.path.dirname(path))
+ except OSError:
+ pass
+
+
def GetFlavor(params):
"""Returns |params.flavor| if it's set, the system's default flavor else."""
flavors = {
'cygwin': 'win',
'win32': 'win',
'darwin': 'mac',
}
if 'flavor' in params:
return params['flavor']
if sys.platform in flavors:
return flavors[sys.platform]
if sys.platform.startswith('sunos'):
return 'solaris'
if sys.platform.startswith('freebsd'):
return 'freebsd'
+ if sys.platform.startswith('openbsd'):
+ return 'openbsd'
+ if sys.platform.startswith('netbsd'):
+ return 'netbsd'
+ if sys.platform.startswith('aix'):
+ return 'aix'
return 'linux'
-def CopyTool(flavor, out_path):
- """Finds (mac|sun|win)_tool.gyp in the gyp directory and copies it
+def CopyTool(flavor, out_path, generator_flags={}):
+ """Finds (flock|mac|win)_tool.gyp in the gyp directory and copies it
to |out_path|."""
- prefix = { 'solaris': 'sun', 'mac': 'mac', 'win': 'win' }.get(flavor, None)
+ # aix and solaris just need flock emulation. mac and win use more complicated
+ # support scripts.
+ prefix = {
+ 'aix': 'flock',
+ 'solaris': 'flock',
+ 'mac': 'mac',
+ 'win': 'win'
+ }.get(flavor, None)
if not prefix:
return
# Slurp input file.
source_path = os.path.join(
os.path.dirname(os.path.abspath(__file__)), '%s_tool.py' % prefix)
with open(source_path) as source_file:
source = source_file.readlines()
+ # Set custom header flags.
+ header = '# Generated by gyp. Do not edit.\n'
+ mac_toolchain_dir = generator_flags.get('mac_toolchain_dir', None)
+ if flavor == 'mac' and mac_toolchain_dir:
+ header += "import os;\nos.environ['DEVELOPER_DIR']='%s'\n" \
+ % mac_toolchain_dir
+
# Add header and write it out.
tool_path = os.path.join(out_path, 'gyp-%s-tool' % prefix)
with open(tool_path, 'w') as tool_file:
tool_file.write(
- ''.join([source[0], '# Generated by gyp. Do not edit.\n'] + source[1:]))
+ ''.join([source[0], header] + source[1:]))
# Make file executable.
os.chmod(tool_path, 0755)
# From Alex Martelli,
# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52560
# ASPN: Python Cookbook: Remove duplicates from a sequence
@@ -419,26 +484,92 @@ def uniquer(seq, idfun=None):
for item in seq:
marker = idfun(item)
if marker in seen: continue
seen[marker] = 1
result.append(item)
return result
+# Based on http://code.activestate.com/recipes/576694/.
+class OrderedSet(collections.MutableSet):
+ def __init__(self, iterable=None):
+ self.end = end = []
+ end += [None, end, end] # sentinel node for doubly linked list
+ self.map = {} # key --> [key, prev, next]
+ if iterable is not None:
+ self |= iterable
+
+ def __len__(self):
+ return len(self.map)
+
+ def __contains__(self, key):
+ return key in self.map
+
+ def add(self, key):
+ if key not in self.map:
+ end = self.end
+ curr = end[1]
+ curr[2] = end[1] = self.map[key] = [key, curr, end]
+
+ def discard(self, key):
+ if key in self.map:
+ key, prev_item, next_item = self.map.pop(key)
+ prev_item[2] = next_item
+ next_item[1] = prev_item
+
+ def __iter__(self):
+ end = self.end
+ curr = end[2]
+ while curr is not end:
+ yield curr[0]
+ curr = curr[2]
+
+ def __reversed__(self):
+ end = self.end
+ curr = end[1]
+ while curr is not end:
+ yield curr[0]
+ curr = curr[1]
+
+ # The second argument is an addition that causes a pylint warning.
+ def pop(self, last=True): # pylint: disable=W0221
+ if not self:
+ raise KeyError('set is empty')
+ key = self.end[1][0] if last else self.end[2][0]
+ self.discard(key)
+ return key
+
+ def __repr__(self):
+ if not self:
+ return '%s()' % (self.__class__.__name__,)
+ return '%s(%r)' % (self.__class__.__name__, list(self))
+
+ def __eq__(self, other):
+ if isinstance(other, OrderedSet):
+ return len(self) == len(other) and list(self) == list(other)
+ return set(self) == set(other)
+
+ # Extensions to the recipe.
+ def update(self, iterable):
+ for i in iterable:
+ if i not in self:
+ self.add(i)
+
+
class CycleError(Exception):
"""An exception raised when an unexpected cycle is detected."""
def __init__(self, nodes):
self.nodes = nodes
def __str__(self):
return 'CycleError: cycle involving: ' + str(self.nodes)
def TopologicallySorted(graph, get_edges):
- """Topologically sort based on a user provided edge definition.
+ r"""Topologically sort based on a user provided edge definition.
Args:
graph: A list of node names.
get_edges: A function mapping from node name to a hashable collection
of node names which this node has outgoing edges to.
Returns:
A list containing all of the node in graph in topological order.
It is assumed that calling get_edges once for each node and caching is
@@ -466,8 +597,19 @@ def TopologicallySorted(graph, get_edges
visiting.add(node)
for neighbor in get_edges(node):
Visit(neighbor)
visiting.remove(node)
ordered_nodes.insert(0, node)
for node in sorted(graph):
Visit(node)
return ordered_nodes
+
+def CrossCompileRequested():
+ # TODO: figure out how to not build extra host objects in the
+ # non-cross-compile case when this is enabled, and enable unconditionally.
+ return (os.environ.get('GYP_CROSSCOMPILE') or
+ os.environ.get('AR_host') or
+ os.environ.get('CC_host') or
+ os.environ.get('CXX_host') or
+ os.environ.get('AR_target') or
+ os.environ.get('CC_target') or
+ os.environ.get('CXX_target'))
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/common_test.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/common_test.py
@@ -53,16 +53,17 @@ class TestGetFlavor(unittest.TestCase):
def assertFlavor(self, expected, argument, param):
sys.platform = argument
self.assertEqual(expected, gyp.common.GetFlavor(param))
def test_platform_default(self):
self.assertFlavor('freebsd', 'freebsd9' , {})
self.assertFlavor('freebsd', 'freebsd10', {})
+ self.assertFlavor('openbsd', 'openbsd5' , {})
self.assertFlavor('solaris', 'sunos5' , {});
self.assertFlavor('solaris', 'sunos' , {});
self.assertFlavor('linux' , 'linux2' , {});
self.assertFlavor('linux' , 'linux3' , {});
def test_param(self):
self.assertFlavor('foobar', 'linux2' , {'flavor': 'foobar'})
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/flock_tool.py
@@ -0,0 +1,54 @@
+#!/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.
+
+"""These functions are executed via gyp-flock-tool when using the Makefile
+generator. Used on systems that don't have a built-in flock."""
+
+import fcntl
+import os
+import struct
+import subprocess
+import sys
+
+
+def main(args):
+ executor = FlockTool()
+ executor.Dispatch(args)
+
+
+class FlockTool(object):
+ """This class emulates the 'flock' command."""
+ def Dispatch(self, args):
+ """Dispatches a string command to a method."""
+ if len(args) < 1:
+ raise Exception("Not enough arguments")
+
+ method = "Exec%s" % self._CommandifyName(args[0])
+ getattr(self, method)(*args[1:])
+
+ def _CommandifyName(self, name_string):
+ """Transforms a tool name like copy-info-plist to CopyInfoPlist"""
+ return name_string.title().replace('-', '')
+
+ def ExecFlock(self, lockfile, *cmd_list):
+ """Emulates the most basic behavior of Linux's flock(1)."""
+ # Rely on exception handling to report errors.
+ # Note that the stock python on SunOS has a bug
+ # where fcntl.flock(fd, LOCK_EX) always fails
+ # with EBADF, that's why we use this F_SETLK
+ # hack instead.
+ fd = os.open(lockfile, os.O_WRONLY|os.O_NOCTTY|os.O_CREAT, 0666)
+ if sys.platform.startswith('aix'):
+ # Python on AIX is compiled with LARGEFILE support, which changes the
+ # struct size.
+ op = struct.pack('hhIllqq', fcntl.F_WRLCK, 0, 0, 0, 0, 0, 0)
+ else:
+ op = struct.pack('hhllhhl', fcntl.F_WRLCK, 0, 0, 0, 0, 0, 0)
+ fcntl.fcntl(fd, fcntl.F_SETLK, op)
+ return subprocess.call(cmd_list)
+
+
+if __name__ == '__main__':
+ sys.exit(main(sys.argv[1:]))
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/analyzer.py
@@ -0,0 +1,741 @@
+# Copyright (c) 2014 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.
+
+"""
+This script is intended for use as a GYP_GENERATOR. It takes as input (by way of
+the generator flag config_path) the path of a json file that dictates the files
+and targets to search for. The following keys are supported:
+files: list of paths (relative) of the files to search for.
+test_targets: unqualified target names to search for. Any target in this list
+that depends upon a file in |files| is output regardless of the type of target
+or chain of dependencies.
+additional_compile_targets: Unqualified targets to search for in addition to
+test_targets. Targets in the combined list that depend upon a file in |files|
+are not necessarily output. For example, if the target is of type none then the
+target is not output (but one of the descendants of the target will be).
+
+The following is output:
+error: only supplied if there is an error.
+compile_targets: minimal set of targets that directly or indirectly (for
+ targets of type none) depend on the files in |files| and is one of the
+ supplied targets or a target that one of the supplied targets depends on.
+ The expectation is this set of targets is passed into a build step. This list
+ always contains the output of test_targets as well.
+test_targets: set of targets from the supplied |test_targets| that either
+ directly or indirectly depend upon a file in |files|. This list if useful
+ if additional processing needs to be done for certain targets after the
+ build, such as running tests.
+status: outputs one of three values: none of the supplied files were found,
+ one of the include files changed so that it should be assumed everything
+ changed (in this case test_targets and compile_targets are not output) or at
+ least one file was found.
+invalid_targets: list of supplied targets that were not found.
+
+Example:
+Consider a graph like the following:
+ A D
+ / \
+B C
+A depends upon both B and C, A is of type none and B and C are executables.
+D is an executable, has no dependencies and nothing depends on it.
+If |additional_compile_targets| = ["A"], |test_targets| = ["B", "C"] and
+files = ["b.cc", "d.cc"] (B depends upon b.cc and D depends upon d.cc), then
+the following is output:
+|compile_targets| = ["B"] B must built as it depends upon the changed file b.cc
+and the supplied target A depends upon it. A is not output as a build_target
+as it is of type none with no rules and actions.
+|test_targets| = ["B"] B directly depends upon the change file b.cc.
+
+Even though the file d.cc, which D depends upon, has changed D is not output
+as it was not supplied by way of |additional_compile_targets| or |test_targets|.
+
+If the generator flag analyzer_output_path is specified, output is written
+there. Otherwise output is written to stdout.
+
+In Gyp the "all" target is shorthand for the root targets in the files passed
+to gyp. For example, if file "a.gyp" contains targets "a1" and
+"a2", and file "b.gyp" contains targets "b1" and "b2" and "a2" has a dependency
+on "b2" and gyp is supplied "a.gyp" then "all" consists of "a1" and "a2".
+Notice that "b1" and "b2" are not in the "all" target as "b.gyp" was not
+directly supplied to gyp. OTOH if both "a.gyp" and "b.gyp" are supplied to gyp
+then the "all" target includes "b1" and "b2".
+"""
+
+import gyp.common
+import gyp.ninja_syntax as ninja_syntax
+import json
+import os
+import posixpath
+import sys
+
+debug = False
+
+found_dependency_string = 'Found dependency'
+no_dependency_string = 'No dependencies'
+# Status when it should be assumed that everything has changed.
+all_changed_string = 'Found dependency (all)'
+
+# MatchStatus is used indicate if and how a target depends upon the supplied
+# sources.
+# The target's sources contain one of the supplied paths.
+MATCH_STATUS_MATCHES = 1
+# The target has a dependency on another target that contains one of the
+# supplied paths.
+MATCH_STATUS_MATCHES_BY_DEPENDENCY = 2
+# The target's sources weren't in the supplied paths and none of the target's
+# dependencies depend upon a target that matched.
+MATCH_STATUS_DOESNT_MATCH = 3
+# The target doesn't contain the source, but the dependent targets have not yet
+# been visited to determine a more specific status yet.
+MATCH_STATUS_TBD = 4
+
+generator_supports_multiple_toolsets = gyp.common.CrossCompileRequested()
+
+generator_wants_static_library_dependencies_adjusted = False
+
+generator_default_variables = {
+}
+for dirname in ['INTERMEDIATE_DIR', 'SHARED_INTERMEDIATE_DIR', 'PRODUCT_DIR',
+ 'LIB_DIR', 'SHARED_LIB_DIR']:
+ generator_default_variables[dirname] = '!!!'
+
+for unused in ['RULE_INPUT_PATH', 'RULE_INPUT_ROOT', 'RULE_INPUT_NAME',
+ 'RULE_INPUT_DIRNAME', 'RULE_INPUT_EXT',
+ 'EXECUTABLE_PREFIX', 'EXECUTABLE_SUFFIX',
+ 'STATIC_LIB_PREFIX', 'STATIC_LIB_SUFFIX',
+ 'SHARED_LIB_PREFIX', 'SHARED_LIB_SUFFIX',
+ 'CONFIGURATION_NAME']:
+ generator_default_variables[unused] = ''
+
+
+def _ToGypPath(path):
+ """Converts a path to the format used by gyp."""
+ if os.sep == '\\' and os.altsep == '/':
+ return path.replace('\\', '/')
+ return path
+
+
+def _ResolveParent(path, base_path_components):
+ """Resolves |path|, which starts with at least one '../'. Returns an empty
+ string if the path shouldn't be considered. See _AddSources() for a
+ description of |base_path_components|."""
+ depth = 0
+ while path.startswith('../'):
+ depth += 1
+ path = path[3:]
+ # Relative includes may go outside the source tree. For example, an action may
+ # have inputs in /usr/include, which are not in the source tree.
+ if depth > len(base_path_components):
+ return ''
+ if depth == len(base_path_components):
+ return path
+ return '/'.join(base_path_components[0:len(base_path_components) - depth]) + \
+ '/' + path
+
+
+def _AddSources(sources, base_path, base_path_components, result):
+ """Extracts valid sources from |sources| and adds them to |result|. Each
+ source file is relative to |base_path|, but may contain '..'. To make
+ resolving '..' easier |base_path_components| contains each of the
+ directories in |base_path|. Additionally each source may contain variables.
+ Such sources are ignored as it is assumed dependencies on them are expressed
+ and tracked in some other means."""
+ # NOTE: gyp paths are always posix style.
+ for source in sources:
+ if not len(source) or source.startswith('!!!') or source.startswith('$'):
+ continue
+ # variable expansion may lead to //.
+ org_source = source
+ source = source[0] + source[1:].replace('//', '/')
+ if source.startswith('../'):
+ source = _ResolveParent(source, base_path_components)
+ if len(source):
+ result.append(source)
+ continue
+ result.append(base_path + source)
+ if debug:
+ print 'AddSource', org_source, result[len(result) - 1]
+
+
+def _ExtractSourcesFromAction(action, base_path, base_path_components,
+ results):
+ if 'inputs' in action:
+ _AddSources(action['inputs'], base_path, base_path_components, results)
+
+
+def _ToLocalPath(toplevel_dir, path):
+ """Converts |path| to a path relative to |toplevel_dir|."""
+ if path == toplevel_dir:
+ return ''
+ if path.startswith(toplevel_dir + '/'):
+ return path[len(toplevel_dir) + len('/'):]
+ return path
+
+
+def _ExtractSources(target, target_dict, toplevel_dir):
+ # |target| is either absolute or relative and in the format of the OS. Gyp
+ # source paths are always posix. Convert |target| to a posix path relative to
+ # |toplevel_dir_|. This is done to make it easy to build source paths.
+ base_path = posixpath.dirname(_ToLocalPath(toplevel_dir, _ToGypPath(target)))
+ base_path_components = base_path.split('/')
+
+ # Add a trailing '/' so that _AddSources() can easily build paths.
+ if len(base_path):
+ base_path += '/'
+
+ if debug:
+ print 'ExtractSources', target, base_path
+
+ results = []
+ if 'sources' in target_dict:
+ _AddSources(target_dict['sources'], base_path, base_path_components,
+ results)
+ # Include the inputs from any actions. Any changes to these affect the
+ # resulting output.
+ if 'actions' in target_dict:
+ for action in target_dict['actions']:
+ _ExtractSourcesFromAction(action, base_path, base_path_components,
+ results)
+ if 'rules' in target_dict:
+ for rule in target_dict['rules']:
+ _ExtractSourcesFromAction(rule, base_path, base_path_components, results)
+
+ return results
+
+
+class Target(object):
+ """Holds information about a particular target:
+ deps: set of Targets this Target depends upon. This is not recursive, only the
+ direct dependent Targets.
+ match_status: one of the MatchStatus values.
+ back_deps: set of Targets that have a dependency on this Target.
+ visited: used during iteration to indicate whether we've visited this target.
+ This is used for two iterations, once in building the set of Targets and
+ again in _GetBuildTargets().
+ name: fully qualified name of the target.
+ requires_build: True if the target type is such that it needs to be built.
+ See _DoesTargetTypeRequireBuild for details.
+ added_to_compile_targets: used when determining if the target was added to the
+ set of targets that needs to be built.
+ in_roots: true if this target is a descendant of one of the root nodes.
+ is_executable: true if the type of target is executable.
+ is_static_library: true if the type of target is static_library.
+ is_or_has_linked_ancestor: true if the target does a link (eg executable), or
+ if there is a target in back_deps that does a link."""
+ def __init__(self, name):
+ self.deps = set()
+ self.match_status = MATCH_STATUS_TBD
+ self.back_deps = set()
+ self.name = name
+ # TODO(sky): I don't like hanging this off Target. This state is specific
+ # to certain functions and should be isolated there.
+ self.visited = False
+ self.requires_build = False
+ self.added_to_compile_targets = False
+ self.in_roots = False
+ self.is_executable = False
+ self.is_static_library = False
+ self.is_or_has_linked_ancestor = False
+
+
+class Config(object):
+ """Details what we're looking for
+ files: set of files to search for
+ targets: see file description for details."""
+ def __init__(self):
+ self.files = []
+ self.targets = set()
+ self.additional_compile_target_names = set()
+ self.test_target_names = set()
+
+ def Init(self, params):
+ """Initializes Config. This is a separate method as it raises an exception
+ if there is a parse error."""
+ generator_flags = params.get('generator_flags', {})
+ config_path = generator_flags.get('config_path', None)
+ if not config_path:
+ return
+ try:
+ f = open(config_path, 'r')
+ config = json.load(f)
+ f.close()
+ except IOError:
+ raise Exception('Unable to open file ' + config_path)
+ except ValueError as e:
+ raise Exception('Unable to parse config file ' + config_path + str(e))
+ if not isinstance(config, dict):
+ raise Exception('config_path must be a JSON file containing a dictionary')
+ self.files = config.get('files', [])
+ self.additional_compile_target_names = set(
+ config.get('additional_compile_targets', []))
+ self.test_target_names = set(config.get('test_targets', []))
+
+
+def _WasBuildFileModified(build_file, data, files, toplevel_dir):
+ """Returns true if the build file |build_file| is either in |files| or
+ one of the files included by |build_file| is in |files|. |toplevel_dir| is
+ the root of the source tree."""
+ if _ToLocalPath(toplevel_dir, _ToGypPath(build_file)) in files:
+ if debug:
+ print 'gyp file modified', build_file
+ return True
+
+ # First element of included_files is the file itself.
+ if len(data[build_file]['included_files']) <= 1:
+ return False
+
+ for include_file in data[build_file]['included_files'][1:]:
+ # |included_files| are relative to the directory of the |build_file|.
+ rel_include_file = \
+ _ToGypPath(gyp.common.UnrelativePath(include_file, build_file))
+ if _ToLocalPath(toplevel_dir, rel_include_file) in files:
+ if debug:
+ print 'included gyp file modified, gyp_file=', build_file, \
+ 'included file=', rel_include_file
+ return True
+ return False
+
+
+def _GetOrCreateTargetByName(targets, target_name):
+ """Creates or returns the Target at targets[target_name]. If there is no
+ Target for |target_name| one is created. Returns a tuple of whether a new
+ Target was created and the Target."""
+ if target_name in targets:
+ return False, targets[target_name]
+ target = Target(target_name)
+ targets[target_name] = target
+ return True, target
+
+
+def _DoesTargetTypeRequireBuild(target_dict):
+ """Returns true if the target type is such that it needs to be built."""
+ # If a 'none' target has rules or actions we assume it requires a build.
+ return bool(target_dict['type'] != 'none' or
+ target_dict.get('actions') or target_dict.get('rules'))
+
+
+def _GenerateTargets(data, target_list, target_dicts, toplevel_dir, files,
+ build_files):
+ """Returns a tuple of the following:
+ . A dictionary mapping from fully qualified name to Target.
+ . A list of the targets that have a source file in |files|.
+ . Targets that constitute the 'all' target. See description at top of file
+ for details on the 'all' target.
+ This sets the |match_status| of the targets that contain any of the source
+ files in |files| to MATCH_STATUS_MATCHES.
+ |toplevel_dir| is the root of the source tree."""
+ # Maps from target name to Target.
+ name_to_target = {}
+
+ # Targets that matched.
+ matching_targets = []
+
+ # Queue of targets to visit.
+ targets_to_visit = target_list[:]
+
+ # Maps from build file to a boolean indicating whether the build file is in
+ # |files|.
+ build_file_in_files = {}
+
+ # Root targets across all files.
+ roots = set()
+
+ # Set of Targets in |build_files|.
+ build_file_targets = set()
+
+ while len(targets_to_visit) > 0:
+ target_name = targets_to_visit.pop()
+ created_target, target = _GetOrCreateTargetByName(name_to_target,
+ target_name)
+ if created_target:
+ roots.add(target)
+ elif target.visited:
+ continue
+
+ target.visited = True
+ target.requires_build = _DoesTargetTypeRequireBuild(
+ target_dicts[target_name])
+ target_type = target_dicts[target_name]['type']
+ target.is_executable = target_type == 'executable'
+ target.is_static_library = target_type == 'static_library'
+ target.is_or_has_linked_ancestor = (target_type == 'executable' or
+ target_type == 'shared_library')
+
+ build_file = gyp.common.ParseQualifiedTarget(target_name)[0]
+ if not build_file in build_file_in_files:
+ build_file_in_files[build_file] = \
+ _WasBuildFileModified(build_file, data, files, toplevel_dir)
+
+ if build_file in build_files:
+ build_file_targets.add(target)
+
+ # If a build file (or any of its included files) is modified we assume all
+ # targets in the file are modified.
+ if build_file_in_files[build_file]:
+ print 'matching target from modified build file', target_name
+ target.match_status = MATCH_STATUS_MATCHES
+ matching_targets.append(target)
+ else:
+ sources = _ExtractSources(target_name, target_dicts[target_name],
+ toplevel_dir)
+ for source in sources:
+ if _ToGypPath(os.path.normpath(source)) in files:
+ print 'target', target_name, 'matches', source
+ target.match_status = MATCH_STATUS_MATCHES
+ matching_targets.append(target)
+ break
+
+ # Add dependencies to visit as well as updating back pointers for deps.
+ for dep in target_dicts[target_name].get('dependencies', []):
+ targets_to_visit.append(dep)
+
+ created_dep_target, dep_target = _GetOrCreateTargetByName(name_to_target,
+ dep)
+ if not created_dep_target:
+ roots.discard(dep_target)
+
+ target.deps.add(dep_target)
+ dep_target.back_deps.add(target)
+
+ return name_to_target, matching_targets, roots & build_file_targets
+
+
+def _GetUnqualifiedToTargetMapping(all_targets, to_find):
+ """Returns a tuple of the following:
+ . mapping (dictionary) from unqualified name to Target for all the
+ Targets in |to_find|.
+ . any target names not found. If this is empty all targets were found."""
+ result = {}
+ if not to_find:
+ return {}, []
+ to_find = set(to_find)
+ for target_name in all_targets.keys():
+ extracted = gyp.common.ParseQualifiedTarget(target_name)
+ if len(extracted) > 1 and extracted[1] in to_find:
+ to_find.remove(extracted[1])
+ result[extracted[1]] = all_targets[target_name]
+ if not to_find:
+ return result, []
+ return result, [x for x in to_find]
+
+
+def _DoesTargetDependOnMatchingTargets(target):
+ """Returns true if |target| or any of its dependencies is one of the
+ targets containing the files supplied as input to analyzer. This updates
+ |matches| of the Targets as it recurses.
+ target: the Target to look for."""
+ if target.match_status == MATCH_STATUS_DOESNT_MATCH:
+ return False
+ if target.match_status == MATCH_STATUS_MATCHES or \
+ target.match_status == MATCH_STATUS_MATCHES_BY_DEPENDENCY:
+ return True
+ for dep in target.deps:
+ if _DoesTargetDependOnMatchingTargets(dep):
+ target.match_status = MATCH_STATUS_MATCHES_BY_DEPENDENCY
+ print '\t', target.name, 'matches by dep', dep.name
+ return True
+ target.match_status = MATCH_STATUS_DOESNT_MATCH
+ return False
+
+
+def _GetTargetsDependingOnMatchingTargets(possible_targets):
+ """Returns the list of Targets in |possible_targets| that depend (either
+ directly on indirectly) on at least one of the targets containing the files
+ supplied as input to analyzer.
+ possible_targets: targets to search from."""
+ found = []
+ print 'Targets that matched by dependency:'
+ for target in possible_targets:
+ if _DoesTargetDependOnMatchingTargets(target):
+ found.append(target)
+ return found
+
+
+def _AddCompileTargets(target, roots, add_if_no_ancestor, result):
+ """Recurses through all targets that depend on |target|, adding all targets
+ that need to be built (and are in |roots|) to |result|.
+ roots: set of root targets.
+ add_if_no_ancestor: If true and there are no ancestors of |target| then add
+ |target| to |result|. |target| must still be in |roots|.
+ result: targets that need to be built are added here."""
+ if target.visited:
+ return
+
+ target.visited = True
+ target.in_roots = target in roots
+
+ for back_dep_target in target.back_deps:
+ _AddCompileTargets(back_dep_target, roots, False, result)
+ target.added_to_compile_targets |= back_dep_target.added_to_compile_targets
+ target.in_roots |= back_dep_target.in_roots
+ target.is_or_has_linked_ancestor |= (
+ back_dep_target.is_or_has_linked_ancestor)
+
+ # Always add 'executable' targets. Even though they may be built by other
+ # targets that depend upon them it makes detection of what is going to be
+ # built easier.
+ # And always add static_libraries that have no dependencies on them from
+ # linkables. This is necessary as the other dependencies on them may be
+ # static libraries themselves, which are not compile time dependencies.
+ if target.in_roots and \
+ (target.is_executable or
+ (not target.added_to_compile_targets and
+ (add_if_no_ancestor or target.requires_build)) or
+ (target.is_static_library and add_if_no_ancestor and
+ not target.is_or_has_linked_ancestor)):
+ print '\t\tadding to compile targets', target.name, 'executable', \
+ target.is_executable, 'added_to_compile_targets', \
+ target.added_to_compile_targets, 'add_if_no_ancestor', \
+ add_if_no_ancestor, 'requires_build', target.requires_build, \
+ 'is_static_library', target.is_static_library, \
+ 'is_or_has_linked_ancestor', target.is_or_has_linked_ancestor
+ result.add(target)
+ target.added_to_compile_targets = True
+
+
+def _GetCompileTargets(matching_targets, supplied_targets):
+ """Returns the set of Targets that require a build.
+ matching_targets: targets that changed and need to be built.
+ supplied_targets: set of targets supplied to analyzer to search from."""
+ result = set()
+ for target in matching_targets:
+ print 'finding compile targets for match', target.name
+ _AddCompileTargets(target, supplied_targets, True, result)
+ return result
+
+
+def _WriteOutput(params, **values):
+ """Writes the output, either to stdout or a file is specified."""
+ if 'error' in values:
+ print 'Error:', values['error']
+ if 'status' in values:
+ print values['status']
+ if 'targets' in values:
+ values['targets'].sort()
+ print 'Supplied targets that depend on changed files:'
+ for target in values['targets']:
+ print '\t', target
+ if 'invalid_targets' in values:
+ values['invalid_targets'].sort()
+ print 'The following targets were not found:'
+ for target in values['invalid_targets']:
+ print '\t', target
+ if 'build_targets' in values:
+ values['build_targets'].sort()
+ print 'Targets that require a build:'
+ for target in values['build_targets']:
+ print '\t', target
+ if 'compile_targets' in values:
+ values['compile_targets'].sort()
+ print 'Targets that need to be built:'
+ for target in values['compile_targets']:
+ print '\t', target
+ if 'test_targets' in values:
+ values['test_targets'].sort()
+ print 'Test targets:'
+ for target in values['test_targets']:
+ print '\t', target
+
+ output_path = params.get('generator_flags', {}).get(
+ 'analyzer_output_path', None)
+ if not output_path:
+ print json.dumps(values)
+ return
+ try:
+ f = open(output_path, 'w')
+ f.write(json.dumps(values) + '\n')
+ f.close()
+ except IOError as e:
+ print 'Error writing to output file', output_path, str(e)
+
+
+def _WasGypIncludeFileModified(params, files):
+ """Returns true if one of the files in |files| is in the set of included
+ files."""
+ if params['options'].includes:
+ for include in params['options'].includes:
+ if _ToGypPath(os.path.normpath(include)) in files:
+ print 'Include file modified, assuming all changed', include
+ return True
+ return False
+
+
+def _NamesNotIn(names, mapping):
+ """Returns a list of the values in |names| that are not in |mapping|."""
+ return [name for name in names if name not in mapping]
+
+
+def _LookupTargets(names, mapping):
+ """Returns a list of the mapping[name] for each value in |names| that is in
+ |mapping|."""
+ return [mapping[name] for name in names if name in mapping]
+
+
+def CalculateVariables(default_variables, params):
+ """Calculate additional variables for use in the build (called by gyp)."""
+ flavor = gyp.common.GetFlavor(params)
+ if flavor == 'mac':
+ default_variables.setdefault('OS', 'mac')
+ elif flavor == 'win':
+ default_variables.setdefault('OS', 'win')
+ # Copy additional generator configuration data from VS, which is shared
+ # by the Windows Ninja generator.
+ import gyp.generator.msvs as msvs_generator
+ generator_additional_non_configuration_keys = getattr(msvs_generator,
+ 'generator_additional_non_configuration_keys', [])
+ generator_additional_path_sections = getattr(msvs_generator,
+ 'generator_additional_path_sections', [])
+
+ gyp.msvs_emulation.CalculateCommonVariables(default_variables, params)
+ else:
+ operating_system = flavor
+ if flavor == 'android':
+ operating_system = 'linux' # Keep this legacy behavior for now.
+ default_variables.setdefault('OS', operating_system)
+
+
+class TargetCalculator(object):
+ """Calculates the matching test_targets and matching compile_targets."""
+ def __init__(self, files, additional_compile_target_names, test_target_names,
+ data, target_list, target_dicts, toplevel_dir, build_files):
+ self._additional_compile_target_names = set(additional_compile_target_names)
+ self._test_target_names = set(test_target_names)
+ self._name_to_target, self._changed_targets, self._root_targets = (
+ _GenerateTargets(data, target_list, target_dicts, toplevel_dir,
+ frozenset(files), build_files))
+ self._unqualified_mapping, self.invalid_targets = (
+ _GetUnqualifiedToTargetMapping(self._name_to_target,
+ self._supplied_target_names_no_all()))
+
+ def _supplied_target_names(self):
+ return self._additional_compile_target_names | self._test_target_names
+
+ def _supplied_target_names_no_all(self):
+ """Returns the supplied test targets without 'all'."""
+ result = self._supplied_target_names();
+ result.discard('all')
+ return result
+
+ def is_build_impacted(self):
+ """Returns true if the supplied files impact the build at all."""
+ return self._changed_targets
+
+ def find_matching_test_target_names(self):
+ """Returns the set of output test targets."""
+ assert self.is_build_impacted()
+ # Find the test targets first. 'all' is special cased to mean all the
+ # root targets. To deal with all the supplied |test_targets| are expanded
+ # to include the root targets during lookup. If any of the root targets
+ # match, we remove it and replace it with 'all'.
+ test_target_names_no_all = set(self._test_target_names)
+ test_target_names_no_all.discard('all')
+ test_targets_no_all = _LookupTargets(test_target_names_no_all,
+ self._unqualified_mapping)
+ test_target_names_contains_all = 'all' in self._test_target_names
+ if test_target_names_contains_all:
+ test_targets = [x for x in (set(test_targets_no_all) |
+ set(self._root_targets))]
+ else:
+ test_targets = [x for x in test_targets_no_all]
+ print 'supplied test_targets'
+ for target_name in self._test_target_names:
+ print '\t', target_name
+ print 'found test_targets'
+ for target in test_targets:
+ print '\t', target.name
+ print 'searching for matching test targets'
+ matching_test_targets = _GetTargetsDependingOnMatchingTargets(test_targets)
+ matching_test_targets_contains_all = (test_target_names_contains_all and
+ set(matching_test_targets) &
+ set(self._root_targets))
+ if matching_test_targets_contains_all:
+ # Remove any of the targets for all that were not explicitly supplied,
+ # 'all' is subsequentely added to the matching names below.
+ matching_test_targets = [x for x in (set(matching_test_targets) &
+ set(test_targets_no_all))]
+ print 'matched test_targets'
+ for target in matching_test_targets:
+ print '\t', target.name
+ matching_target_names = [gyp.common.ParseQualifiedTarget(target.name)[1]
+ for target in matching_test_targets]
+ if matching_test_targets_contains_all:
+ matching_target_names.append('all')
+ print '\tall'
+ return matching_target_names
+
+ def find_matching_compile_target_names(self):
+ """Returns the set of output compile targets."""
+ assert self.is_build_impacted();
+ # Compile targets are found by searching up from changed targets.
+ # Reset the visited status for _GetBuildTargets.
+ for target in self._name_to_target.itervalues():
+ target.visited = False
+
+ supplied_targets = _LookupTargets(self._supplied_target_names_no_all(),
+ self._unqualified_mapping)
+ if 'all' in self._supplied_target_names():
+ supplied_targets = [x for x in (set(supplied_targets) |
+ set(self._root_targets))]
+ print 'Supplied test_targets & compile_targets'
+ for target in supplied_targets:
+ print '\t', target.name
+ print 'Finding compile targets'
+ compile_targets = _GetCompileTargets(self._changed_targets,
+ supplied_targets)
+ return [gyp.common.ParseQualifiedTarget(target.name)[1]
+ for target in compile_targets]
+
+
+def GenerateOutput(target_list, target_dicts, data, params):
+ """Called by gyp as the final stage. Outputs results."""
+ config = Config()
+ try:
+ config.Init(params)
+
+ if not config.files:
+ raise Exception('Must specify files to analyze via config_path generator '
+ 'flag')
+
+ toplevel_dir = _ToGypPath(os.path.abspath(params['options'].toplevel_dir))
+ if debug:
+ print 'toplevel_dir', toplevel_dir
+
+ if _WasGypIncludeFileModified(params, config.files):
+ result_dict = { 'status': all_changed_string,
+ 'test_targets': list(config.test_target_names),
+ 'compile_targets': list(
+ config.additional_compile_target_names |
+ config.test_target_names) }
+ _WriteOutput(params, **result_dict)
+ return
+
+ calculator = TargetCalculator(config.files,
+ config.additional_compile_target_names,
+ config.test_target_names, data,
+ target_list, target_dicts, toplevel_dir,
+ params['build_files'])
+ if not calculator.is_build_impacted():
+ result_dict = { 'status': no_dependency_string,
+ 'test_targets': [],
+ 'compile_targets': [] }
+ if calculator.invalid_targets:
+ result_dict['invalid_targets'] = calculator.invalid_targets
+ _WriteOutput(params, **result_dict)
+ return
+
+ test_target_names = calculator.find_matching_test_target_names()
+ compile_target_names = calculator.find_matching_compile_target_names()
+ found_at_least_one_target = compile_target_names or test_target_names
+ result_dict = { 'test_targets': test_target_names,
+ 'status': found_dependency_string if
+ found_at_least_one_target else no_dependency_string,
+ 'compile_targets': list(
+ set(compile_target_names) |
+ set(test_target_names)) }
+ if calculator.invalid_targets:
+ result_dict['invalid_targets'] = calculator.invalid_targets
+ _WriteOutput(params, **result_dict)
+
+ except Exception as e:
+ _WriteOutput(params, error=str(e))
deleted file mode 100644
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/android.py
+++ /dev/null
@@ -1,1092 +0,0 @@
-# Copyright (c) 2012 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.
-
-# Notes:
-#
-# This generates makefiles suitable for inclusion into the Android build system
-# via an Android.mk file. It is based on make.py, the standard makefile
-# generator.
-#
-# The code below generates a separate .mk file for each target, but
-# all are sourced by the top-level GypAndroid.mk. This means that all
-# variables in .mk-files clobber one another, and furthermore that any
-# variables set potentially clash with other Android build system variables.
-# Try to avoid setting global variables where possible.
-
-import gyp
-import gyp.common
-import gyp.generator.make as make # Reuse global functions from make backend.
-import os
-import re
-
-generator_default_variables = {
- 'OS': 'android',
- 'EXECUTABLE_PREFIX': '',
- 'EXECUTABLE_SUFFIX': '',
- 'STATIC_LIB_PREFIX': 'lib',
- 'SHARED_LIB_PREFIX': 'lib',
- 'STATIC_LIB_SUFFIX': '.a',
- 'SHARED_LIB_SUFFIX': '.so',
- 'INTERMEDIATE_DIR': '$(gyp_intermediate_dir)',
- 'SHARED_INTERMEDIATE_DIR': '$(gyp_shared_intermediate_dir)',
- 'PRODUCT_DIR': '$(gyp_shared_intermediate_dir)',
- 'SHARED_LIB_DIR': '$(builddir)/lib.$(TOOLSET)',
- 'LIB_DIR': '$(obj).$(TOOLSET)',
- 'RULE_INPUT_ROOT': '%(INPUT_ROOT)s', # This gets expanded by Python.
- 'RULE_INPUT_DIRNAME': '%(INPUT_DIRNAME)s', # This gets expanded by Python.
- 'RULE_INPUT_PATH': '$(RULE_SOURCES)',
- 'RULE_INPUT_EXT': '$(suffix $<)',
- 'RULE_INPUT_NAME': '$(notdir $<)',
- 'CONFIGURATION_NAME': 'NOT_USED_ON_ANDROID',
-}
-
-# Make supports multiple toolsets
-generator_supports_multiple_toolsets = True
-
-
-# Generator-specific gyp specs.
-generator_additional_non_configuration_keys = [
- # Boolean to declare that this target does not want its name mangled.
- 'android_unmangled_name',
-]
-generator_additional_path_sections = []
-generator_extra_sources_for_rules = []
-
-
-SHARED_FOOTER = """\
-# "gyp_all_modules" is a concatenation of the "gyp_all_modules" targets from
-# all the included sub-makefiles. This is just here to clarify.
-gyp_all_modules:
-"""
-
-header = """\
-# This file is generated by gyp; do not edit.
-
-"""
-
-android_standard_include_paths = set([
- # JNI_H_INCLUDE in build/core/binary.mk
- 'dalvik/libnativehelper/include/nativehelper',
- # from SRC_HEADERS in build/core/config.mk
- 'system/core/include',
- 'hardware/libhardware/include',
- 'hardware/libhardware_legacy/include',
- 'hardware/ril/include',
- 'dalvik/libnativehelper/include',
- 'frameworks/native/include',
- 'frameworks/native/opengl/include',
- 'frameworks/base/include',
- 'frameworks/base/opengl/include',
- 'frameworks/base/native/include',
- 'external/skia/include',
- # TARGET_C_INCLUDES in build/core/combo/TARGET_linux-arm.mk
- 'bionic/libc/arch-arm/include',
- 'bionic/libc/include',
- 'bionic/libstdc++/include',
- 'bionic/libc/kernel/common',
- 'bionic/libc/kernel/arch-arm',
- 'bionic/libm/include',
- 'bionic/libm/include/arm',
- 'bionic/libthread_db/include',
- ])
-
-
-# Map gyp target types to Android module classes.
-MODULE_CLASSES = {
- 'static_library': 'STATIC_LIBRARIES',
- 'shared_library': 'SHARED_LIBRARIES',
- 'executable': 'EXECUTABLES',
-}
-
-
-def IsCPPExtension(ext):
- return make.COMPILABLE_EXTENSIONS.get(ext) == 'cxx'
-
-
-def Sourceify(path):
- """Convert a path to its source directory form. The Android backend does not
- support options.generator_output, so this function is a noop."""
- return path
-
-
-# Map from qualified target to path to output.
-# For Android, the target of these maps is a tuple ('static', 'modulename'),
-# ('dynamic', 'modulename'), or ('path', 'some/path') instead of a string,
-# since we link by module.
-target_outputs = {}
-# Map from qualified target to any linkable output. A subset
-# of target_outputs. E.g. when mybinary depends on liba, we want to
-# include liba in the linker line; when otherbinary depends on
-# mybinary, we just want to build mybinary first.
-target_link_deps = {}
-
-
-class AndroidMkWriter(object):
- """AndroidMkWriter packages up the writing of one target-specific Android.mk.
-
- Its only real entry point is Write(), and is mostly used for namespacing.
- """
-
- def __init__(self, android_top_dir):
- self.android_top_dir = android_top_dir
-
- def Write(self, qualified_target, base_path, output_filename, spec, configs,
- part_of_all):
- """The main entry point: writes a .mk file for a single target.
-
- Arguments:
- qualified_target: target we're generating
- base_path: path relative to source root we're building in, used to resolve
- target-relative paths
- output_filename: output .mk file name to write
- spec, configs: gyp info
- part_of_all: flag indicating this target is part of 'all'
- """
- make.ensure_directory_exists(output_filename)
-
- self.fp = open(output_filename, 'w')
-
- self.fp.write(header)
-
- self.qualified_target = qualified_target
- self.path = base_path
- self.target = spec['target_name']
- self.type = spec['type']
- self.toolset = spec['toolset']
-
- deps, link_deps = self.ComputeDeps(spec)
-
- # Some of the generation below can add extra output, sources, or
- # link dependencies. All of the out params of the functions that
- # follow use names like extra_foo.
- extra_outputs = []
- extra_sources = []
-
- self.android_class = MODULE_CLASSES.get(self.type, 'NONE')
- self.android_module = self.ComputeAndroidModule(spec)
- (self.android_stem, self.android_suffix) = self.ComputeOutputParts(spec)
- self.output = self.output_binary = self.ComputeOutput(spec)
-
- # Standard header.
- self.WriteLn('include $(CLEAR_VARS)\n')
-
- # Module class and name.
- self.WriteLn('LOCAL_MODULE_CLASS := ' + self.android_class)
- self.WriteLn('LOCAL_MODULE := ' + self.android_module)
- # Only emit LOCAL_MODULE_STEM if it's different to LOCAL_MODULE.
- # The library module classes fail if the stem is set. ComputeOutputParts
- # makes sure that stem == modulename in these cases.
- if self.android_stem != self.android_module:
- self.WriteLn('LOCAL_MODULE_STEM := ' + self.android_stem)
- self.WriteLn('LOCAL_MODULE_SUFFIX := ' + self.android_suffix)
- self.WriteLn('LOCAL_MODULE_TAGS := optional')
- if self.toolset == 'host':
- self.WriteLn('LOCAL_IS_HOST_MODULE := true')
-
- # Grab output directories; needed for Actions and Rules.
- self.WriteLn('gyp_intermediate_dir := $(call local-intermediates-dir)')
- self.WriteLn('gyp_shared_intermediate_dir := '
- '$(call intermediates-dir-for,GYP,shared)')
- self.WriteLn()
-
- # List files this target depends on so that actions/rules/copies/sources
- # can depend on the list.
- # TODO: doesn't pull in things through transitive link deps; needed?
- target_dependencies = [x[1] for x in deps if x[0] == 'path']
- self.WriteLn('# Make sure our deps are built first.')
- self.WriteList(target_dependencies, 'GYP_TARGET_DEPENDENCIES',
- local_pathify=True)
-
- # Actions must come first, since they can generate more OBJs for use below.
- if 'actions' in spec:
- self.WriteActions(spec['actions'], extra_sources, extra_outputs)
-
- # Rules must be early like actions.
- if 'rules' in spec:
- self.WriteRules(spec['rules'], extra_sources, extra_outputs)
-
- if 'copies' in spec:
- self.WriteCopies(spec['copies'], extra_outputs)
-
- # GYP generated outputs.
- self.WriteList(extra_outputs, 'GYP_GENERATED_OUTPUTS', local_pathify=True)
-
- # Set LOCAL_ADDITIONAL_DEPENDENCIES so that Android's build rules depend
- # on both our dependency targets and our generated files.
- self.WriteLn('# Make sure our deps and generated files are built first.')
- self.WriteLn('LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) '
- '$(GYP_GENERATED_OUTPUTS)')
- self.WriteLn()
-
- # Sources.
- if spec.get('sources', []) or extra_sources:
- self.WriteSources(spec, configs, extra_sources)
-
- self.WriteTarget(spec, configs, deps, link_deps, part_of_all)
-
- # Update global list of target outputs, used in dependency tracking.
- target_outputs[qualified_target] = ('path', self.output_binary)
-
- # Update global list of link dependencies.
- if self.type == 'static_library':
- target_link_deps[qualified_target] = ('static', self.android_module)
- elif self.type == 'shared_library':
- target_link_deps[qualified_target] = ('shared', self.android_module)
-
- self.fp.close()
- return self.android_module
-
-
- def WriteActions(self, actions, extra_sources, extra_outputs):
- """Write Makefile code for any 'actions' from the gyp input.
-
- extra_sources: a list that will be filled in with newly generated source
- files, if any
- extra_outputs: a list that will be filled in with any outputs of these
- actions (used to make other pieces dependent on these
- actions)
- """
- for action in actions:
- name = make.StringToMakefileVariable('%s_%s' % (self.qualified_target,
- action['action_name']))
- self.WriteLn('### Rules for action "%s":' % action['action_name'])
- inputs = action['inputs']
- outputs = action['outputs']
-
- # Build up a list of outputs.
- # Collect the output dirs we'll need.
- dirs = set()
- for out in outputs:
- if not out.startswith('$'):
- print ('WARNING: Action for target "%s" writes output to local path '
- '"%s".' % (self.target, out))
- dir = os.path.split(out)[0]
- if dir:
- dirs.add(dir)
- if int(action.get('process_outputs_as_sources', False)):
- extra_sources += outputs
-
- # Prepare the actual command.
- command = gyp.common.EncodePOSIXShellList(action['action'])
- if 'message' in action:
- quiet_cmd = 'Gyp action: %s ($@)' % action['message']
- else:
- quiet_cmd = 'Gyp action: %s ($@)' % name
- if len(dirs) > 0:
- command = 'mkdir -p %s' % ' '.join(dirs) + '; ' + command
-
- cd_action = 'cd $(gyp_local_path)/%s; ' % self.path
- command = cd_action + command
-
- # The makefile rules are all relative to the top dir, but the gyp actions
- # are defined relative to their containing dir. This replaces the gyp_*
- # variables for the action rule with an absolute version so that the
- # output goes in the right place.
- # Only write the gyp_* rules for the "primary" output (:1);
- # it's superfluous for the "extra outputs", and this avoids accidentally
- # writing duplicate dummy rules for those outputs.
- main_output = make.QuoteSpaces(self.LocalPathify(outputs[0]))
- self.WriteLn('%s: gyp_local_path := $(LOCAL_PATH)' % main_output)
- self.WriteLn('%s: gyp_intermediate_dir := '
- '$(GYP_ABS_ANDROID_TOP_DIR)/$(gyp_intermediate_dir)' %
- main_output)
- self.WriteLn('%s: gyp_shared_intermediate_dir := '
- '$(GYP_ABS_ANDROID_TOP_DIR)/$(gyp_shared_intermediate_dir)' %
- main_output)
-
- for input in inputs:
- assert ' ' not in input, (
- "Spaces in action input filenames not supported (%s)" % input)
- for output in outputs:
- assert ' ' not in output, (
- "Spaces in action output filenames not supported (%s)" % output)
-
- self.WriteLn('%s: %s $(GYP_TARGET_DEPENDENCIES)' %
- (main_output, ' '.join(map(self.LocalPathify, inputs))))
- self.WriteLn('\t@echo "%s"' % quiet_cmd)
- self.WriteLn('\t$(hide)%s\n' % command)
- for output in outputs[1:]:
- # Make each output depend on the main output, with an empty command
- # to force make to notice that the mtime has changed.
- self.WriteLn('%s: %s ;' % (self.LocalPathify(output), main_output))
-
- extra_outputs += outputs
- self.WriteLn()
-
- self.WriteLn()
-
-
- def WriteRules(self, rules, extra_sources, extra_outputs):
- """Write Makefile code for any 'rules' from the gyp input.
-
- extra_sources: a list that will be filled in with newly generated source
- files, if any
- extra_outputs: a list that will be filled in with any outputs of these
- rules (used to make other pieces dependent on these rules)
- """
- if len(rules) == 0:
- return
- rule_trigger = '%s_rule_trigger' % self.android_module
-
- did_write_rule = False
- for rule in rules:
- if len(rule.get('rule_sources', [])) == 0:
- continue
- did_write_rule = True
- name = make.StringToMakefileVariable('%s_%s' % (self.qualified_target,
- rule['rule_name']))
- self.WriteLn('\n### Generated for rule "%s":' % name)
- self.WriteLn('# "%s":' % rule)
-
- inputs = rule.get('inputs')
- for rule_source in rule.get('rule_sources', []):
- (rule_source_dirname, rule_source_basename) = os.path.split(rule_source)
- (rule_source_root, rule_source_ext) = \
- os.path.splitext(rule_source_basename)
-
- outputs = [self.ExpandInputRoot(out, rule_source_root,
- rule_source_dirname)
- for out in rule['outputs']]
-
- dirs = set()
- for out in outputs:
- if not out.startswith('$'):
- print ('WARNING: Rule for target %s writes output to local path %s'
- % (self.target, out))
- dir = os.path.dirname(out)
- if dir:
- dirs.add(dir)
- extra_outputs += outputs
- if int(rule.get('process_outputs_as_sources', False)):
- extra_sources.extend(outputs)
-
- components = []
- for component in rule['action']:
- component = self.ExpandInputRoot(component, rule_source_root,
- rule_source_dirname)
- if '$(RULE_SOURCES)' in component:
- component = component.replace('$(RULE_SOURCES)',
- rule_source)
- components.append(component)
-
- command = gyp.common.EncodePOSIXShellList(components)
- cd_action = 'cd $(gyp_local_path)/%s; ' % self.path
- command = cd_action + command
- if dirs:
- command = 'mkdir -p %s' % ' '.join(dirs) + '; ' + command
-
- # We set up a rule to build the first output, and then set up
- # a rule for each additional output to depend on the first.
- outputs = map(self.LocalPathify, outputs)
- main_output = outputs[0]
- self.WriteLn('%s: gyp_local_path := $(LOCAL_PATH)' % main_output)
- self.WriteLn('%s: gyp_intermediate_dir := '
- '$(GYP_ABS_ANDROID_TOP_DIR)/$(gyp_intermediate_dir)'
- % main_output)
- self.WriteLn('%s: gyp_shared_intermediate_dir := '
- '$(GYP_ABS_ANDROID_TOP_DIR)/$(gyp_shared_intermediate_dir)'
- % main_output)
-
- main_output_deps = self.LocalPathify(rule_source)
- if inputs:
- main_output_deps += ' '
- main_output_deps += ' '.join([self.LocalPathify(f) for f in inputs])
-
- self.WriteLn('%s: %s $(GYP_TARGET_DEPENDENCIES)' %
- (main_output, main_output_deps))
- self.WriteLn('\t%s\n' % command)
- for output in outputs[1:]:
- self.WriteLn('%s: %s' % (output, main_output))
- self.WriteLn('.PHONY: %s' % (rule_trigger))
- self.WriteLn('%s: %s' % (rule_trigger, main_output))
- self.WriteLn('')
- if did_write_rule:
- extra_sources.append(rule_trigger) # Force all rules to run.
- self.WriteLn('### Finished generating for all rules')
- self.WriteLn('')
-
-
- def WriteCopies(self, copies, extra_outputs):
- """Write Makefile code for any 'copies' from the gyp input.
-
- extra_outputs: a list that will be filled in with any outputs of this action
- (used to make other pieces dependent on this action)
- """
- self.WriteLn('### Generated for copy rule.')
-
- variable = make.StringToMakefileVariable(self.qualified_target + '_copies')
- outputs = []
- for copy in copies:
- for path in copy['files']:
- # The Android build system does not allow generation of files into the
- # source tree. The destination should start with a variable, which will
- # typically be $(gyp_intermediate_dir) or
- # $(gyp_shared_intermediate_dir). Note that we can't use an assertion
- # because some of the gyp tests depend on this.
- if not copy['destination'].startswith('$'):
- print ('WARNING: Copy rule for target %s writes output to '
- 'local path %s' % (self.target, copy['destination']))
-
- # LocalPathify() calls normpath, stripping trailing slashes.
- path = Sourceify(self.LocalPathify(path))
- filename = os.path.split(path)[1]
- output = Sourceify(self.LocalPathify(os.path.join(copy['destination'],
- filename)))
-
- self.WriteLn('%s: %s $(GYP_TARGET_DEPENDENCIES) | $(ACP)' %
- (output, path))
- self.WriteLn('\t@echo Copying: $@')
- self.WriteLn('\t$(hide) mkdir -p $(dir $@)')
- self.WriteLn('\t$(hide) $(ACP) -r $< $@')
- self.WriteLn()
- outputs.append(output)
- self.WriteLn('%s = %s' % (variable,
- ' '.join(map(make.QuoteSpaces, outputs))))
- extra_outputs.append('$(%s)' % variable)
- self.WriteLn()
-
-
- def WriteSourceFlags(self, spec, configs):
- """Write out the flags and include paths used to compile source files for
- the current target.
-
- Args:
- spec, configs: input from gyp.
- """
- config = configs[spec['default_configuration']]
- extracted_includes = []
-
- self.WriteLn('\n# Flags passed to both C and C++ files.')
- cflags, includes_from_cflags = self.ExtractIncludesFromCFlags(
- config.get('cflags'))
- extracted_includes.extend(includes_from_cflags)
- self.WriteList(cflags, 'MY_CFLAGS')
-
- cflags_c, includes_from_cflags_c = self.ExtractIncludesFromCFlags(
- config.get('cflags_c'))
- extracted_includes.extend(includes_from_cflags_c)
- self.WriteList(cflags_c, 'MY_CFLAGS_C')
-
- self.WriteList(config.get('defines'), 'MY_DEFS', prefix='-D',
- quoter=make.EscapeCppDefine)
- self.WriteLn('LOCAL_CFLAGS := $(MY_CFLAGS_C) $(MY_CFLAGS) $(MY_DEFS)')
-
- # Undefine ANDROID for host modules
- # TODO: the source code should not use macro ANDROID to tell if it's host or
- # target module.
- if self.toolset == 'host':
- self.WriteLn('# Undefine ANDROID for host modules')
- self.WriteLn('LOCAL_CFLAGS += -UANDROID')
-
- self.WriteLn('\n# Include paths placed before CFLAGS/CPPFLAGS')
- includes = list(config.get('include_dirs', []))
- includes.extend(extracted_includes)
- includes = map(Sourceify, map(self.LocalPathify, includes))
- includes = self.NormalizeIncludePaths(includes)
- self.WriteList(includes, 'LOCAL_C_INCLUDES')
- self.WriteLn('LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) '
- '$(LOCAL_C_INCLUDES)')
-
- self.WriteLn('\n# Flags passed to only C++ (and not C) files.')
- self.WriteList(config.get('cflags_cc'), 'LOCAL_CPPFLAGS')
-
-
- def WriteSources(self, spec, configs, extra_sources):
- """Write Makefile code for any 'sources' from the gyp input.
- These are source files necessary to build the current target.
- We need to handle shared_intermediate directory source files as
- a special case by copying them to the intermediate directory and
- treating them as a genereated sources. Otherwise the Android build
- rules won't pick them up.
-
- Args:
- spec, configs: input from gyp.
- extra_sources: Sources generated from Actions or Rules.
- """
- sources = filter(make.Compilable, spec.get('sources', []))
- generated_not_sources = [x for x in extra_sources if not make.Compilable(x)]
- extra_sources = filter(make.Compilable, extra_sources)
-
- # Determine and output the C++ extension used by these sources.
- # We simply find the first C++ file and use that extension.
- all_sources = sources + extra_sources
- local_cpp_extension = '.cpp'
- for source in all_sources:
- (root, ext) = os.path.splitext(source)
- if IsCPPExtension(ext):
- local_cpp_extension = ext
- break
- if local_cpp_extension != '.cpp':
- self.WriteLn('LOCAL_CPP_EXTENSION := %s' % local_cpp_extension)
-
- # We need to move any non-generated sources that are coming from the
- # shared intermediate directory out of LOCAL_SRC_FILES and put them
- # into LOCAL_GENERATED_SOURCES. We also need to move over any C++ files
- # that don't match our local_cpp_extension, since Android will only
- # generate Makefile rules for a single LOCAL_CPP_EXTENSION.
- local_files = []
- for source in sources:
- (root, ext) = os.path.splitext(source)
- if '$(gyp_shared_intermediate_dir)' in source:
- extra_sources.append(source)
- elif '$(gyp_intermediate_dir)' in source:
- extra_sources.append(source)
- elif IsCPPExtension(ext) and ext != local_cpp_extension:
- extra_sources.append(source)
- else:
- local_files.append(os.path.normpath(os.path.join(self.path, source)))
-
- # For any generated source, if it is coming from the shared intermediate
- # directory then we add a Make rule to copy them to the local intermediate
- # directory first. This is because the Android LOCAL_GENERATED_SOURCES
- # must be in the local module intermediate directory for the compile rules
- # to work properly. If the file has the wrong C++ extension, then we add
- # a rule to copy that to intermediates and use the new version.
- final_generated_sources = []
- # If a source file gets copied, we still need to add the orginal source
- # directory as header search path, for GCC searches headers in the
- # directory that contains the source file by default.
- origin_src_dirs = []
- for source in extra_sources:
- local_file = source
- if not '$(gyp_intermediate_dir)/' in local_file:
- basename = os.path.basename(local_file)
- local_file = '$(gyp_intermediate_dir)/' + basename
- (root, ext) = os.path.splitext(local_file)
- if IsCPPExtension(ext) and ext != local_cpp_extension:
- local_file = root + local_cpp_extension
- if local_file != source:
- self.WriteLn('%s: %s' % (local_file, self.LocalPathify(source)))
- self.WriteLn('\tmkdir -p $(@D); cp $< $@')
- origin_src_dirs.append(os.path.dirname(source))
- final_generated_sources.append(local_file)
-
- # We add back in all of the non-compilable stuff to make sure that the
- # make rules have dependencies on them.
- final_generated_sources.extend(generated_not_sources)
- self.WriteList(final_generated_sources, 'LOCAL_GENERATED_SOURCES')
-
- origin_src_dirs = gyp.common.uniquer(origin_src_dirs)
- origin_src_dirs = map(Sourceify, map(self.LocalPathify, origin_src_dirs))
- self.WriteList(origin_src_dirs, 'GYP_COPIED_SOURCE_ORIGIN_DIRS')
-
- self.WriteList(local_files, 'LOCAL_SRC_FILES')
-
- # Write out the flags used to compile the source; this must be done last
- # so that GYP_COPIED_SOURCE_ORIGIN_DIRS can be used as an include path.
- self.WriteSourceFlags(spec, configs)
-
-
- def ComputeAndroidModule(self, spec):
- """Return the Android module name used for a gyp spec.
-
- We use the complete qualified target name to avoid collisions between
- duplicate targets in different directories. We also add a suffix to
- distinguish gyp-generated module names.
- """
-
- if int(spec.get('android_unmangled_name', 0)):
- assert self.type != 'shared_library' or self.target.startswith('lib')
- return self.target
-
- if self.type == 'shared_library':
- # For reasons of convention, the Android build system requires that all
- # shared library modules are named 'libfoo' when generating -l flags.
- prefix = 'lib_'
- else:
- prefix = ''
-
- if spec['toolset'] == 'host':
- suffix = '_host_gyp'
- else:
- suffix = '_gyp'
-
- if self.path:
- name = '%s%s_%s%s' % (prefix, self.path, self.target, suffix)
- else:
- name = '%s%s%s' % (prefix, self.target, suffix)
-
- return make.StringToMakefileVariable(name)
-
-
- def ComputeOutputParts(self, spec):
- """Return the 'output basename' of a gyp spec, split into filename + ext.
-
- Android libraries must be named the same thing as their module name,
- otherwise the linker can't find them, so product_name and so on must be
- ignored if we are building a library, and the "lib" prepending is
- not done for Android.
- """
- assert self.type != 'loadable_module' # TODO: not supported?
-
- target = spec['target_name']
- target_prefix = ''
- target_ext = ''
- if self.type == 'static_library':
- target = self.ComputeAndroidModule(spec)
- target_ext = '.a'
- elif self.type == 'shared_library':
- target = self.ComputeAndroidModule(spec)
- target_ext = '.so'
- elif self.type == 'none':
- target_ext = '.stamp'
- elif self.type != 'executable':
- print ("ERROR: What output file should be generated?",
- "type", self.type, "target", target)
-
- if self.type != 'static_library' and self.type != 'shared_library':
- target_prefix = spec.get('product_prefix', target_prefix)
- target = spec.get('product_name', target)
- product_ext = spec.get('product_extension')
- if product_ext:
- target_ext = '.' + product_ext
-
- target_stem = target_prefix + target
- return (target_stem, target_ext)
-
-
- def ComputeOutputBasename(self, spec):
- """Return the 'output basename' of a gyp spec.
-
- E.g., the loadable module 'foobar' in directory 'baz' will produce
- 'libfoobar.so'
- """
- return ''.join(self.ComputeOutputParts(spec))
-
-
- def ComputeOutput(self, spec):
- """Return the 'output' (full output path) of a gyp spec.
-
- E.g., the loadable module 'foobar' in directory 'baz' will produce
- '$(obj)/baz/libfoobar.so'
- """
- if self.type == 'executable' and self.toolset == 'host':
- # We install host executables into shared_intermediate_dir so they can be
- # run by gyp rules that refer to PRODUCT_DIR.
- path = '$(gyp_shared_intermediate_dir)'
- elif self.type == 'shared_library':
- if self.toolset == 'host':
- path = '$(HOST_OUT_INTERMEDIATE_LIBRARIES)'
- else:
- path = '$(TARGET_OUT_INTERMEDIATE_LIBRARIES)'
- else:
- # Other targets just get built into their intermediate dir.
- if self.toolset == 'host':
- path = '$(call intermediates-dir-for,%s,%s,true)' % (self.android_class,
- self.android_module)
- else:
- path = '$(call intermediates-dir-for,%s,%s)' % (self.android_class,
- self.android_module)
-
- assert spec.get('product_dir') is None # TODO: not supported?
- return os.path.join(path, self.ComputeOutputBasename(spec))
-
-
- def NormalizeLdFlags(self, ld_flags):
- """ Clean up ldflags from gyp file.
- Remove any ldflags that contain android_top_dir.
-
- Args:
- ld_flags: ldflags from gyp files.
-
- Returns:
- clean ldflags
- """
- clean_ldflags = []
- for flag in ld_flags:
- if self.android_top_dir in flag:
- continue
- clean_ldflags.append(flag)
- return clean_ldflags
-
- def NormalizeIncludePaths(self, include_paths):
- """ Normalize include_paths.
- Convert absolute paths to relative to the Android top directory;
- filter out include paths that are already brought in by the Android build
- system.
-
- Args:
- include_paths: A list of unprocessed include paths.
- Returns:
- A list of normalized include paths.
- """
- normalized = []
- for path in include_paths:
- if path[0] == '/':
- path = gyp.common.RelativePath(path, self.android_top_dir)
-
- # Filter out the Android standard search path.
- if path not in android_standard_include_paths:
- normalized.append(path)
- return normalized
-
- def ExtractIncludesFromCFlags(self, cflags):
- """Extract includes "-I..." out from cflags
-
- Args:
- cflags: A list of compiler flags, which may be mixed with "-I.."
- Returns:
- A tuple of lists: (clean_clfags, include_paths). "-I.." is trimmed.
- """
- clean_cflags = []
- include_paths = []
- if cflags:
- for flag in cflags:
- if flag.startswith('-I'):
- include_paths.append(flag[2:])
- else:
- clean_cflags.append(flag)
-
- return (clean_cflags, include_paths)
-
- def ComputeAndroidLibraryModuleNames(self, libraries):
- """Compute the Android module names from libraries, ie spec.get('libraries')
-
- Args:
- libraries: the value of spec.get('libraries')
- Returns:
- A tuple (static_lib_modules, dynamic_lib_modules)
- """
- static_lib_modules = []
- dynamic_lib_modules = []
- for libs in libraries:
- # Libs can have multiple words.
- for lib in libs.split():
- # Filter the system libraries, which are added by default by the Android
- # build system.
- if (lib == '-lc' or lib == '-lstdc++' or lib == '-lm' or
- lib.endswith('libgcc.a')):
- continue
- match = re.search(r'([^/]+)\.a$', lib)
- if match:
- static_lib_modules.append(match.group(1))
- continue
- match = re.search(r'([^/]+)\.so$', lib)
- if match:
- dynamic_lib_modules.append(match.group(1))
- continue
- # "-lstlport" -> libstlport
- if lib.startswith('-l'):
- if lib.endswith('_static'):
- static_lib_modules.append('lib' + lib[2:])
- else:
- dynamic_lib_modules.append('lib' + lib[2:])
- return (static_lib_modules, dynamic_lib_modules)
-
-
- def ComputeDeps(self, spec):
- """Compute the dependencies of a gyp spec.
-
- Returns a tuple (deps, link_deps), where each is a list of
- filenames that will need to be put in front of make for either
- building (deps) or linking (link_deps).
- """
- deps = []
- link_deps = []
- if 'dependencies' in spec:
- deps.extend([target_outputs[dep] for dep in spec['dependencies']
- if target_outputs[dep]])
- for dep in spec['dependencies']:
- if dep in target_link_deps:
- link_deps.append(target_link_deps[dep])
- deps.extend(link_deps)
- return (gyp.common.uniquer(deps), gyp.common.uniquer(link_deps))
-
-
- def WriteTargetFlags(self, spec, configs, link_deps):
- """Write Makefile code to specify the link flags and library dependencies.
-
- spec, configs: input from gyp.
- link_deps: link dependency list; see ComputeDeps()
- """
- config = configs[spec['default_configuration']]
-
- # LDFLAGS
- ldflags = list(config.get('ldflags', []))
- static_flags, dynamic_flags = self.ComputeAndroidLibraryModuleNames(
- ldflags)
- self.WriteLn('')
- self.WriteList(self.NormalizeLdFlags(ldflags), 'LOCAL_LDFLAGS')
-
- # Libraries (i.e. -lfoo)
- libraries = gyp.common.uniquer(spec.get('libraries', []))
- static_libs, dynamic_libs = self.ComputeAndroidLibraryModuleNames(
- libraries)
-
- # Link dependencies (i.e. libfoo.a, libfoo.so)
- static_link_deps = [x[1] for x in link_deps if x[0] == 'static']
- shared_link_deps = [x[1] for x in link_deps if x[0] == 'shared']
- self.WriteLn('')
- self.WriteList(static_flags + static_libs + static_link_deps,
- 'LOCAL_STATIC_LIBRARIES')
- self.WriteLn('# Enable grouping to fix circular references')
- self.WriteLn('LOCAL_GROUP_STATIC_LIBRARIES := true')
- self.WriteLn('')
- self.WriteList(dynamic_flags + dynamic_libs + shared_link_deps,
- 'LOCAL_SHARED_LIBRARIES')
-
-
- def WriteTarget(self, spec, configs, deps, link_deps, part_of_all):
- """Write Makefile code to produce the final target of the gyp spec.
-
- spec, configs: input from gyp.
- deps, link_deps: dependency lists; see ComputeDeps()
- part_of_all: flag indicating this target is part of 'all'
- """
- self.WriteLn('### Rules for final target.')
-
- if self.type != 'none':
- self.WriteTargetFlags(spec, configs, link_deps)
-
- # Add to the set of targets which represent the gyp 'all' target. We use the
- # name 'gyp_all_modules' as the Android build system doesn't allow the use
- # of the Make target 'all' and because 'all_modules' is the equivalent of
- # the Make target 'all' on Android.
- if part_of_all:
- self.WriteLn('# Add target alias to "gyp_all_modules" target.')
- self.WriteLn('.PHONY: gyp_all_modules')
- self.WriteLn('gyp_all_modules: %s' % self.android_module)
- self.WriteLn('')
-
- # Add an alias from the gyp target name to the Android module name. This
- # simplifies manual builds of the target, and is required by the test
- # framework.
- if self.target != self.android_module:
- self.WriteLn('# Alias gyp target name.')
- self.WriteLn('.PHONY: %s' % self.target)
- self.WriteLn('%s: %s' % (self.target, self.android_module))
- self.WriteLn('')
-
- # Add the command to trigger build of the target type depending
- # on the toolset. Ex: BUILD_STATIC_LIBRARY vs. BUILD_HOST_STATIC_LIBRARY
- # NOTE: This has to come last!
- modifier = ''
- if self.toolset == 'host':
- modifier = 'HOST_'
- if self.type == 'static_library':
- self.WriteLn('include $(BUILD_%sSTATIC_LIBRARY)' % modifier)
- elif self.type == 'shared_library':
- self.WriteLn('LOCAL_PRELINK_MODULE := false')
- self.WriteLn('include $(BUILD_%sSHARED_LIBRARY)' % modifier)
- elif self.type == 'executable':
- if self.toolset == 'host':
- self.WriteLn('LOCAL_MODULE_PATH := $(gyp_shared_intermediate_dir)')
- else:
- # Don't install target executables for now, as it results in them being
- # included in ROM. This can be revisited if there's a reason to install
- # them later.
- self.WriteLn('LOCAL_UNINSTALLABLE_MODULE := true')
- self.WriteLn('include $(BUILD_%sEXECUTABLE)' % modifier)
- else:
- self.WriteLn('LOCAL_MODULE_PATH := $(PRODUCT_OUT)/gyp_stamp')
- self.WriteLn('LOCAL_UNINSTALLABLE_MODULE := true')
- self.WriteLn()
- self.WriteLn('include $(BUILD_SYSTEM)/base_rules.mk')
- self.WriteLn()
- self.WriteLn('$(LOCAL_BUILT_MODULE): $(LOCAL_ADDITIONAL_DEPENDENCIES)')
- self.WriteLn('\t$(hide) echo "Gyp timestamp: $@"')
- self.WriteLn('\t$(hide) mkdir -p $(dir $@)')
- self.WriteLn('\t$(hide) touch $@')
-
-
- def WriteList(self, value_list, variable=None, prefix='',
- quoter=make.QuoteIfNecessary, local_pathify=False):
- """Write a variable definition that is a list of values.
-
- E.g. WriteList(['a','b'], 'foo', prefix='blah') writes out
- foo = blaha blahb
- but in a pretty-printed style.
- """
- values = ''
- if value_list:
- value_list = [quoter(prefix + l) for l in value_list]
- if local_pathify:
- value_list = [self.LocalPathify(l) for l in value_list]
- values = ' \\\n\t' + ' \\\n\t'.join(value_list)
- self.fp.write('%s :=%s\n\n' % (variable, values))
-
-
- def WriteLn(self, text=''):
- self.fp.write(text + '\n')
-
-
- def LocalPathify(self, path):
- """Convert a subdirectory-relative path into a normalized path which starts
- with the make variable $(LOCAL_PATH) (i.e. the top of the project tree).
- Absolute paths, or paths that contain variables, are just normalized."""
- if '$(' in path or os.path.isabs(path):
- # path is not a file in the project tree in this case, but calling
- # normpath is still important for trimming trailing slashes.
- return os.path.normpath(path)
- local_path = os.path.join('$(LOCAL_PATH)', self.path, path)
- local_path = os.path.normpath(local_path)
- # Check that normalizing the path didn't ../ itself out of $(LOCAL_PATH)
- # - i.e. that the resulting path is still inside the project tree. The
- # path may legitimately have ended up containing just $(LOCAL_PATH), though,
- # so we don't look for a slash.
- assert local_path.startswith('$(LOCAL_PATH)'), (
- 'Path %s attempts to escape from gyp path %s !)' % (path, self.path))
- return local_path
-
-
- def ExpandInputRoot(self, template, expansion, dirname):
- if '%(INPUT_ROOT)s' not in template and '%(INPUT_DIRNAME)s' not in template:
- return template
- path = template % {
- 'INPUT_ROOT': expansion,
- 'INPUT_DIRNAME': dirname,
- }
- return path
-
-
-def WriteAutoRegenerationRule(params, root_makefile, makefile_name,
- build_files):
- """Write the target to regenerate the Makefile."""
- options = params['options']
- # Sort to avoid non-functional changes to makefile.
- build_files = sorted([os.path.join('$(LOCAL_PATH)', f) for f in build_files])
- build_files_args = [gyp.common.RelativePath(filename, options.toplevel_dir)
- for filename in params['build_files_arg']]
- build_files_args = [os.path.join('$(PRIVATE_LOCAL_PATH)', f)
- for f in build_files_args]
- gyp_binary = gyp.common.FixIfRelativePath(params['gyp_binary'],
- options.toplevel_dir)
- makefile_path = os.path.join('$(LOCAL_PATH)', makefile_name)
- if not gyp_binary.startswith(os.sep):
- gyp_binary = os.path.join('.', gyp_binary)
- root_makefile.write('GYP_FILES := \\\n %s\n\n' %
- '\\\n '.join(map(Sourceify, build_files)))
- root_makefile.write('%s: PRIVATE_LOCAL_PATH := $(LOCAL_PATH)\n' %
- makefile_path)
- root_makefile.write('%s: $(GYP_FILES)\n' % makefile_path)
- root_makefile.write('\techo ACTION Regenerating $@\n\t%s\n\n' %
- gyp.common.EncodePOSIXShellList([gyp_binary, '-fandroid'] +
- gyp.RegenerateFlags(options) +
- build_files_args))
-
-
-def GenerateOutput(target_list, target_dicts, data, params):
- options = params['options']
- generator_flags = params.get('generator_flags', {})
- builddir_name = generator_flags.get('output_dir', 'out')
- limit_to_target_all = generator_flags.get('limit_to_target_all', False)
- android_top_dir = os.environ.get('ANDROID_BUILD_TOP')
- assert android_top_dir, '$ANDROID_BUILD_TOP not set; you need to run lunch.'
-
- def CalculateMakefilePath(build_file, base_name):
- """Determine where to write a Makefile for a given gyp file."""
- # Paths in gyp files are relative to the .gyp file, but we want
- # paths relative to the source root for the master makefile. Grab
- # the path of the .gyp file as the base to relativize against.
- # E.g. "foo/bar" when we're constructing targets for "foo/bar/baz.gyp".
- base_path = gyp.common.RelativePath(os.path.dirname(build_file),
- options.depth)
- # We write the file in the base_path directory.
- output_file = os.path.join(options.depth, base_path, base_name)
- assert not options.generator_output, (
- 'The Android backend does not support options.generator_output.')
- base_path = gyp.common.RelativePath(os.path.dirname(build_file),
- options.toplevel_dir)
- return base_path, output_file
-
- # TODO: search for the first non-'Default' target. This can go
- # away when we add verification that all targets have the
- # necessary configurations.
- default_configuration = None
- toolsets = set([target_dicts[target]['toolset'] for target in target_list])
- for target in target_list:
- spec = target_dicts[target]
- if spec['default_configuration'] != 'Default':
- default_configuration = spec['default_configuration']
- break
- if not default_configuration:
- default_configuration = 'Default'
-
- srcdir = '.'
- makefile_name = 'GypAndroid.mk' + options.suffix
- makefile_path = os.path.join(options.toplevel_dir, makefile_name)
- assert not options.generator_output, (
- 'The Android backend does not support options.generator_output.')
- make.ensure_directory_exists(makefile_path)
- root_makefile = open(makefile_path, 'w')
-
- root_makefile.write(header)
-
- # We set LOCAL_PATH just once, here, to the top of the project tree. This
- # allows all the other paths we use to be relative to the Android.mk file,
- # as the Android build system expects.
- root_makefile.write('\nLOCAL_PATH := $(call my-dir)\n')
-
- # Find the list of targets that derive from the gyp file(s) being built.
- needed_targets = set()
- for build_file in params['build_files']:
- for target in gyp.common.AllTargets(target_list, target_dicts, build_file):
- needed_targets.add(target)
-
- build_files = set()
- include_list = set()
- android_modules = {}
- for qualified_target in target_list:
- build_file, target, toolset = gyp.common.ParseQualifiedTarget(
- qualified_target)
- build_files.add(gyp.common.RelativePath(build_file, options.toplevel_dir))
- included_files = data[build_file]['included_files']
- for included_file in included_files:
- # The included_files entries are relative to the dir of the build file
- # that included them, so we have to undo that and then make them relative
- # to the root dir.
- relative_include_file = gyp.common.RelativePath(
- gyp.common.UnrelativePath(included_file, build_file),
- options.toplevel_dir)
- abs_include_file = os.path.abspath(relative_include_file)
- # If the include file is from the ~/.gyp dir, we should use absolute path
- # so that relocating the src dir doesn't break the path.
- if (params['home_dot_gyp'] and
- abs_include_file.startswith(params['home_dot_gyp'])):
- build_files.add(abs_include_file)
- else:
- build_files.add(relative_include_file)
-
- base_path, output_file = CalculateMakefilePath(build_file,
- target + '.' + toolset + options.suffix + '.mk')
-
- spec = target_dicts[qualified_target]
- configs = spec['configurations']
-
- part_of_all = (qualified_target in needed_targets and
- not int(spec.get('suppress_wildcard', False)))
- if limit_to_target_all and not part_of_all:
- continue
- writer = AndroidMkWriter(android_top_dir)
- android_module = writer.Write(qualified_target, base_path, output_file,
- spec, configs, part_of_all=part_of_all)
- if android_module in android_modules:
- print ('ERROR: Android module names must be unique. The following '
- 'targets both generate Android module name %s.\n %s\n %s' %
- (android_module, android_modules[android_module],
- qualified_target))
- return
- android_modules[android_module] = qualified_target
-
- # Our root_makefile lives at the source root. Compute the relative path
- # from there to the output_file for including.
- mkfile_rel_path = gyp.common.RelativePath(output_file,
- os.path.dirname(makefile_path))
- include_list.add(mkfile_rel_path)
-
- # Some tools need to know the absolute path of the top directory.
- root_makefile.write('GYP_ABS_ANDROID_TOP_DIR := $(shell pwd)\n')
-
- # Write out the sorted list of includes.
- root_makefile.write('\n')
- for include_file in sorted(include_list):
- root_makefile.write('include $(LOCAL_PATH)/' + include_file + '\n')
- root_makefile.write('\n')
-
- if generator_flags.get('auto_regeneration', True):
- WriteAutoRegenerationRule(params, root_makefile, makefile_name, build_files)
-
- root_makefile.write(SHARED_FOOTER)
-
- root_makefile.close()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/cmake.py
@@ -0,0 +1,1248 @@
+# Copyright (c) 2013 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.
+
+"""cmake output module
+
+This module is under development and should be considered experimental.
+
+This module produces cmake (2.8.8+) input as its output. One CMakeLists.txt is
+created for each configuration.
+
+This module's original purpose was to support editing in IDEs like KDevelop
+which use CMake for project management. It is also possible to use CMake to
+generate projects for other IDEs such as eclipse cdt and code::blocks. QtCreator
+will convert the CMakeLists.txt to a code::blocks cbp for the editor to read,
+but build using CMake. As a result QtCreator editor is unaware of compiler
+defines. The generated CMakeLists.txt can also be used to build on Linux. There
+is currently no support for building on platforms other than Linux.
+
+The generated CMakeLists.txt should properly compile all projects. However,
+there is a mismatch between gyp and cmake with regard to linking. All attempts
+are made to work around this, but CMake sometimes sees -Wl,--start-group as a
+library and incorrectly repeats it. As a result the output of this generator
+should not be relied on for building.
+
+When using with kdevelop, use version 4.4+. Previous versions of kdevelop will
+not be able to find the header file directories described in the generated
+CMakeLists.txt file.
+"""
+
+import multiprocessing
+import os
+import signal
+import string
+import subprocess
+import gyp.common
+import gyp.xcode_emulation
+
+generator_default_variables = {
+ 'EXECUTABLE_PREFIX': '',
+ 'EXECUTABLE_SUFFIX': '',
+ 'STATIC_LIB_PREFIX': 'lib',
+ 'STATIC_LIB_SUFFIX': '.a',
+ 'SHARED_LIB_PREFIX': 'lib',
+ 'SHARED_LIB_SUFFIX': '.so',
+ 'SHARED_LIB_DIR': '${builddir}/lib.${TOOLSET}',
+ 'LIB_DIR': '${obj}.${TOOLSET}',
+ 'INTERMEDIATE_DIR': '${obj}.${TOOLSET}/${TARGET}/geni',
+ 'SHARED_INTERMEDIATE_DIR': '${obj}/gen',
+ 'PRODUCT_DIR': '${builddir}',
+ 'RULE_INPUT_PATH': '${RULE_INPUT_PATH}',
+ 'RULE_INPUT_DIRNAME': '${RULE_INPUT_DIRNAME}',
+ 'RULE_INPUT_NAME': '${RULE_INPUT_NAME}',
+ 'RULE_INPUT_ROOT': '${RULE_INPUT_ROOT}',
+ 'RULE_INPUT_EXT': '${RULE_INPUT_EXT}',
+ 'CONFIGURATION_NAME': '${configuration}',
+}
+
+FULL_PATH_VARS = ('${CMAKE_CURRENT_LIST_DIR}', '${builddir}', '${obj}')
+
+generator_supports_multiple_toolsets = True
+generator_wants_static_library_dependencies_adjusted = True
+
+COMPILABLE_EXTENSIONS = {
+ '.c': 'cc',
+ '.cc': 'cxx',
+ '.cpp': 'cxx',
+ '.cxx': 'cxx',
+ '.s': 's', # cc
+ '.S': 's', # cc
+}
+
+
+def RemovePrefix(a, prefix):
+ """Returns 'a' without 'prefix' if it starts with 'prefix'."""
+ return a[len(prefix):] if a.startswith(prefix) else a
+
+
+def CalculateVariables(default_variables, params):
+ """Calculate additional variables for use in the build (called by gyp)."""
+ default_variables.setdefault('OS', gyp.common.GetFlavor(params))
+
+
+def Compilable(filename):
+ """Return true if the file is compilable (should be in OBJS)."""
+ return any(filename.endswith(e) for e in COMPILABLE_EXTENSIONS)
+
+
+def Linkable(filename):
+ """Return true if the file is linkable (should be on the link line)."""
+ return filename.endswith('.o')
+
+
+def NormjoinPathForceCMakeSource(base_path, rel_path):
+ """Resolves rel_path against base_path and returns the result.
+
+ If rel_path is an absolute path it is returned unchanged.
+ Otherwise it is resolved against base_path and normalized.
+ If the result is a relative path, it is forced to be relative to the
+ CMakeLists.txt.
+ """
+ if os.path.isabs(rel_path):
+ return rel_path
+ if any([rel_path.startswith(var) for var in FULL_PATH_VARS]):
+ return rel_path
+ # TODO: do we need to check base_path for absolute variables as well?
+ return os.path.join('${CMAKE_CURRENT_LIST_DIR}',
+ os.path.normpath(os.path.join(base_path, rel_path)))
+
+
+def NormjoinPath(base_path, rel_path):
+ """Resolves rel_path against base_path and returns the result.
+ TODO: what is this really used for?
+ If rel_path begins with '$' it is returned unchanged.
+ Otherwise it is resolved against base_path if relative, then normalized.
+ """
+ if rel_path.startswith('$') and not rel_path.startswith('${configuration}'):
+ return rel_path
+ return os.path.normpath(os.path.join(base_path, rel_path))
+
+
+def CMakeStringEscape(a):
+ """Escapes the string 'a' for use inside a CMake string.
+
+ This means escaping
+ '\' otherwise it may be seen as modifying the next character
+ '"' otherwise it will end the string
+ ';' otherwise the string becomes a list
+
+ The following do not need to be escaped
+ '#' when the lexer is in string state, this does not start a comment
+
+ The following are yet unknown
+ '$' generator variables (like ${obj}) must not be escaped,
+ but text $ should be escaped
+ what is wanted is to know which $ come from generator variables
+ """
+ return a.replace('\\', '\\\\').replace(';', '\\;').replace('"', '\\"')
+
+
+def SetFileProperty(output, source_name, property_name, values, sep):
+ """Given a set of source file, sets the given property on them."""
+ output.write('set_source_files_properties(')
+ output.write(source_name)
+ output.write(' PROPERTIES ')
+ output.write(property_name)
+ output.write(' "')
+ for value in values:
+ output.write(CMakeStringEscape(value))
+ output.write(sep)
+ output.write('")\n')
+
+
+def SetFilesProperty(output, variable, property_name, values, sep):
+ """Given a set of source files, sets the given property on them."""
+ output.write('set_source_files_properties(')
+ WriteVariable(output, variable)
+ output.write(' PROPERTIES ')
+ output.write(property_name)
+ output.write(' "')
+ for value in values:
+ output.write(CMakeStringEscape(value))
+ output.write(sep)
+ output.write('")\n')
+
+
+def SetTargetProperty(output, target_name, property_name, values, sep=''):
+ """Given a target, sets the given property."""
+ output.write('set_target_properties(')
+ output.write(target_name)
+ output.write(' PROPERTIES ')
+ output.write(property_name)
+ output.write(' "')
+ for value in values:
+ output.write(CMakeStringEscape(value))
+ output.write(sep)
+ output.write('")\n')
+
+
+def SetVariable(output, variable_name, value):
+ """Sets a CMake variable."""
+ output.write('set(')
+ output.write(variable_name)
+ output.write(' "')
+ output.write(CMakeStringEscape(value))
+ output.write('")\n')
+
+
+def SetVariableList(output, variable_name, values):
+ """Sets a CMake variable to a list."""
+ if not values:
+ return SetVariable(output, variable_name, "")
+ if len(values) == 1:
+ return SetVariable(output, variable_name, values[0])
+ output.write('list(APPEND ')
+ output.write(variable_name)
+ output.write('\n "')
+ output.write('"\n "'.join([CMakeStringEscape(value) for value in values]))
+ output.write('")\n')
+
+
+def UnsetVariable(output, variable_name):
+ """Unsets a CMake variable."""
+ output.write('unset(')
+ output.write(variable_name)
+ output.write(')\n')
+
+
+def WriteVariable(output, variable_name, prepend=None):
+ if prepend:
+ output.write(prepend)
+ output.write('${')
+ output.write(variable_name)
+ output.write('}')
+
+
+class CMakeTargetType(object):
+ def __init__(self, command, modifier, property_modifier):
+ self.command = command
+ self.modifier = modifier
+ self.property_modifier = property_modifier
+
+
+cmake_target_type_from_gyp_target_type = {
+ 'executable': CMakeTargetType('add_executable', None, 'RUNTIME'),
+ 'static_library': CMakeTargetType('add_library', 'STATIC', 'ARCHIVE'),
+ 'shared_library': CMakeTargetType('add_library', 'SHARED', 'LIBRARY'),
+ 'loadable_module': CMakeTargetType('add_library', 'MODULE', 'LIBRARY'),
+ 'none': CMakeTargetType('add_custom_target', 'SOURCES', None),
+}
+
+
+def StringToCMakeTargetName(a):
+ """Converts the given string 'a' to a valid CMake target name.
+
+ All invalid characters are replaced by '_'.
+ Invalid for cmake: ' ', '/', '(', ')', '"'
+ Invalid for make: ':'
+ Invalid for unknown reasons but cause failures: '.'
+ """
+ return a.translate(string.maketrans(' /():."', '_______'))
+
+
+def WriteActions(target_name, actions, extra_sources, extra_deps,
+ path_to_gyp, output):
+ """Write CMake for the 'actions' in the target.
+
+ Args:
+ target_name: the name of the CMake target being generated.
+ actions: the Gyp 'actions' dict for this target.
+ extra_sources: [(<cmake_src>, <src>)] to append with generated source files.
+ extra_deps: [<cmake_taget>] to append with generated targets.
+ path_to_gyp: relative path from CMakeLists.txt being generated to
+ the Gyp file in which the target being generated is defined.
+ """
+ for action in actions:
+ action_name = StringToCMakeTargetName(action['action_name'])
+ action_target_name = '%s__%s' % (target_name, action_name)
+
+ inputs = action['inputs']
+ inputs_name = action_target_name + '__input'
+ SetVariableList(output, inputs_name,
+ [NormjoinPathForceCMakeSource(path_to_gyp, dep) for dep in inputs])
+
+ outputs = action['outputs']
+ cmake_outputs = [NormjoinPathForceCMakeSource(path_to_gyp, out)
+ for out in outputs]
+ outputs_name = action_target_name + '__output'
+ SetVariableList(output, outputs_name, cmake_outputs)
+
+ # Build up a list of outputs.
+ # Collect the output dirs we'll need.
+ dirs = set(dir for dir in (os.path.dirname(o) for o in outputs) if dir)
+
+ if int(action.get('process_outputs_as_sources', False)):
+ extra_sources.extend(zip(cmake_outputs, outputs))
+
+ # add_custom_command
+ output.write('add_custom_command(OUTPUT ')
+ WriteVariable(output, outputs_name)
+ output.write('\n')
+
+ if len(dirs) > 0:
+ for directory in dirs:
+ output.write(' COMMAND ${CMAKE_COMMAND} -E make_directory ')
+ output.write(directory)
+ output.write('\n')
+
+ output.write(' COMMAND ')
+ output.write(gyp.common.EncodePOSIXShellList(action['action']))
+ output.write('\n')
+
+ output.write(' DEPENDS ')
+ WriteVariable(output, inputs_name)
+ output.write('\n')
+
+ output.write(' WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/')
+ output.write(path_to_gyp)
+ output.write('\n')
+
+ output.write(' COMMENT ')
+ if 'message' in action:
+ output.write(action['message'])
+ else:
+ output.write(action_target_name)
+ output.write('\n')
+
+ output.write(' VERBATIM\n')
+ output.write(')\n')
+
+ # add_custom_target
+ output.write('add_custom_target(')
+ output.write(action_target_name)
+ output.write('\n DEPENDS ')
+ WriteVariable(output, outputs_name)
+ output.write('\n SOURCES ')
+ WriteVariable(output, inputs_name)
+ output.write('\n)\n')
+
+ extra_deps.append(action_target_name)
+
+
+def NormjoinRulePathForceCMakeSource(base_path, rel_path, rule_source):
+ if rel_path.startswith(("${RULE_INPUT_PATH}","${RULE_INPUT_DIRNAME}")):
+ if any([rule_source.startswith(var) for var in FULL_PATH_VARS]):
+ return rel_path
+ return NormjoinPathForceCMakeSource(base_path, rel_path)
+
+
+def WriteRules(target_name, rules, extra_sources, extra_deps,
+ path_to_gyp, output):
+ """Write CMake for the 'rules' in the target.
+
+ Args:
+ target_name: the name of the CMake target being generated.
+ actions: the Gyp 'actions' dict for this target.
+ extra_sources: [(<cmake_src>, <src>)] to append with generated source files.
+ extra_deps: [<cmake_taget>] to append with generated targets.
+ path_to_gyp: relative path from CMakeLists.txt being generated to
+ the Gyp file in which the target being generated is defined.
+ """
+ for rule in rules:
+ rule_name = StringToCMakeTargetName(target_name + '__' + rule['rule_name'])
+
+ inputs = rule.get('inputs', [])
+ inputs_name = rule_name + '__input'
+ SetVariableList(output, inputs_name,
+ [NormjoinPathForceCMakeSource(path_to_gyp, dep) for dep in inputs])
+ outputs = rule['outputs']
+ var_outputs = []
+
+ for count, rule_source in enumerate(rule.get('rule_sources', [])):
+ action_name = rule_name + '_' + str(count)
+
+ rule_source_dirname, rule_source_basename = os.path.split(rule_source)
+ rule_source_root, rule_source_ext = os.path.splitext(rule_source_basename)
+
+ SetVariable(output, 'RULE_INPUT_PATH', rule_source)
+ SetVariable(output, 'RULE_INPUT_DIRNAME', rule_source_dirname)
+ SetVariable(output, 'RULE_INPUT_NAME', rule_source_basename)
+ SetVariable(output, 'RULE_INPUT_ROOT', rule_source_root)
+ SetVariable(output, 'RULE_INPUT_EXT', rule_source_ext)
+
+ # Build up a list of outputs.
+ # Collect the output dirs we'll need.
+ dirs = set(dir for dir in (os.path.dirname(o) for o in outputs) if dir)
+
+ # Create variables for the output, as 'local' variable will be unset.
+ these_outputs = []
+ for output_index, out in enumerate(outputs):
+ output_name = action_name + '_' + str(output_index)
+ SetVariable(output, output_name,
+ NormjoinRulePathForceCMakeSource(path_to_gyp, out,
+ rule_source))
+ if int(rule.get('process_outputs_as_sources', False)):
+ extra_sources.append(('${' + output_name + '}', out))
+ these_outputs.append('${' + output_name + '}')
+ var_outputs.append('${' + output_name + '}')
+
+ # add_custom_command
+ output.write('add_custom_command(OUTPUT\n')
+ for out in these_outputs:
+ output.write(' ')
+ output.write(out)
+ output.write('\n')
+
+ for directory in dirs:
+ output.write(' COMMAND ${CMAKE_COMMAND} -E make_directory ')
+ output.write(directory)
+ output.write('\n')
+
+ output.write(' COMMAND ')
+ output.write(gyp.common.EncodePOSIXShellList(rule['action']))
+ output.write('\n')
+
+ output.write(' DEPENDS ')
+ WriteVariable(output, inputs_name)
+ output.write(' ')
+ output.write(NormjoinPath(path_to_gyp, rule_source))
+ output.write('\n')
+
+ # CMAKE_CURRENT_LIST_DIR is where the CMakeLists.txt lives.
+ # The cwd is the current build directory.
+ output.write(' WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/')
+ output.write(path_to_gyp)
+ output.write('\n')
+
+ output.write(' COMMENT ')
+ if 'message' in rule:
+ output.write(rule['message'])
+ else:
+ output.write(action_name)
+ output.write('\n')
+
+ output.write(' VERBATIM\n')
+ output.write(')\n')
+
+ UnsetVariable(output, 'RULE_INPUT_PATH')
+ UnsetVariable(output, 'RULE_INPUT_DIRNAME')
+ UnsetVariable(output, 'RULE_INPUT_NAME')
+ UnsetVariable(output, 'RULE_INPUT_ROOT')
+ UnsetVariable(output, 'RULE_INPUT_EXT')
+
+ # add_custom_target
+ output.write('add_custom_target(')
+ output.write(rule_name)
+ output.write(' DEPENDS\n')
+ for out in var_outputs:
+ output.write(' ')
+ output.write(out)
+ output.write('\n')
+ output.write('SOURCES ')
+ WriteVariable(output, inputs_name)
+ output.write('\n')
+ for rule_source in rule.get('rule_sources', []):
+ output.write(' ')
+ output.write(NormjoinPath(path_to_gyp, rule_source))
+ output.write('\n')
+ output.write(')\n')
+
+ extra_deps.append(rule_name)
+
+
+def WriteCopies(target_name, copies, extra_deps, path_to_gyp, output):
+ """Write CMake for the 'copies' in the target.
+
+ Args:
+ target_name: the name of the CMake target being generated.
+ actions: the Gyp 'actions' dict for this target.
+ extra_deps: [<cmake_taget>] to append with generated targets.
+ path_to_gyp: relative path from CMakeLists.txt being generated to
+ the Gyp file in which the target being generated is defined.
+ """
+ copy_name = target_name + '__copies'
+
+ # CMake gets upset with custom targets with OUTPUT which specify no output.
+ have_copies = any(copy['files'] for copy in copies)
+ if not have_copies:
+ output.write('add_custom_target(')
+ output.write(copy_name)
+ output.write(')\n')
+ extra_deps.append(copy_name)
+ return
+
+ class Copy(object):
+ def __init__(self, ext, command):
+ self.cmake_inputs = []
+ self.cmake_outputs = []
+ self.gyp_inputs = []
+ self.gyp_outputs = []
+ self.ext = ext
+ self.inputs_name = None
+ self.outputs_name = None
+ self.command = command
+
+ file_copy = Copy('', 'copy')
+ dir_copy = Copy('_dirs', 'copy_directory')
+
+ for copy in copies:
+ files = copy['files']
+ destination = copy['destination']
+ for src in files:
+ path = os.path.normpath(src)
+ basename = os.path.split(path)[1]
+ dst = os.path.join(destination, basename)
+
+ copy = file_copy if os.path.basename(src) else dir_copy
+
+ copy.cmake_inputs.append(NormjoinPathForceCMakeSource(path_to_gyp, src))
+ copy.cmake_outputs.append(NormjoinPathForceCMakeSource(path_to_gyp, dst))
+ copy.gyp_inputs.append(src)
+ copy.gyp_outputs.append(dst)
+
+ for copy in (file_copy, dir_copy):
+ if copy.cmake_inputs:
+ copy.inputs_name = copy_name + '__input' + copy.ext
+ SetVariableList(output, copy.inputs_name, copy.cmake_inputs)
+
+ copy.outputs_name = copy_name + '__output' + copy.ext
+ SetVariableList(output, copy.outputs_name, copy.cmake_outputs)
+
+ # add_custom_command
+ output.write('add_custom_command(\n')
+
+ output.write('OUTPUT')
+ for copy in (file_copy, dir_copy):
+ if copy.outputs_name:
+ WriteVariable(output, copy.outputs_name, ' ')
+ output.write('\n')
+
+ for copy in (file_copy, dir_copy):
+ for src, dst in zip(copy.gyp_inputs, copy.gyp_outputs):
+ # 'cmake -E copy src dst' will create the 'dst' directory if needed.
+ output.write('COMMAND ${CMAKE_COMMAND} -E %s ' % copy.command)
+ output.write(src)
+ output.write(' ')
+ output.write(dst)
+ output.write("\n")
+
+ output.write('DEPENDS')
+ for copy in (file_copy, dir_copy):
+ if copy.inputs_name:
+ WriteVariable(output, copy.inputs_name, ' ')
+ output.write('\n')
+
+ output.write('WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/')
+ output.write(path_to_gyp)
+ output.write('\n')
+
+ output.write('COMMENT Copying for ')
+ output.write(target_name)
+ output.write('\n')
+
+ output.write('VERBATIM\n')
+ output.write(')\n')
+
+ # add_custom_target
+ output.write('add_custom_target(')
+ output.write(copy_name)
+ output.write('\n DEPENDS')
+ for copy in (file_copy, dir_copy):
+ if copy.outputs_name:
+ WriteVariable(output, copy.outputs_name, ' ')
+ output.write('\n SOURCES')
+ if file_copy.inputs_name:
+ WriteVariable(output, file_copy.inputs_name, ' ')
+ output.write('\n)\n')
+
+ extra_deps.append(copy_name)
+
+
+def CreateCMakeTargetBaseName(qualified_target):
+ """This is the name we would like the target to have."""
+ _, gyp_target_name, gyp_target_toolset = (
+ gyp.common.ParseQualifiedTarget(qualified_target))
+ cmake_target_base_name = gyp_target_name
+ if gyp_target_toolset and gyp_target_toolset != 'target':
+ cmake_target_base_name += '_' + gyp_target_toolset
+ return StringToCMakeTargetName(cmake_target_base_name)
+
+
+def CreateCMakeTargetFullName(qualified_target):
+ """An unambiguous name for the target."""
+ gyp_file, gyp_target_name, gyp_target_toolset = (
+ gyp.common.ParseQualifiedTarget(qualified_target))
+ cmake_target_full_name = gyp_file + ':' + gyp_target_name
+ if gyp_target_toolset and gyp_target_toolset != 'target':
+ cmake_target_full_name += '_' + gyp_target_toolset
+ return StringToCMakeTargetName(cmake_target_full_name)
+
+
+class CMakeNamer(object):
+ """Converts Gyp target names into CMake target names.
+
+ CMake requires that target names be globally unique. One way to ensure
+ this is to fully qualify the names of the targets. Unfortunatly, this
+ ends up with all targets looking like "chrome_chrome_gyp_chrome" instead
+ of just "chrome". If this generator were only interested in building, it
+ would be possible to fully qualify all target names, then create
+ unqualified target names which depend on all qualified targets which
+ should have had that name. This is more or less what the 'make' generator
+ does with aliases. However, one goal of this generator is to create CMake
+ files for use with IDEs, and fully qualified names are not as user
+ friendly.
+
+ Since target name collision is rare, we do the above only when required.
+
+ Toolset variants are always qualified from the base, as this is required for
+ building. However, it also makes sense for an IDE, as it is possible for
+ defines to be different.
+ """
+ def __init__(self, target_list):
+ self.cmake_target_base_names_conficting = set()
+
+ cmake_target_base_names_seen = set()
+ for qualified_target in target_list:
+ cmake_target_base_name = CreateCMakeTargetBaseName(qualified_target)
+
+ if cmake_target_base_name not in cmake_target_base_names_seen:
+ cmake_target_base_names_seen.add(cmake_target_base_name)
+ else:
+ self.cmake_target_base_names_conficting.add(cmake_target_base_name)
+
+ def CreateCMakeTargetName(self, qualified_target):
+ base_name = CreateCMakeTargetBaseName(qualified_target)
+ if base_name in self.cmake_target_base_names_conficting:
+ return CreateCMakeTargetFullName(qualified_target)
+ return base_name
+
+
+def WriteTarget(namer, qualified_target, target_dicts, build_dir, config_to_use,
+ options, generator_flags, all_qualified_targets, flavor,
+ output):
+ # The make generator does this always.
+ # TODO: It would be nice to be able to tell CMake all dependencies.
+ circular_libs = generator_flags.get('circular', True)
+
+ if not generator_flags.get('standalone', False):
+ output.write('\n#')
+ output.write(qualified_target)
+ output.write('\n')
+
+ gyp_file, _, _ = gyp.common.ParseQualifiedTarget(qualified_target)
+ rel_gyp_file = gyp.common.RelativePath(gyp_file, options.toplevel_dir)
+ rel_gyp_dir = os.path.dirname(rel_gyp_file)
+
+ # Relative path from build dir to top dir.
+ build_to_top = gyp.common.InvertRelativePath(build_dir, options.toplevel_dir)
+ # Relative path from build dir to gyp dir.
+ build_to_gyp = os.path.join(build_to_top, rel_gyp_dir)
+
+ path_from_cmakelists_to_gyp = build_to_gyp
+
+ spec = target_dicts.get(qualified_target, {})
+ config = spec.get('configurations', {}).get(config_to_use, {})
+
+ xcode_settings = None
+ if flavor == 'mac':
+ xcode_settings = gyp.xcode_emulation.XcodeSettings(spec)
+
+ target_name = spec.get('target_name', '<missing target name>')
+ target_type = spec.get('type', '<missing target type>')
+ target_toolset = spec.get('toolset')
+
+ cmake_target_type = cmake_target_type_from_gyp_target_type.get(target_type)
+ if cmake_target_type is None:
+ print ('Target %s has unknown target type %s, skipping.' %
+ ( target_name, target_type ) )
+ return
+
+ SetVariable(output, 'TARGET', target_name)
+ SetVariable(output, 'TOOLSET', target_toolset)
+
+ cmake_target_name = namer.CreateCMakeTargetName(qualified_target)
+
+ extra_sources = []
+ extra_deps = []
+
+ # Actions must come first, since they can generate more OBJs for use below.
+ if 'actions' in spec:
+ WriteActions(cmake_target_name, spec['actions'], extra_sources, extra_deps,
+ path_from_cmakelists_to_gyp, output)
+
+ # Rules must be early like actions.
+ if 'rules' in spec:
+ WriteRules(cmake_target_name, spec['rules'], extra_sources, extra_deps,
+ path_from_cmakelists_to_gyp, output)
+
+ # Copies
+ if 'copies' in spec:
+ WriteCopies(cmake_target_name, spec['copies'], extra_deps,
+ path_from_cmakelists_to_gyp, output)
+
+ # Target and sources
+ srcs = spec.get('sources', [])
+
+ # Gyp separates the sheep from the goats based on file extensions.
+ # A full separation is done here because of flag handing (see below).
+ s_sources = []
+ c_sources = []
+ cxx_sources = []
+ linkable_sources = []
+ other_sources = []
+ for src in srcs:
+ _, ext = os.path.splitext(src)
+ src_type = COMPILABLE_EXTENSIONS.get(ext, None)
+ src_norm_path = NormjoinPath(path_from_cmakelists_to_gyp, src);
+
+ if src_type == 's':
+ s_sources.append(src_norm_path)
+ elif src_type == 'cc':
+ c_sources.append(src_norm_path)
+ elif src_type == 'cxx':
+ cxx_sources.append(src_norm_path)
+ elif Linkable(ext):
+ linkable_sources.append(src_norm_path)
+ else:
+ other_sources.append(src_norm_path)
+
+ for extra_source in extra_sources:
+ src, real_source = extra_source
+ _, ext = os.path.splitext(real_source)
+ src_type = COMPILABLE_EXTENSIONS.get(ext, None)
+
+ if src_type == 's':
+ s_sources.append(src)
+ elif src_type == 'cc':
+ c_sources.append(src)
+ elif src_type == 'cxx':
+ cxx_sources.append(src)
+ elif Linkable(ext):
+ linkable_sources.append(src)
+ else:
+ other_sources.append(src)
+
+ s_sources_name = None
+ if s_sources:
+ s_sources_name = cmake_target_name + '__asm_srcs'
+ SetVariableList(output, s_sources_name, s_sources)
+
+ c_sources_name = None
+ if c_sources:
+ c_sources_name = cmake_target_name + '__c_srcs'
+ SetVariableList(output, c_sources_name, c_sources)
+
+ cxx_sources_name = None
+ if cxx_sources:
+ cxx_sources_name = cmake_target_name + '__cxx_srcs'
+ SetVariableList(output, cxx_sources_name, cxx_sources)
+
+ linkable_sources_name = None
+ if linkable_sources:
+ linkable_sources_name = cmake_target_name + '__linkable_srcs'
+ SetVariableList(output, linkable_sources_name, linkable_sources)
+
+ other_sources_name = None
+ if other_sources:
+ other_sources_name = cmake_target_name + '__other_srcs'
+ SetVariableList(output, other_sources_name, other_sources)
+
+ # CMake gets upset when executable targets provide no sources.
+ # http://www.cmake.org/pipermail/cmake/2010-July/038461.html
+ dummy_sources_name = None
+ has_sources = (s_sources_name or
+ c_sources_name or
+ cxx_sources_name or
+ linkable_sources_name or
+ other_sources_name)
+ if target_type == 'executable' and not has_sources:
+ dummy_sources_name = cmake_target_name + '__dummy_srcs'
+ SetVariable(output, dummy_sources_name,
+ "${obj}.${TOOLSET}/${TARGET}/genc/dummy.c")
+ output.write('if(NOT EXISTS "')
+ WriteVariable(output, dummy_sources_name)
+ output.write('")\n')
+ output.write(' file(WRITE "')
+ WriteVariable(output, dummy_sources_name)
+ output.write('" "")\n')
+ output.write("endif()\n")
+
+
+ # CMake is opposed to setting linker directories and considers the practice
+ # of setting linker directories dangerous. Instead, it favors the use of
+ # find_library and passing absolute paths to target_link_libraries.
+ # However, CMake does provide the command link_directories, which adds
+ # link directories to targets defined after it is called.
+ # As a result, link_directories must come before the target definition.
+ # CMake unfortunately has no means of removing entries from LINK_DIRECTORIES.
+ library_dirs = config.get('library_dirs')
+ if library_dirs is not None:
+ output.write('link_directories(')
+ for library_dir in library_dirs:
+ output.write(' ')
+ output.write(NormjoinPath(path_from_cmakelists_to_gyp, library_dir))
+ output.write('\n')
+ output.write(')\n')
+
+ output.write(cmake_target_type.command)
+ output.write('(')
+ output.write(cmake_target_name)
+
+ if cmake_target_type.modifier is not None:
+ output.write(' ')
+ output.write(cmake_target_type.modifier)
+
+ if s_sources_name:
+ WriteVariable(output, s_sources_name, ' ')
+ if c_sources_name:
+ WriteVariable(output, c_sources_name, ' ')
+ if cxx_sources_name:
+ WriteVariable(output, cxx_sources_name, ' ')
+ if linkable_sources_name:
+ WriteVariable(output, linkable_sources_name, ' ')
+ if other_sources_name:
+ WriteVariable(output, other_sources_name, ' ')
+ if dummy_sources_name:
+ WriteVariable(output, dummy_sources_name, ' ')
+
+ output.write(')\n')
+
+ # Let CMake know if the 'all' target should depend on this target.
+ exclude_from_all = ('TRUE' if qualified_target not in all_qualified_targets
+ else 'FALSE')
+ SetTargetProperty(output, cmake_target_name,
+ 'EXCLUDE_FROM_ALL', exclude_from_all)
+ for extra_target_name in extra_deps:
+ SetTargetProperty(output, extra_target_name,
+ 'EXCLUDE_FROM_ALL', exclude_from_all)
+
+ # Output name and location.
+ if target_type != 'none':
+ # Link as 'C' if there are no other files
+ if not c_sources and not cxx_sources:
+ SetTargetProperty(output, cmake_target_name, 'LINKER_LANGUAGE', ['C'])
+
+ # Mark uncompiled sources as uncompiled.
+ if other_sources_name:
+ output.write('set_source_files_properties(')
+ WriteVariable(output, other_sources_name, '')
+ output.write(' PROPERTIES HEADER_FILE_ONLY "TRUE")\n')
+
+ # Mark object sources as linkable.
+ if linkable_sources_name:
+ output.write('set_source_files_properties(')
+ WriteVariable(output, other_sources_name, '')
+ output.write(' PROPERTIES EXTERNAL_OBJECT "TRUE")\n')
+
+ # Output directory
+ target_output_directory = spec.get('product_dir')
+ if target_output_directory is None:
+ if target_type in ('executable', 'loadable_module'):
+ target_output_directory = generator_default_variables['PRODUCT_DIR']
+ elif target_type == 'shared_library':
+ target_output_directory = '${builddir}/lib.${TOOLSET}'
+ elif spec.get('standalone_static_library', False):
+ target_output_directory = generator_default_variables['PRODUCT_DIR']
+ else:
+ base_path = gyp.common.RelativePath(os.path.dirname(gyp_file),
+ options.toplevel_dir)
+ target_output_directory = '${obj}.${TOOLSET}'
+ target_output_directory = (
+ os.path.join(target_output_directory, base_path))
+
+ cmake_target_output_directory = NormjoinPathForceCMakeSource(
+ path_from_cmakelists_to_gyp,
+ target_output_directory)
+ SetTargetProperty(output,
+ cmake_target_name,
+ cmake_target_type.property_modifier + '_OUTPUT_DIRECTORY',
+ cmake_target_output_directory)
+
+ # Output name
+ default_product_prefix = ''
+ default_product_name = target_name
+ default_product_ext = ''
+ if target_type == 'static_library':
+ static_library_prefix = generator_default_variables['STATIC_LIB_PREFIX']
+ default_product_name = RemovePrefix(default_product_name,
+ static_library_prefix)
+ default_product_prefix = static_library_prefix
+ default_product_ext = generator_default_variables['STATIC_LIB_SUFFIX']
+
+ elif target_type in ('loadable_module', 'shared_library'):
+ shared_library_prefix = generator_default_variables['SHARED_LIB_PREFIX']
+ default_product_name = RemovePrefix(default_product_name,
+ shared_library_prefix)
+ default_product_prefix = shared_library_prefix
+ default_product_ext = generator_default_variables['SHARED_LIB_SUFFIX']
+
+ elif target_type != 'executable':
+ print ('ERROR: What output file should be generated?',
+ 'type', target_type, 'target', target_name)
+
+ product_prefix = spec.get('product_prefix', default_product_prefix)
+ product_name = spec.get('product_name', default_product_name)
+ product_ext = spec.get('product_extension')
+ if product_ext:
+ product_ext = '.' + product_ext
+ else:
+ product_ext = default_product_ext
+
+ SetTargetProperty(output, cmake_target_name, 'PREFIX', product_prefix)
+ SetTargetProperty(output, cmake_target_name,
+ cmake_target_type.property_modifier + '_OUTPUT_NAME',
+ product_name)
+ SetTargetProperty(output, cmake_target_name, 'SUFFIX', product_ext)
+
+ # Make the output of this target referenceable as a source.
+ cmake_target_output_basename = product_prefix + product_name + product_ext
+ cmake_target_output = os.path.join(cmake_target_output_directory,
+ cmake_target_output_basename)
+ SetFileProperty(output, cmake_target_output, 'GENERATED', ['TRUE'], '')
+
+ # Includes
+ includes = config.get('include_dirs')
+ if includes:
+ # This (target include directories) is what requires CMake 2.8.8
+ includes_name = cmake_target_name + '__include_dirs'
+ SetVariableList(output, includes_name,
+ [NormjoinPathForceCMakeSource(path_from_cmakelists_to_gyp, include)
+ for include in includes])
+ output.write('set_property(TARGET ')
+ output.write(cmake_target_name)
+ output.write(' APPEND PROPERTY INCLUDE_DIRECTORIES ')
+ WriteVariable(output, includes_name, '')
+ output.write(')\n')
+
+ # Defines
+ defines = config.get('defines')
+ if defines is not None:
+ SetTargetProperty(output,
+ cmake_target_name,
+ 'COMPILE_DEFINITIONS',
+ defines,
+ ';')
+
+ # Compile Flags - http://www.cmake.org/Bug/view.php?id=6493
+ # CMake currently does not have target C and CXX flags.
+ # So, instead of doing...
+
+ # cflags_c = config.get('cflags_c')
+ # if cflags_c is not None:
+ # SetTargetProperty(output, cmake_target_name,
+ # 'C_COMPILE_FLAGS', cflags_c, ' ')
+
+ # cflags_cc = config.get('cflags_cc')
+ # if cflags_cc is not None:
+ # SetTargetProperty(output, cmake_target_name,
+ # 'CXX_COMPILE_FLAGS', cflags_cc, ' ')
+
+ # Instead we must...
+ cflags = config.get('cflags', [])
+ cflags_c = config.get('cflags_c', [])
+ cflags_cxx = config.get('cflags_cc', [])
+ if xcode_settings:
+ cflags = xcode_settings.GetCflags(config_to_use)
+ cflags_c = xcode_settings.GetCflagsC(config_to_use)
+ cflags_cxx = xcode_settings.GetCflagsCC(config_to_use)
+ #cflags_objc = xcode_settings.GetCflagsObjC(config_to_use)
+ #cflags_objcc = xcode_settings.GetCflagsObjCC(config_to_use)
+
+ if (not cflags_c or not c_sources) and (not cflags_cxx or not cxx_sources):
+ SetTargetProperty(output, cmake_target_name, 'COMPILE_FLAGS', cflags, ' ')
+
+ elif c_sources and not (s_sources or cxx_sources):
+ flags = []
+ flags.extend(cflags)
+ flags.extend(cflags_c)
+ SetTargetProperty(output, cmake_target_name, 'COMPILE_FLAGS', flags, ' ')
+
+ elif cxx_sources and not (s_sources or c_sources):
+ flags = []
+ flags.extend(cflags)
+ flags.extend(cflags_cxx)
+ SetTargetProperty(output, cmake_target_name, 'COMPILE_FLAGS', flags, ' ')
+
+ else:
+ # TODO: This is broken, one cannot generally set properties on files,
+ # as other targets may require different properties on the same files.
+ if s_sources and cflags:
+ SetFilesProperty(output, s_sources_name, 'COMPILE_FLAGS', cflags, ' ')
+
+ if c_sources and (cflags or cflags_c):
+ flags = []
+ flags.extend(cflags)
+ flags.extend(cflags_c)
+ SetFilesProperty(output, c_sources_name, 'COMPILE_FLAGS', flags, ' ')
+
+ if cxx_sources and (cflags or cflags_cxx):
+ flags = []
+ flags.extend(cflags)
+ flags.extend(cflags_cxx)
+ SetFilesProperty(output, cxx_sources_name, 'COMPILE_FLAGS', flags, ' ')
+
+ # Linker flags
+ ldflags = config.get('ldflags')
+ if ldflags is not None:
+ SetTargetProperty(output, cmake_target_name, 'LINK_FLAGS', ldflags, ' ')
+
+ # XCode settings
+ xcode_settings = config.get('xcode_settings', {})
+ for xcode_setting, xcode_value in xcode_settings.viewitems():
+ SetTargetProperty(output, cmake_target_name,
+ "XCODE_ATTRIBUTE_%s" % xcode_setting, xcode_value,
+ '' if isinstance(xcode_value, str) else ' ')
+
+ # Note on Dependencies and Libraries:
+ # CMake wants to handle link order, resolving the link line up front.
+ # Gyp does not retain or enforce specifying enough information to do so.
+ # So do as other gyp generators and use --start-group and --end-group.
+ # Give CMake as little information as possible so that it doesn't mess it up.
+
+ # Dependencies
+ rawDeps = spec.get('dependencies', [])
+
+ static_deps = []
+ shared_deps = []
+ other_deps = []
+ for rawDep in rawDeps:
+ dep_cmake_name = namer.CreateCMakeTargetName(rawDep)
+ dep_spec = target_dicts.get(rawDep, {})
+ dep_target_type = dep_spec.get('type', None)
+
+ if dep_target_type == 'static_library':
+ static_deps.append(dep_cmake_name)
+ elif dep_target_type == 'shared_library':
+ shared_deps.append(dep_cmake_name)
+ else:
+ other_deps.append(dep_cmake_name)
+
+ # ensure all external dependencies are complete before internal dependencies
+ # extra_deps currently only depend on their own deps, so otherwise run early
+ if static_deps or shared_deps or other_deps:
+ for extra_dep in extra_deps:
+ output.write('add_dependencies(')
+ output.write(extra_dep)
+ output.write('\n')
+ for deps in (static_deps, shared_deps, other_deps):
+ for dep in gyp.common.uniquer(deps):
+ output.write(' ')
+ output.write(dep)
+ output.write('\n')
+ output.write(')\n')
+
+ linkable = target_type in ('executable', 'loadable_module', 'shared_library')
+ other_deps.extend(extra_deps)
+ if other_deps or (not linkable and (static_deps or shared_deps)):
+ output.write('add_dependencies(')
+ output.write(cmake_target_name)
+ output.write('\n')
+ for dep in gyp.common.uniquer(other_deps):
+ output.write(' ')
+ output.write(dep)
+ output.write('\n')
+ if not linkable:
+ for deps in (static_deps, shared_deps):
+ for lib_dep in gyp.common.uniquer(deps):
+ output.write(' ')
+ output.write(lib_dep)
+ output.write('\n')
+ output.write(')\n')
+
+ # Libraries
+ if linkable:
+ external_libs = [lib for lib in spec.get('libraries', []) if len(lib) > 0]
+ if external_libs or static_deps or shared_deps:
+ output.write('target_link_libraries(')
+ output.write(cmake_target_name)
+ output.write('\n')
+ if static_deps:
+ write_group = circular_libs and len(static_deps) > 1 and flavor != 'mac'
+ if write_group:
+ output.write('-Wl,--start-group\n')
+ for dep in gyp.common.uniquer(static_deps):
+ output.write(' ')
+ output.write(dep)
+ output.write('\n')
+ if write_group:
+ output.write('-Wl,--end-group\n')
+ if shared_deps:
+ for dep in gyp.common.uniquer(shared_deps):
+ output.write(' ')
+ output.write(dep)
+ output.write('\n')
+ if external_libs:
+ for lib in gyp.common.uniquer(external_libs):
+ output.write(' "')
+ output.write(RemovePrefix(lib, "$(SDKROOT)"))
+ output.write('"\n')
+
+ output.write(')\n')
+
+ UnsetVariable(output, 'TOOLSET')
+ UnsetVariable(output, 'TARGET')
+
+
+def GenerateOutputForConfig(target_list, target_dicts, data,
+ params, config_to_use):
+ options = params['options']
+ generator_flags = params['generator_flags']
+ flavor = gyp.common.GetFlavor(params)
+
+ # generator_dir: relative path from pwd to where make puts build files.
+ # Makes migrating from make to cmake easier, cmake doesn't put anything here.
+ # Each Gyp configuration creates a different CMakeLists.txt file
+ # to avoid incompatibilities between Gyp and CMake configurations.
+ generator_dir = os.path.relpath(options.generator_output or '.')
+
+ # output_dir: relative path from generator_dir to the build directory.
+ output_dir = generator_flags.get('output_dir', 'out')
+
+ # build_dir: relative path from source root to our output files.
+ # e.g. "out/Debug"
+ build_dir = os.path.normpath(os.path.join(generator_dir,
+ output_dir,
+ config_to_use))
+
+ toplevel_build = os.path.join(options.toplevel_dir, build_dir)
+
+ output_file = os.path.join(toplevel_build, 'CMakeLists.txt')
+ gyp.common.EnsureDirExists(output_file)
+
+ output = open(output_file, 'w')
+ output.write('cmake_minimum_required(VERSION 2.8.8 FATAL_ERROR)\n')
+ output.write('cmake_policy(VERSION 2.8.8)\n')
+
+ gyp_file, project_target, _ = gyp.common.ParseQualifiedTarget(target_list[-1])
+ output.write('project(')
+ output.write(project_target)
+ output.write(')\n')
+
+ SetVariable(output, 'configuration', config_to_use)
+
+ ar = None
+ cc = None
+ cxx = None
+
+ make_global_settings = data[gyp_file].get('make_global_settings', [])
+ build_to_top = gyp.common.InvertRelativePath(build_dir,
+ options.toplevel_dir)
+ for key, value in make_global_settings:
+ if key == 'AR':
+ ar = os.path.join(build_to_top, value)
+ if key == 'CC':
+ cc = os.path.join(build_to_top, value)
+ if key == 'CXX':
+ cxx = os.path.join(build_to_top, value)
+
+ ar = gyp.common.GetEnvironFallback(['AR_target', 'AR'], ar)
+ cc = gyp.common.GetEnvironFallback(['CC_target', 'CC'], cc)
+ cxx = gyp.common.GetEnvironFallback(['CXX_target', 'CXX'], cxx)
+
+ if ar:
+ SetVariable(output, 'CMAKE_AR', ar)
+ if cc:
+ SetVariable(output, 'CMAKE_C_COMPILER', cc)
+ if cxx:
+ SetVariable(output, 'CMAKE_CXX_COMPILER', cxx)
+
+ # The following appears to be as-yet undocumented.
+ # http://public.kitware.com/Bug/view.php?id=8392
+ output.write('enable_language(ASM)\n')
+ # ASM-ATT does not support .S files.
+ # output.write('enable_language(ASM-ATT)\n')
+
+ if cc:
+ SetVariable(output, 'CMAKE_ASM_COMPILER', cc)
+
+ SetVariable(output, 'builddir', '${CMAKE_CURRENT_BINARY_DIR}')
+ SetVariable(output, 'obj', '${builddir}/obj')
+ output.write('\n')
+
+ # TODO: Undocumented/unsupported (the CMake Java generator depends on it).
+ # CMake by default names the object resulting from foo.c to be foo.c.o.
+ # Gyp traditionally names the object resulting from foo.c foo.o.
+ # This should be irrelevant, but some targets extract .o files from .a
+ # and depend on the name of the extracted .o files.
+ output.write('set(CMAKE_C_OUTPUT_EXTENSION_REPLACE 1)\n')
+ output.write('set(CMAKE_CXX_OUTPUT_EXTENSION_REPLACE 1)\n')
+ output.write('\n')
+
+ # Force ninja to use rsp files. Otherwise link and ar lines can get too long,
+ # resulting in 'Argument list too long' errors.
+ # However, rsp files don't work correctly on Mac.
+ if flavor != 'mac':
+ output.write('set(CMAKE_NINJA_FORCE_RESPONSE_FILE 1)\n')
+ output.write('\n')
+
+ namer = CMakeNamer(target_list)
+
+ # The list of targets upon which the 'all' target should depend.
+ # CMake has it's own implicit 'all' target, one is not created explicitly.
+ all_qualified_targets = set()
+ for build_file in params['build_files']:
+ for qualified_target in gyp.common.AllTargets(target_list,
+ target_dicts,
+ os.path.normpath(build_file)):
+ all_qualified_targets.add(qualified_target)
+
+ for qualified_target in target_list:
+ if flavor == 'mac':
+ gyp_file, _, _ = gyp.common.ParseQualifiedTarget(qualified_target)
+ spec = target_dicts[qualified_target]
+ gyp.xcode_emulation.MergeGlobalXcodeSettingsToSpec(data[gyp_file], spec)
+
+ WriteTarget(namer, qualified_target, target_dicts, build_dir, config_to_use,
+ options, generator_flags, all_qualified_targets, flavor, output)
+
+ output.close()
+
+
+def PerformBuild(data, configurations, params):
+ options = params['options']
+ generator_flags = params['generator_flags']
+
+ # generator_dir: relative path from pwd to where make puts build files.
+ # Makes migrating from make to cmake easier, cmake doesn't put anything here.
+ generator_dir = os.path.relpath(options.generator_output or '.')
+
+ # output_dir: relative path from generator_dir to the build directory.
+ output_dir = generator_flags.get('output_dir', 'out')
+
+ for config_name in configurations:
+ # build_dir: relative path from source root to our output files.
+ # e.g. "out/Debug"
+ build_dir = os.path.normpath(os.path.join(generator_dir,
+ output_dir,
+ config_name))
+ arguments = ['cmake', '-G', 'Ninja']
+ print 'Generating [%s]: %s' % (config_name, arguments)
+ subprocess.check_call(arguments, cwd=build_dir)
+
+ arguments = ['ninja', '-C', build_dir]
+ print 'Building [%s]: %s' % (config_name, arguments)
+ subprocess.check_call(arguments)
+
+
+def CallGenerateOutputForConfig(arglist):
+ # Ignore the interrupt signal so that the parent process catches it and
+ # kills all multiprocessing children.
+ signal.signal(signal.SIGINT, signal.SIG_IGN)
+
+ target_list, target_dicts, data, params, config_name = arglist
+ GenerateOutputForConfig(target_list, target_dicts, data, params, config_name)
+
+
+def GenerateOutput(target_list, target_dicts, data, params):
+ user_config = params.get('generator_flags', {}).get('config', None)
+ if user_config:
+ GenerateOutputForConfig(target_list, target_dicts, data,
+ params, user_config)
+ else:
+ config_names = target_dicts[target_list[0]]['configurations'].keys()
+ if params['parallel']:
+ try:
+ pool = multiprocessing.Pool(len(config_names))
+ arglists = []
+ for config_name in config_names:
+ arglists.append((target_list, target_dicts, data,
+ params, config_name))
+ pool.map(CallGenerateOutputForConfig, arglists)
+ except KeyboardInterrupt, e:
+ pool.terminate()
+ raise e
+ else:
+ for config_name in config_names:
+ GenerateOutputForConfig(target_list, target_dicts, data,
+ params, config_name)
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/dump_dependency_json.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/dump_dependency_json.py
@@ -9,27 +9,31 @@ import gyp.common
import gyp.msvs_emulation
import json
import sys
generator_supports_multiple_toolsets = True
generator_wants_static_library_dependencies_adjusted = False
+generator_filelist_paths = {
+}
+
generator_default_variables = {
}
for dirname in ['INTERMEDIATE_DIR', 'SHARED_INTERMEDIATE_DIR', 'PRODUCT_DIR',
'LIB_DIR', 'SHARED_LIB_DIR']:
# Some gyp steps fail if these are empty(!).
generator_default_variables[dirname] = 'dir'
for unused in ['RULE_INPUT_PATH', 'RULE_INPUT_ROOT', 'RULE_INPUT_NAME',
'RULE_INPUT_DIRNAME', 'RULE_INPUT_EXT',
'EXECUTABLE_PREFIX', 'EXECUTABLE_SUFFIX',
'STATIC_LIB_PREFIX', 'STATIC_LIB_SUFFIX',
- 'SHARED_LIB_PREFIX', 'SHARED_LIB_SUFFIX']:
+ 'SHARED_LIB_PREFIX', 'SHARED_LIB_SUFFIX',
+ 'CONFIGURATION_NAME']:
generator_default_variables[unused] = ''
def CalculateVariables(default_variables, params):
generator_flags = params.get('generator_flags', {})
for key, val in generator_flags.items():
default_variables.setdefault(key, val)
default_variables.setdefault('OS', gyp.common.GetFlavor(params))
@@ -39,39 +43,38 @@ def CalculateVariables(default_variables
# Copy additional generator configuration data from VS, which is shared
# by the Windows Ninja generator.
import gyp.generator.msvs as msvs_generator
generator_additional_non_configuration_keys = getattr(msvs_generator,
'generator_additional_non_configuration_keys', [])
generator_additional_path_sections = getattr(msvs_generator,
'generator_additional_path_sections', [])
- # Set a variable so conditions can be based on msvs_version.
- msvs_version = gyp.msvs_emulation.GetVSVersion(generator_flags)
- default_variables['MSVS_VERSION'] = msvs_version.ShortName()
-
- # To determine processor word size on Windows, in addition to checking
- # PROCESSOR_ARCHITECTURE (which reflects the word size of the current
- # process), it is also necessary to check PROCESSOR_ARCHITEW6432 (which
- # contains the actual word size of the system when running thru WOW64).
- if ('64' in os.environ.get('PROCESSOR_ARCHITECTURE', '') or
- '64' in os.environ.get('PROCESSOR_ARCHITEW6432', '')):
- default_variables['MSVS_OS_BITS'] = 64
- else:
- default_variables['MSVS_OS_BITS'] = 32
+ gyp.msvs_emulation.CalculateCommonVariables(default_variables, params)
def CalculateGeneratorInputInfo(params):
"""Calculate the generator specific info that gets fed to input (called by
gyp)."""
generator_flags = params.get('generator_flags', {})
if generator_flags.get('adjust_static_libraries', False):
global generator_wants_static_library_dependencies_adjusted
generator_wants_static_library_dependencies_adjusted = True
+ toplevel = params['options'].toplevel_dir
+ generator_dir = os.path.relpath(params['options'].generator_output or '.')
+ # output_dir: relative path from generator_dir to the build directory.
+ output_dir = generator_flags.get('output_dir', 'out')
+ qualified_out_dir = os.path.normpath(os.path.join(
+ toplevel, generator_dir, output_dir, 'gypfiles'))
+ global generator_filelist_paths
+ generator_filelist_paths = {
+ 'toplevel': toplevel,
+ 'qualified_out_dir': qualified_out_dir,
+ }
def GenerateOutput(target_list, target_dicts, data, params):
# Map of target -> list of targets it depends on.
edges = {}
# Queue of targets to visit.
targets_to_visit = target_list[:]
@@ -80,13 +83,17 @@ def GenerateOutput(target_list, target_d
if target in edges:
continue
edges[target] = []
for dep in target_dicts[target].get('dependencies', []):
edges[target].append(dep)
targets_to_visit.append(dep)
- filename = 'dump.json'
+ try:
+ filepath = params['generator_flags']['output_dir']
+ except KeyError:
+ filepath = '.'
+ filename = os.path.join(filepath, 'dump.json')
f = open(filename, 'w')
json.dump(edges, f)
f.close()
print 'Wrote json to %s.' % filename
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/eclipse.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/eclipse.py
@@ -17,168 +17,224 @@ still result in a few indexer issues her
This generator has no automated tests, so expect it to be broken.
"""
from xml.sax.saxutils import escape
import os.path
import subprocess
import gyp
import gyp.common
+import gyp.msvs_emulation
import shlex
+import xml.etree.cElementTree as ET
generator_wants_static_library_dependencies_adjusted = False
generator_default_variables = {
}
for dirname in ['INTERMEDIATE_DIR', 'PRODUCT_DIR', 'LIB_DIR', 'SHARED_LIB_DIR']:
- # Some gyp steps fail if these are empty(!).
- generator_default_variables[dirname] = 'dir'
+ # Some gyp steps fail if these are empty(!), so we convert them to variables
+ generator_default_variables[dirname] = '$' + dirname
for unused in ['RULE_INPUT_PATH', 'RULE_INPUT_ROOT', 'RULE_INPUT_NAME',
'RULE_INPUT_DIRNAME', 'RULE_INPUT_EXT',
'EXECUTABLE_PREFIX', 'EXECUTABLE_SUFFIX',
'STATIC_LIB_PREFIX', 'STATIC_LIB_SUFFIX',
'SHARED_LIB_PREFIX', 'SHARED_LIB_SUFFIX',
'CONFIGURATION_NAME']:
generator_default_variables[unused] = ''
-# Include dirs will occasionaly use the SHARED_INTERMEDIATE_DIR variable as
+# Include dirs will occasionally use the SHARED_INTERMEDIATE_DIR variable as
# part of the path when dealing with generated headers. This value will be
# replaced dynamically for each configuration.
generator_default_variables['SHARED_INTERMEDIATE_DIR'] = \
- '$SHARED_INTERMEDIATES_DIR'
+ '$SHARED_INTERMEDIATE_DIR'
def CalculateVariables(default_variables, params):
generator_flags = params.get('generator_flags', {})
for key, val in generator_flags.items():
default_variables.setdefault(key, val)
- default_variables.setdefault('OS', gyp.common.GetFlavor(params))
+ flavor = gyp.common.GetFlavor(params)
+ default_variables.setdefault('OS', flavor)
+ if flavor == 'win':
+ # Copy additional generator configuration data from VS, which is shared
+ # by the Eclipse generator.
+ import gyp.generator.msvs as msvs_generator
+ generator_additional_non_configuration_keys = getattr(msvs_generator,
+ 'generator_additional_non_configuration_keys', [])
+ generator_additional_path_sections = getattr(msvs_generator,
+ 'generator_additional_path_sections', [])
+
+ gyp.msvs_emulation.CalculateCommonVariables(default_variables, params)
def CalculateGeneratorInputInfo(params):
"""Calculate the generator specific info that gets fed to input (called by
gyp)."""
generator_flags = params.get('generator_flags', {})
if generator_flags.get('adjust_static_libraries', False):
global generator_wants_static_library_dependencies_adjusted
generator_wants_static_library_dependencies_adjusted = True
def GetAllIncludeDirectories(target_list, target_dicts,
- shared_intermediates_dir, config_name):
+ shared_intermediate_dirs, config_name, params,
+ compiler_path):
"""Calculate the set of include directories to be used.
Returns:
A list including all the include_dir's specified for every target followed
by any include directories that were added as cflag compiler options.
"""
gyp_includes_set = set()
compiler_includes_list = []
+ # Find compiler's default include dirs.
+ if compiler_path:
+ command = shlex.split(compiler_path)
+ command.extend(['-E', '-xc++', '-v', '-'])
+ proc = subprocess.Popen(args=command, stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ output = proc.communicate()[1]
+ # Extract the list of include dirs from the output, which has this format:
+ # ...
+ # #include "..." search starts here:
+ # #include <...> search starts here:
+ # /usr/include/c++/4.6
+ # /usr/local/include
+ # End of search list.
+ # ...
+ in_include_list = False
+ for line in output.splitlines():
+ if line.startswith('#include'):
+ in_include_list = True
+ continue
+ if line.startswith('End of search list.'):
+ break
+ if in_include_list:
+ include_dir = line.strip()
+ if include_dir not in compiler_includes_list:
+ compiler_includes_list.append(include_dir)
+
+ flavor = gyp.common.GetFlavor(params)
+ if flavor == 'win':
+ generator_flags = params.get('generator_flags', {})
for target_name in target_list:
target = target_dicts[target_name]
if config_name in target['configurations']:
config = target['configurations'][config_name]
# Look for any include dirs that were explicitly added via cflags. This
# may be done in gyp files to force certain includes to come at the end.
# TODO(jgreenwald): Change the gyp files to not abuse cflags for this, and
# remove this.
- cflags = config['cflags']
+ if flavor == 'win':
+ msvs_settings = gyp.msvs_emulation.MsvsSettings(target, generator_flags)
+ cflags = msvs_settings.GetCflags(config_name)
+ else:
+ cflags = config['cflags']
for cflag in cflags:
- include_dir = ''
if cflag.startswith('-I'):
include_dir = cflag[2:]
- if include_dir and not include_dir in compiler_includes_list:
- compiler_includes_list.append(include_dir)
+ if include_dir not in compiler_includes_list:
+ compiler_includes_list.append(include_dir)
# Find standard gyp include dirs.
if config.has_key('include_dirs'):
include_dirs = config['include_dirs']
- for include_dir in include_dirs:
- include_dir = include_dir.replace('$SHARED_INTERMEDIATES_DIR',
- shared_intermediates_dir)
- if not os.path.isabs(include_dir):
- base_dir = os.path.dirname(target_name)
+ for shared_intermediate_dir in shared_intermediate_dirs:
+ for include_dir in include_dirs:
+ include_dir = include_dir.replace('$SHARED_INTERMEDIATE_DIR',
+ shared_intermediate_dir)
+ if not os.path.isabs(include_dir):
+ base_dir = os.path.dirname(target_name)
- include_dir = base_dir + '/' + include_dir
- include_dir = os.path.abspath(include_dir)
+ include_dir = base_dir + '/' + include_dir
+ include_dir = os.path.abspath(include_dir)
- if not include_dir in gyp_includes_set:
gyp_includes_set.add(include_dir)
-
# Generate a list that has all the include dirs.
all_includes_list = list(gyp_includes_set)
all_includes_list.sort()
for compiler_include in compiler_includes_list:
if not compiler_include in gyp_includes_set:
all_includes_list.append(compiler_include)
# All done.
return all_includes_list
-def GetCompilerPath(target_list, target_dicts, data):
+def GetCompilerPath(target_list, data, options):
"""Determine a command that can be used to invoke the compiler.
Returns:
If this is a gyp project that has explicit make settings, try to determine
the compiler from that. Otherwise, see if a compiler was specified via the
CC_target environment variable.
"""
-
# First, see if the compiler is configured in make's settings.
build_file, _, _ = gyp.common.ParseQualifiedTarget(target_list[0])
make_global_settings_dict = data[build_file].get('make_global_settings', {})
for key, value in make_global_settings_dict:
if key in ['CC', 'CXX']:
- return value
+ return os.path.join(options.toplevel_dir, value)
# Check to see if the compiler was specified as an environment variable.
for key in ['CC_target', 'CC', 'CXX']:
compiler = os.environ.get(key)
if compiler:
return compiler
return 'gcc'
-def GetAllDefines(target_list, target_dicts, data, config_name):
+def GetAllDefines(target_list, target_dicts, data, config_name, params,
+ compiler_path):
"""Calculate the defines for a project.
Returns:
A dict that includes explict defines declared in gyp files along with all of
the default defines that the compiler uses.
"""
# Get defines declared in the gyp files.
all_defines = {}
+ flavor = gyp.common.GetFlavor(params)
+ if flavor == 'win':
+ generator_flags = params.get('generator_flags', {})
for target_name in target_list:
target = target_dicts[target_name]
+ if flavor == 'win':
+ msvs_settings = gyp.msvs_emulation.MsvsSettings(target, generator_flags)
+ extra_defines = msvs_settings.GetComputedDefines(config_name)
+ else:
+ extra_defines = []
if config_name in target['configurations']:
config = target['configurations'][config_name]
- for define in config['defines']:
- split_define = define.split('=', 1)
- if len(split_define) == 1:
- split_define.append('1')
- if split_define[0].strip() in all_defines:
- # Already defined
- continue
-
- all_defines[split_define[0].strip()] = split_define[1].strip()
-
+ target_defines = config['defines']
+ else:
+ target_defines = []
+ for define in target_defines + extra_defines:
+ split_define = define.split('=', 1)
+ if len(split_define) == 1:
+ split_define.append('1')
+ if split_define[0].strip() in all_defines:
+ # Already defined
+ continue
+ all_defines[split_define[0].strip()] = split_define[1].strip()
# Get default compiler defines (if possible).
- cc_target = GetCompilerPath(target_list, target_dicts, data)
- if cc_target:
- command = shlex.split(cc_target)
+ if flavor == 'win':
+ return all_defines # Default defines already processed in the loop above.
+ if compiler_path:
+ command = shlex.split(compiler_path)
command.extend(['-E', '-dM', '-'])
cpp_proc = subprocess.Popen(args=command, cwd='.',
stdin=subprocess.PIPE, stdout=subprocess.PIPE)
cpp_output = cpp_proc.communicate()[0]
cpp_lines = cpp_output.split('\n')
for cpp_line in cpp_lines:
if not cpp_line.strip():
continue
@@ -229,42 +285,138 @@ def GenerateOutputForConfig(target_list,
generator_flags = params.get('generator_flags', {})
# build_dir: relative path from source root to our output files.
# e.g. "out/Debug"
build_dir = os.path.join(generator_flags.get('output_dir', 'out'),
config_name)
toplevel_build = os.path.join(options.toplevel_dir, build_dir)
- shared_intermediate_dir = os.path.join(toplevel_build, 'obj', 'gen')
+ # Ninja uses out/Debug/gen while make uses out/Debug/obj/gen as the
+ # SHARED_INTERMEDIATE_DIR. Include both possible locations.
+ shared_intermediate_dirs = [os.path.join(toplevel_build, 'obj', 'gen'),
+ os.path.join(toplevel_build, 'gen')]
+
+ GenerateCdtSettingsFile(target_list,
+ target_dicts,
+ data,
+ params,
+ config_name,
+ os.path.join(toplevel_build,
+ 'eclipse-cdt-settings.xml'),
+ options,
+ shared_intermediate_dirs)
+ GenerateClasspathFile(target_list,
+ target_dicts,
+ options.toplevel_dir,
+ toplevel_build,
+ os.path.join(toplevel_build,
+ 'eclipse-classpath.xml'))
+
- if not os.path.exists(toplevel_build):
- os.makedirs(toplevel_build)
- out = open(os.path.join(toplevel_build, 'eclipse-cdt-settings.xml'), 'w')
+def GenerateCdtSettingsFile(target_list, target_dicts, data, params,
+ config_name, out_name, options,
+ shared_intermediate_dirs):
+ gyp.common.EnsureDirExists(out_name)
+ with open(out_name, 'w') as out:
+ out.write('<?xml version="1.0" encoding="UTF-8"?>\n')
+ out.write('<cdtprojectproperties>\n')
- out.write('<?xml version="1.0" encoding="UTF-8"?>\n')
- out.write('<cdtprojectproperties>\n')
+ eclipse_langs = ['C++ Source File', 'C Source File', 'Assembly Source File',
+ 'GNU C++', 'GNU C', 'Assembly']
+ compiler_path = GetCompilerPath(target_list, data, options)
+ include_dirs = GetAllIncludeDirectories(target_list, target_dicts,
+ shared_intermediate_dirs,
+ config_name, params, compiler_path)
+ WriteIncludePaths(out, eclipse_langs, include_dirs)
+ defines = GetAllDefines(target_list, target_dicts, data, config_name,
+ params, compiler_path)
+ WriteMacros(out, eclipse_langs, defines)
+
+ out.write('</cdtprojectproperties>\n')
+
+
+def GenerateClasspathFile(target_list, target_dicts, toplevel_dir,
+ toplevel_build, out_name):
+ '''Generates a classpath file suitable for symbol navigation and code
+ completion of Java code (such as in Android projects) by finding all
+ .java and .jar files used as action inputs.'''
+ gyp.common.EnsureDirExists(out_name)
+ result = ET.Element('classpath')
- eclipse_langs = ['C++ Source File', 'C Source File', 'Assembly Source File',
- 'GNU C++', 'GNU C', 'Assembly']
- include_dirs = GetAllIncludeDirectories(target_list, target_dicts,
- shared_intermediate_dir, config_name)
- WriteIncludePaths(out, eclipse_langs, include_dirs)
- defines = GetAllDefines(target_list, target_dicts, data, config_name)
- WriteMacros(out, eclipse_langs, defines)
+ def AddElements(kind, paths):
+ # First, we need to normalize the paths so they are all relative to the
+ # toplevel dir.
+ rel_paths = set()
+ for path in paths:
+ if os.path.isabs(path):
+ rel_paths.add(os.path.relpath(path, toplevel_dir))
+ else:
+ rel_paths.add(path)
+
+ for path in sorted(rel_paths):
+ entry_element = ET.SubElement(result, 'classpathentry')
+ entry_element.set('kind', kind)
+ entry_element.set('path', path)
+
+ AddElements('lib', GetJavaJars(target_list, target_dicts, toplevel_dir))
+ AddElements('src', GetJavaSourceDirs(target_list, target_dicts, toplevel_dir))
+ # Include the standard JRE container and a dummy out folder
+ AddElements('con', ['org.eclipse.jdt.launching.JRE_CONTAINER'])
+ # Include a dummy out folder so that Eclipse doesn't use the default /bin
+ # folder in the root of the project.
+ AddElements('output', [os.path.join(toplevel_build, '.eclipse-java-build')])
+
+ ET.ElementTree(result).write(out_name)
+
- out.write('</cdtprojectproperties>\n')
- out.close()
+def GetJavaJars(target_list, target_dicts, toplevel_dir):
+ '''Generates a sequence of all .jars used as inputs.'''
+ for target_name in target_list:
+ target = target_dicts[target_name]
+ for action in target.get('actions', []):
+ for input_ in action['inputs']:
+ if os.path.splitext(input_)[1] == '.jar' and not input_.startswith('$'):
+ if os.path.isabs(input_):
+ yield input_
+ else:
+ yield os.path.join(os.path.dirname(target_name), input_)
+
+
+def GetJavaSourceDirs(target_list, target_dicts, toplevel_dir):
+ '''Generates a sequence of all likely java package root directories.'''
+ for target_name in target_list:
+ target = target_dicts[target_name]
+ for action in target.get('actions', []):
+ for input_ in action['inputs']:
+ if (os.path.splitext(input_)[1] == '.java' and
+ not input_.startswith('$')):
+ dir_ = os.path.dirname(os.path.join(os.path.dirname(target_name),
+ input_))
+ # If there is a parent 'src' or 'java' folder, navigate up to it -
+ # these are canonical package root names in Chromium. This will
+ # break if 'src' or 'java' exists in the package structure. This
+ # could be further improved by inspecting the java file for the
+ # package name if this proves to be too fragile in practice.
+ parent_search = dir_
+ while os.path.basename(parent_search) not in ['src', 'java']:
+ parent_search, _ = os.path.split(parent_search)
+ if not parent_search or parent_search == toplevel_dir:
+ # Didn't find a known root, just return the original path
+ yield dir_
+ break
+ else:
+ yield parent_search
def GenerateOutput(target_list, target_dicts, data, params):
"""Generate an XML settings file that can be imported into a CDT project."""
if params['options'].generator_output:
- raise NotImplementedError, "--generator_output not implemented for eclipse"
+ raise NotImplementedError("--generator_output not implemented for eclipse")
user_config = params.get('generator_flags', {}).get('config', None)
if user_config:
GenerateOutputForConfig(target_list, target_dicts, data, params,
user_config)
else:
config_names = target_dicts[target_list[0]]['configurations'].keys()
for config_name in config_names:
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/gypd.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/gypd.py
@@ -34,26 +34,33 @@ to change.
import gyp.common
import errno
import os
import pprint
# These variables should just be spit back out as variable references.
_generator_identity_variables = [
+ 'CONFIGURATION_NAME',
'EXECUTABLE_PREFIX',
'EXECUTABLE_SUFFIX',
'INTERMEDIATE_DIR',
+ 'LIB_DIR',
'PRODUCT_DIR',
'RULE_INPUT_ROOT',
'RULE_INPUT_DIRNAME',
'RULE_INPUT_EXT',
'RULE_INPUT_NAME',
'RULE_INPUT_PATH',
'SHARED_INTERMEDIATE_DIR',
+ 'SHARED_LIB_DIR',
+ 'SHARED_LIB_PREFIX',
+ 'SHARED_LIB_SUFFIX',
+ 'STATIC_LIB_PREFIX',
+ 'STATIC_LIB_SUFFIX',
]
# gypd doesn't define a default value for OS like many other generator
# modules. Specify "-D OS=whatever" on the command line to provide a value.
generator_default_variables = {
}
# gypd supports multiple toolsets
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/make.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/make.py
@@ -1,9 +1,9 @@
-# Copyright (c) 2012 Google Inc. All rights reserved.
+# Copyright (c) 2013 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.
# Notes:
#
# This is all roughly based on the Makefile system used by the Linux
# kernel, but is a non-recursive make -- we put the entire dependency
# graph in front of make and let it figure it out.
@@ -24,16 +24,17 @@
import os
import re
import sys
import subprocess
import gyp
import gyp.common
import gyp.xcode_emulation
from gyp.common import GetEnvironFallback
+from gyp.common import GypError
generator_default_variables = {
'EXECUTABLE_PREFIX': '',
'EXECUTABLE_SUFFIX': '',
'STATIC_LIB_PREFIX': 'lib',
'SHARED_LIB_PREFIX': 'lib',
'STATIC_LIB_SUFFIX': '.a',
'INTERMEDIATE_DIR': '$(obj).$(TOOLSET)/$(TARGET)/geni',
@@ -52,16 +53,17 @@ generator_supports_multiple_toolsets = T
# Request sorted dependencies in the order from dependents to dependencies.
generator_wants_sorted_dependencies = False
# Placates pylint.
generator_additional_non_configuration_keys = []
generator_additional_path_sections = []
generator_extra_sources_for_rules = []
+generator_filelist_paths = None
def CalculateVariables(default_variables, params):
"""Calculate additional variables for use in the build (called by gyp)."""
flavor = gyp.common.GetFlavor(params)
if flavor == 'mac':
default_variables.setdefault('OS', 'mac')
default_variables.setdefault('SHARED_LIB_SUFFIX', '.dylib')
@@ -98,21 +100,27 @@ def CalculateGeneratorInputInfo(params):
gyp)."""
generator_flags = params.get('generator_flags', {})
android_ndk_version = generator_flags.get('android_ndk_version', None)
# Android NDK requires a strict link order.
if android_ndk_version:
global generator_wants_sorted_dependencies
generator_wants_sorted_dependencies = True
+ output_dir = params['options'].generator_output or \
+ params['options'].toplevel_dir
+ builddir_name = generator_flags.get('output_dir', 'out')
+ qualified_out_dir = os.path.normpath(os.path.join(
+ output_dir, builddir_name, 'gypfiles'))
-def ensure_directory_exists(path):
- dir = os.path.dirname(path)
- if dir and not os.path.exists(dir):
- os.makedirs(dir)
+ global generator_filelist_paths
+ generator_filelist_paths = {
+ 'toplevel': params['options'].toplevel_dir,
+ 'qualified_out_dir': qualified_out_dir,
+ }
# The .d checking code below uses these functions:
# wildcard, sort, foreach, shell, wordlist
# wildcard can handle spaces, the rest can't.
# Since I could find no way to make foreach work with spaces in filenames
# correctly, the .d files have spaces replaced with another character. The .d
# file for
@@ -161,25 +169,21 @@ cmd_solink_module = $(LINK.$(TOOLSET)) -
LINK_COMMANDS_MAC = """\
quiet_cmd_alink = LIBTOOL-STATIC $@
cmd_alink = rm -f $@ && ./gyp-mac-tool filter-libtool libtool $(GYP_LIBTOOLFLAGS) -static -o $@ $(filter %.o,$^)
quiet_cmd_link = LINK($(TOOLSET)) $@
cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o "$@" $(LD_INPUTS) $(LIBS)
-# TODO(thakis): Find out and document the difference between shared_library and
-# loadable_module on mac.
quiet_cmd_solink = SOLINK($(TOOLSET)) $@
cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o "$@" $(LD_INPUTS) $(LIBS)
-# TODO(thakis): The solink_module rule is likely wrong. Xcode seems to pass
-# -bundle -single_module here (for osmesa.so).
quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@
-cmd_solink_module = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(filter-out FORCE_DO_CMD, $^) $(LIBS)
+cmd_solink_module = $(LINK.$(TOOLSET)) -bundle $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(filter-out FORCE_DO_CMD, $^) $(LIBS)
"""
LINK_COMMANDS_ANDROID = """\
quiet_cmd_alink = AR($(TOOLSET)) $@
cmd_alink = rm -f $@ && $(AR.$(TOOLSET)) crs $@ $(filter %.o,$^)
quiet_cmd_alink_thin = AR($(TOOLSET)) $@
cmd_alink_thin = rm -f $@ && $(AR.$(TOOLSET)) crsT $@ $(filter %.o,$^)
@@ -200,16 +204,34 @@ cmd_solink = $(LINK.$(TOOLSET)) -shared
quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@
cmd_solink_module = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--start-group $(filter-out FORCE_DO_CMD, $^) -Wl,--end-group $(LIBS)
quiet_cmd_solink_module_host = SOLINK_MODULE($(TOOLSET)) $@
cmd_solink_module_host = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ $(filter-out FORCE_DO_CMD, $^) $(LIBS)
"""
+LINK_COMMANDS_AIX = """\
+quiet_cmd_alink = AR($(TOOLSET)) $@
+cmd_alink = rm -f $@ && $(AR.$(TOOLSET)) -X32_64 crs $@ $(filter %.o,$^)
+
+quiet_cmd_alink_thin = AR($(TOOLSET)) $@
+cmd_alink_thin = rm -f $@ && $(AR.$(TOOLSET)) -X32_64 crs $@ $(filter %.o,$^)
+
+quiet_cmd_link = LINK($(TOOLSET)) $@
+cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(LD_INPUTS) $(LIBS)
+
+quiet_cmd_solink = SOLINK($(TOOLSET)) $@
+cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(LD_INPUTS) $(LIBS)
+
+quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@
+cmd_solink_module = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(filter-out FORCE_DO_CMD, $^) $(LIBS)
+"""
+
+
# Header of toplevel Makefile.
# This should go into the build tree, but it's easier to keep it here for now.
SHARED_HEADER = ("""\
# We borrow heavily from the kernel build setup, though we are simpler since
# we don't have Kconfig tweaking settings on us.
# The implicit make rules have it looking for RCS files, among other things.
# We instead explicitly write all the rules we care about.
@@ -245,41 +267,33 @@ obj := $(builddir)/obj
abs_obj := $(abspath $(obj))
# We build up a list of every single one of the targets so we can slurp in the
# generated dependency rule Makefiles in one pass.
all_deps :=
%(make_global_settings)s
-# C++ apps need to be linked with g++.
-#
-# Note: flock is used to seralize linking. Linking is a memory-intensive
-# process so running parallel links can often lead to thrashing. To disable
-# the serialization, override LINK via an envrionment variable as follows:
-#
-# export LINK=g++
-#
-# This will allow make to invoke N linker processes as specified in -jN.
-LINK ?= %(flock)s $(builddir)/linker.lock $(CXX)
-
CC.target ?= %(CC.target)s
-CFLAGS.target ?= $(CFLAGS)
+CFLAGS.target ?= $(CPPFLAGS) $(CFLAGS)
CXX.target ?= %(CXX.target)s
-CXXFLAGS.target ?= $(CXXFLAGS)
+CXXFLAGS.target ?= $(CPPFLAGS) $(CXXFLAGS)
LINK.target ?= %(LINK.target)s
LDFLAGS.target ?= $(LDFLAGS)
AR.target ?= $(AR)
+# C++ apps need to be linked with g++.
+LINK ?= $(CXX.target)
+
# TODO(evan): move all cross-compilation logic to gyp-time so we don't need
# to replicate this environment fallback in make as well.
CC.host ?= %(CC.host)s
-CFLAGS.host ?=
+CFLAGS.host ?= $(CPPFLAGS_host) $(CFLAGS_host)
CXX.host ?= %(CXX.host)s
-CXXFLAGS.host ?=
+CXXFLAGS.host ?= $(CPPFLAGS_host) $(CXXFLAGS_host)
LINK.host ?= %(LINK.host)s
LDFLAGS.host ?=
AR.host ?= %(AR.host)s
# Define a dir function that can handle spaces.
# http://www.gnu.org/software/make/manual/make.html#Syntax-of-Functions
# "leading spaces cannot appear in the text of the first argument as written.
# These characters can be put into the argument value by variable substitution."
@@ -346,17 +360,17 @@ cmd_cc = $(CC.$(TOOLSET)) $(GYP_CFLAGS)
quiet_cmd_cxx = CXX($(TOOLSET)) $@
cmd_cxx = $(CXX.$(TOOLSET)) $(GYP_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $<
%(extra_commands)s
quiet_cmd_touch = TOUCH $@
cmd_touch = touch $@
quiet_cmd_copy = COPY $@
# send stderr to /dev/null to ignore messages when linking directories.
-cmd_copy = ln -f "$<" "$@" 2>/dev/null || (rm -rf "$@" && cp -af "$<" "$@")
+cmd_copy = ln -f "$<" "$@" 2>/dev/null || (rm -rf "$@" && cp %(copy_archive_args)s "$<" "$@")
%(link_commands)s
"""
r"""
# Define an escape_quotes function to escape single quotes.
# This allows us to handle quotes properly as long as we always use
# use single quotes and escape_quotes.
@@ -390,25 +404,24 @@ command_changed = $(or $(subst $(cmd_$(1
# Helper that is non-empty when a prerequisite changes.
# Normally make does this implicitly, but we force rules to always run
# so we can check their command lines.
# $? -- new prerequisites
# $| -- order-only dependencies
prereq_changed = $(filter-out FORCE_DO_CMD,$(filter-out $|,$?))
-# Helper that executes all postbuilds, and deletes the output file when done
-# if any of the postbuilds failed.
+# Helper that executes all postbuilds until one fails.
define do_postbuilds
@E=0;\\
for p in $(POSTBUILDS); do\\
eval $$p;\\
- F=$$?;\\
- if [ $$F -ne 0 ]; then\\
- E=$$F;\\
+ E=$$?;\\
+ if [ $$E -ne 0 ]; then\\
+ break;\\
fi;\\
done;\\
if [ $$E -ne 0 ]; then\\
rm -rf "$@";\\
exit $$E;\\
fi
endef
@@ -479,24 +492,16 @@ cmd_mac_tool = ./gyp-mac-tool $(4) $< "$
quiet_cmd_mac_package_framework = PACKAGE FRAMEWORK $@
cmd_mac_package_framework = ./gyp-mac-tool package-framework "$@" $(4)
quiet_cmd_infoplist = INFOPLIST $@
cmd_infoplist = $(CC.$(TOOLSET)) -E -P -Wno-trigraphs -x c $(INFOPLIST_DEFINES) "$<" -o "$@"
"""
-SHARED_HEADER_SUN_COMMANDS = """
-# gyp-sun-tool is written next to the root Makefile by gyp.
-# Use $(4) for the command, since $(2) and $(3) are used as flag by do_cmd
-# already.
-quiet_cmd_sun_tool = SUNTOOL $(4) $<
-cmd_sun_tool = ./gyp-sun-tool $(4) $< "$@"
-"""
-
def WriteRootHeaderSuffixRules(writer):
extensions = sorted(COMPILABLE_EXTENSIONS.keys(), key=str.lower)
writer.write('# Suffix rules, putting all outputs into $(obj).\n')
for ext in extensions:
writer.write('$(obj).$(TOOLSET)/%%.o: $(srcdir)/%%%s FORCE_DO_CMD\n' % ext)
writer.write('\t@$(call do_cmd,%s,1)\n' % COMPILABLE_EXTENSIONS[ext])
@@ -614,41 +619,58 @@ def Sourceify(path):
return path
return srcdir_prefix + path
def QuoteSpaces(s, quote=r'\ '):
return s.replace(' ', quote)
-def InvertRelativePath(path):
- """Given a relative path like foo/bar, return the inverse relative path:
- the path from the relative path back to the origin dir.
+# TODO: Avoid code duplication with _ValidateSourcesForMSVSProject in msvs.py.
+def _ValidateSourcesForOSX(spec, all_sources):
+ """Makes sure if duplicate basenames are not specified in the source list.
- E.g. os.path.normpath(os.path.join(path, InvertRelativePath(path)))
- should always produce the empty string."""
+ Arguments:
+ spec: The target dictionary containing the properties of the target.
+ """
+ if spec.get('type', None) != 'static_library':
+ return
- if not path:
- return path
- # Only need to handle relative paths into subdirectories for now.
- assert '..' not in path, path
- depth = len(path.split(os.path.sep))
- return os.path.sep.join(['..'] * depth)
+ basenames = {}
+ for source in all_sources:
+ name, ext = os.path.splitext(source)
+ is_compiled_file = ext in [
+ '.c', '.cc', '.cpp', '.cxx', '.m', '.mm', '.s', '.S']
+ if not is_compiled_file:
+ continue
+ basename = os.path.basename(name) # Don't include extension.
+ basenames.setdefault(basename, []).append(source)
+
+ error = ''
+ for basename, files in basenames.iteritems():
+ if len(files) > 1:
+ error += ' %s: %s\n' % (basename, ' '.join(files))
+
+ if error:
+ print('static library %s has several files with the same basename:\n' %
+ spec['target_name'] + error + 'libtool on OS X will generate' +
+ ' warnings for them.')
+ raise GypError('Duplicate basenames in sources section, see list above')
# Map from qualified target to path to output.
target_outputs = {}
# Map from qualified target to any linkable output. A subset
# of target_outputs. E.g. when mybinary depends on liba, we want to
# include liba in the linker line; when otherbinary depends on
# mybinary, we just want to build mybinary first.
target_link_deps = {}
-class MakefileWriter:
+class MakefileWriter(object):
"""MakefileWriter packages up the writing of one target-specific foobar.mk.
Its only real entry point is Write(), and is mostly used for namespacing.
"""
def __init__(self, generator_flags, flavor):
self.generator_flags = generator_flags
self.flavor = flavor
@@ -683,17 +705,17 @@ class MakefileWriter:
Arguments:
qualified_target: target we're generating
base_path: path relative to source root we're building in, used to resolve
target-relative paths
output_filename: output .mk file name to write
spec, configs: gyp info
part_of_all: flag indicating this target is part of 'all'
"""
- ensure_directory_exists(output_filename)
+ gyp.common.EnsureDirExists(output_filename)
self.fp = open(output_filename, 'w')
self.fp.write(header)
self.qualified_target = qualified_target
self.path = base_path
self.target = spec['target_name']
@@ -756,16 +778,20 @@ class MakefileWriter:
all_mac_bundle_resources = (
spec.get('mac_bundle_resources', []) + extra_mac_bundle_resources)
self.WriteMacBundleResources(all_mac_bundle_resources, mac_bundle_deps)
self.WriteMacInfoPlist(mac_bundle_deps)
# Sources.
all_sources = spec.get('sources', []) + extra_sources
if all_sources:
+ if self.flavor == 'mac':
+ # libtool on OS X generates warnings for duplicate basenames in the same
+ # target.
+ _ValidateSourcesForOSX(spec, all_sources)
self.WriteSources(
configs, deps, all_sources, extra_outputs,
extra_link_deps, part_of_all,
gyp.xcode_emulation.MacPrefixHeader(
self.xcode_settings, lambda p: Sourceify(self.Absolutify(p)),
self.Pchify))
sources = filter(Compilable, all_sources)
if sources:
@@ -812,17 +838,17 @@ class MakefileWriter:
the targets from a single gyp file (i.e. a sub-project).
Arguments:
output_filename: sub-project Makefile name to write
makefile_path: path to the top-level Makefile
targets: list of "all" targets for this sub-project
build_dir: build output directory, relative to the sub-project
"""
- ensure_directory_exists(output_filename)
+ gyp.common.EnsureDirExists(output_filename)
self.fp = open(output_filename, 'w')
self.fp.write(header)
# For consistency with other builders, put sub-project build output in the
# sub-project dir (see test/subdirectory/gyptest-subdir-all.py).
self.WriteLn('export builddir_name ?= %s' %
os.path.join(os.path.dirname(output_filename), build_dir))
self.WriteLn('.PHONY: all')
self.WriteLn('all:')
@@ -988,18 +1014,25 @@ class MakefileWriter:
outputs = map(self.Absolutify, outputs)
all_outputs += outputs
# Only write the 'obj' and 'builddir' rules for the "primary" output
# (:1); it's superfluous for the "extra outputs", and this avoids
# accidentally writing duplicate dummy rules for those outputs.
self.WriteLn('%s: obj := $(abs_obj)' % outputs[0])
self.WriteLn('%s: builddir := $(abs_builddir)' % outputs[0])
- self.WriteMakeRule(outputs, inputs + ['FORCE_DO_CMD'], actions)
+ self.WriteMakeRule(outputs, inputs, actions,
+ command="%s_%d" % (name, count))
+ # Spaces in rule filenames are not supported, but rule variables have
+ # spaces in them (e.g. RULE_INPUT_PATH expands to '$(abspath $<)').
+ # The spaces within the variables are valid, so remove the variables
+ # before checking.
+ variables_with_spaces = re.compile(r'\$\([^ ]* \$<\)')
for output in outputs:
+ output = re.sub(variables_with_spaces, '', output)
assert ' ' not in output, (
"Spaces in rule filenames not yet supported (%s)" % output)
self.WriteLn('all_deps += %s' % ' '.join(outputs))
action = [self.ExpandInputRoot(ac, rule_source_root,
rule_source_dirname)
for ac in rule['action']]
mkdirs = ''
@@ -1093,19 +1126,22 @@ class MakefileWriter:
def WriteMacBundleResources(self, resources, bundle_deps):
"""Writes Makefile code for 'mac_bundle_resources'."""
self.WriteLn('### Generated for mac_bundle_resources')
for output, res in gyp.xcode_emulation.GetMacBundleResources(
generator_default_variables['PRODUCT_DIR'], self.xcode_settings,
map(Sourceify, map(self.Absolutify, resources))):
- self.WriteDoCmd([output], [res], 'mac_tool,,,copy-bundle-resource',
- part_of_all=True)
- bundle_deps.append(output)
+ _, ext = os.path.splitext(output)
+ if ext != '.xcassets':
+ # Make does not supports '.xcassets' emulation.
+ self.WriteDoCmd([output], [res], 'mac_tool,,,copy-bundle-resource',
+ part_of_all=True)
+ bundle_deps.append(output)
def WriteMacInfoPlist(self, bundle_deps):
"""Write Makefile code for bundle Info.plist files."""
info_plist, out, defines, extra_env = gyp.xcode_emulation.GetMacInfoPlist(
generator_default_variables['PRODUCT_DIR'], self.xcode_settings,
lambda p: Sourceify(self.Absolutify(p)))
if not info_plist:
@@ -1412,34 +1448,36 @@ class MakefileWriter:
for configname in sorted(configs.keys()):
config = configs[configname]
if self.flavor == 'mac':
ldflags = self.xcode_settings.GetLdflags(configname,
generator_default_variables['PRODUCT_DIR'],
lambda p: Sourceify(self.Absolutify(p)))
# TARGET_POSTBUILDS_$(BUILDTYPE) is added to postbuilds later on.
- gyp_to_build = InvertRelativePath(self.path)
- target_postbuild = self.xcode_settings.GetTargetPostbuilds(
+ gyp_to_build = gyp.common.InvertRelativePath(self.path)
+ target_postbuild = self.xcode_settings.AddImplicitPostbuilds(
configname,
QuoteSpaces(os.path.normpath(os.path.join(gyp_to_build,
self.output))),
QuoteSpaces(os.path.normpath(os.path.join(gyp_to_build,
self.output_binary))))
if target_postbuild:
target_postbuilds[configname] = target_postbuild
else:
ldflags = config.get('ldflags', [])
# Compute an rpath for this output if needed.
- if any(dep.endswith('.so') for dep in deps):
+ if any(dep.endswith('.so') or '.so.' in dep for dep in deps):
# We want to get the literal string "$ORIGIN" into the link command,
# so we need lots of escaping.
ldflags.append(r'-Wl,-rpath=\$$ORIGIN/lib.%s/' % self.toolset)
ldflags.append(r'-Wl,-rpath-link=\$(builddir)/lib.%s/' %
self.toolset)
+ library_dirs = config.get('library_dirs', [])
+ ldflags += [('-L%s' % library_dir) for library_dir in library_dirs]
self.WriteList(ldflags, 'LDFLAGS_%s' % configname)
if self.flavor == 'mac':
self.WriteList(self.xcode_settings.GetLibtoolflags(configname),
'LIBTOOLFLAGS_%s' % configname)
libraries = spec.get('libraries')
if libraries:
# Remove duplicate entries
libraries = gyp.common.uniquer(libraries)
@@ -1536,17 +1574,17 @@ class MakefileWriter:
else:
self.WriteDoCmd([self.output_binary], link_deps, 'link', part_of_all,
postbuilds=postbuilds)
elif self.type == 'static_library':
for link_dep in link_deps:
assert ' ' not in link_dep, (
"Spaces in alink input filenames not supported (%s)" % link_dep)
- if (self.flavor not in ('mac', 'win') and not
+ if (self.flavor not in ('mac', 'openbsd', 'netbsd', 'win') and not
self.is_standalone_static_library):
self.WriteDoCmd([self.output_binary], link_deps, 'alink_thin',
part_of_all, postbuilds=postbuilds)
else:
self.WriteDoCmd([self.output_binary], link_deps, 'alink', part_of_all,
postbuilds=postbuilds)
elif self.type == 'shared_library':
self.WriteLn('%s: LD_INPUTS := %s' % (
@@ -1646,85 +1684,81 @@ class MakefileWriter:
"""
suffix = ''
if postbuilds:
assert ',' not in command
suffix = ',,1' # Tell do_cmd to honor $POSTBUILDS
self.WriteMakeRule(outputs, inputs,
actions = ['$(call do_cmd,%s%s)' % (command, suffix)],
comment = comment,
+ command = command,
force = True)
# Add our outputs to the list of targets we read depfiles from.
# all_deps is only used for deps file reading, and for deps files we replace
# spaces with ? because escaping doesn't work with make's $(sort) and
# other functions.
outputs = [QuoteSpaces(o, SPACE_REPLACEMENT) for o in outputs]
self.WriteLn('all_deps += %s' % ' '.join(outputs))
def WriteMakeRule(self, outputs, inputs, actions=None, comment=None,
- order_only=False, force=False, phony=False):
+ order_only=False, force=False, phony=False, command=None):
"""Write a Makefile rule, with some extra tricks.
outputs: a list of outputs for the rule (note: this is not directly
supported by make; see comments below)
inputs: a list of inputs for the rule
actions: a list of shell commands to run for the rule
comment: a comment to put in the Makefile above the rule (also useful
for making this Python script's code self-documenting)
order_only: if true, makes the dependency order-only
force: if true, include FORCE_DO_CMD as an order-only dep
phony: if true, the rule does not actually generate the named output, the
output is just a name to run the rule
+ command: (optional) command name to generate unambiguous labels
"""
outputs = map(QuoteSpaces, outputs)
inputs = map(QuoteSpaces, inputs)
if comment:
self.WriteLn('# ' + comment)
if phony:
self.WriteLn('.PHONY: ' + ' '.join(outputs))
- # TODO(evanm): just make order_only a list of deps instead of these hacks.
- if order_only:
- order_insert = '| '
- pick_output = ' '.join(outputs)
- else:
- order_insert = ''
- pick_output = outputs[0]
- if force:
- force_append = ' FORCE_DO_CMD'
- else:
- force_append = ''
if actions:
self.WriteLn("%s: TOOLSET := $(TOOLSET)" % outputs[0])
- self.WriteLn('%s: %s%s%s' % (pick_output, order_insert, ' '.join(inputs),
- force_append))
+ force_append = ' FORCE_DO_CMD' if force else ''
+
+ if order_only:
+ # Order only rule: Just write a simple rule.
+ # TODO(evanm): just make order_only a list of deps instead of this hack.
+ self.WriteLn('%s: | %s%s' %
+ (' '.join(outputs), ' '.join(inputs), force_append))
+ elif len(outputs) == 1:
+ # Regular rule, one output: Just write a simple rule.
+ self.WriteLn('%s: %s%s' % (outputs[0], ' '.join(inputs), force_append))
+ else:
+ # Regular rule, more than one output: Multiple outputs are tricky in
+ # make. We will write three rules:
+ # - All outputs depend on an intermediate file.
+ # - Make .INTERMEDIATE depend on the intermediate.
+ # - The intermediate file depends on the inputs and executes the
+ # actual command.
+ # - The intermediate recipe will 'touch' the intermediate file.
+ # - The multi-output rule will have an do-nothing recipe.
+ intermediate = "%s.intermediate" % (command if command else self.target)
+ self.WriteLn('%s: %s' % (' '.join(outputs), intermediate))
+ self.WriteLn('\t%s' % '@:');
+ self.WriteLn('%s: %s' % ('.INTERMEDIATE', intermediate))
+ self.WriteLn('%s: %s%s' %
+ (intermediate, ' '.join(inputs), force_append))
+ actions.insert(0, '$(call do_cmd,touch)')
+
if actions:
for action in actions:
self.WriteLn('\t%s' % action)
- if not order_only and len(outputs) > 1:
- # If we have more than one output, a rule like
- # foo bar: baz
- # that for *each* output we must run the action, potentially
- # in parallel. That is not what we're trying to write -- what
- # we want is that we run the action once and it generates all
- # the files.
- # http://www.gnu.org/software/hello/manual/automake/Multiple-Outputs.html
- # discusses this problem and has this solution:
- # 1) Write the naive rule that would produce parallel runs of
- # the action.
- # 2) Make the outputs seralized on each other, so we won't start
- # a parallel run until the first run finishes, at which point
- # we'll have generated all the outputs and we're done.
- self.WriteLn('%s: %s' % (' '.join(outputs[1:]), outputs[0]))
- # Add a dummy command to the "extra outputs" rule, otherwise make seems to
- # think these outputs haven't (couldn't have?) changed, and thus doesn't
- # flag them as changed (i.e. include in '$?') when evaluating dependent
- # rules, which in turn causes do_cmd() to skip running dependent commands.
- self.WriteLn('%s: ;' % (' '.join(outputs[1:])))
self.WriteLn()
def WriteAndroidNdkModuleRule(self, module_name, all_sources, link_deps):
"""Write a set of LOCAL_XXX definitions for Android NDK.
These variable definitions will be used by Android NDK but do nothing for
non-Android applications.
@@ -1892,23 +1926,25 @@ class MakefileWriter:
def WriteAutoRegenerationRule(params, root_makefile, makefile_name,
build_files):
"""Write the target to regenerate the Makefile."""
options = params['options']
build_files_args = [gyp.common.RelativePath(filename, options.toplevel_dir)
for filename in params['build_files_arg']]
+
gyp_binary = gyp.common.FixIfRelativePath(params['gyp_binary'],
options.toplevel_dir)
if not gyp_binary.startswith(os.sep):
gyp_binary = os.path.join('.', gyp_binary)
+
root_makefile.write(
"quiet_cmd_regen_makefile = ACTION Regenerating $@\n"
- "cmd_regen_makefile = %(cmd)s\n"
+ "cmd_regen_makefile = cd $(srcdir); %(cmd)s\n"
"%(makefile_name)s: %(deps)s\n"
"\t$(call do_cmd,regen_makefile)\n\n" % {
'makefile_name': makefile_name,
'deps': ' '.join(map(Sourceify, build_files)),
'cmd': gyp.common.EncodePOSIXShellList(
[gyp_binary, '-fmake'] +
gyp.RegenerateFlags(options) +
build_files_args)})
@@ -1939,17 +1975,18 @@ def GenerateOutput(target_list, target_d
# paths relative to the source root for the master makefile. Grab
# the path of the .gyp file as the base to relativize against.
# E.g. "foo/bar" when we're constructing targets for "foo/bar/baz.gyp".
base_path = gyp.common.RelativePath(os.path.dirname(build_file),
options.depth)
# We write the file in the base_path directory.
output_file = os.path.join(options.depth, base_path, base_name)
if options.generator_output:
- output_file = os.path.join(options.generator_output, output_file)
+ output_file = os.path.join(
+ options.depth, options.generator_output, base_path, base_name)
base_path = gyp.common.RelativePath(os.path.dirname(build_file),
options.toplevel_dir)
return base_path, output_file
# TODO: search for the first non-'Default' target. This can go
# away when we add verification that all targets have the
# necessary configurations.
default_configuration = None
@@ -1962,87 +1999,114 @@ def GenerateOutput(target_list, target_d
if not default_configuration:
default_configuration = 'Default'
srcdir = '.'
makefile_name = 'Makefile' + options.suffix
makefile_path = os.path.join(options.toplevel_dir, makefile_name)
if options.generator_output:
global srcdir_prefix
- makefile_path = os.path.join(options.generator_output, makefile_path)
+ makefile_path = os.path.join(
+ options.toplevel_dir, options.generator_output, makefile_name)
srcdir = gyp.common.RelativePath(srcdir, options.generator_output)
srcdir_prefix = '$(srcdir)/'
flock_command= 'flock'
+ copy_archive_arguments = '-af'
header_params = {
'default_target': default_target,
'builddir': builddir_name,
'default_configuration': default_configuration,
'flock': flock_command,
'flock_index': 1,
'link_commands': LINK_COMMANDS_LINUX,
'extra_commands': '',
'srcdir': srcdir,
+ 'copy_archive_args': copy_archive_arguments,
}
if flavor == 'mac':
flock_command = './gyp-mac-tool flock'
header_params.update({
'flock': flock_command,
'flock_index': 2,
'link_commands': LINK_COMMANDS_MAC,
'extra_commands': SHARED_HEADER_MAC_COMMANDS,
})
elif flavor == 'android':
header_params.update({
'link_commands': LINK_COMMANDS_ANDROID,
})
elif flavor == 'solaris':
header_params.update({
- 'flock': './gyp-sun-tool flock',
+ 'flock': './gyp-flock-tool flock',
'flock_index': 2,
- 'extra_commands': SHARED_HEADER_SUN_COMMANDS,
})
elif flavor == 'freebsd':
+ # Note: OpenBSD has sysutils/flock. lockf seems to be FreeBSD specific.
header_params.update({
'flock': 'lockf',
})
+ elif flavor == 'openbsd':
+ copy_archive_arguments = '-pPRf'
+ header_params.update({
+ 'copy_archive_args': copy_archive_arguments,
+ })
+ elif flavor == 'aix':
+ copy_archive_arguments = '-pPRf'
+ header_params.update({
+ 'copy_archive_args': copy_archive_arguments,
+ 'link_commands': LINK_COMMANDS_AIX,
+ 'flock': './gyp-flock-tool flock',
+ 'flock_index': 2,
+ })
header_params.update({
'CC.target': GetEnvironFallback(('CC_target', 'CC'), '$(CC)'),
'AR.target': GetEnvironFallback(('AR_target', 'AR'), '$(AR)'),
'CXX.target': GetEnvironFallback(('CXX_target', 'CXX'), '$(CXX)'),
- 'LINK.target': GetEnvironFallback(('LD_target', 'LD'), '$(LINK)'),
+ 'LINK.target': GetEnvironFallback(('LINK_target', 'LINK'), '$(LINK)'),
'CC.host': GetEnvironFallback(('CC_host',), 'gcc'),
'AR.host': GetEnvironFallback(('AR_host',), 'ar'),
'CXX.host': GetEnvironFallback(('CXX_host',), 'g++'),
- 'LINK.host': GetEnvironFallback(('LD_host',), 'g++'),
+ 'LINK.host': GetEnvironFallback(('LINK_host',), '$(CXX.host)'),
})
build_file, _, _ = gyp.common.ParseQualifiedTarget(target_list[0])
make_global_settings_array = data[build_file].get('make_global_settings', [])
+ wrappers = {}
+ for key, value in make_global_settings_array:
+ if key.endswith('_wrapper'):
+ wrappers[key[:-len('_wrapper')]] = '$(abspath %s)' % value
make_global_settings = ''
for key, value in make_global_settings_array:
+ if re.match('.*_wrapper', key):
+ continue
if value[0] != '$':
value = '$(abspath %s)' % value
- if key == 'LINK':
- make_global_settings += ('%s ?= %s $(builddir)/linker.lock %s\n' %
- (key, flock_command, value))
- elif key in ('CC', 'CC.host', 'CXX', 'CXX.host'):
+ wrapper = wrappers.get(key)
+ if wrapper:
+ value = '%s %s' % (wrapper, value)
+ del wrappers[key]
+ if key in ('CC', 'CC.host', 'CXX', 'CXX.host'):
make_global_settings += (
'ifneq (,$(filter $(origin %s), undefined default))\n' % key)
# Let gyp-time envvars win over global settings.
- if key in os.environ:
- value = os.environ[key]
+ env_key = key.replace('.', '_') # CC.host -> CC_host
+ if env_key in os.environ:
+ value = os.environ[env_key]
make_global_settings += ' %s = %s\n' % (key, value)
make_global_settings += 'endif\n'
else:
make_global_settings += '%s ?= %s\n' % (key, value)
+ # TODO(ukai): define cmd when only wrapper is specified in
+ # make_global_settings.
+
header_params['make_global_settings'] = make_global_settings
- ensure_directory_exists(makefile_path)
+ gyp.common.EnsureDirExists(makefile_path)
root_makefile = open(makefile_path, 'w')
root_makefile.write(SHARED_HEADER % header_params)
# Currently any versions have the same effect, but in future the behavior
# could be different.
if android_ndk_version:
root_makefile.write(
'# Define LOCAL_PATH for build of Android applications.\n'
'LOCAL_PATH := $(call my-dir)\n'
@@ -2064,17 +2128,18 @@ def GenerateOutput(target_list, target_d
build_files = set()
include_list = set()
for qualified_target in target_list:
build_file, target, toolset = gyp.common.ParseQualifiedTarget(
qualified_target)
this_make_global_settings = data[build_file].get('make_global_settings', [])
assert make_global_settings_array == this_make_global_settings, (
- "make_global_settings needs to be the same for all targets.")
+ "make_global_settings needs to be the same for all targets. %s vs. %s" %
+ (this_make_global_settings, make_global_settings))
build_files.add(gyp.common.RelativePath(build_file, options.toplevel_dir))
included_files = data[build_file]['included_files']
for included_file in included_files:
# The included_files entries are relative to the dir of the build file
# that included them, so we have to undo that and then make them relative
# to the root dir.
relative_include_file = gyp.common.RelativePath(
deleted file mode 100644
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/make.py.new
+++ /dev/null
@@ -1,2587 +0,0 @@
-#!/usr/bin/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.
-
-# Notes:
-#
-# This is all roughly based on the Makefile system used by the Linux
-# kernel, but is a non-recursive make -- we put the entire dependency
-# graph in front of make and let it figure it out.
-#
-# The code below generates a separate .mk file for each target, but
-# all are sourced by the top-level Makefile. This means that all
-# variables in .mk-files clobber one another. Be careful to use :=
-# where appropriate for immediate evaluation, and similarly to watch
-# that you're not relying on a variable value to last beween different
-# .mk files.
-#
-# TODOs:
-#
-# Global settings and utility functions are currently stuffed in the
-# toplevel Makefile. It may make sense to generate some .mk files on
-# the side to keep the the files readable.
-
-import gyp
-import gyp.common
-import gyp.system_test
-import os.path
-import os
-import sys
-
-# Debugging-related imports -- remove me once we're solid.
-import code
-import pprint
-
-generator_default_variables = {
- 'EXECUTABLE_PREFIX': '',
- 'EXECUTABLE_SUFFIX': '',
- 'STATIC_LIB_PREFIX': 'lib',
- 'SHARED_LIB_PREFIX': 'lib',
- 'STATIC_LIB_SUFFIX': '.a',
- 'INTERMEDIATE_DIR': '$(obj).$(TOOLSET)/geni',
- 'SHARED_INTERMEDIATE_DIR': '$(obj)/gen',
- 'PRODUCT_DIR': '$(builddir)',
- 'LIB_DIR': '$(obj).$(TOOLSET)',
- 'RULE_INPUT_ROOT': '%(INPUT_ROOT)s', # This gets expanded by Python.
- 'RULE_INPUT_PATH': '$(abspath $<)',
- 'RULE_INPUT_EXT': '$(suffix $<)',
- 'RULE_INPUT_NAME': '$(notdir $<)',
-
- # This appears unused --- ?
- 'CONFIGURATION_NAME': '$(BUILDTYPE)',
-}
-
-# Make supports multiple toolsets
-generator_supports_multiple_toolsets = True
-
-# Request sorted dependencies in the order from dependents to dependencies.
-generator_wants_sorted_dependencies = False
-
-
-def GetFlavor(params):
- """Returns |params.flavor| if it's set, the system's default flavor else."""
- return params.get('flavor', 'mac' if sys.platform == 'darwin' else 'linux')
-
-
-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)
-
- if GetFlavor(params) == 'mac':
- default_variables.setdefault('OS', 'mac')
- default_variables.setdefault('SHARED_LIB_SUFFIX', '.dylib')
- default_variables.setdefault('SHARED_LIB_DIR',
- generator_default_variables['PRODUCT_DIR'])
-
- # Copy additional generator configuration data from Xcode, which is shared
- # by the Mac Make 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', [])
- global COMPILABLE_EXTENSIONS
- COMPILABLE_EXTENSIONS.update({'.m': 'objc', '.mm' : 'objcxx'})
- else:
- default_variables.setdefault('OS', 'linux')
- default_variables.setdefault('SHARED_LIB_SUFFIX', '.so')
- default_variables.setdefault('SHARED_LIB_DIR','$(builddir)' + os.sep + 'lib.$(TOOLSET)')
-
-
-def CalculateGeneratorInputInfo(params):
- """Calculate the generator specific info that gets fed to input (called by
- gyp)."""
- generator_flags = params.get('generator_flags', {})
- android_ndk_version = generator_flags.get('android_ndk_version', None)
- # Android NDK requires a strict link order.
- if android_ndk_version:
- global generator_wants_sorted_dependencies
- generator_wants_sorted_dependencies = True
-
-
-def ensure_directory_exists(path):
- dir = os.path.dirname(path)
- if dir and not os.path.exists(dir):
- os.makedirs(dir)
-
-
-# The .d checking code below uses these functions:
-# wildcard, sort, foreach, shell, wordlist
-# wildcard can handle spaces, the rest can't.
-# Since I could find no way to make foreach work with spaces in filenames
-# correctly, the .d files have spaces replaced with another character. The .d
-# file for
-# Chromium\ Framework.framework/foo
-# is for example
-# out/Release/.deps/out/Release/Chromium?Framework.framework/foo
-# This is the replacement character.
-SPACE_REPLACEMENT = '?'
-
-
-LINK_COMMANDS_LINUX = """\
-quiet_cmd_alink = AR($(TOOLSET)) $@
-cmd_alink = rm -f $@ && $(AR.$(TOOLSET)) $(ARFLAGS.$(TOOLSET)) $@ $(filter %.o,$^)
-
-# Due to circular dependencies between libraries :(, we wrap the
-# special "figure out circular dependencies" flags around the entire
-# input list during linking.
-quiet_cmd_link = LINK($(TOOLSET)) $@
-cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ -Wl,--start-group $(LD_INPUTS) -Wl,--end-group $(LIBS)
-
-# We support two kinds of shared objects (.so):
-# 1) shared_library, which is just bundling together many dependent libraries
-# into a link line.
-# 2) loadable_module, which is generating a module intended for dlopen().
-#
-# They differ only slightly:
-# In the former case, we want to package all dependent code into the .so.
-# In the latter case, we want to package just the API exposed by the
-# outermost module.
-# This means shared_library uses --whole-archive, while loadable_module doesn't.
-# (Note that --whole-archive is incompatible with the --start-group used in
-# normal linking.)
-
-# Other shared-object link notes:
-# - Set SONAME to the library filename so our binaries don't reference
-# the local, absolute paths used on the link command-line.
-quiet_cmd_solink = SOLINK($(TOOLSET)) $@
-cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--whole-archive $(LD_INPUTS) -Wl,--no-whole-archive $(LIBS)
-
-quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@
-cmd_solink_module = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--start-group $(filter-out FORCE_DO_CMD, $^) -Wl,--end-group $(LIBS)
-"""
-
-LINK_COMMANDS_MAC = """\
-quiet_cmd_alink = LIBTOOL-STATIC $@
-cmd_alink = rm -f $@ && libtool -static -o $@ $(filter %.o,$^)
-
-quiet_cmd_link = LINK($(TOOLSET)) $@
-cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o "$@" $(LD_INPUTS) $(LIBS)
-
-# TODO(thakis): Find out and document the difference between shared_library and
-# loadable_module on mac.
-quiet_cmd_solink = SOLINK($(TOOLSET)) $@
-cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o "$@" $(LD_INPUTS) $(LIBS)
-
-# TODO(thakis): The solink_module rule is likely wrong. Xcode seems to pass
-# -bundle -single_module here (for osmesa.so).
-quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@
-cmd_solink_module = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(filter-out FORCE_DO_CMD, $^) $(LIBS)
-"""
-
-# Header of toplevel Makefile.
-# This should go into the build tree, but it's easier to keep it here for now.
-SHARED_HEADER = ("""\
-# We borrow heavily from the kernel build setup, though we are simpler since
-# we don't have Kconfig tweaking settings on us.
-
-# The implicit make rules have it looking for RCS files, among other things.
-# We instead explicitly write all the rules we care about.
-# It's even quicker (saves ~200ms) to pass -r on the command line.
-MAKEFLAGS=-r
-
-# The source directory tree.
-srcdir := %(srcdir)s
-
-# The name of the builddir.
-builddir_name ?= %(builddir)s
-
-# The V=1 flag on command line makes us verbosely print command lines.
-ifdef V
- quiet=
-else
- quiet=quiet_
-endif
-
-# Specify BUILDTYPE=Release on the command line for a release build.
-BUILDTYPE ?= %(default_configuration)s
-
-# Directory all our build output goes into.
-# Note that this must be two directories beneath src/ for unit tests to pass,
-# as they reach into the src/ directory for data with relative paths.
-builddir ?= $(builddir_name)/$(BUILDTYPE)
-abs_builddir := $(abspath $(builddir))
-depsdir := $(builddir)/.deps
-
-# Object output directory.
-obj := $(builddir)/obj
-abs_obj := $(abspath $(obj))
-
-# We build up a list of every single one of the targets so we can slurp in the
-# generated dependency rule Makefiles in one pass.
-all_deps :=
-
-# C++ apps need to be linked with g++. Not sure what's appropriate.
-#
-# Note, the flock is used to seralize linking. Linking is a memory-intensive
-# process so running parallel links can often lead to thrashing. To disable
-# the serialization, override FLOCK via an envrionment variable as follows:
-#
-# export FLOCK=
-#
-# This will allow make to invoke N linker processes as specified in -jN.
-FLOCK ?= %(flock)s $(builddir)/linker.lock
-LINK ?= $(FLOCK) $(CXX)
-
-CC.target ?= $(CC)
-CFLAGS.target ?= $(CFLAGS)
-CXX.target ?= $(CXX)
-CXXFLAGS.target ?= $(CXXFLAGS)
-LINK.target ?= $(LINK)
-LDFLAGS.target ?= $(LDFLAGS) %(LINK_flags)s
-AR.target ?= $(AR)
-ARFLAGS.target ?= %(ARFLAGS.target)s
-
-# N.B.: the logic of which commands to run should match the computation done
-# in gyp's make.py where ARFLAGS.host etc. is computed.
-# TODO(evan): move all cross-compilation logic to gyp-time so we don't need
-# to replicate this environment fallback in make as well.
-CC.host ?= gcc
-CFLAGS.host ?=
-CXX.host ?= g++
-CXXFLAGS.host ?=
-LINK.host ?= g++
-LDFLAGS.host ?=
-AR.host ?= ar
-ARFLAGS.host := %(ARFLAGS.host)s
-
-# Define a dir function that can handle spaces.
-# http://www.gnu.org/software/make/manual/make.html#Syntax-of-Functions
-# "leading spaces cannot appear in the text of the first argument as written.
-# These characters can be put into the argument value by variable substitution."
-empty :=
-space := $(empty) $(empty)
-
-# http://stackoverflow.com/questions/1189781/using-make-dir-or-notdir-on-a-path-with-spaces
-replace_spaces = $(subst $(space),""" + SPACE_REPLACEMENT + """,$1)
-unreplace_spaces = $(subst """ + SPACE_REPLACEMENT + """,$(space),$1)
-dirx = $(call unreplace_spaces,$(dir $(call replace_spaces,$1)))
-
-# Flags to make gcc output dependency info. Note that you need to be
-# careful here to use the flags that ccache and distcc can understand.
-# We write to a dep file on the side first and then rename at the end
-# so we can't end up with a broken dep file.
-depfile = $(depsdir)/$(call replace_spaces,$@).d
-DEPFLAGS = -MMD -MF $(depfile).raw
-
-# We have to fixup the deps output in a few ways.
-# (1) the file output should mention the proper .o file.
-# ccache or distcc lose the path to the target, so we convert a rule of
-# the form:
-# foobar.o: DEP1 DEP2
-# into
-# path/to/foobar.o: DEP1 DEP2
-# (2) we want missing files not to cause us to fail to build.
-# We want to rewrite
-# foobar.o: DEP1 DEP2 \\
-# DEP3
-# to
-# DEP1:
-# DEP2:
-# DEP3:
-# so if the files are missing, they're just considered phony rules.
-# We have to do some pretty insane escaping to get those backslashes
-# and dollar signs past make, the shell, and sed at the same time.
-# Doesn't work with spaces, but that's fine: .d files have spaces in
-# their names replaced with other characters."""
-r"""
-define fixup_dep
-# The depfile may not exist if the input file didn't have any #includes.
-touch $(depfile).raw
-# Fixup path as in (1).
-sed -e "s|^$(notdir $@)|$@|" $(depfile).raw >> $(depfile)
-# Add extra rules as in (2).
-# We remove slashes and replace spaces with new lines;
-# remove blank lines;
-# delete the first line and append a colon to the remaining lines.
-sed -e 's|\\||' -e 'y| |\n|' $(depfile).raw |\
- grep -v '^$$' |\
- sed -e 1d -e 's|$$|:|' \
- >> $(depfile)
-rm $(depfile).raw
-endef
-"""
-"""
-# Command definitions:
-# - cmd_foo is the actual command to run;
-# - quiet_cmd_foo is the brief-output summary of the command.
-
-quiet_cmd_cc = CC($(TOOLSET)) $@
-cmd_cc = $(CC.$(TOOLSET)) $(GYP_CFLAGS) $(DEPFLAGS) $(CFLAGS.$(TOOLSET)) -c -o $@ $<
-
-quiet_cmd_cxx = CXX($(TOOLSET)) $@
-cmd_cxx = $(CXX.$(TOOLSET)) $(GYP_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $<
-%(mac_commands)s
-quiet_cmd_touch = TOUCH $@
-cmd_touch = touch $@
-
-quiet_cmd_copy = COPY $@
-# send stderr to /dev/null to ignore messages when linking directories.
-cmd_copy = ln -f "$<" "$@" 2>/dev/null || (rm -rf "$@" && cp -af "$<" "$@")
-
-%(link_commands)s
-"""
-
-r"""
-# Define an escape_quotes function to escape single quotes.
-# This allows us to handle quotes properly as long as we always use
-# use single quotes and escape_quotes.
-escape_quotes = $(subst ','\'',$(1))
-# This comment is here just to include a ' to unconfuse syntax highlighting.
-# Define an escape_vars function to escape '$' variable syntax.
-# This allows us to read/write command lines with shell variables (e.g.
-# $LD_LIBRARY_PATH), without triggering make substitution.
-escape_vars = $(subst $$,$$$$,$(1))
-# Helper that expands to a shell command to echo a string exactly as it is in
-# make. This uses printf instead of echo because printf's behaviour with respect
-# to escape sequences is more portable than echo's across different shells
-# (e.g., dash, bash).
-exact_echo = printf '%%s\n' '$(call escape_quotes,$(1))'
-"""
-"""
-# Helper to compare the command we're about to run against the command
-# we logged the last time we ran the command. Produces an empty
-# string (false) when the commands match.
-# Tricky point: Make has no string-equality test function.
-# The kernel uses the following, but it seems like it would have false
-# positives, where one string reordered its arguments.
-# arg_check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \\
-# $(filter-out $(cmd_$@), $(cmd_$(1))))
-# We instead substitute each for the empty string into the other, and
-# say they're equal if both substitutions produce the empty string.
-# .d files contain """ + SPACE_REPLACEMENT + \
- """ instead of spaces, take that into account.
-command_changed = $(or $(subst $(cmd_$(1)),,$(cmd_$(call replace_spaces,$@))),\\
- $(subst $(cmd_$(call replace_spaces,$@)),,$(cmd_$(1))))
-
-# Helper that is non-empty when a prerequisite changes.
-# Normally make does this implicitly, but we force rules to always run
-# so we can check their command lines.
-# $? -- new prerequisites
-# $| -- order-only dependencies
-prereq_changed = $(filter-out FORCE_DO_CMD,$(filter-out $|,$?))
-
-# do_cmd: run a command via the above cmd_foo names, if necessary.
-# Should always run for a given target to handle command-line changes.
-# Second argument, if non-zero, makes it do asm/C/C++ dependency munging.
-# Third argument, if non-zero, makes it do POSTBUILDS processing.
-# Note: We intentionally do NOT call dirx for depfile, since it contains """ + \
- SPACE_REPLACEMENT + """ for
-# spaces already and dirx strips the """ + SPACE_REPLACEMENT + \
- """ characters.
-define do_cmd
-$(if $(or $(command_changed),$(prereq_changed)),
- @$(call exact_echo, $($(quiet)cmd_$(1)))
- @mkdir -p "$(call dirx,$@)" "$(dir $(depfile))"
- $(if $(findstring flock,$(word %(flock_index)d,$(cmd_$1))),
- @$(cmd_$(1))
- @echo " $(quiet_cmd_$(1)): Finished",
- @$(cmd_$(1))
- )
- @$(call exact_echo,$(call escape_vars,cmd_$(call replace_spaces,$@) := $(cmd_$(1)))) > $(depfile)
- @$(if $(2),$(fixup_dep))
- $(if $(and $(3), $(POSTBUILDS)),
- @for p in $(POSTBUILDS); do eval $$p; done
- )
-)
-endef
-
-# Declare "all" target first so it is the default, even though we don't have the
-# deps yet.
-.PHONY: all
-all:
-
-# Use FORCE_DO_CMD to force a target to run. Should be coupled with
-# do_cmd.
-.PHONY: FORCE_DO_CMD
-FORCE_DO_CMD:
-
-""")
-
-SHARED_HEADER_MAC_COMMANDS = """
-quiet_cmd_objc = CXX($(TOOLSET)) $@
-cmd_objc = $(CC.$(TOOLSET)) $(GYP_OBJCFLAGS) $(DEPFLAGS) -c -o $@ $<
-
-quiet_cmd_objcxx = CXX($(TOOLSET)) $@
-cmd_objcxx = $(CXX.$(TOOLSET)) $(GYP_OBJCXXFLAGS) $(DEPFLAGS) -c -o $@ $<
-
-# Commands for precompiled header files.
-quiet_cmd_pch_c = CXX($(TOOLSET)) $@
-cmd_pch_c = $(CC.$(TOOLSET)) $(GYP_PCH_CFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $<
-quiet_cmd_pch_cc = CXX($(TOOLSET)) $@
-cmd_pch_cc = $(CC.$(TOOLSET)) $(GYP_PCH_CCFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $<
-quiet_cmd_pch_m = CXX($(TOOLSET)) $@
-cmd_pch_m = $(CC.$(TOOLSET)) $(GYP_PCH_OBJCFLAGS) $(DEPFLAGS) -c -o $@ $<
-quiet_cmd_pch_mm = CXX($(TOOLSET)) $@
-cmd_pch_mm = $(CC.$(TOOLSET)) $(GYP_PCH_OBJCXXFLAGS) $(DEPFLAGS) -c -o $@ $<
-
-# gyp-mac-tool is written next to the root Makefile by gyp.
-# Use $(4) for the command, since $(2) and $(3) are used as flag by do_cmd
-# already.
-quiet_cmd_mac_tool = MACTOOL $(4) $<
-cmd_mac_tool = ./gyp-mac-tool $(4) $< "$@"
-
-quiet_cmd_mac_package_framework = PACKAGE FRAMEWORK $@
-cmd_mac_package_framework = ./gyp-mac-tool package-framework "$@" $(4)
-"""
-
-
-def WriteRootHeaderSuffixRules(writer):
- extensions = sorted(COMPILABLE_EXTENSIONS.keys(), key=str.lower)
-
- writer.write('# Suffix rules, putting all outputs into $(obj).\n')
- for ext in extensions:
- writer.write('$(obj).$(TOOLSET)' + os.sep + '%%.o: $(srcdir)' + os.sep + '%%%s FORCE_DO_CMD\n' % ext)
- writer.write('\t@$(call do_cmd,%s,1)\n' % COMPILABLE_EXTENSIONS[ext])
-
- writer.write('\n# Try building from generated source, too.\n')
- for ext in extensions:
- writer.write(
- '$(obj).$(TOOLSET)' + os.sep + '%%.o: $(obj).$(TOOLSET)' + os.sep + '%%%s FORCE_DO_CMD\n' % ext)
- writer.write('\t@$(call do_cmd,%s,1)\n' % COMPILABLE_EXTENSIONS[ext])
- writer.write('\n')
- for ext in extensions:
- writer.write('$(obj).$(TOOLSET)' + os.sep + '%%.o: $(obj)' + os.sep + '%%%s FORCE_DO_CMD\n' % ext)
- writer.write('\t@$(call do_cmd,%s,1)\n' % COMPILABLE_EXTENSIONS[ext])
- writer.write('\n')
-
-
-SHARED_HEADER_SUFFIX_RULES_COMMENT1 = ("""\
-# Suffix rules, putting all outputs into $(obj).
-""")
-
-
-SHARED_HEADER_SUFFIX_RULES_COMMENT2 = ("""\
-# Try building from generated source, too.
-""")
-
-
-SHARED_FOOTER = """\
-# "all" is a concatenation of the "all" targets from all the included
-# sub-makefiles. This is just here to clarify.
-all:
-
-# Add in dependency-tracking rules. $(all_deps) is the list of every single
-# target in our tree. Only consider the ones with .d (dependency) info:
-d_files := $(wildcard $(foreach f,$(all_deps),$(depsdir)/$(f).d))
-ifneq ($(d_files),)
- # Rather than include each individual .d file, concatenate them into a
- # single file which make is able to load faster. We split this into
- # commands that take 1000 files at a time to avoid overflowing the
- # command line.
- $(shell cat $(wordlist 1,1000,$(d_files)) > $(depsdir)/all.deps)
-%(generate_all_deps)s
- # make looks for ways to re-generate included makefiles, but in our case, we
- # don't have a direct way. Explicitly telling make that it has nothing to do
- # for them makes it go faster.
- $(depsdir)/all.deps: ;
-
- include $(depsdir)/all.deps
-endif
-"""
-
-header = """\
-# This file is generated by gyp; do not edit.
-
-"""
-
-# Maps every compilable file extension to the do_cmd that compiles it.
-COMPILABLE_EXTENSIONS = {
- '.c': 'cc',
- '.cc': 'cxx',
- '.cpp': 'cxx',
- '.cxx': 'cxx',
- '.s': 'cc',
- '.S': 'cc',
-}
-
-def Compilable(filename):
- """Return true if the file is compilable (should be in OBJS)."""
- for res in (filename.endswith(e) for e in COMPILABLE_EXTENSIONS):
- if res:
- return True
- return False
-
-
-def Linkable(filename):
- """Return true if the file is linkable (should be on the link line)."""
- return filename.endswith('.o')
-
-
-def Target(filename):
- """Translate a compilable filename to its .o target."""
- return os.path.splitext(filename)[0] + '.o'
-
-
-def EscapeShellArgument(s):
- """Quotes an argument so that it will be interpreted literally by a POSIX
- shell. Taken from
- http://stackoverflow.com/questions/35817/whats-the-best-way-to-escape-ossystem-calls-in-python
- """
- return "'" + s.replace("'", "'\\''") + "'"
-
-
-def EscapeMakeVariableExpansion(s):
- """Make has its own variable expansion syntax using $. We must escape it for
- string to be interpreted literally."""
- return s.replace('$', '$$')
-
-
-def EscapeCppDefine(s):
- """Escapes a CPP define so that it will reach the compiler unaltered."""
- s = EscapeShellArgument(s)
- s = EscapeMakeVariableExpansion(s)
- return s
-
-
-def QuoteIfNecessary(string):
- """TODO: Should this ideally be replaced with one or more of the above
- functions?"""
- if '"' in string:
- string = '"' + string.replace('"', '\\"') + '"'
- return string
-
-
-def StringToMakefileVariable(string):
- """Convert a string to a value that is acceptable as a make variable name."""
- # TODO: replace other metacharacters that we encounter.
- return string.replace(' ', '_')
-
-
-srcdir_prefix = ''
-def Sourceify(path):
- """Convert a path to its source directory form."""
- if '$(' in path:
- return path
- if os.path.isabs(path):
- return path
- return srcdir_prefix + path
-
-
-def QuoteSpaces(s):
- return s.replace(' ', r'\ ')
-
-
-def ReplaceQuotedSpaces(s):
- return s.replace(r'\ ', SPACE_REPLACEMENT)
-
-
-# Map from qualified target to path to output.
-target_outputs = {}
-# Map from qualified target to any linkable output. A subset
-# of target_outputs. E.g. when mybinary depends on liba, we want to
-# include liba in the linker line; when otherbinary depends on
-# mybinary, we just want to build mybinary first.
-target_link_deps = {}
-
-
-class XcodeSettings(object):
- """A class that understands the gyp 'xcode_settings' object."""
-
- def __init__(self, spec):
- self.spec = spec
-
- # Per-target 'xcode_settings' are pushed down into configs earlier by gyp.
- # This means self.xcode_settings[config] always contains all settings
- # for that config -- the per-target settings as well. Settings that are
- # the same for all configs are implicitly per-target settings.
- self.xcode_settings = {}
- configs = spec['configurations']
- for configname, config in configs.iteritems():
- self.xcode_settings[configname] = config.get('xcode_settings', {})
-
- # This is only non-None temporarily during the execution of some methods.
- self.configname = None
-
- def _Settings(self):
- assert self.configname
- return self.xcode_settings[self.configname]
-
- def _Test(self, test_key, cond_key, default):
- return self._Settings().get(test_key, default) == cond_key
-
- def _Appendf(self, lst, test_key, format_str):
- if test_key in self._Settings():
- lst.append(format_str % str(self._Settings()[test_key]))
-
- def _WarnUnimplemented(self, test_key):
- if test_key in self._Settings():
- print 'Warning: Ignoring not yet implemented key "%s".' % test_key
-
- def _IsBundle(self):
- return int(self.spec.get('mac_bundle', 0)) != 0
-
- def GetFrameworkVersion(self):
- """Returns the framework version of the current target. Only valid for
- bundles."""
- assert self._IsBundle()
- return self.GetPerTargetSetting('FRAMEWORK_VERSION', default='A')
-
- def GetWrapperExtension(self):
- """Returns the bundle extension (.app, .framework, .plugin, etc). Only
- valid for bundles."""
- assert self._IsBundle()
- if self.spec['type'] in ('loadable_module', 'shared_library'):
- wrapper_extension = self.GetPerTargetSetting(
- 'WRAPPER_EXTENSION', default='framework')
- return '.' + self.spec.get('product_extension', wrapper_extension)
- elif self.spec['type'] == 'executable':
- return '.app'
- else:
- assert False, "Don't know extension for '%s', target '%s'" % (
- self.spec['type'], self.spec['target_name'])
-
- def GetProductName(self):
- """Returns PRODUCT_NAME."""
- return self.spec.get('product_name', self.spec['target_name'])
-
- def GetWrapperName(self):
- """Returns the directory name of the bundle represented by this target.
- Only valid for bundles."""
- assert self._IsBundle()
- return self.GetProductName() + self.GetWrapperExtension()
-
- def GetBundleContentsFolderPath(self):
- """Returns the qualified path to the bundle's contents folder. E.g.
- Chromium.app/Contents or Foo.bundle/Versions/A. Only valid for bundles."""
- assert self._IsBundle()
- if self.spec['type'] == 'shared_library':
- return os.path.join(
- self.GetWrapperName(), 'Versions', self.GetFrameworkVersion())
- else:
- # loadable_modules have a 'Contents' folder like executables.
- return os.path.join(self.GetWrapperName(), 'Contents')
-
- def GetBundleResourceFolder(self):
- """Returns the qualified path to the bundle's resource folder. E.g.
- Chromium.app/Contents/Resources. Only valid for bundles."""
- assert self._IsBundle()
- return os.path.join(self.GetBundleContentsFolderPath(), 'Resources')
-
- def GetBundlePlistPath(self):
- """Returns the qualified path to the bundle's plist file. E.g.
- Chromium.app/Contents/Info.plist. Only valid for bundles."""
- assert self._IsBundle()
- assert self.spec['type'] != 'loadable_modules', (
- "Info.plist files for loadable_modules not yet supported by the "
- "make generator (target %s)" % self.spec['target_name']) # Not tested.
- if self.spec['type'] == 'executable':
- return os.path.join(self.GetBundleContentsFolderPath(), 'Info.plist')
- else:
- return os.path.join(self.GetBundleContentsFolderPath(),
- 'Resources', 'Info.plist')
-
- def _GetBundleBinaryPath(self):
- """Returns the name of the bundle binary of by this target.
- E.g. Chromium.app/Contents/MacOS/Chromium. Only valid for bundles."""
- assert self._IsBundle()
- if self.spec['type'] in ('loadable_module', 'shared_library'):
- path = self.GetBundleContentsFolderPath()
- elif self.spec['type'] == 'executable':
- path = os.path.join(self.GetBundleContentsFolderPath(), 'MacOS')
- return os.path.join(path, self.spec.get('product_name',
- self.spec['target_name']))
-
- def _GetStandaloneExecutableSuffix(self):
- if 'product_extension' in self.spec:
- return '.' + self.spec['product_extension']
- return {
- 'executable': '',
- 'static_library': '.a',
- 'shared_library': '.dylib',
- 'loadable_module': '.so',
- }[self.spec['type']]
-
- def _GetStandaloneExecutablePrefix(self):
- return self.spec.get('product_prefix', {
- 'executable': '',
- 'static_library': 'lib',
- 'shared_library': 'lib',
- # Non-bundled loadable_modules are called foo.so for some reason
- # (that is, .so and no prefix) with the xcode build -- match that.
- 'loadable_module': '',
- }[self.spec['type']])
-
- def _GetStandaloneBinaryPath(self):
- """Returns the name of the non-bundle binary represented by this target.
- E.g. hello_world. Only valid for non-bundles."""
- assert not self._IsBundle()
- assert self.spec['type'] in (
- 'executable', 'shared_library', 'static_library', 'loadable_module')
- target = self.spec['target_name']
- if self.spec['type'] == 'static_library':
- if target[:3] == 'lib':
- target = target[3:]
- elif self.spec['type'] in ('loadable_module', 'shared_library'):
- if target[:3] == 'lib':
- target = target[3:]
-
- target_prefix = self._GetStandaloneExecutablePrefix()
- target = self.spec.get('product_name', target)
- target_ext = self._GetStandaloneExecutableSuffix()
- return target_prefix + target + target_ext
-
- def GetExecutablePath(self):
- """Returns the directory name of the bundle represented by this target. E.g.
- Chromium.app/Contents/MacOS/Chromium."""
- if self._IsBundle():
- return self._GetBundleBinaryPath()
- else:
- return self._GetStandaloneBinaryPath()
-
- def GetCflags(self, configname):
- """Returns flags that need to be added to .c, .cc, .m, and .mm
- compilations."""
- # This functions (and the similar ones below) do not offer complete
- # emulation of all xcode_settings keys. They're implemented on demand.
-
- self.configname = configname
- cflags = []
-
- sdk_root = 'Mac10.5'
- if 'SDKROOT' in self._Settings():
- sdk_root = self._Settings()['SDKROOT']
- cflags.append('-isysroot /Developer/SDKs/%s.sdk' % sdk_root)
- sdk_root_dir = '/Developer/SDKs/%s.sdk' % sdk_root
-
- if self._Test('GCC_CW_ASM_SYNTAX', 'YES', default='YES'):
- cflags.append('-fasm-blocks')
-
- if 'GCC_DYNAMIC_NO_PIC' in self._Settings():
- if self._Settings()['GCC_DYNAMIC_NO_PIC'] == 'YES':
- cflags.append('-mdynamic-no-pic')
- else:
- pass
- # TODO: In this case, it depends on the target. xcode passes
- # mdynamic-no-pic by default for executable and possibly static lib
- # according to mento
-
- if self._Test('GCC_ENABLE_PASCAL_STRINGS', 'YES', default='YES'):
- cflags.append('-mpascal-strings')
-
- self._Appendf(cflags, 'GCC_OPTIMIZATION_LEVEL', '-O%s')
-
- dbg_format = self._Settings().get('DEBUG_INFORMATION_FORMAT', 'dwarf')
- if dbg_format == 'none':
- pass
- elif dbg_format == 'dwarf':
- cflags.append('-gdwarf-2')
- elif dbg_format == 'stabs':
- raise NotImplementedError('stabs debug format is not supported yet.')
- elif dbg_format == 'dwarf-with-dsym':
- # TODO(thakis): this is needed for mac_breakpad chromium builds, but not
- # for regular chromium builds.
- # -gdwarf-2 as well, but needs to invoke dsymutil after linking too:
- # dsymutil build/Default/TestAppGyp.app/Contents/MacOS/TestAppGyp \
- # -o build/Default/TestAppGyp.app.dSYM
- raise NotImplementedError('dsym debug format is not supported yet.')
- else:
- raise NotImplementedError('Unknown debug format %s' % dbg_format)
-
- if self._Test('GCC_SYMBOLS_PRIVATE_EXTERN', 'YES', default='NO'):
- cflags.append('-fvisibility=hidden')
-
- if self._Test('GCC_TREAT_WARNINGS_AS_ERRORS', 'YES', default='NO'):
- cflags.append('-Werror')
-
- if self._Test('GCC_WARN_ABOUT_MISSING_NEWLINE', 'YES', default='NO'):
- cflags.append('-Wnewline-eof')
-
- self._Appendf(cflags, 'MACOSX_DEPLOYMENT_TARGET', '-mmacosx-version-min=%s')
-
- # TODO:
- self._WarnUnimplemented('ARCHS')
- self._WarnUnimplemented('COPY_PHASE_STRIP')
- self._WarnUnimplemented('DEPLOYMENT_POSTPROCESSING')
- self._WarnUnimplemented('INFOPLIST_PREPROCESS')
- self._WarnUnimplemented('INFOPLIST_PREPROCESSOR_DEFINITIONS')
- self._WarnUnimplemented('STRIPFLAGS')
- self._WarnUnimplemented('STRIP_INSTALLED_PRODUCT')
-
- # TODO: Do not hardcode arch. Supporting fat binaries will be annoying.
- cflags.append('-arch i386')
-
- cflags += self._Settings().get('OTHER_CFLAGS', [])
- cflags += self._Settings().get('WARNING_CFLAGS', [])
-
- config = self.spec['configurations'][self.configname]
- framework_dirs = config.get('mac_framework_dirs', [])
- for directory in framework_dirs:
- cflags.append('-F ' + os.path.join(sdk_root_dir, directory))
-
- self.configname = None
- return cflags
-
- def GetCflagsC(self, configname):
- """Returns flags that need to be added to .c, and .m compilations."""
- self.configname = configname
- cflags_c = []
- self._Appendf(cflags_c, 'GCC_C_LANGUAGE_STANDARD', '-std=%s')
- self.configname = None
- return cflags_c
-
- def GetCflagsCC(self, configname):
- """Returns flags that need to be added to .cc, and .mm compilations."""
- self.configname = configname
- cflags_cc = []
- if self._Test('GCC_ENABLE_CPP_RTTI', 'NO', default='YES'):
- cflags_cc.append('-fno-rtti')
- if self._Test('GCC_ENABLE_CPP_EXCEPTIONS', 'NO', default='YES'):
- cflags_cc.append('-fno-exceptions')
- if self._Test('GCC_INLINES_ARE_PRIVATE_EXTERN', 'YES', default='NO'):
- cflags_cc.append('-fvisibility-inlines-hidden')
- if self._Test('GCC_THREADSAFE_STATICS', 'NO', default='YES'):
- cflags_cc.append('-fno-threadsafe-statics')
- self.configname = None
- return cflags_cc
-
- def GetCflagsObjC(self, configname):
- """Returns flags that need to be added to .m compilations."""
- self.configname = configname
- self.configname = None
- return []
-
- def GetCflagsObjCC(self, configname):
- """Returns flags that need to be added to .mm compilations."""
- self.configname = configname
- cflags_objcc = []
- if self._Test('GCC_OBJC_CALL_CXX_CDTORS', 'YES', default='NO'):
- cflags_objcc.append('-fobjc-call-cxx-cdtors')
- self.configname = None
- return cflags_objcc
-
- def GetLdflags(self, target, configname):
- """Returns flags that need to be passed to the linker."""
- self.configname = configname
- ldflags = []
-
- # The xcode build is relative to a gyp file's directory, and OTHER_LDFLAGS
- # contains two entries that depend on this. Explicitly absolutify for these
- # two cases.
- def AbsolutifyPrefix(flag, prefix):
- if flag.startswith(prefix):
- flag = prefix + target.Absolutify(flag[len(prefix):])
- return flag
- for ldflag in self._Settings().get('OTHER_LDFLAGS', []):
- # Required for ffmpeg (no idea why they don't use LIBRARY_SEARCH_PATHS,
- # TODO(thakis): Update ffmpeg.gyp):
- ldflag = AbsolutifyPrefix(ldflag, '-L')
- # Required for the nacl plugin:
- ldflag = AbsolutifyPrefix(ldflag, '-Wl,-exported_symbols_list ')
- ldflags.append(ldflag)
-
- if self._Test('DEAD_CODE_STRIPPING', 'YES', default='NO'):
- ldflags.append('-Wl,-dead_strip')
-
- if self._Test('PREBINDING', 'YES', default='NO'):
- ldflags.append('-Wl,-prebind')
-
- self._Appendf(
- ldflags, 'DYLIB_COMPATIBILITY_VERSION', '-compatibility_version %s')
- self._Appendf(
- ldflags, 'DYLIB_CURRENT_VERSION', '-current_version %s')
- self._Appendf(
- ldflags, 'MACOSX_DEPLOYMENT_TARGET', '-mmacosx-version-min=%s')
- self._Appendf(
- ldflags, 'SDKROOT', '-isysroot /Developer/SDKs/%s.sdk')
-
- for library_path in self._Settings().get('LIBRARY_SEARCH_PATHS', []):
- ldflags.append('-L' + library_path)
-
- if 'ORDER_FILE' in self._Settings():
- ldflags.append('-Wl,-order_file ' +
- '-Wl,' + target.Absolutify(self._Settings()['ORDER_FILE']))
-
- # TODO: Do not hardcode arch. Supporting fat binaries will be annoying.
- ldflags.append('-arch i386')
-
- # Xcode adds the product directory by default. It writes static libraries
- # into the product directory. So add both.
- ldflags.append('-L' + generator_default_variables['LIB_DIR'])
- ldflags.append('-L' + generator_default_variables['PRODUCT_DIR'])
-
- install_name = self.GetPerTargetSetting('LD_DYLIB_INSTALL_NAME')
- install_base = self.GetPerTargetSetting('DYLIB_INSTALL_NAME_BASE')
- default_install_name = \
- '$(DYLIB_INSTALL_NAME_BASE:standardizepath)' + os.sep + '$(EXECUTABLE_PATH)'
- if not install_name and install_base:
- install_name = default_install_name
-
- if install_name:
- # Hardcode support for the variables used in chromium for now, to unblock
- # people using the make build.
- if '$' in install_name:
- assert install_name in ('$(DYLIB_INSTALL_NAME_BASE:standardizepath)' + os.sep +
- '$(WRAPPER_NAME)/$(PRODUCT_NAME)', default_install_name), (
- 'Variables in LD_DYLIB_INSTALL_NAME are not generally supported yet'
- ' in target \'%s\' (got \'%s\')' %
- (self.spec['target_name'], install_name))
- # I'm not quite sure what :standardizepath does. Just call normpath(),
- # but don't let @executable_path/../foo collapse to foo.
- if '/' in install_base:
- prefix, rest = '', install_base
- if install_base.startswith('@'):
- prefix, rest = install_base.split('/', 1)
- rest = os.path.normpath(rest) # :standardizepath
- install_base = os.path.join(prefix, rest)
-
- install_name = install_name.replace(
- '$(DYLIB_INSTALL_NAME_BASE:standardizepath)', install_base)
- if self._IsBundle():
- # These are only valid for bundles, hence the |if|.
- install_name = install_name.replace(
- '$(WRAPPER_NAME)', self.GetWrapperName())
- install_name = install_name.replace(
- '$(PRODUCT_NAME)', self.GetProductName())
- else:
- assert '$(WRAPPER_NAME)' not in install_name
- assert '$(PRODUCT_NAME)' not in install_name
-
- install_name = install_name.replace(
- '$(EXECUTABLE_PATH)', self.GetExecutablePath())
-
- install_name = QuoteSpaces(install_name)
- ldflags.append('-install_name ' + install_name)
-
- self.configname = None
- return ldflags
-
- def GetPerTargetSettings(self):
- """Gets a list of all the per-target settings. This will only fetch keys
- whose values are the same across all configurations."""
- first_pass = True
- result = {}
- for configname in sorted(self.xcode_settings.keys()):
- if first_pass:
- result = dict(self.xcode_settings[configname])
- first_pass = False
- else:
- for key, value in self.xcode_settings[configname].iteritems():
- if key not in result:
- continue
- elif result[key] != value:
- del result[key]
- return result
-
- def GetPerTargetSetting(self, setting, default=None):
- """Tries to get xcode_settings.setting from spec. Assumes that the setting
- has the same value in all configurations and throws otherwise."""
- first_pass = True
- result = None
- for configname in sorted(self.xcode_settings.keys()):
- if first_pass:
- result = self.xcode_settings[configname].get(setting, None)
- first_pass = False
- else:
- assert result == self.xcode_settings[configname].get(setting, None), (
- "Expected per-target setting for '%s', got per-config setting "
- "(target %s)" % (setting, spec['target_name']))
- if result is None:
- return default
- return result
-
-
-class MacPrefixHeader(object):
- """A class that helps with emulating Xcode's GCC_PREFIX_HEADER feature. If
- GCC_PREFIX_HEADER isn't present (in most gyp targets on mac, and always on
- non-mac systems), all methods of this class are no-ops."""
-
- def __init__(self, path_provider):
- # This doesn't support per-configuration prefix headers. Good enough
- # for now.
- self.header = None
- if path_provider.flavor == 'mac':
- self.header = path_provider.xcode_settings.GetPerTargetSetting(
- 'GCC_PREFIX_HEADER')
- self.compiled_headers = {}
- if self.header:
- self.header = path_provider.Absolutify(self.header)
- for lang in ['c', 'cc', 'm', 'mm']:
- self.compiled_headers[lang] = path_provider.Pchify(self.header, lang)
-
- def _Gch(self, lang):
- """Returns the actual file name of the prefix header for language |lang|."""
- return self.compiled_headers[lang] + '.gch'
-
- def WriteObjDependencies(self, compilable, objs, writer):
- """Writes dependencies from the object files in |objs| to the corresponding
- precompiled header file. |compilable[i]| has to be the source file belonging
- to |objs[i]|."""
- if not self.header:
- return
-
- writer.WriteLn('# Dependencies from obj files to their precompiled headers')
- for source, obj in zip(compilable, objs):
- ext = os.path.splitext(source)[1]
- lang = {
- '.c': 'c',
- '.cpp': 'cc', '.cc': 'cc', '.cxx': 'cc',
- '.m': 'm',
- '.mm': 'mm',
- }.get(ext, None)
- if lang:
- writer.WriteLn('%s: %s' % (obj, self._Gch(lang)))
- writer.WriteLn('# End precompiled header dependencies')
-
- def GetInclude(self, lang):
- """Gets the cflags to include the prefix header for language |lang|."""
- if lang not in self.compiled_headers:
- return ''
- return '-include %s ' % self.compiled_headers[lang]
-
- def WritePchTargets(self, writer):
- """Writes make rules to compile the prefix headers."""
- if not self.header:
- return
-
- writer.WriteLn(self._Gch('c') + ": GYP_PCH_CFLAGS := "
- "-x c-header "
- "$(DEFS_$(BUILDTYPE)) "
- "$(INCS_$(BUILDTYPE)) "
- "$(CFLAGS_$(BUILDTYPE)) "
- "$(CFLAGS_C_$(BUILDTYPE))")
-
- writer.WriteLn(self._Gch('cc') + ": GYP_PCH_CCFLAGS := "
- "-x c++-header "
- "$(DEFS_$(BUILDTYPE)) "
- "$(INCS_$(BUILDTYPE)) "
- "$(CFLAGS_$(BUILDTYPE)) "
- "$(CFLAGS_CC_$(BUILDTYPE))")
-
- writer.WriteLn(self._Gch('m') + ": GYP_PCH_OBJCFLAGS := "
- "-x objective-c-header "
- "$(DEFS_$(BUILDTYPE)) "
- "$(INCS_$(BUILDTYPE)) "
- "$(CFLAGS_$(BUILDTYPE)) "
- "$(CFLAGS_C_$(BUILDTYPE)) "
- "$(CFLAGS_OBJC_$(BUILDTYPE))")
-
- writer.WriteLn(self._Gch('mm') + ": GYP_PCH_OBJCXXFLAGS := "
- "-x objective-c++-header "
- "$(DEFS_$(BUILDTYPE)) "
- "$(INCS_$(BUILDTYPE)) "
- "$(CFLAGS_$(BUILDTYPE)) "
- "$(CFLAGS_CC_$(BUILDTYPE)) "
- "$(CFLAGS_OBJCC_$(BUILDTYPE))")
-
- for lang in self.compiled_headers:
- writer.WriteLn('%s: %s FORCE_DO_CMD' % (self._Gch(lang), self.header))
- writer.WriteLn('\t@$(call do_cmd,pch_%s,1)' % lang)
- writer.WriteLn('')
- assert ' ' not in self._Gch(lang), (
- "Spaces in gch filenames not supported (%s)" % self._Gch(lang))
- writer.WriteLn('all_deps += %s' % self._Gch(lang))
- writer.WriteLn('')
-
-
-class MakefileWriter:
- """MakefileWriter packages up the writing of one target-specific foobar.mk.
-
- Its only real entry point is Write(), and is mostly used for namespacing.
- """
-
- def __init__(self, generator_flags, flavor):
- self.generator_flags = generator_flags
- self.flavor = flavor
- # Keep track of the total number of outputs for this makefile.
- self._num_outputs = 0
-
- self.suffix_rules_srcdir = {}
- self.suffix_rules_objdir1 = {}
- self.suffix_rules_objdir2 = {}
-
- # Generate suffix rules for all compilable extensions.
- for ext in COMPILABLE_EXTENSIONS.keys():
- # Suffix rules for source folder.
- self.suffix_rules_srcdir.update({ext: ("""\
-$(obj).$(TOOLSET)""" + os.sep + """$(TARGET)""" + os.sep + """%%.o: $(srcdir)""" + os.sep + """%%%s FORCE_DO_CMD
- @$(call do_cmd,%s,1)
-""" % (ext, COMPILABLE_EXTENSIONS[ext]))})
-
- # Suffix rules for generated source files.
- self.suffix_rules_objdir1.update({ext: ("""\
-$(obj).$(TOOLSET)""" + os.sep + """$(TARGET)""" + os.sep + """%%.o: $(obj).$(TOOLSET)""" + os.sep + """%%%s FORCE_DO_CMD
- @$(call do_cmd,%s,1)
-""" % (ext, COMPILABLE_EXTENSIONS[ext]))})
- self.suffix_rules_objdir2.update({ext: ("""\
-$(obj).$(TOOLSET)""" + os.sep + """$(TARGET)""" + os.sep + """%%.o: $(obj)""" + os.sep + """%%%s FORCE_DO_CMD
- @$(call do_cmd,%s,1)
-""" % (ext, COMPILABLE_EXTENSIONS[ext]))})
-
-
- def NumOutputs(self):
- return self._num_outputs
-
-
- def Write(self, qualified_target, base_path, output_filename, spec, configs,
- part_of_all):
- """The main entry point: writes a .mk file for a single target.
-
- Arguments:
- qualified_target: target we're generating
- base_path: path relative to source root we're building in, used to resolve
- target-relative paths
- output_filename: output .mk file name to write
- spec, configs: gyp info
- part_of_all: flag indicating this target is part of 'all'
- """
- ensure_directory_exists(output_filename)
-
- self.fp = open(output_filename, 'w')
-
- self.fp.write(header)
-
- self.path = base_path
- self.target = spec['target_name']
- self.type = spec['type']
- self.toolset = spec['toolset']
-
- # Bundles are directories with a certain subdirectory structure, instead of
- # just a single file. Bundle rules do not produce a binary but also package
- # resources into that directory.
- self.is_mac_bundle = (int(spec.get('mac_bundle', 0)) != 0 and
- self.flavor == 'mac')
- if self.is_mac_bundle:
- assert self.type != 'none', (
- 'mac_bundle targets cannot have type none (target "%s")' %
- self.target)
-
- if self.flavor == 'mac':
- self.xcode_settings = XcodeSettings(spec)
-
- deps, link_deps = self.ComputeDeps(spec)
-
- # Some of the generation below can add extra output, sources, or
- # link dependencies. All of the out params of the functions that
- # follow use names like extra_foo.
- extra_outputs = []
- extra_sources = []
- extra_link_deps = []
- extra_mac_bundle_resources = []
- mac_bundle_deps = []
-
- if self.is_mac_bundle:
- self.output = self.ComputeMacBundleOutput(spec)
- self.output_binary = self.ComputeMacBundleBinaryOutput(spec)
- else:
- self.output = self.output_binary = self.ComputeOutput(spec)
-
- self.output = QuoteSpaces(self.output)
- self.output_binary = QuoteSpaces(self.output_binary)
-
- self._INSTALLABLE_TARGETS = ('executable', 'loadable_module',
- 'shared_library')
- if self.type in self._INSTALLABLE_TARGETS:
- self.alias = os.path.basename(self.output)
- install_path = self._InstallableTargetInstallPath()
- else:
- self.alias = self.output
- install_path = self.output
-
- self.WriteLn("TOOLSET := " + self.toolset)
- self.WriteLn("TARGET := " + self.target)
-
- # Actions must come first, since they can generate more OBJs for use below.
- if 'actions' in spec:
- self.WriteActions(spec['actions'], extra_sources, extra_outputs,
- extra_mac_bundle_resources, part_of_all, spec)
-
- # Rules must be early like actions.
- if 'rules' in spec:
- self.WriteRules(spec['rules'], extra_sources, extra_outputs,
- extra_mac_bundle_resources, part_of_all)
-
- if 'copies' in spec:
- self.WriteCopies(spec['copies'], extra_outputs, part_of_all, spec)
-
- # Bundle resources.
- if self.is_mac_bundle:
- all_mac_bundle_resources = (
- spec.get('mac_bundle_resources', []) + extra_mac_bundle_resources)
- if all_mac_bundle_resources:
- self.WriteMacBundleResources(
- all_mac_bundle_resources, mac_bundle_deps, spec)
- info_plist = self.xcode_settings.GetPerTargetSetting('INFOPLIST_FILE')
- if info_plist:
- self.WriteMacInfoPlist(info_plist, mac_bundle_deps, spec)
-
- # Sources.
- all_sources = spec.get('sources', []) + extra_sources
- if all_sources:
- self.WriteSources(
- configs, deps, all_sources, extra_outputs,
- extra_link_deps, part_of_all, MacPrefixHeader(self))
- sources = filter(Compilable, all_sources)
- if sources:
- self.WriteLn(SHARED_HEADER_SUFFIX_RULES_COMMENT1)
- extensions = set([os.path.splitext(s)[1] for s in sources])
- for ext in extensions:
- if ext in self.suffix_rules_srcdir:
- self.WriteLn(self.suffix_rules_srcdir[ext])
- self.WriteLn(SHARED_HEADER_SUFFIX_RULES_COMMENT2)
- for ext in extensions:
- if ext in self.suffix_rules_objdir1:
- self.WriteLn(self.suffix_rules_objdir1[ext])
- for ext in extensions:
- if ext in self.suffix_rules_objdir2:
- self.WriteLn(self.suffix_rules_objdir2[ext])
- self.WriteLn('# End of this set of suffix rules')
-
- # Add dependency from bundle to bundle binary.
- if self.is_mac_bundle:
- mac_bundle_deps.append(self.output_binary)
-
- self.WriteTarget(spec, configs, deps, extra_link_deps + link_deps,
- mac_bundle_deps, extra_outputs, part_of_all)
-
- # Update global list of target outputs, used in dependency tracking.
- target_outputs[qualified_target] = install_path
-
- # Update global list of link dependencies.
- if self.type in ('static_library', 'shared_library'):
- target_link_deps[qualified_target] = self.output_binary
-
- # Currently any versions have the same effect, but in future the behavior
- # could be different.
- if self.generator_flags.get('android_ndk_version', None):
- self.WriteAndroidNdkModuleRule(self.target, all_sources, link_deps)
-
- self.fp.close()
-
-
- def WriteSubMake(self, output_filename, makefile_path, targets, build_dir):
- """Write a "sub-project" Makefile.
-
- This is a small, wrapper Makefile that calls the top-level Makefile to build
- the targets from a single gyp file (i.e. a sub-project).
-
- Arguments:
- output_filename: sub-project Makefile name to write
- makefile_path: path to the top-level Makefile
- targets: list of "all" targets for this sub-project
- build_dir: build output directory, relative to the sub-project
- """
- ensure_directory_exists(output_filename)
- self.fp = open(output_filename, 'w')
- self.fp.write(header)
- # For consistency with other builders, put sub-project build output in the
- # sub-project dir (see test/subdirectory/gyptest-subdir-all.py).
- self.WriteLn('export builddir_name ?= %s' %
- os.path.join(os.path.dirname(output_filename), build_dir))
- self.WriteLn('.PHONY: all')
- self.WriteLn('all:')
- if makefile_path:
- makefile_path = ' -C ' + makefile_path
- self.WriteLn('\t$(MAKE)%s %s' % (makefile_path, ' '.join(targets)))
- self.fp.close()
-
-
- def WriteActions(self, actions, extra_sources, extra_outputs,
- extra_mac_bundle_resources, part_of_all, spec):
- """Write Makefile code for any 'actions' from the gyp input.
-
- extra_sources: a list that will be filled in with newly generated source
- files, if any
- extra_outputs: a list that will be filled in with any outputs of these
- actions (used to make other pieces dependent on these
- actions)
- part_of_all: flag indicating this target is part of 'all'
- """
- for action in actions:
- name = self.target + '_' + StringToMakefileVariable(action['action_name'])
- self.WriteLn('### Rules for action "%s":' % action['action_name'])
- inputs = action['inputs']
- outputs = action['outputs']
-
- # Build up a list of outputs.
- # Collect the output dirs we'll need.
- dirs = set()
- for out in outputs:
- dir = os.path.split(out)[0]
- if dir:
- dirs.add(dir)
- if int(action.get('process_outputs_as_sources', False)):
- extra_sources += outputs
- if int(action.get('process_outputs_as_mac_bundle_resources', False)):
- extra_mac_bundle_resources += outputs
-
- # Write the actual command.
- command = gyp.common.EncodePOSIXShellList(action['action'])
- if 'message' in action:
- self.WriteLn('quiet_cmd_%s = ACTION %s $@' % (name, action['message']))
- else:
- self.WriteLn('quiet_cmd_%s = ACTION %s $@' % (name, name))
- if len(dirs) > 0:
- command = 'mkdir -p %s' % ' '.join(dirs) + '; ' + command
-
- cd_action = 'cd %s; ' % Sourceify(self.path or '.')
-
- # Set LD_LIBRARY_PATH in case the action runs an executable from this
- # build which links to shared libs from this build.
- # actions run on the host, so they should in theory only use host
- # libraries, but until everything is made cross-compile safe, also use
- # target libraries.
- # TODO(piman): when everything is cross-compile safe, remove lib.target
- self.WriteLn('cmd_%s = export LD_LIBRARY_PATH=$(builddir)' + os.sep + 'lib.host:'
- '$(builddir)' + os.sep + 'lib.target:$$LD_LIBRARY_PATH; %s%s'
- % (name, cd_action, command))
- self.WriteLn()
- outputs = map(self.Absolutify, outputs)
- # The makefile rules are all relative to the top dir, but the gyp actions
- # are defined relative to their containing dir. This replaces the obj
- # variable for the action rule with an absolute version so that the output
- # goes in the right place.
- # Only write the 'obj' and 'builddir' rules for the "primary" output (:1);
- # it's superfluous for the "extra outputs", and this avoids accidentally
- # writing duplicate dummy rules for those outputs.
- # Same for environment.
- self.WriteMakeRule(outputs[:1], ['obj := $(abs_obj)'])
- # Needs to be before builddir is redefined in the next line!
- self.WriteXcodeEnv(outputs[0], spec, target_relative_path=True)
- self.WriteMakeRule(outputs[:1], ['builddir := $(abs_builddir)'])
-
- for input in inputs:
- assert ' ' not in input, (
- "Spaces in action input filenames not supported (%s)" % input)
- for output in outputs:
- assert ' ' not in output, (
- "Spaces in action output filenames not supported (%s)" % output)
-
- self.WriteDoCmd(outputs, map(Sourceify, map(self.Absolutify, inputs)),
- part_of_all=part_of_all, command=name)
-
- # Stuff the outputs in a variable so we can refer to them later.
- outputs_variable = 'action_%s_outputs' % name
- self.WriteLn('%s := %s' % (outputs_variable, ' '.join(outputs)))
- extra_outputs.append('$(%s)' % outputs_variable)
- self.WriteLn()
-
- self.WriteLn()
-
-
- def WriteRules(self, rules, extra_sources, extra_outputs,
- extra_mac_bundle_resources, part_of_all):
- """Write Makefile code for any 'rules' from the gyp input.
-
- extra_sources: a list that will be filled in with newly generated source
- files, if any
- extra_outputs: a list that will be filled in with any outputs of these
- rules (used to make other pieces dependent on these rules)
- part_of_all: flag indicating this target is part of 'all'
- """
- for rule in rules:
- name = self.target + '_' + StringToMakefileVariable(rule['rule_name'])
- count = 0
- self.WriteLn('### Generated for rule %s:' % name)
-
- all_outputs = []
-
- for rule_source in rule.get('rule_sources', []):
- dirs = set()
- rule_source_basename = os.path.basename(rule_source)
- (rule_source_root, rule_source_ext) = \
- os.path.splitext(rule_source_basename)
-
- outputs = [self.ExpandInputRoot(out, rule_source_root)
- for out in rule['outputs']]
- for out in outputs:
- dir = os.path.dirname(out)
- if dir:
- dirs.add(dir)
- if int(rule.get('process_outputs_as_sources', False)):
- extra_sources += outputs
- if int(rule.get('process_outputs_as_mac_bundle_resources', False)):
- extra_mac_bundle_resources += outputs
- all_outputs += outputs
- inputs = map(Sourceify, map(self.Absolutify, [rule_source] +
- rule.get('inputs', [])))
- actions = ['$(call do_cmd,%s_%d)' % (name, count)]
-
- if name == 'resources_grit':
- # HACK: This is ugly. Grit intentionally doesn't touch the
- # timestamp of its output file when the file doesn't change,
- # which is fine in hash-based dependency systems like scons
- # and forge, but not kosher in the make world. After some
- # discussion, hacking around it here seems like the least
- # amount of pain.
- actions += ['@touch --no-create $@']
-
- # Only write the 'obj' and 'builddir' rules for the "primary" output
- # (:1); it's superfluous for the "extra outputs", and this avoids
- # accidentally writing duplicate dummy rules for those outputs.
- self.WriteMakeRule(outputs[:1], ['obj := $(abs_obj)'])
- self.WriteMakeRule(outputs[:1], ['builddir := $(abs_builddir)'])
- self.WriteMakeRule(outputs, inputs + ['FORCE_DO_CMD'], actions)
- for output in outputs:
- assert ' ' not in output, (
- "Spaces in rule filenames not yet supported (%s)" % output)
- self.WriteLn('all_deps += %s' % ' '.join(outputs))
- self._num_outputs += len(outputs)
-
- action = [self.ExpandInputRoot(ac, rule_source_root)
- for ac in rule['action']]
- mkdirs = ''
- if len(dirs) > 0:
- mkdirs = 'mkdir -p %s; ' % ' '.join(dirs)
- cd_action = 'cd %s; ' % Sourceify(self.path or '.')
- # Set LD_LIBRARY_PATH in case the rule runs an executable from this
- # build which links to shared libs from this build.
- # rules run on the host, so they should in theory only use host
- # libraries, but until everything is made cross-compile safe, also use
- # target libraries.
- # TODO(piman): when everything is cross-compile safe, remove lib.target
- self.WriteLn(
- "cmd_%(name)s_%(count)d = export LD_LIBRARY_PATH="
- "$(builddir)" + os.sep + "lib.host:$(builddir)" + os.sep + "lib.target:$$LD_LIBRARY_PATH; "
- "%(cd_action)s%(mkdirs)s%(action)s" % {
- 'action': gyp.common.EncodePOSIXShellList(action),
- 'cd_action': cd_action,
- 'count': count,
- 'mkdirs': mkdirs,
- 'name': name,
- })
- self.WriteLn(
- 'quiet_cmd_%(name)s_%(count)d = RULE %(name)s_%(count)d $@' % {
- 'count': count,
- 'name': name,
- })
- self.WriteLn()
- count += 1
-
- outputs_variable = 'rule_%s_outputs' % name
- self.WriteList(all_outputs, outputs_variable)
- extra_outputs.append('$(%s)' % outputs_variable)
-
- self.WriteLn('### Finished generating for rule: %s' % name)
- self.WriteLn()
- self.WriteLn('### Finished generating for all rules')
- self.WriteLn('')
-
-
- def WriteCopies(self, copies, extra_outputs, part_of_all, spec):
- """Write Makefile code for any 'copies' from the gyp input.
-
- extra_outputs: a list that will be filled in with any outputs of this action
- (used to make other pieces dependent on this action)
- part_of_all: flag indicating this target is part of 'all'
- """
- self.WriteLn('### Generated for copy rule.')
-
- variable = self.target + '_copies'
- outputs = []
- for copy in copies:
- for path in copy['files']:
- path = Sourceify(self.Absolutify(path))
- filename = os.path.split(path)[1]
- output = Sourceify(self.Absolutify(os.path.join(copy['destination'],
- filename)))
- path = QuoteSpaces(path)
- output = QuoteSpaces(output)
-
- # If the output path has variables in it, which happens in practice for
- # 'copies', writing the environment as target-local doesn't work,
- # because the variables are already needed for the target name.
- # Copying the environment variables into global make variables doesn't
- # work either, because then the .d files will potentially contain spaces
- # after variable expansion, and .d file handling cannot handle spaces.
- # As a workaround, manually expand variables at gyp time. Since 'copies'
- # can't run scripts, there's no need to write the env then.
- # WriteDoCmd() will escape spaces for .d files.
- import gyp.generator.xcode as xcode_generator
- env = self.GetXcodeEnv(spec)
- output = xcode_generator.ExpandXcodeVariables(output, env)
- path = xcode_generator.ExpandXcodeVariables(path, env)
- self.WriteDoCmd([output], [path], 'copy', part_of_all)
- outputs.append(output)
- self.WriteLn('%s = %s' % (variable, ' '.join(outputs)))
- extra_outputs.append('$(%s)' % variable)
- self.WriteLn()
-
-
- def WriteMacBundleResources(self, resources, bundle_deps, spec):
- """Writes Makefile code for 'mac_bundle_resources'."""
- self.WriteLn('### Generated for mac_bundle_resources')
- variable = self.target + '_mac_bundle_resources'
- path = generator_default_variables['PRODUCT_DIR']
- dest = os.path.join(path, self.xcode_settings.GetBundleResourceFolder())
- dest = QuoteSpaces(dest)
- for res in resources:
- output = dest
-
- assert ' ' not in res, (
- "Spaces in resource filenames not supported (%s)" % res)
-
- # Split into (path,file).
- path = Sourceify(self.Absolutify(res))
- path_parts = os.path.split(path)
-
- # Now split the path into (prefix,maybe.lproj).
- lproj_parts = os.path.split(path_parts[0])
- # If the resource lives in a .lproj bundle, add that to the destination.
- if lproj_parts[1].endswith('.lproj'):
- output = os.path.join(output, lproj_parts[1])
-
- output = Sourceify(self.Absolutify(os.path.join(output, path_parts[1])))
- # Compiled XIB files are referred to by .nib.
- if output.endswith('.xib'):
- output = output[0:-3] + 'nib'
-
- self.WriteDoCmd([output], [path], 'mac_tool,,,copy-bundle-resource',
- part_of_all=True)
- bundle_deps.append(output)
-
-
- def WriteMacInfoPlist(self, info_plist, bundle_deps, spec):
- """Write Makefile code for bundle Info.plist files."""
- assert ' ' not in info_plist, (
- "Spaces in resource filenames not supported (%s)" % info_plist)
- info_plist = self.Absolutify(info_plist)
- path = generator_default_variables['PRODUCT_DIR']
- dest_plist = os.path.join(path, self.xcode_settings.GetBundlePlistPath())
- dest_plist = QuoteSpaces(dest_plist)
- extra_settings = self.xcode_settings.GetPerTargetSettings()
- # plists can contain envvars and substitute them into the file..
- self.WriteXcodeEnv(dest_plist, spec, additional_settings=extra_settings)
- self.WriteDoCmd([dest_plist], [info_plist], 'mac_tool,,,copy-info-plist',
- part_of_all=True)
- bundle_deps.append(dest_plist)
-
-
- def WriteSources(self, configs, deps, sources,
- extra_outputs, extra_link_deps,
- part_of_all, precompiled_header):
- """Write Makefile code for any 'sources' from the gyp input.
- These are source files necessary to build the current target.
-
- configs, deps, sources: input from gyp.
- extra_outputs: a list of extra outputs this action should be dependent on;
- used to serialize action/rules before compilation
- extra_link_deps: a list that will be filled in with any outputs of
- compilation (to be used in link lines)
- part_of_all: flag indicating this target is part of 'all'
- """
-
- # Write configuration-specific variables for CFLAGS, etc.
- for configname in sorted(configs.keys()):
- config = configs[configname]
- self.WriteList(config.get('defines'), 'DEFS_%s' % configname, prefix='-D',
- quoter=EscapeCppDefine)
-
- if self.flavor == 'mac':
- cflags = self.xcode_settings.GetCflags(configname)
- cflags_c = self.xcode_settings.GetCflagsC(configname)
- cflags_cc = self.xcode_settings.GetCflagsCC(configname)
- cflags_objc = self.xcode_settings.GetCflagsObjC(configname)
- cflags_objcc = self.xcode_settings.GetCflagsObjCC(configname)
- else:
- cflags = config.get('cflags')
- cflags_c = config.get('cflags_c')
- cflags_cc = config.get('cflags_cc')
-
- self.WriteLn("# Flags passed to all source files.");
- self.WriteList(cflags, 'CFLAGS_%s' % configname)
- self.WriteLn("# Flags passed to only C files.");
- self.WriteList(cflags_c, 'CFLAGS_C_%s' % configname)
- self.WriteLn("# Flags passed to only C++ files.");
- self.WriteList(cflags_cc, 'CFLAGS_CC_%s' % configname)
- if self.flavor == 'mac':
- self.WriteLn("# Flags passed to only ObjC files.");
- self.WriteList(cflags_objc, 'CFLAGS_OBJC_%s' % configname)
- self.WriteLn("# Flags passed to only ObjC++ files.");
- self.WriteList(cflags_objcc, 'CFLAGS_OBJCC_%s' % configname)
- includes = config.get('include_dirs')
- if includes:
- includes = map(Sourceify, map(self.Absolutify, includes))
- self.WriteList(includes, 'INCS_%s' % configname, prefix='-I')
-
- compilable = filter(Compilable, sources)
- objs = map(self.Objectify, map(self.Absolutify, map(Target, compilable)))
- self.WriteList(objs, 'OBJS')
-
- for obj in objs:
- assert ' ' not in obj, (
- "Spaces in object filenames not supported (%s)" % obj)
- self.WriteLn('# Add to the list of files we specially track '
- 'dependencies for.')
- self.WriteLn('all_deps += $(OBJS)')
- self._num_outputs += len(objs)
- self.WriteLn()
-
- # Make sure our dependencies are built first.
- if deps:
- self.WriteMakeRule(['$(OBJS)'], deps,
- comment = 'Make sure our dependencies are built '
- 'before any of us.',
- order_only = True)
-
- # Make sure the actions and rules run first.
- # If they generate any extra headers etc., the per-.o file dep tracking
- # will catch the proper rebuilds, so order only is still ok here.
- if extra_outputs:
- self.WriteMakeRule(['$(OBJS)'], extra_outputs,
- comment = 'Make sure our actions/rules run '
- 'before any of us.',
- order_only = True)
-
- precompiled_header.WriteObjDependencies(compilable, objs, self)
-
- if objs:
- extra_link_deps.append('$(OBJS)')
- self.WriteLn("""\
-# CFLAGS et al overrides must be target-local.
-# See "Target-specific Variable Values" in the GNU Make manual.""")
- self.WriteLn("$(OBJS): TOOLSET := $(TOOLSET)")
- self.WriteLn("$(OBJS): GYP_CFLAGS := "
- "$(DEFS_$(BUILDTYPE)) "
- "$(INCS_$(BUILDTYPE)) "
- "%s" % precompiled_header.GetInclude('c') +
- "$(CFLAGS_$(BUILDTYPE)) "
- "$(CFLAGS_C_$(BUILDTYPE))")
- self.WriteLn("$(OBJS): GYP_CXXFLAGS := "
- "$(DEFS_$(BUILDTYPE)) "
- "$(INCS_$(BUILDTYPE)) "
- "%s" % precompiled_header.GetInclude('cc') +
- "$(CFLAGS_$(BUILDTYPE)) "
- "$(CFLAGS_CC_$(BUILDTYPE))")
- if self.flavor == 'mac':
- self.WriteLn("$(OBJS): GYP_OBJCFLAGS := "
- "$(DEFS_$(BUILDTYPE)) "
- "$(INCS_$(BUILDTYPE)) "
- "%s" % precompiled_header.GetInclude('m') +
- "$(CFLAGS_$(BUILDTYPE)) "
- "$(CFLAGS_C_$(BUILDTYPE)) "
- "$(CFLAGS_OBJC_$(BUILDTYPE))")
- self.WriteLn("$(OBJS): GYP_OBJCXXFLAGS := "
- "$(DEFS_$(BUILDTYPE)) "
- "$(INCS_$(BUILDTYPE)) "
- "%s" % precompiled_header.GetInclude('mm') +
- "$(CFLAGS_$(BUILDTYPE)) "
- "$(CFLAGS_CC_$(BUILDTYPE)) "
- "$(CFLAGS_OBJCC_$(BUILDTYPE))")
-
- precompiled_header.WritePchTargets(self)
-
- # If there are any object files in our input file list, link them into our
- # output.
- extra_link_deps += filter(Linkable, sources)
-
- self.WriteLn()
-
-
- def ComputeOutputBasename(self, spec):
- """Return the 'output basename' of a gyp spec.
-
- E.g., the loadable module 'foobar' in directory 'baz' will produce
- 'libfoobar.so'
- """
- assert not self.is_mac_bundle
-
- if self.flavor == 'mac' and self.type in (
- 'static_library', 'executable', 'shared_library', 'loadable_module'):
- return self.xcode_settings.GetExecutablePath()
-
- target = spec['target_name']
- target_prefix = ''
- target_ext = ''
- if self.type == 'static_library':
- if target[:3] == 'lib':
- target = target[3:]
- target_prefix = 'lib'
- target_ext = '.a'
- elif self.type in ('loadable_module', 'shared_library'):
- if target[:3] == 'lib':
- target = target[3:]
- target_prefix = 'lib'
- target_ext = '.so'
- elif self.type == 'none':
- target = '%s.stamp' % target
- elif self.type != 'executable':
- print ("ERROR: What output file should be generated?",
- "type", self.type, "target", target)
-
- target_prefix = spec.get('product_prefix', target_prefix)
- target = spec.get('product_name', target)
- product_ext = spec.get('product_extension')
- if product_ext:
- target_ext = '.' + product_ext
-
- return target_prefix + target + target_ext
-
-
- def ComputeOutput(self, spec):
- """Return the 'output' (full output path) of a gyp spec.
-
- E.g., the loadable module 'foobar' in directory 'baz' will produce
- '$(obj)/baz/libfoobar.so'
- """
- assert not self.is_mac_bundle
-
- if self.type == 'settings':
- return '' # Doesn't have any output.
-
- path = os.path.join('$(obj).' + self.toolset, self.path)
- if self.type == 'executable':
- path = '$(builddir)'
- path = spec.get('product_dir', path)
- return os.path.join(path, self.ComputeOutputBasename(spec))
-
-
- def ComputeMacBundleOutput(self, spec):
- """Return the 'output' (full output path) to a bundle output directory."""
- assert self.is_mac_bundle
- path = generator_default_variables['PRODUCT_DIR']
- return os.path.join(path, self.xcode_settings.GetWrapperName())
-
-
- def ComputeMacBundleBinaryOutput(self, spec):
- """Return the 'output' (full output path) to the binary in a bundle."""
- path = generator_default_variables['PRODUCT_DIR']
- return os.path.join(path, self.xcode_settings.GetExecutablePath())
-
-
- def ComputeDeps(self, spec):
- """Compute the dependencies of a gyp spec.
-
- Returns a tuple (deps, link_deps), where each is a list of
- filenames that will need to be put in front of make for either
- building (deps) or linking (link_deps).
- """
- deps = []
- link_deps = []
- if 'dependencies' in spec:
- deps.extend([target_outputs[dep] for dep in spec['dependencies']
- if target_outputs[dep]])
- for dep in spec['dependencies']:
- if dep in target_link_deps:
- link_deps.append(target_link_deps[dep])
- deps.extend(link_deps)
- # TODO: It seems we need to transitively link in libraries (e.g. -lfoo)?
- # This hack makes it work:
- # link_deps.extend(spec.get('libraries', []))
- return (gyp.common.uniquer(deps), gyp.common.uniquer(link_deps))
-
-
- def WriteDependencyOnExtraOutputs(self, target, extra_outputs):
- self.WriteMakeRule([self.output_binary], extra_outputs,
- comment = 'Build our special outputs first.',
- order_only = True)
-
-
- def WriteTarget(self, spec, configs, deps, link_deps, bundle_deps,
- extra_outputs, part_of_all):
- """Write Makefile code to produce the final target of the gyp spec.
-
- spec, configs: input from gyp.
- deps, link_deps: dependency lists; see ComputeDeps()
- extra_outputs: any extra outputs that our target should depend on
- part_of_all: flag indicating this target is part of 'all'
- """
-
- self.WriteLn('### Rules for final target.')
-
- if extra_outputs:
- self.WriteDependencyOnExtraOutputs(self.output_binary, extra_outputs)
- self.WriteMakeRule(extra_outputs, deps,
- comment=('Preserve order dependency of '
- 'special output on deps.'),
- order_only = True,
- multiple_output_trick = False)
-
- if self.type not in ('settings', 'none'):
- for configname in sorted(configs.keys()):
- config = configs[configname]
- if self.flavor == 'mac':
- ldflags = self.xcode_settings.GetLdflags(self, configname)
- else:
- ldflags = config.get('ldflags', [])
- # Compute an rpath for this output if needed.
- if any(dep.endswith('.so') for dep in deps):
- # We want to get the literal string "$ORIGIN" into the link command,
- # so we need lots of escaping.
- ldflags.append(r'-Wl,-rpath=\$$ORIGIN/lib.%s/' % self.toolset)
- self.WriteList(ldflags, 'LDFLAGS_%s' % configname)
- libraries = spec.get('libraries')
- if libraries:
- # Remove duplicate entries
- libraries = gyp.common.uniquer(libraries)
- # On Mac, framework libraries need to be passed as '-framework Cocoa'.
- if self.flavor == 'mac':
- libraries = [
- '-framework ' + os.path.splitext(os.path.basename(library))[0]
- if library.endswith('.framework') else library
- for library in libraries]
- self.WriteList(libraries, 'LIBS')
- self.WriteLn(
- '%s: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE))' % self.output_binary)
- self.WriteLn('%s: LIBS := $(LIBS)' % self.output_binary)
-
- postbuilds = []
- if self.flavor == 'mac':
- # Postbuild actions. Like actions, but implicitly depend on the target's
- # output.
- for postbuild in spec.get('postbuilds', []):
- postbuilds.append('echo POSTBUILD\\(%s\\) %s' % (
- self.target, postbuild['postbuild_name']))
- shell_list = postbuild['action']
- # The first element is the command. If it's a relative path, it's
- # a script in the source tree relative to the gyp file and needs to be
- # absolutified. Else, it's in the PATH (e.g. install_name_tool, ln).
- if os.path.sep in shell_list[0]:
- shell_list[0] = self.Absolutify(shell_list[0])
- postbuilds.append('%s' % gyp.common.EncodePOSIXShellList(shell_list))
-
- # A bundle directory depends on its dependencies such as bundle resources
- # and bundle binary. When all dependencies have been built, the bundle
- # needs to be packaged.
- if self.is_mac_bundle:
- self.WriteXcodeEnv(self.output, spec) # For postbuilds
-
- # If the framework doesn't contain a binary, then nothing depends
- # on the actions -- make the framework depend on them directly too.
- self.WriteDependencyOnExtraOutputs(self.output, extra_outputs)
-
- # Bundle dependencies. Note that the code below adds actions to this
- # target, so if you move these two lines, move the lines below as well.
- self.WriteList(bundle_deps, 'BUNDLE_DEPS')
- self.WriteLn('%s: $(BUNDLE_DEPS)' % self.output)
-
- # After the framework is built, package it. Needs to happen before
- # postbuilds, since postbuilds depend on this.
- if self.type in ('shared_library', 'loadable_module'):
- self.WriteLn('\t@$(call do_cmd,mac_package_framework,0,0,%s)' %
- self.xcode_settings.GetFrameworkVersion())
-
- # Bundle postbuilds can depend on the whole bundle, so run them after
- # the bundle is packaged, not already after the bundle binary is done.
- for postbuild in postbuilds:
- self.WriteLn('\t@' + postbuild)
- postbuilds = [] # Don't write postbuilds for target's output.
-
- # Needed by test/mac/gyptest-rebuild.py.
- self.WriteLn('\t@true # No-op, used by tests')
-
- # Since this target depends on binary and resources which are in
- # nested subfolders, the framework directory will be older than
- # its dependencies usually. To prevent this rule from executing
- # on every build (expensive, especially with postbuilds), expliclity
- # update the time on the framework directory.
- self.WriteLn('\t@touch -c %s' % self.output)
-
- if postbuilds:
- assert not self.is_mac_bundle, ('Postbuilds for bundles should be done '
- 'on the bundle, not the binary (target \'%s\')' % self.target)
- self.WriteXcodeEnv(self.output_binary, spec) # For postbuilds
- postbuilds = [EscapeShellArgument(p) for p in postbuilds]
- self.WriteLn('%s: builddir := $(abs_builddir)' % self.output_binary)
- self.WriteLn('%s: POSTBUILDS := %s' % (
- self.output_binary, ' '.join(postbuilds)))
-
- if self.type == 'executable':
- self.WriteLn(
- '%s: LD_INPUTS := %s' % (self.output_binary, ' '.join(link_deps)))
- self.WriteDoCmd([self.output_binary], link_deps, 'link', part_of_all,
- postbuilds=postbuilds)
- elif self.type == 'static_library':
- for link_dep in link_deps:
- assert ' ' not in link_dep, (
- "Spaces in alink input filenames not supported (%s)" % link_dep)
- self.WriteDoCmd([self.output_binary], link_deps, 'alink', part_of_all,
- postbuilds=postbuilds)
- elif self.type == 'shared_library':
- self.WriteLn(
- '%s: LD_INPUTS := %s' % (self.output_binary, ' '.join(link_deps)))
- self.WriteDoCmd([self.output_binary], link_deps, 'solink', part_of_all,
- postbuilds=postbuilds)
- elif self.type == 'loadable_module':
- for link_dep in link_deps:
- assert ' ' not in link_dep, (
- "Spaces in module input filenames not supported (%s)" % link_dep)
- self.WriteDoCmd(
- [self.output_binary], link_deps, 'solink_module', part_of_all,
- postbuilds=postbuilds)
- elif self.type == 'none':
- # Write a stamp line.
- self.WriteDoCmd([self.output_binary], deps, 'touch', part_of_all,
- postbuilds=postbuilds)
- elif self.type == 'settings':
- # Only used for passing flags around.
- pass
- else:
- print "WARNING: no output for", self.type, target
-
- # Add an alias for each target (if there are any outputs).
- # Installable target aliases are created below.
- if ((self.output and self.output != self.target) and
- (self.type not in self._INSTALLABLE_TARGETS)):
- self.WriteMakeRule([self.target], [self.output],
- comment='Add target alias', phony = True)
- if part_of_all:
- self.WriteMakeRule(['all'], [self.target],
- comment = 'Add target alias to "all" target.',
- phony = True)
-
- # Add special-case rules for our installable targets.
- # 1) They need to install to the build dir or "product" dir.
- # 2) They get shortcuts for building (e.g. "make chrome").
- # 3) They are part of "make all".
- if self.type in self._INSTALLABLE_TARGETS:
- if self.type == 'shared_library':
- file_desc = 'shared library'
- else:
- file_desc = 'executable'
- install_path = self._InstallableTargetInstallPath()
- installable_deps = [self.output]
- if self.is_mac_bundle:
- # Bundles are created in their install_path location immediately.
- assert install_path == self.output, '%s != %s' % (
- install_path, self.output)
-
- # Point the target alias to the final binary output.
- self.WriteMakeRule([self.target], [install_path],
- comment='Add target alias', phony = True)
- if install_path != self.output:
- assert not self.is_mac_bundle # See comment a few lines above.
- self.WriteDoCmd([install_path], [self.output], 'copy',
- comment = 'Copy this to the %s output path.' %
- file_desc, part_of_all=part_of_all)
- installable_deps.append(install_path)
- if self.output != self.alias and self.alias != self.target:
- self.WriteMakeRule([self.alias], installable_deps,
- comment = 'Short alias for building this %s.' %
- file_desc, phony = True)
- if part_of_all:
- self.WriteMakeRule(['all'], [install_path],
- comment = 'Add %s to "all" target.' % file_desc,
- phony = True)
-
-
- def WriteList(self, list, variable=None, prefix='', quoter=QuoteIfNecessary):
- """Write a variable definition that is a list of values.
-
- E.g. WriteList(['a','b'], 'foo', prefix='blah') writes out
- foo = blaha blahb
- but in a pretty-printed style.
- """
- self.fp.write(variable + " := ")
- if list:
- list = [quoter(prefix + l) for l in list]
- self.fp.write(" \\\n\t".join(list))
- self.fp.write("\n\n")
-
-
- def WriteDoCmd(self, outputs, inputs, command, part_of_all, comment=None,
- postbuilds=False):
- """Write a Makefile rule that uses do_cmd.
-
- This makes the outputs dependent on the command line that was run,
- as well as support the V= make command line flag.
- """
- suffix = ''
- if postbuilds:
- assert ',' not in command
- suffix = ',,1' # Tell do_cmd to honor $POSTBUILDS
- self.WriteMakeRule(outputs, inputs,
- actions = ['$(call do_cmd,%s%s)' % (command, suffix)],
- comment = comment,
- force = True)
- # Add our outputs to the list of targets we read depfiles from.
- # all_deps is only used for deps file reading, and for deps files we replace
- # spaces with ? because escaping doesn't work with make's $(sort) and
- # other functions.
- outputs = [ReplaceQuotedSpaces(o) for o in outputs]
- self.WriteLn('all_deps += %s' % ' '.join(outputs))
- self._num_outputs += len(outputs)
-
-
- def WriteMakeRule(self, outputs, inputs, actions=None, comment=None,
- order_only=False, force=False, phony=False,
- multiple_output_trick=True):
- """Write a Makefile rule, with some extra tricks.
-
- outputs: a list of outputs for the rule (note: this is not directly
- supported by make; see comments below)
- inputs: a list of inputs for the rule
- actions: a list of shell commands to run for the rule
- comment: a comment to put in the Makefile above the rule (also useful
- for making this Python script's code self-documenting)
- order_only: if true, makes the dependency order-only
- force: if true, include FORCE_DO_CMD as an order-only dep
- phony: if true, the rule does not actually generate the named output, the
- output is just a name to run the rule
- multiple_output_trick: if true (the default), perform tricks such as dummy
- rules to avoid problems with multiple outputs.
- """
- if comment:
- self.WriteLn('# ' + comment)
- if phony:
- self.WriteLn('.PHONY: ' + ' '.join(outputs))
- # TODO(evanm): just make order_only a list of deps instead of these hacks.
- if order_only:
- order_insert = '| '
- else:
- order_insert = ''
- if force:
- force_append = ' FORCE_DO_CMD'
- else:
- force_append = ''
- if actions:
- self.WriteLn("%s: TOOLSET := $(TOOLSET)" % outputs[0])
- self.WriteLn('%s: %s%s%s' % (outputs[0], order_insert, ' '.join(inputs),
- force_append))
- if actions:
- for action in actions:
- self.WriteLn('\t%s' % action)
- if multiple_output_trick and len(outputs) > 1:
- # If we have more than one output, a rule like
- # foo bar: baz
- # that for *each* output we must run the action, potentially
- # in parallel. That is not what we're trying to write -- what
- # we want is that we run the action once and it generates all
- # the files.
- # http://www.gnu.org/software/hello/manual/automake/Multiple-Outputs.html
- # discusses this problem and has this solution:
- # 1) Write the naive rule that would produce parallel runs of
- # the action.
- # 2) Make the outputs seralized on each other, so we won't start
- # a parallel run until the first run finishes, at which point
- # we'll have generated all the outputs and we're done.
- self.WriteLn('%s: %s' % (' '.join(outputs[1:]), outputs[0]))
- # Add a dummy command to the "extra outputs" rule, otherwise make seems to
- # think these outputs haven't (couldn't have?) changed, and thus doesn't
- # flag them as changed (i.e. include in '$?') when evaluating dependent
- # rules, which in turn causes do_cmd() to skip running dependent commands.
- self.WriteLn('%s: ;' % (' '.join(outputs[1:])))
- self.WriteLn()
-
-
- def WriteAndroidNdkModuleRule(self, module_name, all_sources, link_deps):
- """Write a set of LOCAL_XXX definitions for Android NDK.
-
- These variable definitions will be used by Android NDK but do nothing for
- non-Android applications.
-
- Arguments:
- module_name: Android NDK module name, which must be unique among all
- module names.
- all_sources: A list of source files (will be filtered by Compilable).
- link_deps: A list of link dependencies, which must be sorted in
- the order from dependencies to dependents.
- """
- if self.type not in ('executable', 'shared_library', 'static_library'):
- return
-
- self.WriteLn('# Variable definitions for Android applications')
- self.WriteLn('include $(CLEAR_VARS)')
- self.WriteLn('LOCAL_MODULE := ' + module_name)
- self.WriteLn('LOCAL_CFLAGS := $(CFLAGS_$(BUILDTYPE)) '
- '$(DEFS_$(BUILDTYPE)) '
- # LOCAL_CFLAGS is applied to both of C and C++. There is
- # no way to specify $(CFLAGS_C_$(BUILDTYPE)) only for C
- # sources.
- '$(CFLAGS_C_$(BUILDTYPE)) '
- # $(INCS_$(BUILDTYPE)) includes the prefix '-I' while
- # LOCAL_C_INCLUDES does not expect it. So put it in
- # LOCAL_CFLAGS.
- '$(INCS_$(BUILDTYPE))')
- # LOCAL_CXXFLAGS is obsolete and LOCAL_CPPFLAGS is preferred.
- self.WriteLn('LOCAL_CPPFLAGS := $(CFLAGS_CC_$(BUILDTYPE))')
- self.WriteLn('LOCAL_C_INCLUDES :=')
- self.WriteLn('LOCAL_LDLIBS := $(LDFLAGS_$(BUILDTYPE)) $(LIBS)')
-
- # Detect the C++ extension.
- cpp_ext = {'.cc': 0, '.cpp': 0, '.cxx': 0}
- default_cpp_ext = '.cpp'
- for filename in all_sources:
- ext = os.path.splitext(filename)[1]
- if ext in cpp_ext:
- cpp_ext[ext] += 1
- if cpp_ext[ext] > cpp_ext[default_cpp_ext]:
- default_cpp_ext = ext
- self.WriteLn('LOCAL_CPP_EXTENSION := ' + default_cpp_ext)
-
- self.WriteList(map(self.Absolutify, filter(Compilable, all_sources)),
- 'LOCAL_SRC_FILES')
-
- # Filter out those which do not match prefix and suffix and produce
- # the resulting list without prefix and suffix.
- def DepsToModules(deps, prefix, suffix):
- modules = []
- for filepath in deps:
- filename = os.path.basename(filepath)
- if filename.startswith(prefix) and filename.endswith(suffix):
- modules.append(filename[len(prefix):-len(suffix)])
- return modules
-
- self.WriteList(
- DepsToModules(link_deps,
- generator_default_variables['SHARED_LIB_PREFIX'],
- generator_default_variables['SHARED_LIB_SUFFIX']),
- 'LOCAL_SHARED_LIBRARIES')
- self.WriteList(
- DepsToModules(link_deps,
- generator_default_variables['STATIC_LIB_PREFIX'],
- generator_default_variables['STATIC_LIB_SUFFIX']),
- 'LOCAL_STATIC_LIBRARIES')
-
- if self.type == 'executable':
- self.WriteLn('include $(BUILD_EXECUTABLE)')
- elif self.type == 'shared_library':
- self.WriteLn('include $(BUILD_SHARED_LIBRARY)')
- elif self.type == 'static_library':
- self.WriteLn('include $(BUILD_STATIC_LIBRARY)')
- self.WriteLn()
-
-
- def WriteLn(self, text=''):
- self.fp.write(text + '\n')
-
-
- def GetXcodeEnv(self, spec, target_relative_path=False):
- """Return the environment variables that Xcode would set. See
- http://developer.apple.com/library/mac/#documentation/DeveloperTools/Reference/XcodeBuildSettingRef/1-Build_Setting_Reference/build_setting_ref.html#//apple_ref/doc/uid/TP40003931-CH3-SW153
- for a full list."""
- if self.flavor != 'mac': return {}
-
- def StripProductDir(s):
- product_dir = generator_default_variables['PRODUCT_DIR']
- assert s.startswith(product_dir), s
- return s[len(product_dir) + 1:]
-
- product_name = spec.get('product_name', self.output)
-
- # Some postbuilds try to read a build output file at
- # ""${BUILT_PRODUCTS_DIR}/${FULL_PRODUCT_NAME}". Static libraries end up
- # "$(obj).target", so
- # BUILT_PRODUCTS_DIR is $(builddir)
- # FULL_PRODUCT_NAME is $(out).target/path/to/lib.a
- # Since $(obj) contains out/Debug already, the postbuild
- # would get out/Debug/out/Debug/obj.target/path/to/lib.a. To prevent this,
- # remove the "out/Debug" prefix from $(obj).
- if product_name.startswith('$(obj)'):
- product_name = (
- '$(subst $(builddir)/,,$(obj))' + product_name[len('$(obj)'):])
-
- built_products_dir = generator_default_variables['PRODUCT_DIR']
- srcroot = self.path
- if target_relative_path:
- built_products_dir = gyp.common.RelativePath(built_products_dir, srcroot)
- srcroot = '.'
- # These are filled in on a as-needed basis.
- env = {
- 'BUILT_PRODUCTS_DIR' : built_products_dir,
- 'CONFIGURATION' : '$(BUILDTYPE)',
- 'PRODUCT_NAME' : product_name,
- # See /Developer/Platforms/MacOSX.platform/Developer/Library/Xcode/Specifications/MacOSX\ Product\ Types.xcspec for FULL_PRODUCT_NAME
- 'FULL_PRODUCT_NAME' : product_name,
- 'SRCROOT' : srcroot,
- # This is not true for static libraries, but currently the env is only
- # written for bundles:
- 'TARGET_BUILD_DIR' : built_products_dir,
- 'TEMP_DIR' : '$(TMPDIR)',
- }
- if self.type in ('executable', 'shared_library'):
- env['EXECUTABLE_NAME'] = os.path.basename(self.output_binary)
- if self.type in ('executable', 'shared_library', 'loadable_module'):
- env['EXECUTABLE_PATH'] = self.xcode_settings.GetExecutablePath()
- if self.is_mac_bundle:
- env['CONTENTS_FOLDER_PATH'] = \
- self.xcode_settings.GetBundleContentsFolderPath()
- env['UNLOCALIZED_RESOURCES_FOLDER_PATH'] = \
- self.xcode_settings.GetBundleResourceFolder()
- env['INFOPLIST_PATH'] = self.xcode_settings.GetBundlePlistPath()
-
- # TODO(thakis): Remove this.
- env['EXECUTABLE_PATH'] = QuoteSpaces(env['EXECUTABLE_PATH'])
- env['CONTENTS_FOLDER_PATH'] = QuoteSpaces(env['CONTENTS_FOLDER_PATH'])
- env['INFOPLIST_PATH'] = QuoteSpaces(env['INFOPLIST_PATH'])
-
- return env
-
-
- def WriteXcodeEnv(self,
- target,
- spec,
- target_relative_path=False,
- additional_settings={}):
- env = additional_settings
- env.update(self.GetXcodeEnv(spec, target_relative_path))
-
- # Keys whose values will not have $(builddir) replaced with $(abs_builddir).
- # These have special substitution rules in some cases; see above in
- # GetXcodeEnv() for the full rationale.
- keys_to_not_absolutify = ('PRODUCT_NAME', 'FULL_PRODUCT_NAME')
-
- # Perform some transformations that are required to mimic Xcode behavior.
- for k in env:
- # Values that are not strings but are, for example, lists or tuples such
- # as LDFLAGS or CFLAGS, should not be written out because they are
- # not needed and it's undefined how multi-valued keys should be written.
- if not isinstance(env[k], str):
- continue
-
- # For
- # foo := a\ b
- # the escaped space does the right thing. For
- # export foo := a\ b
- # it does not -- the backslash is written to the env as literal character.
- # Hence, unescape all spaces here.
- v = env[k].replace(r'\ ', ' ')
-
- # Xcode works purely with absolute paths. When writing env variables to
- # mimic its usage, replace $(builddir) with $(abs_builddir).
- if k not in keys_to_not_absolutify:
- v = v.replace('$(builddir)', '$(abs_builddir)')
-
- self.WriteLn('%s: export %s := %s' % (target, k, v))
-
-
- def Objectify(self, path):
- """Convert a path to its output directory form."""
- if '$(' in path:
- path = path.replace('$(obj)' + os.sep, ('$(obj).%s' + os.sep + '$(TARGET)' + os.sep) % self.toolset)
- return path
- return ('$(obj).%s' + os.sep + '$(TARGET)' + os.sep + '%s') % (self.toolset, path)
-
-
- def Pchify(self, path, lang):
- """Convert a prefix header path to its output directory form."""
- if '$(' in path:
- path = path.replace('$(obj)' + os.sep, ('$(obj).%s' + os.sep + '$(TARGET)' + os.sep + 'pch-%s') %
- (self.toolset, lang))
- return path
- return ('$(obj).%s' + os.sep + '$(TARGET)' + os.sep + 'pch-%s/%s') % (self.toolset, lang, path)
-
-
- def Absolutify(self, path):
- """Convert a subdirectory-relative path into a base-relative path.
- Skips over paths that contain variables."""
- if '$(' in path:
- return path
- return os.path.normpath(os.path.join(self.path, path))
-
-
- def FixupArgPath(self, arg):
- if '/' in arg or '.h.' in arg:
- return self.Absolutify(arg)
- return arg
-
-
- def ExpandInputRoot(self, template, expansion):
- if '%(INPUT_ROOT)s' not in template:
- return template
- path = template % { 'INPUT_ROOT': expansion }
- if not os.path.dirname(path):
- # If it's just the file name, turn it into a path so FixupArgPath()
- # will know to Absolutify() it.
- path = os.path.join('.', path)
- return path
-
-
- def _InstallableTargetInstallPath(self):
- """Returns the location of the final output for an installable target."""
- # Xcode puts shared_library results into PRODUCT_DIR, and some gyp files
- # rely on this. Emulate this behavior for mac.
- if self.type == 'shared_library' and self.flavor != 'mac':
- # Install all shared libs into a common directory (per toolset) for
- # convenient access with LD_LIBRARY_PATH.
- return '($(builddir)' + os.sep + 'lib.%s' + os.sep + '%s') % (self.toolset, self.alias)
- return '$(builddir)' + os.sep + self.alias
-
-
-def WriteAutoRegenerationRule(params, root_makefile, makefile_name,
- build_files):
- """Write the target to regenerate the Makefile."""
- options = params['options']
- build_files_args = [gyp.common.RelativePath(filename, options.toplevel_dir)
- for filename in params['build_files_arg']]
- gyp_binary = gyp.common.FixIfRelativePath(params['gyp_binary'],
- options.toplevel_dir)
- if not gyp_binary.startswith(os.sep):
- gyp_binary = os.path.join('.', gyp_binary)
- root_makefile.write(
- "quiet_cmd_regen_makefile = ACTION Regenerating $@\n"
- "cmd_regen_makefile = %(cmd)s\n"
- "%(makefile_name)s: %(deps)s\n"
- "\t$(call do_cmd,regen_makefile)\n\n" % {
- 'makefile_name': makefile_name,
- 'deps': ' '.join(map(Sourceify, build_files)),
- 'cmd': gyp.common.EncodePOSIXShellList(
- [gyp_binary, '-fmake'] +
- gyp.RegenerateFlags(options) +
- build_files_args)})
-
-
-def RunSystemTests(flavor):
- """Run tests against the system to compute default settings for commands.
-
- Returns:
- dictionary of settings matching the block of command-lines used in
- SHARED_HEADER. E.g. the dictionary will contain a ARFLAGS.target
- key for the default ARFLAGS for the target ar command.
- """
- # Compute flags used for building static archives.
- # N.B.: this fallback logic should match the logic in SHARED_HEADER.
- # See comment there for more details.
- ar_target = os.environ.get('AR.target', os.environ.get('AR', 'ar'))
- cc_target = os.environ.get('CC.target', os.environ.get('CC', 'cc'))
- arflags_target = 'crs'
- # ar -T enables thin archives on Linux. OS X's ar supports a -T flag, but it
- # does something useless (it limits filenames in the archive to 15 chars).
- if flavor != 'mac' and gyp.system_test.TestArSupportsT(ar_command=ar_target,
- cc_command=cc_target):
- arflags_target = 'crsT'
-
- ar_host = os.environ.get('AR.host', 'ar')
- cc_host = os.environ.get('CC.host', 'gcc')
- arflags_host = 'crs'
- # It feels redundant to compute this again given that most builds aren't
- # cross-compiles, but due to quirks of history CC.host defaults to 'gcc'
- # while CC.target defaults to 'cc', so the commands really are different
- # even though they're nearly guaranteed to run the same code underneath.
- if flavor != 'mac' and gyp.system_test.TestArSupportsT(ar_command=ar_host,
- cc_command=cc_host):
- arflags_host = 'crsT'
-
- link_flags = ''
- if gyp.system_test.TestLinkerSupportsThreads(cc_command=cc_target):
- # N.B. we don't test for cross-compilation; as currently written, we
- # don't even use flock when linking in the cross-compile setup!
- # TODO(evan): refactor cross-compilation such that this code can
- # be reused.
- link_flags = '-Wl,--threads -Wl,--thread-count=4'
-
- # TODO(evan): cache this output. (But then we'll need to add extra
- # flags to gyp to flush the cache, yuk! It's fast enough for now to
- # just run it every time.)
-
- return { 'ARFLAGS.target': arflags_target,
- 'ARFLAGS.host': arflags_host,
- 'LINK_flags': link_flags }
-
-
-def CopyMacTool(out_path):
- """Finds mac_tool.gyp in the gyp directory and copies it to |out_path|."""
- source_path = os.path.join(
- os.path.dirname(os.path.abspath(__file__)), '..', 'mac_tool.py')
- source_file = open(source_path)
- source = source_file.readlines()
- source_file.close()
- mactool_file = open(out_path, 'w')
- mactool_file.write(
- ''.join([source[0], '# Generated by gyp. Do not edit.\n'] + source[1:]))
- mactool_file.close()
-
-
-def GenerateOutput(target_list, target_dicts, data, params):
- options = params['options']
- flavor = 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)
-
- def CalculateMakefilePath(build_file, base_name):
- """Determine where to write a Makefile for a given gyp file."""
- # Paths in gyp files are relative to the .gyp file, but we want
- # paths relative to the source root for the master makefile. Grab
- # the path of the .gyp file as the base to relativize against.
- # E.g. "foo/bar" when we're constructing targets for "foo/bar/baz.gyp".
- base_path = gyp.common.RelativePath(os.path.dirname(build_file),
- options.depth)
- # We write the file in the base_path directory.
- output_file = os.path.join(options.depth, base_path, base_name)
- if options.generator_output:
- output_file = os.path.join(options.generator_output, output_file)
- base_path = gyp.common.RelativePath(os.path.dirname(build_file),
- options.toplevel_dir)
- return base_path, output_file
-
- # TODO: search for the first non-'Default' target. This can go
- # away when we add verification that all targets have the
- # necessary configurations.
- default_configuration = None
- toolsets = set([target_dicts[target]['toolset'] for target in target_list])
- for target in target_list:
- spec = target_dicts[target]
- if spec['default_configuration'] != 'Default':
- default_configuration = spec['default_configuration']
- break
- if not default_configuration:
- default_configuration = 'Default'
-
- srcdir = '.'
- makefile_name = 'Makefile' + options.suffix
- makefile_path = os.path.join(options.toplevel_dir, makefile_name)
- if options.generator_output:
- global srcdir_prefix
- global os_sep
- makefile_path = os.path.join(options.generator_output, makefile_path)
- srcdir = gyp.common.RelativePath(srcdir, options.generator_output)
- srcdir_prefix = '$(srcdir)' + os.sep
- os_sep = os.sep
-
- header_params = {
- 'builddir': builddir_name,
- 'default_configuration': default_configuration,
- 'flock': 'flock',
- 'flock_index': 1,
- 'link_commands': LINK_COMMANDS_LINUX,
- 'mac_commands': '',
- 'srcdir': srcdir,
- }
- if flavor == 'mac':
- header_params.update({
- 'flock': './gyp-mac-tool flock',
- 'flock_index': 2,
- 'link_commands': LINK_COMMANDS_MAC,
- 'mac_commands': SHARED_HEADER_MAC_COMMANDS,
- })
- header_params.update(RunSystemTests(flavor))
-
- ensure_directory_exists(makefile_path)
- root_makefile = open(makefile_path, 'w')
- root_makefile.write(SHARED_HEADER % header_params)
- # Currently any versions have the same effect, but in future the behavior
- # could be different.
- if android_ndk_version:
- root_makefile.write(
- '# Define LOCAL_PATH for build of Android applications.\n'
- 'LOCAL_PATH := $(call my-dir)\n'
- '\n')
- for toolset in toolsets:
- root_makefile.write('TOOLSET := %s\n' % toolset)
- WriteRootHeaderSuffixRules(root_makefile)
-
- # Put mac_tool next to the root Makefile.
- if flavor == 'mac':
- mactool_path = os.path.join(os.path.dirname(makefile_path), 'gyp-mac-tool')
- if os.path.exists(mactool_path):
- os.remove(mactool_path)
- CopyMacTool(mactool_path)
- os.chmod(mactool_path, 0755) # Make file executable.
-
- # Find the list of targets that derive from the gyp file(s) being built.
- needed_targets = set()
- for build_file in params['build_files']:
- for target in gyp.common.AllTargets(target_list, target_dicts, build_file):
- needed_targets.add(target)
-
- num_outputs = 0
- build_files = set()
- include_list = set()
- for qualified_target in target_list:
- build_file, target, toolset = gyp.common.ParseQualifiedTarget(
- qualified_target)
- build_files.add(gyp.common.RelativePath(build_file, options.toplevel_dir))
- included_files = data[build_file]['included_files']
- for included_file in included_files:
- # The included_files entries are relative to the dir of the build file
- # that included them, so we have to undo that and then make them relative
- # to the root dir.
- relative_include_file = gyp.common.RelativePath(
- gyp.common.UnrelativePath(included_file, build_file),
- options.toplevel_dir)
- abs_include_file = os.path.abspath(relative_include_file)
- # If the include file is from the ~/.gyp dir, we should use absolute path
- # so that relocating the src dir doesn't break the path.
- if (params['home_dot_gyp'] and
- abs_include_file.startswith(params['home_dot_gyp'])):
- build_files.add(abs_include_file)
- else:
- build_files.add(relative_include_file)
-
- base_path, output_file = CalculateMakefilePath(build_file,
- target + '.' + toolset + options.suffix + '.mk')
-
- spec = target_dicts[qualified_target]
- configs = spec['configurations']
-
- # The xcode generator special-cases global xcode_settings and does something
- # that amounts to merging in the global xcode_settings into each local
- # xcode_settings dict.
- if flavor == 'mac':
- global_xcode_settings = data[build_file].get('xcode_settings', {})
- for configname in configs.keys():
- config = configs[configname]
- if 'xcode_settings' in config:
- new_settings = global_xcode_settings.copy()
- new_settings.update(config['xcode_settings'])
- config['xcode_settings'] = new_settings
-
- writer = MakefileWriter(generator_flags, flavor)
- writer.Write(qualified_target, base_path, output_file, spec, configs,
- part_of_all=qualified_target in needed_targets)
- num_outputs += writer.NumOutputs()
-
- # Our root_makefile lives at the source root. Compute the relative path
- # from there to the output_file for including.
- mkfile_rel_path = gyp.common.RelativePath(output_file,
- os.path.dirname(makefile_path))
- include_list.add(mkfile_rel_path)
-
- # Write out per-gyp (sub-project) Makefiles.
- depth_rel_path = gyp.common.RelativePath(options.depth, os.getcwd())
- for build_file in build_files:
- # The paths in build_files were relativized above, so undo that before
- # testing against the non-relativized items in target_list and before
- # calculating the Makefile path.
- build_file = os.path.join(depth_rel_path, build_file)
- gyp_targets = [target_dicts[target]['target_name'] for target in target_list
- if target.startswith(build_file) and
- target in needed_targets]
- # Only generate Makefiles for gyp files with targets.
- if not gyp_targets:
- continue
- base_path, output_file = CalculateMakefilePath(build_file,
- os.path.splitext(os.path.basename(build_file))[0] + '.Makefile')
- makefile_rel_path = gyp.common.RelativePath(os.path.dirname(makefile_path),
- os.path.dirname(output_file))
- writer.WriteSubMake(output_file, makefile_rel_path, gyp_targets,
- builddir_name)
-
-
- # Write out the sorted list of includes.
- root_makefile.write('\n')
- for include_file in sorted(include_list):
- # We wrap each .mk include in an if statement so users can tell make to
- # not load a file by setting NO_LOAD. The below make code says, only
- # load the .mk file if the .mk filename doesn't start with a token in
- # NO_LOAD.
- root_makefile.write(
- "ifeq ($(strip $(foreach prefix,$(NO_LOAD),\\\n"
- " $(findstring $(join ^,$(prefix)),\\\n"
- " $(join ^," + include_file + ")))),)\n")
- root_makefile.write(" include " + include_file + "\n")
- root_makefile.write("endif\n")
- root_makefile.write('\n')
-
- if generator_flags.get('auto_regeneration', True):
- WriteAutoRegenerationRule(params, root_makefile, makefile_name, build_files)
-
- # Write the rule to load dependencies. We batch 1000 files at a time to
- # avoid overflowing the command line.
- all_deps = ""
- for i in range(1001, num_outputs, 1000):
- all_deps += (("""
- ifneq ($(word %(start)d,$(d_files)),)
- $(shell cat $(wordlist %(start)d,%(end)d,$(d_files)) >> $(depsdir)""" + os.sep + """all.deps)
- endif""") % { 'start': i, 'end': i + 999 })
-
- # Add a check to make sure we tried to process all the .d files.
- all_deps += """
- ifneq ($(word %(last)d,$(d_files)),)
- $(error Found unprocessed dependency files (gyp didn't generate enough rules!))
- endif
-""" % { 'last': ((num_outputs / 1000) + 1) * 1000 + 1 }
-
- root_makefile.write(SHARED_FOOTER % { 'generate_all_deps': all_deps })
-
- root_makefile.close()
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/msvs.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/msvs.py
@@ -7,37 +7,52 @@ import ntpath
import os
import posixpath
import re
import subprocess
import sys
import gyp.common
import gyp.easy_xml as easy_xml
+import gyp.generator.ninja as ninja_generator
import gyp.MSVSNew as MSVSNew
import gyp.MSVSProject as MSVSProject
import gyp.MSVSSettings as MSVSSettings
import gyp.MSVSToolFile as MSVSToolFile
import gyp.MSVSUserFile as MSVSUserFile
+import gyp.MSVSUtil as MSVSUtil
import gyp.MSVSVersion as MSVSVersion
from gyp.common import GypError
+from gyp.common import OrderedSet
+
+# TODO: Remove once bots are on 2.7, http://crbug.com/241769
+def _import_OrderedDict():
+ import collections
+ try:
+ return collections.OrderedDict
+ except AttributeError:
+ import gyp.ordered_dict
+ return gyp.ordered_dict.OrderedDict
+OrderedDict = _import_OrderedDict()
# Regular expression for validating Visual Studio GUIDs. If the GUID
# contains lowercase hex letters, MSVS will be fine. However,
# IncrediBuild BuildConsole will parse the solution file, but then
# silently skip building the target causing hard to track down errors.
# Note that this only happens with the BuildConsole, and does not occur
# if IncrediBuild is executed from inside Visual Studio. This regex
# validates that the string looks like a GUID with all uppercase hex
# letters.
-VALID_MSVS_GUID_CHARS = re.compile('^[A-F0-9\-]+$')
+VALID_MSVS_GUID_CHARS = re.compile(r'^[A-F0-9\-]+$')
generator_default_variables = {
+ 'DRIVER_PREFIX': '',
+ 'DRIVER_SUFFIX': '.sys',
'EXECUTABLE_PREFIX': '',
'EXECUTABLE_SUFFIX': '.exe',
'STATIC_LIB_PREFIX': '',
'SHARED_LIB_PREFIX': '',
'STATIC_LIB_SUFFIX': '.lib',
'SHARED_LIB_SUFFIX': '.dll',
'INTERMEDIATE_DIR': '$(IntDir)',
'SHARED_INTERMEDIATE_DIR': '$(OutDir)obj/global_intermediate',
@@ -58,19 +73,32 @@ generator_additional_path_sections = [
'msvs_cygwin_dirs',
'msvs_props',
]
generator_additional_non_configuration_keys = [
'msvs_cygwin_dirs',
'msvs_cygwin_shell',
+ 'msvs_large_pdb',
'msvs_shard',
+ 'msvs_external_builder',
+ 'msvs_external_builder_out_dir',
+ 'msvs_external_builder_build_cmd',
+ 'msvs_external_builder_clean_cmd',
+ 'msvs_external_builder_clcompile_cmd',
+ 'msvs_enable_winrt',
+ 'msvs_requires_importlibrary',
+ 'msvs_enable_winphone',
+ 'msvs_application_type_revision',
+ 'msvs_target_platform_version',
+ 'msvs_target_platform_minversion',
]
+generator_filelist_paths = None
# List of precompiled header related keys.
precomp_keys = [
'msvs_precompiled_header',
'msvs_precompiled_source',
]
@@ -91,21 +119,21 @@ def _GetDomainAndUserName():
global cached_domain
if not cached_domain or not cached_username:
domain = os.environ.get('USERDOMAIN')
username = os.environ.get('USERNAME')
if not domain or not username:
call = subprocess.Popen(['net', 'config', 'Workstation'],
stdout=subprocess.PIPE)
config = call.communicate()[0]
- username_re = re.compile('^User name\s+(\S+)', re.MULTILINE)
+ username_re = re.compile(r'^User name\s+(\S+)', re.MULTILINE)
username_match = username_re.search(config)
if username_match:
username = username_match.group(1)
- domain_re = re.compile('^Logon domain\s+(\S+)', re.MULTILINE)
+ domain_re = re.compile(r'^Logon domain\s+(\S+)', re.MULTILINE)
domain_match = domain_re.search(config)
if domain_match:
domain = domain_match.group(1)
cached_domain = domain
cached_username = username
return (cached_domain, cached_username)
fixpath_prefix = None
@@ -147,113 +175,152 @@ def _FixPath(path):
def _FixPaths(paths):
"""Fix each of the paths of the list."""
return [_FixPath(i) for i in paths]
def _ConvertSourcesToFilterHierarchy(sources, prefix=None, excluded=None,
- list_excluded=True):
+ list_excluded=True, msvs_version=None):
"""Converts a list split source file paths into a vcproj folder hierarchy.
Arguments:
sources: A list of source file paths split.
prefix: A list of source file path layers meant to apply to each of sources.
excluded: A set of excluded files.
+ msvs_version: A MSVSVersion object.
Returns:
A hierarchy of filenames and MSVSProject.Filter objects that matches the
layout of the source tree.
For example:
_ConvertSourcesToFilterHierarchy([['a', 'bob1.c'], ['b', 'bob2.c']],
prefix=['joe'])
-->
[MSVSProject.Filter('a', contents=['joe\\a\\bob1.c']),
MSVSProject.Filter('b', contents=['joe\\b\\bob2.c'])]
"""
if not prefix: prefix = []
result = []
excluded_result = []
- folders = dict()
+ folders = OrderedDict()
# Gather files into the final result, excluded, or folders.
for s in sources:
if len(s) == 1:
filename = _NormalizedSource('\\'.join(prefix + s))
if filename in excluded:
excluded_result.append(filename)
else:
result.append(filename)
- else:
+ elif msvs_version and not msvs_version.UsesVcxproj():
+ # For MSVS 2008 and earlier, we need to process all files before walking
+ # the sub folders.
if not folders.get(s[0]):
folders[s[0]] = []
folders[s[0]].append(s[1:])
+ else:
+ contents = _ConvertSourcesToFilterHierarchy([s[1:]], prefix + [s[0]],
+ excluded=excluded,
+ list_excluded=list_excluded,
+ msvs_version=msvs_version)
+ contents = MSVSProject.Filter(s[0], contents=contents)
+ result.append(contents)
# Add a folder for excluded files.
if excluded_result and list_excluded:
excluded_folder = MSVSProject.Filter('_excluded_files',
contents=excluded_result)
result.append(excluded_folder)
+
+ if msvs_version and msvs_version.UsesVcxproj():
+ return result
+
# Populate all the folders.
for f in folders:
contents = _ConvertSourcesToFilterHierarchy(folders[f], prefix=prefix + [f],
excluded=excluded,
- list_excluded=list_excluded)
+ list_excluded=list_excluded,
+ msvs_version=msvs_version)
contents = MSVSProject.Filter(f, contents=contents)
result.append(contents)
-
return result
def _ToolAppend(tools, tool_name, setting, value, only_if_unset=False):
if not value: return
+ _ToolSetOrAppend(tools, tool_name, setting, value, only_if_unset)
+
+
+def _ToolSetOrAppend(tools, tool_name, setting, value, only_if_unset=False):
# TODO(bradnelson): ugly hack, fix this more generally!!!
if 'Directories' in setting or 'Dependencies' in setting:
if type(value) == str:
value = value.replace('/', '\\')
else:
value = [i.replace('/', '\\') for i in value]
if not tools.get(tool_name):
tools[tool_name] = dict()
tool = tools[tool_name]
+ if 'CompileAsWinRT' == setting:
+ return
if tool.get(setting):
if only_if_unset: return
- if type(tool[setting]) == list:
+ if type(tool[setting]) == list and type(value) == list:
tool[setting] += value
else:
raise TypeError(
'Appending "%s" to a non-list setting "%s" for tool "%s" is '
'not allowed, previous value: %s' % (
value, setting, tool_name, str(tool[setting])))
else:
tool[setting] = value
+def _ConfigTargetVersion(config_data):
+ return config_data.get('msvs_target_version', 'Windows7')
+
+
def _ConfigPlatform(config_data):
return config_data.get('msvs_configuration_platform', 'Win32')
def _ConfigBaseName(config_name, platform_name):
if config_name.endswith('_' + platform_name):
- return config_name[0:-len(platform_name)-1]
+ return config_name[0:-len(platform_name) - 1]
else:
return config_name
def _ConfigFullName(config_name, config_data):
platform_name = _ConfigPlatform(config_data)
return '%s|%s' % (_ConfigBaseName(config_name, platform_name), platform_name)
+def _ConfigWindowsTargetPlatformVersion(config_data):
+ ver = config_data.get('msvs_windows_sdk_version')
+
+ for key in [r'HKLM\Software\Microsoft\Microsoft SDKs\Windows\%s',
+ r'HKLM\Software\Wow6432Node\Microsoft\Microsoft SDKs\Windows\%s']:
+ sdk_dir = MSVSVersion._RegistryGetValue(key % ver, 'InstallationFolder')
+ if not sdk_dir:
+ continue
+ version = MSVSVersion._RegistryGetValue(key % ver, 'ProductVersion') or ''
+ # Find a matching entry in sdk_dir\include.
+ names = sorted([x for x in os.listdir(r'%s\include' % sdk_dir)
+ if x.startswith(version)], reverse=True)
+ return names[0]
+
+
def _BuildCommandLineForRuleRaw(spec, cmd, cygwin_shell, has_input_path,
quote_cmd, do_setup_env):
if [x for x in cmd if '$(InputDir)' in x]:
input_dir_preamble = (
'set INPUTDIR=$(InputDir)\n'
- 'set INPUTDIR=%INPUTDIR:$(ProjectDir)=%\n'
+ 'if NOT DEFINED INPUTDIR set INPUTDIR=.\\\n'
'set INPUTDIR=%INPUTDIR:~0,-1%\n'
)
else:
input_dir_preamble = ''
if cygwin_shell:
# Find path to cygwin.
cygwin_dir = _FixPath(spec.get('msvs_cygwin_dirs', ['.'])[0])
@@ -265,17 +332,17 @@ def _BuildCommandLineForRuleRaw(spec, cm
'`cygpath -m "${OUTDIR}"`') for i in direct_cmd]
direct_cmd = [i.replace('$(InputDir)',
'`cygpath -m "${INPUTDIR}"`') for i in direct_cmd]
if has_input_path:
direct_cmd = [i.replace('$(InputPath)',
'`cygpath -m "${INPUTPATH}"`')
for i in direct_cmd]
direct_cmd = ['\\"%s\\"' % i.replace('"', '\\\\\\"') for i in direct_cmd]
- #direct_cmd = gyp.common.EncodePOSIXShellList(direct_cmd)
+ # direct_cmd = gyp.common.EncodePOSIXShellList(direct_cmd)
direct_cmd = ' '.join(direct_cmd)
# TODO(quote): regularize quoting path names throughout the module
cmd = ''
if do_setup_env:
cmd += 'call "$(ProjectDir)%(cygwin_dir)s\\setup_env.bat" && '
cmd += 'set CYGWIN=nontsec&& '
if direct_cmd.find('NUMBER_OF_PROCESSORS') >= 0:
cmd += 'set /a NUMBER_OF_PROCESSORS_PLUS_1=%%NUMBER_OF_PROCESSORS%%+1&& '
@@ -301,17 +368,17 @@ def _BuildCommandLineForRuleRaw(spec, cm
# actually batch files themselves.
command.insert(0, 'call')
# Fix the paths
# TODO(quote): This is a really ugly heuristic, and will miss path fixing
# for arguments like "--arg=path" or "/opt:path".
# If the argument starts with a slash or dash, it's probably a command line
# switch
arguments = [i if (i[:1] in "/-") else _FixPath(i) for i in cmd[1:]]
- arguments = [i.replace('$(InputDir)','%INPUTDIR%') for i in arguments]
+ arguments = [i.replace('$(InputDir)', '%INPUTDIR%') for i in arguments]
arguments = [MSVSSettings.FixVCMacroSlashes(i) for i in arguments]
if quote_cmd:
# Support a mode for using cmd directly.
# Convert any paths to native form (first element is used directly).
# TODO(quote): regularize quoting path names throughout the module
arguments = ['"%s"' % i for i in arguments]
# Collapse into a single command.
return input_dir_preamble + ' '.join(command + arguments)
@@ -400,23 +467,23 @@ def _AddAccumulatedActionsToMSVS(p, spec
Arguments:
p: the target project
spec: the target project dict
actions_dict: dictionary keyed on input name, which maps to a list of
dicts describing the actions attached to that input file.
"""
for primary_input in actions_dict:
- inputs = set()
- outputs = set()
+ inputs = OrderedSet()
+ outputs = OrderedSet()
descriptions = []
commands = []
for action in actions_dict[primary_input]:
- inputs.update(set(action['inputs']))
- outputs.update(set(action['outputs']))
+ inputs.update(OrderedSet(action['inputs']))
+ outputs.update(OrderedSet(action['outputs']))
descriptions.append(action['description'])
commands.append(action['command'])
# Add the custom build step for one input file.
description = ', and also '.join(descriptions)
command = '\r\n'.join(commands)
_AddCustomBuildToolForMSVS(p, spec,
primary_input=primary_input,
inputs=inputs,
@@ -448,33 +515,32 @@ def _FindRuleTriggerFiles(rule, sources)
"""Find the list of files which a particular rule applies to.
Arguments:
rule: the rule in question
sources: the set of all known source files for this project
Returns:
The list of sources that trigger a particular rule.
"""
- rule_ext = rule['extension']
- return [s for s in sources if s.endswith('.' + rule_ext)]
+ return rule.get('rule_sources', [])
def _RuleInputsAndOutputs(rule, trigger_file):
"""Find the inputs and outputs generated by a rule.
Arguments:
rule: the rule in question.
trigger_file: the main trigger for this rule.
Returns:
The pair of (inputs, outputs) involved in this rule.
"""
raw_inputs = _FixPaths(rule.get('inputs', []))
raw_outputs = _FixPaths(rule.get('outputs', []))
- inputs = set()
- outputs = set()
+ inputs = OrderedSet()
+ outputs = OrderedSet()
inputs.add(trigger_file)
for i in raw_inputs:
inputs.add(_RuleExpandPath(i, trigger_file))
for o in raw_outputs:
outputs.add(_RuleExpandPath(o, trigger_file))
return (inputs, outputs)
@@ -535,26 +601,26 @@ def _GenerateExternalRules(rules, output
actions_to_add: The list of actions we will add to.
"""
filename = '%s_rules%s.mk' % (spec['target_name'], options.suffix)
mk_file = gyp.common.WriteOnDiff(os.path.join(output_dir, filename))
# Find cygwin style versions of some paths.
mk_file.write('OutDirCygwin:=$(shell cygpath -u "$(OutDir)")\n')
mk_file.write('IntDirCygwin:=$(shell cygpath -u "$(IntDir)")\n')
# Gather stuff needed to emit all: target.
- all_inputs = set()
- all_outputs = set()
- all_output_dirs = set()
+ all_inputs = OrderedSet()
+ all_outputs = OrderedSet()
+ all_output_dirs = OrderedSet()
first_outputs = []
for rule in rules:
trigger_files = _FindRuleTriggerFiles(rule, sources)
for tf in trigger_files:
inputs, outputs = _RuleInputsAndOutputs(rule, tf)
- all_inputs.update(set(inputs))
- all_outputs.update(set(outputs))
+ all_inputs.update(OrderedSet(inputs))
+ all_outputs.update(OrderedSet(outputs))
# Only use one target from each rule as the dependency for
# 'all' so we don't try to build each rule multiple times.
first_outputs.append(list(outputs)[0])
# Get the unique output directories for this rule.
output_dirs = [os.path.split(i)[0] for i in outputs]
for od in output_dirs:
all_output_dirs.add(od)
first_outputs_cyg = [_Cygwinify(i) for i in first_outputs]
@@ -715,17 +781,17 @@ def _EscapeCppDefineForMSVS(s):
quote_replacer_regex2 = re.compile(r'(\\+)"')
def _EscapeCommandLineArgumentForMSBuild(s):
"""Escapes a Windows command-line argument for use by MSBuild."""
def _Replace(match):
- return (len(match.group(1))/2*4)*'\\' + '\\"'
+ return (len(match.group(1)) / 2 * 4) * '\\' + '\\"'
# Escape all quotes so that they are interpreted literally.
s = quote_replacer_regex2.sub(_Replace, s)
return s
def _EscapeMSBuildSpecialCharacters(s):
escape_dictionary = {
@@ -773,46 +839,51 @@ def _GenerateRulesForMSVS(p, output_dir,
# Handle rules that use a native rules file.
if rules_native:
_GenerateNativeRulesForMSVS(p, rules_native, output_dir, spec, options)
# Handle external rules (non-native rules).
if rules_external:
_GenerateExternalRules(rules_external, output_dir, spec,
sources, options, actions_to_add)
- _AdjustSourcesForRules(rules, sources, excluded_sources)
-
-
-def _AdjustSourcesForRules(rules, sources, excluded_sources):
+ _AdjustSourcesForRules(rules, sources, excluded_sources, False)
+
+
+def _AdjustSourcesForRules(rules, sources, excluded_sources, is_msbuild):
# Add outputs generated by each rule (if applicable).
for rule in rules:
- # Done if not processing outputs as sources.
- if int(rule.get('process_outputs_as_sources', False)):
- # Add in the outputs from this rule.
- trigger_files = _FindRuleTriggerFiles(rule, sources)
- for trigger_file in trigger_files:
+ # Add in the outputs from this rule.
+ trigger_files = _FindRuleTriggerFiles(rule, sources)
+ for trigger_file in trigger_files:
+ # Remove trigger_file from excluded_sources to let the rule be triggered
+ # (e.g. rule trigger ax_enums.idl is added to excluded_sources
+ # because it's also in an action's inputs in the same project)
+ excluded_sources.discard(_FixPath(trigger_file))
+ # Done if not processing outputs as sources.
+ if int(rule.get('process_outputs_as_sources', False)):
inputs, outputs = _RuleInputsAndOutputs(rule, trigger_file)
- inputs = set(_FixPaths(inputs))
- outputs = set(_FixPaths(outputs))
+ inputs = OrderedSet(_FixPaths(inputs))
+ outputs = OrderedSet(_FixPaths(outputs))
inputs.remove(_FixPath(trigger_file))
sources.update(inputs)
- excluded_sources.update(inputs)
+ if not is_msbuild:
+ excluded_sources.update(inputs)
sources.update(outputs)
def _FilterActionsFromExcluded(excluded_sources, actions_to_add):
"""Take inputs with actions attached out of the list of exclusions.
Arguments:
excluded_sources: list of source files not to be built.
actions_to_add: dict of actions keyed on source file they're attached to.
Returns:
excluded_sources with files that have actions attached removed.
"""
- must_keep = set(_FixPaths(actions_to_add.keys()))
+ must_keep = OrderedSet(_FixPaths(actions_to_add.keys()))
return [s for s in excluded_sources if s not in must_keep]
def _GetDefaultConfiguration(spec):
return spec['configurations'][spec['default_configuration']]
def _GetGuidOfProject(proj_path, spec):
@@ -849,16 +920,18 @@ def _GetMsbuildToolsetOfProject(proj_pat
Returns:
the platform toolset string or None.
"""
# Pluck out the default configuration.
default_config = _GetDefaultConfiguration(spec)
toolset = default_config.get('msbuild_toolset')
if not toolset and version.DefaultToolset():
toolset = version.DefaultToolset()
+ if spec['type'] == 'windows_driver':
+ toolset = 'WindowsKernelModeDriver10.0'
return toolset
def _GenerateProject(project, options, version, generator_flags):
"""Generates a vcproj file.
Arguments:
project: the MSVSProject object.
@@ -875,57 +948,97 @@ def _GenerateProject(project, options, v
return []
if version.UsesVcxproj():
return _GenerateMSBuildProject(project, options, version, generator_flags)
else:
return _GenerateMSVSProject(project, options, version, generator_flags)
+# TODO: Avoid code duplication with _ValidateSourcesForOSX in make.py.
+def _ValidateSourcesForMSVSProject(spec, version):
+ """Makes sure if duplicate basenames are not specified in the source list.
+
+ Arguments:
+ spec: The target dictionary containing the properties of the target.
+ version: The VisualStudioVersion object.
+ """
+ # This validation should not be applied to MSVC2010 and later.
+ assert not version.UsesVcxproj()
+
+ # TODO: Check if MSVC allows this for loadable_module targets.
+ if spec.get('type', None) not in ('static_library', 'shared_library'):
+ return
+ sources = spec.get('sources', [])
+ basenames = {}
+ for source in sources:
+ name, ext = os.path.splitext(source)
+ is_compiled_file = ext in [
+ '.c', '.cc', '.cpp', '.cxx', '.m', '.mm', '.s', '.S']
+ if not is_compiled_file:
+ continue
+ basename = os.path.basename(name) # Don't include extension.
+ basenames.setdefault(basename, []).append(source)
+
+ error = ''
+ for basename, files in basenames.iteritems():
+ if len(files) > 1:
+ error += ' %s: %s\n' % (basename, ' '.join(files))
+
+ if error:
+ print('static library %s has several files with the same basename:\n' %
+ spec['target_name'] + error + 'MSVC08 cannot handle that.')
+ raise GypError('Duplicate basenames in sources section, see list above')
+
+
def _GenerateMSVSProject(project, options, version, generator_flags):
"""Generates a .vcproj file. It may create .rules and .user files too.
Arguments:
project: The project object we will generate the file for.
options: Global options passed to the generator.
version: The VisualStudioVersion object.
generator_flags: dict of generator-specific flags.
"""
spec = project.spec
- vcproj_dir = os.path.dirname(project.path)
- if vcproj_dir and not os.path.exists(vcproj_dir):
- os.makedirs(vcproj_dir)
+ gyp.common.EnsureDirExists(project.path)
platforms = _GetUniquePlatforms(spec)
p = MSVSProject.Writer(project.path, version, spec['target_name'],
project.guid, platforms)
# Get directory project file is in.
project_dir = os.path.split(project.path)[0]
gyp_path = _NormalizedSource(project.build_file)
relative_path_of_gyp_file = gyp.common.RelativePath(gyp_path, project_dir)
config_type = _GetMSVSConfigurationType(spec, project.build_file)
for config_name, config in spec['configurations'].iteritems():
_AddConfigurationToMSVSProject(p, spec, config_type, config_name, config)
+ # MSVC08 and prior version cannot handle duplicate basenames in the same
+ # target.
+ # TODO: Take excluded sources into consideration if possible.
+ _ValidateSourcesForMSVSProject(spec, version)
+
# Prepare list of sources and excluded sources.
gyp_file = os.path.split(project.build_file)[1]
sources, excluded_sources = _PrepareListOfSources(spec, generator_flags,
gyp_file)
# Add rules.
actions_to_add = {}
_GenerateRulesForMSVS(p, project_dir, options, spec,
sources, excluded_sources,
actions_to_add)
list_excluded = generator_flags.get('msvs_list_excluded_files', True)
sources, excluded_sources, excluded_idl = (
- _AdjustSourcesAndConvertToFilterHierarchy(
- spec, options, project_dir, sources, excluded_sources, list_excluded))
+ _AdjustSourcesAndConvertToFilterHierarchy(spec, options, project_dir,
+ sources, excluded_sources,
+ list_excluded, version))
# Add in files.
missing_sources = _VerifySourcesExist(sources, project_dir)
p.AddFiles(sources)
_AddToolFilesToMSVS(p, spec)
_HandlePreCompiledHeaders(p, sources, spec)
_AddActions(actions_to_add, spec, relative_path_of_gyp_file)
@@ -950,17 +1063,17 @@ def _GetUniquePlatforms(spec):
"""Returns the list of unique platforms for this spec, e.g ['win32', ...].
Arguments:
spec: The target dictionary containing the properties of the target.
Returns:
The MSVSUserFile object created.
"""
# Gather list of unique platforms.
- platforms = set()
+ platforms = OrderedSet()
for configuration in spec['configurations']:
platforms.add(_ConfigPlatform(spec['configurations'][configuration]))
platforms = list(platforms)
return platforms
def _CreateMSVSUserFile(proj_path, version, spec):
"""Generates a .user file for the user running this Gyp program.
@@ -992,71 +1105,82 @@ def _GetMSVSConfigurationType(spec, buil
An integer, the configuration type.
"""
try:
config_type = {
'executable': '1', # .exe
'shared_library': '2', # .dll
'loadable_module': '2', # .dll
'static_library': '4', # .lib
+ 'windows_driver': '5', # .sys
'none': '10', # Utility type
}[spec['type']]
except KeyError:
if spec.get('type'):
- raise Exception('Target type %s is not a valid target type for '
- 'target %s in %s.' %
- (spec['type'], spec['target_name'], build_file))
+ raise GypError('Target type %s is not a valid target type for '
+ 'target %s in %s.' %
+ (spec['type'], spec['target_name'], build_file))
else:
- raise Exception('Missing type field for target %s in %s.' %
- (spec['target_name'], build_file))
+ raise GypError('Missing type field for target %s in %s.' %
+ (spec['target_name'], build_file))
return config_type
def _AddConfigurationToMSVSProject(p, spec, config_type, config_name, config):
"""Adds a configuration to the MSVS project.
Many settings in a vcproj file are specific to a configuration. This
function the main part of the vcproj file that's configuration specific.
Arguments:
p: The target project being generated.
spec: The target dictionary containing the properties of the target.
config_type: The configuration type, a number as defined by Microsoft.
config_name: The name of the configuration.
- config: The dictionnary that defines the special processing to be done
+ config: The dictionary that defines the special processing to be done
for this configuration.
"""
# Get the information for this configuration
- include_dirs, resource_include_dirs = _GetIncludeDirs(config)
+ include_dirs, midl_include_dirs, resource_include_dirs = \
+ _GetIncludeDirs(config)
libraries = _GetLibraries(spec)
+ library_dirs = _GetLibraryDirs(config)
out_file, vc_tool, _ = _GetOutputFilePathAndTool(spec, msbuild=False)
defines = _GetDefines(config)
defines = [_EscapeCppDefineForMSVS(d) for d in defines]
disabled_warnings = _GetDisabledWarnings(config)
prebuild = config.get('msvs_prebuild')
postbuild = config.get('msvs_postbuild')
def_file = _GetModuleDefinition(spec)
precompiled_header = config.get('msvs_precompiled_header')
# Prepare the list of tools as a dictionary.
tools = dict()
# Add in user specified msvs_settings.
msvs_settings = config.get('msvs_settings', {})
MSVSSettings.ValidateMSVSSettings(msvs_settings)
+
+ # Prevent default library inheritance from the environment.
+ _ToolAppend(tools, 'VCLinkerTool', 'AdditionalDependencies', ['$(NOINHERIT)'])
+
for tool in msvs_settings:
settings = config['msvs_settings'][tool]
for setting in settings:
_ToolAppend(tools, tool, setting, settings[setting])
# Add the information to the appropriate tool
_ToolAppend(tools, 'VCCLCompilerTool',
'AdditionalIncludeDirectories', include_dirs)
+ _ToolAppend(tools, 'VCMIDLTool',
+ 'AdditionalIncludeDirectories', midl_include_dirs)
_ToolAppend(tools, 'VCResourceCompilerTool',
'AdditionalIncludeDirectories', resource_include_dirs)
# Add in libraries.
_ToolAppend(tools, 'VCLinkerTool', 'AdditionalDependencies', libraries)
+ _ToolAppend(tools, 'VCLinkerTool', 'AdditionalLibraryDirectories',
+ library_dirs)
if out_file:
_ToolAppend(tools, vc_tool, 'OutputFile', out_file, only_if_unset=True)
# Add defines.
_ToolAppend(tools, 'VCCLCompilerTool', 'PreprocessorDefinitions', defines)
_ToolAppend(tools, 'VCResourceCompilerTool', 'PreprocessorDefinitions',
defines)
# Change program database directory to prevent collisions.
_ToolAppend(tools, 'VCCLCompilerTool', 'ProgramDataBaseFileName',
@@ -1086,49 +1210,68 @@ def _AddConfigurationToMSVSProject(p, sp
_AddConfigurationToMSVS(p, spec, tools, config, config_type, config_name)
def _GetIncludeDirs(config):
"""Returns the list of directories to be used for #include directives.
Arguments:
- config: The dictionnary that defines the special processing to be done
+ config: The dictionary that defines the special processing to be done
for this configuration.
Returns:
The list of directory paths.
"""
# TODO(bradnelson): include_dirs should really be flexible enough not to
# require this sort of thing.
include_dirs = (
config.get('include_dirs', []) +
config.get('msvs_system_include_dirs', []))
+ midl_include_dirs = (
+ config.get('midl_include_dirs', []) +
+ config.get('msvs_system_include_dirs', []))
resource_include_dirs = config.get('resource_include_dirs', include_dirs)
include_dirs = _FixPaths(include_dirs)
+ midl_include_dirs = _FixPaths(midl_include_dirs)
resource_include_dirs = _FixPaths(resource_include_dirs)
- return include_dirs, resource_include_dirs
+ return include_dirs, midl_include_dirs, resource_include_dirs
+
+
+def _GetLibraryDirs(config):
+ """Returns the list of directories to be used for library search paths.
+
+ Arguments:
+ config: The dictionary that defines the special processing to be done
+ for this configuration.
+ Returns:
+ The list of directory paths.
+ """
+
+ library_dirs = config.get('library_dirs', [])
+ library_dirs = _FixPaths(library_dirs)
+ return library_dirs
def _GetLibraries(spec):
"""Returns the list of libraries for this configuration.
Arguments:
spec: The target dictionary containing the properties of the target.
Returns:
The list of directory paths.
"""
libraries = spec.get('libraries', [])
# Strip out -l, as it is not used on windows (but is needed so we can pass
# in libraries that are assumed to be in the default library path).
# Also remove duplicate entries, leaving only the last duplicate, while
# preserving order.
- found = set()
+ found = OrderedSet()
unique_libraries_list = []
for entry in reversed(libraries):
- library = re.sub('^\-l', '', entry)
+ library = re.sub(r'^\-l', '', entry)
if not os.path.splitext(library)[1]:
library += '.lib'
if library not in found:
found.add(library)
unique_libraries_list.append(library)
unique_libraries_list.reverse()
return unique_libraries_list
@@ -1147,16 +1290,17 @@ def _GetOutputFilePathAndTool(spec, msbu
# Select a name for the output file.
out_file = ''
vc_tool = ''
msbuild_tool = ''
output_file_map = {
'executable': ('VCLinkerTool', 'Link', '$(OutDir)', '.exe'),
'shared_library': ('VCLinkerTool', 'Link', '$(OutDir)', '.dll'),
'loadable_module': ('VCLinkerTool', 'Link', '$(OutDir)', '.dll'),
+ 'windows_driver': ('VCLinkerTool', 'Link', '$(OutDir)', '.sys'),
'static_library': ('VCLibrarianTool', 'Lib', '$(OutDir)lib\\', '.lib'),
}
output_file_props = output_file_map.get(spec['type'])
if output_file_props and int(spec.get('msvs_auto_output_file', 1)):
vc_tool, msbuild_tool, out_dir, suffix = output_file_props
if spec.get('standalone_static_library', 0):
out_dir = '$(OutDir)'
out_dir = spec.get('product_dir', out_dir)
@@ -1166,21 +1310,39 @@ def _GetOutputFilePathAndTool(spec, msbu
elif msbuild:
suffix = '$(TargetExt)'
prefix = spec.get('product_prefix', '')
product_name = spec.get('product_name', '$(ProjectName)')
out_file = ntpath.join(out_dir, prefix + product_name + suffix)
return out_file, vc_tool, msbuild_tool
+def _GetOutputTargetExt(spec):
+ """Returns the extension for this target, including the dot
+
+ If product_extension is specified, set target_extension to this to avoid
+ MSB8012, returns None otherwise. Ignores any target_extension settings in
+ the input files.
+
+ Arguments:
+ spec: The target dictionary containing the properties of the target.
+ Returns:
+ A string with the extension, or None
+ """
+ target_extension = spec.get('product_extension')
+ if target_extension:
+ return '.' + target_extension
+ return None
+
+
def _GetDefines(config):
"""Returns the list of preprocessor definitions for this configuation.
Arguments:
- config: The dictionnary that defines the special processing to be done
+ config: The dictionary that defines the special processing to be done
for this configuration.
Returns:
The list of preprocessor definitions.
"""
defines = []
for d in config.get('defines', []):
if type(d) == list:
fd = '='.join([str(dpart) for dpart in d])
@@ -1191,33 +1353,34 @@ def _GetDefines(config):
def _GetDisabledWarnings(config):
return [str(i) for i in config.get('msvs_disabled_warnings', [])]
def _GetModuleDefinition(spec):
def_file = ''
- if spec['type'] in ['shared_library', 'loadable_module', 'executable']:
+ if spec['type'] in ['shared_library', 'loadable_module', 'executable',
+ 'windows_driver']:
def_files = [s for s in spec.get('sources', []) if s.endswith('.def')]
if len(def_files) == 1:
def_file = _FixPath(def_files[0])
elif def_files:
raise ValueError(
'Multiple module definition files in one target, target %s lists '
'multiple .def files: %s' % (
spec['target_name'], ' '.join(def_files)))
return def_file
def _ConvertToolsToExpectedForm(tools):
"""Convert tools to a form expected by Visual Studio.
Arguments:
- tools: A dictionnary of settings; the tool name is the key.
+ tools: A dictionary of settings; the tool name is the key.
Returns:
A list of Tool objects.
"""
tool_list = []
for tool, settings in tools.iteritems():
# Collapse settings with lists.
settings_fixed = {}
for setting, value in settings.iteritems():
@@ -1236,18 +1399,18 @@ def _ConvertToolsToExpectedForm(tools):
def _AddConfigurationToMSVS(p, spec, tools, config, config_type, config_name):
"""Add to the project file the configuration specified by config.
Arguments:
p: The target project being generated.
spec: the target project dict.
- tools: A dictionnary of settings; the tool name is the key.
- config: The dictionnary that defines the special processing to be done
+ tools: A dictionary of settings; the tool name is the key.
+ config: The dictionary that defines the special processing to be done
for this configuration.
config_type: The configuration type, a number as defined by Microsoft.
config_name: The name of the configuration.
"""
attributes = _GetMSVSAttributes(spec, config, config_type)
# Add in this configuration.
tool_list = _ConvertToolsToExpectedForm(tools)
p.AddConfig(_ConfigFullName(config_name, config),
@@ -1276,18 +1439,17 @@ def _GetMSVSAttributes(spec, config, con
else:
intermediate = _FixPath(prepared_attrs['IntermediateDirectory']) + '\\'
intermediate = MSVSSettings.FixVCMacroSlashes(intermediate)
prepared_attrs['IntermediateDirectory'] = intermediate
return prepared_attrs
def _AddNormalizedSources(sources_set, sources_array):
- sources = [_NormalizedSource(s) for s in sources_array]
- sources_set.update(set(sources))
+ sources_set.update(_NormalizedSource(s) for s in sources_array)
def _PrepareListOfSources(spec, generator_flags, gyp_file):
"""Prepare list of sources and excluded sources.
Besides the sources specified directly in the spec, adds the gyp file so
that a change to it will cause a re-compile. Also adds appropriate sources
for actions and copies. Assumes later stage will un-exclude files which
@@ -1295,57 +1457,59 @@ def _PrepareListOfSources(spec, generato
Arguments:
spec: The target dictionary containing the properties of the target.
gyp_file: The name of the gyp file.
Returns:
A pair of (list of sources, list of excluded sources).
The sources will be relative to the gyp file.
"""
- sources = set()
+ sources = OrderedSet()
_AddNormalizedSources(sources, spec.get('sources', []))
- excluded_sources = set()
+ excluded_sources = OrderedSet()
# Add in the gyp file.
if not generator_flags.get('standalone'):
sources.add(gyp_file)
# Add in 'action' inputs and outputs.
for a in spec.get('actions', []):
inputs = a['inputs']
inputs = [_NormalizedSource(i) for i in inputs]
# Add all inputs to sources and excluded sources.
- inputs = set(inputs)
+ inputs = OrderedSet(inputs)
sources.update(inputs)
- excluded_sources.update(inputs)
+ if not spec.get('msvs_external_builder'):
+ excluded_sources.update(inputs)
if int(a.get('process_outputs_as_sources', False)):
_AddNormalizedSources(sources, a.get('outputs', []))
# Add in 'copies' inputs and outputs.
for cpy in spec.get('copies', []):
_AddNormalizedSources(sources, cpy.get('files', []))
return (sources, excluded_sources)
def _AdjustSourcesAndConvertToFilterHierarchy(
- spec, options, gyp_dir, sources, excluded_sources, list_excluded):
+ spec, options, gyp_dir, sources, excluded_sources, list_excluded, version):
"""Adjusts the list of sources and excluded sources.
Also converts the sets to lists.
Arguments:
spec: The target dictionary containing the properties of the target.
options: Global generator options.
gyp_dir: The path to the gyp file being processed.
sources: A set of sources to be included for this project.
excluded_sources: A set of sources to be excluded for this project.
+ version: A MSVSVersion object.
Returns:
A trio of (list of sources, list of excluded sources,
path of excluded IDL file)
"""
# Exclude excluded sources coming into the generator.
- excluded_sources.update(set(spec.get('sources_excluded', [])))
+ excluded_sources.update(OrderedSet(spec.get('sources_excluded', [])))
# Add excluded sources into sources for good measure.
sources.update(excluded_sources)
# Convert to proper windows form.
# NOTE: sources goes from being a set to a list here.
# NOTE: excluded_sources goes from being a set to a list here.
sources = _FixPaths(sources)
# Convert to proper windows form.
excluded_sources = _FixPaths(excluded_sources)
@@ -1354,17 +1518,29 @@ def _AdjustSourcesAndConvertToFilterHier
precompiled_related = _GetPrecompileRelatedFiles(spec)
# Find the excluded ones, minus the precompiled header related ones.
fully_excluded = [i for i in excluded_sources if i not in precompiled_related]
# Convert to folders and the right slashes.
sources = [i.split('\\') for i in sources]
sources = _ConvertSourcesToFilterHierarchy(sources, excluded=fully_excluded,
- list_excluded=list_excluded)
+ list_excluded=list_excluded,
+ msvs_version=version)
+
+ # Prune filters with a single child to flatten ugly directory structures
+ # such as ../../src/modules/module1 etc.
+ if version.UsesVcxproj():
+ while all([isinstance(s, MSVSProject.Filter) for s in sources]) \
+ and len(set([s.name for s in sources])) == 1:
+ assert all([len(s.contents) == 1 for s in sources])
+ sources = [s.contents[0] for s in sources]
+ else:
+ while len(sources) == 1 and isinstance(sources[0], MSVSProject.Filter):
+ sources = sources[0].contents
return sources, excluded_sources, excluded_idl
def _IdlFilesHandledNonNatively(spec, sources):
# If any non-native rules use 'idl' as an extension exclude idl files.
# Gather a list here to use later.
using_idl = False
@@ -1423,17 +1599,17 @@ def _GetExcludedFilesFromBuild(spec, exc
for config_name, config in spec['configurations'].iteritems():
excluded_configs.append((config_name, config))
exclusions[f] = excluded_configs
return exclusions
def _AddToolFilesToMSVS(p, spec):
# Add in tool files (rules).
- tool_files = set()
+ tool_files = OrderedSet()
for _, config in spec['configurations'].iteritems():
for f in config.get('msvs_tool_files', []):
tool_files.add(f)
for f in tool_files:
p.AddToolFile(f)
def _HandlePreCompiledHeaders(p, sources, spec):
@@ -1658,17 +1834,17 @@ def _CreateProjectObjects(target_list, t
A set of created projects, keyed by target.
"""
global fixpath_prefix
# Generate each project.
projects = {}
for qualified_target in target_list:
spec = target_dicts[qualified_target]
if spec['toolset'] != 'target':
- raise Exception(
+ raise GypError(
'Multiple toolsets not supported in msvs build (target %s)' %
qualified_target)
proj_path, fixpath_prefix = _GetPathOfProject(qualified_target, spec,
options, msvs_version)
guid = _GetGuidOfProject(proj_path, spec)
overrides = _GetPlatformOverridesOfProject(spec)
build_file = gyp.common.BuildFile(qualified_target)
# Create object for this project.
@@ -1680,24 +1856,74 @@ def _CreateProjectObjects(target_list, t
build_file=build_file,
config_platform_overrides=overrides,
fixpath_prefix=fixpath_prefix)
# Set project toolset if any (MS build only)
if msvs_version.UsesVcxproj():
obj.set_msbuild_toolset(
_GetMsbuildToolsetOfProject(proj_path, spec, msvs_version))
projects[qualified_target] = obj
- # Set all the dependencies
+ # Set all the dependencies, but not if we are using an external builder like
+ # ninja
for project in projects.values():
- deps = project.spec.get('dependencies', [])
- deps = [projects[d] for d in deps]
- project.set_dependencies(deps)
+ if not project.spec.get('msvs_external_builder'):
+ deps = project.spec.get('dependencies', [])
+ deps = [projects[d] for d in deps]
+ project.set_dependencies(deps)
return projects
+def _InitNinjaFlavor(params, target_list, target_dicts):
+ """Initialize targets for the ninja flavor.
+
+ This sets up the necessary variables in the targets to generate msvs projects
+ that use ninja as an external builder. The variables in the spec are only set
+ if they have not been set. This allows individual specs to override the
+ default values initialized here.
+ Arguments:
+ params: Params provided to the generator.
+ target_list: List of target pairs: 'base/base.gyp:base'.
+ target_dicts: Dict of target properties keyed on target pair.
+ """
+ for qualified_target in target_list:
+ spec = target_dicts[qualified_target]
+ if spec.get('msvs_external_builder'):
+ # The spec explicitly defined an external builder, so don't change it.
+ continue
+
+ path_to_ninja = spec.get('msvs_path_to_ninja', 'ninja.exe')
+
+ spec['msvs_external_builder'] = 'ninja'
+ if not spec.get('msvs_external_builder_out_dir'):
+ gyp_file, _, _ = gyp.common.ParseQualifiedTarget(qualified_target)
+ gyp_dir = os.path.dirname(gyp_file)
+ configuration = '$(Configuration)'
+ if params.get('target_arch') == 'x64':
+ configuration += '_x64'
+ spec['msvs_external_builder_out_dir'] = os.path.join(
+ gyp.common.RelativePath(params['options'].toplevel_dir, gyp_dir),
+ ninja_generator.ComputeOutputDir(params),
+ configuration)
+ if not spec.get('msvs_external_builder_build_cmd'):
+ spec['msvs_external_builder_build_cmd'] = [
+ path_to_ninja,
+ '-C',
+ '$(OutDir)',
+ '$(ProjectName)',
+ ]
+ if not spec.get('msvs_external_builder_clean_cmd'):
+ spec['msvs_external_builder_clean_cmd'] = [
+ path_to_ninja,
+ '-C',
+ '$(OutDir)',
+ '-tclean',
+ '$(ProjectName)',
+ ]
+
+
def CalculateVariables(default_variables, params):
"""Generated variables that require params to be known."""
generator_flags = params.get('generator_flags', {})
# Select project file format version (if unset, default to auto detecting).
msvs_version = MSVSVersion.SelectVisualStudioVersion(
generator_flags.get('msvs_version', 'auto'))
@@ -1712,83 +1938,18 @@ def CalculateVariables(default_variables
# process), it is also necessary to check PROCESSOR_ARCITEW6432 (which
# contains the actual word size of the system when running thru WOW64).
if (os.environ.get('PROCESSOR_ARCHITECTURE', '').find('64') >= 0 or
os.environ.get('PROCESSOR_ARCHITEW6432', '').find('64') >= 0):
default_variables['MSVS_OS_BITS'] = 64
else:
default_variables['MSVS_OS_BITS'] = 32
-
-def _ShardName(name, number):
- """Add a shard number to the end of a target.
-
- Arguments:
- name: name of the target (foo#target)
- number: shard number
- Returns:
- Target name with shard added (foo_1#target)
- """
- parts = name.rsplit('#', 1)
- parts[0] = '%s_%d' % (parts[0], number)
- return '#'.join(parts)
-
-
-def _ShardTargets(target_list, target_dicts):
- """Shard some targets apart to work around the linkers limits.
-
- Arguments:
- target_list: List of target pairs: 'base/base.gyp:base'.
- target_dicts: Dict of target properties keyed on target pair.
- Returns:
- Tuple of the new sharded versions of the inputs.
- """
- # Gather the targets to shard, and how many pieces.
- targets_to_shard = {}
- for t in target_dicts:
- shards = int(target_dicts[t].get('msvs_shard', 0))
- if shards:
- targets_to_shard[t] = shards
- # Shard target_list.
- new_target_list = []
- for t in target_list:
- if t in targets_to_shard:
- for i in range(targets_to_shard[t]):
- new_target_list.append(_ShardName(t, i))
- else:
- new_target_list.append(t)
- # Shard target_dict.
- new_target_dicts = {}
- for t in target_dicts:
- if t in targets_to_shard:
- for i in range(targets_to_shard[t]):
- name = _ShardName(t, i)
- new_target_dicts[name] = copy.copy(target_dicts[t])
- new_target_dicts[name]['target_name'] = _ShardName(
- new_target_dicts[name]['target_name'], i)
- sources = new_target_dicts[name].get('sources', [])
- new_sources = []
- for pos in range(i, len(sources), targets_to_shard[t]):
- new_sources.append(sources[pos])
- new_target_dicts[name]['sources'] = new_sources
- else:
- new_target_dicts[t] = target_dicts[t]
- # Shard dependencies.
- for t in new_target_dicts:
- dependencies = copy.copy(new_target_dicts[t].get('dependencies', []))
- new_dependencies = []
- for d in dependencies:
- if d in targets_to_shard:
- for i in range(targets_to_shard[d]):
- new_dependencies.append(_ShardName(d, i))
- else:
- new_dependencies.append(d)
- new_target_dicts[t]['dependencies'] = new_dependencies
-
- return (new_target_list, new_target_dicts)
+ if gyp.common.GetFlavor(params) == 'ninja':
+ default_variables['SHARED_INTERMEDIATE_DIR'] = '$(OutDir)gen'
def PerformBuild(data, configurations, params):
options = params['options']
msvs_version = params['msvs_version']
devenv = os.path.join(msvs_version.path, 'Common7', 'IDE', 'devenv.com')
for build_file, build_file_dict in data.iteritems():
@@ -1800,16 +1961,29 @@ def PerformBuild(data, configurations, p
sln_path = os.path.join(options.generator_output, sln_path)
for config in configurations:
arguments = [devenv, sln_path, '/Build', config]
print 'Building [%s]: %s' % (config, arguments)
rtn = subprocess.check_call(arguments)
+def CalculateGeneratorInputInfo(params):
+ if params.get('flavor') == 'ninja':
+ toplevel = params['options'].toplevel_dir
+ qualified_out_dir = os.path.normpath(os.path.join(
+ toplevel, ninja_generator.ComputeOutputDir(params),
+ 'gypfiles-msvs-ninja'))
+
+ global generator_filelist_paths
+ generator_filelist_paths = {
+ 'toplevel': toplevel,
+ 'qualified_out_dir': qualified_out_dir,
+ }
+
def GenerateOutput(target_list, target_dicts, data, params):
"""Generate .sln and .vcproj files.
This is the entry point for this generator.
Arguments:
target_list: List of target pairs: 'base/base.gyp:base'.
target_dicts: Dict of target properties keyed on target pair.
data: Dictionary containing per .gyp data.
@@ -1820,17 +1994,26 @@ def GenerateOutput(target_list, target_d
# Get the project file format version back out of where we stashed it in
# GeneratorCalculatedVariables.
msvs_version = params['msvs_version']
generator_flags = params.get('generator_flags', {})
# Optionally shard targets marked with 'msvs_shard': SHARD_COUNT.
- (target_list, target_dicts) = _ShardTargets(target_list, target_dicts)
+ (target_list, target_dicts) = MSVSUtil.ShardTargets(target_list, target_dicts)
+
+ # Optionally use the large PDB workaround for targets marked with
+ # 'msvs_large_pdb': 1.
+ (target_list, target_dicts) = MSVSUtil.InsertLargePdbShims(
+ target_list, target_dicts, generator_default_variables)
+
+ # Optionally configure each spec to use ninja as the external builder.
+ if params.get('flavor') == 'ninja':
+ _InitNinjaFlavor(params, target_list, target_dicts)
# Prepare the set of configurations.
configs = set()
for qualified_target in target_list:
spec = target_dicts[qualified_target]
for config_name, config in spec['configurations'].iteritems():
configs.add(_ConfigFullName(config_name, config))
configs = list(configs)
@@ -1867,52 +2050,52 @@ def GenerateOutput(target_list, target_d
websiteProperties=False,
version=msvs_version)
sln.Write()
if missing_sources:
error_message = "Missing input files:\n" + \
'\n'.join(set(missing_sources))
if generator_flags.get('msvs_error_on_missing_sources', False):
- raise Exception(error_message)
+ raise GypError(error_message)
else:
- print >>sys.stdout, "Warning: " + error_message
+ print >> sys.stdout, "Warning: " + error_message
def _GenerateMSBuildFiltersFile(filters_path, source_files,
- extension_to_rule_name):
+ rule_dependencies, extension_to_rule_name):
"""Generate the filters file.
This file is used by Visual Studio to organize the presentation of source
files into folders.
Arguments:
filters_path: The path of the file to be created.
source_files: The hierarchical structure of all the sources.
extension_to_rule_name: A dictionary mapping file extensions to rules.
"""
filter_group = []
source_group = []
- _AppendFiltersForMSBuild('', source_files, extension_to_rule_name,
- filter_group, source_group)
+ _AppendFiltersForMSBuild('', source_files, rule_dependencies,
+ extension_to_rule_name, filter_group, source_group)
if filter_group:
content = ['Project',
{'ToolsVersion': '4.0',
'xmlns': 'http://schemas.microsoft.com/developer/msbuild/2003'
},
['ItemGroup'] + filter_group,
['ItemGroup'] + source_group
]
easy_xml.WriteXmlIfChanged(content, filters_path, pretty=True, win32=True)
elif os.path.exists(filters_path):
# We don't need this filter anymore. Delete the old filter file.
os.unlink(filters_path)
-def _AppendFiltersForMSBuild(parent_filter_name, sources,
+def _AppendFiltersForMSBuild(parent_filter_name, sources, rule_dependencies,
extension_to_rule_name,
filter_group, source_group):
"""Creates the list of filters and sources to be added in the filter file.
Args:
parent_filter_name: The name of the filter under which the sources are
found.
sources: The hierarchy of filters and sources to process.
@@ -1928,29 +2111,31 @@ def _AppendFiltersForMSBuild(parent_filt
else:
filter_name = '%s\\%s' % (parent_filter_name, source.name)
# Add the filter to the group.
filter_group.append(
['Filter', {'Include': filter_name},
['UniqueIdentifier', MSVSNew.MakeGuid(source.name)]])
# Recurse and add its dependents.
_AppendFiltersForMSBuild(filter_name, source.contents,
- extension_to_rule_name,
+ rule_dependencies, extension_to_rule_name,
filter_group, source_group)
else:
# It's a source. Create a source entry.
- _, element = _MapFileToMsBuildSourceType(source, extension_to_rule_name)
+ _, element = _MapFileToMsBuildSourceType(source, rule_dependencies,
+ extension_to_rule_name)
source_entry = [element, {'Include': source}]
# Specify the filter it is part of, if any.
if parent_filter_name:
source_entry.append(['Filter', parent_filter_name])
source_group.append(source_entry)
-def _MapFileToMsBuildSourceType(source, extension_to_rule_name):
+def _MapFileToMsBuildSourceType(source, rule_dependencies,
+ extension_to_rule_name):
"""Returns the group and element type of the source file.
Arguments:
source: The source file name.
extension_to_rule_name: A dictionary mapping file extensions to rules.
Returns:
A pair of (group this file should be part of, the label of element)
@@ -1963,44 +2148,52 @@ def _MapFileToMsBuildSourceType(source,
group = 'compile'
element = 'ClCompile'
elif ext in ['.h', '.hxx']:
group = 'include'
element = 'ClInclude'
elif ext == '.rc':
group = 'resource'
element = 'ResourceCompile'
+ elif ext == '.asm':
+ group = 'masm'
+ element = 'MASM'
elif ext == '.idl':
group = 'midl'
element = 'Midl'
+ elif source in rule_dependencies:
+ group = 'rule_dependency'
+ element = 'CustomBuild'
else:
group = 'none'
element = 'None'
return (group, element)
def _GenerateRulesForMSBuild(output_dir, options, spec,
sources, excluded_sources,
props_files_of_rules, targets_files_of_rules,
- actions_to_add, extension_to_rule_name):
+ actions_to_add, rule_dependencies,
+ extension_to_rule_name):
# MSBuild rules are implemented using three files: an XML file, a .targets
# file and a .props file.
# See http://blogs.msdn.com/b/vcblog/archive/2010/04/21/quick-help-on-vs2010-custom-build-rule.aspx
# for more details.
rules = spec.get('rules', [])
rules_native = [r for r in rules if not int(r.get('msvs_external_rule', 0))]
rules_external = [r for r in rules if int(r.get('msvs_external_rule', 0))]
msbuild_rules = []
for rule in rules_native:
# Skip a rule with no action and no inputs.
if 'action' not in rule and not rule.get('rule_sources', []):
continue
msbuild_rule = MSBuildRule(rule, spec)
msbuild_rules.append(msbuild_rule)
+ rule_dependencies.update(msbuild_rule.additional_dependencies.split(';'))
extension_to_rule_name[msbuild_rule.extension] = msbuild_rule.rule_name
if msbuild_rules:
base = spec['target_name'] + options.suffix
props_name = base + '.props'
targets_name = base + '.targets'
xml_name = base + '.xml'
props_files_of_rules.add(props_name)
@@ -2012,17 +2205,17 @@ def _GenerateRulesForMSBuild(output_dir,
_GenerateMSBuildRulePropsFile(props_path, msbuild_rules)
_GenerateMSBuildRuleTargetsFile(targets_path, msbuild_rules)
_GenerateMSBuildRuleXmlFile(xml_path, msbuild_rules)
if rules_external:
_GenerateExternalRules(rules_external, output_dir, spec,
sources, options, actions_to_add)
- _AdjustSourcesForRules(rules, sources, excluded_sources)
+ _AdjustSourcesForRules(rules, sources, excluded_sources, True)
class MSBuildRule(object):
"""Used to store information used to generate an MSBuild rule.
Attributes:
rule_name: The rule name, sanitized to use in XML.
target_name: The name of the target.
@@ -2191,16 +2384,19 @@ def _GenerateMSBuildRuleTargetsFile(targ
'File': '$(IntDir)$(ProjectName).read.1.tlog',
'Lines': "^%%(%s.Source);%%(%s.Inputs)" % (rule.tlog, rule.tlog)
}
]
command_and_input_section = [
rule_name,
{'Condition': "'@(%s)' != '' and '%%(%s.ExcludedFromBuild)' != "
"'true'" % (rule_name, rule_name),
+ 'EchoOff': 'true',
+ 'StandardOutputImportance': 'High',
+ 'StandardErrorImportance': 'High',
'CommandLineTemplate': '%%(%s.CommandLineTemplate)' % rule_name,
'AdditionalOptions': '%%(%s.AdditionalOptions)' % rule_name,
'Inputs': rule_inputs
}
]
content.extend([
['Target',
{'Name': rule.target_name,
@@ -2465,36 +2661,89 @@ def _GetMSBuildProjectConfigurations(con
['ProjectConfiguration', {'Include': designation},
['Configuration', configuration],
['Platform', platform]])
return [group]
def _GetMSBuildGlobalProperties(spec, guid, gyp_file_name):
namespace = os.path.splitext(gyp_file_name)[0]
- return [
+ properties = [
['PropertyGroup', {'Label': 'Globals'},
- ['ProjectGuid', guid],
- ['Keyword', 'Win32Proj'],
- ['RootNamespace', namespace],
+ ['ProjectGuid', guid],
+ ['Keyword', 'Win32Proj'],
+ ['RootNamespace', namespace],
+ ['IgnoreWarnCompileDuplicatedFilename', 'true'],
]
- ]
+ ]
+
+ if os.environ.get('PROCESSOR_ARCHITECTURE') == 'AMD64' or \
+ os.environ.get('PROCESSOR_ARCHITEW6432') == 'AMD64':
+ properties[0].append(['PreferredToolArchitecture', 'x64'])
+
+ if spec.get('msvs_enable_winrt'):
+ properties[0].append(['DefaultLanguage', 'en-US'])
+ properties[0].append(['AppContainerApplication', 'true'])
+ if spec.get('msvs_application_type_revision'):
+ app_type_revision = spec.get('msvs_application_type_revision')
+ properties[0].append(['ApplicationTypeRevision', app_type_revision])
+ else:
+ properties[0].append(['ApplicationTypeRevision', '8.1'])
+
+ if spec.get('msvs_target_platform_version'):
+ target_platform_version = spec.get('msvs_target_platform_version')
+ properties[0].append(['WindowsTargetPlatformVersion',
+ target_platform_version])
+ if spec.get('msvs_target_platform_minversion'):
+ target_platform_minversion = spec.get('msvs_target_platform_minversion')
+ properties[0].append(['WindowsTargetPlatformMinVersion',
+ target_platform_minversion])
+ else:
+ properties[0].append(['WindowsTargetPlatformMinVersion',
+ target_platform_version])
+ if spec.get('msvs_enable_winphone'):
+ properties[0].append(['ApplicationType', 'Windows Phone'])
+ else:
+ properties[0].append(['ApplicationType', 'Windows Store'])
+
+ platform_name = None
+ msvs_windows_sdk_version = None
+ for configuration in spec['configurations'].itervalues():
+ platform_name = platform_name or _ConfigPlatform(configuration)
+ msvs_windows_sdk_version = (msvs_windows_sdk_version or
+ _ConfigWindowsTargetPlatformVersion(configuration))
+ if platform_name and msvs_windows_sdk_version:
+ break
+
+ if platform_name == 'ARM':
+ properties[0].append(['WindowsSDKDesktopARMSupport', 'true'])
+ if msvs_windows_sdk_version:
+ properties[0].append(['WindowsTargetPlatformVersion',
+ str(msvs_windows_sdk_version)])
+
+ return properties
def _GetMSBuildConfigurationDetails(spec, build_file):
properties = {}
for name, settings in spec['configurations'].iteritems():
msbuild_attributes = _GetMSBuildAttributes(spec, settings, build_file)
condition = _GetConfigurationCondition(name, settings)
character_set = msbuild_attributes.get('CharacterSet')
+ config_type = msbuild_attributes.get('ConfigurationType')
_AddConditionalProperty(properties, condition, 'ConfigurationType',
- msbuild_attributes['ConfigurationType'])
+ config_type)
+ if config_type == 'Driver':
+ _AddConditionalProperty(properties, condition, 'DriverType', 'WDM')
+ _AddConditionalProperty(properties, condition, 'TargetVersion',
+ _ConfigTargetVersion(settings))
if character_set:
- _AddConditionalProperty(properties, condition, 'CharacterSet',
- character_set)
+ if 'msvs_enable_winrt' not in spec :
+ _AddConditionalProperty(properties, condition, 'CharacterSet',
+ character_set)
return _GetMSBuildPropertyGroup(spec, 'Configuration', properties)
def _GetMSBuildLocalProperties(msbuild_toolset):
# Currently the only local property we support is PlatformToolset
properties = {}
if msbuild_toolset:
properties = [
@@ -2579,16 +2828,17 @@ def _ConvertMSVSCharacterSet(char_set):
def _ConvertMSVSConfigurationType(config_type):
if config_type.isdigit():
config_type = {
'1': 'Application',
'2': 'DynamicLibrary',
'4': 'StaticLibrary',
+ '5': 'Driver',
'10': 'Utility'
}[config_type]
return config_type
def _GetMSBuildAttributes(spec, config, build_file):
if 'msbuild_configuration_attributes' not in config:
msbuild_attributes = _ConvertMSVSBuildAttributes(spec, config, build_file)
@@ -2608,30 +2858,38 @@ def _GetMSBuildAttributes(spec, config,
msbuild_attributes['CharacterSet'] = _ConvertMSVSCharacterSet(
msbuild_attributes['CharacterSet'])
if 'TargetName' not in msbuild_attributes:
prefix = spec.get('product_prefix', '')
product_name = spec.get('product_name', '$(ProjectName)')
target_name = prefix + product_name
msbuild_attributes['TargetName'] = target_name
+ if spec.get('msvs_external_builder'):
+ external_out_dir = spec.get('msvs_external_builder_out_dir', '.')
+ msbuild_attributes['OutputDirectory'] = _FixPath(external_out_dir) + '\\'
+
# Make sure that 'TargetPath' matches 'Lib.OutputFile' or 'Link.OutputFile'
# (depending on the tool used) to avoid MSB8012 warning.
msbuild_tool_map = {
'executable': 'Link',
'shared_library': 'Link',
'loadable_module': 'Link',
+ 'windows_driver': 'Link',
'static_library': 'Lib',
}
msbuild_tool = msbuild_tool_map.get(spec['type'])
if msbuild_tool:
msbuild_settings = config['finalized_msbuild_settings']
out_file = msbuild_settings[msbuild_tool].get('OutputFile')
if out_file:
msbuild_attributes['TargetPath'] = _FixPath(out_file)
+ target_ext = msbuild_settings[msbuild_tool].get('TargetExt')
+ if target_ext:
+ msbuild_attributes['TargetExt'] = target_ext
return msbuild_attributes
def _GetMSBuildConfigurationGlobalProperties(spec, configurations, build_file):
# TODO(jeanluc) We could optimize out the following and do it only if
# there are actions.
# TODO(jeanluc) Handle the equivalent of setting 'CYGWIN=nontsec'.
@@ -2657,16 +2915,19 @@ def _GetMSBuildConfigurationGlobalProper
_AddConditionalProperty(properties, condition, 'OutDir',
attributes['OutputDirectory'])
_AddConditionalProperty(properties, condition, 'TargetName',
attributes['TargetName'])
if attributes.get('TargetPath'):
_AddConditionalProperty(properties, condition, 'TargetPath',
attributes['TargetPath'])
+ if attributes.get('TargetExt'):
+ _AddConditionalProperty(properties, condition, 'TargetExt',
+ attributes['TargetExt'])
if new_paths:
_AddConditionalProperty(properties, condition, 'ExecutablePath',
new_paths)
tool_settings = msbuild_settings.get('', {})
for name, value in sorted(tool_settings.iteritems()):
formatted_value = _GetValueFormattedForMSBuild('', name, value)
_AddConditionalProperty(properties, condition, name, formatted_value)
@@ -2689,17 +2950,17 @@ def _AddConditionalProperty(properties,
values = properties[name]
if value not in values:
values[value] = []
conditions = values[value]
conditions.append(condition)
# Regex for msvs variable references ( i.e. $(FOO) ).
-MSVS_VARIABLE_REFERENCE = re.compile('\$\(([a-zA-Z_][a-zA-Z0-9_]*)\)')
+MSVS_VARIABLE_REFERENCE = re.compile(r'\$\(([a-zA-Z_][a-zA-Z0-9_]*)\)')
def _GetMSBuildPropertyGroup(spec, label, properties):
"""Returns a PropertyGroup definition for the specified properties.
Arguments:
spec: The target project dict.
label: An optional label for the PropertyGroup.
@@ -2773,84 +3034,105 @@ def _FinalizeMSBuildSettings(spec, confi
if 'msbuild_settings' in configuration:
converted = False
msbuild_settings = configuration['msbuild_settings']
MSVSSettings.ValidateMSBuildSettings(msbuild_settings)
else:
converted = True
msvs_settings = configuration.get('msvs_settings', {})
msbuild_settings = MSVSSettings.ConvertToMSBuildSettings(msvs_settings)
- include_dirs, resource_include_dirs = _GetIncludeDirs(configuration)
+ include_dirs, midl_include_dirs, resource_include_dirs = \
+ _GetIncludeDirs(configuration)
libraries = _GetLibraries(spec)
+ library_dirs = _GetLibraryDirs(configuration)
out_file, _, msbuild_tool = _GetOutputFilePathAndTool(spec, msbuild=True)
+ target_ext = _GetOutputTargetExt(spec)
defines = _GetDefines(configuration)
if converted:
# Visual Studio 2010 has TR1
defines = [d for d in defines if d != '_HAS_TR1=0']
# Warn of ignored settings
- ignored_settings = ['msvs_prebuild', 'msvs_postbuild', 'msvs_tool_files']
+ ignored_settings = ['msvs_tool_files']
for ignored_setting in ignored_settings:
value = configuration.get(ignored_setting)
if value:
print ('Warning: The automatic conversion to MSBuild does not handle '
'%s. Ignoring setting of %s' % (ignored_setting, str(value)))
defines = [_EscapeCppDefineForMSBuild(d) for d in defines]
disabled_warnings = _GetDisabledWarnings(configuration)
- # TODO(jeanluc) Validate & warn that we don't translate
- # prebuild = configuration.get('msvs_prebuild')
- # postbuild = configuration.get('msvs_postbuild')
+ prebuild = configuration.get('msvs_prebuild')
+ postbuild = configuration.get('msvs_postbuild')
def_file = _GetModuleDefinition(spec)
precompiled_header = configuration.get('msvs_precompiled_header')
# Add the information to the appropriate tool
# TODO(jeanluc) We could optimize and generate these settings only if
# the corresponding files are found, e.g. don't generate ResourceCompile
# if you don't have any resources.
_ToolAppend(msbuild_settings, 'ClCompile',
'AdditionalIncludeDirectories', include_dirs)
+ _ToolAppend(msbuild_settings, 'Midl',
+ 'AdditionalIncludeDirectories', midl_include_dirs)
_ToolAppend(msbuild_settings, 'ResourceCompile',
'AdditionalIncludeDirectories', resource_include_dirs)
- # Add in libraries.
- _ToolAppend(msbuild_settings, 'Link', 'AdditionalDependencies', libraries)
+ # Add in libraries, note that even for empty libraries, we want this
+ # set, to prevent inheriting default libraries from the enviroment.
+ _ToolSetOrAppend(msbuild_settings, 'Link', 'AdditionalDependencies',
+ libraries)
+ _ToolAppend(msbuild_settings, 'Link', 'AdditionalLibraryDirectories',
+ library_dirs)
if out_file:
_ToolAppend(msbuild_settings, msbuild_tool, 'OutputFile', out_file,
only_if_unset=True)
+ if target_ext:
+ _ToolAppend(msbuild_settings, msbuild_tool, 'TargetExt', target_ext,
+ only_if_unset=True)
# Add defines.
_ToolAppend(msbuild_settings, 'ClCompile',
'PreprocessorDefinitions', defines)
_ToolAppend(msbuild_settings, 'ResourceCompile',
'PreprocessorDefinitions', defines)
# Add disabled warnings.
_ToolAppend(msbuild_settings, 'ClCompile',
'DisableSpecificWarnings', disabled_warnings)
# Turn on precompiled headers if appropriate.
if precompiled_header:
precompiled_header = os.path.split(precompiled_header)[1]
_ToolAppend(msbuild_settings, 'ClCompile', 'PrecompiledHeader', 'Use')
_ToolAppend(msbuild_settings, 'ClCompile',
'PrecompiledHeaderFile', precompiled_header)
_ToolAppend(msbuild_settings, 'ClCompile',
- 'ForcedIncludeFiles', precompiled_header)
+ 'ForcedIncludeFiles', [precompiled_header])
+ else:
+ _ToolAppend(msbuild_settings, 'ClCompile', 'PrecompiledHeader', 'NotUsing')
+ # Turn off WinRT compilation
+ _ToolAppend(msbuild_settings, 'ClCompile', 'CompileAsWinRT', 'false')
+ # Turn on import libraries if appropriate
+ if spec.get('msvs_requires_importlibrary'):
+ _ToolAppend(msbuild_settings, '', 'IgnoreImportLibrary', 'false')
# Loadable modules don't generate import libraries;
# tell dependent projects to not expect one.
if spec['type'] == 'loadable_module':
_ToolAppend(msbuild_settings, '', 'IgnoreImportLibrary', 'true')
# Set the module definition file if any.
if def_file:
_ToolAppend(msbuild_settings, 'Link', 'ModuleDefinitionFile', def_file)
configuration['finalized_msbuild_settings'] = msbuild_settings
+ if prebuild:
+ _ToolAppend(msbuild_settings, 'PreBuildEvent', 'Command', prebuild)
+ if postbuild:
+ _ToolAppend(msbuild_settings, 'PostBuildEvent', 'Command', postbuild)
def _GetValueFormattedForMSBuild(tool_name, name, value):
if type(value) == list:
# For some settings, VS2010 does not automatically extends the settings
# TODO(jeanluc) Is this what we want?
- if name in ['AdditionalDependencies',
- 'AdditionalIncludeDirectories',
+ if name in ['AdditionalIncludeDirectories',
'AdditionalLibraryDirectories',
'AdditionalOptions',
'DelayLoadDLLs',
'DisableSpecificWarnings',
'PreprocessorDefinitions']:
value.append('%%(%s)' % name)
# For most tools, entries in a list should be separated with ';' but some
# settings use a space. Check for those first.
@@ -2889,42 +3171,47 @@ def _VerifySourcesExist(sources, root_di
else:
if '$' not in source:
full_path = os.path.join(root_dir, source)
if not os.path.exists(full_path):
missing_sources.append(full_path)
return missing_sources
-def _GetMSBuildSources(spec, sources, exclusions, extension_to_rule_name,
- actions_spec, sources_handled_by_action, list_excluded):
- groups = ['none', 'midl', 'include', 'compile', 'resource', 'rule']
+def _GetMSBuildSources(spec, sources, exclusions, rule_dependencies,
+ extension_to_rule_name, actions_spec,
+ sources_handled_by_action, list_excluded):
+ groups = ['none', 'masm', 'midl', 'include', 'compile', 'resource', 'rule',
+ 'rule_dependency']
grouped_sources = {}
for g in groups:
grouped_sources[g] = []
_AddSources2(spec, sources, exclusions, grouped_sources,
- extension_to_rule_name, sources_handled_by_action, list_excluded)
+ rule_dependencies, extension_to_rule_name,
+ sources_handled_by_action, list_excluded)
sources = []
for g in groups:
if grouped_sources[g]:
sources.append(['ItemGroup'] + grouped_sources[g])
if actions_spec:
sources.append(['ItemGroup'] + actions_spec)
return sources
def _AddSources2(spec, sources, exclusions, grouped_sources,
- extension_to_rule_name, sources_handled_by_action,
+ rule_dependencies, extension_to_rule_name,
+ sources_handled_by_action,
list_excluded):
extensions_excluded_from_precompile = []
for source in sources:
if isinstance(source, MSVSProject.Filter):
_AddSources2(spec, source.contents, exclusions, grouped_sources,
- extension_to_rule_name, sources_handled_by_action,
+ rule_dependencies, extension_to_rule_name,
+ sources_handled_by_action,
list_excluded)
else:
if not source in sources_handled_by_action:
detail = []
excluded_configurations = exclusions.get(source, [])
if len(excluded_configurations) == len(spec['configurations']):
detail.append(['ExcludedFromBuild', 'true'])
else:
@@ -2957,17 +3244,17 @@ def _AddSources2(spec, sources, exclusio
# Turn off precompiled header usage for source files of a
# different type than the file that generated the
# precompiled header.
for extension in extensions_excluded_from_precompile:
if source.endswith(extension):
detail.append(['PrecompiledHeader', ''])
detail.append(['ForcedIncludeFiles', ''])
- group, element = _MapFileToMsBuildSourceType(source,
+ group, element = _MapFileToMsBuildSourceType(source, rule_dependencies,
extension_to_rule_name)
grouped_sources[group].append([element, {'Include': source}] + detail)
def _GetMSBuildProjectReferences(project):
references = []
if project.dependencies:
group = ['ItemGroup']
@@ -2989,104 +3276,166 @@ def _GetMSBuildProjectReferences(project
references.append(group)
return references
def _GenerateMSBuildProject(project, options, version, generator_flags):
spec = project.spec
configurations = spec['configurations']
project_dir, project_file_name = os.path.split(project.path)
- msbuildproj_dir = os.path.dirname(project.path)
- if msbuildproj_dir and not os.path.exists(msbuildproj_dir):
- os.makedirs(msbuildproj_dir)
+ gyp.common.EnsureDirExists(project.path)
# Prepare list of sources and excluded sources.
gyp_path = _NormalizedSource(project.build_file)
relative_path_of_gyp_file = gyp.common.RelativePath(gyp_path, project_dir)
gyp_file = os.path.split(project.build_file)[1]
sources, excluded_sources = _PrepareListOfSources(spec, generator_flags,
gyp_file)
# Add rules.
actions_to_add = {}
props_files_of_rules = set()
targets_files_of_rules = set()
+ rule_dependencies = set()
extension_to_rule_name = {}
list_excluded = generator_flags.get('msvs_list_excluded_files', True)
- _GenerateRulesForMSBuild(project_dir, options, spec,
- sources, excluded_sources,
- props_files_of_rules, targets_files_of_rules,
- actions_to_add, extension_to_rule_name)
+
+ # Don't generate rules if we are using an external builder like ninja.
+ if not spec.get('msvs_external_builder'):
+ _GenerateRulesForMSBuild(project_dir, options, spec,
+ sources, excluded_sources,
+ props_files_of_rules, targets_files_of_rules,
+ actions_to_add, rule_dependencies,
+ extension_to_rule_name)
+ else:
+ rules = spec.get('rules', [])
+ _AdjustSourcesForRules(rules, sources, excluded_sources, True)
+
sources, excluded_sources, excluded_idl = (
_AdjustSourcesAndConvertToFilterHierarchy(spec, options,
project_dir, sources,
excluded_sources,
- list_excluded))
- _AddActions(actions_to_add, spec, project.build_file)
- _AddCopies(actions_to_add, spec)
-
- # NOTE: this stanza must appear after all actions have been decided.
- # Don't excluded sources with actions attached, or they won't run.
- excluded_sources = _FilterActionsFromExcluded(
- excluded_sources, actions_to_add)
+ list_excluded, version))
+
+ # Don't add actions if we are using an external builder like ninja.
+ if not spec.get('msvs_external_builder'):
+ _AddActions(actions_to_add, spec, project.build_file)
+ _AddCopies(actions_to_add, spec)
+
+ # NOTE: this stanza must appear after all actions have been decided.
+ # Don't excluded sources with actions attached, or they won't run.
+ excluded_sources = _FilterActionsFromExcluded(
+ excluded_sources, actions_to_add)
exclusions = _GetExcludedFilesFromBuild(spec, excluded_sources, excluded_idl)
actions_spec, sources_handled_by_action = _GenerateActionsForMSBuild(
spec, actions_to_add)
_GenerateMSBuildFiltersFile(project.path + '.filters', sources,
+ rule_dependencies,
extension_to_rule_name)
missing_sources = _VerifySourcesExist(sources, project_dir)
for configuration in configurations.itervalues():
_FinalizeMSBuildSettings(spec, configuration)
# Add attributes to root element
import_default_section = [
['Import', {'Project': r'$(VCTargetsPath)\Microsoft.Cpp.Default.props'}]]
import_cpp_props_section = [
['Import', {'Project': r'$(VCTargetsPath)\Microsoft.Cpp.props'}]]
import_cpp_targets_section = [
['Import', {'Project': r'$(VCTargetsPath)\Microsoft.Cpp.targets'}]]
+ import_masm_props_section = [
+ ['Import',
+ {'Project': r'$(VCTargetsPath)\BuildCustomizations\masm.props'}]]
+ import_masm_targets_section = [
+ ['Import',
+ {'Project': r'$(VCTargetsPath)\BuildCustomizations\masm.targets'}]]
macro_section = [['PropertyGroup', {'Label': 'UserMacros'}]]
content = [
'Project',
{'xmlns': 'http://schemas.microsoft.com/developer/msbuild/2003',
'ToolsVersion': version.ProjectVersion(),
'DefaultTargets': 'Build'
}]
content += _GetMSBuildProjectConfigurations(configurations)
content += _GetMSBuildGlobalProperties(spec, project.guid, project_file_name)
content += import_default_section
content += _GetMSBuildConfigurationDetails(spec, project.build_file)
- content += _GetMSBuildLocalProperties(project.msbuild_toolset)
+ if spec.get('msvs_enable_winphone'):
+ content += _GetMSBuildLocalProperties('v120_wp81')
+ else:
+ content += _GetMSBuildLocalProperties(project.msbuild_toolset)
content += import_cpp_props_section
+ content += import_masm_props_section
content += _GetMSBuildExtensions(props_files_of_rules)
content += _GetMSBuildPropertySheets(configurations)
content += macro_section
content += _GetMSBuildConfigurationGlobalProperties(spec, configurations,
project.build_file)
content += _GetMSBuildToolSettingsSections(spec, configurations)
content += _GetMSBuildSources(
- spec, sources, exclusions, extension_to_rule_name, actions_spec,
- sources_handled_by_action, list_excluded)
+ spec, sources, exclusions, rule_dependencies, extension_to_rule_name,
+ actions_spec, sources_handled_by_action, list_excluded)
content += _GetMSBuildProjectReferences(project)
content += import_cpp_targets_section
+ content += import_masm_targets_section
content += _GetMSBuildExtensionTargets(targets_files_of_rules)
+ if spec.get('msvs_external_builder'):
+ content += _GetMSBuildExternalBuilderTargets(spec)
+
# TODO(jeanluc) File a bug to get rid of runas. We had in MSVS:
# has_run_as = _WriteMSVSUserFile(project.path, version, spec)
easy_xml.WriteXmlIfChanged(content, project.path, pretty=True, win32=True)
return missing_sources
+def _GetMSBuildExternalBuilderTargets(spec):
+ """Return a list of MSBuild targets for external builders.
+
+ The "Build" and "Clean" targets are always generated. If the spec contains
+ 'msvs_external_builder_clcompile_cmd', then the "ClCompile" target will also
+ be generated, to support building selected C/C++ files.
+
+ Arguments:
+ spec: The gyp target spec.
+ Returns:
+ List of MSBuild 'Target' specs.
+ """
+ build_cmd = _BuildCommandLineForRuleRaw(
+ spec, spec['msvs_external_builder_build_cmd'],
+ False, False, False, False)
+ build_target = ['Target', {'Name': 'Build'}]
+ build_target.append(['Exec', {'Command': build_cmd}])
+
+ clean_cmd = _BuildCommandLineForRuleRaw(
+ spec, spec['msvs_external_builder_clean_cmd'],
+ False, False, False, False)
+ clean_target = ['Target', {'Name': 'Clean'}]
+ clean_target.append(['Exec', {'Command': clean_cmd}])
+
+ targets = [build_target, clean_target]
+
+ if spec.get('msvs_external_builder_clcompile_cmd'):
+ clcompile_cmd = _BuildCommandLineForRuleRaw(
+ spec, spec['msvs_external_builder_clcompile_cmd'],
+ False, False, False, False)
+ clcompile_target = ['Target', {'Name': 'ClCompile'}]
+ clcompile_target.append(['Exec', {'Command': clcompile_cmd}])
+ targets.append(clcompile_target)
+
+ return targets
+
+
def _GetMSBuildExtensions(props_files_of_rules):
extensions = ['ImportGroup', {'Label': 'ExtensionSettings'}]
for props_file in props_files_of_rules:
extensions.append(['Import', {'Project': props_file}])
return [extensions]
def _GetMSBuildExtensionTargets(targets_files_of_rules):
@@ -3102,44 +3451,44 @@ def _GenerateActionsForMSBuild(spec, act
Arguments:
spec: the target project dict
actions_to_add: dictionary keyed on input name, which maps to a list of
dicts describing the actions attached to that input file.
Returns:
A pair of (action specification, the sources handled by this action).
"""
- sources_handled_by_action = set()
+ sources_handled_by_action = OrderedSet()
actions_spec = []
for primary_input, actions in actions_to_add.iteritems():
- inputs = set()
- outputs = set()
+ inputs = OrderedSet()
+ outputs = OrderedSet()
descriptions = []
commands = []
for action in actions:
- inputs.update(set(action['inputs']))
- outputs.update(set(action['outputs']))
+ inputs.update(OrderedSet(action['inputs']))
+ outputs.update(OrderedSet(action['outputs']))
descriptions.append(action['description'])
cmd = action['command']
# For most actions, add 'call' so that actions that invoke batch files
# return and continue executing. msbuild_use_call provides a way to
# disable this but I have not seen any adverse effect from doing that
# for everything.
if action.get('msbuild_use_call', True):
cmd = 'call ' + cmd
commands.append(cmd)
# Add the custom build action for one input file.
description = ', and also '.join(descriptions)
# We can't join the commands simply with && because the command line will
# get too long. See also _AddActions: cygwin's setup_env mustn't be called
# for every invocation or the command that sets the PATH will grow too
# long.
- command = (
- '\r\nif %errorlevel% neq 0 exit /b %errorlevel%\r\n'.join(commands))
+ command = '\r\n'.join([c + '\r\nif %errorlevel% neq 0 exit /b %errorlevel%'
+ for c in commands])
_AddMSBuildAction(spec,
primary_input,
inputs,
outputs,
command,
description,
sources_handled_by_action,
actions_spec)
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/ninja.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/ninja.py
@@ -1,25 +1,29 @@
-# Copyright (c) 2012 Google Inc. All rights reserved.
+# Copyright (c) 2013 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.
+import collections
import copy
import hashlib
+import json
import multiprocessing
import os.path
import re
import signal
import subprocess
import sys
import gyp
import gyp.common
+from gyp.common import OrderedSet
import gyp.msvs_emulation
-import gyp.MSVSVersion
+import gyp.MSVSUtil as MSVSUtil
import gyp.xcode_emulation
+from cStringIO import StringIO
from gyp.common import GetEnvironFallback
import gyp.ninja_syntax as ninja_syntax
generator_default_variables = {
'EXECUTABLE_PREFIX': '',
'EXECUTABLE_SUFFIX': '',
'STATIC_LIB_PREFIX': 'lib',
@@ -51,28 +55,19 @@ generator_default_variables = {
'RULE_INPUT_EXT': '${ext}',
'RULE_INPUT_NAME': '${name}',
}
# Placates pylint.
generator_additional_non_configuration_keys = []
generator_additional_path_sections = []
generator_extra_sources_for_rules = []
+generator_filelist_paths = None
-# TODO: figure out how to not build extra host objects in the non-cross-compile
-# case when this is enabled, and enable unconditionally.
-generator_supports_multiple_toolsets = (
- os.environ.get('GYP_CROSSCOMPILE') or
- os.environ.get('AR_host') or
- os.environ.get('CC_host') or
- os.environ.get('CXX_host') or
- os.environ.get('AR_target') or
- os.environ.get('CC_target') or
- os.environ.get('CXX_target'))
-
+generator_supports_multiple_toolsets = gyp.common.CrossCompileRequested()
def StripPrefix(arg, prefix):
if arg.startswith(prefix):
return arg[len(prefix):]
return arg
def QuoteShellArgument(arg, flavor):
@@ -92,32 +87,23 @@ def Define(d, flavor):
shell-escaped."""
if flavor == 'win':
# cl.exe replaces literal # characters with = in preprocesor definitions for
# some reason. Octal-encode to work around that.
d = d.replace('#', '\\%03o' % ord('#'))
return QuoteShellArgument(ninja_syntax.escape('-D' + d), flavor)
-def InvertRelativePath(path):
- """Given a relative path like foo/bar, return the inverse relative path:
- the path from the relative path back to the origin dir.
-
- E.g. os.path.normpath(os.path.join(path, InvertRelativePath(path)))
- should always produce the empty string."""
-
- if not path:
- return path
- # Only need to handle relative paths into subdirectories for now.
- assert '..' not in path, path
- depth = len(path.split(os.path.sep))
- return os.path.sep.join(['..'] * depth)
+def AddArch(output, arch):
+ """Adds an arch string to an output path."""
+ output, extension = os.path.splitext(output)
+ return '%s.%s%s' % (output, arch, extension)
-class Target:
+class Target(object):
"""Target represents the paths used within a single gyp target.
Conceptually, building a single target A is a series of steps:
1) actions/rules/copies generates source/resources/etc.
2) compiles generates .o files
3) link generates a binary (library/executable)
4) bundle merges the above in a mac bundle
@@ -148,22 +134,28 @@ class Target:
self.actions_stamp = None
# Path to the output of the link step, if any.
self.binary = None
# Path to the file representing the completion of building the bundle,
# if any.
self.bundle = None
# On Windows, incremental linking requires linking against all the .objs
# that compose a .lib (rather than the .lib itself). That list is stored
- # here.
+ # here. In this case, we also need to save the compile_deps for the target,
+ # so that the the target that directly depends on the .objs can also depend
+ # on those.
self.component_objs = None
+ self.compile_deps = None
# Windows only. The import .lib is the output of a build step, but
# because dependents only link against the lib (not both the lib and the
# dll) we keep track of the import library here.
self.import_lib = None
+ # Track if this target contains any C++ files, to decide if gcc or g++
+ # should be used for linking.
+ self.uses_cpp = False
def Linkable(self):
"""Return true if this is a target that can be linked against."""
return self.type in ('static_library', 'shared_library')
def UsesToc(self, flavor):
"""Return true if the target should produce a restat rule based on a TOC
file."""
@@ -211,44 +203,53 @@ class Target:
#
# - GypPathToNinja translates a gyp path (i.e. relative to the .gyp file)
# into the equivalent ninja path.
#
# - GypPathToUniqueOutput translates a gyp path into a ninja path to write
# an output file; the result can be namespaced such that it is unique
# to the input file name as well as the output target name.
-class NinjaWriter:
- def __init__(self, qualified_target, target_outputs, base_dir, build_dir,
- output_file, flavor, abs_build_dir=None):
+class NinjaWriter(object):
+ def __init__(self, hash_for_rules, target_outputs, base_dir, build_dir,
+ output_file, toplevel_build, output_file_name, flavor,
+ toplevel_dir=None):
"""
base_dir: path from source root to directory containing this gyp file,
by gyp semantics, all input paths are relative to this
build_dir: path from source root to build output
- abs_build_dir: absolute path to the build directory
+ toplevel_dir: path to the toplevel directory
"""
- self.qualified_target = qualified_target
+ self.hash_for_rules = hash_for_rules
self.target_outputs = target_outputs
self.base_dir = base_dir
self.build_dir = build_dir
self.ninja = ninja_syntax.Writer(output_file)
+ self.toplevel_build = toplevel_build
+ self.output_file_name = output_file_name
+
self.flavor = flavor
- self.abs_build_dir = abs_build_dir
+ self.abs_build_dir = None
+ if toplevel_dir is not None:
+ self.abs_build_dir = os.path.abspath(os.path.join(toplevel_dir,
+ build_dir))
self.obj_ext = '.obj' if flavor == 'win' else '.o'
if flavor == 'win':
# See docstring of msvs_emulation.GenerateEnvironmentFiles().
self.win_env = {}
for arch in ('x86', 'x64'):
self.win_env[arch] = 'environment.' + arch
# Relative path from build output dir to base dir.
- self.build_to_base = os.path.join(InvertRelativePath(build_dir), base_dir)
+ build_to_top = gyp.common.InvertRelativePath(build_dir, toplevel_dir)
+ self.build_to_base = os.path.join(build_to_top, base_dir)
# Relative path from base dir to build dir.
- self.base_to_build = os.path.join(InvertRelativePath(base_dir), build_dir)
+ base_to_top = gyp.common.InvertRelativePath(base_dir, toplevel_dir)
+ self.base_to_build = os.path.join(base_to_top, build_dir)
def ExpandSpecial(self, path, product_dir=None):
"""Expand specials like $!PRODUCT_DIR in |path|.
If |product_dir| is None, assumes the cwd is already the product
dir. Otherwise, |product_dir| is the relative path to the product
dir.
"""
@@ -298,17 +299,17 @@ class NinjaWriter:
elif self.flavor == 'win':
path = gyp.msvs_emulation.ExpandMacros(path, env)
if path.startswith('$!'):
expanded = self.ExpandSpecial(path)
if self.flavor == 'win':
expanded = os.path.normpath(expanded)
return expanded
if '$|' in path:
- path = self.ExpandSpecial(path)
+ path = self.ExpandSpecial(path)
assert '$' not in path, path
return os.path.normpath(os.path.join(self.build_to_base, path))
def GypPathToUniqueOutput(self, path, qualified=True):
"""Translate a gyp path to a ninja path for writing output.
If qualified is True, qualify the resulting filename with the name
of the target. This is necessary when e.g. compiling the same
@@ -330,77 +331,107 @@ class NinjaWriter:
# its path, even if the input is brought via a gyp file with '..'.
# 2) simple files like libraries and stamps have a simple filename.
obj = 'obj'
if self.toolset != 'target':
obj += '.' + self.toolset
path_dir, path_basename = os.path.split(path)
+ assert not os.path.isabs(path_dir), (
+ "'%s' can not be absolute path (see crbug.com/462153)." % path_dir)
+
if qualified:
path_basename = self.name + '.' + path_basename
return os.path.normpath(os.path.join(obj, self.base_dir, path_dir,
path_basename))
- def WriteCollapsedDependencies(self, name, targets):
+ def WriteCollapsedDependencies(self, name, targets, order_only=None):
"""Given a list of targets, return a path for a single file
representing the result of building all the targets or None.
Uses a stamp file if necessary."""
assert targets == filter(None, targets), targets
if len(targets) == 0:
+ assert not order_only
return None
- if len(targets) > 1:
+ if len(targets) > 1 or order_only:
stamp = self.GypPathToUniqueOutput(name + '.stamp')
- targets = self.ninja.build(stamp, 'stamp', targets)
+ targets = self.ninja.build(stamp, 'stamp', targets, order_only=order_only)
self.ninja.newline()
return targets[0]
- def WriteSpec(self, spec, config_name, generator_flags,
- case_sensitive_filesystem):
+ def _SubninjaNameForArch(self, arch):
+ output_file_base = os.path.splitext(self.output_file_name)[0]
+ return '%s.%s.ninja' % (output_file_base, arch)
+
+ def WriteSpec(self, spec, config_name, generator_flags):
"""The main entry point for NinjaWriter: write the build rules for a spec.
Returns a Target object, which represents the output paths for this spec.
Returns None if there are no outputs (e.g. a settings-only 'none' type
target)."""
self.config_name = config_name
self.name = spec['target_name']
self.toolset = spec['toolset']
config = spec['configurations'][config_name]
self.target = Target(spec['type'])
self.is_standalone_static_library = bool(
spec.get('standalone_static_library', 0))
+ self.target_rpath = generator_flags.get('target_rpath', r'\$$ORIGIN/lib/')
+
self.is_mac_bundle = gyp.xcode_emulation.IsMacBundle(self.flavor, spec)
self.xcode_settings = self.msvs_settings = None
if self.flavor == 'mac':
self.xcode_settings = gyp.xcode_emulation.XcodeSettings(spec)
+ mac_toolchain_dir = generator_flags.get('mac_toolchain_dir', None)
+ if mac_toolchain_dir:
+ self.xcode_settings.mac_toolchain_dir = mac_toolchain_dir
+
if self.flavor == 'win':
self.msvs_settings = gyp.msvs_emulation.MsvsSettings(spec,
generator_flags)
- target_platform = self.msvs_settings.GetTargetPlatform(config_name)
- self.ninja.variable('arch', self.win_env[target_platform])
+ arch = self.msvs_settings.GetArch(config_name)
+ self.ninja.variable('arch', self.win_env[arch])
+ self.ninja.variable('cc', '$cl_' + arch)
+ self.ninja.variable('cxx', '$cl_' + arch)
+ self.ninja.variable('cc_host', '$cl_' + arch)
+ self.ninja.variable('cxx_host', '$cl_' + arch)
+ self.ninja.variable('asm', '$ml_' + arch)
+
+ if self.flavor == 'mac':
+ self.archs = self.xcode_settings.GetActiveArchs(config_name)
+ if len(self.archs) > 1:
+ self.arch_subninjas = dict(
+ (arch, ninja_syntax.Writer(
+ OpenOutput(os.path.join(self.toplevel_build,
+ self._SubninjaNameForArch(arch)),
+ 'w')))
+ for arch in self.archs)
# Compute predepends for all rules.
# actions_depends is the dependencies this target depends on before running
# any of its action/rule/copy steps.
# compile_depends is the dependencies this target depends on before running
# any of its compile steps.
actions_depends = []
compile_depends = []
# TODO(evan): it is rather confusing which things are lists and which
# are strings. Fix these.
if 'dependencies' in spec:
for dep in spec['dependencies']:
if dep in self.target_outputs:
target = self.target_outputs[dep]
actions_depends.append(target.PreActionInput(self.flavor))
compile_depends.append(target.PreCompileInput())
+ if target.uses_cpp:
+ self.target.uses_cpp = True
actions_depends = filter(None, actions_depends)
compile_depends = filter(None, compile_depends)
actions_depends = self.WriteCollapsedDependencies('actions_depends',
actions_depends)
compile_depends = self.WriteCollapsedDependencies('compile_depends',
compile_depends)
self.target.preaction_stamp = actions_depends
self.target.precompile_stamp = compile_depends
@@ -416,47 +447,71 @@ class NinjaWriter:
# If we have actions/rules/copies, we depend directly on those, but
# otherwise we depend on dependent target's actions/rules/copies etc.
# We never need to explicitly depend on previous target's link steps,
# because no compile ever depends on them.
compile_depends_stamp = (self.target.actions_stamp or compile_depends)
# Write out the compilation steps, if any.
link_deps = []
- sources = spec.get('sources', []) + extra_sources
+ try:
+ sources = extra_sources + spec.get('sources', [])
+ except TypeError:
+ print 'extra_sources: ', str(extra_sources)
+ print 'spec.get("sources"): ', str(spec.get('sources'))
+ raise
if sources:
+ if self.flavor == 'mac' and len(self.archs) > 1:
+ # Write subninja file containing compile and link commands scoped to
+ # a single arch if a fat binary is being built.
+ for arch in self.archs:
+ self.ninja.subninja(self._SubninjaNameForArch(arch))
+
pch = None
if self.flavor == 'win':
+ gyp.msvs_emulation.VerifyMissingSources(
+ sources, self.abs_build_dir, generator_flags, self.GypPathToNinja)
pch = gyp.msvs_emulation.PrecompiledHeader(
- self.msvs_settings, config_name, self.GypPathToNinja)
+ self.msvs_settings, config_name, self.GypPathToNinja,
+ self.GypPathToUniqueOutput, self.obj_ext)
else:
pch = gyp.xcode_emulation.MacPrefixHeader(
self.xcode_settings, self.GypPathToNinja,
lambda path, lang: self.GypPathToUniqueOutput(path + '-' + lang))
link_deps = self.WriteSources(
- config_name, config, sources, compile_depends_stamp, pch,
- case_sensitive_filesystem)
+ self.ninja, config_name, config, sources, compile_depends_stamp, pch,
+ spec)
# Some actions/rules output 'sources' that are already object files.
- link_deps += [self.GypPathToNinja(f)
- for f in sources if f.endswith(self.obj_ext)]
+ obj_outputs = [f for f in sources if f.endswith(self.obj_ext)]
+ if obj_outputs:
+ if self.flavor != 'mac' or len(self.archs) == 1:
+ link_deps += [self.GypPathToNinja(o) for o in obj_outputs]
+ else:
+ print "Warning: Actions/rules writing object files don't work with " \
+ "multiarch targets, dropping. (target %s)" % spec['target_name']
+ elif self.flavor == 'mac' and len(self.archs) > 1:
+ link_deps = collections.defaultdict(list)
+ compile_deps = self.target.actions_stamp or actions_depends
if self.flavor == 'win' and self.target.type == 'static_library':
self.target.component_objs = link_deps
+ self.target.compile_deps = compile_deps
# Write out a link step, if needed.
output = None
+ is_empty_bundle = not link_deps and not mac_bundle_depends
if link_deps or self.target.actions_stamp or actions_depends:
output = self.WriteTarget(spec, config_name, config, link_deps,
- self.target.actions_stamp or actions_depends)
+ compile_deps)
if self.is_mac_bundle:
mac_bundle_depends.append(output)
# Bundle all of the above together, if needed.
if self.is_mac_bundle:
- output = self.WriteMacBundle(spec, mac_bundle_depends)
+ output = self.WriteMacBundle(spec, mac_bundle_depends, is_empty_bundle)
if not output:
return None
assert self.target.FinalOutput(), output
return self.target
def _WinIdlRule(self, source, prebuild, outputs):
@@ -481,49 +536,57 @@ class NinjaWriter:
input = self.GypPathToNinja(source)
self.ninja.build(output, 'idl', input,
variables=vars, order_only=prebuild)
outputs.extend(output)
def WriteWinIdlFiles(self, spec, prebuild):
"""Writes rules to match MSVS's implicit idl handling."""
assert self.flavor == 'win'
- if self.msvs_settings.HasExplicitIdlRules(spec):
+ if self.msvs_settings.HasExplicitIdlRulesOrActions(spec):
return []
outputs = []
for source in filter(lambda x: x.endswith('.idl'), spec['sources']):
self._WinIdlRule(source, prebuild, outputs)
return outputs
def WriteActionsRulesCopies(self, spec, extra_sources, prebuild,
mac_bundle_depends):
"""Write out the Actions, Rules, and Copies steps. Return a path
representing the outputs of these steps."""
outputs = []
+ if self.is_mac_bundle:
+ mac_bundle_resources = spec.get('mac_bundle_resources', [])[:]
+ else:
+ mac_bundle_resources = []
extra_mac_bundle_resources = []
if 'actions' in spec:
outputs += self.WriteActions(spec['actions'], extra_sources, prebuild,
extra_mac_bundle_resources)
if 'rules' in spec:
outputs += self.WriteRules(spec['rules'], extra_sources, prebuild,
+ mac_bundle_resources,
extra_mac_bundle_resources)
if 'copies' in spec:
- outputs += self.WriteCopies(spec['copies'], prebuild)
+ outputs += self.WriteCopies(spec['copies'], prebuild, mac_bundle_depends)
if 'sources' in spec and self.flavor == 'win':
outputs += self.WriteWinIdlFiles(spec, prebuild)
+ if self.xcode_settings and self.xcode_settings.IsIosFramework():
+ self.WriteiOSFrameworkHeaders(spec, outputs, prebuild)
+
stamp = self.WriteCollapsedDependencies('actions_rules_copies', outputs)
if self.is_mac_bundle:
- mac_bundle_resources = spec.get('mac_bundle_resources', []) + \
- extra_mac_bundle_resources
- self.WriteMacBundleResources(mac_bundle_resources, mac_bundle_depends)
- self.WriteMacInfoPlist(mac_bundle_depends)
+ xcassets = self.WriteMacBundleResources(
+ extra_mac_bundle_resources + mac_bundle_resources, mac_bundle_depends)
+ partial_info_plist = self.WriteMacXCassets(xcassets, mac_bundle_depends)
+ self.WriteMacInfoPlist(partial_info_plist, mac_bundle_depends)
return stamp
def GenerateDescription(self, verb, message, fallback):
"""Generate and return a description of a build step.
|verb| is the short summary, e.g. ACTION or RULE.
|message| is a hand-written description, or None if not available.
@@ -534,33 +597,34 @@ class NinjaWriter:
if message:
return '%s %s' % (verb, self.ExpandSpecial(message))
else:
return '%s %s: %s' % (verb, self.name, fallback)
def WriteActions(self, actions, extra_sources, prebuild,
extra_mac_bundle_resources):
# Actions cd into the base directory.
- env = self.GetSortedXcodeEnv()
- if self.flavor == 'win':
- env = self.msvs_settings.GetVSMacroEnv(
- '$!PRODUCT_DIR', config=self.config_name)
+ env = self.GetToolchainEnv()
all_outputs = []
for action in actions:
# First write out a rule for the action.
- name = '%s_%s' % (action['action_name'],
- hashlib.md5(self.qualified_target).hexdigest())
+ name = '%s_%s' % (action['action_name'], self.hash_for_rules)
description = self.GenerateDescription('ACTION',
action.get('message', None),
name)
is_cygwin = (self.msvs_settings.IsRuleRunUnderCygwin(action)
if self.flavor == 'win' else False)
args = action['action']
+ depfile = action.get('depfile', None)
+ if depfile:
+ depfile = self.ExpandSpecial(depfile, self.base_to_build)
+ pool = 'console' if int(action.get('ninja_use_console', 0)) else None
rule_name, _ = self.WriteNewNinjaRule(name, args, description,
- is_cygwin, env=env)
+ is_cygwin, env, pool,
+ depfile=depfile)
inputs = [self.GypPathToNinja(i, env) for i in action['inputs']]
if int(action.get('process_outputs_as_sources', False)):
extra_sources += action['outputs']
if int(action.get('process_outputs_as_mac_bundle_resources', False)):
extra_mac_bundle_resources += action['outputs']
outputs = [self.GypPathToNinja(o, env) for o in action['outputs']]
@@ -569,428 +633,779 @@ class NinjaWriter:
order_only=prebuild)
all_outputs += outputs
self.ninja.newline()
return all_outputs
def WriteRules(self, rules, extra_sources, prebuild,
- extra_mac_bundle_resources):
- env = self.GetSortedXcodeEnv()
+ mac_bundle_resources, extra_mac_bundle_resources):
+ env = self.GetToolchainEnv()
all_outputs = []
for rule in rules:
- # First write out a rule for the rule action.
- name = '%s_%s' % (rule['rule_name'],
- hashlib.md5(self.qualified_target).hexdigest())
# Skip a rule with no action and no inputs.
if 'action' not in rule and not rule.get('rule_sources', []):
continue
+
+ # First write out a rule for the rule action.
+ name = '%s_%s' % (rule['rule_name'], self.hash_for_rules)
+
args = rule['action']
description = self.GenerateDescription(
'RULE',
rule.get('message', None),
('%s ' + generator_default_variables['RULE_INPUT_PATH']) % name)
is_cygwin = (self.msvs_settings.IsRuleRunUnderCygwin(rule)
if self.flavor == 'win' else False)
+ pool = 'console' if int(rule.get('ninja_use_console', 0)) else None
rule_name, args = self.WriteNewNinjaRule(
- name, args, description, is_cygwin, env=env)
+ name, args, description, is_cygwin, env, pool)
# TODO: if the command references the outputs directly, we should
# simplify it to just use $out.
# Rules can potentially make use of some special variables which
# must vary per source file.
# Compute the list of variables we'll need to provide.
special_locals = ('source', 'root', 'dirname', 'ext', 'name')
needed_variables = set(['source'])
for argument in args:
for var in special_locals:
- if ('${%s}' % var) in argument:
+ if '${%s}' % var in argument:
needed_variables.add(var)
+ needed_variables = sorted(needed_variables)
def cygwin_munge(path):
+ # pylint: disable=cell-var-from-loop
if is_cygwin:
return path.replace('\\', '/')
return path
+ inputs = [self.GypPathToNinja(i, env) for i in rule.get('inputs', [])]
+
+ # If there are n source files matching the rule, and m additional rule
+ # inputs, then adding 'inputs' to each build edge written below will
+ # write m * n inputs. Collapsing reduces this to m + n.
+ sources = rule.get('rule_sources', [])
+ num_inputs = len(inputs)
+ if prebuild:
+ num_inputs += 1
+ if num_inputs > 2 and len(sources) > 2:
+ inputs = [self.WriteCollapsedDependencies(
+ rule['rule_name'], inputs, order_only=prebuild)]
+ prebuild = []
+
# For each source file, write an edge that generates all the outputs.
- for source in rule.get('rule_sources', []):
+ for source in sources:
+ source = os.path.normpath(source)
dirname, basename = os.path.split(source)
root, ext = os.path.splitext(basename)
# Gather the list of inputs and outputs, expanding $vars if possible.
outputs = [self.ExpandRuleVariables(o, root, dirname,
source, ext, basename)
for o in rule['outputs']]
- inputs = [self.ExpandRuleVariables(i, root, dirname,
- source, ext, basename)
- for i in rule.get('inputs', [])]
if int(rule.get('process_outputs_as_sources', False)):
extra_sources += outputs
- if int(rule.get('process_outputs_as_mac_bundle_resources', False)):
+
+ was_mac_bundle_resource = source in mac_bundle_resources
+ if was_mac_bundle_resource or \
+ int(rule.get('process_outputs_as_mac_bundle_resources', False)):
extra_mac_bundle_resources += outputs
+ # Note: This is n_resources * n_outputs_in_rule. Put to-be-removed
+ # items in a set and remove them all in a single pass if this becomes
+ # a performance issue.
+ if was_mac_bundle_resource:
+ mac_bundle_resources.remove(source)
extra_bindings = []
for var in needed_variables:
if var == 'root':
extra_bindings.append(('root', cygwin_munge(root)))
elif var == 'dirname':
- extra_bindings.append(('dirname', cygwin_munge(dirname)))
+ # '$dirname' is a parameter to the rule action, which means
+ # it shouldn't be converted to a Ninja path. But we don't
+ # want $!PRODUCT_DIR in there either.
+ dirname_expanded = self.ExpandSpecial(dirname, self.base_to_build)
+ extra_bindings.append(('dirname', cygwin_munge(dirname_expanded)))
elif var == 'source':
# '$source' is a parameter to the rule action, which means
# it shouldn't be converted to a Ninja path. But we don't
# want $!PRODUCT_DIR in there either.
source_expanded = self.ExpandSpecial(source, self.base_to_build)
extra_bindings.append(('source', cygwin_munge(source_expanded)))
elif var == 'ext':
extra_bindings.append(('ext', ext))
elif var == 'name':
extra_bindings.append(('name', cygwin_munge(basename)))
else:
assert var == None, repr(var)
- inputs = [self.GypPathToNinja(i, env) for i in inputs]
outputs = [self.GypPathToNinja(o, env) for o in outputs]
- extra_bindings.append(('unique_name',
- hashlib.md5(outputs[0]).hexdigest()))
+ if self.flavor == 'win':
+ # WriteNewNinjaRule uses unique_name for creating an rsp file on win.
+ extra_bindings.append(('unique_name',
+ hashlib.md5(outputs[0]).hexdigest()))
+
self.ninja.build(outputs, rule_name, self.GypPathToNinja(source),
implicit=inputs,
order_only=prebuild,
variables=extra_bindings)
all_outputs.extend(outputs)
return all_outputs
- def WriteCopies(self, copies, prebuild):
+ def WriteCopies(self, copies, prebuild, mac_bundle_depends):
outputs = []
- env = self.GetSortedXcodeEnv()
+ if self.xcode_settings:
+ extra_env = self.xcode_settings.GetPerTargetSettings()
+ env = self.GetToolchainEnv(additional_settings=extra_env)
+ else:
+ env = self.GetToolchainEnv()
for copy in copies:
for path in copy['files']:
# Normalize the path so trailing slashes don't confuse us.
path = os.path.normpath(path)
basename = os.path.split(path)[1]
src = self.GypPathToNinja(path, env)
dst = self.GypPathToNinja(os.path.join(copy['destination'], basename),
env)
outputs += self.ninja.build(dst, 'copy', src, order_only=prebuild)
+ if self.is_mac_bundle:
+ # gyp has mac_bundle_resources to copy things into a bundle's
+ # Resources folder, but there's no built-in way to copy files to other
+ # places in the bundle. Hence, some targets use copies for this. Check
+ # if this file is copied into the current bundle, and if so add it to
+ # the bundle depends so that dependent targets get rebuilt if the copy
+ # input changes.
+ if dst.startswith(self.xcode_settings.GetBundleContentsFolderPath()):
+ mac_bundle_depends.append(dst)
return outputs
+ def WriteiOSFrameworkHeaders(self, spec, outputs, prebuild):
+ """Prebuild steps to generate hmap files and copy headers to destination."""
+ framework = self.ComputeMacBundleOutput()
+ all_sources = spec['sources']
+ copy_headers = spec['mac_framework_headers']
+ output = self.GypPathToUniqueOutput('headers.hmap')
+ self.xcode_settings.header_map_path = output
+ all_headers = map(self.GypPathToNinja,
+ filter(lambda x:x.endswith(('.h')), all_sources))
+ variables = [('framework', framework),
+ ('copy_headers', map(self.GypPathToNinja, copy_headers))]
+ outputs.extend(self.ninja.build(
+ output, 'compile_ios_framework_headers', all_headers,
+ variables=variables, order_only=prebuild))
+
def WriteMacBundleResources(self, resources, bundle_depends):
"""Writes ninja edges for 'mac_bundle_resources'."""
+ xcassets = []
+
+ extra_env = self.xcode_settings.GetPerTargetSettings()
+ env = self.GetSortedXcodeEnv(additional_settings=extra_env)
+ env = self.ComputeExportEnvString(env)
+ isBinary = self.xcode_settings.IsBinaryOutputFormat(self.config_name)
+
for output, res in gyp.xcode_emulation.GetMacBundleResources(
- self.ExpandSpecial(generator_default_variables['PRODUCT_DIR']),
+ generator_default_variables['PRODUCT_DIR'],
self.xcode_settings, map(self.GypPathToNinja, resources)):
- self.ninja.build(output, 'mac_tool', res,
- variables=[('mactool_cmd', 'copy-bundle-resource')])
- bundle_depends.append(output)
+ output = self.ExpandSpecial(output)
+ if os.path.splitext(output)[-1] != '.xcassets':
+ self.ninja.build(output, 'mac_tool', res,
+ variables=[('mactool_cmd', 'copy-bundle-resource'), \
+ ('env', env), ('binary', isBinary)])
+ bundle_depends.append(output)
+ else:
+ xcassets.append(res)
+ return xcassets
+
+ def WriteMacXCassets(self, xcassets, bundle_depends):
+ """Writes ninja edges for 'mac_bundle_resources' .xcassets files.
+
+ This add an invocation of 'actool' via the 'mac_tool.py' helper script.
+ It assumes that the assets catalogs define at least one imageset and
+ thus an Assets.car file will be generated in the application resources
+ directory. If this is not the case, then the build will probably be done
+ at each invocation of ninja."""
+ if not xcassets:
+ return
- def WriteMacInfoPlist(self, bundle_depends):
+ extra_arguments = {}
+ settings_to_arg = {
+ 'XCASSETS_APP_ICON': 'app-icon',
+ 'XCASSETS_LAUNCH_IMAGE': 'launch-image',
+ }
+ settings = self.xcode_settings.xcode_settings[self.config_name]
+ for settings_key, arg_name in settings_to_arg.iteritems():
+ value = settings.get(settings_key)
+ if value:
+ extra_arguments[arg_name] = value
+
+ partial_info_plist = None
+ if extra_arguments:
+ partial_info_plist = self.GypPathToUniqueOutput(
+ 'assetcatalog_generated_info.plist')
+ extra_arguments['output-partial-info-plist'] = partial_info_plist
+
+ outputs = []
+ outputs.append(
+ os.path.join(
+ self.xcode_settings.GetBundleResourceFolder(),
+ 'Assets.car'))
+ if partial_info_plist:
+ outputs.append(partial_info_plist)
+
+ keys = QuoteShellArgument(json.dumps(extra_arguments), self.flavor)
+ extra_env = self.xcode_settings.GetPerTargetSettings()
+ env = self.GetSortedXcodeEnv(additional_settings=extra_env)
+ env = self.ComputeExportEnvString(env)
+
+ bundle_depends.extend(self.ninja.build(
+ outputs, 'compile_xcassets', xcassets,
+ variables=[('env', env), ('keys', keys)]))
+ return partial_info_plist
+
+ def WriteMacInfoPlist(self, partial_info_plist, bundle_depends):
"""Write build rules for bundle Info.plist files."""
info_plist, out, defines, extra_env = gyp.xcode_emulation.GetMacInfoPlist(
- self.ExpandSpecial(generator_default_variables['PRODUCT_DIR']),
+ generator_default_variables['PRODUCT_DIR'],
self.xcode_settings, self.GypPathToNinja)
if not info_plist:
return
+ out = self.ExpandSpecial(out)
if defines:
# Create an intermediate file to store preprocessed results.
intermediate_plist = self.GypPathToUniqueOutput(
os.path.basename(info_plist))
defines = ' '.join([Define(d, self.flavor) for d in defines])
- info_plist = self.ninja.build(intermediate_plist, 'infoplist', info_plist,
- variables=[('defines',defines)])
+ info_plist = self.ninja.build(
+ intermediate_plist, 'preprocess_infoplist', info_plist,
+ variables=[('defines',defines)])
env = self.GetSortedXcodeEnv(additional_settings=extra_env)
env = self.ComputeExportEnvString(env)
- self.ninja.build(out, 'mac_tool', info_plist,
- variables=[('mactool_cmd', 'copy-info-plist'),
- ('env', env)])
+ if partial_info_plist:
+ intermediate_plist = self.GypPathToUniqueOutput('merged_info.plist')
+ info_plist = self.ninja.build(
+ intermediate_plist, 'merge_infoplist',
+ [partial_info_plist, info_plist])
+
+ keys = self.xcode_settings.GetExtraPlistItems(self.config_name)
+ keys = QuoteShellArgument(json.dumps(keys), self.flavor)
+ isBinary = self.xcode_settings.IsBinaryOutputFormat(self.config_name)
+ self.ninja.build(out, 'copy_infoplist', info_plist,
+ variables=[('env', env), ('keys', keys),
+ ('binary', isBinary)])
bundle_depends.append(out)
- def WriteSources(self, config_name, config, sources, predepends,
- precompiled_header, case_sensitive_filesystem):
+ def WriteSources(self, ninja_file, config_name, config, sources, predepends,
+ precompiled_header, spec):
"""Write build rules to compile all of |sources|."""
if self.toolset == 'host':
self.ninja.variable('ar', '$ar_host')
self.ninja.variable('cc', '$cc_host')
self.ninja.variable('cxx', '$cxx_host')
self.ninja.variable('ld', '$ld_host')
+ self.ninja.variable('ldxx', '$ldxx_host')
+ self.ninja.variable('nm', '$nm_host')
+ self.ninja.variable('readelf', '$readelf_host')
+
+ if self.flavor != 'mac' or len(self.archs) == 1:
+ return self.WriteSourcesForArch(
+ self.ninja, config_name, config, sources, predepends,
+ precompiled_header, spec)
+ else:
+ return dict((arch, self.WriteSourcesForArch(
+ self.arch_subninjas[arch], config_name, config, sources, predepends,
+ precompiled_header, spec, arch=arch))
+ for arch in self.archs)
+
+ def WriteSourcesForArch(self, ninja_file, config_name, config, sources,
+ predepends, precompiled_header, spec, arch=None):
+ """Write build rules to compile all of |sources|."""
extra_defines = []
if self.flavor == 'mac':
- cflags = self.xcode_settings.GetCflags(config_name)
+ cflags = self.xcode_settings.GetCflags(config_name, arch=arch)
cflags_c = self.xcode_settings.GetCflagsC(config_name)
cflags_cc = self.xcode_settings.GetCflagsCC(config_name)
cflags_objc = ['$cflags_c'] + \
self.xcode_settings.GetCflagsObjC(config_name)
cflags_objcc = ['$cflags_cc'] + \
self.xcode_settings.GetCflagsObjCC(config_name)
elif self.flavor == 'win':
+ asmflags = self.msvs_settings.GetAsmflags(config_name)
cflags = self.msvs_settings.GetCflags(config_name)
cflags_c = self.msvs_settings.GetCflagsC(config_name)
cflags_cc = self.msvs_settings.GetCflagsCC(config_name)
extra_defines = self.msvs_settings.GetComputedDefines(config_name)
- self.WriteVariableList('pdbname', [self.name + '.pdb'])
- self.WriteVariableList('pchprefix', [self.name])
+ # See comment at cc_command for why there's two .pdb files.
+ pdbpath_c = pdbpath_cc = self.msvs_settings.GetCompilerPdbName(
+ config_name, self.ExpandSpecial)
+ if not pdbpath_c:
+ obj = 'obj'
+ if self.toolset != 'target':
+ obj += '.' + self.toolset
+ pdbpath = os.path.normpath(os.path.join(obj, self.base_dir, self.name))
+ pdbpath_c = pdbpath + '.c.pdb'
+ pdbpath_cc = pdbpath + '.cc.pdb'
+ self.WriteVariableList(ninja_file, 'pdbname_c', [pdbpath_c])
+ self.WriteVariableList(ninja_file, 'pdbname_cc', [pdbpath_cc])
+ self.WriteVariableList(ninja_file, 'pchprefix', [self.name])
else:
cflags = config.get('cflags', [])
cflags_c = config.get('cflags_c', [])
cflags_cc = config.get('cflags_cc', [])
+ # Respect environment variables related to build, but target-specific
+ # flags can still override them.
+ if self.toolset == 'target':
+ cflags_c = (os.environ.get('CPPFLAGS', '').split() +
+ os.environ.get('CFLAGS', '').split() + cflags_c)
+ cflags_cc = (os.environ.get('CPPFLAGS', '').split() +
+ os.environ.get('CXXFLAGS', '').split() + cflags_cc)
+ elif self.toolset == 'host':
+ cflags_c = (os.environ.get('CPPFLAGS_host', '').split() +
+ os.environ.get('CFLAGS_host', '').split() + cflags_c)
+ cflags_cc = (os.environ.get('CPPFLAGS_host', '').split() +
+ os.environ.get('CXXFLAGS_host', '').split() + cflags_cc)
+
defines = config.get('defines', []) + extra_defines
- self.WriteVariableList('defines', [Define(d, self.flavor) for d in defines])
+ self.WriteVariableList(ninja_file, 'defines',
+ [Define(d, self.flavor) for d in defines])
if self.flavor == 'win':
- self.WriteVariableList('rcflags',
+ self.WriteVariableList(ninja_file, 'asmflags',
+ map(self.ExpandSpecial, asmflags))
+ self.WriteVariableList(ninja_file, 'rcflags',
[QuoteShellArgument(self.ExpandSpecial(f), self.flavor)
for f in self.msvs_settings.GetRcflags(config_name,
self.GypPathToNinja)])
include_dirs = config.get('include_dirs', [])
+
+ env = self.GetToolchainEnv()
if self.flavor == 'win':
include_dirs = self.msvs_settings.AdjustIncludeDirs(include_dirs,
config_name)
- self.WriteVariableList('includes',
- [QuoteShellArgument('-I' + self.GypPathToNinja(i), self.flavor)
+ self.WriteVariableList(ninja_file, 'includes',
+ [QuoteShellArgument('-I' + self.GypPathToNinja(i, env), self.flavor)
for i in include_dirs])
- pch_commands = precompiled_header.GetPchBuildCommands()
+ if self.flavor == 'win':
+ midl_include_dirs = config.get('midl_include_dirs', [])
+ midl_include_dirs = self.msvs_settings.AdjustMidlIncludeDirs(
+ midl_include_dirs, config_name)
+ self.WriteVariableList(ninja_file, 'midl_includes',
+ [QuoteShellArgument('-I' + self.GypPathToNinja(i, env), self.flavor)
+ for i in midl_include_dirs])
+
+ pch_commands = precompiled_header.GetPchBuildCommands(arch)
if self.flavor == 'mac':
- self.WriteVariableList('cflags_pch_c',
- [precompiled_header.GetInclude('c')])
- self.WriteVariableList('cflags_pch_cc',
- [precompiled_header.GetInclude('cc')])
- self.WriteVariableList('cflags_pch_objc',
- [precompiled_header.GetInclude('m')])
- self.WriteVariableList('cflags_pch_objcc',
- [precompiled_header.GetInclude('mm')])
+ # Most targets use no precompiled headers, so only write these if needed.
+ for ext, var in [('c', 'cflags_pch_c'), ('cc', 'cflags_pch_cc'),
+ ('m', 'cflags_pch_objc'), ('mm', 'cflags_pch_objcc')]:
+ include = precompiled_header.GetInclude(ext, arch)
+ if include: ninja_file.variable(var, include)
- 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))
+ arflags = config.get('arflags', [])
+
+ self.WriteVariableList(ninja_file, 'cflags',
+ map(self.ExpandSpecial, cflags))
+ self.WriteVariableList(ninja_file, 'cflags_c',
+ map(self.ExpandSpecial, cflags_c))
+ self.WriteVariableList(ninja_file, '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()
+ self.WriteVariableList(ninja_file, 'cflags_objc',
+ map(self.ExpandSpecial, cflags_objc))
+ self.WriteVariableList(ninja_file, 'cflags_objcc',
+ map(self.ExpandSpecial, cflags_objcc))
+ self.WriteVariableList(ninja_file, 'arflags',
+ map(self.ExpandSpecial, arflags))
+ ninja_file.newline()
outputs = []
+ has_rc_source = False
for source in sources:
filename, ext = os.path.splitext(source)
ext = ext[1:]
obj_ext = self.obj_ext
if ext in ('cc', 'cpp', 'cxx'):
command = 'cxx'
- elif ext == 'c' or (ext in ('s', 'S') and self.flavor != 'win'):
+ self.target.uses_cpp = True
+ elif ext == 'c' or (ext == 'S' and self.flavor != 'win'):
command = 'cc'
+ elif ext == 's' and self.flavor != 'win': # Doesn't generate .o.d files.
+ command = 'cc_s'
elif (self.flavor == 'win' and ext == 'asm' and
- self.msvs_settings.GetTargetPlatform(config_name) == 'Win32'):
- # Asm files only get auto assembled for x86 (not x64).
+ not self.msvs_settings.HasExplicitAsmRules(spec)):
command = 'asm'
# Add the _asm suffix as msvs is capable of handling .cc and
# .asm files of the same name without collision.
obj_ext = '_asm.obj'
elif self.flavor == 'mac' and ext == 'm':
command = 'objc'
elif self.flavor == 'mac' and ext == 'mm':
command = 'objcxx'
+ self.target.uses_cpp = True
elif self.flavor == 'win' and ext == 'rc':
command = 'rc'
obj_ext = '.res'
+ has_rc_source = True
else:
# Ignore unhandled extensions.
continue
input = self.GypPathToNinja(source)
output = self.GypPathToUniqueOutput(filename + obj_ext)
- # Ninja's depfile handling gets confused when the case of a filename
- # changes on a case-insensitive file system. To work around that, always
- # convert .o filenames to lowercase on such file systems. See
- # https://github.com/martine/ninja/issues/402 for details.
- if not case_sensitive_filesystem:
- output = output.lower()
- implicit = precompiled_header.GetObjDependencies([input], [output])
- self.ninja.build(output, command, input,
+ if arch is not None:
+ output = AddArch(output, arch)
+ implicit = precompiled_header.GetObjDependencies([input], [output], arch)
+ variables = []
+ if self.flavor == 'win':
+ variables, output, implicit = precompiled_header.GetFlagsModifications(
+ input, output, implicit, command, cflags_c, cflags_cc,
+ self.ExpandSpecial)
+ ninja_file.build(output, command, input,
implicit=[gch for _, _, gch in implicit],
- order_only=predepends)
+ order_only=predepends, variables=variables)
outputs.append(output)
- self.WritePchTargets(pch_commands)
+ if has_rc_source:
+ resource_include_dirs = config.get('resource_include_dirs', include_dirs)
+ self.WriteVariableList(ninja_file, 'resource_includes',
+ [QuoteShellArgument('-I' + self.GypPathToNinja(i, env), self.flavor)
+ for i in resource_include_dirs])
- self.ninja.newline()
+ self.WritePchTargets(ninja_file, pch_commands)
+
+ ninja_file.newline()
return outputs
- def WritePchTargets(self, pch_commands):
+ def WritePchTargets(self, ninja_file, pch_commands):
"""Writes ninja rules to compile prefix headers."""
if not pch_commands:
return
for gch, lang_flag, lang, input in pch_commands:
var_name = {
'c': 'cflags_pch_c',
'cc': 'cflags_pch_cc',
'm': 'cflags_pch_objc',
'mm': 'cflags_pch_objcc',
}[lang]
map = { 'c': 'cc', 'cc': 'cxx', 'm': 'objc', 'mm': 'objcxx', }
- if self.flavor == 'win':
- map.update({'c': 'cc_pch', 'cc': 'cxx_pch'})
cmd = map.get(lang)
- self.ninja.build(gch, cmd, input, variables=[(var_name, lang_flag)])
+ ninja_file.build(gch, cmd, input, variables=[(var_name, lang_flag)])
- def WriteLink(self, spec, config_name, config, link_deps):
+ def WriteLink(self, spec, config_name, config, link_deps, compile_deps):
"""Write out a link step. Fills out target.binary. """
+ if self.flavor != 'mac' or len(self.archs) == 1:
+ return self.WriteLinkForArch(
+ self.ninja, spec, config_name, config, link_deps, compile_deps)
+ else:
+ output = self.ComputeOutput(spec)
+ inputs = [self.WriteLinkForArch(self.arch_subninjas[arch], spec,
+ config_name, config, link_deps[arch],
+ compile_deps, arch=arch)
+ for arch in self.archs]
+ extra_bindings = []
+ build_output = output
+ if not self.is_mac_bundle:
+ self.AppendPostbuildVariable(extra_bindings, spec, output, output)
+ # TODO(yyanagisawa): more work needed to fix:
+ # https://code.google.com/p/gyp/issues/detail?id=411
+ if (spec['type'] in ('shared_library', 'loadable_module') and
+ not self.is_mac_bundle):
+ extra_bindings.append(('lib', output))
+ self.ninja.build([output, output + '.TOC'], 'solipo', inputs,
+ variables=extra_bindings)
+ else:
+ self.ninja.build(build_output, 'lipo', inputs, variables=extra_bindings)
+ return output
+
+ def WriteLinkForArch(self, ninja_file, spec, config_name, config,
+ link_deps, compile_deps, arch=None):
+ """Write out a link step. Fills out target.binary. """
command = {
'executable': 'link',
'loadable_module': 'solink_module',
'shared_library': 'solink',
}[spec['type']]
+ command_suffix = ''
implicit_deps = set()
solibs = set()
+ order_deps = set()
+
+ if compile_deps:
+ # Normally, the compiles of the target already depend on compile_deps,
+ # but a shared_library target might have no sources and only link together
+ # a few static_library deps, so the link step also needs to depend
+ # on compile_deps to make sure actions in the shared_library target
+ # get run before the link.
+ order_deps.add(compile_deps)
if 'dependencies' in spec:
# Two kinds of dependencies:
# - Linkable dependencies (like a .a or a .so): add them to the link line.
# - Non-linkable dependencies (like a rule that generates a file
# and writes a stamp file): add them to implicit_deps
extra_link_deps = set()
for dep in spec['dependencies']:
target = self.target_outputs.get(dep)
if not target:
continue
linkable = target.Linkable()
if linkable:
+ new_deps = []
if (self.flavor == 'win' and
target.component_objs and
self.msvs_settings.IsUseLibraryDependencyInputs(config_name)):
- extra_link_deps |= set(target.component_objs)
+ new_deps = target.component_objs
+ if target.compile_deps:
+ order_deps.add(target.compile_deps)
elif self.flavor == 'win' and target.import_lib:
- extra_link_deps.add(target.import_lib)
+ new_deps = [target.import_lib]
elif target.UsesToc(self.flavor):
solibs.add(target.binary)
implicit_deps.add(target.binary + '.TOC')
else:
- extra_link_deps.add(target.binary)
+ new_deps = [target.binary]
+ for new_dep in new_deps:
+ if new_dep not in extra_link_deps:
+ extra_link_deps.add(new_dep)
+ link_deps.append(new_dep)
final_output = target.FinalOutput()
if not linkable or final_output != target.binary:
implicit_deps.add(final_output)
- link_deps.extend(list(extra_link_deps))
+ extra_bindings = []
+ if self.target.uses_cpp and self.flavor != 'win':
+ extra_bindings.append(('ld', '$ldxx'))
- extra_bindings = []
- if self.is_mac_bundle:
- output = self.ComputeMacBundleBinaryOutput()
- else:
- output = self.ComputeOutput(spec)
- extra_bindings.append(('postbuilds',
- self.GetPostbuildCommand(spec, output, output)))
+ output = self.ComputeOutput(spec, arch)
+ if arch is None and not self.is_mac_bundle:
+ self.AppendPostbuildVariable(extra_bindings, spec, output, output)
+ is_executable = spec['type'] == 'executable'
+ # The ldflags config key is not used on mac or win. On those platforms
+ # linker flags are set via xcode_settings and msvs_settings, respectively.
+ env_ldflags = os.environ.get('LDFLAGS', '').split()
if self.flavor == 'mac':
ldflags = self.xcode_settings.GetLdflags(config_name,
self.ExpandSpecial(generator_default_variables['PRODUCT_DIR']),
- self.GypPathToNinja)
+ self.GypPathToNinja, arch)
+ ldflags = env_ldflags + ldflags
elif self.flavor == 'win':
- libflags = self.msvs_settings.GetLibFlags(config_name,
- self.GypPathToNinja)
- self.WriteVariableList(
- 'libflags', gyp.common.uniquer(map(self.ExpandSpecial, libflags)))
- is_executable = spec['type'] == 'executable'
- manifest_name = self.GypPathToUniqueOutput(
+ manifest_base_name = self.GypPathToUniqueOutput(
self.ComputeOutputFileName(spec))
- ldflags, manifest_files = self.msvs_settings.GetLdflags(config_name,
- self.GypPathToNinja, self.ExpandSpecial, manifest_name, is_executable)
- self.WriteVariableList('manifests', manifest_files)
+ ldflags, intermediate_manifest, manifest_files = \
+ self.msvs_settings.GetLdflags(config_name, self.GypPathToNinja,
+ self.ExpandSpecial, manifest_base_name,
+ output, is_executable,
+ self.toplevel_build)
+ ldflags = env_ldflags + ldflags
+ self.WriteVariableList(ninja_file, 'manifests', manifest_files)
+ implicit_deps = implicit_deps.union(manifest_files)
+ if intermediate_manifest:
+ self.WriteVariableList(
+ ninja_file, 'intermediatemanifest', [intermediate_manifest])
+ command_suffix = _GetWinLinkRuleNameSuffix(
+ self.msvs_settings.IsEmbedManifest(config_name))
+ def_file = self.msvs_settings.GetDefFile(self.GypPathToNinja)
+ if def_file:
+ implicit_deps.add(def_file)
else:
- ldflags = config.get('ldflags', [])
- self.WriteVariableList('ldflags',
- gyp.common.uniquer(map(self.ExpandSpecial,
- ldflags)))
+ # Respect environment variables related to build, but target-specific
+ # flags can still override them.
+ ldflags = env_ldflags + config.get('ldflags', [])
+ if is_executable and len(solibs):
+ rpath = 'lib/'
+ if self.toolset != 'target':
+ rpath += self.toolset
+ ldflags.append(r'-Wl,-rpath=\$$ORIGIN/%s' % rpath)
+ else:
+ ldflags.append('-Wl,-rpath=%s' % self.target_rpath)
+ ldflags.append('-Wl,-rpath-link=%s' % rpath)
+ self.WriteVariableList(ninja_file, 'ldflags',
+ map(self.ExpandSpecial, ldflags))
+
+ library_dirs = config.get('library_dirs', [])
+ if self.flavor == 'win':
+ library_dirs = [self.msvs_settings.ConvertVSMacros(l, config_name)
+ for l in library_dirs]
+ library_dirs = ['/LIBPATH:' + QuoteShellArgument(self.GypPathToNinja(l),
+ self.flavor)
+ for l in library_dirs]
+ else:
+ library_dirs = [QuoteShellArgument('-L' + self.GypPathToNinja(l),
+ self.flavor)
+ for l in library_dirs]
libraries = gyp.common.uniquer(map(self.ExpandSpecial,
spec.get('libraries', [])))
if self.flavor == 'mac':
- libraries = self.xcode_settings.AdjustLibraries(libraries)
+ libraries = self.xcode_settings.AdjustLibraries(libraries, config_name)
elif self.flavor == 'win':
libraries = self.msvs_settings.AdjustLibraries(libraries)
- self.WriteVariableList('libs', libraries)
- self.target.binary = output
+ self.WriteVariableList(ninja_file, 'libs', library_dirs + libraries)
+
+ linked_binary = output
if command in ('solink', 'solink_module'):
extra_bindings.append(('soname', os.path.split(output)[1]))
extra_bindings.append(('lib',
gyp.common.EncodePOSIXShellArgument(output)))
+ if self.flavor != 'win':
+ link_file_list = output
+ if self.is_mac_bundle:
+ # 'Dependency Framework.framework/Versions/A/Dependency Framework' ->
+ # 'Dependency Framework.framework.rsp'
+ link_file_list = self.xcode_settings.GetWrapperName()
+ if arch:
+ link_file_list += '.' + arch
+ link_file_list += '.rsp'
+ # If an rspfile contains spaces, ninja surrounds the filename with
+ # quotes around it and then passes it to open(), creating a file with
+ # quotes in its name (and when looking for the rsp file, the name
+ # makes it through bash which strips the quotes) :-/
+ link_file_list = link_file_list.replace(' ', '_')
+ extra_bindings.append(
+ ('link_file_list',
+ gyp.common.EncodePOSIXShellArgument(link_file_list)))
if self.flavor == 'win':
- extra_bindings.append(('dll', output))
- if '/NOENTRY' not in ldflags:
+ extra_bindings.append(('binary', output))
+ if ('/NOENTRY' not in ldflags and
+ not self.msvs_settings.GetNoImportLibrary(config_name)):
self.target.import_lib = output + '.lib'
extra_bindings.append(('implibflag',
'/IMPLIB:%s' % self.target.import_lib))
+ pdbname = self.msvs_settings.GetPDBName(
+ config_name, self.ExpandSpecial, output + '.pdb')
output = [output, self.target.import_lib]
+ if pdbname:
+ output.append(pdbname)
+ elif not self.is_mac_bundle:
+ output = [output, output + '.TOC']
else:
- output = [output, output + '.TOC']
+ command = command + '_notoc'
+ elif self.flavor == 'win':
+ extra_bindings.append(('binary', output))
+ pdbname = self.msvs_settings.GetPDBName(
+ config_name, self.ExpandSpecial, output + '.pdb')
+ if pdbname:
+ output = [output, pdbname]
+
if len(solibs):
- extra_bindings.append(('solibs', gyp.common.EncodePOSIXShellList(solibs)))
+ extra_bindings.append(('solibs',
+ gyp.common.EncodePOSIXShellList(sorted(solibs))))
- self.ninja.build(output, command, link_deps,
- implicit=list(implicit_deps),
+ ninja_file.build(output, command + command_suffix, link_deps,
+ implicit=sorted(implicit_deps),
+ order_only=list(order_deps),
variables=extra_bindings)
+ return linked_binary
def WriteTarget(self, spec, config_name, config, link_deps, compile_deps):
- if spec['type'] == 'none':
+ extra_link_deps = any(self.target_outputs.get(dep).Linkable()
+ for dep in spec.get('dependencies', [])
+ if dep in self.target_outputs)
+ if spec['type'] == 'none' or (not link_deps and not extra_link_deps):
# TODO(evan): don't call this function for 'none' target types, as
# it doesn't do anything, and we fake out a 'binary' with a stamp file.
self.target.binary = compile_deps
+ self.target.type = 'none'
elif spec['type'] == 'static_library':
self.target.binary = self.ComputeOutput(spec)
- variables = []
- postbuild = self.GetPostbuildCommand(
- spec, self.target.binary, self.target.binary)
- if postbuild:
- variables.append(('postbuilds', postbuild))
- if self.xcode_settings:
- variables.append(('libtool_flags',
- self.xcode_settings.GetLibtoolflags(config_name)))
- if (self.flavor not in ('mac', 'win') and not
+ if (self.flavor not in ('mac', 'openbsd', 'netbsd', 'win') and not
self.is_standalone_static_library):
self.ninja.build(self.target.binary, 'alink_thin', link_deps,
- order_only=compile_deps, variables=variables)
+ order_only=compile_deps)
else:
- self.ninja.build(self.target.binary, 'alink', link_deps,
- order_only=compile_deps, variables=variables)
+ variables = []
+ if self.xcode_settings:
+ libtool_flags = self.xcode_settings.GetLibtoolflags(config_name)
+ if libtool_flags:
+ variables.append(('libtool_flags', libtool_flags))
+ if self.msvs_settings:
+ libflags = self.msvs_settings.GetLibFlags(config_name,
+ self.GypPathToNinja)
+ variables.append(('libflags', libflags))
+
+ if self.flavor != 'mac' or len(self.archs) == 1:
+ self.AppendPostbuildVariable(variables, spec,
+ self.target.binary, self.target.binary)
+ self.ninja.build(self.target.binary, 'alink', link_deps,
+ order_only=compile_deps, variables=variables)
+ else:
+ inputs = []
+ for arch in self.archs:
+ output = self.ComputeOutput(spec, arch)
+ self.arch_subninjas[arch].build(output, 'alink', link_deps[arch],
+ order_only=compile_deps,
+ variables=variables)
+ inputs.append(output)
+ # TODO: It's not clear if libtool_flags should be passed to the alink
+ # call that combines single-arch .a files into a fat .a file.
+ self.AppendPostbuildVariable(variables, spec,
+ self.target.binary, self.target.binary)
+ self.ninja.build(self.target.binary, 'alink', inputs,
+ # FIXME: test proving order_only=compile_deps isn't
+ # needed.
+ variables=variables)
else:
- self.WriteLink(spec, config_name, config, link_deps)
+ self.target.binary = self.WriteLink(spec, config_name, config, link_deps,
+ compile_deps)
return self.target.binary
- def WriteMacBundle(self, spec, mac_bundle_depends):
+ def WriteMacBundle(self, spec, mac_bundle_depends, is_empty):
assert self.is_mac_bundle
package_framework = spec['type'] in ('shared_library', 'loadable_module')
output = self.ComputeMacBundleOutput()
- postbuild = self.GetPostbuildCommand(spec, output, self.target.binary,
- is_command_start=not package_framework)
+ if is_empty:
+ output += '.stamp'
variables = []
- if postbuild:
- variables.append(('postbuilds', postbuild))
- if package_framework:
- variables.append(('version', self.xcode_settings.GetFrameworkVersion()))
- self.ninja.build(output, 'package_framework', mac_bundle_depends,
- variables=variables)
+ self.AppendPostbuildVariable(variables, spec, output, self.target.binary,
+ is_command_start=not package_framework)
+ if package_framework and not is_empty:
+ if spec['type'] == 'shared_library' and self.xcode_settings.isIOS:
+ self.ninja.build(output, 'package_ios_framework', mac_bundle_depends,
+ variables=variables)
+ else:
+ variables.append(('version', self.xcode_settings.GetFrameworkVersion()))
+ self.ninja.build(output, 'package_framework', mac_bundle_depends,
+ variables=variables)
else:
self.ninja.build(output, 'stamp', mac_bundle_depends,
variables=variables)
self.target.bundle = output
return output
+ def GetToolchainEnv(self, additional_settings=None):
+ """Returns the variables toolchain would set for build steps."""
+ env = self.GetSortedXcodeEnv(additional_settings=additional_settings)
+ if self.flavor == 'win':
+ env = self.GetMsvsToolchainEnv(
+ additional_settings=additional_settings)
+ return env
+
+ def GetMsvsToolchainEnv(self, additional_settings=None):
+ """Returns the variables Visual Studio would set for build steps."""
+ return self.msvs_settings.GetVSMacroEnv('$!PRODUCT_DIR',
+ config=self.config_name)
+
def GetSortedXcodeEnv(self, additional_settings=None):
"""Returns the variables Xcode would set for build steps."""
assert self.abs_build_dir
abs_build_dir = self.abs_build_dir
return gyp.xcode_emulation.GetSortedXcodeEnv(
self.xcode_settings, abs_build_dir,
os.path.join(abs_build_dir, self.build_to_base), self.config_name,
additional_settings)
@@ -1001,46 +1416,52 @@ class NinjaWriter:
# CHROMIUM_STRIP_SAVE_FILE is a chromium-specific hack.
# TODO(thakis): It would be nice to have some general mechanism instead.
strip_save_file = self.xcode_settings.GetPerTargetSetting(
'CHROMIUM_STRIP_SAVE_FILE')
if strip_save_file:
postbuild_settings['CHROMIUM_STRIP_SAVE_FILE'] = strip_save_file
return self.GetSortedXcodeEnv(additional_settings=postbuild_settings)
- def GetPostbuildCommand(self, spec, output, output_binary,
- is_command_start=False):
+ def AppendPostbuildVariable(self, variables, spec, output, binary,
+ is_command_start=False):
+ """Adds a 'postbuild' variable if there is a postbuild for |output|."""
+ postbuild = self.GetPostbuildCommand(spec, output, binary, is_command_start)
+ if postbuild:
+ variables.append(('postbuilds', postbuild))
+
+ def GetPostbuildCommand(self, spec, output, output_binary, is_command_start):
"""Returns a shell command that runs all the postbuilds, and removes
|output| if any of them fails. If |is_command_start| is False, then the
returned string will start with ' && '."""
if not self.xcode_settings or spec['type'] == 'none' or not output:
return ''
output = QuoteShellArgument(output, self.flavor)
- target_postbuilds = self.xcode_settings.GetTargetPostbuilds(
- self.config_name,
- os.path.normpath(os.path.join(self.base_to_build, output)),
- QuoteShellArgument(
- os.path.normpath(os.path.join(self.base_to_build, output_binary)),
- self.flavor),
- quiet=True)
postbuilds = gyp.xcode_emulation.GetSpecPostbuildCommands(spec, quiet=True)
- postbuilds = target_postbuilds + postbuilds
+ if output_binary is not None:
+ postbuilds = self.xcode_settings.AddImplicitPostbuilds(
+ self.config_name,
+ os.path.normpath(os.path.join(self.base_to_build, output)),
+ QuoteShellArgument(
+ os.path.normpath(os.path.join(self.base_to_build, output_binary)),
+ self.flavor),
+ postbuilds, quiet=True)
+
if not postbuilds:
return ''
# Postbuilds expect to be run in the gyp file's directory, so insert an
# implicit postbuild to cd to there.
postbuilds.insert(0, gyp.common.EncodePOSIXShellList(
['cd', self.build_to_base]))
env = self.ComputeExportEnvString(self.GetSortedXcodePostbuildEnv())
# G will be non-null if any postbuild fails. Run all postbuilds in a
# subshell.
- commands = env + ' (F=0; ' + \
- ' '.join([ninja_syntax.escape(command) + ' || F=$$?;'
- for command in postbuilds])
- command_string = (commands + ' exit $$F); G=$$?; '
+ commands = env + ' (' + \
+ ' && '.join([ninja_syntax.escape(command) for command in postbuilds])
+ command_string = (commands + '); G=$$?; '
# Remove the final output if any postbuild failed.
'((exit $$G) || rm -rf %s) ' % output + '&& exit $$G)')
if is_command_start:
return '(' + command_string + ' && '
else:
return '$ && (' + command_string
def ComputeExportEnvString(self, env):
@@ -1051,24 +1472,19 @@ class NinjaWriter:
for k, v in env:
export_str.append('export %s=%s;' %
(k, ninja_syntax.escape(gyp.common.EncodePOSIXShellArgument(v))))
return ' '.join(export_str)
def ComputeMacBundleOutput(self):
"""Return the 'output' (full output path) to a bundle output directory."""
assert self.is_mac_bundle
- path = self.ExpandSpecial(generator_default_variables['PRODUCT_DIR'])
- return os.path.join(path, self.xcode_settings.GetWrapperName())
-
- def ComputeMacBundleBinaryOutput(self):
- """Return the 'output' (full output path) to the binary in a bundle."""
- assert self.is_mac_bundle
- path = self.ExpandSpecial(generator_default_variables['PRODUCT_DIR'])
- return os.path.join(path, self.xcode_settings.GetExecutablePath())
+ path = generator_default_variables['PRODUCT_DIR']
+ return self.ExpandSpecial(
+ os.path.join(path, self.xcode_settings.GetWrapperName()))
def ComputeOutputFileName(self, spec, type=None):
"""Compute the filename of the final output for the current target."""
if not type:
type = spec['type']
default_variables = copy.copy(generator_default_variables)
CalculateVariables(default_variables, {'flavor': self.flavor})
@@ -1110,64 +1526,69 @@ class NinjaWriter:
if type in ('static_library', 'loadable_module', 'shared_library',
'executable'):
return '%s%s%s' % (prefix, target, extension)
elif type == 'none':
return '%s.stamp' % target
else:
raise Exception('Unhandled output type %s' % type)
- def ComputeOutput(self, spec, type=None):
+ def ComputeOutput(self, spec, arch=None):
"""Compute the path for the final output of the spec."""
- assert not self.is_mac_bundle or type
-
- if not type:
- type = spec['type']
+ type = spec['type']
if self.flavor == 'win':
override = self.msvs_settings.GetOutputName(self.config_name,
self.ExpandSpecial)
if override:
return override
- if self.flavor == 'mac' and type in (
+ if arch is None and self.flavor == 'mac' and type in (
'static_library', 'executable', 'shared_library', 'loadable_module'):
filename = self.xcode_settings.GetExecutablePath()
else:
filename = self.ComputeOutputFileName(spec, type)
- if 'product_dir' in spec:
+ if arch is None and 'product_dir' in spec:
path = os.path.join(spec['product_dir'], filename)
return self.ExpandSpecial(path)
# Some products go into the output root, libraries go into shared library
# dir, and everything else goes into the normal place.
type_in_output_root = ['executable', 'loadable_module']
if self.flavor == 'mac' and self.toolset == 'target':
type_in_output_root += ['shared_library', 'static_library']
elif self.flavor == 'win' and self.toolset == 'target':
type_in_output_root += ['shared_library']
- if type in type_in_output_root or self.is_standalone_static_library:
+ if arch is not None:
+ # Make sure partial executables don't end up in a bundle or the regular
+ # output directory.
+ archdir = 'arch'
+ if self.toolset != 'target':
+ archdir = os.path.join('arch', '%s' % self.toolset)
+ return os.path.join(archdir, AddArch(filename, arch))
+ elif type in type_in_output_root or self.is_standalone_static_library:
return filename
elif type == 'shared_library':
libdir = 'lib'
if self.toolset != 'target':
libdir = os.path.join('lib', '%s' % self.toolset)
return os.path.join(libdir, filename)
else:
return self.GypPathToUniqueOutput(filename, qualified=False)
- def WriteVariableList(self, var, values):
+ def WriteVariableList(self, ninja_file, var, values):
assert not isinstance(values, str)
if values is None:
values = []
- self.ninja.variable(var, ' '.join(values))
+ ninja_file.variable(var, ' '.join(values))
- def WriteNewNinjaRule(self, name, args, description, is_cygwin, env):
+ def WriteNewNinjaRule(self, name, args, description, is_cygwin, env, pool,
+ depfile=None):
"""Write out a new ninja "rule" statement for a given command.
Returns the name of the new rule, and a copy of |args| with variables
expanded."""
if self.flavor == 'win':
args = [self.msvs_settings.ConvertVSMacros(
arg, self.base_to_build, config=self.config_name)
@@ -1215,17 +1636,18 @@ class NinjaWriter:
else:
env = self.ComputeExportEnvString(env)
command = gyp.common.EncodePOSIXShellList(args)
command = 'cd %s; ' % self.build_to_base + env + command
# GYP rules/actions express being no-ops by not touching their outputs.
# Avoid executing downstream dependencies in this case by specifying
# restat=1 to ninja.
- self.ninja.rule(rule_name, command, description, restat=True,
+ self.ninja.rule(rule_name, command, description, depfile=depfile,
+ restat=True, pool=pool,
rspfile=rspfile, rspfile_content=rspfile_content)
self.ninja.newline()
return rule_name, args
def CalculateVariables(default_variables, params):
"""Calculate additional variables for use in the build (called by gyp)."""
@@ -1246,419 +1668,648 @@ def CalculateVariables(default_variables
generator_additional_non_configuration_keys = getattr(xcode_generator,
'generator_additional_non_configuration_keys', [])
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', [])
elif flavor == 'win':
+ exts = gyp.MSVSUtil.TARGET_TYPE_EXT
default_variables.setdefault('OS', 'win')
- default_variables['EXECUTABLE_SUFFIX'] = '.exe'
+ default_variables['EXECUTABLE_SUFFIX'] = '.' + exts['executable']
default_variables['STATIC_LIB_PREFIX'] = ''
- default_variables['STATIC_LIB_SUFFIX'] = '.lib'
+ default_variables['STATIC_LIB_SUFFIX'] = '.' + exts['static_library']
default_variables['SHARED_LIB_PREFIX'] = ''
- default_variables['SHARED_LIB_SUFFIX'] = '.dll'
- generator_flags = params.get('generator_flags', {})
+ default_variables['SHARED_LIB_SUFFIX'] = '.' + exts['shared_library']
# Copy additional generator configuration data from VS, which is shared
# by the Windows Ninja generator.
import gyp.generator.msvs as msvs_generator
generator_additional_non_configuration_keys = getattr(msvs_generator,
'generator_additional_non_configuration_keys', [])
generator_additional_path_sections = getattr(msvs_generator,
'generator_additional_path_sections', [])
- # Set a variable so conditions can be based on msvs_version.
- msvs_version = gyp.msvs_emulation.GetVSVersion(generator_flags)
- default_variables['MSVS_VERSION'] = msvs_version.ShortName()
-
- # To determine processor word size on Windows, in addition to checking
- # PROCESSOR_ARCHITECTURE (which reflects the word size of the current
- # process), it is also necessary to check PROCESSOR_ARCHITEW6432 (which
- # contains the actual word size of the system when running thru WOW64).
- if ('64' in os.environ.get('PROCESSOR_ARCHITECTURE', '') or
- '64' in os.environ.get('PROCESSOR_ARCHITEW6432', '')):
- default_variables['MSVS_OS_BITS'] = 64
- else:
- default_variables['MSVS_OS_BITS'] = 32
+ gyp.msvs_emulation.CalculateCommonVariables(default_variables, params)
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')
default_variables.setdefault('SHARED_LIB_DIR',
os.path.join('$!PRODUCT_DIR', 'lib'))
default_variables.setdefault('LIB_DIR',
os.path.join('$!PRODUCT_DIR', 'obj'))
+def ComputeOutputDir(params):
+ """Returns the path from the toplevel_dir to the build output directory."""
+ # generator_dir: relative path from pwd to where make puts build files.
+ # Makes migrating from make to ninja easier, ninja doesn't put anything here.
+ generator_dir = os.path.relpath(params['options'].generator_output or '.')
+
+ # output_dir: relative path from generator_dir to the build directory.
+ output_dir = params.get('generator_flags', {}).get('output_dir', 'out')
+
+ # Relative path from source root to our output files. e.g. "out"
+ return os.path.normpath(os.path.join(generator_dir, output_dir))
+
+
+def CalculateGeneratorInputInfo(params):
+ """Called by __init__ to initialize generator values based on params."""
+ # E.g. "out/gypfiles"
+ toplevel = params['options'].toplevel_dir
+ qualified_out_dir = os.path.normpath(os.path.join(
+ toplevel, ComputeOutputDir(params), 'gypfiles'))
+
+ global generator_filelist_paths
+ generator_filelist_paths = {
+ 'toplevel': toplevel,
+ 'qualified_out_dir': qualified_out_dir,
+ }
+
def OpenOutput(path, mode='w'):
"""Open |path| for writing, creating directories if necessary."""
- try:
- os.makedirs(os.path.dirname(path))
- except OSError:
- pass
+ gyp.common.EnsureDirExists(path)
return open(path, mode)
+def CommandWithWrapper(cmd, wrappers, prog):
+ wrapper = wrappers.get(cmd, '')
+ if wrapper:
+ return wrapper + ' ' + prog
+ return prog
+
+
+def GetDefaultConcurrentLinks():
+ """Returns a best-guess for a number of concurrent links."""
+ pool_size = int(os.environ.get('GYP_LINK_CONCURRENCY', 0))
+ if pool_size:
+ return pool_size
+
+ if sys.platform in ('win32', 'cygwin'):
+ import ctypes
+
+ class MEMORYSTATUSEX(ctypes.Structure):
+ _fields_ = [
+ ("dwLength", ctypes.c_ulong),
+ ("dwMemoryLoad", ctypes.c_ulong),
+ ("ullTotalPhys", ctypes.c_ulonglong),
+ ("ullAvailPhys", ctypes.c_ulonglong),
+ ("ullTotalPageFile", ctypes.c_ulonglong),
+ ("ullAvailPageFile", ctypes.c_ulonglong),
+ ("ullTotalVirtual", ctypes.c_ulonglong),
+ ("ullAvailVirtual", ctypes.c_ulonglong),
+ ("sullAvailExtendedVirtual", ctypes.c_ulonglong),
+ ]
+
+ stat = MEMORYSTATUSEX()
+ stat.dwLength = ctypes.sizeof(stat)
+ ctypes.windll.kernel32.GlobalMemoryStatusEx(ctypes.byref(stat))
+
+ # VS 2015 uses 20% more working set than VS 2013 and can consume all RAM
+ # on a 64 GB machine.
+ mem_limit = max(1, stat.ullTotalPhys / (5 * (2 ** 30))) # total / 5GB
+ hard_cap = max(1, int(os.environ.get('GYP_LINK_CONCURRENCY_MAX', 2**32)))
+ return min(mem_limit, hard_cap)
+ elif sys.platform.startswith('linux'):
+ if os.path.exists("/proc/meminfo"):
+ with open("/proc/meminfo") as meminfo:
+ memtotal_re = re.compile(r'^MemTotal:\s*(\d*)\s*kB')
+ for line in meminfo:
+ match = memtotal_re.match(line)
+ if not match:
+ continue
+ # Allow 8Gb per link on Linux because Gold is quite memory hungry
+ return max(1, int(match.group(1)) / (8 * (2 ** 20)))
+ return 1
+ elif sys.platform == 'darwin':
+ try:
+ avail_bytes = int(subprocess.check_output(['sysctl', '-n', 'hw.memsize']))
+ # A static library debug build of Chromium's unit_tests takes ~2.7GB, so
+ # 4GB per ld process allows for some more bloat.
+ return max(1, avail_bytes / (4 * (2 ** 30))) # total / 4GB
+ except:
+ return 1
+ else:
+ # TODO(scottmg): Implement this for other platforms.
+ return 1
+
+
+def _GetWinLinkRuleNameSuffix(embed_manifest):
+ """Returns the suffix used to select an appropriate linking rule depending on
+ whether the manifest embedding is enabled."""
+ return '_embed' if embed_manifest else ''
+
+
+def _AddWinLinkRules(master_ninja, embed_manifest):
+ """Adds link rules for Windows platform to |master_ninja|."""
+ def FullLinkCommand(ldcmd, out, binary_type):
+ resource_name = {
+ 'exe': '1',
+ 'dll': '2',
+ }[binary_type]
+ return '%(python)s gyp-win-tool link-with-manifests $arch %(embed)s ' \
+ '%(out)s "%(ldcmd)s" %(resname)s $mt $rc "$intermediatemanifest" ' \
+ '$manifests' % {
+ 'python': sys.executable,
+ 'out': out,
+ 'ldcmd': ldcmd,
+ 'resname': resource_name,
+ 'embed': embed_manifest }
+ rule_name_suffix = _GetWinLinkRuleNameSuffix(embed_manifest)
+ use_separate_mspdbsrv = (
+ int(os.environ.get('GYP_USE_SEPARATE_MSPDBSRV', '0')) != 0)
+ dlldesc = 'LINK%s(DLL) $binary' % rule_name_suffix.upper()
+ dllcmd = ('%s gyp-win-tool link-wrapper $arch %s '
+ '$ld /nologo $implibflag /DLL /OUT:$binary '
+ '@$binary.rsp' % (sys.executable, use_separate_mspdbsrv))
+ dllcmd = FullLinkCommand(dllcmd, '$binary', 'dll')
+ master_ninja.rule('solink' + rule_name_suffix,
+ description=dlldesc, command=dllcmd,
+ rspfile='$binary.rsp',
+ rspfile_content='$libs $in_newline $ldflags',
+ restat=True,
+ pool='link_pool')
+ master_ninja.rule('solink_module' + rule_name_suffix,
+ description=dlldesc, command=dllcmd,
+ rspfile='$binary.rsp',
+ rspfile_content='$libs $in_newline $ldflags',
+ restat=True,
+ pool='link_pool')
+ # Note that ldflags goes at the end so that it has the option of
+ # overriding default settings earlier in the command line.
+ exe_cmd = ('%s gyp-win-tool link-wrapper $arch %s '
+ '$ld /nologo /OUT:$binary @$binary.rsp' %
+ (sys.executable, use_separate_mspdbsrv))
+ exe_cmd = FullLinkCommand(exe_cmd, '$binary', 'exe')
+ master_ninja.rule('link' + rule_name_suffix,
+ description='LINK%s $binary' % rule_name_suffix.upper(),
+ command=exe_cmd,
+ rspfile='$binary.rsp',
+ rspfile_content='$in_newline $libs $ldflags',
+ pool='link_pool')
+
+
def GenerateOutputForConfig(target_list, target_dicts, data, params,
config_name):
options = params['options']
flavor = gyp.common.GetFlavor(params)
generator_flags = params.get('generator_flags', {})
- # generator_dir: relative path from pwd to where make puts build files.
- # Makes migrating from make to ninja easier, ninja doesn't put anything here.
- generator_dir = os.path.relpath(params['options'].generator_output or '.')
-
- # output_dir: relative path from generator_dir to the build directory.
- output_dir = generator_flags.get('output_dir', 'out')
-
# build_dir: relative path from source root to our output files.
# e.g. "out/Debug"
- build_dir = os.path.normpath(os.path.join(generator_dir,
- output_dir,
- config_name))
+ build_dir = os.path.normpath(
+ os.path.join(ComputeOutputDir(params), config_name))
toplevel_build = os.path.join(options.toplevel_dir, build_dir)
- master_ninja = ninja_syntax.Writer(
- OpenOutput(os.path.join(toplevel_build, 'build.ninja')),
- width=120)
- case_sensitive_filesystem = not os.path.exists(
- os.path.join(toplevel_build, 'BUILD.NINJA'))
+ master_ninja_file = OpenOutput(os.path.join(toplevel_build, 'build.ninja'))
+ master_ninja = ninja_syntax.Writer(master_ninja_file, width=120)
# Put build-time support tools in out/{config_name}.
- gyp.common.CopyTool(flavor, toplevel_build)
+ gyp.common.CopyTool(flavor, toplevel_build, generator_flags)
# Grab make settings for CC/CXX.
# The rules are
# - The priority from low to high is gcc/g++, the 'make_global_settings' in
# gyp, the environment variable.
# - If there is no 'make_global_settings' for CC.host/CXX.host or
# 'CC_host'/'CXX_host' enviroment variable, cc_host/cxx_host should be set
# to cc/cxx.
if flavor == 'win':
- cc = 'cl.exe'
- cxx = 'cl.exe'
+ ar = 'lib.exe'
+ # cc and cxx must be set to the correct architecture by overriding with one
+ # of cl_x86 or cl_x64 below.
+ cc = 'UNSET'
+ cxx = 'UNSET'
ld = 'link.exe'
- gyp.msvs_emulation.GenerateEnvironmentFiles(
- toplevel_build, generator_flags, OpenOutput)
ld_host = '$ld'
else:
- cc = 'gcc'
- cxx = 'g++'
- ld = '$cxx'
- ld_host = '$cxx_host'
+ ar = 'ar'
+ cc = 'cc'
+ cxx = 'c++'
+ ld = '$cc'
+ ldxx = '$cxx'
+ ld_host = '$cc_host'
+ ldxx_host = '$cxx_host'
+ ar_host = ar
cc_host = None
cxx_host = None
cc_host_global_setting = None
cxx_host_global_setting = None
+ clang_cl = None
+ nm = 'nm'
+ nm_host = 'nm'
+ readelf = 'readelf'
+ readelf_host = 'readelf'
build_file, _, _ = gyp.common.ParseQualifiedTarget(target_list[0])
make_global_settings = data[build_file].get('make_global_settings', [])
- build_to_root = InvertRelativePath(build_dir)
+ build_to_root = gyp.common.InvertRelativePath(build_dir,
+ options.toplevel_dir)
+ wrappers = {}
for key, value in make_global_settings:
+ if key == 'AR':
+ ar = os.path.join(build_to_root, value)
+ if key == 'AR.host':
+ ar_host = os.path.join(build_to_root, value)
if key == 'CC':
cc = os.path.join(build_to_root, value)
+ if cc.endswith('clang-cl'):
+ clang_cl = cc
if key == 'CXX':
cxx = os.path.join(build_to_root, value)
- if key == 'LD':
- ld = os.path.join(build_to_root, value)
if key == 'CC.host':
cc_host = os.path.join(build_to_root, value)
cc_host_global_setting = value
if key == 'CXX.host':
cxx_host = os.path.join(build_to_root, value)
cxx_host_global_setting = value
+ if key == 'LD':
+ ld = os.path.join(build_to_root, value)
if key == 'LD.host':
ld_host = os.path.join(build_to_root, value)
+ if key == 'NM':
+ nm = os.path.join(build_to_root, value)
+ if key == 'NM.host':
+ nm_host = os.path.join(build_to_root, value)
+ if key == 'READELF':
+ readelf = os.path.join(build_to_root, value)
+ if key == 'READELF.host':
+ readelf_host = os.path.join(build_to_root, value)
+ if key.endswith('_wrapper'):
+ wrappers[key[:-len('_wrapper')]] = os.path.join(build_to_root, value)
- flock = 'flock'
- if flavor == 'mac':
- flock = './gyp-mac-tool flock'
+ # Support wrappers from environment variables too.
+ for key, value in os.environ.iteritems():
+ if key.lower().endswith('_wrapper'):
+ key_prefix = key[:-len('_wrapper')]
+ key_prefix = re.sub(r'\.HOST$', '.host', key_prefix)
+ wrappers[key_prefix] = os.path.join(build_to_root, value)
+
+ mac_toolchain_dir = generator_flags.get('mac_toolchain_dir', None)
+ if mac_toolchain_dir:
+ wrappers['LINK'] = "export DEVELOPER_DIR='%s' &&" % mac_toolchain_dir
+
+ if flavor == 'win':
+ configs = [target_dicts[qualified_target]['configurations'][config_name]
+ for qualified_target in target_list]
+ shared_system_includes = None
+ if not generator_flags.get('ninja_use_custom_environment_files', 0):
+ shared_system_includes = \
+ gyp.msvs_emulation.ExtractSharedMSVSSystemIncludes(
+ configs, generator_flags)
+ cl_paths = gyp.msvs_emulation.GenerateEnvironmentFiles(
+ toplevel_build, generator_flags, shared_system_includes, OpenOutput)
+ for arch, path in sorted(cl_paths.iteritems()):
+ if clang_cl:
+ # If we have selected clang-cl, use that instead.
+ path = clang_cl
+ command = CommandWithWrapper('CC', wrappers,
+ QuoteShellArgument(path, 'win'))
+ if clang_cl:
+ # Use clang-cl to cross-compile for x86 or x86_64.
+ command += (' -m32' if arch == 'x86' else ' -m64')
+ master_ninja.variable('cl_' + arch, command)
+
cc = GetEnvironFallback(['CC_target', 'CC'], cc)
- master_ninja.variable('cc', cc)
+ master_ninja.variable('cc', CommandWithWrapper('CC', wrappers, cc))
cxx = GetEnvironFallback(['CXX_target', 'CXX'], cxx)
- master_ninja.variable('cxx', cxx)
- ld = GetEnvironFallback(['LD_target', 'LD'], ld)
-
- if not cc_host:
- cc_host = cc
- if not cxx_host:
- cxx_host = cxx
+ master_ninja.variable('cxx', CommandWithWrapper('CXX', wrappers, cxx))
if flavor == 'win':
master_ninja.variable('ld', ld)
master_ninja.variable('idl', 'midl.exe')
- master_ninja.variable('ar', 'lib.exe')
+ master_ninja.variable('ar', ar)
master_ninja.variable('rc', 'rc.exe')
- master_ninja.variable('asm', 'ml.exe')
+ master_ninja.variable('ml_x86', 'ml.exe')
+ master_ninja.variable('ml_x64', 'ml64.exe')
master_ninja.variable('mt', 'mt.exe')
- master_ninja.variable('use_dep_database', '1')
else:
- master_ninja.variable('ld', flock + ' linker.lock ' + ld)
- master_ninja.variable('ar', GetEnvironFallback(['AR_target', 'AR'], 'ar'))
+ master_ninja.variable('ld', CommandWithWrapper('LINK', wrappers, ld))
+ master_ninja.variable('ldxx', CommandWithWrapper('LINK', wrappers, ldxx))
+ master_ninja.variable('ar', GetEnvironFallback(['AR_target', 'AR'], ar))
+ if flavor != 'mac':
+ # Mac does not use readelf/nm for .TOC generation, so avoiding polluting
+ # the master ninja with extra unused variables.
+ master_ninja.variable(
+ 'nm', GetEnvironFallback(['NM_target', 'NM'], nm))
+ master_ninja.variable(
+ 'readelf', GetEnvironFallback(['READELF_target', 'READELF'], readelf))
- master_ninja.variable('ar_host', GetEnvironFallback(['AR_host'], 'ar'))
- cc_host = GetEnvironFallback(['CC_host'], cc_host)
- cxx_host = GetEnvironFallback(['CXX_host'], cxx_host)
- ld_host = GetEnvironFallback(['LD_host'], ld_host)
+ if generator_supports_multiple_toolsets:
+ if not cc_host:
+ cc_host = cc
+ if not cxx_host:
+ cxx_host = cxx
- # The environment variable could be used in 'make_global_settings', like
- # ['CC.host', '$(CC)'] or ['CXX.host', '$(CXX)'], transform them here.
- if '$(CC)' in cc_host and cc_host_global_setting:
- cc_host = cc_host_global_setting.replace('$(CC)', cc)
- if '$(CXX)' in cxx_host and cxx_host_global_setting:
- cxx_host = cxx_host_global_setting.replace('$(CXX)', cxx)
- master_ninja.variable('cc_host', cc_host)
- master_ninja.variable('cxx_host', cxx_host)
- if flavor == 'win':
- master_ninja.variable('ld_host', ld_host)
- else:
- master_ninja.variable('ld_host', flock + ' linker.lock ' + ld_host)
+ master_ninja.variable('ar_host', GetEnvironFallback(['AR_host'], ar_host))
+ master_ninja.variable('nm_host', GetEnvironFallback(['NM_host'], nm_host))
+ master_ninja.variable('readelf_host',
+ GetEnvironFallback(['READELF_host'], readelf_host))
+ cc_host = GetEnvironFallback(['CC_host'], cc_host)
+ cxx_host = GetEnvironFallback(['CXX_host'], cxx_host)
- if flavor == 'mac':
- master_ninja.variable('mac_tool', os.path.join('.', 'gyp-mac-tool'))
+ # The environment variable could be used in 'make_global_settings', like
+ # ['CC.host', '$(CC)'] or ['CXX.host', '$(CXX)'], transform them here.
+ if '$(CC)' in cc_host and cc_host_global_setting:
+ cc_host = cc_host_global_setting.replace('$(CC)', cc)
+ if '$(CXX)' in cxx_host and cxx_host_global_setting:
+ cxx_host = cxx_host_global_setting.replace('$(CXX)', cxx)
+ master_ninja.variable('cc_host',
+ CommandWithWrapper('CC.host', wrappers, cc_host))
+ master_ninja.variable('cxx_host',
+ CommandWithWrapper('CXX.host', wrappers, cxx_host))
+ if flavor == 'win':
+ master_ninja.variable('ld_host', ld_host)
+ else:
+ master_ninja.variable('ld_host', CommandWithWrapper(
+ 'LINK', wrappers, ld_host))
+ master_ninja.variable('ldxx_host', CommandWithWrapper(
+ 'LINK', wrappers, ldxx_host))
+
master_ninja.newline()
+ master_ninja.pool('link_pool', depth=GetDefaultConcurrentLinks())
+ master_ninja.newline()
+
+ deps = 'msvc' if flavor == 'win' else 'gcc'
+
if flavor != 'win':
master_ninja.rule(
'cc',
description='CC $out',
command=('$cc -MMD -MF $out.d $defines $includes $cflags $cflags_c '
'$cflags_pch_c -c $in -o $out'),
- depfile='$out.d')
+ depfile='$out.d',
+ deps=deps)
+ master_ninja.rule(
+ 'cc_s',
+ description='CC $out',
+ command=('$cc $defines $includes $cflags $cflags_c '
+ '$cflags_pch_c -c $in -o $out'))
master_ninja.rule(
'cxx',
description='CXX $out',
command=('$cxx -MMD -MF $out.d $defines $includes $cflags $cflags_cc '
'$cflags_pch_cc -c $in -o $out'),
- depfile='$out.d')
+ depfile='$out.d',
+ deps=deps)
else:
- # Template for compile commands mostly shared between compiling files
- # and generating PCH. In the case of PCH, the "output" is specified by /Fp
- # rather than /Fo (for object files), but we still need to specify an /Fo
- # when compiling PCH.
- cc_template = ('ninja -t msvc -r . -o $out -e $arch '
+ # TODO(scottmg) Separate pdb names is a test to see if it works around
+ # http://crbug.com/142362. It seems there's a race between the creation of
+ # the .pdb by the precompiled header step for .cc and the compilation of
+ # .c files. This should be handled by mspdbsrv, but rarely errors out with
+ # c1xx : fatal error C1033: cannot open program database
+ # By making the rules target separate pdb files this might be avoided.
+ cc_command = ('ninja -t msvc -e $arch ' +
+ '-- '
+ '$cc /nologo /showIncludes /FC '
+ '@$out.rsp /c $in /Fo$out /Fd$pdbname_c ')
+ cxx_command = ('ninja -t msvc -e $arch ' +
'-- '
- '$cc /nologo /showIncludes /FC '
- '@$out.rsp '
- '$cflags_pch_c /c $in %(outspec)s /Fd$pdbname ')
- cxx_template = ('ninja -t msvc -r . -o $out -e $arch '
- '-- '
- '$cxx /nologo /showIncludes /FC '
- '@$out.rsp '
- '$cflags_pch_cc /c $in %(outspec)s $pchobj /Fd$pdbname ')
+ '$cxx /nologo /showIncludes /FC '
+ '@$out.rsp /c $in /Fo$out /Fd$pdbname_cc ')
master_ninja.rule(
'cc',
description='CC $out',
- command=cc_template % {'outspec': '/Fo$out'},
- depfile='$out.d',
+ command=cc_command,
rspfile='$out.rsp',
- rspfile_content='$defines $includes $cflags $cflags_c')
- master_ninja.rule(
- 'cc_pch',
- description='CC PCH $out',
- command=cc_template % {'outspec': '/Fp$out /Fo$out.obj'},
- depfile='$out.d',
- rspfile='$out.rsp',
- rspfile_content='$defines $includes $cflags $cflags_c')
+ rspfile_content='$defines $includes $cflags $cflags_c',
+ deps=deps)
master_ninja.rule(
'cxx',
description='CXX $out',
- command=cxx_template % {'outspec': '/Fo$out'},
- depfile='$out.d',
+ command=cxx_command,
rspfile='$out.rsp',
- rspfile_content='$defines $includes $cflags $cflags_cc')
- master_ninja.rule(
- 'cxx_pch',
- description='CXX PCH $out',
- command=cxx_template % {'outspec': '/Fp$out /Fo$out.obj'},
- depfile='$out.d',
- rspfile='$out.rsp',
- rspfile_content='$defines $includes $cflags $cflags_cc')
+ rspfile_content='$defines $includes $cflags $cflags_cc',
+ deps=deps)
master_ninja.rule(
'idl',
description='IDL $in',
command=('%s gyp-win-tool midl-wrapper $arch $outdir '
'$tlb $h $dlldata $iid $proxy $in '
- '$idlflags' % sys.executable))
+ '$midl_includes $idlflags' % sys.executable))
master_ninja.rule(
'rc',
description='RC $in',
# Note: $in must be last otherwise rc.exe complains.
command=('%s gyp-win-tool rc-wrapper '
- '$arch $rc $defines $includes $rcflags /fo$out $in' %
+ '$arch $rc $defines $resource_includes $rcflags /fo$out $in' %
sys.executable))
master_ninja.rule(
'asm',
- description='ASM $in',
+ description='ASM $out',
command=('%s gyp-win-tool asm-wrapper '
- '$arch $asm $defines $includes /c /Fo $out $in' %
+ '$arch $asm $defines $includes $asmflags /c /Fo $out $in' %
sys.executable))
if flavor != 'mac' and flavor != 'win':
master_ninja.rule(
'alink',
description='AR $out',
- command='rm -f $out && $ar rcs $out $in')
+ command='rm -f $out && $ar rcs $arflags $out $in')
master_ninja.rule(
'alink_thin',
description='AR $out',
- command='rm -f $out && $ar rcsT $out $in')
+ command='rm -f $out && $ar rcsT $arflags $out $in')
# This allows targets that only need to depend on $lib's API to declare an
# order-only dependency on $lib.TOC and avoid relinking such downstream
# dependencies when $lib changes only in non-public ways.
# The resulting string leaves an uninterpolated %{suffix} which
# is used in the final substitution below.
mtime_preserving_solink_base = (
- 'if [ ! -e $lib -o ! -e ${lib}.TOC ]; then '
- '%(solink)s && %(extract_toc)s > ${lib}.TOC; else '
- '%(solink)s && %(extract_toc)s > ${lib}.tmp && '
- 'if ! cmp -s ${lib}.tmp ${lib}.TOC; then mv ${lib}.tmp ${lib}.TOC ; '
+ 'if [ ! -e $lib -o ! -e $lib.TOC ]; then '
+ '%(solink)s && %(extract_toc)s > $lib.TOC; else '
+ '%(solink)s && %(extract_toc)s > $lib.tmp && '
+ 'if ! cmp -s $lib.tmp $lib.TOC; then mv $lib.tmp $lib.TOC ; '
'fi; fi'
% { 'solink':
'$ld -shared $ldflags -o $lib -Wl,-soname=$soname %(suffix)s',
'extract_toc':
- ('{ readelf -d ${lib} | grep SONAME ; '
- 'nm -gD -f p ${lib} | cut -f1-2 -d\' \'; }')})
+ ('{ $readelf -d $lib | grep SONAME ; '
+ '$nm -gD -f p $lib | cut -f1-2 -d\' \'; }')})
master_ninja.rule(
'solink',
description='SOLINK $lib',
restat=True,
- command=(mtime_preserving_solink_base % {
- 'suffix': '-Wl,--whole-archive $in $solibs -Wl,--no-whole-archive '
- '$libs'}))
+ command=mtime_preserving_solink_base % {'suffix': '@$link_file_list'},
+ rspfile='$link_file_list',
+ rspfile_content=
+ '-Wl,--whole-archive $in $solibs -Wl,--no-whole-archive $libs',
+ pool='link_pool')
master_ninja.rule(
'solink_module',
description='SOLINK(module) $lib',
restat=True,
- command=(mtime_preserving_solink_base % {
- 'suffix': '-Wl,--start-group $in $solibs -Wl,--end-group $libs'}))
+ command=mtime_preserving_solink_base % {'suffix': '@$link_file_list'},
+ rspfile='$link_file_list',
+ rspfile_content='-Wl,--start-group $in -Wl,--end-group $solibs $libs',
+ pool='link_pool')
master_ninja.rule(
'link',
description='LINK $out',
- command=('$ld $ldflags -o $out -Wl,-rpath=\$$ORIGIN/lib '
- '-Wl,--start-group $in $solibs -Wl,--end-group $libs'))
+ command=('$ld $ldflags -o $out '
+ '-Wl,--start-group $in -Wl,--end-group $solibs $libs'),
+ pool='link_pool')
elif flavor == 'win':
master_ninja.rule(
'alink',
description='LIB $out',
- command=('%s gyp-win-tool link-wrapper $arch '
+ command=('%s gyp-win-tool link-wrapper $arch False '
'$ar /nologo /ignore:4221 /OUT:$out @$out.rsp' %
sys.executable),
rspfile='$out.rsp',
rspfile_content='$in_newline $libflags')
- dlldesc = 'LINK(DLL) $dll'
- dllcmd = ('%s gyp-win-tool link-wrapper $arch '
- '$ld /nologo $implibflag /DLL /OUT:$dll '
- '/PDB:$dll.pdb @$dll.rsp' % sys.executable)
- dllcmd += (' && %s gyp-win-tool manifest-wrapper $arch '
- '$mt -nologo -manifest $manifests -out:$dll.manifest' %
- sys.executable)
- master_ninja.rule('solink', description=dlldesc, command=dllcmd,
- rspfile='$dll.rsp',
- rspfile_content='$libs $in_newline $ldflags',
- restat=True)
- master_ninja.rule('solink_module', description=dlldesc, command=dllcmd,
- rspfile='$dll.rsp',
- rspfile_content='$libs $in_newline $ldflags',
- restat=True)
- # Note that ldflags goes at the end so that it has the option of
- # overriding default settings earlier in the command line.
- master_ninja.rule(
- 'link',
- description='LINK $out',
- command=('%s gyp-win-tool link-wrapper $arch '
- '$ld /nologo /OUT:$out /PDB:$out.pdb @$out.rsp && '
- '%s gyp-win-tool manifest-wrapper $arch '
- '$mt -nologo -manifest $manifests -out:$out.manifest' %
- (sys.executable, sys.executable)),
- rspfile='$out.rsp',
- rspfile_content='$in_newline $libs $ldflags')
+ _AddWinLinkRules(master_ninja, embed_manifest=True)
+ _AddWinLinkRules(master_ninja, embed_manifest=False)
else:
master_ninja.rule(
'objc',
description='OBJC $out',
command=('$cc -MMD -MF $out.d $defines $includes $cflags $cflags_objc '
'$cflags_pch_objc -c $in -o $out'),
- depfile='$out.d')
+ depfile='$out.d',
+ deps=deps)
master_ninja.rule(
'objcxx',
description='OBJCXX $out',
command=('$cxx -MMD -MF $out.d $defines $includes $cflags $cflags_objcc '
'$cflags_pch_objcc -c $in -o $out'),
- depfile='$out.d')
+ depfile='$out.d',
+ deps=deps)
master_ninja.rule(
'alink',
description='LIBTOOL-STATIC $out, POSTBUILDS',
command='rm -f $out && '
'./gyp-mac-tool filter-libtool libtool $libtool_flags '
'-static -o $out $in'
'$postbuilds')
+ master_ninja.rule(
+ 'lipo',
+ description='LIPO $out, POSTBUILDS',
+ command='rm -f $out && lipo -create $in -output $out$postbuilds')
+ master_ninja.rule(
+ 'solipo',
+ description='SOLIPO $out, POSTBUILDS',
+ command=(
+ 'rm -f $lib $lib.TOC && lipo -create $in -output $lib$postbuilds &&'
+ '%(extract_toc)s > $lib.TOC'
+ % { 'extract_toc':
+ '{ otool -l $lib | grep LC_ID_DYLIB -A 5; '
+ 'nm -gP $lib | cut -f1-2 -d\' \' | grep -v U$$; true; }'}))
+
# Record the public interface of $lib in $lib.TOC. See the corresponding
# comment in the posix section above for details.
+ solink_base = '$ld %(type)s $ldflags -o $lib %(suffix)s'
mtime_preserving_solink_base = (
- 'if [ ! -e $lib -o ! -e ${lib}.TOC ] || '
+ 'if [ ! -e $lib -o ! -e $lib.TOC ] || '
# Always force dependent targets to relink if this library
# reexports something. Handling this correctly would require
# recursive TOC dumping but this is rare in practice, so punt.
'otool -l $lib | grep -q LC_REEXPORT_DYLIB ; then '
- '%(solink)s && %(extract_toc)s > ${lib}.TOC; '
+ '%(solink)s && %(extract_toc)s > $lib.TOC; '
'else '
- '%(solink)s && %(extract_toc)s > ${lib}.tmp && '
- 'if ! cmp -s ${lib}.tmp ${lib}.TOC; then '
- 'mv ${lib}.tmp ${lib}.TOC ; '
+ '%(solink)s && %(extract_toc)s > $lib.tmp && '
+ 'if ! cmp -s $lib.tmp $lib.TOC; then '
+ 'mv $lib.tmp $lib.TOC ; '
'fi; '
'fi'
- % { 'solink': '$ld -shared $ldflags -o $lib %(suffix)s',
+ % { 'solink': solink_base,
'extract_toc':
'{ otool -l $lib | grep LC_ID_DYLIB -A 5; '
'nm -gP $lib | cut -f1-2 -d\' \' | grep -v U$$; true; }'})
- # TODO(thakis): The solink_module rule is likely wrong. Xcode seems to pass
- # -bundle -single_module here (for osmesa.so).
+
+ solink_suffix = '@$link_file_list$postbuilds'
master_ninja.rule(
'solink',
description='SOLINK $lib, POSTBUILDS',
restat=True,
- command=(mtime_preserving_solink_base % {
- 'suffix': '$in $solibs $libs$postbuilds'}))
+ command=mtime_preserving_solink_base % {'suffix': solink_suffix,
+ 'type': '-shared'},
+ rspfile='$link_file_list',
+ rspfile_content='$in $solibs $libs',
+ pool='link_pool')
+ master_ninja.rule(
+ 'solink_notoc',
+ description='SOLINK $lib, POSTBUILDS',
+ restat=True,
+ command=solink_base % {'suffix':solink_suffix, 'type': '-shared'},
+ rspfile='$link_file_list',
+ rspfile_content='$in $solibs $libs',
+ pool='link_pool')
+
master_ninja.rule(
'solink_module',
description='SOLINK(module) $lib, POSTBUILDS',
restat=True,
- command=(mtime_preserving_solink_base % {
- 'suffix': '$in $solibs $libs$postbuilds'}))
+ command=mtime_preserving_solink_base % {'suffix': solink_suffix,
+ 'type': '-bundle'},
+ rspfile='$link_file_list',
+ rspfile_content='$in $solibs $libs',
+ pool='link_pool')
+ master_ninja.rule(
+ 'solink_module_notoc',
+ description='SOLINK(module) $lib, POSTBUILDS',
+ restat=True,
+ command=solink_base % {'suffix': solink_suffix, 'type': '-bundle'},
+ rspfile='$link_file_list',
+ rspfile_content='$in $solibs $libs',
+ pool='link_pool')
master_ninja.rule(
'link',
description='LINK $out, POSTBUILDS',
command=('$ld $ldflags -o $out '
- '$in $solibs $libs$postbuilds'))
+ '$in $solibs $libs$postbuilds'),
+ pool='link_pool')
master_ninja.rule(
- 'infoplist',
- description='INFOPLIST $out',
+ 'preprocess_infoplist',
+ description='PREPROCESS INFOPLIST $out',
command=('$cc -E -P -Wno-trigraphs -x c $defines $in -o $out && '
'plutil -convert xml1 $out $out'))
master_ninja.rule(
+ 'copy_infoplist',
+ description='COPY INFOPLIST $in',
+ command='$env ./gyp-mac-tool copy-info-plist $in $out $binary $keys')
+ master_ninja.rule(
+ 'merge_infoplist',
+ description='MERGE INFOPLISTS $in',
+ command='$env ./gyp-mac-tool merge-info-plist $out $in')
+ master_ninja.rule(
+ 'compile_xcassets',
+ description='COMPILE XCASSETS $in',
+ command='$env ./gyp-mac-tool compile-xcassets $keys $in')
+ master_ninja.rule(
+ 'compile_ios_framework_headers',
+ description='COMPILE HEADER MAPS AND COPY FRAMEWORK HEADERS $in',
+ command='$env ./gyp-mac-tool compile-ios-framework-header-map $out '
+ '$framework $in && $env ./gyp-mac-tool '
+ 'copy-ios-framework-headers $framework $copy_headers')
+ master_ninja.rule(
'mac_tool',
description='MACTOOL $mactool_cmd $in',
- command='$env $mac_tool $mactool_cmd $in $out')
+ command='$env ./gyp-mac-tool $mactool_cmd $in $out $binary')
master_ninja.rule(
'package_framework',
description='PACKAGE FRAMEWORK $out, POSTBUILDS',
- command='$mac_tool package-framework $out $version$postbuilds '
+ command='./gyp-mac-tool package-framework $out $version$postbuilds '
+ '&& touch $out')
+ master_ninja.rule(
+ 'package_ios_framework',
+ description='PACKAGE IOS FRAMEWORK $out, POSTBUILDS',
+ command='./gyp-mac-tool package-ios-framework $out $postbuilds '
'&& touch $out')
if flavor == 'win':
master_ninja.rule(
'stamp',
description='STAMP $out',
command='%s gyp-win-tool stamp $out' % sys.executable)
master_ninja.rule(
'copy',
@@ -1683,67 +2334,108 @@ def GenerateOutputForConfig(target_list,
all_targets.add(target)
all_outputs = set()
# target_outputs is a map from qualified target name to a Target object.
target_outputs = {}
# target_short_names is a map from target short name to a list of Target
# objects.
target_short_names = {}
+
+ # short name of targets that were skipped because they didn't contain anything
+ # interesting.
+ # NOTE: there may be overlap between this an non_empty_target_names.
+ empty_target_names = set()
+
+ # Set of non-empty short target names.
+ # NOTE: there may be overlap between this an empty_target_names.
+ non_empty_target_names = set()
+
for qualified_target in target_list:
# qualified_target is like: third_party/icu/icu.gyp:icui18n#target
build_file, name, toolset = \
gyp.common.ParseQualifiedTarget(qualified_target)
this_make_global_settings = data[build_file].get('make_global_settings', [])
assert make_global_settings == this_make_global_settings, (
- "make_global_settings needs to be the same for all targets.")
+ "make_global_settings needs to be the same for all targets. %s vs. %s" %
+ (this_make_global_settings, make_global_settings))
spec = target_dicts[qualified_target]
if flavor == 'mac':
gyp.xcode_emulation.MergeGlobalXcodeSettingsToSpec(data[build_file], spec)
- build_file = gyp.common.RelativePath(build_file, options.toplevel_dir)
+ # If build_file is a symlink, we must not follow it because there's a chance
+ # it could point to a path above toplevel_dir, and we cannot correctly deal
+ # with that case at the moment.
+ build_file = gyp.common.RelativePath(build_file, options.toplevel_dir,
+ False)
+
+ qualified_target_for_hash = gyp.common.QualifiedTarget(build_file, name,
+ toolset)
+ hash_for_rules = hashlib.md5(qualified_target_for_hash).hexdigest()
base_path = os.path.dirname(build_file)
obj = 'obj'
if toolset != 'target':
obj += '.' + toolset
output_file = os.path.join(obj, base_path, name + '.ninja')
- abs_build_dir = os.path.abspath(toplevel_build)
- writer = NinjaWriter(qualified_target, target_outputs, base_path, build_dir,
- OpenOutput(os.path.join(toplevel_build, output_file)),
- flavor, abs_build_dir=abs_build_dir)
- master_ninja.subninja(output_file)
+ ninja_output = StringIO()
+ writer = NinjaWriter(hash_for_rules, target_outputs, base_path, build_dir,
+ ninja_output,
+ toplevel_build, output_file,
+ flavor, toplevel_dir=options.toplevel_dir)
+
+ target = writer.WriteSpec(spec, config_name, generator_flags)
- target = writer.WriteSpec(
- spec, config_name, generator_flags, case_sensitive_filesystem)
+ if ninja_output.tell() > 0:
+ # Only create files for ninja files that actually have contents.
+ with OpenOutput(os.path.join(toplevel_build, output_file)) as ninja_file:
+ ninja_file.write(ninja_output.getvalue())
+ ninja_output.close()
+ master_ninja.subninja(output_file)
+
if target:
if name != target.FinalOutput() and spec['toolset'] == 'target':
target_short_names.setdefault(name, []).append(target)
target_outputs[qualified_target] = target
if qualified_target in all_targets:
all_outputs.add(target.FinalOutput())
+ non_empty_target_names.add(name)
+ else:
+ empty_target_names.add(name)
if target_short_names:
# Write a short name to build this target. This benefits both the
# "build chrome" case as well as the gyp tests, which expect to be
# able to run actions and build libraries by their short name.
master_ninja.newline()
master_ninja.comment('Short names for targets.')
- for short_name in target_short_names:
+ for short_name in sorted(target_short_names):
master_ninja.build(short_name, 'phony', [x.FinalOutput() for x in
target_short_names[short_name]])
+ # Write phony targets for any empty targets that weren't written yet. As
+ # short names are not necessarily unique only do this for short names that
+ # haven't already been output for another target.
+ empty_target_names = empty_target_names - non_empty_target_names
+ if empty_target_names:
+ master_ninja.newline()
+ master_ninja.comment('Empty targets (output for completeness).')
+ for name in sorted(empty_target_names):
+ master_ninja.build(name, 'phony')
+
if all_outputs:
master_ninja.newline()
- master_ninja.build('all', 'phony', list(all_outputs))
+ master_ninja.build('all', 'phony', sorted(all_outputs))
master_ninja.default(generator_flags.get('default_target', 'all'))
+ master_ninja_file.close()
+
def PerformBuild(data, configurations, params):
options = params['options']
for config in configurations:
builddir = os.path.join(options.toplevel_dir, 'out', config)
arguments = ['ninja', '-C', builddir]
print 'Building [%s]: %s' % (config, arguments)
subprocess.check_call(arguments)
@@ -1754,29 +2446,38 @@ def CallGenerateOutputForConfig(arglist)
# kills all multiprocessing children.
signal.signal(signal.SIGINT, signal.SIG_IGN)
(target_list, target_dicts, data, params, config_name) = arglist
GenerateOutputForConfig(target_list, target_dicts, data, params, config_name)
def GenerateOutput(target_list, target_dicts, data, params):
+ # Update target_dicts for iOS device builds.
+ target_dicts = gyp.xcode_emulation.CloneConfigurationForDeviceAndEmulator(
+ target_dicts)
+
user_config = params.get('generator_flags', {}).get('config', None)
+ if gyp.common.GetFlavor(params) == 'win':
+ target_list, target_dicts = MSVSUtil.ShardTargets(target_list, target_dicts)
+ target_list, target_dicts = MSVSUtil.InsertLargePdbShims(
+ target_list, target_dicts, generator_default_variables)
+
if user_config:
GenerateOutputForConfig(target_list, target_dicts, data, params,
user_config)
else:
config_names = target_dicts[target_list[0]]['configurations'].keys()
if params['parallel']:
try:
pool = multiprocessing.Pool(len(config_names))
arglists = []
for config_name in config_names:
arglists.append(
(target_list, target_dicts, data, params, config_name))
- pool.map(CallGenerateOutputForConfig, arglists)
+ pool.map(CallGenerateOutputForConfig, arglists)
except KeyboardInterrupt, e:
pool.terminate()
raise e
else:
for config_name in config_names:
GenerateOutputForConfig(target_list, target_dicts, data, params,
config_name)
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/ninja_test.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/ninja_test.py
@@ -9,36 +9,39 @@
import gyp.generator.ninja as ninja
import unittest
import StringIO
import sys
import TestCommon
class TestPrefixesAndSuffixes(unittest.TestCase):
- if sys.platform in ('win32', 'cygwin'):
- def test_BinaryNamesWindows(self):
- writer = ninja.NinjaWriter('foo', 'wee', '.', '.', 'ninja.build', 'win')
+ def test_BinaryNamesWindows(self):
+ # These cannot run on non-Windows as they require a VS installation to
+ # correctly handle variable expansion.
+ if sys.platform.startswith('win'):
+ writer = ninja.NinjaWriter('foo', 'wee', '.', '.', 'build.ninja', '.',
+ 'build.ninja', 'win')
spec = { 'target_name': 'wee' }
self.assertTrue(writer.ComputeOutputFileName(spec, 'executable').
endswith('.exe'))
self.assertTrue(writer.ComputeOutputFileName(spec, 'shared_library').
endswith('.dll'))
self.assertTrue(writer.ComputeOutputFileName(spec, 'static_library').
endswith('.lib'))
- if sys.platform == 'linux2':
- def test_BinaryNamesLinux(self):
- writer = ninja.NinjaWriter('foo', 'wee', '.', '.', 'ninja.build', 'linux')
- spec = { 'target_name': 'wee' }
- self.assertTrue('.' not in writer.ComputeOutputFileName(spec,
- 'executable'))
- self.assertTrue(writer.ComputeOutputFileName(spec, 'shared_library').
- startswith('lib'))
- self.assertTrue(writer.ComputeOutputFileName(spec, 'static_library').
- startswith('lib'))
- self.assertTrue(writer.ComputeOutputFileName(spec, 'shared_library').
- endswith('.so'))
- self.assertTrue(writer.ComputeOutputFileName(spec, 'static_library').
- endswith('.a'))
+ def test_BinaryNamesLinux(self):
+ writer = ninja.NinjaWriter('foo', 'wee', '.', '.', 'build.ninja', '.',
+ 'build.ninja', 'linux')
+ spec = { 'target_name': 'wee' }
+ self.assertTrue('.' not in writer.ComputeOutputFileName(spec,
+ 'executable'))
+ self.assertTrue(writer.ComputeOutputFileName(spec, 'shared_library').
+ startswith('lib'))
+ self.assertTrue(writer.ComputeOutputFileName(spec, 'static_library').
+ startswith('lib'))
+ self.assertTrue(writer.ComputeOutputFileName(spec, 'shared_library').
+ endswith('.so'))
+ self.assertTrue(writer.ComputeOutputFileName(spec, 'static_library').
+ endswith('.a'))
if __name__ == '__main__':
unittest.main()
deleted file mode 100644
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/scons.py
+++ /dev/null
@@ -1,1072 +0,0 @@
-# Copyright (c) 2012 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.
-
-import gyp
-import gyp.common
-import gyp.SCons as SCons
-import os.path
-import pprint
-import re
-import subprocess
-
-
-# TODO: remove when we delete the last WriteList() call in this module
-WriteList = SCons.WriteList
-
-
-generator_default_variables = {
- 'EXECUTABLE_PREFIX': '',
- 'EXECUTABLE_SUFFIX': '',
- 'STATIC_LIB_PREFIX': '${LIBPREFIX}',
- 'SHARED_LIB_PREFIX': '${SHLIBPREFIX}',
- 'STATIC_LIB_SUFFIX': '${LIBSUFFIX}',
- 'SHARED_LIB_SUFFIX': '${SHLIBSUFFIX}',
- 'INTERMEDIATE_DIR': '${INTERMEDIATE_DIR}',
- 'SHARED_INTERMEDIATE_DIR': '${SHARED_INTERMEDIATE_DIR}',
- 'OS': 'linux',
- 'PRODUCT_DIR': '$TOP_BUILDDIR',
- 'SHARED_LIB_DIR': '$LIB_DIR',
- 'LIB_DIR': '$LIB_DIR',
- 'RULE_INPUT_ROOT': '${SOURCE.filebase}',
- 'RULE_INPUT_DIRNAME': '${SOURCE.dir}',
- 'RULE_INPUT_EXT': '${SOURCE.suffix}',
- 'RULE_INPUT_NAME': '${SOURCE.file}',
- 'RULE_INPUT_PATH': '${SOURCE.abspath}',
- 'CONFIGURATION_NAME': '${CONFIG_NAME}',
-}
-
-# Tell GYP how to process the input for us.
-generator_handles_variants = True
-generator_wants_absolute_build_file_paths = True
-
-
-def FixPath(path, prefix):
- if not os.path.isabs(path) and not path[0] == '$':
- path = prefix + path
- return path
-
-
-header = """\
-# This file is generated; do not edit.
-"""
-
-
-_alias_template = """
-if GetOption('verbose'):
- _action = Action([%(action)s])
-else:
- _action = Action([%(action)s], %(message)s)
-_outputs = env.Alias(
- ['_%(target_name)s_action'],
- %(inputs)s,
- _action
-)
-env.AlwaysBuild(_outputs)
-"""
-
-_run_as_template = """
-if GetOption('verbose'):
- _action = Action([%(action)s])
-else:
- _action = Action([%(action)s], %(message)s)
-"""
-
-_run_as_template_suffix = """
-_run_as_target = env.Alias('run_%(target_name)s', target_files, _action)
-env.Requires(_run_as_target, [
- Alias('%(target_name)s'),
-])
-env.AlwaysBuild(_run_as_target)
-"""
-
-_command_template = """
-if GetOption('verbose'):
- _action = Action([%(action)s])
-else:
- _action = Action([%(action)s], %(message)s)
-_outputs = env.Command(
- %(outputs)s,
- %(inputs)s,
- _action
-)
-"""
-
-# This is copied from the default SCons action, updated to handle symlinks.
-_copy_action_template = """
-import shutil
-import SCons.Action
-
-def _copy_files_or_dirs_or_symlinks(dest, src):
- SCons.Node.FS.invalidate_node_memos(dest)
- if SCons.Util.is_List(src) and os.path.isdir(dest):
- for file in src:
- shutil.copy2(file, dest)
- return 0
- elif os.path.islink(src):
- linkto = os.readlink(src)
- os.symlink(linkto, dest)
- return 0
- elif os.path.isfile(src):
- return shutil.copy2(src, dest)
- else:
- return shutil.copytree(src, dest, 1)
-
-def _copy_files_or_dirs_or_symlinks_str(dest, src):
- return 'Copying %s to %s ...' % (src, dest)
-
-GYPCopy = SCons.Action.ActionFactory(_copy_files_or_dirs_or_symlinks,
- _copy_files_or_dirs_or_symlinks_str,
- convert=str)
-"""
-
-_rule_template = """
-%(name)s_additional_inputs = %(inputs)s
-%(name)s_outputs = %(outputs)s
-def %(name)s_emitter(target, source, env):
- return (%(name)s_outputs, source + %(name)s_additional_inputs)
-if GetOption('verbose'):
- %(name)s_action = Action([%(action)s])
-else:
- %(name)s_action = Action([%(action)s], %(message)s)
-env['BUILDERS']['%(name)s'] = Builder(action=%(name)s_action,
- emitter=%(name)s_emitter)
-
-_outputs = []
-_processed_input_files = []
-for infile in input_files:
- if (type(infile) == type('')
- and not os.path.isabs(infile)
- and not infile[0] == '$'):
- infile = %(src_dir)r + infile
- if str(infile).endswith('.%(extension)s'):
- _generated = env.%(name)s(infile)
- env.Precious(_generated)
- _outputs.append(_generated)
- %(process_outputs_as_sources_line)s
- else:
- _processed_input_files.append(infile)
-prerequisites.extend(_outputs)
-input_files = _processed_input_files
-"""
-
-_spawn_hack = """
-import re
-import SCons.Platform.posix
-needs_shell = re.compile('["\\'><!^&]')
-def gyp_spawn(sh, escape, cmd, args, env):
- def strip_scons_quotes(arg):
- if arg[0] == '"' and arg[-1] == '"':
- return arg[1:-1]
- return arg
- stripped_args = [strip_scons_quotes(a) for a in args]
- if needs_shell.search(' '.join(stripped_args)):
- return SCons.Platform.posix.exec_spawnvpe([sh, '-c', ' '.join(args)], env)
- else:
- return SCons.Platform.posix.exec_spawnvpe(stripped_args, env)
-"""
-
-
-def EscapeShellArgument(s):
- """Quotes an argument so that it will be interpreted literally by a POSIX
- shell. Taken from
- http://stackoverflow.com/questions/35817/whats-the-best-way-to-escape-ossystem-calls-in-python
- """
- return "'" + s.replace("'", "'\\''") + "'"
-
-
-def InvertNaiveSConsQuoting(s):
- """SCons tries to "help" with quoting by naively putting double-quotes around
- command-line arguments containing space or tab, which is broken for all
- but trivial cases, so we undo it. (See quote_spaces() in Subst.py)"""
- if ' ' in s or '\t' in s:
- # Then SCons will put double-quotes around this, so add our own quotes
- # to close its quotes at the beginning and end.
- s = '"' + s + '"'
- return s
-
-
-def EscapeSConsVariableExpansion(s):
- """SCons has its own variable expansion syntax using $. We must escape it for
- strings to be interpreted literally. For some reason this requires four
- dollar signs, not two, even without the shell involved."""
- return s.replace('$', '$$$$')
-
-
-def EscapeCppDefine(s):
- """Escapes a CPP define so that it will reach the compiler unaltered."""
- s = EscapeShellArgument(s)
- s = InvertNaiveSConsQuoting(s)
- s = EscapeSConsVariableExpansion(s)
- return s
-
-
-def GenerateConfig(fp, config, indent='', src_dir=''):
- """
- Generates SCons dictionary items for a gyp configuration.
-
- This provides the main translation between the (lower-case) gyp settings
- keywords and the (upper-case) SCons construction variables.
- """
- var_mapping = {
- 'ASFLAGS' : 'asflags',
- 'CCFLAGS' : 'cflags',
- 'CFLAGS' : 'cflags_c',
- 'CXXFLAGS' : 'cflags_cc',
- 'CPPDEFINES' : 'defines',
- 'CPPPATH' : 'include_dirs',
- # Add the ldflags value to $LINKFLAGS, but not $SHLINKFLAGS.
- # SCons defines $SHLINKFLAGS to incorporate $LINKFLAGS, so
- # listing both here would case 'ldflags' to get appended to
- # both, and then have it show up twice on the command line.
- 'LINKFLAGS' : 'ldflags',
- }
- postamble='\n%s],\n' % indent
- for scons_var in sorted(var_mapping.keys()):
- gyp_var = var_mapping[scons_var]
- value = config.get(gyp_var)
- if value:
- if gyp_var in ('defines',):
- value = [EscapeCppDefine(v) for v in value]
- if gyp_var in ('include_dirs',):
- if src_dir and not src_dir.endswith('/'):
- src_dir += '/'
- result = []
- for v in value:
- v = FixPath(v, src_dir)
- # Force SCons to evaluate the CPPPATH directories at
- # SConscript-read time, so delayed evaluation of $SRC_DIR
- # doesn't point it to the --generator-output= directory.
- result.append('env.Dir(%r)' % v)
- value = result
- else:
- value = map(repr, value)
- WriteList(fp,
- value,
- prefix=indent,
- preamble='%s%s = [\n ' % (indent, scons_var),
- postamble=postamble)
-
-
-def GenerateSConscript(output_filename, spec, build_file, build_file_data):
- """
- Generates a SConscript file for a specific target.
-
- This generates a SConscript file suitable for building any or all of
- the target's configurations.
-
- A SConscript file may be called multiple times to generate targets for
- multiple configurations. Consequently, it needs to be ready to build
- the target for any requested configuration, and therefore contains
- information about the settings for all configurations (generated into
- the SConscript file at gyp configuration time) as well as logic for
- selecting (at SCons build time) the specific configuration being built.
-
- The general outline of a generated SConscript file is:
-
- -- Header
-
- -- Import 'env'. This contains a $CONFIG_NAME construction
- variable that specifies what configuration to build
- (e.g. Debug, Release).
-
- -- Configurations. This is a dictionary with settings for
- the different configurations (Debug, Release) under which this
- target can be built. The values in the dictionary are themselves
- dictionaries specifying what construction variables should added
- to the local copy of the imported construction environment
- (Append), should be removed (FilterOut), and should outright
- replace the imported values (Replace).
-
- -- Clone the imported construction environment and update
- with the proper configuration settings.
-
- -- Initialize the lists of the targets' input files and prerequisites.
-
- -- Target-specific actions and rules. These come after the
- input file and prerequisite initializations because the
- outputs of the actions and rules may affect the input file
- list (process_outputs_as_sources) and get added to the list of
- prerequisites (so that they're guaranteed to be executed before
- building the target).
-
- -- Call the Builder for the target itself.
-
- -- Arrange for any copies to be made into installation directories.
-
- -- Set up the {name} Alias (phony Node) for the target as the
- primary handle for building all of the target's pieces.
-
- -- Use env.Require() to make sure the prerequisites (explicitly
- specified, but also including the actions and rules) are built
- before the target itself.
-
- -- Return the {name} Alias to the calling SConstruct file
- so it can be added to the list of default targets.
- """
- scons_target = SCons.Target(spec)
-
- gyp_dir = os.path.dirname(output_filename)
- if not gyp_dir:
- gyp_dir = '.'
- gyp_dir = os.path.abspath(gyp_dir)
-
- output_dir = os.path.dirname(output_filename)
- src_dir = build_file_data['_DEPTH']
- src_dir_rel = gyp.common.RelativePath(src_dir, output_dir)
- subdir = gyp.common.RelativePath(os.path.dirname(build_file), src_dir)
- src_subdir = '$SRC_DIR/' + subdir
- src_subdir_ = src_subdir + '/'
-
- component_name = os.path.splitext(os.path.basename(build_file))[0]
- target_name = spec['target_name']
-
- if not os.path.exists(gyp_dir):
- os.makedirs(gyp_dir)
- fp = open(output_filename, 'w')
- fp.write(header)
-
- fp.write('\nimport os\n')
- fp.write('\nImport("env")\n')
-
- #
- fp.write('\n')
- fp.write('env = env.Clone(COMPONENT_NAME=%s,\n' % repr(component_name))
- fp.write(' TARGET_NAME=%s)\n' % repr(target_name))
-
- #
- for config in spec['configurations'].itervalues():
- if config.get('scons_line_length'):
- fp.write(_spawn_hack)
- break
-
- #
- indent = ' ' * 12
- fp.write('\n')
- fp.write('configurations = {\n')
- for config_name, config in spec['configurations'].iteritems():
- fp.write(' \'%s\' : {\n' % config_name)
-
- fp.write(' \'Append\' : dict(\n')
- GenerateConfig(fp, config, indent, src_subdir)
- libraries = spec.get('libraries')
- if libraries:
- WriteList(fp,
- map(repr, libraries),
- prefix=indent,
- preamble='%sLIBS = [\n ' % indent,
- postamble='\n%s],\n' % indent)
- fp.write(' ),\n')
-
- fp.write(' \'FilterOut\' : dict(\n' )
- for key, var in config.get('scons_remove', {}).iteritems():
- fp.write(' %s = %s,\n' % (key, repr(var)))
- fp.write(' ),\n')
-
- fp.write(' \'Replace\' : dict(\n' )
- scons_settings = config.get('scons_variable_settings', {})
- for key in sorted(scons_settings.keys()):
- val = pprint.pformat(scons_settings[key])
- fp.write(' %s = %s,\n' % (key, val))
- if 'c++' in spec.get('link_languages', []):
- fp.write(' %s = %s,\n' % ('LINK', repr('$CXX')))
- if config.get('scons_line_length'):
- fp.write(' SPAWN = gyp_spawn,\n')
- fp.write(' ),\n')
-
- fp.write(' \'ImportExternal\' : [\n' )
- for var in config.get('scons_import_variables', []):
- fp.write(' %s,\n' % repr(var))
- fp.write(' ],\n')
-
- fp.write(' \'PropagateExternal\' : [\n' )
- for var in config.get('scons_propagate_variables', []):
- fp.write(' %s,\n' % repr(var))
- fp.write(' ],\n')
-
- fp.write(' },\n')
- fp.write('}\n')
-
- fp.write('\n'
- 'config = configurations[env[\'CONFIG_NAME\']]\n'
- 'env.Append(**config[\'Append\'])\n'
- 'env.FilterOut(**config[\'FilterOut\'])\n'
- 'env.Replace(**config[\'Replace\'])\n')
-
- fp.write('\n'
- '# Scons forces -fPIC for SHCCFLAGS on some platforms.\n'
- '# Disable that so we can control it from cflags in gyp.\n'
- '# Note that Scons itself is inconsistent with its -fPIC\n'
- '# setting. SHCCFLAGS forces -fPIC, and SHCFLAGS does not.\n'
- '# This will make SHCCFLAGS consistent with SHCFLAGS.\n'
- 'env[\'SHCCFLAGS\'] = [\'$CCFLAGS\']\n')
-
- fp.write('\n'
- 'for _var in config[\'ImportExternal\']:\n'
- ' if _var in ARGUMENTS:\n'
- ' env[_var] = ARGUMENTS[_var]\n'
- ' elif _var in os.environ:\n'
- ' env[_var] = os.environ[_var]\n'
- 'for _var in config[\'PropagateExternal\']:\n'
- ' if _var in ARGUMENTS:\n'
- ' env[_var] = ARGUMENTS[_var]\n'
- ' elif _var in os.environ:\n'
- ' env[\'ENV\'][_var] = os.environ[_var]\n')
-
- fp.write('\n'
- "env['ENV']['LD_LIBRARY_PATH'] = env.subst('$LIB_DIR')\n")
-
- #
- #fp.write("\nif env.has_key('CPPPATH'):\n")
- #fp.write(" env['CPPPATH'] = map(env.Dir, env['CPPPATH'])\n")
-
- variants = spec.get('variants', {})
- for setting in sorted(variants.keys()):
- if_fmt = 'if ARGUMENTS.get(%s) not in (None, \'0\'):\n'
- fp.write('\n')
- fp.write(if_fmt % repr(setting.upper()))
- fp.write(' env.AppendUnique(\n')
- GenerateConfig(fp, variants[setting], indent, src_subdir)
- fp.write(' )\n')
-
- #
- scons_target.write_input_files(fp)
-
- fp.write('\n')
- fp.write('target_files = []\n')
- prerequisites = spec.get('scons_prerequisites', [])
- fp.write('prerequisites = %s\n' % pprint.pformat(prerequisites))
-
- actions = spec.get('actions', [])
- for action in actions:
- a = ['cd', src_subdir, '&&'] + action['action']
- message = action.get('message')
- if message:
- message = repr(message)
- inputs = [FixPath(f, src_subdir_) for f in action.get('inputs', [])]
- outputs = [FixPath(f, src_subdir_) for f in action.get('outputs', [])]
- if outputs:
- template = _command_template
- else:
- template = _alias_template
- fp.write(template % {
- 'inputs' : pprint.pformat(inputs),
- 'outputs' : pprint.pformat(outputs),
- 'action' : pprint.pformat(a),
- 'message' : message,
- 'target_name': target_name,
- })
- if int(action.get('process_outputs_as_sources', 0)):
- fp.write('input_files.extend(_outputs)\n')
- fp.write('prerequisites.extend(_outputs)\n')
- fp.write('target_files.extend(_outputs)\n')
-
- rules = spec.get('rules', [])
- for rule in rules:
- name = re.sub('[^a-zA-Z0-9_]', '_', rule['rule_name'])
- message = rule.get('message')
- if message:
- message = repr(message)
- if int(rule.get('process_outputs_as_sources', 0)):
- poas_line = '_processed_input_files.extend(_generated)'
- else:
- poas_line = '_processed_input_files.append(infile)'
- inputs = [FixPath(f, src_subdir_) for f in rule.get('inputs', [])]
- outputs = [FixPath(f, src_subdir_) for f in rule.get('outputs', [])]
- # Skip a rule with no action and no inputs.
- if 'action' not in rule and not rule.get('rule_sources', []):
- continue
- a = ['cd', src_subdir, '&&'] + rule['action']
- fp.write(_rule_template % {
- 'inputs' : pprint.pformat(inputs),
- 'outputs' : pprint.pformat(outputs),
- 'action' : pprint.pformat(a),
- 'extension' : rule['extension'],
- 'name' : name,
- 'message' : message,
- 'process_outputs_as_sources_line' : poas_line,
- 'src_dir' : src_subdir_,
- })
-
- scons_target.write_target(fp, src_subdir)
-
- copies = spec.get('copies', [])
- if copies:
- fp.write(_copy_action_template)
- for copy in copies:
- destdir = None
- files = None
- try:
- destdir = copy['destination']
- except KeyError, e:
- gyp.common.ExceptionAppend(
- e,
- "Required 'destination' key missing for 'copies' in %s." % build_file)
- raise
- try:
- files = copy['files']
- except KeyError, e:
- gyp.common.ExceptionAppend(
- e, "Required 'files' key missing for 'copies' in %s." % build_file)
- raise
- if not files:
- # TODO: should probably add a (suppressible) warning;
- # a null file list may be unintentional.
- continue
- if not destdir:
- raise Exception(
- "Required 'destination' key is empty for 'copies' in %s." % build_file)
-
- fmt = ('\n'
- '_outputs = env.Command(%s,\n'
- ' %s,\n'
- ' GYPCopy(\'$TARGET\', \'$SOURCE\'))\n')
- for f in copy['files']:
- # Remove trailing separators so basename() acts like Unix basename and
- # always returns the last element, whether a file or dir. Without this,
- # only the contents, not the directory itself, are copied (and nothing
- # might be copied if dest already exists, since scons thinks nothing needs
- # to be done).
- dest = os.path.join(destdir, os.path.basename(f.rstrip(os.sep)))
- f = FixPath(f, src_subdir_)
- dest = FixPath(dest, src_subdir_)
- fp.write(fmt % (repr(dest), repr(f)))
- fp.write('target_files.extend(_outputs)\n')
-
- run_as = spec.get('run_as')
- if run_as:
- action = run_as.get('action', [])
- working_directory = run_as.get('working_directory')
- if not working_directory:
- working_directory = gyp_dir
- else:
- if not os.path.isabs(working_directory):
- working_directory = os.path.normpath(os.path.join(gyp_dir,
- working_directory))
- if run_as.get('environment'):
- for (key, val) in run_as.get('environment').iteritems():
- action = ['%s="%s"' % (key, val)] + action
- action = ['cd', '"%s"' % working_directory, '&&'] + action
- fp.write(_run_as_template % {
- 'action' : pprint.pformat(action),
- 'message' : run_as.get('message', ''),
- })
-
- fmt = "\ngyp_target = env.Alias('%s', target_files)\n"
- fp.write(fmt % target_name)
-
- dependencies = spec.get('scons_dependencies', [])
- if dependencies:
- WriteList(fp, dependencies, preamble='dependencies = [\n ',
- postamble='\n]\n')
- fp.write('env.Requires(target_files, dependencies)\n')
- fp.write('env.Requires(gyp_target, dependencies)\n')
- fp.write('for prerequisite in prerequisites:\n')
- fp.write(' env.Requires(prerequisite, dependencies)\n')
- fp.write('env.Requires(gyp_target, prerequisites)\n')
-
- if run_as:
- fp.write(_run_as_template_suffix % {
- 'target_name': target_name,
- })
-
- fp.write('Return("gyp_target")\n')
-
- fp.close()
-
-
-#############################################################################
-# TEMPLATE BEGIN
-
-_wrapper_template = """\
-
-__doc__ = '''
-Wrapper configuration for building this entire "solution,"
-including all the specific targets in various *.scons files.
-'''
-
-import os
-import sys
-
-import SCons.Environment
-import SCons.Util
-
-def GetProcessorCount():
- '''
- Detects the number of CPUs on the system. Adapted form:
- http://codeliberates.blogspot.com/2008/05/detecting-cpuscores-in-python.html
- '''
- # Linux, Unix and Mac OS X:
- if hasattr(os, 'sysconf'):
- if os.sysconf_names.has_key('SC_NPROCESSORS_ONLN'):
- # Linux and Unix or Mac OS X with python >= 2.5:
- return os.sysconf('SC_NPROCESSORS_ONLN')
- else: # Mac OS X with Python < 2.5:
- return int(os.popen2("sysctl -n hw.ncpu")[1].read())
- # Windows:
- if os.environ.has_key('NUMBER_OF_PROCESSORS'):
- return max(int(os.environ.get('NUMBER_OF_PROCESSORS', '1')), 1)
- return 1 # Default
-
-# Support PROGRESS= to show progress in different ways.
-p = ARGUMENTS.get('PROGRESS')
-if p == 'spinner':
- Progress(['/\\r', '|\\r', '\\\\\\r', '-\\r'],
- interval=5,
- file=open('/dev/tty', 'w'))
-elif p == 'name':
- Progress('$TARGET\\r', overwrite=True, file=open('/dev/tty', 'w'))
-
-# Set the default -j value based on the number of processors.
-SetOption('num_jobs', GetProcessorCount() + 1)
-
-# Have SCons use its cached dependency information.
-SetOption('implicit_cache', 1)
-
-# Only re-calculate MD5 checksums if a timestamp has changed.
-Decider('MD5-timestamp')
-
-# Since we set the -j value by default, suppress SCons warnings about being
-# unable to support parallel build on versions of Python with no threading.
-default_warnings = ['no-no-parallel-support']
-SetOption('warn', default_warnings + GetOption('warn'))
-
-AddOption('--mode', nargs=1, dest='conf_list', default=[],
- action='append', help='Configuration to build.')
-
-AddOption('--verbose', dest='verbose', default=False,
- action='store_true', help='Verbose command-line output.')
-
-
-#
-sconscript_file_map = %(sconscript_files)s
-
-class LoadTarget:
- '''
- Class for deciding if a given target sconscript is to be included
- based on a list of included target names, optionally prefixed with '-'
- to exclude a target name.
- '''
- def __init__(self, load):
- '''
- Initialize a class with a list of names for possible loading.
-
- Arguments:
- load: list of elements in the LOAD= specification
- '''
- self.included = set([c for c in load if not c.startswith('-')])
- self.excluded = set([c[1:] for c in load if c.startswith('-')])
-
- if not self.included:
- self.included = set(['all'])
-
- def __call__(self, target):
- '''
- Returns True if the specified target's sconscript file should be
- loaded, based on the initialized included and excluded lists.
- '''
- return (target in self.included or
- ('all' in self.included and not target in self.excluded))
-
-if 'LOAD' in ARGUMENTS:
- load = ARGUMENTS['LOAD'].split(',')
-else:
- load = []
-load_target = LoadTarget(load)
-
-sconscript_files = []
-for target, sconscript in sconscript_file_map.iteritems():
- if load_target(target):
- sconscript_files.append(sconscript)
-
-
-target_alias_list= []
-
-conf_list = GetOption('conf_list')
-if conf_list:
- # In case the same --mode= value was specified multiple times.
- conf_list = list(set(conf_list))
-else:
- conf_list = [%(default_configuration)r]
-
-sconsbuild_dir = Dir(%(sconsbuild_dir)s)
-
-
-def FilterOut(self, **kw):
- kw = SCons.Environment.copy_non_reserved_keywords(kw)
- for key, val in kw.items():
- envval = self.get(key, None)
- if envval is None:
- # No existing variable in the environment, so nothing to delete.
- continue
-
- for vremove in val:
- # Use while not if, so we can handle duplicates.
- while vremove in envval:
- envval.remove(vremove)
-
- self[key] = envval
-
- # TODO(sgk): SCons.Environment.Append() has much more logic to deal
- # with various types of values. We should handle all those cases in here
- # too. (If variable is a dict, etc.)
-
-
-non_compilable_suffixes = {
- 'LINUX' : set([
- '.bdic',
- '.css',
- '.dat',
- '.fragment',
- '.gperf',
- '.h',
- '.hh',
- '.hpp',
- '.html',
- '.hxx',
- '.idl',
- '.in',
- '.in0',
- '.in1',
- '.js',
- '.mk',
- '.rc',
- '.sigs',
- '',
- ]),
- 'WINDOWS' : set([
- '.h',
- '.hh',
- '.hpp',
- '.dat',
- '.idl',
- '.in',
- '.in0',
- '.in1',
- ]),
-}
-
-def compilable(env, file):
- base, ext = os.path.splitext(str(file))
- if ext in non_compilable_suffixes[env['TARGET_PLATFORM']]:
- return False
- return True
-
-def compilable_files(env, sources):
- return [x for x in sources if compilable(env, x)]
-
-def GypProgram(env, target, source, *args, **kw):
- source = compilable_files(env, source)
- result = env.Program(target, source, *args, **kw)
- if env.get('INCREMENTAL'):
- env.Precious(result)
- return result
-
-def GypTestProgram(env, target, source, *args, **kw):
- source = compilable_files(env, source)
- result = env.Program(target, source, *args, **kw)
- if env.get('INCREMENTAL'):
- env.Precious(*result)
- return result
-
-def GypLibrary(env, target, source, *args, **kw):
- source = compilable_files(env, source)
- result = env.Library(target, source, *args, **kw)
- return result
-
-def GypLoadableModule(env, target, source, *args, **kw):
- source = compilable_files(env, source)
- result = env.LoadableModule(target, source, *args, **kw)
- return result
-
-def GypStaticLibrary(env, target, source, *args, **kw):
- source = compilable_files(env, source)
- result = env.StaticLibrary(target, source, *args, **kw)
- return result
-
-def GypSharedLibrary(env, target, source, *args, **kw):
- source = compilable_files(env, source)
- result = env.SharedLibrary(target, source, *args, **kw)
- if env.get('INCREMENTAL'):
- env.Precious(result)
- return result
-
-def add_gyp_methods(env):
- env.AddMethod(GypProgram)
- env.AddMethod(GypTestProgram)
- env.AddMethod(GypLibrary)
- env.AddMethod(GypLoadableModule)
- env.AddMethod(GypStaticLibrary)
- env.AddMethod(GypSharedLibrary)
-
- env.AddMethod(FilterOut)
-
- env.AddMethod(compilable)
-
-
-base_env = Environment(
- tools = %(scons_tools)s,
- INTERMEDIATE_DIR='$OBJ_DIR/${COMPONENT_NAME}/_${TARGET_NAME}_intermediate',
- LIB_DIR='$TOP_BUILDDIR/lib',
- OBJ_DIR='$TOP_BUILDDIR/obj',
- SCONSBUILD_DIR=sconsbuild_dir.abspath,
- SHARED_INTERMEDIATE_DIR='$OBJ_DIR/_global_intermediate',
- SRC_DIR=Dir(%(src_dir)r),
- TARGET_PLATFORM='LINUX',
- TOP_BUILDDIR='$SCONSBUILD_DIR/$CONFIG_NAME',
- LIBPATH=['$LIB_DIR'],
-)
-
-if not GetOption('verbose'):
- base_env.SetDefault(
- ARCOMSTR='Creating library $TARGET',
- ASCOMSTR='Assembling $TARGET',
- CCCOMSTR='Compiling $TARGET',
- CONCATSOURCECOMSTR='ConcatSource $TARGET',
- CXXCOMSTR='Compiling $TARGET',
- LDMODULECOMSTR='Building loadable module $TARGET',
- LINKCOMSTR='Linking $TARGET',
- MANIFESTCOMSTR='Updating manifest for $TARGET',
- MIDLCOMSTR='Compiling IDL $TARGET',
- PCHCOMSTR='Precompiling $TARGET',
- RANLIBCOMSTR='Indexing $TARGET',
- RCCOMSTR='Compiling resource $TARGET',
- SHCCCOMSTR='Compiling $TARGET',
- SHCXXCOMSTR='Compiling $TARGET',
- SHLINKCOMSTR='Linking $TARGET',
- SHMANIFESTCOMSTR='Updating manifest for $TARGET',
- )
-
-add_gyp_methods(base_env)
-
-for conf in conf_list:
- env = base_env.Clone(CONFIG_NAME=conf)
- SConsignFile(env.File('$TOP_BUILDDIR/.sconsign').abspath)
- for sconscript in sconscript_files:
- target_alias = env.SConscript(sconscript, exports=['env'])
- if target_alias:
- target_alias_list.extend(target_alias)
-
-Default(Alias('all', target_alias_list))
-
-help_fmt = '''
-Usage: hammer [SCONS_OPTIONS] [VARIABLES] [TARGET] ...
-
-Local command-line build options:
- --mode=CONFIG Configuration to build:
- --mode=Debug [default]
- --mode=Release
- --verbose Print actual executed command lines.
-
-Supported command-line build variables:
- LOAD=[module,...] Comma-separated list of components to load in the
- dependency graph ('-' prefix excludes)
- PROGRESS=type Display a progress indicator:
- name: print each evaluated target name
- spinner: print a spinner every 5 targets
-
-The following TARGET names can also be used as LOAD= module names:
-
-%%s
-'''
-
-if GetOption('help'):
- def columnar_text(items, width=78, indent=2, sep=2):
- result = []
- colwidth = max(map(len, items)) + sep
- cols = (width - indent) / colwidth
- if cols < 1:
- cols = 1
- rows = (len(items) + cols - 1) / cols
- indent = '%%*s' %% (indent, '')
- sep = indent
- for row in xrange(0, rows):
- result.append(sep)
- for i in xrange(row, len(items), rows):
- result.append('%%-*s' %% (colwidth, items[i]))
- sep = '\\n' + indent
- result.append('\\n')
- return ''.join(result)
-
- load_list = set(sconscript_file_map.keys())
- target_aliases = set(map(str, target_alias_list))
-
- common = load_list and target_aliases
- load_only = load_list - common
- target_only = target_aliases - common
- help_text = [help_fmt %% columnar_text(sorted(list(common)))]
- if target_only:
- fmt = "The following are additional TARGET names:\\n\\n%%s\\n"
- help_text.append(fmt %% columnar_text(sorted(list(target_only))))
- if load_only:
- fmt = "The following are additional LOAD= module names:\\n\\n%%s\\n"
- help_text.append(fmt %% columnar_text(sorted(list(load_only))))
- Help(''.join(help_text))
-"""
-
-# TEMPLATE END
-#############################################################################
-
-
-def GenerateSConscriptWrapper(build_file, build_file_data, name,
- output_filename, sconscript_files,
- default_configuration):
- """
- Generates the "wrapper" SConscript file (analogous to the Visual Studio
- solution) that calls all the individual target SConscript files.
- """
- output_dir = os.path.dirname(output_filename)
- src_dir = build_file_data['_DEPTH']
- src_dir_rel = gyp.common.RelativePath(src_dir, output_dir)
- if not src_dir_rel:
- src_dir_rel = '.'
- scons_settings = build_file_data.get('scons_settings', {})
- sconsbuild_dir = scons_settings.get('sconsbuild_dir', '#')
- scons_tools = scons_settings.get('tools', ['default'])
-
- sconscript_file_lines = ['dict(']
- for target in sorted(sconscript_files.keys()):
- sconscript = sconscript_files[target]
- sconscript_file_lines.append(' %s = %r,' % (target, sconscript))
- sconscript_file_lines.append(')')
-
- fp = open(output_filename, 'w')
- fp.write(header)
- fp.write(_wrapper_template % {
- 'default_configuration' : default_configuration,
- 'name' : name,
- 'scons_tools' : repr(scons_tools),
- 'sconsbuild_dir' : repr(sconsbuild_dir),
- 'sconscript_files' : '\n'.join(sconscript_file_lines),
- 'src_dir' : src_dir_rel,
- })
- fp.close()
-
- # Generate the SConstruct file that invokes the wrapper SConscript.
- dir, fname = os.path.split(output_filename)
- SConstruct = os.path.join(dir, 'SConstruct')
- fp = open(SConstruct, 'w')
- fp.write(header)
- fp.write('SConscript(%s)\n' % repr(fname))
- fp.close()
-
-
-def TargetFilename(target, build_file=None, output_suffix=''):
- """Returns the .scons file name for the specified target.
- """
- if build_file is None:
- build_file, target = gyp.common.ParseQualifiedTarget(target)[:2]
- output_file = os.path.join(os.path.dirname(build_file),
- target + output_suffix + '.scons')
- return output_file
-
-
-def PerformBuild(data, configurations, params):
- options = params['options']
-
- # Due to the way we test gyp on the chromium typbots
- # we need to look for 'scons.py' as well as the more common 'scons'
- # TODO(sbc): update the trybots to have a more normal install
- # of scons.
- scons = 'scons'
- paths = os.environ['PATH'].split(os.pathsep)
- for scons_name in ['scons', 'scons.py']:
- for path in paths:
- test_scons = os.path.join(path, scons_name)
- print 'looking for: %s' % test_scons
- if os.path.exists(test_scons):
- print "found scons: %s" % scons
- scons = test_scons
- break
-
- for config in configurations:
- arguments = [scons, '-C', options.toplevel_dir, '--mode=%s' % config]
- print "Building [%s]: %s" % (config, arguments)
- subprocess.check_call(arguments)
-
-
-def GenerateOutput(target_list, target_dicts, data, params):
- """
- Generates all the output files for the specified targets.
- """
- options = params['options']
-
- if options.generator_output:
- def output_path(filename):
- return filename.replace(params['cwd'], options.generator_output)
- else:
- def output_path(filename):
- return filename
-
- default_configuration = None
-
- for qualified_target in target_list:
- spec = target_dicts[qualified_target]
- if spec['toolset'] != 'target':
- raise Exception(
- 'Multiple toolsets not supported in scons build (target %s)' %
- qualified_target)
- scons_target = SCons.Target(spec)
- if scons_target.is_ignored:
- continue
-
- # TODO: assumes the default_configuration of the first target
- # non-Default target is the correct default for all targets.
- # Need a better model for handle variation between targets.
- if (not default_configuration and
- spec['default_configuration'] != 'Default'):
- default_configuration = spec['default_configuration']
-
- build_file, target = gyp.common.ParseQualifiedTarget(qualified_target)[:2]
- output_file = TargetFilename(target, build_file, options.suffix)
- if options.generator_output:
- output_file = output_path(output_file)
-
- if not spec.has_key('libraries'):
- spec['libraries'] = []
-
- # Add dependent static library targets to the 'libraries' value.
- deps = spec.get('dependencies', [])
- spec['scons_dependencies'] = []
- for d in deps:
- td = target_dicts[d]
- target_name = td['target_name']
- spec['scons_dependencies'].append("Alias('%s')" % target_name)
- if td['type'] in ('static_library', 'shared_library'):
- libname = td.get('product_name', target_name)
- spec['libraries'].append('lib' + libname)
- if td['type'] == 'loadable_module':
- prereqs = spec.get('scons_prerequisites', [])
- # TODO: parameterize with <(SHARED_LIBRARY_*) variables?
- td_target = SCons.Target(td)
- td_target.target_prefix = '${SHLIBPREFIX}'
- td_target.target_suffix = '${SHLIBSUFFIX}'
-
- GenerateSConscript(output_file, spec, build_file, data[build_file])
-
- if not default_configuration:
- default_configuration = 'Default'
-
- for build_file in sorted(data.keys()):
- path, ext = os.path.splitext(build_file)
- if ext != '.gyp':
- continue
- output_dir, basename = os.path.split(path)
- output_filename = path + '_main' + options.suffix + '.scons'
-
- all_targets = gyp.common.AllTargets(target_list, target_dicts, build_file)
- sconscript_files = {}
- for t in all_targets:
- scons_target = SCons.Target(target_dicts[t])
- if scons_target.is_ignored:
- continue
- bf, target = gyp.common.ParseQualifiedTarget(t)[:2]
- target_filename = TargetFilename(target, bf, options.suffix)
- tpath = gyp.common.RelativePath(target_filename, output_dir)
- sconscript_files[target] = tpath
-
- output_filename = output_path(output_filename)
- if sconscript_files:
- GenerateSConscriptWrapper(build_file, data[build_file], basename,
- output_filename, sconscript_files,
- default_configuration)
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/xcode.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/xcode.py
@@ -1,15 +1,16 @@
# Copyright (c) 2012 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.
import filecmp
import gyp.common
import gyp.xcodeproj_file
+import gyp.xcode_ninja
import errno
import os
import sys
import posixpath
import re
import shutil
import subprocess
import tempfile
@@ -63,30 +64,37 @@ generator_additional_path_sections = [
'mac_framework_headers',
'mac_framework_private_headers',
# 'mac_framework_dirs', input already handles _dirs endings.
]
# The Xcode-specific keys that exist on targets and aren't moved down to
# configurations.
generator_additional_non_configuration_keys = [
+ 'ios_app_extension',
+ 'ios_watch_app',
+ 'ios_watchkit_extension',
'mac_bundle',
'mac_bundle_resources',
'mac_framework_headers',
'mac_framework_private_headers',
+ 'mac_xctest_bundle',
+ 'mac_xcuitest_bundle',
'xcode_create_dependents_test_runner',
]
# We want to let any rules apply to files that are resources also.
generator_extra_sources_for_rules = [
'mac_bundle_resources',
'mac_framework_headers',
'mac_framework_private_headers',
]
+generator_filelist_paths = None
+
# Xcode's standard set of library directories, which don't need to be duplicated
# in LIBRARY_SEARCH_PATHS. This list is not exhaustive, but that's okay.
xcode_standard_library_dirs = frozenset([
'$(SDKROOT)/usr/lib',
'$(SDKROOT)/usr/local/lib',
])
def CreateXCConfigurationList(configuration_names):
@@ -475,53 +483,20 @@ sys.exit(subprocess.call(sys.argv[1:]))"
# Don't leave turds behind. In fact, if this code was responsible for
# creating the xcodeproj directory, get rid of that too.
os.unlink(new_pbxproj_path)
if self.created_dir:
shutil.rmtree(self.path, True)
raise
-cached_xcode_version = None
-def InstalledXcodeVersion():
- """Fetches the installed version of Xcode, returns empty string if it is
- unable to figure it out."""
-
- global cached_xcode_version
- if not cached_xcode_version is None:
- return cached_xcode_version
-
- # Default to an empty string
- cached_xcode_version = ''
-
- # Collect the xcodebuild's version information.
- try:
- import subprocess
- cmd = ['/usr/bin/xcodebuild', '-version']
- proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)
- xcodebuild_version_info = proc.communicate()[0]
- # Any error, return empty string
- if proc.returncode:
- xcodebuild_version_info = ''
- except OSError:
- # We failed to launch the tool
- xcodebuild_version_info = ''
-
- # Pull out the Xcode version itself.
- match_line = re.search('^Xcode (.*)$', xcodebuild_version_info, re.MULTILINE)
- if match_line:
- cached_xcode_version = match_line.group(1)
- # Done!
- return cached_xcode_version
-
-
def AddSourceToTarget(source, type, pbxp, xct):
# TODO(mark): Perhaps source_extensions and library_extensions can be made a
# little bit fancier.
- source_extensions = ['c', 'cc', 'cpp', 'cxx', 'm', 'mm', 's']
+ source_extensions = ['c', 'cc', 'cpp', 'cxx', 'm', 'mm', 's', 'swift']
# .o is conceptually more of a "source" than a "library," but Xcode thinks
# of "sources" as things to compile and "libraries" (or "frameworks") as
# things to link with. Adding an object file to an Xcode target's frameworks
# phase works properly.
library_extensions = ['a', 'dylib', 'framework', 'o']
basename = posixpath.basename(source)
@@ -547,17 +522,17 @@ def AddResourceToTarget(resource, pbxp,
def AddHeaderToTarget(header, pbxp, xct, is_public):
# TODO(mark): Combine with AddSourceToTarget above? Or just inline this call
# where it's used.
settings = '{ATTRIBUTES = (%s, ); }' % ('Private', 'Public')[is_public]
xct.HeadersPhase().AddFile(header, settings)
-_xcode_variable_re = re.compile('(\$\((.*?)\))')
+_xcode_variable_re = re.compile(r'(\$\((.*?)\))')
def ExpandXcodeVariables(string, expansions):
"""Expands Xcode-style $(VARIABLES) in string per the expansions dict.
In some rare cases, it is appropriate to expand Xcode variables when a
project file is generated. For any substring $(VAR) in string, if VAR is a
key in the expansions dict, $(VAR) will be replaced with expansions[VAR].
Any $(VAR) substring in string for which VAR is not a key in the expansions
dict will remain in the returned string.
@@ -574,23 +549,23 @@ def ExpandXcodeVariables(string, expansi
continue
replacement = expansions[variable]
string = re.sub(re.escape(to_replace), replacement, string)
return string
-def EscapeXCodeArgument(s):
- """We must escape the arguments that we give to XCode so that it knows not to
- split on spaces and to respect backslash and quote literals."""
- s = s.replace('\\', '\\\\')
- s = s.replace('"', '\\"')
- return '"' + s + '"'
-
+_xcode_define_re = re.compile(r'([\\\"\' ])')
+def EscapeXcodeDefine(s):
+ """We must escape the defines that we give to XCode so that it knows not to
+ split on spaces and to respect backslash and quote literals. However, we
+ must not quote the define, or Xcode will incorrectly intepret variables
+ especially $(inherited)."""
+ return re.sub(_xcode_define_re, r'\\\1', s)
def PerformBuild(data, configurations, params):
options = params['options']
for build_file, build_file_dict in data.iteritems():
(build_file_root, build_file_ext) = os.path.splitext(build_file)
if build_file_ext != '.gyp':
@@ -601,42 +576,82 @@ def PerformBuild(data, configurations, p
for config in configurations:
arguments = ['xcodebuild', '-project', xcodeproj_path]
arguments += ['-configuration', config]
print "Building [%s]: %s" % (config, arguments)
subprocess.check_call(arguments)
+def CalculateGeneratorInputInfo(params):
+ toplevel = params['options'].toplevel_dir
+ if params.get('flavor') == 'ninja':
+ generator_dir = os.path.relpath(params['options'].generator_output or '.')
+ output_dir = params.get('generator_flags', {}).get('output_dir', 'out')
+ output_dir = os.path.normpath(os.path.join(generator_dir, output_dir))
+ qualified_out_dir = os.path.normpath(os.path.join(
+ toplevel, output_dir, 'gypfiles-xcode-ninja'))
+ else:
+ output_dir = os.path.normpath(os.path.join(toplevel, 'xcodebuild'))
+ qualified_out_dir = os.path.normpath(os.path.join(
+ toplevel, output_dir, 'gypfiles'))
+
+ global generator_filelist_paths
+ generator_filelist_paths = {
+ 'toplevel': toplevel,
+ 'qualified_out_dir': qualified_out_dir,
+ }
+
+
def GenerateOutput(target_list, target_dicts, data, params):
+ # Optionally configure each spec to use ninja as the external builder.
+ ninja_wrapper = params.get('flavor') == 'ninja'
+ if ninja_wrapper:
+ (target_list, target_dicts, data) = \
+ gyp.xcode_ninja.CreateWrapper(target_list, target_dicts, data, params)
+
options = params['options']
generator_flags = params.get('generator_flags', {})
parallel_builds = generator_flags.get('xcode_parallel_builds', True)
serialize_all_tests = \
generator_flags.get('xcode_serialize_all_test_runs', True)
- project_version = generator_flags.get('xcode_project_version', None)
+ upgrade_check_project_version = \
+ generator_flags.get('xcode_upgrade_check_project_version', None)
+
+ # Format upgrade_check_project_version with leading zeros as needed.
+ if upgrade_check_project_version:
+ upgrade_check_project_version = str(upgrade_check_project_version)
+ while len(upgrade_check_project_version) < 4:
+ upgrade_check_project_version = '0' + upgrade_check_project_version
+
skip_excluded_files = \
not generator_flags.get('xcode_list_excluded_files', True)
xcode_projects = {}
for build_file, build_file_dict in data.iteritems():
(build_file_root, build_file_ext) = os.path.splitext(build_file)
if build_file_ext != '.gyp':
continue
xcodeproj_path = build_file_root + options.suffix + '.xcodeproj'
if options.generator_output:
xcodeproj_path = os.path.join(options.generator_output, xcodeproj_path)
xcp = XcodeProject(build_file, xcodeproj_path, build_file_dict)
xcode_projects[build_file] = xcp
pbxp = xcp.project
+ # Set project-level attributes from multiple options
+ project_attributes = {};
if parallel_builds:
- pbxp.SetProperty('attributes',
- {'BuildIndependentTargetsInParallel': 'YES'})
- if project_version:
- xcp.project_file.SetXcodeVersion(project_version)
+ project_attributes['BuildIndependentTargetsInParallel'] = 'YES'
+ if upgrade_check_project_version:
+ project_attributes['LastUpgradeCheck'] = upgrade_check_project_version
+ project_attributes['LastTestingUpgradeCheck'] = \
+ upgrade_check_project_version
+ project_attributes['LastSwiftUpdateCheck'] = \
+ upgrade_check_project_version
+ pbxp.SetProperty('attributes', project_attributes)
# Add gyp/gypi files to project
if not generator_flags.get('standalone'):
main_group = pbxp.GetProperty('mainGroup')
build_group = gyp.xcodeproj_file.PBXGroup({'name': 'Build'})
main_group.AppendChild(build_group)
for included_file in build_file_dict['included_files']:
build_group.AddOrGetFileByPath(included_file, False)
@@ -664,48 +679,91 @@ def GenerateOutput(target_list, target_d
xccl = CreateXCConfigurationList(configuration_names)
# Create an XCTarget subclass object for the target. The type with
# "+bundle" appended will be used if the target has "mac_bundle" set.
# loadable_modules not in a mac_bundle are mapped to
# com.googlecode.gyp.xcode.bundle, a pseudo-type that xcode.py interprets
# to create a single-file mh_bundle.
_types = {
- 'executable': 'com.apple.product-type.tool',
- 'loadable_module': 'com.googlecode.gyp.xcode.bundle',
- 'shared_library': 'com.apple.product-type.library.dynamic',
- 'static_library': 'com.apple.product-type.library.static',
- 'executable+bundle': 'com.apple.product-type.application',
- 'loadable_module+bundle': 'com.apple.product-type.bundle',
- 'shared_library+bundle': 'com.apple.product-type.framework',
+ 'executable': 'com.apple.product-type.tool',
+ 'loadable_module': 'com.googlecode.gyp.xcode.bundle',
+ 'shared_library': 'com.apple.product-type.library.dynamic',
+ 'static_library': 'com.apple.product-type.library.static',
+ 'mac_kernel_extension': 'com.apple.product-type.kernel-extension',
+ 'executable+bundle': 'com.apple.product-type.application',
+ 'loadable_module+bundle': 'com.apple.product-type.bundle',
+ 'loadable_module+xctest': 'com.apple.product-type.bundle.unit-test',
+ 'loadable_module+xcuitest': 'com.apple.product-type.bundle.ui-testing',
+ 'shared_library+bundle': 'com.apple.product-type.framework',
+ 'executable+extension+bundle': 'com.apple.product-type.app-extension',
+ 'executable+watch+extension+bundle':
+ 'com.apple.product-type.watchkit-extension',
+ 'executable+watch+bundle':
+ 'com.apple.product-type.application.watchapp',
+ 'mac_kernel_extension+bundle': 'com.apple.product-type.kernel-extension',
}
target_properties = {
'buildConfigurationList': xccl,
'name': target_name,
}
type = spec['type']
- is_bundle = int(spec.get('mac_bundle', 0))
+ is_xctest = int(spec.get('mac_xctest_bundle', 0))
+ is_xcuitest = int(spec.get('mac_xcuitest_bundle', 0))
+ is_bundle = int(spec.get('mac_bundle', 0)) or is_xctest
+ is_app_extension = int(spec.get('ios_app_extension', 0))
+ is_watchkit_extension = int(spec.get('ios_watchkit_extension', 0))
+ is_watch_app = int(spec.get('ios_watch_app', 0))
if type != 'none':
type_bundle_key = type
- if is_bundle:
+ if is_xcuitest:
+ type_bundle_key += '+xcuitest'
+ assert type == 'loadable_module', (
+ 'mac_xcuitest_bundle targets must have type loadable_module '
+ '(target %s)' % target_name)
+ elif is_xctest:
+ type_bundle_key += '+xctest'
+ assert type == 'loadable_module', (
+ 'mac_xctest_bundle targets must have type loadable_module '
+ '(target %s)' % target_name)
+ elif is_app_extension:
+ assert is_bundle, ('ios_app_extension flag requires mac_bundle '
+ '(target %s)' % target_name)
+ type_bundle_key += '+extension+bundle'
+ elif is_watchkit_extension:
+ assert is_bundle, ('ios_watchkit_extension flag requires mac_bundle '
+ '(target %s)' % target_name)
+ type_bundle_key += '+watch+extension+bundle'
+ elif is_watch_app:
+ assert is_bundle, ('ios_watch_app flag requires mac_bundle '
+ '(target %s)' % target_name)
+ type_bundle_key += '+watch+bundle'
+ elif is_bundle:
type_bundle_key += '+bundle'
+
xctarget_type = gyp.xcodeproj_file.PBXNativeTarget
try:
target_properties['productType'] = _types[type_bundle_key]
except KeyError, e:
gyp.common.ExceptionAppend(e, "-- unknown product type while "
"writing target %s" % target_name)
raise
else:
xctarget_type = gyp.xcodeproj_file.PBXAggregateTarget
assert not is_bundle, (
'mac_bundle targets cannot have type none (target "%s")' %
target_name)
+ assert not is_xcuitest, (
+ 'mac_xcuitest_bundle targets cannot have type none (target "%s")' %
+ target_name)
+ assert not is_xctest, (
+ 'mac_xctest_bundle targets cannot have type none (target "%s")' %
+ target_name)
target_product_name = spec.get('product_name')
if target_product_name is not None:
target_properties['productName'] = target_product_name
xct = xctarget_type(target_properties, parent=pbxp,
force_outdir=spec.get('product_dir'),
force_prefix=spec.get('product_prefix'),
@@ -719,21 +777,26 @@ def GenerateOutput(target_list, target_d
# Xcode has some "issues" with checking dependencies for the "Compile
# sources" step with any source files/headers generated by actions/rules.
# To work around this, if a target is building anything directly (not
# type "none"), then a second target is used to run the GYP actions/rules
# and is made a dependency of this target. This way the work is done
# before the dependency checks for what should be recompiled.
support_xct = None
- if type != 'none' and (spec_actions or spec_rules):
+ # The Xcode "issues" don't affect xcode-ninja builds, since the dependency
+ # logic all happens in ninja. Don't bother creating the extra targets in
+ # that case.
+ if type != 'none' and (spec_actions or spec_rules) and not ninja_wrapper:
support_xccl = CreateXCConfigurationList(configuration_names);
+ support_target_suffix = generator_flags.get(
+ 'support_target_suffix', ' Support')
support_target_properties = {
'buildConfigurationList': support_xccl,
- 'name': target_name + ' Support',
+ 'name': target_name + support_target_suffix,
}
if target_product_name:
support_target_properties['productName'] = \
target_product_name + ' Support'
support_xct = \
gyp.xcodeproj_file.PBXAggregateTarget(support_target_properties,
parent=pbxp)
pbxp.AppendProperty('targets', support_xct)
@@ -1048,17 +1111,17 @@ def GenerateOutput(target_list, target_d
# would be ncpus^2 things going. With a machine that has 2 quad-core
# Xeons, a build can quickly run out of processes based on
# scheduling/other tasks, and randomly failing builds are no good.
script = \
"""JOB_COUNT="$(/usr/sbin/sysctl -n hw.ncpu)"
if [ "${JOB_COUNT}" -gt 4 ]; then
JOB_COUNT=4
fi
-exec "${DEVELOPER_BIN_DIR}/make" -f "${PROJECT_FILE_PATH}/%s" -j "${JOB_COUNT}"
+exec xcrun make -f "${PROJECT_FILE_PATH}/%s" -j "${JOB_COUNT}"
exit 1
""" % makefile_name
ssbp = gyp.xcodeproj_file.PBXShellScriptBuildPhase({
'name': 'Rule "' + rule['rule_name'] + '"',
'shellScript': script,
'showEnvVarsInLog': 0,
})
@@ -1105,33 +1168,45 @@ exit 1
# Add "mac_framework_headers". These can be valid for both frameworks
# and static libraries.
if is_bundle or type == 'static_library':
for header in spec.get('mac_framework_headers', []):
AddHeaderToTarget(header, pbxp, xct, True)
# Add "copies".
+ pbxcp_dict = {}
for copy_group in spec.get('copies', []):
- pbxcp = gyp.xcodeproj_file.PBXCopyFilesBuildPhase({
- 'name': 'Copy to ' + copy_group['destination']
- },
- parent=xct)
dest = copy_group['destination']
if dest[0] not in ('/', '$'):
# Relative paths are relative to $(SRCROOT).
dest = '$(SRCROOT)/' + dest
- pbxcp.SetDestination(dest)
+
+ code_sign = int(copy_group.get('xcode_code_sign', 0))
+ settings = (None, '{ATTRIBUTES = (CodeSignOnCopy, ); }')[code_sign];
- # TODO(mark): The usual comment about this knowing too much about
- # gyp.xcodeproj_file internals applies.
- xct._properties['buildPhases'].insert(prebuild_index, pbxcp)
+ # Coalesce multiple "copies" sections in the same target with the same
+ # "destination" property into the same PBXCopyFilesBuildPhase, otherwise
+ # they'll wind up with ID collisions.
+ pbxcp = pbxcp_dict.get(dest, None)
+ if pbxcp is None:
+ pbxcp = gyp.xcodeproj_file.PBXCopyFilesBuildPhase({
+ 'name': 'Copy to ' + copy_group['destination']
+ },
+ parent=xct)
+ pbxcp.SetDestination(dest)
+
+ # TODO(mark): The usual comment about this knowing too much about
+ # gyp.xcodeproj_file internals applies.
+ xct._properties['buildPhases'].insert(prebuild_index, pbxcp)
+
+ pbxcp_dict[dest] = pbxcp
for file in copy_group['files']:
- pbxcp.AddFile(file)
+ pbxcp.AddFile(file, settings)
# Excluded files can also go into the project file.
if not skip_excluded_files:
for key in ['sources', 'mac_bundle_resources', 'mac_framework_headers',
'mac_framework_private_headers']:
excluded_key = key + '_excluded'
for item in spec.get(excluded_key, []):
pbxp.AddOrGetFileInRootGroup(item)
@@ -1197,19 +1272,25 @@ exit 1
for configuration_name in configuration_names:
configuration = spec['configurations'][configuration_name]
xcbc = xct.ConfigurationNamed(configuration_name)
for include_dir in configuration.get('mac_framework_dirs', []):
xcbc.AppendBuildSetting('FRAMEWORK_SEARCH_PATHS', include_dir)
for include_dir in configuration.get('include_dirs', []):
xcbc.AppendBuildSetting('HEADER_SEARCH_PATHS', include_dir)
+ for library_dir in configuration.get('library_dirs', []):
+ if library_dir not in xcode_standard_library_dirs and (
+ not xcbc.HasBuildSetting(_library_search_paths_var) or
+ library_dir not in xcbc.GetBuildSetting(_library_search_paths_var)):
+ xcbc.AppendBuildSetting(_library_search_paths_var, library_dir)
+
if 'defines' in configuration:
for define in configuration['defines']:
- set_define = EscapeXCodeArgument(define)
+ set_define = EscapeXcodeDefine(define)
xcbc.AppendBuildSetting('GCC_PREPROCESSOR_DEFINITIONS', set_define)
if 'xcode_settings' in configuration:
for xck, xcv in configuration['xcode_settings'].iteritems():
xcbc.SetBuildSetting(xck, xcv)
if 'xcode_config_file' in configuration:
config_ref = pbxp.AddOrGetFileInRootGroup(
configuration['xcode_config_file'])
xcbc.SetBaseConfiguration(config_ref)
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/xcode_test.py
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 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.
+
+""" Unit tests for the xcode.py file. """
+
+import gyp.generator.xcode as xcode
+import unittest
+import sys
+
+
+class TestEscapeXcodeDefine(unittest.TestCase):
+ if sys.platform == 'darwin':
+ def test_InheritedRemainsUnescaped(self):
+ self.assertEqual(xcode.EscapeXcodeDefine('$(inherited)'), '$(inherited)')
+
+ def test_Escaping(self):
+ self.assertEqual(xcode.EscapeXcodeDefine('a b"c\\'), 'a\\ b\\"c\\\\')
+
+if __name__ == '__main__':
+ unittest.main()
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/input.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/input.py
@@ -5,33 +5,41 @@
from compiler.ast import Const
from compiler.ast import Dict
from compiler.ast import Discard
from compiler.ast import List
from compiler.ast import Module
from compiler.ast import Node
from compiler.ast import Stmt
import compiler
-import copy
import gyp.common
+import gyp.simple_copy
import multiprocessing
import optparse
import os.path
import re
import shlex
import signal
import subprocess
import sys
import threading
import time
+import traceback
from gyp.common import GypError
+from gyp.common import OrderedSet
# A list of types that are treated as linkable.
-linkable_types = ['executable', 'shared_library', 'loadable_module']
+linkable_types = [
+ 'executable',
+ 'shared_library',
+ 'loadable_module',
+ 'mac_kernel_extension',
+ 'windows_driver',
+]
# A list of sections that contain links to other targets.
dependency_sections = ['dependencies', 'export_dependent_settings']
# base_path_sections is a list of sections defined by GYP that contain
# pathnames. The generators can provide more keys, the two lists are merged
# into path_sections, but you should call IsPathSection instead of using either
# list directly.
@@ -39,63 +47,74 @@ base_path_sections = [
'destination',
'files',
'include_dirs',
'inputs',
'libraries',
'outputs',
'sources',
]
-path_sections = []
-
+path_sections = set()
+
+# These per-process dictionaries are used to cache build file data when loading
+# in parallel mode.
+per_process_data = {}
+per_process_aux_data = {}
def IsPathSection(section):
- # If section ends in one of these characters, it's applied to a section
+ # If section ends in one of the '=+?!' characters, it's applied to a section
# without the trailing characters. '/' is notably absent from this list,
# because there's no way for a regular expression to be treated as a path.
- while section[-1:] in ('=', '+', '?', '!'):
- section = section[0:-1]
-
- if section in path_sections or \
- section.endswith('_dir') or section.endswith('_dirs') or \
- section.endswith('_file') or section.endswith('_files') or \
- section.endswith('_path') or section.endswith('_paths'):
+ while section and section[-1:] in '=+?!':
+ section = section[:-1]
+
+ if section in path_sections:
return True
+
+ # Sections mathing the regexp '_(dir|file|path)s?$' are also
+ # considered PathSections. Using manual string matching since that
+ # is much faster than the regexp and this can be called hundreds of
+ # thousands of times so micro performance matters.
+ if "_" in section:
+ tail = section[-6:]
+ if tail[-1] == 's':
+ tail = tail[:-1]
+ if tail[-5:] in ('_file', '_path'):
+ return True
+ return tail[-4:] == '_dir'
+
return False
-
-# base_non_configuraiton_keys is a list of key names that belong in the target
+# base_non_configuration_keys is a list of key names that belong in the target
# itself and should not be propagated into its configurations. It is merged
# with a list that can come from the generator to
# create non_configuration_keys.
base_non_configuration_keys = [
# Sections that must exist inside targets and not configurations.
'actions',
'configurations',
'copies',
'default_configuration',
'dependencies',
'dependencies_original',
- 'link_languages',
'libraries',
'postbuilds',
'product_dir',
'product_extension',
'product_name',
'product_prefix',
'rules',
'run_as',
'sources',
'standalone_static_library',
'suppress_wildcard',
'target_name',
'toolset',
'toolsets',
'type',
- 'variants',
# Sections that can be found inside targets or configurations, but that
# should not be propagated from targets into their configurations.
'variables',
]
non_configuration_keys = []
# Keys that do not belong inside a configuration dictionary.
@@ -108,22 +127,24 @@ invalid_configuration_keys = [
'libraries',
'link_settings',
'sources',
'standalone_static_library',
'target_name',
'type',
]
-# Controls how the generator want the build file paths.
-absolute_build_file_paths = False
-
# Controls whether or not the generator supports multiple toolsets.
multiple_toolsets = False
+# Paths for converting filelist paths to output paths: {
+# toplevel,
+# qualified_output_dir,
+# }
+generator_filelist_paths = None
def GetIncludedBuildFiles(build_file_path, aux_data, included=None):
"""Return a list of all build files included into build_file_path.
The returned list will contain build_file_path as well as all other files
that it included, either directly or indirectly. Note that the list may
contain files that were included into a conditional section that evaluated
to false and was not merged into build_file_path's dict.
@@ -195,21 +216,21 @@ def CheckNode(node, keypath):
for index, child in enumerate(c):
kp = list(keypath) # Copy list.
kp.append(repr(index))
children.append(CheckNode(child, kp))
return children
elif isinstance(node, Const):
return node.getChildren()[0]
else:
- raise TypeError, "Unknown AST node at key path '" + '.'.join(keypath) + \
- "': " + repr(node)
-
-
-def LoadOneBuildFile(build_file_path, data, aux_data, variables, includes,
+ raise TypeError("Unknown AST node at key path '" + '.'.join(keypath) +
+ "': " + repr(node))
+
+
+def LoadOneBuildFile(build_file_path, data, aux_data, includes,
is_target, check):
if build_file_path in data:
return data[build_file_path]
if os.path.exists(build_file_path):
build_file_contents = open(build_file_path).read()
else:
raise GypError("%s not found (cwd: %s)" % (build_file_path, os.getcwd()))
@@ -223,37 +244,42 @@ def LoadOneBuildFile(build_file_path, da
None)
except SyntaxError, e:
e.filename = build_file_path
raise
except Exception, e:
gyp.common.ExceptionAppend(e, 'while reading ' + build_file_path)
raise
+ if type(build_file_data) is not dict:
+ raise GypError("%s does not evaluate to a dictionary." % build_file_path)
+
data[build_file_path] = build_file_data
aux_data[build_file_path] = {}
# Scan for includes and merge them in.
- try:
- if is_target:
- LoadBuildFileIncludesIntoDict(build_file_data, build_file_path, data,
- aux_data, variables, includes, check)
- else:
- LoadBuildFileIncludesIntoDict(build_file_data, build_file_path, data,
- aux_data, variables, None, check)
- except Exception, e:
- gyp.common.ExceptionAppend(e,
- 'while reading includes of ' + build_file_path)
- raise
+ if ('skip_includes' not in build_file_data or
+ not build_file_data['skip_includes']):
+ try:
+ if is_target:
+ LoadBuildFileIncludesIntoDict(build_file_data, build_file_path, data,
+ aux_data, includes, check)
+ else:
+ LoadBuildFileIncludesIntoDict(build_file_data, build_file_path, data,
+ aux_data, None, check)
+ except Exception, e:
+ gyp.common.ExceptionAppend(e,
+ 'while reading includes of ' + build_file_path)
+ raise
return build_file_data
def LoadBuildFileIncludesIntoDict(subdict, subdict_path, data, aux_data,
- variables, includes, check):
+ includes, check):
includes_list = []
if includes != None:
includes_list.extend(includes)
if 'includes' in subdict:
for include in subdict['includes']:
# "include" is specified relative to subdict_path, so compute the real
# path to include by appending the provided "include" to the directory
# in which subdict_path resides.
@@ -264,43 +290,40 @@ def LoadBuildFileIncludesIntoDict(subdic
del subdict['includes']
# Merge in the included files.
for include in includes_list:
if not 'included' in aux_data[subdict_path]:
aux_data[subdict_path]['included'] = []
aux_data[subdict_path]['included'].append(include)
- gyp.DebugOutput(gyp.DEBUG_INCLUDES, "Loading Included File: '%s'" % include)
+ gyp.DebugOutput(gyp.DEBUG_INCLUDES, "Loading Included File: '%s'", include)
MergeDicts(subdict,
- LoadOneBuildFile(include, data, aux_data, variables, None,
- False, check),
+ LoadOneBuildFile(include, data, aux_data, None, False, check),
subdict_path, include)
# Recurse into subdictionaries.
for k, v in subdict.iteritems():
- if v.__class__ == dict:
- LoadBuildFileIncludesIntoDict(v, subdict_path, data, aux_data, variables,
+ if type(v) is dict:
+ LoadBuildFileIncludesIntoDict(v, subdict_path, data, aux_data,
None, check)
- elif v.__class__ == list:
- LoadBuildFileIncludesIntoList(v, subdict_path, data, aux_data, variables,
+ elif type(v) is list:
+ LoadBuildFileIncludesIntoList(v, subdict_path, data, aux_data,
check)
# This recurses into lists so that it can look for dicts.
-def LoadBuildFileIncludesIntoList(sublist, sublist_path, data, aux_data,
- variables, check):
+def LoadBuildFileIncludesIntoList(sublist, sublist_path, data, aux_data, check):
for item in sublist:
- if item.__class__ == dict:
+ if type(item) is dict:
LoadBuildFileIncludesIntoDict(item, sublist_path, data, aux_data,
- variables, None, check)
- elif item.__class__ == list:
- LoadBuildFileIncludesIntoList(item, sublist_path, data, aux_data,
- variables, check)
+ None, check)
+ elif type(item) is list:
+ LoadBuildFileIncludesIntoList(item, sublist_path, data, aux_data, check)
# Processes toolsets in all the targets. This recurses into condition entries
# since they can contain toolsets as well.
def ProcessToolsetsInDict(data):
if 'targets' in data:
target_list = data['targets']
new_target_list = []
for target in target_list:
@@ -314,27 +337,28 @@ def ProcessToolsetsInDict(data):
else:
toolsets = ['target']
# Make sure this 'toolsets' definition is only processed once.
if 'toolsets' in target:
del target['toolsets']
if len(toolsets) > 0:
# Optimization: only do copies if more than one toolset is specified.
for build in toolsets[1:]:
- new_target = copy.deepcopy(target)
+ new_target = gyp.simple_copy.deepcopy(target)
new_target['toolset'] = build
new_target_list.append(new_target)
target['toolset'] = toolsets[0]
new_target_list.append(target)
data['targets'] = new_target_list
if 'conditions' in data:
for condition in data['conditions']:
- if isinstance(condition, list):
+ if type(condition) is list:
for condition_dict in condition[1:]:
- ProcessToolsetsInDict(condition_dict)
+ if type(condition_dict) is dict:
+ ProcessToolsetsInDict(condition_dict)
# TODO(mark): I don't love this name. It just means that it's going to load
# a build file that contains targets and is expected to provide a targets dict
# that contains the targets...
def LoadTargetBuildFile(build_file_path, data, aux_data, variables, includes,
depth, check, load_dependencies):
# If depth is set, predefine the DEPTH variable to be a relative path from
@@ -344,29 +368,32 @@ def LoadTargetBuildFile(build_file_path,
# temporary measure. This should really be addressed by keeping all paths
# in POSIX until actual project generation.
d = gyp.common.RelativePath(depth, os.path.dirname(build_file_path))
if d == '':
variables['DEPTH'] = '.'
else:
variables['DEPTH'] = d.replace('\\', '/')
- # If the generator needs absolue paths, then do so.
- if absolute_build_file_paths:
- build_file_path = os.path.abspath(build_file_path)
-
- if build_file_path in data['target_build_files']:
- # Already loaded.
- return False
- data['target_build_files'].add(build_file_path)
+ # The 'target_build_files' key is only set when loading target build files in
+ # the non-parallel code path, where LoadTargetBuildFile is called
+ # recursively. In the parallel code path, we don't need to check whether the
+ # |build_file_path| has already been loaded, because the 'scheduled' set in
+ # ParallelState guarantees that we never load the same |build_file_path|
+ # twice.
+ if 'target_build_files' in data:
+ if build_file_path in data['target_build_files']:
+ # Already loaded.
+ return False
+ data['target_build_files'].add(build_file_path)
gyp.DebugOutput(gyp.DEBUG_INCLUDES,
- "Loading Target Build File '%s'" % build_file_path)
-
- build_file_data = LoadOneBuildFile(build_file_path, data, aux_data, variables,
+ "Loading Target Build File '%s'", build_file_path)
+
+ build_file_data = LoadOneBuildFile(build_file_path, data, aux_data,
includes, True, check)
# Store DEPTH for later use in generators.
build_file_data['_DEPTH'] = depth
# Set up the included_files key indicating which .gyp files contributed to
# this target dict.
if 'included_files' in build_file_data:
@@ -406,17 +433,18 @@ def LoadTargetBuildFile(build_file_path,
# This procedure needs to give the impression that target_defaults is
# used as defaults, and the individual targets inherit from that.
# The individual targets need to be merged into the defaults. Make
# a deep copy of the defaults for each target, merge the target dict
# as found in the input file into that copy, and then hook up the
# copy with the target-specific data merged into it as the replacement
# target dict.
old_target_dict = build_file_data['targets'][index]
- new_target_dict = copy.deepcopy(build_file_data['target_defaults'])
+ new_target_dict = gyp.simple_copy.deepcopy(
+ build_file_data['target_defaults'])
MergeDicts(new_target_dict, old_target_dict,
build_file_path, build_file_path)
build_file_data['targets'][index] = new_target_dict
index += 1
# No longer needed.
del build_file_data['target_defaults']
@@ -441,65 +469,58 @@ def LoadTargetBuildFile(build_file_path,
includes, depth, check, load_dependencies)
except Exception, e:
gyp.common.ExceptionAppend(
e, 'while loading dependencies of %s' % build_file_path)
raise
else:
return (build_file_path, dependencies)
-
def CallLoadTargetBuildFile(global_flags,
- build_file_path, data,
- aux_data, variables,
- includes, depth, check):
+ build_file_path, variables,
+ includes, depth, check,
+ generator_input_info):
"""Wrapper around LoadTargetBuildFile for parallel processing.
This wrapper is used when LoadTargetBuildFile is executed in
a worker process.
"""
try:
signal.signal(signal.SIGINT, signal.SIG_IGN)
# Apply globals so that the worker process behaves the same.
for key, value in global_flags.iteritems():
globals()[key] = value
- # Save the keys so we can return data that changed.
- data_keys = set(data)
- aux_data_keys = set(aux_data)
-
- result = LoadTargetBuildFile(build_file_path, data,
- aux_data, variables,
+ SetGeneratorGlobals(generator_input_info)
+ result = LoadTargetBuildFile(build_file_path, per_process_data,
+ per_process_aux_data, variables,
includes, depth, check, False)
if not result:
return result
(build_file_path, dependencies) = result
- data_out = {}
- for key in data:
- if key == 'target_build_files':
- continue
- if key not in data_keys:
- data_out[key] = data[key]
- aux_data_out = {}
- for key in aux_data:
- if key not in aux_data_keys:
- aux_data_out[key] = aux_data[key]
+ # We can safely pop the build_file_data from per_process_data because it
+ # will never be referenced by this process again, so we don't need to keep
+ # it in the cache.
+ build_file_data = per_process_data.pop(build_file_path)
# This gets serialized and sent back to the main process via a pipe.
# It's handled in LoadTargetBuildFileCallback.
return (build_file_path,
- data_out,
- aux_data_out,
+ build_file_data,
dependencies)
+ except GypError, e:
+ sys.stderr.write("gyp: %s\n" % e)
+ return None
except Exception, e:
- print "Exception: ", e
+ print >>sys.stderr, 'Exception:', e
+ print >>sys.stderr, traceback.format_exc()
return None
class ParallelProcessingError(Exception):
pass
class ParallelState(object):
@@ -513,18 +534,16 @@ class ParallelState(object):
def __init__(self):
# The multiprocessing pool.
self.pool = None
# The condition variable used to protect this object and notify
# the main loop when there might be more data to process.
self.condition = None
# The "data" dict that was passed to LoadTargetBuildFileParallel
self.data = None
- # The "aux_data" dict that was passed to LoadTargetBuildFileParallel
- self.aux_data = None
# The number of parallel calls outstanding; decremented when a response
# was received.
self.pending = 0
# The set of all build files that have been scheduled, so we don't
# schedule the same one twice.
self.scheduled = set()
# A list of dependency build file paths that haven't been scheduled yet.
self.dependencies = []
@@ -535,154 +554,153 @@ class ParallelState(object):
"""Handle the results of running LoadTargetBuildFile in another process.
"""
self.condition.acquire()
if not result:
self.error = True
self.condition.notify()
self.condition.release()
return
- (build_file_path0, data0, aux_data0, dependencies0) = result
+ (build_file_path0, build_file_data0, dependencies0) = result
+ self.data[build_file_path0] = build_file_data0
self.data['target_build_files'].add(build_file_path0)
- for key in data0:
- self.data[key] = data0[key]
- for key in aux_data0:
- self.aux_data[key] = aux_data0[key]
for new_dependency in dependencies0:
if new_dependency not in self.scheduled:
self.scheduled.add(new_dependency)
self.dependencies.append(new_dependency)
self.pending -= 1
self.condition.notify()
self.condition.release()
-def LoadTargetBuildFileParallel(build_file_path, data, aux_data,
- variables, includes, depth, check):
+def LoadTargetBuildFilesParallel(build_files, data, variables, includes, depth,
+ check, generator_input_info):
parallel_state = ParallelState()
parallel_state.condition = threading.Condition()
- parallel_state.dependencies = [build_file_path]
- parallel_state.scheduled = set([build_file_path])
+ # Make copies of the build_files argument that we can modify while working.
+ parallel_state.dependencies = list(build_files)
+ parallel_state.scheduled = set(build_files)
parallel_state.pending = 0
parallel_state.data = data
- parallel_state.aux_data = aux_data
try:
parallel_state.condition.acquire()
while parallel_state.dependencies or parallel_state.pending:
if parallel_state.error:
break
if not parallel_state.dependencies:
parallel_state.condition.wait()
continue
dependency = parallel_state.dependencies.pop()
parallel_state.pending += 1
- data_in = {}
- data_in['target_build_files'] = data['target_build_files']
- aux_data_in = {}
global_flags = {
'path_sections': globals()['path_sections'],
'non_configuration_keys': globals()['non_configuration_keys'],
- 'absolute_build_file_paths': globals()['absolute_build_file_paths'],
'multiple_toolsets': globals()['multiple_toolsets']}
if not parallel_state.pool:
- parallel_state.pool = multiprocessing.Pool(8)
+ parallel_state.pool = multiprocessing.Pool(multiprocessing.cpu_count())
parallel_state.pool.apply_async(
CallLoadTargetBuildFile,
args = (global_flags, dependency,
- data_in, aux_data_in,
- variables, includes, depth, check),
+ variables, includes, depth, check, generator_input_info),
callback = parallel_state.LoadTargetBuildFileCallback)
except KeyboardInterrupt, e:
parallel_state.pool.terminate()
raise e
parallel_state.condition.release()
+
+ parallel_state.pool.close()
+ parallel_state.pool.join()
+ parallel_state.pool = None
+
if parallel_state.error:
- sys.exit()
-
+ sys.exit(1)
# Look for the bracket that matches the first bracket seen in a
# string, and return the start and end as a tuple. For example, if
# the input is something like "<(foo <(bar)) blah", then it would
# return (1, 13), indicating the entire string except for the leading
# "<" and trailing " blah".
-def FindEnclosingBracketGroup(input):
- brackets = { '}': '{',
- ']': '[',
- ')': '(', }
+LBRACKETS= set('{[(')
+BRACKETS = {'}': '{', ']': '[', ')': '('}
+def FindEnclosingBracketGroup(input_str):
stack = []
- count = 0
start = -1
- for char in input:
- if char in brackets.values():
+ for index, char in enumerate(input_str):
+ if char in LBRACKETS:
stack.append(char)
if start == -1:
- start = count
- if char in brackets.keys():
- try:
- last_bracket = stack.pop()
- except IndexError:
- return (-1, -1)
- if last_bracket != brackets[char]:
+ start = index
+ elif char in BRACKETS:
+ if not stack:
return (-1, -1)
- if len(stack) == 0:
- return (start, count + 1)
- count = count + 1
+ if stack.pop() != BRACKETS[char]:
+ return (-1, -1)
+ if not stack:
+ return (start, index + 1)
return (-1, -1)
-canonical_int_re = re.compile('^(0|-?[1-9][0-9]*)$')
-
-
def IsStrCanonicalInt(string):
"""Returns True if |string| is in its canonical integer form.
The canonical form is such that str(int(string)) == string.
"""
- if not isinstance(string, str) or not canonical_int_re.match(string):
- return False
-
- return True
+ if type(string) is str:
+ # This function is called a lot so for maximum performance, avoid
+ # involving regexps which would otherwise make the code much
+ # shorter. Regexps would need twice the time of this function.
+ if string:
+ if string == "0":
+ return True
+ if string[0] == "-":
+ string = string[1:]
+ if not string:
+ return False
+ if '1' <= string[0] <= '9':
+ return string.isdigit()
+
+ return False
# This matches things like "<(asdf)", "<!(cmd)", "<!@(cmd)", "<|(list)",
# "<!interpreter(arguments)", "<([list])", and even "<([)" and "<(<())".
# In the last case, the inner "<()" is captured in match['content'].
early_variable_re = re.compile(
- '(?P<replace>(?P<type><(?:(?:!?@?)|\|)?)'
- '(?P<command_string>[-a-zA-Z0-9_.]+)?'
- '\((?P<is_array>\s*\[?)'
- '(?P<content>.*?)(\]?)\))')
+ r'(?P<replace>(?P<type><(?:(?:!?@?)|\|)?)'
+ r'(?P<command_string>[-a-zA-Z0-9_.]+)?'
+ r'\((?P<is_array>\s*\[?)'
+ r'(?P<content>.*?)(\]?)\))')
# This matches the same as early_variable_re, but with '>' instead of '<'.
late_variable_re = re.compile(
- '(?P<replace>(?P<type>>(?:(?:!?@?)|\|)?)'
- '(?P<command_string>[-a-zA-Z0-9_.]+)?'
- '\((?P<is_array>\s*\[?)'
- '(?P<content>.*?)(\]?)\))')
+ r'(?P<replace>(?P<type>>(?:(?:!?@?)|\|)?)'
+ r'(?P<command_string>[-a-zA-Z0-9_.]+)?'
+ r'\((?P<is_array>\s*\[?)'
+ r'(?P<content>.*?)(\]?)\))')
# This matches the same as early_variable_re, but with '^' instead of '<'.
latelate_variable_re = re.compile(
- '(?P<replace>(?P<type>[\^](?:(?:!?@?)|\|)?)'
- '(?P<command_string>[-a-zA-Z0-9_.]+)?'
- '\((?P<is_array>\s*\[?)'
- '(?P<content>.*?)(\]?)\))')
+ r'(?P<replace>(?P<type>[\^](?:(?:!?@?)|\|)?)'
+ r'(?P<command_string>[-a-zA-Z0-9_.]+)?'
+ r'\((?P<is_array>\s*\[?)'
+ r'(?P<content>.*?)(\]?)\))')
# Global cache of results from running commands so they don't have to be run
# more then once.
cached_command_results = {}
def FixupPlatformCommand(cmd):
if sys.platform == 'win32':
- if type(cmd) == list:
+ if type(cmd) is list:
cmd = [re.sub('^cat ', 'type ', cmd[0])] + cmd[1:]
else:
cmd = re.sub('^cat ', 'type ', cmd)
return cmd
PHASE_EARLY = 0
PHASE_LATE = 1
@@ -708,30 +726,29 @@ def ExpandVariables(input, phase, variab
return int(input_str)
# Do a quick scan to determine if an expensive regex search is warranted.
if expansion_symbol not in input_str:
return input_str
# Get the entire list of matches as a list of MatchObject instances.
# (using findall here would return strings instead of MatchObjects).
- matches = [match for match in variable_re.finditer(input_str)]
+ matches = list(variable_re.finditer(input_str))
if not matches:
return input_str
output = input_str
# Reverse the list of matches so that replacements are done right-to-left.
# That ensures that earlier replacements won't mess up the string in a
# way that causes later calls to find the earlier substituted text instead
# of what's intended for replacement.
matches.reverse()
for match_group in matches:
match = match_group.groupdict()
- gyp.DebugOutput(gyp.DEBUG_VARIABLES,
- "Matches: %s" % repr(match))
+ gyp.DebugOutput(gyp.DEBUG_VARIABLES, "Matches: %r", match)
# match['replace'] is the substring to look for, match['type']
# is the character code for the replacement type (< > <! >! <| >| <@
# >@ <!@ >!@), match['is_array'] contains a '[' for command
# arrays, and match['content'] is the name of the variable (< >)
# or command to run (<! >!). match['command_string'] is an optional
# command string. Currently, only 'pymod_do_main' is supported.
# run_command is true if a ! variant is used.
@@ -763,17 +780,17 @@ def ExpandVariables(input, phase, variab
contents_end = replace_end - 1
contents = input_str[contents_start:contents_end]
# Do filter substitution now for <|().
# Admittedly, this is different than the evaluation order in other
# contexts. However, since filtration has no chance to run on <|(),
# this seems like the only obvious way to give them access to filters.
if file_list:
- processed_variables = copy.deepcopy(variables)
+ processed_variables = gyp.simple_copy.deepcopy(variables)
ProcessListFiltersInDict(contents, processed_variables)
# Recurse to expand variables in the contents
contents = ExpandVariables(contents, phase,
processed_variables, build_file)
else:
# Recurse to expand variables in the contents
contents = ExpandVariables(contents, phase, variables, build_file)
@@ -788,109 +805,130 @@ def ExpandVariables(input, phase, variab
# expansions, there can be no other text besides the variable
# expansion in the input string.
expand_to_list = '@' in match['type'] and input_str == replacement
if run_command or file_list:
# Find the build file's directory, so commands can be run or file lists
# generated relative to it.
build_file_dir = os.path.dirname(build_file)
- if build_file_dir == '':
+ if build_file_dir == '' and not file_list:
# If build_file is just a leaf filename indicating a file in the
# current directory, build_file_dir might be an empty string. Set
# it to None to signal to subprocess.Popen that it should run the
# command in the current directory.
build_file_dir = None
# Support <|(listfile.txt ...) which generates a file
# containing items from a gyp list, generated at gyp time.
# This works around actions/rules which have more inputs than will
# fit on the command line.
if file_list:
- if type(contents) == list:
+ if type(contents) is list:
contents_list = contents
else:
contents_list = contents.split(' ')
replacement = contents_list[0]
- path = replacement
- if not os.path.isabs(path):
- path = os.path.join(build_file_dir, path)
+ if os.path.isabs(replacement):
+ raise GypError('| cannot handle absolute paths, got "%s"' % replacement)
+
+ if not generator_filelist_paths:
+ path = os.path.join(build_file_dir, replacement)
+ else:
+ if os.path.isabs(build_file_dir):
+ toplevel = generator_filelist_paths['toplevel']
+ rel_build_file_dir = gyp.common.RelativePath(build_file_dir, toplevel)
+ else:
+ rel_build_file_dir = build_file_dir
+ qualified_out_dir = generator_filelist_paths['qualified_out_dir']
+ path = os.path.join(qualified_out_dir, rel_build_file_dir, replacement)
+ gyp.common.EnsureDirExists(path)
+
+ replacement = gyp.common.RelativePath(path, build_file_dir)
f = gyp.common.WriteOnDiff(path)
for i in contents_list[1:]:
f.write('%s\n' % i)
f.close()
elif run_command:
use_shell = True
if match['is_array']:
contents = eval(contents)
use_shell = False
# Check for a cached value to avoid executing commands, or generating
- # file lists more than once.
- # TODO(http://code.google.com/p/gyp/issues/detail?id=112): It is
- # possible that the command being invoked depends on the current
- # directory. For that case the syntax needs to be extended so that the
- # directory is also used in cache_key (it becomes a tuple).
+ # file lists more than once. The cache key contains the command to be
+ # run as well as the directory to run it from, to account for commands
+ # that depend on their current directory.
# TODO(http://code.google.com/p/gyp/issues/detail?id=111): In theory,
# someone could author a set of GYP files where each time the command
# is invoked it produces different output by design. When the need
# arises, the syntax should be extended to support no caching off a
# command's output so it is run every time.
- cache_key = str(contents)
+ cache_key = (str(contents), build_file_dir)
cached_value = cached_command_results.get(cache_key, None)
if cached_value is None:
gyp.DebugOutput(gyp.DEBUG_VARIABLES,
- "Executing command '%s' in directory '%s'" %
- (contents,build_file_dir))
+ "Executing command '%s' in directory '%s'",
+ contents, build_file_dir)
replacement = ''
if command_string == 'pymod_do_main':
# <!pymod_do_main(modulename param eters) loads |modulename| as a
# python module and then calls that module's DoMain() function,
# passing ["param", "eters"] as a single list argument. For modules
# that don't load quickly, this can be faster than
# <!(python modulename param eters). Do this in |build_file_dir|.
oldwd = os.getcwd() # Python doesn't like os.open('.'): no fchdir.
- os.chdir(build_file_dir)
-
- parsed_contents = shlex.split(contents)
- py_module = __import__(parsed_contents[0])
- replacement = str(py_module.DoMain(parsed_contents[1:])).rstrip()
-
- os.chdir(oldwd)
+ if build_file_dir: # build_file_dir may be None (see above).
+ os.chdir(build_file_dir)
+ try:
+
+ parsed_contents = shlex.split(contents)
+ try:
+ py_module = __import__(parsed_contents[0])
+ except ImportError as e:
+ raise GypError("Error importing pymod_do_main"
+ "module (%s): %s" % (parsed_contents[0], e))
+ replacement = str(py_module.DoMain(parsed_contents[1:])).rstrip()
+ finally:
+ os.chdir(oldwd)
assert replacement != None
elif command_string:
raise GypError("Unknown command string '%s' in '%s'." %
(command_string, contents))
else:
# Fix up command with platform specific workarounds.
contents = FixupPlatformCommand(contents)
- p = subprocess.Popen(contents, shell=use_shell,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
- stdin=subprocess.PIPE,
- cwd=build_file_dir)
+ try:
+ p = subprocess.Popen(contents, shell=use_shell,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ stdin=subprocess.PIPE,
+ cwd=build_file_dir)
+ except Exception, e:
+ raise GypError("%s while executing command '%s' in %s" %
+ (e, contents, build_file))
p_stdout, p_stderr = p.communicate('')
if p.wait() != 0 or p_stderr:
sys.stderr.write(p_stderr)
# Simulate check_call behavior, since check_call only exists
# in python 2.5 and later.
- raise GypError("Call to '%s' returned exit status %d." %
- (contents, p.returncode))
+ raise GypError("Call to '%s' returned exit status %d while in %s." %
+ (contents, p.returncode, build_file))
replacement = p_stdout.rstrip()
cached_command_results[cache_key] = replacement
else:
gyp.DebugOutput(gyp.DEBUG_VARIABLES,
- "Had cache value for command '%s' in directory '%s'" %
- (contents,build_file_dir))
+ "Had cache value for command '%s' in directory '%s'",
+ contents,build_file_dir)
replacement = cached_value
else:
if not contents in variables:
if contents[-1] in ['!', '/']:
# In order to allow cross-compiles (nacl) to happen more naturally,
# we will allow references to >(sources/) etc. to resolve to
# and empty list if undefined. This allows actions to:
@@ -902,49 +940,47 @@ def ExpandVariables(input, phase, variab
# ],
replacement = []
else:
raise GypError('Undefined variable ' + contents +
' in ' + build_file)
else:
replacement = variables[contents]
- if isinstance(replacement, list):
+ if type(replacement) is list:
for item in replacement:
- if (not contents[-1] == '/' and
- not isinstance(item, str) and not isinstance(item, int)):
+ if not contents[-1] == '/' and type(item) not in (str, int):
raise GypError('Variable ' + contents +
' must expand to a string or list of strings; ' +
'list contains a ' +
item.__class__.__name__)
# Run through the list and handle variable expansions in it. Since
# the list is guaranteed not to contain dicts, this won't do anything
# with conditions sections.
ProcessVariablesAndConditionsInList(replacement, phase, variables,
build_file)
- elif not isinstance(replacement, str) and \
- not isinstance(replacement, int):
+ elif type(replacement) not in (str, int):
raise GypError('Variable ' + contents +
' must expand to a string or list of strings; ' +
'found a ' + replacement.__class__.__name__)
if expand_to_list:
# Expanding in list context. It's guaranteed that there's only one
# replacement to do in |input_str| and that it's this replacement. See
# above.
- if isinstance(replacement, list):
+ if type(replacement) is list:
# If it's already a list, make a copy.
output = replacement[:]
else:
# Split it the same way sh would split arguments.
output = shlex.split(str(replacement))
else:
# Expanding in string context.
encoded_replacement = ''
- if isinstance(replacement, list):
+ if type(replacement) is list:
# When expanding a list into string context, turn the list items
# into a string in a way that will work with a subprocess call.
#
# TODO(mark): This isn't completely correct. This should
# call a generator-provided function that observes the
# proper list-to-argument quoting rules on a specific
# platform instead of just calling the POSIX encoding
# routine.
@@ -952,45 +988,124 @@ def ExpandVariables(input, phase, variab
else:
encoded_replacement = replacement
output = output[:replace_start] + str(encoded_replacement) + \
output[replace_end:]
# Prepare for the next match iteration.
input_str = output
- # Look for more matches now that we've replaced some, to deal with
- # expanding local variables (variables defined in the same
- # variables block as this one).
- gyp.DebugOutput(gyp.DEBUG_VARIABLES,
- "Found output %s, recursing." % repr(output))
- if isinstance(output, list):
- if output and isinstance(output[0], list):
- # Leave output alone if it's a list of lists.
- # We don't want such lists to be stringified.
- pass
+ if output == input:
+ gyp.DebugOutput(gyp.DEBUG_VARIABLES,
+ "Found only identity matches on %r, avoiding infinite "
+ "recursion.",
+ output)
+ else:
+ # Look for more matches now that we've replaced some, to deal with
+ # expanding local variables (variables defined in the same
+ # variables block as this one).
+ gyp.DebugOutput(gyp.DEBUG_VARIABLES, "Found output %r, recursing.", output)
+ if type(output) is list:
+ if output and type(output[0]) is list:
+ # Leave output alone if it's a list of lists.
+ # We don't want such lists to be stringified.
+ pass
+ else:
+ new_output = []
+ for item in output:
+ new_output.append(
+ ExpandVariables(item, phase, variables, build_file))
+ output = new_output
else:
- new_output = []
- for item in output:
- new_output.append(
- ExpandVariables(item, phase, variables, build_file))
- output = new_output
- else:
- output = ExpandVariables(output, phase, variables, build_file)
+ output = ExpandVariables(output, phase, variables, build_file)
# Convert all strings that are canonically-represented integers into integers.
- if isinstance(output, list):
+ if type(output) is list:
for index in xrange(0, len(output)):
if IsStrCanonicalInt(output[index]):
output[index] = int(output[index])
elif IsStrCanonicalInt(output):
output = int(output)
return output
+# The same condition is often evaluated over and over again so it
+# makes sense to cache as much as possible between evaluations.
+cached_conditions_asts = {}
+
+def EvalCondition(condition, conditions_key, phase, variables, build_file):
+ """Returns the dict that should be used or None if the result was
+ that nothing should be used."""
+ if type(condition) is not list:
+ raise GypError(conditions_key + ' must be a list')
+ if len(condition) < 2:
+ # It's possible that condition[0] won't work in which case this
+ # attempt will raise its own IndexError. That's probably fine.
+ raise GypError(conditions_key + ' ' + condition[0] +
+ ' must be at least length 2, not ' + str(len(condition)))
+
+ i = 0
+ result = None
+ while i < len(condition):
+ cond_expr = condition[i]
+ true_dict = condition[i + 1]
+ if type(true_dict) is not dict:
+ raise GypError('{} {} must be followed by a dictionary, not {}'.format(
+ conditions_key, cond_expr, type(true_dict)))
+ if len(condition) > i + 2 and type(condition[i + 2]) is dict:
+ false_dict = condition[i + 2]
+ i = i + 3
+ if i != len(condition):
+ raise GypError('{} {} has {} unexpected trailing items'.format(
+ conditions_key, cond_expr, len(condition) - i))
+ else:
+ false_dict = None
+ i = i + 2
+ if result == None:
+ result = EvalSingleCondition(
+ cond_expr, true_dict, false_dict, phase, variables, build_file)
+
+ return result
+
+
+def EvalSingleCondition(
+ cond_expr, true_dict, false_dict, phase, variables, build_file):
+ """Returns true_dict if cond_expr evaluates to true, and false_dict
+ otherwise."""
+ # Do expansions on the condition itself. Since the conditon can naturally
+ # contain variable references without needing to resort to GYP expansion
+ # syntax, this is of dubious value for variables, but someone might want to
+ # use a command expansion directly inside a condition.
+ cond_expr_expanded = ExpandVariables(cond_expr, phase, variables,
+ build_file)
+ if type(cond_expr_expanded) not in (str, int):
+ raise ValueError(
+ 'Variable expansion in this context permits str and int ' + \
+ 'only, found ' + cond_expr_expanded.__class__.__name__)
+
+ try:
+ if cond_expr_expanded in cached_conditions_asts:
+ ast_code = cached_conditions_asts[cond_expr_expanded]
+ else:
+ ast_code = compile(cond_expr_expanded, '<string>', 'eval')
+ cached_conditions_asts[cond_expr_expanded] = ast_code
+ if eval(ast_code, {'__builtins__': None}, variables):
+ return true_dict
+ return false_dict
+ except SyntaxError, e:
+ syntax_error = SyntaxError('%s while evaluating condition \'%s\' in %s '
+ 'at character %d.' %
+ (str(e.args[0]), e.text, build_file, e.offset),
+ e.filename, e.lineno, e.offset, e.text)
+ raise syntax_error
+ except NameError, e:
+ gyp.common.ExceptionAppend(e, 'while evaluating condition \'%s\' in %s' %
+ (cond_expr_expanded, build_file))
+ raise GypError(e)
+
def ProcessConditionsInDict(the_dict, phase, variables, build_file):
# Process a 'conditions' or 'target_conditions' section in the_dict,
# depending on phase.
# early -> conditions
# late -> target_conditions
# latelate -> no conditions
#
@@ -1016,88 +1131,46 @@ def ProcessConditionsInDict(the_dict, ph
if not conditions_key in the_dict:
return
conditions_list = the_dict[conditions_key]
# Unhook the conditions list, it's no longer needed.
del the_dict[conditions_key]
for condition in conditions_list:
- if not isinstance(condition, list):
- raise GypError(conditions_key + ' must be a list')
- if len(condition) != 2 and len(condition) != 3:
- # It's possible that condition[0] won't work in which case this
- # attempt will raise its own IndexError. That's probably fine.
- raise GypError(conditions_key + ' ' + condition[0] +
- ' must be length 2 or 3, not ' + str(len(condition)))
-
- [cond_expr, true_dict] = condition[0:2]
- false_dict = None
- if len(condition) == 3:
- false_dict = condition[2]
-
- # Do expansions on the condition itself. Since the conditon can naturally
- # contain variable references without needing to resort to GYP expansion
- # syntax, this is of dubious value for variables, but someone might want to
- # use a command expansion directly inside a condition.
- cond_expr_expanded = ExpandVariables(cond_expr, phase, variables,
- build_file)
- if not isinstance(cond_expr_expanded, str) and \
- not isinstance(cond_expr_expanded, int):
- raise ValueError, \
- 'Variable expansion in this context permits str and int ' + \
- 'only, found ' + expanded.__class__.__name__
-
- try:
- ast_code = compile(cond_expr_expanded, '<string>', 'eval')
-
- if eval(ast_code, {'__builtins__': None}, variables):
- merge_dict = true_dict
- else:
- merge_dict = false_dict
- except SyntaxError, e:
- syntax_error = SyntaxError('%s while evaluating condition \'%s\' in %s '
- 'at character %d.' %
- (str(e.args[0]), e.text, build_file, e.offset),
- e.filename, e.lineno, e.offset, e.text)
- raise syntax_error
- except NameError, e:
- gyp.common.ExceptionAppend(e, 'while evaluating condition \'%s\' in %s' %
- (cond_expr_expanded, build_file))
- raise
+ merge_dict = EvalCondition(condition, conditions_key, phase, variables,
+ build_file)
if merge_dict != None:
# Expand variables and nested conditinals in the merge_dict before
# merging it.
ProcessVariablesAndConditionsInDict(merge_dict, phase,
variables, build_file)
MergeDicts(the_dict, merge_dict, build_file, build_file)
def LoadAutomaticVariablesFromDict(variables, the_dict):
# Any keys with plain string values in the_dict become automatic variables.
# The variable name is the key name with a "_" character prepended.
for key, value in the_dict.iteritems():
- if isinstance(value, str) or isinstance(value, int) or \
- isinstance(value, list):
+ if type(value) in (str, int, list):
variables['_' + key] = value
def LoadVariablesFromVariablesDict(variables, the_dict, the_dict_key):
# Any keys in the_dict's "variables" dict, if it has one, becomes a
# variable. The variable name is the key name in the "variables" dict.
# Variables that end with the % character are set only if they are unset in
# the variables dict. the_dict_key is the name of the key that accesses
# the_dict in the_dict's parent dict. If the_dict's parent is not a dict
# (it could be a list or it could be parentless because it is a root dict),
# the_dict_key will be None.
for key, value in the_dict.get('variables', {}).iteritems():
- if not isinstance(value, str) and not isinstance(value, int) and \
- not isinstance(value, list):
+ if type(value) not in (str, int, list):
continue
if key.endswith('%'):
variable_name = key[:-1]
if variable_name in variables:
# If the variable is already set, don't set it.
continue
if the_dict_key is 'variables' and variable_name in the_dict:
@@ -1140,22 +1213,22 @@ def ProcessVariablesAndConditionsInDict(
# should just be an ordinary variable in this scope.
ProcessVariablesAndConditionsInDict(the_dict['variables'], phase,
variables, build_file, 'variables')
LoadVariablesFromVariablesDict(variables, the_dict, the_dict_key)
for key, value in the_dict.iteritems():
# Skip "variables", which was already processed if present.
- if key != 'variables' and isinstance(value, str):
+ if key != 'variables' and type(value) is str:
expanded = ExpandVariables(value, phase, variables, build_file)
- if not isinstance(expanded, str) and not isinstance(expanded, int):
- raise ValueError, \
+ if type(expanded) not in (str, int):
+ raise ValueError(
'Variable expansion in this context permits str and int ' + \
- 'only, found ' + expanded.__class__.__name__ + ' for ' + key
+ 'only, found ' + expanded.__class__.__name__ + ' for ' + key)
the_dict[key] = expanded
# Variable expansion may have resulted in changes to automatics. Reload.
# TODO(mark): Optimization: only reload if no changes were made.
variables = variables_in.copy()
LoadAutomaticVariablesFromDict(variables, the_dict)
LoadVariablesFromVariablesDict(variables, the_dict, the_dict_key)
@@ -1199,66 +1272,66 @@ def ProcessVariablesAndConditionsInDict(
LoadAutomaticVariablesFromDict(variables, the_dict)
LoadVariablesFromVariablesDict(variables, the_dict, the_dict_key)
# Recurse into child dicts, or process child lists which may result in
# further recursion into descendant dicts.
for key, value in the_dict.iteritems():
# Skip "variables" and string values, which were already processed if
# present.
- if key == 'variables' or isinstance(value, str):
+ if key == 'variables' or type(value) is str:
continue
- if isinstance(value, dict):
+ if type(value) is dict:
# Pass a copy of the variables dict so that subdicts can't influence
# parents.
ProcessVariablesAndConditionsInDict(value, phase, variables,
build_file, key)
- elif isinstance(value, list):
+ elif type(value) is list:
# The list itself can't influence the variables dict, and
# ProcessVariablesAndConditionsInList will make copies of the variables
# dict if it needs to pass it to something that can influence it. No
# copy is necessary here.
ProcessVariablesAndConditionsInList(value, phase, variables,
build_file)
- elif not isinstance(value, int):
- raise TypeError, 'Unknown type ' + value.__class__.__name__ + \
- ' for ' + key
+ elif type(value) is not int:
+ raise TypeError('Unknown type ' + value.__class__.__name__ + \
+ ' for ' + key)
def ProcessVariablesAndConditionsInList(the_list, phase, variables,
build_file):
# Iterate using an index so that new values can be assigned into the_list.
index = 0
while index < len(the_list):
item = the_list[index]
- if isinstance(item, dict):
+ if type(item) is dict:
# Make a copy of the variables dict so that it won't influence anything
# outside of its own scope.
ProcessVariablesAndConditionsInDict(item, phase, variables, build_file)
- elif isinstance(item, list):
+ elif type(item) is list:
ProcessVariablesAndConditionsInList(item, phase, variables, build_file)
- elif isinstance(item, str):
+ elif type(item) is str:
expanded = ExpandVariables(item, phase, variables, build_file)
- if isinstance(expanded, str) or isinstance(expanded, int):
+ if type(expanded) in (str, int):
the_list[index] = expanded
- elif isinstance(expanded, list):
+ elif type(expanded) is list:
the_list[index:index+1] = expanded
index += len(expanded)
# index now identifies the next item to examine. Continue right now
# without falling into the index increment below.
continue
else:
- raise ValueError, \
+ raise ValueError(
'Variable expansion in this context permits strings and ' + \
'lists only, found ' + expanded.__class__.__name__ + ' at ' + \
- index
- elif not isinstance(item, int):
- raise TypeError, 'Unknown type ' + item.__class__.__name__ + \
- ' at index ' + index
+ index)
+ elif type(item) is not int:
+ raise TypeError('Unknown type ' + item.__class__.__name__ + \
+ ' at index ' + index)
index = index + 1
def BuildTargetsDict(data):
"""Builds a dict mapping fully-qualified target names to their target dicts.
|data| is a dict mapping loaded build files by pathname relative to the
current directory. Values in |data| are build file contents. For each
@@ -1402,16 +1475,49 @@ def RemoveDuplicateDependencies(targets)
lists."""
for target_name, target_dict in targets.iteritems():
for dependency_key in dependency_sections:
dependencies = target_dict.get(dependency_key, [])
if dependencies:
target_dict[dependency_key] = Unify(dependencies)
+def Filter(l, item):
+ """Removes item from l."""
+ res = {}
+ return [res.setdefault(e, e) for e in l if e != item]
+
+
+def RemoveSelfDependencies(targets):
+ """Remove self dependencies from targets that have the prune_self_dependency
+ variable set."""
+ for target_name, target_dict in targets.iteritems():
+ for dependency_key in dependency_sections:
+ dependencies = target_dict.get(dependency_key, [])
+ if dependencies:
+ for t in dependencies:
+ if t == target_name:
+ if targets[t].get('variables', {}).get('prune_self_dependency', 0):
+ target_dict[dependency_key] = Filter(dependencies, target_name)
+
+
+def RemoveLinkDependenciesFromNoneTargets(targets):
+ """Remove dependencies having the 'link_dependency' attribute from the 'none'
+ targets."""
+ for target_name, target_dict in targets.iteritems():
+ for dependency_key in dependency_sections:
+ dependencies = target_dict.get(dependency_key, [])
+ if dependencies:
+ for t in dependencies:
+ if target_dict.get('type', None) == 'none':
+ if targets[t].get('variables', {}).get('link_dependency', 0):
+ target_dict[dependency_key] = \
+ Filter(target_dict[dependency_key], t)
+
+
class DependencyGraphNode(object):
"""
Attributes:
ref: A reference to an object that this DependencyGraphNode represents.
dependencies: List of DependencyGraphNodes on which this one depends.
dependents: List of DependencyGraphNodes that depend on this one.
"""
@@ -1419,61 +1525,88 @@ class DependencyGraphNode(object):
class CircularException(GypError):
pass
def __init__(self, ref):
self.ref = ref
self.dependencies = []
self.dependents = []
- # This Mozilla change makes DependencyGraphNode more idempotent.
- def __hash__(self):
- return hash(self.ref)
+ def __repr__(self):
+ return '<DependencyGraphNode: %r>' % self.ref
def FlattenToList(self):
# flat_list is the sorted list of dependencies - actually, the list items
# are the "ref" attributes of DependencyGraphNodes. Every target will
# appear in flat_list after all of its dependencies, and before all of its
# dependents.
- flat_list = []
+ flat_list = OrderedSet()
+
+ def ExtractNodeRef(node):
+ """Extracts the object that the node represents from the given node."""
+ return node.ref
# in_degree_zeros is the list of DependencyGraphNodes that have no
# dependencies not in flat_list. Initially, it is a copy of the children
# of this node, because when the graph was built, nodes with no
# dependencies were made implicit dependents of the root node.
- in_degree_zeros = set(self.dependents[:])
+ in_degree_zeros = sorted(self.dependents[:], key=ExtractNodeRef)
while in_degree_zeros:
# Nodes in in_degree_zeros have no dependencies not in flat_list, so they
# can be appended to flat_list. Take these nodes out of in_degree_zeros
# as work progresses, so that the next node to process from the list can
# always be accessed at a consistent position.
node = in_degree_zeros.pop()
- flat_list.append(node.ref)
+ flat_list.add(node.ref)
# Look at dependents of the node just added to flat_list. Some of them
# may now belong in in_degree_zeros.
- for node_dependent in node.dependents:
+ for node_dependent in sorted(node.dependents, key=ExtractNodeRef):
is_in_degree_zero = True
- for node_dependent_dependency in node_dependent.dependencies:
+ # TODO: We want to check through the
+ # node_dependent.dependencies list but if it's long and we
+ # always start at the beginning, then we get O(n^2) behaviour.
+ for node_dependent_dependency in (sorted(node_dependent.dependencies,
+ key=ExtractNodeRef)):
if not node_dependent_dependency.ref in flat_list:
# The dependent one or more dependencies not in flat_list. There
# will be more chances to add it to flat_list when examining
# it again as a dependent of those other dependencies, provided
# that there are no cycles.
is_in_degree_zero = False
break
if is_in_degree_zero:
# All of the dependent's dependencies are already in flat_list. Add
# it to in_degree_zeros where it will be processed in a future
# iteration of the outer loop.
- in_degree_zeros.add(node_dependent)
-
- return flat_list
+ in_degree_zeros += [node_dependent]
+
+ return list(flat_list)
+
+ def FindCycles(self):
+ """
+ Returns a list of cycles in the graph, where each cycle is its own list.
+ """
+ results = []
+ visited = set()
+
+ def Visit(node, path):
+ for child in node.dependents:
+ if child in path:
+ results.append([child] + path[:path.index(child) + 1])
+ elif not child in visited:
+ visited.add(child)
+ Visit(child, [child] + path)
+
+ visited.add(self)
+ Visit(self, [self])
+
+ return results
def DirectDependencies(self, dependencies=None):
"""Returns a list of just direct dependencies."""
if dependencies == None:
dependencies = []
for dependency in self.dependencies:
# Check for None, corresponding to the root node.
@@ -1528,44 +1661,55 @@ class DependencyGraphNode(object):
dependencies that a dependency has advertised settings should be exported
through the dependency for.
"""
dependencies = self.DirectDependencies(dependencies)
return self._AddImportedDependencies(targets, dependencies)
def DeepDependencies(self, dependencies=None):
- """Returns a list of all of a target's dependencies, recursively."""
- if dependencies == None:
- dependencies = []
+ """Returns an OrderedSet of all of a target's dependencies, recursively."""
+ if dependencies is None:
+ # Using a list to get ordered output and a set to do fast "is it
+ # already added" checks.
+ dependencies = OrderedSet()
for dependency in self.dependencies:
# Check for None, corresponding to the root node.
- if dependency.ref != None and dependency.ref not in dependencies:
- dependencies.append(dependency.ref)
+ if dependency.ref is None:
+ continue
+ if dependency.ref not in dependencies:
dependency.DeepDependencies(dependencies)
+ dependencies.add(dependency.ref)
return dependencies
- def LinkDependencies(self, targets, dependencies=None, initial=True):
- """Returns a list of dependency targets that are linked into this target.
+ def _LinkDependenciesInternal(self, targets, include_shared_libraries,
+ dependencies=None, initial=True):
+ """Returns an OrderedSet of dependency targets that are linked
+ into this target.
This function has a split personality, depending on the setting of
|initial|. Outside callers should always leave |initial| at its default
setting.
When adding a target to the list of dependencies, this function will
recurse into itself with |initial| set to False, to collect dependencies
that are linked into the linkable target for which the list is being built.
+
+ If |include_shared_libraries| is False, the resulting dependencies will not
+ include shared_library targets that are linked into this target.
"""
- if dependencies == None:
- dependencies = []
+ if dependencies is None:
+ # Using a list to get ordered output and a set to do fast "is it
+ # already added" checks.
+ dependencies = OrderedSet()
# Check for None, corresponding to the root node.
- if self.ref == None:
+ if self.ref is None:
return dependencies
# It's kind of sucky that |targets| has to be passed into this function,
# but that's presently the easiest way to access the target dicts so that
# this function can find target types.
if 'target_name' not in targets[self.ref]:
raise GypError("Missing 'target_name' field in target.")
@@ -1583,40 +1727,73 @@ class DependencyGraphNode(object):
# return an empty list of link dependencies, because the link
# dependencies are intended to apply to the target itself (initial is
# 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)
+ dependencies.add(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
- # executable or load the loadable_module.
- if not initial and target_type in ('executable', 'loadable_module'):
+ # Executables, mac kernel extensions, windows drivers 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 executable or load the loadable_module.
+ if not initial and target_type in ('executable', 'loadable_module',
+ 'mac_kernel_extension',
+ 'windows_driver'):
+ return dependencies
+
+ # Shared libraries are already fully linked. They should only be included
+ # in |dependencies| when adjusting static library dependencies (in order to
+ # link against the shared_library's import lib), but should not be included
+ # in |dependencies| when propagating link_settings.
+ # The |include_shared_libraries| flag controls which of these two cases we
+ # are handling.
+ if (not initial and target_type == 'shared_library' and
+ not include_shared_libraries):
return dependencies
# The target is linkable, add it to the list of link dependencies.
if self.ref not in dependencies:
- dependencies.append(self.ref)
+ dependencies.add(self.ref)
if initial or not is_linkable:
# If this is a subsequent target and it's linkable, don't look any
# further for linkable dependencies, as they'll already be linked into
# this target linkable. Always look at dependencies of the initial
# target, and always look at dependencies of non-linkables.
for dependency in self.dependencies:
- dependency.LinkDependencies(targets, dependencies, False)
+ dependency._LinkDependenciesInternal(targets,
+ include_shared_libraries,
+ dependencies, False)
return dependencies
+ def DependenciesForLinkSettings(self, targets):
+ """
+ Returns a list of dependency targets whose link_settings should be merged
+ into this target.
+ """
+
+ # TODO(sbaig) Currently, chrome depends on the bug that shared libraries'
+ # link_settings are propagated. So for now, we will allow it, unless the
+ # 'allow_sharedlib_linksettings_propagation' flag is explicitly set to
+ # False. Once chrome is fixed, we can remove this flag.
+ include_shared_libraries = \
+ targets[self.ref].get('allow_sharedlib_linksettings_propagation', True)
+ return self._LinkDependenciesInternal(targets, include_shared_libraries)
+
+ def DependenciesToLinkAgainst(self, targets):
+ """
+ Returns a list of dependency targets that are linked into this target.
+ """
+ return self._LinkDependenciesInternal(targets, True)
+
def BuildDependencyList(targets):
# Create a DependencyGraphNode for each target. Put it into a dict for easy
# access.
dependency_nodes = {}
for target, spec in targets.iteritems():
if target not in dependency_nodes:
dependency_nodes[target] = DependencyGraphNode(target)
@@ -1638,22 +1815,32 @@ def BuildDependencyList(targets):
raise GypError("Dependency '%s' not found while "
"trying to load target %s" % (dependency, target))
target_node.dependencies.append(dependency_node)
dependency_node.dependents.append(target_node)
flat_list = root_node.FlattenToList()
# If there's anything left unvisited, there must be a circular dependency
- # (cycle). If you need to figure out what's wrong, look for elements of
- # targets that are not in flat_list.
+ # (cycle).
if len(flat_list) != len(targets):
+ if not root_node.dependents:
+ # If all targets have dependencies, add the first target as a dependent
+ # of root_node so that the cycle can be discovered from root_node.
+ target = targets.keys()[0]
+ target_node = dependency_nodes[target]
+ target_node.dependencies.append(root_node)
+ root_node.dependents.append(target_node)
+
+ cycles = []
+ for cycle in root_node.FindCycles():
+ paths = [node.ref for node in cycle]
+ cycles.append('Cycle: %s' % ' -> '.join(paths))
raise DependencyGraphNode.CircularException(
- 'Some targets not reachable, cycle in dependency graph detected: ' +
- ' '.join(set(flat_list) ^ set(targets)))
+ 'Cycles in dependency graph detected:\n' + '\n'.join(cycles))
return [dependency_nodes, flat_list]
def VerifyNoGYPFileCircularDependencies(targets):
# Create a DependencyGraphNode for each gyp file containing a target. Put
# it into a dict for easy access.
dependency_nodes = {}
@@ -1693,41 +1880,46 @@ def VerifyNoGYPFileCircularDependencies(
build_file_node.dependencies.append(root_node)
root_node.dependents.append(build_file_node)
flat_list = root_node.FlattenToList()
# If there's anything left unvisited, there must be a circular dependency
# (cycle).
if len(flat_list) != len(dependency_nodes):
- bad_files = []
- for file in dependency_nodes.iterkeys():
- if not file in flat_list:
- bad_files.append(file)
- raise DependencyGraphNode.CircularException, \
- 'Some files not reachable, cycle in .gyp file dependency graph ' + \
- 'detected involving some or all of: ' + \
- ' '.join(bad_files)
+ if not root_node.dependents:
+ # If all files have dependencies, add the first file as a dependent
+ # of root_node so that the cycle can be discovered from root_node.
+ file_node = dependency_nodes.values()[0]
+ file_node.dependencies.append(root_node)
+ root_node.dependents.append(file_node)
+ cycles = []
+ for cycle in root_node.FindCycles():
+ paths = [node.ref for node in cycle]
+ cycles.append('Cycle: %s' % ' -> '.join(paths))
+ raise DependencyGraphNode.CircularException(
+ 'Cycles in .gyp file dependency graph detected:\n' + '\n'.join(cycles))
def DoDependentSettings(key, flat_list, targets, dependency_nodes):
# key should be one of all_dependent_settings, direct_dependent_settings,
# or link_settings.
for target in flat_list:
target_dict = targets[target]
build_file = gyp.common.BuildFile(target)
if key == 'all_dependent_settings':
dependencies = dependency_nodes[target].DeepDependencies()
elif key == 'direct_dependent_settings':
dependencies = \
dependency_nodes[target].DirectAndImportedDependencies(targets)
elif key == 'link_settings':
- dependencies = dependency_nodes[target].LinkDependencies(targets)
+ dependencies = \
+ dependency_nodes[target].DependenciesForLinkSettings(targets)
else:
raise GypError("DoDependentSettings doesn't know how to determine "
'dependencies for ' + key)
for dependency in dependencies:
dependency_dict = targets[dependency]
if not key in dependency_dict:
continue
@@ -1790,17 +1982,18 @@ def AdjustStaticLibraryDependencies(flat
else:
del target_dict['dependencies']
elif target_type in linkable_types:
# Get a list of dependency targets that should be linked into this
# target. Add them to the dependencies list if they're not already
# present.
- link_dependencies = dependency_nodes[target].LinkDependencies(targets)
+ link_dependencies = \
+ dependency_nodes[target].DependenciesToLinkAgainst(targets)
for dependency in link_dependencies:
if dependency == target:
continue
if not 'dependencies' in target_dict:
target_dict['dependencies'] = []
if not dependency in target_dict['dependencies']:
target_dict['dependencies'].append(dependency)
# Sort the dependencies list in the order from dependents to dependencies.
@@ -1844,66 +2037,63 @@ def MakePathRelative(to_file, fro_file,
gyp.common.RelativePath(os.path.dirname(fro_file),
os.path.dirname(to_file)),
item)).replace('\\', '/')
if item[-1] == '/':
ret += '/'
return ret
def MergeLists(to, fro, to_file, fro_file, is_paths=False, append=True):
- def is_hashable(x):
- try:
- hash(x)
- except TypeError:
- return False
- return True
+ # Python documentation recommends objects which do not support hash
+ # set this value to None. Python library objects follow this rule.
+ is_hashable = lambda val: val.__hash__
+
# If x is hashable, returns whether x is in s. Else returns whether x is in l.
def is_in_set_or_list(x, s, l):
if is_hashable(x):
return x in s
return x in l
prepend_index = 0
# Make membership testing of hashables in |to| (in particular, strings)
# faster.
- hashable_to_set = set([x for x in to if is_hashable(x)])
-
+ hashable_to_set = set(x for x in to if is_hashable(x))
for item in fro:
singleton = False
- if isinstance(item, str) or isinstance(item, int):
+ if type(item) in (str, int):
# The cheap and easy case.
if is_paths:
to_item = MakePathRelative(to_file, fro_file, item)
else:
to_item = item
- if not isinstance(item, str) or not item.startswith('-'):
+ if not (type(item) is str and item.startswith('-')):
# Any string that doesn't begin with a "-" is a singleton - it can
# only appear once in a list, to be enforced by the list merge append
# or prepend.
singleton = True
- elif isinstance(item, dict):
+ elif type(item) is dict:
# Make a copy of the dictionary, continuing to look for paths to fix.
# The other intelligent aspects of merge processing won't apply because
# item is being merged into an empty dict.
to_item = {}
MergeDicts(to_item, item, to_file, fro_file)
- elif isinstance(item, list):
+ elif type(item) is list:
# Recurse, making a copy of the list. If the list contains any
# descendant dicts, path fixing will occur. Note that here, custom
# values for is_paths and append are dropped; those are only to be
# applied to |to| and |fro|, not sublists of |fro|. append shouldn't
# matter anyway because the new |to_item| list is empty.
to_item = []
MergeLists(to_item, item, to_file, fro_file)
else:
- raise TypeError, \
+ raise TypeError(
'Attempt to merge list item of unsupported type ' + \
- item.__class__.__name__
+ item.__class__.__name__)
if append:
# If appending a singleton that's already in the list, don't append.
# This ensures that the earliest occurrence of the item will stay put.
if not singleton or not is_in_set_or_list(to_item, hashable_to_set, to):
to.append(to_item)
if is_hashable(to_item):
hashable_to_set.add(to_item)
@@ -1928,40 +2118,40 @@ def MergeDicts(to, fro, to_file, fro_fil
for k, v in fro.iteritems():
# It would be nice to do "if not k in to: to[k] = v" but that wouldn't give
# copy semantics. Something else may want to merge from the |fro| dict
# later, and having the same dict ref pointed to twice in the tree isn't
# what anyone wants considering that the dicts may subsequently be
# modified.
if k in to:
bad_merge = False
- if isinstance(v, str) or isinstance(v, int):
- if not (isinstance(to[k], str) or isinstance(to[k], int)):
+ if type(v) in (str, int):
+ if type(to[k]) not in (str, int):
bad_merge = True
- elif v.__class__ != to[k].__class__:
+ elif type(v) is not type(to[k]):
bad_merge = True
if bad_merge:
- raise TypeError, \
+ raise TypeError(
'Attempt to merge dict value of type ' + v.__class__.__name__ + \
' into incompatible type ' + to[k].__class__.__name__ + \
- ' for key ' + k
- if isinstance(v, str) or isinstance(v, int):
+ ' for key ' + k)
+ if type(v) in (str, int):
# Overwrite the existing value, if any. Cheap and easy.
is_path = IsPathSection(k)
if is_path:
to[k] = MakePathRelative(to_file, fro_file, v)
else:
to[k] = v
- elif isinstance(v, dict):
+ elif type(v) is dict:
# Recurse, guaranteeing copies will be made of objects that require it.
if not k in to:
to[k] = {}
MergeDicts(to[k], v, to_file, fro_file)
- elif isinstance(v, list):
+ elif type(v) is list:
# Lists in dicts can be merged with different policies, depending on
# how the key in the "from" dict (k, the from-key) is written.
#
# If the from-key has ...the to-list will have this action
# this character appended:... applied when receiving the from-list:
# = replace
# + prepend
# ? set, only if to-list does not yet exist
@@ -1994,37 +2184,37 @@ def MergeDicts(to, fro, to_file, fro_fil
raise GypError('Incompatible list policies ' + k + ' and ' +
list_incompatible)
if list_base in to:
if ext == '?':
# If the key ends in "?", the list will only be merged if it doesn't
# already exist.
continue
- if not isinstance(to[list_base], list):
+ elif type(to[list_base]) is not list:
# This may not have been checked above if merging in a list with an
# extension character.
- raise TypeError, \
+ raise TypeError(
'Attempt to merge dict value of type ' + v.__class__.__name__ + \
' into incompatible type ' + to[list_base].__class__.__name__ + \
- ' for key ' + list_base + '(' + k + ')'
+ ' for key ' + list_base + '(' + k + ')')
else:
to[list_base] = []
# Call MergeLists, which will make copies of objects that require it.
# MergeLists can recurse back into MergeDicts, although this will be
# to make copies of dicts (with paths fixed), there will be no
# subsequent dict "merging" once entering a list because lists are
# always replaced, appended to, or prepended to.
is_paths = IsPathSection(list_base)
MergeLists(to[list_base], v, to_file, fro_file, is_paths, append)
else:
- raise TypeError, \
+ raise TypeError(
'Attempt to merge dict value of unsupported type ' + \
- v.__class__.__name__ + ' for key ' + k
+ v.__class__.__name__ + ' for key ' + k)
def MergeConfigWithInheritance(new_configuration_dict, build_file,
target_dict, configuration, visited):
# Skip if previously visted.
if configuration in visited:
return
@@ -2055,53 +2245,49 @@ def SetUpConfigurations(target, target_d
build_file = gyp.common.BuildFile(target)
# Provide a single configuration by default if none exists.
# TODO(mark): Signal an error if default_configurations exists but
# configurations does not.
if not 'configurations' in target_dict:
target_dict['configurations'] = {'Default': {}}
if not 'default_configuration' in target_dict:
- concrete = [i for i in target_dict['configurations'].keys()
- if not target_dict['configurations'][i].get('abstract')]
+ concrete = [i for (i, config) in target_dict['configurations'].iteritems()
+ if not config.get('abstract')]
target_dict['default_configuration'] = sorted(concrete)[0]
- for configuration in target_dict['configurations'].keys():
- old_configuration_dict = target_dict['configurations'][configuration]
+ merged_configurations = {}
+ configs = target_dict['configurations']
+ for (configuration, old_configuration_dict) in configs.iteritems():
# Skip abstract configurations (saves work only).
if old_configuration_dict.get('abstract'):
continue
# Configurations inherit (most) settings from the enclosing target scope.
# Get the inheritance relationship right by making a copy of the target
# dict.
- new_configuration_dict = copy.deepcopy(target_dict)
-
- # Take out the bits that don't belong in a "configurations" section.
- # Since configuration setup is done before conditional, exclude, and rules
- # processing, be careful with handling of the suffix characters used in
- # those phases.
- delete_keys = []
- for key in new_configuration_dict:
+ new_configuration_dict = {}
+ for (key, target_val) in target_dict.iteritems():
key_ext = key[-1:]
if key_ext in key_suffixes:
key_base = key[:-1]
else:
key_base = key
- if key_base in non_configuration_keys:
- delete_keys.append(key)
-
- for key in delete_keys:
- del new_configuration_dict[key]
+ if not key_base in non_configuration_keys:
+ new_configuration_dict[key] = gyp.simple_copy.deepcopy(target_val)
# Merge in configuration (with all its parents first).
MergeConfigWithInheritance(new_configuration_dict, build_file,
target_dict, configuration, [])
- # Put the new result back into the target dict as a configuration.
- target_dict['configurations'][configuration] = new_configuration_dict
+ merged_configurations[configuration] = new_configuration_dict
+
+ # Put the new configurations back into the target dict as a configuration.
+ for configuration in merged_configurations.keys():
+ target_dict['configurations'][configuration] = (
+ merged_configurations[configuration])
# Now drop all the abstract ones.
for configuration in target_dict['configurations'].keys():
old_configuration_dict = target_dict['configurations'][configuration]
if old_configuration_dict.get('abstract'):
del target_dict['configurations'][configuration]
# Now that all of the target's configurations have been built, go through
@@ -2162,33 +2348,34 @@ def ProcessListFiltersInDict(name, the_d
lists = []
del_lists = []
for key, value in the_dict.iteritems():
operation = key[-1]
if operation != '!' and operation != '/':
continue
- if not isinstance(value, list):
- raise ValueError, name + ' key ' + key + ' must be list, not ' + \
- value.__class__.__name__
+ if type(value) is not list:
+ raise ValueError(name + ' key ' + key + ' must be list, not ' + \
+ value.__class__.__name__)
list_key = key[:-1]
if list_key not in the_dict:
# This happens when there's a list like "sources!" but no corresponding
# "sources" list. Since there's nothing for it to operate on, queue up
# the "sources!" list for deletion now.
del_lists.append(key)
continue
- if not isinstance(the_dict[list_key], list):
- raise ValueError, name + ' key ' + list_key + \
- ' must be list, not ' + \
- value.__class__.__name__ + ' when applying ' + \
- {'!': 'exclusion', '/': 'regex'}[operation]
+ if type(the_dict[list_key]) is not list:
+ value = the_dict[list_key]
+ raise ValueError(name + ' key ' + list_key + \
+ ' must be list, not ' + \
+ value.__class__.__name__ + ' when applying ' + \
+ {'!': 'exclusion', '/': 'regex'}[operation])
if not list_key in lists:
lists.append(list_key)
# Delete the lists that are known to be unneeded at this point.
for del_list in del_lists:
del the_dict[del_list]
@@ -2227,18 +2414,18 @@ def ProcessListFiltersInDict(name, the_d
if action == 'exclude':
# This item matches an exclude regex, so set its value to 0 (exclude).
action_value = 0
elif action == 'include':
# This item matches an include regex, so set its value to 1 (include).
action_value = 1
else:
# This is an action that doesn't make any sense.
- raise ValueError, 'Unrecognized action ' + action + ' in ' + name + \
- ' key ' + regex_key
+ raise ValueError('Unrecognized action ' + action + ' in ' + name + \
+ ' key ' + regex_key)
for index in xrange(0, len(the_list)):
list_item = the_list[index]
if list_actions[index] == action_value:
# Even if the regex matches, nothing will change so continue (regex
# searches are expensive).
continue
if pattern_re.search(list_item):
@@ -2275,56 +2462,58 @@ def ProcessListFiltersInDict(name, the_d
# If anything was excluded, put the excluded list into the_dict at
# excluded_key.
if len(excluded_list) > 0:
the_dict[excluded_key] = excluded_list
# Now recurse into subdicts and lists that may contain dicts.
for key, value in the_dict.iteritems():
- if isinstance(value, dict):
+ if type(value) is dict:
ProcessListFiltersInDict(key, value)
- elif isinstance(value, list):
+ elif type(value) is list:
ProcessListFiltersInList(key, value)
def ProcessListFiltersInList(name, the_list):
for item in the_list:
- if isinstance(item, dict):
+ if type(item) is dict:
ProcessListFiltersInDict(name, item)
- elif isinstance(item, list):
+ elif type(item) is list:
ProcessListFiltersInList(name, item)
def ValidateTargetType(target, target_dict):
"""Ensures the 'type' field on the target is one of the known types.
Arguments:
target: string, name of target.
target_dict: dict, target spec.
Raises an exception on error.
"""
VALID_TARGET_TYPES = ('executable', 'loadable_module',
'static_library', 'shared_library',
- 'none')
+ 'mac_kernel_extension', 'none', 'windows_driver')
target_type = target_dict.get('type', None)
if target_type not in VALID_TARGET_TYPES:
raise GypError("Target %s has an invalid target type '%s'. "
"Must be one of %s." %
(target, target_type, '/'.join(VALID_TARGET_TYPES)))
if (target_dict.get('standalone_static_library', 0) and
not target_type == 'static_library'):
raise GypError('Target %s has type %s but standalone_static_library flag is'
' only valid for static_library type.' % (target,
target_type))
-def ValidateSourcesInTarget(target, target_dict, build_file):
- # TODO: Check if MSVC allows this for non-static_library targets.
+def ValidateSourcesInTarget(target, target_dict, build_file,
+ duplicate_basename_check):
+ if not duplicate_basename_check:
+ return
if target_dict.get('type', None) != 'static_library':
return
sources = target_dict.get('sources', [])
basenames = {}
for source in sources:
name, ext = os.path.splitext(source)
is_compiled_file = ext in [
'.c', '.cc', '.cpp', '.cxx', '.m', '.mm', '.s', '.S']
@@ -2335,18 +2524,18 @@ def ValidateSourcesInTarget(target, targ
error = ''
for basename, files in basenames.iteritems():
if len(files) > 1:
error += ' %s: %s\n' % (basename, ' '.join(files))
if error:
print('static library %s has several files with the same basename:\n' %
- target + error + 'Some build systems, e.g. MSVC08, '
- 'cannot handle that.')
+ target + error + 'libtool on Mac cannot handle that. Use '
+ '--no-duplicate-basename-check to disable this validation.')
raise GypError('Duplicate basenames in sources section, see list above')
def ValidateRulesInTarget(target, target_dict, extra_sources_for_rules):
"""Ensures that the rules sections in target_dict are valid and consistent,
and determines which sources they apply to.
Arguments:
@@ -2366,72 +2555,73 @@ def ValidateRulesInTarget(target, target
# Make sure that there's no conflict among rule names and extensions.
rule_name = rule['rule_name']
if rule_name in rule_names:
raise GypError('rule %s exists in duplicate, target %s' %
(rule_name, target))
rule_names[rule_name] = rule
rule_extension = rule['extension']
+ if rule_extension.startswith('.'):
+ rule_extension = rule_extension[1:]
if rule_extension in rule_extensions:
raise GypError(('extension %s associated with multiple rules, ' +
'target %s rules %s and %s') %
(rule_extension, target,
rule_extensions[rule_extension]['rule_name'],
rule_name))
rule_extensions[rule_extension] = rule
# Make sure rule_sources isn't already there. It's going to be
# created below if needed.
if 'rule_sources' in rule:
raise GypError(
'rule_sources must not exist in input, target %s rule %s' %
(target, rule_name))
- extension = rule['extension']
rule_sources = []
source_keys = ['sources']
source_keys.extend(extra_sources_for_rules)
for source_key in source_keys:
for source in target_dict.get(source_key, []):
(source_root, source_extension) = os.path.splitext(source)
if source_extension.startswith('.'):
source_extension = source_extension[1:]
- if source_extension == extension:
+ if source_extension == rule_extension:
rule_sources.append(source)
if len(rule_sources) > 0:
rule['rule_sources'] = rule_sources
def ValidateRunAsInTarget(target, target_dict, build_file):
target_name = target_dict.get('target_name')
run_as = target_dict.get('run_as')
if not run_as:
return
- if not isinstance(run_as, dict):
+ if type(run_as) is not dict:
raise GypError("The 'run_as' in target %s from file %s should be a "
"dictionary." %
(target_name, build_file))
action = run_as.get('action')
if not action:
raise GypError("The 'run_as' in target %s from file %s must have an "
"'action' section." %
(target_name, build_file))
- if not isinstance(action, list):
+ if type(action) is not list:
raise GypError("The 'action' for 'run_as' in target %s from file %s "
"must be a list." %
(target_name, build_file))
working_directory = run_as.get('working_directory')
- if working_directory and not isinstance(working_directory, str):
+ if working_directory and type(working_directory) is not str:
raise GypError("The 'working_directory' for 'run_as' in target %s "
"in file %s should be a string." %
(target_name, build_file))
environment = run_as.get('environment')
- if environment and not isinstance(environment, dict):
+ if environment and type(environment) is not dict:
raise GypError("The 'environment' for 'run_as' in target %s "
"in file %s should be a dictionary." %
(target_name, build_file))
def ValidateActionsInTarget(target, target_dict, build_file):
'''Validates the inputs to the actions in a target.'''
target_name = target_dict.get('target_name')
@@ -2451,42 +2641,77 @@ def ValidateActionsInTarget(target, targ
def TurnIntIntoStrInDict(the_dict):
"""Given dict the_dict, recursively converts all integers into strings.
"""
# Use items instead of iteritems because there's no need to try to look at
# reinserted keys and their associated values.
for k, v in the_dict.items():
- if isinstance(v, int):
+ if type(v) is int:
v = str(v)
the_dict[k] = v
- elif isinstance(v, dict):
+ elif type(v) is dict:
TurnIntIntoStrInDict(v)
- elif isinstance(v, list):
+ elif type(v) is list:
TurnIntIntoStrInList(v)
- if isinstance(k, int):
+ if type(k) is int:
+ del the_dict[k]
the_dict[str(k)] = v
- del the_dict[k]
def TurnIntIntoStrInList(the_list):
"""Given list the_list, recursively converts all integers into strings.
"""
for index in xrange(0, len(the_list)):
item = the_list[index]
- if isinstance(item, int):
+ if type(item) is int:
the_list[index] = str(item)
- elif isinstance(item, dict):
+ elif type(item) is dict:
TurnIntIntoStrInDict(item)
- elif isinstance(item, list):
+ elif type(item) is list:
TurnIntIntoStrInList(item)
+def PruneUnwantedTargets(targets, flat_list, dependency_nodes, root_targets,
+ data):
+ """Return only the targets that are deep dependencies of |root_targets|."""
+ qualified_root_targets = []
+ for target in root_targets:
+ target = target.strip()
+ qualified_targets = gyp.common.FindQualifiedTargets(target, flat_list)
+ if not qualified_targets:
+ raise GypError("Could not find target %s" % target)
+ qualified_root_targets.extend(qualified_targets)
+
+ wanted_targets = {}
+ for target in qualified_root_targets:
+ wanted_targets[target] = targets[target]
+ for dependency in dependency_nodes[target].DeepDependencies():
+ wanted_targets[dependency] = targets[dependency]
+
+ wanted_flat_list = [t for t in flat_list if t in wanted_targets]
+
+ # Prune unwanted targets from each build_file's data dict.
+ for build_file in data['target_build_files']:
+ if not 'targets' in data[build_file]:
+ continue
+ new_targets = []
+ for target in data[build_file]['targets']:
+ qualified_name = gyp.common.QualifiedTarget(build_file,
+ target['target_name'],
+ target['toolset'])
+ if qualified_name in wanted_targets:
+ new_targets.append(target)
+ data[build_file]['targets'] = new_targets
+
+ return wanted_targets, wanted_flat_list
+
+
def VerifyNoCollidingTargets(targets):
"""Verify that no two targets in the same directory share the same name.
Arguments:
targets: A list of targets in the form 'path/to/file.gyp:target_name'.
"""
# Keep a dict going from 'subdirectory:target_name' to 'foo.gyp'.
used = {}
@@ -2504,78 +2729,83 @@ def VerifyNoCollidingTargets(targets):
key = subdir + ':' + name
if key in used:
# Complain if this target is already used.
raise GypError('Duplicate target name "%s" in directory "%s" used both '
'in "%s" and "%s".' % (name, subdir, gyp, used[key]))
used[key] = gyp
-def Load(build_files, variables, includes, depth, generator_input_info, check,
- circular_check, parallel):
+def SetGeneratorGlobals(generator_input_info):
# Set up path_sections and non_configuration_keys with the default data plus
- # the generator-specifc data.
+ # the generator-specific data.
global path_sections
- path_sections = base_path_sections[:]
- path_sections.extend(generator_input_info['path_sections'])
+ path_sections = set(base_path_sections)
+ path_sections.update(generator_input_info['path_sections'])
global non_configuration_keys
non_configuration_keys = base_non_configuration_keys[:]
non_configuration_keys.extend(generator_input_info['non_configuration_keys'])
- # TODO(mark) handle variants if the generator doesn't want them directly.
- generator_handles_variants = \
- generator_input_info['generator_handles_variants']
-
- global absolute_build_file_paths
- absolute_build_file_paths = \
- generator_input_info['generator_wants_absolute_build_file_paths']
-
global multiple_toolsets
multiple_toolsets = generator_input_info[
'generator_supports_multiple_toolsets']
+ global generator_filelist_paths
+ generator_filelist_paths = generator_input_info['generator_filelist_paths']
+
+
+def Load(build_files, variables, includes, depth, generator_input_info, check,
+ circular_check, duplicate_basename_check, parallel, root_targets):
+ SetGeneratorGlobals(generator_input_info)
# A generator can have other lists (in addition to sources) be processed
# for rules.
extra_sources_for_rules = generator_input_info['extra_sources_for_rules']
# Load build files. This loads every target-containing build file into
# the |data| dictionary such that the keys to |data| are build file names,
# and the values are the entire build file contents after "early" or "pre"
# processing has been done and includes have been resolved.
# NOTE: data contains both "target" files (.gyp) and "includes" (.gypi), as
# well as meta-data (e.g. 'included_files' key). 'target_build_files' keeps
# track of the keys corresponding to "target" files.
data = {'target_build_files': set()}
- aux_data = {}
- for build_file in build_files:
- # Normalize paths everywhere. This is important because paths will be
- # used as keys to the data dict and for references between input files.
- build_file = os.path.normpath(build_file)
- try:
- if parallel:
- print >>sys.stderr, 'Using parallel processing (experimental).'
- LoadTargetBuildFileParallel(build_file, data, aux_data,
- variables, includes, depth, check)
- else:
+ # Normalize paths everywhere. This is important because paths will be
+ # used as keys to the data dict and for references between input files.
+ build_files = set(map(os.path.normpath, build_files))
+ if parallel:
+ LoadTargetBuildFilesParallel(build_files, data, variables, includes, depth,
+ check, generator_input_info)
+ else:
+ aux_data = {}
+ for build_file in build_files:
+ try:
LoadTargetBuildFile(build_file, data, aux_data,
variables, includes, depth, check, True)
- except Exception, e:
- gyp.common.ExceptionAppend(e, 'while trying to load %s' % build_file)
- raise
+ except Exception, e:
+ gyp.common.ExceptionAppend(e, 'while trying to load %s' % build_file)
+ raise
# Build a dict to access each target's subdict by qualified name.
targets = BuildTargetsDict(data)
# Fully qualify all dependency links.
QualifyDependencies(targets)
+ # Remove self-dependencies from targets that have 'prune_self_dependencies'
+ # set to 1.
+ RemoveSelfDependencies(targets)
+
# Expand dependencies specified as build_file:*.
ExpandWildcardDependencies(targets, data)
+ # Remove all dependencies marked as 'link_dependency' from the targets of
+ # type 'none'.
+ RemoveLinkDependenciesFromNoneTargets(targets)
+
# Apply exclude (!) and regex (/) list filters only for dependency_sections.
for target_name, target_dict in targets.iteritems():
tmp_dict = {}
for key_base in dependency_sections:
for op in ('', '!', '/'):
key = key_base + op
if key in target_dict:
tmp_dict[key] = target_dict[key]
@@ -2590,16 +2820,22 @@ def Load(build_files, variables, include
if circular_check:
# Make sure that any targets in a.gyp don't contain dependencies in other
# .gyp files that further depend on a.gyp.
VerifyNoGYPFileCircularDependencies(targets)
[dependency_nodes, flat_list] = BuildDependencyList(targets)
+ if root_targets:
+ # Remove, from |targets| and |flat_list|, the targets that are not deep
+ # dependencies of the targets specified in |root_targets|.
+ targets, flat_list = PruneUnwantedTargets(
+ targets, flat_list, dependency_nodes, root_targets, data)
+
# Check that no two targets in the same directory have the same name.
VerifyNoCollidingTargets(flat_list)
# Handle dependent settings of various types.
for settings_type in ['all_dependent_settings',
'direct_dependent_settings',
'link_settings']:
DoDependentSettings(settings_type, flat_list, targets, dependency_nodes)
@@ -2645,20 +2881,18 @@ def Load(build_files, variables, include
# Make sure that the rules make sense, and build up rule_sources lists as
# needed. Not all generators will need to use the rule_sources lists, but
# some may, and it seems best to build the list in a common spot.
# Also validate actions and run_as elements in targets.
for target in flat_list:
target_dict = targets[target]
build_file = gyp.common.BuildFile(target)
ValidateTargetType(target, target_dict)
- # TODO(thakis): Get vpx_scale/arm/scalesystemdependent.c to be renamed to
- # scalesystemdependent_arm_additions.c or similar.
- if 'arm' not in variables.get('target_arch', ''):
- ValidateSourcesInTarget(target, target_dict, build_file)
+ ValidateSourcesInTarget(target, target_dict, build_file,
+ duplicate_basename_check)
ValidateRulesInTarget(target, target_dict, extra_sources_for_rules)
ValidateRunAsInTarget(target, target_dict, build_file)
ValidateActionsInTarget(target, target_dict, build_file)
# Generators might not expect ints. Turn them into strs.
TurnIntIntoStrInDict(data)
# TODO(mark): Return |data| for now because the generator needs a list of
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/input_test.py
@@ -0,0 +1,90 @@
+#!/usr/bin/env python
+
+# Copyright 2013 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.
+
+"""Unit tests for the input.py file."""
+
+import gyp.input
+import unittest
+import sys
+
+
+class TestFindCycles(unittest.TestCase):
+ def setUp(self):
+ self.nodes = {}
+ for x in ('a', 'b', 'c', 'd', 'e'):
+ self.nodes[x] = gyp.input.DependencyGraphNode(x)
+
+ def _create_dependency(self, dependent, dependency):
+ dependent.dependencies.append(dependency)
+ dependency.dependents.append(dependent)
+
+ def test_no_cycle_empty_graph(self):
+ for label, node in self.nodes.iteritems():
+ self.assertEquals([], node.FindCycles())
+
+ def test_no_cycle_line(self):
+ self._create_dependency(self.nodes['a'], self.nodes['b'])
+ self._create_dependency(self.nodes['b'], self.nodes['c'])
+ self._create_dependency(self.nodes['c'], self.nodes['d'])
+
+ for label, node in self.nodes.iteritems():
+ self.assertEquals([], node.FindCycles())
+
+ def test_no_cycle_dag(self):
+ self._create_dependency(self.nodes['a'], self.nodes['b'])
+ self._create_dependency(self.nodes['a'], self.nodes['c'])
+ self._create_dependency(self.nodes['b'], self.nodes['c'])
+
+ for label, node in self.nodes.iteritems():
+ self.assertEquals([], node.FindCycles())
+
+ def test_cycle_self_reference(self):
+ self._create_dependency(self.nodes['a'], self.nodes['a'])
+
+ self.assertEquals([[self.nodes['a'], self.nodes['a']]],
+ self.nodes['a'].FindCycles())
+
+ def test_cycle_two_nodes(self):
+ self._create_dependency(self.nodes['a'], self.nodes['b'])
+ self._create_dependency(self.nodes['b'], self.nodes['a'])
+
+ self.assertEquals([[self.nodes['a'], self.nodes['b'], self.nodes['a']]],
+ self.nodes['a'].FindCycles())
+ self.assertEquals([[self.nodes['b'], self.nodes['a'], self.nodes['b']]],
+ self.nodes['b'].FindCycles())
+
+ def test_two_cycles(self):
+ self._create_dependency(self.nodes['a'], self.nodes['b'])
+ self._create_dependency(self.nodes['b'], self.nodes['a'])
+
+ self._create_dependency(self.nodes['b'], self.nodes['c'])
+ self._create_dependency(self.nodes['c'], self.nodes['b'])
+
+ cycles = self.nodes['a'].FindCycles()
+ self.assertTrue(
+ [self.nodes['a'], self.nodes['b'], self.nodes['a']] in cycles)
+ self.assertTrue(
+ [self.nodes['b'], self.nodes['c'], self.nodes['b']] in cycles)
+ self.assertEquals(2, len(cycles))
+
+ def test_big_cycle(self):
+ self._create_dependency(self.nodes['a'], self.nodes['b'])
+ self._create_dependency(self.nodes['b'], self.nodes['c'])
+ self._create_dependency(self.nodes['c'], self.nodes['d'])
+ self._create_dependency(self.nodes['d'], self.nodes['e'])
+ self._create_dependency(self.nodes['e'], self.nodes['a'])
+
+ self.assertEquals([[self.nodes['a'],
+ self.nodes['b'],
+ self.nodes['c'],
+ self.nodes['d'],
+ self.nodes['e'],
+ self.nodes['a']]],
+ self.nodes['a'].FindCycles())
+
+
+if __name__ == '__main__':
+ unittest.main()
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/mac_tool.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/mac_tool.py
@@ -4,23 +4,28 @@
# found in the LICENSE file.
"""Utility functions to perform Xcode-style build steps.
These functions are executed via gyp-mac-tool when using the Makefile generator.
"""
import fcntl
+import fnmatch
+import glob
+import json
import os
import plistlib
import re
import shutil
import string
+import struct
import subprocess
import sys
+import tempfile
def main(args):
executor = MacTool()
exit_code = executor.Dispatch(args)
if exit_code is not None:
sys.exit(exit_code)
@@ -36,104 +41,187 @@ class MacTool(object):
method = "Exec%s" % self._CommandifyName(args[0])
return getattr(self, method)(*args[1:])
def _CommandifyName(self, name_string):
"""Transforms a tool name like copy-info-plist to CopyInfoPlist"""
return name_string.title().replace('-', '')
- def ExecCopyBundleResource(self, source, dest):
+ def ExecCopyBundleResource(self, source, dest, convert_to_binary):
"""Copies a resource file to the bundle/Resources directory, performing any
necessary compilation on each resource."""
+ convert_to_binary = convert_to_binary == 'True'
extension = os.path.splitext(source)[1].lower()
if os.path.isdir(source):
# Copy tree.
+ # TODO(thakis): This copies file attributes like mtime, while the
+ # single-file branch below doesn't. This should probably be changed to
+ # be consistent with the single-file branch.
if os.path.exists(dest):
shutil.rmtree(dest)
shutil.copytree(source, dest)
elif extension == '.xib':
return self._CopyXIBFile(source, dest)
- elif extension == '.strings':
+ elif extension == '.storyboard':
+ return self._CopyXIBFile(source, dest)
+ elif extension == '.strings' and not convert_to_binary:
self._CopyStringsFile(source, dest)
else:
- shutil.copyfile(source, dest)
+ if os.path.exists(dest):
+ os.unlink(dest)
+ shutil.copy(source, dest)
+
+ if convert_to_binary and extension in ('.plist', '.strings'):
+ self._ConvertToBinary(dest)
def _CopyXIBFile(self, source, dest):
"""Compiles a XIB file with ibtool into a binary plist in the bundle."""
- tools_dir = os.environ.get('DEVELOPER_BIN_DIR', '/usr/bin')
- args = [os.path.join(tools_dir, 'ibtool'), '--errors', '--warnings',
- '--notices', '--output-format', 'human-readable-text', '--compile',
- dest, source]
+
+ # ibtool sometimes crashes with relative paths. See crbug.com/314728.
+ base = os.path.dirname(os.path.realpath(__file__))
+ if os.path.relpath(source):
+ source = os.path.join(base, source)
+ if os.path.relpath(dest):
+ dest = os.path.join(base, dest)
+
+ args = ['xcrun', 'ibtool', '--errors', '--warnings', '--notices']
+
+ if os.environ['XCODE_VERSION_ACTUAL'] > '0700':
+ args.extend(['--auto-activate-custom-fonts'])
+ if 'IPHONEOS_DEPLOYMENT_TARGET' in os.environ:
+ args.extend([
+ '--target-device', 'iphone', '--target-device', 'ipad',
+ '--minimum-deployment-target',
+ os.environ['IPHONEOS_DEPLOYMENT_TARGET'],
+ ])
+ else:
+ args.extend([
+ '--target-device', 'mac',
+ '--minimum-deployment-target',
+ os.environ['MACOSX_DEPLOYMENT_TARGET'],
+ ])
+
+ args.extend(['--output-format', 'human-readable-text', '--compile', dest,
+ source])
+
ibtool_section_re = re.compile(r'/\*.*\*/')
ibtool_re = re.compile(r'.*note:.*is clipping its content')
ibtoolout = subprocess.Popen(args, stdout=subprocess.PIPE)
current_section_header = None
for line in ibtoolout.stdout:
if ibtool_section_re.match(line):
current_section_header = line
elif not ibtool_re.match(line):
if current_section_header:
sys.stdout.write(current_section_header)
current_section_header = None
sys.stdout.write(line)
return ibtoolout.returncode
+ def _ConvertToBinary(self, dest):
+ subprocess.check_call([
+ 'xcrun', 'plutil', '-convert', 'binary1', '-o', dest, dest])
+
def _CopyStringsFile(self, source, dest):
"""Copies a .strings file using iconv to reconvert the input into UTF-16."""
input_code = self._DetectInputEncoding(source) or "UTF-8"
- fp = open(dest, 'w')
- args = ['/usr/bin/iconv', '--from-code', input_code, '--to-code',
- 'UTF-16', source]
- subprocess.call(args, stdout=fp)
+
+ # Xcode's CpyCopyStringsFile / builtin-copyStrings seems to call
+ # CFPropertyListCreateFromXMLData() behind the scenes; at least it prints
+ # CFPropertyListCreateFromXMLData(): Old-style plist parser: missing
+ # semicolon in dictionary.
+ # on invalid files. Do the same kind of validation.
+ import CoreFoundation
+ s = open(source, 'rb').read()
+ d = CoreFoundation.CFDataCreate(None, s, len(s))
+ _, error = CoreFoundation.CFPropertyListCreateFromXMLData(None, d, 0, None)
+ if error:
+ return
+
+ fp = open(dest, 'wb')
+ fp.write(s.decode(input_code).encode('UTF-16'))
fp.close()
def _DetectInputEncoding(self, file_name):
"""Reads the first few bytes from file_name and tries to guess the text
encoding. Returns None as a guess if it can't detect it."""
fp = open(file_name, 'rb')
try:
header = fp.read(3)
except e:
fp.close()
return None
fp.close()
if header.startswith("\xFE\xFF"):
- return "UTF-16BE"
+ return "UTF-16"
elif header.startswith("\xFF\xFE"):
- return "UTF-16LE"
+ return "UTF-16"
elif header.startswith("\xEF\xBB\xBF"):
return "UTF-8"
else:
return None
- def ExecCopyInfoPlist(self, source, dest):
+ def ExecCopyInfoPlist(self, source, dest, convert_to_binary, *keys):
"""Copies the |source| Info.plist to the destination directory |dest|."""
# Read the source Info.plist into memory.
fd = open(source, 'r')
lines = fd.read()
fd.close()
+ # Insert synthesized key/value pairs (e.g. BuildMachineOSBuild).
+ plist = plistlib.readPlistFromString(lines)
+ if keys:
+ plist = dict(plist.items() + json.loads(keys[0]).items())
+ lines = plistlib.writePlistToString(plist)
+
# Go through all the environment variables and replace them as variables in
# the file.
+ IDENT_RE = re.compile(r'[_/\s]')
for key in os.environ:
if key.startswith('_'):
continue
evar = '${%s}' % key
- lines = string.replace(lines, evar, os.environ[key])
+ evalue = os.environ[key]
+ lines = string.replace(lines, evar, evalue)
+
+ # Xcode supports various suffices on environment variables, which are
+ # all undocumented. :rfc1034identifier is used in the standard project
+ # template these days, and :identifier was used earlier. They are used to
+ # convert non-url characters into things that look like valid urls --
+ # except that the replacement character for :identifier, '_' isn't valid
+ # in a URL either -- oops, hence :rfc1034identifier was born.
+ evar = '${%s:identifier}' % key
+ evalue = IDENT_RE.sub('_', os.environ[key])
+ lines = string.replace(lines, evar, evalue)
+
+ evar = '${%s:rfc1034identifier}' % key
+ evalue = IDENT_RE.sub('-', os.environ[key])
+ lines = string.replace(lines, evar, evalue)
+
+ # Remove any keys with values that haven't been replaced.
+ lines = lines.split('\n')
+ for i in range(len(lines)):
+ if lines[i].strip().startswith("<string>${"):
+ lines[i] = None
+ lines[i - 1] = None
+ lines = '\n'.join(filter(lambda x: x is not None, lines))
# Write out the file with variables replaced.
fd = open(dest, 'w')
fd.write(lines)
fd.close()
# Now write out PkgInfo file now that the Info.plist file has been
# "compiled".
self._WritePkgInfo(dest)
+ if convert_to_binary == 'True':
+ self._ConvertToBinary(dest)
+
def _WritePkgInfo(self, info_plist):
"""This writes the PkgInfo file from the data stored in Info.plist."""
plist = plistlib.readPlist(info_plist)
if not plist:
return
# Only create PkgInfo for executable types.
package_type = plist['CFBundlePackageType']
@@ -150,30 +238,66 @@ class MacTool(object):
dest = os.path.join(os.path.dirname(info_plist), 'PkgInfo')
fp = open(dest, 'w')
fp.write('%s%s' % (package_type, signature_code))
fp.close()
def ExecFlock(self, lockfile, *cmd_list):
"""Emulates the most basic behavior of Linux's flock(1)."""
# Rely on exception handling to report errors.
- fd = os.open(lockfile, os.O_RDONLY|os.O_NOCTTY|os.O_CREAT, 0666)
+ fd = os.open(lockfile, os.O_RDONLY|os.O_NOCTTY|os.O_CREAT, 0o666)
fcntl.flock(fd, fcntl.LOCK_EX)
return subprocess.call(cmd_list)
def ExecFilterLibtool(self, *cmd_list):
- """Calls libtool and filters out 'libtool: file: foo.o has no symbols'."""
- libtool_re = re.compile(r'^libtool: file: .* has no symbols$')
- libtoolout = subprocess.Popen(cmd_list, stderr=subprocess.PIPE)
+ """Calls libtool and filters out '/path/to/libtool: file: foo.o has no
+ symbols'."""
+ libtool_re = re.compile(r'^.*libtool: (?:for architecture: \S* )?'
+ r'file: .* has no symbols$')
+ libtool_re5 = re.compile(
+ r'^.*libtool: warning for library: ' +
+ r'.* the table of contents is empty ' +
+ r'\(no object file members in the library define global symbols\)$')
+ env = os.environ.copy()
+ # Ref:
+ # http://www.opensource.apple.com/source/cctools/cctools-809/misc/libtool.c
+ # The problem with this flag is that it resets the file mtime on the file to
+ # epoch=0, e.g. 1970-1-1 or 1969-12-31 depending on timezone.
+ env['ZERO_AR_DATE'] = '1'
+ libtoolout = subprocess.Popen(cmd_list, stderr=subprocess.PIPE, env=env)
_, err = libtoolout.communicate()
for line in err.splitlines():
- if not libtool_re.match(line):
+ if not libtool_re.match(line) and not libtool_re5.match(line):
print >>sys.stderr, line
+ # Unconditionally touch the output .a file on the command line if present
+ # and the command succeeded. A bit hacky.
+ if not libtoolout.returncode:
+ for i in range(len(cmd_list) - 1):
+ if cmd_list[i] == "-o" and cmd_list[i+1].endswith('.a'):
+ os.utime(cmd_list[i+1], None)
+ break
return libtoolout.returncode
+ def ExecPackageIosFramework(self, framework):
+ # Find the name of the binary based on the part before the ".framework".
+ binary = os.path.basename(framework).split('.')[0]
+ module_path = os.path.join(framework, 'Modules');
+ if not os.path.exists(module_path):
+ os.mkdir(module_path)
+ module_template = 'framework module %s {\n' \
+ ' umbrella header "%s.h"\n' \
+ '\n' \
+ ' export *\n' \
+ ' module * { export * }\n' \
+ '}\n' % (binary, binary)
+
+ module_file = open(os.path.join(module_path, 'module.modulemap'), "w")
+ module_file.write(module_template)
+ module_file.close()
+
def ExecPackageFramework(self, framework, version):
"""Takes a path to Something.framework and the Current version of that and
sets up all the symlinks."""
# Find the name of the binary based on the part before the ".framework".
binary = os.path.basename(framework).split('.')[0]
CURRENT = 'Current'
RESOURCES = 'Resources'
@@ -200,11 +324,389 @@ class MacTool(object):
def _Relink(self, dest, link):
"""Creates a symlink to |dest| named |link|. If |link| already exists,
it is overwritten."""
if os.path.lexists(link):
os.remove(link)
os.symlink(dest, link)
+ def ExecCompileIosFrameworkHeaderMap(self, out, framework, *all_headers):
+ framework_name = os.path.basename(framework).split('.')[0]
+ all_headers = map(os.path.abspath, all_headers)
+ filelist = {}
+ for header in all_headers:
+ filename = os.path.basename(header)
+ filelist[filename] = header
+ filelist[os.path.join(framework_name, filename)] = header
+ WriteHmap(out, filelist)
+
+ def ExecCopyIosFrameworkHeaders(self, framework, *copy_headers):
+ header_path = os.path.join(framework, 'Headers');
+ if not os.path.exists(header_path):
+ os.makedirs(header_path)
+ for header in copy_headers:
+ shutil.copy(header, os.path.join(header_path, os.path.basename(header)))
+
+ def ExecCompileXcassets(self, keys, *inputs):
+ """Compiles multiple .xcassets files into a single .car file.
+
+ This invokes 'actool' to compile all the inputs .xcassets files. The
+ |keys| arguments is a json-encoded dictionary of extra arguments to
+ pass to 'actool' when the asset catalogs contains an application icon
+ or a launch image.
+
+ Note that 'actool' does not create the Assets.car file if the asset
+ catalogs does not contains imageset.
+ """
+ command_line = [
+ 'xcrun', 'actool', '--output-format', 'human-readable-text',
+ '--compress-pngs', '--notices', '--warnings', '--errors',
+ ]
+ is_iphone_target = 'IPHONEOS_DEPLOYMENT_TARGET' in os.environ
+ if is_iphone_target:
+ platform = os.environ['CONFIGURATION'].split('-')[-1]
+ if platform not in ('iphoneos', 'iphonesimulator'):
+ platform = 'iphonesimulator'
+ command_line.extend([
+ '--platform', platform, '--target-device', 'iphone',
+ '--target-device', 'ipad', '--minimum-deployment-target',
+ os.environ['IPHONEOS_DEPLOYMENT_TARGET'], '--compile',
+ os.path.abspath(os.environ['CONTENTS_FOLDER_PATH']),
+ ])
+ else:
+ command_line.extend([
+ '--platform', 'macosx', '--target-device', 'mac',
+ '--minimum-deployment-target', os.environ['MACOSX_DEPLOYMENT_TARGET'],
+ '--compile',
+ os.path.abspath(os.environ['UNLOCALIZED_RESOURCES_FOLDER_PATH']),
+ ])
+ if keys:
+ keys = json.loads(keys)
+ for key, value in keys.iteritems():
+ arg_name = '--' + key
+ if isinstance(value, bool):
+ if value:
+ command_line.append(arg_name)
+ elif isinstance(value, list):
+ for v in value:
+ command_line.append(arg_name)
+ command_line.append(str(v))
+ else:
+ command_line.append(arg_name)
+ command_line.append(str(value))
+ # Note: actool crashes if inputs path are relative, so use os.path.abspath
+ # to get absolute path name for inputs.
+ command_line.extend(map(os.path.abspath, inputs))
+ subprocess.check_call(command_line)
+
+ def ExecMergeInfoPlist(self, output, *inputs):
+ """Merge multiple .plist files into a single .plist file."""
+ merged_plist = {}
+ for path in inputs:
+ plist = self._LoadPlistMaybeBinary(path)
+ self._MergePlist(merged_plist, plist)
+ plistlib.writePlist(merged_plist, output)
+
+ def ExecCodeSignBundle(self, key, entitlements, provisioning, path, preserve):
+ """Code sign a bundle.
+
+ This function tries to code sign an iOS bundle, following the same
+ algorithm as Xcode:
+ 1. pick the provisioning profile that best match the bundle identifier,
+ and copy it into the bundle as embedded.mobileprovision,
+ 2. copy Entitlements.plist from user or SDK next to the bundle,
+ 3. code sign the bundle.
+ """
+ substitutions, overrides = self._InstallProvisioningProfile(
+ provisioning, self._GetCFBundleIdentifier())
+ entitlements_path = self._InstallEntitlements(
+ entitlements, substitutions, overrides)
+
+ args = ['codesign', '--force', '--sign', key]
+ if preserve == 'True':
+ args.extend(['--deep', '--preserve-metadata=identifier,entitlements'])
+ else:
+ args.extend(['--entitlements', entitlements_path])
+ args.extend(['--timestamp=none', path])
+ subprocess.check_call(args)
+
+ def _InstallProvisioningProfile(self, profile, bundle_identifier):
+ """Installs embedded.mobileprovision into the bundle.
+
+ Args:
+ profile: string, optional, short name of the .mobileprovision file
+ to use, if empty or the file is missing, the best file installed
+ will be used
+ bundle_identifier: string, value of CFBundleIdentifier from Info.plist
+
+ Returns:
+ A tuple containing two dictionary: variables substitutions and values
+ to overrides when generating the entitlements file.
+ """
+ source_path, provisioning_data, team_id = self._FindProvisioningProfile(
+ profile, bundle_identifier)
+ target_path = os.path.join(
+ os.environ['BUILT_PRODUCTS_DIR'],
+ os.environ['CONTENTS_FOLDER_PATH'],
+ 'embedded.mobileprovision')
+ shutil.copy2(source_path, target_path)
+ substitutions = self._GetSubstitutions(bundle_identifier, team_id + '.')
+ return substitutions, provisioning_data['Entitlements']
+
+ def _FindProvisioningProfile(self, profile, bundle_identifier):
+ """Finds the .mobileprovision file to use for signing the bundle.
+
+ Checks all the installed provisioning profiles (or if the user specified
+ the PROVISIONING_PROFILE variable, only consult it) and select the most
+ specific that correspond to the bundle identifier.
+
+ Args:
+ profile: string, optional, short name of the .mobileprovision file
+ to use, if empty or the file is missing, the best file installed
+ will be used
+ bundle_identifier: string, value of CFBundleIdentifier from Info.plist
+
+ Returns:
+ A tuple of the path to the selected provisioning profile, the data of
+ the embedded plist in the provisioning profile and the team identifier
+ to use for code signing.
+
+ Raises:
+ SystemExit: if no .mobileprovision can be used to sign the bundle.
+ """
+ profiles_dir = os.path.join(
+ os.environ['HOME'], 'Library', 'MobileDevice', 'Provisioning Profiles')
+ if not os.path.isdir(profiles_dir):
+ print >>sys.stderr, (
+ 'cannot find mobile provisioning for %s' % bundle_identifier)
+ sys.exit(1)
+ provisioning_profiles = None
+ if profile:
+ profile_path = os.path.join(profiles_dir, profile + '.mobileprovision')
+ if os.path.exists(profile_path):
+ provisioning_profiles = [profile_path]
+ if not provisioning_profiles:
+ provisioning_profiles = glob.glob(
+ os.path.join(profiles_dir, '*.mobileprovision'))
+ valid_provisioning_profiles = {}
+ for profile_path in provisioning_profiles:
+ profile_data = self._LoadProvisioningProfile(profile_path)
+ app_id_pattern = profile_data.get(
+ 'Entitlements', {}).get('application-identifier', '')
+ for team_identifier in profile_data.get('TeamIdentifier', []):
+ app_id = '%s.%s' % (team_identifier, bundle_identifier)
+ if fnmatch.fnmatch(app_id, app_id_pattern):
+ valid_provisioning_profiles[app_id_pattern] = (
+ profile_path, profile_data, team_identifier)
+ if not valid_provisioning_profiles:
+ print >>sys.stderr, (
+ 'cannot find mobile provisioning for %s' % bundle_identifier)
+ sys.exit(1)
+ # If the user has multiple provisioning profiles installed that can be
+ # used for ${bundle_identifier}, pick the most specific one (ie. the
+ # provisioning profile whose pattern is the longest).
+ selected_key = max(valid_provisioning_profiles, key=lambda v: len(v))
+ return valid_provisioning_profiles[selected_key]
+
+ def _LoadProvisioningProfile(self, profile_path):
+ """Extracts the plist embedded in a provisioning profile.
+
+ Args:
+ profile_path: string, path to the .mobileprovision file
+
+ Returns:
+ Content of the plist embedded in the provisioning profile as a dictionary.
+ """
+ with tempfile.NamedTemporaryFile() as temp:
+ subprocess.check_call([
+ 'security', 'cms', '-D', '-i', profile_path, '-o', temp.name])
+ return self._LoadPlistMaybeBinary(temp.name)
+
+ def _MergePlist(self, merged_plist, plist):
+ """Merge |plist| into |merged_plist|."""
+ for key, value in plist.iteritems():
+ if isinstance(value, dict):
+ merged_value = merged_plist.get(key, {})
+ if isinstance(merged_value, dict):
+ self._MergePlist(merged_value, value)
+ merged_plist[key] = merged_value
+ else:
+ merged_plist[key] = value
+ else:
+ merged_plist[key] = value
+
+ def _LoadPlistMaybeBinary(self, plist_path):
+ """Loads into a memory a plist possibly encoded in binary format.
+
+ This is a wrapper around plistlib.readPlist that tries to convert the
+ plist to the XML format if it can't be parsed (assuming that it is in
+ the binary format).
+
+ Args:
+ plist_path: string, path to a plist file, in XML or binary format
+
+ Returns:
+ Content of the plist as a dictionary.
+ """
+ try:
+ # First, try to read the file using plistlib that only supports XML,
+ # and if an exception is raised, convert a temporary copy to XML and
+ # load that copy.
+ return plistlib.readPlist(plist_path)
+ except:
+ pass
+ with tempfile.NamedTemporaryFile() as temp:
+ shutil.copy2(plist_path, temp.name)
+ subprocess.check_call(['plutil', '-convert', 'xml1', temp.name])
+ return plistlib.readPlist(temp.name)
+
+ def _GetSubstitutions(self, bundle_identifier, app_identifier_prefix):
+ """Constructs a dictionary of variable substitutions for Entitlements.plist.
+
+ Args:
+ bundle_identifier: string, value of CFBundleIdentifier from Info.plist
+ app_identifier_prefix: string, value for AppIdentifierPrefix
+
+ Returns:
+ Dictionary of substitutions to apply when generating Entitlements.plist.
+ """
+ return {
+ 'CFBundleIdentifier': bundle_identifier,
+ 'AppIdentifierPrefix': app_identifier_prefix,
+ }
+
+ def _GetCFBundleIdentifier(self):
+ """Extracts CFBundleIdentifier value from Info.plist in the bundle.
+
+ Returns:
+ Value of CFBundleIdentifier in the Info.plist located in the bundle.
+ """
+ info_plist_path = os.path.join(
+ os.environ['TARGET_BUILD_DIR'],
+ os.environ['INFOPLIST_PATH'])
+ info_plist_data = self._LoadPlistMaybeBinary(info_plist_path)
+ return info_plist_data['CFBundleIdentifier']
+
+ def _InstallEntitlements(self, entitlements, substitutions, overrides):
+ """Generates and install the ${BundleName}.xcent entitlements file.
+
+ Expands variables "$(variable)" pattern in the source entitlements file,
+ add extra entitlements defined in the .mobileprovision file and the copy
+ the generated plist to "${BundlePath}.xcent".
+
+ Args:
+ entitlements: string, optional, path to the Entitlements.plist template
+ to use, defaults to "${SDKROOT}/Entitlements.plist"
+ substitutions: dictionary, variable substitutions
+ overrides: dictionary, values to add to the entitlements
+
+ Returns:
+ Path to the generated entitlements file.
+ """
+ source_path = entitlements
+ target_path = os.path.join(
+ os.environ['BUILT_PRODUCTS_DIR'],
+ os.environ['PRODUCT_NAME'] + '.xcent')
+ if not source_path:
+ source_path = os.path.join(
+ os.environ['SDKROOT'],
+ 'Entitlements.plist')
+ shutil.copy2(source_path, target_path)
+ data = self._LoadPlistMaybeBinary(target_path)
+ data = self._ExpandVariables(data, substitutions)
+ if overrides:
+ for key in overrides:
+ if key not in data:
+ data[key] = overrides[key]
+ plistlib.writePlist(data, target_path)
+ return target_path
+
+ def _ExpandVariables(self, data, substitutions):
+ """Expands variables "$(variable)" in data.
+
+ Args:
+ data: object, can be either string, list or dictionary
+ substitutions: dictionary, variable substitutions to perform
+
+ Returns:
+ Copy of data where each references to "$(variable)" has been replaced
+ by the corresponding value found in substitutions, or left intact if
+ the key was not found.
+ """
+ if isinstance(data, str):
+ for key, value in substitutions.iteritems():
+ data = data.replace('$(%s)' % key, value)
+ return data
+ if isinstance(data, list):
+ return [self._ExpandVariables(v, substitutions) for v in data]
+ if isinstance(data, dict):
+ return {k: self._ExpandVariables(data[k], substitutions) for k in data}
+ return data
+
+def NextGreaterPowerOf2(x):
+ return 2**(x).bit_length()
+
+def WriteHmap(output_name, filelist):
+ """Generates a header map based on |filelist|.
+
+ Per Mark Mentovai:
+ A header map is structured essentially as a hash table, keyed by names used
+ in #includes, and providing pathnames to the actual files.
+
+ The implementation below and the comment above comes from inspecting:
+ http://www.opensource.apple.com/source/distcc/distcc-2503/distcc_dist/include_server/headermap.py?txt
+ while also looking at the implementation in clang in:
+ https://llvm.org/svn/llvm-project/cfe/trunk/lib/Lex/HeaderMap.cpp
+ """
+ magic = 1751998832
+ version = 1
+ _reserved = 0
+ count = len(filelist)
+ capacity = NextGreaterPowerOf2(count)
+ strings_offset = 24 + (12 * capacity)
+ max_value_length = len(max(filelist.items(), key=lambda (k,v):len(v))[1])
+
+ out = open(output_name, "wb")
+ out.write(struct.pack('<LHHLLLL', magic, version, _reserved, strings_offset,
+ count, capacity, max_value_length))
+
+ # Create empty hashmap buckets.
+ buckets = [None] * capacity
+ for file, path in filelist.items():
+ key = 0
+ for c in file:
+ key += ord(c.lower()) * 13
+
+ # Fill next empty bucket.
+ while buckets[key & capacity - 1] is not None:
+ key = key + 1
+ buckets[key & capacity - 1] = (file, path)
+
+ next_offset = 1
+ for bucket in buckets:
+ if bucket is None:
+ out.write(struct.pack('<LLL', 0, 0, 0))
+ else:
+ (file, path) = bucket
+ key_offset = next_offset
+ prefix_offset = key_offset + len(file) + 1
+ suffix_offset = prefix_offset + len(os.path.dirname(path) + os.sep) + 1
+ next_offset = suffix_offset + len(os.path.basename(path)) + 1
+ out.write(struct.pack('<LLL', key_offset, prefix_offset, suffix_offset))
+
+ # Pad byte since next offset starts at 1.
+ out.write(struct.pack('<x'))
+
+ for bucket in buckets:
+ if bucket is not None:
+ (file, path) = bucket
+ out.write(struct.pack('<%ds' % len(file), file))
+ out.write(struct.pack('<s', '\0'))
+ base = os.path.dirname(path) + os.sep
+ out.write(struct.pack('<%ds' % len(base), base))
+ out.write(struct.pack('<s', '\0'))
+ path = os.path.basename(path)
+ out.write(struct.pack('<%ds' % len(path), path))
+ out.write(struct.pack('<s', '\0'))
if __name__ == '__main__':
sys.exit(main(sys.argv[1:]))
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/msvs_emulation.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/msvs_emulation.py
@@ -7,20 +7,24 @@ This module helps emulate Visual Studio
build systems, primarily ninja.
"""
import os
import re
import subprocess
import sys
+from gyp.common import OrderedSet
+import gyp.MSVSUtil
import gyp.MSVSVersion
+
windows_quoter_regex = re.compile(r'(\\*)"')
+
def QuoteForRspFile(arg):
"""Quote a command line argument so that it appears as one argument when
processed via cmd.exe and parsed by CommandLineToArgvW (as is typical for
Windows programs)."""
# See http://goo.gl/cuFbX and http://goo.gl/dhPnp including the comment
# threads. This is actually the quoting rules for CommandLineToArgvW, not
# for the shell, because the shell doesn't do anything in Windows. This
# works more or less because most programs (including the compiler, etc.)
@@ -126,79 +130,151 @@ def _FindDirectXInstallation():
if 'InstallPath' in line:
dxsdk_dir = line.split(' ')[3] + "\\"
# Cache return value
_FindDirectXInstallation.dxsdk_dir = dxsdk_dir
return dxsdk_dir
+def GetGlobalVSMacroEnv(vs_version):
+ """Get a dict of variables mapping internal VS macro names to their gyp
+ equivalents. Returns all variables that are independent of the target."""
+ env = {}
+ # '$(VSInstallDir)' and '$(VCInstallDir)' are available when and only when
+ # Visual Studio is actually installed.
+ if vs_version.Path():
+ env['$(VSInstallDir)'] = vs_version.Path()
+ env['$(VCInstallDir)'] = os.path.join(vs_version.Path(), 'VC') + '\\'
+ # Chromium uses DXSDK_DIR in include/lib paths, but it may or may not be
+ # set. This happens when the SDK is sync'd via src-internal, rather than
+ # by typical end-user installation of the SDK. If it's not set, we don't
+ # want to leave the unexpanded variable in the path, so simply strip it.
+ dxsdk_dir = _FindDirectXInstallation()
+ env['$(DXSDK_DIR)'] = dxsdk_dir if dxsdk_dir else ''
+ # Try to find an installation location for the Windows DDK by checking
+ # the WDK_DIR environment variable, may be None.
+ env['$(WDK_DIR)'] = os.environ.get('WDK_DIR', '')
+ return env
+
+def ExtractSharedMSVSSystemIncludes(configs, generator_flags):
+ """Finds msvs_system_include_dirs that are common to all targets, removes
+ them from all targets, and returns an OrderedSet containing them."""
+ all_system_includes = OrderedSet(
+ configs[0].get('msvs_system_include_dirs', []))
+ for config in configs[1:]:
+ system_includes = config.get('msvs_system_include_dirs', [])
+ all_system_includes = all_system_includes & OrderedSet(system_includes)
+ if not all_system_includes:
+ return None
+ # Expand macros in all_system_includes.
+ env = GetGlobalVSMacroEnv(GetVSVersion(generator_flags))
+ expanded_system_includes = OrderedSet([ExpandMacros(include, env)
+ for include in all_system_includes])
+ if any(['$' in include for include in expanded_system_includes]):
+ # Some path relies on target-specific variables, bail.
+ return None
+
+ # Remove system includes shared by all targets from the targets.
+ for config in configs:
+ includes = config.get('msvs_system_include_dirs', [])
+ if includes: # Don't insert a msvs_system_include_dirs key if not needed.
+ # This must check the unexpanded includes list:
+ new_includes = [i for i in includes if i not in all_system_includes]
+ config['msvs_system_include_dirs'] = new_includes
+ return expanded_system_includes
+
+
class MsvsSettings(object):
"""A class that understands the gyp 'msvs_...' values (especially the
msvs_settings field). They largely correpond to the VS2008 IDE DOM. This
class helps map those settings to command line options."""
def __init__(self, spec, generator_flags):
self.spec = spec
self.vs_version = GetVSVersion(generator_flags)
- self.dxsdk_dir = _FindDirectXInstallation()
-
- # Try to find an installation location for the Windows DDK by checking
- # the WDK_DIR environment variable, may be None.
- self.wdk_dir = os.environ.get('WDK_DIR')
supported_fields = [
('msvs_configuration_attributes', dict),
('msvs_settings', dict),
('msvs_system_include_dirs', list),
('msvs_disabled_warnings', list),
('msvs_precompiled_header', str),
('msvs_precompiled_source', str),
+ ('msvs_configuration_platform', str),
('msvs_target_platform', str),
]
configs = spec['configurations']
for field, default in supported_fields:
setattr(self, field, {})
for configname, config in configs.iteritems():
getattr(self, field)[configname] = config.get(field, default())
self.msvs_cygwin_dirs = spec.get('msvs_cygwin_dirs', ['.'])
+ unsupported_fields = [
+ 'msvs_prebuild',
+ 'msvs_postbuild',
+ ]
+ unsupported = []
+ for field in unsupported_fields:
+ for config in configs.values():
+ if field in config:
+ unsupported += ["%s not supported (target %s)." %
+ (field, spec['target_name'])]
+ if unsupported:
+ raise Exception('\n'.join(unsupported))
+
+ def GetExtension(self):
+ """Returns the extension for the target, with no leading dot.
+
+ Uses 'product_extension' if specified, otherwise uses MSVS defaults based on
+ the target type.
+ """
+ ext = self.spec.get('product_extension', None)
+ if ext:
+ return ext
+ return gyp.MSVSUtil.TARGET_TYPE_EXT.get(self.spec['type'], '')
+
def GetVSMacroEnv(self, base_to_build=None, config=None):
"""Get a dict of variables mapping internal VS macro names to their gyp
equivalents."""
- target_platform = self.GetTargetPlatform(config)
- target_platform = {'x86': 'Win32'}.get(target_platform, target_platform)
+ target_platform = 'Win32' if self.GetArch(config) == 'x86' else 'x64'
+ target_name = self.spec.get('product_prefix', '') + \
+ self.spec.get('product_name', self.spec['target_name'])
+ target_dir = base_to_build + '\\' if base_to_build else ''
+ target_ext = '.' + self.GetExtension()
+ target_file_name = target_name + target_ext
+
replacements = {
- '$(VSInstallDir)': self.vs_version.Path(),
- '$(VCInstallDir)': os.path.join(self.vs_version.Path(), 'VC') + '\\',
- '$(OutDir)\\': base_to_build + '\\' if base_to_build else '',
+ '$(InputName)': '${root}',
+ '$(InputPath)': '${source}',
'$(IntDir)': '$!INTERMEDIATE_DIR',
- '$(InputPath)': '${source}',
- '$(InputName)': '${root}',
- '$(ProjectName)': self.spec['target_name'],
+ '$(OutDir)\\': target_dir,
'$(PlatformName)': target_platform,
'$(ProjectDir)\\': '',
+ '$(ProjectName)': self.spec['target_name'],
+ '$(TargetDir)\\': target_dir,
+ '$(TargetExt)': target_ext,
+ '$(TargetFileName)': target_file_name,
+ '$(TargetName)': target_name,
+ '$(TargetPath)': os.path.join(target_dir, target_file_name),
}
- # Chromium uses DXSDK_DIR in include/lib paths, but it may or may not be
- # set. This happens when the SDK is sync'd via src-internal, rather than
- # by typical end-user installation of the SDK. If it's not set, we don't
- # want to leave the unexpanded variable in the path, so simply strip it.
- replacements['$(DXSDK_DIR)'] = self.dxsdk_dir if self.dxsdk_dir else ''
- replacements['$(WDK_DIR)'] = self.wdk_dir if self.wdk_dir else ''
+ replacements.update(GetGlobalVSMacroEnv(self.vs_version))
return replacements
def ConvertVSMacros(self, s, base_to_build=None, config=None):
"""Convert from VS macro names to something equivalent."""
env = self.GetVSMacroEnv(base_to_build, config=config)
return ExpandMacros(s, env)
def AdjustLibraries(self, libraries):
"""Strip -l from library if it's specified with that."""
- return [lib[2:] if lib.startswith('-l') else lib for lib in libraries]
+ libs = [lib[2:] if lib.startswith('-l') else lib for lib in libraries]
+ return [lib + '.lib' if not lib.endswith('.lib') else lib for lib in libs]
def _GetAndMunge(self, field, path, default, prefix, append, map):
"""Retrieve a value from |field| at |path| or return |default|. If
|append| is specified, and the item is found, it will be appended to that
object instead of returned. If |map| is specified, results will be
remapped through |map| before being returned or appended."""
result = _GenericRetrieve(field, default, path)
result = _DoRemapping(result, map)
@@ -210,275 +286,504 @@ class MsvsSettings(object):
self.parent = parent
self.field = field
self.base_path = [base_path]
self.append = append
def __call__(self, name, map=None, prefix='', default=None):
return self.parent._GetAndMunge(self.field, self.base_path + [name],
default=default, prefix=prefix, append=self.append, map=map)
- def GetTargetPlatform(self, config):
- target_platform = self.msvs_target_platform.get(config, '')
- if not target_platform:
- target_platform = 'Win32'
- return {'Win32': 'x86'}.get(target_platform, target_platform)
+ def GetArch(self, config):
+ """Get architecture based on msvs_configuration_platform and
+ msvs_target_platform. Returns either 'x86' or 'x64'."""
+ configuration_platform = self.msvs_configuration_platform.get(config, '')
+ platform = self.msvs_target_platform.get(config, '')
+ if not platform: # If no specific override, use the configuration's.
+ platform = configuration_platform
+ # Map from platform to architecture.
+ return {'Win32': 'x86', 'x64': 'x64'}.get(platform, 'x86')
- def _RealConfig(self, config):
- target_platform = self.GetTargetPlatform(config)
- if target_platform == 'x64' and not config.endswith('_x64'):
+ def _TargetConfig(self, config):
+ """Returns the target-specific configuration."""
+ # There's two levels of architecture/platform specification in VS. The
+ # first level is globally for the configuration (this is what we consider
+ # "the" config at the gyp level, which will be something like 'Debug' or
+ # 'Release_x64'), and a second target-specific configuration, which is an
+ # override for the global one. |config| is remapped here to take into
+ # account the local target-specific overrides to the global configuration.
+ arch = self.GetArch(config)
+ if arch == 'x64' and not config.endswith('_x64'):
config += '_x64'
+ if arch == 'x86' and config.endswith('_x64'):
+ config = config.rsplit('_', 1)[0]
return config
def _Setting(self, path, config,
default=None, prefix='', append=None, map=None):
"""_GetAndMunge for msvs_settings."""
- config = self._RealConfig(config)
return self._GetAndMunge(
self.msvs_settings[config], path, default, prefix, append, map)
def _ConfigAttrib(self, path, config,
default=None, prefix='', append=None, map=None):
"""_GetAndMunge for msvs_configuration_attributes."""
- config = self._RealConfig(config)
return self._GetAndMunge(
self.msvs_configuration_attributes[config],
path, default, prefix, append, map)
def AdjustIncludeDirs(self, include_dirs, config):
"""Updates include_dirs to expand VS specific paths, and adds the system
include dirs used for platform SDK and similar."""
- config = self._RealConfig(config)
+ config = self._TargetConfig(config)
includes = include_dirs + self.msvs_system_include_dirs[config]
includes.extend(self._Setting(
('VCCLCompilerTool', 'AdditionalIncludeDirectories'), config, default=[]))
return [self.ConvertVSMacros(p, config=config) for p in includes]
+ def AdjustMidlIncludeDirs(self, midl_include_dirs, config):
+ """Updates midl_include_dirs to expand VS specific paths, and adds the
+ system include dirs used for platform SDK and similar."""
+ config = self._TargetConfig(config)
+ includes = midl_include_dirs + self.msvs_system_include_dirs[config]
+ includes.extend(self._Setting(
+ ('VCMIDLTool', 'AdditionalIncludeDirectories'), config, default=[]))
+ return [self.ConvertVSMacros(p, config=config) for p in includes]
+
def GetComputedDefines(self, config):
"""Returns the set of defines that are injected to the defines list based
on other VS settings."""
- config = self._RealConfig(config)
+ config = self._TargetConfig(config)
defines = []
if self._ConfigAttrib(['CharacterSet'], config) == '1':
defines.extend(('_UNICODE', 'UNICODE'))
if self._ConfigAttrib(['CharacterSet'], config) == '2':
defines.append('_MBCS')
defines.extend(self._Setting(
('VCCLCompilerTool', 'PreprocessorDefinitions'), config, default=[]))
return defines
+ def GetCompilerPdbName(self, config, expand_special):
+ """Get the pdb file name that should be used for compiler invocations, or
+ None if there's no explicit name specified."""
+ config = self._TargetConfig(config)
+ pdbname = self._Setting(
+ ('VCCLCompilerTool', 'ProgramDataBaseFileName'), config)
+ if pdbname:
+ pdbname = expand_special(self.ConvertVSMacros(pdbname))
+ return pdbname
+
+ def GetMapFileName(self, config, expand_special):
+ """Gets the explicitly overriden map file name for a target or returns None
+ if it's not set."""
+ config = self._TargetConfig(config)
+ map_file = self._Setting(('VCLinkerTool', 'MapFileName'), config)
+ if map_file:
+ map_file = expand_special(self.ConvertVSMacros(map_file, config=config))
+ return map_file
+
def GetOutputName(self, config, expand_special):
"""Gets the explicitly overridden output name for a target or returns None
if it's not overridden."""
- config = self._RealConfig(config)
+ config = self._TargetConfig(config)
type = self.spec['type']
root = 'VCLibrarianTool' if type == 'static_library' else 'VCLinkerTool'
# TODO(scottmg): Handle OutputDirectory without OutputFile.
output_file = self._Setting((root, 'OutputFile'), config)
if output_file:
output_file = expand_special(self.ConvertVSMacros(
output_file, config=config))
return output_file
+ def GetPDBName(self, config, expand_special, default):
+ """Gets the explicitly overridden pdb name for a target or returns
+ default if it's not overridden, or if no pdb will be generated."""
+ config = self._TargetConfig(config)
+ output_file = self._Setting(('VCLinkerTool', 'ProgramDatabaseFile'), config)
+ generate_debug_info = self._Setting(
+ ('VCLinkerTool', 'GenerateDebugInformation'), config)
+ if generate_debug_info == 'true':
+ if output_file:
+ return expand_special(self.ConvertVSMacros(output_file, config=config))
+ else:
+ return default
+ else:
+ return None
+
+ def GetNoImportLibrary(self, config):
+ """If NoImportLibrary: true, ninja will not expect the output to include
+ an import library."""
+ config = self._TargetConfig(config)
+ noimplib = self._Setting(('NoImportLibrary',), config)
+ return noimplib == 'true'
+
+ def GetAsmflags(self, config):
+ """Returns the flags that need to be added to ml invocations."""
+ config = self._TargetConfig(config)
+ asmflags = []
+ safeseh = self._Setting(('MASM', 'UseSafeExceptionHandlers'), config)
+ if safeseh == 'true':
+ asmflags.append('/safeseh')
+ return asmflags
+
def GetCflags(self, config):
"""Returns the flags that need to be added to .c and .cc compilations."""
- config = self._RealConfig(config)
+ config = self._TargetConfig(config)
cflags = []
cflags.extend(['/wd' + w for w in self.msvs_disabled_warnings[config]])
cl = self._GetWrapper(self, self.msvs_settings[config],
'VCCLCompilerTool', append=cflags)
cl('Optimization',
- map={'0': 'd', '1': '1', '2': '2', '3': 'x'}, prefix='/O')
+ map={'0': 'd', '1': '1', '2': '2', '3': 'x'}, prefix='/O', default='2')
cl('InlineFunctionExpansion', prefix='/Ob')
+ cl('DisableSpecificWarnings', prefix='/wd')
+ cl('StringPooling', map={'true': '/GF'})
+ cl('EnableFiberSafeOptimizations', map={'true': '/GT'})
cl('OmitFramePointers', map={'false': '-', 'true': ''}, prefix='/Oy')
+ cl('EnableIntrinsicFunctions', map={'false': '-', 'true': ''}, prefix='/Oi')
cl('FavorSizeOrSpeed', map={'1': 't', '2': 's'}, prefix='/O')
+ cl('FloatingPointModel',
+ map={'0': 'precise', '1': 'strict', '2': 'fast'}, prefix='/fp:',
+ default='0')
+ cl('CompileAsManaged', map={'false': '', 'true': '/clr'})
cl('WholeProgramOptimization', map={'true': '/GL'})
cl('WarningLevel', prefix='/W')
cl('WarnAsError', map={'true': '/WX'})
+ cl('CallingConvention',
+ map={'0': 'd', '1': 'r', '2': 'z', '3': 'v'}, prefix='/G')
cl('DebugInformationFormat',
map={'1': '7', '3': 'i', '4': 'I'}, prefix='/Z')
cl('RuntimeTypeInfo', map={'true': '/GR', 'false': '/GR-'})
cl('EnableFunctionLevelLinking', map={'true': '/Gy', 'false': '/Gy-'})
cl('MinimalRebuild', map={'true': '/Gm'})
cl('BufferSecurityCheck', map={'true': '/GS', 'false': '/GS-'})
cl('BasicRuntimeChecks', map={'1': 's', '2': 'u', '3': '1'}, prefix='/RTC')
cl('RuntimeLibrary',
map={'0': 'T', '1': 'Td', '2': 'D', '3': 'Dd'}, prefix='/M')
cl('ExceptionHandling', map={'1': 'sc','2': 'a'}, prefix='/EH')
+ cl('DefaultCharIsUnsigned', map={'true': '/J'})
+ cl('TreatWChar_tAsBuiltInType',
+ map={'false': '-', 'true': ''}, prefix='/Zc:wchar_t')
+ cl('EnablePREfast', map={'true': '/analyze'})
cl('AdditionalOptions', prefix='')
+ cl('EnableEnhancedInstructionSet',
+ map={'1': 'SSE', '2': 'SSE2', '3': 'AVX', '4': 'IA32', '5': 'AVX2'},
+ prefix='/arch:')
+ cflags.extend(['/FI' + f for f in self._Setting(
+ ('VCCLCompilerTool', 'ForcedIncludeFiles'), config, default=[])])
+ if self.vs_version.short_name in ('2013', '2013e', '2015'):
+ # New flag required in 2013 to maintain previous PDB behavior.
+ cflags.append('/FS')
# ninja handles parallelism by itself, don't have the compiler do it too.
cflags = filter(lambda x: not x.startswith('/MP'), cflags)
return cflags
- def GetPrecompiledHeader(self, config, gyp_to_build_path):
- """Returns an object that handles the generation of precompiled header
- build steps."""
- config = self._RealConfig(config)
- return _PchHelper(self, config, gyp_to_build_path)
-
def _GetPchFlags(self, config, extension):
"""Get the flags to be added to the cflags for precompiled header support.
"""
- config = self._RealConfig(config)
+ config = self._TargetConfig(config)
# The PCH is only built once by a particular source file. Usage of PCH must
# only be for the same language (i.e. C vs. C++), so only include the pch
# flags when the language matches.
if self.msvs_precompiled_header[config]:
source_ext = os.path.splitext(self.msvs_precompiled_source[config])[1]
if _LanguageMatchesForPch(source_ext, extension):
- pch = os.path.split(self.msvs_precompiled_header[config])[1]
- return ['/Yu' + pch, '/FI' + pch, '/Fp${pchprefix}.' + pch + '.pch']
+ pch = self.msvs_precompiled_header[config]
+ pchbase = os.path.split(pch)[1]
+ return ['/Yu' + pch, '/FI' + pch, '/Fp${pchprefix}.' + pchbase + '.pch']
return []
def GetCflagsC(self, config):
"""Returns the flags that need to be added to .c compilations."""
- config = self._RealConfig(config)
+ config = self._TargetConfig(config)
return self._GetPchFlags(config, '.c')
def GetCflagsCC(self, config):
"""Returns the flags that need to be added to .cc compilations."""
- config = self._RealConfig(config)
+ config = self._TargetConfig(config)
return ['/TP'] + self._GetPchFlags(config, '.cc')
def _GetAdditionalLibraryDirectories(self, root, config, gyp_to_build_path):
"""Get and normalize the list of paths in AdditionalLibraryDirectories
setting."""
- config = self._RealConfig(config)
+ config = self._TargetConfig(config)
libpaths = self._Setting((root, 'AdditionalLibraryDirectories'),
config, default=[])
libpaths = [os.path.normpath(
gyp_to_build_path(self.ConvertVSMacros(p, config=config)))
for p in libpaths]
return ['/LIBPATH:"' + p + '"' for p in libpaths]
def GetLibFlags(self, config, gyp_to_build_path):
"""Returns the flags that need to be added to lib commands."""
- config = self._RealConfig(config)
+ config = self._TargetConfig(config)
libflags = []
lib = self._GetWrapper(self, self.msvs_settings[config],
'VCLibrarianTool', append=libflags)
libflags.extend(self._GetAdditionalLibraryDirectories(
'VCLibrarianTool', config, gyp_to_build_path))
+ lib('LinkTimeCodeGeneration', map={'true': '/LTCG'})
+ lib('TargetMachine', map={'1': 'X86', '17': 'X64', '3': 'ARM'},
+ prefix='/MACHINE:')
lib('AdditionalOptions')
return libflags
- def _GetDefFileAsLdflags(self, spec, ldflags, gyp_to_build_path):
- """.def files get implicitly converted to a ModuleDefinitionFile for the
- linker in the VS generator. Emulate that behaviour here."""
- def_file = ''
+ def GetDefFile(self, gyp_to_build_path):
+ """Returns the .def file from sources, if any. Otherwise returns None."""
+ spec = self.spec
if spec['type'] in ('shared_library', 'loadable_module', 'executable'):
def_files = [s for s in spec.get('sources', []) if s.endswith('.def')]
if len(def_files) == 1:
- ldflags.append('/DEF:"%s"' % gyp_to_build_path(def_files[0]))
+ return gyp_to_build_path(def_files[0])
elif len(def_files) > 1:
raise Exception("Multiple .def files")
+ return None
+
+ def _GetDefFileAsLdflags(self, ldflags, gyp_to_build_path):
+ """.def files get implicitly converted to a ModuleDefinitionFile for the
+ linker in the VS generator. Emulate that behaviour here."""
+ def_file = self.GetDefFile(gyp_to_build_path)
+ if def_file:
+ ldflags.append('/DEF:"%s"' % def_file)
+
+ def GetPGDName(self, config, expand_special):
+ """Gets the explicitly overridden pgd name for a target or returns None
+ if it's not overridden."""
+ config = self._TargetConfig(config)
+ output_file = self._Setting(
+ ('VCLinkerTool', 'ProfileGuidedDatabase'), config)
+ if output_file:
+ output_file = expand_special(self.ConvertVSMacros(
+ output_file, config=config))
+ return output_file
def GetLdflags(self, config, gyp_to_build_path, expand_special,
- manifest_base_name, is_executable):
+ manifest_base_name, output_name, is_executable, build_dir):
"""Returns the flags that need to be added to link commands, and the
manifest files."""
- config = self._RealConfig(config)
+ config = self._TargetConfig(config)
ldflags = []
ld = self._GetWrapper(self, self.msvs_settings[config],
'VCLinkerTool', append=ldflags)
- self._GetDefFileAsLdflags(self.spec, ldflags, gyp_to_build_path)
+ self._GetDefFileAsLdflags(ldflags, gyp_to_build_path)
ld('GenerateDebugInformation', map={'true': '/DEBUG'})
- ld('TargetMachine', map={'1': 'X86', '17': 'X64'}, prefix='/MACHINE:')
+ ld('TargetMachine', map={'1': 'X86', '17': 'X64', '3': 'ARM'},
+ prefix='/MACHINE:')
ldflags.extend(self._GetAdditionalLibraryDirectories(
'VCLinkerTool', config, gyp_to_build_path))
ld('DelayLoadDLLs', prefix='/DELAYLOAD:')
+ ld('TreatLinkerWarningAsErrors', prefix='/WX',
+ map={'true': '', 'false': ':NO'})
out = self.GetOutputName(config, expand_special)
if out:
ldflags.append('/OUT:' + out)
+ pdb = self.GetPDBName(config, expand_special, output_name + '.pdb')
+ if pdb:
+ ldflags.append('/PDB:' + pdb)
+ pgd = self.GetPGDName(config, expand_special)
+ if pgd:
+ ldflags.append('/PGD:' + pgd)
+ map_file = self.GetMapFileName(config, expand_special)
+ ld('GenerateMapFile', map={'true': '/MAP:' + map_file if map_file
+ else '/MAP'})
+ ld('MapExports', map={'true': '/MAPINFO:EXPORTS'})
ld('AdditionalOptions', prefix='')
- ld('SubSystem', map={'1': 'CONSOLE', '2': 'WINDOWS'}, prefix='/SUBSYSTEM:')
+
+ minimum_required_version = self._Setting(
+ ('VCLinkerTool', 'MinimumRequiredVersion'), config, default='')
+ if minimum_required_version:
+ minimum_required_version = ',' + minimum_required_version
+ ld('SubSystem',
+ map={'1': 'CONSOLE%s' % minimum_required_version,
+ '2': 'WINDOWS%s' % minimum_required_version},
+ prefix='/SUBSYSTEM:')
+
+ stack_reserve_size = self._Setting(
+ ('VCLinkerTool', 'StackReserveSize'), config, default='')
+ if stack_reserve_size:
+ stack_commit_size = self._Setting(
+ ('VCLinkerTool', 'StackCommitSize'), config, default='')
+ if stack_commit_size:
+ stack_commit_size = ',' + stack_commit_size
+ ldflags.append('/STACK:%s%s' % (stack_reserve_size, stack_commit_size))
+
+ ld('TerminalServerAware', map={'1': ':NO', '2': ''}, prefix='/TSAWARE')
ld('LinkIncremental', map={'1': ':NO', '2': ''}, prefix='/INCREMENTAL')
+ ld('BaseAddress', prefix='/BASE:')
ld('FixedBaseAddress', map={'1': ':NO', '2': ''}, prefix='/FIXED')
ld('RandomizedBaseAddress',
map={'1': ':NO', '2': ''}, prefix='/DYNAMICBASE')
ld('DataExecutionPrevention',
map={'1': ':NO', '2': ''}, prefix='/NXCOMPAT')
ld('OptimizeReferences', map={'1': 'NOREF', '2': 'REF'}, prefix='/OPT:')
+ ld('ForceSymbolReferences', prefix='/INCLUDE:')
ld('EnableCOMDATFolding', map={'1': 'NOICF', '2': 'ICF'}, prefix='/OPT:')
- ld('LinkTimeCodeGeneration', map={'1': '/LTCG'})
+ ld('LinkTimeCodeGeneration',
+ map={'1': '', '2': ':PGINSTRUMENT', '3': ':PGOPTIMIZE',
+ '4': ':PGUPDATE'},
+ prefix='/LTCG')
ld('IgnoreDefaultLibraryNames', prefix='/NODEFAULTLIB:')
ld('ResourceOnlyDLL', map={'true': '/NOENTRY'})
ld('EntryPointSymbol', prefix='/ENTRY:')
+ ld('Profile', map={'true': '/PROFILE'})
+ ld('LargeAddressAware',
+ map={'1': ':NO', '2': ''}, prefix='/LARGEADDRESSAWARE')
# TODO(scottmg): This should sort of be somewhere else (not really a flag).
ld('AdditionalDependencies', prefix='')
- # TODO(scottmg): These too.
- ldflags.extend(('kernel32.lib', 'user32.lib', 'gdi32.lib', 'winspool.lib',
- 'comdlg32.lib', 'advapi32.lib', 'shell32.lib', 'ole32.lib',
- 'oleaut32.lib', 'uuid.lib', 'odbc32.lib', 'DelayImp.lib'))
+
+ if self.GetArch(config) == 'x86':
+ safeseh_default = 'true'
+ else:
+ safeseh_default = None
+ ld('ImageHasSafeExceptionHandlers',
+ map={'false': ':NO', 'true': ''}, prefix='/SAFESEH',
+ default=safeseh_default)
# If the base address is not specifically controlled, DYNAMICBASE should
# be on by default.
base_flags = filter(lambda x: 'DYNAMICBASE' in x or x == '/FIXED',
ldflags)
if not base_flags:
ldflags.append('/DYNAMICBASE')
# If the NXCOMPAT flag has not been specified, default to on. Despite the
# documentation that says this only defaults to on when the subsystem is
# Vista or greater (which applies to the linker), the IDE defaults it on
# unless it's explicitly off.
if not filter(lambda x: 'NXCOMPAT' in x, ldflags):
ldflags.append('/NXCOMPAT')
have_def_file = filter(lambda x: x.startswith('/DEF:'), ldflags)
- manifest_flags, intermediate_manifest_file = self._GetLdManifestFlags(
- config, manifest_base_name, is_executable and not have_def_file)
+ manifest_flags, intermediate_manifest, manifest_files = \
+ self._GetLdManifestFlags(config, manifest_base_name, gyp_to_build_path,
+ is_executable and not have_def_file, build_dir)
ldflags.extend(manifest_flags)
- manifest_files = self._GetAdditionalManifestFiles(config, gyp_to_build_path)
- manifest_files.append(intermediate_manifest_file)
-
- return ldflags, manifest_files
+ return ldflags, intermediate_manifest, manifest_files
- def _GetLdManifestFlags(self, config, name, allow_isolation):
- """Returns the set of flags that need to be added to the link to generate
- a default manifest, as well as the name of the generated file."""
- # Add manifest flags that mirror the defaults in VS. Chromium dev builds
- # do not currently use any non-default settings, but we could parse
- # VCManifestTool blocks if Chromium or other projects need them in the
- # future. Of particular note, we do not yet support EmbedManifest because
- # it complicates incremental linking.
+ def _GetLdManifestFlags(self, config, name, gyp_to_build_path,
+ allow_isolation, build_dir):
+ """Returns a 3-tuple:
+ - the set of flags that need to be added to the link to generate
+ a default manifest
+ - the intermediate manifest that the linker will generate that should be
+ used to assert it doesn't add anything to the merged one.
+ - the list of all the manifest files to be merged by the manifest tool and
+ included into the link."""
+ generate_manifest = self._Setting(('VCLinkerTool', 'GenerateManifest'),
+ config,
+ default='true')
+ if generate_manifest != 'true':
+ # This means not only that the linker should not generate the intermediate
+ # manifest but also that the manifest tool should do nothing even when
+ # additional manifests are specified.
+ return ['/MANIFEST:NO'], [], []
+
output_name = name + '.intermediate.manifest'
flags = [
'/MANIFEST',
'/ManifestFile:' + output_name,
- '''/MANIFESTUAC:"level='asInvoker' uiAccess='false'"'''
]
+
+ # Instead of using the MANIFESTUAC flags, we generate a .manifest to
+ # include into the list of manifests. This allows us to avoid the need to
+ # do two passes during linking. The /MANIFEST flag and /ManifestFile are
+ # still used, and the intermediate manifest is used to assert that the
+ # final manifest we get from merging all the additional manifest files
+ # (plus the one we generate here) isn't modified by merging the
+ # intermediate into it.
+
+ # Always NO, because we generate a manifest file that has what we want.
+ flags.append('/MANIFESTUAC:NO')
+
+ config = self._TargetConfig(config)
+ enable_uac = self._Setting(('VCLinkerTool', 'EnableUAC'), config,
+ default='true')
+ manifest_files = []
+ generated_manifest_outer = \
+"<?xml version='1.0' encoding='UTF-8' standalone='yes'?>" \
+"<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>%s" \
+"</assembly>"
+ if enable_uac == 'true':
+ execution_level = self._Setting(('VCLinkerTool', 'UACExecutionLevel'),
+ config, default='0')
+ execution_level_map = {
+ '0': 'asInvoker',
+ '1': 'highestAvailable',
+ '2': 'requireAdministrator'
+ }
+
+ ui_access = self._Setting(('VCLinkerTool', 'UACUIAccess'), config,
+ default='false')
+
+ inner = '''
+<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
+ <security>
+ <requestedPrivileges>
+ <requestedExecutionLevel level='%s' uiAccess='%s' />
+ </requestedPrivileges>
+ </security>
+</trustInfo>''' % (execution_level_map[execution_level], ui_access)
+ else:
+ inner = ''
+
+ generated_manifest_contents = generated_manifest_outer % inner
+ generated_name = name + '.generated.manifest'
+ # Need to join with the build_dir here as we're writing it during
+ # generation time, but we return the un-joined version because the build
+ # will occur in that directory. We only write the file if the contents
+ # have changed so that simply regenerating the project files doesn't
+ # cause a relink.
+ build_dir_generated_name = os.path.join(build_dir, generated_name)
+ gyp.common.EnsureDirExists(build_dir_generated_name)
+ f = gyp.common.WriteOnDiff(build_dir_generated_name)
+ f.write(generated_manifest_contents)
+ f.close()
+ manifest_files = [generated_name]
+
if allow_isolation:
flags.append('/ALLOWISOLATION')
- return flags, output_name
+
+ manifest_files += self._GetAdditionalManifestFiles(config,
+ gyp_to_build_path)
+ return flags, output_name, manifest_files
def _GetAdditionalManifestFiles(self, config, gyp_to_build_path):
"""Gets additional manifest files that are added to the default one
generated by the linker."""
files = self._Setting(('VCManifestTool', 'AdditionalManifestFiles'), config,
default=[])
- if (self._Setting(
- ('VCManifestTool', 'EmbedManifest'), config, default='') == 'true'):
- print 'gyp/msvs_emulation.py: "EmbedManifest: true" not yet supported.'
if isinstance(files, str):
files = files.split(';')
return [os.path.normpath(
gyp_to_build_path(self.ConvertVSMacros(f, config=config)))
for f in files]
def IsUseLibraryDependencyInputs(self, config):
"""Returns whether the target should be linked via Use Library Dependency
Inputs (using component .objs of a given .lib)."""
- config = self._RealConfig(config)
+ config = self._TargetConfig(config)
uldi = self._Setting(('VCLinkerTool', 'UseLibraryDependencyInputs'), config)
return uldi == 'true'
+ def IsEmbedManifest(self, config):
+ """Returns whether manifest should be linked into binary."""
+ config = self._TargetConfig(config)
+ embed = self._Setting(('VCManifestTool', 'EmbedManifest'), config,
+ default='true')
+ return embed == 'true'
+
+ def IsLinkIncremental(self, config):
+ """Returns whether the target should be linked incrementally."""
+ config = self._TargetConfig(config)
+ link_inc = self._Setting(('VCLinkerTool', 'LinkIncremental'), config)
+ return link_inc != '1'
+
def GetRcflags(self, config, gyp_to_ninja_path):
"""Returns the flags that need to be added to invocations of the resource
compiler."""
- config = self._RealConfig(config)
+ config = self._TargetConfig(config)
rcflags = []
rc = self._GetWrapper(self, self.msvs_settings[config],
'VCResourceCompilerTool', append=rcflags)
rc('AdditionalIncludeDirectories', map=gyp_to_ninja_path, prefix='/I')
rcflags.append('/I' + gyp_to_ninja_path('.'))
rc('PreprocessorDefinitions', prefix='/d')
# /l arg must be in hex without leading '0x'
rc('Culture', prefix='/l', map=lambda x: hex(int(x))[2:])
@@ -505,28 +810,43 @@ class MsvsSettings(object):
return cmd
def IsRuleRunUnderCygwin(self, rule):
"""Determine if an action should be run under cygwin. If the variable is
unset, or set to 1 we use cygwin."""
return int(rule.get('msvs_cygwin_shell',
self.spec.get('msvs_cygwin_shell', 1))) != 0
- def HasExplicitIdlRules(self, spec):
- """Determine if there's an explicit rule for idl files. When there isn't we
- need to generate implicit rules to build MIDL .idl files."""
+ def _HasExplicitRuleForExtension(self, spec, extension):
+ """Determine if there's an explicit rule for a particular extension."""
for rule in spec.get('rules', []):
- if rule['extension'] == 'idl' and int(rule.get('msvs_external_rule', 0)):
+ if rule['extension'] == extension:
return True
return False
+ def _HasExplicitIdlActions(self, spec):
+ """Determine if an action should not run midl for .idl files."""
+ return any([action.get('explicit_idl_action', 0)
+ for action in spec.get('actions', [])])
+
+ def HasExplicitIdlRulesOrActions(self, spec):
+ """Determine if there's an explicit rule or action for idl files. When
+ there isn't we need to generate implicit rules to build MIDL .idl files."""
+ return (self._HasExplicitRuleForExtension(spec, 'idl') or
+ self._HasExplicitIdlActions(spec))
+
+ def HasExplicitAsmRules(self, spec):
+ """Determine if there's an explicit rule for asm files. When there isn't we
+ need to generate implicit rules to assemble .asm files."""
+ return self._HasExplicitRuleForExtension(spec, 'asm')
+
def GetIdlBuildData(self, source, config):
"""Determine the implicit outputs for an idl file. Returns output
directory, outputs, and variables and flags that are required."""
- config = self._RealConfig(config)
+ config = self._TargetConfig(config)
midl_get = self._GetWrapper(self, self.msvs_settings[config], 'VCMIDLTool')
def midl(name, default=None):
return self.ConvertVSMacros(midl_get(name, default=default),
config=config)
tlb = midl('TypeLibraryName', default='${root}.tlb')
header = midl('HeaderFileName', default='${root}.h')
dlldata = midl('DLLDataFileName', default='dlldata.c')
iid = midl('InterfaceIdentifierFileName', default='${root}_i.c')
@@ -536,82 +856,87 @@ class MsvsSettings(object):
outdir = midl('OutputDirectory', default='')
output = [header, dlldata, iid, proxy]
variables = [('tlb', tlb),
('h', header),
('dlldata', dlldata),
('iid', iid),
('proxy', proxy)]
# TODO(scottmg): Are there configuration settings to set these flags?
- flags = ['/char', 'signed', '/env', 'win32', '/Oicf']
+ target_platform = 'win32' if self.GetArch(config) == 'x86' else 'x64'
+ flags = ['/char', 'signed', '/env', target_platform, '/Oicf']
return outdir, output, variables, flags
def _LanguageMatchesForPch(source_ext, pch_source_ext):
c_exts = ('.c',)
cc_exts = ('.cc', '.cxx', '.cpp')
return ((source_ext in c_exts and pch_source_ext in c_exts) or
(source_ext in cc_exts and pch_source_ext in cc_exts))
+
class PrecompiledHeader(object):
"""Helper to generate dependencies and build rules to handle generation of
precompiled headers. Interface matches the GCH handler in xcode_emulation.py.
"""
- def __init__(self, settings, config, gyp_to_build_path):
+ def __init__(
+ self, settings, config, gyp_to_build_path, gyp_to_unique_output, obj_ext):
self.settings = settings
self.config = config
- self.gyp_to_build_path = gyp_to_build_path
+ pch_source = self.settings.msvs_precompiled_source[self.config]
+ self.pch_source = gyp_to_build_path(pch_source)
+ filename, _ = os.path.splitext(pch_source)
+ self.output_obj = gyp_to_unique_output(filename + obj_ext).lower()
def _PchHeader(self):
"""Get the header that will appear in an #include line for all source
files."""
- return os.path.split(self.settings.msvs_precompiled_header[self.config])[1]
+ return self.settings.msvs_precompiled_header[self.config]
- def _PchSource(self):
- """Get the source file that is built once to compile the pch data."""
- return self.gyp_to_build_path(
- self.settings.msvs_precompiled_source[self.config])
-
- def _PchOutput(self):
- """Get the name of the output of the compiled pch data."""
- return '${pchprefix}.' + self._PchHeader() + '.pch'
-
- def GetObjDependencies(self, sources, objs):
+ def GetObjDependencies(self, sources, objs, arch):
"""Given a list of sources files and the corresponding object files,
returns a list of the pch files that should be depended upon. The
- additional wrapping in the return value is for interface compatability
+ additional wrapping in the return value is for interface compatibility
with make.py on Mac, and xcode_emulation.py."""
+ assert arch is None
if not self._PchHeader():
return []
- source = self._PchSource()
- assert source
- pch_ext = os.path.splitext(self._PchSource())[1]
+ pch_ext = os.path.splitext(self.pch_source)[1]
for source in sources:
if _LanguageMatchesForPch(os.path.splitext(source)[1], pch_ext):
- return [(None, None, self._PchOutput())]
+ return [(None, None, self.output_obj)]
+ return []
+
+ def GetPchBuildCommands(self, arch):
+ """Not used on Windows as there are no additional build steps required
+ (instead, existing steps are modified in GetFlagsModifications below)."""
return []
- def GetPchBuildCommands(self):
- """Returns [(path_to_pch, language_flag, language, header)].
- |path_to_gch| and |header| are relative to the build directory."""
- header = self._PchHeader()
- source = self._PchSource()
- if not source or not header:
- return []
- ext = os.path.splitext(source)[1]
- lang = 'c' if ext == '.c' else 'cc'
- return [(self._PchOutput(), '/Yc' + header, lang, source)]
+ def GetFlagsModifications(self, input, output, implicit, command,
+ cflags_c, cflags_cc, expand_special):
+ """Get the modified cflags and implicit dependencies that should be used
+ for the pch compilation step."""
+ if input == self.pch_source:
+ pch_output = ['/Yc' + self._PchHeader()]
+ if command == 'cxx':
+ return ([('cflags_cc', map(expand_special, cflags_cc + pch_output))],
+ self.output_obj, [])
+ elif command == 'cc':
+ return ([('cflags_c', map(expand_special, cflags_c + pch_output))],
+ self.output_obj, [])
+ return [], output, implicit
vs_version = None
def GetVSVersion(generator_flags):
global vs_version
if not vs_version:
vs_version = gyp.MSVSVersion.SelectVisualStudioVersion(
- generator_flags.get('msvs_version', 'auto'))
+ generator_flags.get('msvs_version', 'auto'),
+ allow_fallback=False)
return vs_version
def _GetVsvarsSetupArgs(generator_flags, arch):
vs = GetVSVersion(generator_flags)
return vs.SetupScript()
def ExpandMacros(string, expansions):
"""Expand $(Variable) per expansions dict. See MsvsSettings.GetVSMacroEnv
@@ -632,16 +957,20 @@ def _ExtractImportantEnvironment(output_
'libpath',
'path',
'pathext',
'systemroot',
'temp',
'tmp',
)
env = {}
+ # This occasionally happens and leads to misleading SYSTEMROOT error messages
+ # if not caught here.
+ if output_of_set.count('=') == 0:
+ raise Exception('Invalid output_of_set. Value is:\n%s' % output_of_set)
for line in output_of_set.splitlines():
for envvar in envvars_to_save:
if re.match(envvar + '=', line.lower()):
var, setting = line.split('=', 1)
if envvar == 'path':
# Our own rules (for running gyp-win-tool) and other actions in
# Chromium rely on python being in the path. Add the path to this
# python here so that if it's not in the path when ninja is run
@@ -661,31 +990,105 @@ def _FormatAsEnvironmentBlock(envvar_dic
CreateProcess documentation for more details."""
block = ''
nul = '\0'
for key, value in envvar_dict.iteritems():
block += key + '=' + value + nul
block += nul
return block
-def GenerateEnvironmentFiles(toplevel_build_dir, generator_flags, open_out):
+def _ExtractCLPath(output_of_where):
+ """Gets the path to cl.exe based on the output of calling the environment
+ setup batch file, followed by the equivalent of `where`."""
+ # Take the first line, as that's the first found in the PATH.
+ for line in output_of_where.strip().splitlines():
+ if line.startswith('LOC:'):
+ return line[len('LOC:'):].strip()
+
+def GenerateEnvironmentFiles(toplevel_build_dir, generator_flags,
+ system_includes, open_out):
"""It's not sufficient to have the absolute path to the compiler, linker,
etc. on Windows, as those tools rely on .dlls being in the PATH. We also
need to support both x86 and x64 compilers within the same build (to support
msvs_target_platform hackery). Different architectures require a different
compiler binary, and different supporting environment variables (INCLUDE,
LIB, LIBPATH). So, we extract the environment here, wrap all invocations
of compiler tools (cl, link, lib, rc, midl, etc.) via win_tool.py which
sets up the environment, and then we do not prefix the compiler with
an absolute path, instead preferring something like "cl.exe" in the rule
- which will then run whichever the environment setup has put in the path."""
+ which will then run whichever the environment setup has put in the path.
+ When the following procedure to generate environment files does not
+ meet your requirement (e.g. for custom toolchains), you can pass
+ "-G ninja_use_custom_environment_files" to the gyp to suppress file
+ generation and use custom environment files prepared by yourself."""
+ archs = ('x86', 'x64')
+ if generator_flags.get('ninja_use_custom_environment_files', 0):
+ cl_paths = {}
+ for arch in archs:
+ cl_paths[arch] = 'cl.exe'
+ return cl_paths
vs = GetVSVersion(generator_flags)
- for arch in ('x86', 'x64'):
+ cl_paths = {}
+ for arch in archs:
+ # Extract environment variables for subprocesses.
args = vs.SetupScript(arch)
args.extend(('&&', 'set'))
popen = subprocess.Popen(
args, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
variables, _ = popen.communicate()
+ if popen.returncode != 0:
+ raise Exception('"%s" failed with error %d' % (args, popen.returncode))
env = _ExtractImportantEnvironment(variables)
+
+ # Inject system includes from gyp files into INCLUDE.
+ if system_includes:
+ system_includes = system_includes | OrderedSet(
+ env.get('INCLUDE', '').split(';'))
+ env['INCLUDE'] = ';'.join(system_includes)
+
env_block = _FormatAsEnvironmentBlock(env)
f = open_out(os.path.join(toplevel_build_dir, 'environment.' + arch), 'wb')
f.write(env_block)
f.close()
+
+ # Find cl.exe location for this architecture.
+ args = vs.SetupScript(arch)
+ args.extend(('&&',
+ 'for', '%i', 'in', '(cl.exe)', 'do', '@echo', 'LOC:%~$PATH:i'))
+ popen = subprocess.Popen(args, shell=True, stdout=subprocess.PIPE)
+ output, _ = popen.communicate()
+ cl_paths[arch] = _ExtractCLPath(output)
+ return cl_paths
+
+def VerifyMissingSources(sources, build_dir, generator_flags, gyp_to_ninja):
+ """Emulate behavior of msvs_error_on_missing_sources present in the msvs
+ generator: Check that all regular source files, i.e. not created at run time,
+ exist on disk. Missing files cause needless recompilation when building via
+ VS, and we want this check to match for people/bots that build using ninja,
+ so they're not surprised when the VS build fails."""
+ if int(generator_flags.get('msvs_error_on_missing_sources', 0)):
+ no_specials = filter(lambda x: '$' not in x, sources)
+ relative = [os.path.join(build_dir, gyp_to_ninja(s)) for s in no_specials]
+ missing = filter(lambda x: not os.path.exists(x), relative)
+ if missing:
+ # They'll look like out\Release\..\..\stuff\things.cc, so normalize the
+ # path for a slightly less crazy looking output.
+ cleaned_up = [os.path.normpath(x) for x in missing]
+ raise Exception('Missing input files:\n%s' % '\n'.join(cleaned_up))
+
+# Sets some values in default_variables, which are required for many
+# generators, run on Windows.
+def CalculateCommonVariables(default_variables, params):
+ generator_flags = params.get('generator_flags', {})
+
+ # Set a variable so conditions can be based on msvs_version.
+ msvs_version = gyp.msvs_emulation.GetVSVersion(generator_flags)
+ default_variables['MSVS_VERSION'] = msvs_version.ShortName()
+
+ # To determine processor word size on Windows, in addition to checking
+ # PROCESSOR_ARCHITECTURE (which reflects the word size of the current
+ # process), it is also necessary to check PROCESSOR_ARCHITEW6432 (which
+ # contains the actual word size of the system when running thru WOW64).
+ if ('64' in os.environ.get('PROCESSOR_ARCHITECTURE', '') or
+ '64' in os.environ.get('PROCESSOR_ARCHITEW6432', '')):
+ default_variables['MSVS_OS_BITS'] = 64
+ else:
+ default_variables['MSVS_OS_BITS'] = 32
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/ninja_syntax.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/ninja_syntax.py
@@ -29,32 +29,41 @@ class Writer(object):
def variable(self, key, value, indent=0):
if value is None:
return
if isinstance(value, list):
value = ' '.join(filter(None, value)) # Filter out empty strings.
self._line('%s = %s' % (key, value), indent)
+ def pool(self, name, depth):
+ self._line('pool %s' % name)
+ self.variable('depth', depth, indent=1)
+
def rule(self, name, command, description=None, depfile=None,
- generator=False, restat=False, rspfile=None, rspfile_content=None):
+ generator=False, pool=None, restat=False, rspfile=None,
+ rspfile_content=None, deps=None):
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)
+ if pool:
+ self.variable('pool', pool, indent=1)
if restat:
self.variable('restat', '1', indent=1)
if rspfile:
self.variable('rspfile', rspfile, indent=1)
if rspfile_content:
self.variable('rspfile_content', rspfile_content, indent=1)
+ if deps:
+ self.variable('deps', deps, 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 = list(map(escape_path, outputs))
all_inputs = list(map(escape_path, all_inputs))
@@ -62,23 +71,22 @@ class Writer(object):
implicit = map(escape_path, self._as_list(implicit))
all_inputs.append('|')
all_inputs.extend(implicit)
if order_only:
order_only = map(escape_path, self._as_list(order_only))
all_inputs.append('||')
all_inputs.extend(order_only)
- self._line('build %s: %s %s' % (' '.join(out_outputs),
- rule,
- ' '.join(all_inputs)))
+ self._line('build %s: %s' % (' '.join(out_outputs),
+ ' '.join([rule] + all_inputs)))
if variables:
if isinstance(variables, dict):
- iterator = variables.iteritems()
+ iterator = iter(variables.items())
else:
iterator = iter(variables)
for key, val in iterator:
self.variable(key, val, indent=1)
return outputs
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/ordered_dict.py
@@ -0,0 +1,289 @@
+# Unmodified from http://code.activestate.com/recipes/576693/
+# other than to add MIT license header (as specified on page, but not in code).
+# Linked from Python documentation here:
+# http://docs.python.org/2/library/collections.html#collections.OrderedDict
+#
+# This should be deleted once Py2.7 is available on all bots, see
+# http://crbug.com/241769.
+#
+# Copyright (c) 2009 Raymond Hettinger.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+# Backport of OrderedDict() class that runs on Python 2.4, 2.5, 2.6, 2.7 and pypy.
+# Passes Python2.7's test suite and incorporates all the latest updates.
+
+try:
+ from thread import get_ident as _get_ident
+except ImportError:
+ from dummy_thread import get_ident as _get_ident
+
+try:
+ from _abcoll import KeysView, ValuesView, ItemsView
+except ImportError:
+ pass
+
+
+class OrderedDict(dict):
+ 'Dictionary that remembers insertion order'
+ # An inherited dict maps keys to values.
+ # The inherited dict provides __getitem__, __len__, __contains__, and get.
+ # The remaining methods are order-aware.
+ # Big-O running times for all methods are the same as for regular dictionaries.
+
+ # The internal self.__map dictionary maps keys to links in a doubly linked list.
+ # The circular doubly linked list starts and ends with a sentinel element.
+ # The sentinel element never gets deleted (this simplifies the algorithm).
+ # Each link is stored as a list of length three: [PREV, NEXT, KEY].
+
+ def __init__(self, *args, **kwds):
+ '''Initialize an ordered dictionary. Signature is the same as for
+ regular dictionaries, but keyword arguments are not recommended
+ because their insertion order is arbitrary.
+
+ '''
+ if len(args) > 1:
+ raise TypeError('expected at most 1 arguments, got %d' % len(args))
+ try:
+ self.__root
+ except AttributeError:
+ self.__root = root = [] # sentinel node
+ root[:] = [root, root, None]
+ self.__map = {}
+ self.__update(*args, **kwds)
+
+ def __setitem__(self, key, value, dict_setitem=dict.__setitem__):
+ 'od.__setitem__(i, y) <==> od[i]=y'
+ # Setting a new item creates a new link which goes at the end of the linked
+ # list, and the inherited dictionary is updated with the new key/value pair.
+ if key not in self:
+ root = self.__root
+ last = root[0]
+ last[1] = root[0] = self.__map[key] = [last, root, key]
+ dict_setitem(self, key, value)
+
+ def __delitem__(self, key, dict_delitem=dict.__delitem__):
+ 'od.__delitem__(y) <==> del od[y]'
+ # Deleting an existing item uses self.__map to find the link which is
+ # then removed by updating the links in the predecessor and successor nodes.
+ dict_delitem(self, key)
+ link_prev, link_next, key = self.__map.pop(key)
+ link_prev[1] = link_next
+ link_next[0] = link_prev
+
+ def __iter__(self):
+ 'od.__iter__() <==> iter(od)'
+ root = self.__root
+ curr = root[1]
+ while curr is not root:
+ yield curr[2]
+ curr = curr[1]
+
+ def __reversed__(self):
+ 'od.__reversed__() <==> reversed(od)'
+ root = self.__root
+ curr = root[0]
+ while curr is not root:
+ yield curr[2]
+ curr = curr[0]
+
+ def clear(self):
+ 'od.clear() -> None. Remove all items from od.'
+ try:
+ for node in self.__map.itervalues():
+ del node[:]
+ root = self.__root
+ root[:] = [root, root, None]
+ self.__map.clear()
+ except AttributeError:
+ pass
+ dict.clear(self)
+
+ def popitem(self, last=True):
+ '''od.popitem() -> (k, v), return and remove a (key, value) pair.
+ Pairs are returned in LIFO order if last is true or FIFO order if false.
+
+ '''
+ if not self:
+ raise KeyError('dictionary is empty')
+ root = self.__root
+ if last:
+ link = root[0]
+ link_prev = link[0]
+ link_prev[1] = root
+ root[0] = link_prev
+ else:
+ link = root[1]
+ link_next = link[1]
+ root[1] = link_next
+ link_next[0] = root
+ key = link[2]
+ del self.__map[key]
+ value = dict.pop(self, key)
+ return key, value
+
+ # -- the following methods do not depend on the internal structure --
+
+ def keys(self):
+ 'od.keys() -> list of keys in od'
+ return list(self)
+
+ def values(self):
+ 'od.values() -> list of values in od'
+ return [self[key] for key in self]
+
+ def items(self):
+ 'od.items() -> list of (key, value) pairs in od'
+ return [(key, self[key]) for key in self]
+
+ def iterkeys(self):
+ 'od.iterkeys() -> an iterator over the keys in od'
+ return iter(self)
+
+ def itervalues(self):
+ 'od.itervalues -> an iterator over the values in od'
+ for k in self:
+ yield self[k]
+
+ def iteritems(self):
+ 'od.iteritems -> an iterator over the (key, value) items in od'
+ for k in self:
+ yield (k, self[k])
+
+ # Suppress 'OrderedDict.update: Method has no argument':
+ # pylint: disable=E0211
+ def update(*args, **kwds):
+ '''od.update(E, **F) -> None. Update od from dict/iterable E and F.
+
+ If E is a dict instance, does: for k in E: od[k] = E[k]
+ If E has a .keys() method, does: for k in E.keys(): od[k] = E[k]
+ Or if E is an iterable of items, does: for k, v in E: od[k] = v
+ In either case, this is followed by: for k, v in F.items(): od[k] = v
+
+ '''
+ if len(args) > 2:
+ raise TypeError('update() takes at most 2 positional '
+ 'arguments (%d given)' % (len(args),))
+ elif not args:
+ raise TypeError('update() takes at least 1 argument (0 given)')
+ self = args[0]
+ # Make progressively weaker assumptions about "other"
+ other = ()
+ if len(args) == 2:
+ other = args[1]
+ if isinstance(other, dict):
+ for key in other:
+ self[key] = other[key]
+ elif hasattr(other, 'keys'):
+ for key in other.keys():
+ self[key] = other[key]
+ else:
+ for key, value in other:
+ self[key] = value
+ for key, value in kwds.items():
+ self[key] = value
+
+ __update = update # let subclasses override update without breaking __init__
+
+ __marker = object()
+
+ def pop(self, key, default=__marker):
+ '''od.pop(k[,d]) -> v, remove specified key and return the corresponding value.
+ If key is not found, d is returned if given, otherwise KeyError is raised.
+
+ '''
+ if key in self:
+ result = self[key]
+ del self[key]
+ return result
+ if default is self.__marker:
+ raise KeyError(key)
+ return default
+
+ def setdefault(self, key, default=None):
+ 'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od'
+ if key in self:
+ return self[key]
+ self[key] = default
+ return default
+
+ def __repr__(self, _repr_running={}):
+ 'od.__repr__() <==> repr(od)'
+ call_key = id(self), _get_ident()
+ if call_key in _repr_running:
+ return '...'
+ _repr_running[call_key] = 1
+ try:
+ if not self:
+ return '%s()' % (self.__class__.__name__,)
+ return '%s(%r)' % (self.__class__.__name__, self.items())
+ finally:
+ del _repr_running[call_key]
+
+ def __reduce__(self):
+ 'Return state information for pickling'
+ items = [[k, self[k]] for k in self]
+ inst_dict = vars(self).copy()
+ for k in vars(OrderedDict()):
+ inst_dict.pop(k, None)
+ if inst_dict:
+ return (self.__class__, (items,), inst_dict)
+ return self.__class__, (items,)
+
+ def copy(self):
+ 'od.copy() -> a shallow copy of od'
+ return self.__class__(self)
+
+ @classmethod
+ def fromkeys(cls, iterable, value=None):
+ '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S
+ and values equal to v (which defaults to None).
+
+ '''
+ d = cls()
+ for key in iterable:
+ d[key] = value
+ return d
+
+ def __eq__(self, other):
+ '''od.__eq__(y) <==> od==y. Comparison to another OD is order-sensitive
+ while comparison to a regular mapping is order-insensitive.
+
+ '''
+ if isinstance(other, OrderedDict):
+ return len(self)==len(other) and self.items() == other.items()
+ return dict.__eq__(self, other)
+
+ def __ne__(self, other):
+ return not self == other
+
+ # -- the following methods are only used in Python 2.7 --
+
+ def viewkeys(self):
+ "od.viewkeys() -> a set-like object providing a view on od's keys"
+ return KeysView(self)
+
+ def viewvalues(self):
+ "od.viewvalues() -> an object providing a view on od's values"
+ return ValuesView(self)
+
+ def viewitems(self):
+ "od.viewitems() -> a set-like object providing a view on od's items"
+ return ItemsView(self)
+
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/simple_copy.py
@@ -0,0 +1,46 @@
+# Copyright 2014 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.
+
+"""A clone of the default copy.deepcopy that doesn't handle cyclic
+structures or complex types except for dicts and lists. This is
+because gyp copies so large structure that small copy overhead ends up
+taking seconds in a project the size of Chromium."""
+
+class Error(Exception):
+ pass
+
+__all__ = ["Error", "deepcopy"]
+
+def deepcopy(x):
+ """Deep copy operation on gyp objects such as strings, ints, dicts
+ and lists. More than twice as fast as copy.deepcopy but much less
+ generic."""
+
+ try:
+ return _deepcopy_dispatch[type(x)](x)
+ except KeyError:
+ raise Error('Unsupported type %s for deepcopy. Use copy.deepcopy ' +
+ 'or expand simple_copy support.' % type(x))
+
+_deepcopy_dispatch = d = {}
+
+def _deepcopy_atomic(x):
+ return x
+
+for x in (type(None), int, long, float,
+ bool, str, unicode, type):
+ d[x] = _deepcopy_atomic
+
+def _deepcopy_list(x):
+ return [deepcopy(a) for a in x]
+d[list] = _deepcopy_list
+
+def _deepcopy_dict(x):
+ y = {}
+ for key, value in x.iteritems():
+ y[deepcopy(key)] = deepcopy(value)
+ return y
+d[dict] = _deepcopy_dict
+
+del d
deleted file mode 100755
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/sun_tool.py
+++ /dev/null
@@ -1,51 +0,0 @@
-#!/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.
-
-"""These functions are executed via gyp-sun-tool when using the Makefile
-generator."""
-
-import fcntl
-import os
-import struct
-import subprocess
-import sys
-
-
-def main(args):
- executor = SunTool()
- executor.Dispatch(args)
-
-
-class SunTool(object):
- """This class performs all the SunOS tooling steps. The methods can either be
- executed directly, or dispatched from an argument list."""
-
- def Dispatch(self, args):
- """Dispatches a string command to a method."""
- if len(args) < 1:
- raise Exception("Not enough arguments")
-
- method = "Exec%s" % self._CommandifyName(args[0])
- getattr(self, method)(*args[1:])
-
- def _CommandifyName(self, name_string):
- """Transforms a tool name like copy-info-plist to CopyInfoPlist"""
- return name_string.title().replace('-', '')
-
- def ExecFlock(self, lockfile, *cmd_list):
- """Emulates the most basic behavior of Linux's flock(1)."""
- # Rely on exception handling to report errors.
- # Note that the stock python on SunOS has a bug
- # where fcntl.flock(fd, LOCK_EX) always fails
- # with EBADF, that's why we use this F_SETLK
- # hack instead.
- fd = os.open(lockfile, os.O_WRONLY|os.O_NOCTTY|os.O_CREAT, 0666)
- op = struct.pack('hhllhhl', fcntl.F_WRLCK, 0, 0, 0, 0, 0, 0)
- fcntl.fcntl(fd, fcntl.F_SETLK, op)
- return subprocess.call(cmd_list)
-
-
-if __name__ == '__main__':
- sys.exit(main(sys.argv[1:]))
old mode 100644
new mode 100755
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/win_tool.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/win_tool.py
@@ -4,61 +4,68 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Utility functions for Windows builds.
These functions are executed via gyp-win-tool when using the ninja generator.
"""
-from ctypes import windll, wintypes
import os
+import re
import shutil
import subprocess
+import stat
+import string
import sys
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
+# A regex matching an argument corresponding to the output filename passed to
+# link.exe.
+_LINK_EXE_OUT_ARG = re.compile('/OUT:(?P<out>.+)$', re.IGNORECASE)
def main(args):
executor = WinTool()
exit_code = executor.Dispatch(args)
if exit_code is not None:
sys.exit(exit_code)
-class LinkLock(object):
- """A flock-style lock to limit the number of concurrent links to one.
-
- Uses a session-local mutex based on the file's directory.
- """
- def __enter__(self):
- name = 'Local\\%s' % BASE_DIR.replace('\\', '_').replace(':', '_')
- self.mutex = windll.kernel32.CreateMutexW(
- wintypes.c_int(0),
- wintypes.c_int(0),
- wintypes.create_unicode_buffer(name))
- assert self.mutex
- result = windll.kernel32.WaitForSingleObject(
- self.mutex, wintypes.c_int(0xFFFFFFFF))
- # 0x80 means another process was killed without releasing the mutex, but
- # that this process has been given ownership. This is fine for our
- # purposes.
- assert result in (0, 0x80), (
- "%s, %s" % (result, windll.kernel32.GetLastError()))
-
- def __exit__(self, type, value, traceback):
- windll.kernel32.ReleaseMutex(self.mutex)
- windll.kernel32.CloseHandle(self.mutex)
-
-
class WinTool(object):
"""This class performs all the Windows tooling steps. The methods can either
be executed directly, or dispatched from an argument list."""
+ def _UseSeparateMspdbsrv(self, env, args):
+ """Allows to use a unique instance of mspdbsrv.exe per linker instead of a
+ shared one."""
+ if len(args) < 1:
+ raise Exception("Not enough arguments")
+
+ if args[0] != 'link.exe':
+ return
+
+ # Use the output filename passed to the linker to generate an endpoint name
+ # for mspdbsrv.exe.
+ endpoint_name = None
+ for arg in args:
+ m = _LINK_EXE_OUT_ARG.match(arg)
+ if m:
+ endpoint_name = re.sub(r'\W+', '',
+ '%s_%d' % (m.group('out'), os.getpid()))
+ break
+
+ if endpoint_name is None:
+ return
+
+ # Adds the appropriate environment variable. This will be read by link.exe
+ # to know which instance of mspdbsrv.exe it should connect to (if it's
+ # not set then the default endpoint is used).
+ env['_MSPDBSRV_ENDPOINT_'] = endpoint_name
+
def Dispatch(self, args):
"""Dispatches a string command to a method."""
if len(args) < 1:
raise Exception("Not enough arguments")
method = "Exec%s" % self._CommandifyName(args[0])
return getattr(self, method)(*args[1:])
@@ -78,52 +85,162 @@ class WinTool(object):
def ExecStamp(self, path):
"""Simple stamp command."""
open(path, 'w').close()
def ExecRecursiveMirror(self, source, dest):
"""Emulation of rm -rf out && cp -af in out."""
if os.path.exists(dest):
if os.path.isdir(dest):
- shutil.rmtree(dest)
+ def _on_error(fn, path, excinfo):
+ # The operation failed, possibly because the file is set to
+ # read-only. If that's why, make it writable and try the op again.
+ if not os.access(path, os.W_OK):
+ os.chmod(path, stat.S_IWRITE)
+ fn(path)
+ shutil.rmtree(dest, onerror=_on_error)
else:
+ if not os.access(dest, os.W_OK):
+ # Attempt to make the file writable before deleting it.
+ os.chmod(dest, stat.S_IWRITE)
os.unlink(dest)
+
if os.path.isdir(source):
shutil.copytree(source, dest)
else:
shutil.copy2(source, dest)
- def ExecLinkWrapper(self, arch, *args):
+ def ExecLinkWrapper(self, arch, use_separate_mspdbsrv, *args):
"""Filter diagnostic output from link that looks like:
' Creating library ui.dll.lib and object ui.dll.exp'
This happens when there are exports from the dll or exe.
"""
- with LinkLock():
- env = self._GetEnv(arch)
- popen = subprocess.Popen(args, shell=True, env=env,
- stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
- out, _ = popen.communicate()
- for line in out.splitlines():
- if not line.startswith(' Creating library '):
- print line
- return popen.returncode
+ env = self._GetEnv(arch)
+ if use_separate_mspdbsrv == 'True':
+ self._UseSeparateMspdbsrv(env, args)
+ if sys.platform == 'win32':
+ args = list(args) # *args is a tuple by default, which is read-only.
+ args[0] = args[0].replace('/', '\\')
+ # https://docs.python.org/2/library/subprocess.html:
+ # "On Unix with shell=True [...] if args is a sequence, the first item
+ # specifies the command string, and any additional items will be treated as
+ # additional arguments to the shell itself. That is to say, Popen does the
+ # equivalent of:
+ # Popen(['/bin/sh', '-c', args[0], args[1], ...])"
+ # For that reason, since going through the shell doesn't seem necessary on
+ # non-Windows don't do that there.
+ link = subprocess.Popen(args, shell=sys.platform == 'win32', env=env,
+ stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+ out, _ = link.communicate()
+ for line in out.splitlines():
+ if (not line.startswith(' Creating library ') and
+ not line.startswith('Generating code') and
+ not line.startswith('Finished generating code')):
+ print line
+ return link.returncode
+
+ def ExecLinkWithManifests(self, arch, embed_manifest, out, ldcmd, resname,
+ mt, rc, intermediate_manifest, *manifests):
+ """A wrapper for handling creating a manifest resource and then executing
+ a link command."""
+ # The 'normal' way to do manifests is to have link generate a manifest
+ # based on gathering dependencies from the object files, then merge that
+ # manifest with other manifests supplied as sources, convert the merged
+ # manifest to a resource, and then *relink*, including the compiled
+ # version of the manifest resource. This breaks incremental linking, and
+ # is generally overly complicated. Instead, we merge all the manifests
+ # provided (along with one that includes what would normally be in the
+ # linker-generated one, see msvs_emulation.py), and include that into the
+ # first and only link. We still tell link to generate a manifest, but we
+ # only use that to assert that our simpler process did not miss anything.
+ variables = {
+ 'python': sys.executable,
+ 'arch': arch,
+ 'out': out,
+ 'ldcmd': ldcmd,
+ 'resname': resname,
+ 'mt': mt,
+ 'rc': rc,
+ 'intermediate_manifest': intermediate_manifest,
+ 'manifests': ' '.join(manifests),
+ }
+ add_to_ld = ''
+ if manifests:
+ subprocess.check_call(
+ '%(python)s gyp-win-tool manifest-wrapper %(arch)s %(mt)s -nologo '
+ '-manifest %(manifests)s -out:%(out)s.manifest' % variables)
+ if embed_manifest == 'True':
+ subprocess.check_call(
+ '%(python)s gyp-win-tool manifest-to-rc %(arch)s %(out)s.manifest'
+ ' %(out)s.manifest.rc %(resname)s' % variables)
+ subprocess.check_call(
+ '%(python)s gyp-win-tool rc-wrapper %(arch)s %(rc)s '
+ '%(out)s.manifest.rc' % variables)
+ add_to_ld = ' %(out)s.manifest.res' % variables
+ subprocess.check_call(ldcmd + add_to_ld)
+
+ # Run mt.exe on the theoretically complete manifest we generated, merging
+ # it with the one the linker generated to confirm that the linker
+ # generated one does not add anything. This is strictly unnecessary for
+ # correctness, it's only to verify that e.g. /MANIFESTDEPENDENCY was not
+ # used in a #pragma comment.
+ if manifests:
+ # Merge the intermediate one with ours to .assert.manifest, then check
+ # that .assert.manifest is identical to ours.
+ subprocess.check_call(
+ '%(python)s gyp-win-tool manifest-wrapper %(arch)s %(mt)s -nologo '
+ '-manifest %(out)s.manifest %(intermediate_manifest)s '
+ '-out:%(out)s.assert.manifest' % variables)
+ assert_manifest = '%(out)s.assert.manifest' % variables
+ our_manifest = '%(out)s.manifest' % variables
+ # Load and normalize the manifests. mt.exe sometimes removes whitespace,
+ # and sometimes doesn't unfortunately.
+ with open(our_manifest, 'rb') as our_f:
+ with open(assert_manifest, 'rb') as assert_f:
+ our_data = our_f.read().translate(None, string.whitespace)
+ assert_data = assert_f.read().translate(None, string.whitespace)
+ if our_data != assert_data:
+ os.unlink(out)
+ def dump(filename):
+ sys.stderr.write('%s\n-----\n' % filename)
+ with open(filename, 'rb') as f:
+ sys.stderr.write(f.read() + '\n-----\n')
+ dump(intermediate_manifest)
+ dump(our_manifest)
+ dump(assert_manifest)
+ sys.stderr.write(
+ 'Linker generated manifest "%s" added to final manifest "%s" '
+ '(result in "%s"). '
+ 'Were /MANIFEST switches used in #pragma statements? ' % (
+ intermediate_manifest, our_manifest, assert_manifest))
+ return 1
def ExecManifestWrapper(self, arch, *args):
"""Run manifest tool with environment set. Strip out undesirable warning
(some XML blocks are recognized by the OS loader, but not the manifest
tool)."""
env = self._GetEnv(arch)
popen = subprocess.Popen(args, shell=True, env=env,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
out, _ = popen.communicate()
for line in out.splitlines():
if line and 'manifest authoring warning 81010002' not in line:
print line
return popen.returncode
+ def ExecManifestToRc(self, arch, *args):
+ """Creates a resource file pointing a SxS assembly manifest.
+ |args| is tuple containing path to resource file, path to manifest file
+ and resource name which can be "1" (for executables) or "2" (for DLLs)."""
+ manifest_path, resource_path, resource_name = args
+ with open(resource_path, 'wb') as output:
+ output.write('#include <windows.h>\n%s RT_MANIFEST "%s"' % (
+ resource_name,
+ os.path.abspath(manifest_path).replace('\\', '/')))
+
def ExecMidlWrapper(self, arch, outdir, tlb, h, dlldata, iid, proxy, idl,
*flags):
"""Filter noisy filenames output from MIDL compile step that isn't
quietable via command line flags.
"""
args = ['midl', '/nologo'] + list(flags) + [
'/out', outdir,
'/tlb', tlb,
@@ -136,29 +253,27 @@ class WinTool(object):
popen = subprocess.Popen(args, shell=True, env=env,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
out, _ = popen.communicate()
# Filter junk out of stdout, and write filtered versions. Output we want
# to filter is pairs of lines that look like this:
# Processing C:\Program Files (x86)\Microsoft SDKs\...\include\objidl.idl
# objidl.idl
lines = out.splitlines()
- prefix = 'Processing '
- processing = set(os.path.basename(x) for x in lines if x.startswith(prefix))
+ prefixes = ('Processing ', '64 bit Processing ')
+ processing = set(os.path.basename(x)
+ for x in lines if x.startswith(prefixes))
for line in lines:
- if not line.startswith(prefix) and line not in processing:
+ if not line.startswith(prefixes) and line not in processing:
print line
return popen.returncode
def ExecAsmWrapper(self, arch, *args):
"""Filter logo banner from invocations of asm.exe."""
env = self._GetEnv(arch)
- # MSVS doesn't assemble x64 asm files.
- if arch == 'environment.x64':
- return 0
popen = subprocess.Popen(args, shell=True, env=env,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
out, _ = popen.communicate()
for line in out.splitlines():
if (not line.startswith('Copyright (C) Microsoft Corporation') and
not line.startswith('Microsoft (R) Macro Assembler') and
not line.startswith(' Assembling: ') and
line):
@@ -178,16 +293,30 @@ class WinTool(object):
line):
print line
return popen.returncode
def ExecActionWrapper(self, arch, rspfile, *dir):
"""Runs an action command line from a response file using the environment
for |arch|. If |dir| is supplied, use that as the working directory."""
env = self._GetEnv(arch)
+ # TODO(scottmg): This is a temporary hack to get some specific variables
+ # through to actions that are set after gyp-time. http://crbug.com/333738.
+ for k, v in os.environ.iteritems():
+ if k not in env:
+ env[k] = v
args = open(rspfile).read()
dir = dir[0] if dir else None
- popen = subprocess.Popen(args, shell=True, env=env, cwd=dir)
- popen.wait()
- return popen.returncode
+ return subprocess.call(args, shell=True, env=env, cwd=dir)
+
+ def ExecClCompile(self, project_dir, selected_files):
+ """Executed by msvs-ninja projects when the 'ClCompile' target is used to
+ build selected C/C++ files."""
+ project_dir = os.path.relpath(project_dir, BASE_DIR)
+ selected_files = selected_files.split(';')
+ ninja_targets = [os.path.join(project_dir, filename) + '^^'
+ for filename in selected_files]
+ cmd = ['ninja.exe']
+ cmd.extend(ninja_targets)
+ return subprocess.call(cmd, shell=True, cwd=BASE_DIR)
if __name__ == '__main__':
sys.exit(main(sys.argv[1:]))
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/xcode_emulation.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/xcode_emulation.py
@@ -2,46 +2,210 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""
This module contains classes that help to emulate xcodebuild behavior on top of
other build systems, such as make and ninja.
"""
+import copy
import gyp.common
+import os
import os.path
import re
import shlex
+import subprocess
+import sys
+import tempfile
+from gyp.common import GypError
+
+# Populated lazily by XcodeVersion, for efficiency, and to fix an issue when
+# "xcodebuild" is called too quickly (it has been found to return incorrect
+# version number).
+XCODE_VERSION_CACHE = None
+
+# Populated lazily by GetXcodeArchsDefault, to an |XcodeArchsDefault| instance
+# corresponding to the installed version of Xcode.
+XCODE_ARCHS_DEFAULT_CACHE = None
+
+
+def XcodeArchsVariableMapping(archs, archs_including_64_bit=None):
+ """Constructs a dictionary with expansion for $(ARCHS_STANDARD) variable,
+ and optionally for $(ARCHS_STANDARD_INCLUDING_64_BIT)."""
+ mapping = {'$(ARCHS_STANDARD)': archs}
+ if archs_including_64_bit:
+ mapping['$(ARCHS_STANDARD_INCLUDING_64_BIT)'] = archs_including_64_bit
+ return mapping
+
+class XcodeArchsDefault(object):
+ """A class to resolve ARCHS variable from xcode_settings, resolving Xcode
+ macros and implementing filtering by VALID_ARCHS. The expansion of macros
+ depends on the SDKROOT used ("macosx", "iphoneos", "iphonesimulator") and
+ on the version of Xcode.
+ """
+
+ # Match variable like $(ARCHS_STANDARD).
+ variable_pattern = re.compile(r'\$\([a-zA-Z_][a-zA-Z0-9_]*\)$')
+
+ def __init__(self, default, mac, iphonesimulator, iphoneos):
+ self._default = (default,)
+ self._archs = {'mac': mac, 'ios': iphoneos, 'iossim': iphonesimulator}
+
+ def _VariableMapping(self, sdkroot):
+ """Returns the dictionary of variable mapping depending on the SDKROOT."""
+ sdkroot = sdkroot.lower()
+ if 'iphoneos' in sdkroot:
+ return self._archs['ios']
+ elif 'iphonesimulator' in sdkroot:
+ return self._archs['iossim']
+ else:
+ return self._archs['mac']
+
+ def _ExpandArchs(self, archs, sdkroot):
+ """Expands variables references in ARCHS, and remove duplicates."""
+ variable_mapping = self._VariableMapping(sdkroot)
+ expanded_archs = []
+ for arch in archs:
+ if self.variable_pattern.match(arch):
+ variable = arch
+ try:
+ variable_expansion = variable_mapping[variable]
+ for arch in variable_expansion:
+ if arch not in expanded_archs:
+ expanded_archs.append(arch)
+ except KeyError as e:
+ print 'Warning: Ignoring unsupported variable "%s".' % variable
+ elif arch not in expanded_archs:
+ expanded_archs.append(arch)
+ return expanded_archs
+
+ def ActiveArchs(self, archs, valid_archs, sdkroot):
+ """Expands variables references in ARCHS, and filter by VALID_ARCHS if it
+ is defined (if not set, Xcode accept any value in ARCHS, otherwise, only
+ values present in VALID_ARCHS are kept)."""
+ expanded_archs = self._ExpandArchs(archs or self._default, sdkroot or '')
+ if valid_archs:
+ filtered_archs = []
+ for arch in expanded_archs:
+ if arch in valid_archs:
+ filtered_archs.append(arch)
+ expanded_archs = filtered_archs
+ return expanded_archs
+
+
+def GetXcodeArchsDefault():
+ """Returns the |XcodeArchsDefault| object to use to expand ARCHS for the
+ installed version of Xcode. The default values used by Xcode for ARCHS
+ and the expansion of the variables depends on the version of Xcode used.
+
+ For all version anterior to Xcode 5.0 or posterior to Xcode 5.1 included
+ uses $(ARCHS_STANDARD) if ARCHS is unset, while Xcode 5.0 to 5.0.2 uses
+ $(ARCHS_STANDARD_INCLUDING_64_BIT). This variable was added to Xcode 5.0
+ and deprecated with Xcode 5.1.
+
+ For "macosx" SDKROOT, all version starting with Xcode 5.0 includes 64-bit
+ architecture as part of $(ARCHS_STANDARD) and default to only building it.
+
+ For "iphoneos" and "iphonesimulator" SDKROOT, 64-bit architectures are part
+ of $(ARCHS_STANDARD_INCLUDING_64_BIT) from Xcode 5.0. From Xcode 5.1, they
+ are also part of $(ARCHS_STANDARD).
+
+ All thoses rules are coded in the construction of the |XcodeArchsDefault|
+ object to use depending on the version of Xcode detected. The object is
+ for performance reason."""
+ global XCODE_ARCHS_DEFAULT_CACHE
+ if XCODE_ARCHS_DEFAULT_CACHE:
+ return XCODE_ARCHS_DEFAULT_CACHE
+ xcode_version, _ = XcodeVersion()
+ if xcode_version < '0500':
+ XCODE_ARCHS_DEFAULT_CACHE = XcodeArchsDefault(
+ '$(ARCHS_STANDARD)',
+ XcodeArchsVariableMapping(['i386']),
+ XcodeArchsVariableMapping(['i386']),
+ XcodeArchsVariableMapping(['armv7']))
+ elif xcode_version < '0510':
+ XCODE_ARCHS_DEFAULT_CACHE = XcodeArchsDefault(
+ '$(ARCHS_STANDARD_INCLUDING_64_BIT)',
+ XcodeArchsVariableMapping(['x86_64'], ['x86_64']),
+ XcodeArchsVariableMapping(['i386'], ['i386', 'x86_64']),
+ XcodeArchsVariableMapping(
+ ['armv7', 'armv7s'],
+ ['armv7', 'armv7s', 'arm64']))
+ else:
+ XCODE_ARCHS_DEFAULT_CACHE = XcodeArchsDefault(
+ '$(ARCHS_STANDARD)',
+ XcodeArchsVariableMapping(['x86_64'], ['x86_64']),
+ XcodeArchsVariableMapping(['i386', 'x86_64'], ['i386', 'x86_64']),
+ XcodeArchsVariableMapping(
+ ['armv7', 'armv7s', 'arm64'],
+ ['armv7', 'armv7s', 'arm64']))
+ return XCODE_ARCHS_DEFAULT_CACHE
+
class XcodeSettings(object):
"""A class that understands the gyp 'xcode_settings' object."""
- # Computed lazily by _GetSdkBaseDir(). Shared by all XcodeSettings, so cached
+ # Populated lazily by _SdkPath(). Shared by all XcodeSettings, so cached
# at class-level for efficiency.
- _sdk_base_dir = None
+ _sdk_path_cache = {}
+ _platform_path_cache = {}
+ _sdk_root_cache = {}
+
+ # Populated lazily by GetExtraPlistItems(). Shared by all XcodeSettings, so
+ # cached at class-level for efficiency.
+ _plist_cache = {}
+
+ # Populated lazily by GetIOSPostbuilds. Shared by all XcodeSettings, so
+ # cached at class-level for efficiency.
+ _codesigning_key_cache = {}
def __init__(self, spec):
self.spec = spec
+ self.isIOS = False
+ self.mac_toolchain_dir = None
+ self.header_map_path = None
+
# Per-target 'xcode_settings' are pushed down into configs earlier by gyp.
# This means self.xcode_settings[config] always contains all settings
# for that config -- the per-target settings as well. Settings that are
# the same for all configs are implicitly per-target settings.
self.xcode_settings = {}
configs = spec['configurations']
for configname, config in configs.iteritems():
self.xcode_settings[configname] = config.get('xcode_settings', {})
+ self._ConvertConditionalKeys(configname)
+ if self.xcode_settings[configname].get('IPHONEOS_DEPLOYMENT_TARGET',
+ None):
+ self.isIOS = True
# This is only non-None temporarily during the execution of some methods.
self.configname = None
# Used by _AdjustLibrary to match .a and .dylib entries in libraries.
self.library_re = re.compile(r'^lib([^/]+)\.(a|dylib)$')
+ def _ConvertConditionalKeys(self, configname):
+ """Converts or warns on conditional keys. Xcode supports conditional keys,
+ such as CODE_SIGN_IDENTITY[sdk=iphoneos*]. This is a partial implementation
+ with some keys converted while the rest force a warning."""
+ settings = self.xcode_settings[configname]
+ conditional_keys = [key for key in settings if key.endswith(']')]
+ for key in conditional_keys:
+ # If you need more, speak up at http://crbug.com/122592
+ if key.endswith("[sdk=iphoneos*]"):
+ if configname.endswith("iphoneos"):
+ new_key = key.split("[")[0]
+ settings[new_key] = settings[key]
+ else:
+ print 'Warning: Conditional keys not implemented, ignoring:', \
+ ' '.join(conditional_keys)
+ del settings[key]
+
def _Settings(self):
assert self.configname
return self.xcode_settings[self.configname]
def _Test(self, test_key, cond_key, default):
return self._Settings().get(test_key, default) == cond_key
def _Appendf(self, lst, test_key, format_str, default=None):
@@ -49,18 +213,44 @@ class XcodeSettings(object):
lst.append(format_str % str(self._Settings()[test_key]))
elif default:
lst.append(format_str % str(default))
def _WarnUnimplemented(self, test_key):
if test_key in self._Settings():
print 'Warning: Ignoring not yet implemented key "%s".' % test_key
+ def IsBinaryOutputFormat(self, configname):
+ default = "binary" if self.isIOS else "xml"
+ format = self.xcode_settings[configname].get('INFOPLIST_OUTPUT_FORMAT',
+ default)
+ return format == "binary"
+
+ def IsIosFramework(self):
+ return self.spec['type'] == 'shared_library' and self._IsBundle() and \
+ self.isIOS
+
def _IsBundle(self):
- return int(self.spec.get('mac_bundle', 0)) != 0
+ return int(self.spec.get('mac_bundle', 0)) != 0 or self._IsXCTest() or \
+ self._IsXCUiTest()
+
+ def _IsXCTest(self):
+ return int(self.spec.get('mac_xctest_bundle', 0)) != 0
+
+ def _IsXCUiTest(self):
+ return int(self.spec.get('mac_xcuitest_bundle', 0)) != 0
+
+ def _IsIosAppExtension(self):
+ return int(self.spec.get('ios_app_extension', 0)) != 0
+
+ def _IsIosWatchKitExtension(self):
+ return int(self.spec.get('ios_watchkit_extension', 0)) != 0
+
+ def _IsIosWatchApp(self):
+ return int(self.spec.get('ios_watch_app', 0)) != 0
def GetFrameworkVersion(self):
"""Returns the framework version of the current target. Only valid for
bundles."""
assert self._IsBundle()
return self.GetPerTargetSetting('FRAMEWORK_VERSION', default='A')
def GetWrapperExtension(self):
@@ -71,17 +261,20 @@ class XcodeSettings(object):
default_wrapper_extension = {
'loadable_module': 'bundle',
'shared_library': 'framework',
}[self.spec['type']]
wrapper_extension = self.GetPerTargetSetting(
'WRAPPER_EXTENSION', default=default_wrapper_extension)
return '.' + self.spec.get('product_extension', wrapper_extension)
elif self.spec['type'] == 'executable':
- return '.app'
+ if self._IsIosAppExtension() or self._IsIosWatchKitExtension():
+ return '.' + self.spec.get('product_extension', 'appex')
+ else:
+ return '.' + self.spec.get('product_extension', 'app')
else:
assert False, "Don't know extension for '%s', target '%s'" % (
self.spec['type'], self.spec['target_name'])
def GetProductName(self):
"""Returns PRODUCT_NAME."""
return self.spec.get('product_name', self.spec['target_name'])
@@ -96,42 +289,113 @@ class XcodeSettings(object):
"""Returns the directory name of the bundle represented by this target.
Only valid for bundles."""
assert self._IsBundle()
return self.GetProductName() + self.GetWrapperExtension()
def GetBundleContentsFolderPath(self):
"""Returns the qualified path to the bundle's contents folder. E.g.
Chromium.app/Contents or Foo.bundle/Versions/A. Only valid for bundles."""
+ if self.isIOS:
+ return self.GetWrapperName()
assert self._IsBundle()
if self.spec['type'] == 'shared_library':
return os.path.join(
self.GetWrapperName(), 'Versions', self.GetFrameworkVersion())
else:
# loadable_modules have a 'Contents' folder like executables.
return os.path.join(self.GetWrapperName(), 'Contents')
def GetBundleResourceFolder(self):
"""Returns the qualified path to the bundle's resource folder. E.g.
Chromium.app/Contents/Resources. Only valid for bundles."""
assert self._IsBundle()
+ if self.isIOS:
+ return self.GetBundleContentsFolderPath()
return os.path.join(self.GetBundleContentsFolderPath(), 'Resources')
+ def GetBundleExecutableFolderPath(self):
+ """Returns the qualified path to the bundle's executables folder. E.g.
+ Chromium.app/Contents/MacOS. Only valid for bundles."""
+ assert self._IsBundle()
+ if self.spec['type'] in ('shared_library') or self.isIOS:
+ return self.GetBundleContentsFolderPath()
+ elif self.spec['type'] in ('executable', 'loadable_module'):
+ return os.path.join(self.GetBundleContentsFolderPath(), 'MacOS')
+
+ def GetBundleJavaFolderPath(self):
+ """Returns the qualified path to the bundle's Java resource folder.
+ E.g. Chromium.app/Contents/Resources/Java. Only valid for bundles."""
+ assert self._IsBundle()
+ return os.path.join(self.GetBundleResourceFolder(), 'Java')
+
+ def GetBundleFrameworksFolderPath(self):
+ """Returns the qualified path to the bundle's frameworks folder. E.g,
+ Chromium.app/Contents/Frameworks. Only valid for bundles."""
+ assert self._IsBundle()
+ return os.path.join(self.GetBundleContentsFolderPath(), 'Frameworks')
+
+ def GetBundleSharedFrameworksFolderPath(self):
+ """Returns the qualified path to the bundle's frameworks folder. E.g,
+ Chromium.app/Contents/SharedFrameworks. Only valid for bundles."""
+ assert self._IsBundle()
+ return os.path.join(self.GetBundleContentsFolderPath(),
+ 'SharedFrameworks')
+
+ def GetBundleSharedSupportFolderPath(self):
+ """Returns the qualified path to the bundle's shared support folder. E.g,
+ Chromium.app/Contents/SharedSupport. Only valid for bundles."""
+ assert self._IsBundle()
+ if self.spec['type'] == 'shared_library':
+ return self.GetBundleResourceFolder()
+ else:
+ return os.path.join(self.GetBundleContentsFolderPath(),
+ 'SharedSupport')
+
+ def GetBundlePlugInsFolderPath(self):
+ """Returns the qualified path to the bundle's plugins folder. E.g,
+ Chromium.app/Contents/PlugIns. Only valid for bundles."""
+ assert self._IsBundle()
+ return os.path.join(self.GetBundleContentsFolderPath(), 'PlugIns')
+
+ def GetBundleXPCServicesFolderPath(self):
+ """Returns the qualified path to the bundle's XPC services folder. E.g,
+ Chromium.app/Contents/XPCServices. Only valid for bundles."""
+ assert self._IsBundle()
+ return os.path.join(self.GetBundleContentsFolderPath(), 'XPCServices')
+
def GetBundlePlistPath(self):
"""Returns the qualified path to the bundle's plist file. E.g.
Chromium.app/Contents/Info.plist. Only valid for bundles."""
assert self._IsBundle()
- if self.spec['type'] in ('executable', 'loadable_module'):
+ if self.spec['type'] in ('executable', 'loadable_module') or \
+ self.IsIosFramework():
return os.path.join(self.GetBundleContentsFolderPath(), 'Info.plist')
else:
return os.path.join(self.GetBundleContentsFolderPath(),
'Resources', 'Info.plist')
def GetProductType(self):
"""Returns the PRODUCT_TYPE of this target."""
+ if self._IsIosAppExtension():
+ assert self._IsBundle(), ('ios_app_extension flag requires mac_bundle '
+ '(target %s)' % self.spec['target_name'])
+ return 'com.apple.product-type.app-extension'
+ if self._IsIosWatchKitExtension():
+ assert self._IsBundle(), ('ios_watchkit_extension flag requires '
+ 'mac_bundle (target %s)' % self.spec['target_name'])
+ return 'com.apple.product-type.watchkit-extension'
+ if self._IsIosWatchApp():
+ assert self._IsBundle(), ('ios_watch_app flag requires mac_bundle '
+ '(target %s)' % self.spec['target_name'])
+ return 'com.apple.product-type.application.watchapp'
+ if self._IsXCUiTest():
+ assert self._IsBundle(), ('mac_xcuitest_bundle flag requires mac_bundle '
+ '(target %s)' % self.spec['target_name'])
+ return 'com.apple.product-type.bundle.ui-testing'
if self._IsBundle():
return {
'executable': 'com.apple.product-type.application',
'loadable_module': 'com.apple.product-type.bundle',
'shared_library': 'com.apple.product-type.framework',
}[self.spec['type']]
else:
return {
@@ -152,21 +416,18 @@ class XcodeSettings(object):
'shared_library': 'mh_dylib',
'loadable_module': 'mh_bundle',
}[self.spec['type']]
def _GetBundleBinaryPath(self):
"""Returns the name of the bundle binary of by this target.
E.g. Chromium.app/Contents/MacOS/Chromium. Only valid for bundles."""
assert self._IsBundle()
- if self.spec['type'] in ('shared_library'):
- path = self.GetBundleContentsFolderPath()
- elif self.spec['type'] in ('executable', 'loadable_module'):
- path = os.path.join(self.GetBundleContentsFolderPath(), 'MacOS')
- return os.path.join(path, self.GetExecutableName())
+ return os.path.join(self.GetBundleExecutableFolderPath(), \
+ self.GetExecutableName())
def _GetStandaloneExecutableSuffix(self):
if 'product_extension' in self.spec:
return '.' + self.spec['product_extension']
return {
'executable': '',
'static_library': '.a',
'shared_library': '.dylib',
@@ -207,65 +468,100 @@ class XcodeSettings(object):
"""Returns the executable name of the bundle represented by this target.
E.g. Chromium."""
if self._IsBundle():
return self.spec.get('product_name', self.spec['target_name'])
else:
return self._GetStandaloneBinaryPath()
def GetExecutablePath(self):
- """Returns the directory name of the bundle represented by this target. E.g.
- Chromium.app/Contents/MacOS/Chromium."""
+ """Returns the qualified path to the primary executable of the bundle
+ represented by this target. E.g. Chromium.app/Contents/MacOS/Chromium."""
if self._IsBundle():
return self._GetBundleBinaryPath()
else:
return self._GetStandaloneBinaryPath()
- def _GetSdkBaseDir(self):
- """Returns the root of the 'Developer' directory. On Xcode 4.2 and prior,
- this is usually just /Developer. Xcode 4.3 moved that folder into the Xcode
- bundle."""
- if not XcodeSettings._sdk_base_dir:
- import subprocess
- job = subprocess.Popen(['xcode-select', '-print-path'],
- stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT)
- out, err = job.communicate()
- if job.returncode != 0:
- print out
- raise Exception('Error %d running xcode-select' % job.returncode)
- # The Developer folder moved in Xcode 4.3.
- xcode43_sdk_path = os.path.join(
- out.rstrip(), 'Platforms/MacOSX.platform/Developer/SDKs')
- if os.path.isdir(xcode43_sdk_path):
- XcodeSettings._sdk_base_dir = xcode43_sdk_path
+ def GetActiveArchs(self, configname):
+ """Returns the architectures this target should be built for."""
+ config_settings = self.xcode_settings[configname]
+ xcode_archs_default = GetXcodeArchsDefault()
+ return xcode_archs_default.ActiveArchs(
+ config_settings.get('ARCHS'),
+ config_settings.get('VALID_ARCHS'),
+ config_settings.get('SDKROOT'))
+
+ def _GetSdkVersionInfoItem(self, sdk, infoitem):
+ # xcodebuild requires Xcode and can't run on Command Line Tools-only
+ # systems from 10.7 onward.
+ # Since the CLT has no SDK paths anyway, returning None is the
+ # most sensible route and should still do the right thing.
+ try:
+ return GetStdout(['xcrun', '--sdk', sdk, infoitem])
+ except:
+ pass
+
+ def _SdkRoot(self, configname):
+ if configname is None:
+ configname = self.configname
+ return self.GetPerConfigSetting('SDKROOT', configname, default='')
+
+ def _XcodePlatformPath(self, configname=None):
+ sdk_root = self._SdkRoot(configname)
+ if sdk_root not in XcodeSettings._platform_path_cache:
+ platform_path = self._GetSdkVersionInfoItem(sdk_root,
+ '--show-sdk-platform-path')
+ XcodeSettings._platform_path_cache[sdk_root] = platform_path
+ return XcodeSettings._platform_path_cache[sdk_root]
+
+ def _SdkPath(self, configname=None):
+ sdk_root = self._SdkRoot(configname)
+ if sdk_root.startswith('/'):
+ return sdk_root
+ return self._XcodeSdkPath(sdk_root)
+
+ def _XcodeSdkPath(self, sdk_root):
+ if sdk_root not in XcodeSettings._sdk_path_cache:
+ sdk_path = self._GetSdkVersionInfoItem(sdk_root, '--show-sdk-path')
+ XcodeSettings._sdk_path_cache[sdk_root] = sdk_path
+ if sdk_root:
+ XcodeSettings._sdk_root_cache[sdk_path] = sdk_root
+ return XcodeSettings._sdk_path_cache[sdk_root]
+
+ def _AppendPlatformVersionMinFlags(self, lst):
+ self._Appendf(lst, 'MACOSX_DEPLOYMENT_TARGET', '-mmacosx-version-min=%s')
+ if 'IPHONEOS_DEPLOYMENT_TARGET' in self._Settings():
+ # TODO: Implement this better?
+ sdk_path_basename = os.path.basename(self._SdkPath())
+ if sdk_path_basename.lower().startswith('iphonesimulator'):
+ self._Appendf(lst, 'IPHONEOS_DEPLOYMENT_TARGET',
+ '-mios-simulator-version-min=%s')
else:
- XcodeSettings._sdk_base_dir = os.path.join(out.rstrip(), 'SDKs')
- return XcodeSettings._sdk_base_dir
+ self._Appendf(lst, 'IPHONEOS_DEPLOYMENT_TARGET',
+ '-miphoneos-version-min=%s')
- def _SdkPath(self):
- sdk_root = self.GetPerTargetSetting('SDKROOT', default='macosx10.5')
- if sdk_root.startswith('macosx'):
- return os.path.join(self._GetSdkBaseDir(),
- 'MacOSX' + sdk_root[len('macosx'):] + '.sdk')
- return sdk_root
-
- def GetCflags(self, configname):
+ def GetCflags(self, configname, arch=None):
"""Returns flags that need to be added to .c, .cc, .m, and .mm
compilations."""
# This functions (and the similar ones below) do not offer complete
# emulation of all xcode_settings keys. They're implemented on demand.
self.configname = configname
cflags = []
sdk_root = self._SdkPath()
- if 'SDKROOT' in self._Settings():
+ if 'SDKROOT' in self._Settings() and sdk_root:
cflags.append('-isysroot %s' % sdk_root)
+ if self.header_map_path:
+ cflags.append('-I%s' % self.header_map_path)
+
+ if self._Test('CLANG_WARN_CONSTANT_CONVERSION', 'YES', default='NO'):
+ cflags.append('-Wconstant-conversion')
+
if self._Test('GCC_CHAR_IS_UNSIGNED_CHAR', 'YES', default='NO'):
cflags.append('-funsigned-char')
if self._Test('GCC_CW_ASM_SYNTAX', 'YES', default='YES'):
cflags.append('-fasm-blocks')
if 'GCC_DYNAMIC_NO_PIC' in self._Settings():
if self._Settings()['GCC_DYNAMIC_NO_PIC'] == 'YES':
@@ -287,38 +583,54 @@ class XcodeSettings(object):
cflags.append('-gdwarf-2')
elif dbg_format == 'stabs':
raise NotImplementedError('stabs debug format is not supported yet.')
elif dbg_format == 'dwarf-with-dsym':
cflags.append('-gdwarf-2')
else:
raise NotImplementedError('Unknown debug format %s' % dbg_format)
+ if self._Settings().get('GCC_STRICT_ALIASING') == 'YES':
+ cflags.append('-fstrict-aliasing')
+ elif self._Settings().get('GCC_STRICT_ALIASING') == 'NO':
+ cflags.append('-fno-strict-aliasing')
+
if self._Test('GCC_SYMBOLS_PRIVATE_EXTERN', 'YES', default='NO'):
cflags.append('-fvisibility=hidden')
if self._Test('GCC_TREAT_WARNINGS_AS_ERRORS', 'YES', default='NO'):
cflags.append('-Werror')
if self._Test('GCC_WARN_ABOUT_MISSING_NEWLINE', 'YES', default='NO'):
cflags.append('-Wnewline-eof')
- self._Appendf(cflags, 'MACOSX_DEPLOYMENT_TARGET', '-mmacosx-version-min=%s')
+ # In Xcode, this is only activated when GCC_COMPILER_VERSION is clang or
+ # llvm-gcc. It also requires a fairly recent libtool, and
+ # if the system clang isn't used, DYLD_LIBRARY_PATH needs to contain the
+ # path to the libLTO.dylib that matches the used clang.
+ if self._Test('LLVM_LTO', 'YES', default='NO'):
+ cflags.append('-flto')
+
+ self._AppendPlatformVersionMinFlags(cflags)
# TODO:
if self._Test('COPY_PHASE_STRIP', 'YES', default='NO'):
self._WarnUnimplemented('COPY_PHASE_STRIP')
self._WarnUnimplemented('GCC_DEBUGGING_SYMBOLS')
self._WarnUnimplemented('GCC_ENABLE_OBJC_EXCEPTIONS')
# TODO: This is exported correctly, but assigning to it is not supported.
self._WarnUnimplemented('MACH_O_TYPE')
self._WarnUnimplemented('PRODUCT_TYPE')
- archs = self._Settings().get('ARCHS', ['i386'])
+ if arch is not None:
+ archs = [arch]
+ else:
+ assert self.configname
+ archs = self.GetActiveArchs(self.configname)
if len(archs) != 1:
# TODO: Supporting fat binaries will be annoying.
self._WarnUnimplemented('ARCHS')
archs = ['i386']
cflags.append('-arch ' + archs[0])
if archs[0] in ('i386', 'x86_64'):
if self._Test('GCC_ENABLE_SSE3_EXTENSIONS', 'YES', default='NO'):
@@ -328,45 +640,67 @@ class XcodeSettings(object):
cflags.append('-mssse3') # Note 3rd 's'.
if self._Test('GCC_ENABLE_SSE41_EXTENSIONS', 'YES', default='NO'):
cflags.append('-msse4.1')
if self._Test('GCC_ENABLE_SSE42_EXTENSIONS', 'YES', default='NO'):
cflags.append('-msse4.2')
cflags += self._Settings().get('WARNING_CFLAGS', [])
+ platform_root = self._XcodePlatformPath(configname)
+ if platform_root and self._IsXCTest():
+ cflags.append('-F' + platform_root + '/Developer/Library/Frameworks/')
+
+ if sdk_root:
+ framework_root = sdk_root
+ else:
+ framework_root = ''
config = self.spec['configurations'][self.configname]
framework_dirs = config.get('mac_framework_dirs', [])
for directory in framework_dirs:
- cflags.append('-F' + directory.replace('$(SDKROOT)', sdk_root))
+ cflags.append('-F' + directory.replace('$(SDKROOT)', framework_root))
self.configname = None
return cflags
def GetCflagsC(self, configname):
"""Returns flags that need to be added to .c, and .m compilations."""
self.configname = configname
cflags_c = []
- self._Appendf(cflags_c, 'GCC_C_LANGUAGE_STANDARD', '-std=%s')
+ if self._Settings().get('GCC_C_LANGUAGE_STANDARD', '') == 'ansi':
+ cflags_c.append('-ansi')
+ else:
+ self._Appendf(cflags_c, 'GCC_C_LANGUAGE_STANDARD', '-std=%s')
cflags_c += self._Settings().get('OTHER_CFLAGS', [])
self.configname = None
return cflags_c
def GetCflagsCC(self, configname):
"""Returns flags that need to be added to .cc, and .mm compilations."""
self.configname = configname
cflags_cc = []
+
+ clang_cxx_language_standard = self._Settings().get(
+ 'CLANG_CXX_LANGUAGE_STANDARD')
+ # Note: Don't make c++0x to c++11 so that c++0x can be used with older
+ # clangs that don't understand c++11 yet (like Xcode 4.2's).
+ if clang_cxx_language_standard:
+ cflags_cc.append('-std=%s' % clang_cxx_language_standard)
+
+ self._Appendf(cflags_cc, 'CLANG_CXX_LIBRARY', '-stdlib=%s')
+
if self._Test('GCC_ENABLE_CPP_RTTI', 'NO', default='YES'):
cflags_cc.append('-fno-rtti')
if self._Test('GCC_ENABLE_CPP_EXCEPTIONS', 'NO', default='YES'):
cflags_cc.append('-fno-exceptions')
if self._Test('GCC_INLINES_ARE_PRIVATE_EXTERN', 'YES', default='NO'):
cflags_cc.append('-fvisibility-inlines-hidden')
if self._Test('GCC_THREADSAFE_STATICS', 'NO', default='YES'):
cflags_cc.append('-fno-threadsafe-statics')
+ # Note: This flag is a no-op for clang, it only has an effect for gcc.
if self._Test('GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO', 'NO', default='YES'):
cflags_cc.append('-Wno-invalid-offsetof')
other_ccflags = []
for flag in self._Settings().get('OTHER_CPLUSPLUSFLAGS', ['$(inherited)']):
# TODO: More general variable expansion. Missing in many other places too.
if flag in ('$inherited', '$(inherited)', '${inherited}'):
@@ -382,31 +716,42 @@ class XcodeSettings(object):
def _AddObjectiveCGarbageCollectionFlags(self, flags):
gc_policy = self._Settings().get('GCC_ENABLE_OBJC_GC', 'unsupported')
if gc_policy == 'supported':
flags.append('-fobjc-gc')
elif gc_policy == 'required':
flags.append('-fobjc-gc-only')
+ def _AddObjectiveCARCFlags(self, flags):
+ if self._Test('CLANG_ENABLE_OBJC_ARC', 'YES', default='NO'):
+ flags.append('-fobjc-arc')
+
+ def _AddObjectiveCMissingPropertySynthesisFlags(self, flags):
+ if self._Test('CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS',
+ 'YES', default='NO'):
+ flags.append('-Wobjc-missing-property-synthesis')
+
def GetCflagsObjC(self, configname):
"""Returns flags that need to be added to .m compilations."""
self.configname = configname
cflags_objc = []
-
self._AddObjectiveCGarbageCollectionFlags(cflags_objc)
-
+ self._AddObjectiveCARCFlags(cflags_objc)
+ self._AddObjectiveCMissingPropertySynthesisFlags(cflags_objc)
self.configname = None
return cflags_objc
def GetCflagsObjCC(self, configname):
"""Returns flags that need to be added to .mm compilations."""
self.configname = configname
cflags_objcc = []
self._AddObjectiveCGarbageCollectionFlags(cflags_objcc)
+ self._AddObjectiveCARCFlags(cflags_objcc)
+ self._AddObjectiveCMissingPropertySynthesisFlags(cflags_objcc)
if self._Test('GCC_OBJC_CALL_CXX_CDTORS', 'YES', default='NO'):
cflags_objcc.append('-fobjc-call-cxx-cdtors')
self.configname = None
return cflags_objcc
def GetInstallNameBase(self):
"""Return DYLIB_INSTALL_NAME_BASE for this target."""
# Xcode sets this for shared_libraries, and for nonbundled loadable_modules.
@@ -471,18 +816,18 @@ class XcodeSettings(object):
def _MapLinkerFlagFilename(self, ldflag, gyp_to_build_path):
"""Checks if ldflag contains a filename and if so remaps it from
gyp-directory-relative to build-directory-relative."""
# This list is expanded on demand.
# They get matched as:
# -exported_symbols_list file
# -Wl,exported_symbols_list file
# -Wl,exported_symbols_list,file
- LINKER_FILE = '(\S+)'
- WORD = '\S+'
+ LINKER_FILE = r'(\S+)'
+ WORD = r'\S+'
linker_flags = [
['-exported_symbols_list', LINKER_FILE], # Needed for NaCl.
['-unexported_symbols_list', LINKER_FILE],
['-reexported_symbols_list', LINKER_FILE],
['-sectcreate', WORD, WORD, LINKER_FILE], # Needed for remoting.
]
for flag_pattern in linker_flags:
regex = re.compile('(?:-Wl,)?' + '[ ,]'.join(flag_pattern))
@@ -491,17 +836,17 @@ class XcodeSettings(object):
ldflag = ldflag[:m.start(1)] + gyp_to_build_path(m.group(1)) + \
ldflag[m.end(1):]
# Required for ffmpeg (no idea why they don't use LIBRARY_SEARCH_PATHS,
# TODO(thakis): Update ffmpeg.gyp):
if ldflag.startswith('-L'):
ldflag = '-L' + gyp_to_build_path(ldflag[len('-L'):])
return ldflag
- def GetLdflags(self, configname, product_dir, gyp_to_build_path):
+ def GetLdflags(self, configname, product_dir, gyp_to_build_path, arch=None):
"""Returns flags that need to be passed to the linker.
Args:
configname: The name of the configuration to get ld flags for.
product_dir: The directory where products such static and dynamic
libraries are placed. This is added to the library search path.
gyp_to_build_path: A function that converts paths relative to the
current gyp file to paths relative to the build direcotry.
@@ -519,50 +864,80 @@ class XcodeSettings(object):
if self._Test('PREBINDING', 'YES', default='NO'):
ldflags.append('-Wl,-prebind')
self._Appendf(
ldflags, 'DYLIB_COMPATIBILITY_VERSION', '-compatibility_version %s')
self._Appendf(
ldflags, 'DYLIB_CURRENT_VERSION', '-current_version %s')
- self._Appendf(
- ldflags, 'MACOSX_DEPLOYMENT_TARGET', '-mmacosx-version-min=%s')
- if 'SDKROOT' in self._Settings():
+
+ self._AppendPlatformVersionMinFlags(ldflags)
+
+ if 'SDKROOT' in self._Settings() and self._SdkPath():
ldflags.append('-isysroot ' + self._SdkPath())
for library_path in self._Settings().get('LIBRARY_SEARCH_PATHS', []):
ldflags.append('-L' + gyp_to_build_path(library_path))
if 'ORDER_FILE' in self._Settings():
ldflags.append('-Wl,-order_file ' +
'-Wl,' + gyp_to_build_path(
self._Settings()['ORDER_FILE']))
- archs = self._Settings().get('ARCHS', ['i386'])
+ if arch is not None:
+ archs = [arch]
+ else:
+ assert self.configname
+ archs = self.GetActiveArchs(self.configname)
if len(archs) != 1:
# TODO: Supporting fat binaries will be annoying.
self._WarnUnimplemented('ARCHS')
archs = ['i386']
ldflags.append('-arch ' + archs[0])
# Xcode adds the product directory by default.
- ldflags.append('-L' + product_dir)
+ # Rewrite -L. to -L./ to work around http://www.openradar.me/25313838
+ ldflags.append('-L' + (product_dir if product_dir != '.' else './'))
install_name = self.GetInstallName()
- if install_name:
+ if install_name and self.spec['type'] != 'loadable_module':
ldflags.append('-install_name ' + install_name.replace(' ', r'\ '))
for rpath in self._Settings().get('LD_RUNPATH_SEARCH_PATHS', []):
ldflags.append('-Wl,-rpath,' + rpath)
+ sdk_root = self._SdkPath()
+ if not sdk_root:
+ sdk_root = ''
config = self.spec['configurations'][self.configname]
framework_dirs = config.get('mac_framework_dirs', [])
for directory in framework_dirs:
- ldflags.append('-F' + directory.replace('$(SDKROOT)', self._SdkPath()))
+ ldflags.append('-F' + directory.replace('$(SDKROOT)', sdk_root))
+
+ platform_root = self._XcodePlatformPath(configname)
+ if sdk_root and platform_root and self._IsXCTest():
+ ldflags.append('-F' + platform_root + '/Developer/Library/Frameworks/')
+ ldflags.append('-framework XCTest')
+
+ is_extension = self._IsIosAppExtension() or self._IsIosWatchKitExtension()
+ if sdk_root and is_extension:
+ # Adds the link flags for extensions. These flags are common for all
+ # extensions and provide loader and main function.
+ # These flags reflect the compilation options used by xcode to compile
+ # extensions.
+ if XcodeVersion() < '0900':
+ ldflags.append('-lpkstart')
+ ldflags.append(sdk_root +
+ '/System/Library/PrivateFrameworks/PlugInKit.framework/PlugInKit')
+ else:
+ ldflags.append('-e _NSExtensionMain')
+ ldflags.append('-fapplication-extension')
+
+ self._Appendf(ldflags, 'CLANG_CXX_LIBRARY', '-stdlib=%s')
self.configname = None
return ldflags
def GetLibtoolflags(self, configname):
"""Returns flags that need to be passed to the static linker.
Args:
@@ -590,45 +965,52 @@ class XcodeSettings(object):
else:
for key, value in self.xcode_settings[configname].iteritems():
if key not in result:
continue
elif result[key] != value:
del result[key]
return result
+ def GetPerConfigSetting(self, setting, configname, default=None):
+ if configname in self.xcode_settings:
+ return self.xcode_settings[configname].get(setting, default)
+ else:
+ return self.GetPerTargetSetting(setting, default)
+
def GetPerTargetSetting(self, setting, default=None):
"""Tries to get xcode_settings.setting from spec. Assumes that the setting
has the same value in all configurations and throws otherwise."""
- first_pass = True
+ is_first_pass = True
result = None
for configname in sorted(self.xcode_settings.keys()):
- if first_pass:
+ if is_first_pass:
result = self.xcode_settings[configname].get(setting, None)
- first_pass = False
+ is_first_pass = False
else:
assert result == self.xcode_settings[configname].get(setting, None), (
"Expected per-target setting for '%s', got per-config setting "
- "(target %s)" % (setting, spec['target_name']))
+ "(target %s)" % (setting, self.spec['target_name']))
if result is None:
return default
return result
def _GetStripPostbuilds(self, configname, output_binary, quiet):
"""Returns a list of shell commands that contain the shell commands
neccessary to strip this target's binary. These should be run as postbuilds
before the actual postbuilds run."""
self.configname = configname
result = []
if (self._Test('DEPLOYMENT_POSTPROCESSING', 'YES', default='NO') and
self._Test('STRIP_INSTALLED_PRODUCT', 'YES', default='NO')):
default_strip_style = 'debugging'
- if self._IsBundle():
+ if ((self.spec['type'] == 'loadable_module' or self._IsIosAppExtension())
+ and self._IsBundle()):
default_strip_style = 'non-global'
elif self.spec['type'] == 'executable':
default_strip_style = 'all'
strip_style = self._Settings().get('STRIP_STYLE', default_strip_style)
strip_flags = {
'all': '',
'non-global': '-x',
@@ -660,42 +1042,240 @@ class XcodeSettings(object):
self.spec['type'] != 'static_library'):
if not quiet:
result.append('echo DSYMUTIL\\(%s\\)' % self.spec['target_name'])
result.append('dsymutil %s -o %s' % (output_binary, output + '.dSYM'))
self.configname = None
return result
- def GetTargetPostbuilds(self, configname, output, output_binary, quiet=False):
+ def _GetTargetPostbuilds(self, configname, output, output_binary,
+ quiet=False):
"""Returns a list of shell commands that contain the shell commands
to run as postbuilds for this target, before the actual postbuilds."""
# dSYMs need to build before stripping happens.
return (
self._GetDebugInfoPostbuilds(configname, output, output_binary, quiet) +
self._GetStripPostbuilds(configname, output_binary, quiet))
- def _AdjustLibrary(self, library):
+ def _GetIOSPostbuilds(self, configname, output_binary):
+ """Return a shell command to codesign the iOS output binary so it can
+ be deployed to a device. This should be run as the very last step of the
+ build."""
+ if not (self.isIOS and
+ (self.spec['type'] == 'executable' or self._IsXCTest()) or
+ self.IsIosFramework()):
+ return []
+
+ postbuilds = []
+ product_name = self.GetFullProductName()
+ settings = self.xcode_settings[configname]
+
+ # Xcode expects XCTests to be copied into the TEST_HOST dir.
+ if self._IsXCTest():
+ source = os.path.join("${BUILT_PRODUCTS_DIR}", product_name)
+ test_host = os.path.dirname(settings.get('TEST_HOST'));
+ xctest_destination = os.path.join(test_host, 'PlugIns', product_name)
+ postbuilds.extend(['ditto %s %s' % (source, xctest_destination)])
+
+ key = self._GetIOSCodeSignIdentityKey(settings)
+ if not key:
+ return postbuilds
+
+ # Warn for any unimplemented signing xcode keys.
+ unimpl = ['OTHER_CODE_SIGN_FLAGS']
+ unimpl = set(unimpl) & set(self.xcode_settings[configname].keys())
+ if unimpl:
+ print 'Warning: Some codesign keys not implemented, ignoring: %s' % (
+ ', '.join(sorted(unimpl)))
+
+ if self._IsXCTest():
+ # For device xctests, Xcode copies two extra frameworks into $TEST_HOST.
+ test_host = os.path.dirname(settings.get('TEST_HOST'));
+ frameworks_dir = os.path.join(test_host, 'Frameworks')
+ platform_root = self._XcodePlatformPath(configname)
+ frameworks = \
+ ['Developer/Library/PrivateFrameworks/IDEBundleInjection.framework',
+ 'Developer/Library/Frameworks/XCTest.framework']
+ for framework in frameworks:
+ source = os.path.join(platform_root, framework)
+ destination = os.path.join(frameworks_dir, os.path.basename(framework))
+ postbuilds.extend(['ditto %s %s' % (source, destination)])
+
+ # Then re-sign everything with 'preserve=True'
+ postbuilds.extend(['%s code-sign-bundle "%s" "%s" "%s" "%s" %s' % (
+ os.path.join('${TARGET_BUILD_DIR}', 'gyp-mac-tool'), key,
+ settings.get('CODE_SIGN_ENTITLEMENTS', ''),
+ settings.get('PROVISIONING_PROFILE', ''), destination, True)
+ ])
+ plugin_dir = os.path.join(test_host, 'PlugIns')
+ targets = [os.path.join(plugin_dir, product_name), test_host]
+ for target in targets:
+ postbuilds.extend(['%s code-sign-bundle "%s" "%s" "%s" "%s" %s' % (
+ os.path.join('${TARGET_BUILD_DIR}', 'gyp-mac-tool'), key,
+ settings.get('CODE_SIGN_ENTITLEMENTS', ''),
+ settings.get('PROVISIONING_PROFILE', ''), target, True)
+ ])
+
+ postbuilds.extend(['%s code-sign-bundle "%s" "%s" "%s" "%s" %s' % (
+ os.path.join('${TARGET_BUILD_DIR}', 'gyp-mac-tool'), key,
+ settings.get('CODE_SIGN_ENTITLEMENTS', ''),
+ settings.get('PROVISIONING_PROFILE', ''),
+ os.path.join("${BUILT_PRODUCTS_DIR}", product_name), False)
+ ])
+ return postbuilds
+
+ def _GetIOSCodeSignIdentityKey(self, settings):
+ identity = settings.get('CODE_SIGN_IDENTITY')
+ if not identity:
+ return None
+ if identity not in XcodeSettings._codesigning_key_cache:
+ output = subprocess.check_output(
+ ['security', 'find-identity', '-p', 'codesigning', '-v'])
+ for line in output.splitlines():
+ if identity in line:
+ fingerprint = line.split()[1]
+ cache = XcodeSettings._codesigning_key_cache
+ assert identity not in cache or fingerprint == cache[identity], (
+ "Multiple codesigning fingerprints for identity: %s" % identity)
+ XcodeSettings._codesigning_key_cache[identity] = fingerprint
+ return XcodeSettings._codesigning_key_cache.get(identity, '')
+
+ def AddImplicitPostbuilds(self, configname, output, output_binary,
+ postbuilds=[], quiet=False):
+ """Returns a list of shell commands that should run before and after
+ |postbuilds|."""
+ assert output_binary is not None
+ pre = self._GetTargetPostbuilds(configname, output, output_binary, quiet)
+ post = self._GetIOSPostbuilds(configname, output_binary)
+ return pre + postbuilds + post
+
+ def _AdjustLibrary(self, library, config_name=None):
if library.endswith('.framework'):
l = '-framework ' + os.path.splitext(os.path.basename(library))[0]
else:
m = self.library_re.match(library)
if m:
l = '-l' + m.group(1)
else:
l = library
- return l.replace('$(SDKROOT)', self._SdkPath())
- def AdjustLibraries(self, libraries):
+ sdk_root = self._SdkPath(config_name)
+ if not sdk_root:
+ sdk_root = ''
+ # Xcode 7 started shipping with ".tbd" (text based stubs) files instead of
+ # ".dylib" without providing a real support for them. What it does, for
+ # "/usr/lib" libraries, is do "-L/usr/lib -lname" which is dependent on the
+ # library order and cause collision when building Chrome.
+ #
+ # Instead substitude ".tbd" to ".dylib" in the generated project when the
+ # following conditions are both true:
+ # - library is referenced in the gyp file as "$(SDKROOT)/**/*.dylib",
+ # - the ".dylib" file does not exists but a ".tbd" file do.
+ library = l.replace('$(SDKROOT)', sdk_root)
+ if l.startswith('$(SDKROOT)'):
+ basename, ext = os.path.splitext(library)
+ if ext == '.dylib' and not os.path.exists(library):
+ tbd_library = basename + '.tbd'
+ if os.path.exists(tbd_library):
+ library = tbd_library
+ return library
+
+ def AdjustLibraries(self, libraries, config_name=None):
"""Transforms entries like 'Cocoa.framework' in libraries into entries like
'-framework Cocoa', 'libcrypto.dylib' into '-lcrypto', etc.
"""
- libraries = [ self._AdjustLibrary(library) for library in libraries]
+ libraries = [self._AdjustLibrary(library, config_name)
+ for library in libraries]
return libraries
+ def _BuildMachineOSBuild(self):
+ return GetStdout(['sw_vers', '-buildVersion'])
+
+ def _XcodeIOSDeviceFamily(self, configname):
+ family = self.xcode_settings[configname].get('TARGETED_DEVICE_FAMILY', '1')
+ return [int(x) for x in family.split(',')]
+
+ def GetExtraPlistItems(self, configname=None):
+ """Returns a dictionary with extra items to insert into Info.plist."""
+ if configname not in XcodeSettings._plist_cache:
+ cache = {}
+ cache['BuildMachineOSBuild'] = self._BuildMachineOSBuild()
+
+ xcode, xcode_build = XcodeVersion()
+ cache['DTXcode'] = xcode
+ cache['DTXcodeBuild'] = xcode_build
+ compiler = self.xcode_settings[configname].get('GCC_VERSION')
+ if compiler is not None:
+ cache['DTCompiler'] = compiler
+
+ sdk_root = self._SdkRoot(configname)
+ if not sdk_root:
+ sdk_root = self._DefaultSdkRoot()
+ sdk_version = self._GetSdkVersionInfoItem(sdk_root, '--show-sdk-version')
+ cache['DTSDKName'] = sdk_root + (sdk_version or '')
+ if xcode >= '0720':
+ cache['DTSDKBuild'] = self._GetSdkVersionInfoItem(
+ sdk_root, '--show-sdk-build-version')
+ elif xcode >= '0430':
+ cache['DTSDKBuild'] = sdk_version
+ else:
+ cache['DTSDKBuild'] = cache['BuildMachineOSBuild']
+
+ if self.isIOS:
+ cache['MinimumOSVersion'] = self.xcode_settings[configname].get(
+ 'IPHONEOS_DEPLOYMENT_TARGET')
+ cache['DTPlatformName'] = sdk_root
+ cache['DTPlatformVersion'] = sdk_version
+
+ if configname.endswith("iphoneos"):
+ cache['CFBundleSupportedPlatforms'] = ['iPhoneOS']
+ cache['DTPlatformBuild'] = cache['DTSDKBuild']
+ else:
+ cache['CFBundleSupportedPlatforms'] = ['iPhoneSimulator']
+ # This is weird, but Xcode sets DTPlatformBuild to an empty field
+ # for simulator builds.
+ cache['DTPlatformBuild'] = ""
+ XcodeSettings._plist_cache[configname] = cache
+
+ # Include extra plist items that are per-target, not per global
+ # XcodeSettings.
+ items = dict(XcodeSettings._plist_cache[configname])
+ if self.isIOS:
+ items['UIDeviceFamily'] = self._XcodeIOSDeviceFamily(configname)
+ return items
+
+ def _DefaultSdkRoot(self):
+ """Returns the default SDKROOT to use.
+
+ Prior to version 5.0.0, if SDKROOT was not explicitly set in the Xcode
+ project, then the environment variable was empty. Starting with this
+ version, Xcode uses the name of the newest SDK installed.
+ """
+ xcode_version, xcode_build = XcodeVersion()
+ if xcode_version < '0500':
+ return ''
+ default_sdk_path = self._XcodeSdkPath('')
+ default_sdk_root = XcodeSettings._sdk_root_cache.get(default_sdk_path)
+ if default_sdk_root:
+ return default_sdk_root
+ try:
+ all_sdks = GetStdout(['xcodebuild', '-showsdks'])
+ except:
+ # If xcodebuild fails, there will be no valid SDKs
+ return ''
+ for line in all_sdks.splitlines():
+ items = line.split()
+ if len(items) >= 3 and items[-2] == '-sdk':
+ sdk_root = items[-1]
+ sdk_path = self._XcodeSdkPath(sdk_root)
+ if sdk_path == default_sdk_path:
+ return sdk_root
+ return ''
+
class MacPrefixHeader(object):
"""A class that helps with emulating Xcode's GCC_PREFIX_HEADER feature.
This feature consists of several pieces:
* If GCC_PREFIX_HEADER is present, all compilations in that project get an
additional |-include path_to_prefix_header| cflag.
* If GCC_PRECOMPILE_PREFIX_HEADER is present too, then the prefix header is
@@ -737,31 +1317,38 @@ class MacPrefixHeader(object):
self.compiled_headers = {}
if self.header:
if self.compile_headers:
for lang in ['c', 'cc', 'm', 'mm']:
self.compiled_headers[lang] = gyp_path_to_build_output(
self.header, lang)
self.header = gyp_path_to_build_path(self.header)
- def GetInclude(self, lang):
+ def _CompiledHeader(self, lang, arch):
+ assert self.compile_headers
+ h = self.compiled_headers[lang]
+ if arch:
+ h += '.' + arch
+ return h
+
+ def GetInclude(self, lang, arch=None):
"""Gets the cflags to include the prefix header for language |lang|."""
if self.compile_headers and lang in self.compiled_headers:
- return '-include %s' % self.compiled_headers[lang]
+ return '-include %s' % self._CompiledHeader(lang, arch)
elif self.header:
return '-include %s' % self.header
else:
return ''
- def _Gch(self, lang):
+ def _Gch(self, lang, arch):
"""Returns the actual file name of the prefix header for language |lang|."""
assert self.compile_headers
- return self.compiled_headers[lang] + '.gch'
+ return self._CompiledHeader(lang, arch) + '.gch'
- def GetObjDependencies(self, sources, objs):
+ def GetObjDependencies(self, sources, objs, arch=None):
"""Given a list of source files and the corresponding object files, returns
a list of (source, object, gch) tuples, where |gch| is the build-directory
relative path to the gch file each object file depends on. |compilable[i]|
has to be the source file belonging to |objs[i]|."""
if not self.header or not self.compile_headers:
return []
result = []
@@ -769,33 +1356,108 @@ class MacPrefixHeader(object):
ext = os.path.splitext(source)[1]
lang = {
'.c': 'c',
'.cpp': 'cc', '.cc': 'cc', '.cxx': 'cc',
'.m': 'm',
'.mm': 'mm',
}.get(ext, None)
if lang:
- result.append((source, obj, self._Gch(lang)))
+ result.append((source, obj, self._Gch(lang, arch)))
return result
- def GetPchBuildCommands(self):
+ def GetPchBuildCommands(self, arch=None):
"""Returns [(path_to_gch, language_flag, language, header)].
|path_to_gch| and |header| are relative to the build directory.
"""
if not self.header or not self.compile_headers:
return []
return [
- (self._Gch('c'), '-x c-header', 'c', self.header),
- (self._Gch('cc'), '-x c++-header', 'cc', self.header),
- (self._Gch('m'), '-x objective-c-header', 'm', self.header),
- (self._Gch('mm'), '-x objective-c++-header', 'mm', self.header),
+ (self._Gch('c', arch), '-x c-header', 'c', self.header),
+ (self._Gch('cc', arch), '-x c++-header', 'cc', self.header),
+ (self._Gch('m', arch), '-x objective-c-header', 'm', self.header),
+ (self._Gch('mm', arch), '-x objective-c++-header', 'mm', self.header),
]
+def XcodeVersion():
+ """Returns a tuple of version and build version of installed Xcode."""
+ # `xcodebuild -version` output looks like
+ # Xcode 4.6.3
+ # Build version 4H1503
+ # or like
+ # Xcode 3.2.6
+ # Component versions: DevToolsCore-1809.0; DevToolsSupport-1806.0
+ # BuildVersion: 10M2518
+ # Convert that to '0463', '4H1503'.
+ global XCODE_VERSION_CACHE
+ if XCODE_VERSION_CACHE:
+ return XCODE_VERSION_CACHE
+ try:
+ version_list = GetStdout(['xcodebuild', '-version']).splitlines()
+ # In some circumstances xcodebuild exits 0 but doesn't return
+ # the right results; for example, a user on 10.7 or 10.8 with
+ # a bogus path set via xcode-select
+ # In that case this may be a CLT-only install so fall back to
+ # checking that version.
+ if len(version_list) < 2:
+ raise GypError("xcodebuild returned unexpected results")
+ except:
+ version = CLTVersion()
+ if version:
+ version = re.match(r'(\d\.\d\.?\d*)', version).groups()[0]
+ else:
+ raise GypError("No Xcode or CLT version detected!")
+ # The CLT has no build information, so we return an empty string.
+ version_list = [version, '']
+ version = version_list[0]
+ build = version_list[-1]
+ # Be careful to convert "4.2" to "0420":
+ version = version.split()[-1].replace('.', '')
+ version = (version + '0' * (3 - len(version))).zfill(4)
+ if build:
+ build = build.split()[-1]
+ XCODE_VERSION_CACHE = (version, build)
+ return XCODE_VERSION_CACHE
+
+
+# This function ported from the logic in Homebrew's CLT version check
+def CLTVersion():
+ """Returns the version of command-line tools from pkgutil."""
+ # pkgutil output looks like
+ # package-id: com.apple.pkg.CLTools_Executables
+ # version: 5.0.1.0.1.1382131676
+ # volume: /
+ # location: /
+ # install-time: 1382544035
+ # groups: com.apple.FindSystemFiles.pkg-group com.apple.DevToolsBoth.pkg-group com.apple.DevToolsNonRelocatableShared.pkg-group
+ STANDALONE_PKG_ID = "com.apple.pkg.DeveloperToolsCLILeo"
+ FROM_XCODE_PKG_ID = "com.apple.pkg.DeveloperToolsCLI"
+ MAVERICKS_PKG_ID = "com.apple.pkg.CLTools_Executables"
+
+ regex = re.compile('version: (?P<version>.+)')
+ for key in [MAVERICKS_PKG_ID, STANDALONE_PKG_ID, FROM_XCODE_PKG_ID]:
+ try:
+ output = GetStdout(['/usr/sbin/pkgutil', '--pkg-info', key])
+ return re.search(regex, output).groupdict()['version']
+ except:
+ continue
+
+
+def GetStdout(cmdlist):
+ """Returns the content of standard output returned by invoking |cmdlist|.
+ Raises |GypError| if the command return with a non-zero return code."""
+ job = subprocess.Popen(cmdlist, stdout=subprocess.PIPE)
+ out = job.communicate()[0]
+ if job.returncode != 0:
+ sys.stderr.write(out + '\n')
+ raise GypError('Error %d running %s' % (job.returncode, cmdlist[0]))
+ return out.rstrip('\n')
+
+
def MergeGlobalXcodeSettingsToSpec(global_dict, spec):
"""Merges the global xcode_settings dictionary into each configuration of the
target represented by spec. For keys that are both in the global and the local
xcode_settings dict, the local key gets precendence.
"""
# The xcode generator special-cases global xcode_settings and does something
# that amounts to merging in the global xcode_settings into each local
# xcode_settings dict.
@@ -808,17 +1470,20 @@ def MergeGlobalXcodeSettingsToSpec(globa
def IsMacBundle(flavor, spec):
"""Returns if |spec| should be treated as a bundle.
Bundles are directories with a certain subdirectory structure, instead of
just a single file. Bundle rules do not produce a binary but also package
resources into that directory."""
- is_mac_bundle = (int(spec.get('mac_bundle', 0)) != 0 and flavor == 'mac')
+ is_mac_bundle = int(spec.get('mac_xctest_bundle', 0)) != 0 or \
+ int(spec.get('mac_xcuitest_bundle', 0)) != 0 or \
+ (int(spec.get('mac_bundle', 0)) != 0 and flavor == 'mac')
+
if is_mac_bundle:
assert spec['type'] != 'none', (
'mac_bundle targets cannot have type none (target "%s")' %
spec['target_name'])
return is_mac_bundle
def GetMacBundleResources(product_dir, xcode_settings, resources):
@@ -848,24 +1513,27 @@ def GetMacBundleResources(product_dir, x
lproj_parts = os.path.split(res_parts[0])
# If the resource lives in a .lproj bundle, add that to the destination.
if lproj_parts[1].endswith('.lproj'):
output = os.path.join(output, lproj_parts[1])
output = os.path.join(output, res_parts[1])
# Compiled XIB files are referred to by .nib.
if output.endswith('.xib'):
- output = output[0:-3] + 'nib'
+ output = os.path.splitext(output)[0] + '.nib'
+ # Compiled storyboard files are referred to by .storyboardc.
+ if output.endswith('.storyboard'):
+ output = os.path.splitext(output)[0] + '.storyboardc'
yield output, res
def GetMacInfoPlist(product_dir, xcode_settings, gyp_path_to_build_path):
"""Returns (info_plist, dest_plist, defines, extra_env), where:
- * |info_plist| is the sourc plist path, relative to the
+ * |info_plist| is the source plist path, relative to the
build directory,
* |dest_plist| is the destination plist path, relative to the
build directory,
* |defines| is a list of preprocessor defines (empty if the plist
shouldn't be preprocessed,
* |extra_env| is a dict of env variables that should be exported when
invoking |mac_tool copy-info-plist|.
@@ -915,63 +1583,91 @@ def _GetXcodeEnv(xcode_settings, built_p
xcode_settings: An XcodeSettings object. If this is None, this function
returns an empty dict.
built_products_dir: Absolute path to the built products dir.
srcroot: Absolute path to the source root.
configuration: The build configuration name.
additional_settings: An optional dict with more values to add to the
result.
"""
+
if not xcode_settings: return {}
# This function is considered a friend of XcodeSettings, so let it reach into
# its implementation details.
spec = xcode_settings.spec
- # These are filled in on a as-needed basis.
+ # These are filled in on an as-needed basis.
env = {
+ 'BUILT_FRAMEWORKS_DIR' : built_products_dir,
'BUILT_PRODUCTS_DIR' : built_products_dir,
'CONFIGURATION' : configuration,
'PRODUCT_NAME' : xcode_settings.GetProductName(),
# See /Developer/Platforms/MacOSX.platform/Developer/Library/Xcode/Specifications/MacOSX\ Product\ Types.xcspec for FULL_PRODUCT_NAME
'SRCROOT' : srcroot,
'SOURCE_ROOT': '${SRCROOT}',
# This is not true for static libraries, but currently the env is only
# written for bundles:
'TARGET_BUILD_DIR' : built_products_dir,
'TEMP_DIR' : '${TMPDIR}',
+ 'XCODE_VERSION_ACTUAL' : XcodeVersion()[0],
}
- if xcode_settings.GetPerTargetSetting('SDKROOT'):
- env['SDKROOT'] = xcode_settings._SdkPath()
+ if xcode_settings.GetPerConfigSetting('SDKROOT', configuration):
+ env['SDKROOT'] = xcode_settings._SdkPath(configuration)
else:
env['SDKROOT'] = ''
+ if xcode_settings.mac_toolchain_dir:
+ env['DEVELOPER_DIR'] = xcode_settings.mac_toolchain_dir
+
if spec['type'] in (
'executable', 'static_library', 'shared_library', 'loadable_module'):
env['EXECUTABLE_NAME'] = xcode_settings.GetExecutableName()
env['EXECUTABLE_PATH'] = xcode_settings.GetExecutablePath()
env['FULL_PRODUCT_NAME'] = xcode_settings.GetFullProductName()
mach_o_type = xcode_settings.GetMachOType()
if mach_o_type:
env['MACH_O_TYPE'] = mach_o_type
env['PRODUCT_TYPE'] = xcode_settings.GetProductType()
if xcode_settings._IsBundle():
+ # xcodeproj_file.py sets the same Xcode subfolder value for this as for
+ # FRAMEWORKS_FOLDER_PATH so Xcode builds will actually use FFP's value.
+ env['BUILT_FRAMEWORKS_DIR'] = \
+ os.path.join(built_products_dir + os.sep \
+ + xcode_settings.GetBundleFrameworksFolderPath())
env['CONTENTS_FOLDER_PATH'] = \
- xcode_settings.GetBundleContentsFolderPath()
+ xcode_settings.GetBundleContentsFolderPath()
+ env['EXECUTABLE_FOLDER_PATH'] = \
+ xcode_settings.GetBundleExecutableFolderPath()
env['UNLOCALIZED_RESOURCES_FOLDER_PATH'] = \
xcode_settings.GetBundleResourceFolder()
+ env['JAVA_FOLDER_PATH'] = xcode_settings.GetBundleJavaFolderPath()
+ env['FRAMEWORKS_FOLDER_PATH'] = \
+ xcode_settings.GetBundleFrameworksFolderPath()
+ env['SHARED_FRAMEWORKS_FOLDER_PATH'] = \
+ xcode_settings.GetBundleSharedFrameworksFolderPath()
+ env['SHARED_SUPPORT_FOLDER_PATH'] = \
+ xcode_settings.GetBundleSharedSupportFolderPath()
+ env['PLUGINS_FOLDER_PATH'] = xcode_settings.GetBundlePlugInsFolderPath()
+ env['XPCSERVICES_FOLDER_PATH'] = \
+ xcode_settings.GetBundleXPCServicesFolderPath()
env['INFOPLIST_PATH'] = xcode_settings.GetBundlePlistPath()
env['WRAPPER_NAME'] = xcode_settings.GetWrapperName()
install_name = xcode_settings.GetInstallName()
if install_name:
env['LD_DYLIB_INSTALL_NAME'] = install_name
install_name_base = xcode_settings.GetInstallNameBase()
if install_name_base:
env['DYLIB_INSTALL_NAME_BASE'] = install_name_base
+ if XcodeVersion() >= '0500' and not env.get('SDKROOT'):
+ sdk_root = xcode_settings._SdkRoot(configuration)
+ if not sdk_root:
+ sdk_root = xcode_settings._XcodeSdkPath('')
+ env['SDKROOT'] = sdk_root
if not additional_settings:
additional_settings = {}
else:
# Flatten lists to strings.
for k in additional_settings:
if not isinstance(additional_settings[k], str):
additional_settings[k] = ' '.join(additional_settings[k])
@@ -1037,17 +1733,17 @@ def _TopologicallySortedEnvVarKeys(env):
try:
# Topologically sort, and then reverse, because we used an edge definition
# that's inverted from the expected result of this function (see comment
# above).
order = gyp.common.TopologicallySorted(env.keys(), GetEdges)
order.reverse()
return order
except gyp.common.CycleError, e:
- raise Exception(
+ raise GypError(
'Xcode environment variables are cyclically dependent: ' + str(e.nodes))
def GetSortedXcodeEnv(xcode_settings, built_products_dir, srcroot,
configuration, additional_settings=None):
env = _GetXcodeEnv(xcode_settings, built_products_dir, srcroot, configuration,
additional_settings)
return [(key, env[key]) for key in _TopologicallySortedEnvVarKeys(env)]
@@ -1058,8 +1754,41 @@ def GetSpecPostbuildCommands(spec, quiet
executable by a shell."""
postbuilds = []
for postbuild in spec.get('postbuilds', []):
if not quiet:
postbuilds.append('echo POSTBUILD\\(%s\\) %s' % (
spec['target_name'], postbuild['postbuild_name']))
postbuilds.append(gyp.common.EncodePOSIXShellList(postbuild['action']))
return postbuilds
+
+
+def _HasIOSTarget(targets):
+ """Returns true if any target contains the iOS specific key
+ IPHONEOS_DEPLOYMENT_TARGET."""
+ for target_dict in targets.values():
+ for config in target_dict['configurations'].values():
+ if config.get('xcode_settings', {}).get('IPHONEOS_DEPLOYMENT_TARGET'):
+ return True
+ return False
+
+
+def _AddIOSDeviceConfigurations(targets):
+ """Clone all targets and append -iphoneos to the name. Configure these targets
+ to build for iOS devices and use correct architectures for those builds."""
+ for target_dict in targets.itervalues():
+ toolset = target_dict['toolset']
+ configs = target_dict['configurations']
+ for config_name, simulator_config_dict in dict(configs).iteritems():
+ iphoneos_config_dict = copy.deepcopy(simulator_config_dict)
+ configs[config_name + '-iphoneos'] = iphoneos_config_dict
+ configs[config_name + '-iphonesimulator'] = simulator_config_dict
+ if toolset == 'target':
+ simulator_config_dict['xcode_settings']['SDKROOT'] = 'iphonesimulator'
+ iphoneos_config_dict['xcode_settings']['SDKROOT'] = 'iphoneos'
+ return targets
+
+def CloneConfigurationForDeviceAndEmulator(target_dicts):
+ """If |target_dicts| contains any iOS targets, automatically create -iphoneos
+ targets for iOS device builds."""
+ if _HasIOSTarget(target_dicts):
+ return _AddIOSDeviceConfigurations(target_dicts)
+ return target_dicts
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/xcode_ninja.py
@@ -0,0 +1,289 @@
+# Copyright (c) 2014 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.
+
+"""Xcode-ninja wrapper project file generator.
+
+This updates the data structures passed to the Xcode gyp generator to build
+with ninja instead. The Xcode project itself is transformed into a list of
+executable targets, each with a build step to build with ninja, and a target
+with every source and resource file. This appears to sidestep some of the
+major performance headaches experienced using complex projects and large number
+of targets within Xcode.
+"""
+
+import errno
+import gyp.generator.ninja
+import os
+import re
+import xml.sax.saxutils
+
+
+def _WriteWorkspace(main_gyp, sources_gyp, params):
+ """ Create a workspace to wrap main and sources gyp paths. """
+ (build_file_root, build_file_ext) = os.path.splitext(main_gyp)
+ workspace_path = build_file_root + '.xcworkspace'
+ options = params['options']
+ if options.generator_output:
+ workspace_path = os.path.join(options.generator_output, workspace_path)
+ try:
+ os.makedirs(workspace_path)
+ except OSError, e:
+ if e.errno != errno.EEXIST:
+ raise
+ output_string = '<?xml version="1.0" encoding="UTF-8"?>\n' + \
+ '<Workspace version = "1.0">\n'
+ for gyp_name in [main_gyp, sources_gyp]:
+ name = os.path.splitext(os.path.basename(gyp_name))[0] + '.xcodeproj'
+ name = xml.sax.saxutils.quoteattr("group:" + name)
+ output_string += ' <FileRef location = %s></FileRef>\n' % name
+ output_string += '</Workspace>\n'
+
+ workspace_file = os.path.join(workspace_path, "contents.xcworkspacedata")
+
+ try:
+ with open(workspace_file, 'r') as input_file:
+ input_string = input_file.read()
+ if input_string == output_string:
+ return
+ except IOError:
+ # Ignore errors if the file doesn't exist.
+ pass
+
+ with open(workspace_file, 'w') as output_file:
+ output_file.write(output_string)
+
+def _TargetFromSpec(old_spec, params):
+ """ Create fake target for xcode-ninja wrapper. """
+ # Determine ninja top level build dir (e.g. /path/to/out).
+ ninja_toplevel = None
+ jobs = 0
+ if params:
+ options = params['options']
+ ninja_toplevel = \
+ os.path.join(options.toplevel_dir,
+ gyp.generator.ninja.ComputeOutputDir(params))
+ jobs = params.get('generator_flags', {}).get('xcode_ninja_jobs', 0)
+
+ target_name = old_spec.get('target_name')
+ product_name = old_spec.get('product_name', target_name)
+ product_extension = old_spec.get('product_extension')
+
+ ninja_target = {}
+ ninja_target['target_name'] = target_name
+ ninja_target['product_name'] = product_name
+ if product_extension:
+ ninja_target['product_extension'] = product_extension
+ ninja_target['toolset'] = old_spec.get('toolset')
+ ninja_target['default_configuration'] = old_spec.get('default_configuration')
+ ninja_target['configurations'] = {}
+
+ # Tell Xcode to look in |ninja_toplevel| for build products.
+ new_xcode_settings = {}
+ if ninja_toplevel:
+ new_xcode_settings['CONFIGURATION_BUILD_DIR'] = \
+ "%s/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)" % ninja_toplevel
+
+ if 'configurations' in old_spec:
+ for config in old_spec['configurations'].iterkeys():
+ old_xcode_settings = \
+ old_spec['configurations'][config].get('xcode_settings', {})
+ if 'IPHONEOS_DEPLOYMENT_TARGET' in old_xcode_settings:
+ new_xcode_settings['CODE_SIGNING_REQUIRED'] = "NO"
+ new_xcode_settings['IPHONEOS_DEPLOYMENT_TARGET'] = \
+ old_xcode_settings['IPHONEOS_DEPLOYMENT_TARGET']
+ for key in ['BUNDLE_LOADER', 'TEST_HOST']:
+ if key in old_xcode_settings:
+ new_xcode_settings[key] = old_xcode_settings[key]
+
+ ninja_target['configurations'][config] = {}
+ ninja_target['configurations'][config]['xcode_settings'] = \
+ new_xcode_settings
+
+ ninja_target['mac_bundle'] = old_spec.get('mac_bundle', 0)
+ ninja_target['mac_xctest_bundle'] = old_spec.get('mac_xctest_bundle', 0)
+ ninja_target['ios_app_extension'] = old_spec.get('ios_app_extension', 0)
+ ninja_target['ios_watchkit_extension'] = \
+ old_spec.get('ios_watchkit_extension', 0)
+ ninja_target['ios_watchkit_app'] = old_spec.get('ios_watchkit_app', 0)
+ ninja_target['type'] = old_spec['type']
+ if ninja_toplevel:
+ ninja_target['actions'] = [
+ {
+ 'action_name': 'Compile and copy %s via ninja' % target_name,
+ 'inputs': [],
+ 'outputs': [],
+ 'action': [
+ 'env',
+ 'PATH=%s' % os.environ['PATH'],
+ 'ninja',
+ '-C',
+ new_xcode_settings['CONFIGURATION_BUILD_DIR'],
+ target_name,
+ ],
+ 'message': 'Compile and copy %s via ninja' % target_name,
+ },
+ ]
+ if jobs > 0:
+ ninja_target['actions'][0]['action'].extend(('-j', jobs))
+ return ninja_target
+
+def IsValidTargetForWrapper(target_extras, executable_target_pattern, spec):
+ """Limit targets for Xcode wrapper.
+
+ Xcode sometimes performs poorly with too many targets, so only include
+ proper executable targets, with filters to customize.
+ Arguments:
+ target_extras: Regular expression to always add, matching any target.
+ executable_target_pattern: Regular expression limiting executable targets.
+ spec: Specifications for target.
+ """
+ target_name = spec.get('target_name')
+ # Always include targets matching target_extras.
+ if target_extras is not None and re.search(target_extras, target_name):
+ return True
+
+ # Otherwise just show executable targets and xc_tests.
+ if (int(spec.get('mac_xctest_bundle', 0)) != 0 or
+ (spec.get('type', '') == 'executable' and
+ spec.get('product_extension', '') != 'bundle')):
+
+ # If there is a filter and the target does not match, exclude the target.
+ if executable_target_pattern is not None:
+ if not re.search(executable_target_pattern, target_name):
+ return False
+ return True
+ return False
+
+def CreateWrapper(target_list, target_dicts, data, params):
+ """Initialize targets for the ninja wrapper.
+
+ This sets up the necessary variables in the targets to generate Xcode projects
+ that use ninja as an external builder.
+ Arguments:
+ target_list: List of target pairs: 'base/base.gyp:base'.
+ target_dicts: Dict of target properties keyed on target pair.
+ data: Dict of flattened build files keyed on gyp path.
+ params: Dict of global options for gyp.
+ """
+ orig_gyp = params['build_files'][0]
+ for gyp_name, gyp_dict in data.iteritems():
+ if gyp_name == orig_gyp:
+ depth = gyp_dict['_DEPTH']
+
+ # Check for custom main gyp name, otherwise use the default CHROMIUM_GYP_FILE
+ # and prepend .ninja before the .gyp extension.
+ generator_flags = params.get('generator_flags', {})
+ main_gyp = generator_flags.get('xcode_ninja_main_gyp', None)
+ if main_gyp is None:
+ (build_file_root, build_file_ext) = os.path.splitext(orig_gyp)
+ main_gyp = build_file_root + ".ninja" + build_file_ext
+
+ # Create new |target_list|, |target_dicts| and |data| data structures.
+ new_target_list = []
+ new_target_dicts = {}
+ new_data = {}
+
+ # Set base keys needed for |data|.
+ new_data[main_gyp] = {}
+ new_data[main_gyp]['included_files'] = []
+ new_data[main_gyp]['targets'] = []
+ new_data[main_gyp]['xcode_settings'] = \
+ data[orig_gyp].get('xcode_settings', {})
+
+ # Normally the xcode-ninja generator includes only valid executable targets.
+ # If |xcode_ninja_executable_target_pattern| is set, that list is reduced to
+ # executable targets that match the pattern. (Default all)
+ executable_target_pattern = \
+ generator_flags.get('xcode_ninja_executable_target_pattern', None)
+
+ # For including other non-executable targets, add the matching target name
+ # to the |xcode_ninja_target_pattern| regular expression. (Default none)
+ target_extras = generator_flags.get('xcode_ninja_target_pattern', None)
+
+ for old_qualified_target in target_list:
+ spec = target_dicts[old_qualified_target]
+ if IsValidTargetForWrapper(target_extras, executable_target_pattern, spec):
+ # Add to new_target_list.
+ target_name = spec.get('target_name')
+ new_target_name = '%s:%s#target' % (main_gyp, target_name)
+ new_target_list.append(new_target_name)
+
+ # Add to new_target_dicts.
+ new_target_dicts[new_target_name] = _TargetFromSpec(spec, params)
+
+ # Add to new_data.
+ for old_target in data[old_qualified_target.split(':')[0]]['targets']:
+ if old_target['target_name'] == target_name:
+ new_data_target = {}
+ new_data_target['target_name'] = old_target['target_name']
+ new_data_target['toolset'] = old_target['toolset']
+ new_data[main_gyp]['targets'].append(new_data_target)
+
+ # Create sources target.
+ sources_target_name = 'sources_for_indexing'
+ sources_target = _TargetFromSpec(
+ { 'target_name' : sources_target_name,
+ 'toolset': 'target',
+ 'default_configuration': 'Default',
+ 'mac_bundle': '0',
+ 'type': 'executable'
+ }, None)
+
+ # Tell Xcode to look everywhere for headers.
+ sources_target['configurations'] = {'Default': { 'include_dirs': [ depth ] } }
+
+ # Put excluded files into the sources target so they can be opened in Xcode.
+ skip_excluded_files = \
+ not generator_flags.get('xcode_ninja_list_excluded_files', True)
+
+ sources = []
+ for target, target_dict in target_dicts.iteritems():
+ base = os.path.dirname(target)
+ files = target_dict.get('sources', []) + \
+ target_dict.get('mac_bundle_resources', [])
+
+ if not skip_excluded_files:
+ files.extend(target_dict.get('sources_excluded', []) +
+ target_dict.get('mac_bundle_resources_excluded', []))
+
+ for action in target_dict.get('actions', []):
+ files.extend(action.get('inputs', []))
+
+ if not skip_excluded_files:
+ files.extend(action.get('inputs_excluded', []))
+
+ # Remove files starting with $. These are mostly intermediate files for the
+ # build system.
+ files = [ file for file in files if not file.startswith('$')]
+
+ # Make sources relative to root build file.
+ relative_path = os.path.dirname(main_gyp)
+ sources += [ os.path.relpath(os.path.join(base, file), relative_path)
+ for file in files ]
+
+ sources_target['sources'] = sorted(set(sources))
+
+ # Put sources_to_index in it's own gyp.
+ sources_gyp = \
+ os.path.join(os.path.dirname(main_gyp), sources_target_name + ".gyp")
+ fully_qualified_target_name = \
+ '%s:%s#target' % (sources_gyp, sources_target_name)
+
+ # Add to new_target_list, new_target_dicts and new_data.
+ new_target_list.append(fully_qualified_target_name)
+ new_target_dicts[fully_qualified_target_name] = sources_target
+ new_data_target = {}
+ new_data_target['target_name'] = sources_target['target_name']
+ new_data_target['_DEPTH'] = depth
+ new_data_target['toolset'] = "target"
+ new_data[sources_gyp] = {}
+ new_data[sources_gyp]['targets'] = []
+ new_data[sources_gyp]['included_files'] = []
+ new_data[sources_gyp]['xcode_settings'] = \
+ data[orig_gyp].get('xcode_settings', {})
+ new_data[sources_gyp]['targets'].append(new_data_target)
+
+ # Write workspace to file.
+ _WriteWorkspace(main_gyp, sources_gyp, params)
+ return (new_target_list, new_target_dicts, new_data)
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/xcodeproj_file.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/xcodeproj_file.py
@@ -164,21 +164,21 @@ except ImportError:
_unquoted = re.compile('^[A-Za-z0-9$./_]+$')
# Strings that match this pattern are quoted regardless of what _unquoted says.
# Oddly, Xcode will quote any string with a run of three or more underscores.
_quoted = re.compile('___')
# This pattern should match any character that needs to be escaped by
# XCObject._EncodeString. See that function.
-_escaped = re.compile('[\\\\"]|[^ -~]')
+_escaped = re.compile('[\\\\"]|[\x00-\x1f]')
# Used by SourceTreeAndPathFromPath
-_path_leading_variable = re.compile('^\$\((.*?)\)(/(.*))?$')
+_path_leading_variable = re.compile(r'^\$\((.*?)\)(/(.*))?$')
def SourceTreeAndPathFromPath(input_path):
"""Given input_path, returns a tuple with sourceTree and path values.
Examples:
input_path (source_tree, output_path)
'$(VAR)/path' ('VAR', 'path')
'$(VAR)' ('VAR', None)
@@ -191,17 +191,17 @@ def SourceTreeAndPathFromPath(input_path
output_path = source_group_match.group(3) # This may be None.
else:
source_tree = None
output_path = input_path
return (source_tree, output_path)
def ConvertVariablesToShellSyntax(input_string):
- return re.sub('\$\((.*?)\)', '${\\1}', input_string)
+ return re.sub(r'\$\((.*?)\)', '${\\1}', input_string)
class XCObject(object):
"""The abstract base of all class types used in Xcode project files.
Class variables:
_schema: A dictionary defining the properties of this class. The keys to
_schema are string property keys as used in project files. Values
are a list of four or five elements:
@@ -336,23 +336,23 @@ class XCObject(object):
new_item = item.Copy()
new_item.parent = that
that._properties[key].append(new_item)
else:
that._properties[key] = value[:]
elif isinstance(value, dict):
# dicts are never strong.
if is_strong:
- raise TypeError, 'Strong dict for key ' + key + ' in ' + \
- self.__class__.__name__
+ raise TypeError('Strong dict for key ' + key + ' in ' + \
+ self.__class__.__name__)
else:
that._properties[key] = value.copy()
else:
- raise TypeError, 'Unexpected type ' + value.__class__.__name__ + \
- ' for key ' + key + ' in ' + self.__class__.__name__
+ raise TypeError('Unexpected type ' + value.__class__.__name__ + \
+ ' for key ' + key + ' in ' + self.__class__.__name__)
return that
def Name(self):
"""Return the name corresponding to an object.
Not all objects necessarily need to be nameable, and not all that do have
a "name" property. Override as needed.
@@ -361,18 +361,17 @@ class XCObject(object):
# If the schema indicates that "name" is required, try to access the
# property even if it doesn't exist. This will result in a KeyError
# being raised for the property that should be present, which seems more
# appropriate than NotImplementedError in this case.
if 'name' in self._properties or \
('name' in self._schema and self._schema['name'][3]):
return self._properties['name']
- raise NotImplementedError, \
- self.__class__.__name__ + ' must implement Name'
+ raise NotImplementedError(self.__class__.__name__ + ' must implement Name')
def Comment(self):
"""Return a comment string for the object.
Most objects just use their name as the comment, but PBXProject uses
different values.
The returned comment is not escaped and does not have any comment marker
@@ -461,20 +460,20 @@ class XCObject(object):
"""Verifies that no two objects have the same ID. Checks all descendants.
"""
ids = {}
descendants = self.Descendants()
for descendant in descendants:
if descendant.id in ids:
other = ids[descendant.id]
- raise KeyError, \
+ raise KeyError(
'Duplicate ID %s, objects "%s" and "%s" in "%s"' % \
(descendant.id, str(descendant._properties),
- str(other._properties), self._properties['rootObject'].Name())
+ str(other._properties), self._properties['rootObject'].Name()))
ids[descendant.id] = descendant
def Children(self):
"""Returns a list of all of this object's owned (strong) children."""
children = []
for property, attributes in self._schema.iteritems():
(is_list, property_type, is_strong) = attributes[0:3]
@@ -552,19 +551,19 @@ class XCObject(object):
# 9 ^I HT is passed through as-is without escaping
# 10 ^J NL is passed through as-is without escaping
# 13 ^M CR is passed through as-is without escaping
# - In other objects:
# 9 ^I HT is encoded as "\t"
# 10 ^J NL is encoded as "\n"
# 13 ^M CR is encoded as "\n" rendering it indistinguishable from
# 10 ^J NL
- # All other nonprintable characters within the ASCII range (0 through 127
- # inclusive) are encoded as "\U001f" referring to the Unicode code point in
- # hexadecimal. For example, character 14 (^N SO) is encoded as "\U000e".
+ # All other characters within the ASCII control character range (0 through
+ # 31 inclusive) are encoded as "\U001f" referring to the Unicode code point
+ # in hexadecimal. For example, character 14 (^N SO) is encoded as "\U000e".
# Characters above the ASCII range are passed through to the output encoded
# as UTF-8 without any escaping. These mappings are contained in the
# class' _encode_transforms list.
if _unquoted.search(value) and not _quoted.search(value):
return value
return '"' + _escaped.sub(self._EncodeTransform, value) + '"'
@@ -625,17 +624,17 @@ class XCObject(object):
printable = '{' + sep
for item_key, item_value in sorted(value.iteritems()):
printable += element_tabs + \
self._XCPrintableValue(tabs + 1, item_key, flatten_list) + ' = ' + \
self._XCPrintableValue(tabs + 1, item_value, flatten_list) + ';' + \
sep
printable += end_tabs + '}'
else:
- raise TypeError, "Can't make " + value.__class__.__name__ + ' printable'
+ raise TypeError("Can't make " + value.__class__.__name__ + ' printable')
if comment != None:
printable += ' ' + self._EncodeComment(comment)
return printable
def _XCKVPrint(self, file, tabs, key, value):
"""Prints a key and value, members of an XCObject's _properties dictionary,
@@ -751,41 +750,41 @@ class XCObject(object):
"""
if properties is None:
return
for property, value in properties.iteritems():
# Make sure the property is in the schema.
if not property in self._schema:
- raise KeyError, property + ' not in ' + self.__class__.__name__
+ raise KeyError(property + ' not in ' + self.__class__.__name__)
# Make sure the property conforms to the schema.
(is_list, property_type, is_strong) = self._schema[property][0:3]
if is_list:
if value.__class__ != list:
- raise TypeError, \
+ raise TypeError(
property + ' of ' + self.__class__.__name__ + \
- ' must be list, not ' + value.__class__.__name__
+ ' must be list, not ' + value.__class__.__name__)
for item in value:
if not isinstance(item, property_type) and \
not (item.__class__ == unicode and property_type == str):
# Accept unicode where str is specified. str is treated as
# UTF-8-encoded.
- raise TypeError, \
+ raise TypeError(
'item of ' + property + ' of ' + self.__class__.__name__ + \
' must be ' + property_type.__name__ + ', not ' + \
- item.__class__.__name__
+ item.__class__.__name__)
elif not isinstance(value, property_type) and \
not (value.__class__ == unicode and property_type == str):
# Accept unicode where str is specified. str is treated as
# UTF-8-encoded.
- raise TypeError, \
+ raise TypeError(
property + ' of ' + self.__class__.__name__ + ' must be ' + \
- property_type.__name__ + ', not ' + value.__class__.__name__
+ property_type.__name__ + ', not ' + value.__class__.__name__)
# Checks passed, perform the assignment.
if do_copy:
if isinstance(value, XCObject):
if is_strong:
self._properties[property] = value.Copy()
else:
self._properties[property] = value
@@ -799,19 +798,19 @@ class XCObject(object):
self._properties[property] = []
for item in value:
self._properties[property].append(item.Copy())
else:
self._properties[property] = value[:]
elif isinstance(value, dict):
self._properties[property] = value.copy()
else:
- raise TypeError, "Don't know how to copy a " + \
- value.__class__.__name__ + ' object for ' + \
- property + ' in ' + self.__class__.__name__
+ raise TypeError("Don't know how to copy a " + \
+ value.__class__.__name__ + ' object for ' + \
+ property + ' in ' + self.__class__.__name__)
else:
self._properties[property] = value
# Set up the child's back-reference to this object. Don't use |value|
# any more because it may not be right if do_copy is true.
if is_strong:
if not is_list:
self._properties[property].parent = self
@@ -832,25 +831,25 @@ class XCObject(object):
if key in self._properties:
del self._properties[key]
def AppendProperty(self, key, value):
# TODO(mark): Support ExtendProperty too (and make this call that)?
# Schema validation.
if not key in self._schema:
- raise KeyError, key + ' not in ' + self.__class__.__name__
+ raise KeyError(key + ' not in ' + self.__class__.__name__)
(is_list, property_type, is_strong) = self._schema[key][0:3]
if not is_list:
- raise TypeError, key + ' of ' + self.__class__.__name__ + ' must be list'
+ raise TypeError(key + ' of ' + self.__class__.__name__ + ' must be list')
if not isinstance(value, property_type):
- raise TypeError, 'item of ' + key + ' of ' + self.__class__.__name__ + \
- ' must be ' + property_type.__name__ + ', not ' + \
- value.__class__.__name__
+ raise TypeError('item of ' + key + ' of ' + self.__class__.__name__ + \
+ ' must be ' + property_type.__name__ + ', not ' + \
+ value.__class__.__name__)
# If the property doesn't exist yet, create a new empty list to receive the
# item.
if not key in self._properties:
self._properties[key] = []
# Set up the ownership link.
if is_strong:
@@ -864,17 +863,17 @@ class XCObject(object):
set.
"""
# TODO(mark): A stronger verification mechanism is needed. Some
# subclasses need to perform validation beyond what the schema can enforce.
for property, attributes in self._schema.iteritems():
(is_list, property_type, is_strong, is_required) = attributes[0:4]
if is_required and not property in self._properties:
- raise KeyError, self.__class__.__name__ + ' requires ' + property
+ raise KeyError(self.__class__.__name__ + ' requires ' + property)
def _SetDefaultsFromSchema(self):
"""Assign object default values according to the schema. This will not
overwrite properties that have already been set."""
defaults = {}
for property, attributes in self._schema.iteritems():
(is_list, property_type, is_strong, is_required) = attributes[0:4]
@@ -1138,26 +1137,26 @@ class PBXGroup(XCHierarchicalElement):
# not include the child names.
return XCHierarchicalElement.Hashables(self)
def _AddChildToDicts(self, child):
# Sets up this PBXGroup object's dicts to reference the child properly.
child_path = child.PathFromSourceTreeAndPath()
if child_path:
if child_path in self._children_by_path:
- raise ValueError, 'Found multiple children with path ' + child_path
+ raise ValueError('Found multiple children with path ' + child_path)
self._children_by_path[child_path] = child
if isinstance(child, PBXVariantGroup):
child_name = child._properties.get('name', None)
key = (child_name, child_path)
if key in self._variant_children_by_name_and_path:
- raise ValueError, 'Found multiple PBXVariantGroup children with ' + \
- 'name ' + str(child_name) + ' and path ' + \
- str(child_path)
+ raise ValueError('Found multiple PBXVariantGroup children with ' + \
+ 'name ' + str(child_name) + ' and path ' + \
+ str(child_path))
self._variant_children_by_name_and_path[key] = child
def AppendChild(self, child):
# Callers should use this instead of calling
# AppendProperty('children', child) directly because this function
# maintains the group's dicts.
self.AppendProperty('children', child)
self._AddChildToDicts(child)
@@ -1469,70 +1468,87 @@ class PBXFileReference(XCFileLikeElement
is_dir = False
if 'path' in self._properties and \
not 'lastKnownFileType' in self._properties and \
not 'explicitFileType' in self._properties:
# TODO(mark): This is the replacement for a replacement for a quick hack.
# It is no longer incredibly sucky, but this list needs to be extended.
extension_map = {
- 'a': 'archive.ar',
- 'app': 'wrapper.application',
- 'bdic': 'file',
- 'bundle': 'wrapper.cfbundle',
- 'c': 'sourcecode.c.c',
- 'cc': 'sourcecode.cpp.cpp',
- 'cpp': 'sourcecode.cpp.cpp',
- 'css': 'text.css',
- 'cxx': 'sourcecode.cpp.cpp',
- 'dylib': 'compiled.mach-o.dylib',
- 'framework': 'wrapper.framework',
- 'h': 'sourcecode.c.h',
- 'hxx': 'sourcecode.cpp.h',
- 'icns': 'image.icns',
- 'java': 'sourcecode.java',
- 'js': 'sourcecode.javascript',
- 'm': 'sourcecode.c.objc',
- 'mm': 'sourcecode.cpp.objcpp',
- 'nib': 'wrapper.nib',
- 'o': 'compiled.mach-o.objfile',
- 'pdf': 'image.pdf',
- 'pl': 'text.script.perl',
- 'plist': 'text.plist.xml',
- 'pm': 'text.script.perl',
- 'png': 'image.png',
- 'py': 'text.script.python',
- 'r': 'sourcecode.rez',
- 'rez': 'sourcecode.rez',
- 's': 'sourcecode.asm',
- 'strings': 'text.plist.strings',
- 'ttf': 'file',
- 'xcconfig': 'text.xcconfig',
- 'xib': 'file.xib',
- 'y': 'sourcecode.yacc',
+ 'a': 'archive.ar',
+ 'app': 'wrapper.application',
+ 'bdic': 'file',
+ 'bundle': 'wrapper.cfbundle',
+ 'c': 'sourcecode.c.c',
+ 'cc': 'sourcecode.cpp.cpp',
+ 'cpp': 'sourcecode.cpp.cpp',
+ 'css': 'text.css',
+ 'cxx': 'sourcecode.cpp.cpp',
+ 'dart': 'sourcecode',
+ 'dylib': 'compiled.mach-o.dylib',
+ 'framework': 'wrapper.framework',
+ 'gyp': 'sourcecode',
+ 'gypi': 'sourcecode',
+ 'h': 'sourcecode.c.h',
+ 'hxx': 'sourcecode.cpp.h',
+ 'icns': 'image.icns',
+ 'java': 'sourcecode.java',
+ 'js': 'sourcecode.javascript',
+ 'kext': 'wrapper.kext',
+ 'm': 'sourcecode.c.objc',
+ 'mm': 'sourcecode.cpp.objcpp',
+ 'nib': 'wrapper.nib',
+ 'o': 'compiled.mach-o.objfile',
+ 'pdf': 'image.pdf',
+ 'pl': 'text.script.perl',
+ 'plist': 'text.plist.xml',
+ 'pm': 'text.script.perl',
+ 'png': 'image.png',
+ 'py': 'text.script.python',
+ 'r': 'sourcecode.rez',
+ 'rez': 'sourcecode.rez',
+ 's': 'sourcecode.asm',
+ 'storyboard': 'file.storyboard',
+ 'strings': 'text.plist.strings',
+ 'swift': 'sourcecode.swift',
+ 'ttf': 'file',
+ 'xcassets': 'folder.assetcatalog',
+ 'xcconfig': 'text.xcconfig',
+ 'xcdatamodel': 'wrapper.xcdatamodel',
+ 'xcdatamodeld':'wrapper.xcdatamodeld',
+ 'xib': 'file.xib',
+ 'y': 'sourcecode.yacc',
+ }
+
+ prop_map = {
+ 'dart': 'explicitFileType',
+ 'gyp': 'explicitFileType',
+ 'gypi': 'explicitFileType',
}
if is_dir:
file_type = 'folder'
+ prop_name = 'lastKnownFileType'
else:
basename = posixpath.basename(self._properties['path'])
(root, ext) = posixpath.splitext(basename)
# Check the map using a lowercase extension.
# TODO(mark): Maybe it should try with the original case first and fall
# back to lowercase, in case there are any instances where case
# matters. There currently aren't.
if ext != '':
ext = ext[1:].lower()
# TODO(mark): "text" is the default value, but "file" is appropriate
# for unrecognized files not containing text. Xcode seems to choose
# based on content.
file_type = extension_map.get(ext, 'text')
-
- self._properties['lastKnownFileType'] = file_type
+ prop_name = prop_map.get(ext, 'lastKnownFileType')
+
+ self._properties[prop_name] = file_type
class PBXVariantGroup(PBXGroup, XCFileLikeElement):
"""PBXVariantGroup is used by Xcode to represent localizations."""
# No additions to the schema relative to PBXGroup.
pass
@@ -1587,17 +1603,17 @@ class XCConfigurationList(XCObject):
self.parent.__class__.__name__ + ' "' + self.parent.Name() + '"'
def ConfigurationNamed(self, name):
"""Convenience accessor to obtain an XCBuildConfiguration by name."""
for configuration in self._properties['buildConfigurations']:
if configuration._properties['name'] == name:
return configuration
- raise KeyError, name
+ raise KeyError(name)
def DefaultConfiguration(self):
"""Convenience accessor to obtain the default XCBuildConfiguration."""
return self.ConfigurationNamed(self._properties['defaultConfigurationName'])
def HasBuildSetting(self, key):
"""Determines the state of a build setting in all XCBuildConfiguration
child objects.
@@ -1644,17 +1660,17 @@ class XCConfigurationList(XCObject):
value = None
for configuration in self._properties['buildConfigurations']:
configuration_value = configuration.GetBuildSetting(key)
if value is None:
value = configuration_value
else:
if value != configuration_value:
- raise ValueError, 'Variant values for ' + key
+ raise ValueError('Variant values for ' + key)
return value
def SetBuildSetting(self, key, value):
"""Sets the build setting for key to value in all child
XCBuildConfiguration objects.
"""
@@ -1751,27 +1767,27 @@ class XCBuildPhase(XCObject):
self._AddBuildFileToDicts(pbxbuildfile)
def FileGroup(self, path):
# Subclasses must override this by returning a two-element tuple. The
# first item in the tuple should be the PBXGroup to which "path" should be
# added, either as a child or deeper descendant. The second item should
# be a boolean indicating whether files should be added into hierarchical
# groups or one single flat group.
- raise NotImplementedError, \
- self.__class__.__name__ + ' must implement FileGroup'
+ raise NotImplementedError(
+ self.__class__.__name__ + ' must implement FileGroup')
def _AddPathToDict(self, pbxbuildfile, path):
"""Adds path to the dict tracking paths belonging to this build phase.
If the path is already a member of this build phase, raises an exception.
"""
if path in self._files_by_path:
- raise ValueError, 'Found multiple build files with path ' + path
+ raise ValueError('Found multiple build files with path ' + path)
self._files_by_path[path] = pbxbuildfile
def _AddBuildFileToDicts(self, pbxbuildfile, path=None):
"""Maintains the _files_by_path and _files_by_xcfilelikeelement dicts.
If path is specified, then it is the path that is being added to the
phase, and pbxbuildfile must contain either a PBXFileReference directly
referencing that path, or it must contain a PBXVariantGroup that itself
@@ -1816,18 +1832,18 @@ class XCBuildPhase(XCObject):
# having access to a real pathname and not just an object's Name().
for a_path in paths:
self._AddPathToDict(pbxbuildfile, a_path)
# If another PBXBuildFile references this XCFileLikeElement, there's a
# problem.
if xcfilelikeelement in self._files_by_xcfilelikeelement and \
self._files_by_xcfilelikeelement[xcfilelikeelement] != pbxbuildfile:
- raise ValueError, 'Found multiple build files for ' + \
- xcfilelikeelement.Name()
+ raise ValueError('Found multiple build files for ' + \
+ xcfilelikeelement.Name())
self._files_by_xcfilelikeelement[xcfilelikeelement] = pbxbuildfile
def AppendBuildFile(self, pbxbuildfile, path=None):
# Callers should use this instead of calling
# AppendProperty('files', pbxbuildfile) directly because this function
# maintains the object's dicts. Better yet, callers can just call AddFile
# with a pathname and not worry about building their own PBXBuildFile
# objects.
@@ -1924,34 +1940,50 @@ class PBXShellScriptBuildPhase(XCBuildPh
class PBXCopyFilesBuildPhase(XCBuildPhase):
_schema = XCBuildPhase._schema.copy()
_schema.update({
'dstPath': [0, str, 0, 1],
'dstSubfolderSpec': [0, int, 0, 1],
'name': [0, str, 0, 0],
})
- # path_tree_re matches "$(DIR)/path" or just "$(DIR)". Match group 1 is
- # "DIR", match group 3 is "path" or None.
- path_tree_re = re.compile('^\\$\\((.*)\\)(/(.*)|)$')
-
- # path_tree_to_subfolder maps names of Xcode variables to the associated
- # dstSubfolderSpec property value used in a PBXCopyFilesBuildPhase object.
- path_tree_to_subfolder = {
- 'BUILT_PRODUCTS_DIR': 16, # Products Directory
- # Other types that can be chosen via the Xcode UI.
- # TODO(mark): Map Xcode variable names to these.
- # : 1, # Wrapper
- # : 6, # Executables: 6
- # : 7, # Resources
- # : 15, # Java Resources
- # : 10, # Frameworks
- # : 11, # Shared Frameworks
- # : 12, # Shared Support
- # : 13, # PlugIns
+ # path_tree_re matches "$(DIR)/path", "$(DIR)/$(DIR2)/path" or just "$(DIR)".
+ # Match group 1 is "DIR", group 3 is "path" or "$(DIR2") or "$(DIR2)/path"
+ # or None. If group 3 is "path", group 4 will be None otherwise group 4 is
+ # "DIR2" and group 6 is "path".
+ path_tree_re = re.compile(r'^\$\((.*?)\)(/(\$\((.*?)\)(/(.*)|)|(.*)|)|)$')
+
+ # path_tree_{first,second}_to_subfolder map names of Xcode variables to the
+ # associated dstSubfolderSpec property value used in a PBXCopyFilesBuildPhase
+ # object.
+ path_tree_first_to_subfolder = {
+ # Types that can be chosen via the Xcode UI.
+ 'BUILT_PRODUCTS_DIR': 16, # Products Directory
+ 'BUILT_FRAMEWORKS_DIR': 10, # Not an official Xcode macro.
+ # Existed before support for the
+ # names below was added. Maps to
+ # "Frameworks".
+ }
+
+ path_tree_second_to_subfolder = {
+ 'WRAPPER_NAME': 1, # Wrapper
+ # Although Xcode's friendly name is "Executables", the destination
+ # is demonstrably the value of the build setting
+ # EXECUTABLE_FOLDER_PATH not EXECUTABLES_FOLDER_PATH.
+ 'EXECUTABLE_FOLDER_PATH': 6, # Executables.
+ 'UNLOCALIZED_RESOURCES_FOLDER_PATH': 7, # Resources
+ 'JAVA_FOLDER_PATH': 15, # Java Resources
+ 'FRAMEWORKS_FOLDER_PATH': 10, # Frameworks
+ 'SHARED_FRAMEWORKS_FOLDER_PATH': 11, # Shared Frameworks
+ 'SHARED_SUPPORT_FOLDER_PATH': 12, # Shared Support
+ 'PLUGINS_FOLDER_PATH': 13, # PlugIns
+ # For XPC Services, Xcode sets both dstPath and dstSubfolderSpec.
+ # Note that it re-uses the BUILT_PRODUCTS_DIR value for
+ # dstSubfolderSpec. dstPath is set below.
+ 'XPCSERVICES_FOLDER_PATH': 16, # XPC Services.
}
def Name(self):
if 'name' in self._properties:
return self._properties['name']
return 'CopyFiles'
@@ -1962,37 +1994,84 @@ class PBXCopyFilesBuildPhase(XCBuildPhas
"""Set the dstSubfolderSpec and dstPath properties from path.
path may be specified in the same notation used for XCHierarchicalElements,
specifically, "$(DIR)/path".
"""
path_tree_match = self.path_tree_re.search(path)
if path_tree_match:
- # Everything else needs to be relative to an Xcode variable.
- path_tree = path_tree_match.group(1)
- relative_path = path_tree_match.group(3)
-
- if path_tree in self.path_tree_to_subfolder:
- subfolder = self.path_tree_to_subfolder[path_tree]
+ path_tree = path_tree_match.group(1);
+ if path_tree in self.path_tree_first_to_subfolder:
+ subfolder = self.path_tree_first_to_subfolder[path_tree]
+ relative_path = path_tree_match.group(3)
if relative_path is None:
relative_path = ''
+
+ if subfolder == 16 and path_tree_match.group(4) is not None:
+ # BUILT_PRODUCTS_DIR (16) is the first element in a path whose
+ # second element is possibly one of the variable names in
+ # path_tree_second_to_subfolder. Xcode sets the values of all these
+ # variables to relative paths so .gyp files must prefix them with
+ # BUILT_PRODUCTS_DIR, e.g.
+ # $(BUILT_PRODUCTS_DIR)/$(PLUGINS_FOLDER_PATH). Then
+ # xcode_emulation.py can export these variables with the same values
+ # as Xcode yet make & ninja files can determine the absolute path
+ # to the target. Xcode uses the dstSubfolderSpec value set here
+ # to determine the full path.
+ #
+ # An alternative of xcode_emulation.py setting the values to absolute
+ # paths when exporting these variables has been ruled out because
+ # then the values would be different depending on the build tool.
+ #
+ # Another alternative is to invent new names for the variables used
+ # to match to the subfolder indices in the second table. .gyp files
+ # then will not need to prepend $(BUILT_PRODUCTS_DIR) because
+ # xcode_emulation.py can set the values of those variables to
+ # the absolute paths when exporting. This is possibly the thinking
+ # behind BUILT_FRAMEWORKS_DIR which is used in exactly this manner.
+ #
+ # Requiring prepending BUILT_PRODUCTS_DIR has been chosen because
+ # this same way could be used to specify destinations in .gyp files
+ # that pre-date this addition to GYP. However they would only work
+ # with the Xcode generator. The previous version of xcode_emulation.py
+ # does not export these variables. Such files will get the benefit
+ # of the Xcode UI showing the proper destination name simply by
+ # regenerating the projects with this version of GYP.
+ path_tree = path_tree_match.group(4)
+ relative_path = path_tree_match.group(6)
+ separator = '/'
+
+ if path_tree in self.path_tree_second_to_subfolder:
+ subfolder = self.path_tree_second_to_subfolder[path_tree]
+ if relative_path is None:
+ relative_path = ''
+ separator = ''
+ if path_tree == 'XPCSERVICES_FOLDER_PATH':
+ relative_path = '$(CONTENTS_FOLDER_PATH)/XPCServices' \
+ + separator + relative_path
+ else:
+ # subfolder = 16 from above
+ # The second element of the path is an unrecognized variable.
+ # Include it and any remaining elements in relative_path.
+ relative_path = path_tree_match.group(3);
+
else:
# The path starts with an unrecognized Xcode variable
# name like $(SRCROOT). Xcode will still handle this
# as an "absolute path" that starts with the variable.
subfolder = 0
relative_path = path
elif path.startswith('/'):
# Special case. Absolute paths are in dstSubfolderSpec 0.
subfolder = 0
relative_path = path[1:]
else:
- raise ValueError, 'Can\'t use path %s in a %s' % \
- (path, self.__class__.__name__)
+ raise ValueError('Can\'t use path %s in a %s' % \
+ (path, self.__class__.__name__))
self._properties['dstPath'] = relative_path
self._properties['dstSubfolderSpec'] = subfolder
class PBXBuildRule(XCObject):
_schema = XCObject._schema.copy()
_schema.update({
@@ -2218,32 +2297,44 @@ class PBXNativeTarget(XCTarget):
'buildRules': [1, PBXBuildRule, 1, 1, []],
'productReference': [0, PBXFileReference, 0, 1],
'productType': [0, str, 0, 1],
})
# Mapping from Xcode product-types to settings. The settings are:
# filetype : used for explicitFileType in the project file
# prefix : the prefix for the file name
- # suffix : the suffix for the filen ame
+ # suffix : the suffix for the file name
_product_filetypes = {
- 'com.apple.product-type.application': ['wrapper.application',
- '', '.app'],
- 'com.apple.product-type.bundle': ['wrapper.cfbundle',
- '', '.bundle'],
- 'com.apple.product-type.framework': ['wrapper.framework',
- '', '.framework'],
- 'com.apple.product-type.library.dynamic': ['compiled.mach-o.dylib',
- 'lib', '.dylib'],
- 'com.apple.product-type.library.static': ['archive.ar',
- 'lib', '.a'],
- 'com.apple.product-type.tool': ['compiled.mach-o.executable',
- '', ''],
- 'com.googlecode.gyp.xcode.bundle': ['compiled.mach-o.dylib',
- '', '.so'],
+ 'com.apple.product-type.application': ['wrapper.application',
+ '', '.app'],
+ 'com.apple.product-type.application.watchapp': ['wrapper.application',
+ '', '.app'],
+ 'com.apple.product-type.watchkit-extension': ['wrapper.app-extension',
+ '', '.appex'],
+ 'com.apple.product-type.app-extension': ['wrapper.app-extension',
+ '', '.appex'],
+ 'com.apple.product-type.bundle': ['wrapper.cfbundle',
+ '', '.bundle'],
+ 'com.apple.product-type.framework': ['wrapper.framework',
+ '', '.framework'],
+ 'com.apple.product-type.library.dynamic': ['compiled.mach-o.dylib',
+ 'lib', '.dylib'],
+ 'com.apple.product-type.library.static': ['archive.ar',
+ 'lib', '.a'],
+ 'com.apple.product-type.tool': ['compiled.mach-o.executable',
+ '', ''],
+ 'com.apple.product-type.bundle.unit-test': ['wrapper.cfbundle',
+ '', '.xctest'],
+ 'com.apple.product-type.bundle.ui-testing': ['wrapper.cfbundle',
+ '', '.xctest'],
+ 'com.googlecode.gyp.xcode.bundle': ['compiled.mach-o.dylib',
+ '', '.so'],
+ 'com.apple.product-type.kernel-extension': ['wrapper.kext',
+ '', '.kext'],
}
def __init__(self, properties=None, id=None, parent=None,
force_outdir=None, force_prefix=None, force_extension=None):
# super
XCTarget.__init__(self, properties, id, parent)
if 'productName' in self._properties and \
@@ -2285,23 +2376,30 @@ class PBXNativeTarget(XCTarget):
self._properties['productType'] = \
'com.apple.product-type.library.dynamic'
self.SetBuildSetting('MACH_O_TYPE', 'mh_bundle')
self.SetBuildSetting('DYLIB_CURRENT_VERSION', '')
self.SetBuildSetting('DYLIB_COMPATIBILITY_VERSION', '')
if force_extension is None:
force_extension = suffix[1:]
+ if self._properties['productType'] == \
+ 'com.apple.product-type-bundle.unit.test' or \
+ self._properties['productType'] == \
+ 'com.apple.product-type-bundle.ui-testing':
+ if force_extension is None:
+ force_extension = suffix[1:]
+
if force_extension is not None:
# If it's a wrapper (bundle), set WRAPPER_EXTENSION.
+ # Extension override.
+ suffix = '.' + force_extension
if filetype.startswith('wrapper.'):
self.SetBuildSetting('WRAPPER_EXTENSION', force_extension)
else:
- # Extension override.
- suffix = '.' + force_extension
self.SetBuildSetting('EXECUTABLE_EXTENSION', force_extension)
if filetype.startswith('compiled.mach-o.executable'):
product_name = self._properties['productName']
product_name += suffix
suffix = ''
self.SetProperty('productName', product_name)
self.SetBuildSetting('PRODUCT_NAME', product_name)
@@ -2707,18 +2805,63 @@ class PBXProject(XCContainerPortal):
else:
# The link already exists. Pull out the relevnt data.
project_ref_dict = self._other_pbxprojects[other_pbxproject]
product_group = project_ref_dict['ProductGroup']
project_ref = project_ref_dict['ProjectRef']
self._SetUpProductReferences(other_pbxproject, product_group, project_ref)
+ inherit_unique_symroot = self._AllSymrootsUnique(other_pbxproject, False)
+ targets = other_pbxproject.GetProperty('targets')
+ if all(self._AllSymrootsUnique(t, inherit_unique_symroot) for t in targets):
+ dir_path = project_ref._properties['path']
+ product_group._hashables.extend(dir_path)
+
return [product_group, project_ref]
+ def _AllSymrootsUnique(self, target, inherit_unique_symroot):
+ # Returns True if all configurations have a unique 'SYMROOT' attribute.
+ # The value of inherit_unique_symroot decides, if a configuration is assumed
+ # to inherit a unique 'SYMROOT' attribute from its parent, if it doesn't
+ # define an explicit value for 'SYMROOT'.
+ symroots = self._DefinedSymroots(target)
+ for s in self._DefinedSymroots(target):
+ if (s is not None and not self._IsUniqueSymrootForTarget(s) or
+ s is None and not inherit_unique_symroot):
+ return False
+ return True if symroots else inherit_unique_symroot
+
+ def _DefinedSymroots(self, target):
+ # Returns all values for the 'SYMROOT' attribute defined in all
+ # configurations for this target. If any configuration doesn't define the
+ # 'SYMROOT' attribute, None is added to the returned set. If all
+ # configurations don't define the 'SYMROOT' attribute, an empty set is
+ # returned.
+ config_list = target.GetProperty('buildConfigurationList')
+ symroots = set()
+ for config in config_list.GetProperty('buildConfigurations'):
+ setting = config.GetProperty('buildSettings')
+ if 'SYMROOT' in setting:
+ symroots.add(setting['SYMROOT'])
+ else:
+ symroots.add(None)
+ if len(symroots) == 1 and None in symroots:
+ return set()
+ return symroots
+
+ def _IsUniqueSymrootForTarget(self, symroot):
+ # This method returns True if all configurations in target contain a
+ # 'SYMROOT' attribute that is unique for the given target. A value is
+ # unique, if the Xcode macro '$SRCROOT' appears in it in any form.
+ uniquifier = ['$SRCROOT', '$(SRCROOT)']
+ if any(x in symroot for x in uniquifier):
+ return True
+ return False
+
def _SetUpProductReferences(self, other_pbxproject, product_group,
project_ref):
# TODO(mark): This only adds references to products in other_pbxproject
# when they don't exist in this pbxproject. Perhaps it should also
# remove references from this pbxproject that are no longer present in
# other_pbxproject. Perhaps it should update various properties if they
# change.
for target in other_pbxproject._properties['targets']:
@@ -2777,45 +2920,28 @@ class PBXProject(XCContainerPortal):
continue
remote_products.append(target._properties['productReference'])
# Sort the PBXReferenceProxy children according to the list of remote
# products.
product_group = ref_dict['ProductGroup']
product_group._properties['children'] = sorted(
product_group._properties['children'],
- cmp=lambda x, y: CompareProducts(x, y, remote_products))
+ cmp=lambda x, y, rp=remote_products: CompareProducts(x, y, rp))
class XCProjectFile(XCObject):
_schema = XCObject._schema.copy()
_schema.update({
'archiveVersion': [0, int, 0, 1, 1],
'classes': [0, dict, 0, 1, {}],
- 'objectVersion': [0, int, 0, 1, 45],
+ 'objectVersion': [0, int, 0, 1, 46],
'rootObject': [0, PBXProject, 1, 1],
})
- def SetXcodeVersion(self, version):
- version_to_object_version = {
- '2.4': 45,
- '3.0': 45,
- '3.1': 45,
- '3.2': 46,
- }
- if not version in version_to_object_version:
- supported_str = ', '.join(sorted(version_to_object_version.keys()))
- raise Exception(
- 'Unsupported Xcode version %s (supported: %s)' %
- ( version, supported_str ) )
- compatibility_version = 'Xcode %s' % version
- self._properties['rootObject'].SetProperty('compatibilityVersion',
- compatibility_version)
- self.SetProperty('objectVersion', version_to_object_version[version]);
-
def ComputeIDs(self, recursive=True, overwrite=True, hash=None):
# Although XCProjectFile is implemented here as an XCObject, it's not a
# proper object in the Xcode sense, and it certainly doesn't have its own
# ID. Pass through an attempt to update IDs to the real root object.
if recursive:
self._properties['rootObject'].ComputeIDs(recursive, overwrite, hash)
def Print(self, file=sys.stdout):
deleted file mode 100644
--- a/media/webrtc/trunk/tools/gyp/pylintrc
+++ /dev/null
@@ -1,307 +0,0 @@
-[MASTER]
-
-# Specify a configuration file.
-#rcfile=
-
-# Python code to execute, usually for sys.path manipulation such as
-# pygtk.require().
-#init-hook=
-
-# Profiled execution.
-profile=no
-
-# Add files or directories to the blacklist. They should be base names, not
-# paths.
-ignore=CVS
-
-# Pickle collected data for later comparisons.
-persistent=yes
-
-# List of plugins (as comma separated values of python modules names) to load,
-# usually to register additional checkers.
-load-plugins=
-
-
-[MESSAGES CONTROL]
-
-# Enable the message, report, category or checker with the given id(s). You can
-# either give multiple identifier separated by comma (,) or put this option
-# multiple time.
-#enable=
-
-# Disable the message, report, category or checker with the given id(s). You
-# can either give multiple identifier separated by comma (,) or put this option
-# multiple time (only on the command line, not in the configuration file where
-# it should appear only once).
-# C0103: Invalid name "NN" (should match [a-z_][a-z0-9_]{2,30}$)
-# C0111: Missing docstring
-# C0302: Too many lines in module (NN)
-# R0902: Too many instance attributes (N/7)
-# R0903: Too few public methods (N/2)
-# R0904: Too many public methods (NN/20)
-# R0912: Too many branches (NN/12)
-# R0913: Too many arguments (N/5)
-# R0914: Too many local variables (NN/15)
-# R0915: Too many statements (NN/50)
-# W0141: Used builtin function 'map'
-# W0142: Used * or ** magic
-# W0232: Class has no __init__ method
-# W0511: TODO
-# W0603: Using the global statement
-#
-# These should be enabled eventually:
-# C0112: Empty docstring
-# C0301: Line too long (NN/80)
-# C0321: More than one statement on single line
-# C0322: Operator not preceded by a space
-# C0323: Operator not followed by a space
-# C0324: Comma not followed by a space
-# E0101: Explicit return in __init__
-# E0102: function already defined line NN
-# E1002: Use of super on an old style class
-# E1101: Instance of 'XX' has no 'YY' member
-# E1103: Instance of 'XX' has no 'XX' member (but some types could not be inferred)
-# E0602: Undefined variable 'XX'
-# F0401: Unable to import 'XX'
-# R0201: Method could be a function
-# R0801: Similar lines in N files
-# W0102: Dangerous default value {} as argument
-# W0104: Statement seems to have no effect
-# W0105: String statement has no effect
-# W0108: Lambda may not be necessary
-# W0201: Attribute 'XX' defined outside __init__
-# W0212: Access to a protected member XX of a client class
-# W0221: Arguments number differs from overridden method
-# W0223: Method 'XX' is abstract in class 'YY' but is not overridden
-# W0231: __init__ method from base class 'XX' is not called
-# W0301: Unnecessary semicolon
-# W0311: Bad indentation. Found NN spaces, expected NN
-# W0401: Wildcard import XX
-# W0402: Uses of a deprecated module 'string'
-# W0403: Relative import 'XX', should be 'YY.XX'
-# W0404: Reimport 'XX' (imported line NN)
-# W0601: Global variable 'XX' undefined at the module level
-# W0602: Using global for 'XX' but no assignment is done
-# W0611: Unused import pprint
-# W0612: Unused variable 'XX'
-# W0613: Unused argument 'XX'
-# W0614: Unused import XX from wildcard import
-# W0621: Redefining name 'XX' from outer scope (line NN)
-# W0622: Redefining built-in 'NN'
-# W0631: Using possibly undefined loop variable 'XX'
-# W0701: Raising a string exception
-# W0702: No exception type(s) specified
-disable=C0103,C0111,C0302,R0902,R0903,R0904,R0912,R0913,R0914,R0915,W0141,W0142,W0232,W0511,W0603,C0112,C0301,C0321,C0322,C0323,C0324,E0101,E0102,E1002,E1101,E1103,E0602,F0401,R0201,R0801,W0102,W0104,W0105,W0108,W0201,W0212,W0221,W0223,W0231,W0301,W0311,W0401,W0402,W0403,W0404,W0601,W0602,W0611,W0612,W0613,W0614,W0621,W0622,W0631,W0701,W0702
-
-
-[REPORTS]
-
-# Set the output format. Available formats are text, parseable, colorized, msvs
-# (visual studio) and html
-output-format=text
-
-# Include message's id in output
-include-ids=yes
-
-# Put messages in a separate file for each module / package specified on the
-# command line instead of printing them on stdout. Reports (if any) will be
-# written in a file name "pylint_global.[txt|html]".
-files-output=no
-
-# Tells whether to display a full report or only the messages
-reports=no
-
-# Python expression which should return a note less than 10 (10 is the highest
-# note). You have access to the variables errors warning, statement which
-# respectively contain the number of errors / warnings messages and the total
-# number of statements analyzed. This is used by the global evaluation report
-# (RP0004).
-evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
-
-# Add a comment according to your evaluation note. This is used by the global
-# evaluation report (RP0004).
-comment=no
-
-
-[VARIABLES]
-
-# Tells whether we should check for unused import in __init__ files.
-init-import=no
-
-# A regular expression matching the beginning of the name of dummy variables
-# (i.e. not used).
-dummy-variables-rgx=_|dummy
-
-# List of additional names supposed to be defined in builtins. Remember that
-# you should avoid to define new builtins when possible.
-additional-builtins=
-
-
-[TYPECHECK]
-
-# Tells whether missing members accessed in mixin class should be ignored. A
-# mixin class is detected if its name ends with "mixin" (case insensitive).
-ignore-mixin-members=yes
-
-# List of classes names for which member attributes should not be checked
-# (useful for classes with attributes dynamically set).
-ignored-classes=SQLObject
-
-# When zope mode is activated, add a predefined set of Zope acquired attributes
-# to generated-members.
-zope=no
-
-# List of members which are set dynamically and missed by pylint inference
-# system, and so shouldn't trigger E0201 when accessed. Python regular
-# expressions are accepted.
-generated-members=REQUEST,acl_users,aq_parent
-
-
-[MISCELLANEOUS]
-
-# List of note tags to take in consideration, separated by a comma.
-notes=FIXME,XXX,TODO
-
-
-[SIMILARITIES]
-
-# Minimum lines number of a similarity.
-min-similarity-lines=4
-
-# Ignore comments when computing similarities.
-ignore-comments=yes
-
-# Ignore docstrings when computing similarities.
-ignore-docstrings=yes
-
-
-[FORMAT]
-
-# Maximum number of characters on a single line.
-max-line-length=80
-
-# Maximum number of lines in a module
-max-module-lines=1000
-
-# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
-# tab).
-indent-string=' '
-
-
-[BASIC]
-
-# Required attributes for module, separated by a comma
-required-attributes=
-
-# List of builtins function names that should not be used, separated by a comma
-bad-functions=map,filter,apply,input
-
-# Regular expression which should only match correct module names
-module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
-
-# Regular expression which should only match correct module level names
-const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$
-
-# Regular expression which should only match correct class names
-class-rgx=[A-Z_][a-zA-Z0-9]+$
-
-# Regular expression which should only match correct function names
-function-rgx=[a-z_][a-z0-9_]{2,30}$
-
-# Regular expression which should only match correct method names
-method-rgx=[a-z_][a-z0-9_]{2,30}$
-
-# Regular expression which should only match correct instance attribute names
-attr-rgx=[a-z_][a-z0-9_]{2,30}$
-
-# Regular expression which should only match correct argument names
-argument-rgx=[a-z_][a-z0-9_]{2,30}$
-
-# Regular expression which should only match correct variable names
-variable-rgx=[a-z_][a-z0-9_]{2,30}$
-
-# Regular expression which should only match correct list comprehension /
-# generator expression variable names
-inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
-
-# Good variable names which should always be accepted, separated by a comma
-good-names=i,j,k,ex,Run,_
-
-# Bad variable names which should always be refused, separated by a comma
-bad-names=foo,bar,baz,toto,tutu,tata
-
-# Regular expression which should only match functions or classes name which do
-# not require a docstring
-no-docstring-rgx=__.*__
-
-
-[DESIGN]
-
-# Maximum number of arguments for function / method
-max-args=5
-
-# Argument names that match this expression will be ignored. Default to name
-# with leading underscore
-ignored-argument-names=_.*
-
-# Maximum number of locals for function / method body
-max-locals=15
-
-# Maximum number of return / yield for function / method body
-max-returns=6
-
-# Maximum number of branch for function / method body
-max-branchs=12
-
-# Maximum number of statements in function / method body
-max-statements=50
-
-# Maximum number of parents for a class (see R0901).
-max-parents=7
-
-# Maximum number of attributes for a class (see R0902).
-max-attributes=7
-
-# Minimum number of public methods for a class (see R0903).
-min-public-methods=2
-
-# Maximum number of public methods for a class (see R0904).
-max-public-methods=20
-
-
-[CLASSES]
-
-# List of interface methods to ignore, separated by a comma. This is used for
-# instance to not check methods defines in Zope's Interface base class.
-ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by
-
-# List of method names used to declare (i.e. assign) instance attributes.
-defining-attr-methods=__init__,__new__,setUp
-
-# List of valid names for the first argument in a class method.
-valid-classmethod-first-arg=cls
-
-
-[IMPORTS]
-
-# Deprecated modules which should not be used, separated by a comma
-deprecated-modules=regsub,string,TERMIOS,Bastion,rexec
-
-# Create a graph of every (i.e. internal and external) dependencies in the
-# given file (report RP0402 must not be disabled)
-import-graph=
-
-# Create a graph of external dependencies in the given file (report RP0402 must
-# not be disabled)
-ext-import-graph=
-
-# Create a graph of internal dependencies in the given file (report RP0402 must
-# not be disabled)
-int-import-graph=
-
-
-[EXCEPTIONS]
-
-# Exceptions that will emit a warning when being caught. Defaults to
-# "Exception"
-overgeneral-exceptions=Exception
--- a/media/webrtc/trunk/tools/gyp/setup.py
+++ b/media/webrtc/trunk/tools/gyp/setup.py
@@ -1,26 +1,19 @@
#!/usr/bin/env python
# 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.
-from distutils.core import setup
-from distutils.command.install import install
-from distutils.command.install_lib import install_lib
-from distutils.command.install_scripts import install_scripts
+from setuptools import setup
setup(
name='gyp',
version='0.1',
description='Generate Your Projects',
author='Chromium Authors',
author_email='chromium-dev@googlegroups.com',
url='http://code.google.com/p/gyp',
package_dir = {'': 'pylib'},
packages=['gyp', 'gyp.generator'],
-
- scripts = ['gyp'],
- cmdclass = {'install': install,
- 'install_lib': install_lib,
- 'install_scripts': install_scripts},
+ entry_points = {'console_scripts': ['gyp=gyp:script_main'] }
)
--- a/media/webrtc/trunk/tools/gyp/test/actions-bare/gyptest-bare.py
+++ b/media/webrtc/trunk/tools/gyp/test/actions-bare/gyptest-bare.py
@@ -8,16 +8,17 @@
Verifies actions which are not depended on by other targets get executed.
"""
import TestGyp
test = TestGyp.TestGyp()
test.run_gyp('bare.gyp', chdir='src')
+
test.relocate('src', 'relocate/src')
test.build('bare.gyp', chdir='relocate/src')
file_content = 'Hello from bare.py\n'
test.built_file_must_match('out.txt', file_content, chdir='relocate/src')
test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/actions-depfile/depfile.gyp
@@ -0,0 +1,25 @@
+# Copyright (c) 2015 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': 'depfile_target',
+ 'type': 'none',
+ 'actions': [
+ {
+ 'action_name': 'depfile_action',
+ 'inputs': [
+ 'input.txt',
+ ],
+ 'outputs': [
+ 'output.txt',
+ ],
+ 'depfile': 'depfile.d',
+ 'action': [ ]
+ },
+ ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/actions-depfile/gyptest-all.py
@@ -0,0 +1,20 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 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.
+
+"""Verifies that depfile fields are output in ninja rules."""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+if test.format == 'ninja':
+ test.run_gyp('depfile.gyp')
+ contents = open(test.built_file_path('obj/depfile_target.ninja')).read()
+
+ expected = 'depfile = depfile.d'
+ if expected not in contents:
+ test.fail_test()
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/actions-depfile/input.txt
@@ -0,0 +1,1 @@
+input
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/actions-multiple-outputs-with-dependencies/gyptest-action.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2015 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.
+
+"""
+Verifies actions with multiple outputs & dependncies will correctly rebuild.
+
+This is a regression test for crrev.com/1177163002.
+"""
+
+import TestGyp
+import os
+import sys
+import time
+
+if sys.platform in ('darwin', 'win32'):
+ print "This test is currently disabled: https://crbug.com/483696."
+ sys.exit(0)
+
+test = TestGyp.TestGyp()
+
+TESTDIR='relocate/src'
+test.run_gyp('action.gyp', chdir='src')
+test.relocate('src', TESTDIR)
+
+def build_and_check(content):
+ test.write(TESTDIR + '/input.txt', content)
+ test.build('action.gyp', 'upper', chdir=TESTDIR)
+ test.built_file_must_match('result.txt', content, chdir=TESTDIR)
+
+build_and_check('Content for first build.')
+
+# Ninja works with timestamps and the test above is fast enough that the
+# 'updated' file may end up with the same timestamp as the original, meaning
+# that ninja may not always recognize the input file has changed.
+if test.format == 'ninja':
+ time.sleep(1)
+
+build_and_check('An updated input file.')
+
+test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/actions-multiple-outputs-with-dependencies/src/action.gyp
@@ -0,0 +1,28 @@
+# Copyright (c) 2015 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': 'upper',
+ 'type': 'none',
+ 'actions': [{
+ 'action_name': 'upper_action',
+ 'inputs': ['<(PRODUCT_DIR)/out2.txt'],
+ 'outputs': ['<(PRODUCT_DIR)/result.txt'],
+ 'action': ['python', 'rcopy.py', '<@(_inputs)', '<@(_outputs)'],
+ }],
+ },
+ {
+ 'target_name': 'lower',
+ 'type': 'none',
+ 'actions': [{
+ 'action_name': 'lower_action',
+ 'inputs': ['input.txt'],
+ 'outputs': ['<(PRODUCT_DIR)/out1.txt', '<(PRODUCT_DIR)/out2.txt'],
+ 'action': ['python', 'rcopy.py', '<@(_inputs)', '<@(_outputs)'],
+ }],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/actions-multiple-outputs-with-dependencies/src/rcopy.py
@@ -0,0 +1,20 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2015 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.
+
+import os
+import sys
+
+"""A slightly odd 'cp' implementation for this test.
+
+This 'cp' can have many targets, but only one source. 'cp src dest1 dest2'
+will copy the file 'src' to both 'dest1' and 'dest2'."""
+
+with open(sys.argv[1], 'r') as f:
+ src = f.read()
+for dest in sys.argv[2:]:
+ with open(dest, 'w') as f:
+ f.write(src)
+
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/actions-multiple-outputs/gyptest-multiple-outputs.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2015 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.
+
+"""
+Verifies actions with multiple outputs will correctly rebuild.
+"""
+
+import TestGyp
+import os
+import sys
+
+if sys.platform == 'win32':
+ print "This test is currently disabled: https://crbug.com/483696."
+ sys.exit(0)
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('multiple-outputs.gyp', chdir='src')
+
+chdir = 'relocate/src'
+test.relocate('src', chdir)
+
+def build_and_check():
+ # Build + check that both outputs exist.
+ test.build('multiple-outputs.gyp', chdir=chdir)
+ test.built_file_must_exist('out1.txt', chdir=chdir)
+ test.built_file_must_exist('out2.txt', chdir=chdir)
+
+# Plain build.
+build_and_check()
+
+# Remove either + rebuild. Both should exist (again).
+os.remove(test.built_file_path('out1.txt', chdir=chdir))
+build_and_check();
+
+# Remove the other + rebuild. Both should exist (again).
+os.remove(test.built_file_path('out2.txt', chdir=chdir))
+build_and_check();
+
+test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/actions-multiple-outputs/src/multiple-outputs.gyp
@@ -0,0 +1,23 @@
+# Copyright (c) 2015 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': 'multiple-outputs',
+ 'type': 'none',
+ 'actions': [
+ {
+ 'action_name': 'action1',
+ 'inputs': [],
+ 'outputs': [
+ '<(PRODUCT_DIR)/out1.txt',
+ '<(PRODUCT_DIR)/out2.txt',
+ ],
+ 'action': ['python', 'touch.py', '<@(_outputs)'],
+ },
+ ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/actions-multiple-outputs/src/touch.py
@@ -0,0 +1,16 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2015 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.
+
+import os
+import sys
+
+"""Cross-platform touch."""
+
+for fname in sys.argv[1:]:
+ if os.path.exists(fname):
+ os.utime(fname, None)
+ else:
+ open(fname, 'w').close()
--- a/media/webrtc/trunk/tools/gyp/test/actions-none/gyptest-none.py
+++ b/media/webrtc/trunk/tools/gyp/test/actions-none/gyptest-none.py
@@ -6,21 +6,19 @@
"""
Verifies actions can be in 'none' type targets with source files.
"""
import TestGyp
test = TestGyp.TestGyp()
-# TODO(bradnelson): fix scons.
-if test.format == 'scons':
- test.skip_test()
test.run_gyp('none_with_source_files.gyp', chdir='src')
+
test.relocate('src', 'relocate/src')
test.build('none_with_source_files.gyp', chdir='relocate/src')
file_content = 'foo.cc\n'
test.built_file_must_match('fake.out', file_content, chdir='relocate/src')
test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/actions/generated-header/action.py
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 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.
+
+import os
+import sys
+
+outfile = sys.argv[1]
+open(outfile, 'w').write('const char kFoo[] = "%s";' % sys.argv[2])
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/actions/generated-header/main.cc
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+#include "MyHeader.h"
+
+int main() {
+ printf("%s\n", kFoo);
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/actions/generated-header/test.gyp
@@ -0,0 +1,34 @@
+# Copyright (c) 2013 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': 'generate_header',
+ 'type': 'none',
+ 'actions': [
+ {
+ 'inputs': [ ],
+ 'outputs': [
+ '<(SHARED_INTERMEDIATE_DIR)/MyHeader.h',
+ ],
+ 'action_name': 'generate header',
+ 'action': ['python', './action.py',
+ '<(SHARED_INTERMEDIATE_DIR)/MyHeader.h', 'foobar output' ],
+ },
+ ],
+ 'msvs_cygwin_shell': 0,
+ },
+ {
+ 'target_name': 'program',
+ 'type': 'executable',
+ 'dependencies': [
+ 'generate_header',
+ ],
+ 'include_dirs': [
+ '<(SHARED_INTERMEDIATE_DIR)',
+ ],
+ 'sources': [ 'main.cc' ],
+ },
+ ],
+}
--- a/media/webrtc/trunk/tools/gyp/test/actions/gyptest-all.py
+++ b/media/webrtc/trunk/tools/gyp/test/actions/gyptest-all.py
@@ -17,18 +17,17 @@ test = TestGyp.TestGyp(workdir='workarea
test.run_gyp('actions.gyp', chdir='src')
test.relocate('src', 'relocate/src')
# Some gyp files use an action that mentions an output but never
# writes it as a means to making the action run on every build. That
# doesn't mesh well with ninja's semantics. TODO(evan): figure out
# how to work always-run actions in to ninja.
-# Android also can't do this as it doesn't have order-only dependencies.
-if test.format in ['ninja', 'android']:
+if test.format in ['ninja', 'xcode-ninja']:
test.build('actions.gyp', test.ALL, chdir='relocate/src')
else:
# Test that an "always run" action increases a counter on multiple
# invocations, and that a dependent action updates in step.
test.build('actions.gyp', test.ALL, chdir='relocate/src')
test.must_match('relocate/src/subdir1/actions-out/action-counter.txt', '1')
test.must_match('relocate/src/subdir1/actions-out/action-counter_2.txt', '1')
test.build('actions.gyp', test.ALL, chdir='relocate/src')
--- a/media/webrtc/trunk/tools/gyp/test/actions/gyptest-default.py
+++ b/media/webrtc/trunk/tools/gyp/test/actions/gyptest-default.py
@@ -15,18 +15,17 @@ test = TestGyp.TestGyp(workdir='workarea
test.run_gyp('actions.gyp', chdir='src')
test.relocate('src', 'relocate/src')
# Some gyp files use an action that mentions an output but never
# writes it as a means to making the action run on every build. That
# doesn't mesh well with ninja's semantics. TODO(evan): figure out
# how to work always-run actions in to ninja.
-# Android also can't do this as it doesn't have order-only dependencies.
-if test.format in ['ninja', 'android']:
+if test.format in ['ninja', 'xcode-ninja']:
test.build('actions.gyp', test.ALL, chdir='relocate/src')
else:
# Test that an "always run" action increases a counter on multiple
# invocations, and that a dependent action updates in step.
test.build('actions.gyp', chdir='relocate/src')
test.must_match('relocate/src/subdir1/actions-out/action-counter.txt', '1')
test.must_match('relocate/src/subdir1/actions-out/action-counter_2.txt', '1')
test.build('actions.gyp', chdir='relocate/src')
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/actions/gyptest-generated-header.py
@@ -0,0 +1,38 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 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.
+
+"""
+Verifies that dependencies on generated headers work, even if the header has
+a mixed-case file name.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+CHDIR = 'generated-header'
+
+test.run_gyp('test.gyp', chdir=CHDIR)
+test.build('test.gyp', 'program', chdir=CHDIR)
+test.up_to_date('test.gyp', 'program', chdir=CHDIR)
+
+expect = 'foobar output\n'
+test.run_built_executable('program', chdir=CHDIR, stdout=expect)
+
+# Change what's written to the generated header, regyp and rebuild, and check
+# that the change makes it to the executable and that the build is clean.
+test.sleep()
+test.write('generated-header/test.gyp',
+ test.read('generated-header/test.gyp').replace('foobar', 'barbaz'))
+
+test.run_gyp('test.gyp', chdir=CHDIR)
+test.build('test.gyp', 'program', chdir=CHDIR)
+test.up_to_date('test.gyp', 'program', chdir=CHDIR)
+
+expect = 'barbaz output\n'
+test.run_built_executable('program', chdir=CHDIR, stdout=expect)
+
+test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/actions/src/subdir1/counter.py
+++ b/media/webrtc/trunk/tools/gyp/test/actions/src/subdir1/counter.py
@@ -24,21 +24,19 @@ if len(sys.argv) > 2:
oldcount = 0
try:
oldcount = open(output, 'r').read()
except:
pass
# Save the count in a file that is undeclared, and thus hidden, to gyp. We need
-# to do this because, prior to running commands, scons deletes any declared
-# outputs, so we would lose our count if we just wrote to the given output file.
-# (The other option is to use Precious() in the scons generator, but that seems
-# too heavy-handed just to support this somewhat unrealistic test case, and
-# might lead to unintended side-effects).
+# to do this because, prior to running commands, some build systems deletes
+# any declared outputs, so we would lose our count if we just wrote to the
+# given output file.
open(persistoutput, 'w').write('%d' % (count))
# Only write the given output file if the count has changed.
if int(oldcount) != count:
open(output, 'w').write('%d' % (count))
# Sleep so the next run changes the file time sufficiently to make the build
# detect the file as changed.
time.sleep(1)
--- a/media/webrtc/trunk/tools/gyp/test/actions/src/subdir1/program.c
+++ b/media/webrtc/trunk/tools/gyp/test/actions/src/subdir1/program.c
@@ -1,12 +1,12 @@
#include <stdio.h>
extern void prog1(void);
extern void prog2(void);
-int main(int argc, char *argv[])
+int main(void)
{
printf("Hello from program.c\n");
prog1();
prog2();
return 0;
}
--- a/media/webrtc/trunk/tools/gyp/test/actions/src/subdir3/generate_main.py
+++ b/media/webrtc/trunk/tools/gyp/test/actions/src/subdir3/generate_main.py
@@ -4,17 +4,17 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import sys
contents = """
#include <stdio.h>
-int main(int argc, char *argv[])
+int main(void)
{
printf("Hello from generate_main.py\\n");
return 0;
}
"""
open(sys.argv[1], 'w').write(contents)
--- a/media/webrtc/trunk/tools/gyp/test/additional-targets/gyptest-additional.py
+++ b/media/webrtc/trunk/tools/gyp/test/additional-targets/gyptest-additional.py
@@ -7,17 +7,20 @@
"""
Verifies simple actions when using an explicit build target of 'all'.
"""
import TestGyp
test = TestGyp.TestGyp()
-test.run_gyp('all.gyp', chdir='src')
+test.run_gyp('all.gyp',
+ '-G', 'xcode_ninja_target_pattern=^all_targets$',
+ chdir='src')
+
test.relocate('src', 'relocate/src')
# Build all.
test.build('all.gyp', chdir='relocate/src')
if test.format=='xcode':
chdir = 'relocate/src/dir1'
else:
@@ -27,18 +30,22 @@ else:
file_content = 'Hello from emit.py\n'
test.built_file_must_match('out2.txt', file_content, chdir=chdir)
test.built_file_must_not_exist('out.txt', chdir='relocate/src')
test.built_file_must_not_exist('foolib1',
type=test.SHARED_LIB,
chdir=chdir)
-# TODO(mmoss) Make consistent with scons, with 'dir1' before 'out/Default'?
-if test.format in ('make', 'ninja', 'android'):
+# xcode-ninja doesn't generate separate workspaces for sub-gyps by design
+if test.format == 'xcode-ninja':
+ test.pass_test()
+
+# TODO(mmoss) Make consistent with msvs, with 'dir1' before 'out/Default'?
+if test.format in ('make', 'ninja', 'cmake'):
chdir='relocate/src'
else:
chdir='relocate/src/dir1'
# Build the action explicitly.
test.build('actions.gyp', 'action1_target', chdir=chdir)
# Check that things got run.
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/analyzer/common.gypi
@@ -0,0 +1,6 @@
+# Copyright (c) 2014 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.
+
+{
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/analyzer/gyptest-analyzer.py
@@ -0,0 +1,425 @@
+#!/usr/bin/env python
+# Copyright (c) 2014 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.
+
+"""Tests for analyzer
+"""
+
+import json
+import TestGyp
+
+found = 'Found dependency'
+found_all = 'Found dependency (all)'
+not_found = 'No dependencies'
+
+
+def _CreateConfigFile(files, additional_compile_targets, test_targets=[]):
+ """Creates the analyzer config file, which is used as the input to analyzer.
+ See description of analyzer.py for description of the arguments."""
+ f = open('test_file', 'w')
+ to_write = {'files': files,
+ 'test_targets': test_targets,
+ 'additional_compile_targets': additional_compile_targets }
+ json.dump(to_write, f)
+ f.close()
+
+
+def _CreateBogusConfigFile():
+ f = open('test_file','w')
+ f.write('bogus')
+ f.close()
+
+
+def _ReadOutputFileContents():
+ f = open('analyzer_output', 'r')
+ result = json.load(f)
+ f.close()
+ return result
+
+
+# NOTE: this would be clearer if it subclassed TestGypCustom, but that trips
+# over a bug in pylint (E1002).
+test = TestGyp.TestGypCustom(format='analyzer')
+
+def CommonArgs():
+ return ('-Gconfig_path=test_file',
+ '-Ganalyzer_output_path=analyzer_output')
+
+
+def run_analyzer(*args, **kw):
+ """Runs the test specifying a particular config and output path."""
+ args += CommonArgs()
+ test.run_gyp('test.gyp', *args, **kw)
+
+
+def run_analyzer2(*args, **kw):
+ """Same as run_analyzer(), but passes in test2.gyp instead of test.gyp."""
+ args += CommonArgs()
+ test.run_gyp('test2.gyp', *args, **kw)
+
+
+def run_analyzer3(*args, **kw):
+ """Same as run_analyzer(), but passes in test3.gyp instead of test.gyp."""
+ args += CommonArgs()
+ test.run_gyp('test3.gyp', *args, **kw)
+
+
+def run_analyzer4(*args, **kw):
+ """Same as run_analyzer(), but passes in test3.gyp instead of test.gyp."""
+ args += CommonArgs()
+ test.run_gyp('test4.gyp', *args, **kw)
+
+
+def EnsureContains(matched=False, compile_targets=set(), test_targets=set()):
+ """Verifies output contains |compile_targets|."""
+ result = _ReadOutputFileContents()
+ if 'error' in result:
+ print 'unexpected error', result.get('error')
+ test.fail_test()
+
+ if 'invalid_targets' in result:
+ print 'unexpected invalid_targets', result.get('invalid_targets')
+ test.fail_test()
+
+ actual_compile_targets = set(result['compile_targets'])
+ if actual_compile_targets != compile_targets:
+ print 'actual compile_targets:', actual_compile_targets, \
+ '\nexpected compile_targets:', compile_targets
+ test.fail_test()
+
+ actual_test_targets = set(result['test_targets'])
+ if actual_test_targets != test_targets:
+ print 'actual test_targets:', actual_test_targets, \
+ '\nexpected test_targets:', test_targets
+ test.fail_test()
+
+ if matched and result['status'] != found:
+ print 'expected', found, 'got', result['status']
+ test.fail_test()
+ elif not matched and result['status'] != not_found:
+ print 'expected', not_found, 'got', result['status']
+ test.fail_test()
+
+
+def EnsureMatchedAll(compile_targets, test_targets=set()):
+ result = _ReadOutputFileContents()
+ if 'error' in result:
+ print 'unexpected error', result.get('error')
+ test.fail_test()
+
+ if 'invalid_targets' in result:
+ print 'unexpected invalid_targets', result.get('invalid_targets')
+ test.fail_test()
+
+ if result['status'] != found_all:
+ print 'expected', found_all, 'got', result['status']
+ test.fail_test()
+
+ actual_compile_targets = set(result['compile_targets'])
+ if actual_compile_targets != compile_targets:
+ print ('actual compile_targets:', actual_compile_targets,
+ '\nexpected compile_targets:', compile_targets)
+ test.fail_test()
+
+ actual_test_targets = set(result['test_targets'])
+ if actual_test_targets != test_targets:
+ print ('actual test_targets:', actual_test_targets,
+ '\nexpected test_targets:', test_targets)
+ test.fail_test()
+
+
+def EnsureError(expected_error_string):
+ """Verifies output contains the error string."""
+ result = _ReadOutputFileContents()
+ if result.get('error', '').find(expected_error_string) == -1:
+ print 'actual error:', result.get('error', ''), '\nexpected error:', \
+ expected_error_string
+ test.fail_test()
+
+
+def EnsureStdoutContains(expected_error_string):
+ if test.stdout().find(expected_error_string) == -1:
+ print 'actual stdout:', test.stdout(), '\nexpected stdout:', \
+ expected_error_string
+ test.fail_test()
+
+
+def EnsureInvalidTargets(expected_invalid_targets):
+ """Verifies output contains invalid_targets."""
+ result = _ReadOutputFileContents()
+ actual_invalid_targets = set(result['invalid_targets'])
+ if actual_invalid_targets != expected_invalid_targets:
+ print 'actual invalid_targets:', actual_invalid_targets, \
+ '\nexpected :', expected_invalid_targets
+ test.fail_test()
+
+
+# Two targets, A and B (both static_libraries) and A depends upon B. If a file
+# in B changes, then both A and B are output. It is not strictly necessary that
+# A is compiled in this case, only B.
+_CreateConfigFile(['b.c'], ['all'])
+test.run_gyp('static_library_test.gyp', *CommonArgs())
+EnsureContains(matched=True, compile_targets={'a' ,'b'})
+
+# Verifies config_path must be specified.
+test.run_gyp('test.gyp')
+EnsureStdoutContains('Must specify files to analyze via config_path')
+
+# Verifies config_path must point to a valid file.
+test.run_gyp('test.gyp', '-Gconfig_path=bogus_file',
+ '-Ganalyzer_output_path=analyzer_output')
+EnsureError('Unable to open file bogus_file')
+
+# Verify 'invalid_targets' is present when bad target is specified.
+_CreateConfigFile(['exe2.c'], ['bad_target'])
+run_analyzer()
+EnsureInvalidTargets({'bad_target'})
+
+# Verifies config_path must point to a valid json file.
+_CreateBogusConfigFile()
+run_analyzer()
+EnsureError('Unable to parse config file test_file')
+
+# Trivial test of a source.
+_CreateConfigFile(['foo.c'], ['all'])
+run_analyzer()
+EnsureContains(matched=True, compile_targets={'exe'})
+
+# Conditional source that is excluded.
+_CreateConfigFile(['conditional_source.c'], ['all'])
+run_analyzer()
+EnsureContains(matched=False)
+
+# Conditional source that is included by way of argument.
+_CreateConfigFile(['conditional_source.c'], ['all'])
+run_analyzer('-Dtest_variable=1')
+EnsureContains(matched=True, compile_targets={'exe'})
+
+# Two unknown files.
+_CreateConfigFile(['unknown1.c', 'unoknow2.cc'], ['all'])
+run_analyzer()
+EnsureContains()
+
+# Two unknown files.
+_CreateConfigFile(['unknown1.c', 'subdir/subdir_sourcex.c'], ['all'])
+run_analyzer()
+EnsureContains()
+
+# Included dependency
+_CreateConfigFile(['unknown1.c', 'subdir/subdir_source.c'], ['all'])
+run_analyzer()
+EnsureContains(matched=True, compile_targets={'exe', 'exe3'})
+
+# Included inputs to actions.
+_CreateConfigFile(['action_input.c'], ['all'])
+run_analyzer()
+EnsureContains(matched=True, compile_targets={'exe'})
+
+# Don't consider outputs.
+_CreateConfigFile(['action_output.c'], ['all'])
+run_analyzer()
+EnsureContains(matched=False)
+
+# Rule inputs.
+_CreateConfigFile(['rule_input.c'], ['all'])
+run_analyzer()
+EnsureContains(matched=True, compile_targets={'exe'})
+
+# Ignore path specified with PRODUCT_DIR.
+_CreateConfigFile(['product_dir_input.c'], ['all'])
+run_analyzer()
+EnsureContains(matched=False)
+
+# Path specified via a variable.
+_CreateConfigFile(['subdir/subdir_source2.c'], ['all'])
+run_analyzer()
+EnsureContains(matched=True, compile_targets={'exe'})
+
+# Verifies paths with // are fixed up correctly.
+_CreateConfigFile(['parent_source.c'], ['all'])
+run_analyzer()
+EnsureContains(matched=True, compile_targets={'exe', 'exe3'})
+
+# Verifies relative paths are resolved correctly.
+_CreateConfigFile(['subdir/subdir_source.h'], ['all'])
+run_analyzer()
+EnsureContains(matched=True, compile_targets={'exe'})
+
+# Verifies relative paths in inputs are resolved correctly.
+_CreateConfigFile(['rel_path1.h'], ['all'])
+run_analyzer()
+EnsureContains(matched=True, compile_targets={'exe'})
+
+# Various permutations when passing in targets.
+_CreateConfigFile(['exe2.c', 'subdir/subdir2b_source.c'],
+ ['all'], ['exe', 'exe3'])
+run_analyzer()
+EnsureContains(matched=True, test_targets={'exe3'},
+ compile_targets={'exe2', 'exe3'})
+
+_CreateConfigFile(['exe2.c', 'subdir/subdir2b_source.c'], ['all'], ['exe'])
+run_analyzer()
+EnsureContains(matched=True, compile_targets={'exe2', 'exe3'})
+
+# Verifies duplicates are ignored.
+_CreateConfigFile(['exe2.c', 'subdir/subdir2b_source.c'], ['all'],
+ ['exe', 'exe'])
+run_analyzer()
+EnsureContains(matched=True, compile_targets={'exe2', 'exe3'})
+
+_CreateConfigFile(['exe2.c'], ['all'], ['exe'])
+run_analyzer()
+EnsureContains(matched=True, compile_targets={'exe2'})
+
+_CreateConfigFile(['exe2.c'], ['all'])
+run_analyzer()
+EnsureContains(matched=True, compile_targets={'exe2'})
+
+_CreateConfigFile(['subdir/subdir2b_source.c', 'exe2.c'], ['all'])
+run_analyzer()
+EnsureContains(matched=True, compile_targets={'exe2', 'exe3'})
+
+_CreateConfigFile(['subdir/subdir2b_source.c'], ['all'], ['exe3'])
+run_analyzer()
+EnsureContains(matched=True, test_targets={'exe3'}, compile_targets={'exe3'})
+
+_CreateConfigFile(['exe2.c'], ['all'])
+run_analyzer()
+EnsureContains(matched=True, compile_targets={'exe2'})
+
+_CreateConfigFile(['foo.c'], ['all'])
+run_analyzer()
+EnsureContains(matched=True, compile_targets={'exe'})
+
+# Assertions when modifying build (gyp/gypi) files, especially when said files
+# are included.
+_CreateConfigFile(['subdir2/d.cc'], ['all'], ['exe', 'exe2', 'foo', 'exe3'])
+run_analyzer2()
+EnsureContains(matched=True, test_targets={'exe', 'foo'},
+ compile_targets={'exe', 'foo'})
+
+_CreateConfigFile(['subdir2/subdir.includes.gypi'], ['all'],
+ ['exe', 'exe2', 'foo', 'exe3'])
+run_analyzer2()
+EnsureContains(matched=True, test_targets={'exe', 'foo'},
+ compile_targets={'exe', 'foo'})
+
+_CreateConfigFile(['subdir2/subdir.gyp'], ['all'],
+ ['exe', 'exe2', 'foo', 'exe3'])
+run_analyzer2()
+EnsureContains(matched=True, test_targets={'exe', 'foo'},
+ compile_targets={'exe', 'foo'})
+
+_CreateConfigFile(['test2.includes.gypi'], ['all'],
+ ['exe', 'exe2', 'foo', 'exe3'])
+run_analyzer2()
+EnsureContains(matched=True, test_targets={'exe', 'exe2', 'exe3'},
+ compile_targets={'exe', 'exe2', 'exe3'})
+
+# Verify modifying a file included makes all targets dirty.
+_CreateConfigFile(['common.gypi'], ['all'], ['exe', 'exe2', 'foo', 'exe3'])
+run_analyzer2('-Icommon.gypi')
+EnsureMatchedAll({'all', 'exe', 'exe2', 'foo', 'exe3'},
+ {'exe', 'exe2', 'foo', 'exe3'})
+
+# Assertions from test3.gyp.
+_CreateConfigFile(['d.c', 'f.c'], ['all'], ['a'])
+run_analyzer3()
+EnsureContains(matched=True, test_targets={'a'}, compile_targets={'a', 'b'})
+
+_CreateConfigFile(['f.c'], ['all'], ['a'])
+run_analyzer3()
+EnsureContains(matched=True, test_targets={'a'}, compile_targets={'a', 'b'})
+
+_CreateConfigFile(['f.c'], ['all'])
+run_analyzer3()
+EnsureContains(matched=True, compile_targets={'a', 'b'})
+
+_CreateConfigFile(['c.c', 'e.c'], ['all'])
+run_analyzer3()
+EnsureContains(matched=True, compile_targets={'a', 'b', 'c', 'e'})
+
+_CreateConfigFile(['d.c'], ['all'], ['a'])
+run_analyzer3()
+EnsureContains(matched=True, test_targets={'a'}, compile_targets={'a', 'b'})
+
+_CreateConfigFile(['a.c'], ['all'], ['a', 'b'])
+run_analyzer3()
+EnsureContains(matched=True, test_targets={'a'}, compile_targets={'a'})
+
+_CreateConfigFile(['a.c'], ['all'], ['a', 'b'])
+run_analyzer3()
+EnsureContains(matched=True, test_targets={'a'}, compile_targets={'a'})
+
+_CreateConfigFile(['d.c'], ['all'], ['a', 'b'])
+run_analyzer3()
+EnsureContains(matched=True, test_targets={'a', 'b'},
+ compile_targets={'a', 'b'})
+
+_CreateConfigFile(['f.c'], ['all'], ['a'])
+run_analyzer3()
+EnsureContains(matched=True, test_targets={'a'}, compile_targets={'a', 'b'})
+
+_CreateConfigFile(['a.c'], ['all'], ['a'])
+run_analyzer3()
+EnsureContains(matched=True, test_targets={'a'}, compile_targets={'a'})
+
+_CreateConfigFile(['a.c'], ['all'])
+run_analyzer3()
+EnsureContains(matched=True, compile_targets={'a'})
+
+_CreateConfigFile(['d.c'], ['all'])
+run_analyzer3()
+EnsureContains(matched=True, compile_targets={'a', 'b'})
+
+# Assertions around test4.gyp.
+_CreateConfigFile(['f.c'], ['all'])
+run_analyzer4()
+EnsureContains(matched=True, compile_targets={'e', 'f'})
+
+_CreateConfigFile(['d.c'], ['all'])
+run_analyzer4()
+EnsureContains(matched=True, compile_targets={'a', 'b', 'c', 'd'})
+
+_CreateConfigFile(['i.c'], ['all'])
+run_analyzer4()
+EnsureContains(matched=True, compile_targets={'h', 'i'})
+
+# Assertions where 'all' is not supplied in compile_targets.
+
+_CreateConfigFile(['exe2.c'], [], ['exe2'])
+run_analyzer()
+EnsureContains(matched=True, test_targets={'exe2'}, compile_targets={'exe2'})
+
+_CreateConfigFile(['exe20.c'], [], ['exe2'])
+run_analyzer()
+EnsureContains(matched=False)
+
+
+_CreateConfigFile(['exe2.c', 'exe3.c'], [], ['exe2', 'exe3'])
+run_analyzer()
+EnsureContains(matched=True, test_targets={'exe2', 'exe3'},
+ compile_targets={'exe2', 'exe3'})
+
+_CreateConfigFile(['exe2.c', 'exe3.c'], ['exe3'], ['exe2'])
+run_analyzer()
+EnsureContains(matched=True, test_targets={'exe2'},
+ compile_targets={'exe2', 'exe3'})
+
+_CreateConfigFile(['exe3.c'], ['exe2'], ['exe2'])
+run_analyzer()
+EnsureContains(matched=False)
+
+# Assertions with 'all' listed as a test_target.
+_CreateConfigFile(['exe3.c'], [], ['all'])
+run_analyzer()
+EnsureContains(matched=True, compile_targets={'exe3', 'all'},
+ test_targets={'all'})
+
+_CreateConfigFile(['exe2.c'], [], ['all', 'exe2'])
+run_analyzer()
+EnsureContains(matched=True, compile_targets={'exe2', 'all'},
+ test_targets={'all', 'exe2'})
+
+test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/analyzer/static_library_test.gyp
@@ -0,0 +1,34 @@
+# Copyright 2015 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.
+
+# These gyp files create the following dependencies:
+#
+# test.gyp:
+# #a -> b
+# a.c
+# #b
+# b.c
+# a and b are static libraries.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'a',
+ 'type': 'static_library',
+ 'sources': [
+ 'a.c',
+ ],
+ 'dependencies': [
+ 'b',
+ ],
+ },
+ {
+ 'target_name': 'b',
+ 'type': 'static_library',
+ 'sources': [
+ 'b.c',
+ ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/analyzer/subdir/subdir.gyp
@@ -0,0 +1,36 @@
+# Copyright (c) 2014 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.
+
+{
+ 'variables': {
+ 'trailing_dir_path': '../',
+ },
+ 'targets': [
+ {
+ 'target_name': 'foo',
+ 'type': 'static_library',
+ 'sources': [
+ 'subdir_source.c',
+ '<(trailing_dir_path)/parent_source.c',
+ ],
+ },
+ {
+ 'target_name': 'subdir2a',
+ 'type': 'static_library',
+ 'sources': [
+ 'subdir2_source.c',
+ ],
+ 'dependencies': [
+ 'subdir2b',
+ ],
+ },
+ {
+ 'target_name': 'subdir2b',
+ 'type': 'static_library',
+ 'sources': [
+ 'subdir2b_source.c',
+ ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/analyzer/subdir/subdir2/subdir2.gyp
@@ -0,0 +1,15 @@
+# Copyright (c) 2014 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': 'subdir2',
+ 'type': 'static_library',
+ 'sources': [
+ '../subdir_source.h',
+ ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/analyzer/subdir2/subdir.gyp
@@ -0,0 +1,18 @@
+# Copyright (c) 2014 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': 'foo',
+ 'type': 'static_library',
+ 'sources': [
+ 'subdir_source.c',
+ ],
+ 'includes': [
+ 'subdir.includes.gypi',
+ ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/analyzer/subdir2/subdir.includes.gypi
@@ -0,0 +1,9 @@
+# Copyright (c) 2014 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.
+
+{
+ 'sources': [
+ 'd.cc'
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/analyzer/test.gyp
@@ -0,0 +1,114 @@
+# Copyright (c) 2014 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.
+
+# These gyp files create the following dependencies:
+#
+# test.gyp:
+# #exe -> subdir/subdir.gyp#foo, subdir/subdir2/subdir2.gyp#subdir2
+# foo.c
+# subdir/subdir_source2.c
+# conditional_source.c (if test_variable==1)
+# action_input.c
+# action_output.c
+# rule_input.c
+# rule_output.pdf
+# #exe2
+# exe2.c
+# #exe3 -> subdir/subdir.gyp#foo, subdir/subdir.gyp#subdir2a
+# exe3.c
+# #allx (type none) -> exe, exe3
+#
+# subdir/subdir.gyp
+# #foo
+# subdir/subdir_source.c
+# parent_source.c
+# #subdir2a -> subdir2b
+# subdir/subdir2_source.c
+# #subdir2b
+# subdir/subdir2b_source.c
+#
+# subdir/subdir2/subdir2.gyp
+# #subdir2
+# subdir/subdir_source.h
+
+{
+ 'variables': {
+ 'test_variable%': 0,
+ 'variable_path': 'subdir',
+ },
+ 'targets': [
+ {
+ 'target_name': 'exe',
+ 'type': 'executable',
+ 'dependencies': [
+ 'subdir/subdir.gyp:foo',
+ 'subdir/subdir2/subdir2.gyp:subdir2',
+ ],
+ 'sources': [
+ 'foo.c',
+ '<(variable_path)/subdir_source2.c',
+ ],
+ 'conditions': [
+ ['test_variable==1', {
+ 'sources': [
+ 'conditional_source.c',
+ ],
+ }],
+ ],
+ 'actions': [
+ {
+ 'action_name': 'action',
+ 'inputs': [
+ '<(PRODUCT_DIR)/product_dir_input.c',
+ 'action_input.c',
+ '../bad_path1.h',
+ '../../bad_path2.h',
+ './rel_path1.h',
+ ],
+ 'outputs': [
+ 'action_output.c',
+ ],
+ },
+ ],
+ 'rules': [
+ {
+ 'rule_name': 'rule',
+ 'extension': 'pdf',
+ 'inputs': [
+ 'rule_input.c',
+ ],
+ 'outputs': [
+ 'rule_output.pdf',
+ ],
+ },
+ ],
+ },
+ {
+ 'target_name': 'exe2',
+ 'type': 'executable',
+ 'sources': [
+ 'exe2.c',
+ ],
+ },
+ {
+ 'target_name': 'exe3',
+ 'type': 'executable',
+ 'dependencies': [
+ 'subdir/subdir.gyp:foo',
+ 'subdir/subdir.gyp:subdir2a',
+ ],
+ 'sources': [
+ 'exe3.c',
+ ],
+ },
+ {
+ 'target_name': 'allx',
+ 'type': 'none',
+ 'dependencies': [
+ 'exe',
+ 'exe3',
+ ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/analyzer/test2.gyp
@@ -0,0 +1,25 @@
+# Copyright (c) 2014 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': 'exe',
+ 'type': 'executable',
+ 'dependencies': [
+ 'subdir2/subdir.gyp:foo',
+ ],
+ },
+ {
+ 'target_name': 'exe2',
+ 'type': 'executable',
+ 'includes': [
+ 'test2.includes.gypi',
+ ],
+ },
+ ],
+ 'includes': [
+ 'test2.toplevel_includes.gypi',
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/analyzer/test2.includes.gypi
@@ -0,0 +1,13 @@
+# Copyright (c) 2014 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.
+
+{
+ 'sources': [
+ 'a.cc',
+ 'b.cc'
+ ],
+ 'includes': [
+ 'test2.includes.includes.gypi',
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/analyzer/test2.includes.includes.gypi
@@ -0,0 +1,9 @@
+# Copyright (c) 2014 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.
+
+{
+ 'sources': [
+ 'c.cc'
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/analyzer/test2.toplevel_includes.gypi
@@ -0,0 +1,15 @@
+# Copyright (c) 2014 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': 'exe3',
+ 'type': 'executable',
+ 'sources': [
+ 'e.cc',
+ ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/analyzer/test3.gyp
@@ -0,0 +1,77 @@
+# Copyright (c) 2014 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': 'allx',
+ 'type': 'none',
+ 'dependencies': [
+ 'a',
+ 'b',
+ ],
+ },
+ {
+ 'target_name': 'a',
+ 'type': 'executable',
+ 'sources': [
+ 'a.c',
+ ],
+ 'dependencies': [
+ 'c',
+ 'd',
+ ],
+ },
+ {
+ 'target_name': 'b',
+ 'type': 'executable',
+ 'sources': [
+ 'b.c',
+ ],
+ 'dependencies': [
+ 'd',
+ 'e',
+ ],
+ },
+ {
+ 'target_name': 'c',
+ 'type': 'executable',
+ 'sources': [
+ 'c.c',
+ ],
+ },
+ {
+ 'target_name': 'd',
+ 'type': 'none',
+ 'sources': [
+ 'd.c',
+ ],
+ 'dependencies': [
+ 'f',
+ 'g',
+ ],
+ },
+ {
+ 'target_name': 'e',
+ 'type': 'executable',
+ 'sources': [
+ 'e.c',
+ ],
+ },
+ {
+ 'target_name': 'f',
+ 'type': 'static_library',
+ 'sources': [
+ 'f.c',
+ ],
+ },
+ {
+ 'target_name': 'g',
+ 'type': 'executable',
+ 'sources': [
+ 'g.c',
+ ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/analyzer/test4.gyp
@@ -0,0 +1,80 @@
+# Copyright (c) 2014 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': 'a',
+ 'type': 'executable',
+ 'sources': [
+ 'a.c',
+ ],
+ 'dependencies': [
+ 'b',
+ 'c',
+ ],
+ },
+ {
+ 'target_name': 'b',
+ 'type': 'executable',
+ 'sources': [
+ 'b.c',
+ ],
+ 'dependencies': [
+ 'd',
+ ],
+ },
+ {
+ 'target_name': 'c',
+ 'type': 'executable',
+ 'sources': [
+ 'c.c',
+ ],
+ 'dependencies': [
+ 'b',
+ 'd',
+ ],
+ },
+ {
+ 'target_name': 'd',
+ 'type': 'executable',
+ 'sources': [
+ 'd.c',
+ ],
+ },
+ {
+ 'target_name': 'e',
+ 'type': 'executable',
+ 'dependencies': [
+ 'test5.gyp:f',
+ ],
+ },
+ {
+ 'target_name': 'h',
+ 'type': 'none',
+ 'dependencies': [
+ 'i',
+ ],
+ 'rules': [
+ {
+ 'rule_name': 'rule',
+ 'extension': 'pdf',
+ 'inputs': [
+ 'rule_input.c',
+ ],
+ 'outputs': [
+ 'rule_output.pdf',
+ ],
+ },
+ ],
+ },
+ {
+ 'target_name': 'i',
+ 'type': 'static_library',
+ 'sources': [
+ 'i.c',
+ ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/analyzer/test5.gyp
@@ -0,0 +1,25 @@
+# Copyright (c) 2014 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': 'f',
+ 'type': 'executable',
+ 'sources': [
+ 'f.c',
+ ],
+ },
+ {
+ 'target_name': 'g',
+ 'type': 'executable',
+ 'sources': [
+ 'g.c',
+ ],
+ 'dependencies': [
+ 'f',
+ ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/arflags/gyptest-arflags.py
@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 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.
+
+"""
+Verifies that building a target with invalid arflags fails.
+"""
+
+import os
+import sys
+import TestGyp
+
+if sys.platform == 'darwin':
+ print "This test is currently disabled: https://crbug.com/483696."
+ sys.exit(0)
+
+
+test = TestGyp.TestGyp(formats=['ninja'])
+test.run_gyp('test.gyp')
+expected_status = 0 if sys.platform in ['darwin', 'win32'] else 1
+test.build('test.gyp', target='lib', status=expected_status)
+test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/arflags/test.gyp
@@ -0,0 +1,10 @@
+{
+ 'targets': [
+ {
+ 'target_name': 'lib',
+ 'type': 'static_library',
+ 'sources': ['lib.cc'],
+ 'arflags': ['--nonexistent'],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/assembly/gyptest-override.py
@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 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.
+
+"""
+Make sure that manual rules on Windows override the built in ones.
+"""
+
+import sys
+import TestGyp
+
+if sys.platform == 'win32':
+ test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+ CHDIR = 'src'
+ test.run_gyp('override.gyp', chdir=CHDIR)
+ test.build('override.gyp', test.ALL, chdir=CHDIR)
+ expect = """\
+Hello from program.c
+Got 42.
+"""
+ test.run_built_executable('program', chdir=CHDIR, stdout=expect)
+ test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/assembly/src/as.bat
+++ b/media/webrtc/trunk/tools/gyp/test/assembly/src/as.bat
@@ -1,4 +1,4 @@
@echo off
:: Mock windows assembler.
-cl /c %1 /Fo"%2"
+cl /MD /c %1 /Fo"%2"
--- a/media/webrtc/trunk/tools/gyp/test/assembly/src/assembly.gyp
+++ b/media/webrtc/trunk/tools/gyp/test/assembly/src/assembly.gyp
@@ -3,17 +3,17 @@
# found in the LICENSE file.
{
'target_defaults': {
'conditions': [
['OS=="win"', {
'defines': ['PLATFORM_WIN'],
}],
- ['OS=="mac"', {
+ ['OS=="mac" or OS=="ios"', {
'defines': ['PLATFORM_MAC'],
}],
['OS=="linux"', {
'defines': ['PLATFORM_LINUX'],
}],
['OS=="android"', {
'defines': ['PLATFORM_ANDROID'],
}],
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/assembly/src/override.gyp
@@ -0,0 +1,34 @@
+# Copyright (c) 2012 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': 'program',
+ 'type': 'executable',
+ 'sources': [
+ 'program.c',
+ 'override_asm.asm',
+ ],
+ 'rules': [
+ {
+ # Test that if there's a specific .asm rule, it overrides the
+ # built in one on Windows.
+ 'rule_name': 'assembler',
+ 'msvs_cygwin_shell': 0,
+ 'extension': 'asm',
+ 'inputs': [
+ 'as.bat',
+ ],
+ 'outputs': [
+ 'output.obj',
+ ],
+ 'action': ['as.bat', 'lib1.c', '<(_outputs)'],
+ 'message': 'Building assembly file <(RULE_INPUT_PATH)',
+ 'process_outputs_as_sources': 1,
+ },
+ ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/assembly/src/override_asm.asm
@@ -0,0 +1,8 @@
+; Copyright (c) 2012 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.
+
+; This is a placeholder. It should not be referenced if overrides work
+; correctly.
+
+Bad stuff that shouldn't assemble.
--- a/media/webrtc/trunk/tools/gyp/test/assembly/src/program.c
+++ b/media/webrtc/trunk/tools/gyp/test/assembly/src/program.c
@@ -1,12 +1,12 @@
#include <stdio.h>
extern int lib1_function(void);
-int main(int argc, char *argv[])
+int main(void)
{
fprintf(stdout, "Hello from program.c\n");
fflush(stdout);
fprintf(stdout, "Got %d.\n", lib1_function());
fflush(stdout);
return 0;
}
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/build-option/gyptest-build.py
@@ -0,0 +1,27 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 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.
+
+"""
+Verifies simplest-possible build of a "Hello, world!" program
+using the default build target.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp(workdir='workarea_default')
+
+if test.format == 'xcode-ninja':
+ # The xcode-ninja generator doesn't support --build
+ # cf. https://code.google.com/p/gyp/issues/detail?id=453
+ test.skip_test()
+
+test.run_gyp('hello.gyp', '--build=Default')
+
+test.run_built_executable('hello', stdout="Hello, world!\n")
+
+test.up_to_date('hello.gyp', test.DEFAULT)
+
+test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/build-option/hello.c
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2012 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>
+
+int main(void)
+{
+ printf("Hello, world!\n");
+ return 0;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/build-option/hello.gyp
@@ -0,0 +1,15 @@
+# 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': 'hello',
+ 'type': 'executable',
+ 'sources': [
+ 'hello.c',
+ ],
+ },
+ ],
+}
--- a/media/webrtc/trunk/tools/gyp/test/builddir/gyptest-all.py
+++ b/media/webrtc/trunk/tools/gyp/test/builddir/gyptest-all.py
@@ -18,18 +18,18 @@ import TestGyp
# gyp-file-specific settings (e.g. the stuff in builddir.gypi) that the other
# generators support, so this doesn't work yet for make.
# TODO(mmoss) Make also has the issue that the top-level Makefile is written to
# the "--depth" location, which is one level above 'src', but then this test
# moves 'src' somewhere else, leaving the Makefile behind, so make can't find
# its sources. I'm not sure if make is wrong for writing outside the current
# directory, or if the test is wrong for assuming everything generated is under
# the current directory.
-# Android does not support setting the build directory.
-test = TestGyp.TestGyp(formats=['!make', '!ninja', '!android'])
+# Ninja and CMake do not support setting the build directory.
+test = TestGyp.TestGyp(formats=['!make', '!ninja', '!cmake'])
test.run_gyp('prog1.gyp', '--depth=..', chdir='src')
if test.format == 'msvs':
if test.uses_msbuild:
test.must_contain('src/prog1.vcxproj',
'<OutDir>..\\builddir\\Default\\</OutDir>')
else:
test.must_contain('src/prog1.vcproj',
--- a/media/webrtc/trunk/tools/gyp/test/builddir/gyptest-default.py
+++ b/media/webrtc/trunk/tools/gyp/test/builddir/gyptest-default.py
@@ -18,18 +18,18 @@ import TestGyp
# gyp-file-specific settings (e.g. the stuff in builddir.gypi) that the other
# generators support, so this doesn't work yet for make.
# TODO(mmoss) Make also has the issue that the top-level Makefile is written to
# the "--depth" location, which is one level above 'src', but then this test
# moves 'src' somewhere else, leaving the Makefile behind, so make can't find
# its sources. I'm not sure if make is wrong for writing outside the current
# directory, or if the test is wrong for assuming everything generated is under
# the current directory.
-# Android does not support setting the build directory.
-test = TestGyp.TestGyp(formats=['!make', '!ninja', '!android'])
+# Ninja and CMake do not support setting the build directory.
+test = TestGyp.TestGyp(formats=['!make', '!ninja', '!cmake'])
test.run_gyp('prog1.gyp', '--depth=..', chdir='src')
if test.format == 'msvs':
if test.uses_msbuild:
test.must_contain('src/prog1.vcxproj',
'<OutDir>..\\builddir\\Default\\</OutDir>')
else:
test.must_contain('src/prog1.vcproj',
--- a/media/webrtc/trunk/tools/gyp/test/builddir/src/builddir.gypi
+++ b/media/webrtc/trunk/tools/gyp/test/builddir/src/builddir.gypi
@@ -7,15 +7,12 @@
'configurations': {
'Default': {
'msvs_configuration_attributes': {
'OutputDirectory': '<(DEPTH)\\builddir/Default',
},
},
},
},
- 'scons_settings': {
- 'sconsbuild_dir': '<(DEPTH)/builddir',
- },
'xcode_settings': {
'SYMROOT': '<(DEPTH)/builddir',
},
}
--- a/media/webrtc/trunk/tools/gyp/test/builddir/src/prog1.c
+++ b/media/webrtc/trunk/tools/gyp/test/builddir/src/prog1.c
@@ -1,10 +1,10 @@
#include <stdio.h>
extern void func1(void);
-int main(int argc, char *argv[])
+int main(void)
{
printf("Hello from prog1.c\n");
func1();
return 0;
}
--- a/media/webrtc/trunk/tools/gyp/test/builddir/src/subdir2/prog2.c
+++ b/media/webrtc/trunk/tools/gyp/test/builddir/src/subdir2/prog2.c
@@ -1,10 +1,10 @@
#include <stdio.h>
extern void func2(void);
-int main(int argc, char *argv[])
+int main(void)
{
printf("Hello from subdir2/prog2.c\n");
func2();
return 0;
}
--- a/media/webrtc/trunk/tools/gyp/test/builddir/src/subdir2/subdir3/prog3.c
+++ b/media/webrtc/trunk/tools/gyp/test/builddir/src/subdir2/subdir3/prog3.c
@@ -1,10 +1,10 @@
#include <stdio.h>
extern void func3(void);
-int main(int argc, char *argv[])
+int main(void)
{
printf("Hello from subdir2/subdir3/prog3.c\n");
func3();
return 0;
}
--- a/media/webrtc/trunk/tools/gyp/test/builddir/src/subdir2/subdir3/subdir4/prog4.c
+++ b/media/webrtc/trunk/tools/gyp/test/builddir/src/subdir2/subdir3/subdir4/prog4.c
@@ -1,10 +1,10 @@
#include <stdio.h>
extern void func4(void);
-int main(int argc, char *argv[])
+int main(void)
{
printf("Hello from subdir2/subdir3/subdir4/prog4.c\n");
func4();
return 0;
}
--- a/media/webrtc/trunk/tools/gyp/test/builddir/src/subdir2/subdir3/subdir4/subdir5/prog5.c
+++ b/media/webrtc/trunk/tools/gyp/test/builddir/src/subdir2/subdir3/subdir4/subdir5/prog5.c
@@ -1,10 +1,10 @@
#include <stdio.h>
extern void func5(void);
-int main(int argc, char *argv[])
+int main(void)
{
printf("Hello from subdir2/subdir3/subdir4/subdir5/prog5.c\n");
func5();
return 0;
}
--- a/media/webrtc/trunk/tools/gyp/test/cflags/cflags.c
+++ b/media/webrtc/trunk/tools/gyp/test/cflags/cflags.c
@@ -1,15 +1,15 @@
/* Copyright (c) 2010 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>
-int main(int argc, char *argv[])
+int main(void)
{
-#ifdef __OPTIMIZE__
- printf("Using an optimization flag\n");
+#ifdef FOO
+ printf("FOO defined\n");
#else
- printf("Using no optimization flag\n");
+ printf("FOO not defined\n");
#endif
return 0;
}
--- a/media/webrtc/trunk/tools/gyp/test/cflags/cflags.gyp
+++ b/media/webrtc/trunk/tools/gyp/test/cflags/cflags.gyp
@@ -2,15 +2,22 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
{
'targets': [
{
'target_name': 'cflags',
'type': 'executable',
- 'opt': '-Os',
+ 'sources': [
+ 'cflags.c',
+ ],
+ },
+ {
+ 'target_name': 'cflags_host',
+ 'toolsets': ['host'],
+ 'type': 'executable',
'sources': [
'cflags.c',
],
},
],
}
--- a/media/webrtc/trunk/tools/gyp/test/cflags/gyptest-cflags.py
+++ b/media/webrtc/trunk/tools/gyp/test/cflags/gyptest-cflags.py
@@ -1,65 +1,75 @@
#!/usr/bin/env python
# Copyright (c) 2012 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.
"""
-Verifies build of an executable with C++ define specified by a gyp define, and
-the use of the environment during regeneration when the gyp file changes.
+Verifies the use of the environment during regeneration when the gyp file
+changes, specifically via build of an executable with C preprocessor
+definition specified by CFLAGS.
+
+In this test, gyp and build both run in same local environment.
"""
-import os
import TestGyp
-env_stack = []
+# CPPFLAGS works in ninja but not make; CFLAGS works in both
+FORMATS = ('make', 'ninja')
+test = TestGyp.TestGyp(formats=FORMATS)
-def PushEnv():
- env_copy = os.environ.copy()
- env_stack.append(env_copy)
+# First set CFLAGS to blank in case the platform doesn't support unsetenv.
+with TestGyp.LocalEnv({'CFLAGS': '',
+ 'GYP_CROSSCOMPILE': '1'}):
+ test.run_gyp('cflags.gyp')
+ test.build('cflags.gyp')
-def PopEnv():
- os.eniron=env_stack.pop()
+expect = """FOO not defined\n"""
+test.run_built_executable('cflags', stdout=expect)
+test.run_built_executable('cflags_host', stdout=expect)
-# Regenerating build files when a gyp file changes is currently only supported
-# by the make and Android generators.
-test = TestGyp.TestGyp(formats=['make', 'android'])
+test.sleep()
+
+with TestGyp.LocalEnv({'CFLAGS': '-DFOO=1',
+ 'GYP_CROSSCOMPILE': '1'}):
+ test.run_gyp('cflags.gyp')
+ test.build('cflags.gyp')
-try:
- PushEnv()
- os.environ['CFLAGS'] = '-O0'
+expect = """FOO defined\n"""
+test.run_built_executable('cflags', stdout=expect)
+
+# Environment variable CFLAGS shouldn't influence the flags for the host.
+expect = """FOO not defined\n"""
+test.run_built_executable('cflags_host', stdout=expect)
+
+test.sleep()
+
+with TestGyp.LocalEnv({'CFLAGS_host': '-DFOO=1',
+ 'GYP_CROSSCOMPILE': '1'}):
test.run_gyp('cflags.gyp')
-finally:
- # We clear the environ after calling gyp. When the auto-regeneration happens,
- # the same define should be reused anyway. Reset to empty string first in
- # case the platform doesn't support unsetenv.
- PopEnv()
+ test.build('cflags.gyp')
+
+# Environment variable CFLAGS_host should influence the flags for the host.
+expect = """FOO defined\n"""
+test.run_built_executable('cflags_host', stdout=expect)
-test.build('cflags.gyp')
+test.sleep()
-expect = """\
-Using no optimization flag
-"""
+with TestGyp.LocalEnv({'CFLAGS': ''}):
+ test.run_gyp('cflags.gyp')
+ test.build('cflags.gyp')
+
+expect = """FOO not defined\n"""
test.run_built_executable('cflags', stdout=expect)
test.sleep()
-try:
- PushEnv()
- os.environ['CFLAGS'] = '-O2'
+with TestGyp.LocalEnv({'CFLAGS': '-DFOO=1'}):
test.run_gyp('cflags.gyp')
-finally:
- # We clear the environ after calling gyp. When the auto-regeneration happens,
- # the same define should be reused anyway. Reset to empty string first in
- # case the platform doesn't support unsetenv.
- PopEnv()
+ test.build('cflags.gyp')
-test.build('cflags.gyp')
-
-expect = """\
-Using an optimization flag
-"""
+expect = """FOO defined\n"""
test.run_built_executable('cflags', stdout=expect)
test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/compilable/src/program.cpp
+++ b/media/webrtc/trunk/tools/gyp/test/compilable/src/program.cpp
@@ -1,9 +1,9 @@
#include <stdio.h>
#include "lib1.hpp"
-int main(int argc, char *argv[]) {
+int main(void) {
fprintf(stdout, "Hello from program.c\n");
fflush(stdout);
lib1_function();
return 0;
}
rename from media/webrtc/trunk/tools/gyp/test/compiler-override/compiler.gyp
rename to media/webrtc/trunk/tools/gyp/test/compiler-override/compiler-exe.gyp
--- a/media/webrtc/trunk/tools/gyp/test/compiler-override/compiler-host.gyp
+++ b/media/webrtc/trunk/tools/gyp/test/compiler-override/compiler-host.gyp
@@ -1,16 +1,16 @@
# Copyright (c) 2012 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': [
{
- 'toolset': 'host',
+ 'toolset': 'host',
'target_name': 'hello',
'type': 'executable',
'sources': [
'test.c',
'cxxtest.cc',
],
},
],
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/compiler-override/compiler-shared-lib.gyp
@@ -0,0 +1,16 @@
+# Copyright (c) 2012 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': 'hello-lib',
+ 'type': 'shared_library',
+ 'sources': [
+ 'test.c',
+ 'cxxtest.cc',
+ ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/compiler-override/gyptest-compiler-env-toolchain.py
@@ -0,0 +1,78 @@
+#!/usr/bin/env python
+# Copyright (c) 2012 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.
+"""
+Verifies that the user can override the compiler and linker using
+CC/CXX/NM/READELF environment variables.
+"""
+
+import TestGyp
+import os
+import copy
+import sys
+
+here = os.path.dirname(os.path.abspath(__file__))
+
+if sys.platform == 'win32':
+ # cross compiling not supported by ninja on windows
+ # and make not supported on windows at all.
+ sys.exit(0)
+
+# Clear any existing compiler related env vars.
+for key in ['CC', 'CXX', 'LINK', 'CC_host', 'CXX_host', 'LINK_host',
+ 'NM_target', 'READELF_target']:
+ if key in os.environ:
+ del os.environ[key]
+
+
+def CheckCompiler(test, gypfile, check_for, run_gyp):
+ if run_gyp:
+ test.run_gyp(gypfile)
+ test.build(gypfile)
+
+ test.must_contain_all_lines(test.stdout(), check_for)
+
+
+test = TestGyp.TestGyp(formats=['ninja'])
+# Must set the test format to something with a flavor (the part after the '-')
+# in order to test the desired behavior. Since we want to run a non-host
+# toolchain, we have to set the flavor to something that the ninja generator
+# doesn't know about, so it doesn't default to the host-specific tools (e.g.,
+# 'otool' on mac to generate the .TOC).
+#
+# Note that we can't just pass format=['ninja-some_toolchain'] to the
+# constructor above, because then this test wouldn't be recognized as a ninja
+# format test.
+test.formats = ['ninja-my_flavor' if f == 'ninja' else f for f in test.formats]
+
+
+def TestTargetOverideSharedLib():
+ # The std output from nm and readelf is redirected to files, so we can't
+ # expect their output to appear. Instead, check for the files they create to
+ # see if they actually ran.
+ expected = ['my_cc.py', 'my_cxx.py', 'FOO']
+
+ # Check that CC, CXX, NM, READELF, set target compiler
+ env = {'CC': 'python %s/my_cc.py FOO' % here,
+ 'CXX': 'python %s/my_cxx.py FOO' % here,
+ 'NM': 'python %s/my_nm.py' % here,
+ 'READELF': 'python %s/my_readelf.py' % here}
+
+ with TestGyp.LocalEnv(env):
+ CheckCompiler(test, 'compiler-shared-lib.gyp', expected, True)
+ test.must_contain(test.built_file_path('RAN_MY_NM'), 'RAN_MY_NM')
+ test.must_contain(test.built_file_path('RAN_MY_READELF'), 'RAN_MY_READELF')
+ test.unlink(test.built_file_path('RAN_MY_NM'))
+ test.unlink(test.built_file_path('RAN_MY_READELF'))
+
+ # Run the same tests once the eviron has been restored. The generated
+ # projects should have embedded all the settings in the project files so the
+ # results should be the same.
+ CheckCompiler(test, 'compiler-shared-lib.gyp', expected, False)
+ test.must_contain(test.built_file_path('RAN_MY_NM'), 'RAN_MY_NM')
+ test.must_contain(test.built_file_path('RAN_MY_READELF'), 'RAN_MY_READELF')
+
+
+TestTargetOverideSharedLib()
+test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/compiler-override/gyptest-compiler-env.py
+++ b/media/webrtc/trunk/tools/gyp/test/compiler-override/gyptest-compiler-env.py
@@ -10,46 +10,101 @@ environment variables.
import TestGyp
import os
import copy
import sys
here = os.path.dirname(os.path.abspath(__file__))
if sys.platform == 'win32':
- # cross compiling not support by ninja on windows
+ # cross compiling not supported by ninja on windows
# and make not supported on windows at all.
sys.exit(0)
+# Clear any existing compiler related env vars.
+for key in ['CC', 'CXX', 'LINK', 'CC_host', 'CXX_host', 'LINK_host']:
+ if key in os.environ:
+ del os.environ[key]
+
+
+def CheckCompiler(test, gypfile, check_for, run_gyp):
+ if run_gyp:
+ test.run_gyp(gypfile)
+ test.build(gypfile)
+
+ test.must_contain_all_lines(test.stdout(), check_for)
+
+
test = TestGyp.TestGyp(formats=['ninja', 'make'])
-def CheckCompiler(test, gypfile, check_for):
- test.run_gyp(gypfile)
- test.build(gypfile)
+def TestTargetOveride():
+ expected = ['my_cc.py', 'my_cxx.py', 'FOO' ]
- # We can't test to presence of my_ld.py in the output since
- # ninja will use CXX_target as the linker regardless
- test.must_contain_all_lines(test.stdout(), check_for)
+ # ninja just uses $CC / $CXX as linker.
+ if test.format not in ['ninja', 'xcode-ninja']:
+ expected.append('FOO_LINK')
-oldenv = os.environ.copy()
-try:
# Check that CC, CXX and LD set target compiler
- os.environ['CC'] = 'python %s/my_cc.py FOO' % here
- os.environ['CXX'] = 'python %s/my_cxx.py FOO' % here
- os.environ['LD'] = 'python %s/my_ld.py FOO_LINK' % here
- CheckCompiler(test, 'compiler.gyp',
- ['my_cc.py', 'my_cxx.py', 'FOO', 'FOO_LINK'])
-finally:
- os.environ.clear()
- os.environ.update(oldenv)
+ oldenv = os.environ.copy()
+ try:
+ os.environ['CC'] = 'python %s/my_cc.py FOO' % here
+ os.environ['CXX'] = 'python %s/my_cxx.py FOO' % here
+ os.environ['LINK'] = 'python %s/my_ld.py FOO_LINK' % here
+
+ CheckCompiler(test, 'compiler-exe.gyp', expected, True)
+ finally:
+ os.environ.clear()
+ os.environ.update(oldenv)
+
+ # Run the same tests once the eviron has been restored. The
+ # generated should have embedded all the settings in the
+ # project files so the results should be the same.
+ CheckCompiler(test, 'compiler-exe.gyp', expected, False)
+
+
+def TestTargetOverideCompilerOnly():
+ # Same test again but with that CC, CXX and not LD
+ oldenv = os.environ.copy()
+ try:
+ os.environ['CC'] = 'python %s/my_cc.py FOO' % here
+ os.environ['CXX'] = 'python %s/my_cxx.py FOO' % here
+
+ CheckCompiler(test, 'compiler-exe.gyp',
+ ['my_cc.py', 'my_cxx.py', 'FOO'],
+ True)
+ finally:
+ os.environ.clear()
+ os.environ.update(oldenv)
-try:
+ # Run the same tests once the eviron has been restored. The
+ # generated should have embedded all the settings in the
+ # project files so the results should be the same.
+ CheckCompiler(test, 'compiler-exe.gyp',
+ ['my_cc.py', 'my_cxx.py', 'FOO'],
+ False)
+
+
+def TestHostOveride():
+ expected = ['my_cc.py', 'my_cxx.py', 'HOST' ]
+ if test.format != 'ninja': # ninja just uses $CC / $CXX as linker.
+ expected.append('HOST_LINK')
+
# Check that CC_host sets host compilee
- os.environ['CC_host'] = 'python %s/my_cc.py HOST' % here
- os.environ['CXX_host'] = 'python %s/my_cxx.py HOST' % here
- os.environ['LD_host'] = 'python %s/my_ld.py HOST_LINK' % here
- CheckCompiler(test, 'compiler-host.gyp',
- ['my_cc.py', 'my_cxx.py', 'HOST', 'HOST_LINK'])
-finally:
- os.environ.clear()
- os.environ.update(oldenv)
+ oldenv = os.environ.copy()
+ try:
+ os.environ['CC_host'] = 'python %s/my_cc.py HOST' % here
+ os.environ['CXX_host'] = 'python %s/my_cxx.py HOST' % here
+ os.environ['LINK_host'] = 'python %s/my_ld.py HOST_LINK' % here
+ CheckCompiler(test, 'compiler-host.gyp', expected, True)
+ finally:
+ os.environ.clear()
+ os.environ.update(oldenv)
+
+ # Run the same tests once the eviron has been restored. The
+ # generated should have embedded all the settings in the
+ # project files so the results should be the same.
+ CheckCompiler(test, 'compiler-host.gyp', expected, False)
+
+
+TestTargetOveride()
+TestTargetOverideCompilerOnly()
test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/compiler-override/gyptest-compiler-global-settings.py
+++ b/media/webrtc/trunk/tools/gyp/test/compiler-override/gyptest-compiler-global-settings.py
@@ -29,24 +29,50 @@ replacements = { 'PYTHON': '/usr/bin/pyt
# since we need to include absolute paths in the make_global_settings
# section.
replacements['TOOLSET'] = 'target'
s = Template(open(gypfile + '.in').read())
output = open(gypfile, 'w')
output.write(s.substitute(replacements))
output.close()
+old_env = dict(os.environ)
+os.environ['GYP_CROSSCOMPILE'] = '1'
test.run_gyp(gypfile)
+os.environ.clear()
+os.environ.update(old_env)
+
test.build(gypfile)
test.must_contain_all_lines(test.stdout(), ['my_cc.py', 'my_cxx.py', 'FOO'])
+# The xcode generator chokes on the 'host' toolset. Skip the rest of
+# this test (cf. https://code.google.com/p/gyp/issues/detail?id=454).
+if test.format == 'xcode-ninja':
+ test.pass_test()
+
# Same again but with the host toolset.
replacements['TOOLSET'] = 'host'
s = Template(open(gypfile + '.in').read())
output = open(gypfile, 'w')
output.write(s.substitute(replacements))
output.close()
+old_env = dict(os.environ)
+os.environ['GYP_CROSSCOMPILE'] = '1'
test.run_gyp(gypfile)
+os.environ.clear()
+os.environ.update(old_env)
+
test.build(gypfile)
test.must_contain_all_lines(test.stdout(), ['my_cc.py', 'my_cxx.py', 'BAR'])
+# Check that CC_host overrides make_global_settings
+old_env = dict(os.environ)
+os.environ['CC_host'] = '%s %s/my_cc.py SECRET' % (replacements['PYTHON'],
+ replacements['PWD'])
+test.run_gyp(gypfile)
+os.environ.clear()
+os.environ.update(old_env)
+
+test.build(gypfile)
+test.must_contain_all_lines(test.stdout(), ['SECRET', 'my_cxx.py', 'BAR'])
+
test.pass_test()
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/compiler-override/my_nm.py
@@ -0,0 +1,8 @@
+#!/usr/bin/env python
+# Copyright (c) 2014 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.
+import sys
+print sys.argv
+with open('RAN_MY_NM', 'w') as f:
+ f.write('RAN_MY_NM')
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/compiler-override/my_readelf.py
@@ -0,0 +1,8 @@
+#!/usr/bin/env python
+# Copyright (c) 2014 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.
+import sys
+print sys.argv
+with open('RAN_MY_READELF', 'w') as f:
+ f.write('RAN_MY_READELF')
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/conditions/elseif/elseif.gyp
@@ -0,0 +1,43 @@
+# Copyright (c) 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'variables': { 'test_var': 0 },
+ 'target_name': 'program0',
+ 'type': 'executable',
+ 'sources': [ 'program.cc' ],
+ 'includes': [ 'elseif_conditions.gypi' ],
+ },
+ {
+ 'variables': { 'test_var': 1 },
+ 'target_name': 'program1',
+ 'type': 'executable',
+ 'sources': [ 'program.cc' ],
+ 'includes': [ 'elseif_conditions.gypi' ],
+ },
+ {
+ 'variables': { 'test_var': 2 },
+ 'target_name': 'program2',
+ 'type': 'executable',
+ 'sources': [ 'program.cc' ],
+ 'includes': [ 'elseif_conditions.gypi' ],
+ },
+ {
+ 'variables': { 'test_var': 3 },
+ 'target_name': 'program3',
+ 'type': 'executable',
+ 'sources': [ 'program.cc' ],
+ 'includes': [ 'elseif_conditions.gypi' ],
+ },
+ {
+ 'variables': { 'test_var': 4 },
+ 'target_name': 'program4',
+ 'type': 'executable',
+ 'sources': [ 'program.cc' ],
+ 'includes': [ 'elseif_conditions.gypi' ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/conditions/elseif/elseif_bad1.gyp
@@ -0,0 +1,20 @@
+# Copyright (c) 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Trigger an error because of two consecutive string conditions.
+
+{
+ 'targets': [
+ {
+ 'variables': { 'test_var': 0 },
+ 'target_name': 'program',
+ 'type': 'executable',
+ 'sources': [ 'program.cc' ],
+ 'conditions': [
+ ['test_var==0', 'test_var==1', {
+ }],
+ ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/conditions/elseif/elseif_bad2.gyp
@@ -0,0 +1,22 @@
+# Copyright (c) 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Trigger an error because of two consecutive string conditions, even if the
+# conditions are not actually evaluated.
+
+{
+ 'targets': [
+ {
+ 'variables': { 'test_var': 0 },
+ 'target_name': 'program',
+ 'type': 'executable',
+ 'sources': [ 'program.cc' ],
+ 'conditions': [
+ ['test_var==0', {
+ }, 'test_var==1', 'test_var==2', {
+ }],
+ ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/conditions/elseif/elseif_bad3.gyp
@@ -0,0 +1,23 @@
+# Copyright (c) 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Trigger an error because there are unexpected trailing items in a condition.
+
+{
+ 'targets': [
+ {
+ 'variables': { 'test_var': 0 },
+ 'target_name': 'program',
+ 'type': 'executable',
+ 'sources': [ 'program.cc' ],
+ 'conditions': [
+ ['test_var==0' {
+ }, 'test_var==1', {
+ }, {
+ }, 'test_var==2', {
+ }],
+ ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/conditions/elseif/elseif_conditions.gypi
@@ -0,0 +1,15 @@
+{
+ 'conditions': [
+ ['test_var==0', {
+ 'defines': ['FOO="first_if"'],
+ }, 'test_var==1', {
+ 'defines': ['FOO="first_else_if"'],
+ }, 'test_var==2', {
+ 'defines': ['FOO="second_else_if"'],
+ }, 'test_var==3', {
+ 'defines': ['FOO="third_else_if"'],
+ }, {
+ 'defines': ['FOO="last_else"'],
+ }],
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/conditions/elseif/gyptest_elseif.py
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 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 "else-if" conditions work.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('elseif.gyp')
+test.build('elseif.gyp', test.ALL)
+test.run_built_executable(
+ 'program0', stdout='first_if\n')
+test.run_built_executable(
+ 'program1', stdout='first_else_if\n')
+test.run_built_executable(
+ 'program2', stdout='second_else_if\n')
+test.run_built_executable(
+ 'program3', stdout='third_else_if\n')
+test.run_built_executable(
+ 'program4', stdout='last_else\n')
+
+# Verify that bad condition blocks fail at gyp time.
+test.run_gyp('elseif_bad1.gyp', status=1, stderr=None)
+test.run_gyp('elseif_bad2.gyp', status=1, stderr=None)
+test.run_gyp('elseif_bad3.gyp', status=1, stderr=None)
+
+test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/conditions/elseif/program.cc
@@ -0,0 +1,10 @@
+// Copyright (c) 2014 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>
+
+int main() {
+ printf("%s\n", FOO);
+ return 0;
+}
--- a/media/webrtc/trunk/tools/gyp/test/configurations/basics/configurations.c
+++ b/media/webrtc/trunk/tools/gyp/test/configurations/basics/configurations.c
@@ -1,11 +1,11 @@
#include <stdio.h>
-int main(int argc, char *argv[])
+int main(void)
{
#ifdef FOO
printf("Foo configuration\n");
#endif
#ifdef DEBUG
printf("Debug configuration\n");
#endif
#ifdef RELEASE
--- a/media/webrtc/trunk/tools/gyp/test/configurations/inheritance/configurations.c
+++ b/media/webrtc/trunk/tools/gyp/test/configurations/inheritance/configurations.c
@@ -1,11 +1,11 @@
#include <stdio.h>
-int main(int argc, char *argv[])
+int main(void)
{
#ifdef BASE
printf("Base configuration\n");
#endif
#ifdef COMMON
printf("Common configuration\n");
#endif
#ifdef COMMON2
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/configurations/inheritance/duplicates.gyp
@@ -0,0 +1,27 @@
+# Copyright 2014 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.
+
+{
+ 'target_defaults': {
+ 'default_configuration': 'A',
+ 'configurations': {
+ 'A': {
+ 'defines': ['SOMETHING'],
+ },
+ 'B': {
+ 'inherit_from': ['A'],
+ },
+ },
+ 'cflags': ['-g'],
+ },
+ 'targets': [
+ {
+ 'target_name': 'configurations',
+ 'type': 'executable',
+ 'sources': [
+ 'configurations.c',
+ ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/configurations/inheritance/duplicates.gypd.golden
@@ -0,0 +1,12 @@
+{'_DEPTH': '.',
+ 'included_files': ['duplicates.gyp'],
+ 'targets': [{'configurations': {'A': {'cflags': ['-g'],
+ 'defines': ['SOMETHING']},
+ 'B': {'cflags': ['-g'],
+ 'defines': ['SOMETHING'],
+ 'inherit_from': ['A']}},
+ 'default_configuration': 'A',
+ 'sources': ['configurations.c'],
+ 'target_name': 'configurations',
+ 'toolset': 'target',
+ 'type': 'executable'}]}
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/configurations/inheritance/gyptest-duplicates.py
@@ -0,0 +1,34 @@
+#!/usr/bin/env python
+
+# Copyright 2014 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.
+
+"""
+Verifies that configurations do not duplicate other settings.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp(format='gypd')
+
+test.run_gyp('duplicates.gyp')
+
+# Verify the duplicates.gypd against the checked-in expected contents.
+#
+# Normally, we should canonicalize line endings in the expected
+# contents file setting the Subversion svn:eol-style to native,
+# but that would still fail if multiple systems are sharing a single
+# workspace on a network-mounted file system. Consequently, we
+# massage the Windows line endings ('\r\n') in the output to the
+# checked-in UNIX endings ('\n').
+
+contents = test.read('duplicates.gypd').replace(
+ '\r', '').replace('\\\\', '/')
+expect = test.read('duplicates.gypd.golden').replace('\r', '')
+if not test.match(contents, expect):
+ print "Unexpected contents of `duplicates.gypd'"
+ test.diff(expect, contents, 'duplicates.gypd ')
+ test.fail_test()
+
+test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/configurations/invalid/gyptest-configurations.py
+++ b/media/webrtc/trunk/tools/gyp/test/configurations/invalid/gyptest-configurations.py
@@ -22,18 +22,15 @@ invalid_configuration_keys = [
'sources',
'standalone_static_library',
'target_name',
'type',
]
test = TestGyp.TestGyp()
-if test.format == 'scons':
- test.skip_test('TODO: http://code.google.com/p/gyp/issues/detail?id=176\n')
-
for test_key in invalid_configuration_keys:
test.run_gyp('%s.gyp' % test_key, status=1, stderr=None)
expect = ['%s not allowed in the Debug configuration, found in target '
'%s.gyp:configurations#target' % (test_key, test_key)]
test.must_contain_all_lines(test.stderr(), expect)
test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/configurations/invalid/standalone_static_library.gyp
@@ -0,0 +1,17 @@
+# Copyright (c) 2012 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': 'configurations',
+ 'type': 'none',
+ 'configurations': {
+ 'Debug': {
+ 'standalone_static_library': 1,
+ },
+ }
+ },
+ ],
+}
--- a/media/webrtc/trunk/tools/gyp/test/configurations/target_platform/front.c
+++ b/media/webrtc/trunk/tools/gyp/test/configurations/target_platform/front.c
@@ -1,8 +1,8 @@
#include <stdio.h>
const char *message(void);
-int main(int argc, char *argv[]) {
+int main(void) {
printf("%s\n", message());
return 0;
}
--- a/media/webrtc/trunk/tools/gyp/test/configurations/x64/configurations.c
+++ b/media/webrtc/trunk/tools/gyp/test/configurations/x64/configurations.c
@@ -1,11 +1,11 @@
#include <stdio.h>
-int main(int argc, char *argv[]) {
+int main(void) {
if (sizeof(void*) == 4) {
printf("Running Win32\n");
} else if (sizeof(void*) == 8) {
printf("Running x64\n");
} else {
printf("Unexpected platform\n");
}
return 0;
--- a/media/webrtc/trunk/tools/gyp/test/copies/gyptest-all.py
+++ b/media/webrtc/trunk/tools/gyp/test/copies/gyptest-all.py
@@ -7,17 +7,19 @@
"""
Verifies file copies using an explicit build target of 'all'.
"""
import TestGyp
test = TestGyp.TestGyp()
-test.run_gyp('copies.gyp', chdir='src')
+test.run_gyp('copies.gyp',
+ '-G', 'xcode_ninja_target_pattern=^(?!copies_null)',
+ chdir='src')
test.relocate('src', 'relocate/src')
test.build('copies.gyp', test.ALL, chdir='relocate/src')
test.must_match(['relocate', 'src', 'copies-out', 'file1'], 'file1 contents\n')
test.built_file_must_match('copies-out/file2',
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/copies/gyptest-attribs.py
@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 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.
+
+"""
+Verifies that copying files preserves file attributes.
+"""
+
+import TestGyp
+
+import os
+import stat
+import sys
+
+
+def check_attribs(path, expected_exec_bit):
+ out_path = test.built_file_path(path, chdir='src')
+
+ in_stat = os.stat(os.path.join('src', path))
+ out_stat = os.stat(out_path)
+ if out_stat.st_mode & stat.S_IXUSR != expected_exec_bit:
+ test.fail_test()
+
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('copies-attribs.gyp', chdir='src')
+
+test.build('copies-attribs.gyp', chdir='src')
+
+if sys.platform != 'win32':
+ out_path = test.built_file_path('executable-file.sh', chdir='src')
+ test.must_contain(out_path,
+ '#!/bin/bash\n'
+ '\n'
+ 'echo echo echo echo cho ho o o\n')
+ check_attribs('executable-file.sh', expected_exec_bit=stat.S_IXUSR)
+
+test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/copies/gyptest-default.py
+++ b/media/webrtc/trunk/tools/gyp/test/copies/gyptest-default.py
@@ -7,17 +7,19 @@
"""
Verifies file copies using the build tool default.
"""
import TestGyp
test = TestGyp.TestGyp()
-test.run_gyp('copies.gyp', chdir='src')
+test.run_gyp('copies.gyp',
+ '-G', 'xcode_ninja_target_pattern=^(?!copies_null)',
+ chdir='src')
test.relocate('src', 'relocate/src')
test.build('copies.gyp', chdir='relocate/src')
test.must_match(['relocate', 'src', 'copies-out', 'file1'], 'file1 contents\n')
test.built_file_must_match('copies-out/file2',
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/copies/gyptest-samedir.py
@@ -0,0 +1,28 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 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.
+
+"""
+Verifies file copies where two copies sections in the same target have the
+same destination directory.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+test.run_gyp('copies-samedir.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+test.build('copies-samedir.gyp', 'copies_samedir', chdir='relocate/src')
+
+test.built_file_must_match('copies-out-samedir/file1',
+ 'file1 contents\n',
+ chdir='relocate/src')
+
+test.built_file_must_match('copies-out-samedir/file2',
+ 'file2 contents\n',
+ chdir='relocate/src')
+
+test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/copies/gyptest-slash.py
+++ b/media/webrtc/trunk/tools/gyp/test/copies/gyptest-slash.py
@@ -7,16 +7,17 @@
"""
Verifies file copies with a trailing slash in the destination directory.
"""
import TestGyp
test = TestGyp.TestGyp()
test.run_gyp('copies-slash.gyp', chdir='src')
+
test.relocate('src', 'relocate/src')
test.build('copies-slash.gyp', chdir='relocate/src')
test.built_file_must_match('copies-out-slash/directory/file3',
'file3 contents\n',
chdir='relocate/src')
test.built_file_must_match('copies-out-slash/directory/file4',
'file4 contents\n',
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/copies/gyptest-sourceless-shared-lib.py
@@ -0,0 +1,20 @@
+#!/usr/bin/env python
+
+# 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.
+
+"""
+Verifies copies in sourceless shared_library targets are executed.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+test.run_gyp('copies-sourceless-shared-lib.gyp', chdir='src')
+test.relocate('src', 'relocate/src')
+test.build('copies-sourceless-shared-lib.gyp', chdir='relocate/src')
+test.built_file_must_match('copies-out/file1',
+ 'file1 contents\n',
+ chdir='relocate/src')
+test.pass_test()
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/copies/gyptest-updir.py
@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 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.
+
+"""
+Verifies file copies where the destination is one level above an expansion that
+yields a make variable.
+"""
+
+import sys
+
+import TestGyp
+
+if sys.platform == 'darwin':
+ print "This test is currently disabled: https://crbug.com/483696."
+ sys.exit(0)
+
+test = TestGyp.TestGyp()
+test.run_gyp('copies-updir.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+test.build('copies-updir.gyp', 'copies_up', chdir='relocate/src')
+
+test.built_file_must_match('../copies-out-updir/file1',
+ 'file1 contents\n',
+ chdir='relocate/src')
+
+test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/copies/src/copies-attribs.gyp
@@ -0,0 +1,20 @@
+# Copyright (c) 2013 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': 'copies1',
+ 'type': 'none',
+ 'copies': [
+ {
+ 'destination': '<(PRODUCT_DIR)',
+ 'files': [
+ 'executable-file.sh',
+ ],
+ },
+ ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/copies/src/copies-samedir.gyp
@@ -0,0 +1,37 @@
+# Copyright (c) 2013 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': 'copies_samedir',
+ 'type': 'none',
+ 'dependencies': [
+ 'copies_samedir_dependency',
+ ],
+ 'copies': [
+ {
+ 'destination': '<(PRODUCT_DIR)/copies-out-samedir',
+ 'files': [
+ 'file1',
+ ],
+ },
+ ],
+ },
+ {
+ 'target_name': 'copies_samedir_dependency',
+ 'type': 'none',
+ 'direct_dependent_settings': {
+ 'copies': [
+ {
+ 'destination': '<(PRODUCT_DIR)/copies-out-samedir',
+ 'files': [
+ 'file2',
+ ],
+ },
+ ],
+ },
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/copies/src/copies-sourceless-shared-lib.gyp
@@ -0,0 +1,27 @@
+# Copyright (c) 2015 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': 'mylib',
+ 'type': 'static_library',
+ 'sources': [ 'foo.c' ],
+ },
+ {
+ 'target_name': 'mysolib',
+ 'type': 'shared_library',
+ 'dependencies': [ 'mylib' ],
+ 'copies': [
+ {
+ 'destination': '<(PRODUCT_DIR)/copies-out',
+ 'files': [ 'file1' ],
+ },
+ ],
+ # link.exe gets confused by sourceless shared libraries and needs this
+ # to become unconfused.
+ 'msvs_settings': { 'VCLinkerTool': { 'TargetMachine': '1', }, },
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/copies/src/copies-updir.gyp
@@ -0,0 +1,21 @@
+# Copyright (c) 2012 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': 'copies_up',
+ 'type': 'none',
+ 'copies': [
+ {
+ 'destination': '<(PRODUCT_DIR)/../copies-out-updir',
+ 'files': [
+ 'file1',
+ ],
+ },
+ ],
+ },
+ ],
+}
+
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/copies/src/executable-file.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+echo echo echo echo cho ho o o
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/copies/src/foo.c
@@ -0,0 +1,13 @@
+// Copyright (c) 2015 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 f() { return 42; }
+
+#ifdef _MSC_VER
+// link.exe gets confused by sourceless shared libraries and needs this
+// to become unconfused.
+int __stdcall _DllMainCRTStartup(
+ unsigned hInst, unsigned reason, void* reserved) {
+ return 1;
+}
+#endif
--- a/media/webrtc/trunk/tools/gyp/test/cxxflags/cxxflags.cc
+++ b/media/webrtc/trunk/tools/gyp/test/cxxflags/cxxflags.cc
@@ -1,15 +1,15 @@
/* Copyright (c) 2010 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>
-int main(int argc, char *argv[])
+int main(void)
{
-#ifdef __OPTIMIZE__
- printf("Using an optimization flag\n");
+#ifdef ABC
+ printf("With define\n");
#else
- printf("Using no optimization flag\n");
+ printf("No define\n");
#endif
return 0;
}
--- a/media/webrtc/trunk/tools/gyp/test/cxxflags/cxxflags.gyp
+++ b/media/webrtc/trunk/tools/gyp/test/cxxflags/cxxflags.gyp
@@ -2,15 +2,14 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
{
'targets': [
{
'target_name': 'cxxflags',
'type': 'executable',
- 'opt': '-Os',
'sources': [
'cxxflags.cc',
],
},
],
}
--- a/media/webrtc/trunk/tools/gyp/test/cxxflags/gyptest-cxxflags.py
+++ b/media/webrtc/trunk/tools/gyp/test/cxxflags/gyptest-cxxflags.py
@@ -1,65 +1,45 @@
#!/usr/bin/env python
# Copyright (c) 2012 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.
"""
-Verifies build of an executable with C++ define specified by a gyp define, and
-the use of the environment during regeneration when the gyp file changes.
+Verifies the use of the environment during regeneration when the gyp file
+changes, specifically via build of an executable with C++ flags specified by
+CXXFLAGS.
+
+In this test, gyp happens within a local environment, but build outside of it.
"""
-import os
import TestGyp
-env_stack = []
-
+FORMATS = ('ninja',)
-def PushEnv():
- env_copy = os.environ.copy()
- env_stack.append(env_copy)
-
-def PopEnv():
- os.eniron=env_stack.pop()
+test = TestGyp.TestGyp(formats=FORMATS)
-# Regenerating build files when a gyp file changes is currently only supported
-# by the make and Android generators.
-test = TestGyp.TestGyp(formats=['make', 'android'])
-
-try:
- PushEnv()
- os.environ['CXXFLAGS'] = '-O0'
+# We reset the environ after calling gyp. When the auto-regeneration happens,
+# the same define should be reused anyway.
+with TestGyp.LocalEnv({'CXXFLAGS': ''}):
test.run_gyp('cxxflags.gyp')
-finally:
- # We clear the environ after calling gyp. When the auto-regeneration happens,
- # the same define should be reused anyway. Reset to empty string first in
- # case the platform doesn't support unsetenv.
- PopEnv()
test.build('cxxflags.gyp')
expect = """\
-Using no optimization flag
+No define
"""
test.run_built_executable('cxxflags', stdout=expect)
test.sleep()
-try:
- PushEnv()
- os.environ['CXXFLAGS'] = '-O2'
+with TestGyp.LocalEnv({'CXXFLAGS': '-DABC'}):
test.run_gyp('cxxflags.gyp')
-finally:
- # We clear the environ after calling gyp. When the auto-regeneration happens,
- # the same define should be reused anyway. Reset to empty string first in
- # case the platform doesn't support unsetenv.
- PopEnv()
test.build('cxxflags.gyp')
expect = """\
-Using an optimization flag
+With define
"""
test.run_built_executable('cxxflags', stdout=expect)
test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/defines-escaping/defines-escaping.c
+++ b/media/webrtc/trunk/tools/gyp/test/defines-escaping/defines-escaping.c
@@ -1,11 +1,11 @@
/* Copyright (c) 2010 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>
-int main(int argc, char *argv[])
+int main(void)
{
printf(TEST_FORMAT, TEST_ARGS);
return 0;
}
--- a/media/webrtc/trunk/tools/gyp/test/defines/defines.c
+++ b/media/webrtc/trunk/tools/gyp/test/defines/defines.c
@@ -1,15 +1,15 @@
/* 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>
-int main(int argc, char *argv[])
+int main(void)
{
#ifdef FOO
printf("FOO is defined\n");
#endif
printf("VALUE is %d\n", VALUE);
#ifdef PAREN_VALUE
printf("2*PAREN_VALUE is %d\n", 2*PAREN_VALUE);
--- a/media/webrtc/trunk/tools/gyp/test/defines/gyptest-define-override.py
+++ b/media/webrtc/trunk/tools/gyp/test/defines/gyptest-define-override.py
@@ -8,27 +8,36 @@
Verifies that a default gyp define can be overridden.
"""
import os
import TestGyp
test = TestGyp.TestGyp()
+# CMake loudly warns about passing '#' to the compiler and drops the define.
+expect_stderr = ''
+if test.format == 'cmake':
+ expect_stderr = (
+"""WARNING: Preprocessor definitions containing '#' may not be passed on the"""
+""" compiler command line because many compilers do not support it.\n"""
+"""CMake is dropping a preprocessor definition: HASH_VALUE="a#1"\n"""
+"""Consider defining the macro in a (configured) header file.\n\n""")
+
# Command-line define
test.run_gyp('defines.gyp', '-D', 'OS=fakeos')
-test.build('defines.gyp')
+test.build('defines.gyp', stderr=expect_stderr)
test.built_file_must_exist('fakeosprogram', type=test.EXECUTABLE)
# Clean up the exe so subsequent tests don't find an old exe.
os.remove(test.built_file_path('fakeosprogram', type=test.EXECUTABLE))
# Without "OS" override, fokeosprogram shouldn't be built.
test.run_gyp('defines.gyp')
-test.build('defines.gyp')
+test.build('defines.gyp', stderr=expect_stderr)
test.built_file_must_not_exist('fakeosprogram', type=test.EXECUTABLE)
# Environment define
os.environ['GYP_DEFINES'] = 'OS=fakeos'
test.run_gyp('defines.gyp')
-test.build('defines.gyp')
+test.build('defines.gyp', stderr=expect_stderr)
test.built_file_must_exist('fakeosprogram', type=test.EXECUTABLE)
test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/defines/gyptest-defines-env-regyp.py
+++ b/media/webrtc/trunk/tools/gyp/test/defines/gyptest-defines-env-regyp.py
@@ -8,18 +8,18 @@
Verifies build of an executable with C++ define specified by a gyp define, and
the use of the environment during regeneration when the gyp file changes.
"""
import os
import TestGyp
# Regenerating build files when a gyp file changes is currently only supported
-# by the make and Android generators.
-test = TestGyp.TestGyp(formats=['make', 'android'])
+# by the make generator.
+test = TestGyp.TestGyp(formats=['make'])
try:
os.environ['GYP_DEFINES'] = 'value=50'
test.run_gyp('defines.gyp')
finally:
# We clear the environ after calling gyp. When the auto-regeneration happens,
# the same define should be reused anyway. Reset to empty string first in
# case the platform doesn't support unsetenv.
--- a/media/webrtc/trunk/tools/gyp/test/defines/gyptest-defines.py
+++ b/media/webrtc/trunk/tools/gyp/test/defines/gyptest-defines.py
@@ -9,19 +9,31 @@ Verifies build of an executable with C++
"""
import TestGyp
test = TestGyp.TestGyp()
test.run_gyp('defines.gyp')
-test.build('defines.gyp')
-
expect = """\
FOO is defined
VALUE is 1
2*PAREN_VALUE is 12
-HASH_VALUE is a#1
"""
+
+#CMake loudly warns about passing '#' to the compiler and drops the define.
+expect_stderr = ''
+if test.format == 'cmake':
+ expect_stderr = (
+"""WARNING: Preprocessor definitions containing '#' may not be passed on the"""
+""" compiler command line because many compilers do not support it.\n"""
+"""CMake is dropping a preprocessor definition: HASH_VALUE="a#1"\n"""
+"""Consider defining the macro in a (configured) header file.\n\n""")
+else:
+ expect += """HASH_VALUE is a#1
+"""
+
+test.build('defines.gyp', stderr=expect_stderr)
+
test.run_built_executable('defines', stdout=expect)
test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/dependencies/adso/all_dependent_settings_order.gyp
@@ -0,0 +1,45 @@
+{
+ 'targets': [
+ {
+ 'target_name': 'a',
+ 'type': 'none',
+ 'sources': ['a.cc'],
+ 'all_dependent_settings': {'sources': ['a.cc']},
+ },
+ {
+ 'target_name': 'b',
+ 'type': 'none',
+ 'sources': ['b.cc'],
+ 'all_dependent_settings': {'sources': ['b.cc']},
+ 'dependencies': ['a'],
+ },
+
+ {
+ 'target_name': 'c',
+ 'type': 'none',
+ 'sources': ['c.cc'],
+ 'all_dependent_settings': {'sources': ['c.cc']},
+ 'dependencies': ['b', 'a'],
+ },
+ {
+ 'target_name': 'd',
+ 'type': 'none',
+ 'sources': ['d.cc'],
+ 'dependencies': ['c', 'a', 'b'],
+ 'actions': [
+ {
+ 'action_name': 'write_sources',
+ 'inputs': ['write_args.py'],
+ 'outputs': ['<(PRODUCT_DIR)/out.txt'],
+ 'action': [
+ 'python',
+ 'write_args.py',
+ '<(PRODUCT_DIR)/out.txt',
+ '>@(_sources)'
+ ],
+ 'msvs_cygwin_shell': 0,
+ },
+ ],
+ },
+ ],
+}
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/dependencies/adso/write_args.py
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+
+# Copyright 2015 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.
+
+import sys
+
+f = open(sys.argv[1], 'wb')
+f.write(' '.join(sys.argv[2:]))
+f.close()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/dependencies/gyptest-all-dependent-settings-order.py
@@ -0,0 +1,19 @@
+#!/usr/bin/env python
+
+# Copyright 2015 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.
+
+"""
+Tests that all_dependent_settings are processed in topological order.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('all_dependent_settings_order.gyp', chdir='adso')
+test.build('all_dependent_settings_order.gyp', chdir='adso')
+test.built_file_must_match('out.txt', 'd.cc a.cc b.cc c.cc',
+ chdir='adso')
+test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/dependencies/gyptest-extra-targets.py
+++ b/media/webrtc/trunk/tools/gyp/test/dependencies/gyptest-extra-targets.py
@@ -7,15 +7,16 @@
"""
Verify that dependencies don't pull unused targets into the build.
"""
import TestGyp
test = TestGyp.TestGyp()
-test.run_gyp('extra_targets.gyp')
+test.run_gyp('extra_targets.gyp',
+ '-G', 'xcode_ninja_target_pattern=^a$')
# This should fail if it tries to build 'c_unused' since 'c/c.c' has a syntax
# error and won't compile.
test.build('extra_targets.gyp', test.ALL)
test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/dependencies/gyptest-indirect-module-dependency.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2015 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.
+
+"""
+Make sure that we cause downstream modules to get built when we depend on the
+parent targets.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+CHDIR = 'module-dep'
+test.run_gyp('indirect-module-dependency.gyp', chdir=CHDIR)
+test.build('indirect-module-dependency.gyp', 'an_exe', chdir=CHDIR)
+test.built_file_must_exist(
+ test.built_file_basename('a_module', test.LOADABLE_MODULE), chdir=CHDIR)
+
+test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/dependencies/gyptest-lib-only.py
+++ b/media/webrtc/trunk/tools/gyp/test/dependencies/gyptest-lib-only.py
@@ -18,22 +18,22 @@ test = TestGyp.TestGyp()
test.run_gyp('lib_only.gyp')
test.build('lib_only.gyp', test.ALL)
test.built_file_must_exist('a', type=test.STATIC_LIB)
# TODO(bradnelson/mark):
# On linux and windows a library target will at least pull its link dependencies
-# into the generated sln/_main.scons, since not doing so confuses users.
+# into the generated project, since not doing so confuses users.
# This is not currently implemented on mac, which has the opposite behavior.
if sys.platform == 'darwin':
if test.format == 'xcode':
test.built_file_must_not_exist('b', type=test.STATIC_LIB)
else:
- assert test.format in ('make', 'ninja')
+ assert test.format in ('make', 'ninja', 'xcode-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;
# for the 'b' library, that is in the 'b' subdirectory.
test.built_file_must_exist('b', type=test.STATIC_LIB, subdir='b')
test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/dependencies/gyptest-sharedlib-linksettings.py
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 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 link_settings in a shared_library are not propagated to targets
+that depend on the shared_library, but are used in the shared_library itself.
+"""
+
+import TestGyp
+import sys
+
+CHDIR='sharedlib-linksettings'
+
+test = TestGyp.TestGyp()
+test.run_gyp('test.gyp', chdir=CHDIR)
+test.build('test.gyp', test.ALL, chdir=CHDIR)
+test.run_built_executable('program', stdout="1\n2\n", chdir=CHDIR)
+test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/dependencies/module-dep/a.cc
@@ -0,0 +1,7 @@
+// Copyright (c) 2015 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 some_function() {
+ return 0;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/dependencies/module-dep/dll.cc
@@ -0,0 +1,9 @@
+// Copyright (c) 2015 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.
+
+#if defined(_MSC_VER)
+__declspec(dllexport)
+#endif
+ void SomeFunction() {
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/dependencies/module-dep/exe.cc
@@ -0,0 +1,7 @@
+// Copyright (c) 2015 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 main() {
+ return 0;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/dependencies/module-dep/indirect-module-dependency.gyp
@@ -0,0 +1,37 @@
+# Copyright (c) 2015 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': 'an_exe',
+ 'type': 'executable',
+ 'sources': ['exe.cc'],
+ 'dependencies': [
+ 'a_dll',
+ ],
+ },
+ {
+ 'target_name': 'a_dll',
+ 'type': 'shared_library',
+ 'sources': ['dll.cc'],
+ 'dependencies': [
+ 'a_lib',
+ ],
+ },
+ {
+ 'target_name': 'a_lib',
+ 'type': 'static_library',
+ 'dependencies': [
+ 'a_module',
+ ],
+ 'sources': ['a.cc'],
+ },
+ {
+ 'target_name': 'a_module',
+ 'type': 'loadable_module',
+ 'sources': ['a.cc'],
+ },
+ ]
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/dependencies/sharedlib-linksettings/program.c
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2013 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>
+
+/*
+ * This will fail to compile if TEST_DEFINE was propagated from sharedlib to
+ * program.
+ */
+#ifdef TEST_DEFINE
+#error TEST_DEFINE is already defined!
+#endif
+
+#define TEST_DEFINE 2
+
+extern int staticLibFunc();
+
+int main() {
+ printf("%d\n", staticLibFunc());
+ printf("%d\n", TEST_DEFINE);
+ return 0;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/dependencies/sharedlib-linksettings/sharedlib.c
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2013 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.
+ */
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sharedLibFunc() {
+ /*
+ * This will fail to compile if TEST_DEFINE was not obtained from sharedlib's
+ * link_settings.
+ */
+ return TEST_DEFINE;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/dependencies/sharedlib-linksettings/staticlib.c
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2013 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.
+ */
+
+/*
+ * This will fail to compile if TEST_DEFINE was propagated from sharedlib to
+ * staticlib.
+ */
+#ifdef TEST_DEFINE
+#error TEST_DEFINE is defined!
+#endif
+
+#ifdef _WIN32
+__declspec(dllimport)
+#else
+extern
+#endif
+int sharedLibFunc();
+
+int staticLibFunc() {
+ return sharedLibFunc();
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/dependencies/sharedlib-linksettings/test.gyp
@@ -0,0 +1,37 @@
+# Copyright (c) 2013 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.
+
+{
+ 'target_defaults': {
+ 'allow_sharedlib_linksettings_propagation': 0,
+ },
+ 'targets': [
+ {
+ 'target_name': 'sharedlib',
+ 'type': 'shared_library',
+ 'sources': [ 'sharedlib.c' ],
+ 'link_settings': {
+ 'defines': [ 'TEST_DEFINE=1' ],
+ },
+ 'conditions': [
+ ['OS=="linux"', {
+ # Support 64-bit shared libs (also works fine for 32-bit).
+ 'cflags': ['-fPIC'],
+ }],
+ ],
+ },
+ {
+ 'target_name': 'staticlib',
+ 'type': 'static_library',
+ 'sources': [ 'staticlib.c' ],
+ 'dependencies': [ 'sharedlib' ],
+ },
+ {
+ 'target_name': 'program',
+ 'type': 'executable',
+ 'sources': [ 'program.c' ],
+ 'dependencies': [ 'staticlib' ],
+ },
+ ],
+}
--- a/media/webrtc/trunk/tools/gyp/test/dependency-copy/src/file1.c
+++ b/media/webrtc/trunk/tools/gyp/test/dependency-copy/src/file1.c
@@ -1,7 +1,7 @@
#include <stdio.h>
-int main(int argc, char *argv[])
+int main(void)
{
printf("Hello from file1.c\n");
return 0;
}
--- a/media/webrtc/trunk/tools/gyp/test/dependency-copy/src/file2.c
+++ b/media/webrtc/trunk/tools/gyp/test/dependency-copy/src/file2.c
@@ -1,7 +1,7 @@
#include <stdio.h>
-int main(int argc, char *argv[])
+int main(void)
{
printf("Hello from file2.c\n");
return 0;
}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/determinism/determinism.gyp
@@ -0,0 +1,59 @@
+# Copyright (c) 2015 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': 'determinism',
+ 'type': 'none',
+ 'actions': [
+ {
+ 'action_name': 'depfile_action',
+ 'inputs': [
+ 'input.txt',
+ ],
+ 'outputs': [
+ 'output.txt',
+ ],
+ 'depfile': 'depfile.d',
+ 'action': [ ]
+ },
+ ],
+ },
+ {
+ 'target_name': 'determinism2',
+ 'type': 'none',
+ 'actions': [
+ {
+ 'action_name': 'depfile_action',
+ 'inputs': [
+ 'input.txt',
+ ],
+ 'outputs': [
+ 'output.txt',
+ ],
+ 'depfile': 'depfile.d',
+ 'action': [ ]
+ },
+ ],
+ },
+ {
+ 'target_name': 'determinism3',
+ 'type': 'none',
+ 'actions': [
+ {
+ 'action_name': 'depfile_action',
+ 'inputs': [
+ 'input.txt',
+ ],
+ 'outputs': [
+ 'output.txt',
+ ],
+ 'depfile': 'depfile.d',
+ 'action': [ ]
+ },
+ ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/determinism/empty-targets.gyp
@@ -0,0 +1,32 @@
+# Copyright (c) 2015 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': 'empty_target1',
+ 'type': 'none',
+ },
+ {
+ 'target_name': 'empty_target2',
+ 'type': 'none',
+ },
+ {
+ 'target_name': 'empty_target3',
+ 'type': 'none',
+ },
+ {
+ 'target_name': 'empty_target4',
+ 'type': 'none',
+ },
+ {
+ 'target_name': 'empty_target5',
+ 'type': 'none',
+ },
+ {
+ 'target_name': 'empty_target6',
+ 'type': 'none',
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/determinism/gyptest-determinism.py
@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2015 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.
+
+"""
+Verifies builds are the same even with different PYTHONHASHSEEDs.
+Tests target_short_names and FlattenToList.
+"""
+
+import os
+import sys
+import TestGyp
+
+test = TestGyp.TestGyp()
+if test.format == 'ninja':
+ os.environ["PYTHONHASHSEED"] = "1"
+ test.run_gyp('determinism.gyp')
+ base = open(test.built_file_path('build.ninja')).read()
+
+ for i in range(1,5):
+ os.environ["PYTHONHASHSEED"] = str(i)
+ test.run_gyp('determinism.gyp')
+ contents = open(test.built_file_path('build.ninja')).read()
+ if base != contents:
+ test.fail_test()
+
+ del os.environ["PYTHONHASHSEED"]
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/determinism/gyptest-empty-target-names.py
@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2015 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.
+
+"""
+Verifies builds are the same even with different PYTHONHASHSEEDs.
+Tests both solibs and implicit_deps.
+"""
+
+import os
+import sys
+import TestGyp
+
+test = TestGyp.TestGyp()
+if test.format == 'ninja':
+ os.environ["PYTHONHASHSEED"] = "1"
+ test.run_gyp('empty-targets.gyp')
+ base = open(test.built_file_path('build.ninja')).read()
+
+ for i in range(1,5):
+ os.environ["PYTHONHASHSEED"] = str(i)
+ test.run_gyp('empty-targets.gyp')
+ contents = open(test.built_file_path('build.ninja')).read()
+ if base != contents:
+ test.fail_test()
+
+ del os.environ["PYTHONHASHSEED"]
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/determinism/gyptest-needed-variables.py
@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2015 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.
+
+"""
+Verifies builds are the same even with different PYTHONHASHSEEDs.
+Tests needed_variables.
+"""
+
+import os
+import sys
+import TestGyp
+
+test = TestGyp.TestGyp()
+if test.format == 'ninja':
+ os.environ["PYTHONHASHSEED"] = "1"
+ test.run_gyp('needed-variables.gyp')
+ base = open(test.built_file_path('test.ninja', subdir='obj')).read()
+
+ for i in range(1,5):
+ os.environ["PYTHONHASHSEED"] = str(i)
+ test.run_gyp('needed-variables.gyp')
+ contents = open(test.built_file_path('test.ninja', subdir='obj')).read()
+ if base != contents:
+ test.fail_test()
+
+ del os.environ["PYTHONHASHSEED"]
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/determinism/gyptest-solibs.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2015 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.
+
+"""
+Verifies builds are the same even with different PYTHONHASHSEEDs.
+Tests all_targets, implicit_deps and solibs.
+"""
+
+import os
+import sys
+import TestGyp
+
+test = TestGyp.TestGyp()
+if test.format == 'ninja':
+ os.environ["PYTHONHASHSEED"] = "1"
+ test.run_gyp('solibs.gyp')
+ base1 = open(test.built_file_path('c.ninja', subdir='obj')).read()
+ base2 = open(test.built_file_path('build.ninja')).read()
+
+ for i in range(1,5):
+ os.environ["PYTHONHASHSEED"] = str(i)
+ test.run_gyp('solibs.gyp')
+ contents1 = open(test.built_file_path('c.ninja', subdir='obj')).read()
+ contents2 = open(test.built_file_path('build.ninja')).read()
+ if base1 != contents1:
+ test.fail_test()
+ if base2 != contents2:
+ print base2
+ test.fail_test()
+
+ del os.environ["PYTHONHASHSEED"]
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/determinism/main.cc
@@ -0,0 +1,5 @@
+extern int foo();
+
+int main() {
+ return foo();
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/determinism/needed-variables.gyp
@@ -0,0 +1,33 @@
+# Copyright (c) 2015 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': 'test',
+ 'type': 'executable',
+ 'sources': ['rule.ext'],
+ 'rules': [{
+ 'rule_name': 'rule',
+ 'extension': 'ext',
+ 'inputs': [ 'rule.py', ],
+ 'action': [
+ 'python',
+ 'rule.py',
+ '<(RULE_INPUT_ROOT)',
+ '<(RULE_INPUT_EXT)',
+ '<(RULE_INPUT_DIRNAME)',
+ '<(RULE_INPUT_NAME)',
+ '<(RULE_INPUT_PATH)',
+ ],
+ 'outputs': [ 'hello_world.txt' ],
+ 'sources': ['rule.ext'],
+ 'message': 'Processing <(RULE_INPUT_PATH)',
+ 'process_outputs_as_sources': 1,
+ # Allows the test to run without hermetic cygwin on windows.
+ 'msvs_cygwin_shell': 0,
+ }],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/determinism/rule.py
@@ -0,0 +1,3 @@
+#!/usr/bin/env python
+
+print 'Hello World'
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/determinism/solib.cc
@@ -0,0 +1,8 @@
+#ifdef _MSC_VER
+__declspec(dllexport)
+#else
+__attribute__((visibility("default")))
+#endif
+int foo() {
+ return 42;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/determinism/solibs.gyp
@@ -0,0 +1,32 @@
+# Copyright (c) 2015 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.
+
+# This test both tests solibs and implicit_deps.
+{
+ 'targets': [
+ {
+ 'target_name': 'a',
+ 'type': 'shared_library',
+ 'sources': [ 'solib.cc' ],
+ },
+ {
+ 'target_name': 'b',
+ 'type': 'shared_library',
+ 'sources': [ 'solib.cc' ],
+ },
+ {
+ 'target_name': 'c',
+ 'type': 'executable',
+ 'sources': [ 'main.cc' ],
+ 'dependencies': [ 'a', 'b' ],
+ },
+ ],
+ 'conditions': [
+ ['OS=="linux"', {
+ 'target_defaults': {
+ 'cflags': ['-fPIC'],
+ },
+ }],
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/empty-target/empty-target.gyp
@@ -0,0 +1,12 @@
+# Copyright (c) 2014 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': 'empty_target',
+ 'type': 'none',
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/empty-target/gyptest-empty-target.py
@@ -0,0 +1,18 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 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.
+
+"""
+Verifies building a target with nothing succeeds.
+"""
+
+import os
+import sys
+import TestGyp
+
+test = TestGyp.TestGyp()
+test.run_gyp('empty-target.gyp')
+test.build('empty-target.gyp', target='empty_target')
+test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/errors/dependency_cycle.gyp
@@ -0,0 +1,23 @@
+# Copyright 2014 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': 'target0',
+ 'type': 'none',
+ 'dependencies': [ 'target1' ],
+ },
+ {
+ 'target_name': 'target1',
+ 'type': 'none',
+ 'dependencies': [ 'target2' ],
+ },
+ {
+ 'target_name': 'target2',
+ 'type': 'none',
+ 'dependencies': [ 'target0' ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/errors/duplicate_basenames.gyp
@@ -0,0 +1,13 @@
+# 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': 'foo',
+ 'type': 'static_library',
+ 'sources': ['foo.c', 'foo.cc'],
+ },
+ ]
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/errors/duplicate_node.gyp
@@ -0,0 +1,12 @@
+# 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.
+
+{
+ 'targets': [
+ { 'target_name' : 'foo', 'type': 'executable' },
+ ],
+ 'targets': [
+ { 'target_name' : 'bar', 'type': 'executable' },
+ ]
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/errors/duplicate_rule.gyp
@@ -0,0 +1,22 @@
+# 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.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'foo',
+ 'type': 'executable',
+ 'rules': [
+ {
+ 'rule_name': 'bar',
+ 'extension': '',
+ },
+ {
+ 'rule_name': 'bar',
+ 'extension': '',
+ },
+ ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/errors/duplicate_targets.gyp
@@ -0,0 +1,14 @@
+# 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': 'foo'
+ },
+ {
+ 'target_name': 'foo'
+ },
+ ]
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/errors/error_command.gyp
@@ -0,0 +1,12 @@
+# Copyright (c) 2015 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': 'foo',
+ 'type': '<!(["python", "-c", "import sys; sys.exit(3)"])',
+ },
+ ]
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/errors/file_cycle0.gyp
@@ -0,0 +1,17 @@
+# Copyright 2014 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': 'top',
+ 'type': 'none',
+ 'dependencies': [ 'file_cycle1.gyp:middle' ],
+ },
+ {
+ 'target_name': 'bottom',
+ 'type': 'none',
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/errors/file_cycle1.gyp
@@ -0,0 +1,13 @@
+# Copyright 2014 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': 'middle',
+ 'type': 'none',
+ 'dependencies': [ 'file_cycle0.gyp:bottom' ],
+ },
+ ],
+}
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/errors/gyptest-errors.py
@@ -0,0 +1,80 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 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.
+
+"""
+Test that two targets with the same name generates an error.
+"""
+
+import os
+import sys
+
+import TestGyp
+import TestCmd
+
+# TODO(sbc): Remove the use of match_re below, done because scons
+# error messages were not consistent with other generators.
+# Also remove input.py:generator_wants_absolute_build_file_paths.
+
+test = TestGyp.TestGyp()
+
+stderr = ('gyp: Duplicate target definitions for '
+ '.*duplicate_targets.gyp:foo#target\n')
+test.run_gyp('duplicate_targets.gyp', status=1, stderr=stderr,
+ match=TestCmd.match_re)
+
+stderr = ('.*: Unable to find targets in build file .*missing_targets.gyp.*')
+test.run_gyp('missing_targets.gyp', status=1, stderr=stderr,
+ match=TestCmd.match_re_dotall)
+
+stderr = ('gyp: rule bar exists in duplicate, target '
+ '.*duplicate_rule.gyp:foo#target\n')
+test.run_gyp('duplicate_rule.gyp', status=1, stderr=stderr,
+ match=TestCmd.match_re)
+
+stderr = ("gyp: Key 'targets' repeated at level 1 with key path '' while "
+ "reading .*duplicate_node.gyp.*")
+test.run_gyp('duplicate_node.gyp', '--check', status=1, stderr=stderr,
+ match=TestCmd.match_re_dotall)
+
+stderr = (".*target0.*target1.*target2.*target0.*")
+test.run_gyp('dependency_cycle.gyp', status=1, stderr=stderr,
+ match=TestCmd.match_re_dotall)
+
+stderr = (".*file_cycle0.*file_cycle1.*file_cycle0.*")
+test.run_gyp('file_cycle0.gyp', status=1, stderr=stderr,
+ match=TestCmd.match_re_dotall)
+
+stderr = 'gyp: Duplicate basenames in sources section, see list above\n'
+test.run_gyp('duplicate_basenames.gyp', status=1, stderr=stderr)
+
+# Check if '--no-duplicate-basename-check' works.
+if ((test.format == 'make' and sys.platform == 'darwin') or
+ (test.format == 'msvs' and
+ int(os.environ.get('GYP_MSVS_VERSION', 2010)) < 2010)):
+ stderr = 'gyp: Duplicate basenames in sources section, see list above\n'
+ test.run_gyp('duplicate_basenames.gyp', '--no-duplicate-basename-check',
+ status=1, stderr=stderr)
+else:
+ test.run_gyp('duplicate_basenames.gyp', '--no-duplicate-basename-check')
+
+stderr = ("gyp: Dependency '.*missing_dep.gyp:missing.gyp#target' not found "
+ "while trying to load target .*missing_dep.gyp:foo#target\n")
+test.run_gyp('missing_dep.gyp', status=1, stderr=stderr,
+ match=TestCmd.match_re)
+
+# Make sure invalid <!() command invocations say what command it was and
+# mention the gyp file name. Use a "random" command name to trigger an ENOENT.
+stderr = (".*invalid-command-name-egtyevNif3.*netDurj9.*missing_command.gyp.*")
+test.run_gyp('missing_command.gyp', status=1, stderr=stderr,
+ match=TestCmd.match_re_dotall)
+
+# Make sure <!() commands that error out result in a message that mentions
+# the command and gyp file name
+stderr = (".*python.*-c.*import sys.*sys.exit.*3.*error_command.gyp.*")
+test.run_gyp('error_command.gyp', status=1, stderr=stderr,
+ match=TestCmd.match_re_dotall)
+
+test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/errors/missing_command.gyp
@@ -0,0 +1,12 @@
+# Copyright (c) 2015 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': 'foo',
+ 'type': '<!(["invalid-command-name-egtyevNif3", "netDurj9"])',
+ },
+ ]
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/errors/missing_dep.gyp
@@ -0,0 +1,15 @@
+# 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.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'foo',
+ 'type': 'static_library',
+ 'dependencies': [
+ 'missing.gyp'
+ ]
+ },
+ ]
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/errors/missing_targets.gyp
@@ -0,0 +1,8 @@
+# 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.
+
+{
+ 'target_defaults': {
+ },
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/escaping/colon/test.gyp
@@ -0,0 +1,21 @@
+# Copyright (c) 2012 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': 'colon',
+ 'type': 'executable',
+ 'sources': [
+ 'a:b.c',
+ ],
+ 'copies': [
+ {
+ 'destination': '<(PRODUCT_DIR)/',
+ # MSVS2008 gets confused if the same file is in 'sources' and 'copies'
+ 'files': [ 'a:b.c-d', ],
+ },
+ ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/escaping/gyptest-colon.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 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.
+
+"""
+Tests that filenames that contain colons are handled correctly.
+(This is important for absolute paths on Windows.)
+"""
+
+import os
+import sys
+
+if sys.platform == 'win32':
+ print "This test is currently disabled: https://crbug.com/483696."
+ sys.exit(0)
+
+
+import TestGyp
+
+# TODO: Make colons in filenames work with make, if required.
+test = TestGyp.TestGyp(formats=['!make'])
+CHDIR = 'colon'
+
+source_name = 'colon/a:b.c'
+copies_name = 'colon/a:b.c-d'
+if sys.platform == 'win32':
+ # Windows uses : as drive separator and doesn't allow it in regular filenames.
+ # Use abspath() to create a path that contains a colon instead.
+ abs_source = os.path.abspath('colon/file.c')
+ test.write('colon/test.gyp',
+ test.read('colon/test.gyp').replace("'a:b.c'", repr(abs_source)))
+ source_name = abs_source
+
+ abs_copies = os.path.abspath('colon/file.txt')
+ test.write('colon/test.gyp',
+ test.read('colon/test.gyp').replace("'a:b.c-d'", repr(abs_copies)))
+ copies_name = abs_copies
+
+# Create the file dynamically, Windows is unhappy if a file with a colon in
+# its name is checked in.
+test.write(source_name, 'int main() {}')
+test.write(copies_name, 'foo')
+
+test.run_gyp('test.gyp', chdir=CHDIR)
+test.build('test.gyp', test.ALL, chdir=CHDIR)
+test.built_file_must_exist(os.path.basename(copies_name), chdir=CHDIR)
+test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/exclusion/hello.c
+++ b/media/webrtc/trunk/tools/gyp/test/exclusion/hello.c
@@ -3,13 +3,13 @@
* found in the LICENSE file. */
#include <stdio.h>
int func1(void) {
return 42;
}
-int main(int argc, char *argv[]) {
+int main(void) {
printf("Hello, world!\n");
printf("%d\n", func1());
return 0;
}
--- a/media/webrtc/trunk/tools/gyp/test/external-cross-compile/gyptest-cross.py
+++ b/media/webrtc/trunk/tools/gyp/test/external-cross-compile/gyptest-cross.py
@@ -8,20 +8,16 @@
Verifies that actions can be + a source scanner can be used to implement,
cross-compiles (for Native Client at this point).
"""
import TestGyp
test = TestGyp.TestGyp()
-# TODO(bradnelson): fix scons.
-if test.format == 'scons':
- test.skip_test()
-
test.run_gyp('cross.gyp', chdir='src')
test.relocate('src', 'relocate/src')
test.build('cross.gyp', test.ALL, chdir='relocate/src')
expect = """\
From test1.cc
--- a/media/webrtc/trunk/tools/gyp/test/external-cross-compile/src/program.cc
+++ b/media/webrtc/trunk/tools/gyp/test/external-cross-compile/src/program.cc
@@ -5,12 +5,12 @@
*/
#include <stdio.h>
static char data[] = {
#include "cross_program.h"
};
-int main(int argc, char *argv[]) {
+int main(void) {
fwrite(data, 1, sizeof(data), stdout);
return 0;
}
--- a/media/webrtc/trunk/tools/gyp/test/generator-output/actions/subdir1/program.c
+++ b/media/webrtc/trunk/tools/gyp/test/generator-output/actions/subdir1/program.c
@@ -1,12 +1,12 @@
#include <stdio.h>
extern void prog1(void);
extern void prog2(void);
-int main(int argc, char *argv[])
+int main(void)
{
printf("Hello from program.c\n");
prog1();
prog2();
return 0;
}
--- a/media/webrtc/trunk/tools/gyp/test/generator-output/gyptest-actions.py
+++ b/media/webrtc/trunk/tools/gyp/test/generator-output/gyptest-actions.py
@@ -5,18 +5,17 @@
# found in the LICENSE file.
"""
Verifies --generator-output= behavior when using actions.
"""
import TestGyp
-# Ninja and Android don't support --generator-output.
-test = TestGyp.TestGyp(formats=['!ninja', '!android'])
+test = TestGyp.TestGyp()
# All the generated files should go under 'gypfiles'. The source directory
# ('actions') should be untouched.
test.writable(test.workpath('actions'), False)
test.run_gyp('actions.gyp',
'--generator-output=' + test.workpath('gypfiles'),
chdir='actions')
--- a/media/webrtc/trunk/tools/gyp/test/generator-output/gyptest-copies.py
+++ b/media/webrtc/trunk/tools/gyp/test/generator-output/gyptest-copies.py
@@ -6,23 +6,23 @@
"""
Verifies file copies with --generator-output using an explicit build
target of 'all'.
"""
import TestGyp
-# Ninja and Android don't support --generator-output.
-test = TestGyp.TestGyp(formats=['!ninja', '!android'])
+test = TestGyp.TestGyp()
test.writable(test.workpath('copies'), False)
test.run_gyp('copies.gyp',
'--generator-output=' + test.workpath('gypfiles'),
+ '-G', 'xcode_ninja_target_pattern=^(?!copies_null)',
chdir='copies')
test.writable(test.workpath('copies'), True)
test.relocate('copies', 'relocate/copies')
test.relocate('gypfiles', 'relocate/gypfiles')
test.writable(test.workpath('relocate/copies'), False)
@@ -34,26 +34,26 @@ test.writable(test.workpath('relocate/co
test.build('copies.gyp', test.ALL, chdir='relocate/gypfiles')
test.must_match(['relocate', 'copies', 'copies-out', 'file1'],
"file1 contents\n")
if test.format == 'xcode':
chdir = 'relocate/copies/build'
-elif test.format == 'make':
+elif test.format in ['make', 'ninja', 'xcode-ninja', 'cmake']:
chdir = 'relocate/gypfiles/out'
else:
chdir = 'relocate/gypfiles'
test.must_match([chdir, 'Default', 'copies-out', 'file2'], "file2 contents\n")
test.must_match(['relocate', 'copies', 'subdir', 'copies-out', 'file3'],
"file3 contents\n")
if test.format == 'xcode':
chdir = 'relocate/copies/subdir/build'
-elif test.format == 'make':
+elif test.format in ['make', 'ninja', 'xcode-ninja', 'cmake']:
chdir = 'relocate/gypfiles/out'
else:
chdir = 'relocate/gypfiles'
test.must_match([chdir, 'Default', 'copies-out', 'file4'], "file4 contents\n")
test.pass_test()
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/generator-output/gyptest-depth.py
@@ -0,0 +1,58 @@
+#!/usr/bin/env python
+
+# Copyright 2014 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.
+
+"""
+Verifies building a project hierarchy created when the --generator-output=
+and --depth= options is used to put the build configuration files in a separate
+directory tree.
+"""
+
+import TestGyp
+import os
+
+# This is a regression test for the make generator only.
+test = TestGyp.TestGyp(formats=['make'])
+
+test.writable(test.workpath('src'), False)
+
+toplevel_dir = os.path.basename(test.workpath())
+
+test.run_gyp(os.path.join(toplevel_dir, 'src', 'prog1.gyp'),
+ '-Dset_symroot=1',
+ '--generator-output=gypfiles',
+ depth=toplevel_dir,
+ chdir='..')
+
+test.writable(test.workpath('src/build'), True)
+test.writable(test.workpath('src/subdir2/build'), True)
+test.writable(test.workpath('src/subdir3/build'), True)
+
+test.build('prog1.gyp', test.ALL, chdir='gypfiles')
+
+chdir = 'gypfiles'
+
+expect = """\
+Hello from %s
+Hello from inc.h
+Hello from inc1/include1.h
+Hello from inc2/include2.h
+Hello from inc3/include3.h
+Hello from subdir2/deeper/deeper.h
+"""
+
+if test.format == 'xcode':
+ chdir = 'src'
+test.run_built_executable('prog1', chdir=chdir, stdout=expect % 'prog1.c')
+
+if test.format == 'xcode':
+ chdir = 'src/subdir2'
+test.run_built_executable('prog2', chdir=chdir, stdout=expect % 'prog2.c')
+
+if test.format == 'xcode':
+ chdir = 'src/subdir3'
+test.run_built_executable('prog3', chdir=chdir, stdout=expect % 'prog3.c')
+
+test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/generator-output/gyptest-mac-bundle.py
+++ b/media/webrtc/trunk/tools/gyp/test/generator-output/gyptest-mac-bundle.py
@@ -8,18 +8,20 @@
Verifies mac bundles work with --generator-output.
"""
import TestGyp
import sys
if sys.platform == 'darwin':
- # Ninja doesn't support --generator-output.
- test = TestGyp.TestGyp(formats=['!ninja'])
+ print "This test is currently disabled: https://crbug.com/483696."
+ sys.exit(0)
+
+ test = TestGyp.TestGyp(formats=[])
MAC_BUNDLE_DIR = 'mac-bundle'
GYPFILES_DIR = 'gypfiles'
test.writable(test.workpath(MAC_BUNDLE_DIR), False)
test.run_gyp('test.gyp',
'--generator-output=' + test.workpath(GYPFILES_DIR),
chdir=MAC_BUNDLE_DIR)
test.writable(test.workpath(MAC_BUNDLE_DIR), True)
--- a/media/webrtc/trunk/tools/gyp/test/generator-output/gyptest-relocate.py
+++ b/media/webrtc/trunk/tools/gyp/test/generator-output/gyptest-relocate.py
@@ -6,18 +6,17 @@
"""
Verifies that a project hierarchy created with the --generator-output=
option can be built even when it's relocated to a different path.
"""
import TestGyp
-# Ninja and Android don't support --generator-output.
-test = TestGyp.TestGyp(formats=['!ninja', '!android'])
+test = TestGyp.TestGyp()
test.writable(test.workpath('src'), False)
test.run_gyp('prog1.gyp',
'-Dset_symroot=1',
'--generator-output=' + test.workpath('gypfiles'),
chdir='src')
--- a/media/webrtc/trunk/tools/gyp/test/generator-output/gyptest-rules.py
+++ b/media/webrtc/trunk/tools/gyp/test/generator-output/gyptest-rules.py
@@ -5,18 +5,17 @@
# found in the LICENSE file.
"""
Verifies --generator-output= behavior when using rules.
"""
import TestGyp
-# Ninja and Android don't support --generator-output.
-test = TestGyp.TestGyp(formats=['!ninja', '!android'])
+test = TestGyp.TestGyp()
test.writable(test.workpath('rules'), False)
test.run_gyp('rules.gyp',
'--generator-output=' + test.workpath('gypfiles'),
chdir='rules')
test.writable(test.workpath('rules'), True)
--- a/media/webrtc/trunk/tools/gyp/test/generator-output/gyptest-subdir2-deep.py
+++ b/media/webrtc/trunk/tools/gyp/test/generator-output/gyptest-subdir2-deep.py
@@ -7,18 +7,17 @@
"""
Verifies building a target from a .gyp file a few subdirectories
deep when the --generator-output= option is used to put the build
configuration files in a separate directory tree.
"""
import TestGyp
-# Ninja and Android don't support --generator-output.
-test = TestGyp.TestGyp(formats=['!ninja', '!android'])
+test = TestGyp.TestGyp()
test.writable(test.workpath('src'), False)
test.writable(test.workpath('src/subdir2/deeper/build'), True)
test.run_gyp('deeper.gyp',
'-Dset_symroot=1',
'--generator-output=' + test.workpath('gypfiles'),
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/generator-output/gyptest-symlink.py
@@ -0,0 +1,42 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 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.
+
+"""
+Verifies building a target when the --generator-output= option is used to put
+the build configuration files in a separate directory tree referenced by a
+symlink.
+"""
+
+import TestGyp
+import os
+
+test = TestGyp.TestGyp()
+if not hasattr(os, 'symlink'):
+ test.skip_test('Missing os.symlink -- skipping test.\n')
+
+test.writable(test.workpath('src'), False)
+
+test.writable(test.workpath('src/subdir2/deeper/build'), True)
+
+test.subdir(test.workpath('build'))
+test.subdir(test.workpath('build/deeper'))
+test.symlink('build/deeper', test.workpath('symlink'))
+
+test.writable(test.workpath('build/deeper'), True)
+test.run_gyp('deeper.gyp',
+ '-Dset_symroot=2',
+ '--generator-output=' + test.workpath('symlink'),
+ chdir='src/subdir2/deeper')
+
+chdir = 'symlink'
+test.build('deeper.gyp', test.ALL, chdir=chdir)
+
+if test.format == 'xcode':
+ chdir = 'src/subdir2/deeper'
+test.run_built_executable('deeper',
+ chdir=chdir,
+ stdout="Hello from deeper.c\n")
+test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/generator-output/gyptest-top-all.py
+++ b/media/webrtc/trunk/tools/gyp/test/generator-output/gyptest-top-all.py
@@ -7,18 +7,17 @@
"""
Verifies building a project hierarchy created when the --generator-output=
option is used to put the build configuration files in a separate
directory tree.
"""
import TestGyp
-# Ninja and Android don't support --generator-output.
-test = TestGyp.TestGyp(formats=['!ninja', '!android'])
+test = TestGyp.TestGyp()
test.writable(test.workpath('src'), False)
test.run_gyp('prog1.gyp',
'-Dset_symroot=1',
'--generator-output=' + test.workpath('gypfiles'),
chdir='src')
--- a/media/webrtc/trunk/tools/gyp/test/generator-output/rules/subdir1/executable.gyp
+++ b/media/webrtc/trunk/tools/gyp/test/generator-output/rules/subdir1/executable.gyp
@@ -21,34 +21,34 @@
'rules': [
{
'rule_name': 'copy_file_0',
'extension': 'in0',
'inputs': [
'../copy-file.py',
],
'outputs': [
- # TODO: fix SCons and Make to support generated files not
+ # TODO: fix Make to support generated files not
# in a variable-named path like <(INTERMEDIATE_DIR)
#'<(RULE_INPUT_ROOT).c',
'<(INTERMEDIATE_DIR)/<(RULE_INPUT_ROOT).h',
],
'action': [
'python', '<(_inputs)', '<(RULE_INPUT_PATH)', '<@(_outputs)',
],
'process_outputs_as_sources': 0,
},
{
'rule_name': 'copy_file_1',
'extension': 'in1',
'inputs': [
'../copy-file.py',
],
'outputs': [
- # TODO: fix SCons and Make to support generated files not
+ # TODO: fix Make to support generated files not
# in a variable-named path like <(INTERMEDIATE_DIR)
#'<(RULE_INPUT_ROOT).c',
'<(INTERMEDIATE_DIR)/<(RULE_INPUT_ROOT).c',
],
'action': [
'python', '<(_inputs)', '<(RULE_INPUT_PATH)', '<@(_outputs)',
],
'process_outputs_as_sources': 1,
--- a/media/webrtc/trunk/tools/gyp/test/generator-output/rules/subdir1/program.c
+++ b/media/webrtc/trunk/tools/gyp/test/generator-output/rules/subdir1/program.c
@@ -2,17 +2,17 @@
#include "define3.h"
#include "define4.h"
extern void function1(void);
extern void function2(void);
extern void function3(void);
extern void function4(void);
-int main(int argc, char *argv[])
+int main(void)
{
printf("Hello from program.c\n");
function1();
function2();
printf("%s", STRING3);
printf("%s", STRING4);
return 0;
}
--- a/media/webrtc/trunk/tools/gyp/test/generator-output/src/prog1.c
+++ b/media/webrtc/trunk/tools/gyp/test/generator-output/src/prog1.c
@@ -1,17 +1,17 @@
#include <stdio.h>
#include "inc.h"
#include "include1.h"
#include "include2.h"
#include "include3.h"
#include "deeper.h"
-int main(int argc, char *argv[])
+int main(void)
{
printf("Hello from prog1.c\n");
printf("Hello from %s\n", INC_STRING);
printf("Hello from %s\n", INCLUDE1_STRING);
printf("Hello from %s\n", INCLUDE2_STRING);
printf("Hello from %s\n", INCLUDE3_STRING);
printf("Hello from %s\n", DEEPER_STRING);
return 0;
--- a/media/webrtc/trunk/tools/gyp/test/generator-output/src/subdir2/deeper/deeper.c
+++ b/media/webrtc/trunk/tools/gyp/test/generator-output/src/subdir2/deeper/deeper.c
@@ -1,7 +1,7 @@
#include <stdio.h>
-int main(int argc, char *argv[])
+int main(void)
{
printf("Hello from deeper.c\n");
return 0;
}
--- a/media/webrtc/trunk/tools/gyp/test/generator-output/src/subdir2/prog2.c
+++ b/media/webrtc/trunk/tools/gyp/test/generator-output/src/subdir2/prog2.c
@@ -1,17 +1,17 @@
#include <stdio.h>
#include "inc.h"
#include "include1.h"
#include "include2.h"
#include "include3.h"
#include "deeper.h"
-int main(int argc, char *argv[])
+int main(void)
{
printf("Hello from prog2.c\n");
printf("Hello from %s\n", INC_STRING);
printf("Hello from %s\n", INCLUDE1_STRING);
printf("Hello from %s\n", INCLUDE2_STRING);
printf("Hello from %s\n", INCLUDE3_STRING);
printf("Hello from %s\n", DEEPER_STRING);
return 0;
--- a/media/webrtc/trunk/tools/gyp/test/generator-output/src/subdir3/prog3.c
+++ b/media/webrtc/trunk/tools/gyp/test/generator-output/src/subdir3/prog3.c
@@ -1,17 +1,17 @@
#include <stdio.h>
#include "inc.h"
#include "include1.h"
#include "include2.h"
#include "include3.h"
#include "deeper.h"
-int main(int argc, char *argv[])
+int main(void)
{
printf("Hello from prog3.c\n");
printf("Hello from %s\n", INC_STRING);
printf("Hello from %s\n", INCLUDE1_STRING);
printf("Hello from %s\n", INCLUDE2_STRING);
printf("Hello from %s\n", INCLUDE3_STRING);
printf("Hello from %s\n", DEEPER_STRING);
return 0;
--- a/media/webrtc/trunk/tools/gyp/test/gyp-defines/gyptest-multiple-values.py
+++ b/media/webrtc/trunk/tools/gyp/test/gyp-defines/gyptest-multiple-values.py
@@ -11,23 +11,25 @@ is used.
import os
import TestGyp
test = TestGyp.TestGyp()
os.environ['GYP_DEFINES'] = 'key=value1 key=value2 key=value3'
test.run_gyp('defines.gyp')
+
test.build('defines.gyp')
test.must_contain('action.txt', 'value3')
# The last occurrence of a repeated set should take precedence over other
# values.
os.environ['GYP_DEFINES'] = 'key=repeated_value key=value1 key=repeated_value'
test.run_gyp('defines.gyp')
+
if test.format == 'msvs' and not test.uses_msbuild:
# msvs versions before 2010 don't detect build rule changes not reflected
# in file system timestamps. Rebuild to see differences.
test.build('defines.gyp', rebuild=True)
else:
test.build('defines.gyp')
test.must_contain('action.txt', 'repeated_value')
--- a/media/webrtc/trunk/tools/gyp/test/gyp-defines/gyptest-regyp.py
+++ b/media/webrtc/trunk/tools/gyp/test/gyp-defines/gyptest-regyp.py
@@ -8,18 +8,18 @@
Verifies that when the same value is repeated for a gyp define, duplicates are
stripped from the regeneration rule.
"""
import os
import TestGyp
# Regenerating build files when a gyp file changes is currently only supported
-# by the make and Android generators.
-test = TestGyp.TestGyp(formats=['make', 'android'])
+# by the make generator.
+test = TestGyp.TestGyp(formats=['make'])
os.environ['GYP_DEFINES'] = 'key=repeated_value key=value1 key=repeated_value'
test.run_gyp('defines.gyp')
test.build('defines.gyp')
# The last occurrence of a repeated set should take precedence over other
# values. See gyptest-multiple-values.py.
test.must_contain('action.txt', 'repeated_value')
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/hello/gyptest-regyp-output.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 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.
+
+"""
+Verifies that Makefiles get rebuilt when a source gyp file changes and
+--generator-output is used.
+"""
+
+import TestGyp
+
+# Regenerating build files when a gyp file changes is currently only supported
+# by the make generator, and --generator-output is not supported by ninja, so we
+# can only test for make.
+test = TestGyp.TestGyp(formats=['make'])
+
+CHDIR='generator-output'
+
+test.run_gyp('hello.gyp', '--generator-output=%s' % CHDIR)
+
+test.build('hello.gyp', test.ALL, chdir=CHDIR)
+
+test.run_built_executable('hello', stdout="Hello, world!\n", chdir=CHDIR)
+
+# Sleep so that the changed gyp file will have a newer timestamp than the
+# previously generated build files.
+test.sleep()
+test.write('hello.gyp', test.read('hello2.gyp'))
+
+test.build('hello.gyp', test.ALL, chdir=CHDIR)
+
+test.run_built_executable('hello', stdout="Hello, two!\n", chdir=CHDIR)
+
+test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/hello/gyptest-regyp.py
+++ b/media/webrtc/trunk/tools/gyp/test/hello/gyptest-regyp.py
@@ -6,18 +6,18 @@
"""
Verifies that Makefiles get rebuilt when a source gyp file changes.
"""
import TestGyp
# Regenerating build files when a gyp file changes is currently only supported
-# by the make and Android generators.
-test = TestGyp.TestGyp(formats=['make', 'android'])
+# by the make generator.
+test = TestGyp.TestGyp(formats=['make'])
test.run_gyp('hello.gyp')
test.build('hello.gyp', test.ALL)
test.run_built_executable('hello', stdout="Hello, world!\n")
# Sleep so that the changed gyp file will have a newer timestamp than the
--- a/media/webrtc/trunk/tools/gyp/test/hello/hello.c
+++ b/media/webrtc/trunk/tools/gyp/test/hello/hello.c
@@ -1,11 +1,11 @@
/* 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. */
#include <stdio.h>
-int main(int argc, char *argv[])
+int main(void)
{
printf("Hello, world!\n");
return 0;
}
--- a/media/webrtc/trunk/tools/gyp/test/hello/hello2.c
+++ b/media/webrtc/trunk/tools/gyp/test/hello/hello2.c
@@ -1,11 +1,11 @@
/* 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. */
#include <stdio.h>
-int main(int argc, char *argv[])
+int main(void)
{
printf("Hello, two!\n");
return 0;
}
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/home_dot_gyp/gyptest-home-includes-config-arg.py
@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 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.
+
+"""
+Verifies inclusion of $HOME/.gyp/include.gypi works when --config-dir is
+specified.
+"""
+
+import os
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+os.environ['HOME'] = os.path.abspath('home2')
+
+test.run_gyp('all.gyp', '--config-dir=~/.gyp_new', chdir='src')
+
+# After relocating, we should still be able to build (build file shouldn't
+# contain relative reference to ~/.gyp/include.gypi)
+test.relocate('src', 'relocate/src')
+
+test.build('all.gyp', test.ALL, chdir='relocate/src')
+
+test.run_built_executable('printfoo',
+ chdir='relocate/src',
+ stdout='FOO is fromhome3\n')
+
+test.pass_test()
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/home_dot_gyp/gyptest-home-includes-config-env.py
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 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.
+
+"""
+Verifies inclusion of $HOME/.gyp_new/include.gypi works when GYP_CONFIG_DIR
+is set.
+"""
+
+import os
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+os.environ['HOME'] = os.path.abspath('home')
+os.environ['GYP_CONFIG_DIR'] = os.path.join(os.path.abspath('home2'),
+ '.gyp_new')
+
+test.run_gyp('all.gyp', chdir='src')
+
+# After relocating, we should still be able to build (build file shouldn't
+# contain relative reference to ~/.gyp_new/include.gypi)
+test.relocate('src', 'relocate/src')
+
+test.build('all.gyp', test.ALL, chdir='relocate/src')
+
+test.run_built_executable('printfoo',
+ chdir='relocate/src',
+ stdout='FOO is fromhome3\n')
+
+test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/home_dot_gyp/gyptest-home-includes-regyp.py
+++ b/media/webrtc/trunk/tools/gyp/test/home_dot_gyp/gyptest-home-includes-regyp.py
@@ -8,18 +8,18 @@
Verifies inclusion of $HOME/.gyp/include.gypi works properly with relocation
and with regeneration.
"""
import os
import TestGyp
# Regenerating build files when a gyp file changes is currently only supported
-# by the make and Android generators.
-test = TestGyp.TestGyp(formats=['make', 'android'])
+# by the make generator.
+test = TestGyp.TestGyp(formats=['make'])
os.environ['HOME'] = os.path.abspath('home')
test.run_gyp('all.gyp', chdir='src')
# After relocating, we should still be able to build (build file shouldn't
# contain relative reference to ~/.gyp/include.gypi)
test.relocate('src', 'relocate/src')
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/home_dot_gyp/home2/.gyp_new/include.gypi
@@ -0,0 +1,5 @@
+{
+ 'variables': {
+ 'foo': '"fromhome3"',
+ },
+}
--- a/media/webrtc/trunk/tools/gyp/test/home_dot_gyp/src/printfoo.c
+++ b/media/webrtc/trunk/tools/gyp/test/home_dot_gyp/src/printfoo.c
@@ -1,7 +1,7 @@
#include <stdio.h>
-int main(int argc, char *argv[])
+int main(void)
{
printf("FOO is %s\n", FOO);
return 0;
}
--- a/media/webrtc/trunk/tools/gyp/test/include_dirs/gyptest-all.py
+++ b/media/webrtc/trunk/tools/gyp/test/include_dirs/gyptest-all.py
@@ -7,19 +7,16 @@
"""
Verifies use of include_dirs when using an explicit build target of 'all'.
"""
import TestGyp
test = TestGyp.TestGyp()
-if test.format == 'scons':
- test.skip_test('TODO: http://code.google.com/p/gyp/issues/detail?id=176\n')
-
test.run_gyp('includes.gyp', chdir='src')
test.relocate('src', 'relocate/src')
test.build('includes.gyp', test.ALL, chdir='relocate/src')
expect = """\
Hello from includes.c
--- a/media/webrtc/trunk/tools/gyp/test/include_dirs/gyptest-default.py
+++ b/media/webrtc/trunk/tools/gyp/test/include_dirs/gyptest-default.py
@@ -7,19 +7,16 @@
"""
Verifies use of include_dirs when using the default build target.
"""
import TestGyp
test = TestGyp.TestGyp()
-if test.format == 'scons':
- test.skip_test('TODO: http://code.google.com/p/gyp/issues/detail?id=176\n')
-
test.run_gyp('includes.gyp', chdir='src')
test.relocate('src', 'relocate/src')
test.build('includes.gyp', test.ALL, chdir='relocate/src')
expect = """\
Hello from includes.c
--- a/media/webrtc/trunk/tools/gyp/test/include_dirs/src/includes.c
+++ b/media/webrtc/trunk/tools/gyp/test/include_dirs/src/includes.c
@@ -1,16 +1,16 @@
#include <stdio.h>
#include "inc.h"
#include "include1.h"
#include "include2.h"
#include "shadow.h"
-int main(int argc, char *argv[])
+int main(void)
{
printf("Hello from includes.c\n");
printf("Hello from %s\n", INC_STRING);
printf("Hello from %s\n", INCLUDE1_STRING);
printf("Hello from %s\n", INCLUDE2_STRING);
/* Test that include_dirs happen first: The gyp file has a -Ishadow1
cflag and an include_dir of shadow2. Including shadow.h should get
the shadow.h from the include_dir. */
--- a/media/webrtc/trunk/tools/gyp/test/include_dirs/src/subdir/subdir_includes.c
+++ b/media/webrtc/trunk/tools/gyp/test/include_dirs/src/subdir/subdir_includes.c
@@ -1,14 +1,14 @@
#include <stdio.h>
#include "inc.h"
#include "include1.h"
#include "include2.h"
-int main(int argc, char *argv[])
+int main(void)
{
printf("Hello from subdir/subdir_includes.c\n");
printf("Hello from %s\n", INC_STRING);
printf("Hello from %s\n", INCLUDE1_STRING);
printf("Hello from %s\n", INCLUDE2_STRING);
return 0;
}
--- a/media/webrtc/trunk/tools/gyp/test/intermediate_dir/gyptest-intermediate-dir.py
+++ b/media/webrtc/trunk/tools/gyp/test/intermediate_dir/gyptest-intermediate-dir.py
@@ -8,25 +8,27 @@
Verifies that targets have independent INTERMEDIATE_DIRs.
"""
import TestGyp
test = TestGyp.TestGyp()
test.run_gyp('test.gyp', chdir='src')
+
test.build('test.gyp', 'target1', chdir='src')
# Check stuff exists.
intermediate_file1 = test.read('src/outfile.txt')
test.must_contain(intermediate_file1, 'target1')
shared_intermediate_file1 = test.read('src/shared_outfile.txt')
test.must_contain(shared_intermediate_file1, 'shared_target1')
test.run_gyp('test2.gyp', chdir='src')
+
# Force the shared intermediate to be rebuilt.
test.sleep()
test.touch('src/shared_infile.txt')
test.build('test2.gyp', 'target2', chdir='src')
# Check INTERMEDIATE_DIR file didn't get overwritten but SHARED_INTERMEDIATE_DIR
# file did.
intermediate_file2 = test.read('src/outfile.txt')
test.must_contain(intermediate_file1, 'target1')
copy from media/webrtc/trunk/tools/gyp/test/mac/app-bundle/TestApp/English.lproj/InfoPlist.strings
copy to media/webrtc/trunk/tools/gyp/test/ios/app-bundle/TestApp/English.lproj/InfoPlist-error.strings
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/app-bundle/TestApp/English.lproj/InfoPlist.strings
@@ -0,0 +1,3 @@
+/* Localized versions of Info.plist keys */
+
+NSHumanReadableCopyright = "Copyright ©2011 Google Inc.";
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/app-bundle/TestApp/English.lproj/LanguageMap.plist
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>en</key>
+ <string>en</string>
+</dict>
+</plist>
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/app-bundle/TestApp/English.lproj/MainMenu.xib
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="9060" systemVersion="15B42" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
+ <dependencies>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9051"/>
+ <capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
+ <capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
+ </dependencies>
+ <objects>
+ <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+ <viewController id="Ssz-5V-cv2">
+ <view key="view" contentMode="scaleToFill" id="tRS-Cx-RH3">
+ </view>
+ <point key="canvasLocation" x="548" y="1086"/>
+ </viewController>
+ </objects>
+</document>
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/app-bundle/TestApp/English.lproj/Main_iPhone.storyboard
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="1.0" toolsVersion="1906" systemVersion="11A511" targetRuntime="iOS.CocoaTouch" nextObjectID="6" propertyAccessControl="none" initialViewController="2">
+ <dependencies>
+ <development defaultVersion="4200" identifier="xcode"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="902"/>
+ </dependencies>
+ <scenes>
+ <scene sceneID="5">
+ <objects>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="4" sceneMemberID="firstResponder"/>
+ <viewController id="2" customClass="ViewController" sceneMemberID="viewController">
+ <view key="view" contentMode="scaleToFill" id="3">
+ <rect key="frame" x="0.0" y="20" width="320" height="460"/>
+ <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+ <subviews/>
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
+ </view>
+ </viewController>
+ </objects>
+ </scene>
+ </scenes>
+ <simulatedMetricsContainer key="defaultSimulatedMetrics">
+ <simulatedStatusBarMetrics key="statusBar"/>
+ <simulatedOrientationMetrics key="orientation"/>
+ <simulatedScreenMetrics key="destination"/>
+ </simulatedMetricsContainer>
+</document>
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/app-bundle/TestApp/Images.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,58 @@
+{
+ "images" : [
+ {
+ "idiom" : "mac",
+ "size" : "16x16",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "16x16",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "32x32",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "32x32",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "128x128",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "128x128",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "256x256",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "256x256",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "512x512",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "512x512",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/app-bundle/TestApp/Images.xcassets/image.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "super_sylvain.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "super_sylvain@2x.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "super_sylvain@3x.png"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
new file mode 100644
index 0000000000000000000000000000000000000000..0ba769182f117a972f76280a19bd69d6e81b68f7
GIT binary patch
literal 3263
zc$@*h3_$aVP)<h;3K|Lk000e1NJLTq000yK000yS1^@s6jfou%000U>X+uL$Nkc;*
zP;zf(X>4Tx07wm;mUmQB*%pV-y*Itk5+Wca^cs2zAksTX6$DX<Nq|rShJ+?|L<L3^
z5h+$=RKNj8hazJ|6bplbV%G`s5KzX!QA9=M-HdAq@2xfS-kSZ#S>M^`x7XQc?|s+0
z08spb1j2M!0f022SQPH-!CVp(%f$Br7!UytSOLJ{W@ZFO_(THK{JlMynW#v{v-a*T
zfMmPdEWc1DbJqWVks>!kBnAKqMb$PuekK>?0+ds;#ThdH1j_W4DKdsJG8Ul;qO2n0
z#IJ1jr{*iW$(WZW<e?f_&KbNko{YOt-kK%hql^ThT$m-`XQO-vWxZ5MngHeZDAUvU
zoJ;^P6q#Sl=O&?Si84hL8SaVl0ssh<#5ufj4vYCYXr2Igrf1}e1c^yvrV-beY31n1
zX8Q57Q~6>sE0n`c;fQ!l&-AnmjxZO1uWyz`0VP>&nP`#itsL#`S=Q!g`M=rU9)45(
zJ;-|dRq-b5&z?byo>|{)?5r=n76A4nTALlSzLiw~v~31J<>9PP?;rs31pu_(obw)r
zY+jPY;tVGXi|p)da{-@gE-UCa`=5eu%D;v=_nFJ?`&K)q7e9d`Nfk3?MdhZarb|T3
z%nS~f&t(1g5dY)AIcd$w!z`Siz!&j_=v7hZlnI21XuE|xfmo0(WD10T)!}~_HYW!e
zew}L+XmwuzeT6wtxJd`dZ#@7*BLgIEKY9Xv>st^p3dp{^Xswa2bB{85{^$B13tWnB
z;Y>jyQ|9&zk7RNsqAVGs--K+z0uqo1bf5|}fi5rtEMN^BfHQCd-XH*kfJhJnmIE$G
z0%<@5vOzxB0181d*a3EfYH$G5fqKvcPJ%XY23!PJzzuK<41h;K3WmW;Fah3yX$XSw
z5EY_9s*o0>51B&N5F1(uc|$=^I1~fLLy3?Ol0f;;Ca4%HgQ}rJP(Ab`bQ-z{U4#0d
z2hboi2K@njgb|nm(_szR0JebHusa+GN5aeCM0gdP2N%HG;Yzp`J`T6S7vUT504#-H
z!jlL<$Or?`Mpy_N@kBz9SR?@vA#0H$qyni$nvf2p8@Y{0k#Xb$28W?xm>3qu8RLgp
zjNxKdVb)?wFx8l2m{v>|<~C*!GlBVnrDD~wrdTJeKXwT=5u1%I#8zOBU|X=4u>;s)
z>^mF|$G{ol9B_WP7+f-LHLe7=57&&lfa}8z;U@8Tyei%l?}87(bMRt(A-)QK9Dg3)
zj~~XrCy)tR1Z#p1A(kK{Y$Q|=8VKhI{e%(1G*N-5Pjn)N5P8I0VkxnX*g?EW941ba
z6iJ387g8iCnY4jaNopcpCOsy-A(P2EWJhusSwLP-t|XrzUnLKcKTwn?CKOLf97RIe
zPB}`sKzTrUL#0v;sBY9)s+hW+T2H-1eM)^VN0T#`^Oxhvt&^*fYnAJldnHel*Ozyf
zUoM{~Um<@={-*r60#U(0!Bc^wuvVc);k3d%g-J!4qLpHZVwz%!VuRu}#Ze`^l7W)9
z5>Kf>>9Eozr6C$Z)1`URxU@~QI@)F0FdauXr2Es8>BaOP=)Lp_WhG@><tXJG<r?L)
z%2EcxFktvIQW>R;lZ?BJkMlI<xzFRz+cvLhUjMu)mH8@eDtwh9m1dOzm5-`SRd3Z4
z)t#zss!!A~Y9?x7YT0W0)h?@z&!^9Kp3j|MH2>uMhw8ApiF&yDYW2hFJ?fJhni{?u
z85&g@mo&yT8JcdI$(rSw=QPK(Xj%)k1X|@<=e1rim6`6$RAwc!i#egKuI;BS(LSWz
zt39n_sIypSqfWEV6J3%nTQ@<sT(?tqLQhLCSTA3%QSYHXQJ<}!q`ybMTYt*H&>-4i
zi$R;gsG*9XzhRzXqv2yCs*$VFDx+GXJH|L;wsDH_KI2;^u!)^Xl1YupO;gy^-c(?^
z&$Q1BYvyPsG^;hc$D**@Sy`+`)}T4VJji^bd7Jqw3q6Zii=7tT7GEswEK@D(EFW1Z
zSp`^awCb?>!`j4}Yh7b~$A)U-W3$et-R8BesV(1jzwLcHnq9En7Q0Tn&-M=XBKs!$
zF$X<|c!#|X_t<oHD7%Dx)e-CH;keH6jN=C<dnd8eNvGePS<WfW4bGzr3>WYh)GZit
z(Q)Cp9CDE^WG;+fcyOWARoj*0TI>4EP1lX*cEoMO-Pk?Z{kZ!p4@(b`M~lalr<3Oz
z&kJ6Nm#<fmSFg8{_hRpA@25UGK8Ze!J`=unzN>vN_+kA5{dW4@^Vjg_`q%qU1ULk&
z3Fr!>1V#i_2R;ij2@(Z$1jE4r!MlPVFVbHmT+|i<Li|H^g**v03|$raa~LixG^{4<
zdAL=0et35TEn-DPL&UpCkI2%<M~jUXOBQ!V$w$RS)kjT5dqtN;OP5$IS+nFuj9QE!
zracxP8x?ybc5<or(%nmk<Lu%J<L)jqT$Z!!+H$q!smsr<kYB-BaVj1gA06Ki|A`aA
zspU+r^k2Dm<pkH0yNCOd=f*4NjqzRhW&Du@mxQu}(L|TTU5R5!u1OV1;{s1XwcvHK
zU-E(Esg#hEqbW0~(W%X8gtYjy(?TU-im)qPGd(B0FT*sWFhjb^Y1Qsk6QV%TkxVFa
zS!TPKj{Z#bNQ@+#C4*TDvud*5XGdk9%2CV_=Je#6<ZjCy$@9tkel=z_cXemJcK(L^
z!8Pt{4y}dOu3X!>PIq0wy5aS{>yK?9ZAjVh%SOwMWgFjair&;wpi!{CU}&@N=Eg#~
zLQ&zpEzVmGY{hI9Z0+4<v#n~|mm*%#^<vB7isDZt+>-0xS$$Xe-OToc?Y*V;rTcf_
zb_jRe-RZjXSeas3UfIyD;9afd%<`i0x4T#DzE)vdabOQ=k7SRuGN`h>O0Q~1)u-yD
z>VX=Mn&!Rgd$;YK+Q-}1zu#?t(*cbG#Ronf6db&N$oEidtwC+YVcg-Y!_VuY>bk#Y
ze_ww@?MU&F&qswvrN_dLb=5o6*Egs)ls3YRlE$&)amR1{;Ppd$6RYV^Go!iq1UMl%
z@#4q$AMc(FJlT1QeX8jv{h#)>&{~RGq1N2iiMFIRX?sk2-|2wUogK~{EkB$8eDsX=
znVPf8XG_nK&J~=SIiGia@<PUi@r#KUhdNhuKDxBz(w(lbuHMUmm#<#&xpJx7z5D!C
zm#b&4IbAz_oqfIShW(A!9=o2FU+jKq>9y}|z3FhX{g&gcj=lwb=lWgyFW&aLedUh-
zof`v-2Kw$UzI*>(+&$@i-u=-BsSjR1%z8NeX#HdC<Dw@DPb!|OKdt@M_}6Bsz4Yv$
z*I>`Hh-Z(6xI-`hmHDqv!v)W&&nrf>M(RhcN6(D;jNN*%^u_SYjF;2ng}*8Ow)d6M
ztDk;%`@Lsk$;9w$(d(H%O5UixIr`T2ZRcd@<kNR)@201U-mAVp_JRGO`(yOSk?HJD
z_)nFejX!sM3H<VSCT(Ws-}i*``!YINegFUhIY~r8R5%f(ls#w^K@`XTv%9zCJc7Z)
zBA^jDY(%uM7S2Pfq_T;ED8gAtkf22xn-qSagcO1Z!A1zEMJ&W1Hs;{O6yg^gL5pBv
zP&D2l+%0>1`!T+Ex66Gv0|`DD_RX93e)DGL?Gqr$&sO&c%f7>^5Ey0KRz*tuAm5S<
zS~I2D?1o^NVWmDnh+SKSDE*|YMS*|BYG)?!e=y#G5@MD`YM$ph$?Y>y7&Bm#Lv1s}
z^Uo3LI%i^8`a2W2c3}q!qoOao=!TeIaIx(4ncEX)8ULC)mhp*nAFLV1o@o<T&)OK)
z1Zsc+Cl16*4Ik4t8yLUs;MFhL!DLf7J)$ORfiOD(fhSRIs}grtTKHNGvGFay$3JQy
zKZ-&kto@WYyjQ@=+E~0|;^pfW?!Wa>T=y0JU6Ux>sK@8%8rxdN#Dhy|?C0lAB#iLx
zjfa_Xa-qpW_p3QFIXEGTa}C^E_3^tE2bczq9!q0sGSwvvXnG)JHcaE`iib%8&zF5P
z;^2{-jq{pEQQu+4!qW5*IA-mIgUcTzmdhUAHw`SFj9+UYvt+8zF!nf@AHu2KT-*W^
zW8EU}z1jrEUv-8~fM@Fw&gE!7D&(n)8BFy?xdB!+WuwjT;S(2+zk~>SL8LdU0d6gL
zs0`SXsW^VU{$2k+lbbDYXs3WnYTA!b(PYLz?u~rp5{)x7)Y6iuY^qCD5l}L?(-OL-
xSlph87|b%bZF8rkbRWg-d|M!n;aFxc>o1aGzi<rUj#2;s002ovPDHLkV1oMAPV4{x
new file mode 100644
index 0000000000000000000000000000000000000000..edfa6a5682f108afb4d7f23ff53e6897a24959c5
GIT binary patch
literal 3847
zc$@(T5BTtjP)<h;3K|Lk000e1NJLTq001Ze001Zm1^@s6jQ+T7000U>X+uL$Nkc;*
zP;zf(X>4Tx07wm;mUmQB*%pV-y*Itk5+Wca^cs2zAksTX6$DX<Nq|rShJ+?|L<L3^
z5h+$=RKNj8hazJ|6bplbV%G`s5KzX!QA9=M-HdAq@2xfS-kSZ#S>M^`x7XQc?|s+0
z08spb1j2M!0f022SQPH-!CVp(%f$Br7!UytSOLJ{W@ZFO_(THK{JlMynW#v{v-a*T
zfMmPdEWc1DbJqWVks>!kBnAKqMb$PuekK>?0+ds;#ThdH1j_W4DKdsJG8Ul;qO2n0
z#IJ1jr{*iW$(WZW<e?f_&KbNko{YOt-kK%hql^ThT$m-`XQO-vWxZ5MngHeZDAUvU
zoJ;^P6q#Sl=O&?Si84hL8SaVl0ssh<#5ufj4vYCYXr2Igrf1}e1c^yvrV-beY31n1
zX8Q57Q~6>sE0n`c;fQ!l&-AnmjxZO1uWyz`0VP>&nP`#itsL#`S=Q!g`M=rU9)45(
zJ;-|dRq-b5&z?byo>|{)?5r=n76A4nTALlSzLiw~v~31J<>9PP?;rs31pu_(obw)r
zY+jPY;tVGXi|p)da{-@gE-UCa`=5eu%D;v=_nFJ?`&K)q7e9d`Nfk3?MdhZarb|T3
z%nS~f&t(1g5dY)AIcd$w!z`Siz!&j_=v7hZlnI21XuE|xfmo0(WD10T)!}~_HYW!e
zew}L+XmwuzeT6wtxJd`dZ#@7*BLgIEKY9Xv>st^p3dp{^Xswa2bB{85{^$B13tWnB
z;Y>jyQ|9&zk7RNsqAVGs--K+z0uqo1bf5|}fi5rtEMN^BfHQCd-XH*kfJhJnmIE$G
z0%<@5vOzxB0181d*a3EfYH$G5fqKvcPJ%XY23!PJzzuK<41h;K3WmW;Fah3yX$XSw
z5EY_9s*o0>51B&N5F1(uc|$=^I1~fLLy3?Ol0f;;Ca4%HgQ}rJP(Ab`bQ-z{U4#0d
z2hboi2K@njgb|nm(_szR0JebHusa+GN5aeCM0gdP2N%HG;Yzp`J`T6S7vUT504#-H
z!jlL<$Or?`Mpy_N@kBz9SR?@vA#0H$qyni$nvf2p8@Y{0k#Xb$28W?xm>3qu8RLgp
zjNxKdVb)?wFx8l2m{v>|<~C*!GlBVnrDD~wrdTJeKXwT=5u1%I#8zOBU|X=4u>;s)
z>^mF|$G{ol9B_WP7+f-LHLe7=57&&lfa}8z;U@8Tyei%l?}87(bMRt(A-)QK9Dg3)
zj~~XrCy)tR1Z#p1A(kK{Y$Q|=8VKhI{e%(1G*N-5Pjn)N5P8I0VkxnX*g?EW941ba
z6iJ387g8iCnY4jaNopcpCOsy-A(P2EWJhusSwLP-t|XrzUnLKcKTwn?CKOLf97RIe
zPB}`sKzTrUL#0v;sBY9)s+hW+T2H-1eM)^VN0T#`^Oxhvt&^*fYnAJldnHel*Ozyf
zUoM{~Um<@={-*r60#U(0!Bc^wuvVc);k3d%g-J!4qLpHZVwz%!VuRu}#Ze`^l7W)9
z5>Kf>>9Eozr6C$Z)1`URxU@~QI@)F0FdauXr2Es8>BaOP=)Lp_WhG@><tXJG<r?L)
z%2EcxFktvIQW>R;lZ?BJkMlI<xzFRz+cvLhUjMu)mH8@eDtwh9m1dOzm5-`SRd3Z4
z)t#zss!!A~Y9?x7YT0W0)h?@z&!^9Kp3j|MH2>uMhw8ApiF&yDYW2hFJ?fJhni{?u
z85&g@mo&yT8JcdI$(rSw=QPK(Xj%)k1X|@<=e1rim6`6$RAwc!i#egKuI;BS(LSWz
zt39n_sIypSqfWEV6J3%nTQ@<sT(?tqLQhLCSTA3%QSYHXQJ<}!q`ybMTYt*H&>-4i
zi$R;gsG*9XzhRzXqv2yCs*$VFDx+GXJH|L;wsDH_KI2;^u!)^Xl1YupO;gy^-c(?^
z&$Q1BYvyPsG^;hc$D**@Sy`+`)}T4VJji^bd7Jqw3q6Zii=7tT7GEswEK@D(EFW1Z
zSp`^awCb?>!`j4}Yh7b~$A)U-W3$et-R8BesV(1jzwLcHnq9En7Q0Tn&-M=XBKs!$
zF$X<|c!#|X_t<oHD7%Dx)e-CH;keH6jN=C<dnd8eNvGePS<WfW4bGzr3>WYh)GZit
z(Q)Cp9CDE^WG;+fcyOWARoj*0TI>4EP1lX*cEoMO-Pk?Z{kZ!p4@(b`M~lalr<3Oz
z&kJ6Nm#<fmSFg8{_hRpA@25UGK8Ze!J`=unzN>vN_+kA5{dW4@^Vjg_`q%qU1ULk&
z3Fr!>1V#i_2R;ij2@(Z$1jE4r!MlPVFVbHmT+|i<Li|H^g**v03|$raa~LixG^{4<
zdAL=0et35TEn-DPL&UpCkI2%<M~jUXOBQ!V$w$RS)kjT5dqtN;OP5$IS+nFuj9QE!
zracxP8x?ybc5<or(%nmk<Lu%J<L)jqT$Z!!+H$q!smsr<kYB-BaVj1gA06Ki|A`aA
zspU+r^k2Dm<pkH0yNCOd=f*4NjqzRhW&Du@mxQu}(L|TTU5R5!u1OV1;{s1XwcvHK
zU-E(Esg#hEqbW0~(W%X8gtYjy(?TU-im)qPGd(B0FT*sWFhjb^Y1Qsk6QV%TkxVFa
zS!TPKj{Z#bNQ@+#C4*TDvud*5XGdk9%2CV_=Je#6<ZjCy$@9tkel=z_cXemJcK(L^
z!8Pt{4y}dOu3X!>PIq0wy5aS{>yK?9ZAjVh%SOwMWgFjair&;wpi!{CU}&@N=Eg#~
zLQ&zpEzVmGY{hI9Z0+4<v#n~|mm*%#^<vB7isDZt+>-0xS$$Xe-OToc?Y*V;rTcf_
zb_jRe-RZjXSeas3UfIyD;9afd%<`i0x4T#DzE)vdabOQ=k7SRuGN`h>O0Q~1)u-yD
z>VX=Mn&!Rgd$;YK+Q-}1zu#?t(*cbG#Ronf6db&N$oEidtwC+YVcg-Y!_VuY>bk#Y
ze_ww@?MU&F&qswvrN_dLb=5o6*Egs)ls3YRlE$&)amR1{;Ppd$6RYV^Go!iq1UMl%
z@#4q$AMc(FJlT1QeX8jv{h#)>&{~RGq1N2iiMFIRX?sk2-|2wUogK~{EkB$8eDsX=
znVPf8XG_nK&J~=SIiGia@<PUi@r#KUhdNhuKDxBz(w(lbuHMUmm#<#&xpJx7z5D!C
zm#b&4IbAz_oqfIShW(A!9=o2FU+jKq>9y}|z3FhX{g&gcj=lwb=lWgyFW&aLedUh-
zof`v-2Kw$UzI*>(+&$@i-u=-BsSjR1%z8NeX#HdC<Dw@DPb!|OKdt@M_}6Bsz4Yv$
z*I>`Hh-Z(6xI-`hmHDqv!v)W&&nrf>M(RhcN6(D;jNN*%^u_SYjF;2ng}*8Ow)d6M
ztDk;%`@Lsk$;9w$(d(H%O5UixIr`T2ZRcd@<kNR)@201U-mAVp_JRGO`(yOSk?HJD
z_)nFejX!sM3H<VSCT(Ws-}i*``!YINegFUjfk{L`R9FekS#O9`RTTf-H}Acfbw?ZA
z5_ZXDYzV~_A)_#14P}u;gP4LPA^V~qB<VvR{8EHeTNGgt3?=$yGXhJbv?UO6iG_qz
z6l=jh475A31DhMGJI?gpoA++_zIBH8?t8N{_pLeZm$~<xbI<wRbKW`k-m?V4-<J1g
z`iP?M0ioL{MK2*FDTv(HDW$YT2qr<v8S0ovN8jxl_ZlFzN#DV7eTCM0h*0bUfl{MC
z&|eCN5_~yrO};gLu+QYSU4Sk)wfASXldTUFPy=Hua_6S2liN8+*Hf<N9ujb_*BBO#
z$sOPO=B~CatPQ*f9&X26ugoVzo4&b5;9S?i#isCVT}ZC2Jcdo3FC~kIk$FtPs%7&<
z!KhG7-Exq3^Dw$@j!j)uo$FL^U}qf9r(;OOf<Q{QZH)eE;PcB)kl6x-V<TIK=4cDD
z0g=oa9fz_yTB+i*1q1t!SttgyG$%wW$UPdqXb~KTkXjkXSG%<4XhI|+03;ZCC5}Wu
z8O2|PDz4^j%-R7alIb|!&IIYrC~7kSk-s#fVWSY&>TL_}<P2P>3lqFC*nw=uzyHmf
zH4Npgx>PFzzlIi8tXM8Cp*Z!O7aUhYkvm?&rHWsn+7-h(KdI?VwAOS1s)C4V<Cnh$
znmeWV{-O|Ty?!?dTM$Z<4sk$>9>YKn@W)hugA2c#_`1qK)izaeFcB16kRlDR%);mY
zBY5$(C9qCZkjo1^mMz2Q{nD~C=@1t$TevAi4lxDU!A|_RCxO?6#E=Cf%10{H-D~3b
zCfm5KRaq#{Uo>!d%#Ku?y&xk2<O=vn@(C-}DX%thY&*F0n}PR7ZOn<h7U$9-uIbHR
zGx74LWt_fl*K?r8tN*glKmA+>et0v1fzCQrY7p6jJ}bI{z1wu`>{F2pxiq-4wvCTI
ztKh8U4d?y<^q}3*AII)Z8XgS+`tP3xc6|FkpCleEp~I0e1A`ym#mRi|ij_!fcvUjg
zl68<^?+ZH8Y!&x|#=LaniizO~q5io?T^XgpCD`pNI|Rwb$sf95Ie;k@FKy6#H<@Kq
z9AKz!44<>GD-(y;h~y_I`B*ADm=&-*vCeDW&s^H2_`q?l?iXn~lPfc(gPSG4&O|r6
zj1Gik1k3CXw~O(lD9PnWV1s_^ff>c&GZy-VQ{>5KJ20}^#+3;hQ!^B)9u=Ebvv-QH
zzB*IIPj>}klWF7lG+0=?X5eH&MRukC>XdjShK=h(JXzO6apJfseWJ*P_@1%cF?NC!
zf@P$RB`}~EJ5|OJ@dFOX1qq8P)XzMnV}HMf$CG|<dd=J_SU7Upz}X1kxE`|QgFADJ
zdK)t(-6;hdRw+ocx5_^(iI%gEuQ<(aG|bCI*}CG{9q%2ohdXN?0&6{V>0xo!!AQi%
z`9j7xHidUK7ZPeKk6}}I+m*Mv+6pAh_<Z~AsKR@~yzLq$(@q-4#Id<$hWCVd+qIp5
zytdsIFvG-YE<oN3<~?C{C&{%n+&rudL#;o}0R{@#!}f28{{ZGhgjYt%CaM4c002ov
JPDHLkV1hi3a|8eY
new file mode 100644
index 0000000000000000000000000000000000000000..e0652efc729dcf260f02468e2d49c635bfae9d42
GIT binary patch
literal 4394
zc$@($5!LRAP)<h;3K|Lk000e1NJLTq002Ay002A)1^@s6I{evk000U>X+uL$Nkc;*
zP;zf(X>4Tx07wm;mUmQB*%pV-y*Itk5+Wca^cs2zAksTX6$DX<Nq|rShJ+?|L<L3^
z5h+$=RKNj8hazJ|6bplbV%G`s5KzX!QA9=M-HdAq@2xfS-kSZ#S>M^`x7XQc?|s+0
z08spb1j2M!0f022SQPH-!CVp(%f$Br7!UytSOLJ{W@ZFO_(THK{JlMynW#v{v-a*T
zfMmPdEWc1DbJqWVks>!kBnAKqMb$PuekK>?0+ds;#ThdH1j_W4DKdsJG8Ul;qO2n0
z#IJ1jr{*iW$(WZW<e?f_&KbNko{YOt-kK%hql^ThT$m-`XQO-vWxZ5MngHeZDAUvU
zoJ;^P6q#Sl=O&?Si84hL8SaVl0ssh<#5ufj4vYCYXr2Igrf1}e1c^yvrV-beY31n1
zX8Q57Q~6>sE0n`c;fQ!l&-AnmjxZO1uWyz`0VP>&nP`#itsL#`S=Q!g`M=rU9)45(
zJ;-|dRq-b5&z?byo>|{)?5r=n76A4nTALlSzLiw~v~31J<>9PP?;rs31pu_(obw)r
zY+jPY;tVGXi|p)da{-@gE-UCa`=5eu%D;v=_nFJ?`&K)q7e9d`Nfk3?MdhZarb|T3
z%nS~f&t(1g5dY)AIcd$w!z`Siz!&j_=v7hZlnI21XuE|xfmo0(WD10T)!}~_HYW!e
zew}L+XmwuzeT6wtxJd`dZ#@7*BLgIEKY9Xv>st^p3dp{^Xswa2bB{85{^$B13tWnB
z;Y>jyQ|9&zk7RNsqAVGs--K+z0uqo1bf5|}fi5rtEMN^BfHQCd-XH*kfJhJnmIE$G
z0%<@5vOzxB0181d*a3EfYH$G5fqKvcPJ%XY23!PJzzuK<41h;K3WmW;Fah3yX$XSw
z5EY_9s*o0>51B&N5F1(uc|$=^I1~fLLy3?Ol0f;;Ca4%HgQ}rJP(Ab`bQ-z{U4#0d
z2hboi2K@njgb|nm(_szR0JebHusa+GN5aeCM0gdP2N%HG;Yzp`J`T6S7vUT504#-H
z!jlL<$Or?`Mpy_N@kBz9SR?@vA#0H$qyni$nvf2p8@Y{0k#Xb$28W?xm>3qu8RLgp
zjNxKdVb)?wFx8l2m{v>|<~C*!GlBVnrDD~wrdTJeKXwT=5u1%I#8zOBU|X=4u>;s)
z>^mF|$G{ol9B_WP7+f-LHLe7=57&&lfa}8z;U@8Tyei%l?}87(bMRt(A-)QK9Dg3)
zj~~XrCy)tR1Z#p1A(kK{Y$Q|=8VKhI{e%(1G*N-5Pjn)N5P8I0VkxnX*g?EW941ba
z6iJ387g8iCnY4jaNopcpCOsy-A(P2EWJhusSwLP-t|XrzUnLKcKTwn?CKOLf97RIe
zPB}`sKzTrUL#0v;sBY9)s+hW+T2H-1eM)^VN0T#`^Oxhvt&^*fYnAJldnHel*Ozyf
zUoM{~Um<@={-*r60#U(0!Bc^wuvVc);k3d%g-J!4qLpHZVwz%!VuRu}#Ze`^l7W)9
z5>Kf>>9Eozr6C$Z)1`URxU@~QI@)F0FdauXr2Es8>BaOP=)Lp_WhG@><tXJG<r?L)
z%2EcxFktvIQW>R;lZ?BJkMlI<xzFRz+cvLhUjMu)mH8@eDtwh9m1dOzm5-`SRd3Z4
z)t#zss!!A~Y9?x7YT0W0)h?@z&!^9Kp3j|MH2>uMhw8ApiF&yDYW2hFJ?fJhni{?u
z85&g@mo&yT8JcdI$(rSw=QPK(Xj%)k1X|@<=e1rim6`6$RAwc!i#egKuI;BS(LSWz
zt39n_sIypSqfWEV6J3%nTQ@<sT(?tqLQhLCSTA3%QSYHXQJ<}!q`ybMTYt*H&>-4i
zi$R;gsG*9XzhRzXqv2yCs*$VFDx+GXJH|L;wsDH_KI2;^u!)^Xl1YupO;gy^-c(?^
z&$Q1BYvyPsG^;hc$D**@Sy`+`)}T4VJji^bd7Jqw3q6Zii=7tT7GEswEK@D(EFW1Z
zSp`^awCb?>!`j4}Yh7b~$A)U-W3$et-R8BesV(1jzwLcHnq9En7Q0Tn&-M=XBKs!$
zF$X<|c!#|X_t<oHD7%Dx)e-CH;keH6jN=C<dnd8eNvGePS<WfW4bGzr3>WYh)GZit
z(Q)Cp9CDE^WG;+fcyOWARoj*0TI>4EP1lX*cEoMO-Pk?Z{kZ!p4@(b`M~lalr<3Oz
z&kJ6Nm#<fmSFg8{_hRpA@25UGK8Ze!J`=unzN>vN_+kA5{dW4@^Vjg_`q%qU1ULk&
z3Fr!>1V#i_2R;ij2@(Z$1jE4r!MlPVFVbHmT+|i<Li|H^g**v03|$raa~LixG^{4<
zdAL=0et35TEn-DPL&UpCkI2%<M~jUXOBQ!V$w$RS)kjT5dqtN;OP5$IS+nFuj9QE!
zracxP8x?ybc5<or(%nmk<Lu%J<L)jqT$Z!!+H$q!smsr<kYB-BaVj1gA06Ki|A`aA
zspU+r^k2Dm<pkH0yNCOd=f*4NjqzRhW&Du@mxQu}(L|TTU5R5!u1OV1;{s1XwcvHK
zU-E(Esg#hEqbW0~(W%X8gtYjy(?TU-im)qPGd(B0FT*sWFhjb^Y1Qsk6QV%TkxVFa
zS!TPKj{Z#bNQ@+#C4*TDvud*5XGdk9%2CV_=Je#6<ZjCy$@9tkel=z_cXemJcK(L^
z!8Pt{4y}dOu3X!>PIq0wy5aS{>yK?9ZAjVh%SOwMWgFjair&;wpi!{CU}&@N=Eg#~
zLQ&zpEzVmGY{hI9Z0+4<v#n~|mm*%#^<vB7isDZt+>-0xS$$Xe-OToc?Y*V;rTcf_
zb_jRe-RZjXSeas3UfIyD;9afd%<`i0x4T#DzE)vdabOQ=k7SRuGN`h>O0Q~1)u-yD
z>VX=Mn&!Rgd$;YK+Q-}1zu#?t(*cbG#Ronf6db&N$oEidtwC+YVcg-Y!_VuY>bk#Y
ze_ww@?MU&F&qswvrN_dLb=5o6*Egs)ls3YRlE$&)amR1{;Ppd$6RYV^Go!iq1UMl%
z@#4q$AMc(FJlT1QeX8jv{h#)>&{~RGq1N2iiMFIRX?sk2-|2wUogK~{EkB$8eDsX=
znVPf8XG_nK&J~=SIiGia@<PUi@r#KUhdNhuKDxBz(w(lbuHMUmm#<#&xpJx7z5D!C
zm#b&4IbAz_oqfIShW(A!9=o2FU+jKq>9y}|z3FhX{g&gcj=lwb=lWgyFW&aLedUh-
zof`v-2Kw$UzI*>(+&$@i-u=-BsSjR1%z8NeX#HdC<Dw@DPb!|OKdt@M_}6Bsz4Yv$
z*I>`Hh-Z(6xI-`hmHDqv!v)W&&nrf>M(RhcN6(D;jNN*%^u_SYjF;2ng}*8Ow)d6M
ztDk;%`@Lsk$;9w$(d(H%O5UixIr`T2ZRcd@<kNR)@201U-mAVp_JRGO`(yOSk?HJD
z_)nFejX!sM3H<VSCT(Ws-}i*``!YINegFUlq)9|URA>d|TYGF%RT%%>+t<1cSaefa
zP!|v(I7yU%EM$pYCQ1;HV4|Y&k+8(5M2v)lpm7G!sEJ^7{vjBApd==n4kdshGfuNP
zLNGdXii-@$MuM8b*7bF7uiv?&-EDhM+uNSDcAli|d7t0!JLi1gcW&>IkR;sR{Pzsl
z?5ku+S`G=bG!4~~B$X#=lJ_D_(?%r;gV4|)*0cjqmG*C%uRO;CBAFE|X}(bHvb$b{
zBt1suHnTea;XD<ZwkMzjUiiMbYA_yW0%6bAODiE`uLNmIeC1+FYtTjz#zP&?Pu*|C
zEgKUJTQ9DsCHrZylVzM32gZeQGIEU0Fq>IcfojGG!C1K{;~HpdYpWwOtrKQ@*6DEd
zO@^5@n-sRZgQ37&wx{*kWD07sl4Sy5+;k<(;>`5O4(Dl#7n?RF$d-Z{4h3suW@o9{
zWGBlcW7B;K-Knr7sN${6xXR3fDqac}krP+@xVvbvVK&vBz;s8%8fqBz0wdY<XQ3_Q
zYR`vn+<1!vOKa_zbF~fSL^wW-j)rk&KtackA+!x>@x{W@jH}eJeI#ciEL`Zs#s()U
zEvQ8QMFo35@nhcwVLW3x$`N4+8`iq9f{Z|>;rLf$*mNwMX>)G7%n@<Bl(1!8Syp6O
z*9-0_#hZ2F;R)}tzOe)iS8=6bsbHSRjiw4qO;T1COSsI2rxqpOu;<T)aJVyo4>|%k
zdQ!o#nhc|adsjP>Rj^!Ux7;F0gN2JoL2=5Jiy^%BUI0hP3{8X(&@Q2AjT`sRF_*o4
zx|3!(gk8fEt+I)kkCIW35|+>7%&w|pTT49I$RHYawT@x;Z#)Gh;kKK_!4%gMxop!+
zY%HU7t|x%b2tUs6zSaQFah7-0wc=ok>#0n}b#8Muzn|gFp0U1)L#NGMf^stC(~VWL
zh>Igkx`n3@N~5l1a-=_}C79%Wq$=fMOw}&2ob->Ma?PIM&b^8DcAt{iCN8J9%ZGb@
zqD<;58kn%WnlOJ`+zfkF4EUljV<HuEO0XkMCt`#hCW3~KK(Y*!IKuQKygSK~obM?`
z>slx3%VK1a_k=*gK-<?rBr}&4HBK}?U5@wfbD~kO2bHemgc8QEf}K4a+hRa8W0n(}
zpD0J`x)L<iiiKbp#x$Cf)6yerO7Sqqb23E{45Ryp0N(0UF=SdnTxL!PGkEoNE<ERP
za7~pd1vQN0<fLrvP=#sb_;GT!o;te%xbtlvx`)znIxfSq$yiY5#%IsC@jz8PR59tC
z&9D*PlqwsZy~~AqOD-a5{ewPiIblIy#z8spybz9#P44HD9w(O0x0^aB(RzkR_kJ(7
z^qRYzhH7a?bGD>S5qQIB`NEG?FL}|@8A@>$9`9lC$`Ukk4ke~zq{z%K;V2jlZS)Xe
z%`2m5=~8r;G+LApv7u=h=h&H0H+4pV2u}cO>+oYaDYsJ`x0Kbaob5pEM3byy1t+Yd
zr{_G6?-;|MJfFpBL!BVcOw4JC0DZL4jcZI~fBc{qn@*&obi#P~O9k&NGlxXy2_Zqu
z4AT+L946qlNB&kxjklksIQ1bibw9~!h#^cz!$Hm-oH^Ut5In-76ty)pT+wOx<1h1N
zTT<h~hH7rZn1aT|c9g{AL=qZ;#)krt><oSd5e5$R@idNv74)}DN?Tg(!1`M`=EtYv
zyO_tj88E%vL>S@zW5J|acJszkY_GS0PKL38ysxIa-8lTHi|c)z|5ZVMY^#h@JYADP
zhhgmeR>2z{UY9Z!*SqNhC_xRwJ`HxKgbH^mr547=M|rEqI!s|R%!cmm^5gR%^Sx|@
z#)wu<lhYsz{6db&0Z}%IKnNwwNbTG+hQnu5lQs%~7e9Z}kM&(*PfNlHgC6F+`k@!E
z_b6G|R5}{c|HBWq^NbWvM5*(0dpsnCw298aOKzZ79XJX&2BNCrR9_J99t?qWU`~SM
z*>-6pAMbh8UQhn;OdD#hkTKOY!No_<od^F>(c7=$$e@_5FwuK#jJ<+LFSXFi)xeFh
zMdDMv14N2Gg$!g5hGh08c_BgMb!_4)>#xn{b=1NQ#<<GtjsQU@>{`o@3{=Kd)-OcR
z9fACeS-??<Bjc*uVRj)xzavmUJh>d2abq0W7&>A7_6J>vAO$AYt;r>ebo*wUh+E`_
zOVrcS?*wS!4U>vABTJkj_Z^sw5{@eWt7|+=0!$k0LIhoQ+D*w~)ZXl()^5hZIJ1l!
k3kfqko<06O8L#5~3mrKpj{Is>w*UYD07*qoM6N<$f?pec9{>OV
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/app-bundle/TestApp/TestApp-Info.plist
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.google.${PRODUCT_NAME}</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>ause</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+ <key>NSMainNibFile</key>
+ <string>MainMenu</string>
+ <key>NSPrincipalClass</key>
+ <string>NSApplication</string>
+</dict>
+</plist>
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/app-bundle/TestApp/check_no_signature.py
@@ -0,0 +1,13 @@
+#!/usr/bin/python
+
+import os
+import subprocess
+import sys
+
+p = os.path.join(os.environ['BUILT_PRODUCTS_DIR'],os.environ['EXECUTABLE_PATH'])
+proc = subprocess.Popen(['codesign', '-v', p],
+ stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
+o = proc.communicate()[0].strip()
+if "code object is not signed at all" not in o:
+ sys.stderr.write('File should not already be signed.')
+ sys.exit(1)
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/app-bundle/TestApp/main.m
@@ -0,0 +1,13 @@
+// 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.
+
+#import <UIKit/UIKit.h>
+
+int main(int argc, char *argv[])
+{
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+ int retVal = UIApplicationMain(argc, argv, nil, nil);
+ [pool release];
+ return retVal;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/app-bundle/TestApp/only-compile-in-32-bits.m
@@ -0,0 +1,7 @@
+// Copyright (c) 2013 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.
+
+#if defined(__LP64__)
+# error 64-bit build
+#endif
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/app-bundle/TestApp/only-compile-in-64-bits.m
@@ -0,0 +1,7 @@
+// Copyright (c) 2013 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.
+
+#if !defined(__LP64__)
+# error 32-bit build
+#endif
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/app-bundle/test-archs.gyp
@@ -0,0 +1,109 @@
+# Copyright (c) 2013 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.
+{
+ 'make_global_settings': [
+ ['CC', '/usr/bin/clang'],
+ ],
+ 'target_defaults': {
+ 'mac_bundle_resources': [
+ 'TestApp/English.lproj/InfoPlist.strings',
+ 'TestApp/English.lproj/MainMenu.xib',
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
+ '$(SDKROOT)/System/Library/Frameworks/UIKit.framework',
+ ],
+ },
+ 'xcode_settings': {
+ 'OTHER_CFLAGS': [
+ '-fobjc-abi-version=2',
+ ],
+ 'CODE_SIGNING_REQUIRED': 'NO',
+ 'SDKROOT': 'iphoneos', # -isysroot
+ 'TARGETED_DEVICE_FAMILY': '1,2',
+ 'INFOPLIST_FILE': 'TestApp/TestApp-Info.plist',
+ 'IPHONEOS_DEPLOYMENT_TARGET': '7.0',
+ 'CONFIGURATION_BUILD_DIR':'build/Default',
+ },
+ },
+ 'targets': [
+ {
+ 'target_name': 'TestNoArchs',
+ 'product_name': 'TestNoArchs',
+ 'type': 'executable',
+ 'mac_bundle': 1,
+ 'sources': [
+ 'TestApp/main.m',
+ 'TestApp/only-compile-in-32-bits.m',
+ ],
+ 'xcode_settings': {
+ 'VALID_ARCHS': [
+ 'i386',
+ 'x86_64',
+ 'arm64',
+ 'armv7',
+ ],
+ }
+ },
+ {
+ 'target_name': 'TestArch32Bits',
+ 'product_name': 'TestArch32Bits',
+ 'type': 'executable',
+ 'mac_bundle': 1,
+ 'sources': [
+ 'TestApp/main.m',
+ 'TestApp/only-compile-in-32-bits.m',
+ ],
+ 'xcode_settings': {
+ 'ARCHS': [
+ '$(ARCHS_STANDARD)',
+ ],
+ 'VALID_ARCHS': [
+ 'i386',
+ 'armv7',
+ ],
+ },
+ },
+ {
+ 'target_name': 'TestArch64Bits',
+ 'product_name': 'TestArch64Bits',
+ 'type': 'executable',
+ 'mac_bundle': 1,
+ 'sources': [
+ 'TestApp/main.m',
+ 'TestApp/only-compile-in-64-bits.m',
+ ],
+ 'xcode_settings': {
+ 'ARCHS': [
+ '$(ARCHS_STANDARD_INCLUDING_64_BIT)',
+ ],
+ 'VALID_ARCHS': [
+ 'x86_64',
+ 'arm64',
+ ],
+ },
+ },
+ {
+ 'target_name': 'TestMultiArchs',
+ 'product_name': 'TestMultiArchs',
+ 'type': 'executable',
+ 'mac_bundle': 1,
+ 'sources': [
+ 'TestApp/main.m',
+ ],
+ 'xcode_settings': {
+ 'ARCHS': [
+ '$(ARCHS_STANDARD_INCLUDING_64_BIT)',
+ ],
+ 'VALID_ARCHS': [
+ 'x86_64',
+ 'i386',
+ 'arm64',
+ 'armv7',
+ ],
+ }
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/app-bundle/test-assets-catalog.gyp
@@ -0,0 +1,45 @@
+# 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.
+{
+ 'conditions': [
+ ['"<(GENERATOR)"=="ninja"', {
+ 'make_global_settings': [
+ ['CC', '/usr/bin/clang'],
+ ['CXX', '/usr/bin/clang++'],
+ ],
+ }],
+ ],
+ 'targets': [
+ {
+ 'target_name': 'test_app',
+ 'product_name': 'Test App Assets Catalog Gyp',
+ 'type': 'executable',
+ 'mac_bundle': 1,
+ 'sources': [
+ 'TestApp/main.m',
+ ],
+ 'mac_bundle_resources': [
+ 'TestApp/English.lproj/InfoPlist.strings',
+ 'TestApp/English.lproj/MainMenu.xib',
+ 'TestApp/English.lproj/Main_iPhone.storyboard',
+ 'TestApp/Images.xcassets',
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
+ '$(SDKROOT)/System/Library/Frameworks/UIKit.framework',
+ ],
+ },
+ 'xcode_settings': {
+ 'OTHER_CFLAGS': [
+ '-fobjc-abi-version=2',
+ ],
+ 'INFOPLIST_FILE': 'TestApp/TestApp-Info.plist',
+ 'SDKROOT': 'iphonesimulator', # -isysroot
+ 'IPHONEOS_DEPLOYMENT_TARGET': '7.0',
+ 'CONFIGURATION_BUILD_DIR':'build/Default',
+ },
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/app-bundle/test-crosscompile.gyp
@@ -0,0 +1,47 @@
+# Copyright (c) 2014 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.
+{
+ 'make_global_settings': [
+ ['CC', '/usr/bin/clang'],
+ ],
+ 'targets': [
+ # This target will not be built, but is here so that ninja Xcode emulation
+ # understand this is a multi-platform (ios + mac) build.
+ {
+ 'target_name': 'TestDummy',
+ 'product_name': 'TestDummy',
+ 'toolsets': ['target'],
+ 'type': 'executable',
+ 'mac_bundle': 1,
+ 'sources': [
+ 'tool_main.cc',
+ ],
+ 'xcode_settings': {
+ 'SDKROOT': 'iphonesimulator', # -isysroot
+ 'TARGETED_DEVICE_FAMILY': '1,2',
+ 'IPHONEOS_DEPLOYMENT_TARGET': '7.0',
+ },
+ },
+ {
+ 'target_name': 'TestHost',
+ 'product_name': 'TestHost',
+ 'toolsets': ['host'],
+ 'type': 'executable',
+ 'mac_bundle': 0,
+ 'sources': [
+ 'tool_main.cc',
+ ],
+ 'xcode_settings': {
+ 'SDKROOT': 'macosx',
+ 'ARCHS': [
+ '$(ARCHS_STANDARD)',
+ 'x86_64',
+ ],
+ 'VALID_ARCHS': [
+ 'x86_64',
+ ],
+ }
+ }
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/app-bundle/test-device.gyp
@@ -0,0 +1,109 @@
+# 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.
+{
+ 'conditions': [
+ ['"<(GENERATOR)"=="xcode"', {
+ 'target_defaults': {
+ 'configurations': {
+ 'Default': {
+ 'xcode_settings': {
+ 'SDKROOT': 'iphonesimulator',
+ 'CONFIGURATION_BUILD_DIR':'build/Default',
+ }
+ },
+ 'Default-iphoneos': {
+ 'xcode_settings': {
+ 'SDKROOT': 'iphoneos',
+ 'CONFIGURATION_BUILD_DIR':'build/Default-iphoneos',
+ }
+ },
+ },
+ },
+ }, {
+ 'target_defaults': {
+ 'configurations': {
+ 'Default': {
+ 'xcode_settings': {
+ 'SDKROOT': 'iphonesimulator',
+ }
+ },
+ },
+ },
+ }],
+ ],
+ 'targets': [
+ {
+ 'target_name': 'test_app',
+ 'product_name': 'Test App Gyp',
+ 'type': 'executable',
+ 'mac_bundle': 1,
+ 'sources': [
+ 'TestApp/main.m',
+ ],
+ 'mac_bundle_resources': [
+ 'TestApp/English.lproj/InfoPlist.strings',
+ 'TestApp/English.lproj/MainMenu.xib',
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
+ '$(SDKROOT)/System/Library/Frameworks/UIKit.framework',
+ ],
+ },
+ 'xcode_settings': {
+ 'OTHER_CFLAGS': [
+ '-fobjc-abi-version=2',
+ ],
+ 'SDKROOT': 'iphonesimulator', # -isysroot
+ 'TARGETED_DEVICE_FAMILY': '1,2',
+ 'INFOPLIST_OUTPUT_FORMAT':'xml',
+ 'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0',
+ 'INFOPLIST_FILE': 'TestApp/TestApp-Info.plist',
+ 'IPHONEOS_DEPLOYMENT_TARGET': '8.0',
+ 'CODE_SIGNING_REQUIRED': 'NO',
+ 'CODE_SIGN_IDENTITY[sdk=iphoneos*]': '',
+
+ },
+ },
+ {
+ 'target_name': 'sig_test',
+ 'product_name': 'sigtest',
+ 'type': 'executable',
+ 'mac_bundle': 1,
+ 'sources': [
+ 'TestApp/main.m',
+ ],
+ 'mac_bundle_resources': [
+ 'TestApp/English.lproj/InfoPlist.strings',
+ 'TestApp/English.lproj/MainMenu.xib',
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
+ '$(SDKROOT)/System/Library/Frameworks/UIKit.framework',
+ ],
+ },
+ 'postbuilds': [
+ {
+ 'postbuild_name': 'Verify no signature',
+ 'action': [
+ 'python',
+ 'TestApp/check_no_signature.py'
+ ],
+ },
+ ],
+ 'xcode_settings': {
+ 'OTHER_CFLAGS': [
+ '-fobjc-abi-version=2',
+ ],
+ 'SDKROOT': 'iphonesimulator', # -isysroot
+ 'CODE_SIGN_IDENTITY[sdk=iphoneos*]': 'iPhone Developer',
+ 'INFOPLIST_OUTPUT_FORMAT':'xml',
+ 'INFOPLIST_FILE': 'TestApp/TestApp-Info.plist',
+ 'IPHONEOS_DEPLOYMENT_TARGET': '8.0',
+ 'CONFIGURATION_BUILD_DIR':'buildsig/Default',
+ },
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/app-bundle/test.gyp
@@ -0,0 +1,75 @@
+# 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.
+{
+ 'conditions': [
+ ['"<(GENERATOR)"=="ninja"', {
+ 'make_global_settings': [
+ ['CC', '/usr/bin/clang'],
+ ['CXX', '/usr/bin/clang++'],
+ ],
+ }],
+ ],
+ 'targets': [
+ {
+ 'target_name': 'test_app',
+ 'product_name': 'Test App Gyp',
+ 'type': 'executable',
+ 'mac_bundle': 1,
+ 'sources': [
+ 'TestApp/main.m',
+ ],
+ 'mac_bundle_resources': [
+ 'TestApp/English.lproj/InfoPlist.strings',
+ 'TestApp/English.lproj/LanguageMap.plist',
+ 'TestApp/English.lproj/MainMenu.xib',
+ 'TestApp/English.lproj/Main_iPhone.storyboard',
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
+ '$(SDKROOT)/System/Library/Frameworks/UIKit.framework',
+ ],
+ },
+ 'xcode_settings': {
+ 'OTHER_CFLAGS': [
+ '-fobjc-abi-version=2',
+ ],
+ 'INFOPLIST_FILE': 'TestApp/TestApp-Info.plist',
+ 'SDKROOT': 'iphonesimulator', # -isysroot
+ 'IPHONEOS_DEPLOYMENT_TARGET': '5.0',
+ 'CONFIGURATION_BUILD_DIR':'build/Default',
+ },
+ },
+ {
+ 'target_name': 'test_app_xml',
+ 'product_name': 'Test App Gyp XML',
+ 'type': 'executable',
+ 'mac_bundle': 1,
+ 'sources': [
+ 'TestApp/main.m',
+ ],
+ 'mac_bundle_resources': [
+ 'TestApp/English.lproj/InfoPlist.strings',
+ 'TestApp/English.lproj/MainMenu.xib',
+ 'TestApp/English.lproj/Main_iPhone.storyboard',
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
+ '$(SDKROOT)/System/Library/Frameworks/UIKit.framework',
+ ],
+ },
+ 'xcode_settings': {
+ 'OTHER_CFLAGS': [
+ '-fobjc-abi-version=2',
+ ],
+ 'INFOPLIST_FILE': 'TestApp/TestApp-Info.plist',
+ 'INFOPLIST_OUTPUT_FORMAT':'xml',
+ 'SDKROOT': 'iphonesimulator', # -isysroot
+ 'IPHONEOS_DEPLOYMENT_TARGET': '5.0',
+ 'CONFIGURATION_BUILD_DIR':'build/Default',
+ },
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/app-bundle/tool_main.cc
@@ -0,0 +1,7 @@
+// Copyright (c) 2014 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 main() {
+ return 0;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/copies-with-xcode-envvars/Info.plist
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIdentifier</key>
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+</dict>
+</plist>
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/copies-with-xcode-envvars/copies-with-xcode-envvars.gyp
@@ -0,0 +1,97 @@
+# Copyright (c) 2016 Mark Callow. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#
+# For testing use of the UI settings & environment variables
+# available in Xcode's PBXCopyFilesBuildPhase.
+{
+ 'targets': [
+ {
+ 'target_name': 'copies-with-xcode-envvars',
+ 'type': 'executable',
+ 'mac_bundle': 1,
+ 'xcode_settings': {
+ 'SDKROOT': 'iphoneos',
+ 'TARGETED_DEVICE_FAMILY': '1,2',
+ 'IPHONEOS_DEPLOYMENT_TARGET': '7.0',
+ 'CODE_SIGNING_REQUIRED': 'NO',
+ 'INFOPLIST_FILE': 'Info.plist',
+ # This is where the test framework looks for results. Without
+ # this line the result will be in build/Default-iphoneos.
+ 'CONFIGURATION_BUILD_DIR':'build/Default',
+ },
+ 'sources': [ 'empty.c' ],
+ 'conditions': [
+ ['OS == "ios" or OS == "mac"', {
+ 'copies': [{
+ 'destination': '$(BUILT_PRODUCTS_DIR)',
+ 'files': [
+ 'file0',
+ ],
+ }, {
+ 'destination': '$(BUILT_PRODUCTS_DIR)/$(WRAPPER_NAME)',
+ 'files': [
+ 'file1',
+ ],
+ }, {
+ 'destination': '<(PRODUCT_DIR)/$(EXECUTABLE_FOLDER_PATH)',
+ 'files': [
+ 'file2',
+ ],
+ }, {
+ 'destination': '<(PRODUCT_DIR)/$(UNLOCALIZED_RESOURCES_FOLDER_PATH)',
+ 'files': [
+ 'file3',
+ ],
+ }, {
+ 'destination': '<(PRODUCT_DIR)/$(UNLOCALIZED_RESOURCES_FOLDER_PATH)/testimages',
+ 'files': [
+ 'file4',
+ ],
+ }, {
+ 'destination': '$(BUILT_PRODUCTS_DIR)/$(JAVA_FOLDER_PATH)',
+ 'files': [
+ 'file5',
+ ],
+ }, {
+ 'destination': '<(PRODUCT_DIR)/$(FRAMEWORKS_FOLDER_PATH)',
+ 'files': [
+ 'file6',
+ ],
+ }, {
+ # NOTE: This is not an Xcode macro name but
+ # xcodeproj_file.py recognizes it and sends
+ # the output to the same place as
+ # $(FRAMEWORKS_FOLDER_PATH). xcode_emulation.py
+ # sets its value to an absolute path.
+ 'destination': '$(BUILT_FRAMEWORKS_DIR)',
+ 'files': [
+ 'file7',
+ ],
+ }, {
+ 'destination': '<(PRODUCT_DIR)/$(SHARED_FRAMEWORKS_FOLDER_PATH)',
+ 'files': [
+ 'file8',
+ ],
+ }, {
+ 'destination': '<(PRODUCT_DIR)/$(SHARED_SUPPORT_FOLDER_PATH)',
+ 'files': [
+ 'file9',
+ ],
+ }, {
+ 'destination': '<(PRODUCT_DIR)/$(PLUGINS_FOLDER_PATH)',
+ 'files': [
+ 'file10',
+ ],
+ }, {
+ 'destination': '<(PRODUCT_DIR)/$(XPCSERVICES_FOLDER_PATH)',
+ 'files': [
+ 'file11',
+ ],
+ }], # copies
+ }], # OS == "ios" or OS == "mac"
+ ], # conditions
+ }], # targets
+}
+
+# vim:ai:ts=4:sts=4:sw=2:expandtab:textwidth=70
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/copies-with-xcode-envvars/empty.c
@@ -0,0 +1,1 @@
+int main() {}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/copies-with-xcode-envvars/file0
@@ -0,0 +1,1 @@
+file0 contents
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/copies-with-xcode-envvars/file1
@@ -0,0 +1,1 @@
+file1 contents
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/copies-with-xcode-envvars/file10
@@ -0,0 +1,1 @@
+file10 contents
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/copies-with-xcode-envvars/file11
@@ -0,0 +1,1 @@
+file11 contents
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/copies-with-xcode-envvars/file2
@@ -0,0 +1,1 @@
+file2 contents
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/copies-with-xcode-envvars/file3
@@ -0,0 +1,1 @@
+file3 contents
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/copies-with-xcode-envvars/file4
@@ -0,0 +1,1 @@
+file4 contents
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/copies-with-xcode-envvars/file5
@@ -0,0 +1,1 @@
+file5 contents
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/copies-with-xcode-envvars/file6
@@ -0,0 +1,1 @@
+file6 contents
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/copies-with-xcode-envvars/file7
@@ -0,0 +1,1 @@
+file7 contents
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/copies-with-xcode-envvars/file8
@@ -0,0 +1,1 @@
+file8 contents
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/copies-with-xcode-envvars/file9
@@ -0,0 +1,1 @@
+file9 contents
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/deployment-target/check-version-min.c
@@ -0,0 +1,33 @@
+/* Copyright (c) 2013 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 <Availability.h>
+
+/* GYPTEST_MAC_VERSION_MIN: should be set to the corresponding value of
+ * xcode setting 'MACOSX_DEPLOYMENT_TARGET', otherwise both should be
+ * left undefined.
+ *
+ * GYPTEST_IOS_VERSION_MIN: should be set to the corresponding value of
+ * xcode setting 'IPHONEOS_DEPLOYMENT_TARGET', otherwise both should be
+ * left undefined.
+ */
+
+#if defined(GYPTEST_MAC_VERSION_MIN)
+# if GYPTEST_MAC_VERSION_MIN != __MAC_OS_X_VERSION_MIN_REQUIRED
+# error __MAC_OS_X_VERSION_MIN_REQUIRED has wrong value
+# endif
+#elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
+# error __MAC_OS_X_VERSION_MIN_REQUIRED should be undefined
+#endif
+
+#if defined(GYPTEST_IOS_VERSION_MIN)
+# if GYPTEST_IOS_VERSION_MIN != __IPHONE_OS_VERSION_MIN_REQUIRED
+# error __IPHONE_OS_VERSION_MIN_REQUIRED has wrong value
+# endif
+#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
+# error __IPHONE_OS_VERSION_MIN_REQUIRED should be undefined
+#endif
+
+int main() { return 0; }
+
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/deployment-target/deployment-target.gyp
@@ -0,0 +1,34 @@
+# Copyright (c) 2013 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.
+{
+ 'make_global_settings': [
+ ['CC', '/usr/bin/clang'],
+ ['CXX', '/usr/bin/clang++'],
+ ],
+ 'targets': [
+ {
+ 'target_name': 'version-min-4.3',
+ 'type': 'static_library',
+ 'sources': [ 'check-version-min.c', ],
+ 'defines': [ 'GYPTEST_IOS_VERSION_MIN=40300', ],
+ 'xcode_settings': {
+ 'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0',
+ 'SDKROOT': 'iphoneos',
+ 'IPHONEOS_DEPLOYMENT_TARGET': '4.3',
+ },
+ },
+ {
+ 'target_name': 'version-min-5.0',
+ 'type': 'static_library',
+ 'sources': [ 'check-version-min.c', ],
+ 'defines': [ 'GYPTEST_IOS_VERSION_MIN=50000', ],
+ 'xcode_settings': {
+ 'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0',
+ 'SDKROOT': 'iphoneos',
+ 'IPHONEOS_DEPLOYMENT_TARGET': '5.0',
+ },
+ }
+ ],
+}
+
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/extension/ActionExtension/ActionViewController.h
@@ -0,0 +1,9 @@
+// Copyright (c) 2014 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.
+
+#import <UIKit/UIKit.h>
+
+@interface ActionViewController : UIViewController
+
+@end
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/extension/ActionExtension/ActionViewController.m
@@ -0,0 +1,31 @@
+// Copyright (c) 2014 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.
+
+#import "ActionViewController.h"
+#import <MobileCoreServices/MobileCoreServices.h>
+
+@interface ActionViewController ()
+
+@end
+
+@implementation ActionViewController
+
+- (void)viewDidLoad {
+ [super viewDidLoad];
+}
+
+- (void)didReceiveMemoryWarning {
+ [super didReceiveMemoryWarning];
+ // Dispose of any resources that can be recreated.
+}
+
+- (IBAction)done {
+ // Return any edited content to the host app.
+ // This template doesn't do anything, so we just echo the passed in items.
+ [self.extensionContext
+ completeRequestReturningItems:self.extensionContext.inputItems
+ completionHandler:nil];
+}
+
+@end
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/extension/ActionExtension/Info.plist
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleDisplayName</key>
+ <string>ActionExtension</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.google.gyptest.extension.ActionExtension</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>XPC!</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+ <key>NSExtension</key>
+ <dict>
+ <key>NSExtensionAttributes</key>
+ <dict>
+ <key>NSExtensionActivationRule</key>
+ <string>TRUEPREDICATE</string>
+ <key>NSExtensionPointName</key>
+ <string>com.apple.ui-services</string>
+ <key>NSExtensionPointVersion</key>
+ <string>1.0</string>
+ </dict>
+ <key>NSExtensionMainStoryboard</key>
+ <string>MainInterface</string>
+ <key>NSExtensionPointIdentifier</key>
+ <string>com.apple.ui-services</string>
+ </dict>
+</dict>
+</plist>
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/extension/ActionExtension/MainInterface.storyboard
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6148" systemVersion="14A229a" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" initialViewController="ObA-dk-sSI">
+ <dependencies>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6147"/>
+ </dependencies>
+ <scenes>
+ <!--Action View Controller - Image-->
+ <scene sceneID="7MM-of-jgj">
+ <objects>
+ <viewController title="Image" id="ObA-dk-sSI" customClass="ActionViewController" customModuleProvider="" sceneMemberID="viewController">
+ <layoutGuides>
+ <viewControllerLayoutGuide type="top" id="qkL-Od-lgU"/>
+ <viewControllerLayoutGuide type="bottom" id="n38-gi-rB5"/>
+ </layoutGuides>
+ <view key="view" contentMode="scaleToFill" id="zMn-AG-sqS">
+ <rect key="frame" x="0.0" y="0.0" width="320" height="528"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <subviews>
+ <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="9ga-4F-77Z">
+ <rect key="frame" x="0.0" y="64" width="320" height="464"/>
+ </imageView>
+ <navigationBar contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="NOA-Dm-cuz">
+ <rect key="frame" x="0.0" y="20" width="320" height="44"/>
+ <items>
+ <navigationItem id="3HJ-uW-3hn">
+ <barButtonItem key="leftBarButtonItem" title="Done" style="done" id="WYi-yp-eM6">
+ <connections>
+ <action selector="done" destination="ObA-dk-sSI" id="Qdu-qn-U6V"/>
+ </connections>
+ </barButtonItem>
+ </navigationItem>
+ </items>
+ </navigationBar>
+ </subviews>
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+ <constraints>
+ <constraint firstAttribute="trailing" secondItem="NOA-Dm-cuz" secondAttribute="trailing" id="A05-Pj-hrr"/>
+ <constraint firstItem="9ga-4F-77Z" firstAttribute="top" secondItem="NOA-Dm-cuz" secondAttribute="bottom" id="Fps-3D-QQW"/>
+ <constraint firstItem="NOA-Dm-cuz" firstAttribute="leading" secondItem="zMn-AG-sqS" secondAttribute="leading" id="HxO-8t-aoh"/>
+ <constraint firstAttribute="trailing" secondItem="9ga-4F-77Z" secondAttribute="trailing" id="Ozw-Hg-0yh"/>
+ <constraint firstItem="9ga-4F-77Z" firstAttribute="leading" secondItem="zMn-AG-sqS" secondAttribute="leading" id="XH5-ld-ONA"/>
+ <constraint firstItem="n38-gi-rB5" firstAttribute="top" secondItem="9ga-4F-77Z" secondAttribute="bottom" id="eQg-nn-Zy4"/>
+ <constraint firstItem="NOA-Dm-cuz" firstAttribute="top" secondItem="qkL-Od-lgU" secondAttribute="bottom" id="we0-1t-bgp"/>
+ </constraints>
+ </view>
+ <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
+ <size key="freeformSize" width="320" height="528"/>
+ <connections>
+ <outlet property="imageView" destination="9ga-4F-77Z" id="5y6-5w-9QO"/>
+ <outlet property="view" destination="zMn-AG-sqS" id="Qma-de-2ek"/>
+ </connections>
+ </viewController>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="X47-rx-isc" userLabel="First Responder" sceneMemberID="firstResponder"/>
+ </objects>
+ <point key="canvasLocation" x="252" y="-124"/>
+ </scene>
+ </scenes>
+ <simulatedMetricsContainer key="defaultSimulatedMetrics">
+ <simulatedStatusBarMetrics key="statusBar"/>
+ <simulatedOrientationMetrics key="orientation"/>
+ <simulatedScreenMetrics key="destination" type="retina4"/>
+ </simulatedMetricsContainer>
+</document>
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/extension/ExtensionContainer/AppDelegate.h
@@ -0,0 +1,12 @@
+// Copyright (c) 2014 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.
+
+#import <UIKit/UIKit.h>
+
+@interface AppDelegate : UIResponder <UIApplicationDelegate>
+
+@property (strong, nonatomic) UIWindow *window;
+
+@end
+
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/extension/ExtensionContainer/AppDelegate.m
@@ -0,0 +1,19 @@
+// Copyright (c) 2014 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.
+
+#import "AppDelegate.h"
+
+@interface AppDelegate ()
+
+@end
+
+@implementation AppDelegate
+
+- (BOOL)application:(UIApplication*)application
+ didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
+ // Override point for customization after application launch.
+ return YES;
+}
+
+@end
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/extension/ExtensionContainer/Base.lproj/Main.storyboard
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6162" systemVersion="14A238h" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
+ <dependencies>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6160"/>
+ </dependencies>
+ <scenes>
+ <!--View Controller-->
+ <scene sceneID="tne-QT-ifu">
+ <objects>
+ <viewController id="BYZ-38-t0r" customClass="ViewController" customModuleProvider="" sceneMemberID="viewController">
+ <layoutGuides>
+ <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
+ <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
+ </layoutGuides>
+ <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
+ <rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
+ </view>
+ </viewController>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
+ </objects>
+ </scene>
+ </scenes>
+</document>
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/extension/ExtensionContainer/Images.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,53 @@
+{
+ "images" : [
+ {
+ "idiom" : "iphone",
+ "size" : "29x29",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "40x40",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "60x60",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "29x29",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "29x29",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "40x40",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "40x40",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "76x76",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "76x76",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/extension/ExtensionContainer/Images.xcassets/LaunchImage.launchimage/Contents.json
@@ -0,0 +1,51 @@
+{
+ "images" : [
+ {
+ "orientation" : "portrait",
+ "idiom" : "iphone",
+ "extent" : "full-screen",
+ "minimum-system-version" : "7.0",
+ "scale" : "2x"
+ },
+ {
+ "orientation" : "portrait",
+ "idiom" : "iphone",
+ "subtype" : "retina4",
+ "extent" : "full-screen",
+ "minimum-system-version" : "7.0",
+ "scale" : "2x"
+ },
+ {
+ "orientation" : "portrait",
+ "idiom" : "ipad",
+ "extent" : "full-screen",
+ "minimum-system-version" : "7.0",
+ "scale" : "1x"
+ },
+ {
+ "orientation" : "landscape",
+ "idiom" : "ipad",
+ "extent" : "full-screen",
+ "minimum-system-version" : "7.0",
+ "scale" : "1x"
+ },
+ {
+ "orientation" : "portrait",
+ "idiom" : "ipad",
+ "extent" : "full-screen",
+ "minimum-system-version" : "7.0",
+ "scale" : "2x"
+ },
+ {
+ "orientation" : "landscape",
+ "idiom" : "ipad",
+ "extent" : "full-screen",
+ "minimum-system-version" : "7.0",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/extension/ExtensionContainer/Info.plist
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleExecutable</key>
+ <string>ExtensionContainer</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.google.gyptest.extension</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+ <key>LSRequiresIPhoneOS</key>
+ <true/>
+ <key>UIMainStoryboardFile</key>
+ <string>Main</string>
+ <key>UIRequiredDeviceCapabilities</key>
+ <array>
+ <string>armv7</string>
+ </array>
+</dict>
+</plist>
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/extension/ExtensionContainer/ViewController.h
@@ -0,0 +1,11 @@
+// Copyright (c) 2014 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.
+
+#import <UIKit/UIKit.h>
+
+@interface ViewController : UIViewController
+
+
+@end
+
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/extension/ExtensionContainer/ViewController.m
@@ -0,0 +1,24 @@
+// Copyright (c) 2014 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.
+
+#import "ViewController.h"
+
+@interface ViewController ()
+
+
+@end
+
+@implementation ViewController
+
+- (void)viewDidLoad {
+ [super viewDidLoad];
+ // Do any additional setup after loading the view, typically from a nib.
+}
+
+- (void)didReceiveMemoryWarning {
+ [super didReceiveMemoryWarning];
+ // Dispose of any resources that can be recreated.
+}
+
+@end
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/extension/ExtensionContainer/main.m
@@ -0,0 +1,13 @@
+// Copyright (c) 2014 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.
+//
+#import <UIKit/UIKit.h>
+#import "AppDelegate.h"
+
+int main(int argc, char* argv[]) {
+ @autoreleasepool {
+ return UIApplicationMain(argc, argv, nil,
+ NSStringFromClass([AppDelegate class]));
+ }
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/extension/extension.gyp
@@ -0,0 +1,91 @@
+# Copyright (c) 2014 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.
+
+{
+ 'make_global_settings': [
+ ['CC', '/usr/bin/clang'],
+ ['CXX', '/usr/bin/clang++'],
+ ],
+ 'targets': [
+ {
+ 'target_name': 'ExtensionContainer',
+ 'product_name': 'ExtensionContainer',
+ 'type': 'executable',
+ 'mac_bundle': 1,
+ 'mac_bundle_resources': [
+ 'ExtensionContainer/Base.lproj/Main.storyboard',
+ ],
+ 'sources': [
+ 'ExtensionContainer/AppDelegate.h',
+ 'ExtensionContainer/AppDelegate.m',
+ 'ExtensionContainer/ViewController.h',
+ 'ExtensionContainer/ViewController.m',
+ 'ExtensionContainer/main.m',
+ ],
+ 'copies': [
+ {
+ 'destination': '<(PRODUCT_DIR)/ExtensionContainer.app/PlugIns',
+ 'files': [
+ '<(PRODUCT_DIR)/ActionExtension.appex',
+ ]}],
+ 'dependencies': [
+ 'ActionExtension'
+ ],
+
+ 'link_settings': {
+ 'libraries': [
+ '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
+ '$(SDKROOT)/System/Library/Frameworks/UIKit.framework',
+ ],
+ },
+ 'xcode_settings': {
+ 'OTHER_CFLAGS': [
+ '-fobjc-abi-version=2',
+ ],
+ 'INFOPLIST_FILE': 'ExtensionContainer/Info.plist',
+ 'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0',
+ 'ARCHS': [ 'armv7' ],
+ 'SDKROOT': 'iphoneos',
+ 'IPHONEOS_DEPLOYMENT_TARGET': '7.0',
+ 'CODE_SIGNING_REQUIRED': 'NO',
+ 'DEPLOYMENT_POSTPROCESSING': 'YES',
+ 'STRIP_INSTALLED_PRODUCT': 'YES',
+ 'CONFIGURATION_BUILD_DIR':'build/Default',
+ },
+ },
+ {
+ 'target_name': 'ActionExtension',
+ 'product_name': 'ActionExtension',
+ 'type': 'executable',
+ 'mac_bundle': 1,
+ 'ios_app_extension': 1,
+ 'sources': [
+ 'ActionExtension/ActionViewController.h',
+ 'ActionExtension/ActionViewController.m',
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
+ '$(SDKROOT)/System/Library/Frameworks/UIKit.framework',
+ '$(SDKROOT)/System/Library/Frameworks/MobileCoreServices.framework',
+ ],
+ },
+ 'xcode_settings': {
+ 'OTHER_CFLAGS': [
+ '-fobjc-abi-version=2',
+ ],
+ 'INFOPLIST_FILE': 'ActionExtension/Info.plist',
+ 'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0',
+ 'ARCHS': [ 'armv7' ],
+ 'SDKROOT': 'iphoneos',
+ 'IPHONEOS_DEPLOYMENT_TARGET': '7.0',
+ 'CODE_SIGNING_REQUIRED': 'NO',
+ 'DEPLOYMENT_POSTPROCESSING': 'YES',
+ 'STRIP_INSTALLED_PRODUCT': 'YES',
+ 'CONFIGURATION_BUILD_DIR':'build/Default',
+ },
+ },
+ ],
+}
+
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/framework/framework.gyp
@@ -0,0 +1,43 @@
+# Copyright 2016 The Chromium Authors. 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': 'iOSFramework',
+ 'type': 'shared_library',
+ 'mac_bundle': 1,
+ 'sources': [
+ 'iOSFramework/iOSFramework.h',
+ 'iOSFramework/Thing.h',
+ 'iOSFramework/Thing.m',
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
+ '$(SDKROOT)/System/Library/Frameworks/UIKit.framework',
+ ],
+ },
+ 'mac_framework_headers': [
+ # Using two headers here tests mac_tool.py NextGreaterPowerOf2.
+ 'iOSFramework/iOSFramework.h',
+ 'iOSFramework/Thing.h',
+ ],
+ 'mac_framework_dirs': [
+ '$(SDKROOT)/../../Library/Frameworks',
+ ],
+ 'xcode_settings': {
+ 'OTHER_CFLAGS': [
+ '-fobjc-abi-version=2',
+ ],
+ 'INFOPLIST_FILE': 'iOSFramework/Info.plist',
+ 'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0',
+ 'SDKROOT': 'iphoneos',
+ 'IPHONEOS_DEPLOYMENT_TARGET': '8.0',
+ 'CONFIGURATION_BUILD_DIR':'build/Default',
+ 'CODE_SIGN_IDENTITY[sdk=iphoneos*]': 'iPhone Developer',
+ },
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/framework/iOSFramework/Info.plist
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleExecutable</key>
+ <string>$(EXECUTABLE_NAME)</string>
+ <key>CFBundleIdentifier</key>
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>$(PRODUCT_NAME)</string>
+ <key>CFBundlePackageType</key>
+ <string>FMWK</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>$(CURRENT_PROJECT_VERSION)</string>
+ <key>NSPrincipalClass</key>
+ <string></string>
+</dict>
+</plist>
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/framework/iOSFramework/Thing.h
@@ -0,0 +1,10 @@
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+@interface Thing : NSObject
+
++ (instancetype)thing;
+
+- (void)sayHello;
+
+@end
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/framework/iOSFramework/Thing.m
@@ -0,0 +1,22 @@
+#import "Thing.h"
+
+@interface Thing ()
+
+@end
+
+@implementation Thing
+
++ (instancetype)thing {
+ static Thing* thing = nil;
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ thing = [[[self class] alloc] init];
+ });
+ return thing;
+}
+
+- (void)sayHello {
+ NSLog(@"Hello World");
+}
+
+@end
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/framework/iOSFramework/iOSFramework.h
@@ -0,0 +1,9 @@
+#import <UIKit/UIKit.h>
+
+//! Project version number for iOSFramework.
+FOUNDATION_EXPORT double iOSFrameworkVersionNumber;
+
+//! Project version string for iOSFramework.
+FOUNDATION_EXPORT const unsigned char iOSFrameworkVersionString[];
+
+#import <iOSFramework/Thing.h>
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/gyptest-app-ios-assets-catalog.py
@@ -0,0 +1,57 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 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.
+
+"""
+Verifies that ios app bundles are built correctly.
+"""
+
+import TestGyp
+import TestMac
+
+import os.path
+import sys
+
+# Xcode supports for assets catalog was introduced in Xcode 6.0
+if sys.platform == 'darwin' and TestMac.Xcode.Version() >= '0600':
+ test_gyp_path = 'test-assets-catalog.gyp'
+ test_app_path = 'Test App Assets Catalog Gyp.app'
+
+ test = TestGyp.TestGyp(formats=['xcode', 'ninja'])
+ test.run_gyp(test_gyp_path, chdir='app-bundle')
+ test.build(test_gyp_path, test.ALL, chdir='app-bundle')
+
+ # Test that the extension is .bundle
+ test.built_file_must_exist(
+ os.path.join(test_app_path, 'Test App Assets Catalog Gyp'),
+ chdir='app-bundle')
+
+ # Info.plist
+ info_plist = test.built_file_path(
+ os.path.join(test_app_path, 'Info.plist'),
+ chdir='app-bundle')
+ # Resources
+ test.built_file_must_exist(
+ os.path.join(test_app_path, 'English.lproj/InfoPlist.strings'),
+ chdir='app-bundle')
+ test.built_file_must_exist(
+ os.path.join(test_app_path, 'English.lproj/MainMenu.nib'),
+ chdir='app-bundle')
+ test.built_file_must_exist(
+ os.path.join(test_app_path, 'English.lproj/Main_iPhone.storyboardc'),
+ chdir='app-bundle')
+ test.built_file_must_exist(
+ os.path.join(test_app_path, 'Assets.car'),
+ chdir='app-bundle')
+
+ # Packaging
+ test.built_file_must_exist(
+ os.path.join(test_app_path, 'PkgInfo'),
+ chdir='app-bundle')
+ test.built_file_must_match(
+ os.path.join(test_app_path, 'PkgInfo'), 'APPLause',
+ chdir='app-bundle')
+
+ test.pass_test()
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/gyptest-app-ios.py
@@ -0,0 +1,77 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 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.
+
+"""
+Verifies that ios app bundles are built correctly.
+"""
+
+import TestGyp
+
+import subprocess
+import sys
+
+def CheckFileXMLPropertyList(file):
+ output = subprocess.check_output(['file', file])
+ # The double space after XML is intentional.
+ if not 'XML document text' in output:
+ print 'File: Expected XML document text, got %s' % output
+ test.fail_test()
+
+def CheckFileBinaryPropertyList(file):
+ output = subprocess.check_output(['file', file])
+ if not 'Apple binary property list' in output:
+ print 'File: Expected Apple binary property list, got %s' % output
+ test.fail_test()
+
+if sys.platform == 'darwin':
+ test = TestGyp.TestGyp(formats=['xcode', 'ninja'])
+
+ test.run_gyp('test.gyp', chdir='app-bundle')
+
+ test.build('test.gyp', test.ALL, chdir='app-bundle')
+
+ # Test that the extension is .bundle
+ test.built_file_must_exist('Test App Gyp.app/Test App Gyp',
+ chdir='app-bundle')
+
+ # Info.plist
+ info_plist = test.built_file_path('Test App Gyp.app/Info.plist',
+ chdir='app-bundle')
+ test.built_file_must_exist(info_plist)
+ CheckFileBinaryPropertyList(info_plist)
+
+ # XML Info.plist
+ info_plist = test.built_file_path('Test App Gyp XML.app/Info.plist',
+ chdir='app-bundle')
+ CheckFileXMLPropertyList(info_plist)
+
+ # Resources
+ strings_file = test.built_file_path(
+ 'Test App Gyp.app/English.lproj/InfoPlist.strings',
+ chdir='app-bundle')
+ test.built_file_must_exist(strings_file)
+ CheckFileBinaryPropertyList(strings_file)
+
+ extra_plist_file = test.built_file_path(
+ 'Test App Gyp.app/English.lproj/LanguageMap.plist',
+ chdir='app-bundle')
+ test.built_file_must_exist(extra_plist_file)
+ CheckFileBinaryPropertyList(extra_plist_file)
+
+ test.built_file_must_exist(
+ 'Test App Gyp.app/English.lproj/MainMenu.nib',
+ chdir='app-bundle')
+ test.built_file_must_exist(
+ 'Test App Gyp.app/English.lproj/Main_iPhone.storyboardc',
+ chdir='app-bundle')
+
+ # Packaging
+ test.built_file_must_exist('Test App Gyp.app/PkgInfo',
+ chdir='app-bundle')
+ test.built_file_must_match('Test App Gyp.app/PkgInfo', 'APPLause',
+ chdir='app-bundle')
+
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/gyptest-archs.py
@@ -0,0 +1,58 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 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.
+
+"""
+Verifies that device and simulator bundles are built correctly.
+"""
+
+import TestGyp
+import TestMac
+
+import collections
+import sys
+
+
+if sys.platform == 'darwin':
+ test = TestGyp.TestGyp(formats=['ninja', 'xcode'])
+
+ test_cases = [
+ ('Default', 'TestArch32Bits', ['i386']),
+ ('Default-iphoneos', 'TestArch32Bits', ['armv7']),
+ ]
+
+ if TestMac.Xcode.Version() < '0510':
+ test_cases.extend([
+ ('Default', 'TestNoArchs', ['i386']),
+ ('Default-iphoneos', 'TestNoArchs', ['armv7'])])
+
+ if TestMac.Xcode.Version() >= '0500':
+ test_cases.extend([
+ ('Default', 'TestArch64Bits', ['x86_64']),
+ ('Default', 'TestMultiArchs', ['i386', 'x86_64']),
+ ('Default-iphoneos', 'TestArch64Bits', ['arm64']),
+ ('Default-iphoneos', 'TestMultiArchs', ['armv7', 'arm64'])])
+
+ test.run_gyp('test-archs.gyp', chdir='app-bundle')
+ for configuration, target, archs in test_cases:
+ is_device_build = configuration.endswith('-iphoneos')
+
+ kwds = collections.defaultdict(list)
+ if test.format == 'xcode':
+ if is_device_build:
+ configuration, sdk = configuration.split('-')
+ kwds['arguments'].extend(['-sdk', sdk])
+ if TestMac.Xcode.Version() < '0500':
+ kwds['arguments'].extend(['-arch', archs[0]])
+
+ test.set_configuration(configuration)
+ filename = '%s.app/%s' % (target, target)
+ test.build('test-archs.gyp', target, chdir='app-bundle', **kwds)
+ result_file = test.built_file_path(filename, chdir='app-bundle')
+
+ test.must_exist(result_file)
+ TestMac.CheckFileType(test, result_file, archs)
+
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/gyptest-copies-with-xcode-envvars.py
@@ -0,0 +1,65 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2016 Mark Callow. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that files are copied to the correct destinations when those
+destinations are specified using environment variables available in
+Xcode's PBXCopyFilesBuildPhase.
+"""
+
+import TestGyp
+
+import os
+import stat
+import sys
+
+
+test = TestGyp.TestGyp(formats=['ninja', 'xcode'])
+
+if sys.platform == 'darwin':
+ test.run_gyp('copies-with-xcode-envvars.gyp',
+ chdir='copies-with-xcode-envvars')
+
+ test.build('copies-with-xcode-envvars.gyp', chdir='copies-with-xcode-envvars')
+
+ wrapper_name = 'copies-with-xcode-envvars.app/'
+ contents_path = wrapper_name
+ out_path = test.built_file_path('file0', chdir='copies-with-xcode-envvars')
+ test.must_contain(out_path, 'file0 contents\n')
+ out_path = test.built_file_path(wrapper_name + 'file1',
+ chdir='copies-with-xcode-envvars')
+ test.must_contain(out_path, 'file1 contents\n')
+ out_path = test.built_file_path(contents_path + 'file2',
+ chdir='copies-with-xcode-envvars')
+ test.must_contain(out_path, 'file2 contents\n')
+ out_path = test.built_file_path(contents_path + 'file3',
+ chdir='copies-with-xcode-envvars')
+ test.must_contain(out_path, 'file3 contents\n')
+ out_path = test.built_file_path(contents_path + 'testimages/file4',
+ chdir='copies-with-xcode-envvars')
+ test.must_contain(out_path, 'file4 contents\n')
+ out_path = test.built_file_path(contents_path + 'Java/file5',
+ chdir='copies-with-xcode-envvars')
+ test.must_contain(out_path, 'file5 contents\n')
+ out_path = test.built_file_path(contents_path + 'Frameworks/file6',
+ chdir='copies-with-xcode-envvars')
+ test.must_contain(out_path, 'file6 contents\n')
+ out_path = test.built_file_path(contents_path + 'Frameworks/file7',
+ chdir='copies-with-xcode-envvars')
+ test.must_contain(out_path, 'file7 contents\n')
+ out_path = test.built_file_path(contents_path + 'SharedFrameworks/file8',
+ chdir='copies-with-xcode-envvars')
+ test.must_contain(out_path, 'file8 contents\n')
+ out_path = test.built_file_path(contents_path + 'SharedSupport/file9',
+ chdir='copies-with-xcode-envvars')
+ test.must_contain(out_path, 'file9 contents\n')
+ out_path = test.built_file_path(contents_path + 'PlugIns/file10',
+ chdir='copies-with-xcode-envvars')
+ test.must_contain(out_path, 'file10 contents\n')
+ out_path = test.built_file_path(contents_path + 'XPCServices/file11',
+ chdir='copies-with-xcode-envvars')
+ test.must_contain(out_path, 'file11 contents\n')
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/gyptest-crosscompile.py
@@ -0,0 +1,34 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 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.
+
+"""
+Verifies that tools are built correctly.
+"""
+
+import TestGyp
+import TestMac
+
+import sys
+import os
+
+if sys.platform == 'darwin':
+ test = TestGyp.TestGyp(formats=['ninja', 'xcode'])
+
+ oldenv = os.environ.copy()
+ try:
+ os.environ['GYP_CROSSCOMPILE'] = '1'
+ test.run_gyp('test-crosscompile.gyp', chdir='app-bundle')
+ finally:
+ os.environ.clear()
+ os.environ.update(oldenv)
+
+ test.set_configuration('Default')
+ test.build('test-crosscompile.gyp', 'TestHost', chdir='app-bundle')
+ result_file = test.built_file_path('TestHost', chdir='app-bundle')
+ test.must_exist(result_file)
+ TestMac.CheckFileType(test, result_file, ['x86_64'])
+
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/gyptest-deployment-target.py
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 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.
+
+"""
+Verifies that IPHONEOS_DEPLOYMENT_TARGET works.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'darwin':
+ test = TestGyp.TestGyp(formats=['make', 'ninja', 'xcode'])
+
+ test.run_gyp('deployment-target.gyp', chdir='deployment-target')
+
+ test.build('deployment-target.gyp', test.ALL, chdir='deployment-target')
+
+ test.pass_test()
+
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/gyptest-extension.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 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.
+
+"""
+Verifies that ios app extensions are built correctly.
+"""
+
+import TestGyp
+import TestMac
+import subprocess
+import sys
+
+def CheckStrip(p, expected):
+ if expected not in subprocess.check_output(['nm','-gU', p]):
+ print expected + " shouldn't get stripped out."
+ test.fail_test()
+
+def CheckEntrypoint(p, expected):
+ if expected not in subprocess.check_output(['nm', p]):
+ print expected + "not found."
+ test.fail_test()
+
+if sys.platform == 'darwin' and TestMac.Xcode.Version()>="0600":
+
+ test = TestGyp.TestGyp(formats=['ninja', 'xcode'])
+
+ test.run_gyp('extension.gyp', chdir='extension')
+
+ test.build('extension.gyp', 'ExtensionContainer', chdir='extension')
+
+ # Test that the extension is .appex
+ test.built_file_must_exist(
+ 'ExtensionContainer.app/PlugIns/ActionExtension.appex',
+ chdir='extension')
+
+ path = test.built_file_path(
+ 'ExtensionContainer.app/PlugIns/ActionExtension.appex/ActionExtension',
+ chdir='extension')
+ CheckStrip(path, "ActionViewController")
+ CheckEntrypoint(path, "_NSExtensionMain")
+
+ test.pass_test()
+
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/gyptest-framework.py
@@ -0,0 +1,37 @@
+#!/usr/bin/env python
+
+# Copyright 2016 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.
+
+"""
+Verifies that ios app frameworks are built correctly.
+"""
+
+import TestGyp
+import TestMac
+import subprocess
+import sys
+
+if sys.platform == 'darwin' and TestMac.Xcode.Version()>="0700":
+
+ test = TestGyp.TestGyp(formats=['ninja'])
+ if test.format == 'xcode-ninja':
+ test.skip_test()
+
+ test.run_gyp('framework.gyp', chdir='framework')
+
+ test.build('framework.gyp', 'iOSFramework', chdir='framework')
+
+ test.built_file_must_exist(
+ 'iOSFramework.framework/Headers/iOSFramework.h',
+ chdir='framework')
+ test.built_file_must_exist(
+ 'iOSFramework.framework/Headers/Thing.h',
+ chdir='framework')
+ test.built_file_must_exist(
+ 'iOSFramework.framework/iOSFramework',
+ chdir='framework')
+
+ test.pass_test()
+
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/gyptest-per-config-settings.py
@@ -0,0 +1,185 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 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.
+
+"""
+Verifies that device and simulator bundles are built correctly.
+"""
+
+import plistlib
+import TestGyp
+import os
+import struct
+import subprocess
+import sys
+import tempfile
+import TestMac
+
+def CheckFileType(file, expected):
+ proc = subprocess.Popen(['lipo', '-info', file], stdout=subprocess.PIPE)
+ o = proc.communicate()[0].strip()
+ assert not proc.returncode
+ if not expected in o:
+ print 'File: Expected %s, got %s' % (expected, o)
+ test.fail_test()
+
+def HasCerts():
+ # Because the bots do not have certs, don't check them if there are no
+ # certs available.
+ proc = subprocess.Popen(['security','find-identity','-p', 'codesigning',
+ '-v'], stdout=subprocess.PIPE)
+ return "0 valid identities found" not in proc.communicate()[0].strip()
+
+def CheckSignature(file):
+ proc = subprocess.Popen(['codesign', '-v', file], stdout=subprocess.PIPE)
+ o = proc.communicate()[0].strip()
+ assert not proc.returncode
+ if "code object is not signed at all" in o:
+ print 'File %s not properly signed.' % (file)
+ test.fail_test()
+
+def CheckEntitlements(file, expected_entitlements):
+ with tempfile.NamedTemporaryFile() as temp:
+ proc = subprocess.Popen(['codesign', '--display', '--entitlements',
+ temp.name, file], stdout=subprocess.PIPE)
+ o = proc.communicate()[0].strip()
+ assert not proc.returncode
+ data = temp.read()
+ entitlements = ParseEntitlements(data)
+ if not entitlements:
+ print 'No valid entitlements found in %s.' % (file)
+ test.fail_test()
+ if entitlements != expected_entitlements:
+ print 'Unexpected entitlements found in %s.' % (file)
+ test.fail_test()
+
+def ParseEntitlements(data):
+ if len(data) < 8:
+ return None
+ magic, length = struct.unpack('>II', data[:8])
+ if magic != 0xfade7171 or length != len(data):
+ return None
+ return data[8:]
+
+def GetXcodeVersionValue(type):
+ args = ['xcodebuild', '-version', '-sdk', 'iphoneos', type]
+ job = subprocess.Popen(args, stdout=subprocess.PIPE)
+ return job.communicate()[0].strip()
+
+def GetMachineBuild():
+ args = ['sw_vers', '-buildVersion']
+ job = subprocess.Popen(args, stdout=subprocess.PIPE)
+ return job.communicate()[0].strip()
+
+def CheckPlistvalue(plist, key, expected):
+ if key not in plist:
+ print '%s not set in plist' % key
+ test.fail_test()
+ return
+ actual = plist[key]
+ if actual != expected:
+ print 'File: Expected %s, got %s for %s' % (expected, actual, key)
+ test.fail_test()
+
+def CheckPlistNotSet(plist, key):
+ if key in plist:
+ print '%s should not be set in plist' % key
+ test.fail_test()
+ return
+
+def ConvertBinaryPlistToXML(path):
+ proc = subprocess.call(['plutil', '-convert', 'xml1', path],
+ stdout=subprocess.PIPE)
+
+if sys.platform == 'darwin':
+ test = TestGyp.TestGyp(formats=['ninja', 'xcode'])
+
+ test.run_gyp('test-device.gyp', chdir='app-bundle')
+
+ test_configs = ['Default-iphoneos', 'Default']
+ for configuration in test_configs:
+ test.set_configuration(configuration)
+ test.build('test-device.gyp', 'test_app', chdir='app-bundle')
+ result_file = test.built_file_path('Test App Gyp.app/Test App Gyp',
+ chdir='app-bundle')
+ test.must_exist(result_file)
+ info_plist = test.built_file_path('Test App Gyp.app/Info.plist',
+ chdir='app-bundle')
+ plist = plistlib.readPlist(info_plist)
+ xcode_version = TestMac.Xcode.Version()
+ if xcode_version >= '0720':
+ if len(plist) != 23:
+ print 'plist should have 23 entries, but it has %s' % len(plist)
+ test.fail_test()
+
+ # Values that will hopefully never change.
+ CheckPlistvalue(plist, 'CFBundleDevelopmentRegion', 'English')
+ CheckPlistvalue(plist, 'CFBundleExecutable', 'Test App Gyp')
+ CheckPlistvalue(plist, 'CFBundleIdentifier', 'com.google.Test App Gyp')
+ CheckPlistvalue(plist, 'CFBundleInfoDictionaryVersion', '6.0')
+ CheckPlistvalue(plist, 'CFBundleName', 'Test App Gyp')
+ CheckPlistvalue(plist, 'CFBundlePackageType', 'APPL')
+ CheckPlistvalue(plist, 'CFBundleShortVersionString', '1.0')
+ CheckPlistvalue(plist, 'CFBundleSignature', 'ause')
+ CheckPlistvalue(plist, 'CFBundleVersion', '1')
+ CheckPlistvalue(plist, 'NSMainNibFile', 'MainMenu')
+ CheckPlistvalue(plist, 'NSPrincipalClass', 'NSApplication')
+ CheckPlistvalue(plist, 'UIDeviceFamily', [1, 2])
+
+ # Values that get pulled from xcodebuild.
+ machine_build = GetMachineBuild()
+ platform_version = GetXcodeVersionValue('ProductVersion')
+ sdk_build = GetXcodeVersionValue('ProductBuildVersion')
+ xcode_build = TestMac.Xcode.Build()
+
+ # Xcode keeps changing what gets included in executable plists, and it
+ # changes between device and simuator builds. Allow the strictest tests for
+ # Xcode 7.2 and above.
+ if xcode_version >= '0720':
+ CheckPlistvalue(plist, 'BuildMachineOSBuild', machine_build)
+ CheckPlistvalue(plist, 'DTCompiler', 'com.apple.compilers.llvm.clang.1_0')
+ CheckPlistvalue(plist, 'DTPlatformVersion', platform_version)
+ CheckPlistvalue(plist, 'DTSDKBuild', sdk_build)
+ CheckPlistvalue(plist, 'DTXcode', xcode_version)
+ CheckPlistvalue(plist, 'DTXcodeBuild', xcode_build)
+ CheckPlistvalue(plist, 'MinimumOSVersion', '8.0')
+
+
+ if configuration == 'Default-iphoneos':
+ platform_name = 'iphoneos'
+ CheckFileType(result_file, 'armv7')
+ CheckPlistvalue(plist, 'CFBundleSupportedPlatforms', ['iPhoneOS'])
+ # Apple keeps changing their mind.
+ if xcode_version >= '0720':
+ CheckPlistvalue(plist, 'DTPlatformBuild', sdk_build)
+ else:
+ platform_name = 'iphonesimulator'
+ CheckFileType(result_file, 'i386')
+ CheckPlistvalue(plist, 'CFBundleSupportedPlatforms', ['iPhoneSimulator'])
+ if xcode_version >= '0720':
+ CheckPlistvalue(plist, 'DTPlatformBuild', '')
+
+ CheckPlistvalue(plist, 'DTPlatformName', platform_name)
+ CheckPlistvalue(plist, 'DTSDKName', platform_name + platform_version)
+
+
+ if HasCerts() and configuration == 'Default-iphoneos':
+ test.build('test-device.gyp', 'sig_test', chdir='app-bundle')
+ result_file = test.built_file_path('sigtest.app/sigtest',
+ chdir='app-bundle')
+ CheckSignature(result_file)
+ info_plist = test.built_file_path('sigtest.app/Info.plist',
+ chdir='app-bundle')
+
+ plist = plistlib.readPlist(info_plist)
+ CheckPlistvalue(plist, 'UIDeviceFamily', [1])
+
+ entitlements_file = test.built_file_path('sig_test.xcent',
+ chdir='app-bundle')
+ if os.path.isfile(entitlements_file):
+ expected_entitlements = open(entitlements_file).read()
+ CheckEntitlements(result_file, expected_entitlements)
+
+ test.pass_test()
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/gyptest-watch.py
@@ -0,0 +1,42 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 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.
+
+"""
+Verifies that ios watch extensions and apps are built correctly.
+"""
+
+import TestGyp
+import TestMac
+
+import sys
+
+if sys.platform == 'darwin':
+ print "This test is currently disabled: https://crbug.com/483696."
+ sys.exit(0)
+
+
+if sys.platform == 'darwin' and TestMac.Xcode.Version() >= "0620":
+ test = TestGyp.TestGyp(formats=['ninja', 'xcode'])
+
+ test.run_gyp('watch.gyp', chdir='watch')
+
+ test.build(
+ 'watch.gyp',
+ 'WatchContainer',
+ chdir='watch')
+
+ # Test that the extension exists
+ test.built_file_must_exist(
+ 'WatchContainer.app/PlugIns/WatchKitExtension.appex',
+ chdir='watch')
+
+ # Test that the watch app exists
+ test.built_file_must_exist(
+ 'WatchContainer.app/PlugIns/WatchKitExtension.appex/WatchApp.app',
+ chdir='watch')
+
+ test.pass_test()
+
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/gyptest-xcode-ninja.py
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 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 the xcode-ninja GYP_GENERATOR runs and builds correctly.
+"""
+
+import TestGyp
+
+import os
+import sys
+
+if sys.platform == 'darwin':
+ test = TestGyp.TestGyp(formats=['xcode'])
+
+ # Run ninja and xcode-ninja
+ test.formats = ['ninja', 'xcode-ninja']
+ test.run_gyp('test.gyp', chdir='app-bundle')
+
+ # If it builds the target, it works.
+ test.build('test.ninja.gyp', chdir='app-bundle')
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/watch/WatchApp/Images.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,62 @@
+{
+ "images" : [
+ {
+ "size" : "14.5x14.5",
+ "idiom" : "watch",
+ "scale" : "2x",
+ "role" : "notificationCenter",
+ "subtype" : "38mm"
+ },
+ {
+ "size" : "18x18",
+ "idiom" : "watch",
+ "scale" : "2x",
+ "role" : "notificationCenter",
+ "subtype" : "42mm"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "watch",
+ "role" : "companionSettings",
+ "scale" : "2x"
+ },
+ {
+ "size" : "29.3x29.3",
+ "idiom" : "watch",
+ "role" : "companionSettings",
+ "scale" : "3x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "watch",
+ "scale" : "2x",
+ "role" : "appLauncher",
+ "subtype" : "38mm"
+ },
+ {
+ "size" : "44x44",
+ "idiom" : "watch",
+ "scale" : "2x",
+ "role" : "appLauncher",
+ "subtype" : "42mm"
+ },
+ {
+ "size" : "86x86",
+ "idiom" : "watch",
+ "scale" : "2x",
+ "role" : "quickLook",
+ "subtype" : "38mm"
+ },
+ {
+ "size" : "98x98",
+ "idiom" : "watch",
+ "scale" : "2x",
+ "role" : "quickLook",
+ "subtype" : "42mm"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/watch/WatchApp/Images.xcassets/LaunchImage.launchimage/Contents.json
@@ -0,0 +1,24 @@
+{
+ "images" : [
+ {
+ "orientation" : "portrait",
+ "idiom" : "watch",
+ "extent" : "full-screen",
+ "minimum-system-version" : "8.0",
+ "subtype" : "38mm",
+ "scale" : "2x"
+ },
+ {
+ "orientation" : "portrait",
+ "idiom" : "watch",
+ "extent" : "full-screen",
+ "minimum-system-version" : "8.0",
+ "subtype" : "42mm",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/watch/WatchApp/Info.plist
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleDisplayName</key>
+ <string>WatchApp</string>
+ <key>CFBundleExecutable</key>
+ <string>$(EXECUTABLE_NAME)</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.google.gyptest.watch.watchapp</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>$(PRODUCT_NAME)</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+ <key>UISupportedInterfaceOrientations</key>
+ <array>
+ <string>UIInterfaceOrientationPortrait</string>
+ <string>UIInterfaceOrientationPortraitUpsideDown</string>
+ </array>
+ <key>WKCompanionAppBundleIdentifier</key>
+ <string>com.google.gyptest.watch</string>
+ <key>WKWatchKitApp</key>
+ <true/>
+</dict>
+</plist>
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/watch/WatchApp/Interface.storyboard
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder.WatchKit.Storyboard" version="3.0" toolsVersion="6221" systemVersion="13E28" targetRuntime="watchKit" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="AgC-eL-Hgc">
+ <dependencies>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6213"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBWatchKitPlugin" version="3733"/>
+ </dependencies>
+ <scenes>
+ <!--Interface Controller-->
+ <scene sceneID="aou-V4-d1y">
+ <objects>
+ <controller id="AgC-eL-Hgc" customClass="InterfaceController" customModuleProvider=""/>
+ </objects>
+ </scene>
+ </scenes>
+</document>
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/watch/WatchContainer/AppDelegate.h
@@ -0,0 +1,12 @@
+// Copyright (c) 2014 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.
+
+#import <UIKit/UIKit.h>
+
+@interface AppDelegate : UIResponder <UIApplicationDelegate>
+
+@property (strong, nonatomic) UIWindow *window;
+
+@end
+
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/watch/WatchContainer/AppDelegate.m
@@ -0,0 +1,19 @@
+// Copyright (c) 2014 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.
+
+#import "AppDelegate.h"
+
+@interface AppDelegate ()
+
+@end
+
+@implementation AppDelegate
+
+- (BOOL)application:(UIApplication*)application
+ didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
+ // Override point for customization after application launch.
+ return YES;
+}
+
+@end
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/watch/WatchContainer/Base.lproj/Main.storyboard
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6162" systemVersion="14A238h" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
+ <dependencies>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6160"/>
+ </dependencies>
+ <scenes>
+ <!--View Controller-->
+ <scene sceneID="tne-QT-ifu">
+ <objects>
+ <viewController id="BYZ-38-t0r" customClass="ViewController" customModuleProvider="" sceneMemberID="viewController">
+ <layoutGuides>
+ <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
+ <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
+ </layoutGuides>
+ <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
+ <rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
+ </view>
+ </viewController>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
+ </objects>
+ </scene>
+ </scenes>
+</document>
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/watch/WatchContainer/Images.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,53 @@
+{
+ "images" : [
+ {
+ "idiom" : "iphone",
+ "size" : "29x29",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "40x40",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "60x60",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "29x29",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "29x29",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "40x40",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "40x40",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "76x76",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "76x76",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/watch/WatchContainer/Images.xcassets/LaunchImage.launchimage/Contents.json
@@ -0,0 +1,51 @@
+{
+ "images" : [
+ {
+ "orientation" : "portrait",
+ "idiom" : "iphone",
+ "extent" : "full-screen",
+ "minimum-system-version" : "7.0",
+ "scale" : "2x"
+ },
+ {
+ "orientation" : "portrait",
+ "idiom" : "iphone",
+ "subtype" : "retina4",
+ "extent" : "full-screen",
+ "minimum-system-version" : "7.0",
+ "scale" : "2x"
+ },
+ {
+ "orientation" : "portrait",
+ "idiom" : "ipad",
+ "extent" : "full-screen",
+ "minimum-system-version" : "7.0",
+ "scale" : "1x"
+ },
+ {
+ "orientation" : "landscape",
+ "idiom" : "ipad",
+ "extent" : "full-screen",
+ "minimum-system-version" : "7.0",
+ "scale" : "1x"
+ },
+ {
+ "orientation" : "portrait",
+ "idiom" : "ipad",
+ "extent" : "full-screen",
+ "minimum-system-version" : "7.0",
+ "scale" : "2x"
+ },
+ {
+ "orientation" : "landscape",
+ "idiom" : "ipad",
+ "extent" : "full-screen",
+ "minimum-system-version" : "7.0",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/watch/WatchContainer/Info.plist
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleExecutable</key>
+ <string>WatchContainer</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.google.gyptest.watch</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+ <key>LSRequiresIPhoneOS</key>
+ <true/>
+ <key>UIMainStoryboardFile</key>
+ <string>Main</string>
+ <key>UIRequiredDeviceCapabilities</key>
+ <array>
+ <string>armv7</string>
+ </array>
+</dict>
+</plist>
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/watch/WatchContainer/ViewController.h
@@ -0,0 +1,11 @@
+// Copyright (c) 2014 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.
+
+#import <UIKit/UIKit.h>
+
+@interface ViewController : UIViewController
+
+
+@end
+
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/watch/WatchContainer/ViewController.m
@@ -0,0 +1,24 @@
+// Copyright (c) 2014 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.
+
+#import "ViewController.h"
+
+@interface ViewController ()
+
+
+@end
+
+@implementation ViewController
+
+- (void)viewDidLoad {
+ [super viewDidLoad];
+ // Do any additional setup after loading the view, typically from a nib.
+}
+
+- (void)didReceiveMemoryWarning {
+ [super didReceiveMemoryWarning];
+ // Dispose of any resources that can be recreated.
+}
+
+@end
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/watch/WatchContainer/main.m
@@ -0,0 +1,13 @@
+// Copyright (c) 2014 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.
+//
+#import <UIKit/UIKit.h>
+#import "AppDelegate.h"
+
+int main(int argc, char* argv[]) {
+ @autoreleasepool {
+ return UIApplicationMain(argc, argv, nil,
+ NSStringFromClass([AppDelegate class]));
+ }
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/watch/WatchKitExtension/Images.xcassets/MyImage.imageset/Contents.json
@@ -0,0 +1,20 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/watch/WatchKitExtension/Info.plist
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleDisplayName</key>
+ <string>WatchContainer WatchKit Extension</string>
+ <key>CFBundleExecutable</key>
+ <string>$(EXECUTABLE_NAME)</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.google.gyptest.watch.watchkitextension</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>$(PRODUCT_NAME)</string>
+ <key>CFBundlePackageType</key>
+ <string>XPC!</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+ <key>NSExtension</key>
+ <dict>
+ <key>NSExtensionAttributes</key>
+ <dict>
+ <key>WKAppBundleIdentifier</key>
+ <string>com.google.gyptest.watch.watchapp</string>
+ </dict>
+ <key>NSExtensionPointIdentifier</key>
+ <string>com.apple.watchkit</string>
+ </dict>
+ <key>RemoteInterfacePrincipalClass</key>
+ <string>InterfaceController</string>
+</dict>
+</plist>
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/watch/WatchKitExtension/InterfaceController.h
@@ -0,0 +1,10 @@
+// Copyright (c) 2014 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.
+
+#import <Foundation/Foundation.h>
+#import <WatchKit/WatchKit.h>
+
+@interface InterfaceController : WKInterfaceController
+@end
+
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/watch/WatchKitExtension/InterfaceController.m
@@ -0,0 +1,25 @@
+// Copyright (c) 2014 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.
+
+#import "InterfaceController.h"
+
+@implementation InterfaceController
+
+- (instancetype)initWithContext:(id)context {
+ if ((self = [super initWithContext:context])) {
+ // -initWithContext:
+ }
+ return self;
+}
+
+- (void)willActivate {
+ // -willActivate
+}
+
+- (void)didDeactivate {
+ // -didDeactivate
+}
+
+@end
+
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/watch/WatchKitExtension/MainInterface.storyboard
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6148" systemVersion="14A229a" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" initialViewController="ObA-dk-sSI">
+ <dependencies>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6147"/>
+ </dependencies>
+ <scenes>
+ <!--Action View Controller - Image-->
+ <scene sceneID="7MM-of-jgj">
+ <objects>
+ <viewController title="Image" id="ObA-dk-sSI" customClass="ActionViewController" customModuleProvider="" sceneMemberID="viewController">
+ <layoutGuides>
+ <viewControllerLayoutGuide type="top" id="qkL-Od-lgU"/>
+ <viewControllerLayoutGuide type="bottom" id="n38-gi-rB5"/>
+ </layoutGuides>
+ <view key="view" contentMode="scaleToFill" id="zMn-AG-sqS">
+ <rect key="frame" x="0.0" y="0.0" width="320" height="528"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <subviews>
+ <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="9ga-4F-77Z">
+ <rect key="frame" x="0.0" y="64" width="320" height="464"/>
+ </imageView>
+ <navigationBar contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="NOA-Dm-cuz">
+ <rect key="frame" x="0.0" y="20" width="320" height="44"/>
+ <items>
+ <navigationItem id="3HJ-uW-3hn">
+ <barButtonItem key="leftBarButtonItem" title="Done" style="done" id="WYi-yp-eM6">
+ <connections>
+ <action selector="done" destination="ObA-dk-sSI" id="Qdu-qn-U6V"/>
+ </connections>
+ </barButtonItem>
+ </navigationItem>
+ </items>
+ </navigationBar>
+ </subviews>
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+ <constraints>
+ <constraint firstAttribute="trailing" secondItem="NOA-Dm-cuz" secondAttribute="trailing" id="A05-Pj-hrr"/>
+ <constraint firstItem="9ga-4F-77Z" firstAttribute="top" secondItem="NOA-Dm-cuz" secondAttribute="bottom" id="Fps-3D-QQW"/>
+ <constraint firstItem="NOA-Dm-cuz" firstAttribute="leading" secondItem="zMn-AG-sqS" secondAttribute="leading" id="HxO-8t-aoh"/>
+ <constraint firstAttribute="trailing" secondItem="9ga-4F-77Z" secondAttribute="trailing" id="Ozw-Hg-0yh"/>
+ <constraint firstItem="9ga-4F-77Z" firstAttribute="leading" secondItem="zMn-AG-sqS" secondAttribute="leading" id="XH5-ld-ONA"/>
+ <constraint firstItem="n38-gi-rB5" firstAttribute="top" secondItem="9ga-4F-77Z" secondAttribute="bottom" id="eQg-nn-Zy4"/>
+ <constraint firstItem="NOA-Dm-cuz" firstAttribute="top" secondItem="qkL-Od-lgU" secondAttribute="bottom" id="we0-1t-bgp"/>
+ </constraints>
+ </view>
+ <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
+ <size key="freeformSize" width="320" height="528"/>
+ <connections>
+ <outlet property="imageView" destination="9ga-4F-77Z" id="5y6-5w-9QO"/>
+ <outlet property="view" destination="zMn-AG-sqS" id="Qma-de-2ek"/>
+ </connections>
+ </viewController>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="X47-rx-isc" userLabel="First Responder" sceneMemberID="firstResponder"/>
+ </objects>
+ <point key="canvasLocation" x="252" y="-124"/>
+ </scene>
+ </scenes>
+ <simulatedMetricsContainer key="defaultSimulatedMetrics">
+ <simulatedStatusBarMetrics key="statusBar"/>
+ <simulatedOrientationMetrics key="orientation"/>
+ <simulatedScreenMetrics key="destination" type="retina4"/>
+ </simulatedMetricsContainer>
+</document>
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/watch/watch.gyp
@@ -0,0 +1,105 @@
+# Copyright (c) 2014 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.
+
+{
+ 'make_global_settings': [
+ ['CC', '/usr/bin/clang'],
+ ['CXX', '/usr/bin/clang++'],
+ ],
+ 'target_defaults': {
+ 'xcode_settings': {
+ 'OTHER_CFLAGS': [
+ '-fobjc-abi-version=2',
+ ],
+ 'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0',
+ 'SDKROOT': 'iphoneos',
+ 'IPHONEOS_DEPLOYMENT_TARGET': '8.2',
+ 'CODE_SIGN_IDENTITY[sdk=iphoneos*]': 'iPhone Developer',
+ }
+ },
+ 'targets': [
+ {
+ 'target_name': 'WatchContainer',
+ 'product_name': 'WatchContainer',
+ 'type': 'executable',
+ 'mac_bundle': 1,
+ 'mac_bundle_resources': [
+ 'WatchContainer/Base.lproj/Main.storyboard',
+ ],
+ 'sources': [
+ 'WatchContainer/AppDelegate.h',
+ 'WatchContainer/AppDelegate.m',
+ 'WatchContainer/ViewController.h',
+ 'WatchContainer/ViewController.m',
+ 'WatchContainer/main.m',
+ ],
+ 'copies': [
+ {
+ 'destination': '<(PRODUCT_DIR)/WatchContainer.app/PlugIns',
+ 'files': [
+ '<(PRODUCT_DIR)/WatchKitExtension.appex',
+ ]}],
+ 'dependencies': [
+ 'WatchKitExtension'
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
+ '$(SDKROOT)/System/Library/Frameworks/UIKit.framework',
+ ],
+ },
+ 'xcode_settings': {
+ 'INFOPLIST_FILE': 'WatchContainer/Info.plist',
+ },
+ },
+ {
+ 'target_name': 'WatchKitExtension',
+ 'product_name': 'WatchKitExtension',
+ 'type': 'executable',
+ 'mac_bundle': 1,
+ 'ios_watchkit_extension': 1,
+ 'sources': [
+ 'WatchKitExtension/InterfaceController.h',
+ 'WatchKitExtension/InterfaceController.m',
+ ],
+ 'mac_bundle_resources': [
+ 'WatchKitExtension/Images.xcassets',
+ '<(PRODUCT_DIR)/WatchApp.app',
+ ],
+ 'dependencies': [
+ 'WatchApp'
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
+ '$(SDKROOT)/System/Library/Frameworks/WatchKit.framework',
+ ],
+ },
+ 'xcode_settings': {
+ 'INFOPLIST_FILE': 'WatchKitExtension/Info.plist',
+ 'SKIP_INSTALL': 'YES',
+ 'COPY_PHASE_STRIP': 'NO',
+ },
+ },
+ {
+ 'target_name': 'WatchApp',
+ 'product_name': 'WatchApp',
+ 'type': 'executable',
+ 'mac_bundle': 1,
+ 'ios_watch_app': 1,
+ 'mac_bundle_resources': [
+ 'WatchApp/Images.xcassets',
+ 'WatchApp/Interface.storyboard',
+ ],
+ 'xcode_settings': {
+ 'INFOPLIST_FILE': 'WatchApp/Info.plist',
+ 'SKIP_INSTALL': 'YES',
+ 'COPY_PHASE_STRIP': 'NO',
+ 'TARGETED_DEVICE_FAMILY': '4',
+ 'TARGETED_DEVICE_FAMILY[sdk=iphonesimulator*]': '1,4',
+ },
+ },
+ ],
+}
+
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/xctests/App/AppDelegate.h
@@ -0,0 +1,11 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <UIKit/UIKit.h>
+
+@interface AppDelegate : UIResponder<UIApplicationDelegate>
+
+@property(strong, nonatomic) UIWindow* window;
+
+@end
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/xctests/App/AppDelegate.m
@@ -0,0 +1,18 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "AppDelegate.h"
+
+@interface AppDelegate ()
+
+@end
+
+@implementation AppDelegate
+
+- (BOOL)application:(UIApplication*)application
+ didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
+ return YES;
+}
+
+@end
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/xctests/App/Base.lproj/LaunchScreen.xib
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="6214" systemVersion="14A314h" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
+ <dependencies>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6207"/>
+ <capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
+ </dependencies>
+ <objects>
+ <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+ <view contentMode="scaleToFill" id="iN0-l3-epB">
+ <rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <subviews>
+ <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright (c) 2014 Google. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
+ <rect key="frame" x="20" y="439" width="441" height="21"/>
+ <fontDescription key="fontDescription" type="system" pointSize="17"/>
+ <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
+ <nil key="highlightedColor"/>
+ </label>
+ <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="App" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX">
+ <rect key="frame" x="20" y="140" width="441" height="43"/>
+ <fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
+ <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
+ <nil key="highlightedColor"/>
+ </label>
+ </subviews>
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
+ <constraints>
+ <constraint firstItem="kId-c2-rCX" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="bottom" multiplier="1/3" constant="1" id="5cJ-9S-tgC"/>
+ <constraint firstAttribute="centerX" secondItem="kId-c2-rCX" secondAttribute="centerX" id="Koa-jz-hwk"/>
+ <constraint firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Kzo-t9-V3l"/>
+ <constraint firstItem="8ie-xW-0ye" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="MfP-vx-nX0"/>
+ <constraint firstAttribute="centerX" secondItem="8ie-xW-0ye" secondAttribute="centerX" id="ZEH-qu-HZ9"/>
+ <constraint firstItem="kId-c2-rCX" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="fvb-Df-36g"/>
+ </constraints>
+ <nil key="simulatedStatusBarMetrics"/>
+ <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
+ <point key="canvasLocation" x="548" y="455"/>
+ </view>
+ </objects>
+</document>
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/xctests/App/Base.lproj/Main.storyboard
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6211" systemVersion="14A298i" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
+ <dependencies>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6204"/>
+ </dependencies>
+ <scenes>
+ <!--View Controller-->
+ <scene sceneID="tne-QT-ifu">
+ <objects>
+ <viewController id="BYZ-38-t0r" customClass="ViewController" customModuleProvider="" sceneMemberID="viewController">
+ <layoutGuides>
+ <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
+ <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
+ </layoutGuides>
+ <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
+ <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
+ </view>
+ </viewController>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
+ </objects>
+ </scene>
+ </scenes>
+</document>
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/xctests/App/Images.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,68 @@
+{
+ "images" : [
+ {
+ "idiom" : "iphone",
+ "size" : "29x29",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "29x29",
+ "scale" : "3x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "40x40",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "40x40",
+ "scale" : "3x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "60x60",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "60x60",
+ "scale" : "3x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "29x29",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "29x29",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "40x40",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "40x40",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "76x76",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "76x76",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/xctests/App/Info.plist
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.google.gyptest.App</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+ <key>LSRequiresIPhoneOS</key>
+ <true/>
+ <key>UILaunchStoryboardName</key>
+ <string>LaunchScreen</string>
+ <key>UIMainStoryboardFile</key>
+ <string>Main</string>
+ <key>UIRequiredDeviceCapabilities</key>
+ <array>
+ <string>armv7</string>
+ </array>
+ <key>UISupportedInterfaceOrientations</key>
+ <array>
+ <string>UIInterfaceOrientationPortrait</string>
+ <string>UIInterfaceOrientationLandscapeLeft</string>
+ <string>UIInterfaceOrientationLandscapeRight</string>
+ </array>
+ <key>UISupportedInterfaceOrientations~ipad</key>
+ <array>
+ <string>UIInterfaceOrientationPortrait</string>
+ <string>UIInterfaceOrientationPortraitUpsideDown</string>
+ <string>UIInterfaceOrientationLandscapeLeft</string>
+ <string>UIInterfaceOrientationLandscapeRight</string>
+ </array>
+</dict>
+</plist>
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/xctests/App/ViewController.h
@@ -0,0 +1,9 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <UIKit/UIKit.h>
+
+@interface ViewController : UIViewController
+
+@end
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/xctests/App/ViewController.m
@@ -0,0 +1,21 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ViewController.h"
+
+@interface ViewController ()
+
+@end
+
+@implementation ViewController
+
+- (void)viewDidLoad {
+ [super viewDidLoad];
+}
+
+- (void)didReceiveMemoryWarning {
+ [super didReceiveMemoryWarning];
+}
+
+@end
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/xctests/App/main.m
@@ -0,0 +1,13 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <UIKit/UIKit.h>
+#import "AppDelegate.h"
+
+int main(int argc, char* argv[]) {
+ @autoreleasepool {
+ return UIApplicationMain(
+ argc, argv, nil, NSStringFromClass([AppDelegate class]));
+ }
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/xctests/AppTests/AppTests.m
@@ -0,0 +1,31 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <UIKit/UIKit.h>
+#import <XCTest/XCTest.h>
+
+@interface AppTests : XCTestCase
+
+@end
+
+@implementation AppTests
+
+- (void)setUp {
+ [super setUp];
+}
+
+- (void)tearDown {
+ [super tearDown];
+}
+
+- (void)testExample {
+ XCTAssert(YES, @"Pass");
+}
+
+- (void)testPerformanceExample {
+ [self measureBlock:^{
+ }];
+}
+
+@end
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/xctests/AppTests/Info.plist
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.google.gyptest.AppTests</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>BNDL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+</dict>
+</plist>
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/xctests/gyptest-xctests.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that iOS XCTests can be built correctly.
+"""
+
+import TestGyp
+
+import os
+import subprocess
+import sys
+
+def HasCerts():
+ # Because the bots do not have certs, don't check them if there are no
+ # certs available.
+ proc = subprocess.Popen(['security','find-identity','-p', 'codesigning',
+ '-v'], stdout=subprocess.PIPE)
+ return "0 valid identities found" not in proc.communicate()[0].strip()
+
+if sys.platform == "darwin":
+ test = TestGyp.TestGyp(formats=['xcode', 'ninja'])
+ test.run_gyp('xctests.gyp')
+ test_configs = ['Default']
+ # TODO(crbug.com/557418): Enable this once xcodebuild works for iOS devices.
+ #if HasCerts() and test.format == 'xcode':
+ # test_configs.append('Default-iphoneos')
+ for config in test_configs:
+ test.set_configuration(config)
+ test.build('xctests.gyp', test.ALL)
+ test.built_file_must_exist('app_under_test.app/app_under_test')
+ test.built_file_must_exist('app_tests.xctest/app_tests')
+ if 'ninja' in test.format:
+ test.built_file_must_exist('obj/AppTests/app_tests.AppTests.i386.o')
+ test.built_file_must_exist('obj/AppTests/app_tests.AppTests.x86_64.o')
+ elif test.format == 'xcode':
+ xcode_object_path = os.path.join('..', 'xctests.build',
+ 'Default-iphonesimulator',
+ 'app_tests.build', 'Objects-normal',
+ '%s', 'AppTests.o')
+ test.built_file_must_exist(xcode_object_path % 'i386')
+ test.built_file_must_exist(xcode_object_path % 'x86_64')
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ios/xctests/xctests.gyp
@@ -0,0 +1,74 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+ 'conditions': [
+ ['"<(GENERATOR)"=="ninja"', {
+ 'make_global_settings': [
+ ['CC', '/usr/bin/clang'],
+ ['CXX', '/usr/bin/clang++'],
+ ],
+ }]
+ ],
+ 'target_defaults': {
+ 'xcode_settings': {
+ 'OTHER_CFLAGS': [
+ '-fobjc-abi-version=2',
+ ],
+ 'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0',
+ 'SDKROOT': 'iphonesimulator', # -isysroot
+ 'CONFIGURATION_BUILD_DIR':'build/Default',
+ 'IPHONEOS_DEPLOYMENT_TARGET': '9.0',
+ 'CODE_SIGN_IDENTITY[sdk=iphoneos*]': 'iPhone Developer',
+ }
+ },
+ 'targets': [
+ {
+ 'target_name': 'app_under_test',
+ 'type': 'executable',
+ 'mac_bundle': 1,
+ 'mac_bundle_resources': [
+ 'App/Base.lproj/LaunchScreen.xib',
+ 'App/Base.lproj/Main.storyboard',
+ ],
+ 'sources': [
+ 'App/AppDelegate.h',
+ 'App/AppDelegate.m',
+ 'App/ViewController.h',
+ 'App/ViewController.m',
+ 'App/main.m',
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
+ '$(SDKROOT)/System/Library/Frameworks/UIKit.framework',
+ ],
+ },
+ 'xcode_settings': {
+ 'INFOPLIST_FILE': 'App/Info.plist',
+ },
+ },
+ {
+ 'target_name': 'app_tests',
+ 'type': 'loadable_module',
+ 'mac_xctest_bundle': 1,
+ 'sources': [
+ 'AppTests/AppTests.m',
+ ],
+ 'dependencies': [
+ 'app_under_test'
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
+ ],
+ },
+ 'xcode_settings': {
+ 'WRAPPER_EXTENSION': 'xctest',
+ 'INFOPLIST_FILE': 'AppTests/Info.plist',
+ 'BUNDLE_LOADER': '$(BUILT_PRODUCTS_DIR)/app_under_test.app/app_under_test',
+ 'TEST_HOST': '$(BUNDLE_LOADER)',
+ },
+ },
+ ],
+}
--- a/media/webrtc/trunk/tools/gyp/test/lib/TestCommon.py
+++ b/media/webrtc/trunk/tools/gyp/test/lib/TestCommon.py
@@ -112,69 +112,81 @@ from TestCmd import __all__
'lib_prefix',
'lib_suffix',
'dll_prefix',
'dll_suffix',
])
# Variables that describe the prefixes and suffixes on this system.
if sys.platform == 'win32':
- exe_suffix = '.exe'
- obj_suffix = '.obj'
- shobj_suffix = '.obj'
- shobj_prefix = ''
- lib_prefix = ''
- lib_suffix = '.lib'
- dll_prefix = ''
- dll_suffix = '.dll'
+ exe_suffix = '.exe'
+ obj_suffix = '.obj'
+ shobj_suffix = '.obj'
+ shobj_prefix = ''
+ lib_prefix = ''
+ lib_suffix = '.lib'
+ dll_prefix = ''
+ dll_suffix = '.dll'
+ module_prefix = ''
+ module_suffix = '.dll'
elif sys.platform == 'cygwin':
- exe_suffix = '.exe'
- obj_suffix = '.o'
- shobj_suffix = '.os'
- shobj_prefix = ''
- lib_prefix = 'lib'
- lib_suffix = '.a'
- dll_prefix = ''
- dll_suffix = '.dll'
+ exe_suffix = '.exe'
+ obj_suffix = '.o'
+ shobj_suffix = '.os'
+ shobj_prefix = ''
+ lib_prefix = 'lib'
+ lib_suffix = '.a'
+ dll_prefix = ''
+ dll_suffix = '.dll'
+ module_prefix = ''
+ module_suffix = '.dll'
elif string.find(sys.platform, 'irix') != -1:
- exe_suffix = ''
- obj_suffix = '.o'
- shobj_suffix = '.o'
- shobj_prefix = ''
- lib_prefix = 'lib'
- lib_suffix = '.a'
- dll_prefix = 'lib'
- dll_suffix = '.so'
+ exe_suffix = ''
+ obj_suffix = '.o'
+ shobj_suffix = '.o'
+ shobj_prefix = ''
+ lib_prefix = 'lib'
+ lib_suffix = '.a'
+ dll_prefix = 'lib'
+ dll_suffix = '.so'
+ module_prefix = 'lib'
+ module_prefix = '.so'
elif string.find(sys.platform, 'darwin') != -1:
- exe_suffix = ''
- obj_suffix = '.o'
- shobj_suffix = '.os'
- shobj_prefix = ''
- lib_prefix = 'lib'
- lib_suffix = '.a'
- dll_prefix = 'lib'
- dll_suffix = '.dylib'
+ exe_suffix = ''
+ obj_suffix = '.o'
+ shobj_suffix = '.os'
+ shobj_prefix = ''
+ lib_prefix = 'lib'
+ lib_suffix = '.a'
+ dll_prefix = 'lib'
+ dll_suffix = '.dylib'
+ module_prefix = ''
+ module_suffix = '.so'
elif string.find(sys.platform, 'sunos') != -1:
- exe_suffix = ''
- obj_suffix = '.o'
- shobj_suffix = '.os'
- shobj_prefix = 'so_'
- lib_prefix = 'lib'
- lib_suffix = '.a'
- dll_prefix = 'lib'
- dll_suffix = '.dylib'
+ exe_suffix = ''
+ obj_suffix = '.o'
+ shobj_suffix = '.os'
+ shobj_prefix = 'so_'
+ lib_prefix = 'lib'
+ lib_suffix = '.a'
+ dll_prefix = 'lib'
+ dll_suffix = '.dylib'
+ module_prefix = ''
+ module_suffix = '.so'
else:
- exe_suffix = ''
- obj_suffix = '.o'
- shobj_suffix = '.os'
- shobj_prefix = ''
- lib_prefix = 'lib'
- lib_suffix = '.a'
- dll_prefix = 'lib'
- dll_suffix = '.so'
+ exe_suffix = ''
+ obj_suffix = '.o'
+ shobj_suffix = '.os'
+ shobj_prefix = ''
+ lib_prefix = 'lib'
+ lib_suffix = '.a'
+ dll_prefix = 'lib'
+ dll_suffix = '.so'
+ module_prefix = 'lib'
+ module_suffix = '.so'
def is_List(e):
return type(e) is types.ListType \
or isinstance(e, UserList.UserList)
def is_writable(f):
mode = os.stat(f)[stat.ST_MODE]
return mode & stat.S_IWUSR
--- a/media/webrtc/trunk/tools/gyp/test/lib/TestGyp.py
+++ b/media/webrtc/trunk/tools/gyp/test/lib/TestGyp.py
@@ -1,50 +1,68 @@
# Copyright (c) 2012 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.
"""
TestGyp.py: a testing framework for GYP integration tests.
"""
+import collections
+from contextlib import contextmanager
+import itertools
import os
import re
import shutil
-import stat
import subprocess
import sys
import tempfile
+import TestCmd
import TestCommon
from TestCommon import __all__
__all__.extend([
'TestGyp',
])
+
def remove_debug_line_numbers(contents):
"""Function to remove the line numbers from the debug output
- of gyp and thus remove the exremem fragility of the stdout
+ of gyp and thus reduce the extreme fragility of the stdout
comparison tests.
"""
lines = contents.splitlines()
# split each line on ":"
lines = [l.split(":", 3) for l in lines]
# join each line back together while ignoring the
# 3rd column which is the line number
lines = [len(l) > 3 and ":".join(l[3:]) or l for l in lines]
return "\n".join(lines)
+
def match_modulo_line_numbers(contents_a, contents_b):
"""File contents matcher that ignores line numbers."""
contents_a = remove_debug_line_numbers(contents_a)
contents_b = remove_debug_line_numbers(contents_b)
return TestCommon.match_exact(contents_a, contents_b)
+
+@contextmanager
+def LocalEnv(local_env):
+ """Context manager to provide a local OS environment."""
+ old_env = os.environ.copy()
+ os.environ.update(local_env)
+ try:
+ yield
+ finally:
+ os.environ.clear()
+ os.environ.update(old_env)
+
+
class TestGypBase(TestCommon.TestCommon):
"""
Class for controlling end-to-end tests of gyp generators.
Instantiating this class will create a temporary directory and
arrange for its destruction (via the TestCmd superclass) and
copy all of the non-gyptest files in the directory hierarchy of the
executing script.
@@ -54,49 +72,56 @@ class TestGypBase(TestCommon.TestCommon)
instantiation, or by setting the TESTGYP_GYP environment variable.
This class should be subclassed for each supported gyp generator
(format). Various abstract methods below define calling signatures
used by the test scripts to invoke builds on the generated build
configuration and to run executables generated by those builds.
"""
+ formats = []
build_tool = None
build_tool_list = []
_exe = TestCommon.exe_suffix
_obj = TestCommon.obj_suffix
shobj_ = TestCommon.shobj_prefix
_shobj = TestCommon.shobj_suffix
lib_ = TestCommon.lib_prefix
_lib = TestCommon.lib_suffix
dll_ = TestCommon.dll_prefix
_dll = TestCommon.dll_suffix
+ module_ = TestCommon.module_prefix
+ _module = TestCommon.module_suffix
# Constants to represent different targets.
ALL = '__all__'
DEFAULT = '__default__'
# Constants for different target types.
EXECUTABLE = '__executable__'
STATIC_LIB = '__static_lib__'
SHARED_LIB = '__shared_lib__'
+ LOADABLE_MODULE = '__loadable_module__'
def __init__(self, gyp=None, *args, **kw):
self.origin_cwd = os.path.abspath(os.path.dirname(sys.argv[0]))
self.extra_args = sys.argv[1:]
if not gyp:
gyp = os.environ.get('TESTGYP_GYP')
if not gyp:
if sys.platform == 'win32':
gyp = 'gyp.bat'
else:
gyp = 'gyp'
self.gyp = os.path.abspath(gyp)
+ self.no_parallel = False
+
+ self.formats = [self.format]
self.initialize_build_tool()
kw.setdefault('match', TestCommon.match_exact)
# Put test output in out/testworkarea by default.
# Use temporary names so there are no collisions.
workdir = os.path.join('out', kw.get('workdir', 'testworkarea'))
@@ -105,33 +130,37 @@ class TestGypBase(TestCommon.TestCommon)
os.makedirs(workdir)
kw['workdir'] = tempfile.mktemp(prefix='testgyp.', dir=workdir)
formats = kw.pop('formats', [])
super(TestGypBase, self).__init__(*args, **kw)
+ real_format = self.format.split('-')[-1]
excluded_formats = set([f for f in formats if f[0] == '!'])
included_formats = set(formats) - excluded_formats
- if ('!'+self.format in excluded_formats or
- included_formats and self.format not in included_formats):
+ if ('!'+real_format in excluded_formats or
+ included_formats and real_format not in included_formats):
msg = 'Invalid test for %r format; skipping test.\n'
self.skip_test(msg % self.format)
self.copy_test_configuration(self.origin_cwd, self.workdir)
self.set_configuration(None)
# Set $HOME so that gyp doesn't read the user's actual
# ~/.gyp/include.gypi file, which may contain variables
# and other settings that would change the output.
os.environ['HOME'] = self.workpath()
# Clear $GYP_DEFINES for the same reason.
if 'GYP_DEFINES' in os.environ:
del os.environ['GYP_DEFINES']
+ # Override the user's language settings, which could
+ # otherwise make the output vary from what is expected.
+ os.environ['LC_ALL'] = 'C'
def built_file_must_exist(self, name, type=None, **kw):
"""
Fails the test if the specified built file name does not exist.
"""
return self.must_exist(self.built_file_path(name, type, **kw))
def built_file_must_not_exist(self, name, type=None, **kw):
@@ -149,16 +178,23 @@ class TestGypBase(TestCommon.TestCommon)
def built_file_must_not_match(self, name, contents, **kw):
"""
Fails the test if the contents of the specified built file name
match the specified contents.
"""
return self.must_not_match(self.built_file_path(name, **kw), contents)
+ def built_file_must_not_contain(self, name, contents, **kw):
+ """
+ Fails the test if the specified built file name contains the specified
+ contents.
+ """
+ return self.must_not_contain(self.built_file_path(name, **kw), contents)
+
def copy_test_configuration(self, source_dir, dest_dir):
"""
Copies the test configuration from the specified source_dir
(the directory in which the test script lives) to the
specified dest_dir (a temporary working directory).
This ignores all files and directories that begin with
the string 'gyptest', and all '.svn' subdirectories.
@@ -174,16 +210,37 @@ class TestGypBase(TestCommon.TestCommon)
os.mkdir(destination)
if sys.platform != 'win32':
shutil.copystat(source, destination)
for filename in files:
source = os.path.join(root, filename)
destination = source.replace(source_dir, dest_dir)
shutil.copy2(source, destination)
+ # The gyp tests are run with HOME pointing to |dest_dir| to provide an
+ # hermetic environment. Symlink login.keychain and the 'Provisioning
+ # Profiles' folder to allow codesign to access to the data required for
+ # signing binaries.
+ if sys.platform == 'darwin':
+ old_keychain = GetDefaultKeychainPath()
+ old_provisioning_profiles = os.path.join(
+ os.environ['HOME'], 'Library', 'MobileDevice',
+ 'Provisioning Profiles')
+
+ new_keychain = os.path.join(dest_dir, 'Library', 'Keychains')
+ MakeDirs(new_keychain)
+ os.symlink(old_keychain, os.path.join(new_keychain, 'login.keychain'))
+
+ if os.path.exists(old_provisioning_profiles):
+ new_provisioning_profiles = os.path.join(
+ dest_dir, 'Library', 'MobileDevice')
+ MakeDirs(new_provisioning_profiles)
+ os.symlink(old_provisioning_profiles,
+ os.path.join(new_provisioning_profiles, 'Provisioning Profiles'))
+
def initialize_build_tool(self):
"""
Initializes the .build_tool attribute.
Searches the .build_tool_list for an executable name on the user's
$PATH. The first tool on the list is used as-is if nothing is found
on the current $PATH.
"""
@@ -217,17 +274,17 @@ class TestGypBase(TestCommon.TestCommon)
os.rename(source, destination)
def report_not_up_to_date(self):
"""
Reports that a build is not up-to-date.
This provides common reporting for formats that have complicated
conditions for checking whether a build is up-to-date. Formats
- that expect exact output from the command (make, scons) can
+ that expect exact output from the command (make) can
just set stdout= when they call the run_build() method.
"""
print "Build is not up-to-date:"
print self.banner('STDOUT ')
print self.stdout()
stderr = self.stderr()
if stderr:
print self.banner('STDERR ')
@@ -240,18 +297,28 @@ class TestGypBase(TestCommon.TestCommon)
# When running gyp, and comparing its output we use a comparitor
# that ignores the line numbers that gyp logs in its debug output.
if kw.pop('ignore_line_numbers', False):
kw.setdefault('match', match_modulo_line_numbers)
# TODO: --depth=. works around Chromium-specific tree climbing.
depth = kw.pop('depth', '.')
- run_args = ['--depth='+depth, '--format='+self.format, gyp_file]
+ run_args = ['--depth='+depth]
+ run_args.extend(['--format='+f for f in self.formats]);
+ run_args.append(gyp_file)
+ if self.no_parallel:
+ run_args += ['--no-parallel']
+ # TODO: if extra_args contains a '--build' flag
+ # we really want that to only apply to the last format (self.format).
run_args.extend(self.extra_args)
+ # Default xcode_ninja_target_pattern to ^.*$ to fix xcode-ninja tests
+ xcode_ninja_target_pattern = kw.pop('xcode_ninja_target_pattern', '.*')
+ run_args.extend(
+ ['-G', 'xcode_ninja_target_pattern=%s' % xcode_ninja_target_pattern])
run_args.extend(args)
return self.run(program=self.gyp, arguments=run_args, **kw)
def run(self, *args, **kw):
"""
Executes a program by calling the superclass .run() method.
This exists to provide a common place to filter out keyword
@@ -313,16 +380,18 @@ class TestGypBase(TestCommon.TestCommon)
"""
if not kw.get('bare'):
if type == self.EXECUTABLE:
name = name + self._exe
elif type == self.STATIC_LIB:
name = self.lib_ + name + self._lib
elif type == self.SHARED_LIB:
name = self.dll_ + name + self._dll
+ elif type == self.LOADABLE_MODULE:
+ name = self.module_ + name + self._module
return name
def run_built_executable(self, name, *args, **kw):
"""
Runs an executable program built from a gyp-generated configuration.
The specified name should be independent of any particular generator.
Subclasses should find the output executable in the appropriate
@@ -343,184 +412,133 @@ class TestGypBase(TestCommon.TestCommon)
class TestGypGypd(TestGypBase):
"""
Subclass for testing the GYP 'gypd' generator (spit out the
internal data structure as pretty-printed Python).
"""
format = 'gypd'
+ def __init__(self, gyp=None, *args, **kw):
+ super(TestGypGypd, self).__init__(*args, **kw)
+ # gypd implies the use of 'golden' files, so parallelizing conflicts as it
+ # causes ordering changes.
+ self.no_parallel = True
class TestGypCustom(TestGypBase):
"""
Subclass for testing the GYP with custom generator
"""
def __init__(self, gyp=None, *args, **kw):
self.format = kw.pop("format")
super(TestGypCustom, self).__init__(*args, **kw)
-class TestGypAndroid(TestGypBase):
+class TestGypCMake(TestGypBase):
+ """
+ Subclass for testing the GYP CMake generator, using cmake's ninja backend.
"""
- Subclass for testing the GYP Android makefile generator. Note that
- build/envsetup.sh and lunch must have been run before running tests.
+ format = 'cmake'
+ build_tool_list = ['cmake']
+ ALL = 'all'
+
+ def cmake_build(self, gyp_file, target=None, **kw):
+ arguments = kw.get('arguments', [])[:]
- TODO: This is currently an incomplete implementation. We do not support
- run_built_executable(), so we pass only tests which do not use this. As a
- result, support for host targets is not properly tested.
- """
- format = 'android'
+ self.build_tool_list = ['cmake']
+ self.initialize_build_tool()
+
+ chdir = os.path.join(kw.get('chdir', '.'),
+ 'out',
+ self.configuration_dirname())
+ kw['chdir'] = chdir
+
+ arguments.append('-G')
+ arguments.append('Ninja')
- # Note that we can't use mmm as the build tool because ...
- # - it builds all targets, whereas we need to pass a target
- # - it is a function, whereas the test runner assumes the build tool is a file
- # Instead we use make and duplicate the logic from mmm.
- build_tool_list = ['make']
+ kw['arguments'] = arguments
+
+ stderr = kw.get('stderr', None)
+ if stderr:
+ kw['stderr'] = stderr.split('$$$')[0]
+
+ self.run(program=self.build_tool, **kw)
+
+ def ninja_build(self, gyp_file, target=None, **kw):
+ arguments = kw.get('arguments', [])[:]
- # We use our custom target 'gyp_all_modules', as opposed to the 'all_modules'
- # target used by mmm, to build only those targets which are part of the gyp
- # target 'all'.
- ALL = 'gyp_all_modules'
+ self.build_tool_list = ['ninja']
+ self.initialize_build_tool()
+
+ # Add a -C output/path to the command line.
+ arguments.append('-C')
+ arguments.append(os.path.join('out', self.configuration_dirname()))
+
+ if target not in (None, self.DEFAULT):
+ arguments.append(target)
+
+ kw['arguments'] = arguments
- def __init__(self, gyp=None, *args, **kw):
- # Android requires build and test output to be outside its source tree.
- # We use the following working directory for the test's source, but the
- # test's build output still goes to $ANDROID_PRODUCT_OUT.
- # Note that some tests explicitly set format='gypd' to invoke the gypd
- # backend. This writes to the source tree, but there's no way around this.
- kw['workdir'] = os.path.join('/tmp', 'gyptest',
- kw.get('workdir', 'testworkarea'))
- # We need to remove all gyp outputs from out/. Ths is because some tests
- # don't have rules to regenerate output, so they will simply re-use stale
- # output if present. Since the test working directory gets regenerated for
- # each test run, this can confuse things.
- # We don't have a list of build outputs because we don't know which
- # dependent targets were built. Instead we delete all gyp-generated output.
- # This may be excessive, but should be safe.
- out_dir = os.environ['ANDROID_PRODUCT_OUT']
- obj_dir = os.path.join(out_dir, 'obj')
- shutil.rmtree(os.path.join(obj_dir, 'GYP'), ignore_errors = True)
- shutil.rmtree(os.path.join(obj_dir, 'NONE'), ignore_errors = True)
- for x in ['EXECUTABLES', 'STATIC_LIBRARIES', 'SHARED_LIBRARIES']:
- for d in os.listdir(os.path.join(obj_dir, x)):
- if d.endswith('_gyp_intermediates'):
- shutil.rmtree(os.path.join(obj_dir, x, d), ignore_errors = True)
- for x in [os.path.join('obj', 'lib'), os.path.join('system', 'lib')]:
- for d in os.listdir(os.path.join(out_dir, x)):
- if d.endswith('_gyp.so'):
- os.remove(os.path.join(out_dir, x, d))
+ stderr = kw.get('stderr', None)
+ if stderr:
+ stderrs = stderr.split('$$$')
+ kw['stderr'] = stderrs[1] if len(stderrs) > 1 else ''
+
+ return self.run(program=self.build_tool, **kw)
+
+ def build(self, gyp_file, target=None, status=0, **kw):
+ # Two tools must be run to build, cmake and the ninja.
+ # Allow cmake to succeed when the overall expectation is to fail.
+ if status is None:
+ kw['status'] = None
+ else:
+ if not isinstance(status, collections.Iterable): status = (status,)
+ kw['status'] = list(itertools.chain((0,), status))
+ self.cmake_build(gyp_file, target, **kw)
+ kw['status'] = status
+ self.ninja_build(gyp_file, target, **kw)
+
+ 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':
+ configuration = self.configuration_dirname()
+ os.environ['DYLD_LIBRARY_PATH'] = os.path.join('out', configuration)
+ return self.run(program=program, *args, **kw)
- super(TestGypAndroid, self).__init__(*args, **kw)
-
- def target_name(self, target):
- if target == self.ALL:
- return self.ALL
- # The default target is 'droid'. However, we want to use our special target
- # to build only the gyp target 'all'.
- if target in (None, self.DEFAULT):
- return self.ALL
- return target
+ def built_file_path(self, name, type=None, **kw):
+ result = []
+ chdir = kw.get('chdir')
+ if chdir:
+ result.append(chdir)
+ result.append('out')
+ result.append(self.configuration_dirname())
+ if type == self.STATIC_LIB:
+ if sys.platform != 'darwin':
+ result.append('obj.target')
+ elif type == self.SHARED_LIB:
+ if sys.platform != 'darwin' and sys.platform != 'win32':
+ result.append('lib.target')
+ subdir = kw.get('subdir')
+ if subdir and type != self.SHARED_LIB:
+ result.append(subdir)
+ result.append(self.built_file_basename(name, type, **kw))
+ return self.workpath(*result)
- def build(self, gyp_file, target=None, **kw):
- """
- Runs a build using the Android makefiles generated from the specified
- gyp_file. This logic is taken from Android's mmm.
- """
- arguments = kw.get('arguments', [])[:]
- arguments.append(self.target_name(target))
- arguments.append('-C')
- arguments.append(os.environ['ANDROID_BUILD_TOP'])
- kw['arguments'] = arguments
- chdir = kw.get('chdir', '')
- makefile = os.path.join(self.workdir, chdir, 'GypAndroid.mk')
- os.environ['ONE_SHOT_MAKEFILE'] = makefile
- result = self.run(program=self.build_tool, **kw)
- del os.environ['ONE_SHOT_MAKEFILE']
+ def up_to_date(self, gyp_file, target=None, **kw):
+ result = self.ninja_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
- def android_module(self, group, name, subdir):
- if subdir:
- name = '%s_%s' % (subdir, name)
- if group == 'SHARED_LIBRARIES':
- name = 'lib_%s' % name
- return '%s_gyp' % name
-
- def intermediates_dir(self, group, module_name):
- return os.path.join(os.environ['ANDROID_PRODUCT_OUT'], 'obj', group,
- '%s_intermediates' % module_name)
-
- def built_file_path(self, name, type=None, **kw):
- """
- Returns a path to the specified file name, of the specified type,
- as built by Android. Note that we don't support the configuration
- parameter.
- """
- # Built files are in $ANDROID_PRODUCT_OUT. This requires copying logic from
- # the Android build system.
- if type == None:
- return os.path.join(os.environ['ANDROID_PRODUCT_OUT'], 'obj', 'GYP',
- 'shared_intermediates', name)
- subdir = kw.get('subdir')
- if type == self.EXECUTABLE:
- # We don't install executables
- group = 'EXECUTABLES'
- module_name = self.android_module(group, name, subdir)
- return os.path.join(self.intermediates_dir(group, module_name), name)
- if type == self.STATIC_LIB:
- group = 'STATIC_LIBRARIES'
- module_name = self.android_module(group, name, subdir)
- return os.path.join(self.intermediates_dir(group, module_name),
- '%s.a' % module_name)
- if type == self.SHARED_LIB:
- group = 'SHARED_LIBRARIES'
- module_name = self.android_module(group, name, subdir)
- return os.path.join(self.intermediates_dir(group, module_name), 'LINKED',
- '%s.so' % module_name)
- assert False, 'Unhandled type'
-
- def run_built_executable(self, name, *args, **kw):
- """
- Runs an executable program built from a gyp-generated configuration.
-
- This is not correctly implemented for Android. For now, we simply check
- that the executable file exists.
- """
- # Running executables requires a device. Even if we build for target x86,
- # the binary is not built with the correct toolchain options to actually
- # run on the host.
-
- # Copied from TestCommon.run()
- match = kw.pop('match', self.match)
- status = None
- if os.path.exists(self.built_file_path(name)):
- status = 1
- self._complete(None, None, None, None, status, self.match)
-
- def match_single_line(self, lines = None, expected_line = None):
- """
- Checks that specified line appears in the text.
- """
- for line in lines.split('\n'):
- if line == expected_line:
- return 1
- return
-
- def up_to_date(self, gyp_file, target=None, **kw):
- """
- Verifies that a build of the specified target is up to date.
- """
- kw['stdout'] = ("make: Nothing to be done for `%s'." %
- self.target_name(target))
-
- # We need to supply a custom matcher, since we don't want to depend on the
- # exact stdout string.
- kw['match'] = self.match_single_line
- return self.build(gyp_file, target, **kw)
class TestGypMake(TestGypBase):
"""
Subclass for testing the GYP Make generator.
"""
format = 'make'
build_tool_list = ['make']
ALL = 'all'
@@ -607,71 +625,128 @@ class TestGypMake(TestGypBase):
def ConvertToCygpath(path):
"""Convert to cygwin path if we are using cygwin."""
if sys.platform == 'cygwin':
p = subprocess.Popen(['cygpath', path], stdout=subprocess.PIPE)
path = p.communicate()[0].strip()
return path
+def MakeDirs(new_dir):
+ """A wrapper around os.makedirs() that emulates "mkdir -p"."""
+ try:
+ os.makedirs(new_dir)
+ except OSError as e:
+ if e.errno != errno.EEXIST:
+ raise
+
+def GetDefaultKeychainPath():
+ """Get the keychain path, for used before updating HOME."""
+ assert sys.platform == 'darwin'
+ # Format is:
+ # $ security default-keychain
+ # "/Some/Path/To/default.keychain"
+ path = subprocess.check_output(['security', 'default-keychain']).strip()
+ return path[1:-1]
+
+def FindMSBuildInstallation(msvs_version = 'auto'):
+ """Returns path to MSBuild for msvs_version or latest available.
+
+ Looks in the registry to find install location of MSBuild.
+ MSBuild before v4.0 will not build c++ projects, so only use newer versions.
+ """
+ import TestWin
+ registry = TestWin.Registry()
+
+ msvs_to_msbuild = {
+ '2013': r'12.0',
+ '2012': r'4.0', # Really v4.0.30319 which comes with .NET 4.5.
+ '2010': r'4.0'}
+
+ msbuild_basekey = r'HKLM\SOFTWARE\Microsoft\MSBuild\ToolsVersions'
+ if not registry.KeyExists(msbuild_basekey):
+ print 'Error: could not find MSBuild base registry entry'
+ return None
+
+ msbuild_version = None
+ if msvs_version in msvs_to_msbuild:
+ msbuild_test_version = msvs_to_msbuild[msvs_version]
+ if registry.KeyExists(msbuild_basekey + '\\' + msbuild_test_version):
+ msbuild_version = msbuild_test_version
+ else:
+ print ('Warning: Environment variable GYP_MSVS_VERSION specifies "%s" '
+ 'but corresponding MSBuild "%s" was not found.' %
+ (msvs_version, msbuild_version))
+ if not msbuild_version:
+ for msvs_version in sorted(msvs_to_msbuild, reverse=True):
+ msbuild_test_version = msvs_to_msbuild[msvs_version]
+ if registry.KeyExists(msbuild_basekey + '\\' + msbuild_test_version):
+ msbuild_version = msbuild_test_version
+ break
+ if not msbuild_version:
+ print 'Error: could not find MSBuild registry entry'
+ return None
+
+ msbuild_path = registry.GetValue(msbuild_basekey + '\\' + msbuild_version,
+ 'MSBuildToolsPath')
+ if not msbuild_path:
+ print 'Error: could not get MSBuild registry entry value'
+ return None
+
+ return os.path.join(msbuild_path, 'MSBuild.exe')
+
+
def FindVisualStudioInstallation():
"""Returns appropriate values for .build_tool and .uses_msbuild fields
of TestGypBase for Visual Studio.
We use the value specified by GYP_MSVS_VERSION. If not specified, we
search %PATH% and %PATHEXT% for a devenv.{exe,bat,...} executable.
Failing that, we search for likely deployment paths.
"""
- possible_roots = ['C:\\Program Files (x86)', 'C:\\Program Files',
- 'E:\\Program Files (x86)', 'E:\\Program Files']
+ possible_roots = ['%s:\\Program Files%s' % (chr(drive), suffix)
+ for drive in range(ord('C'), ord('Z') + 1)
+ for suffix in ['', ' (x86)']]
possible_paths = {
+ '2015': r'Microsoft Visual Studio 14.0\Common7\IDE\devenv.com',
+ '2013': r'Microsoft Visual Studio 12.0\Common7\IDE\devenv.com',
+ '2012': r'Microsoft Visual Studio 11.0\Common7\IDE\devenv.com',
'2010': r'Microsoft Visual Studio 10.0\Common7\IDE\devenv.com',
'2008': r'Microsoft Visual Studio 9.0\Common7\IDE\devenv.com',
'2005': r'Microsoft Visual Studio 8\Common7\IDE\devenv.com'}
possible_roots = [ConvertToCygpath(r) for r in possible_roots]
msvs_version = 'auto'
for flag in (f for f in sys.argv if f.startswith('msvs_version=')):
msvs_version = flag.split('=')[-1]
msvs_version = os.environ.get('GYP_MSVS_VERSION', msvs_version)
- build_tool = None
if msvs_version in possible_paths:
# Check that the path to the specified GYP_MSVS_VERSION exists.
path = possible_paths[msvs_version]
for r in possible_roots:
- bt = os.path.join(r, path)
- if os.path.exists(bt):
- build_tool = bt
+ build_tool = os.path.join(r, path)
+ if os.path.exists(build_tool):
uses_msbuild = msvs_version >= '2010'
- return build_tool, uses_msbuild
+ msbuild_path = FindMSBuildInstallation(msvs_version)
+ return build_tool, uses_msbuild, msbuild_path
else:
print ('Warning: Environment variable GYP_MSVS_VERSION specifies "%s" '
'but corresponding "%s" was not found.' % (msvs_version, path))
- if build_tool:
- # We found 'devenv' on the path, use that and try to guess the version.
- for version, path in possible_paths.iteritems():
- if build_tool.find(path) >= 0:
- uses_msbuild = version >= '2010'
- return build_tool, uses_msbuild
- else:
- # If not, assume not MSBuild.
- uses_msbuild = False
- return build_tool, uses_msbuild
# Neither GYP_MSVS_VERSION nor the path help us out. Iterate through
# the choices looking for a match.
for version in sorted(possible_paths, reverse=True):
path = possible_paths[version]
for r in possible_roots:
- bt = os.path.join(r, path)
- if os.path.exists(bt):
- build_tool = bt
+ build_tool = os.path.join(r, path)
+ if os.path.exists(build_tool):
uses_msbuild = msvs_version >= '2010'
- return build_tool, uses_msbuild
+ msbuild_path = FindMSBuildInstallation(msvs_version)
+ return build_tool, uses_msbuild, msbuild_path
print 'Error: could not find devenv'
sys.exit(1)
class TestGypOnMSToolchain(TestGypBase):
"""
Common subclass for testing generators that target the Microsoft Visual
Studio toolchain (cl, link, dumpbin, etc.)
"""
@@ -679,17 +754,18 @@ class TestGypOnMSToolchain(TestGypBase):
def _ComputeVsvarsPath(devenv_path):
devenv_dir = os.path.split(devenv_path)[0]
vsvars_path = os.path.join(devenv_path, '../../Tools/vsvars32.bat')
return vsvars_path
def initialize_build_tool(self):
super(TestGypOnMSToolchain, self).initialize_build_tool()
if sys.platform in ('win32', 'cygwin'):
- self.devenv_path, self.uses_msbuild = FindVisualStudioInstallation()
+ build_tools = FindVisualStudioInstallation()
+ self.devenv_path, self.uses_msbuild, self.msbuild_path = build_tools
self.vsvars_path = TestGypOnMSToolchain._ComputeVsvarsPath(
self.devenv_path)
def run_dumpbin(self, *dumpbin_args):
"""Run the dumpbin tool with the specified arguments, and capturing and
returning stdout."""
assert sys.platform in ('win32', 'cygwin')
cmd = os.environ.get('COMSPEC', 'cmd.exe')
@@ -778,23 +854,25 @@ class TestGypMSVS(TestGypOnMSToolchain):
# Note: we must use devenv.com to be able to capture build output.
# Directly executing devenv.exe only sends output to BuildLog.htm.
build_tool_list = [None, 'devenv.com']
def initialize_build_tool(self):
super(TestGypMSVS, self).initialize_build_tool()
self.build_tool = self.devenv_path
- def build(self, gyp_file, target=None, rebuild=False, **kw):
+ def build(self, gyp_file, target=None, rebuild=False, clean=False, **kw):
"""
Runs a Visual Studio build using the configuration generated
from the specified gyp_file.
"""
configuration = self.configuration_buildname()
- if rebuild:
+ if clean:
+ build = '/Clean'
+ elif rebuild:
build = '/Rebuild'
else:
build = '/Build'
arguments = kw.get('arguments', [])[:]
arguments.extend([gyp_file.replace('.gyp', '.sln'),
build, configuration])
# Note: the Visual Studio generator doesn't add an explicit 'all'
# target, so we just treat it the same as the default.
@@ -857,86 +935,64 @@ class TestGypMSVS(TestGypOnMSToolchain):
result.append(chdir)
result.append(self.configuration_dirname())
if type == self.STATIC_LIB:
result.append('lib')
result.append(self.built_file_basename(name, type, **kw))
return self.workpath(*result)
-class TestGypSCons(TestGypBase):
+class TestGypMSVSNinja(TestGypNinja):
"""
- Subclass for testing the GYP SCons generator.
+ Subclass for testing the GYP Visual Studio Ninja generator.
"""
- format = 'scons'
- build_tool_list = ['scons', 'scons.py']
- ALL = 'all'
- def build(self, gyp_file, target=None, **kw):
+ format = 'msvs-ninja'
+
+ def initialize_build_tool(self):
+ super(TestGypMSVSNinja, self).initialize_build_tool()
+ # When using '--build', make sure ninja is first in the format list.
+ self.formats.insert(0, 'ninja')
+
+ def build(self, gyp_file, target=None, rebuild=False, clean=False, **kw):
"""
- Runs a scons build using the SCons configuration generated from the
- specified gyp_file.
+ Runs a Visual Studio build using the configuration generated
+ from the specified gyp_file.
"""
arguments = kw.get('arguments', [])[:]
- dirname = os.path.dirname(gyp_file)
- if dirname:
- arguments.extend(['-C', dirname])
- if self.configuration:
- arguments.append('--mode=' + self.configuration)
- if target not in (None, self.DEFAULT):
- arguments.append(target)
- kw['arguments'] = arguments
- return self.run(program=self.build_tool, **kw)
- def up_to_date(self, gyp_file, target=None, **kw):
- """
- Verifies that a build of the specified SCons target is up to date.
- """
- if target in (None, self.DEFAULT):
- up_to_date_targets = 'all'
+ if target in (None, self.ALL, self.DEFAULT):
+ # Note: the Visual Studio generator doesn't add an explicit 'all' target.
+ # This will build each project. This will work if projects are hermetic,
+ # but may fail if they are not (a project may run more than once).
+ # It would be nice to supply an all.metaproj for MSBuild.
+ arguments.extend([gyp_file.replace('.gyp', '.sln')])
else:
- up_to_date_targets = target
- up_to_date_lines = []
- for arg in up_to_date_targets.split():
- up_to_date_lines.append("scons: `%s' is up to date.\n" % arg)
- kw['stdout'] = ''.join(up_to_date_lines)
- arguments = kw.get('arguments', [])[:]
- arguments.append('-Q')
+ # MSBuild documentation claims that one can specify a sln but then build a
+ # project target like 'msbuild a.sln /t:proj:target' but this format only
+ # supports 'Clean', 'Rebuild', and 'Publish' (with none meaning Default).
+ # This limitation is due to the .sln -> .sln.metaproj conversion.
+ # The ':' is not special, 'proj:target' is a target in the metaproj.
+ arguments.extend([target+'.vcxproj'])
+
+ if clean:
+ build = 'Clean'
+ elif rebuild:
+ build = 'Rebuild'
+ else:
+ build = 'Build'
+ arguments.extend(['/target:'+build])
+ configuration = self.configuration_buildname()
+ config = configuration.split('|')
+ arguments.extend(['/property:Configuration='+config[0]])
+ if len(config) > 1:
+ arguments.extend(['/property:Platform='+config[1]])
+ arguments.extend(['/property:BuildInParallel=false'])
+ arguments.extend(['/verbosity:minimal'])
+
kw['arguments'] = arguments
- return self.build(gyp_file, target, **kw)
- def run_built_executable(self, name, *args, **kw):
- """
- Runs an executable built by scons.
- """
- configuration = self.configuration_dirname()
- os.environ['LD_LIBRARY_PATH'] = os.path.join(configuration, 'lib')
- # Enclosing the name in a list avoids prepending the original dir.
- program = [self.built_file_path(name, type=self.EXECUTABLE, **kw)]
- return self.run(program=program, *args, **kw)
- def built_file_path(self, name, type=None, **kw):
- """
- Returns a path to the specified file name, of the specified type,
- as built by Scons.
-
- Built files are in a subdirectory that matches the configuration
- name. The default is 'Default'.
-
- A chdir= keyword argument specifies the source directory
- relative to which the output subdirectory can be found.
-
- "type" values of STATIC_LIB or SHARED_LIB append the necessary
- prefixes and suffixes to a platform-independent library base name.
- """
- result = []
- chdir = kw.get('chdir')
- if chdir:
- result.append(chdir)
- result.append(self.configuration_dirname())
- if type in (self.STATIC_LIB, self.SHARED_LIB):
- result.append('lib')
- result.append(self.built_file_basename(name, type, **kw))
- return self.workpath(*result)
+ return self.run(program=self.msbuild_path, **kw)
class TestGypXcode(TestGypBase):
"""
Subclass for testing the GYP Xcode generator.
"""
format = 'xcode'
build_tool_list = ['xcodebuild']
@@ -955,16 +1011,18 @@ class TestGypXcode(TestGypBase):
# The message from distcc_pump can trail the "BUILD SUCCEEDED"
# message, so strip that, too.
re.compile('__________Shutting down distcc-pump include server\n', re.S),
]
up_to_date_endings = (
'Checking Dependencies...\n** BUILD SUCCEEDED **\n', # Xcode 3.0/3.1
'Check dependencies\n** BUILD SUCCEEDED **\n\n', # Xcode 3.2
+ 'Check dependencies\n\n\n** BUILD SUCCEEDED **\n\n', # Xcode 4.2
+ 'Check dependencies\n\n** BUILD SUCCEEDED **\n\n', # Xcode 5.0
)
def build(self, gyp_file, target=None, **kw):
"""
Runs an xcodebuild using the .xcodeproj generated from the specified
gyp_file.
"""
# Be sure we're working with a copy of 'arguments' since we modify it.
@@ -976,16 +1034,33 @@ class TestGypXcode(TestGypBase):
elif target not in (None, self.DEFAULT):
arguments.extend(['-target', target])
if self.configuration:
arguments.extend(['-configuration', self.configuration])
symroot = kw.get('SYMROOT', '$SRCROOT/build')
if symroot:
arguments.append('SYMROOT='+symroot)
kw['arguments'] = arguments
+
+ # Work around spurious stderr output from Xcode 4, http://crbug.com/181012
+ match = kw.pop('match', self.match)
+ def match_filter_xcode(actual, expected):
+ if actual:
+ if not TestCmd.is_List(actual):
+ actual = actual.split('\n')
+ if not TestCmd.is_List(expected):
+ expected = expected.split('\n')
+ actual = [a for a in actual
+ if 'No recorder, buildTask: <Xcode3BuildTask:' not in a and
+ 'Beginning test session' not in a and
+ 'Writing diagnostic log' not in a and
+ 'Logs/Test/' not in a]
+ return match(actual, expected)
+ kw['match'] = match_filter_xcode
+
return self.run(program=self.build_tool, **kw)
def up_to_date(self, gyp_file, target=None, **kw):
"""
Verifies that a build of the specified Xcode target is up to date.
"""
result = self.build(gyp_file, target, **kw)
if not result:
output = self.stdout()
@@ -1023,24 +1098,93 @@ class TestGypXcode(TestGypBase):
if chdir:
result.append(chdir)
configuration = self.configuration_dirname()
result.extend(['build', configuration])
result.append(self.built_file_basename(name, type, **kw))
return self.workpath(*result)
+class TestGypXcodeNinja(TestGypXcode):
+ """
+ Subclass for testing the GYP Xcode Ninja generator.
+ """
+ format = 'xcode-ninja'
+
+ def initialize_build_tool(self):
+ super(TestGypXcodeNinja, self).initialize_build_tool()
+ # When using '--build', make sure ninja is first in the format list.
+ self.formats.insert(0, 'ninja')
+
+ def build(self, gyp_file, target=None, **kw):
+ """
+ Runs an xcodebuild using the .xcodeproj generated from the specified
+ gyp_file.
+ """
+ build_config = self.configuration
+ if build_config and build_config.endswith(('-iphoneos',
+ '-iphonesimulator')):
+ build_config, sdk = self.configuration.split('-')
+ kw['arguments'] = kw.get('arguments', []) + ['-sdk', sdk]
+
+ with self._build_configuration(build_config):
+ return super(TestGypXcodeNinja, self).build(
+ gyp_file.replace('.gyp', '.ninja.gyp'), target, **kw)
+
+ @contextmanager
+ def _build_configuration(self, build_config):
+ config = self.configuration
+ self.configuration = build_config
+ try:
+ yield
+ finally:
+ self.configuration = config
+
+ def built_file_path(self, name, type=None, **kw):
+ result = []
+ chdir = kw.get('chdir')
+ if chdir:
+ result.append(chdir)
+ result.append('out')
+ result.append(self.configuration_dirname())
+ subdir = kw.get('subdir')
+ if subdir and type != self.SHARED_LIB:
+ result.append(subdir)
+ result.append(self.built_file_basename(name, type, **kw))
+ return self.workpath(*result)
+
+ def up_to_date(self, gyp_file, target=None, **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
+
+ def run_built_executable(self, name, *args, **kw):
+ """
+ Runs an executable built by xcodebuild + ninja.
+ """
+ configuration = self.configuration_dirname()
+ os.environ['DYLD_LIBRARY_PATH'] = os.path.join('out', configuration)
+ # Enclosing the name in a list avoids prepending the original dir.
+ program = [self.built_file_path(name, type=self.EXECUTABLE, **kw)]
+ return self.run(program=program, *args, **kw)
+
+
format_class_list = [
TestGypGypd,
- TestGypAndroid,
+ TestGypCMake,
TestGypMake,
TestGypMSVS,
+ TestGypMSVSNinja,
TestGypNinja,
- TestGypSCons,
TestGypXcode,
+ TestGypXcodeNinja,
]
def TestGyp(*args, **kw):
"""
Returns an appropriate TestGyp* instance for a specified GYP format.
"""
format = kw.pop('format', os.environ.get('TESTGYP_FORMAT'))
for format_class in format_class_list:
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/lib/TestMac.py
@@ -0,0 +1,73 @@
+# Copyright (c) 2014 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.
+
+"""
+TestMac.py: a collection of helper function shared between test on Mac OS X.
+"""
+
+import re
+import subprocess
+
+__all__ = ['Xcode', 'CheckFileType']
+
+
+def CheckFileType(test, file, archs):
+ """Check that |file| contains exactly |archs| or fails |test|."""
+ proc = subprocess.Popen(['lipo', '-info', file], stdout=subprocess.PIPE)
+ o = proc.communicate()[0].strip()
+ assert not proc.returncode
+ if len(archs) == 1:
+ pattern = re.compile('^Non-fat file: (.*) is architecture: (.*)$')
+ else:
+ pattern = re.compile('^Architectures in the fat file: (.*) are: (.*)$')
+ match = pattern.match(o)
+ if match is None:
+ print 'Ouput does not match expected pattern: %s' % (pattern.pattern)
+ test.fail_test()
+ else:
+ found_file, found_archs = match.groups()
+ if found_file != file or set(found_archs.split()) != set(archs):
+ print 'Expected file %s with arch %s, got %s with arch %s' % (
+ file, ' '.join(archs), found_file, found_archs)
+ test.fail_test()
+
+
+class XcodeInfo(object):
+ """Simplify access to Xcode informations."""
+
+ def __init__(self):
+ self._cache = {}
+
+ def _XcodeVersion(self):
+ lines = subprocess.check_output(['xcodebuild', '-version']).splitlines()
+ version = ''.join(lines[0].split()[-1].split('.'))
+ version = (version + '0' * (3 - len(version))).zfill(4)
+ return version, lines[-1].split()[-1]
+
+ def Version(self):
+ if 'Version' not in self._cache:
+ self._cache['Version'], self._cache['Build'] = self._XcodeVersion()
+ return self._cache['Version']
+
+ def Build(self):
+ if 'Build' not in self._cache:
+ self._cache['Version'], self._cache['Build'] = self._XcodeVersion()
+ return self._cache['Build']
+
+ def SDKBuild(self):
+ if 'SDKBuild' not in self._cache:
+ self._cache['SDKBuild'] = subprocess.check_output(
+ ['xcodebuild', '-version', '-sdk', '', 'ProductBuildVersion'])
+ self._cache['SDKBuild'] = self._cache['SDKBuild'].rstrip('\n')
+ return self._cache['SDKBuild']
+
+ def SDKVersion(self):
+ if 'SDKVersion' not in self._cache:
+ self._cache['SDKVersion'] = subprocess.check_output(
+ ['xcodebuild', '-version', '-sdk', '', 'SDKVersion'])
+ self._cache['SDKVersion'] = self._cache['SDKVersion'].rstrip('\n')
+ return self._cache['SDKVersion']
+
+
+Xcode = XcodeInfo()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/lib/TestWin.py
@@ -0,0 +1,101 @@
+# Copyright (c) 2014 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.
+
+"""
+TestWin.py: a collection of helpers for testing on Windows.
+"""
+
+import errno
+import os
+import re
+import sys
+import subprocess
+
+class Registry(object):
+ def _QueryBase(self, sysdir, key, value):
+ """Use reg.exe to read a particular key.
+
+ While ideally we might use the win32 module, we would like gyp to be
+ python neutral, so for instance cygwin python lacks this module.
+
+ Arguments:
+ sysdir: The system subdirectory to attempt to launch reg.exe from.
+ key: The registry key to read from.
+ value: The particular value to read.
+ Return:
+ stdout from reg.exe, or None for failure.
+ """
+ # Skip if not on Windows or Python Win32 setup issue
+ if sys.platform not in ('win32', 'cygwin'):
+ return None
+ # Setup params to pass to and attempt to launch reg.exe
+ cmd = [os.path.join(os.environ.get('WINDIR', ''), sysdir, 'reg.exe'),
+ 'query', key]
+ if value:
+ cmd.extend(['/v', value])
+ p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ # Get the stdout from reg.exe, reading to the end so p.returncode is valid
+ # Note that the error text may be in [1] in some cases
+ text = p.communicate()[0]
+ # Check return code from reg.exe; officially 0==success and 1==error
+ if p.returncode:
+ return None
+ return text
+
+ def Query(self, key, value=None):
+ r"""Use reg.exe to read a particular key through _QueryBase.
+
+ First tries to launch from %WinDir%\Sysnative to avoid WoW64 redirection. If
+ that fails, it falls back to System32. Sysnative is available on Vista and
+ up and available on Windows Server 2003 and XP through KB patch 942589. Note
+ that Sysnative will always fail if using 64-bit python due to it being a
+ virtual directory and System32 will work correctly in the first place.
+
+ KB 942589 - http://support.microsoft.com/kb/942589/en-us.
+
+ Arguments:
+ key: The registry key.
+ value: The particular registry value to read (optional).
+ Return:
+ stdout from reg.exe, or None for failure.
+ """
+ text = None
+ try:
+ text = self._QueryBase('Sysnative', key, value)
+ except OSError, e:
+ if e.errno == errno.ENOENT:
+ text = self._QueryBase('System32', key, value)
+ else:
+ raise
+ return text
+
+ def GetValue(self, key, value):
+ """Use reg.exe to obtain the value of a registry key.
+
+ Args:
+ key: The registry key.
+ value: The particular registry value to read.
+ Return:
+ contents of the registry key's value, or None on failure.
+ """
+ text = self.Query(key, value)
+ if not text:
+ return None
+ # Extract value.
+ match = re.search(r'REG_\w+\s+([^\r]+)\r\n', text)
+ if not match:
+ return None
+ return match.group(1)
+
+ def KeyExists(self, key):
+ """Use reg.exe to see if a key exists.
+
+ Args:
+ key: The registry key to check.
+ Return:
+ True if the key exists
+ """
+ if not self.Query(key):
+ return False
+ return True
--- a/media/webrtc/trunk/tools/gyp/test/library/gyptest-shared-obj-install-path.py
+++ b/media/webrtc/trunk/tools/gyp/test/library/gyptest-shared-obj-install-path.py
@@ -18,20 +18,17 @@ import TestGyp
test = TestGyp.TestGyp(formats=['make'])
test.run_gyp('shared_dependency.gyp',
chdir='src')
test.relocate('src', 'relocate/src')
test.build('shared_dependency.gyp', test.ALL, chdir='relocate/src')
-if test.format=='android':
- makefile_path = 'relocate/src/GypAndroid.mk'
-else:
- makefile_path = 'relocate/src/Makefile'
+makefile_path = 'relocate/src/Makefile'
with open(makefile_path) as makefile:
make_contents = makefile.read()
# If we remove the code to generate lib1, Make should still be able
# to build lib2 since lib1.so already exists.
make_contents = make_contents.replace('include lib1.target.mk', '')
with open(makefile_path, 'w') as makefile:
--- a/media/webrtc/trunk/tools/gyp/test/library/src/program.c
+++ b/media/webrtc/trunk/tools/gyp/test/library/src/program.c
@@ -1,15 +1,15 @@
#include <stdio.h>
extern void lib1_function(void);
extern void lib2_function(void);
extern void moveable_function(void);
-int main(int argc, char *argv[])
+int main(void)
{
fprintf(stdout, "Hello from program.c\n");
fflush(stdout);
lib1_function();
lib2_function();
moveable_function();
return 0;
}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/library_dirs/gyptest-library-dirs.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 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.
+
+"""
+Verifies library_dirs (in link_settings) are properly found.
+"""
+
+import sys
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+lib_dir = test.tempdir('secret_location')
+
+test.run_gyp('test.gyp',
+ '-D', 'abs_path_to_secret_library_location={0}'.format(lib_dir),
+ chdir='subdir')
+
+# Must build each target independently, since they are not in each others'
+# 'dependencies' (test.ALL does NOT work here for some builders, and in any case
+# would not ensure the correct ordering).
+test.build('test.gyp', 'mylib', chdir='subdir')
+test.build('test.gyp', 'libraries-search-path-test', chdir='subdir')
+
+expect = """Hello world
+"""
+test.run_built_executable(
+ 'libraries-search-path-test', chdir='subdir', stdout=expect)
+
+if sys.platform in ('win32', 'cygwin'):
+ test.run_gyp('test-win.gyp',
+ '-D',
+ 'abs_path_to_secret_library_location={0}'.format(lib_dir),
+ chdir='subdir')
+
+ test.build('test.gyp', 'mylib', chdir='subdir')
+ test.build('test-win.gyp',
+ 'libraries-search-path-test-lib-suffix',
+ chdir='subdir')
+
+ test.run_built_executable(
+ 'libraries-search-path-test-lib-suffix', chdir='subdir', stdout=expect)
+
+
+test.pass_test()
+test.cleanup()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/library_dirs/subdir/README.txt
@@ -0,0 +1,1 @@
+Make things live in a subdirectory, to make sure that DEPTH works correctly.
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/library_dirs/subdir/hello.cc
@@ -0,0 +1,11 @@
+// Copyright (c) 2013 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 <iostream>
+#include "mylib.h"
+
+int main() {
+ std::cout << "Hello " << my_foo(99) << std::endl;
+ return 0;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/library_dirs/subdir/mylib.cc
@@ -0,0 +1,9 @@
+// Copyright (c) 2013 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 "mylib.h"
+
+std::string my_foo(int x) {
+ return std::string("world");
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/library_dirs/subdir/mylib.h
@@ -0,0 +1,12 @@
+// Copyright (c) 2013 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.
+
+#ifndef TEST_LIBRARY_DIRS_SUBDIR_MYLIB_H
+#define TEST_LIBRARY_DIRS_SUBDIR_MYLIB_H
+
+#include <string>
+
+std::string my_foo(int);
+
+#endif // TEST_LIBRARY_DIRS_SUBDIR_MYLIB_H
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/library_dirs/subdir/test-win.gyp
@@ -0,0 +1,60 @@
+# Copyright (c) 2013 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': [
+ {
+ # This creates a static library and puts it in a nonstandard location for
+ # libraries-search-path-test.
+ 'target_name': 'mylib',
+ 'type': 'static_library',
+ 'standalone_static_library': 1,
+ # This directory is NOT in the default library search locations. It also
+ # MUST be passed in on the gyp command line:
+ #
+ # -D abs_path_to_secret_library_location=/some_absolute_path
+ #
+ # The gyptest itself (../gyptest-library-dirs.py) provides this.
+ 'product_dir': '<(abs_path_to_secret_library_location)',
+ 'sources': [
+ 'mylib.cc',
+ ],
+ },
+ {
+ 'target_name': 'libraries-search-path-test-lib-suffix',
+ 'type': 'executable',
+ 'dependencies': [
+ # It is important to NOT list the mylib as a dependency here, because
+ # some build systems will track it down based on its product_dir,
+ # such that the link succeeds even without the library_dirs below.
+ #
+ # The point of this weird structuring is to ensure that 'library_dirs'
+ # works as advertised, such that just '-lmylib' (or its equivalent)
+ # works based on the directories that library_dirs puts in the library
+ # link path.
+ #
+ # If 'mylib' was listed as a proper dependency here, the build system
+ # would find it and link with its path on disk.
+ #
+ # Note that this implies 'mylib' must already be built when building
+ # 'libraries-search-path-test' (see ../gyptest-library-dirs.py).
+ #
+ #'mylib',
+ ],
+ 'sources': [
+ 'hello.cc',
+ ],
+ # Note that without this, the mylib library would not be found and
+ # successfully linked.
+ 'library_dirs': [
+ '<(abs_path_to_secret_library_location)',
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '-lmylib.lib',
+ ],
+ },
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/library_dirs/subdir/test.gyp
@@ -0,0 +1,68 @@
+# Copyright (c) 2013 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': [
+ {
+ # This creates a static library and puts it in a nonstandard location for
+ # libraries-search-path-test.
+ 'target_name': 'mylib',
+ 'type': 'static_library',
+ 'standalone_static_library': 1,
+ # This directory is NOT in the default library search locations. It also
+ # MUST be passed in on the gyp command line:
+ #
+ # -D abs_path_to_secret_library_location=/some_absolute_path
+ #
+ # The gyptest itself (../gyptest-library-dirs.py) provides this.
+ 'product_dir': '<(abs_path_to_secret_library_location)',
+ 'sources': [
+ 'mylib.cc',
+ ],
+ },
+ {
+ 'target_name': 'libraries-search-path-test',
+ 'type': 'executable',
+ 'dependencies': [
+ # It is important to NOT list the mylib as a dependency here, because
+ # some build systems will track it down based on its product_dir,
+ # such that the link succeeds even without the library_dirs below.
+ #
+ # The point of this weird structuring is to ensure that 'library_dirs'
+ # works as advertised, such that just '-lmylib' (or its equivalent)
+ # works based on the directories that library_dirs puts in the library
+ # link path.
+ #
+ # If 'mylib' was listed as a proper dependency here, the build system
+ # would find it and link with its path on disk.
+ #
+ # Note that this implies 'mylib' must already be built when building
+ # 'libraries-search-path-test' (see ../gyptest-library-dirs.py).
+ #
+ #'mylib',
+ ],
+ 'sources': [
+ 'hello.cc',
+ ],
+ # Note that without this, the mylib library would not be found and
+ # successfully linked.
+ 'library_dirs': [
+ '<(abs_path_to_secret_library_location)',
+ ],
+ 'link_settings': {
+ 'conditions': [
+ ['OS=="linux"', {
+ 'libraries': [
+ '-lmylib',
+ ],
+ }, { # else
+ 'libraries': [
+ '<(STATIC_LIB_PREFIX)mylib<(STATIC_LIB_SUFFIX)',
+ ],
+ }],
+ ], # conditions
+ },
+ },
+ ],
+}
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/link-dependency/gyptest-link-dependency.py
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 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 a target marked as 'link_dependency==1' isn't being pulled into
+the 'none' target's dependency (which would otherwise lead to a dependency
+cycle in ninja).
+"""
+
+import TestGyp
+
+# See https://codereview.chromium.org/177043010/#msg15 for why this doesn't
+# work with cmake.
+test = TestGyp.TestGyp(formats=['!cmake'])
+
+test.run_gyp('test.gyp')
+test.build('test.gyp', 'main')
+
+# If running gyp worked, all is well.
+test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/link-dependency/main.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+#include <stdlib.h>
+int main() {
+ void *p = malloc(1);
+ printf("p: %p\n", p);
+ return 0;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/link-dependency/mymalloc.c
@@ -0,0 +1,12 @@
+#include <stdlib.h>
+
+// The windows ninja generator is expecting an import library to get generated,
+// but it doesn't if there are no exports.
+#ifdef _MSC_VER
+__declspec(dllexport) void foo() {}
+#endif
+
+void *malloc(size_t size) {
+ (void)size;
+ return (void*)0xdeadbeef;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/link-dependency/test.gyp
@@ -0,0 +1,37 @@
+{
+ 'variables': {
+ 'custom_malloc%' : 1,
+ },
+ 'target_defaults': {
+ 'conditions': [
+ ['custom_malloc==1', {
+ 'dependencies': [
+ 'malloc',
+ ],
+ }],
+ ],
+ },
+ 'targets': [
+ {
+ 'target_name': 'main',
+ 'type': 'none',
+ 'dependencies': [ 'main_initial',],
+ },
+ {
+ 'target_name': 'main_initial',
+ 'type': 'executable',
+ 'product_name': 'main',
+ 'sources': [ 'main.c' ],
+ },
+ {
+ 'target_name': 'malloc',
+ 'type': 'shared_library',
+ 'variables': {
+ 'prune_self_dependency': 1,
+ # Targets with type 'none' won't depend on this target.
+ 'link_dependency': 1,
+ },
+ 'sources': [ 'mymalloc.c' ],
+ },
+ ],
+}
--- a/media/webrtc/trunk/tools/gyp/test/link-objects/base.c
+++ b/media/webrtc/trunk/tools/gyp/test/link-objects/base.c
@@ -1,6 +1,6 @@
void extra();
-int main(int argc, char** argv) {
+int main(void) {
extra();
return 0;
}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/linux/gyptest-implicit-rpath.py
@@ -0,0 +1,48 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 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.
+
+"""
+Verifies that the implicit rpath is added only when needed.
+"""
+
+import TestGyp
+
+import re
+import subprocess
+import sys
+
+if sys.platform.startswith('linux'):
+ test = TestGyp.TestGyp(formats=['ninja', 'make'])
+
+ CHDIR = 'implicit-rpath'
+ test.run_gyp('test.gyp', chdir=CHDIR)
+ test.build('test.gyp', test.ALL, chdir=CHDIR)
+
+ def GetRpaths(p):
+ p = test.built_file_path(p, chdir=CHDIR)
+ r = re.compile(r'Library rpath: \[([^\]]+)\]')
+ proc = subprocess.Popen(['readelf', '-d', p], stdout=subprocess.PIPE)
+ o = proc.communicate()[0]
+ assert not proc.returncode
+ return r.findall(o)
+
+ if test.format == 'ninja':
+ expect = '$ORIGIN/lib/'
+ elif test.format == 'make':
+ expect = '$ORIGIN/lib.target/'
+ else:
+ test.fail_test()
+
+ if GetRpaths('shared_executable') != [expect]:
+ test.fail_test()
+
+ if GetRpaths('shared_executable_no_so_suffix') != [expect]:
+ test.fail_test()
+
+ if GetRpaths('static_executable'):
+ test.fail_test()
+
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/linux/gyptest-ldflags-duplicates.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2015 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.
+
+"""
+Verifies duplicate ldflags are not removed.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform.startswith('linux'):
+ test = TestGyp.TestGyp()
+
+ CHDIR = 'ldflags-duplicates'
+ test.run_gyp('test.gyp', chdir=CHDIR)
+ test.build('test.gyp', chdir=CHDIR)
+
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/linux/gyptest-target-rpath.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 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.
+
+"""
+Check target_rpath generator flag for ninja.
+"""
+
+import TestGyp
+
+import re
+import subprocess
+import sys
+
+if sys.platform.startswith('linux'):
+ test = TestGyp.TestGyp(formats=['ninja'])
+
+ CHDIR = 'target-rpath'
+ test.run_gyp('test.gyp', '-G', 'target_rpath=/usr/lib/gyptest/', chdir=CHDIR)
+ test.build('test.gyp', test.ALL, chdir=CHDIR)
+
+ def GetRpaths(p):
+ p = test.built_file_path(p, chdir=CHDIR)
+ r = re.compile(r'Library rpath: \[([^\]]+)\]')
+ proc = subprocess.Popen(['readelf', '-d', p], stdout=subprocess.PIPE)
+ o = proc.communicate()[0]
+ assert not proc.returncode
+ return r.findall(o)
+
+ expect = '/usr/lib/gyptest/'
+
+ if GetRpaths('shared_executable') != [expect]:
+ test.fail_test()
+
+ if GetRpaths('shared_executable_no_so_suffix') != [expect]:
+ test.fail_test()
+
+ if GetRpaths('static_executable'):
+ test.fail_test()
+
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/linux/implicit-rpath/file.c
@@ -0,0 +1,1 @@
+void f() {}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/linux/implicit-rpath/main.c
@@ -0,0 +1,1 @@
+int main() {}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/linux/implicit-rpath/test.gyp
@@ -0,0 +1,47 @@
+# Copyright (c) 2013 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': 'shared',
+ 'type': 'shared_library',
+ 'sources': [ 'file.c' ],
+ },
+ {
+ 'target_name': 'shared_no_so_suffix',
+ 'product_extension': 'so.0.1',
+ 'type': 'shared_library',
+ 'sources': [ 'file.c' ],
+ },
+ {
+ 'target_name': 'static',
+ 'type': 'static_library',
+ 'sources': [ 'file.c' ],
+ },
+ {
+ 'target_name': 'shared_executable',
+ 'type': 'executable',
+ 'sources': [ 'main.c' ],
+ 'dependencies': [
+ 'shared',
+ ]
+ },
+ {
+ 'target_name': 'shared_executable_no_so_suffix',
+ 'type': 'executable',
+ 'sources': [ 'main.c' ],
+ 'dependencies': [
+ 'shared_no_so_suffix',
+ ]
+ },
+ {
+ 'target_name': 'static_executable',
+ 'type': 'executable',
+ 'sources': [ 'main.c' ],
+ 'dependencies': [
+ 'static',
+ ]
+ },
+ ],
+}
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/linux/ldflags-duplicates/check-ldflags.py
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2015 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.
+
+"""
+Verifies duplicate ldflags are not removed.
+"""
+
+import sys
+
+def CheckContainsFlags(args, substring):
+ if args.find(substring) is -1:
+ print 'ERROR: Linker arguments "%s" are missing in "%s"' % (substring, args)
+ return False;
+ return True;
+
+if __name__ == '__main__':
+ args = " ".join(sys.argv)
+ print "args = " +args
+ if not CheckContainsFlags(args, 'lib1.a -Wl,--no-whole-archive') \
+ or not CheckContainsFlags(args, 'lib2.a -Wl,--no-whole-archive'):
+ sys.exit(1);
+ sys.exit(0)
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/linux/ldflags-duplicates/lib1.c
@@ -0,0 +1,6 @@
+// Copyright (c) 2015 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.
+
+void foo() {
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/linux/ldflags-duplicates/lib2.c
@@ -0,0 +1,6 @@
+// Copyright (c) 2015 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.
+
+void bar() {
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/linux/ldflags-duplicates/main.c
@@ -0,0 +1,7 @@
+// Copyright (c) 2015 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 main() {
+ return 0;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/linux/ldflags-duplicates/test.gyp
@@ -0,0 +1,45 @@
+# Copyright (c) 2015 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.
+
+{
+ 'make_global_settings': [
+ ['LINK_wrapper', './check-ldflags.py'],
+ ],
+ 'targets': [
+ {
+ 'target_name': 'test',
+ 'type': 'executable',
+ 'ldflags': [
+ '-Wl,--whole-archive <(PRODUCT_DIR)/lib1.a',
+ '-Wl,--no-whole-archive',
+
+ '-Wl,--whole-archive <(PRODUCT_DIR)/lib2.a',
+ '-Wl,--no-whole-archive',
+ ],
+ 'dependencies': [
+ 'lib1',
+ 'lib2',
+ ],
+ 'sources': [
+ 'main.c',
+ ],
+ },
+ {
+ 'target_name': 'lib1',
+ 'type': 'static_library',
+ 'standalone_static_library': 1,
+ 'sources': [
+ 'lib1.c',
+ ],
+ },
+ {
+ 'target_name': 'lib2',
+ 'type': 'static_library',
+ 'standalone_static_library': 1,
+ 'sources': [
+ 'lib2.c',
+ ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/linux/target-rpath/file.c
@@ -0,0 +1,1 @@
+void f() {}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/linux/target-rpath/main.c
@@ -0,0 +1,1 @@
+int main() {}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/linux/target-rpath/test.gyp
@@ -0,0 +1,47 @@
+# Copyright (c) 2013 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': 'shared',
+ 'type': 'shared_library',
+ 'sources': [ 'file.c' ],
+ },
+ {
+ 'target_name': 'shared_no_so_suffix',
+ 'product_extension': 'so.0.1',
+ 'type': 'shared_library',
+ 'sources': [ 'file.c' ],
+ },
+ {
+ 'target_name': 'static',
+ 'type': 'static_library',
+ 'sources': [ 'file.c' ],
+ },
+ {
+ 'target_name': 'shared_executable',
+ 'type': 'executable',
+ 'sources': [ 'main.c' ],
+ 'dependencies': [
+ 'shared',
+ ]
+ },
+ {
+ 'target_name': 'shared_executable_no_so_suffix',
+ 'type': 'executable',
+ 'sources': [ 'main.c' ],
+ 'dependencies': [
+ 'shared_no_so_suffix',
+ ]
+ },
+ {
+ 'target_name': 'static_executable',
+ 'type': 'executable',
+ 'sources': [ 'main.c' ],
+ 'dependencies': [
+ 'static',
+ ]
+ },
+ ],
+}
copy from media/webrtc/trunk/tools/gyp/test/mac/app-bundle/TestApp/English.lproj/InfoPlist.strings
copy to media/webrtc/trunk/tools/gyp/test/mac/app-bundle/TestApp/English.lproj/InfoPlist-error.strings
--- a/media/webrtc/trunk/tools/gyp/test/mac/app-bundle/TestApp/English.lproj/InfoPlist.strings
+++ b/media/webrtc/trunk/tools/gyp/test/mac/app-bundle/TestApp/English.lproj/InfoPlist.strings
@@ -1,3 +1,3 @@
/* Localized versions of Info.plist keys */
-NSHumanReadableCopyright = "Copyright ©2011 Google Inc."
+NSHumanReadableCopyright = "Copyright ©2011 Google Inc.";
new file mode 100644
index 0000000000000000000000000000000000000000..580783735f59601d6ac9d39cc2c3b21c66162e4a
GIT binary patch
literal 208
zc${sH%MQU%6h+s#U(s~ff!9=w43LNcUr^N|^pO?`f8-~z)KpIH-S_T&&dPbc=@S#O
zq#`BZ%#jBfJH4CQ(CSo_YN+Pk3xB!q9(C8>a?w56eeb$rnSr%p!<;LH+>*6<A~#{{
nRK`?7?L;GC&!J;XJkj6e$%p|%D`aL~nS3d~ZBloM7!!N|?BOJz
new file mode 100644
index 0000000000000000000000000000000000000000..eeb383784c8b7de5e1c5e76c7d59d72f3befd78d
GIT binary patch
literal 208
zc${sH%?`m(6okLEr)awDLa`Mq3nXH}6I8Vb{Yi_2H}aDB)K*UJopWdA%suZ{Ohmwv
zij;&iM;>JC<Zfa^D^pR5ftY(QeC76i>dxPCkv-|Ycdm$-p0#4boGXR7C2RG>+=Q)D
n8B-H#CmIv>9J-8&C;Y2C88KjJ1<cedm2b*#o77!G#{T&M50WIG
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/app-bundle/TestApp/Images.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,58 @@
+{
+ "images" : [
+ {
+ "idiom" : "mac",
+ "size" : "16x16",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "16x16",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "32x32",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "32x32",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "128x128",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "128x128",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "256x256",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "256x256",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "512x512",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "512x512",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/app-bundle/TestApp/Images.xcassets/image.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "super_sylvain.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "super_sylvain@2x.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "super_sylvain@3x.png"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
new file mode 100644
index 0000000000000000000000000000000000000000..0ba769182f117a972f76280a19bd69d6e81b68f7
GIT binary patch
literal 3263
zc$@*h3_$aVP)<h;3K|Lk000e1NJLTq000yK000yS1^@s6jfou%000U>X+uL$Nkc;*
zP;zf(X>4Tx07wm;mUmQB*%pV-y*Itk5+Wca^cs2zAksTX6$DX<Nq|rShJ+?|L<L3^
z5h+$=RKNj8hazJ|6bplbV%G`s5KzX!QA9=M-HdAq@2xfS-kSZ#S>M^`x7XQc?|s+0
z08spb1j2M!0f022SQPH-!CVp(%f$Br7!UytSOLJ{W@ZFO_(THK{JlMynW#v{v-a*T
zfMmPdEWc1DbJqWVks>!kBnAKqMb$PuekK>?0+ds;#ThdH1j_W4DKdsJG8Ul;qO2n0
z#IJ1jr{*iW$(WZW<e?f_&KbNko{YOt-kK%hql^ThT$m-`XQO-vWxZ5MngHeZDAUvU
zoJ;^P6q#Sl=O&?Si84hL8SaVl0ssh<#5ufj4vYCYXr2Igrf1}e1c^yvrV-beY31n1
zX8Q57Q~6>sE0n`c;fQ!l&-AnmjxZO1uWyz`0VP>&nP`#itsL#`S=Q!g`M=rU9)45(
zJ;-|dRq-b5&z?byo>|{)?5r=n76A4nTALlSzLiw~v~31J<>9PP?;rs31pu_(obw)r
zY+jPY;tVGXi|p)da{-@gE-UCa`=5eu%D;v=_nFJ?`&K)q7e9d`Nfk3?MdhZarb|T3
z%nS~f&t(1g5dY)AIcd$w!z`Siz!&j_=v7hZlnI21XuE|xfmo0(WD10T)!}~_HYW!e
zew}L+XmwuzeT6wtxJd`dZ#@7*BLgIEKY9Xv>st^p3dp{^Xswa2bB{85{^$B13tWnB
z;Y>jyQ|9&zk7RNsqAVGs--K+z0uqo1bf5|}fi5rtEMN^BfHQCd-XH*kfJhJnmIE$G
z0%<@5vOzxB0181d*a3EfYH$G5fqKvcPJ%XY23!PJzzuK<41h;K3WmW;Fah3yX$XSw
z5EY_9s*o0>51B&N5F1(uc|$=^I1~fLLy3?Ol0f;;Ca4%HgQ}rJP(Ab`bQ-z{U4#0d
z2hboi2K@njgb|nm(_szR0JebHusa+GN5aeCM0gdP2N%HG;Yzp`J`T6S7vUT504#-H
z!jlL<$Or?`Mpy_N@kBz9SR?@vA#0H$qyni$nvf2p8@Y{0k#Xb$28W?xm>3qu8RLgp
zjNxKdVb)?wFx8l2m{v>|<~C*!GlBVnrDD~wrdTJeKXwT=5u1%I#8zOBU|X=4u>;s)
z>^mF|$G{ol9B_WP7+f-LHLe7=57&&lfa}8z;U@8Tyei%l?}87(bMRt(A-)QK9Dg3)
zj~~XrCy)tR1Z#p1A(kK{Y$Q|=8VKhI{e%(1G*N-5Pjn)N5P8I0VkxnX*g?EW941ba
z6iJ387g8iCnY4jaNopcpCOsy-A(P2EWJhusSwLP-t|XrzUnLKcKTwn?CKOLf97RIe
zPB}`sKzTrUL#0v;sBY9)s+hW+T2H-1eM)^VN0T#`^Oxhvt&^*fYnAJldnHel*Ozyf
zUoM{~Um<@={-*r60#U(0!Bc^wuvVc);k3d%g-J!4qLpHZVwz%!VuRu}#Ze`^l7W)9
z5>Kf>>9Eozr6C$Z)1`URxU@~QI@)F0FdauXr2Es8>BaOP=)Lp_WhG@><tXJG<r?L)
z%2EcxFktvIQW>R;lZ?BJkMlI<xzFRz+cvLhUjMu)mH8@eDtwh9m1dOzm5-`SRd3Z4
z)t#zss!!A~Y9?x7YT0W0)h?@z&!^9Kp3j|MH2>uMhw8ApiF&yDYW2hFJ?fJhni{?u
z85&g@mo&yT8JcdI$(rSw=QPK(Xj%)k1X|@<=e1rim6`6$RAwc!i#egKuI;BS(LSWz
zt39n_sIypSqfWEV6J3%nTQ@<sT(?tqLQhLCSTA3%QSYHXQJ<}!q`ybMTYt*H&>-4i
zi$R;gsG*9XzhRzXqv2yCs*$VFDx+GXJH|L;wsDH_KI2;^u!)^Xl1YupO;gy^-c(?^
z&$Q1BYvyPsG^;hc$D**@Sy`+`)}T4VJji^bd7Jqw3q6Zii=7tT7GEswEK@D(EFW1Z
zSp`^awCb?>!`j4}Yh7b~$A)U-W3$et-R8BesV(1jzwLcHnq9En7Q0Tn&-M=XBKs!$
zF$X<|c!#|X_t<oHD7%Dx)e-CH;keH6jN=C<dnd8eNvGePS<WfW4bGzr3>WYh)GZit
z(Q)Cp9CDE^WG;+fcyOWARoj*0TI>4EP1lX*cEoMO-Pk?Z{kZ!p4@(b`M~lalr<3Oz
z&kJ6Nm#<fmSFg8{_hRpA@25UGK8Ze!J`=unzN>vN_+kA5{dW4@^Vjg_`q%qU1ULk&
z3Fr!>1V#i_2R;ij2@(Z$1jE4r!MlPVFVbHmT+|i<Li|H^g**v03|$raa~LixG^{4<
zdAL=0et35TEn-DPL&UpCkI2%<M~jUXOBQ!V$w$RS)kjT5dqtN;OP5$IS+nFuj9QE!
zracxP8x?ybc5<or(%nmk<Lu%J<L)jqT$Z!!+H$q!smsr<kYB-BaVj1gA06Ki|A`aA
zspU+r^k2Dm<pkH0yNCOd=f*4NjqzRhW&Du@mxQu}(L|TTU5R5!u1OV1;{s1XwcvHK
zU-E(Esg#hEqbW0~(W%X8gtYjy(?TU-im)qPGd(B0FT*sWFhjb^Y1Qsk6QV%TkxVFa
zS!TPKj{Z#bNQ@+#C4*TDvud*5XGdk9%2CV_=Je#6<ZjCy$@9tkel=z_cXemJcK(L^
z!8Pt{4y}dOu3X!>PIq0wy5aS{>yK?9ZAjVh%SOwMWgFjair&;wpi!{CU}&@N=Eg#~
zLQ&zpEzVmGY{hI9Z0+4<v#n~|mm*%#^<vB7isDZt+>-0xS$$Xe-OToc?Y*V;rTcf_
zb_jRe-RZjXSeas3UfIyD;9afd%<`i0x4T#DzE)vdabOQ=k7SRuGN`h>O0Q~1)u-yD
z>VX=Mn&!Rgd$;YK+Q-}1zu#?t(*cbG#Ronf6db&N$oEidtwC+YVcg-Y!_VuY>bk#Y
ze_ww@?MU&F&qswvrN_dLb=5o6*Egs)ls3YRlE$&)amR1{;Ppd$6RYV^Go!iq1UMl%
z@#4q$AMc(FJlT1QeX8jv{h#)>&{~RGq1N2iiMFIRX?sk2-|2wUogK~{EkB$8eDsX=
znVPf8XG_nK&J~=SIiGia@<PUi@r#KUhdNhuKDxBz(w(lbuHMUmm#<#&xpJx7z5D!C
zm#b&4IbAz_oqfIShW(A!9=o2FU+jKq>9y}|z3FhX{g&gcj=lwb=lWgyFW&aLedUh-
zof`v-2Kw$UzI*>(+&$@i-u=-BsSjR1%z8NeX#HdC<Dw@DPb!|OKdt@M_}6Bsz4Yv$
z*I>`Hh-Z(6xI-`hmHDqv!v)W&&nrf>M(RhcN6(D;jNN*%^u_SYjF;2ng}*8Ow)d6M
ztDk;%`@Lsk$;9w$(d(H%O5UixIr`T2ZRcd@<kNR)@201U-mAVp_JRGO`(yOSk?HJD
z_)nFejX!sM3H<VSCT(Ws-}i*``!YINegFUhIY~r8R5%f(ls#w^K@`XTv%9zCJc7Z)
zBA^jDY(%uM7S2Pfq_T;ED8gAtkf22xn-qSagcO1Z!A1zEMJ&W1Hs;{O6yg^gL5pBv
zP&D2l+%0>1`!T+Ex66Gv0|`DD_RX93e)DGL?Gqr$&sO&c%f7>^5Ey0KRz*tuAm5S<
zS~I2D?1o^NVWmDnh+SKSDE*|YMS*|BYG)?!e=y#G5@MD`YM$ph$?Y>y7&Bm#Lv1s}
z^Uo3LI%i^8`a2W2c3}q!qoOao=!TeIaIx(4ncEX)8ULC)mhp*nAFLV1o@o<T&)OK)
z1Zsc+Cl16*4Ik4t8yLUs;MFhL!DLf7J)$ORfiOD(fhSRIs}grtTKHNGvGFay$3JQy
zKZ-&kto@WYyjQ@=+E~0|;^pfW?!Wa>T=y0JU6Ux>sK@8%8rxdN#Dhy|?C0lAB#iLx
zjfa_Xa-qpW_p3QFIXEGTa}C^E_3^tE2bczq9!q0sGSwvvXnG)JHcaE`iib%8&zF5P
z;^2{-jq{pEQQu+4!qW5*IA-mIgUcTzmdhUAHw`SFj9+UYvt+8zF!nf@AHu2KT-*W^
zW8EU}z1jrEUv-8~fM@Fw&gE!7D&(n)8BFy?xdB!+WuwjT;S(2+zk~>SL8LdU0d6gL
zs0`SXsW^VU{$2k+lbbDYXs3WnYTA!b(PYLz?u~rp5{)x7)Y6iuY^qCD5l}L?(-OL-
xSlph87|b%bZF8rkbRWg-d|M!n;aFxc>o1aGzi<rUj#2;s002ovPDHLkV1oMAPV4{x
new file mode 100644
index 0000000000000000000000000000000000000000..edfa6a5682f108afb4d7f23ff53e6897a24959c5
GIT binary patch
literal 3847
zc$@(T5BTtjP)<h;3K|Lk000e1NJLTq001Ze001Zm1^@s6jQ+T7000U>X+uL$Nkc;*
zP;zf(X>4Tx07wm;mUmQB*%pV-y*Itk5+Wca^cs2zAksTX6$DX<Nq|rShJ+?|L<L3^
z5h+$=RKNj8hazJ|6bplbV%G`s5KzX!QA9=M-HdAq@2xfS-kSZ#S>M^`x7XQc?|s+0
z08spb1j2M!0f022SQPH-!CVp(%f$Br7!UytSOLJ{W@ZFO_(THK{JlMynW#v{v-a*T
zfMmPdEWc1DbJqWVks>!kBnAKqMb$PuekK>?0+ds;#ThdH1j_W4DKdsJG8Ul;qO2n0
z#IJ1jr{*iW$(WZW<e?f_&KbNko{YOt-kK%hql^ThT$m-`XQO-vWxZ5MngHeZDAUvU
zoJ;^P6q#Sl=O&?Si84hL8SaVl0ssh<#5ufj4vYCYXr2Igrf1}e1c^yvrV-beY31n1
zX8Q57Q~6>sE0n`c;fQ!l&-AnmjxZO1uWyz`0VP>&nP`#itsL#`S=Q!g`M=rU9)45(
zJ;-|dRq-b5&z?byo>|{)?5r=n76A4nTALlSzLiw~v~31J<>9PP?;rs31pu_(obw)r
zY+jPY;tVGXi|p)da{-@gE-UCa`=5eu%D;v=_nFJ?`&K)q7e9d`Nfk3?MdhZarb|T3
z%nS~f&t(1g5dY)AIcd$w!z`Siz!&j_=v7hZlnI21XuE|xfmo0(WD10T)!}~_HYW!e
zew}L+XmwuzeT6wtxJd`dZ#@7*BLgIEKY9Xv>st^p3dp{^Xswa2bB{85{^$B13tWnB
z;Y>jyQ|9&zk7RNsqAVGs--K+z0uqo1bf5|}fi5rtEMN^BfHQCd-XH*kfJhJnmIE$G
z0%<@5vOzxB0181d*a3EfYH$G5fqKvcPJ%XY23!PJzzuK<41h;K3WmW;Fah3yX$XSw
z5EY_9s*o0>51B&N5F1(uc|$=^I1~fLLy3?Ol0f;;Ca4%HgQ}rJP(Ab`bQ-z{U4#0d
z2hboi2K@njgb|nm(_szR0JebHusa+GN5aeCM0gdP2N%HG;Yzp`J`T6S7vUT504#-H
z!jlL<$Or?`Mpy_N@kBz9SR?@vA#0H$qyni$nvf2p8@Y{0k#Xb$28W?xm>3qu8RLgp
zjNxKdVb)?wFx8l2m{v>|<~C*!GlBVnrDD~wrdTJeKXwT=5u1%I#8zOBU|X=4u>;s)
z>^mF|$G{ol9B_WP7+f-LHLe7=57&&lfa}8z;U@8Tyei%l?}87(bMRt(A-)QK9Dg3)
zj~~XrCy)tR1Z#p1A(kK{Y$Q|=8VKhI{e%(1G*N-5Pjn)N5P8I0VkxnX*g?EW941ba
z6iJ387g8iCnY4jaNopcpCOsy-A(P2EWJhusSwLP-t|XrzUnLKcKTwn?CKOLf97RIe
zPB}`sKzTrUL#0v;sBY9)s+hW+T2H-1eM)^VN0T#`^Oxhvt&^*fYnAJldnHel*Ozyf
zUoM{~Um<@={-*r60#U(0!Bc^wuvVc);k3d%g-J!4qLpHZVwz%!VuRu}#Ze`^l7W)9
z5>Kf>>9Eozr6C$Z)1`URxU@~QI@)F0FdauXr2Es8>BaOP=)Lp_WhG@><tXJG<r?L)
z%2EcxFktvIQW>R;lZ?BJkMlI<xzFRz+cvLhUjMu)mH8@eDtwh9m1dOzm5-`SRd3Z4
z)t#zss!!A~Y9?x7YT0W0)h?@z&!^9Kp3j|MH2>uMhw8ApiF&yDYW2hFJ?fJhni{?u
z85&g@mo&yT8JcdI$(rSw=QPK(Xj%)k1X|@<=e1rim6`6$RAwc!i#egKuI;BS(LSWz
zt39n_sIypSqfWEV6J3%nTQ@<sT(?tqLQhLCSTA3%QSYHXQJ<}!q`ybMTYt*H&>-4i
zi$R;gsG*9XzhRzXqv2yCs*$VFDx+GXJH|L;wsDH_KI2;^u!)^Xl1YupO;gy^-c(?^
z&$Q1BYvyPsG^;hc$D**@Sy`+`)}T4VJji^bd7Jqw3q6Zii=7tT7GEswEK@D(EFW1Z
zSp`^awCb?>!`j4}Yh7b~$A)U-W3$et-R8BesV(1jzwLcHnq9En7Q0Tn&-M=XBKs!$
zF$X<|c!#|X_t<oHD7%Dx)e-CH;keH6jN=C<dnd8eNvGePS<WfW4bGzr3>WYh)GZit
z(Q)Cp9CDE^WG;+fcyOWARoj*0TI>4EP1lX*cEoMO-Pk?Z{kZ!p4@(b`M~lalr<3Oz
z&kJ6Nm#<fmSFg8{_hRpA@25UGK8Ze!J`=unzN>vN_+kA5{dW4@^Vjg_`q%qU1ULk&
z3Fr!>1V#i_2R;ij2@(Z$1jE4r!MlPVFVbHmT+|i<Li|H^g**v03|$raa~LixG^{4<
zdAL=0et35TEn-DPL&UpCkI2%<M~jUXOBQ!V$w$RS)kjT5dqtN;OP5$IS+nFuj9QE!
zracxP8x?ybc5<or(%nmk<Lu%J<L)jqT$Z!!+H$q!smsr<kYB-BaVj1gA06Ki|A`aA
zspU+r^k2Dm<pkH0yNCOd=f*4NjqzRhW&Du@mxQu}(L|TTU5R5!u1OV1;{s1XwcvHK
zU-E(Esg#hEqbW0~(W%X8gtYjy(?TU-im)qPGd(B0FT*sWFhjb^Y1Qsk6QV%TkxVFa
zS!TPKj{Z#bNQ@+#C4*TDvud*5XGdk9%2CV_=Je#6<ZjCy$@9tkel=z_cXemJcK(L^
z!8Pt{4y}dOu3X!>PIq0wy5aS{>yK?9ZAjVh%SOwMWgFjair&;wpi!{CU}&@N=Eg#~
zLQ&zpEzVmGY{hI9Z0+4<v#n~|mm*%#^<vB7isDZt+>-0xS$$Xe-OToc?Y*V;rTcf_
zb_jRe-RZjXSeas3UfIyD;9afd%<`i0x4T#DzE)vdabOQ=k7SRuGN`h>O0Q~1)u-yD
z>VX=Mn&!Rgd$;YK+Q-}1zu#?t(*cbG#Ronf6db&N$oEidtwC+YVcg-Y!_VuY>bk#Y
ze_ww@?MU&F&qswvrN_dLb=5o6*Egs)ls3YRlE$&)amR1{;Ppd$6RYV^Go!iq1UMl%
z@#4q$AMc(FJlT1QeX8jv{h#)>&{~RGq1N2iiMFIRX?sk2-|2wUogK~{EkB$8eDsX=
znVPf8XG_nK&J~=SIiGia@<PUi@r#KUhdNhuKDxBz(w(lbuHMUmm#<#&xpJx7z5D!C
zm#b&4IbAz_oqfIShW(A!9=o2FU+jKq>9y}|z3FhX{g&gcj=lwb=lWgyFW&aLedUh-
zof`v-2Kw$UzI*>(+&$@i-u=-BsSjR1%z8NeX#HdC<Dw@DPb!|OKdt@M_}6Bsz4Yv$
z*I>`Hh-Z(6xI-`hmHDqv!v)W&&nrf>M(RhcN6(D;jNN*%^u_SYjF;2ng}*8Ow)d6M
ztDk;%`@Lsk$;9w$(d(H%O5UixIr`T2ZRcd@<kNR)@201U-mAVp_JRGO`(yOSk?HJD
z_)nFejX!sM3H<VSCT(Ws-}i*``!YINegFUjfk{L`R9FekS#O9`RTTf-H}Acfbw?ZA
z5_ZXDYzV~_A)_#14P}u;gP4LPA^V~qB<VvR{8EHeTNGgt3?=$yGXhJbv?UO6iG_qz
z6l=jh475A31DhMGJI?gpoA++_zIBH8?t8N{_pLeZm$~<xbI<wRbKW`k-m?V4-<J1g
z`iP?M0ioL{MK2*FDTv(HDW$YT2qr<v8S0ovN8jxl_ZlFzN#DV7eTCM0h*0bUfl{MC
z&|eCN5_~yrO};gLu+QYSU4Sk)wfASXldTUFPy=Hua_6S2liN8+*Hf<N9ujb_*BBO#
z$sOPO=B~CatPQ*f9&X26ugoVzo4&b5;9S?i#isCVT}ZC2Jcdo3FC~kIk$FtPs%7&<
z!KhG7-Exq3^Dw$@j!j)uo$FL^U}qf9r(;OOf<Q{QZH)eE;PcB)kl6x-V<TIK=4cDD
z0g=oa9fz_yTB+i*1q1t!SttgyG$%wW$UPdqXb~KTkXjkXSG%<4XhI|+03;ZCC5}Wu
z8O2|PDz4^j%-R7alIb|!&IIYrC~7kSk-s#fVWSY&>TL_}<P2P>3lqFC*nw=uzyHmf
zH4Npgx>PFzzlIi8tXM8Cp*Z!O7aUhYkvm?&rHWsn+7-h(KdI?VwAOS1s)C4V<Cnh$
znmeWV{-O|Ty?!?dTM$Z<4sk$>9>YKn@W)hugA2c#_`1qK)izaeFcB16kRlDR%);mY
zBY5$(C9qCZkjo1^mMz2Q{nD~C=@1t$TevAi4lxDU!A|_RCxO?6#E=Cf%10{H-D~3b
zCfm5KRaq#{Uo>!d%#Ku?y&xk2<O=vn@(C-}DX%thY&*F0n}PR7ZOn<h7U$9-uIbHR
zGx74LWt_fl*K?r8tN*glKmA+>et0v1fzCQrY7p6jJ}bI{z1wu`>{F2pxiq-4wvCTI
ztKh8U4d?y<^q}3*AII)Z8XgS+`tP3xc6|FkpCleEp~I0e1A`ym#mRi|ij_!fcvUjg
zl68<^?+ZH8Y!&x|#=LaniizO~q5io?T^XgpCD`pNI|Rwb$sf95Ie;k@FKy6#H<@Kq
z9AKz!44<>GD-(y;h~y_I`B*ADm=&-*vCeDW&s^H2_`q?l?iXn~lPfc(gPSG4&O|r6
zj1Gik1k3CXw~O(lD9PnWV1s_^ff>c&GZy-VQ{>5KJ20}^#+3;hQ!^B)9u=Ebvv-QH
zzB*IIPj>}klWF7lG+0=?X5eH&MRukC>XdjShK=h(JXzO6apJfseWJ*P_@1%cF?NC!
zf@P$RB`}~EJ5|OJ@dFOX1qq8P)XzMnV}HMf$CG|<dd=J_SU7Upz}X1kxE`|QgFADJ
zdK)t(-6;hdRw+ocx5_^(iI%gEuQ<(aG|bCI*}CG{9q%2ohdXN?0&6{V>0xo!!AQi%
z`9j7xHidUK7ZPeKk6}}I+m*Mv+6pAh_<Z~AsKR@~yzLq$(@q-4#Id<$hWCVd+qIp5
zytdsIFvG-YE<oN3<~?C{C&{%n+&rudL#;o}0R{@#!}f28{{ZGhgjYt%CaM4c002ov
JPDHLkV1hi3a|8eY
new file mode 100644
index 0000000000000000000000000000000000000000..e0652efc729dcf260f02468e2d49c635bfae9d42
GIT binary patch
literal 4394
zc$@($5!LRAP)<h;3K|Lk000e1NJLTq002Ay002A)1^@s6I{evk000U>X+uL$Nkc;*
zP;zf(X>4Tx07wm;mUmQB*%pV-y*Itk5+Wca^cs2zAksTX6$DX<Nq|rShJ+?|L<L3^
z5h+$=RKNj8hazJ|6bplbV%G`s5KzX!QA9=M-HdAq@2xfS-kSZ#S>M^`x7XQc?|s+0
z08spb1j2M!0f022SQPH-!CVp(%f$Br7!UytSOLJ{W@ZFO_(THK{JlMynW#v{v-a*T
zfMmPdEWc1DbJqWVks>!kBnAKqMb$PuekK>?0+ds;#ThdH1j_W4DKdsJG8Ul;qO2n0
z#IJ1jr{*iW$(WZW<e?f_&KbNko{YOt-kK%hql^ThT$m-`XQO-vWxZ5MngHeZDAUvU
zoJ;^P6q#Sl=O&?Si84hL8SaVl0ssh<#5ufj4vYCYXr2Igrf1}e1c^yvrV-beY31n1
zX8Q57Q~6>sE0n`c;fQ!l&-AnmjxZO1uWyz`0VP>&nP`#itsL#`S=Q!g`M=rU9)45(
zJ;-|dRq-b5&z?byo>|{)?5r=n76A4nTALlSzLiw~v~31J<>9PP?;rs31pu_(obw)r
zY+jPY;tVGXi|p)da{-@gE-UCa`=5eu%D;v=_nFJ?`&K)q7e9d`Nfk3?MdhZarb|T3
z%nS~f&t(1g5dY)AIcd$w!z`Siz!&j_=v7hZlnI21XuE|xfmo0(WD10T)!}~_HYW!e
zew}L+XmwuzeT6wtxJd`dZ#@7*BLgIEKY9Xv>st^p3dp{^Xswa2bB{85{^$B13tWnB
z;Y>jyQ|9&zk7RNsqAVGs--K+z0uqo1bf5|}fi5rtEMN^BfHQCd-XH*kfJhJnmIE$G
z0%<@5vOzxB0181d*a3EfYH$G5fqKvcPJ%XY23!PJzzuK<41h;K3WmW;Fah3yX$XSw
z5EY_9s*o0>51B&N5F1(uc|$=^I1~fLLy3?Ol0f;;Ca4%HgQ}rJP(Ab`bQ-z{U4#0d
z2hboi2K@njgb|nm(_szR0JebHusa+GN5aeCM0gdP2N%HG;Yzp`J`T6S7vUT504#-H
z!jlL<$Or?`Mpy_N@kBz9SR?@vA#0H$qyni$nvf2p8@Y{0k#Xb$28W?xm>3qu8RLgp
zjNxKdVb)?wFx8l2m{v>|<~C*!GlBVnrDD~wrdTJeKXwT=5u1%I#8zOBU|X=4u>;s)
z>^mF|$G{ol9B_WP7+f-LHLe7=57&&lfa}8z;U@8Tyei%l?}87(bMRt(A-)QK9Dg3)
zj~~XrCy)tR1Z#p1A(kK{Y$Q|=8VKhI{e%(1G*N-5Pjn)N5P8I0VkxnX*g?EW941ba
z6iJ387g8iCnY4jaNopcpCOsy-A(P2EWJhusSwLP-t|XrzUnLKcKTwn?CKOLf97RIe
zPB}`sKzTrUL#0v;sBY9)s+hW+T2H-1eM)^VN0T#`^Oxhvt&^*fYnAJldnHel*Ozyf
zUoM{~Um<@={-*r60#U(0!Bc^wuvVc);k3d%g-J!4qLpHZVwz%!VuRu}#Ze`^l7W)9
z5>Kf>>9Eozr6C$Z)1`URxU@~QI@)F0FdauXr2Es8>BaOP=)Lp_WhG@><tXJG<r?L)
z%2EcxFktvIQW>R;lZ?BJkMlI<xzFRz+cvLhUjMu)mH8@eDtwh9m1dOzm5-`SRd3Z4
z)t#zss!!A~Y9?x7YT0W0)h?@z&!^9Kp3j|MH2>uMhw8ApiF&yDYW2hFJ?fJhni{?u
z85&g@mo&yT8JcdI$(rSw=QPK(Xj%)k1X|@<=e1rim6`6$RAwc!i#egKuI;BS(LSWz
zt39n_sIypSqfWEV6J3%nTQ@<sT(?tqLQhLCSTA3%QSYHXQJ<}!q`ybMTYt*H&>-4i
zi$R;gsG*9XzhRzXqv2yCs*$VFDx+GXJH|L;wsDH_KI2;^u!)^Xl1YupO;gy^-c(?^
z&$Q1BYvyPsG^;hc$D**@Sy`+`)}T4VJji^bd7Jqw3q6Zii=7tT7GEswEK@D(EFW1Z
zSp`^awCb?>!`j4}Yh7b~$A)U-W3$et-R8BesV(1jzwLcHnq9En7Q0Tn&-M=XBKs!$
zF$X<|c!#|X_t<oHD7%Dx)e-CH;keH6jN=C<dnd8eNvGePS<WfW4bGzr3>WYh)GZit
z(Q)Cp9CDE^WG;+fcyOWARoj*0TI>4EP1lX*cEoMO-Pk?Z{kZ!p4@(b`M~lalr<3Oz
z&kJ6Nm#<fmSFg8{_hRpA@25UGK8Ze!J`=unzN>vN_+kA5{dW4@^Vjg_`q%qU1ULk&
z3Fr!>1V#i_2R;ij2@(Z$1jE4r!MlPVFVbHmT+|i<Li|H^g**v03|$raa~LixG^{4<
zdAL=0et35TEn-DPL&UpCkI2%<M~jUXOBQ!V$w$RS)kjT5dqtN;OP5$IS+nFuj9QE!
zracxP8x?ybc5<or(%nmk<Lu%J<L)jqT$Z!!+H$q!smsr<kYB-BaVj1gA06Ki|A`aA
zspU+r^k2Dm<pkH0yNCOd=f*4NjqzRhW&Du@mxQu}(L|TTU5R5!u1OV1;{s1XwcvHK
zU-E(Esg#hEqbW0~(W%X8gtYjy(?TU-im)qPGd(B0FT*sWFhjb^Y1Qsk6QV%TkxVFa
zS!TPKj{Z#bNQ@+#C4*TDvud*5XGdk9%2CV_=Je#6<ZjCy$@9tkel=z_cXemJcK(L^
z!8Pt{4y}dOu3X!>PIq0wy5aS{>yK?9ZAjVh%SOwMWgFjair&;wpi!{CU}&@N=Eg#~
zLQ&zpEzVmGY{hI9Z0+4<v#n~|mm*%#^<vB7isDZt+>-0xS$$Xe-OToc?Y*V;rTcf_
zb_jRe-RZjXSeas3UfIyD;9afd%<`i0x4T#DzE)vdabOQ=k7SRuGN`h>O0Q~1)u-yD
z>VX=Mn&!Rgd$;YK+Q-}1zu#?t(*cbG#Ronf6db&N$oEidtwC+YVcg-Y!_VuY>bk#Y
ze_ww@?MU&F&qswvrN_dLb=5o6*Egs)ls3YRlE$&)amR1{;Ppd$6RYV^Go!iq1UMl%
z@#4q$AMc(FJlT1QeX8jv{h#)>&{~RGq1N2iiMFIRX?sk2-|2wUogK~{EkB$8eDsX=
znVPf8XG_nK&J~=SIiGia@<PUi@r#KUhdNhuKDxBz(w(lbuHMUmm#<#&xpJx7z5D!C
zm#b&4IbAz_oqfIShW(A!9=o2FU+jKq>9y}|z3FhX{g&gcj=lwb=lWgyFW&aLedUh-
zof`v-2Kw$UzI*>(+&$@i-u=-BsSjR1%z8NeX#HdC<Dw@DPb!|OKdt@M_}6Bsz4Yv$
z*I>`Hh-Z(6xI-`hmHDqv!v)W&&nrf>M(RhcN6(D;jNN*%^u_SYjF;2ng}*8Ow)d6M
ztDk;%`@Lsk$;9w$(d(H%O5UixIr`T2ZRcd@<kNR)@201U-mAVp_JRGO`(yOSk?HJD
z_)nFejX!sM3H<VSCT(Ws-}i*``!YINegFUlq)9|URA>d|TYGF%RT%%>+t<1cSaefa
zP!|v(I7yU%EM$pYCQ1;HV4|Y&k+8(5M2v)lpm7G!sEJ^7{vjBApd==n4kdshGfuNP
zLNGdXii-@$MuM8b*7bF7uiv?&-EDhM+uNSDcAli|d7t0!JLi1gcW&>IkR;sR{Pzsl
z?5ku+S`G=bG!4~~B$X#=lJ_D_(?%r;gV4|)*0cjqmG*C%uRO;CBAFE|X}(bHvb$b{
zBt1suHnTea;XD<ZwkMzjUiiMbYA_yW0%6bAODiE`uLNmIeC1+FYtTjz#zP&?Pu*|C
zEgKUJTQ9DsCHrZylVzM32gZeQGIEU0Fq>IcfojGG!C1K{;~HpdYpWwOtrKQ@*6DEd
zO@^5@n-sRZgQ37&wx{*kWD07sl4Sy5+;k<(;>`5O4(Dl#7n?RF$d-Z{4h3suW@o9{
zWGBlcW7B;K-Knr7sN${6xXR3fDqac}krP+@xVvbvVK&vBz;s8%8fqBz0wdY<XQ3_Q
zYR`vn+<1!vOKa_zbF~fSL^wW-j)rk&KtackA+!x>@x{W@jH}eJeI#ciEL`Zs#s()U
zEvQ8QMFo35@nhcwVLW3x$`N4+8`iq9f{Z|>;rLf$*mNwMX>)G7%n@<Bl(1!8Syp6O
z*9-0_#hZ2F;R)}tzOe)iS8=6bsbHSRjiw4qO;T1COSsI2rxqpOu;<T)aJVyo4>|%k
zdQ!o#nhc|adsjP>Rj^!Ux7;F0gN2JoL2=5Jiy^%BUI0hP3{8X(&@Q2AjT`sRF_*o4
zx|3!(gk8fEt+I)kkCIW35|+>7%&w|pTT49I$RHYawT@x;Z#)Gh;kKK_!4%gMxop!+
zY%HU7t|x%b2tUs6zSaQFah7-0wc=ok>#0n}b#8Muzn|gFp0U1)L#NGMf^stC(~VWL
zh>Igkx`n3@N~5l1a-=_}C79%Wq$=fMOw}&2ob->Ma?PIM&b^8DcAt{iCN8J9%ZGb@
zqD<;58kn%WnlOJ`+zfkF4EUljV<HuEO0XkMCt`#hCW3~KK(Y*!IKuQKygSK~obM?`
z>slx3%VK1a_k=*gK-<?rBr}&4HBK}?U5@wfbD~kO2bHemgc8QEf}K4a+hRa8W0n(}
zpD0J`x)L<iiiKbp#x$Cf)6yerO7Sqqb23E{45Ryp0N(0UF=SdnTxL!PGkEoNE<ERP
za7~pd1vQN0<fLrvP=#sb_;GT!o;te%xbtlvx`)znIxfSq$yiY5#%IsC@jz8PR59tC
z&9D*PlqwsZy~~AqOD-a5{ewPiIblIy#z8spybz9#P44HD9w(O0x0^aB(RzkR_kJ(7
z^qRYzhH7a?bGD>S5qQIB`NEG?FL}|@8A@>$9`9lC$`Ukk4ke~zq{z%K;V2jlZS)Xe
z%`2m5=~8r;G+LApv7u=h=h&H0H+4pV2u}cO>+oYaDYsJ`x0Kbaob5pEM3byy1t+Yd
zr{_G6?-;|MJfFpBL!BVcOw4JC0DZL4jcZI~fBc{qn@*&obi#P~O9k&NGlxXy2_Zqu
z4AT+L946qlNB&kxjklksIQ1bibw9~!h#^cz!$Hm-oH^Ut5In-76ty)pT+wOx<1h1N
zTT<h~hH7rZn1aT|c9g{AL=qZ;#)krt><oSd5e5$R@idNv74)}DN?Tg(!1`M`=EtYv
zyO_tj88E%vL>S@zW5J|acJszkY_GS0PKL38ysxIa-8lTHi|c)z|5ZVMY^#h@JYADP
zhhgmeR>2z{UY9Z!*SqNhC_xRwJ`HxKgbH^mr547=M|rEqI!s|R%!cmm^5gR%^Sx|@
z#)wu<lhYsz{6db&0Z}%IKnNwwNbTG+hQnu5lQs%~7e9Z}kM&(*PfNlHgC6F+`k@!E
z_b6G|R5}{c|HBWq^NbWvM5*(0dpsnCw298aOKzZ79XJX&2BNCrR9_J99t?qWU`~SM
z*>-6pAMbh8UQhn;OdD#hkTKOY!No_<od^F>(c7=$$e@_5FwuK#jJ<+LFSXFi)xeFh
zMdDMv14N2Gg$!g5hGh08c_BgMb!_4)>#xn{b=1NQ#<<GtjsQU@>{`o@3{=Kd)-OcR
z9fACeS-??<Bjc*uVRj)xzavmUJh>d2abq0W7&>A7_6J>vAO$AYt;r>ebo*wUh+E`_
zOVrcS?*wS!4U>vABTJkj_Z^sw5{@eWt7|+=0!$k0LIhoQ+D*w~)ZXl()^5hZIJ1l!
k3kfqko<06O8L#5~3mrKpj{Is>w*UYD07*qoM6N<$f?pec9{>OV
--- a/media/webrtc/trunk/tools/gyp/test/mac/app-bundle/TestApp/TestApp-Info.plist
+++ b/media/webrtc/trunk/tools/gyp/test/mac/app-bundle/TestApp/TestApp-Info.plist
@@ -1,20 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
+ <key>BuildMachineOSBuild</key>
+ <string>Doesn't matter, will be overwritten</string>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
- <string>com.google.${PRODUCT_NAME}</string>
+ <string>com.google.${PRODUCT_NAME:rfc1034identifier}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/app-bundle/test-assets-catalog.gyp
@@ -0,0 +1,43 @@
+# 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.
+{
+ 'targets': [
+ {
+ 'target_name': 'dep_framework',
+ 'product_name': 'Dependency Framework',
+ 'type': 'shared_library',
+ 'mac_bundle': 1,
+ 'sources': [ 'empty.c', ],
+ },
+ {
+ 'target_name': 'test_app',
+ 'product_name': 'Test App Assets Catalog Gyp',
+ 'type': 'executable',
+ 'mac_bundle': 1,
+ 'dependencies': [ 'dep_framework', ],
+ 'sources': [
+ 'TestApp/main.m',
+ 'TestApp/TestApp_Prefix.pch',
+ 'TestApp/TestAppAppDelegate.h',
+ 'TestApp/TestAppAppDelegate.m',
+ ],
+ 'mac_bundle_resources': [
+ 'TestApp/English.lproj/InfoPlist.strings', # UTF-8
+ 'TestApp/English.lproj/utf-16be.strings',
+ 'TestApp/English.lproj/utf-16le.strings',
+ 'TestApp/English.lproj/MainMenu.xib',
+ 'TestApp/Images.xcassets',
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '$(SDKROOT)/System/Library/Frameworks/Cocoa.framework',
+ ],
+ },
+ 'xcode_settings': {
+ 'INFOPLIST_FILE': 'TestApp/TestApp-Info.plist',
+ 'MACOSX_DEPLOYMENT_TARGET': '10.9',
+ },
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/app-bundle/test-error.gyp
@@ -0,0 +1,31 @@
+# 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.
+{
+ 'targets': [
+ {
+ 'target_name': 'test_app',
+ 'product_name': 'Test App Gyp',
+ 'type': 'executable',
+ 'mac_bundle': 1,
+ 'sources': [
+ 'TestApp/main.m',
+ 'TestApp/TestApp_Prefix.pch',
+ 'TestApp/TestAppAppDelegate.h',
+ 'TestApp/TestAppAppDelegate.m',
+ ],
+ 'mac_bundle_resources': [
+ 'TestApp/English.lproj/InfoPlist-error.strings',
+ 'TestApp/English.lproj/MainMenu.xib',
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '$(SDKROOT)/System/Library/Frameworks/Cocoa.framework',
+ ],
+ },
+ 'xcode_settings': {
+ 'INFOPLIST_FILE': 'TestApp/TestApp-Info.plist',
+ },
+ },
+ ],
+}
--- a/media/webrtc/trunk/tools/gyp/test/mac/app-bundle/test.gyp
+++ b/media/webrtc/trunk/tools/gyp/test/mac/app-bundle/test.gyp
@@ -18,17 +18,19 @@
'dependencies': [ 'dep_framework', ],
'sources': [
'TestApp/main.m',
'TestApp/TestApp_Prefix.pch',
'TestApp/TestAppAppDelegate.h',
'TestApp/TestAppAppDelegate.m',
],
'mac_bundle_resources': [
- 'TestApp/English.lproj/InfoPlist.strings',
+ 'TestApp/English.lproj/InfoPlist.strings', # UTF-8
+ 'TestApp/English.lproj/utf-16be.strings',
+ 'TestApp/English.lproj/utf-16le.strings',
'TestApp/English.lproj/MainMenu.xib',
],
'link_settings': {
'libraries': [
'$(SDKROOT)/System/Library/Frameworks/Cocoa.framework',
],
},
'xcode_settings': {
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/archs/empty_main.cc
@@ -0,0 +1,1 @@
+int main() {}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/archs/file.mm
@@ -0,0 +1,1 @@
+MyInt f() { return 0; }
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/archs/file_a.cc
@@ -0,0 +1,8 @@
+// Copyright (c) 2014 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 "file_a.h"
+
+void DependentFunctionA() {
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/archs/file_a.h
@@ -0,0 +1,10 @@
+// Copyright (c) 2014 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.
+
+#ifndef _INCLUDED_TEST_MAC_DEPENDENCIES_FILE_A_H_
+#define _INCLUDED_TEST_MAC_DEPENDENCIES_FILE_A_H_
+
+void DependentFunctionA();
+
+#endif // _INCLUDED_TEST_MAC_DEPENDENCIES_FILE_A_H_
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/archs/file_b.cc
@@ -0,0 +1,8 @@
+// Copyright (c) 2014 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 "file_b.h"
+
+void DependentFunctionB() {
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/archs/file_b.h
@@ -0,0 +1,10 @@
+// Copyright (c) 2014 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.
+
+#ifndef _INCLUDED_TEST_MAC_DEPENDENCIES_FILE_B_H_
+#define _INCLUDED_TEST_MAC_DEPENDENCIES_FILE_B_H_
+
+void DependentFunctionB();
+
+#endif // _INCLUDED_TEST_MAC_DEPENDENCIES_FILE_B_H_
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/archs/file_c.cc
@@ -0,0 +1,11 @@
+// Copyright (c) 2014 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 "file_a.h"
+#include "file_b.h"
+
+void PublicFunctionC() {
+ DependentFunctionA();
+ DependentFunctionB();
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/archs/file_d.cc
@@ -0,0 +1,11 @@
+// Copyright (c) 2014 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 "file_a.h"
+#include "file_b.h"
+
+void PublicFunctionD() {
+ DependentFunctionA();
+ DependentFunctionB();
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/archs/header.h
@@ -0,0 +1,1 @@
+typedef int MyInt;
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/archs/test-archs-multiarch.gyp
@@ -0,0 +1,92 @@
+# Copyright (c) 2012 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': 'static_32_64',
+ 'type': 'static_library',
+ 'sources': [ 'my_file.cc' ],
+ 'xcode_settings': {
+ 'ARCHS': [ 'i386', 'x86_64' ],
+ },
+ },
+ {
+ 'target_name': 'shared_32_64',
+ 'type': 'shared_library',
+ 'sources': [ 'my_file.cc' ],
+ 'xcode_settings': {
+ 'ARCHS': [ 'i386', 'x86_64' ],
+ },
+ },
+ {
+ 'target_name': 'shared_32_64_bundle',
+ 'product_name': 'My Framework',
+ 'type': 'shared_library',
+ 'mac_bundle': 1,
+ 'sources': [ 'my_file.cc' ],
+ 'xcode_settings': {
+ 'ARCHS': [ 'i386', 'x86_64' ],
+ },
+ },
+ {
+ 'target_name': 'module_32_64',
+ 'type': 'loadable_module',
+ 'sources': [ 'my_file.cc' ],
+ 'xcode_settings': {
+ 'ARCHS': [ 'i386', 'x86_64' ],
+ },
+ },
+ {
+ 'target_name': 'module_32_64_bundle',
+ 'product_name': 'My Bundle',
+ 'type': 'loadable_module',
+ 'mac_bundle': 1,
+ 'sources': [ 'my_file.cc' ],
+ 'xcode_settings': {
+ 'ARCHS': [ 'i386', 'x86_64' ],
+ },
+ },
+ {
+ 'target_name': 'exe_32_64',
+ 'type': 'executable',
+ 'sources': [ 'empty_main.cc' ],
+ 'xcode_settings': {
+ 'ARCHS': [ 'i386', 'x86_64' ],
+ },
+ },
+ {
+ 'target_name': 'exe_32_64_bundle',
+ 'product_name': 'Test App',
+ 'type': 'executable',
+ 'mac_bundle': 1,
+ 'sources': [ 'empty_main.cc' ],
+ 'xcode_settings': {
+ 'ARCHS': [ 'i386', 'x86_64' ],
+ },
+ },
+ # This only needs to compile.
+ {
+ 'target_name': 'precompiled_prefix_header_mm_32_64',
+ 'type': 'shared_library',
+ 'sources': [ 'file.mm', ],
+ 'xcode_settings': {
+ 'GCC_PREFIX_HEADER': 'header.h',
+ 'GCC_PRECOMPILE_PREFIX_HEADER': 'YES',
+ },
+ },
+ # This does not compile but should not cause generation errors.
+ {
+ 'target_name': 'exe_32_64_no_sources',
+ 'type': 'executable',
+ 'dependencies': [
+ 'static_32_64',
+ ],
+ 'sources': [],
+ 'xcode_settings': {
+ 'ARCHS': ['i386', 'x86_64'],
+ },
+ },
+ ]
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/archs/test-dependencies.gyp
@@ -0,0 +1,92 @@
+# Copyright (c) 2014 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.
+
+{
+ 'target_defaults': {
+ 'xcode_settings': {
+ 'ARCHS': ['i386', 'x86_64'],
+ },
+ },
+ 'targets': [
+ {
+ 'target_name': 'target_a',
+ 'type': 'static_library',
+ 'sources': [
+ 'file_a.cc',
+ 'file_a.h',
+ ],
+ },
+ {
+ 'target_name': 'target_b',
+ 'type': 'static_library',
+ 'sources': [
+ 'file_b.cc',
+ 'file_b.h',
+ ],
+ },
+ {
+ 'target_name': 'target_c_standalone_helper',
+ 'type': 'loadable_module',
+ 'hard_dependency': 1,
+ 'dependencies': [
+ 'target_a',
+ 'target_b',
+ ],
+ 'sources': [
+ 'file_c.cc',
+ ],
+ },
+ {
+ 'target_name': 'target_c_standalone',
+ 'type': 'none',
+ 'dependencies': [
+ 'target_c_standalone_helper',
+ ],
+ 'actions': [
+ {
+ 'action_name': 'Package C',
+ 'inputs': [],
+ 'outputs': [
+ '<(PRODUCT_DIR)/libc_standalone.a',
+ ],
+ 'action': [
+ 'touch',
+ '<@(_outputs)',
+ ],
+ },
+ ],
+ },
+ {
+ 'target_name': 'target_d_standalone_helper',
+ 'type': 'shared_library',
+ 'dependencies': [
+ 'target_a',
+ 'target_b',
+ ],
+ 'sources': [
+ 'file_d.cc',
+ ],
+ },
+ {
+ 'target_name': 'target_d_standalone',
+ 'type': 'none',
+ 'dependencies': [
+ 'target_d_standalone_helper',
+ ],
+ 'actions': [
+ {
+ 'action_name': 'Package D',
+ 'inputs': [],
+ 'outputs': [
+ '<(PRODUCT_DIR)/libd_standalone.a',
+ ],
+ 'action': [
+ 'touch',
+ '<@(_outputs)',
+ ],
+ },
+ ],
+ }
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/archs/test-valid-archs.gyp
@@ -0,0 +1,28 @@
+# Copyright (c) 2014 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': 'lib',
+ 'product_name': 'Test',
+ 'type': 'static_library',
+ 'sources': [ 'my_file.cc' ],
+ 'xcode_settings': {
+ 'ARCHS': ['i386', 'x86_64', 'unknown-arch'],
+ 'VALID_ARCHS': ['x86_64'],
+ },
+ },
+ {
+ 'target_name': 'exe',
+ 'product_name': 'Test',
+ 'type': 'executable',
+ 'dependencies': [ 'lib' ],
+ 'sources': [ 'my_main_file.cc' ],
+ 'xcode_settings': {
+ 'ARCHS': ['i386', 'x86_64', 'unknown-arch'],
+ 'VALID_ARCHS': ['x86_64'],
+ },
+ }]
+}
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/bundle-resources/change.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+tr a-z A-Z < "${1}" > "${2}"
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/bundle-resources/executable-file.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+echo echo echo echo cho ho o o
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/bundle-resources/secret.txt
@@ -0,0 +1,1 @@
+abc
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/bundle-resources/test.gyp
@@ -0,0 +1,59 @@
+# Copyright (c) 2013 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': 'resource',
+ 'type': 'executable',
+ 'mac_bundle': 1,
+ 'mac_bundle_resources': [
+ 'secret.txt',
+ 'executable-file.sh',
+ ],
+ },
+ # A rule with process_outputs_as_mac_bundle_resources should copy files
+ # into the Resources folder.
+ {
+ 'target_name': 'source_rule',
+ 'type': 'executable',
+ 'mac_bundle': 1,
+ 'sources': [
+ 'secret.txt',
+ ],
+ 'rules': [
+ {
+ 'rule_name': 'bundlerule',
+ 'extension': 'txt',
+ 'outputs': [
+ '<(INTERMEDIATE_DIR)/<(RULE_INPUT_ROOT).txt',
+ ],
+ 'action': ['./change.sh', '<(RULE_INPUT_PATH)', '<@(_outputs)'],
+ 'message': 'Running rule on <(RULE_INPUT_PATH)',
+ 'process_outputs_as_mac_bundle_resources': 1,
+ },
+ ],
+ },
+ # So should an ordinary rule acting on mac_bundle_resources.
+ {
+ 'target_name': 'resource_rule',
+ 'type': 'executable',
+ 'mac_bundle': 1,
+ 'mac_bundle_resources': [
+ 'secret.txt',
+ ],
+ 'rules': [
+ {
+ 'rule_name': 'bundlerule',
+ 'extension': 'txt',
+ 'outputs': [
+ '<(INTERMEDIATE_DIR)/<(RULE_INPUT_ROOT).txt',
+ ],
+ 'action': ['./change.sh', '<(RULE_INPUT_PATH)', '<@(_outputs)'],
+ 'message': 'Running rule on <(RULE_INPUT_PATH)',
+ },
+ ],
+ },
+ ],
+}
+
--- a/media/webrtc/trunk/tools/gyp/test/mac/cflags/test.gyp
+++ b/media/webrtc/trunk/tools/gyp/test/mac/cflags/test.gyp
@@ -110,10 +110,23 @@
],
'OTHER_CPLUSPLUSFLAGS': [
'${inherited}',
'-DCCFLAG',
],
'GCC_C_LANGUAGE_STANDARD': 'c99',
},
},
+ {
+ 'target_name': 'ansi_standard',
+ 'type': 'shared_library',
+ 'sources': [
+ 'cfile.c',
+ ],
+ 'xcode_settings': {
+ 'OTHER_CFLAGS': [
+ '-DCFLAG',
+ ],
+ 'GCC_C_LANGUAGE_STANDARD': 'ansi',
+ },
+ },
],
}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/clang-cxx-language-standard/c++11.cc
@@ -0,0 +1,8 @@
+// Copyright (c) 2013 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.
+
+static_assert(__cplusplus == 201103L, "wrong c++ standard version");
+
+int main() { return 0; }
+
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/clang-cxx-language-standard/c++98.cc
@@ -0,0 +1,24 @@
+// Copyright (c) 2013 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.
+
+#if __cplusplus != 199711L
+#error wrong c++ standard version
+#endif
+
+enum cxx11_keywords {
+ alignas,
+ alignof,
+ char16_t,
+ char32_t,
+ constexpr,
+ decltype,
+ noexcept,
+ nullptr,
+ override,
+ static_assert,
+ thread_local,
+};
+
+int main() { return 0; }
+
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/clang-cxx-language-standard/clang-cxx-language-standard.gyp
@@ -0,0 +1,30 @@
+# Copyright (c) 2013 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.
+{
+ 'make_global_settings': [
+ ['CC', '/usr/bin/clang'],
+ ['CXX', '/usr/bin/clang++'],
+ ],
+ 'targets': [
+ {
+ 'target_name': 'c++98',
+ 'type': 'executable',
+ 'sources': [ 'c++98.cc', ],
+ 'xcode_settings': {
+ 'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0',
+ 'CLANG_CXX_LANGUAGE_STANDARD': 'c++98',
+ },
+ },
+ {
+ 'target_name': 'c++11',
+ 'type': 'executable',
+ 'sources': [ 'c++11.cc', ],
+ 'xcode_settings': {
+ 'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0',
+ 'CLANG_CXX_LANGUAGE_STANDARD': 'c++0x',
+ },
+ },
+ ],
+}
+
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/clang-cxx-library/clang-cxx-library.gyp
@@ -0,0 +1,32 @@
+# Copyright (c) 2013 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.
+{
+ 'make_global_settings': [
+ ['CC', '/usr/bin/clang'],
+ ['CXX', '/usr/bin/clang++'],
+ ],
+ 'targets': [
+ {
+ 'target_name': 'libc++',
+ 'type': 'executable',
+ 'sources': [ 'libc++.cc', ],
+ 'xcode_settings': {
+ 'CC': 'clang',
+ # libc++ requires OS X 10.7+.
+ 'MACOSX_DEPLOYMENT_TARGET': '10.7',
+ 'CLANG_CXX_LIBRARY': 'libc++',
+ },
+ },
+ {
+ 'target_name': 'libstdc++',
+ 'type': 'executable',
+ 'sources': [ 'libstdc++.cc', ],
+ 'xcode_settings': {
+ 'CC': 'clang',
+ 'CLANG_CXX_LIBRARY': 'libstdc++',
+ },
+ },
+ ],
+}
+
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/clang-cxx-library/libc++.cc
@@ -0,0 +1,11 @@
+// Copyright (c) 2013 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 <string>
+#ifndef _LIBCPP_VERSION
+#error expected std library: libc++
+#endif
+
+int main() { std::string x; return x.size(); }
+
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/clang-cxx-library/libstdc++.cc
@@ -0,0 +1,11 @@
+// Copyright (c) 2013 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 <string>
+#ifndef __GLIBCXX__
+#error expected std library: libstdc++
+#endif
+
+int main() { std::string x; return x.size(); }
+
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/copies-with-xcode-envvars/copies-with-xcode-envvars.gyp
@@ -0,0 +1,87 @@
+# Copyright (c) 2016 Mark Callow. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#
+# For testing use of the UI settings & environment variables
+# available in Xcode's PBXCopyFilesBuildPhase.
+{
+'targets': [
+ {
+ 'target_name': 'copies-with-xcode-envvars',
+ 'type': 'executable',
+ 'mac_bundle': 1,
+ 'sources': [ 'empty.c' ],
+ 'conditions': [
+ ['OS == "ios" or OS == "mac"', {
+ 'copies': [{
+ 'destination': '$(BUILT_PRODUCTS_DIR)',
+ 'files': [
+ 'file0',
+ ],
+ }, {
+ 'destination': '$(BUILT_PRODUCTS_DIR)/$(WRAPPER_NAME)',
+ 'files': [
+ 'file1',
+ ],
+ }, {
+ 'destination': '<(PRODUCT_DIR)/$(EXECUTABLE_FOLDER_PATH)',
+ 'files': [
+ 'file2',
+ ],
+ }, {
+ 'destination': '<(PRODUCT_DIR)/$(UNLOCALIZED_RESOURCES_FOLDER_PATH)',
+ 'files': [
+ 'file3',
+ ],
+ }, {
+ 'destination': '<(PRODUCT_DIR)/$(UNLOCALIZED_RESOURCES_FOLDER_PATH)/testimages',
+ 'files': [
+ 'file4',
+ ],
+ }, {
+ 'destination': '$(BUILT_PRODUCTS_DIR)/$(JAVA_FOLDER_PATH)',
+ 'files': [
+ 'file5',
+ ],
+ }, {
+ 'destination': '<(PRODUCT_DIR)/$(FRAMEWORKS_FOLDER_PATH)',
+ 'files': [
+ 'file6',
+ ],
+ }, {
+ # NOTE: This is not an Xcode macro name but
+ # xcodeproj_file.py recognizes it and sends
+ # the output to the same place as
+ # $(FRAMEWORKS_FOLDER_PATH). xcode_emulation.py
+ # sets its value to an absolute path.
+ 'destination': '$(BUILT_FRAMEWORKS_DIR)',
+ 'files': [
+ 'file7',
+ ],
+ }, {
+ 'destination': '<(PRODUCT_DIR)/$(SHARED_FRAMEWORKS_FOLDER_PATH)',
+ 'files': [
+ 'file8',
+ ],
+ }, {
+ 'destination': '<(PRODUCT_DIR)/$(SHARED_SUPPORT_FOLDER_PATH)',
+ 'files': [
+ 'file9',
+ ],
+ }, {
+ 'destination': '<(PRODUCT_DIR)/$(PLUGINS_FOLDER_PATH)',
+ 'files': [
+ 'file10',
+ ],
+ }, {
+ 'destination': '<(PRODUCT_DIR)/$(XPCSERVICES_FOLDER_PATH)',
+ 'files': [
+ 'file11',
+ ],
+ }], # copies
+ }], # OS == "ios" or OS == "mac"
+ ], # conditions
+ }], # targets
+}
+
+# vim:ai:ts=4:sts=4:sw=2:expandtab:textwidth=70
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/copies-with-xcode-envvars/empty.c
@@ -0,0 +1,1 @@
+int main() {}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/copies-with-xcode-envvars/file0
@@ -0,0 +1,1 @@
+file0 contents
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/copies-with-xcode-envvars/file1
@@ -0,0 +1,1 @@
+file1 contents
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/copies-with-xcode-envvars/file10
@@ -0,0 +1,1 @@
+file10 contents
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/copies-with-xcode-envvars/file11
@@ -0,0 +1,1 @@
+file11 contents
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/copies-with-xcode-envvars/file2
@@ -0,0 +1,1 @@
+file2 contents
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/copies-with-xcode-envvars/file3
@@ -0,0 +1,1 @@
+file3 contents
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/copies-with-xcode-envvars/file4
@@ -0,0 +1,1 @@
+file4 contents
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/copies-with-xcode-envvars/file5
@@ -0,0 +1,1 @@
+file5 contents
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/copies-with-xcode-envvars/file6
@@ -0,0 +1,1 @@
+file6 contents
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/copies-with-xcode-envvars/file7
@@ -0,0 +1,1 @@
+file7 contents
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/copies-with-xcode-envvars/file8
@@ -0,0 +1,1 @@
+file8 contents
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/copies-with-xcode-envvars/file9
@@ -0,0 +1,1 @@
+file9 contents
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/deployment-target/check-version-min.c
@@ -0,0 +1,33 @@
+/* Copyright (c) 2013 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 <Availability.h>
+
+/* GYPTEST_MAC_VERSION_MIN: should be set to the corresponding value of
+ * xcode setting 'MACOSX_DEPLOYMENT_TARGET', otherwise both should be
+ * left undefined.
+ *
+ * GYPTEST_IOS_VERSION_MIN: should be set to the corresponding value of
+ * xcode setting 'IPHONEOS_DEPLOYMENT_TARGET', otherwise both should be
+ * left undefined.
+ */
+
+#if defined(GYPTEST_MAC_VERSION_MIN)
+# if GYPTEST_MAC_VERSION_MIN != __MAC_OS_X_VERSION_MIN_REQUIRED
+# error __MAC_OS_X_VERSION_MIN_REQUIRED has wrong value
+# endif
+#elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
+# error __MAC_OS_X_VERSION_MIN_REQUIRED should be undefined
+#endif
+
+#if defined(GYPTEST_IOS_VERSION_MIN)
+# if GYPTEST_IOS_VERSION_MIN != __IPHONE_OS_VERSION_MIN_REQUIRED
+# error __IPHONE_OS_VERSION_MIN_REQUIRED has wrong value
+# endif
+#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
+# error __IPHONE_OS_VERSION_MIN_REQUIRED should be undefined
+#endif
+
+int main() { return 0; }
+
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/deployment-target/deployment-target.gyp
@@ -0,0 +1,28 @@
+# Copyright (c) 2013 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': 'macosx-version-min-10.5',
+ 'type': 'executable',
+ 'sources': [ 'check-version-min.c', ],
+ 'defines': [ 'GYPTEST_MAC_VERSION_MIN=1050', ],
+ 'xcode_settings': {
+ 'SDKROOT': 'macosx',
+ 'MACOSX_DEPLOYMENT_TARGET': '10.5',
+ },
+ },
+ {
+ 'target_name': 'macosx-version-min-10.6',
+ 'type': 'executable',
+ 'sources': [ 'check-version-min.c', ],
+ 'defines': [ 'GYPTEST_MAC_VERSION_MIN=1060', ],
+ 'xcode_settings': {
+ 'SDKROOT': 'macosx',
+ 'MACOSX_DEPLOYMENT_TARGET': '10.6',
+ },
+ },
+ ],
+}
+
--- a/media/webrtc/trunk/tools/gyp/test/mac/framework/TestFramework/Info.plist
+++ b/media/webrtc/trunk/tools/gyp/test/mac/framework/TestFramework/Info.plist
@@ -4,17 +4,17 @@
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
- <string>com.yourcompany.${PRODUCT_NAME}</string>
+ <string>com.yourcompany.${PRODUCT_NAME:identifier}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
--- a/media/webrtc/trunk/tools/gyp/test/mac/framework/framework.gyp
+++ b/media/webrtc/trunk/tools/gyp/test/mac/framework/framework.gyp
@@ -16,19 +16,16 @@
'type': 'shared_library',
'mac_bundle': 1,
'dependencies': [ 'dep_framework', ],
'sources': [
'TestFramework/ObjCVector.h',
'TestFramework/ObjCVectorInternal.h',
'TestFramework/ObjCVector.mm',
],
- 'mac_framework_headers': [
- 'TestFramework/ObjCVector.h',
- ],
'mac_bundle_resources': [
'TestFramework/English.lproj/InfoPlist.strings',
],
'link_settings': {
'libraries': [
'$(SDKROOT)/System/Library/Frameworks/Cocoa.framework',
],
},
@@ -65,10 +62,47 @@
{
'action_name': 'aektschn',
'inputs': [],
'outputs': ['<(PRODUCT_DIR)/touched_file'],
'action': ['touch', '${BUILT_PRODUCTS_DIR}/action_file'],
},
],
},
+ {
+ 'target_name': 'copy_embedded',
+ 'type': 'none',
+ 'dependencies': [ 'test_framework' ],
+ 'copies': [
+ # Test copying framework to FRAMEWORK directory.
+ {
+ 'destination': '$(BUILT_FRAMEWORKS_DIR)/Embedded',
+ 'files': [
+ '<(PRODUCT_DIR)/Test Framework.framework',
+ ],
+ },
+ ],
+ },
+ {
+ 'target_name': 'copy_target_code_sign',
+ 'type': 'none',
+ 'dependencies': [ 'test_framework', 'dep_framework', ],
+ 'copies': [
+ # Test copying directories with spaces in src and dest paths.
+ {
+ 'destination': '<(PRODUCT_DIR)/Test Framework.framework/foo',
+ 'files': [
+ '<(PRODUCT_DIR)/Dependency Bundle.framework',
+ ],
+ 'xcode_code_sign': 1,
+ },
+ ],
+ 'actions': [
+ {
+ 'action_name': 'aektschn',
+ 'inputs': [],
+ 'outputs': ['<(PRODUCT_DIR)/touched_file'],
+ 'action': ['touch', '${BUILT_PRODUCTS_DIR}/action_file'],
+ },
+ ],
+ },
],
}
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-action-envvars.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-action-envvars.py
@@ -10,16 +10,22 @@ Verifies that env vars work with actions
import TestGyp
import sys
if sys.platform == 'darwin':
test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
+ # The xcode-ninja generator handles gypfiles which are not at the
+ # project root incorrectly.
+ # cf. https://code.google.com/p/gyp/issues/detail?id=460
+ if test.format == 'xcode-ninja':
+ test.skip_test()
+
CHDIR = 'action-envvars'
test.run_gyp('action/action.gyp', chdir=CHDIR)
test.build('action/action.gyp', 'action', chdir=CHDIR, SYMROOT='../build')
result_file = test.built_file_path('result', chdir=CHDIR)
test.must_exist(result_file)
test.must_contain(result_file, 'Test output')
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-app-assets-catalog.py
@@ -0,0 +1,123 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 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.
+
+"""
+Verifies that app bundles are built correctly.
+"""
+
+import TestGyp
+import TestMac
+
+import os
+import plistlib
+import subprocess
+import sys
+
+if sys.platform == 'darwin':
+ print "This test is currently disabled: https://crbug.com/483696."
+ sys.exit(0)
+
+def ExpectEq(expected, actual):
+ if expected != actual:
+ print >>sys.stderr, 'Expected "%s", got "%s"' % (expected, actual)
+ test.fail_test()
+
+def ls(path):
+ '''Returns a list of all files in a directory, relative to the directory.'''
+ result = []
+ for dirpath, _, files in os.walk(path):
+ for f in files:
+ result.append(os.path.join(dirpath, f)[len(path) + 1:])
+ return result
+
+# Xcode supports for assets catalog was introduced in Xcode 6.0
+if sys.platform == 'darwin' and TestMac.Xcode.Version() >= '0600':
+ test_gyp_path = 'test-assets-catalog.gyp'
+ test_app_path = 'Test App Assets Catalog Gyp.app'
+
+ test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
+ test.run_gyp(test_gyp_path, chdir='app-bundle')
+ test.build(test_gyp_path, test.ALL, chdir='app-bundle')
+
+ # Binary
+ test.built_file_must_exist(
+ os.path.join(test_app_path, 'Contents/MacOS/Test App Assets Catalog Gyp'),
+ chdir='app-bundle')
+
+ # Info.plist
+ info_plist = test.built_file_path(
+ os.path.join(test_app_path, 'Contents/Info.plist'),
+ chdir='app-bundle')
+ test.must_exist(info_plist)
+ test.must_contain(
+ info_plist,
+ 'com.google.Test-App-Assets-Catalog-Gyp') # Variable expansion
+ test.must_not_contain(info_plist, '${MACOSX_DEPLOYMENT_TARGET}');
+
+ if test.format != 'make':
+ # TODO: Synthesized plist entries aren't hooked up in the make generator.
+ machine = subprocess.check_output(['sw_vers', '-buildVersion']).rstrip('\n')
+ plist = plistlib.readPlist(info_plist)
+ ExpectEq(machine, plist['BuildMachineOSBuild'])
+
+ expected = ''
+ version = TestMac.Xcode.SDKVersion()
+ expected = 'macosx' + version
+ ExpectEq(expected, plist['DTSDKName'])
+ sdkbuild = TestMac.Xcode.SDKBuild()
+ if not sdkbuild:
+ # Above command doesn't work in Xcode 4.2.
+ sdkbuild = plist['BuildMachineOSBuild']
+ ExpectEq(sdkbuild, plist['DTSDKBuild'])
+ ExpectEq(TestMac.Xcode.Version(), plist['DTXcode'])
+ ExpectEq(TestMac.Xcode.Build(), plist['DTXcodeBuild'])
+
+ # Resources
+ strings_files = ['InfoPlist.strings', 'utf-16be.strings', 'utf-16le.strings']
+ for f in strings_files:
+ strings = test.built_file_path(
+ os.path.join(test_app_path, 'Contents/Resources/English.lproj', f),
+ chdir='app-bundle')
+ test.must_exist(strings)
+ # Xcodes writes UTF-16LE with BOM.
+ contents = open(strings, 'rb').read()
+ if not contents.startswith('\xff\xfe' + '/* Localized'.encode('utf-16le')):
+ test.fail_test()
+
+ test.built_file_must_exist(
+ os.path.join(
+ test_app_path, 'Contents/Resources/English.lproj/MainMenu.nib'),
+ chdir='app-bundle')
+
+ # make does not supports .xcassets files
+ extra_content_files = []
+ if test.format != 'make':
+ extra_content_files = ['Contents/Resources/Assets.car']
+ for f in extra_content_files:
+ test.built_file_must_exist(
+ os.path.join(test_app_path, f),
+ chdir='app-bundle')
+
+ # Packaging
+ test.built_file_must_exist(
+ os.path.join(test_app_path, 'Contents/PkgInfo'),
+ chdir='app-bundle')
+ test.built_file_must_match(
+ os.path.join(test_app_path, 'Contents/PkgInfo'), 'APPLause',
+ chdir='app-bundle')
+
+ # Check that no other files get added to the bundle.
+ if set(ls(test.built_file_path(test_app_path, chdir='app-bundle'))) != \
+ set(['Contents/MacOS/Test App Assets Catalog Gyp',
+ 'Contents/Info.plist',
+ 'Contents/Resources/English.lproj/MainMenu.nib',
+ 'Contents/PkgInfo',
+ ] + extra_content_files +
+ [os.path.join('Contents/Resources/English.lproj', f)
+ for f in strings_files]):
+ test.fail_test()
+
+ test.pass_test()
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-app-error.py
@@ -0,0 +1,47 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 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.
+
+"""
+Verifies that invalid strings files cause the build to fail.
+"""
+
+import TestCmd
+import TestGyp
+
+import sys
+
+if sys.platform == 'darwin':
+ print "This test is currently disabled: https://crbug.com/483696."
+ sys.exit(0)
+
+ expected_error = 'Old-style plist parser: missing semicolon in dictionary'
+ saw_expected_error = [False] # Python2 has no "nonlocal" keyword.
+ def match(a, b):
+ if a == b:
+ return True
+ if not TestCmd.is_List(a):
+ a = a.split('\n')
+ if not TestCmd.is_List(b):
+ b = b.split('\n')
+ if expected_error in '\n'.join(a) + '\n'.join(b):
+ saw_expected_error[0] = True
+ return True
+ return False
+ test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'], match=match)
+
+ test.run_gyp('test-error.gyp', chdir='app-bundle')
+
+ test.build('test-error.gyp', test.ALL, chdir='app-bundle')
+
+ # Ninja pipes stderr of subprocesses to stdout.
+ if test.format in ['ninja', 'xcode-ninja'] \
+ and expected_error in test.stdout():
+ saw_expected_error[0] = True
+
+ if saw_expected_error[0]:
+ test.pass_test()
+ else:
+ test.fail_test()
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-app.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-app.py
@@ -4,44 +4,117 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""
Verifies that app bundles are built correctly.
"""
import TestGyp
+import TestMac
+import os
+import plistlib
+import subprocess
import sys
+
+if sys.platform in ('darwin', 'win32'):
+ print "This test is currently disabled: https://crbug.com/483696."
+ sys.exit(0)
+
+
+def CheckFileXMLPropertyList(file):
+ output = subprocess.check_output(['file', file])
+ # The double space after XML is intentional.
+ if not 'XML document text' in output:
+ print 'File: Expected XML document text, got %s' % output
+ test.fail_test()
+
+def ExpectEq(expected, actual):
+ if expected != actual:
+ print >>sys.stderr, 'Expected "%s", got "%s"' % (expected, actual)
+ test.fail_test()
+
+def ls(path):
+ '''Returns a list of all files in a directory, relative to the directory.'''
+ result = []
+ for dirpath, _, files in os.walk(path):
+ for f in files:
+ result.append(os.path.join(dirpath, f)[len(path) + 1:])
+ return result
+
+
if sys.platform == 'darwin':
test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
test.run_gyp('test.gyp', chdir='app-bundle')
test.build('test.gyp', test.ALL, chdir='app-bundle')
# Binary
test.built_file_must_exist('Test App Gyp.app/Contents/MacOS/Test App Gyp',
chdir='app-bundle')
# Info.plist
info_plist = test.built_file_path('Test App Gyp.app/Contents/Info.plist',
chdir='app-bundle')
test.must_exist(info_plist)
- test.must_contain(info_plist, 'com.google.Test App Gyp') # Variable expansion
+ test.must_contain(info_plist, 'com.google.Test-App-Gyp') # Variable expansion
+ test.must_not_contain(info_plist, '${MACOSX_DEPLOYMENT_TARGET}');
+ CheckFileXMLPropertyList(info_plist)
+
+ if test.format != 'make':
+ # TODO: Synthesized plist entries aren't hooked up in the make generator.
+ machine = subprocess.check_output(['sw_vers', '-buildVersion']).rstrip('\n')
+ plist = plistlib.readPlist(info_plist)
+ ExpectEq(machine, plist['BuildMachineOSBuild'])
+
+ # Prior to Xcode 5.0.0, SDKROOT (and thus DTSDKName) was only defined if
+ # set in the Xcode project file. Starting with that version, it is always
+ # defined.
+ expected = ''
+ if TestMac.Xcode.Version() >= '0500':
+ version = TestMac.Xcode.SDKVersion()
+ expected = 'macosx' + version
+ ExpectEq(expected, plist['DTSDKName'])
+ sdkbuild = TestMac.Xcode.SDKBuild()
+ if not sdkbuild:
+ # Above command doesn't work in Xcode 4.2.
+ sdkbuild = plist['BuildMachineOSBuild']
+ ExpectEq(sdkbuild, plist['DTSDKBuild'])
+ ExpectEq(TestMac.Xcode.Version(), plist['DTXcode'])
+ ExpectEq(TestMac.Xcode.Build(), plist['DTXcodeBuild'])
# Resources
- test.built_file_must_exist(
- 'Test App Gyp.app/Contents/Resources/English.lproj/InfoPlist.strings',
- chdir='app-bundle')
+ strings_files = ['InfoPlist.strings', 'utf-16be.strings', 'utf-16le.strings']
+ for f in strings_files:
+ strings = test.built_file_path(
+ os.path.join('Test App Gyp.app/Contents/Resources/English.lproj', f),
+ chdir='app-bundle')
+ test.must_exist(strings)
+ # Xcodes writes UTF-16LE with BOM.
+ contents = open(strings, 'rb').read()
+ if not contents.startswith('\xff\xfe' + '/* Localized'.encode('utf-16le')):
+ test.fail_test()
+
test.built_file_must_exist(
'Test App Gyp.app/Contents/Resources/English.lproj/MainMenu.nib',
chdir='app-bundle')
# Packaging
test.built_file_must_exist('Test App Gyp.app/Contents/PkgInfo',
chdir='app-bundle')
test.built_file_must_match('Test App Gyp.app/Contents/PkgInfo', 'APPLause',
chdir='app-bundle')
+ # Check that no other files get added to the bundle.
+ if set(ls(test.built_file_path('Test App Gyp.app', chdir='app-bundle'))) != \
+ set(['Contents/MacOS/Test App Gyp',
+ 'Contents/Info.plist',
+ 'Contents/Resources/English.lproj/MainMenu.nib',
+ 'Contents/PkgInfo',
+ ] +
+ [os.path.join('Contents/Resources/English.lproj', f)
+ for f in strings_files]):
+ test.fail_test()
test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-archs.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-archs.py
@@ -4,34 +4,92 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""
Tests things related to ARCHS.
"""
import TestGyp
+import TestMac
+import re
import subprocess
import sys
if sys.platform == 'darwin':
test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
- def CheckFileType(file, expected):
- proc = subprocess.Popen(['file', '-b', file], stdout=subprocess.PIPE)
- o = proc.communicate()[0].strip()
- assert not proc.returncode
- if o != expected:
- print 'File: Expected %s, got %s' % (expected, o)
- test.fail_test()
-
test.run_gyp('test-no-archs.gyp', chdir='archs')
test.build('test-no-archs.gyp', test.ALL, chdir='archs')
result_file = test.built_file_path('Test', chdir='archs')
test.must_exist(result_file)
- CheckFileType(result_file, 'Mach-O executable i386')
+
+ if TestMac.Xcode.Version() >= '0500':
+ expected_type = ['x86_64']
+ else:
+ expected_type = ['i386']
+ TestMac.CheckFileType(test, result_file, expected_type)
+
+ test.run_gyp('test-valid-archs.gyp', chdir='archs')
+ test.build('test-valid-archs.gyp', test.ALL, chdir='archs')
+ result_file = test.built_file_path('Test', chdir='archs')
+ test.must_exist(result_file)
+ TestMac.CheckFileType(test, result_file, ['x86_64'])
test.run_gyp('test-archs-x86_64.gyp', chdir='archs')
test.build('test-archs-x86_64.gyp', test.ALL, chdir='archs')
result_file = test.built_file_path('Test64', chdir='archs')
test.must_exist(result_file)
- CheckFileType(result_file, 'Mach-O 64-bit executable x86_64')
+ TestMac.CheckFileType(test, result_file, ['x86_64'])
+
+ test.run_gyp('test-dependencies.gyp', chdir='archs')
+ test.build('test-dependencies.gyp', target=test.ALL, chdir='archs')
+ products = ['c_standalone', 'd_standalone']
+ for product in products:
+ result_file = test.built_file_path(
+ product, chdir='archs', type=test.STATIC_LIB)
+ test.must_exist(result_file)
+
+ if test.format != 'make':
+ # Build all targets except 'exe_32_64_no_sources' that does build
+ # but should not cause error when generating ninja files
+ targets = [
+ 'static_32_64', 'shared_32_64', 'shared_32_64_bundle',
+ 'module_32_64', 'module_32_64_bundle',
+ 'exe_32_64', 'exe_32_64_bundle', 'precompiled_prefix_header_mm_32_64',
+ ]
+
+ test.run_gyp('test-archs-multiarch.gyp', chdir='archs')
+
+ for target in targets:
+ test.build('test-archs-multiarch.gyp', target=target, chdir='archs')
+
+ result_file = test.built_file_path(
+ 'static_32_64', chdir='archs', type=test.STATIC_LIB)
+ test.must_exist(result_file)
+ TestMac.CheckFileType(test, result_file, ['i386', 'x86_64'])
+
+ result_file = test.built_file_path(
+ 'shared_32_64', chdir='archs', type=test.SHARED_LIB)
+ test.must_exist(result_file)
+ TestMac.CheckFileType(test, result_file, ['i386', 'x86_64'])
+
+ result_file = test.built_file_path('My Framework.framework/My Framework',
+ chdir='archs')
+ test.must_exist(result_file)
+ TestMac.CheckFileType(test, result_file, ['i386', 'x86_64'])
+ # Check that symbol "_x" made it into both versions of the binary:
+ if not all(['D _x' in subprocess.check_output(
+ ['nm', '-arch', arch, result_file]) for arch in ['i386', 'x86_64']]):
+ # This can only flakily fail, due to process ordering issues. If this
+ # does fail flakily, then something's broken, it's not the test at fault.
+ test.fail_test()
+
+ result_file = test.built_file_path(
+ 'exe_32_64', chdir='archs', type=test.EXECUTABLE)
+ test.must_exist(result_file)
+ TestMac.CheckFileType(test, result_file, ['i386', 'x86_64'])
+
+ result_file = test.built_file_path('Test App.app/Contents/MacOS/Test App',
+ chdir='archs')
+ test.must_exist(result_file)
+ TestMac.CheckFileType(test, result_file, ['i386', 'x86_64'])
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-bundle-resources.py
@@ -0,0 +1,62 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 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.
+
+"""
+Verifies things related to bundle resources.
+"""
+
+import TestGyp
+
+import os
+import stat
+import sys
+
+if sys.platform in ('darwin'):
+ print "This test is currently disabled: https://crbug.com/483696."
+ sys.exit(0)
+
+
+def check_attribs(path, expected_exec_bit):
+ out_path = test.built_file_path(
+ os.path.join('resource.app/Contents/Resources', path), chdir=CHDIR)
+
+ in_stat = os.stat(os.path.join(CHDIR, path))
+ out_stat = os.stat(out_path)
+ if in_stat.st_mtime == out_stat.st_mtime:
+ test.fail_test()
+ if out_stat.st_mode & stat.S_IXUSR != expected_exec_bit:
+ test.fail_test()
+
+
+if sys.platform == 'darwin':
+ # set |match| to ignore build stderr output.
+ test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
+
+ CHDIR = 'bundle-resources'
+ test.run_gyp('test.gyp', chdir=CHDIR)
+
+ test.build('test.gyp', test.ALL, chdir=CHDIR)
+
+ test.built_file_must_match('resource.app/Contents/Resources/secret.txt',
+ 'abc\n', chdir=CHDIR)
+ test.built_file_must_match('source_rule.app/Contents/Resources/secret.txt',
+ 'ABC\n', chdir=CHDIR)
+
+ test.built_file_must_match(
+ 'resource.app/Contents/Resources/executable-file.sh',
+ '#!/bin/bash\n'
+ '\n'
+ 'echo echo echo echo cho ho o o\n', chdir=CHDIR)
+
+ check_attribs('executable-file.sh', expected_exec_bit=stat.S_IXUSR)
+ check_attribs('secret.txt', expected_exec_bit=0)
+
+ # TODO(thakis): This currently fails with make.
+ if test.format != 'make':
+ test.built_file_must_match(
+ 'resource_rule.app/Contents/Resources/secret.txt', 'ABC\n', chdir=CHDIR)
+
+ test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-cflags.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-cflags.py
@@ -1,9 +1,8 @@
-
#!/usr/bin/env python
# Copyright (c) 2012 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.
"""
Verifies that compile-time flags work.
@@ -12,10 +11,11 @@ Verifies that compile-time flags work.
import TestGyp
import sys
if sys.platform == 'darwin':
test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
CHDIR = 'cflags'
test.run_gyp('test.gyp', chdir=CHDIR)
+
test.build('test.gyp', test.ALL, chdir=CHDIR)
test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-clang-cxx-language-standard.py
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 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.
+
+"""
+Verifies that CLANG_CXX_LANGUAGE_STANDARD works.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'darwin':
+ test = TestGyp.TestGyp(formats=['make', 'ninja', 'xcode'])
+
+ test.run_gyp('clang-cxx-language-standard.gyp',
+ chdir='clang-cxx-language-standard')
+
+ test.build('clang-cxx-language-standard.gyp', test.ALL,
+ chdir='clang-cxx-language-standard')
+
+ test.pass_test()
+
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-clang-cxx-library.py
@@ -0,0 +1,28 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 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.
+
+"""
+Verifies that CLANG_CXX_LIBRARY works.
+"""
+
+import TestGyp
+import TestMac
+
+import os
+import sys
+
+if sys.platform == 'darwin':
+ # Xcode 4.2 on OS X 10.6 doesn't install the libc++ headers, don't run this
+ # test there.
+ if TestMac.Xcode.Version() <= '0420':
+ sys.exit(0)
+
+ test = TestGyp.TestGyp(formats=['make', 'ninja', 'xcode'])
+ test.run_gyp('clang-cxx-library.gyp', chdir='clang-cxx-library')
+ test.build('clang-cxx-library.gyp', test.ALL, chdir='clang-cxx-library')
+
+ test.pass_test()
+
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-copies-with-xcode-envvars.py
@@ -0,0 +1,65 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2016 Mark Callow. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that files are copied to the correct destinations when those
+destinations are specified using environment variables available in
+Xcode's PBXCopyFilesBuildPhase.
+"""
+
+import TestGyp
+
+import os
+import stat
+import sys
+
+
+test = TestGyp.TestGyp(formats=['make', 'ninja', 'xcode'])
+
+if sys.platform == 'darwin':
+ test.run_gyp('copies-with-xcode-envvars.gyp',
+ chdir='copies-with-xcode-envvars')
+
+ test.build('copies-with-xcode-envvars.gyp', chdir='copies-with-xcode-envvars')
+
+ wrapper_name = 'copies-with-xcode-envvars.app/'
+ contents_path = wrapper_name + 'Contents/'
+ out_path = test.built_file_path('file0', chdir='copies-with-xcode-envvars')
+ test.must_contain(out_path, 'file0 contents\n')
+ out_path = test.built_file_path(wrapper_name + 'file1',
+ chdir='copies-with-xcode-envvars')
+ test.must_contain(out_path, 'file1 contents\n')
+ out_path = test.built_file_path(contents_path + 'MacOS/file2',
+ chdir='copies-with-xcode-envvars')
+ test.must_contain(out_path, 'file2 contents\n')
+ out_path = test.built_file_path(contents_path + 'Resources/file3',
+ chdir='copies-with-xcode-envvars')
+ test.must_contain(out_path, 'file3 contents\n')
+ out_path = test.built_file_path(contents_path + 'Resources/testimages/file4',
+ chdir='copies-with-xcode-envvars')
+ test.must_contain(out_path, 'file4 contents\n')
+ out_path = test.built_file_path(contents_path + 'Resources/Java/file5',
+ chdir='copies-with-xcode-envvars')
+ test.must_contain(out_path, 'file5 contents\n')
+ out_path = test.built_file_path(contents_path + 'Frameworks/file6',
+ chdir='copies-with-xcode-envvars')
+ test.must_contain(out_path, 'file6 contents\n')
+ out_path = test.built_file_path(contents_path + 'Frameworks/file7',
+ chdir='copies-with-xcode-envvars')
+ test.must_contain(out_path, 'file7 contents\n')
+ out_path = test.built_file_path(contents_path + 'SharedFrameworks/file8',
+ chdir='copies-with-xcode-envvars')
+ test.must_contain(out_path, 'file8 contents\n')
+ out_path = test.built_file_path(contents_path + 'SharedSupport/file9',
+ chdir='copies-with-xcode-envvars')
+ test.must_contain(out_path, 'file9 contents\n')
+ out_path = test.built_file_path(contents_path + 'PlugIns/file10',
+ chdir='copies-with-xcode-envvars')
+ test.must_contain(out_path, 'file10 contents\n')
+ out_path = test.built_file_path(contents_path + 'XPCServices/file11',
+ chdir='copies-with-xcode-envvars')
+ test.must_contain(out_path, 'file11 contents\n')
+ test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-copies.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-copies.py
@@ -10,16 +10,19 @@ Verifies that 'copies' with app bundles
import TestGyp
import os
import sys
import time
if sys.platform == 'darwin':
+ print "This test is currently disabled: https://crbug.com/483696."
+ sys.exit(0)
+
test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
test.run_gyp('framework.gyp', chdir='framework')
test.build('framework.gyp', 'copy_target', chdir='framework')
# Check that the copy succeeded.
test.built_file_must_exist(
@@ -27,23 +30,31 @@ if sys.platform == 'darwin':
chdir='framework')
test.built_file_must_exist(
'Test Framework.framework/foo/Dependency Bundle.framework/Versions/A',
chdir='framework')
test.built_file_must_exist(
'Test Framework.framework/Versions/A/Libraries/empty.c',
chdir='framework')
+ # Verify BUILT_FRAMEWORKS_DIR is set and working.
+ test.build('framework.gyp', 'copy_embedded', chdir='framework')
+
+ test.built_file_must_exist(
+ 'Embedded/Test Framework.framework', chdir='framework')
# Check that rebuilding the target a few times works.
dep_bundle = test.built_file_path('Dependency Bundle.framework',
chdir='framework')
mtime = os.path.getmtime(dep_bundle)
atime = os.path.getatime(dep_bundle)
for i in range(3):
os.utime(dep_bundle, (atime + i * 1000, mtime + i * 1000))
test.build('framework.gyp', 'copy_target', chdir='framework')
# Check that actions ran.
test.built_file_must_exist('action_file', chdir='framework')
+ # Test that a copy with the "Code Sign on Copy" flag on succeeds.
+ test.build('framework.gyp', 'copy_target_code_sign', chdir='framework')
+
test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-depend-on-bundle.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-depend-on-bundle.py
@@ -8,16 +8,19 @@
Verifies that a dependency on a bundle causes the whole bundle to be built.
"""
import TestGyp
import sys
if sys.platform == 'darwin':
+ print "This test is currently disabled: https://crbug.com/483696."
+ sys.exit(0)
+
test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
test.run_gyp('test.gyp', chdir='depend-on-bundle')
test.build('test.gyp', 'dependent_on_bundle', chdir='depend-on-bundle')
# Binary itself.
test.built_file_must_exist('dependent_on_bundle', chdir='depend-on-bundle')
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-deployment-target.py
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 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.
+
+"""
+Verifies that MACOSX_DEPLOYMENT_TARGET works.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'darwin':
+ test = TestGyp.TestGyp(formats=['make', 'ninja', 'xcode'])
+
+ test.run_gyp('deployment-target.gyp', chdir='deployment-target')
+
+ test.build('deployment-target.gyp', test.ALL, chdir='deployment-target')
+
+ test.pass_test()
+
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-framework.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-framework.py
@@ -5,34 +5,51 @@
# found in the LICENSE file.
"""
Verifies that app bundles are built correctly.
"""
import TestGyp
+import os
import sys
if sys.platform == 'darwin':
+ print "This test is currently disabled: https://crbug.com/483696."
+ sys.exit(0)
+
+
+def ls(path):
+ '''Returns a list of all files in a directory, relative to the directory.'''
+ result = []
+ for dirpath, _, files in os.walk(path):
+ for f in files:
+ result.append(os.path.join(dirpath, f)[len(path) + 1:])
+ return result
+
+
+if sys.platform == 'darwin':
test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
test.run_gyp('framework.gyp', chdir='framework')
test.build('framework.gyp', 'test_framework', chdir='framework')
# Binary
test.built_file_must_exist(
'Test Framework.framework/Versions/A/Test Framework',
chdir='framework')
# Info.plist
- test.built_file_must_exist(
+ info_plist = test.built_file_path(
'Test Framework.framework/Versions/A/Resources/Info.plist',
chdir='framework')
+ test.must_exist(info_plist)
+ test.must_contain(info_plist, 'com.yourcompany.Test_Framework')
# Resources
test.built_file_must_exist(
'Test Framework.framework/Versions/A/Resources/English.lproj/'
'InfoPlist.strings',
chdir='framework')
# Symlinks created by packaging process
@@ -42,9 +59,20 @@ if sys.platform == 'darwin':
chdir='framework')
test.built_file_must_exist('Test Framework.framework/Test Framework',
chdir='framework')
# PkgInfo.
test.built_file_must_not_exist(
'Test Framework.framework/Versions/A/Resources/PkgInfo',
chdir='framework')
+ # Check that no other files get added to the bundle.
+ if set(ls(test.built_file_path('Test Framework.framework',
+ chdir='framework'))) != \
+ set(['Versions/A/Test Framework',
+ 'Versions/A/Resources/Info.plist',
+ 'Versions/A/Resources/English.lproj/InfoPlist.strings',
+ 'Test Framework',
+ 'Versions/A/Libraries/empty.c', # Written by a gyp action.
+ ]):
+ test.fail_test()
+
test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-global-settings.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-global-settings.py
@@ -10,16 +10,23 @@ Regression test for http://crbug.com/109
"""
import TestGyp
import sys
if sys.platform == 'darwin':
test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
+
+ # The xcode-ninja generator handles gypfiles which are not at the
+ # project root incorrectly.
+ # cf. https://code.google.com/p/gyp/issues/detail?id=460
+ if test.format == 'xcode-ninja':
+ test.skip_test()
+
test.run_gyp('src/dir2/dir2.gyp', chdir='global-settings', depth='src')
# run_gyp shouldn't throw.
# Check that BUILT_PRODUCTS_DIR was set correctly, too.
test.build('dir2/dir2.gyp', 'dir2_target', chdir='global-settings/src',
SYMROOT='../build')
test.built_file_must_exist('file.txt', chdir='global-settings/src')
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-identical-name.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 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.
+
+"""
+Verifies libraries (in identical-names) are properly handeled by xcode.
+
+The names for all libraries participating in this build are:
+libtestlib.a - identical-name/testlib
+libtestlib.a - identical-name/proxy/testlib
+libproxy.a - identical-name/proxy
+The first two libs produce a hash collision in Xcode when Gyp is executed,
+because they have the same name and would be copied to the same directory with
+Xcode default settings.
+For this scenario to work one needs to change the Xcode variables SYMROOT and
+CONFIGURATION_BUILD_DIR. Setting these to per-lib-unique directories, avoids
+copying the libs into the same directory.
+
+The test consists of two steps. The first one verifies that by setting both
+vars, there is no hash collision anymore during Gyp execution and that the libs
+can actually be be built. The second one verifies that there is still a hash
+collision if the vars are not set and thus the current behavior is preserved.
+"""
+
+import TestGyp
+
+import sys
+
+def IgnoreOutput(string, expected_string):
+ return True
+
+if sys.platform == 'darwin':
+ test = TestGyp.TestGyp(formats=['xcode'])
+
+
+ test.run_gyp('test.gyp', chdir='identical-name')
+ test.build('test.gyp', test.ALL, chdir='identical-name')
+
+ test.run_gyp('test-should-fail.gyp', chdir='identical-name')
+ test.built_file_must_not_exist('test-should-fail.xcodeproj')
+
+ test.pass_test()
+
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-infoplist-process.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-infoplist-process.py
@@ -8,16 +8,19 @@
Verifies the Info.plist preprocessor functionality.
"""
import TestGyp
import sys
if sys.platform == 'darwin':
+ print "This test is currently disabled: https://crbug.com/483696."
+ sys.exit(0)
+
test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
CHDIR = 'infoplist-process'
INFO_PLIST_PATH = 'Test.app/Contents/Info.plist'
# First process both keys.
test.set_configuration('One')
test.run_gyp('test1.gyp', chdir=CHDIR)
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-installname.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-installname.py
@@ -11,20 +11,24 @@ correctly.
import TestGyp
import re
import subprocess
import sys
if sys.platform == 'darwin':
+ print "This test is currently disabled: https://crbug.com/483696."
+ sys.exit(0)
+
test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
CHDIR = 'installname'
test.run_gyp('test.gyp', chdir=CHDIR)
+
test.build('test.gyp', test.ALL, chdir=CHDIR)
def GetInstallname(p):
p = test.built_file_path(p, chdir=CHDIR)
r = re.compile(r'cmd LC_ID_DYLIB.*?name (.*?) \(offset \d+\)', re.DOTALL)
proc = subprocess.Popen(['otool', '-l', p], stdout=subprocess.PIPE)
o = proc.communicate()[0]
assert not proc.returncode
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-kext.py
@@ -0,0 +1,27 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2015 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.
+
+"""
+Verifies that kext bundles are built correctly.
+"""
+
+import TestGyp
+import TestMac
+
+import os
+import plistlib
+import subprocess
+import sys
+
+if sys.platform == 'darwin':
+ test = TestGyp.TestGyp(formats=['xcode'])
+ test.run_gyp('kext.gyp', chdir='kext')
+ test.build('kext.gyp', test.ALL, chdir='kext')
+ test.built_file_must_exist('GypKext.kext/Contents/MacOS/GypKext',
+ chdir='kext')
+ test.built_file_must_exist('GypKext.kext/Contents/Info.plist',
+ chdir='kext')
+ test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-ldflags-passed-to-libtool.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-ldflags-passed-to-libtool.py
@@ -8,23 +8,27 @@
Verifies that OTHER_LDFLAGS is passed to libtool.
"""
import TestGyp
import sys
if sys.platform == 'darwin':
+ print "This test is currently disabled: https://crbug.com/483696."
+ sys.exit(0)
+
test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'],
match = lambda a, b: True)
build_error_code = {
- 'xcode': 1,
+ 'xcode': [1, 65], # 1 for xcode 3, 65 for xcode 4 (see `man sysexits`)
'make': 2,
'ninja': 1,
+ 'xcode-ninja': [1, 65],
}[test.format]
CHDIR = 'ldflags-libtool'
test.run_gyp('test.gyp', chdir=CHDIR)
test.build('test.gyp', 'ldflags_passed_to_libtool', chdir=CHDIR,
status=build_error_code)
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-ldflags.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-ldflags.py
@@ -11,16 +11,22 @@ build-directory relative paths correctly
import TestGyp
import sys
if sys.platform == 'darwin':
test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
+ # The xcode-ninja generator handles gypfiles which are not at the
+ # project root incorrectly.
+ # cf. https://code.google.com/p/gyp/issues/detail?id=460
+ if test.format == 'xcode-ninja':
+ test.skip_test()
+
CHDIR = 'ldflags'
test.run_gyp('subdirectory/test.gyp', chdir=CHDIR)
test.build('subdirectory/test.gyp', test.ALL, chdir=CHDIR)
test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-libraries.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-libraries.py
@@ -10,13 +10,19 @@ Verifies libraries (in link_settings) ar
import TestGyp
import sys
if sys.platform == 'darwin':
test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
+ # The xcode-ninja generator handles gypfiles which are not at the
+ # project root incorrectly.
+ # cf. https://code.google.com/p/gyp/issues/detail?id=460
+ if test.format == 'xcode-ninja':
+ test.skip_test()
+
test.run_gyp('subdir/test.gyp', chdir='libraries')
test.build('subdir/test.gyp', test.ALL, chdir='libraries')
test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-libtool-zero.py
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 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.
+
+"""
+Verifies libraries have proper mtime.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'darwin':
+ test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
+
+ CHDIR = 'libtool-zero'
+
+ test.run_gyp('test.gyp', chdir=CHDIR)
+
+ test.build('test.gyp', 'mylib', chdir=CHDIR)
+
+ test.up_to_date('test.gyp', 'mylib', chdir=CHDIR)
+
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-loadable-module-bundle-product-extension.py
@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 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.
+
+"""
+Tests that loadable_modules don't collide when using the same name with
+different file extensions.
+"""
+
+import TestGyp
+
+import os
+import struct
+import sys
+
+if sys.platform == 'darwin':
+ test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
+
+ CHDIR = 'loadable-module-bundle-product-extension'
+ test.run_gyp('test.gyp',
+ '-G', 'xcode_ninja_target_pattern=^.*$',
+ chdir=CHDIR)
+
+ test.build('test.gyp', test.ALL, chdir=CHDIR)
+
+ test.must_exist(test.built_file_path('Collide.foo', chdir=CHDIR))
+ test.must_exist(test.built_file_path('Collide.bar', chdir=CHDIR))
+
+ test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-loadable-module.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-loadable-module.py
@@ -6,40 +6,47 @@
"""
Tests that a loadable_module target is built correctly.
"""
import TestGyp
import os
+import struct
import sys
if sys.platform == 'darwin':
+ print "This test is currently disabled: https://crbug.com/483696."
+ sys.exit(0)
+
test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
- test.run_gyp('test.gyp', chdir='loadable-module')
- test.build('test.gyp', test.ALL, chdir='loadable-module')
+ CHDIR = 'loadable-module'
+ test.run_gyp('test.gyp', chdir=CHDIR)
+
+ test.build('test.gyp', test.ALL, chdir=CHDIR)
# Binary.
- test.built_file_must_exist(
+ binary = test.built_file_path(
'test_loadable_module.plugin/Contents/MacOS/test_loadable_module',
- chdir='loadable-module')
+ chdir=CHDIR)
+ test.must_exist(binary)
+ MH_BUNDLE = 8
+ if struct.unpack('4I', open(binary, 'rb').read(16))[3] != MH_BUNDLE:
+ test.fail_test()
# Info.plist.
info_plist = test.built_file_path(
- 'test_loadable_module.plugin/Contents/Info.plist',
- chdir='loadable-module')
+ 'test_loadable_module.plugin/Contents/Info.plist', chdir=CHDIR)
test.must_exist(info_plist)
test.must_contain(info_plist, """
<key>CFBundleExecutable</key>
<string>test_loadable_module</string>
""")
# PkgInfo.
test.built_file_must_not_exist(
- 'test_loadable_module.plugin/Contents/PkgInfo',
- chdir='loadable-module')
+ 'test_loadable_module.plugin/Contents/PkgInfo', chdir=CHDIR)
test.built_file_must_not_exist(
- 'test_loadable_module.plugin/Contents/Resources',
- chdir='loadable-module')
+ 'test_loadable_module.plugin/Contents/Resources', chdir=CHDIR)
test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-lto.py
@@ -0,0 +1,65 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2015 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.
+
+"""
+Verifies that LTO flags work.
+"""
+
+import TestGyp
+
+import os
+import re
+import subprocess
+import sys
+
+if sys.platform == 'darwin':
+ test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
+ CHDIR = 'lto'
+ test.run_gyp('test.gyp', chdir=CHDIR)
+
+ test.build('test.gyp', test.ALL, chdir=CHDIR)
+
+ def ObjPath(srcpath, target):
+ # TODO: Move this into TestGyp if it's needed elsewhere.
+ if test.format == 'xcode':
+ return os.path.join(CHDIR, 'build', 'test.build', 'Default',
+ target + '.build', 'Objects-normal', 'x86_64',
+ srcpath + '.o')
+ elif 'ninja' in test.format: # ninja, xcode-ninja
+ return os.path.join(CHDIR, 'out', 'Default', 'obj',
+ target + '.' + srcpath + '.o')
+ elif test.format == 'make':
+ return os.path.join(CHDIR, 'out', 'Default', 'obj.target',
+ target, srcpath + '.o')
+
+ def ObjType(p, t_expected):
+ r = re.compile(r'nsyms\s+(\d+)')
+ o = subprocess.check_output(['file', p])
+ objtype = 'unknown'
+ if ': Mach-O ' in o:
+ objtype = 'mach-o'
+ elif ': LLVM bit-code ' in o:
+ objtype = 'llvm'
+ if objtype != t_expected:
+ print 'Expected %s, got %s' % (t_expected, objtype)
+ test.fail_test()
+
+ ObjType(ObjPath('cfile', 'lto'), 'llvm')
+ ObjType(ObjPath('ccfile', 'lto'), 'llvm')
+ ObjType(ObjPath('mfile', 'lto'), 'llvm')
+ ObjType(ObjPath('mmfile', 'lto'), 'llvm')
+ ObjType(ObjPath('asmfile', 'lto'), 'mach-o')
+
+ ObjType(ObjPath('cfile', 'lto_static'), 'llvm')
+ ObjType(ObjPath('ccfile', 'lto_static'), 'llvm')
+ ObjType(ObjPath('mfile', 'lto_static'), 'llvm')
+ ObjType(ObjPath('mmfile', 'lto_static'), 'llvm')
+ ObjType(ObjPath('asmfile', 'lto_static'), 'mach-o')
+
+ test.pass_test()
+
+ # TODO: Probably test for -object_path_lto too, else dsymutil won't be
+ # useful maybe?
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-missing-cfbundlesignature.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-missing-cfbundlesignature.py
@@ -8,16 +8,19 @@
Verifies that an Info.plist with CFBundleSignature works.
"""
import TestGyp
import sys
if sys.platform == 'darwin':
+ print "This test is currently disabled: https://crbug.com/483696."
+ sys.exit(0)
+
test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
test.run_gyp('test.gyp', chdir='missing-cfbundlesignature')
test.build('test.gyp', test.ALL, chdir='missing-cfbundlesignature')
test.built_file_must_match('mytarget.app/Contents/PkgInfo', 'APPL????',
chdir='missing-cfbundlesignature')
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-non-strs-flattened-to-env.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-non-strs-flattened-to-env.py
@@ -9,16 +9,19 @@ Verifies that list xcode_settings are fl
environment.
"""
import TestGyp
import sys
if sys.platform == 'darwin':
+ print "This test is currently disabled: https://crbug.com/483696."
+ sys.exit(0)
+
test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
CHDIR = 'non-strs-flattened-to-env'
INFO_PLIST_PATH = 'Test.app/Contents/Info.plist'
test.run_gyp('test.gyp', chdir=CHDIR)
test.build('test.gyp', test.ALL, chdir=CHDIR)
info_plist = test.built_file_path(INFO_PLIST_PATH, chdir=CHDIR)
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-objc-arc.py
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 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.
+
+"""
+Verifies that ARC objc settings are handled correctly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'darwin':
+ # set |match| to ignore build stderr output.
+ test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'],
+ match = lambda a, b: True)
+
+ CHDIR = 'objc-arc'
+ test.run_gyp('test.gyp', chdir=CHDIR)
+
+ test.build('test.gyp', 'arc_enabled', chdir=CHDIR)
+ test.build('test.gyp', 'arc_disabled', chdir=CHDIR)
+
+ test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-objc-gc.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-objc-gc.py
@@ -1,45 +1,51 @@
#!/usr/bin/env python
# Copyright (c) 2012 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.
"""
-Verifies that objc settings are handled correctly.
+Verifies that GC objc settings are handled correctly.
"""
import TestGyp
+import TestMac
import sys
if sys.platform == 'darwin':
# set |match| to ignore build stderr output.
test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'],
match = lambda a, b: True)
- CHDIR = 'objc-gc'
- test.run_gyp('test.gyp', chdir=CHDIR)
+ # Xcode 5.1 removed support for garbage-collection:
+ # error: garbage collection is no longer supported
+ if TestMac.Xcode.Version() < '0510':
- build_error_code = {
- 'xcode': [1, 65], # Linker error code. 1 on Xcode 3, 65 on Xcode 4
- 'make': 2,
- 'ninja': 1,
- }[test.format]
+ CHDIR = 'objc-gc'
+ test.run_gyp('test.gyp', chdir=CHDIR)
+
+ build_error_code = {
+ 'xcode': [1, 65], # 1 for xcode 3, 65 for xcode 4 (see `man sysexits`)
+ 'make': 2,
+ 'ninja': 1,
+ }[test.format]
- test.build('test.gyp', 'gc_exe_fails', chdir=CHDIR, status=build_error_code)
- test.build(
- 'test.gyp', 'gc_off_exe_req_lib', chdir=CHDIR, status=build_error_code)
+ test.build('test.gyp', 'gc_exe_fails', chdir=CHDIR, status=build_error_code)
+ test.build(
+ 'test.gyp', 'gc_off_exe_req_lib', chdir=CHDIR, status=build_error_code)
- test.build('test.gyp', 'gc_req_exe', chdir=CHDIR)
- test.run_built_executable('gc_req_exe', chdir=CHDIR, stdout="gc on: 1\n")
+ test.build('test.gyp', 'gc_req_exe', chdir=CHDIR)
+ test.run_built_executable('gc_req_exe', chdir=CHDIR, stdout="gc on: 1\n")
- test.build('test.gyp', 'gc_exe_req_lib', chdir=CHDIR)
- test.run_built_executable('gc_exe_req_lib', chdir=CHDIR, stdout="gc on: 1\n")
+ test.build('test.gyp', 'gc_exe_req_lib', chdir=CHDIR)
+ test.run_built_executable(
+ 'gc_exe_req_lib', chdir=CHDIR, stdout="gc on: 1\n")
- test.build('test.gyp', 'gc_exe', chdir=CHDIR)
- test.run_built_executable('gc_exe', chdir=CHDIR, stdout="gc on: 1\n")
+ test.build('test.gyp', 'gc_exe', chdir=CHDIR)
+ test.run_built_executable('gc_exe', chdir=CHDIR, stdout="gc on: 1\n")
- test.build('test.gyp', 'gc_off_exe', chdir=CHDIR)
- test.run_built_executable('gc_off_exe', chdir=CHDIR, stdout="gc on: 0\n")
+ test.build('test.gyp', 'gc_off_exe', chdir=CHDIR)
+ test.run_built_executable('gc_off_exe', chdir=CHDIR, stdout="gc on: 0\n")
test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-postbuild-copy-bundle.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-postbuild-copy-bundle.py
@@ -16,21 +16,24 @@ import sys
if sys.platform == 'darwin':
# TODO(thakis): Make this pass with the make generator, http://crbug.com/95529
test = TestGyp.TestGyp(formats=['ninja', 'xcode'])
CHDIR = 'postbuild-copy-bundle'
test.run_gyp('test.gyp', chdir=CHDIR)
- app_bundle_dir = test.built_file_path('Test app.app', chdir=CHDIR)
+ app_bundle_dir = test.built_file_path('Test App.app', chdir=CHDIR)
bundled_framework_dir = os.path.join(
app_bundle_dir, 'Contents', 'My Framework.framework', 'Resources')
final_plist_path = os.path.join(bundled_framework_dir, 'Info.plist')
final_resource_path = os.path.join(bundled_framework_dir, 'resource_file.sb')
+ final_copies_path = os.path.join(
+ app_bundle_dir, 'Contents', 'My Framework.framework', 'Versions', 'A',
+ 'Libraries', 'copied.txt')
# Check that the dependency was built and copied into the app bundle:
test.build('test.gyp', 'test_app', chdir=CHDIR)
test.must_exist(final_resource_path)
test.must_match(final_resource_path,
'This is included in the framework bundle.\n')
test.must_exist(final_plist_path)
@@ -54,9 +57,19 @@ if sys.platform == 'darwin':
test.write('postbuild-copy-bundle/Framework-Info.plist', contents)
test.build('test.gyp', 'test_app', chdir=CHDIR)
test.must_exist(final_plist_path)
test.must_contain(final_plist_path, '''\
\t<key>RandomKey</key>
\t<string>NewRandomValue</string>''')
+ # Check the same for the copies section, test for http://crbug.com/157077
+ test.sleep()
+ contents = test.read('postbuild-copy-bundle/copied.txt')
+ contents = contents.replace('old', 'new')
+ test.write('postbuild-copy-bundle/copied.txt', contents)
+ test.build('test.gyp', 'test_app', chdir=CHDIR)
+
+ test.must_exist(final_copies_path)
+ test.must_contain(final_copies_path, 'new copied file')
+
test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-postbuild-defaults.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-postbuild-defaults.py
@@ -8,16 +8,19 @@
Verifies that a postbuild invoking |defaults| works.
"""
import TestGyp
import sys
if sys.platform == 'darwin':
+ print "This test is currently disabled: https://crbug.com/483696."
+ sys.exit(0)
+
test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
CHDIR = 'postbuild-defaults'
test.run_gyp('test.gyp', chdir=CHDIR)
test.build('test.gyp', test.ALL, chdir=CHDIR)
result_file = test.built_file_path('result', chdir=CHDIR)
test.must_exist(result_file)
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-postbuild-fail.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-postbuild-fail.py
@@ -15,41 +15,54 @@ import sys
if sys.platform == 'darwin':
# set |match| to ignore build stderr output.
test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'],
match = lambda a, b: True)
test.run_gyp('test.gyp', chdir='postbuild-fail')
build_error_code = {
- 'xcode': 1,
+ 'xcode': [1, 65], # 1 for xcode 3, 65 for xcode 4 (see `man sysexits`)
'make': 2,
'ninja': 1,
+ 'xcode-ninja': [1, 65],
}[test.format]
# If a postbuild fails, all postbuilds should be re-run on the next build.
- # However, even if the first postbuild fails the other postbuilds are still
- # executed.
+ # In Xcode 3, even if the first postbuild fails the other postbuilds were
+ # still executed. In Xcode 4, postbuilds are stopped after the first
+ # failing postbuild. This test checks for the Xcode 4 behavior.
+ # Ignore this test on Xcode 3.
+ import subprocess
+ job = subprocess.Popen(['xcodebuild', '-version'],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+ out, err = job.communicate()
+ if job.returncode != 0:
+ print out
+ raise Exception('Error %d running xcodebuild' % job.returncode)
+ if out.startswith('Xcode 3.'):
+ test.pass_test()
# Non-bundles
test.build('test.gyp', 'nonbundle', chdir='postbuild-fail',
status=build_error_code)
- test.built_file_must_exist('static_touch',
- chdir='postbuild-fail')
+ test.built_file_must_not_exist('static_touch',
+ chdir='postbuild-fail')
# Check for non-up-to-date-ness by checking if building again produces an
# error.
test.build('test.gyp', 'nonbundle', chdir='postbuild-fail',
status=build_error_code)
# Bundles
test.build('test.gyp', 'bundle', chdir='postbuild-fail',
status=build_error_code)
- test.built_file_must_exist('dynamic_touch',
- chdir='postbuild-fail')
+ test.built_file_must_not_exist('dynamic_touch',
+ chdir='postbuild-fail')
# Check for non-up-to-date-ness by checking if building again produces an
# error.
test.build('test.gyp', 'bundle', chdir='postbuild-fail',
status=build_error_code)
test.pass_test()
rename from media/webrtc/trunk/tools/gyp/test/mac/gyptest-postbuild-static-library.gyp
rename to media/webrtc/trunk/tools/gyp/test/mac/gyptest-postbuild-static-library.py
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-prefixheader.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-prefixheader.py
@@ -10,10 +10,11 @@ Verifies that GCC_PREFIX_HEADER works.
import TestGyp
import sys
if sys.platform == 'darwin':
test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
test.run_gyp('test.gyp', chdir='prefixheader')
+
test.build('test.gyp', test.ALL, chdir='prefixheader')
test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-rebuild.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-rebuild.py
@@ -8,16 +8,19 @@
Verifies that app bundles are rebuilt correctly.
"""
import TestGyp
import sys
if sys.platform == 'darwin':
+ print "This test is currently disabled: https://crbug.com/483696."
+ sys.exit(0)
+
test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
CHDIR = 'rebuild'
test.run_gyp('test.gyp', chdir=CHDIR)
test.build('test.gyp', 'test_app', chdir=CHDIR)
# Touch a source file, rebuild, and check that the app target is up-to-date.
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-rpath.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-rpath.py
@@ -15,35 +15,36 @@ import re
import subprocess
import sys
if sys.platform == 'darwin':
test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
CHDIR = 'rpath'
test.run_gyp('test.gyp', chdir=CHDIR)
+
test.build('test.gyp', test.ALL, chdir=CHDIR)
def GetRpaths(p):
p = test.built_file_path(p, chdir=CHDIR)
r = re.compile(r'cmd LC_RPATH.*?path (.*?) \(offset \d+\)', re.DOTALL)
proc = subprocess.Popen(['otool', '-l', p], stdout=subprocess.PIPE)
o = proc.communicate()[0]
assert not proc.returncode
return r.findall(o)
- if (GetRpaths('libdefault_rpath.dylib') != []):
+ if GetRpaths('libdefault_rpath.dylib') != []:
test.fail_test()
- if (GetRpaths('libexplicit_rpath.dylib') != ['@executable_path/.']):
+ if GetRpaths('libexplicit_rpath.dylib') != ['@executable_path/.']:
test.fail_test()
if (GetRpaths('libexplicit_rpaths_escaped.dylib') !=
['First rpath', 'Second rpath']):
test.fail_test()
- if (GetRpaths('My Framework.framework/My Framework') != ['@loader_path/.']):
+ if GetRpaths('My Framework.framework/My Framework') != ['@loader_path/.']:
test.fail_test()
- if (GetRpaths('executable') != ['@executable_path/.']):
+ if GetRpaths('executable') != ['@executable_path/.']:
test.fail_test()
test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-sdkroot.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-sdkroot.py
@@ -5,16 +5,50 @@
# found in the LICENSE file.
"""
Verifies that setting SDKROOT works.
"""
import TestGyp
+import os
+import subprocess
import sys
+
if sys.platform == 'darwin':
+ print "This test is currently disabled: https://crbug.com/483696."
+ sys.exit(0)
+
test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
- test.run_gyp('test.gyp', chdir='sdkroot')
+ def GetSDKPath(sdk):
+ """Return SDKROOT if the SDK version |sdk| is installed or empty string."""
+ DEVNULL = open(os.devnull, 'wb')
+ try:
+ proc = subprocess.Popen(
+ ['xcodebuild', '-version', '-sdk', 'macosx' + sdk, 'Path'],
+ stdout=subprocess.PIPE, stderr=DEVNULL)
+ return proc.communicate()[0].rstrip('\n')
+ finally:
+ DEVNULL.close()
+
+ def SelectSDK():
+ """Select the oldest SDK installed (greater than 10.6)."""
+ for sdk in ['10.6', '10.7', '10.8', '10.9']:
+ path = GetSDKPath(sdk)
+ if path:
+ return True, sdk, path
+ return False, '', ''
+
+ # Make sure this works on the bots, which only have the 10.6 sdk, and on
+ # dev machines which usually don't have the 10.6 sdk.
+ sdk_found, sdk, sdk_path = SelectSDK()
+ if not sdk_found:
+ test.fail_test()
+
+ test.write('sdkroot/test.gyp', test.read('sdkroot/test.gyp') % sdk)
+
+ test.run_gyp('test.gyp', '-D', 'sdk_path=%s' % sdk_path,
+ chdir='sdkroot')
test.build('test.gyp', test.ALL, chdir='sdkroot')
test.pass_test()
deleted file mode 100644
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-sourceless-module.gyp
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/usr/bin/env python
-
-# Copyright (c) 2012 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.
-
-"""
-Verifies that bundles that have no 'sources' (pure resource containers) work.
-"""
-
-import TestGyp
-
-import sys
-
-if sys.platform == 'darwin':
- test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
-
- test.run_gyp('test.gyp', chdir='sourceless-module')
-
- # Just needs to build without errors.
- test.build('test.gyp', 'empty_bundle', chdir='sourceless-module')
- test.built_file_must_not_exist(
- 'empty_bundle.bundle', chdir='sourceless-module')
-
- # Needs to build, and contain a resource.
- test.build('test.gyp', 'resource_bundle', chdir='sourceless-module')
-
- test.built_file_must_exist(
- 'resource_bundle.bundle/Contents/Resources/foo.manifest',
- chdir='sourceless-module')
- test.built_file_must_not_exist(
- 'resource_bundle.bundle/Contents/MacOS/resource_bundle',
- chdir='sourceless-module')
-
- # Needs to build and cause the bundle to be built.
- test.build(
- 'test.gyp', 'dependent_on_resource_bundle', chdir='sourceless-module')
-
- test.built_file_must_exist(
- 'resource_bundle.bundle/Contents/Resources/foo.manifest',
- chdir='sourceless-module')
- test.built_file_must_not_exist(
- 'resource_bundle.bundle/Contents/MacOS/resource_bundle',
- chdir='sourceless-module')
-
- test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-sourceless-module.py
@@ -0,0 +1,75 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 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.
+
+"""
+Verifies that bundles that have no 'sources' (pure resource containers) work.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'darwin':
+ print "This test is currently disabled: https://crbug.com/483696."
+ sys.exit(0)
+
+ test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
+
+ test.run_gyp('test.gyp', chdir='sourceless-module')
+
+ # Just needs to build without errors.
+ test.build('test.gyp', 'empty_bundle', chdir='sourceless-module')
+ test.built_file_must_not_exist(
+ 'empty_bundle.bundle', chdir='sourceless-module')
+
+ # Needs to build, and contain a resource.
+ test.build('test.gyp', 'resource_bundle', chdir='sourceless-module')
+
+ test.built_file_must_exist(
+ 'resource_bundle.bundle/Contents/Resources/foo.manifest',
+ chdir='sourceless-module')
+ test.built_file_must_not_exist(
+ 'resource_bundle.bundle/Contents/MacOS/resource_bundle',
+ chdir='sourceless-module')
+
+ # Build an app containing an actionless bundle.
+ test.build(
+ 'test.gyp',
+ 'bundle_dependent_on_resource_bundle_no_actions',
+ chdir='sourceless-module')
+
+ test.built_file_must_exist(
+ 'bundle_dependent_on_resource_bundle_no_actions.app/Contents/Resources/'
+ 'mac_resource_bundle_no_actions.bundle/Contents/Resources/empty.txt',
+ chdir='sourceless-module')
+
+ # Needs to build and cause the bundle to be built.
+ test.build(
+ 'test.gyp', 'dependent_on_resource_bundle', chdir='sourceless-module')
+
+ test.built_file_must_exist(
+ 'resource_bundle.bundle/Contents/Resources/foo.manifest',
+ chdir='sourceless-module')
+ test.built_file_must_not_exist(
+ 'resource_bundle.bundle/Contents/MacOS/resource_bundle',
+ chdir='sourceless-module')
+
+ # TODO(thakis): shared_libraries that have no sources but depend on static
+ # libraries currently only work with the ninja generator. This is used by
+ # chrome/mac's components build.
+ if test.format == 'ninja':
+ # Check that an executable depending on a resource framework links fine too.
+ test.build(
+ 'test.gyp', 'dependent_on_resource_framework', chdir='sourceless-module')
+
+ test.built_file_must_exist(
+ 'resource_framework.framework/Resources/foo.manifest',
+ chdir='sourceless-module')
+ test.built_file_must_exist(
+ 'resource_framework.framework/resource_framework',
+ chdir='sourceless-module')
+
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-strip-default.py
@@ -0,0 +1,95 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 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.
+
+"""
+Verifies that the default STRIP_STYLEs match between different generators.
+"""
+
+import TestGyp
+
+import re
+import subprocess
+import sys
+import time
+
+if sys.platform == 'darwin':
+ test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
+
+ CHDIR='strip'
+ test.run_gyp('test-defaults.gyp', chdir=CHDIR)
+
+ test.build('test-defaults.gyp', test.ALL, chdir=CHDIR)
+
+ # Lightweight check if stripping was done.
+ def OutPath(s):
+ return test.built_file_path(s, chdir=CHDIR)
+
+ def CheckNsyms(p, o_expected):
+ proc = subprocess.Popen(['nm', '-aU', p], stdout=subprocess.PIPE)
+ o = proc.communicate()[0]
+
+ # Filter out mysterious "00 0000 OPT radr://5614542" symbol which
+ # is apparently only printed on the bots (older toolchain?).
+ # Yes, "radr", not "rdar".
+ o = ''.join(filter(lambda s: 'radr://5614542' not in s, o.splitlines(True)))
+
+ o = o.replace('A', 'T')
+ o = re.sub(r'^[a-fA-F0-9]+', 'XXXXXXXX', o, flags=re.MULTILINE)
+ assert not proc.returncode
+ if o != o_expected:
+ print 'Stripping: Expected symbols """\n%s""", got """\n%s"""' % (
+ o_expected, o)
+ test.fail_test()
+
+ CheckNsyms(OutPath('libsingle_dylib.dylib'),
+"""\
+XXXXXXXX S _ci
+XXXXXXXX S _i
+XXXXXXXX T _the_function
+XXXXXXXX t _the_hidden_function
+XXXXXXXX T _the_used_function
+XXXXXXXX T _the_visible_function
+""")
+ CheckNsyms(OutPath('single_so.so'),
+"""\
+XXXXXXXX S _ci
+XXXXXXXX S _i
+XXXXXXXX T _the_function
+XXXXXXXX t _the_hidden_function
+XXXXXXXX T _the_used_function
+XXXXXXXX T _the_visible_function
+""")
+ CheckNsyms(OutPath('single_exe'),
+"""\
+XXXXXXXX T __mh_execute_header
+""")
+
+ CheckNsyms(test.built_file_path(
+ 'bundle_dylib.framework/Versions/A/bundle_dylib', chdir=CHDIR),
+"""\
+XXXXXXXX S _ci
+XXXXXXXX S _i
+XXXXXXXX T _the_function
+XXXXXXXX t _the_hidden_function
+XXXXXXXX T _the_used_function
+XXXXXXXX T _the_visible_function
+""")
+ CheckNsyms(test.built_file_path(
+ 'bundle_so.bundle/Contents/MacOS/bundle_so', chdir=CHDIR),
+"""\
+XXXXXXXX S _ci
+XXXXXXXX S _i
+XXXXXXXX T _the_function
+XXXXXXXX T _the_used_function
+XXXXXXXX T _the_visible_function
+""")
+ CheckNsyms(test.built_file_path(
+ 'bundle_exe.app/Contents/MacOS/bundle_exe', chdir=CHDIR),
+"""\
+XXXXXXXX T __mh_execute_header
+""")
+
+ test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-strip.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-strip.py
@@ -4,16 +4,17 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""
Verifies that stripping works.
"""
import TestGyp
+import TestMac
import re
import subprocess
import sys
import time
if sys.platform == 'darwin':
test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
@@ -23,31 +24,38 @@ if sys.platform == 'darwin':
test.build('test.gyp', test.ALL, chdir='strip')
# Lightweight check if stripping was done.
def OutPath(s):
return test.built_file_path(s, type=test.SHARED_LIB, chdir='strip')
def CheckNsyms(p, n_expected):
r = re.compile(r'nsyms\s+(\d+)')
- proc = subprocess.Popen(['otool', '-l', p], stdout=subprocess.PIPE)
- o = proc.communicate()[0]
- assert not proc.returncode
+ o = subprocess.check_output(['otool', '-l', p])
m = r.search(o)
n = int(m.group(1))
if n != n_expected:
print 'Stripping: Expected %d symbols, got %d' % (n_expected, n)
test.fail_test()
+ # Starting with Xcode 5.0, clang adds an additional symbols to the compiled
+ # file when using a relative path to the input file. So when using ninja
+ # with Xcode 5.0 or higher, take this additional symbol into consideration
+ # for unstripped builds (it is stripped by all strip commands).
+ expected_extra_symbol_count = 0
+ if test.format in ['ninja', 'xcode-ninja'] \
+ and TestMac.Xcode.Version() >= '0500':
+ expected_extra_symbol_count = 1
+
# The actual numbers here are not interesting, they just need to be the same
# in both the xcode and the make build.
- CheckNsyms(OutPath('no_postprocess'), 11)
- CheckNsyms(OutPath('no_strip'), 11)
+ CheckNsyms(OutPath('no_postprocess'), 29 + expected_extra_symbol_count)
+ CheckNsyms(OutPath('no_strip'), 29 + expected_extra_symbol_count)
CheckNsyms(OutPath('strip_all'), 0)
- CheckNsyms(OutPath('strip_nonglobal'), 2)
- CheckNsyms(OutPath('strip_debugging'), 3)
+ CheckNsyms(OutPath('strip_nonglobal'), 6)
+ CheckNsyms(OutPath('strip_debugging'), 7)
CheckNsyms(OutPath('strip_all_custom_flags'), 0)
CheckNsyms(test.built_file_path(
'strip_all_bundle.framework/Versions/A/strip_all_bundle', chdir='strip'),
0)
- CheckNsyms(OutPath('strip_save'), 3)
+ CheckNsyms(OutPath('strip_save'), 7)
test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-swift-library.py
@@ -0,0 +1,65 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 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.
+
+"""
+Verifies that a swift framework builds correctly.
+"""
+
+import TestGyp
+import TestMac
+
+import collections
+import sys
+import subprocess
+
+if sys.platform == 'darwin':
+ print "This test is currently disabled: https://crbug.com/483696."
+ sys.exit(0)
+
+ test = TestGyp.TestGyp(formats=['xcode'])
+
+ # Ensures that the given symbol is present in the given file, by running nm.
+ def CheckHasSymbolName(path, symbol):
+ output = subprocess.check_output(['nm', '-j', path])
+ idx = output.find(symbol)
+ if idx == -1:
+ print 'Swift: Could not find symobl: %s' % symbol
+ test.fail_test()
+
+ test_cases = []
+
+ # Run this for iOS on XCode 6.0 or greater
+ if TestMac.Xcode.Version() >= '0600':
+ test_cases.append(('Default', 'iphoneos'))
+ test_cases.append(('Default', 'iphonesimulator'))
+
+ # Run it for Mac on XCode 6.1 or greater
+ if TestMac.Xcode.Version() >= '0610':
+ test_cases.append(('Default', None))
+
+ # Generate the project.
+ test.run_gyp('test.gyp', chdir='swift-library')
+
+ # Build and verify for each configuration.
+ for configuration, sdk in test_cases:
+ kwds = collections.defaultdict(list)
+ if test.format == 'xcode':
+ if sdk is not None:
+ kwds['arguments'].extend(['-sdk', sdk])
+
+ test.set_configuration(configuration)
+ test.build('test.gyp', 'SwiftFramework', chdir='swift-library', **kwds)
+
+ filename = 'SwiftFramework.framework/SwiftFramework'
+ result_file = test.built_file_path(filename, chdir='swift-library')
+
+ test.must_exist(result_file)
+
+ # Check to make sure that our swift class (GypSwiftTest) is present in the
+ # built binary
+ CheckHasSymbolName(result_file, "C14SwiftFramework12GypSwiftTest")
+
+ test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-type-envvars.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-type-envvars.py
@@ -10,15 +10,17 @@ Test that MACH_O_TYPE etc are set correc
import TestGyp
import sys
if sys.platform == 'darwin':
test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
- test.run_gyp('test.gyp', chdir='type_envvars')
+ test.run_gyp('test.gyp',
+ '-G', 'xcode_ninja_target_pattern=^(?!nonbundle_none).*$',
+ chdir='type_envvars')
test.build('test.gyp', test.ALL, chdir='type_envvars')
# The actual test is done by postbuild scripts during |test.build()|.
test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-unicode-settings.py
@@ -0,0 +1,20 @@
+#!/usr/bin/env python
+
+# Copyright 2013 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.
+
+"""
+Verifies that unicode strings in 'xcode_settings' work.
+Also checks that ASCII control characters are escaped properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'darwin':
+ test = TestGyp.TestGyp(formats=['xcode'])
+ test.run_gyp('test.gyp', chdir='unicode-settings')
+ test.build('test.gyp', test.ALL, chdir='unicode-settings')
+ test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-xcode-env-order.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-xcode-env-order.py
@@ -4,20 +4,25 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""
Verifies that dependent Xcode settings are processed correctly.
"""
import TestGyp
+import TestMac
+import subprocess
import sys
if sys.platform == 'darwin':
+ print "This test is currently disabled: https://crbug.com/483696."
+ sys.exit(0)
+
test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
CHDIR = 'xcode-env-order'
INFO_PLIST_PATH = 'Test.app/Contents/Info.plist'
test.run_gyp('test.gyp', chdir=CHDIR)
test.build('test.gyp', test.ALL, chdir=CHDIR)
@@ -66,18 +71,23 @@ if sys.platform == 'darwin':
\t<string>D:/Source/Project/Test</string>''')
test.must_contain(info_plist, '''\
\t<key>BareProcessedKey2</key>
\t<string>/Source/Project/Test</string>''')
# NOTE: For bare variables, $PRODUCT_TYPE is not replaced! It _is_ replaced
# if it's not right at the start of the string (e.g. ':$PRODUCT_TYPE'), so
# this looks like an Xcode bug. This bug isn't emulated (yet?), so check this
# only for Xcode.
- if test.format == 'xcode':
+ if test.format == 'xcode' and TestMac.Xcode.Version() < '0500':
test.must_contain(info_plist, '''\
\t<key>BareProcessedKey3</key>
\t<string>$PRODUCT_TYPE:D:/Source/Project/Test</string>''')
+ else:
+ # The bug has been fixed by Xcode version 5.0.0.
+ test.must_contain(info_plist, '''\
+\t<key>BareProcessedKey3</key>
+\t<string>com.apple.product-type.application:D:/Source/Project/Test</string>''')
test.must_contain(info_plist, '''\
\t<key>MixedProcessedKey</key>
\t<string>/Source/Project:Test:mh_execute</string>''')
test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-xcode-gcc-clang.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 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.
+
+"""
+Verifies that xcode-style GCC_... settings that require clang are handled
+properly.
+"""
+
+import TestGyp
+
+import os
+import sys
+
+if sys.platform == 'darwin':
+ test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
+
+ CHDIR = 'xcode-gcc'
+ test.run_gyp('test-clang.gyp', chdir=CHDIR)
+
+ test.build('test-clang.gyp', 'aliasing_yes', chdir=CHDIR)
+ test.run_built_executable('aliasing_yes', chdir=CHDIR, stdout="1\n")
+ test.build('test-clang.gyp', 'aliasing_no', chdir=CHDIR)
+ test.run_built_executable('aliasing_no', chdir=CHDIR, stdout="0\n")
+
+ # The default behavior changed: strict aliasing used to be off, now it's on
+ # by default. The important part is that this is identical for all generators
+ # (which it is). TODO(thakis): Enable this once the bots have a newer Xcode.
+ #test.build('test-clang.gyp', 'aliasing_default', chdir=CHDIR)
+ #test.run_built_executable('aliasing_default', chdir=CHDIR, stdout="1\n")
+ # For now, just check the generated ninja file:
+ if test.format == 'ninja':
+ contents = open(test.built_file_path('obj/aliasing_default.ninja',
+ chdir=CHDIR)).read()
+ if 'strict-aliasing' in contents:
+ test.fail_test()
+
+ test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-xcode-gcc.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-xcode-gcc.py
@@ -5,34 +5,54 @@
# found in the LICENSE file.
"""
Verifies that xcode-style GCC_... settings are handled properly.
"""
import TestGyp
+import os
+import subprocess
import sys
def IgnoreOutput(string, expected_string):
return True
+def CompilerVersion(compiler):
+ stdout = subprocess.check_output([compiler, '-v'], stderr=subprocess.STDOUT)
+ return stdout.rstrip('\n')
+
+def CompilerSupportsWarnAboutInvalidOffsetOfMacro(test):
+ # "clang" does not support the "-Winvalid-offsetof" flag, and silently
+ # ignore it. Starting with Xcode 5.0.0, "gcc" is just a "clang" binary with
+ # some hard-coded include path hack, so use the output of "-v" to detect if
+ # the compiler supports the flag or not.
+ return 'clang' not in CompilerVersion('/usr/bin/cc')
+
if sys.platform == 'darwin':
test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
+ if test.format == 'xcode-ninja':
+ test.skip_test()
+
CHDIR = 'xcode-gcc'
test.run_gyp('test.gyp', chdir=CHDIR)
# List of targets that'll pass. It expects targets of the same name with
# '-fail' appended that'll fail to build.
targets = [
- 'warn_about_invalid_offsetof_macro',
'warn_about_missing_newline',
]
+ # clang doesn't warn on invalid offsetofs, it silently ignores
+ # -Wno-invalid-offsetof.
+ if CompilerSupportsWarnAboutInvalidOffsetOfMacro(test):
+ targets.append('warn_about_invalid_offsetof_macro')
+
for target in targets:
test.build('test.gyp', target, chdir=CHDIR)
test.built_file_must_exist(target, chdir=CHDIR)
fail_target = target + '-fail'
test.build('test.gyp', fail_target, chdir=CHDIR, status=None,
stderr=None, match=IgnoreOutput)
test.built_file_must_not_exist(fail_target, chdir=CHDIR)
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-xcode-support-actions.py
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 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.
+
+"""
+Verifies that support actions are properly created.
+"""
+
+import TestGyp
+
+import os
+import subprocess
+import sys
+
+if sys.platform == 'darwin':
+ test = TestGyp.TestGyp(formats=['xcode'])
+
+ CHDIR = 'xcode-support-actions'
+
+ test.run_gyp('test.gyp', '-Gsupport_target_suffix=_customsuffix', chdir=CHDIR)
+ test.build('test.gyp', target='target_customsuffix', chdir=CHDIR)
+
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-xctest.py
@@ -0,0 +1,38 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 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.
+
+"""
+Verifies that xctest targets are correctly configured.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'darwin':
+ test = TestGyp.TestGyp(formats=['xcode'])
+
+ # Ignore this test if Xcode 5 is not installed
+ import subprocess
+ job = subprocess.Popen(['xcodebuild', '-version'],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+ out, err = job.communicate()
+ if job.returncode != 0:
+ raise Exception('Error %d running xcodebuild' % job.returncode)
+ xcode_version, build_number = out.splitlines()
+ # Convert the version string from 'Xcode 5.0' to ['5','0'].
+ xcode_version = xcode_version.split()[-1].split('.')
+ if xcode_version < ['5']:
+ test.pass_test()
+
+ CHDIR = 'xctest'
+ test.run_gyp('test.gyp', chdir=CHDIR)
+ test.build('test.gyp', chdir=CHDIR, arguments=['-scheme', 'classes', 'test'])
+
+ test.built_file_must_match('tests.xctest/Contents/Resources/resource.txt',
+ 'foo\n', chdir=CHDIR)
+ test.pass_test()
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-xcuitest.py
@@ -0,0 +1,39 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 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.
+
+"""
+Verifies that xcuitest targets are correctly configured.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'darwin':
+ test = TestGyp.TestGyp(formats=['xcode'])
+
+ # Ignore this test if Xcode 5 is not installed
+ import subprocess
+ job = subprocess.Popen(['xcodebuild', '-version'],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+ out, err = job.communicate()
+ if job.returncode != 0:
+ raise Exception('Error %d running xcodebuild' % job.returncode)
+ xcode_version, build_number = out.splitlines()
+ # Convert the version string from 'Xcode 5.0' to ['5','0'].
+ xcode_version = xcode_version.split()[-1].split('.')
+ if xcode_version < ['7']:
+ test.pass_test()
+
+ CHDIR = 'xcuitest'
+ test.run_gyp('test.gyp', chdir=CHDIR)
+ test.build('test.gyp', chdir=CHDIR, arguments=[
+ '-target', 'tests',
+ '-sdk', 'iphonesimulator',
+ ])
+
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/identical-name/proxy/proxy.cc
@@ -0,0 +1,2 @@
+// Empty file
+
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/identical-name/proxy/proxy.gyp
@@ -0,0 +1,9 @@
+{
+ 'includes': ['../test.gypi'],
+ 'targets': [{
+ 'target_name': 'testlib',
+ 'type': 'none',
+ 'dependencies': ['testlib/testlib.gyp:testlib'],
+ 'sources': ['proxy.cc'],
+ }],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/identical-name/proxy/testlib/testlib.cc
@@ -0,0 +1,2 @@
+// Empty file
+
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/identical-name/proxy/testlib/testlib.gyp
@@ -0,0 +1,8 @@
+{
+ 'includes': ['../../test.gypi'],
+ 'targets': [{
+ 'target_name': 'testlib',
+ 'type': 'static_library',
+ 'sources': ['testlib.cc'],
+ }],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/identical-name/test-should-fail.gyp
@@ -0,0 +1,10 @@
+{
+ 'targets': [{
+ 'target_name': 'test',
+ 'type': 'executable',
+ 'dependencies': [
+ 'testlib/testlib.gyp:proxy',
+ 'proxy/proxy.gyp:testlib',
+ ],
+ }],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/identical-name/test.gyp
@@ -0,0 +1,11 @@
+{
+ 'includes': ['test.gypi'],
+ 'targets': [{
+ 'target_name': 'test',
+ 'type': 'executable',
+ 'dependencies': [
+ 'testlib/testlib.gyp:proxy',
+ 'proxy/proxy.gyp:testlib',
+ ],
+ }],
+}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/identical-name/test.gypi
@@ -0,0 +1,7 @@
+{
+ 'target_defaults': {
+ 'xcode_settings': {
+ 'SYMROOT': '<(DEPTH)/$SRCROOT/',
+ },
+ },
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/identical-name/testlib/main.cc
@@ -0,0 +1,3 @@
+int main(int argc, char **argv) {
+ return 0;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/identical-name/testlib/testlib.gyp
@@ -0,0 +1,14 @@
+{
+ 'includes': ['../test.gypi'],
+ 'targets': [{
+ 'target_name': 'proxy',
+ 'type': 'static_library',
+ 'sources': ['void.cc'],
+ 'dependencies': ['testlib'],
+ 'export_dependent_settings': ['testlib'],
+ }, {
+ 'target_name': 'testlib',
+ 'type': 'static_library',
+ 'sources': ['main.cc'],
+ }],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/identical-name/testlib/void.cc
@@ -0,0 +1,2 @@
+// Empty file
+
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/kext/GypKext/GypKext-Info.plist
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>BuildMachineOSBuild</key>
+ <string>Doesn't matter, will be overwritten</string>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIconFile</key>
+ <string></string>
+ <key>CFBundleIdentifier</key>
+ <string>com.google.${PRODUCT_NAME:rfc1034identifier}</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>KEXT</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>ause</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+ <key>LSMinimumSystemVersion</key>
+ <string>${MACOSX_DEPLOYMENT_TARGET}</string>
+ <key>OSBundleLibraries</key>
+ <dict>
+ <key>com.apple.kpi.libkern</key>
+ <string>10.0</string>
+ </dict>
+</dict>
+</plist>
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/kext/GypKext/GypKext.c
@@ -0,0 +1,16 @@
+// Copyright (c) 2015 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 <sys/systm.h>
+#include <mach/mach_types.h>
+
+kern_return_t GypKext_start(kmod_info_t* ki, void* d) {
+ printf("GypKext has started.\n");
+ return KERN_SUCCESS;
+}
+
+kern_return_t GypKext_stop(kmod_info_t* ki, void* d) {
+ printf("GypKext has stopped.\n");
+ return KERN_SUCCESS;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/kext/kext.gyp
@@ -0,0 +1,18 @@
+# Copyright (c) 2015 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': 'gypkext',
+ 'product_name': 'GypKext',
+ 'type': 'mac_kernel_extension',
+ 'sources': [
+ 'GypKext/GypKext.c',
+ ],
+ 'xcode_settings': {
+ 'INFOPLIST_FILE': 'GypKext/GypKext-Info.plist',
+ },
+ },
+ ],
+}
--- a/media/webrtc/trunk/tools/gyp/test/mac/libraries/subdir/test.gyp
+++ b/media/webrtc/trunk/tools/gyp/test/mac/libraries/subdir/test.gyp
@@ -8,17 +8,16 @@
'target_name': 'libraries-test',
'type': 'executable',
'sources': [
'hello.cc',
],
'link_settings': {
'libraries': [
'libcrypto.dylib',
- 'libfl.a',
],
},
},
{
# This creates a static library and puts it in a nonstandard location for
# libraries-search-path-test.
'target_name': 'mylib',
'type': 'static_library',
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/libtool-zero/mylib.c
@@ -0,0 +1,7 @@
+// Copyright (c) 2014 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 my_foo(int x) {
+ return x + 1;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/libtool-zero/test.gyp
@@ -0,0 +1,18 @@
+# Copyright (c) 2014 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': 'mylib',
+ 'type': 'static_library',
+ 'sources': [
+ 'mylib.c',
+ ],
+ 'xcode_settings': {
+ 'ARCHS': [ 'i386', 'x86_64' ],
+ },
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/loadable-module-bundle-product-extension/src.cc
@@ -0,0 +1,7 @@
+// Copyright (c) 2014 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 test() {
+ return 1337;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/loadable-module-bundle-product-extension/test.gyp
@@ -0,0 +1,24 @@
+# Copyright (c) 2014 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': 'test',
+ 'type': 'none',
+ 'dependencies': ['child_one', 'child_two'],
+ }, {
+ 'target_name': 'child_one',
+ 'product_name': 'Collide',
+ 'product_extension': 'bar',
+ 'sources': ['src.cc'],
+ 'type': 'loadable_module',
+ 'mac_bundle': 1,
+ }, {
+ 'target_name': 'child_two',
+ 'product_name': 'Collide',
+ 'product_extension': 'foo',
+ 'sources': ['src.cc'],
+ 'type': 'loadable_module',
+ 'mac_bundle': 1,
+ }],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/lto/asmfile.S
@@ -0,0 +1,2 @@
+.globl _asfun
+ret
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/lto/ccfile.cc
@@ -0,0 +1,1 @@
+void ccfun() {}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/lto/cfile.c
@@ -0,0 +1,1 @@
+void cfun() {}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/lto/mfile.m
@@ -0,0 +1,1 @@
+void mfun() {}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/lto/mmfile.mm
@@ -0,0 +1,1 @@
+void mmfun() {}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/lto/test.gyp
@@ -0,0 +1,35 @@
+# Copyright (c) 2015 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': 'lto',
+ 'type': 'shared_library',
+ 'sources': [
+ 'cfile.c',
+ 'mfile.m',
+ 'ccfile.cc',
+ 'mmfile.mm',
+ 'asmfile.S',
+ ],
+ 'xcode_settings': {
+ 'LLVM_LTO': 'YES',
+ },
+ },
+ {
+ 'target_name': 'lto_static',
+ 'type': 'static_library',
+ 'sources': [
+ 'cfile.c',
+ 'mfile.m',
+ 'ccfile.cc',
+ 'mmfile.mm',
+ 'asmfile.S',
+ ],
+ 'xcode_settings': {
+ 'LLVM_LTO': 'YES',
+ },
+ },
+ ],
+}
--- a/media/webrtc/trunk/tools/gyp/test/mac/non-strs-flattened-to-env/test.gyp
+++ b/media/webrtc/trunk/tools/gyp/test/mac/non-strs-flattened-to-env/test.gyp
@@ -14,11 +14,14 @@
'MY_VAR': 'some expansion',
'OTHER_CFLAGS': [
# Just some (more than one) random flags.
'-fstack-protector-all',
'-fno-strict-aliasing',
'-DS="A Space"', # Would normally be in 'defines'
],
},
+ 'include_dirs': [
+ '$(SDKROOT)/usr/include/libxml2',
+ ],
},
],
}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/objc-arc/c-file.c
@@ -0,0 +1,6 @@
+#if __has_feature(objc_arc)
+#error "C files shouldn't be ARC'd!"
+#endif
+
+void c_fun() {}
+
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/objc-arc/cc-file.cc
@@ -0,0 +1,5 @@
+#if __has_feature(objc_arc)
+#error "C++ files shouldn't be ARC'd!"
+#endif
+
+void cc_fun() {}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/objc-arc/m-file-no-arc.m
@@ -0,0 +1,5 @@
+#if __has_feature(objc_arc)
+#error "ObjC files without CLANG_ENABLE_OBJC_ARC should not be ARC'd!"
+#endif
+
+void m_fun() {}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/objc-arc/m-file.m
@@ -0,0 +1,5 @@
+#if !__has_feature(objc_arc)
+#error "ObjC files with CLANG_ENABLE_OBJC_ARC should be ARC'd!"
+#endif
+
+void m_fun() {}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/objc-arc/mm-file-no-arc.mm
@@ -0,0 +1,5 @@
+#if __has_feature(objc_arc)
+#error "ObjC++ files without CLANG_ENABLE_OBJC_ARC should not be ARC'd!"
+#endif
+
+void mm_fun() {}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/objc-arc/mm-file.mm
@@ -0,0 +1,5 @@
+#if !__has_feature(objc_arc)
+#error "ObjC++ files with CLANG_ENABLE_OBJC_ARC should be ARC'd!"
+#endif
+
+void mm_fun() {}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/objc-arc/test.gyp
@@ -0,0 +1,45 @@
+# Copyright (c) 2013 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.
+{
+ 'make_global_settings': [
+ ['CC', '/usr/bin/clang'],
+ ['CXX', '/usr/bin/clang++'],
+ ],
+
+ 'targets': [
+ {
+ 'target_name': 'arc_enabled',
+ 'type': 'static_library',
+ 'sources': [
+ 'c-file.c',
+ 'cc-file.cc',
+ 'm-file.m',
+ 'mm-file.mm',
+ ],
+ 'xcode_settings': {
+ 'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0',
+ 'MACOSX_DEPLOYMENT_TARGET': '10.6',
+ 'ARCHS': [ 'x86_64' ], # For the non-fragile objc ABI.
+ 'CLANG_ENABLE_OBJC_ARC': 'YES',
+ },
+ },
+
+ {
+ 'target_name': 'arc_disabled',
+ 'type': 'static_library',
+ 'sources': [
+ 'c-file.c',
+ 'cc-file.cc',
+ 'm-file-no-arc.m',
+ 'mm-file-no-arc.mm',
+ ],
+ 'xcode_settings': {
+ 'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0',
+ 'MACOSX_DEPLOYMENT_TARGET': '10.6',
+ 'ARCHS': [ 'x86_64' ], # For the non-fragile objc ABI.
+ },
+ },
+ ],
+}
+
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/postbuild-copy-bundle/copied.txt
@@ -0,0 +1,1 @@
+old copied file
--- a/media/webrtc/trunk/tools/gyp/test/mac/postbuild-copy-bundle/test.gyp
+++ b/media/webrtc/trunk/tools/gyp/test/mac/postbuild-copy-bundle/test.gyp
@@ -10,16 +10,22 @@
'mac_bundle': 1,
'sources': [ 'empty.c', ],
'xcode_settings': {
'INFOPLIST_FILE': 'Framework-Info.plist',
},
'mac_bundle_resources': [
'resource_file.sb',
],
+ 'copies': [
+ {
+ 'destination': '<(PRODUCT_DIR)/$(CONTENTS_FOLDER_PATH)/Libraries',
+ 'files': [ 'copied.txt' ],
+ },
+ ],
},
{
'target_name': 'test_app',
'product_name': 'Test App',
'type': 'executable',
'mac_bundle': 1,
'dependencies': [
'test_bundle',
--- a/media/webrtc/trunk/tools/gyp/test/mac/postbuilds/test.gyp
+++ b/media/webrtc/trunk/tools/gyp/test/mac/postbuilds/test.gyp
@@ -78,10 +78,16 @@
'action': [
'cp',
'${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}',
'${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}_gyp_touch.dylib',
],
},
],
},
+ {
+ 'target_name': 'EmptyBundle',
+ 'product_extension': 'bundle',
+ 'type': 'executable',
+ 'mac_bundle': 1,
+ },
],
}
--- a/media/webrtc/trunk/tools/gyp/test/mac/sdkroot/test.gyp
+++ b/media/webrtc/trunk/tools/gyp/test/mac/sdkroot/test.gyp
@@ -3,17 +3,31 @@
# found in the LICENSE file.
{
'targets': [
{
'target_name': 'mytarget',
'type': 'executable',
'sources': [ 'file.cc', ],
'xcode_settings': {
- 'SDKROOT': 'macosx10.6',
+ 'SDKROOT': 'macosx%s',
+ },
+ 'postbuilds': [
+ {
+ 'postbuild_name': 'envtest',
+ 'action': [ './test_shorthand.sh', ],
+ },
+ ],
+ },
+ {
+ 'target_name': 'absolute',
+ 'type': 'executable',
+ 'sources': [ 'file.cc', ],
+ 'xcode_settings': {
+ 'SDKROOT': '<(sdk_path)',
},
'postbuilds': [
{
'postbuild_name': 'envtest',
'action': [ './test_shorthand.sh', ],
},
],
},
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/sdkroot/test_shorthand.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+# Copyright (c) 2012 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.
+
+set -e
+
+found=false
+for sdk in 10.6 10.7 10.8 10.9 ; do
+ if expected=$(xcodebuild -version -sdk macosx$sdk Path 2>/dev/null) ; then
+ found=true
+ break
+ fi
+done
+if ! $found ; then
+ echo >&2 "cannot find installed SDK"
+ exit 1
+fi
+
+test $SDKROOT = $expected
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/sourceless-module/empty.txt
@@ -0,0 +1,2 @@
+
+
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/sourceless-module/fun.c
@@ -0,0 +1,1 @@
+int f() { return 42; }
--- a/media/webrtc/trunk/tools/gyp/test/mac/sourceless-module/test.gyp
+++ b/media/webrtc/trunk/tools/gyp/test/mac/sourceless-module/test.gyp
@@ -29,11 +29,68 @@
{
'target_name': 'dependent_on_resource_bundle',
'type': 'executable',
'sources': [ 'empty.c' ],
'dependencies': [
'resource_bundle',
],
},
+
+ {
+ 'target_name': 'alib',
+ 'type': 'static_library',
+ 'sources': [ 'fun.c' ]
+ },
+ { # No sources, but depends on a static_library so must be linked.
+ 'target_name': 'resource_framework',
+ 'type': 'shared_library',
+ 'mac_bundle': 1,
+ 'dependencies': [
+ 'alib',
+ ],
+ 'actions': [
+ {
+ 'action_name': 'Add Resource',
+ 'inputs': [],
+ 'outputs': [
+ '<(INTERMEDIATE_DIR)/app_manifest/foo.manifest',
+ ],
+ 'action': [
+ 'touch', '<(INTERMEDIATE_DIR)/app_manifest/foo.manifest',
+ ],
+ 'process_outputs_as_mac_bundle_resources': 1,
+ },
+ ],
+ },
+ {
+ 'target_name': 'dependent_on_resource_framework',
+ 'type': 'executable',
+ 'sources': [ 'empty.c' ],
+ 'dependencies': [
+ 'resource_framework',
+ ],
+ },
+
+ { # No actions, but still have resources.
+ 'target_name': 'mac_resource_bundle_no_actions',
+ 'product_extension': 'bundle',
+ 'type': 'executable',
+ 'mac_bundle': 1,
+ 'mac_bundle_resources': [
+ 'empty.txt',
+ ],
+ },
+ {
+ 'target_name': 'bundle_dependent_on_resource_bundle_no_actions',
+ 'type': 'executable',
+ 'mac_bundle': 1,
+ 'sources': [ 'empty.c' ],
+ 'dependencies': [
+ 'mac_resource_bundle_no_actions',
+ ],
+ 'mac_bundle_resources': [
+ '<(PRODUCT_DIR)/mac_resource_bundle_no_actions.bundle',
+ ],
+ },
],
}
--- a/media/webrtc/trunk/tools/gyp/test/mac/strip/file.c
+++ b/media/webrtc/trunk/tools/gyp/test/mac/strip/file.c
@@ -1,9 +1,22 @@
// 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.
static void the_static_function() {}
+__attribute__((used)) void the_used_function() {}
+
+__attribute__((visibility("hidden"))) __attribute__((used))
+ void the_hidden_function() {}
+__attribute__((visibility("default"))) __attribute__((used))
+ void the_visible_function() {}
+
+extern const int eci;
+__attribute__((used)) int i;
+__attribute__((used)) const int ci = 34623;
void the_function() {
the_static_function();
+ the_used_function();
+ the_hidden_function();
+ the_visible_function();
}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/strip/main.c
@@ -0,0 +1,25 @@
+// Copyright (c) 2013 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.
+
+static void the_static_function() {}
+__attribute__((used)) void the_used_function() {}
+
+__attribute__((visibility("hidden"))) __attribute__((used))
+void the_hidden_function() {}
+__attribute__((visibility("default"))) __attribute__((used))
+void the_visible_function() {}
+
+void the_function() {}
+
+extern const int eci;
+__attribute__((used)) int i;
+__attribute__((used)) const int ci = 34623;
+
+int main() {
+ the_function();
+ the_static_function();
+ the_used_function();
+ the_hidden_function();
+ the_visible_function();
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/strip/test-defaults.gyp
@@ -0,0 +1,51 @@
+# Copyright (c) 2013 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.
+{
+ 'make_global_settings': [
+ ['CC', '/usr/bin/clang'],
+ ],
+ 'target_defaults': {
+ 'xcode_settings': {
+ 'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0',
+ 'DEPLOYMENT_POSTPROCESSING': 'YES',
+ 'STRIP_INSTALLED_PRODUCT': 'YES',
+ },
+ },
+ 'targets': [
+ {
+ 'target_name': 'single_dylib',
+ 'type': 'shared_library',
+ 'sources': [ 'file.c', ],
+ },
+ {
+ 'target_name': 'single_so',
+ 'type': 'loadable_module',
+ 'sources': [ 'file.c', ],
+ },
+ {
+ 'target_name': 'single_exe',
+ 'type': 'executable',
+ 'sources': [ 'main.c', ],
+ },
+
+ {
+ 'target_name': 'bundle_dylib',
+ 'type': 'shared_library',
+ 'mac_bundle': '1',
+ 'sources': [ 'file.c', ],
+ },
+ {
+ 'target_name': 'bundle_so',
+ 'type': 'loadable_module',
+ 'mac_bundle': '1',
+ 'sources': [ 'file.c', ],
+ },
+ {
+ 'target_name': 'bundle_exe',
+ 'type': 'executable',
+ 'mac_bundle': '1',
+ 'sources': [ 'main.c', ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/swift-library/Info.plist
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIconFile</key>
+ <string></string>
+ <key>CFBundleIdentifier</key>
+ <string>com.yourcompany.${PRODUCT_NAME:identifier}</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>FMWK</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+ <key>NSPrincipalClass</key>
+ <string></string>
+</dict>
+</plist>
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/swift-library/file.swift
@@ -0,0 +1,9 @@
+import Foundation
+
+public class GypSwiftTest {
+ let myProperty = false
+
+ init() {
+ self.myProperty = true
+ }
+}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/swift-library/test.gyp
@@ -0,0 +1,21 @@
+# 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.
+{
+ 'targets': [
+ {
+ 'target_name': 'SwiftFramework',
+ 'product_name': 'SwiftFramework',
+ 'type': 'shared_library',
+ 'mac_bundle': 1,
+ 'xcode_settings': {
+ 'INFOPLIST_FILE': 'Info.plist',
+ 'CODE_SIGNING_REQUIRED': 'NO',
+ 'CONFIGURATION_BUILD_DIR':'build/Default',
+ },
+ 'sources': [
+ 'file.swift',
+ ],
+ },
+ ],
+}
--- a/media/webrtc/trunk/tools/gyp/test/mac/type_envvars/test_bundle_executable.sh
+++ b/media/webrtc/trunk/tools/gyp/test/mac/type_envvars/test_bundle_executable.sh
@@ -9,13 +9,22 @@ test $MACH_O_TYPE = mh_execute
test $PRODUCT_TYPE = com.apple.product-type.application
test "${PRODUCT_NAME}" = "My App"
test "${FULL_PRODUCT_NAME}" = "My App.app"
test "${EXECUTABLE_NAME}" = "My App"
test "${EXECUTABLE_PATH}" = "My App.app/Contents/MacOS/My App"
test "${WRAPPER_NAME}" = "My App.app"
+test "${CONTENTS_FOLDER_PATH}" = "My App.app/Contents"
+test "${EXECUTABLE_FOLDER_PATH}" = "My App.app/Contents/MacOS"
+test "${UNLOCALIZED_RESOURCES_FOLDER_PATH}" = "My App.app/Contents/Resources"
+test "${JAVA_FOLDER_PATH}" = "My App.app/Contents/Resources/Java"
+test "${FRAMEWORKS_FOLDER_PATH}" = "My App.app/Contents/Frameworks"
+test "${SHARED_FRAMEWORKS_FOLDER_PATH}" = "My App.app/Contents/SharedFrameworks"
+test "${SHARED_SUPPORT_FOLDER_PATH}" = "My App.app/Contents/SharedSupport"
+test "${PLUGINS_FOLDER_PATH}" = "My App.app/Contents/PlugIns"
+test "${XPCSERVICES_FOLDER_PATH}" = "My App.app/Contents/XPCServices"
+
[[ ! $DYLIB_INSTALL_NAME_BASE && ${DYLIB_INSTALL_NAME_BASE-_} ]]
[[ ! $LD_DYLIB_INSTALL_NAME && ${LD_DYLIB_INSTALL_NAME-_} ]]
-# Should be set, but empty.
-[[ ! $SDKROOT && ! ${SDKROOT-_} ]]
+"$(dirname "$0")/test_check_sdkroot.sh"
--- a/media/webrtc/trunk/tools/gyp/test/mac/type_envvars/test_bundle_loadable_module.sh
+++ b/media/webrtc/trunk/tools/gyp/test/mac/type_envvars/test_bundle_loadable_module.sh
@@ -10,13 +10,26 @@ test $PRODUCT_TYPE = com.apple.product-t
test $PRODUCT_NAME = bundle_loadable_module
test $FULL_PRODUCT_NAME = bundle_loadable_module.bundle
test $EXECUTABLE_NAME = bundle_loadable_module
test $EXECUTABLE_PATH = \
"bundle_loadable_module.bundle/Contents/MacOS/bundle_loadable_module"
test $WRAPPER_NAME = bundle_loadable_module.bundle
+test $CONTENTS_FOLDER_PATH = bundle_loadable_module.bundle/Contents
+test $EXECUTABLE_FOLDER_PATH = bundle_loadable_module.bundle/Contents/MacOS
+test $UNLOCALIZED_RESOURCES_FOLDER_PATH = \
+ bundle_loadable_module.bundle/Contents/Resources
+test $JAVA_FOLDER_PATH = bundle_loadable_module.bundle/Contents/Resources/Java
+test $FRAMEWORKS_FOLDER_PATH = bundle_loadable_module.bundle/Contents/Frameworks
+test $SHARED_FRAMEWORKS_FOLDER_PATH = \
+ bundle_loadable_module.bundle/Contents/SharedFrameworks
+test $SHARED_SUPPORT_FOLDER_PATH = \
+ bundle_loadable_module.bundle/Contents/SharedSupport
+test $PLUGINS_FOLDER_PATH = bundle_loadable_module.bundle/Contents/PlugIns
+test $XPCSERVICES_FOLDER_PATH = \
+ bundle_loadable_module.bundle/Contents/XPCServices
+
[[ ! $DYLIB_INSTALL_NAME_BASE && ${DYLIB_INSTALL_NAME_BASE-_} ]]
[[ ! $LD_DYLIB_INSTALL_NAME && ${LD_DYLIB_INSTALL_NAME-_} ]]
-# Should be set, but empty.
-[[ ! $SDKROOT && ! ${SDKROOT-_} ]]
+"$(dirname "$0")/test_check_sdkroot.sh"
--- a/media/webrtc/trunk/tools/gyp/test/mac/type_envvars/test_bundle_shared_library.sh
+++ b/media/webrtc/trunk/tools/gyp/test/mac/type_envvars/test_bundle_shared_library.sh
@@ -10,14 +10,29 @@ test $PRODUCT_TYPE = com.apple.product-t
test $PRODUCT_NAME = bundle_shared_library
test $FULL_PRODUCT_NAME = bundle_shared_library.framework
test $EXECUTABLE_NAME = bundle_shared_library
test $EXECUTABLE_PATH = \
"bundle_shared_library.framework/Versions/A/bundle_shared_library"
test $WRAPPER_NAME = bundle_shared_library.framework
+test $CONTENTS_FOLDER_PATH = bundle_shared_library.framework/Versions/A
+test $EXECUTABLE_FOLDER_PATH = bundle_shared_library.framework/Versions/A
+test $UNLOCALIZED_RESOURCES_FOLDER_PATH = \
+ bundle_shared_library.framework/Versions/A/Resources
+test $JAVA_FOLDER_PATH = \
+ bundle_shared_library.framework/Versions/A/Resources/Java
+test $FRAMEWORKS_FOLDER_PATH = \
+ bundle_shared_library.framework/Versions/A/Frameworks
+test $SHARED_FRAMEWORKS_FOLDER_PATH = \
+ bundle_shared_library.framework/Versions/A/SharedFrameworks
+test $SHARED_SUPPORT_FOLDER_PATH = \
+ bundle_shared_library.framework/Versions/A/Resources
+test $PLUGINS_FOLDER_PATH = bundle_shared_library.framework/Versions/A/PlugIns
+test $XPCSERVICES_FOLDER_PATH = \
+ bundle_shared_library.framework/Versions/A/XPCServices
+
test $DYLIB_INSTALL_NAME_BASE = "/Library/Frameworks"
test $LD_DYLIB_INSTALL_NAME = \
"/Library/Frameworks/bundle_shared_library.framework/Versions/A/bundle_shared_library"
-# Should be set, but empty.
-[[ ! $SDKROOT && ! ${SDKROOT-_} ]]
+"$(dirname "$0")/test_check_sdkroot.sh"
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/type_envvars/test_check_sdkroot.sh
@@ -0,0 +1,47 @@
+#!/bin/bash
+# Copyright (c) 2014 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.
+
+set -e
+
+# `xcodebuild -version` output looks like
+# Xcode 4.6.3
+# Build version 4H1503
+# or like
+# Xcode 4.2
+# Build version 4C199
+# or like
+# Xcode 3.2.6
+# Component versions: DevToolsCore-1809.0; DevToolsSupport-1806.0
+# BuildVersion: 10M2518
+# Convert that to '0463', '0420' and '0326' respectively.
+function xcodeversion() {
+ xcodebuild -version | awk '/Xcode ([0-9]+\.[0-9]+(\.[0-9]+)?)/ {
+ version = $2
+ gsub(/\./, "", version)
+ if (length(version) < 3) {
+ version = version "0"
+ }
+ if (length(version) < 4) {
+ version = "0" version
+ }
+ }
+ END { print version }'
+}
+
+# Returns true if |string1| is smaller than |string2|.
+# This function assumes that both strings represent Xcode version numbers
+# as returned by |xcodeversion|.
+function smaller() {
+ local min="$(echo -ne "${1}\n${2}\n" | sort -n | head -n1)"
+ test "${min}" != "${2}"
+}
+
+if [[ "$(xcodeversion)" < "0500" ]]; then
+ # Xcode version is older than 5.0, check that SDKROOT is set but empty.
+ [[ -z "${SDKROOT}" && -z "${SDKROOT-_}" ]]
+else
+ # Xcode version is newer than 5.0, check that SDKROOT is set.
+ [[ "${SDKROOT}" == "$(xcodebuild -version -sdk '' Path)" ]]
+fi
--- a/media/webrtc/trunk/tools/gyp/test/mac/type_envvars/test_nonbundle_executable.sh
+++ b/media/webrtc/trunk/tools/gyp/test/mac/type_envvars/test_nonbundle_executable.sh
@@ -1,22 +1,33 @@
#!/bin/bash
# Copyright (c) 2012 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.
set -e
+
# For some reason, Xcode doesn't set MACH_O_TYPE for non-bundle executables.
# Check for "not set", not just "empty":
[[ ! $MACH_O_TYPE && ${MACH_O_TYPE-_} ]]
test $PRODUCT_TYPE = com.apple.product-type.tool
test $PRODUCT_NAME = nonbundle_executable
test $FULL_PRODUCT_NAME = nonbundle_executable
test $EXECUTABLE_NAME = nonbundle_executable
test $EXECUTABLE_PATH = nonbundle_executable
[[ ! $WRAPPER_NAME && ${WRAPPER_NAME-_} ]]
+[[ ! $CONTENTS_FOLDER_PATH && ${CONTENTS_FOLDER_PATH-_} ]]
+[[ ! $EXECUTABLE_FOLDER_PATH && ${EXECUTABLE_FOLDER_PATH-_} ]]
+[[ ! $UNLOCALIZED_RESOURCES_FOLDER_PATH \
+ && ${UNLOCALIZED_RESOURCES_FOLDER_PATH-_} ]]
+[[ ! $JAVA_FOLDER_PATH && ${JAVA_FOLDER_PATH-_} ]]
+[[ ! $FRAMEWORKS_FOLDER_PATH && ${FRAMEWORKS_FOLDER_PATH-_} ]]
+[[ ! $SHARED_FRAMEWORKS_FOLDER_PATH && ${SHARED_FRAMEWORKS_FOLDER_PATH-_} ]]
+[[ ! $SHARED_SUPPORT_FOLDER_PATH && ${SHARED_SUPPORT_FOLDER_PATH-_} ]]
+[[ ! $PLUGINS_FOLDER_PATH && ${PLUGINS_FOLDER_PATH-_} ]]
+[[ ! $XPCSERVICES_FOLDER_PATH && ${XPCSERVICES_FOLDER_PATH-_} ]]
+
[[ ! $DYLIB_INSTALL_NAME_BASE && ${DYLIB_INSTALL_NAME_BASE-_} ]]
[[ ! $LD_DYLIB_INSTALL_NAME && ${LD_DYLIB_INSTALL_NAME-_} ]]
-# Should be set, but empty.
-[[ ! $SDKROOT && ! ${SDKROOT-_} ]]
+"$(dirname "$0")/test_check_sdkroot.sh"
--- a/media/webrtc/trunk/tools/gyp/test/mac/type_envvars/test_nonbundle_loadable_module.sh
+++ b/media/webrtc/trunk/tools/gyp/test/mac/type_envvars/test_nonbundle_loadable_module.sh
@@ -9,13 +9,23 @@ test $MACH_O_TYPE = mh_bundle
test $PRODUCT_TYPE = com.apple.product-type.library.dynamic
test $PRODUCT_NAME = nonbundle_loadable_module
test $FULL_PRODUCT_NAME = nonbundle_loadable_module.so
test $EXECUTABLE_NAME = nonbundle_loadable_module.so
test $EXECUTABLE_PATH = nonbundle_loadable_module.so
[[ ! $WRAPPER_NAME && ${WRAPPER_NAME-_} ]]
+[[ ! $CONTENTS_FOLDER_PATH && ${CONTENTS_FOLDER_PATH-_} ]]
+[[ ! $EXECUTABLE_FOLDER_PATH && ${EXECUTABLE_FOLDER_PATH-_} ]]
+[[ ! $UNLOCALIZED_RESOURCES_FOLDER_PATH \
+ && ${UNLOCALIZED_RESOURCES_FOLDER_PATH-_} ]]
+[[ ! $JAVA_FOLDER_PATH && ${JAVA_FOLDER_PATH-_} ]]
+[[ ! $FRAMEWORKS_FOLDER_PATH && ${FRAMEWORKS_FOLDER_PATH-_} ]]
+[[ ! $SHARED_FRAMEWORKS_FOLDER_PATH && ${SHARED_FRAMEWORKS_FOLDER_PATH-_} ]]
+[[ ! $SHARED_SUPPORT_FOLDER_PATH && ${SHARED_SUPPORT_FOLDER_PATH-_} ]]
+[[ ! $PLUGINS_FOLDER_PATH && ${PLUGINS_FOLDER_PATH-_} ]]
+[[ ! $XPCSERVICES_FOLDER_PATH && ${XPCSERVICES_FOLDER_PATH-_} ]]
+
test $DYLIB_INSTALL_NAME_BASE = "/usr/local/lib"
test $LD_DYLIB_INSTALL_NAME = "/usr/local/lib/nonbundle_loadable_module.so"
-# Should be set, but empty.
-[[ ! $SDKROOT && ! ${SDKROOT-_} ]]
+"$(dirname "$0")/test_check_sdkroot.sh"
--- a/media/webrtc/trunk/tools/gyp/test/mac/type_envvars/test_nonbundle_none.sh
+++ b/media/webrtc/trunk/tools/gyp/test/mac/type_envvars/test_nonbundle_none.sh
@@ -10,13 +10,23 @@ set -e
[[ ! $PRODUCT_TYPE && ${PRODUCT_TYPE-_} ]]
test $PRODUCT_NAME = nonbundle_none
[[ ! $FULL_PRODUCT_NAME && ${FULL_PRODUCT_NAME-_} ]]
[[ ! $EXECUTABLE_NAME && ${EXECUTABLE_NAME-_} ]]
[[ ! $EXECUTABLE_PATH && ${EXECUTABLE_PATH-_} ]]
[[ ! $WRAPPER_NAME && ${WRAPPER_NAME-_} ]]
+[[ ! $CONTENTS_FOLDER_PATH && ${CONTENTS_FOLDER_PATH-_} ]]
+[[ ! $EXECUTABLE_FOLDER_PATH && ${EXECUTABLE_FOLDER_PATH-_} ]]
+[[ ! $UNLOCALIZED_RESOURCES_FOLDER_PATH \
+ && ${UNLOCALIZED_RESOURCES_FOLDER_PATH-_} ]]
+[[ ! $JAVA_FOLDER_PATH && ${JAVA_FOLDER_PATH-_} ]]
+[[ ! $FRAMEWORKS_FOLDER_PATH && ${FRAMEWORKS_FOLDER_PATH-_} ]]
+[[ ! $SHARED_FRAMEWORKS_FOLDER_PATH && ${SHARED_FRAMEWORKS_FOLDER_PATH-_} ]]
+[[ ! $SHARED_SUPPORT_FOLDER_PATH && ${SHARED_SUPPORT_FOLDER_PATH-_} ]]
+[[ ! $PLUGINS_FOLDER_PATH && ${PLUGINS_FOLDER_PATH-_} ]]
+[[ ! $XPCSERVICES_FOLDER_PATH && ${XPCSERVICES_FOLDER_PATH-_} ]]
+
[[ ! $DYLIB_INSTALL_NAME_BASE && ${DYLIB_INSTALL_NAME_BASE-_} ]]
[[ ! $LD_DYLIB_INSTALL_NAME && ${LD_DYLIB_INSTALL_NAME-_} ]]
-# Should be set, but empty.
-[[ ! $SDKROOT && ! ${SDKROOT-_} ]]
+"$(dirname "$0")/test_check_sdkroot.sh"
--- a/media/webrtc/trunk/tools/gyp/test/mac/type_envvars/test_nonbundle_shared_library.sh
+++ b/media/webrtc/trunk/tools/gyp/test/mac/type_envvars/test_nonbundle_shared_library.sh
@@ -9,13 +9,23 @@ test $MACH_O_TYPE = mh_dylib
test $PRODUCT_TYPE = com.apple.product-type.library.dynamic
test $PRODUCT_NAME = nonbundle_shared_library
test $FULL_PRODUCT_NAME = libnonbundle_shared_library.dylib
test $EXECUTABLE_NAME = libnonbundle_shared_library.dylib
test $EXECUTABLE_PATH = libnonbundle_shared_library.dylib
[[ ! $WRAPPER_NAME && ${WRAPPER_NAME-_} ]]
+[[ ! $CONTENTS_FOLDER_PATH && ${CONTENTS_FOLDER_PATH-_} ]]
+[[ ! $EXECUTABLE_FOLDER_PATH && ${EXECUTABLE_FOLDER_PATH-_} ]]
+[[ ! $UNLOCALIZED_RESOURCES_FOLDER_PATH && \
+ ${UNLOCALIZED_RESOURCES_FOLDER_PATH-_} ]]
+[[ ! $JAVA_FOLDER_PATH && ${JAVA_FOLDER_PATH-_} ]]
+[[ ! $FRAMEWORKS_FOLDER_PATH && ${FRAMEWORKS_FOLDER_PATH-_} ]]
+[[ ! $SHARED_FRAMEWORKS_FOLDER_PATH && ${SHARED_FRAMEWORKS_FOLDER_PATH-_} ]]
+[[ ! $SHARED_SUPPORT_FOLDER_PATH && ${SHARED_SUPPORT_FOLDER_PATH-_} ]]
+[[ ! $PLUGINS_FOLDER_PATH && ${PLUGINS_FOLDER_PATH-_} ]]
+[[ ! $XPCSERVICES_FOLDER_PATH && ${XPCSERVICES_FOLDER_PATH-_} ]]
+
test $DYLIB_INSTALL_NAME_BASE = "/usr/local/lib"
test $LD_DYLIB_INSTALL_NAME = "/usr/local/lib/libnonbundle_shared_library.dylib"
-# Should be set, but empty.
-[[ ! $SDKROOT && ! ${SDKROOT-_} ]]
+"$(dirname "$0")/test_check_sdkroot.sh"
--- a/media/webrtc/trunk/tools/gyp/test/mac/type_envvars/test_nonbundle_static_library.sh
+++ b/media/webrtc/trunk/tools/gyp/test/mac/type_envvars/test_nonbundle_static_library.sh
@@ -9,13 +9,23 @@ test $MACH_O_TYPE = staticlib
test $PRODUCT_TYPE = com.apple.product-type.library.static
test $PRODUCT_NAME = nonbundle_static_library
test $FULL_PRODUCT_NAME = libnonbundle_static_library.a
test $EXECUTABLE_NAME = libnonbundle_static_library.a
test $EXECUTABLE_PATH = libnonbundle_static_library.a
[[ ! $WRAPPER_NAME && ${WRAPPER_NAME-_} ]]
+[[ ! $CONTENTS_FOLDER_PATH && ${CONTENTS_FOLDER_PATH-_} ]]
+[[ ! $EXECUTABLE_FOLDER_PATH && ${EXECUTABLE_FOLDER_PATH-_} ]]
+[[ ! $UNLOCALIZED_RESOURCES_FOLDER_PATH && \
+ ${UNLOCALIZED_RESOURCES_FOLDER_PATH-_} ]]
+[[ ! $JAVA_FOLDER_PATH && ${JAVA_FOLDER_PATH-_} ]]
+[[ ! $FRAMEWORKS_FOLDER_PATH && ${FRAMEWORKS_FOLDER_PATH-_} ]]
+[[ ! $SHARED_FRAMEWORKS_FOLDER_PATH && ${SHARED_FRAMEWORKS_FOLDER_PATH-_} ]]
+[[ ! $SHARED_SUPPORT_FOLDER_PATH && ${SHARED_SUPPORT_FOLDER_PATH-_} ]]
+[[ ! $PLUGINS_FOLDER_PATH && ${PLUGINS_FOLDER_PATH-_} ]]
+[[ ! $XPCSERVICES_FOLDER_PATH && ${XPCSERVICES_FOLDER_PATH-_} ]]
+
[[ ! $DYLIB_INSTALL_NAME_BASE && ${DYLIB_INSTALL_NAME_BASE-_} ]]
[[ ! $LD_DYLIB_INSTALL_NAME && ${LD_DYLIB_INSTALL_NAME-_} ]]
-# Should be set, but empty.
-[[ ! $SDKROOT && ! ${SDKROOT-_} ]]
+"$(dirname "$0")/test_check_sdkroot.sh"
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/unicode-settings/file.cc
@@ -0,0 +1,2 @@
+int main() {
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/unicode-settings/test.gyp
@@ -0,0 +1,23 @@
+# Copyright 2013 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': 'myapp',
+ 'type': 'executable',
+ 'mac_bundle': 1,
+ 'sources': [ 'file.cc', ],
+ 'xcode_settings': {
+ 'BUNDLE_DISPLAY_NAME': 'α\011',
+ },
+ 'postbuilds': [
+ {
+ 'postbuild_name': 'envtest',
+ 'action': [ './test_bundle_display_name.sh', ],
+ },
+ ],
+ },
+ ],
+}
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/unicode-settings/test_bundle_display_name.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+# Copyright 2013 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.
+
+test "${BUNDLE_DISPLAY_NAME}" = 'α '
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/xcode-gcc/aliasing.cc
@@ -0,0 +1,13 @@
+#include <stdio.h>
+
+void check(int* h, long* k) {
+ *h = 1;
+ *k = 0;
+ printf("%d\n", *h);
+}
+
+int main(void) {
+ long k;
+ check((int*)&k, &k);
+ return 0;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/xcode-gcc/test-clang.gyp
@@ -0,0 +1,42 @@
+# Copyright (c) 2013 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.
+{
+ 'make_global_settings': [
+ ['CC', '/usr/bin/clang'],
+ ['CXX', '/usr/bin/clang++'],
+ ],
+
+ 'targets': [
+ {
+ 'target_name': 'aliasing_yes',
+ 'type': 'executable',
+ 'sources': [ 'aliasing.cc', ],
+ 'xcode_settings': {
+ 'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0',
+ 'GCC_STRICT_ALIASING': 'YES',
+ 'GCC_OPTIMIZATION_LEVEL': 2,
+ },
+ },
+ {
+ 'target_name': 'aliasing_no',
+ 'type': 'executable',
+ 'sources': [ 'aliasing.cc', ],
+ 'xcode_settings': {
+ 'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0',
+ 'GCC_STRICT_ALIASING': 'NO',
+ 'GCC_OPTIMIZATION_LEVEL': 2,
+ },
+ },
+ {
+ 'target_name': 'aliasing_default',
+ 'type': 'executable',
+ 'sources': [ 'aliasing.cc', ],
+ 'xcode_settings': {
+ 'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0',
+ 'GCC_OPTIMIZATION_LEVEL': 2,
+ },
+ },
+ ],
+}
+
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/xcode-support-actions/test.gyp
@@ -0,0 +1,26 @@
+# Copyright (c) 2014 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': 'target',
+ 'product_name': 'Product',
+ 'type': 'shared_library',
+ 'mac_bundle': 1,
+ 'sources': [
+ '<(PRODUCT_DIR)/copy.c',
+ ],
+ 'actions': [
+ {
+ 'action_name': 'Helper',
+ 'description': 'Helps',
+ 'inputs': [ 'source.c' ],
+ 'outputs': [ '<(PRODUCT_DIR)/copy.c' ],
+ 'action': [ 'cp', '${SOURCE_ROOT}/source.c',
+ '<(PRODUCT_DIR)/copy.c' ],
+ },
+ ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/xctest/MyClass.h
@@ -0,0 +1,8 @@
+// Copyright (c) 2013 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.
+
+#import <Foundation/Foundation.h>
+
+@interface MyClass : NSObject
+@end
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/xctest/MyClass.m
@@ -0,0 +1,8 @@
+// Copyright (c) 2013 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.
+
+#import "MyClass.h"
+
+@implementation MyClass
+@end
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/xctest/TestCase.m
@@ -0,0 +1,16 @@
+// Copyright (c) 2013 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.
+
+#import <XCTest/XCTest.h>
+#import "MyClass.h"
+
+@interface TestCase : XCTestCase
+@end
+
+@implementation TestCase
+- (void)testFoo {
+ MyClass *foo = [[MyClass alloc] init];
+ XCTAssertNotNil(foo, @"expected non-nil object");
+}
+@end
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/xctest/resource.txt
@@ -0,0 +1,1 @@
+foo
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/xctest/test.gyp
@@ -0,0 +1,47 @@
+# Copyright (c) 2013 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': 'classes',
+ 'type': 'static_library',
+ 'sources': [
+ 'MyClass.h',
+ 'MyClass.m',
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
+ ],
+ },
+ },
+ {
+ 'target_name': 'tests',
+ 'type': 'loadable_module',
+ 'mac_xctest_bundle': 1,
+ 'sources': [
+ 'TestCase.m',
+ ],
+ 'dependencies': [
+ 'classes',
+ ],
+ 'mac_bundle_resources': [
+ 'resource.txt',
+ ],
+ 'xcode_settings': {
+ 'WRAPPER_EXTENSION': 'xctest',
+ 'FRAMEWORK_SEARCH_PATHS': [
+ '$(inherited)',
+ '$(DEVELOPER_FRAMEWORKS_DIR)',
+ ],
+ 'OTHER_LDFLAGS': [
+ '$(inherited)',
+ '-ObjC',
+ ],
+ },
+ },
+ ],
+}
+
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/xctest/test.xcodeproj/xcshareddata/xcschemes/classes.xcscheme
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ LastUpgradeVersion = "0500"
+ version = "1.3">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "YES">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "D3B79173B4570A3C70A902FF"
+ BuildableName = "libclasses.a"
+ BlueprintName = "classes"
+ ReferencedContainer = "container:test.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
+ </BuildAction>
+ <TestAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ buildConfiguration = "Default">
+ <Testables>
+ <TestableReference
+ skipped = "NO">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "2ACDAB234B9E5D65CACBCF9C"
+ BuildableName = "tests.xctest"
+ BlueprintName = "tests"
+ ReferencedContainer = "container:test.xcodeproj">
+ </BuildableReference>
+ </TestableReference>
+ </Testables>
+ </TestAction>
+ <LaunchAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Default"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ allowLocationSimulation = "YES">
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Default"
+ debugDocumentVersioning = "YES">
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Default">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Default"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+</Scheme>
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/xcuitest/Info.plist
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIconFile</key>
+ <string></string>
+ <key>CFBundleIdentifier</key>
+ <string>com.yourcompany.${PRODUCT_NAME}</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>BNDL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+ <key>NSPrincipalClass</key>
+ <string></string>
+</dict>
+</plist>
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/xcuitest/MyAppDelegate.h
@@ -0,0 +1,8 @@
+// Copyright (c) 2013 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.
+
+#import <UIKit/UIKit.h>
+
+@interface MyAppDelegate : NSObject<UIApplicationDelegate>
+@end
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/xcuitest/MyAppDelegate.m
@@ -0,0 +1,19 @@
+// Copyright (c) 2013 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.
+
+#import "MyAppDelegate.h"
+
+
+@implementation MyAppDelegate
+@synthesize window;
+
+- (BOOL)application:(UIApplication *)application
+ didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
+ self.window = [[UIWindow alloc] init];
+ self.window.rootViewController = [[UIViewController alloc] init];
+ [self.window makeKeyAndVisible];
+ return YES;
+}
+
+@end
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/xcuitest/TestCase.m
@@ -0,0 +1,15 @@
+// Copyright (c) 2013 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.
+
+#import <XCTest/XCTest.h>
+
+@interface TestCase : XCTestCase
+@end
+
+@implementation TestCase
+- (void)testFoo {
+ XCUIApplication *foo = [[XCUIApplication alloc] init];
+ XCTAssertNotNil(foo, @"expected non-nil object");
+}
+@end
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/xcuitest/main.m
@@ -0,0 +1,15 @@
+// Copyright (c) 2013 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.
+
+#import <UIKit/UIKit.h>
+
+#import "MyAppDelegate.h"
+
+int main(int argc, char * argv[]) {
+ @autoreleasepool {
+ UIApplicationMain(argc, argv,
+ nil, NSStringFromClass([MyAppDelegate class]));
+ }
+ return 1;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/xcuitest/resource.txt
@@ -0,0 +1,1 @@
+foo
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/mac/xcuitest/test.gyp
@@ -0,0 +1,69 @@
+# Copyright (c) 2013 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.
+
+{
+ 'target_defaults': {
+ 'xcode_settings': {
+ 'SDKROOT': 'iphoneos',
+ 'FRAMEWORK_SEARCH_PATHS': [
+ '$(inherited)',
+ '$(DEVELOPER_FRAMEWORKS_DIR)',
+ ],
+ 'OTHER_LDFLAGS': [
+ '$(inherited)',
+ '-ObjC',
+ ],
+ 'GCC_PREFIX_HEADER': '',
+ 'CLANG_ENABLE_OBJC_ARC': 'YES',
+ 'INFOPLIST_FILE': 'Info.plist',
+ },
+ },
+ 'targets': [
+ {
+ 'target_name': 'testApp',
+ 'type': 'executable',
+ 'mac_bundle': 1,
+ 'sources': [
+ 'MyAppDelegate.h',
+ 'MyAppDelegate.m',
+ 'main.m',
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
+ '$(SDKROOT)/System/Library/Frameworks/UIKit.framework',
+ ],
+ },
+ },
+ {
+ 'target_name': 'tests',
+ 'type': 'loadable_module',
+ 'mac_bundle': 1,
+ 'mac_xcuitest_bundle': 1,
+ 'sources': [
+ 'TestCase.m',
+ ],
+ 'dependencies': [
+ 'testApp',
+ ],
+ 'mac_bundle_resources': [
+ 'resource.txt',
+ ],
+ 'variables': {
+ # This must *not* be set for xctest ui tests.
+ 'xctest_host': '',
+ },
+ 'link_settings': {
+ 'libraries': [
+ '$(SDKROOT)/System/Library/Frameworks/XCTest.framework',
+ ]
+ },
+ 'xcode_settings': {
+ 'WRAPPER_EXTENSION': 'xctest',
+ 'TEST_TARGET_NAME': 'testApp',
+ },
+ },
+ ],
+}
+
--- a/media/webrtc/trunk/tools/gyp/test/make/main.cc
+++ b/media/webrtc/trunk/tools/gyp/test/make/main.cc
@@ -1,12 +1,12 @@
/* 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. */
#include <stdio.h>
#include "main.h"
-int main(int argc, char *argv[]) {
+int main(void) {
printf("hello world\n");
return 0;
}
--- a/media/webrtc/trunk/tools/gyp/test/make/noload/main.c
+++ b/media/webrtc/trunk/tools/gyp/test/make/noload/main.c
@@ -1,9 +1,9 @@
#include <stdio.h>
#include "lib/shared.h"
-int main(int argc, char *argv[])
+int main(void)
{
printf("Hello from %s.\n", kSharedStr);
return 0;
}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/make_global_settings/ar/gyptest-make_global_settings_ar.py
@@ -0,0 +1,126 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 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.
+
+"""
+Verifies 'AR' in make_global_settings.
+"""
+
+import os
+import sys
+import TestGyp
+
+def resolve_path(test, path):
+ if path is None:
+ return None
+ elif test.format == 'make':
+ return '$(abspath %s)' % path
+ elif test.format in ['ninja', 'xcode-ninja']:
+ return os.path.join('..', '..', path)
+ else:
+ test.fail_test()
+
+
+def verify_ar_target(test, ar=None, rel_path=False):
+ if rel_path:
+ ar_expected = resolve_path(test, ar)
+ else:
+ ar_expected = ar
+ # Resolve default values
+ if ar_expected is None:
+ if test.format == 'make':
+ # Make generator hasn't set the default value for AR.
+ # You can remove the following assertion as long as it doesn't
+ # break existing projects.
+ test.must_not_contain('Makefile', 'AR ?= ')
+ return
+ elif test.format in ['ninja', 'xcode-ninja']:
+ if sys.platform == 'win32':
+ ar_expected = 'lib.exe'
+ else:
+ ar_expected = 'ar'
+ if test.format == 'make':
+ test.must_contain('Makefile', 'AR ?= %s' % ar_expected)
+ elif test.format in ['ninja', 'xcode-ninja']:
+ test.must_contain('out/Default/build.ninja', 'ar = %s' % ar_expected)
+ else:
+ test.fail_test()
+
+
+def verify_ar_host(test, ar=None, rel_path=False):
+ if rel_path:
+ ar_expected = resolve_path(test, ar)
+ else:
+ ar_expected = ar
+ # Resolve default values
+ if ar_expected is None:
+ if sys.platform == 'win32':
+ ar_expected = 'lib.exe'
+ else:
+ ar_expected = 'ar'
+ if test.format == 'make':
+ test.must_contain('Makefile', 'AR.host ?= %s' % ar_expected)
+ elif test.format in ['ninja', 'xcode-ninja']:
+ test.must_contain('out/Default/build.ninja', 'ar_host = %s' % ar_expected)
+ else:
+ test.fail_test()
+
+
+test_format = ['ninja']
+if sys.platform in ('linux2', 'darwin'):
+ test_format += ['make']
+
+test = TestGyp.TestGyp(formats=test_format)
+
+# Check default values
+test.run_gyp('make_global_settings_ar.gyp')
+verify_ar_target(test)
+
+
+# Check default values with GYP_CROSSCOMPILE enabled.
+with TestGyp.LocalEnv({'GYP_CROSSCOMPILE': '1'}):
+ test.run_gyp('make_global_settings_ar.gyp')
+verify_ar_target(test)
+verify_ar_host(test)
+
+
+# Test 'AR' in 'make_global_settings'.
+with TestGyp.LocalEnv({'GYP_CROSSCOMPILE': '1'}):
+ test.run_gyp('make_global_settings_ar.gyp', '-Dcustom_ar_target=my_ar')
+verify_ar_target(test, ar='my_ar', rel_path=True)
+
+
+# Test 'AR'/'AR.host' in 'make_global_settings'.
+with TestGyp.LocalEnv({'GYP_CROSSCOMPILE': '1'}):
+ test.run_gyp('make_global_settings_ar.gyp',
+ '-Dcustom_ar_target=my_ar_target1',
+ '-Dcustom_ar_host=my_ar_host1')
+verify_ar_target(test, ar='my_ar_target1', rel_path=True)
+verify_ar_host(test, ar='my_ar_host1', rel_path=True)
+
+
+# Test $AR and $AR_host environment variables.
+with TestGyp.LocalEnv({'AR': 'my_ar_target2',
+ 'AR_host': 'my_ar_host2'}):
+ test.run_gyp('make_global_settings_ar.gyp')
+# Ninja generator resolves $AR in gyp phase. Make generator doesn't.
+if test.format == 'ninja':
+ if sys.platform == 'win32':
+ # TODO(yukawa): Make sure if this is an expected result or not.
+ verify_ar_target(test, ar='lib.exe', rel_path=False)
+ else:
+ verify_ar_target(test, ar='my_ar_target2', rel_path=False)
+verify_ar_host(test, ar='my_ar_host2', rel_path=False)
+
+
+# Test 'AR' in 'make_global_settings' with $AR_host environment variable.
+with TestGyp.LocalEnv({'AR_host': 'my_ar_host3'}):
+ test.run_gyp('make_global_settings_ar.gyp',
+ '-Dcustom_ar_target=my_ar_target3')
+verify_ar_target(test, ar='my_ar_target3', rel_path=True)
+verify_ar_host(test, ar='my_ar_host3', rel_path=False)
+
+
+test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/make_global_settings/ar/make_global_settings_ar.gyp
@@ -0,0 +1,29 @@
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style licence that can be
+# found in the LICENSE file.
+
+{
+ 'variables': {
+ 'custom_ar_target%': '',
+ 'custom_ar_host%': '',
+ },
+ 'conditions': [
+ ['"<(custom_ar_target)"!=""', {
+ 'make_global_settings': [
+ ['AR', '<(custom_ar_target)'],
+ ],
+ }],
+ ['"<(custom_ar_host)"!=""', {
+ 'make_global_settings': [
+ ['AR.host', '<(custom_ar_host)'],
+ ],
+ }],
+ ],
+ 'targets': [
+ {
+ 'target_name': 'make_global_settings_ar_test',
+ 'type': 'static_library',
+ 'sources': [ 'foo.c' ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/make_global_settings/basics/gyptest-make_global_settings.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 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.
+
+"""
+Verifies make_global_settings.
+"""
+
+import os
+import sys
+import TestGyp
+
+test_format = ['ninja']
+if sys.platform in ('linux2', 'darwin'):
+ test_format += ['make']
+
+test = TestGyp.TestGyp(formats=test_format)
+
+test.run_gyp('make_global_settings.gyp')
+
+if test.format == 'make':
+ cc_expected = """ifneq (,$(filter $(origin CC), undefined default))
+ CC = $(abspath clang)
+endif
+"""
+ if sys.platform == 'linux2':
+ link_expected = """
+LINK ?= $(abspath clang)
+"""
+ elif sys.platform == 'darwin':
+ link_expected = """
+LINK ?= $(abspath clang)
+"""
+ test.must_contain('Makefile', cc_expected)
+ test.must_contain('Makefile', link_expected)
+if test.format == 'ninja':
+ cc_expected = 'cc = ' + os.path.join('..', '..', 'clang')
+ ld_expected = 'ld = $cc'
+ if sys.platform == 'win32':
+ ld_expected = 'link.exe'
+ test.must_contain('out/Default/build.ninja', cc_expected)
+ test.must_contain('out/Default/build.ninja', ld_expected)
+
+test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/make_global_settings/basics/make_global_settings.gyp
@@ -0,0 +1,17 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style licence that can be
+# found in the LICENSE file.
+
+{
+ 'make_global_settings': [
+ ['CC', 'clang'],
+ ['LINK', 'clang'],
+ ],
+ 'targets': [
+ {
+ 'target_name': 'test',
+ 'type': 'static_library',
+ 'sources': [ 'foo.c' ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/make_global_settings/env-wrapper/gyptest-wrapper.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 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.
+
+"""
+Verifies *_wrapper in environment.
+"""
+
+import os
+import sys
+import TestGyp
+
+test_format = ['ninja']
+
+os.environ['CC_wrapper'] = 'distcc'
+os.environ['LINK_wrapper'] = 'distlink'
+os.environ['CC.host_wrapper'] = 'ccache'
+
+test = TestGyp.TestGyp(formats=test_format)
+
+old_env = dict(os.environ)
+os.environ['GYP_CROSSCOMPILE'] = '1'
+test.run_gyp('wrapper.gyp')
+os.environ.clear()
+os.environ.update(old_env)
+
+if test.format == 'ninja':
+ cc_expected = ('cc = ' + os.path.join('..', '..', 'distcc') + ' ' +
+ os.path.join('..', '..', 'clang'))
+ cc_host_expected = ('cc_host = ' + os.path.join('..', '..', 'ccache') + ' ' +
+ os.path.join('..', '..', 'clang'))
+ ld_expected = 'ld = ../../distlink $cc'
+ if sys.platform != 'win32':
+ ldxx_expected = 'ldxx = ../../distlink $cxx'
+
+ if sys.platform == 'win32':
+ ld_expected = 'link.exe'
+ test.must_contain('out/Default/build.ninja', cc_expected)
+ test.must_contain('out/Default/build.ninja', cc_host_expected)
+ test.must_contain('out/Default/build.ninja', ld_expected)
+ if sys.platform != 'win32':
+ test.must_contain('out/Default/build.ninja', ldxx_expected)
+
+test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/make_global_settings/env-wrapper/wrapper.gyp
@@ -0,0 +1,17 @@
+# Copyright (c) 2013 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.
+
+{
+ 'make_global_settings': [
+ ['CC', 'clang'],
+ ['CC.host', 'clang'],
+ ],
+ 'targets': [
+ {
+ 'target_name': 'test',
+ 'type': 'static_library',
+ 'sources': [ 'foo.c' ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/make_global_settings/full-toolchain/bar.cc
@@ -0,0 +1,1 @@
+#error Not a real source file
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/make_global_settings/full-toolchain/foo.c
@@ -0,0 +1,1 @@
+#error Not a real source file
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/make_global_settings/full-toolchain/gyptest-make_global_settings.py
@@ -0,0 +1,48 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 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.
+
+"""
+Verifies make_global_settings works with the full toolchain.
+"""
+
+import os
+import sys
+import TestGyp
+
+if sys.platform == 'win32':
+ # cross compiling not supported by ninja on windows
+ # and make not supported on windows at all.
+ sys.exit(0)
+
+test = TestGyp.TestGyp(formats=['ninja'])
+# Must set the test format to something with a flavor (the part after the '-')
+# in order to test the desired behavior. Since we want to run a non-host
+# toolchain, we have to set the flavor to something that the ninja generator
+# doesn't know about, so it doesn't default to the host-specific tools (e.g.,
+# 'otool' on mac to generate the .TOC).
+#
+# Note that we can't just pass format=['ninja-some_toolchain'] to the
+# constructor above, because then this test wouldn't be recognized as a ninja
+# format test.
+test.formats = ['ninja-my_flavor' if f == 'ninja' else f for f in test.formats]
+
+gyp_file = 'make_global_settings.gyp'
+
+test.run_gyp(gyp_file,
+ # Teach the .gyp file about the location of my_nm.py and
+ # my_readelf.py, and the python executable.
+ '-Dworkdir=%s' % test.workdir,
+ '-Dpython=%s' % sys.executable)
+test.build(gyp_file,
+ arguments=['-v'] if test.format == 'ninja-my_flavor' else [])
+
+expected = ['MY_CC', 'MY_CXX']
+test.must_contain_all_lines(test.stdout(), expected)
+
+test.must_contain(test.built_file_path('RAN_MY_NM'), 'RAN_MY_NM')
+test.must_contain(test.built_file_path('RAN_MY_READELF'), 'RAN_MY_READELF')
+
+test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/make_global_settings/full-toolchain/make_global_settings.gyp
@@ -0,0 +1,22 @@
+# Copyright (c) 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style licence that can be
+# found in the LICENSE file.
+
+{
+ 'make_global_settings': [
+ ['CC', '/bin/echo MY_CC'],
+ ['CXX', '/bin/echo MY_CXX'],
+ ['NM', '<(python) <(workdir)/my_nm.py'],
+ ['READELF', '<(python) <(workdir)/my_readelf.py'],
+ ],
+ 'targets': [
+ {
+ 'target_name': 'test',
+ 'type': 'shared_library',
+ 'sources': [
+ 'foo.c',
+ 'bar.cc',
+ ],
+ },
+ ],
+}
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/make_global_settings/full-toolchain/my_nm.py
@@ -0,0 +1,8 @@
+#!/usr/bin/env python
+# Copyright (c) 2014 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.
+import sys
+print sys.argv
+with open('RAN_MY_NM', 'w') as f:
+ f.write('RAN_MY_NM')
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/make_global_settings/full-toolchain/my_readelf.py
@@ -0,0 +1,8 @@
+#!/usr/bin/env python
+# Copyright (c) 2014 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.
+import sys
+print sys.argv
+with open('RAN_MY_READELF', 'w') as f:
+ f.write('RAN_MY_READELF')
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/make_global_settings/ld/gyptest-make_global_settings_ld.py
@@ -0,0 +1,130 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 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.
+
+"""
+Verifies 'LD' in make_global_settings.
+"""
+
+import os
+import sys
+import TestGyp
+
+def resolve_path(test, path):
+ if path is None:
+ return None
+ elif test.format == 'make':
+ return '$(abspath %s)' % path
+ elif test.format in ['ninja', 'xcode-ninja']:
+ return os.path.join('..', '..', path)
+ else:
+ test.fail_test()
+
+
+def verify_ld_target(test, ld=None, rel_path=False):
+ if rel_path:
+ ld_expected = resolve_path(test, ld)
+ else:
+ ld_expected = ld
+ # Resolve default values
+ if ld_expected is None:
+ if test.format == 'make':
+ # Make generator hasn't set the default value for LD.
+ # You can remove the following assertion as long as it doesn't
+ # break existing projects.
+ test.must_not_contain('Makefile', 'LD ?= ')
+ return
+ elif test.format in ['ninja', 'xcode-ninja']:
+ if sys.platform == 'win32':
+ ld_expected = 'link.exe'
+ else:
+ ld_expected = '$cc'
+ if test.format == 'make':
+ test.must_contain('Makefile', 'LD ?= %s' % ld_expected)
+ elif test.format in ['ninja', 'xcode-ninja']:
+ test.must_contain('out/Default/build.ninja', 'ld = %s' % ld_expected)
+ else:
+ test.fail_test()
+
+
+def verify_ld_host(test, ld=None, rel_path=False):
+ if rel_path:
+ ld_expected = resolve_path(test, ld)
+ else:
+ ld_expected = ld
+ # Resolve default values
+ if ld_expected is None:
+ if test.format == 'make':
+ # Make generator hasn't set the default value for LD.host.
+ # You can remove the following assertion as long as it doesn't
+ # break existing projects.
+ test.must_not_contain('Makefile', 'LD.host ?= ')
+ return
+ elif test.format in ['ninja', 'xcode-ninja']:
+ if sys.platform == 'win32':
+ ld_expected = '$ld'
+ else:
+ ld_expected = '$cc_host'
+ if test.format == 'make':
+ test.must_contain('Makefile', 'LD.host ?= %s' % ld_expected)
+ elif test.format in ['ninja', 'xcode-ninja']:
+ test.must_contain('out/Default/build.ninja', 'ld_host = %s' % ld_expected)
+ else:
+ test.fail_test()
+
+
+test_format = ['ninja']
+if sys.platform in ('linux2', 'darwin'):
+ test_format += ['make']
+
+test = TestGyp.TestGyp(formats=test_format)
+
+# Check default values
+test.run_gyp('make_global_settings_ld.gyp')
+verify_ld_target(test)
+
+
+# Check default values with GYP_CROSSCOMPILE enabled.
+with TestGyp.LocalEnv({'GYP_CROSSCOMPILE': '1'}):
+ test.run_gyp('make_global_settings_ld.gyp')
+verify_ld_target(test)
+verify_ld_host(test)
+
+
+# Test 'LD' in 'make_global_settings'.
+with TestGyp.LocalEnv({'GYP_CROSSCOMPILE': '1'}):
+ test.run_gyp('make_global_settings_ld.gyp', '-Dcustom_ld_target=my_ld')
+verify_ld_target(test, ld='my_ld', rel_path=True)
+
+
+# Test 'LD'/'LD.host' in 'make_global_settings'.
+with TestGyp.LocalEnv({'GYP_CROSSCOMPILE': '1'}):
+ test.run_gyp('make_global_settings_ld.gyp',
+ '-Dcustom_ld_target=my_ld_target1',
+ '-Dcustom_ld_host=my_ld_host1')
+verify_ld_target(test, ld='my_ld_target1', rel_path=True)
+verify_ld_host(test, ld='my_ld_host1', rel_path=True)
+
+
+# Unlike other environment variables such as $AR/$AR_host, $CC/$CC_host,
+# and $CXX/$CXX_host, neither Make generator nor Ninja generator recognizes
+# $LD/$LD_host environment variables as of r1935. This may or may not be
+# intentional, but here we leave a test case to verify this behavior just for
+# the record.
+# If you want to support $LD/$LD_host, please revise the following test case as
+# well as the generator.
+with TestGyp.LocalEnv({'GYP_CROSSCOMPILE': '1',
+ 'LD': 'my_ld_target2',
+ 'LD_host': 'my_ld_host2'}):
+ test.run_gyp('make_global_settings_ld.gyp')
+if test.format == 'make':
+ test.must_not_contain('Makefile', 'my_ld_target2')
+ test.must_not_contain('Makefile', 'my_ld_host2')
+elif test.format == 'ninja':
+ test.must_not_contain('out/Default/build.ninja', 'my_ld_target2')
+ test.must_not_contain('out/Default/build.ninja', 'my_ld_host2')
+
+
+test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/make_global_settings/ld/make_global_settings_ld.gyp
@@ -0,0 +1,29 @@
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style licence that can be
+# found in the LICENSE file.
+
+{
+ 'variables': {
+ 'custom_ld_target%': '',
+ 'custom_ld_host%': '',
+ },
+ 'conditions': [
+ ['"<(custom_ld_target)"!=""', {
+ 'make_global_settings': [
+ ['LD', '<(custom_ld_target)'],
+ ],
+ }],
+ ['"<(custom_ld_host)"!=""', {
+ 'make_global_settings': [
+ ['LD.host', '<(custom_ld_host)'],
+ ],
+ }],
+ ],
+ 'targets': [
+ {
+ 'target_name': 'make_global_settings_ld_test',
+ 'type': 'static_library',
+ 'sources': [ 'foo.c' ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/make_global_settings/wrapper/gyptest-wrapper.py
@@ -0,0 +1,47 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 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.
+
+"""
+Verifies *_wrapper in make_global_settings.
+"""
+
+import os
+import sys
+import TestGyp
+
+test_format = ['ninja']
+if sys.platform in ('linux2', 'darwin'):
+ test_format += ['make']
+
+test = TestGyp.TestGyp(formats=test_format)
+
+old_env = dict(os.environ)
+os.environ['GYP_CROSSCOMPILE'] = '1'
+test.run_gyp('wrapper.gyp')
+os.environ.clear()
+os.environ.update(old_env)
+
+if test.format == 'make':
+ cc_expected = """ifneq (,$(filter $(origin CC), undefined default))
+ CC = $(abspath distcc) $(abspath clang)
+endif
+"""
+ link_expected = 'LINK ?= $(abspath distlink) $(abspath clang++)'
+ test.must_contain('Makefile', cc_expected)
+ test.must_contain('Makefile', link_expected)
+if test.format == 'ninja':
+ cc_expected = ('cc = ' + os.path.join('..', '..', 'distcc') + ' ' +
+ os.path.join('..', '..', 'clang'))
+ cc_host_expected = ('cc_host = ' + os.path.join('..', '..', 'ccache') + ' ' +
+ os.path.join('..', '..', 'clang'))
+ ld_expected = 'ld = ../../distlink $cc'
+ if sys.platform == 'win32':
+ ld_expected = 'link.exe'
+ test.must_contain('out/Default/build.ninja', cc_expected)
+ test.must_contain('out/Default/build.ninja', cc_host_expected)
+ test.must_contain('out/Default/build.ninja', ld_expected)
+
+test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/make_global_settings/wrapper/wrapper.gyp
@@ -0,0 +1,21 @@
+# Copyright (c) 2013 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.
+
+{
+ 'make_global_settings': [
+ ['CC', 'clang'],
+ ['CC_wrapper', 'distcc'],
+ ['LINK', 'clang++'],
+ ['LINK_wrapper', 'distlink'],
+ ['CC.host', 'clang'],
+ ['CC.host_wrapper', 'ccache'],
+ ],
+ 'targets': [
+ {
+ 'target_name': 'test',
+ 'type': 'static_library',
+ 'sources': [ 'foo.c' ],
+ },
+ ],
+}
--- a/media/webrtc/trunk/tools/gyp/test/many-actions/gyptest-many-actions-unsorted.py
+++ b/media/webrtc/trunk/tools/gyp/test/many-actions/gyptest-many-actions-unsorted.py
@@ -4,21 +4,28 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""
Make sure lots of actions in the same target don't cause exceeding command
line length.
"""
+import sys
+
+if sys.platform == 'win32':
+ print "This test is currently disabled: https://crbug.com/483696."
+ sys.exit(0)
+
import TestGyp
test = TestGyp.TestGyp()
test.run_gyp('many-actions-unsorted.gyp')
+
test.build('many-actions-unsorted.gyp', test.ALL)
for i in range(15):
test.built_file_must_exist('generated_%d.h' % i)
# Make sure the optimized cygwin setup doesn't cause problems for incremental
# builds.
test.touch('file1')
test.build('many-actions-unsorted.gyp', test.ALL)
--- a/media/webrtc/trunk/tools/gyp/test/many-actions/gyptest-many-actions.py
+++ b/media/webrtc/trunk/tools/gyp/test/many-actions/gyptest-many-actions.py
@@ -4,16 +4,23 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""
Make sure lots of actions in the same target don't cause exceeding command
line length.
"""
+import sys
+
+if sys.platform == 'win32':
+ print "This test is currently disabled: https://crbug.com/483696."
+ sys.exit(0)
+
+
import TestGyp
test = TestGyp.TestGyp()
test.run_gyp('many-actions.gyp')
test.build('many-actions.gyp', test.ALL)
for i in range(200):
test.built_file_must_exist('generated_%d.h' % i)
--- a/media/webrtc/trunk/tools/gyp/test/module/gyptest-default.py
+++ b/media/webrtc/trunk/tools/gyp/test/module/gyptest-default.py
@@ -7,18 +7,17 @@
"""
Verifies simple build of a "Hello, world!" program with loadable modules. The
default for all platforms should be to output the loadable modules to the same
path as the executable.
"""
import TestGyp
-# Android doesn't support loadable modules
-test = TestGyp.TestGyp(formats=['!android'])
+test = TestGyp.TestGyp()
test.run_gyp('module.gyp', chdir='src')
test.build('module.gyp', test.ALL, chdir='src')
expect = """\
Hello from program.c
Hello from lib1.c
--- a/media/webrtc/trunk/tools/gyp/test/module/src/module.gyp
+++ b/media/webrtc/trunk/tools/gyp/test/module/src/module.gyp
@@ -3,17 +3,17 @@
# found in the LICENSE file.
{
'target_defaults': {
'conditions': [
['OS=="win"', {
'defines': ['PLATFORM_WIN'],
}],
- ['OS=="mac"', {
+ ['OS=="mac" or OS=="ios"', {
'defines': ['PLATFORM_MAC'],
}],
['OS=="linux"', {
'defines': ['PLATFORM_LINUX'],
# Support 64-bit shared libs (also works fine for 32-bit).
'cflags': ['-fPIC'],
'libraries': ['-ldl'],
}],
@@ -31,25 +31,23 @@
'program.c',
],
},
{
'target_name': 'lib1',
'type': 'loadable_module',
'product_name': 'lib1',
'product_prefix': '',
- 'xcode_settings': {'OTHER_LDFLAGS': ['-dynamiclib'], 'MACH_O_TYPE': ''},
'sources': [
'lib1.c',
],
},
{
'target_name': 'lib2',
'product_name': 'lib2',
'product_prefix': '',
'type': 'loadable_module',
- 'xcode_settings': {'OTHER_LDFLAGS': ['-dynamiclib'], 'MACH_O_TYPE': ''},
'sources': [
'lib2.c',
],
},
],
}
--- a/media/webrtc/trunk/tools/gyp/test/module/src/program.c
+++ b/media/webrtc/trunk/tools/gyp/test/module/src/program.c
@@ -89,23 +89,23 @@ void CallModule(const char* module) {
int main(int argc, char *argv[])
{
fprintf(stdout, "Hello from program.c\n");
fflush(stdout);
#if defined(PLATFORM_WIN)
if (!GetModuleFileName(NULL, bin_path, MAX_PATH)) {
fprintf(stderr, "Failed to determine executable path.\n");
- return;
+ return 1;
}
#elif defined(PLATFORM_MAC) || defined(PLATFORM_LINUX)
// Using argv[0] should be OK here since we control how the tests run, and
// can avoid exec and such issues that make it unreliable.
if (!realpath(argv[0], bin_path)) {
fprintf(stderr, "Failed to determine executable path (%s).\n", argv[0]);
- return;
+ return 1;
}
#endif
CallModule("lib1");
CallModule("lib2");
return 0;
}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/msvs/buildevents/buildevents.gyp
@@ -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.
+{
+ 'targets': [
+ {
+ 'target_name': 'main',
+ 'type': 'executable',
+ 'sources': [ 'main.cc', ],
+ 'msvs_prebuild': r'echo starting',
+ 'msvs_postbuild': r'echo finished',
+ },
+ ],
+}
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/msvs/buildevents/gyptest-msbuild-supports-prepostbuild.py
@@ -0,0 +1,24 @@
+#!/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.
+
+"""
+Verifies that msvs_prebuild and msvs_postbuild can be specified in both
+VS 2008 and 2010.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp(formats=['msvs'], workdir='workarea_all')
+
+test.run_gyp('buildevents.gyp', '-G', 'msvs_version=2008')
+test.must_contain('main.vcproj', 'Name="VCPreBuildEventTool"')
+test.must_contain('main.vcproj', 'Name="VCPostBuildEventTool"')
+
+test.run_gyp('buildevents.gyp', '-G', 'msvs_version=2010')
+test.must_contain('main.vcxproj', '<PreBuildEvent>')
+test.must_contain('main.vcxproj', '<PostBuildEvent>')
+
+test.pass_test()
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/msvs/buildevents/gyptest-ninja-warnings.py
@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 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.
+
+"""
+Verifies that ninja errors out when encountering msvs_prebuild/msvs_postbuild.
+"""
+
+import sys
+import TestCmd
+import TestGyp
+
+
+if sys.platform == 'win32':
+ test = TestGyp.TestGyp(formats=['ninja'])
+
+ test.run_gyp('buildevents.gyp',
+ status=1,
+ stderr=r'.*msvs_prebuild not supported \(target main\).*',
+ match=TestCmd.match_re_dotall)
+
+ test.run_gyp('buildevents.gyp',
+ status=1,
+ stderr=r'.*msvs_postbuild not supported \(target main\).*',
+ match=TestCmd.match_re_dotall)
+
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/msvs/buildevents/main.cc
@@ -0,0 +1,5 @@
+// Copyright (c) 2014 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 main() {}
--- a/media/webrtc/trunk/tools/gyp/test/msvs/config_attrs/gyptest-config_attrs.py
+++ b/media/webrtc/trunk/tools/gyp/test/msvs/config_attrs/gyptest-config_attrs.py
@@ -8,16 +8,24 @@
Verifies that msvs_configuration_attributes and
msbuild_configuration_attributes are applied by using
them to set the OutputDirectory.
"""
import TestGyp
import os
+import sys
+
+if sys.platform == 'win32':
+ print "This test is currently disabled: https://crbug.com/483696."
+ sys.exit(0)
+
+
+
test = TestGyp.TestGyp(workdir='workarea_all',formats=['msvs'])
vc_version = 'VC90'
if os.getenv('GYP_MSVS_VERSION'):
vc_version = ['VC90','VC100'][int(os.getenv('GYP_MSVS_VERSION')) >= 2010]
expected_exe_file = os.path.join(test.workdir, vc_version, 'hello.exe')
--- a/media/webrtc/trunk/tools/gyp/test/msvs/config_attrs/hello.c
+++ b/media/webrtc/trunk/tools/gyp/test/msvs/config_attrs/hello.c
@@ -1,11 +1,11 @@
/* Copyright (c) 2012 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>
-int main(int argc, char *argv[])
+int main(void)
{
printf("Hello, world!\n");
return 0;
-}
\ No newline at end of file
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/msvs/external_builder/external.gyp
@@ -0,0 +1,68 @@
+# Copyright (c) 2013 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.
+
+{
+ 'variables': {
+ # the test driver switches this flag when testing external builder
+ 'use_external_builder%': 0,
+ },
+ 'targets': [
+ {
+ 'target_name': 'external',
+ 'type': 'executable',
+ 'sources': [
+ 'hello.cpp',
+ 'hello.z',
+ ],
+ 'rules': [
+ {
+ 'rule_name': 'test_rule',
+ 'extension': 'z',
+ 'outputs': [
+ 'msbuild_rule.out',
+ ],
+ 'action': [
+ 'python',
+ 'msbuild_rule.py',
+ '<(RULE_INPUT_PATH)',
+ 'a', 'b', 'c',
+ ],
+ 'msvs_cygwin_shell': 0,
+ },
+ ],
+ 'actions': [
+ {
+ 'action_name': 'test action',
+ 'inputs': [
+ 'msbuild_action.py',
+ ],
+ 'outputs': [
+ 'msbuild_action.out',
+ ],
+ 'action': [
+ 'python',
+ '<@(_inputs)',
+ 'x', 'y', 'z',
+ ],
+ 'msvs_cygwin_shell': 0,
+ },
+ ],
+ 'conditions': [
+ ['use_external_builder==1', {
+ 'msvs_external_builder': 'test',
+ 'msvs_external_builder_build_cmd': [
+ 'python',
+ 'external_builder.py',
+ 'build', '1', '2', '3',
+ ],
+ 'msvs_external_builder_clean_cmd': [
+ 'python',
+ 'external_builder.py',
+ 'clean', '4', '5',
+ ],
+ }],
+ ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/msvs/external_builder/external_builder.py
@@ -0,0 +1,9 @@
+# Copyright (c) 2013 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.
+
+import sys
+
+with open('external_builder.out', 'w') as f:
+ f.write(' '.join(sys.argv))
+
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/msvs/external_builder/gyptest-all.py
@@ -0,0 +1,59 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 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.
+
+"""
+Verifies that msvs_external_builder being set will invoke the provided
+msvs_external_builder_build_cmd and msvs_external_builder_clean_cmd, and will
+not invoke MSBuild actions and rules.
+"""
+
+import os
+import sys
+import TestGyp
+
+if int(os.environ.get('GYP_MSVS_VERSION', 0)) < 2010:
+ sys.exit(0)
+
+test = TestGyp.TestGyp(formats=['msvs'], workdir='workarea_all')
+
+# without the flag set
+test.run_gyp('external.gyp')
+test.build('external.gyp', target='external')
+test.must_not_exist('external_builder.out')
+test.must_exist('msbuild_rule.out')
+test.must_exist('msbuild_action.out')
+test.must_match('msbuild_rule.out', 'msbuild_rule.py hello.z a b c')
+test.must_match('msbuild_action.out', 'msbuild_action.py x y z')
+os.remove('msbuild_rule.out')
+os.remove('msbuild_action.out')
+
+# with the flag set, using Build
+try:
+ os.environ['GYP_DEFINES'] = 'use_external_builder=1'
+ test.run_gyp('external.gyp')
+ test.build('external.gyp', target='external')
+finally:
+ del os.environ['GYP_DEFINES']
+test.must_not_exist('msbuild_rule.out')
+test.must_not_exist('msbuild_action.out')
+test.must_exist('external_builder.out')
+test.must_match('external_builder.out', 'external_builder.py build 1 2 3')
+os.remove('external_builder.out')
+
+# with the flag set, using Clean
+try:
+ os.environ['GYP_DEFINES'] = 'use_external_builder=1'
+ test.run_gyp('external.gyp')
+ test.build('external.gyp', target='external', clean=True)
+finally:
+ del os.environ['GYP_DEFINES']
+test.must_not_exist('msbuild_rule.out')
+test.must_not_exist('msbuild_action.out')
+test.must_exist('external_builder.out')
+test.must_match('external_builder.out', 'external_builder.py clean 4 5')
+os.remove('external_builder.out')
+
+test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/msvs/external_builder/hello.cpp
@@ -0,0 +1,10 @@
+// Copyright (c) 2012 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>
+
+int main(void) {
+ printf("Hello, world!\n");
+ return 0;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/msvs/external_builder/hello.z
@@ -0,0 +1,6 @@
+# Copyright (c) 2013 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.
+
+This file will be passed to the test rule.
+
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/msvs/external_builder/msbuild_action.py
@@ -0,0 +1,9 @@
+# Copyright (c) 2013 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.
+
+import sys
+
+with open('msbuild_action.out', 'w') as f:
+ f.write(' '.join(sys.argv))
+
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/msvs/external_builder/msbuild_rule.py
@@ -0,0 +1,11 @@
+# Copyright (c) 2013 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.
+
+import sys, os.path
+
+sys.argv[1] = os.path.basename(sys.argv[1])
+
+with open('msbuild_rule.out', 'w') as f:
+ f.write(' '.join(sys.argv))
+
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/msvs/filters/filters.gyp
@@ -0,0 +1,47 @@
+# Copyright (c) 2014 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': 'no_source_files',
+ 'type': 'none',
+ 'sources': [ ],
+ },
+ {
+ 'target_name': 'one_source_file',
+ 'type': 'executable',
+ 'sources': [
+ '../folder/a.c',
+ ],
+ },
+ {
+ 'target_name': 'two_source_files',
+ 'type': 'executable',
+ 'sources': [
+ '../folder/a.c',
+ '../folder/b.c',
+ ],
+ },
+ {
+ 'target_name': 'three_files_in_two_folders',
+ 'type': 'executable',
+ 'sources': [
+ '../folder1/a.c',
+ '../folder1/b.c',
+ '../folder2/c.c',
+ ],
+ },
+ {
+ 'target_name': 'nested_folders',
+ 'type': 'executable',
+ 'sources': [
+ '../folder1/nested/a.c',
+ '../folder2/d.c',
+ '../folder1/nested/b.c',
+ '../folder1/other/c.c',
+ ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/msvs/filters/gyptest-filters-2008.py
@@ -0,0 +1,68 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 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.
+
+"""
+Verifies that extra filters are pruned correctly for Visual Studio 2008.
+"""
+
+import re
+import TestGyp
+
+
+def strip_ws(str):
+ return re.sub('^ +', '', str, flags=re.M).replace('\n', '')
+
+
+test = TestGyp.TestGyp(formats=['msvs'])
+
+test.run_gyp('filters.gyp', '-G', 'standalone', '-G', 'msvs_version=2008')
+
+test.must_contain('no_source_files.vcproj', '<Files/>')
+
+test.must_contain('one_source_file.vcproj', strip_ws('''\
+<Files>
+ <File RelativePath="..\\folder\\a.c"/>
+</Files>
+'''))
+
+test.must_contain('two_source_files.vcproj', strip_ws('''\
+<Files>
+ <File RelativePath="..\\folder\\a.c"/>
+ <File RelativePath="..\\folder\\b.c"/>
+</Files>
+'''))
+
+test.must_contain('three_files_in_two_folders.vcproj', strip_ws('''\
+<Files>
+ <Filter Name="folder1">
+ <File RelativePath="..\\folder1\\a.c"/>
+ <File RelativePath="..\\folder1\\b.c"/>
+ </Filter>
+ <Filter Name="folder2">
+ <File RelativePath="..\\folder2\\c.c"/>
+ </Filter>
+</Files>
+'''))
+
+test.must_contain('nested_folders.vcproj', strip_ws('''\
+<Files>
+ <Filter Name="folder1">
+ <Filter Name="nested">
+ <File RelativePath="..\\folder1\\nested\\a.c"/>
+ <File RelativePath="..\\folder1\\nested\\b.c"/>
+ </Filter>
+ <Filter Name="other">
+ <File RelativePath="..\\folder1\\other\\c.c"/>
+ </Filter>
+ </Filter>
+ <Filter Name="folder2">
+ <File RelativePath="..\\folder2\\d.c"/>
+ </Filter>
+</Files>
+'''))
+
+
+test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/msvs/filters/gyptest-filters-2010.py
@@ -0,0 +1,57 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 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.
+
+"""
+Verifies that extra filters are pruned correctly for Visual Studio 2010
+and later.
+"""
+
+import TestGyp
+
+
+test = TestGyp.TestGyp(formats=['msvs'])
+
+test.run_gyp('filters.gyp', '-G', 'standalone', '-G', 'msvs_version=2010')
+
+test.must_not_exist('no_source_files.vcxproj.filters')
+
+test.must_not_exist('one_source_file.vcxproj.filters')
+
+test.must_not_exist('two_source_files.vcxproj.filters')
+
+test.must_contain('three_files_in_two_folders.vcxproj.filters', '''\
+ <ItemGroup>
+ <ClCompile Include="..\\folder1\\a.c">
+ <Filter>folder1</Filter>
+ </ClCompile>
+ <ClCompile Include="..\\folder1\\b.c">
+ <Filter>folder1</Filter>
+ </ClCompile>
+ <ClCompile Include="..\\folder2\\c.c">
+ <Filter>folder2</Filter>
+ </ClCompile>
+ </ItemGroup>
+'''.replace('\n', '\r\n'))
+
+test.must_contain('nested_folders.vcxproj.filters', '''\
+ <ItemGroup>
+ <ClCompile Include="..\\folder1\\nested\\a.c">
+ <Filter>folder1\\nested</Filter>
+ </ClCompile>
+ <ClCompile Include="..\\folder2\\d.c">
+ <Filter>folder2</Filter>
+ </ClCompile>
+ <ClCompile Include="..\\folder1\\nested\\b.c">
+ <Filter>folder1\\nested</Filter>
+ </ClCompile>
+ <ClCompile Include="..\\folder1\\other\\c.c">
+ <Filter>folder1\\other</Filter>
+ </ClCompile>
+ </ItemGroup>
+'''.replace('\n', '\r\n'))
+
+
+test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/msvs/list_excluded/hello.cpp
+++ b/media/webrtc/trunk/tools/gyp/test/msvs/list_excluded/hello.cpp
@@ -1,10 +1,10 @@
// Copyright (c) 2012 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>
-int main(int argc, char *argv[]) {
+int main(void) {
printf("Hello, world!\n");
return 0;
}
--- a/media/webrtc/trunk/tools/gyp/test/msvs/missing_sources/gyptest-missing.py
+++ b/media/webrtc/trunk/tools/gyp/test/msvs/missing_sources/gyptest-missing.py
@@ -6,36 +6,38 @@
"""
Verifies that missing 'sources' files are treated as fatal errors when the
the generator flag 'msvs_error_on_missing_sources' is set.
"""
import TestGyp
import os
-
-test = TestGyp.TestGyp(formats=['msvs'], workdir='workarea_all')
+import sys
-# With the flag not set
-test.run_gyp('hello_missing.gyp')
+if sys.platform == 'win32':
+ test = TestGyp.TestGyp(formats=['msvs', 'ninja'], workdir='workarea_all')
-# With the flag explicitly set to 0
-try:
- os.environ['GYP_GENERATOR_FLAGS'] = 'msvs_error_on_missing_sources=0'
+ # With the flag not set
test.run_gyp('hello_missing.gyp')
-finally:
- del os.environ['GYP_GENERATOR_FLAGS']
+
+ # With the flag explicitly set to 0
+ try:
+ os.environ['GYP_GENERATOR_FLAGS'] = 'msvs_error_on_missing_sources=0'
+ test.run_gyp('hello_missing.gyp')
+ finally:
+ del os.environ['GYP_GENERATOR_FLAGS']
-# With the flag explicitly set to 1
-try:
- os.environ['GYP_GENERATOR_FLAGS'] = 'msvs_error_on_missing_sources=1'
- # Test to make sure GYP raises an exception (exit status 1). Since this will
- # also print a backtrace, ensure that TestGyp is not checking that stderr is
- # empty by specifying None, which means do not perform any checking.
- # Instead, stderr is checked below to ensure it contains the expected
- # output.
- test.run_gyp('hello_missing.gyp', status=1, stderr=None)
-finally:
- del os.environ['GYP_GENERATOR_FLAGS']
-test.must_contain_any_line(test.stderr(),
- ["Missing input files:"])
+ # With the flag explicitly set to 1
+ try:
+ os.environ['GYP_GENERATOR_FLAGS'] = 'msvs_error_on_missing_sources=1'
+ # Test to make sure GYP raises an exception (exit status 1). Since this will
+ # also print a backtrace, ensure that TestGyp is not checking that stderr is
+ # empty by specifying None, which means do not perform any checking.
+ # Instead, stderr is checked below to ensure it contains the expected
+ # output.
+ test.run_gyp('hello_missing.gyp', status=1, stderr=None)
+ finally:
+ del os.environ['GYP_GENERATOR_FLAGS']
+ test.must_contain_any_line(test.stderr(),
+ ["Missing input files:"])
-test.pass_test()
\ No newline at end of file
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/msvs/multiple_actions_error_handling/action_fail.py
@@ -0,0 +1,7 @@
+# Copyright (c) 2014 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.
+
+import sys
+
+sys.exit(1)
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/msvs/multiple_actions_error_handling/action_succeed.py
@@ -0,0 +1,7 @@
+# Copyright (c) 2014 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.
+
+import sys
+
+sys.exit(0)
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/msvs/multiple_actions_error_handling/actions.gyp
@@ -0,0 +1,40 @@
+# Copyright (c) 2014 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': 'actions-test',
+ 'type': 'none',
+ 'actions': [
+ {
+ 'action_name': 'first action (fails)',
+ 'inputs': [
+ 'action_fail.py',
+ ],
+ 'outputs': [
+ 'ALWAYS_OUT_OF_DATE',
+ ],
+ 'action': [
+ 'python', '<@(_inputs)'
+ ],
+ 'msvs_cygwin_shell': 0,
+ },
+ {
+ 'action_name': 'second action (succeeds)',
+ 'inputs': [
+ 'action_succeed.py',
+ ],
+ 'outputs': [
+ 'ALWAYS_OUT_OF_DATE',
+ ],
+ 'action': [
+ 'python', '<@(_inputs)'
+ ],
+ 'msvs_cygwin_shell': 0,
+ },
+ ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/msvs/multiple_actions_error_handling/gyptest.py
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 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.
+
+"""
+Verifies that failing actions make the build fail reliably, even when there
+are multiple actions in one project.
+"""
+
+import os
+import sys
+import TestGyp
+import TestCmd
+
+test = TestGyp.TestGyp(formats=['msvs'], workdir='workarea_all')
+
+test.run_gyp('actions.gyp')
+test.build('actions.gyp',
+ target='actions-test',
+ status=1,
+ stdout=r'.*"cmd\.exe" exited with code 1\..*',
+ match=TestCmd.match_re_dotall)
+
+test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/msvs/props/hello.c
+++ b/media/webrtc/trunk/tools/gyp/test/msvs/props/hello.c
@@ -1,11 +1,11 @@
/* Copyright (c) 2012 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>
-int main(int argc, char *argv[])
+int main(void)
{
printf("Hello, world!\n");
return 0;
}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/msvs/rules_stdout_stderr/dummy.bar
@@ -0,0 +1,5 @@
+# Copyright (c) 2015 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.
+
+A dummy file with the .bar extension (used for stderr rule).
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/msvs/rules_stdout_stderr/dummy.foo
@@ -0,0 +1,5 @@
+# Copyright (c) 2015 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.
+
+A dummy file with the .foo extension (used for stdout rule).
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/msvs/rules_stdout_stderr/gyptest-rules-stdout-stderr.py
@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2015 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.
+
+""" Verifies that stdout and stderr from rules get logged in the build's
+stdout."""
+
+import sys
+import TestGyp
+
+if sys.platform == 'win32':
+ test = TestGyp.TestGyp(formats=['msvs'])
+
+ test.run_gyp('rules-stdout-stderr.gyp')
+ test.build('rules-stdout-stderr.gyp', test.ALL)
+
+ expected_stdout_lines = [
+ 'testing stdout',
+ 'This will go to stdout',
+
+ # Note: stderr output from rules will go to the build's stdout.
+ 'testing stderr',
+ 'This will go to stderr',
+ ]
+ test.must_contain_all_lines(test.stdout(), expected_stdout_lines)
+
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/msvs/rules_stdout_stderr/rule_stderr.py
@@ -0,0 +1,7 @@
+#!/usr/bin/env python
+# Copyright (c) 2015 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.
+
+import sys
+print >>sys.stderr, "This will go to stderr"
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/msvs/rules_stdout_stderr/rule_stdout.py
@@ -0,0 +1,6 @@
+#!/usr/bin/env python
+# Copyright (c) 2015 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.
+
+print "This will go to stdout"
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/msvs/rules_stdout_stderr/rules-stdout-stderr.gyp
@@ -0,0 +1,52 @@
+# Copyright (c) 2015 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': 'test',
+ 'type': 'none',
+ 'sources': [
+ 'dummy.foo',
+ 'dummy.bar',
+ ],
+ 'rules': [
+ {
+ 'rule_name': 'test_stdout',
+ 'extension': 'foo',
+ 'message': 'testing stdout',
+ 'msvs_cygwin_shell': 0,
+ 'inputs': [
+ 'rule_stdout.py',
+ ],
+ 'outputs': [
+ 'dummy.foo_output',
+ ],
+ 'action': [
+ 'python',
+ 'rule_stdout.py',
+ '<(RULE_INPUT_PATH)',
+ ],
+ },
+ {
+ 'rule_name': 'test_stderr',
+ 'extension': 'bar',
+ 'message': 'testing stderr',
+ 'msvs_cygwin_shell': 0,
+ 'inputs': [
+ 'rule_stderr.py',
+ ],
+ 'outputs': [
+ 'dummy.bar_output',
+ ],
+ 'action': [
+ 'python',
+ 'rule_stderr.py',
+ '<(RULE_INPUT_PATH)',
+ ],
+ },
+ ],
+ },
+ ],
+}
--- a/media/webrtc/trunk/tools/gyp/test/msvs/shared_output/hello.c
+++ b/media/webrtc/trunk/tools/gyp/test/msvs/shared_output/hello.c
@@ -1,12 +1,12 @@
/*
* Copyright (c) 2012 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>
-int main(int argc, char *argv[]) {
+int main(void) {
printf("Hello, world!\n");
return 0;
}
--- a/media/webrtc/trunk/tools/gyp/test/msvs/shared_output/there/there.c
+++ b/media/webrtc/trunk/tools/gyp/test/msvs/shared_output/there/there.c
@@ -1,12 +1,12 @@
/*
* Copyright (c) 2012 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>
-int main(int argc, char *argv[]) {
+int main(void) {
printf("Hello, world!\n");
return 0;
}
--- a/media/webrtc/trunk/tools/gyp/test/msvs/uldi2010/hello.c
+++ b/media/webrtc/trunk/tools/gyp/test/msvs/uldi2010/hello.c
@@ -1,13 +1,13 @@
/* Copyright (c) 2012 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 hello2();
-int main(int argc, char *argv[]) {
+int main(void) {
printf("Hello, world!\n");
hello2();
return 0;
}
--- a/media/webrtc/trunk/tools/gyp/test/multiple-targets/gyptest-all.py
+++ b/media/webrtc/trunk/tools/gyp/test/multiple-targets/gyptest-all.py
@@ -1,27 +1,22 @@
#!/usr/bin/env python
# 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.
-"""
-"""
-
import TestGyp
test = TestGyp.TestGyp()
test.run_gyp('multiple.gyp', chdir='src')
test.relocate('src', 'relocate/src')
-# TODO(sgk): remove stderr=None when the --generator-output= support
-# gets rid of the scons warning
test.build('multiple.gyp', test.ALL, chdir='relocate/src', stderr=None)
expect1 = """\
hello from prog1.c
hello from common.c
"""
expect2 = """\
--- a/media/webrtc/trunk/tools/gyp/test/multiple-targets/gyptest-default.py
+++ b/media/webrtc/trunk/tools/gyp/test/multiple-targets/gyptest-default.py
@@ -1,28 +1,23 @@
#!/usr/bin/env python
# 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.
-"""
-"""
-
import TestGyp
test = TestGyp.TestGyp()
test.run_gyp('multiple.gyp', chdir='src')
test.relocate('src', 'relocate/src')
-# TODO(sgk): remove stderr=None when the --generator-output= support
-# gets rid of the scons warning
-test.build('multiple.gyp', chdir='relocate/src', stderr=None)
+test.build('multiple.gyp', chdir='relocate/src')
expect1 = """\
hello from prog1.c
hello from common.c
"""
expect2 = """\
hello from prog2.c
--- a/media/webrtc/trunk/tools/gyp/test/multiple-targets/src/prog1.c
+++ b/media/webrtc/trunk/tools/gyp/test/multiple-targets/src/prog1.c
@@ -1,10 +1,10 @@
#include <stdio.h>
extern void common(void);
-int main(int argc, char *argv[])
+int main(void)
{
printf("hello from prog1.c\n");
common();
return 0;
}
--- a/media/webrtc/trunk/tools/gyp/test/multiple-targets/src/prog2.c
+++ b/media/webrtc/trunk/tools/gyp/test/multiple-targets/src/prog2.c
@@ -1,10 +1,10 @@
#include <stdio.h>
extern void common(void);
-int main(int argc, char *argv[])
+int main(void)
{
printf("hello from prog2.c\n");
common();
return 0;
}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ninja/action-rule-hash/gyptest-action-rule-hash.py
@@ -0,0 +1,32 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 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 running gyp in a different directory does not cause actions and
+rules to rerun.
+"""
+
+import os
+import sys
+import TestGyp
+
+test = TestGyp.TestGyp(formats=['ninja'])
+# The xcode-ninja generator handles gypfiles which are not at the
+# project root incorrectly.
+# cf. https://code.google.com/p/gyp/issues/detail?id=460
+if test.format == 'xcode-ninja':
+ test.skip_test()
+
+test.run_gyp('subdir/action-rule-hash.gyp')
+test.build('subdir/action-rule-hash.gyp', test.ALL)
+test.up_to_date('subdir/action-rule-hash.gyp')
+
+# Verify that everything is still up-to-date when we re-invoke gyp from a
+# different directory.
+test.run_gyp('action-rule-hash.gyp', '--depth=../', chdir='subdir')
+test.up_to_date('subdir/action-rule-hash.gyp')
+
+test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ninja/action-rule-hash/subdir/action-rule-hash.gyp
@@ -0,0 +1,29 @@
+# Copyright (c) 2014 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': 'program',
+ 'type': 'executable',
+ 'sources': [
+ '<(INTERMEDIATE_DIR)/main.cc',
+ ],
+ 'actions': [
+ {
+ 'action_name': 'emit_main_cc',
+ 'inputs': ['emit.py'],
+ 'outputs': ['<(INTERMEDIATE_DIR)/main.cc'],
+ 'action': [
+ 'python',
+ 'emit.py',
+ '<(INTERMEDIATE_DIR)/main.cc',
+ ],
+ # Allows the test to run without hermetic cygwin on windows.
+ 'msvs_cygwin_shell': 0,
+ },
+ ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ninja/action-rule-hash/subdir/emit.py
@@ -0,0 +1,13 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 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.
+
+import sys
+
+f = open(sys.argv[1], 'wb')
+f.write('int main() {\n')
+f.write(' return 0;\n')
+f.write('}\n')
+f.close()
--- a/media/webrtc/trunk/tools/gyp/test/ninja/action_dependencies/gyptest-action-dependencies.py
+++ b/media/webrtc/trunk/tools/gyp/test/ninja/action_dependencies/gyptest-action-dependencies.py
@@ -6,26 +6,35 @@
"""
Verify that building an object file correctly depends on running actions in
dependent targets, but not the targets themselves.
"""
import os
import sys
+
+if sys.platform == 'win32':
+ print "This test is currently disabled: https://crbug.com/483696."
+ sys.exit(0)
+
+
import TestGyp
# NOTE(piman): This test will not work with other generators because:
# - it explicitly tests the optimization, which is not implemented (yet?) on
# other generators
# - it relies on the exact path to output object files, which is generator
# dependent, and actually, relies on the ability to build only that object file,
# which I don't think is available on all generators.
# TODO(piman): Extend to other generators when possible.
test = TestGyp.TestGyp(formats=['ninja'])
+# xcode-ninja doesn't support building single object files by design.
+if test.format == 'xcode-ninja':
+ test.skip_test()
test.run_gyp('action_dependencies.gyp', chdir='src')
chdir = 'relocate/src'
test.relocate('src', chdir)
objext = '.obj' if sys.platform == 'win32' else '.o'
--- a/media/webrtc/trunk/tools/gyp/test/ninja/chained-dependency/chained.c
+++ b/media/webrtc/trunk/tools/gyp/test/ninja/chained-dependency/chained.c
@@ -1,5 +1,5 @@
#include "generated/header.h"
-int main(int argc, char** argv) {
+int main(void) {
return 0;
}
--- a/media/webrtc/trunk/tools/gyp/test/ninja/chained-dependency/gyptest-chained-dependency.py
+++ b/media/webrtc/trunk/tools/gyp/test/ninja/chained-dependency/gyptest-chained-dependency.py
@@ -13,14 +13,18 @@ import os
import sys
import TestGyp
# This test is Ninja-specific in that:
# - the bug only showed nondeterministically in parallel builds;
# - it relies on a ninja-specific output file path.
test = TestGyp.TestGyp(formats=['ninja'])
+# xcode-ninja doesn't support building single object files by design.
+if test.format == 'xcode-ninja':
+ test.skip_test()
+
test.run_gyp('chained-dependency.gyp')
objext = '.obj' if sys.platform == 'win32' else '.o'
test.build('chained-dependency.gyp',
os.path.join('obj', 'chained.chained' + objext))
# The test passes if the .o file builds successfully.
test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ninja/empty-and-non-empty-duplicate-name/gyptest-empty-and-non-empty-duplicate-name.py
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 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.
+
+"""
+Verifies a phony target isn't output if a target exists with the same name that
+was output.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp(formats=['ninja'])
+
+# Reset xcode_ninja_target_pattern to its default for this test.
+test.run_gyp('test.gyp', '-G', 'xcode_ninja_target_pattern=^$')
+
+# Check for both \r and \n to cover both windows and linux.
+test.must_not_contain('out/Default/build.ninja', 'build empty_target: phony\r')
+test.must_not_contain('out/Default/build.ninja', 'build empty_target: phony\n')
+
+test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ninja/empty-and-non-empty-duplicate-name/subdir/included.gyp
@@ -0,0 +1,19 @@
+# Copyright (c) 2014 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': 'empty_target',
+ 'type': 'executable',
+ 'sources': [
+ 'test.cc',
+ ],
+ },
+ {
+ 'target_name': 'included_empty_target',
+ 'type': 'none',
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ninja/empty-and-non-empty-duplicate-name/test.gyp
@@ -0,0 +1,19 @@
+# Copyright (c) 2014 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': 'All',
+ 'type': 'none',
+ 'dependencies': [
+ 'subdir/included.gyp:included_empty_target'
+ ]
+ },
+ {
+ 'target_name': 'empty_target',
+ 'type': 'none',
+ },
+ ],
+}
--- a/media/webrtc/trunk/tools/gyp/test/ninja/normalize-paths-win/gyptest-normalize-paths.py
+++ b/media/webrtc/trunk/tools/gyp/test/ninja/normalize-paths-win/gyptest-normalize-paths.py
@@ -26,16 +26,20 @@ if sys.platform == 'win32':
if 'out\\Default' in subninja:
test.fail_test()
second = open(test.built_file_path('obj/second.ninja')).read()
if ('..\\..\\things\\AnotherName.exe' in second or
'AnotherName.exe' not in second):
test.fail_test()
+ copytarget = open(test.built_file_path('obj/copy_target.ninja')).read()
+ if '$(VSInstallDir)' in copytarget:
+ test.fail_test()
+
action = open(test.built_file_path('obj/action.ninja')).read()
if '..\\..\\out\\Default' in action:
test.fail_test()
if '..\\..\\SomethingElse' in action or 'SomethingElse' not in action:
test.fail_test()
if '..\\..\\SomeOtherInput' in action or 'SomeOtherInput' not in action:
test.fail_test()
--- a/media/webrtc/trunk/tools/gyp/test/ninja/normalize-paths-win/normalize-paths.gyp
+++ b/media/webrtc/trunk/tools/gyp/test/ninja/normalize-paths-win/normalize-paths.gyp
@@ -25,16 +25,28 @@
'OutputFile': '$(OutDir)\\things\\AnotherName.exe',
},
},
'sources': [
'HeLLo.cc',
],
},
{
+ 'target_name': 'Copy_Target',
+ 'type': 'none',
+ 'copies': [
+ {
+ 'destination': '<(PRODUCT_DIR)',
+ 'files': [
+ '$(VSInstallDir)\\bin\\cl.exe',
+ ],
+ },
+ ],
+ },
+ {
'target_name': 'action',
'type': 'none',
'msvs_cygwin_shell': '0',
'actions': [
{
'inputs': [
'$(IntDir)\\SomeInput',
'$(OutDir)\\SomeOtherInput',
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ninja/s-needs-no-depfiles/empty.s
@@ -0,0 +1,1 @@
+# This file intentionally left blank.
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ninja/s-needs-no-depfiles/gyptest-s-needs-no-depfiles.py
@@ -0,0 +1,42 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 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 .s files don't always trigger a rebuild, as would happen if depfiles
+were used for them (since clang & gcc ignore -MMD when building .s->.o on
+linux).
+"""
+
+import os
+import sys
+import TestCommon
+import TestGyp
+
+# NOTE(fischman): Each generator uses depfiles (or not) differently, so this is
+# a ninja-specific test.
+test = TestGyp.TestGyp(formats=['ninja'])
+
+if sys.platform == 'win32' or sys.platform == 'win64':
+ # This test is about clang/gcc vs. depfiles; VS gets a pass.
+ test.pass_test()
+ sys.exit(0)
+
+test.run_gyp('s-needs-no-depfiles.gyp')
+
+# Build the library, grab its timestamp, rebuild the library, ensure timestamp
+# hasn't changed.
+test.build('s-needs-no-depfiles.gyp', 'empty')
+empty_dll = test.built_file_path('empty', test.SHARED_LIB)
+test.built_file_must_exist(empty_dll)
+pre_stat = os.stat(test.built_file_path(empty_dll))
+test.sleep()
+test.build('s-needs-no-depfiles.gyp', 'empty')
+post_stat = os.stat(test.built_file_path(empty_dll))
+
+if pre_stat.st_mtime != post_stat.st_mtime:
+ test.fail_test()
+else:
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ninja/s-needs-no-depfiles/s-needs-no-depfiles.gyp
@@ -0,0 +1,13 @@
+# Copyright (c) 2012 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': 'empty',
+ 'type': 'shared_library',
+ 'sources': [ 'empty.s' ],
+ },
+ ],
+}
--- a/media/webrtc/trunk/tools/gyp/test/ninja/solibs_avoid_relinking/gyptest-solibs-avoid-relinking.py
+++ b/media/webrtc/trunk/tools/gyp/test/ninja/solibs_avoid_relinking/gyptest-solibs-avoid-relinking.py
@@ -17,16 +17,21 @@ import TestGyp
# NOTE(fischman): This test will not work with other generators because the
# API-hash-based-mtime-preservation optimization is only implemented in
# ninja.py. It could be extended to the make.py generator as well pretty
# easily, probably.
# (also, it tests ninja-specific out paths, which would have to be generalized
# if this was extended to other generators).
test = TestGyp.TestGyp(formats=['ninja'])
+if not os.environ.get('ProgramFiles(x86)'):
+ # TODO(scottmg)
+ print 'Skipping test on x86, http://crbug.com/365833'
+ test.pass_test()
+
test.run_gyp('solibs_avoid_relinking.gyp')
# Build the executable, grab its timestamp, touch the solib's source, rebuild
# executable, ensure timestamp hasn't changed.
test.build('solibs_avoid_relinking.gyp', 'b')
test.built_file_must_exist('b' + TestCommon.exe_suffix)
pre_stat = os.stat(test.built_file_path('b' + TestCommon.exe_suffix))
os.utime(os.path.join(test.workdir, 'solib.cc'),
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ninja/use-console/foo.bar
@@ -0,0 +1,5 @@
+# Copyright (c) 2014 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.
+
+This is a dummy file for rule/action input.
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ninja/use-console/gyptest-use-console.py
@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 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.
+
+"""
+Make sure 'ninja_use_console' is supported in actions and rules.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp(formats=['ninja'])
+
+test.run_gyp('use-console.gyp')
+
+no_pool = open(test.built_file_path('obj/no_pool.ninja')).read()
+if 'pool =' in no_pool:
+ test.fail_test()
+
+action_pool = open(test.built_file_path('obj/action_pool.ninja')).read()
+if 'pool = console' not in action_pool:
+ test.fail_test()
+
+rule_pool = open(test.built_file_path('obj/rule_pool.ninja')).read()
+if 'pool = console' not in rule_pool:
+ test.fail_test()
+
+test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ninja/use-console/use-console.gyp
@@ -0,0 +1,60 @@
+# Copyright (c) 2014 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': 'no_pool',
+ 'type': 'none',
+ 'actions': [
+ {
+ 'action_name': 'some_action',
+ 'action': ['echo', 'hello'],
+ 'inputs': ['foo.bar'],
+ 'outputs': ['dummy'],
+ },
+ ],
+ 'rules': [
+ {
+ 'rule_name': 'some_rule',
+ 'extension': 'bar',
+ 'action': ['echo', 'hello'],
+ 'outputs': ['dummy'],
+ },
+ ],
+ 'sources': [
+ 'foo.bar',
+ ],
+ },
+ {
+ 'target_name': 'action_pool',
+ 'type': 'none',
+ 'actions': [
+ {
+ 'action_name': 'some_action',
+ 'action': ['echo', 'hello'],
+ 'inputs': ['foo.bar'],
+ 'outputs': ['dummy'],
+ 'ninja_use_console': 1,
+ },
+ ],
+ },
+ {
+ 'target_name': 'rule_pool',
+ 'type': 'none',
+ 'rules': [
+ {
+ 'rule_name': 'some_rule',
+ 'extension': 'bar',
+ 'action': ['echo', 'hello'],
+ 'outputs': ['dummy'],
+ 'ninja_use_console': 1,
+ },
+ ],
+ 'sources': [
+ 'foo.bar',
+ ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ninja/use-custom-environment-files/gyptest-use-custom-environment-files.py
@@ -0,0 +1,28 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 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.
+
+"""
+Make sure environment files can be suppressed.
+"""
+
+import TestGyp
+
+import os
+import sys
+
+if sys.platform == 'win32':
+ test = TestGyp.TestGyp(formats=['ninja'])
+
+ test.run_gyp('use-custom-environment-files.gyp',
+ '-G', 'ninja_use_custom_environment_files')
+
+ # Make sure environment files do not exist.
+ if os.path.exists(test.built_file_path('environment.x86')):
+ test.fail_test()
+ if os.path.exists(test.built_file_path('environment.x64')):
+ test.fail_test()
+
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ninja/use-custom-environment-files/use-custom-environment-files.cc
@@ -0,0 +1,7 @@
+// Copyright (c) 2012 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 main() {
+ return 0;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/ninja/use-custom-environment-files/use-custom-environment-files.gyp
@@ -0,0 +1,15 @@
+# Copyright (c) 2010 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': 'test_use_custom_environment_files',
+ 'type': 'executable',
+ 'sources': [
+ 'use-custom-environment-files.cc',
+ ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/no-cpp/gyptest-no-cpp.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 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.
+
+"""
+Checks that C-only targets aren't linked against libstdc++.
+"""
+
+import TestGyp
+
+import re
+import subprocess
+import sys
+
+# set |match| to ignore build stderr output.
+test = TestGyp.TestGyp(match = lambda a, b: True)
+if sys.platform != 'win32' and test.format != 'make':
+ # TODO: This doesn't pass with make.
+ # TODO: Does a test like this make sense with Windows?
+
+ CHDIR = 'src'
+ test.run_gyp('test.gyp', chdir=CHDIR)
+ test.build('test.gyp', 'no_cpp', chdir=CHDIR)
+
+ def LinksLibStdCpp(path):
+ path = test.built_file_path(path, chdir=CHDIR)
+ if sys.platform == 'darwin':
+ proc = subprocess.Popen(['otool', '-L', path], stdout=subprocess.PIPE)
+ else:
+ proc = subprocess.Popen(['ldd', path], stdout=subprocess.PIPE)
+ output = proc.communicate()[0]
+ assert not proc.returncode
+ return 'libstdc++' in output or 'libc++' in output
+
+ if LinksLibStdCpp('no_cpp'):
+ test.fail_test()
+
+ build_error_code = {
+ 'xcode': [1, 65], # 1 for xcode 3, 65 for xcode 4 (see `man sysexits`)
+ 'make': 2,
+ 'ninja': 1,
+ 'cmake': 0, # CMake picks the compiler driver based on transitive checks.
+ 'xcode-ninja': [1, 65],
+ }[test.format]
+
+ test.build('test.gyp', 'no_cpp_dep_on_cc_lib', chdir=CHDIR,
+ status=build_error_code)
+
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/no-cpp/src/call-f-main.c
@@ -0,0 +1,2 @@
+void* f();
+int main() { f(); }
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/no-cpp/src/empty-main.c
@@ -0,0 +1,1 @@
+int main() {}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/no-cpp/src/f.cc
@@ -0,0 +1,3 @@
+extern "C" { void* f(); }
+
+void* f() { return new int; }
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/no-cpp/src/test.gyp
@@ -0,0 +1,25 @@
+# Copyright (c) 2013 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': 'no_cpp',
+ 'type': 'executable',
+ 'sources': [ 'empty-main.c' ],
+ },
+ # A static_library with a cpp file and a linkable with only .c files
+ # depending on it causes a linker error:
+ {
+ 'target_name': 'cpp_lib',
+ 'type': 'static_library',
+ 'sources': [ 'f.cc' ],
+ },
+ {
+ 'target_name': 'no_cpp_dep_on_cc_lib',
+ 'type': 'executable',
+ 'dependencies': [ 'cpp_lib' ],
+ 'sources': [ 'call-f-main.c' ],
+ },
+ ],
+}
--- a/media/webrtc/trunk/tools/gyp/test/product/gyptest-product.py
+++ b/media/webrtc/trunk/tools/gyp/test/product/gyptest-product.py
@@ -6,18 +6,17 @@
"""
Verifies simplest-possible build of a "Hello, world!" program
using the default build target.
"""
import TestGyp
-# Android does not support setting the build directory.
-test = TestGyp.TestGyp(formats=['!android'])
+test = TestGyp.TestGyp()
test.run_gyp('product.gyp')
test.build('product.gyp')
# executables
test.built_file_must_exist('alt1' + test._exe, test.EXECUTABLE, bare=True)
test.built_file_must_exist('hello2.stuff', test.EXECUTABLE, bare=True)
test.built_file_must_exist('yoalt3.stuff', test.EXECUTABLE, bare=True)
--- a/media/webrtc/trunk/tools/gyp/test/product/hello.c
+++ b/media/webrtc/trunk/tools/gyp/test/product/hello.c
@@ -3,13 +3,13 @@
* found in the LICENSE file. */
#include <stdio.h>
int func1(void) {
return 42;
}
-int main(int argc, char *argv[]) {
+int main(void) {
printf("Hello, world!\n");
printf("%d\n", func1());
return 0;
}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/prune_targets/gyptest-prune-targets.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 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.
+
+"""
+Verifies --root-target removes the unnecessary targets.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+# The xcode-ninja generator has its own logic for which targets to include
+if test.format == 'xcode-ninja':
+ test.skip_test()
+
+build_error_code = {
+ 'cmake': 1,
+ 'make': 2,
+ 'msvs': 1,
+ 'ninja': 1,
+ 'xcode': 65,
+}[test.format]
+
+# By default, everything will be included.
+test.run_gyp('test1.gyp')
+test.build('test2.gyp', 'lib1')
+test.build('test2.gyp', 'lib2')
+test.build('test2.gyp', 'lib3')
+test.build('test2.gyp', 'lib_indirect')
+test.build('test1.gyp', 'program1')
+test.build('test1.gyp', 'program2')
+test.build('test1.gyp', 'program3')
+
+# With deep dependencies of program1 only.
+test.run_gyp('test1.gyp', '--root-target=program1')
+test.build('test2.gyp', 'lib1')
+test.build('test2.gyp', 'lib2', status=build_error_code, stderr=None)
+test.build('test2.gyp', 'lib3', status=build_error_code, stderr=None)
+test.build('test2.gyp', 'lib_indirect')
+test.build('test1.gyp', 'program1')
+test.build('test1.gyp', 'program2', status=build_error_code, stderr=None)
+test.build('test1.gyp', 'program3', status=build_error_code, stderr=None)
+
+# With deep dependencies of program2 only.
+test.run_gyp('test1.gyp', '--root-target=program2')
+test.build('test2.gyp', 'lib1', status=build_error_code, stderr=None)
+test.build('test2.gyp', 'lib2')
+test.build('test2.gyp', 'lib3', status=build_error_code, stderr=None)
+test.build('test2.gyp', 'lib_indirect')
+test.build('test1.gyp', 'program1', status=build_error_code, stderr=None)
+test.build('test1.gyp', 'program2')
+test.build('test1.gyp', 'program3', status=build_error_code, stderr=None)
+
+# With deep dependencies of program1 and program2.
+test.run_gyp('test1.gyp', '--root-target=program1', '--root-target=program2')
+test.build('test2.gyp', 'lib1')
+test.build('test2.gyp', 'lib2')
+test.build('test2.gyp', 'lib3', status=build_error_code, stderr=None)
+test.build('test2.gyp', 'lib_indirect')
+test.build('test1.gyp', 'program1')
+test.build('test1.gyp', 'program2')
+test.build('test1.gyp', 'program3', status=build_error_code, stderr=None)
+
+test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/prune_targets/lib1.cc
@@ -0,0 +1,6 @@
+// Copyright (c) 2013 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.
+
+void libfunc1() {
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/prune_targets/lib2.cc
@@ -0,0 +1,6 @@
+// Copyright (c) 2013 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.
+
+void libfunc2() {
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/prune_targets/lib3.cc
@@ -0,0 +1,6 @@
+// Copyright (c) 2013 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.
+
+void libfunc3() {
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/prune_targets/lib_indirect.cc
@@ -0,0 +1,6 @@
+// Copyright (c) 2013 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.
+
+void libfunc_indirect() {
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/prune_targets/program.cc
@@ -0,0 +1,7 @@
+// Copyright (c) 2013 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 main() {
+ return 0;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/prune_targets/test1.gyp
@@ -0,0 +1,26 @@
+# Copyright (c) 2013 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': 'program1',
+ 'type': 'executable',
+ 'sources': [ 'program.cc' ],
+ 'dependencies': [ 'test2.gyp:lib1' ],
+ },
+ {
+ 'target_name': 'program2',
+ 'type': 'executable',
+ 'sources': [ 'program.cc' ],
+ 'dependencies': [ 'test2.gyp:lib2' ],
+ },
+ {
+ 'target_name': 'program3',
+ 'type': 'executable',
+ 'sources': [ 'program.cc' ],
+ 'dependencies': [ 'test2.gyp:lib3' ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/prune_targets/test2.gyp
@@ -0,0 +1,30 @@
+# Copyright (c) 2013 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': 'lib1',
+ 'type': 'static_library',
+ 'sources': [ 'lib1.cc' ],
+ 'dependencies': [ 'lib_indirect' ],
+ },
+ {
+ 'target_name': 'lib2',
+ 'type': 'static_library',
+ 'sources': [ 'lib2.cc' ],
+ 'dependencies': [ 'lib_indirect' ],
+ },
+ {
+ 'target_name': 'lib3',
+ 'type': 'static_library',
+ 'sources': [ 'lib3.cc' ],
+ },
+ {
+ 'target_name': 'lib_indirect',
+ 'type': 'static_library',
+ 'sources': [ 'lib_indirect.cc' ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/rename/filecase/file.c
@@ -0,0 +1,1 @@
+int main() { return 0; }
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/rename/filecase/test-casesensitive.gyp
@@ -0,0 +1,15 @@
+# Copyright (c) 2012 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': 'filecaserename_sensitive',
+ 'type': 'executable',
+ 'sources': [
+ 'FiLe.c',
+ 'fIlE.c',
+ ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/rename/filecase/test.gyp
@@ -0,0 +1,14 @@
+# Copyright (c) 2012 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': 'filecaserename',
+ 'type': 'executable',
+ 'sources': [
+ 'file.c',
+ ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/rename/gyptest-filecase.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 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.
+
+"""
+Checks that files whose file case changes get rebuilt correctly.
+"""
+
+import os
+import TestGyp
+
+test = TestGyp.TestGyp()
+CHDIR = 'filecase'
+test.run_gyp('test.gyp', chdir=CHDIR)
+test.build('test.gyp', test.ALL, chdir=CHDIR)
+
+os.rename('filecase/file.c', 'filecase/fIlE.c')
+test.write('filecase/test.gyp',
+ test.read('filecase/test.gyp').replace('file.c', 'fIlE.c'))
+test.run_gyp('test.gyp', chdir=CHDIR)
+test.build('test.gyp', test.ALL, chdir=CHDIR)
+
+
+# Check that having files that differ just in their case still work on
+# case-sensitive file systems.
+test.write('filecase/FiLe.c', 'int f(); int main() { return f(); }')
+test.write('filecase/fIlE.c', 'int f() { return 42; }')
+is_case_sensitive = test.read('filecase/FiLe.c') != test.read('filecase/fIlE.c')
+if is_case_sensitive:
+ test.run_gyp('test-casesensitive.gyp', chdir=CHDIR)
+ test.build('test-casesensitive.gyp', test.ALL, chdir=CHDIR)
+
+test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/rules-dirname/gyptest-dirname.py
+++ b/media/webrtc/trunk/tools/gyp/test/rules-dirname/gyptest-dirname.py
@@ -4,35 +4,52 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""
Verifies simple rules when using an explicit build target of 'all'.
"""
import TestGyp
+import os
+import sys
-test = TestGyp.TestGyp(formats=['make', 'ninja', 'xcode'])
+if sys.platform == 'win32':
+ print "This test is currently disabled: https://crbug.com/483696."
+ sys.exit(0)
+
+
+test = TestGyp.TestGyp(formats=['make', 'ninja', 'xcode', 'msvs'])
test.run_gyp('actions.gyp', chdir='src')
test.relocate('src', 'relocate/src')
test.build('actions.gyp', chdir='relocate/src')
expect = """\
+no dir here
hi c
hello baz
"""
if test.format == 'xcode':
chdir = 'relocate/src/subdir'
else:
chdir = 'relocate/src'
test.run_built_executable('gencc_int_output', chdir=chdir, stdout=expect)
+if test.format == 'msvs':
+ test.run_built_executable('gencc_int_output_external', chdir=chdir,
+ stdout=expect)
-if test.format == 'msvs':
- test.must_exist('relocate/src/subdir/foo/bar/baz.printed')
- test.must_exist('relocate/src/subdir/a/b/c.printed')
-else:
- test.must_match('relocate/src/subdir/foo/bar/baz.printed', 'foo/bar')
- test.must_match('relocate/src/subdir/a/b/c.printed', 'a/b')
+test.must_match('relocate/src/subdir/foo/bar/baz.dirname',
+ os.path.join('foo', 'bar'))
+test.must_match('relocate/src/subdir/a/b/c.dirname',
+ os.path.join('a', 'b'))
+
+# FIXME the xcode and make generators incorrectly convert RULE_INPUT_PATH
+# to an absolute path, making the tests below fail!
+if test.format != 'xcode' and test.format != 'make':
+ test.must_match('relocate/src/subdir/foo/bar/baz.path',
+ os.path.join('foo', 'bar', 'baz.printvars'))
+ test.must_match('relocate/src/subdir/a/b/c.path',
+ os.path.join('a', 'b', 'c.printvars'))
test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/rules-dirname/src/subdir/a/b/c.gencc
+++ b/media/webrtc/trunk/tools/gyp/test/rules-dirname/src/subdir/a/b/c.gencc
@@ -1,11 +1,8 @@
// -*- mode: c++ -*-
-#include <iostream>
-
-using std::cout;
-using std::endl;
+#include <stdio.h>
namespace gen {
void c() {
- cout << "hi c" << endl;
+ printf("hi c\n");
}
}
--- a/media/webrtc/trunk/tools/gyp/test/rules-dirname/src/subdir/foo/bar/baz.gencc
+++ b/media/webrtc/trunk/tools/gyp/test/rules-dirname/src/subdir/foo/bar/baz.gencc
@@ -1,11 +1,8 @@
// -*- mode: c++ -*-
-#include <iostream>
-
-using std::cout;
-using std::endl;
+#include <stdio.h>
namespace gen {
void baz() {
- cout << "hello baz" << endl;
+ printf("hello baz\n");
}
}
--- a/media/webrtc/trunk/tools/gyp/test/rules-dirname/src/subdir/input-rule-dirname.gyp
+++ b/media/webrtc/trunk/tools/gyp/test/rules-dirname/src/subdir/input-rule-dirname.gyp
@@ -1,78 +1,126 @@
# 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.
{
'targets': [
{
+ 'target_name': 'print_rule_input_dirname',
+ 'type': 'none',
+ 'msvs_cygwin_shell': 0,
+ 'sources': [
+ 'foo/bar/baz.printvars',
+ 'a/b/c.printvars',
+ ],
+ 'rules': [
+ {
+ 'rule_name': 'printvars',
+ 'extension': 'printvars',
+ 'inputs': [
+ 'printvars.py',
+ ],
+ 'outputs': [
+ '<(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT).dirname',
+ ],
+ 'action': [
+ 'python', '<@(_inputs)', '<(RULE_INPUT_DIRNAME)', '<@(_outputs)',
+ ],
+ },
+ ],
+ },
+ {
'target_name': 'print_rule_input_path',
'type': 'none',
'msvs_cygwin_shell': 0,
'sources': [
'foo/bar/baz.printvars',
'a/b/c.printvars',
],
'rules': [
{
'rule_name': 'printvars',
'extension': 'printvars',
'inputs': [
'printvars.py',
],
'outputs': [
- '<(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT).printed',
+ '<(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT).path',
],
'action': [
- 'python', '<@(_inputs)', '<(RULE_INPUT_DIRNAME)', '<@(_outputs)',
+ 'python', '<@(_inputs)', '<(RULE_INPUT_PATH)', '<@(_outputs)',
],
},
- ],
+ ],
},
{
'target_name': 'gencc_int_output',
'type': 'executable',
'msvs_cygwin_shell': 0,
- 'msvs_cygwin_dirs': ['../../../../../../<(DEPTH)/third_party/cygwin'],
'sources': [
+ 'nodir.gencc',
'foo/bar/baz.gencc',
'a/b/c.gencc',
- 'main.cc',
- ],
- 'conditions': [
- ['OS=="win"', {
- 'dependencies': [
- 'cygwin',
- ],
- }],
+ 'main.cc',
],
'rules': [
{
'rule_name': 'gencc',
'extension': 'gencc',
- 'msvs_external_rule': 1,
'inputs': [
'<(DEPTH)/copy-file.py',
],
'outputs': [
'<(INTERMEDIATE_DIR)/<(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT).cc',
],
'action': [
'python', '<@(_inputs)', '<(RULE_INPUT_PATH)', '<@(_outputs)',
],
'process_outputs_as_sources': 1,
},
- ],
+ ],
},
],
'conditions': [
['OS=="win"', {
'targets': [
{
+ 'target_name': 'gencc_int_output_external',
+ 'type': 'executable',
+ 'msvs_cygwin_shell': 0,
+ 'msvs_cygwin_dirs': ['../../../../../../<(DEPTH)/third_party/cygwin'],
+ 'sources': [
+ 'nodir.gencc',
+ 'foo/bar/baz.gencc',
+ 'a/b/c.gencc',
+ 'main.cc',
+ ],
+ 'dependencies': [
+ 'cygwin',
+ ],
+ 'rules': [
+ {
+ 'rule_name': 'gencc',
+ 'extension': 'gencc',
+ 'msvs_external_rule': 1,
+ 'inputs': [
+ '<(DEPTH)/copy-file.py',
+ ],
+ 'outputs': [
+ '<(INTERMEDIATE_DIR)/<(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT).cc',
+ ],
+ 'action': [
+ 'python', '<@(_inputs)', '<(RULE_INPUT_PATH)', '<@(_outputs)',
+ ],
+ 'process_outputs_as_sources': 1,
+ },
+ ],
+ },
+ {
'target_name': 'cygwin',
'type': 'none',
'actions': [
{
'action_name': 'setup_mount',
'msvs_cygwin_shell': 0,
'inputs': [
'../../../../../../<(DEPTH)/third_party/cygwin/setup_mount.bat',
--- a/media/webrtc/trunk/tools/gyp/test/rules-dirname/src/subdir/main.cc
+++ b/media/webrtc/trunk/tools/gyp/test/rules-dirname/src/subdir/main.cc
@@ -1,12 +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.
namespace gen {
+ extern void nodir();
extern void c();
extern void baz();
}
int main() {
+ gen::nodir();
gen::c();
gen::baz();
}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/rules-dirname/src/subdir/nodir.gencc
@@ -0,0 +1,8 @@
+// -*- mode: c++ -*-
+#include <stdio.h>
+
+namespace gen {
+ void nodir() {
+ printf("no dir here\n");
+ }
+}
--- a/media/webrtc/trunk/tools/gyp/test/rules-rebuild/src/main.c
+++ b/media/webrtc/trunk/tools/gyp/test/rules-rebuild/src/main.c
@@ -1,12 +1,12 @@
#include <stdio.h>
extern void prog1(void);
extern void prog2(void);
-int main(int argc, char *argv[])
+int main(void)
{
printf("Hello from main.c\n");
prog1();
prog2();
return 0;
}
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/rules-use-built-dependencies/gyptest-use-built-dependencies.py
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 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.
+
+"""
+Verifies that rules which use built dependencies work correctly.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('use-built-dependencies-rule.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+test.build('use-built-dependencies-rule.gyp', chdir='relocate/src')
+
+test.built_file_must_exist('main_output', chdir='relocate/src')
+test.built_file_must_match('main_output', 'output', chdir='relocate/src')
+
+test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/rules-use-built-dependencies/src/main.cc
@@ -0,0 +1,17 @@
+// Copyright (c) 2013 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>
+
+int main(int argc, char *argv[]) {
+ if (argc < 2) {
+ return 2;
+ }
+ FILE* file;
+ file = fopen(argv[1], "wb");
+ const char output[] = "output";
+ fwrite(output, 1, sizeof(output) - 1, file);
+ fclose(file);
+ return 0;
+}
+
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/rules-use-built-dependencies/src/use-built-dependencies-rule.gyp
@@ -0,0 +1,42 @@
+# Copyright (c) 2013 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': 'main',
+ 'toolsets': ['host'],
+ 'type': 'executable',
+ 'sources': [
+ 'main.cc',
+ ],
+ },
+ {
+ 'target_name': 'post',
+ 'toolsets': ['host'],
+ 'type': 'none',
+ 'dependencies': [
+ 'main',
+ ],
+ 'sources': [
+ # As this test is written it could easily be made into an action.
+ # An acutal use case would have a number of these 'sources'.
+ '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)main<(EXECUTABLE_SUFFIX)',
+ ],
+ 'rules': [
+ {
+ 'rule_name': 'generate_output',
+ 'extension': '<(EXECUTABLE_SUFFIX)',
+ 'outputs': [ '<(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT)_output', ],
+ 'msvs_cygwin_shell': 0,
+ 'action': [
+ '<(RULE_INPUT_PATH)',
+ '<(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT)_output',
+ ],
+ 'message': 'Generating output for <(RULE_INPUT_ROOT)'
+ },
+ ],
+ },
+ ],
+}
--- a/media/webrtc/trunk/tools/gyp/test/rules-variables/gyptest-rules-variables.py
+++ b/media/webrtc/trunk/tools/gyp/test/rules-variables/gyptest-rules-variables.py
@@ -3,16 +3,23 @@
# 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.
"""
Verifies rules related variables are expanded.
"""
+import sys
+
+if sys.platform == 'win32':
+ print "This test is currently disabled: https://crbug.com/483696."
+ sys.exit(0)
+
+
import TestGyp
test = TestGyp.TestGyp(formats=['ninja'])
test.relocate('src', 'relocate/src')
test.run_gyp('variables.gyp', chdir='relocate/src')
--- a/media/webrtc/trunk/tools/gyp/test/rules/gyptest-all.py
+++ b/media/webrtc/trunk/tools/gyp/test/rules/gyptest-all.py
@@ -3,24 +3,33 @@
# 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.
"""
Verifies simple rules when using an explicit build target of 'all'.
"""
+import sys
+
+if sys.platform == 'win32':
+ print "This test is currently disabled: https://crbug.com/483696."
+ sys.exit(0)
+
+
import TestGyp
test = TestGyp.TestGyp()
test.run_gyp('no_action_with_rules_fails.gyp', chdir='src/noaction', status=1,
stderr=None)
-test.run_gyp('actions.gyp', chdir='src')
+test.run_gyp('actions.gyp',
+ '-G', 'xcode_ninja_target_pattern=^pull_in_all_actions$',
+ chdir='src')
test.relocate('src', 'relocate/src')
test.build('actions.gyp', test.ALL, chdir='relocate/src')
expect = """\
Hello from program.c
Hello from function1.in
@@ -45,16 +54,20 @@ else:
test.run_built_executable('program2', chdir=chdir, stdout=expect)
test.must_match('relocate/src/subdir2/file1.out', 'Hello from file1.in\n')
test.must_match('relocate/src/subdir2/file2.out', 'Hello from file2.in\n')
test.must_match('relocate/src/subdir2/file1.out2', 'Hello from file1.in\n')
test.must_match('relocate/src/subdir2/file2.out2', 'Hello from file2.in\n')
+test.must_match('relocate/src/subdir2/file1.out4', 'Hello from file1.in\n')
+test.must_match('relocate/src/subdir2/file2.out4', 'Hello from file2.in\n')
+test.must_match('relocate/src/subdir2/file1.copy', 'Hello from file1.in\n')
+
test.must_match('relocate/src/external/file1.external_rules.out',
'Hello from file1.in\n')
test.must_match('relocate/src/external/file2.external_rules.out',
'Hello from file2.in\n')
expect = """\
Hello from program.c
Got 41.
--- a/media/webrtc/trunk/tools/gyp/test/rules/gyptest-default.py
+++ b/media/webrtc/trunk/tools/gyp/test/rules/gyptest-default.py
@@ -3,21 +3,30 @@
# 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.
"""
Verifies simple rules when using an explicit build target of 'all'.
"""
+import sys
+
+if sys.platform == 'win32':
+ print "This test is currently disabled: https://crbug.com/483696."
+ sys.exit(0)
+
+
import TestGyp
test = TestGyp.TestGyp()
-test.run_gyp('actions.gyp', chdir='src')
+test.run_gyp('actions.gyp',
+ '-G', 'xcode_ninja_target_pattern=^pull_in_all_actions$',
+ chdir='src')
test.relocate('src', 'relocate/src')
test.build('actions.gyp', chdir='relocate/src')
expect = """\
Hello from program.c
Hello from function1.in
@@ -42,14 +51,18 @@ else:
test.run_built_executable('program2', chdir=chdir, stdout=expect)
test.must_match('relocate/src/subdir2/file1.out', 'Hello from file1.in\n')
test.must_match('relocate/src/subdir2/file2.out', 'Hello from file2.in\n')
test.must_match('relocate/src/subdir2/file1.out2', 'Hello from file1.in\n')
test.must_match('relocate/src/subdir2/file2.out2', 'Hello from file2.in\n')
+test.must_match('relocate/src/subdir2/file1.out4', 'Hello from file1.in\n')
+test.must_match('relocate/src/subdir2/file2.out4', 'Hello from file2.in\n')
+test.must_match('relocate/src/subdir2/file1.copy', 'Hello from file1.in\n')
+
test.must_match('relocate/src/external/file1.external_rules.out',
'Hello from file1.in\n')
test.must_match('relocate/src/external/file2.external_rules.out',
'Hello from file2.in\n')
test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/rules/gyptest-special-variables.py
@@ -0,0 +1,18 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 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.
+
+""" Verifies that VS variables that require special variables are expanded
+correctly. """
+
+import sys
+import TestGyp
+
+if sys.platform == 'win32':
+ test = TestGyp.TestGyp()
+
+ test.run_gyp('special-variables.gyp', chdir='src')
+ test.build('special-variables.gyp', test.ALL, chdir='src')
+ test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/rules/src/actions.gyp
+++ b/media/webrtc/trunk/tools/gyp/test/rules/src/actions.gyp
@@ -4,16 +4,17 @@
{
'targets': [
{
'target_name': 'pull_in_all_actions',
'type': 'none',
'dependencies': [
'subdir1/executable.gyp:*',
+ 'subdir2/both_rule_and_action_input.gyp:*',
'subdir2/never_used.gyp:*',
'subdir2/no_inputs.gyp:*',
'subdir2/no_action.gyp:*',
'subdir2/none.gyp:*',
'subdir3/executable2.gyp:*',
'subdir4/build-asm.gyp:*',
'external/external.gyp:*',
],
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/rules/src/an_asm.S
@@ -0,0 +1,6 @@
+// Copyright (c) 2012 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.
+
+// Fake asm file.
+int main() {}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/rules/src/as.bat
@@ -0,0 +1,7 @@
+@echo off
+:: 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.
+
+:: Fake assembler for Windows
+cl /TP /c %1 /Fo%2
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/rules/src/special-variables.gyp
@@ -0,0 +1,34 @@
+# Copyright (c) 2012 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': [
+ {
+ 'rules': [
+ {
+ 'rule_name': 'assembler (gnu-compatible)',
+ 'msvs_cygwin_shell': 0,
+ 'msvs_quote_cmd': 0,
+ 'extension': 'S',
+ 'inputs': [
+ 'as.bat',
+ ],
+ 'outputs': [
+ '$(IntDir)/$(InputName).obj',
+ ],
+ 'action': [
+ 'as.bat',
+ '$(InputPath)',
+ '$(IntDir)/$(InputName).obj',
+ ],
+ 'message': 'Building assembly language file $(InputPath)',
+ 'process_outputs_as_sources': 1,
+ },
+ ],
+ 'target_name': 'test',
+ 'type': 'static_library',
+ 'sources': [ 'an_asm.S' ],
+ },
+ ],
+}
--- a/media/webrtc/trunk/tools/gyp/test/rules/src/subdir1/executable.gyp
+++ b/media/webrtc/trunk/tools/gyp/test/rules/src/subdir1/executable.gyp
@@ -16,17 +16,17 @@
'rules': [
{
'rule_name': 'copy_file',
'extension': 'in',
'inputs': [
'../copy-file.py',
],
'outputs': [
- # TODO: fix SCons and Make to support generated files not
+ # TODO: fix Make to support generated files not
# in a variable-named path like <(INTERMEDIATE_DIR)
#'<(RULE_INPUT_ROOT).c',
'<(INTERMEDIATE_DIR)/<(RULE_INPUT_ROOT).c',
],
'action': [
'python', '<(_inputs)', '<(RULE_INPUT_PATH)', '<@(_outputs)',
],
'process_outputs_as_sources': 1,
--- a/media/webrtc/trunk/tools/gyp/test/rules/src/subdir1/program.c
+++ b/media/webrtc/trunk/tools/gyp/test/rules/src/subdir1/program.c
@@ -1,12 +1,12 @@
#include <stdio.h>
extern void function1(void);
extern void function2(void);
-int main(int argc, char *argv[])
+int main(void)
{
printf("Hello from program.c\n");
function1();
function2();
return 0;
}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/rules/src/subdir2/both_rule_and_action_input.gyp
@@ -0,0 +1,50 @@
+# Copyright (c) 2014 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.
+
+# Tests that if a rule input is also an action input, both the rule and action
+# are executed
+{
+ 'targets': [
+ {
+ 'target_name': 'files_both_rule_and_action_input',
+ 'type': 'executable',
+ 'msvs_cygwin_shell': 0,
+ 'sources': [
+ 'program.c',
+ 'file1.in',
+ 'file2.in',
+ ],
+ 'rules': [
+ {
+ 'rule_name': 'copy_file',
+ 'extension': 'in',
+ 'inputs': [
+ '../copy-file.py',
+ ],
+ 'outputs': [
+ '<(RULE_INPUT_ROOT).out4',
+ ],
+ 'action': [
+ 'python', '<(_inputs)', '<(RULE_INPUT_PATH)', '<@(_outputs)',
+ ],
+ },
+ ],
+ 'actions': [
+ {
+ 'action_name': 'copy_file1_in',
+ 'inputs': [
+ '../copy-file.py',
+ 'file1.in',
+ ],
+ 'outputs': [
+ 'file1.copy',
+ ],
+ 'action': [
+ 'python', '<@(_inputs)', '<(_outputs)'
+ ],
+ },
+ ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/rules/src/subdir2/program.c
@@ -0,0 +1,12 @@
+/* Copyright (c) 2014 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>
+
+int main(void)
+{
+ printf("Hello from program.c\n");
+ return 0;
+}
--- a/media/webrtc/trunk/tools/gyp/test/rules/src/subdir3/program.c
+++ b/media/webrtc/trunk/tools/gyp/test/rules/src/subdir3/program.c
@@ -1,10 +1,10 @@
#include <stdio.h>
extern void function3(void);
-int main(int argc, char *argv[])
+int main(void)
{
printf("Hello from program.c\n");
function3();
return 0;
}
rename from media/webrtc/trunk/tools/gyp/test/rules/src/subdir4/asm-function.asm
rename to media/webrtc/trunk/tools/gyp/test/rules/src/subdir4/asm-function.assem
--- a/media/webrtc/trunk/tools/gyp/test/rules/src/subdir4/build-asm.gyp
+++ b/media/webrtc/trunk/tools/gyp/test/rules/src/subdir4/build-asm.gyp
@@ -18,31 +18,31 @@
}],
],
},
'targets': [
{
'target_name': 'program4',
'type': 'executable',
'sources': [
- 'asm-function.asm',
+ 'asm-function.assem',
'program.c',
],
'conditions': [
['OS=="linux" or OS=="mac"', {
'rules': [
{
- 'rule_name': 'convert_asm',
- 'extension': 'asm',
+ 'rule_name': 'convert_assem',
+ 'extension': 'assem',
'inputs': [],
'outputs': [
'<(SHARED_INTERMEDIATE_DIR)/<(RULE_INPUT_ROOT).S',
],
'action': [
- 'bash', '-c', 'mv <(RULE_INPUT_PATH) <@(_outputs)',
+ 'bash', '-c', 'cp <(RULE_INPUT_PATH) <@(_outputs)',
],
'process_outputs_as_sources': 1,
},
],
}],
],
},
],
--- a/media/webrtc/trunk/tools/gyp/test/rules/src/subdir4/program.c
+++ b/media/webrtc/trunk/tools/gyp/test/rules/src/subdir4/program.c
@@ -4,16 +4,16 @@
#if PLATFORM_LINUX || PLATFORM_MAC
extern int asm_function(void);
#else
int asm_function() {
return 41;
}
#endif
-int main(int argc, char *argv[])
+int main(void)
{
fprintf(stdout, "Hello from program.c\n");
fflush(stdout);
fprintf(stdout, "Got %d.\n", asm_function());
fflush(stdout);
return 0;
}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/same-gyp-name/gyptest-library.py
@@ -0,0 +1,20 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 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.
+
+"""
+Verifies that a dependency on two gyp files with the same name do not create a
+uid collision in the resulting generated xcode file.
+"""
+
+import TestGyp
+
+import sys
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('test.gyp', chdir='library')
+
+test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/same-gyp-name/library/one/sub.gyp
@@ -0,0 +1,11 @@
+# Copyright (c) 2012 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': 'one',
+ 'type': 'static_library',
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/same-gyp-name/library/test.gyp
@@ -0,0 +1,15 @@
+# Copyright (c) 2012 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': 'duplicate_names',
+ 'type': 'shared_library',
+ 'dependencies': [
+ 'one/sub.gyp:one',
+ 'two/sub.gyp:two',
+ ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/same-gyp-name/library/two/sub.gyp
@@ -0,0 +1,11 @@
+# Copyright (c) 2012 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': 'two',
+ 'type': 'static_library',
+ },
+ ],
+}
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/same-source-file-name/gyptest-pass-executable.py
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 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.
+
+"""
+Checks that gyp does not fail on executable targets which have several files
+with the same basename.
+"""
+
+import TestGyp
+
+# While MSVS supports building executables that contain several files with the
+# same name, the msvs gyp generator does not.
+test = TestGyp.TestGyp(formats=['!msvs'])
+
+test.run_gyp('double-executable.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+test.build('double-executable.gyp', test.ALL, chdir='relocate/src')
+
+expect = """\
+Hello from prog3.c
+Hello prog3 from func.c
+Hello prog3 from subdir1/func.c
+Hello prog3 from subdir2/func.c
+"""
+
+test.run_built_executable('prog3', chdir='relocate/src', stdout=expect)
+
+test.pass_test()
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/same-source-file-name/gyptest-pass-shared.py
@@ -0,0 +1,18 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 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.
+
+"""
+Checks that gyp does not fail on shared_library targets which have several files
+with the same basename.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('double-shared.gyp', chdir='src')
+
+test.pass_test()
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/same-source-file-name/gyptest-static.py
@@ -0,0 +1,34 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 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.
+
+"""
+Checks that gyp fails on static_library targets which have several files with
+the same basename.
+"""
+
+import os
+import sys
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+# Fails by default for the compatibility with legacy generators such as
+# VCProj generator for Visual C++ 2008 and Makefile generator on Mac.
+# TODO: Update expected behavior when these legacy generators are deprecated.
+test.run_gyp('double-static.gyp', chdir='src', status=1, stderr=None)
+
+if ((test.format == 'make' and sys.platform == 'darwin') or
+ (test.format == 'msvs' and
+ int(os.environ.get('GYP_MSVS_VERSION', 2010)) < 2010)):
+ test.run_gyp('double-static.gyp', '--no-duplicate-basename-check',
+ chdir='src', status=1, stderr=None)
+else:
+ test.run_gyp('double-static.gyp', '--no-duplicate-basename-check',
+ chdir='src')
+ test.build('double-static.gyp', test.ALL, chdir='src')
+
+test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/same-source-file-name/src/double-executable.gyp
@@ -0,0 +1,21 @@
+# Copyright (c) 2012 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': 'prog3',
+ 'type': 'executable',
+ 'sources': [
+ 'prog3.c',
+ 'func.c',
+ 'subdir1/func.c',
+ 'subdir2/func.c',
+ ],
+ 'defines': [
+ 'PROG="prog3"',
+ ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/same-source-file-name/src/double-shared.gyp
@@ -0,0 +1,27 @@
+# Copyright (c) 2012 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': 'lib',
+ 'product_name': 'test_shared_lib',
+ 'type': 'shared_library',
+ 'sources': [
+ 'prog2.c',
+ 'func.c',
+ 'subdir1/func.c',
+ 'subdir2/func.c',
+ ],
+ 'defines': [
+ 'PROG="prog2"',
+ ],
+ 'conditions': [
+ ['OS=="linux"', {
+ 'cflags': ['-fPIC'],
+ }],
+ ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/same-source-file-name/src/double-static.gyp
@@ -0,0 +1,22 @@
+# Copyright (c) 2012 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': 'lib',
+ 'product_name': 'test_static_lib',
+ 'type': 'static_library',
+ 'sources': [
+ 'prog1.c',
+ 'func.c',
+ 'subdir1/func.c',
+ 'subdir2/func.c',
+ ],
+ 'defines': [
+ 'PROG="prog1"',
+ ],
+ },
+ ],
+}
--- a/media/webrtc/trunk/tools/gyp/test/same-source-file-name/src/prog1.c
+++ b/media/webrtc/trunk/tools/gyp/test/same-source-file-name/src/prog1.c
@@ -1,13 +1,13 @@
#include <stdio.h>
extern void func(void);
-int main(int argc, char *argv[])
+int main(void)
{
printf("Hello from prog1.c\n");
func();
/*
* Uncomment to test same-named files in different directories,
* which Visual Studio doesn't support.
subdir1_func();
subdir2_func();
--- a/media/webrtc/trunk/tools/gyp/test/same-source-file-name/src/prog2.c
+++ b/media/webrtc/trunk/tools/gyp/test/same-source-file-name/src/prog2.c
@@ -1,13 +1,13 @@
#include <stdio.h>
extern void func(void);
-int main(int argc, char *argv[])
+int main(void)
{
printf("Hello from prog2.c\n");
func();
/*
* Uncomment to test same-named files in different directories,
* which Visual Studio doesn't support.
subdir1_func();
subdir2_func();
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/same-source-file-name/src/prog3.c
@@ -0,0 +1,18 @@
+// Copyright (c) 2012 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 void func(void);
+extern void subdir1_func(void);
+extern void subdir2_func(void);
+
+int main(void)
+{
+ printf("Hello from prog3.c\n");
+ func();
+ subdir1_func();
+ subdir2_func();
+ return 0;
+}
--- a/media/webrtc/trunk/tools/gyp/test/same-target-name-different-directory/gyptest-all.py
+++ b/media/webrtc/trunk/tools/gyp/test/same-target-name-different-directory/gyptest-all.py
@@ -5,17 +5,22 @@
# found in the LICENSE file.
"""
Test cases when multiple targets in different directories have the same name.
"""
import TestGyp
-test = TestGyp.TestGyp(formats=['android', 'ninja', 'make'])
+test = TestGyp.TestGyp(formats=['ninja', 'make'])
+
+# xcode-ninja fails to generate a project due to id collisions
+# cf. https://code.google.com/p/gyp/issues/detail?id=461
+if test.format == 'xcode-ninja':
+ test.skip_test()
test.run_gyp('subdirs.gyp', chdir='src')
test.relocate('src', 'relocate/src')
# Test that we build all targets.
test.build('subdirs.gyp', 'target', chdir='relocate/src')
test.must_exist('relocate/src/subdir1/action1.txt')
deleted file mode 100755
--- a/media/webrtc/trunk/tools/gyp/test/scons_tools/gyptest-tools.py
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/usr/bin/env python
-
-# 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.
-
-"""
-Verifies that a scons build picks up tools modules specified
-via 'scons_tools' in the 'scons_settings' dictionary.
-"""
-
-import TestGyp
-
-test = TestGyp.TestGyp()
-
-test.run_gyp('tools.gyp')
-
-test.build('tools.gyp', test.ALL)
-
-if test.format == 'scons':
- expect = "Hello, world!\n"
-else:
- expect = ""
-test.run_built_executable('tools', stdout=expect)
-
-test.pass_test()
deleted file mode 100644
--- a/media/webrtc/trunk/tools/gyp/test/scons_tools/site_scons/site_tools/this_tool.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# 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.
-
-# SCons "tool" module that simply sets a -D value.
-def generate(env):
- env['CPPDEFINES'] = ['THIS_TOOL']
-
-def exists(env):
- pass
deleted file mode 100644
--- a/media/webrtc/trunk/tools/gyp/test/scons_tools/tools.c
+++ /dev/null
@@ -1,13 +0,0 @@
-/* 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. */
-
-#include <stdio.h>
-
-int main(int argc, char *argv[])
-{
-#ifdef THIS_TOOL
- printf("Hello, world!\n");
-#endif
- return 0;
-}
deleted file mode 100644
--- a/media/webrtc/trunk/tools/gyp/test/scons_tools/tools.gyp
+++ /dev/null
@@ -1,18 +0,0 @@
-# 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': 'tools',
- 'type': 'executable',
- 'sources': [
- 'tools.c',
- ],
- },
- ],
- 'scons_settings': {
- 'tools': ['default', 'this_tool'],
- },
-}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/self-dependency/common.gypi
@@ -0,0 +1,13 @@
+# Copyright (c) 2013 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.
+
+# A common file that other .gyp files include.
+# Makes every target in the project depend on dep.gyp:dep.
+{
+ 'target_defaults': {
+ 'dependencies': [
+ 'dep.gyp:dep',
+ ],
+ },
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/self-dependency/dep.gyp
@@ -0,0 +1,23 @@
+# Copyright (c) 2013 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.
+
+# dep.gyp contains a target dep, on which all the targets in the project
+# depend. This means there's a self-dependency of dep on itself, which is
+# pruned by setting prune_self_dependency to 1.
+
+{
+ 'includes': [
+ 'common.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'dep',
+ 'type': 'none',
+ 'variables': {
+ # Without this GYP will report a cycle in dependency graph.
+ 'prune_self_dependency': 1,
+ },
+ },
+ ],
+}
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/self-dependency/gyptest-self-dependency.py
@@ -0,0 +1,19 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 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 pulling in a dependency a second time in a conditional works for
+shared_library targets. Regression test for http://crbug.com/122588
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('self_dependency.gyp')
+
+# If running gyp worked, all is well.
+test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/self-dependency/self_dependency.gyp
@@ -0,0 +1,15 @@
+# Copyright (c) 2013 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.
+
+{
+ 'includes': [
+ 'common.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'a',
+ 'type': 'none',
+ },
+ ],
+}
--- a/media/webrtc/trunk/tools/gyp/test/sibling/gyptest-all.py
+++ b/media/webrtc/trunk/tools/gyp/test/sibling/gyptest-all.py
@@ -1,32 +1,35 @@
#!/usr/bin/env python
# Copyright (c) 2012 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.
-"""
-"""
-
import TestGyp
test = TestGyp.TestGyp()
+# The xcode-ninja generator handles gypfiles which are not at the
+# project root incorrectly.
+# cf. https://code.google.com/p/gyp/issues/detail?id=460
+if test.format == 'xcode-ninja':
+ test.skip_test()
+
test.run_gyp('build/all.gyp', chdir='src')
test.build('build/all.gyp', test.ALL, chdir='src')
chdir = 'src/build'
# The top-level Makefile is in the directory where gyp was run.
# TODO(mmoss) Should the Makefile go in the directory of the passed in .gyp
# file? What about when passing in multiple .gyp files? Would sub-project
# Makefiles (see http://codereview.chromium.org/340008 comments) solve this?
-if test.format in ('make', 'ninja'):
+if test.format in ('make', 'ninja', 'cmake'):
chdir = 'src'
if test.format == 'xcode':
chdir = 'src/prog1'
test.run_built_executable('program1',
chdir=chdir,
stdout="Hello from prog1.c\n")
--- a/media/webrtc/trunk/tools/gyp/test/sibling/gyptest-relocate.py
+++ b/media/webrtc/trunk/tools/gyp/test/sibling/gyptest-relocate.py
@@ -1,34 +1,37 @@
#!/usr/bin/env python
# Copyright (c) 2012 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.
-"""
-"""
-
import TestGyp
test = TestGyp.TestGyp()
+# The xcode-ninja generator handles gypfiles which are not at the
+# project root incorrectly.
+# cf. https://code.google.com/p/gyp/issues/detail?id=460
+if test.format == 'xcode-ninja':
+ test.skip_test()
+
test.run_gyp('build/all.gyp', chdir='src')
test.relocate('src', 'relocate/src')
test.build('build/all.gyp', test.ALL, chdir='relocate/src')
chdir = 'relocate/src/build'
# The top-level Makefile is in the directory where gyp was run.
# TODO(mmoss) Should the Makefile go in the directory of the passed in .gyp
# file? What about when passing in multiple .gyp files? Would sub-project
# Makefiles (see http://codereview.chromium.org/340008 comments) solve this?
-if test.format in ('make', 'ninja'):
+if test.format in ('make', 'ninja', 'cmake'):
chdir = 'relocate/src'
if test.format == 'xcode':
chdir = 'relocate/src/prog1'
test.run_built_executable('program1',
chdir=chdir,
stdout="Hello from prog1.c\n")
--- a/media/webrtc/trunk/tools/gyp/test/sibling/src/build/all.gyp
+++ b/media/webrtc/trunk/tools/gyp/test/sibling/src/build/all.gyp
@@ -1,16 +1,15 @@
# 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': [
{
- # TODO(sgk): a target name of 'all' leads to a scons dependency cycle
'target_name': 'All',
'type': 'none',
'dependencies': [
'../prog1/prog1.gyp:*',
'../prog2/prog2.gyp:*',
],
},
],
--- a/media/webrtc/trunk/tools/gyp/test/sibling/src/prog1/prog1.c
+++ b/media/webrtc/trunk/tools/gyp/test/sibling/src/prog1/prog1.c
@@ -1,7 +1,7 @@
#include <stdio.h>
-int main(int argc, char *argv[])
+int main(void)
{
printf("Hello from prog1.c\n");
return 0;
}
--- a/media/webrtc/trunk/tools/gyp/test/sibling/src/prog2/prog2.c
+++ b/media/webrtc/trunk/tools/gyp/test/sibling/src/prog2/prog2.c
@@ -1,7 +1,7 @@
#include <stdio.h>
-int main(int argc, char *argv[])
+int main(void)
{
printf("Hello from prog2.c\n");
return 0;
}
--- a/media/webrtc/trunk/tools/gyp/test/small/gyptest-small.py
+++ b/media/webrtc/trunk/tools/gyp/test/small/gyptest-small.py
@@ -15,25 +15,27 @@ import unittest
import TestGyp
test = TestGyp.TestGyp()
# Add pylib to the import path (so tests can import their dependencies).
# This is consistant with the path.append done in the top file "gyp".
-sys.path.append(os.path.join(test._cwd, 'pylib'))
+sys.path.insert(0, os.path.join(test._cwd, 'pylib'))
# Add new test suites here.
files_to_test = [
'pylib/gyp/MSVSSettings_test.py',
'pylib/gyp/easy_xml_test.py',
'pylib/gyp/generator/msvs_test.py',
'pylib/gyp/generator/ninja_test.py',
+ 'pylib/gyp/generator/xcode_test.py',
'pylib/gyp/common_test.py',
+ 'pylib/gyp/input_test.py',
]
# Collect all the suites from the above files.
suites = []
for filename in files_to_test:
# Carve the module name out of the path.
name = os.path.splitext(os.path.split(filename)[1])[0]
# Find the complete module path.
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/standalone-static-library/gyptest-standalone-static-library.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 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.
+
+"""
+Verifies build of a static_library with the standalone_static_library flag set.
+"""
+
+import os
+import subprocess
+import sys
+import TestGyp
+
+# standalone_static_library currently means two things: a specific output
+# location for the built target and non-thin archive files.
+test = TestGyp.TestGyp()
+
+# Verify that types other than static_library cause a failure.
+test.run_gyp('invalid.gyp', status=1, stderr=None)
+target_str = 'invalid.gyp:bad#target'
+err = ['gyp: Target %s has type executable but standalone_static_library flag '
+ 'is only valid for static_library type.' % target_str]
+test.must_contain_all_lines(test.stderr(), err)
+
+# Build a valid standalone_static_library.
+test.run_gyp('mylib.gyp')
+test.build('mylib.gyp', target='prog')
+
+# Verify that the static library is copied to the correct location.
+# We expect the library to be copied to $PRODUCT_DIR.
+standalone_static_library_dir = test.EXECUTABLE
+path_to_lib = os.path.split(
+ test.built_file_path('mylib', type=standalone_static_library_dir))[0]
+lib_name = test.built_file_basename('mylib', type=test.STATIC_LIB)
+path = os.path.join(path_to_lib, lib_name)
+test.must_exist(path)
+
+# Verify that the program runs properly.
+expect = 'hello from mylib.c\n'
+test.run_built_executable('prog', stdout=expect)
+
+# Verify that libmylib.a contains symbols. "ar -x" fails on a 'thin' archive.
+supports_thick = ('make', 'ninja', 'cmake')
+if test.format in supports_thick and sys.platform.startswith('linux'):
+ retcode = subprocess.call(['ar', '-x', path])
+ assert retcode == 0
+
+test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/standalone-static-library/invalid.gyp
@@ -0,0 +1,16 @@
+# Copyright (c) 2012 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': 'bad',
+ 'type': 'executable',
+ 'standalone_static_library': 1,
+ 'sources': [
+ 'prog.c',
+ ],
+ },
+ ],
+}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/standalone-static-library/mylib.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+void print(void)
+{
+ printf("hello from mylib.c\n");
+ return;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/standalone-static-library/mylib.gyp
@@ -0,0 +1,26 @@
+# Copyright (c) 2012 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': 'mylib',
+ 'type': 'static_library',
+ 'standalone_static_library': 1,
+ 'sources': [
+ 'mylib.c',
+ ],
+ },
+ {
+ 'target_name': 'prog',
+ 'type': 'executable',
+ 'sources': [
+ 'prog.c',
+ ],
+ 'dependencies': [
+ 'mylib',
+ ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/standalone-static-library/prog.c
@@ -0,0 +1,7 @@
+extern void print(void);
+
+int main(void)
+{
+ print();
+ return 0;
+}
--- a/media/webrtc/trunk/tools/gyp/test/subdirectory/gyptest-SYMROOT-all.py
+++ b/media/webrtc/trunk/tools/gyp/test/subdirectory/gyptest-SYMROOT-all.py
@@ -4,17 +4,17 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""
Verifies building a target and a subsidiary dependent target from a
.gyp file in a subdirectory, without specifying an explicit output build
directory, and using the generated solution or project file at the top
of the tree as the entry point.
-
+
The configuration sets the Xcode SYMROOT variable and uses --depth=
to make Xcode behave like the other build tools--that is, put all
built targets in a single output build directory at the top of the tree.
"""
import TestGyp
test = TestGyp.TestGyp()
--- a/media/webrtc/trunk/tools/gyp/test/subdirectory/gyptest-SYMROOT-default.py
+++ b/media/webrtc/trunk/tools/gyp/test/subdirectory/gyptest-SYMROOT-default.py
@@ -4,17 +4,17 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""
Verifies building a target and a subsidiary dependent target from a
.gyp file in a subdirectory, without specifying an explicit output build
directory, and using the generated solution or project file at the top
of the tree as the entry point.
-
+
The configuration sets the Xcode SYMROOT variable and uses --depth=
to make Xcode behave like the other build tools--that is, put all
built targets in a single output build directory at the top of the tree.
"""
import TestGyp
test = TestGyp.TestGyp()
--- a/media/webrtc/trunk/tools/gyp/test/subdirectory/gyptest-subdir-all.py
+++ b/media/webrtc/trunk/tools/gyp/test/subdirectory/gyptest-subdir-all.py
@@ -7,18 +7,19 @@
"""
Verifies building a subsidiary dependent target from a .gyp file in a
subdirectory, without specifying an explicit output build directory,
and using the subdirectory's solution or project file as the entry point.
"""
import TestGyp
-# Ninja and Android don't support running from subdirectories.
-test = TestGyp.TestGyp(formats=['!ninja', '!android'])
+# Ninja doesn't support relocation.
+# CMake produces a single CMakeLists.txt in the output directory.
+test = TestGyp.TestGyp(formats=['!ninja', '!cmake'])
test.run_gyp('prog1.gyp', chdir='src')
test.relocate('src', 'relocate/src')
chdir = 'relocate/src/subdir'
target = test.ALL
--- a/media/webrtc/trunk/tools/gyp/test/subdirectory/gyptest-subdir-default.py
+++ b/media/webrtc/trunk/tools/gyp/test/subdirectory/gyptest-subdir-default.py
@@ -8,18 +8,19 @@
Verifies building a subsidiary dependent target from a .gyp file in a
subdirectory, without specifying an explicit output build directory,
and using the subdirectory's solution or project file as the entry point.
"""
import TestGyp
import errno
-# Ninja and Android don't support running from subdirectories.
-test = TestGyp.TestGyp(formats=['!ninja', '!android'])
+# Ninja doesn't support relocation.
+# CMake produces a single CMakeLists.txt in the output directory.
+test = TestGyp.TestGyp(formats=['!ninja', '!cmake'])
test.run_gyp('prog1.gyp', chdir='src')
test.relocate('src', 'relocate/src')
chdir = 'relocate/src/subdir'
test.build('prog2.gyp', chdir=chdir)
--- a/media/webrtc/trunk/tools/gyp/test/subdirectory/gyptest-top-all.py
+++ b/media/webrtc/trunk/tools/gyp/test/subdirectory/gyptest-top-all.py
@@ -8,17 +8,17 @@
Verifies building a target and a subsidiary dependent target from a
.gyp file in a subdirectory, without specifying an explicit output build
directory, and using the generated solution or project file at the top
of the tree as the entry point.
There is a difference here in the default behavior of the underlying
build tools. Specifically, when building the entire "solution", Xcode
puts the output of each project relative to the .xcodeproj directory,
-while Visual Studio (and our implementations of SCons and Make) put it
+while Visual Studio (and our implementation of Make) put it
in a build directory relative to the "solution"--that is, the entry-point
from which you built the entire tree.
"""
import TestGyp
test = TestGyp.TestGyp()
--- a/media/webrtc/trunk/tools/gyp/test/subdirectory/gyptest-top-default.py
+++ b/media/webrtc/trunk/tools/gyp/test/subdirectory/gyptest-top-default.py
@@ -8,17 +8,17 @@
Verifies building a target and a subsidiary dependent target from a
.gyp file in a subdirectory, without specifying an explicit output build
directory, and using the generated solution or project file at the top
of the tree as the entry point.
There is a difference here in the default behavior of the underlying
build tools. Specifically, when building the entire "solution", Xcode
puts the output of each project relative to the .xcodeproj directory,
-while Visual Studio (and our implementations of SCons and Make) put it
+while Visual Studio (and our implementation of Make) put it
in a build directory relative to the "solution"--that is, the entry-point
from which you built the entire tree.
"""
import TestGyp
test = TestGyp.TestGyp()
--- a/media/webrtc/trunk/tools/gyp/test/subdirectory/src/prog1.c
+++ b/media/webrtc/trunk/tools/gyp/test/subdirectory/src/prog1.c
@@ -1,7 +1,7 @@
#include <stdio.h>
-int main(int argc, char *argv[])
+int main(void)
{
printf("Hello from prog1.c\n");
return 0;
}
--- a/media/webrtc/trunk/tools/gyp/test/subdirectory/src/subdir/prog2.c
+++ b/media/webrtc/trunk/tools/gyp/test/subdirectory/src/subdir/prog2.c
@@ -1,7 +1,7 @@
#include <stdio.h>
-int main(int argc, char *argv[])
+int main(void)
{
printf("Hello from prog2.c\n");
return 0;
}
--- a/media/webrtc/trunk/tools/gyp/test/subdirectory/src/subdir/subdir2/prog3.c
+++ b/media/webrtc/trunk/tools/gyp/test/subdirectory/src/subdir/subdir2/prog3.c
@@ -1,7 +1,7 @@
#include <stdio.h>
-int main(int argc, char *argv[])
+int main(void)
{
printf("Hello from prog3.c\n");
return 0;
}
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/symlinks/gyptest-symlinks.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2015 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.
+
+"""
+Test that RelativePath(s, d) doesn't return a path starting with '..' when
+s is textually below d, but is also a symlink to a file that is not below d.
+
+Returning .. in this case would break the Ninja generator in such a case,
+because it computes output directories by concatenating paths, and concat'ing
+a path starting with .. can unexpectedly erase other parts of the path. It's
+difficult to test this directly since the test harness assumes toplevel_dir is
+the root of the repository, but this test should at least verify that the
+required behavior doesn't change.
+"""
+
+import TestGyp
+import os
+import sys
+import tempfile
+
+if sys.platform != 'win32':
+ test = TestGyp.TestGyp()
+
+ # Copy hello.gyp and hello.c to temporary named files, which will then be
+ # symlinked back and processed. Note that we don't ask gyp to touch the
+ # original files at all; they are only there as source material for the copy.
+ # That's why hello.gyp references symlink_hello.c instead of hello.c.
+ with tempfile.NamedTemporaryFile() as gyp_file:
+ with tempfile.NamedTemporaryFile() as c_file:
+ with open('hello.gyp') as orig_gyp_file:
+ gyp_file.write(orig_gyp_file.read())
+ gyp_file.flush()
+ with open('hello.c') as orig_c_file:
+ c_file.write(orig_c_file.read())
+ c_file.flush()
+ # We need to flush the files because we want to read them before closing
+ # them, since when they are closed they will be deleted.
+
+ # Don't proceed with the test on a system that doesn't let you read from
+ # a still-open temporary file.
+ if os.path.getsize(gyp_file.name) == 0:
+ raise OSError("Copy to temporary file didn't work.")
+
+ symlink_gyp = test.built_file_path('symlink_hello.gyp')
+ symlink_c = test.built_file_path('symlink_hello.c')
+ outdir = os.path.dirname(symlink_gyp)
+
+ # Make sure the outdir exists.
+ try:
+ os.makedirs(outdir)
+ except OSError:
+ if not os.path.isdir(outdir):
+ raise
+ os.symlink(gyp_file.name, symlink_gyp)
+ os.symlink(c_file.name, symlink_c)
+
+ # Run gyp on the symlinked files.
+ test.run_gyp(symlink_gyp, chdir=outdir)
+ test.build(symlink_gyp, chdir=outdir)
+ test.run_built_executable('symlink_hello', stdout="Hello, world!\n",
+ chdir=outdir)
+
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/symlinks/hello.c
@@ -0,0 +1,12 @@
+/* Copyright (c) 2015 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>
+
+int main(void)
+{
+ printf("Hello, world!\n");
+ return 0;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/symlinks/hello.gyp
@@ -0,0 +1,15 @@
+# Copyright (c) 2015 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': 'symlink_hello',
+ 'type': 'executable',
+ 'sources': [
+ 'symlink_hello.c',
+ ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/target/gyptest-target.py
@@ -0,0 +1,37 @@
+#!/usr/bin/env python
+
+# 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.
+
+"""
+Verifies simplest-possible build of a "Hello, world!" program
+using non-default extension. In particular, verifies how
+target_extension is used to avoid MSB8012 for msvs.
+"""
+
+import sys
+import TestGyp
+
+if sys.platform in ('win32', 'cygwin'):
+ test = TestGyp.TestGyp()
+
+ test.run_gyp('target.gyp')
+ test.build('target.gyp')
+
+ # executables
+ test.built_file_must_exist('hello1.stuff', test.EXECUTABLE, bare=True)
+ test.built_file_must_exist('hello2.exe', test.EXECUTABLE, bare=True)
+ test.built_file_must_not_exist('hello2.stuff', test.EXECUTABLE, bare=True)
+
+ # check msvs log for errors
+ if test.format == "msvs":
+ log_file = "obj\\hello1\\hello1.log"
+ test.built_file_must_exist(log_file)
+ test.built_file_must_not_contain(log_file, "MSB8012")
+
+ log_file = "obj\\hello2\\hello2.log"
+ test.built_file_must_exist(log_file)
+ test.built_file_must_not_contain(log_file, "MSB8012")
+
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/target/hello.c
@@ -0,0 +1,7 @@
+/* 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. */
+
+void main(void) {
+ printf("Hello, world!\n");
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/target/target.gyp
@@ -0,0 +1,24 @@
+# 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': 'hello1',
+ 'product_extension': 'stuff',
+ 'type': 'executable',
+ 'sources': [
+ 'hello.c',
+ ],
+ },
+ {
+ 'target_name': 'hello2',
+ 'target_extension': 'stuff',
+ 'type': 'executable',
+ 'sources': [
+ 'hello.c',
+ ],
+ }
+ ]
+}
--- a/media/webrtc/trunk/tools/gyp/test/toolsets/gyptest-toolsets.py
+++ b/media/webrtc/trunk/tools/gyp/test/toolsets/gyptest-toolsets.py
@@ -2,22 +2,30 @@
# 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.
"""
Verifies that toolsets are correctly applied
"""
-
+import os
+import sys
import TestGyp
-# Multiple toolsets are currently only supported by the make generator.
-test = TestGyp.TestGyp(formats=['make'])
+if sys.platform.startswith('linux'):
-test.run_gyp('toolsets.gyp')
+ test = TestGyp.TestGyp(formats=['make', 'ninja'])
-test.build('toolsets.gyp', test.ALL)
+ oldenv = os.environ.copy()
+ try:
+ os.environ['GYP_CROSSCOMPILE'] = '1'
+ test.run_gyp('toolsets.gyp')
+ finally:
+ os.environ.clear()
+ os.environ.update(oldenv)
-test.run_built_executable('host-main', stdout="Host\n")
-test.run_built_executable('target-main', stdout="Target\n")
+ test.build('toolsets.gyp', test.ALL)
-test.pass_test()
+ test.run_built_executable('host-main', stdout="Host\nShared: Host\n")
+ test.run_built_executable('target-main', stdout="Target\nShared: Target\n")
+
+ test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/toolsets/main.cc
+++ b/media/webrtc/trunk/tools/gyp/test/toolsets/main.cc
@@ -1,11 +1,13 @@
/* 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. */
#include <stdio.h>
const char *GetToolset();
+const char *GetToolsetShared();
-int main(int argc, char *argv[]) {
+int main(void) {
printf("%s\n", GetToolset());
+ printf("Shared: %s\n", GetToolsetShared());
}
--- a/media/webrtc/trunk/tools/gyp/test/toolsets/toolsets.gyp
+++ b/media/webrtc/trunk/tools/gyp/test/toolsets/toolsets.gyp
@@ -16,34 +16,47 @@
'sources': [
'toolsets.cc',
],
},
{
'target_name': 'host-main',
'type': 'executable',
'toolsets': ['host'],
- 'dependencies': ['toolsets'],
+ 'dependencies': ['toolsets', 'toolsets_shared'],
'sources': [
'main.cc',
],
},
{
'target_name': 'target-main',
'type': 'executable',
- 'dependencies': ['toolsets'],
+ 'dependencies': ['toolsets', 'toolsets_shared'],
'sources': [
'main.cc',
],
},
# This tests that build systems can handle a shared library being build for
# both host and target.
{
'target_name': 'janus',
'type': 'shared_library',
'toolsets': ['target', 'host'],
'sources': [
'toolsets.cc',
],
'cflags': [ '-fPIC' ],
},
+ {
+ 'target_name': 'toolsets_shared',
+ 'type': 'shared_library',
+ 'toolsets': ['target', 'host'],
+ 'target_conditions': [
+ # Ensure target and host have different shared_library names
+ ['_toolset=="host"', {'product_extension': 'host'}],
+ ],
+ 'sources': [
+ 'toolsets_shared.cc',
+ ],
+ 'cflags': [ '-fPIC' ],
+ },
],
}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/toolsets/toolsets_shared.cc
@@ -0,0 +1,11 @@
+/* Copyright (c) 2013 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. */
+
+const char *GetToolsetShared() {
+#ifdef TARGET
+ return "Target";
+#else
+ return "Host";
+#endif
+}
--- a/media/webrtc/trunk/tools/gyp/test/toplevel-dir/gyptest-toplevel-dir.py
+++ b/media/webrtc/trunk/tools/gyp/test/toplevel-dir/gyptest-toplevel-dir.py
@@ -15,17 +15,17 @@ import errno
test = TestGyp.TestGyp(formats=['ninja', 'make'])
# We want our Makefile to be one dir up from main.gyp.
test.run_gyp('main.gyp', '--toplevel-dir=..', chdir='src/sub1')
toplevel_dir = 'src'
-test.build('all', chdir=toplevel_dir)
+test.build('sub1/main.gyp', test.ALL, chdir=toplevel_dir)
test.built_file_must_exist('prog1', type=test.EXECUTABLE, chdir=toplevel_dir)
test.run_built_executable('prog1',
chdir=toplevel_dir,
stdout="Hello from prog1.c\n")
test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/toplevel-dir/src/sub1/prog1.c
+++ b/media/webrtc/trunk/tools/gyp/test/toplevel-dir/src/sub1/prog1.c
@@ -1,7 +1,7 @@
#include <stdio.h>
-int main(int argc, char *argv[])
+int main(void)
{
printf("Hello from prog1.c\n");
return 0;
}
--- a/media/webrtc/trunk/tools/gyp/test/toplevel-dir/src/sub2/prog2.c
+++ b/media/webrtc/trunk/tools/gyp/test/toplevel-dir/src/sub2/prog2.c
@@ -1,7 +1,7 @@
#include <stdio.h>
-int main(int argc, char *argv[])
+int main(void)
{
printf("Hello from prog2.c\n");
return 0;
}
--- a/media/webrtc/trunk/tools/gyp/test/variables/commands/commands-repeated.gyp.stdout
+++ b/media/webrtc/trunk/tools/gyp/test/variables/commands/commands-repeated.gyp.stdout
@@ -1,136 +1,136 @@
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output 'ABCDEFG', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'other_letters', 'is_array': '', 'replace': '<(other_letters)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output '<(letters_list)EFGHIJK', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output 'ABCDEFGHIJK', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'included_variable', 'is_array': '', 'replace': '<(included_variable)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output 'XYZ', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'included_variable', 'is_array': '', 'replace': '<(included_variable)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output 'XYZ', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'third_letters', 'is_array': '', 'replace': '<(third_letters)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output '<(other_letters)HIJK', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'other_letters', 'is_array': '', 'replace': '<(other_letters)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output '<(letters_list)EFGHIJK', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output 'ABCDEFGHIJK', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'python -c "print \'<!(python -c "<(pi', 'is_array': '', 'replace': '<!(python -c "print \'<!(python -c "<(pi)', 'type': '<!', 'command_string': None}
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'python -c "<(pi', 'is_array': '', 'replace': '<!(python -c "<(pi)', 'type': '<!', 'command_string': None}
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'pi', 'is_array': '', 'replace': '<(pi)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output 'python -c "import math; print math.pi"', recursing.
-VARIABLES:input.py:676:ExpandVariables Executing command 'python -c "import math; print math.pi"' in directory 'None'
-VARIABLES:input.py:797:ExpandVariables Found output 'python -c "print \'3.14159265359 ABCD\'"', recursing.
-VARIABLES:input.py:676:ExpandVariables Executing command 'python -c "print '3.14159265359 ABCD'"' in directory 'None'
-VARIABLES:input.py:797:ExpandVariables Found output '3.14159265359 ABCD', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': '"python", "-c", "<(pi', 'is_array': '[', 'replace': '<!(["python", "-c", "<(pi)', 'type': '<!', 'command_string': None}
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'pi', 'is_array': '', 'replace': '<(pi)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output '["python", "-c", "import math; print math.pi"]', recursing.
-VARIABLES:input.py:676:ExpandVariables Executing command '['python', '-c', 'import math; print math.pi']' in directory 'None'
-VARIABLES:input.py:797:ExpandVariables Found output '3.14159265359', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': '<!(python -c "print \'letters_list\'"', 'is_array': '', 'replace': '<(<!(python -c "print \'letters_list\'")', 'type': '<', 'command_string': None}
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'python -c "print \'letters_list\'"', 'is_array': '', 'replace': '<!(python -c "print \'letters_list\'")', 'type': '<!', 'command_string': None}
-VARIABLES:input.py:676:ExpandVariables Executing command 'python -c "print 'letters_list'"' in directory 'None'
-VARIABLES:input.py:797:ExpandVariables Found output 'letters_list', recursing.
-VARIABLES:input.py:797:ExpandVariables Found output 'ABCD', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'check_int', 'is_array': '', 'replace': '<(check_int)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output '5', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': '"python", "-c", "<(pi', 'is_array': '[', 'replace': '<!(["python", "-c", "<(pi)', 'type': '<!', 'command_string': None}
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'pi', 'is_array': '', 'replace': '<(pi)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output '["python", "-c", "import math; print math.pi"]', recursing.
-VARIABLES:input.py:721:ExpandVariables Had cache value for command '['python', '-c', 'import math; print math.pi']' in directory 'None'
-VARIABLES:input.py:797:ExpandVariables Found output '3.14159265359', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'python -c "print \'<(letters_list', 'is_array': '', 'replace': '<!(python -c "print \'<(letters_list)', 'type': '<!', 'command_string': None}
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output 'python -c "print \'ABCD\'"', recursing.
-VARIABLES:input.py:676:ExpandVariables Executing command 'python -c "print 'ABCD'"' in directory 'None'
-VARIABLES:input.py:797:ExpandVariables Found output 'ABCD', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'python -c "print \'<!(python -c "<(pi', 'is_array': '', 'replace': '<!(python -c "print \'<!(python -c "<(pi)', 'type': '<!', 'command_string': None}
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'python -c "<(pi', 'is_array': '', 'replace': '<!(python -c "<(pi)', 'type': '<!', 'command_string': None}
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'pi', 'is_array': '', 'replace': '<(pi)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output 'python -c "import math; print math.pi"', recursing.
-VARIABLES:input.py:721:ExpandVariables Had cache value for command 'python -c "import math; print math.pi"' in directory 'None'
-VARIABLES:input.py:797:ExpandVariables Found output 'python -c "print \'3.14159265359 ABCD\'"', recursing.
-VARIABLES:input.py:721:ExpandVariables Had cache value for command 'python -c "print '3.14159265359 ABCD'"' in directory 'None'
-VARIABLES:input.py:797:ExpandVariables Found output '3.14159265359 ABCD', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'check_str_int', 'is_array': '', 'replace': '<(check_str_int)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output '6', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'check_int', 'is_array': '', 'replace': '<(check_int)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output '5blah', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': '<!(python -c "print \'letters_list\'"', 'is_array': '', 'replace': '<(<!(python -c "print \'letters_list\'")', 'type': '<', 'command_string': None}
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'python -c "print \'letters_list\'"', 'is_array': '', 'replace': '<!(python -c "print \'letters_list\'")', 'type': '<!', 'command_string': None}
-VARIABLES:input.py:721:ExpandVariables Had cache value for command 'python -c "print 'letters_list'"' in directory 'None'
-VARIABLES:input.py:797:ExpandVariables Found output 'letters_list', recursing.
-VARIABLES:input.py:797:ExpandVariables Found output 'ABCD', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'python -c "print \'<(letters_list', 'is_array': '', 'replace': '<!(python -c "print \'<(letters_list)', 'type': '<!', 'command_string': None}
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output 'python -c "print \'ABCD\'"', recursing.
-VARIABLES:input.py:721:ExpandVariables Had cache value for command 'python -c "print 'ABCD'"' in directory 'None'
-VARIABLES:input.py:797:ExpandVariables Found output 'ABCD', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'not_int_4', 'is_array': '', 'replace': '<(not_int_4)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output '13.0', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'not_int_3', 'is_array': '', 'replace': '<(not_int_3)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output '012', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'negative_int', 'is_array': '', 'replace': '<(negative_int)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output '-15', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'not_int_5', 'is_array': '', 'replace': '<(not_int_5)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output '+14', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'check_list_int', 'is_array': '', 'replace': '<(check_list_int)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output '7 8 9', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'not_int_2', 'is_array': '', 'replace': '<(not_int_2)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output '11 ', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'not_int_1', 'is_array': '', 'replace': '<(not_int_1)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output ' 10', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'zero_int', 'is_array': '', 'replace': '<(zero_int)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output '0', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'check_list_int', 'is_array': '', 'replace': '<@(check_list_int)', 'type': '<@', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output [7, 8, 9], recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'var6', 'is_array': '', 'replace': '<(var6)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'echo <(var5', 'is_array': '', 'replace': '<!(echo <(var5)', 'type': '<!', 'command_string': None}
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'var5', 'is_array': '', 'replace': '<(var5)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output 'echo letters_list', recursing.
-VARIABLES:input.py:676:ExpandVariables Executing command 'echo letters_list' in directory 'None'
-VARIABLES:input.py:797:ExpandVariables Found output 'letters_list', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': '_inputs', 'is_array': '', 'replace': '<(_inputs)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'var2', 'is_array': '', 'replace': '<(var2)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output '3.14159265359 ABCD', recursing.
-VARIABLES:input.py:797:ExpandVariables Found output '"3.14159265359 ABCD"', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': '_outputs', 'is_array': '', 'replace': '<(_outputs)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'var4', 'is_array': '', 'replace': '<(var4)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output 'ABCD', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'var7', 'is_array': '', 'replace': '<(var7)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output 'letters_list', recursing.
-VARIABLES:input.py:797:ExpandVariables Found output 'ABCD letters_list', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'var6', 'is_array': '', 'replace': '<(var6)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'echo <(var5', 'is_array': '', 'replace': '<!(echo <(var5)', 'type': '<!', 'command_string': None}
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'var5', 'is_array': '', 'replace': '<(var5)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output 'echo letters_list', recursing.
-VARIABLES:input.py:721:ExpandVariables Had cache value for command 'echo letters_list' in directory 'None'
-VARIABLES:input.py:797:ExpandVariables Found output 'letters_list', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': '_inputs', 'is_array': '', 'replace': '<(_inputs)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'var2', 'is_array': '', 'replace': '<(var2)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output '3.14159265359 ABCD', recursing.
-VARIABLES:input.py:797:ExpandVariables Found output '"3.14159265359 ABCD"', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': '_outputs', 'is_array': '', 'replace': '<(_outputs)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'var4', 'is_array': '', 'replace': '<(var4)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output 'ABCD', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'var7', 'is_array': '', 'replace': '<(var7)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output 'letters_list', recursing.
-VARIABLES:input.py:797:ExpandVariables Found output 'ABCD letters_list', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'var6', 'is_array': '', 'replace': '<(var6)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'echo <(var5', 'is_array': '', 'replace': '<!(echo <(var5)', 'type': '<!', 'command_string': None}
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'var5', 'is_array': '', 'replace': '<(var5)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output 'echo letters_list', recursing.
-VARIABLES:input.py:721:ExpandVariables Had cache value for command 'echo letters_list' in directory 'None'
-VARIABLES:input.py:797:ExpandVariables Found output 'letters_list', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': '_inputs', 'is_array': '', 'replace': '<(_inputs)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'var2prime', 'is_array': '', 'replace': '<(var2prime)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output '3.14159265359 ABCD', recursing.
-VARIABLES:input.py:797:ExpandVariables Found output '"3.14159265359 ABCD"', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': '_outputs', 'is_array': '', 'replace': '<(_outputs)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'var4prime', 'is_array': '', 'replace': '<(var4prime)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output 'ABCD', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'var7', 'is_array': '', 'replace': '<(var7)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output 'letters_list', recursing.
-VARIABLES:input.py:797:ExpandVariables Found output 'ABCD letters_list', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'other_letters', 'is_array': '', 'replace': '<(other_letters)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '<(letters_list)EFGHIJK', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCDEFGHIJK', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCDEFG', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'included_variable', 'is_array': '', 'replace': '<(included_variable)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'XYZ', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'included_variable', 'is_array': '', 'replace': '<(included_variable)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'XYZ', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'third_letters', 'is_array': '', 'replace': '<(third_letters)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '<(other_letters)HIJK', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'other_letters', 'is_array': '', 'replace': '<(other_letters)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '<(letters_list)EFGHIJK', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCDEFGHIJK', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'python -c "print \'<!(python -c "<(pi', 'is_array': '', 'replace': '<!(python -c "print \'<!(python -c "<(pi)', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'python -c "<(pi', 'is_array': '', 'replace': '<!(python -c "<(pi)', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'pi', 'is_array': '', 'replace': '<(pi)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'python -c "import math; print math.pi"', recursing.
+VARIABLES:input.py:838:ExpandVariables Executing command 'python -c "import math; print math.pi"' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output 'python -c "print \'3.14159265359 ABCD\'"', recursing.
+VARIABLES:input.py:838:ExpandVariables Executing command 'python -c "print '3.14159265359 ABCD'"' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output '3.14159265359 ABCD', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': '"python", "-c", "<(pi', 'is_array': '[', 'replace': '<!(["python", "-c", "<(pi)', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'pi', 'is_array': '', 'replace': '<(pi)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '["python", "-c", "import math; print math.pi"]', recursing.
+VARIABLES:input.py:838:ExpandVariables Executing command '['python', '-c', 'import math; print math.pi']' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output '3.14159265359', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': '<!(python -c "print \'letters_list\'"', 'is_array': '', 'replace': '<(<!(python -c "print \'letters_list\'")', 'type': '<', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'python -c "print \'letters_list\'"', 'is_array': '', 'replace': '<!(python -c "print \'letters_list\'")', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:838:ExpandVariables Executing command 'python -c "print 'letters_list'"' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output 'letters_list', recursing.
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCD', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'check_int', 'is_array': '', 'replace': '<(check_int)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '5', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': '"python", "-c", "<(pi', 'is_array': '[', 'replace': '<!(["python", "-c", "<(pi)', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'pi', 'is_array': '', 'replace': '<(pi)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '["python", "-c", "import math; print math.pi"]', recursing.
+VARIABLES:input.py:889:ExpandVariables Had cache value for command '['python', '-c', 'import math; print math.pi']' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output '3.14159265359', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'python -c "print \'<(letters_list', 'is_array': '', 'replace': '<!(python -c "print \'<(letters_list)', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'python -c "print \'ABCD\'"', recursing.
+VARIABLES:input.py:838:ExpandVariables Executing command 'python -c "print 'ABCD'"' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCD', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'python -c "print \'<!(python -c "<(pi', 'is_array': '', 'replace': '<!(python -c "print \'<!(python -c "<(pi)', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'python -c "<(pi', 'is_array': '', 'replace': '<!(python -c "<(pi)', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'pi', 'is_array': '', 'replace': '<(pi)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'python -c "import math; print math.pi"', recursing.
+VARIABLES:input.py:889:ExpandVariables Had cache value for command 'python -c "import math; print math.pi"' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output 'python -c "print \'3.14159265359 ABCD\'"', recursing.
+VARIABLES:input.py:889:ExpandVariables Had cache value for command 'python -c "print '3.14159265359 ABCD'"' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output '3.14159265359 ABCD', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'check_str_int', 'is_array': '', 'replace': '<(check_str_int)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '6', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'check_int', 'is_array': '', 'replace': '<(check_int)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '5blah', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': '<!(python -c "print \'letters_list\'"', 'is_array': '', 'replace': '<(<!(python -c "print \'letters_list\'")', 'type': '<', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'python -c "print \'letters_list\'"', 'is_array': '', 'replace': '<!(python -c "print \'letters_list\'")', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:889:ExpandVariables Had cache value for command 'python -c "print 'letters_list'"' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output 'letters_list', recursing.
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCD', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'python -c "print \'<(letters_list', 'is_array': '', 'replace': '<!(python -c "print \'<(letters_list)', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'python -c "print \'ABCD\'"', recursing.
+VARIABLES:input.py:889:ExpandVariables Had cache value for command 'python -c "print 'ABCD'"' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCD', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'not_int_4', 'is_array': '', 'replace': '<(not_int_4)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '13.0', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'not_int_3', 'is_array': '', 'replace': '<(not_int_3)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '012', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'negative_int', 'is_array': '', 'replace': '<(negative_int)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '-15', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'not_int_5', 'is_array': '', 'replace': '<(not_int_5)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '+14', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'check_list_int', 'is_array': '', 'replace': '<(check_list_int)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '7 8 9', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'not_int_2', 'is_array': '', 'replace': '<(not_int_2)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '11 ', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'not_int_1', 'is_array': '', 'replace': '<(not_int_1)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output ' 10', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'zero_int', 'is_array': '', 'replace': '<(zero_int)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '0', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'check_list_int', 'is_array': '', 'replace': '<@(check_list_int)', 'type': '<@', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output [7, 8, 9], recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var6', 'is_array': '', 'replace': '<(var6)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'echo <(var5', 'is_array': '', 'replace': '<!(echo <(var5)', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var5', 'is_array': '', 'replace': '<(var5)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'echo letters_list', recursing.
+VARIABLES:input.py:838:ExpandVariables Executing command 'echo letters_list' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output 'letters_list', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': '_inputs', 'is_array': '', 'replace': '<(_inputs)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var2', 'is_array': '', 'replace': '<(var2)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '3.14159265359 ABCD', recursing.
+VARIABLES:input.py:964:ExpandVariables Found output '"3.14159265359 ABCD"', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': '_outputs', 'is_array': '', 'replace': '<(_outputs)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var4', 'is_array': '', 'replace': '<(var4)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCD', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var7', 'is_array': '', 'replace': '<(var7)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'letters_list', recursing.
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCD letters_list', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var6', 'is_array': '', 'replace': '<(var6)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'echo <(var5', 'is_array': '', 'replace': '<!(echo <(var5)', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var5', 'is_array': '', 'replace': '<(var5)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'echo letters_list', recursing.
+VARIABLES:input.py:889:ExpandVariables Had cache value for command 'echo letters_list' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output 'letters_list', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': '_inputs', 'is_array': '', 'replace': '<(_inputs)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var2', 'is_array': '', 'replace': '<(var2)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '3.14159265359 ABCD', recursing.
+VARIABLES:input.py:964:ExpandVariables Found output '"3.14159265359 ABCD"', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': '_outputs', 'is_array': '', 'replace': '<(_outputs)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var4', 'is_array': '', 'replace': '<(var4)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCD', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var7', 'is_array': '', 'replace': '<(var7)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'letters_list', recursing.
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCD letters_list', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var6', 'is_array': '', 'replace': '<(var6)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'echo <(var5', 'is_array': '', 'replace': '<!(echo <(var5)', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var5', 'is_array': '', 'replace': '<(var5)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'echo letters_list', recursing.
+VARIABLES:input.py:889:ExpandVariables Had cache value for command 'echo letters_list' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output 'letters_list', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': '_inputs', 'is_array': '', 'replace': '<(_inputs)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var2prime', 'is_array': '', 'replace': '<(var2prime)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '3.14159265359 ABCD', recursing.
+VARIABLES:input.py:964:ExpandVariables Found output '"3.14159265359 ABCD"', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': '_outputs', 'is_array': '', 'replace': '<(_outputs)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var4prime', 'is_array': '', 'replace': '<(var4prime)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCD', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var7', 'is_array': '', 'replace': '<(var7)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'letters_list', recursing.
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCD letters_list', recursing.
--- a/media/webrtc/trunk/tools/gyp/test/variables/commands/commands-repeated.gypd.golden
+++ b/media/webrtc/trunk/tools/gyp/test/variables/commands/commands-repeated.gypd.golden
@@ -53,16 +53,21 @@
'target_name': 'dummy',
'toolset': 'target',
'type': 'none'}],
'variables': {'check_included': 'XYZ',
'check_int': '5',
'check_list_int': ['7', '8', '9'],
'check_lists': ['XYZ', 'ABCDEFGHIJK'],
'check_str_int': '6',
+ 'default_empty_files%': '',
+ 'default_empty_str%': '',
+ 'default_int%': '0',
+ 'default_int_files%': '0',
+ 'default_str%': 'my_str',
'included_variable': 'XYZ',
'letters_list': 'ABCD',
'negative_int': '-15',
'not_int_1': ' 10',
'not_int_2': '11 ',
'not_int_3': '012',
'not_int_4': '13.0',
'not_int_5': '+14',
--- a/media/webrtc/trunk/tools/gyp/test/variables/commands/commands.gyp
+++ b/media/webrtc/trunk/tools/gyp/test/variables/commands/commands.gyp
@@ -55,16 +55,21 @@
'var13': '<(not_int_2)',
'var14': '<(not_int_3)',
'var15': '<(not_int_4)',
'var16': '<(not_int_5)',
'var17': '<(negative_int)',
'var18': '<(zero_int)',
'var19': ['<!@(python test.py)'],
'var20': '<!(python test.py)',
+ 'var21': '<(default_str)',
+ 'var22': '<(default_empty_str)',
+ 'var23': '<(default_int)',
+ 'var24': '<(default_empty_files)',
+ 'var25': '<(default_int_files)',
},
'actions': [
{
'action_name': 'test_action',
'variables': {
'var7': '<!(echo <(var5)<(var6))',
},
'inputs' : [
--- a/media/webrtc/trunk/tools/gyp/test/variables/commands/commands.gyp.ignore-env.stdout
+++ b/media/webrtc/trunk/tools/gyp/test/variables/commands/commands.gyp.ignore-env.stdout
@@ -1,86 +1,96 @@
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output 'ABCDEFG', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'other_letters', 'is_array': '', 'replace': '<(other_letters)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output '<(letters_list)EFGHIJK', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output 'ABCDEFGHIJK', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'included_variable', 'is_array': '', 'replace': '<(included_variable)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output 'XYZ', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'included_variable', 'is_array': '', 'replace': '<(included_variable)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output 'XYZ', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'third_letters', 'is_array': '', 'replace': '<(third_letters)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output '<(other_letters)HIJK', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'other_letters', 'is_array': '', 'replace': '<(other_letters)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output '<(letters_list)EFGHIJK', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output 'ABCDEFGHIJK', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': '<!(python -c "print \'letters_list\'"', 'is_array': '', 'replace': '<(<!(python -c "print \'letters_list\'")', 'type': '<', 'command_string': None}
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'python -c "print \'letters_list\'"', 'is_array': '', 'replace': '<!(python -c "print \'letters_list\'")', 'type': '<!', 'command_string': None}
-VARIABLES:input.py:676:ExpandVariables Executing command 'python -c "print 'letters_list'"' in directory 'None'
-VARIABLES:input.py:797:ExpandVariables Found output 'letters_list', recursing.
-VARIABLES:input.py:797:ExpandVariables Found output 'ABCD', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'check_int', 'is_array': '', 'replace': '<(check_int)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output '5', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': '"python", "-c", "<(pi', 'is_array': '[', 'replace': '<!(["python", "-c", "<(pi)', 'type': '<!', 'command_string': None}
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'pi', 'is_array': '', 'replace': '<(pi)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output '["python", "-c", "import math; print math.pi"]', recursing.
-VARIABLES:input.py:676:ExpandVariables Executing command '['python', '-c', 'import math; print math.pi']' in directory 'None'
-VARIABLES:input.py:797:ExpandVariables Found output '3.14159265359', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'python -c "print \'<(letters_list', 'is_array': '', 'replace': '<!(python -c "print \'<(letters_list)', 'type': '<!', 'command_string': None}
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output 'python -c "print \'ABCD\'"', recursing.
-VARIABLES:input.py:676:ExpandVariables Executing command 'python -c "print 'ABCD'"' in directory 'None'
-VARIABLES:input.py:797:ExpandVariables Found output 'ABCD', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'python -c "print \'<!(python -c "<(pi', 'is_array': '', 'replace': '<!(python -c "print \'<!(python -c "<(pi)', 'type': '<!', 'command_string': None}
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'python -c "<(pi', 'is_array': '', 'replace': '<!(python -c "<(pi)', 'type': '<!', 'command_string': None}
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'pi', 'is_array': '', 'replace': '<(pi)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output 'python -c "import math; print math.pi"', recursing.
-VARIABLES:input.py:676:ExpandVariables Executing command 'python -c "import math; print math.pi"' in directory 'None'
-VARIABLES:input.py:797:ExpandVariables Found output 'python -c "print \'3.14159265359 ABCD\'"', recursing.
-VARIABLES:input.py:676:ExpandVariables Executing command 'python -c "print '3.14159265359 ABCD'"' in directory 'None'
-VARIABLES:input.py:797:ExpandVariables Found output '3.14159265359 ABCD', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'python test.py', 'is_array': '', 'replace': '<!(python test.py)', 'type': '<!', 'command_string': None}
-VARIABLES:input.py:676:ExpandVariables Executing command 'python test.py' in directory 'None'
-VARIABLES:input.py:797:ExpandVariables Found output 'sample\\path\\foo.cpp', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'check_str_int', 'is_array': '', 'replace': '<(check_str_int)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output '6', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'check_int', 'is_array': '', 'replace': '<(check_int)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output '5blah', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'not_int_4', 'is_array': '', 'replace': '<(not_int_4)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output '13.0', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'not_int_3', 'is_array': '', 'replace': '<(not_int_3)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output '012', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'negative_int', 'is_array': '', 'replace': '<(negative_int)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output '-15', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'not_int_5', 'is_array': '', 'replace': '<(not_int_5)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output '+14', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'check_list_int', 'is_array': '', 'replace': '<(check_list_int)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output '7 8 9', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'not_int_2', 'is_array': '', 'replace': '<(not_int_2)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output '11 ', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'not_int_1', 'is_array': '', 'replace': '<(not_int_1)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output ' 10', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'zero_int', 'is_array': '', 'replace': '<(zero_int)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output '0', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'check_list_int', 'is_array': '', 'replace': '<@(check_list_int)', 'type': '<@', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output [7, 8, 9], recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'python test.py', 'is_array': '', 'replace': '<!@(python test.py)', 'type': '<!@', 'command_string': None}
-VARIABLES:input.py:721:ExpandVariables Had cache value for command 'python test.py' in directory 'None'
-VARIABLES:input.py:797:ExpandVariables Found output ['samplepathfoo.cpp'], recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'var6', 'is_array': '', 'replace': '<(var6)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'echo <(var5', 'is_array': '', 'replace': '<!(echo <(var5)', 'type': '<!', 'command_string': None}
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'var5', 'is_array': '', 'replace': '<(var5)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output 'echo letters_list', recursing.
-VARIABLES:input.py:676:ExpandVariables Executing command 'echo letters_list' in directory 'None'
-VARIABLES:input.py:797:ExpandVariables Found output 'letters_list', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': '_inputs', 'is_array': '', 'replace': '<(_inputs)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'var2', 'is_array': '', 'replace': '<(var2)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output '3.14159265359 ABCD', recursing.
-VARIABLES:input.py:797:ExpandVariables Found output '"3.14159265359 ABCD"', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': '_outputs', 'is_array': '', 'replace': '<(_outputs)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'var4', 'is_array': '', 'replace': '<(var4)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output 'ABCD', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'var7', 'is_array': '', 'replace': '<(var7)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output 'letters_list', recursing.
-VARIABLES:input.py:797:ExpandVariables Found output 'ABCD letters_list', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'other_letters', 'is_array': '', 'replace': '<(other_letters)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '<(letters_list)EFGHIJK', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCDEFGHIJK', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCDEFG', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'included_variable', 'is_array': '', 'replace': '<(included_variable)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'XYZ', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'included_variable', 'is_array': '', 'replace': '<(included_variable)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'XYZ', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'third_letters', 'is_array': '', 'replace': '<(third_letters)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '<(other_letters)HIJK', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'other_letters', 'is_array': '', 'replace': '<(other_letters)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '<(letters_list)EFGHIJK', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCDEFGHIJK', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'default_empty_files', 'is_array': '', 'replace': '<(default_empty_files)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'default_int_files', 'is_array': '', 'replace': '<(default_int_files)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '0', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'python test.py', 'is_array': '', 'replace': '<!(python test.py)', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:838:ExpandVariables Executing command 'python test.py' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output 'sample\\path\\foo.cpp', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'default_str', 'is_array': '', 'replace': '<(default_str)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'my_str', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'default_empty_str', 'is_array': '', 'replace': '<(default_empty_str)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'default_int', 'is_array': '', 'replace': '<(default_int)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '0', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': '<!(python -c "print \'letters_list\'"', 'is_array': '', 'replace': '<(<!(python -c "print \'letters_list\'")', 'type': '<', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'python -c "print \'letters_list\'"', 'is_array': '', 'replace': '<!(python -c "print \'letters_list\'")', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:838:ExpandVariables Executing command 'python -c "print 'letters_list'"' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output 'letters_list', recursing.
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCD', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'check_int', 'is_array': '', 'replace': '<(check_int)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '5', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': '"python", "-c", "<(pi', 'is_array': '[', 'replace': '<!(["python", "-c", "<(pi)', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'pi', 'is_array': '', 'replace': '<(pi)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '["python", "-c", "import math; print math.pi"]', recursing.
+VARIABLES:input.py:838:ExpandVariables Executing command '['python', '-c', 'import math; print math.pi']' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output '3.14159265359', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'python -c "print \'<(letters_list', 'is_array': '', 'replace': '<!(python -c "print \'<(letters_list)', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'python -c "print \'ABCD\'"', recursing.
+VARIABLES:input.py:838:ExpandVariables Executing command 'python -c "print 'ABCD'"' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCD', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'python -c "print \'<!(python -c "<(pi', 'is_array': '', 'replace': '<!(python -c "print \'<!(python -c "<(pi)', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'python -c "<(pi', 'is_array': '', 'replace': '<!(python -c "<(pi)', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'pi', 'is_array': '', 'replace': '<(pi)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'python -c "import math; print math.pi"', recursing.
+VARIABLES:input.py:838:ExpandVariables Executing command 'python -c "import math; print math.pi"' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output 'python -c "print \'3.14159265359 ABCD\'"', recursing.
+VARIABLES:input.py:838:ExpandVariables Executing command 'python -c "print '3.14159265359 ABCD'"' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output '3.14159265359 ABCD', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'check_str_int', 'is_array': '', 'replace': '<(check_str_int)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '6', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'check_int', 'is_array': '', 'replace': '<(check_int)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '5blah', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'not_int_4', 'is_array': '', 'replace': '<(not_int_4)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '13.0', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'not_int_3', 'is_array': '', 'replace': '<(not_int_3)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '012', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'negative_int', 'is_array': '', 'replace': '<(negative_int)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '-15', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'not_int_5', 'is_array': '', 'replace': '<(not_int_5)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '+14', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'check_list_int', 'is_array': '', 'replace': '<(check_list_int)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '7 8 9', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'not_int_2', 'is_array': '', 'replace': '<(not_int_2)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '11 ', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'not_int_1', 'is_array': '', 'replace': '<(not_int_1)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output ' 10', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'zero_int', 'is_array': '', 'replace': '<(zero_int)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '0', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'check_list_int', 'is_array': '', 'replace': '<@(check_list_int)', 'type': '<@', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output [7, 8, 9], recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'python test.py', 'is_array': '', 'replace': '<!@(python test.py)', 'type': '<!@', 'command_string': None}
+VARIABLES:input.py:889:ExpandVariables Had cache value for command 'python test.py' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output ['samplepathfoo.cpp'], recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var6', 'is_array': '', 'replace': '<(var6)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'echo <(var5', 'is_array': '', 'replace': '<!(echo <(var5)', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var5', 'is_array': '', 'replace': '<(var5)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'echo letters_list', recursing.
+VARIABLES:input.py:838:ExpandVariables Executing command 'echo letters_list' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output 'letters_list', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': '_inputs', 'is_array': '', 'replace': '<(_inputs)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var2', 'is_array': '', 'replace': '<(var2)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '3.14159265359 ABCD', recursing.
+VARIABLES:input.py:964:ExpandVariables Found output '"3.14159265359 ABCD"', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': '_outputs', 'is_array': '', 'replace': '<(_outputs)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var4', 'is_array': '', 'replace': '<(var4)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCD', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var7', 'is_array': '', 'replace': '<(var7)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'letters_list', recursing.
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCD letters_list', recursing.
--- a/media/webrtc/trunk/tools/gyp/test/variables/commands/commands.gyp.stdout
+++ b/media/webrtc/trunk/tools/gyp/test/variables/commands/commands.gyp.stdout
@@ -1,86 +1,96 @@
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output 'ABCDEFG', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'other_letters', 'is_array': '', 'replace': '<(other_letters)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output '<(letters_list)EFGHIJK', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output 'ABCDEFGHIJK', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'included_variable', 'is_array': '', 'replace': '<(included_variable)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output 'XYZ', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'included_variable', 'is_array': '', 'replace': '<(included_variable)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output 'XYZ', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'third_letters', 'is_array': '', 'replace': '<(third_letters)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output '<(other_letters)HIJK', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'other_letters', 'is_array': '', 'replace': '<(other_letters)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output '<(letters_list)EFGHIJK', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output 'ABCDEFGHIJK', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': '<!(python -c "print \'letters_list\'"', 'is_array': '', 'replace': '<(<!(python -c "print \'letters_list\'")', 'type': '<', 'command_string': None}
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'python -c "print \'letters_list\'"', 'is_array': '', 'replace': '<!(python -c "print \'letters_list\'")', 'type': '<!', 'command_string': None}
-VARIABLES:input.py:676:ExpandVariables Executing command 'python -c "print 'letters_list'"' in directory 'None'
-VARIABLES:input.py:797:ExpandVariables Found output 'letters_list', recursing.
-VARIABLES:input.py:797:ExpandVariables Found output 'ABCD', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'check_int', 'is_array': '', 'replace': '<(check_int)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output '5', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': '"python", "-c", "<(pi', 'is_array': '[', 'replace': '<!(["python", "-c", "<(pi)', 'type': '<!', 'command_string': None}
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'pi', 'is_array': '', 'replace': '<(pi)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output '["python", "-c", "import math; print math.pi"]', recursing.
-VARIABLES:input.py:676:ExpandVariables Executing command '['python', '-c', 'import math; print math.pi']' in directory 'None'
-VARIABLES:input.py:797:ExpandVariables Found output '3.14159265359', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'python -c "print \'<(letters_list', 'is_array': '', 'replace': '<!(python -c "print \'<(letters_list)', 'type': '<!', 'command_string': None}
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output 'python -c "print \'ABCD\'"', recursing.
-VARIABLES:input.py:676:ExpandVariables Executing command 'python -c "print 'ABCD'"' in directory 'None'
-VARIABLES:input.py:797:ExpandVariables Found output 'ABCD', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'python -c "print \'<!(python -c "<(pi', 'is_array': '', 'replace': '<!(python -c "print \'<!(python -c "<(pi)', 'type': '<!', 'command_string': None}
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'python -c "<(pi', 'is_array': '', 'replace': '<!(python -c "<(pi)', 'type': '<!', 'command_string': None}
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'pi', 'is_array': '', 'replace': '<(pi)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output 'python -c "import math; print math.pi"', recursing.
-VARIABLES:input.py:676:ExpandVariables Executing command 'python -c "import math; print math.pi"' in directory 'None'
-VARIABLES:input.py:797:ExpandVariables Found output 'python -c "print \'3.14159265359 ABCD\'"', recursing.
-VARIABLES:input.py:676:ExpandVariables Executing command 'python -c "print '3.14159265359 ABCD'"' in directory 'None'
-VARIABLES:input.py:797:ExpandVariables Found output '3.14159265359 ABCD', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'python test.py', 'is_array': '', 'replace': '<!(python test.py)', 'type': '<!', 'command_string': None}
-VARIABLES:input.py:676:ExpandVariables Executing command 'python test.py' in directory 'None'
-VARIABLES:input.py:797:ExpandVariables Found output 'sample\\path\\foo.cpp', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'check_str_int', 'is_array': '', 'replace': '<(check_str_int)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output '6', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'check_int', 'is_array': '', 'replace': '<(check_int)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output '5blah', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'not_int_4', 'is_array': '', 'replace': '<(not_int_4)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output '13.0', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'not_int_3', 'is_array': '', 'replace': '<(not_int_3)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output '012', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'negative_int', 'is_array': '', 'replace': '<(negative_int)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output '-15', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'not_int_5', 'is_array': '', 'replace': '<(not_int_5)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output '+14', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'check_list_int', 'is_array': '', 'replace': '<(check_list_int)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output '7 8 9', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'not_int_2', 'is_array': '', 'replace': '<(not_int_2)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output '11 ', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'not_int_1', 'is_array': '', 'replace': '<(not_int_1)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output ' 10', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'zero_int', 'is_array': '', 'replace': '<(zero_int)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output '0', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'check_list_int', 'is_array': '', 'replace': '<@(check_list_int)', 'type': '<@', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output [7, 8, 9], recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'python test.py', 'is_array': '', 'replace': '<!@(python test.py)', 'type': '<!@', 'command_string': None}
-VARIABLES:input.py:721:ExpandVariables Had cache value for command 'python test.py' in directory 'None'
-VARIABLES:input.py:797:ExpandVariables Found output ['samplepathfoo.cpp'], recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'var6', 'is_array': '', 'replace': '<(var6)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'echo <(var5', 'is_array': '', 'replace': '<!(echo <(var5)', 'type': '<!', 'command_string': None}
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'var5', 'is_array': '', 'replace': '<(var5)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output 'echo letters_list', recursing.
-VARIABLES:input.py:676:ExpandVariables Executing command 'echo letters_list' in directory 'None'
-VARIABLES:input.py:797:ExpandVariables Found output 'letters_list', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': '_inputs', 'is_array': '', 'replace': '<(_inputs)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'var2', 'is_array': '', 'replace': '<(var2)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output '3.14159265359 ABCD', recursing.
-VARIABLES:input.py:797:ExpandVariables Found output '"3.14159265359 ABCD"', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': '_outputs', 'is_array': '', 'replace': '<(_outputs)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'var4', 'is_array': '', 'replace': '<(var4)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output 'ABCD', recursing.
-VARIABLES:input.py:562:ExpandVariables Matches: {'content': 'var7', 'is_array': '', 'replace': '<(var7)', 'type': '<', 'command_string': None}
-VARIABLES:input.py:797:ExpandVariables Found output 'letters_list', recursing.
-VARIABLES:input.py:797:ExpandVariables Found output 'ABCD letters_list', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'other_letters', 'is_array': '', 'replace': '<(other_letters)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '<(letters_list)EFGHIJK', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCDEFGHIJK', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCDEFG', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'included_variable', 'is_array': '', 'replace': '<(included_variable)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'XYZ', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'included_variable', 'is_array': '', 'replace': '<(included_variable)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'XYZ', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'third_letters', 'is_array': '', 'replace': '<(third_letters)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '<(other_letters)HIJK', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'other_letters', 'is_array': '', 'replace': '<(other_letters)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '<(letters_list)EFGHIJK', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCDEFGHIJK', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'default_empty_files', 'is_array': '', 'replace': '<(default_empty_files)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'default_int_files', 'is_array': '', 'replace': '<(default_int_files)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '0', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'python test.py', 'is_array': '', 'replace': '<!(python test.py)', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:838:ExpandVariables Executing command 'python test.py' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output 'sample\\path\\foo.cpp', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'default_str', 'is_array': '', 'replace': '<(default_str)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'my_str', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'default_empty_str', 'is_array': '', 'replace': '<(default_empty_str)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'default_int', 'is_array': '', 'replace': '<(default_int)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '0', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': '<!(python -c "print \'letters_list\'"', 'is_array': '', 'replace': '<(<!(python -c "print \'letters_list\'")', 'type': '<', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'python -c "print \'letters_list\'"', 'is_array': '', 'replace': '<!(python -c "print \'letters_list\'")', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:838:ExpandVariables Executing command 'python -c "print 'letters_list'"' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output 'letters_list', recursing.
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCD', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'check_int', 'is_array': '', 'replace': '<(check_int)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '5', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': '"python", "-c", "<(pi', 'is_array': '[', 'replace': '<!(["python", "-c", "<(pi)', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'pi', 'is_array': '', 'replace': '<(pi)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '["python", "-c", "import math; print math.pi"]', recursing.
+VARIABLES:input.py:838:ExpandVariables Executing command '['python', '-c', 'import math; print math.pi']' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output '3.14159265359', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'python -c "print \'<(letters_list', 'is_array': '', 'replace': '<!(python -c "print \'<(letters_list)', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'python -c "print \'ABCD\'"', recursing.
+VARIABLES:input.py:838:ExpandVariables Executing command 'python -c "print 'ABCD'"' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCD', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'letters_list', 'is_array': '', 'replace': '<(letters_list)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'python -c "print \'<!(python -c "<(pi', 'is_array': '', 'replace': '<!(python -c "print \'<!(python -c "<(pi)', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'python -c "<(pi', 'is_array': '', 'replace': '<!(python -c "<(pi)', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'pi', 'is_array': '', 'replace': '<(pi)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'python -c "import math; print math.pi"', recursing.
+VARIABLES:input.py:838:ExpandVariables Executing command 'python -c "import math; print math.pi"' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output 'python -c "print \'3.14159265359 ABCD\'"', recursing.
+VARIABLES:input.py:838:ExpandVariables Executing command 'python -c "print '3.14159265359 ABCD'"' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output '3.14159265359 ABCD', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'check_str_int', 'is_array': '', 'replace': '<(check_str_int)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '6', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'check_int', 'is_array': '', 'replace': '<(check_int)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '5blah', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'not_int_4', 'is_array': '', 'replace': '<(not_int_4)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '13.0', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'not_int_3', 'is_array': '', 'replace': '<(not_int_3)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '012', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'negative_int', 'is_array': '', 'replace': '<(negative_int)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '-15', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'not_int_5', 'is_array': '', 'replace': '<(not_int_5)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '+14', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'check_list_int', 'is_array': '', 'replace': '<(check_list_int)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '7 8 9', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'not_int_2', 'is_array': '', 'replace': '<(not_int_2)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '11 ', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'not_int_1', 'is_array': '', 'replace': '<(not_int_1)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output ' 10', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'zero_int', 'is_array': '', 'replace': '<(zero_int)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '0', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'check_list_int', 'is_array': '', 'replace': '<@(check_list_int)', 'type': '<@', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output [7, 8, 9], recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'python test.py', 'is_array': '', 'replace': '<!@(python test.py)', 'type': '<!@', 'command_string': None}
+VARIABLES:input.py:889:ExpandVariables Had cache value for command 'python test.py' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output ['samplepathfoo.cpp'], recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var6', 'is_array': '', 'replace': '<(var6)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'echo <(var5', 'is_array': '', 'replace': '<!(echo <(var5)', 'type': '<!', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var5', 'is_array': '', 'replace': '<(var5)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'echo letters_list', recursing.
+VARIABLES:input.py:838:ExpandVariables Executing command 'echo letters_list' in directory 'None'
+VARIABLES:input.py:964:ExpandVariables Found output 'letters_list', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': '_inputs', 'is_array': '', 'replace': '<(_inputs)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var2', 'is_array': '', 'replace': '<(var2)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output '3.14159265359 ABCD', recursing.
+VARIABLES:input.py:964:ExpandVariables Found output '"3.14159265359 ABCD"', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': '_outputs', 'is_array': '', 'replace': '<(_outputs)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var4', 'is_array': '', 'replace': '<(var4)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCD', recursing.
+VARIABLES:input.py:724:ExpandVariables Matches: {'content': 'var7', 'is_array': '', 'replace': '<(var7)', 'type': '<', 'command_string': None}
+VARIABLES:input.py:964:ExpandVariables Found output 'letters_list', recursing.
+VARIABLES:input.py:964:ExpandVariables Found output 'ABCD letters_list', recursing.
--- a/media/webrtc/trunk/tools/gyp/test/variables/commands/commands.gypd.golden
+++ b/media/webrtc/trunk/tools/gyp/test/variables/commands/commands.gypd.golden
@@ -20,16 +20,21 @@
'var14': '012',
'var15': '13.0',
'var16': '+14',
'var17': '-15',
'var18': '0',
'var19': ['samplepathfoo.cpp'],
'var2': '3.14159265359 ABCD',
'var20': 'sample\\path\\foo.cpp',
+ 'var21': 'my_str',
+ 'var22': '',
+ 'var23': '0',
+ 'var24': '',
+ 'var25': '0',
'var3': 'ABCD',
'var4': 'ABCD',
'var5': 'letters_',
'var6': 'list',
'var7': '5',
'var8': '5blah',
'var9': '6'}},
{'configurations': {'Default': {}},
@@ -37,16 +42,21 @@
'target_name': 'dummy',
'toolset': 'target',
'type': 'none'}],
'variables': {'check_included': 'XYZ',
'check_int': '5',
'check_list_int': ['7', '8', '9'],
'check_lists': ['XYZ', 'ABCDEFGHIJK'],
'check_str_int': '6',
+ 'default_empty_files%': '',
+ 'default_empty_str%': '',
+ 'default_int%': '0',
+ 'default_int_files%': '0',
+ 'default_str%': 'my_str',
'included_variable': 'XYZ',
'letters_list': 'ABCD',
'negative_int': '-15',
'not_int_1': ' 10',
'not_int_2': '11 ',
'not_int_3': '012',
'not_int_4': '13.0',
'not_int_5': '+14',
--- a/media/webrtc/trunk/tools/gyp/test/variables/commands/commands.gypi
+++ b/media/webrtc/trunk/tools/gyp/test/variables/commands/commands.gypi
@@ -1,16 +1,23 @@
# 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.
# This file is included from commands.gyp to test evaluation order of includes.
{
'variables': {
'included_variable': 'XYZ',
+
+ 'default_str%': 'my_str',
+ 'default_empty_str%': '',
+ 'default_int%': 0,
+
+ 'default_empty_files%': '',
+ 'default_int_files%': 0,
},
'targets': [
{
'target_name': 'dummy',
'type': 'none',
},
],
}
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/variables/commands/gyptest-commands-repeated-multidir.py
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+
+# Copyright 2014 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.
+
+"""
+Test variable expansion of '<!()' syntax commands where they are evaluated
+more than once from different directories.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+# This tests GYP's cache of commands, ensuring that the directory a command is
+# run from is part of its cache key. Parallelism may lead to multiple cache
+# lookups failing, resulting in the command being run multiple times by
+# chance, not by GYP's logic. Turn off parallelism to ensure that the logic is
+# being tested.
+test.run_gyp('repeated_multidir/main.gyp', '--no-parallel')
+
+test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/variables/commands/repeated_multidir/dir_1/test_1.gyp
@@ -0,0 +1,13 @@
+# Copyright 2014 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.
+
+{
+ 'variables': {
+ 'expected_value': 'dir_1',
+ 'target_name': 'target_1',
+ },
+ 'includes': [
+ '../repeated_command_common.gypi',
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/variables/commands/repeated_multidir/dir_2/test_2.gyp
@@ -0,0 +1,13 @@
+# Copyright 2014 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.
+
+{
+ 'variables': {
+ 'expected_value': 'dir_2',
+ 'target_name': 'target_2',
+ },
+ 'includes': [
+ '../repeated_command_common.gypi',
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/variables/commands/repeated_multidir/main.gyp
@@ -0,0 +1,16 @@
+# Copyright 2014 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': 'main',
+ 'type': 'none',
+ 'dependencies': [
+ 'dir_1/test_1.gyp:target_1',
+ 'dir_2/test_2.gyp:target_2',
+ ],
+ },
+ ],
+}
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/variables/commands/repeated_multidir/print_cwd_basename.py
@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+
+# Copyright 2014 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.
+
+import os
+import os.path
+
+print os.path.basename(os.getcwd())
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/variables/commands/repeated_multidir/repeated_command_common.gypi
@@ -0,0 +1,25 @@
+# Copyright 2014 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.
+
+{
+ 'variables': {
+ # This command will be run from the directories of the .gyp files that
+ # include this .gypi, the subdirectories dir_1 and dir_2, so use a
+ # relative path from those directories to the script.
+ 'observed_value': '<!(python ../print_cwd_basename.py)',
+ },
+ 'targets': [
+ {
+ 'target_name': '<(target_name)',
+ 'type': 'none',
+ 'conditions': [
+ ['observed_value != expected_value', {
+ # Attempt to expand an undefined variable. This triggers a GYP
+ # error.
+ 'assertion': '<(observed_value_must_equal_expected_value)',
+ }],
+ ],
+ },
+ ],
+}
--- a/media/webrtc/trunk/tools/gyp/test/variables/commands/update_golden
+++ b/media/webrtc/trunk/tools/gyp/test/variables/commands/update_golden
@@ -1,11 +1,11 @@
#!/bin/bash
# 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.
-python ../../../gyp --debug variables --debug general --format gypd --depth . commands.gyp > commands.gyp.stdout
-python ../../../gyp --ignore-environment --debug variables --debug general --format gypd --depth . commands.gyp > commands.gyp.ignore-env.stdout
+python ../../../gyp --debug variables --format gypd --depth . commands.gyp > commands.gyp.stdout
+python ../../../gyp --ignore-environment --debug variables --format gypd --depth . commands.gyp > commands.gyp.ignore-env.stdout
cp -f commands.gypd commands.gypd.golden
-python ../../../gyp --debug variables --debug general --format gypd --depth . commands-repeated.gyp > commands-repeated.gyp.stdout
+python ../../../gyp --debug variables --format gypd --depth . commands-repeated.gyp > commands-repeated.gyp.stdout
cp -f commands-repeated.gypd commands-repeated.gypd.golden
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/variables/empty/empty.gyp
@@ -0,0 +1,13 @@
+# Copyright (c) 2015 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.
+
+{
+ 'includes': ['empty.gypi'],
+ 'targets': [
+ {
+ 'target_name': 'empty',
+ 'type': 'none',
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/variables/empty/empty.gypi
@@ -0,0 +1,9 @@
+# Copyright (c) 2015 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.
+
+{
+ 'variables': {
+ '': '',
+ },
+}
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/variables/empty/gyptest-empty.py
@@ -0,0 +1,19 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2015 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.
+
+"""
+Test that empty variable names don't cause infinite loops.
+"""
+
+import os
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('empty.gyp')
+
+test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/variables/filelist/gyptest-filelist-golden.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 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.
+
+"""
+Test variable expansion of '<|(list.txt ...)' syntax commands.
+"""
+
+import os
+import sys
+
+import TestGyp
+
+test = TestGyp.TestGyp(format='gypd')
+
+expect = test.read('filelist.gyp.stdout')
+if sys.platform == 'win32':
+ expect = expect.replace('/', r'\\').replace('\r\n', '\n')
+
+test.run_gyp('src/filelist.gyp',
+ '--debug', 'variables',
+ stdout=expect, ignore_line_numbers=True)
+
+# Verify the filelist.gypd against the checked-in expected contents.
+#
+# Normally, we should canonicalize line endings in the expected
+# contents file setting the Subversion svn:eol-style to native,
+# but that would still fail if multiple systems are sharing a single
+# workspace on a network-mounted file system. Consequently, we
+# massage the Windows line endings ('\r\n') in the output to the
+# checked-in UNIX endings ('\n').
+
+contents = test.read('src/filelist.gypd').replace(
+ '\r', '').replace('\\\\', '/')
+expect = test.read('filelist.gypd.golden').replace('\r', '')
+if not test.match(contents, expect):
+ print "Unexpected contents of `src/filelist.gypd'"
+ test.diff(expect, contents, 'src/filelist.gypd ')
+ test.fail_test()
+
+contents = test.read('src/names.txt')
+expect = 'John\nJacob\nJingleheimer\nSchmidt\n'
+if not test.match(contents, expect):
+ print "Unexpected contents of `src/names.txt'"
+ test.diff(expect, contents, 'src/names.txt ')
+ test.fail_test()
+
+test.pass_test()
+
--- a/media/webrtc/trunk/tools/gyp/test/variables/filelist/gyptest-filelist.py
+++ b/media/webrtc/trunk/tools/gyp/test/variables/filelist/gyptest-filelist.py
@@ -8,43 +8,22 @@
Test variable expansion of '<|(list.txt ...)' syntax commands.
"""
import os
import sys
import TestGyp
-test = TestGyp.TestGyp(format='gypd')
-
-expect = test.read('filelist.gyp.stdout')
-if sys.platform == 'win32':
- expect = expect.replace('/', r'\\').replace('\r\n', '\n')
-
-test.run_gyp('src/filelist.gyp',
- '--debug', 'variables',
- stdout=expect, ignore_line_numbers=True)
+test = TestGyp.TestGyp()
-# Verify the filelist.gypd against the checked-in expected contents.
-#
-# Normally, we should canonicalize line endings in the expected
-# contents file setting the Subversion svn:eol-style to native,
-# but that would still fail if multiple systems are sharing a single
-# workspace on a network-mounted file system. Consequently, we
-# massage the Windows line endings ('\r\n') in the output to the
-# checked-in UNIX endings ('\n').
+CHDIR = 'src'
+test.run_gyp('filelist2.gyp', chdir=CHDIR)
-contents = test.read('src/filelist.gypd').replace(
- '\r', '').replace('\\\\', '/')
-expect = test.read('filelist.gypd.golden').replace('\r', '')
-if not test.match(contents, expect):
- print "Unexpected contents of `src/filelist.gypd'"
- test.diff(expect, contents, 'src/filelist.gypd ')
- test.fail_test()
-
-contents = test.read('src/names.txt')
+test.build('filelist2.gyp', 'foo', chdir=CHDIR)
+contents = test.read('src/dummy_foo').replace('\r', '')
expect = 'John\nJacob\nJingleheimer\nSchmidt\n'
if not test.match(contents, expect):
- print "Unexpected contents of `src/names.txt'"
- test.diff(expect, contents, 'src/names.txt ')
+ print "Unexpected contents of `src/dummy_foo'"
+ test.diff(expect, contents, 'src/dummy_foo')
test.fail_test()
test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/variables/filelist/src/dummy.py
@@ -0,0 +1,5 @@
+#!/usr/bin/env python
+
+import sys
+
+open(sys.argv[1], 'w').write(open(sys.argv[2]).read())
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/variables/filelist/src/filelist2.gyp
@@ -0,0 +1,40 @@
+# Copyright (c) 2013 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.
+
+# This is a test to make sure that <|(foo.txt a b c) generates
+# a pre-calculated file list at gyp time and returns foo.txt.
+# This feature is useful to work around limits in the number of arguments that
+# can be passed to rule/action.
+
+{
+ 'variables': {
+ 'names': [
+ 'John',
+ 'Jacob',
+ 'Jingleheimer',
+ 'Schmidt',
+ ],
+ },
+ 'targets': [
+ {
+ 'target_name': 'foo',
+ 'type': 'none',
+ 'variables': {
+ 'names_listfile': '<|(names.txt <@(names))',
+ },
+ 'actions': [
+ {
+ 'action_name': 'test_action',
+ 'msvs_cygwin_shell': 0,
+ 'inputs' : [ '<(names_listfile)' ],
+ 'outputs': [ 'dummy_foo' ],
+ 'action': [
+ 'python', 'dummy.py', '<@(_outputs)', '<(names_listfile)',
+ ],
+ },
+ ],
+ },
+ ],
+}
+
--- a/media/webrtc/trunk/tools/gyp/test/variables/latelate/src/program.cc
+++ b/media/webrtc/trunk/tools/gyp/test/variables/latelate/src/program.cc
@@ -2,12 +2,12 @@
* Copyright (c) 2012 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>
-int main(int argc, char *argv[]) {
+int main(void) {
printf(FOO "\n");
return 0;
}
deleted file mode 100755
--- a/media/webrtc/trunk/tools/gyp/test/variants/gyptest-variants.py
+++ /dev/null
@@ -1,45 +0,0 @@
-#!/usr/bin/env python
-
-# 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.
-
-"""
-Verify handling of build variants.
-
-TODO: Right now, only the SCons generator supports this, so the
-test case is SCons-specific. In particular, it relise on SCons'
-ability to rebuild in response to changes on the command line. It
-may be simpler to just drop this feature if the other generators
-can't be made to behave the same way.
-"""
-
-import TestGyp
-
-test = TestGyp.TestGyp(formats=['scons'])
-
-test.run_gyp('variants.gyp', chdir='src')
-
-test.relocate('src', 'relocate/src')
-
-test.build('variants.gyp', chdir='relocate/src')
-
-test.run_built_executable('variants',
- chdir='relocate/src',
- stdout="Hello, world!\n")
-
-test.sleep()
-test.build('variants.gyp', 'VARIANT1=1', chdir='relocate/src')
-
-test.run_built_executable('variants',
- chdir='relocate/src',
- stdout="Hello from VARIANT1\n")
-
-test.sleep()
-test.build('variants.gyp', 'VARIANT2=1', chdir='relocate/src')
-
-test.run_built_executable('variants',
- chdir='relocate/src',
- stdout="Hello from VARIANT2\n")
-
-test.pass_test()
deleted file mode 100644
--- a/media/webrtc/trunk/tools/gyp/test/variants/src/variants.c
+++ /dev/null
@@ -1,13 +0,0 @@
-#include <stdio.h>
-
-int main(int argc, char *argv[])
-{
-#if defined(VARIANT1)
- printf("Hello from VARIANT1\n");
-#elif defined(VARIANT2)
- printf("Hello from VARIANT2\n");
-#else
- printf("Hello, world!\n");
-#endif
- return 0;
-}
deleted file mode 100644
--- a/media/webrtc/trunk/tools/gyp/test/variants/src/variants.gyp
+++ /dev/null
@@ -1,27 +0,0 @@
-# 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': 'variants',
- 'type': 'executable',
- 'sources': [
- 'variants.c',
- ],
- 'variants': {
- 'variant1' : {
- 'defines': [
- 'VARIANT1',
- ],
- },
- 'variant2' : {
- 'defines': [
- 'VARIANT2',
- ],
- },
- },
- },
- ],
-}
--- a/media/webrtc/trunk/tools/gyp/test/win/command-quote/command-quote.gyp
+++ b/media/webrtc/trunk/tools/gyp/test/win/command-quote/command-quote.gyp
@@ -10,75 +10,70 @@
{
'target_name': 'test_batch',
'type': 'none',
'rules': [
{
'rule_name': 'build_with_batch',
'msvs_cygwin_shell': 0,
'extension': 'S',
- 'inputs': ['<(RULE_INPUT_PATH)'],
'outputs': ['output.obj'],
'action': ['call go.bat', '<(RULE_INPUT_PATH)', 'output.obj'],
},],
'sources': ['a.S'],
},
{
'target_name': 'test_call_separate',
'type': 'none',
'rules': [
{
'rule_name': 'build_with_batch2',
'msvs_cygwin_shell': 0,
'extension': 'S',
- 'inputs': ['<(RULE_INPUT_PATH)'],
'outputs': ['output2.obj'],
'action': ['call', 'go.bat', '<(RULE_INPUT_PATH)', 'output2.obj'],
},],
'sources': ['a.S'],
},
{
'target_name': 'test_with_spaces',
'type': 'none',
'rules': [
{
'rule_name': 'build_with_batch3',
'msvs_cygwin_shell': 0,
'extension': 'S',
- 'inputs': ['<(RULE_INPUT_PATH)'],
'outputs': ['output3.obj'],
'action': ['bat with spaces.bat', '<(RULE_INPUT_PATH)', 'output3.obj'],
},],
'sources': ['a.S'],
},
{
'target_name': 'test_with_double_quotes',
'type': 'none',
'rules': [
{
'rule_name': 'build_with_batch3',
'msvs_cygwin_shell': 1,
'extension': 'S',
- 'inputs': ['<(RULE_INPUT_PATH)'],
'outputs': ['output4.obj'],
'arguments': ['-v'],
'action': ['python', '-c', 'import shutil; '
'shutil.copy("<(RULE_INPUT_PATH)", "output4.obj")'],
},],
'sources': ['a.S'],
},
{
'target_name': 'test_with_single_quotes',
'type': 'none',
'rules': [
{
'rule_name': 'build_with_batch3',
'msvs_cygwin_shell': 1,
'extension': 'S',
- 'inputs': ['<(RULE_INPUT_PATH)'],
'outputs': ['output5.obj'],
'action': ['python', '-c', "import shutil; "
"shutil.copy('<(RULE_INPUT_PATH)', 'output5.obj')"],
},],
'sources': ['a.S'],
},
]
}
--- a/media/webrtc/trunk/tools/gyp/test/win/command-quote/subdir/and/another/in-subdir.gyp
+++ b/media/webrtc/trunk/tools/gyp/test/win/command-quote/subdir/and/another/in-subdir.gyp
@@ -13,16 +13,15 @@
# I guess it should work here too.
'filepath': [ 'call <(DEPTH)/../../../go.bat' ],
},
'rules': [
{
'rule_name': 'build_with_batch4',
'msvs_cygwin_shell': 0,
'extension': 'S',
- 'inputs': ['<(RULE_INPUT_PATH)'],
'outputs': ['output4.obj'],
'action': ['<@(filepath)', '<(RULE_INPUT_PATH)', 'output4.obj'],
},],
'sources': ['<(DEPTH)\\..\\..\\..\\a.S'],
},
]
}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/compiler-flags/analysis.gyp
@@ -0,0 +1,40 @@
+# Copyright (c) 2012 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': 'test_analysis_on',
+ 'type': 'executable',
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'EnablePREfast': 'true',
+ 'WarnAsError': 'true',
+ },
+ },
+ 'sources': ['uninit.cc'],
+ },
+ {
+ 'target_name': 'test_analysis_off',
+ 'type': 'executable',
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'EnablePREfast': 'false',
+ 'WarnAsError': 'true',
+ },
+ },
+ 'sources': ['uninit.cc'],
+ },
+ {
+ 'target_name': 'test_analysis_unspec',
+ 'type': 'executable',
+ 'sources': ['uninit.cc'],
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'WarnAsError': 'true',
+ },
+ },
+ },
+ ]
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/compiler-flags/calling-convention-cdecl.def
@@ -0,0 +1,6 @@
+; Copyright (c) 2014 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.
+
+EXPORTS
+ foo
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/compiler-flags/calling-convention-fastcall.def
@@ -0,0 +1,6 @@
+; Copyright (c) 2014 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.
+
+EXPORTS
+ @foo@0
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/compiler-flags/calling-convention-stdcall.def
@@ -0,0 +1,6 @@
+; Copyright (c) 2014 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.
+
+EXPORTS
+ _foo@0
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/compiler-flags/calling-convention-vectorcall.def
@@ -0,0 +1,6 @@
+; Copyright (c) 2014 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.
+
+EXPORTS
+ foo@@0
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/compiler-flags/calling-convention.cc
@@ -0,0 +1,6 @@
+// Copyright (c) 2014 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.
+
+extern "C" void foo() {
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/compiler-flags/calling-convention.gyp
@@ -0,0 +1,66 @@
+# Copyright (c) 2014 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': 'test_cdecl',
+ 'type': 'loadable_module',
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'CallingConvention': 0,
+ },
+ },
+ 'sources': [
+ 'calling-convention.cc',
+ 'calling-convention-cdecl.def',
+ ],
+ },
+ {
+ 'target_name': 'test_fastcall',
+ 'type': 'loadable_module',
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'CallingConvention': 1,
+ },
+ },
+ 'sources': [
+ 'calling-convention.cc',
+ 'calling-convention-fastcall.def',
+ ],
+ },
+ {
+ 'target_name': 'test_stdcall',
+ 'type': 'loadable_module',
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'CallingConvention': 2,
+ },
+ },
+ 'sources': [
+ 'calling-convention.cc',
+ 'calling-convention-stdcall.def',
+ ],
+ },
+ ],
+ 'conditions': [
+ ['MSVS_VERSION[0:4]>="2013"', {
+ 'targets': [
+ {
+ 'target_name': 'test_vectorcall',
+ 'type': 'loadable_module',
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'CallingConvention': 3,
+ },
+ },
+ 'sources': [
+ 'calling-convention.cc',
+ 'calling-convention-vectorcall.def',
+ ],
+ },
+ ],
+ }],
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/compiler-flags/compile-as-managed.cc
@@ -0,0 +1,9 @@
+// Copyright (c) 2015 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 <vcclr.h>
+
+int main() {
+ return 0;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/compiler-flags/compile-as-managed.gyp
@@ -0,0 +1,29 @@
+# Copyright (c) 2015 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': 'test-compile-as-managed',
+ 'type': 'executable',
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'CompileAsManaged': 'true',
+ 'ExceptionHandling': '0' # /clr is incompatible with /EHs
+ }
+ },
+ 'sources': ['compile-as-managed.cc'],
+ },
+ {
+ 'target_name': 'test-compile-as-unmanaged',
+ 'type': 'executable',
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'CompileAsManaged': 'false',
+ }
+ },
+ 'sources': ['compile-as-managed.cc'],
+ },
+ ]
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/compiler-flags/compile-as-winrt.cc
@@ -0,0 +1,12 @@
+// Copyright (c) 2016 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.
+
+using namespace Platform;
+
+int main() {
+ wchar_t msg[] = L"Test";
+ String^ str1 = ref new String(msg);
+ auto str2 = String::Concat(str1, " Concat");
+ return 0;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/compiler-flags/compile-as-winrt.gyp
@@ -0,0 +1,20 @@
+# Copyright (c) 2016 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': 'test-compile-as-winrt',
+ 'type': 'executable',
+ 'msvs_windows_sdk_version': 'v10.0',
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'AdditionalUsingDirectories': ['$(VCInstallDir)vcpackages;$(WindowsSdkDir)UnionMetadata;%(AdditionalUsingDirectories)'],
+ 'CompileAsWinRT': 'true'
+ }
+ },
+ 'sources': ['compile-as-winrt.cc']
+ }
+ ]
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/compiler-flags/default-char-is-unsigned.cc
@@ -0,0 +1,15 @@
+// Copyright (c) 2012 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.
+
+template <bool>
+struct CompileAssert {
+};
+
+#define COMPILE_ASSERT(expr, msg) \
+ typedef CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1]
+
+int main() {
+ COMPILE_ASSERT(char(-1) > 0, default_char_is_unsigned);
+ return 0;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/compiler-flags/default-char-is-unsigned.gyp
@@ -0,0 +1,20 @@
+# Copyright (c) 2010 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': 'test_default_char_is_unsigned',
+ 'type': 'executable',
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'DefaultCharIsUnsigned': 'true',
+ },
+ },
+ 'sources': [
+ 'default-char-is-unsigned.cc',
+ ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/compiler-flags/disable-specific-warnings.cc
@@ -0,0 +1,9 @@
+// Copyright (c) 2013 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 main() {
+ // Causes level 1 warning (C4700)
+ int i;
+ return i;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/compiler-flags/disable-specific-warnings.gyp
@@ -0,0 +1,29 @@
+# Copyright (c) 2013 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': 'test_disable_specific_warnings_set',
+ 'type': 'executable',
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'WarnAsError': 'true',
+ 'DisableSpecificWarnings': ['4700']
+ }
+ },
+ 'sources': ['disable-specific-warnings.cc']
+ },
+ {
+ 'target_name': 'test_disable_specific_warnings_unset',
+ 'type': 'executable',
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'WarnAsError': 'true'
+ }
+ },
+ 'sources': ['disable-specific-warnings.cc']
+ },
+ ]
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/compiler-flags/enable-enhanced-instruction-set.cc
@@ -0,0 +1,28 @@
+// Copyright (c) 2014 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>
+
+static const char* GetArchOption() {
+#if _M_IX86_FP == 0
+ return "IA32";
+#elif _M_IX86_FP == 1
+ return "SSE";
+#elif _M_IX86_FP == 2
+# if defined(__AVX2__)
+ return "AVX2";
+# elif defined(__AVX__)
+ return "AVX";
+# else
+ return "SSE2";
+# endif
+#else
+ return "UNSUPPORTED OPTION";
+#endif
+}
+
+int main() {
+ printf("/arch:%s\n", GetArchOption());
+ return 0;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/compiler-flags/enable-enhanced-instruction-set.gyp
@@ -0,0 +1,68 @@
+# Copyright (c) 2014 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': 'sse_extensions',
+ 'type': 'executable',
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'EnableEnhancedInstructionSet': '1', # StreamingSIMDExtensions
+ }
+ },
+ 'sources': ['enable-enhanced-instruction-set.cc'],
+ },
+ {
+ 'target_name': 'sse2_extensions',
+ 'type': 'executable',
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'EnableEnhancedInstructionSet': '2', # StreamingSIMDExtensions2
+ }
+ },
+ 'sources': ['enable-enhanced-instruction-set.cc'],
+ },
+ ],
+ 'conditions': [
+ ['MSVS_VERSION[0:4]>"2010"', {
+ 'targets': [
+ {
+ 'target_name': 'avx_extensions',
+ 'type': 'executable',
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'EnableEnhancedInstructionSet': '3', # AdvancedVectorExtensions
+ }
+ },
+ 'sources': ['enable-enhanced-instruction-set.cc'],
+ },
+ {
+ 'target_name': 'no_extensions',
+ 'type': 'executable',
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'EnableEnhancedInstructionSet': '4', # NoExtensions
+ }
+ },
+ 'sources': ['enable-enhanced-instruction-set.cc'],
+ },
+ ],
+ }],
+ ['MSVS_VERSION[0:4]>="2013"', {
+ 'targets': [
+ {
+ 'target_name': 'avx2_extensions',
+ 'type': 'executable',
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'EnableEnhancedInstructionSet': '5', # AdvancedVectorExtensions2
+ }
+ },
+ 'sources': ['enable-enhanced-instruction-set.cc'],
+ },
+ ],
+ }],
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/compiler-flags/floating-point-model-fast.cc
@@ -0,0 +1,19 @@
+// Copyright (c) 2014 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.
+
+#ifdef _M_FP_PRECISE
+#error
+#endif
+
+#ifdef _M_FP_STRICT
+#error
+#endif
+
+#ifndef _M_FP_FAST
+#error
+#endif
+
+int main() {
+ return 0;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/compiler-flags/floating-point-model-precise.cc
@@ -0,0 +1,19 @@
+// Copyright (c) 2014 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.
+
+#ifndef _M_FP_PRECISE
+#error
+#endif
+
+#ifdef _M_FP_STRICT
+#error
+#endif
+
+#ifdef _M_FP_FAST
+#error
+#endif
+
+int main() {
+ return 0;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/compiler-flags/floating-point-model-strict.cc
@@ -0,0 +1,19 @@
+// Copyright (c) 2014 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.
+
+#ifdef _M_FP_PRECISE
+#error
+#endif
+
+#ifndef _M_FP_STRICT
+#error
+#endif
+
+#ifdef _M_FP_FAST
+#error
+#endif
+
+int main() {
+ return 0;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/compiler-flags/floating-point-model.gyp
@@ -0,0 +1,43 @@
+# Copyright (c) 2014 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': 'test-floating-point-model-default',
+ 'type': 'executable',
+ 'sources': ['floating-point-model-precise.cc'],
+ },
+ {
+ 'target_name': 'test-floating-point-model-precise',
+ 'type': 'executable',
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'FloatingPointModel': '0'
+ }
+ },
+ 'sources': ['floating-point-model-precise.cc'],
+ },
+ {
+ 'target_name': 'test-floating-point-model-strict',
+ 'type': 'executable',
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'FloatingPointModel': '1'
+ }
+ },
+ 'sources': ['floating-point-model-strict.cc'],
+ },
+ {
+ 'target_name': 'test-floating-point-model-fast',
+ 'type': 'executable',
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'FloatingPointModel': '2'
+ }
+ },
+ 'sources': ['floating-point-model-fast.cc'],
+ },
+ ]
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/compiler-flags/force-include-files-with-precompiled.cc
@@ -0,0 +1,10 @@
+// Copyright (c) 2012 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>
+
+int main() {
+ std::string s;
+ return 0;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/compiler-flags/force-include-files.cc
@@ -0,0 +1,8 @@
+// Copyright (c) 2012 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 main() {
+ std::list<std::vector<std::string> > l;
+ return 0;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/compiler-flags/force-include-files.gyp
@@ -0,0 +1,36 @@
+# Copyright (c) 2010 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': 'test_force_include_files',
+ 'type': 'executable',
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'ForcedIncludeFiles': ['string', 'vector', 'list'],
+ },
+ },
+ 'sources': [
+ 'force-include-files.cc',
+ ],
+ },
+ {
+ 'target_name': 'test_force_include_with_precompiled',
+ 'type': 'executable',
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'ForcedIncludeFiles': ['string'],
+ },
+ },
+ 'msvs_precompiled_header': 'stdio.h',
+ 'msvs_precompiled_source': 'precomp.cc',
+ 'msvs_disabled_warnings': [ 4530, ],
+ 'sources': [
+ 'force-include-files-with-precompiled.cc',
+ 'precomp.cc',
+ ],
+ },
+ ],
+}
--- a/media/webrtc/trunk/tools/gyp/test/win/compiler-flags/optimizations.gyp
+++ b/media/webrtc/trunk/tools/gyp/test/win/compiler-flags/optimizations.gyp
@@ -69,16 +69,36 @@
'msvs_settings': {
'VCCLCompilerTool': {
'OmitFramePointers': 'false'
}
},
'sources': ['hello.cc'],
},
{
+ 'target_name': 'test_opt_intrinsic',
+ 'type': 'executable',
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'EnableIntrinsicFunctions': 'true'
+ }
+ },
+ 'sources': ['hello.cc'],
+ },
+ {
+ 'target_name': 'test_opt_intrinsic_off',
+ 'type': 'executable',
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'EnableIntrinsicFunctions': 'false'
+ }
+ },
+ 'sources': ['hello.cc'],
+ },
+ {
'target_name': 'test_opt_inline_off',
'type': 'executable',
'msvs_settings': {
'VCCLCompilerTool': {
'InlineFunctionExpansion': '0'
}
},
'sources': ['hello.cc'],
@@ -138,10 +158,50 @@
'type': 'executable',
'msvs_settings': {
'VCCLCompilerTool': {
'WholeProgramOptimization': 'true'
}
},
'sources': ['hello.cc'],
},
+ {
+ 'target_name': 'test_opt_sp',
+ 'type': 'executable',
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'StringPooling': 'true'
+ }
+ },
+ 'sources': ['hello.cc'],
+ },
+ {
+ 'target_name': 'test_opt_sp_off',
+ 'type': 'executable',
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'StringPooling': 'false'
+ }
+ },
+ 'sources': ['hello.cc'],
+ },
+ {
+ 'target_name': 'test_opt_fso',
+ 'type': 'executable',
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'EnableFiberSafeOptimizations': 'true'
+ }
+ },
+ 'sources': ['hello.cc'],
+ },
+ {
+ 'target_name': 'test_opt_fso_off',
+ 'type': 'executable',
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'EnableFiberSafeOptimizations': 'false'
+ }
+ },
+ 'sources': ['hello.cc'],
+ },
]
}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/compiler-flags/pdbname-override.gyp
@@ -0,0 +1,26 @@
+# Copyright (c) 2013 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': 'test_pdbname',
+ 'type': 'executable',
+ 'sources': [
+ 'hello.cc',
+ 'pdbname.cc',
+ ],
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'DebugInformationFormat': '3',
+ 'ProgramDataBaseFileName': '<(PRODUCT_DIR)/compiler_generated.pdb',
+ },
+ 'VCLinkerTool': {
+ 'GenerateDebugInformation': 'true',
+ 'ProgramDatabaseFile': '<(PRODUCT_DIR)/linker_generated.pdb',
+ },
+ },
+ },
+ ]
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/compiler-flags/precomp.cc
@@ -0,0 +1,6 @@
+// Copyright 2013 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 <windows.h>
+#include <stdio.h>
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/compiler-flags/treat-wchar-t-as-built-in-type.gyp
@@ -0,0 +1,33 @@
+# Copyright (c) 2010 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': 'test_treat_wchar_t_as_built_in_type_negative',
+ 'type': 'executable',
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'TreatWChar_tAsBuiltInType': 'false',
+ },
+ },
+ 'sources': [
+ 'treat-wchar-t-as-built-in-type1.cc',
+ ],
+ },
+ {
+ 'target_name': 'test_treat_wchar_t_as_built_in_type_positive',
+ 'type': 'executable',
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'TreatWChar_tAsBuiltInType': 'true',
+ },
+ },
+ 'sources': [
+ 'treat-wchar-t-as-built-in-type2.cc',
+ ],
+ },
+
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/compiler-flags/treat-wchar-t-as-built-in-type1.cc
@@ -0,0 +1,11 @@
+// Copyright (c) 2012 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.
+
+#ifdef _NATIVE_WCHAR_T_DEFINED
+#error
+#endif
+
+int main() {
+ return 0;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/compiler-flags/treat-wchar-t-as-built-in-type2.cc
@@ -0,0 +1,11 @@
+// Copyright (c) 2012 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.
+
+#ifndef _NATIVE_WCHAR_T_DEFINED
+#error
+#endif
+
+int main() {
+ return 0;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/compiler-flags/uninit.cc
@@ -0,0 +1,13 @@
+// Copyright (c) 2012 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.
+
+// Should trigger C6001: using uninitialized memory <variable> for |i|.
+int f(bool b) {
+ int i;
+ if (b)
+ i = 0;
+ return i;
+}
+
+int main() {}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/enable-winrt/dllmain.cc
@@ -0,0 +1,30 @@
+// Copyright (c) 2013 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 <windows.h>
+#include <wrl.h>
+#include <wrl/wrappers/corewrappers.h>
+#include <windows.graphics.display.h>
+
+using namespace Microsoft::WRL;
+using namespace Microsoft::WRL::Wrappers;
+using namespace ABI::Windows::Foundation;
+using namespace ABI::Windows::Graphics::Display;
+
+bool TryToUseSomeWinRT() {
+ ComPtr<IDisplayPropertiesStatics> dp;
+ HStringReference s(RuntimeClass_Windows_Graphics_Display_DisplayProperties);
+ HRESULT hr = GetActivationFactory(s.Get(), dp.GetAddressOf());
+ if (SUCCEEDED(hr)) {
+ float dpi = 96.0f;
+ if (SUCCEEDED(dp->get_LogicalDpi(&dpi))) {
+ return true;
+ }
+ }
+ return false;
+}
+
+BOOL WINAPI DllMain(HINSTANCE hinstance, DWORD reason, LPVOID reserved) {
+ return TRUE;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/enable-winrt/enable-winrt.gyp
@@ -0,0 +1,39 @@
+# Copyright (c) 2013 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': 'enable_winrt_dll',
+ 'type': 'shared_library',
+ 'msvs_enable_winrt': 1,
+ 'sources': [
+ 'dllmain.cc',
+ ],
+ },
+ {
+ 'target_name': 'enable_winrt_missing_dll',
+ 'type': 'shared_library',
+ 'sources': [
+ 'dllmain.cc',
+ ],
+ },
+ {
+ 'target_name': 'enable_winrt_winphone_dll',
+ 'type': 'shared_library',
+ 'msvs_enable_winrt': 1,
+ 'msvs_enable_winphone': 1,
+ 'sources': [
+ 'dllmain.cc',
+ ],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'AdditionalDependencies': [
+ '%(AdditionalDependencies)',
+ ],
+ },
+ },
+ },
+ ]
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/generator-output-different-drive/gyptest-generator-output-different-drive.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 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.
+
+"""
+Test that the generator output can be written to a different drive on Windows.
+"""
+
+import os
+import TestGyp
+import string
+import subprocess
+import sys
+
+
+if sys.platform == 'win32':
+ import win32api
+
+ test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+ def GetFirstFreeDriveLetter():
+ """ Returns the first unused Windows drive letter in [A, Z] """
+ all_letters = [c for c in string.uppercase]
+ in_use = win32api.GetLogicalDriveStrings()
+ free = list(set(all_letters) - set(in_use))
+ return free[0]
+
+ output_dir = os.path.join('different-drive', 'output')
+ if not os.path.isdir(os.path.abspath(output_dir)):
+ os.makedirs(os.path.abspath(output_dir))
+ output_drive = GetFirstFreeDriveLetter()
+ subprocess.call(['subst', '%c:' % output_drive, os.path.abspath(output_dir)])
+ try:
+ test.run_gyp('prog.gyp', '--generator-output=%s' % (
+ os.path.join(output_drive, 'output')))
+ test.build('prog.gyp', test.ALL, chdir=os.path.join(output_drive, 'output'))
+ test.built_file_must_exist('program', chdir=os.path.join(output_drive,
+ 'output'),
+ type=test.EXECUTABLE)
+ test.pass_test()
+ finally:
+ subprocess.call(['subst', '%c:' % output_drive, '/D'])
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/generator-output-different-drive/prog.c
@@ -0,0 +1,10 @@
+// Copyright 2013 The Chromium Authors. 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>
+
+int main(void) {
+ printf("Hello from prog.c\n");
+ return 0;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/generator-output-different-drive/prog.gyp
@@ -0,0 +1,15 @@
+# Copyright 2013 The Chromium Authors. 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': 'program',
+ 'type': 'executable',
+ 'sources': [
+ 'prog.c',
+ ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-cl-analysis.py
@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 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.
+
+"""
+Make sure PREfast (code analysis) setting is extracted properly.
+"""
+
+import TestGyp
+
+import os
+import sys
+
+if (sys.platform == 'win32' and
+ int(os.environ.get('GYP_MSVS_VERSION', 0)) >= 2012):
+ test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+ CHDIR = 'compiler-flags'
+ test.run_gyp('analysis.gyp', chdir=CHDIR)
+
+ # Analysis enabled, should fail.
+ test.build('analysis.gyp', 'test_analysis_on', chdir=CHDIR, status=1)
+
+ # Analysis not enabled, or unspecified, should pass.
+ test.build('analysis.gyp', 'test_analysis_off', chdir=CHDIR)
+ test.build('analysis.gyp', 'test_analysis_unspec', chdir=CHDIR)
+
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-cl-calling-convention.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 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.
+
+"""
+Make sure calling convention setting is extracted properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+ test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+ CHDIR = 'compiler-flags'
+ test.run_gyp('calling-convention.gyp', chdir=CHDIR)
+ test.build('calling-convention.gyp', test.ALL, chdir=CHDIR)
+
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-cl-compile-as-managed.py
@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2015 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.
+
+"""
+Make sure compile as managed (clr) settings are extracted properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+ test = TestGyp.TestGyp()
+
+ CHDIR = 'compiler-flags'
+ test.run_gyp('compile-as-managed.gyp', chdir=CHDIR)
+ test.build('compile-as-managed.gyp', "test-compile-as-managed", chdir=CHDIR)
+ # Must fail.
+ test.build('compile-as-managed.gyp', "test-compile-as-unmanaged",
+ chdir=CHDIR, status=1)
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-cl-compile-as-winrt.py
@@ -0,0 +1,20 @@
+# Copyright (c) 2016 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.
+
+import TestGyp
+
+import os
+import sys
+
+if (sys.platform == 'win32' and
+ int(os.environ.get('GYP_MSVS_VERSION', 0)) >= 2015):
+ test = TestGyp.TestGyp(formats=['msvs'])
+
+ CHDIR = 'compiler-flags'
+
+ test.run_gyp('compile-as-winrt.gyp', chdir=CHDIR)
+
+ test.build('compile-as-winrt.gyp', 'test-compile-as-winrt', chdir=CHDIR)
+
+ test.pass_test()
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-cl-default-char-is-unsigned.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 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.
+
+"""
+Make sure DefaultCharIsUnsigned option is functional.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+ test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+ CHDIR = 'compiler-flags'
+ test.run_gyp('default-char-is-unsigned.gyp', chdir=CHDIR)
+ test.build('default-char-is-unsigned.gyp', test.ALL, chdir=CHDIR)
+
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-cl-disable-specific-warnings.py
@@ -0,0 +1,32 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 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.
+
+"""
+Make sure disable specific warnings is extracted properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+ test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+ CHDIR = 'compiler-flags'
+ test.run_gyp('disable-specific-warnings.gyp', chdir=CHDIR)
+
+ # The source file contains a warning, so if WarnAsError is true and
+ # DisableSpecificWarnings for the warning in question is set, then the build
+ # should succeed, otherwise it must fail.
+
+ test.build('disable-specific-warnings.gyp',
+ 'test_disable_specific_warnings_set',
+ chdir=CHDIR)
+ test.build('disable-specific-warnings.gyp',
+ 'test_disable_specific_warnings_unset',
+ chdir=CHDIR, status=1)
+
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-cl-enable-enhanced-instruction-set.py
@@ -0,0 +1,47 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 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.
+
+"""
+Test VCCLCompilerTool EnableEnhancedInstructionSet setting.
+"""
+
+import TestGyp
+
+import os
+import sys
+
+if sys.platform == 'win32':
+ print "This test is currently disabled: https://crbug.com/483696."
+ sys.exit(0)
+
+ test = TestGyp.TestGyp()
+
+ CHDIR = 'compiler-flags'
+ test.run_gyp('enable-enhanced-instruction-set.gyp', chdir=CHDIR)
+
+ test.build('enable-enhanced-instruction-set.gyp', test.ALL, chdir=CHDIR)
+
+ test.run_built_executable('sse_extensions', chdir=CHDIR,
+ stdout='/arch:SSE\n')
+ test.run_built_executable('sse2_extensions', chdir=CHDIR,
+ stdout='/arch:SSE2\n')
+
+ # /arch:AVX introduced in VS2010, but MSBuild support lagged until 2012.
+ if os.path.exists(test.built_file_path('avx_extensions')):
+ test.run_built_executable('avx_extensions', chdir=CHDIR,
+ stdout='/arch:AVX\n')
+
+ # /arch:IA32 introduced in VS2012.
+ if os.path.exists(test.built_file_path('no_extensions')):
+ test.run_built_executable('no_extensions', chdir=CHDIR,
+ stdout='/arch:IA32\n')
+
+ # /arch:AVX2 introduced in VS2013r2.
+ if os.path.exists(test.built_file_path('avx2_extensions')):
+ test.run_built_executable('avx2_extensions', chdir=CHDIR,
+ stdout='/arch:AVX2\n')
+
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-cl-floating-point-model.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 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.
+
+"""
+Make sure floating point model settings are extracted properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+ test = TestGyp.TestGyp()
+
+ CHDIR = 'compiler-flags'
+ test.run_gyp('floating-point-model.gyp', chdir=CHDIR)
+ test.build('floating-point-model.gyp', test.ALL, chdir=CHDIR)
+
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-cl-force-include-files.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 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.
+
+"""
+Make sure ForcedIncludeFiles option is functional.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+ test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+ CHDIR = 'compiler-flags'
+ test.run_gyp('force-include-files.gyp', chdir=CHDIR)
+ test.build('force-include-files.gyp', test.ALL, chdir=CHDIR)
+
+ test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/win/gyptest-cl-optimizations.py
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-cl-optimizations.py
@@ -32,26 +32,36 @@ if sys.platform == 'win32':
test.must_contain(ninja_file, 'cflags = /O2')
ninja_file = test.built_file_path('obj/test_opt_lev_max.ninja', chdir=CHDIR)
test.must_contain(ninja_file, 'cflags = /Ox')
ninja_file = test.built_file_path('obj/test_opt_unset.ninja', chdir=CHDIR)
test.must_not_contain(ninja_file, '/Od')
test.must_not_contain(ninja_file, '/O1')
- test.must_not_contain(ninja_file, '/O2')
test.must_not_contain(ninja_file, '/Ox')
+ # Set by default if none specified.
+ test.must_contain(ninja_file, '/O2')
ninja_file = test.built_file_path('obj/test_opt_fpo.ninja', chdir=CHDIR)
test.must_contain(ninja_file, '/Oy')
test.must_not_contain(ninja_file, '/Oy-')
ninja_file = test.built_file_path('obj/test_opt_fpo_off.ninja', chdir=CHDIR)
test.must_contain(ninja_file, '/Oy-')
+ ninja_file = test.built_file_path('obj/test_opt_intrinsic.ninja',
+ chdir=CHDIR)
+ test.must_contain(ninja_file, '/Oi')
+ test.must_not_contain(ninja_file, '/Oi-')
+
+ ninja_file = test.built_file_path('obj/test_opt_intrinsic_off.ninja',
+ chdir=CHDIR)
+ test.must_contain(ninja_file, '/Oi-')
+
ninja_file = test.built_file_path('obj/test_opt_inline_off.ninja',
chdir=CHDIR)
test.must_contain(ninja_file, '/Ob0')
ninja_file = test.built_file_path('obj/test_opt_inline_manual.ninja',
chdir=CHDIR)
test.must_contain(ninja_file, '/Ob1')
@@ -71,9 +81,25 @@ if sys.platform == 'win32':
ninja_file = test.built_file_path('obj/test_opt_speed.ninja',
chdir=CHDIR)
test.must_contain(ninja_file, '/Ot')
ninja_file = test.built_file_path('obj/test_opt_wpo.ninja',
chdir=CHDIR)
test.must_contain(ninja_file, '/GL')
+ ninja_file = test.built_file_path('obj/test_opt_sp.ninja',
+ chdir=CHDIR)
+ test.must_contain(ninja_file, '/GF')
+
+ ninja_file = test.built_file_path('obj/test_opt_sp_off.ninja',
+ chdir=CHDIR)
+ test.must_not_contain(ninja_file, '/GF')
+
+ ninja_file = test.built_file_path('obj/test_opt_fso.ninja',
+ chdir=CHDIR)
+ test.must_contain(ninja_file, '/GT')
+
+ ninja_file = test.built_file_path('obj/test_opt_fso_off.ninja',
+ chdir=CHDIR)
+ test.must_not_contain(ninja_file, '/GT')
+
test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-cl-pdbname-override.py
@@ -0,0 +1,27 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 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.
+
+"""
+Make sure pdb is named as expected (shared between .cc files).
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+ test = TestGyp.TestGyp()
+
+ CHDIR = 'compiler-flags'
+ test.run_gyp('pdbname-override.gyp', chdir=CHDIR)
+ test.build('pdbname-override.gyp', test.ALL, chdir=CHDIR)
+
+ # Confirm that the pdb generated by the compiler was renamed (and we also
+ # have the linker generated one).
+ test.built_file_must_exist('compiler_generated.pdb', chdir=CHDIR)
+ test.built_file_must_exist('linker_generated.pdb', chdir=CHDIR)
+
+ test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/win/gyptest-cl-pdbname.py
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-cl-pdbname.py
@@ -1,11 +1,11 @@
#!/usr/bin/env python
-# Copyright (c) 2012 Google Inc. All rights reserved.
+# Copyright (c) 2013 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.
"""
Make sure pdb is named as expected (shared between .cc files).
"""
import TestGyp
@@ -16,11 +16,15 @@ if sys.platform == 'win32':
test = TestGyp.TestGyp(formats=['ninja'])
CHDIR = 'compiler-flags'
test.run_gyp('pdbname.gyp', chdir=CHDIR)
test.build('pdbname.gyp', test.ALL, chdir=CHDIR)
# Confirm that the default behaviour is to name the .pdb per-target (rather
# than per .cc file).
- test.built_file_must_exist('test_pdbname.pdb', chdir=CHDIR)
+ test.built_file_must_exist('obj/test_pdbname.cc.pdb', chdir=CHDIR)
+
+ # Confirm that there should be a .pdb alongside the executable.
+ test.built_file_must_exist('test_pdbname.exe', chdir=CHDIR)
+ test.built_file_must_exist('test_pdbname.exe.pdb', chdir=CHDIR)
test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-cl-treat-wchar-t-as-built-in-type.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 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.
+
+"""
+Make sure TreatWChar_tAsBuiltInType option is functional.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+ test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+ CHDIR = 'compiler-flags'
+ test.run_gyp('treat-wchar-t-as-built-in-type.gyp', chdir=CHDIR)
+ test.build('treat-wchar-t-as-built-in-type.gyp', test.ALL, chdir=CHDIR)
+
+ test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/win/gyptest-command-quote.py
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-command-quote.py
@@ -12,16 +12,19 @@ application in the path. Specifically, t
than calling "x.bat".
"""
import TestGyp
import sys
if sys.platform == 'win32':
+ print "This test is currently disabled: https://crbug.com/483696."
+ sys.exit(0)
+
test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
CHDIR = 'command-quote'
test.run_gyp('command-quote.gyp', chdir=CHDIR)
test.build('command-quote.gyp', 'test_batch', chdir=CHDIR)
test.build('command-quote.gyp', 'test_call_separate', chdir=CHDIR)
test.build('command-quote.gyp', 'test_with_double_quotes', chdir=CHDIR)
test.build('command-quote.gyp', 'test_with_single_quotes', chdir=CHDIR)
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-crosscompile-ar.py
@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+
+# Copyright 2015 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.
+
+"""
+Verifies that ar_host is set correctly when enabling cross-compile on windows.
+"""
+
+import TestGyp
+
+import sys
+import os
+
+if sys.platform == 'win32':
+ test = TestGyp.TestGyp(formats=['ninja'])
+
+ CHDIR = 'lib-crosscompile'
+ oldenv = os.environ.copy()
+ try:
+ os.environ['GYP_CROSSCOMPILE'] = '1'
+ test.run_gyp('use_host_ar.gyp', chdir=CHDIR)
+ finally:
+ os.environ.clear()
+ os.environ.update(oldenv)
+
+ test.build('use_host_ar.gyp', test.ALL, chdir=CHDIR)
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-lib-ltcg.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 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.
+
+"""
+Make sure LTCG setting is extracted properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+ test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+ CHDIR = 'lib-flags'
+ test.run_gyp('ltcg.gyp', chdir=CHDIR)
+ test.build('ltcg.gyp', test.ALL, chdir=CHDIR)
+ test.must_not_contain_any_line(test.stdout(), ['restarting link with /LTCG'])
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-base-address.py
@@ -0,0 +1,62 @@
+#!/usr/bin/env python
+
+# Copyright 2013 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.
+
+"""
+Make sure the base address setting is extracted properly.
+"""
+
+import TestGyp
+
+import re
+import sys
+
+if sys.platform == 'win32':
+ test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+ CHDIR = 'linker-flags'
+ test.run_gyp('base-address.gyp', chdir=CHDIR)
+ test.build('base-address.gyp', test.ALL, chdir=CHDIR)
+
+ def GetHeaders(exe):
+ full_path = test.built_file_path(exe, chdir=CHDIR)
+ return test.run_dumpbin('/headers', full_path)
+
+ # Extract the image base address from the headers output.
+ image_base_reg_ex = re.compile(r'.*\s+([0-9]+) image base.*', re.DOTALL)
+
+ exe_headers = GetHeaders('test_base_specified_exe.exe')
+ exe_match = image_base_reg_ex.match(exe_headers)
+
+ if not exe_match or not exe_match.group(1):
+ test.fail_test()
+ if exe_match.group(1) != '420000':
+ test.fail_test()
+
+ dll_headers = GetHeaders('test_base_specified_dll.dll')
+ dll_match = image_base_reg_ex.match(dll_headers)
+
+ if not dll_match or not dll_match.group(1):
+ test.fail_test()
+ if dll_match.group(1) != '10420000':
+ test.fail_test()
+
+ default_exe_headers = GetHeaders('test_base_default_exe.exe')
+ default_exe_match = image_base_reg_ex.match(default_exe_headers)
+
+ if not default_exe_match or not default_exe_match.group(1):
+ test.fail_test()
+ if default_exe_match.group(1) != '400000':
+ test.fail_test()
+
+ default_dll_headers = GetHeaders('test_base_default_dll.dll')
+ default_dll_match = image_base_reg_ex.match(default_dll_headers)
+
+ if not default_dll_match or not default_dll_match.group(1):
+ test.fail_test()
+ if default_dll_match.group(1) != '10000000':
+ test.fail_test()
+
+ test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-default-libs.py
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-default-libs.py
@@ -11,12 +11,12 @@ Make sure we include the default libs.
import TestGyp
import sys
if sys.platform == 'win32':
test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
CHDIR = 'linker-flags'
- test.run_gyp('default-libs.gyp', chdir=CHDIR)
- test.build('default-libs.gyp', test.ALL, chdir=CHDIR)
+ test.run_gyp('no-default-libs.gyp', chdir=CHDIR)
+ test.build('no-default-libs.gyp', test.ALL, chdir=CHDIR, status=1)
test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-defrelink.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 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.
+
+"""
+Make sure a relink is performed when a .def file is touched.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+ print "This test is currently disabled: https://crbug.com/483696."
+ sys.exit(0)
+
+ test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+ CHDIR = 'linker-flags'
+ target = 'test_deffile_dll_ok'
+ def_contents = test.read('linker-flags/deffile.def')
+
+ # This first build makes sure everything is up to date.
+ test.run_gyp('deffile.gyp', chdir=CHDIR)
+ test.build('deffile.gyp', target, chdir=CHDIR)
+ test.up_to_date('deffile.gyp', target, chdir=CHDIR)
+
+ def HasExport(binary, export):
+ full_path = test.built_file_path(binary, chdir=CHDIR)
+ output = test.run_dumpbin('/exports', full_path)
+ return export in output
+
+ # Verify that only one function is exported.
+ if not HasExport('test_deffile_dll_ok.dll', 'AnExportedFunction'):
+ test.fail_test()
+ if HasExport('test_deffile_dll_ok.dll', 'AnotherExportedFunction'):
+ test.fail_test()
+
+ # Add AnotherExportedFunction to the def file, then rebuild. If it doesn't
+ # relink the DLL, then the subsequent check for AnotherExportedFunction will
+ # fail.
+ new_def_contents = def_contents + "\n AnotherExportedFunction"
+ test.write('linker-flags/deffile.def', new_def_contents)
+ test.build('deffile.gyp', target, chdir=CHDIR)
+ test.up_to_date('deffile.gyp', target, chdir=CHDIR)
+
+ if not HasExport('test_deffile_dll_ok.dll', 'AnExportedFunction'):
+ test.fail_test()
+ if not HasExport('test_deffile_dll_ok.dll', 'AnotherExportedFunction'):
+ test.fail_test()
+
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-embed-manifest.py
@@ -0,0 +1,99 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 Yandex LLC. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure manifests are embedded in binaries properly. Handling of
+AdditionalManifestFiles is tested too.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+ import pywintypes
+ import win32api
+ import winerror
+
+ RT_MANIFEST = 24
+
+ class LoadLibrary(object):
+ """Context manager for loading and releasing binaries in Windows.
+ Yields the handle of the binary loaded."""
+ def __init__(self, path):
+ self._path = path
+ self._handle = None
+
+ def __enter__(self):
+ self._handle = win32api.LoadLibrary(self._path)
+ return self._handle
+
+ def __exit__(self, type, value, traceback):
+ win32api.FreeLibrary(self._handle)
+
+
+ def extract_manifest(path, resource_name):
+ """Reads manifest from |path| and returns it as a string.
+ Returns None is there is no such manifest."""
+ with LoadLibrary(path) as handle:
+ try:
+ return win32api.LoadResource(handle, RT_MANIFEST, resource_name)
+ except pywintypes.error as error:
+ if error.args[0] == winerror.ERROR_RESOURCE_DATA_NOT_FOUND:
+ return None
+ else:
+ raise
+
+ test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+ CHDIR = 'linker-flags'
+ test.run_gyp('embed-manifest.gyp', chdir=CHDIR)
+ test.build('embed-manifest.gyp', test.ALL, chdir=CHDIR)
+
+ # The following binaries must contain a manifest embedded.
+ test.fail_test(not extract_manifest(test.built_file_path(
+ 'test_manifest_exe.exe', chdir=CHDIR), 1))
+ test.fail_test(not extract_manifest(test.built_file_path(
+ 'test_manifest_exe_inc.exe', chdir=CHDIR), 1))
+ test.fail_test(not extract_manifest(test.built_file_path(
+ 'test_manifest_dll.dll', chdir=CHDIR), 2))
+ test.fail_test(not extract_manifest(test.built_file_path(
+ 'test_manifest_dll_inc.dll', chdir=CHDIR), 2))
+
+ # Must contain the Win7 support GUID, but not the Vista one (from
+ # extra2.manifest).
+ test.fail_test(
+ '35138b9a-5d96-4fbd-8e2d-a2440225f93a' not in
+ extract_manifest(test.built_file_path('test_manifest_extra1.exe',
+ chdir=CHDIR), 1))
+ test.fail_test(
+ 'e2011457-1546-43c5-a5fe-008deee3d3f0' in
+ extract_manifest(test.built_file_path('test_manifest_extra1.exe',
+ chdir=CHDIR), 1))
+ # Must contain both.
+ test.fail_test(
+ '35138b9a-5d96-4fbd-8e2d-a2440225f93a' not in
+ extract_manifest(test.built_file_path('test_manifest_extra2.exe',
+ chdir=CHDIR), 1))
+ test.fail_test(
+ 'e2011457-1546-43c5-a5fe-008deee3d3f0' not in
+ extract_manifest(test.built_file_path('test_manifest_extra2.exe',
+ chdir=CHDIR), 1))
+
+ # Same as extra2, but using list syntax instead.
+ test.fail_test(
+ '35138b9a-5d96-4fbd-8e2d-a2440225f93a' not in
+ extract_manifest(test.built_file_path('test_manifest_extra_list.exe',
+ chdir=CHDIR), 1))
+ test.fail_test(
+ 'e2011457-1546-43c5-a5fe-008deee3d3f0' not in
+ extract_manifest(test.built_file_path('test_manifest_extra_list.exe',
+ chdir=CHDIR), 1))
+
+ # Test that incremental linking doesn't force manifest embedding.
+ test.fail_test(extract_manifest(test.built_file_path(
+ 'test_manifest_exe_inc_no_embed.exe', chdir=CHDIR), 1))
+
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-enable-uac.py
@@ -0,0 +1,95 @@
+#!/usr/bin/env python
+
+# Copyright 2013 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.
+
+"""
+Verifies that embedding UAC information into the manifest works.
+"""
+
+import TestGyp
+
+import sys
+from xml.dom.minidom import parseString
+
+if sys.platform == 'win32':
+ import pywintypes
+ import win32api
+ import winerror
+
+ RT_MANIFEST = 24
+
+ class LoadLibrary(object):
+ """Context manager for loading and releasing binaries in Windows.
+ Yields the handle of the binary loaded."""
+ def __init__(self, path):
+ self._path = path
+ self._handle = None
+
+ def __enter__(self):
+ self._handle = win32api.LoadLibrary(self._path)
+ return self._handle
+
+ def __exit__(self, type, value, traceback):
+ win32api.FreeLibrary(self._handle)
+
+
+ def extract_manifest(path, resource_name):
+ """Reads manifest from |path| and returns it as a string.
+ Returns None is there is no such manifest."""
+ with LoadLibrary(path) as handle:
+ try:
+ return win32api.LoadResource(handle, RT_MANIFEST, resource_name)
+ except pywintypes.error as error:
+ if error.args[0] == winerror.ERROR_RESOURCE_DATA_NOT_FOUND:
+ return None
+ else:
+ raise
+
+ test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+ CHDIR = 'linker-flags'
+ test.run_gyp('enable-uac.gyp', chdir=CHDIR)
+ test.build('enable-uac.gyp', test.ALL, chdir=CHDIR)
+
+ # The following binaries must contain a manifest embedded.
+ test.fail_test(not extract_manifest(test.built_file_path(
+ 'enable_uac.exe', chdir=CHDIR), 1))
+ test.fail_test(not extract_manifest(test.built_file_path(
+ 'enable_uac_no.exe', chdir=CHDIR), 1))
+ test.fail_test(not extract_manifest(test.built_file_path(
+ 'enable_uac_admin.exe', chdir=CHDIR), 1))
+
+ # Verify that <requestedExecutionLevel level="asInvoker" uiAccess="false" />
+ # is present.
+ manifest = parseString(extract_manifest(
+ test.built_file_path('enable_uac.exe', chdir=CHDIR), 1))
+ execution_level = manifest.getElementsByTagName('requestedExecutionLevel')
+ test.fail_test(len(execution_level) != 1)
+ execution_level = execution_level[0].attributes
+ test.fail_test(not (
+ execution_level.has_key('level') and
+ execution_level.has_key('uiAccess') and
+ execution_level['level'].nodeValue == 'asInvoker' and
+ execution_level['uiAccess'].nodeValue == 'false'))
+
+ # Verify that <requestedExecutionLevel> is not in the menifest.
+ manifest = parseString(extract_manifest(
+ test.built_file_path('enable_uac_no.exe', chdir=CHDIR), 1))
+ execution_level = manifest.getElementsByTagName('requestedExecutionLevel')
+ test.fail_test(len(execution_level) != 0)
+
+ # Verify that <requestedExecutionLevel level="requireAdministrator"
+ # uiAccess="true" /> is present.
+ manifest = parseString(extract_manifest(
+ test.built_file_path('enable_uac_admin.exe', chdir=CHDIR), 1))
+ execution_level = manifest.getElementsByTagName('requestedExecutionLevel')
+ test.fail_test(len(execution_level) != 1)
+ execution_level = execution_level[0].attributes
+ test.fail_test(not (
+ execution_level.has_key('level') and
+ execution_level.has_key('uiAccess') and
+ execution_level['level'].nodeValue == 'requireAdministrator' and
+ execution_level['uiAccess'].nodeValue == 'true'))
+
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-enable-winrt-app-revision.py
@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 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.
+
+"""
+Make sure msvs_application_type_revision works correctly.
+"""
+
+import TestGyp
+
+import os
+import sys
+import struct
+
+CHDIR = 'winrt-app-type-revision'
+
+print 'This test is not currently working on the bots: https://code.google.com/p/gyp/issues/detail?id=466'
+sys.exit(0)
+
+if (sys.platform == 'win32' and
+ int(os.environ.get('GYP_MSVS_VERSION', 0)) == 2013):
+ test = TestGyp.TestGyp(formats=['msvs'])
+
+ test.run_gyp('winrt-app-type-revision.gyp', chdir=CHDIR)
+
+ test.build('winrt-app-type-revision.gyp', 'enable_winrt_81_revision_dll',
+ chdir=CHDIR)
+
+ # Revision is set to 8.2 which is invalid for 2013 projects so compilation
+ # must fail.
+ test.build('winrt-app-type-revision.gyp', 'enable_winrt_82_revision_dll',
+ chdir=CHDIR, status=1)
+
+ # Revision is set to an invalid value for 2013 projects so compilation
+ # must fail.
+ test.build('winrt-app-type-revision.gyp', 'enable_winrt_invalid_revision_dll',
+ chdir=CHDIR, status=1)
+
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-enable-winrt-target-platform-version.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2015 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.
+
+"""
+Make sure msvs_target_platform_version works correctly.
+"""
+
+import TestGyp
+
+import os
+import sys
+import struct
+
+CHDIR = 'winrt-target-platform-version'
+
+print 'This test is not currently working on the bots: https://code.google.com/p/gyp/issues/detail?id=466'
+sys.exit(0)
+
+if (sys.platform == 'win32' and
+ int(os.environ.get('GYP_MSVS_VERSION', 0)) == 2015):
+ test = TestGyp.TestGyp(formats=['msvs'])
+
+ test.run_gyp('winrt-target-platform-version.gyp', chdir=CHDIR)
+
+ test.build('winrt-target-platform-version.gyp',
+ 'enable_winrt_10_platversion_dll', chdir=CHDIR)
+
+ # Target Platform without Minimum Target Platform version defaults to a valid
+ # Target Platform and compiles.
+ test.build('winrt-target-platform-version.gyp',
+ 'enable_winrt_10_platversion_nominver_dll', chdir=CHDIR)
+
+ # Target Platform is set to 9.0 which is invalid for 2015 projects so
+ # compilation must fail.
+ test.build('winrt-target-platform-version.gyp',
+ 'enable_winrt_9_platversion_dll', chdir=CHDIR, status=1)
+
+ # Missing Target Platform for 2015 projects must fail.
+ test.build('winrt-target-platform-version.gyp',
+ 'enable_winrt_missing_platversion_dll', chdir=CHDIR, status=1)
+
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-enable-winrt.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 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.
+
+"""
+Make sure msvs_enable_winrt works correctly.
+"""
+
+import TestGyp
+
+import os
+import sys
+import struct
+
+CHDIR = 'enable-winrt'
+
+print 'This test is not currently working on the bots: https://code.google.com/p/gyp/issues/detail?id=466'
+sys.exit(0)
+
+if (sys.platform == 'win32' and
+ int(os.environ.get('GYP_MSVS_VERSION', 0)) >= 2013):
+ test = TestGyp.TestGyp(formats=['msvs'])
+
+ test.run_gyp('enable-winrt.gyp', chdir=CHDIR)
+
+ test.build('enable-winrt.gyp', 'enable_winrt_dll', chdir=CHDIR)
+
+ test.build('enable-winrt.gyp', 'enable_winrt_missing_dll', chdir=CHDIR,
+ status=1)
+
+ test.build('enable-winrt.gyp', 'enable_winrt_winphone_dll', chdir=CHDIR)
+
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-force-symbol-reference.py
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 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.
+
+"""
+Make sure ForceSymbolReference is translated properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+ test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+ CHDIR = 'linker-flags'
+ test.run_gyp('force-symbol-reference.gyp', chdir=CHDIR)
+ test.build('force-symbol-reference.gyp', test.ALL, chdir=CHDIR)
+
+ output = test.run_dumpbin(
+ '/disasm', test.built_file_path('test_force_reference.exe', chdir=CHDIR))
+ if '?x@@YAHXZ:' not in output or '?y@@YAHXZ:' not in output:
+ test.fail_test()
+ test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-generate-manifest.py
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-generate-manifest.py
@@ -9,36 +9,119 @@ Make sure we generate a manifest file wh
handling AdditionalManifestFiles.
"""
import TestGyp
import sys
if sys.platform == 'win32':
+ import pywintypes
+ import win32api
+ import winerror
+
+ RT_MANIFEST = 24
+
+ class LoadLibrary(object):
+ """Context manager for loading and releasing binaries in Windows.
+ Yields the handle of the binary loaded."""
+ def __init__(self, path):
+ self._path = path
+ self._handle = None
+
+ def __enter__(self):
+ self._handle = win32api.LoadLibrary(self._path)
+ return self._handle
+
+ def __exit__(self, type, value, traceback):
+ win32api.FreeLibrary(self._handle)
+
+ def extract_manifest(path, resource_name):
+ """Reads manifest from |path| and returns it as a string.
+ Returns None is there is no such manifest."""
+ with LoadLibrary(path) as handle:
+ try:
+ return win32api.LoadResource(handle, RT_MANIFEST, resource_name)
+ except pywintypes.error as error:
+ if error.args[0] == winerror.ERROR_RESOURCE_DATA_NOT_FOUND:
+ return None
+ else:
+ raise
+
test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
CHDIR = 'linker-flags'
test.run_gyp('generate-manifest.gyp', chdir=CHDIR)
test.build('generate-manifest.gyp', test.ALL, chdir=CHDIR)
- test.built_file_must_exist('test_manifest_exe.exe.manifest', chdir=CHDIR)
- test.built_file_must_exist('test_manifest_dll.dll.manifest', chdir=CHDIR)
+
+ # Make sure that generation of .generated.manifest does not cause a relink.
+ test.run_gyp('generate-manifest.gyp', chdir=CHDIR)
+ test.up_to_date('generate-manifest.gyp', test.ALL, chdir=CHDIR)
- # Must contain the Win7 support GUID, but not the Vista one (from
- # extra2.manifest).
- extra1_manifest = test.built_file_path(
- 'test_manifest_extra1.exe.manifest', chdir=CHDIR)
- test.must_contain(extra1_manifest, '35138b9a-5d96-4fbd-8e2d-a2440225f93a')
- test.must_not_contain(extra1_manifest, 'e2011457-1546-43c5-a5fe-008deee3d3f0')
+ def test_manifest(filename, generate_manifest, embedded_manifest,
+ extra_manifest):
+ exe_file = test.built_file_path(filename, chdir=CHDIR)
+ if not generate_manifest:
+ test.must_not_exist(exe_file + '.manifest')
+ manifest = extract_manifest(exe_file, 1)
+ test.fail_test(manifest)
+ return
+ if embedded_manifest:
+ manifest = extract_manifest(exe_file, 1)
+ test.fail_test(not manifest)
+ else:
+ test.must_exist(exe_file + '.manifest')
+ manifest = test.read(exe_file + '.manifest')
+ test.fail_test(not manifest)
+ test.fail_test(extract_manifest(exe_file, 1))
+ if generate_manifest:
+ test.must_contain_any_line(manifest, 'requestedExecutionLevel')
+ if extra_manifest:
+ test.must_contain_any_line(manifest,
+ '35138b9a-5d96-4fbd-8e2d-a2440225f93a')
+ test.must_contain_any_line(manifest,
+ 'e2011457-1546-43c5-a5fe-008deee3d3f0')
- # Must contain both.
- extra2_manifest = test.built_file_path(
- 'test_manifest_extra2.exe.manifest', chdir=CHDIR)
- test.must_contain(extra2_manifest, '35138b9a-5d96-4fbd-8e2d-a2440225f93a')
- test.must_contain(extra2_manifest, 'e2011457-1546-43c5-a5fe-008deee3d3f0')
-
- # Same as extra2, but using list syntax instead.
- extra_list_manifest = test.built_file_path(
- 'test_manifest_extra_list.exe.manifest', chdir=CHDIR)
- test.must_contain(extra_list_manifest, '35138b9a-5d96-4fbd-8e2d-a2440225f93a')
- test.must_contain(extra_list_manifest, 'e2011457-1546-43c5-a5fe-008deee3d3f0')
-
+ test_manifest('test_generate_manifest_true.exe',
+ generate_manifest=True,
+ embedded_manifest=False,
+ extra_manifest=False)
+ test_manifest('test_generate_manifest_false.exe',
+ generate_manifest=False,
+ embedded_manifest=False,
+ extra_manifest=False)
+ test_manifest('test_generate_manifest_default.exe',
+ generate_manifest=True,
+ embedded_manifest=False,
+ extra_manifest=False)
+ test_manifest('test_generate_manifest_true_as_embedded.exe',
+ generate_manifest=True,
+ embedded_manifest=True,
+ extra_manifest=False)
+ test_manifest('test_generate_manifest_false_as_embedded.exe',
+ generate_manifest=False,
+ embedded_manifest=True,
+ extra_manifest=False)
+ test_manifest('test_generate_manifest_default_as_embedded.exe',
+ generate_manifest=True,
+ embedded_manifest=True,
+ extra_manifest=False)
+ test_manifest('test_generate_manifest_true_with_extra_manifest.exe',
+ generate_manifest=True,
+ embedded_manifest=False,
+ extra_manifest=True)
+ test_manifest('test_generate_manifest_false_with_extra_manifest.exe',
+ generate_manifest=False,
+ embedded_manifest=False,
+ extra_manifest=True)
+ test_manifest('test_generate_manifest_true_with_extra_manifest_list.exe',
+ generate_manifest=True,
+ embedded_manifest=False,
+ extra_manifest=True)
+ test_manifest('test_generate_manifest_false_with_extra_manifest_list.exe',
+ generate_manifest=False,
+ embedded_manifest=False,
+ extra_manifest=True)
+ test_manifest('test_generate_manifest_default_embed_default.exe',
+ generate_manifest=True,
+ embedded_manifest=True,
+ extra_manifest=False)
test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-large-address-aware.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 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.
+
+"""
+Make sure largeaddressaware setting is extracted properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+ test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+ CHDIR = 'linker-flags'
+ test.run_gyp('large-address-aware.gyp', chdir=CHDIR)
+ test.build('large-address-aware.gyp', test.ALL, chdir=CHDIR)
+
+ def GetHeaders(exe):
+ return test.run_dumpbin('/headers', test.built_file_path(exe, chdir=CHDIR))
+
+ MARKER = 'Application can handle large (>2GB) addresses'
+
+ # Explicitly off.
+ if MARKER in GetHeaders('test_large_address_aware_no.exe'):
+ test.fail_test()
+
+ # Explicitly on.
+ if MARKER not in GetHeaders('test_large_address_aware_yes.exe'):
+ test.fail_test()
+
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-large-pdb.py
@@ -0,0 +1,74 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 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.
+
+"""
+Make sure msvs_large_pdb works correctly.
+"""
+
+import TestGyp
+
+import struct
+import sys
+
+if sys.platform == 'win32':
+ print "This test is currently disabled: https://crbug.com/483696."
+ sys.exit(0)
+
+
+CHDIR = 'large-pdb'
+
+
+def CheckImageAndPdb(test, image_basename, expected_page_size,
+ pdb_basename=None):
+ if not pdb_basename:
+ pdb_basename = image_basename + '.pdb'
+ test.built_file_must_exist(image_basename, chdir=CHDIR)
+ test.built_file_must_exist(pdb_basename, chdir=CHDIR)
+
+ # We expect the PDB to have the given page size. For full details of the
+ # header look here: https://code.google.com/p/pdbparser/wiki/MSF_Format
+ # We read the little-endian 4-byte unsigned integer at position 32 of the
+ # file.
+ pdb_path = test.built_file_path(pdb_basename, chdir=CHDIR)
+ pdb_file = open(pdb_path, 'rb')
+ pdb_file.seek(32, 0)
+ page_size = struct.unpack('<I', pdb_file.read(4))[0]
+ if page_size != expected_page_size:
+ print "Expected page size of %d, got %d for PDB file `%s'." % (
+ expected_page_size, page_size, pdb_path)
+
+
+if sys.platform == 'win32':
+ test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+ test.run_gyp('large-pdb.gyp', chdir=CHDIR)
+
+ test.build('large-pdb.gyp', 'large_pdb_exe', chdir=CHDIR)
+ CheckImageAndPdb(test, 'large_pdb_exe.exe', 4096)
+
+ test.build('large-pdb.gyp', 'small_pdb_exe', chdir=CHDIR)
+ CheckImageAndPdb(test, 'small_pdb_exe.exe', 1024)
+
+ test.build('large-pdb.gyp', 'large_pdb_dll', chdir=CHDIR)
+ CheckImageAndPdb(test, 'large_pdb_dll.dll', 4096)
+
+ test.build('large-pdb.gyp', 'small_pdb_dll', chdir=CHDIR)
+ CheckImageAndPdb(test, 'small_pdb_dll.dll', 1024)
+
+ test.build('large-pdb.gyp', 'large_pdb_implicit_exe', chdir=CHDIR)
+ CheckImageAndPdb(test, 'large_pdb_implicit_exe.exe', 4096)
+
+ # This target has a different PDB name because it uses an
+ # 'msvs_large_pdb_path' variable.
+ test.build('large-pdb.gyp', 'large_pdb_variable_exe', chdir=CHDIR)
+ CheckImageAndPdb(test, 'large_pdb_variable_exe.exe', 4096,
+ pdb_basename='foo.pdb')
+
+ # This target has a different output name because it uses 'product_name'.
+ test.build('large-pdb.gyp', 'large_pdb_product_exe', chdir=CHDIR)
+ CheckImageAndPdb(test, 'bar.exe', 4096)
+
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-ltcg.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 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.
+
+"""
+Make sure LTCG is working properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+ test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+ CHDIR = 'linker-flags'
+ test.run_gyp('ltcg.gyp', chdir=CHDIR)
+
+ # Here we expect LTCG is able to inline functions beyond compile unit.
+ # Note: This marker is embedded in 'inline_test_main.cc'
+ INLINE_MARKER = '==== inlined ===='
+
+ # link.exe generates following lines when LTCG is enabled.
+ # Note: Future link.exe may or may not generate them. Update as needed.
+ LTCG_LINKER_MESSAGES = ['Generating code', 'Finished generating code']
+
+ # test 'LinkTimeCodeGenerationOptionDefault'
+ test.build('ltcg.gyp', 'test_ltcg_off', chdir=CHDIR)
+ test.run_built_executable('test_ltcg_off', chdir=CHDIR)
+ test.must_not_contain_any_line(test.stdout(), [INLINE_MARKER])
+
+ # test 'LinkTimeCodeGenerationOptionUse'
+ test.build('ltcg.gyp', 'test_ltcg_on', chdir=CHDIR)
+ if test.format == 'ninja':
+ # Make sure ninja win_tool.py filters out noisy lines.
+ test.must_not_contain_any_line(test.stdout(), LTCG_LINKER_MESSAGES)
+ elif test.format == 'msvs':
+ test.must_contain_any_line(test.stdout(), LTCG_LINKER_MESSAGES)
+ test.run_built_executable('test_ltcg_on', chdir=CHDIR)
+ test.must_contain_any_line(test.stdout(), [INLINE_MARKER])
+
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-mapfile.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 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.
+
+"""
+Make sure mapfile settings are extracted properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+ test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+ CHDIR = 'linker-flags'
+ test.run_gyp('mapfile.gyp', chdir=CHDIR)
+ test.build('mapfile.gyp', test.ALL, chdir=CHDIR)
+
+ map_file = test.built_file_path('test_mapfile_unset.map', chdir=CHDIR)
+ test.must_not_exist(map_file)
+
+ map_file = test.built_file_path('test_mapfile_generate.map', chdir=CHDIR)
+ test.must_exist(map_file)
+ test.must_contain(map_file, '?AnExportedFunction@@YAXXZ')
+ test.must_not_contain(map_file, 'void __cdecl AnExportedFunction(void)')
+
+ map_file = test.built_file_path('test_mapfile_generate_exports.map',
+ chdir=CHDIR)
+ test.must_exist(map_file)
+ test.must_contain(map_file, 'void __cdecl AnExportedFunction(void)')
+
+ map_file = test.built_file_path('test_mapfile_generate_filename.map',
+ chdir=CHDIR)
+ test.must_not_exist(map_file)
+
+ map_file = test.built_file_path('custom_file_name.map', chdir=CHDIR)
+ test.must_exist(map_file)
+ test.must_contain(map_file, '?AnExportedFunction@@YAXXZ')
+ test.must_not_contain(map_file, 'void __cdecl AnExportedFunction(void)')
+
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-noimportlib.py
@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2015 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.
+
+"""
+Make sure that the (custom) NoImportLibrary flag is handled correctly.
+"""
+
+import TestGyp
+
+import os
+import sys
+
+if sys.platform == 'win32':
+ test = TestGyp.TestGyp(formats=['ninja'])
+
+ CHDIR = 'importlib'
+ test.run_gyp('noimplib.gyp', chdir=CHDIR)
+ test.build('noimplib.gyp', test.ALL, chdir=CHDIR)
+
+ # The target has an entry point, but no exports. Ordinarily, ninja expects
+ # all DLLs to export some symbols (with the exception of /NOENTRY resource-
+ # only DLLs). When the NoImportLibrary flag is set, this is suppressed. If
+ # this is not working correctly, the expected .lib will never be generated
+ # but will be expected, so the build will not be up to date.
+ test.up_to_date('noimplib.gyp', test.ALL, chdir=CHDIR)
+
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-ordering.py
@@ -0,0 +1,101 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 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.
+
+"""
+Make sure the link order of object files is the same between msvs and ninja.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+ test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+ CHDIR = 'linker-flags'
+ test.run_gyp('link-ordering.gyp', chdir=CHDIR)
+ test.build('link-ordering.gyp', test.ALL, chdir=CHDIR)
+
+ def GetDisasm(exe):
+ full_path = test.built_file_path(exe, chdir=CHDIR)
+ # Get disassembly and drop int3 padding between functions.
+ return '\n'.join(
+ x for x in test.run_dumpbin('/disasm', full_path).splitlines()
+ if 'CC' not in x)
+
+ # This is the full dump that we expect. The source files in the .gyp match
+ # this order which is what determines the ordering in the binary.
+
+ expected_disasm_basic = '''
+_mainCRTStartup:
+ 00401000: B8 05 00 00 00 mov eax,5
+ 00401005: C3 ret
+?z@@YAHXZ:
+ 00401010: B8 03 00 00 00 mov eax,3
+ 00401015: C3 ret
+?x@@YAHXZ:
+ 00401020: B8 01 00 00 00 mov eax,1
+ 00401025: C3 ret
+?y@@YAHXZ:
+ 00401030: B8 02 00 00 00 mov eax,2
+ 00401035: C3 ret
+_main:
+ 00401040: 33 C0 xor eax,eax
+ 00401042: C3 ret
+'''
+
+ if expected_disasm_basic not in GetDisasm('test_ordering_exe.exe'):
+ print GetDisasm('test_ordering_exe.exe')
+ test.fail_test()
+
+ # Similar to above. The VS generator handles subdirectories differently.
+
+ expected_disasm_subdirs = '''
+_mainCRTStartup:
+ 00401000: B8 05 00 00 00 mov eax,5
+ 00401005: C3 ret
+_main:
+ 00401010: 33 C0 xor eax,eax
+ 00401012: C3 ret
+?y@@YAHXZ:
+ 00401020: B8 02 00 00 00 mov eax,2
+ 00401025: C3 ret
+?z@@YAHXZ:
+ 00401030: B8 03 00 00 00 mov eax,3
+ 00401035: C3 ret
+'''
+
+ if expected_disasm_subdirs not in GetDisasm('test_ordering_subdirs.exe'):
+ print GetDisasm('test_ordering_subdirs.exe')
+ test.fail_test()
+
+ # Similar, but with directories mixed into folders (crt and main at the same
+ # level, but with a subdir in the middle).
+
+ expected_disasm_subdirs_mixed = '''
+_mainCRTStartup:
+ 00401000: B8 05 00 00 00 mov eax,5
+ 00401005: C3 ret
+?x@@YAHXZ:
+ 00401010: B8 01 00 00 00 mov eax,1
+ 00401015: C3 ret
+_main:
+ 00401020: 33 C0 xor eax,eax
+ 00401022: C3 ret
+?z@@YAHXZ:
+ 00401030: B8 03 00 00 00 mov eax,3
+ 00401035: C3 ret
+?y@@YAHXZ:
+ 00401040: B8 02 00 00 00 mov eax,2
+ 00401045: C3 ret
+'''
+
+ if (expected_disasm_subdirs_mixed not in
+ GetDisasm('test_ordering_subdirs_mixed.exe')):
+ print GetDisasm('test_ordering_subdirs_mixed.exe')
+ test.fail_test()
+
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-pdb-no-output.py
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 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.
+
+"""
+Ensure that when debug information is not output, a pdb is not expected.
+"""
+
+import TestGyp
+
+import os
+import sys
+
+if sys.platform == 'win32':
+ test = TestGyp.TestGyp()
+ CHDIR = 'linker-flags'
+ test.run_gyp('pdb-output.gyp', chdir=CHDIR)
+ test.build('pdb-output.gyp', 'test_pdb_output_disabled', chdir=CHDIR)
+ # Make sure that the build doesn't expect a PDB to be generated when there
+ # will be none.
+ test.up_to_date('pdb-output.gyp', 'test_pdb_output_disabled', chdir=CHDIR)
+
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-pdb-output.py
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 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.
+
+"""
+Ensure that ninja includes the .pdb as an output file from linking.
+"""
+
+import TestGyp
+
+import os
+import sys
+
+if sys.platform == 'win32':
+ test = TestGyp.TestGyp(formats=['ninja'])
+ CHDIR = 'linker-flags'
+ test.run_gyp('pdb-output.gyp', chdir=CHDIR)
+ # Note, building the pdbs rather than ALL or gyp target.
+ test.build('pdb-output.gyp', 'output_exe.pdb', chdir=CHDIR)
+ test.build('pdb-output.gyp', 'output_dll.pdb', chdir=CHDIR)
+
+ def FindFile(pdb):
+ full_path = test.built_file_path(pdb, chdir=CHDIR)
+ return os.path.isfile(full_path)
+
+ if not FindFile('output_exe.pdb'):
+ test.fail_test()
+ if not FindFile('output_dll.pdb'):
+ test.fail_test()
+
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-pdb.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 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.
+
+"""
+Verifies that the 'ProgramDatabaseFile' attribute in VCLinker is extracted
+properly.
+"""
+
+import TestGyp
+
+import os
+import sys
+
+
+if sys.platform == 'win32':
+ test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+ CHDIR = 'linker-flags'
+ test.run_gyp('program-database.gyp', chdir=CHDIR)
+ test.build('program-database.gyp', test.ALL, chdir=CHDIR)
+
+ def FindFile(pdb):
+ full_path = test.built_file_path(pdb, chdir=CHDIR)
+ return os.path.isfile(full_path)
+
+ # Verify the specified PDB is created when ProgramDatabaseFile
+ # is provided.
+ if not FindFile('name_outdir.pdb'):
+ test.fail_test()
+ if not FindFile('name_proddir.pdb'):
+ test.fail_test()
+
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-pgo.py
@@ -0,0 +1,75 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 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.
+
+"""
+Make sure PGO is working properly.
+"""
+
+import TestGyp
+
+import os
+import sys
+
+if sys.platform == 'win32':
+ test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+ CHDIR = 'linker-flags'
+ test.run_gyp('pgo.gyp', chdir=CHDIR)
+
+ def IsPGOAvailable():
+ """Returns true if the Visual Studio available here supports PGO."""
+ test.build('pgo.gyp', 'gen_linker_option', chdir=CHDIR)
+ tmpfile = test.read(test.built_file_path('linker_options.txt', chdir=CHDIR))
+ return any(line.find('PGOPTIMIZE') for line in tmpfile)
+
+ # Test generated build files look fine.
+ if test.format == 'ninja':
+ ninja = test.built_file_path('obj/test_pgo_instrument.ninja', chdir=CHDIR)
+ test.must_contain(ninja, '/LTCG:PGINSTRUMENT')
+ test.must_contain(ninja, 'test_pgo.pgd')
+ ninja = test.built_file_path('obj/test_pgo_optimize.ninja', chdir=CHDIR)
+ test.must_contain(ninja, '/LTCG:PGOPTIMIZE')
+ test.must_contain(ninja, 'test_pgo.pgd')
+ ninja = test.built_file_path('obj/test_pgo_update.ninja', chdir=CHDIR)
+ test.must_contain(ninja, '/LTCG:PGUPDATE')
+ test.must_contain(ninja, 'test_pgo.pgd')
+ elif test.format == 'msvs':
+ LTCG_FORMAT = '<LinkTimeCodeGeneration>%s</LinkTimeCodeGeneration>'
+ vcproj = test.workpath('linker-flags/test_pgo_instrument.vcxproj')
+ test.must_contain(vcproj, LTCG_FORMAT % 'PGInstrument')
+ test.must_contain(vcproj, 'test_pgo.pgd')
+ vcproj = test.workpath('linker-flags/test_pgo_optimize.vcxproj')
+ test.must_contain(vcproj, LTCG_FORMAT % 'PGOptimization')
+ test.must_contain(vcproj, 'test_pgo.pgd')
+ vcproj = test.workpath('linker-flags/test_pgo_update.vcxproj')
+ test.must_contain(vcproj, LTCG_FORMAT % 'PGUpdate')
+ test.must_contain(vcproj, 'test_pgo.pgd')
+
+ # When PGO is available, try building binaries with PGO.
+ if IsPGOAvailable():
+ pgd_path = test.built_file_path('test_pgo.pgd', chdir=CHDIR)
+
+ # Test if 'PGInstrument' generates PGD (Profile-Guided Database) file.
+ if os.path.exists(pgd_path):
+ test.unlink(pgd_path)
+ test.must_not_exist(pgd_path)
+ test.build('pgo.gyp', 'test_pgo_instrument', chdir=CHDIR)
+ test.must_exist(pgd_path)
+
+ # Test if 'PGOptimize' works well
+ test.build('pgo.gyp', 'test_pgo_optimize', chdir=CHDIR)
+ test.must_contain_any_line(test.stdout(), ['profiled functions'])
+
+ # Test if 'PGUpdate' works well
+ test.build('pgo.gyp', 'test_pgo_update', chdir=CHDIR)
+ # With 'PGUpdate', linker should not complain that sources are changed after
+ # the previous training run.
+ test.touch(test.workpath('linker-flags/inline_test_main.cc'))
+ test.unlink(test.built_file_path('test_pgo_update.exe', chdir=CHDIR))
+ test.build('pgo.gyp', 'test_pgo_update', chdir=CHDIR)
+ test.must_contain_any_line(test.stdout(), ['profiled functions'])
+
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-profile.py
@@ -0,0 +1,37 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 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.
+
+"""
+Verifies that the 'Profile' attribute in VCLinker is extracted properly.
+"""
+
+import TestGyp
+
+import os
+import sys
+
+
+if sys.platform == 'win32':
+ test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+ CHDIR = 'linker-flags'
+ test.run_gyp('profile.gyp', chdir=CHDIR)
+ test.build('profile.gyp', test.ALL, chdir=CHDIR)
+
+ def GetSummary(exe):
+ full_path = test.built_file_path(exe, chdir=CHDIR)
+ return test.run_dumpbin(full_path)
+
+ # '.idata' section will be missing when /PROFILE is enabled.
+ if '.idata' in GetSummary('test_profile_true.exe'):
+ test.fail_test()
+
+ if not '.idata' in GetSummary('test_profile_false.exe'):
+ test.fail_test()
+
+ if not '.idata' in GetSummary('test_profile_default.exe'):
+ test.fail_test()
+
+ test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-restat-importlib.py
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-restat-importlib.py
@@ -6,22 +6,28 @@
"""
Make sure we don't cause unnecessary builds due to import libs appearing
to be out of date.
"""
import TestGyp
+import os
import sys
import time
if sys.platform == 'win32':
test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+ if not os.environ.get('ProgramFiles(x86)'):
+ # TODO(scottmg)
+ print 'Skipping test on x86, http://crbug.com/365833'
+ test.pass_test()
+
CHDIR = 'importlib'
test.run_gyp('importlib.gyp', chdir=CHDIR)
test.build('importlib.gyp', test.ALL, chdir=CHDIR)
# Delay briefly so that there's time for this touch not to have the
# timestamp as the previous run.
test.sleep()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-safeseh.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 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.
+
+"""
+Make sure safeseh setting is extracted properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+ test = TestGyp.TestGyp()
+
+ CHDIR = 'linker-flags'
+ test.run_gyp('safeseh.gyp', chdir=CHDIR)
+ test.build('safeseh.gyp', test.ALL, chdir=CHDIR)
+
+ def HasSafeExceptionHandlers(exe):
+ full_path = test.built_file_path(exe, chdir=CHDIR)
+ output = test.run_dumpbin('/LOADCONFIG', full_path)
+ return ' Safe Exception Handler Table' in output
+
+ # From MSDN: http://msdn.microsoft.com/en-us/library/9a89h429.aspx
+ # If /SAFESEH is not specified, the linker will produce an image with a
+ # table of safe exceptions handlers if all modules are compatible with
+ # the safe exception handling feature. If any modules were not
+ # compatible with safe exception handling feature, the resulting image
+ # will not contain a table of safe exception handlers.
+ # However, the msvs IDE passes /SAFESEH to the linker by default, if
+ # ImageHasSafeExceptionHandlers is not set to false in the vcxproj file.
+ # We emulate this behavior in msvs_emulation.py, so 'test_safeseh_default'
+ # and 'test_safeseh_yes' are built identically.
+ if not HasSafeExceptionHandlers('test_safeseh_default.exe'):
+ test.fail_test()
+ if HasSafeExceptionHandlers('test_safeseh_no.exe'):
+ test.fail_test()
+ if not HasSafeExceptionHandlers('test_safeseh_yes.exe'):
+ test.fail_test()
+ if HasSafeExceptionHandlers('test_safeseh_x64.exe'):
+ test.fail_test()
+
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-shard.py
@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 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.
+
+"""
+Make sure msvs_shard works correctly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+ test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+ CHDIR = 'shard'
+ test.run_gyp('shard.gyp', chdir=CHDIR)
+ test.build('shard.gyp', test.ALL, chdir=CHDIR)
+
+ test.built_file_must_exist('shard_0.lib', chdir=CHDIR)
+ test.built_file_must_exist('shard_1.lib', chdir=CHDIR)
+ test.built_file_must_exist('shard_2.lib', chdir=CHDIR)
+ test.built_file_must_exist('shard_3.lib', chdir=CHDIR)
+
+ test.run_gyp('shard_ref.gyp', chdir=CHDIR)
+ test.build('shard_ref.gyp', test.ALL, chdir=CHDIR)
+
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-stacksize.py
@@ -0,0 +1,62 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2015 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.
+
+"""
+Make sure StackReserveSize and StackCommitSize settings are extracted properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+ test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+ CHDIR = 'linker-flags'
+ test.run_gyp('stacksize.gyp', chdir=CHDIR)
+ test.build('stacksize.gyp', test.ALL, chdir=CHDIR)
+
+ def GetHeaders(exe):
+ return test.run_dumpbin('/headers', test.built_file_path(exe, chdir=CHDIR))
+
+ # Verify default sizes as reported by dumpbin:
+ # 100000h = 1MB
+ # 1000h = 4KB
+ default_headers = GetHeaders('test_default.exe')
+ if '100000 size of stack reserve' not in default_headers:
+ test.fail_test()
+ if '1000 size of stack commit' not in default_headers:
+ test.fail_test()
+
+ # Verify that reserved size is changed, but commit size is unchanged:
+ # 200000h = 2MB
+ # 1000h = 4KB
+ set_reserved_size_headers = GetHeaders('test_set_reserved_size.exe')
+ if '200000 size of stack reserve' not in set_reserved_size_headers:
+ test.fail_test()
+ if '1000 size of stack commit' not in set_reserved_size_headers:
+ test.fail_test()
+
+ # Verify that setting the commit size, without the reserve size, has no
+ # effect:
+ # 100000h = 1MB
+ # 1000h = 4KB
+ set_commit_size_headers = GetHeaders('test_set_commit_size.exe')
+ if '100000 size of stack reserve' not in set_commit_size_headers:
+ test.fail_test()
+ if '1000 size of stack commit' not in set_commit_size_headers:
+ test.fail_test()
+
+ # Verify that setting both works:
+ # 200000h = 2MB
+ # 2000h = 8KB
+ set_both_headers = GetHeaders('test_set_both.exe')
+ if '200000 size of stack reserve' not in set_both_headers:
+ test.fail_test()
+ if '2000 size of stack commit' not in set_both_headers:
+ test.fail_test()
+
+ test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-subsystem.py
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-subsystem.py
@@ -18,11 +18,21 @@ if sys.platform == 'win32':
CHDIR = 'linker-flags'
test.run_gyp('subsystem.gyp', chdir=CHDIR)
test.build('subsystem.gyp', 'test_console_ok', chdir=CHDIR)
test.build('subsystem.gyp', 'test_console_fail', chdir=CHDIR, status=1)
test.build('subsystem.gyp', 'test_windows_ok', chdir=CHDIR)
test.build('subsystem.gyp', 'test_windows_fail', chdir=CHDIR, status=1)
+ test.build('subsystem.gyp', 'test_console_xp', chdir=CHDIR)
+ test.build('subsystem.gyp', 'test_windows_xp', chdir=CHDIR)
+ # Make sure we are targeting XP.
+ def GetHeaders(exe):
+ return test.run_dumpbin('/headers', test.built_file_path(exe, chdir=CHDIR))
+ if '5.01 subsystem version' not in GetHeaders('test_console_xp.exe'):
+ test.fail_test()
+ if '5.01 subsystem version' not in GetHeaders('test_windows_xp.exe'):
+ test.fail_test()
+
# TODO(scottmg): There are other subsystems (WinCE, etc.) that we don't use.
test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-target-machine.py
@@ -0,0 +1,28 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 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.
+
+"""
+Make sure TargetMachine setting is extracted properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+ test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+ CHDIR = 'linker-flags'
+ test.run_gyp('target-machine.gyp', chdir=CHDIR)
+ # The .cc file is compiled as x86 (the default), so the link/libs that are
+ # x64 need to fail.
+ test.build('target-machine.gyp', 'test_target_link_x86', chdir=CHDIR)
+ test.build(
+ 'target-machine.gyp', 'test_target_link_x64', chdir=CHDIR, status=1)
+ test.build('target-machine.gyp', 'test_target_lib_x86', chdir=CHDIR)
+ test.build('target-machine.gyp', 'test_target_lib_x64', chdir=CHDIR, status=1)
+
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-tsaware.py
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 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.
+
+"""
+Make sure tsaware setting is extracted properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+ test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+ CHDIR = 'linker-flags'
+ test.run_gyp('tsaware.gyp', chdir=CHDIR)
+ test.build('tsaware.gyp', test.ALL, chdir=CHDIR)
+
+ def GetHeaders(exe):
+ return test.run_dumpbin('/headers', test.built_file_path(exe, chdir=CHDIR))
+
+ # Explicitly off, should not be marked NX compatiable.
+ if 'Terminal Server Aware' in GetHeaders('test_tsaware_no.exe'):
+ test.fail_test()
+
+ # Explicitly on.
+ if 'Terminal Server Aware' not in GetHeaders('test_tsaware_yes.exe'):
+ test.fail_test()
+
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-uldi-depending-on-module.py
@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2015 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.
+
+"""
+Make sure that when ULDI is on, we link cause downstream modules to get built
+when we depend on the component objs.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+ test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+ CHDIR = 'uldi'
+ test.run_gyp('uldi-depending-on-module.gyp', chdir=CHDIR)
+ test.build('uldi-depending-on-module.gyp', 'an_exe', chdir=CHDIR)
+ test.built_file_must_exist('a_module.dll', chdir=CHDIR)
+
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-unsupported-manifest.py
@@ -0,0 +1,27 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 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.
+
+"""
+Make sure we error out if #pragma comments are used to modify manifests.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+ # This assertion only applies to the ninja build.
+ test = TestGyp.TestGyp(formats=['ninja'])
+
+ CHDIR = 'linker-flags'
+ test.run_gyp('unsupported-manifest.gyp', chdir=CHDIR)
+
+ # Just needs to fail to build.
+ test.build('unsupported-manifest.gyp',
+ 'test_unsupported', chdir=CHDIR, status=1)
+ test.must_not_exist(test.built_file_path('test_unsupported.exe', chdir=CHDIR))
+
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-update-manifest.py
@@ -0,0 +1,103 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 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.
+
+"""
+Make sure binary is relinked when manifest settings are changed.
+"""
+
+import TestGyp
+
+import os
+import sys
+
+if sys.platform == 'win32':
+ import pywintypes
+ import win32api
+ import winerror
+
+ RT_MANIFEST = 24
+
+ class LoadLibrary(object):
+ """Context manager for loading and releasing binaries in Windows.
+ Yields the handle of the binary loaded."""
+ def __init__(self, path):
+ self._path = path
+ self._handle = None
+
+ def __enter__(self):
+ self._handle = win32api.LoadLibrary(self._path)
+ return self._handle
+
+ def __exit__(self, type, value, traceback):
+ win32api.FreeLibrary(self._handle)
+
+ def extract_manifest(path, resource_name):
+ """Reads manifest from |path| and returns it as a string.
+ Returns None is there is no such manifest."""
+ with LoadLibrary(path) as handle:
+ try:
+ return win32api.LoadResource(handle, RT_MANIFEST, resource_name)
+ except pywintypes.error as error:
+ if error.args[0] == winerror.ERROR_RESOURCE_DATA_NOT_FOUND:
+ return None
+ else:
+ raise
+
+ test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+ CHDIR = 'linker-flags'
+
+ gyp_template = '''
+{
+ 'targets': [
+ {
+ 'target_name': 'test_update_manifest',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'EnableUAC': 'true',
+ 'UACExecutionLevel': '%(uac_execution_level)d',
+ },
+ 'VCManifestTool': {
+ 'EmbedManifest': 'true',
+ 'AdditionalManifestFiles': '%(additional_manifest_files)s',
+ },
+ },
+ },
+ ],
+}
+'''
+
+ gypfile = 'update-manifest.gyp'
+
+ def WriteAndUpdate(uac_execution_level, additional_manifest_files, do_build):
+ with open(os.path.join(CHDIR, gypfile), 'wb') as f:
+ f.write(gyp_template % {
+ 'uac_execution_level': uac_execution_level,
+ 'additional_manifest_files': additional_manifest_files,
+ })
+ test.run_gyp(gypfile, chdir=CHDIR)
+ if do_build:
+ test.build(gypfile, chdir=CHDIR)
+ exe_file = test.built_file_path('test_update_manifest.exe', chdir=CHDIR)
+ return extract_manifest(exe_file, 1)
+
+ manifest = WriteAndUpdate(0, '', True)
+ test.fail_test('asInvoker' not in manifest)
+ test.fail_test('35138b9a-5d96-4fbd-8e2d-a2440225f93a' in manifest)
+
+ # Make sure that updating .gyp and regenerating doesn't cause a rebuild.
+ WriteAndUpdate(0, '', False)
+ test.up_to_date(gypfile, test.ALL, chdir=CHDIR)
+
+ # But make sure that changing a manifest property does cause a relink.
+ manifest = WriteAndUpdate(2, '', True)
+ test.fail_test('requireAdministrator' not in manifest)
+
+ # Adding a manifest causes a rebuild.
+ manifest = WriteAndUpdate(2, 'extra.manifest', True)
+ test.fail_test('35138b9a-5d96-4fbd-8e2d-a2440225f93a' not in manifest)
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-warnings-as-errors.py
@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 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.
+
+"""
+Make sure linker warnings-as-errors setting is extracted properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+ test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+ CHDIR = 'linker-flags'
+ test.run_gyp('warn-as-error.gyp', chdir=CHDIR)
+
+ test.build('warn-as-error.gyp', 'test_on', chdir=CHDIR, status=1)
+ test.build('warn-as-error.gyp', 'test_off', chdir=CHDIR)
+ test.build('warn-as-error.gyp', 'test_default', chdir=CHDIR)
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-macro-targetext.py
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 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.
+
+"""
+Make sure macro expansion of $(TargetExt) is handled.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+ test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+ CHDIR = 'vs-macros'
+ test.run_gyp('targetext.gyp', chdir=CHDIR)
+ test.build('targetext.gyp', test.ALL, chdir=CHDIR)
+ test.built_file_must_exist('executable.exe', chdir=CHDIR)
+ test.built_file_must_exist('loadable_module.dll', chdir=CHDIR)
+ test.built_file_must_exist('shared_library.dll', chdir=CHDIR)
+ test.built_file_must_exist('static_library.lib', chdir=CHDIR)
+ test.built_file_must_exist('product_extension.library', chdir=CHDIR)
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-macro-targetfilename.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 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.
+
+"""
+Make sure macro expansion of $(TargetFileName) is handled.
+"""
+
+import TestGyp
+
+import os
+import sys
+
+if sys.platform == 'win32':
+ print "This test is currently disabled: https://crbug.com/483696."
+ sys.exit(0)
+
+ test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+ if not (test.format == 'msvs' and
+ int(os.environ.get('GYP_MSVS_VERSION', 0)) == 2013):
+ CHDIR = 'vs-macros'
+ test.run_gyp('targetfilename.gyp', chdir=CHDIR)
+ test.build('targetfilename.gyp', test.ALL, chdir=CHDIR)
+ test.built_file_must_exist('test_targetfilename_executable.exe', chdir=CHDIR)
+ test.built_file_must_exist('test_targetfilename_loadable_module.dll',
+ chdir=CHDIR)
+ test.built_file_must_exist('test_targetfilename_shared_library.dll',
+ chdir=CHDIR)
+ test.built_file_must_exist('test_targetfilename_static_library.lib',
+ chdir=CHDIR)
+ test.built_file_must_exist('test_targetfilename_product_extension.foo',
+ chdir=CHDIR)
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-macro-targetname.py
@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 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.
+
+"""
+Make sure macro expansion of $(TargetName) and $(TargetDir) are handled.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+ test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+ CHDIR = 'vs-macros'
+ test.run_gyp('targetname.gyp', chdir=CHDIR)
+ test.build('targetname.gyp', test.ALL, chdir=CHDIR)
+ test.built_file_must_exist('test_targetname_plus_something1.exe',
+ chdir=CHDIR)
+ test.built_file_must_exist(
+ 'prod_prefixtest_targetname_with_prefix_plus_something2.exe',
+ chdir=CHDIR)
+ test.built_file_must_exist('prod_name_plus_something3.exe', chdir=CHDIR)
+ test.built_file_must_exist('prod_prefixprod_name_plus_something4.exe',
+ chdir=CHDIR)
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-macro-targetpath.py
@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 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.
+
+"""
+Make sure macro expansion of $(TargetPath) is handled.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+ test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+ CHDIR = 'vs-macros'
+ test.run_gyp('targetpath.gyp', chdir=CHDIR)
+ test.build('targetpath.gyp', test.ALL, chdir=CHDIR)
+ test.built_file_must_exist('test_targetpath_executable.exe', chdir=CHDIR)
+ test.built_file_must_exist('test_targetpath_loadable_module.dll',
+ chdir=CHDIR)
+ test.built_file_must_exist('test_targetpath_shared_library.dll',
+ chdir=CHDIR)
+ test.built_file_must_exist('test_targetpath_static_library.lib',
+ chdir=CHDIR)
+ test.built_file_must_exist('test_targetpath_product_extension.foo',
+ chdir=CHDIR)
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-midl-excluded.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 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.
+
+"""
+Test that .idl files in actions and non-native rules are excluded.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+ test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+ CHDIR = 'idl-excluded'
+ test.run_gyp('idl-excluded.gyp', chdir=CHDIR)
+ test.build('idl-excluded.gyp', test.ALL, chdir=CHDIR)
+
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-midl-includedirs.py
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 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 'midl_include_dirs' is handled.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+ test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+ CHDIR = 'idl-includedirs'
+ test.run_gyp('idl-includedirs.gyp', chdir=CHDIR)
+ test.build('idl-includedirs.gyp', test.ALL, chdir=CHDIR)
+ test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/win/gyptest-midl-rules.py
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-midl-rules.py
@@ -12,11 +12,17 @@ import TestGyp
import sys
if sys.platform == 'win32':
test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
CHDIR = 'idl-rules'
test.run_gyp('basic-idl.gyp', chdir=CHDIR)
- test.build('basic-idl.gyp', test.ALL, chdir=CHDIR)
+ for platform in ['Win32', 'x64']:
+ test.set_configuration('Debug|%s' % platform)
+ test.build('basic-idl.gyp', test.ALL, chdir=CHDIR)
- test.pass_test()
+ # Make sure ninja win_tool.py filters out noisy lines.
+ if test.format == 'ninja' and 'Processing' in test.stdout():
+ test.fail_test()
+
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-ml-safeseh.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 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.
+
+"""
+Make sure the /safeseh option can be passed to ml.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+ test = TestGyp.TestGyp(formats=['ninja'])
+
+ CHDIR = 'ml-safeseh'
+ test.run_gyp('ml-safeseh.gyp', chdir=CHDIR)
+ test.build('ml-safeseh.gyp', test.ALL, chdir=CHDIR)
+
+ test.pass_test()
--- a/media/webrtc/trunk/tools/gyp/test/win/gyptest-rc-build.py
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-rc-build.py
@@ -8,16 +8,19 @@
Make sure we build and include .rc files.
"""
import TestGyp
import sys
if sys.platform == 'win32':
+ print "This test is currently disabled: https://crbug.com/483696."
+ sys.exit(0)
+
test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
CHDIR = 'rc-build'
test.run_gyp('hello.gyp', chdir=CHDIR)
test.build('hello.gyp', test.ALL, chdir=CHDIR)
test.up_to_date('hello.gyp', 'resource_only_dll', chdir=CHDIR)
test.run_built_executable('with_resources', chdir=CHDIR, status=4)
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-sys.py
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2016 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.
+
+"""
+Verifies that Windows drivers are built correctly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+ test = TestGyp.TestGyp(formats=['msvs'])
+
+ CHDIR = 'win-driver-target-type'
+ test.run_gyp('win-driver-target-type.gyp', chdir=CHDIR)
+ test.build('win-driver-target-type.gyp', 'win_driver_target_type',
+ chdir=CHDIR)
+
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-system-include.py
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 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.
+
+"""
+Checks that msvs_system_include_dirs works.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+ test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
+
+ CHDIR = 'system-include'
+ test.run_gyp('test.gyp', chdir=CHDIR)
+ test.build('test.gyp', test.ALL, chdir=CHDIR)
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/idl-excluded/bad.idl
@@ -0,0 +1,6 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+This is a dummy .idl file that will trigger an error if it is not excluded from
+the build.
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/idl-excluded/copy-file.py
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+
+# 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.
+import sys
+
+contents = open(sys.argv[1], 'r').read()
+open(sys.argv[2], 'wb').write(contents)
+
+sys.exit(0)
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/idl-excluded/idl-excluded.gyp
@@ -0,0 +1,58 @@
+# Copyright (c) 2014 The Chromium Authors. 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': 'exclude_with_action',
+ 'type': 'none',
+ 'msvs_cygwin_shell': 0,
+ 'actions': [{
+ 'action_name': 'copy_action',
+ 'inputs': [
+ 'copy-file.py',
+ 'bad.idl',
+ ],
+ 'outputs': [
+ '<(INTERMEDIATE_DIR)/bad.idl',
+ ],
+ 'action': [
+ 'python', '<@(_inputs)', '<@(_outputs)',
+ ],
+ }],
+ },
+ {
+ 'target_name': 'exclude_with_rule',
+ 'type': 'none',
+ 'msvs_cygwin_shell': 0,
+ 'sources': [
+ 'bad.idl',
+ ],
+ 'rules': [{
+ 'rule_name': 'copy_rule',
+ 'extension': 'idl',
+ 'inputs': [
+ 'copy-file.py',
+ ],
+ 'outputs': [
+ '<(INTERMEDIATE_DIR)/<(RULE_INPUT_ROOT).idl',
+ ],
+ 'action': [
+ 'python', '<@(_inputs)', '<(RULE_INPUT_PATH)', '<@(_outputs)',
+ ],
+ }],
+ },
+ {
+ 'target_name': 'program',
+ 'type': 'executable',
+ 'sources': [
+ 'program.cc',
+ ],
+ 'dependencies': [
+ 'exclude_with_action',
+ 'exclude_with_rule',
+ ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/idl-excluded/program.cc
@@ -0,0 +1,7 @@
+// Copyright (c) 2014 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 main() {
+ return 0;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/idl-includedirs/hello.cc
@@ -0,0 +1,7 @@
+// Copyright (c) 2014 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 main() {
+ return 0;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/idl-includedirs/idl-includedirs.gyp
@@ -0,0 +1,26 @@
+# Copyright (c) 2014 The Chromium Authors. 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': 'test_midl_include_dirs',
+ 'type': 'executable',
+ 'sources': [
+ 'hello.cc',
+ 'subdir/foo.idl',
+ 'subdir/bar.idl',
+ ],
+ 'midl_include_dirs': [
+ 'subdir',
+ ],
+ 'msvs_settings': {
+ 'VCMIDLTool': {
+ 'OutputDirectory': '<(INTERMEDIATE_DIR)',
+ 'DLLDataFileName': '$(InputName)_dlldata.h',
+ },
+ },
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/idl-includedirs/subdir/bar.idl
@@ -0,0 +1,13 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import "oaidl.idl";
+
+[
+ object,
+ uuid(A03D1421-B1EC-11D0-8C3A-00C04FC31D3F),
+]
+interface Bar : IUnknown {
+ HRESULT BarFunction();
+};
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/idl-includedirs/subdir/foo.idl
@@ -0,0 +1,14 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import "oaidl.idl";
+import "bar.idl";
+
+[
+ object,
+ uuid(9C1100DD-51D4-4827-AE9F-3B8FAC4AED72),
+]
+interface Foo : IUnknown {
+ HRESULT FooFunction(Bar* bar);
+};
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/idl-rules/Window.idl
@@ -0,0 +1,9 @@
+// Copyright (c) 2014 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.
+
+[
+ WillBeGarbageCollected,
+] interface Window {
+ void alert();
+};
--- a/media/webrtc/trunk/tools/gyp/test/win/idl-rules/basic-idl.gyp
+++ b/media/webrtc/trunk/tools/gyp/test/win/idl-rules/basic-idl.gyp
@@ -1,30 +1,67 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-{
- 'variables': {
- 'midl_out_dir': '<(SHARED_INTERMEDIATE_DIR)',
- },
- 'targets': [
- {
- 'target_name': 'idl_test',
- 'type': 'executable',
- 'sources': [
- 'history_indexer.idl',
- '<(midl_out_dir)/history_indexer.h',
- '<(midl_out_dir)/history_indexer_i.c',
- 'history_indexer_user.cc',
- ],
- 'include_dirs': [
- '<(midl_out_dir)',
- ],
- 'msvs_settings': {
- 'VCMIDLTool': {
- 'OutputDirectory': '<(midl_out_dir)',
- 'HeaderFileName': '<(RULE_INPUT_ROOT).h',
- },
- },
- },
- ],
-}
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'variables': {
+ 'midl_out_dir': '<(SHARED_INTERMEDIATE_DIR)',
+ },
+ 'target_defaults': {
+ 'configurations': {
+ 'Debug': {
+ 'msvs_configuration_platform': 'Win32',
+ },
+ 'Debug_x64': {
+ 'inherit_from': ['Debug'],
+ 'msvs_configuration_platform': 'x64',
+ },
+ },
+ },
+ 'targets': [
+ {
+ 'target_name': 'idl_test',
+ 'type': 'executable',
+ 'sources': [
+ 'history_indexer.idl',
+ '<(midl_out_dir)/history_indexer.h',
+ '<(midl_out_dir)/history_indexer_i.c',
+ 'history_indexer_user.cc',
+ ],
+ 'libraries': ['ole32.lib'],
+ 'include_dirs': [
+ '<(midl_out_dir)',
+ ],
+ 'msvs_settings': {
+ 'VCMIDLTool': {
+ 'OutputDirectory': '<(midl_out_dir)',
+ 'HeaderFileName': '<(RULE_INPUT_ROOT).h',
+ },
+ },
+ },
+ {
+ 'target_name': 'idl_explicit_action',
+ 'type': 'none',
+ 'sources': [
+ 'Window.idl',
+ ],
+ 'actions': [{
+ 'action_name': 'blink_idl',
+ 'explicit_idl_action': 1,
+ 'msvs_cygwin_shell': 0,
+ 'inputs': [
+ 'Window.idl',
+ 'idl_compiler.py',
+ ],
+ 'outputs': [
+ 'Window.cpp',
+ 'Window.h',
+ ],
+ 'action': [
+ 'python',
+ 'idl_compiler.py',
+ 'Window.idl',
+ ],
+ }],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/idl-rules/idl_compiler.py
@@ -0,0 +1,17 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 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.
+
+# mock, just outputs empty .h/.cpp files
+
+import os
+import sys
+
+if len(sys.argv) == 2:
+ basename, ext = os.path.splitext(sys.argv[1])
+ with open('%s.h' % basename, 'w') as f:
+ f.write('// %s.h\n' % basename)
+ with open('%s.cpp' % basename, 'w') as f:
+ f.write('// %s.cpp\n' % basename)
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/importlib/dll_no_exports.cc
@@ -0,0 +1,9 @@
+// Copyright (c) 2015 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 <windows.h>
+
+BOOL APIENTRY DllMain(HMODULE module, DWORD reason, LPVOID reserved) {
+ return TRUE;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/importlib/noimplib.gyp
@@ -0,0 +1,16 @@
+# Copyright (c) 2015 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': 'no_import_library',
+ 'type': 'loadable_module',
+ 'msvs_settings': {
+ 'NoImportLibrary': 'true',
+ },
+ 'sources': ['dll_no_exports.cc'],
+ },
+ ]
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/large-pdb/dllmain.cc
@@ -0,0 +1,9 @@
+// Copyright (c) 2013 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 <windows.h>
+
+BOOL WINAPI DllMain(HINSTANCE hinstance, DWORD reason, LPVOID reserved) {
+ return TRUE;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/large-pdb/large-pdb.gyp
@@ -0,0 +1,98 @@
+# Copyright (c) 2013 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': 'large_pdb_exe',
+ 'type': 'executable',
+ 'msvs_large_pdb': 1,
+ 'sources': [
+ 'main.cc',
+ ],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'GenerateDebugInformation': 'true',
+ 'ProgramDatabaseFile': '<(PRODUCT_DIR)/large_pdb_exe.exe.pdb',
+ },
+ },
+ },
+ {
+ 'target_name': 'small_pdb_exe',
+ 'type': 'executable',
+ 'msvs_large_pdb': 0,
+ 'sources': [
+ 'main.cc',
+ ],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'GenerateDebugInformation': 'true',
+ 'ProgramDatabaseFile': '<(PRODUCT_DIR)/small_pdb_exe.exe.pdb',
+ },
+ },
+ },
+ {
+ 'target_name': 'large_pdb_dll',
+ 'type': 'shared_library',
+ 'msvs_large_pdb': 1,
+ 'sources': [
+ 'dllmain.cc',
+ ],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'GenerateDebugInformation': 'true',
+ 'ProgramDatabaseFile': '<(PRODUCT_DIR)/large_pdb_dll.dll.pdb',
+ },
+ },
+ },
+ {
+ 'target_name': 'small_pdb_dll',
+ 'type': 'shared_library',
+ 'msvs_large_pdb': 0,
+ 'sources': [
+ 'dllmain.cc',
+ ],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'GenerateDebugInformation': 'true',
+ 'ProgramDatabaseFile': '<(PRODUCT_DIR)/small_pdb_dll.dll.pdb',
+ },
+ },
+ },
+ {
+ 'target_name': 'large_pdb_implicit_exe',
+ 'type': 'executable',
+ 'msvs_large_pdb': 1,
+ 'sources': [
+ 'main.cc',
+ ],
+ # No PDB file is specified. However, the msvs_large_pdb mechanism should
+ # default to the appropriate <(PRODUCT_DIR)/<(TARGET_NAME).exe.pdb.
+ },
+ {
+ 'target_name': 'large_pdb_variable_exe',
+ 'type': 'executable',
+ 'msvs_large_pdb': 1,
+ 'sources': [
+ 'main.cc',
+ ],
+ # No PDB file is specified. However, the msvs_large_pdb_path variable
+ # explicitly sets one.
+ 'variables': {
+ 'msvs_large_pdb_path': '<(PRODUCT_DIR)/foo.pdb',
+ },
+ },
+ {
+ 'target_name': 'large_pdb_product_exe',
+ 'product_name': 'bar',
+ 'type': 'executable',
+ 'msvs_large_pdb': 1,
+ 'sources': [
+ 'main.cc',
+ ],
+ # No PDB file is specified. However, we've specified a product name so
+ # it should use <(PRODUCT_DIR)/bar.exe.pdb.
+ },
+ ]
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/large-pdb/main.cc
@@ -0,0 +1,7 @@
+// Copyright (c) 2013 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 main(void) {
+ return 0;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/lib-crosscompile/answer.cc
@@ -0,0 +1,9 @@
+// Copyright (c) 2012 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 "answer.h"
+
+int answer() {
+ return 42;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/lib-crosscompile/answer.h
@@ -0,0 +1,5 @@
+// Copyright (c) 2012 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 answer();
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/lib-crosscompile/use_host_ar.gyp
@@ -0,0 +1,17 @@
+# Copyright (c) 2015 The Chromium Authors. 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': 'lib_answer',
+ 'type': 'static_library',
+ 'toolsets': ['host'],
+ 'msvs_settings': {
+ 'msvs_cygwin_shell': 0,
+ },
+ 'sources': ['answer.cc'],
+ },
+ ]
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/lib-flags/answer.cc
@@ -0,0 +1,9 @@
+// Copyright (c) 2012 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 "answer.h"
+
+int answer() {
+ return 42;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/lib-flags/answer.h
@@ -0,0 +1,5 @@
+// Copyright (c) 2012 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 answer();
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/lib-flags/ltcg.gyp
@@ -0,0 +1,21 @@
+# Copyright (c) 2012 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': 'lib_answer',
+ 'type': 'static_library',
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'WholeProgramOptimization': 'true', # /GL
+ },
+ 'VCLibrarianTool': {
+ 'LinkTimeCodeGeneration': 'true', # /LTCG
+ },
+ },
+ 'sources': ['answer.cc'],
+ },
+ ]
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/linker-flags/a/x.cc
@@ -0,0 +1,7 @@
+// Copyright (c) 2013 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 x() {
+ return 1;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/linker-flags/a/z.cc
@@ -0,0 +1,7 @@
+// Copyright (c) 2013 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 z() {
+ return 3;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/linker-flags/b/y.cc
@@ -0,0 +1,7 @@
+// Copyright (c) 2013 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 y() {
+ return 2;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/linker-flags/base-address.gyp
@@ -0,0 +1,38 @@
+# Copyright 2013 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': 'test_base_specified_exe',
+ 'type': 'executable',
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'BaseAddress': '0x00420000',
+ },
+ },
+ 'sources': ['hello.cc'],
+ },
+ {
+ 'target_name': 'test_base_specified_dll',
+ 'type': 'shared_library',
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'BaseAddress': '0x10420000',
+ },
+ },
+ 'sources': ['hello.cc'],
+ },
+ {
+ 'target_name': 'test_base_default_exe',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ },
+ {
+ 'target_name': 'test_base_default_dll',
+ 'type': 'shared_library',
+ 'sources': ['hello.cc'],
+ },
+ ]
+}
deleted file mode 100644
--- a/media/webrtc/trunk/tools/gyp/test/win/linker-flags/default-libs.cc
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (c) 2012 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 <windows.h>
-#include <delayimp.h>
-#include <odbcinst.h>
-#include <shlobj.h>
-#include <sql.h>
-#include <stdio.h>
-
-// Reference something in each of the default-linked libraries to cause a link
-// error if one is not correctly included.
-
-extern "C" void* __puiHead; // DelayImp
-
-int main() {
- CopyFile(0, 0, 0); // kernel32
- MessageBox(0, 0, 0, 0); // user32
- CreateDC(0, 0, 0, 0); // gdi32
- AddPrinter(0, 0, 0); // winspool
- FindText(0); // comdlg32
- ClearEventLog(0, 0); // advapi32
- SHGetSettings(0, 0); // shell32
- OleFlushClipboard(); // ole32
- VarAdd(0, 0, 0); // oleaut32
- printf("%p", &CLSID_FileOpenDialog); // uuid
- SQLAllocHandle(0, 0, 0); // odbc32
- return 0;
-}
deleted file mode 100644
--- a/media/webrtc/trunk/tools/gyp/test/win/linker-flags/default-libs.gyp
+++ /dev/null
@@ -1,13 +0,0 @@
-# Copyright (c) 2012 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': 'test_default',
- 'type': 'executable',
- 'sources': ['default-libs.cc'],
- },
- ]
-}
--- a/media/webrtc/trunk/tools/gyp/test/win/linker-flags/deffile.cc
+++ b/media/webrtc/trunk/tools/gyp/test/win/linker-flags/deffile.cc
@@ -1,10 +1,13 @@
// Copyright (c) 2012 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.
void AnExportedFunction() {
}
+void AnotherExportedFunction() {
+}
+
int main() {
return 0;
}
--- a/media/webrtc/trunk/tools/gyp/test/win/linker-flags/delay-load-dlls.gyp
+++ b/media/webrtc/trunk/tools/gyp/test/win/linker-flags/delay-load-dlls.gyp
@@ -7,21 +7,29 @@
{
'target_name': 'test_dld_none',
'type': 'executable',
'msvs_settings': {
'VCLinkerTool': {
}
},
'sources': ['delay-load.cc'],
+ 'libraries': [
+ 'delayimp.lib',
+ 'shell32.lib',
+ ],
},
{
'target_name': 'test_dld_shell32',
'type': 'executable',
'msvs_settings': {
'VCLinkerTool': {
'DelayLoadDLLs': ['shell32.dll']
}
},
'sources': ['delay-load.cc'],
+ 'libraries': [
+ 'delayimp.lib',
+ 'shell32.lib',
+ ],
},
]
}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/linker-flags/embed-manifest.gyp
@@ -0,0 +1,109 @@
+# Copyright (c) 2013 Yandex LLC. 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': 'test_manifest_exe',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'LinkIncremental': '1',
+ },
+ 'VCManifestTool': {
+ 'EmbedManifest': 'true',
+ }
+ },
+ },
+ {
+ 'target_name': 'test_manifest_dll',
+ 'type': 'loadable_module',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'LinkIncremental': '1',
+ },
+ 'VCManifestTool': {
+ 'EmbedManifest': 'true',
+ }
+ },
+ },
+ {
+ 'target_name': 'test_manifest_extra1',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCManifestTool': {
+ 'EmbedManifest': 'true',
+ 'AdditionalManifestFiles': 'extra.manifest',
+ }
+ },
+ },
+ {
+ 'target_name': 'test_manifest_extra2',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCManifestTool': {
+ 'EmbedManifest': 'true',
+ 'AdditionalManifestFiles': 'extra.manifest;extra2.manifest',
+ }
+ },
+ },
+ {
+ 'target_name': 'test_manifest_extra_list',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCManifestTool': {
+ 'EmbedManifest': 'true',
+ 'AdditionalManifestFiles': [
+ 'extra.manifest',
+ 'extra2.manifest'
+ ],
+ }
+ },
+ },
+ {
+ 'target_name': 'test_manifest_dll_inc',
+ 'type': 'loadable_module',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'LinkIncremental': '2',
+ },
+ 'VCManifestTool': {
+ 'EmbedManifest': 'true',
+ }
+ },
+ },
+ {
+ 'target_name': 'test_manifest_exe_inc',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'LinkIncremental': '2',
+ },
+ 'VCManifestTool': {
+ 'EmbedManifest': 'true',
+ }
+ },
+ },
+ {
+ 'target_name': 'test_manifest_exe_inc_no_embed',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'LinkIncremental': '2',
+ },
+ 'VCManifestTool': {
+ 'EmbedManifest': 'false',
+ }
+ },
+ },
+ ]
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/linker-flags/enable-uac.gyp
@@ -0,0 +1,45 @@
+# Copyright 2013 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': 'enable_uac',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCManifestTool': {
+ 'EmbedManifest': 'true',
+ }
+ },
+ },
+ {
+ 'target_name': 'enable_uac_no',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'EnableUAC': 'false',
+ },
+ 'VCManifestTool': {
+ 'EmbedManifest': 'true',
+ }
+ },
+ },
+ {
+ 'target_name': 'enable_uac_admin',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'UACExecutionLevel': 2,
+ 'UACUIAccess': 'true',
+ },
+ 'VCManifestTool': {
+ 'EmbedManifest': 'true',
+ }
+ },
+ },
+ ]
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/linker-flags/force-symbol-reference.gyp
@@ -0,0 +1,39 @@
+# Copyright (c) 2013 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': 'test_force_reference_lib',
+ 'type': 'static_library',
+ 'sources': ['x.cc', 'y.cc'],
+ },
+ {
+ 'target_name': 'test_force_reference',
+ 'type': 'executable',
+ # Turn on debug info to get symbols in disasm for the test code, and
+ # turn on opt:ref to drop unused symbols to make sure we wouldn't
+ # otherwise have the symbols.
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'DebugInformationFormat': '3',
+ },
+ 'VCLinkerTool': {
+ 'GenerateDebugInformation': 'true',
+ 'AdditionalOptions': [
+ '/OPT:REF',
+ ],
+ 'ForceSymbolReferences': [
+ '?x@@YAHXZ',
+ '?y@@YAHXZ',
+ ],
+ },
+ },
+ 'sources': ['hello.cc'],
+ 'dependencies': [
+ 'test_force_reference_lib',
+ ],
+ },
+ ]
+}
--- a/media/webrtc/trunk/tools/gyp/test/win/linker-flags/generate-manifest.gyp
+++ b/media/webrtc/trunk/tools/gyp/test/win/linker-flags/generate-manifest.gyp
@@ -1,64 +1,166 @@
-# Copyright (c) 2012 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': 'test_manifest_exe',
- 'type': 'executable',
- 'sources': ['hello.cc'],
- 'msvs_settings': {
- 'VCManifestTool': {
- 'EmbedManifest': 'false',
- }
- },
- },
- {
- 'target_name': 'test_manifest_dll',
- 'type': 'shared_library',
- 'sources': ['hello.cc'],
- 'msvs_settings': {
- 'VCManifestTool': {
- 'EmbedManifest': 'false',
- }
- },
- },
- {
- 'target_name': 'test_manifest_extra1',
- 'type': 'executable',
- 'sources': ['hello.cc'],
- 'msvs_settings': {
- 'VCManifestTool': {
- 'EmbedManifest': 'false',
- 'AdditionalManifestFiles': 'extra.manifest',
- }
- },
- },
- {
- 'target_name': 'test_manifest_extra2',
- 'type': 'executable',
- 'sources': ['hello.cc'],
- 'msvs_settings': {
- 'VCManifestTool': {
- 'EmbedManifest': 'false',
- 'AdditionalManifestFiles': 'extra.manifest;extra2.manifest',
- }
- },
- },
- {
- 'target_name': 'test_manifest_extra_list',
- 'type': 'executable',
- 'sources': ['hello.cc'],
- 'msvs_settings': {
- 'VCManifestTool': {
- 'EmbedManifest': 'false',
- 'AdditionalManifestFiles': [
- 'extra.manifest',
- 'extra2.manifest'
- ],
- }
- },
- },
- ]
-}
+# Copyright (c) 2012 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': 'test_generate_manifest_true',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'EnableUAC': 'true',
+ 'GenerateManifest': 'true',
+ },
+ 'VCManifestTool': {
+ 'EmbedManifest': 'false',
+ },
+ },
+ },
+ {
+ 'target_name': 'test_generate_manifest_false',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'EnableUAC': 'true',
+ 'GenerateManifest': 'false',
+ },
+ 'VCManifestTool': {
+ 'EmbedManifest': 'false',
+ },
+ },
+ },
+ {
+ 'target_name': 'test_generate_manifest_default',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'EnableUAC': 'true',
+ },
+ 'VCManifestTool': {
+ 'EmbedManifest': 'false',
+ },
+ },
+ },
+ {
+ 'target_name': 'test_generate_manifest_true_as_embedded',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'EnableUAC': 'true',
+ 'GenerateManifest': 'true',
+ },
+ 'VCManifestTool': {
+ 'EmbedManifest': 'true',
+ },
+ },
+ },
+ {
+ 'target_name': 'test_generate_manifest_false_as_embedded',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'EnableUAC': 'true',
+ 'GenerateManifest': 'false',
+ },
+ 'VCManifestTool': {
+ 'EmbedManifest': 'true',
+ },
+ },
+ },
+ {
+ 'target_name': 'test_generate_manifest_default_as_embedded',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'EnableUAC': 'true',
+ },
+ 'VCManifestTool': {
+ 'EmbedManifest': 'true',
+ },
+ },
+ },
+ {
+ 'target_name': 'test_generate_manifest_true_with_extra_manifest',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'EnableUAC': 'true',
+ 'GenerateManifest': 'true',
+ },
+ 'VCManifestTool': {
+ 'EmbedManifest': 'false',
+ 'AdditionalManifestFiles': 'extra.manifest;extra2.manifest',
+ },
+ },
+ },
+ {
+ 'target_name': 'test_generate_manifest_false_with_extra_manifest',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'EnableUAC': 'true',
+ 'GenerateManifest': 'false',
+ },
+ 'VCManifestTool': {
+ 'EmbedManifest': 'false',
+ 'AdditionalManifestFiles': 'extra.manifest;extra2.manifest',
+ },
+ },
+ },
+ {
+ 'target_name': 'test_generate_manifest_true_with_extra_manifest_list',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'EnableUAC': 'true',
+ 'GenerateManifest': 'true',
+ },
+ 'VCManifestTool': {
+ 'EmbedManifest': 'false',
+ 'AdditionalManifestFiles': [
+ 'extra.manifest',
+ 'extra2.manifest',
+ ],
+ },
+ },
+ },
+ {
+ 'target_name': 'test_generate_manifest_false_with_extra_manifest_list',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'EnableUAC': 'true',
+ 'GenerateManifest': 'false',
+ },
+ 'VCManifestTool': {
+ 'EmbedManifest': 'false',
+ 'AdditionalManifestFiles': [
+ 'extra.manifest',
+ 'extra2.manifest',
+ ],
+ },
+ },
+ },
+ {
+ 'target_name': 'test_generate_manifest_default_embed_default',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'EnableUAC': 'true',
+ },
+ },
+ },
+ ]
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/linker-flags/inline_test.cc
@@ -0,0 +1,12 @@
+// Copyright (c) 2013 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 "inline_test.h"
+
+#include <intrin.h>
+#pragma intrinsic(_ReturnAddress)
+
+bool IsFunctionInlined(void* caller_return_address) {
+ return _ReturnAddress() == caller_return_address;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/linker-flags/inline_test.h
@@ -0,0 +1,5 @@
+// Copyright (c) 2013 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.
+
+bool IsFunctionInlined(void* current_return_address);
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/linker-flags/inline_test_main.cc
@@ -0,0 +1,15 @@
+// Copyright (c) 2013 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 "inline_test.h"
+
+#include <intrin.h>
+#include <stdio.h>
+
+#pragma intrinsic(_ReturnAddress)
+
+int main() {
+ if (IsFunctionInlined(_ReturnAddress()))
+ puts("==== inlined ====\n");
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/linker-flags/large-address-aware.gyp
@@ -0,0 +1,28 @@
+# Copyright (c) 2012 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': 'test_large_address_aware_no',
+ 'type': 'executable',
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'LargeAddressAware': '1',
+ }
+ },
+ 'sources': ['hello.cc'],
+ },
+ {
+ 'target_name': 'test_large_address_aware_yes',
+ 'type': 'executable',
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'LargeAddressAware': '2',
+ },
+ },
+ 'sources': ['hello.cc'],
+ },
+ ]
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/linker-flags/link-ordering.gyp
@@ -0,0 +1,95 @@
+# Copyright (c) 2013 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': 'test_ordering_exe',
+ 'type': 'executable',
+ # These are so the names of the functions appear in the disassembly.
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'DebugInformationFormat': '3',
+ 'Optimization': '2',
+ },
+ 'VCLinkerTool': {
+ 'GenerateDebugInformation': 'true',
+ 'LinkIncremental': '1',
+ 'GenerateManifest': 'false',
+ # Minimize the disassembly to just our code.
+ 'AdditionalOptions': [
+ '/NODEFAULTLIB',
+ ],
+ },
+ },
+ 'sources': [
+ # Explicitly sorted the same way as the disassembly in the test .py.
+ 'main-crt.c',
+ 'z.cc',
+ 'x.cc',
+ 'y.cc',
+ 'hello.cc',
+ ],
+ },
+
+ {
+ 'target_name': 'test_ordering_subdirs',
+ 'type': 'executable',
+ # These are so the names of the functions appear in the disassembly.
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'DebugInformationFormat': '3',
+ 'Optimization': '2',
+ },
+ 'VCLinkerTool': {
+ 'GenerateDebugInformation': 'true',
+ 'LinkIncremental': '1',
+ 'GenerateManifest': 'false',
+ # Minimize the disassembly to just our code.
+ 'AdditionalOptions': [
+ '/NODEFAULTLIB',
+ ],
+ },
+ },
+ 'sources': [
+ # Explicitly sorted the same way as the disassembly in the test .py.
+ 'main-crt.c',
+ 'hello.cc',
+ 'b/y.cc',
+ 'a/z.cc',
+ ],
+ },
+
+
+ {
+ 'target_name': 'test_ordering_subdirs_mixed',
+ 'type': 'executable',
+ # These are so the names of the functions appear in the disassembly.
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'DebugInformationFormat': '3',
+ 'Optimization': '2',
+ },
+ 'VCLinkerTool': {
+ 'GenerateDebugInformation': 'true',
+ 'LinkIncremental': '1',
+ 'GenerateManifest': 'false',
+ # Minimize the disassembly to just our code.
+ 'AdditionalOptions': [
+ '/NODEFAULTLIB',
+ ],
+ },
+ },
+ 'sources': [
+ # Explicitly sorted the same way as the disassembly in the test .py.
+ 'main-crt.c',
+ 'a/x.cc',
+ 'hello.cc',
+ 'a/z.cc',
+ 'y.cc',
+ ],
+ },
+
+ ]
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/linker-flags/link-warning.cc
@@ -0,0 +1,10 @@
+// Copyright (c) 2013 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.
+
+// This will cause LNK4254.
+#pragma comment(linker, "/merge:.data=.text")
+
+int main() {
+ return 0;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/linker-flags/ltcg.gyp
@@ -0,0 +1,42 @@
+# Copyright (c) 2013 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': 'test_ltcg_off',
+ 'type': 'executable',
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'WholeProgramOptimization': 'false',
+ },
+ 'VCLinkerTool': {
+ 'LinkTimeCodeGeneration': '0',
+ },
+ },
+ 'sources': [
+ 'inline_test.h',
+ 'inline_test.cc',
+ 'inline_test_main.cc',
+ ],
+ },
+ {
+ 'target_name': 'test_ltcg_on',
+ 'type': 'executable',
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'WholeProgramOptimization': 'true', # /GL
+ },
+ 'VCLinkerTool': {
+ 'LinkTimeCodeGeneration': '1', # /LTCG
+ },
+ },
+ 'sources': [
+ 'inline_test.h',
+ 'inline_test.cc',
+ 'inline_test_main.cc',
+ ],
+ },
+ ]
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/linker-flags/main-crt.c
@@ -0,0 +1,8 @@
+// Copyright (c) 2013 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.
+
+// Stub so we can link with /NODEFAULTLIB when checking disasm.
+int mainCRTStartup() {
+ return 5;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/linker-flags/manifest-in-comment.cc
@@ -0,0 +1,13 @@
+// Copyright 2013 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.
+
+#pragma comment(linker, \
+ "\"/manifestdependency:type='Win32' " \
+ "name='Test.Research.SampleAssembly' version='6.0.0.0' " \
+ "processorArchitecture='X86' " \
+ "publicKeyToken='0000000000000000' language='*'\"")
+
+int main() {
+ return 0;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/linker-flags/mapfile.cc
@@ -0,0 +1,12 @@
+// Copyright (c) 2013 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.
+
+__declspec(dllexport)
+void AnExportedFunction() {
+ // We need an exported function to verify that /MAPINFO:EXPORTS works.
+}
+
+int main() {
+ return 0;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/linker-flags/mapfile.gyp
@@ -0,0 +1,45 @@
+# Copyright (c) 2013 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': 'test_mapfile_unset',
+ 'type': 'executable',
+ 'sources': ['mapfile.cc'],
+ },
+ {
+ 'target_name': 'test_mapfile_generate',
+ 'type': 'executable',
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'GenerateMapFile': 'true',
+ },
+ },
+ 'sources': ['mapfile.cc'],
+ },
+ {
+ 'target_name': 'test_mapfile_generate_exports',
+ 'type': 'executable',
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'GenerateMapFile': 'true',
+ 'MapExports': 'true',
+ },
+ },
+ 'sources': ['mapfile.cc'],
+ },
+ {
+ 'target_name': 'test_mapfile_generate_filename',
+ 'type': 'executable',
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'GenerateMapFile': 'true',
+ 'MapFileName': '<(PRODUCT_DIR)/custom_file_name.map',
+ },
+ },
+ 'sources': ['mapfile.cc'],
+ },
+ ]
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/linker-flags/no-default-libs.cc
@@ -0,0 +1,18 @@
+// Copyright (c) 2012 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.
+
+// Reference something in kernel32.dll. This will fail to link, verifying that
+// GYP provides no default import library configuration.
+// Note that we don't include Windows.h, as that will result in generating
+// linker directives in the object file through #pragma comment(lib, ...).
+typedef short BOOL;
+
+extern "C" __declspec(dllimport)
+BOOL CopyFileW(const wchar_t*, const wchar_t*, BOOL);
+
+
+int main() {
+ CopyFileW(0, 0, 0); // kernel32
+ return 0;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/linker-flags/no-default-libs.gyp
@@ -0,0 +1,13 @@
+# Copyright (c) 2012 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': 'test_default',
+ 'type': 'executable',
+ 'sources': ['no-default-libs.cc'],
+ },
+ ]
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/linker-flags/pdb-output.gyp
@@ -0,0 +1,49 @@
+# Copyright (c) 2014 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': 'test_pdb_output_exe',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'DebugInformationFormat': '3'
+ },
+ 'VCLinkerTool': {
+ 'GenerateDebugInformation': 'true',
+ 'ProgramDatabaseFile': 'output_exe.pdb',
+ },
+ },
+ },
+ {
+ 'target_name': 'test_pdb_output_dll',
+ 'type': 'shared_library',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'DebugInformationFormat': '3'
+ },
+ 'VCLinkerTool': {
+ 'GenerateDebugInformation': 'true',
+ 'ProgramDatabaseFile': 'output_dll.pdb',
+ },
+ },
+ },
+ {
+ 'target_name': 'test_pdb_output_disabled',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'DebugInformationFormat': '0'
+ },
+ 'VCLinkerTool': {
+ 'GenerateDebugInformation': 'false',
+ },
+ },
+ },
+ ]
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/linker-flags/pgo.gyp
@@ -0,0 +1,143 @@
+# Copyright (c) 2013 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.
+
+{
+ 'variables': {
+ 'pgd_basename': 'test_pgo',
+ },
+ 'targets': [
+ # In the PGO (Profile-Guided Optimization) build flow, we need to build the
+ # target binary multiple times. To implement this flow with gyp, here we
+ # define multiple 'executable' targets, each of which represents one build
+ # particular build/profile stage. On tricky part to do this is that these
+ # 'executable' targets should share the code itself so that profile data
+ # can be reused among these 'executable' files. In other words, the only
+ # differences among below 'executable' targets are:
+ # 1) PGO (Profile-Guided Optimization) database, and
+ # 2) linker options.
+ # The following static library contains all the logic including entry point.
+ # Basically we don't need to rebuild this target once we enter profiling
+ # phase of PGO.
+ {
+ 'target_name': 'test_pgo_main',
+ 'type': 'static_library',
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'WholeProgramOptimization': 'true', # /GL
+ },
+ 'VCLibrarianTool': {
+ 'LinkTimeCodeGeneration': 'true',
+ },
+ },
+ 'link_settings': {
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'ProfileGuidedDatabase': '$(OutDir)\\<(pgd_basename).pgd',
+ 'TargetMachine': '1', # x86 - 32
+ 'SubSystem': '1', # /SUBSYSTEM:CONSOLE
+ # Tell ninja generator not to pass /ManifestFile:<filename> option
+ # to the linker, because it causes LNK1268 error in PGO biuld.
+ 'GenerateManifest': 'false',
+ # We need to specify 'libcmt.lib' here so that the linker can pick
+ # up a valid entry point.
+ 'AdditionalDependencies': [
+ 'libcmt.lib',
+ ],
+ },
+ },
+ },
+ 'sources': [
+ 'inline_test.h',
+ 'inline_test.cc',
+ 'inline_test_main.cc',
+ ],
+ },
+ {
+ 'target_name': 'test_pgo_instrument',
+ 'type': 'executable',
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'LinkTimeCodeGeneration': '2',
+ },
+ },
+ 'dependencies': [
+ 'test_pgo_main',
+ ],
+ },
+ {
+ 'target_name': 'gen_profile_guided_database',
+ 'type': 'none',
+ 'msvs_cygwin_shell': 0,
+ 'actions': [
+ {
+ 'action_name': 'action_main',
+ 'inputs': [],
+ 'outputs': [
+ '$(OutDir)\\<(pgd_basename).pgd',
+ ],
+ 'action': [
+ 'python', 'update_pgd.py',
+ '--vcbindir', '$(VCInstallDir)bin',
+ '--exe', '$(OutDir)\\test_pgo_instrument.exe',
+ '--pgd', '$(OutDir)\\<(pgd_basename).pgd',
+ ],
+ },
+ ],
+ 'dependencies': [
+ 'test_pgo_instrument',
+ ],
+ },
+ {
+ 'target_name': 'test_pgo_optimize',
+ 'type': 'executable',
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'LinkTimeCodeGeneration': '3',
+ },
+ },
+ 'sources': [
+ '$(OutDir)\\<(pgd_basename).pgd',
+ ],
+ 'dependencies': [
+ 'test_pgo_main',
+ 'gen_profile_guided_database',
+ ],
+ },
+ {
+ 'target_name': 'test_pgo_update',
+ 'type': 'executable',
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'LinkTimeCodeGeneration': '4',
+ },
+ },
+ 'sources': [
+ '$(OutDir)\\<(pgd_basename).pgd',
+ ],
+ 'dependencies': [
+ 'test_pgo_main',
+ ],
+ },
+ # A helper target to dump link.exe's command line options. We can use the
+ # output to determine if PGO (Profile-Guided Optimization) is available on
+ # the test environment.
+ {
+ 'target_name': 'gen_linker_option',
+ 'type': 'none',
+ 'msvs_cygwin_shell': 0,
+ 'actions': [
+ {
+ 'action_name': 'action_main',
+ 'inputs': [],
+ 'outputs': [
+ '$(OutDir)\\linker_options.txt',
+ ],
+ 'action': [
+ 'cmd.exe', '/c link.exe > $(OutDir)\\linker_options.txt & exit 0',
+ ],
+ },
+ ],
+ },
+ ]
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/linker-flags/profile.gyp
@@ -0,0 +1,50 @@
+# Copyright (c) 2012 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': [
+ # Verify that 'Profile' option correctly makes it to LINK steup in Ninja
+ {
+ 'target_name': 'test_profile_true',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'DebugInformationFormat': '3'
+ },
+ 'VCLinkerTool': {
+ 'Profile': 'true',
+ 'GenerateDebugInformation': 'true',
+ },
+ },
+ },
+ {
+ 'target_name': 'test_profile_false',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'DebugInformationFormat': '3'
+ },
+ 'VCLinkerTool': {
+ 'Profile': 'false',
+ 'GenerateDebugInformation': 'true',
+ },
+ },
+ },
+ {
+ 'target_name': 'test_profile_default',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'DebugInformationFormat': '3'
+ },
+ 'VCLinkerTool': {
+ 'GenerateDebugInformation': 'true',
+ },
+ },
+ },
+ ]
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/linker-flags/program-database.gyp
@@ -0,0 +1,40 @@
+# Copyright (c) 2012 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': [
+ # Verify that 'ProgramDatabaseFile' option correctly makes it to LINK
+ # step in Ninja.
+ {
+ # Verify that VC macros and windows paths work correctly.
+ 'target_name': 'test_pdb_outdir',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'DebugInformationFormat': '3'
+ },
+ 'VCLinkerTool': {
+ 'GenerateDebugInformation': 'true',
+ 'ProgramDatabaseFile': '$(OutDir)\\name_outdir.pdb',
+ },
+ },
+ },
+ {
+ # Verify that GYP macros and POSIX paths work correctly.
+ 'target_name': 'test_pdb_proddir',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'DebugInformationFormat': '3'
+ },
+ 'VCLinkerTool': {
+ 'GenerateDebugInformation': 'true',
+ 'ProgramDatabaseFile': '<(PRODUCT_DIR)/name_proddir.pdb',
+ },
+ },
+ },
+ ]
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/linker-flags/safeseh.gyp
@@ -0,0 +1,79 @@
+# Copyright (c) 2014 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.
+
+{
+ 'target_defaults': {
+ 'configurations': {
+ 'Default': {
+ 'msvs_configuration_platform': 'Win32',
+ },
+ 'Default_x64': {
+ 'inherit_from': ['Default'],
+ 'msvs_configuration_platform': 'x64',
+ },
+ },
+ },
+ 'targets': [
+ {
+ 'target_name': 'test_safeseh_default',
+ 'type': 'executable',
+ 'msvs_settings': {
+ # By default, msvs passes /SAFESEH for Link, but not for MASM. In
+ # order for test_safeseh_default to link successfully, we need to
+ # explicitly specify /SAFESEH for MASM.
+ 'MASM': {
+ 'UseSafeExceptionHandlers': 'true',
+ },
+ },
+ 'sources': [
+ 'safeseh_hello.cc',
+ 'safeseh_zero.asm',
+ ],
+ },
+ {
+ 'target_name': 'test_safeseh_no',
+ 'type': 'executable',
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'ImageHasSafeExceptionHandlers': 'false',
+ },
+ },
+ 'sources': [
+ 'safeseh_hello.cc',
+ 'safeseh_zero.asm',
+ ],
+ },
+ {
+ 'target_name': 'test_safeseh_yes',
+ 'type': 'executable',
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'ImageHasSafeExceptionHandlers': 'true',
+ },
+ 'MASM': {
+ 'UseSafeExceptionHandlers': 'true',
+ },
+ },
+ 'sources': [
+ 'safeseh_hello.cc',
+ 'safeseh_zero.asm',
+ ],
+ },
+ {
+ # x64 targets cannot have ImageHasSafeExceptionHandlers or
+ # UseSafeExceptionHandlers set.
+ 'target_name': 'test_safeseh_x64',
+ 'type': 'executable',
+ 'configurations': {
+ 'Default': {
+ 'msvs_target_platform': 'x64',
+ },
+ },
+ 'sources': [
+ 'safeseh_hello.cc',
+ 'safeseh_zero64.asm',
+ ],
+ },
+ ]
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/linker-flags/safeseh_hello.cc
@@ -0,0 +1,11 @@
+// Copyright (c) 2014 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.
+
+extern "C" {
+int zero(void);
+}
+
+int main() {
+ return zero();
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/linker-flags/safeseh_zero.asm
@@ -0,0 +1,10 @@
+.MODEL FLAT, C
+.CODE
+
+PUBLIC zero
+zero PROC
+ xor eax, eax
+ ret 0
+zero ENDP
+
+END
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/linker-flags/safeseh_zero64.asm
@@ -0,0 +1,9 @@
+.CODE
+
+PUBLIC zero
+zero PROC
+ xor eax, eax
+ ret 0
+zero ENDP
+
+END
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/linker-flags/stacksize.gyp
@@ -0,0 +1,44 @@
+# Copyright (c) 2015 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': 'test_default',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ },
+ {
+ 'target_name': 'test_set_reserved_size',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'StackReserveSize': 2097152, # 2MB
+ }
+ },
+ },
+ {
+ 'target_name': 'test_set_commit_size',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'StackCommitSize': 8192, # 8KB
+ }
+ },
+ },
+ {
+ 'target_name': 'test_set_both',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'StackReserveSize': 2097152, # 2MB
+ 'StackCommitSize': 8192, # 8KB
+ }
+ },
+ },
+ ]
+}
--- a/media/webrtc/trunk/tools/gyp/test/win/linker-flags/subsystem.gyp
+++ b/media/webrtc/trunk/tools/gyp/test/win/linker-flags/subsystem.gyp
@@ -39,10 +39,32 @@
'type': 'executable',
'msvs_settings': {
'VCLinkerTool': {
'SubSystem': '2'
}
},
'sources': ['hello.cc'],
},
+ {
+ 'target_name': 'test_console_xp',
+ 'type': 'executable',
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'SubSystem': '1',
+ 'MinimumRequiredVersion': '5.01', # XP.
+ }
+ },
+ 'sources': ['hello.cc'],
+ },
+ {
+ 'target_name': 'test_windows_xp',
+ 'type': 'executable',
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'SubSystem': '2',
+ 'MinimumRequiredVersion': '5.01', # XP.
+ }
+ },
+ 'sources': ['subsystem-windows.cc'],
+ },
]
}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/linker-flags/target-machine.gyp
@@ -0,0 +1,48 @@
+# Copyright (c) 2013 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': 'test_target_link_x86',
+ 'type': 'executable',
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'TargetMachine': '1',
+ }
+ },
+ 'sources': ['hello.cc'],
+ },
+ {
+ 'target_name': 'test_target_link_x64',
+ 'type': 'executable',
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'TargetMachine': '17',
+ },
+ },
+ 'sources': ['hello.cc'],
+ },
+ {
+ 'target_name': 'test_target_lib_x86',
+ 'type': 'static_library',
+ 'msvs_settings': {
+ 'VCLibrarianTool': {
+ 'TargetMachine': '1',
+ }
+ },
+ 'sources': ['hello.cc'],
+ },
+ {
+ 'target_name': 'test_target_lib_x64',
+ 'type': 'static_library',
+ 'msvs_settings': {
+ 'VCLibrarianTool': {
+ 'TargetMachine': '17',
+ },
+ },
+ 'sources': ['hello.cc'],
+ },
+ ]
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/linker-flags/tsaware.gyp
@@ -0,0 +1,28 @@
+# Copyright (c) 2012 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': 'test_tsaware_no',
+ 'type': 'executable',
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'TerminalServerAware': '1',
+ }
+ },
+ 'sources': ['hello.cc'],
+ },
+ {
+ 'target_name': 'test_tsaware_yes',
+ 'type': 'executable',
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'TerminalServerAware': '2',
+ },
+ },
+ 'sources': ['hello.cc'],
+ },
+ ]
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/linker-flags/unsupported-manifest.gyp
@@ -0,0 +1,13 @@
+# Copyright (c) 2013 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': 'test_unsupported',
+ 'type': 'executable',
+ 'sources': ['manifest-in-comment.cc'],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/linker-flags/update_pgd.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 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.
+
+from optparse import OptionParser
+import glob
+import os
+import subprocess
+
+parser = OptionParser()
+parser.add_option('--exe', dest='exe')
+parser.add_option('--vcbindir', dest='vcbindir')
+parser.add_option('--pgd', dest='pgd')
+(options, args) = parser.parse_args()
+
+# Instrumented binaries fail to run unless the Visual C++'s bin dir is included
+# in the PATH environment variable.
+os.environ['PATH'] = os.environ['PATH'] + os.pathsep + options.vcbindir
+
+# Run Instrumented binary. The profile will be recorded into *.pgc file.
+subprocess.call([options.exe])
+
+# Merge *.pgc files into a *.pgd (Profile-Guided Database) file.
+subprocess.call(['pgomgr', '/merge', options.pgd])
+
+# *.pgc files are no longer necessary. Clear all of them.
+pgd_file = os.path.abspath(options.pgd)
+pgd_dir = os.path.dirname(pgd_file)
+(pgd_basename, _) = os.path.splitext(os.path.basename(pgd_file))
+pgc_filepattern = os.path.join(pgd_dir, '%s!*.pgc' % pgd_basename)
+pgc_files= glob.glob(pgc_filepattern)
+for pgc_file in pgc_files:
+ os.unlink(pgc_file)
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/linker-flags/warn-as-error.gyp
@@ -0,0 +1,33 @@
+# Copyright (c) 2013 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': 'test_on',
+ 'type': 'executable',
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'TreatLinkerWarningAsErrors': 'true',
+ }
+ },
+ 'sources': ['link-warning.cc'],
+ },
+ {
+ 'target_name': 'test_off',
+ 'type': 'executable',
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'TreatLinkerWarningAsErrors': 'false',
+ }
+ },
+ 'sources': ['link-warning.cc'],
+ },
+ {
+ 'target_name': 'test_default',
+ 'type': 'executable',
+ 'sources': ['link-warning.cc'],
+ },
+ ]
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/linker-flags/x.cc
@@ -0,0 +1,7 @@
+// Copyright (c) 2013 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 x() {
+ return 1;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/linker-flags/y.cc
@@ -0,0 +1,7 @@
+// Copyright (c) 2013 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 y() {
+ return 2;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/linker-flags/z.cc
@@ -0,0 +1,7 @@
+// Copyright (c) 2013 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 z() {
+ return 3;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/ml-safeseh/a.asm
@@ -0,0 +1,10 @@
+.MODEL FLAT, C
+.CODE
+
+PUBLIC zero
+zero PROC
+ xor eax, eax
+ ret 0
+zero ENDP
+
+END
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/ml-safeseh/hello.cc
@@ -0,0 +1,11 @@
+// Copyright (c) 2014 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.
+
+extern "C" {
+int zero(void);
+}
+
+int main() {
+ return zero();
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/ml-safeseh/ml-safeseh.gyp
@@ -0,0 +1,24 @@
+# Copyright (c) 2014 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': 'ml_safeseh',
+ 'type': 'executable',
+ 'sources': [
+ 'hello.cc',
+ 'a.asm',
+ ],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'ImageHasSafeExceptionHandlers': 'true',
+ },
+ 'MASM': {
+ 'UseSafeExceptionHandlers': 'true',
+ },
+ },
+ },
+ ]
+}
--- a/media/webrtc/trunk/tools/gyp/test/win/precompiled/hello.c
+++ b/media/webrtc/trunk/tools/gyp/test/win/precompiled/hello.c
@@ -2,13 +2,13 @@
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file. */
// Note the abscence of a stdio.h include. This will be inserted because of the
// precompiled header.
extern int hello2();
-int main(int argc, char *argv[]) {
+int main(void) {
printf("Hello, world!\n");
hello2();
return 0;
}
--- a/media/webrtc/trunk/tools/gyp/test/win/rc-build/hello.gyp
+++ b/media/webrtc/trunk/tools/gyp/test/win/rc-build/hello.gyp
@@ -17,16 +17,20 @@
'VCResourceCompilerTool': {
'Culture' : '1033',
},
},
'sources': [
'hello.cpp',
'hello.rc',
],
+ 'libraries': [
+ 'kernel32.lib',
+ 'user32.lib',
+ ],
},
{
'target_name': 'with_resources_subdir',
'type': 'executable',
'msvs_settings': {
'VCCLCompilerTool': {
'DebugInformationFormat': '3',
},
@@ -36,16 +40,46 @@
'VCResourceCompilerTool': {
'Culture' : '1033',
},
},
'sources': [
'hello.cpp',
'subdir/hello2.rc',
],
+ 'libraries': [
+ 'kernel32.lib',
+ 'user32.lib',
+ ],
+ },
+ {
+ 'target_name': 'with_include_subdir',
+ 'type': 'executable',
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'DebugInformationFormat': '3',
+ },
+ 'VCLinkerTool': {
+ 'GenerateDebugInformation': 'true',
+ },
+ 'VCResourceCompilerTool': {
+ 'Culture' : '1033',
+ },
+ },
+ 'resource_include_dirs': [
+ '$(ProjectDir)\\subdir',
+ ],
+ 'sources': [
+ 'hello.cpp',
+ 'hello3.rc',
+ ],
+ 'libraries': [
+ 'kernel32.lib',
+ 'user32.lib',
+ ],
},
{
'target_name': 'resource_only_dll',
'type': 'shared_library',
'msvs_settings': {
'VCLinkerTool': {
'ResourceOnlyDLL': 'true',
},
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/rc-build/hello3.rc
@@ -0,0 +1,87 @@
+//Microsoft Visual C++ generated resource script.
+//
+#include "include.h"
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#ifndef APSTUDIO_INVOKED
+#include "targetver.h"
+#endif
+#define APSTUDIO_HIDDEN_SYMBOLS
+#include "windows.h"
+#undef APSTUDIO_HIDDEN_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+LANGUAGE 9, 1
+#pragma code_page(932)
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+
+IDI_HELLO ICON "hello.ico"
+IDI_SMALL ICON "small.ico"
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#ifndef APSTUDIO_INVOKED\r\n"
+ "#include ""targetver.h""\r\n"
+ "#endif\r\n"
+ "#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
+ "#include ""windows.h""\r\n"
+ "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE
+BEGIN
+ IDC_HELLO "HELLO"
+ IDS_APP_TITLE "hello"
+END
+
+#endif
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/shard/hello.cc
@@ -0,0 +1,7 @@
+// Copyright 2014 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 main() {
+ return 0;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/shard/hello1.cc
@@ -0,0 +1,7 @@
+// Copyright (c) 2013 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 f1() {
+ return 0;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/shard/hello2.cc
@@ -0,0 +1,7 @@
+// Copyright (c) 2013 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 f2() {
+ return 0;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/shard/hello3.cc
@@ -0,0 +1,7 @@
+// Copyright (c) 2013 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 f3() {
+ return 0;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/shard/hello4.cc
@@ -0,0 +1,7 @@
+// Copyright (c) 2013 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 f4() {
+ return 0;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/shard/shard.gyp
@@ -0,0 +1,31 @@
+# Copyright (c) 2013 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': 'shard',
+ 'type': 'static_library',
+ 'msvs_shard': 4,
+ 'sources': [
+ 'hello1.cc',
+ 'hello2.cc',
+ 'hello3.cc',
+ 'hello4.cc',
+ ],
+ 'product_dir': '<(PRODUCT_DIR)',
+ },
+ {
+ 'target_name': 'refs_to_shard',
+ 'type': 'executable',
+ 'dependencies': [
+ # Make sure references are correctly updated.
+ 'shard',
+ ],
+ 'sources': [
+ 'hello.cc',
+ ],
+ },
+ ]
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/shard/shard_ref.gyp
@@ -0,0 +1,41 @@
+# Copyright 2014 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': 'refs_to_shard_external_lib',
+ 'type': 'static_library',
+ 'dependencies': [
+ # Make sure references in other files are updated correctly.
+ 'shard.gyp:shard',
+ ],
+ 'sources': [
+ 'hello.cc',
+ ],
+ },
+ {
+ 'target_name': 'refs_to_shard_external_exe',
+ 'type': 'executable',
+ 'dependencies': [
+ # Make sure references in other files are updated correctly.
+ 'shard.gyp:shard',
+ ],
+ 'sources': [
+ 'hello.cc',
+ ],
+ },
+ {
+ 'target_name': 'refs_to_shard_external_dll',
+ 'type': 'shared_library',
+ 'dependencies': [
+ # Make sure references in other files are updated correctly.
+ 'shard.gyp:shard',
+ ],
+ 'sources': [
+ 'hello.cc',
+ ],
+ },
+ ]
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/system-include/main.cc
@@ -0,0 +1,4 @@
+#include <commonheader.h>
+#include <header.h>
+
+int main() {}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/system-include/test.gyp
@@ -0,0 +1,26 @@
+{
+ 'target_defaults': {
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'WarningLevel': '4',
+ 'WarnAsError': 'true',
+ },
+ },
+ 'msvs_system_include_dirs': [
+ '$(ProjectName)', # Different for each target
+ 'common', # Same for all targets
+ ],
+ },
+ 'targets': [
+ {
+ 'target_name': 'foo',
+ 'type': 'executable',
+ 'sources': [ 'main.cc', ],
+ },
+ {
+ 'target_name': 'bar',
+ 'type': 'executable',
+ 'sources': [ 'main.cc', ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/uldi/dll.cc
@@ -0,0 +1,6 @@
+// Copyright (c) 2015 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.
+
+__declspec(dllexport) void SomeFunction() {
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/uldi/exe.cc
@@ -0,0 +1,7 @@
+// Copyright (c) 2015 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 main() {
+ return 0;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/uldi/uldi-depending-on-module.gyp
@@ -0,0 +1,42 @@
+# Copyright (c) 2015 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': 'an_exe',
+ 'type': 'executable',
+ 'sources': ['exe.cc'],
+ 'dependencies': [
+ 'a_dll',
+ ],
+ },
+ {
+ 'target_name': 'a_dll',
+ 'type': 'shared_library',
+ 'sources': ['dll.cc'],
+ 'dependencies': [
+ 'a_lib',
+ ],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'UseLibraryDependencyInputs': 'true'
+ },
+ },
+ },
+ {
+ 'target_name': 'a_lib',
+ 'type': 'static_library',
+ 'dependencies': [
+ 'a_module',
+ ],
+ 'sources': ['a.cc'],
+ },
+ {
+ 'target_name': 'a_module',
+ 'type': 'loadable_module',
+ 'sources': ['a.cc'],
+ },
+ ]
+}
--- a/media/webrtc/trunk/tools/gyp/test/win/vs-macros/containing-gyp.gyp
+++ b/media/webrtc/trunk/tools/gyp/test/win/vs-macros/containing-gyp.gyp
@@ -11,17 +11,16 @@
'rules': [
{
'rule_name': 'assembler (gnu-compatible)',
'msvs_cygwin_shell': 0,
'msvs_quote_cmd': 0,
'extension': 'S',
'inputs': [
'as.py',
- '$(InputPath)'
],
'outputs': [
'$(IntDir)/$(InputName).obj',
],
'action':
['python',
'as.py',
'-a', '$(PlatformName)',
--- a/media/webrtc/trunk/tools/gyp/test/win/vs-macros/input-output-macros.gyp
+++ b/media/webrtc/trunk/tools/gyp/test/win/vs-macros/input-output-macros.gyp
@@ -8,17 +8,16 @@
'target_name': 'test_expansions',
'msvs_cygwin_shell': 0,
'type': 'none',
'rules': [
{
'rule_name': 'generate_file',
'extension': 'blah',
'inputs': [
- '<(RULE_INPUT_PATH)',
'do_stuff.py',
],
'outputs': [
'$(OutDir)\\<(RULE_INPUT_NAME).something',
],
'action': ['python',
'do_stuff.py',
'<(RULE_INPUT_PATH)',
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/vs-macros/targetext.gyp
@@ -0,0 +1,59 @@
+# Copyright (c) 2014 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': 'test_targetext_executable',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'OutputFile': '$(TargetDir)\\executable$(TargetExt)',
+ },
+ },
+ },
+ {
+ 'target_name': 'test_targetext_loadable_module',
+ 'type': 'loadable_module',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'OutputFile': '$(TargetDir)\\loadable_module$(TargetExt)',
+ },
+ },
+ },
+ {
+ 'target_name': 'test_targetext_shared_library',
+ 'type': 'shared_library',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'OutputFile': '$(TargetDir)\\shared_library$(TargetExt)',
+ },
+ },
+ },
+ {
+ 'target_name': 'test_targetext_static_library',
+ 'type': 'static_library',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCLibrarianTool': {
+ 'OutputFile': '$(TargetDir)\\static_library$(TargetExt)',
+ },
+ },
+ },
+ {
+ 'target_name': 'test_targetext_product_extension',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'product_extension': 'library',
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'OutputFile': '$(TargetDir)\\product_extension$(TargetExt)',
+ },
+ },
+ },
+ ]
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/vs-macros/targetfilename.gyp
@@ -0,0 +1,59 @@
+# Copyright (c) 2014 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': 'test_targetfilename_executable',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'OutputFile': '$(TargetDir)\\$(TargetFileName)',
+ },
+ },
+ },
+ {
+ 'target_name': 'test_targetfilename_loadable_module',
+ 'type': 'loadable_module',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'OutputFile': '$(TargetDir)\\$(TargetFileName)',
+ },
+ },
+ },
+ {
+ 'target_name': 'test_targetfilename_shared_library',
+ 'type': 'loadable_module',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'OutputFile': '$(TargetDir)\\$(TargetFileName)',
+ },
+ },
+ },
+ {
+ 'target_name': 'test_targetfilename_static_library',
+ 'type': 'static_library',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCLibrarianTool': {
+ 'OutputFile': '$(TargetDir)\\$(TargetFileName)',
+ },
+ },
+ },
+ {
+ 'target_name': 'test_targetfilename_product_extension',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'product_extension': 'foo',
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'OutputFile': '$(TargetDir)\\$(TargetFileName)',
+ },
+ },
+ },
+ ]
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/vs-macros/targetname.gyp
@@ -0,0 +1,52 @@
+# Copyright (c) 2013 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': 'test_targetname',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'OutputFile': '$(TargetDir)\\$(TargetName)_plus_something1.exe',
+ },
+ },
+ },
+ {
+ 'target_name': 'test_targetname_with_prefix',
+ 'product_prefix': 'prod_prefix',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'OutputFile': '$(TargetDir)\\$(TargetName)_plus_something2.exe',
+ },
+ },
+ },
+ {
+ 'target_name': 'test_targetname_with_prodname',
+ 'product_name': 'prod_name',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'OutputFile': '$(TargetDir)\\$(TargetName)_plus_something3.exe',
+ },
+ },
+ },
+ {
+ 'target_name': 'test_targetname_with_prodname_with_prefix',
+ 'product_name': 'prod_name',
+ 'product_prefix': 'prod_prefix',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'OutputFile': '$(TargetDir)\\$(TargetName)_plus_something4.exe',
+ },
+ },
+ },
+ ]
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/vs-macros/targetpath.gyp
@@ -0,0 +1,59 @@
+# Copyright (c) 2014 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': 'test_targetpath_executable',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'OutputFile': '$(TargetPath)',
+ },
+ },
+ },
+ {
+ 'target_name': 'test_targetpath_loadable_module',
+ 'type': 'loadable_module',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'OutputFile': '$(TargetPath)',
+ },
+ },
+ },
+ {
+ 'target_name': 'test_targetpath_shared_library',
+ 'type': 'loadable_module',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'OutputFile': '$(TargetPath)',
+ },
+ },
+ },
+ {
+ 'target_name': 'test_targetpath_static_library',
+ 'type': 'static_library',
+ 'sources': ['hello.cc'],
+ 'msvs_settings': {
+ 'VCLibrarianTool': {
+ 'OutputFile': '$(TargetPath)',
+ },
+ },
+ },
+ {
+ 'target_name': 'test_targetpath_product_extension',
+ 'type': 'executable',
+ 'sources': ['hello.cc'],
+ 'product_extension': 'foo',
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'OutputFile': '$(TargetPath)',
+ },
+ },
+ },
+ ]
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/win-driver-target-type/win-driver-target-type.c
@@ -0,0 +1,10 @@
+// Copyright (c) 2016 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 "win-driver-target-type.h"
+
+NTSTATUS DriverEntry(_In_ struct _DRIVER_OBJECT *DriverObject,
+ _In_ PUNICODE_STRING RegistryPath) {
+ return STATUS_SUCCESS;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/win-driver-target-type/win-driver-target-type.gyp
@@ -0,0 +1,32 @@
+# Copyright (c) 2016 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': 'win_driver_target_type',
+ 'type': 'windows_driver',
+ 'msvs_target_version': 'Windows7',
+ 'sources': [
+ 'win-driver-target-type.c',
+ 'win-driver-target-type.h',
+ 'win-driver-target-type.rc',
+ ],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'AdditionalDependencies': [
+ 'wdmsec.lib',
+ 'ntoskrnl.lib',
+ 'hal.lib',
+ 'wmilib.lib',
+ 'bufferoverflowfastfailk.lib',
+ ],
+ },
+ 'VCCLCompilerTool': {
+ 'WarnAsError': 'false',
+ },
+ },
+ },
+ ]
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/win-driver-target-type/win-driver-target-type.h
@@ -0,0 +1,13 @@
+// Copyright (c) 2016 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE
+
+#ifndef _WIN_DRIVER_TARGET_TYPE_H_
+#define _WIN_DRIVER_TARGET_TYPE_H_
+
+#include <ntifs.h>
+#include <ntdddisk.h>
+
+DRIVER_INITIALIZE DriverEntry;
+
+#endif
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/win-driver-target-type/win-driver-target-type.rc
@@ -0,0 +1,14 @@
+// Copyright (c) 2016 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 <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+#define VER_FILEDESCRIPTION_STR "Windows Driver GYP target type"
+#define VER_INTERNALNAME_STR "win-driver-target-type.sys"
+#define VER_ORIGINALFILENAME_STR "win-driver-target-type.sys"
+
+#include "common.ver"
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/win-tool/copies_readonly_files.gyp
@@ -0,0 +1,29 @@
+{
+ 'targets': [
+ {
+ 'target_name': 'foo',
+ 'type': 'none',
+ 'copies': [
+ {
+ 'destination': '<(PRODUCT_DIR)/dest',
+ 'files': [
+ 'read-only-file',
+ ],
+ },
+ ],
+ }, # target: foo
+
+ {
+ 'target_name': 'bar',
+ 'type': 'none',
+ 'copies': [
+ {
+ 'destination': '<(PRODUCT_DIR)/dest',
+ 'files': [
+ 'subdir/',
+ ],
+ },
+ ],
+ }, # target: bar
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/win-tool/gyptest-win-tool-handles-readonly-files.py
@@ -0,0 +1,55 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 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.
+
+"""
+Make sure overwriting read-only files works as expected (via win-tool).
+"""
+
+import TestGyp
+
+import filecmp
+import os
+import stat
+import sys
+
+if sys.platform == 'win32':
+ test = TestGyp.TestGyp(formats=['ninja'])
+
+ # First, create the source files.
+ os.makedirs('subdir')
+ read_only_files = ['read-only-file', 'subdir/A', 'subdir/B', 'subdir/C']
+ for f in read_only_files:
+ test.write(f, 'source_contents')
+ test.chmod(f, stat.S_IREAD)
+ if os.access(f, os.W_OK):
+ test.fail_test()
+
+ # Second, create the read-only destination files. Note that we are creating
+ # them where the ninja and win-tool will try to copy them to, in order to test
+ # that copies overwrite the files.
+ os.makedirs(test.built_file_path('dest/subdir'))
+ for f in read_only_files:
+ f = os.path.join('dest', f)
+ test.write(test.built_file_path(f), 'SHOULD BE OVERWRITTEN')
+ test.chmod(test.built_file_path(f), stat.S_IREAD)
+ # Ensure not writable.
+ if os.access(test.built_file_path(f), os.W_OK):
+ test.fail_test()
+
+ test.run_gyp('copies_readonly_files.gyp')
+ test.build('copies_readonly_files.gyp')
+
+ # Check the destination files were overwritten by ninja.
+ for f in read_only_files:
+ f = os.path.join('dest', f)
+ test.must_contain(test.built_file_path(f), 'source_contents')
+
+ # This will fail if the files are not the same mode or contents.
+ for f in read_only_files:
+ if not filecmp.cmp(f, test.built_file_path(os.path.join('dest', f))):
+ test.fail_test()
+
+ test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/winrt-app-type-revision/dllmain.cc
@@ -0,0 +1,30 @@
+// Copyright (c) 2013 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 <windows.h>
+#include <wrl.h>
+#include <wrl/wrappers/corewrappers.h>
+#include <windows.graphics.display.h>
+
+using namespace Microsoft::WRL;
+using namespace Microsoft::WRL::Wrappers;
+using namespace ABI::Windows::Foundation;
+using namespace ABI::Windows::Graphics::Display;
+
+bool TryToUseSomeWinRT() {
+ ComPtr<IDisplayPropertiesStatics> dp;
+ HStringReference s(RuntimeClass_Windows_Graphics_Display_DisplayProperties);
+ HRESULT hr = GetActivationFactory(s.Get(), dp.GetAddressOf());
+ if (SUCCEEDED(hr)) {
+ float dpi = 96.0f;
+ if (SUCCEEDED(dp->get_LogicalDpi(&dpi))) {
+ return true;
+ }
+ }
+ return false;
+}
+
+BOOL WINAPI DllMain(HINSTANCE hinstance, DWORD reason, LPVOID reserved) {
+ return TRUE;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/winrt-app-type-revision/winrt-app-type-revison.gyp
@@ -0,0 +1,43 @@
+# Copyright (c) 2013 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': 'enable_winrt_81_revision_dll',
+ 'type': 'shared_library',
+ 'msvs_enable_winrt': 1,
+ 'msvs_application_type_revision': '8.1'
+ 'sources': [
+ 'dllmain.cc',
+ ],
+ },
+ {
+ 'target_name': 'enable_winrt_82_revision_dll',
+ 'type': 'shared_library',
+ 'msvs_enable_winrt': 1,
+ 'msvs_application_type_revision': '8.2'
+ 'sources': [
+ 'dllmain.cc',
+ ],
+ },
+ {
+ 'target_name': 'enable_winrt_invalid_revision_dll',
+ 'type': 'shared_library',
+ 'msvs_enable_winrt': 1,
+ 'msvs_application_type_revision': '999'
+ 'sources': [
+ 'dllmain.cc',
+ ],
+ },
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'AdditionalDependencies': [
+ '%(AdditionalDependencies)',
+ ],
+ },
+ },
+ },
+ ]
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/winrt-target-platform-version/dllmain.cc
@@ -0,0 +1,30 @@
+// Copyright (c) 2015 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 <windows.h>
+#include <wrl.h>
+#include <wrl/wrappers/corewrappers.h>
+#include <windows.graphics.display.h>
+
+using namespace Microsoft::WRL;
+using namespace Microsoft::WRL::Wrappers;
+using namespace ABI::Windows::Foundation;
+using namespace ABI::Windows::Graphics::Display;
+
+bool TryToUseSomeWinRT() {
+ ComPtr<IDisplayPropertiesStatics> dp;
+ HStringReference s(RuntimeClass_Windows_Graphics_Display_DisplayProperties);
+ HRESULT hr = GetActivationFactory(s.Get(), dp.GetAddressOf());
+ if (SUCCEEDED(hr)) {
+ float dpi = 96.0f;
+ if (SUCCEEDED(dp->get_LogicalDpi(&dpi))) {
+ return true;
+ }
+ }
+ return false;
+}
+
+BOOL WINAPI DllMain(HINSTANCE hinstance, DWORD reason, LPVOID reserved) {
+ return TRUE;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/win/winrt-target-platform-version/winrt-target-platform-version.gyp
@@ -0,0 +1,49 @@
+# Copyright (c) 2015 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': 'enable_winrt_10_platversion_dll',
+ 'type': 'shared_library',
+ 'msvs_enable_winrt': 1,
+ 'msvs_application_type_revision': '10.0',
+ 'msvs_target_platform_version':'10.0.10240.0',
+ 'msvs_target_platform_minversion':'10.0.10240.0'
+ 'sources': [
+ 'dllmain.cc',
+ ],
+ },
+ {
+ 'target_name': 'enable_winrt_10_platversion_nominver_dll',
+ 'type': 'shared_library',
+ 'msvs_enable_winrt': 1,
+ 'msvs_application_type_revision': '10.0',
+ 'msvs_target_platform_version':'10.0.10240.0',
+ 'sources': [
+ 'dllmain.cc',
+ ],
+ },
+ {
+ 'target_name': 'enable_winrt_9_platversion_dll',
+ 'type': 'shared_library',
+ 'msvs_enable_winrt': 1,
+ 'msvs_application_type_revision': '10.0',
+ 'msvs_target_platform_version':'9.0.0.0',
+ 'msvs_target_platform_minversion':'9.0.0.0'
+ 'sources': [
+ 'dllmain.cc',
+ ],
+ },
+ {
+ 'target_name': 'enable_winrt_missing_platversion_dll',
+ 'type': 'shared_library',
+ 'msvs_enable_winrt': 1,
+ 'msvs_application_type_revision': '10.0',
+ 'sources': [
+ 'dllmain.cc',
+ ],
+ },
+ ]
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/xcode-ninja/list_excluded/gyptest-all.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that excluded files are listed in sources_for_indexing.xcodeproj by
+default, and that the generator flag xcode_ninja_list_excluded_files can be
+used to override the default behavior.
+"""
+
+import os
+import TestGyp
+
+
+test = TestGyp.TestGyp()
+
+if test.format != 'xcode-ninja':
+ test.skip_test()
+
+
+# With the generator flag not set.
+test.run_gyp('hello_exclude.gyp')
+test.must_contain(
+ 'sources_for_indexing.xcodeproj/project.pbxproj', 'hello_excluded.cpp')
+
+
+# With the generator flag set to 0.
+try:
+ os.environ['GYP_GENERATOR_FLAGS'] = 'xcode_ninja_list_excluded_files=0'
+ test.run_gyp('hello_exclude.gyp')
+finally:
+ del os.environ['GYP_GENERATOR_FLAGS']
+test.must_not_contain(
+ 'sources_for_indexing.xcodeproj/project.pbxproj', 'hello_excluded.cpp')
+
+
+# With the generator flag explicitly set to 1.
+try:
+ os.environ['GYP_GENERATOR_FLAGS'] = 'xcode_ninja_list_excluded_files=1'
+ test.run_gyp('hello_exclude.gyp')
+finally:
+ del os.environ['GYP_GENERATOR_FLAGS']
+test.must_contain(
+ 'sources_for_indexing.xcodeproj/project.pbxproj', 'hello_excluded.cpp')
+
+
+test.pass_test()
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/xcode-ninja/list_excluded/hello.cpp
@@ -0,0 +1,7 @@
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int main() {
+ return 0;
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/xcode-ninja/list_excluded/hello_exclude.gyp
@@ -0,0 +1,19 @@
+# Copyright (c) 2016 The Chromium Authors. 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': 'hello',
+ 'type': 'executable',
+ 'sources': [
+ 'hello.cpp',
+ 'hello_excluded.cpp',
+ ],
+ 'sources!': [
+ 'hello_excluded.cpp',
+ ],
+ },
+ ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/tools/gyp/test/xcode-ninja/list_excluded/hello_excluded.cpp
@@ -0,0 +1,7 @@
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+int main() {
+ return 42;
+}
--- a/media/webrtc/trunk/tools/gyp/tools/emacs/gyp-tests.el
+++ b/media/webrtc/trunk/tools/gyp/tools/emacs/gyp-tests.el
@@ -21,21 +21,30 @@
(font-lock-fontify-buffer)
(buffer-string)))
(defun read-golden-sample (filename)
(with-temp-buffer
(insert-file-contents-literally (concat filename ".fontified"))
(read (current-buffer))))
+(defun equivalent-face (face)
+ "For the purposes of face comparison, we're not interested in the
+ differences between certain faces. For example, the difference between
+ font-lock-comment-delimiter and font-lock-comment-face."
+ (case face
+ ((font-lock-comment-delimiter-face) font-lock-comment-face)
+ (t face)))
+
(defun text-face-properties (s)
"Extract the text properties from s"
(let ((result (list t)))
(dotimes (i (length s))
- (setq result (cons (get-text-property i 'face s) result)))
+ (setq result (cons (equivalent-face (get-text-property i 'face s))
+ result)))
(nreverse result)))
(ert-deftest test-golden-samples ()
"Check that fontification produces the same results as the golden samples"
(dolist (sample samples)
(let ((golden (read-golden-sample sample))
(fontified (fontify sample)))
(should (equal golden fontified))
--- a/media/webrtc/trunk/tools/gyp/tools/emacs/gyp.el
+++ b/media/webrtc/trunk/tools/gyp/tools/emacs/gyp.el
@@ -10,44 +10,68 @@
(require 'python)
(require 'cl)
(when (string-match "python-mode.el" (symbol-file 'python-mode 'defun))
(error (concat "python-mode must be loaded from python.el (bundled with "
"recent emacsen), not from the older and less maintained "
"python-mode.el")))
-(defadvice python-calculate-indentation (after ami-outdent-closing-parens
- activate)
+(defadvice python-indent-calculate-levels (after gyp-outdent-closing-parens
+ activate)
"De-indent closing parens, braces, and brackets in gyp-mode."
- (if (and (eq major-mode 'gyp-mode)
- (string-match "^ *[])}][],)}]* *$"
- (buffer-substring-no-properties
- (line-beginning-position) (line-end-position))))
- (setq ad-return-value (- ad-return-value 2))))
+ (when (and (eq major-mode 'gyp-mode)
+ (string-match "^ *[])}][],)}]* *$"
+ (buffer-substring-no-properties
+ (line-beginning-position) (line-end-position))))
+ (setf (first python-indent-levels)
+ (- (first python-indent-levels) python-continuation-offset))))
+
+(defadvice python-indent-guess-indent-offset (around
+ gyp-indent-guess-indent-offset
+ activate)
+ "Guess correct indent offset in gyp-mode."
+ (or (and (not (eq major-mode 'gyp-mode))
+ ad-do-it)
+ (save-excursion
+ (save-restriction
+ (widen)
+ (goto-char (point-min))
+ ;; Find first line ending with an opening brace that is not a comment.
+ (or (and (re-search-forward "\\(^[[{]$\\|^.*[^#].*[[{]$\\)")
+ (forward-line)
+ (/= (current-indentation) 0)
+ (set (make-local-variable 'python-indent-offset)
+ (current-indentation))
+ (set (make-local-variable 'python-continuation-offset)
+ (current-indentation)))
+ (message "Can't guess gyp indent offset, using default: %s"
+ python-continuation-offset))))))
(define-derived-mode gyp-mode python-mode "Gyp"
"Major mode for editing .gyp files. See http://code.google.com/p/gyp/"
;; gyp-parse-history is a stack of (POSITION . PARSE-STATE) tuples,
;; with greater positions at the top of the stack. PARSE-STATE
;; is a list of section symbols (see gyp-section-name and gyp-parse-to)
;; with most nested section symbol at the front of the list.
(set (make-local-variable 'gyp-parse-history) '((1 . (list))))
(gyp-add-font-lock-keywords))
(defun gyp-set-indentation ()
"Hook function to configure python indentation to suit gyp mode."
- (setq python-continuation-offset 2
- python-indent 2
- python-guess-indent nil))
+ (set (make-local-variable 'python-indent-offset) 2)
+ (set (make-local-variable 'python-continuation-offset) 2)
+ (set (make-local-variable 'python-indent-guess-indent-offset) t)
+ (python-indent-guess-indent-offset))
(add-hook 'gyp-mode-hook 'gyp-set-indentation)
(add-to-list 'auto-mode-alist '("\\.gyp\\'" . gyp-mode))
(add-to-list 'auto-mode-alist '("\\.gypi\\'" . gyp-mode))
+(add-to-list 'auto-mode-alist '("/\\.gclient\\'" . gyp-mode))
;;; Font-lock support
(defconst gyp-dependencies-regexp
(regexp-opt (list "dependencies" "export_dependent_settings"))
"Regular expression to introduce 'dependencies' section")
(defconst gyp-sources-regexp
@@ -130,17 +154,17 @@
target-point
-1
t))
(sections (gyp-parse-sections)))
(if (= (nth 0 state) -1)
(setq sections (cdr sections)) ; pop out a level
(cond ((looking-at-p "['\"]") ; a string
(setq string-start (point))
- (forward-sexp 1)
+ (goto-char (scan-sexps (point) 1))
(if (gyp-inside-dictionary-p)
;; Look for sections inside a dictionary
(let ((section (gyp-section-name
(buffer-substring-no-properties
(+ 1 string-start)
(- (point) 1)))))
(setq sections (cons section (cdr sections)))))
;; Stop after the string so it can be fontified.
@@ -212,21 +236,21 @@
;; TODO(jknotten): Move all the keyword highlighting into gyp-section-match
;; so that we can do the font-locking in a single font-lock pass.
(font-lock-add-keywords
nil
(list
;; Top-level keywords
(list (concat "['\"]\\("
(regexp-opt (list "action" "action_name" "actions" "cflags"
- "conditions" "configurations" "copies" "defines"
- "dependencies" "destination"
+ "cflags_cc" "conditions" "configurations"
+ "copies" "defines" "dependencies" "destination"
"direct_dependent_settings"
"export_dependent_settings" "extension" "files"
- "include_dirs" "includes" "inputs" "libraries"
+ "include_dirs" "includes" "inputs" "ldflags" "libraries"
"link_settings" "mac_bundle" "message"
"msvs_external_rule" "outputs" "product_name"
"process_outputs_as_sources" "rules" "rule_name"
"sources" "suppress_wildcard"
"target_conditions" "target_defaults"
"target_defines" "target_name" "toolsets"
"targets" "type" "variables" "xcode_settings"))
"[!/+=]?\\)") 1 'font-lock-keyword-face t)
--- a/media/webrtc/trunk/tools/gyp/tools/pretty_gyp.py
+++ b/media/webrtc/trunk/tools/gyp/tools/pretty_gyp.py
@@ -113,34 +113,33 @@ def count_braces(line):
def prettyprint_input(lines):
"""Does the main work of indenting the input based on the brace counts."""
indent = 0
basic_offset = 2
last_line = ""
for line in lines:
- if COMMENT_RE.match(line):
- print line
- else:
- line = line.strip('\r\n\t ') # Otherwise doesn't strip \r on Unix.
- if len(line) > 0:
+ line = line.strip('\r\n\t ') # Otherwise doesn't strip \r on Unix.
+ if len(line) > 0:
+ brace_diff = 0
+ if not COMMENT_RE.match(line):
(brace_diff, after) = count_braces(line)
- if brace_diff != 0:
- if after:
- print " " * (basic_offset * indent) + line
- indent += brace_diff
- else:
- indent += brace_diff
- print " " * (basic_offset * indent) + line
+ if brace_diff != 0:
+ if after:
+ print " " * (basic_offset * indent) + line
+ indent += brace_diff
else:
+ indent += brace_diff
print " " * (basic_offset * indent) + line
else:
- print ""
- last_line = line
+ print " " * (basic_offset * indent) + line
+ else:
+ print ""
+ last_line = line
def main():
if len(sys.argv) > 1:
data = open(sys.argv[1]).read().splitlines()
else:
data = sys.stdin.read().splitlines()
# Split up the double braces.
--- a/media/webrtc/trunk/tools/gyp/tools/pretty_sln.py
+++ b/media/webrtc/trunk/tools/gyp/tools/pretty_sln.py
@@ -33,22 +33,23 @@ def ParseSolution(solution_file):
# All projects, their clsid and paths.
projects = dict()
# A list of dependencies associated with a project.
dependencies = dict()
# Regular expressions that matches the SLN format.
# The first line of a project definition.
- begin_project = re.compile(('^Project\("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942'
- '}"\) = "(.*)", "(.*)", "(.*)"$'))
+ begin_project = re.compile(r'^Project\("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942'
+ r'}"\) = "(.*)", "(.*)", "(.*)"$')
# The last line of a project definition.
end_project = re.compile('^EndProject$')
# The first line of a dependency list.
- begin_dep = re.compile('ProjectSection\(ProjectDependencies\) = postProject$')
+ begin_dep = re.compile(
+ r'ProjectSection\(ProjectDependencies\) = postProject$')
# The last line of a dependency list.
end_dep = re.compile('EndProjectSection$')
# A line describing a dependency.
dep_line = re.compile(' *({.*}) = ({.*})$')
in_deps = False
solution = open(solution_file)
for line in solution: