cocoapods 1.5.2 → 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +365 -1
  3. data/bin/pod +1 -1
  4. data/lib/cocoapods/command/cache/clean.rb +1 -1
  5. data/lib/cocoapods/command/init.rb +4 -2
  6. data/lib/cocoapods/command/install.rb +7 -0
  7. data/lib/cocoapods/command/lib/lint.rb +8 -1
  8. data/lib/cocoapods/command/outdated.rb +4 -9
  9. data/lib/cocoapods/command/repo/add.rb +1 -1
  10. data/lib/cocoapods/command/repo/list.rb +1 -1
  11. data/lib/cocoapods/command/repo/push.rb +17 -12
  12. data/lib/cocoapods/command/repo/remove.rb +1 -1
  13. data/lib/cocoapods/command/repo/update.rb +1 -1
  14. data/lib/cocoapods/command/setup.rb +1 -1
  15. data/lib/cocoapods/command/spec/create.rb +39 -39
  16. data/lib/cocoapods/command/spec/lint.rb +8 -1
  17. data/lib/cocoapods/command.rb +3 -1
  18. data/lib/cocoapods/config.rb +13 -2
  19. data/lib/cocoapods/downloader/cache.rb +1 -1
  20. data/lib/cocoapods/executable.rb +3 -3
  21. data/lib/cocoapods/external_sources/abstract_external_source.rb +23 -13
  22. data/lib/cocoapods/external_sources.rb +7 -4
  23. data/lib/cocoapods/gem_version.rb +1 -1
  24. data/lib/cocoapods/generator/acknowledgements/markdown.rb +6 -0
  25. data/lib/cocoapods/generator/acknowledgements/plist.rb +13 -2
  26. data/lib/cocoapods/generator/app_target_helper.rb +141 -17
  27. data/lib/cocoapods/generator/copy_resources_script.rb +14 -3
  28. data/lib/cocoapods/generator/dummy_source.rb +14 -5
  29. data/lib/cocoapods/generator/embed_frameworks_script.rb +37 -20
  30. data/lib/cocoapods/generator/header.rb +1 -1
  31. data/lib/cocoapods/generator/info_plist_file.rb +12 -4
  32. data/lib/cocoapods/generator/prefix_header.rb +2 -2
  33. data/lib/cocoapods/hooks_manager.rb +28 -17
  34. data/lib/cocoapods/installer/analyzer/analysis_result.rb +52 -22
  35. data/lib/cocoapods/installer/analyzer/locking_dependency_analyzer.rb +14 -6
  36. data/lib/cocoapods/installer/analyzer/pod_variant.rb +4 -5
  37. data/lib/cocoapods/installer/analyzer/sandbox_analyzer.rb +3 -14
  38. data/lib/cocoapods/installer/analyzer/specs_state.rb +28 -4
  39. data/lib/cocoapods/installer/analyzer/target_inspection_result.rb +27 -14
  40. data/lib/cocoapods/installer/analyzer/target_inspector.rb +17 -11
  41. data/lib/cocoapods/installer/analyzer.rb +391 -284
  42. data/lib/cocoapods/installer/installation_options.rb +2 -0
  43. data/lib/cocoapods/installer/pod_source_installer.rb +31 -43
  44. data/lib/cocoapods/installer/post_install_hooks_context.rb +72 -47
  45. data/lib/cocoapods/installer/pre_install_hooks_context.rb +22 -13
  46. data/lib/cocoapods/installer/source_provider_hooks_context.rb +3 -1
  47. data/lib/cocoapods/installer/user_project_integrator/target_integrator/xcconfig_integrator.rb +44 -11
  48. data/lib/cocoapods/installer/user_project_integrator/target_integrator.rb +69 -29
  49. data/lib/cocoapods/installer/user_project_integrator.rb +6 -4
  50. data/lib/cocoapods/installer/xcode/pods_project_generator/aggregate_target_installer.rb +25 -16
  51. data/lib/cocoapods/installer/xcode/pods_project_generator/app_host_installer.rb +104 -0
  52. data/lib/cocoapods/installer/xcode/pods_project_generator/file_references_installer.rb +23 -50
  53. data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_installer.rb +296 -177
  54. data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_integrator.rb +51 -33
  55. data/lib/cocoapods/installer/xcode/pods_project_generator/target_installation_result.rb +93 -0
  56. data/lib/cocoapods/installer/xcode/pods_project_generator/target_installer.rb +62 -69
  57. data/lib/cocoapods/installer/xcode/pods_project_generator/target_installer_helper.rb +72 -0
  58. data/lib/cocoapods/installer/xcode/pods_project_generator.rb +130 -122
  59. data/lib/cocoapods/installer/xcode/target_validator.rb +15 -9
  60. data/lib/cocoapods/installer.rb +140 -63
  61. data/lib/cocoapods/project.rb +16 -14
  62. data/lib/cocoapods/resolver/resolver_specification.rb +41 -0
  63. data/lib/cocoapods/resolver.rb +79 -98
  64. data/lib/cocoapods/sandbox/file_accessor.rb +11 -6
  65. data/lib/cocoapods/sandbox/headers_store.rb +9 -8
  66. data/lib/cocoapods/sandbox/path_list.rb +5 -8
  67. data/lib/cocoapods/sandbox.rb +31 -43
  68. data/lib/cocoapods/sources_manager.rb +1 -1
  69. data/lib/cocoapods/target/aggregate_target.rb +143 -85
  70. data/lib/cocoapods/target/build_settings.rb +1124 -0
  71. data/lib/cocoapods/target/framework_paths.rb +36 -0
  72. data/lib/cocoapods/target/pod_target.rb +198 -295
  73. data/lib/cocoapods/target.rb +92 -37
  74. data/lib/cocoapods/user_interface.rb +5 -0
  75. data/lib/cocoapods/validator.rb +149 -44
  76. data/lib/cocoapods.rb +0 -1
  77. metadata +31 -23
  78. data/lib/cocoapods/generator/xcconfig/aggregate_xcconfig.rb +0 -260
  79. data/lib/cocoapods/generator/xcconfig/pod_xcconfig.rb +0 -87
  80. data/lib/cocoapods/generator/xcconfig/xcconfig_helper.rb +0 -558
  81. data/lib/cocoapods/generator/xcconfig.rb +0 -13
