cocoapods-tt 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. checksums.yaml +7 -0
  2. data/lib/cocoapods-tt/command/native/install.rb +56 -0
  3. data/lib/cocoapods-tt/command/native/update.rb +157 -0
  4. data/lib/cocoapods-tt/command/tt/make.rb +92 -0
  5. data/lib/cocoapods-tt/command/tt.rb +115 -0
  6. data/lib/cocoapods-tt/command.rb +1 -0
  7. data/lib/cocoapods-tt/gem_version.rb +3 -0
  8. data/lib/cocoapods-tt/native/command.rb +185 -0
  9. data/lib/cocoapods-tt/native/config.rb +366 -0
  10. data/lib/cocoapods-tt/native/core_overrides.rb +1 -0
  11. data/lib/cocoapods-tt/native/downloader/cache.rb +322 -0
  12. data/lib/cocoapods-tt/native/downloader/request.rb +86 -0
  13. data/lib/cocoapods-tt/native/downloader/response.rb +16 -0
  14. data/lib/cocoapods-tt/native/downloader.rb +192 -0
  15. data/lib/cocoapods-tt/native/executable.rb +247 -0
  16. data/lib/cocoapods-tt/native/external_sources/abstract_external_source.rb +205 -0
  17. data/lib/cocoapods-tt/native/external_sources/downloader_source.rb +30 -0
  18. data/lib/cocoapods-tt/native/external_sources/path_source.rb +55 -0
  19. data/lib/cocoapods-tt/native/external_sources/podspec_source.rb +54 -0
  20. data/lib/cocoapods-tt/native/external_sources.rb +57 -0
  21. data/lib/cocoapods-tt/native/gem_version.rb +5 -0
  22. data/lib/cocoapods-tt/native/generator/acknowledgements/markdown.rb +44 -0
  23. data/lib/cocoapods-tt/native/generator/acknowledgements/plist.rb +94 -0
  24. data/lib/cocoapods-tt/native/generator/acknowledgements.rb +107 -0
  25. data/lib/cocoapods-tt/native/generator/app_target_helper.rb +363 -0
  26. data/lib/cocoapods-tt/native/generator/bridge_support.rb +22 -0
  27. data/lib/cocoapods-tt/native/generator/constant.rb +19 -0
  28. data/lib/cocoapods-tt/native/generator/copy_dsyms_script.rb +56 -0
  29. data/lib/cocoapods-tt/native/generator/copy_resources_script.rb +223 -0
  30. data/lib/cocoapods-tt/native/generator/copy_xcframework_script.rb +227 -0
  31. data/lib/cocoapods-tt/native/generator/dummy_source.rb +31 -0
  32. data/lib/cocoapods-tt/native/generator/embed_frameworks_script.rb +196 -0
  33. data/lib/cocoapods-tt/native/generator/file_list.rb +39 -0
  34. data/lib/cocoapods-tt/native/generator/header.rb +103 -0
  35. data/lib/cocoapods-tt/native/generator/info_plist_file.rb +128 -0
  36. data/lib/cocoapods-tt/native/generator/module_map.rb +99 -0
  37. data/lib/cocoapods-tt/native/generator/prefix_header.rb +60 -0
  38. data/lib/cocoapods-tt/native/generator/script_phase_constants.rb +100 -0
  39. data/lib/cocoapods-tt/native/generator/umbrella_header.rb +46 -0
  40. data/lib/cocoapods-tt/native/hooks_manager.rb +132 -0
  41. data/lib/cocoapods-tt/native/installer/analyzer/analysis_result.rb +87 -0
  42. data/lib/cocoapods-tt/native/installer/analyzer/locking_dependency_analyzer.rb +103 -0
  43. data/lib/cocoapods-tt/native/installer/analyzer/pod_variant.rb +87 -0
  44. data/lib/cocoapods-tt/native/installer/analyzer/pod_variant_set.rb +175 -0
  45. data/lib/cocoapods-tt/native/installer/analyzer/podfile_dependency_cache.rb +55 -0
  46. data/lib/cocoapods-tt/native/installer/analyzer/sandbox_analyzer.rb +268 -0
  47. data/lib/cocoapods-tt/native/installer/analyzer/specs_state.rb +108 -0
  48. data/lib/cocoapods-tt/native/installer/analyzer/target_inspection_result.rb +58 -0
  49. data/lib/cocoapods-tt/native/installer/analyzer/target_inspector.rb +258 -0
  50. data/lib/cocoapods-tt/native/installer/analyzer.rb +1204 -0
  51. data/lib/cocoapods-tt/native/installer/base_install_hooks_context.rb +135 -0
  52. data/lib/cocoapods-tt/native/installer/installation_options.rb +195 -0
  53. data/lib/cocoapods-tt/native/installer/pod_source_installer.rb +224 -0
  54. data/lib/cocoapods-tt/native/installer/pod_source_preparer.rb +77 -0
  55. data/lib/cocoapods-tt/native/installer/podfile_validator.rb +168 -0
  56. data/lib/cocoapods-tt/native/installer/post_install_hooks_context.rb +9 -0
  57. data/lib/cocoapods-tt/native/installer/post_integrate_hooks_context.rb +9 -0
  58. data/lib/cocoapods-tt/native/installer/pre_install_hooks_context.rb +51 -0
  59. data/lib/cocoapods-tt/native/installer/pre_integrate_hooks_context.rb +9 -0
  60. data/lib/cocoapods-tt/native/installer/project_cache/project_cache.rb +11 -0
  61. data/lib/cocoapods-tt/native/installer/project_cache/project_cache_analysis_result.rb +53 -0
  62. data/lib/cocoapods-tt/native/installer/project_cache/project_cache_analyzer.rb +200 -0
  63. data/lib/cocoapods-tt/native/installer/project_cache/project_cache_version.rb +43 -0
  64. data/lib/cocoapods-tt/native/installer/project_cache/project_installation_cache.rb +103 -0
  65. data/lib/cocoapods-tt/native/installer/project_cache/project_metadata_cache.rb +73 -0
  66. data/lib/cocoapods-tt/native/installer/project_cache/target_cache_key.rb +176 -0
  67. data/lib/cocoapods-tt/native/installer/project_cache/target_metadata.rb +74 -0
  68. data/lib/cocoapods-tt/native/installer/sandbox_dir_cleaner.rb +105 -0
  69. data/lib/cocoapods-tt/native/installer/sandbox_header_paths_installer.rb +45 -0
  70. data/lib/cocoapods-tt/native/installer/source_provider_hooks_context.rb +34 -0
  71. data/lib/cocoapods-tt/native/installer/target_uuid_generator.rb +34 -0
  72. data/lib/cocoapods-tt/native/installer/user_project_integrator/target_integrator/xcconfig_integrator.rb +179 -0
  73. data/lib/cocoapods-tt/native/installer/user_project_integrator/target_integrator.rb +815 -0
  74. data/lib/cocoapods-tt/native/installer/user_project_integrator.rb +280 -0
  75. data/lib/cocoapods-tt/native/installer/xcode/multi_pods_project_generator.rb +82 -0
  76. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/aggregate_target_dependency_installer.rb +66 -0
  77. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/aggregate_target_installer.rb +192 -0
  78. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/app_host_installer.rb +154 -0
  79. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/file_references_installer.rb +329 -0
  80. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/pod_target_dependency_installer.rb +195 -0
  81. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/pod_target_installer.rb +1239 -0
  82. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/pod_target_integrator.rb +312 -0
  83. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/pods_project_writer.rb +90 -0
  84. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/project_generator.rb +120 -0
  85. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/target_installation_result.rb +140 -0
  86. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/target_installer.rb +257 -0
  87. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/target_installer_helper.rb +110 -0
  88. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator.rb +291 -0
  89. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator_result.rb +54 -0
  90. data/lib/cocoapods-tt/native/installer/xcode/single_pods_project_generator.rb +38 -0
  91. data/lib/cocoapods-tt/native/installer/xcode/target_validator.rb +170 -0
  92. data/lib/cocoapods-tt/native/installer/xcode.rb +11 -0
  93. data/lib/cocoapods-tt/native/installer.rb +1044 -0
  94. data/lib/cocoapods-tt/native/native_target_extension.rb +60 -0
  95. data/lib/cocoapods-tt/native/open-uri.rb +33 -0
  96. data/lib/cocoapods-tt/native/podfile.rb +13 -0
  97. data/lib/cocoapods-tt/native/project.rb +544 -0
  98. data/lib/cocoapods-tt/native/resolver/lazy_specification.rb +88 -0
  99. data/lib/cocoapods-tt/native/resolver/resolver_specification.rb +41 -0
  100. data/lib/cocoapods-tt/native/resolver.rb +600 -0
  101. data/lib/cocoapods-tt/native/sandbox/file_accessor.rb +532 -0
  102. data/lib/cocoapods-tt/native/sandbox/headers_store.rb +163 -0
  103. data/lib/cocoapods-tt/native/sandbox/path_list.rb +242 -0
  104. data/lib/cocoapods-tt/native/sandbox/pod_dir_cleaner.rb +71 -0
  105. data/lib/cocoapods-tt/native/sandbox/podspec_finder.rb +23 -0
  106. data/lib/cocoapods-tt/native/sandbox.rb +470 -0
  107. data/lib/cocoapods-tt/native/sources_manager.rb +221 -0
  108. data/lib/cocoapods-tt/native/target/aggregate_target.rb +558 -0
  109. data/lib/cocoapods-tt/native/target/build_settings.rb +1385 -0
  110. data/lib/cocoapods-tt/native/target/pod_target.rb +1168 -0
  111. data/lib/cocoapods-tt/native/target.rb +378 -0
  112. data/lib/cocoapods-tt/native/user_interface/error_report.rb +204 -0
  113. data/lib/cocoapods-tt/native/user_interface/inspector_reporter.rb +102 -0
  114. data/lib/cocoapods-tt/native/user_interface.rb +463 -0
  115. data/lib/cocoapods-tt/native/validator.rb +1170 -0
  116. data/lib/cocoapods-tt/native/version_metadata.rb +26 -0
  117. data/lib/cocoapods-tt/native/xcode/framework_paths.rb +54 -0
  118. data/lib/cocoapods-tt/native/xcode/linkage_analyzer.rb +22 -0
  119. data/lib/cocoapods-tt/native/xcode/xcframework/xcframework_slice.rb +138 -0
  120. data/lib/cocoapods-tt/native/xcode/xcframework.rb +99 -0
  121. data/lib/cocoapods-tt/native/xcode.rb +7 -0
  122. data/lib/cocoapods-tt.rb +1 -0
  123. data/lib/cocoapods_plugin.rb +17 -0
  124. metadata +193 -0
