cocoapods 1.8.4 → 1.9.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +69 -1
  3. data/lib/cocoapods.rb +1 -0
  4. data/lib/cocoapods/command/setup.rb +1 -0
  5. data/lib/cocoapods/executable.rb +1 -1
  6. data/lib/cocoapods/gem_version.rb +1 -1
  7. data/lib/cocoapods/generator/embed_frameworks_script.rb +36 -6
  8. data/lib/cocoapods/generator/prepare_artifacts_script.rb +244 -0
  9. data/lib/cocoapods/installer.rb +6 -5
  10. data/lib/cocoapods/installer/analyzer.rb +137 -59
  11. data/lib/cocoapods/installer/analyzer/pod_variant.rb +27 -12
  12. data/lib/cocoapods/installer/analyzer/pod_variant_set.rb +11 -2
  13. data/lib/cocoapods/installer/project_cache/project_cache_analyzer.rb +10 -2
  14. data/lib/cocoapods/installer/project_cache/project_installation_cache.rb +15 -2
  15. data/lib/cocoapods/installer/project_cache/target_cache_key.rb +7 -5
  16. data/lib/cocoapods/installer/user_project_integrator.rb +1 -10
  17. data/lib/cocoapods/installer/user_project_integrator/target_integrator.rb +100 -19
  18. data/lib/cocoapods/installer/xcode/pods_project_generator.rb +3 -0
  19. data/lib/cocoapods/installer/xcode/pods_project_generator/aggregate_target_installer.rb +29 -4
  20. data/lib/cocoapods/installer/xcode/pods_project_generator/app_host_installer.rb +7 -2
  21. data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_installer.rb +106 -45
  22. data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_integrator.rb +68 -1
  23. data/lib/cocoapods/installer/xcode/pods_project_generator/pods_project_writer.rb +29 -14
  24. data/lib/cocoapods/sandbox/file_accessor.rb +32 -21
  25. data/lib/cocoapods/sources_manager.rb +9 -2
  26. data/lib/cocoapods/target.rb +11 -14
  27. data/lib/cocoapods/target/aggregate_target.rb +78 -18
  28. data/lib/cocoapods/target/build_settings.rb +64 -31
  29. data/lib/cocoapods/target/pod_target.rb +236 -87
  30. data/lib/cocoapods/user_interface/error_report.rb +14 -4
  31. data/lib/cocoapods/validator.rb +2 -0
  32. data/lib/cocoapods/xcode.rb +7 -0
  33. data/lib/cocoapods/{target → xcode}/framework_paths.rb +14 -1
  34. data/lib/cocoapods/xcode/linkage_analyzer.rb +22 -0
  35. data/lib/cocoapods/xcode/xcframework.rb +81 -0
  36. data/lib/cocoapods/xcode/xcframework/xcframework_slice.rb +51 -0
  37. metadata +12 -8
  38. data/lib/cocoapods/target/build_type.rb +0 -139
@@ -22,6 +22,10 @@ module Pod
22
22
  #
23
23
  attr_reader :project_object_version
24
24
 
25
+ # @return [Hash<String, Hash>] The podfile plugins to be run for the installation.
26
+ #
27
+ attr_reader :podfile_plugins
28
+
25
29
  # @return [Array<PodTarget>] The list of pod targets.
26
30
  #
27
31
  attr_reader :pod_targets
@@ -40,15 +44,17 @@ module Pod
40
44
  # @param [ProjectInstallationCache] cache @see #cache
41
45
  # @param [Hash{String => Symbol}] build_configurations @see #build_configurations
42
46
  # @param [Integer] project_object_version @see #project_object_version
47
+ # @param [Hash<String, Hash>] podfile_plugins @see #podfile_plugins
43
48
  # @param [Array<PodTarget>] pod_targets @see #pod_targets
44
49
  # @param [Array<AggregateTarget>] aggregate_targets @see #aggregate_targets
45
50
  # @param [Bool] clean_install @see #clean_install
46
51
  #
47
- def initialize(sandbox, cache, build_configurations, project_object_version, pod_targets, aggregate_targets,
52
+ def initialize(sandbox, cache, build_configurations, project_object_version, podfile_plugins, pod_targets, aggregate_targets,
48
53
  clean_install: false)
49
54
  @sandbox = sandbox
50
55
  @cache = cache
51
56
  @build_configurations = build_configurations
57
+ @podfile_plugins = podfile_plugins
52
58
  @pod_targets = pod_targets
53
59
  @aggregate_targets = aggregate_targets
54
60
  @project_object_version = project_object_version
@@ -70,7 +76,9 @@ module Pod
70
76
  end
71
77
 
72
78
  # Bail out early since these properties affect all targets and their associate projects.
73
- if cache.build_configurations != build_configurations || cache.project_object_version != project_object_version
79
+ if cache.build_configurations != build_configurations ||
80
+ cache.project_object_version != project_object_version ||
81
+ YAMLHelper.convert(cache.podfile_plugins) != YAMLHelper.convert(podfile_plugins)
74
82
  UI.message 'Ignoring project cache due to project configuration changes.'
75
83
  return full_install_results
76
84
  end
@@ -21,16 +21,23 @@ module Pod
21
21
  #
22
22
  attr_reader :project_object_version
23
23
 
24
+ # @return [Hash<String, Hash>]
25
+ # Podfile plugins used with a particular install.
26
+ #
27
+ attr_reader :podfile_plugins
28
+
24
29
  # Initializes a new instance.
25
30
  #
26
31
  # @param [Hash{String => TargetCacheKey}] cache_key_by_target_label @see #cache_key_by_target_label
27
32
  # @param [Hash{String => Symbol}] build_configurations @see #build_configurations
28
33
  # @param [Integer] project_object_version @see #project_object_version
34
+ # @param [Hash<String, Hash>] podfile_plugins @see #podfile_plugins
29
35
  #
30
- def initialize(cache_key_by_target_label = {}, build_configurations = nil, project_object_version = nil)
36
+ def initialize(cache_key_by_target_label = {}, build_configurations = nil, project_object_version = nil, podfile_plugins = {})
31
37
  @cache_key_by_target_label = cache_key_by_target_label
32
38
  @build_configurations = build_configurations
33
39
  @project_object_version = project_object_version
40
+ @podfile_plugins = podfile_plugins
34
41
  end
35
42
 
36
43
  def update_cache_key_by_target_label!(cache_key_by_target_label)
@@ -45,6 +52,10 @@ module Pod
45
52
  @project_object_version = project_object_version
46
53
  end
47
54
 
55
+ def update_podfile_plugins!(podfile_plugins)
56
+ @podfile_plugins = podfile_plugins
57
+ end
58
+
48
59
  def save_as(path)
49
60
  Pathname(path).dirname.mkpath
50
61
  Sandbox.update_changed_file(path, YAMLHelper.convert(to_hash))
@@ -59,7 +70,8 @@ module Pod
59
70
  end]