@@ -6,75 +6,108 @@ module Pod
6
6
  # relative support files.
7
7
  #
8
8
  class PodTargetInstaller < TargetInstaller
9
+ require 'cocoapods/installer/xcode/pods_project_generator/app_host_installer'
10
+
11
+ # @return [Array<Pathname>] Array of umbrella header paths in the headers directory
12
+ #
13
+ attr_reader :umbrella_header_paths
14
+
15
+ # Initialize a new instance
16
+ #
17
+ # @param [Sandbox] sandbox @see TargetInstaller#sandbox
18
+ # @param [Pod::Project] project @see TargetInstaller#project
19
+ # @param [Target] target @see TargetInstaller#target
20
+ # @param [Array<Pathname>] umbrella_header_paths @see #umbrella_header_paths
21
+ #
22
+ def initialize(sandbox, project, target, umbrella_header_paths = nil)
23
+ super(sandbox, project, target)
24
+ @umbrella_header_paths = umbrella_header_paths
25
+ end
26
+
9
27
  # Creates the target in the Pods project and the relative support files.
10
28
  #
11
- # @return [void]
29
+ # @return [TargetInstallationResult] the result of the installation of this target.
12
30
  #
13
31
  def install!
14
- unless target.should_build?
15
- add_resources_bundle_targets
16
- return
17
- end
18
-
19
32
  UI.message "- Installing target `#{target.name}` #{target.platform}" do
20
- add_target
21
33
  create_support_files_dir
22
- if target.contains_test_specifications?
23
- add_test_targets
24
- add_test_app_host_targets
34
+ test_file_accessors, file_accessors = target.file_accessors.partition { |fa| fa.spec.test_specification? }
35
+
36
+ unless target.should_build?
37
+ # For targets that should not be built (e.g. pre-built vendored frameworks etc), we add a placeholder
38
+ # PBXAggregateTarget that will be used to wire up dependencies later.
39
+ native_target = add_placeholder_target
40
+ resource_bundle_targets = add_resources_bundle_targets(file_accessors).values.flatten
41
+ create_xcconfig_file(native_target, resource_bundle_targets)
42
+ return TargetInstallationResult.new(target, native_target, resource_bundle_targets)
25
43
  end
26
- add_resources_bundle_targets
27
- add_files_to_build_phases
28
- create_xcconfig_file
29
- create_test_xcconfig_files if target.contains_test_specifications?
44
+
45
+ native_target = add_target
46
+ resource_bundle_targets = add_resources_bundle_targets(file_accessors).values.flatten
47
+
48
+ test_native_targets = add_test_targets
49
+ test_app_host_targets = add_test_app_host_targets(test_native_targets)
50
+ test_resource_bundle_targets = add_resources_bundle_targets(test_file_accessors)
51
+
52
+ add_files_to_build_phases(native_target, test_native_targets)
53
+ validate_targets_contain_sources(test_native_targets + [native_target])
54
+
55
+ create_xcconfig_file(native_target, resource_bundle_targets)
56
+ create_test_xcconfig_files(test_native_targets, test_resource_bundle_targets)
30
57
 
31
58
  if target.defines_module?
32
- create_module_map do |generator|
59
+ create_module_map(native_target) do |generator|
33
60
  generator.headers.concat module_map_additional_headers
34
61
  end
35
- create_umbrella_header do |generator|
36
- file_accessors = target.file_accessors
37
- file_accessors = file_accessors.reject { |f| f.spec.test_specification? } if target.contains_test_specifications?
38
- generator.imports += if header_mappings_dir
39
- file_accessors.flat_map(&:public_headers).map do |pathname|
40
- pathname.relative_path_from(header_mappings_dir)
41
- end
42
- else
43
- file_accessors.flat_map(&:public_headers).map(&:basename)
62
+ create_umbrella_header(native_target) do |generator|
63
+ generator.imports += file_accessors.flat_map do |file_accessor|
64
+ header_dir = if !target.requires_frameworks? && dir = file_accessor.spec_consumer.header_dir
65
+ Pathname.new(dir)
66
+ end
67
+
68
+ file_accessor.public_headers.map do |public_header|
69
+ public_header = if header_mappings_dir
70
+ public_header.relative_path_from(header_mappings_dir)
71
+ else
72
+ public_header.basename
44
73
  end
74
+ if header_dir
75
+ public_header = header_dir.join(public_header)
76
+ end
77
+ public_header
78
+ end
79
+ end
45
80
  end
46
81
  end
47
82
 
48
83
  if target.requires_frameworks?
