* [win] Add support for MS VS2017 (via Registry)

REF: eb296f67da
PR-URL: https://github.com/nodejs/node/pull/12450
Reviewed-By: João Reis <reis@janeasystems.com>
This commit is contained in:
Refael Ackermann 2017-03-14 18:12:22 -04:00
Родитель 1e7f6b1571
Коммит 3a334b1280
25 изменённых файлов: 1129 добавлений и 450 удалений

Просмотреть файл

@ -10,3 +10,6 @@ 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>
Refael Ackermann <refack@gmail.com>

Просмотреть файл

@ -3,8 +3,7 @@
# (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 = {
@ -13,12 +12,12 @@ deps = {
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",
},
}

Просмотреть файл

@ -124,16 +124,3 @@ def CheckChangeOnCommit(input_api, output_api):
finally:
sys.path = old_sys_path
return report
TRYBOTS = [
'linux_try',
'mac_try',
'win_try',
]
def GetPreferredTryMasters(_, change):
return {
'client.gyp': { t: set(['defaulttests']) for t in TRYBOTS },
}

4
tools/gyp/README.md Normal file
Просмотреть файл

@ -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.

Просмотреть файл

@ -1,10 +1,6 @@
# This file is used by gcl to get repository specific information.
CODE_REVIEW_SERVER: codereview.chromium.org
# This file is used by git cl to get repository specific information.
CC_LIST: gyp-developer@googlegroups.com
VIEW_VC: https://chromium.googlesource.com/external/gyp/+/
TRY_ON_UPLOAD: False
TRYSERVER_PROJECT: gyp
TRYSERVER_PATCHLEVEL: 1
TRYSERVER_ROOT: gyp
TRYSERVER_SVN_URL: svn://svn.chromium.org/chrome-try/try-nacl
CODE_REVIEW_SERVER: codereview.chromium.org
GERRIT_HOST: True
PROJECT: gyp
VIEW_VC: https://chromium.googlesource.com/external/gyp/+/

Просмотреть файл

@ -10,6 +10,7 @@ gyptest.py -- test runner for GYP tests.
import os
import optparse
import shlex
import subprocess
import sys

Просмотреть файл

@ -592,6 +592,7 @@ _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',

Просмотреть файл

@ -14,6 +14,7 @@ TARGET_TYPE_EXT = {
'loadable_module': 'dll',
'shared_library': 'dll',
'static_library': 'lib',
'windows_driver': 'sys',
}
@ -110,7 +111,7 @@ def ShardTargets(target_list, target_dicts):
else:
new_target_dicts[t] = target_dicts[t]
# Shard dependencies.
for t in new_target_dicts:
for t in sorted(new_target_dicts):
for deptype in ('dependencies', 'dependencies_original'):
dependencies = copy.copy(new_target_dicts[t].get(deptype, []))
new_dependencies = []

Просмотреть файл

