Unverified Commit 071e84d9 authored by Samuel Giddins's avatar Samuel Giddins Committed by GitHub

Merge pull request #7631 from CocoaPods/segiddins/build-settings-refactor

Refactor build settings generation to be memoizable
parents 42688f78 08ea793e
...@@ -18,6 +18,9 @@ To install release candidates run `[sudo] gem install cocoapods --pre` ...@@ -18,6 +18,9 @@ To install release candidates run `[sudo] gem install cocoapods --pre`
* Improve performance of Pods project generator by skipping native targets for which dependent targets have already been added. * Improve performance of Pods project generator by skipping native targets for which dependent targets have already been added.
[Jacek Suliga](https://github.com/jmkk) [Jacek Suliga](https://github.com/jmkk)
* Refactor build settings generation to perform much better on large projects.
[Samuel Giddins](https://github.com/segiddins)
##### Bug Fixes ##### Bug Fixes
* Remove [system] declaration attribute from generated module maps * Remove [system] declaration attribute from generated module maps
...@@ -56,6 +59,12 @@ To install release candidates run `[sudo] gem install cocoapods --pre` ...@@ -56,6 +59,12 @@ To install release candidates run `[sudo] gem install cocoapods --pre`
[Maxime Le Moine](https://github.com/MaximeLM) [Maxime Le Moine](https://github.com/MaximeLM)
[#7590](https://github.com/CocoaPods/CocoaPods/issues/7590) [#7590](https://github.com/CocoaPods/CocoaPods/issues/7590)
* When integrating a vendored framework while building pods as static
libraries, public headers will be found via `FRAMEWORK_SEARCH_PATHS`
instead of via the sandbox headers store.
[Samuel Giddins](https://github.com/segiddins)
## 1.5.0 (2018-04-04) ## 1.5.0 (2018-04-04)
##### Enhancements ##### Enhancements
......
...@@ -66,7 +66,6 @@ module Pod ...@@ -66,7 +66,6 @@ module Pod
autoload :ModuleMap, 'cocoapods/generator/module_map' autoload :ModuleMap, 'cocoapods/generator/module_map'
autoload :PrefixHeader, 'cocoapods/generator/prefix_header' autoload :PrefixHeader, 'cocoapods/generator/prefix_header'
autoload :UmbrellaHeader, 'cocoapods/generator/umbrella_header' autoload :UmbrellaHeader, 'cocoapods/generator/umbrella_header'
autoload :XCConfig, 'cocoapods/generator/xcconfig'
autoload :AppTargetHelper, 'cocoapods/generator/app_target_helper' autoload :AppTargetHelper, 'cocoapods/generator/app_target_helper'
end end
......
module Pod
module Generator
# Generates Xcode configuration files. A configuration file is generated
# for each Pod and for each Pod target definition. The aggregates the
# configurations of the Pods and define target specific settings.
#
module XCConfig
autoload :AggregateXCConfig, 'cocoapods/generator/xcconfig/aggregate_xcconfig'
autoload :PodXCConfig, 'cocoapods/generator/xcconfig/pod_xcconfig'
autoload :XCConfigHelper, 'cocoapods/generator/xcconfig/xcconfig_helper'
end
end
end
module Pod
module Generator
module XCConfig
# Generates the xcconfigs for the aggregate targets.
#
class AggregateXCConfig
# @return [AggregateTarget] the target represented by this xcconfig.
#
attr_reader :target
# @return [String] the name of the build configuration to generate this
# xcconfig for.
#
attr_reader :configuration_name
# Initialize a new instance
#
# @param [Target] target @see #target
# @param [String] configuration_name @see #configuration_name
#
def initialize(target, configuration_name)
@target = target
@configuration_name = configuration_name
end
# Generates and saves the xcconfig to the given path.
#
# @param [Pathname] path
# the path where the xcconfig should be stored.
#
# @return [Xcodeproj::Config]
#
def save_as(path)
result = generate
result.save_as(path)
result
end
# Generates the xcconfig.
#
# @note The xcconfig file for a Pods integration target includes the
# namespaced xcconfig files for each spec target dependency.
# Each namespaced configuration value is merged into the Pod
# xcconfig file.
#
# @todo This doesn't include the specs xcconfigs anymore and now the
# logic is duplicated.
#
# @return [Xcodeproj::Config]
#
def generate
includes_static_libs = !target.requires_frameworks?
includes_static_libs ||= pod_targets.flat_map(&:file_accessors).any? { |fa| !fa.vendored_static_artifacts.empty? }
config = {
'FRAMEWORK_SEARCH_PATHS' => '$(inherited) ',
'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) COCOAPODS=1',
'HEADER_SEARCH_PATHS' => '$(inherited) ',
'LIBRARY_SEARCH_PATHS' => '$(inherited) ',
'OTHER_CFLAGS' => '$(inherited) ',
'OTHER_LDFLAGS' => '$(inherited) ' + XCConfigHelper.default_ld_flags(target, includes_static_libs),
'OTHER_SWIFT_FLAGS' => '$(inherited) ',
'PODS_PODFILE_DIR_PATH' => target.podfile_dir_relative_path,
'PODS_ROOT' => target.relative_pods_root,
'SWIFT_INCLUDE_PATHS' => '$(inherited) ',
}.merge(embedded_content_settings)
xcconfig = Xcodeproj::Config.new(config)
xcconfig.merge!(merged_user_target_xcconfigs)
generate_settings_to_import_pod_targets(xcconfig)
XCConfigHelper.add_target_specific_settings(target, xcconfig)
targets = pod_targets + target.search_paths_aggregate_targets.flat_map(&:pod_targets)
XCConfigHelper.generate_vendored_build_settings(target, targets, xcconfig)
XCConfigHelper.generate_other_ld_flags(target, pod_targets, xcconfig)
# TODO: Need to decide how we are going to ensure settings like these
# are always excluded from the user's project.
#
# See https://github.com/CocoaPods/CocoaPods/issues/1216
xcconfig.attributes.delete('USE_HEADERMAP')
# If any of the aggregate target dependencies bring in any vendored dynamic artifacts we should ensure to
# update the runpath search paths.
vendored_dynamic_artifacts = pod_targets.flat_map(&:file_accessors).flat_map(&:vendored_dynamic_artifacts)
symbol_type = target.user_targets.map(&:symbol_type).uniq.first
test_bundle = symbol_type == :octest_bundle || symbol_type == :unit_test_bundle || symbol_type == :ui_test_bundle
XCConfigHelper.generate_ld_runpath_search_paths(target, target.requires_host_target?, test_bundle, xcconfig) if target.requires_frameworks? || vendored_dynamic_artifacts.count > 0
xcconfig
end
#---------------------------------------------------------------------#
protected
# @return [Hash<String, String>] the build settings necessary to import
# the pod targets.
#
def settings_to_import_pod_targets
if target.requires_frameworks?
build_pod_targets = pod_targets.select(&:should_build?)
framework_header_search_paths = build_pod_targets.map do |target|
"#{target.build_product_path}/Headers"
end
build_settings = {
# TODO: remove quote imports in CocoaPods 2.0
# Make framework headers discoverable by `import "…"`
'OTHER_CFLAGS' => XCConfigHelper.quote(framework_header_search_paths, '-iquote'),
}
if pod_targets.any? { |t| !t.should_build? }
# Make library headers discoverable by `#import "…"`
library_header_search_paths = target.sandbox.public_headers.search_paths(target.platform)
# TODO: remove quote imports in CocoaPods 2.0
build_settings['HEADER_SEARCH_PATHS'] = XCConfigHelper.quote(library_header_search_paths)
build_settings['OTHER_CFLAGS'] += ' ' + XCConfigHelper.quote(library_header_search_paths, '-isystem')
end
build_settings
else
# Make headers discoverable from $PODS_ROOT/Headers directory
header_search_paths = target.sandbox.public_headers.search_paths(target.platform)
{
# TODO: remove quote imports in CocoaPods 2.0
# by `#import "…"`
'HEADER_SEARCH_PATHS' => XCConfigHelper.quote(header_search_paths),
# by `#import <…>`
'OTHER_CFLAGS' => XCConfigHelper.quote(header_search_paths, '-isystem'),
}
end
end
#---------------------------------------------------------------------#
private
# @return String the SWIFT_VERSION of the target being integrated
#
def target_swift_version
target.target_definition.swift_version unless target.target_definition.swift_version.blank?
end
EMBED_STANDARD_LIBRARIES_MINIMUM_VERSION = Gem::Version.new('2.3')
# @return [Hash<String, String>] the build settings necessary for Swift
# targets to be correctly embedded in their host.
#
def embedded_content_settings
# For embedded targets, which live in a host target, CocoaPods
# copies all of the embedded target's pod_targets its host
# target. Therefore, this check will properly require the Swift
# libs in the host target, if the embedded target has any pod targets
# that use Swift. Setting this for the embedded target would
# cause an App Store rejection because frameworks cannot be embedded
# in embedded targets.
swift_version = Gem::Version.new(target_swift_version)
should_embed = !target.requires_host_target? && pod_targets.any?(&:uses_swift?)
config = {}
if should_embed
if swift_version >= EMBED_STANDARD_LIBRARIES_MINIMUM_VERSION
config['ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES'] = 'YES'
else
config['EMBEDDED_CONTENT_CONTAINS_SWIFT'] = 'YES'
end
end
config
end
# Add build settings, which ensure that the pod targets can be imported from the integrating target.
# For >= 1.5.0 we use modular (stricter) header search paths this means that the integrated target will only be
# able to import public headers using `<>` or `@import` notation, but never import any private headers.
#
# For < 1.5.0 legacy header search paths the same rules apply: It's the wild west.
#
def generate_settings_to_import_pod_targets(xcconfig)
xcconfig.merge! XCConfigHelper.search_paths_for_dependent_targets(target, pod_targets)
xcconfig.merge!(settings_to_import_pod_targets)
target.search_paths_aggregate_targets.each do |search_paths_target|
generator = AggregateXCConfig.new(search_paths_target, configuration_name)
xcconfig.merge! XCConfigHelper.search_paths_for_dependent_targets(nil, search_paths_target.pod_targets)
xcconfig.merge!(generator.settings_to_import_pod_targets)
# Propagate any HEADER_SEARCH_PATHS settings from the search paths.
XCConfigHelper.propagate_header_search_paths_from_search_paths(search_paths_target, xcconfig)
end
end
#---------------------------------------------------------------------#
# !@group Private Helpers
# Returns the {PodTarget}s which are active for the current
# configuration name.
#
# @return [Array<PodTarget>]
#
def pod_targets
target.pod_targets_for_build_configuration(configuration_name)
end
# Returns the +user_target_xcconfig+ for all pod targets and their spec
# consumers grouped by keys
#
# @return [Hash{String,Hash{Target,String}]
#
def user_target_xcconfig_values_by_consumer_by_key
pod_targets.each_with_object({}) do |target, hash|
target.spec_consumers.each do |spec_consumer|
spec_consumer.user_target_xcconfig.each do |k, v|
(hash[k] ||= {})[spec_consumer] = v
end
end
end
end
# Merges the +user_target_xcconfig+ for all pod targets into the
# #xcconfig and warns on conflicting definitions.
#
# @return [Hash{String, String}]
#
def merged_user_target_xcconfigs
settings = user_target_xcconfig_values_by_consumer_by_key
settings.each_with_object({}) do |(key, values_by_consumer), xcconfig|
uniq_values = values_by_consumer.values.uniq
values_are_bools = uniq_values.all? { |v| v =~ /^(yes|no)$/i }
if values_are_bools
# Boolean build settings
if uniq_values.count > 1
UI.warn 'Can\'t merge user_target_xcconfig for pod targets: ' \
"#{values_by_consumer.keys.map(&:name)}. Boolean build "\
"setting #{key} has different values."
else
xcconfig[key] = uniq_values.first
end
elsif key =~ /S$/
# Plural build settings
xcconfig[key] = uniq_values.join(' ')
else
# Singular build settings
if uniq_values.count > 1
UI.warn 'Can\'t merge user_target_xcconfig for pod targets: ' \
"#{values_by_consumer.keys.map(&:name)}. Singular build "\
"setting #{key} has different values."
else
xcconfig[key] = uniq_values.first
end
end
end
end
#---------------------------------------------------------------------#
end
end
end
end
module Pod
module Generator
module XCConfig
# Generates the private xcconfigs for the pod targets.
#
# The xcconfig file for a Pod target merges the pod target
# configuration values with the default configuration values
# required by CocoaPods.
#
class PodXCConfig
# @return [Target] the target represented by this xcconfig.
#
attr_reader :target
# @return [Boolean] whether this xcconfig is for a test target.
#
attr_reader :test_xcconfig
alias test_xcconfig? test_xcconfig
# Initialize a new instance
#
# @param [Target] target @see #target
#
# @param [Boolean] test_xcconfig
# whether this is an xcconfig for a test native target.
#
def initialize(target, test_xcconfig = false)
@target = target
@test_xcconfig = test_xcconfig
end
# Generates and saves the xcconfig to the given path.
#
# @param [Pathname] path
# the path where the xcconfig should be stored.
#
# @return [Xcodeproj::Config]
#
def save_as(path)
result = generate
result.save_as(path)
result
end
# Generates the xcconfig.
#
# @return [Xcodeproj::Config]
#
def generate
config = {
'FRAMEWORK_SEARCH_PATHS' => '$(inherited) ',
'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) COCOAPODS=1',
'HEADER_SEARCH_PATHS' => '$(inherited) ' + XCConfigHelper.quote(target.header_search_paths(test_xcconfig?)),
'LIBRARY_SEARCH_PATHS' => '$(inherited) ',
'OTHER_CFLAGS' => '$(inherited) ',
'OTHER_LDFLAGS' => XCConfigHelper.default_ld_flags(target, test_xcconfig?),
'OTHER_SWIFT_FLAGS' => '$(inherited) ',
'PODS_ROOT' => '${SRCROOT}',
'PODS_TARGET_SRCROOT' => target.pod_target_srcroot,
'PRODUCT_BUNDLE_IDENTIFIER' => 'org.cocoapods.${PRODUCT_NAME:rfc1034identifier}',
'SKIP_INSTALL' => 'YES',
'SWIFT_ACTIVE_COMPILATION_CONDITIONS' => '$(inherited) ',
'SWIFT_INCLUDE_PATHS' => '$(inherited) ',
}
xcconfig = Xcodeproj::Config.new(config)
XCConfigHelper.add_settings_for_file_accessors_of_target(nil, target, xcconfig, true, test_xcconfig?)
target.file_accessors.each do |file_accessor|
xcconfig.merge!(file_accessor.spec_consumer.pod_target_xcconfig) if test_xcconfig? == file_accessor.spec.test_specification?
end
XCConfigHelper.add_target_specific_settings(target, xcconfig)
recursive_dependent_targets = target.recursive_dependent_targets
xcconfig.merge! XCConfigHelper.search_paths_for_dependent_targets(target, recursive_dependent_targets, test_xcconfig?)
XCConfigHelper.generate_vendored_build_settings(target, recursive_dependent_targets, xcconfig, false, test_xcconfig?)
if test_xcconfig?
test_dependent_targets = [target, *target.recursive_test_dependent_targets].uniq
xcconfig.merge! XCConfigHelper.search_paths_for_dependent_targets(target, test_dependent_targets - recursive_dependent_targets, test_xcconfig?)
XCConfigHelper.generate_vendored_build_settings(nil, target.all_dependent_targets, xcconfig, true, test_xcconfig?)
XCConfigHelper.generate_other_ld_flags(nil, target.all_dependent_targets, xcconfig)
XCConfigHelper.generate_ld_runpath_search_paths(target, false, true, xcconfig)
end
xcconfig
end
#-----------------------------------------------------------------------#
end
end
end
end
require 'active_support/core_ext/object/try'
module Pod
module Generator
module XCConfig
# Stores the shared logic of the classes of the XCConfig module.
#
module XCConfigHelper
# @return [String] Used as alias for BUILD_DIR, so that when this
# is overridden in the user target, the user can override
# this variable to point to the standard directory, which
# will be used by CocoaPods.
#
BUILD_DIR_VARIABLE = '${PODS_BUILD_DIR}'.freeze
# @return [String] Used as alias for CONFIGURATION_BUILD_DIR, so that
# when this is overridden per {PodTarget}, it is still possible
# to reference other build products relative to the original
# path. Furthermore if it was overridden in the user target,
# the user can override this variable to point to the standard
# directory, which will be used by CocoaPods.
#
CONFIGURATION_BUILD_DIR_VARIABLE = '${PODS_CONFIGURATION_BUILD_DIR}'.freeze
# Converts an array of strings to a single string where the each string
# is surrounded by double quotes and separated by a space. Used to
# represent strings in a xcconfig file.
#
# @param [Array<String>] strings
# a list of strings.
#
# @param [String] prefix
# optional prefix, such as a flag or option.
#
# @return [String] the resulting string.
#
def self.quote(strings, prefix = nil)
prefix = "#{prefix} " if prefix
strings.sort.map { |s| %W( #{prefix}"#{s}" ) }.join(' ')
end
# Return the default linker flags
#
# @param [Target] target
# the target, which is used to check if the ARC compatibility
# flag is required.
#
# @param [Boolean] include_objc_flag
# whether to include `-ObjC` in the other linker flags
#
# @return [String] the default linker flags. `-ObjC` is optionally included depending
# on the target while `-fobjc-arc` is included only if requested in the Podfile.
#
def self.default_ld_flags(target, include_objc_flag = false)
ld_flags = ''
ld_flags << '-ObjC' if include_objc_flag
if target.podfile.set_arc_compatibility_flag? &&
target.spec_consumers.any?(&:requires_arc?)
ld_flags << ' -fobjc-arc'
end
ld_flags.strip
end
# Configures the given Xcconfig
#
# @param [Target] target
# The root target, may be nil.
#
# @param [PodTarget] pod_target
# The pod target, which holds the list of +Spec::FileAccessor+.
#
# @param [Xcodeproj::Config] xcconfig
# The xcconfig to edit.
#
# @param [Boolean] include_ld_flags
# Indicates whether or not to generate ld flags in addition to compile flags
#
# @param [Boolean] test_xcconfig
# Whether the settings for dependent targets are being generated for a test xcconfig or not.
#
# @return [void]
#
def self.add_settings_for_file_accessors_of_target(target, pod_target, xcconfig, include_ld_flags = true, test_xcconfig = false)
file_accessors = pod_target.file_accessors
file_accessors = file_accessors.reject { |f| f.spec.test_specification? } unless test_xcconfig
file_accessors.each do |file_accessor|
if target.nil? || !file_accessor.spec.test_specification?
XCConfigHelper.add_spec_build_settings_to_xcconfig(file_accessor.spec_consumer, xcconfig) if include_ld_flags
XCConfigHelper.add_static_dependency_build_settings(target, pod_target, xcconfig, file_accessor, include_ld_flags)
end
end
XCConfigHelper.add_dynamic_dependency_build_settings(target, pod_target, xcconfig, include_ld_flags, test_xcconfig)
if pod_target.requires_frameworks?
pod_target.dependent_targets.each do |dependent_target|
XCConfigHelper.add_dynamic_dependency_build_settings(target, dependent_target, xcconfig, include_ld_flags, test_xcconfig)
end
end
end
# Adds build settings for static vendored frameworks and libraries.
#
# @param [Target] target
# The root target, may be nil.
#
# @param [PodTarget] pod_target
# The pod target, which holds the list of +Spec::FileAccessor+.
#
# @param [Xcodeproj::Config] xcconfig
# The xcconfig to edit.
#
# @param [Spec::FileAccessor] file_accessor
# The file accessor, which holds the list of static frameworks.
#
# @param [Boolean] include_ld_flags
# Indicates whether or not to generate ld flags in addition to compile flags
#
# @return [void]
#
def self.add_static_dependency_build_settings(target, pod_target, xcconfig, file_accessor, include_ld_flags)
if target.nil? || !file_accessor.spec.test_specification?
adds_other_ldflags = include_ld_flags && XCConfigHelper.links_dependency?(target, pod_target)
file_accessor.vendored_static_frameworks.each do |vendored_static_framework|
XCConfigHelper.add_framework_build_settings(vendored_static_framework, xcconfig, pod_target.sandbox.root, adds_other_ldflags)
end
file_accessor.vendored_static_libraries.each do |vendored_static_library|
XCConfigHelper.add_library_build_settings(vendored_static_library, xcconfig, pod_target.sandbox.root, adds_other_ldflags)
end
end
end
# @param [AggregateTarget] aggregate_target
# The aggregate target, may be nil.
#
# @param [PodTarget] pod_target
# The pod target to link or not.
#
# @return [Boolean] Whether static dependency should be added to the 'OTHER_LDFLAGS'
# of the aggregate target. Aggregate targets that inherit search paths will only link
# if the target has explicitly declared the pod dependency.
#
def self.links_dependency?(aggregate_target, pod_target)
return true if aggregate_target.nil? || aggregate_target.target_definition.inheritance == 'complete'
aggregate_target.pod_targets_to_link.include?(pod_target)
end
# Adds build settings for dynamic vendored frameworks and libraries.
#
# @param [Target] target
# The root target, may be nil.
#
# @param [PodTarget] pod_target
# The pod target, which holds the list of +Spec::FileAccessor+.
#
# @param [Xcodeproj::Config] xcconfig
# The xcconfig to edit.
#
# @param [Boolean] include_ld_flags
# Indicates whether or not to generate ld flags in addition to compile flags
#
# @param [Boolean] test_xcconfig
# Whether the settings for dependent targets are being generated for a test xcconfig or not.
#
# @return [void]
#
def self.add_dynamic_dependency_build_settings(target, pod_target, xcconfig, include_ld_flags, test_xcconfig)
file_accessors = pod_target.file_accessors
file_accessors = file_accessors.reject { |f| f.spec.test_specification? } unless test_xcconfig
file_accessors.each do |file_accessor|
if target.nil? || !file_accessor.spec.test_specification?
file_accessor.vendored_dynamic_frameworks.each do |vendored_dynamic_framework|
XCConfigHelper.add_framework_build_settings(vendored_dynamic_framework, xcconfig, pod_target.sandbox.root, include_ld_flags)
end
file_accessor.vendored_dynamic_libraries.each do |vendored_dynamic_library|
XCConfigHelper.add_library_build_settings(vendored_dynamic_library, xcconfig, pod_target.sandbox.root, include_ld_flags)
end
end
end
end
# Configures the given Xcconfig according to the build settings of the
# given Specification.
#
# @param [Specification::Consumer] consumer
# The consumer of the specification.
#
# @param [Xcodeproj::Config] xcconfig
# The xcconfig to edit.
#
# @return [void]
#
def self.add_spec_build_settings_to_xcconfig(consumer, xcconfig)
xcconfig.libraries.merge(consumer.libraries)
xcconfig.frameworks.merge(consumer.frameworks)
xcconfig.weak_frameworks.merge(consumer.weak_frameworks)
add_developers_frameworks_if_needed(xcconfig)
end
# Configures the given Xcconfig with the build settings for the given
# framework path.
#
# @param [Pathname] framework_path
# The path of the framework.
#
# @param [Xcodeproj::Config] xcconfig
# The xcconfig to edit.
#
# @param [Pathname] sandbox_root
# The path retrieved from Sandbox#root.
#
# @param [Boolean] include_ld_flags
# Indicates whether or not to generate ld flags in addition to compile flags
#
# @return [void]
#
def self.add_framework_build_settings(framework_path, xcconfig, sandbox_root, include_ld_flags = true)
name = File.basename(framework_path, '.framework')
dirname = '${PODS_ROOT}/' + framework_path.dirname.relative_path_from(sandbox_root).to_s
build_settings = {
'FRAMEWORK_SEARCH_PATHS' => quote([dirname]),
}
build_settings['OTHER_LDFLAGS'] = "-framework \"#{name}\"" if include_ld_flags
xcconfig.merge!(build_settings)
end
# Configures the given Xcconfig with the build settings for the given
# library path.
#
# @param [Pathname] library_path
# The path of the library.
#
# @param [Xcodeproj::Config] xcconfig
# The xcconfig to edit.
#
# @param [Pathname] sandbox_root
# The path retrieved from Sandbox#root.
#
# @param [Boolean] include_ld_flags
# Indicates whether or not to generate ld flags in addition to compile flags
#
# @return [void]
#
def self.add_library_build_settings(library_path, xcconfig, sandbox_root, include_ld_flags = true)
extension = File.extname(library_path)
name = File.basename(library_path, extension).sub(/\Alib/, '')
dirname = '${PODS_ROOT}/' + library_path.dirname.relative_path_from(sandbox_root).to_s
build_settings = {
'LIBRARY_SEARCH_PATHS' => quote([dirname]),
}
build_settings['OTHER_LDFLAGS'] = "-l\"#{name}\"" if include_ld_flags
xcconfig.merge!(build_settings)
end
# Add the code signing settings for generated targets to ensure that
# frameworks are correctly signed to be integrated and re-signed when
# building the application and embedding the framework
#
# @param [Target] target
# The target.
#
# @param [Xcodeproj::Config] xcconfig
# The xcconfig to edit.
#
# @return [void]
#
def self.add_code_signing_settings(target, xcconfig)
build_settings = {}
if target.platform.to_sym == :osx
build_settings['CODE_SIGN_IDENTITY'] = ''
end
xcconfig.merge!(build_settings)
end
# Checks if the given target requires specific settings and configures
# the given Xcconfig.
#
# @param [Target] target
# The target.
#
# @param [Xcodeproj::Config] xcconfig
# The xcconfig to edit.
#
# @return [void]
#
def self.add_target_specific_settings(target, xcconfig)
if target.requires_frameworks?
add_code_signing_settings(target, xcconfig)
end
add_language_specific_settings(target, xcconfig)
end
# Returns the search paths for frameworks and libraries the given target
# depends on, so that it can be correctly built and linked.
#
# @param [Target] target
# The target.
#
# @param [Array<PodTarget>] dependent_targets
# The pod targets the given target depends on.
#
# @param [Boolean] test_xcconfig
# Whether the settings for dependent targets are being generated for a test xcconfig or not.
#
# @return [Hash<String, String>] the settings
#
def self.search_paths_for_dependent_targets(target, dependent_targets, test_xcconfig = false)
dependent_targets = dependent_targets.select(&:should_build?)
# Filter out dependent targets that are subsets of another target.
subset_targets = []
dependent_targets.uniq.combination(2) do |a, b|
if (a.specs - b.specs).empty?
subset_targets << a
elsif (b.specs - a.specs).empty?
subset_targets << b
end
end
dependent_targets -= subset_targets
# Alias build dirs to avoid recursive definitions for pod targets and depending
# on build settings which could be overwritten in the user target.
build_settings = {
BUILD_DIR_VARIABLE[2..-2] => '${BUILD_DIR}',
CONFIGURATION_BUILD_DIR_VARIABLE[2..-2] => "#{BUILD_DIR_VARIABLE}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)",
}
# Scope pod targets as long as they are not test targets.
if !test_xcconfig && target.respond_to?(:configuration_build_dir)
build_settings['CONFIGURATION_BUILD_DIR'] = target.configuration_build_dir(CONFIGURATION_BUILD_DIR_VARIABLE)
end
module_map_files = []
unless dependent_targets.empty?
framework_search_paths = []
library_search_paths = []
swift_import_paths = []
dependent_targets.each do |dependent_target|
if dependent_target.requires_frameworks?
framework_search_paths << dependent_target.configuration_build_dir(CONFIGURATION_BUILD_DIR_VARIABLE)
else
library_search_paths << dependent_target.configuration_build_dir(CONFIGURATION_BUILD_DIR_VARIABLE)
if dependent_target.defines_module?
module_map_file = if dependent_target.uses_swift?
# for swift, we have a custom build phase that copies in the module map, appending the .Swift module
"${PODS_CONFIGURATION_BUILD_DIR}/#{dependent_target.label}/#{dependent_target.product_module_name}.modulemap"
else
"${PODS_ROOT}/#{dependent_target.module_map_path.relative_path_from(dependent_target.sandbox.root)}"
end
module_map_files << %(-fmodule-map-file="#{module_map_file}")
swift_import_paths << dependent_target.configuration_build_dir(CONFIGURATION_BUILD_DIR_VARIABLE) if dependent_target.uses_swift?
end
end
end
build_settings['FRAMEWORK_SEARCH_PATHS'] = XCConfigHelper.quote(framework_search_paths.uniq)
build_settings['LIBRARY_SEARCH_PATHS'] = XCConfigHelper.quote(library_search_paths.uniq)
build_settings['SWIFT_INCLUDE_PATHS'] = XCConfigHelper.quote(swift_import_paths.uniq)
end
other_swift_flags = module_map_files.tap(&:uniq!).flat_map { |f| ['-Xcc', f] }
if target.is_a?(PodTarget) && !target.requires_frameworks? && target.defines_module? && !test_xcconfig
# make it possible for a mixed swift/objc static library to be able to import the objc from within swift
other_swift_flags += ['-import-underlying-module', '-Xcc', '-fmodule-map-file="${SRCROOT}/${MODULEMAP_FILE}"']
end
# unconditionally set these, because of (the possibility of) having to add the pod targets own module map file
build_settings['OTHER_CFLAGS'] = module_map_files.join(' ')
build_settings['OTHER_SWIFT_FLAGS'] = other_swift_flags.join(' ')
build_settings
end
# Updates xcconfig with the HEADER_SEARCH_PATHS from the search_paths.
#
# @param [Target] search_paths_target
# The target.
#
# @param [Xcodeproj::Config] xcconfig
# The xcconfig to edit.
#
def self.propagate_header_search_paths_from_search_paths(search_paths_target, xcconfig)
header_search_paths_list = []
search_paths_target.pod_targets.each do |target|
target.spec_consumers.each do |spec_consumer|
paths = spec_consumer.user_target_xcconfig['HEADER_SEARCH_PATHS']
header_search_paths_list <<= paths unless paths.nil?
end
unless header_search_paths_list == []
header_search_paths = header_search_paths_list.join(' ')
unless header_search_paths.include? '$(inherited)'
header_search_paths = '$(inherited) ' + header_search_paths
end
build_settings = { 'HEADER_SEARCH_PATHS' => header_search_paths }
xcconfig.merge!(build_settings)
end
end
end
# Add custom build settings and required build settings to link to
# vendored libraries and frameworks.
#
# @param [Target] target
# The root target, may be nil.
#
# @param [Array<PodTarget] dep_targets
# The dependency targets to add the vendored build settings for.
#
# @param [Xcodeproj::Config] xcconfig
# The xcconfig to edit.
#
# @param [Boolean] include_ld_flags
# Indicates whether or not to generate ld flags in addition to compile flags
#
# @param [Boolean] test_xcconfig
# Indicates whether or not the generated ld flags are for a test xcconfig or not
#
# @note
# In case of generated pod targets, which require frameworks, the
# vendored frameworks and libraries are already linked statically
# into the framework binary and must not be linked again to the
# user target.
#
def self.generate_vendored_build_settings(target, dep_targets, xcconfig, include_ld_flags = true, test_xcconfig = false)
dep_targets.each do |dep_target|
unless dep_target.should_build? && dep_target.requires_frameworks? && !dep_target.static_framework?
XCConfigHelper.add_settings_for_file_accessors_of_target(target, dep_target, xcconfig, include_ld_flags, test_xcconfig)
end
end
end
# Ensure to add the default linker run path search paths as they could
# be not present due to being historically absent in the project or
# target template or just being removed by being superficial when
# linking third-party dependencies exclusively statically. This is not
# something a project needs specifically for the integration with
# CocoaPods, but makes sure that it is self-contained for the given
# constraints.
#
# @param [Target] target
# The target, this can be an aggregate target or a pod target.
#
# @param [Boolean] requires_host_target
# If this target requires a host target
#
# @param [Boolean] test_bundle
# Whether this is a test bundle or not. This has an effect when the platform is `osx` and changes
# the runtime search paths accordingly.
#
# @param [Xcodeproj::Config] xcconfig
# The xcconfig to edit.
#
# @return [void]
#
def self.generate_ld_runpath_search_paths(target, requires_host_target, test_bundle, xcconfig)
ld_runpath_search_paths = ['$(inherited)']
if target.platform.symbolic_name == :osx
ld_runpath_search_paths << "'@executable_path/../Frameworks'"
ld_runpath_search_paths << \
if test_bundle
"'@loader_path/../Frameworks'"
else
"'@loader_path/Frameworks'"
end
else
ld_runpath_search_paths << [
"'@executable_path/Frameworks'",
"'@loader_path/Frameworks'",
]
ld_runpath_search_paths << "'@executable_path/../../Frameworks'" if requires_host_target
end
xcconfig.merge!('LD_RUNPATH_SEARCH_PATHS' => ld_runpath_search_paths.join(' '))
end
# Add pod target to list of frameworks / libraries that are linked
# with the user’s project.
#
# @param [AggregateTarget] aggregate_target
# The aggregate target, may be nil.
#
# @param [Array<PodTarget] pod_targets
# The pod targets to add the vendored build settings for.
#
# @param [Xcodeproj::Config] xcconfig
# The xcconfig to edit.
#
# @return [void]
#
def self.generate_other_ld_flags(aggregate_target, pod_targets, xcconfig)
# Make sure -framework option gets added for the search paths when static_frameworks are involved.
# Otherwise test targets won't link in their primary target's dependencies.
unless aggregate_target.nil?
dependent_targets = aggregate_target.search_paths_aggregate_targets
dependent_targets.each do |dependent_target|
if aggregate_target.requires_frameworks? && dependent_target.pod_targets.any?(&:static_framework?)
generate_other_ld_flags(dependent_target, dependent_target.pod_targets, xcconfig)
end
end
end
other_ld_flags = pod_targets.select(&:should_build?).map do |pod_target|
if pod_target.requires_frameworks?
%(-framework "#{pod_target.product_basename}")
elsif XCConfigHelper.links_dependency?(aggregate_target, pod_target)
%(-l "#{pod_target.product_basename}")
end
end
xcconfig.merge!('OTHER_LDFLAGS' => other_ld_flags.compact.join(' '))
end
# Checks if the given target requires language specific settings and
# configures the given Xcconfig.
#
# @param [Target] target
# The target.
#
# @param [Xcodeproj::Config] xcconfig
# The xcconfig to edit.
#
# @return [void]
#
def self.add_language_specific_settings(target, xcconfig)
if target.uses_swift?
other_swift_flags = ['$(inherited)', quote(%w(-D COCOAPODS))]
other_swift_flags << quote(%w(-suppress-warnings)) if target.try(:inhibit_warnings?)
build_settings = { 'OTHER_SWIFT_FLAGS' => other_swift_flags.join(' ') }
xcconfig.merge!(build_settings)
end
end
# Adds the search paths of the developer frameworks to the specification
# if needed. This is done because the `SenTestingKit` requires them and
# adding them to each specification which requires it is repetitive and
# error prone.
#
# @param [Xcodeproj::Config] xcconfig
# The xcconfig to edit.
#
# @return [void]
#
def self.add_developers_frameworks_if_needed(xcconfig)
matched_frameworks = xcconfig.frameworks & %w(XCTest SenTestingKit)
unless matched_frameworks.empty?
search_paths = xcconfig.attributes['FRAMEWORK_SEARCH_PATHS'] ||= ''
search_paths_to_add = []
search_paths_to_add << '$(inherited)'
frameworks_path = '"$(PLATFORM_DIR)/Developer/Library/Frameworks"'
search_paths_to_add << frameworks_path
search_paths_to_add.each do |search_path|
unless search_paths.include?(search_path)
search_paths << ' ' unless search_paths.empty?
search_paths << search_path
end
end
end
end
#---------------------------------------------------------------------#
end
end
end
end
...@@ -441,7 +441,7 @@ module Pod ...@@ -441,7 +441,7 @@ module Pod
user_project = nil user_project = nil
client_root = config.installation_root.realpath client_root = config.installation_root.realpath
user_target_uuids = [] user_target_uuids = []
user_build_configurations = target_definition.build_configurations || { 'Release' => :release, 'Debug' => :debug } user_build_configurations = target_definition.build_configurations || Target::DEFAULT_BUILD_CONFIGURATIONS
archs = [] archs = []
if target_definition.platform && target_definition.platform.name == :osx if target_definition.platform && target_definition.platform.name == :osx
archs = ['$(ARCHS_STANDARD_64_BIT)'] archs = ['$(ARCHS_STANDARD_64_BIT)']
......
...@@ -96,9 +96,9 @@ module Pod ...@@ -96,9 +96,9 @@ module Pod
def create_xcconfig_file(native_target) def create_xcconfig_file(native_target)
native_target.build_configurations.each do |configuration| native_target.build_configurations.each do |configuration|
path = target.xcconfig_path(configuration.name) path = target.xcconfig_path(configuration.name)
gen = Generator::XCConfig::AggregateXCConfig.new(target, configuration.name) build_settings = target.build_settings(configuration.name)
xcconfig = update_changed_file(gen, path) update_changed_file(build_settings, path)
target.xcconfigs[configuration.name] = xcconfig target.xcconfigs[configuration.name] = build_settings.xcconfig
xcconfig_file_ref = add_file_to_support_group(path) xcconfig_file_ref = add_file_to_support_group(path)
configuration.base_configuration_reference = xcconfig_file_ref configuration.base_configuration_reference = xcconfig_file_ref
end end
......
...@@ -158,13 +158,6 @@ module Pod ...@@ -158,13 +158,6 @@ module Pod
added_public_headers = true added_public_headers = true
sandbox.public_headers.add_files(namespaced_path, files) sandbox.public_headers.add_files(namespaced_path, files)
end end
unless pod_target.requires_frameworks?
vendored_frameworks_header_mappings(headers_sandbox, file_accessor).each do |namespaced_path, files|
added_public_headers = true
sandbox.public_headers.add_files(namespaced_path, files)
end
end
end end
pod_target.build_headers.add_search_path(headers_sandbox, pod_target.platform) if added_build_headers pod_target.build_headers.add_search_path(headers_sandbox, pod_target.platform) if added_build_headers
...@@ -332,36 +325,6 @@ module Pod ...@@ -332,36 +325,6 @@ module Pod
mappings mappings
end end
# Computes the destination sub-directory in the sandbox for headers
# from inside vendored frameworks.
#
# @param [Pathname] headers_sandbox
# The sandbox where the header links should be stored for this
# Pod.
#
# @param [Sandbox::FileAccessor] file_accessor
# The consumer file accessor for which the headers need to be
# linked.
#
def vendored_frameworks_header_mappings(headers_sandbox, file_accessor)
mappings = {}
file_accessor.vendored_frameworks.each do |framework|
headers_dir = Sandbox::FileAccessor.vendored_frameworks_headers_dir(framework)
headers = Sandbox::FileAccessor.vendored_frameworks_headers(framework)
framework_name = framework.basename(framework.extname)
dir = headers_sandbox + framework_name
headers.each do |header|
# the relative path of framework headers should be kept,
# not flattened like is done for most public headers.
relative_path = header.relative_path_from(headers_dir)
sub_dir = dir + relative_path.dirname
mappings[sub_dir] ||= []
mappings[sub_dir] << header
end
end
mappings
end
#-----------------------------------------------------------------------# #-----------------------------------------------------------------------#
end end
end end
......
...@@ -402,8 +402,7 @@ module Pod ...@@ -402,8 +402,7 @@ module Pod
# #
def create_xcconfig_file(native_target, resource_bundle_targets) def create_xcconfig_file(native_target, resource_bundle_targets)
path = target.xcconfig_path path = target.xcconfig_path
xcconfig_gen = Generator::XCConfig::PodXCConfig.new(target) update_changed_file(target.build_settings, path)
update_changed_file(xcconfig_gen, path)
xcconfig_file_ref = add_file_to_support_group(path) xcconfig_file_ref = add_file_to_support_group(path)
native_target.build_configurations.each do |c| native_target.build_configurations.each do |c|
...@@ -427,8 +426,7 @@ module Pod ...@@ -427,8 +426,7 @@ module Pod
def create_test_xcconfig_files(test_native_targets, test_resource_bundle_targets) def create_test_xcconfig_files(test_native_targets, test_resource_bundle_targets)
target.supported_test_types.each do |test_type| target.supported_test_types.each do |test_type|
path = target.xcconfig_path(test_type.to_s) path = target.xcconfig_path(test_type.to_s)
xcconfig_gen = Generator::XCConfig::PodXCConfig.new(target, true) update_changed_file(Target::BuildSettings::PodTargetSettings.new(target, true), path)
update_changed_file(xcconfig_gen, path)
xcconfig_file_ref = add_file_to_support_group(path) xcconfig_file_ref = add_file_to_support_group(path)
test_native_targets.each do |test_target| test_native_targets.each do |test_target|
......
...@@ -63,7 +63,7 @@ module Pod ...@@ -63,7 +63,7 @@ module Pod
paths << "${PODS_ROOT}/#{headers_dir}/#{@relative_path}" if !use_modular_headers || @visibility_scope == :public paths << "${PODS_ROOT}/#{headers_dir}/#{@relative_path}" if !use_modular_headers || @visibility_scope == :public
paths << "${PODS_ROOT}/#{headers_dir}/#{entry[:path]}" if !use_modular_headers || @visibility_scope == :private paths << "${PODS_ROOT}/#{headers_dir}/#{entry[:path]}" if !use_modular_headers || @visibility_scope == :private
paths paths
end.uniq end.tap(&:uniq!).freeze
end end
# Removes the directory as it is regenerated from scratch during each # Removes the directory as it is regenerated from scratch during each
......
require 'cocoapods/target/build_settings'
module Pod module Pod
# Model class which describes a Pods target. # Model class which describes a Pods target.
# #
...@@ -8,6 +10,7 @@ module Pod ...@@ -8,6 +10,7 @@ module Pod
class Target class Target
DEFAULT_VERSION = '1.0.0'.freeze DEFAULT_VERSION = '1.0.0'.freeze
DEFAULT_NAME = 'Default'.freeze DEFAULT_NAME = 'Default'.freeze
DEFAULT_BUILD_CONFIGURATIONS = { 'Release' => :release, 'Debug' => :debug }.freeze
# @return [Sandbox] The sandbox where the Pods should be installed. # @return [Sandbox] The sandbox where the Pods should be installed.
# #
...@@ -33,6 +36,10 @@ module Pod ...@@ -33,6 +36,10 @@ module Pod
# #
attr_reader :platform attr_reader :platform
# @return [BuildSettings] the build settings for this target.
#
attr_reader :build_settings
# Initialize a new target # Initialize a new target
# #
# @param [Sandbox] sandbox @see #sandbox # @param [Sandbox] sandbox @see #sandbox
...@@ -47,6 +54,8 @@ module Pod ...@@ -47,6 +54,8 @@ module Pod
@user_build_configurations = user_build_configurations @user_build_configurations = user_build_configurations
@archs = archs @archs = archs
@platform = platform @platform = platform
@build_settings = create_build_settings
end end
# @return [String] the name of the library. # @return [String] the name of the library.
...@@ -228,5 +237,9 @@ module Pod ...@@ -228,5 +237,9 @@ module Pod
def c99ext_identifier(name) def c99ext_identifier(name)
name.gsub(/^([0-9])/, '_\1').gsub(/[^a-zA-Z0-9_]/, '_') name.gsub(/^([0-9])/, '_\1').gsub(/[^a-zA-Z0-9_]/, '_')
end end
def create_build_settings
BuildSettings.new(self)
end
end end
end end
...@@ -77,6 +77,16 @@ module Pod ...@@ -77,6 +77,16 @@ module Pod
@xcconfigs = {} @xcconfigs = {}
end end
def build_settings(configuration_name = nil)
if configuration_name
@build_settings[configuration_name] ||
raise(ArgumentError, "#{self} does not contain a build setting for the #{configuration_name.inspect} configuration, only #{@build_settings.keys.inspect}")
else
@build_settings.each_value.first ||
raise(ArgumentError, "#{self} does not contain any build settings")
end
end
# @return [Boolean] True if the user_target refers to a # @return [Boolean] True if the user_target refers to a
# library (framework, static or dynamic lib). # library (framework, static or dynamic lib).
# #
...@@ -153,10 +163,6 @@ module Pod ...@@ -153,10 +163,6 @@ module Pod
end end
end end
def pod_targets_to_link
@pod_targets_to_link ||= pod_targets.to_set - search_paths_aggregate_targets.flat_map(&:pod_targets)
end
# @return [Array<Specification>] The specifications used by this aggregate target. # @return [Array<Specification>] The specifications used by this aggregate target.
# #
def specs def specs
...@@ -309,5 +315,15 @@ module Pod ...@@ -309,5 +315,15 @@ module Pod
def relative_to_srcroot(path) def relative_to_srcroot(path)
path.relative_path_from(client_root).to_s path.relative_path_from(client_root).to_s
end end
def create_build_settings
settings = {}
user_build_configurations.each_key do |configuration_name|
settings[configuration_name] = BuildSettings::AggregateTargetSettings.new(self, configuration_name)
end
settings
end
end end
end end
# frozen_string_literal: true
module Pod
class Target
# @since 1.5.0
class BuildSettings
#-------------------------------------------------------------------------#
# @!group Constants
# @return [Set<String>]
# The build settings that should be treated as arrays, rather than strings.
#
PLURAL_SETTINGS = %w(
ALTERNATE_PERMISSIONS_FILES
ARCHS
BUILD_VARIANTS
EXCLUDED_SOURCE_FILE_NAMES
FRAMEWORK_SEARCH_PATHS
GCC_PREPROCESSOR_DEFINITIONS
GCC_PREPROCESSOR_DEFINITIONS_NOT_USED_IN_PRECOMPS
HEADER_SEARCH_PATHS
INFOPLIST_PREPROCESSOR_DEFINITIONS
LD_RUNPATH_SEARCH_PATHS
LIBRARY_SEARCH_PATHS
OTHER_CFLAGS
OTHER_CPLUSPLUSFLAGS
OTHER_LDFLAGS
OTHER_SWIFT_FLAGS
REZ_SEARCH_PATHS
SECTORDER_FLAGS
SWIFT_ACTIVE_COMPILATION_CONDITIONS
SWIFT_INCLUDE_PATHS
WARNING_CFLAGS
WARNING_LDFLAGS
).to_set.freeze
# @return [String]
# The variable for the configuration build directory used when building pod targets.
#
CONFIGURATION_BUILD_DIR_VARIABLE = '${PODS_CONFIGURATION_BUILD_DIR}'.freeze
#-------------------------------------------------------------------------#
# @!group DSL
# Creates a method that calculates a part of the build settings for the {#target}.
#
# @!visibility private
#
# @param [Symbol,String] method_name
# The name of the method to define
#
# @param [Boolean] build_setting
# Whether the method name should be added (upcased) to {.build_setting_names}
#
# @param [Boolean] memoized
# Whether the method should be memoized
#
# @param [Boolean] sorted
# Whether the return value should be sorted
#
# @param [Boolean] uniqued
# Whether the return value should be uniqued
#
# @param [Boolean] compacted
# Whether the return value should be compacted
#
# @param [Boolean] frozen
# Whether the return value should be frozen
#
# @param [Boolean, Symbol] from_search_paths_aggregate_targets
# If truthy, the method from {Aggregate} that should be used to concatenate build settings from
# {::Pod::AggregateTarget#search_paths_aggregate_target}
#
# @param [Symbol] from_pod_targets_to_link
# If truthy, the `_to_import` values from `BuildSettings#pod_targets_to_link` will be concatenated
#
# @param [Block] implementation
#
# @macro [attach] define_build_settings_method
# @!method $1
#
# The `$1` build setting for the {#target}.
#
# The return value from this method will be: `${1--1}`.
#
def self.define_build_settings_method(method_name, build_setting: false,
memoized: false, sorted: false, uniqued: false, compacted: false, frozen: true,
from_search_paths_aggregate_targets: false, from_pod_targets_to_link: false,
&implementation)
memoized_key = "#{self}##{method_name}".freeze
(@build_settings_names ||= Set.new) << method_name.to_s.upcase if build_setting
raw_method_name = :"_raw_#{method_name}"
define_method(raw_method_name, &implementation)
private(raw_method_name)
dup_before_freeze = frozen && (from_pod_targets_to_link || from_search_paths_aggregate_targets || uniqued || sorted)
define_method(method_name) do
if memoized
@__memoized ||= {}
retval = @__memoized.fetch(memoized_key, :not_found)
return retval if :not_found != retval
end
retval = send(raw_method_name)
if retval.nil?
@__memoized[memoized_key] = retval if memoized
return
end
retval = retval.dup if dup_before_freeze && retval.frozen?
retval.concat(pod_targets_to_link.flat_map { |pod_target| pod_target.build_settings.public_send("#{method_name}_to_import") }) if from_pod_targets_to_link
retval.concat(search_paths_aggregate_target_pod_target_build_settings.flat_map(&from_search_paths_aggregate_targets)) if from_search_paths_aggregate_targets
retval.compact! if compacted
retval.uniq! if uniqued
retval.sort! if sorted
retval.freeze if frozen
@__memoized[memoized_key] = retval if memoized
retval
end
end
private_class_method :define_build_settings_method
class << self
#-------------------------------------------------------------------------#
# @!group Public API
# @return [Set<String>] a set of all the build settings names that will
# be present in the #xcconfig
#
attr_reader :build_settings_names
end
#-------------------------------------------------------------------------#
# @!group Public API
# @return [Target]
# The target this build settings object is generating build settings for
#
attr_reader :target
# Initialize a new instance
#
# @param [Target] target
# see {#target}
#
def initialize(target)
@target = target
end
# @return [Xcodeproj::Config]
define_build_settings_method :xcconfig, :memoized => true do
settings = add_inherited_to_plural(to_h)
Xcodeproj::Config.new(settings)
end
# @return [Xcodeproj::Config]
#
# @!visibility private
# @see #__clear__
# @see #xcconfig
def generate
__clear__
xcconfig
end
# Saves the generated xcconfig to the given path
#
# @return [Xcodeproj::Config]
#
# @see #xcconfig
#
# @param [String,Pathname] path
# The path the xcconfig will be saved to
#
def save_as(path)
xcconfig.save_as(path)
end
#-------------------------------------------------------------------------#
# @!group Paths
# @return [String]
define_build_settings_method :pods_build_dir, :build_setting => true do
'${BUILD_DIR}'
end
# @return [String]
define_build_settings_method :pods_configuration_build_dir, :build_setting => true do
'${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)'
end
#-------------------------------------------------------------------------#
# @!group Code Signing
# @return [String]
define_build_settings_method :code_sign_identity, :build_setting => true do
return unless target.requires_frameworks?
return unless target.platform.to_sym == :osx
''
end
#-------------------------------------------------------------------------#
# @!group Frameworks
# @return [Array<String>]
define_build_settings_method :frameworks do
[]
end
# @return [Array<String>]
define_build_settings_method :weak_frameworks do
[]
end
# @return [Array<String>]
define_build_settings_method :framework_search_paths, :build_setting => true, :memoized => true do
framework_search_paths_to_import_developer_frameworks(frameworks)
end
# @param [Array<String>] frameworks
# The list of framework names
#
# @return [Array<String>]
# the `FRAMEWORK_SEARCH_PATHS` needed to import developer frameworks
def framework_search_paths_to_import_developer_frameworks(frameworks)
if frameworks.include?('XCTest') || frameworks.include?('SenTestingKit')
%w[ $(PLATFORM_DIR)/Developer/Library/Frameworks ]
else
[]
end
end
#-------------------------------------------------------------------------#
# @!group Libraries
# @return [Array<String>]
define_build_settings_method :libraries do
[]
end
#-------------------------------------------------------------------------#
# @!group Clang
# @return [Array<String>]
define_build_settings_method :gcc_preprocessor_definitions, :build_setting => true do
%w( COCOAPODS=1 )
end
# @return [Array<String>]
define_build_settings_method :other_cflags, :build_setting => true, :memoized => true do
module_map_files.map { |f| "-fmodule-map-file=#{f}" }
end
# @return [Array<String>]
define_build_settings_method :module_map_files do
[]
end
#-------------------------------------------------------------------------#
# @!group Swift
# @return [Boolean]
# Whether `OTHER_SWIFT_FLAGS` should be generated when the target
# does not use swift.
#
def other_swift_flags_without_swift?
false
end
# @return [Array<String>]
define_build_settings_method :other_swift_flags, :build_setting => true, :memoized => true do
return unless target.uses_swift? || other_swift_flags_without_swift?
flags = %w(-D COCOAPODS)
flags.concat module_map_files.flat_map { |f| ['-Xcc', "-fmodule-map-file=#{f}"] }
flags
end
#-------------------------------------------------------------------------#
# @!group Linking
# @return [Boolean]
define_build_settings_method :requires_objc_linker_flag? do
false
end
# @return [Boolean]
define_build_settings_method :requires_fobjc_arc? do
false
end
# @return [Array<String>]
# the `LD_RUNPATH_SEARCH_PATHS` needed for dynamically linking the {#target}
#
# @param [Boolean] requires_host_target
#
# @param [Boolean] test_bundle
#
def _ld_runpath_search_paths(requires_host_target: false, test_bundle: false)
if target.platform.symbolic_name == :osx
["'@executable_path/../Frameworks'",
test_bundle ? "'@loader_path/../Frameworks'" : "'@loader_path/Frameworks'"]
else
paths = [
"'@executable_path/Frameworks'",
"'@loader_path/Frameworks'",
]
paths << "'@executable_path/../../Frameworks'" if requires_host_target
paths
end
end
private :_ld_runpath_search_paths
# @return [Array<String>]
define_build_settings_method :other_ldflags, :build_setting => true, :memoized => true do
ld_flags = []
ld_flags << '-ObjC' if requires_objc_linker_flag?
if requires_fobjc_arc?
ld_flags << '-fobjc-arc'
end
libraries.each { |l| ld_flags << %(-l"#{l}") }
frameworks.each { |f| ld_flags << '-framework' << %("#{f}") }
weak_frameworks.each { |f| ld_flags << '-weak_framework' << %("#{f}") }
ld_flags
end
#-------------------------------------------------------------------------#
# @!group Private Methods
# Clears all memoized settings.
# @!visibility private
# @return [Void]
def __clear__
@__memoized = nil
end
private
# @return [Hash<String => String|Array<String>>]
def to_h
hash = {}
self.class.build_settings_names.sort.each do |setting|
hash[setting] = public_send(setting.downcase)
end
hash
end
# @return [Hash<String => String>]
def add_inherited_to_plural(hash)
Hash[hash.map do |key, value|
next [key, '$(inherited)'] if value.nil?
if PLURAL_SETTINGS.include?(key)
raise ArgumentError, "#{key} is a plural setting, cannot have #{value.inspect} as its value" unless value.is_a? Array
value = "$(inherited) #{quote_array(value)}"
else
raise ArgumentError, "#{key} is not a plural setting, cannot have #{value.inspect} as its value" unless value.is_a? String
end
[key, value]
end]
end
# @return [Array<String>]
#
# @param [Array<String>] array
#
def quote_array(array)
array.map do |element|
case element
when /\A([\w-]+?)=(.+)\z/
key = Regexp.last_match(1)
value = Regexp.last_match(2)
value = %("#{value}") if value =~ /[^\w\d]/
%(#{key}=#{value})
when /[\$\[\]\ ]/
%("#{element}")
else
element
end
end.join(' ')
end
# @param [Hash] xcconfig_values_by_consumer_by_key
#
# @param [#to_s] attribute
# The name of the attribute being merged
#
# @return [Hash<String, String>]
#
def merged_xcconfigs(xcconfig_values_by_consumer_by_key, attribute)
xcconfig_values_by_consumer_by_key.each_with_object({}) do |(key, values_by_consumer), xcconfig|
uniq_values = values_by_consumer.values.uniq
values_are_bools = uniq_values.all? { |v| v =~ /\A(yes|no)\z/i }
if values_are_bools
# Boolean build settings
if uniq_values.count > 1
UI.warn "Can't merge #{attribute} for pod targets: " \
"#{values_by_consumer.keys.map(&:name)}. Boolean build " \
"setting #{key} has different values."
else
xcconfig[key] = uniq_values.first
end
elsif PLURAL_SETTINGS.include? key
# Plural build settings
xcconfig[key] = uniq_values.join(' ')
elsif uniq_values.count > 1
# Singular build settings
UI.warn "Can't merge #{attribute} for pod targets: " \
"#{values_by_consumer.keys.map(&:name)}. Singular build " \
"setting #{key} has different values."
else
xcconfig[key] = uniq_values.first
end
end
end
# Filters out pod targets whose `specs` are a subset of
# another target's.
#
# @param [Array<PodTarget>] dependent_targets
#
# @return [Array<PodTarget>]
#
def select_maximal_pod_targets(pod_targets)
subset_targets = []
pod_targets.uniq.combination(2) do |a, b|
if (a.specs - b.specs).empty?
subset_targets << a
elsif (b.specs - a.specs).empty?
subset_targets << b
end
end
pod_targets - subset_targets
end
# A subclass that generates build settings for a {PodTarget}
class PodTargetSettings < BuildSettings
#-------------------------------------------------------------------------#
# @!group Public API
# @see BuildSettings.build_settings_names
def self.build_settings_names
@build_settings_names | BuildSettings.build_settings_names
end
# @return [Boolean]
# whether settings are being generated for a test bundle
#
attr_reader :test_xcconfig
alias test_xcconfig? test_xcconfig
# Intializes a new instance
#
# @param [PodTarget] target
# see {#target}
#
# @param [String] configuration_name
# see {#configuration_name}
#
# @param [Boolean] test_xcconfig
# see {#test_xcconfig?}
#
def initialize(target, test_xcconfig)
super(target)
@test_xcconfig = test_xcconfig
end
# @return [Xcodeproj::Xconfig]
define_build_settings_method :xcconfig, :memoized => true do
xcconfig = super()
xcconfig.merge(pod_target_xcconfig)
end
#-------------------------------------------------------------------------#
# @!group Paths
# @return [String]
define_build_settings_method :pods_root, :build_setting => true do
'${SRCROOT}'
end
# @return [String]
define_build_settings_method :pods_target_srcroot, :build_setting => true do
target.pod_target_srcroot
end
#-------------------------------------------------------------------------#
# @!group Frameworks
# @return [Array<String>]
define_build_settings_method :consumer_frameworks, :memoized => true do
spec_consumers.flat_map(&:frameworks)
end
# @return [Array<String>]
define_build_settings_method :frameworks, :memoized => true, :sorted => true, :uniqued => true do
return [] if (!target.requires_frameworks? || target.static_framework?) && !test_xcconfig?
frameworks = vendored_dynamic_frameworks.map { |l| File.basename(l, '.framework') }
frameworks.concat vendored_static_frameworks.map { |l| File.basename(l, '.framework') } unless test_xcconfig?
frameworks.concat consumer_frameworks
frameworks.concat dependent_targets.flat_map { |pt| pt.build_settings.dynamic_frameworks_to_import }
frameworks.concat dependent_targets.flat_map { |pt| pt.build_settings.static_frameworks_to_import } if test_xcconfig?
frameworks
end
# @return [Array<String>]
define_build_settings_method :static_frameworks_to_import, :memoized => true do
static_frameworks_to_import = []
static_frameworks_to_import.concat vendored_static_frameworks.map { |f| File.basename(f, '.framework') } unless target.should_build? && target.requires_frameworks? && !target.static_framework?
static_frameworks_to_import << target.product_basename if target.should_build? && target.requires_frameworks? && target.static_framework?
static_frameworks_to_import
end
# @return [Array<String>]
define_build_settings_method :dynamic_frameworks_to_import, :memoized => true do
dynamic_frameworks_to_import = vendored_dynamic_frameworks.map { |f| File.basename(f, '.framework') }
dynamic_frameworks_to_import << target.product_basename if target.should_build? && target.requires_frameworks? && !target.static_framework?
dynamic_frameworks_to_import.concat consumer_frameworks
dynamic_frameworks_to_import
end
# @return [Array<String>]
define_build_settings_method :weak_frameworks, :memoized => true do
return [] if (!target.requires_frameworks? || target.static_framework?) && !test_xcconfig?
weak_frameworks = spec_consumers.flat_map(&:weak_frameworks)
weak_frameworks.concat dependent_targets.flat_map { |pt| pt.build_settings.weak_frameworks_to_import }
weak_frameworks
end
# @return [Array<String>]
define_build_settings_method :frameworks_to_import, :memoized => true, :sorted => true, :uniqued => true do
static_frameworks_to_import + dynamic_frameworks_to_import
end
# @return [Array<String>]
define_build_settings_method :weak_frameworks_to_import, :memoized => true, :sorted => true, :uniqued => true do
[]
end
# @return [Array<String>]
define_build_settings_method :framework_search_paths, :build_setting => true, :memoized => true, :sorted => true, :uniqued => true do
paths = super().dup
paths.concat dependent_targets.flat_map { |t| t.build_settings.framework_search_paths_to_import }
paths.concat framework_search_paths_to_import
paths.delete(target.configuration_build_dir(CONFIGURATION_BUILD_DIR_VARIABLE)) unless test_xcconfig?
paths
end
# @return [Array<String>]
define_build_settings_method :vendored_framework_search_paths, :memoized => true do
file_accessors.flat_map(&:vendored_frameworks).map { |f| File.join '${PODS_ROOT}', f.dirname.relative_path_from(target.sandbox.root) }
end
# @return [Array<String>]
define_build_settings_method :framework_search_paths_to_import, :memoized => true do
paths = framework_search_paths_to_import_developer_frameworks(consumer_frameworks)
paths.concat vendored_framework_search_paths
return paths unless target.requires_frameworks? && target.should_build?
paths + [target.configuration_build_dir(CONFIGURATION_BUILD_DIR_VARIABLE)]
end
# @return [Array<String>]
define_build_settings_method :vendored_static_frameworks, :memoized => true do
file_accessors.flat_map(&:vendored_static_frameworks)
end
# @return [Array<String>]
define_build_settings_method :vendored_dynamic_frameworks, :memoized => true do
file_accessors.flat_map(&:vendored_dynamic_frameworks)
end
#-------------------------------------------------------------------------#
# @!group Libraries
# @return [Array<String>]
define_build_settings_method :libraries, :memoized => true, :sorted => true, :uniqued => true do
return [] if (!target.requires_frameworks? || target.static_framework?) && !test_xcconfig?
libraries = vendored_dynamic_libraries.map { |l| File.basename(l, l.extname).sub(/\Alib/, '') }
libraries.concat spec_consumers.flat_map(&:libraries)
libraries.concat dependent_targets.flat_map { |pt| pt.build_settings.dynamic_libraries_to_import }
libraries.concat dependent_targets.flat_map { |pt| pt.build_settings.static_libraries_to_import } if test_xcconfig?
libraries
end
# @return [Array<String>]
define_build_settings_method :static_libraries_to_import, :memoized => true do
static_libraries_to_import = vendored_static_libraries.map { |l| File.basename(l, l.extname).sub(/\Alib/, '') }
static_libraries_to_import << target.product_basename if target.should_build? && !target.requires_frameworks?
static_libraries_to_import
end
# @return [Array<String>]
define_build_settings_method :dynamic_libraries_to_import, :memoized => true do
vendored_dynamic_libraries.map { |l| File.basename(l, l.extname).sub(/\Alib/, '') } +
spec_consumers.flat_map(&:libraries)
end
# @return [Array<String>]
define_build_settings_method :libraries_to_import, :memoized => true, :sorted => true, :uniqued => true do
static_libraries_to_import + dynamic_libraries_to_import
end
# @return [Array<String>]
define_build_settings_method :library_search_paths, :build_setting => true, :memoized => true, :sorted => true, :uniqued => true do
vendored = vendored_dynamic_library_search_paths.dup
vendored.concat dependent_targets.flat_map { |t| t.build_settings.vendored_dynamic_library_search_paths }
if test_xcconfig?
vendored.concat dependent_targets.flat_map { |t| t.build_settings.library_search_paths_to_import }
else
vendored.delete(target.configuration_build_dir(CONFIGURATION_BUILD_DIR_VARIABLE))
end
vendored
end
# @return [Array<String>]
define_build_settings_method :vendored_static_libraries, :memoized => true do
file_accessors.flat_map(&:vendored_static_libraries)
end
# @return [Array<String>]
define_build_settings_method :vendored_dynamic_libraries, :memoized => true do
file_accessors.flat_map(&:vendored_dynamic_libraries)
end
# @return [Array<String>]
define_build_settings_method :vendored_static_library_search_paths, :memoized => true do
vendored_static_libraries.map { |f| File.join '${PODS_ROOT}', f.dirname.relative_path_from(target.sandbox.root) }
end
# @return [Array<String>]
define_build_settings_method :vendored_dynamic_library_search_paths, :memoized => true do
vendored_dynamic_libraries.map { |f| File.join '${PODS_ROOT}', f.dirname.relative_path_from(target.sandbox.root) }
end
# @return [Array<String>]
define_build_settings_method :library_search_paths_to_import, :memoized => true do
vendored_library_search_paths = vendored_static_library_search_paths + vendored_dynamic_library_search_paths
return vendored_library_search_paths if target.requires_frameworks? || !target.should_build?
vendored_library_search_paths << target.configuration_build_dir(CONFIGURATION_BUILD_DIR_VARIABLE)
end
#-------------------------------------------------------------------------#
# @!group Clang
# @return [Array<String>]
define_build_settings_method :module_map_files, :memoized => true do
dependent_targets.map { |t| t.build_settings.module_map_file_to_import }.compact.sort
end
# @return [Array<String>]
define_build_settings_method :module_map_file_to_import, :memoized => true do
return unless target.should_build?
return if target.requires_frameworks?
return unless target.defines_module?
if target.uses_swift?
# for swift, we have a custom build phase that copies in the module map, appending the .Swift module
"${PODS_CONFIGURATION_BUILD_DIR}/#{target.label}/#{target.product_module_name}.modulemap"
else
"${PODS_ROOT}/#{target.module_map_path.relative_path_from(target.sandbox.root)}"
end
end
# @return [Array<String>]
define_build_settings_method :header_search_paths, :build_setting => true, :memoized => true, :sorted => true do
target.header_search_paths(test_xcconfig?)
end
#-------------------------------------------------------------------------#
# @!group Swift
# @return [Array<String>]
define_build_settings_method :other_swift_flags, :build_setting => true, :memoized => true do
return unless target.uses_swift?
flags = super()
flags << '-suppress-warnings' if target.inhibit_warnings?
if !target.requires_frameworks? && target.defines_module? && !test_xcconfig?
flags.concat %w( -import-underlying-module -Xcc -fmodule-map-file=${SRCROOT}/${MODULEMAP_FILE} )
end
flags
end
# @return [Array<String>]
define_build_settings_method :swift_include_paths, :build_setting => true, :memoized => true, :sorted => true, :uniqued => true do
paths = dependent_targets.flat_map { |t| t.build_settings.swift_include_paths_to_import }
paths.concat swift_include_paths_to_import if test_xcconfig?
paths
end
# @return [Array<String>]
define_build_settings_method :swift_include_paths_to_import, :memoized => true do
return [] unless target.uses_swift? && !target.requires_frameworks?
[target.configuration_build_dir(CONFIGURATION_BUILD_DIR_VARIABLE)]
end
#-------------------------------------------------------------------------#
# @!group Linking
# @return [Boolean] whether the `-ObjC` linker flag is required.
#
# @note this is only true when generating build settings for a test bundle
#
def requires_objc_linker_flag?
test_xcconfig?
end
# @return [Boolean] whether the `-fobjc-arc` linker flag is required.
#
define_build_settings_method :requires_fobjc_arc?, :memoized => true do
target.podfile.set_arc_compatibility_flag? &&
file_accessors.any? { |fa| fa.spec_consumer.requires_arc? }
end
# @return [Array<String>]
define_build_settings_method :ld_runpath_search_paths, :build_setting => true, :memoized => true do
return unless test_xcconfig?
_ld_runpath_search_paths(:test_bundle => true)
end
#-------------------------------------------------------------------------#
# @!group Packaging
# @return [String]
define_build_settings_method :skip_install, :build_setting => true do
'YES'
end
# @return [String]
define_build_settings_method :product_bundle_identifier, :build_setting => true do
'org.cocoapods.${PRODUCT_NAME:rfc1034identifier}'
end
# @return [String]
define_build_settings_method :configuration_build_dir, :build_setting => true, :memoized => true do
return if test_xcconfig?
target.configuration_build_dir(CONFIGURATION_BUILD_DIR_VARIABLE)
end
#-------------------------------------------------------------------------#
# @!group Target Properties
# @return [Array<PodTarget>]
define_build_settings_method :dependent_targets, :memoized => true do
select_maximal_pod_targets(
if test_xcconfig?
target.all_dependent_targets
else
target.recursive_dependent_targets
end,
)
end
# @return [Hash<String => String>]
define_build_settings_method :pod_target_xcconfig, :memoized => true do
config = {}
spec_consumers.each do |consumer|
config.update(consumer.pod_target_xcconfig) # TODO: resolve conflicts
end
config
end
# Returns the +pod_target_xcconfig+ for the pod target and its spec
# consumers grouped by keys
#
# @return [Hash{String,Hash{Target,String}]
#
def pod_target_xcconfig_values_by_consumer_by_key
spec_consumers.each_with_object({}) do |spec_consumer, hash|
spec_consumer.user_target_xcconfig.each do |k, v|
(hash[k] ||= {})[spec_consumer] = v
end
end
end
# Merges the +pod_target_xcconfig+ for all pod targets into a
# single hash and warns on conflicting definitions.
#
# @return [Hash{String, String}]
#
define_build_settings_method :merged_pod_target_xcconfigs, :memoized => true do
merged_xcconfigs(pod_target_xcconfig_values_by_consumer_by_key, :pod_target_xcconfig)
end
# @return [Array<Sandbox::FileAccessor>]
define_build_settings_method :file_accessors, :memoized => true do
target.file_accessors.select { |fa| fa.spec.test_specification? == test_xcconfig? }
end
# @return [Array<Specification::Consumer>]
define_build_settings_method :spec_consumers, :memoized => true do
target.spec_consumers.select { |c| c.spec.test_specification? == test_xcconfig? }
end
#-------------------------------------------------------------------------#
# @!group Private Methods
def __clear__
super
dependent_targets.each { |pt| pt.build_settings.__clear__ }
end
end
# A subclass that generates build settings for a `PodTarget`
class AggregateTargetSettings < BuildSettings
#-------------------------------------------------------------------------#
# @!group Public API
# @see BuildSettings.build_settings_names
def self.build_settings_names
@build_settings_names | BuildSettings.build_settings_names
end
# @return [String]
# The build configuration these settings will be used for
attr_reader :configuration_name
# Intializes a new instance
#
# @param [AggregateTarget] target
# see {#target}
#
# @param [String] configuration_name
# see {#configuration_name}
#
def initialize(target, configuration_name)
super(target)
@configuration_name = configuration_name
end
# @return [Xcodeproj::Config] xcconfig
define_build_settings_method :xcconfig, :memoized => true do
xcconfig = super()
xcconfig.merge(merged_user_target_xcconfigs)
end
#-------------------------------------------------------------------------#
# @!group Paths
# @return [String]
define_build_settings_method :pods_podfile_dir_path, :build_setting => true, :memoized => true do
target.podfile_dir_relative_path
end
# @return [String]
define_build_settings_method :pods_root, :build_setting => true, :memoized => true do
target.relative_pods_root
end
#-------------------------------------------------------------------------#
# @!group Frameworks
# @return [Array<String>]
define_build_settings_method :frameworks, :memoized => true, :sorted => true, :uniqued => true, :from_pod_targets_to_link => true, :from_search_paths_aggregate_targets => :dynamic_frameworks_to_import do
[]
end
# @return [Array<String>]
define_build_settings_method :weak_frameworks, :memoized => true, :sorted => true, :uniqued => true, :from_pod_targets_to_link => true, :from_search_paths_aggregate_targets => :weak_frameworks do
[]
end
# @return [Array<String>]
define_build_settings_method :framework_search_paths, :build_setting => true, :memoized => true, :sorted => true, :uniqued => true, :from_pod_targets_to_link => true, :from_search_paths_aggregate_targets => :framework_search_paths_to_import do
[]
end
#-------------------------------------------------------------------------#
# @!group Libraries
# @return [Array<String>]
define_build_settings_method :libraries, :memoized => true, :sorted => true, :uniqued => true, :from_pod_targets_to_link => true, :from_search_paths_aggregate_targets => :dynamic_libraries_to_import do
[]
end
# @return [Array<String>]
define_build_settings_method :library_search_paths, :build_setting => true, :memoized => true, :sorted => true, :uniqued => true, :from_pod_targets_to_link => true, :from_search_paths_aggregate_targets => :vendored_dynamic_library_search_paths do
[]
end
#-------------------------------------------------------------------------#
# @!group Clang
# @return [Array<String>]
define_build_settings_method :header_search_paths, :build_setting => true, :memoized => true, :sorted => true, :uniqued => true do
paths = []
if !target.requires_frameworks? || !pod_targets.all?(&:should_build?)
paths.concat target.sandbox.public_headers.search_paths(target.platform)
end
paths.concat target.search_paths_aggregate_targets.flat_map { |at| at.build_settings(configuration_name).header_search_paths }
paths
end
# @return [Array<String>]
define_build_settings_method :other_cflags, :build_setting => true, :memoized => true do
flags = super()
flags +
header_search_paths.flat_map { |p| ['-isystem', p] } +
framework_header_paths_for_iquote.flat_map { |p| ['-iquote', p] }
end
# @return [Array<String>]
define_build_settings_method :framework_header_paths_for_iquote, :memoized => true, :sorted => true, :uniqued => true do
paths = pod_targets.
select { |pt| pt.should_build? && pt.requires_frameworks? }.
map { |pt| "#{pt.build_product_path}/Headers" }
paths.concat target.search_paths_aggregate_targets.flat_map { |at| at.build_settings(configuration_name).framework_header_paths_for_iquote }
paths
end
# @return [Array<String>]
define_build_settings_method :module_map_files, :memoized => true, :sorted => true, :uniqued => true, :compacted => true, :from_search_paths_aggregate_targets => :module_map_file_to_import do
pod_targets.map { |t| t.build_settings.module_map_file_to_import }
end
#-------------------------------------------------------------------------#
# @!group Swift
# @see BuildSettings#other_swift_flags_without_swift?
def other_swift_flags_without_swift?
module_map_files.any?
end
# @return [Array<String>]
define_build_settings_method :swift_include_paths, :build_setting => true, :memoized => true, :sorted => true, :uniqued => true, :from_pod_targets_to_link => true, :from_search_paths_aggregate_targets => :swift_include_paths_to_import do
[]
end
# @return [String]
define_build_settings_method :always_embed_swift_standard_libraries, :build_setting => true, :memoized => true do
return unless must_embed_swift?
return if target_swift_version < EMBED_STANDARD_LIBRARIES_MINIMUM_VERSION
'YES'
end
# @return [String]
define_build_settings_method :embedded_content_contains_swift, :build_setting => true, :memoized => true do
return unless must_embed_swift?
return if target_swift_version >= EMBED_STANDARD_LIBRARIES_MINIMUM_VERSION
'YES'
end
# @return [Boolean]
define_build_settings_method :must_embed_swift?, :memoized => true do
!target.requires_host_target? && pod_targets.any?(&:uses_swift?)
end
#-------------------------------------------------------------------------#
# @!group Linking
# @return [Array<String>]
define_build_settings_method :ld_runpath_search_paths, :build_setting => true, :memoized => true, :uniqued => true do
return unless target.requires_frameworks? || any_vendored_dynamic_artifacts?
symbol_type = target.user_targets.map(&:symbol_type).uniq.first
test_bundle = symbol_type == :octest_bundle || symbol_type == :unit_test_bundle || symbol_type == :ui_test_bundle
_ld_runpath_search_paths(:requires_host_target => target.requires_host_target?, :test_bundle => test_bundle)
end
# @return [Boolean]
define_build_settings_method :any_vendored_dynamic_artifacts?, :memoized => true do
pod_targets.any? do |pt|
pt.file_accessors.any? do |fa|
fa.vendored_dynamic_artifacts.any?
end
end
end
# @return [Boolean]
define_build_settings_method :requires_objc_linker_flag?, :memoized => true do
includes_static_libs = !target.requires_frameworks?
includes_static_libs || pod_targets.flat_map(&:file_accessors).any? { |fa| !fa.vendored_static_artifacts.empty? }
end
# @return [Boolean]
define_build_settings_method :requires_fobjc_arc?, :memoized => true do
target.podfile.set_arc_compatibility_flag? &&
target.spec_consumers.any?(&:requires_arc?)
end
#-------------------------------------------------------------------------#
# @!group Target Properties
# @return [Version] the SWIFT_VERSION of the target being integrated
#
define_build_settings_method :target_swift_version, :memoized => true, :frozen => false do
swift_version = target.target_definition.swift_version
swift_version = nil if swift_version.blank?
Version.new(swift_version)
end
EMBED_STANDARD_LIBRARIES_MINIMUM_VERSION = Version.new('2.3')
private_constant :EMBED_STANDARD_LIBRARIES_MINIMUM_VERSION
# Returns the {PodTarget}s which are active for the current
# configuration name.
#
# @return [Array<PodTarget>]
#
define_build_settings_method :pod_targets, :memoized => true do
target.pod_targets_for_build_configuration(configuration_name)
end
# @return [Array<PodTarget>]
define_build_settings_method :pod_targets_to_link, :memoized => true do
pod_targets -
target.search_paths_aggregate_targets.flat_map { |at| at.build_settings(configuration_name).pod_targets_to_link }
end
# @return [Array<PodTarget>]
define_build_settings_method :search_paths_aggregate_target_pod_target_build_settings, :memoized => true, :uniqued => true do
pod_targets = target.search_paths_aggregate_targets.flat_map { |at| at.build_settings(configuration_name).pod_targets }
pod_targets = select_maximal_pod_targets(pod_targets)
pod_targets.flat_map(&:build_settings)
end
# Returns the +user_target_xcconfig+ for all pod targets and their spec
# consumers grouped by keys
#
# @return [Hash{String,Hash{Target,String}]
#
def user_target_xcconfig_values_by_consumer_by_key
pod_targets.each_with_object({}) do |target, hash|
target.spec_consumers.each do |spec_consumer|
spec_consumer.user_target_xcconfig.each do |k, v|
(hash[k] ||= {})[spec_consumer] = v
end
end
end
end
# Merges the +user_target_xcconfig+ for all pod targets into a
# single hash and warns on conflicting definitions.
#
# @return [Hash{String, String}]
#
define_build_settings_method :merged_user_target_xcconfigs, :memoized => true do
merged_xcconfigs(user_target_xcconfig_values_by_consumer_by_key, :user_target_xcconfig)
end
#-------------------------------------------------------------------------#
# @!group Private Methods
def __clear__
super
pod_targets.each { |pt| pt.build_settings.__clear__ }
target.search_paths_aggregate_targets.each { |at| at.build_settings(configuration_name).__clear__ }
end
end
end
end
end
...@@ -275,7 +275,7 @@ module Pod ...@@ -275,7 +275,7 @@ module Pod
accessor.resources.flat_map { |res| "${PODS_ROOT}/#{res.relative_path_from(sandbox.project.path.dirname)}" } accessor.resources.flat_map { |res| "${PODS_ROOT}/#{res.relative_path_from(sandbox.project.path.dirname)}" }
end end
resource_bundles = accessors.flat_map do |accessor| resource_bundles = accessors.flat_map do |accessor|
prefix = Generator::XCConfig::XCConfigHelper::CONFIGURATION_BUILD_DIR_VARIABLE prefix = BuildSettings::CONFIGURATION_BUILD_DIR_VARIABLE
prefix = configuration_build_dir unless accessor.spec.test_specification? prefix = configuration_build_dir unless accessor.spec.test_specification?
accessor.resource_bundles.keys.map { |name| "#{prefix}/#{name.shellescape}.bundle" } accessor.resource_bundles.keys.map { |name| "#{prefix}/#{name.shellescape}.bundle" }
end end
...@@ -535,7 +535,7 @@ module Pod ...@@ -535,7 +535,7 @@ module Pod
# #
# @return [String] The absolute path to the configuration build dir # @return [String] The absolute path to the configuration build dir
# #
def configuration_build_dir(dir = Generator::XCConfig::XCConfigHelper::CONFIGURATION_BUILD_DIR_VARIABLE) def configuration_build_dir(dir = BuildSettings::CONFIGURATION_BUILD_DIR_VARIABLE)
"#{dir}/#{label}" "#{dir}/#{label}"
end end
...@@ -544,7 +544,7 @@ module Pod ...@@ -544,7 +544,7 @@ module Pod
# #
# @return [String] The absolute path to the build product # @return [String] The absolute path to the build product
# #
def build_product_path(dir = Generator::XCConfig::XCConfigHelper::CONFIGURATION_BUILD_DIR_VARIABLE) def build_product_path(dir = BuildSettings::CONFIGURATION_BUILD_DIR_VARIABLE)
"#{configuration_build_dir(dir)}/#{product_name}" "#{configuration_build_dir(dir)}/#{product_name}"
end end
...@@ -610,5 +610,9 @@ module Pod ...@@ -610,5 +610,9 @@ module Pod
Specification.root_name(dependency.name) == pod_name Specification.root_name(dependency.name) == pod_name
end end
end end
def create_build_settings
BuildSettings::PodTargetSettings.new(self, false)
end
end end
end end
Subproject commit f85066239cc102e9386b2417e7638512d2b696eb Subproject commit 2faa5dd550afc3158b119ebc1fe90eea5fa15825
...@@ -146,7 +146,7 @@ def fixture_pod_target_with_specs(specs, host_requires_frameworks = false, user_ ...@@ -146,7 +146,7 @@ def fixture_pod_target_with_specs(specs, host_requires_frameworks = false, user_
target_definitions, file_accessors, scope_suffix) target_definitions, file_accessors, scope_suffix)
end end
def fixture_aggregate_target(pod_targets = [], host_requires_frameworks = false, user_build_configurations = {}, def fixture_aggregate_target(pod_targets = [], host_requires_frameworks = false, user_build_configurations = Pod::Target::DEFAULT_BUILD_CONFIGURATIONS,
archs = [], platform = Pod::Platform.new(:ios, '6.0'), target_definition = nil) archs = [], platform = Pod::Platform.new(:ios, '6.0'), target_definition = nil)
target_definition ||= pod_targets.flat_map(&:target_definitions).first || fixture_target_definition target_definition ||= pod_targets.flat_map(&:target_definitions).first || fixture_target_definition
Pod::AggregateTarget.new(config.sandbox, host_requires_frameworks, user_build_configurations, archs, platform, Pod::AggregateTarget.new(config.sandbox, host_requires_frameworks, user_build_configurations, archs, platform,
......
require File.expand_path('../../../../spec_helper', __FILE__)
module Pod
module Generator
module XCConfig
describe XCConfigHelper do
before do
@sut = XCConfigHelper
end
#---------------------------------------------------------------------#
describe '::default_ld_flags' do
it 'returns the default linker flags' do
podfile = stub('podfile', :set_arc_compatibility_flag? => false)
target = stub('target', :podfile => podfile)
result = @sut.default_ld_flags(target)
result.should == ''
result = @sut.default_ld_flags(target, true)
result.should == '-ObjC'
end
it 'includes the ARC compatibility flag if required by the Podfile' do
podfile = stub('podfile', :set_arc_compatibility_flag? => true)
spec_consumer = stub('spec_consumer', :requires_arc? => true)
target = stub('target', :podfile => podfile, :spec_consumers => [spec_consumer])
result = @sut.default_ld_flags(target)
result.should == '-fobjc-arc'
result = @sut.default_ld_flags(target, true)
result.should == '-ObjC -fobjc-arc'
end
end
#---------------------------------------------------------------------#
describe '::quote' do
it 'quotes strings' do
result = @sut.quote(%w(string1 string2))
result.should == '"string1" "string2"'
end
it 'inserts an optional string and then the normal quoted string' do
result = @sut.quote(%w(string1 string2), '-isystem')
result.should == '-isystem "string1" -isystem "string2"'
end
end
#---------------------------------------------------------------------#
describe '::add_spec_build_settings_to_xcconfig' do
it 'adds the libraries of the xcconfig' do
xcconfig = Xcodeproj::Config.new
consumer = stub('consumer',
:pod_target_xcconfig => {},
:libraries => ['xml2'],
:frameworks => [],
:weak_frameworks => [],
:platform_name => :ios,
)
@sut.add_spec_build_settings_to_xcconfig(consumer, xcconfig)
xcconfig.to_hash['OTHER_LDFLAGS'].should == '-l"xml2"'
end
it 'check that subspec subsets are removed from frameworks search paths' do
target1 = stub('target1',
:specs => %w(A, B),
:should_build? => true,
:requires_frameworks? => true,
:configuration_build_dir => 'AB',
:uses_swift? => false,
)
target2 = stub('target2',
:specs => ['B'],
:should_build? => true,
:requires_frameworks? => true,
:configuration_build_dir => 'B',
:uses_swift? => false,
)
dependent_targets = [target1, target2]
build_settings = @sut.search_paths_for_dependent_targets(nil, dependent_targets)
build_settings['FRAMEWORK_SEARCH_PATHS'].should == '"AB"'
end
it 'adds the frameworks search paths once if there are duplicated targets' do
target = stub(
:specs => %w(A, B),
:should_build? => true,
:requires_frameworks? => true,
:configuration_build_dir => 'AB',
)
dependent_targets = [target, target]
build_settings = @sut.search_paths_for_dependent_targets(nil, dependent_targets)
build_settings['FRAMEWORK_SEARCH_PATHS'].should == '"AB"'
end
it 'adds the libraries of the xcconfig for a static framework' do
spec = stub('spec', :test_specification? => false)
target_definition = stub('target_definition', :inheritance => 'search_paths')
consumer = stub('consumer',
:pod_target_xcconfig => {},
:libraries => ['xml2'],
:frameworks => [],
:weak_frameworks => [],
:platform_name => :ios,
)
file_accessor = stub('file_accessor',
:spec => spec,
:spec_consumer => consumer,
:vendored_static_frameworks => [],
:vendored_dynamic_frameworks => [],
:vendored_static_libraries => [],
:vendored_dynamic_libraries => [],
)
pod_target = stub('pod_target',
:name => 'BananaLib',
:sandbox => config.sandbox,
:should_build? => true,
:requires_frameworks? => true,
:static_framework? => true,
:dependent_targets => [],
:file_accessors => [file_accessor],
)
pod_targets = [pod_target]
aggregate_target = stub('aggregate_target',
:target_definition => target_definition,
:pod_targets => pod_targets,
:search_paths_aggregate_targets => [],
:pod_targets_to_link => pod_targets,
)
xcconfig = Xcodeproj::Config.new
@sut.generate_vendored_build_settings(aggregate_target, pod_targets, xcconfig)
xcconfig.to_hash['OTHER_LDFLAGS'].should == '-l"xml2"'
end
it 'checks OTHER_LDFLAGS and FRAMEWORK_SEARCH_PATHS for a vendored dependencies to a static framework' do
spec = stub('spec', :test_specification? => false)
target_definition = stub('target_definition', :inheritance => 'search_paths')
consumer = stub('consumer',
:pod_target_xcconfig => {},
:libraries => ['xml2'],
:frameworks => [],
:weak_frameworks => [],
:platform_name => :ios,
)
file_accessor = stub('file_accessor',
:spec => spec,
:spec_consumer => consumer,
:vendored_static_frameworks => [config.sandbox.root + 'StaticFramework.framework'],
:vendored_static_libraries => [config.sandbox.root + 'StaticLibrary.a'],
:vendored_dynamic_frameworks => [config.sandbox.root + 'VendoredFramework.framework'],
:vendored_dynamic_libraries => [config.sandbox.root + 'VendoredDyld.dyld'],
)
dep_target = stub('dep_target',
:name => 'BananaLib',
:sandbox => config.sandbox,
:should_build? => false,
:requires_frameworks? => true,
:static_framework? => false,
:dependent_targets => [],
:file_accessors => [file_accessor],
)
dep_targets = [dep_target]
target = stub('target',
:target_definition => target_definition,
:pod_targets => dep_targets,
:search_paths_aggregate_targets => [],
:static_framework => true,
:pod_targets_to_link => dep_targets,
)
xcconfig = Xcodeproj::Config.new
@sut.generate_vendored_build_settings(target, dep_targets, xcconfig, true)
xcconfig.to_hash['OTHER_LDFLAGS'].should == '-l"StaticLibrary" -l"VendoredDyld" -l"xml2" -framework "StaticFramework" -framework "VendoredFramework"'
xcconfig.to_hash['FRAMEWORK_SEARCH_PATHS'].should == '"${PODS_ROOT}/."'
end
it 'quotes OTHER_LDFLAGS to properly handle spaces' do
framework_path = config.sandbox.root + 'Sample/Framework with Spaces.framework'
library_path = config.sandbox.root + 'Sample/libSample Lib.a'
xcconfig = Xcodeproj::Config.new
@sut.add_framework_build_settings(framework_path, xcconfig, config.sandbox.root)
@sut.add_library_build_settings(library_path, xcconfig, config.sandbox.root)
hash_config = xcconfig.to_hash
hash_config['OTHER_LDFLAGS'].should == '-l"Sample Lib" -framework "Framework with Spaces"'
end
it 'check that include_ld_flags being false doesnt generate OTHER_LDFLAGS' do
spec = stub('spec', :test_specification? => false)
target_definition = stub('target_definition', :inheritance => 'search_paths')
consumer = stub('consumer',
:pod_target_xcconfig => {},
:libraries => ['xml2'],
:frameworks => [],
:weak_frameworks => [],
:platform_name => :ios,
)
file_accessor = stub('file_accessor',
:spec => spec,
:spec_consumer => consumer,
:vendored_static_frameworks => [config.sandbox.root + 'StaticFramework.framework'],
:vendored_static_libraries => [config.sandbox.root + 'StaticLibrary.a'],
:vendored_dynamic_frameworks => [config.sandbox.root + 'VendoredFramework.framework'],
:vendored_dynamic_libraries => [config.sandbox.root + 'VendoredDyld.dyld'],
)
dep_target = stub('dep_target',
:name => 'BananaLib',
:sandbox => config.sandbox,
:should_build? => false,
:requires_frameworks? => true,
:static_framework? => false,
:dependent_targets => [],
:file_accessors => [file_accessor],
)
dep_targets = [dep_target]
target = stub('target',
:target_definition => target_definition,
:pod_targets => dep_targets,
:search_paths_aggregate_targets => [],
)
xcconfig = Xcodeproj::Config.new
@sut.generate_vendored_build_settings(target, dep_targets, xcconfig, false)
xcconfig.to_hash['OTHER_LDFLAGS'].should.nil?
xcconfig.to_hash['FRAMEWORK_SEARCH_PATHS'].should == '"${PODS_ROOT}/."'
end
it 'makes sure setting from search_paths get propagated for static frameworks' do
target_definition = stub('target_definition', :inheritance => 'search_paths')
consumer = stub('consumer',
:pod_target_xcconfig => {},
:libraries => ['xml2'],
:frameworks => ['Foo'],
:weak_frameworks => [],
:platform_name => :ios,
)
file_accessor = stub('file_accessor',
:spec_consumer => consumer,
:vendored_static_frameworks => [],
:vendored_dynamic_frameworks => [],
:vendored_static_libraries => [],
:vendored_dynamic_libraries => [],
)
pod_target = stub('pod_target',
:name => 'BananaLib',
:sandbox => config.sandbox,
:should_build? => true,
:requires_frameworks? => true,
:static_framework? => true,
:dependent_targets => [],
:file_accessors => [file_accessor],
:product_basename => 'Foo',
)
pod_targets = [pod_target]
aggregate_target = stub('aggregate_target',
:target_definition => target_definition,
:pod_targets => pod_targets,
:search_paths_aggregate_targets => [],
)
test_aggregate_target = stub('test_aggregate_target',
:target_definition => target_definition,
:pod_targets => [],
:search_paths_aggregate_targets => [aggregate_target],
:requires_frameworks? => true,
)
xcconfig = Xcodeproj::Config.new
@sut.generate_other_ld_flags(test_aggregate_target, [], xcconfig)
xcconfig.to_hash['OTHER_LDFLAGS'].should == '-framework "Foo"'
end
it 'makes sure setting from search_paths dont propagate for static frameworks when static linking' do
target_definition = stub('target_definition', :inheritance => 'search_paths')
consumer = stub('consumer',
:pod_target_xcconfig => {},
:libraries => ['xml2'],
:frameworks => ['Foo'],
:weak_frameworks => [],
:platform_name => :ios,
)
file_accessor = stub('file_accessor',
:spec_consumer => consumer,
:vendored_static_frameworks => [],
:vendored_dynamic_frameworks => [],
:vendored_static_libraries => [],
:vendored_dynamic_libraries => [],
)
pod_target = stub('pod_target',
:name => 'BananaLib',
:sandbox => config.sandbox,
:should_build? => true,
:requires_frameworks? => false,
:static_framework? => true,
:dependent_targets => [],
:file_accessors => [file_accessor],
:product_basename => 'Foo',
)
pod_targets = [pod_target]
aggregate_target = stub('aggregate_target',
:target_definition => target_definition,
:pod_targets => pod_targets,
:search_paths_aggregate_targets => [],
)
test_aggregate_target = stub('test_aggregate_target',
:target_definition => target_definition,
:pod_targets => [],
:search_paths_aggregate_targets => [aggregate_target],
:requires_frameworks? => false,
)
xcconfig = Xcodeproj::Config.new
@sut.generate_other_ld_flags(test_aggregate_target, [], xcconfig)
xcconfig.to_hash['OTHER_LDFLAGS'].should.be.nil
end
it 'includes HEADER_SEARCH_PATHS from search paths' do
xcconfig = Xcodeproj::Config.new
spec_consumer = stub('spec_consumer', :user_target_xcconfig => { 'HEADER_SEARCH_PATHS' => 'my/path' })
pod_target = stub('pod_target', :spec_consumers => [spec_consumer])
search_path_target = stub('search_path_target',
:pod_targets_for_build_configuration => [pod_target],
:pod_targets => [pod_target],
)
@sut.propagate_header_search_paths_from_search_paths(search_path_target, xcconfig)
xcconfig.to_hash['HEADER_SEARCH_PATHS'].should == '$(inherited) my/path'
end
it 'adds the frameworks of the xcconfig' do
xcconfig = Xcodeproj::Config.new
consumer = stub('consumer',
:pod_target_xcconfig => {},
:libraries => [],
:frameworks => ['CoreAnimation'],
:weak_frameworks => [],
:platform_name => :ios,
)
@sut.add_spec_build_settings_to_xcconfig(consumer, xcconfig)
xcconfig.to_hash['OTHER_LDFLAGS'].should == '-framework "CoreAnimation"'
end
it 'adds the weak frameworks of the xcconfig' do
xcconfig = Xcodeproj::Config.new
consumer = stub('consumer',
:pod_target_xcconfig => {},
:libraries => [],
:frameworks => [],
:weak_frameworks => ['iAd'],
:platform_name => :ios,
)
@sut.add_spec_build_settings_to_xcconfig(consumer, xcconfig)
xcconfig.to_hash['OTHER_LDFLAGS'].should == '-weak_framework "iAd"'
end
it 'adds the ios developer frameworks search paths if needed' do
xcconfig = Xcodeproj::Config.new
consumer = stub('consumer',
:pod_target_xcconfig => {},
:libraries => [],
:frameworks => ['SenTestingKit'],
:weak_frameworks => [],
:platform_name => :ios,
)
@sut.add_spec_build_settings_to_xcconfig(consumer, xcconfig)
xcconfig.to_hash['FRAMEWORK_SEARCH_PATHS'].should.not.include('SDKROOT')
xcconfig.to_hash['FRAMEWORK_SEARCH_PATHS'].should.not.include('DEVELOPER_LIBRARY_DIR')
end
it 'adds the osx developer frameworks search paths if needed' do
xcconfig = Xcodeproj::Config.new
consumer = stub('consumer',
:pod_target_xcconfig => {},
:libraries => [],
:frameworks => ['SenTestingKit'],
:weak_frameworks => [],
:platform_name => :osx,
)
@sut.add_spec_build_settings_to_xcconfig(consumer, xcconfig)
xcconfig.to_hash['FRAMEWORK_SEARCH_PATHS'].should.not.include('DEVELOPER_LIBRARY_DIR')
xcconfig.to_hash['FRAMEWORK_SEARCH_PATHS'].should.not.include('SDKROOT')
end
end
#---------------------------------------------------------------------#
describe '::add_framework_build_settings' do
it 'adds the build settings of a framework to the given xcconfig' do
framework_path = config.sandbox.root + 'Parse/Parse.framework'
xcconfig = Xcodeproj::Config.new
@sut.add_framework_build_settings(framework_path, xcconfig, config.sandbox.root)
hash_config = xcconfig.to_hash
hash_config['OTHER_LDFLAGS'].should == '-framework "Parse"'
hash_config['FRAMEWORK_SEARCH_PATHS'].should == '"${PODS_ROOT}/Parse"'
end
it "doesn't override existing linker flags" do
framework_path = config.sandbox.root + 'Parse/Parse.framework'
xcconfig = Xcodeproj::Config.new('OTHER_LDFLAGS' => '-framework CoreAnimation')
@sut.add_framework_build_settings(framework_path, xcconfig, config.sandbox.root)
hash_config = xcconfig.to_hash
hash_config['OTHER_LDFLAGS'].should == '-framework "CoreAnimation" -framework "Parse"'
end
it "doesn't override existing frameworks search paths" do
framework_path = config.sandbox.root + 'Parse/Parse.framework'
xcconfig = Xcodeproj::Config.new('FRAMEWORK_SEARCH_PATHS' => '"path/to/frameworks"')
@sut.add_framework_build_settings(framework_path, xcconfig, config.sandbox.root)
hash_config = xcconfig.to_hash
hash_config['FRAMEWORK_SEARCH_PATHS'].should == '"path/to/frameworks" "${PODS_ROOT}/Parse"'
end
end
#---------------------------------------------------------------------#
describe '::add_library_build_settings' do
it 'adds the build settings of a framework to the given xcconfig' do
path = config.sandbox.root + 'MapBox/Proj4/libProj4.a'
xcconfig = Xcodeproj::Config.new
@sut.add_library_build_settings(path, xcconfig, config.sandbox.root)
hash_config = xcconfig.to_hash
hash_config['OTHER_LDFLAGS'].should == '-l"Proj4"'
hash_config['LIBRARY_SEARCH_PATHS'].should == '"${PODS_ROOT}/MapBox/Proj4"'
end
it 'adds dylib build settings to the given xcconfig' do
path = config.sandbox.root + 'MapBox/Proj4/libProj4.dylib'
xcconfig = Xcodeproj::Config.new
@sut.add_library_build_settings(path, xcconfig, config.sandbox.root)
hash_config = xcconfig.to_hash
hash_config['OTHER_LDFLAGS'].should == '-l"Proj4"'
hash_config['LIBRARY_SEARCH_PATHS'].should == '"${PODS_ROOT}/MapBox/Proj4"'
end
end
#---------------------------------------------------------------------#
describe '::add_developers_frameworks_if_needed' do
it 'adds the developer frameworks search paths to the xcconfig if SenTestingKit has been detected' do
xcconfig = Xcodeproj::Config.new('OTHER_LDFLAGS' => '-framework SenTestingKit')
@sut.add_developers_frameworks_if_needed(xcconfig)
frameworks_search_paths = xcconfig.to_hash['FRAMEWORK_SEARCH_PATHS']
frameworks_search_paths.should.include?('$(inherited)')
frameworks_search_paths.should.not.include?('"$(SDKROOT)/Developer/Library/Frameworks"')
frameworks_search_paths.should.not.include?('"$(DEVELOPER_LIBRARY_DIR)/Frameworks"')
end
it 'adds the developer frameworks search paths to the xcconfig if XCTest has been detected' do
xcconfig = Xcodeproj::Config.new('OTHER_LDFLAGS' => '-framework XCTest')
@sut.add_developers_frameworks_if_needed(xcconfig)
frameworks_search_paths = xcconfig.to_hash['FRAMEWORK_SEARCH_PATHS']
frameworks_search_paths.should.include?('$(inherited)')
frameworks_search_paths.should.not.include?('"$(SDKROOT)/Developer/Library/Frameworks"')
frameworks_path = '"$(PLATFORM_DIR)/Developer/Library/Frameworks"'
frameworks_search_paths.should.include?(frameworks_path)
frameworks_search_paths.should.not.include?('"$(DEVELOPER_LIBRARY_DIR)/Frameworks"')
end
end
#---------------------------------------------------------------------#
describe '::add_language_specific_settings' do
it 'does not add OTHER_SWIFT_FLAGS to the xcconfig if the target does not use swift' do
target = stub('target', :uses_swift? => false)
xcconfig = Xcodeproj::Config.new
@sut.add_language_specific_settings(target, xcconfig)
other_swift_flags = xcconfig.to_hash['OTHER_SWIFT_FLAGS']
other_swift_flags.should.nil?
end
it 'does not add the -suppress-warnings flag to the xcconfig if the target uses swift, but does not inhibit warnings' do
target = stub('target', :uses_swift? => true, :inhibit_warnings? => false)
xcconfig = Xcodeproj::Config.new
@sut.add_language_specific_settings(target, xcconfig)
other_swift_flags = xcconfig.to_hash['OTHER_SWIFT_FLAGS']
other_swift_flags.should.not.include?('-suppress-warnings')
end
it 'adds the -suppress-warnings flag to the xcconfig if the target uses swift and inhibits warnings' do
target = stub('target', :uses_swift? => true, :inhibit_warnings? => true)
xcconfig = Xcodeproj::Config.new
@sut.add_language_specific_settings(target, xcconfig)
other_swift_flags = xcconfig.to_hash['OTHER_SWIFT_FLAGS']
other_swift_flags.should.include?('-suppress-warnings')
end
end
#---------------------------------------------------------------------#
describe 'concerning settings for file accessors' do
it 'does not propagate framework or libraries from a test specification to an aggregate target' do
spec = stub('spec', :test_specification? => true)
consumer = stub('consumer',
:libraries => ['xml2'],
:frameworks => ['XCTest'],
:weak_frameworks => [],
:spec => spec,
)
file_accessor = stub('file_accessor',
:spec => spec,
:spec_consumer => consumer,
:vendored_static_frameworks => [config.sandbox.root + 'StaticFramework.framework'],
:vendored_static_libraries => [config.sandbox.root + 'StaticLibrary.a'],
:vendored_dynamic_frameworks => [config.sandbox.root + 'VendoredFramework.framework'],
:vendored_dynamic_libraries => [config.sandbox.root + 'VendoredDyld.dyld'],
)
pod_target = stub('pod_target',
:file_accessors => [file_accessor],
:requires_frameworks? => true,
:dependent_targets => [],
:sandbox => config.sandbox,
)
target_definition = stub('target_definition', :inheritance => 'complete')
aggregate_target = stub('aggregate_target', :target_definition => target_definition)
xcconfig = Xcodeproj::Config.new
@sut.add_settings_for_file_accessors_of_target(aggregate_target, pod_target, xcconfig)
xcconfig.to_hash['OTHER_LDFLAGS'].should.be.nil
end
it 'propagates correct frameworks or libraries to both test and non test xcconfigs' do
spec = stub('spec', :test_specification? => false)
consumer = stub('consumer',
:libraries => [],
:frameworks => [],
:weak_frameworks => [],
:spec => spec,
)
file_accessor = stub('file_accessor',
:spec => spec,
:spec_consumer => consumer,
:vendored_static_frameworks => [config.sandbox.root + 'StaticFramework.framework'],
:vendored_static_libraries => [config.sandbox.root + 'StaticLibrary.a'],
:vendored_dynamic_frameworks => [config.sandbox.root + 'VendoredFramework.framework'],
:vendored_dynamic_libraries => [config.sandbox.root + 'VendoredDyld.dyld'],
)
test_spec = stub('test_spec', :test_specification? => true)
test_consumer = stub('test_consumer',
:libraries => ['xml2'],
:frameworks => ['XCTest'],
:weak_frameworks => [],
:spec => test_spec,
)
test_file_accessor = stub('test_file_accessor',
:spec => test_spec,
:spec_consumer => test_consumer,
:vendored_static_frameworks => [],
:vendored_static_libraries => [],
:vendored_dynamic_frameworks => [],
:vendored_dynamic_libraries => [],
)
pod_target = stub('pod_target',
:file_accessors => [file_accessor, test_file_accessor],
:requires_frameworks? => true,
:dependent_targets => [],
:sandbox => config.sandbox,
)
xcconfig = Xcodeproj::Config.new
@sut.add_settings_for_file_accessors_of_target(nil, pod_target, xcconfig, true, false)
xcconfig.to_hash['OTHER_LDFLAGS'].should == '-l"StaticLibrary" -l"VendoredDyld" -framework "StaticFramework" -framework "VendoredFramework"'
test_xcconfig = Xcodeproj::Config.new
@sut.add_settings_for_file_accessors_of_target(nil, pod_target, test_xcconfig, true, true)
test_xcconfig.to_hash['OTHER_LDFLAGS'].should == '-l"StaticLibrary" -l"VendoredDyld" -l"xml2" -framework "StaticFramework" -framework "VendoredFramework" -framework "XCTest"'
end
it 'does propagate framework or libraries from a non test specification to an aggregate target' do
spec = stub('spec', :test_specification? => false)
consumer = stub('consumer',
:libraries => ['xml2'],
:frameworks => ['XCTest'],
:weak_frameworks => [],
:spec => spec,
)
file_accessor = stub('file_accessor',
:spec => spec,
:spec_consumer => consumer,
:vendored_static_frameworks => [config.sandbox.root + 'StaticFramework.framework'],
:vendored_static_libraries => [config.sandbox.root + 'StaticLibrary.a'],
:vendored_dynamic_frameworks => [config.sandbox.root + 'VendoredFramework.framework'],
:vendored_dynamic_libraries => [config.sandbox.root + 'VendoredDyld.dyld'],
)
pod_target = stub('pod_target',
:file_accessors => [file_accessor],
:requires_frameworks? => true,
:dependent_targets => [],
:sandbox => config.sandbox,
)
target_definition = stub('target_definition', :inheritance => 'complete')
aggregate_target = stub('aggregate_target', :target_definition => target_definition)
xcconfig = Xcodeproj::Config.new
@sut.add_settings_for_file_accessors_of_target(aggregate_target, pod_target, xcconfig)
xcconfig.to_hash['OTHER_LDFLAGS'].should.be == '-l"StaticLibrary" -l"VendoredDyld" -l"xml2" -framework "StaticFramework" -framework "VendoredFramework" -framework "XCTest"'
end
it 'does propagate framework or libraries to a nil aggregate target' do
spec = stub('spec', :test_specification? => false)
consumer = stub('consumer',
:libraries => ['xml2'],
:frameworks => ['XCTest'],
:weak_frameworks => [],
:spec => spec,
)
file_accessor = stub('file_accessor',
:spec => spec,
:spec_consumer => consumer,
:vendored_static_frameworks => [config.sandbox.root + 'StaticFramework.framework'],
:vendored_static_libraries => [config.sandbox.root + 'StaticLibrary.a'],
:vendored_dynamic_frameworks => [config.sandbox.root + 'VendoredFramework.framework'],
:vendored_dynamic_libraries => [config.sandbox.root + 'VendoredDyld.dyld'],
)
pod_target = stub('pod_target',
:file_accessors => [file_accessor],
:requires_frameworks? => true,
:dependent_targets => [],
:sandbox => config.sandbox,
)
xcconfig = Xcodeproj::Config.new
@sut.add_settings_for_file_accessors_of_target(nil, pod_target, xcconfig)
xcconfig.to_hash['OTHER_LDFLAGS'].should.be == '-l"StaticLibrary" -l"VendoredDyld" -l"xml2" -framework "StaticFramework" -framework "VendoredFramework" -framework "XCTest"'
end
end
describe 'for proper other ld flags' do
def stub_aggregate_target(pod_targets, target_definition = nil, search_paths_aggregate_targets: [])
target_definition.stubs(:abstract? => false) unless target_definition.respond_to?(:abstract?)
fixture_aggregate_target(pod_targets, false, {}, [], Platform.ios, target_definition).tap do |aggregate_target|
aggregate_target.search_paths_aggregate_targets.concat(search_paths_aggregate_targets).freeze
end
end
before do
@root = fixture('banana-lib')
@path_list = Sandbox::PathList.new(@root)
@spec = fixture_spec('banana-lib/BananaLib.podspec')
@spec_consumer = @spec.consumer(:ios)
@accessor = Pod::Sandbox::FileAccessor.new(@path_list, @spec_consumer)
end
it 'should not include static framework other ld flags when inheriting search paths' do
target_definition = stub('target_definition', :inheritance => 'search_paths')
aggregate_target = stub_aggregate_target([], target_definition)
pod_target = stub('pod_target', :sandbox => config.sandbox)
xcconfig = Xcodeproj::Config.new
@sut.add_static_dependency_build_settings(aggregate_target, pod_target, xcconfig, @accessor, true)
xcconfig.to_hash['LIBRARY_SEARCH_PATHS'].should == '"${PODS_ROOT}/../../spec/fixtures/banana-lib"'
xcconfig.to_hash['FRAMEWORK_SEARCH_PATHS'].should == '"${PODS_ROOT}/../../spec/fixtures/banana-lib"'
xcconfig.to_hash['OTHER_LDFLAGS'].should.be.nil
end
it 'should include static framework other ld flags when inheriting search paths but explicitly declared' do
target_definition = stub('target_definition', :inheritance => 'search_paths')
pod_target = stub('pod_target', :name => 'BananaLib', :sandbox => config.sandbox)
aggregate_target = stub_aggregate_target([pod_target], target_definition)
xcconfig = Xcodeproj::Config.new
@sut.add_static_dependency_build_settings(aggregate_target, pod_target, xcconfig, @accessor, true)
xcconfig.to_hash['LIBRARY_SEARCH_PATHS'].should == '"${PODS_ROOT}/../../spec/fixtures/banana-lib"'
xcconfig.to_hash['FRAMEWORK_SEARCH_PATHS'].should == '"${PODS_ROOT}/../../spec/fixtures/banana-lib"'
xcconfig.to_hash['OTHER_LDFLAGS'].should == '-l"Bananalib" -framework "Bananalib"'
end
it 'should include static framework other ld flags when not inheriting search paths' do
target_definition = stub('target_definition', :inheritance => 'complete')
aggregate_target = stub_aggregate_target([], target_definition)
pod_target = stub('pod_target', :sandbox => config.sandbox)
xcconfig = Xcodeproj::Config.new
@sut.add_static_dependency_build_settings(aggregate_target, pod_target, xcconfig, @accessor, true)
xcconfig.to_hash['LIBRARY_SEARCH_PATHS'].should == '"${PODS_ROOT}/../../spec/fixtures/banana-lib"'
xcconfig.to_hash['FRAMEWORK_SEARCH_PATHS'].should == '"${PODS_ROOT}/../../spec/fixtures/banana-lib"'
xcconfig.to_hash['OTHER_LDFLAGS'].should == '-l"Bananalib" -framework "Bananalib"'
end
it 'should include static framework for pod targets' do
pod_target = stub('pod_target', :sandbox => config.sandbox)
xcconfig = Xcodeproj::Config.new
@sut.add_static_dependency_build_settings(nil, pod_target, xcconfig, @accessor, true)
xcconfig.to_hash['LIBRARY_SEARCH_PATHS'].should == '"${PODS_ROOT}/../../spec/fixtures/banana-lib"'
xcconfig.to_hash['FRAMEWORK_SEARCH_PATHS'].should == '"${PODS_ROOT}/../../spec/fixtures/banana-lib"'
xcconfig.to_hash['OTHER_LDFLAGS'].should == '-l"Bananalib" -framework "Bananalib"'
end
it 'should link static dependency for pod targets' do
pod_target = stub('pod_target', :name => 'BananaLib', :sandbox => config.sandbox)
@sut.links_dependency?(nil, pod_target).should.be.true
end
it 'should link static dependency when target explicitly specifies it' do
target_definition = stub('target_definition', :inheritance => 'complete')
pod_target = stub('pod_target', :name => 'BananaLib', :sandbox => config.sandbox)
aggregate_target = stub_aggregate_target([pod_target], target_definition)
@sut.links_dependency?(aggregate_target, pod_target).should.be.true
end
it 'should link static dependency when target explicitly specifies it even with search paths' do
target_definition = stub('target_definition', :inheritance => 'search_paths')
pod_target = stub('pod_target', :name => 'BananaLib', :sandbox => config.sandbox)
aggregate_target = stub_aggregate_target([pod_target], target_definition)
@sut.links_dependency?(aggregate_target, pod_target).should.be.true
end
it 'should not link static dependency when inheriting search paths and parent includes dependency' do
parent_target_definition = stub
child_target_definition = stub('child_target_definition', :inheritance => 'search_paths')
pod_target = stub('pod_target', :name => 'BananaLib', :sandbox => config.sandbox)
parent_aggregate_target = stub_aggregate_target([pod_target], parent_target_definition)
child_aggregate_target = stub_aggregate_target([], child_target_definition, :search_paths_aggregate_targets => [parent_aggregate_target])
@sut.links_dependency?(child_aggregate_target, pod_target).should.be.false
end
it 'should link static transitive dependencies if the parent does not link them' do
child_pod_target = stub('child_pod_target', :name => 'ChildPod', :sandbox => config.sandbox)
parent_pod_target = stub('parent_pod_target', :name => 'ParentPod', :sandbox => config.sandbox, :dependent_targets => [child_pod_target])
parent_target_definition = stub
child_target_definition = stub('child_target_definition', :inheritance => 'search_paths')
parent_aggregate_target = stub_aggregate_target([], parent_target_definition)
child_aggregate_target = stub_aggregate_target([parent_pod_target, child_pod_target], child_target_definition, :search_paths_aggregate_targets => [parent_aggregate_target])
@sut.links_dependency?(child_aggregate_target, child_pod_target).should.be.true
@sut.links_dependency?(child_aggregate_target, parent_pod_target).should.be.true
end
it 'should link static only transitive dependencies that the parent does not link' do
child_pod_target = stub('child_pod_target', :name => 'ChildPod', :sandbox => config.sandbox)
parent_pod_target = stub('parent_pod_target', :name => 'ParentPod', :sandbox => config.sandbox, :dependent_targets => [child_pod_target])
parent_target_definition = stub
child_target_definition = stub('child_target_definition', :inheritance => 'search_paths')
parent_aggregate_target = stub('parent_aggregate_target', :target_definition => parent_target_definition, :pod_targets => [child_pod_target], :search_paths_aggregate_targets => [], :pod_targets_to_link => [child_pod_target])
child_aggregate_target = stub('child_aggregate_target', :target_definition => child_target_definition, :pod_targets => [parent_pod_target, child_pod_target], :search_paths_aggregate_targets => [parent_aggregate_target], :pod_targets_to_link => [parent_pod_target])
@sut.links_dependency?(child_aggregate_target, child_pod_target).should.be.false
@sut.links_dependency?(child_aggregate_target, parent_pod_target).should.be.true
end
end
#---------------------------------------------------------------------#
end
end
end
end
require File.expand_path('../../../spec_helper', __FILE__)
module Pod
describe Generator::XCConfig do
end
end
...@@ -90,12 +90,8 @@ module Pod ...@@ -90,12 +90,8 @@ module Pod
framework_subdir_header = headers_root + 'BananaLib/Bananalib/SubDir/SubBananalib.h' framework_subdir_header = headers_root + 'BananaLib/Bananalib/SubDir/SubBananalib.h'
public_headers.each { |public_header| public_header.should.exist } public_headers.each { |public_header| public_header.should.exist }
private_header.should.not.exist private_header.should.not.exist
framework_header.should.exist framework_header.should.not.exist
framework_subdir_header.should.exist framework_subdir_header.should.not.exist
config.sandbox.public_headers.search_paths(@pod_target.platform).should == %w(
${PODS_ROOT}/Headers/Public
${PODS_ROOT}/Headers/Public/BananaLib
)
end end
it 'links the public headers meant for the user for a vendored framework' do it 'links the public headers meant for the user for a vendored framework' do
......
...@@ -322,8 +322,9 @@ module Pod ...@@ -322,8 +322,9 @@ module Pod
user_target = stub('SampleApp-iOS-User-Target', :symbol_type => :application) user_target = stub('SampleApp-iOS-User-Target', :symbol_type => :application)
user_target.expects(:common_resolved_build_setting).with('APPLICATION_EXTENSION_API_ONLY').returns('NO') user_target.expects(:common_resolved_build_setting).with('APPLICATION_EXTENSION_API_ONLY').returns('NO')
target = AggregateTarget.new(config.sandbox, false, {}, [], target = AggregateTarget.new(config.sandbox, false,
Platform.new(:ios, '6.0'), fixture_target_definition, { 'App Store' => :release, 'Debug' => :debug, 'Release' => :release, 'Test' => :debug },
[], Platform.new(:ios, '6.0'), fixture_target_definition,
config.sandbox.root.dirname, proj, nil, []) config.sandbox.root.dirname, proj, nil, [])
target.stubs(:user_targets).returns([user_target]) target.stubs(:user_targets).returns([user_target])
......
require File.expand_path('../../../../spec_helper', __FILE__) require File.expand_path('../../../../spec_helper', __FILE__)
module Pod module Pod
module Generator class Target
module XCConfig class BuildSettings
describe AggregateXCConfig do describe AggregateTargetSettings do
def specs def specs
[fixture_spec('banana-lib/BananaLib.podspec')] [fixture_spec('banana-lib/BananaLib.podspec')]
end end
...@@ -18,14 +18,14 @@ module Pod ...@@ -18,14 +18,14 @@ module Pod
@specs.first.user_target_xcconfig = { 'OTHER_LDFLAGS' => '-no_compact_unwind' } unless @specs.empty? @specs.first.user_target_xcconfig = { 'OTHER_LDFLAGS' => '-no_compact_unwind' } unless @specs.empty?
@specs.first.pod_target_xcconfig = { 'CLANG_CXX_LANGUAGE_STANDARD' => 'c++11' } unless @specs.empty? @specs.first.pod_target_xcconfig = { 'CLANG_CXX_LANGUAGE_STANDARD' => 'c++11' } unless @specs.empty?
@pod_targets = @specs.map { |spec| pod_target(spec, @target_definition) } @pod_targets = @specs.map { |spec| pod_target(spec, @target_definition) }
@target = fixture_aggregate_target(@pod_targets, false, {}, [], Platform.new(:ios, '6.0'), @target_definition) @target = fixture_aggregate_target(@pod_targets, false, { 'Release' => :release }, [], Platform.new(:ios, '6.0'), @target_definition)
unless @specs.empty? unless @specs.empty?
@target.target_definition.whitelist_pod_for_configuration(@specs.first.name, 'Release') @target.target_definition.whitelist_pod_for_configuration(@specs.first.name, 'Release')
end end
@generator = AggregateXCConfig.new(@target, 'Release') @generator = AggregateTargetSettings.new(@target, 'Release')
end end
shared 'AggregateXCConfig' do shared 'Aggregate' do
it 'returns the path of the pods root relative to the user project' do it 'returns the path of the pods root relative to the user project' do
@generator.target.relative_pods_root.should == '${SRCROOT}/Pods' @generator.target.relative_pods_root.should == '${SRCROOT}/Pods'
end end
...@@ -135,7 +135,7 @@ module Pod ...@@ -135,7 +135,7 @@ module Pod
[fixture_spec('banana-lib/BananaLib.podspec')] [fixture_spec('banana-lib/BananaLib.podspec')]
end end
behaves_like 'AggregateXCConfig' behaves_like 'Aggregate'
it 'configures the project to load all members that implement Objective-c classes or categories' do it 'configures the project to load all members that implement Objective-c classes or categories' do
@xcconfig.to_hash['OTHER_LDFLAGS'].should.include '-ObjC' @xcconfig.to_hash['OTHER_LDFLAGS'].should.include '-ObjC'
...@@ -158,6 +158,13 @@ module Pod ...@@ -158,6 +158,13 @@ module Pod
@xcconfig.to_hash['OTHER_CFLAGS'].should == expected @xcconfig.to_hash['OTHER_CFLAGS'].should == expected
end end
it 'adds the dependent pods module map file to OTHER_SWIFT_FLAGS' do
@pod_targets.each { |pt| pt.stubs(:defines_module? => true) }
@xcconfig = @generator.generate
expected = '$(inherited) -D COCOAPODS -Xcc -fmodule-map-file="${PODS_ROOT}/Headers/Private/BananaLib/BananaLib.modulemap"'
@xcconfig.to_hash['OTHER_SWIFT_FLAGS'].should == expected
end
describe 'with a scoped pod target' do describe 'with a scoped pod target' do
def pod_target(spec, target_definition) def pod_target(spec, target_definition)
fixture_pod_target(spec, false, {}, [], Platform.new(:ios, '6.0'), [target_definition]).scoped.first fixture_pod_target(spec, false, {}, [], Platform.new(:ios, '6.0'), [target_definition]).scoped.first
...@@ -175,10 +182,50 @@ module Pod ...@@ -175,10 +182,50 @@ module Pod
end end
it 'does not links the pod targets with the aggregate target for non-whitelisted configuration' do it 'does not links the pod targets with the aggregate target for non-whitelisted configuration' do
@generator = AggregateXCConfig.new(@target, 'Debug') @generator = AggregateTargetSettings.new(@target, 'Debug')
@xcconfig = @generator.generate @xcconfig = @generator.generate
@xcconfig.to_hash['OTHER_LDFLAGS'].should.not.include '-l"Pods-BananaLib"' @xcconfig.to_hash['OTHER_LDFLAGS'].should.not.include '-l"Pods-BananaLib"'
end end
it 'does propagate framework or libraries from a non test specification to an aggregate target' do
target_definition = stub('target_definition', :inheritance => 'complete', :abstract? => false, :podfile => Podfile.new, :platform => Platform.ios)
spec = stub('spec', :test_specification? => false)
consumer = stub('consumer',
:libraries => ['xml2'],
:frameworks => ['XCTest'],
:weak_frameworks => [],
:spec => spec,
)
file_accessor = stub('file_accessor',
:spec => spec,
:spec_consumer => consumer,
:vendored_static_frameworks => [config.sandbox.root + 'StaticFramework.framework'],
:vendored_static_libraries => [config.sandbox.root + 'StaticLibrary.a'],
:vendored_dynamic_frameworks => [config.sandbox.root + 'VendoredFramework.framework'],
:vendored_dynamic_libraries => [config.sandbox.root + 'VendoredDyld.dyld'],
)
file_accessor.stubs(:vendored_frameworks => file_accessor.vendored_static_frameworks + file_accessor.vendored_dynamic_frameworks,
:vendored_dynamic_artifacts => file_accessor.vendored_dynamic_frameworks + file_accessor.vendored_dynamic_libraries)
pod_target = stub('pod_target',
:file_accessors => [file_accessor],
:spec_consumers => [consumer],
:requires_frameworks? => false,
:dependent_targets => [],
:recursive_dependent_targets => [],
:sandbox => config.sandbox,
:should_build? => true,
:configuration_build_dir => 'CBD',
:include_in_build_config? => true,
:uses_swift? => false,
:build_product_path => 'BPP',
:product_basename => 'PodTarget',
:target_definitions => [target_definition],
)
pod_target.stubs(:build_settings => PodTargetSettings.new(pod_target, false))
aggregate_target = fixture_aggregate_target([pod_target])
@generator = AggregateTargetSettings.new(aggregate_target, 'Debug')
@generator.other_ldflags.should == %w(-ObjC -l"PodTarget" -l"StaticLibrary" -l"VendoredDyld" -l"xml2" -framework "StaticFramework" -framework "VendoredFramework" -framework "XCTest")
end
end end
describe 'with framework' do describe 'with framework' do
...@@ -190,7 +237,7 @@ module Pod ...@@ -190,7 +237,7 @@ module Pod
Target.any_instance.stubs(:requires_frameworks?).returns(true) Target.any_instance.stubs(:requires_frameworks?).returns(true)
end end
behaves_like 'AggregateXCConfig' behaves_like 'Aggregate'
it "doesn't configure the project to load all members that implement Objective-c classes or categories" do it "doesn't configure the project to load all members that implement Objective-c classes or categories" do
@xcconfig.to_hash['OTHER_LDFLAGS'].should.not.include '-ObjC' @xcconfig.to_hash['OTHER_LDFLAGS'].should.not.include '-ObjC'
...@@ -220,7 +267,7 @@ module Pod ...@@ -220,7 +267,7 @@ module Pod
end end
it 'includes the public header paths as system headers' do it 'includes the public header paths as system headers' do
expected = '$(inherited) -iquote "${PODS_CONFIGURATION_BUILD_DIR}/OrangeFramework/OrangeFramework.framework/Headers" -isystem "${PODS_ROOT}/Headers/Public/monkey"' expected = '$(inherited) -isystem "${PODS_ROOT}/Headers/Public/monkey" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/OrangeFramework/OrangeFramework.framework/Headers"'
@generator.stubs(:pod_targets).returns([@pod_targets.first, pod_target(fixture_spec('orange-framework/OrangeFramework.podspec'), @target_definition)]) @generator.stubs(:pod_targets).returns([@pod_targets.first, pod_target(fixture_spec('orange-framework/OrangeFramework.podspec'), @target_definition)])
@xcconfig = @generator.generate @xcconfig = @generator.generate
@xcconfig.to_hash['OTHER_CFLAGS'].should == expected @xcconfig.to_hash['OTHER_CFLAGS'].should == expected
...@@ -259,7 +306,7 @@ module Pod ...@@ -259,7 +306,7 @@ module Pod
end end
it 'adds the framework build path to the xcconfig, with quotes, as framework search paths' do it 'adds the framework build path to the xcconfig, with quotes, as framework search paths' do
@xcconfig.to_hash['FRAMEWORK_SEARCH_PATHS'].should == '$(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/BananaLib-iOS" "${PODS_CONFIGURATION_BUILD_DIR}/OrangeFramework-iOS"' @xcconfig.to_hash['FRAMEWORK_SEARCH_PATHS'].should == '$(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/BananaLib-iOS" "${PODS_CONFIGURATION_BUILD_DIR}/OrangeFramework-iOS" "${PODS_ROOT}/../../spec/fixtures/banana-lib"'
end end
it 'adds the framework header paths to the xcconfig, with quotes, as local headers' do it 'adds the framework header paths to the xcconfig, with quotes, as local headers' do
...@@ -284,7 +331,7 @@ module Pod ...@@ -284,7 +331,7 @@ module Pod
end end
it 'adds the COCOAPODS macro definition' do it 'adds the COCOAPODS macro definition' do
@xcconfig.to_hash['OTHER_SWIFT_FLAGS'].should.include '$(inherited) "-D" "COCOAPODS"' @xcconfig.to_hash['OTHER_SWIFT_FLAGS'].should.include '$(inherited) -D COCOAPODS'
end end
it 'includes default runpath search path list for a non host target' do it 'includes default runpath search path list for a non host target' do
...@@ -313,58 +360,143 @@ module Pod ...@@ -313,58 +360,143 @@ module Pod
it 'uses the target definition swift version' do it 'uses the target definition swift version' do
@target_definition.stubs(:swift_version).returns('0.1') @target_definition.stubs(:swift_version).returns('0.1')
@generator.send(:target_swift_version).should == '0.1' @generator.send :__clear__
@generator.send(:target_swift_version).should == Version.new('0.1')
end end
it 'sets EMBEDDED_CONTENT_CONTAINS_SWIFT when the target_swift_version is < 2.3' do it 'sets EMBEDDED_CONTENT_CONTAINS_SWIFT when the target_swift_version is < 2.3' do
@generator.send(:pod_targets).first.stubs(:uses_swift?).returns(true) @generator.send(:pod_targets).first.stubs(:uses_swift?).returns(true)
@generator.stubs(:target_swift_version).returns('2.2') @target_definition.stubs(:swift_version).returns('2.2')
@generator.generate.to_hash['EMBEDDED_CONTENT_CONTAINS_SWIFT'].should == 'YES' @generator.generate.to_hash['EMBEDDED_CONTENT_CONTAINS_SWIFT'].should == 'YES'
end end
it 'does not set EMBEDDED_CONTENT_CONTAINS_SWIFT when there is no swift' do it 'does not set EMBEDDED_CONTENT_CONTAINS_SWIFT when there is no swift' do
@generator.send(:pod_targets).each { |pt| pt.stubs(:uses_swift?).returns(false) } @generator.send(:pod_targets).each { |pt| pt.stubs(:uses_swift?).returns(false) }
@generator.stubs(:target_swift_version).returns('2.2') @target_definition.stubs(:swift_version).returns('2.2')
@generator.generate.to_hash['EMBEDDED_CONTENT_CONTAINS_SWIFT'].should.be.nil @generator.generate.to_hash['EMBEDDED_CONTENT_CONTAINS_SWIFT'].should.be.nil
end end
it 'does not set EMBEDDED_CONTENT_CONTAINS_SWIFT when there is swift, but the target is an extension' do it 'does not set EMBEDDED_CONTENT_CONTAINS_SWIFT when there is swift, but the target is an extension' do
@target.stubs(:requires_host_target?).returns(true) @target.stubs(:requires_host_target?).returns(true)
@generator.stubs(:target_swift_version).returns('2.2') @target_definition.stubs(:swift_version).returns('2.2')
@generator.send(:pod_targets).first.stubs(:uses_swift?).returns(true) @generator.send(:pod_targets).first.stubs(:uses_swift?).returns(true)
@generator.generate.to_hash['EMBEDDED_CONTENT_CONTAINS_SWIFT'].should.be.nil @generator.generate.to_hash['EMBEDDED_CONTENT_CONTAINS_SWIFT'].should.be.nil
end end
it 'sets EMBEDDED_CONTENT_CONTAINS_SWIFT when the target_swift_version is nil' do it 'sets EMBEDDED_CONTENT_CONTAINS_SWIFT when the target_swift_version is nil' do
@generator.send(:pod_targets).first.stubs(:uses_swift?).returns(true) @generator.send(:pod_targets).first.stubs(:uses_swift?).returns(true)
@generator.stubs(:target_swift_version).returns(nil) @target_definition.stubs(:swift_version).returns(nil)
@generator.generate.to_hash['EMBEDDED_CONTENT_CONTAINS_SWIFT'].should == 'YES' @generator.generate.to_hash['EMBEDDED_CONTENT_CONTAINS_SWIFT'].should == 'YES'
end end
it 'sets ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES to YES when there is swift >= 2.3' do it 'sets ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES to YES when there is swift >= 2.3' do
@generator.send(:pod_targets).first.stubs(:uses_swift?).returns(true) @generator.send(:pod_targets).first.stubs(:uses_swift?).returns(true)
@generator.stubs(:target_swift_version).returns('2.3') @target_definition.stubs(:swift_version).returns('2.3')
@generator.generate.to_hash['ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES'].should == 'YES' @generator.generate.to_hash['ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES'].should == 'YES'
end end
it 'does not set ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES when there is no swift' do it 'does not set ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES when there is no swift' do
@generator.send(:pod_targets).first.stubs(:uses_swift?).returns(false) @generator.send(:pod_targets).first.stubs(:uses_swift?).returns(false)
@generator.stubs(:target_swift_version).returns(nil) @target_definition.stubs(:swift_version).returns(nil)
@generator.generate.to_hash['ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES'].nil?.should == true @generator.generate.to_hash['ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES'].nil?.should == true
end end
it 'does not set ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES when there is swift, but the target is an extension' do it 'does not set ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES when there is swift, but the target is an extension' do
@target.stubs(:requires_host_target?).returns(true) @target.stubs(:requires_host_target?).returns(true)
@generator.stubs(:target_swift_version).returns('2.3') @target_definition.stubs(:swift_version).returns('2.3')
@generator.send(:pod_targets).first.stubs(:uses_swift?).returns(true) @generator.send(:pod_targets).first.stubs(:uses_swift?).returns(true)
@generator.generate.to_hash['ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES'].nil?.should == true @generator.generate.to_hash['ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES'].nil?.should == true
end end
it 'does not set EMBEDDED_CONTENT_CONTAINS_SWIFT when there is swift 2.3 or higher' do it 'does not set EMBEDDED_CONTENT_CONTAINS_SWIFT when there is swift 2.3 or higher' do
@generator.send(:pod_targets).first.stubs(:uses_swift?).returns(true) @generator.send(:pod_targets).first.stubs(:uses_swift?).returns(true)
@generator.stubs(:target_swift_version).returns('2.3') @target_definition.stubs(:swift_version).returns('2.3')
@generator.generate.to_hash.key?('EMBEDDED_CONTENT_CONTAINS_SWIFT').should == false @generator.generate.to_hash.key?('EMBEDDED_CONTENT_CONTAINS_SWIFT').should == false
end end
it 'does propagate framework or libraries from a non test specification to an aggregate target' do
target_definition = stub('target_definition', :inheritance => 'complete', :abstract? => false, :podfile => Podfile.new, :platform => Platform.ios)
spec = stub('spec', :test_specification? => false)
consumer = stub('consumer',
:libraries => ['xml2'],
:frameworks => ['XCTest'],
:weak_frameworks => [],
:spec => spec,
)
file_accessor = stub('file_accessor',
:spec => spec,
:spec_consumer => consumer,
:vendored_static_frameworks => [config.sandbox.root + 'StaticFramework.framework'],
:vendored_static_libraries => [config.sandbox.root + 'StaticLibrary.a'],
:vendored_dynamic_frameworks => [config.sandbox.root + 'VendoredFramework.framework'],
:vendored_dynamic_libraries => [config.sandbox.root + 'VendoredDyld.dyld'],
)
file_accessor.stubs(:vendored_frameworks => file_accessor.vendored_static_frameworks + file_accessor.vendored_dynamic_frameworks,
:vendored_dynamic_artifacts => file_accessor.vendored_dynamic_frameworks + file_accessor.vendored_dynamic_libraries,
:vendored_static_artifacts => file_accessor.vendored_static_frameworks + file_accessor.vendored_static_libraries)
pod_target = stub('pod_target',
:file_accessors => [file_accessor],
:spec_consumers => [consumer],
:requires_frameworks? => true,
:static_framework? => false,
:dependent_targets => [],
:recursive_dependent_targets => [],
:sandbox => config.sandbox,
:should_build? => true,
:configuration_build_dir => 'CBD',
:include_in_build_config? => true,
:uses_swift? => false,
:build_product_path => 'BPP',
:product_basename => 'PodTarget',
:target_definitions => [target_definition],
)
pod_target.stubs(:build_settings => PodTargetSettings.new(pod_target, false))
aggregate_target = fixture_aggregate_target([pod_target])
@generator = AggregateTargetSettings.new(aggregate_target, 'Debug')
@generator.other_ldflags.should == %w(-ObjC -l"StaticLibrary" -l"VendoredDyld" -l"xml2" -framework "PodTarget" -framework "VendoredFramework" -framework "XCTest")
end
it 'does propagate framework or libraries from a non test specification static framework to an aggregate target' do
target_definition = stub('target_definition', :inheritance => 'complete', :abstract? => false, :podfile => Podfile.new, :platform => Platform.ios)
spec = stub('spec', :test_specification? => false)
consumer = stub('consumer',
:libraries => ['xml2'],
:frameworks => ['XCTest'],
:weak_frameworks => [],
:spec => spec,
)
file_accessor = stub('file_accessor',
:spec => spec,
:spec_consumer => consumer,
:vendored_static_frameworks => [config.sandbox.root + 'StaticFramework.framework'],
:vendored_static_libraries => [config.sandbox.root + 'StaticLibrary.a'],
:vendored_dynamic_frameworks => [config.sandbox.root + 'VendoredFramework.framework'],
:vendored_dynamic_libraries => [config.sandbox.root + 'VendoredDyld.dyld'],
)
file_accessor.stubs(:vendored_frameworks => file_accessor.vendored_static_frameworks + file_accessor.vendored_dynamic_frameworks,
:vendored_dynamic_artifacts => file_accessor.vendored_dynamic_frameworks + file_accessor.vendored_dynamic_libraries,
:vendored_static_artifacts => file_accessor.vendored_static_frameworks + file_accessor.vendored_static_libraries)
pod_target = stub('pod_target',
:file_accessors => [file_accessor],
:spec_consumers => [consumer],
:requires_frameworks? => true,
:static_framework? => true,
:dependent_targets => [],
:recursive_dependent_targets => [],
:sandbox => config.sandbox,
:should_build? => true,
:configuration_build_dir => 'CBD',
:include_in_build_config? => true,
:uses_swift? => false,
:build_product_path => 'BPP',
:product_basename => 'PodTarget',
:target_definitions => [target_definition],
)
pod_target.stubs(:build_settings => PodTargetSettings.new(pod_target, false))
aggregate_target = fixture_aggregate_target([pod_target])
@generator = AggregateTargetSettings.new(aggregate_target, 'Debug')
@generator.other_ldflags.should == %w(-ObjC -l"StaticLibrary" -l"VendoredDyld" -l"xml2" -framework "PodTarget" -framework "StaticFramework" -framework "VendoredFramework" -framework "XCTest")
end
end end
#-----------------------------------------------------------------------# #-----------------------------------------------------------------------#
...@@ -455,7 +587,7 @@ module Pod ...@@ -455,7 +587,7 @@ module Pod
it 'adds values from all subspecs' do it 'adds values from all subspecs' do
@consumer_b.stubs(:user_target_xcconfig).returns('OTHER_CPLUSPLUSFLAGS' => '-std=c++1y') @consumer_b.stubs(:user_target_xcconfig).returns('OTHER_CPLUSPLUSFLAGS' => '-std=c++1y')
consumer_c = mock(:user_target_xcconfig => { 'OTHER_CPLUSPLUSFLAGS' => '-stdlib=libc++' }, :script_phases => []) consumer_c = mock('consumer_c', :user_target_xcconfig => { 'OTHER_CPLUSPLUSFLAGS' => '-stdlib=libc++' }, :script_phases => [], :spec => mock(:test_specification? => false), :frameworks => [], :libraries => [])
@pod_targets[1].stubs(:spec_consumers).returns([@consumer_b, consumer_c]) @pod_targets[1].stubs(:spec_consumers).returns([@consumer_b, consumer_c])
@xcconfig = @generator.generate @xcconfig = @generator.generate
@xcconfig.to_hash['OTHER_CPLUSPLUSFLAGS'].should == '-std=c++1y -stdlib=libc++' @xcconfig.to_hash['OTHER_CPLUSPLUSFLAGS'].should == '-std=c++1y -stdlib=libc++'
...@@ -484,7 +616,7 @@ module Pod ...@@ -484,7 +616,7 @@ module Pod
describe 'an empty pod target' do describe 'an empty pod target' do
before do before do
@blank_target = fixture_aggregate_target @blank_target = fixture_aggregate_target
@generator = AggregateXCConfig.new(@blank_target, 'Release') @generator = AggregateTargetSettings.new(@blank_target, 'Release')
end end
it 'it should not have any framework search paths' do it 'it should not have any framework search paths' do
...@@ -493,12 +625,32 @@ module Pod ...@@ -493,12 +625,32 @@ module Pod
end end
describe 'with inherited targets' do describe 'with inherited targets' do
it 'should include inherited search paths' do before do
# It's the responsibility of the analyzer to # It's the responsibility of the analyzer to
# populate this when the file is loaded. # populate this when the file is loaded.
@blank_target.search_paths_aggregate_targets.replace [@target] @blank_target.search_paths_aggregate_targets.replace [@target]
end
it 'should include inherited search paths' do
@xcconfig = @generator.generate @xcconfig = @generator.generate
@xcconfig.to_hash['FRAMEWORK_SEARCH_PATHS'].should.not.be.nil @xcconfig.to_hash['FRAMEWORK_SEARCH_PATHS'].should == '$(inherited) "${PODS_ROOT}/../../spec/fixtures/banana-lib"'
end
it 'should include OTHER_LDFLAGS to link against dynamic libraries' do
@target.pod_targets.each { |pt| pt.spec_consumers.each { |sc| sc.stubs(:frameworks => %w(UIKit), :libraries => %w(z c++)) } }
@xcconfig = @generator.generate
@xcconfig.to_hash['OTHER_LDFLAGS'].should == '$(inherited) -ObjC -l"c++" -l"z" -framework "UIKit"'
end
it 'should not doubly link static libraries' do
@specs.each { |s| s.user_target_xcconfig = nil }
@target.pod_targets.each { |pt| pt.spec_consumers.each { |sc| sc.stubs(:frameworks => %w(UIKit), :libraries => %w(z), :vendored_libraries => %w()) } }
@blank_target.pod_targets.replace @target.pod_targets
@xcconfig = @generator.generate
# -lBananaLib is not added
@xcconfig.to_hash['OTHER_LDFLAGS'].should == '$(inherited) -ObjC -l"z" -framework "UIKit"'
end end
end end
end end
......
require File.expand_path('../../../../spec_helper', __FILE__) require File.expand_path('../../../../spec_helper', __FILE__)
module Pod module Pod
module Generator class Target
module XCConfig class BuildSettings
describe PodXCConfig do describe PodTargetSettings do
describe 'in general' do describe 'in general' do
before do before do
@monkey_spec = fixture_spec('monkey/monkey.podspec') @monkey_spec = fixture_spec('monkey/monkey.podspec')
...@@ -12,6 +12,7 @@ module Pod ...@@ -12,6 +12,7 @@ module Pod
vspec = stub(:test_specification? => false) vspec = stub(:test_specification? => false)
consumer = stub( consumer = stub(
"Spec Consumer (#{vspec} iOS)", "Spec Consumer (#{vspec} iOS)",
:spec => vspec,
:pod_target_xcconfig => {}, :pod_target_xcconfig => {},
:libraries => ['xml2'], :libraries => ['xml2'],
:frameworks => [], :frameworks => [],
...@@ -27,6 +28,8 @@ module Pod ...@@ -27,6 +28,8 @@ module Pod
:vendored_dynamic_frameworks => [config.sandbox.root + 'CCC/VendoredFramework.framework'], :vendored_dynamic_frameworks => [config.sandbox.root + 'CCC/VendoredFramework.framework'],
:vendored_dynamic_libraries => [config.sandbox.root + 'DDD/VendoredDyld.dyld'], :vendored_dynamic_libraries => [config.sandbox.root + 'DDD/VendoredDyld.dyld'],
) )
file_accessor.stubs(:vendored_libraries => file_accessor.vendored_static_libraries + file_accessor.vendored_dynamic_libraries,
:vendored_frameworks => file_accessor.vendored_static_frameworks + file_accessor.vendored_dynamic_frameworks)
vendored_dep_target = stub( vendored_dep_target = stub(
'Vendored Dependent Target', 'Vendored Dependent Target',
:name => 'BananaLib', :name => 'BananaLib',
...@@ -36,9 +39,14 @@ module Pod ...@@ -36,9 +39,14 @@ module Pod
:requires_frameworks? => true, :requires_frameworks? => true,
:static_framework? => false, :static_framework? => false,
:dependent_targets => [], :dependent_targets => [],
:recursive_dependent_targets => [],
:file_accessors => [file_accessor], :file_accessors => [file_accessor],
:spec_consumers => [consumer],
:uses_modular_headers? => false, :uses_modular_headers? => false,
:uses_swift? => false,
:specs => [vspec],
) )
vendored_dep_target.stubs(:build_settings => PodTargetSettings.new(vendored_dep_target, false))
@spec = fixture_spec('banana-lib/BananaLib.podspec') @spec = fixture_spec('banana-lib/BananaLib.podspec')
@pod_target = fixture_pod_target(@spec, true) @pod_target = fixture_pod_target(@spec, true)
...@@ -46,7 +54,7 @@ module Pod ...@@ -46,7 +54,7 @@ module Pod
@consumer = @pod_target.spec_consumers.first @consumer = @pod_target.spec_consumers.first
@podfile = @pod_target.podfile @podfile = @pod_target.podfile
@generator = PodXCConfig.new(@pod_target) @generator = PodTargetSettings.new(@pod_target, false)
@spec.pod_target_xcconfig = { 'OTHER_LDFLAGS' => '-no_compact_unwind' } @spec.pod_target_xcconfig = { 'OTHER_LDFLAGS' => '-no_compact_unwind' }
@spec.user_target_xcconfig = { 'CLANG_CXX_LANGUAGE_STANDARD' => 'c++11' } @spec.user_target_xcconfig = { 'CLANG_CXX_LANGUAGE_STANDARD' => 'c++11' }
...@@ -169,12 +177,51 @@ module Pod ...@@ -169,12 +177,51 @@ module Pod
@xcconfig.to_hash['PRODUCT_BUNDLE_IDENTIFIER'].should == 'org.cocoapods.${PRODUCT_NAME:rfc1034identifier}' @xcconfig.to_hash['PRODUCT_BUNDLE_IDENTIFIER'].should == 'org.cocoapods.${PRODUCT_NAME:rfc1034identifier}'
end end
it 'does not have a module map to import if it is not built' do
@pod_target.stubs(:should_build? => false, :requires_frameworks? => false, :defines_module? => true)
@generator.generate
@generator.module_map_file_to_import.should.be.nil
end
it 'saves the xcconfig' do it 'saves the xcconfig' do
path = temporary_directory + 'sample.xcconfig' path = temporary_directory + 'sample.xcconfig'
@generator.save_as(path) @generator.save_as(path)
generated = Xcodeproj::Config.new(path) generated = Xcodeproj::Config.new(path)
generated.class.should == Xcodeproj::Config generated.class.should == Xcodeproj::Config
end end
it 'does propagate framework or libraries' do
spec = stub('spec', :test_specification? => false)
consumer = stub('consumer',
:libraries => ['xml2'],
:frameworks => ['XCTest'],
:weak_frameworks => [],
:spec => spec,
)
file_accessor = stub('file_accessor',
:spec => spec,
:spec_consumer => consumer,
:vendored_static_frameworks => [config.sandbox.root + 'StaticFramework.framework'],
:vendored_static_libraries => [config.sandbox.root + 'StaticLibrary.a'],
:vendored_dynamic_frameworks => [config.sandbox.root + 'VendoredFramework.framework'],
:vendored_dynamic_libraries => [config.sandbox.root + 'VendoredDyld.dyld'],
)
pod_target = stub('pod_target',
:file_accessors => [file_accessor],
:spec_consumers => [consumer],
:requires_frameworks? => true,
:static_framework? => true,
:dependent_targets => [],
:recursive_dependent_targets => [],
:sandbox => config.sandbox,
:should_build? => true,
)
pod_target.stubs(:build_settings => PodTargetSettings.new(pod_target, false))
@generator.spec_consumers.each { |sc| sc.stubs(:frameworks => []) }
@generator.stubs(:dependent_targets => [pod_target])
@generator.send :__clear__
@generator.other_ldflags.should.be == %w(-l"VendoredDyld" -l"xml2" -framework "Bananalib" -framework "VendoredFramework" -framework "XCTest" -weak_framework "iAd")
end
end end
describe 'test xcconfig generation' do describe 'test xcconfig generation' do
...@@ -201,7 +248,7 @@ module Pod ...@@ -201,7 +248,7 @@ module Pod
it 'does not merge pod target xcconfig of test specifications for a non test xcconfig' do it 'does not merge pod target xcconfig of test specifications for a non test xcconfig' do
@coconut_spec.pod_target_xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => 'NON_TEST_FLAG=1' } @coconut_spec.pod_target_xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => 'NON_TEST_FLAG=1' }
@coconut_test_spec.pod_target_xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => 'TEST_ONLY=1' } @coconut_test_spec.pod_target_xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => 'TEST_ONLY=1' }
generator = PodXCConfig.new(@coconut_pod_target, false) generator = PodTargetSettings.new(@coconut_pod_target, false)
xcconfig = generator.generate xcconfig = generator.generate
xcconfig.to_hash['GCC_PREPROCESSOR_DEFINITIONS'].should == '$(inherited) COCOAPODS=1 NON_TEST_FLAG=1' xcconfig.to_hash['GCC_PREPROCESSOR_DEFINITIONS'].should == '$(inherited) COCOAPODS=1 NON_TEST_FLAG=1'
end end
...@@ -209,41 +256,41 @@ module Pod ...@@ -209,41 +256,41 @@ module Pod
it 'merges the pod target xcconfig of non test specifications for test xcconfigs' do it 'merges the pod target xcconfig of non test specifications for test xcconfigs' do
@coconut_spec.pod_target_xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => 'NON_TEST_FLAG=1' } @coconut_spec.pod_target_xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => 'NON_TEST_FLAG=1' }
@coconut_test_spec.pod_target_xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => 'TEST_ONLY=1' } @coconut_test_spec.pod_target_xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => 'TEST_ONLY=1' }
generator = PodXCConfig.new(@coconut_pod_target, true) generator = PodTargetSettings.new(@coconut_pod_target, true)
xcconfig = generator.generate xcconfig = generator.generate
xcconfig.to_hash['GCC_PREPROCESSOR_DEFINITIONS'].should == '$(inherited) COCOAPODS=1 NON_TEST_FLAG=1 TEST_ONLY=1' xcconfig.to_hash['GCC_PREPROCESSOR_DEFINITIONS'].should == '$(inherited) COCOAPODS=1 NON_TEST_FLAG=1 TEST_ONLY=1'
end end
it 'includes correct other ld flags' do it 'includes correct other ld flags' do
generator = PodXCConfig.new(@coconut_pod_target, true) generator = PodTargetSettings.new(@coconut_pod_target, true)
xcconfig = generator.generate xcconfig = generator.generate
xcconfig.to_hash['OTHER_LDFLAGS'].should == '-ObjC -l"CoconutLib"' xcconfig.to_hash['OTHER_LDFLAGS'].should == '$(inherited) -ObjC -l"CoconutLib"'
end end
it 'includes correct other ld flags when requires frameworks' do it 'includes correct other ld flags when requires frameworks' do
@coconut_pod_target.stubs(:requires_frameworks?).returns(true) @coconut_pod_target.stubs(:requires_frameworks?).returns(true)
generator = PodXCConfig.new(@coconut_pod_target, true) generator = PodTargetSettings.new(@coconut_pod_target, true)
xcconfig = generator.generate xcconfig = generator.generate
xcconfig.to_hash['OTHER_LDFLAGS'].should == '-ObjC -framework "CoconutLib"' xcconfig.to_hash['OTHER_LDFLAGS'].should == '$(inherited) -ObjC -framework "CoconutLib"'
end end
it 'includes other ld flags for transitive dependent targets' do it 'includes other ld flags for transitive dependent targets' do
@coconut_pod_target.dependent_targets = [@monkey_pod_target] @coconut_pod_target.dependent_targets = [@monkey_pod_target]
generator = PodXCConfig.new(@coconut_pod_target, true) generator = PodTargetSettings.new(@coconut_pod_target, true)
xcconfig = generator.generate xcconfig = generator.generate
xcconfig.to_hash['OTHER_LDFLAGS'].should == '-ObjC -l"CoconutLib" -l"monkey" -framework "dynamic-monkey"' xcconfig.to_hash['OTHER_LDFLAGS'].should == '$(inherited) -ObjC -l"CoconutLib" -l"monkey" -framework "dynamic-monkey"'
end end
it 'includes other ld flags for test dependent targets' do it 'includes other ld flags for test dependent targets' do
@coconut_pod_target.test_dependent_targets_by_spec_name = { @coconut_test_spec.name => [@monkey_pod_target] } @coconut_pod_target.test_dependent_targets_by_spec_name = { @coconut_test_spec.name => [@monkey_pod_target] }
generator = PodXCConfig.new(@coconut_pod_target, true) generator = PodTargetSettings.new(@coconut_pod_target, true)
xcconfig = generator.generate xcconfig = generator.generate
xcconfig.to_hash['OTHER_LDFLAGS'].should == '-ObjC -l"CoconutLib" -l"monkey" -framework "dynamic-monkey"' xcconfig.to_hash['OTHER_LDFLAGS'].should == '$(inherited) -ObjC -l"CoconutLib" -l"monkey" -framework "dynamic-monkey"'
end end
it 'adds settings for test dependent targets' do it 'adds settings for test dependent targets' do
@coconut_pod_target.test_dependent_targets_by_spec_name = { @coconut_test_spec.name => [@banana_pod_target] } @coconut_pod_target.test_dependent_targets_by_spec_name = { @coconut_test_spec.name => [@banana_pod_target] }
generator = PodXCConfig.new(@coconut_pod_target, true) generator = PodTargetSettings.new(@coconut_pod_target, true)
xcconfig = generator.generate xcconfig = generator.generate
xcconfig.to_hash['FRAMEWORK_SEARCH_PATHS'].should == '$(inherited) "${PODS_ROOT}/../../spec/fixtures/banana-lib"' xcconfig.to_hash['FRAMEWORK_SEARCH_PATHS'].should == '$(inherited) "${PODS_ROOT}/../../spec/fixtures/banana-lib"'
xcconfig.to_hash['LIBRARY_SEARCH_PATHS'].should == '$(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/BananaLib" "${PODS_CONFIGURATION_BUILD_DIR}/CoconutLib" "${PODS_ROOT}/../../spec/fixtures/banana-lib"' xcconfig.to_hash['LIBRARY_SEARCH_PATHS'].should == '$(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/BananaLib" "${PODS_CONFIGURATION_BUILD_DIR}/CoconutLib" "${PODS_ROOT}/../../spec/fixtures/banana-lib"'
...@@ -252,10 +299,23 @@ module Pod ...@@ -252,10 +299,23 @@ module Pod
it 'adds settings for test dependent targets excluding the parents targets' do it 'adds settings for test dependent targets excluding the parents targets' do
@coconut_pod_target.dependent_targets = [@banana_pod_target] @coconut_pod_target.dependent_targets = [@banana_pod_target]
@coconut_pod_target.test_dependent_targets_by_spec_name = { @coconut_test_spec.name => [@banana_pod_target] } @coconut_pod_target.test_dependent_targets_by_spec_name = { @coconut_test_spec.name => [@banana_pod_target] }
generator = PodXCConfig.new(@coconut_pod_target, true) generator = PodTargetSettings.new(@coconut_pod_target, true)
xcconfig = generator.generate xcconfig = generator.generate
xcconfig.to_hash['FRAMEWORK_SEARCH_PATHS'].should == '$(inherited) "${PODS_ROOT}/../../spec/fixtures/banana-lib"' xcconfig.to_hash['FRAMEWORK_SEARCH_PATHS'].should == '$(inherited) "${PODS_ROOT}/../../spec/fixtures/banana-lib"'
xcconfig.to_hash['LIBRARY_SEARCH_PATHS'].should == '$(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/BananaLib" "${PODS_ROOT}/../../spec/fixtures/banana-lib" "${PODS_CONFIGURATION_BUILD_DIR}/CoconutLib"' xcconfig.to_hash['LIBRARY_SEARCH_PATHS'].should == '$(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/BananaLib" "${PODS_CONFIGURATION_BUILD_DIR}/CoconutLib" "${PODS_ROOT}/../../spec/fixtures/banana-lib"'
end
it 'adds the developer frameworks dir when XCTest is used but not linked' do
@banana_pod_target.spec_consumers.each { |sc| sc.stubs(:frameworks => %w(XCTest), :vendored_frameworks => []) }
@coconut_pod_target.dependent_targets = [@banana_pod_target]
generator = PodTargetSettings.new(@coconut_pod_target, false)
xcconfig = generator.generate
xcconfig.to_hash['FRAMEWORK_SEARCH_PATHS'].should == '$(inherited) "$(PLATFORM_DIR)/Developer/Library/Frameworks"'
generator = PodTargetSettings.new(@banana_pod_target, false)
xcconfig = generator.generate
xcconfig.to_hash['FRAMEWORK_SEARCH_PATHS'].should == '$(inherited) "$(PLATFORM_DIR)/Developer/Library/Frameworks"'
end end
it 'adds correct header search paths for dependent and test targets without modular headers' do it 'adds correct header search paths for dependent and test targets without modular headers' do
...@@ -269,7 +329,7 @@ module Pod ...@@ -269,7 +329,7 @@ module Pod
@coconut_pod_target.sandbox.public_headers.add_search_path('CoconutLib', Platform.ios) @coconut_pod_target.sandbox.public_headers.add_search_path('CoconutLib', Platform.ios)
@coconut_pod_target.test_dependent_targets_by_spec_name = { @coconut_test_spec.name => [@monkey_pod_target] } @coconut_pod_target.test_dependent_targets_by_spec_name = { @coconut_test_spec.name => [@monkey_pod_target] }
@coconut_pod_target.dependent_targets = [@banana_pod_target] @coconut_pod_target.dependent_targets = [@banana_pod_target]
generator = PodXCConfig.new(@coconut_pod_target, true) generator = PodTargetSettings.new(@coconut_pod_target, true)
xcconfig = generator.generate xcconfig = generator.generate
xcconfig.to_hash['HEADER_SEARCH_PATHS'].should == '$(inherited) "${PODS_ROOT}/Headers/Private"' \ xcconfig.to_hash['HEADER_SEARCH_PATHS'].should == '$(inherited) "${PODS_ROOT}/Headers/Private"' \
' "${PODS_ROOT}/Headers/Private/CoconutLib"' \ ' "${PODS_ROOT}/Headers/Private/CoconutLib"' \
...@@ -291,7 +351,7 @@ module Pod ...@@ -291,7 +351,7 @@ module Pod
@coconut_pod_target.test_dependent_targets_by_spec_name = { @coconut_test_spec.name => [@monkey_pod_target] } @coconut_pod_target.test_dependent_targets_by_spec_name = { @coconut_test_spec.name => [@monkey_pod_target] }
@coconut_pod_target.dependent_targets = [@banana_pod_target] @coconut_pod_target.dependent_targets = [@banana_pod_target]
# This is not an test xcconfig so it should exclude header search paths for the 'monkey' pod # This is not an test xcconfig so it should exclude header search paths for the 'monkey' pod
generator = PodXCConfig.new(@coconut_pod_target, false) generator = PodTargetSettings.new(@coconut_pod_target, false)
xcconfig = generator.generate xcconfig = generator.generate
xcconfig.to_hash['HEADER_SEARCH_PATHS'].should == '$(inherited) "${PODS_ROOT}/Headers/Private"' \ xcconfig.to_hash['HEADER_SEARCH_PATHS'].should == '$(inherited) "${PODS_ROOT}/Headers/Private"' \
' "${PODS_ROOT}/Headers/Private/CoconutLib"' \ ' "${PODS_ROOT}/Headers/Private/CoconutLib"' \
...@@ -311,7 +371,7 @@ module Pod ...@@ -311,7 +371,7 @@ module Pod
@coconut_pod_target.sandbox.public_headers.add_search_path('CoconutLib', Platform.ios) @coconut_pod_target.sandbox.public_headers.add_search_path('CoconutLib', Platform.ios)
@coconut_pod_target.test_dependent_targets_by_spec_name = { @coconut_test_spec.name => [@monkey_pod_target] } @coconut_pod_target.test_dependent_targets_by_spec_name = { @coconut_test_spec.name => [@monkey_pod_target] }
@coconut_pod_target.dependent_targets = [@banana_pod_target] @coconut_pod_target.dependent_targets = [@banana_pod_target]
generator = PodXCConfig.new(@coconut_pod_target, true) generator = PodTargetSettings.new(@coconut_pod_target, true)
xcconfig = generator.generate xcconfig = generator.generate
xcconfig.to_hash['HEADER_SEARCH_PATHS'].should == '$(inherited) "${PODS_ROOT}/Headers/Private"' \ xcconfig.to_hash['HEADER_SEARCH_PATHS'].should == '$(inherited) "${PODS_ROOT}/Headers/Private"' \
' "${PODS_ROOT}/Headers/Private/CoconutLib"' \ ' "${PODS_ROOT}/Headers/Private/CoconutLib"' \
...@@ -329,7 +389,7 @@ module Pod ...@@ -329,7 +389,7 @@ module Pod
@coconut_pod_target.sandbox.public_headers.add_search_path('CoconutLib', Platform.ios) @coconut_pod_target.sandbox.public_headers.add_search_path('CoconutLib', Platform.ios)
@coconut_pod_target.test_dependent_targets_by_spec_name = { @coconut_test_spec.name => [@monkey_pod_target] } @coconut_pod_target.test_dependent_targets_by_spec_name = { @coconut_test_spec.name => [@monkey_pod_target] }
@coconut_pod_target.dependent_targets = [@banana_pod_target] @coconut_pod_target.dependent_targets = [@banana_pod_target]
generator = PodXCConfig.new(@coconut_pod_target, false) generator = PodTargetSettings.new(@coconut_pod_target, false)
xcconfig = generator.generate xcconfig = generator.generate
xcconfig.to_hash['HEADER_SEARCH_PATHS'].should == '$(inherited) "${PODS_ROOT}/Headers/Private"' \ xcconfig.to_hash['HEADER_SEARCH_PATHS'].should == '$(inherited) "${PODS_ROOT}/Headers/Private"' \
' "${PODS_ROOT}/Headers/Private/CoconutLib"' \ ' "${PODS_ROOT}/Headers/Private/CoconutLib"' \
...@@ -338,27 +398,27 @@ module Pod ...@@ -338,27 +398,27 @@ module Pod
it 'does not include other ld flags for test dependent targets if its not a test xcconfig' do it 'does not include other ld flags for test dependent targets if its not a test xcconfig' do
@coconut_pod_target.test_dependent_targets_by_spec_name = { @coconut_test_spec.name => [@monkey_pod_target] } @coconut_pod_target.test_dependent_targets_by_spec_name = { @coconut_test_spec.name => [@monkey_pod_target] }
generator = PodXCConfig.new(@coconut_pod_target) generator = PodTargetSettings.new(@coconut_pod_target, false)
xcconfig = generator.generate xcconfig = generator.generate
xcconfig.to_hash['LIBRARY_SEARCH_PATHS'].should.be.nil xcconfig.to_hash['LIBRARY_SEARCH_PATHS'].should.be.nil
xcconfig.to_hash['OTHER_LDFLAGS'].should.be.nil xcconfig.to_hash['OTHER_LDFLAGS'].should.be.nil
end end
it 'includes default runpath search path list for test xcconfigs' do it 'includes default runpath search path list for test xcconfigs' do
generator = PodXCConfig.new(@coconut_pod_target, true) generator = PodTargetSettings.new(@coconut_pod_target, true)
xcconfig = generator.generate xcconfig = generator.generate
xcconfig.to_hash['LD_RUNPATH_SEARCH_PATHS'].should == "$(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'" xcconfig.to_hash['LD_RUNPATH_SEARCH_PATHS'].should == "$(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'"
end end
it 'includes default runpath search path list for test xcconfigs for test bundle' do it 'includes default runpath search path list for test xcconfigs for test bundle' do
@coconut_pod_target.stubs(:platform).returns(Platform.new(:osx, '10.10')) @coconut_pod_target.stubs(:platform).returns(Platform.new(:osx, '10.10'))
generator = PodXCConfig.new(@coconut_pod_target, true) generator = PodTargetSettings.new(@coconut_pod_target, true)
xcconfig = generator.generate xcconfig = generator.generate
xcconfig.to_hash['LD_RUNPATH_SEARCH_PATHS'].should == "$(inherited) '@executable_path/../Frameworks' '@loader_path/../Frameworks'" xcconfig.to_hash['LD_RUNPATH_SEARCH_PATHS'].should == "$(inherited) '@executable_path/../Frameworks' '@loader_path/../Frameworks'"
end end
it 'does not set configuration build dir for test xcconfigs' do it 'does not set configuration build dir for test xcconfigs' do
generator = PodXCConfig.new(@coconut_pod_target, true) generator = PodTargetSettings.new(@coconut_pod_target, true)
xcconfig = generator.generate xcconfig = generator.generate
xcconfig.to_hash['CONFIGURATION_BUILD_DIR'].should.be.nil xcconfig.to_hash['CONFIGURATION_BUILD_DIR'].should.be.nil
end end
......
require File.expand_path('../../../spec_helper', __FILE__)
module Pod
class Target
describe BuildSettings do
def pod(pod_target, test_xcconfig = false)
BuildSettings::PodTargetSettings.new(pod_target, test_xcconfig)
end
def aggregate(aggregate_target, configuration_name = 'Release')
BuildSettings::AggregateTargetSettings.new(aggregate_target, configuration_name)
end
describe 'memoization' do
it 'memoizes methods when requested' do
cls = Class.new(BuildSettings) do
define_build_settings_method :foobar, :memoized => true do
Object.new
end
end
settings = cls.new(stub('Target'))
object = settings.foobar
object.should.be.frozen
object.should.equal?(settings.foobar)
end
it 'memoizes array methods when requested' do
cls = Class.new(BuildSettings) do
define_build_settings_method :foobar, :memoized => true, :sorted => true, :uniqued => true do
%w(b a c a)
end
end
settings = cls.new(stub('Target'))
object = settings.foobar
object.should.be.frozen
object.should == %w(a b c)
object.should.equal?(settings.foobar)
end
end
#---------------------------------------------------------------------#
describe '::add_developers_frameworks_if_needed' do
it 'adds the developer frameworks search paths to the xcconfig if SenTestingKit has been detected' do
xcconfig = BuildSettings.new(stub('Target'))
xcconfig.stubs(:frameworks => %w(SenTestingKit))
frameworks_search_paths = xcconfig.framework_search_paths
frameworks_search_paths.should == %w($(PLATFORM_DIR)/Developer/Library/Frameworks)
end
it 'adds the developer frameworks search paths to the xcconfig if XCTest has been detected' do
xcconfig = BuildSettings.new(stub('Target'))
xcconfig.stubs(:frameworks => %w(XCTest))
frameworks_search_paths = xcconfig.framework_search_paths
frameworks_search_paths.should == %w($(PLATFORM_DIR)/Developer/Library/Frameworks)
end
end
#---------------------------------------------------------------------#
describe '::add_language_specific_settings' do
it 'does not add OTHER_SWIFT_FLAGS to the xcconfig if the target does not use swift' do
target = fixture_pod_target('integration/Reachability/Reachability.podspec')
build_settings = pod(target)
other_swift_flags = build_settings.xcconfig.to_hash['OTHER_SWIFT_FLAGS']
other_swift_flags.should.be.nil
end
it 'does not add the -suppress-warnings flag to the xcconfig if the target uses swift, but does not inhibit warnings' do
target = fixture_pod_target('integration/Reachability/Reachability.podspec')
target.stubs(:uses_swift? => true, :inhibit_warnings? => false)
build_settings = pod(target)
other_swift_flags = build_settings.xcconfig.to_hash['OTHER_SWIFT_FLAGS']
other_swift_flags.should.not.include '-suppress-warnings'
end
it 'adds the -suppress-warnings flag to the xcconfig if the target uses swift and inhibits warnings' do
target = fixture_pod_target('integration/Reachability/Reachability.podspec')
target.stubs(:uses_swift? => true, :inhibit_warnings? => true)
build_settings = pod(target)
other_swift_flags = build_settings.xcconfig.to_hash['OTHER_SWIFT_FLAGS']
other_swift_flags.should.include '-suppress-warnings'
end
end
#---------------------------------------------------------------------#
describe 'concerning settings for file accessors' do
it 'does not propagate framework or libraries from a test specification to an aggregate target' do
target_definition = stub('target_definition', :inheritance => 'complete', :abstract? => false, :podfile => Podfile.new)
spec = stub('spec', :test_specification? => true)
consumer = stub('consumer',
:libraries => ['xml2'],
:frameworks => ['XCTest'],
:weak_frameworks => [],
:spec => spec,
)
file_accessor = stub('file_accessor',
:spec => spec,
:spec_consumer => consumer,
:vendored_static_frameworks => [config.sandbox.root + 'StaticFramework.framework'],
:vendored_static_libraries => [config.sandbox.root + 'StaticLibrary.a'],
:vendored_dynamic_frameworks => [config.sandbox.root + 'VendoredFramework.framework'],
:vendored_dynamic_libraries => [config.sandbox.root + 'VendoredDyld.dyld'],
)
pod_target = stub('pod_target',
:file_accessors => [file_accessor],
:requires_frameworks? => true,
:dependent_targets => [],
:recursive_dependent_targets => [],
:sandbox => config.sandbox,
:include_in_build_config? => true,
:should_build? => false,
:spec_consumers => [consumer],
:static_framework? => false,
:product_basename => 'PodTarget',
:target_definitions => [target_definition],
)
pod_target.stubs(:build_settings => pod(pod_target))
aggregate_target = fixture_aggregate_target([pod_target])
aggregate(aggregate_target).other_ldflags.should.not.include '-framework'
end
end
#---------------------------------------------------------------------#
end
end
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment