redsnow 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (174) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +34 -0
  3. data/.gitmodules +3 -0
  4. data/.travis.yml +20 -0
  5. data/CHANGELOG.md +4 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE +21 -0
  8. data/README.md +62 -0
  9. data/Rakefile +36 -0
  10. data/Vagrantfile +20 -0
  11. data/ext/snowcrash/Makefile +64 -0
  12. data/ext/snowcrash/Vagrantfile +20 -0
  13. data/ext/snowcrash/bin/snowcrash +0 -0
  14. data/ext/snowcrash/common.gypi +163 -0
  15. data/ext/snowcrash/config.gypi +10 -0
  16. data/ext/snowcrash/config.mk +5 -0
  17. data/ext/snowcrash/configure +213 -0
  18. data/ext/snowcrash/provisioning.sh +15 -0
  19. data/ext/snowcrash/snowcrash.gyp +141 -0
  20. data/ext/snowcrash/src/ActionParser.h +503 -0
  21. data/ext/snowcrash/src/AssetParser.h +215 -0
  22. data/ext/snowcrash/src/BlockUtility.h +186 -0
  23. data/ext/snowcrash/src/Blueprint.h +283 -0
  24. data/ext/snowcrash/src/BlueprintParser.h +347 -0
  25. data/ext/snowcrash/src/BlueprintParserCore.h +190 -0
  26. data/ext/snowcrash/src/BlueprintSection.h +140 -0
  27. data/ext/snowcrash/src/BlueprintUtility.h +126 -0
  28. data/ext/snowcrash/src/CBlueprint.cc +600 -0
  29. data/ext/snowcrash/src/CBlueprint.h +354 -0
  30. data/ext/snowcrash/src/CSourceAnnotation.cc +140 -0
  31. data/ext/snowcrash/src/CSourceAnnotation.h +106 -0
  32. data/ext/snowcrash/src/CodeBlockUtility.h +189 -0
  33. data/ext/snowcrash/src/DescriptionSectionUtility.h +156 -0
  34. data/ext/snowcrash/src/HTTP.cc +46 -0
  35. data/ext/snowcrash/src/HTTP.h +105 -0
  36. data/ext/snowcrash/src/HeaderParser.h +289 -0
  37. data/ext/snowcrash/src/ListBlockUtility.h +273 -0
  38. data/ext/snowcrash/src/ListUtility.h +95 -0
  39. data/ext/snowcrash/src/MarkdownBlock.cc +176 -0
  40. data/ext/snowcrash/src/MarkdownBlock.h +93 -0
  41. data/ext/snowcrash/src/MarkdownParser.cc +266 -0
  42. data/ext/snowcrash/src/MarkdownParser.h +88 -0
  43. data/ext/snowcrash/src/ParameterDefinitonParser.h +570 -0
  44. data/ext/snowcrash/src/ParametersParser.h +252 -0
  45. data/ext/snowcrash/src/Parser.cc +71 -0
  46. data/ext/snowcrash/src/Parser.h +29 -0
  47. data/ext/snowcrash/src/ParserCore.cc +120 -0
  48. data/ext/snowcrash/src/ParserCore.h +82 -0
  49. data/ext/snowcrash/src/PayloadParser.h +672 -0
  50. data/ext/snowcrash/src/Platform.h +54 -0
  51. data/ext/snowcrash/src/RegexMatch.h +32 -0
  52. data/ext/snowcrash/src/ResourceGroupParser.h +195 -0
  53. data/ext/snowcrash/src/ResourceParser.h +584 -0
  54. data/ext/snowcrash/src/SectionUtility.h +142 -0
  55. data/ext/snowcrash/src/Serialize.cc +52 -0
  56. data/ext/snowcrash/src/Serialize.h +69 -0
  57. data/ext/snowcrash/src/SerializeJSON.cc +601 -0
  58. data/ext/snowcrash/src/SerializeJSON.h +21 -0
  59. data/ext/snowcrash/src/SerializeYAML.cc +336 -0
  60. data/ext/snowcrash/src/SerializeYAML.h +21 -0
  61. data/ext/snowcrash/src/SourceAnnotation.h +177 -0
  62. data/ext/snowcrash/src/StringUtility.h +109 -0
  63. data/ext/snowcrash/src/SymbolTable.h +83 -0
  64. data/ext/snowcrash/src/UriTemplateParser.cc +195 -0
  65. data/ext/snowcrash/src/UriTemplateParser.h +243 -0
  66. data/ext/snowcrash/src/Version.h +39 -0
  67. data/ext/snowcrash/src/csnowcrash.cc +23 -0
  68. data/ext/snowcrash/src/csnowcrash.h +38 -0
  69. data/ext/snowcrash/src/posix/RegexMatch.cc +99 -0
  70. data/ext/snowcrash/src/snowcrash.cc +18 -0
  71. data/ext/snowcrash/src/snowcrash.h +41 -0
  72. data/ext/snowcrash/src/snowcrash/snowcrash.cc +170 -0
  73. data/ext/snowcrash/src/win/RegexMatch.cc +78 -0
  74. data/ext/snowcrash/sundown/CONTRIBUTING.md +10 -0
  75. data/ext/snowcrash/sundown/Makefile +83 -0
  76. data/ext/snowcrash/sundown/Makefile.win +33 -0
  77. data/ext/snowcrash/sundown/examples/smartypants.c +72 -0
  78. data/ext/snowcrash/sundown/examples/sundown.c +80 -0
  79. data/ext/snowcrash/sundown/html/houdini.h +37 -0
  80. data/ext/snowcrash/sundown/html/houdini_href_e.c +108 -0
  81. data/ext/snowcrash/sundown/html/houdini_html_e.c +84 -0
  82. data/ext/snowcrash/sundown/html/html.c +647 -0
  83. data/ext/snowcrash/sundown/html/html.h +77 -0
  84. data/ext/snowcrash/sundown/html/html_smartypants.c +389 -0
  85. data/ext/snowcrash/sundown/html_block_names.txt +25 -0
  86. data/ext/snowcrash/sundown/src/autolink.c +297 -0
  87. data/ext/snowcrash/sundown/src/autolink.h +51 -0
  88. data/ext/snowcrash/sundown/src/buffer.c +225 -0
  89. data/ext/snowcrash/sundown/src/buffer.h +96 -0
  90. data/ext/snowcrash/sundown/src/html_blocks.h +206 -0
  91. data/ext/snowcrash/sundown/src/markdown.c +2701 -0
  92. data/ext/snowcrash/sundown/src/markdown.h +147 -0
  93. data/ext/snowcrash/sundown/src/src_map.c +200 -0
  94. data/ext/snowcrash/sundown/src/src_map.h +58 -0
  95. data/ext/snowcrash/sundown/src/stack.c +81 -0
  96. data/ext/snowcrash/sundown/src/stack.h +29 -0
  97. data/ext/snowcrash/sundown/sundown.def +20 -0
  98. data/ext/snowcrash/tools/gyp/AUTHORS +11 -0
  99. data/ext/snowcrash/tools/gyp/DEPS +24 -0
  100. data/ext/snowcrash/tools/gyp/OWNERS +1 -0
  101. data/ext/snowcrash/tools/gyp/PRESUBMIT.py +120 -0
  102. data/ext/snowcrash/tools/gyp/buildbot/buildbot_run.py +190 -0
  103. data/ext/snowcrash/tools/gyp/codereview.settings +10 -0
  104. data/ext/snowcrash/tools/gyp/data/win/large-pdb-shim.cc +12 -0
  105. data/ext/snowcrash/tools/gyp/gyp +8 -0
  106. data/ext/snowcrash/tools/gyp/gyp.bat +5 -0
  107. data/ext/snowcrash/tools/gyp/gyp_main.py +18 -0
  108. data/ext/snowcrash/tools/gyp/pylib/gyp/MSVSNew.py +340 -0
  109. data/ext/snowcrash/tools/gyp/pylib/gyp/MSVSProject.py +208 -0
  110. data/ext/snowcrash/tools/gyp/pylib/gyp/MSVSSettings.py +1063 -0
  111. data/ext/snowcrash/tools/gyp/pylib/gyp/MSVSToolFile.py +58 -0
  112. data/ext/snowcrash/tools/gyp/pylib/gyp/MSVSUserFile.py +147 -0
  113. data/ext/snowcrash/tools/gyp/pylib/gyp/MSVSUtil.py +267 -0
  114. data/ext/snowcrash/tools/gyp/pylib/gyp/MSVSVersion.py +409 -0
  115. data/ext/snowcrash/tools/gyp/pylib/gyp/__init__.py +537 -0
  116. data/ext/snowcrash/tools/gyp/pylib/gyp/__init__.pyc +0 -0
  117. data/ext/snowcrash/tools/gyp/pylib/gyp/common.py +521 -0
  118. data/ext/snowcrash/tools/gyp/pylib/gyp/common.pyc +0 -0
  119. data/ext/snowcrash/tools/gyp/pylib/gyp/easy_xml.py +157 -0
  120. data/ext/snowcrash/tools/gyp/pylib/gyp/flock_tool.py +49 -0
  121. data/ext/snowcrash/tools/gyp/pylib/gyp/generator/__init__.py +0 -0
  122. data/ext/snowcrash/tools/gyp/pylib/gyp/generator/__init__.pyc +0 -0
  123. data/ext/snowcrash/tools/gyp/pylib/gyp/generator/android.py +1069 -0
  124. data/ext/snowcrash/tools/gyp/pylib/gyp/generator/cmake.py +1143 -0
  125. data/ext/snowcrash/tools/gyp/pylib/gyp/generator/dump_dependency_json.py +81 -0
  126. data/ext/snowcrash/tools/gyp/pylib/gyp/generator/eclipse.py +335 -0
  127. data/ext/snowcrash/tools/gyp/pylib/gyp/generator/gypd.py +87 -0
  128. data/ext/snowcrash/tools/gyp/pylib/gyp/generator/gypsh.py +56 -0
  129. data/ext/snowcrash/tools/gyp/pylib/gyp/generator/make.py +2181 -0
  130. data/ext/snowcrash/tools/gyp/pylib/gyp/generator/make.pyc +0 -0
  131. data/ext/snowcrash/tools/gyp/pylib/gyp/generator/msvs.py +3335 -0
  132. data/ext/snowcrash/tools/gyp/pylib/gyp/generator/ninja.py +2156 -0
  133. data/ext/snowcrash/tools/gyp/pylib/gyp/generator/xcode.py +1224 -0
  134. data/ext/snowcrash/tools/gyp/pylib/gyp/generator/xcode.pyc +0 -0
  135. data/ext/snowcrash/tools/gyp/pylib/gyp/input.py +2809 -0
  136. data/ext/snowcrash/tools/gyp/pylib/gyp/input.pyc +0 -0
  137. data/ext/snowcrash/tools/gyp/pylib/gyp/mac_tool.py +510 -0
  138. data/ext/snowcrash/tools/gyp/pylib/gyp/msvs_emulation.py +972 -0
  139. data/ext/snowcrash/tools/gyp/pylib/gyp/ninja_syntax.py +160 -0
  140. data/ext/snowcrash/tools/gyp/pylib/gyp/ordered_dict.py +289 -0
  141. data/ext/snowcrash/tools/gyp/pylib/gyp/win_tool.py +292 -0
  142. data/ext/snowcrash/tools/gyp/pylib/gyp/xcode_emulation.py +1440 -0
  143. data/ext/snowcrash/tools/gyp/pylib/gyp/xcode_emulation.pyc +0 -0
  144. data/ext/snowcrash/tools/gyp/pylib/gyp/xcodeproj_file.py +2889 -0
  145. data/ext/snowcrash/tools/gyp/pylib/gyp/xcodeproj_file.pyc +0 -0
  146. data/ext/snowcrash/tools/gyp/pylib/gyp/xml_fix.py +69 -0
  147. data/ext/snowcrash/tools/gyp/pylintrc +307 -0
  148. data/ext/snowcrash/tools/gyp/samples/samples +81 -0
  149. data/ext/snowcrash/tools/gyp/samples/samples.bat +5 -0
  150. data/ext/snowcrash/tools/gyp/setup.py +19 -0
  151. data/ext/snowcrash/tools/gyp/tools/Xcode/Specifications/gyp.pbfilespec +27 -0
  152. data/ext/snowcrash/tools/gyp/tools/Xcode/Specifications/gyp.xclangspec +226 -0
  153. data/ext/snowcrash/tools/gyp/tools/emacs/gyp.el +252 -0
  154. data/ext/snowcrash/tools/gyp/tools/graphviz.py +100 -0
  155. data/ext/snowcrash/tools/gyp/tools/pretty_gyp.py +155 -0
  156. data/ext/snowcrash/tools/gyp/tools/pretty_sln.py +168 -0
  157. data/ext/snowcrash/tools/gyp/tools/pretty_vcproj.py +329 -0
  158. data/ext/snowcrash/tools/homebrew/snowcrash.rb +11 -0
  159. data/ext/snowcrash/vcbuild.bat +184 -0
  160. data/lib/redsnow.rb +31 -0
  161. data/lib/redsnow/binding.rb +132 -0
  162. data/lib/redsnow/blueprint.rb +365 -0
  163. data/lib/redsnow/object.rb +18 -0
  164. data/lib/redsnow/parseresult.rb +107 -0
  165. data/lib/redsnow/version.rb +4 -0
  166. data/provisioning.sh +20 -0
  167. data/redsnow.gemspec +35 -0
  168. data/test/_helper.rb +15 -0
  169. data/test/fixtures/sample-api-ast.json +97 -0
  170. data/test/fixtures/sample-api.apib +20 -0
  171. data/test/redsnow_binding_test.rb +35 -0
  172. data/test/redsnow_parseresult_test.rb +50 -0
  173. data/test/redsnow_test.rb +285 -0
  174. metadata +358 -0