@@ -0,0 +1,1239 @@
1
+ require 'active_support/core_ext/array'
2
+ require 'active_support/core_ext/string/inflections'
3
+ require 'cocoapods/xcode'
4
+
5
+ module Pod
6
+ class Installer
7
+ class Xcode
8
+ class PodsProjectGenerator
9
+ # Creates the target for the Pods libraries in the Pods project and the
10
+ # relative support files.
11
+ #
12
+ class PodTargetInstaller < TargetInstaller
13
+ require 'cocoapods/installer/xcode/pods_project_generator/app_host_installer'
14
+
15
+ # @return [Array<Pathname>] Array of umbrella header paths in the headers directory
16
+ #
17
+ attr_reader :umbrella_header_paths
18
+
19
+ # @return [PodTarget] @see TargetInstaller#target
20
+ #
21
+ attr_reader :target
22
+
23
+ # Initialize a new instance
24
+ #
25
+ # @param [Sandbox] sandbox @see TargetInstaller#sandbox
26
+ # @param [Pod::Project] project @see TargetInstaller#project
27
+ # @param [PodTarget] target @see TargetInstaller#target
28
+ # @param [Array<Pathname>] umbrella_header_paths @see #umbrella_header_paths
29
+ #
30
+ def initialize(sandbox, project, target, umbrella_header_paths = nil)
31
+ super(sandbox, project, target)
32
+ @umbrella_header_paths = umbrella_header_paths
33
+ end
34
+
35
+ # Creates the target in the Pods project and the relative support files.
36
+ #
37
+ # @return [TargetInstallationResult] the result of the installation of this target.
38
+ #
39
+ def install!
40
+ UI.message "- Installing target `#{target.name}` #{target.platform}" do
41
+ create_support_files_dir
42
+ library_file_accessors = target.file_accessors.select { |fa| fa.spec.library_specification? }
43
+ test_file_accessors = target.file_accessors.select { |fa| fa.spec.test_specification? }
44
+ app_file_accessors = target.file_accessors.select { |fa| fa.spec.app_specification? }
45
+
46
+ native_target = if target.should_build?
47
+ add_target
48
+ else
49
+ # For targets that should not be built (e.g. pre-built vendored frameworks etc), we add a placeholder
50
+ # PBXAggregateTarget that will be used to wire up dependencies later.
51
+ add_placeholder_target
52
+ end
53
+
54
+ resource_bundle_targets = add_resources_bundle_targets(library_file_accessors).values.flatten
55
+
56
+ test_native_targets = add_test_targets
57
+ test_app_host_targets = add_test_app_host_targets
58
+ test_resource_bundle_targets = add_resources_bundle_targets(test_file_accessors)
59
+
60
+ app_native_targets = add_app_targets
61
+ app_resource_bundle_targets = add_resources_bundle_targets(app_file_accessors)
62
+
63
+ add_files_to_build_phases(native_target, test_native_targets, app_native_targets)
64
+ targets_to_validate = test_native_targets + app_native_targets.values
65
+ targets_to_validate << native_target if target.should_build?
66
+ validate_targets_contain_sources(targets_to_validate)
67
+ validate_xcframeworks if target.should_build?
68
+
69
+ create_copy_xcframeworks_script unless target.xcframeworks.values.all?(&:empty?)
70
+
71
+ create_xcconfig_file(native_target, resource_bundle_targets)
72
+ create_test_xcconfig_files(test_native_targets, test_resource_bundle_targets)
73
+ create_app_xcconfig_files(app_native_targets, app_resource_bundle_targets)
74
+
75
+ if target.should_build? && target.defines_module? && !skip_modulemap?(target.library_specs)
76
+ create_module_map(native_target) do |generator|
77
+ generator.headers.concat module_map_additional_headers
78
+ end
79
+ create_umbrella_header(native_target) do |generator|
80
+ generator.imports += library_file_accessors.flat_map do |file_accessor|
81
+ header_dir = if !target.build_as_framework? && dir = file_accessor.spec_consumer.header_dir
82
+ Pathname.new(dir)
83
+ end
84
+
85
+ file_accessor.public_headers.map do |public_header|
86
+ public_header = if header_mappings_dir(file_accessor)
87
+ public_header.relative_path_from(header_mappings_dir(file_accessor))
88
+ else
89
+ public_header.basename
90
+ end
91
+ if header_dir
92
+ public_header = header_dir.join(public_header)
93
+ end
94
+ public_header
95
+ end
96
+ end
97
+ end
98
+ end
99
+
100
+ if target.should_build? && target.build_as_framework?
101
+ unless skip_info_plist?(native_target)
102
+ create_info_plist_file(target.info_plist_path, native_target, target.version, target.platform,
103
+ :additional_entries => target.info_plist_entries)
104
+ end
105
+ create_build_phase_to_symlink_header_folders(native_target)
106
+ end
107
+
108
+ if target.should_build? && target.build_as_library? && target.uses_swift?
109
+ add_swift_library_compatibility_header_phase(native_target)
110
+ end
111
+
112
+ project_directory = project.path.dirname
113
+
114
+ if target.should_build? && !skip_pch?(target.library_specs)
115
+ path = target.prefix_header_path
116
+ create_prefix_header(path, library_file_accessors, target.platform, native_target, project_directory)
117
+ add_file_to_support_group(path)
118
+ end
119
+ unless skip_pch?(target.test_specs)
120
+ target.test_specs.each do |test_spec|
121
+ path = target.prefix_header_path_for_spec(test_spec)
122
+ test_spec_consumer = test_spec.consumer(target.platform)
123
+ test_native_target = test_native_target_from_spec(test_spec_consumer.spec, test_native_targets)
124
+ create_prefix_header(path, test_file_accessors, target.platform, test_native_target, project_directory)
125
+ add_file_to_support_group(path)
126
+ end
127
+ end
128
+ unless skip_pch?(target.app_specs)
129
+ target.app_specs.each do |app_spec|
130
+ path = target.prefix_header_path_for_spec(app_spec)
131
+ app_spec_consumer = app_spec.consumer(target.platform)
132
+ app_native_target = app_native_targets[app_spec_consumer.spec]
133
+ create_prefix_header(path, app_file_accessors, target.platform, app_native_target, project_directory)
134
+ add_file_to_support_group(path)
135
+ end
136
+ end
137
+ create_dummy_source(native_target) if target.should_build?
138
+ create_copy_dsyms_script
139
+ clean_support_files_temp_dir
140
+ TargetInstallationResult.new(target, native_target, resource_bundle_targets,
141
+ test_native_targets, test_resource_bundle_targets, test_app_host_targets,
142
+ app_native_targets, app_resource_bundle_targets)
143
+ end
144
+ end
145
+
146
+ private
147
+
148
+ # Adds the target for the library to the Pods project with the
149
+ # appropriate build configurations.
150
+ #
151
+ # @note Overrides the superclass implementation to remove settings that are set in the pod target xcconfig
152
+ #
153
+ # @return [PBXNativeTarget] the native target that was added.
154
+ #
155
+ def add_target
156
+ super.tap do |native_target|
157
+ remove_pod_target_xcconfig_overrides_from_target(target.build_settings, native_target)
158
+ end
159
+ end
160
+
161
+ # Removes overrides of the `pod_target_xcconfig` settings from the target's
162
+ # build configurations.
163
+ #
164
+ # @param [Hash{Symbol => Pod::Target::BuildSettings}] build_settings_by_config the build settings by config
165
+ # of the target.
166
+ #
167
+ # @param [PBXNativeTarget] native_target
168
+ # the native target to remove pod target xcconfig overrides from.
169
+ #
170
+ # @return [Void]
171
+ #
172
+ #
173
+ def remove_pod_target_xcconfig_overrides_from_target(build_settings_by_config, native_target)
174
+ native_target.build_configurations.each do |configuration|
175
+ build_settings = build_settings_by_config[target.user_build_configurations[configuration.name]]
176
+ unless build_settings.nil?
177
+ build_settings.merged_pod_target_xcconfigs.each_key do |setting|
178
+ configuration.build_settings.delete(setting)
179
+ end
180
+ end
181
+ end
182
+ end
183
+
184
+ # @param [Array<Specification>] specs
185
+ # the specs to check against whether `.pch` generation should be skipped or not.
186
+ #
187
+ # @return [Boolean] Whether the target should build a pch file.
188
+ #
189
+ def skip_pch?(specs)
190
+ specs.any? { |spec| spec.root.prefix_header_file.is_a?(FalseClass) }
191
+ end
192
+
193
+ def skip_modulemap?(specs)
194
+ specs.any? { |spec| spec.module_map.is_a?(FalseClass) }
195
+ end
196
+
197
+ # True if info.plist generation should be skipped
198
+ #
199
+ # @param [PXNativeTarget] native_target
200
+ #
201
+ # @return [Boolean] Whether the target should build an Info.plist file
202
+ #
203
+ def skip_info_plist?(native_target)
204
+ existing_setting = native_target.resolved_build_setting('INFOPLIST_FILE', true).values.compact
205
+ !existing_setting.empty?
206
+ end
207
+
208
+ # Remove the default headers folder path settings for static library pod
209
+ # targets.
210
+ #
211
+ # @return [Hash{String => String}]
212
+ #
213
+ def custom_build_settings
214
+ settings = super
215
+ unless target.build_as_framework?
216
+ settings['PRIVATE_HEADERS_FOLDER_PATH'] = ''
217
+ settings['PUBLIC_HEADERS_FOLDER_PATH'] = ''
218
+ end
219
+
220
+ settings['PRODUCT_NAME'] = target.product_basename
221
+ settings['PRODUCT_MODULE_NAME'] = target.product_module_name
222
+
223
+ settings['CODE_SIGN_IDENTITY[sdk=appletvos*]'] = ''
224
+ settings['CODE_SIGN_IDENTITY[sdk=iphoneos*]'] = ''
225
+ settings['CODE_SIGN_IDENTITY[sdk=watchos*]'] = ''
226
+
227
+ settings['SWIFT_ACTIVE_COMPILATION_CONDITIONS'] = '$(inherited) '
228
+
229
+ if target.swift_version
230
+ settings['SWIFT_VERSION'] = target.swift_version
231
+ end
232
+
233
+ if info_plist_bundle_id
234
+ settings['PRODUCT_BUNDLE_IDENTIFIER'] = info_plist_bundle_id
235
+ end
236
+
237
+ settings
238
+ end
239
+
240
+ # @return [String] Bundle Identifier found in the custom Info.plist entries
241
+ #
242
+ def info_plist_bundle_id
243
+ return @plist_bundle_id if defined?(@plist_bundle_id)
244
+ unless target.info_plist_entries.nil?
245
+ @plist_bundle_id = target.info_plist_entries['CFBundleIdentifier']
246
+ unless @plist_bundle_id.nil?
247
+ message = "The `#{target.name}` target " \
248
+ "sets a Bundle Identifier of `#{@plist_bundle_id}` in it's info.plist file. " \
249
+ 'The Bundle Identifier should be set using pod_target_xcconfig: ' \
250
+ "s.pod_target_xcconfig = { 'PRODUCT_BUNDLE_IDENTIFIER': '#{@plist_bundle_id}' }`."
251
+ UI.warn message
252
+ end
253
+ @plist_bundle_id
254
+ end
255
+ end
256
+
257
+ # Filters the given resource file references discarding empty paths which are
258
+ # added by their parent directory. This will also include references to the parent [PBXVariantGroup]
259
+ # for all resources underneath it.
260
+ #
261
+ # @param [Array<Pathname>] resource_file_references
262
+ # The array of all resource file references to filter.
263
+ #
264
+ # @yield_param [Array<PBXFileReference>} The filtered resource file references to be installed
265
+ # in the copy resources phase.
266
+ #
267
+ # @yield_param [Array<PBXFileReference>} The filtered resource file references to be installed
268
+ # in the compile sources phase.
269
+ #
270
+ # @note Core Data model directories (.xcdatamodeld) and RealityKit projects (.rcproject)
271
+ # used to be added to the `Copy Resources` build phase like all other resources,
272
+ # since they would compile correctly in either the resources or compile phase. In
273
+ # recent versions of xcode, there's an exception for data models that generate
274
+ # headers. These need to be added to the compile sources phase of a real
275
+ # target for the headers to be built in time for code in the target to
276
+ # use them. These kinds of models generally break when added to resource
277
+ # bundles.
278
+ #
279
+ def filter_resource_file_references(resource_file_references)
280
+ file_references = resource_file_references.map do |resource_file_reference|
281
+ ref = project.reference_for_path(resource_file_reference)
282
+
283
+ # Some nested files are not directly present in the Xcode project, such as the contents
284
+ # of an .xcdatamodeld directory. These files are implicitly included by including their
285
+ # parent directory.
286
+ next if ref.nil?
287
+
288
+ # For variant groups, the variant group itself is added, not its members.
289
+ next ref.parent if ref.parent.is_a?(Xcodeproj::Project::Object::PBXVariantGroup)
290
+
291
+ ref
292
+ end.compact.uniq
293
+ compile_phase_matcher = lambda { |ref| !(ref.path =~ /.*\.(xcdatamodeld|rcproject)/i).nil? }
294
+ compile_phase_refs, resources_phase_refs = file_references.partition(&compile_phase_matcher)
295
+ yield compile_phase_refs, resources_phase_refs
296
+ end
297
+
298
+ #-----------------------------------------------------------------------#
299
+
300
+ # Adds the build files of the pods to the target and adds a reference to
301
+ # the frameworks of the Pods.
302
+ #
303
+ # @note The Frameworks are used only for presentation purposes as the
304
+ # xcconfig is the authoritative source about their information.
305
+ #
306
+ # @note Core Data model directories (.xcdatamodeld) defined in the `resources`
307
+ # property are currently added to the `Copy Resources` build phase like
308
+ # all other resources. The Xcode UI adds these to the `Compile Sources`
309
+ # build phase, but they will compile correctly either way.
310
+ #
311
+ # @return [void]
312
+ #
313
+ def add_files_to_build_phases(library_native_target, test_native_targets, app_native_targets)
314
+ target.file_accessors.each do |file_accessor|
315
+ consumer = file_accessor.spec_consumer
316
+
317
+ native_target = case consumer.spec.spec_type
318
+ when :library
319
+ library_native_target
320
+ when :test
321
+ test_native_target_from_spec(consumer.spec, test_native_targets)
322
+ when :app
323
+ app_native_targets[consumer.spec]
324
+ else
325
+ raise ArgumentError, "Unknown spec type #{consumer.spec.spec_type}."
326
+ end
327
+
328
+ next if native_target.is_a?(Xcodeproj::Project::Object::PBXAggregateTarget)
329
+
330
+ headers = file_accessor.headers
331
+ public_headers = file_accessor.public_headers.map(&:realpath)
332
+ project_headers = file_accessor.project_headers.map(&:realpath)
333
+ private_headers = file_accessor.private_headers.map(&:realpath)
334
+ other_source_files = file_accessor.other_source_files
335
+
336
+ {
337
+ true => file_accessor.arc_source_files,
338
+ false => file_accessor.non_arc_source_files,
339
+ }.each do |arc, source_files|
340
+ next if source_files.empty?
341
+ source_files = source_files - headers - other_source_files
342
+ swift_source_files, non_swift_source_files = source_files.partition { |file| file.extname == '.swift' }
343
+ {
344
+ :objc => non_swift_source_files,
345
+ :swift => swift_source_files,
346
+ }.each do |language, files|
347
+ compiler_flags = compiler_flags_for_consumer(consumer, arc, language)
348
+ file_refs = project_file_references_array(files, 'source')
349
+ native_target.add_file_references(file_refs, compiler_flags)
350
+ end
351
+ end
352
+
353
+ header_file_refs = project_file_references_array(headers, 'header')
354
+ native_target.add_file_references(header_file_refs) do |build_file|
355
+ add_header(file_accessor, build_file, public_headers, project_headers, private_headers, native_target)
356
+ end
357
+
358
+ other_file_refs = project_file_references_array(other_source_files, 'other source')
359
+ native_target.add_file_references(other_file_refs, nil)
360
+
361
+ next unless target.build_as_framework?
362
+
363
+ filter_resource_file_references(file_accessor.resources.flatten) do |compile_phase_refs, resource_phase_refs|
364
+ native_target.add_file_references(compile_phase_refs, nil)
365
+
366
+ if target.build_as_static_framework? && consumer.spec.library_specification?
367
+ resource_phase_refs = resource_phase_refs.select do |ref|
368
+ filename = ref.name || ref.path
369
+ Target.resource_extension_compilable?(File.extname(filename))
370
+ end
371
+ end
372
+
373
+ native_target.add_resources(resource_phase_refs)
374
+ end
375
+ end
376
+ end
377
+
378
+ # Adds the test targets for the library to the Pods project with the
379
+ # appropriate build configurations.
380
+ #
381
+ # @return [Array<PBXNativeTarget>] the test native targets created.
382
+ #
383
+ def add_test_targets
384
+ target.test_specs.map do |test_spec|
385
+ spec_consumer = test_spec.consumer(target.platform)
386
+ test_type = spec_consumer.test_type
387
+ product_type = target.product_type_for_test_type(test_type)
388
+ name = target.test_target_label(test_spec)
389
+ platform_name = target.platform.name
390
+ language = target.uses_swift_for_spec?(test_spec) ? :swift : :objc
391
+ product_basename = target.product_basename_for_spec(test_spec)
392
+ embedded_content_contains_swift = target.dependent_targets_for_test_spec(test_spec).any?(&:uses_swift?)
393
+ test_native_target = project.new_target(product_type, name, platform_name,
394
+ target.deployment_target_for_non_library_spec(test_spec), nil,
395
+ language, product_basename)
396
+ test_native_target.product_reference.name = name
397
+
398
+ target.user_build_configurations.each do |bc_name, type|
399
+ test_native_target.add_build_configuration(bc_name, type)
400
+ end
401
+
402
+ test_native_target.build_configurations.each do |configuration|
403
+ configuration.build_settings.merge!(custom_build_settings)
404
+ # target_installer will automatically add an empty `OTHER_LDFLAGS`. For test
405
+ # targets those are set via a test xcconfig file instead.
406
+ configuration.build_settings.delete('OTHER_LDFLAGS')
407
+ # target_installer will automatically set the product name to the module name if the target
408
+ # requires frameworks. For tests we always use the test target name as the product name
409
+ # irrelevant to whether we use frameworks or not.
410
+ configuration.build_settings['PRODUCT_NAME'] = name
411
+ # target_installer sets 'MACH_O_TYPE' for static frameworks ensure this does not propagate
412
+ # to test target.
413
+ configuration.build_settings.delete('MACH_O_TYPE')
414
+ # Use xcode default product module name, which is $(PRODUCT_NAME:c99extidentifier)
415
+ # this gives us always valid name that is distinct from the parent spec module name
416
+ # which allow tests to use either import or @testable import to access the parent framework
417
+ configuration.build_settings.delete('PRODUCT_MODULE_NAME')
418
+ # We must codesign iOS XCTest bundles that contain binary frameworks to allow them to be launchable in the simulator
419
+ unless target.platform == :osx
420
+ configuration.build_settings['CODE_SIGNING_REQUIRED'] = 'YES'
421
+ configuration.build_settings['CODE_SIGNING_ALLOWED'] = 'YES'
422
+ end
423
+ # For macOS we do not code sign the XCTest bundle because we do not code sign the frameworks either.
424
+ if target.platform == :osx
425
+ configuration.build_settings['CODE_SIGN_IDENTITY'] = ''
426
+ elsif target.platform == :ios
427
+ configuration.build_settings['CODE_SIGN_IDENTITY'] = 'iPhone Developer'
428
+ end
429
+ # Ensure swift stdlib gets copied in if needed, even when the target contains no swift files,
430
+ # because a dependency uses swift
431
+ configuration.build_settings['ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES'] = 'YES' if embedded_content_contains_swift
432
+ end
433
+
434
+ remove_pod_target_xcconfig_overrides_from_target(target.test_spec_build_settings_by_config[test_spec.name], test_native_target)
435
+
436
+ # Test native targets also need frameworks and resources to be copied over to their xctest bundle.
437
+ create_test_target_embed_frameworks_script(test_spec)
438
+ create_test_target_copy_resources_script(test_spec)
439
+
440
+ # Generate vanilla Info.plist for test target similar to the one Xcode generates for new test target.
441
+ # This creates valid test bundle accessible at the runtime, allowing tests to load bundle resources
442
+ # defined in podspec.
443
+ additional_entries = spec_consumer.info_plist
444
+ path = target.info_plist_path_for_spec(test_spec)
445
+ create_info_plist_file(path, test_native_target, '1.0', target.platform, :bndl, :additional_entries => additional_entries)
446
+
447
+ test_native_target
448
+ end
449
+ end
450
+
451
+ # Adds the test app host targets for the library to the Pods project with the
452
+ # appropriate build configurations.
453
+ #
454
+ # @return [Array<PBXNativeTarget>] the app host targets created.
455
+ #
456
+ def add_test_app_host_targets
457
+ target.test_spec_consumers.reject(&:requires_app_host?).select(&:app_host_name).each do |test_spec_consumer|
458
+ raise Informative, "`#{target.label}-#{test_spec_consumer.test_type}-Tests` manually specifies an app host but has not specified `requires_app_host = true`."
459
+ end
460
+
461
+ target.test_spec_consumers.select(&:requires_app_host?).reject(&:app_host_name).group_by { |consumer| target.app_host_target_label(consumer.spec) }.
462
+ map do |(_, target_name), _|
463
+ AppHostInstaller.new(sandbox, project, target.platform, target_name, target.pod_name, target_name).install!
464
+ end
465
+ end
466
+
467
+ # Adds the app targets for the library to the Pods project with the
468
+ # appropriate build configurations.
469
+ #
470
+ # @return [Hash{Specification => PBXNativeTarget}] the app native targets created, keyed by their app spec
471
+ #
472
+ def add_app_targets
473
+ target.app_specs.each_with_object({}) do |app_spec, hash|
474
+ spec_consumer = app_spec.consumer(target.platform)
475
+ spec_name = app_spec.parent.name
476
+ subspec_name = target.subspec_label(app_spec)
477
+ app_target_label = target.app_target_label(app_spec)
478
+ platform = Platform.new(target.platform.symbolic_name, target.deployment_target_for_non_library_spec(app_spec))
479
+ info_plist_entries = spec_consumer.info_plist
480
+ resources = target.file_accessors.find { |fa| fa.spec == app_spec }.resources
481
+ add_launchscreen_storyboard = resources.none? { |resource| resource.basename.to_s == 'LaunchScreen.storyboard' } && platform.name == :ios
482
+ embedded_content_contains_swift = target.dependent_targets_for_app_spec(app_spec).any?(&:uses_swift?)
483
+ app_native_target = AppHostInstaller.new(sandbox, project, platform, subspec_name, spec_name,
484
+ app_target_label, :add_main => false,
485
+ :add_launchscreen_storyboard => add_launchscreen_storyboard,
486
+ :info_plist_entries => info_plist_entries,
487
+ :product_basename => target.product_basename_for_spec(app_spec)).install!
488
+
489
+ app_native_target.product_reference.name = app_target_label
490
+ target.user_build_configurations.each do |bc_name, type|
491
+ app_native_target.add_build_configuration(bc_name, type)
492
+ end
493
+
494
+ app_native_target.build_configurations.each do |configuration|
495
+ configuration.build_settings.merge!(custom_build_settings)
496
+
497
+ # target_installer will automatically add an empty `OTHER_LDFLAGS`. For app
498
+ # targets those are set via an app xcconfig file instead.
499
+ configuration.build_settings.delete('OTHER_LDFLAGS')
500
+ # target_installer will automatically set the product name to the module name if the target
501
+ # requires frameworks. For apps we always use the app target name as the product name
502
+ # irrelevant to whether we use frameworks or not.
503
+ configuration.build_settings['PRODUCT_NAME'] = app_target_label
504
+ # target_installer sets 'MACH_O_TYPE' for static frameworks ensure this does not propagate
505
+ # to app target.
506
+ configuration.build_settings.delete('MACH_O_TYPE')
507
+ # Use xcode default product module name, which is $(PRODUCT_NAME:c99extidentifier)
508
+ # this gives us always valid name that is distinct from the parent spec module name
509
+ # which allow the app to use import to access the parent framework
510
+ configuration.build_settings.delete('PRODUCT_MODULE_NAME')
511
+
512
+ # We must codesign iOS app bundles that contain binary frameworks to allow them to be launchable in the simulator
513
+ unless target.platform == :osx
514
+ configuration.build_settings['CODE_SIGNING_REQUIRED'] = 'YES'
515
+ configuration.build_settings['CODE_SIGNING_ALLOWED'] = 'YES'
516
+ end
517
+ # For macOS we do not code sign the appbundle because we do not code sign the frameworks either.
518
+ configuration.build_settings['CODE_SIGN_IDENTITY'] = '' if target.platform == :osx
519
+ # For iOS, we delete the target_installer empty values that get set for libraries since CocoaPods will
520
+ # code sign the libraries manually but for apps this is not true.
521
+ if target.platform == :ios
522
+ configuration.build_settings.delete('CODE_SIGN_IDENTITY[sdk=appletvos*]')
523
+ configuration.build_settings.delete('CODE_SIGN_IDENTITY[sdk=iphoneos*]')
524
+ configuration.build_settings.delete('CODE_SIGN_IDENTITY[sdk=watchos*]')
525
+ end
526
+ # Ensure swift stdlib gets copied in if needed, even when the target contains no swift files,
527
+ # because a dependency uses swift
528
+ configuration.build_settings['ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES'] = 'YES' if embedded_content_contains_swift
529
+ end
530
+
531
+ remove_pod_target_xcconfig_overrides_from_target(target.app_spec_build_settings_by_config[app_spec.name], app_native_target)
532
+
533
+ create_app_target_embed_frameworks_script(app_spec)
534
+ create_app_target_copy_resources_script(app_spec)
535
+ add_resources_to_target(resources, app_native_target)
536
+
537
+ hash[app_spec] = app_native_target
538
+ end
539
+ end
540
+
541
+ # Adds the resources to the compile resources phase of the target.
542
+ #
543
+ # @param [Array<Pathname>] paths the paths to add to the target.
544
+ #
545
+ # @param [PBXNativeTarget] target the target resources are added to.
546
+ #
547
+ # @return [Boolean] whether any compile phase references were added.
548
+ #
549
+ def add_resources_to_target(paths, target)
550
+ filter_resource_file_references(paths) do |compile_phase_refs, resource_phase_refs|
551
+ # Resource bundles are only meant to have resources, so install everything
552
+ # into the resources phase. See note in filter_resource_file_references.
553
+ target.add_resources(resource_phase_refs + compile_phase_refs)
554
+ !compile_phase_refs.empty?
555
+ end
556
+ end
557
+
558
+ # Adds the resources of the Pods to the Pods project.
559
+ #
560
+ # @note The source files are grouped by Pod and in turn by subspec
561
+ # (recursively) in the resources group.
562
+ #
563
+ # @param [Array<Sandbox::FileAccessor>] file_accessors
564
+ # the file accessors list to generate resource bundles for.
565
+ #
566
+ # @return [Hash{String=>Array<PBXNativeTarget>}] the resource bundle native targets created.
567
+ #
568
+ def add_resources_bundle_targets(file_accessors)
569
+ file_accessors.each_with_object({}) do |file_accessor, hash|
570
+ hash[file_accessor.spec.name] = file_accessor.resource_bundles.map do |bundle_name, paths|
571
+ label = target.resources_bundle_target_label(bundle_name)
572
+ resource_bundle_target = project.new_resources_bundle(label, file_accessor.spec_consumer.platform_name, nil, bundle_name)
573
+ resource_bundle_target.product_reference.name = label
574
+ contains_compile_phase_refs = add_resources_to_target(paths, resource_bundle_target)
575
+
576
+ target.user_build_configurations.each do |bc_name, type|
577
+ resource_bundle_target.add_build_configuration(bc_name, type)
578
+ end
579
+ resource_bundle_target.deployment_target = if file_accessor.spec.non_library_specification?
580
+ target.deployment_target_for_non_library_spec(file_accessor.spec)
581
+ else
582
+ deployment_target
583
+ end
584
+ # Create Info.plist file for bundle
585
+ path = target.info_plist_path
586
+ path.dirname.mkdir unless path.dirname.exist?
587
+ info_plist_path = path.dirname + "ResourceBundle-#{bundle_name}-#{path.basename}"
588
+ create_info_plist_file(info_plist_path, resource_bundle_target, target.version, target.platform, :bndl)
589
+
590
+ resource_bundle_target.build_configurations.each do |configuration|
591
+ configuration.build_settings['PRODUCT_NAME'] = bundle_name
592
+ # Do not set the CONFIGURATION_BUILD_DIR for resource bundles that are only meant for test targets.
593
+ # This is because the test target itself also does not set this configuration build dir and it expects
594
+ # all bundles to be copied from the default path.
595
+ unless file_accessor.spec.test_specification?
596
+ configuration.build_settings['CONFIGURATION_BUILD_DIR'] = target.configuration_build_dir('$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)')
597
+ end
598
+
599
+ # Set the 'IBSC_MODULE' build settings for resource bundles so that Storyboards and Xibs can load
600
+ # classes from the parent module.
601
+ configuration.build_settings['IBSC_MODULE'] = target.product_module_name
602
+
603
+ # Set the `SWIFT_VERSION` build setting for resource bundles that could have resources that get
604
+ # compiled such as an `xcdatamodeld` file which has 'Swift' as its code generation language.
605
+ if contains_compile_phase_refs && file_accessors.any? { |fa| target.uses_swift_for_spec?(fa.spec) }
606
+ configuration.build_settings['SWIFT_VERSION'] = target.swift_version
607
+ end
608
+
609
+ # Set the correct device family for this bundle, based on the platform
610
+ device_family_by_platform = {
611
+ :ios => '1,2',
612
+ :tvos => '3',
613
+ :watchos => '1,2,4',
614
+ }
615
+
616
+ if (family = device_family_by_platform[target.platform.name])
617
+ configuration.build_settings['TARGETED_DEVICE_FAMILY'] = family
618
+ end
619
+ end
620
+
621
+ remove_pod_target_xcconfig_overrides_from_target(target.build_settings_by_config_for_spec(file_accessor.spec), resource_bundle_target)
622
+
623
+ resource_bundle_target
624
+ end
625
+ end
626
+ end
627
+
628
+ # Generates the contents of the xcconfig file and saves it to disk.
629
+ #
630
+ # @param [PBXNativeTarget] native_target
631
+ # the native target to link the xcconfig file into.
632
+ #
633
+ # @param [Array<PBXNativeTarget>] resource_bundle_targets
634
+ # the additional resource bundle targets to link the xcconfig file into.
635
+ #
636
+ # @return [void]
637
+ #
638
+ def create_xcconfig_file(native_target, resource_bundle_targets)
639
+ target.user_config_names_by_config_type.each do |config, names|
640
+ path = target.xcconfig_path(config)
641
+ update_changed_file(target.build_settings[config], path)
642
+ xcconfig_file_ref = add_file_to_support_group(path)
643
+
644
+ # also apply the private config to resource bundle targets.
645
+ apply_xcconfig_file_ref_to_targets([native_target] + resource_bundle_targets, xcconfig_file_ref, names)
646
+ end
647
+ end
648
+
649
+ # Generates the contents of the xcconfig file used for each test target type and saves it to disk.
650
+ #
651
+ # @param [Array<PBXNativeTarget>] test_native_targets
652
+ # the test native target to link the xcconfig file into.
653
+ #
654
+ # @param [Hash{String=>Array<PBXNativeTarget>}] test_resource_bundle_targets
655
+ # the additional test resource bundle targets to link the xcconfig file into.
656
+ #
657
+ # @return [void]
658
+ #
659
+ def create_test_xcconfig_files(test_native_targets, test_resource_bundle_targets)
660
+ target.test_specs.each do |test_spec|
661
+ spec_consumer = test_spec.consumer(target.platform)
662
+ test_type = spec_consumer.test_type
663
+ test_native_target = test_native_target_from_spec(spec_consumer.spec, test_native_targets)
664
+
665
+ target.user_config_names_by_config_type.each do |config, names|
666
+ path = target.xcconfig_path("#{test_type.capitalize}-#{target.subspec_label(test_spec)}.#{config}")
667
+ test_spec_build_settings = target.build_settings_for_spec(test_spec, :configuration => config)
668
+ update_changed_file(test_spec_build_settings, path)
669
+ test_xcconfig_file_ref = add_file_to_support_group(path)
670
+
671
+ # also apply the private config to resource bundle test targets related to this test spec.
672
+ scoped_test_resource_bundle_targets = test_resource_bundle_targets[test_spec.name]
673
+ apply_xcconfig_file_ref_to_targets([test_native_target] + scoped_test_resource_bundle_targets, test_xcconfig_file_ref, names)
674
+ end
675
+ end
676
+ end
677
+
678
+ # Creates a script that copies the resources to the bundle of the test target.
679
+ #
680
+ # @param [Specification] test_spec
681
+ # The test spec to create the copy resources script for.
682
+ #
683
+ # @return [void]
684
+ #
685
+ def create_test_target_copy_resources_script(test_spec)
686
+ path = target.copy_resources_script_path_for_spec(test_spec)
687
+ host_target_spec_names = target.app_host_dependent_targets_for_spec(test_spec).flat_map do |pt|
688
+ pt.specs.map(&:name)
689
+ end.uniq
690
+ resource_paths_by_config = target.user_build_configurations.each_with_object({}) do |(config_name, config), resources_by_config|
691
+ resources_by_config[config_name] = target.dependent_targets_for_test_spec(test_spec, :configuration => config).flat_map do |pod_target|
692
+ spec_paths_to_include = pod_target.library_specs.map(&:name)
693
+ spec_paths_to_include -= host_target_spec_names
694
+ spec_paths_to_include << test_spec.name if pod_target == target
695
+ pod_target.resource_paths.values_at(*spec_paths_to_include).flatten.compact
696
+ end
697
+ end
698
+ unless resource_paths_by_config.each_value.all?(&:empty?)
699
+ generator = Generator::CopyResourcesScript.new(resource_paths_by_config, target.platform)
700
+ update_changed_file(generator, path)
701
+ add_file_to_support_group(path)
702
+ end
703
+ end
704
+
705
+ # Creates a script that embeds the frameworks to the bundle of the test target.
706
+ #
707
+ # @param [Specification] test_spec
708
+ # The test spec to create the embed frameworks script for.
709
+ #
710
+ # @return [void]
711
+ #
712
+ def create_test_target_embed_frameworks_script(test_spec)
713
+ path = target.embed_frameworks_script_path_for_spec(test_spec)
714
+ host_target_spec_names = target.app_host_dependent_targets_for_spec(test_spec).flat_map do |pt|
715
+ pt.specs.map(&:name)
716
+ end.uniq
717
+ framework_paths_by_config = target.user_build_configurations.each_with_object({}) do |(config_name, config), paths_by_config|
718
+ paths_by_config[config_name] = target.dependent_targets_for_test_spec(test_spec, :configuration => config).flat_map do |pod_target|
719
+ spec_paths_to_include = pod_target.library_specs.map(&:name)
720
+ spec_paths_to_include -= host_target_spec_names
721
+ spec_paths_to_include << test_spec.name if pod_target == target
722
+ pod_target.framework_paths.values_at(*spec_paths_to_include).flatten.compact.uniq
723
+ end
724
+ end
725
+ xcframeworks_by_config = target.user_build_configurations.each_with_object({}) do |(config_name, config), paths_by_config|
726
+ paths_by_config[config_name] = target.dependent_targets_for_test_spec(test_spec, :configuration => config).flat_map do |pod_target|
727
+ spec_paths_to_include = pod_target.library_specs.map(&:name)
728
+ spec_paths_to_include -= host_target_spec_names
729
+ spec_paths_to_include << test_spec.name if pod_target == target
730
+ pod_target.xcframeworks.values_at(*spec_paths_to_include).flatten.compact.uniq
731
+ end
732
+ end
733
+ unless framework_paths_by_config.each_value.all?(&:empty?) && xcframeworks_by_config.each_value.all?(&:empty?)
734
+ generator = Generator::EmbedFrameworksScript.new(framework_paths_by_config, xcframeworks_by_config)
735
+ update_changed_file(generator, path)
736
+ add_file_to_support_group(path)
737
+ end
738
+ end
739
+
740
+ # Generates the contents of the xcconfig file used for each app target type and saves it to disk.
741
+ #
742
+ # @param [Hash{Specification => PBXNativeTarget}] app_native_targets
743
+ # the app native targets to link the xcconfig file into.
744
+ #
745
+ # @param [Hash{String=>Array<PBXNativeTarget>}] app_resource_bundle_targets
746
+ # the additional app resource bundle targets to link the xcconfig file into.
747
+ #
748
+ # @return [void]
749
+ #
750
+ def create_app_xcconfig_files(app_native_targets, app_resource_bundle_targets)
751
+ target.app_specs.each do |app_spec|
752
+ spec_consumer = app_spec.consumer(target.platform)
753
+ app_native_target = app_native_targets[spec_consumer.spec]
754
+
755
+ target.user_config_names_by_config_type.each do |config, names|
756
+ path = target.xcconfig_path("#{target.subspec_label(app_spec)}.#{config}")
757
+ app_spec_build_settings = target.build_settings_for_spec(app_spec, :configuration => config)
758
+ update_changed_file(app_spec_build_settings, path)
759
+ app_xcconfig_file_ref = add_file_to_support_group(path)
760
+
761
+ # also apply the private config to resource bundle app targets related to this app spec.
762
+ scoped_app_resource_bundle_targets = app_resource_bundle_targets[app_spec.name]
763
+ apply_xcconfig_file_ref_to_targets([app_native_target] + scoped_app_resource_bundle_targets, app_xcconfig_file_ref, names)
764
+ end
765
+ end
766
+ end
767
+
768
+ # Creates a script that copies the resources to the bundle of the app target.
769
+ #
770
+ # @param [Specification] app_spec
771
+ # The app spec to create the copy resources script for.
772
+ #
773
+ # @return [void]
774
+ #
775
+ def create_app_target_copy_resources_script(app_spec)
776
+ path = target.copy_resources_script_path_for_spec(app_spec)
777
+ resource_paths_by_config = target.user_build_configurations.each_with_object({}) do |(config_name, config), resources_by_config|
778
+ pod_targets = target.dependent_targets_for_app_spec(app_spec, :configuration => config)
779
+ resources_by_config[config_name] = pod_targets.flat_map do |pod_target|
780
+ spec_paths_to_include = pod_target.library_specs.map(&:name)
781
+ spec_paths_to_include << app_spec.name if pod_target == target
782
+ pod_target.resource_paths.values_at(*spec_paths_to_include).flatten.compact
783
+ end
784
+ end
785
+ unless resource_paths_by_config.each_value.all?(&:empty?)
786
+ generator = Generator::CopyResourcesScript.new(resource_paths_by_config, target.platform)
787
+ update_changed_file(generator, path)
788
+ add_file_to_support_group(path)
789
+ end
790
+ end
791
+
792
+ # Creates a script that embeds the frameworks to the bundle of the app target.
793
+ #
794
+ # @param [Specification] app_spec
795
+ # The app spec to create the embed frameworks script for.
796
+ #
797
+ # @return [void]
798
+ #
799
+ def create_app_target_embed_frameworks_script(app_spec)
800
+ path = target.embed_frameworks_script_path_for_spec(app_spec)
801
+ framework_paths_by_config = target.user_build_configurations.each_with_object({}) do |(config_name, config), paths_by_config|
802
+ paths_by_config[config_name] = target.dependent_targets_for_app_spec(app_spec, :configuration => config).flat_map do |pod_target|
803
+ spec_paths_to_include = pod_target.library_specs.map(&:name)
804
+ spec_paths_to_include << app_spec.name if pod_target == target
805
+ pod_target.framework_paths.values_at(*spec_paths_to_include).flatten.compact.uniq
806
+ end
807
+ end
808
+ xcframeworks_by_config = target.user_build_configurations.each_with_object({}) do |(config_name, config), paths_by_config|
809
+ paths_by_config[config_name] = target.dependent_targets_for_app_spec(app_spec, :configuration => config).flat_map do |pod_target|
810
+ spec_paths_to_include = pod_target.library_specs.map(&:name)
811
+ spec_paths_to_include << app_spec.name if pod_target == target
812
+ pod_target.xcframeworks.values_at(*spec_paths_to_include).flatten.compact.uniq
813
+ end
814
+ end
815
+
816
+ unless framework_paths_by_config.each_value.all?(&:empty?) && xcframeworks_by_config.each_value.all?(&:empty?)
817
+ generator = Generator::EmbedFrameworksScript.new(framework_paths_by_config, xcframeworks_by_config)
818
+ update_changed_file(generator, path)
819
+ add_file_to_support_group(path)
820
+ end
821
+ end
822
+
823
+ # Creates a script that copies and strips vendored dSYMs and bcsymbolmaps.
824
+ #
825
+ # @return [void]
826
+ #
827
+ def create_copy_dsyms_script
828
+ dsym_paths = PodTargetInstaller.dsym_paths(target)
829
+ bcsymbolmap_paths = PodTargetInstaller.bcsymbolmap_paths(target)
830
+ path = target.copy_dsyms_script_path
831
+ unless dsym_paths.empty? && bcsymbolmap_paths.empty?
832
+ generator = Generator::CopydSYMsScript.new(dsym_paths, bcsymbolmap_paths)
833
+ update_changed_file(generator, path)
834
+ add_file_to_support_group(path)
835
+ end
836
+ end
837
+
838
+ # Creates a script that copies the appropriate xcframework slice to the build dir.
839
+ #
840
+ # @note We can't use Xcode default link libraries phase, because
841
+ # we need to ensure that we only copy the frameworks which are
842
+ # relevant for the current build configuration.
843
+ #
844
+ # @return [void]
845
+ #
846
+ def create_copy_xcframeworks_script
847
+ path = target.copy_xcframeworks_script_path
848
+ generator = Generator::CopyXCFrameworksScript.new(target.xcframeworks.values.flatten, sandbox.root, target.platform)
849
+ update_changed_file(generator, path)
850
+ add_file_to_support_group(path)
851
+ end
852
+
853
+ # Creates a build phase which links the versioned header folders
854
+ # of the OS X framework into the framework bundle's root directory.
855
+ # This is only necessary because the way how headers are copied
856
+ # via custom copy file build phases in combination with
857
+ # header_mappings_dir interferes with xcodebuild's expectations
858
+ # about the existence of private or public headers.
859
+ #
860
+ # @param [PBXNativeTarget] native_target
861
+ # the native target to add the script phase into.
862
+ #
863
+ # @return [void]
864
+ #
865
+ def create_build_phase_to_symlink_header_folders(native_target)
866
+ # This is required on iOS for Catalyst, which uses macOS framework layouts
867
+ return unless (target.platform.name == :osx || target.platform.name == :ios) && any_header_mapping_dirs?
868
+
869
+ build_phase = native_target.new_shell_script_build_phase('Create Symlinks to Header Folders')
870
+ build_phase.shell_script = <<-eos.strip_heredoc
871
+ cd "$CONFIGURATION_BUILD_DIR/$WRAPPER_NAME" || exit 1
872
+ if [ ! -d Versions ]; then
873
+ # Not a versioned framework, so no need to do anything
874
+ exit 0
875
+ fi
876
+
877
+ public_path="${PUBLIC_HEADERS_FOLDER_PATH\#\$CONTENTS_FOLDER_PATH/}"
878
+ if [ ! -f "$public_path" ]; then
879
+ ln -fs "${PUBLIC_HEADERS_FOLDER_PATH\#$WRAPPER_NAME/}" "$public_path"
880
+ fi
881
+
882
+ private_path="${PRIVATE_HEADERS_FOLDER_PATH\#\$CONTENTS_FOLDER_PATH/}"
883
+ if [ ! -f "$private_path" ]; then
884
+ ln -fs "${PRIVATE_HEADERS_FOLDER_PATH\#\$WRAPPER_NAME/}" "$private_path"
885
+ fi
886
+ eos
887
+ end
888
+
889
+ ENABLE_OBJECT_USE_OBJC_FROM = {
890
+ :ios => Version.new('6'),
891
+ :osx => Version.new('10.8'),
892
+ :watchos => Version.new('2.0'),
893
+ :tvos => Version.new('9.0'),
894
+ }.freeze
895
+
896
+ # Returns the compiler flags for the source files of the given specification.
897
+ #
898
+ # The following behavior is regarding the `OS_OBJECT_USE_OBJC` flag. When
899
+ # set to `0`, it will allow code to use `dispatch_release()` on >= iOS 6.0
900
+ # and OS X 10.8.
901
+ #
902
+ # * New libraries that do *not* require ARC don’t need to care about this
903
+ # issue at all.
904
+ #
905
+ # * New libraries that *do* require ARC _and_ have a deployment target of
906
+ # >= iOS 6.0 or OS X 10.8:
907
+ #
908
+ # These no longer use `dispatch_release()` and should *not* have the
909
+ # `OS_OBJECT_USE_OBJC` flag set to `0`.
910
+ #
911
+ # **Note:** this means that these libraries *have* to specify the
912
+ # deployment target in order to function well.
913
+ #
914
+ # * New libraries that *do* require ARC, but have a deployment target of
915
+ # < iOS 6.0 or OS X 10.8:
916
+ #
917
+ # These contain `dispatch_release()` calls and as such need the
918
+ # `OS_OBJECT_USE_OBJC` flag set to `1`.
919
+ #
920
+ # **Note:** libraries that do *not* specify a platform version are
921
+ # assumed to have a deployment target of < iOS 6.0 or OS X 10.8.
922
+ #
923
+ # For more information, see: https://opensource.apple.com/source/libdispatch/libdispatch-228.18/os/object.h
924
+ #
925
+ # @param [Specification::Consumer] consumer
926
+ # The consumer for the specification for which the compiler flags
927
+ # are needed.
928
+ #
929
+ # @param [Boolean] arc
930
+ # Whether the arc is enabled or not.
931
+ #
932
+ # @param [Symbol] language
933
+ # The language these compiler warnings are for. Can be either :objc or :swift.
934
+ #
935
+ # @return [String] The compiler flags.
936
+ #
937
+ def compiler_flags_for_consumer(consumer, arc, language)
938
+ flags = consumer.compiler_flags.dup
939
+ if !arc && language == :objc
940
+ flags << '-fno-objc-arc'
941
+ else
942
+ platform_name = consumer.platform_name
943
+ spec_deployment_target = consumer.spec.deployment_target(platform_name)
944
+ if spec_deployment_target.nil? || Version.new(spec_deployment_target) < ENABLE_OBJECT_USE_OBJC_FROM[platform_name]
945
+ flags << '-DOS_OBJECT_USE_OBJC=0'
946
+ end
947
+ end
948
+ if target.inhibit_warnings? && language == :objc
949
+ flags << '-w -Xanalyzer -analyzer-disable-all-checks'
950
+ end
951
+ flags * ' '
952
+ end
953
+
954
+ def apply_xcconfig_file_ref_to_targets(targets, xcconfig_file_ref, configurations)
955
+ targets.each do |config_target|
956
+ config_target.build_configurations.each do |configuration|
957
+ next unless configurations.include?(configuration.name)
958
+ configuration.base_configuration_reference = xcconfig_file_ref
959
+ end
960
+ end
961
+ end
962
+
963
+ def create_module_map(native_target)
964
+ return super(native_target) unless custom_module_map
965
+
966
+ path = target.module_map_path_to_write
967
+ UI.message "- Copying module map file to #{UI.path(path)}" do
968
+ contents = custom_module_map.read
969
+ unless target.build_as_framework?
970
+ contents.gsub!(/^(\s*)framework\s+(module[^{}]+){/, '\1\2{')
971
+ end
972
+ generator = Generator::Constant.new(contents)
973
+ update_changed_file(generator, path)
974
+ add_file_to_support_group(path)
975
+
976
+ linked_path = target.module_map_path
977
+ if path != linked_path
978
+ linked_path.dirname.mkpath
979
+ source = path.relative_path_from(linked_path.dirname)
980
+ FileUtils.ln_sf(source, linked_path)
981
+ end
982
+
983
+ relative_path = target.module_map_path.relative_path_from(sandbox.root).to_s
984
+ native_target.build_configurations.each do |c|
985
+ c.build_settings['MODULEMAP_FILE'] = relative_path.to_s
986
+ end
987
+ end
988
+ end
989
+
990
+ def module_map_additional_headers
991
+ return [] unless umbrella_header_paths
992
+
993
+ other_paths = umbrella_header_paths - [target.umbrella_header_path]
994
+ other_paths.map do |module_map_path|
995
+ # exclude other targets umbrella headers, to avoid
996
+ # incomplete umbrella warnings
997
+ Generator::ModuleMap::Header.new(module_map_path.basename, nil, nil, nil, true)
998
+ end
999
+ end
1000
+
1001
+ def create_umbrella_header(native_target)
1002
+ super(native_target) unless custom_module_map
1003
+ end
1004
+
1005
+ def custom_module_map
1006
+ @custom_module_map ||= target.file_accessors.first.module_map
1007
+ end
1008
+
1009
+ def project_file_references_array(files, file_type)
1010
+ error_message_for_missing_reference = lambda do |sf, target|
1011
+ "Unable to find #{file_type} ref for `#{sf.basename}` for target `#{target.name}`."
1012
+ end
1013
+ files.map do |sf|
1014
+ begin
1015
+ project.reference_for_path(sf).tap do |ref|
1016
+ raise Informative, error_message_for_missing_reference.call(sf, target) unless ref
1017
+ end
1018
+ rescue Errno::ENOENT
1019
+ # Normalize the error for Ruby < 2.7. Ruby 2.7 can crash on a different call of real path compared
1020
+ # to older versions. This ensures that the error message is consistent.
1021
+ raise Informative, error_message_for_missing_reference.call(sf, target)
1022
+ end
1023
+ end
1024
+ end
1025
+
1026
+ def any_header_mapping_dirs?
1027
+ return @any_header_mapping_dirs if defined?(@any_header_mapping_dirs)
1028
+ @any_header_mapping_dirs = target.file_accessors.any? { |fa| fa.spec_consumer.header_mappings_dir }
1029
+ end
1030
+
1031
+ def header_mappings_dir(file_accessor)
1032
+ @header_mappings_dirs ||= {}
1033
+ return @header_mappings_dirs[file_accessor] if @header_mappings_dirs.key?(file_accessor)
1034
+ @header_mappings_dirs[file_accessor] = if dir = file_accessor.spec_consumer.header_mappings_dir
1035
+ file_accessor.path_list.root + dir
1036
+ end
1037
+ end
1038
+
1039
+ def add_header(file_accessor, build_file, public_headers, project_headers, private_headers, native_target)
1040
+ file_ref = build_file.file_ref
1041
+ acl = if !target.build_as_framework? # Headers are already rooted at ${PODS_ROOT}/Headers/P*/[pod]/...
1042
+ 'Project'
1043
+ elsif public_headers.include?(file_ref.real_path)
1044
+ 'Public'
1045
+ elsif project_headers.include?(file_ref.real_path)
1046
+ 'Project'
1047
+ elsif private_headers.include?(file_ref.real_path)
1048
+ 'Private'
1049
+ else
1050
+ 'Project'
1051
+ end
1052
+
1053
+ if target.build_as_framework? && !header_mappings_dir(file_accessor).nil? && acl != 'Project'
1054
+ relative_path = if mapping_dir = header_mappings_dir(file_accessor)
1055
+ file_ref.real_path.relative_path_from(mapping_dir)
1056
+ else
1057
+ file_ref.real_path.relative_path_from(file_accessor.path_list.root)
1058
+ end
1059
+ compile_build_phase_index = native_target.build_phases.index do |bp|
1060
+ bp.is_a?(Xcodeproj::Project::Object::PBXSourcesBuildPhase)
1061
+ end
1062
+ sub_dir = relative_path.dirname
1063
+ copy_phase_name = "Copy #{sub_dir} #{acl} Headers"
1064
+ copy_phase = native_target.copy_files_build_phases.find { |bp| bp.name == copy_phase_name } ||
1065
+ native_target.new_copy_files_build_phase(copy_phase_name)
1066
+ native_target.build_phases.move(copy_phase, compile_build_phase_index - 1) unless compile_build_phase_index.nil?
1067
+ copy_phase.symbol_dst_subfolder_spec = :products_directory
1068
+ copy_phase.dst_path = "$(#{acl.upcase}_HEADERS_FOLDER_PATH)/#{sub_dir}"
1069
+ copy_phase.add_file_reference(file_ref, true)
1070
+ else
1071
+ build_file.settings ||= {}
1072
+ build_file.settings['ATTRIBUTES'] = [acl]
1073
+ end
1074
+ end
1075
+
1076
+ def support_files_group
1077
+ pod_name = target.pod_name
1078
+ dir = target.support_files_dir
1079
+ project.pod_support_files_group(pod_name, dir)
1080
+ end
1081
+
1082
+ def test_native_target_from_spec(spec, test_native_targets)
1083
+ test_target_label = target.test_target_label(spec)
1084
+ test_native_targets.find do |test_native_target|
1085
+ test_native_target.name == test_target_label
1086
+ end
1087
+ end
1088
+
1089
+ # Adds a placeholder native target for the library to the Pods project with the
1090
+ # appropriate build configurations.
1091
+ #
1092
+ # @return [PBXAggregateTarget] the native target that was added.
1093
+ #
1094
+ def add_placeholder_target
1095
+ native_target = project.new_aggregate_target(target.label, [], target.platform.name, deployment_target)
1096
+ target.user_build_configurations.each do |bc_name, type|
1097
+ native_target.add_build_configuration(bc_name, type)
1098
+ end
1099
+ unless target.archs.empty?
1100
+ native_target.build_configurations.each do |configuration|
1101
+ configuration.build_settings['ARCHS'] = target.archs
1102
+ end
1103
+ end
1104
+ native_target
1105
+ end
1106
+
1107
+ # Adds a shell script phase, intended only for library targets that contain swift,
1108
+ # to copy the ObjC compatibility header (the -Swift.h file that the swift compiler generates)
1109
+ # to the built products directory. Additionally, the script phase copies the module map, appending a `.Swift`
1110
+ # submodule that references the (moved) compatibility header. Since the module map has been moved, the umbrella header
1111
+ # is _also_ copied, so that it is sitting next to the module map. This is necessary for a successful archive build.
1112
+ #
1113
+ # @param [PBXNativeTarget] native_target
1114
+ # the native target to add the Swift static library script phase into.
1115
+ #
1116
+ # @return [Void]
1117
+ #
1118
+ def add_swift_library_compatibility_header_phase(native_target)
1119
+ if custom_module_map
1120
+ raise Informative, 'Using Swift static libraries with custom module maps is currently not supported. ' \
1121
+ "Please build `#{target.label}` as a framework or remove the custom module map."
1122
+ end
1123
+
1124
+ build_phase = native_target.new_shell_script_build_phase('Copy generated compatibility header')
1125
+
1126
+ relative_module_map_path = target.module_map_path.relative_path_from(target.sandbox.root)
1127
+ relative_umbrella_header_path = target.umbrella_header_path.relative_path_from(target.sandbox.root)
1128
+
1129
+ build_phase.shell_script = <<-SH.strip_heredoc
1130
+ COMPATIBILITY_HEADER_PATH="${BUILT_PRODUCTS_DIR}/Swift Compatibility Header/${PRODUCT_MODULE_NAME}-Swift.h"
1131
+ MODULE_MAP_PATH="${BUILT_PRODUCTS_DIR}/${PRODUCT_MODULE_NAME}.modulemap"
1132
+
1133
+ ditto "${DERIVED_SOURCES_DIR}/${PRODUCT_MODULE_NAME}-Swift.h" "${COMPATIBILITY_HEADER_PATH}"
1134
+ ditto "${PODS_ROOT}/#{relative_module_map_path}" "${MODULE_MAP_PATH}"
1135
+ ditto "${PODS_ROOT}/#{relative_umbrella_header_path}" "${BUILT_PRODUCTS_DIR}"
1136
+ printf "\\n\\nmodule ${PRODUCT_MODULE_NAME}.Swift {\\n header \\"${COMPATIBILITY_HEADER_PATH}\\"\\n requires objc\\n}\\n" >> "${MODULE_MAP_PATH}"
1137
+ SH
1138
+ build_phase.input_paths = %W(
1139
+ ${DERIVED_SOURCES_DIR}/${PRODUCT_MODULE_NAME}-Swift.h
1140
+ ${PODS_ROOT}/#{relative_module_map_path}
1141
+ ${PODS_ROOT}/#{relative_umbrella_header_path}
1142
+ )
1143
+ build_phase.output_paths = %W(
1144
+ ${BUILT_PRODUCTS_DIR}/${PRODUCT_MODULE_NAME}.modulemap
1145
+ ${BUILT_PRODUCTS_DIR}/#{relative_umbrella_header_path.basename}
1146
+ ${BUILT_PRODUCTS_DIR}/Swift\ Compatibility\ Header/${PRODUCT_MODULE_NAME}-Swift.h
1147
+ )
1148
+ end
1149
+
1150
+ def validate_targets_contain_sources(native_targets)
1151
+ native_targets.each do |native_target|
1152
+ next unless native_target.source_build_phase.files.empty?
1153
+ raise Informative, "Unable to install the `#{target.label}` pod, because the `#{native_target}` target in Xcode would have no sources to compile."
1154
+ end
1155
+ end
1156
+
1157
+ # Raises if a vendored xcframework contains frameworks of mixed linkage or mixed packaging
1158
+ #
1159
+ def validate_xcframeworks
1160
+ target.xcframeworks.each_value do |xcframeworks|
1161
+ xcframeworks.each do |xcframework|
1162
+ if xcframework.slices.empty?
1163
+ raise Informative, "Unable to install vendored xcframework `#{xcframework.name}` for Pod `#{target.label}` because it does not contain any binaries."
1164
+ end
1165
+ if xcframework.build_type.dynamic_library?
1166
+ raise Informative, <<-MSG.strip_heredoc
1167
+ Unable to install vendored xcframework `#{xcframework.name}` for Pod `#{target.label}` because it contains dynamic libraries which are not supported.
1168
+ Use dynamic frameworks for dynamic linking instead.
1169
+ MSG
1170
+ end
1171
+ if xcframework.build_type.static_library?
1172
+ binary_names = xcframework.slices.map { |slice| File.basename(slice.binary_path, File.extname(slice.binary_path)) }.uniq
1173
+ if binary_names.size > 1
1174
+ raise Informative, <<-MSG.strip_heredoc
1175
+ Unable to install vendored xcframework `#{xcframework.name}` for Pod `#{target.label}` because it contains static libraries
1176
+ with differing binary names: #{binary_names.to_sentence}.
1177
+ MSG
1178
+ end
1179
+ end
1180
+ dynamic_slices, static_slices = xcframework.slices.partition(&:dynamic?)
1181
+ if !dynamic_slices.empty? && !static_slices.empty?
1182
+ raise Informative, "Unable to install vendored xcframework `#{xcframework.name}` for Pod `#{target.label}`, because it contains both static and dynamic frameworks."
1183
+ end
1184
+ library_slices, framework_slices = xcframework.slices.partition(&:library?)
1185
+ if !library_slices.empty? && !framework_slices.empty?
1186
+ raise Informative, "Unable to install vendored xcframework `#{xcframework.name}` for Pod `#{target.label}`, because it contains both libraries and frameworks."
1187
+ end
1188
+ end
1189
+ end
1190
+ end
1191
+
1192
+ #-----------------------------------------------------------------------#
1193
+
1194
+ class << self
1195
+ # @param [PodTarget] target the target to be installed
1196
+ #
1197
+ # @return [Array<String>] the dSYM paths for the given target
1198
+ #
1199
+ def dsym_paths(target)
1200
+ dsym_paths = target.framework_paths.values.flatten.reject { |fmwk_path| fmwk_path.dsym_path.nil? }.map(&:dsym_path)
1201
+ dsym_paths.concat(target.xcframeworks.values.flatten.flat_map { |xcframework| xcframework_dsyms(xcframework.path) })
1202
+ dsym_paths.map do |dsym_path|
1203
+ dsym_pathname = Pathname(dsym_path)
1204
+ dsym_path = "${PODS_ROOT}/#{dsym_pathname.relative_path_from(target.sandbox.root)}" unless dsym_pathname.relative?
1205
+ dsym_path
1206
+ end
1207
+ end
1208
+
1209
+ # @param [PodTarget] target the target to be installed
1210
+ #
1211
+ # @return [Array<String>] the bcsymbolmap paths for the given target
1212
+ #
1213
+ def bcsymbolmap_paths(target)
1214
+ target.framework_paths.values.flatten.reject do |fmwk_path|
1215
+ fmwk_path.bcsymbolmap_paths.nil?
1216
+ end.flat_map(&:bcsymbolmap_paths).uniq
1217
+ end
1218
+
1219
+ # @param [Pathname] xcframework_path
1220
+ # the base path of the .xcframework bundle
1221
+ #
1222
+ # @return [Array<Pathname>] all found .dSYM paths
1223
+ #
1224
+ def xcframework_dsyms(xcframework_path)
1225
+ basename = File.basename(xcframework_path, '.xcframework')
1226
+ dsym_basename = basename + '.dSYMs'
1227
+ path = xcframework_path.dirname + dsym_basename
1228
+ if File.directory?(path)
1229
+ Dir.glob(path + '*.dSYM')
1230
+ else
1231
+ []
1232
+ end
1233
+ end
1234
+ end
1235
+ end
1236
+ end
1237
+ end
1238
+ end
1239
+ end