Class: Pod::PodTarget

Inherits:
Target
  • Object
show all
Defined in:
lib/cocoapods/target/pod_target.rb

Overview

Stores the information relative to the target used to compile a single Pod. A pod can have one or more activated spec, subspecs and test specs.

Constant Summary

Constants inherited from Target

Target::DEFAULT_BUILD_CONFIGURATIONS, Target::DEFAULT_NAME, Target::DEFAULT_VERSION

Instance Attribute Summary collapse

Attributes inherited from Target

#archs, #build_settings, #host_requires_frameworks, #platform, #sandbox, #user_build_configurations

Instance Method Summary collapse

Methods inherited from Target

#bridge_support_path, #dummy_source_path, #framework_name, #info_plist_path, #inspect, #module_map_path_to_write, #name, #product_basename, #product_name, #product_type, #requires_frameworks?, #static_library_name, #support_files_dir, #umbrella_header_path, #umbrella_header_path_to_write, #xcconfig_path

Constructor Details

#initialize(sandbox, host_requires_frameworks, user_build_configurations, archs, platform, specs, target_definitions, file_accessors = [], scope_suffix = nil) ⇒ PodTarget

Initialize a new instance



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/cocoapods/target/pod_target.rb', line 61

def initialize(sandbox, host_requires_frameworks, user_build_configurations, archs, platform, specs,
               target_definitions, file_accessors = [], scope_suffix = nil)
  super(sandbox, host_requires_frameworks, user_build_configurations, archs, platform)
  raise "Can't initialize a PodTarget without specs!" if specs.nil? || specs.empty?
  raise "Can't initialize a PodTarget without TargetDefinition!" if target_definitions.nil? || target_definitions.empty?
  raise "Can't initialize a PodTarget with only abstract TargetDefinitions!" if target_definitions.all?(&:abstract?)
  raise "Can't initialize a PodTarget with an empty string scope suffix!" if scope_suffix == ''
  @specs = specs.dup.freeze
  @target_definitions = target_definitions
  @file_accessors = file_accessors
  @scope_suffix = scope_suffix
  @test_specs, @non_test_specs = @specs.partition(&:test_specification?)
  @build_headers = Sandbox::HeadersStore.new(sandbox, 'Private', :private)
  @dependent_targets = []
  @test_dependent_targets_by_spec_name = {}
  @build_config_cache = {}
end

Instance Attribute Details

#build_headersHeadersStore (readonly)



39
40
41
# File 'lib/cocoapods/target/pod_target.rb', line 39

def build_headers
  @build_headers
end

#dependent_targetsArray<PodTarget>



44
45
46
# File 'lib/cocoapods/target/pod_target.rb', line 44

def dependent_targets
  @dependent_targets
end

#file_accessorsArray<Sandbox::FileAccessor> (readonly)



28
29
30
# File 'lib/cocoapods/target/pod_target.rb', line 28

def file_accessors
  @file_accessors
end

#non_test_specsArray<Specification> (readonly)



18
19
20
# File 'lib/cocoapods/target/pod_target.rb', line 18

def non_test_specs
  @non_test_specs
end

#scope_suffixString (readonly)

Note:

This affects the value returned by #configuration_build_dir and accessors relying on this as #build_product_path.

Returns the suffix used for this target when deduplicated. May be nil.



35
36
37
# File 'lib/cocoapods/target/pod_target.rb', line 35

def scope_suffix
  @scope_suffix
end

#specsArray<Specification> (readonly)



8
9
10
# File 'lib/cocoapods/target/pod_target.rb', line 8

def specs
  @specs
end

#target_definitionsArray<TargetDefinition> (readonly)



23
24
25
# File 'lib/cocoapods/target/pod_target.rb', line 23

def target_definitions
  @target_definitions
end

#test_dependent_targets_by_spec_nameHash{String=>Array<PodTarget>}



48
49
50
# File 'lib/cocoapods/target/pod_target.rb', line 48

def test_dependent_targets_by_spec_name
  @test_dependent_targets_by_spec_name
end