49
- unless target.static_framework?
84
+ unless skip_info_plist?(native_target)
50
85
  create_info_plist_file(target.info_plist_path, native_target, target.version, target.platform)
51
86
  end
52
- create_build_phase_to_symlink_header_folders
87
+ create_build_phase_to_symlink_header_folders(native_target)
53
88
  elsif target.uses_swift?
54
- add_swift_static_library_compatibility_header_phase
89
+ add_swift_static_library_compatibility_header_phase(native_target)
55
90
  end
56
91
 
57
92
  unless skip_pch?(target.non_test_specs)
58
93
  path = target.prefix_header_path
59
- file_accessors = target.file_accessors.reject { |f| f.spec.test_specification? }
60
- create_prefix_header(path, file_accessors, target.platform, [native_target])
94
+ create_prefix_header(path, file_accessors, target.platform, native_target)
61
95
  end
62
96
  unless skip_pch?(target.test_specs)
63
- target.supported_test_types.each do |test_type|
64
- path = target.prefix_header_path_for_test_type(test_type)
65
- file_accessors = target.file_accessors.select { |f| f.spec.test_specification? }
66
- create_prefix_header(path, file_accessors, target.platform, target.test_native_targets)
97
+ target.test_specs.each do |test_spec|
98
+ path = target.prefix_header_path_for_test_spec(test_spec)
99
+ test_spec_consumer = test_spec.consumer(target.platform)
100
+ test_native_target = test_native_target_from_spec_consumer(test_spec_consumer, test_native_targets)
101
+ create_prefix_header(path, test_file_accessors, target.platform, test_native_target)
67
102
  end
68
103
  end
69
- create_dummy_source
104
+ create_dummy_source(native_target)
105
+ clean_support_files_temp_dir
106
+ TargetInstallationResult.new(target, native_target, resource_bundle_targets, test_native_targets,
107
+ test_resource_bundle_targets, test_app_host_targets)
70
108
  end
71
109
  end
72
110
 
73
- # @return [Hash<Pathname,Pathname>] A hash of all umbrella headers, grouped by the directory
74
- # the are stored in
75
- #
76
- attr_accessor :umbrella_headers_by_dir
77
-
78
111
  private
79
112
 
80
113
  # @param [Array<Specification>] specs
@@ -86,6 +119,17 @@ module Pod
86
119
  specs.any? { |spec| spec.prefix_header_file.is_a?(FalseClass) }
87
120
  end
88
121
 
122
+ # True if info.plist generation should be skipped
123
+ #
124
+ # @param [PXNativeTarget] native_target
125
+ #
126
+ # @return [Boolean] Whether the target should build an Info.plist file
127
+ #
128
+ def skip_info_plist?(native_target)
129
+ existing_setting = native_target.resolved_build_setting('INFOPLIST_FILE', true).values.compact
130
+ !existing_setting.empty?
131
+ end
132
+
89
133
  # Remove the default headers folder path settings for static library pod
90
134
  # targets.
91
135
  #
@@ -158,8 +202,6 @@ module Pod
158
202
 
159
203
  #-----------------------------------------------------------------------#
160
204
 
161
- SOURCE_FILE_EXTENSIONS = Sandbox::FileAccessor::SOURCE_FILE_EXTENSIONS
162
-
163
205
  # Adds the build files of the pods to the target and adds a reference to
164
206
  # the frameworks of the Pods.
165
207
  #
@@ -173,20 +215,26 @@ module Pod
173
215
  #
174
216
  # @return [void]
175
217
  #
176
- def add_files_to_build_phases
218
+ def add_files_to_build_phases(native_target, test_native_targets)
177
219
  target.file_accessors.each do |file_accessor|
178
220
  consumer = file_accessor.spec_consumer
179
221
 
180
- native_target = target.native_target_for_spec(consumer.spec)
222
+ native_target = if !consumer.spec.test_specification?
223
+ native_target
224
+ else
225
+ test_native_target_from_spec_consumer(consumer, test_native_targets)
226
+ end
227
+
181
228
  headers = file_accessor.headers
182
229
  public_headers = file_accessor.public_headers.map(&:realpath)
183
230
  private_headers = file_accessor.private_headers.map(&:realpath)
184
- other_source_files = file_accessor.source_files.reject { |sf| SOURCE_FILE_EXTENSIONS.include?(sf.extname) }
231
+ other_source_files = file_accessor.other_source_files
185
232
 
186
233
  {
187
234
  true => file_accessor.arc_source_files,
188
235
  false => file_accessor.non_arc_source_files,
189
236
  }.each do |arc, files|
237
+ next if files.empty?
190
238
  files = files - headers - other_source_files
191
239
  flags = compiler_flags_for_consumer(consumer, arc)
192
240
  regular_file_refs = project_file_references_array(files, 'source')
@@ -210,62 +258,27 @@ module Pod
210
258
  end
211
259
  end
212
260
 
