cocoapods-dykit 0.5.2 → 0.5.3

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/lib/pod/command.rb +2 -0
  3. data/lib/pod/command/dyinstall.rb +51 -0
  4. data/lib/pod/command/dyupdate.rb +106 -0
  5. data/lib/pod/command/fmwk.rb +4 -0
  6. data/lib/pod/command/lib/dylint.rb +1 -0
  7. data/lib/pod/gem_version.rb +1 -1
  8. data/lib/pod/installer.rb +715 -0
  9. data/lib/pod/installer/analyzer.rb +934 -0
  10. data/lib/pod/installer/analyzer/analysis_result.rb +57 -0
  11. data/lib/pod/installer/analyzer/locking_dependency_analyzer.rb +95 -0
  12. data/lib/pod/installer/analyzer/pod_variant.rb +68 -0
  13. data/lib/pod/installer/analyzer/pod_variant_set.rb +157 -0
  14. data/lib/pod/installer/analyzer/podfile_dependency_cache.rb +54 -0
  15. data/lib/pod/installer/analyzer/sandbox_analyzer.rb +251 -0
  16. data/lib/pod/installer/analyzer/specs_state.rb +84 -0
  17. data/lib/pod/installer/analyzer/target_inspection_result.rb +45 -0
  18. data/lib/pod/installer/analyzer/target_inspector.rb +254 -0
  19. data/lib/pod/installer/installation_options.rb +158 -0
  20. data/lib/pod/installer/pod_source_installer.rb +214 -0
  21. data/lib/pod/installer/pod_source_preparer.rb +77 -0
  22. data/lib/pod/installer/podfile_validator.rb +139 -0
  23. data/lib/pod/installer/post_install_hooks_context.rb +107 -0
  24. data/lib/pod/installer/pre_install_hooks_context.rb +42 -0
  25. data/lib/pod/installer/source_provider_hooks_context.rb +32 -0
  26. data/lib/pod/installer/user_project_integrator.rb +253 -0
  27. data/lib/pod/installer/user_project_integrator/target_integrator.rb +462 -0
  28. data/lib/pod/installer/user_project_integrator/target_integrator/xcconfig_integrator.rb +146 -0
  29. data/lib/pod/installer/xcode.rb +8 -0
  30. data/lib/pod/installer/xcode/pods_project_generator.rb +353 -0
  31. data/lib/pod/installer/xcode/pods_project_generator/aggregate_target_installer.rb +172 -0
  32. data/lib/pod/installer/xcode/pods_project_generator/file_references_installer.rb +367 -0
  33. data/lib/pod/installer/xcode/pods_project_generator/pod_target_installer.rb +718 -0
  34. data/lib/pod/installer/xcode/pods_project_generator/pod_target_integrator.rb +111 -0
  35. data/lib/pod/installer/xcode/pods_project_generator/target_installer.rb +265 -0
  36. data/lib/pod/installer/xcode/target_validator.rb +141 -0
  37. data/lib/pod/resolver.rb +632 -0
  38. metadata +34 -2
