OLD | NEW |
---|---|
1 # Copyright (c) 2012 Google Inc. All rights reserved. | 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 | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 """ | 5 """ |
6 This module contains classes that help to emulate xcodebuild behavior on top of | 6 This module contains classes that help to emulate xcodebuild behavior on top of |
7 other build systems, such as make and ninja. | 7 other build systems, such as make and ninja. |
8 """ | 8 """ |
9 | 9 |
10 import gyp.common | 10 import gyp.common |
11 import os.path | 11 import os.path |
12 import re | 12 import re |
13 import shlex | 13 import shlex |
14 import subprocess | |
14 | 15 |
15 class XcodeSettings(object): | 16 class XcodeSettings(object): |
16 """A class that understands the gyp 'xcode_settings' object.""" | 17 """A class that understands the gyp 'xcode_settings' object.""" |
17 | 18 |
18 # Computed lazily by _GetSdkBaseDir(). Shared by all XcodeSettings, so cached | 19 # Populated lazily by _SdkPath(). Shared by all XcodeSettings, so cached |
19 # at class-level for efficiency. | 20 # at class-level for efficiency. |
20 _sdk_base_dir = None | 21 _sdk_path_cache = {} |
21 | 22 |
22 def __init__(self, spec): | 23 def __init__(self, spec): |
23 self.spec = spec | 24 self.spec = spec |
24 | 25 |
25 # Per-target 'xcode_settings' are pushed down into configs earlier by gyp. | 26 # Per-target 'xcode_settings' are pushed down into configs earlier by gyp. |
26 # This means self.xcode_settings[config] always contains all settings | 27 # This means self.xcode_settings[config] always contains all settings |
27 # for that config -- the per-target settings as well. Settings that are | 28 # for that config -- the per-target settings as well. Settings that are |
28 # the same for all configs are implicitly per-target settings. | 29 # the same for all configs are implicitly per-target settings. |
29 self.xcode_settings = {} | 30 self.xcode_settings = {} |
30 configs = spec['configurations'] | 31 configs = spec['configurations'] |
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
212 return self._GetStandaloneBinaryPath() | 213 return self._GetStandaloneBinaryPath() |
213 | 214 |
214 def GetExecutablePath(self): | 215 def GetExecutablePath(self): |
215 """Returns the directory name of the bundle represented by this target. E.g. | 216 """Returns the directory name of the bundle represented by this target. E.g. |
216 Chromium.app/Contents/MacOS/Chromium.""" | 217 Chromium.app/Contents/MacOS/Chromium.""" |
217 if self._IsBundle(): | 218 if self._IsBundle(): |
218 return self._GetBundleBinaryPath() | 219 return self._GetBundleBinaryPath() |
219 else: | 220 else: |
220 return self._GetStandaloneBinaryPath() | 221 return self._GetStandaloneBinaryPath() |
221 | 222 |
222 def _GetSdkBaseDir(self): | 223 def _GetSdkVersionInfoItem(self, sdk, infoitem): |
223 """Returns the root of the 'Developer' directory. On Xcode 4.2 and prior, | 224 job = subprocess.Popen(['xcodebuild', '-version', '-sdk', sdk, infoitem], |
Nico
2013/03/11 17:14:40
Nice!
| |
224 this is usually just /Developer. Xcode 4.3 moved that folder into the Xcode | 225 stdout=subprocess.PIPE, |
225 bundle.""" | 226 stderr=subprocess.STDOUT) |
226 if not XcodeSettings._sdk_base_dir: | 227 out, err = job.communicate() |
227 import subprocess | 228 if job.returncode != 0: |
228 job = subprocess.Popen(['xcode-select', '-print-path'], | 229 print out |
Nico
2013/03/11 17:14:40
Isn't `err` more interesting?
kal
2013/03/12 13:10:08
'out' gets both stdout and stderr from xcodebuild.
| |
229 stdout=subprocess.PIPE, | 230 raise Exception('Error %d running xcodebuild' % job.returncode) |
230 stderr=subprocess.STDOUT) | 231 return out.rstrip('\n') |
231 out, err = job.communicate() | |
232 if job.returncode != 0: | |
233 print out | |
234 raise Exception('Error %d running xcode-select' % job.returncode) | |
235 # The Developer folder moved in Xcode 4.3. | |
236 xcode43_sdk_path = os.path.join( | |
237 out.rstrip(), 'Platforms/MacOSX.platform/Developer/SDKs') | |
238 if os.path.isdir(xcode43_sdk_path): | |
239 XcodeSettings._sdk_base_dir = xcode43_sdk_path | |
240 else: | |
241 XcodeSettings._sdk_base_dir = os.path.join(out.rstrip(), 'SDKs') | |
242 return XcodeSettings._sdk_base_dir | |
243 | 232 |
244 def _SdkPath(self): | 233 def _SdkPath(self): |
245 sdk_root = self.GetPerTargetSetting('SDKROOT', default='macosx10.5') | 234 sdk_root = self.GetPerTargetSetting('SDKROOT', default='macosx') |
246 if sdk_root.startswith('macosx'): | 235 if sdk_root not in XcodeSettings._sdk_path_cache: |
247 return os.path.join(self._GetSdkBaseDir(), | 236 XcodeSettings._sdk_path_cache[sdk_root] = self._GetSdkVersionInfoItem( |
248 'MacOSX' + sdk_root[len('macosx'):] + '.sdk') | 237 sdk_root, 'Path') |
249 return sdk_root | 238 return XcodeSettings._sdk_path_cache[sdk_root] |
239 | |
240 def _AppendPlatformVersionMinFlags(self, lst): | |
241 self._Appendf(lst, 'MACOSX_DEPLOYMENT_TARGET', '-mmacosx-version-min=%s') | |
242 if 'IPHONEOS_DEPLOYMENT_TARGET' in self._Settings(): | |
243 # TODO: Implement this better? | |
244 sdk_path_basename = os.path.basename(self._SdkPath()) | |
245 if sdk_path_basename.lower().startswith('iphonesimulator'): | |
246 self._Appendf(lst, 'IPHONEOS_DEPLOYMENT_TARGET', | |
247 '-mios-simulator-version-min=%s') | |
248 else: | |
249 self._Appendf(lst, 'IPHONEOS_DEPLOYMENT_TARGET', | |
250 '-miphoneos-version-min=%s') | |
250 | 251 |
251 def GetCflags(self, configname): | 252 def GetCflags(self, configname): |
252 """Returns flags that need to be added to .c, .cc, .m, and .mm | 253 """Returns flags that need to be added to .c, .cc, .m, and .mm |
253 compilations.""" | 254 compilations.""" |
254 # This functions (and the similar ones below) do not offer complete | 255 # This functions (and the similar ones below) do not offer complete |
255 # emulation of all xcode_settings keys. They're implemented on demand. | 256 # emulation of all xcode_settings keys. They're implemented on demand. |
256 | 257 |
257 self.configname = configname | 258 self.configname = configname |
258 cflags = [] | 259 cflags = [] |
259 | 260 |
260 sdk_root = self._SdkPath() | 261 sdk_root = self._SdkPath() |
261 if 'SDKROOT' in self._Settings(): | 262 if 'SDKROOT' in self._Settings(): |
262 cflags.append('-isysroot %s' % sdk_root) | 263 cflags.append('-isysroot %s' % sdk_root) |
263 | 264 |
265 if self._Test('CLANG_WARN_CONSTANT_CONVERSION', 'YES', default='NO'): | |
266 cflags.append('-Wconstant-conversion') | |
267 | |
264 if self._Test('GCC_CHAR_IS_UNSIGNED_CHAR', 'YES', default='NO'): | 268 if self._Test('GCC_CHAR_IS_UNSIGNED_CHAR', 'YES', default='NO'): |
265 cflags.append('-funsigned-char') | 269 cflags.append('-funsigned-char') |
266 | 270 |
267 if self._Test('GCC_CW_ASM_SYNTAX', 'YES', default='YES'): | 271 if self._Test('GCC_CW_ASM_SYNTAX', 'YES', default='YES'): |
268 cflags.append('-fasm-blocks') | 272 cflags.append('-fasm-blocks') |
269 | 273 |
270 if 'GCC_DYNAMIC_NO_PIC' in self._Settings(): | 274 if 'GCC_DYNAMIC_NO_PIC' in self._Settings(): |
271 if self._Settings()['GCC_DYNAMIC_NO_PIC'] == 'YES': | 275 if self._Settings()['GCC_DYNAMIC_NO_PIC'] == 'YES': |
272 cflags.append('-mdynamic-no-pic') | 276 cflags.append('-mdynamic-no-pic') |
273 else: | 277 else: |
(...skipping 20 matching lines...) Expand all Loading... | |
294 | 298 |
295 if self._Test('GCC_SYMBOLS_PRIVATE_EXTERN', 'YES', default='NO'): | 299 if self._Test('GCC_SYMBOLS_PRIVATE_EXTERN', 'YES', default='NO'): |
296 cflags.append('-fvisibility=hidden') | 300 cflags.append('-fvisibility=hidden') |
297 | 301 |
298 if self._Test('GCC_TREAT_WARNINGS_AS_ERRORS', 'YES', default='NO'): | 302 if self._Test('GCC_TREAT_WARNINGS_AS_ERRORS', 'YES', default='NO'): |
299 cflags.append('-Werror') | 303 cflags.append('-Werror') |
300 | 304 |
301 if self._Test('GCC_WARN_ABOUT_MISSING_NEWLINE', 'YES', default='NO'): | 305 if self._Test('GCC_WARN_ABOUT_MISSING_NEWLINE', 'YES', default='NO'): |
302 cflags.append('-Wnewline-eof') | 306 cflags.append('-Wnewline-eof') |
303 | 307 |
304 self._Appendf(cflags, 'MACOSX_DEPLOYMENT_TARGET', '-mmacosx-version-min=%s') | 308 self._AppendPlatformVersionMinFlags(cflags) |
305 | 309 |
306 # TODO: | 310 # TODO: |
307 if self._Test('COPY_PHASE_STRIP', 'YES', default='NO'): | 311 if self._Test('COPY_PHASE_STRIP', 'YES', default='NO'): |
308 self._WarnUnimplemented('COPY_PHASE_STRIP') | 312 self._WarnUnimplemented('COPY_PHASE_STRIP') |
309 self._WarnUnimplemented('GCC_DEBUGGING_SYMBOLS') | 313 self._WarnUnimplemented('GCC_DEBUGGING_SYMBOLS') |
310 self._WarnUnimplemented('GCC_ENABLE_OBJC_EXCEPTIONS') | 314 self._WarnUnimplemented('GCC_ENABLE_OBJC_EXCEPTIONS') |
311 | 315 |
312 # TODO: This is exported correctly, but assigning to it is not supported. | 316 # TODO: This is exported correctly, but assigning to it is not supported. |
313 self._WarnUnimplemented('MACH_O_TYPE') | 317 self._WarnUnimplemented('MACH_O_TYPE') |
314 self._WarnUnimplemented('PRODUCT_TYPE') | 318 self._WarnUnimplemented('PRODUCT_TYPE') |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
347 cflags_c = [] | 351 cflags_c = [] |
348 self._Appendf(cflags_c, 'GCC_C_LANGUAGE_STANDARD', '-std=%s') | 352 self._Appendf(cflags_c, 'GCC_C_LANGUAGE_STANDARD', '-std=%s') |
349 cflags_c += self._Settings().get('OTHER_CFLAGS', []) | 353 cflags_c += self._Settings().get('OTHER_CFLAGS', []) |
350 self.configname = None | 354 self.configname = None |
351 return cflags_c | 355 return cflags_c |
352 | 356 |
353 def GetCflagsCC(self, configname): | 357 def GetCflagsCC(self, configname): |
354 """Returns flags that need to be added to .cc, and .mm compilations.""" | 358 """Returns flags that need to be added to .cc, and .mm compilations.""" |
355 self.configname = configname | 359 self.configname = configname |
356 cflags_cc = [] | 360 cflags_cc = [] |
361 | |
362 clang_cxx_language_standard = self._Settings().get( | |
363 'CLANG_CXX_LANGUAGE_STANDARD') | |
364 if clang_cxx_language_standard == 'c++0x': | |
365 cflags_cc.append('-std=c++11') | |
366 elif clang_cxx_language_standard == 'gnu++0x': | |
367 cflags_cc.append('-std=gnu++11') | |
368 elif clang_cxx_language_standard: | |
369 cflags_cc.append('-std=%s' % clang_cxx_language_standard) | |
370 | |
371 self._Appendf(cflags_cc, 'CLANG_CXX_LIBRARY', '-stdlib=%s') | |
372 | |
357 if self._Test('GCC_ENABLE_CPP_RTTI', 'NO', default='YES'): | 373 if self._Test('GCC_ENABLE_CPP_RTTI', 'NO', default='YES'): |
358 cflags_cc.append('-fno-rtti') | 374 cflags_cc.append('-fno-rtti') |
359 if self._Test('GCC_ENABLE_CPP_EXCEPTIONS', 'NO', default='YES'): | 375 if self._Test('GCC_ENABLE_CPP_EXCEPTIONS', 'NO', default='YES'): |
360 cflags_cc.append('-fno-exceptions') | 376 cflags_cc.append('-fno-exceptions') |
361 if self._Test('GCC_INLINES_ARE_PRIVATE_EXTERN', 'YES', default='NO'): | 377 if self._Test('GCC_INLINES_ARE_PRIVATE_EXTERN', 'YES', default='NO'): |
362 cflags_cc.append('-fvisibility-inlines-hidden') | 378 cflags_cc.append('-fvisibility-inlines-hidden') |
363 if self._Test('GCC_THREADSAFE_STATICS', 'NO', default='YES'): | 379 if self._Test('GCC_THREADSAFE_STATICS', 'NO', default='YES'): |
364 cflags_cc.append('-fno-threadsafe-statics') | 380 cflags_cc.append('-fno-threadsafe-statics') |
365 if self._Test('GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO', 'NO', default='YES'): | 381 if self._Test('GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO', 'NO', default='YES'): |
366 cflags_cc.append('-Wno-invalid-offsetof') | 382 cflags_cc.append('-Wno-invalid-offsetof') |
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
517 if self._Test('DEAD_CODE_STRIPPING', 'YES', default='NO'): | 533 if self._Test('DEAD_CODE_STRIPPING', 'YES', default='NO'): |
518 ldflags.append('-Wl,-dead_strip') | 534 ldflags.append('-Wl,-dead_strip') |
519 | 535 |
520 if self._Test('PREBINDING', 'YES', default='NO'): | 536 if self._Test('PREBINDING', 'YES', default='NO'): |
521 ldflags.append('-Wl,-prebind') | 537 ldflags.append('-Wl,-prebind') |
522 | 538 |
523 self._Appendf( | 539 self._Appendf( |
524 ldflags, 'DYLIB_COMPATIBILITY_VERSION', '-compatibility_version %s') | 540 ldflags, 'DYLIB_COMPATIBILITY_VERSION', '-compatibility_version %s') |
525 self._Appendf( | 541 self._Appendf( |
526 ldflags, 'DYLIB_CURRENT_VERSION', '-current_version %s') | 542 ldflags, 'DYLIB_CURRENT_VERSION', '-current_version %s') |
527 self._Appendf( | 543 |
528 ldflags, 'MACOSX_DEPLOYMENT_TARGET', '-mmacosx-version-min=%s') | 544 self._AppendPlatformVersionMinFlags(ldflags) |
545 | |
529 if 'SDKROOT' in self._Settings(): | 546 if 'SDKROOT' in self._Settings(): |
530 ldflags.append('-isysroot ' + self._SdkPath()) | 547 ldflags.append('-isysroot ' + self._SdkPath()) |
531 | 548 |
532 for library_path in self._Settings().get('LIBRARY_SEARCH_PATHS', []): | 549 for library_path in self._Settings().get('LIBRARY_SEARCH_PATHS', []): |
533 ldflags.append('-L' + gyp_to_build_path(library_path)) | 550 ldflags.append('-L' + gyp_to_build_path(library_path)) |
534 | 551 |
535 if 'ORDER_FILE' in self._Settings(): | 552 if 'ORDER_FILE' in self._Settings(): |
536 ldflags.append('-Wl,-order_file ' + | 553 ldflags.append('-Wl,-order_file ' + |
537 '-Wl,' + gyp_to_build_path( | 554 '-Wl,' + gyp_to_build_path( |
538 self._Settings()['ORDER_FILE'])) | 555 self._Settings()['ORDER_FILE'])) |
(...skipping 517 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1056 def GetSpecPostbuildCommands(spec, quiet=False): | 1073 def GetSpecPostbuildCommands(spec, quiet=False): |
1057 """Returns the list of postbuilds explicitly defined on |spec|, in a form | 1074 """Returns the list of postbuilds explicitly defined on |spec|, in a form |
1058 executable by a shell.""" | 1075 executable by a shell.""" |
1059 postbuilds = [] | 1076 postbuilds = [] |
1060 for postbuild in spec.get('postbuilds', []): | 1077 for postbuild in spec.get('postbuilds', []): |
1061 if not quiet: | 1078 if not quiet: |
1062 postbuilds.append('echo POSTBUILD\\(%s\\) %s' % ( | 1079 postbuilds.append('echo POSTBUILD\\(%s\\) %s' % ( |
1063 spec['target_name'], postbuild['postbuild_name'])) | 1080 spec['target_name'], postbuild['postbuild_name'])) |
1064 postbuilds.append(gyp.common.EncodePOSIXShellList(postbuild['action'])) | 1081 postbuilds.append(gyp.common.EncodePOSIXShellList(postbuild['action'])) |
1065 return postbuilds | 1082 return postbuilds |
OLD | NEW |