cocoapods 1.9.1 → 1.10.0.rc.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +229 -5
  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 +254 -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/file_references_installer.rb +2 -1
  33. data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_dependency_installer.rb +8 -6
  34. data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_installer.rb +175 -58
  35. data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_integrator.rb +61 -30
  36. data/lib/cocoapods/installer/xcode/pods_project_generator/project_generator.rb +3 -2
  37. data/lib/cocoapods/installer/xcode/pods_project_generator/target_installation_result.rb +5 -7
  38. data/lib/cocoapods/installer/xcode/pods_project_generator_result.rb +19 -0
  39. data/lib/cocoapods/installer/xcode/target_validator.rb +1 -1
  40. data/lib/cocoapods/sources_manager.rb +2 -1
  41. data/lib/cocoapods/target.rb +44 -2
  42. data/lib/cocoapods/target/aggregate_target.rb +35 -0
  43. data/lib/cocoapods/target/build_settings.rb +84 -17
  44. data/lib/cocoapods/target/pod_target.rb +85 -11
  45. data/lib/cocoapods/user_interface/error_report.rb +1 -1
  46. data/lib/cocoapods/user_interface/inspector_reporter.rb +3 -10
  47. data/lib/cocoapods/validator.rb +37 -11
  48. data/lib/cocoapods/xcode/framework_paths.rb +1 -1
  49. data/lib/cocoapods/xcode/xcframework.rb +17 -4
  50. data/lib/cocoapods/xcode/xcframework/xcframework_slice.rb +81 -3
  51. metadata +32 -54
  52. 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.
@@ -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
@@ -377,7 +414,6 @@ module Pod
377
414
  remove_pod_target_xcconfig_overrides_from_target(target.test_spec_build_settings_by_config[test_spec.name], test_native_target)
378
415
 
379
416
  # 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
417
  create_test_target_embed_frameworks_script(test_spec)
382
418
  create_test_target_copy_resources_script(test_spec)
383
419
 
@@ -411,10 +447,10 @@ module Pod
411
447
  # Adds the app targets for the library to the Pods project with the
412
448
  # appropriate build configurations.
413
449
  #
414
- # @return [Array<PBXNativeTarget>] the app native targets created.
450
+ # @return [Hash{Specification => PBXNativeTarget}] the app native targets created, keyed by their app spec
415
451
  #
416
452
  def add_app_targets
417
- target.app_specs.map do |app_spec|
453
+ target.app_specs.each_with_object({}) do |app_spec, hash|
418
454
  spec_consumer = app_spec.consumer(target.platform)
419
455
  spec_name = app_spec.parent.name
420
456
  subspec_name = target.subspec_label(app_spec)
@@ -473,7 +509,7 @@ module Pod
473
509
  create_app_target_copy_resources_script(app_spec)
474
510
  add_resources_to_target(resources, app_native_target)
475
511
 
476
- app_native_target
512
+ hash[app_spec] = app_native_target
477
513
  end
478
514
  end
479
515
 
@@ -649,33 +685,6 @@ module Pod
649
685
  end
650
686
  end
651
687
 
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
688
  # Creates a script that embeds the frameworks to the bundle of the test target.
680
689
  #
681
690
  # @param [Specification] test_spec
@@ -696,8 +705,16 @@ module Pod
696
705
  pod_target.framework_paths.values_at(*spec_paths_to_include).flatten.compact.uniq
697
706
  end
698
707
  end
699
- unless framework_paths_by_config.each_value.all?(&:empty?)
700
- generator = Generator::EmbedFrameworksScript.new(framework_paths_by_config)
708
+ xcframeworks_by_config = target.user_build_configurations.each_with_object({}) do |(config_name, config), paths_by_config|
709
+ paths_by_config[config_name] = target.dependent_targets_for_test_spec(test_spec, :configuration => config).flat_map do |pod_target|
710
+ spec_paths_to_include = pod_target.library_specs.map(&:name)
711
+ spec_paths_to_include -= host_target_spec_names
712
+ spec_paths_to_include << test_spec.name if pod_target == target
713
+ pod_target.xcframeworks.values_at(*spec_paths_to_include).flatten.compact.uniq
714
+ end
715
+ end
716
+ unless framework_paths_by_config.each_value.all?(&:empty?) && xcframeworks_by_config.each_value.all?(&:empty?)
717
+ generator = Generator::EmbedFrameworksScript.new(framework_paths_by_config, xcframeworks_by_config)
701
718
  update_changed_file(generator, path)
702
719
  add_file_to_support_group(path)
703
720
  end
@@ -705,8 +722,8 @@ module Pod
705
722
 
706
723
  # Generates the contents of the xcconfig file used for each app target type and saves it to disk.
707
724
  #
708
- # @param [Array<PBXNativeTarget>] app_native_targets
709
- # the app native target to link the xcconfig file into.
725
+ # @param [Hash{Specification => PBXNativeTarget}] app_native_targets
726
+ # the app native targets to link the xcconfig file into.
710
727
  #