@@ -0,0 +1,1440 @@
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
+ """
6
+ This module contains classes that help to emulate xcodebuild behavior on top of
7
+ other build systems, such as make and ninja.
8
+ """
9
+
10
+ import copy
11
+ import gyp.common
12
+ import os
13
+ import os.path
14
+ import re
15
+ import shlex
16
+ import subprocess
17
+ import sys
18
+ import tempfile
19
+ from gyp.common import GypError
20
+
21
+ class XcodeSettings(object):
22
+ """A class that understands the gyp 'xcode_settings' object."""
23
+
24
+ # Populated lazily by _SdkPath(). Shared by all XcodeSettings, so cached
25
+ # at class-level for efficiency.
26
+ _sdk_path_cache = {}
27
+ _sdk_root_cache = {}
28
+
29
+ # Populated lazily by GetExtraPlistItems(). Shared by all XcodeSettings, so
30
+ # cached at class-level for efficiency.
31
+ _plist_cache = {}
32
+
33
+ # Populated lazily by GetIOSPostbuilds. Shared by all XcodeSettings, so
34
+ # cached at class-level for efficiency.
35
+ _codesigning_key_cache = {}
36
+
37
+ # Populated lazily by _XcodeVersion. Shared by all XcodeSettings, so cached
38
+ # at class-level for efficiency.
39
+ _xcode_version_cache = ()
40
+
41
+ def __init__(self, spec):
42
+ self.spec = spec
43
+
44
+ self.isIOS = False
45
+
46
+ # Per-target 'xcode_settings' are pushed down into configs earlier by gyp.
47
+ # This means self.xcode_settings[config] always contains all settings
48
+ # for that config -- the per-target settings as well. Settings that are
49
+ # the same for all configs are implicitly per-target settings.
50
+ self.xcode_settings = {}
51
+ configs = spec['configurations']
52
+ for configname, config in configs.iteritems():
53
+ self.xcode_settings[configname] = config.get('xcode_settings', {})
54
+ self._ConvertConditionalKeys(configname)
55
+ if self.xcode_settings[configname].get('IPHONEOS_DEPLOYMENT_TARGET',
56
+ None):
57
+ self.isIOS = True
58
+
59
+ # This is only non-None temporarily during the execution of some methods.
60
+ self.configname = None
61
+
62
+ # Used by _AdjustLibrary to match .a and .dylib entries in libraries.
63
+ self.library_re = re.compile(r'^lib([^/]+)\.(a|dylib)$')
64
+
65
+ def _ConvertConditionalKeys(self, configname):
66
+ """Converts or warns on conditional keys. Xcode supports conditional keys,
67
+ such as CODE_SIGN_IDENTITY[sdk=iphoneos*]. This is a partial implementation
68
+ with some keys converted while the rest force a warning."""
69
+ settings = self.xcode_settings[configname]
70
+ conditional_keys = [key for key in settings if key.endswith(']')]
71
+ for key in conditional_keys:
72
+ # If you need more, speak up at http://crbug.com/122592
73
+ if key.endswith("[sdk=iphoneos*]"):
74
+ if configname.endswith("iphoneos"):
75
+ new_key = key.split("[")[0]
76
+ settings[new_key] = settings[key]
77
+ else:
78
+ print 'Warning: Conditional keys not implemented, ignoring:', \
79
+ ' '.join(conditional_keys)
80
+ del settings[key]
81
+
82
+ def _Settings(self):
83
+ assert self.configname
84
+ return self.xcode_settings[self.configname]
85
+
86
+ def _Test(self, test_key, cond_key, default):
87
+ return self._Settings().get(test_key, default) == cond_key
88
+
89
+ def _Appendf(self, lst, test_key, format_str, default=None):
90
+ if test_key in self._Settings():
91
+ lst.append(format_str % str(self._Settings()[test_key]))
92
+ elif default:
93
+ lst.append(format_str % str(default))
94
+
95
+ def _WarnUnimplemented(self, test_key):
96
+ if test_key in self._Settings():
97
+ print 'Warning: Ignoring not yet implemented key "%s".' % test_key
98
+
99
+ def _IsBundle(self):
100
+ return int(self.spec.get('mac_bundle', 0)) != 0
101
+
102
+ def GetFrameworkVersion(self):
103
+ """Returns the framework version of the current target. Only valid for
104
+ bundles."""
105
+ assert self._IsBundle()
106
+ return self.GetPerTargetSetting('FRAMEWORK_VERSION', default='A')
107
+
108
+ def GetWrapperExtension(self):
109
+ """Returns the bundle extension (.app, .framework, .plugin, etc). Only
110
+ valid for bundles."""
111
+ assert self._IsBundle()
112
+ if self.spec['type'] in ('loadable_module', 'shared_library'):
113
+ default_wrapper_extension = {
114
+ 'loadable_module': 'bundle',
115
+ 'shared_library': 'framework',
116
+ }[self.spec['type']]
117
+ wrapper_extension = self.GetPerTargetSetting(
118
+ 'WRAPPER_EXTENSION', default=default_wrapper_extension)
119
+ return '.' + self.spec.get('product_extension', wrapper_extension)
120
+ elif self.spec['type'] == 'executable':
121
+ return '.' + self.spec.get('product_extension', 'app')
122
+ else:
123
+ assert False, "Don't know extension for '%s', target '%s'" % (
124
+ self.spec['type'], self.spec['target_name'])
125
+
126
+ def GetProductName(self):
127
+ """Returns PRODUCT_NAME."""
128
+ return self.spec.get('product_name', self.spec['target_name'])
129
+
130
+ def GetFullProductName(self):
131
+ """Returns FULL_PRODUCT_NAME."""
132
+ if self._IsBundle():
133
+ return self.GetWrapperName()
134
+ else:
135
+ return self._GetStandaloneBinaryPath()
136
+
137
+ def GetWrapperName(self):
138
+ """Returns the directory name of the bundle represented by this target.
139
+ Only valid for bundles."""
140
+ assert self._IsBundle()
141
+ return self.GetProductName() + self.GetWrapperExtension()
142
+
143
+ def GetBundleContentsFolderPath(self):
144
+ """Returns the qualified path to the bundle's contents folder. E.g.
145
+ Chromium.app/Contents or Foo.bundle/Versions/A. Only valid for bundles."""
146
+ if self.isIOS:
147
+ return self.GetWrapperName()
148
+ assert self._IsBundle()
149
+ if self.spec['type'] == 'shared_library':
150
+ return os.path.join(
151
+ self.GetWrapperName(), 'Versions', self.GetFrameworkVersion())
152
+ else:
153
+ # loadable_modules have a 'Contents' folder like executables.
154
+ return os.path.join(self.GetWrapperName(), 'Contents')
155
+
156
+ def GetBundleResourceFolder(self):
157
+ """Returns the qualified path to the bundle's resource folder. E.g.
158
+ Chromium.app/Contents/Resources. Only valid for bundles."""
159
+ assert self._IsBundle()
160
+ if self.isIOS:
161
+ return self.GetBundleContentsFolderPath()
162
+ return os.path.join(self.GetBundleContentsFolderPath(), 'Resources')
163
+
164
+ def GetBundlePlistPath(self):
165
+ """Returns the qualified path to the bundle's plist file. E.g.
166
+ Chromium.app/Contents/Info.plist. Only valid for bundles."""
167
+ assert self._IsBundle()
168
+ if self.spec['type'] in ('executable', 'loadable_module'):
169
+ return os.path.join(self.GetBundleContentsFolderPath(), 'Info.plist')
170
+ else:
171
+ return os.path.join(self.GetBundleContentsFolderPath(),
172
+ 'Resources', 'Info.plist')
173
+
174
+ def GetProductType(self):
175
+ """Returns the PRODUCT_TYPE of this target."""
176
+ if self._IsBundle():
177
+ return {
178
+ 'executable': 'com.apple.product-type.application',
179
+ 'loadable_module': 'com.apple.product-type.bundle',
180
+ 'shared_library': 'com.apple.product-type.framework',
181
+ }[self.spec['type']]
182
+ else:
183
+ return {
184
+ 'executable': 'com.apple.product-type.tool',
185
+ 'loadable_module': 'com.apple.product-type.library.dynamic',
186
+ 'shared_library': 'com.apple.product-type.library.dynamic',
187
+ 'static_library': 'com.apple.product-type.library.static',
188
+ }[self.spec['type']]
189
+
190
+ def GetMachOType(self):
191
+ """Returns the MACH_O_TYPE of this target."""
192
+ # Weird, but matches Xcode.
193
+ if not self._IsBundle() and self.spec['type'] == 'executable':
194
+ return ''
195
+ return {
196
+ 'executable': 'mh_execute',
197
+ 'static_library': 'staticlib',
198
+ 'shared_library': 'mh_dylib',
199
+ 'loadable_module': 'mh_bundle',
200
+ }[self.spec['type']]
201
+
202
+ def _GetBundleBinaryPath(self):
203
+ """Returns the name of the bundle binary of by this target.
204
+ E.g. Chromium.app/Contents/MacOS/Chromium. Only valid for bundles."""
205
+ assert self._IsBundle()
206
+ if self.spec['type'] in ('shared_library') or self.isIOS:
207
+ path = self.GetBundleContentsFolderPath()
208
+ elif self.spec['type'] in ('executable', 'loadable_module'):
209
+ path = os.path.join(self.GetBundleContentsFolderPath(), 'MacOS')
210
+ return os.path.join(path, self.GetExecutableName())
211
+
212
+ def _GetStandaloneExecutableSuffix(self):
213
+ if 'product_extension' in self.spec:
214
+ return '.' + self.spec['product_extension']
215
+ return {
216
+ 'executable': '',
217
+ 'static_library': '.a',
218
+ 'shared_library': '.dylib',
219
+ 'loadable_module': '.so',
220
+ }[self.spec['type']]
221
+
222
+ def _GetStandaloneExecutablePrefix(self):
223
+ return self.spec.get('product_prefix', {
224
+ 'executable': '',
225
+ 'static_library': 'lib',
226
+ 'shared_library': 'lib',
227
+ # Non-bundled loadable_modules are called foo.so for some reason
228
+ # (that is, .so and no prefix) with the xcode build -- match that.
229
+ 'loadable_module': '',
230
+ }[self.spec['type']])
231
+
232
+ def _GetStandaloneBinaryPath(self):
233
+ """Returns the name of the non-bundle binary represented by this target.
234
+ E.g. hello_world. Only valid for non-bundles."""
235
+ assert not self._IsBundle()
236
+ assert self.spec['type'] in (
237
+ 'executable', 'shared_library', 'static_library', 'loadable_module'), (
238
+ 'Unexpected type %s' % self.spec['type'])
239
+ target = self.spec['target_name']
240
+ if self.spec['type'] == 'static_library':
241
+ if target[:3] == 'lib':
242
+ target = target[3:]
243
+ elif self.spec['type'] in ('loadable_module', 'shared_library'):
244
+ if target[:3] == 'lib':
245
+ target = target[3:]
246
+
247
+ target_prefix = self._GetStandaloneExecutablePrefix()
248
+ target = self.spec.get('product_name', target)
249
+ target_ext = self._GetStandaloneExecutableSuffix()
250
+ return target_prefix + target + target_ext
251
+
252
+ def GetExecutableName(self):
253
+ """Returns the executable name of the bundle represented by this target.
254
+ E.g. Chromium."""
255
+ if self._IsBundle():
256
+ return self.spec.get('product_name', self.spec['target_name'])
257
+ else:
258
+ return self._GetStandaloneBinaryPath()
259
+
260
+ def GetExecutablePath(self):
261
+ """Returns the directory name of the bundle represented by this target. E.g.
262
+ Chromium.app/Contents/MacOS/Chromium."""
263
+ if self._IsBundle():
264
+ return self._GetBundleBinaryPath()
265
+ else:
266
+ return self._GetStandaloneBinaryPath()
267
+
268
+ def GetActiveArchs(self, configname):
269
+ """Returns the architectures this target should be built for."""
270
+ # TODO: Look at VALID_ARCHS, ONLY_ACTIVE_ARCH; possibly set
271
+ # CURRENT_ARCH / NATIVE_ARCH env vars?
272
+ return self.xcode_settings[configname].get('ARCHS', [self._DefaultArch()])
273
+
274
+ def _GetStdout(self, cmdlist):
275
+ job = subprocess.Popen(cmdlist, stdout=subprocess.PIPE)
276
+ out = job.communicate()[0]
277
+ if job.returncode != 0:
278
+ sys.stderr.write(out + '\n')
279
+ raise GypError('Error %d running %s' % (job.returncode, cmdlist[0]))
280
+ return out.rstrip('\n')
281
+
282
+ def _GetSdkVersionInfoItem(self, sdk, infoitem):
283
+ # xcodebuild requires Xcode and can't run on Command Line Tools-only
284
+ # systems from 10.7 onward.
285
+ # Since the CLT has no SDK paths anyway, returning None is the
286
+ # most sensible route and should still do the right thing.
287
+ try:
288
+ return self._GetStdout(['xcodebuild', '-version', '-sdk', sdk, infoitem])
289
+ except:
290
+ pass
291
+
292
+ def _SdkRoot(self, configname):
293
+ if configname is None:
294
+ configname = self.configname
295
+ return self.GetPerConfigSetting('SDKROOT', configname, default='')
296
+
297
+ def _SdkPath(self, configname=None):
298
+ sdk_root = self._SdkRoot(configname)
299
+ if sdk_root.startswith('/'):
300
+ return sdk_root
301
+ return self._XcodeSdkPath(sdk_root)
302
+
303
+ def _XcodeSdkPath(self, sdk_root):
304
+ if sdk_root not in XcodeSettings._sdk_path_cache:
305
+ sdk_path = self._GetSdkVersionInfoItem(sdk_root, 'Path')
306
+ XcodeSettings._sdk_path_cache[sdk_root] = sdk_path
307
+ if sdk_root:
308
+ XcodeSettings._sdk_root_cache[sdk_path] = sdk_root
309
+ return XcodeSettings._sdk_path_cache[sdk_root]
310
+
311
+ def _AppendPlatformVersionMinFlags(self, lst):
312
+ self._Appendf(lst, 'MACOSX_DEPLOYMENT_TARGET', '-mmacosx-version-min=%s')
313
+ if 'IPHONEOS_DEPLOYMENT_TARGET' in self._Settings():
314
+ # TODO: Implement this better?
315
+ sdk_path_basename = os.path.basename(self._SdkPath())
316
+ if sdk_path_basename.lower().startswith('iphonesimulator'):
317
+ self._Appendf(lst, 'IPHONEOS_DEPLOYMENT_TARGET',
318
+ '-mios-simulator-version-min=%s')
319
+ else:
320
+ self._Appendf(lst, 'IPHONEOS_DEPLOYMENT_TARGET',
321
+ '-miphoneos-version-min=%s')
322
+
323
+ def GetCflags(self, configname, arch=None):
324
+ """Returns flags that need to be added to .c, .cc, .m, and .mm
325
+ compilations."""
326
+ # This functions (and the similar ones below) do not offer complete
327
+ # emulation of all xcode_settings keys. They're implemented on demand.
328
+
329
+ self.configname = configname
330
+ cflags = []
331
+
332
+ sdk_root = self._SdkPath()
333
+ if 'SDKROOT' in self._Settings() and sdk_root:
334
+ cflags.append('-isysroot %s' % sdk_root)
335
+
336
+ if self._Test('CLANG_WARN_CONSTANT_CONVERSION', 'YES', default='NO'):
337
+ cflags.append('-Wconstant-conversion')
338
+
339
+ if self._Test('GCC_CHAR_IS_UNSIGNED_CHAR', 'YES', default='NO'):
340
+ cflags.append('-funsigned-char')
341
+
342
+ if self._Test('GCC_CW_ASM_SYNTAX', 'YES', default='YES'):
343
+ cflags.append('-fasm-blocks')
344
+
345
+ if 'GCC_DYNAMIC_NO_PIC' in self._Settings():
346
+ if self._Settings()['GCC_DYNAMIC_NO_PIC'] == 'YES':
347
+ cflags.append('-mdynamic-no-pic')
348
+ else:
349
+ pass
350
+ # TODO: In this case, it depends on the target. xcode passes
351
+ # mdynamic-no-pic by default for executable and possibly static lib
352
+ # according to mento
353
+
354
+ if self._Test('GCC_ENABLE_PASCAL_STRINGS', 'YES', default='YES'):
355
+ cflags.append('-mpascal-strings')
356
+
357
+ self._Appendf(cflags, 'GCC_OPTIMIZATION_LEVEL', '-O%s', default='s')
358
+
359
+ if self._Test('GCC_GENERATE_DEBUGGING_SYMBOLS', 'YES', default='YES'):
360
+ dbg_format = self._Settings().get('DEBUG_INFORMATION_FORMAT', 'dwarf')
361
+ if dbg_format == 'dwarf':
362
+ cflags.append('-gdwarf-2')
363
+ elif dbg_format == 'stabs':
364
+ raise NotImplementedError('stabs debug format is not supported yet.')
365
+ elif dbg_format == 'dwarf-with-dsym':
366
+ cflags.append('-gdwarf-2')
367
+ else:
368
+ raise NotImplementedError('Unknown debug format %s' % dbg_format)
369
+
370
+ if self._Settings().get('GCC_STRICT_ALIASING') == 'YES':
371
+ cflags.append('-fstrict-aliasing')
372
+ elif self._Settings().get('GCC_STRICT_ALIASING') == 'NO':
373
+ cflags.append('-fno-strict-aliasing')
374
+
375
+ if self._Test('GCC_SYMBOLS_PRIVATE_EXTERN', 'YES', default='NO'):
376
+ cflags.append('-fvisibility=hidden')
377
+
378
+ if self._Test('GCC_TREAT_WARNINGS_AS_ERRORS', 'YES', default='NO'):
379
+ cflags.append('-Werror')
380
+
381
+ if self._Test('GCC_WARN_ABOUT_MISSING_NEWLINE', 'YES', default='NO'):
382
+ cflags.append('-Wnewline-eof')
383
+
384
+ self._AppendPlatformVersionMinFlags(cflags)
385
+
386
+ # TODO:
387
+ if self._Test('COPY_PHASE_STRIP', 'YES', default='NO'):
388
+ self._WarnUnimplemented('COPY_PHASE_STRIP')
389
+ self._WarnUnimplemented('GCC_DEBUGGING_SYMBOLS')
390
+ self._WarnUnimplemented('GCC_ENABLE_OBJC_EXCEPTIONS')
391
+
392
+ # TODO: This is exported correctly, but assigning to it is not supported.
393
+ self._WarnUnimplemented('MACH_O_TYPE')
394
+ self._WarnUnimplemented('PRODUCT_TYPE')
395
+
396
+ if arch is not None:
397
+ archs = [arch]
398
+ else:
399
+ archs = self._Settings().get('ARCHS', [self._DefaultArch()])
400
+ if len(archs) != 1:
401
+ # TODO: Supporting fat binaries will be annoying.
402
+ self._WarnUnimplemented('ARCHS')
403
+ archs = ['i386']
404
+ cflags.append('-arch ' + archs[0])
405
+
406
+ if archs[0] in ('i386', 'x86_64'):
407
+ if self._Test('GCC_ENABLE_SSE3_EXTENSIONS', 'YES', default='NO'):
408
+ cflags.append('-msse3')
409
+ if self._Test('GCC_ENABLE_SUPPLEMENTAL_SSE3_INSTRUCTIONS', 'YES',
410
+ default='NO'):
411
+ cflags.append('-mssse3') # Note 3rd 's'.
412
+ if self._Test('GCC_ENABLE_SSE41_EXTENSIONS', 'YES', default='NO'):
413
+ cflags.append('-msse4.1')
414
+ if self._Test('GCC_ENABLE_SSE42_EXTENSIONS', 'YES', default='NO'):
415
+ cflags.append('-msse4.2')
416
+
417
+ cflags += self._Settings().get('WARNING_CFLAGS', [])
418
+
419
+ if sdk_root:
420
+ framework_root = sdk_root
421
+ else:
422
+ framework_root = ''
423
+ config = self.spec['configurations'][self.configname]
424
+ framework_dirs = config.get('mac_framework_dirs', [])
425
+ for directory in framework_dirs:
426
+ cflags.append('-F' + directory.replace('$(SDKROOT)', framework_root))
427
+
428
+ self.configname = None
429
+ return cflags
430
+
431
+ def GetCflagsC(self, configname):
432
+ """Returns flags that need to be added to .c, and .m compilations."""
433
+ self.configname = configname
434
+ cflags_c = []
435
+ if self._Settings().get('GCC_C_LANGUAGE_STANDARD', '') == 'ansi':
436
+ cflags_c.append('-ansi')
437
+ else:
438
+ self._Appendf(cflags_c, 'GCC_C_LANGUAGE_STANDARD', '-std=%s')
439
+ cflags_c += self._Settings().get('OTHER_CFLAGS', [])
440
+ self.configname = None
441
+ return cflags_c
442
+
443
+ def GetCflagsCC(self, configname):
444
+ """Returns flags that need to be added to .cc, and .mm compilations."""
445
+ self.configname = configname
446
+ cflags_cc = []
447
+
448
+ clang_cxx_language_standard = self._Settings().get(
449
+ 'CLANG_CXX_LANGUAGE_STANDARD')
450
+ # Note: Don't make c++0x to c++11 so that c++0x can be used with older
451
+ # clangs that don't understand c++11 yet (like Xcode 4.2's).
452
+ if clang_cxx_language_standard:
453
+ cflags_cc.append('-std=%s' % clang_cxx_language_standard)
454
+
455
+ self._Appendf(cflags_cc, 'CLANG_CXX_LIBRARY', '-stdlib=%s')
456
+
457
+ if self._Test('GCC_ENABLE_CPP_RTTI', 'NO', default='YES'):
458
+ cflags_cc.append('-fno-rtti')
459
+ if self._Test('GCC_ENABLE_CPP_EXCEPTIONS', 'NO', default='YES'):
460
+ cflags_cc.append('-fno-exceptions')
461
+ if self._Test('GCC_INLINES_ARE_PRIVATE_EXTERN', 'YES', default='NO'):
462
+ cflags_cc.append('-fvisibility-inlines-hidden')
463
+ if self._Test('GCC_THREADSAFE_STATICS', 'NO', default='YES'):
464
+ cflags_cc.append('-fno-threadsafe-statics')
465
+ # Note: This flag is a no-op for clang, it only has an effect for gcc.
466
+ if self._Test('GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO', 'NO', default='YES'):
467
+ cflags_cc.append('-Wno-invalid-offsetof')
468
+
469
+ other_ccflags = []
470
+
471
+ for flag in self._Settings().get('OTHER_CPLUSPLUSFLAGS', ['$(inherited)']):
472
+ # TODO: More general variable expansion. Missing in many other places too.
473
+ if flag in ('$inherited', '$(inherited)', '${inherited}'):
474
+ flag = '$OTHER_CFLAGS'
475
+ if flag in ('$OTHER_CFLAGS', '$(OTHER_CFLAGS)', '${OTHER_CFLAGS}'):
476
+ other_ccflags += self._Settings().get('OTHER_CFLAGS', [])
477
+ else:
478
+ other_ccflags.append(flag)
479
+ cflags_cc += other_ccflags
480
+
481
+ self.configname = None
482
+ return cflags_cc
483
+
484
+ def _AddObjectiveCGarbageCollectionFlags(self, flags):
485
+ gc_policy = self._Settings().get('GCC_ENABLE_OBJC_GC', 'unsupported')
486
+ if gc_policy == 'supported':
487
+ flags.append('-fobjc-gc')
488
+ elif gc_policy == 'required':
489
+ flags.append('-fobjc-gc-only')
490
+
491
+ def _AddObjectiveCARCFlags(self, flags):
492
+ if self._Test('CLANG_ENABLE_OBJC_ARC', 'YES', default='NO'):
493
+ flags.append('-fobjc-arc')
494
+
495
+ def _AddObjectiveCMissingPropertySynthesisFlags(self, flags):
496
+ if self._Test('CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS',
497
+ 'YES', default='NO'):
498
+ flags.append('-Wobjc-missing-property-synthesis')
499
+
500
+ def GetCflagsObjC(self, configname):
501
+ """Returns flags that need to be added to .m compilations."""
502
+ self.configname = configname
503
+ cflags_objc = []
504
+ self._AddObjectiveCGarbageCollectionFlags(cflags_objc)
505
+ self._AddObjectiveCARCFlags(cflags_objc)
506
+ self._AddObjectiveCMissingPropertySynthesisFlags(cflags_objc)
507
+ self.configname = None
508
+ return cflags_objc
509
+
510
+ def GetCflagsObjCC(self, configname):
511
+ """Returns flags that need to be added to .mm compilations."""
512
+ self.configname = configname
513
+ cflags_objcc = []
514
+ self._AddObjectiveCGarbageCollectionFlags(cflags_objcc)
515
+ self._AddObjectiveCARCFlags(cflags_objcc)
516
+ self._AddObjectiveCMissingPropertySynthesisFlags(cflags_objcc)
517
+ if self._Test('GCC_OBJC_CALL_CXX_CDTORS', 'YES', default='NO'):
518
+ cflags_objcc.append('-fobjc-call-cxx-cdtors')
519
+ self.configname = None
520
+ return cflags_objcc
521
+
522
+ def GetInstallNameBase(self):
523
+ """Return DYLIB_INSTALL_NAME_BASE for this target."""
524
+ # Xcode sets this for shared_libraries, and for nonbundled loadable_modules.
525
+ if (self.spec['type'] != 'shared_library' and
526
+ (self.spec['type'] != 'loadable_module' or self._IsBundle())):
527
+ return None
528
+ install_base = self.GetPerTargetSetting(
529
+ 'DYLIB_INSTALL_NAME_BASE',
530
+ default='/Library/Frameworks' if self._IsBundle() else '/usr/local/lib')
531
+ return install_base
532
+
533
+ def _StandardizePath(self, path):
534
+ """Do :standardizepath processing for path."""
535
+ # I'm not quite sure what :standardizepath does. Just call normpath(),
536
+ # but don't let @executable_path/../foo collapse to foo.
537
+ if '/' in path:
538
+ prefix, rest = '', path
539
+ if path.startswith('@'):
540
+ prefix, rest = path.split('/', 1)
541
+ rest = os.path.normpath(rest) # :standardizepath
542
+ path = os.path.join(prefix, rest)
543
+ return path
544
+
545
+ def GetInstallName(self):
546
+ """Return LD_DYLIB_INSTALL_NAME for this target."""
547
+ # Xcode sets this for shared_libraries, and for nonbundled loadable_modules.
548
+ if (self.spec['type'] != 'shared_library' and
549
+ (self.spec['type'] != 'loadable_module' or self._IsBundle())):
550
+ return None
551
+
552
+ default_install_name = \
553
+ '$(DYLIB_INSTALL_NAME_BASE:standardizepath)/$(EXECUTABLE_PATH)'
554
+ install_name = self.GetPerTargetSetting(
555
+ 'LD_DYLIB_INSTALL_NAME', default=default_install_name)
556
+
557
+ # Hardcode support for the variables used in chromium for now, to
558
+ # unblock people using the make build.
559
+ if '$' in install_name:
560
+ assert install_name in ('$(DYLIB_INSTALL_NAME_BASE:standardizepath)/'
561
+ '$(WRAPPER_NAME)/$(PRODUCT_NAME)', default_install_name), (
562
+ 'Variables in LD_DYLIB_INSTALL_NAME are not generally supported '
563
+ 'yet in target \'%s\' (got \'%s\')' %
564
+ (self.spec['target_name'], install_name))
565
+
566
+ install_name = install_name.replace(
567
+ '$(DYLIB_INSTALL_NAME_BASE:standardizepath)',
568
+ self._StandardizePath(self.GetInstallNameBase()))
569
+ if self._IsBundle():
570
+ # These are only valid for bundles, hence the |if|.
571
+ install_name = install_name.replace(
572
+ '$(WRAPPER_NAME)', self.GetWrapperName())
573
+ install_name = install_name.replace(
574
+ '$(PRODUCT_NAME)', self.GetProductName())
575
+ else:
576
+ assert '$(WRAPPER_NAME)' not in install_name
577
+ assert '$(PRODUCT_NAME)' not in install_name
578
+
579
+ install_name = install_name.replace(
580
+ '$(EXECUTABLE_PATH)', self.GetExecutablePath())
581
+ return install_name
582
+
583
+ def _MapLinkerFlagFilename(self, ldflag, gyp_to_build_path):
584
+ """Checks if ldflag contains a filename and if so remaps it from
585
+ gyp-directory-relative to build-directory-relative."""
586
+ # This list is expanded on demand.
587
+ # They get matched as:
588
+ # -exported_symbols_list file
589
+ # -Wl,exported_symbols_list file
590
+ # -Wl,exported_symbols_list,file
591
+ LINKER_FILE = '(\S+)'
592
+ WORD = '\S+'
593
+ linker_flags = [
594
+ ['-exported_symbols_list', LINKER_FILE], # Needed for NaCl.
595
+ ['-unexported_symbols_list', LINKER_FILE],
596
+ ['-reexported_symbols_list', LINKER_FILE],
597
+ ['-sectcreate', WORD, WORD, LINKER_FILE], # Needed for remoting.
598
+ ]
599
+ for flag_pattern in linker_flags:
600
+ regex = re.compile('(?:-Wl,)?' + '[ ,]'.join(flag_pattern))
601
+ m = regex.match(ldflag)
602
+ if m:
603
+ ldflag = ldflag[:m.start(1)] + gyp_to_build_path(m.group(1)) + \
604
+ ldflag[m.end(1):]
605
+ # Required for ffmpeg (no idea why they don't use LIBRARY_SEARCH_PATHS,
606
+ # TODO(thakis): Update ffmpeg.gyp):
607
+ if ldflag.startswith('-L'):
608
+ ldflag = '-L' + gyp_to_build_path(ldflag[len('-L'):])
609
+ return ldflag
610
+
611
+ def GetLdflags(self, configname, product_dir, gyp_to_build_path, arch=None):
612
+ """Returns flags that need to be passed to the linker.
613
+
614
+ Args:
615
+ configname: The name of the configuration to get ld flags for.
616
+ product_dir: The directory where products such static and dynamic
617
+ libraries are placed. This is added to the library search path.
618
+ gyp_to_build_path: A function that converts paths relative to the
619
+ current gyp file to paths relative to the build direcotry.
620
+ """
621
+ self.configname = configname
622
+ ldflags = []
623
+
624
+ # The xcode build is relative to a gyp file's directory, and OTHER_LDFLAGS
625
+ # can contain entries that depend on this. Explicitly absolutify these.
626
+ for ldflag in self._Settings().get('OTHER_LDFLAGS', []):
627
+ ldflags.append(self._MapLinkerFlagFilename(ldflag, gyp_to_build_path))
628
+
629
+ if self._Test('DEAD_CODE_STRIPPING', 'YES', default='NO'):
630
+ ldflags.append('-Wl,-dead_strip')
631
+
632
+ if self._Test('PREBINDING', 'YES', default='NO'):
633
+ ldflags.append('-Wl,-prebind')
634
+
635
+ self._Appendf(
636
+ ldflags, 'DYLIB_COMPATIBILITY_VERSION', '-compatibility_version %s')
637
+ self._Appendf(
638
+ ldflags, 'DYLIB_CURRENT_VERSION', '-current_version %s')
639
+
640
+ self._AppendPlatformVersionMinFlags(ldflags)
641
+
642
+ if 'SDKROOT' in self._Settings() and self._SdkPath():
643
+ ldflags.append('-isysroot ' + self._SdkPath())
644
+
645
+ for library_path in self._Settings().get('LIBRARY_SEARCH_PATHS', []):
646
+ ldflags.append('-L' + gyp_to_build_path(library_path))
647
+
648
+ if 'ORDER_FILE' in self._Settings():
649
+ ldflags.append('-Wl,-order_file ' +
650
+ '-Wl,' + gyp_to_build_path(
651
+ self._Settings()['ORDER_FILE']))
652
+
653
+ if arch is not None:
654
+ archs = [arch]
655
+ else:
656
+ archs = self._Settings().get('ARCHS', [self._DefaultArch()])
657
+ if len(archs) != 1:
658
+ # TODO: Supporting fat binaries will be annoying.
659
+ self._WarnUnimplemented('ARCHS')
660
+ archs = ['i386']
661
+ ldflags.append('-arch ' + archs[0])
662
+
663
+ # Xcode adds the product directory by default.
664
+ ldflags.append('-L' + product_dir)
665
+
666
+ install_name = self.GetInstallName()
667
+ if install_name and self.spec['type'] != 'loadable_module':
668
+ ldflags.append('-install_name ' + install_name.replace(' ', r'\ '))
669
+
670
+ for rpath in self._Settings().get('LD_RUNPATH_SEARCH_PATHS', []):
671
+ ldflags.append('-Wl,-rpath,' + rpath)
672
+
673
+ sdk_root = self._SdkPath()
674
+ if not sdk_root:
675
+ sdk_root = ''
676
+ config = self.spec['configurations'][self.configname]
677
+ framework_dirs = config.get('mac_framework_dirs', [])
678
+ for directory in framework_dirs:
679
+ ldflags.append('-F' + directory.replace('$(SDKROOT)', sdk_root))
680
+
681
+ self.configname = None
682
+ return ldflags
683
+
684
+ def GetLibtoolflags(self, configname):
685
+ """Returns flags that need to be passed to the static linker.
686
+
687
+ Args:
688
+ configname: The name of the configuration to get ld flags for.
689
+ """
690
+ self.configname = configname
691
+ libtoolflags = []
692
+
693
+ for libtoolflag in self._Settings().get('OTHER_LDFLAGS', []):
694
+ libtoolflags.append(libtoolflag)
695
+ # TODO(thakis): ARCHS?
696
+
697
+ self.configname = None
698
+ return libtoolflags
699
+
700
+ def GetPerTargetSettings(self):
701
+ """Gets a list of all the per-target settings. This will only fetch keys
702
+ whose values are the same across all configurations."""
703
+ first_pass = True
704
+ result = {}
705
+ for configname in sorted(self.xcode_settings.keys()):
706
+ if first_pass:
707
+ result = dict(self.xcode_settings[configname])
708
+ first_pass = False
709
+ else:
710
+ for key, value in self.xcode_settings[configname].iteritems():
711
+ if key not in result:
712
+ continue
713
+ elif result[key] != value:
714
+ del result[key]
715
+ return result
716
+
717
+ def GetPerConfigSetting(self, setting, configname, default=None):
718
+ if configname in self.xcode_settings:
719
+ return self.xcode_settings[configname].get(setting, default)
720
+ else:
721
+ return self.GetPerTargetSetting(setting, default)
722
+
723
+ def GetPerTargetSetting(self, setting, default=None):
724
+ """Tries to get xcode_settings.setting from spec. Assumes that the setting
725
+ has the same value in all configurations and throws otherwise."""
726
+ is_first_pass = True
727
+ result = None
728
+ for configname in sorted(self.xcode_settings.keys()):
729
+ if is_first_pass:
730
+ result = self.xcode_settings[configname].get(setting, None)
731
+ is_first_pass = False
732
+ else:
733
+ assert result == self.xcode_settings[configname].get(setting, None), (
734
+ "Expected per-target setting for '%s', got per-config setting "
735
+ "(target %s)" % (setting, self.spec['target_name']))
736
+ if result is None:
737
+ return default
738
+ return result
739
+
740
+ def _GetStripPostbuilds(self, configname, output_binary, quiet):
741
+ """Returns a list of shell commands that contain the shell commands
742
+ neccessary to strip this target's binary. These should be run as postbuilds
743
+ before the actual postbuilds run."""
744
+ self.configname = configname
745
+
746
+ result = []
747
+ if (self._Test('DEPLOYMENT_POSTPROCESSING', 'YES', default='NO') and
748
+ self._Test('STRIP_INSTALLED_PRODUCT', 'YES', default='NO')):
749
+
750
+ default_strip_style = 'debugging'
751
+ if self.spec['type'] == 'loadable_module' and self._IsBundle():
752
+ default_strip_style = 'non-global'
753
+ elif self.spec['type'] == 'executable':
754
+ default_strip_style = 'all'
755
+
756
+ strip_style = self._Settings().get('STRIP_STYLE', default_strip_style)
757
+ strip_flags = {
758
+ 'all': '',
759
+ 'non-global': '-x',
760
+ 'debugging': '-S',
761
+ }[strip_style]
762
+
763
+ explicit_strip_flags = self._Settings().get('STRIPFLAGS', '')
764
+ if explicit_strip_flags:
765
+ strip_flags += ' ' + _NormalizeEnvVarReferences(explicit_strip_flags)
766
+
767
+ if not quiet:
768
+ result.append('echo STRIP\\(%s\\)' % self.spec['target_name'])
769
+ result.append('strip %s %s' % (strip_flags, output_binary))
770
+
771
+ self.configname = None
772
+ return result
773
+
774
+ def _GetDebugInfoPostbuilds(self, configname, output, output_binary, quiet):
775
+ """Returns a list of shell commands that contain the shell commands
776
+ neccessary to massage this target's debug information. These should be run
777
+ as postbuilds before the actual postbuilds run."""
778
+ self.configname = configname
779
+
780
+ # For static libraries, no dSYMs are created.
781
+ result = []
782
+ if (self._Test('GCC_GENERATE_DEBUGGING_SYMBOLS', 'YES', default='YES') and
783
+ self._Test(
784
+ 'DEBUG_INFORMATION_FORMAT', 'dwarf-with-dsym', default='dwarf') and
785
+ self.spec['type'] != 'static_library'):
786
+ if not quiet:
787
+ result.append('echo DSYMUTIL\\(%s\\)' % self.spec['target_name'])
788
+ result.append('dsymutil %s -o %s' % (output_binary, output + '.dSYM'))
789
+
790
+ self.configname = None
791
+ return result
792
+
793
+ def _GetTargetPostbuilds(self, configname, output, output_binary,
794
+ quiet=False):
795
+ """Returns a list of shell commands that contain the shell commands
796
+ to run as postbuilds for this target, before the actual postbuilds."""
797
+ # dSYMs need to build before stripping happens.
798
+ return (
799
+ self._GetDebugInfoPostbuilds(configname, output, output_binary, quiet) +
800
+ self._GetStripPostbuilds(configname, output_binary, quiet))
801
+
802
+ def _GetIOSPostbuilds(self, configname, output_binary):
803
+ """Return a shell command to codesign the iOS output binary so it can
804
+ be deployed to a device. This should be run as the very last step of the
805
+ build."""
806
+ if not (self.isIOS and self.spec['type'] == "executable"):
807
+ return []
808
+
809
+ settings = self.xcode_settings[configname]
810
+ key = self._GetIOSCodeSignIdentityKey(settings)
811
+ if not key:
812
+ return []
813
+
814
+ # Warn for any unimplemented signing xcode keys.
815
+ unimpl = ['OTHER_CODE_SIGN_FLAGS']
816
+ unimpl = set(unimpl) & set(self.xcode_settings[configname].keys())
817
+ if unimpl:
818
+ print 'Warning: Some codesign keys not implemented, ignoring: %s' % (
819
+ ', '.join(sorted(unimpl)))
820
+
821
+ return ['%s code-sign-bundle "%s" "%s" "%s" "%s"' % (
822
+ os.path.join('${TARGET_BUILD_DIR}', 'gyp-mac-tool'), key,
823
+ settings.get('CODE_SIGN_RESOURCE_RULES_PATH', ''),
824
+ settings.get('CODE_SIGN_ENTITLEMENTS', ''),
825
+ settings.get('PROVISIONING_PROFILE', ''))
826
+ ]
827
+
828
+ def _GetIOSCodeSignIdentityKey(self, settings):
829
+ identity = settings.get('CODE_SIGN_IDENTITY')
830
+ if not identity:
831
+ return None
832
+ if identity not in XcodeSettings._codesigning_key_cache:
833
+ output = subprocess.check_output(
834
+ ['security', 'find-identity', '-p', 'codesigning', '-v'])
835
+ for line in output.splitlines():
836
+ if identity in line:
837
+ fingerprint = line.split()[1]
838
+ cache = XcodeSettings._codesigning_key_cache
839
+ assert identity not in cache or fingerprint == cache[identity], (
840
+ "Multiple codesigning fingerprints for identity: %s" % identity)
841
+ XcodeSettings._codesigning_key_cache[identity] = fingerprint
842
+ return XcodeSettings._codesigning_key_cache.get(identity, '')
843
+
844
+ def AddImplicitPostbuilds(self, configname, output, output_binary,
845
+ postbuilds=[], quiet=False):
846
+ """Returns a list of shell commands that should run before and after
847
+ |postbuilds|."""
848
+ assert output_binary is not None
849
+ pre = self._GetTargetPostbuilds(configname, output, output_binary, quiet)
850
+ post = self._GetIOSPostbuilds(configname, output_binary)
851
+ return pre + postbuilds + post
852
+
853
+ def _AdjustLibrary(self, library, config_name=None):
854
+ if library.endswith('.framework'):
855
+ l = '-framework ' + os.path.splitext(os.path.basename(library))[0]
856
+ else:
857
+ m = self.library_re.match(library)
858
+ if m:
859
+ l = '-l' + m.group(1)
860
+ else:
861
+ l = library
862
+
863
+ sdk_root = self._SdkPath(config_name)
864
+ if not sdk_root:
865
+ sdk_root = ''
866
+ return l.replace('$(SDKROOT)', sdk_root)
867
+
868
+ def AdjustLibraries(self, libraries, config_name=None):
869
+ """Transforms entries like 'Cocoa.framework' in libraries into entries like
870
+ '-framework Cocoa', 'libcrypto.dylib' into '-lcrypto', etc.
871
+ """
872
+ libraries = [self._AdjustLibrary(library, config_name)
873
+ for library in libraries]
874
+ return libraries
875
+
876
+ def _BuildMachineOSBuild(self):
877
+ return self._GetStdout(['sw_vers', '-buildVersion'])
878
+
879
+ # This method ported from the logic in Homebrew's CLT version check
880
+ def _CLTVersion(self):
881
+ # pkgutil output looks like
882
+ # package-id: com.apple.pkg.CLTools_Executables
883
+ # version: 5.0.1.0.1.1382131676
884
+ # volume: /
885
+ # location: /
886
+ # install-time: 1382544035
887
+ # groups: com.apple.FindSystemFiles.pkg-group com.apple.DevToolsBoth.pkg-group com.apple.DevToolsNonRelocatableShared.pkg-group
888
+ STANDALONE_PKG_ID = "com.apple.pkg.DeveloperToolsCLILeo"
889
+ FROM_XCODE_PKG_ID = "com.apple.pkg.DeveloperToolsCLI"
890
+ MAVERICKS_PKG_ID = "com.apple.pkg.CLTools_Executables"
891
+
892
+ regex = re.compile('version: (?P<version>.+)')
893
+ for key in [MAVERICKS_PKG_ID, STANDALONE_PKG_ID, FROM_XCODE_PKG_ID]:
894
+ try:
895
+ output = self._GetStdout(['/usr/sbin/pkgutil', '--pkg-info', key])
896
+ return re.search(regex, output).groupdict()['version']
897
+ except:
898
+ continue
899
+
900
+ def _XcodeVersion(self):
901
+ # `xcodebuild -version` output looks like
902
+ # Xcode 4.6.3
903
+ # Build version 4H1503
904
+ # or like
905
+ # Xcode 3.2.6
906
+ # Component versions: DevToolsCore-1809.0; DevToolsSupport-1806.0
907
+ # BuildVersion: 10M2518
908
+ # Convert that to '0463', '4H1503'.
909
+ if len(XcodeSettings._xcode_version_cache) == 0:
910
+ try:
911
+ version_list = self._GetStdout(['xcodebuild', '-version']).splitlines()
912
+ # In some circumstances xcodebuild exits 0 but doesn't return
913
+ # the right results; for example, a user on 10.7 or 10.8 with
914
+ # a bogus path set via xcode-select
915
+ # In that case this may be a CLT-only install so fall back to
916
+ # checking that version.
917
+ if len(version_list) < 2:
918
+ raise GypError, "xcodebuild returned unexpected results"
919
+ except:
920
+ version = self._CLTVersion()
921
+ if version:
922
+ version = re.match('(\d\.\d\.?\d*)', version).groups()[0]
923
+ else:
924
+ raise GypError, "No Xcode or CLT version detected!"
925
+ # The CLT has no build information, so we return an empty string.
926
+ version_list = [version, '']
927
+ version = version_list[0]
928
+ build = version_list[-1]
929
+ # Be careful to convert "4.2" to "0420":
930
+ version = version.split()[-1].replace('.', '')
931
+ version = (version + '0' * (3 - len(version))).zfill(4)
932
+ if build:
933
+ build = build.split()[-1]
934
+ XcodeSettings._xcode_version_cache = (version, build)
935
+ return XcodeSettings._xcode_version_cache
936
+
937
+ def _XcodeIOSDeviceFamily(self, configname):
938
+ family = self.xcode_settings[configname].get('TARGETED_DEVICE_FAMILY', '1')
939
+ return [int(x) for x in family.split(',')]
940
+
941
+ def GetExtraPlistItems(self, configname=None):
942
+ """Returns a dictionary with extra items to insert into Info.plist."""
943
+ if configname not in XcodeSettings._plist_cache:
944
+ cache = {}
945
+ cache['BuildMachineOSBuild'] = self._BuildMachineOSBuild()
946
+
947
+ xcode, xcode_build = self._XcodeVersion()
948
+ cache['DTXcode'] = xcode
949
+ cache['DTXcodeBuild'] = xcode_build
950
+
951
+ sdk_root = self._SdkRoot(configname)
952
+ if not sdk_root:
953
+ sdk_root = self._DefaultSdkRoot()
954
+ cache['DTSDKName'] = sdk_root
955
+ if xcode >= '0430':
956
+ cache['DTSDKBuild'] = self._GetSdkVersionInfoItem(
957
+ sdk_root, 'ProductBuildVersion')
958
+ else:
959
+ cache['DTSDKBuild'] = cache['BuildMachineOSBuild']
960
+
961
+ if self.isIOS:
962
+ cache['DTPlatformName'] = cache['DTSDKName']
963
+ if configname.endswith("iphoneos"):
964
+ cache['DTPlatformVersion'] = self._GetSdkVersionInfoItem(
965
+ sdk_root, 'ProductVersion')
966
+ cache['CFBundleSupportedPlatforms'] = ['iPhoneOS']
967
+ else:
968
+ cache['CFBundleSupportedPlatforms'] = ['iPhoneSimulator']
969
+ XcodeSettings._plist_cache[configname] = cache
970
+
971
+ # Include extra plist items that are per-target, not per global
972
+ # XcodeSettings.
973
+ items = dict(XcodeSettings._plist_cache[configname])
974
+ if self.isIOS:
975
+ items['UIDeviceFamily'] = self._XcodeIOSDeviceFamily(configname)
976
+ return items
977
+
978
+ def _DefaultSdkRoot(self):
979
+ """Returns the default SDKROOT to use.
980
+
981
+ Prior to version 5.0.0, if SDKROOT was not explicitly set in the Xcode
982
+ project, then the environment variable was empty. Starting with this
983
+ version, Xcode uses the name of the newest SDK installed.
984
+ """
985
+ if self._XcodeVersion() < '0500':
986
+ return ''
987
+ default_sdk_path = self._XcodeSdkPath('')
988
+ default_sdk_root = XcodeSettings._sdk_root_cache.get(default_sdk_path)
989
+ if default_sdk_root:
990
+ return default_sdk_root
991
+ try:
992
+ all_sdks = self._GetStdout(['xcodebuild', '-showsdks'])
993
+ except:
994
+ # If xcodebuild fails, there will be no valid SDKs
995
+ return ''
996
+ for line in all_sdks.splitlines():
997
+ items = line.split()
998
+ if len(items) >= 3 and items[-2] == '-sdk':
999
+ sdk_root = items[-1]
1000
+ sdk_path = self._XcodeSdkPath(sdk_root)
1001
+ if sdk_path == default_sdk_path:
1002
+ return sdk_root
1003
+ return ''
1004
+
1005
+ def _DefaultArch(self):
1006
+ # For Mac projects, Xcode changed the default value used when ARCHS is not
1007
+ # set from "i386" to "x86_64".
1008
+ #
1009
+ # For iOS projects, if ARCHS is unset, it defaults to "armv7 armv7s" when
1010
+ # building for a device, and the simulator binaries are always build for
1011
+ # "i386".
1012
+ #
1013
+ # For new projects, ARCHS is set to $(ARCHS_STANDARD_INCLUDING_64_BIT),
1014
+ # which correspond to "armv7 armv7s arm64", and when building the simulator
1015
+ # the architecture is either "i386" or "x86_64" depending on the simulated
1016
+ # device (respectively 32-bit or 64-bit device).
1017
+ #
1018
+ # Since the value returned by this function is only used when ARCHS is not
1019
+ # set, then on iOS we return "i386", as the default xcode project generator
1020
+ # does not set ARCHS if it is not set in the .gyp file.
1021
+ if self.isIOS:
1022
+ return 'i386'
1023
+ version, build = self._XcodeVersion()
1024
+ if version >= '0500':
1025
+ return 'x86_64'
1026
+ return 'i386'
1027
+
1028
+ class MacPrefixHeader(object):
1029
+ """A class that helps with emulating Xcode's GCC_PREFIX_HEADER feature.
1030
+
1031
+ This feature consists of several pieces:
1032
+ * If GCC_PREFIX_HEADER is present, all compilations in that project get an
1033
+ additional |-include path_to_prefix_header| cflag.
1034
+ * If GCC_PRECOMPILE_PREFIX_HEADER is present too, then the prefix header is
1035
+ instead compiled, and all other compilations in the project get an
1036
+ additional |-include path_to_compiled_header| instead.
1037
+ + Compiled prefix headers have the extension gch. There is one gch file for
1038
+ every language used in the project (c, cc, m, mm), since gch files for
1039
+ different languages aren't compatible.
1040
+ + gch files themselves are built with the target's normal cflags, but they
1041
+ obviously don't get the |-include| flag. Instead, they need a -x flag that
1042
+ describes their language.
1043
+ + All o files in the target need to depend on the gch file, to make sure
1044
+ it's built before any o file is built.
1045
+
1046
+ This class helps with some of these tasks, but it needs help from the build
1047
+ system for writing dependencies to the gch files, for writing build commands
1048
+ for the gch files, and for figuring out the location of the gch files.
1049
+ """
1050
+ def __init__(self, xcode_settings,
1051
+ gyp_path_to_build_path, gyp_path_to_build_output):
1052
+ """If xcode_settings is None, all methods on this class are no-ops.
1053
+
1054
+ Args:
1055
+ gyp_path_to_build_path: A function that takes a gyp-relative path,
1056
+ and returns a path relative to the build directory.
1057
+ gyp_path_to_build_output: A function that takes a gyp-relative path and
1058
+ a language code ('c', 'cc', 'm', or 'mm'), and that returns a path
1059
+ to where the output of precompiling that path for that language
1060
+ should be placed (without the trailing '.gch').
1061
+ """
1062
+ # This doesn't support per-configuration prefix headers. Good enough
1063
+ # for now.
1064
+ self.header = None
1065
+ self.compile_headers = False
1066
+ if xcode_settings:
1067
+ self.header = xcode_settings.GetPerTargetSetting('GCC_PREFIX_HEADER')
1068
+ self.compile_headers = xcode_settings.GetPerTargetSetting(
1069
+ 'GCC_PRECOMPILE_PREFIX_HEADER', default='NO') != 'NO'
1070
+ self.compiled_headers = {}
1071
+ if self.header:
1072
+ if self.compile_headers:
1073
+ for lang in ['c', 'cc', 'm', 'mm']:
1074
+ self.compiled_headers[lang] = gyp_path_to_build_output(
1075
+ self.header, lang)
1076
+ self.header = gyp_path_to_build_path(self.header)
1077
+
1078
+ def _CompiledHeader(self, lang, arch):
1079
+ assert self.compile_headers
1080
+ h = self.compiled_headers[lang]
1081
+ if arch:
1082
+ h += '.' + arch
1083
+ return h
1084
+
1085
+ def GetInclude(self, lang, arch=None):
1086
+ """Gets the cflags to include the prefix header for language |lang|."""
1087
+ if self.compile_headers and lang in self.compiled_headers:
1088
+ return '-include %s' % self._CompiledHeader(lang, arch)
1089
+ elif self.header:
1090
+ return '-include %s' % self.header
1091
+ else:
1092
+ return ''
1093
+
1094
+ def _Gch(self, lang, arch):
1095
+ """Returns the actual file name of the prefix header for language |lang|."""
1096
+ assert self.compile_headers
1097
+ return self._CompiledHeader(lang, arch) + '.gch'
1098
+
1099
+ def GetObjDependencies(self, sources, objs, arch=None):
1100
+ """Given a list of source files and the corresponding object files, returns
1101
+ a list of (source, object, gch) tuples, where |gch| is the build-directory
1102
+ relative path to the gch file each object file depends on. |compilable[i]|
1103
+ has to be the source file belonging to |objs[i]|."""
1104
+ if not self.header or not self.compile_headers:
1105
+ return []
1106
+
1107
+ result = []
1108
+ for source, obj in zip(sources, objs):
1109
+ ext = os.path.splitext(source)[1]
1110
+ lang = {
1111
+ '.c': 'c',
1112
+ '.cpp': 'cc', '.cc': 'cc', '.cxx': 'cc',
1113
+ '.m': 'm',
1114
+ '.mm': 'mm',
1115
+ }.get(ext, None)
1116
+ if lang:
1117
+ result.append((source, obj, self._Gch(lang, arch)))
1118
+ return result
1119
+
1120
+ def GetPchBuildCommands(self, arch=None):
1121
+ """Returns [(path_to_gch, language_flag, language, header)].
1122
+ |path_to_gch| and |header| are relative to the build directory.
1123
+ """
1124
+ if not self.header or not self.compile_headers:
1125
+ return []
1126
+ return [
1127
+ (self._Gch('c', arch), '-x c-header', 'c', self.header),
1128
+ (self._Gch('cc', arch), '-x c++-header', 'cc', self.header),
1129
+ (self._Gch('m', arch), '-x objective-c-header', 'm', self.header),
1130
+ (self._Gch('mm', arch), '-x objective-c++-header', 'mm', self.header),
1131
+ ]
1132
+
1133
+
1134
+ def MergeGlobalXcodeSettingsToSpec(global_dict, spec):
1135
+ """Merges the global xcode_settings dictionary into each configuration of the
1136
+ target represented by spec. For keys that are both in the global and the local
1137
+ xcode_settings dict, the local key gets precendence.
1138
+ """
1139
+ # The xcode generator special-cases global xcode_settings and does something
1140
+ # that amounts to merging in the global xcode_settings into each local
1141
+ # xcode_settings dict.
1142
+ global_xcode_settings = global_dict.get('xcode_settings', {})
1143
+ for config in spec['configurations'].values():
1144
+ if 'xcode_settings' in config:
1145
+ new_settings = global_xcode_settings.copy()
1146
+ new_settings.update(config['xcode_settings'])
1147
+ config['xcode_settings'] = new_settings
1148
+
1149
+
1150
+ def IsMacBundle(flavor, spec):
1151
+ """Returns if |spec| should be treated as a bundle.
1152
+
1153
+ Bundles are directories with a certain subdirectory structure, instead of
1154
+ just a single file. Bundle rules do not produce a binary but also package
1155
+ resources into that directory."""
1156
+ is_mac_bundle = (int(spec.get('mac_bundle', 0)) != 0 and flavor == 'mac')
1157
+ if is_mac_bundle:
1158
+ assert spec['type'] != 'none', (
1159
+ 'mac_bundle targets cannot have type none (target "%s")' %
1160
+ spec['target_name'])
1161
+ return is_mac_bundle
1162
+
1163
+
1164
+ def GetMacBundleResources(product_dir, xcode_settings, resources):
1165
+ """Yields (output, resource) pairs for every resource in |resources|.
1166
+ Only call this for mac bundle targets.
1167
+
1168
+ Args:
1169
+ product_dir: Path to the directory containing the output bundle,
1170
+ relative to the build directory.
1171
+ xcode_settings: The XcodeSettings of the current target.
1172
+ resources: A list of bundle resources, relative to the build directory.
1173
+ """
1174
+ dest = os.path.join(product_dir,
1175
+ xcode_settings.GetBundleResourceFolder())
1176
+ for res in resources:
1177
+ output = dest
1178
+
1179
+ # The make generator doesn't support it, so forbid it everywhere
1180
+ # to keep the generators more interchangable.
1181
+ assert ' ' not in res, (
1182
+ "Spaces in resource filenames not supported (%s)" % res)
1183
+
1184
+ # Split into (path,file).
1185
+ res_parts = os.path.split(res)
1186
+
1187
+ # Now split the path into (prefix,maybe.lproj).
1188
+ lproj_parts = os.path.split(res_parts[0])
1189
+ # If the resource lives in a .lproj bundle, add that to the destination.
1190
+ if lproj_parts[1].endswith('.lproj'):
1191
+ output = os.path.join(output, lproj_parts[1])
1192
+
1193
+ output = os.path.join(output, res_parts[1])
1194
+ # Compiled XIB files are referred to by .nib.
1195
+ if output.endswith('.xib'):
1196
+ output = os.path.splitext(output)[0] + '.nib'
1197
+ # Compiled storyboard files are referred to by .storyboardc.
1198
+ if output.endswith('.storyboard'):
1199
+ output = os.path.splitext(output)[0] + '.storyboardc'
1200
+
1201
+ yield output, res
1202
+
1203
+
1204
+ def GetMacInfoPlist(product_dir, xcode_settings, gyp_path_to_build_path):
1205
+ """Returns (info_plist, dest_plist, defines, extra_env), where:
1206
+ * |info_plist| is the source plist path, relative to the
1207
+ build directory,
1208
+ * |dest_plist| is the destination plist path, relative to the
1209
+ build directory,
1210
+ * |defines| is a list of preprocessor defines (empty if the plist
1211
+ shouldn't be preprocessed,
1212
+ * |extra_env| is a dict of env variables that should be exported when
1213
+ invoking |mac_tool copy-info-plist|.
1214
+
1215
+ Only call this for mac bundle targets.
1216
+
1217
+ Args:
1218
+ product_dir: Path to the directory containing the output bundle,
1219
+ relative to the build directory.
1220
+ xcode_settings: The XcodeSettings of the current target.
1221
+ gyp_to_build_path: A function that converts paths relative to the
1222
+ current gyp file to paths relative to the build direcotry.
1223
+ """
1224
+ info_plist = xcode_settings.GetPerTargetSetting('INFOPLIST_FILE')
1225
+ if not info_plist:
1226
+ return None, None, [], {}
1227
+
1228
+ # The make generator doesn't support it, so forbid it everywhere
1229
+ # to keep the generators more interchangable.
1230
+ assert ' ' not in info_plist, (
1231
+ "Spaces in Info.plist filenames not supported (%s)" % info_plist)
1232
+
1233
+ info_plist = gyp_path_to_build_path(info_plist)
1234
+
1235
+ # If explicitly set to preprocess the plist, invoke the C preprocessor and
1236
+ # specify any defines as -D flags.
1237
+ if xcode_settings.GetPerTargetSetting(
1238
+ 'INFOPLIST_PREPROCESS', default='NO') == 'YES':
1239
+ # Create an intermediate file based on the path.
1240
+ defines = shlex.split(xcode_settings.GetPerTargetSetting(
1241
+ 'INFOPLIST_PREPROCESSOR_DEFINITIONS', default=''))
1242
+ else:
1243
+ defines = []
1244
+
1245
+ dest_plist = os.path.join(product_dir, xcode_settings.GetBundlePlistPath())
1246
+ extra_env = xcode_settings.GetPerTargetSettings()
1247
+
1248
+ return info_plist, dest_plist, defines, extra_env
1249
+
1250
+
1251
+ def _GetXcodeEnv(xcode_settings, built_products_dir, srcroot, configuration,
1252
+ additional_settings=None):
1253
+ """Return the environment variables that Xcode would set. See
1254
+ 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
1255
+ for a full list.
1256
+
1257
+ Args:
1258
+ xcode_settings: An XcodeSettings object. If this is None, this function
1259
+ returns an empty dict.
1260
+ built_products_dir: Absolute path to the built products dir.
1261
+ srcroot: Absolute path to the source root.
1262
+ configuration: The build configuration name.
1263
+ additional_settings: An optional dict with more values to add to the
1264
+ result.
1265
+ """
1266
+ if not xcode_settings: return {}
1267
+
1268
+ # This function is considered a friend of XcodeSettings, so let it reach into
1269
+ # its implementation details.
1270
+ spec = xcode_settings.spec
1271
+
1272
+ # These are filled in on a as-needed basis.
1273
+ env = {
1274
+ 'BUILT_PRODUCTS_DIR' : built_products_dir,
1275
+ 'CONFIGURATION' : configuration,
1276
+ 'PRODUCT_NAME' : xcode_settings.GetProductName(),
1277
+ # See /Developer/Platforms/MacOSX.platform/Developer/Library/Xcode/Specifications/MacOSX\ Product\ Types.xcspec for FULL_PRODUCT_NAME
1278
+ 'SRCROOT' : srcroot,
1279
+ 'SOURCE_ROOT': '${SRCROOT}',
1280
+ # This is not true for static libraries, but currently the env is only
1281
+ # written for bundles:
1282
+ 'TARGET_BUILD_DIR' : built_products_dir,
1283
+ 'TEMP_DIR' : '${TMPDIR}',
1284
+ }
1285
+ if xcode_settings.GetPerConfigSetting('SDKROOT', configuration):
1286
+ env['SDKROOT'] = xcode_settings._SdkPath(configuration)
1287
+ else:
1288
+ env['SDKROOT'] = ''
1289
+
1290
+ if spec['type'] in (
1291
+ 'executable', 'static_library', 'shared_library', 'loadable_module'):
1292
+ env['EXECUTABLE_NAME'] = xcode_settings.GetExecutableName()
1293
+ env['EXECUTABLE_PATH'] = xcode_settings.GetExecutablePath()
1294
+ env['FULL_PRODUCT_NAME'] = xcode_settings.GetFullProductName()
1295
+ mach_o_type = xcode_settings.GetMachOType()
1296
+ if mach_o_type:
1297
+ env['MACH_O_TYPE'] = mach_o_type
1298
+ env['PRODUCT_TYPE'] = xcode_settings.GetProductType()
1299
+ if xcode_settings._IsBundle():
1300
+ env['CONTENTS_FOLDER_PATH'] = \
1301
+ xcode_settings.GetBundleContentsFolderPath()
1302
+ env['UNLOCALIZED_RESOURCES_FOLDER_PATH'] = \
1303
+ xcode_settings.GetBundleResourceFolder()
1304
+ env['INFOPLIST_PATH'] = xcode_settings.GetBundlePlistPath()
1305
+ env['WRAPPER_NAME'] = xcode_settings.GetWrapperName()
1306
+
1307
+ install_name = xcode_settings.GetInstallName()
1308
+ if install_name:
1309
+ env['LD_DYLIB_INSTALL_NAME'] = install_name
1310
+ install_name_base = xcode_settings.GetInstallNameBase()
1311
+ if install_name_base:
1312
+ env['DYLIB_INSTALL_NAME_BASE'] = install_name_base
1313
+
1314
+ if not additional_settings:
1315
+ additional_settings = {}
1316
+ else:
1317
+ # Flatten lists to strings.
1318
+ for k in additional_settings:
1319
+ if not isinstance(additional_settings[k], str):
1320
+ additional_settings[k] = ' '.join(additional_settings[k])
1321
+ additional_settings.update(env)
1322
+
1323
+ for k in additional_settings:
1324
+ additional_settings[k] = _NormalizeEnvVarReferences(additional_settings[k])
1325
+
1326
+ return additional_settings
1327
+
1328
+
1329
+ def _NormalizeEnvVarReferences(str):
1330
+ """Takes a string containing variable references in the form ${FOO}, $(FOO),
1331
+ or $FOO, and returns a string with all variable references in the form ${FOO}.
1332
+ """
1333
+ # $FOO -> ${FOO}
1334
+ str = re.sub(r'\$([a-zA-Z_][a-zA-Z0-9_]*)', r'${\1}', str)
1335
+
1336
+ # $(FOO) -> ${FOO}
1337
+ matches = re.findall(r'(\$\(([a-zA-Z0-9\-_]+)\))', str)
1338
+ for match in matches:
1339
+ to_replace, variable = match
1340
+ assert '$(' not in match, '$($(FOO)) variables not supported: ' + match
1341
+ str = str.replace(to_replace, '${' + variable + '}')
1342
+
1343
+ return str
1344
+
1345
+
1346
+ def ExpandEnvVars(string, expansions):
1347
+ """Expands ${VARIABLES}, $(VARIABLES), and $VARIABLES in string per the
1348
+ expansions list. If the variable expands to something that references
1349
+ another variable, this variable is expanded as well if it's in env --
1350
+ until no variables present in env are left."""
1351
+ for k, v in reversed(expansions):
1352
+ string = string.replace('${' + k + '}', v)
1353
+ string = string.replace('$(' + k + ')', v)
1354
+ string = string.replace('$' + k, v)
1355
+ return string
1356
+
1357
+
1358
+ def _TopologicallySortedEnvVarKeys(env):
1359
+ """Takes a dict |env| whose values are strings that can refer to other keys,
1360
+ for example env['foo'] = '$(bar) and $(baz)'. Returns a list L of all keys of
1361
+ env such that key2 is after key1 in L if env[key2] refers to env[key1].
1362
+
1363
+ Throws an Exception in case of dependency cycles.
1364
+ """
1365
+ # Since environment variables can refer to other variables, the evaluation
1366
+ # order is important. Below is the logic to compute the dependency graph
1367
+ # and sort it.
1368
+ regex = re.compile(r'\$\{([a-zA-Z0-9\-_]+)\}')
1369
+ def GetEdges(node):
1370
+ # Use a definition of edges such that user_of_variable -> used_varible.
1371
+ # This happens to be easier in this case, since a variable's
1372
+ # definition contains all variables it references in a single string.
1373
+ # We can then reverse the result of the topological sort at the end.
1374
+ # Since: reverse(topsort(DAG)) = topsort(reverse_edges(DAG))
1375
+ matches = set([v for v in regex.findall(env[node]) if v in env])
1376
+ for dependee in matches:
1377
+ assert '${' not in dependee, 'Nested variables not supported: ' + dependee
1378
+ return matches
1379
+
1380
+ try:
1381
+ # Topologically sort, and then reverse, because we used an edge definition
1382
+ # that's inverted from the expected result of this function (see comment
1383
+ # above).
1384
+ order = gyp.common.TopologicallySorted(env.keys(), GetEdges)
1385
+ order.reverse()
1386
+ return order
1387
+ except gyp.common.CycleError, e:
1388
+ raise GypError(
1389
+ 'Xcode environment variables are cyclically dependent: ' + str(e.nodes))
1390
+
1391
+
1392
+ def GetSortedXcodeEnv(xcode_settings, built_products_dir, srcroot,
1393
+ configuration, additional_settings=None):
1394
+ env = _GetXcodeEnv(xcode_settings, built_products_dir, srcroot, configuration,
1395
+ additional_settings)
1396
+ return [(key, env[key]) for key in _TopologicallySortedEnvVarKeys(env)]
1397
+
1398
+
1399
+ def GetSpecPostbuildCommands(spec, quiet=False):
1400
+ """Returns the list of postbuilds explicitly defined on |spec|, in a form
1401
+ executable by a shell."""
1402
+ postbuilds = []
1403
+ for postbuild in spec.get('postbuilds', []):
1404
+ if not quiet:
1405
+ postbuilds.append('echo POSTBUILD\\(%s\\) %s' % (
1406
+ spec['target_name'], postbuild['postbuild_name']))
1407
+ postbuilds.append(gyp.common.EncodePOSIXShellList(postbuild['action']))
1408
+ return postbuilds
1409
+
1410
+
1411
+ def _HasIOSTarget(targets):
1412
+ """Returns true if any target contains the iOS specific key
1413
+ IPHONEOS_DEPLOYMENT_TARGET."""
1414
+ for target_dict in targets.values():
1415
+ for config in target_dict['configurations'].values():
1416
+ if config.get('xcode_settings', {}).get('IPHONEOS_DEPLOYMENT_TARGET'):
1417
+ return True
1418
+ return False
1419
+
1420
+
1421
+ def _AddIOSDeviceConfigurations(targets):
1422
+ """Clone all targets and append -iphoneos to the name. Configure these targets
1423
+ to build for iOS devices."""
1424
+ for target_dict in targets.values():
1425
+ for config_name in target_dict['configurations'].keys():
1426
+ config = target_dict['configurations'][config_name]
1427
+ new_config_name = config_name + '-iphoneos'
1428
+ new_config_dict = copy.deepcopy(config)
1429
+ if target_dict['toolset'] == 'target':
1430
+ new_config_dict['xcode_settings']['ARCHS'] = ['armv7']
1431
+ new_config_dict['xcode_settings']['SDKROOT'] = 'iphoneos'
1432
+ target_dict['configurations'][new_config_name] = new_config_dict
1433
+ return targets
1434
+
1435
+ def CloneConfigurationForDeviceAndEmulator(target_dicts):
1436
+ """If |target_dicts| contains any iOS targets, automatically create -iphoneos
1437
+ targets for iOS device builds."""
1438
+ if _HasIOSTarget(target_dicts):
1439
+ return _AddIOSDeviceConfigurations(target_dicts)
1440
+ return target_dicts