@ -18,7 +18,7 @@ class VisualStudioVersion(object):
def __init__(self, short_name, description,
solution_version, project_version, flat_sln, uses_vcxproj,
path, sdk_based, default_toolset=None):
path, sdk_based, default_toolset=None, compatible_sdks=None):
self.short_name = short_name
self.description = description
self.solution_version = solution_version
@ -28,6 +28,9 @@ class VisualStudioVersion(object):
self.path = path
self.sdk_based = sdk_based
self.default_toolset = default_toolset
compatible_sdks = compatible_sdks or []
compatible_sdks.sort(key=lambda v: float(v.replace('v', '')), reverse=True)
self.compatible_sdks = compatible_sdks
def ShortName(self):
return self.short_name
@ -68,17 +71,19 @@ class VisualStudioVersion(object):
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
@ -106,6 +111,14 @@ class VisualStudioVersion(object):
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.
@ -226,6 +239,16 @@ def _CreateVersion(name, path, sdk_based=False):
if path:
path = os.path.normpath(path)
versions = {
'2017': VisualStudioVersion('2017',
'Visual Studio 2017',
solution_version='12.00',
project_version='15.0',
flat_sln=False,
uses_vcxproj=True,
path=path,
sdk_based=sdk_based,
default_toolset='v141',
compatible_sdks=['v8.1', 'v10.0']),
'2015': VisualStudioVersion('2015',
'Visual Studio 2015',
solution_version='12.00',
@ -338,7 +361,6 @@ def _DetectVisualStudioVersions(versions_to_check, force_express):
A list of visual studio versions installed in descending order of
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)
@ -346,6 +368,7 @@ def _DetectVisualStudioVersions(versions_to_check, force_express):
2012(e) - Visual Studio 2012 (11)
2013(e) - Visual Studio 2013 (12)
2015 - Visual Studio 2015 (14)
2017 - Visual Studio 2017 (15)
Where (e) is e for express editions of MSVS and blank otherwise.
"""
version_to_year = {
@ -355,6 +378,7 @@ def _DetectVisualStudioVersions(versions_to_check, force_express):
'11.0': '2012',
'12.0': '2013',
'14.0': '2015',
'15.0': '2017'
}
versions = []
for version in versions_to_check:
@ -385,13 +409,18 @@ def _DetectVisualStudioVersions(versions_to_check, force_express):
# 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']
r'HKLM\Software\Wow6432Node\Microsoft\VisualStudio\SxS\VC7',
r'HKLM\Software\Microsoft\VisualStudio\SxS\VS7',
r'HKLM\Software\Wow6432Node\Microsoft\VisualStudio\SxS\VS7']
for index in range(len(keys)):
path = _RegistryGetValue(keys[index], version)
if not path:
continue
path = _ConvertToCygpath(path)
if version != '14.0': # There is no Express edition for 2015.
if version == '15.0':
if os.path.exists(path):
versions.append(_CreateVersion('2017', path))
elif 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))
@ -410,7 +439,7 @@ def SelectVisualStudioVersion(version='auto', allow_fallback=True):
if version == 'auto':
version = os.environ.get('GYP_MSVS_VERSION', 'auto')
version_map = {
'auto': ('14.0', '12.0', '10.0', '9.0', '8.0', '11.0'),
'auto': ('15.0', '14.0', '12.0', '10.0', '9.0', '8.0', '11.0'),
'2005': ('8.0',),
'2005e': ('8.0',),
'2008': ('9.0',),
@ -422,6 +451,7 @@ def SelectVisualStudioVersion(version='auto', allow_fallback=True):
'2013': ('12.0',),
'2013e': ('12.0',),
'2015': ('14.0',),
'2017': ('15.0',),
}
override_path = os.environ.get('GYP_MSVS_OVERRIDE_PATH')
if override_path:

Просмотреть файл

@ -425,13 +425,15 @@ def GetFlavor(params):
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):
def CopyTool(flavor, out_path, generator_flags={}):
"""Finds (flock|mac|win)_tool.gyp in the gyp directory and copies it
to |out_path|."""
# aix and solaris just need flock emulation. mac and win use more complicated
@ -451,11 +453,18 @@ def CopyTool(flavor, out_path):
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)

Просмотреть файл

@ -7,23 +7,59 @@ 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.
targets: list of targets to search for. The target names are unqualified.
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.
targets: the set of targets passed in via targets that either directly or
indirectly depend upon the set of paths supplied in files.
build_targets: minimal set of targets that directly depend on the changed
files and need to be built. The expectation is this set of targets is passed
into a build step.
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 targets and build_targets are not output) or at
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 thare were not 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
@ -210,6 +246,8 @@ class Config(object):
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
@ -229,7 +267,9 @@ class Config(object):
if not isinstance(config, dict):
raise Exception('config_path must be a JSON file containing a dictionary')
self.files = config.get('files', [])
self.targets = set(config.get('targets', []))
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):
@ -280,12 +320,13 @@ def _GenerateTargets(data, target_list, target_dicts, toplevel_dir, 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|.
. Set of root Targets reachable from the the files |build_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.
targets = {}
name_to_target = {}
# Targets that matched.
matching_targets = []
@ -305,7 +346,8 @@ def _GenerateTargets(data, target_list, target_dicts, toplevel_dir, files,
while len(targets_to_visit) > 0:
target_name = targets_to_visit.pop()
created_target, target = _GetOrCreateTargetByName(targets, target_name)
created_target, target = _GetOrCreateTargetByName(name_to_target,
target_name)
if created_target:
roots.add(target)
elif target.visited:
@ -348,22 +390,25 @@ def _GenerateTargets(data, target_list, target_dicts, toplevel_dir, files,
for dep in target_dicts[target_name].get('dependencies', []):
targets_to_visit.append(dep)
created_dep_target, dep_target = _GetOrCreateTargetByName(targets, 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 targets, matching_targets, roots & build_file_targets
return name_to_target, matching_targets, roots & build_file_targets
def _GetUnqualifiedToTargetMapping(all_targets, to_find):
"""Returns a mapping (dictionary) from unqualified name to Target for all the
Targets in |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 result
return {}, []
to_find = set(to_find)
for target_name in all_targets.keys():
extracted = gyp.common.ParseQualifiedTarget(target_name)
@ -371,13 +416,14 @@ def _GetUnqualifiedToTargetMapping(all_targets, to_find):
to_find.remove(extracted[1])
result[extracted[1]] = all_targets[target_name]
if not to_find:
return result
return result
return result, []
return result, [x for x in to_find]
def _DoesTargetDependOn(target):
"""Returns true if |target| or any of its dependencies matches the supplied
set of paths. This updates |matches| of the Targets as it recurses.
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
@ -385,7 +431,7 @@ def _DoesTargetDependOn(target):
target.match_status == MATCH_STATUS_MATCHES_BY_DEPENDENCY:
return True
for dep in target.deps:
if _DoesTargetDependOn(dep):
if _DoesTargetDependOnMatchingTargets(dep):
target.match_status = MATCH_STATUS_MATCHES_BY_DEPENDENCY
print '\t', target.name, 'matches by dep', dep.name
return True
@ -393,19 +439,20 @@ def _DoesTargetDependOn(target):
return False
def _GetTargetsDependingOn(possible_targets):
def _GetTargetsDependingOnMatchingTargets(possible_targets):
"""Returns the list of Targets in |possible_targets| that depend (either
directly on indirectly) on the matched targets.
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 _DoesTargetDependOn(target):
if _DoesTargetDependOnMatchingTargets(target):
found.append(target)
return found
def _AddBuildTargets(target, roots, add_if_no_ancestor, result):
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.
@ -416,10 +463,10 @@ def _AddBuildTargets(target, roots, add_if_no_ancestor, result):
return
target.visited = True
target.in_roots = not target.back_deps and target in roots
target.in_roots = target in roots
for back_dep_target in target.back_deps:
_AddBuildTargets(back_dep_target, roots, False, result)
_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 |= (
@ -437,7 +484,7 @@ def _AddBuildTargets(target, roots, add_if_no_ancestor, result):
(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 build targets', target.name, 'executable', \
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, \
@ -447,14 +494,14 @@ def _AddBuildTargets(target, roots, add_if_no_ancestor, result):
target.added_to_compile_targets = True
def _GetBuildTargets(matching_targets, roots):
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.
roots: set of root targets in the build files to search from."""
supplied_targets: set of targets supplied to analyzer to search from."""
result = set()
for target in matching_targets:
print '\tfinding build targets for match', target.name
_AddBuildTargets(target, roots, True, result)
print 'finding compile targets for match', target.name
_AddCompileTargets(target, supplied_targets, True, result)
return result
@ -479,6 +526,16 @@ def _WriteOutput(params, **values):
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)
@ -538,11 +595,104 @@ def CalculateVariables(default_variables, params):
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')
@ -553,55 +703,38 @@ def GenerateOutput(target_list, target_dicts, data, params):
if _WasGypIncludeFileModified(params, config.files):
result_dict = { 'status': all_changed_string,
'targets': list(config.targets) }
'test_targets': list(config.test_target_names),
'compile_targets': list(
config.additional_compile_target_names |
config.test_target_names) }
_WriteOutput(params, **result_dict)
return
all_targets, matching_targets, roots = _GenerateTargets(
data, target_list, target_dicts, toplevel_dir, frozenset(config.files),
params['build_files'])
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
print 'roots:'
for root in roots:
print '\t', root.name
unqualified_mapping = _GetUnqualifiedToTargetMapping(all_targets,
config.targets)
invalid_targets = None
if len(unqualified_mapping) != len(config.targets):
invalid_targets = _NamesNotIn(config.targets, unqualified_mapping)
if matching_targets:
search_targets = _LookupTargets(config.targets, unqualified_mapping)
print 'supplied targets'
for target in config.targets:
print '\t', target
print 'expanded supplied targets'
for target in search_targets:
print '\t', target.name
matched_search_targets = _GetTargetsDependingOn(search_targets)
print 'raw matched search targets:'
for target in matched_search_targets:
print '\t', target.name
# Reset the visited status for _GetBuildTargets.
for target in all_targets.itervalues():
target.visited = False
print 'Finding build targets'
build_targets = _GetBuildTargets(matching_targets, roots)
matched_search_targets = [gyp.common.ParseQualifiedTarget(target.name)[1]
for target in matched_search_targets]
build_targets = [gyp.common.ParseQualifiedTarget(target.name)[1]
for target in build_targets]
else:
matched_search_targets = []
build_targets = []
result_dict = { 'targets': matched_search_targets,
'status': found_dependency_string if matching_targets else
no_dependency_string,
'build_targets': build_targets}
if invalid_targets:
result_dict['invalid_targets'] = invalid_targets
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:

Просмотреть файл

@ -34,6 +34,7 @@ import signal
import string
import subprocess
import gyp.common
import gyp.xcode_emulation
generator_default_variables = {
'EXECUTABLE_PREFIX': '',
@ -55,7 +56,7 @@ generator_default_variables = {
'CONFIGURATION_NAME': '${configuration}',
}
FULL_PATH_VARS = ('${CMAKE_SOURCE_DIR}', '${builddir}', '${obj}')
FULL_PATH_VARS = ('${CMAKE_CURRENT_LIST_DIR}', '${builddir}', '${obj}')
generator_supports_multiple_toolsets = True
generator_wants_static_library_dependencies_adjusted = True
@ -103,7 +104,7 @@ def NormjoinPathForceCMakeSource(base_path, 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_SOURCE_DIR}',
return os.path.join('${CMAKE_CURRENT_LIST_DIR}',
os.path.normpath(os.path.join(base_path, rel_path)))
@ -293,7 +294,7 @@ def WriteActions(target_name, actions, extra_sources, extra_deps,
WriteVariable(output, inputs_name)
output.write('\n')
output.write(' WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/')
output.write(' WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/')
output.write(path_to_gyp)
output.write('\n')
@ -398,9 +399,9 @@ def WriteRules(target_name, rules, extra_sources, extra_deps,
output.write(NormjoinPath(path_to_gyp, rule_source))
output.write('\n')
# CMAKE_SOURCE_DIR is where the CMakeLists.txt lives.
# CMAKE_CURRENT_LIST_DIR is where the CMakeLists.txt lives.
# The cwd is the current build directory.
output.write(' WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/')
output.write(' WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/')
output.write(path_to_gyp)
output.write('\n')
@ -522,7 +523,7 @@ def WriteCopies(target_name, copies, extra_deps, path_to_gyp, output):
WriteVariable(output, copy.inputs_name, ' ')
output.write('\n')
output.write('WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/')
output.write('WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/')
output.write(path_to_gyp)
output.write('\n')
@ -608,8 +609,8 @@ class CMakeNamer(object):
def WriteTarget(namer, qualified_target, target_dicts, build_dir, config_to_use,
options, generator_flags, all_qualified_targets, output):
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)
@ -633,6 +634,10 @@ def WriteTarget(namer, qualified_target, target_dicts, build_dir, config_to_use,
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')
@ -904,10 +909,10 @@ def WriteTarget(namer, qualified_target, target_dicts, build_dir, config_to_use,
defines = config.get('defines')
if defines is not None:
SetTargetProperty(output,
cmake_target_name,
'COMPILE_DEFINITIONS',
defines,
';')
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.
@ -927,6 +932,13 @@ def WriteTarget(namer, qualified_target, target_dicts, build_dir, config_to_use,
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, ' ')
@ -965,6 +977,13 @@ def WriteTarget(namer, qualified_target, target_dicts, build_dir, config_to_use,
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.
@ -1029,7 +1048,7 @@ def WriteTarget(namer, qualified_target, target_dicts, build_dir, config_to_use,
output.write(cmake_target_name)
output.write('\n')
if static_deps:
write_group = circular_libs and len(static_deps) > 1
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):
@ -1045,9 +1064,9 @@ def WriteTarget(namer, qualified_target, target_dicts, build_dir, config_to_use,
output.write('\n')
if external_libs:
for lib in gyp.common.uniquer(external_libs):
output.write(' ')
output.write(lib)
output.write('\n')
output.write(' "')
output.write(RemovePrefix(lib, "$(SDKROOT)"))
output.write('"\n')
output.write(')\n')
@ -1059,6 +1078,7 @@ 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.
@ -1126,7 +1146,7 @@ def GenerateOutputForConfig(target_list, target_dicts, data,
if cc:
SetVariable(output, 'CMAKE_ASM_COMPILER', cc)
SetVariable(output, 'builddir', '${CMAKE_BINARY_DIR}')
SetVariable(output, 'builddir', '${CMAKE_CURRENT_BINARY_DIR}')
SetVariable(output, 'obj', '${builddir}/obj')
output.write('\n')
@ -1141,7 +1161,9 @@ def GenerateOutputForConfig(target_list, target_dicts, data,
# Force ninja to use rsp files. Otherwise link and ar lines can get too long,
# resulting in 'Argument list too long' errors.
output.write('set(CMAKE_NINJA_FORCE_RESPONSE_FILE 1)\n')
# 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)
@ -1156,8 +1178,13 @@ def GenerateOutputForConfig(target_list, target_dicts, data,
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, output)
options, generator_flags, all_qualified_targets, flavor, output)
output.close()

Просмотреть файл

@ -1,115 +0,0 @@
# Copyright (c) 2016 Ben Noordhuis <info@bnoordhuis.nl>. 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.common
import gyp.xcode_emulation
import json
import os
generator_additional_non_configuration_keys = []
generator_additional_path_sections = []
generator_extra_sources_for_rules = []
generator_filelist_paths = None
generator_supports_multiple_toolsets = True
generator_wants_sorted_dependencies = False
# Lifted from make.py. The actual values don't matter much.
generator_default_variables = {
'CONFIGURATION_NAME': '$(BUILDTYPE)',
'EXECUTABLE_PREFIX': '',
'EXECUTABLE_SUFFIX': '',
'INTERMEDIATE_DIR': '$(obj).$(TOOLSET)/$(TARGET)/geni',
'PRODUCT_DIR': '$(builddir)',
'RULE_INPUT_DIRNAME': '%(INPUT_DIRNAME)s',
'RULE_INPUT_EXT': '$(suffix $<)',
'RULE_INPUT_NAME': '$(notdir $<)',
'RULE_INPUT_PATH': '$(abspath $<)',
'RULE_INPUT_ROOT': '%(INPUT_ROOT)s',
'SHARED_INTERMEDIATE_DIR': '$(obj)/gen',
'SHARED_LIB_PREFIX': 'lib',
'STATIC_LIB_PREFIX': 'lib',
'STATIC_LIB_SUFFIX': '.a',
}
def IsMac(params):
return 'mac' == gyp.common.GetFlavor(params)
def CalculateVariables(default_variables, params):
default_variables.setdefault('OS', gyp.common.GetFlavor(params))
def AddCommandsForTarget(cwd, target, params, per_config_commands):
output_dir = params['generator_flags']['output_dir']
for configuration_name, configuration in target['configurations'].iteritems():
builddir_name = os.path.join(output_dir, configuration_name)
if IsMac(params):
xcode_settings = gyp.xcode_emulation.XcodeSettings(target)
cflags = xcode_settings.GetCflags(configuration_name)
cflags_c = xcode_settings.GetCflagsC(configuration_name)
cflags_cc = xcode_settings.GetCflagsCC(configuration_name)
else:
cflags = configuration.get('cflags', [])
cflags_c = configuration.get('cflags_c', [])
cflags_cc = configuration.get('cflags_cc', [])
cflags_c = cflags + cflags_c
cflags_cc = cflags + cflags_cc
defines = configuration.get('defines', [])
defines = ['-D' + s for s in defines]
# TODO(bnoordhuis) Handle generated source files.
sources = target.get('sources', [])
sources = [s for s in sources if s.endswith('.c') or s.endswith('.cc')]
def resolve(filename):
return os.path.abspath(os.path.join(cwd, filename))
# TODO(bnoordhuis) Handle generated header files.
include_dirs = configuration.get('include_dirs', [])
include_dirs = [s for s in include_dirs if not s.startswith('$(obj)')]
includes = ['-I' + resolve(s) for s in include_dirs]
defines = gyp.common.EncodePOSIXShellList(defines)
includes = gyp.common.EncodePOSIXShellList(includes)
cflags_c = gyp.common.EncodePOSIXShellList(cflags_c)
cflags_cc = gyp.common.EncodePOSIXShellList(cflags_cc)
commands = per_config_commands.setdefault(configuration_name, [])
for source in sources:
file = resolve(source)
isc = source.endswith('.c')
cc = 'cc' if isc else 'c++'
cflags = cflags_c if isc else cflags_cc
command = ' '.join((cc, defines, includes, cflags,
'-c', gyp.common.EncodePOSIXShellArgument(file)))
commands.append(dict(command=command, directory=output_dir, file=file))
def GenerateOutput(target_list, target_dicts, data, params):
per_config_commands = {}
for qualified_target, target in target_dicts.iteritems():
build_file, target_name, toolset = (
gyp.common.ParseQualifiedTarget(qualified_target))
if IsMac(params):
settings = data[build_file]
gyp.xcode_emulation.MergeGlobalXcodeSettingsToSpec(settings, target)
cwd = os.path.dirname(build_file)
AddCommandsForTarget(cwd, target, params, per_config_commands)
output_dir = params['generator_flags']['output_dir']
for configuration_name, commands in per_config_commands.iteritems():
filename = os.path.join(output_dir,
configuration_name,
'compile_commands.json')
gyp.common.EnsureDirExists(filename)
fp = open(filename, 'w')
json.dump(commands, fp=fp, indent=0, check_circular=False)
def PerformBuild(data, configurations, params):
pass

Просмотреть файл

@ -147,7 +147,7 @@ cmd_alink_thin = rm -f $@ && $(AR.$(TOOLSET)) crsT $@ $(filter %.o,$^)
# 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) $(LIBS) -Wl,--end-group
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
@ -1587,7 +1587,7 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
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', 'openbsd', '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)
@ -1754,7 +1754,7 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
# Hash the target name to avoid generating overlong filenames.
cmddigest = hashlib.sha1(command if command else self.target).hexdigest()
intermediate = "%s.intermediate" % cmddigest
intermediate = "%s.intermediate" % (cmddigest)
self.WriteLn('%s: %s' % (' '.join(outputs), intermediate))
self.WriteLn('\t%s' % '@:');
self.WriteLn('%s: %s' % ('.INTERMEDIATE', intermediate))
@ -2055,6 +2055,11 @@ def GenerateOutput(target_list, target_dicts, data, params):
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({
@ -2069,10 +2074,10 @@ def GenerateOutput(target_list, target_dicts, data, params):
'AR.target': GetEnvironFallback(('AR_target', 'AR'), '$(AR)'),
'CXX.target': GetEnvironFallback(('CXX_target', 'CXX'), '$(CXX)'),
'LINK.target': GetEnvironFallback(('LINK_target', 'LINK'), '$(LINK)'),
'CC.host': GetEnvironFallback(('CC_host', 'CC'), 'gcc'),
'AR.host': GetEnvironFallback(('AR_host', 'AR'), 'ar'),
'CXX.host': GetEnvironFallback(('CXX_host', 'CXX'), 'g++'),
'LINK.host': GetEnvironFallback(('LINK_host', 'LINK'), '$(CXX.host)'),
'CC.host': GetEnvironFallback(('CC_host',), 'gcc'),
'AR.host': GetEnvironFallback(('AR_host',), 'ar'),
'CXX.host': GetEnvironFallback(('CXX_host',), 'g++'),
'LINK.host': GetEnvironFallback(('LINK_host',), '$(CXX.host)'),
})
build_file, _, _ = gyp.common.ParseQualifiedTarget(target_list[0])

Просмотреть файл

@ -46,6 +46,8 @@ 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': '',
@ -91,6 +93,7 @@ generator_additional_non_configuration_keys = [
'msvs_target_platform_minversion',
]
generator_filelist_paths = None
# List of precompiled header related keys.
precomp_keys = [
@ -256,6 +259,8 @@ def _ToolSetOrAppend(tools, tool_name, setting, value, only_if_unset=False):
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 and type(value) == list:
@ -269,6 +274,10 @@ def _ToolSetOrAppend(tools, tool_name, setting, value, only_if_unset=False):
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')
@ -285,6 +294,23 @@ def _ConfigFullName(config_name, config_data):
return '%s|%s' % (_ConfigBaseName(config_name, platform_name), platform_name)
def _ConfigWindowsTargetPlatformVersion(config_data, version):
config_ver = config_data.get('msvs_windows_sdk_version')
vers = [config_ver] if config_ver else version.compatible_sdks
for ver in vers:
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):
@ -901,6 +927,8 @@ def _GetMsbuildToolsetOfProject(proj_path, spec, version):
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
@ -1084,6 +1112,7 @@ def _GetMSVSConfigurationType(spec, build_file):
'shared_library': '2', # .dll
'loadable_module': '2', # .dll
'static_library': '4', # .lib
'windows_driver': '5', # .sys
'none': '10', # Utility type
}[spec['type']]
except KeyError:
@ -1268,6 +1297,7 @@ def _GetOutputFilePathAndTool(spec, msbuild):
'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'])
@ -1330,7 +1360,8 @@ def _GetDisabledWarnings(config):
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])
@ -1937,6 +1968,19 @@ def PerformBuild(data, configurations, params):
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.
@ -2622,7 +2666,7 @@ def _GetMSBuildProjectConfigurations(configurations):
return [group]
def _GetMSBuildGlobalProperties(spec, guid, gyp_file_name):
def _GetMSBuildGlobalProperties(spec, version, guid, gyp_file_name):
namespace = os.path.splitext(gyp_file_name)[0]
properties = [
['PropertyGroup', {'Label': 'Globals'},
@ -2637,6 +2681,18 @@ def _GetMSBuildGlobalProperties(spec, guid, gyp_file_name):
os.environ.get('PROCESSOR_ARCHITEW6432') == 'AMD64':
properties[0].append(['PreferredToolArchitecture', 'x64'])
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_winrt'):
properties[0].append(['DefaultLanguage', 'en-US'])
properties[0].append(['AppContainerApplication', 'true'])
@ -2645,33 +2701,45 @@ def _GetMSBuildGlobalProperties(spec, guid, gyp_file_name):
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, version))
if platform_name and msvs_windows_sdk_version:
break
if msvs_windows_sdk_version:
properties[0].append(['WindowsTargetPlatformVersion',
str(msvs_windows_sdk_version)])
elif version.compatible_sdks:
raise GypError('%s requires any SDK of %o version, but non were found' %
(version.description, version.compatible_sdks))
if platform_name == 'ARM':
properties[0].append(['WindowsSDKDesktopARMSupport', 'true'])
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:
if 'msvs_enable_winrt' not in spec :
_AddConditionalProperty(properties, condition, 'CharacterSet',
@ -2770,6 +2838,7 @@ def _ConvertMSVSConfigurationType(config_type):
'1': 'Application',
'2': 'DynamicLibrary',
'4': 'StaticLibrary',
'5': 'Driver',
'10': 'Utility'
}[config_type]
return config_type
@ -2798,6 +2867,9 @@ def _GetMSBuildAttributes(spec, config, build_file):
product_name = spec.get('product_name', '$(ProjectName)')
target_name = prefix + product_name
msbuild_attributes['TargetName'] = target_name
if 'TargetExt' not in msbuild_attributes and 'product_extension' in spec:
ext = spec.get('product_extension')
msbuild_attributes['TargetExt'] = '.' + ext
if spec.get('msvs_external_builder'):
external_out_dir = spec.get('msvs_external_builder_out_dir', '.')
@ -2809,6 +2881,7 @@ def _GetMSBuildAttributes(spec, config, build_file):
'executable': 'Link',
'shared_library': 'Link',
'loadable_module': 'Link',
'windows_driver': 'Link',
'static_library': 'Lib',
}
msbuild_tool = msbuild_tool_map.get(spec['type'])
@ -2851,6 +2924,9 @@ def _GetMSBuildConfigurationGlobalProperties(spec, configurations, build_file):
attributes['OutputDirectory'])
_AddConditionalProperty(properties, condition, 'TargetName',
attributes['TargetName'])
if 'TargetExt' in attributes:
_AddConditionalProperty(properties, condition, 'TargetExt',
attributes['TargetExt'])
if attributes.get('TargetPath'):
_AddConditionalProperty(properties, condition, 'TargetPath',
@ -3203,6 +3279,9 @@ def _GetMSBuildProjectReferences(project):
['ReferenceOutputAssembly', 'false']
]
for config in dependency.spec.get('configurations', {}).itervalues():
if config.get('msvs_use_library_dependency_inputs', 0):
project_ref.append(['UseLibraryDependencyInputs', 'true'])
break
# If it's disabled in any config, turn it off in the reference.
if config.get('msvs_2010_disable_uldi_when_referenced', 0):
project_ref.append(['UseLibraryDependencyInputs', 'false'])
@ -3295,7 +3374,8 @@ def _GenerateMSBuildProject(project, options, version, generator_flags):
}]
content += _GetMSBuildProjectConfigurations(configurations)
content += _GetMSBuildGlobalProperties(spec, project.guid, project_file_name)
content += _GetMSBuildGlobalProperties(spec, version, project.guid,
project_file_name)
content += import_default_section
content += _GetMSBuildConfigurationDetails(spec, project.build_file)
if spec.get('msvs_enable_winphone'):