60
71
  project_object_version = contents['OBJECT_VERSION']
61
72
  build_configurations = contents['BUILD_CONFIGURATIONS']
62
- ProjectInstallationCache.new(cache_key_by_target_label, build_configurations, project_object_version)
73
+ podfile_plugins = contents['PLUGINS']
74
+ ProjectInstallationCache.new(cache_key_by_target_label, build_configurations, project_object_version, podfile_plugins)
63
75
  end
64
76
 
65
77
  def to_hash
@@ -69,6 +81,7 @@ module Pod
69
81
  contents = { 'CACHE_KEYS' => cache_key_contents }
70
82
  contents['BUILD_CONFIGURATIONS'] = build_configurations if build_configurations
71
83
  contents['OBJECT_VERSION'] = project_object_version if project_object_version
84
+ contents['PLUGINS'] = podfile_plugins if podfile_plugins
72
85
  contents
73
86
  end
74
87
  end
@@ -116,12 +116,14 @@ module Pod
116
116
  #
117
117
  def self.from_pod_target(sandbox, pod_target, is_local_pod: false, checkout_options: nil)
118
118
  build_settings = {}
119
- build_settings[pod_target.label.to_s] = Digest::MD5.hexdigest(pod_target.build_settings.xcconfig.to_s)
120
- pod_target.test_spec_build_settings.each do |name, settings|
121
- build_settings[name] = Digest::MD5.hexdigest(settings.xcconfig.to_s)
119
+ build_settings[pod_target.label.to_s] = Hash[pod_target.build_settings.map do |k, v|
120
+ [k, Digest::MD5.hexdigest(v.xcconfig.to_s)]
121
+ end]
122
+ pod_target.test_spec_build_settings_by_config.each do |name, settings_by_config|
123
+ build_settings[name] = Hash[settings_by_config.map { |k, v| [k, Digest::MD5.hexdigest(v.xcconfig.to_s)] }]
122
124
  end
123
- pod_target.app_spec_build_settings.each do |name, settings|
124
- build_settings[name] = Digest::MD5.hexdigest(settings.xcconfig.to_s)
125
+ pod_target.app_spec_build_settings_by_config.each do |name, settings_by_config|
126
+ build_settings[name] = Hash[settings_by_config.map { |k, v| [k, Digest::MD5.hexdigest(v.xcconfig.to_s)] }]
125
127
  end
126
128
 
