Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
xcode_emulation.py1937 linesDownload Raw Back to gyp
1# Copyright (c) 2012 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"""
6This module contains classes that help to emulate xcodebuild behavior on top of
7other build systems, such as make and ninja.
8"""
9
10import copy
11import os
12import os.path
13import re
14import shlex
15import subprocess
16import sys
17
18import gyp.common
19from gyp.common import GypError
20
21# Populated lazily by XcodeVersion, for efficiency, and to fix an issue when
22# "xcodebuild" is called too quickly (it has been found to return incorrect
23# version number).
24XCODE_VERSION_CACHE = None
25
26# Populated lazily by GetXcodeArchsDefault, to an |XcodeArchsDefault| instance
27# corresponding to the installed version of Xcode.
28XCODE_ARCHS_DEFAULT_CACHE = None
29
30
31def XcodeArchsVariableMapping(archs, archs_including_64_bit=None):
32    """Constructs a dictionary with expansion for $(ARCHS_STANDARD) variable,
33    and optionally for $(ARCHS_STANDARD_INCLUDING_64_BIT)."""
34    mapping = {"$(ARCHS_STANDARD)": archs}
35    if archs_including_64_bit:
36        mapping["$(ARCHS_STANDARD_INCLUDING_64_BIT)"] = archs_including_64_bit
37    return mapping
38
39
40class XcodeArchsDefault:
41    """A class to resolve ARCHS variable from xcode_settings, resolving Xcode
42    macros and implementing filtering by VALID_ARCHS. The expansion of macros
43    depends on the SDKROOT used ("macosx", "iphoneos", "iphonesimulator") and
44    on the version of Xcode.
45    """
46
47    # Match variable like $(ARCHS_STANDARD).
48    variable_pattern = re.compile(r"\$\([a-zA-Z_][a-zA-Z0-9_]*\)$")
49
50    def __init__(self, default, mac, iphonesimulator, iphoneos):
51        self._default = (default,)
52        self._archs = {"mac": mac, "ios": iphoneos, "iossim": iphonesimulator}
53
54    def _VariableMapping(self, sdkroot):
55        """Returns the dictionary of variable mapping depending on the SDKROOT."""
56        sdkroot = sdkroot.lower()
57        if "iphoneos" in sdkroot:
58            return self._archs["ios"]
59        elif "iphonesimulator" in sdkroot:
60            return self._archs["iossim"]
61        else:
62            return self._archs["mac"]
63
64    def _ExpandArchs(self, archs, sdkroot):
65        """Expands variables references in ARCHS, and remove duplicates."""
66        variable_mapping = self._VariableMapping(sdkroot)
67        expanded_archs = []
68        for arch in archs:
69            if self.variable_pattern.match(arch):
70                variable = arch
71                try:
72                    variable_expansion = variable_mapping[variable]
73                    for arch in variable_expansion:
74                        if arch not in expanded_archs:
75                            expanded_archs.append(arch)
76                except KeyError:
77                    print('Warning: Ignoring unsupported variable "%s".' % variable)
78            elif arch not in expanded_archs:
79                expanded_archs.append(arch)
80        return expanded_archs
81
82    def ActiveArchs(self, archs, valid_archs, sdkroot):
83        """Expands variables references in ARCHS, and filter by VALID_ARCHS if it
84        is defined (if not set, Xcode accept any value in ARCHS, otherwise, only
85        values present in VALID_ARCHS are kept)."""
86        expanded_archs = self._ExpandArchs(archs or self._default, sdkroot or "")
87        if valid_archs:
88            filtered_archs = []
89            for arch in expanded_archs:
90                if arch in valid_archs:
91                    filtered_archs.append(arch)
92            expanded_archs = filtered_archs
93        return expanded_archs
94
95
96def GetXcodeArchsDefault():
97    """Returns the |XcodeArchsDefault| object to use to expand ARCHS for the
98    installed version of Xcode. The default values used by Xcode for ARCHS
99    and the expansion of the variables depends on the version of Xcode used.
100
101    For all version anterior to Xcode 5.0 or posterior to Xcode 5.1 included
102    uses $(ARCHS_STANDARD) if ARCHS is unset, while Xcode 5.0 to 5.0.2 uses
103    $(ARCHS_STANDARD_INCLUDING_64_BIT). This variable was added to Xcode 5.0
104    and deprecated with Xcode 5.1.
105
106    For "macosx" SDKROOT, all version starting with Xcode 5.0 includes 64-bit
107    architecture as part of $(ARCHS_STANDARD) and default to only building it.
108
109    For "iphoneos" and "iphonesimulator" SDKROOT, 64-bit architectures are part
110    of $(ARCHS_STANDARD_INCLUDING_64_BIT) from Xcode 5.0. From Xcode 5.1, they
111    are also part of $(ARCHS_STANDARD).
112
113    All these rules are coded in the construction of the |XcodeArchsDefault|
114    object to use depending on the version of Xcode detected. The object is
115    for performance reason."""
116    global XCODE_ARCHS_DEFAULT_CACHE
117    if XCODE_ARCHS_DEFAULT_CACHE:
118        return XCODE_ARCHS_DEFAULT_CACHE
119    xcode_version, _ = XcodeVersion()
120    if xcode_version < "0500":
121        XCODE_ARCHS_DEFAULT_CACHE = XcodeArchsDefault(
122            "$(ARCHS_STANDARD)",
123            XcodeArchsVariableMapping(["i386"]),
124            XcodeArchsVariableMapping(["i386"]),
125            XcodeArchsVariableMapping(["armv7"]),
126        )
127    elif xcode_version < "0510":
128        XCODE_ARCHS_DEFAULT_CACHE = XcodeArchsDefault(
129            "$(ARCHS_STANDARD_INCLUDING_64_BIT)",
130            XcodeArchsVariableMapping(["x86_64"], ["x86_64"]),
131            XcodeArchsVariableMapping(["i386"], ["i386", "x86_64"]),
132            XcodeArchsVariableMapping(
133                ["armv7", "armv7s"], ["armv7", "armv7s", "arm64"]
134            ),
135        )
136    else:
137        XCODE_ARCHS_DEFAULT_CACHE = XcodeArchsDefault(
138            "$(ARCHS_STANDARD)",
139            XcodeArchsVariableMapping(["x86_64"], ["x86_64"]),
140            XcodeArchsVariableMapping(["i386", "x86_64"], ["i386", "x86_64"]),
141            XcodeArchsVariableMapping(
142                ["armv7", "armv7s", "arm64"], ["armv7", "armv7s", "arm64"]
143            ),
144        )
145    return XCODE_ARCHS_DEFAULT_CACHE
146
147
148class XcodeSettings:
149    """A class that understands the gyp 'xcode_settings' object."""
150
151    # Populated lazily by _SdkPath(). Shared by all XcodeSettings, so cached
152    # at class-level for efficiency.
153    _sdk_path_cache = {}
154    _platform_path_cache = {}
155    _sdk_root_cache = {}
156
157    # Populated lazily by GetExtraPlistItems(). Shared by all XcodeSettings, so
158    # cached at class-level for efficiency.
159    _plist_cache = {}
160
161    # Populated lazily by GetIOSPostbuilds.  Shared by all XcodeSettings, so
162    # cached at class-level for efficiency.
163    _codesigning_key_cache = {}
164
165    def __init__(self, spec):
166        self.spec = spec
167
168        self.isIOS = False
169        self.mac_toolchain_dir = None
170        self.header_map_path = None
171
172        # Per-target 'xcode_settings' are pushed down into configs earlier by gyp.
173        # This means self.xcode_settings[config] always contains all settings
174        # for that config -- the per-target settings as well. Settings that are
175        # the same for all configs are implicitly per-target settings.
176        self.xcode_settings = {}
177        configs = spec["configurations"]
178        for configname, config in configs.items():
179            self.xcode_settings[configname] = config.get("xcode_settings", {})
180            self._ConvertConditionalKeys(configname)
181            if self.xcode_settings[configname].get("IPHONEOS_DEPLOYMENT_TARGET", None):
182                self.isIOS = True
183
184        # This is only non-None temporarily during the execution of some methods.
185        self.configname = None
186
187        # Used by _AdjustLibrary to match .a and .dylib entries in libraries.
188        self.library_re = re.compile(r"^lib([^/]+)\.(a|dylib)$")
189
190    def _ConvertConditionalKeys(self, configname):
191        """Converts or warns on conditional keys.  Xcode supports conditional keys,
192        such as CODE_SIGN_IDENTITY[sdk=iphoneos*].  This is a partial implementation
193        with some keys converted while the rest force a warning."""
194        settings = self.xcode_settings[configname]
195        conditional_keys = [key for key in settings if key.endswith("]")]
196        for key in conditional_keys:
197            # If you need more, speak up at http://crbug.com/122592
198            if key.endswith("[sdk=iphoneos*]"):
199                if configname.endswith("iphoneos"):
200                    new_key = key.split("[")[0]
201                    settings[new_key] = settings[key]
202            else:
203                print(
204                    "Warning: Conditional keys not implemented, ignoring:",
205                    " ".join(conditional_keys),
206                )
207            del settings[key]
208
209    def _Settings(self):
210        assert self.configname
211        return self.xcode_settings[self.configname]
212
213    def _Test(self, test_key, cond_key, default):
214        return self._Settings().get(test_key, default) == cond_key
215
216    def _Appendf(self, lst, test_key, format_str, default=None):
217        if test_key in self._Settings():
218            lst.append(format_str % str(self._Settings()[test_key]))
219        elif default:
220            lst.append(format_str % str(default))
221
222    def _WarnUnimplemented(self, test_key):
223        if test_key in self._Settings():
224            print('Warning: Ignoring not yet implemented key "%s".' % test_key)
225
226    def IsBinaryOutputFormat(self, configname):
227        default = "binary" if self.isIOS else "xml"
228        format = self.xcode_settings[configname].get("INFOPLIST_OUTPUT_FORMAT", default)
229        return format == "binary"
230
231    def IsIosFramework(self):
232        return self.spec["type"] == "shared_library" and self._IsBundle() and self.isIOS
233
234    def _IsBundle(self):
235        return (
236            int(self.spec.get("mac_bundle", 0)) != 0
237            or self._IsXCTest()
238            or self._IsXCUiTest()
239        )
240
241    def _IsXCTest(self):
242        return int(self.spec.get("mac_xctest_bundle", 0)) != 0
243
244    def _IsXCUiTest(self):
245        return int(self.spec.get("mac_xcuitest_bundle", 0)) != 0
246
247    def _IsIosAppExtension(self):
248        return int(self.spec.get("ios_app_extension", 0)) != 0
249
250    def _IsIosWatchKitExtension(self):
251        return int(self.spec.get("ios_watchkit_extension", 0)) != 0
252
253    def _IsIosWatchApp(self):
254        return int(self.spec.get("ios_watch_app", 0)) != 0
255
256    def GetFrameworkVersion(self):
257        """Returns the framework version of the current target. Only valid for
258        bundles."""
259        assert self._IsBundle()
260        return self.GetPerTargetSetting("FRAMEWORK_VERSION", default="A")
261
262    def GetWrapperExtension(self):
263        """Returns the bundle extension (.app, .framework, .plugin, etc).  Only
264        valid for bundles."""
265        assert self._IsBundle()
266        if self.spec["type"] in ("loadable_module", "shared_library"):
267            default_wrapper_extension = {
268                "loadable_module": "bundle",
269                "shared_library": "framework",
270            }[self.spec["type"]]
271            wrapper_extension = self.GetPerTargetSetting(
272                "WRAPPER_EXTENSION", default=default_wrapper_extension
273            )
274            return "." + self.spec.get("product_extension", wrapper_extension)
275        elif self.spec["type"] == "executable":
276            if self._IsIosAppExtension() or self._IsIosWatchKitExtension():
277                return "." + self.spec.get("product_extension", "appex")
278            else:
279                return "." + self.spec.get("product_extension", "app")
280        else:
281            assert False, "Don't know extension for '{}', target '{}'".format(
282                self.spec["type"],
283                self.spec["target_name"],
284            )
285
286    def GetProductName(self):
287        """Returns PRODUCT_NAME."""
288        return self.spec.get("product_name", self.spec["target_name"])
289
290    def GetFullProductName(self):
291        """Returns FULL_PRODUCT_NAME."""
292        if self._IsBundle():
293            return self.GetWrapperName()
294        else:
295            return self._GetStandaloneBinaryPath()
296
297    def GetWrapperName(self):
298        """Returns the directory name of the bundle represented by this target.
299        Only valid for bundles."""
300        assert self._IsBundle()
301        return self.GetProductName() + self.GetWrapperExtension()
302
303    def GetBundleContentsFolderPath(self):
304        """Returns the qualified path to the bundle's contents folder. E.g.
305        Chromium.app/Contents or Foo.bundle/Versions/A. Only valid for bundles."""
306        if self.isIOS:
307            return self.GetWrapperName()
308        assert self._IsBundle()
309        if self.spec["type"] == "shared_library":
310            return os.path.join(
311                self.GetWrapperName(), "Versions", self.GetFrameworkVersion()
312            )
313        else:
314            # loadable_modules have a 'Contents' folder like executables.
315            return os.path.join(self.GetWrapperName(), "Contents")
316
317    def GetBundleResourceFolder(self):
318        """Returns the qualified path to the bundle's resource folder. E.g.
319        Chromium.app/Contents/Resources. Only valid for bundles."""
320        assert self._IsBundle()
321        if self.isIOS:
322            return self.GetBundleContentsFolderPath()
323        return os.path.join(self.GetBundleContentsFolderPath(), "Resources")
324
325    def GetBundleExecutableFolderPath(self):
326        """Returns the qualified path to the bundle's executables folder. E.g.
327        Chromium.app/Contents/MacOS. Only valid for bundles."""
328        assert self._IsBundle()
329        if self.spec["type"] in ("shared_library") or self.isIOS:
330            return self.GetBundleContentsFolderPath()
331        elif self.spec["type"] in ("executable", "loadable_module"):
332            return os.path.join(self.GetBundleContentsFolderPath(), "MacOS")
333
334    def GetBundleJavaFolderPath(self):
335        """Returns the qualified path to the bundle's Java resource folder.
336        E.g. Chromium.app/Contents/Resources/Java. Only valid for bundles."""
337        assert self._IsBundle()
338        return os.path.join(self.GetBundleResourceFolder(), "Java")
339
340    def GetBundleFrameworksFolderPath(self):
341        """Returns the qualified path to the bundle's frameworks folder. E.g,
342        Chromium.app/Contents/Frameworks. Only valid for bundles."""
343        assert self._IsBundle()
344        return os.path.join(self.GetBundleContentsFolderPath(), "Frameworks")
345
346    def GetBundleSharedFrameworksFolderPath(self):
347        """Returns the qualified path to the bundle's frameworks folder. E.g,
348        Chromium.app/Contents/SharedFrameworks. Only valid for bundles."""
349        assert self._IsBundle()
350        return os.path.join(self.GetBundleContentsFolderPath(), "SharedFrameworks")
351
352    def GetBundleSharedSupportFolderPath(self):
353        """Returns the qualified path to the bundle's shared support folder. E.g,
354        Chromium.app/Contents/SharedSupport. Only valid for bundles."""
355        assert self._IsBundle()
356        if self.spec["type"] == "shared_library":
357            return self.GetBundleResourceFolder()
358        else:
359            return os.path.join(self.GetBundleContentsFolderPath(), "SharedSupport")
360
361    def GetBundlePlugInsFolderPath(self):
362        """Returns the qualified path to the bundle's plugins folder. E.g,
363        Chromium.app/Contents/PlugIns. Only valid for bundles."""
364        assert self._IsBundle()
365        return os.path.join(self.GetBundleContentsFolderPath(), "PlugIns")
366
367    def GetBundleXPCServicesFolderPath(self):
368        """Returns the qualified path to the bundle's XPC services folder. E.g,
369        Chromium.app/Contents/XPCServices. Only valid for bundles."""
370        assert self._IsBundle()
371        return os.path.join(self.GetBundleContentsFolderPath(), "XPCServices")
372
373    def GetBundlePlistPath(self):
374        """Returns the qualified path to the bundle's plist file. E.g.
375        Chromium.app/Contents/Info.plist. Only valid for bundles."""
376        assert self._IsBundle()
377        if (
378            self.spec["type"] in ("executable", "loadable_module")
379            or self.IsIosFramework()
380        ):
381            return os.path.join(self.GetBundleContentsFolderPath(), "Info.plist")
382        else:
383            return os.path.join(
384                self.GetBundleContentsFolderPath(), "Resources", "Info.plist"
385            )
386
387    def GetProductType(self):
388        """Returns the PRODUCT_TYPE of this target."""
389        if self._IsIosAppExtension():
390            assert self._IsBundle(), (
391                "ios_app_extension flag requires mac_bundle "
392                "(target %s)" % self.spec["target_name"]
393            )
394            return "com.apple.product-type.app-extension"
395        if self._IsIosWatchKitExtension():
396            assert self._IsBundle(), (
397                "ios_watchkit_extension flag requires "
398                "mac_bundle (target %s)" % self.spec["target_name"]
399            )
400            return "com.apple.product-type.watchkit-extension"
401        if self._IsIosWatchApp():
402            assert self._IsBundle(), (
403                "ios_watch_app flag requires mac_bundle "
404                "(target %s)" % self.spec["target_name"]
405            )
406            return "com.apple.product-type.application.watchapp"
407        if self._IsXCUiTest():
408            assert self._IsBundle(), (
409                "mac_xcuitest_bundle flag requires mac_bundle "
410                "(target %s)" % self.spec["target_name"]
411            )
412            return "com.apple.product-type.bundle.ui-testing"
413        if self._IsBundle():
414            return {
415                "executable": "com.apple.product-type.application",
416                "loadable_module": "com.apple.product-type.bundle",
417                "shared_library": "com.apple.product-type.framework",
418            }[self.spec["type"]]
419        else:
420            return {
421                "executable": "com.apple.product-type.tool",
422                "loadable_module": "com.apple.product-type.library.dynamic",
423                "shared_library": "com.apple.product-type.library.dynamic",
424                "static_library": "com.apple.product-type.library.static",
425            }[self.spec["type"]]
426
427    def GetMachOType(self):
428        """Returns the MACH_O_TYPE of this target."""
429        # Weird, but matches Xcode.
430        if not self._IsBundle() and self.spec["type"] == "executable":
431            return ""
432        return {
433            "executable": "mh_execute",
434            "static_library": "staticlib",
435            "shared_library": "mh_dylib",
436            "loadable_module": "mh_bundle",
437        }[self.spec["type"]]
438
439    def _GetBundleBinaryPath(self):
440        """Returns the name of the bundle binary of by this target.
441        E.g. Chromium.app/Contents/MacOS/Chromium. Only valid for bundles."""
442        assert self._IsBundle()
443        return os.path.join(
444            self.GetBundleExecutableFolderPath(), self.GetExecutableName()
445        )
446
447    def _GetStandaloneExecutableSuffix(self):
448        if "product_extension" in self.spec:
449            return "." + self.spec["product_extension"]
450        return {
451            "executable": "",
452            "static_library": ".a",
453            "shared_library": ".dylib",
454            "loadable_module": ".so",
455        }[self.spec["type"]]
456
457    def _GetStandaloneExecutablePrefix(self):
458        return self.spec.get(
459            "product_prefix",
460            {
461                "executable": "",
462                "static_library": "lib",
463                "shared_library": "lib",
464                # Non-bundled loadable_modules are called foo.so for some reason
465                # (that is, .so and no prefix) with the xcode build -- match that.
466                "loadable_module": "",
467            }[self.spec["type"]],
468        )
469
470    def _GetStandaloneBinaryPath(self):
471        """Returns the name of the non-bundle binary represented by this target.
472        E.g. hello_world. Only valid for non-bundles."""
473        assert not self._IsBundle()
474        assert self.spec["type"] in {
475            "executable",
476            "shared_library",
477            "static_library",
478            "loadable_module",
479        }, "Unexpected type %s" % self.spec["type"]
480        target = self.spec["target_name"]
481        if self.spec["type"] in {"loadable_module", "shared_library", "static_library"}:
482            if target[:3] == "lib":
483                target = target[3:]
484
485        target_prefix = self._GetStandaloneExecutablePrefix()
486        target = self.spec.get("product_name", target)
487        target_ext = self._GetStandaloneExecutableSuffix()
488        return target_prefix + target + target_ext
489
490    def GetExecutableName(self):
491        """Returns the executable name of the bundle represented by this target.
492        E.g. Chromium."""
493        if self._IsBundle():
494            return self.spec.get("product_name", self.spec["target_name"])
495        else:
496            return self._GetStandaloneBinaryPath()
497
498    def GetExecutablePath(self):
499        """Returns the qualified path to the primary executable of the bundle
500        represented by this target. E.g. Chromium.app/Contents/MacOS/Chromium."""
501        if self._IsBundle():
502            return self._GetBundleBinaryPath()
503        else:
504            return self._GetStandaloneBinaryPath()
505
506    def GetActiveArchs(self, configname):
507        """Returns the architectures this target should be built for."""
508        config_settings = self.xcode_settings[configname]
509        xcode_archs_default = GetXcodeArchsDefault()
510        return xcode_archs_default.ActiveArchs(
511            config_settings.get("ARCHS"),
512            config_settings.get("VALID_ARCHS"),
513            config_settings.get("SDKROOT"),
514        )
515
516    def _GetSdkVersionInfoItem(self, sdk, infoitem):
517        # xcodebuild requires Xcode and can't run on Command Line Tools-only
518        # systems from 10.7 onward.
519        # Since the CLT has no SDK paths anyway, returning None is the
520        # most sensible route and should still do the right thing.
521        try:
522            return GetStdoutQuiet(["xcrun", "--sdk", sdk, infoitem])
523        except (GypError, OSError):
524            pass
525
526    def _SdkRoot(self, configname):
527        if configname is None:
528            configname = self.configname
529        return self.GetPerConfigSetting("SDKROOT", configname, default="")
530
531    def _XcodePlatformPath(self, configname=None):
532        sdk_root = self._SdkRoot(configname)
533        if sdk_root not in XcodeSettings._platform_path_cache:
534            platform_path = self._GetSdkVersionInfoItem(
535                sdk_root, "--show-sdk-platform-path"
536            )
537            XcodeSettings._platform_path_cache[sdk_root] = platform_path
538        return XcodeSettings._platform_path_cache[sdk_root]
539
540    def _SdkPath(self, configname=None):
541        sdk_root = self._SdkRoot(configname)
542        if sdk_root.startswith("/"):
543            return sdk_root
544        return self._XcodeSdkPath(sdk_root)
545
546    def _XcodeSdkPath(self, sdk_root):
547        if sdk_root not in XcodeSettings._sdk_path_cache:
548            sdk_path = self._GetSdkVersionInfoItem(sdk_root, "--show-sdk-path")
549            XcodeSettings._sdk_path_cache[sdk_root] = sdk_path
550            if sdk_root:
551                XcodeSettings._sdk_root_cache[sdk_path] = sdk_root
552        return XcodeSettings._sdk_path_cache[sdk_root]
553
554    def _AppendPlatformVersionMinFlags(self, lst):
555        self._Appendf(lst, "MACOSX_DEPLOYMENT_TARGET", "-mmacosx-version-min=%s")
556        if "IPHONEOS_DEPLOYMENT_TARGET" in self._Settings():
557            # TODO: Implement this better?
558            sdk_path_basename = os.path.basename(self._SdkPath())
559            if sdk_path_basename.lower().startswith("iphonesimulator"):
560                self._Appendf(
561                    lst, "IPHONEOS_DEPLOYMENT_TARGET", "-mios-simulator-version-min=%s"
562                )
563            else:
564                self._Appendf(
565                    lst, "IPHONEOS_DEPLOYMENT_TARGET", "-miphoneos-version-min=%s"
566                )
567
568    def GetCflags(self, configname, arch=None):
569        """Returns flags that need to be added to .c, .cc, .m, and .mm
570        compilations."""
571        # This functions (and the similar ones below) do not offer complete
572        # emulation of all xcode_settings keys. They're implemented on demand.
573
574        self.configname = configname
575        cflags = []
576
577        sdk_root = self._SdkPath()
578        if "SDKROOT" in self._Settings() and sdk_root:
579            cflags.append("-isysroot")
580            cflags.append(sdk_root)
581
582        if self.header_map_path:
583            cflags.append("-I%s" % self.header_map_path)
584
585        if self._Test("CLANG_WARN_CONSTANT_CONVERSION", "YES", default="NO"):
586            cflags.append("-Wconstant-conversion")
587
588        if self._Test("GCC_CHAR_IS_UNSIGNED_CHAR", "YES", default="NO"):
589            cflags.append("-funsigned-char")
590
591        if self._Test("GCC_CW_ASM_SYNTAX", "YES", default="YES"):
592            cflags.append("-fasm-blocks")
593
594        if "GCC_DYNAMIC_NO_PIC" in self._Settings():
595            if self._Settings()["GCC_DYNAMIC_NO_PIC"] == "YES":
596                cflags.append("-mdynamic-no-pic")
597        else:
598            pass
599            # TODO: In this case, it depends on the target. xcode passes
600            # mdynamic-no-pic by default for executable and possibly static lib
601            # according to mento
602
603        if self._Test("GCC_ENABLE_PASCAL_STRINGS", "YES", default="YES"):
604            cflags.append("-mpascal-strings")
605
606        self._Appendf(cflags, "GCC_OPTIMIZATION_LEVEL", "-O%s", default="s")
607
608        if self._Test("GCC_GENERATE_DEBUGGING_SYMBOLS", "YES", default="YES"):
609            dbg_format = self._Settings().get("DEBUG_INFORMATION_FORMAT", "dwarf")
610            if dbg_format == "dwarf":
611                cflags.append("-gdwarf-2")
612            elif dbg_format == "stabs":
613                raise NotImplementedError("stabs debug format is not supported yet.")
614            elif dbg_format == "dwarf-with-dsym":
615                cflags.append("-gdwarf-2")
616            else:
617                raise NotImplementedError("Unknown debug format %s" % dbg_format)
618
619        if self._Settings().get("GCC_STRICT_ALIASING") == "YES":
620            cflags.append("-fstrict-aliasing")
621        elif self._Settings().get("GCC_STRICT_ALIASING") == "NO":
622            cflags.append("-fno-strict-aliasing")
623
624        if self._Test("GCC_SYMBOLS_PRIVATE_EXTERN", "YES", default="NO"):
625            cflags.append("-fvisibility=hidden")
626
627        if self._Test("GCC_TREAT_WARNINGS_AS_ERRORS", "YES", default="NO"):
628            cflags.append("-Werror")
629
630        if self._Test("GCC_WARN_ABOUT_MISSING_NEWLINE", "YES", default="NO"):
631            cflags.append("-Wnewline-eof")
632
633        # In Xcode, this is only activated when GCC_COMPILER_VERSION is clang or
634        # llvm-gcc. It also requires a fairly recent libtool, and
635        # if the system clang isn't used, DYLD_LIBRARY_PATH needs to contain the
636        # path to the libLTO.dylib that matches the used clang.
637        if self._Test("LLVM_LTO", "YES", default="NO"):
638            cflags.append("-flto")
639
640        self._AppendPlatformVersionMinFlags(cflags)
641
642        # TODO:
643        if self._Test("COPY_PHASE_STRIP", "YES", default="NO"):
644            self._WarnUnimplemented("COPY_PHASE_STRIP")
645        self._WarnUnimplemented("GCC_DEBUGGING_SYMBOLS")
646        self._WarnUnimplemented("GCC_ENABLE_OBJC_EXCEPTIONS")
647
648        # TODO: This is exported correctly, but assigning to it is not supported.
649        self._WarnUnimplemented("MACH_O_TYPE")
650        self._WarnUnimplemented("PRODUCT_TYPE")
651
652        # If GYP_CROSSCOMPILE (--cross-compiling), disable architecture-specific
653        # additions and assume these will be provided as required via CC_host,
654        # CXX_host, CC_target and CXX_target.
655        if not gyp.common.CrossCompileRequested():
656            if arch is not None:
657                archs = [arch]
658            else:
659                assert self.configname
660                archs = self.GetActiveArchs(self.configname)
661            if len(archs) != 1:
662                # TODO: Supporting fat binaries will be annoying.
663                self._WarnUnimplemented("ARCHS")
664                archs = ["i386"]
665            cflags.append("-arch")
666            cflags.append(archs[0])
667
668            if archs[0] in ("i386", "x86_64"):
669                if self._Test("GCC_ENABLE_SSE3_EXTENSIONS", "YES", default="NO"):
670                    cflags.append("-msse3")
671                if self._Test(
672                    "GCC_ENABLE_SUPPLEMENTAL_SSE3_INSTRUCTIONS", "YES", default="NO"
673                ):
674                    cflags.append("-mssse3")  # Note 3rd 's'.
675                if self._Test("GCC_ENABLE_SSE41_EXTENSIONS", "YES", default="NO"):
676                    cflags.append("-msse4.1")
677                if self._Test("GCC_ENABLE_SSE42_EXTENSIONS", "YES", default="NO"):
678                    cflags.append("-msse4.2")
679
680        cflags += self._Settings().get("WARNING_CFLAGS", [])
681
682        if self._IsXCTest():
683            platform_root = self._XcodePlatformPath(configname)
684            if platform_root:
685                cflags.append("-F" + platform_root + "/Developer/Library/Frameworks/")
686
687        framework_root = sdk_root if sdk_root else ""
688        config = self.spec["configurations"][self.configname]
689        framework_dirs = config.get("mac_framework_dirs", [])
690        for directory in framework_dirs:
691            cflags.append("-F" + directory.replace("$(SDKROOT)", framework_root))
692
693        self.configname = None
694        return cflags
695
696    def GetCflagsC(self, configname):
697        """Returns flags that need to be added to .c, and .m compilations."""
698        self.configname = configname
699        cflags_c = []
700        if self._Settings().get("GCC_C_LANGUAGE_STANDARD", "") == "ansi":
701            cflags_c.append("-ansi")
702        else:
703            self._Appendf(cflags_c, "GCC_C_LANGUAGE_STANDARD", "-std=%s")
704        cflags_c += self._Settings().get("OTHER_CFLAGS", [])
705        self.configname = None
706        return cflags_c
707
708    def GetCflagsCC(self, configname):
709        """Returns flags that need to be added to .cc, and .mm compilations."""
710        self.configname = configname
711        cflags_cc = []
712
713        clang_cxx_language_standard = self._Settings().get(
714            "CLANG_CXX_LANGUAGE_STANDARD"
715        )
716        # Note: Don't make c++0x to c++11 so that c++0x can be used with older
717        # clangs that don't understand c++11 yet (like Xcode 4.2's).
718        if clang_cxx_language_standard:
719            cflags_cc.append("-std=%s" % clang_cxx_language_standard)
720
721        self._Appendf(cflags_cc, "CLANG_CXX_LIBRARY", "-stdlib=%s")
722
723        if self._Test("GCC_ENABLE_CPP_RTTI", "NO", default="YES"):
724            cflags_cc.append("-fno-rtti")
725        if self._Test("GCC_ENABLE_CPP_EXCEPTIONS", "NO", default="YES"):
726            cflags_cc.append("-fno-exceptions")
727        if self._Test("GCC_INLINES_ARE_PRIVATE_EXTERN", "YES", default="NO"):
728            cflags_cc.append("-fvisibility-inlines-hidden")
729        if self._Test("GCC_THREADSAFE_STATICS", "NO", default="YES"):
730            cflags_cc.append("-fno-threadsafe-statics")
731        # Note: This flag is a no-op for clang, it only has an effect for gcc.
732        if self._Test("GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO", "NO", default="YES"):
733            cflags_cc.append("-Wno-invalid-offsetof")
734
735        other_ccflags = []
736
737        for flag in self._Settings().get("OTHER_CPLUSPLUSFLAGS", ["$(inherited)"]):
738            # TODO: More general variable expansion. Missing in many other places too.
739            if flag in ("$inherited", "$(inherited)", "${inherited}"):
740                flag = "$OTHER_CFLAGS"
741            if flag in ("$OTHER_CFLAGS", "$(OTHER_CFLAGS)", "${OTHER_CFLAGS}"):
742                other_ccflags += self._Settings().get("OTHER_CFLAGS", [])
743            else:
744                other_ccflags.append(flag)
745        cflags_cc += other_ccflags
746
747        self.configname = None
748        return cflags_cc
749
750    def _AddObjectiveCGarbageCollectionFlags(self, flags):
751        gc_policy = self._Settings().get("GCC_ENABLE_OBJC_GC", "unsupported")
752        if gc_policy == "supported":
753            flags.append("-fobjc-gc")
754        elif gc_policy == "required":
755            flags.append("-fobjc-gc-only")
756
757    def _AddObjectiveCARCFlags(self, flags):
758        if self._Test("CLANG_ENABLE_OBJC_ARC", "YES", default="NO"):
759            flags.append("-fobjc-arc")
760
761    def _AddObjectiveCMissingPropertySynthesisFlags(self, flags):
762        if self._Test(
763            "CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS", "YES", default="NO"
764        ):
765            flags.append("-Wobjc-missing-property-synthesis")
766
767    def GetCflagsObjC(self, configname):
768        """Returns flags that need to be added to .m compilations."""
769        self.configname = configname
770        cflags_objc = []
771        self._AddObjectiveCGarbageCollectionFlags(cflags_objc)
772        self._AddObjectiveCARCFlags(cflags_objc)
773        self._AddObjectiveCMissingPropertySynthesisFlags(cflags_objc)
774        self.configname = None
775        return cflags_objc
776
777    def GetCflagsObjCC(self, configname):
778        """Returns flags that need to be added to .mm compilations."""
779        self.configname = configname
780        cflags_objcc = []
781        self._AddObjectiveCGarbageCollectionFlags(cflags_objcc)
782        self._AddObjectiveCARCFlags(cflags_objcc)
783        self._AddObjectiveCMissingPropertySynthesisFlags(cflags_objcc)
784        if self._Test("GCC_OBJC_CALL_CXX_CDTORS", "YES", default="NO"):
785            cflags_objcc.append("-fobjc-call-cxx-cdtors")
786        self.configname = None
787        return cflags_objcc
788
789    def GetInstallNameBase(self):
790        """Return DYLIB_INSTALL_NAME_BASE for this target."""
791        # Xcode sets this for shared_libraries, and for nonbundled loadable_modules.
792        if self.spec["type"] != "shared_library" and (
793            self.spec["type"] != "loadable_module" or self._IsBundle()
794        ):
795            return None
796        install_base = self.GetPerTargetSetting(
797            "DYLIB_INSTALL_NAME_BASE",
798            default="/Library/Frameworks" if self._IsBundle() else "/usr/local/lib",
799        )
800        return install_base
801
802    def _StandardizePath(self, path):
803        """Do :standardizepath processing for path."""
804        # I'm not quite sure what :standardizepath does. Just call normpath(),
805        # but don't let @executable_path/../foo collapse to foo.
806        if "/" in path:
807            prefix, rest = "", path
808            if path.startswith("@"):
809                prefix, rest = path.split("/", 1)
810            rest = os.path.normpath(rest)  # :standardizepath
811            path = os.path.join(prefix, rest)
812        return path
813
814    def GetInstallName(self):
815        """Return LD_DYLIB_INSTALL_NAME for this target."""
816        # Xcode sets this for shared_libraries, and for nonbundled loadable_modules.
817        if self.spec["type"] != "shared_library" and (
818            self.spec["type"] != "loadable_module" or self._IsBundle()
819        ):
820            return None
821
822        default_install_name = (
823            "$(DYLIB_INSTALL_NAME_BASE:standardizepath)/$(EXECUTABLE_PATH)"
824        )
825        install_name = self.GetPerTargetSetting(
826            "LD_DYLIB_INSTALL_NAME", default=default_install_name
827        )
828
829        # Hardcode support for the variables used in chromium for now, to
830        # unblock people using the make build.
831        if "$" in install_name:
832            assert install_name in (
833                "$(DYLIB_INSTALL_NAME_BASE:standardizepath)/"
834                "$(WRAPPER_NAME)/$(PRODUCT_NAME)",
835                default_install_name,
836            ), (
837                "Variables in LD_DYLIB_INSTALL_NAME are not generally supported "
838                "yet in target '%s' (got '%s')"
839                % (self.spec["target_name"], install_name)
840            )
841
842            install_name = install_name.replace(
843                "$(DYLIB_INSTALL_NAME_BASE:standardizepath)",
844                self._StandardizePath(self.GetInstallNameBase()),
845            )
846            if self._IsBundle():
847                # These are only valid for bundles, hence the |if|.
848                install_name = install_name.replace(
849                    "$(WRAPPER_NAME)", self.GetWrapperName()
850                )
851                install_name = install_name.replace(
852                    "$(PRODUCT_NAME)", self.GetProductName()
853                )
854            else:
855                assert "$(WRAPPER_NAME)" not in install_name
856                assert "$(PRODUCT_NAME)" not in install_name
857
858            install_name = install_name.replace(
859                "$(EXECUTABLE_PATH)", self.GetExecutablePath()
860            )
861        return install_name
862
863    def _MapLinkerFlagFilename(self, ldflag, gyp_to_build_path):
864        """Checks if ldflag contains a filename and if so remaps it from
865        gyp-directory-relative to build-directory-relative."""
866        # This list is expanded on demand.
867        # They get matched as:
868        #   -exported_symbols_list file
869        #   -Wl,exported_symbols_list file
870        #   -Wl,exported_symbols_list,file
871        LINKER_FILE = r"(\S+)"
872        WORD = r"\S+"
873        linker_flags = [
874            ["-exported_symbols_list", LINKER_FILE],  # Needed for NaCl.
875            ["-unexported_symbols_list", LINKER_FILE],
876            ["-reexported_symbols_list", LINKER_FILE],
877            ["-sectcreate", WORD, WORD, LINKER_FILE],  # Needed for remoting.
878        ]
879        for flag_pattern in linker_flags:
880            regex = re.compile("(?:-Wl,)?" + "[ ,]".join(flag_pattern))
881            m = regex.match(ldflag)
882            if m:
883                ldflag = (
884                    ldflag[: m.start(1)]
885                    + gyp_to_build_path(m.group(1))
886                    + ldflag[m.end(1) :]
887                )
888        # Required for ffmpeg (no idea why they don't use LIBRARY_SEARCH_PATHS,
889        # TODO(thakis): Update ffmpeg.gyp):
890        if ldflag.startswith("-L"):
891            ldflag = "-L" + gyp_to_build_path(ldflag[len("-L") :])
892        return ldflag
893
894    def GetLdflags(self, configname, product_dir, gyp_to_build_path, arch=None):
895        """Returns flags that need to be passed to the linker.
896
897        Args:
898            configname: The name of the configuration to get ld flags for.
899            product_dir: The directory where products such static and dynamic
900                libraries are placed. This is added to the library search path.
901            gyp_to_build_path: A function that converts paths relative to the
902                current gyp file to paths relative to the build directory.
903        """
904        self.configname = configname
905        ldflags = []
906
907        # The xcode build is relative to a gyp file's directory, and OTHER_LDFLAGS
908        # can contain entries that depend on this. Explicitly absolutify these.
909        for ldflag in self._Settings().get("OTHER_LDFLAGS", []):
910            ldflags.append(self._MapLinkerFlagFilename(ldflag, gyp_to_build_path))
911
912        if self._Test("DEAD_CODE_STRIPPING", "YES", default="NO"):
913            ldflags.append("-Wl,-dead_strip")
914
915        if self._Test("PREBINDING", "YES", default="NO"):
916            ldflags.append("-Wl,-prebind")
917
918        self._Appendf(
919            ldflags, "DYLIB_COMPATIBILITY_VERSION", "-compatibility_version %s"
920        )
921        self._Appendf(ldflags, "DYLIB_CURRENT_VERSION", "-current_version %s")
922
923        self._AppendPlatformVersionMinFlags(ldflags)
924
925        if "SDKROOT" in self._Settings() and self._SdkPath():
926            ldflags.append("-isysroot")
927            ldflags.append(self._SdkPath())
928
929        for library_path in self._Settings().get("LIBRARY_SEARCH_PATHS", []):
930            ldflags.append("-L" + gyp_to_build_path(library_path))
931
932        if "ORDER_FILE" in self._Settings():
933            ldflags.append("-Wl,-order_file")
934            ldflags.append("-Wl," + gyp_to_build_path(self._Settings()["ORDER_FILE"]))
935
936        if not gyp.common.CrossCompileRequested():
937            if arch is not None:
938                archs = [arch]
939            else:
940                assert self.configname
941                archs = self.GetActiveArchs(self.configname)
942            if len(archs) != 1:
943                # TODO: Supporting fat binaries will be annoying.
944                self._WarnUnimplemented("ARCHS")
945                archs = ["i386"]
946            # Avoid quoting the space between -arch and the arch name
947            ldflags.append("-arch")
948            ldflags.append(archs[0])
949
950        # Xcode adds the product directory by default.
951        # Rewrite -L. to -L./ to work around http://www.openradar.me/25313838
952        ldflags.append("-L" + (product_dir if product_dir != "." else "./"))
953
954        install_name = self.GetInstallName()
955        if install_name and self.spec["type"] != "loadable_module":
956            ldflags.append("-install_name")
957            ldflags.append(install_name.replace(" ", r"\ "))
958
959        for rpath in self._Settings().get("LD_RUNPATH_SEARCH_PATHS", []):
960            ldflags.append("-Wl,-rpath," + rpath)
961
962        sdk_root = self._SdkPath()
963        if not sdk_root:
964            sdk_root = ""
965        config = self.spec["configurations"][self.configname]
966        framework_dirs = config.get("mac_framework_dirs", [])
967        for directory in framework_dirs:
968            ldflags.append("-F" + directory.replace("$(SDKROOT)", sdk_root))
969
970        if self._IsXCTest():
971            platform_root = self._XcodePlatformPath(configname)
972            if sdk_root and platform_root:
973                ldflags.append("-F" + platform_root + "/Developer/Library/Frameworks/")
974                ldflags.append("-framework")
975                ldflags.append("XCTest")
976
977        is_extension = self._IsIosAppExtension() or self._IsIosWatchKitExtension()
978        if sdk_root and is_extension:
979            # Adds the link flags for extensions. These flags are common for all
980            # extensions and provide loader and main function.
981            # These flags reflect the compilation options used by xcode to compile
982            # extensions.
983            xcode_version, _ = XcodeVersion()
984            if xcode_version < "0900":
985                ldflags.append("-lpkstart")
986                ldflags.append(
987                    sdk_root
988                    + "/System/Library/PrivateFrameworks/PlugInKit.framework/PlugInKit"
989                )
990            else:
991                ldflags.append("-e")
992                ldflags.append("_NSExtensionMain")
993            ldflags.append("-fapplication-extension")
994
995        self._Appendf(ldflags, "CLANG_CXX_LIBRARY", "-stdlib=%s")
996
997        self.configname = None
998        return ldflags
999
1000    def GetLibtoolflags(self, configname):
1001        """Returns flags that need to be passed to the static linker.
1002
1003        Args:
1004            configname: The name of the configuration to get ld flags for.
1005        """
1006        self.configname = configname
1007        libtoolflags = []
1008
1009        for libtoolflag in self._Settings().get("OTHER_LDFLAGS", []):
1010            libtoolflags.append(libtoolflag)
1011        # TODO(thakis): ARCHS?
1012
1013        self.configname = None
1014        return libtoolflags
1015
1016    def GetPerTargetSettings(self):
1017        """Gets a list of all the per-target settings. This will only fetch keys
1018        whose values are the same across all configurations."""
1019        first_pass = True
1020        result = {}
1021        for configname in sorted(self.xcode_settings.keys()):
1022            if first_pass:
1023                result = dict(self.xcode_settings[configname])
1024                first_pass = False
1025            else:
1026                for key, value in self.xcode_settings[configname].items():
1027                    if key not in result:
1028                        continue
1029                    elif result[key] != value:
1030                        del result[key]
1031        return result
1032
1033    def GetPerConfigSetting(self, setting, configname, default=None):
1034        if configname in self.xcode_settings:
1035            return self.xcode_settings[configname].get(setting, default)
1036        else:
1037            return self.GetPerTargetSetting(setting, default)
1038
1039    def GetPerTargetSetting(self, setting, default=None):
1040        """Tries to get xcode_settings.setting from spec. Assumes that the setting
1041        has the same value in all configurations and throws otherwise."""
1042        is_first_pass = True
1043        result = None
1044        for configname in sorted(self.xcode_settings.keys()):
1045            if is_first_pass:
1046                result = self.xcode_settings[configname].get(setting, None)
1047                is_first_pass = False
1048            else:
1049                assert result == self.xcode_settings[configname].get(setting, None), (
1050                    "Expected per-target setting for '%s', got per-config setting "
1051                    "(target %s)" % (setting, self.spec["target_name"])
1052                )
1053        if result is None:
1054            return default
1055        return result
1056
1057    def _GetStripPostbuilds(self, configname, output_binary, quiet):
1058        """Returns a list of shell commands that contain the shell commands
1059        necessary to strip this target's binary. These should be run as postbuilds
1060        before the actual postbuilds run."""
1061        self.configname = configname
1062
1063        result = []
1064        if self._Test("DEPLOYMENT_POSTPROCESSING", "YES", default="NO") and self._Test(
1065            "STRIP_INSTALLED_PRODUCT", "YES", default="NO"
1066        ):
1067            default_strip_style = "debugging"
1068            if (
1069                self.spec["type"] == "loadable_module" or self._IsIosAppExtension()
1070            ) and self._IsBundle():
1071                default_strip_style = "non-global"
1072            elif self.spec["type"] == "executable":
1073                default_strip_style = "all"
1074
1075            strip_style = self._Settings().get("STRIP_STYLE", default_strip_style)
1076            strip_flags = {"all": "", "non-global": "-x", "debugging": "-S"}[
1077                strip_style
1078            ]
1079
1080            explicit_strip_flags = self._Settings().get("STRIPFLAGS", "")
1081            if explicit_strip_flags:
1082                strip_flags += " " + _NormalizeEnvVarReferences(explicit_strip_flags)
1083
1084            if not quiet:
1085                result.append("echo STRIP\\(%s\\)" % self.spec["target_name"])
1086            result.append(f"strip {strip_flags} {output_binary}")
1087
1088        self.configname = None
1089        return result
1090
1091    def _GetDebugInfoPostbuilds(self, configname, output, output_binary, quiet):
1092        """Returns a list of shell commands that contain the shell commands
1093        necessary to massage this target's debug information. These should be run
1094        as postbuilds before the actual postbuilds run."""
1095        self.configname = configname
1096
1097        # For static libraries, no dSYMs are created.
1098        result = []
1099        if (
1100            self._Test("GCC_GENERATE_DEBUGGING_SYMBOLS", "YES", default="YES")
1101            and self._Test(
1102                "DEBUG_INFORMATION_FORMAT", "dwarf-with-dsym", default="dwarf"
1103            )
1104            and self.spec["type"] != "static_library"
1105        ):
1106            if not quiet:
1107                result.append("echo DSYMUTIL\\(%s\\)" % self.spec["target_name"])
1108            result.append("dsymutil {} -o {}".format(output_binary, output + ".dSYM"))
1109
1110        self.configname = None
1111        return result
1112
1113    def _GetTargetPostbuilds(self, configname, output, output_binary, quiet=False):
1114        """Returns a list of shell commands that contain the shell commands
1115        to run as postbuilds for this target, before the actual postbuilds."""
1116        # dSYMs need to build before stripping happens.
1117        return self._GetDebugInfoPostbuilds(
1118            configname, output, output_binary, quiet
1119        ) + self._GetStripPostbuilds(configname, output_binary, quiet)
1120
1121    def _GetIOSPostbuilds(self, configname, output_binary):
1122        """Return a shell command to codesign the iOS output binary so it can
1123        be deployed to a device.  This should be run as the very last step of the
1124        build."""
1125        if not (
1126            (self.isIOS and (self.spec["type"] == "executable" or self._IsXCTest()))
1127            or self.IsIosFramework()
1128        ):
1129            return []
1130
1131        postbuilds = []
1132        product_name = self.GetFullProductName()
1133        settings = self.xcode_settings[configname]
1134
1135        # Xcode expects XCTests to be copied into the TEST_HOST dir.
1136        if self._IsXCTest():
1137            source = os.path.join("${BUILT_PRODUCTS_DIR}", product_name)
1138            test_host = os.path.dirname(settings.get("TEST_HOST"))
1139            xctest_destination = os.path.join(test_host, "PlugIns", product_name)
1140            postbuilds.extend([f"ditto {source} {xctest_destination}"])
1141
1142        key = self._GetIOSCodeSignIdentityKey(settings)
1143        if not key:
1144            return postbuilds
1145
1146        # Warn for any unimplemented signing xcode keys.
1147        unimpl = ["OTHER_CODE_SIGN_FLAGS"]
1148        unimpl = set(unimpl) & set(self.xcode_settings[configname].keys())
1149        if unimpl:
1150            print(
1151                "Warning: Some codesign keys not implemented, ignoring: %s"
1152                % ", ".join(sorted(unimpl))
1153            )
1154
1155        if self._IsXCTest():
1156            # For device xctests, Xcode copies two extra frameworks into $TEST_HOST.
1157            test_host = os.path.dirname(settings.get("TEST_HOST"))
1158            frameworks_dir = os.path.join(test_host, "Frameworks")
1159            platform_root = self._XcodePlatformPath(configname)
1160            frameworks = [
1161                "Developer/Library/PrivateFrameworks/IDEBundleInjection.framework",
1162                "Developer/Library/Frameworks/XCTest.framework",
1163            ]
1164            for framework in frameworks:
1165                source = os.path.join(platform_root, framework)
1166                destination = os.path.join(frameworks_dir, os.path.basename(framework))
1167                postbuilds.extend([f"ditto {source} {destination}"])
1168
1169                # Then re-sign everything with 'preserve=True'
1170                postbuilds.extend(
1171                    [
1172                        '%s %s code-sign-bundle "%s" "%s" "%s" "%s" %s'
1173                        % (
1174                            sys.executable,
1175                            os.path.join("${TARGET_BUILD_DIR}", "gyp-mac-tool"),
1176                            key,
1177                            settings.get("CODE_SIGN_ENTITLEMENTS", ""),
1178                            settings.get("PROVISIONING_PROFILE", ""),
1179                            destination,
1180                            True,
1181                        )
1182                    ]
1183                )
1184            plugin_dir = os.path.join(test_host, "PlugIns")
1185            targets = [os.path.join(plugin_dir, product_name), test_host]
1186            for target in targets:
1187                postbuilds.extend(
1188                    [
1189                        '%s %s code-sign-bundle "%s" "%s" "%s" "%s" %s'
1190                        % (
1191                            sys.executable,
1192                            os.path.join("${TARGET_BUILD_DIR}", "gyp-mac-tool"),
1193                            key,
1194                            settings.get("CODE_SIGN_ENTITLEMENTS", ""),
1195                            settings.get("PROVISIONING_PROFILE", ""),
1196                            target,
1197                            True,
1198                        )
1199                    ]
1200                )

Showing the first 1,200 of 1937 lines. Download the file for the rest.

codekingpro/portable-devtools · Team Ai