Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
MSVSUtil.py271 linesDownload Raw Back to gyp
1# Copyright (c) 2013 Google Inc. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Utility functions shared amongst the Windows generators."""
6
7import copy
8import os
9
10# A dictionary mapping supported target types to extensions.
11TARGET_TYPE_EXT = {
12    "executable": "exe",
13    "loadable_module": "dll",
14    "shared_library": "dll",
15    "static_library": "lib",
16    "windows_driver": "sys",
17}
18
19
20def _GetLargePdbShimCcPath():
21    """Returns the path of the large_pdb_shim.cc file."""
22    this_dir = os.path.abspath(os.path.dirname(__file__))
23    src_dir = os.path.abspath(os.path.join(this_dir, "..", ".."))
24    win_data_dir = os.path.join(src_dir, "data", "win")
25    large_pdb_shim_cc = os.path.join(win_data_dir, "large-pdb-shim.cc")
26    return large_pdb_shim_cc
27
28
29def _DeepCopySomeKeys(in_dict, keys):
30    """Performs a partial deep-copy on |in_dict|, only copying the keys in |keys|.
31
32    Arguments:
33      in_dict: The dictionary to copy.
34      keys: The keys to be copied. If a key is in this list and doesn't exist in
35          |in_dict| this is not an error.
36    Returns:
37      The partially deep-copied dictionary.
38    """
39    d = {}
40    for key in keys:
41        if key not in in_dict:
42            continue
43        d[key] = copy.deepcopy(in_dict[key])
44    return d
45
46
47def _SuffixName(name, suffix):
48    """Add a suffix to the end of a target.
49
50    Arguments:
51      name: name of the target (foo#target)
52      suffix: the suffix to be added
53    Returns:
54      Target name with suffix added (foo_suffix#target)
55    """
56    parts = name.rsplit("#", 1)
57    parts[0] = f"{parts[0]}_{suffix}"
58    return "#".join(parts)
59
60
61def _ShardName(name, number):
62    """Add a shard number to the end of a target.
63
64    Arguments:
65      name: name of the target (foo#target)
66      number: shard number
67    Returns:
68      Target name with shard added (foo_1#target)
69    """
70    return _SuffixName(name, str(number))
71
72
73def ShardTargets(target_list, target_dicts):
74    """Shard some targets apart to work around the linkers limits.
75
76    Arguments:
77      target_list: List of target pairs: 'base/base.gyp:base'.
78      target_dicts: Dict of target properties keyed on target pair.
79    Returns:
80      Tuple of the new sharded versions of the inputs.
81    """
82    # Gather the targets to shard, and how many pieces.
83    targets_to_shard = {}
84    for t in target_dicts:
85        shards = int(target_dicts[t].get("msvs_shard", 0))
86        if shards:
87            targets_to_shard[t] = shards
88    # Shard target_list.
89    new_target_list = []
90    for t in target_list:
91        if t in targets_to_shard:
92            for i in range(targets_to_shard[t]):
93                new_target_list.append(_ShardName(t, i))
94        else:
95            new_target_list.append(t)
96    # Shard target_dict.
97    new_target_dicts = {}
98    for t in target_dicts:
99        if t in targets_to_shard:
100            for i in range(targets_to_shard[t]):
101                name = _ShardName(t, i)
102                new_target_dicts[name] = copy.copy(target_dicts[t])
103                new_target_dicts[name]["target_name"] = _ShardName(
104                    new_target_dicts[name]["target_name"], i
105                )
106                sources = new_target_dicts[name].get("sources", [])
107                new_sources = []
108                for pos in range(i, len(sources), targets_to_shard[t]):
109                    new_sources.append(sources[pos])
110                new_target_dicts[name]["sources"] = new_sources
111        else:
112            new_target_dicts[t] = target_dicts[t]
113    # Shard dependencies.
114    for t in sorted(new_target_dicts):
115        for deptype in ("dependencies", "dependencies_original"):
116            dependencies = copy.copy(new_target_dicts[t].get(deptype, []))
117            new_dependencies = []
118            for d in dependencies:
119                if d in targets_to_shard:
120                    for i in range(targets_to_shard[d]):
121                        new_dependencies.append(_ShardName(d, i))
122                else:
123                    new_dependencies.append(d)
124            new_target_dicts[t][deptype] = new_dependencies
125
126    return (new_target_list, new_target_dicts)
127
128
129def _GetPdbPath(target_dict, config_name, vars):
130    """Returns the path to the PDB file that will be generated by a given
131    configuration.
132
133    The lookup proceeds as follows:
134      - Look for an explicit path in the VCLinkerTool configuration block.
135      - Look for an 'msvs_large_pdb_path' variable.
136      - Use '<(PRODUCT_DIR)/<(product_name).(exe|dll).pdb' if 'product_name' is
137        specified.
138      - Use '<(PRODUCT_DIR)/<(target_name).(exe|dll).pdb'.
139
140    Arguments:
141      target_dict: The target dictionary to be searched.
142      config_name: The name of the configuration of interest.
143      vars: A dictionary of common GYP variables with generator-specific values.
144    Returns:
145      The path of the corresponding PDB file.
146    """
147    config = target_dict["configurations"][config_name]
148    msvs = config.setdefault("msvs_settings", {})
149
150    linker = msvs.get("VCLinkerTool", {})
151
152    pdb_path = linker.get("ProgramDatabaseFile")
153    if pdb_path:
154        return pdb_path
155
156    variables = target_dict.get("variables", {})
157    pdb_path = variables.get("msvs_large_pdb_path", None)
158    if pdb_path:
159        return pdb_path
160
161    pdb_base = target_dict.get("product_name", target_dict["target_name"])
162    pdb_base = "{}.{}.pdb".format(pdb_base, TARGET_TYPE_EXT[target_dict["type"]])
163    pdb_path = vars["PRODUCT_DIR"] + "/" + pdb_base
164
165    return pdb_path
166
167
168def InsertLargePdbShims(target_list, target_dicts, vars):
169    """Insert a shim target that forces the linker to use 4KB pagesize PDBs.
170
171    This is a workaround for targets with PDBs greater than 1GB in size, the
172    limit for the 1KB pagesize PDBs created by the linker by default.
173
174    Arguments:
175      target_list: List of target pairs: 'base/base.gyp:base'.
176      target_dicts: Dict of target properties keyed on target pair.
177      vars: A dictionary of common GYP variables with generator-specific values.
178    Returns:
179      Tuple of the shimmed version of the inputs.
180    """
181    # Determine which targets need shimming.
182    targets_to_shim = []
183    for t in target_dicts:
184        target_dict = target_dicts[t]
185
186        # We only want to shim targets that have msvs_large_pdb enabled.
187        if not int(target_dict.get("msvs_large_pdb", 0)):
188            continue
189        # This is intended for executable, shared_library and loadable_module
190        # targets where every configuration is set up to produce a PDB output.
191        # If any of these conditions is not true then the shim logic will fail
192        # below.
193        targets_to_shim.append(t)
194
195    large_pdb_shim_cc = _GetLargePdbShimCcPath()
196
197    for t in targets_to_shim:
198        target_dict = target_dicts[t]
199        target_name = target_dict.get("target_name")
200
201        base_dict = _DeepCopySomeKeys(
202            target_dict, ["configurations", "default_configuration", "toolset"]
203        )
204
205        # This is the dict for copying the source file (part of the GYP tree)
206        # to the intermediate directory of the project. This is necessary because
207        # we can't always build a relative path to the shim source file (on Windows
208        # GYP and the project may be on different drives), and Ninja hates absolute
209        # paths (it ends up generating the .obj and .obj.d alongside the source
210        # file, polluting GYPs tree).
211        copy_suffix = "large_pdb_copy"
212        copy_target_name = target_name + "_" + copy_suffix
213        full_copy_target_name = _SuffixName(t, copy_suffix)
214        shim_cc_basename = os.path.basename(large_pdb_shim_cc)
215        shim_cc_dir = vars["SHARED_INTERMEDIATE_DIR"] + "/" + copy_target_name
216        shim_cc_path = shim_cc_dir + "/" + shim_cc_basename
217        copy_dict = copy.deepcopy(base_dict)
218        copy_dict["target_name"] = copy_target_name
219        copy_dict["type"] = "none"
220        copy_dict["sources"] = [large_pdb_shim_cc]
221        copy_dict["copies"] = [
222            {"destination": shim_cc_dir, "files": [large_pdb_shim_cc]}
223        ]
224
225        # This is the dict for the PDB generating shim target. It depends on the
226        # copy target.
227        shim_suffix = "large_pdb_shim"
228        shim_target_name = target_name + "_" + shim_suffix
229        full_shim_target_name = _SuffixName(t, shim_suffix)
230        shim_dict = copy.deepcopy(base_dict)
231        shim_dict["target_name"] = shim_target_name
232        shim_dict["type"] = "static_library"
233        shim_dict["sources"] = [shim_cc_path]
234        shim_dict["dependencies"] = [full_copy_target_name]
235
236        # Set up the shim to output its PDB to the same location as the final linker
237        # target.
238        for config_name, config in shim_dict.get("configurations").items():
239            pdb_path = _GetPdbPath(target_dict, config_name, vars)
240
241            # A few keys that we don't want to propagate.
242            for key in ["msvs_precompiled_header", "msvs_precompiled_source", "test"]:
243                config.pop(key, None)
244
245            msvs = config.setdefault("msvs_settings", {})
246
247            # Update the compiler directives in the shim target.
248            compiler = msvs.setdefault("VCCLCompilerTool", {})
249            compiler["DebugInformationFormat"] = "3"
250            compiler["ProgramDataBaseFileName"] = pdb_path
251
252            # Set the explicit PDB path in the appropriate configuration of the
253            # original target.
254            config = target_dict["configurations"][config_name]
255            msvs = config.setdefault("msvs_settings", {})
256            linker = msvs.setdefault("VCLinkerTool", {})
257            linker["GenerateDebugInformation"] = "true"
258            linker["ProgramDatabaseFile"] = pdb_path
259
260        # Add the new targets. They must go to the beginning of the list so that
261        # the dependency generation works as expected in ninja.
262        target_list.insert(0, full_copy_target_name)
263        target_list.insert(0, full_shim_target_name)
264        target_dicts[full_copy_target_name] = copy_dict
265        target_dicts[full_shim_target_name] = shim_dict
266
267        # Update the original target to depend on the shim target.
268        target_dict.setdefault("dependencies", []).append(full_shim_target_name)
269
270    return (target_list, target_dicts)
271 
codekingpro/portable-devtools · Team Ai