127
129
  contents = {
@@ -92,7 +92,7 @@ module Pod
92
92
  # @return [void]
93
93
  #
94
94
  def create_workspace
95
- all_projects = user_project_paths_to_integrate.sort.push(sandbox.project_path).uniq
95
+ all_projects = user_project_paths.sort.push(sandbox.project_path).uniq
96
96
  file_references = all_projects.map do |path|
97
97
  relative_path = path.relative_path_from(workspace_path.dirname).to_s
98
98
  Xcodeproj::Workspace::FileReference.new(relative_path, 'group')
@@ -221,15 +221,6 @@ module Pod
221
221
  end
222
222
  end
223
223
 
224
- # @return [Array<Pathname>] the paths of all the user projects referenced
225
- # by the targets that require integration.
226
- #
227
- # @note Empty target definitions are ignored.
228
- #
229
- def user_project_paths_to_integrate
230
- targets_to_integrate.map(&:user_project_path).compact.uniq
231
- end
232
-
233
224
  # @return [Array<Xcodeproj::Project>] the projects of all the targets that require integration.
234
225
  #
235
226
  # @note Empty target definitions are ignored.
@@ -1,5 +1,5 @@
1
1
  require 'active_support/core_ext/string/inflections'
2
- require 'cocoapods/target/framework_paths'
2
+ require 'cocoapods/xcode/framework_paths'
3
3
 
4
4
  module Pod
5
5
  class Installer
@@ -37,6 +37,10 @@ module Pod
37
37
  #
38
38
  EMBED_FRAMEWORK_PHASE_NAME = 'Embed Pods Frameworks'.freeze
39
39
 
40
+ # @return [String] the name of the embed frameworks phase
41
+ #
42
+ PREPARE_ARTIFACTS_PHASE_NAME = 'Prepare Artifacts'.freeze
43
+
40
44
  # @return [String] the name of the copy resources phase
41
45
  #
42
46
  COPY_PODS_RESOURCES_PHASE_NAME = 'Copy Pods Resources'.freeze
@@ -45,6 +49,10 @@ module Pod
45
49
  #
46
50
  MAX_INPUT_OUTPUT_PATHS = 1000
47
51
 
52
+ # @return [String] the path to the artifact lists file used in the prepare & embed scripts
53
+ #
54
+ ARTIFACT_LIST_FILE = '${BUILT_PRODUCTS_DIR}/cocoapods-artifacts-${CONFIGURATION}.txt'.freeze
55
+
48
56
  # @return [AggregateTarget] the target that should be integrated.
49
57
  #
50
58
  attr_reader :target
@@ -135,15 +143,52 @@ module Pod
135
143
  TargetIntegrator.set_input_output_paths(phase, input_paths_by_config, output_paths_by_config)
136
144
  end
137
145
 
146
+ # Adds a shell script build phase responsible to copy xcframeworks slices
147
+ # generated by the TargetDefinition to the build directory.
148
+ #
149
+ # @param [PBXNativeTarget] native_target
150
+ # The native target to add the script phase into.
151
+ #
152
+ # @param [String] script_path
153
+ # The script path to execute as part of this script phase.
154
+ #
155
+ # @param [Hash<Array, String>] input_paths_by_config
156
+ # The input paths (if any) to include for this script phase.
157
+ #
158
+ # @param [Hash<Array, String>] output_paths_by_config
159
+ # The output paths (if any) to include for this script phase.
160
+ #
161
+ # @return [void]
162
+ #
163
+ def create_or_update_prepare_artifacts_script_phase_to_target(native_target, script_path, input_paths_by_config = {}, output_paths_by_config = {})
164
+ phase = TargetIntegrator.create_or_update_shell_script_build_phase(native_target, BUILD_PHASE_PREFIX + PREPARE_ARTIFACTS_PHASE_NAME)
165
+ phase.shell_script = %("#{script_path}"\n)
166
+ reorder_script_phase(native_target, phase, :before_compile)
167
+ TargetIntegrator.set_input_output_paths(phase, input_paths_by_config, output_paths_by_config)
168
+ end
169
+
138
170
  # Delete a 'Embed Pods Frameworks' Copy Files Build Phase if present
139
171
  #
140
172
  # @param [PBXNativeTarget] native_target
141
173
  # The native target to remove the script phase from.
142
174
  #
143
175
  def remove_embed_frameworks_script_phase_from_target(native_target)
144
- embed_build_phase = native_target.shell_script_build_phases.find { |bp| bp.name && bp.name.end_with?(EMBED_FRAMEWORK_PHASE_NAME) }
145
- return unless embed_build_phase.present?
146
- native_target.build_phases.delete(embed_build_phase)
176
+ remove_script_phase_from_target(native_target, EMBED_FRAMEWORK_PHASE_NAME)
177
+ end
178
+
179
+ # Delete a 'Embed Pods Frameworks' Copy Files Build Phase if present
180
+ #
181
+ # @param [PBXNativeTarget] native_target
182
+ # The native target to remove the script phase from.
183
+ #
184
+ def remove_prepare_artifacts_script_phase_from_target(native_target)
185
+ remove_script_phase_from_target(native_target, PREPARE_ARTIFACTS_PHASE_NAME)
186
+ end
187
+
188
+ def remove_script_phase_from_target(native_target, phase_name)
189
+ build_phase = native_target.shell_script_build_phases.find { |bp| bp.name && bp.name.end_with?(phase_name) }
190
+ return unless build_phase.present?
191
+ native_target.build_phases.delete(build_phase)
147
192
  end
148
193
 
149
194
  # Adds a shell script build phase responsible to copy the resources
@@ -235,6 +280,7 @@ module Pod
235
280
  phase.output_paths = script_phase[:output_files]
236
281
  phase.input_file_list_paths = script_phase[:input_file_lists]
237
282
  phase.output_file_list_paths = script_phase[:output_file_lists]
283
+ phase.dependency_file = script_phase[:dependency_file]
238
284
  # At least with Xcode 10 `showEnvVarsInLog` is *NOT* set to any value even if it's checked and it only
239
285
  # gets set to '0' if the user has explicitly disabled this.
240
286
  if (show_env_vars_in_log = script_phase.fetch(:show_env_vars_in_log, '1')) == '0'
@@ -242,19 +288,22 @@ module Pod
242
288
  end
243
289
 
244
290
  execution_position = script_phase[:execution_position]
245
- unless execution_position == :any
246
- compile_build_phase_index = native_target.build_phases.index do |bp|
247
- bp.is_a?(Xcodeproj::Project::Object::PBXSourcesBuildPhase)
248
- end
249
- unless compile_build_phase_index.nil?
250
- script_phase_index = native_target.build_phases.index do |bp|
251
- bp.is_a?(Xcodeproj::Project::Object::PBXShellScriptBuildPhase) && !bp.name.nil? && bp.name == name_with_prefix
252
- end
253
- if (execution_position == :before_compile && script_phase_index > compile_build_phase_index) ||
254
- (execution_position == :after_compile && script_phase_index < compile_build_phase_index)
255
- native_target.build_phases.move_from(script_phase_index, compile_build_phase_index)
256
- end
257
- end
291
+ reorder_script_phase(native_target, phase, execution_position)
292
+ end
293
+ end
294
+
295
+ def reorder_script_phase(native_target, script_phase, execution_position)
296
+ return if execution_position == :any
297
+ compile_build_phase_index = native_target.build_phases.index do |bp|
298
+ bp.is_a?(Xcodeproj::Project::Object::PBXSourcesBuildPhase)
299
+ end
300
+ unless compile_build_phase_index.nil?
301
+ script_phase_index = native_target.build_phases.index do |bp|
302
+ bp.is_a?(Xcodeproj::Project::Object::PBXShellScriptBuildPhase) && !bp.name.nil? && bp.name == script_phase.name
303
+ end
304
+ if (execution_position == :before_compile && script_phase_index > compile_build_phase_index) ||
305
+ (execution_position == :after_compile && script_phase_index < compile_build_phase_index)
306
+ native_target.build_phases.move_from(script_phase_index, compile_build_phase_index)
258
307
  end
259
308
  end
260
309
  end
@@ -318,7 +367,7 @@ module Pod
318
367
 
319
368
  # Returns the framework output paths for the given input paths
320
369
  #
321
- # @param [Array<Target::FrameworkPaths>] framework_input_paths
370
+ # @param [Array<Xcode::FrameworkPaths>] framework_input_paths
322
371
  # The framework input paths to map to output paths.
323
372
  #
324
373
  # @return [Array<String>] The framework output paths
@@ -351,6 +400,7 @@ module Pod
351
400
 
352
401
  add_pods_library
353
402
  add_embed_frameworks_script_phase
403
+ add_prepare_artifacts_script_phase
354
404
  remove_embed_frameworks_script_phase_from_embedded_targets
355
405
  add_copy_resources_script_phase
356
406
  add_check_manifest_lock_script_phase
@@ -454,7 +504,7 @@ module Pod
454
504
  # @return [void]
455
505
  #
456
506
  def add_embed_frameworks_script_phase
457
- unless target.includes_frameworks?
507
+ unless target.includes_frameworks? || target.includes_xcframeworks?
458
508
  native_targets_to_embed_in.each do |native_target|
459
509
  TargetIntegrator.remove_embed_frameworks_script_phase_from_target(native_target)
460
510
  end
@@ -468,6 +518,7 @@ module Pod
468
518
  target.framework_paths_by_config.each do |config, framework_paths|
469
519
  input_paths_key = XCFileListConfigKey.new(target.embed_frameworks_script_input_files_path(config), target.embed_frameworks_script_input_files_relative_path)
470
520
  input_paths = input_paths_by_config[input_paths_key] = [script_path]
521
+ input_paths << ARTIFACT_LIST_FILE if target.includes_xcframeworks?
471
522
  framework_paths.each do |path|
472
523
  input_paths.concat(path.all_paths)
473
524
  end
@@ -482,6 +533,36 @@ module Pod
482
533
  end
483
534
  end
484
535
 
536
+ # Find or create a 'Prepare Artifacts' Copy Files Build Phase
537
+ #
538
+ # @return [void]
539
+ #
540
+ def add_prepare_artifacts_script_phase
541
+ unless target.includes_xcframeworks?
542
+ native_targets_to_embed_in.each do |native_target|
543
+ TargetIntegrator.remove_prepare_artifacts_script_phase_from_target(native_target)
544
+ end
545
+ return
546
+ end
547
+
548
+ script_path = target.prepare_artifacts_script_relative_path
549
+ input_paths_by_config = {}
550
+ output_paths_by_config = {}
551
+ if use_input_output_paths?
552
+ target.xcframeworks_by_config.each do |config, xcframeworks|
553
+ input_paths_key = XCFileListConfigKey.new(target.prepare_artifacts_script_input_files_path(config), target.prepare_artifacts_script_input_files_relative_path)
554
+ input_paths = input_paths_by_config[input_paths_key] = [script_path]
555
+ input_paths.concat(xcframeworks.map { |xcf| "${PODS_ROOT}/#{xcf.path.relative_path_from(target.sandbox.root)}" })
556
+
557
+ output_paths_key = XCFileListConfigKey.new(target.prepare_artifacts_script_output_files_path(config), target.prepare_artifacts_script_output_files_relative_path)
558
+ output_paths_by_config[output_paths_key] = [ARTIFACT_LIST_FILE]
559
+ end
560
+ end
561
+ native_targets_to_embed_in.each do |native_target|
562
+ TargetIntegrator.create_or_update_prepare_artifacts_script_phase_to_target(native_target, script_path, input_paths_by_config, output_paths_by_config)
563
+ end
564
+ end
565
+
485
566
  # Updates all target script phases for the current target, including creating or updating, deleting
486
567
  # and re-ordering.
487
568
  #
@@ -238,6 +238,9 @@ module Pod
238
238
  environment_variables.assign_variable(:key => k, :value => v)
239
239
  end
240
240
  scheme.launch_action.environment_variables = environment_variables
241
+ if scheme_configuration.key?(:code_coverage)
242
+ scheme.test_action.code_coverage_enabled = scheme_configuration[:code_coverage]
243
+ end
241
244
  scheme.save!
242
245
  end
243
246
  Xcodeproj::XCScheme.share_scheme(project.path, scheme_name) if share_scheme
@@ -16,7 +16,7 @@ module Pod
16
16
  create_support_files_dir
17
17
  create_support_files_group
18
18
  create_xcconfig_file(native_target)
19
- if target.host_requires_frameworks?
19
+ if target.build_as_framework?
20
20
  create_info_plist_file(target.info_plist_path, native_target, target.version, target.platform)
21
21
  create_module_map(native_target)
22
22
  create_umbrella_header(native_target)
@@ -30,7 +30,8 @@ module Pod
30
30
  # cause an App Store rejection because frameworks cannot be
31
31
  # embedded in embedded targets.
32
32
  #
33
- create_embed_frameworks_script if target.includes_frameworks? && !target.requires_host_target?
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?
34
35
  create_bridge_support_file(native_target)
35
36
  create_copy_resources_script if target.includes_resources?
36
37
  create_acknowledgements
@@ -145,8 +146,8 @@ module Pod
145
146
  # Creates a script that embeds the frameworks to the bundle of the client
146
147
  # target.
147
148
  #
148
- # @note We can't use Xcode default copy bundle resource phase, because
149
- # we need to ensure that we only copy the resources, which are
149
+ # @note We can't use Xcode default link libraries phase, because
150
+ # we need to ensure that we only copy the frameworks which are
150
151
  # relevant for the current build configuration.
151
152
  #
152
153
  # @return [void]
@@ -158,6 +159,30 @@ module Pod
158
159
  add_file_to_support_group(path)
159
160
  end
160
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)
173
+ update_changed_file(generator, path)
174
+ 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
+ end
185
+
161
186
  # Generates the acknowledgement files (markdown and plist) for the target.