213
- # Adds the test app host targets for the library to the Pods project with the
214
- # appropriate build configurations.
215
- #
216
- # @return [void]
217
- #
218
- def add_test_app_host_targets
219
- target.test_specs.each do |test_spec|
220
- next unless test_spec.consumer(target.platform).requires_app_host?
221
- name = target.app_host_label(test_spec.test_type)
222
- platform_name = target.platform.name
223
- app_host_target = project.targets.find { |t| t.name == name }
224
- if app_host_target.nil?
225
- app_host_target = Pod::Generator::AppTargetHelper.add_app_target(project, platform_name, deployment_target, name)
226
- app_host_target.build_configurations.each do |configuration|
227
- configuration.build_settings.merge!(custom_build_settings)
228
- configuration.build_settings['PRODUCT_NAME'] = name
229
- configuration.build_settings['PRODUCT_BUNDLE_IDENTIFIER'] = 'org.cocoapods.${PRODUCT_NAME:rfc1034identifier}'
230
- configuration.build_settings['CODE_SIGN_IDENTITY'] = '' if target.platform == :osx
231
- end
232
- Pod::Generator::AppTargetHelper.add_app_host_main_file(project, app_host_target, platform_name, name)
233
- app_host_info_plist_path = project.path.dirname.+("#{name}/Info.plist")
234
- create_info_plist_file(app_host_info_plist_path, app_host_target, '1.0.0', target.platform, :appl)
235
- end
236
- # Wire all test native targets with the app host.
237
- native_test_target = target.native_target_for_spec(test_spec)
238
- native_test_target.build_configurations.each do |configuration|
239
- test_host = "$(BUILT_PRODUCTS_DIR)/#{name}.app/"
240
- test_host << 'Contents/MacOS/' if target.platform == :osx
241
- test_host << name.to_s
242
- configuration.build_settings['TEST_HOST'] = test_host
243
- end
244
- target_attributes = project.root_object.attributes['TargetAttributes'] || {}
245
- target_attributes[native_test_target.uuid.to_s] = { 'TestTargetID' => app_host_target.uuid.to_s }
246
- project.root_object.attributes['TargetAttributes'] = target_attributes
247
- end
248
- end
249
-
250
261
  # Adds the test targets for the library to the Pods project with the
251
262
  # appropriate build configurations.
252
263
  #
253
- # @return [void]
264
+ # @return [Array<PBXNativeTarget>] the test native targets created.
254
265
  #
255
266
  def add_test_targets
256
- target.supported_test_types.each do |test_type|
267
+ target.test_specs.map do |test_spec|
268
+ spec_consumer = test_spec.consumer(target.platform)
269
+ test_type = spec_consumer.test_type
257
270
  product_type = target.product_type_for_test_type(test_type)
258
- name = target.test_target_label(test_type)
271
+ name = target.test_target_label(test_spec)
259
272
  platform_name = target.platform.name
260
- language = target.all_dependent_targets.any?(&:uses_swift?) ? :swift : :objc
261
- native_test_target = project.new_target(product_type, name, platform_name, deployment_target, nil, language)
262
- native_test_target.product_reference.name = name
273
+ language = target.uses_swift_for_test_spec?(test_spec) ? :swift : :objc
274
+ test_native_target = project.new_target(product_type, name, platform_name, deployment_target, nil, language)
275
+ test_native_target.product_reference.name = name
263
276
 
264
277
  target.user_build_configurations.each do |bc_name, type|
265
- native_test_target.add_build_configuration(bc_name, type)
278
+ test_native_target.add_build_configuration(bc_name, type)
266
279
  end
267
280
 
268
- native_test_target.build_configurations.each do |configuration|
281
+ test_native_target.build_configurations.each do |configuration|
269
282
  configuration.build_settings.merge!(custom_build_settings)
270
283
  # target_installer will automatically add an empty `OTHER_LDFLAGS`. For test
271
284
  # targets those are set via a test xcconfig file instead.
@@ -274,6 +287,9 @@ module Pod
274
287
  # requires frameworks. For tests we always use the test target name as the product name
275
288
  # irrelevant to whether we use frameworks or not.
276
289
  configuration.build_settings['PRODUCT_NAME'] = name
290
+ # target_installer sets 'MACH_O_TYPE' for static frameworks ensure this does not propagate
291
+ # to test target.
292
+ configuration.build_settings.delete('MACH_O_TYPE')
277
293
  # Use xcode default product module name, which is $(PRODUCT_NAME:c99extidentifier)
278
294
  # this gives us always valid name that is distinct from the parent spec module name
279
295
  # which allow tests to use either import or @testable import to access the parent framework
@@ -288,15 +304,46 @@ module Pod
288
304
  end
289
305
 
290
306
  # Test native targets also need frameworks and resources to be copied over to their xctest bundle.
291
- create_test_target_embed_frameworks_script(test_type)
292
- create_test_target_copy_resources_script(test_type)
307
+ create_test_target_embed_frameworks_script(test_spec)
308
+ create_test_target_copy_resources_script(test_spec)
293
309
 
294
- # Generate vanila Info.plist for test target similar to the one xcode gererates for new test target.
310
+ # Generate vanilla Info.plist for test target similar to the one Xcode generates for new test target.
295
311
  # This creates valid test bundle accessible at the runtime, allowing tests to load bundle resources
296
312
  # defined in podspec.
297
- create_info_plist_file(target.info_plist_path_for_test_type(test_type), native_test_target, '1.0', target.platform, :bndl)
313
+ create_info_plist_file(target.info_plist_path_for_test_spec(test_spec), test_native_target, '1.0', target.platform, :bndl)
314
+
315
+ test_native_target
316
+ end
317
+ end
298
318
 
