cocoapods 1.9.2 → 1.10.0

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 (53) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +235 -6
  3. data/README.md +2 -1
  4. data/lib/cocoapods.rb +3 -1
  5. data/lib/cocoapods/command.rb +12 -2
  6. data/lib/cocoapods/command/lib/lint.rb +12 -3
  7. data/lib/cocoapods/command/repo/push.rb +1 -1
  8. data/lib/cocoapods/command/repo/update.rb +11 -0
  9. data/lib/cocoapods/command/spec/lint.rb +12 -3
  10. data/lib/cocoapods/config.rb +17 -0
  11. data/lib/cocoapods/downloader/cache.rb +2 -2
  12. data/lib/cocoapods/gem_version.rb +1 -1
  13. data/lib/cocoapods/generator/app_target_helper.rb +10 -2
  14. data/lib/cocoapods/generator/copy_dsyms_script.rb +56 -0
  15. data/lib/cocoapods/generator/copy_resources_script.rb +2 -14
  16. data/lib/cocoapods/generator/copy_xcframework_script.rb +245 -0
  17. data/lib/cocoapods/generator/embed_frameworks_script.rb +125 -212
  18. data/lib/cocoapods/generator/script_phase_constants.rb +99 -0
  19. data/lib/cocoapods/installer.rb +70 -3
  20. data/lib/cocoapods/installer/analyzer.rb +17 -8
  21. data/lib/cocoapods/installer/analyzer/target_inspection_result.rb +1 -1
  22. data/lib/cocoapods/installer/base_install_hooks_context.rb +135 -0
  23. data/lib/cocoapods/installer/installation_options.rb +5 -0
  24. data/lib/cocoapods/installer/pod_source_installer.rb +2 -1
  25. data/lib/cocoapods/installer/post_install_hooks_context.rb +1 -127
  26. data/lib/cocoapods/installer/post_integrate_hooks_context.rb +9 -0
  27. data/lib/cocoapods/installer/project_cache/project_metadata_cache.rb +4 -0
  28. data/lib/cocoapods/installer/sandbox_dir_cleaner.rb +2 -1
  29. data/lib/cocoapods/installer/user_project_integrator/target_integrator.rb +132 -111
  30. data/lib/cocoapods/installer/xcode/pods_project_generator.rb +45 -6
  31. data/lib/cocoapods/installer/xcode/pods_project_generator/aggregate_target_installer.rb +13 -27
  32. data/lib/cocoapods/installer/xcode/pods_project_generator/app_host_installer.rb +5 -1
  33. data/lib/cocoapods/installer/xcode/pods_project_generator/file_references_installer.rb +2 -1
  34. data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_dependency_installer.rb +8 -6
  35. data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_installer.rb +180 -59
  36. data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_integrator.rb +61 -30
  37. data/lib/cocoapods/installer/xcode/pods_project_generator/project_generator.rb +3 -2
  38. data/lib/cocoapods/installer/xcode/pods_project_generator/target_installation_result.rb +5 -7
  39. data/lib/cocoapods/installer/xcode/pods_project_generator_result.rb +19 -0
  40. data/lib/cocoapods/installer/xcode/target_validator.rb +1 -1
  41. data/lib/cocoapods/sources_manager.rb +2 -1
  42. data/lib/cocoapods/target.rb +44 -2
  43. data/lib/cocoapods/target/aggregate_target.rb +35 -0
  44. data/lib/cocoapods/target/build_settings.rb +94 -18
  45. data/lib/cocoapods/target/pod_target.rb +85 -11
  46. data/lib/cocoapods/user_interface/error_report.rb +1 -1
  47. data/lib/cocoapods/user_interface/inspector_reporter.rb +3 -10
  48. data/lib/cocoapods/validator.rb +37 -11
  49. data/lib/cocoapods/xcode/framework_paths.rb +1 -1
  50. data/lib/cocoapods/xcode/xcframework.rb +17 -4
  51. data/lib/cocoapods/xcode/xcframework/xcframework_slice.rb +81 -3
  52. metadata +31 -53
  53. data/lib/cocoapods/generator/prepare_artifacts_script.rb +0 -257
@@ -79,13 +79,14 @@ module Pod
79
79
  #
80
80
  # @param [PBXProject] project The project to configure schemes for.
81
81
  # @param [Array<PodTarget>] pod_targets The pod targets within that project to configure their schemes.
82
+ # @param [PodsProjectGeneratorResult] generator_result the result of the project generation
82
83
  #
83
84
  # @return [void]
84
85
  #
85
- def configure_schemes(project, pod_targets)
86
+ def configure_schemes(project, pod_targets, generator_result)
86
87
  pod_targets.each do |pod_target|
87
88
  share_scheme = pod_target.should_build? && share_scheme_for_development_pod?(pod_target.pod_name) && sandbox.local?(pod_target.pod_name)