#test_specsArray<Specification> (readonly)



13
14
15
# File 'lib/cocoapods/target/pod_target.rb', line 13

def test_specs
  @test_specs
end

Instance Method Details

#all_dependent_targetsArray<PodTarget>



456
457
458
# File 'lib/cocoapods/target/pod_target.rb', line 456

def all_dependent_targets
  [self, *recursive_dependent_targets, *recursive_test_dependent_targets].uniq
end

#build_product_path(dir = BuildSettings::CONFIGURATION_BUILD_DIR_VARIABLE) ⇒ String



502
503
504
# File 'lib/cocoapods/target/pod_target.rb', line 502

def build_product_path(dir = BuildSettings::CONFIGURATION_BUILD_DIR_VARIABLE)
  "#{configuration_build_dir(dir)}/#{product_name}"
end

#configuration_build_dir(dir = BuildSettings::CONFIGURATION_BUILD_DIR_VARIABLE) ⇒ String



493
494
495
# File 'lib/cocoapods/target/pod_target.rb', line 493

def configuration_build_dir(dir = BuildSettings::CONFIGURATION_BUILD_DIR_VARIABLE)
  "#{dir}/#{label}"
end

#contains_script_phases?Boolean



225
226
227
# File 'lib/cocoapods/target/pod_target.rb', line 225

def contains_script_phases?
  !script_phases.empty?
end

#contains_test_specifications?Boolean



231
232
233
# File 'lib/cocoapods/target/pod_target.rb', line 231

def contains_test_specifications?
  !test_specs.empty?
end

#copy_resources_script_path_for_test_type(test_type) ⇒ Pathname



373
374
375
# File 'lib/cocoapods/target/pod_target.rb', line 373

def copy_resources_script_path_for_test_type(test_type)
  support_files_dir + "#{test_target_label(test_type)}-resources.sh"
end

#defines_module?Boolean

Note:

Static library targets can temporarily opt in to this behavior by setting ‘DEFINES_MODULE = YES` in their specification’s pod_target_xcconfig.

Returns Whether the target defines a “module” (and thus will need a module map and umbrella header).



209
210
211
212
213
214
215
# File 'lib/cocoapods/target/pod_target.rb', line 209

def defines_module?
  return @defines_module if defined?(@defines_module)
  return @defines_module = true if uses_swift? || requires_frameworks?
  return @defines_module = true if target_definitions.all? { |td| td.build_pod_as_module?(pod_name) }

  @defines_module = non_test_specs.any? { |s| s.consumer(platform).pod_target_xcconfig['DEFINES_MODULE'] == 'YES' }
end

#dependenciesArray<String>



413
414
415
416
417
# File 'lib/cocoapods/target/pod_target.rb', line 413

def dependencies
  spec_consumers.flat_map do |consumer|
    consumer.dependencies.map { |dep| Specification.root_name(dep.name) }
  end.uniq
end

#embed_frameworks_script_path_for_test_type(test_type) ⇒ Pathname



382
383
384
# File 'lib/cocoapods/target/pod_target.rb', line 382

def embed_frameworks_script_path_for_test_type(test_type)
  support_files_dir + "#{test_target_label(test_type)}-frameworks.sh"
end

#framework_pathsHash{String=>Array<Hash{Symbol=>String}>}



245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
# File 'lib/cocoapods/target/pod_target.rb', line 245

def framework_paths
  @framework_paths ||= begin
    file_accessors.each_with_object({}) do |file_accessor, hash|
      frameworks = []
      file_accessor.vendored_dynamic_artifacts.map do |framework_path|
        relative_path_to_sandbox = framework_path.relative_path_from(sandbox.root)
        framework = { :name => framework_path.basename.to_s,
                      :input_path => "${PODS_ROOT}/#{relative_path_to_sandbox}",
                      :output_path => "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/#{framework_path.basename}" }
        # Until this can be configured, assume the dSYM file uses the file name as the framework.
        # See https://github.com/CocoaPods/CocoaPods/issues/1698
        dsym_name = "#{framework_path.basename}.dSYM"
        dsym_path = Pathname.new("#{framework_path.dirname}/#{dsym_name}")
        if dsym_path.exist?
          framework[:dsym_name] = dsym_name
          framework[:dsym_input_path] = "${PODS_ROOT}/#{relative_path_to_sandbox}.dSYM"
          framework[:dsym_output_path] = "${DWARF_DSYM_FOLDER_PATH}/#{dsym_name}"
        end
        frameworks << framework
      end
      if !file_accessor.spec.test_specification? && should_build? && requires_frameworks? && !static_framework?
        frameworks << { :name => product_name,
                        :input_path => build_product_path('${BUILT_PRODUCTS_DIR}'),
                        :output_path => "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/#{product_name}" }
      end
      hash[file_accessor.spec.name] = frameworks
    end
  end
end

#header_search_paths(include_test_dependent_targets = false) ⇒ Array<String>



524
525
526
527
528
529
530
531
532
533
534
# File 'lib/cocoapods/target/pod_target.rb', line 524

def header_search_paths(include_test_dependent_targets = false)
  header_search_paths = []
  header_search_paths.concat(build_headers.search_paths(platform, nil, false))
  header_search_paths.concat(sandbox.public_headers.search_paths(platform, pod_name, uses_modular_headers?))
  dependent_targets = recursive_dependent_targets
  dependent_targets += recursive_test_dependent_targets if include_test_dependent_targets
  dependent_targets.uniq.each do |dependent_target|
    header_search_paths.concat(sandbox.public_headers.search_paths(platform, dependent_target.pod_name, defines_module? && dependent_target.uses_modular_headers?(false)))
  end
  header_search_paths.uniq
end

#info_plist_path_for_test_type(test_type) ⇒ Pathname



391
392
393
# File 'lib/cocoapods/target/pod_target.rb', line 391

def info_plist_path_for_test_type(test_type)
  support_files_dir + "#{test_target_label(test_type)}-Info.plist"
end

#inhibit_warnings?Bool

Checks if warnings should be inhibited for this pod.



464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
# File 'lib/cocoapods/target/pod_target.rb', line 464

def inhibit_warnings?
  return @inhibit_warnings if defined? @inhibit_warnings
  whitelists = target_definitions.map do |target_definition|
    target_definition.inhibits_warnings_for_pod?(root_spec.name)
  end.uniq

  if whitelists.empty?
    @inhibit_warnings = false
    false
  elsif whitelists.count == 1
    @inhibit_warnings = whitelists.first
    whitelists.first
  else
    UI.warn "The pod `#{pod_name}` is linked to different targets " \
      "(#{target_definitions.map(&:label)}), which contain different " \
      'settings to inhibit warnings. CocoaPods does not currently ' \
      'support different settings and will fall back to your preference ' \
      'set in the root target definition.'
    podfile.root_target_definitions.first.inhibits_warnings_for_pod?(root_spec.name)
  end
end

#labelString



107
108
109
110
111
112
113
# File 'lib/cocoapods/target/pod_target.rb', line 107

def label
  if scope_suffix.nil? || scope_suffix[0] == '.'
    "#{root_spec.name}#{scope_suffix}"
  else
    "#{root_spec.name}-#{scope_suffix}"
  end
end

#module_map_pathPathname



339
340
341
342
343
344
345
346
347
348
# File 'lib/cocoapods/target/pod_target.rb', line 339

def module_map_path
  basename = "#{label}.modulemap"
  if requires_frameworks?
    super
  elsif file_accessors.any?(&:module_map)
    build_headers.root + product_module_name + basename
  else
    sandbox.public_headers.root + product_module_name + basename
  end
end

#pod_nameString



332
333
334
# File 'lib/cocoapods/target/pod_target.rb', line 332

def pod_name
  root_spec.name
end

#pod_target_srcrootString



508
509
510
# File 'lib/cocoapods/target/pod_target.rb', line 508

def pod_target_srcroot
  "${PODS_ROOT}/#{sandbox.pod_dir(pod_name).relative_path_from(sandbox.root)}"