299
- target.test_native_targets << native_test_target
319
+ # Adds the test app host targets for the library to the Pods project with the
320
+ # appropriate build configurations.
321
+ #
322
+ # @param [Array<PBXNativeTarget>] test_native_targets
323
+ # the test native targets that have been created to use as a lookup when linking the app host to.
324
+ #
325
+ # @return [Array<PBXNativeTarget>] the app host targets created.
326
+ #
327
+ def add_test_app_host_targets(test_native_targets)
328
+ target.test_spec_consumers.select(&:requires_app_host?).group_by(&:test_type).map do |test_type, test_spec_consumers|
329
+ platform = target.platform
330
+ name = "AppHost-#{target.label}-#{test_type.capitalize}-Tests"
331
+ app_host_target = AppHostInstaller.new(sandbox, project, platform, name, target.pod_name).install!
332
+ # Wire test native targets to the generated app host.
333
+ test_spec_consumers.each do |test_spec_consumer|
334
+ test_native_target = test_native_target_from_spec_consumer(test_spec_consumer, test_native_targets)
335
+ test_native_target.build_configurations.each do |configuration|
336
+ test_host = "$(BUILT_PRODUCTS_DIR)/#{app_host_target.name}.app/"
337
+ test_host << 'Contents/MacOS/' if platform == :osx
338
+ test_host << app_host_target.name.to_s
339
+ configuration.build_settings['TEST_HOST'] = test_host
340
+ end
341
+ target_attributes = project.root_object.attributes['TargetAttributes'] || {}
342
+ target_attributes[test_native_target.uuid.to_s] = { 'TestTargetID' => app_host_target.uuid.to_s }
343
+ project.root_object.attributes['TargetAttributes'] = target_attributes
344
+ test_native_target.add_dependency(app_host_target)
345
+ end
346
+ app_host_target
300
347
  end
301
348
  end
302
349
 
@@ -305,58 +352,53 @@ module Pod
305
352
  # @note The source files are grouped by Pod and in turn by subspec
306
353
  # (recursively) in the resources group.
307
354
  #
308
- # @return [void]
355
+ # @param [Array<Sandbox::FileAccessor>] file_accessors
356
+ # the file accessors list to generate resource bundles for.
309
357
  #
310
- def add_resources_bundle_targets
311
- target.file_accessors.each do |file_accessor|
312
- file_accessor.resource_bundles.each do |bundle_name, paths|
358
+ # @return [Array<PBXNativeTarget] the resource bundle native targets created.
359
+ #
360
+ def add_resources_bundle_targets(file_accessors)
361
+ file_accessors.each_with_object({}) do |file_accessor, hash|
362
+ hash[file_accessor.spec.name] = file_accessor.resource_bundles.map do |bundle_name, paths|
313
363
  label = target.resources_bundle_target_label(bundle_name)
314
- bundle_target = project.new_resources_bundle(label, file_accessor.spec_consumer.platform_name)
315
- bundle_target.product_reference.tap do |bundle_product|
364
+ resource_bundle_target = project.new_resources_bundle(label, file_accessor.spec_consumer.platform_name)
365
+ resource_bundle_target.product_reference.tap do |bundle_product|
316
366
  bundle_file_name = "#{bundle_name}.bundle"
317
367
  bundle_product.name = bundle_file_name
318
368
  end
319
369
 
370
+ contains_compile_phase_refs = false
320
371
  filter_resource_file_references(paths) do |resource_phase_refs, compile_phase_refs|
321
372
  # Resource bundles are only meant to have resources, so install everything
322
373
  # into the resources phase. See note in filter_resource_file_references.
323
- bundle_target.add_resources(resource_phase_refs + compile_phase_refs)
374
+ resource_bundle_target.add_resources(resource_phase_refs + compile_phase_refs)
375
+ contains_compile_phase_refs = !compile_phase_refs.empty?
324
376
  end
325
377
 
326
- native_target = target.native_target_for_spec(file_accessor.spec_consumer.spec)
327
378
  target.user_build_configurations.each do |bc_name, type|
328
- bundle_target.add_build_configuration(bc_name, type)
329
- end
330
- bundle_target.deployment_target = deployment_target
331
-
332
- test_specification = file_accessor.spec.test_specification?
333
-
334
- if test_specification
335
- target.test_resource_bundle_targets << bundle_target
336
- else
337
- target.resource_bundle_targets << bundle_target
338
- end
339
-
340
- if target.should_build?
341
- native_target.add_dependency(bundle_target)
342
- if target.requires_frameworks?
343
- native_target.add_resources([bundle_target.product_reference])
344
- end
379
+ resource_bundle_target.add_build_configuration(bc_name, type)
345
380
  end
381
+ resource_bundle_target.deployment_target = deployment_target
346
382
 
347
383
  # Create Info.plist file for bundle
348
384
  path = target.info_plist_path
349
385
  path.dirname.mkdir unless path.dirname.exist?
350
386
  info_plist_path = path.dirname + "ResourceBundle-#{bundle_name}-#{path.basename}"
351
- create_info_plist_file(info_plist_path, bundle_target, target.version, target.platform, :bndl)
387
+ create_info_plist_file(info_plist_path, resource_bundle_target, target.version, target.platform, :bndl)
352
388
 
353
- bundle_target.build_configurations.each do |c|
354
- c.build_settings['PRODUCT_NAME'] = bundle_name
389
+ resource_bundle_target.build_configurations.each do |configuration|
390
+ configuration.build_settings['PRODUCT_NAME'] = bundle_name
355
391
  # Do not set the CONFIGURATION_BUILD_DIR for resource bundles that are only meant for test targets.
356
392
  # This is because the test target itself also does not set this configuration build dir and it expects
357
393
  # all bundles to be copied from the default path.
