CocoaPods / CocoaPods

The Cocoa Dependency Manager.
https://cocoapods.org/
Other
14.52k stars 2.62k forks source link

Could not find any way to mark all headers in one subspec into Project Headers (not Public or Private), compared to native Xcode framework project (or Carthage) #8483

Open dreampiggy opened 5 years ago

dreampiggy commented 5 years ago

Report

What did you do?

I have a Pod, which one subspec should only be imported by another subspec, so itself should not produce any Public Headers. And it can not use Private Headers because the parent spec should import the header files.

The podspec looks like this one:

  # HEIF Encoding need libx265
  s.subspec 'libx265' do |ss|
    ss.dependency 'libx265'
    ss.dependency 'SDWebImageHEIFCoder/libheif'
    ss.source_files = 'Vendors/libheif/libheif/heif_encoder_x265.{h,c,cc}'
    ss.public_header_files = 'Vendors/libheif/libheif/heif_encoder_x265.h' # I don't want to mark this into publoic headers actually. This subspec should be project headers only. But I can not find a way to do so
    ss.preserve_path = 'Vendors'
    ss.xcconfig = {
      'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) HAVE_X265=1',
      'HEADER_SEARCH_PATHS' => '$(inherited) ${PODS_ROOT}/SDWebImageHEIFCoder/Vendors/include'
    }
  end

I've tried any of CocoaPods's podspec syntax, even with some tricks, it can build using pod install. But with no luck to pass pod trunk push

Trick 1: Mark both public_header_files && private_header_files to be empty.

ss.public_header_files = ''
ss.private_header_files = ''

Trick 2: Use one dummy headers (or one exist public headers from another subspec) as public headers

ss.public_header_files = 'MyAnotherSubspec/public_headers.h'

What did you expect to happen?

There should be a podspec option project_header_files, to explicitly set the project header. It's not public, not private. Because sometime, you don't want to mark those header files into public for end-user to let them import. It's a common use case in framework author, and Swift author already support this type inside language using package control attribute.

For Objective-C/C/C++, it's already supported by native Xcode project, but can not be done via CocoaPods's DSL. Since CocoaPods DSL is aim to generate Xcode project, it should at least cover this type of usage.

What happened instead?

The above tricks can works on pod install. And generate the correct Xcode project.

However, the pod trunk push failed, because of either one type of error or another error.

Trick 1, error:

The 'public_header_files' pattern did not match any file.

Trick 2, error:

public_header_files: The pattern includes header files that are not listed in source_file

CocoaPods Environment

Stack

   CocoaPods : 1.5.3
        Ruby : ruby 2.3.7p456 (2018-03-28 revision 63024) [x86_64-darwin18]
    RubyGems : 2.7.8
        Host : Mac OS X 10.14 (18A391)
       Xcode : 10.1 (10B61)
         Git : git version 2.17.2 (Apple Git-113)
Ruby lib dir : /Users/lizhuoli/.rvm/rubies/ruby-2.3.7/lib
Repositories : byted-cj_pods_specs - git@code.byted.org:caijing_ios/cj_pods_specs.git @ 73a98b1e893494c1baff39a3f5ca50efdfdd3f8f
               byted-cocoapods-master-specs-mirror - git@code.byted.org:TTIOS/cocoapods-master-specs-mirror.git @ efe3275b6e97ddd14c40bfe05585e684e77ffe4c
               byted-ez_source_repo - git@code.byted.org:sunxurang/ez_source_repo.git @ 78ec163e8009f7d5bcb917d1ac0c625f970d22b6
               byted-podspecs - git@code.byted.org:bds/podspecs.git @ 415177578ec88c9ffd3dff1278f635a5b74b9336
               byted-privatethird_binary_repo - git@code.byted.org:iOS_Library/privatethird_binary_repo.git @ b68871ad4f8b2b92212d3db55653ea5fcf6de081
               byted-privatethird_source_repo - git@code.byted.org:iOS_Library/privatethird_source_repo.git @ e4428849234afdb1ab7dba7c06dfe671975952c5
               byted-publicthird_binary_repo - git@code.byted.org:iOS_Library/publicthird_binary_repo.git @ a86db2e23b0fec0164a97fc591a0491503363959
               byted-publicthird_source_repo - git@code.byted.org:iOS_Library/publicthird_source_repo.git @ 7b7156cfeeabd5eb190c70551b629e6da65fdf08
               byted-toutiao_binary_repo - git@code.byted.org:iOS_Library/toutiao_binary_repo.git @ b094d1ed83349948336686be2483e945d336edc9
               byted-toutiao_source_repo - git@code.byted.org:iOS_Library/toutiao_source_repo.git @ 976fd76f52919506002fa6f35db99bae364228d3
               byted-ttvideo-pods - git@code.byted.org:TTVideo/ttvideo-pods.git @ 932b66378ce6a69c680788e927b30af08eac5664
               byted-ugcspecs - git@code.byted.org:ugc/UGCSpecs.git @ becd4dbb144026fd8e05e01114ffe1624c1a4e11
               byted-xigua_binary_repo - git@code.byted.org:iOS_Library/xigua_binary_repo.git @ 0cfbb8a551c04f3cc1fdcecd53236fa0a550cdee
               byted-xigua_source_repo - git@code.byted.org:iOS_Library/xigua_source_repo.git @ 3da0ef744fe5a6ff4724eb6ae062e6450fc5ce1f
               master - https://github.com/CocoaPods/Specs.git @ e742e240cb62fc5691ab9031b910878da8e85e9e

Installation Source

Executable Path: /Users/lizhuoli/.rvm/gems/ruby-2.3.7/bin/pod