711
728
  # @param [Hash{String=>Array<PBXNativeTarget>}] app_resource_bundle_targets
712
729
  # the additional app resource bundle targets to link the xcconfig file into.
@@ -716,7 +733,7 @@ module Pod
716
733
  def create_app_xcconfig_files(app_native_targets, app_resource_bundle_targets)
717
734
  target.app_specs.each do |app_spec|
718
735
  spec_consumer = app_spec.consumer(target.platform)
719
- app_native_target = app_native_target_from_spec(spec_consumer.spec, app_native_targets)
736
+ app_native_target = app_native_targets[spec_consumer.spec]
720
737
 
721
738
  target.user_config_names_by_config_type.each do |config, names|
722
739
  path = target.xcconfig_path("#{target.subspec_label(app_spec)}.#{config}")
@@ -765,20 +782,57 @@ module Pod
765
782
  def create_app_target_embed_frameworks_script(app_spec)
766
783
  path = target.embed_frameworks_script_path_for_spec(app_spec)
767
784
  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|
785
+ paths_by_config[config_name] = target.dependent_targets_for_app_spec(app_spec, :configuration => config).flat_map do |pod_target|
770
786
  spec_paths_to_include = pod_target.library_specs.map(&:name)
771
787
  spec_paths_to_include << app_spec.name if pod_target == target
772
788
  pod_target.framework_paths.values_at(*spec_paths_to_include).flatten.compact.uniq
773
789
  end
774
790
  end
775
- unless framework_paths_by_config.each_value.all?(&:empty?)
776
- generator = Generator::EmbedFrameworksScript.new(framework_paths_by_config)
791
+ xcframeworks_by_config = target.user_build_configurations.each_with_object({}) do |(config_name, config), paths_by_config|
792
+ paths_by_config[config_name] = target.dependent_targets_for_app_spec(app_spec, :configuration => config).flat_map do |pod_target|
793
+ spec_paths_to_include = pod_target.library_specs.map(&:name)
794
+ spec_paths_to_include << app_spec.name if pod_target == target
795
+ pod_target.xcframeworks.values_at(*spec_paths_to_include).flatten.compact.uniq
796
+ end
797
+ end
798
+
799
+ unless framework_paths_by_config.each_value.all?(&:empty?) && xcframeworks_by_config.each_value.all?(&:empty?)
800
+ generator = Generator::EmbedFrameworksScript.new(framework_paths_by_config, xcframeworks_by_config)
801
+ update_changed_file(generator, path)
802
+ add_file_to_support_group(path)
803
+ end
804
+ end
805
+
806
+ # Creates a script that copies and strips vendored dSYMs and bcsymbolmaps.
807
+ #
808
+ # @return [void]
809
+ #
810
+ def create_copy_dsyms_script
811
+ dsym_paths = PodTargetInstaller.dsym_paths(target)
812
+ bcsymbolmap_paths = PodTargetInstaller.bcsymbolmap_paths(target)
813
+ path = target.copy_dsyms_script_path
814
+ unless dsym_paths.empty? && bcsymbolmap_paths.empty?
815
+ generator = Generator::CopydSYMsScript.new(dsym_paths, bcsymbolmap_paths)
777
816
  update_changed_file(generator, path)
778
817
  add_file_to_support_group(path)
779
818
  end
780
819
  end
781
820
 
821
+ # Creates a script that copies the appropriate xcframework slice to the build dir.
822
+ #
823
+ # @note We can't use Xcode default link libraries phase, because
824
+ # we need to ensure that we only copy the frameworks which are
825
+ # relevant for the current build configuration.
826
+ #
827
+ # @return [void]
828
+ #
829
+ def create_copy_xcframeworks_script
830
+ path = target.copy_xcframeworks_script_path
831
+ generator = Generator::CopyXCFrameworksScript.new(target.xcframeworks.values.flatten, sandbox.root, target.platform)
832
+ update_changed_file(generator, path)
833
+ add_file_to_support_group(path)
834
+ end
835
+
782
836
  # Manually add `libswiftSwiftOnoneSupport.dylib` as it seems there is an issue with tests that do not include it for Debug configurations.
783
837
  # Possibly related to Swift module optimization.
784
838
  #
@@ -943,9 +997,18 @@ module Pod
943
997
  end
944
998
 
945
999
  def project_file_references_array(files, file_type)
1000
+ error_message_for_missing_reference = lambda do |sf, target|
1001
+ "Unable to find #{file_type} ref for `#{sf.basename}` for target `#{target.name}`."
1002
+ end
946
1003
  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
1004
+ begin
1005
+ project.reference_for_path(sf).tap do |ref|
1006
+ raise Informative, error_message_for_missing_reference.call(sf, target) unless ref
1007
+ end
1008
+ rescue Errno::ENOENT
1009
+ # Normalize the error for Ruby < 2.7. Ruby 2.7 can crash on a different call of real path compared
1010
+ # to older versions. This ensures that the error message is consistent.
1011
+ raise Informative, error_message_for_missing_reference.call(sf, target)
949
1012
  end