358
- unless test_specification
359
- c.build_settings['CONFIGURATION_BUILD_DIR'] = target.configuration_build_dir('$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)')
394
+ unless file_accessor.spec.test_specification?
395
+ configuration.build_settings['CONFIGURATION_BUILD_DIR'] = target.configuration_build_dir('$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)')
396
+ end
397
+
398
+ # Set the `SWIFT_VERSION` build setting for resource bundles that could have resources that get
399
+ # compiled such as an `xcdatamodeld` file which has 'Swift' as its code generation language.
400
+ if contains_compile_phase_refs && target.uses_swift?
401
+ configuration.build_settings['SWIFT_VERSION'] = target.swift_version
360
402
  end
361
403
 
362
404
  # Set the correct device family for this bundle, based on the platform
@@ -367,21 +409,28 @@ module Pod
367
409
  }
368
410
 
369
411
  if (family = device_family_by_platform[target.platform.name])
370
- c.build_settings['TARGETED_DEVICE_FAMILY'] = family
412
+ configuration.build_settings['TARGETED_DEVICE_FAMILY'] = family
371
413
  end
372
414
  end
415
+
416
+ resource_bundle_target
373
417
  end
374
418
  end
375
419
  end
376
420
 
377
421
  # Generates the contents of the xcconfig file and saves it to disk.
378
422
  #
423
+ # @param [PBXNativeTarget] native_target
424
+ # the native target to link the xcconfig file into.
425
+ #
426
+ # @param [Array<PBXNativeTarget>] resource_bundle_targets
427
+ # the additional resource bundle targets to link the xcconfig file into.
428
+ #
379
429
  # @return [void]
380
430
  #
381
- def create_xcconfig_file
431
+ def create_xcconfig_file(native_target, resource_bundle_targets)
382
432
  path = target.xcconfig_path
383
- xcconfig_gen = Generator::XCConfig::PodXCConfig.new(target)
384
- update_changed_file(xcconfig_gen, path)
433
+ update_changed_file(target.build_settings, path)
385
434
  xcconfig_file_ref = add_file_to_support_group(path)
386
435
 
387
436
  native_target.build_configurations.each do |c|
@@ -389,46 +438,56 @@ module Pod
389
438
  end
390
439
 
391
440
  # also apply the private config to resource bundle targets.
392
- apply_xcconfig_file_ref_to_resource_bundle_targets(target.resource_bundle_targets, xcconfig_file_ref)
441
+ apply_xcconfig_file_ref_to_resource_bundle_targets(resource_bundle_targets, xcconfig_file_ref)
393
442
  end
394
443
 
395
444
  # Generates the contents of the xcconfig file used for each test target type and saves it to disk.
396
445
  #
446
+ # @param [Array<PBXNativeTarget>] test_native_targets
447
+ # the test native target to link the xcconfig file into.
448
+ #
449
+ # @param [Hash{String=>Array<PBXNativeTarget>}] test_resource_bundle_targets
450
+ # the additional test resource bundle targets to link the xcconfig file into.
451
+ #
397
452
  # @return [void]
398
453
  #
399
- def create_test_xcconfig_files
400
- target.supported_test_types.each do |test_type|
401
- path = target.xcconfig_path(test_type.to_s)
402
- xcconfig_gen = Generator::XCConfig::PodXCConfig.new(target, true)
403
- update_changed_file(xcconfig_gen, path)
404
- xcconfig_file_ref = add_file_to_support_group(path)
405
-
406
- target.test_native_targets.each do |test_target|
407
- test_target.build_configurations.each do |test_target_bc|
408
- test_target_swift_debug_hack(test_target_bc)
409
- test_target_bc.base_configuration_reference = xcconfig_file_ref
410
- end
454
+ def create_test_xcconfig_files(test_native_targets, test_resource_bundle_targets)
455
+ target.test_specs.each do |test_spec|
456
+ spec_consumer = test_spec.consumer(target.platform)
457
+ test_type = spec_consumer.test_type
458
+ path = target.xcconfig_path("#{test_type.capitalize}-#{test_spec.name.split('/')[1..-1].join('-')}")
459
+ update_changed_file(Target::BuildSettings::PodTargetSettings.new(target, test_spec), path)
460
+ test_xcconfig_file_ref = add_file_to_support_group(path)
461
+
462
+ test_native_target = test_native_target_from_spec_consumer(spec_consumer, test_native_targets)
463
+ test_native_target.build_configurations.each do |test_native_target_bc|
464
+ test_target_swift_debug_hack(test_spec, test_native_target_bc)
465
+ test_native_target_bc.base_configuration_reference = test_xcconfig_file_ref
411
466
  end
412
467
 
413
- # also apply the private config to resource bundle test targets.
414
- apply_xcconfig_file_ref_to_resource_bundle_targets(target.test_resource_bundle_targets, xcconfig_file_ref)
468
+ # also apply the private config to resource bundle test targets related to this test spec.
469
+ scoped_test_resource_bundle_targets = test_resource_bundle_targets[test_spec.name]
470
+ unless scoped_test_resource_bundle_targets.empty?
471
+ apply_xcconfig_file_ref_to_resource_bundle_targets(scoped_test_resource_bundle_targets, test_xcconfig_file_ref)
472
+ end
415
473
  end
416
474
  end
417
475
 
418
476
  # Creates a script that copies the resources to the bundle of the test target.
419
477
  #
420
- # @param [Symbol] test_type
421
- # The test type to create the script for.
478
+ # @param [Specification] test_spec
479
+ # The test spec to create the copy resources script for.
422
480
  #
