mirror of
https://github.com/zebrajr/node.git
synced 2025-12-06 12:20:27 +01:00
tools: update gyp-next to 0.20.4
PR-URL: https://github.com/nodejs/node/pull/59690 Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
This commit is contained in:
parent
255dd7b62c
commit
ff533758df
|
|
@ -1,5 +1,13 @@
|
|||
# Changelog
|
||||
|
||||
## [0.20.4](https://github.com/nodejs/gyp-next/compare/v0.20.3...v0.20.4) (2025-08-25)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **cli:** remove duplicate usage ([#308](https://github.com/nodejs/gyp-next/issues/308)) ([0996f60](https://github.com/nodejs/gyp-next/commit/0996f60e9bc83ec9d7b31e39bebd23f8dc990130))
|
||||
* **docs:** Add running gyp via uv ([#306](https://github.com/nodejs/gyp-next/issues/306)) ([0e43f61](https://github.com/nodejs/gyp-next/commit/0e43f61da8154f9b460ccba9ce4c0a25d2383ac4))
|
||||
|
||||
## [0.20.3](https://github.com/nodejs/gyp-next/compare/v0.20.2...v0.20.3) (2025-08-20)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -6,8 +6,9 @@ Documents are available at [`./docs`](./docs).
|
|||
__gyp-next__ is [released](https://github.com/nodejs/gyp-next/releases) to the [__Python Packaging Index__](https://pypi.org/project/gyp-next) (PyPI) and can be installed with the command:
|
||||
* `python3 -m pip install gyp-next`
|
||||
|
||||
When used as a command line utility, __gyp-next__ can also be installed with [pipx](https://pypa.github.io/pipx):
|
||||
* `pipx install gyp-next`
|
||||
When used as a command line utility, __gyp-next__ can also be installed with [pipx](https://pypa.github.io/pipx) or [uv](https://docs.astral.sh/uv):
|
||||
* `pipx install gyp-next ` # --or--
|
||||
* `uv tool install gyp-next`
|
||||
```
|
||||
Installing to a new venv 'gyp-next'
|
||||
installed package gyp-next 0.13.0, installed using Python 3.10.6
|
||||
|
|
@ -17,10 +18,11 @@ done! ✨ 🌟 ✨
|
|||
```
|
||||
|
||||
Or to run __gyp-next__ directly without installing it:
|
||||
* `pipx run gyp-next --help`
|
||||
* `pipx run gyp-next --help ` # --or--
|
||||
* `uvx --from=gyp-next gyp --help`
|
||||
```
|
||||
NOTE: running app 'gyp' from 'gyp-next'
|
||||
usage: usage: gyp [options ...] [build_file ...]
|
||||
usage: gyp [options ...] [build_file ...]
|
||||
|
||||
options:
|
||||
-h, --help show this help message and exit
|
||||
|
|
|
|||
|
|
@ -32,18 +32,18 @@ ENTRY_TYPE_GUIDS = {
|
|||
def MakeGuid(name, seed="msvs_new"):
|
||||
"""Returns a GUID for the specified target name.
|
||||
|
||||
Args:
|
||||
name: Target name.
|
||||
seed: Seed for MD5 hash.
|
||||
Returns:
|
||||
A GUID-line string calculated from the name and seed.
|
||||
Args:
|
||||
name: Target name.
|
||||
seed: Seed for MD5 hash.
|
||||
Returns:
|
||||
A GUID-line string calculated from the name and seed.
|
||||
|
||||
This generates something which looks like a GUID, but depends only on the
|
||||
name and seed. This means the same name/seed will always generate the same
|
||||
GUID, so that projects and solutions which refer to each other can explicitly
|
||||
determine the GUID to refer to explicitly. It also means that the GUID will
|
||||
not change when the project for a target is rebuilt.
|
||||
"""
|
||||
This generates something which looks like a GUID, but depends only on the
|
||||
name and seed. This means the same name/seed will always generate the same
|
||||
GUID, so that projects and solutions which refer to each other can explicitly
|
||||
determine the GUID to refer to explicitly. It also means that the GUID will
|
||||
not change when the project for a target is rebuilt.
|
||||
"""
|
||||
# Calculate a MD5 signature for the seed and name.
|
||||
d = hashlib.md5((str(seed) + str(name)).encode("utf-8")).hexdigest().upper()
|
||||
# Convert most of the signature to GUID form (discard the rest)
|
||||
|
|
@ -78,15 +78,15 @@ class MSVSFolder(MSVSSolutionEntry):
|
|||
def __init__(self, path, name=None, entries=None, guid=None, items=None):
|
||||
"""Initializes the folder.
|
||||
|
||||
Args:
|
||||
path: Full path to the folder.
|
||||
name: Name of the folder.
|
||||
entries: List of folder entries to nest inside this folder. May contain
|
||||
Folder or Project objects. May be None, if the folder is empty.
|
||||
guid: GUID to use for folder, if not None.
|
||||
items: List of solution items to include in the folder project. May be
|
||||
None, if the folder does not directly contain items.
|
||||
"""
|
||||
Args:
|
||||
path: Full path to the folder.
|
||||
name: Name of the folder.
|
||||
entries: List of folder entries to nest inside this folder. May contain
|
||||
Folder or Project objects. May be None, if the folder is empty.
|
||||
guid: GUID to use for folder, if not None.
|
||||
items: List of solution items to include in the folder project. May be
|
||||
None, if the folder does not directly contain items.
|
||||
"""
|
||||
if name:
|
||||
self.name = name
|
||||
else:
|
||||
|
|
@ -128,19 +128,19 @@ class MSVSProject(MSVSSolutionEntry):
|
|||
):
|
||||
"""Initializes the project.
|
||||
|
||||
Args:
|
||||
path: Absolute path to the project file.
|
||||
name: Name of project. If None, the name will be the same as the base
|
||||
name of the project file.
|
||||
dependencies: List of other Project objects this project is dependent
|
||||
upon, if not None.
|
||||
guid: GUID to use for project, if not None.
|
||||
spec: Dictionary specifying how to build this project.
|
||||
build_file: Filename of the .gyp file that the vcproj file comes from.
|
||||
config_platform_overrides: optional dict of configuration platforms to
|
||||
used in place of the default for this target.
|
||||
fixpath_prefix: the path used to adjust the behavior of _fixpath
|
||||
"""
|
||||
Args:
|
||||
path: Absolute path to the project file.
|
||||
name: Name of project. If None, the name will be the same as the base
|
||||
name of the project file.
|
||||
dependencies: List of other Project objects this project is dependent
|
||||
upon, if not None.
|
||||
guid: GUID to use for project, if not None.
|
||||
spec: Dictionary specifying how to build this project.
|
||||
build_file: Filename of the .gyp file that the vcproj file comes from.
|
||||
config_platform_overrides: optional dict of configuration platforms to
|
||||
used in place of the default for this target.
|
||||
fixpath_prefix: the path used to adjust the behavior of _fixpath
|
||||
"""
|
||||
self.path = path
|
||||
self.guid = guid
|
||||
self.spec = spec
|
||||
|
|
@ -195,16 +195,16 @@ class MSVSSolution:
|
|||
):
|
||||
"""Initializes the solution.
|
||||
|
||||
Args:
|
||||
path: Path to solution file.
|
||||
version: Format version to emit.
|
||||
entries: List of entries in solution. May contain Folder or Project
|
||||
objects. May be None, if the folder is empty.
|
||||
variants: List of build variant strings. If none, a default list will
|
||||
be used.
|
||||
websiteProperties: Flag to decide if the website properties section
|
||||
is generated.
|
||||
"""
|
||||
Args:
|
||||
path: Path to solution file.
|
||||
version: Format version to emit.
|
||||
entries: List of entries in solution. May contain Folder or Project
|
||||
objects. May be None, if the folder is empty.
|
||||
variants: List of build variant strings. If none, a default list will
|
||||
be used.
|
||||
websiteProperties: Flag to decide if the website properties section
|
||||
is generated.
|
||||
"""
|
||||
self.path = path
|
||||
self.websiteProperties = websiteProperties
|
||||
self.version = version
|
||||
|
|
@ -230,9 +230,9 @@ class MSVSSolution:
|
|||
def Write(self, writer=gyp.common.WriteOnDiff):
|
||||
"""Writes the solution file to disk.
|
||||
|
||||
Raises:
|
||||
IndexError: An entry appears multiple times.
|
||||
"""
|
||||
Raises:
|
||||
IndexError: An entry appears multiple times.
|
||||
"""
|
||||
# Walk the entry tree and collect all the folders and projects.
|
||||
all_entries = set()
|
||||
entries_to_check = self.entries[:]
|
||||
|
|
|
|||
|
|
@ -15,19 +15,19 @@ class Tool:
|
|||
def __init__(self, name, attrs=None):
|
||||
"""Initializes the tool.
|
||||
|
||||
Args:
|
||||
name: Tool name.
|
||||
attrs: Dict of tool attributes; may be None.
|
||||
"""
|
||||
Args:
|
||||
name: Tool name.
|
||||
attrs: Dict of tool attributes; may be None.
|
||||
"""
|
||||
self._attrs = attrs or {}
|
||||
self._attrs["Name"] = name
|
||||
|
||||
def _GetSpecification(self):
|
||||
"""Creates an element for the tool.
|
||||
|
||||
Returns:
|
||||
A new xml.dom.Element for the tool.
|
||||
"""
|
||||
Returns:
|
||||
A new xml.dom.Element for the tool.
|
||||
"""
|
||||
return ["Tool", self._attrs]
|
||||
|
||||
|
||||
|
|
@ -37,10 +37,10 @@ class Filter:
|
|||
def __init__(self, name, contents=None):
|
||||
"""Initializes the folder.
|
||||
|
||||
Args:
|
||||
name: Filter (folder) name.
|
||||
contents: List of filenames and/or Filter objects contained.
|
||||
"""
|
||||
Args:
|
||||
name: Filter (folder) name.
|
||||
contents: List of filenames and/or Filter objects contained.
|
||||
"""
|
||||
self.name = name
|
||||
self.contents = list(contents or [])
|
||||
|
||||
|
|
@ -54,13 +54,13 @@ class Writer:
|
|||
def __init__(self, project_path, version, name, guid=None, platforms=None):
|
||||
"""Initializes the project.
|
||||
|
||||
Args:
|
||||
project_path: Path to the project file.
|
||||
version: Format version to emit.
|
||||
name: Name of the project.
|
||||
guid: GUID to use for project, if not None.
|
||||
platforms: Array of string, the supported platforms. If null, ['Win32']
|
||||
"""
|
||||
Args:
|
||||
project_path: Path to the project file.
|
||||
version: Format version to emit.
|
||||
name: Name of the project.
|
||||
guid: GUID to use for project, if not None.
|
||||
platforms: Array of string, the supported platforms. If null, ['Win32']
|
||||
"""
|
||||
self.project_path = project_path
|
||||
self.version = version
|
||||
self.name = name
|
||||
|
|
@ -84,21 +84,21 @@ class Writer:
|
|||
def AddToolFile(self, path):
|
||||
"""Adds a tool file to the project.
|
||||
|
||||
Args:
|
||||
path: Relative path from project to tool file.
|
||||
"""
|
||||
Args:
|
||||
path: Relative path from project to tool file.
|
||||
"""
|
||||
self.tool_files_section.append(["ToolFile", {"RelativePath": path}])
|
||||
|
||||
def _GetSpecForConfiguration(self, config_type, config_name, attrs, tools):
|
||||
"""Returns the specification for a configuration.
|
||||
|
||||
Args:
|
||||
config_type: Type of configuration node.
|
||||
config_name: Configuration name.
|
||||
attrs: Dict of configuration attributes; may be None.
|
||||
tools: List of tools (strings or Tool objects); may be None.
|
||||
Returns:
|
||||
"""
|
||||
Args:
|
||||
config_type: Type of configuration node.
|
||||
config_name: Configuration name.
|
||||
attrs: Dict of configuration attributes; may be None.
|
||||
tools: List of tools (strings or Tool objects); may be None.
|
||||
Returns:
|
||||
"""
|
||||
# Handle defaults
|
||||
if not attrs:
|
||||
attrs = {}
|
||||
|
|
@ -122,23 +122,23 @@ class Writer:
|
|||
def AddConfig(self, name, attrs=None, tools=None):
|
||||
"""Adds a configuration to the project.
|
||||
|
||||
Args:
|
||||
name: Configuration name.
|
||||
attrs: Dict of configuration attributes; may be None.
|
||||
tools: List of tools (strings or Tool objects); may be None.
|
||||
"""
|
||||
Args:
|
||||
name: Configuration name.
|
||||
attrs: Dict of configuration attributes; may be None.
|
||||
tools: List of tools (strings or Tool objects); may be None.
|
||||
"""
|
||||
spec = self._GetSpecForConfiguration("Configuration", name, attrs, tools)
|
||||
self.configurations_section.append(spec)
|
||||
|
||||
def _AddFilesToNode(self, parent, files):
|
||||
"""Adds files and/or filters to the parent node.
|
||||
|
||||
Args:
|
||||
parent: Destination node
|
||||
files: A list of Filter objects and/or relative paths to files.
|
||||
Args:
|
||||
parent: Destination node
|
||||
files: A list of Filter objects and/or relative paths to files.
|
||||
|
||||
Will call itself recursively, if the files list contains Filter objects.
|
||||
"""
|
||||
Will call itself recursively, if the files list contains Filter objects.
|
||||
"""
|
||||
for f in files:
|
||||
if isinstance(f, Filter):
|
||||
node = ["Filter", {"Name": f.name}]
|
||||
|
|
@ -151,13 +151,13 @@ class Writer:
|
|||
def AddFiles(self, files):
|
||||
"""Adds files to the project.
|
||||
|
||||
Args:
|
||||
files: A list of Filter objects and/or relative paths to files.
|
||||
Args:
|
||||
files: A list of Filter objects and/or relative paths to files.
|
||||
|
||||
This makes a copy of the file/filter tree at the time of this call. If you
|
||||
later add files to a Filter object which was passed into a previous call
|
||||
to AddFiles(), it will not be reflected in this project.
|
||||
"""
|
||||
This makes a copy of the file/filter tree at the time of this call. If you
|
||||
later add files to a Filter object which was passed into a previous call
|
||||
to AddFiles(), it will not be reflected in this project.
|
||||
"""
|
||||
self._AddFilesToNode(self.files_section, files)
|
||||
# TODO(rspangler) This also doesn't handle adding files to an existing
|
||||
# filter. That is, it doesn't merge the trees.
|
||||
|
|
@ -165,15 +165,15 @@ class Writer:
|
|||
def AddFileConfig(self, path, config, attrs=None, tools=None):
|
||||
"""Adds a configuration to a file.
|
||||
|
||||
Args:
|
||||
path: Relative path to the file.
|
||||
config: Name of configuration to add.
|
||||
attrs: Dict of configuration attributes; may be None.
|
||||
tools: List of tools (strings or Tool objects); may be None.
|
||||
Args:
|
||||
path: Relative path to the file.
|
||||
config: Name of configuration to add.
|
||||
attrs: Dict of configuration attributes; may be None.
|
||||
tools: List of tools (strings or Tool objects); may be None.
|
||||
|
||||
Raises:
|
||||
ValueError: Relative path does not match any file added via AddFiles().
|
||||
"""
|
||||
Raises:
|
||||
ValueError: Relative path does not match any file added via AddFiles().
|
||||
"""
|
||||
# Find the file node with the right relative path
|
||||
parent = self.files_dict.get(path)
|
||||
if not parent:
|
||||
|
|
|
|||
|
|
@ -35,10 +35,10 @@ _msbuild_name_of_tool = {}
|
|||
class _Tool:
|
||||
"""Represents a tool used by MSVS or MSBuild.
|
||||
|
||||
Attributes:
|
||||
msvs_name: The name of the tool in MSVS.
|
||||
msbuild_name: The name of the tool in MSBuild.
|
||||
"""
|
||||
Attributes:
|
||||
msvs_name: The name of the tool in MSVS.
|
||||
msbuild_name: The name of the tool in MSBuild.
|
||||
"""
|
||||
|
||||
def __init__(self, msvs_name, msbuild_name):
|
||||
self.msvs_name = msvs_name
|
||||
|
|
@ -48,11 +48,11 @@ class _Tool:
|
|||
def _AddTool(tool):
|
||||
"""Adds a tool to the four dictionaries used to process settings.
|
||||
|
||||
This only defines the tool. Each setting also needs to be added.
|
||||
This only defines the tool. Each setting also needs to be added.
|
||||
|
||||
Args:
|
||||
tool: The _Tool object to be added.
|
||||
"""
|
||||
Args:
|
||||
tool: The _Tool object to be added.
|
||||
"""
|
||||
_msvs_validators[tool.msvs_name] = {}
|
||||
_msbuild_validators[tool.msbuild_name] = {}
|
||||
_msvs_to_msbuild_converters[tool.msvs_name] = {}
|
||||
|
|
@ -70,35 +70,35 @@ class _Type:
|
|||
def ValidateMSVS(self, value):
|
||||
"""Verifies that the value is legal for MSVS.
|
||||
|
||||
Args:
|
||||
value: the value to check for this type.
|
||||
Args:
|
||||
value: the value to check for this type.
|
||||
|
||||
Raises:
|
||||
ValueError if value is not valid for MSVS.
|
||||
"""
|
||||
Raises:
|
||||
ValueError if value is not valid for MSVS.
|
||||
"""
|
||||
|
||||
def ValidateMSBuild(self, value):
|
||||
"""Verifies that the value is legal for MSBuild.
|
||||
|
||||
Args:
|
||||
value: the value to check for this type.
|
||||
Args:
|
||||
value: the value to check for this type.
|
||||
|
||||
Raises:
|
||||
ValueError if value is not valid for MSBuild.
|
||||
"""
|
||||
Raises:
|
||||
ValueError if value is not valid for MSBuild.
|
||||
"""
|
||||
|
||||
def ConvertToMSBuild(self, value):
|
||||
"""Returns the MSBuild equivalent of the MSVS value given.
|
||||
|
||||
Args:
|
||||
value: the MSVS value to convert.
|
||||
Args:
|
||||
value: the MSVS value to convert.
|
||||
|
||||
Returns:
|
||||
the MSBuild equivalent.
|
||||
Returns:
|
||||
the MSBuild equivalent.
|
||||
|
||||
Raises:
|
||||
ValueError if value is not valid.
|
||||
"""
|
||||
Raises:
|
||||
ValueError if value is not valid.
|
||||
"""
|
||||
return value
|
||||
|
||||
|
||||
|
|
@ -178,15 +178,15 @@ class _Integer(_Type):
|
|||
class _Enumeration(_Type):
|
||||
"""Type of settings that is an enumeration.
|
||||
|
||||
In MSVS, the values are indexes like '0', '1', and '2'.
|
||||
MSBuild uses text labels that are more representative, like 'Win32'.
|
||||
In MSVS, the values are indexes like '0', '1', and '2'.
|
||||
MSBuild uses text labels that are more representative, like 'Win32'.
|
||||
|
||||
Constructor args:
|
||||
label_list: an array of MSBuild labels that correspond to the MSVS index.
|
||||
In the rare cases where MSVS has skipped an index value, None is
|
||||
used in the array to indicate the unused spot.
|
||||
new: an array of labels that are new to MSBuild.
|
||||
"""
|
||||
Constructor args:
|
||||
label_list: an array of MSBuild labels that correspond to the MSVS index.
|
||||
In the rare cases where MSVS has skipped an index value, None is
|
||||
used in the array to indicate the unused spot.
|
||||
new: an array of labels that are new to MSBuild.
|
||||
"""
|
||||
|
||||
def __init__(self, label_list, new=None):
|
||||
_Type.__init__(self)
|
||||
|
|
@ -234,23 +234,23 @@ _newly_boolean = _Enumeration(["", "false", "true"])
|
|||
def _Same(tool, name, setting_type):
|
||||
"""Defines a setting that has the same name in MSVS and MSBuild.
|
||||
|
||||
Args:
|
||||
tool: a dictionary that gives the names of the tool for MSVS and MSBuild.
|
||||
name: the name of the setting.
|
||||
setting_type: the type of this setting.
|
||||
"""
|
||||
Args:
|
||||
tool: a dictionary that gives the names of the tool for MSVS and MSBuild.
|
||||
name: the name of the setting.
|
||||
setting_type: the type of this setting.
|
||||
"""
|
||||
_Renamed(tool, name, name, setting_type)
|
||||
|
||||
|
||||
def _Renamed(tool, msvs_name, msbuild_name, setting_type):
|
||||
"""Defines a setting for which the name has changed.
|
||||
|
||||
Args:
|
||||
tool: a dictionary that gives the names of the tool for MSVS and MSBuild.
|
||||
msvs_name: the name of the MSVS setting.
|
||||
msbuild_name: the name of the MSBuild setting.
|
||||
setting_type: the type of this setting.
|
||||
"""
|
||||
Args:
|
||||
tool: a dictionary that gives the names of the tool for MSVS and MSBuild.
|
||||
msvs_name: the name of the MSVS setting.
|
||||
msbuild_name: the name of the MSBuild setting.
|
||||
setting_type: the type of this setting.
|
||||
"""
|
||||
|
||||
def _Translate(value, msbuild_settings):
|
||||
msbuild_tool_settings = _GetMSBuildToolSettings(msbuild_settings, tool)
|
||||
|
|
@ -272,13 +272,13 @@ def _MovedAndRenamed(
|
|||
):
|
||||
"""Defines a setting that may have moved to a new section.
|
||||
|
||||
Args:
|
||||
tool: a dictionary that gives the names of the tool for MSVS and MSBuild.
|
||||
msvs_settings_name: the MSVS name of the setting.
|
||||
msbuild_tool_name: the name of the MSBuild tool to place the setting under.
|
||||
msbuild_settings_name: the MSBuild name of the setting.
|
||||
setting_type: the type of this setting.
|
||||
"""
|
||||
Args:
|
||||
tool: a dictionary that gives the names of the tool for MSVS and MSBuild.
|
||||
msvs_settings_name: the MSVS name of the setting.
|
||||
msbuild_tool_name: the name of the MSBuild tool to place the setting under.
|
||||
msbuild_settings_name: the MSBuild name of the setting.
|
||||
setting_type: the type of this setting.
|
||||
"""
|
||||
|
||||
def _Translate(value, msbuild_settings):
|
||||
tool_settings = msbuild_settings.setdefault(msbuild_tool_name, {})
|
||||
|
|
@ -293,11 +293,11 @@ def _MovedAndRenamed(
|
|||
def _MSVSOnly(tool, name, setting_type):
|
||||
"""Defines a setting that is only found in MSVS.
|
||||
|
||||
Args:
|
||||
tool: a dictionary that gives the names of the tool for MSVS and MSBuild.
|
||||
name: the name of the setting.
|
||||
setting_type: the type of this setting.
|
||||
"""
|
||||
Args:
|
||||
tool: a dictionary that gives the names of the tool for MSVS and MSBuild.
|
||||
name: the name of the setting.
|
||||
setting_type: the type of this setting.
|
||||
"""
|
||||
|
||||
def _Translate(unused_value, unused_msbuild_settings):
|
||||
# Since this is for MSVS only settings, no translation will happen.
|
||||
|
|
@ -310,11 +310,11 @@ def _MSVSOnly(tool, name, setting_type):
|
|||
def _MSBuildOnly(tool, name, setting_type):
|
||||
"""Defines a setting that is only found in MSBuild.
|
||||
|
||||
Args:
|
||||
tool: a dictionary that gives the names of the tool for MSVS and MSBuild.
|
||||
name: the name of the setting.
|
||||
setting_type: the type of this setting.
|
||||
"""
|
||||
Args:
|
||||
tool: a dictionary that gives the names of the tool for MSVS and MSBuild.
|
||||
name: the name of the setting.
|
||||
setting_type: the type of this setting.
|
||||
"""
|
||||
|
||||
def _Translate(value, msbuild_settings):
|
||||
# Let msbuild-only properties get translated as-is from msvs_settings.
|
||||
|
|
@ -328,11 +328,11 @@ def _MSBuildOnly(tool, name, setting_type):
|
|||
def _ConvertedToAdditionalOption(tool, msvs_name, flag):
|
||||
"""Defines a setting that's handled via a command line option in MSBuild.
|
||||
|
||||
Args:
|
||||
tool: a dictionary that gives the names of the tool for MSVS and MSBuild.
|
||||
msvs_name: the name of the MSVS setting that if 'true' becomes a flag
|
||||
flag: the flag to insert at the end of the AdditionalOptions
|
||||
"""
|
||||
Args:
|
||||
tool: a dictionary that gives the names of the tool for MSVS and MSBuild.
|
||||
msvs_name: the name of the MSVS setting that if 'true' becomes a flag
|
||||
flag: the flag to insert at the end of the AdditionalOptions
|
||||
"""
|
||||
|
||||
def _Translate(value, msbuild_settings):
|
||||
if value == "true":
|
||||
|
|
@ -384,15 +384,15 @@ _EXCLUDED_SUFFIX_RE = re.compile("^(.*)_excluded$")
|
|||
def _ValidateExclusionSetting(setting, settings, error_msg, stderr=sys.stderr):
|
||||
"""Verify that 'setting' is valid if it is generated from an exclusion list.
|
||||
|
||||
If the setting appears to be generated from an exclusion list, the root name
|
||||
is checked.
|
||||
If the setting appears to be generated from an exclusion list, the root name
|
||||
is checked.
|
||||
|
||||
Args:
|
||||
setting: A string that is the setting name to validate
|
||||
settings: A dictionary where the keys are valid settings
|
||||
error_msg: The message to emit in the event of error
|
||||
stderr: The stream receiving the error messages.
|
||||
"""
|
||||
Args:
|
||||
setting: A string that is the setting name to validate
|
||||
settings: A dictionary where the keys are valid settings
|
||||
error_msg: The message to emit in the event of error
|
||||
stderr: The stream receiving the error messages.
|
||||
"""
|
||||
# This may be unrecognized because it's an exclusion list. If the
|
||||
# setting name has the _excluded suffix, then check the root name.
|
||||
unrecognized = True
|
||||
|
|
@ -408,11 +408,11 @@ def _ValidateExclusionSetting(setting, settings, error_msg, stderr=sys.stderr):
|
|||
def FixVCMacroSlashes(s):
|
||||
"""Replace macros which have excessive following slashes.
|
||||
|
||||
These macros are known to have a built-in trailing slash. Furthermore, many
|
||||
scripts hiccup on processing paths with extra slashes in the middle.
|
||||
These macros are known to have a built-in trailing slash. Furthermore, many
|
||||
scripts hiccup on processing paths with extra slashes in the middle.
|
||||
|
||||
This list is probably not exhaustive. Add as needed.
|
||||
"""
|
||||
This list is probably not exhaustive. Add as needed.
|
||||
"""
|
||||
if "$" in s:
|
||||
s = fix_vc_macro_slashes_regex.sub(r"\1", s)
|
||||
return s
|
||||
|
|
@ -421,8 +421,8 @@ def FixVCMacroSlashes(s):
|
|||
def ConvertVCMacrosToMSBuild(s):
|
||||
"""Convert the MSVS macros found in the string to the MSBuild equivalent.
|
||||
|
||||
This list is probably not exhaustive. Add as needed.
|
||||
"""
|
||||
This list is probably not exhaustive. Add as needed.
|
||||
"""
|
||||
if "$" in s:
|
||||
replace_map = {
|
||||
"$(ConfigurationName)": "$(Configuration)",
|
||||
|
|
@ -444,16 +444,16 @@ def ConvertVCMacrosToMSBuild(s):
|
|||
def ConvertToMSBuildSettings(msvs_settings, stderr=sys.stderr):
|
||||
"""Converts MSVS settings (VS2008 and earlier) to MSBuild settings (VS2010+).
|
||||
|
||||
Args:
|
||||
msvs_settings: A dictionary. The key is the tool name. The values are
|
||||
themselves dictionaries of settings and their values.
|
||||
stderr: The stream receiving the error messages.
|
||||
Args:
|
||||
msvs_settings: A dictionary. The key is the tool name. The values are
|
||||
themselves dictionaries of settings and their values.
|
||||
stderr: The stream receiving the error messages.
|
||||
|
||||
Returns:
|
||||
A dictionary of MSBuild settings. The key is either the MSBuild tool name
|
||||
or the empty string (for the global settings). The values are themselves
|
||||
dictionaries of settings and their values.
|
||||
"""
|
||||
Returns:
|
||||
A dictionary of MSBuild settings. The key is either the MSBuild tool name
|
||||
or the empty string (for the global settings). The values are themselves
|
||||
dictionaries of settings and their values.
|
||||
"""
|
||||
msbuild_settings = {}
|
||||
for msvs_tool_name, msvs_tool_settings in msvs_settings.items():
|
||||
if msvs_tool_name in _msvs_to_msbuild_converters:
|
||||
|
|
@ -492,36 +492,36 @@ def ConvertToMSBuildSettings(msvs_settings, stderr=sys.stderr):
|
|||
def ValidateMSVSSettings(settings, stderr=sys.stderr):
|
||||
"""Validates that the names of the settings are valid for MSVS.
|
||||
|
||||
Args:
|
||||
settings: A dictionary. The key is the tool name. The values are
|
||||
themselves dictionaries of settings and their values.
|
||||
stderr: The stream receiving the error messages.
|
||||
"""
|
||||
Args:
|
||||
settings: A dictionary. The key is the tool name. The values are
|
||||
themselves dictionaries of settings and their values.
|
||||
stderr: The stream receiving the error messages.
|
||||
"""
|
||||
_ValidateSettings(_msvs_validators, settings, stderr)
|
||||
|
||||
|
||||
def ValidateMSBuildSettings(settings, stderr=sys.stderr):
|
||||
"""Validates that the names of the settings are valid for MSBuild.
|
||||
|
||||
Args:
|
||||
settings: A dictionary. The key is the tool name. The values are
|
||||
themselves dictionaries of settings and their values.
|
||||
stderr: The stream receiving the error messages.
|
||||
"""
|
||||
Args:
|
||||
settings: A dictionary. The key is the tool name. The values are
|
||||
themselves dictionaries of settings and their values.
|
||||
stderr: The stream receiving the error messages.
|
||||
"""
|
||||
_ValidateSettings(_msbuild_validators, settings, stderr)
|
||||
|
||||
|
||||
def _ValidateSettings(validators, settings, stderr):
|
||||
"""Validates that the settings are valid for MSBuild or MSVS.
|
||||
|
||||
We currently only validate the names of the settings, not their values.
|
||||
We currently only validate the names of the settings, not their values.
|
||||
|
||||
Args:
|
||||
validators: A dictionary of tools and their validators.
|
||||
settings: A dictionary. The key is the tool name. The values are
|
||||
themselves dictionaries of settings and their values.
|
||||
stderr: The stream receiving the error messages.
|
||||
"""
|
||||
Args:
|
||||
validators: A dictionary of tools and their validators.
|
||||
settings: A dictionary. The key is the tool name. The values are
|
||||
themselves dictionaries of settings and their values.
|
||||
stderr: The stream receiving the error messages.
|
||||
"""
|
||||
for tool_name in settings:
|
||||
if tool_name in validators:
|
||||
tool_validators = validators[tool_name]
|
||||
|
|
@ -637,7 +637,9 @@ _Same(
|
|||
),
|
||||
) # /RTC1
|
||||
_Same(
|
||||
_compile, "BrowseInformation", _Enumeration(["false", "true", "true"]) # /FR
|
||||
_compile,
|
||||
"BrowseInformation",
|
||||
_Enumeration(["false", "true", "true"]), # /FR
|
||||
) # /Fr
|
||||
_Same(
|
||||
_compile,
|
||||
|
|
@ -695,7 +697,9 @@ _Same(
|
|||
_Enumeration(["false", "Sync", "Async"], new=["SyncCThrow"]), # /EHsc # /EHa
|
||||
) # /EHs
|
||||
_Same(
|
||||
_compile, "FavorSizeOrSpeed", _Enumeration(["Neither", "Speed", "Size"]) # /Ot
|
||||
_compile,
|
||||
"FavorSizeOrSpeed",
|
||||
_Enumeration(["Neither", "Speed", "Size"]), # /Ot
|
||||
) # /Os
|
||||
_Same(
|
||||
_compile,
|
||||
|
|
@ -908,7 +912,9 @@ _target_machine_enumeration = _Enumeration(
|
|||
) # /MACHINE:X64
|
||||
|
||||
_Same(
|
||||
_link, "AssemblyDebug", _Enumeration(["", "true", "false"]) # /ASSEMBLYDEBUG
|
||||
_link,
|
||||
"AssemblyDebug",
|
||||
_Enumeration(["", "true", "false"]), # /ASSEMBLYDEBUG
|
||||
) # /ASSEMBLYDEBUG:DISABLE
|
||||
_Same(
|
||||
_link,
|
||||
|
|
@ -1158,17 +1164,23 @@ _Renamed(_midl, "ValidateParameters", "ValidateAllParameters", _boolean) # /rob
|
|||
_MSBuildOnly(_midl, "ApplicationConfigurationMode", _boolean) # /app_config
|
||||
_MSBuildOnly(_midl, "ClientStubFile", _file_name) # /cstub
|
||||
_MSBuildOnly(
|
||||
_midl, "GenerateClientFiles", _Enumeration([], new=["Stub", "None"]) # /client stub
|
||||
_midl,
|
||||
"GenerateClientFiles",
|
||||
_Enumeration([], new=["Stub", "None"]), # /client stub
|
||||
) # /client none
|
||||
_MSBuildOnly(
|
||||
_midl, "GenerateServerFiles", _Enumeration([], new=["Stub", "None"]) # /client stub
|
||||
_midl,
|
||||
"GenerateServerFiles",
|
||||
_Enumeration([], new=["Stub", "None"]), # /client stub
|
||||
) # /client none
|
||||
_MSBuildOnly(_midl, "LocaleID", _integer) # /lcid DECIMAL
|
||||
_MSBuildOnly(_midl, "ServerStubFile", _file_name) # /sstub
|
||||
_MSBuildOnly(_midl, "SuppressCompilerWarnings", _boolean) # /no_warn
|
||||
_MSBuildOnly(_midl, "TrackerLogDirectory", _folder_name)
|
||||
_MSBuildOnly(
|
||||
_midl, "TypeLibFormat", _Enumeration([], new=["NewFormat", "OldFormat"]) # /newtlb
|
||||
_midl,
|
||||
"TypeLibFormat",
|
||||
_Enumeration([], new=["NewFormat", "OldFormat"]), # /newtlb
|
||||
) # /oldtlb
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1143,47 +1143,47 @@ class TestSequenceFunctions(unittest.TestCase):
|
|||
def testConvertToMSBuildSettings_actual(self):
|
||||
"""Tests the conversion of an actual project.
|
||||
|
||||
A VS2008 project with most of the options defined was created through the
|
||||
VS2008 IDE. It was then converted to VS2010. The tool settings found in
|
||||
the .vcproj and .vcxproj files were converted to the two dictionaries
|
||||
msvs_settings and expected_msbuild_settings.
|
||||
A VS2008 project with most of the options defined was created through the
|
||||
VS2008 IDE. It was then converted to VS2010. The tool settings found in
|
||||
the .vcproj and .vcxproj files were converted to the two dictionaries
|
||||
msvs_settings and expected_msbuild_settings.
|
||||
|
||||
Note that for many settings, the VS2010 converter adds macros like
|
||||
%(AdditionalIncludeDirectories) to make sure than inherited values are
|
||||
included. Since the Gyp projects we generate do not use inheritance,
|
||||
we removed these macros. They were:
|
||||
ClCompile:
|
||||
AdditionalIncludeDirectories: ';%(AdditionalIncludeDirectories)'
|
||||
AdditionalOptions: ' %(AdditionalOptions)'
|
||||
AdditionalUsingDirectories: ';%(AdditionalUsingDirectories)'
|
||||
DisableSpecificWarnings: ';%(DisableSpecificWarnings)',
|
||||
ForcedIncludeFiles: ';%(ForcedIncludeFiles)',
|
||||
ForcedUsingFiles: ';%(ForcedUsingFiles)',
|
||||
PreprocessorDefinitions: ';%(PreprocessorDefinitions)',
|
||||
UndefinePreprocessorDefinitions:
|
||||
';%(UndefinePreprocessorDefinitions)',
|
||||
Link:
|
||||
AdditionalDependencies: ';%(AdditionalDependencies)',
|
||||
AdditionalLibraryDirectories: ';%(AdditionalLibraryDirectories)',
|
||||
AdditionalManifestDependencies:
|
||||
';%(AdditionalManifestDependencies)',
|
||||
AdditionalOptions: ' %(AdditionalOptions)',
|
||||
AddModuleNamesToAssembly: ';%(AddModuleNamesToAssembly)',
|
||||
AssemblyLinkResource: ';%(AssemblyLinkResource)',
|
||||
DelayLoadDLLs: ';%(DelayLoadDLLs)',
|
||||
EmbedManagedResourceFile: ';%(EmbedManagedResourceFile)',
|
||||
ForceSymbolReferences: ';%(ForceSymbolReferences)',
|
||||
IgnoreSpecificDefaultLibraries:
|
||||
';%(IgnoreSpecificDefaultLibraries)',
|
||||
ResourceCompile:
|
||||
AdditionalIncludeDirectories: ';%(AdditionalIncludeDirectories)',
|
||||
AdditionalOptions: ' %(AdditionalOptions)',
|
||||
PreprocessorDefinitions: ';%(PreprocessorDefinitions)',
|
||||
Manifest:
|
||||
AdditionalManifestFiles: ';%(AdditionalManifestFiles)',
|
||||
AdditionalOptions: ' %(AdditionalOptions)',
|
||||
InputResourceManifests: ';%(InputResourceManifests)',
|
||||
"""
|
||||
Note that for many settings, the VS2010 converter adds macros like
|
||||
%(AdditionalIncludeDirectories) to make sure than inherited values are
|
||||
included. Since the Gyp projects we generate do not use inheritance,
|
||||
we removed these macros. They were:
|
||||
ClCompile:
|
||||
AdditionalIncludeDirectories: ';%(AdditionalIncludeDirectories)'
|
||||
AdditionalOptions: ' %(AdditionalOptions)'
|
||||
AdditionalUsingDirectories: ';%(AdditionalUsingDirectories)'
|
||||
DisableSpecificWarnings: ';%(DisableSpecificWarnings)',
|
||||
ForcedIncludeFiles: ';%(ForcedIncludeFiles)',
|
||||
ForcedUsingFiles: ';%(ForcedUsingFiles)',
|
||||
PreprocessorDefinitions: ';%(PreprocessorDefinitions)',
|
||||
UndefinePreprocessorDefinitions:
|
||||
';%(UndefinePreprocessorDefinitions)',
|
||||
Link:
|
||||
AdditionalDependencies: ';%(AdditionalDependencies)',
|
||||
AdditionalLibraryDirectories: ';%(AdditionalLibraryDirectories)',
|
||||
AdditionalManifestDependencies:
|
||||
';%(AdditionalManifestDependencies)',
|
||||
AdditionalOptions: ' %(AdditionalOptions)',
|
||||
AddModuleNamesToAssembly: ';%(AddModuleNamesToAssembly)',
|
||||
AssemblyLinkResource: ';%(AssemblyLinkResource)',
|
||||
DelayLoadDLLs: ';%(DelayLoadDLLs)',
|
||||
EmbedManagedResourceFile: ';%(EmbedManagedResourceFile)',
|
||||
ForceSymbolReferences: ';%(ForceSymbolReferences)',
|
||||
IgnoreSpecificDefaultLibraries:
|
||||
';%(IgnoreSpecificDefaultLibraries)',
|
||||
ResourceCompile:
|
||||
AdditionalIncludeDirectories: ';%(AdditionalIncludeDirectories)',
|
||||
AdditionalOptions: ' %(AdditionalOptions)',
|
||||
PreprocessorDefinitions: ';%(PreprocessorDefinitions)',
|
||||
Manifest:
|
||||
AdditionalManifestFiles: ';%(AdditionalManifestFiles)',
|
||||
AdditionalOptions: ' %(AdditionalOptions)',
|
||||
InputResourceManifests: ';%(InputResourceManifests)',
|
||||
"""
|
||||
msvs_settings = {
|
||||
"VCCLCompilerTool": {
|
||||
"AdditionalIncludeDirectories": "dir1",
|
||||
|
|
@ -1346,8 +1346,7 @@ class TestSequenceFunctions(unittest.TestCase):
|
|||
"EmbedManifest": "false",
|
||||
"GenerateCatalogFiles": "true",
|
||||
"InputResourceManifests": "asfsfdafs",
|
||||
"ManifestResourceFile":
|
||||
"$(IntDir)\\$(TargetFileName).embed.manifest.resfdsf",
|
||||
"ManifestResourceFile": "$(IntDir)\\$(TargetFileName).embed.manifest.resfdsf", # noqa: E501
|
||||
"OutputManifestFile": "$(TargetPath).manifestdfs",
|
||||
"RegistrarScriptFile": "sdfsfd",
|
||||
"ReplacementsFile": "sdffsd",
|
||||
|
|
@ -1531,8 +1530,7 @@ class TestSequenceFunctions(unittest.TestCase):
|
|||
"LinkIncremental": "",
|
||||
},
|
||||
"ManifestResourceCompile": {
|
||||
"ResourceOutputFileName":
|
||||
"$(IntDir)$(TargetFileName).embed.manifest.resfdsf"
|
||||
"ResourceOutputFileName": "$(IntDir)$(TargetFileName).embed.manifest.resfdsf" # noqa: E501
|
||||
},
|
||||
}
|
||||
self.maxDiff = 9999 # on failure display a long diff
|
||||
|
|
|
|||
|
|
@ -13,10 +13,10 @@ class Writer:
|
|||
def __init__(self, tool_file_path, name):
|
||||
"""Initializes the tool file.
|
||||
|
||||
Args:
|
||||
tool_file_path: Path to the tool file.
|
||||
name: Name of the tool file.
|
||||
"""
|
||||
Args:
|
||||
tool_file_path: Path to the tool file.
|
||||
name: Name of the tool file.
|
||||
"""
|
||||
self.tool_file_path = tool_file_path
|
||||
self.name = name
|
||||
self.rules_section = ["Rules"]
|
||||
|
|
@ -26,14 +26,14 @@ class Writer:
|
|||
):
|
||||
"""Adds a rule to the tool file.
|
||||
|
||||
Args:
|
||||
name: Name of the rule.
|
||||
description: Description of the rule.
|
||||
cmd: Command line of the rule.
|
||||
additional_dependencies: other files which may trigger the rule.
|
||||
outputs: outputs of the rule.
|
||||
extensions: extensions handled by the rule.
|
||||
"""
|
||||
Args:
|
||||
name: Name of the rule.
|
||||
description: Description of the rule.
|
||||
cmd: Command line of the rule.
|
||||
additional_dependencies: other files which may trigger the rule.
|
||||
outputs: outputs of the rule.
|
||||
extensions: extensions handled by the rule.
|
||||
"""
|
||||
rule = [
|
||||
"CustomBuildRule",
|
||||
{
|
||||
|
|
|
|||
|
|
@ -15,11 +15,11 @@ from gyp import easy_xml
|
|||
|
||||
def _FindCommandInPath(command):
|
||||
"""If there are no slashes in the command given, this function
|
||||
searches the PATH env to find the given command, and converts it
|
||||
to an absolute path. We have to do this because MSVS is looking
|
||||
for an actual file to launch a debugger on, not just a command
|
||||
line. Note that this happens at GYP time, so anything needing to
|
||||
be built needs to have a full path."""
|
||||
searches the PATH env to find the given command, and converts it
|
||||
to an absolute path. We have to do this because MSVS is looking
|
||||
for an actual file to launch a debugger on, not just a command
|
||||
line. Note that this happens at GYP time, so anything needing to
|
||||
be built needs to have a full path."""
|
||||
if "/" in command or "\\" in command:
|
||||
# If the command already has path elements (either relative or
|
||||
# absolute), then assume it is constructed properly.
|
||||
|
|
@ -58,11 +58,11 @@ class Writer:
|
|||
def __init__(self, user_file_path, version, name):
|
||||
"""Initializes the user file.
|
||||
|
||||
Args:
|
||||
user_file_path: Path to the user file.
|
||||
version: Version info.
|
||||
name: Name of the user file.
|
||||
"""
|
||||
Args:
|
||||
user_file_path: Path to the user file.
|
||||
version: Version info.
|
||||
name: Name of the user file.
|
||||
"""
|
||||
self.user_file_path = user_file_path
|
||||
self.version = version
|
||||
self.name = name
|
||||
|
|
@ -71,9 +71,9 @@ class Writer:
|
|||
def AddConfig(self, name):
|
||||
"""Adds a configuration to the project.
|
||||
|
||||
Args:
|
||||
name: Configuration name.
|
||||
"""
|
||||
Args:
|
||||
name: Configuration name.
|
||||
"""
|
||||
self.configurations[name] = ["Configuration", {"Name": name}]
|
||||
|
||||
def AddDebugSettings(
|
||||
|
|
@ -81,12 +81,12 @@ class Writer:
|
|||
):
|
||||
"""Adds a DebugSettings node to the user file for a particular config.
|
||||
|
||||
Args:
|
||||
command: command line to run. First element in the list is the
|
||||
executable. All elements of the command will be quoted if
|
||||
necessary.
|
||||
working_directory: other files which may trigger the rule. (optional)
|
||||
"""
|
||||
Args:
|
||||
command: command line to run. First element in the list is the
|
||||
executable. All elements of the command will be quoted if
|
||||
necessary.
|
||||
working_directory: other files which may trigger the rule. (optional)
|
||||
"""
|
||||
command = _QuoteWin32CommandLineArgs(command)
|
||||
|
||||
abs_command = _FindCommandInPath(command[0])
|
||||
|
|
|
|||
|
|
@ -29,13 +29,13 @@ def _GetLargePdbShimCcPath():
|
|||
def _DeepCopySomeKeys(in_dict, keys):
|
||||
"""Performs a partial deep-copy on |in_dict|, only copying the keys in |keys|.
|
||||
|
||||
Arguments:
|
||||
in_dict: The dictionary to copy.
|
||||
keys: The keys to be copied. If a key is in this list and doesn't exist in
|
||||
|in_dict| this is not an error.
|
||||
Returns:
|
||||
The partially deep-copied dictionary.
|
||||
"""
|
||||
Arguments:
|
||||
in_dict: The dictionary to copy.
|
||||
keys: The keys to be copied. If a key is in this list and doesn't exist in
|
||||
|in_dict| this is not an error.
|
||||
Returns:
|
||||
The partially deep-copied dictionary.
|
||||
"""
|
||||
d = {}
|
||||
for key in keys:
|
||||
if key not in in_dict:
|
||||
|
|
@ -47,12 +47,12 @@ def _DeepCopySomeKeys(in_dict, keys):
|
|||
def _SuffixName(name, suffix):
|
||||
"""Add a suffix to the end of a target.
|
||||
|
||||
Arguments:
|
||||
name: name of the target (foo#target)
|
||||
suffix: the suffix to be added
|
||||
Returns:
|
||||
Target name with suffix added (foo_suffix#target)
|
||||
"""
|
||||
Arguments:
|
||||
name: name of the target (foo#target)
|
||||
suffix: the suffix to be added
|
||||
Returns:
|
||||
Target name with suffix added (foo_suffix#target)
|
||||
"""
|
||||
parts = name.rsplit("#", 1)
|
||||
parts[0] = f"{parts[0]}_{suffix}"
|
||||
return "#".join(parts)
|
||||
|
|
@ -61,24 +61,24 @@ def _SuffixName(name, suffix):
|
|||
def _ShardName(name, number):
|
||||
"""Add a shard number to the end of a target.
|
||||
|
||||
Arguments:
|
||||
name: name of the target (foo#target)
|
||||
number: shard number
|
||||
Returns:
|
||||
Target name with shard added (foo_1#target)
|
||||
"""
|
||||
Arguments:
|
||||
name: name of the target (foo#target)
|
||||
number: shard number
|
||||
Returns:
|
||||
Target name with shard added (foo_1#target)
|
||||
"""
|
||||
return _SuffixName(name, str(number))
|
||||
|
||||
|
||||
def ShardTargets(target_list, target_dicts):
|
||||
"""Shard some targets apart to work around the linkers limits.
|
||||
|
||||
Arguments:
|
||||
target_list: List of target pairs: 'base/base.gyp:base'.
|
||||
target_dicts: Dict of target properties keyed on target pair.
|
||||
Returns:
|
||||
Tuple of the new sharded versions of the inputs.
|
||||
"""
|
||||
Arguments:
|
||||
target_list: List of target pairs: 'base/base.gyp:base'.
|
||||
target_dicts: Dict of target properties keyed on target pair.
|
||||
Returns:
|
||||
Tuple of the new sharded versions of the inputs.
|
||||
"""
|
||||
# Gather the targets to shard, and how many pieces.
|
||||
targets_to_shard = {}
|
||||
for t in target_dicts:
|
||||
|
|
@ -128,22 +128,22 @@ def ShardTargets(target_list, target_dicts):
|
|||
|
||||
def _GetPdbPath(target_dict, config_name, vars):
|
||||
"""Returns the path to the PDB file that will be generated by a given
|
||||
configuration.
|
||||
configuration.
|
||||
|
||||
The lookup proceeds as follows:
|
||||
- Look for an explicit path in the VCLinkerTool configuration block.
|
||||
- Look for an 'msvs_large_pdb_path' variable.
|
||||
- Use '<(PRODUCT_DIR)/<(product_name).(exe|dll).pdb' if 'product_name' is
|
||||
specified.
|
||||
- Use '<(PRODUCT_DIR)/<(target_name).(exe|dll).pdb'.
|
||||
The lookup proceeds as follows:
|
||||
- Look for an explicit path in the VCLinkerTool configuration block.
|
||||
- Look for an 'msvs_large_pdb_path' variable.
|
||||
- Use '<(PRODUCT_DIR)/<(product_name).(exe|dll).pdb' if 'product_name' is
|
||||
specified.
|
||||
- Use '<(PRODUCT_DIR)/<(target_name).(exe|dll).pdb'.
|
||||
|
||||
Arguments:
|
||||
target_dict: The target dictionary to be searched.
|
||||
config_name: The name of the configuration of interest.
|
||||
vars: A dictionary of common GYP variables with generator-specific values.
|
||||
Returns:
|
||||
The path of the corresponding PDB file.
|
||||
"""
|
||||
Arguments:
|
||||
target_dict: The target dictionary to be searched.
|
||||
config_name: The name of the configuration of interest.
|
||||
vars: A dictionary of common GYP variables with generator-specific values.
|
||||
Returns:
|
||||
The path of the corresponding PDB file.
|
||||
"""
|
||||
config = target_dict["configurations"][config_name]
|
||||
msvs = config.setdefault("msvs_settings", {})
|
||||
|
||||
|
|
@ -168,16 +168,16 @@ def _GetPdbPath(target_dict, config_name, vars):
|
|||
def InsertLargePdbShims(target_list, target_dicts, vars):
|
||||
"""Insert a shim target that forces the linker to use 4KB pagesize PDBs.
|
||||
|
||||
This is a workaround for targets with PDBs greater than 1GB in size, the
|
||||
limit for the 1KB pagesize PDBs created by the linker by default.
|
||||
This is a workaround for targets with PDBs greater than 1GB in size, the
|
||||
limit for the 1KB pagesize PDBs created by the linker by default.
|
||||
|
||||
Arguments:
|
||||
target_list: List of target pairs: 'base/base.gyp:base'.
|
||||
target_dicts: Dict of target properties keyed on target pair.
|
||||
vars: A dictionary of common GYP variables with generator-specific values.
|
||||
Returns:
|
||||
Tuple of the shimmed version of the inputs.
|
||||
"""
|
||||
Arguments:
|
||||
target_list: List of target pairs: 'base/base.gyp:base'.
|
||||
target_dicts: Dict of target properties keyed on target pair.
|
||||
vars: A dictionary of common GYP variables with generator-specific values.
|
||||
Returns:
|
||||
Tuple of the shimmed version of the inputs.
|
||||
"""
|
||||
# Determine which targets need shimming.
|
||||
targets_to_shim = []
|
||||
for t in target_dicts:
|
||||
|
|
|
|||
|
|
@ -76,17 +76,17 @@ class VisualStudioVersion:
|
|||
return self.path
|
||||
|
||||
def ToolPath(self, tool):
|
||||
"""Returns the path to a given compiler tool. """
|
||||
"""Returns the path to a given compiler tool."""
|
||||
return os.path.normpath(os.path.join(self.path, "VC/bin", tool))
|
||||
|
||||
def DefaultToolset(self):
|
||||
"""Returns the msbuild toolset version that will be used in the absence
|
||||
of a user override."""
|
||||
of a user override."""
|
||||
return self.default_toolset
|
||||
|
||||
def _SetupScriptInternal(self, target_arch):
|
||||
"""Returns a command (with arguments) to be used to set up the
|
||||
environment."""
|
||||
environment."""
|
||||
assert target_arch in ("x86", "x64"), "target_arch not supported"
|
||||
# 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
|
||||
|
|
@ -154,16 +154,16 @@ class VisualStudioVersion:
|
|||
def _RegistryQueryBase(sysdir, key, value):
|
||||
"""Use reg.exe to read a particular key.
|
||||
|
||||
While ideally we might use the win32 module, we would like gyp to be
|
||||
python neutral, so for instance cygwin python lacks this module.
|
||||
While ideally we might use the win32 module, we would like gyp to be
|
||||
python neutral, so for instance cygwin python lacks this module.
|
||||
|
||||
Arguments:
|
||||
sysdir: The system subdirectory to attempt to launch reg.exe from.
|
||||
key: The registry key to read from.
|
||||
value: The particular value to read.
|
||||
Return:
|
||||
stdout from reg.exe, or None for failure.
|
||||
"""
|
||||
Arguments:
|
||||
sysdir: The system subdirectory to attempt to launch reg.exe from.
|
||||
key: The registry key to read from.
|
||||
value: The particular value to read.
|
||||
Return:
|
||||
stdout from reg.exe, or None for failure.
|
||||
"""
|
||||
# Skip if not on Windows or Python Win32 setup issue
|
||||
if sys.platform not in ("win32", "cygwin"):
|
||||
return None
|
||||
|
|
@ -184,20 +184,20 @@ def _RegistryQueryBase(sysdir, key, value):
|
|||
def _RegistryQuery(key, value=None):
|
||||
r"""Use reg.exe to read a particular key through _RegistryQueryBase.
|
||||
|
||||
First tries to launch from %WinDir%\Sysnative to avoid WoW64 redirection. If
|
||||
that fails, it falls back to System32. Sysnative is available on Vista and
|
||||
up and available on Windows Server 2003 and XP through KB patch 942589. Note
|
||||
that Sysnative will always fail if using 64-bit python due to it being a
|
||||
virtual directory and System32 will work correctly in the first place.
|
||||
First tries to launch from %WinDir%\Sysnative to avoid WoW64 redirection. If
|
||||
that fails, it falls back to System32. Sysnative is available on Vista and
|
||||
up and available on Windows Server 2003 and XP through KB patch 942589. Note
|
||||
that Sysnative will always fail if using 64-bit python due to it being a
|
||||
virtual directory and System32 will work correctly in the first place.
|
||||
|
||||
KB 942589 - http://support.microsoft.com/kb/942589/en-us.
|
||||
KB 942589 - http://support.microsoft.com/kb/942589/en-us.
|
||||
|
||||
Arguments:
|
||||
key: The registry key.
|
||||
value: The particular registry value to read (optional).
|
||||
Return:
|
||||
stdout from reg.exe, or None for failure.
|
||||
"""
|
||||
Arguments:
|
||||
key: The registry key.
|
||||
value: The particular registry value to read (optional).
|
||||
Return:
|
||||
stdout from reg.exe, or None for failure.
|
||||
"""
|
||||
text = None
|
||||
try:
|
||||
text = _RegistryQueryBase("Sysnative", key, value)
|
||||
|
|
@ -212,14 +212,15 @@ def _RegistryQuery(key, value=None):
|
|||
def _RegistryGetValueUsingWinReg(key, value):
|
||||
"""Use the _winreg module to obtain the value of a registry key.
|
||||
|
||||
Args:
|
||||
key: The registry key.
|
||||
value: The particular registry value to read.
|
||||
Return:
|
||||
contents of the registry key's value, or None on failure. Throws
|
||||
ImportError if winreg is unavailable.
|
||||
"""
|
||||
Args:
|
||||
key: The registry key.
|
||||
value: The particular registry value to read.
|
||||
Return:
|
||||
contents of the registry key's value, or None on failure. Throws
|
||||
ImportError if winreg is unavailable.
|
||||
"""
|
||||
from winreg import HKEY_LOCAL_MACHINE, OpenKey, QueryValueEx # noqa: PLC0415
|
||||
|
||||
try:
|
||||
root, subkey = key.split("\\", 1)
|
||||
assert root == "HKLM" # Only need HKLM for now.
|
||||
|
|
@ -232,17 +233,17 @@ def _RegistryGetValueUsingWinReg(key, value):
|
|||
def _RegistryGetValue(key, value):
|
||||
"""Use _winreg or reg.exe to obtain the value of a registry key.
|
||||
|
||||
Using _winreg is preferable because it solves an issue on some corporate
|
||||
environments where access to reg.exe is locked down. However, we still need
|
||||
to fallback to reg.exe for the case where the _winreg module is not available
|
||||
(for example in cygwin python).
|
||||
Using _winreg is preferable because it solves an issue on some corporate
|
||||
environments where access to reg.exe is locked down. However, we still need
|
||||
to fallback to reg.exe for the case where the _winreg module is not available
|
||||
(for example in cygwin python).
|
||||
|
||||
Args:
|
||||
key: The registry key.
|
||||
value: The particular registry value to read.
|
||||
Return:
|
||||
contents of the registry key's value, or None on failure.
|
||||
"""
|
||||
Args:
|
||||
key: The registry key.
|
||||
value: The particular registry value to read.
|
||||
Return:
|
||||
contents of the registry key's value, or None on failure.
|
||||
"""
|
||||
try:
|
||||
return _RegistryGetValueUsingWinReg(key, value)
|
||||
except ImportError:
|
||||
|
|
@ -262,10 +263,10 @@ def _RegistryGetValue(key, value):
|
|||
def _CreateVersion(name, path, sdk_based=False):
|
||||
"""Sets up MSVS project generation.
|
||||
|
||||
Setup is based off the GYP_MSVS_VERSION environment variable or whatever is
|
||||
autodetected if GYP_MSVS_VERSION is not explicitly specified. If a version is
|
||||
passed in that doesn't match a value in versions python will throw a error.
|
||||
"""
|
||||
Setup is based off the GYP_MSVS_VERSION environment variable or whatever is
|
||||
autodetected if GYP_MSVS_VERSION is not explicitly specified. If a version is
|
||||
passed in that doesn't match a value in versions python will throw a error.
|
||||
"""
|
||||
if path:
|
||||
path = os.path.normpath(path)
|
||||
versions = {
|
||||
|
|
@ -435,22 +436,22 @@ def _ConvertToCygpath(path):
|
|||
def _DetectVisualStudioVersions(versions_to_check, force_express):
|
||||
"""Collect the list of installed visual studio versions.
|
||||
|
||||
Returns:
|
||||
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.
|
||||
Possibilities are:
|
||||
2005(e) - Visual Studio 2005 (8)
|
||||
2008(e) - Visual Studio 2008 (9)
|
||||
2010(e) - Visual Studio 2010 (10)
|
||||
2012(e) - Visual Studio 2012 (11)
|
||||
2013(e) - Visual Studio 2013 (12)
|
||||
2015 - Visual Studio 2015 (14)
|
||||
2017 - Visual Studio 2017 (15)
|
||||
2019 - Visual Studio 2019 (16)
|
||||
2022 - Visual Studio 2022 (17)
|
||||
Where (e) is e for express editions of MSVS and blank otherwise.
|
||||
"""
|
||||
Returns:
|
||||
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.
|
||||
Possibilities are:
|
||||
2005(e) - Visual Studio 2005 (8)
|
||||
2008(e) - Visual Studio 2008 (9)
|
||||
2010(e) - Visual Studio 2010 (10)
|
||||
2012(e) - Visual Studio 2012 (11)
|
||||
2013(e) - Visual Studio 2013 (12)
|
||||
2015 - Visual Studio 2015 (14)
|
||||
2017 - Visual Studio 2017 (15)
|
||||
2019 - Visual Studio 2019 (16)
|
||||
2022 - Visual Studio 2022 (17)
|
||||
Where (e) is e for express editions of MSVS and blank otherwise.
|
||||
"""
|
||||
version_to_year = {
|
||||
"8.0": "2005",
|
||||
"9.0": "2008",
|
||||
|
|
@ -527,11 +528,11 @@ def _DetectVisualStudioVersions(versions_to_check, force_express):
|
|||
def SelectVisualStudioVersion(version="auto", allow_fallback=True):
|
||||
"""Select which version of Visual Studio projects to generate.
|
||||
|
||||
Arguments:
|
||||
version: Hook to allow caller to force a particular version (vs auto).
|
||||
Returns:
|
||||
An object representing a visual studio project format version.
|
||||
"""
|
||||
Arguments:
|
||||
version: Hook to allow caller to force a particular version (vs auto).
|
||||
Returns:
|
||||
An object representing a visual studio project format version.
|
||||
"""
|
||||
# In auto mode, check environment variable for override.
|
||||
if version == "auto":
|
||||
version = os.environ.get("GYP_MSVS_VERSION", "auto")
|
||||
|
|
|
|||
|
|
@ -25,19 +25,21 @@ DEBUG_GENERAL = "general"
|
|||
DEBUG_VARIABLES = "variables"
|
||||
DEBUG_INCLUDES = "includes"
|
||||
|
||||
|
||||
def EscapeForCString(string: bytes | str) -> str:
|
||||
if isinstance(string, str):
|
||||
string = string.encode(encoding='utf8')
|
||||
string = string.encode(encoding="utf8")
|
||||
|
||||
backslash_or_double_quote = {ord('\\'), ord('"')}
|
||||
result = ''
|
||||
backslash_or_double_quote = {ord("\\"), ord('"')}
|
||||
result = ""
|
||||
for char in string:
|
||||
if char in backslash_or_double_quote or not 32 <= char < 127:
|
||||
result += '\\%03o' % char
|
||||
result += "\\%03o" % char
|
||||
else:
|
||||
result += chr(char)
|
||||
return result
|
||||
|
||||
|
||||
def DebugOutput(mode, message, *args):
|
||||
if "all" in gyp.debug or mode in gyp.debug:
|
||||
ctx = ("unknown", 0, "unknown")
|
||||
|
|
@ -76,11 +78,11 @@ def Load(
|
|||
circular_check=True,
|
||||
):
|
||||
"""
|
||||
Loads one or more specified build files.
|
||||
default_variables and includes will be copied before use.
|
||||
Returns the generator for the specified format and the
|
||||
data returned by loading the specified build files.
|
||||
"""
|
||||
Loads one or more specified build files.
|
||||
default_variables and includes will be copied before use.
|
||||
Returns the generator for the specified format and the
|
||||
data returned by loading the specified build files.
|
||||
"""
|
||||
if params is None:
|
||||
params = {}
|
||||
|
||||
|
|
@ -114,7 +116,7 @@ def Load(
|
|||
# These parameters are passed in order (as opposed to by key)
|
||||
# because ActivePython cannot handle key parameters to __import__.
|
||||
generator = __import__(generator_name, globals(), locals(), generator_name)
|
||||
for (key, val) in generator.generator_default_variables.items():
|
||||
for key, val in generator.generator_default_variables.items():
|
||||
default_variables.setdefault(key, val)
|
||||
|
||||
output_dir = params["options"].generator_output or params["options"].toplevel_dir
|
||||
|
|
@ -184,10 +186,10 @@ def Load(
|
|||
|
||||
def NameValueListToDict(name_value_list):
|
||||
"""
|
||||
Takes an array of strings of the form 'NAME=VALUE' and creates a dictionary
|
||||
of the pairs. If a string is simply NAME, then the value in the dictionary
|
||||
is set to True. If VALUE can be converted to an integer, it is.
|
||||
"""
|
||||
Takes an array of strings of the form 'NAME=VALUE' and creates a dictionary
|
||||
of the pairs. If a string is simply NAME, then the value in the dictionary
|
||||
is set to True. If VALUE can be converted to an integer, it is.
|
||||
"""
|
||||
result = {}
|
||||
for item in name_value_list:
|
||||
tokens = item.split("=", 1)
|
||||
|
|
@ -220,13 +222,13 @@ def FormatOpt(opt, value):
|
|||
def RegenerateAppendFlag(flag, values, predicate, env_name, options):
|
||||
"""Regenerate a list of command line flags, for an option of action='append'.
|
||||
|
||||
The |env_name|, if given, is checked in the environment and used to generate
|
||||
an initial list of options, then the options that were specified on the
|
||||
command line (given in |values|) are appended. This matches the handling of
|
||||
environment variables and command line flags where command line flags override
|
||||
the environment, while not requiring the environment to be set when the flags
|
||||
are used again.
|
||||
"""
|
||||
The |env_name|, if given, is checked in the environment and used to generate
|
||||
an initial list of options, then the options that were specified on the
|
||||
command line (given in |values|) are appended. This matches the handling of
|
||||
environment variables and command line flags where command line flags override
|
||||
the environment, while not requiring the environment to be set when the flags
|
||||
are used again.
|
||||
"""
|
||||
flags = []
|
||||
if options.use_environment and env_name:
|
||||
for flag_value in ShlexEnv(env_name):
|
||||
|
|
@ -242,14 +244,14 @@ def RegenerateAppendFlag(flag, values, predicate, env_name, options):
|
|||
|
||||
def RegenerateFlags(options):
|
||||
"""Given a parsed options object, and taking the environment variables into
|
||||
account, returns a list of flags that should regenerate an equivalent options
|
||||
object (even in the absence of the environment variables.)
|
||||
account, returns a list of flags that should regenerate an equivalent options
|
||||
object (even in the absence of the environment variables.)
|
||||
|
||||
Any path options will be normalized relative to depth.
|
||||
Any path options will be normalized relative to depth.
|
||||
|
||||
The format flag is not included, as it is assumed the calling generator will
|
||||
set that as appropriate.
|
||||
"""
|
||||
The format flag is not included, as it is assumed the calling generator will
|
||||
set that as appropriate.
|
||||
"""
|
||||
|
||||
def FixPath(path):
|
||||
path = gyp.common.FixIfRelativePath(path, options.depth)
|
||||
|
|
@ -307,15 +309,15 @@ class RegeneratableOptionParser(argparse.ArgumentParser):
|
|||
def add_argument(self, *args, **kw):
|
||||
"""Add an option to the parser.
|
||||
|
||||
This accepts the same arguments as ArgumentParser.add_argument, plus the
|
||||
following:
|
||||
regenerate: can be set to False to prevent this option from being included
|
||||
in regeneration.
|
||||
env_name: name of environment variable that additional values for this
|
||||
option come from.
|
||||
type: adds type='path', to tell the regenerator that the values of
|
||||
this option need to be made relative to options.depth
|
||||
"""
|
||||
This accepts the same arguments as ArgumentParser.add_argument, plus the
|
||||
following:
|
||||
regenerate: can be set to False to prevent this option from being included
|
||||
in regeneration.
|
||||
env_name: name of environment variable that additional values for this
|
||||
option come from.
|
||||
type: adds type='path', to tell the regenerator that the values of
|
||||
this option need to be made relative to options.depth
|
||||
"""
|
||||
env_name = kw.pop("env_name", None)
|
||||
if "dest" in kw and kw.pop("regenerate", True):
|
||||
dest = kw["dest"]
|
||||
|
|
@ -343,7 +345,7 @@ class RegeneratableOptionParser(argparse.ArgumentParser):
|
|||
|
||||
def gyp_main(args):
|
||||
my_name = os.path.basename(sys.argv[0])
|
||||
usage = "usage: %(prog)s [options ...] [build_file ...]"
|
||||
usage = "%(prog)s [options ...] [build_file ...]"
|
||||
|
||||
parser = RegeneratableOptionParser(usage=usage.replace("%s", "%(prog)s"))
|
||||
parser.add_argument(
|
||||
|
|
@ -490,6 +492,7 @@ def gyp_main(args):
|
|||
options, build_files_arg = parser.parse_args(args)
|
||||
if options.version:
|
||||
import pkg_resources # noqa: PLC0415
|
||||
|
||||
print(f"v{pkg_resources.get_distribution('gyp-next').version}")
|
||||
return 0
|
||||
build_files = build_files_arg
|
||||
|
|
|
|||
|
|
@ -31,9 +31,8 @@ class memoize:
|
|||
|
||||
class GypError(Exception):
|
||||
"""Error class representing an error, which is to be presented
|
||||
to the user. The main entry point will catch and display this.
|
||||
"""
|
||||
|
||||
to the user. The main entry point will catch and display this.
|
||||
"""
|
||||
|
||||
|
||||
def ExceptionAppend(e, msg):
|
||||
|
|
@ -48,9 +47,9 @@ def ExceptionAppend(e, msg):
|
|||
|
||||
def FindQualifiedTargets(target, qualified_list):
|
||||
"""
|
||||
Given a list of qualified targets, return the qualified targets for the
|
||||
specified |target|.
|
||||
"""
|
||||
Given a list of qualified targets, return the qualified targets for the
|
||||
specified |target|.
|
||||
"""
|
||||
return [t for t in qualified_list if ParseQualifiedTarget(t)[1] == target]
|
||||
|
||||
|
||||
|
|
@ -115,7 +114,7 @@ def BuildFile(fully_qualified_target):
|
|||
|
||||
def GetEnvironFallback(var_list, default):
|
||||
"""Look up a key in the environment, with fallback to secondary keys
|
||||
and finally falling back to a default value."""
|
||||
and finally falling back to a default value."""
|
||||
for var in var_list:
|
||||
if var in os.environ:
|
||||
return os.environ[var]
|
||||
|
|
@ -178,11 +177,11 @@ def RelativePath(path, relative_to, follow_path_symlink=True):
|
|||
@memoize
|
||||
def InvertRelativePath(path, toplevel_dir=None):
|
||||
"""Given a path like foo/bar that is relative to toplevel_dir, return
|
||||
the inverse relative path back to the toplevel_dir.
|
||||
the inverse relative path back to the toplevel_dir.
|
||||
|
||||
E.g. os.path.normpath(os.path.join(path, InvertRelativePath(path)))
|
||||
should always produce the empty string, unless the path contains symlinks.
|
||||
"""
|
||||
E.g. os.path.normpath(os.path.join(path, InvertRelativePath(path)))
|
||||
should always produce the empty string, unless the path contains symlinks.
|
||||
"""
|
||||
if not path:
|
||||
return path
|
||||
toplevel_dir = "." if toplevel_dir is None else toplevel_dir
|
||||
|
|
@ -262,12 +261,12 @@ _escape = re.compile(r'(["\\`])')
|
|||
def EncodePOSIXShellArgument(argument):
|
||||
"""Encodes |argument| suitably for consumption by POSIX shells.
|
||||
|
||||
argument may be quoted and escaped as necessary to ensure that POSIX shells
|
||||
treat the returned value as a literal representing the argument passed to
|
||||
this function. Parameter (variable) expansions beginning with $ are allowed
|
||||
to remain intact without escaping the $, to allow the argument to contain
|
||||
references to variables to be expanded by the shell.
|
||||
"""
|
||||
argument may be quoted and escaped as necessary to ensure that POSIX shells
|
||||
treat the returned value as a literal representing the argument passed to
|
||||
this function. Parameter (variable) expansions beginning with $ are allowed
|
||||
to remain intact without escaping the $, to allow the argument to contain
|
||||
references to variables to be expanded by the shell.
|
||||
"""
|
||||
|
||||
if not isinstance(argument, str):
|
||||
argument = str(argument)
|
||||
|
|
@ -282,9 +281,9 @@ def EncodePOSIXShellArgument(argument):
|
|||
def EncodePOSIXShellList(list):
|
||||
"""Encodes |list| suitably for consumption by POSIX shells.
|
||||
|
||||
Returns EncodePOSIXShellArgument for each item in list, and joins them
|
||||
together using the space character as an argument separator.
|
||||
"""
|
||||
Returns EncodePOSIXShellArgument for each item in list, and joins them
|
||||
together using the space character as an argument separator.
|
||||
"""
|
||||
|
||||
encoded_arguments = []
|
||||
for argument in list:
|
||||
|
|
@ -312,14 +311,12 @@ def DeepDependencyTargets(target_dicts, roots):
|
|||
|
||||
|
||||
def BuildFileTargets(target_list, build_file):
|
||||
"""From a target_list, returns the subset from the specified build_file.
|
||||
"""
|
||||
"""From a target_list, returns the subset from the specified build_file."""
|
||||
return [p for p in target_list if BuildFile(p) == build_file]
|
||||
|
||||
|
||||
def AllTargets(target_list, target_dicts, build_file):
|
||||
"""Returns all targets (direct and dependencies) for the specified build_file.
|
||||
"""
|
||||
"""Returns all targets (direct and dependencies) for the specified build_file."""
|
||||
bftargets = BuildFileTargets(target_list, build_file)
|
||||
deptargets = DeepDependencyTargets(target_dicts, bftargets)
|
||||
return bftargets + deptargets
|
||||
|
|
@ -328,12 +325,12 @@ def AllTargets(target_list, target_dicts, build_file):
|
|||
def WriteOnDiff(filename):
|
||||
"""Write to a file only if the new contents differ.
|
||||
|
||||
Arguments:
|
||||
filename: name of the file to potentially write to.
|
||||
Returns:
|
||||
A file like object which will write to temporary file and only overwrite
|
||||
the target if it differs (on close).
|
||||
"""
|
||||
Arguments:
|
||||
filename: name of the file to potentially write to.
|
||||
Returns:
|
||||
A file like object which will write to temporary file and only overwrite
|
||||
the target if it differs (on close).
|
||||
"""
|
||||
|
||||
class Writer:
|
||||
"""Wrapper around file which only covers the target if it differs."""
|
||||
|
|
@ -421,6 +418,7 @@ def EnsureDirExists(path):
|
|||
except OSError:
|
||||
pass
|
||||
|
||||
|
||||
def GetCompilerPredefines(): # -> dict
|
||||
cmd = []
|
||||
defines = {}
|
||||
|
|
@ -448,15 +446,14 @@ def GetCompilerPredefines(): # -> dict
|
|||
try:
|
||||
os.close(fd)
|
||||
stdout = subprocess.run(
|
||||
real_cmd, shell=True,
|
||||
capture_output=True, check=True
|
||||
real_cmd, shell=True, capture_output=True, check=True
|
||||
).stdout
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(
|
||||
"Warning: failed to get compiler predefines\n"
|
||||
"cmd: %s\n"
|
||||
"status: %d" % (e.cmd, e.returncode),
|
||||
file=sys.stderr
|
||||
file=sys.stderr,
|
||||
)
|
||||
return defines
|
||||
finally:
|
||||
|
|
@ -466,15 +463,14 @@ def GetCompilerPredefines(): # -> dict
|
|||
real_cmd = [*cmd, "-dM", "-E", "-x", "c", input]
|
||||
try:
|
||||
stdout = subprocess.run(
|
||||
real_cmd, shell=False,
|
||||
capture_output=True, check=True
|
||||
real_cmd, shell=False, capture_output=True, check=True
|
||||
).stdout
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(
|
||||
"Warning: failed to get compiler predefines\n"
|
||||
"cmd: %s\n"
|
||||
"status: %d" % (e.cmd, e.returncode),
|
||||
file=sys.stderr
|
||||
file=sys.stderr,
|
||||
)
|
||||
return defines
|
||||
|
||||
|
|
@ -485,6 +481,7 @@ def GetCompilerPredefines(): # -> dict
|
|||
defines[key] = " ".join(value)
|
||||
return defines
|
||||
|
||||
|
||||
def GetFlavorByPlatform():
|
||||
"""Returns |params.flavor| if it's set, the system's default flavor else."""
|
||||
flavors = {
|
||||
|
|
@ -512,6 +509,7 @@ def GetFlavorByPlatform():
|
|||
|
||||
return "linux"
|
||||
|
||||
|
||||
def GetFlavor(params):
|
||||
if "flavor" in params:
|
||||
return params["flavor"]
|
||||
|
|
@ -527,7 +525,7 @@ def GetFlavor(params):
|
|||
|
||||
def CopyTool(flavor, out_path, generator_flags={}):
|
||||
"""Finds (flock|mac|win)_tool.gyp in the gyp directory and copies it
|
||||
to |out_path|."""
|
||||
to |out_path|."""
|
||||
# aix and solaris just need flock emulation. mac and win use more complicated
|
||||
# support scripts.
|
||||
prefix = {
|
||||
|
|
@ -662,24 +660,24 @@ class CycleError(Exception):
|
|||
def TopologicallySorted(graph, get_edges):
|
||||
r"""Topologically sort based on a user provided edge definition.
|
||||
|
||||
Args:
|
||||
graph: A list of node names.
|
||||
get_edges: A function mapping from node name to a hashable collection
|
||||
of node names which this node has outgoing edges to.
|
||||
Returns:
|
||||
A list containing all of the node in graph in topological order.
|
||||
It is assumed that calling get_edges once for each node and caching is
|
||||
cheaper than repeatedly calling get_edges.
|
||||
Raises:
|
||||
CycleError in the event of a cycle.
|
||||
Example:
|
||||
graph = {'a': '$(b) $(c)', 'b': 'hi', 'c': '$(b)'}
|
||||
def GetEdges(node):
|
||||
return re.findall(r'\$\(([^))]\)', graph[node])
|
||||
print TopologicallySorted(graph.keys(), GetEdges)
|
||||
==>
|
||||
['a', 'c', b']
|
||||
"""
|
||||
Args:
|
||||
graph: A list of node names.
|
||||
get_edges: A function mapping from node name to a hashable collection
|
||||
of node names which this node has outgoing edges to.
|
||||
Returns:
|
||||
A list containing all of the node in graph in topological order.
|
||||
It is assumed that calling get_edges once for each node and caching is
|
||||
cheaper than repeatedly calling get_edges.
|
||||
Raises:
|
||||
CycleError in the event of a cycle.
|
||||
Example:
|
||||
graph = {'a': '$(b) $(c)', 'b': 'hi', 'c': '$(b)'}
|
||||
def GetEdges(node):
|
||||
return re.findall(r'\$\(([^))]\)', graph[node])
|
||||
print TopologicallySorted(graph.keys(), GetEdges)
|
||||
==>
|
||||
['a', 'c', b']
|
||||
"""
|
||||
get_edges = memoize(get_edges)
|
||||
visited = set()
|
||||
visiting = set()
|
||||
|
|
|
|||
|
|
@ -28,8 +28,12 @@ class TestTopologicallySorted(unittest.TestCase):
|
|||
def GetEdge(node):
|
||||
return tuple(graph[node])
|
||||
|
||||
assert gyp.common.TopologicallySorted(
|
||||
graph.keys(), GetEdge) == ["a", "c", "d", "b"]
|
||||
assert gyp.common.TopologicallySorted(graph.keys(), GetEdge) == [
|
||||
"a",
|
||||
"c",
|
||||
"d",
|
||||
"b",
|
||||
]
|
||||
|
||||
def test_Cycle(self):
|
||||
"""Test that an exception is thrown on a cyclic graph."""
|
||||
|
|
@ -97,10 +101,7 @@ class TestGetFlavor(unittest.TestCase):
|
|||
if throws:
|
||||
mock_run.side_effect = subprocess.CalledProcessError(
|
||||
returncode=1,
|
||||
cmd=[
|
||||
*expected_cmd,
|
||||
"-dM", "-E", "-x", "c", expected_input
|
||||
]
|
||||
cmd=[*expected_cmd, "-dM", "-E", "-x", "c", expected_input],
|
||||
)
|
||||
else:
|
||||
mock_process = MagicMock()
|
||||
|
|
@ -115,75 +116,71 @@ class TestGetFlavor(unittest.TestCase):
|
|||
flavor = gyp.common.GetFlavor({})
|
||||
if env.get("CC_target") or env.get("CC"):
|
||||
mock_run.assert_called_with(
|
||||
[
|
||||
*expected_cmd,
|
||||
"-dM", "-E", "-x", "c", expected_input
|
||||
],
|
||||
[*expected_cmd, "-dM", "-E", "-x", "c", expected_input],
|
||||
shell=sys.platform == "win32",
|
||||
capture_output=True, check=True)
|
||||
capture_output=True,
|
||||
check=True,
|
||||
)
|
||||
return [defines, flavor]
|
||||
|
||||
[defines0, _] = mock_run({ "CC": "cl.exe" }, "", ["cl.exe"], True)
|
||||
[defines0, _] = mock_run({"CC": "cl.exe"}, "", ["cl.exe"], True)
|
||||
assert defines0 == {}
|
||||
|
||||
[defines1, _] = mock_run({}, "", [])
|
||||
assert defines1 == {}
|
||||
|
||||
[defines2, flavor2] = mock_run(
|
||||
{ "CC_target": "/opt/wasi-sdk/bin/clang" },
|
||||
{"CC_target": "/opt/wasi-sdk/bin/clang"},
|
||||
"#define __wasm__ 1\n#define __wasi__ 1\n",
|
||||
["/opt/wasi-sdk/bin/clang"]
|
||||
["/opt/wasi-sdk/bin/clang"],
|
||||
)
|
||||
assert defines2 == { "__wasm__": "1", "__wasi__": "1" }
|
||||
assert defines2 == {"__wasm__": "1", "__wasi__": "1"}
|
||||
assert flavor2 == "wasi"
|
||||
|
||||
[defines3, flavor3] = mock_run(
|
||||
{ "CC_target": "/opt/wasi-sdk/bin/clang --target=wasm32" },
|
||||
{"CC_target": "/opt/wasi-sdk/bin/clang --target=wasm32"},
|
||||
"#define __wasm__ 1\n",
|
||||
["/opt/wasi-sdk/bin/clang", "--target=wasm32"]
|
||||
["/opt/wasi-sdk/bin/clang", "--target=wasm32"],
|
||||
)
|
||||
assert defines3 == { "__wasm__": "1" }
|
||||
assert defines3 == {"__wasm__": "1"}
|
||||
assert flavor3 == "wasm"
|
||||
|
||||
[defines4, flavor4] = mock_run(
|
||||
{ "CC_target": "/emsdk/upstream/emscripten/emcc" },
|
||||
{"CC_target": "/emsdk/upstream/emscripten/emcc"},
|
||||
"#define __EMSCRIPTEN__ 1\n",
|
||||
["/emsdk/upstream/emscripten/emcc"]
|
||||
["/emsdk/upstream/emscripten/emcc"],
|
||||
)
|
||||
assert defines4 == { "__EMSCRIPTEN__": "1" }
|
||||
assert defines4 == {"__EMSCRIPTEN__": "1"}
|
||||
assert flavor4 == "emscripten"
|
||||
|
||||
# Test path which include white space
|
||||
[defines5, flavor5] = mock_run(
|
||||
{
|
||||
"CC_target": "\"/Users/Toyo Li/wasi-sdk/bin/clang\" -O3",
|
||||
"CFLAGS": "--target=wasm32-wasi-threads -pthread"
|
||||
"CC_target": '"/Users/Toyo Li/wasi-sdk/bin/clang" -O3',
|
||||
"CFLAGS": "--target=wasm32-wasi-threads -pthread",
|
||||
},
|
||||
"#define __wasm__ 1\n#define __wasi__ 1\n#define _REENTRANT 1\n",
|
||||
[
|
||||
"/Users/Toyo Li/wasi-sdk/bin/clang",
|
||||
"-O3",
|
||||
"--target=wasm32-wasi-threads",
|
||||
"-pthread"
|
||||
]
|
||||
"-pthread",
|
||||
],
|
||||
)
|
||||
assert defines5 == {
|
||||
"__wasm__": "1",
|
||||
"__wasi__": "1",
|
||||
"_REENTRANT": "1"
|
||||
}
|
||||
assert defines5 == {"__wasm__": "1", "__wasi__": "1", "_REENTRANT": "1"}
|
||||
assert flavor5 == "wasi"
|
||||
|
||||
original_sep = os.sep
|
||||
os.sep = "\\"
|
||||
[defines6, flavor6] = mock_run(
|
||||
{ "CC_target": "\"C:\\Program Files\\wasi-sdk\\clang.exe\"" },
|
||||
{"CC_target": '"C:\\Program Files\\wasi-sdk\\clang.exe"'},
|
||||
"#define __wasm__ 1\n#define __wasi__ 1\n",
|
||||
["C:/Program Files/wasi-sdk/clang.exe"]
|
||||
["C:/Program Files/wasi-sdk/clang.exe"],
|
||||
)
|
||||
os.sep = original_sep
|
||||
assert defines6 == { "__wasm__": "1", "__wasi__": "1" }
|
||||
assert defines6 == {"__wasm__": "1", "__wasi__": "1"}
|
||||
assert flavor6 == "wasi"
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
|||
|
|
@ -10,43 +10,43 @@ from functools import reduce
|
|||
|
||||
|
||||
def XmlToString(content, encoding="utf-8", pretty=False):
|
||||
""" Writes the XML content to disk, touching the file only if it has changed.
|
||||
"""Writes the XML content to disk, touching the file only if it has changed.
|
||||
|
||||
Visual Studio files have a lot of pre-defined structures. This function makes
|
||||
it easy to represent these structures as Python data structures, instead of
|
||||
having to create a lot of function calls.
|
||||
Visual Studio files have a lot of pre-defined structures. This function makes
|
||||
it easy to represent these structures as Python data structures, instead of
|
||||
having to create a lot of function calls.
|
||||
|
||||
Each XML element of the content is represented as a list composed of:
|
||||
1. The name of the element, a string,
|
||||
2. The attributes of the element, a dictionary (optional), and
|
||||
3+. The content of the element, if any. Strings are simple text nodes and
|
||||
lists are child elements.
|
||||
Each XML element of the content is represented as a list composed of:
|
||||
1. The name of the element, a string,
|
||||
2. The attributes of the element, a dictionary (optional), and
|
||||
3+. The content of the element, if any. Strings are simple text nodes and
|
||||
lists are child elements.
|
||||
|
||||
Example 1:
|
||||
<test/>
|
||||
becomes
|
||||
['test']
|
||||
Example 1:
|
||||
<test/>
|
||||
becomes
|
||||
['test']
|
||||
|
||||
Example 2:
|
||||
<myelement a='value1' b='value2'>
|
||||
<childtype>This is</childtype>
|
||||
<childtype>it!</childtype>
|
||||
</myelement>
|
||||
Example 2:
|
||||
<myelement a='value1' b='value2'>
|
||||
<childtype>This is</childtype>
|
||||
<childtype>it!</childtype>
|
||||
</myelement>
|
||||
|
||||
becomes
|
||||
['myelement', {'a':'value1', 'b':'value2'},
|
||||
['childtype', 'This is'],
|
||||
['childtype', 'it!'],
|
||||
]
|
||||
becomes
|
||||
['myelement', {'a':'value1', 'b':'value2'},
|
||||
['childtype', 'This is'],
|
||||
['childtype', 'it!'],
|
||||
]
|
||||
|
||||
Args:
|
||||
content: The structured content to be converted.
|
||||
encoding: The encoding to report on the first XML line.
|
||||
pretty: True if we want pretty printing with indents and new lines.
|
||||
Args:
|
||||
content: The structured content to be converted.
|
||||
encoding: The encoding to report on the first XML line.
|
||||
pretty: True if we want pretty printing with indents and new lines.
|
||||
|
||||
Returns:
|
||||
The XML content as a string.
|
||||
"""
|
||||
Returns:
|
||||
The XML content as a string.
|
||||
"""
|
||||
# We create a huge list of all the elements of the file.
|
||||
xml_parts = ['<?xml version="1.0" encoding="%s"?>' % encoding]
|
||||
if pretty:
|
||||
|
|
@ -58,14 +58,14 @@ def XmlToString(content, encoding="utf-8", pretty=False):
|
|||
|
||||
|
||||
def _ConstructContentList(xml_parts, specification, pretty, level=0):
|
||||
""" Appends the XML parts corresponding to the specification.
|
||||
"""Appends the XML parts corresponding to the specification.
|
||||
|
||||
Args:
|
||||
xml_parts: A list of XML parts to be appended to.
|
||||
specification: The specification of the element. See EasyXml docs.
|
||||
pretty: True if we want pretty printing with indents and new lines.
|
||||
level: Indentation level.
|
||||
"""
|
||||
Args:
|
||||
xml_parts: A list of XML parts to be appended to.
|
||||
specification: The specification of the element. See EasyXml docs.
|
||||
pretty: True if we want pretty printing with indents and new lines.
|
||||
level: Indentation level.
|
||||
"""
|
||||
# The first item in a specification is the name of the element.
|
||||
if pretty:
|
||||
indentation = " " * level
|
||||
|
|
@ -107,16 +107,17 @@ def _ConstructContentList(xml_parts, specification, pretty, level=0):
|
|||
xml_parts.append("/>%s" % new_line)
|
||||
|
||||
|
||||
def WriteXmlIfChanged(content, path, encoding="utf-8", pretty=False,
|
||||
win32=(sys.platform == "win32")):
|
||||
""" Writes the XML content to disk, touching the file only if it has changed.
|
||||
def WriteXmlIfChanged(
|
||||
content, path, encoding="utf-8", pretty=False, win32=(sys.platform == "win32")
|
||||
):
|
||||
"""Writes the XML content to disk, touching the file only if it has changed.
|
||||
|
||||
Args:
|
||||
content: The structured content to be written.
|
||||
path: Location of the file.
|
||||
encoding: The encoding to report on the first line of the XML file.
|
||||
pretty: True if we want pretty printing with indents and new lines.
|
||||
"""
|
||||
Args:
|
||||
content: The structured content to be written.
|
||||
path: Location of the file.
|
||||
encoding: The encoding to report on the first line of the XML file.
|
||||
pretty: True if we want pretty printing with indents and new lines.
|
||||
"""
|
||||
xml_string = XmlToString(content, encoding, pretty)
|
||||
if win32 and os.linesep != "\r\n":
|
||||
xml_string = xml_string.replace("\n", "\r\n")
|
||||
|
|
@ -157,7 +158,7 @@ _xml_escape_re = re.compile("(%s)" % "|".join(map(re.escape, _xml_escape_map.key
|
|||
|
||||
|
||||
def _XmlEscape(value, attr=False):
|
||||
""" Escape a string for inclusion in XML."""
|
||||
"""Escape a string for inclusion in XML."""
|
||||
|
||||
def replace(match):
|
||||
m = match.string[match.start() : match.end()]
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
""" Unit tests for the easy_xml.py file. """
|
||||
"""Unit tests for the easy_xml.py file."""
|
||||
|
||||
import unittest
|
||||
from io import StringIO
|
||||
|
|
|
|||
|
|
@ -62,7 +62,6 @@ 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 json
|
||||
import os
|
||||
import posixpath
|
||||
|
|
@ -130,8 +129,8 @@ def _ToGypPath(path):
|
|||
|
||||
def _ResolveParent(path, base_path_components):
|
||||
"""Resolves |path|, which starts with at least one '../'. Returns an empty
|
||||
string if the path shouldn't be considered. See _AddSources() for a
|
||||
description of |base_path_components|."""
|
||||
string if the path shouldn't be considered. See _AddSources() for a
|
||||
description of |base_path_components|."""
|
||||
depth = 0
|
||||
while path.startswith("../"):
|
||||
depth += 1
|
||||
|
|
@ -151,11 +150,11 @@ def _ResolveParent(path, base_path_components):
|
|||
|
||||
def _AddSources(sources, base_path, base_path_components, result):
|
||||
"""Extracts valid sources from |sources| and adds them to |result|. Each
|
||||
source file is relative to |base_path|, but may contain '..'. To make
|
||||
resolving '..' easier |base_path_components| contains each of the
|
||||
directories in |base_path|. Additionally each source may contain variables.
|
||||
Such sources are ignored as it is assumed dependencies on them are expressed
|
||||
and tracked in some other means."""
|
||||
source file is relative to |base_path|, but may contain '..'. To make
|
||||
resolving '..' easier |base_path_components| contains each of the
|
||||
directories in |base_path|. Additionally each source may contain variables.
|
||||
Such sources are ignored as it is assumed dependencies on them are expressed
|
||||
and tracked in some other means."""
|
||||
# NOTE: gyp paths are always posix style.
|
||||
for source in sources:
|
||||
if not len(source) or source.startswith(("!!!", "$")):
|
||||
|
|
@ -218,23 +217,23 @@ def _ExtractSources(target, target_dict, toplevel_dir):
|
|||
|
||||
class Target:
|
||||
"""Holds information about a particular target:
|
||||
deps: set of Targets this Target depends upon. This is not recursive, only the
|
||||
direct dependent Targets.
|
||||
match_status: one of the MatchStatus values.
|
||||
back_deps: set of Targets that have a dependency on this Target.
|
||||
visited: used during iteration to indicate whether we've visited this target.
|
||||
This is used for two iterations, once in building the set of Targets and
|
||||
again in _GetBuildTargets().
|
||||
name: fully qualified name of the target.
|
||||
requires_build: True if the target type is such that it needs to be built.
|
||||
See _DoesTargetTypeRequireBuild for details.
|
||||
added_to_compile_targets: used when determining if the target was added to the
|
||||
set of targets that needs to be built.
|
||||
in_roots: true if this target is a descendant of one of the root nodes.
|
||||
is_executable: true if the type of target is executable.
|
||||
is_static_library: true if the type of target is static_library.
|
||||
is_or_has_linked_ancestor: true if the target does a link (eg executable), or
|
||||
if there is a target in back_deps that does a link."""
|
||||
deps: set of Targets this Target depends upon. This is not recursive, only the
|
||||
direct dependent Targets.
|
||||
match_status: one of the MatchStatus values.
|
||||
back_deps: set of Targets that have a dependency on this Target.
|
||||
visited: used during iteration to indicate whether we've visited this target.
|
||||
This is used for two iterations, once in building the set of Targets and
|
||||
again in _GetBuildTargets().
|
||||
name: fully qualified name of the target.
|
||||
requires_build: True if the target type is such that it needs to be built.
|
||||
See _DoesTargetTypeRequireBuild for details.
|
||||
added_to_compile_targets: used when determining if the target was added to the
|
||||
set of targets that needs to be built.
|
||||
in_roots: true if this target is a descendant of one of the root nodes.
|
||||
is_executable: true if the type of target is executable.
|
||||
is_static_library: true if the type of target is static_library.
|
||||
is_or_has_linked_ancestor: true if the target does a link (eg executable), or
|
||||
if there is a target in back_deps that does a link."""
|
||||
|
||||
def __init__(self, name):
|
||||
self.deps = set()
|
||||
|
|
@ -254,8 +253,8 @@ class Target:
|
|||
|
||||
class Config:
|
||||
"""Details what we're looking for
|
||||
files: set of files to search for
|
||||
targets: see file description for details."""
|
||||
files: set of files to search for
|
||||
targets: see file description for details."""
|
||||
|
||||
def __init__(self):
|
||||
self.files = []
|
||||
|
|
@ -265,7 +264,7 @@ class Config:
|
|||
|
||||
def Init(self, params):
|
||||
"""Initializes Config. This is a separate method as it raises an exception
|
||||
if there is a parse error."""
|
||||
if there is a parse error."""
|
||||
generator_flags = params.get("generator_flags", {})
|
||||
config_path = generator_flags.get("config_path", None)
|
||||
if not config_path:
|
||||
|
|
@ -289,8 +288,8 @@ class Config:
|
|||
|
||||
def _WasBuildFileModified(build_file, data, files, toplevel_dir):
|
||||
"""Returns true if the build file |build_file| is either in |files| or
|
||||
one of the files included by |build_file| is in |files|. |toplevel_dir| is
|
||||
the root of the source tree."""
|
||||
one of the files included by |build_file| is in |files|. |toplevel_dir| is
|
||||
the root of the source tree."""
|
||||
if _ToLocalPath(toplevel_dir, _ToGypPath(build_file)) in files:
|
||||
if debug:
|
||||
print("gyp file modified", build_file)
|
||||
|
|
@ -319,8 +318,8 @@ def _WasBuildFileModified(build_file, data, files, toplevel_dir):
|
|||
|
||||
def _GetOrCreateTargetByName(targets, target_name):
|
||||
"""Creates or returns the Target at targets[target_name]. If there is no
|
||||
Target for |target_name| one is created. Returns a tuple of whether a new
|
||||
Target was created and the Target."""
|
||||
Target for |target_name| one is created. Returns a tuple of whether a new
|
||||
Target was created and the Target."""
|
||||
if target_name in targets:
|
||||
return False, targets[target_name]
|
||||
target = Target(target_name)
|
||||
|
|
@ -340,13 +339,13 @@ def _DoesTargetTypeRequireBuild(target_dict):
|
|||
|
||||
def _GenerateTargets(data, target_list, target_dicts, toplevel_dir, files, build_files):
|
||||
"""Returns a tuple of the following:
|
||||
. A dictionary mapping from fully qualified name to Target.
|
||||
. A list of the targets that have a source file in |files|.
|
||||
. Targets that constitute the 'all' target. See description at top of file
|
||||
for details on the 'all' target.
|
||||
This sets the |match_status| of the targets that contain any of the source
|
||||
files in |files| to MATCH_STATUS_MATCHES.
|
||||
|toplevel_dir| is the root of the source tree."""
|
||||
. A dictionary mapping from fully qualified name to Target.
|
||||
. A list of the targets that have a source file in |files|.
|
||||
. Targets that constitute the 'all' target. See description at top of file
|
||||
for details on the 'all' target.
|
||||
This sets the |match_status| of the targets that contain any of the source
|
||||
files in |files| to MATCH_STATUS_MATCHES.
|
||||
|toplevel_dir| is the root of the source tree."""
|
||||
# Maps from target name to Target.
|
||||
name_to_target = {}
|
||||
|
||||
|
|
@ -379,9 +378,10 @@ def _GenerateTargets(data, target_list, target_dicts, toplevel_dir, files, build
|
|||
target_type = target_dicts[target_name]["type"]
|
||||
target.is_executable = target_type == "executable"
|
||||
target.is_static_library = target_type == "static_library"
|
||||
target.is_or_has_linked_ancestor = (
|
||||
target_type in {"executable", "shared_library"}
|
||||
)
|
||||
target.is_or_has_linked_ancestor = target_type in {
|
||||
"executable",
|
||||
"shared_library",
|
||||
}
|
||||
|
||||
build_file = gyp.common.ParseQualifiedTarget(target_name)[0]
|
||||
if build_file not in build_file_in_files:
|
||||
|
|
@ -427,9 +427,9 @@ def _GenerateTargets(data, target_list, target_dicts, toplevel_dir, files, build
|
|||
|
||||
def _GetUnqualifiedToTargetMapping(all_targets, to_find):
|
||||
"""Returns a tuple of the following:
|
||||
. mapping (dictionary) from unqualified name to Target for all the
|
||||
Targets in |to_find|.
|
||||
. any target names not found. If this is empty all targets were found."""
|
||||
. 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 {}, []
|
||||
|
|
@ -446,15 +446,15 @@ def _GetUnqualifiedToTargetMapping(all_targets, to_find):
|
|||
|
||||
def _DoesTargetDependOnMatchingTargets(target):
|
||||
"""Returns true if |target| or any of its dependencies is one of the
|
||||
targets containing the files supplied as input to analyzer. This updates
|
||||
|matches| of the Targets as it recurses.
|
||||
target: the Target to look for."""
|
||||
targets containing the files supplied as input to analyzer. This updates
|
||||
|matches| of the Targets as it recurses.
|
||||
target: the Target to look for."""
|
||||
if target.match_status == MATCH_STATUS_DOESNT_MATCH:
|
||||
return False
|
||||
if (
|
||||
target.match_status in {MATCH_STATUS_MATCHES,
|
||||
MATCH_STATUS_MATCHES_BY_DEPENDENCY}
|
||||
):
|
||||
if target.match_status in {
|
||||
MATCH_STATUS_MATCHES,
|
||||
MATCH_STATUS_MATCHES_BY_DEPENDENCY,
|
||||
}:
|
||||
return True
|
||||
for dep in target.deps:
|
||||
if _DoesTargetDependOnMatchingTargets(dep):
|
||||
|
|
@ -467,9 +467,9 @@ def _DoesTargetDependOnMatchingTargets(target):
|
|||
|
||||
def _GetTargetsDependingOnMatchingTargets(possible_targets):
|
||||
"""Returns the list of Targets in |possible_targets| that depend (either
|
||||
directly on indirectly) on at least one of the targets containing the files
|
||||
supplied as input to analyzer.
|
||||
possible_targets: targets to search from."""
|
||||
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:
|
||||
|
|
@ -480,11 +480,11 @@ def _GetTargetsDependingOnMatchingTargets(possible_targets):
|
|||
|
||||
def _AddCompileTargets(target, roots, add_if_no_ancestor, result):
|
||||
"""Recurses through all targets that depend on |target|, adding all targets
|
||||
that need to be built (and are in |roots|) to |result|.
|
||||
roots: set of root targets.
|
||||
add_if_no_ancestor: If true and there are no ancestors of |target| then add
|
||||
|target| to |result|. |target| must still be in |roots|.
|
||||
result: targets that need to be built are added here."""
|
||||
that need to be built (and are in |roots|) to |result|.
|
||||
roots: set of root targets.
|
||||
add_if_no_ancestor: If true and there are no ancestors of |target| then add
|
||||
|target| to |result|. |target| must still be in |roots|.
|
||||
result: targets that need to be built are added here."""
|
||||
if target.visited:
|
||||
return
|
||||
|
||||
|
|
@ -537,8 +537,8 @@ def _AddCompileTargets(target, roots, add_if_no_ancestor, result):
|
|||
|
||||
def _GetCompileTargets(matching_targets, supplied_targets):
|
||||
"""Returns the set of Targets that require a build.
|
||||
matching_targets: targets that changed and need to be built.
|
||||
supplied_targets: set of targets supplied to analyzer to search from."""
|
||||
matching_targets: targets that changed and need to be built.
|
||||
supplied_targets: set of targets supplied to analyzer to search from."""
|
||||
result = set()
|
||||
for target in matching_targets:
|
||||
print("finding compile targets for match", target.name)
|
||||
|
|
@ -592,7 +592,7 @@ def _WriteOutput(params, **values):
|
|||
|
||||
def _WasGypIncludeFileModified(params, files):
|
||||
"""Returns true if one of the files in |files| is in the set of included
|
||||
files."""
|
||||
files."""
|
||||
if params["options"].includes:
|
||||
for include in params["options"].includes:
|
||||
if _ToGypPath(os.path.normpath(include)) in files:
|
||||
|
|
@ -608,7 +608,7 @@ def _NamesNotIn(names, mapping):
|
|||
|
||||
def _LookupTargets(names, mapping):
|
||||
"""Returns a list of the mapping[name] for each value in |names| that is in
|
||||
|mapping|."""
|
||||
|mapping|."""
|
||||
return [mapping[name] for name in names if name in mapping]
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -177,9 +177,7 @@ class AndroidMkWriter:
|
|||
self.WriteLn("LOCAL_IS_HOST_MODULE := true")
|
||||
self.WriteLn("LOCAL_MULTILIB := $(GYP_HOST_MULTILIB)")
|
||||
elif sdk_version > 0:
|
||||
self.WriteLn(
|
||||
"LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)"
|
||||
)
|
||||
self.WriteLn("LOCAL_MODULE_TARGET_ARCH := $(TARGET_$(GYP_VAR_PREFIX)ARCH)")
|
||||
self.WriteLn("LOCAL_SDK_VERSION := %s" % sdk_version)
|
||||
|
||||
# Grab output directories; needed for Actions and Rules.
|
||||
|
|
@ -588,7 +586,8 @@ class AndroidMkWriter:
|
|||
local_files = []
|
||||
for source in sources:
|
||||
(root, ext) = os.path.splitext(source)
|
||||
if ("$(gyp_shared_intermediate_dir)" in source
|
||||
if (
|
||||
"$(gyp_shared_intermediate_dir)" in source
|
||||
or "$(gyp_intermediate_dir)" in source
|
||||
or (IsCPPExtension(ext) and ext != local_cpp_extension)
|
||||
):
|
||||
|
|
@ -734,8 +733,7 @@ class AndroidMkWriter:
|
|||
elif self.toolset == "host":
|
||||
path = (
|
||||
"$(call intermediates-dir-for,%s,%s,true,,"
|
||||
"$(GYP_HOST_VAR_PREFIX))"
|
||||
% (self.android_class, self.android_module)
|
||||
"$(GYP_HOST_VAR_PREFIX))" % (self.android_class, self.android_module)
|
||||
)
|
||||
else:
|
||||
path = (
|
||||
|
|
@ -1001,9 +999,9 @@ class AndroidMkWriter:
|
|||
# - i.e. that the resulting path is still inside the project tree. The
|
||||
# path may legitimately have ended up containing just $(LOCAL_PATH), though,
|
||||
# so we don't look for a slash.
|
||||
assert local_path.startswith(
|
||||
"$(LOCAL_PATH)"
|
||||
), f"Path {path} attempts to escape from gyp path {self.path} !)"
|
||||
assert local_path.startswith("$(LOCAL_PATH)"), (
|
||||
f"Path {path} attempts to escape from gyp path {self.path} !)"
|
||||
)
|
||||
return local_path
|
||||
|
||||
def ExpandInputRoot(self, template, expansion, dirname):
|
||||
|
|
@ -1045,9 +1043,9 @@ def GenerateOutput(target_list, target_dicts, data, params):
|
|||
base_path = gyp.common.RelativePath(os.path.dirname(build_file), options.depth)
|
||||
# We write the file in the base_path directory.
|
||||
output_file = os.path.join(options.depth, base_path, base_name)
|
||||
assert (
|
||||
not options.generator_output
|
||||
), "The Android backend does not support options.generator_output."
|
||||
assert not options.generator_output, (
|
||||
"The Android backend does not support options.generator_output."
|
||||
)
|
||||
base_path = gyp.common.RelativePath(
|
||||
os.path.dirname(build_file), options.toplevel_dir
|
||||
)
|
||||
|
|
@ -1067,9 +1065,9 @@ def GenerateOutput(target_list, target_dicts, data, params):
|
|||
|
||||
makefile_name = "GypAndroid" + options.suffix + ".mk"
|
||||
makefile_path = os.path.join(options.toplevel_dir, makefile_name)
|
||||
assert (
|
||||
not options.generator_output
|
||||
), "The Android backend does not support options.generator_output."
|
||||
assert not options.generator_output, (
|
||||
"The Android backend does not support options.generator_output."
|
||||
)
|
||||
gyp.common.EnsureDirExists(makefile_path)
|
||||
root_makefile = open(makefile_path, "w")
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ not be able to find the header file directories described in the generated
|
|||
CMakeLists.txt file.
|
||||
"""
|
||||
|
||||
|
||||
import multiprocessing
|
||||
import os
|
||||
import signal
|
||||
|
|
@ -97,11 +96,11 @@ def Linkable(filename):
|
|||
def NormjoinPathForceCMakeSource(base_path, rel_path):
|
||||
"""Resolves rel_path against base_path and returns the result.
|
||||
|
||||
If rel_path is an absolute path it is returned unchanged.
|
||||
Otherwise it is resolved against base_path and normalized.
|
||||
If the result is a relative path, it is forced to be relative to the
|
||||
CMakeLists.txt.
|
||||
"""
|
||||
If rel_path is an absolute path it is returned unchanged.
|
||||
Otherwise it is resolved against base_path and normalized.
|
||||
If the result is a relative path, it is forced to be relative to the
|
||||
CMakeLists.txt.
|
||||
"""
|
||||
if os.path.isabs(rel_path):
|
||||
return rel_path
|
||||
if any(rel_path.startswith(var) for var in FULL_PATH_VARS):
|
||||
|
|
@ -114,10 +113,10 @@ def NormjoinPathForceCMakeSource(base_path, rel_path):
|
|||
|
||||
def NormjoinPath(base_path, rel_path):
|
||||
"""Resolves rel_path against base_path and returns the result.
|
||||
TODO: what is this really used for?
|
||||
If rel_path begins with '$' it is returned unchanged.
|
||||
Otherwise it is resolved against base_path if relative, then normalized.
|
||||
"""
|
||||
TODO: what is this really used for?
|
||||
If rel_path begins with '$' it is returned unchanged.
|
||||
Otherwise it is resolved against base_path if relative, then normalized.
|
||||
"""
|
||||
if rel_path.startswith("$") and not rel_path.startswith("${configuration}"):
|
||||
return rel_path
|
||||
return os.path.normpath(os.path.join(base_path, rel_path))
|
||||
|
|
@ -126,19 +125,19 @@ def NormjoinPath(base_path, rel_path):
|
|||
def CMakeStringEscape(a):
|
||||
"""Escapes the string 'a' for use inside a CMake string.
|
||||
|
||||
This means escaping
|
||||
'\' otherwise it may be seen as modifying the next character
|
||||
'"' otherwise it will end the string
|
||||
';' otherwise the string becomes a list
|
||||
This means escaping
|
||||
'\' otherwise it may be seen as modifying the next character
|
||||
'"' otherwise it will end the string
|
||||
';' otherwise the string becomes a list
|
||||
|
||||
The following do not need to be escaped
|
||||
'#' when the lexer is in string state, this does not start a comment
|
||||
The following do not need to be escaped
|
||||
'#' when the lexer is in string state, this does not start a comment
|
||||
|
||||
The following are yet unknown
|
||||
'$' generator variables (like ${obj}) must not be escaped,
|
||||
but text $ should be escaped
|
||||
what is wanted is to know which $ come from generator variables
|
||||
"""
|
||||
The following are yet unknown
|
||||
'$' generator variables (like ${obj}) must not be escaped,
|
||||
but text $ should be escaped
|
||||
what is wanted is to know which $ come from generator variables
|
||||
"""
|
||||
return a.replace("\\", "\\\\").replace(";", "\\;").replace('"', '\\"')
|
||||
|
||||
|
||||
|
|
@ -237,25 +236,25 @@ cmake_target_type_from_gyp_target_type = {
|
|||
def StringToCMakeTargetName(a):
|
||||
"""Converts the given string 'a' to a valid CMake target name.
|
||||
|
||||
All invalid characters are replaced by '_'.
|
||||
Invalid for cmake: ' ', '/', '(', ')', '"'
|
||||
Invalid for make: ':'
|
||||
Invalid for unknown reasons but cause failures: '.'
|
||||
"""
|
||||
All invalid characters are replaced by '_'.
|
||||
Invalid for cmake: ' ', '/', '(', ')', '"'
|
||||
Invalid for make: ':'
|
||||
Invalid for unknown reasons but cause failures: '.'
|
||||
"""
|
||||
return a.translate(_maketrans(' /():."', "_______"))
|
||||
|
||||
|
||||
def WriteActions(target_name, actions, extra_sources, extra_deps, path_to_gyp, output):
|
||||
"""Write CMake for the 'actions' in the target.
|
||||
|
||||
Args:
|
||||
target_name: the name of the CMake target being generated.
|
||||
actions: the Gyp 'actions' dict for this target.
|
||||
extra_sources: [(<cmake_src>, <src>)] to append with generated source files.
|
||||
extra_deps: [<cmake_target>] to append with generated targets.
|
||||
path_to_gyp: relative path from CMakeLists.txt being generated to
|
||||
the Gyp file in which the target being generated is defined.
|
||||
"""
|
||||
Args:
|
||||
target_name: the name of the CMake target being generated.
|
||||
actions: the Gyp 'actions' dict for this target.
|
||||
extra_sources: [(<cmake_src>, <src>)] to append with generated source files.
|
||||
extra_deps: [<cmake_target>] to append with generated targets.
|
||||
path_to_gyp: relative path from CMakeLists.txt being generated to
|
||||
the Gyp file in which the target being generated is defined.
|
||||
"""
|
||||
for action in actions:
|
||||
action_name = StringToCMakeTargetName(action["action_name"])
|
||||
action_target_name = f"{target_name}__{action_name}"
|
||||
|
|
@ -337,14 +336,14 @@ def NormjoinRulePathForceCMakeSource(base_path, rel_path, rule_source):
|
|||
def WriteRules(target_name, rules, extra_sources, extra_deps, path_to_gyp, output):
|
||||
"""Write CMake for the 'rules' in the target.
|
||||
|
||||
Args:
|
||||
target_name: the name of the CMake target being generated.
|
||||
actions: the Gyp 'actions' dict for this target.
|
||||
extra_sources: [(<cmake_src>, <src>)] to append with generated source files.
|
||||
extra_deps: [<cmake_target>] to append with generated targets.
|
||||
path_to_gyp: relative path from CMakeLists.txt being generated to
|
||||
the Gyp file in which the target being generated is defined.
|
||||
"""
|
||||
Args:
|
||||
target_name: the name of the CMake target being generated.
|
||||
actions: the Gyp 'actions' dict for this target.
|
||||
extra_sources: [(<cmake_src>, <src>)] to append with generated source files.
|
||||
extra_deps: [<cmake_target>] to append with generated targets.
|
||||
path_to_gyp: relative path from CMakeLists.txt being generated to
|
||||
the Gyp file in which the target being generated is defined.
|
||||
"""
|
||||
for rule in rules:
|
||||
rule_name = StringToCMakeTargetName(target_name + "__" + rule["rule_name"])
|
||||
|
||||
|
|
@ -455,13 +454,13 @@ def WriteRules(target_name, rules, extra_sources, extra_deps, path_to_gyp, outpu
|
|||
def WriteCopies(target_name, copies, extra_deps, path_to_gyp, output):
|
||||
"""Write CMake for the 'copies' in the target.
|
||||
|
||||
Args:
|
||||
target_name: the name of the CMake target being generated.
|
||||
actions: the Gyp 'actions' dict for this target.
|
||||
extra_deps: [<cmake_target>] to append with generated targets.
|
||||
path_to_gyp: relative path from CMakeLists.txt being generated to
|
||||
the Gyp file in which the target being generated is defined.
|
||||
"""
|
||||
Args:
|
||||
target_name: the name of the CMake target being generated.
|
||||
actions: the Gyp 'actions' dict for this target.
|
||||
extra_deps: [<cmake_target>] to append with generated targets.
|
||||
path_to_gyp: relative path from CMakeLists.txt being generated to
|
||||
the Gyp file in which the target being generated is defined.
|
||||
"""
|
||||
copy_name = target_name + "__copies"
|
||||
|
||||
# CMake gets upset with custom targets with OUTPUT which specify no output.
|
||||
|
|
@ -585,23 +584,23 @@ def CreateCMakeTargetFullName(qualified_target):
|
|||
class CMakeNamer:
|
||||
"""Converts Gyp target names into CMake target names.
|
||||
|
||||
CMake requires that target names be globally unique. One way to ensure
|
||||
this is to fully qualify the names of the targets. Unfortunately, this
|
||||
ends up with all targets looking like "chrome_chrome_gyp_chrome" instead
|
||||
of just "chrome". If this generator were only interested in building, it
|
||||
would be possible to fully qualify all target names, then create
|
||||
unqualified target names which depend on all qualified targets which
|
||||
should have had that name. This is more or less what the 'make' generator
|
||||
does with aliases. However, one goal of this generator is to create CMake
|
||||
files for use with IDEs, and fully qualified names are not as user
|
||||
friendly.
|
||||
CMake requires that target names be globally unique. One way to ensure
|
||||
this is to fully qualify the names of the targets. Unfortunately, this
|
||||
ends up with all targets looking like "chrome_chrome_gyp_chrome" instead
|
||||
of just "chrome". If this generator were only interested in building, it
|
||||
would be possible to fully qualify all target names, then create
|
||||
unqualified target names which depend on all qualified targets which
|
||||
should have had that name. This is more or less what the 'make' generator
|
||||
does with aliases. However, one goal of this generator is to create CMake
|
||||
files for use with IDEs, and fully qualified names are not as user
|
||||
friendly.
|
||||
|
||||
Since target name collision is rare, we do the above only when required.
|
||||
Since target name collision is rare, we do the above only when required.
|
||||
|
||||
Toolset variants are always qualified from the base, as this is required for
|
||||
building. However, it also makes sense for an IDE, as it is possible for
|
||||
defines to be different.
|
||||
"""
|
||||
Toolset variants are always qualified from the base, as this is required for
|
||||
building. However, it also makes sense for an IDE, as it is possible for
|
||||
defines to be different.
|
||||
"""
|
||||
|
||||
def __init__(self, target_list):
|
||||
self.cmake_target_base_names_conflicting = set()
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ def CalculateVariables(default_variables, params):
|
|||
|
||||
def CalculateGeneratorInputInfo(params):
|
||||
"""Calculate the generator specific info that gets fed to input (called by
|
||||
gyp)."""
|
||||
gyp)."""
|
||||
generator_flags = params.get("generator_flags", {})
|
||||
if generator_flags.get("adjust_static_libraries", False):
|
||||
global generator_wants_static_library_dependencies_adjusted
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ def CalculateVariables(default_variables, params):
|
|||
|
||||
def CalculateGeneratorInputInfo(params):
|
||||
"""Calculate the generator specific info that gets fed to input (called by
|
||||
gyp)."""
|
||||
gyp)."""
|
||||
generator_flags = params.get("generator_flags", {})
|
||||
if generator_flags.get("adjust_static_libraries", False):
|
||||
global generator_wants_static_library_dependencies_adjusted
|
||||
|
|
@ -86,10 +86,10 @@ def GetAllIncludeDirectories(
|
|||
):
|
||||
"""Calculate the set of include directories to be used.
|
||||
|
||||
Returns:
|
||||
A list including all the include_dir's specified for every target followed
|
||||
by any include directories that were added as cflag compiler options.
|
||||
"""
|
||||
Returns:
|
||||
A list including all the include_dir's specified for every target followed
|
||||
by any include directories that were added as cflag compiler options.
|
||||
"""
|
||||
|
||||
gyp_includes_set = set()
|
||||
compiler_includes_list = []
|
||||
|
|
@ -178,11 +178,11 @@ def GetAllIncludeDirectories(
|
|||
def GetCompilerPath(target_list, data, options):
|
||||
"""Determine a command that can be used to invoke the compiler.
|
||||
|
||||
Returns:
|
||||
If this is a gyp project that has explicit make settings, try to determine
|
||||
the compiler from that. Otherwise, see if a compiler was specified via the
|
||||
CC_target environment variable.
|
||||
"""
|
||||
Returns:
|
||||
If this is a gyp project that has explicit make settings, try to determine
|
||||
the compiler from that. Otherwise, see if a compiler was specified via the
|
||||
CC_target environment variable.
|
||||
"""
|
||||
# First, see if the compiler is configured in make's settings.
|
||||
build_file, _, _ = gyp.common.ParseQualifiedTarget(target_list[0])
|
||||
make_global_settings_dict = data[build_file].get("make_global_settings", {})
|
||||
|
|
@ -202,10 +202,10 @@ def GetCompilerPath(target_list, data, options):
|
|||
def GetAllDefines(target_list, target_dicts, data, config_name, params, compiler_path):
|
||||
"""Calculate the defines for a project.
|
||||
|
||||
Returns:
|
||||
A dict that includes explicit defines declared in gyp files along with all
|
||||
of the default defines that the compiler uses.
|
||||
"""
|
||||
Returns:
|
||||
A dict that includes explicit defines declared in gyp files along with all
|
||||
of the default defines that the compiler uses.
|
||||
"""
|
||||
|
||||
# Get defines declared in the gyp files.
|
||||
all_defines = {}
|
||||
|
|
@ -373,8 +373,8 @@ def GenerateClasspathFile(
|
|||
target_list, target_dicts, toplevel_dir, toplevel_build, out_name
|
||||
):
|
||||
"""Generates a classpath file suitable for symbol navigation and code
|
||||
completion of Java code (such as in Android projects) by finding all
|
||||
.java and .jar files used as action inputs."""
|
||||
completion of Java code (such as in Android projects) by finding all
|
||||
.java and .jar files used as action inputs."""
|
||||
gyp.common.EnsureDirExists(out_name)
|
||||
result = ET.Element("classpath")
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ The specific formatting of the output generated by this module is subject
|
|||
to change.
|
||||
"""
|
||||
|
||||
|
||||
import pprint
|
||||
|
||||
import gyp.common
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ by the input module.
|
|||
The expected usage is "gyp -f gypsh -D OS=desired_os".
|
||||
"""
|
||||
|
||||
|
||||
import code
|
||||
import sys
|
||||
|
||||
|
|
|
|||
|
|
@ -218,7 +218,7 @@ cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o
|
|||
|
||||
quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@
|
||||
cmd_solink_module = $(LINK.$(TOOLSET)) -bundle $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(filter-out FORCE_DO_CMD, $^) $(LIBS)
|
||||
""" % {'python': sys.executable} # noqa: E501
|
||||
""" % {"python": sys.executable} # noqa: E501
|
||||
|
||||
LINK_COMMANDS_ANDROID = """\
|
||||
quiet_cmd_alink = AR($(TOOLSET)) $@
|
||||
|
|
@ -443,21 +443,27 @@ DEPFLAGS = %(makedep_args)s -MF $(depfile).raw
|
|||
define fixup_dep
|
||||
# The depfile may not exist if the input file didn't have any #includes.
|
||||
touch $(depfile).raw
|
||||
# Fixup path as in (1).""" +
|
||||
(r"""
|
||||
# Fixup path as in (1)."""
|
||||
+ (
|
||||
r"""
|
||||
sed -e "s|^$(notdir $@)|$@|" -re 's/\\\\([^$$])/\/\1/g' $(depfile).raw >> $(depfile)"""
|
||||
if sys.platform == 'win32' else r"""
|
||||
sed -e "s|^$(notdir $@)|$@|" $(depfile).raw >> $(depfile)""") +
|
||||
r"""
|
||||
if sys.platform == "win32"
|
||||
else r"""
|
||||
sed -e "s|^$(notdir $@)|$@|" $(depfile).raw >> $(depfile)"""
|
||||
)
|
||||
+ r"""
|
||||
# Add extra rules as in (2).
|
||||
# We remove slashes and replace spaces with new lines;
|
||||
# remove blank lines;
|
||||
# delete the first line and append a colon to the remaining lines.""" +
|
||||
("""
|
||||
# delete the first line and append a colon to the remaining lines."""
|
||||
+ (
|
||||
"""
|
||||
sed -e 's/\\\\\\\\$$//' -e 's/\\\\\\\\/\\//g' -e 'y| |\\n|' $(depfile).raw |\\"""
|
||||
if sys.platform == 'win32' else """
|
||||
sed -e 's|\\\\||' -e 'y| |\\n|' $(depfile).raw |\\""") +
|
||||
r"""
|
||||
if sys.platform == "win32"
|
||||
else """
|
||||
sed -e 's|\\\\||' -e 'y| |\\n|' $(depfile).raw |\\"""
|
||||
)
|
||||
+ r"""
|
||||
grep -v '^$$' |\
|
||||
sed -e 1d -e 's|$$|:|' \
|
||||
>> $(depfile)
|
||||
|
|
@ -616,7 +622,7 @@ cmd_mac_package_framework = %(python)s gyp-mac-tool package-framework "$@" $(4)
|
|||
|
||||
quiet_cmd_infoplist = INFOPLIST $@
|
||||
cmd_infoplist = $(CC.$(TOOLSET)) -E -P -Wno-trigraphs -x c $(INFOPLIST_DEFINES) "$<" -o "$@"
|
||||
""" % {'python': sys.executable} # noqa: E501
|
||||
""" % {"python": sys.executable} # noqa: E501
|
||||
|
||||
|
||||
def WriteRootHeaderSuffixRules(writer):
|
||||
|
|
@ -733,11 +739,13 @@ def QuoteIfNecessary(string):
|
|||
string = '"' + string.replace('"', '\\"') + '"'
|
||||
return string
|
||||
|
||||
|
||||
def replace_sep(string):
|
||||
if sys.platform == 'win32':
|
||||
string = string.replace('\\\\', '/').replace('\\', '/')
|
||||
if sys.platform == "win32":
|
||||
string = string.replace("\\\\", "/").replace("\\", "/")
|
||||
return string
|
||||
|
||||
|
||||
def StringToMakefileVariable(string):
|
||||
"""Convert a string to a value that is acceptable as a make variable name."""
|
||||
return re.sub("[^a-zA-Z0-9_]", "_", string)
|
||||
|
|
@ -1439,9 +1447,7 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
|
|||
|
||||
for obj in objs:
|
||||
assert " " not in obj, "Spaces in object filenames not supported (%s)" % obj
|
||||
self.WriteLn(
|
||||
"# Add to the list of files we specially track dependencies for."
|
||||
)
|
||||
self.WriteLn("# Add to the list of files we specially track dependencies for.")
|
||||
self.WriteLn("all_deps += $(OBJS)")
|
||||
self.WriteLn()
|
||||
|
||||
|
|
@ -1498,7 +1504,8 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
|
|||
"$(OBJS): GYP_OBJCFLAGS := "
|
||||
"$(DEFS_$(BUILDTYPE)) "
|
||||
"$(INCS_$(BUILDTYPE)) "
|
||||
"%s " % precompiled_header.GetInclude("m")
|
||||
"%s "
|
||||
% precompiled_header.GetInclude("m")
|
||||
+ "$(CFLAGS_$(BUILDTYPE)) "
|
||||
"$(CFLAGS_C_$(BUILDTYPE)) "
|
||||
"$(CFLAGS_OBJC_$(BUILDTYPE))"
|
||||
|
|
@ -1507,7 +1514,8 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
|
|||
"$(OBJS): GYP_OBJCXXFLAGS := "
|
||||
"$(DEFS_$(BUILDTYPE)) "
|
||||
"$(INCS_$(BUILDTYPE)) "
|
||||
"%s " % precompiled_header.GetInclude("mm")
|
||||
"%s "
|
||||
% precompiled_header.GetInclude("mm")
|
||||
+ "$(CFLAGS_$(BUILDTYPE)) "
|
||||
"$(CFLAGS_CC_$(BUILDTYPE)) "
|
||||
"$(CFLAGS_OBJCC_$(BUILDTYPE))"
|
||||
|
|
@ -2383,9 +2391,13 @@ def WriteAutoRegenerationRule(params, root_makefile, makefile_name, build_files)
|
|||
"deps": replace_sep(
|
||||
" ".join(sorted(SourceifyAndQuoteSpaces(bf) for bf in build_files))
|
||||
),
|
||||
"cmd": replace_sep(gyp.common.EncodePOSIXShellList(
|
||||
[gyp_binary, "-fmake"] + gyp.RegenerateFlags(options) + build_files_args
|
||||
)),
|
||||
"cmd": replace_sep(
|
||||
gyp.common.EncodePOSIXShellList(
|
||||
[gyp_binary, "-fmake"]
|
||||
+ gyp.RegenerateFlags(options)
|
||||
+ build_files_args
|
||||
)
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
|
|
@ -2458,8 +2470,8 @@ def GenerateOutput(target_list, target_dicts, data, params):
|
|||
# wasm-ld doesn't support --start-group/--end-group
|
||||
link_commands = LINK_COMMANDS_LINUX
|
||||
if flavor in ["wasi", "wasm"]:
|
||||
link_commands = link_commands.replace(' -Wl,--start-group', '').replace(
|
||||
' -Wl,--end-group', ''
|
||||
link_commands = link_commands.replace(" -Wl,--start-group", "").replace(
|
||||
" -Wl,--end-group", ""
|
||||
)
|
||||
|
||||
CC_target = replace_sep(GetEnvironFallback(("CC_target", "CC"), "$(CC)"))
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -3,7 +3,7 @@
|
|||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
""" Unit tests for the msvs.py file. """
|
||||
"""Unit tests for the msvs.py file."""
|
||||
|
||||
import unittest
|
||||
from io import StringIO
|
||||
|
|
|
|||
|
|
@ -1303,7 +1303,7 @@ class NinjaWriter:
|
|||
ninja_file.build(gch, cmd, input, variables=[(var_name, lang_flag)])
|
||||
|
||||
def WriteLink(self, spec, config_name, config, link_deps, compile_deps):
|
||||
"""Write out a link step. Fills out target.binary. """
|
||||
"""Write out a link step. Fills out target.binary."""
|
||||
if self.flavor != "mac" or len(self.archs) == 1:
|
||||
return self.WriteLinkForArch(
|
||||
self.ninja, spec, config_name, config, link_deps, compile_deps
|
||||
|
|
@ -1347,7 +1347,7 @@ class NinjaWriter:
|
|||
def WriteLinkForArch(
|
||||
self, ninja_file, spec, config_name, config, link_deps, compile_deps, arch=None
|
||||
):
|
||||
"""Write out a link step. Fills out target.binary. """
|
||||
"""Write out a link step. Fills out target.binary."""
|
||||
command = {
|
||||
"executable": "link",
|
||||
"loadable_module": "solink_module",
|
||||
|
|
@ -1755,11 +1755,9 @@ class NinjaWriter:
|
|||
+ " && ".join([ninja_syntax.escape(command) for command in postbuilds])
|
||||
)
|
||||
command_string = (
|
||||
commands
|
||||
+ "); G=$$?; "
|
||||
commands + "); G=$$?; "
|
||||
# Remove the final output if any postbuild failed.
|
||||
"((exit $$G) || rm -rf %s) " % output
|
||||
+ "&& exit $$G)"
|
||||
"((exit $$G) || rm -rf %s) " % output + "&& exit $$G)"
|
||||
)
|
||||
if is_command_start:
|
||||
return "(" + command_string + " && "
|
||||
|
|
@ -1948,7 +1946,8 @@ class NinjaWriter:
|
|||
)
|
||||
else:
|
||||
rspfile_content = gyp.msvs_emulation.EncodeRspFileList(
|
||||
args, win_shell_flags.quote)
|
||||
args, win_shell_flags.quote
|
||||
)
|
||||
command = (
|
||||
"%s gyp-win-tool action-wrapper $arch " % sys.executable
|
||||
+ rspfile
|
||||
|
|
@ -2085,6 +2084,7 @@ def GetDefaultConcurrentLinks():
|
|||
return pool_size
|
||||
|
||||
if sys.platform in ("win32", "cygwin"):
|
||||
|
||||
class MEMORYSTATUSEX(ctypes.Structure):
|
||||
_fields_ = [
|
||||
("dwLength", ctypes.c_ulong),
|
||||
|
|
@ -2104,8 +2104,8 @@ def GetDefaultConcurrentLinks():
|
|||
|
||||
# VS 2015 uses 20% more working set than VS 2013 and can consume all RAM
|
||||
# on a 64 GiB machine.
|
||||
mem_limit = max(1, stat.ullTotalPhys // (5 * (2 ** 30))) # total / 5GiB
|
||||
hard_cap = max(1, int(os.environ.get("GYP_LINK_CONCURRENCY_MAX") or 2 ** 32))
|
||||
mem_limit = max(1, stat.ullTotalPhys // (5 * (2**30))) # total / 5GiB
|
||||
hard_cap = max(1, int(os.environ.get("GYP_LINK_CONCURRENCY_MAX") or 2**32))
|
||||
return min(mem_limit, hard_cap)
|
||||
elif sys.platform.startswith("linux"):
|
||||
if os.path.exists("/proc/meminfo"):
|
||||
|
|
@ -2116,14 +2116,14 @@ def GetDefaultConcurrentLinks():
|
|||
if not match:
|
||||
continue
|
||||
# Allow 8Gb per link on Linux because Gold is quite memory hungry
|
||||
return max(1, int(match.group(1)) // (8 * (2 ** 20)))
|
||||
return max(1, int(match.group(1)) // (8 * (2**20)))
|
||||
return 1
|
||||
elif sys.platform == "darwin":
|
||||
try:
|
||||
avail_bytes = int(subprocess.check_output(["sysctl", "-n", "hw.memsize"]))
|
||||
# A static library debug build of Chromium's unit_tests takes ~2.7GB, so
|
||||
# 4GB per ld process allows for some more bloat.
|
||||
return max(1, avail_bytes // (4 * (2 ** 30))) # total / 4GB
|
||||
return max(1, avail_bytes // (4 * (2**30))) # total / 4GB
|
||||
except subprocess.CalledProcessError:
|
||||
return 1
|
||||
else:
|
||||
|
|
@ -2411,8 +2411,7 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params, config_name
|
|||
"cc_s",
|
||||
description="CC $out",
|
||||
command=(
|
||||
"$cc $defines $includes $cflags $cflags_c "
|
||||
"$cflags_pch_c -c $in -o $out"
|
||||
"$cc $defines $includes $cflags $cflags_c $cflags_pch_c -c $in -o $out"
|
||||
),
|
||||
)
|
||||
master_ninja.rule(
|
||||
|
|
@ -2523,8 +2522,7 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params, config_name
|
|||
"solink",
|
||||
description="SOLINK $lib",
|
||||
restat=True,
|
||||
command=mtime_preserving_solink_base
|
||||
% {"suffix": "@$link_file_list"},
|
||||
command=mtime_preserving_solink_base % {"suffix": "@$link_file_list"},
|
||||
rspfile="$link_file_list",
|
||||
rspfile_content=(
|
||||
"-Wl,--whole-archive $in $solibs -Wl,--no-whole-archive $libs"
|
||||
|
|
@ -2709,7 +2707,7 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params, config_name
|
|||
command="$env %(python)s gyp-mac-tool compile-ios-framework-header-map "
|
||||
"$out $framework $in && $env %(python)s gyp-mac-tool "
|
||||
"copy-ios-framework-headers $framework $copy_headers"
|
||||
% {'python': sys.executable},
|
||||
% {"python": sys.executable},
|
||||
)
|
||||
master_ninja.rule(
|
||||
"mac_tool",
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
""" Unit tests for the ninja.py file. """
|
||||
"""Unit tests for the ninja.py file."""
|
||||
|
||||
import sys
|
||||
import unittest
|
||||
|
|
|
|||
|
|
@ -564,12 +564,12 @@ _xcode_variable_re = re.compile(r"(\$\((.*?)\))")
|
|||
def ExpandXcodeVariables(string, expansions):
|
||||
"""Expands Xcode-style $(VARIABLES) in string per the expansions dict.
|
||||
|
||||
In some rare cases, it is appropriate to expand Xcode variables when a
|
||||
project file is generated. For any substring $(VAR) in string, if VAR is a
|
||||
key in the expansions dict, $(VAR) will be replaced with expansions[VAR].
|
||||
Any $(VAR) substring in string for which VAR is not a key in the expansions
|
||||
dict will remain in the returned string.
|
||||
"""
|
||||
In some rare cases, it is appropriate to expand Xcode variables when a
|
||||
project file is generated. For any substring $(VAR) in string, if VAR is a
|
||||
key in the expansions dict, $(VAR) will be replaced with expansions[VAR].
|
||||
Any $(VAR) substring in string for which VAR is not a key in the expansions
|
||||
dict will remain in the returned string.
|
||||
"""
|
||||
|
||||
matches = _xcode_variable_re.findall(string)
|
||||
if matches is None:
|
||||
|
|
@ -592,9 +592,9 @@ _xcode_define_re = re.compile(r"([\\\"\' ])")
|
|||
|
||||
def EscapeXcodeDefine(s):
|
||||
"""We must escape the defines that we give to XCode so that it knows not to
|
||||
split on spaces and to respect backslash and quote literals. However, we
|
||||
must not quote the define, or Xcode will incorrectly interpret variables
|
||||
especially $(inherited)."""
|
||||
split on spaces and to respect backslash and quote literals. However, we
|
||||
must not quote the define, or Xcode will incorrectly interpret variables
|
||||
especially $(inherited)."""
|
||||
return re.sub(_xcode_define_re, r"\\\1", s)
|
||||
|
||||
|
||||
|
|
@ -679,9 +679,9 @@ def GenerateOutput(target_list, target_dicts, data, params):
|
|||
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["LastTestingUpgradeCheck"] = (
|
||||
upgrade_check_project_version
|
||||
)
|
||||
project_attributes["LastSwiftUpdateCheck"] = upgrade_check_project_version
|
||||
pbxp.SetProperty("attributes", project_attributes)
|
||||
|
||||
|
|
@ -734,8 +734,7 @@ def GenerateOutput(target_list, target_dicts, data, params):
|
|||
"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+extension+bundle": "com.apple.product-type.watchkit-extension", # noqa: E501
|
||||
"executable+watch+bundle": "com.apple.product-type.application.watchapp",
|
||||
"mac_kernel_extension+bundle": "com.apple.product-type.kernel-extension",
|
||||
}
|
||||
|
|
@ -780,8 +779,7 @@ def GenerateOutput(target_list, target_dicts, data, params):
|
|||
type_bundle_key += "+watch+extension+bundle"
|
||||
elif is_watch_app:
|
||||
assert is_bundle, (
|
||||
"ios_watch_app flag requires mac_bundle "
|
||||
"(target %s)" % target_name
|
||||
"ios_watch_app flag requires mac_bundle (target %s)" % target_name
|
||||
)
|
||||
type_bundle_key += "+watch+bundle"
|
||||
elif is_bundle:
|
||||
|
|
@ -1103,7 +1101,7 @@ def GenerateOutput(target_list, target_dicts, data, params):
|
|||
eol = " \\"
|
||||
makefile.write(f" {concrete_output}{eol}\n")
|
||||
|
||||
for (rule_source, concrete_outputs, message, action) in zip(
|
||||
for rule_source, concrete_outputs, message, action in zip(
|
||||
rule["rule_sources"],
|
||||
concrete_outputs_by_rule_source,
|
||||
messages,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
""" Unit tests for the xcode.py file. """
|
||||
"""Unit tests for the xcode.py file."""
|
||||
|
||||
import sys
|
||||
import unittest
|
||||
|
|
|
|||
|
|
@ -139,21 +139,21 @@ generator_filelist_paths = None
|
|||
def GetIncludedBuildFiles(build_file_path, aux_data, included=None):
|
||||
"""Return a list of all build files included into build_file_path.
|
||||
|
||||
The returned list will contain build_file_path as well as all other files
|
||||
that it included, either directly or indirectly. Note that the list may
|
||||
contain files that were included into a conditional section that evaluated
|
||||
to false and was not merged into build_file_path's dict.
|
||||
The returned list will contain build_file_path as well as all other files
|
||||
that it included, either directly or indirectly. Note that the list may
|
||||
contain files that were included into a conditional section that evaluated
|
||||
to false and was not merged into build_file_path's dict.
|
||||
|
||||
aux_data is a dict containing a key for each build file or included build
|
||||
file. Those keys provide access to dicts whose "included" keys contain
|
||||
lists of all other files included by the build file.
|
||||
aux_data is a dict containing a key for each build file or included build
|
||||
file. Those keys provide access to dicts whose "included" keys contain
|
||||
lists of all other files included by the build file.
|
||||
|
||||
included should be left at its default None value by external callers. It
|
||||
is used for recursion.
|
||||
included should be left at its default None value by external callers. It
|
||||
is used for recursion.
|
||||
|
||||
The returned list will not contain any duplicate entries. Each build file
|
||||
in the list will be relative to the current directory.
|
||||
"""
|
||||
The returned list will not contain any duplicate entries. Each build file
|
||||
in the list will be relative to the current directory.
|
||||
"""
|
||||
|
||||
if included is None:
|
||||
included = []
|
||||
|
|
@ -171,10 +171,10 @@ def GetIncludedBuildFiles(build_file_path, aux_data, included=None):
|
|||
|
||||
def CheckedEval(file_contents):
|
||||
"""Return the eval of a gyp file.
|
||||
The gyp file is restricted to dictionaries and lists only, and
|
||||
repeated keys are not allowed.
|
||||
Note that this is slower than eval() is.
|
||||
"""
|
||||
The gyp file is restricted to dictionaries and lists only, and
|
||||
repeated keys are not allowed.
|
||||
Note that this is slower than eval() is.
|
||||
"""
|
||||
|
||||
syntax_tree = ast.parse(file_contents)
|
||||
assert isinstance(syntax_tree, ast.Module)
|
||||
|
|
@ -508,9 +508,9 @@ def CallLoadTargetBuildFile(
|
|||
):
|
||||
"""Wrapper around LoadTargetBuildFile for parallel processing.
|
||||
|
||||
This wrapper is used when LoadTargetBuildFile is executed in
|
||||
a worker process.
|
||||
"""
|
||||
This wrapper is used when LoadTargetBuildFile is executed in
|
||||
a worker process.
|
||||
"""
|
||||
|
||||
try:
|
||||
signal.signal(signal.SIGINT, signal.SIG_IGN)
|
||||
|
|
@ -559,10 +559,10 @@ class ParallelProcessingError(Exception):
|
|||
class ParallelState:
|
||||
"""Class to keep track of state when processing input files in parallel.
|
||||
|
||||
If build files are loaded in parallel, use this to keep track of
|
||||
state during farming out and processing parallel jobs. It's stored
|
||||
in a global so that the callback function can have access to it.
|
||||
"""
|
||||
If build files are loaded in parallel, use this to keep track of
|
||||
state during farming out and processing parallel jobs. It's stored
|
||||
in a global so that the callback function can have access to it.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
# The multiprocessing pool.
|
||||
|
|
@ -584,8 +584,7 @@ class ParallelState:
|
|||
self.error = False
|
||||
|
||||
def LoadTargetBuildFileCallback(self, result):
|
||||
"""Handle the results of running LoadTargetBuildFile in another process.
|
||||
"""
|
||||
"""Handle the results of running LoadTargetBuildFile in another process."""
|
||||
self.condition.acquire()
|
||||
if not result:
|
||||
self.error = True
|
||||
|
|
@ -692,8 +691,8 @@ def FindEnclosingBracketGroup(input_str):
|
|||
def IsStrCanonicalInt(string):
|
||||
"""Returns True if |string| is in its canonical integer form.
|
||||
|
||||
The canonical form is such that str(int(string)) == string.
|
||||
"""
|
||||
The canonical form is such that str(int(string)) == string.
|
||||
"""
|
||||
if isinstance(string, str):
|
||||
# This function is called a lot so for maximum performance, avoid
|
||||
# involving regexps which would otherwise make the code much
|
||||
|
|
@ -870,8 +869,9 @@ def ExpandVariables(input, phase, variables, build_file):
|
|||
# This works around actions/rules which have more inputs than will
|
||||
# fit on the command line.
|
||||
if file_list:
|
||||
contents_list = (contents if isinstance(contents, list)
|
||||
else contents.split(" "))
|
||||
contents_list = (
|
||||
contents if isinstance(contents, list) else contents.split(" ")
|
||||
)
|
||||
replacement = contents_list[0]
|
||||
if os.path.isabs(replacement):
|
||||
raise GypError('| cannot handle absolute paths, got "%s"' % replacement)
|
||||
|
|
@ -934,7 +934,6 @@ def ExpandVariables(input, phase, variables, build_file):
|
|||
os.chdir(build_file_dir)
|
||||
sys.path.append(os.getcwd())
|
||||
try:
|
||||
|
||||
parsed_contents = shlex.split(contents)
|
||||
try:
|
||||
py_module = __import__(parsed_contents[0])
|
||||
|
|
@ -965,7 +964,7 @@ def ExpandVariables(input, phase, variables, build_file):
|
|||
stdout=subprocess.PIPE,
|
||||
shell=use_shell,
|
||||
cwd=build_file_dir,
|
||||
check=False
|
||||
check=False,
|
||||
)
|
||||
except Exception as e:
|
||||
raise GypError(
|
||||
|
|
@ -1003,9 +1002,7 @@ def ExpandVariables(input, phase, variables, build_file):
|
|||
# ],
|
||||
replacement = []
|
||||
else:
|
||||
raise GypError(
|
||||
"Undefined variable " + contents + " in " + build_file
|
||||
)
|
||||
raise GypError("Undefined variable " + contents + " in " + build_file)
|
||||
else:
|
||||
replacement = variables[contents]
|
||||
|
||||
|
|
@ -1114,7 +1111,7 @@ cached_conditions_asts = {}
|
|||
|
||||
def EvalCondition(condition, conditions_key, phase, variables, build_file):
|
||||
"""Returns the dict that should be used or None if the result was
|
||||
that nothing should be used."""
|
||||
that nothing should be used."""
|
||||
if not isinstance(condition, list):
|
||||
raise GypError(conditions_key + " must be a list")
|
||||
if len(condition) < 2:
|
||||
|
|
@ -1159,7 +1156,7 @@ def EvalCondition(condition, conditions_key, phase, variables, build_file):
|
|||
|
||||
def EvalSingleCondition(cond_expr, true_dict, false_dict, phase, variables, build_file):
|
||||
"""Returns true_dict if cond_expr evaluates to true, and false_dict
|
||||
otherwise."""
|
||||
otherwise."""
|
||||
# Do expansions on the condition itself. Since the condition can naturally
|
||||
# contain variable references without needing to resort to GYP expansion
|
||||
# syntax, this is of dubious value for variables, but someone might want to
|
||||
|
|
@ -1289,10 +1286,10 @@ def ProcessVariablesAndConditionsInDict(
|
|||
):
|
||||
"""Handle all variable and command expansion and conditional evaluation.
|
||||
|
||||
This function is the public entry point for all variable expansions and
|
||||
conditional evaluations. The variables_in dictionary will not be modified
|
||||
by this function.
|
||||
"""
|
||||
This function is the public entry point for all variable expansions and
|
||||
conditional evaluations. The variables_in dictionary will not be modified
|
||||
by this function.
|
||||
"""
|
||||
|
||||
# Make a copy of the variables_in dict that can be modified during the
|
||||
# loading of automatics and the loading of the variables dict.
|
||||
|
|
@ -1441,15 +1438,15 @@ def ProcessVariablesAndConditionsInList(the_list, phase, variables, build_file):
|
|||
def BuildTargetsDict(data):
|
||||
"""Builds a dict mapping fully-qualified target names to their target dicts.
|
||||
|
||||
|data| is a dict mapping loaded build files by pathname relative to the
|
||||
current directory. Values in |data| are build file contents. For each
|
||||
|data| value with a "targets" key, the value of the "targets" key is taken
|
||||
as a list containing target dicts. Each target's fully-qualified name is
|
||||
constructed from the pathname of the build file (|data| key) and its
|
||||
"target_name" property. These fully-qualified names are used as the keys
|
||||
in the returned dict. These keys provide access to the target dicts,
|
||||
the dicts in the "targets" lists.
|
||||
"""
|
||||
|data| is a dict mapping loaded build files by pathname relative to the
|
||||
current directory. Values in |data| are build file contents. For each
|
||||
|data| value with a "targets" key, the value of the "targets" key is taken
|
||||
as a list containing target dicts. Each target's fully-qualified name is
|
||||
constructed from the pathname of the build file (|data| key) and its
|
||||
"target_name" property. These fully-qualified names are used as the keys
|
||||
in the returned dict. These keys provide access to the target dicts,
|
||||
the dicts in the "targets" lists.
|
||||
"""
|
||||
|
||||
targets = {}
|
||||
for build_file in data["target_build_files"]:
|
||||
|
|
@ -1467,13 +1464,13 @@ def BuildTargetsDict(data):
|
|||
def QualifyDependencies(targets):
|
||||
"""Make dependency links fully-qualified relative to the current directory.
|
||||
|
||||
|targets| is a dict mapping fully-qualified target names to their target
|
||||
dicts. For each target in this dict, keys known to contain dependency
|
||||
links are examined, and any dependencies referenced will be rewritten
|
||||
so that they are fully-qualified and relative to the current directory.
|
||||
All rewritten dependencies are suitable for use as keys to |targets| or a
|
||||
similar dict.
|
||||
"""
|
||||
|targets| is a dict mapping fully-qualified target names to their target
|
||||
dicts. For each target in this dict, keys known to contain dependency
|
||||
links are examined, and any dependencies referenced will be rewritten
|
||||
so that they are fully-qualified and relative to the current directory.
|
||||
All rewritten dependencies are suitable for use as keys to |targets| or a
|
||||
similar dict.
|
||||
"""
|
||||
|
||||
all_dependency_sections = [
|
||||
dep + op for dep in dependency_sections for op in ("", "!", "/")
|
||||
|
|
@ -1516,18 +1513,18 @@ def QualifyDependencies(targets):
|
|||
def ExpandWildcardDependencies(targets, data):
|
||||
"""Expands dependencies specified as build_file:*.
|
||||
|
||||
For each target in |targets|, examines sections containing links to other
|
||||
targets. If any such section contains a link of the form build_file:*, it
|
||||
is taken as a wildcard link, and is expanded to list each target in
|
||||
build_file. The |data| dict provides access to build file dicts.
|
||||
For each target in |targets|, examines sections containing links to other
|
||||
targets. If any such section contains a link of the form build_file:*, it
|
||||
is taken as a wildcard link, and is expanded to list each target in
|
||||
build_file. The |data| dict provides access to build file dicts.
|
||||
|
||||
Any target that does not wish to be included by wildcard can provide an
|
||||
optional "suppress_wildcard" key in its target dict. When present and
|
||||
true, a wildcard dependency link will not include such targets.
|
||||
Any target that does not wish to be included by wildcard can provide an
|
||||
optional "suppress_wildcard" key in its target dict. When present and
|
||||
true, a wildcard dependency link will not include such targets.
|
||||
|
||||
All dependency names, including the keys to |targets| and the values in each
|
||||
dependency list, must be qualified when this function is called.
|
||||
"""
|
||||
All dependency names, including the keys to |targets| and the values in each
|
||||
dependency list, must be qualified when this function is called.
|
||||
"""
|
||||
|
||||
for target, target_dict in targets.items():
|
||||
target_build_file = gyp.common.BuildFile(target)
|
||||
|
|
@ -1573,14 +1570,10 @@ def ExpandWildcardDependencies(targets, data):
|
|||
if int(dependency_target_dict.get("suppress_wildcard", False)):
|
||||
continue
|
||||
dependency_target_name = dependency_target_dict["target_name"]
|
||||
if (
|
||||
dependency_target not in {"*", dependency_target_name}
|
||||
):
|
||||
if dependency_target not in {"*", dependency_target_name}:
|
||||
continue
|
||||
dependency_target_toolset = dependency_target_dict["toolset"]
|
||||
if (
|
||||
dependency_toolset not in {"*", dependency_target_toolset}
|
||||
):
|
||||
if dependency_toolset not in {"*", dependency_target_toolset}:
|
||||
continue
|
||||
dependency = gyp.common.QualifiedTarget(
|
||||
dependency_build_file,
|
||||
|
|
@ -1601,7 +1594,7 @@ def Unify(items):
|
|||
|
||||
def RemoveDuplicateDependencies(targets):
|
||||
"""Makes sure every dependency appears only once in all targets's dependency
|
||||
lists."""
|
||||
lists."""
|
||||
for target_name, target_dict in targets.items():
|
||||
for dependency_key in dependency_sections:
|
||||
dependencies = target_dict.get(dependency_key, [])
|
||||
|
|
@ -1617,25 +1610,21 @@ def Filter(items, item):
|
|||
|
||||
def RemoveSelfDependencies(targets):
|
||||
"""Remove self dependencies from targets that have the prune_self_dependency
|
||||
variable set."""
|
||||
variable set."""
|
||||
for target_name, target_dict in targets.items():
|
||||
for dependency_key in dependency_sections:
|
||||
dependencies = target_dict.get(dependency_key, [])
|
||||
if dependencies:
|
||||
for t in dependencies:
|
||||
if t == target_name and (
|
||||
targets[t]
|
||||
.get("variables", {})
|
||||
.get("prune_self_dependency", 0)
|
||||
targets[t].get("variables", {}).get("prune_self_dependency", 0)
|
||||
):
|
||||
target_dict[dependency_key] = Filter(
|
||||
dependencies, target_name
|
||||
)
|
||||
target_dict[dependency_key] = Filter(dependencies, target_name)
|
||||
|
||||
|
||||
def RemoveLinkDependenciesFromNoneTargets(targets):
|
||||
"""Remove dependencies having the 'link_dependency' attribute from the 'none'
|
||||
targets."""
|
||||
targets."""
|
||||
for target_name, target_dict in targets.items():
|
||||
for dependency_key in dependency_sections:
|
||||
dependencies = target_dict.get(dependency_key, [])
|
||||
|
|
@ -1651,11 +1640,11 @@ def RemoveLinkDependenciesFromNoneTargets(targets):
|
|||
class DependencyGraphNode:
|
||||
"""
|
||||
|
||||
Attributes:
|
||||
ref: A reference to an object that this DependencyGraphNode represents.
|
||||
dependencies: List of DependencyGraphNodes on which this one depends.
|
||||
dependents: List of DependencyGraphNodes that depend on this one.
|
||||
"""
|
||||
Attributes:
|
||||
ref: A reference to an object that this DependencyGraphNode represents.
|
||||
dependencies: List of DependencyGraphNodes on which this one depends.
|
||||
dependents: List of DependencyGraphNodes that depend on this one.
|
||||
"""
|
||||
|
||||
class CircularException(GypError):
|
||||
pass
|
||||
|
|
@ -1721,8 +1710,8 @@ class DependencyGraphNode:
|
|||
|
||||
def FindCycles(self):
|
||||
"""
|
||||
Returns a list of cycles in the graph, where each cycle is its own list.
|
||||
"""
|
||||
Returns a list of cycles in the graph, where each cycle is its own list.
|
||||
"""
|
||||
results = []
|
||||
visited = set()
|
||||
|
||||
|
|
@ -1753,21 +1742,21 @@ class DependencyGraphNode:
|
|||
|
||||
def _AddImportedDependencies(self, targets, dependencies=None):
|
||||
"""Given a list of direct dependencies, adds indirect dependencies that
|
||||
other dependencies have declared to export their settings.
|
||||
other dependencies have declared to export their settings.
|
||||
|
||||
This method does not operate on self. Rather, it operates on the list
|
||||
of dependencies in the |dependencies| argument. For each dependency in
|
||||
that list, if any declares that it exports the settings of one of its
|
||||
own dependencies, those dependencies whose settings are "passed through"
|
||||
are added to the list. As new items are added to the list, they too will
|
||||
be processed, so it is possible to import settings through multiple levels
|
||||
of dependencies.
|
||||
This method does not operate on self. Rather, it operates on the list
|
||||
of dependencies in the |dependencies| argument. For each dependency in
|
||||
that list, if any declares that it exports the settings of one of its
|
||||
own dependencies, those dependencies whose settings are "passed through"
|
||||
are added to the list. As new items are added to the list, they too will
|
||||
be processed, so it is possible to import settings through multiple levels
|
||||
of dependencies.
|
||||
|
||||
This method is not terribly useful on its own, it depends on being
|
||||
"primed" with a list of direct dependencies such as one provided by
|
||||
DirectDependencies. DirectAndImportedDependencies is intended to be the
|
||||
public entry point.
|
||||
"""
|
||||
This method is not terribly useful on its own, it depends on being
|
||||
"primed" with a list of direct dependencies such as one provided by
|
||||
DirectDependencies. DirectAndImportedDependencies is intended to be the
|
||||
public entry point.
|
||||
"""
|
||||
|
||||
if dependencies is None:
|
||||
dependencies = []
|
||||
|
|
@ -1795,9 +1784,9 @@ class DependencyGraphNode:
|
|||
|
||||
def DirectAndImportedDependencies(self, targets, dependencies=None):
|
||||
"""Returns a list of a target's direct dependencies and all indirect
|
||||
dependencies that a dependency has advertised settings should be exported
|
||||
through the dependency for.
|
||||
"""
|
||||
dependencies that a dependency has advertised settings should be exported
|
||||
through the dependency for.
|
||||
"""
|
||||
|
||||
dependencies = self.DirectDependencies(dependencies)
|
||||
return self._AddImportedDependencies(targets, dependencies)
|
||||
|
|
@ -1823,19 +1812,19 @@ class DependencyGraphNode:
|
|||
self, targets, include_shared_libraries, dependencies=None, initial=True
|
||||
):
|
||||
"""Returns an OrderedSet of dependency targets that are linked
|
||||
into this target.
|
||||
into this target.
|
||||
|
||||
This function has a split personality, depending on the setting of
|
||||
|initial|. Outside callers should always leave |initial| at its default
|
||||
setting.
|
||||
This function has a split personality, depending on the setting of
|
||||
|initial|. Outside callers should always leave |initial| at its default
|
||||
setting.
|
||||
|
||||
When adding a target to the list of dependencies, this function will
|
||||
recurse into itself with |initial| set to False, to collect dependencies
|
||||
that are linked into the linkable target for which the list is being built.
|
||||
When adding a target to the list of dependencies, this function will
|
||||
recurse into itself with |initial| set to False, to collect dependencies
|
||||
that are linked into the linkable target for which the list is being built.
|
||||
|
||||
If |include_shared_libraries| is False, the resulting dependencies will not
|
||||
include shared_library targets that are linked into this target.
|
||||
"""
|
||||
If |include_shared_libraries| is False, the resulting dependencies will not
|
||||
include shared_library targets that are linked into this target.
|
||||
"""
|
||||
if dependencies is None:
|
||||
# Using a list to get ordered output and a set to do fast "is it
|
||||
# already added" checks.
|
||||
|
|
@ -1917,9 +1906,9 @@ class DependencyGraphNode:
|
|||
|
||||
def DependenciesForLinkSettings(self, targets):
|
||||
"""
|
||||
Returns a list of dependency targets whose link_settings should be merged
|
||||
into this target.
|
||||
"""
|
||||
Returns a list of dependency targets whose link_settings should be merged
|
||||
into this target.
|
||||
"""
|
||||
|
||||
# TODO(sbaig) Currently, chrome depends on the bug that shared libraries'
|
||||
# link_settings are propagated. So for now, we will allow it, unless the
|
||||
|
|
@ -1932,8 +1921,8 @@ class DependencyGraphNode:
|
|||
|
||||
def DependenciesToLinkAgainst(self, targets):
|
||||
"""
|
||||
Returns a list of dependency targets that are linked into this target.
|
||||
"""
|
||||
Returns a list of dependency targets that are linked into this target.
|
||||
"""
|
||||
return self._LinkDependenciesInternal(targets, True)
|
||||
|
||||
|
||||
|
|
@ -2446,7 +2435,7 @@ def SetUpConfigurations(target, target_dict):
|
|||
|
||||
merged_configurations = {}
|
||||
configs = target_dict["configurations"]
|
||||
for (configuration, old_configuration_dict) in configs.items():
|
||||
for configuration, old_configuration_dict in configs.items():
|
||||
# Skip abstract configurations (saves work only).
|
||||
if old_configuration_dict.get("abstract"):
|
||||
continue
|
||||
|
|
@ -2454,7 +2443,7 @@ def SetUpConfigurations(target, target_dict):
|
|||
# Get the inheritance relationship right by making a copy of the target
|
||||
# dict.
|
||||
new_configuration_dict = {}
|
||||
for (key, target_val) in target_dict.items():
|
||||
for key, target_val in target_dict.items():
|
||||
key_ext = key[-1:]
|
||||
key_base = key[:-1] if key_ext in key_suffixes else key
|
||||
if key_base not in non_configuration_keys:
|
||||
|
|
@ -2502,25 +2491,25 @@ def SetUpConfigurations(target, target_dict):
|
|||
def ProcessListFiltersInDict(name, the_dict):
|
||||
"""Process regular expression and exclusion-based filters on lists.
|
||||
|
||||
An exclusion list is in a dict key named with a trailing "!", like
|
||||
"sources!". Every item in such a list is removed from the associated
|
||||
main list, which in this example, would be "sources". Removed items are
|
||||
placed into a "sources_excluded" list in the dict.
|
||||
An exclusion list is in a dict key named with a trailing "!", like
|
||||
"sources!". Every item in such a list is removed from the associated
|
||||
main list, which in this example, would be "sources". Removed items are
|
||||
placed into a "sources_excluded" list in the dict.
|
||||
|
||||
Regular expression (regex) filters are contained in dict keys named with a
|
||||
trailing "/", such as "sources/" to operate on the "sources" list. Regex
|
||||
filters in a dict take the form:
|
||||
'sources/': [ ['exclude', '_(linux|mac|win)\\.cc$'],
|
||||
['include', '_mac\\.cc$'] ],
|
||||
The first filter says to exclude all files ending in _linux.cc, _mac.cc, and
|
||||
_win.cc. The second filter then includes all files ending in _mac.cc that
|
||||
are now or were once in the "sources" list. Items matching an "exclude"
|
||||
filter are subject to the same processing as would occur if they were listed
|
||||
by name in an exclusion list (ending in "!"). Items matching an "include"
|
||||
filter are brought back into the main list if previously excluded by an
|
||||
exclusion list or exclusion regex filter. Subsequent matching "exclude"
|
||||
patterns can still cause items to be excluded after matching an "include".
|
||||
"""
|
||||
Regular expression (regex) filters are contained in dict keys named with a
|
||||
trailing "/", such as "sources/" to operate on the "sources" list. Regex
|
||||
filters in a dict take the form:
|
||||
'sources/': [ ['exclude', '_(linux|mac|win)\\.cc$'],
|
||||
['include', '_mac\\.cc$'] ],
|
||||
The first filter says to exclude all files ending in _linux.cc, _mac.cc, and
|
||||
_win.cc. The second filter then includes all files ending in _mac.cc that
|
||||
are now or were once in the "sources" list. Items matching an "exclude"
|
||||
filter are subject to the same processing as would occur if they were listed
|
||||
by name in an exclusion list (ending in "!"). Items matching an "include"
|
||||
filter are brought back into the main list if previously excluded by an
|
||||
exclusion list or exclusion regex filter. Subsequent matching "exclude"
|
||||
patterns can still cause items to be excluded after matching an "include".
|
||||
"""
|
||||
|
||||
# Look through the dictionary for any lists whose keys end in "!" or "/".
|
||||
# These are lists that will be treated as exclude lists and regular
|
||||
|
|
@ -2682,12 +2671,12 @@ def ProcessListFiltersInList(name, the_list):
|
|||
def ValidateTargetType(target, target_dict):
|
||||
"""Ensures the 'type' field on the target is one of the known types.
|
||||
|
||||
Arguments:
|
||||
target: string, name of target.
|
||||
target_dict: dict, target spec.
|
||||
Arguments:
|
||||
target: string, name of target.
|
||||
target_dict: dict, target spec.
|
||||
|
||||
Raises an exception on error.
|
||||
"""
|
||||
Raises an exception on error.
|
||||
"""
|
||||
VALID_TARGET_TYPES = (
|
||||
"executable",
|
||||
"loadable_module",
|
||||
|
|
@ -2715,14 +2704,14 @@ def ValidateTargetType(target, target_dict):
|
|||
|
||||
def ValidateRulesInTarget(target, target_dict, extra_sources_for_rules):
|
||||
"""Ensures that the rules sections in target_dict are valid and consistent,
|
||||
and determines which sources they apply to.
|
||||
and determines which sources they apply to.
|
||||
|
||||
Arguments:
|
||||
target: string, name of target.
|
||||
target_dict: dict, target spec containing "rules" and "sources" lists.
|
||||
extra_sources_for_rules: a list of keys to scan for rule matches in
|
||||
addition to 'sources'.
|
||||
"""
|
||||
Arguments:
|
||||
target: string, name of target.
|
||||
target_dict: dict, target spec containing "rules" and "sources" lists.
|
||||
extra_sources_for_rules: a list of keys to scan for rule matches in
|
||||
addition to 'sources'.
|
||||
"""
|
||||
|
||||
# Dicts to map between values found in rules' 'rule_name' and 'extension'
|
||||
# keys and the rule dicts themselves.
|
||||
|
|
@ -2734,9 +2723,7 @@ def ValidateRulesInTarget(target, target_dict, extra_sources_for_rules):
|
|||
# Make sure that there's no conflict among rule names and extensions.
|
||||
rule_name = rule["rule_name"]
|
||||
if rule_name in rule_names:
|
||||
raise GypError(
|
||||
f"rule {rule_name} exists in duplicate, target {target}"
|
||||
)
|
||||
raise GypError(f"rule {rule_name} exists in duplicate, target {target}")
|
||||
rule_names[rule_name] = rule
|
||||
|
||||
rule_extension = rule["extension"]
|
||||
|
|
@ -2835,8 +2822,7 @@ def ValidateActionsInTarget(target, target_dict, build_file):
|
|||
|
||||
|
||||
def TurnIntIntoStrInDict(the_dict):
|
||||
"""Given dict the_dict, recursively converts all integers into strings.
|
||||
"""
|
||||
"""Given dict the_dict, recursively converts all integers into strings."""
|
||||
# Use items instead of iteritems because there's no need to try to look at
|
||||
# reinserted keys and their associated values.
|
||||
for k, v in the_dict.items():
|
||||
|
|
@ -2854,8 +2840,7 @@ def TurnIntIntoStrInDict(the_dict):
|
|||
|
||||
|
||||
def TurnIntIntoStrInList(the_list):
|
||||
"""Given list the_list, recursively converts all integers into strings.
|
||||
"""
|
||||
"""Given list the_list, recursively converts all integers into strings."""
|
||||
for index, item in enumerate(the_list):
|
||||
if isinstance(item, int):
|
||||
the_list[index] = str(item)
|
||||
|
|
@ -2902,9 +2887,9 @@ def PruneUnwantedTargets(targets, flat_list, dependency_nodes, root_targets, dat
|
|||
def VerifyNoCollidingTargets(targets):
|
||||
"""Verify that no two targets in the same directory share the same name.
|
||||
|
||||
Arguments:
|
||||
targets: A list of targets in the form 'path/to/file.gyp:target_name'.
|
||||
"""
|
||||
Arguments:
|
||||
targets: A list of targets in the form 'path/to/file.gyp:target_name'.
|
||||
"""
|
||||
# Keep a dict going from 'subdirectory:target_name' to 'foo.gyp'.
|
||||
used = {}
|
||||
for target in targets:
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@
|
|||
These functions are executed via gyp-mac-tool when using the Makefile generator.
|
||||
"""
|
||||
|
||||
|
||||
import fcntl
|
||||
import fnmatch
|
||||
import glob
|
||||
|
|
@ -31,7 +30,7 @@ def main(args):
|
|||
|
||||
class MacTool:
|
||||
"""This class performs all the Mac tooling steps. The methods can either be
|
||||
executed directly, or dispatched from an argument list."""
|
||||
executed directly, or dispatched from an argument list."""
|
||||
|
||||
def Dispatch(self, args):
|
||||
"""Dispatches a string command to a method."""
|
||||
|
|
@ -47,7 +46,7 @@ class MacTool:
|
|||
|
||||
def ExecCopyBundleResource(self, source, dest, convert_to_binary):
|
||||
"""Copies a resource file to the bundle/Resources directory, performing any
|
||||
necessary compilation on each resource."""
|
||||
necessary compilation on each resource."""
|
||||
convert_to_binary = convert_to_binary == "True"
|
||||
extension = os.path.splitext(source)[1].lower()
|
||||
if os.path.isdir(source):
|
||||
|
|
@ -155,15 +154,15 @@ class MacTool:
|
|||
|
||||
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."""
|
||||
encoding. Returns None as a guess if it can't detect it."""
|
||||
with open(file_name, "rb") as fp:
|
||||
try:
|
||||
header = fp.read(3)
|
||||
except Exception:
|
||||
return None
|
||||
if header.startswith((b"\xFE\xFF", b"\xFF\xFE")):
|
||||
if header.startswith((b"\xfe\xff", b"\xff\xfe")):
|
||||
return "UTF-16"
|
||||
elif header.startswith(b"\xEF\xBB\xBF"):
|
||||
elif header.startswith(b"\xef\xbb\xbf"):
|
||||
return "UTF-8"
|
||||
else:
|
||||
return None
|
||||
|
|
@ -254,7 +253,7 @@ class MacTool:
|
|||
|
||||
def ExecFilterLibtool(self, *cmd_list):
|
||||
"""Calls libtool and filters out '/path/to/libtool: file: foo.o has no
|
||||
symbols'."""
|
||||
symbols'."""
|
||||
libtool_re = re.compile(
|
||||
r"^.*libtool: (?:for architecture: \S* )?file: .* has no symbols$"
|
||||
)
|
||||
|
|
@ -303,7 +302,7 @@ class MacTool:
|
|||
|
||||
def ExecPackageFramework(self, framework, version):
|
||||
"""Takes a path to Something.framework and the Current version of that and
|
||||
sets up all the symlinks."""
|
||||
sets up all the symlinks."""
|
||||
# Find the name of the binary based on the part before the ".framework".
|
||||
binary = os.path.basename(framework).split(".")[0]
|
||||
|
||||
|
|
@ -332,7 +331,7 @@ class MacTool:
|
|||
|
||||
def _Relink(self, dest, link):
|
||||
"""Creates a symlink to |dest| named |link|. If |link| already exists,
|
||||
it is overwritten."""
|
||||
it is overwritten."""
|
||||
if os.path.lexists(link):
|
||||
os.remove(link)
|
||||
os.symlink(dest, link)
|
||||
|
|
@ -357,14 +356,14 @@ class MacTool:
|
|||
def ExecCompileXcassets(self, keys, *inputs):
|
||||
"""Compiles multiple .xcassets files into a single .car file.
|
||||
|
||||
This invokes 'actool' to compile all the inputs .xcassets files. The
|
||||
|keys| arguments is a json-encoded dictionary of extra arguments to
|
||||
pass to 'actool' when the asset catalogs contains an application icon
|
||||
or a launch image.
|
||||
This invokes 'actool' to compile all the inputs .xcassets files. The
|
||||
|keys| arguments is a json-encoded dictionary of extra arguments to
|
||||
pass to 'actool' when the asset catalogs contains an application icon
|
||||
or a launch image.
|
||||
|
||||
Note that 'actool' does not create the Assets.car file if the asset
|
||||
catalogs does not contains imageset.
|
||||
"""
|
||||
Note that 'actool' does not create the Assets.car file if the asset
|
||||
catalogs does not contains imageset.
|
||||
"""
|
||||
command_line = [
|
||||
"xcrun",
|
||||
"actool",
|
||||
|
|
@ -437,13 +436,13 @@ class MacTool:
|
|||
def ExecCodeSignBundle(self, key, entitlements, provisioning, path, preserve):
|
||||
"""Code sign a bundle.
|
||||
|
||||
This function tries to code sign an iOS bundle, following the same
|
||||
algorithm as Xcode:
|
||||
1. pick the provisioning profile that best match the bundle identifier,
|
||||
and copy it into the bundle as embedded.mobileprovision,
|
||||
2. copy Entitlements.plist from user or SDK next to the bundle,
|
||||
3. code sign the bundle.
|
||||
"""
|
||||
This function tries to code sign an iOS bundle, following the same
|
||||
algorithm as Xcode:
|
||||
1. pick the provisioning profile that best match the bundle identifier,
|
||||
and copy it into the bundle as embedded.mobileprovision,
|
||||
2. copy Entitlements.plist from user or SDK next to the bundle,
|
||||
3. code sign the bundle.
|
||||
"""
|
||||
substitutions, overrides = self._InstallProvisioningProfile(
|
||||
provisioning, self._GetCFBundleIdentifier()
|
||||
)
|
||||
|
|
@ -462,16 +461,16 @@ class MacTool:
|
|||
def _InstallProvisioningProfile(self, profile, bundle_identifier):
|
||||
"""Installs embedded.mobileprovision into the bundle.
|
||||
|
||||
Args:
|
||||
profile: string, optional, short name of the .mobileprovision file
|
||||
to use, if empty or the file is missing, the best file installed
|
||||
will be used
|
||||
bundle_identifier: string, value of CFBundleIdentifier from Info.plist
|
||||
Args:
|
||||
profile: string, optional, short name of the .mobileprovision file
|
||||
to use, if empty or the file is missing, the best file installed
|
||||
will be used
|
||||
bundle_identifier: string, value of CFBundleIdentifier from Info.plist
|
||||
|
||||
Returns:
|
||||
A tuple containing two dictionary: variables substitutions and values
|
||||
to overrides when generating the entitlements file.
|
||||
"""
|
||||
Returns:
|
||||
A tuple containing two dictionary: variables substitutions and values
|
||||
to overrides when generating the entitlements file.
|
||||
"""
|
||||
source_path, provisioning_data, team_id = self._FindProvisioningProfile(
|
||||
profile, bundle_identifier
|
||||
)
|
||||
|
|
@ -487,24 +486,24 @@ class MacTool:
|
|||
def _FindProvisioningProfile(self, profile, bundle_identifier):
|
||||
"""Finds the .mobileprovision file to use for signing the bundle.
|
||||
|
||||
Checks all the installed provisioning profiles (or if the user specified
|
||||
the PROVISIONING_PROFILE variable, only consult it) and select the most
|
||||
specific that correspond to the bundle identifier.
|
||||
Checks all the installed provisioning profiles (or if the user specified
|
||||
the PROVISIONING_PROFILE variable, only consult it) and select the most
|
||||
specific that correspond to the bundle identifier.
|
||||
|
||||
Args:
|
||||
profile: string, optional, short name of the .mobileprovision file
|
||||
to use, if empty or the file is missing, the best file installed
|
||||
will be used
|
||||
bundle_identifier: string, value of CFBundleIdentifier from Info.plist
|
||||
Args:
|
||||
profile: string, optional, short name of the .mobileprovision file
|
||||
to use, if empty or the file is missing, the best file installed
|
||||
will be used
|
||||
bundle_identifier: string, value of CFBundleIdentifier from Info.plist
|
||||
|
||||
Returns:
|
||||
A tuple of the path to the selected provisioning profile, the data of
|
||||
the embedded plist in the provisioning profile and the team identifier
|
||||
to use for code signing.
|
||||
Returns:
|
||||
A tuple of the path to the selected provisioning profile, the data of
|
||||
the embedded plist in the provisioning profile and the team identifier
|
||||
to use for code signing.
|
||||
|
||||
Raises:
|
||||
SystemExit: if no .mobileprovision can be used to sign the bundle.
|
||||
"""
|
||||
Raises:
|
||||
SystemExit: if no .mobileprovision can be used to sign the bundle.
|
||||
"""
|
||||
profiles_dir = os.path.join(
|
||||
os.environ["HOME"], "Library", "MobileDevice", "Provisioning Profiles"
|
||||
)
|
||||
|
|
@ -552,12 +551,12 @@ class MacTool:
|
|||
def _LoadProvisioningProfile(self, profile_path):
|
||||
"""Extracts the plist embedded in a provisioning profile.
|
||||
|
||||
Args:
|
||||
profile_path: string, path to the .mobileprovision file
|
||||
Args:
|
||||
profile_path: string, path to the .mobileprovision file
|
||||
|
||||
Returns:
|
||||
Content of the plist embedded in the provisioning profile as a dictionary.
|
||||
"""
|
||||
Returns:
|
||||
Content of the plist embedded in the provisioning profile as a dictionary.
|
||||
"""
|
||||
with tempfile.NamedTemporaryFile() as temp:
|
||||
subprocess.check_call(
|
||||
["security", "cms", "-D", "-i", profile_path, "-o", temp.name]
|
||||
|
|
@ -580,16 +579,16 @@ class MacTool:
|
|||
def _LoadPlistMaybeBinary(self, plist_path):
|
||||
"""Loads into a memory a plist possibly encoded in binary format.
|
||||
|
||||
This is a wrapper around plistlib.readPlist that tries to convert the
|
||||
plist to the XML format if it can't be parsed (assuming that it is in
|
||||
the binary format).
|
||||
This is a wrapper around plistlib.readPlist that tries to convert the
|
||||
plist to the XML format if it can't be parsed (assuming that it is in
|
||||
the binary format).
|
||||
|
||||
Args:
|
||||
plist_path: string, path to a plist file, in XML or binary format
|
||||
Args:
|
||||
plist_path: string, path to a plist file, in XML or binary format
|
||||
|
||||
Returns:
|
||||
Content of the plist as a dictionary.
|
||||
"""
|
||||
Returns:
|
||||
Content of the plist as a dictionary.
|
||||
"""
|
||||
try:
|
||||
# First, try to read the file using plistlib that only supports XML,
|
||||
# and if an exception is raised, convert a temporary copy to XML and
|
||||
|
|
@ -605,13 +604,13 @@ class MacTool:
|
|||
def _GetSubstitutions(self, bundle_identifier, app_identifier_prefix):
|
||||
"""Constructs a dictionary of variable substitutions for Entitlements.plist.
|
||||
|
||||
Args:
|
||||
bundle_identifier: string, value of CFBundleIdentifier from Info.plist
|
||||
app_identifier_prefix: string, value for AppIdentifierPrefix
|
||||
Args:
|
||||
bundle_identifier: string, value of CFBundleIdentifier from Info.plist
|
||||
app_identifier_prefix: string, value for AppIdentifierPrefix
|
||||
|
||||
Returns:
|
||||
Dictionary of substitutions to apply when generating Entitlements.plist.
|
||||
"""
|
||||
Returns:
|
||||
Dictionary of substitutions to apply when generating Entitlements.plist.
|
||||
"""
|
||||
return {
|
||||
"CFBundleIdentifier": bundle_identifier,
|
||||
"AppIdentifierPrefix": app_identifier_prefix,
|
||||
|
|
@ -620,9 +619,9 @@ class MacTool:
|
|||
def _GetCFBundleIdentifier(self):
|
||||
"""Extracts CFBundleIdentifier value from Info.plist in the bundle.
|
||||
|
||||
Returns:
|
||||
Value of CFBundleIdentifier in the Info.plist located in the bundle.
|
||||
"""
|
||||
Returns:
|
||||
Value of CFBundleIdentifier in the Info.plist located in the bundle.
|
||||
"""
|
||||
info_plist_path = os.path.join(
|
||||
os.environ["TARGET_BUILD_DIR"], os.environ["INFOPLIST_PATH"]
|
||||
)
|
||||
|
|
@ -632,19 +631,19 @@ class MacTool:
|
|||
def _InstallEntitlements(self, entitlements, substitutions, overrides):
|
||||
"""Generates and install the ${BundleName}.xcent entitlements file.
|
||||
|
||||
Expands variables "$(variable)" pattern in the source entitlements file,
|
||||
add extra entitlements defined in the .mobileprovision file and the copy
|
||||
the generated plist to "${BundlePath}.xcent".
|
||||
Expands variables "$(variable)" pattern in the source entitlements file,
|
||||
add extra entitlements defined in the .mobileprovision file and the copy
|
||||
the generated plist to "${BundlePath}.xcent".
|
||||
|
||||
Args:
|
||||
entitlements: string, optional, path to the Entitlements.plist template
|
||||
to use, defaults to "${SDKROOT}/Entitlements.plist"
|
||||
substitutions: dictionary, variable substitutions
|
||||
overrides: dictionary, values to add to the entitlements
|
||||
Args:
|
||||
entitlements: string, optional, path to the Entitlements.plist template
|
||||
to use, defaults to "${SDKROOT}/Entitlements.plist"
|
||||
substitutions: dictionary, variable substitutions
|
||||
overrides: dictionary, values to add to the entitlements
|
||||
|
||||
Returns:
|
||||
Path to the generated entitlements file.
|
||||
"""
|
||||
Returns:
|
||||
Path to the generated entitlements file.
|
||||
"""
|
||||
source_path = entitlements
|
||||
target_path = os.path.join(
|
||||
os.environ["BUILT_PRODUCTS_DIR"], os.environ["PRODUCT_NAME"] + ".xcent"
|
||||
|
|
@ -664,15 +663,15 @@ class MacTool:
|
|||
def _ExpandVariables(self, data, substitutions):
|
||||
"""Expands variables "$(variable)" in data.
|
||||
|
||||
Args:
|
||||
data: object, can be either string, list or dictionary
|
||||
substitutions: dictionary, variable substitutions to perform
|
||||
Args:
|
||||
data: object, can be either string, list or dictionary
|
||||
substitutions: dictionary, variable substitutions to perform
|
||||
|
||||
Returns:
|
||||
Copy of data where each references to "$(variable)" has been replaced
|
||||
by the corresponding value found in substitutions, or left intact if
|
||||
the key was not found.
|
||||
"""
|
||||
Returns:
|
||||
Copy of data where each references to "$(variable)" has been replaced
|
||||
by the corresponding value found in substitutions, or left intact if
|
||||
the key was not found.
|
||||
"""
|
||||
if isinstance(data, str):
|
||||
for key, value in substitutions.items():
|
||||
data = data.replace("$(%s)" % key, value)
|
||||
|
|
@ -691,15 +690,15 @@ def NextGreaterPowerOf2(x):
|
|||
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.
|
||||
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
|
||||
"""
|
||||
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
|
||||
|
|
|
|||
|
|
@ -74,8 +74,7 @@ def EncodeRspFileList(args, quote_cmd):
|
|||
program = call + " " + os.path.normpath(program)
|
||||
else:
|
||||
program = os.path.normpath(args[0])
|
||||
return (program + " "
|
||||
+ " ".join(QuoteForRspFile(arg, quote_cmd) for arg in args[1:]))
|
||||
return program + " " + " ".join(QuoteForRspFile(arg, quote_cmd) for arg in args[1:])
|
||||
|
||||
|
||||
def _GenericRetrieve(root, default, path):
|
||||
|
|
@ -934,14 +933,17 @@ class MsvsSettings:
|
|||
includes whether it should run under cygwin (msvs_cygwin_shell), and
|
||||
whether the commands should be quoted (msvs_quote_cmd)."""
|
||||
# If the variable is unset, or set to 1 we use cygwin
|
||||
cygwin = int(rule.get("msvs_cygwin_shell",
|
||||
self.spec.get("msvs_cygwin_shell", 1))) != 0
|
||||
cygwin = (
|
||||
int(rule.get("msvs_cygwin_shell", self.spec.get("msvs_cygwin_shell", 1)))
|
||||
!= 0
|
||||
)
|
||||
# Default to quoting. There's only a few special instances where the
|
||||
# target command uses non-standard command line parsing and handle quotes
|
||||
# and quote escaping differently.
|
||||
quote_cmd = int(rule.get("msvs_quote_cmd", 1))
|
||||
assert quote_cmd != 0 or cygwin != 1, \
|
||||
"msvs_quote_cmd=0 only applicable for msvs_cygwin_shell=0"
|
||||
assert quote_cmd != 0 or cygwin != 1, (
|
||||
"msvs_quote_cmd=0 only applicable for msvs_cygwin_shell=0"
|
||||
)
|
||||
return MsvsSettings.RuleShellFlags(cygwin, quote_cmd)
|
||||
|
||||
def _HasExplicitRuleForExtension(self, spec, extension):
|
||||
|
|
@ -1129,8 +1131,7 @@ def _ExtractImportantEnvironment(output_of_set):
|
|||
for required in ("SYSTEMROOT", "TEMP", "TMP"):
|
||||
if required not in env:
|
||||
raise Exception(
|
||||
'Environment variable "%s" '
|
||||
"required to be set to valid path" % required
|
||||
'Environment variable "%s" required to be set to valid path' % required
|
||||
)
|
||||
return env
|
||||
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@ __all__ = ["Error", "deepcopy"]
|
|||
|
||||
def deepcopy(x):
|
||||
"""Deep copy operation on gyp objects such as strings, ints, dicts
|
||||
and lists. More than twice as fast as copy.deepcopy but much less
|
||||
generic."""
|
||||
and lists. More than twice as fast as copy.deepcopy but much less
|
||||
generic."""
|
||||
|
||||
try:
|
||||
return _deepcopy_dispatch[type(x)](x)
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@
|
|||
These functions are executed via gyp-win-tool when using the ninja generator.
|
||||
"""
|
||||
|
||||
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
|
|
@ -33,11 +32,11 @@ def main(args):
|
|||
|
||||
class WinTool:
|
||||
"""This class performs all the Windows tooling steps. The methods can either
|
||||
be executed directly, or dispatched from an argument list."""
|
||||
be executed directly, or dispatched from an argument list."""
|
||||
|
||||
def _UseSeparateMspdbsrv(self, env, args):
|
||||
"""Allows to use a unique instance of mspdbsrv.exe per linker instead of a
|
||||
shared one."""
|
||||
shared one."""
|
||||
if len(args) < 1:
|
||||
raise Exception("Not enough arguments")
|
||||
|
||||
|
|
@ -114,9 +113,9 @@ class WinTool:
|
|||
|
||||
def ExecLinkWrapper(self, arch, use_separate_mspdbsrv, *args):
|
||||
"""Filter diagnostic output from link that looks like:
|
||||
' Creating library ui.dll.lib and object ui.dll.exp'
|
||||
This happens when there are exports from the dll or exe.
|
||||
"""
|
||||
' Creating library ui.dll.lib and object ui.dll.exp'
|
||||
This happens when there are exports from the dll or exe.
|
||||
"""
|
||||
env = self._GetEnv(arch)
|
||||
if use_separate_mspdbsrv == "True":
|
||||
self._UseSeparateMspdbsrv(env, args)
|
||||
|
|
@ -158,10 +157,10 @@ class WinTool:
|
|||
mt,
|
||||
rc,
|
||||
intermediate_manifest,
|
||||
*manifests
|
||||
*manifests,
|
||||
):
|
||||
"""A wrapper for handling creating a manifest resource and then executing
|
||||
a link command."""
|
||||
a link command."""
|
||||
# The 'normal' way to do manifests is to have link generate a manifest
|
||||
# based on gathering dependencies from the object files, then merge that
|
||||
# manifest with other manifests supplied as sources, convert the merged
|
||||
|
|
@ -245,8 +244,8 @@ class WinTool:
|
|||
|
||||
def ExecManifestWrapper(self, arch, *args):
|
||||
"""Run manifest tool with environment set. Strip out undesirable warning
|
||||
(some XML blocks are recognized by the OS loader, but not the manifest
|
||||
tool)."""
|
||||
(some XML blocks are recognized by the OS loader, but not the manifest
|
||||
tool)."""
|
||||
env = self._GetEnv(arch)
|
||||
popen = subprocess.Popen(
|
||||
args, shell=True, env=env, stdout=subprocess.PIPE, stderr=subprocess.STDOUT
|
||||
|
|
@ -259,8 +258,8 @@ class WinTool:
|
|||
|
||||
def ExecManifestToRc(self, arch, *args):
|
||||
"""Creates a resource file pointing a SxS assembly manifest.
|
||||
|args| is tuple containing path to resource file, path to manifest file
|
||||
and resource name which can be "1" (for executables) or "2" (for DLLs)."""
|
||||
|args| is tuple containing path to resource file, path to manifest file
|
||||
and resource name which can be "1" (for executables) or "2" (for DLLs)."""
|
||||
manifest_path, resource_path, resource_name = args
|
||||
with open(resource_path, "w") as output:
|
||||
output.write(
|
||||
|
|
@ -270,8 +269,8 @@ class WinTool:
|
|||
|
||||
def ExecMidlWrapper(self, arch, outdir, tlb, h, dlldata, iid, proxy, idl, *flags):
|
||||
"""Filter noisy filenames output from MIDL compile step that isn't
|
||||
quietable via command line flags.
|
||||
"""
|
||||
quietable via command line flags.
|
||||
"""
|
||||
args = (
|
||||
["midl", "/nologo"]
|
||||
+ list(flags)
|
||||
|
|
@ -327,7 +326,7 @@ class WinTool:
|
|||
|
||||
def ExecRcWrapper(self, arch, *args):
|
||||
"""Filter logo banner from invocations of rc.exe. Older versions of RC
|
||||
don't support the /nologo flag."""
|
||||
don't support the /nologo flag."""
|
||||
env = self._GetEnv(arch)
|
||||
popen = subprocess.Popen(
|
||||
args, shell=True, env=env, stdout=subprocess.PIPE, stderr=subprocess.STDOUT
|
||||
|
|
@ -344,7 +343,7 @@ class WinTool:
|
|||
|
||||
def ExecActionWrapper(self, arch, rspfile, *dir):
|
||||
"""Runs an action command line from a response file using the environment
|
||||
for |arch|. If |dir| is supplied, use that as the working directory."""
|
||||
for |arch|. If |dir| is supplied, use that as the working directory."""
|
||||
env = self._GetEnv(arch)
|
||||
# TODO(scottmg): This is a temporary hack to get some specific variables
|
||||
# through to actions that are set after gyp-time. http://crbug.com/333738.
|
||||
|
|
@ -357,7 +356,7 @@ class WinTool:
|
|||
|
||||
def ExecClCompile(self, project_dir, selected_files):
|
||||
"""Executed by msvs-ninja projects when the 'ClCompile' target is used to
|
||||
build selected C/C++ files."""
|
||||
build selected C/C++ files."""
|
||||
project_dir = os.path.relpath(project_dir, BASE_DIR)
|
||||
selected_files = selected_files.split(";")
|
||||
ninja_targets = [
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ This module contains classes that help to emulate xcodebuild behavior on top of
|
|||
other build systems, such as make and ninja.
|
||||
"""
|
||||
|
||||
|
||||
import copy
|
||||
import os
|
||||
import os.path
|
||||
|
|
@ -31,7 +30,7 @@ XCODE_ARCHS_DEFAULT_CACHE = None
|
|||
|
||||
def XcodeArchsVariableMapping(archs, archs_including_64_bit=None):
|
||||
"""Constructs a dictionary with expansion for $(ARCHS_STANDARD) variable,
|
||||
and optionally for $(ARCHS_STANDARD_INCLUDING_64_BIT)."""
|
||||
and optionally for $(ARCHS_STANDARD_INCLUDING_64_BIT)."""
|
||||
mapping = {"$(ARCHS_STANDARD)": archs}
|
||||
if archs_including_64_bit:
|
||||
mapping["$(ARCHS_STANDARD_INCLUDING_64_BIT)"] = archs_including_64_bit
|
||||
|
|
@ -40,10 +39,10 @@ def XcodeArchsVariableMapping(archs, archs_including_64_bit=None):
|
|||
|
||||
class XcodeArchsDefault:
|
||||
"""A class to resolve ARCHS variable from xcode_settings, resolving Xcode
|
||||
macros and implementing filtering by VALID_ARCHS. The expansion of macros
|
||||
depends on the SDKROOT used ("macosx", "iphoneos", "iphonesimulator") and
|
||||
on the version of Xcode.
|
||||
"""
|
||||
macros and implementing filtering by VALID_ARCHS. The expansion of macros
|
||||
depends on the SDKROOT used ("macosx", "iphoneos", "iphonesimulator") and
|
||||
on the version of Xcode.
|
||||
"""
|
||||
|
||||
# Match variable like $(ARCHS_STANDARD).
|
||||
variable_pattern = re.compile(r"\$\([a-zA-Z_][a-zA-Z0-9_]*\)$")
|
||||
|
|
@ -82,8 +81,8 @@ class XcodeArchsDefault:
|
|||
|
||||
def ActiveArchs(self, archs, valid_archs, sdkroot):
|
||||
"""Expands variables references in ARCHS, and filter by VALID_ARCHS if it
|
||||
is defined (if not set, Xcode accept any value in ARCHS, otherwise, only
|
||||
values present in VALID_ARCHS are kept)."""
|
||||
is defined (if not set, Xcode accept any value in ARCHS, otherwise, only
|
||||
values present in VALID_ARCHS are kept)."""
|
||||
expanded_archs = self._ExpandArchs(archs or self._default, sdkroot or "")
|
||||
if valid_archs:
|
||||
filtered_archs = []
|
||||
|
|
@ -96,24 +95,24 @@ class XcodeArchsDefault:
|
|||
|
||||
def GetXcodeArchsDefault():
|
||||
"""Returns the |XcodeArchsDefault| object to use to expand ARCHS for the
|
||||
installed version of Xcode. The default values used by Xcode for ARCHS
|
||||
and the expansion of the variables depends on the version of Xcode used.
|
||||
installed version of Xcode. The default values used by Xcode for ARCHS
|
||||
and the expansion of the variables depends on the version of Xcode used.
|
||||
|
||||
For all version anterior to Xcode 5.0 or posterior to Xcode 5.1 included
|
||||
uses $(ARCHS_STANDARD) if ARCHS is unset, while Xcode 5.0 to 5.0.2 uses
|
||||
$(ARCHS_STANDARD_INCLUDING_64_BIT). This variable was added to Xcode 5.0
|
||||
and deprecated with Xcode 5.1.
|
||||
For all version anterior to Xcode 5.0 or posterior to Xcode 5.1 included
|
||||
uses $(ARCHS_STANDARD) if ARCHS is unset, while Xcode 5.0 to 5.0.2 uses
|
||||
$(ARCHS_STANDARD_INCLUDING_64_BIT). This variable was added to Xcode 5.0
|
||||
and deprecated with Xcode 5.1.
|
||||
|
||||
For "macosx" SDKROOT, all version starting with Xcode 5.0 includes 64-bit
|
||||
architecture as part of $(ARCHS_STANDARD) and default to only building it.
|
||||
For "macosx" SDKROOT, all version starting with Xcode 5.0 includes 64-bit
|
||||
architecture as part of $(ARCHS_STANDARD) and default to only building it.
|
||||
|
||||
For "iphoneos" and "iphonesimulator" SDKROOT, 64-bit architectures are part
|
||||
of $(ARCHS_STANDARD_INCLUDING_64_BIT) from Xcode 5.0. From Xcode 5.1, they
|
||||
are also part of $(ARCHS_STANDARD).
|
||||
For "iphoneos" and "iphonesimulator" SDKROOT, 64-bit architectures are part
|
||||
of $(ARCHS_STANDARD_INCLUDING_64_BIT) from Xcode 5.0. From Xcode 5.1, they
|
||||
are also part of $(ARCHS_STANDARD).
|
||||
|
||||
All these rules are coded in the construction of the |XcodeArchsDefault|
|
||||
object to use depending on the version of Xcode detected. The object is
|
||||
for performance reason."""
|
||||
All these rules are coded in the construction of the |XcodeArchsDefault|
|
||||
object to use depending on the version of Xcode detected. The object is
|
||||
for performance reason."""
|
||||
global XCODE_ARCHS_DEFAULT_CACHE
|
||||
if XCODE_ARCHS_DEFAULT_CACHE:
|
||||
return XCODE_ARCHS_DEFAULT_CACHE
|
||||
|
|
@ -190,8 +189,8 @@ class XcodeSettings:
|
|||
|
||||
def _ConvertConditionalKeys(self, configname):
|
||||
"""Converts or warns on conditional keys. Xcode supports conditional keys,
|
||||
such as CODE_SIGN_IDENTITY[sdk=iphoneos*]. This is a partial implementation
|
||||
with some keys converted while the rest force a warning."""
|
||||
such as CODE_SIGN_IDENTITY[sdk=iphoneos*]. This is a partial implementation
|
||||
with some keys converted while the rest force a warning."""
|
||||
settings = self.xcode_settings[configname]
|
||||
conditional_keys = [key for key in settings if key.endswith("]")]
|
||||
for key in conditional_keys:
|
||||
|
|
@ -256,13 +255,13 @@ class XcodeSettings:
|
|||
|
||||
def GetFrameworkVersion(self):
|
||||
"""Returns the framework version of the current target. Only valid for
|
||||
bundles."""
|
||||
bundles."""
|
||||
assert self._IsBundle()
|
||||
return self.GetPerTargetSetting("FRAMEWORK_VERSION", default="A")
|
||||
|
||||
def GetWrapperExtension(self):
|
||||
"""Returns the bundle extension (.app, .framework, .plugin, etc). Only
|
||||
valid for bundles."""
|
||||
valid for bundles."""
|
||||
assert self._IsBundle()
|
||||
if self.spec["type"] in ("loadable_module", "shared_library"):
|
||||
default_wrapper_extension = {
|
||||
|
|
@ -297,13 +296,13 @@ class XcodeSettings:
|
|||
|
||||
def GetWrapperName(self):
|
||||
"""Returns the directory name of the bundle represented by this target.
|
||||
Only valid for bundles."""
|
||||
Only valid for bundles."""
|
||||
assert self._IsBundle()
|
||||
return self.GetProductName() + self.GetWrapperExtension()
|
||||
|
||||
def GetBundleContentsFolderPath(self):
|
||||
"""Returns the qualified path to the bundle's contents folder. E.g.
|
||||
Chromium.app/Contents or Foo.bundle/Versions/A. Only valid for bundles."""
|
||||
Chromium.app/Contents or Foo.bundle/Versions/A. Only valid for bundles."""
|
||||
if self.isIOS:
|
||||
return self.GetWrapperName()
|
||||
assert self._IsBundle()
|
||||
|
|
@ -317,7 +316,7 @@ class XcodeSettings:
|
|||
|
||||
def GetBundleResourceFolder(self):
|
||||
"""Returns the qualified path to the bundle's resource folder. E.g.
|
||||
Chromium.app/Contents/Resources. Only valid for bundles."""
|
||||
Chromium.app/Contents/Resources. Only valid for bundles."""
|
||||
assert self._IsBundle()
|
||||
if self.isIOS:
|
||||
return self.GetBundleContentsFolderPath()
|
||||
|
|
@ -325,7 +324,7 @@ class XcodeSettings:
|
|||
|
||||
def GetBundleExecutableFolderPath(self):
|
||||
"""Returns the qualified path to the bundle's executables folder. E.g.
|
||||
Chromium.app/Contents/MacOS. Only valid for bundles."""
|
||||
Chromium.app/Contents/MacOS. Only valid for bundles."""
|
||||
assert self._IsBundle()
|
||||
if self.spec["type"] in ("shared_library") or self.isIOS:
|
||||
return self.GetBundleContentsFolderPath()
|
||||
|
|
@ -334,25 +333,25 @@ class XcodeSettings:
|
|||
|
||||
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."""
|
||||
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."""
|
||||
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."""
|
||||
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."""
|
||||
Chromium.app/Contents/SharedSupport. Only valid for bundles."""
|
||||
assert self._IsBundle()
|
||||
if self.spec["type"] == "shared_library":
|
||||
return self.GetBundleResourceFolder()
|
||||
|
|
@ -361,19 +360,19 @@ class XcodeSettings:
|
|||
|
||||
def GetBundlePlugInsFolderPath(self):
|
||||
"""Returns the qualified path to the bundle's plugins folder. E.g,
|
||||
Chromium.app/Contents/PlugIns. Only valid for bundles."""
|
||||
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."""
|
||||
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."""
|
||||
Chromium.app/Contents/Info.plist. Only valid for bundles."""
|
||||
assert self._IsBundle()
|
||||
if (
|
||||
self.spec["type"] in ("executable", "loadable_module")
|
||||
|
|
@ -439,7 +438,7 @@ class XcodeSettings:
|
|||
|
||||
def _GetBundleBinaryPath(self):
|
||||
"""Returns the name of the bundle binary of by this target.
|
||||
E.g. Chromium.app/Contents/MacOS/Chromium. Only valid for bundles."""
|
||||
E.g. Chromium.app/Contents/MacOS/Chromium. Only valid for bundles."""
|
||||
assert self._IsBundle()
|
||||
return os.path.join(
|
||||
self.GetBundleExecutableFolderPath(), self.GetExecutableName()
|
||||
|
|
@ -470,14 +469,14 @@ class XcodeSettings:
|
|||
|
||||
def _GetStandaloneBinaryPath(self):
|
||||
"""Returns the name of the non-bundle binary represented by this target.
|
||||
E.g. hello_world. Only valid for non-bundles."""
|
||||
E.g. hello_world. Only valid for non-bundles."""
|
||||
assert not self._IsBundle()
|
||||
assert self.spec["type"] in {
|
||||
"executable",
|
||||
"shared_library",
|
||||
"static_library",
|
||||
"loadable_module",
|
||||
}, ("Unexpected type %s" % self.spec["type"])
|
||||
}, "Unexpected type %s" % self.spec["type"]
|
||||
target = self.spec["target_name"]
|
||||
if self.spec["type"] in {"loadable_module", "shared_library", "static_library"}:
|
||||
if target[:3] == "lib":
|
||||
|
|
@ -490,7 +489,7 @@ class XcodeSettings:
|
|||
|
||||
def GetExecutableName(self):
|
||||
"""Returns the executable name of the bundle represented by this target.
|
||||
E.g. Chromium."""
|
||||
E.g. Chromium."""
|
||||
if self._IsBundle():
|
||||
return self.spec.get("product_name", self.spec["target_name"])
|
||||
else:
|
||||
|
|
@ -498,7 +497,7 @@ class XcodeSettings:
|
|||
|
||||
def GetExecutablePath(self):
|
||||
"""Returns the qualified path to the primary executable of the bundle
|
||||
represented by this target. E.g. Chromium.app/Contents/MacOS/Chromium."""
|
||||
represented by this target. E.g. Chromium.app/Contents/MacOS/Chromium."""
|
||||
if self._IsBundle():
|
||||
return self._GetBundleBinaryPath()
|
||||
else:
|
||||
|
|
@ -568,7 +567,7 @@ class XcodeSettings:
|
|||
|
||||
def GetCflags(self, configname, arch=None):
|
||||
"""Returns flags that need to be added to .c, .cc, .m, and .mm
|
||||
compilations."""
|
||||
compilations."""
|
||||
# This functions (and the similar ones below) do not offer complete
|
||||
# emulation of all xcode_settings keys. They're implemented on demand.
|
||||
|
||||
|
|
@ -863,7 +862,7 @@ class XcodeSettings:
|
|||
|
||||
def _MapLinkerFlagFilename(self, ldflag, gyp_to_build_path):
|
||||
"""Checks if ldflag contains a filename and if so remaps it from
|
||||
gyp-directory-relative to build-directory-relative."""
|
||||
gyp-directory-relative to build-directory-relative."""
|
||||
# This list is expanded on demand.
|
||||
# They get matched as:
|
||||
# -exported_symbols_list file
|
||||
|
|
@ -895,13 +894,13 @@ class XcodeSettings:
|
|||
def GetLdflags(self, configname, product_dir, gyp_to_build_path, arch=None):
|
||||
"""Returns flags that need to be passed to the linker.
|
||||
|
||||
Args:
|
||||
configname: The name of the configuration to get ld flags for.
|
||||
product_dir: The directory where products such static and dynamic
|
||||
libraries are placed. This is added to the library search path.
|
||||
gyp_to_build_path: A function that converts paths relative to the
|
||||
current gyp file to paths relative to the build directory.
|
||||
"""
|
||||
Args:
|
||||
configname: The name of the configuration to get ld flags for.
|
||||
product_dir: The directory where products such static and dynamic
|
||||
libraries are placed. This is added to the library search path.
|
||||
gyp_to_build_path: A function that converts paths relative to the
|
||||
current gyp file to paths relative to the build directory.
|
||||
"""
|
||||
self.configname = configname
|
||||
ldflags = []
|
||||
|
||||
|
|
@ -1001,9 +1000,9 @@ class XcodeSettings:
|
|||
def GetLibtoolflags(self, configname):
|
||||
"""Returns flags that need to be passed to the static linker.
|
||||
|
||||
Args:
|
||||
configname: The name of the configuration to get ld flags for.
|
||||
"""
|
||||
Args:
|
||||
configname: The name of the configuration to get ld flags for.
|
||||
"""
|
||||
self.configname = configname
|
||||
libtoolflags = []
|
||||
|
||||
|
|
@ -1016,7 +1015,7 @@ class XcodeSettings:
|
|||
|
||||
def GetPerTargetSettings(self):
|
||||
"""Gets a list of all the per-target settings. This will only fetch keys
|
||||
whose values are the same across all configurations."""
|
||||
whose values are the same across all configurations."""
|
||||
first_pass = True
|
||||
result = {}
|
||||
for configname in sorted(self.xcode_settings.keys()):
|
||||
|
|
@ -1039,7 +1038,7 @@ class XcodeSettings:
|
|||
|
||||
def GetPerTargetSetting(self, setting, default=None):
|
||||
"""Tries to get xcode_settings.setting from spec. Assumes that the setting
|
||||
has the same value in all configurations and throws otherwise."""
|
||||
has the same value in all configurations and throws otherwise."""
|
||||
is_first_pass = True
|
||||
result = None
|
||||
for configname in sorted(self.xcode_settings.keys()):
|
||||
|
|
@ -1057,15 +1056,14 @@ class XcodeSettings:
|
|||
|
||||
def _GetStripPostbuilds(self, configname, output_binary, quiet):
|
||||
"""Returns a list of shell commands that contain the shell commands
|
||||
necessary to strip this target's binary. These should be run as postbuilds
|
||||
before the actual postbuilds run."""
|
||||
necessary to strip this target's binary. These should be run as postbuilds
|
||||
before the actual postbuilds run."""
|
||||
self.configname = configname
|
||||
|
||||
result = []
|
||||
if self._Test("DEPLOYMENT_POSTPROCESSING", "YES", default="NO") and self._Test(
|
||||
"STRIP_INSTALLED_PRODUCT", "YES", default="NO"
|
||||
):
|
||||
|
||||
default_strip_style = "debugging"
|
||||
if (
|
||||
self.spec["type"] == "loadable_module" or self._IsIosAppExtension()
|
||||
|
|
@ -1092,8 +1090,8 @@ class XcodeSettings:
|
|||
|
||||
def _GetDebugInfoPostbuilds(self, configname, output, output_binary, quiet):
|
||||
"""Returns a list of shell commands that contain the shell commands
|
||||
necessary to massage this target's debug information. These should be run
|
||||
as postbuilds before the actual postbuilds run."""
|
||||
necessary to massage this target's debug information. These should be run
|
||||
as postbuilds before the actual postbuilds run."""
|
||||
self.configname = configname
|
||||
|
||||
# For static libraries, no dSYMs are created.
|
||||
|
|
@ -1114,7 +1112,7 @@ class XcodeSettings:
|
|||
|
||||
def _GetTargetPostbuilds(self, configname, output, output_binary, quiet=False):
|
||||
"""Returns a list of shell commands that contain the shell commands
|
||||
to run as postbuilds for this target, before the actual postbuilds."""
|
||||
to run as postbuilds for this target, before the actual postbuilds."""
|
||||
# dSYMs need to build before stripping happens.
|
||||
return self._GetDebugInfoPostbuilds(
|
||||
configname, output, output_binary, quiet
|
||||
|
|
@ -1122,11 +1120,10 @@ class XcodeSettings:
|
|||
|
||||
def _GetIOSPostbuilds(self, configname, output_binary):
|
||||
"""Return a shell command to codesign the iOS output binary so it can
|
||||
be deployed to a device. This should be run as the very last step of the
|
||||
build."""
|
||||
be deployed to a device. This should be run as the very last step of the
|
||||
build."""
|
||||
if not (
|
||||
(self.isIOS
|
||||
and (self.spec["type"] == "executable" or self._IsXCTest()))
|
||||
(self.isIOS and (self.spec["type"] == "executable" or self._IsXCTest()))
|
||||
or self.IsIosFramework()
|
||||
):
|
||||
return []
|
||||
|
|
@ -1240,7 +1237,7 @@ class XcodeSettings:
|
|||
self, configname, output, output_binary, postbuilds=[], quiet=False
|
||||
):
|
||||
"""Returns a list of shell commands that should run before and after
|
||||
|postbuilds|."""
|
||||
|postbuilds|."""
|
||||
assert output_binary is not None
|
||||
pre = self._GetTargetPostbuilds(configname, output, output_binary, quiet)
|
||||
post = self._GetIOSPostbuilds(configname, output_binary)
|
||||
|
|
@ -1276,8 +1273,8 @@ class XcodeSettings:
|
|||
|
||||
def AdjustLibraries(self, libraries, config_name=None):
|
||||
"""Transforms entries like 'Cocoa.framework' in libraries into entries like
|
||||
'-framework Cocoa', 'libcrypto.dylib' into '-lcrypto', etc.
|
||||
"""
|
||||
'-framework Cocoa', 'libcrypto.dylib' into '-lcrypto', etc.
|
||||
"""
|
||||
libraries = [self._AdjustLibrary(library, config_name) for library in libraries]
|
||||
return libraries
|
||||
|
||||
|
|
@ -1342,10 +1339,10 @@ class XcodeSettings:
|
|||
def _DefaultSdkRoot(self):
|
||||
"""Returns the default SDKROOT to use.
|
||||
|
||||
Prior to version 5.0.0, if SDKROOT was not explicitly set in the Xcode
|
||||
project, then the environment variable was empty. Starting with this
|
||||
version, Xcode uses the name of the newest SDK installed.
|
||||
"""
|
||||
Prior to version 5.0.0, if SDKROOT was not explicitly set in the Xcode
|
||||
project, then the environment variable was empty. Starting with this
|
||||
version, Xcode uses the name of the newest SDK installed.
|
||||
"""
|
||||
xcode_version, _ = XcodeVersion()
|
||||
if xcode_version < "0500":
|
||||
return ""
|
||||
|
|
@ -1370,39 +1367,39 @@ class XcodeSettings:
|
|||
class MacPrefixHeader:
|
||||
"""A class that helps with emulating Xcode's GCC_PREFIX_HEADER feature.
|
||||
|
||||
This feature consists of several pieces:
|
||||
* If GCC_PREFIX_HEADER is present, all compilations in that project get an
|
||||
additional |-include path_to_prefix_header| cflag.
|
||||
* If GCC_PRECOMPILE_PREFIX_HEADER is present too, then the prefix header is
|
||||
instead compiled, and all other compilations in the project get an
|
||||
additional |-include path_to_compiled_header| instead.
|
||||
+ Compiled prefix headers have the extension gch. There is one gch file for
|
||||
every language used in the project (c, cc, m, mm), since gch files for
|
||||
different languages aren't compatible.
|
||||
+ gch files themselves are built with the target's normal cflags, but they
|
||||
obviously don't get the |-include| flag. Instead, they need a -x flag that
|
||||
describes their language.
|
||||
+ All o files in the target need to depend on the gch file, to make sure
|
||||
it's built before any o file is built.
|
||||
This feature consists of several pieces:
|
||||
* If GCC_PREFIX_HEADER is present, all compilations in that project get an
|
||||
additional |-include path_to_prefix_header| cflag.
|
||||
* If GCC_PRECOMPILE_PREFIX_HEADER is present too, then the prefix header is
|
||||
instead compiled, and all other compilations in the project get an
|
||||
additional |-include path_to_compiled_header| instead.
|
||||
+ Compiled prefix headers have the extension gch. There is one gch file for
|
||||
every language used in the project (c, cc, m, mm), since gch files for
|
||||
different languages aren't compatible.
|
||||
+ gch files themselves are built with the target's normal cflags, but they
|
||||
obviously don't get the |-include| flag. Instead, they need a -x flag that
|
||||
describes their language.
|
||||
+ All o files in the target need to depend on the gch file, to make sure
|
||||
it's built before any o file is built.
|
||||
|
||||
This class helps with some of these tasks, but it needs help from the build
|
||||
system for writing dependencies to the gch files, for writing build commands
|
||||
for the gch files, and for figuring out the location of the gch files.
|
||||
"""
|
||||
This class helps with some of these tasks, but it needs help from the build
|
||||
system for writing dependencies to the gch files, for writing build commands
|
||||
for the gch files, and for figuring out the location of the gch files.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self, xcode_settings, gyp_path_to_build_path, gyp_path_to_build_output
|
||||
):
|
||||
"""If xcode_settings is None, all methods on this class are no-ops.
|
||||
|
||||
Args:
|
||||
gyp_path_to_build_path: A function that takes a gyp-relative path,
|
||||
and returns a path relative to the build directory.
|
||||
gyp_path_to_build_output: A function that takes a gyp-relative path and
|
||||
a language code ('c', 'cc', 'm', or 'mm'), and that returns a path
|
||||
to where the output of precompiling that path for that language
|
||||
should be placed (without the trailing '.gch').
|
||||
"""
|
||||
Args:
|
||||
gyp_path_to_build_path: A function that takes a gyp-relative path,
|
||||
and returns a path relative to the build directory.
|
||||
gyp_path_to_build_output: A function that takes a gyp-relative path and
|
||||
a language code ('c', 'cc', 'm', or 'mm'), and that returns a path
|
||||
to where the output of precompiling that path for that language
|
||||
should be placed (without the trailing '.gch').
|
||||
"""
|
||||
# This doesn't support per-configuration prefix headers. Good enough
|
||||
# for now.
|
||||
self.header = None
|
||||
|
|
@ -1447,9 +1444,9 @@ class MacPrefixHeader:
|
|||
|
||||
def GetObjDependencies(self, sources, objs, arch=None):
|
||||
"""Given a list of source files and the corresponding object files, returns
|
||||
a list of (source, object, gch) tuples, where |gch| is the build-directory
|
||||
relative path to the gch file each object file depends on. |compilable[i]|
|
||||
has to be the source file belonging to |objs[i]|."""
|
||||
a list of (source, object, gch) tuples, where |gch| is the build-directory
|
||||
relative path to the gch file each object file depends on. |compilable[i]|
|
||||
has to be the source file belonging to |objs[i]|."""
|
||||
if not self.header or not self.compile_headers:
|
||||
return []
|
||||
|
||||
|
|
@ -1470,8 +1467,8 @@ class MacPrefixHeader:
|
|||
|
||||
def GetPchBuildCommands(self, arch=None):
|
||||
"""Returns [(path_to_gch, language_flag, language, header)].
|
||||
|path_to_gch| and |header| are relative to the build directory.
|
||||
"""
|
||||
|path_to_gch| and |header| are relative to the build directory.
|
||||
"""
|
||||
if not self.header or not self.compile_headers:
|
||||
return []
|
||||
return [
|
||||
|
|
@ -1555,8 +1552,8 @@ def CLTVersion():
|
|||
|
||||
def GetStdoutQuiet(cmdlist):
|
||||
"""Returns the content of standard output returned by invoking |cmdlist|.
|
||||
Ignores the stderr.
|
||||
Raises |GypError| if the command return with a non-zero return code."""
|
||||
Ignores the stderr.
|
||||
Raises |GypError| if the command return with a non-zero return code."""
|
||||
job = subprocess.Popen(cmdlist, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
out = job.communicate()[0].decode("utf-8")
|
||||
if job.returncode != 0:
|
||||
|
|
@ -1566,7 +1563,7 @@ def GetStdoutQuiet(cmdlist):
|
|||
|
||||
def GetStdout(cmdlist):
|
||||
"""Returns the content of standard output returned by invoking |cmdlist|.
|
||||
Raises |GypError| if the command return with a non-zero return code."""
|
||||
Raises |GypError| if the command return with a non-zero return code."""
|
||||
job = subprocess.Popen(cmdlist, stdout=subprocess.PIPE)
|
||||
out = job.communicate()[0].decode("utf-8")
|
||||
if job.returncode != 0:
|
||||
|
|
@ -1577,9 +1574,9 @@ def GetStdout(cmdlist):
|
|||
|
||||
def MergeGlobalXcodeSettingsToSpec(global_dict, spec):
|
||||
"""Merges the global xcode_settings dictionary into each configuration of the
|
||||
target represented by spec. For keys that are both in the global and the local
|
||||
xcode_settings dict, the local key gets precedence.
|
||||
"""
|
||||
target represented by spec. For keys that are both in the global and the local
|
||||
xcode_settings dict, the local key gets precedence.
|
||||
"""
|
||||
# The xcode generator special-cases global xcode_settings and does something
|
||||
# that amounts to merging in the global xcode_settings into each local
|
||||
# xcode_settings dict.
|
||||
|
|
@ -1594,9 +1591,9 @@ def MergeGlobalXcodeSettingsToSpec(global_dict, spec):
|
|||
def IsMacBundle(flavor, spec):
|
||||
"""Returns if |spec| should be treated as a bundle.
|
||||
|
||||
Bundles are directories with a certain subdirectory structure, instead of
|
||||
just a single file. Bundle rules do not produce a binary but also package
|
||||
resources into that directory."""
|
||||
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_xctest_bundle", 0)) != 0
|
||||
or int(spec.get("mac_xcuitest_bundle", 0)) != 0
|
||||
|
|
@ -1613,14 +1610,14 @@ def IsMacBundle(flavor, spec):
|
|||
|
||||
def GetMacBundleResources(product_dir, xcode_settings, resources):
|
||||
"""Yields (output, resource) pairs for every resource in |resources|.
|
||||
Only call this for mac bundle targets.
|
||||
Only call this for mac bundle targets.
|
||||
|
||||
Args:
|
||||
product_dir: Path to the directory containing the output bundle,
|
||||
relative to the build directory.
|
||||
xcode_settings: The XcodeSettings of the current target.
|
||||
resources: A list of bundle resources, relative to the build directory.
|
||||
"""
|
||||
Args:
|
||||
product_dir: Path to the directory containing the output bundle,
|
||||
relative to the build directory.
|
||||
xcode_settings: The XcodeSettings of the current target.
|
||||
resources: A list of bundle resources, relative to the build directory.
|
||||
"""
|
||||
dest = os.path.join(product_dir, xcode_settings.GetBundleResourceFolder())
|
||||
for res in resources:
|
||||
output = dest
|
||||
|
|
@ -1651,24 +1648,24 @@ def GetMacBundleResources(product_dir, xcode_settings, resources):
|
|||
|
||||
def GetMacInfoPlist(product_dir, xcode_settings, gyp_path_to_build_path):
|
||||
"""Returns (info_plist, dest_plist, defines, extra_env), where:
|
||||
* |info_plist| is the source plist path, relative to the
|
||||
build directory,
|
||||
* |dest_plist| is the destination plist path, relative to the
|
||||
build directory,
|
||||
* |defines| is a list of preprocessor defines (empty if the plist
|
||||
shouldn't be preprocessed,
|
||||
* |extra_env| is a dict of env variables that should be exported when
|
||||
invoking |mac_tool copy-info-plist|.
|
||||
* |info_plist| is the source plist path, relative to the
|
||||
build directory,
|
||||
* |dest_plist| is the destination plist path, relative to the
|
||||
build directory,
|
||||
* |defines| is a list of preprocessor defines (empty if the plist
|
||||
shouldn't be preprocessed,
|
||||
* |extra_env| is a dict of env variables that should be exported when
|
||||
invoking |mac_tool copy-info-plist|.
|
||||
|
||||
Only call this for mac bundle targets.
|
||||
Only call this for mac bundle targets.
|
||||
|
||||
Args:
|
||||
product_dir: Path to the directory containing the output bundle,
|
||||
relative to the build directory.
|
||||
xcode_settings: The XcodeSettings of the current target.
|
||||
gyp_to_build_path: A function that converts paths relative to the
|
||||
current gyp file to paths relative to the build directory.
|
||||
"""
|
||||
Args:
|
||||
product_dir: Path to the directory containing the output bundle,
|
||||
relative to the build directory.
|
||||
xcode_settings: The XcodeSettings of the current target.
|
||||
gyp_to_build_path: A function that converts paths relative to the
|
||||
current gyp file to paths relative to the build directory.
|
||||
"""
|
||||
info_plist = xcode_settings.GetPerTargetSetting("INFOPLIST_FILE")
|
||||
if not info_plist:
|
||||
return None, None, [], {}
|
||||
|
|
@ -1706,18 +1703,18 @@ def _GetXcodeEnv(
|
|||
xcode_settings, built_products_dir, srcroot, configuration, additional_settings=None
|
||||
):
|
||||
"""Return the environment variables that Xcode would set. See
|
||||
http://developer.apple.com/library/mac/#documentation/DeveloperTools/Reference/XcodeBuildSettingRef/1-Build_Setting_Reference/build_setting_ref.html#//apple_ref/doc/uid/TP40003931-CH3-SW153
|
||||
for a full list.
|
||||
http://developer.apple.com/library/mac/#documentation/DeveloperTools/Reference/XcodeBuildSettingRef/1-Build_Setting_Reference/build_setting_ref.html#//apple_ref/doc/uid/TP40003931-CH3-SW153
|
||||
for a full list.
|
||||
|
||||
Args:
|
||||
xcode_settings: An XcodeSettings object. If this is None, this function
|
||||
returns an empty dict.
|
||||
built_products_dir: Absolute path to the built products dir.
|
||||
srcroot: Absolute path to the source root.
|
||||
configuration: The build configuration name.
|
||||
additional_settings: An optional dict with more values to add to the
|
||||
result.
|
||||
"""
|
||||
Args:
|
||||
xcode_settings: An XcodeSettings object. If this is None, this function
|
||||
returns an empty dict.
|
||||
built_products_dir: Absolute path to the built products dir.
|
||||
srcroot: Absolute path to the source root.
|
||||
configuration: The build configuration name.
|
||||
additional_settings: An optional dict with more values to add to the
|
||||
result.
|
||||
"""
|
||||
|
||||
if not xcode_settings:
|
||||
return {}
|
||||
|
|
@ -1771,17 +1768,17 @@ def _GetXcodeEnv(
|
|||
)
|
||||
env["CONTENTS_FOLDER_PATH"] = xcode_settings.GetBundleContentsFolderPath()
|
||||
env["EXECUTABLE_FOLDER_PATH"] = xcode_settings.GetBundleExecutableFolderPath()
|
||||
env[
|
||||
"UNLOCALIZED_RESOURCES_FOLDER_PATH"
|
||||
] = xcode_settings.GetBundleResourceFolder()
|
||||
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["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()
|
||||
|
|
@ -1817,8 +1814,8 @@ def _GetXcodeEnv(
|
|||
|
||||
def _NormalizeEnvVarReferences(str):
|
||||
"""Takes a string containing variable references in the form ${FOO}, $(FOO),
|
||||
or $FOO, and returns a string with all variable references in the form ${FOO}.
|
||||
"""
|
||||
or $FOO, and returns a string with all variable references in the form ${FOO}.
|
||||
"""
|
||||
# $FOO -> ${FOO}
|
||||
str = re.sub(r"\$([a-zA-Z_][a-zA-Z0-9_]*)", r"${\1}", str)
|
||||
|
||||
|
|
@ -1834,9 +1831,9 @@ def _NormalizeEnvVarReferences(str):
|
|||
|
||||
def ExpandEnvVars(string, expansions):
|
||||
"""Expands ${VARIABLES}, $(VARIABLES), and $VARIABLES in string per the
|
||||
expansions list. If the variable expands to something that references
|
||||
another variable, this variable is expanded as well if it's in env --
|
||||
until no variables present in env are left."""
|
||||
expansions list. If the variable expands to something that references
|
||||
another variable, this variable is expanded as well if it's in env --
|
||||
until no variables present in env are left."""
|
||||
for k, v in reversed(expansions):
|
||||
string = string.replace("${" + k + "}", v)
|
||||
string = string.replace("$(" + k + ")", v)
|
||||
|
|
@ -1846,11 +1843,11 @@ def ExpandEnvVars(string, expansions):
|
|||
|
||||
def _TopologicallySortedEnvVarKeys(env):
|
||||
"""Takes a dict |env| whose values are strings that can refer to other keys,
|
||||
for example env['foo'] = '$(bar) and $(baz)'. Returns a list L of all keys of
|
||||
env such that key2 is after key1 in L if env[key2] refers to env[key1].
|
||||
for example env['foo'] = '$(bar) and $(baz)'. Returns a list L of all keys of
|
||||
env such that key2 is after key1 in L if env[key2] refers to env[key1].
|
||||
|
||||
Throws an Exception in case of dependency cycles.
|
||||
"""
|
||||
Throws an Exception in case of dependency cycles.
|
||||
"""
|
||||
# Since environment variables can refer to other variables, the evaluation
|
||||
# order is important. Below is the logic to compute the dependency graph
|
||||
# and sort it.
|
||||
|
|
@ -1891,7 +1888,7 @@ def GetSortedXcodeEnv(
|
|||
|
||||
def GetSpecPostbuildCommands(spec, quiet=False):
|
||||
"""Returns the list of postbuilds explicitly defined on |spec|, in a form
|
||||
executable by a shell."""
|
||||
executable by a shell."""
|
||||
postbuilds = []
|
||||
for postbuild in spec.get("postbuilds", []):
|
||||
if not quiet:
|
||||
|
|
@ -1905,7 +1902,7 @@ def GetSpecPostbuildCommands(spec, quiet=False):
|
|||
|
||||
def _HasIOSTarget(targets):
|
||||
"""Returns true if any target contains the iOS specific key
|
||||
IPHONEOS_DEPLOYMENT_TARGET."""
|
||||
IPHONEOS_DEPLOYMENT_TARGET."""
|
||||
for target_dict in targets.values():
|
||||
for config in target_dict["configurations"].values():
|
||||
if config.get("xcode_settings", {}).get("IPHONEOS_DEPLOYMENT_TARGET"):
|
||||
|
|
@ -1915,7 +1912,7 @@ def _HasIOSTarget(targets):
|
|||
|
||||
def _AddIOSDeviceConfigurations(targets):
|
||||
"""Clone all targets and append -iphoneos to the name. Configure these targets
|
||||
to build for iOS devices and use correct architectures for those builds."""
|
||||
to build for iOS devices and use correct architectures for those builds."""
|
||||
for target_dict in targets.values():
|
||||
toolset = target_dict["toolset"]
|
||||
configs = target_dict["configurations"]
|
||||
|
|
@ -1931,7 +1928,7 @@ def _AddIOSDeviceConfigurations(targets):
|
|||
|
||||
def CloneConfigurationForDeviceAndEmulator(target_dicts):
|
||||
"""If |target_dicts| contains any iOS targets, automatically create -iphoneos
|
||||
targets for iOS device builds."""
|
||||
targets for iOS device builds."""
|
||||
if _HasIOSTarget(target_dicts):
|
||||
return _AddIOSDeviceConfigurations(target_dicts)
|
||||
return target_dicts
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import gyp.generator.ninja
|
|||
|
||||
|
||||
def _WriteWorkspace(main_gyp, sources_gyp, params):
|
||||
""" Create a workspace to wrap main and sources gyp paths. """
|
||||
"""Create a workspace to wrap main and sources gyp paths."""
|
||||
(build_file_root, build_file_ext) = os.path.splitext(main_gyp)
|
||||
workspace_path = build_file_root + ".xcworkspace"
|
||||
options = params["options"]
|
||||
|
|
@ -57,7 +57,7 @@ def _WriteWorkspace(main_gyp, sources_gyp, params):
|
|||
|
||||
|
||||
def _TargetFromSpec(old_spec, params):
|
||||
""" Create fake target for xcode-ninja wrapper. """
|
||||
"""Create fake target for xcode-ninja wrapper."""
|
||||
# Determine ninja top level build dir (e.g. /path/to/out).
|
||||
ninja_toplevel = None
|
||||
jobs = 0
|
||||
|
|
@ -102,9 +102,9 @@ def _TargetFromSpec(old_spec, params):
|
|||
new_xcode_settings[key] = old_xcode_settings[key]
|
||||
|
||||
ninja_target["configurations"][config] = {}
|
||||
ninja_target["configurations"][config][
|
||||
"xcode_settings"
|
||||
] = new_xcode_settings
|
||||
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)
|
||||
|
|
@ -137,13 +137,13 @@ def _TargetFromSpec(old_spec, params):
|
|||
def IsValidTargetForWrapper(target_extras, executable_target_pattern, spec):
|
||||
"""Limit targets for Xcode wrapper.
|
||||
|
||||
Xcode sometimes performs poorly with too many targets, so only include
|
||||
proper executable targets, with filters to customize.
|
||||
Arguments:
|
||||
target_extras: Regular expression to always add, matching any target.
|
||||
executable_target_pattern: Regular expression limiting executable targets.
|
||||
spec: Specifications for target.
|
||||
"""
|
||||
Xcode sometimes performs poorly with too many targets, so only include
|
||||
proper executable targets, with filters to customize.
|
||||
Arguments:
|
||||
target_extras: Regular expression to always add, matching any target.
|
||||
executable_target_pattern: Regular expression limiting executable targets.
|
||||
spec: Specifications for target.
|
||||
"""
|
||||
target_name = spec.get("target_name")
|
||||
# Always include targets matching target_extras.
|
||||
if target_extras is not None and re.search(target_extras, target_name):
|
||||
|
|
@ -154,7 +154,6 @@ def IsValidTargetForWrapper(target_extras, executable_target_pattern, spec):
|
|||
spec.get("type", "") == "executable"
|
||||
and spec.get("product_extension", "") != "bundle"
|
||||
):
|
||||
|
||||
# If there is a filter and the target does not match, exclude the target.
|
||||
if executable_target_pattern is not None:
|
||||
if not re.search(executable_target_pattern, target_name):
|
||||
|
|
@ -166,14 +165,14 @@ def IsValidTargetForWrapper(target_extras, executable_target_pattern, spec):
|
|||
def CreateWrapper(target_list, target_dicts, data, params):
|
||||
"""Initialize targets for the ninja wrapper.
|
||||
|
||||
This sets up the necessary variables in the targets to generate Xcode projects
|
||||
that use ninja as an external builder.
|
||||
Arguments:
|
||||
target_list: List of target pairs: 'base/base.gyp:base'.
|
||||
target_dicts: Dict of target properties keyed on target pair.
|
||||
data: Dict of flattened build files keyed on gyp path.
|
||||
params: Dict of global options for gyp.
|
||||
"""
|
||||
This sets up the necessary variables in the targets to generate Xcode projects
|
||||
that use ninja as an external builder.
|
||||
Arguments:
|
||||
target_list: List of target pairs: 'base/base.gyp:base'.
|
||||
target_dicts: Dict of target properties keyed on target pair.
|
||||
data: Dict of flattened build files keyed on gyp path.
|
||||
params: Dict of global options for gyp.
|
||||
"""
|
||||
orig_gyp = params["build_files"][0]
|
||||
for gyp_name, gyp_dict in data.items():
|
||||
if gyp_name == orig_gyp:
|
||||
|
|
|
|||
|
|
@ -176,12 +176,12 @@ _path_leading_variable = re.compile(r"^\$\((.*?)\)(/(.*))?$")
|
|||
def SourceTreeAndPathFromPath(input_path):
|
||||
"""Given input_path, returns a tuple with sourceTree and path values.
|
||||
|
||||
Examples:
|
||||
input_path (source_tree, output_path)
|
||||
'$(VAR)/path' ('VAR', 'path')
|
||||
'$(VAR)' ('VAR', None)
|
||||
'path' (None, 'path')
|
||||
"""
|
||||
Examples:
|
||||
input_path (source_tree, output_path)
|
||||
'$(VAR)/path' ('VAR', 'path')
|
||||
'$(VAR)' ('VAR', None)
|
||||
'path' (None, 'path')
|
||||
"""
|
||||
|
||||
if source_group_match := _path_leading_variable.match(input_path):
|
||||
source_tree = source_group_match.group(1)
|
||||
|
|
@ -200,70 +200,70 @@ def ConvertVariablesToShellSyntax(input_string):
|
|||
class XCObject:
|
||||
"""The abstract base of all class types used in Xcode project files.
|
||||
|
||||
Class variables:
|
||||
_schema: A dictionary defining the properties of this class. The keys to
|
||||
_schema are string property keys as used in project files. Values
|
||||
are a list of four or five elements:
|
||||
[ is_list, property_type, is_strong, is_required, default ]
|
||||
is_list: True if the property described is a list, as opposed
|
||||
to a single element.
|
||||
property_type: The type to use as the value of the property,
|
||||
or if is_list is True, the type to use for each
|
||||
element of the value's list. property_type must
|
||||
be an XCObject subclass, or one of the built-in
|
||||
types str, int, or dict.
|
||||
is_strong: If property_type is an XCObject subclass, is_strong
|
||||
is True to assert that this class "owns," or serves
|
||||
as parent, to the property value (or, if is_list is
|
||||
True, values). is_strong must be False if
|
||||
property_type is not an XCObject subclass.
|
||||
is_required: True if the property is required for the class.
|
||||
Note that is_required being True does not preclude
|
||||
an empty string ("", in the case of property_type
|
||||
str) or list ([], in the case of is_list True) from
|
||||
being set for the property.
|
||||
default: Optional. If is_required is True, default may be set
|
||||
to provide a default value for objects that do not supply
|
||||
their own value. If is_required is True and default
|
||||
is not provided, users of the class must supply their own
|
||||
value for the property.
|
||||
Note that although the values of the array are expressed in
|
||||
boolean terms, subclasses provide values as integers to conserve
|
||||
horizontal space.
|
||||
_should_print_single_line: False in XCObject. Subclasses whose objects
|
||||
should be written to the project file in the
|
||||
alternate single-line format, such as
|
||||
PBXFileReference and PBXBuildFile, should
|
||||
set this to True.
|
||||
_encode_transforms: Used by _EncodeString to encode unprintable characters.
|
||||
The index into this list is the ordinal of the
|
||||
character to transform; each value is a string
|
||||
used to represent the character in the output. XCObject
|
||||
provides an _encode_transforms list suitable for most
|
||||
XCObject subclasses.
|
||||
_alternate_encode_transforms: Provided for subclasses that wish to use
|
||||
the alternate encoding rules. Xcode seems
|
||||
to use these rules when printing objects in
|
||||
single-line format. Subclasses that desire
|
||||
this behavior should set _encode_transforms
|
||||
to _alternate_encode_transforms.
|
||||
_hashables: A list of XCObject subclasses that can be hashed by ComputeIDs
|
||||
to construct this object's ID. Most classes that need custom
|
||||
hashing behavior should do it by overriding Hashables,
|
||||
but in some cases an object's parent may wish to push a
|
||||
hashable value into its child, and it can do so by appending
|
||||
to _hashables.
|
||||
Attributes:
|
||||
id: The object's identifier, a 24-character uppercase hexadecimal string.
|
||||
Usually, objects being created should not set id until the entire
|
||||
project file structure is built. At that point, UpdateIDs() should
|
||||
be called on the root object to assign deterministic values for id to
|
||||
each object in the tree.
|
||||
parent: The object's parent. This is set by a parent XCObject when a child
|
||||
object is added to it.
|
||||
_properties: The object's property dictionary. An object's properties are
|
||||
described by its class' _schema variable.
|
||||
"""
|
||||
Class variables:
|
||||
_schema: A dictionary defining the properties of this class. The keys to
|
||||
_schema are string property keys as used in project files. Values
|
||||
are a list of four or five elements:
|
||||
[ is_list, property_type, is_strong, is_required, default ]
|
||||
is_list: True if the property described is a list, as opposed
|
||||
to a single element.
|
||||
property_type: The type to use as the value of the property,
|
||||
or if is_list is True, the type to use for each
|
||||
element of the value's list. property_type must
|
||||
be an XCObject subclass, or one of the built-in
|
||||
types str, int, or dict.
|
||||
is_strong: If property_type is an XCObject subclass, is_strong
|
||||
is True to assert that this class "owns," or serves
|
||||
as parent, to the property value (or, if is_list is
|
||||
True, values). is_strong must be False if
|
||||
property_type is not an XCObject subclass.
|
||||
is_required: True if the property is required for the class.
|
||||
Note that is_required being True does not preclude
|
||||
an empty string ("", in the case of property_type
|
||||
str) or list ([], in the case of is_list True) from
|
||||
being set for the property.
|
||||
default: Optional. If is_required is True, default may be set
|
||||
to provide a default value for objects that do not supply
|
||||
their own value. If is_required is True and default
|
||||
is not provided, users of the class must supply their own
|
||||
value for the property.
|
||||
Note that although the values of the array are expressed in
|
||||
boolean terms, subclasses provide values as integers to conserve
|
||||
horizontal space.
|
||||
_should_print_single_line: False in XCObject. Subclasses whose objects
|
||||
should be written to the project file in the
|
||||
alternate single-line format, such as
|
||||
PBXFileReference and PBXBuildFile, should
|
||||
set this to True.
|
||||
_encode_transforms: Used by _EncodeString to encode unprintable characters.
|
||||
The index into this list is the ordinal of the
|
||||
character to transform; each value is a string
|
||||
used to represent the character in the output. XCObject
|
||||
provides an _encode_transforms list suitable for most
|
||||
XCObject subclasses.
|
||||
_alternate_encode_transforms: Provided for subclasses that wish to use
|
||||
the alternate encoding rules. Xcode seems
|
||||
to use these rules when printing objects in
|
||||
single-line format. Subclasses that desire
|
||||
this behavior should set _encode_transforms
|
||||
to _alternate_encode_transforms.
|
||||
_hashables: A list of XCObject subclasses that can be hashed by ComputeIDs
|
||||
to construct this object's ID. Most classes that need custom
|
||||
hashing behavior should do it by overriding Hashables,
|
||||
but in some cases an object's parent may wish to push a
|
||||
hashable value into its child, and it can do so by appending
|
||||
to _hashables.
|
||||
Attributes:
|
||||
id: The object's identifier, a 24-character uppercase hexadecimal string.
|
||||
Usually, objects being created should not set id until the entire
|
||||
project file structure is built. At that point, UpdateIDs() should
|
||||
be called on the root object to assign deterministic values for id to
|
||||
each object in the tree.
|
||||
parent: The object's parent. This is set by a parent XCObject when a child
|
||||
object is added to it.
|
||||
_properties: The object's property dictionary. An object's properties are
|
||||
described by its class' _schema variable.
|
||||
"""
|
||||
|
||||
_schema = {}
|
||||
_should_print_single_line = False
|
||||
|
|
@ -305,12 +305,12 @@ class XCObject:
|
|||
def Copy(self):
|
||||
"""Make a copy of this object.
|
||||
|
||||
The new object will have its own copy of lists and dicts. Any XCObject
|
||||
objects owned by this object (marked "strong") will be copied in the
|
||||
new object, even those found in lists. If this object has any weak
|
||||
references to other XCObjects, the same references are added to the new
|
||||
object without making a copy.
|
||||
"""
|
||||
The new object will have its own copy of lists and dicts. Any XCObject
|
||||
objects owned by this object (marked "strong") will be copied in the
|
||||
new object, even those found in lists. If this object has any weak
|
||||
references to other XCObjects, the same references are added to the new
|
||||
object without making a copy.
|
||||
"""
|
||||
|
||||
that = self.__class__(id=self.id, parent=self.parent)
|
||||
for key, value in self._properties.items():
|
||||
|
|
@ -359,9 +359,9 @@ class XCObject:
|
|||
def Name(self):
|
||||
"""Return the name corresponding to an object.
|
||||
|
||||
Not all objects necessarily need to be nameable, and not all that do have
|
||||
a "name" property. Override as needed.
|
||||
"""
|
||||
Not all objects necessarily need to be nameable, and not all that do have
|
||||
a "name" property. Override as needed.
|
||||
"""
|
||||
|
||||
# If the schema indicates that "name" is required, try to access the
|
||||
# property even if it doesn't exist. This will result in a KeyError
|
||||
|
|
@ -377,12 +377,12 @@ class XCObject:
|
|||
def Comment(self):
|
||||
"""Return a comment string for the object.
|
||||
|
||||
Most objects just use their name as the comment, but PBXProject uses
|
||||
different values.
|
||||
Most objects just use their name as the comment, but PBXProject uses
|
||||
different values.
|
||||
|
||||
The returned comment is not escaped and does not have any comment marker
|
||||
strings applied to it.
|
||||
"""
|
||||
The returned comment is not escaped and does not have any comment marker
|
||||
strings applied to it.
|
||||
"""
|
||||
|
||||
return self.Name()
|
||||
|
||||
|
|
@ -402,26 +402,26 @@ class XCObject:
|
|||
def ComputeIDs(self, recursive=True, overwrite=True, seed_hash=None):
|
||||
"""Set "id" properties deterministically.
|
||||
|
||||
An object's "id" property is set based on a hash of its class type and
|
||||
name, as well as the class type and name of all ancestor objects. As
|
||||
such, it is only advisable to call ComputeIDs once an entire project file
|
||||
tree is built.
|
||||
An object's "id" property is set based on a hash of its class type and
|
||||
name, as well as the class type and name of all ancestor objects. As
|
||||
such, it is only advisable to call ComputeIDs once an entire project file
|
||||
tree is built.
|
||||
|
||||
If recursive is True, recurse into all descendant objects and update their
|
||||
hashes.
|
||||
If recursive is True, recurse into all descendant objects and update their
|
||||
hashes.
|
||||
|
||||
If overwrite is True, any existing value set in the "id" property will be
|
||||
replaced.
|
||||
"""
|
||||
If overwrite is True, any existing value set in the "id" property will be
|
||||
replaced.
|
||||
"""
|
||||
|
||||
def _HashUpdate(hash, data):
|
||||
"""Update hash with data's length and contents.
|
||||
|
||||
If the hash were updated only with the value of data, it would be
|
||||
possible for clowns to induce collisions by manipulating the names of
|
||||
their objects. By adding the length, it's exceedingly less likely that
|
||||
ID collisions will be encountered, intentionally or not.
|
||||
"""
|
||||
If the hash were updated only with the value of data, it would be
|
||||
possible for clowns to induce collisions by manipulating the names of
|
||||
their objects. By adding the length, it's exceedingly less likely that
|
||||
ID collisions will be encountered, intentionally or not.
|
||||
"""
|
||||
|
||||
hash.update(struct.pack(">i", len(data)))
|
||||
if isinstance(data, str):
|
||||
|
|
@ -464,8 +464,7 @@ class XCObject:
|
|||
self.id = "%08X%08X%08X" % tuple(id_ints)
|
||||
|
||||
def EnsureNoIDCollisions(self):
|
||||
"""Verifies that no two objects have the same ID. Checks all descendants.
|
||||
"""
|
||||
"""Verifies that no two objects have the same ID. Checks all descendants."""
|
||||
|
||||
ids = {}
|
||||
descendants = self.Descendants()
|
||||
|
|
@ -498,8 +497,8 @@ class XCObject:
|
|||
|
||||
def Descendants(self):
|
||||
"""Returns a list of all of this object's descendants, including this
|
||||
object.
|
||||
"""
|
||||
object.
|
||||
"""
|
||||
|
||||
children = self.Children()
|
||||
descendants = [self]
|
||||
|
|
@ -515,8 +514,8 @@ class XCObject:
|
|||
|
||||
def _EncodeComment(self, comment):
|
||||
"""Encodes a comment to be placed in the project file output, mimicking
|
||||
Xcode behavior.
|
||||
"""
|
||||
Xcode behavior.
|
||||
"""
|
||||
|
||||
# This mimics Xcode behavior by wrapping the comment in "/*" and "*/". If
|
||||
# the string already contains a "*/", it is turned into "(*)/". This keeps
|
||||
|
|
@ -543,8 +542,8 @@ class XCObject:
|
|||
|
||||
def _EncodeString(self, value):
|
||||
"""Encodes a string to be placed in the project file output, mimicking
|
||||
Xcode behavior.
|
||||
"""
|
||||
Xcode behavior.
|
||||
"""
|
||||
|
||||
# Use quotation marks when any character outside of the range A-Z, a-z, 0-9,
|
||||
# $ (dollar sign), . (period), and _ (underscore) is present. Also use
|
||||
|
|
@ -585,18 +584,18 @@ class XCObject:
|
|||
|
||||
def _XCPrintableValue(self, tabs, value, flatten_list=False):
|
||||
"""Returns a representation of value that may be printed in a project file,
|
||||
mimicking Xcode's behavior.
|
||||
mimicking Xcode's behavior.
|
||||
|
||||
_XCPrintableValue can handle str and int values, XCObjects (which are
|
||||
made printable by returning their id property), and list and dict objects
|
||||
composed of any of the above types. When printing a list or dict, and
|
||||
_should_print_single_line is False, the tabs parameter is used to determine
|
||||
how much to indent the lines corresponding to the items in the list or
|
||||
dict.
|
||||
_XCPrintableValue can handle str and int values, XCObjects (which are
|
||||
made printable by returning their id property), and list and dict objects
|
||||
composed of any of the above types. When printing a list or dict, and
|
||||
_should_print_single_line is False, the tabs parameter is used to determine
|
||||
how much to indent the lines corresponding to the items in the list or
|
||||
dict.
|
||||
|
||||
If flatten_list is True, single-element lists will be transformed into
|
||||
strings.
|
||||
"""
|
||||
If flatten_list is True, single-element lists will be transformed into
|
||||
strings.
|
||||
"""
|
||||
|
||||
printable = ""
|
||||
comment = None
|
||||
|
|
@ -657,12 +656,12 @@ class XCObject:
|
|||
|
||||
def _XCKVPrint(self, file, tabs, key, value):
|
||||
"""Prints a key and value, members of an XCObject's _properties dictionary,
|
||||
to file.
|
||||
to file.
|
||||
|
||||
tabs is an int identifying the indentation level. If the class'
|
||||
_should_print_single_line variable is True, tabs is ignored and the
|
||||
key-value pair will be followed by a space instead of a newline.
|
||||
"""
|
||||
tabs is an int identifying the indentation level. If the class'
|
||||
_should_print_single_line variable is True, tabs is ignored and the
|
||||
key-value pair will be followed by a space instead of a newline.
|
||||
"""
|
||||
|
||||
if self._should_print_single_line:
|
||||
printable = ""
|
||||
|
|
@ -720,8 +719,8 @@ class XCObject:
|
|||
|
||||
def Print(self, file=sys.stdout):
|
||||
"""Prints a reprentation of this object to file, adhering to Xcode output
|
||||
formatting.
|
||||
"""
|
||||
formatting.
|
||||
"""
|
||||
|
||||
self.VerifyHasRequiredProperties()
|
||||
|
||||
|
|
@ -759,15 +758,15 @@ class XCObject:
|
|||
def UpdateProperties(self, properties, do_copy=False):
|
||||
"""Merge the supplied properties into the _properties dictionary.
|
||||
|
||||
The input properties must adhere to the class schema or a KeyError or
|
||||
TypeError exception will be raised. If adding an object of an XCObject
|
||||
subclass and the schema indicates a strong relationship, the object's
|
||||
parent will be set to this object.
|
||||
The input properties must adhere to the class schema or a KeyError or
|
||||
TypeError exception will be raised. If adding an object of an XCObject
|
||||
subclass and the schema indicates a strong relationship, the object's
|
||||
parent will be set to this object.
|
||||
|
||||
If do_copy is True, then lists, dicts, strong-owned XCObjects, and
|
||||
strong-owned XCObjects in lists will be copied instead of having their
|
||||
references added.
|
||||
"""
|
||||
If do_copy is True, then lists, dicts, strong-owned XCObjects, and
|
||||
strong-owned XCObjects in lists will be copied instead of having their
|
||||
references added.
|
||||
"""
|
||||
|
||||
if properties is None:
|
||||
return
|
||||
|
|
@ -908,8 +907,8 @@ class XCObject:
|
|||
|
||||
def VerifyHasRequiredProperties(self):
|
||||
"""Ensure that all properties identified as required by the schema are
|
||||
set.
|
||||
"""
|
||||
set.
|
||||
"""
|
||||
|
||||
# TODO(mark): A stronger verification mechanism is needed. Some
|
||||
# subclasses need to perform validation beyond what the schema can enforce.
|
||||
|
|
@ -920,7 +919,7 @@ class XCObject:
|
|||
|
||||
def _SetDefaultsFromSchema(self):
|
||||
"""Assign object default values according to the schema. This will not
|
||||
overwrite properties that have already been set."""
|
||||
overwrite properties that have already been set."""
|
||||
|
||||
defaults = {}
|
||||
for property, attributes in self._schema.items():
|
||||
|
|
@ -942,7 +941,7 @@ class XCObject:
|
|||
|
||||
class XCHierarchicalElement(XCObject):
|
||||
"""Abstract base for PBXGroup and PBXFileReference. Not represented in a
|
||||
project file."""
|
||||
project file."""
|
||||
|
||||
# TODO(mark): Do name and path belong here? Probably so.
|
||||
# If path is set and name is not, name may have a default value. Name will
|
||||
|
|
@ -1008,27 +1007,27 @@ class XCHierarchicalElement(XCObject):
|
|||
def Hashables(self):
|
||||
"""Custom hashables for XCHierarchicalElements.
|
||||
|
||||
XCHierarchicalElements are special. Generally, their hashes shouldn't
|
||||
change if the paths don't change. The normal XCObject implementation of
|
||||
Hashables adds a hashable for each object, which means that if
|
||||
the hierarchical structure changes (possibly due to changes caused when
|
||||
TakeOverOnlyChild runs and encounters slight changes in the hierarchy),
|
||||
the hashes will change. For example, if a project file initially contains
|
||||
a/b/f1 and a/b becomes collapsed into a/b, f1 will have a single parent
|
||||
a/b. If someone later adds a/f2 to the project file, a/b can no longer be
|
||||
collapsed, and f1 winds up with parent b and grandparent a. That would
|
||||
be sufficient to change f1's hash.
|
||||
XCHierarchicalElements are special. Generally, their hashes shouldn't
|
||||
change if the paths don't change. The normal XCObject implementation of
|
||||
Hashables adds a hashable for each object, which means that if
|
||||
the hierarchical structure changes (possibly due to changes caused when
|
||||
TakeOverOnlyChild runs and encounters slight changes in the hierarchy),
|
||||
the hashes will change. For example, if a project file initially contains
|
||||
a/b/f1 and a/b becomes collapsed into a/b, f1 will have a single parent
|
||||
a/b. If someone later adds a/f2 to the project file, a/b can no longer be
|
||||
collapsed, and f1 winds up with parent b and grandparent a. That would
|
||||
be sufficient to change f1's hash.
|
||||
|
||||
To counteract this problem, hashables for all XCHierarchicalElements except
|
||||
for the main group (which has neither a name nor a path) are taken to be
|
||||
just the set of path components. Because hashables are inherited from
|
||||
parents, this provides assurance that a/b/f1 has the same set of hashables
|
||||
whether its parent is b or a/b.
|
||||
To counteract this problem, hashables for all XCHierarchicalElements except
|
||||
for the main group (which has neither a name nor a path) are taken to be
|
||||
just the set of path components. Because hashables are inherited from
|
||||
parents, this provides assurance that a/b/f1 has the same set of hashables
|
||||
whether its parent is b or a/b.
|
||||
|
||||
The main group is a special case. As it is permitted to have no name or
|
||||
path, it is permitted to use the standard XCObject hash mechanism. This
|
||||
is not considered a problem because there can be only one main group.
|
||||
"""
|
||||
The main group is a special case. As it is permitted to have no name or
|
||||
path, it is permitted to use the standard XCObject hash mechanism. This
|
||||
is not considered a problem because there can be only one main group.
|
||||
"""
|
||||
|
||||
if self == self.PBXProjectAncestor()._properties["mainGroup"]:
|
||||
# super
|
||||
|
|
@ -1157,12 +1156,12 @@ class XCHierarchicalElement(XCObject):
|
|||
|
||||
class PBXGroup(XCHierarchicalElement):
|
||||
"""
|
||||
Attributes:
|
||||
_children_by_path: Maps pathnames of children of this PBXGroup to the
|
||||
actual child XCHierarchicalElement objects.
|
||||
_variant_children_by_name_and_path: Maps (name, path) tuples of
|
||||
PBXVariantGroup children to the actual child PBXVariantGroup objects.
|
||||
"""
|
||||
Attributes:
|
||||
_children_by_path: Maps pathnames of children of this PBXGroup to the
|
||||
actual child XCHierarchicalElement objects.
|
||||
_variant_children_by_name_and_path: Maps (name, path) tuples of
|
||||
PBXVariantGroup children to the actual child PBXVariantGroup objects.
|
||||
"""
|
||||
|
||||
_schema = XCHierarchicalElement._schema.copy()
|
||||
_schema.update(
|
||||
|
|
@ -1281,20 +1280,20 @@ class PBXGroup(XCHierarchicalElement):
|
|||
def AddOrGetFileByPath(self, path, hierarchical):
|
||||
"""Returns an existing or new file reference corresponding to path.
|
||||
|
||||
If hierarchical is True, this method will create or use the necessary
|
||||
hierarchical group structure corresponding to path. Otherwise, it will
|
||||
look in and create an item in the current group only.
|
||||
If hierarchical is True, this method will create or use the necessary
|
||||
hierarchical group structure corresponding to path. Otherwise, it will
|
||||
look in and create an item in the current group only.
|
||||
|
||||
If an existing matching reference is found, it is returned, otherwise, a
|
||||
new one will be created, added to the correct group, and returned.
|
||||
If an existing matching reference is found, it is returned, otherwise, a
|
||||
new one will be created, added to the correct group, and returned.
|
||||
|
||||
If path identifies a directory by virtue of carrying a trailing slash,
|
||||
this method returns a PBXFileReference of "folder" type. If path
|
||||
identifies a variant, by virtue of it identifying a file inside a directory
|
||||
with an ".lproj" extension, this method returns a PBXVariantGroup
|
||||
containing the variant named by path, and possibly other variants. For
|
||||
all other paths, a "normal" PBXFileReference will be returned.
|
||||
"""
|
||||
If path identifies a directory by virtue of carrying a trailing slash,
|
||||
this method returns a PBXFileReference of "folder" type. If path
|
||||
identifies a variant, by virtue of it identifying a file inside a directory
|
||||
with an ".lproj" extension, this method returns a PBXVariantGroup
|
||||
containing the variant named by path, and possibly other variants. For
|
||||
all other paths, a "normal" PBXFileReference will be returned.
|
||||
"""
|
||||
|
||||
# Adding or getting a directory? Directories end with a trailing slash.
|
||||
is_dir = False
|
||||
|
|
@ -1379,15 +1378,15 @@ class PBXGroup(XCHierarchicalElement):
|
|||
def AddOrGetVariantGroupByNameAndPath(self, name, path):
|
||||
"""Returns an existing or new PBXVariantGroup for name and path.
|
||||
|
||||
If a PBXVariantGroup identified by the name and path arguments is already
|
||||
present as a child of this object, it is returned. Otherwise, a new
|
||||
PBXVariantGroup with the correct properties is created, added as a child,
|
||||
and returned.
|
||||
If a PBXVariantGroup identified by the name and path arguments is already
|
||||
present as a child of this object, it is returned. Otherwise, a new
|
||||
PBXVariantGroup with the correct properties is created, added as a child,
|
||||
and returned.
|
||||
|
||||
This method will generally be called by AddOrGetFileByPath, which knows
|
||||
when to create a variant group based on the structure of the pathnames
|
||||
passed to it.
|
||||
"""
|
||||
This method will generally be called by AddOrGetFileByPath, which knows
|
||||
when to create a variant group based on the structure of the pathnames
|
||||
passed to it.
|
||||
"""
|
||||
|
||||
key = (name, path)
|
||||
if key in self._variant_children_by_name_and_path:
|
||||
|
|
@ -1405,19 +1404,19 @@ class PBXGroup(XCHierarchicalElement):
|
|||
|
||||
def TakeOverOnlyChild(self, recurse=False):
|
||||
"""If this PBXGroup has only one child and it's also a PBXGroup, take
|
||||
it over by making all of its children this object's children.
|
||||
it over by making all of its children this object's children.
|
||||
|
||||
This function will continue to take over only children when those children
|
||||
are groups. If there are three PBXGroups representing a, b, and c, with
|
||||
c inside b and b inside a, and a and b have no other children, this will
|
||||
result in a taking over both b and c, forming a PBXGroup for a/b/c.
|
||||
This function will continue to take over only children when those children
|
||||
are groups. If there are three PBXGroups representing a, b, and c, with
|
||||
c inside b and b inside a, and a and b have no other children, this will
|
||||
result in a taking over both b and c, forming a PBXGroup for a/b/c.
|
||||
|
||||
If recurse is True, this function will recurse into children and ask them
|
||||
to collapse themselves by taking over only children as well. Assuming
|
||||
an example hierarchy with files at a/b/c/d1, a/b/c/d2, and a/b/c/d3/e/f
|
||||
(d1, d2, and f are files, the rest are groups), recursion will result in
|
||||
a group for a/b/c containing a group for d3/e.
|
||||
"""
|
||||
If recurse is True, this function will recurse into children and ask them
|
||||
to collapse themselves by taking over only children as well. Assuming
|
||||
an example hierarchy with files at a/b/c/d1, a/b/c/d2, and a/b/c/d3/e/f
|
||||
(d1, d2, and f are files, the rest are groups), recursion will result in
|
||||
a group for a/b/c containing a group for d3/e.
|
||||
"""
|
||||
|
||||
# At this stage, check that child class types are PBXGroup exactly,
|
||||
# instead of using isinstance. The only subclass of PBXGroup,
|
||||
|
|
@ -1716,16 +1715,16 @@ class XCConfigurationList(XCObject):
|
|||
|
||||
def HasBuildSetting(self, key):
|
||||
"""Determines the state of a build setting in all XCBuildConfiguration
|
||||
child objects.
|
||||
child objects.
|
||||
|
||||
If all child objects have key in their build settings, and the value is the
|
||||
same in all child objects, returns 1.
|
||||
If all child objects have key in their build settings, and the value is the
|
||||
same in all child objects, returns 1.
|
||||
|
||||
If no child objects have the key in their build settings, returns 0.
|
||||
If no child objects have the key in their build settings, returns 0.
|
||||
|
||||
If some, but not all, child objects have the key in their build settings,
|
||||
or if any children have different values for the key, returns -1.
|
||||
"""
|
||||
If some, but not all, child objects have the key in their build settings,
|
||||
or if any children have different values for the key, returns -1.
|
||||
"""
|
||||
|
||||
has = None
|
||||
value = None
|
||||
|
|
@ -1751,9 +1750,9 @@ class XCConfigurationList(XCObject):
|
|||
def GetBuildSetting(self, key):
|
||||
"""Gets the build setting for key.
|
||||
|
||||
All child XCConfiguration objects must have the same value set for the
|
||||
setting, or a ValueError will be raised.
|
||||
"""
|
||||
All child XCConfiguration objects must have the same value set for the
|
||||
setting, or a ValueError will be raised.
|
||||
"""
|
||||
|
||||
# TODO(mark): This is wrong for build settings that are lists. The list
|
||||
# contents should be compared (and a list copy returned?)
|
||||
|
|
@ -1770,31 +1769,30 @@ class XCConfigurationList(XCObject):
|
|||
|
||||
def SetBuildSetting(self, key, value):
|
||||
"""Sets the build setting for key to value in all child
|
||||
XCBuildConfiguration objects.
|
||||
"""
|
||||
XCBuildConfiguration objects.
|
||||
"""
|
||||
|
||||
for configuration in self._properties["buildConfigurations"]:
|
||||
configuration.SetBuildSetting(key, value)
|
||||
|
||||
def AppendBuildSetting(self, key, value):
|
||||
"""Appends value to the build setting for key, which is treated as a list,
|
||||
in all child XCBuildConfiguration objects.
|
||||
"""
|
||||
in all child XCBuildConfiguration objects.
|
||||
"""
|
||||
|
||||
for configuration in self._properties["buildConfigurations"]:
|
||||
configuration.AppendBuildSetting(key, value)
|
||||
|
||||
def DelBuildSetting(self, key):
|
||||
"""Deletes the build setting key from all child XCBuildConfiguration
|
||||
objects.
|
||||
"""
|
||||
objects.
|
||||
"""
|
||||
|
||||
for configuration in self._properties["buildConfigurations"]:
|
||||
configuration.DelBuildSetting(key)
|
||||
|
||||
def SetBaseConfiguration(self, value):
|
||||
"""Sets the build configuration in all child XCBuildConfiguration objects.
|
||||
"""
|
||||
"""Sets the build configuration in all child XCBuildConfiguration objects."""
|
||||
|
||||
for configuration in self._properties["buildConfigurations"]:
|
||||
configuration.SetBaseConfiguration(value)
|
||||
|
|
@ -1834,14 +1832,14 @@ class PBXBuildFile(XCObject):
|
|||
|
||||
class XCBuildPhase(XCObject):
|
||||
"""Abstract base for build phase classes. Not represented in a project
|
||||
file.
|
||||
file.
|
||||
|
||||
Attributes:
|
||||
_files_by_path: A dict mapping each path of a child in the files list by
|
||||
path (keys) to the corresponding PBXBuildFile children (values).
|
||||
_files_by_xcfilelikeelement: A dict mapping each XCFileLikeElement (keys)
|
||||
to the corresponding PBXBuildFile children (values).
|
||||
"""
|
||||
Attributes:
|
||||
_files_by_path: A dict mapping each path of a child in the files list by
|
||||
path (keys) to the corresponding PBXBuildFile children (values).
|
||||
_files_by_xcfilelikeelement: A dict mapping each XCFileLikeElement (keys)
|
||||
to the corresponding PBXBuildFile children (values).
|
||||
"""
|
||||
|
||||
# TODO(mark): Some build phase types, like PBXShellScriptBuildPhase, don't
|
||||
# actually have a "files" list. XCBuildPhase should not have "files" but
|
||||
|
|
@ -1880,8 +1878,8 @@ class XCBuildPhase(XCObject):
|
|||
def _AddPathToDict(self, pbxbuildfile, path):
|
||||
"""Adds path to the dict tracking paths belonging to this build phase.
|
||||
|
||||
If the path is already a member of this build phase, raises an exception.
|
||||
"""
|
||||
If the path is already a member of this build phase, raises an exception.
|
||||
"""
|
||||
|
||||
if path in self._files_by_path:
|
||||
raise ValueError("Found multiple build files with path " + path)
|
||||
|
|
@ -1890,28 +1888,28 @@ class XCBuildPhase(XCObject):
|
|||
def _AddBuildFileToDicts(self, pbxbuildfile, path=None):
|
||||
"""Maintains the _files_by_path and _files_by_xcfilelikeelement dicts.
|
||||
|
||||
If path is specified, then it is the path that is being added to the
|
||||
phase, and pbxbuildfile must contain either a PBXFileReference directly
|
||||
referencing that path, or it must contain a PBXVariantGroup that itself
|
||||
contains a PBXFileReference referencing the path.
|
||||
If path is specified, then it is the path that is being added to the
|
||||
phase, and pbxbuildfile must contain either a PBXFileReference directly
|
||||
referencing that path, or it must contain a PBXVariantGroup that itself
|
||||
contains a PBXFileReference referencing the path.
|
||||
|
||||
If path is not specified, either the PBXFileReference's path or the paths
|
||||
of all children of the PBXVariantGroup are taken as being added to the
|
||||
phase.
|
||||
If path is not specified, either the PBXFileReference's path or the paths
|
||||
of all children of the PBXVariantGroup are taken as being added to the
|
||||
phase.
|
||||
|
||||
If the path is already present in the phase, raises an exception.
|
||||
If the path is already present in the phase, raises an exception.
|
||||
|
||||
If the PBXFileReference or PBXVariantGroup referenced by pbxbuildfile
|
||||
are already present in the phase, referenced by a different PBXBuildFile
|
||||
object, raises an exception. This does not raise an exception when
|
||||
a PBXFileReference or PBXVariantGroup reappear and are referenced by the
|
||||
same PBXBuildFile that has already introduced them, because in the case
|
||||
of PBXVariantGroup objects, they may correspond to multiple paths that are
|
||||
not all added simultaneously. When this situation occurs, the path needs
|
||||
to be added to _files_by_path, but nothing needs to change in
|
||||
_files_by_xcfilelikeelement, and the caller should have avoided adding
|
||||
the PBXBuildFile if it is already present in the list of children.
|
||||
"""
|
||||
If the PBXFileReference or PBXVariantGroup referenced by pbxbuildfile
|
||||
are already present in the phase, referenced by a different PBXBuildFile
|
||||
object, raises an exception. This does not raise an exception when
|
||||
a PBXFileReference or PBXVariantGroup reappear and are referenced by the
|
||||
same PBXBuildFile that has already introduced them, because in the case
|
||||
of PBXVariantGroup objects, they may correspond to multiple paths that are
|
||||
not all added simultaneously. When this situation occurs, the path needs
|
||||
to be added to _files_by_path, but nothing needs to change in
|
||||
_files_by_xcfilelikeelement, and the caller should have avoided adding
|
||||
the PBXBuildFile if it is already present in the list of children.
|
||||
"""
|
||||
|
||||
xcfilelikeelement = pbxbuildfile._properties["fileRef"]
|
||||
|
||||
|
|
@ -2102,9 +2100,9 @@ class PBXCopyFilesBuildPhase(XCBuildPhase):
|
|||
def SetDestination(self, path):
|
||||
"""Set the dstSubfolderSpec and dstPath properties from path.
|
||||
|
||||
path may be specified in the same notation used for XCHierarchicalElements,
|
||||
specifically, "$(DIR)/path".
|
||||
"""
|
||||
path may be specified in the same notation used for XCHierarchicalElements,
|
||||
specifically, "$(DIR)/path".
|
||||
"""
|
||||
|
||||
if path_tree_match := self.path_tree_re.search(path):
|
||||
path_tree = path_tree_match.group(1)
|
||||
|
|
@ -2178,9 +2176,7 @@ class PBXCopyFilesBuildPhase(XCBuildPhase):
|
|||
subfolder = 0
|
||||
relative_path = path[1:]
|
||||
else:
|
||||
raise ValueError(
|
||||
f"Can't use path {path} in a {self.__class__.__name__}"
|
||||
)
|
||||
raise ValueError(f"Can't use path {path} in a {self.__class__.__name__}")
|
||||
|
||||
self._properties["dstPath"] = relative_path
|
||||
self._properties["dstSubfolderSpec"] = subfolder
|
||||
|
|
@ -2530,9 +2526,9 @@ class PBXNativeTarget(XCTarget):
|
|||
# loadable modules, but there's precedent: Python loadable modules on
|
||||
# Mac OS X use an .so extension.
|
||||
if self._properties["productType"] == "com.googlecode.gyp.xcode.bundle":
|
||||
self._properties[
|
||||
"productType"
|
||||
] = "com.apple.product-type.library.dynamic"
|
||||
self._properties["productType"] = (
|
||||
"com.apple.product-type.library.dynamic"
|
||||
)
|
||||
self.SetBuildSetting("MACH_O_TYPE", "mh_bundle")
|
||||
self.SetBuildSetting("DYLIB_CURRENT_VERSION", "")
|
||||
self.SetBuildSetting("DYLIB_COMPATIBILITY_VERSION", "")
|
||||
|
|
@ -2540,9 +2536,10 @@ class PBXNativeTarget(XCTarget):
|
|||
force_extension = suffix[1:]
|
||||
|
||||
if (
|
||||
self._properties["productType"] in {
|
||||
self._properties["productType"]
|
||||
in {
|
||||
"com.apple.product-type-bundle.unit.test",
|
||||
"com.apple.product-type-bundle.ui-testing"
|
||||
"com.apple.product-type-bundle.ui-testing",
|
||||
}
|
||||
) and force_extension is None:
|
||||
force_extension = suffix[1:]
|
||||
|
|
@ -2694,10 +2691,8 @@ class PBXNativeTarget(XCTarget):
|
|||
other._properties["productType"] == static_library_type
|
||||
or (
|
||||
(
|
||||
other._properties["productType"] in {
|
||||
shared_library_type,
|
||||
framework_type
|
||||
}
|
||||
other._properties["productType"]
|
||||
in {shared_library_type, framework_type}
|
||||
)
|
||||
and (
|
||||
(not other.HasBuildSetting("MACH_O_TYPE"))
|
||||
|
|
@ -2706,7 +2701,6 @@ class PBXNativeTarget(XCTarget):
|
|||
)
|
||||
)
|
||||
):
|
||||
|
||||
file_ref = other.GetProperty("productReference")
|
||||
|
||||
pbxproject = self.PBXProjectAncestor()
|
||||
|
|
@ -2732,13 +2726,13 @@ class PBXProject(XCContainerPortal):
|
|||
# PBXContainerItemProxy.
|
||||
"""
|
||||
|
||||
Attributes:
|
||||
path: "sample.xcodeproj". TODO(mark) Document me!
|
||||
_other_pbxprojects: A dictionary, keyed by other PBXProject objects. Each
|
||||
value is a reference to the dict in the
|
||||
projectReferences list associated with the keyed
|
||||
PBXProject.
|
||||
"""
|
||||
Attributes:
|
||||
path: "sample.xcodeproj". TODO(mark) Document me!
|
||||
_other_pbxprojects: A dictionary, keyed by other PBXProject objects. Each
|
||||
value is a reference to the dict in the
|
||||
projectReferences list associated with the keyed
|
||||
PBXProject.
|
||||
"""
|
||||
|
||||
_schema = XCContainerPortal._schema.copy()
|
||||
_schema.update(
|
||||
|
|
@ -2833,17 +2827,17 @@ class PBXProject(XCContainerPortal):
|
|||
def RootGroupForPath(self, path):
|
||||
"""Returns a PBXGroup child of this object to which path should be added.
|
||||
|
||||
This method is intended to choose between SourceGroup and
|
||||
IntermediatesGroup on the basis of whether path is present in a source
|
||||
directory or an intermediates directory. For the purposes of this
|
||||
determination, any path located within a derived file directory such as
|
||||
PROJECT_DERIVED_FILE_DIR is treated as being in an intermediates
|
||||
directory.
|
||||
This method is intended to choose between SourceGroup and
|
||||
IntermediatesGroup on the basis of whether path is present in a source
|
||||
directory or an intermediates directory. For the purposes of this
|
||||
determination, any path located within a derived file directory such as
|
||||
PROJECT_DERIVED_FILE_DIR is treated as being in an intermediates
|
||||
directory.
|
||||
|
||||
The returned value is a two-element tuple. The first element is the
|
||||
PBXGroup, and the second element specifies whether that group should be
|
||||
organized hierarchically (True) or as a single flat list (False).
|
||||
"""
|
||||
The returned value is a two-element tuple. The first element is the
|
||||
PBXGroup, and the second element specifies whether that group should be
|
||||
organized hierarchically (True) or as a single flat list (False).
|
||||
"""
|
||||
|
||||
# TODO(mark): make this a class variable and bind to self on call?
|
||||
# Also, this list is nowhere near exhaustive.
|
||||
|
|
@ -2869,11 +2863,11 @@ class PBXProject(XCContainerPortal):
|
|||
|
||||
def AddOrGetFileInRootGroup(self, path):
|
||||
"""Returns a PBXFileReference corresponding to path in the correct group
|
||||
according to RootGroupForPath's heuristics.
|
||||
according to RootGroupForPath's heuristics.
|
||||
|
||||
If an existing PBXFileReference for path exists, it will be returned.
|
||||
Otherwise, one will be created and returned.
|
||||
"""
|
||||
If an existing PBXFileReference for path exists, it will be returned.
|
||||
Otherwise, one will be created and returned.
|
||||
"""
|
||||
|
||||
(group, hierarchical) = self.RootGroupForPath(path)
|
||||
return group.AddOrGetFileByPath(path, hierarchical)
|
||||
|
|
@ -2923,17 +2917,17 @@ class PBXProject(XCContainerPortal):
|
|||
|
||||
def AddOrGetProjectReference(self, other_pbxproject):
|
||||
"""Add a reference to another project file (via PBXProject object) to this
|
||||
one.
|
||||
one.
|
||||
|
||||
Returns [ProductGroup, ProjectRef]. ProductGroup is a PBXGroup object in
|
||||
this project file that contains a PBXReferenceProxy object for each
|
||||
product of each PBXNativeTarget in the other project file. ProjectRef is
|
||||
a PBXFileReference to the other project file.
|
||||
Returns [ProductGroup, ProjectRef]. ProductGroup is a PBXGroup object in
|
||||
this project file that contains a PBXReferenceProxy object for each
|
||||
product of each PBXNativeTarget in the other project file. ProjectRef is
|
||||
a PBXFileReference to the other project file.
|
||||
|
||||
If this project file already references the other project file, the
|
||||
existing ProductGroup and ProjectRef are returned. The ProductGroup will
|
||||
still be updated if necessary.
|
||||
"""
|
||||
If this project file already references the other project file, the
|
||||
existing ProductGroup and ProjectRef are returned. The ProductGroup will
|
||||
still be updated if necessary.
|
||||
"""
|
||||
|
||||
if "projectReferences" not in self._properties:
|
||||
self._properties["projectReferences"] = []
|
||||
|
|
@ -2985,7 +2979,7 @@ class PBXProject(XCContainerPortal):
|
|||
# Xcode seems to sort this list case-insensitively
|
||||
self._properties["projectReferences"] = sorted(
|
||||
self._properties["projectReferences"],
|
||||
key=lambda x: x["ProjectRef"].Name().lower()
|
||||
key=lambda x: x["ProjectRef"].Name().lower(),
|
||||
)
|
||||
else:
|
||||
# The link already exists. Pull out the relevant data.
|
||||
|
|
@ -3010,11 +3004,8 @@ class PBXProject(XCContainerPortal):
|
|||
# define an explicit value for 'SYMROOT'.
|
||||
symroots = self._DefinedSymroots(target)
|
||||
for s in self._DefinedSymroots(target):
|
||||
if (
|
||||
(s is not None
|
||||
and not self._IsUniqueSymrootForTarget(s))
|
||||
or (s is None
|
||||
and not inherit_unique_symroot)
|
||||
if (s is not None and not self._IsUniqueSymrootForTarget(s)) or (
|
||||
s is None and not inherit_unique_symroot
|
||||
):
|
||||
return False
|
||||
return True if symroots else inherit_unique_symroot
|
||||
|
|
@ -3118,7 +3109,8 @@ class PBXProject(XCContainerPortal):
|
|||
product_group._properties["children"] = sorted(
|
||||
product_group._properties["children"],
|
||||
key=cmp_to_key(
|
||||
lambda x, y, rp=remote_products: CompareProducts(x, y, rp)),
|
||||
lambda x, y, rp=remote_products: CompareProducts(x, y, rp)
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -3152,9 +3144,7 @@ class XCProjectFile(XCObject):
|
|||
self._XCPrint(file, 0, "{ ")
|
||||
else:
|
||||
self._XCPrint(file, 0, "{\n")
|
||||
for property, value in sorted(
|
||||
self._properties.items()
|
||||
):
|
||||
for property, value in sorted(self._properties.items()):
|
||||
if property == "objects":
|
||||
self._PrintObjects(file)
|
||||
else:
|
||||
|
|
@ -3180,9 +3170,7 @@ class XCProjectFile(XCObject):
|
|||
for class_name in sorted(objects_by_class):
|
||||
self._XCPrint(file, 0, "\n")
|
||||
self._XCPrint(file, 0, "/* Begin " + class_name + " section */\n")
|
||||
for object in sorted(
|
||||
objects_by_class[class_name], key=attrgetter("id")
|
||||
):
|
||||
for object in sorted(objects_by_class[class_name], key=attrgetter("id")):
|
||||
object.Print(file)
|
||||
self._XCPrint(file, 0, "/* End " + class_name + " section */\n")
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ Working around this: http://bugs.python.org/issue5752
|
|||
TODO(bradnelson): Consider dropping this when we drop XP support.
|
||||
"""
|
||||
|
||||
|
||||
import xml.dom.minidom
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|||
|
||||
[project]
|
||||
name = "gyp-next"
|
||||
version = "0.20.3"
|
||||
version = "0.20.4"
|
||||
authors = [
|
||||
{ name="Node.js contributors", email="ryzokuken@disroot.org" },
|
||||
]
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
|
||||
"""gyptest.py -- test runner for GYP tests."""
|
||||
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import platform
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@
|
|||
generate input suitable for graphviz to render a dependency graph of
|
||||
targets."""
|
||||
|
||||
|
||||
import collections
|
||||
import json
|
||||
import sys
|
||||
|
|
@ -22,7 +21,7 @@ def ParseTarget(target):
|
|||
|
||||
def LoadEdges(filename, targets):
|
||||
"""Load the edges map from the dump file, and filter it to only
|
||||
show targets in |targets| and their depedendents."""
|
||||
show targets in |targets| and their depedendents."""
|
||||
|
||||
file = open("dump.json")
|
||||
edges = json.load(file)
|
||||
|
|
@ -43,7 +42,7 @@ def LoadEdges(filename, targets):
|
|||
|
||||
def WriteGraph(edges):
|
||||
"""Print a graphviz graph to stdout.
|
||||
|edges| is a map of target to a list of other targets it depends on."""
|
||||
|edges| is a map of target to a list of other targets it depends on."""
|
||||
|
||||
# Bucket targets by file.
|
||||
files = collections.defaultdict(list)
|
||||
|
|
@ -64,9 +63,7 @@ def WriteGraph(edges):
|
|||
# the display by making it a box without an internal node.
|
||||
target = targets[0]
|
||||
build_file, target_name, toolset = ParseTarget(target)
|
||||
print(
|
||||
f' "{target}" [shape=box, label="{filename}\\n{target_name}"]'
|
||||
)
|
||||
print(f' "{target}" [shape=box, label="{filename}\\n{target_name}"]')
|
||||
else:
|
||||
# Group multiple nodes together in a subgraph.
|
||||
print(' subgraph "cluster_%s" {' % filename)
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
"""Pretty-prints the contents of a GYP file."""
|
||||
|
||||
|
||||
import re
|
||||
import sys
|
||||
|
||||
|
|
@ -49,7 +48,7 @@ def mask_quotes(input):
|
|||
def do_split(input, masked_input, search_re):
|
||||
output = []
|
||||
mask_output = []
|
||||
for (line, masked_line) in zip(input, masked_input):
|
||||
for line, masked_line in zip(input, masked_input):
|
||||
m = search_re.match(masked_line)
|
||||
while m:
|
||||
split = len(m.group(1))
|
||||
|
|
@ -63,13 +62,13 @@ def do_split(input, masked_input, search_re):
|
|||
|
||||
def split_double_braces(input):
|
||||
"""Masks out the quotes and comments, and then splits appropriate
|
||||
lines (lines that matche the double_*_brace re's above) before
|
||||
indenting them below.
|
||||
lines (lines that matche the double_*_brace re's above) before
|
||||
indenting them below.
|
||||
|
||||
These are used to split lines which have multiple braces on them, so
|
||||
that the indentation looks prettier when all laid out (e.g. closing
|
||||
braces make a nice diagonal line).
|
||||
"""
|
||||
These are used to split lines which have multiple braces on them, so
|
||||
that the indentation looks prettier when all laid out (e.g. closing
|
||||
braces make a nice diagonal line).
|
||||
"""
|
||||
double_open_brace_re = re.compile(r"(.*?[\[\{\(,])(\s*)([\[\{\(])")
|
||||
double_close_brace_re = re.compile(r"(.*?[\]\}\)],?)(\s*)([\]\}\)])")
|
||||
|
||||
|
|
@ -85,8 +84,8 @@ def split_double_braces(input):
|
|||
def count_braces(line):
|
||||
"""keeps track of the number of braces on a given line and returns the result.
|
||||
|
||||
It starts at zero and subtracts for closed braces, and adds for open braces.
|
||||
"""
|
||||
It starts at zero and subtracts for closed braces, and adds for open braces.
|
||||
"""
|
||||
open_braces = ["[", "(", "{"]
|
||||
close_braces = ["]", ")", "}"]
|
||||
closing_prefix_re = re.compile(r"[^\s\]\}\)]\s*[\]\}\)]+,?\s*$")
|
||||
|
|
|
|||
|
|
@ -6,13 +6,12 @@
|
|||
|
||||
"""Prints the information in a sln file in a diffable way.
|
||||
|
||||
It first outputs each projects in alphabetical order with their
|
||||
dependencies.
|
||||
It first outputs each projects in alphabetical order with their
|
||||
dependencies.
|
||||
|
||||
Then it outputs a possible build order.
|
||||
Then it outputs a possible build order.
|
||||
"""
|
||||
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
|
@ -113,7 +112,7 @@ def PrintDependencies(projects, deps):
|
|||
print("---------------------------------------")
|
||||
print("-- --")
|
||||
|
||||
for (project, dep_list) in sorted(deps.items()):
|
||||
for project, dep_list in sorted(deps.items()):
|
||||
print("Project : %s" % project)
|
||||
print("Path : %s" % projects[project][0])
|
||||
if dep_list:
|
||||
|
|
@ -131,7 +130,7 @@ def PrintBuildOrder(projects, deps):
|
|||
print("-- --")
|
||||
|
||||
built = []
|
||||
for (project, _) in sorted(deps.items()):
|
||||
for project, _ in sorted(deps.items()):
|
||||
if project not in built:
|
||||
BuildProject(project, built, projects, deps)
|
||||
|
||||
|
|
@ -139,7 +138,6 @@ def PrintBuildOrder(projects, deps):
|
|||
|
||||
|
||||
def PrintVCProj(projects):
|
||||
|
||||
for project in projects:
|
||||
print("-------------------------------------")
|
||||
print("-------------------------------------")
|
||||
|
|
|
|||
|
|
@ -6,13 +6,12 @@
|
|||
|
||||
"""Make the format of a vcproj really pretty.
|
||||
|
||||
This script normalize and sort an xml. It also fetches all the properties
|
||||
inside linked vsprops and include them explicitly in the vcproj.
|
||||
This script normalize and sort an xml. It also fetches all the properties
|
||||
inside linked vsprops and include them explicitly in the vcproj.
|
||||
|
||||
It outputs the resulting xml to stdout.
|
||||
It outputs the resulting xml to stdout.
|
||||
"""
|
||||
|
||||
|
||||
import os
|
||||
import sys
|
||||
from xml.dom.minidom import Node, parse
|
||||
|
|
@ -48,11 +47,11 @@ class CmpNode:
|
|||
node_string += node.getAttribute("Name")
|
||||
|
||||
all_nodes = []
|
||||
for (name, value) in node.attributes.items():
|
||||
for name, value in node.attributes.items():
|
||||
all_nodes.append((name, value))
|
||||
|
||||
all_nodes.sort(CmpTuple())
|
||||
for (name, value) in all_nodes:
|
||||
for name, value in all_nodes:
|
||||
node_string += name
|
||||
node_string += value
|
||||
|
||||
|
|
@ -81,10 +80,10 @@ def PrettyPrintNode(node, indent=0):
|
|||
print("{}<{}".format(" " * indent, node.nodeName))
|
||||
|
||||
all_attributes = []
|
||||
for (name, value) in node.attributes.items():
|
||||
for name, value in node.attributes.items():
|
||||
all_attributes.append((name, value))
|
||||
all_attributes.sort(CmpTuple())
|
||||
for (name, value) in all_attributes:
|
||||
for name, value in all_attributes:
|
||||
print('{} {}="{}"'.format(" " * indent, name, value))
|
||||
print("%s>" % (" " * indent))
|
||||
if node.nodeValue:
|
||||
|
|
@ -130,7 +129,7 @@ def FixFilenames(filenames, current_directory):
|
|||
def AbsoluteNode(node):
|
||||
"""Makes all the properties we know about in this node absolute."""
|
||||
if node.attributes:
|
||||
for (name, value) in node.attributes.items():
|
||||
for name, value in node.attributes.items():
|
||||
if name in [
|
||||
"InheritedPropertySheets",
|
||||
"RelativePath",
|
||||
|
|
@ -163,7 +162,7 @@ def CleanupVcproj(node):
|
|||
# Fix all the semicolon separated attributes to be sorted, and we also
|
||||
# remove the dups.
|
||||
if node.attributes:
|
||||
for (name, value) in node.attributes.items():
|
||||
for name, value in node.attributes.items():
|
||||
sorted_list = sorted(value.split(";"))
|
||||
unique_list = []
|
||||
for i in sorted_list:
|
||||
|
|
@ -252,7 +251,7 @@ def MergeAttributes(node1, node2):
|
|||
if not node2.attributes:
|
||||
return
|
||||
|
||||
for (name, value2) in node2.attributes.items():
|
||||
for name, value2 in node2.attributes.items():
|
||||
# Don't merge the 'Name' attribute.
|
||||
if name == "Name":
|
||||
continue
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user