88
- configure_schemes_for_pod_target(project, pod_target, share_scheme)
89
+ configure_schemes_for_pod_target(project, pod_target, share_scheme, generator_result)
89
90
  end
90
91
  end
91
92
 
@@ -143,8 +144,10 @@ module Pod
143
144
  pod_installations_to_integrate = pod_target_installation_results.values.select do |pod_target_installation_result|
144
145
  pod_target = pod_target_installation_result.target
145
146
  !pod_target_installation_result.test_native_targets.empty? ||
146
- !pod_target_installation_result.app_native_targets.empty? ||
147
- pod_target.contains_script_phases?
147
+ !pod_target_installation_result.app_native_targets.empty? ||
148
+ pod_target.contains_script_phases? ||
149
+ pod_target.framework_paths.values.flatten.any? { |paths| !paths.dsym_path.nil? } ||
150
+ pod_target.xcframeworks.values.any? { |xcframeworks| !xcframeworks.empty? }
148
151
  end
149
152
  return if pod_installations_to_integrate.empty?
150
153
 
@@ -218,14 +221,35 @@ module Pod
218
221
  end
219
222
  end
220
223
 
221
- def configure_schemes_for_pod_target(project, pod_target, share_scheme)
224
+ # @param [Project] project
225
+ # the project of the pod target
226
+ #
227
+ # @param [Pod::PodTarget] pod_target
228
+ # the pod target for which to configure schemes
229
+ #
230
+ # @param [Boolean] share_scheme
231
+ # whether the created schemes should be shared
232
+ #
233
+ # @param [PodsProjectGeneratorResult] generator_result
234
+ # the project generation result
235
+ #
236
+ def configure_schemes_for_pod_target(project, pod_target, share_scheme, generator_result)
222
237
  # Ignore subspecs because they do not provide a scheme configuration due to the fact that they are always
223
238
  # merged with the root spec scheme.
224
239
  specs = [pod_target.root_spec] + pod_target.test_specs + pod_target.app_specs
240
+ hosted_test_specs_by_host = Hash.new do |hash, key|
241
+ hash[key] = []
242
+ end
243
+ pod_target.test_app_hosts_by_spec.each do |spec, (host_spec, host_target)|
244
+ if host_target == pod_target
245
+ hosted_test_specs_by_host[host_spec] << spec
246
+ end
247
+ end
248
+ is_custom_host = !hosted_test_specs_by_host.empty?
225
249
  specs.each do |spec|
226
250
  scheme_name = spec.spec_type == :library ? pod_target.label : pod_target.non_library_spec_label(spec)
227
251
  scheme_configuration = pod_target.scheme_for_spec(spec)
228
- unless scheme_configuration.empty?
252
+ if !scheme_configuration.empty? || is_custom_host
229
253
  scheme_path = Xcodeproj::XCScheme.user_data_dir(project.path) + "#{scheme_name}.xcscheme"
230
254
  scheme = Xcodeproj::XCScheme.new(scheme_path)
231
255
  command_line_arguments = scheme.launch_action.command_line_arguments
@@ -241,6 +265,21 @@ module Pod
241
265
  if scheme_configuration.key?(:code_coverage)
242
266
  scheme.test_action.code_coverage_enabled = scheme_configuration[:code_coverage]
243
267
  end
268
+
269
+ hosted_test_specs_by_host[spec].each do |hosted_spec|
270
+ # We are an app spec which hosts this test spec.
271
+ # Include the test specs's test bundle within our scheme's test action
272
+ native_target = generator_result.native_target_for_spec(hosted_spec)
273
+ testable = Xcodeproj::XCScheme::TestAction::TestableReference.new(native_target)
274
+ scheme.test_action.add_testable(testable)
275
+ end
276
+
277
+ if spec.test_specification?
278
+ # Default to using the test bundle to expand variables
279
+ native_target_for_expansion = generator_result.native_target_for_spec(spec)
280
+ macro_expansion = Xcodeproj::XCScheme::MacroExpansion.new(native_target_for_expansion)
281
+ scheme.launch_action.add_macro_expansion(macro_expansion)
282
+ end
244
283
  scheme.save!
245
284
  end
246
285
  Xcodeproj::XCScheme.share_scheme(project.path, scheme_name) if share_scheme
@@ -6,6 +6,10 @@ module Pod
6
6
  # project and the relative support files.
7
7
  #
8
8
  class AggregateTargetInstaller < TargetInstaller
9
+ # @return [AggregateTarget] @see TargetInstaller#target
10
+ #
11
+ attr_reader :target
12
+
9
13
  # Creates the target in the Pods project and the relative support files.
10
14
  #
11
15
  # @return [TargetInstallationResult] the result of the installation of this target.
@@ -30,8 +34,7 @@ module Pod
30
34
  # cause an App Store rejection because frameworks cannot be
31
35
  # embedded in embedded targets.
32
36
  #