950
1013
  end
951
1014
  end
@@ -1011,13 +1074,6 @@ module Pod
1011
1074
  end
1012
1075
  end
1013
1076
 
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
1077
  # Adds a placeholder native target for the library to the Pods project with the
1022
1078
  # appropriate build configurations.
1023
1079
  #
@@ -1086,19 +1142,80 @@ module Pod
1086
1142
  end
1087
1143
  end
1088
1144
 
1089
- # Raises if a vendored xcframework contains frameworks of mixed linkage
1145
+ # Raises if a vendored xcframework contains frameworks of mixed linkage or mixed packaging
1090
1146
  #
1091
- def validate_xcframeworks_no_mixed_linkage
1147
+ def validate_xcframeworks
1092
1148
  target.xcframeworks.each_value do |xcframeworks|
1093
1149
  xcframeworks.each do |xcframework|
1094
- dynamic_slices, static_slices = xcframework.slices.partition { |slice| Pod::Xcode::LinkageAnalyzer.dynamic_binary?(slice.path) }
1150
+ if xcframework.slices.empty?
1151
+ raise Informative, "Unable to install vendored xcframework `#{xcframework.name}` for Pod `#{target.label}` because it does not contain any binaries."
1152
+ end
1153
+ if xcframework.build_type.dynamic_library?
1154
+ raise Informative, <<-MSG.strip_heredoc
1155
+ Unable to install vendored xcframework `#{xcframework.name}` for Pod `#{target.label}` because it contains dynamic libraries which are not supported.
1156
+ Use dynamic frameworks for dynamic linking instead.
1157
+ MSG
1158
+ end
1159
+ if xcframework.build_type.static_library?
1160
+ binary_names = xcframework.slices.map { |slice| File.basename(slice.binary_path, File.extname(slice.binary_path)) }.uniq
1161
+ if binary_names.size > 1
1162
+ raise Informative, <<-MSG.strip_heredoc
1163
+ Unable to install vendored xcframework `#{xcframework.name}` for Pod `#{target.label}` because it contains static libraries
1164
+ with differing binary names: #{binary_names.to_sentence}.
1165
+ MSG
1166
+ end
1167
+ end
1168
+ dynamic_slices, static_slices = xcframework.slices.partition(&:dynamic?)
1095
1169
  if !dynamic_slices.empty? && !static_slices.empty?
1096
1170
  raise Informative, "Unable to install vendored xcframework `#{xcframework.name}` for Pod `#{target.label}`, because it contains both static and dynamic frameworks."
1097
1171
  end
1172
+ library_slices, framework_slices = xcframework.slices.partition(&:library?)
1173
+ if !library_slices.empty? && !framework_slices.empty?
1174
+ raise Informative, "Unable to install vendored xcframework `#{xcframework.name}` for Pod `#{target.label}`, because it contains both libraries and frameworks."
1175
+ end
1098
1176
  end
1099
1177
  end
1100
1178
  end
1179
+
1101
1180
  #-----------------------------------------------------------------------#
1181
+
1182
+ class << self
1183
+ # @param [PodTarget] target the target to be installed
1184
+ #
1185
+ # @return [Array<String>] the dSYM paths for the given target
1186
+ #
1187
+ def dsym_paths(target)
1188
+ dsym_paths = target.framework_paths.values.flatten.reject { |fmwk_path| fmwk_path.dsym_path.nil? }.map(&:dsym_path)
1189
+ dsym_paths.concat(target.xcframeworks.values.flatten.flat_map { |xcframework| xcframework_dsyms(xcframework.path) })
1190
+ dsym_paths
1191
+ end
1192
+
1193
+ # @param [PodTarget] target the target to be installed
1194
+ #
1195
+ # @return [Array<String>] the bcsymbolmap paths for the given target
1196
+ #
1197
+ def bcsymbolmap_paths(target)
1198
+ target.framework_paths.values.flatten.reject do |fmwk_path|
1199
+ fmwk_path.bcsymbolmap_paths.nil?
1200
+ end.flat_map(&:bcsymbolmap_paths)
1201
+ end
1202
+
1203
+ # @param [Pathname] xcframework_path
1204
+ # the base path of the .xcframework bundle
1205
+ #
1206
+ # @return [Array<Pathname>] all found .dSYM paths
1207
+ #
1208
+ def xcframework_dsyms(xcframework_path)
1209
+ basename = File.basename(xcframework_path, '.xcframework')
1210
+ dsym_basename = basename + '.dSYMs'
1211
+ path = xcframework_path.dirname + dsym_basename
1212
+ if File.directory?(path)
1213
+ Dir.glob(path + '*.dSYM')
1214
+ else
1215
+ []
1216
+ end
1217
+ end
1218
+ end
1102
1219
  end
1103
1220
  end
1104
1221
  end