162
187
  #
163
188
  # @return [void]
@@ -37,6 +37,10 @@ module Pod
37
37
  #
38
38
  attr_reader :add_main
39
39
 
40
+ # @return [Boolean] whether the app host installer should add a launch screen storyboard
41
+ #
42
+ attr_reader :add_launchscreen_storyboard
43
+
40
44
  # @return [Hash] Info.plist entries for the app host
41
45
  #
42
46
  attr_reader :info_plist_entries
@@ -52,7 +56,7 @@ module Pod
52
56
  # @param [Boolean] add_main see #add_main
53
57
  # @param [Hash] info_plist_entries see #info_plist_entries
54
58
  #
55
- def initialize(sandbox, project, platform, subgroup_name, group_name, app_target_label, add_main: true, info_plist_entries: {})
59
+ def initialize(sandbox, project, platform, subgroup_name, group_name, app_target_label, add_main: true, add_launchscreen_storyboard: platform == :ios, info_plist_entries: {})
56
60
  @sandbox = sandbox
57
61
  @project = project
58
62
  @platform = platform
@@ -60,6 +64,7 @@ module Pod
60
64
  @group_name = group_name
61
65
  @app_target_label = app_target_label
62
66
  @add_main = add_main
67
+ @add_launchscreen_storyboard = add_launchscreen_storyboard
63
68
  @info_plist_entries = info_plist_entries