33
- create_embed_frameworks_script if (target.includes_frameworks? || target.includes_xcframeworks?) && !target.requires_host_target?
34
- create_prepare_artifacts_script if target.includes_xcframeworks? && !target.requires_host_target?
37
+ create_embed_frameworks_script if embed_frameworks_script_required?
35
38
  create_bridge_support_file(native_target)
36
39
  create_copy_resources_script if target.includes_resources?
37
40
  create_acknowledgements
@@ -76,6 +79,13 @@ module Pod
76
79
  super.merge(settings)
77
80
  end
78
81
 
82
+ # @return [Boolean] whether this target requires an `Embed Frameworks` script phase
83
+ #
84
+ def embed_frameworks_script_required?
85
+ includes_dynamic_xcframeworks = target.xcframeworks_by_config.values.flatten.map(&:build_type).any?(&:dynamic_framework?)
86
+ (target.includes_frameworks? || includes_dynamic_xcframeworks) && !target.requires_host_target?
87
+ end
88
+
79
89
  # Creates the group that holds the references to the support files
80
90
  # generated by this installer.
81
91
  #
@@ -154,33 +164,9 @@ module Pod
154
164
  #
155
165
  def create_embed_frameworks_script
156
166
  path = target.embed_frameworks_script_path
157
- generator = Generator::EmbedFrameworksScript.new(target.framework_paths_by_config)
158
- update_changed_file(generator, path)
159
- add_file_to_support_group(path)
160
- end
161
-
162
- # Creates a script that prepares artifacts for embedding into a host target.
163
- #
164
- # @note We can't use Xcode default link libraries phase, because
165
- # we need to ensure that we only copy the frameworks which are
166
- # relevant for the current build configuration.
167
- #
168
- # @return [void]
169
- #
170
- def create_prepare_artifacts_script
171
- path = target.prepare_artifacts_script_path
172
- generator = Generator::PrepareArtifactsScript.new(target.xcframeworks_by_config, sandbox.root, target.platform)
167
+ generator = Generator::EmbedFrameworksScript.new(target.framework_paths_by_config, target.xcframeworks_by_config)
173
168
  update_changed_file(generator, path)
174
169
  add_file_to_support_group(path)
175
-
176
- target.user_build_configurations.each_key do |config|
177
- if (input_file_list = target.prepare_artifacts_script_input_files_path(config))
178
- add_file_to_support_group(input_file_list)
179
- end
180
- if (output_file_list = target.prepare_artifacts_script_output_files_path(config))
181
- add_file_to_support_group(output_file_list)
182
- end
183
- end
184
170
  end
185
171
 
186
172
  # Generates the acknowledgement files (markdown and plist) for the target.
@@ -79,7 +79,11 @@ module Pod
79
79
  app_host_target.build_configurations.each do |configuration|
80
80
  configuration.build_settings['PRODUCT_NAME'] = app_target_label
81
81
  configuration.build_settings['PRODUCT_BUNDLE_IDENTIFIER'] = 'org.cocoapods.${PRODUCT_NAME:rfc1034identifier}'
82
- configuration.build_settings['CODE_SIGN_IDENTITY'] = '' if platform == :osx
82
+ if platform == :osx
83
+ configuration.build_settings['CODE_SIGN_IDENTITY'] = ''
84
+ elsif platform == :ios
85
+ configuration.build_settings['CODE_SIGN_IDENTITY'] = 'iPhone Developer'
86
+ end
83
87
  configuration.build_settings['CURRENT_PROJECT_VERSION'] = '1'
84
88
  end
85
89
 
@@ -218,7 +218,8 @@ module Pod
218
218
  pod_name = file_accessor.spec.name
219
219
  preserve_pod_file_structure_flag = (sandbox.local?(pod_name) || preserve_pod_file_structure) && reflect_file_system_structure
220
220
  base_path = preserve_pod_file_structure_flag ? common_path(paths) : nil
221
- group = pods_project.group_for_spec(pod_name, group_key)
221
+ actual_group_key = preserve_pod_file_structure_flag ? nil : group_key
222
+ group = pods_project.group_for_spec(pod_name, actual_group_key)
222
223
  paths.each do |path|
223
224
  pods_project.add_file_reference(path, group, preserve_pod_file_structure_flag, base_path)
224
225
  end
@@ -53,8 +53,8 @@ module Pod
53
53
 
54
54
  # Wire up app native targets.
55
55
  unless pod_target_installation_result.app_native_targets.empty?
56
- wire_app_native_targets(pod_target, native_target, pod_target_installation_result,
57
- pod_target_installation_results, project, frameworks_group, metadata_cache)
56
+ wire_app_native_targets(pod_target, pod_target_installation_result, pod_target_installation_results,
57
+ project, frameworks_group, metadata_cache)
58
58
  end
59
59
  end
60
60
  end
@@ -152,15 +152,17 @@ module Pod
152
152
  target_attributes[test_native_target.uuid.to_s] = { 'TestTargetID' => app_native_target.uuid.to_s }
