Unverified Commit 8307a689 authored by Dimitris Koutsogiorgas's avatar Dimitris Koutsogiorgas Committed by GitHub

Merge pull request #7412 from dnkoutso/strict_header_search_paths

Add support for modular header search paths, include "legacy" support
parents 31b2b9cb 95d59b9d
...@@ -8,6 +8,10 @@ To install release candidates run `[sudo] gem install cocoapods --pre` ...@@ -8,6 +8,10 @@ To install release candidates run `[sudo] gem install cocoapods --pre`
##### Enhancements ##### Enhancements
* Add support for modular header search paths, include "legacy" support.
[Dimitris Koutsogiorgas](https://github.com/dnkoutso)
[#7412](https://github.com/CocoaPods/CocoaPods/pull/7412)
* Set direct and transitive dependency header search paths for pod targets * Set direct and transitive dependency header search paths for pod targets
[Dimitris Koutsogiorgas](https://github.com/dnkoutso) [Dimitris Koutsogiorgas](https://github.com/dnkoutso)
[#7116](https://github.com/CocoaPods/CocoaPods/pull/7116) [#7116](https://github.com/CocoaPods/CocoaPods/pull/7116)
......
...@@ -7,7 +7,7 @@ GIT ...@@ -7,7 +7,7 @@ GIT
GIT GIT
remote: https://github.com/CocoaPods/Core.git remote: https://github.com/CocoaPods/Core.git
revision: 1f8ced657a224eabeba6958d130ee04058d91f60 revision: e0c6884b37ab6a44095a2bbdbfe9032627a90388
branch: master branch: master
specs: specs:
cocoapods-core (1.4.0) cocoapods-core (1.4.0)
......
...@@ -163,11 +163,11 @@ module Pod ...@@ -163,11 +163,11 @@ module Pod
private private
# Add build settings, which ensure that the pod targets can be imported # Add build settings, which ensure that the pod targets can be imported from the integrating target.
# from the integrating target by all sort of imports, which are: # For >= 1.5.0 we use modular (stricter) header search paths this means that the integrated target will only be
# - `#import <…>` # able to import public headers using `<>` or `@import` notation, but never import any private headers.
# - `#import "…"` #
# - `@import …;` / `import …` # For < 1.5.0 legacy header search paths the same rules apply: It's the wild west.
# #
def generate_settings_to_import_pod_targets def generate_settings_to_import_pod_targets
@xcconfig.merge! XCConfigHelper.search_paths_for_dependent_targets(target, pod_targets) @xcconfig.merge! XCConfigHelper.search_paths_for_dependent_targets(target, pod_targets)
...@@ -176,7 +176,6 @@ module Pod ...@@ -176,7 +176,6 @@ module Pod
generator = AggregateXCConfig.new(search_paths_target, configuration_name) generator = AggregateXCConfig.new(search_paths_target, configuration_name)
@xcconfig.merge! XCConfigHelper.search_paths_for_dependent_targets(nil, search_paths_target.pod_targets) @xcconfig.merge! XCConfigHelper.search_paths_for_dependent_targets(nil, search_paths_target.pod_targets)
@xcconfig.merge!(generator.settings_to_import_pod_targets) @xcconfig.merge!(generator.settings_to_import_pod_targets)
# Propagate any HEADER_SEARCH_PATHS settings from the search paths. # Propagate any HEADER_SEARCH_PATHS settings from the search paths.
XCConfigHelper.propagate_header_search_paths_from_search_paths(search_paths_target, @xcconfig) XCConfigHelper.propagate_header_search_paths_from_search_paths(search_paths_target, @xcconfig)
end end
......
...@@ -147,11 +147,15 @@ module Pod ...@@ -147,11 +147,15 @@ module Pod
pod_target.build_headers.add_search_path(headers_sandbox, pod_target.platform) pod_target.build_headers.add_search_path(headers_sandbox, pod_target.platform)
sandbox.public_headers.add_search_path(headers_sandbox, pod_target.platform) sandbox.public_headers.add_search_path(headers_sandbox, pod_target.platform)
# Private headers will always end up in Pods/Headers/Private/PodA/*.h
# This will allow for `""` imports to work.
header_mappings(headers_sandbox, file_accessor, file_accessor.headers).each do |namespaced_path, files| header_mappings(headers_sandbox, file_accessor, file_accessor.headers).each do |namespaced_path, files|
pod_target.build_headers.add_files(namespaced_path, files.reject { |f| f.to_path =~ framework_exp }) pod_target.build_headers.add_files(namespaced_path, files.reject { |f| f.to_path =~ framework_exp })
end end
header_mappings(headers_sandbox, file_accessor, file_accessor.public_headers).each do |namespaced_path, files| # Public headers on the other hand will be added in Pods/Headers/Public/PodA/PodA/*.h
# The extra folder is intentional in order for `<>` imports to work.
header_mappings(headers_sandbox, file_accessor, file_accessor.public_headers, :public).each do |namespaced_path, files|
sandbox.public_headers.add_files(namespaced_path, files.reject { |f| f.to_path =~ framework_exp }) sandbox.public_headers.add_files(namespaced_path, files.reject { |f| f.to_path =~ framework_exp })
end end
end end
...@@ -295,6 +299,10 @@ module Pod ...@@ -295,6 +299,10 @@ module Pod
# The consumer file accessor for which the headers need to be # The consumer file accessor for which the headers need to be
# linked. # linked.
# #
# @param [Symbol] visibility_scope
# The visibility scope to produce header mappings for. If set to :public then the headers
# are nested an additional level deep. For example, 'Pods/Headers/Public/PodA/PodA'.
#
# @param [Array<Pathname>] headers # @param [Array<Pathname>] headers
# The absolute paths of the headers which need to be mapped. # The absolute paths of the headers which need to be mapped.
# #
...@@ -302,17 +310,18 @@ module Pod ...@@ -302,17 +310,18 @@ module Pod
# headers folders as the keys and the absolute paths of the # headers folders as the keys and the absolute paths of the
# header files as the values. # header files as the values.
# #
def header_mappings(headers_sandbox, file_accessor, headers) def header_mappings(headers_sandbox, file_accessor, headers, visibility_scope = :private)
consumer = file_accessor.spec_consumer consumer = file_accessor.spec_consumer
header_mappings_dir = consumer.header_mappings_dir
dir = headers_sandbox dir = headers_sandbox
dir += headers_sandbox if visibility_scope == :public
dir += consumer.header_dir if consumer.header_dir dir += consumer.header_dir if consumer.header_dir
mappings = {} mappings = {}
headers.each do |header| headers.each do |header|
sub_dir = dir sub_dir = dir
if consumer.header_mappings_dir if header_mappings_dir
header_mappings_dir = file_accessor.path_list.root + consumer.header_mappings_dir relative_path = header.relative_path_from(file_accessor.path_list.root + header_mappings_dir)
relative_path = header.relative_path_from(header_mappings_dir)
sub_dir += relative_path.dirname sub_dir += relative_path.dirname
end end
mappings[sub_dir] ||= [] mappings[sub_dir] ||= []
......
...@@ -57,7 +57,7 @@ module Pod ...@@ -57,7 +57,7 @@ module Pod
def initialize(root) def initialize(root)
FileUtils.mkdir_p(root) FileUtils.mkdir_p(root)
@root = Pathname.new(root).realpath @root = Pathname.new(root).realpath
@public_headers = HeadersStore.new(self, 'Public') @public_headers = HeadersStore.new(self, 'Public', :public)
@predownloaded_pods = [] @predownloaded_pods = []
@checkout_sources = {} @checkout_sources = {}
@development_pods = {} @development_pods = {}
......
...@@ -4,7 +4,7 @@ module Pod ...@@ -4,7 +4,7 @@ module Pod
# the header search paths. # the header search paths.
# #
class HeadersStore class HeadersStore
SEARCH_PATHS_KEY = Struct.new(:platform_name, :target_name) SEARCH_PATHS_KEY = Struct.new(:platform_name, :target_name, :use_modular_headers)
# @return [Pathname] the absolute path of this header directory. # @return [Pathname] the absolute path of this header directory.
# #
...@@ -22,36 +22,48 @@ module Pod ...@@ -22,36 +22,48 @@ module Pod
# the relative path to the sandbox root and hence to the Pods # the relative path to the sandbox root and hence to the Pods
# project. # project.
# #
def initialize(sandbox, relative_path) # @param [Symbol] visibility_scope
# the header visibility scope to use in this store. Can be `:private` or `:public`.
#
def initialize(sandbox, relative_path, visibility_scope)
@sandbox = sandbox @sandbox = sandbox
@relative_path = relative_path @relative_path = relative_path
@search_paths = [] @search_paths = []
@search_paths_cache = {} @search_paths_cache = {}
@visibility_scope = visibility_scope
end end
# @param [Platform] platform # @param [Platform] platform
# the platform for which the header search paths should be # the platform for which the header search paths should be
# returned # returned.
# #
# @param [String] target_name # @param [String] target_name
# the target for which the header search paths should be # the target for which the header search paths should be
# returned. This will return only header root scope e.g. `${PODS_ROOT}/Headers/Public` # returned. Can be `nil` in which case all headers that match the platform
# if the target name specified is `nil`. # will be returned.
#
# @param [Boolean] use_modular_headers
# whether the search paths generated should use modular (stricter) style.
# #
# @return [Array<String>] All the search paths of the header directory in # @return [Array<String>] All the search paths of the header directory in
# xcconfig format. The paths are specified relative to the pods # xcconfig format. The paths are specified relative to the pods
# root with the `${PODS_ROOT}` variable. # root with the `${PODS_ROOT}` variable.
# #
def search_paths(platform, target_name = nil) def search_paths(platform, target_name = nil, use_modular_headers = false)
key = SEARCH_PATHS_KEY.new(platform.name, target_name) key = SEARCH_PATHS_KEY.new(platform.name, target_name, use_modular_headers)
return @search_paths_cache[key] if @search_paths_cache.key?(key) return @search_paths_cache[key] if @search_paths_cache.key?(key)
platform_search_paths = @search_paths.select do |entry| search_paths = @search_paths.select do |entry|
matches_platform = entry[:platform] == platform.name matches_platform = entry[:platform] == platform.name
matches_target = target_name.nil? || (entry[:path].basename.to_s == target_name) matches_target = target_name.nil? || (entry[:path].basename.to_s == target_name)
matches_platform && matches_target matches_platform && matches_target
end end
headers_dir = root.relative_path_from(sandbox.root).dirname headers_dir = root.relative_path_from(sandbox.root).dirname
@search_paths_cache[key] = ["${PODS_ROOT}/#{headers_dir}/#{@relative_path}"] + platform_search_paths.uniq.map { |entry| "${PODS_ROOT}/#{headers_dir}/#{entry[:path]}" } @search_paths_cache[key] = search_paths.uniq.flat_map do |entry|
path = "${PODS_ROOT}/#{headers_dir}/#{entry[:path]}"
paths = [path]
paths.push("#{path}/#{entry[:path].basename}") if !use_modular_headers && @visibility_scope == :public
paths
end
end end
# Removes the directory as it is regenerated from scratch during each # Removes the directory as it is regenerated from scratch during each
......
...@@ -54,7 +54,7 @@ module Pod ...@@ -54,7 +54,7 @@ module Pod
@target_definitions = target_definitions @target_definitions = target_definitions
@sandbox = sandbox @sandbox = sandbox
@scope_suffix = scope_suffix @scope_suffix = scope_suffix
@build_headers = Sandbox::HeadersStore.new(sandbox, 'Private') @build_headers = Sandbox::HeadersStore.new(sandbox, 'Private', :private)
@file_accessors = [] @file_accessors = []
@resource_bundle_targets = [] @resource_bundle_targets = []
@test_resource_bundle_targets = [] @test_resource_bundle_targets = []
...@@ -195,6 +195,20 @@ module Pod ...@@ -195,6 +195,20 @@ module Pod
end end
end end
# @return [Boolean] Whether the target defines a "module"
# (and thus will need a module map and umbrella header).
#
# @note Static library targets can temporarily opt in to this behavior by setting
# `DEFINES_MODULE = YES` in their specification's `pod_target_xcconfig`.
#
def defines_module?
return @defines_module if defined?(@defines_module)
return @defines_module = true if uses_swift? || requires_frameworks?
return @defines_module = true if target_definitions.any? { |td| td.build_pod_as_module?(pod_name) }
@defines_module = non_test_specs.any? { |s| s.consumer(platform).pod_target_xcconfig['DEFINES_MODULE'] == 'YES' }
end
# @return [Array<Hash{Symbol=>String}>] An array of hashes where each hash represents a single script phase. # @return [Array<Hash{Symbol=>String}>] An array of hashes where each hash represents a single script phase.
# #
def script_phases def script_phases
...@@ -224,7 +238,7 @@ module Pod ...@@ -224,7 +238,7 @@ module Pod
# #
attr_reader :test_specs attr_reader :test_specs
# @return [Array<Specification>] All of the non test specs within this target. # @return [Array<Specification>] All of the specs within this target that are not test specs.
# #
attr_reader :non_test_specs attr_reader :non_test_specs
...@@ -572,16 +586,33 @@ module Pod ...@@ -572,16 +586,33 @@ module Pod
# #
def header_search_paths(include_test_dependent_targets = false) def header_search_paths(include_test_dependent_targets = false)
header_search_paths = [] header_search_paths = []
header_search_paths.concat(build_headers.search_paths(platform)) header_search_paths.concat(build_headers.search_paths(platform, nil, uses_modular_headers?))
header_search_paths.concat(sandbox.public_headers.search_paths(platform, pod_name)) header_search_paths.concat(sandbox.public_headers.search_paths(platform, pod_name, uses_modular_headers?))
dependent_targets = recursive_dependent_targets dependent_targets = recursive_dependent_targets
dependent_targets += recursive_test_dependent_targets if include_test_dependent_targets dependent_targets += recursive_test_dependent_targets if include_test_dependent_targets
dependent_targets.each do |dependent_target| dependent_targets.each do |dependent_target|
header_search_paths.concat(sandbox.public_headers.search_paths(platform, dependent_target.pod_name)) header_search_paths.concat(sandbox.public_headers.search_paths(platform, dependent_target.pod_name, defines_module? && dependent_target.uses_modular_headers?(false)))
end end
header_search_paths.uniq header_search_paths.uniq
end end
protected
# Returns whether the pod target should use modular headers.
#
# @param [Boolean] only_if_defines_modules
# whether the use of modular headers should require the target to define a module
#
# @note This must return false when a pod has a `header_mappings_dir`,
# as that allows the spec to completely customize the header structure, and
# therefore it might not be expecting the module name to be prepended
# to imports at all.
#
def uses_modular_headers?(only_if_defines_modules = true)
return false if only_if_defines_modules && !defines_module?
spec_consumers.none?(&:header_mappings_dir)
end
private private
# @param [TargetDefinition] target_definition # @param [TargetDefinition] target_definition
......
Subproject commit 4bb5eeef8cb713fc2e0abe51f79716d0edceb019 Subproject commit b21c05141a790ac307a0ff605d2015e58c173889
...@@ -279,6 +279,11 @@ describe_cli 'pod' do ...@@ -279,6 +279,11 @@ describe_cli 'pod' do
'install --no-repo-update' 'install --no-repo-update'
end end
describe 'Integrates a Pod with a header mappings directory' do
behaves_like cli_spec 'install_header_mappings_dir',
'install --no-repo-update'
end
describe 'Integrates a Pod using non Objective-C source files' do describe 'Integrates a Pod using non Objective-C source files' do
behaves_like cli_spec 'install_non_objective_c_files', behaves_like cli_spec 'install_non_objective_c_files',
'install --no-repo-update' 'install --no-repo-update'
......
...@@ -126,6 +126,10 @@ module Pod ...@@ -126,6 +126,10 @@ module Pod
#-----------------------------------------------------------------------# #-----------------------------------------------------------------------#
describe 'with library' do describe 'with library' do
before do
config.sandbox.public_headers.stubs(:search_paths).returns(['${PODS_ROOT}/Headers/Public/BananaLib'])
end
def specs def specs
[fixture_spec('banana-lib/BananaLib.podspec')] [fixture_spec('banana-lib/BananaLib.podspec')]
end end
...@@ -137,12 +141,12 @@ module Pod ...@@ -137,12 +141,12 @@ module Pod
end end
it 'adds the sandbox public headers search paths to the xcconfig, with quotes, as header search paths' do it 'adds the sandbox public headers search paths to the xcconfig, with quotes, as header search paths' do
expected = "$(inherited) \"#{config.sandbox.public_headers.search_paths(Platform.ios).join('" "')}\"" expected = '$(inherited) "${PODS_ROOT}/Headers/Public/BananaLib"'
@xcconfig.to_hash['HEADER_SEARCH_PATHS'].should == expected @xcconfig.to_hash['HEADER_SEARCH_PATHS'].should == expected
end end
it 'adds the sandbox public headers search paths to the xcconfig, with quotes, as system headers' do it 'adds the sandbox public headers search paths to the xcconfig, with quotes, as system headers' do
expected = "$(inherited) -isystem \"#{config.sandbox.public_headers.search_paths(Platform.ios).join('" -isystem "')}\"" expected = '$(inherited) -isystem "${PODS_ROOT}/Headers/Public/BananaLib"'
@xcconfig.to_hash['OTHER_CFLAGS'].should == expected @xcconfig.to_hash['OTHER_CFLAGS'].should == expected
end end
...@@ -185,6 +189,10 @@ module Pod ...@@ -185,6 +189,10 @@ module Pod
end end
describe 'with a vendored-library pod' do describe 'with a vendored-library pod' do
before do
config.sandbox.public_headers.stubs(:search_paths).returns(['${PODS_ROOT}/Headers/Public/monkey'])
end
def specs def specs
[fixture_spec('monkey/monkey.podspec')] [fixture_spec('monkey/monkey.podspec')]
end end
...@@ -199,23 +207,26 @@ module Pod ...@@ -199,23 +207,26 @@ module Pod
it 'does not include framework header paths as local headers for pods that are linked statically' do it 'does not include framework header paths as local headers for pods that are linked statically' do
monkey_headers = '-iquote "${PODS_CONFIGURATION_BUILD_DIR}/monkey.framework/Headers"' monkey_headers = '-iquote "${PODS_CONFIGURATION_BUILD_DIR}/monkey.framework/Headers"'
@xcconfig = @generator.generate
@xcconfig.to_hash['OTHER_CFLAGS'].should.not.include monkey_headers @xcconfig.to_hash['OTHER_CFLAGS'].should.not.include monkey_headers
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"' expected = '$(inherited) -iquote "${PODS_CONFIGURATION_BUILD_DIR}/OrangeFramework/OrangeFramework.framework/Headers" -isystem "${PODS_ROOT}/Headers/Public/monkey"'
@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
end end
it 'includes the public header paths as user headers' do it 'includes the public header paths as user headers' do
expected = '${PODS_ROOT}/Headers/Public' expected = '${PODS_ROOT}/Headers/Public/monkey'
@xcconfig = @generator.generate
@xcconfig.to_hash['HEADER_SEARCH_PATHS'].should.include expected @xcconfig.to_hash['HEADER_SEARCH_PATHS'].should.include expected
end end
it 'includes $(inherited) in the header search paths' do it 'includes $(inherited) in the header search paths' do
expected = '$(inherited)' expected = '$(inherited)'
@xcconfig = @generator.generate
@xcconfig.to_hash['HEADER_SEARCH_PATHS'].should.include expected @xcconfig.to_hash['HEADER_SEARCH_PATHS'].should.include expected
end end
......
...@@ -11,6 +11,7 @@ module Pod ...@@ -11,6 +11,7 @@ module Pod
vspec = stub(:test_specification? => false) vspec = stub(:test_specification? => false)
consumer = stub( consumer = stub(
"Spec Consumer (#{vspec} iOS)",
:pod_target_xcconfig => {}, :pod_target_xcconfig => {},
:libraries => ['xml2'], :libraries => ['xml2'],
:frameworks => [], :frameworks => [],
...@@ -18,6 +19,7 @@ module Pod ...@@ -18,6 +19,7 @@ module Pod
:platform_name => :ios, :platform_name => :ios,
) )
file_accessor = stub( file_accessor = stub(
'File Accessor',
:spec => vspec, :spec => vspec,
:spec_consumer => consumer, :spec_consumer => consumer,
:vendored_static_frameworks => [config.sandbox.root + 'AAA/StaticFramework.framework'], :vendored_static_frameworks => [config.sandbox.root + 'AAA/StaticFramework.framework'],
...@@ -26,6 +28,7 @@ module Pod ...@@ -26,6 +28,7 @@ module Pod
:vendored_dynamic_libraries => [config.sandbox.root + 'DDD/VendoredDyld.dyld'], :vendored_dynamic_libraries => [config.sandbox.root + 'DDD/VendoredDyld.dyld'],
) )
vendored_dep_target = stub( vendored_dep_target = stub(
'Vendored Dependent Target',
:name => 'BananaLib', :name => 'BananaLib',
:pod_name => 'BananaLib', :pod_name => 'BananaLib',
:sandbox => config.sandbox, :sandbox => config.sandbox,
...@@ -34,6 +37,7 @@ module Pod ...@@ -34,6 +37,7 @@ module Pod
:static_framework? => false, :static_framework? => false,
:dependent_targets => [], :dependent_targets => [],
:file_accessors => [file_accessor], :file_accessors => [file_accessor],
:uses_modular_headers? => false,
) )
@spec = fixture_spec('banana-lib/BananaLib.podspec') @spec = fixture_spec('banana-lib/BananaLib.podspec')
...@@ -133,11 +137,8 @@ module Pod ...@@ -133,11 +137,8 @@ module Pod
@xcconfig.to_hash['PODS_TARGET_SRCROOT'].should == '${PODS_ROOT}/../../spec/fixtures/banana-lib' @xcconfig.to_hash['PODS_TARGET_SRCROOT'].should == '${PODS_ROOT}/../../spec/fixtures/banana-lib'
end end
it 'adds the library build headers and public headers search paths to the xcconfig, with quotes' do it 'does not add root public or private header search paths to the xcconfig' do
private_headers = "\"#{@pod_target.build_headers.search_paths(Platform.new(:ios)).join('" "')}\"" @xcconfig.to_hash['HEADER_SEARCH_PATHS'].should.be.empty
public_headers = "\"#{config.sandbox.public_headers.search_paths(Platform.new(:ios)).join('" "')}\""
@xcconfig.to_hash['HEADER_SEARCH_PATHS'].should.include private_headers
@xcconfig.to_hash['HEADER_SEARCH_PATHS'].should.include public_headers
end end
it 'adds the COCOAPODS macro definition' do it 'adds the COCOAPODS macro definition' do
...@@ -269,8 +270,10 @@ module Pod ...@@ -269,8 +270,10 @@ module Pod
@coconut_pod_target.dependent_targets = [@banana_pod_target] @coconut_pod_target.dependent_targets = [@banana_pod_target]
generator = PodXCConfig.new(@coconut_pod_target, true) generator = PodXCConfig.new(@coconut_pod_target, true)
xcconfig = generator.generate xcconfig = generator.generate
xcconfig.to_hash['HEADER_SEARCH_PATHS'].should == '"${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/CoconutLib"' \ xcconfig.to_hash['HEADER_SEARCH_PATHS'].should == '"${PODS_ROOT}/Headers/Private/CoconutLib"' \
' "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/BananaLib" "${PODS_ROOT}/Headers/Public/CoconutLib" "${PODS_ROOT}/Headers/Public/monkey"' ' "${PODS_ROOT}/Headers/Public/BananaLib" "${PODS_ROOT}/Headers/Public/BananaLib/BananaLib"' \
' "${PODS_ROOT}/Headers/Public/CoconutLib" "${PODS_ROOT}/Headers/Public/CoconutLib/CoconutLib"' \
' "${PODS_ROOT}/Headers/Public/monkey" "${PODS_ROOT}/Headers/Public/monkey/monkey"'
end end
it 'adds correct header search paths for dependent and test targets for non test xcconfigs' do it 'adds correct header search paths for dependent and test targets for non test xcconfigs' do
...@@ -285,8 +288,9 @@ module Pod ...@@ -285,8 +288,9 @@ module Pod
# 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 = PodXCConfig.new(@coconut_pod_target, false)
xcconfig = generator.generate xcconfig = generator.generate
xcconfig.to_hash['HEADER_SEARCH_PATHS'].should == '"${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/CoconutLib"' \ xcconfig.to_hash['HEADER_SEARCH_PATHS'].should == '"${PODS_ROOT}/Headers/Private/CoconutLib"' \
' "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/BananaLib" "${PODS_ROOT}/Headers/Public/CoconutLib"' ' "${PODS_ROOT}/Headers/Public/BananaLib" "${PODS_ROOT}/Headers/Public/BananaLib/BananaLib"' \
' "${PODS_ROOT}/Headers/Public/CoconutLib" "${PODS_ROOT}/Headers/Public/CoconutLib/CoconutLib"'
end end
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
......
...@@ -84,7 +84,7 @@ module Pod ...@@ -84,7 +84,7 @@ module Pod
it 'links the public headers meant for the user' do it 'links the public headers meant for the user' do
@installer.install! @installer.install!
headers_root = config.sandbox.public_headers.root headers_root = config.sandbox.public_headers.root
public_headers = [headers_root + 'BananaLib/Banana.h', headers_root + 'BananaLib/MoreBanana.h'] public_headers = [headers_root + 'BananaLib/BananaLib/Banana.h', headers_root + 'BananaLib/BananaLib/MoreBanana.h']
private_header = headers_root + 'BananaLib/BananaPrivate.h' private_header = headers_root + 'BananaLib/BananaPrivate.h'
framework_header = headers_root + 'BananaLib/Bananalib/Bananalib.h' framework_header = headers_root + 'BananaLib/Bananalib/Bananalib.h'
framework_subdir_header = headers_root + 'BananaLib/Bananalib/SubDir/SubBananalib.h' framework_subdir_header = headers_root + 'BananaLib/Bananalib/SubDir/SubBananalib.h'
...@@ -106,7 +106,7 @@ module Pod ...@@ -106,7 +106,7 @@ module Pod
headers_root = config.sandbox.public_headers.root headers_root = config.sandbox.public_headers.root
banana_headers = [headers_root + 'BananaLib/Banana.h', headers_root + 'BananaLib/MoreBanana.h'] banana_headers = [headers_root + 'BananaLib/Banana.h', headers_root + 'BananaLib/MoreBanana.h']
banana_headers.each { |banana_header| banana_header.should.not.exist } banana_headers.each { |banana_header| banana_header.should.not.exist }
monkey_header = headers_root + 'monkey/monkey.h' monkey_header = headers_root + 'monkey/monkey/monkey.h'
monkey_header.should.exist monkey_header.should.exist
end end
...@@ -206,22 +206,32 @@ module Pod ...@@ -206,22 +206,32 @@ module Pod
end end
describe '#header_mappings' do describe '#header_mappings' do
it 'returns the header mappings' do it 'returns the correct public header mappings' do
headers_sandbox = Pathname.new('BananaLib') headers_sandbox = Pathname.new('BananaLib')
headers = [Pathname.new('BananaLib/Banana.h')] headers = [Pathname.new('Banana.h')]
mappings = @installer.send(:header_mappings, headers_sandbox, @file_accessor, headers) mappings = @installer.send(:header_mappings, headers_sandbox, @file_accessor, headers, :public)
mappings.should == {
Pathname.new('BananaLib/BananaLib') => [Pathname.new('Banana.h')],
}
end
it 'takes into account the header dir specified in the spec for public headers' do
headers_sandbox = Pathname.new('BananaLib')
headers = [Pathname.new('Banana.h')]
@file_accessor.spec_consumer.stubs(:header_dir).returns('Sub_dir')
mappings = @installer.send(:header_mappings, headers_sandbox, @file_accessor, headers, :public)
mappings.should == { mappings.should == {
headers_sandbox => headers, Pathname.new('BananaLib/BananaLib/Sub_dir') => [Pathname.new('Banana.h')],
} }
end end
it 'takes into account the header dir specified in the spec' do it 'takes into account the header dir specified in the spec for private headers' do
headers_sandbox = Pathname.new('BananaLib') headers_sandbox = Pathname.new('BananaLib')
headers = [Pathname.new('BananaLib/Banana.h')] headers = [Pathname.new('Banana.h')]
@file_accessor.spec_consumer.stubs(:header_dir).returns('Sub_dir') @file_accessor.spec_consumer.stubs(:header_dir).returns('Sub_dir')
mappings = @installer.send(:header_mappings, headers_sandbox, @file_accessor, headers) mappings = @installer.send(:header_mappings, headers_sandbox, @file_accessor, headers)
mappings.should == { mappings.should == {
(headers_sandbox + 'Sub_dir') => headers, Pathname.new('BananaLib/Sub_dir') => [Pathname.new('Banana.h')],
} }
end end
......
...@@ -4,11 +4,12 @@ module Pod ...@@ -4,11 +4,12 @@ module Pod
describe Sandbox::HeadersStore do describe Sandbox::HeadersStore do
before do before do
@sandbox = Pod::Sandbox.new(temporary_directory + 'Sandbox') @sandbox = Pod::Sandbox.new(temporary_directory + 'Sandbox')
@header_dir = Sandbox::HeadersStore.new(@sandbox, 'Public') @public_header_dir = Sandbox::HeadersStore.new(@sandbox, 'Public', :public)
@private_header_dir = Sandbox::HeadersStore.new(@sandbox, 'Private', :private)
end end
it "returns it's headers root" do it "returns it's headers root" do
@header_dir.root.should == temporary_directory + 'Sandbox/Headers/Public' @public_header_dir.root.should == temporary_directory + 'Sandbox/Headers/Public'
end end
it 'can add namespaced headers to its header path using symlinks and return the relative path' do it 'can add namespaced headers to its header path using symlinks and return the relative path' do
...@@ -21,7 +22,7 @@ module Pod ...@@ -21,7 +22,7 @@ module Pod
relative_header_paths.each do |path| relative_header_paths.each do |path|
File.open(@sandbox.root + path, 'w') { |file| file.write('hello') } File.open(@sandbox.root + path, 'w') { |file| file.write('hello') }
end end
symlink_paths = @header_dir.add_files(namespace_path, relative_header_paths) symlink_paths = @public_header_dir.add_files(namespace_path, relative_header_paths)
symlink_paths.each do |path| symlink_paths.each do |path|
path.should.be.symlink path.should.be.symlink
File.read(path).should == 'hello' File.read(path).should == 'hello'
...@@ -39,35 +40,75 @@ module Pod ...@@ -39,35 +40,75 @@ module Pod
File.open(@sandbox.root + path, 'w') { |file| file.write('hello') } File.open(@sandbox.root + path, 'w') { |file| file.write('hello') }
end end
fake_platform = mock(:name => 'fake_platform') fake_platform = mock(:name => 'fake_platform')
@header_dir.add_files(namespace_path, relative_header_paths) @public_header_dir.add_files(namespace_path, relative_header_paths)
@header_dir.search_paths(fake_platform).should.not.include('${PODS_ROOT}/Headers/Public/ExampleLib') @public_header_dir.search_paths(fake_platform).should.not.include('${PODS_ROOT}/Headers/Public/ExampleLib')
end end
it 'always adds the Headers root to the header search paths' do describe 'non modular header search paths' do
fake_platform = mock(:name => 'fake_platform') it 'returns the correct public header search paths for the given platform' do
@header_dir.search_paths(fake_platform).should.include('${PODS_ROOT}/Headers/Public') @public_header_dir.add_search_path('iOS Search Path', Platform.ios)
end @public_header_dir.add_search_path('OS X Search Path', Platform.osx)
@public_header_dir.search_paths(Platform.ios).sort.should == [
'${PODS_ROOT}/Headers/Public/iOS Search Path',
'${PODS_ROOT}/Headers/Public/iOS Search Path/iOS Search Path',
]
end
it 'only exposes header search paths for the given platform' do it 'returns the correct public header search paths given platform and target' do
@header_dir.add_search_path('iOS Search Path', Platform.ios) @public_header_dir.add_search_path('ios-target', Platform.ios)
@header_dir.add_search_path('OS X Search Path', Platform.osx) @public_header_dir.add_search_path('osx-target', Platform.osx)
@header_dir.search_paths(Platform.ios).sort.should == [ @public_header_dir.search_paths(Platform.ios, 'ios-target').sort.should == [
'${PODS_ROOT}/Headers/Public', '${PODS_ROOT}/Headers/Public/ios-target',
'${PODS_ROOT}/Headers/Public/iOS Search Path', '${PODS_ROOT}/Headers/Public/ios-target/ios-target',
] ]
@public_header_dir.search_paths(Platform.osx, 'osx-target').sort.should == [
'${PODS_ROOT}/Headers/Public/osx-target',
'${PODS_ROOT}/Headers/Public/osx-target/osx-target',
]
end
it 'returns the correct private header search paths given platform and target' do
@private_header_dir.add_search_path('ios-target', Platform.ios)
@private_header_dir.add_search_path('osx-target', Platform.osx)
@private_header_dir.search_paths(Platform.ios, 'ios-target', false).sort.should == [
'${PODS_ROOT}/Headers/Private/ios-target',
]
@private_header_dir.search_paths(Platform.osx, 'osx-target', false).sort.should == [
'${PODS_ROOT}/Headers/Private/osx-target',
]
end
end end
it 'returns the correct header search paths given platform and target' do describe 'modular header search paths' do
@header_dir.add_search_path('ios-target', Platform.ios) it 'returns the correct public header search paths for the given platform' do
@header_dir.add_search_path('osx-target', Platform.osx) @public_header_dir.add_search_path('iOS Search Path', Platform.ios)
@header_dir.search_paths(Platform.ios, 'ios-target').sort.should == [ @public_header_dir.add_search_path('OS X Search Path', Platform.osx)
'${PODS_ROOT}/Headers/Public', @public_header_dir.search_paths(Platform.ios, nil, true).sort.should == [
'${PODS_ROOT}/Headers/Public/ios-target', '${PODS_ROOT}/Headers/Public/iOS Search Path',
] ]
@header_dir.search_paths(Platform.osx, 'osx-target').sort.should == [ end
'${PODS_ROOT}/Headers/Public',
'${PODS_ROOT}/Headers/Public/osx-target', it 'returns the correct public header search paths given platform and target' do
] @public_header_dir.add_search_path('ios-target', Platform.ios)
@public_header_dir.add_search_path('osx-target', Platform.osx)
@public_header_dir.search_paths(Platform.ios, 'ios-target', true).sort.should == [
'${PODS_ROOT}/Headers/Public/ios-target',
]
@public_header_dir.search_paths(Platform.osx, 'osx-target', true).sort.should == [
'${PODS_ROOT}/Headers/Public/osx-target',
]
end
it 'returns the correct private header search paths given platform and target' do
@private_header_dir.add_search_path('ios-target', Platform.ios)
@private_header_dir.add_search_path('osx-target', Platform.osx)
@private_header_dir.search_paths(Platform.ios, 'ios-target', true).sort.should == [
'${PODS_ROOT}/Headers/Private/ios-target',
]
@private_header_dir.search_paths(Platform.osx, 'osx-target', true).sort.should == [
'${PODS_ROOT}/Headers/Private/osx-target',
]
end
end end
end end
end end
...@@ -234,52 +234,113 @@ module Pod ...@@ -234,52 +234,113 @@ module Pod
@pod_target.prefix_header_path.to_s.should.include 'Pods/Target Support Files/BananaLib/BananaLib-prefix.pch' @pod_target.prefix_header_path.to_s.should.include 'Pods/Target Support Files/BananaLib/BananaLib-prefix.pch'
end end
it 'returns the correct header search paths' do describe 'non modular header search paths' do
@pod_target.build_headers.add_search_path('BananaLib', Platform.ios) it 'returns the correct search paths' do
@pod_target.sandbox.public_headers.add_search_path('BananaLib', Platform.ios) @pod_target.build_headers.add_search_path('BananaLib', Platform.ios)
header_search_paths = @pod_target.header_search_paths @pod_target.sandbox.public_headers.add_search_path('BananaLib', Platform.ios)
header_search_paths.sort.should == [ header_search_paths = @pod_target.header_search_paths
'${PODS_ROOT}/Headers/Private', header_search_paths.sort.should == [
'${PODS_ROOT}/Headers/Private/BananaLib', '${PODS_ROOT}/Headers/Private/BananaLib',
'${PODS_ROOT}/Headers/Public', '${PODS_ROOT}/Headers/Public/BananaLib',
'${PODS_ROOT}/Headers/Public/BananaLib', '${PODS_ROOT}/Headers/Public/BananaLib/BananaLib',
] ]
end end
it 'returns the correct header search paths recursively for dependent targets' do it 'returns the correct header search paths recursively for dependent targets' do
@pod_target.build_headers.add_search_path('BananaLib', Platform.ios) @pod_target.build_headers.add_search_path('BananaLib', Platform.ios)
@pod_target.sandbox.public_headers.add_search_path('BananaLib', Platform.ios) @pod_target.sandbox.public_headers.add_search_path('BananaLib', Platform.ios)
@pod_target.sandbox.public_headers.add_search_path('monkey', Platform.ios) @pod_target.sandbox.public_headers.add_search_path('monkey', Platform.ios)
monkey_spec = fixture_spec('monkey/monkey.podspec') monkey_spec = fixture_spec('monkey/monkey.podspec')
monkey_pod_target = PodTarget.new([monkey_spec], [@target_definition], config.sandbox) monkey_pod_target = PodTarget.new([monkey_spec], [@target_definition], config.sandbox)
monkey_pod_target.stubs(:platform).returns(Platform.ios) monkey_pod_target.stubs(:platform).returns(Platform.ios)
@pod_target.stubs(:dependent_targets).returns([monkey_pod_target]) @pod_target.stubs(:dependent_targets).returns([monkey_pod_target])
header_search_paths = @pod_target.header_search_paths header_search_paths = @pod_target.header_search_paths
header_search_paths.sort.should == [ header_search_paths.sort.should == [
'${PODS_ROOT}/Headers/Private', '${PODS_ROOT}/Headers/Private/BananaLib',
'${PODS_ROOT}/Headers/Private/BananaLib', '${PODS_ROOT}/Headers/Public/BananaLib',
'${PODS_ROOT}/Headers/Public', '${PODS_ROOT}/Headers/Public/BananaLib/BananaLib',
'${PODS_ROOT}/Headers/Public/BananaLib', '${PODS_ROOT}/Headers/Public/monkey',
'${PODS_ROOT}/Headers/Public/monkey', '${PODS_ROOT}/Headers/Public/monkey/monkey',
] ]
end end
it 'returns the correct header search paths recursively for dependent targets excluding platform' do it 'returns the correct header search paths recursively for dependent targets excluding platform' do
@pod_target.build_headers.add_search_path('BananaLib', Platform.ios) @pod_target.build_headers.add_search_path('BananaLib', Platform.ios)
@pod_target.sandbox.public_headers.add_search_path('BananaLib', Platform.ios) @pod_target.sandbox.public_headers.add_search_path('BananaLib', Platform.ios)
@pod_target.sandbox.public_headers.add_search_path('monkey', Platform.osx) @pod_target.sandbox.public_headers.add_search_path('monkey', Platform.osx)
monkey_spec = fixture_spec('monkey/monkey.podspec') monkey_spec = fixture_spec('monkey/monkey.podspec')
monkey_pod_target = PodTarget.new([monkey_spec], [@target_definition], config.sandbox) monkey_pod_target = PodTarget.new([monkey_spec], [@target_definition], config.sandbox)
monkey_pod_target.stubs(:platform).returns(Platform.ios) monkey_pod_target.stubs(:platform).returns(Platform.ios)
@pod_target.stubs(:dependent_targets).returns([monkey_pod_target]) @pod_target.stubs(:dependent_targets).returns([monkey_pod_target])
header_search_paths = @pod_target.header_search_paths header_search_paths = @pod_target.header_search_paths
# The monkey lib header search paths should not be present since they are only present in OSX. # The monkey lib header search paths should not be present since they are only present in OSX.
header_search_paths.sort.should == [ header_search_paths.sort.should == [
'${PODS_ROOT}/Headers/Private', '${PODS_ROOT}/Headers/Private/BananaLib',
'${PODS_ROOT}/Headers/Private/BananaLib', '${PODS_ROOT}/Headers/Public/BananaLib',
'${PODS_ROOT}/Headers/Public', '${PODS_ROOT}/Headers/Public/BananaLib/BananaLib',
'${PODS_ROOT}/Headers/Public/BananaLib', ]
] end
end
describe 'modular header search paths' do
before do
@pod_target.stubs(:defines_module?).returns(true)
end
it 'uses modular header search paths when specified in the podfile' do
@pod_target.unstub(:defines_module?)
@pod_target.target_definitions.first.stubs(:build_pod_as_module?).with('BananaLib').returns(true)
@pod_target.build_headers.add_search_path('BananaLib', Platform.ios)
@pod_target.sandbox.public_headers.add_search_path('BananaLib', Platform.ios)
header_search_paths = @pod_target.header_search_paths
header_search_paths.sort.should == [
'${PODS_ROOT}/Headers/Private/BananaLib',
'${PODS_ROOT}/Headers/Public/BananaLib',
]
end
it 'returns the correct header search paths' do
@pod_target.build_headers.add_search_path('BananaLib', Platform.ios)
@pod_target.sandbox.public_headers.add_search_path('BananaLib', Platform.ios)
header_search_paths = @pod_target.header_search_paths
header_search_paths.sort.should == [
'${PODS_ROOT}/Headers/Private/BananaLib',
'${PODS_ROOT}/Headers/Public/BananaLib',
]
end
it 'returns the correct header search paths recursively for dependent targets' do
@pod_target.build_headers.add_search_path('BananaLib', Platform.ios)
@pod_target.sandbox.public_headers.add_search_path('BananaLib', Platform.ios)
@pod_target.sandbox.public_headers.add_search_path('monkey', Platform.ios)
monkey_spec = fixture_spec('monkey/monkey.podspec')
monkey_pod_target = PodTarget.new([monkey_spec], [@target_definition], config.sandbox)
monkey_pod_target.stubs(:platform).returns(Platform.ios)
@pod_target.stubs(:dependent_targets).returns([monkey_pod_target])
header_search_paths = @pod_target.header_search_paths
header_search_paths.sort.should == [
'${PODS_ROOT}/Headers/Private/BananaLib',
'${PODS_ROOT}/Headers/Public/BananaLib',
'${PODS_ROOT}/Headers/Public/monkey',
]
end
it 'returns the correct header search paths recursively for dependent targets excluding platform' do
@pod_target.build_headers.add_search_path('BananaLib', Platform.ios)
@pod_target.sandbox.public_headers.add_search_path('BananaLib', Platform.ios)
@pod_target.sandbox.public_headers.add_search_path('monkey', Platform.osx)
monkey_spec = fixture_spec('monkey/monkey.podspec')
monkey_pod_target = PodTarget.new([monkey_spec], [@target_definition], config.sandbox)
monkey_pod_target.stubs(:platform).returns(Platform.ios)
@pod_target.stubs(:dependent_targets).returns([monkey_pod_target])
header_search_paths = @pod_target.header_search_paths
# The monkey lib header search paths should not be present since they are only present in OSX.
header_search_paths.sort.should == [
'${PODS_ROOT}/Headers/Private/BananaLib',
'${PODS_ROOT}/Headers/Public/BananaLib',
]
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