Plugins

cocoapods-deintegrate : 1.0.2
cocoapods-plugins     : 1.0.0
cocoapods-search      : 1.0.0
cocoapods-stats       : 1.1.0
cocoapods-trunk       : 1.3.1
cocoapods-try         : 1.1.0

Project that demonstrates the issue

You can use this SDWebImageHEIFCoder.podspec, by modifying the contents of libx265 subspec's public_header_files with empty string, and can works with pod install. But can not pass pod trunk push. So current, we expose those dummy headers(heif_decoder_libde265 && heif_encoder_libx265) into public. Actually, those should be project headers, and not visible to end-user.

amorde commented 5 years ago

@dreampiggy including headers in source_files and not including them in either private_header_files nor public_header_files will result in the header being marked as a Project header. Does this solve what you're trying to accomplish?

dreampiggy commented 5 years ago

@amorde No. For this case, actually you means:

ss.source_files = 'Vendors/libheif/libheif/heif_encoder_x265.{h,c,cc}'
ss.public_header_files = "" # nothing
ss.private_header_files = "" # nothing

However, this can work for local podspec (using :path => require), but does not pass the pod spec lint or pod trunk push, make this pod does not works for public usage.

The 'public_header_files' pattern did not match any file. The 'private_header_files' pattern did not match any file.

My current use case, is that one subspec, only contains Project Headers, no any Public Headers or Private Headers. And with some compile source files.

amorde commented 5 years ago

Why doesn't this work?

ss.source_files = 'Vendors/libheif/libheif/heif_encoder_x265.{h,c,cc}'

Any headers within source_files will be Project headers, and there are no public or private headers specified. Or is the issue that you are trying to convert the public_header_files in the 'SDWebImageHEIFCoder/libheif' subspec from public to project?

dreampiggy commented 5 years ago

@amorde This syntax, resolve the Pod Poject to use the subspec's headers as Public Headers, but not Project Headers...I've already try this syntax. And I think this is because of the project header generate rules:

  1. If only source_files, treate all headers as public headers
  2. If not any headers outside public_headers or private_headers, treated as project headers

By following these rules, there are no way to treate all as project headers. So I think it's better to introduce a new podspec syntax. Or there are one hack way, to let user pass public_headers = "" && private_headers = "" works. But however, current cocoapos-trunk forbid this usage.

Here is the screenshot:

  # HEIF Encoding need libx265
  s.subspec 'libx265' do |ss|
    ss.dependency 'libx265'
    ss.dependency 'SDWebImageHEIFCoder/libheif'
    ss.source_files = 'Vendors/libheif/libheif/heif_encoder_x265.{h,c,cc}'
    ss.preserve_path = 'Vendors'
    ss.xcconfig = {
      'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) HAVE_X265=1',
      'HEADER_SEARCH_PATHS' => '$(inherited) ${PODS_ROOT}/SDWebImageHEIFCoder/Vendors/include ${PODS_ROOT}/libx265/source/'
    }
  end

image

Code about this: https://github.com/CocoaPods/CocoaPods/blob/1.6.0/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_installer.rb#L715-L723

amorde commented 5 years ago

right, but isn't that because that subspec depends on the 'libheif' subspec which does include it in its public header files?

https://github.com/SDWebImage/SDWebImageHEIFCoder/blob/04bbd3ddb6718f4678cff7900b41804f6cae9934/SDWebImageHEIFCoder.podspec#L36

amorde commented 5 years ago

actually not sure that it is included, it looks like there's a nested folder that isn't in the glob pattern. will take a look

dreampiggy commented 5 years ago

@amorde Sorry to bother. But actually, the folder structure looks like this:

- Vendor
-- include
--- libheif
---- heif.h
---- heif_version.h
-- libheif(Git Submodule, below it's another repo's content)
--- libheif
---- src
----- heif_decoder_libde265.h

So, even I use ss.public_header_files = 'Vendors/include/libheif/*.h',, this could not revolve that heif_decoder_libde265.h to become public header. include folders contains only two exact files.

This issue it's easy to reproduce actually, and does not only effect Subspec. Actually, I can not build a Pod, which does not expose any public headers or private headers (A framework, only contains Project Headers, such as extension/hook only framework).

amorde commented 5 years ago

I am able to reproduce, and I narrowed down the source of this behavior to this code path:

https://github.com/CocoaPods/CocoaPods/blob/23d4bfc5c755bac874bf2027b6f61796d05d44cf/lib/cocoapods/sandbox/file_accessor.rb#L132-L136

So yes you are right if there are any headers at all, they default to public unless public_header_files or private_header_files are non-empty. This seems like something that can be changed, the logic has stayed the same since it was written 6 years ago. Going to investigate whether we need this behavior or not and possibly make a PR.

Thanks for the report!

amorde commented 5 years ago

In the mean time, you should be able to work around this by adding one of the public header files from the other subspec that libx265 depends on

ss.public_header_files = 'Vendors/include/libheif/*.h'
dreampiggy commented 5 years ago

@amorde This does not works...I already point this out in the Issue Description. It's forbidden because of pod trunk push extra rules. Only works for local pod install or pod lib lint.

public_header_files: The pattern includes header files that are not listed in source_file

I think, maybe CocoaPods should better filter these special case ? Do I need to submit a issue report for https://github.com/CocoaPods/cocoapods-trunk ? I think their rules is not so suitable.

wellbranding commented 5 years ago

@dreampiggy Hello, may you check if it is related to our problem? https://github.com/CocoaPods/CocoaPods/issues/8594

xiafan-su commented 3 years ago

So any fix for this issue? It's still there for 1.10.1