New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for modular header search paths, include "legacy" support #7412
Add support for modular header search paths, include "legacy" support #7412
Conversation
ec2cbff
to
6a2c009
Compare
6a2c009
to
6e27d9c
Compare
This looks great! How will a podspec choose to "legacy" or "new" functionality? |
Isn't that comment only about Swift static libraries? My understanding is that this PR making the imports more restrictive will break Pods that were implicitly depending on the incorrectly exposed headers - like using quotes instead of brackets or importing a private header. |
6e27d9c
to
ea6c5c0
Compare
# @param [Array<Pathname>] headers | ||
# The absolute paths of the headers which need to be mapped. | ||
# | ||
# @return [Hash{Pathname => Array<Pathname>}] A hash containing the | ||
# headers folders as the keys and the absolute paths of the | ||
# header files as the values. | ||
# | ||
def header_mappings(headers_sandbox, file_accessor, headers) | ||
def header_mappings(headers_sandbox, file_accessor, headers, visibility_scope = :private) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am thinking on removing visibilty_scope
from this method and instead pass in the initializer. Some header stores are explicitly created as private stores but yet this method talks about a public
header scope.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
actually this comment is on the wrong file, I meant header_store.rb
and yes I changed it there. This is fine to keep here.
@paulb777 it is mostly tied to Swift static libs but not 100%, the
I think "turning this on by default" might break the world. Any additional thoughts or ideas around this? We could potentially offer a |
I'm worried about (2). I suspect we have pure Objective C podspecs that are sloppy with |
68c76b6
to
cac5952
Compare
cac5952
to
2dff7a8
Compare
@paulb777 pods built as frameworks already dont get the header search paths, since they find headers via the |
@@ -147,11 +147,15 @@ def link_headers | |||
pod_target.build_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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why the <
?
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 }) | ||
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
<
s?
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, true).each do |namespaced_path, files| |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks like the 4th parameter should be a symbol rather than a bool?
lib/cocoapods/target/pod_target.rb
Outdated
@@ -571,13 +584,19 @@ def version | |||
# @return [Array<String>] The set of header search paths this target uses. | |||
# | |||
def header_search_paths(include_test_dependent_targets = false) | |||
defines_module = defines_module? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no need to extract this into a variable, it's cached
@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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we may also need to keep doing this for podspecs that define a header mappings dir, since they might be using something like j2objc that will expect things like com/company/foo/bar/header.h
to be directly importable, without the module name prefix
4da688a
to
953f391
Compare
/cc @efirestone please take a look at the top of this PR for all header description. |
Updated integration specs, also fixed compatibility with pods that define a |
lib/cocoapods/target/pod_target.rb
Outdated
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' } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we need to decide if we want to hoist this setting up into the Podfile, instead of leaving it in the podspec
31c0267
to
2867fac
Compare
LGTM, thanks for the fix on header mappings dir, do we want to merge this and continue discussion of |
# 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: Its the wild west. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Its -> It's
@@ -133,13 +137,6 @@ module XCConfig | |||
@xcconfig.to_hash['PODS_TARGET_SRCROOT'].should == '${PODS_ROOT}/../../spec/fixtures/banana-lib' | |||
end | |||
|
|||
it 'adds the library build headers and public headers search paths to the xcconfig, with quotes' do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can/should this be converted to a negative test?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like it, I may have toyed with the idea but ultimately decided to remove. Will add back.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
2867fac
to
29160de
Compare
29160de
to
1fe2eab
Compare
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' } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we decided to keep this for now
c0e1bc2
to
c6d6d5d
Compare
Updated, ready for final review! |
👍 👍 |
c6d6d5d
to
95d59b9
Compare
A few possible gotchas I see:
|
Legacy support retains the ability to import everything
Correct
The fully namespaced import is required when "modular_headers" are enabled for a pod |
PodA
,PodB
andPodC
in a project.PodA
depends only onPodB
but not onPodC
Header search paths for
PodA
:before (<= 1.4, a.k.a today)
Notice that root
Public
folder but also thatPodC
is included in the pod's header search paths despite the fact thatPodA
does not depend onPodC
.after (> 1.5)
Notice that
PodC
is correctly not included (due to #7116) but also that the root folderPublic
is no longer present which would have otherwise allowed consumers to include headers ofPodC
without directly depending on it in their podspec.Instead, the root
Public
folder is "expanded" so users can continue to use<>
and""
header imports. Functionally, this is still the same and it shouldn't break anyone upgrading to 1.5.0 but it also makes it more clear by removing the rootPublic
folder.When using/enabling modular headers there is no "before" state because we never had modular header support in CocoaPods, but
PodA
header search paths look like this (using static libraries):As for the file system all public headers are now nested an additional folder further so it looks like this:
Public header symlinks on the file system (notice the extra nested folder):
Private header symlinks on the file system (notice no extra folder as all imports can work with
""
):This means that
PodA
can now use<>
imports ofPodB
but not use""
imports forPodB
private headers (unless maybeUSE_HEADERMAPS
is set toYES
?).The above only applies
HEADER_SEARCH_PATHS
which get populated when static libraries are used. When frameworks are used thenFRAMEWORK_SEARCH_PATHS
are used which continue to work as they are today.Note that CocoaPods does not also change or interfere with the
USE_HEADERMAPS
flag, which can cause plenty of dark magic to find headers of targets that are otherwise not part of the header search paths.closes #7011