Просмотреть файл

@ -139,12 +139,18 @@ class Target(object):
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."""
@ -372,14 +378,17 @@ class NinjaWriter(object):
self.target = Target(spec['type'])
self.is_standalone_static_library = bool(
spec.get('standalone_static_library', 0))
# Track if this target contains any C++ files, to decide if gcc or g++
# should be used for linking.
self.uses_cpp = False
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)
@ -416,6 +425,8 @@ class NinjaWriter(object):
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',
@ -441,7 +452,12 @@ class NinjaWriter(object):
# Write out the compilation steps, if any.
link_deps = []
sources = extra_sources + spec.get('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
@ -474,16 +490,17 @@ class NinjaWriter(object):
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)
@ -555,6 +572,9 @@ class NinjaWriter(object):
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:
@ -652,6 +672,7 @@ class NinjaWriter(object):
for var in special_locals:
if '${%s}' % var in argument:
needed_variables.add(var)
needed_variables = sorted(needed_variables)
def cygwin_munge(path):
# pylint: disable=cell-var-from-loop
@ -725,6 +746,7 @@ class NinjaWriter(object):
# 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,
@ -736,7 +758,11 @@ class NinjaWriter(object):
def WriteCopies(self, copies, prebuild, mac_bundle_depends):
outputs = []
env = self.GetToolchainEnv()
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.
@ -758,18 +784,38 @@ class NinjaWriter(object):
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(
generator_default_variables['PRODUCT_DIR'],
self.xcode_settings, map(self.GypPathToNinja, resources)):
output = self.ExpandSpecial(output)
if os.path.splitext(output)[-1] != '.xcassets':
isBinary = self.xcode_settings.IsBinaryOutputFormat(self.config_name)
self.ninja.build(output, 'mac_tool', res,
variables=[('mactool_cmd', 'copy-bundle-resource'), \
('binary', isBinary)])
('env', env), ('binary', isBinary)])
bundle_depends.append(output)
else:
xcassets.append(res)
@ -988,7 +1034,7 @@ class NinjaWriter(object):
obj_ext = self.obj_ext
if ext in ('cc', 'cpp', 'cxx'):
command = 'cxx'
self.uses_cpp = True
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.
@ -1003,7 +1049,7 @@ class NinjaWriter(object):
command = 'objc'
elif self.flavor == 'mac' and ext == 'mm':
command = 'objcxx'
self.uses_cpp = True
self.target.uses_cpp = True
elif self.flavor == 'win' and ext == 'rc':
command = 'rc'
obj_ext = '.res'
@ -1054,16 +1100,16 @@ class NinjaWriter(object):
cmd = map.get(lang)
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)
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],
arch=arch)
compile_deps, arch=arch)
for arch in self.archs]
extra_bindings = []
build_output = output
@ -1082,7 +1128,7 @@ class NinjaWriter(object):
return output
def WriteLinkForArch(self, ninja_file, spec, config_name, config,
link_deps, arch=None):
link_deps, compile_deps, arch=None):
"""Write out a link step. Fills out target.binary. """
command = {
'executable': 'link',
@ -1093,6 +1139,15 @@ class NinjaWriter(object):
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:
@ -1111,6 +1166,8 @@ class NinjaWriter(object):
target.component_objs and
self.msvs_settings.IsUseLibraryDependencyInputs(config_name)):
new_deps = target.component_objs
if target.compile_deps:
order_deps.add(target.compile_deps)
elif self.flavor == 'win' and target.import_lib:
new_deps = [target.import_lib]
elif target.UsesToc(self.flavor):
@ -1128,7 +1185,7 @@ class NinjaWriter(object):
implicit_deps.add(final_output)
extra_bindings = []
if self.uses_cpp and self.flavor != 'win':
if self.target.uses_cpp and self.flavor != 'win':
extra_bindings.append(('ld', '$ldxx'))
output = self.ComputeOutput(spec, arch)
@ -1171,7 +1228,9 @@ class NinjaWriter(object):
rpath = 'lib/'
if self.toolset != 'target':
rpath += self.toolset
ldflags.append(r'-Wl,-rpath=\$$ORIGIN/%s' % rpath)
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))
@ -1245,10 +1304,12 @@ class NinjaWriter(object):
if len(solibs):
extra_bindings.append(('solibs', gyp.common.EncodePOSIXShellList(solibs)))
extra_bindings.append(('solibs',
gyp.common.EncodePOSIXShellList(sorted(solibs))))
ninja_file.build(output, command + command_suffix, link_deps,
implicit=list(implicit_deps),
implicit=sorted(implicit_deps),
order_only=list(order_deps),
variables=extra_bindings)
return linked_binary
@ -1263,7 +1324,7 @@ class NinjaWriter(object):
self.target.type = 'none'
elif spec['type'] == 'static_library':
self.target.binary = self.ComputeOutput(spec)
if (self.flavor not in ('mac', 'openbsd', '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)
@ -1300,7 +1361,8 @@ class NinjaWriter(object):
# needed.
variables=variables)
else:
self.target.binary = 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, is_empty):
@ -1313,9 +1375,13 @@ class NinjaWriter(object):
self.AppendPostbuildVariable(variables, spec, output, self.target.binary,
is_command_start=not package_framework)
if package_framework and not is_empty:
variables.append(('version', self.xcode_settings.GetFrameworkVersion()))
self.ninja.build(output, 'package_framework', mac_bundle_depends,
variables=variables)
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)
@ -1802,7 +1868,7 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params,
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
@ -1828,7 +1894,7 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params,
ld_host = '$cc_host'
ldxx_host = '$cxx_host'
ar_host = 'ar'
ar_host = ar
cc_host = None
cxx_host = None
cc_host_global_setting = None
@ -1883,6 +1949,10 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params,
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]
@ -1893,7 +1963,7 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params,
configs, generator_flags)
cl_paths = gyp.msvs_emulation.GenerateEnvironmentFiles(
toplevel_build, generator_flags, shared_system_includes, OpenOutput)
for arch, path in cl_paths.iteritems():
for arch, path in sorted(cl_paths.iteritems()):
if clang_cl:
# If we have selected clang-cl, use that instead.
path = clang_cl
@ -2216,6 +2286,12 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params,
'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',
@ -2225,6 +2301,11 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params,
description='PACKAGE FRAMEWORK $out, 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',
@ -2329,7 +2410,7 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params,
# 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]])
@ -2345,7 +2426,7 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params,
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()

Просмотреть файл

@ -77,6 +77,7 @@ generator_additional_non_configuration_keys = [
'mac_framework_headers',
'mac_framework_private_headers',
'mac_xctest_bundle',
'mac_xcuitest_bundle',
'xcode_create_dependents_test_runner',
]
@ -87,6 +88,8 @@ generator_extra_sources_for_rules = [
'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([
@ -578,6 +581,26 @@ def PerformBuild(data, configurations, params):
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'
@ -590,6 +613,15 @@ def GenerateOutput(target_list, target_dicts, data, params):
parallel_builds = generator_flags.get('xcode_parallel_builds', True)
serialize_all_tests = \
generator_flags.get('xcode_serialize_all_test_runs', True)
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 = {}
@ -604,9 +636,17 @@ def GenerateOutput(target_list, target_dicts, data, params):
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'})
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'):
@ -648,14 +688,18 @@ def GenerateOutput(target_list, target_dicts, data, params):
'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',
'executable+watch+bundle':
'com.apple.product-type.application.watchapp',
'mac_kernel_extension+bundle': 'com.apple.product-type.kernel-extension',
}
target_properties = {
@ -665,13 +709,19 @@ def GenerateOutput(target_list, target_dicts, data, params):
type = spec['type']
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_xctest:
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 '
@ -703,6 +753,9 @@ def GenerateOutput(target_list, target_dicts, data, params):
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)

Просмотреть файл

@ -28,7 +28,13 @@ 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']
@ -1534,11 +1540,15 @@ class DependencyGraphNode(object):
# dependents.
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
@ -1550,12 +1560,13 @@ class DependencyGraphNode(object):
# 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
# 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 node_dependent.dependencies:
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
@ -1568,7 +1579,7 @@ class DependencyGraphNode(object):
# 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)
in_degree_zeros += [node_dependent]
return list(flat_list)
@ -1724,11 +1735,13 @@ class DependencyGraphNode(object):
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
@ -2479,7 +2492,7 @@ def ValidateTargetType(target, target_dict):
"""
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'. "