64
69
  target_group = project.pod_group(group_name)
65
70
  @group = target_group[subgroup_name] || target_group.new_group(subgroup_name)
@@ -79,7 +84,7 @@ module Pod
79
84
  end
80
85
 
81
86
  Pod::Generator::AppTargetHelper.add_app_host_main_file(project, app_host_target, platform_name, @group, app_target_label) if add_main
82
- Pod::Generator::AppTargetHelper.add_launchscreen_storyboard(project, app_host_target, @group, deployment_target, app_target_label) if platform == :ios
87
+ Pod::Generator::AppTargetHelper.add_launchscreen_storyboard(project, app_host_target, @group, deployment_target, app_target_label) if add_launchscreen_storyboard
83
88
  create_info_plist_file_with_sandbox(sandbox, app_host_info_plist_path, app_host_target, '1.0.0', platform,
84
89
  :appl, :additional_entries => additional_info_plist_entries)
85
90
  @group.new_file(app_host_info_plist_path)
@@ -1,3 +1,5 @@
1
+ require 'cocoapods/xcode'
2
+
1
3
  module Pod
2
4
  class Installer
3
5
  class Xcode
@@ -56,6 +58,7 @@ module Pod
56
58
 
57
59
  add_files_to_build_phases(native_target, test_native_targets, app_native_targets)
58
60
  validate_targets_contain_sources(test_native_targets + app_native_targets + [native_target])
61
+ validate_xcframeworks_no_mixed_linkage
59
62
 
60
63
  create_xcconfig_file(native_target, resource_bundle_targets)
61
64
  create_test_xcconfig_files(test_native_targets, test_resource_bundle_targets)
@@ -69,7 +72,7 @@ module Pod
69
72
  generator.imports += library_file_accessors.flat_map do |file_accessor|
70
73
  header_dir = if !target.build_as_framework? && dir = file_accessor.spec_consumer.header_dir
71
74
  Pathname.new(dir)
72
- end
75
+ end
73
76
 
74
77
  file_accessor.public_headers.map do |public_header|
75
78
  public_header = if header_mappings_dir(file_accessor)
@@ -148,14 +151,18 @@ module Pod
148
151
  # Removes overrides of the `pod_target_xcconfig` settings from the target's
149
152
  # build configurations.
150
153
  #
151
- # @return [Void]
152
- #
153
- # @param [Target::BuildSettings] build_settings
154
+ # @param [Hash{Symbol => Pod::Target::BuildSettings}] build_settings_by_config the build settings by config
155
+ # of the target.
154
156
  #
155
157
  # @param [PBXNativeTarget] native_target
158
+ # the native target to remove pod target xcconfig overrides from.
159
+ #
160
+ # @return [Void]
156
161
  #
157
- def remove_pod_target_xcconfig_overrides_from_target(build_settings, native_target)
162
+ #
163
+ def remove_pod_target_xcconfig_overrides_from_target(build_settings_by_config, native_target)
158
164
  native_target.build_configurations.each do |configuration|
165
+ build_settings = build_settings_by_config[target.user_build_configurations[configuration.name]]
159
166
  build_settings.merged_pod_target_xcconfigs.each_key do |setting|
160
167
  configuration.build_settings.delete(setting)
161
168
  end
@@ -365,9 +372,10 @@ module Pod
365
372
  configuration.build_settings['CODE_SIGN_IDENTITY'] = '' if target.platform == :osx
366
373
  end
367
374
 
368
- remove_pod_target_xcconfig_overrides_from_target(target.build_settings_for_spec(test_spec), test_native_target)
375
+ remove_pod_target_xcconfig_overrides_from_target(target.test_spec_build_settings_by_config[test_spec.name], test_native_target)
369
376
 