153
153
  project.root_object.attributes['TargetAttributes'] = target_attributes
154
154
  test_native_target.add_dependency(app_native_target)
155
- else
155
+ elsif cached_dependency = metadata_cache.target_label_by_metadata[app_host_target_label]
156
156
  # Hit the cache
157
- cached_dependency = metadata_cache.target_label_by_metadata[app_host_target_label]
158
157
  project.add_cached_subproject_reference(sandbox, cached_dependency, project.dependencies_group)
159
158
  Project.add_cached_dependency(sandbox, test_native_target, cached_dependency)
159
+ else
160
+ raise "Expected to either have an installation or cache result for #{app_host_target_label} (from pod #{app_host_pod_target_label}) " \
161
+ "for target #{test_native_target.name} in project #{project.project_name}"
160
162
  end
161
163
  end
162
164
 
163
- def wire_app_native_targets(pod_target, native_target, installation_result, pod_target_installation_results, project, frameworks_group, metadata_cache)
165
+ def wire_app_native_targets(pod_target, installation_result, pod_target_installation_results, project, frameworks_group, metadata_cache)
164
166
  installation_result.app_specs_by_native_target.each do |app_native_target, app_spec|
165
167
  resource_bundle_native_targets = installation_result.app_resource_bundle_targets[app_spec.name] || []
166
168
  resource_bundle_native_targets.each do |app_resource_bundle_target|
@@ -187,7 +189,7 @@ module Pod
187
189
  # Hit the cache
188
190
  cached_dependency = metadata_cache.target_label_by_metadata[app_dependent_target.label]
189
191
  project.add_cached_pod_subproject(sandbox, cached_dependency, is_local)
190
- Project.add_cached_dependency(sandbox, native_target, cached_dependency)
192
+ Project.add_cached_dependency(sandbox, app_native_target, cached_dependency)
191
193
  end
192
194
  end
193
195
  end
@@ -1,3 +1,5 @@
1
+ require 'active_support/core_ext/array'
2
+ require 'active_support/core_ext/string/inflections'
1
3
  require 'cocoapods/xcode'
2
4
 
3
5
  module Pod
@@ -14,11 +16,15 @@ module Pod
14
16
  #
15
17
  attr_reader :umbrella_header_paths
16
18
 
19
+ # @return [PodTarget] @see TargetInstaller#target
20
+ #
21
+ attr_reader :target
22
+
17
23
  # Initialize a new instance
18
24
  #
19
25
  # @param [Sandbox] sandbox @see TargetInstaller#sandbox
20
26
  # @param [Pod::Project] project @see TargetInstaller#project
21
- # @param [Target] target @see TargetInstaller#target
27
+ # @param [PodTarget] target @see TargetInstaller#target
22
28
  # @param [Array<Pathname>] umbrella_header_paths @see #umbrella_header_paths
23
29
  #
24
30
  def initialize(sandbox, project, target, umbrella_header_paths = nil)
@@ -42,6 +48,8 @@ module Pod
42
48
  # PBXAggregateTarget that will be used to wire up dependencies later.
43
49
  native_target = add_placeholder_target
44
50
  resource_bundle_targets = add_resources_bundle_targets(library_file_accessors).values.flatten
51
+ create_copy_dsyms_script
52
+ create_copy_xcframeworks_script unless target.xcframeworks.values.all?(&:empty?)
45
53
  create_xcconfig_file(native_target, resource_bundle_targets)
46
54
  return TargetInstallationResult.new(target, native_target, resource_bundle_targets)
47
55
  end
@@ -57,8 +65,10 @@ module Pod
57
65
  app_resource_bundle_targets = add_resources_bundle_targets(app_file_accessors)
58
66
 
59
67
  add_files_to_build_phases(native_target, test_native_targets, app_native_targets)
60
- validate_targets_contain_sources(test_native_targets + app_native_targets + [native_target])
61
- validate_xcframeworks_no_mixed_linkage
68
+ validate_targets_contain_sources(test_native_targets + app_native_targets.values + [native_target])
69
+ validate_xcframeworks
70
+
71
+ create_copy_xcframeworks_script unless target.xcframeworks.values.all?(&:empty?)
62
72
 
63
73
  create_xcconfig_file(native_target, resource_bundle_targets)
64
74
  create_test_xcconfig_files(test_native_targets, test_resource_bundle_targets)
@@ -120,12 +130,13 @@ module Pod
120
130
  target.app_specs.each do |app_spec|
121
131
  path = target.prefix_header_path_for_spec(app_spec)
122
132
  app_spec_consumer = app_spec.consumer(target.platform)
123
- app_native_target = app_native_target_from_spec(app_spec_consumer.spec, app_native_targets)
133
+ app_native_target = app_native_targets[app_spec_consumer.spec]
124
134
  create_prefix_header(path, app_file_accessors, target.platform, app_native_target, project_directory)