@@ -0,0 +1,718 @@
1
+ module Pod
2
+ class DyInstaller
3
+ class Xcode
4
+ class PodsProjectGenerator
5
+ # Creates the target for the Pods libraries in the Pods project and the
6
+ # relative support files.
7
+ #
8
+ class PodTargetInstaller < TargetInstaller
9
+ # Creates the target in the Pods project and the relative support files.
10
+ #
11
+ # @return [void]
12
+ #
13
+ def install!
14
+ unless target.should_build?
15
+ add_resources_bundle_targets
16
+ return
17
+ end
18
+
19
+ UI.message "- Installing target `#{target.name}` #{target.platform}" do
20
+ add_target
21
+ create_support_files_dir
22
+ if target.contains_test_specifications?
23
+ add_test_targets
24
+ add_test_app_host_targets
25
+ 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?
30
+
31
+ if target.defines_module?
32
+ create_module_map do |generator|
33
+ generator.headers.concat module_map_additional_headers
34
+ 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)
44
+ end
45
+ end
46
+ end
47
+
48
+ if target.requires_frameworks?
49
+ unless target.static_framework?
50
+ create_info_plist_file(target.info_plist_path, native_target, target.version, target.platform)
51
+ end
52
+ create_build_phase_to_symlink_header_folders
53
+ elsif target.uses_swift?
54
+ add_swift_static_library_compatibility_header_phase
55
+ end
56
+
57
+ unless skip_pch?(target.non_test_specs)
58
+ 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])
61
+ end
62
+ 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)
67
+ end
68
+ end
69
+ create_dummy_source
70
+ end
71
+ end
72
+
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
+ private
79
+
80
+ # @param [Array<Specification>] specs
81
+ # the specs to check against whether `.pch` generation should be skipped or not.
82
+ #
83
+ # @return [Boolean] Whether the target should build a pch file.
84
+ #
85
+ def skip_pch?(specs)
86
+ specs.any? { |spec| spec.prefix_header_file.is_a?(FalseClass) }
87
+ end
88
+
89
+ # Remove the default headers folder path settings for static library pod
90
+ # targets.
91
+ #
92
+ # @return [Hash{String => String}]
93
+ #
94
+ def custom_build_settings
95
+ settings = super
96
+ unless target.requires_frameworks?
97
+ settings['PRIVATE_HEADERS_FOLDER_PATH'] = ''
98
+ settings['PUBLIC_HEADERS_FOLDER_PATH'] = ''
99
+ end
100
+
101
+ settings['PRODUCT_NAME'] = target.product_basename
102
+ settings['PRODUCT_MODULE_NAME'] = target.product_module_name
103
+
104
+ settings['CODE_SIGN_IDENTITY[sdk=appletvos*]'] = ''
105
+ settings['CODE_SIGN_IDENTITY[sdk=iphoneos*]'] = ''
106
+ settings['CODE_SIGN_IDENTITY[sdk=watchos*]'] = ''
107
+
108
+ settings['SWIFT_ACTIVE_COMPILATION_CONDITIONS'] = '$(inherited) '
109
+
110
+ if target.swift_version
111
+ settings['SWIFT_VERSION'] = target.swift_version
112
+ end
113
+
114
+ settings
115
+ end
116
+
117
+ # Filters the given resource file references discarding empty paths which are
118
+ # added by their parent directory. This will also include references to the parent [PBXVariantGroup]
119
+ # for all resources underneath it.
120
+ #
121
+ # @param [Array<Pathname>] resource_file_references
122
+ # The array of all resource file references to filter.
123
+ #
124
+ # @yield_param [Array<PBXFileReference>} The filtered resource file references to be installed
125
+ # in the copy resources phase.
126
+ #
127
+ # @yield_param [Array<PBXFileReference>} The filtered resource file references to be installed
128
+ # in the compile sources phase.
129
+ #
130
+ # @note Core Data model directories (.xcdatamodeld) used to be added to the
131
+ # `Copy Resources` build phase like all other resources, since they would
132
+ # compile correctly in either the resources or compile phase. In recent
133
+ # versions of xcode, there's an exception for data models that generate
134
+ # headers. These need to be added to the compile sources phase of a real
135
+ # target for the headers to be built in time for code in the target to
136
+ # use them. These kinds of models generally break when added to resource
137
+ # bundles.
138
+ #
139
+ def filter_resource_file_references(resource_file_references)
140
+ file_references = resource_file_references.map do |resource_file_reference|
141
+ ref = project.reference_for_path(resource_file_reference)
142
+
143
+ # Some nested files are not directly present in the Xcode project, such as the contents
144
+ # of an .xcdatamodeld directory. These files are implicitly included by including their
145
+ # parent directory.
146
+ next if ref.nil?
147
+
148
+ # For variant groups, the variant group itself is added, not its members.
149
+ next ref.parent if ref.parent.is_a?(Xcodeproj::Project::Object::PBXVariantGroup)
150
+
151
+ ref
152
+ end.compact.uniq
153
+ compile_phase_matcher = lambda { |ref| !(ref.path =~ /.*\.xcdatamodeld/i).nil? }
154
+ resources_phase_refs = file_references.reject(&compile_phase_matcher)
155
+ compile_phase_refs = file_references.select(&compile_phase_matcher)
156
+ yield resources_phase_refs, compile_phase_refs
157
+ end
158
+
159
+ #-----------------------------------------------------------------------#
160
+
161
+ SOURCE_FILE_EXTENSIONS = Sandbox::FileAccessor::SOURCE_FILE_EXTENSIONS
162
+
163
+ # Adds the build files of the pods to the target and adds a reference to
164
+ # the frameworks of the Pods.
165
+ #
166
+ # @note The Frameworks are used only for presentation purposes as the
167
+ # xcconfig is the authoritative source about their information.
168
+ #
169
+ # @note Core Data model directories (.xcdatamodeld) defined in the `resources`
170
+ # property are currently added to the `Copy Resources` build phase like
171
+ # all other resources. The Xcode UI adds these to the `Compile Sources`
172
+ # build phase, but they will compile correctly either way.
173
+ #
174
+ # @return [void]
175
+ #
176
+ def add_files_to_build_phases
177
+ target.file_accessors.each do |file_accessor|
178
+ consumer = file_accessor.spec_consumer
179
+
180
+ native_target = target.native_target_for_spec(consumer.spec)
181
+ headers = file_accessor.headers
182
+ public_headers = file_accessor.public_headers.map(&:realpath)
183
+ private_headers = file_accessor.private_headers.map(&:realpath)
184
+ other_source_files = file_accessor.source_files.reject { |sf| SOURCE_FILE_EXTENSIONS.include?(sf.extname) }
185
+
186
+ {
187
+ true => file_accessor.arc_source_files,
188
+ false => file_accessor.non_arc_source_files,
189
+ }.each do |arc, files|
190
+ files = files - headers - other_source_files
191
+ flags = compiler_flags_for_consumer(consumer, arc)
192
+ regular_file_refs = project_file_references_array(files, 'source')
193
+ native_target.add_file_references(regular_file_refs, flags)
194
+ end
195
+
196
+ header_file_refs = project_file_references_array(headers, 'header')
197
+ native_target.add_file_references(header_file_refs) do |build_file|
198
+ add_header(build_file, public_headers, private_headers, native_target)
199
+ end
200
+
201
+ other_file_refs = project_file_references_array(other_source_files, 'other source')
202
+ native_target.add_file_references(other_file_refs, nil)
203
+
204
+ next unless target.requires_frameworks?
205
+
206
+ filter_resource_file_references(file_accessor.resources.flatten) do |resource_phase_refs, compile_phase_refs|
207
+ native_target.add_file_references(compile_phase_refs, nil)
208
+ native_target.add_resources(resource_phase_refs)
209
+ end
210
+ end
211
+ end
212
+
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
+ # Adds the test targets for the library to the Pods project with the
251
+ # appropriate build configurations.
252
+ #
253
+ # @return [void]
254
+ #
255
+ def add_test_targets
256
+ target.supported_test_types.each do |test_type|
257
+ product_type = target.product_type_for_test_type(test_type)
258
+ name = target.test_target_label(test_type)
259
+ 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
263
+
264
+ target.user_build_configurations.each do |bc_name, type|
265
+ native_test_target.add_build_configuration(bc_name, type)
266
+ end
267
+
268
+ native_test_target.build_configurations.each do |configuration|
269
+ configuration.build_settings.merge!(custom_build_settings)
270
+ # target_installer will automatically add an empty `OTHER_LDFLAGS`. For test
271
+ # targets those are set via a test xcconfig file instead.
272
+ configuration.build_settings.delete('OTHER_LDFLAGS')
273
+ # target_installer will automatically set the product name to the module name if the target
274
+ # requires frameworks. For tests we always use the test target name as the product name
275
+ # irrelevant to whether we use frameworks or not.
276
+ configuration.build_settings['PRODUCT_NAME'] = name
277
+ # Use xcode default product module name, which is $(PRODUCT_NAME:c99extidentifier)
278
+ # this gives us always valid name that is distinct from the parent spec module name
279
+ # which allow tests to use either import or @testable import to access the parent framework
280
+ configuration.build_settings.delete('PRODUCT_MODULE_NAME')
281
+ # We must codesign iOS XCTest bundles that contain binary frameworks to allow them to be launchable in the simulator
282
+ unless target.platform == :osx
283
+ configuration.build_settings['CODE_SIGNING_REQUIRED'] = 'YES'
284
+ configuration.build_settings['CODE_SIGNING_ALLOWED'] = 'YES'
285
+ end
286
+ # For macOS we do not code sign the XCTest bundle because we do not code sign the frameworks either.
287
+ configuration.build_settings['CODE_SIGN_IDENTITY'] = '' if target.platform == :osx
288
+ end
289
+
290
+ # 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)
293
+
294
+ # Generate vanila Info.plist for test target similar to the one xcode gererates for new test target.
295
+ # This creates valid test bundle accessible at the runtime, allowing tests to load bundle resources
296
+ # 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)
298
+
299
+ target.test_native_targets << native_test_target
300
+ end
301
+ end
302
+
303
+ # Adds the resources of the Pods to the Pods project.
304
+ #
305
+ # @note The source files are grouped by Pod and in turn by subspec
306
+ # (recursively) in the resources group.
307
+ #
308
+ # @return [void]
309
+ #
310
+ def add_resources_bundle_targets
311
+ target.file_accessors.each do |file_accessor|
312
+ file_accessor.resource_bundles.each do |bundle_name, paths|
313
+ 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|
316
+ bundle_file_name = "#{bundle_name}.bundle"
317
+ bundle_product.name = bundle_file_name
318
+ end
319
+
320
+ filter_resource_file_references(paths) do |resource_phase_refs, compile_phase_refs|
321
+ # Resource bundles are only meant to have resources, so install everything
322
+ # into the resources phase. See note in filter_resource_file_references.
323
+ bundle_target.add_resources(resource_phase_refs + compile_phase_refs)
324
+ end
325
+
326
+ native_target = target.native_target_for_spec(file_accessor.spec_consumer.spec)
327
+ 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
345
+ end
346
+
347
+ # Create Info.plist file for bundle
348
+ path = target.info_plist_path
349
+ path.dirname.mkdir unless path.dirname.exist?
350
+ 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)
352
+
353
+ bundle_target.build_configurations.each do |c|
354
+ c.build_settings['PRODUCT_NAME'] = bundle_name
355
+ # Do not set the CONFIGURATION_BUILD_DIR for resource bundles that are only meant for test targets.
356
+ # This is because the test target itself also does not set this configuration build dir and it expects
357
+ # 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)')
360
+ end
361
+
362
+ # Set the correct device family for this bundle, based on the platform
363
+ device_family_by_platform = {
364
+ :ios => '1,2',
365
+ :tvos => '3',
366
+ :watchos => '1,2' # The device family for watchOS is 4, but Xcode creates watchkit-compatible bundles as 1,2
367
+ }
368
+
369
+ if (family = device_family_by_platform[target.platform.name])
370
+ c.build_settings['TARGETED_DEVICE_FAMILY'] = family
371
+ end
372
+ end
373
+ end
374
+ end
375
+ end
376
+
377
+ # Generates the contents of the xcconfig file and saves it to disk.
378
+ #
379
+ # @return [void]
380
+ #
381
+ def create_xcconfig_file
382
+ path = target.xcconfig_path
383
+ xcconfig_gen = Generator::XCConfig::PodXCConfig.new(target)
384
+ update_changed_file(xcconfig_gen, path)
385
+ xcconfig_file_ref = add_file_to_support_group(path)
386
+
387
+ native_target.build_configurations.each do |c|
388
+ c.base_configuration_reference = xcconfig_file_ref
389
+ end
390
+
391
+ # 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)
393
+ end
394
+
395
+ # Generates the contents of the xcconfig file used for each test target type and saves it to disk.
396
+ #
397
+ # @return [void]
398
+ #
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
411
+ end
412
+
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)
415
+ end
416
+ end
417
+
418
+ # Creates a script that copies the resources to the bundle of the test target.
419
+ #
420
+ # @param [Symbol] test_type
421
+ # The test type to create the script for.
422
+ #
423
+ # @return [void]
424
+ #
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
428
+ resource_paths_by_config = target.user_build_configurations.keys.each_with_object({}) do |config, resources_by_config|
429
+ 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)
432
+ end
433
+ end
434
+ generator = Generator::CopyResourcesScript.new(resource_paths_by_config, target.platform)
435
+ update_changed_file(generator, path)
436
+ add_file_to_support_group(path)
437
+ end
438
+
439
+ # Creates a script that embeds the frameworks to the bundle of the test target.
440
+ #
441
+ # @param [Symbol] test_type
442
+ # The test type to create the script for.
443
+ #
444
+ # @return [void]
445
+ #
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
449
+ framework_paths_by_config = target.user_build_configurations.keys.each_with_object({}) do |config, paths_by_config|
450
+ 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)
453
+ end
454
+ end
455
+ generator = Generator::EmbedFrameworksScript.new(framework_paths_by_config)
456
+ update_changed_file(generator, path)
457
+ add_file_to_support_group(path)
458
+ end
459
+
460
+ # Manually add `libswiftSwiftOnoneSupport.dylib` as it seems there is an issue with tests that do not include it for Debug configurations.
461
+ # Possibly related to Swift module optimization.
462
+ #
463
+ # @return [void]
464
+ #
465
+ def test_target_swift_debug_hack(test_target_bc)
466
+ return unless test_target_bc.debug?
467
+ return unless target.all_dependent_targets.any?(&:uses_swift?)
468
+ ldflags = test_target_bc.build_settings['OTHER_LDFLAGS'] ||= '$(inherited)'
469
+ ldflags << ' -lswiftSwiftOnoneSupport'
470
+ end
471
+
472
+ # Creates a build phase which links the versioned header folders
473
+ # of the OS X into the framework bundle's root root directory.
474
+ # This is only necessary because the way how headers are copied
475
+ # via custom copy file build phases in combination with
476
+ # header_mappings_dir interferes with xcodebuild's expectations
477
+ # about the existence of private or public headers.
478
+ #
479
+ # @return [void]
480
+ #
481
+ def create_build_phase_to_symlink_header_folders
482
+ return unless target.platform.name == :osx && header_mappings_dir
483
+
484
+ build_phase = native_target.new_shell_script_build_phase('Create Symlinks to Header Folders')
485
+ build_phase.shell_script = <<-eos.strip_heredoc
486
+ base="$CONFIGURATION_BUILD_DIR/$WRAPPER_NAME"
487
+ ln -fs "$base/${PUBLIC_HEADERS_FOLDER_PATH\#$WRAPPER_NAME/}" "$base/${PUBLIC_HEADERS_FOLDER_PATH\#\$CONTENTS_FOLDER_PATH/}"
488
+ ln -fs "$base/${PRIVATE_HEADERS_FOLDER_PATH\#\$WRAPPER_NAME/}" "$base/${PRIVATE_HEADERS_FOLDER_PATH\#\$CONTENTS_FOLDER_PATH/}"
489
+ eos
490
+ end
491
+
492
+ # Creates a prefix header file which imports `UIKit` or `Cocoa` according
493
+ # to the platform of the target. This file also include any prefix header
494
+ # content reported by the specification of the pods.
495
+ #
496
+ # @param [Pathname] path
497
+ # the path to generate the prefix header for.
498
+ #
499
+ # @param [Array<Sandbox::FileAccessor>] file_accessors
500
+ # the file accessors to use for this prefix header that point to a path of a prefix header.
501
+ #
502
+ # @param [Platform] platform
503
+ # the platform to use for this prefix header.
504
+ #
505
+ # @param [Array<PBXNativetarget>] native_targets
506
+ # the native targets on which the prefix header should be configured for.
507
+ #
508
+ # @return [void]
509
+ #
510
+ def create_prefix_header(path, file_accessors, platform, native_targets)
511
+ generator = Generator::PrefixHeader.new(file_accessors, platform)
512
+ update_changed_file(generator, path)
513
+ add_file_to_support_group(path)
514
+
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
520
+ end
521
+ end
522
+
523
+ ENABLE_OBJECT_USE_OBJC_FROM = {
524
+ :ios => Version.new('6'),
525
+ :osx => Version.new('10.8'),
526
+ :watchos => Version.new('2.0'),
527
+ :tvos => Version.new('9.0'),
528
+ }.freeze
529
+
530
+ # Returns the compiler flags for the source files of the given specification.
531
+ #
532
+ # The following behavior is regarding the `OS_OBJECT_USE_OBJC` flag. When
533
+ # set to `0`, it will allow code to use `dispatch_release()` on >= iOS 6.0
534
+ # and OS X 10.8.
535
+ #
536
+ # * New libraries that do *not* require ARC don’t need to care about this
537
+ # issue at all.
538
+ #
539
+ # * New libraries that *do* require ARC _and_ have a deployment target of
540
+ # >= iOS 6.0 or OS X 10.8:
541
+ #
542
+ # These no longer use `dispatch_release()` and should *not* have the
543
+ # `OS_OBJECT_USE_OBJC` flag set to `0`.
544
+ #
545
+ # **Note:** this means that these libraries *have* to specify the
546
+ # deployment target in order to function well.
547
+ #
548
+ # * New libraries that *do* require ARC, but have a deployment target of
549
+ # < iOS 6.0 or OS X 10.8:
550
+ #
551
+ # These contain `dispatch_release()` calls and as such need the
552
+ # `OS_OBJECT_USE_OBJC` flag set to `1`.
553
+ #
554
+ # **Note:** libraries that do *not* specify a platform version are
555
+ # assumed to have a deployment target of < iOS 6.0 or OS X 10.8.
556
+ #
557
+ # For more information, see: http://opensource.apple.com/source/libdispatch/libdispatch-228.18/os/object.h
558
+ #
559
+ # @param [Specification::Consumer] consumer
560
+ # The consumer for the specification for which the compiler flags
561
+ # are needed.
562
+ #
563
+ # @return [String] The compiler flags.
564
+ #
565
+ def compiler_flags_for_consumer(consumer, arc)
566
+ flags = consumer.compiler_flags.dup
567
+ if !arc
568
+ flags << '-fno-objc-arc'
569
+ else
570
+ platform_name = consumer.platform_name
571
+ spec_deployment_target = consumer.spec.deployment_target(platform_name)
572
+ if spec_deployment_target.nil? || Version.new(spec_deployment_target) < ENABLE_OBJECT_USE_OBJC_FROM[platform_name]
573
+ flags << '-DOS_OBJECT_USE_OBJC=0'
574
+ end
575
+ end
576
+ if target.inhibit_warnings?
577
+ flags << '-w -Xanalyzer -analyzer-disable-all-checks'
578
+ end
579
+ flags * ' '
580
+ end
581
+
582
+ def apply_xcconfig_file_ref_to_resource_bundle_targets(resource_bundle_targets, xcconfig_file_ref)
583
+ resource_bundle_targets.each do |rsrc_target|
584
+ rsrc_target.build_configurations.each do |rsrc_bc|
585
+ rsrc_bc.base_configuration_reference = xcconfig_file_ref
586
+ end
587
+ end
588
+ end
589
+
590
+ def create_module_map
591
+ return super unless custom_module_map
592
+
593
+ path = target.module_map_path
594
+ UI.message "- Copying module map file to #{UI.path(path)}" do
595
+ contents = custom_module_map.read
596
+ unless target.requires_frameworks?
597
+ contents.gsub!(/^(\s*)framework\s+(module[^{}]+){/, '\1\2{')
598
+ end
599
+ generator = Generator::Constant.new(contents)
600
+ update_changed_file(generator, path)
601
+ add_file_to_support_group(path)
602
+
603
+ native_target.build_configurations.each do |c|
604
+ relative_path = path.relative_path_from(sandbox.root)
605
+ c.build_settings['MODULEMAP_FILE'] = relative_path.to_s
606
+ end
607
+ end
608
+ end
609
+
610
+ def module_map_additional_headers
611
+ return [] unless umbrella_headers_by_dir
612
+
613
+ other_paths = umbrella_headers_by_dir[target.module_map_path.dirname] - [target.umbrella_header_path]
614
+ other_paths.map do |module_map_path|
615
+ # exclude other targets umbrella headers, to avoid
616
+ # incomplete umbrella warnings
617
+ Generator::ModuleMap::Header.new(module_map_path.basename, nil, nil, nil, true)
618
+ end
619
+ end
620
+
621
+ def create_umbrella_header
622
+ return super unless custom_module_map
623
+ end
624
+
625
+ def custom_module_map
626
+ @custom_module_map ||= target.file_accessors.first.module_map
627
+ end
628
+
629
+ def project_file_references_array(files, file_type)
630
+ files.map do |sf|
631
+ project.reference_for_path(sf).tap do |ref|
632
+ raise Informative, "Unable to find #{file_type} ref for #{sf} for target #{target.name}." unless ref
633
+ end
634
+ end
635
+ end
636
+
637
+ def header_mappings_dir
638
+ return @header_mappings_dir if defined?(@header_mappings_dir)
639
+ file_accessor = target.file_accessors.first
640
+ @header_mappings_dir = if dir = file_accessor.spec_consumer.header_mappings_dir
641
+ file_accessor.path_list.root + dir
642
+ end
643
+ end
644
+
645
+ def add_header(build_file, public_headers, private_headers, native_target)
646
+ file_ref = build_file.file_ref
647
+ acl = if !target.requires_frameworks? # Headers are already rooted at ${PODS_ROOT}/Headers/P*/[pod]/...
648
+ 'Project'
649
+ elsif public_headers.include?(file_ref.real_path)
650
+ 'Public'
651
+ elsif private_headers.include?(file_ref.real_path)
652
+ 'Private'
653
+ else
654
+ 'Project'
655
+ end
656
+
657
+ if target.requires_frameworks? && header_mappings_dir && acl != 'Project'
658
+ relative_path = file_ref.real_path.relative_path_from(header_mappings_dir)
659
+ sub_dir = relative_path.dirname
660
+ copy_phase_name = "Copy #{sub_dir} #{acl} Headers"
661
+ copy_phase = native_target.copy_files_build_phases.find { |bp| bp.name == copy_phase_name } ||
662
+ native_target.new_copy_files_build_phase(copy_phase_name)
663
+ copy_phase.symbol_dst_subfolder_spec = :products_directory
664
+ copy_phase.dst_path = "$(#{acl.upcase}_HEADERS_FOLDER_PATH)/#{sub_dir}"
665
+ copy_phase.add_file_reference(file_ref, true)
666
+ else
667
+ build_file.settings ||= {}
668
+ build_file.settings['ATTRIBUTES'] = [acl]
669
+ end
670
+ end
671
+
672
+ def support_files_group
673
+ pod_name = target.pod_name
674
+ dir = target.support_files_dir
675
+ project.pod_support_files_group(pod_name, dir)
676
+ end
677
+
678
+ # Adds a shell script phase, intended only for static library targets that contain swift,
679
+ # to copy the ObjC compatibility header (the -Swift.h file that the swift compiler generates)
680
+ # to the built products directory. Additionally, the script phase copies the module map, appending a `.Swift`
681
+ # submodule that references the (moved) compatibility header. Since the module map has been moved, the umbrella header
682
+ # is _also_ copied, so that it is sitting next to the module map. This is necessary for a successful archive build.
683
+ #
684
+ # @return [Void]
685
+ #
686
+ def add_swift_static_library_compatibility_header_phase
687
+ build_phase = native_target.new_shell_script_build_phase('Copy generated compatibility header')
688
+
689
+ relative_module_map_path = target.module_map_path.relative_path_from(target.sandbox.root)
690
+ relative_umbrella_header_path = target.umbrella_header_path.relative_path_from(target.sandbox.root)
691
+
692
+ build_phase.shell_script = <<-SH.strip_heredoc
693
+ COMPATIBILITY_HEADER_PATH="${BUILT_PRODUCTS_DIR}/Swift Compatibility Header/${PRODUCT_MODULE_NAME}-Swift.h"
694
+ MODULE_MAP_PATH="${BUILT_PRODUCTS_DIR}/${PRODUCT_MODULE_NAME}.modulemap"
695
+
696
+ ditto "${DERIVED_SOURCES_DIR}/${PRODUCT_MODULE_NAME}-Swift.h" "${COMPATIBILITY_HEADER_PATH}"
697
+ ditto "${PODS_ROOT}/#{relative_module_map_path}" "${MODULE_MAP_PATH}"
698
+ ditto "${PODS_ROOT}/#{relative_umbrella_header_path}" "${BUILT_PRODUCTS_DIR}"
699
+ printf "\\n\\nmodule ${PRODUCT_MODULE_NAME}.Swift {\\n header \\"${COMPATIBILITY_HEADER_PATH}\\"\\n requires objc\\n}\\n" >> "${MODULE_MAP_PATH}"
700
+ SH
701
+ build_phase.input_paths = %W(
702
+ ${DERIVED_SOURCES_DIR}/${PRODUCT_MODULE_NAME}-Swift.h
703
+ ${PODS_ROOT}/#{relative_module_map_path}
704
+ ${PODS_ROOT}/#{relative_umbrella_header_path}
705
+ )
706
+ build_phase.output_paths = %W(
707
+ ${BUILT_PRODUCTS_DIR}/${PRODUCT_MODULE_NAME}.modulemap
708
+ ${BUILT_PRODUCTS_DIR}/#{relative_umbrella_header_path.basename}
709
+ ${BUILT_PRODUCTS_DIR}/Swift\ Compatibility\ Header/${PRODUCT_MODULE_NAME}-Swift.h
710
+ )
711
+ end
712
+
713
+ #-----------------------------------------------------------------------#
714
+ end
715
+ end
716
+ end
717
+ end
718
+ end