370
377
  # Test native targets also need frameworks and resources to be copied over to their xctest bundle.
378
+ create_test_target_prepare_artifacts_script(test_spec)
371
379
  create_test_target_embed_frameworks_script(test_spec)
372
380
  create_test_target_copy_resources_script(test_spec)
373
381
 
@@ -411,8 +419,11 @@ module Pod
411
419
  app_target_label = target.app_target_label(app_spec)
412
420
  platform = Platform.new(target.platform.symbolic_name, target.deployment_target_for_non_library_spec(app_spec))
413
421
  info_plist_entries = spec_consumer.info_plist
422
+ resources = target.file_accessors.find { |fa| fa.spec == app_spec }.resources
423
+ add_launchscreen_storyboard = resources.none? { |resource| resource.basename.to_s == 'LaunchScreen.storyboard' } && platform.name == :ios
414
424
  app_native_target = AppHostInstaller.new(sandbox, project, platform, subspec_name, spec_name,
415
425
  app_target_label, :add_main => false,
426
+ :add_launchscreen_storyboard => add_launchscreen_storyboard,
416
427
  :info_plist_entries => info_plist_entries).install!
417
428
 
418
429
  app_native_target.product_reference.name = app_target_label
@@ -454,11 +465,11 @@ module Pod
454
465
  end
455
466
  end
456
467
 
457
- remove_pod_target_xcconfig_overrides_from_target(target.build_settings_for_spec(app_spec), app_native_target)
468
+ remove_pod_target_xcconfig_overrides_from_target(target.app_spec_build_settings_by_config[app_spec.name], app_native_target)
458
469
 
459
470
  create_app_target_embed_frameworks_script(app_spec)
460
471
  create_app_target_copy_resources_script(app_spec)
461
- add_resources_to_target(target.file_accessors.find { |fa| fa.spec == app_spec }.resources, app_native_target)
472
+ add_resources_to_target(resources, app_native_target)
462
473
 
463
474
  app_native_target
464
475
  end
@@ -489,7 +500,7 @@ module Pod
489
500
  # @param [Array<Sandbox::FileAccessor>] file_accessors
490
501
  # the file accessors list to generate resource bundles for.
491
502
  #
492
- # @return [Array<PBXNativeTarget>] the resource bundle native targets created.
503
+ # @return [Hash{String=>Array<PBXNativeTarget>}] the resource bundle native targets created.
493
504
  #
494
505
  def add_resources_bundle_targets(file_accessors)
495
506
  file_accessors.each_with_object({}) do |file_accessor, hash|
@@ -548,7 +559,7 @@ module Pod
548
559
  end
549
560
  end
550
561
 
551
- remove_pod_target_xcconfig_overrides_from_target(target.build_settings_for_spec(file_accessor.spec), resource_bundle_target)
562
+ remove_pod_target_xcconfig_overrides_from_target(target.build_settings_by_config_for_spec(file_accessor.spec), resource_bundle_target)
552
563
 
553
564
  resource_bundle_target
554
565
  end
@@ -566,12 +577,14 @@ module Pod
566
577
  # @return [void]
567
578
  #
568
579
  def create_xcconfig_file(native_target, resource_bundle_targets)
569
- path = target.xcconfig_path
570
- update_changed_file(target.build_settings, path)
571
- xcconfig_file_ref = add_file_to_support_group(path)
580
+ target.user_config_names_by_config_type.each do |config, names|
581
+ path = target.xcconfig_path(config)
582
+ update_changed_file(target.build_settings[config], path)
583
+ xcconfig_file_ref = add_file_to_support_group(path)
572
584
 
573
- # also apply the private config to resource bundle targets.
574
- apply_xcconfig_file_ref_to_targets([native_target] + resource_bundle_targets, xcconfig_file_ref)
585
+ # also apply the private config to resource bundle targets.
586
+ apply_xcconfig_file_ref_to_targets([native_target] + resource_bundle_targets, xcconfig_file_ref, names)
587
+ end
575
588
  end
576
589
 
577
590
  # Generates the contents of the xcconfig file used for each test target type and saves it to disk.
@@ -588,19 +601,22 @@ module Pod
588
601
  target.test_specs.each do |test_spec|
589
602
  spec_consumer = test_spec.consumer(target.platform)
590
603
  test_type = spec_consumer.test_type
591
- path = target.xcconfig_path("#{test_type.capitalize}-#{target.subspec_label(test_spec)}")
592
- test_spec_build_settings = target.build_settings_for_spec(test_spec)
593
- update_changed_file(test_spec_build_settings, path)
594
- test_xcconfig_file_ref = add_file_to_support_group(path)
595
-
596
604
  test_native_target = test_native_target_from_spec(spec_consumer.spec, test_native_targets)
605
+
606
+ target.user_config_names_by_config_type.each do |config, names|
607
+ path = target.xcconfig_path("#{test_type.capitalize}-#{target.subspec_label(test_spec)}.#{config}")
608
+ test_spec_build_settings = target.build_settings_for_spec(test_spec, :configuration => config)
609
+ update_changed_file(test_spec_build_settings, path)
610
+ test_xcconfig_file_ref = add_file_to_support_group(path)
611
+
612
+ # also apply the private config to resource bundle test targets related to this test spec.
613
+ scoped_test_resource_bundle_targets = test_resource_bundle_targets[test_spec.name]
614
+ apply_xcconfig_file_ref_to_targets([test_native_target] + scoped_test_resource_bundle_targets, test_xcconfig_file_ref, names)
615
+ end
616
+
597
617
  test_native_target.build_configurations.each do |test_native_target_bc|