Просмотреть файл

@ -17,6 +17,7 @@ import plistlib
import re
import shutil
import string
import struct
import subprocess
import sys
import tempfile
@ -48,6 +49,7 @@ class MacTool(object):
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.
@ -61,11 +63,16 @@ class MacTool(object):
return self._CopyXIBFile(source, dest)
elif extension == '.storyboard':
return self._CopyXIBFile(source, dest)
elif extension == '.strings':
self._CopyStringsFile(source, dest, convert_to_binary)
elif extension == '.strings' and not convert_to_binary:
self._CopyStringsFile(source, dest)
else:
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."""
@ -76,8 +83,26 @@ class MacTool(object):
if os.path.relpath(dest):
dest = os.path.join(base, dest)
args = ['xcrun', 'ibtool', '--errors', '--warnings', '--notices',
'--output-format', 'human-readable-text', '--compile', dest, source]
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)
@ -96,7 +121,7 @@ class MacTool(object):
subprocess.check_call([
'xcrun', 'plutil', '-convert', 'binary1', '-o', dest, dest])
def _CopyStringsFile(self, source, dest, convert_to_binary):
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"
@ -116,16 +141,13 @@ class MacTool(object):
fp.write(s.decode(input_code).encode('UTF-16'))
fp.close()
if convert_to_binary == 'True':
self._ConvertToBinary(dest)
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:
except:
fp.close()
return None
fp.close()
@ -153,7 +175,7 @@ class MacTool(object):
# Go through all the environment variables and replace them as variables in
# the file.
IDENT_RE = re.compile(r'[/\s]')
IDENT_RE = re.compile(r'[_/\s]')
for key in os.environ:
if key.startswith('_'):
continue
@ -228,7 +250,8 @@ class MacTool(object):
def ExecFilterLibtool(self, *cmd_list):
"""Calls libtool and filters out '/path/to/libtool: file: foo.o has no
symbols'."""
libtool_re = re.compile(r'^.*libtool: file: .* 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 ' +
@ -253,6 +276,23 @@ class MacTool(object):
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."""
@ -289,6 +329,23 @@ class MacTool(object):
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.
@ -349,49 +406,28 @@ class MacTool(object):
self._MergePlist(merged_plist, plist)
plistlib.writePlist(merged_plist, output)
def ExecCodeSignBundle(self, key, resource_rules, entitlements, provisioning):
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. copy ResourceRules.plist from the user or the SDK into the bundle,
2. pick the provisioning profile that best match the bundle identifier,
1. pick the provisioning profile that best match the bundle identifier,
and copy it into the bundle as embedded.mobileprovision,
3. copy Entitlements.plist from user or SDK next to the bundle,
4. code sign the bundle.
2. copy Entitlements.plist from user or SDK next to the bundle,
3. code sign the bundle.
"""
resource_rules_path = self._InstallResourceRules(resource_rules)
substitutions, overrides = self._InstallProvisioningProfile(
provisioning, self._GetCFBundleIdentifier())
entitlements_path = self._InstallEntitlements(
entitlements, substitutions, overrides)
subprocess.check_call([
'codesign', '--force', '--sign', key, '--resource-rules',
resource_rules_path, '--entitlements', entitlements_path,
os.path.join(
os.environ['TARGET_BUILD_DIR'],
os.environ['FULL_PRODUCT_NAME'])])
def _InstallResourceRules(self, resource_rules):
"""Installs ResourceRules.plist from user or SDK into the bundle.
Args:
resource_rules: string, optional, path to the ResourceRules.plist file
to use, default to "${SDKROOT}/ResourceRules.plist"
Returns:
Path to the copy of ResourceRules.plist into the bundle.
"""
source_path = resource_rules
target_path = os.path.join(
os.environ['BUILT_PRODUCTS_DIR'],
os.environ['CONTENTS_FOLDER_PATH'],
'ResourceRules.plist')
if not source_path:
source_path = os.path.join(
os.environ['SDKROOT'], 'ResourceRules.plist')
shutil.copy2(source_path, target_path)
return target_path
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.
@ -606,5 +642,71 @@ class MacTool(object):
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:]))