423
481
  # @return [void]
424
482
  #
425
- def create_test_target_copy_resources_script(test_type)
426
- path = target.copy_resources_script_path_for_test_type(test_type)
427
- pod_targets = target.all_dependent_targets
483
+ def create_test_target_copy_resources_script(test_spec)
484
+ path = target.copy_resources_script_path_for_test_spec(test_spec)
485
+ pod_targets = target.dependent_targets_for_test_spec(test_spec)
428
486
  resource_paths_by_config = target.user_build_configurations.keys.each_with_object({}) do |config, resources_by_config|
429
487
  resources_by_config[config] = pod_targets.flat_map do |pod_target|
430
- include_test_spec_paths = pod_target == target
431
- pod_target.resource_paths(include_test_spec_paths)
488
+ spec_paths_to_include = pod_target.non_test_specs.map(&:name)
489
+ spec_paths_to_include << test_spec.name if pod_target == target
490
+ pod_target.resource_paths.values_at(*spec_paths_to_include).flatten.compact
432
491
  end
433
492
  end
434
493
  generator = Generator::CopyResourcesScript.new(resource_paths_by_config, target.platform)
@@ -438,18 +497,19 @@ module Pod
438
497
 
439
498
  # Creates a script that embeds the frameworks to the bundle of the test target.
440
499
  #
441
- # @param [Symbol] test_type
442
- # The test type to create the script for.
500
+ # @param [Specification] test_spec
501
+ # The test spec to create the embed frameworks script for.
443
502
  #
444
503
  # @return [void]
445
504
  #
446
- def create_test_target_embed_frameworks_script(test_type)
447
- path = target.embed_frameworks_script_path_for_test_type(test_type)
448
- pod_targets = target.all_dependent_targets
505
+ def create_test_target_embed_frameworks_script(test_spec)
506
+ path = target.embed_frameworks_script_path_for_test_spec(test_spec)
507
+ pod_targets = target.dependent_targets_for_test_spec(test_spec)
449
508
  framework_paths_by_config = target.user_build_configurations.keys.each_with_object({}) do |config, paths_by_config|
450
509
  paths_by_config[config] = pod_targets.flat_map do |pod_target|
451
- include_test_spec_paths = pod_target == target
452
- pod_target.framework_paths(include_test_spec_paths)
510
+ spec_paths_to_include = pod_target.non_test_specs.map(&:name)
511
+ spec_paths_to_include << test_spec.name if pod_target == target
512
+ pod_target.framework_paths.values_at(*spec_paths_to_include).flatten.compact.uniq
453
513
  end
454
514
  end
455
515
  generator = Generator::EmbedFrameworksScript.new(framework_paths_by_config)
@@ -462,9 +522,9 @@ module Pod
462
522
  #
463
523
  # @return [void]
464
524
  #
465
- def test_target_swift_debug_hack(test_target_bc)
525
+ def test_target_swift_debug_hack(test_spec, test_target_bc)
466
526
  return unless test_target_bc.debug?
467
- return unless target.all_dependent_targets.any?(&:uses_swift?)
527
+ return unless target.dependent_targets_for_test_spec(test_spec).any?(&:uses_swift?)
468
528
  ldflags = test_target_bc.build_settings['OTHER_LDFLAGS'] ||= '$(inherited)'
469
529
  ldflags << ' -lswiftSwiftOnoneSupport'
470
530
  end
@@ -476,9 +536,12 @@ module Pod
476
536
  # header_mappings_dir interferes with xcodebuild's expectations
477
537
  # about the existence of private or public headers.
478
538
  #
539
+ # @param [PBXNativeTarget] native_target
540
+ # the native target to add the script phase into.
541
+ #
479
542
  # @return [void]
480
543
  #
481
- def create_build_phase_to_symlink_header_folders
544
+ def create_build_phase_to_symlink_header_folders(native_target)
482
545
  return unless target.platform.name == :osx && header_mappings_dir
483
546
 
484
547
  build_phase = native_target.new_shell_script_build_phase('Create Symlinks to Header Folders')
@@ -502,21 +565,19 @@ module Pod
502
565
  # @param [Platform] platform
503
566
  # the platform to use for this prefix header.
504
567
  #
505
- # @param [Array<PBXNativetarget>] native_targets
506
- # the native targets on which the prefix header should be configured for.
568
+ # @param [PBXNativeTarget] native_target
569
+ # the native target on which the prefix header should be configured for.
507
570
  #
508
571
  # @return [void]
509
572
  #
510
- def create_prefix_header(path, file_accessors, platform, native_targets)
573
+ def create_prefix_header(path, file_accessors, platform, native_target)
511
574
  generator = Generator::PrefixHeader.new(file_accessors, platform)
512
575
  update_changed_file(generator, path)
513
576
  add_file_to_support_group(path)
514
577
 
515
- native_targets.each do |native_target|
516
- native_target.build_configurations.each do |c|
517
- relative_path = path.relative_path_from(project.path.dirname)
518
- c.build_settings['GCC_PREFIX_HEADER'] = relative_path.to_s
519
- end
578
+ relative_path = path.relative_path_from(project.path.dirname)
579
+ native_target.build_configurations.each do |c|
580
+ c.build_settings['GCC_PREFIX_HEADER'] = relative_path.to_s
520
581
  end
521
582
  end
522
583
 