125
135
  add_file_to_support_group(path)
126
136
  end
127
137
  end
128
138
  create_dummy_source(native_target)
139
+ create_copy_dsyms_script
129
140
  clean_support_files_temp_dir
130
141
  TargetInstallationResult.new(target, native_target, resource_bundle_targets,
131
142
  test_native_targets, test_resource_bundle_targets, test_app_host_targets,
@@ -177,7 +188,7 @@ module Pod
177
188
  # @return [Boolean] Whether the target should build a pch file.
178
189
  #
179
190
  def skip_pch?(specs)
180
- specs.any? { |spec| spec.prefix_header_file.is_a?(FalseClass) }
191
+ specs.any? { |spec| spec.root.prefix_header_file.is_a?(FalseClass) }
181
192
  end
182
193
 
183
194
  # True if info.plist generation should be skipped
@@ -216,9 +227,30 @@ module Pod
216
227
  settings['SWIFT_VERSION'] = target.swift_version
217
228
  end
218
229
 
230
+ if info_plist_bundle_id
231
+ settings['PRODUCT_BUNDLE_IDENTIFIER'] = info_plist_bundle_id
232
+ end
233
+
219
234
  settings
220
235
  end
221
236
 
237
+ # @return [String] Bundle Identifier found in the custom Info.plist entries
238
+ #
239
+ def info_plist_bundle_id
240
+ return @plist_bundle_id if defined?(@plist_bundle_id)
241
+ unless target.info_plist_entries.nil?
242
+ @plist_bundle_id = target.info_plist_entries['CFBundleIdentifier']
243
+ unless @plist_bundle_id.nil?
244
+ message = "The `#{target.name}` target " \
245
+ "sets a Bundle Identifier of `#{@plist_bundle_id}` in it's info.plist file. " \
246
+ 'The Bundle Identifier should be set using pod_target_xcconfig: ' \
247
+ "s.pod_target_xcconfig = { 'PRODUCT_BUNDLE_IDENTIFIER': '#{@plist_bundle_id}' }`."
248
+ UI.warn message
249
+ end
250
+ @plist_bundle_id
251
+ end
252
+ end
253
+
222
254
  # Filters the given resource file references discarding empty paths which are
223
255
  # added by their parent directory. This will also include references to the parent [PBXVariantGroup]
224
256
  # for all resources underneath it.
@@ -285,7 +317,7 @@ module Pod
285
317
  when :test
286
318
  test_native_target_from_spec(consumer.spec, test_native_targets)
287
319
  when :app
288
- app_native_target_from_spec(consumer.spec, app_native_targets)
320
+ app_native_targets[consumer.spec]
289
321
  end
290
322
 
291
323
  headers = file_accessor.headers
@@ -322,6 +354,11 @@ module Pod
322
354
 
323
355
  filter_resource_file_references(file_accessor.resources.flatten) do |compile_phase_refs, resource_phase_refs|
324
356
  native_target.add_file_references(compile_phase_refs, nil)
357
+
358
+ if target.build_as_static_framework? && consumer.spec.library_specification?
359
+ resource_phase_refs = resource_phase_refs.select { |ref| Target.resource_extension_compilable?(File.extname(ref.path)) }
360
+ end
361
+
325
362
  native_target.add_resources(resource_phase_refs)
326
363
  end
327
364
  end
@@ -371,13 +408,16 @@ module Pod
371
408
  configuration.build_settings['CODE_SIGNING_ALLOWED'] = 'YES'
372
409
  end
373
410
  # For macOS we do not code sign the XCTest bundle because we do not code sign the frameworks either.
374
- configuration.build_settings['CODE_SIGN_IDENTITY'] = '' if target.platform == :osx
411
+ if target.platform == :osx
412
+ configuration.build_settings['CODE_SIGN_IDENTITY'] = ''
413
+ elsif target.platform == :ios
414
+ configuration.build_settings['CODE_SIGN_IDENTITY'] = 'iPhone Developer'
415
+ end
375
416
  end
376
417
 
377
418
  remove_pod_target_xcconfig_overrides_from_target(target.test_spec_build_settings_by_config[test_spec.name], test_native_target)
378
419
 
379
420
  # Test native targets also need frameworks and resources to be copied over to their xctest bundle.
380
- create_test_target_prepare_artifacts_script(test_spec)
381
421
  create_test_target_embed_frameworks_script(test_spec)
382
422
  create_test_target_copy_resources_script(test_spec)
383
423
 
@@ -411,10 +451,10 @@ module Pod
411
451
  # Adds the app targets for the library to the Pods project with the
412
452
  # appropriate build configurations.
413
453
  #
414
- # @return [Array<PBXNativeTarget>] the app native targets created.
454
+ # @return [Hash{Specification => PBXNativeTarget}] the app native targets created, keyed by their app spec
415
455
  #
416
456
  def add_app_targets
417
- target.app_specs.map do |app_spec|
457
+ target.app_specs.each_with_object({}) do |app_spec, hash|
418
458
  spec_consumer = app_spec.consumer(target.platform)
419
459
  spec_name = app_spec.parent.name
420
460
  subspec_name = target.subspec_label(app_spec)
@@ -473,7 +513,7 @@ module Pod
473
513
  create_app_target_copy_resources_script(app_spec)
474
514
  add_resources_to_target(resources, app_native_target)
475
515
 
476
- app_native_target
516
+ hash[app_spec] = app_native_target
477
517
  end
478
518
  end
479
519
 
@@ -649,33 +689,6 @@ module Pod
649
689
  end
650
690
  end
651
691
 
652
- # Creates a script that prepares artifacts for the test target.
653
- #
654
- # @param [Specification] test_spec
655
- # The test spec to create the script for.
656
- #
657
- # @return [void]
658
- #
659
- def create_test_target_prepare_artifacts_script(test_spec)
660
- path = target.prepare_artifacts_script_path_for_spec(test_spec)
661
- host_target_spec_names = target.app_host_dependent_targets_for_spec(test_spec).flat_map do |pt|
662
- pt.specs.map(&:name)
663
- end.uniq
664
- frameworks_by_config = target.user_build_configurations.each_with_object({}) do |(config_name, config), paths_by_config|
665
- paths_by_config[config_name] = target.dependent_targets_for_test_spec(test_spec, :configuration => config).flat_map do |pod_target|
666
- spec_paths_to_include = pod_target.library_specs.map(&:name)
667
- spec_paths_to_include -= host_target_spec_names
668
- spec_paths_to_include << test_spec.name if pod_target == target
669
- pod_target.xcframeworks.values_at(*spec_paths_to_include).flatten.compact.uniq
670
- end
671
- end
672
- unless frameworks_by_config.each_value.all?(&:empty?)
673
- generator = Generator::PrepareArtifactsScript.new(frameworks_by_config, target.sandbox.root, target.platform)
674
- update_changed_file(generator, path)
675
- add_file_to_support_group(path)
676
- end
677
- end
678
-
679
692
  # Creates a script that embeds the frameworks to the bundle of the test target.
680
693
  #
681
694
  # @param [Specification] test_spec
@@ -696,8 +709,16 @@ module Pod
696
709
  pod_target.framework_paths.values_at(*spec_paths_to_include).flatten.compact.uniq
697
710
  end
698
711
  end
699
- unless framework_paths_by_config.each_value.all?(&:empty?)
700
- generator = Generator::EmbedFrameworksScript.new(framework_paths_by_config)
712
+ xcframeworks_by_config = target.user_build_configurations.each_with_object({}) do |(config_name, config), paths_by_config|
713
+ paths_by_config[config_name] = target.dependent_targets_for_test_spec(test_spec, :configuration => config).flat_map do |pod_target|
714
+ spec_paths_to_include = pod_target.library_specs.map(&:name)
715
+ spec_paths_to_include -= host_target_spec_names
716
+ spec_paths_to_include << test_spec.name if pod_target == target
717
+ pod_target.xcframeworks.values_at(*spec_paths_to_include).flatten.compact.uniq
718
+ end
719
+ end
720
+ unless framework_paths_by_config.each_value.all?(&:empty?) && xcframeworks_by_config.each_value.all?(&:empty?)
721
+ generator = Generator::EmbedFrameworksScript.new(framework_paths_by_config, xcframeworks_by_config)
701
722
  update_changed_file(generator, path)
702
723
  add_file_to_support_group(path)
703
724
  end
@@ -705,8 +726,8 @@ module Pod
705
726
 
706
727
  # Generates the contents of the xcconfig file used for each app target type and saves it to disk.
707
728
  #
708
- # @param [Array<PBXNativeTarget>] app_native_targets
709
- # the app native target to link the xcconfig file into.
729
+ # @param [Hash{Specification => PBXNativeTarget}] app_native_targets
730
+ # the app native targets to link the xcconfig file into.
710
731
  #
711
732
  # @param [Hash{String=>Array<PBXNativeTarget>}] app_resource_bundle_targets
712
733
  # the additional app resource bundle targets to link the xcconfig file into.
@@ -716,7 +737,7 @@ module Pod
716
737
  def create_app_xcconfig_files(app_native_targets, app_resource_bundle_targets)
717
738
  target.app_specs.each do |app_spec|
718
739
  spec_consumer = app_spec.consumer(target.platform)
719
- app_native_target = app_native_target_from_spec(spec_consumer.spec, app_native_targets)
740
+ app_native_target = app_native_targets[spec_consumer.spec]
720
741
 
721
742
  target.user_config_names_by_config_type.each do |config, names|
722
743
  path = target.xcconfig_path("#{target.subspec_label(app_spec)}.#{config}")
@@ -765,20 +786,57 @@ module Pod
765
786
  def create_app_target_embed_frameworks_script(app_spec)
766
787
  path = target.embed_frameworks_script_path_for_spec(app_spec)
767
788
  framework_paths_by_config = target.user_build_configurations.each_with_object({}) do |(config_name, config), paths_by_config|
768
- pod_targets = target.dependent_targets_for_app_spec(app_spec, :configuration => config)
769
- paths_by_config[config_name] = pod_targets.flat_map do |pod_target|
789
+ paths_by_config[config_name] = target.dependent_targets_for_app_spec(app_spec, :configuration => config).flat_map do |pod_target|
770
790
  spec_paths_to_include = pod_target.library_specs.map(&:name)
771
791
  spec_paths_to_include << app_spec.name if pod_target == target
772
792
  pod_target.framework_paths.values_at(*spec_paths_to_include).flatten.compact.uniq
773
793
  end
774
794
  end
775
- unless framework_paths_by_config.each_value.all?(&:empty?)
776
- generator = Generator::EmbedFrameworksScript.new(framework_paths_by_config)
795
+ xcframeworks_by_config = target.user_build_configurations.each_with_object({}) do |(config_name, config), paths_by_config|
796
+ paths_by_config[config_name] = target.dependent_targets_for_app_spec(app_spec, :configuration => config).flat_map do |pod_target|
797
+ spec_paths_to_include = pod_target.library_specs.map(&:name)
798
+ spec_paths_to_include << app_spec.name if pod_target == target
799
+ pod_target.xcframeworks.values_at(*spec_paths_to_include).flatten.compact.uniq
800
+ end
801
+ end
802
+
803
+ unless framework_paths_by_config.each_value.all?(&:empty?) && xcframeworks_by_config.each_value.all?(&:empty?)
804
+ generator = Generator::EmbedFrameworksScript.new(framework_paths_by_config, xcframeworks_by_config)
805
+ update_changed_file(generator, path)
806
+ add_file_to_support_group(path)
807
+ end
808
+ end
809
+
810
+ # Creates a script that copies and strips vendored dSYMs and bcsymbolmaps.
811
+ #
812
+ # @return [void]
813
+ #
814
+ def create_copy_dsyms_script
815
+ dsym_paths = PodTargetInstaller.dsym_paths(target)
816
+ bcsymbolmap_paths = PodTargetInstaller.bcsymbolmap_paths(target)
817
+ path = target.copy_dsyms_script_path
818
+ unless dsym_paths.empty? && bcsymbolmap_paths.empty?
819
+ generator = Generator::CopydSYMsScript.new(dsym_paths, bcsymbolmap_paths)
777
820
  update_changed_file(generator, path)
778
821
  add_file_to_support_group(path)
779
822
  end
780
823
  end
781
824
 
825
+ # Creates a script that copies the appropriate xcframework slice to the build dir.
826
+ #
827
+ # @note We can't use Xcode default link libraries phase, because
828
+ # we need to ensure that we only copy the frameworks which are
829
+ # relevant for the current build configuration.
830
+ #
831
+ # @return [void]
832
+ #
833
+ def create_copy_xcframeworks_script
834
+ path = target.copy_xcframeworks_script_path
835
+ generator = Generator::CopyXCFrameworksScript.new(target.xcframeworks.values.flatten, sandbox.root, target.platform)
836
+ update_changed_file(generator, path)
837
+ add_file_to_support_group(path)
838
+ end
839
+
782
840
  # Manually add `libswiftSwiftOnoneSupport.dylib` as it seems there is an issue with tests that do not include it for Debug configurations.
783
841
  # Possibly related to Swift module optimization.
784
842
  #
@@ -943,9 +1001,18 @@ module Pod
943
1001
  end
944
1002
 
945
1003
  def project_file_references_array(files, file_type)
1004
+ error_message_for_missing_reference = lambda do |sf, target|
1005
+ "Unable to find #{file_type} ref for `#{sf.basename}` for target `#{target.name}`."
1006
+ end
946
1007
  files.map do |sf|
947
- project.reference_for_path(sf).tap do |ref|
948
- raise Informative, "Unable to find #{file_type} ref for `#{sf.basename}` for target `#{target.name}`." unless ref
1008
+ begin
1009
+ project.reference_for_path(sf).tap do |ref|
1010
+ raise Informative, error_message_for_missing_reference.call(sf, target) unless ref
1011
+ end
1012
+ rescue Errno::ENOENT
1013
+ # Normalize the error for Ruby < 2.7. Ruby 2.7 can crash on a different call of real path compared
1014
+ # to older versions. This ensures that the error message is consistent.
1015
+ raise Informative, error_message_for_missing_reference.call(sf, target)
949
1016
  end
950
1017
  end
951
1018
  end
@@ -1011,13 +1078,6 @@ module Pod
1011
1078
  end
1012
1079
  end
1013
1080
 
1014
- def app_native_target_from_spec(spec, app_native_targets)
1015
- app_target_label = target.app_target_label(spec)
1016
- app_native_targets.find do |app_native_target|
1017
- app_native_target.name == app_target_label
1018
- end
1019
- end
1020
-
1021
1081
  # Adds a placeholder native target for the library to the Pods project with the
1022
1082
  # appropriate build configurations.
1023
1083
  #
@@ -1086,19 +1146,80 @@ module Pod
1086
1146
  end
1087
1147
  end
1088
1148
 
1089
- # Raises if a vendored xcframework contains frameworks of mixed linkage
1149
+ # Raises if a vendored xcframework contains frameworks of mixed linkage or mixed packaging
1090
1150
  #
1091
- def validate_xcframeworks_no_mixed_linkage
1151
+ def validate_xcframeworks
1092
1152
  target.xcframeworks.each_value do |xcframeworks|
1093
1153
  xcframeworks.each do |xcframework|
1094
- dynamic_slices, static_slices = xcframework.slices.partition { |slice| Pod::Xcode::LinkageAnalyzer.dynamic_binary?(slice.path) }
1154
+ if xcframework.slices.empty?
1155
+ raise Informative, "Unable to install vendored xcframework `#{xcframework.name}` for Pod `#{target.label}` because it does not contain any binaries."
1156
+ end
1157
+ if xcframework.build_type.dynamic_library?
1158
+ raise Informative, <<-MSG.strip_heredoc
1159
+ Unable to install vendored xcframework `#{xcframework.name}` for Pod `#{target.label}` because it contains dynamic libraries which are not supported.
1160
+ Use dynamic frameworks for dynamic linking instead.
1161
+ MSG
1162
+ end
1163
+ if xcframework.build_type.static_library?
1164
+ binary_names = xcframework.slices.map { |slice| File.basename(slice.binary_path, File.extname(slice.binary_path)) }.uniq
1165
+ if binary_names.size > 1
1166
+ raise Informative, <<-MSG.strip_heredoc
1167
+ Unable to install vendored xcframework `#{xcframework.name}` for Pod `#{target.label}` because it contains static libraries
1168
+ with differing binary names: #{binary_names.to_sentence}.
1169
+ MSG
1170
+ end
1171
+ end
1172
+ dynamic_slices, static_slices = xcframework.slices.partition(&:dynamic?)
1095
1173
  if !dynamic_slices.empty? && !static_slices.empty?
1096
1174
  raise Informative, "Unable to install vendored xcframework `#{xcframework.name}` for Pod `#{target.label}`, because it contains both static and dynamic frameworks."
1097
1175
  end
1176
+ library_slices, framework_slices = xcframework.slices.partition(&:library?)
1177
+ if !library_slices.empty? && !framework_slices.empty?
1178
+ raise Informative, "Unable to install vendored xcframework `#{xcframework.name}` for Pod `#{target.label}`, because it contains both libraries and frameworks."
1179
+ end
1098
1180
  end
1099
1181
  end
1100
1182
  end
1183
+
1101
1184
  #-----------------------------------------------------------------------#
1185
+
1186
+ class << self
1187
+ # @param [PodTarget] target the target to be installed
1188
+ #
1189
+ # @return [Array<String>] the dSYM paths for the given target
1190
+ #
1191
+ def dsym_paths(target)
1192
+ dsym_paths = target.framework_paths.values.flatten.reject { |fmwk_path| fmwk_path.dsym_path.nil? }.map(&:dsym_path)
1193
+ dsym_paths.concat(target.xcframeworks.values.flatten.flat_map { |xcframework| xcframework_dsyms(xcframework.path) })
1194
+ dsym_paths
1195
+ end
1196
+
1197
+ # @param [PodTarget] target the target to be installed
1198
+ #
1199
+ # @return [Array<String>] the bcsymbolmap paths for the given target
1200
+ #
1201
+ def bcsymbolmap_paths(target)
1202
+ target.framework_paths.values.flatten.reject do |fmwk_path|
1203
+ fmwk_path.bcsymbolmap_paths.nil?
1204
+ end.flat_map(&:bcsymbolmap_paths)
1205
+ end
1206
+
1207
+ # @param [Pathname] xcframework_path
1208
+ # the base path of the .xcframework bundle
1209
+ #
1210
+ # @return [Array<Pathname>] all found .dSYM paths
1211
+ #
1212
+ def xcframework_dsyms(xcframework_path)
1213
+ basename = File.basename(xcframework_path, '.xcframework')
1214
+ dsym_basename = basename + '.dSYMs'
1215
+ path = xcframework_path.dirname + dsym_basename
1216
+ if File.directory?(path)
1217
+ Dir.glob(path + '*.dSYM')
1218
+ else
1219
+ []
1220
+ end
1221
+ end
1222
+ end
1102
1223
  end
1103
1224
  end
1104
1225
  end