Просмотреть файл

@ -485,8 +485,9 @@ class MsvsSettings(object):
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):
@ -888,7 +889,7 @@ class PrecompiledHeader(object):
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 GetObjDependencies(self, sources, objs, arch):
"""Given a list of sources files and the corresponding object files,
@ -961,6 +962,10 @@ def _ExtractImportantEnvironment(output_of_set):
'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()):
@ -1029,6 +1034,8 @@ def GenerateEnvironmentFiles(toplevel_build_dir, generator_flags,
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.

Просмотреть файл

@ -116,11 +116,19 @@ class WinTool(object):
env = self._GetEnv(arch)
if use_separate_mspdbsrv == 'True':
self._UseSeparateMspdbsrv(env, args)
link = subprocess.Popen([args[0].replace('/', '\\')] + list(args[1:]),
shell=True,
env=env,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
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

Просмотреть файл

@ -147,6 +147,7 @@ class XcodeSettings(object):
# Populated lazily by _SdkPath(). Shared by all XcodeSettings, so cached
# at class-level for efficiency.
_sdk_path_cache = {}
_platform_path_cache = {}
_sdk_root_cache = {}
# Populated lazily by GetExtraPlistItems(). Shared by all XcodeSettings, so
@ -161,6 +162,8 @@ class XcodeSettings(object):
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
@ -221,8 +224,19 @@ class XcodeSettings(object):
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
@ -298,11 +312,62 @@ class XcodeSettings(object):
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(),
@ -322,6 +387,10 @@ class XcodeSettings(object):
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',
@ -352,11 +421,8 @@ class XcodeSettings(object):
"""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') or self.isIOS:
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:
@ -407,8 +473,8 @@ class XcodeSettings(object):
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:
@ -429,7 +495,7 @@ class XcodeSettings(object):
# 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(['xcodebuild', '-version', '-sdk', sdk, infoitem])
return GetStdout(['xcrun', '--sdk', sdk, infoitem])
except:
pass
@ -438,6 +504,14 @@ class XcodeSettings(object):
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('/'):
@ -446,7 +520,7 @@ class XcodeSettings(object):
def _XcodeSdkPath(self, sdk_root):
if sdk_root not in XcodeSettings._sdk_path_cache:
sdk_path = self._GetSdkVersionInfoItem(sdk_root, 'Path')
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
@ -477,6 +551,9 @@ class XcodeSettings(object):
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')
@ -568,6 +645,10 @@ class XcodeSettings(object):
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:
@ -814,7 +895,8 @@ class XcodeSettings(object):
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 and self.spec['type'] != 'loadable_module':
@ -831,19 +913,24 @@ class XcodeSettings(object):
for directory in framework_dirs:
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.
ldflags.append('-lpkstart')
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')
ldflags.append('-Xlinker -rpath '
'-Xlinker @executable_path/../../Frameworks')
self._Appendf(ldflags, 'CLANG_CXX_LIBRARY', '-stdlib=%s')
@ -917,7 +1004,8 @@ class XcodeSettings(object):
self._Test('STRIP_INSTALLED_PRODUCT', 'YES', default='NO')):
default_strip_style = 'debugging'
if self.spec['type'] == 'loadable_module' and 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'
@ -972,13 +1060,25 @@ class XcodeSettings(object):
"""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'):
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 []
return postbuilds
# Warn for any unimplemented signing xcode keys.
unimpl = ['OTHER_CODE_SIGN_FLAGS']
@ -987,12 +1087,41 @@ class XcodeSettings(object):
print 'Warning: Some codesign keys not implemented, ignoring: %s' % (
', '.join(sorted(unimpl)))
return ['%s code-sign-bundle "%s" "%s" "%s" "%s"' % (
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_RESOURCE_RULES_PATH', ''),
settings.get('CODE_SIGN_ENTITLEMENTS', ''),
settings.get('PROVISIONING_PROFILE', ''))
]
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')
@ -1074,25 +1203,37 @@ class XcodeSettings(object):
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()
cache['DTSDKName'] = sdk_root
if xcode >= '0430':
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, 'ProductBuildVersion')
sdk_root, '--show-sdk-build-version')
elif xcode >= '0430':
cache['DTSDKBuild'] = sdk_version
else:
cache['DTSDKBuild'] = cache['BuildMachineOSBuild']
if self.isIOS:
cache['DTPlatformName'] = cache['DTSDKName']
cache['MinimumOSVersion'] = self.xcode_settings[configname].get(
'IPHONEOS_DEPLOYMENT_TARGET')
cache['DTPlatformName'] = sdk_root
cache['DTPlatformVersion'] = sdk_version
if configname.endswith("iphoneos"):
cache['DTPlatformVersion'] = self._GetSdkVersionInfoItem(
sdk_root, 'ProductVersion')
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
@ -1334,7 +1475,10 @@ def IsMacBundle(flavor, spec):
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")' %
@ -1444,14 +1588,16 @@ def _GetXcodeEnv(xcode_settings, built_products_dir, srcroot, configuration,
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(),
@ -1462,12 +1608,16 @@ def _GetXcodeEnv(xcode_settings, built_products_dir, srcroot, configuration,
# written for bundles:
'TARGET_BUILD_DIR' : built_products_dir,
'TEMP_DIR' : '${TMPDIR}',
'XCODE_VERSION_ACTUAL' : XcodeVersion()[0],
}
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()
@ -1478,10 +1628,27 @@ def _GetXcodeEnv(xcode_settings, built_products_dir, srcroot, configuration,
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()
@ -1495,8 +1662,6 @@ def _GetXcodeEnv(xcode_settings, built_products_dir, srcroot, configuration,
sdk_root = xcode_settings._SdkRoot(configuration)
if not sdk_root:
sdk_root = xcode_settings._XcodeSdkPath('')
if sdk_root is None:
sdk_root = ''
env['SDKROOT'] = sdk_root
if not additional_settings:
@ -1612,11 +1777,12 @@ def _AddIOSDeviceConfigurations(targets):
for target_dict in targets.itervalues():
toolset = target_dict['toolset']
configs = target_dict['configurations']
for config_name, config_dict in dict(configs).iteritems():
iphoneos_config_dict = copy.deepcopy(config_dict)
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'] = 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

Просмотреть файл

@ -92,11 +92,16 @@ def _TargetFromSpec(old_spec, params):
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)
@ -138,9 +143,10 @@ def IsValidTargetForWrapper(target_extras, executable_target_pattern, spec):
if target_extras is not None and re.search(target_extras, target_name):
return True
# Otherwise just show executable targets.
if spec.get('type', '') == 'executable' and \
spec.get('product_extension', '') != 'bundle':
# 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:
@ -227,13 +233,26 @@ def CreateWrapper(target_list, target_dicts, data, params):
# 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('$')]

Просмотреть файл

@ -1492,6 +1492,7 @@ class PBXFileReference(XCFileLikeElement, XCContainerPortal, XCRemoteObject):
'icns': 'image.icns',
'java': 'sourcecode.java',
'js': 'sourcecode.javascript',
'kext': 'wrapper.kext',
'm': 'sourcecode.c.objc',
'mm': 'sourcecode.cpp.objcpp',
'nib': 'wrapper.nib',
@ -1944,24 +1945,40 @@ class PBXCopyFilesBuildPhase(XCBuildPhase):
'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_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_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_{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):
@ -1982,14 +1999,61 @@ class PBXCopyFilesBuildPhase(XCBuildPhase):
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
@ -2260,8 +2324,12 @@ class PBXNativeTarget(XCTarget):
'', ''],
'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,
@ -2314,7 +2382,9 @@ class PBXNativeTarget(XCTarget):
force_extension = suffix[1:]
if self._properties['productType'] == \
'com.apple.product-type-bundle.unit.test':
'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:]

Просмотреть файл

@ -118,24 +118,23 @@ def prettyprint_input(lines):
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():