@@ -587,10 +648,10 @@ module Pod
587
648
  end
588
649
  end
589
650
 
590
- def create_module_map
591
- return super unless custom_module_map
651
+ def create_module_map(native_target)
652
+ return super(native_target) unless custom_module_map
592
653
 
593
- path = target.module_map_path
654
+ path = target.module_map_path_to_write
594
655
  UI.message "- Copying module map file to #{UI.path(path)}" do
595
656
  contents = custom_module_map.read
596
657
  unless target.requires_frameworks?
@@ -600,17 +661,24 @@ module Pod
600
661
  update_changed_file(generator, path)
601
662
  add_file_to_support_group(path)
602
663
 
664
+ linked_path = target.module_map_path
665
+ if path != linked_path
666
+ linked_path.dirname.mkpath
667
+ source = path.relative_path_from(linked_path.dirname)
668
+ FileUtils.ln_sf(source, linked_path)
669
+ end
670
+
671
+ relative_path = target.module_map_path.relative_path_from(sandbox.root).to_s
603
672
  native_target.build_configurations.each do |c|
604
- relative_path = path.relative_path_from(sandbox.root)
605
673
  c.build_settings['MODULEMAP_FILE'] = relative_path.to_s
606
674
  end
607
675
  end
608
676
  end
609
677
 
610
678
  def module_map_additional_headers
611
- return [] unless umbrella_headers_by_dir
679
+ return [] unless umbrella_header_paths
612
680
 
613
- other_paths = umbrella_headers_by_dir[target.module_map_path.dirname] - [target.umbrella_header_path]
681
+ other_paths = umbrella_header_paths - [target.umbrella_header_path]
614
682
  other_paths.map do |module_map_path|
615
683
  # exclude other targets umbrella headers, to avoid
616
684
  # incomplete umbrella warnings
@@ -618,8 +686,8 @@ module Pod
618
686
  end
619
687
  end
620
688
 
621
- def create_umbrella_header
622
- return super unless custom_module_map
689
+ def create_umbrella_header(native_target)
690
+ return super(native_target) unless custom_module_map
623
691
  end
624
692
 
625
693
  def custom_module_map
@@ -675,15 +743,59 @@ module Pod
675
743
  project.pod_support_files_group(pod_name, dir)
676
744
  end
677
745
 
746
+ # @param [String] name
747
+ # The name of the app host.
748
+
749
+ # @param [Symbol] test_type
750
+ # The test type this Info.plist path is for.
751
+ #
752
+ # @return [Pathname] The absolute path of the Info.plist to use for an app host.
753
+ #
754
+ def app_host_info_plist_path_for_test_type(name, test_type)
755
+ project.path.dirname.+("#{name}/#{target.app_host_label(test_type)}-Info.plist")
756
+ end
757
+
758
+ def test_native_target_from_spec_consumer(spec_consumer, test_native_targets)
759
+ test_native_targets.find do |test_native_target|
760
+ test_native_target.name == target.test_target_label(spec_consumer.spec)
761
+ end
762
+ end
763
+
764
+ # Adds a placeholder native target for the library to the Pods project with the
765
+ # appropriate build configurations.
766
+ #
767
+ # @return [PBXAggregateTarget] the native target that was added.
768
+ #
769
+ def add_placeholder_target
770
+ native_target = project.new_aggregate_target(target.label, [], target.platform.name, deployment_target)
771
+ target.user_build_configurations.each do |bc_name, type|
772
+ native_target.add_build_configuration(bc_name, type)
773
+ end
774
+ unless target.archs.empty?
775
+ native_target.build_configurations.each do |configuration|
776
+ configuration.build_settings['ARCHS'] = target.archs
777
+ end
778
+ end
779
+ native_target
780
+ end
781
+
678
782
  # Adds a shell script phase, intended only for static library targets that contain swift,
679
783
  # to copy the ObjC compatibility header (the -Swift.h file that the swift compiler generates)
680
784
  # to the built products directory. Additionally, the script phase copies the module map, appending a `.Swift`
681
785
  # submodule that references the (moved) compatibility header. Since the module map has been moved, the umbrella header
682
786
  # is _also_ copied, so that it is sitting next to the module map. This is necessary for a successful archive build.
683
787
  #
788
+ # @param [PBXNativeTarget] native_target
789
+ # the native target to add the Swift static library script phase into.
790
+ #
684
791
  # @return [Void]
685
792
  #
686
- def add_swift_static_library_compatibility_header_phase
793
+ def add_swift_static_library_compatibility_header_phase(native_target)
794
+ if custom_module_map
795
+ raise Informative, 'Using Swift static libraries with custom module maps is currently not supported. ' \
796
+ "Please build `#{target.label}` as a framework or remove the custom module map."
797
+ end
798
+
687
799
  build_phase = native_target.new_shell_script_build_phase('Copy generated compatibility header')
688
800
 
689
801
  relative_module_map_path = target.module_map_path.relative_path_from(target.sandbox.root)
@@ -710,6 +822,13 @@ module Pod
710
822
  )
711
823
  end
712
824
 
825
+ def validate_targets_contain_sources(native_targets)
826
+ native_targets.each do |native_target|
827
+ next unless native_target.source_build_phase.files.empty?
828
+ raise Informative, "Unable to install the `#{target.label}` pod, because the `#{native_target}` target in Xcode would have no sources to compile."
829
+ end
830
+ end
831
+
713
832
  #-----------------------------------------------------------------------#
714
833
  end
715
834
  end