12f50e033f2bbdde2b168177750995e54a98a7375bradnelson@google.com# Copyright (c) 2012 Google Inc. All rights reserved. 2df8224662e615bd36cf8bebae8e58c017201f998sgk@chromium.org# Use of this source code is governed by a BSD-style license that can be 3df8224662e615bd36cf8bebae8e58c017201f998sgk@chromium.org# found in the LICENSE file. 4df8224662e615bd36cf8bebae8e58c017201f998sgk@chromium.org 52c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.orgimport filecmp 6f6d65a99233197a7b2e194d19be63ec85ff635d2mark@chromium.orgimport gyp.common 7f6d65a99233197a7b2e194d19be63ec85ff635d2mark@chromium.orgimport gyp.xcodeproj_file 8d49e6fec9631d1c51a1fe34ff9ee9dd60fa692b7justincohen@chromium.orgimport gyp.xcode_ninja 9a85d7de5129e37e558dc6e9c70ded4d300a71c5emark@chromium.orgimport errno 10a85d7de5129e37e558dc6e9c70ded4d300a71c5emark@chromium.orgimport os 11365cdc471e361b0bad9f27cbe6cde76abc56a343sbc@chromium.orgimport sys 12ff3d7702d6dba2fa383fb695f25fd8e4f151237ethomasvl@chromium.orgimport posixpath 131f3179fdaed9a35b6314adebc01675601cdcaf48mark@chromium.orgimport re 146105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.orgimport shutil 15d2b869f20e7b69f5de48a911d1984d9a3c3133eathomasvl@chromium.orgimport subprocess 162c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.orgimport tempfile 17a85d7de5129e37e558dc6e9c70ded4d300a71c5emark@chromium.org 18a85d7de5129e37e558dc6e9c70ded4d300a71c5emark@chromium.org 19581bb7d62b84353879c8aeb1950127644f669799mark@chromium.org# Project files generated by this module will use _intermediate_var as a 20581bb7d62b84353879c8aeb1950127644f669799mark@chromium.org# custom Xcode setting whose value is a DerivedSources-like directory that's 21581bb7d62b84353879c8aeb1950127644f669799mark@chromium.org# project-specific and configuration-specific. The normal choice, 22581bb7d62b84353879c8aeb1950127644f669799mark@chromium.org# DERIVED_FILE_DIR, is target-specific, which is thought to be too restrictive 23581bb7d62b84353879c8aeb1950127644f669799mark@chromium.org# as it is likely that multiple targets within a single project file will want 24581bb7d62b84353879c8aeb1950127644f669799mark@chromium.org# to access the same set of generated files. The other option, 25581bb7d62b84353879c8aeb1950127644f669799mark@chromium.org# PROJECT_DERIVED_FILE_DIR, is unsuitable because while it is project-specific, 26581bb7d62b84353879c8aeb1950127644f669799mark@chromium.org# it is not configuration-specific. INTERMEDIATE_DIR is defined as 27581bb7d62b84353879c8aeb1950127644f669799mark@chromium.org# $(PROJECT_DERIVED_FILE_DIR)/$(CONFIGURATION). 28581bb7d62b84353879c8aeb1950127644f669799mark@chromium.org_intermediate_var = 'INTERMEDIATE_DIR' 294ab0292c010f9aa9a35c57ca1413cf01cded7091mark@chromium.org 30debfd1043df75767ec9c2b91f9c0685faf13a669mark@chromium.org# SHARED_INTERMEDIATE_DIR is the same, except that it is shared among all 31debfd1043df75767ec9c2b91f9c0685faf13a669mark@chromium.org# targets that share the same BUILT_PRODUCTS_DIR. 32debfd1043df75767ec9c2b91f9c0685faf13a669mark@chromium.org_shared_intermediate_var = 'SHARED_INTERMEDIATE_DIR' 33debfd1043df75767ec9c2b91f9c0685faf13a669mark@chromium.org 346b4f0fecc1ebaf7f785ae4f1efbc193b49356500mark@chromium.org_library_search_paths_var = 'LIBRARY_SEARCH_PATHS' 356b4f0fecc1ebaf7f785ae4f1efbc193b49356500mark@chromium.org 361d4bf03af656e8f45c6ff3edd85af569acf710aamark@chromium.orggenerator_default_variables = { 376717b752a535daa9c401bc823c36397ca823ebd5mark@chromium.org 'EXECUTABLE_PREFIX': '', 386717b752a535daa9c401bc823c36397ca823ebd5mark@chromium.org 'EXECUTABLE_SUFFIX': '', 39d813fe1dcf7ab60f4ab729d1e32199598059b7bfbradnelson@google.com 'STATIC_LIB_PREFIX': 'lib', 40526e49cfa997c408b05d0155984b8a3e5def3bf4thomasvl@chromium.org 'SHARED_LIB_PREFIX': 'lib', 41aaf279794cd1028f98a2cb9a2be3bca794afcf35gspencer@google.com 'STATIC_LIB_SUFFIX': '.a', 42aaf279794cd1028f98a2cb9a2be3bca794afcf35gspencer@google.com 'SHARED_LIB_SUFFIX': '.dylib', 435ca0052c48077a11341c00a09bf37a0276416af9mark@chromium.org # INTERMEDIATE_DIR is a place for targets to build up intermediate products. 445ca0052c48077a11341c00a09bf37a0276416af9mark@chromium.org # It is specific to each build environment. It is only guaranteed to exist 45581bb7d62b84353879c8aeb1950127644f669799mark@chromium.org # and be constant within the context of a project, corresponding to a single 46581bb7d62b84353879c8aeb1950127644f669799mark@chromium.org # input file. Some build environments may allow their intermediate directory 47581bb7d62b84353879c8aeb1950127644f669799mark@chromium.org # to be shared on a wider scale, but this is not guaranteed. 48581bb7d62b84353879c8aeb1950127644f669799mark@chromium.org 'INTERMEDIATE_DIR': '$(%s)' % _intermediate_var, 491d4bf03af656e8f45c6ff3edd85af569acf710aamark@chromium.org 'OS': 'mac', 506717b752a535daa9c401bc823c36397ca823ebd5mark@chromium.org 'PRODUCT_DIR': '$(BUILT_PRODUCTS_DIR)', 51d813fe1dcf7ab60f4ab729d1e32199598059b7bfbradnelson@google.com 'LIB_DIR': '$(BUILT_PRODUCTS_DIR)', 526105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org 'RULE_INPUT_ROOT': '$(INPUT_FILE_BASE)', 536105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org 'RULE_INPUT_EXT': '$(INPUT_FILE_SUFFIX)', 546105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org 'RULE_INPUT_NAME': '$(INPUT_FILE_NAME)', 556105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org 'RULE_INPUT_PATH': '$(INPUT_FILE_PATH)', 56cdaa7e6d2e12c7d592265333396c6d1307632e22scr@chromium.org 'RULE_INPUT_DIRNAME': '$(INPUT_FILE_DIRNAME)', 57debfd1043df75767ec9c2b91f9c0685faf13a669mark@chromium.org 'SHARED_INTERMEDIATE_DIR': '$(%s)' % _shared_intermediate_var, 582c9e8675a425664fcc6fa1038c20dae9f2138af3bradnelson@google.com 'CONFIGURATION_NAME': '$(CONFIGURATION)', 591d4bf03af656e8f45c6ff3edd85af569acf710aamark@chromium.org} 6081f836d22e87477721a659f6edb72ff6113594c9mark@chromium.org 61565b6377c2de175e7177cc9fd3dcf957b37601d9thomasvl@chromium.org# The Xcode-specific sections that hold paths. 62a887771018238c16ecbc9ef66bbc38becce0f0fethomasvl@chromium.orggenerator_additional_path_sections = [ 63a887771018238c16ecbc9ef66bbc38becce0f0fethomasvl@chromium.org 'mac_bundle_resources', 64c5ff18b9991ffd97d70e296ff3e042c25ed9879dmark@chromium.org 'mac_framework_headers', 6529f8e2ce4be5527f72745c7345e7b48b090630ccmark@chromium.org 'mac_framework_private_headers', 66a887771018238c16ecbc9ef66bbc38becce0f0fethomasvl@chromium.org # 'mac_framework_dirs', input already handles _dirs endings. 67a887771018238c16ecbc9ef66bbc38becce0f0fethomasvl@chromium.org] 68a887771018238c16ecbc9ef66bbc38becce0f0fethomasvl@chromium.org 69565b6377c2de175e7177cc9fd3dcf957b37601d9thomasvl@chromium.org# The Xcode-specific keys that exist on targets and aren't moved down to 70a887771018238c16ecbc9ef66bbc38becce0f0fethomasvl@chromium.org# configurations. 71a887771018238c16ecbc9ef66bbc38becce0f0fethomasvl@chromium.orggenerator_additional_non_configuration_keys = [ 72f536bafefff908e7001e5634a5a75d29b1e2cab8sdefresne@chromium.org 'ios_app_extension', 73a887771018238c16ecbc9ef66bbc38becce0f0fethomasvl@chromium.org 'mac_bundle', 74a887771018238c16ecbc9ef66bbc38becce0f0fethomasvl@chromium.org 'mac_bundle_resources', 75c5ff18b9991ffd97d70e296ff3e042c25ed9879dmark@chromium.org 'mac_framework_headers', 7629f8e2ce4be5527f72745c7345e7b48b090630ccmark@chromium.org 'mac_framework_private_headers', 77c0b8cd7cd914fcda8d0ed8215f458886321bc848mark@chromium.org 'mac_xctest_bundle', 78a887771018238c16ecbc9ef66bbc38becce0f0fethomasvl@chromium.org 'xcode_create_dependents_test_runner', 79a887771018238c16ecbc9ef66bbc38becce0f0fethomasvl@chromium.org] 8081f836d22e87477721a659f6edb72ff6113594c9mark@chromium.org 816bfd4530db863baa22944fe9564d9f12586ab472thomasvl@chromium.org# We want to let any rules apply to files that are resources also. 826bfd4530db863baa22944fe9564d9f12586ab472thomasvl@chromium.orggenerator_extra_sources_for_rules = [ 836bfd4530db863baa22944fe9564d9f12586ab472thomasvl@chromium.org 'mac_bundle_resources', 84c5ff18b9991ffd97d70e296ff3e042c25ed9879dmark@chromium.org 'mac_framework_headers', 8529f8e2ce4be5527f72745c7345e7b48b090630ccmark@chromium.org 'mac_framework_private_headers', 866bfd4530db863baa22944fe9564d9f12586ab472thomasvl@chromium.org] 876bfd4530db863baa22944fe9564d9f12586ab472thomasvl@chromium.org 886b4f0fecc1ebaf7f785ae4f1efbc193b49356500mark@chromium.org# Xcode's standard set of library directories, which don't need to be duplicated 896b4f0fecc1ebaf7f785ae4f1efbc193b49356500mark@chromium.org# in LIBRARY_SEARCH_PATHS. This list is not exhaustive, but that's okay. 906b4f0fecc1ebaf7f785ae4f1efbc193b49356500mark@chromium.orgxcode_standard_library_dirs = frozenset([ 916b4f0fecc1ebaf7f785ae4f1efbc193b49356500mark@chromium.org '$(SDKROOT)/usr/lib', 926b4f0fecc1ebaf7f785ae4f1efbc193b49356500mark@chromium.org '$(SDKROOT)/usr/local/lib', 936b4f0fecc1ebaf7f785ae4f1efbc193b49356500mark@chromium.org]) 942fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org 952fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.orgdef CreateXCConfigurationList(configuration_names): 962fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org xccl = gyp.xcodeproj_file.XCConfigurationList({'buildConfigurations': []}) 974fcdd886cef5cfc58446e51b17b0b48f46ffd8a5mark@chromium.org if len(configuration_names) == 0: 984fcdd886cef5cfc58446e51b17b0b48f46ffd8a5mark@chromium.org configuration_names = ['Default'] 992fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org for configuration_name in configuration_names: 1002fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org xcbc = gyp.xcodeproj_file.XCBuildConfiguration({ 1012fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org 'name': configuration_name}) 1022fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org xccl.AppendProperty('buildConfigurations', xcbc) 1032fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org xccl.SetProperty('defaultConfigurationName', configuration_names[0]) 1042fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org return xccl 1052fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org 1062fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org 107a85d7de5129e37e558dc6e9c70ded4d300a71c5emark@chromium.orgclass XcodeProject(object): 10820db697424a38bd19aac48ae14dbf49e8fa6a4d3mark@chromium.org def __init__(self, gyp_path, path, build_file_dict): 10959bcf62c6030f720b82251b2464fcc632c0ad8bamark@chromium.org self.gyp_path = gyp_path 110475089d4d1a7ea54e6f25312d665da1e982d96d0mark@chromium.org self.path = path 111f6d65a99233197a7b2e194d19be63ec85ff635d2mark@chromium.org self.project = gyp.xcodeproj_file.PBXProject(path=path) 1129c88b549cd9f1773ed472daa27d6cbd8bc690b41sgk@chromium.org projectDirPath = gyp.common.RelativePath( 1139c88b549cd9f1773ed472daa27d6cbd8bc690b41sgk@chromium.org os.path.dirname(os.path.abspath(self.gyp_path)), 1149c88b549cd9f1773ed472daa27d6cbd8bc690b41sgk@chromium.org os.path.dirname(path) or '.') 1159c88b549cd9f1773ed472daa27d6cbd8bc690b41sgk@chromium.org self.project.SetProperty('projectDirPath', projectDirPath) 116f6d65a99233197a7b2e194d19be63ec85ff635d2mark@chromium.org self.project_file = \ 117f6d65a99233197a7b2e194d19be63ec85ff635d2mark@chromium.org gyp.xcodeproj_file.XCProjectFile({'rootObject': self.project}) 11820db697424a38bd19aac48ae14dbf49e8fa6a4d3mark@chromium.org self.build_file_dict = build_file_dict 119a85d7de5129e37e558dc6e9c70ded4d300a71c5emark@chromium.org 1206105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # TODO(mark): add destructor that cleans up self.path if created_dir is 121937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # True and things didn't complete successfully. Or do something even 122937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # better with "try"? 1236105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org self.created_dir = False 1246105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org try: 1259c88b549cd9f1773ed472daa27d6cbd8bc690b41sgk@chromium.org os.makedirs(self.path) 1266105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org self.created_dir = True 1276105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org except OSError, e: 1286105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org if e.errno != errno.EEXIST: 1296105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org raise 1306105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org 131366c66406ae02027430da1a30554810bcfc7f90ethomasvl@chromium.org def Finalize1(self, xcode_targets, serialize_all_tests): 13235d23def8cd397d452a491a0ac7aa8bc1720c7d9mark@chromium.org # Collect a list of all of the build configuration names used by the 13335d23def8cd397d452a491a0ac7aa8bc1720c7d9mark@chromium.org # various targets in the file. It is very heavily advised to keep each 13435d23def8cd397d452a491a0ac7aa8bc1720c7d9mark@chromium.org # target in an entire project (even across multiple project files) using 13535d23def8cd397d452a491a0ac7aa8bc1720c7d9mark@chromium.org # the same set of configuration names. 13635d23def8cd397d452a491a0ac7aa8bc1720c7d9mark@chromium.org configurations = [] 13735d23def8cd397d452a491a0ac7aa8bc1720c7d9mark@chromium.org for xct in self.project.GetProperty('targets'): 13835d23def8cd397d452a491a0ac7aa8bc1720c7d9mark@chromium.org xccl = xct.GetProperty('buildConfigurationList') 13935d23def8cd397d452a491a0ac7aa8bc1720c7d9mark@chromium.org xcbcs = xccl.GetProperty('buildConfigurations') 14035d23def8cd397d452a491a0ac7aa8bc1720c7d9mark@chromium.org for xcbc in xcbcs: 14135d23def8cd397d452a491a0ac7aa8bc1720c7d9mark@chromium.org name = xcbc.GetProperty('name') 14235d23def8cd397d452a491a0ac7aa8bc1720c7d9mark@chromium.org if name not in configurations: 14335d23def8cd397d452a491a0ac7aa8bc1720c7d9mark@chromium.org configurations.append(name) 14435d23def8cd397d452a491a0ac7aa8bc1720c7d9mark@chromium.org 14535d23def8cd397d452a491a0ac7aa8bc1720c7d9mark@chromium.org # Replace the XCConfigurationList attached to the PBXProject object with 14635d23def8cd397d452a491a0ac7aa8bc1720c7d9mark@chromium.org # a new one specifying all of the configuration names used by the various 14735d23def8cd397d452a491a0ac7aa8bc1720c7d9mark@chromium.org # targets. 148e8db48c52a4ed5df520e472193d54674b681e9d4gspencer@google.com try: 1492fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org xccl = CreateXCConfigurationList(configurations) 150e8db48c52a4ed5df520e472193d54674b681e9d4gspencer@google.com self.project.SetProperty('buildConfigurationList', xccl) 151e8db48c52a4ed5df520e472193d54674b681e9d4gspencer@google.com except: 152e8db48c52a4ed5df520e472193d54674b681e9d4gspencer@google.com sys.stderr.write("Problem with gyp file %s\n" % self.gyp_path) 153e8db48c52a4ed5df520e472193d54674b681e9d4gspencer@google.com raise 15435d23def8cd397d452a491a0ac7aa8bc1720c7d9mark@chromium.org 155581bb7d62b84353879c8aeb1950127644f669799mark@chromium.org # The need for this setting is explained above where _intermediate_var is 156581bb7d62b84353879c8aeb1950127644f669799mark@chromium.org # defined. The comments below about wanting to avoid project-wide build 157581bb7d62b84353879c8aeb1950127644f669799mark@chromium.org # settings apply here too, but this needs to be set on a project-wide basis 158581bb7d62b84353879c8aeb1950127644f669799mark@chromium.org # so that files relative to the _intermediate_var setting can be displayed 159581bb7d62b84353879c8aeb1950127644f669799mark@chromium.org # properly in the Xcode UI. 160581bb7d62b84353879c8aeb1950127644f669799mark@chromium.org # 161581bb7d62b84353879c8aeb1950127644f669799mark@chromium.org # Note that for configuration-relative files such as anything relative to 162581bb7d62b84353879c8aeb1950127644f669799mark@chromium.org # _intermediate_var, for the purposes of UI tree view display, Xcode will 163581bb7d62b84353879c8aeb1950127644f669799mark@chromium.org # only resolve the configuration name once, when the project file is 164581bb7d62b84353879c8aeb1950127644f669799mark@chromium.org # opened. If the active build configuration is changed, the project file 165581bb7d62b84353879c8aeb1950127644f669799mark@chromium.org # must be closed and reopened if it is desired for the tree view to update. 166581bb7d62b84353879c8aeb1950127644f669799mark@chromium.org # This is filed as Apple radar 6588391. 167581bb7d62b84353879c8aeb1950127644f669799mark@chromium.org xccl.SetBuildSetting(_intermediate_var, 1684ab0292c010f9aa9a35c57ca1413cf01cded7091mark@chromium.org '$(PROJECT_DERIVED_FILE_DIR)/$(CONFIGURATION)') 169debfd1043df75767ec9c2b91f9c0685faf13a669mark@chromium.org xccl.SetBuildSetting(_shared_intermediate_var, 170debfd1043df75767ec9c2b91f9c0685faf13a669mark@chromium.org '$(SYMROOT)/DerivedSources/$(CONFIGURATION)') 1714ab0292c010f9aa9a35c57ca1413cf01cded7091mark@chromium.org 172dd7f027a8e695320332cbcb91cae83daf59a0f46thomasvl@chromium.org # Set user-specified project-wide build settings and config files. This 173dd7f027a8e695320332cbcb91cae83daf59a0f46thomasvl@chromium.org # is intended to be used very sparingly. Really, almost everything should 174dd7f027a8e695320332cbcb91cae83daf59a0f46thomasvl@chromium.org # go into target-specific build settings sections. The project-wide 175dd7f027a8e695320332cbcb91cae83daf59a0f46thomasvl@chromium.org # settings are only intended to be used in cases where Xcode attempts to 176dd7f027a8e695320332cbcb91cae83daf59a0f46thomasvl@chromium.org # resolve variable references in a project context as opposed to a target 177dd7f027a8e695320332cbcb91cae83daf59a0f46thomasvl@chromium.org # context, such as when resolving sourceTree references while building up 178dd7f027a8e695320332cbcb91cae83daf59a0f46thomasvl@chromium.org # the tree tree view for UI display. 179dd7f027a8e695320332cbcb91cae83daf59a0f46thomasvl@chromium.org # Any values set globally are applied to all configurations, then any 180dd7f027a8e695320332cbcb91cae83daf59a0f46thomasvl@chromium.org # per-configuration values are applied. 18120db697424a38bd19aac48ae14dbf49e8fa6a4d3mark@chromium.org for xck, xcv in self.build_file_dict.get('xcode_settings', {}).iteritems(): 18220db697424a38bd19aac48ae14dbf49e8fa6a4d3mark@chromium.org xccl.SetBuildSetting(xck, xcv) 183dd7f027a8e695320332cbcb91cae83daf59a0f46thomasvl@chromium.org if 'xcode_config_file' in self.build_file_dict: 184dd7f027a8e695320332cbcb91cae83daf59a0f46thomasvl@chromium.org config_ref = self.project.AddOrGetFileInRootGroup( 185dd7f027a8e695320332cbcb91cae83daf59a0f46thomasvl@chromium.org self.build_file_dict['xcode_config_file']) 186dd7f027a8e695320332cbcb91cae83daf59a0f46thomasvl@chromium.org xccl.SetBaseConfiguration(config_ref) 187dd7f027a8e695320332cbcb91cae83daf59a0f46thomasvl@chromium.org build_file_configurations = self.build_file_dict.get('configurations', {}) 188dd7f027a8e695320332cbcb91cae83daf59a0f46thomasvl@chromium.org if build_file_configurations: 189dd7f027a8e695320332cbcb91cae83daf59a0f46thomasvl@chromium.org for config_name in configurations: 190dd7f027a8e695320332cbcb91cae83daf59a0f46thomasvl@chromium.org build_file_configuration_named = \ 191dd7f027a8e695320332cbcb91cae83daf59a0f46thomasvl@chromium.org build_file_configurations.get(config_name, {}) 192dd7f027a8e695320332cbcb91cae83daf59a0f46thomasvl@chromium.org if build_file_configuration_named: 193dd7f027a8e695320332cbcb91cae83daf59a0f46thomasvl@chromium.org xcc = xccl.ConfigurationNamed(config_name) 194dd7f027a8e695320332cbcb91cae83daf59a0f46thomasvl@chromium.org for xck, xcv in build_file_configuration_named.get('xcode_settings', 195dd7f027a8e695320332cbcb91cae83daf59a0f46thomasvl@chromium.org {}).iteritems(): 196dd7f027a8e695320332cbcb91cae83daf59a0f46thomasvl@chromium.org xcc.SetBuildSetting(xck, xcv) 197dd7f027a8e695320332cbcb91cae83daf59a0f46thomasvl@chromium.org if 'xcode_config_file' in build_file_configuration_named: 198dd7f027a8e695320332cbcb91cae83daf59a0f46thomasvl@chromium.org config_ref = self.project.AddOrGetFileInRootGroup( 199dd7f027a8e695320332cbcb91cae83daf59a0f46thomasvl@chromium.org build_file_configurations[config_name]['xcode_config_file']) 200dd7f027a8e695320332cbcb91cae83daf59a0f46thomasvl@chromium.org xcc.SetBaseConfiguration(config_ref) 20120db697424a38bd19aac48ae14dbf49e8fa6a4d3mark@chromium.org 20259bcf62c6030f720b82251b2464fcc632c0ad8bamark@chromium.org # Sort the targets based on how they appeared in the input. 20359bcf62c6030f720b82251b2464fcc632c0ad8bamark@chromium.org # TODO(mark): Like a lot of other things here, this assumes internal 20459bcf62c6030f720b82251b2464fcc632c0ad8bamark@chromium.org # knowledge of PBXProject - in this case, of its "targets" property. 2051cce7e1a85d52ab149e5bf4357d5b8352fec423amark@chromium.org 206ca91bab057f10704438b15410a4fa084e1e63110thomasvl@chromium.org # ordinary_targets are ordinary targets that are already in the project 207366c66406ae02027430da1a30554810bcfc7f90ethomasvl@chromium.org # file. run_test_targets are the targets that run unittests and should be 2082fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org # used for the Run All Tests target. support_targets are the action/rule 2092fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org # targets used by GYP file targets, just kept for the assert check. 210ca91bab057f10704438b15410a4fa084e1e63110thomasvl@chromium.org ordinary_targets = [] 211366c66406ae02027430da1a30554810bcfc7f90ethomasvl@chromium.org run_test_targets = [] 2122fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org support_targets = [] 2131cce7e1a85d52ab149e5bf4357d5b8352fec423amark@chromium.org 214ca91bab057f10704438b15410a4fa084e1e63110thomasvl@chromium.org # targets is full list of targets in the project. 2151cce7e1a85d52ab149e5bf4357d5b8352fec423amark@chromium.org targets = [] 2161cce7e1a85d52ab149e5bf4357d5b8352fec423amark@chromium.org 21783891a83bee6f9ab4a471d2ef74ce5c28fc81c64thomasvl@chromium.org # does the it define it's own "all"? 21883891a83bee6f9ab4a471d2ef74ce5c28fc81c64thomasvl@chromium.org has_custom_all = False 21983891a83bee6f9ab4a471d2ef74ce5c28fc81c64thomasvl@chromium.org 220ca91bab057f10704438b15410a4fa084e1e63110thomasvl@chromium.org # targets_for_all is the list of ordinary_targets that should be listed 2211cce7e1a85d52ab149e5bf4357d5b8352fec423amark@chromium.org # in this project's "All" target. It includes each non_runtest_target 2221cce7e1a85d52ab149e5bf4357d5b8352fec423amark@chromium.org # that does not have suppress_wildcard set. 2231cce7e1a85d52ab149e5bf4357d5b8352fec423amark@chromium.org targets_for_all = [] 2241cce7e1a85d52ab149e5bf4357d5b8352fec423amark@chromium.org 225c4e3156b31433b6ab7f607975c22cf466fcf0051thomasvl@chromium.org for target in self.build_file_dict['targets']: 22659bcf62c6030f720b82251b2464fcc632c0ad8bamark@chromium.org target_name = target['target_name'] 227821df584822a40838f71013666f9a9ccd3fa8fcfbradnelson@google.com toolset = target['toolset'] 228821df584822a40838f71013666f9a9ccd3fa8fcfbradnelson@google.com qualified_target = gyp.common.QualifiedTarget(self.gyp_path, target_name, 229821df584822a40838f71013666f9a9ccd3fa8fcfbradnelson@google.com toolset) 23059bcf62c6030f720b82251b2464fcc632c0ad8bamark@chromium.org xcode_target = xcode_targets[qualified_target] 23159bcf62c6030f720b82251b2464fcc632c0ad8bamark@chromium.org # Make sure that the target being added to the sorted list is already in 23259bcf62c6030f720b82251b2464fcc632c0ad8bamark@chromium.org # the unsorted list. 23359bcf62c6030f720b82251b2464fcc632c0ad8bamark@chromium.org assert xcode_target in self.project._properties['targets'] 2341cce7e1a85d52ab149e5bf4357d5b8352fec423amark@chromium.org targets.append(xcode_target) 235ca91bab057f10704438b15410a4fa084e1e63110thomasvl@chromium.org ordinary_targets.append(xcode_target) 2362fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org if xcode_target.support_target: 2372fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org support_targets.append(xcode_target.support_target) 2382fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org targets.append(xcode_target.support_target) 2391cce7e1a85d52ab149e5bf4357d5b8352fec423amark@chromium.org 2407136d45e1193828e00c026cb133289cc11cbcbf3ajwong@chromium.org if not int(target.get('suppress_wildcard', False)): 2411cce7e1a85d52ab149e5bf4357d5b8352fec423amark@chromium.org targets_for_all.append(xcode_target) 2429cc2a902440738e239ff7a860ec4c4c226a9c056mark@chromium.org 24383891a83bee6f9ab4a471d2ef74ce5c28fc81c64thomasvl@chromium.org if target_name.lower() == 'all': 24483891a83bee6f9ab4a471d2ef74ce5c28fc81c64thomasvl@chromium.org has_custom_all = True; 24583891a83bee6f9ab4a471d2ef74ce5c28fc81c64thomasvl@chromium.org 246731b434223c7b3cf8e03d1e40bb4ad513f786871thomasvl@chromium.org # If this target has a 'run_as' attribute, add its target to the 247731b434223c7b3cf8e03d1e40bb4ad513f786871thomasvl@chromium.org # targets, and add it to the test targets. 248731b434223c7b3cf8e03d1e40bb4ad513f786871thomasvl@chromium.org if target.get('run_as'): 249aaf279794cd1028f98a2cb9a2be3bca794afcf35gspencer@google.com # Make a target to run something. It should have one 250aaf279794cd1028f98a2cb9a2be3bca794afcf35gspencer@google.com # dependency, the parent xcode target. 2512fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org xccl = CreateXCConfigurationList(configurations) 2529cc2a902440738e239ff7a860ec4c4c226a9c056mark@chromium.org run_target = gyp.xcodeproj_file.PBXAggregateTarget({ 2532fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org 'name': 'Run ' + target_name, 2542fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org 'productName': xcode_target.GetProperty('productName'), 2552fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org 'buildConfigurationList': xccl, 2569cc2a902440738e239ff7a860ec4c4c226a9c056mark@chromium.org }, 2579cc2a902440738e239ff7a860ec4c4c226a9c056mark@chromium.org parent=self.project) 2589cc2a902440738e239ff7a860ec4c4c226a9c056mark@chromium.org run_target.AddDependency(xcode_target) 2599cc2a902440738e239ff7a860ec4c4c226a9c056mark@chromium.org 260731b434223c7b3cf8e03d1e40bb4ad513f786871thomasvl@chromium.org command = target['run_as'] 261aaf279794cd1028f98a2cb9a2be3bca794afcf35gspencer@google.com script = '' 262aaf279794cd1028f98a2cb9a2be3bca794afcf35gspencer@google.com if command.get('working_directory'): 263366c66406ae02027430da1a30554810bcfc7f90ethomasvl@chromium.org script = script + 'cd "%s"\n' % \ 264aaf279794cd1028f98a2cb9a2be3bca794afcf35gspencer@google.com gyp.xcodeproj_file.ConvertVariablesToShellSyntax( 265aaf279794cd1028f98a2cb9a2be3bca794afcf35gspencer@google.com command.get('working_directory')) 266aaf279794cd1028f98a2cb9a2be3bca794afcf35gspencer@google.com 267aaf279794cd1028f98a2cb9a2be3bca794afcf35gspencer@google.com if command.get('environment'): 268aaf279794cd1028f98a2cb9a2be3bca794afcf35gspencer@google.com script = script + "\n".join( 269aaf279794cd1028f98a2cb9a2be3bca794afcf35gspencer@google.com ['export %s="%s"' % 270aaf279794cd1028f98a2cb9a2be3bca794afcf35gspencer@google.com (key, gyp.xcodeproj_file.ConvertVariablesToShellSyntax(val)) 271aaf279794cd1028f98a2cb9a2be3bca794afcf35gspencer@google.com for (key, val) in command.get('environment').iteritems()]) + "\n" 272aaf279794cd1028f98a2cb9a2be3bca794afcf35gspencer@google.com 273366c66406ae02027430da1a30554810bcfc7f90ethomasvl@chromium.org # Some test end up using sockets, files on disk, etc. and can get 274366c66406ae02027430da1a30554810bcfc7f90ethomasvl@chromium.org # confused if more then one test runs at a time. The generator 275366c66406ae02027430da1a30554810bcfc7f90ethomasvl@chromium.org # flag 'xcode_serialize_all_test_runs' controls the forcing of all 276366c66406ae02027430da1a30554810bcfc7f90ethomasvl@chromium.org # tests serially. It defaults to True. To get serial runs this 277366c66406ae02027430da1a30554810bcfc7f90ethomasvl@chromium.org # little bit of python does the same as the linux flock utility to 278366c66406ae02027430da1a30554810bcfc7f90ethomasvl@chromium.org # make sure only one runs at a time. 279366c66406ae02027430da1a30554810bcfc7f90ethomasvl@chromium.org command_prefix = '' 280731b434223c7b3cf8e03d1e40bb4ad513f786871thomasvl@chromium.org if serialize_all_tests: 281366c66406ae02027430da1a30554810bcfc7f90ethomasvl@chromium.org command_prefix = \ 282366c66406ae02027430da1a30554810bcfc7f90ethomasvl@chromium.org"""python -c "import fcntl, subprocess, sys 283366c66406ae02027430da1a30554810bcfc7f90ethomasvl@chromium.orgfile = open('$TMPDIR/GYP_serialize_test_runs', 'a') 284366c66406ae02027430da1a30554810bcfc7f90ethomasvl@chromium.orgfcntl.flock(file.fileno(), fcntl.LOCK_EX) 285366c66406ae02027430da1a30554810bcfc7f90ethomasvl@chromium.orgsys.exit(subprocess.call(sys.argv[1:]))" """ 286366c66406ae02027430da1a30554810bcfc7f90ethomasvl@chromium.org 287aaf279794cd1028f98a2cb9a2be3bca794afcf35gspencer@google.com # If we were unable to exec for some reason, we want to exit 288aaf279794cd1028f98a2cb9a2be3bca794afcf35gspencer@google.com # with an error, and fixup variable references to be shell 289aaf279794cd1028f98a2cb9a2be3bca794afcf35gspencer@google.com # syntax instead of xcode syntax. 290366c66406ae02027430da1a30554810bcfc7f90ethomasvl@chromium.org script = script + 'exec ' + command_prefix + '%s\nexit 1\n' % \ 291aaf279794cd1028f98a2cb9a2be3bca794afcf35gspencer@google.com gyp.xcodeproj_file.ConvertVariablesToShellSyntax( 292aaf279794cd1028f98a2cb9a2be3bca794afcf35gspencer@google.com gyp.common.EncodePOSIXShellList(command.get('action'))) 293aaf279794cd1028f98a2cb9a2be3bca794afcf35gspencer@google.com 2949cc2a902440738e239ff7a860ec4c4c226a9c056mark@chromium.org ssbp = gyp.xcodeproj_file.PBXShellScriptBuildPhase({ 2959cc2a902440738e239ff7a860ec4c4c226a9c056mark@chromium.org 'shellScript': script, 2969cc2a902440738e239ff7a860ec4c4c226a9c056mark@chromium.org 'showEnvVarsInLog': 0, 2979cc2a902440738e239ff7a860ec4c4c226a9c056mark@chromium.org }) 2989cc2a902440738e239ff7a860ec4c4c226a9c056mark@chromium.org run_target.AppendProperty('buildPhases', ssbp) 2999cc2a902440738e239ff7a860ec4c4c226a9c056mark@chromium.org 300aaf279794cd1028f98a2cb9a2be3bca794afcf35gspencer@google.com # Add the run target to the project file. 3019cc2a902440738e239ff7a860ec4c4c226a9c056mark@chromium.org targets.append(run_target) 302731b434223c7b3cf8e03d1e40bb4ad513f786871thomasvl@chromium.org run_test_targets.append(run_target) 303731b434223c7b3cf8e03d1e40bb4ad513f786871thomasvl@chromium.org xcode_target.test_runner = run_target 304aaf279794cd1028f98a2cb9a2be3bca794afcf35gspencer@google.com 3059cc2a902440738e239ff7a860ec4c4c226a9c056mark@chromium.org 30659bcf62c6030f720b82251b2464fcc632c0ad8bamark@chromium.org # Make sure that the list of targets being replaced is the same length as 3079cc2a902440738e239ff7a860ec4c4c226a9c056mark@chromium.org # the one replacing it, but allow for the added test runner targets. 3082fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org assert len(self.project._properties['targets']) == \ 3092fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org len(ordinary_targets) + len(support_targets) 31059bcf62c6030f720b82251b2464fcc632c0ad8bamark@chromium.org 31159bcf62c6030f720b82251b2464fcc632c0ad8bamark@chromium.org self.project._properties['targets'] = targets 31259bcf62c6030f720b82251b2464fcc632c0ad8bamark@chromium.org 313581bb7d62b84353879c8aeb1950127644f669799mark@chromium.org # Get rid of unnecessary levels of depth in groups like the Source group. 3147ed07f90f08824e19760db1be06ad107ce6cf85bmark@chromium.org self.project.RootGroupsTakeOverOnlyChildren(True) 3157ed07f90f08824e19760db1be06ad107ce6cf85bmark@chromium.org 3166eeb5ee0a871fd52817b2034e539cb2d4e529c0amark@chromium.org # Sort the groups nicely. Do this after sorting the targets, because the 3176eeb5ee0a871fd52817b2034e539cb2d4e529c0amark@chromium.org # Products group is sorted based on the order of the targets. 3186eeb5ee0a871fd52817b2034e539cb2d4e529c0amark@chromium.org self.project.SortGroups() 3196eeb5ee0a871fd52817b2034e539cb2d4e529c0amark@chromium.org 32059bcf62c6030f720b82251b2464fcc632c0ad8bamark@chromium.org # Create an "All" target if there's more than one target in this project 32183891a83bee6f9ab4a471d2ef74ce5c28fc81c64thomasvl@chromium.org # file and the project didn't define its own "All" target. Put a generated 32283891a83bee6f9ab4a471d2ef74ce5c28fc81c64thomasvl@chromium.org # "All" target first so that people opening up the project for the first 32383891a83bee6f9ab4a471d2ef74ce5c28fc81c64thomasvl@chromium.org # time will build everything by default. 32483891a83bee6f9ab4a471d2ef74ce5c28fc81c64thomasvl@chromium.org if len(targets_for_all) > 1 and not has_custom_all: 3252fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org xccl = CreateXCConfigurationList(configurations) 32637964e1e03b108dd29cba4d9b87e05684b8bc504mark@chromium.org all_target = gyp.xcodeproj_file.PBXAggregateTarget( 32737964e1e03b108dd29cba4d9b87e05684b8bc504mark@chromium.org { 32837964e1e03b108dd29cba4d9b87e05684b8bc504mark@chromium.org 'buildConfigurationList': xccl, 32937964e1e03b108dd29cba4d9b87e05684b8bc504mark@chromium.org 'name': 'All', 33037964e1e03b108dd29cba4d9b87e05684b8bc504mark@chromium.org }, 33137964e1e03b108dd29cba4d9b87e05684b8bc504mark@chromium.org parent=self.project) 33237964e1e03b108dd29cba4d9b87e05684b8bc504mark@chromium.org 3331cce7e1a85d52ab149e5bf4357d5b8352fec423amark@chromium.org for target in targets_for_all: 33437964e1e03b108dd29cba4d9b87e05684b8bc504mark@chromium.org all_target.AddDependency(target) 33537964e1e03b108dd29cba4d9b87e05684b8bc504mark@chromium.org 33637964e1e03b108dd29cba4d9b87e05684b8bc504mark@chromium.org # TODO(mark): This is evil because it relies on internal knowledge of 33737964e1e03b108dd29cba4d9b87e05684b8bc504mark@chromium.org # PBXProject._properties. It's important to get the "All" target first, 33837964e1e03b108dd29cba4d9b87e05684b8bc504mark@chromium.org # though. 33937964e1e03b108dd29cba4d9b87e05684b8bc504mark@chromium.org self.project._properties['targets'].insert(0, all_target) 34037964e1e03b108dd29cba4d9b87e05684b8bc504mark@chromium.org 341366c66406ae02027430da1a30554810bcfc7f90ethomasvl@chromium.org # The same, but for run_test_targets. 342366c66406ae02027430da1a30554810bcfc7f90ethomasvl@chromium.org if len(run_test_targets) > 1: 3432fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org xccl = CreateXCConfigurationList(configurations) 3449cc2a902440738e239ff7a860ec4c4c226a9c056mark@chromium.org run_all_tests_target = gyp.xcodeproj_file.PBXAggregateTarget( 3459cc2a902440738e239ff7a860ec4c4c226a9c056mark@chromium.org { 3469cc2a902440738e239ff7a860ec4c4c226a9c056mark@chromium.org 'buildConfigurationList': xccl, 3479cc2a902440738e239ff7a860ec4c4c226a9c056mark@chromium.org 'name': 'Run All Tests', 3489cc2a902440738e239ff7a860ec4c4c226a9c056mark@chromium.org }, 3499cc2a902440738e239ff7a860ec4c4c226a9c056mark@chromium.org parent=self.project) 350366c66406ae02027430da1a30554810bcfc7f90ethomasvl@chromium.org for run_test_target in run_test_targets: 351366c66406ae02027430da1a30554810bcfc7f90ethomasvl@chromium.org run_all_tests_target.AddDependency(run_test_target) 3529cc2a902440738e239ff7a860ec4c4c226a9c056mark@chromium.org 3539cc2a902440738e239ff7a860ec4c4c226a9c056mark@chromium.org # Insert after the "All" target, which must exist if there is more than 3549cc2a902440738e239ff7a860ec4c4c226a9c056mark@chromium.org # one run_test_target. 3559cc2a902440738e239ff7a860ec4c4c226a9c056mark@chromium.org self.project._properties['targets'].insert(1, run_all_tests_target) 3569cc2a902440738e239ff7a860ec4c4c226a9c056mark@chromium.org 357c4e3156b31433b6ab7f607975c22cf466fcf0051thomasvl@chromium.org def Finalize2(self, xcode_targets, xcode_target_to_target_dict): 35859bcf62c6030f720b82251b2464fcc632c0ad8bamark@chromium.org # Finalize2 needs to happen in a separate step because the process of 35959bcf62c6030f720b82251b2464fcc632c0ad8bamark@chromium.org # updating references to other projects depends on the ordering of targets 36059bcf62c6030f720b82251b2464fcc632c0ad8bamark@chromium.org # within remote project files. Finalize1 is responsible for sorting duty, 36159bcf62c6030f720b82251b2464fcc632c0ad8bamark@chromium.org # and once all project files are sorted, Finalize2 can come in and update 36259bcf62c6030f720b82251b2464fcc632c0ad8bamark@chromium.org # these references. 36359bcf62c6030f720b82251b2464fcc632c0ad8bamark@chromium.org 36483891a83bee6f9ab4a471d2ef74ce5c28fc81c64thomasvl@chromium.org # To support making a "test runner" target that will run all the tests 36583891a83bee6f9ab4a471d2ef74ce5c28fc81c64thomasvl@chromium.org # that are direct dependents of any given target, we look for 36683891a83bee6f9ab4a471d2ef74ce5c28fc81c64thomasvl@chromium.org # xcode_create_dependents_test_runner being set on an Aggregate target, 367366c66406ae02027430da1a30554810bcfc7f90ethomasvl@chromium.org # and generate a second target that will run the tests runners found under 368366c66406ae02027430da1a30554810bcfc7f90ethomasvl@chromium.org # the marked target. 36983891a83bee6f9ab4a471d2ef74ce5c28fc81c64thomasvl@chromium.org for bf_tgt in self.build_file_dict['targets']: 370ca359a77c83539ba95896309f9aacc0ba6180868mark@chromium.org if int(bf_tgt.get('xcode_create_dependents_test_runner', 0)): 37183891a83bee6f9ab4a471d2ef74ce5c28fc81c64thomasvl@chromium.org tgt_name = bf_tgt['target_name'] 372821df584822a40838f71013666f9a9ccd3fa8fcfbradnelson@google.com toolset = bf_tgt['toolset'] 37383891a83bee6f9ab4a471d2ef74ce5c28fc81c64thomasvl@chromium.org qualified_target = gyp.common.QualifiedTarget(self.gyp_path, 374821df584822a40838f71013666f9a9ccd3fa8fcfbradnelson@google.com tgt_name, toolset) 37583891a83bee6f9ab4a471d2ef74ce5c28fc81c64thomasvl@chromium.org xcode_target = xcode_targets[qualified_target] 37683891a83bee6f9ab4a471d2ef74ce5c28fc81c64thomasvl@chromium.org if isinstance(xcode_target, gyp.xcodeproj_file.PBXAggregateTarget): 377366c66406ae02027430da1a30554810bcfc7f90ethomasvl@chromium.org # Collect all the run test targets. 378366c66406ae02027430da1a30554810bcfc7f90ethomasvl@chromium.org all_run_tests = [] 37983891a83bee6f9ab4a471d2ef74ce5c28fc81c64thomasvl@chromium.org pbxtds = xcode_target.GetProperty('dependencies') 38083891a83bee6f9ab4a471d2ef74ce5c28fc81c64thomasvl@chromium.org for pbxtd in pbxtds: 38183891a83bee6f9ab4a471d2ef74ce5c28fc81c64thomasvl@chromium.org pbxcip = pbxtd.GetProperty('targetProxy') 38283891a83bee6f9ab4a471d2ef74ce5c28fc81c64thomasvl@chromium.org dependency_xct = pbxcip.GetProperty('remoteGlobalIDString') 383731b434223c7b3cf8e03d1e40bb4ad513f786871thomasvl@chromium.org if hasattr(dependency_xct, 'test_runner'): 384366c66406ae02027430da1a30554810bcfc7f90ethomasvl@chromium.org all_run_tests.append(dependency_xct.test_runner) 38583891a83bee6f9ab4a471d2ef74ce5c28fc81c64thomasvl@chromium.org 386366c66406ae02027430da1a30554810bcfc7f90ethomasvl@chromium.org # Directly depend on all the runners as they depend on the target 387366c66406ae02027430da1a30554810bcfc7f90ethomasvl@chromium.org # that builds them. 388366c66406ae02027430da1a30554810bcfc7f90ethomasvl@chromium.org if len(all_run_tests) > 0: 38983891a83bee6f9ab4a471d2ef74ce5c28fc81c64thomasvl@chromium.org run_all_target = gyp.xcodeproj_file.PBXAggregateTarget({ 39083891a83bee6f9ab4a471d2ef74ce5c28fc81c64thomasvl@chromium.org 'name': 'Run %s Tests' % tgt_name, 39183891a83bee6f9ab4a471d2ef74ce5c28fc81c64thomasvl@chromium.org 'productName': tgt_name, 39283891a83bee6f9ab4a471d2ef74ce5c28fc81c64thomasvl@chromium.org }, 39383891a83bee6f9ab4a471d2ef74ce5c28fc81c64thomasvl@chromium.org parent=self.project) 394366c66406ae02027430da1a30554810bcfc7f90ethomasvl@chromium.org for run_test_target in all_run_tests: 395366c66406ae02027430da1a30554810bcfc7f90ethomasvl@chromium.org run_all_target.AddDependency(run_test_target) 39683891a83bee6f9ab4a471d2ef74ce5c28fc81c64thomasvl@chromium.org 39783891a83bee6f9ab4a471d2ef74ce5c28fc81c64thomasvl@chromium.org # Insert the test runner after the related target. 39883891a83bee6f9ab4a471d2ef74ce5c28fc81c64thomasvl@chromium.org idx = self.project._properties['targets'].index(xcode_target) 39983891a83bee6f9ab4a471d2ef74ce5c28fc81c64thomasvl@chromium.org self.project._properties['targets'].insert(idx + 1, run_all_target) 4000652ae9b86c7a3ede25695d8cc77d07ac448b40emark@chromium.org 40137964e1e03b108dd29cba4d9b87e05684b8bc504mark@chromium.org # Update all references to other projects, to make sure that the lists of 40237964e1e03b108dd29cba4d9b87e05684b8bc504mark@chromium.org # remote products are complete. Otherwise, Xcode will fill them in when 40337964e1e03b108dd29cba4d9b87e05684b8bc504mark@chromium.org # it opens the project file, which will result in unnecessary diffs. 40437964e1e03b108dd29cba4d9b87e05684b8bc504mark@chromium.org # TODO(mark): This is evil because it relies on internal knowledge of 40537964e1e03b108dd29cba4d9b87e05684b8bc504mark@chromium.org # PBXProject._other_pbxprojects. 40637964e1e03b108dd29cba4d9b87e05684b8bc504mark@chromium.org for other_pbxproject in self.project._other_pbxprojects.keys(): 40737964e1e03b108dd29cba4d9b87e05684b8bc504mark@chromium.org self.project.AddOrGetProjectReference(other_pbxproject) 40837964e1e03b108dd29cba4d9b87e05684b8bc504mark@chromium.org 40959bcf62c6030f720b82251b2464fcc632c0ad8bamark@chromium.org self.project.SortRemoteProductReferences() 41059bcf62c6030f720b82251b2464fcc632c0ad8bamark@chromium.org 41135d23def8cd397d452a491a0ac7aa8bc1720c7d9mark@chromium.org # Give everything an ID. 412a85d7de5129e37e558dc6e9c70ded4d300a71c5emark@chromium.org self.project_file.ComputeIDs() 413475089d4d1a7ea54e6f25312d665da1e982d96d0mark@chromium.org 4147d90ffc5c63c7af8181d8bb388fa684b257d3010mark@chromium.org # Make sure that no two objects in the project file have the same ID. If 4157d90ffc5c63c7af8181d8bb388fa684b257d3010mark@chromium.org # multiple objects wind up with the same ID, upon loading the file, Xcode 4167d90ffc5c63c7af8181d8bb388fa684b257d3010mark@chromium.org # will only recognize one object (the last one in the file?) and the 4177d90ffc5c63c7af8181d8bb388fa684b257d3010mark@chromium.org # results are unpredictable. 4187d90ffc5c63c7af8181d8bb388fa684b257d3010mark@chromium.org self.project_file.EnsureNoIDCollisions() 4197d90ffc5c63c7af8181d8bb388fa684b257d3010mark@chromium.org 420475089d4d1a7ea54e6f25312d665da1e982d96d0mark@chromium.org def Write(self): 4212c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org # Write the project file to a temporary location first. Xcode watches for 4222c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org # changes to the project file and presents a UI sheet offering to reload 4232c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org # the project when it does change. However, in some cases, especially when 4242c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org # multiple projects are open or when Xcode is busy, things don't work so 4252c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org # seamlessly. Sometimes, Xcode is able to detect that a project file has 4262c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org # changed but can't unload it because something else is referencing it. 4272c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org # To mitigate this problem, and to avoid even having Xcode present the UI 4282c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org # sheet when an open project is rewritten for inconsequential changes, the 4292c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org # project file is written to a temporary file in the xcodeproj directory 4302c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org # first. The new temporary file is then compared to the existing project 4312c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org # file, if any. If they differ, the new file replaces the old; otherwise, 4322c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org # the new project file is simply deleted. Xcode properly detects a file 4332c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org # being renamed over an open project file as a change and so it remains 4342c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org # able to present the "project file changed" sheet under this system. 4352c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org # Writing to a temporary file first also avoids the possible problem of 4362c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org # Xcode rereading an incomplete project file. 4372c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org (output_fd, new_pbxproj_path) = \ 4382c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org tempfile.mkstemp(suffix='.tmp', prefix='project.pbxproj.gyp.', 4392c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org dir=self.path) 4402c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org 4412c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org try: 442ff3d7702d6dba2fa383fb695f25fd8e4f151237ethomasvl@chromium.org output_file = os.fdopen(output_fd, 'wb') 4432c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org 4442c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org self.project_file.Print(output_file) 4452c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org output_file.close() 4462c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org 4472c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org pbxproj_path = os.path.join(self.path, 'project.pbxproj') 4482c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org 4492c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org same = False 4502c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org try: 4512c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org same = filecmp.cmp(pbxproj_path, new_pbxproj_path, False) 4522c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org except OSError, e: 4532c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org if e.errno != errno.ENOENT: 4542c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org raise 4552c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org 4562c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org if same: 4572c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org # The new file is identical to the old one, just get rid of the new 4582c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org # one. 4592c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org os.unlink(new_pbxproj_path) 4602c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org else: 4612c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org # The new file is different from the old one, or there is no old one. 4622c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org # Rename the new file to the permanent name. 4632c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org # 4642c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org # tempfile.mkstemp uses an overly restrictive mode, resulting in a 4652c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org # file that can only be read by the owner, regardless of the umask. 4662c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org # There's no reason to not respect the umask here, which means that 4672c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org # an extra hoop is required to fetch it and reset the new file's mode. 4682c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org # 4692c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org # No way to get the umask without setting a new one? Set a safe one 4702c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org # and then set it back to the old value. 4712c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org umask = os.umask(077) 4722c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org os.umask(umask) 4732c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org 4742c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org os.chmod(new_pbxproj_path, 0666 & ~umask) 4752c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org os.rename(new_pbxproj_path, pbxproj_path) 4762c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org 4772c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org except Exception: 4782c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org # Don't leave turds behind. In fact, if this code was responsible for 4792c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org # creating the xcodeproj directory, get rid of that too. 4802c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org os.unlink(new_pbxproj_path) 4816105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org if self.created_dir: 4826105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org shutil.rmtree(self.path, True) 4832c57244bcc526da737b23c01bce81b3a432018a6mark@chromium.org raise 484a85d7de5129e37e558dc6e9c70ded4d300a71c5emark@chromium.org 4854dc2b8955125d56199bdd40e5c59ea1e2df79884mark@chromium.org 4862f50e033f2bbdde2b168177750995e54a98a7375bradnelson@google.comdef AddSourceToTarget(source, type, pbxp, xct): 4879114a1c5625522ba4a26ba25a87d4c58a9fc8bb4mark@chromium.org # TODO(mark): Perhaps source_extensions and library_extensions can be made a 4889114a1c5625522ba4a26ba25a87d4c58a9fc8bb4mark@chromium.org # little bit fancier. 4891cb8ccdc9dadd727394f1b81ddcaa98b8ec34c69mark@chromium.org source_extensions = ['c', 'cc', 'cpp', 'cxx', 'm', 'mm', 's'] 4909114a1c5625522ba4a26ba25a87d4c58a9fc8bb4mark@chromium.org 4919114a1c5625522ba4a26ba25a87d4c58a9fc8bb4mark@chromium.org # .o is conceptually more of a "source" than a "library," but Xcode thinks 4929114a1c5625522ba4a26ba25a87d4c58a9fc8bb4mark@chromium.org # of "sources" as things to compile and "libraries" (or "frameworks") as 4939114a1c5625522ba4a26ba25a87d4c58a9fc8bb4mark@chromium.org # things to link with. Adding an object file to an Xcode target's frameworks 4949114a1c5625522ba4a26ba25a87d4c58a9fc8bb4mark@chromium.org # phase works properly. 4959114a1c5625522ba4a26ba25a87d4c58a9fc8bb4mark@chromium.org library_extensions = ['a', 'dylib', 'framework', 'o'] 4969114a1c5625522ba4a26ba25a87d4c58a9fc8bb4mark@chromium.org 497ff3d7702d6dba2fa383fb695f25fd8e4f151237ethomasvl@chromium.org basename = posixpath.basename(source) 498ff3d7702d6dba2fa383fb695f25fd8e4f151237ethomasvl@chromium.org (root, ext) = posixpath.splitext(basename) 499365cdc471e361b0bad9f27cbe6cde76abc56a343sbc@chromium.org if ext: 50093cb07e8ee315e78a0524c9a1bcf6fb69d874a6dbradnelson@google.com ext = ext[1:].lower() 501df568f04a7a521e316155e3bda790ad664b18cb1mark@chromium.org 5022f50e033f2bbdde2b168177750995e54a98a7375bradnelson@google.com if ext in source_extensions and type != 'none': 503df568f04a7a521e316155e3bda790ad664b18cb1mark@chromium.org xct.SourcesPhase().AddFile(source) 5042f50e033f2bbdde2b168177750995e54a98a7375bradnelson@google.com elif ext in library_extensions and type != 'none': 5059114a1c5625522ba4a26ba25a87d4c58a9fc8bb4mark@chromium.org xct.FrameworksPhase().AddFile(source) 506df568f04a7a521e316155e3bda790ad664b18cb1mark@chromium.org else: 5079114a1c5625522ba4a26ba25a87d4c58a9fc8bb4mark@chromium.org # Files that aren't added to a sources or frameworks build phase can still 5089114a1c5625522ba4a26ba25a87d4c58a9fc8bb4mark@chromium.org # go into the project file, just not as part of a build phase. 5096eb312d5514774feaeb85bce5217d46f65c99f4cmark@chromium.org pbxp.AddOrGetFileInRootGroup(source) 510a85d7de5129e37e558dc6e9c70ded4d300a71c5emark@chromium.org 5114dc2b8955125d56199bdd40e5c59ea1e2df79884mark@chromium.org 512df568f04a7a521e316155e3bda790ad664b18cb1mark@chromium.orgdef AddResourceToTarget(resource, pbxp, xct): 51341b29907da6ab12d5f831de9e324ceac2302bd50mark@chromium.org # TODO(mark): Combine with AddSourceToTarget above? Or just inline this call 51441b29907da6ab12d5f831de9e324ceac2302bd50mark@chromium.org # where it's used. 515df568f04a7a521e316155e3bda790ad664b18cb1mark@chromium.org xct.ResourcesPhase().AddFile(resource) 516df568f04a7a521e316155e3bda790ad664b18cb1mark@chromium.org 517df568f04a7a521e316155e3bda790ad664b18cb1mark@chromium.org 51829f8e2ce4be5527f72745c7345e7b48b090630ccmark@chromium.orgdef AddHeaderToTarget(header, pbxp, xct, is_public): 519c5ff18b9991ffd97d70e296ff3e042c25ed9879dmark@chromium.org # TODO(mark): Combine with AddSourceToTarget above? Or just inline this call 520c5ff18b9991ffd97d70e296ff3e042c25ed9879dmark@chromium.org # where it's used. 52129f8e2ce4be5527f72745c7345e7b48b090630ccmark@chromium.org settings = '{ATTRIBUTES = (%s, ); }' % ('Private', 'Public')[is_public] 52229f8e2ce4be5527f72745c7345e7b48b090630ccmark@chromium.org xct.HeadersPhase().AddFile(header, settings) 523c5ff18b9991ffd97d70e296ff3e042c25ed9879dmark@chromium.org 524c5ff18b9991ffd97d70e296ff3e042c25ed9879dmark@chromium.org 5256105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org_xcode_variable_re = re.compile('(\$\((.*?)\))') 5266105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.orgdef ExpandXcodeVariables(string, expansions): 5276105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org """Expands Xcode-style $(VARIABLES) in string per the expansions dict. 5284dc2b8955125d56199bdd40e5c59ea1e2df79884mark@chromium.org 5296105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org In some rare cases, it is appropriate to expand Xcode variables when a 5306105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org project file is generated. For any substring $(VAR) in string, if VAR is a 5316105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org key in the expansions dict, $(VAR) will be replaced with expansions[VAR]. 5326105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org Any $(VAR) substring in string for which VAR is not a key in the expansions 5336105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org dict will remain in the returned string. 5346105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org """ 535581bb7d62b84353879c8aeb1950127644f669799mark@chromium.org 5366105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org matches = _xcode_variable_re.findall(string) 537581bb7d62b84353879c8aeb1950127644f669799mark@chromium.org if matches == None: 538581bb7d62b84353879c8aeb1950127644f669799mark@chromium.org return string 5394dc2b8955125d56199bdd40e5c59ea1e2df79884mark@chromium.org 540581bb7d62b84353879c8aeb1950127644f669799mark@chromium.org matches.reverse() 541581bb7d62b84353879c8aeb1950127644f669799mark@chromium.org for match in matches: 542581bb7d62b84353879c8aeb1950127644f669799mark@chromium.org (to_replace, variable) = match 5436105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org if not variable in expansions: 544581bb7d62b84353879c8aeb1950127644f669799mark@chromium.org continue 5454dc2b8955125d56199bdd40e5c59ea1e2df79884mark@chromium.org 5466105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org replacement = expansions[variable] 5476105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org string = re.sub(re.escape(to_replace), replacement, string) 548581bb7d62b84353879c8aeb1950127644f669799mark@chromium.org 5496105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org return string 5504dc2b8955125d56199bdd40e5c59ea1e2df79884mark@chromium.org 5514dc2b8955125d56199bdd40e5c59ea1e2df79884mark@chromium.org 552c1acc4ec18f3c15510d36c85e2b9f737df375c32mark@chromium.org_xcode_define_re = re.compile(r'([\\\"\' ])') 553c00a2e4dd4094100a45651d8ef48e68df1453a5cmark@chromium.orgdef EscapeXcodeDefine(s): 554c00a2e4dd4094100a45651d8ef48e68df1453a5cmark@chromium.org """We must escape the defines that we give to XCode so that it knows not to 555c00a2e4dd4094100a45651d8ef48e68df1453a5cmark@chromium.org split on spaces and to respect backslash and quote literals. However, we 556c00a2e4dd4094100a45651d8ef48e68df1453a5cmark@chromium.org must not quote the define, or Xcode will incorrectly intepret variables 557c00a2e4dd4094100a45651d8ef48e68df1453a5cmark@chromium.org especially $(inherited).""" 558c1acc4ec18f3c15510d36c85e2b9f737df375c32mark@chromium.org return re.sub(_xcode_define_re, r'\\\1', s) 559e604b70501586dd3396720641f652da55e5930aftschmelcher@chromium.org 56008fc464f96f4d8664ae6549d9b7767e8d7fbfa6bsbc@chromium.org 56108fc464f96f4d8664ae6549d9b7767e8d7fbfa6bsbc@chromium.orgdef PerformBuild(data, configurations, params): 56208fc464f96f4d8664ae6549d9b7767e8d7fbfa6bsbc@chromium.org options = params['options'] 56308fc464f96f4d8664ae6549d9b7767e8d7fbfa6bsbc@chromium.org 56408fc464f96f4d8664ae6549d9b7767e8d7fbfa6bsbc@chromium.org for build_file, build_file_dict in data.iteritems(): 56508fc464f96f4d8664ae6549d9b7767e8d7fbfa6bsbc@chromium.org (build_file_root, build_file_ext) = os.path.splitext(build_file) 56608fc464f96f4d8664ae6549d9b7767e8d7fbfa6bsbc@chromium.org if build_file_ext != '.gyp': 56708fc464f96f4d8664ae6549d9b7767e8d7fbfa6bsbc@chromium.org continue 56808fc464f96f4d8664ae6549d9b7767e8d7fbfa6bsbc@chromium.org xcodeproj_path = build_file_root + options.suffix + '.xcodeproj' 56908fc464f96f4d8664ae6549d9b7767e8d7fbfa6bsbc@chromium.org if options.generator_output: 57008fc464f96f4d8664ae6549d9b7767e8d7fbfa6bsbc@chromium.org xcodeproj_path = os.path.join(options.generator_output, xcodeproj_path) 57108fc464f96f4d8664ae6549d9b7767e8d7fbfa6bsbc@chromium.org 57208fc464f96f4d8664ae6549d9b7767e8d7fbfa6bsbc@chromium.org for config in configurations: 57308fc464f96f4d8664ae6549d9b7767e8d7fbfa6bsbc@chromium.org arguments = ['xcodebuild', '-project', xcodeproj_path] 57408fc464f96f4d8664ae6549d9b7767e8d7fbfa6bsbc@chromium.org arguments += ['-configuration', config] 57508fc464f96f4d8664ae6549d9b7767e8d7fbfa6bsbc@chromium.org print "Building [%s]: %s" % (config, arguments) 57608fc464f96f4d8664ae6549d9b7767e8d7fbfa6bsbc@chromium.org subprocess.check_call(arguments) 57708fc464f96f4d8664ae6549d9b7767e8d7fbfa6bsbc@chromium.org 57808fc464f96f4d8664ae6549d9b7767e8d7fbfa6bsbc@chromium.org 5795c712802f5d54ec659ba0a1a9551ff53db110f41agl@chromium.orgdef GenerateOutput(target_list, target_dicts, data, params): 580d49e6fec9631d1c51a1fe34ff9ee9dd60fa692b7justincohen@chromium.org # Optionally configure each spec to use ninja as the external builder. 581d49e6fec9631d1c51a1fe34ff9ee9dd60fa692b7justincohen@chromium.org ninja_wrapper = params.get('flavor') == 'ninja' 582d49e6fec9631d1c51a1fe34ff9ee9dd60fa692b7justincohen@chromium.org if ninja_wrapper: 583d49e6fec9631d1c51a1fe34ff9ee9dd60fa692b7justincohen@chromium.org (target_list, target_dicts, data) = \ 584d49e6fec9631d1c51a1fe34ff9ee9dd60fa692b7justincohen@chromium.org gyp.xcode_ninja.CreateWrapper(target_list, target_dicts, data, params) 585d49e6fec9631d1c51a1fe34ff9ee9dd60fa692b7justincohen@chromium.org 5865c712802f5d54ec659ba0a1a9551ff53db110f41agl@chromium.org options = params['options'] 58762cccaf64f861d4a96f48c759ecbf476e9289bf1sgk@chromium.org generator_flags = params.get('generator_flags', {}) 58891ad8f838fbffd7d169788b5f5fe611a5ed1a872thomasvl@chromium.org parallel_builds = generator_flags.get('xcode_parallel_builds', True) 589366c66406ae02027430da1a30554810bcfc7f90ethomasvl@chromium.org serialize_all_tests = \ 590366c66406ae02027430da1a30554810bcfc7f90ethomasvl@chromium.org generator_flags.get('xcode_serialize_all_test_runs', True) 5912728d47070a86a333e111bd8807a132bd96d0cebthomasvl@chromium.org project_version = generator_flags.get('xcode_project_version', None) 592bc09226aa146f71557f6f22ed54fe21f9dd9ff6bthomasvl@chromium.org skip_excluded_files = \ 593bc09226aa146f71557f6f22ed54fe21f9dd9ff6bthomasvl@chromium.org not generator_flags.get('xcode_list_excluded_files', True) 594a85d7de5129e37e558dc6e9c70ded4d300a71c5emark@chromium.org xcode_projects = {} 595a85d7de5129e37e558dc6e9c70ded4d300a71c5emark@chromium.org for build_file, build_file_dict in data.iteritems(): 59640a44668e6a551919713f058d3c2002c3308efdcmark@chromium.org (build_file_root, build_file_ext) = os.path.splitext(build_file) 59740a44668e6a551919713f058d3c2002c3308efdcmark@chromium.org if build_file_ext != '.gyp': 598bf684ddd17bb8e6c0ad08d3d693875a8c070e20amark@chromium.org continue 5999c88b549cd9f1773ed472daa27d6cbd8bc690b41sgk@chromium.org xcodeproj_path = build_file_root + options.suffix + '.xcodeproj' 6009c88b549cd9f1773ed472daa27d6cbd8bc690b41sgk@chromium.org if options.generator_output: 6019c88b549cd9f1773ed472daa27d6cbd8bc690b41sgk@chromium.org xcodeproj_path = os.path.join(options.generator_output, xcodeproj_path) 6029c88b549cd9f1773ed472daa27d6cbd8bc690b41sgk@chromium.org xcp = XcodeProject(build_file, xcodeproj_path, build_file_dict) 6032bafdca3c85166060506e2b06d393f735eb35747mark@chromium.org xcode_projects[build_file] = xcp 6042bafdca3c85166060506e2b06d393f735eb35747mark@chromium.org pbxp = xcp.project 6052bafdca3c85166060506e2b06d393f735eb35747mark@chromium.org 60691ad8f838fbffd7d169788b5f5fe611a5ed1a872thomasvl@chromium.org if parallel_builds: 60791ad8f838fbffd7d169788b5f5fe611a5ed1a872thomasvl@chromium.org pbxp.SetProperty('attributes', 60891ad8f838fbffd7d169788b5f5fe611a5ed1a872thomasvl@chromium.org {'BuildIndependentTargetsInParallel': 'YES'}) 6092728d47070a86a333e111bd8807a132bd96d0cebthomasvl@chromium.org if project_version: 6102728d47070a86a333e111bd8807a132bd96d0cebthomasvl@chromium.org xcp.project_file.SetXcodeVersion(project_version) 61196f9b1cc4ed20262839d012a6ae854347a8f597bmark@chromium.org 612365cdc471e361b0bad9f27cbe6cde76abc56a343sbc@chromium.org # Add gyp/gypi files to project 613365cdc471e361b0bad9f27cbe6cde76abc56a343sbc@chromium.org if not generator_flags.get('standalone'): 614365cdc471e361b0bad9f27cbe6cde76abc56a343sbc@chromium.org main_group = pbxp.GetProperty('mainGroup') 615365cdc471e361b0bad9f27cbe6cde76abc56a343sbc@chromium.org build_group = gyp.xcodeproj_file.PBXGroup({'name': 'Build'}) 616365cdc471e361b0bad9f27cbe6cde76abc56a343sbc@chromium.org main_group.AppendChild(build_group) 617365cdc471e361b0bad9f27cbe6cde76abc56a343sbc@chromium.org for included_file in build_file_dict['included_files']: 618365cdc471e361b0bad9f27cbe6cde76abc56a343sbc@chromium.org build_group.AddOrGetFileByPath(included_file, False) 619a85d7de5129e37e558dc6e9c70ded4d300a71c5emark@chromium.org 620a85d7de5129e37e558dc6e9c70ded4d300a71c5emark@chromium.org xcode_targets = {} 621c4e3156b31433b6ab7f607975c22cf466fcf0051thomasvl@chromium.org xcode_target_to_target_dict = {} 6227868141eb6a6211aeada7ef186e2d14dfda05929mark@chromium.org for qualified_target in target_list: 623821df584822a40838f71013666f9a9ccd3fa8fcfbradnelson@google.com [build_file, target_name, toolset] = \ 624821df584822a40838f71013666f9a9ccd3fa8fcfbradnelson@google.com gyp.common.ParseQualifiedTarget(qualified_target) 625821df584822a40838f71013666f9a9ccd3fa8fcfbradnelson@google.com 6267868141eb6a6211aeada7ef186e2d14dfda05929mark@chromium.org spec = target_dicts[qualified_target] 627821df584822a40838f71013666f9a9ccd3fa8fcfbradnelson@google.com if spec['toolset'] != 'target': 628821df584822a40838f71013666f9a9ccd3fa8fcfbradnelson@google.com raise Exception( 629821df584822a40838f71013666f9a9ccd3fa8fcfbradnelson@google.com 'Multiple toolsets not supported in xcode build (target %s)' % 630821df584822a40838f71013666f9a9ccd3fa8fcfbradnelson@google.com qualified_target) 631fbafe02cf1d9050ef42e598af10eac66041ede3fmark@chromium.org configuration_names = [spec['default_configuration']] 632fbafe02cf1d9050ef42e598af10eac66041ede3fmark@chromium.org for configuration_name in sorted(spec['configurations'].keys()): 633fbafe02cf1d9050ef42e598af10eac66041ede3fmark@chromium.org if configuration_name not in configuration_names: 634fbafe02cf1d9050ef42e598af10eac66041ede3fmark@chromium.org configuration_names.append(configuration_name) 6359cc2a902440738e239ff7a860ec4c4c226a9c056mark@chromium.org xcp = xcode_projects[build_file] 6369cc2a902440738e239ff7a860ec4c4c226a9c056mark@chromium.org pbxp = xcp.project 637d7c127eea478f455f80c57a051cf43c0b9f1a605mark@chromium.org 638d7c127eea478f455f80c57a051cf43c0b9f1a605mark@chromium.org # Set up the configurations for the target according to the list of names 639d7c127eea478f455f80c57a051cf43c0b9f1a605mark@chromium.org # supplied. 6402fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org xccl = CreateXCConfigurationList(configuration_names) 641d7c127eea478f455f80c57a051cf43c0b9f1a605mark@chromium.org 642b80ff0aec12d63b3386cfd551ae450465295d29amark@chromium.org # Create an XCTarget subclass object for the target. The type with 643b80ff0aec12d63b3386cfd551ae450465295d29amark@chromium.org # "+bundle" appended will be used if the target has "mac_bundle" set. 644b80ff0aec12d63b3386cfd551ae450465295d29amark@chromium.org # loadable_modules not in a mac_bundle are mapped to 645b80ff0aec12d63b3386cfd551ae450465295d29amark@chromium.org # com.googlecode.gyp.xcode.bundle, a pseudo-type that xcode.py interprets 646b80ff0aec12d63b3386cfd551ae450465295d29amark@chromium.org # to create a single-file mh_bundle. 647d7c127eea478f455f80c57a051cf43c0b9f1a605mark@chromium.org _types = { 648f536bafefff908e7001e5634a5a75d29b1e2cab8sdefresne@chromium.org 'executable': 'com.apple.product-type.tool', 649f536bafefff908e7001e5634a5a75d29b1e2cab8sdefresne@chromium.org 'loadable_module': 'com.googlecode.gyp.xcode.bundle', 650f536bafefff908e7001e5634a5a75d29b1e2cab8sdefresne@chromium.org 'shared_library': 'com.apple.product-type.library.dynamic', 651f536bafefff908e7001e5634a5a75d29b1e2cab8sdefresne@chromium.org 'static_library': 'com.apple.product-type.library.static', 652f536bafefff908e7001e5634a5a75d29b1e2cab8sdefresne@chromium.org 'executable+bundle': 'com.apple.product-type.application', 653f536bafefff908e7001e5634a5a75d29b1e2cab8sdefresne@chromium.org 'loadable_module+bundle': 'com.apple.product-type.bundle', 654f536bafefff908e7001e5634a5a75d29b1e2cab8sdefresne@chromium.org 'loadable_module+xctest': 'com.apple.product-type.bundle.unit-test', 655f536bafefff908e7001e5634a5a75d29b1e2cab8sdefresne@chromium.org 'shared_library+bundle': 'com.apple.product-type.framework', 656f536bafefff908e7001e5634a5a75d29b1e2cab8sdefresne@chromium.org 'executable+extension+bundle': 'com.apple.product-type.app-extension', 657d7c127eea478f455f80c57a051cf43c0b9f1a605mark@chromium.org } 658d7c127eea478f455f80c57a051cf43c0b9f1a605mark@chromium.org 659d7c127eea478f455f80c57a051cf43c0b9f1a605mark@chromium.org target_properties = { 660d7c127eea478f455f80c57a051cf43c0b9f1a605mark@chromium.org 'buildConfigurationList': xccl, 661d7c127eea478f455f80c57a051cf43c0b9f1a605mark@chromium.org 'name': target_name, 662d7c127eea478f455f80c57a051cf43c0b9f1a605mark@chromium.org } 663d7c127eea478f455f80c57a051cf43c0b9f1a605mark@chromium.org 664d7c127eea478f455f80c57a051cf43c0b9f1a605mark@chromium.org type = spec['type'] 665c0b8cd7cd914fcda8d0ed8215f458886321bc848mark@chromium.org is_xctest = int(spec.get('mac_xctest_bundle', 0)) 666c0b8cd7cd914fcda8d0ed8215f458886321bc848mark@chromium.org is_bundle = int(spec.get('mac_bundle', 0)) or is_xctest 667f536bafefff908e7001e5634a5a75d29b1e2cab8sdefresne@chromium.org is_extension = int(spec.get('ios_app_extension', 0)) 668d7c127eea478f455f80c57a051cf43c0b9f1a605mark@chromium.org if type != 'none': 669ef6985cb69e329799d36b6629d4926fe5422ebeethomasvl@chromium.org type_bundle_key = type 670c0b8cd7cd914fcda8d0ed8215f458886321bc848mark@chromium.org if is_xctest: 671c0b8cd7cd914fcda8d0ed8215f458886321bc848mark@chromium.org type_bundle_key += '+xctest' 672c0b8cd7cd914fcda8d0ed8215f458886321bc848mark@chromium.org assert type == 'loadable_module', ( 673c0b8cd7cd914fcda8d0ed8215f458886321bc848mark@chromium.org 'mac_xctest_bundle targets must have type loadable_module ' 674c0b8cd7cd914fcda8d0ed8215f458886321bc848mark@chromium.org '(target %s)' % target_name) 675f536bafefff908e7001e5634a5a75d29b1e2cab8sdefresne@chromium.org elif is_extension: 676f536bafefff908e7001e5634a5a75d29b1e2cab8sdefresne@chromium.org assert is_bundle, ('ios_app_extension flag requires mac_bundle ' 677f536bafefff908e7001e5634a5a75d29b1e2cab8sdefresne@chromium.org '(target %s)' % target_name) 678f536bafefff908e7001e5634a5a75d29b1e2cab8sdefresne@chromium.org type_bundle_key += '+extension+bundle' 679c0b8cd7cd914fcda8d0ed8215f458886321bc848mark@chromium.org elif is_bundle: 680ef6985cb69e329799d36b6629d4926fe5422ebeethomasvl@chromium.org type_bundle_key += '+bundle' 681c0b8cd7cd914fcda8d0ed8215f458886321bc848mark@chromium.org 682d7c127eea478f455f80c57a051cf43c0b9f1a605mark@chromium.org xctarget_type = gyp.xcodeproj_file.PBXNativeTarget 68337a6f64232dc1dda7b605ee8dd39c33e2a4d24efgspencer@google.com try: 68437a6f64232dc1dda7b605ee8dd39c33e2a4d24efgspencer@google.com target_properties['productType'] = _types[type_bundle_key] 68537a6f64232dc1dda7b605ee8dd39c33e2a4d24efgspencer@google.com except KeyError, e: 68637a6f64232dc1dda7b605ee8dd39c33e2a4d24efgspencer@google.com gyp.common.ExceptionAppend(e, "-- unknown product type while " 68737a6f64232dc1dda7b605ee8dd39c33e2a4d24efgspencer@google.com "writing target %s" % target_name) 68837a6f64232dc1dda7b605ee8dd39c33e2a4d24efgspencer@google.com raise 689d7c127eea478f455f80c57a051cf43c0b9f1a605mark@chromium.org else: 690d7c127eea478f455f80c57a051cf43c0b9f1a605mark@chromium.org xctarget_type = gyp.xcodeproj_file.PBXAggregateTarget 69174091530de3012a744af0e64239155002e79cb0dthakis@chromium.org assert not is_bundle, ( 69274091530de3012a744af0e64239155002e79cb0dthakis@chromium.org 'mac_bundle targets cannot have type none (target "%s")' % 69374091530de3012a744af0e64239155002e79cb0dthakis@chromium.org target_name) 694c0b8cd7cd914fcda8d0ed8215f458886321bc848mark@chromium.org assert not is_xctest, ( 695c0b8cd7cd914fcda8d0ed8215f458886321bc848mark@chromium.org 'mac_xctest_bundle targets cannot have type none (target "%s")' % 696c0b8cd7cd914fcda8d0ed8215f458886321bc848mark@chromium.org target_name) 697d7c127eea478f455f80c57a051cf43c0b9f1a605mark@chromium.org 6984433ceec4876f3db8aa845a5fe08aa8e0bae2b1cbradnelson@google.com target_product_name = spec.get('product_name') 6994433ceec4876f3db8aa845a5fe08aa8e0bae2b1cbradnelson@google.com if target_product_name is not None: 7002fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org target_properties['productName'] = target_product_name 701d7c127eea478f455f80c57a051cf43c0b9f1a605mark@chromium.org 7024d6b2679749b27ad04944251692892c17e5aa5a7mark@chromium.org xct = xctarget_type(target_properties, parent=pbxp, 7034433ceec4876f3db8aa845a5fe08aa8e0bae2b1cbradnelson@google.com force_outdir=spec.get('product_dir'), 7044433ceec4876f3db8aa845a5fe08aa8e0bae2b1cbradnelson@google.com force_prefix=spec.get('product_prefix'), 7054433ceec4876f3db8aa845a5fe08aa8e0bae2b1cbradnelson@google.com force_extension=spec.get('product_extension')) 706d7c127eea478f455f80c57a051cf43c0b9f1a605mark@chromium.org pbxp.AppendProperty('targets', xct) 70735d23def8cd397d452a491a0ac7aa8bc1720c7d9mark@chromium.org xcode_targets[qualified_target] = xct 708c4e3156b31433b6ab7f607975c22cf466fcf0051thomasvl@chromium.org xcode_target_to_target_dict[xct] = spec 709d7c127eea478f455f80c57a051cf43c0b9f1a605mark@chromium.org 7102fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org spec_actions = spec.get('actions', []) 7112fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org spec_rules = spec.get('rules', []) 7122fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org 7132fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org # Xcode has some "issues" with checking dependencies for the "Compile 7142fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org # sources" step with any source files/headers generated by actions/rules. 7152fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org # To work around this, if a target is building anything directly (not 716e8934c9af66645f47884f59ac08eb19f40269a40thakis@chromium.org # type "none"), then a second target is used to run the GYP actions/rules 7172fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org # and is made a dependency of this target. This way the work is done 7182fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org # before the dependency checks for what should be recompiled. 7192fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org support_xct = None 720d49e6fec9631d1c51a1fe34ff9ee9dd60fa692b7justincohen@chromium.org # The Xcode "issues" don't affect xcode-ninja builds, since the dependency 721d49e6fec9631d1c51a1fe34ff9ee9dd60fa692b7justincohen@chromium.org # logic all happens in ninja. Don't bother creating the extra targets in 722d49e6fec9631d1c51a1fe34ff9ee9dd60fa692b7justincohen@chromium.org # that case. 723d49e6fec9631d1c51a1fe34ff9ee9dd60fa692b7justincohen@chromium.org if type != 'none' and (spec_actions or spec_rules) and not ninja_wrapper: 7242fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org support_xccl = CreateXCConfigurationList(configuration_names); 72507e497bd1c8f08e3d64b7b89b0d0fa741b3f0756mark@chromium.org support_target_suffix = generator_flags.get( 72607e497bd1c8f08e3d64b7b89b0d0fa741b3f0756mark@chromium.org 'support_target_suffix', ' Support') 7272fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org support_target_properties = { 7282fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org 'buildConfigurationList': support_xccl, 72907e497bd1c8f08e3d64b7b89b0d0fa741b3f0756mark@chromium.org 'name': target_name + support_target_suffix, 7302fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org } 7312fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org if target_product_name: 7322fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org support_target_properties['productName'] = \ 7332fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org target_product_name + ' Support' 7342fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org support_xct = \ 7352fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org gyp.xcodeproj_file.PBXAggregateTarget(support_target_properties, 7362fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org parent=pbxp) 7372fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org pbxp.AppendProperty('targets', support_xct) 7382fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org xct.AddDependency(support_xct) 7392fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org # Hang the support target off the main target so it can be tested/found 7402fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org # by the generator during Finalize. 7412fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org xct.support_target = support_xct 7422fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org 7434dc2b8955125d56199bdd40e5c59ea1e2df79884mark@chromium.org prebuild_index = 0 74435d23def8cd397d452a491a0ac7aa8bc1720c7d9mark@chromium.org 7456105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # Add custom shell script phases for "actions" sections. 7462fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org for action in spec_actions: 747cb6f53f225b902a519e22f391e3907ea4acd8968mark@chromium.org # There's no need to write anything into the script to ensure that the 748cb6f53f225b902a519e22f391e3907ea4acd8968mark@chromium.org # output directories already exist, because Xcode will look at the 749cb6f53f225b902a519e22f391e3907ea4acd8968mark@chromium.org # declared outputs and automatically ensure that they exist for us. 750debfd1043df75767ec9c2b91f9c0685faf13a669mark@chromium.org 75114cfb71e1e4c67b0779999a7cf4eb6be2e2c2ed1thomasvl@chromium.org # Do we have a message to print when this action runs? 75214cfb71e1e4c67b0779999a7cf4eb6be2e2c2ed1thomasvl@chromium.org message = action.get('message') 75314cfb71e1e4c67b0779999a7cf4eb6be2e2c2ed1thomasvl@chromium.org if message: 75414cfb71e1e4c67b0779999a7cf4eb6be2e2c2ed1thomasvl@chromium.org message = 'echo note: ' + gyp.common.EncodePOSIXShellArgument(message) 75514cfb71e1e4c67b0779999a7cf4eb6be2e2c2ed1thomasvl@chromium.org else: 75614cfb71e1e4c67b0779999a7cf4eb6be2e2c2ed1thomasvl@chromium.org message = '' 75714cfb71e1e4c67b0779999a7cf4eb6be2e2c2ed1thomasvl@chromium.org 7580be4796de4a43311feb4cca55725f685f5182581mark@chromium.org # Turn the list into a string that can be passed to a shell. 7590be4796de4a43311feb4cca55725f685f5182581mark@chromium.org action_string = gyp.common.EncodePOSIXShellList(action['action']) 7600be4796de4a43311feb4cca55725f685f5182581mark@chromium.org 7610c3d85d2650c028b4f8887615d1c1defbad9cec5mark@chromium.org # Convert Xcode-type variable references to sh-compatible environment 7620be4796de4a43311feb4cca55725f685f5182581mark@chromium.org # variable references. 763aaf279794cd1028f98a2cb9a2be3bca794afcf35gspencer@google.com message_sh = gyp.xcodeproj_file.ConvertVariablesToShellSyntax(message) 764aaf279794cd1028f98a2cb9a2be3bca794afcf35gspencer@google.com action_string_sh = gyp.xcodeproj_file.ConvertVariablesToShellSyntax( 765aaf279794cd1028f98a2cb9a2be3bca794afcf35gspencer@google.com action_string) 7660be4796de4a43311feb4cca55725f685f5182581mark@chromium.org 76714cfb71e1e4c67b0779999a7cf4eb6be2e2c2ed1thomasvl@chromium.org script = '' 76814cfb71e1e4c67b0779999a7cf4eb6be2e2c2ed1thomasvl@chromium.org # Include the optional message 76914cfb71e1e4c67b0779999a7cf4eb6be2e2c2ed1thomasvl@chromium.org if message_sh: 77014cfb71e1e4c67b0779999a7cf4eb6be2e2c2ed1thomasvl@chromium.org script += message_sh + '\n' 7710be4796de4a43311feb4cca55725f685f5182581mark@chromium.org # Be sure the script runs in exec, and that if exec fails, the script 7720be4796de4a43311feb4cca55725f685f5182581mark@chromium.org # exits signalling an error. 77314cfb71e1e4c67b0779999a7cf4eb6be2e2c2ed1thomasvl@chromium.org script += 'exec ' + action_string_sh + '\nexit 1\n' 7740c3d85d2650c028b4f8887615d1c1defbad9cec5mark@chromium.org ssbp = gyp.xcodeproj_file.PBXShellScriptBuildPhase({ 7750c3d85d2650c028b4f8887615d1c1defbad9cec5mark@chromium.org 'inputPaths': action['inputs'], 7760c3d85d2650c028b4f8887615d1c1defbad9cec5mark@chromium.org 'name': 'Action "' + action['action_name'] + '"', 7770c3d85d2650c028b4f8887615d1c1defbad9cec5mark@chromium.org 'outputPaths': action['outputs'], 7780c3d85d2650c028b4f8887615d1c1defbad9cec5mark@chromium.org 'shellScript': script, 7790c3d85d2650c028b4f8887615d1c1defbad9cec5mark@chromium.org 'showEnvVarsInLog': 0, 7800c3d85d2650c028b4f8887615d1c1defbad9cec5mark@chromium.org }) 7810c3d85d2650c028b4f8887615d1c1defbad9cec5mark@chromium.org 7822fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org if support_xct: 7832fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org support_xct.AppendProperty('buildPhases', ssbp) 7842fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org else: 7852fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org # TODO(mark): this assumes too much knowledge of the internals of 7862fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org # xcodeproj_file; some of these smarts should move into xcodeproj_file 7872fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org # itself. 7882fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org xct._properties['buildPhases'].insert(prebuild_index, ssbp) 7892fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org prebuild_index = prebuild_index + 1 7900c3d85d2650c028b4f8887615d1c1defbad9cec5mark@chromium.org 7913a3f1240c04c2a5120052b87646514f562bd88ecmark@chromium.org # TODO(mark): Should verify that at most one of these is specified. 7927136d45e1193828e00c026cb133289cc11cbcbf3ajwong@chromium.org if int(action.get('process_outputs_as_sources', False)): 7930c3d85d2650c028b4f8887615d1c1defbad9cec5mark@chromium.org for output in action['outputs']: 7942f50e033f2bbdde2b168177750995e54a98a7375bradnelson@google.com AddSourceToTarget(output, type, pbxp, xct) 7950c3d85d2650c028b4f8887615d1c1defbad9cec5mark@chromium.org 7967136d45e1193828e00c026cb133289cc11cbcbf3ajwong@chromium.org if int(action.get('process_outputs_as_mac_bundle_resources', False)): 7973a3f1240c04c2a5120052b87646514f562bd88ecmark@chromium.org for output in action['outputs']: 7983a3f1240c04c2a5120052b87646514f562bd88ecmark@chromium.org AddResourceToTarget(output, pbxp, xct) 7993a3f1240c04c2a5120052b87646514f562bd88ecmark@chromium.org 8006bfd4530db863baa22944fe9564d9f12586ab472thomasvl@chromium.org # tgt_mac_bundle_resources holds the list of bundle resources so 8016bfd4530db863baa22944fe9564d9f12586ab472thomasvl@chromium.org # the rule processing can check against it. 802ca359a77c83539ba95896309f9aacc0ba6180868mark@chromium.org if is_bundle: 8036bfd4530db863baa22944fe9564d9f12586ab472thomasvl@chromium.org tgt_mac_bundle_resources = spec.get('mac_bundle_resources', []) 8046bfd4530db863baa22944fe9564d9f12586ab472thomasvl@chromium.org else: 8056bfd4530db863baa22944fe9564d9f12586ab472thomasvl@chromium.org tgt_mac_bundle_resources = [] 8066bfd4530db863baa22944fe9564d9f12586ab472thomasvl@chromium.org 8076105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # Add custom shell script phases driving "make" for "rules" sections. 8086105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # 8096105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # Xcode's built-in rule support is almost powerful enough to use directly, 8106105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # but there are a few significant deficiencies that render them unusable. 8116105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # There are workarounds for some of its inadequacies, but in aggregate, 8126105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # the workarounds added complexity to the generator, and some workarounds 8136105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # actually require input files to be crafted more carefully than I'd like. 8146105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # Consequently, until Xcode rules are made more capable, "rules" input 8156105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # sections will be handled in Xcode output by shell script build phases 8166105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # performed prior to the compilation phase. 8176105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # 8186105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # The following problems with Xcode rules were found. The numbers are 8196105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # Apple radar IDs. I hope that these shortcomings are addressed, I really 8206105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # liked having the rules handled directly in Xcode during the period that 8216105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # I was prototyping this. 8226105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # 8236105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # 6588600 Xcode compiles custom script rule outputs too soon, compilation 8246105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # fails. This occurs when rule outputs from distinct inputs are 8256105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # interdependent. The only workaround is to put rules and their 8266105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # inputs in a separate target from the one that compiles the rule 8276105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # outputs. This requires input file cooperation and it means that 8286105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # process_outputs_as_sources is unusable. 8296105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # 6584932 Need to declare that custom rule outputs should be excluded from 8306105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # compilation. A possible workaround is to lie to Xcode about a 8316105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # rule's output, giving it a dummy file it doesn't know how to 8326105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # compile. The rule action script would need to touch the dummy. 8336105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # 6584839 I need a way to declare additional inputs to a custom rule. 8346105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # A possible workaround is a shell script phase prior to 8356105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # compilation that touches a rule's primary input files if any 8366105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # would-be additional inputs are newer than the output. Modifying 8376105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # the source tree - even just modification times - feels dirty. 8386105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # 6564240 Xcode "custom script" build rules always dump all environment 8396105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # variables. This is a low-prioroty problem and is not a 8406105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # show-stopper. 8416105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org rules_by_ext = {} 8422fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org for rule in spec_rules: 8436105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org rules_by_ext[rule['extension']] = rule 844937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org 845937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # First, some definitions: 846937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # 847937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # A "rule source" is a file that was listed in a target's "sources" 848937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # list and will have a rule applied to it on the basis of matching the 849937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # rule's "extensions" attribute. Rule sources are direct inputs to 850937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # rules. 851937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # 852937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # Rule definitions may specify additional inputs in their "inputs" 853937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # attribute. These additional inputs are used for dependency tracking 854937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # purposes. 855937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # 856937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # A "concrete output" is a rule output with input-dependent variables 857937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # resolved. For example, given a rule with: 858937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # 'extension': 'ext', 'outputs': ['$(INPUT_FILE_BASE).cc'], 859937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # if the target's "sources" list contained "one.ext" and "two.ext", 860937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # the "concrete output" for rule input "two.ext" would be "two.cc". If 861937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # a rule specifies multiple outputs, each input file that the rule is 862937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # applied to will have the same number of concrete outputs. 863937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # 864937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # If any concrete outputs are outdated or missing relative to their 865937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # corresponding rule_source or to any specified additional input, the 866937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # rule action must be performed to generate the concrete outputs. 867937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org 868937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # concrete_outputs_by_rule_source will have an item at the same index 869937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # as the rule['rule_sources'] that it corresponds to. Each item is a 870937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # list of all of the concrete outputs for the rule_source. 8716105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org concrete_outputs_by_rule_source = [] 872937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org 873937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # concrete_outputs_all is a flat list of all concrete outputs that this 874937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # rule is able to produce, given the known set of input files 875937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # (rule_sources) that apply to it. 8766105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org concrete_outputs_all = [] 877937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org 87814cfb71e1e4c67b0779999a7cf4eb6be2e2c2ed1thomasvl@chromium.org # messages & actions are keyed by the same indices as rule['rule_sources'] 87914cfb71e1e4c67b0779999a7cf4eb6be2e2c2ed1thomasvl@chromium.org # and concrete_outputs_by_rule_source. They contain the message and 88014cfb71e1e4c67b0779999a7cf4eb6be2e2c2ed1thomasvl@chromium.org # action to perform after resolving input-dependent variables. The 88114cfb71e1e4c67b0779999a7cf4eb6be2e2c2ed1thomasvl@chromium.org # message is optional, in which case None is stored for each rule source. 88214cfb71e1e4c67b0779999a7cf4eb6be2e2c2ed1thomasvl@chromium.org messages = [] 8836105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org actions = [] 8846105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org 8856105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org for rule_source in rule.get('rule_sources', []): 886cdaa7e6d2e12c7d592265333396c6d1307632e22scr@chromium.org rule_source_dirname, rule_source_basename = \ 887cdaa7e6d2e12c7d592265333396c6d1307632e22scr@chromium.org posixpath.split(rule_source) 8886105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org (rule_source_root, rule_source_ext) = \ 889ff3d7702d6dba2fa383fb695f25fd8e4f151237ethomasvl@chromium.org posixpath.splitext(rule_source_basename) 8906105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org 891937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # These are the same variable names that Xcode uses for its own native 892937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # rule support. Because Xcode's rule engine is not being used, they 893937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # need to be expanded as they are written to the makefile. 8946105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org rule_input_dict = { 8956105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org 'INPUT_FILE_BASE': rule_source_root, 8966105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org 'INPUT_FILE_SUFFIX': rule_source_ext, 8976105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org 'INPUT_FILE_NAME': rule_source_basename, 8986105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org 'INPUT_FILE_PATH': rule_source, 899cdaa7e6d2e12c7d592265333396c6d1307632e22scr@chromium.org 'INPUT_FILE_DIRNAME': rule_source_dirname, 9006105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org } 9016105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org 9026105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org concrete_outputs_for_this_rule_source = [] 9036105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org for output in rule.get('outputs', []): 904937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # Fortunately, Xcode and make both use $(VAR) format for their 905937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # variables, so the expansion is the only transformation necessary. 906937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # Any remaning $(VAR)-type variables in the string can be given 907937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # directly to make, which will pick up the correct settings from 908937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # what Xcode puts into the environment. 9096105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org concrete_output = ExpandXcodeVariables(output, rule_input_dict) 9106105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org concrete_outputs_for_this_rule_source.append(concrete_output) 9116105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org 912937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # Add all concrete outputs to the project. 9136105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org pbxp.AddOrGetFileInRootGroup(concrete_output) 9146105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org 9156105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org concrete_outputs_by_rule_source.append( \ 9166105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org concrete_outputs_for_this_rule_source) 9176105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org concrete_outputs_all.extend(concrete_outputs_for_this_rule_source) 9183a3f1240c04c2a5120052b87646514f562bd88ecmark@chromium.org 9193a3f1240c04c2a5120052b87646514f562bd88ecmark@chromium.org # TODO(mark): Should verify that at most one of these is specified. 920ca359a77c83539ba95896309f9aacc0ba6180868mark@chromium.org if int(rule.get('process_outputs_as_sources', False)): 9216105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org for output in concrete_outputs_for_this_rule_source: 9222f50e033f2bbdde2b168177750995e54a98a7375bradnelson@google.com AddSourceToTarget(output, type, pbxp, xct) 9236105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org 9246bfd4530db863baa22944fe9564d9f12586ab472thomasvl@chromium.org # If the file came from the mac_bundle_resources list or if the rule 9256bfd4530db863baa22944fe9564d9f12586ab472thomasvl@chromium.org # is marked to process outputs as bundle resource, do so. 9266bfd4530db863baa22944fe9564d9f12586ab472thomasvl@chromium.org was_mac_bundle_resource = rule_source in tgt_mac_bundle_resources 9276bfd4530db863baa22944fe9564d9f12586ab472thomasvl@chromium.org if was_mac_bundle_resource or \ 928ca359a77c83539ba95896309f9aacc0ba6180868mark@chromium.org int(rule.get('process_outputs_as_mac_bundle_resources', False)): 9293a3f1240c04c2a5120052b87646514f562bd88ecmark@chromium.org for output in concrete_outputs_for_this_rule_source: 9303a3f1240c04c2a5120052b87646514f562bd88ecmark@chromium.org AddResourceToTarget(output, pbxp, xct) 9313a3f1240c04c2a5120052b87646514f562bd88ecmark@chromium.org 93214cfb71e1e4c67b0779999a7cf4eb6be2e2c2ed1thomasvl@chromium.org # Do we have a message to print when this rule runs? 93314cfb71e1e4c67b0779999a7cf4eb6be2e2c2ed1thomasvl@chromium.org message = rule.get('message') 93414cfb71e1e4c67b0779999a7cf4eb6be2e2c2ed1thomasvl@chromium.org if message: 93514cfb71e1e4c67b0779999a7cf4eb6be2e2c2ed1thomasvl@chromium.org message = gyp.common.EncodePOSIXShellArgument(message) 936ec670df7ec53a964ae4a2b9f39265598c286c0d4thomasvl@chromium.org message = ExpandXcodeVariables(message, rule_input_dict) 93714cfb71e1e4c67b0779999a7cf4eb6be2e2c2ed1thomasvl@chromium.org messages.append(message) 93814cfb71e1e4c67b0779999a7cf4eb6be2e2c2ed1thomasvl@chromium.org 9390be4796de4a43311feb4cca55725f685f5182581mark@chromium.org # Turn the list into a string that can be passed to a shell. 9400be4796de4a43311feb4cca55725f685f5182581mark@chromium.org action_string = gyp.common.EncodePOSIXShellList(rule['action']) 9410be4796de4a43311feb4cca55725f685f5182581mark@chromium.org 9420be4796de4a43311feb4cca55725f685f5182581mark@chromium.org action = ExpandXcodeVariables(action_string, rule_input_dict) 9436105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org actions.append(action) 9446105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org 9456105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org if len(concrete_outputs_all) > 0: 9466105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # TODO(mark): There's a possibilty for collision here. Consider 9476105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # target "t" rule "A_r" and target "t_A" rule "r". 948e7771c0907843e73a75222a2bde44c0cdfe3f6a7thakis@chromium.org makefile_name = '%s.make' % re.sub( 949e7771c0907843e73a75222a2bde44c0cdfe3f6a7thakis@chromium.org '[^a-zA-Z0-9_]', '_' , '%s_%s' % (target_name, rule['rule_name'])) 9506105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org makefile_path = os.path.join(xcode_projects[build_file].path, 9516105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org makefile_name) 952937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # TODO(mark): try/close? Write to a temporary file and swap it only 953937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # if it's got changes? 954ff3d7702d6dba2fa383fb695f25fd8e4f151237ethomasvl@chromium.org makefile = open(makefile_path, 'wb') 9556105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org 956937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # make will build the first target in the makefile by default. By 957937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # convention, it's called "all". List all (or at least one) 958937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # concrete output for each rule source as a prerequisite of the "all" 959937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # target. 9606105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org makefile.write('all: \\\n') 9616105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org for concrete_output_index in \ 9626105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org xrange(0, len(concrete_outputs_by_rule_source)): 9636105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # Only list the first (index [0]) concrete output of each input 9646105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # in the "all" target. Otherwise, a parallel make (-j > 1) would 9656105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # attempt to process each input multiple times simultaneously. 9666105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # Otherwise, "all" could just contain the entire list of 9676105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # concrete_outputs_all. 9686105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org concrete_output = \ 9696105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org concrete_outputs_by_rule_source[concrete_output_index][0] 9706105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org if concrete_output_index == len(concrete_outputs_by_rule_source) - 1: 9716105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org eol = '' 9726105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org else: 9736105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org eol = ' \\' 9746105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org makefile.write(' %s%s\n' % (concrete_output, eol)) 9756105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org 97614cfb71e1e4c67b0779999a7cf4eb6be2e2c2ed1thomasvl@chromium.org for (rule_source, concrete_outputs, message, action) in \ 97714cfb71e1e4c67b0779999a7cf4eb6be2e2c2ed1thomasvl@chromium.org zip(rule['rule_sources'], concrete_outputs_by_rule_source, 97814cfb71e1e4c67b0779999a7cf4eb6be2e2c2ed1thomasvl@chromium.org messages, actions): 979937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org makefile.write('\n') 980937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org 981937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # Add a rule that declares it can build each concrete output of a 982cb6f53f225b902a519e22f391e3907ea4acd8968mark@chromium.org # rule source. Collect the names of the directories that are 983cb6f53f225b902a519e22f391e3907ea4acd8968mark@chromium.org # required. 984cb6f53f225b902a519e22f391e3907ea4acd8968mark@chromium.org concrete_output_dirs = [] 9856105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org for concrete_output_index in xrange(0, len(concrete_outputs)): 9866105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org concrete_output = concrete_outputs[concrete_output_index] 9876105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org if concrete_output_index == 0: 9886105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org bol = '' 9896105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org else: 9906105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org bol = ' ' 9916105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org makefile.write('%s%s \\\n' % (bol, concrete_output)) 9926105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org 993ff3d7702d6dba2fa383fb695f25fd8e4f151237ethomasvl@chromium.org concrete_output_dir = posixpath.dirname(concrete_output) 99445a90d82e8c974fb09788af03418fccf97e03f29sgk@chromium.org if (concrete_output_dir and 99545a90d82e8c974fb09788af03418fccf97e03f29sgk@chromium.org concrete_output_dir not in concrete_output_dirs): 996cb6f53f225b902a519e22f391e3907ea4acd8968mark@chromium.org concrete_output_dirs.append(concrete_output_dir) 997cb6f53f225b902a519e22f391e3907ea4acd8968mark@chromium.org 9986105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org makefile.write(' : \\\n') 9996105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org 1000937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # The prerequisites for this rule are the rule source itself and 1001937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # the set of additional rule inputs, if any. 1002937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org prerequisites = [rule_source] 1003937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org prerequisites.extend(rule.get('inputs', [])) 1004937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org for prerequisite_index in xrange(0, len(prerequisites)): 1005937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org prerequisite = prerequisites[prerequisite_index] 1006937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org if prerequisite_index == len(prerequisites) - 1: 10076105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org eol = '' 10086105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org else: 10096105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org eol = ' \\' 1010937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org makefile.write(' %s%s\n' % (prerequisite, eol)) 10116105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org 1012cb6f53f225b902a519e22f391e3907ea4acd8968mark@chromium.org # Make sure that output directories exist before executing the rule 1013cb6f53f225b902a519e22f391e3907ea4acd8968mark@chromium.org # action. 1014cb6f53f225b902a519e22f391e3907ea4acd8968mark@chromium.org if len(concrete_output_dirs) > 0: 1015ec670df7ec53a964ae4a2b9f39265598c286c0d4thomasvl@chromium.org makefile.write('\t@mkdir -p "%s"\n' % 1016ec670df7ec53a964ae4a2b9f39265598c286c0d4thomasvl@chromium.org '" "'.join(concrete_output_dirs)) 1017cb6f53f225b902a519e22f391e3907ea4acd8968mark@chromium.org 101814cfb71e1e4c67b0779999a7cf4eb6be2e2c2ed1thomasvl@chromium.org # The rule message and action have already had the necessary variable 1019937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # substitutions performed. 102014cfb71e1e4c67b0779999a7cf4eb6be2e2c2ed1thomasvl@chromium.org if message: 1021ec670df7ec53a964ae4a2b9f39265598c286c0d4thomasvl@chromium.org # Mark it with note: so Xcode picks it up in build output. 1022ec670df7ec53a964ae4a2b9f39265598c286c0d4thomasvl@chromium.org makefile.write('\t@echo note: %s\n' % message) 10236105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org makefile.write('\t%s\n' % action) 10246105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org 10256105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org makefile.close() 10266105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org 1027cb6f53f225b902a519e22f391e3907ea4acd8968mark@chromium.org # It might be nice to ensure that needed output directories exist 1028cb6f53f225b902a519e22f391e3907ea4acd8968mark@chromium.org # here rather than in each target in the Makefile, but that wouldn't 1029cb6f53f225b902a519e22f391e3907ea4acd8968mark@chromium.org # work if there ever was a concrete output that had an input-dependent 1030cb6f53f225b902a519e22f391e3907ea4acd8968mark@chromium.org # variable anywhere other than in the leaf position. 10310336cc25f6c699536b570c60dcf220a0d48321cdmark@chromium.org 10326105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # Don't declare any inputPaths or outputPaths. If they're present, 10336105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # Xcode will provide a slight optimization by only running the script 10346105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # phase if any output is missing or outdated relative to any input. 10356105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # Unfortunately, it will also assume that all outputs are touched by 10366105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # the script, and if the outputs serve as files in a compilation 10376105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # phase, they will be unconditionally rebuilt. Since make might not 10386105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # rebuild everything that could be declared here as an output, this 10396105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # extra compilation activity is unnecessary. With inputPaths and 10406105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # outputPaths not supplied, make will always be called, but it knows 10416105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # enough to not do anything when everything is up-to-date. 10425270fcdd9af421a59ad14994938d133334656a15thomasvl@chromium.org 10435270fcdd9af421a59ad14994938d133334656a15thomasvl@chromium.org # To help speed things up, pass -j COUNT to make so it does some work 10445270fcdd9af421a59ad14994938d133334656a15thomasvl@chromium.org # in parallel. Don't use ncpus because Xcode will build ncpus targets 10455270fcdd9af421a59ad14994938d133334656a15thomasvl@chromium.org # in parallel and if each target happens to have a rules step, there 10465270fcdd9af421a59ad14994938d133334656a15thomasvl@chromium.org # would be ncpus^2 things going. With a machine that has 2 quad-core 10475270fcdd9af421a59ad14994938d133334656a15thomasvl@chromium.org # Xeons, a build can quickly run out of processes based on 10485270fcdd9af421a59ad14994938d133334656a15thomasvl@chromium.org # scheduling/other tasks, and randomly failing builds are no good. 1049cb6f53f225b902a519e22f391e3907ea4acd8968mark@chromium.org script = \ 105028a7a94e52dc391488a6b9e79c4c39a60643f31cmark@chromium.org"""JOB_COUNT="$(/usr/sbin/sysctl -n hw.ncpu)" 10515270fcdd9af421a59ad14994938d133334656a15thomasvl@chromium.orgif [ "${JOB_COUNT}" -gt 4 ]; then 10525270fcdd9af421a59ad14994938d133334656a15thomasvl@chromium.org JOB_COUNT=4 10535270fcdd9af421a59ad14994938d133334656a15thomasvl@chromium.orgfi 1054cb1c21bb0aa903c094b7c4fe273fb8bf88b7354fmark@chromium.orgexec xcrun make -f "${PROJECT_FILE_PATH}/%s" -j "${JOB_COUNT}" 10556105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.orgexit 1 10566105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org""" % makefile_name 10576105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org ssbp = gyp.xcodeproj_file.PBXShellScriptBuildPhase({ 10586105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org 'name': 'Rule "' + rule['rule_name'] + '"', 10596105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org 'shellScript': script, 10606105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org 'showEnvVarsInLog': 0, 10616105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org }) 10626105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org 10632fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org if support_xct: 10642fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org support_xct.AppendProperty('buildPhases', ssbp) 10652fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org else: 10662fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org # TODO(mark): this assumes too much knowledge of the internals of 10672fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org # xcodeproj_file; some of these smarts should move into xcodeproj_file 10682fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org # itself. 10692fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org xct._properties['buildPhases'].insert(prebuild_index, ssbp) 10702fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org prebuild_index = prebuild_index + 1 10716105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org 1072937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # Extra rule inputs also go into the project file. Concrete outputs were 1073937c5e2af9d90e88558b2cf4edbf2c4f8132e63bmark@chromium.org # already added when they were computed. 1074bc09226aa146f71557f6f22ed54fe21f9dd9ff6bthomasvl@chromium.org groups = ['inputs', 'inputs_excluded'] 1075bc09226aa146f71557f6f22ed54fe21f9dd9ff6bthomasvl@chromium.org if skip_excluded_files: 1076bc09226aa146f71557f6f22ed54fe21f9dd9ff6bthomasvl@chromium.org groups = [x for x in groups if not x.endswith('_excluded')] 1077bc09226aa146f71557f6f22ed54fe21f9dd9ff6bthomasvl@chromium.org for group in groups: 10786105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org for item in rule.get(group, []): 10796105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org pbxp.AddOrGetFileInRootGroup(item) 10806105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org 10816105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # Add "sources". 10820c3d85d2650c028b4f8887615d1c1defbad9cec5mark@chromium.org for source in spec.get('sources', []): 1083ff3d7702d6dba2fa383fb695f25fd8e4f151237ethomasvl@chromium.org (source_root, source_extension) = posixpath.splitext(source) 10846bfd4530db863baa22944fe9564d9f12586ab472thomasvl@chromium.org if source_extension[1:] not in rules_by_ext: 10856105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # AddSourceToTarget will add the file to a root group if it's not 10866105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org # already there. 10872f50e033f2bbdde2b168177750995e54a98a7375bradnelson@google.com AddSourceToTarget(source, type, pbxp, xct) 10886105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org else: 10896105598b39c567277bd230431a3e7a1b83f4447bmark@chromium.org pbxp.AddOrGetFileInRootGroup(source) 1090dbd5170901cfeb753bd7cee93b5b7c40dcc76337mark@chromium.org 10914cfea613522a978e2d34c4b7197fb460b6b4f8afthakis@chromium.org # Add "mac_bundle_resources" and "mac_framework_private_headers" if 10924cfea613522a978e2d34c4b7197fb460b6b4f8afthakis@chromium.org # it's a bundle of any type. 1093ca359a77c83539ba95896309f9aacc0ba6180868mark@chromium.org if is_bundle: 10946bfd4530db863baa22944fe9564d9f12586ab472thomasvl@chromium.org for resource in tgt_mac_bundle_resources: 10956bfd4530db863baa22944fe9564d9f12586ab472thomasvl@chromium.org (resource_root, resource_extension) = posixpath.splitext(resource) 10966bfd4530db863baa22944fe9564d9f12586ab472thomasvl@chromium.org if resource_extension[1:] not in rules_by_ext: 10976bfd4530db863baa22944fe9564d9f12586ab472thomasvl@chromium.org AddResourceToTarget(resource, pbxp, xct) 10986bfd4530db863baa22944fe9564d9f12586ab472thomasvl@chromium.org else: 10996bfd4530db863baa22944fe9564d9f12586ab472thomasvl@chromium.org pbxp.AddOrGetFileInRootGroup(resource) 1100df568f04a7a521e316155e3bda790ad664b18cb1mark@chromium.org 110129f8e2ce4be5527f72745c7345e7b48b090630ccmark@chromium.org for header in spec.get('mac_framework_private_headers', []): 110229f8e2ce4be5527f72745c7345e7b48b090630ccmark@chromium.org AddHeaderToTarget(header, pbxp, xct, False) 1103c5ff18b9991ffd97d70e296ff3e042c25ed9879dmark@chromium.org 11044cfea613522a978e2d34c4b7197fb460b6b4f8afthakis@chromium.org # Add "mac_framework_headers". These can be valid for both frameworks 11054cfea613522a978e2d34c4b7197fb460b6b4f8afthakis@chromium.org # and static libraries. 11064cfea613522a978e2d34c4b7197fb460b6b4f8afthakis@chromium.org if is_bundle or type == 'static_library': 11074cfea613522a978e2d34c4b7197fb460b6b4f8afthakis@chromium.org for header in spec.get('mac_framework_headers', []): 11084cfea613522a978e2d34c4b7197fb460b6b4f8afthakis@chromium.org AddHeaderToTarget(header, pbxp, xct, True) 11094cfea613522a978e2d34c4b7197fb460b6b4f8afthakis@chromium.org 1110660f956666798a1d732cc612d2adbaeac4fe3b14mark@chromium.org # Add "copies". 11115f30bb815433b9feea320d7221182e79363848f1mark@chromium.org pbxcp_dict = {} 1112660f956666798a1d732cc612d2adbaeac4fe3b14mark@chromium.org for copy_group in spec.get('copies', []): 11134f6c7bda24f785ad4a7a3e084c5999329dc05660sgk@chromium.org dest = copy_group['destination'] 11144f6c7bda24f785ad4a7a3e084c5999329dc05660sgk@chromium.org if dest[0] not in ('/', '$'): 11154f6c7bda24f785ad4a7a3e084c5999329dc05660sgk@chromium.org # Relative paths are relative to $(SRCROOT). 11164f6c7bda24f785ad4a7a3e084c5999329dc05660sgk@chromium.org dest = '$(SRCROOT)/' + dest 1117660f956666798a1d732cc612d2adbaeac4fe3b14mark@chromium.org 11185f30bb815433b9feea320d7221182e79363848f1mark@chromium.org # Coalesce multiple "copies" sections in the same target with the same 11195f30bb815433b9feea320d7221182e79363848f1mark@chromium.org # "destination" property into the same PBXCopyFilesBuildPhase, otherwise 11205f30bb815433b9feea320d7221182e79363848f1mark@chromium.org # they'll wind up with ID collisions. 11215f30bb815433b9feea320d7221182e79363848f1mark@chromium.org pbxcp = pbxcp_dict.get(dest, None) 11225f30bb815433b9feea320d7221182e79363848f1mark@chromium.org if pbxcp is None: 11235f30bb815433b9feea320d7221182e79363848f1mark@chromium.org pbxcp = gyp.xcodeproj_file.PBXCopyFilesBuildPhase({ 11245f30bb815433b9feea320d7221182e79363848f1mark@chromium.org 'name': 'Copy to ' + copy_group['destination'] 11255f30bb815433b9feea320d7221182e79363848f1mark@chromium.org }, 11265f30bb815433b9feea320d7221182e79363848f1mark@chromium.org parent=xct) 11275f30bb815433b9feea320d7221182e79363848f1mark@chromium.org pbxcp.SetDestination(dest) 11285f30bb815433b9feea320d7221182e79363848f1mark@chromium.org 11295f30bb815433b9feea320d7221182e79363848f1mark@chromium.org # TODO(mark): The usual comment about this knowing too much about 11305f30bb815433b9feea320d7221182e79363848f1mark@chromium.org # gyp.xcodeproj_file internals applies. 11315f30bb815433b9feea320d7221182e79363848f1mark@chromium.org xct._properties['buildPhases'].insert(prebuild_index, pbxcp) 11325f30bb815433b9feea320d7221182e79363848f1mark@chromium.org 11335f30bb815433b9feea320d7221182e79363848f1mark@chromium.org pbxcp_dict[dest] = pbxcp 1134660f956666798a1d732cc612d2adbaeac4fe3b14mark@chromium.org 1135660f956666798a1d732cc612d2adbaeac4fe3b14mark@chromium.org for file in copy_group['files']: 1136660f956666798a1d732cc612d2adbaeac4fe3b14mark@chromium.org pbxcp.AddFile(file) 1137660f956666798a1d732cc612d2adbaeac4fe3b14mark@chromium.org 11386eb312d5514774feaeb85bce5217d46f65c99f4cmark@chromium.org # Excluded files can also go into the project file. 1139bc09226aa146f71557f6f22ed54fe21f9dd9ff6bthomasvl@chromium.org if not skip_excluded_files: 114029f8e2ce4be5527f72745c7345e7b48b090630ccmark@chromium.org for key in ['sources', 'mac_bundle_resources', 'mac_framework_headers', 114129f8e2ce4be5527f72745c7345e7b48b090630ccmark@chromium.org 'mac_framework_private_headers']: 1142bc09226aa146f71557f6f22ed54fe21f9dd9ff6bthomasvl@chromium.org excluded_key = key + '_excluded' 1143bc09226aa146f71557f6f22ed54fe21f9dd9ff6bthomasvl@chromium.org for item in spec.get(excluded_key, []): 1144bc09226aa146f71557f6f22ed54fe21f9dd9ff6bthomasvl@chromium.org pbxp.AddOrGetFileInRootGroup(item) 11457bf9d8be9e8ea36b38da8093730af981c33c6ca3mark@chromium.org 1146925aac506abf3125b8e7d5024b40897196afbd0dmark@chromium.org # So can "inputs" and "outputs" sections of "actions" groups. 1147bc09226aa146f71557f6f22ed54fe21f9dd9ff6bthomasvl@chromium.org groups = ['inputs', 'inputs_excluded', 'outputs', 'outputs_excluded'] 1148bc09226aa146f71557f6f22ed54fe21f9dd9ff6bthomasvl@chromium.org if skip_excluded_files: 1149bc09226aa146f71557f6f22ed54fe21f9dd9ff6bthomasvl@chromium.org groups = [x for x in groups if not x.endswith('_excluded')] 1150df568f04a7a521e316155e3bda790ad664b18cb1mark@chromium.org for action in spec.get('actions', []): 1151df568f04a7a521e316155e3bda790ad664b18cb1mark@chromium.org for group in groups: 1152df568f04a7a521e316155e3bda790ad664b18cb1mark@chromium.org for item in action.get(group, []): 1153df568f04a7a521e316155e3bda790ad664b18cb1mark@chromium.org # Exclude anything in BUILT_PRODUCTS_DIR. They're products, not 1154df568f04a7a521e316155e3bda790ad664b18cb1mark@chromium.org # sources. 1155df568f04a7a521e316155e3bda790ad664b18cb1mark@chromium.org if not item.startswith('$(BUILT_PRODUCTS_DIR)/'): 11566eb312d5514774feaeb85bce5217d46f65c99f4cmark@chromium.org pbxp.AddOrGetFileInRootGroup(item) 1157925aac506abf3125b8e7d5024b40897196afbd0dmark@chromium.org 11586d246822bc38b8fb10f1b7b1e583e47f4babf765mark@chromium.org for postbuild in spec.get('postbuilds', []): 11596d246822bc38b8fb10f1b7b1e583e47f4babf765mark@chromium.org action_string_sh = gyp.common.EncodePOSIXShellList(postbuild['action']) 11606d246822bc38b8fb10f1b7b1e583e47f4babf765mark@chromium.org script = 'exec ' + action_string_sh + '\nexit 1\n' 116126d2ce054dc62a3d78d520b4cbaa72272b0fabe1mark@chromium.org 116226d2ce054dc62a3d78d520b4cbaa72272b0fabe1mark@chromium.org # Make the postbuild step depend on the output of ld or ar from this 116326d2ce054dc62a3d78d520b4cbaa72272b0fabe1mark@chromium.org # target. Apparently putting the script step after the link step isn't 116426d2ce054dc62a3d78d520b4cbaa72272b0fabe1mark@chromium.org # sufficient to ensure proper ordering in all cases. With an input 116526d2ce054dc62a3d78d520b4cbaa72272b0fabe1mark@chromium.org # declared but no outputs, the script step should run every time, as 116626d2ce054dc62a3d78d520b4cbaa72272b0fabe1mark@chromium.org # desired. 11676d246822bc38b8fb10f1b7b1e583e47f4babf765mark@chromium.org ssbp = gyp.xcodeproj_file.PBXShellScriptBuildPhase({ 116826d2ce054dc62a3d78d520b4cbaa72272b0fabe1mark@chromium.org 'inputPaths': ['$(BUILT_PRODUCTS_DIR)/$(EXECUTABLE_PATH)'], 11696d246822bc38b8fb10f1b7b1e583e47f4babf765mark@chromium.org 'name': 'Postbuild "' + postbuild['postbuild_name'] + '"', 11706d246822bc38b8fb10f1b7b1e583e47f4babf765mark@chromium.org 'shellScript': script, 11716d246822bc38b8fb10f1b7b1e583e47f4babf765mark@chromium.org 'showEnvVarsInLog': 0, 11726d246822bc38b8fb10f1b7b1e583e47f4babf765mark@chromium.org }) 11736d246822bc38b8fb10f1b7b1e583e47f4babf765mark@chromium.org xct.AppendProperty('buildPhases', ssbp) 11746d246822bc38b8fb10f1b7b1e583e47f4babf765mark@chromium.org 11757bf9d8be9e8ea36b38da8093730af981c33c6ca3mark@chromium.org # Add dependencies before libraries, because adding a dependency may imply 11767bf9d8be9e8ea36b38da8093730af981c33c6ca3mark@chromium.org # adding a library. It's preferable to keep dependencies listed first 11777bf9d8be9e8ea36b38da8093730af981c33c6ca3mark@chromium.org # during a link phase so that they can override symbols that would 11787bf9d8be9e8ea36b38da8093730af981c33c6ca3mark@chromium.org # otherwise be provided by libraries, which will usually include system 11797bf9d8be9e8ea36b38da8093730af981c33c6ca3mark@chromium.org # libraries. On some systems, ld is finicky and even requires the 11807bf9d8be9e8ea36b38da8093730af981c33c6ca3mark@chromium.org # libraries to be ordered in such a way that unresolved symbols in 11817bf9d8be9e8ea36b38da8093730af981c33c6ca3mark@chromium.org # earlier-listed libraries may only be resolved by later-listed libraries. 11827bf9d8be9e8ea36b38da8093730af981c33c6ca3mark@chromium.org # The Mac linker doesn't work that way, but other platforms do, and so 11837bf9d8be9e8ea36b38da8093730af981c33c6ca3mark@chromium.org # their linker invocations need to be constructed in this way. There's 11847bf9d8be9e8ea36b38da8093730af981c33c6ca3mark@chromium.org # no compelling reason for Xcode's linker invocations to differ. 11857bf9d8be9e8ea36b38da8093730af981c33c6ca3mark@chromium.org 118642ca7d073c71f0f4b7e7f1255ae4e915eafecb8fmark@chromium.org if 'dependencies' in spec: 118742ca7d073c71f0f4b7e7f1255ae4e915eafecb8fmark@chromium.org for dependency in spec['dependencies']: 118835d23def8cd397d452a491a0ac7aa8bc1720c7d9mark@chromium.org xct.AddDependency(xcode_targets[dependency]) 11892fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org # The support project also gets the dependencies (in case they are 11902fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org # needed for the actions/rules to work). 11912fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org if support_xct: 11922fa5568850ffcf19f5c8631cec4e4cd65236eaf3thomasvl@chromium.org support_xct.AddDependency(xcode_targets[dependency]) 1193a85d7de5129e37e558dc6e9c70ded4d300a71c5emark@chromium.org 11947bf9d8be9e8ea36b38da8093730af981c33c6ca3mark@chromium.org if 'libraries' in spec: 11957bf9d8be9e8ea36b38da8093730af981c33c6ca3mark@chromium.org for library in spec['libraries']: 119635d23def8cd397d452a491a0ac7aa8bc1720c7d9mark@chromium.org xct.FrameworksPhase().AddFile(library) 1197ee5a85a1fe3f930d233487bdd3f2139fb6d0197fmark@chromium.org # Add the library's directory to LIBRARY_SEARCH_PATHS if necessary. 1198ee5a85a1fe3f930d233487bdd3f2139fb6d0197fmark@chromium.org # I wish Xcode handled this automatically. 11996b4f0fecc1ebaf7f785ae4f1efbc193b49356500mark@chromium.org library_dir = posixpath.dirname(library) 12006b4f0fecc1ebaf7f785ae4f1efbc193b49356500mark@chromium.org if library_dir not in xcode_standard_library_dirs and ( 12016b4f0fecc1ebaf7f785ae4f1efbc193b49356500mark@chromium.org not xct.HasBuildSetting(_library_search_paths_var) or 12026b4f0fecc1ebaf7f785ae4f1efbc193b49356500mark@chromium.org library_dir not in xct.GetBuildSetting(_library_search_paths_var)): 12036b4f0fecc1ebaf7f785ae4f1efbc193b49356500mark@chromium.org xct.AppendBuildSetting(_library_search_paths_var, library_dir) 120435d23def8cd397d452a491a0ac7aa8bc1720c7d9mark@chromium.org 1205fbafe02cf1d9050ef42e598af10eac66041ede3fmark@chromium.org for configuration_name in configuration_names: 1206fbafe02cf1d9050ef42e598af10eac66041ede3fmark@chromium.org configuration = spec['configurations'][configuration_name] 120735d23def8cd397d452a491a0ac7aa8bc1720c7d9mark@chromium.org xcbc = xct.ConfigurationNamed(configuration_name) 120841b29907da6ab12d5f831de9e324ceac2302bd50mark@chromium.org for include_dir in configuration.get('mac_framework_dirs', []): 120941b29907da6ab12d5f831de9e324ceac2302bd50mark@chromium.org xcbc.AppendBuildSetting('FRAMEWORK_SEARCH_PATHS', include_dir) 121041b29907da6ab12d5f831de9e324ceac2302bd50mark@chromium.org for include_dir in configuration.get('include_dirs', []): 121141b29907da6ab12d5f831de9e324ceac2302bd50mark@chromium.org xcbc.AppendBuildSetting('HEADER_SEARCH_PATHS', include_dir) 1212f37c83ad866169311ce41cb09b32116c00c82244dimator@google.com for library_dir in configuration.get('library_dirs', []): 1213f37c83ad866169311ce41cb09b32116c00c82244dimator@google.com if library_dir not in xcode_standard_library_dirs and ( 1214f37c83ad866169311ce41cb09b32116c00c82244dimator@google.com not xcbc.HasBuildSetting(_library_search_paths_var) or 1215f37c83ad866169311ce41cb09b32116c00c82244dimator@google.com library_dir not in xcbc.GetBuildSetting(_library_search_paths_var)): 1216f37c83ad866169311ce41cb09b32116c00c82244dimator@google.com xcbc.AppendBuildSetting(_library_search_paths_var, library_dir) 1217f37c83ad866169311ce41cb09b32116c00c82244dimator@google.com 121835d23def8cd397d452a491a0ac7aa8bc1720c7d9mark@chromium.org if 'defines' in configuration: 121935d23def8cd397d452a491a0ac7aa8bc1720c7d9mark@chromium.org for define in configuration['defines']: 1220c00a2e4dd4094100a45651d8ef48e68df1453a5cmark@chromium.org set_define = EscapeXcodeDefine(define) 12217f5db5ccaadb3b469204da6e9c16c21e2d625cf3mark@chromium.org xcbc.AppendBuildSetting('GCC_PREPROCESSOR_DEFINITIONS', set_define) 1222407804ed35f70aa71aaf2302c552a2acb537c1d8mark@chromium.org if 'xcode_settings' in configuration: 1223407804ed35f70aa71aaf2302c552a2acb537c1d8mark@chromium.org for xck, xcv in configuration['xcode_settings'].iteritems(): 1224407804ed35f70aa71aaf2302c552a2acb537c1d8mark@chromium.org xcbc.SetBuildSetting(xck, xcv) 1225d13b3844deb56e21c867495e3e7ec2e0e114184cstuartmorgan@chromium.org if 'xcode_config_file' in configuration: 1226d13b3844deb56e21c867495e3e7ec2e0e114184cstuartmorgan@chromium.org config_ref = pbxp.AddOrGetFileInRootGroup( 1227d13b3844deb56e21c867495e3e7ec2e0e114184cstuartmorgan@chromium.org configuration['xcode_config_file']) 1228d13b3844deb56e21c867495e3e7ec2e0e114184cstuartmorgan@chromium.org xcbc.SetBaseConfiguration(config_ref) 12297bf9d8be9e8ea36b38da8093730af981c33c6ca3mark@chromium.org 123059bcf62c6030f720b82251b2464fcc632c0ad8bamark@chromium.org build_files = [] 1231a85d7de5129e37e558dc6e9c70ded4d300a71c5emark@chromium.org for build_file, build_file_dict in data.iteritems(): 1232bf684ddd17bb8e6c0ad08d3d693875a8c070e20amark@chromium.org if build_file.endswith('.gyp'): 123359bcf62c6030f720b82251b2464fcc632c0ad8bamark@chromium.org build_files.append(build_file) 1234475089d4d1a7ea54e6f25312d665da1e982d96d0mark@chromium.org 123559bcf62c6030f720b82251b2464fcc632c0ad8bamark@chromium.org for build_file in build_files: 1236366c66406ae02027430da1a30554810bcfc7f90ethomasvl@chromium.org xcode_projects[build_file].Finalize1(xcode_targets, serialize_all_tests) 123759bcf62c6030f720b82251b2464fcc632c0ad8bamark@chromium.org 123859bcf62c6030f720b82251b2464fcc632c0ad8bamark@chromium.org for build_file in build_files: 1239c4e3156b31433b6ab7f607975c22cf466fcf0051thomasvl@chromium.org xcode_projects[build_file].Finalize2(xcode_targets, 1240c4e3156b31433b6ab7f607975c22cf466fcf0051thomasvl@chromium.org xcode_target_to_target_dict) 124159bcf62c6030f720b82251b2464fcc632c0ad8bamark@chromium.org 124259bcf62c6030f720b82251b2464fcc632c0ad8bamark@chromium.org for build_file in build_files: 124359bcf62c6030f720b82251b2464fcc632c0ad8bamark@chromium.org xcode_projects[build_file].Write() 1244