bazel-xcode / PodToBUILD

An easy way to integrate CocoaPods into Bazel
Apache License 2.0
322 stars 69 forks source link

Module Maps for Obj-C/C/C++ include too many files #13

Open sayrer opened 6 years ago

sayrer commented 6 years ago

I noticed this with https://github.com/facebook/yoga

filegroup(
  name = "yoga_hdrs",
  srcs = glob(
    [
      "pod_support/Headers/Public/**/*.h"
    ],
    exclude_directories = 1
    ),
  visibility = [
    "//visibility:public"
  ]
  )
gen_module_map(
  "yoga",
  "yoga_module_map",
  "yoga",
  [
    "yoga_hdrs"
  ]
  )

It seems like pod_support/Headers/Public/ contains too many files (every yoga header, public or private), given that the podspec lists only three public headers: https://github.com/facebook/yoga/blob/master/Yoga.podspec#L28.

sayrer commented 6 years ago

Digging into this further, it looks like PodToBUILD doesn't yet create umbrella headers and the modulemap files to go with them. Yoga is a good demo. Here's a summary of what Cocoapods generates:

$ ls -l MyApp/Pods/Target\ Support\ Files/Yoga/
total 48
-rw-r--r--  1 sayrer  staff  828 May 23 08:12 Info.plist
-rw-r--r--  1 sayrer  staff  112 May 23 08:12 Yoga-dummy.m
-rw-r--r--  1 sayrer  staff  195 May 23 08:12 Yoga-prefix.pch
-rw-r--r--  1 sayrer  staff  358 May 23 08:12 Yoga-umbrella.h
-rw-r--r--  1 sayrer  staff   98 May 23 08:12 Yoga.modulemap
-rw-r--r--  1 sayrer  staff  399 May 23 08:12 Yoga.xcconfig

$ cat MyApp/Pods/Target\ Support\ Files/Yoga/Yoga-umbrella.h
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#else
#ifndef FOUNDATION_EXPORT
#if defined(__cplusplus)
#define FOUNDATION_EXPORT extern "C"
#else
#define FOUNDATION_EXPORT extern
#endif
#endif
#endif

#import "YGEnums.h"
#import "YGMacros.h"
#import "Yoga.h"

FOUNDATION_EXPORT double yogaVersionNumber;
FOUNDATION_EXPORT const unsigned char yogaVersionString[];

$ cat MyApp/Pods/Target\ Support\ Files/Yoga/Yoga.modulemap 
framework module yoga {
  umbrella header "Yoga-umbrella.h"

  export *
  module * { export * }
}

I ran into this issue because Yoga exports a C interface in its public headers, which is fine to use with a .m Obj-C file. At the moment, PodToBUILD exports all of the private headers in the modulemap. These include C++ files which can't be included in a .m file, and so my build fails.

jerrymarino commented 6 years ago

Hey @sayrer - the current behavior of module map includes all of the headers ( currently, whatever is symlinked into pod_support ), which every header right now. It symlinks every possible header into that directory, and there is an issue that causing garbage symlinks to be created. This is not good!

You're right, CocoaPods is generating an umbrella header which achieves a similar result as what the current code does, but they use public headers only. Ideally PodToBUILD follows an identical pattern: only including public headers in the module map, perhaps generating an umbrella header if needed. This would be awesome.

Until this is fixed, do you absolutely need the module map? If not, turn it off for now. That would be an easy workaround 🔨.

new_pod_repository(
  name = "Yoga",
  ....
  generate_module_map = False
 ) 

Then,

# Update the repository to disable module generation
Vendor/bin/update_pods.py

Otherwise it is possible to augment BUILD files and the generated directory in Vendor/Yoga:

new_pod_repository(
  name = "Yoga",
  ....
   # Turn of the default module map code gen
   generate_module_map = False

   install_script = """
   # Setup the Yoga repo by default
   __INIT_REPO__
   # Copy a module map that includes only public headers
   ditto path/to/ideal/module.modulemap Vendor/Yoga/pod_support/Headers/Public/Yoga/
   """
 )