598
618
  test_target_swift_debug_hack(test_spec, test_native_target_bc)
599
619
  end
600
-
601
- # also apply the private config to resource bundle test targets related to this test spec.
602
- scoped_test_resource_bundle_targets = test_resource_bundle_targets[test_spec.name]
603
- apply_xcconfig_file_ref_to_targets([test_native_target] + scoped_test_resource_bundle_targets, test_xcconfig_file_ref)
604
620
  end
605
621
  end
606
622
 
@@ -613,12 +629,11 @@ module Pod
613
629
  #
614
630
  def create_test_target_copy_resources_script(test_spec)
615
631
  path = target.copy_resources_script_path_for_spec(test_spec)
616
- pod_targets = target.dependent_targets_for_test_spec(test_spec)
617
632
  host_target_spec_names = target.app_host_dependent_targets_for_spec(test_spec).flat_map do |pt|
618
633
  pt.specs.map(&:name)
619
634
  end.uniq
620
- resource_paths_by_config = target.user_build_configurations.keys.each_with_object({}) do |config, resources_by_config|
621
- resources_by_config[config] = pod_targets.flat_map do |pod_target|
635
+ resource_paths_by_config = target.user_build_configurations.each_with_object({}) do |(config_name, config), resources_by_config|
636
+ resources_by_config[config_name] = target.dependent_targets_for_test_spec(test_spec, :configuration => config).flat_map do |pod_target|
622
637
  spec_paths_to_include = pod_target.library_specs.map(&:name)
623
638
  spec_paths_to_include -= host_target_spec_names
624
639
  spec_paths_to_include << test_spec.name if pod_target == target
@@ -632,6 +647,33 @@ module Pod
632
647
  end
633
648
  end
634
649
 
650
+ # Creates a script that prepares artifacts for the test target.
651
+ #
652
+ # @param [Specification] test_spec
653
+ # The test spec to create the script for.
654
+ #
655
+ # @return [void]
656
+ #
657
+ def create_test_target_prepare_artifacts_script(test_spec)
658
+ path = target.prepare_artifacts_script_path_for_spec(test_spec)
659
+ host_target_spec_names = target.app_host_dependent_targets_for_spec(test_spec).flat_map do |pt|
660
+ pt.specs.map(&:name)
661
+ end.uniq
662
+ frameworks_by_config = target.user_build_configurations.each_with_object({}) do |(config_name, config), paths_by_config|
663
+ paths_by_config[config_name] = target.dependent_targets_for_test_spec(test_spec, :configuration => config).flat_map do |pod_target|
664
+ spec_paths_to_include = pod_target.library_specs.map(&:name)
665
+ spec_paths_to_include -= host_target_spec_names
666
+ spec_paths_to_include << test_spec.name if pod_target == target
667
+ pod_target.xcframeworks.values_at(*spec_paths_to_include).flatten.compact.uniq
668
+ end
669
+ end
670
+ unless frameworks_by_config.each_value.all?(&:empty?)
671
+ generator = Generator::PrepareArtifactsScript.new(frameworks_by_config, target.sandbox.root, target.platform)
672
+ update_changed_file(generator, path)
673
+ add_file_to_support_group(path)
674
+ end
675
+ end
676
+
635
677
  # Creates a script that embeds the frameworks to the bundle of the test target.
636
678
  #
637
679
  # @param [Specification] test_spec
@@ -641,12 +683,11 @@ module Pod
641
683
  #
642
684
  def create_test_target_embed_frameworks_script(test_spec)
643
685
  path = target.embed_frameworks_script_path_for_spec(test_spec)
644
- pod_targets = target.dependent_targets_for_test_spec(test_spec)
645
686
  host_target_spec_names = target.app_host_dependent_targets_for_spec(test_spec).flat_map do |pt|
646
687
  pt.specs.map(&:name)
647
688
  end.uniq
648
- framework_paths_by_config = target.user_build_configurations.keys.each_with_object({}) do |config, paths_by_config|
649
- paths_by_config[config] = pod_targets.flat_map do |pod_target|
689
+ framework_paths_by_config = target.user_build_configurations.each_with_object({}) do |(config_name, config), paths_by_config|
690
+ paths_by_config[config_name] = target.dependent_targets_for_test_spec(test_spec, :configuration => config).flat_map do |pod_target|
650
691
  spec_paths_to_include = pod_target.library_specs.map(&:name)
651
692
  spec_paths_to_include -= host_target_spec_names
652
693
  spec_paths_to_include << test_spec.name if pod_target == target
@@ -673,15 +714,18 @@ module Pod
673
714
  def create_app_xcconfig_files(app_native_targets, app_resource_bundle_targets)
674
715
  target.app_specs.each do |app_spec|
675
716
  spec_consumer = app_spec.consumer(target.platform)
676
- path = target.xcconfig_path(target.subspec_label(app_spec))
677
- update_changed_file(target.build_settings_for_spec(app_spec), path)
678
- app_xcconfig_file_ref = add_file_to_support_group(path)
679
-
680
717
  app_native_target = app_native_target_from_spec(spec_consumer.spec, app_native_targets)
681
718
 
682
- # also apply the private config to resource bundle app targets related to this app spec.
683
- scoped_app_resource_bundle_targets = app_resource_bundle_targets[app_spec.name]
684
- apply_xcconfig_file_ref_to_targets([app_native_target] + scoped_app_resource_bundle_targets, app_xcconfig_file_ref)
719
+ target.user_config_names_by_config_type.each do |config, names|
720
+ path = target.xcconfig_path("#{target.subspec_label(app_spec)}.#{config}")
721
+ app_spec_build_settings = target.build_settings_for_spec(app_spec, :configuration => config)
722
+ update_changed_file(app_spec_build_settings, path)
723
+ app_xcconfig_file_ref = add_file_to_support_group(path)
724
+
725
+ # also apply the private config to resource bundle app targets related to this app spec.
726
+ scoped_app_resource_bundle_targets = app_resource_bundle_targets[app_spec.name]
727
+ apply_xcconfig_file_ref_to_targets([app_native_target] + scoped_app_resource_bundle_targets, app_xcconfig_file_ref, names)
728
+ end
685
729
  end
