Commit fb622fcb authored by Dimitris Koutsogiorgas's avatar Dimitris Koutsogiorgas Committed by Samuel Giddins

Add support for modular header search paths, include "legacy" support

parent 31b2b9cb
...@@ -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)
......
...@@ -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,9 +310,10 @@ module Pod ...@@ -302,9 +310,10 @@ 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
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 = {}
......
...@@ -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,19 @@ module Pod ...@@ -195,6 +195,19 @@ 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?
@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 +237,7 @@ module Pod ...@@ -224,7 +237,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,12 +585,12 @@ module Pod ...@@ -572,12 +585,12 @@ 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, defines_module?))
header_search_paths.concat(sandbox.public_headers.search_paths(platform, pod_name)) header_search_paths.concat(sandbox.public_headers.search_paths(platform, pod_name, defines_module?))
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?))
end end
header_search_paths.uniq header_search_paths.uniq
end end
......
...@@ -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
......
...@@ -133,11 +133,8 @@ module Pod ...@@ -133,11 +133,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 +266,10 @@ module Pod ...@@ -269,8 +266,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 +284,9 @@ module Pod ...@@ -285,8 +284,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)
@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 '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').sort.should == [
'${PODS_ROOT}/Headers/Public/ios-target',
'${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 end
it 'only exposes header search paths for the given platform' do it 'returns the correct private header search paths given platform and target' do
@header_dir.add_search_path('iOS Search Path', Platform.ios) @private_header_dir.add_search_path('ios-target', Platform.ios)
@header_dir.add_search_path('OS X Search Path', Platform.osx) @private_header_dir.add_search_path('osx-target', Platform.osx)
@header_dir.search_paths(Platform.ios).sort.should == [ @private_header_dir.search_paths(Platform.ios, 'ios-target', false).sort.should == [
'${PODS_ROOT}/Headers/Public', '${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
describe 'modular header search paths' do
it 'returns the correct public header search paths for the given platform' do
@public_header_dir.add_search_path('iOS Search Path', Platform.ios)
@public_header_dir.add_search_path('OS X Search Path', Platform.osx)
@public_header_dir.search_paths(Platform.ios, nil, true).sort.should == [
'${PODS_ROOT}/Headers/Public/iOS Search Path', '${PODS_ROOT}/Headers/Public/iOS Search Path',
] ]
end end
it 'returns the correct header search paths given platform and target' do it 'returns the correct public header search paths given platform and target' do
@header_dir.add_search_path('ios-target', Platform.ios) @public_header_dir.add_search_path('ios-target', Platform.ios)
@header_dir.add_search_path('osx-target', Platform.osx) @public_header_dir.add_search_path('osx-target', Platform.osx)
@header_dir.search_paths(Platform.ios, 'ios-target').sort.should == [ @public_header_dir.search_paths(Platform.ios, 'ios-target', true).sort.should == [
'${PODS_ROOT}/Headers/Public',
'${PODS_ROOT}/Headers/Public/ios-target', '${PODS_ROOT}/Headers/Public/ios-target',
] ]
@header_dir.search_paths(Platform.osx, 'osx-target').sort.should == [ @public_header_dir.search_paths(Platform.osx, 'osx-target', true).sort.should == [
'${PODS_ROOT}/Headers/Public',
'${PODS_ROOT}/Headers/Public/osx-target', '${PODS_ROOT}/Headers/Public/osx-target',
] ]
end 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
...@@ -234,14 +234,65 @@ module Pod ...@@ -234,14 +234,65 @@ 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
describe 'non modular header search paths' do
it 'returns the correct 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',
'${PODS_ROOT}/Headers/Public/BananaLib/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/BananaLib/BananaLib',
'${PODS_ROOT}/Headers/Public/monkey',
'${PODS_ROOT}/Headers/Public/monkey/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',
'${PODS_ROOT}/Headers/Public/BananaLib/BananaLib',
]
end
end
describe 'modular header search paths' do
before do
@pod_target.stubs(:defines_module?).returns(true)
end
it 'returns the correct header search paths' do it 'returns the correct header search paths' 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)
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',
'${PODS_ROOT}/Headers/Public/BananaLib', '${PODS_ROOT}/Headers/Public/BananaLib',
] ]
end end
...@@ -256,9 +307,7 @@ module Pod ...@@ -256,9 +307,7 @@ module Pod
@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',
'${PODS_ROOT}/Headers/Public/BananaLib', '${PODS_ROOT}/Headers/Public/BananaLib',
'${PODS_ROOT}/Headers/Public/monkey', '${PODS_ROOT}/Headers/Public/monkey',
] ]
...@@ -275,13 +324,12 @@ module Pod ...@@ -275,13 +324,12 @@ module Pod
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',
'${PODS_ROOT}/Headers/Public/BananaLib', '${PODS_ROOT}/Headers/Public/BananaLib',
] ]
end end
end end
end
describe 'Product type dependent helpers' do describe 'Product type dependent helpers' do
describe 'With libraries' do describe 'With libraries' do
......
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