end

#podfilePodfile



131
132
133
# File 'lib/cocoapods/target/pod_target.rb', line 131

def podfile
  target_definitions.first.podfile
end

#prefix_header_pathPathname



397
398
399
# File 'lib/cocoapods/target/pod_target.rb', line 397

def prefix_header_path
  support_files_dir + "#{label}-prefix.pch"
end

#prefix_header_path_for_test_type(test_type) ⇒ Pathname



406
407
408
# File 'lib/cocoapods/target/pod_target.rb', line 406

def prefix_header_path_for_test_type(test_type)
  support_files_dir + "#{test_target_label(test_type)}-prefix.pch"
end

#product_module_nameString



139
140
141
# File 'lib/cocoapods/target/pod_target.rb', line 139

def product_module_name
  root_spec.module_name
end

#product_type_for_test_type(test_type) ⇒ Symbol

Returns the corresponding native product type to use given the test type. This is primarily used when creating the native targets in order to produce the correct test bundle target based on the type of tests included.



299
300
301
302
303
304
305
306
# File 'lib/cocoapods/target/pod_target.rb', line 299

def product_type_for_test_type(test_type)
  case test_type
  when :unit
    :unit_test_bundle
  else
    raise Informative, "Unknown test type `#{test_type}`."
  end
end

#recursive_dependent_targetsArray<PodTarget>



422
423
424
# File 'lib/cocoapods/target/pod_target.rb', line 422

def recursive_dependent_targets
  @recursive_dependent_targets ||= _add_recursive_dependent_targets(Set.new).delete(self).to_a
end

#recursive_test_dependent_targetsArray<PodTarget>



438
439
440
# File 'lib/cocoapods/target/pod_target.rb', line 438

def recursive_test_dependent_targets
  @recursive_test_dependent_targets ||= _add_recursive_test_dependent_targets(Set.new).to_a
end

#resource_pathsHash{String=>Array<String>}



278
279
280
281
282
283
284
285
286
287
288
# File 'lib/cocoapods/target/pod_target.rb', line 278

def resource_paths
  @resource_paths ||= begin
    file_accessors.each_with_object({}) do |file_accessor, hash|
      resource_paths = file_accessor.resources.map { |res| "${PODS_ROOT}/#{res.relative_path_from(sandbox.project.path.dirname)}" }
      prefix = Pod::Target::BuildSettings::CONFIGURATION_BUILD_DIR_VARIABLE
      prefix = configuration_build_dir unless file_accessor.spec.test_specification?
      resource_bundle_paths = file_accessor.resource_bundles.keys.map { |name| "#{prefix}/#{name.shellescape}.bundle" }
      hash[file_accessor.spec.name] = resource_paths + resource_bundle_paths
    end
  end
end

#resources_bundle_target_label(bundle_name) ⇒ String



355
356
357
# File 'lib/cocoapods/target/pod_target.rb', line 355

def resources_bundle_target_label(bundle_name)
  "#{label}-#{bundle_name}"
end

#root_specSpecification



326
327
328
# File 'lib/cocoapods/target/pod_target.rb', line 326

def root_spec
  specs.first.root
end

#scoped(cache = {}) ⇒ Array<PodTarget>

Scopes the current target based on the existing pod targets within the cache.



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/cocoapods/target/pod_target.rb', line 86

def scoped(cache = {})
  target_definitions.map do |target_definition|
    cache_key = [specs, target_definition]
    if cache[cache_key]
      cache[cache_key]
    else
      target = PodTarget.new(sandbox, host_requires_frameworks, user_build_configurations, archs, platform, specs, [target_definition], file_accessors, target_definition.label)
      target.dependent_targets = dependent_targets.flat_map { |pt| pt.scoped(cache) }.select { |pt| pt.target_definitions == [target_definition] }
      target.test_dependent_targets_by_spec_name = Hash[test_dependent_targets_by_spec_name.map do |spec_name, test_pod_targets|
        scoped_test_pod_targets = test_pod_targets.flat_map do |test_pod_target|
          test_pod_target.scoped(cache).select { |pt| pt.target_definitions == [target_definition] }
        end
        [spec_name, scoped_test_pod_targets]
      end]
      cache[cache_key] = target
    end
  end
end

#script_phasesArray<Hash{Symbol=>String}>



219
220
221
# File 'lib/cocoapods/target/pod_target.rb', line 219

def script_phases
  spec_consumers.flat_map(&:script_phases)
end

#should_build?Bool

A target should not be built if it has no source files.



147
148
149
150
151
152
153
# File 'lib/cocoapods/target/pod_target.rb', line 147

def should_build?
  return @should_build if defined? @should_build
  accessors = file_accessors.reject { |fa| fa.spec.test_specification? }
  source_files = accessors.flat_map(&:source_files)
  source_files -= accessors.flat_map(&:headers)
  @should_build = !source_files.empty?
end

#spec_consumersArray<Specification::Consumer>



158
159
160
# File 'lib/cocoapods/target/pod_target.rb', line 158

def spec_consumers
  specs.map { |spec| spec.consumer(platform) }
end

#spec_swift_versionString



125
126
127
# File 'lib/cocoapods/target/pod_target.rb', line 125

def spec_swift_version
  root_spec.swift_version
end

#static_framework?Boolean



199
200
201
# File 'lib/cocoapods/target/pod_target.rb', line 199

def static_framework?
  requires_frameworks? && root_spec.static_framework
end

#supported_test_typesArray<Symbol>



237
238
239
# File 'lib/cocoapods/target/pod_target.rb', line 237

def supported_test_types
  test_specs.map(&:test_type).uniq
end

#swift_versionString



119
120
121
# File 'lib/cocoapods/target/pod_target.rb', line 119

def swift_version
  spec_swift_version || target_definitions.map(&:swift_version).compact.uniq.first
end

#test_spec_consumersArray<Specification::Consumer>



165
166
167
# File 'lib/cocoapods/target/pod_target.rb', line 165

def test_spec_consumers
  test_specs.map { |test_spec| test_spec.consumer(platform) }
end

#test_target_label(test_type) ⇒ String



364
365
366
# File 'lib/cocoapods/target/pod_target.rb', line 364

def test_target_label(test_type)
  "#{label}-#{test_type.capitalize}-Tests"
end

#test_type_for_product_type(product_type) ⇒ Symbol

Returns the corresponding test type given the product type.



315
316
317
318
319
320
321
322
# File 'lib/cocoapods/target/pod_target.rb', line 315

def test_type_for_product_type(product_type)
  case product_type
  when :unit_test_bundle
    :unit
  else
    raise Informative, "Unknown product type `#{product_type}`."
  end
end

#uses_swift?Boolean



171
172
173
174
175
176
177
178
# File 'lib/cocoapods/target/pod_target.rb', line 171

def uses_swift?
  return @uses_swift if defined? @uses_swift
  @uses_swift = begin
    file_accessors.reject { |a| a.spec.test_specification? }.any? do |file_accessor|
      file_accessor.source_files.any? { |sf| sf.extname == '.swift' }
    end
  end
end

#uses_swift_for_test_type?(test_type) ⇒ Boolean

Checks whether a particular test type uses Swift or not.



187
188
189
190
191
192
193
194
195
# File 'lib/cocoapods/target/pod_target.rb', line 187

def uses_swift_for_test_type?(test_type)
  @uses_swift_for_test_type ||= {}
  return @uses_swift_for_test_type[test_type] if @uses_swift_for_test_type.key?(test_type)
  @uses_swift_for_test_type[test_type] = begin
    file_accessors.select { |a| a.spec.test_specification? && a.spec.test_type == test_type }.any? do |file_accessor|
      file_accessor.source_files.any? { |sf| sf.extname == '.swift' }
    end
  end
end

#versionString



514
515
516
517
# File 'lib/cocoapods/target/pod_target.rb', line 514

def version
  version = root_spec.version
  [version.major, version.minor, version.patch].join('.')
end