686
730
  end
687
731
 
@@ -694,9 +738,9 @@ module Pod
694
738
  #
695
739
  def create_app_target_copy_resources_script(app_spec)
696
740
  path = target.copy_resources_script_path_for_spec(app_spec)
697
- pod_targets = target.dependent_targets_for_app_spec(app_spec)
698
- resource_paths_by_config = target.user_build_configurations.keys.each_with_object({}) do |config, resources_by_config|
699
- resources_by_config[config] = pod_targets.flat_map do |pod_target|
741
+ resource_paths_by_config = target.user_build_configurations.each_with_object({}) do |(config_name, config), resources_by_config|
742
+ pod_targets = target.dependent_targets_for_app_spec(app_spec, :configuration => config)
743
+ resources_by_config[config_name] = pod_targets.flat_map do |pod_target|
700
744
  spec_paths_to_include = pod_target.library_specs.map(&:name)
701
745
  spec_paths_to_include << app_spec.name if pod_target == target
702
746
  pod_target.resource_paths.values_at(*spec_paths_to_include).flatten.compact
@@ -718,9 +762,9 @@ module Pod
718
762
  #
719
763
  def create_app_target_embed_frameworks_script(app_spec)
720
764
  path = target.embed_frameworks_script_path_for_spec(app_spec)
721
- pod_targets = target.dependent_targets_for_app_spec(app_spec)
722
- framework_paths_by_config = target.user_build_configurations.keys.each_with_object({}) do |config, paths_by_config|
723
- paths_by_config[config] = pod_targets.flat_map do |pod_target|
765
+ framework_paths_by_config = target.user_build_configurations.each_with_object({}) do |(config_name, config), paths_by_config|
766
+ pod_targets = target.dependent_targets_for_app_spec(app_spec, :configuration => config)
767
+ paths_by_config[config_name] = pod_targets.flat_map do |pod_target|
724
768
  spec_paths_to_include = pod_target.library_specs.map(&:name)
725
769
  spec_paths_to_include << app_spec.name if pod_target == target
726
770
  pod_target.framework_paths.values_at(*spec_paths_to_include).flatten.compact.uniq
@@ -841,9 +885,10 @@ module Pod
841
885
  flags * ' '
842
886
  end
843
887
 
844
- def apply_xcconfig_file_ref_to_targets(targets, xcconfig_file_ref)
888
+ def apply_xcconfig_file_ref_to_targets(targets, xcconfig_file_ref, configurations)
845
889
  targets.each do |config_target|
846
890
  config_target.build_configurations.each do |configuration|
891
+ next unless configurations.include?(configuration.name)
847
892
  configuration.base_configuration_reference = xcconfig_file_ref
848
893
  end
849
894
  end
@@ -928,16 +973,20 @@ module Pod
928
973
  'Project'
929
974
  end
930
975
 
931
- if target.build_as_framework? && any_header_mapping_dirs? && acl != 'Project'
976
+ if target.build_as_framework? && !header_mappings_dir(file_accessor).nil? && acl != 'Project'
932
977
  relative_path = if mapping_dir = header_mappings_dir(file_accessor)
933
978
  file_ref.real_path.relative_path_from(mapping_dir)
934
979
  else
935
980
  file_ref.real_path.relative_path_from(file_accessor.path_list.root)
936
981
  end
982
+ compile_build_phase_index = native_target.build_phases.index do |bp|
983
+ bp.is_a?(Xcodeproj::Project::Object::PBXSourcesBuildPhase)
984
+ end
937
985
  sub_dir = relative_path.dirname
938
986
  copy_phase_name = "Copy #{sub_dir} #{acl} Headers"
939
987
  copy_phase = native_target.copy_files_build_phases.find { |bp| bp.name == copy_phase_name } ||
940
988
  native_target.new_copy_files_build_phase(copy_phase_name)
989
+ native_target.build_phases.move(copy_phase, compile_build_phase_index - 1) unless compile_build_phase_index.nil?
941
990
  copy_phase.symbol_dst_subfolder_spec = :products_directory
942
991
  copy_phase.dst_path = "$(#{acl.upcase}_HEADERS_FOLDER_PATH)/#{sub_dir}"
943
992
  copy_phase.add_file_reference(file_ref, true)
@@ -1035,6 +1084,18 @@ module Pod
1035
1084
  end
1036
1085
  end
1037
1086
 
1087
+ # Raises if a vendored xcframework contains frameworks of mixed linkage
1088
+ #
1089
+ def validate_xcframeworks_no_mixed_linkage
1090
+ target.xcframeworks.each_value do |xcframeworks|
1091
+ xcframeworks.each do |xcframework|
1092
+ dynamic_slices, static_slices = xcframework.slices.partition { |slice| Pod::Xcode::LinkageAnalyzer.dynamic_binary?(slice.path) }
1093
+ if !dynamic_slices.empty? && !static_slices.empty?
1094
+ raise Informative, "Unable to install vendored xcframework `#{xcframework.name}` for Pod `#{target.label}`, because it contains both static and dynamic frameworks."
1095
+ end
1096
+ end
1097
+ end
1098
+ end
1038
1099
  #-----------------------------------------------------------------------#
1039
1100
  end
1040
1101
  end