|
| 1 | +# Headers and Imports |
| 2 | + |
| 3 | +## Introduction |
| 4 | + |
| 5 | +Follow this set of guidelines when creating header files and importing them. The |
| 6 | +guidelines are designed to support a wide range of build systems and usage scenarios. |
| 7 | + |
| 8 | +In this document, the term `library` refers to a buildable package. In CocoaPods, it's a CocoaPod. |
| 9 | +In Swift Package Manager, it's a library target. |
| 10 | + |
| 11 | +## Header File Types and Locations - For Header File Creators |
| 12 | + |
| 13 | +* *Public Headers* - Headers that define the library's API. They should be located in |
| 14 | + `FirebaseFoo/Sources/Public`. Any additions require a minor version update. Any changes or |
| 15 | + deletions require a major version update. |
| 16 | + |
| 17 | +* *Public Umbrella Header* - A single header that includes the full library's public API located at |
| 18 | + `FirebaseFoo/Sources/Public/FirebaseFoo.h`. |
| 19 | + |
| 20 | +* *Private Headers* - Headers that are available to other libraries in the repo, but are not part |
| 21 | + of the public API. These should be located in `FirebaseFoo/Sources/Private`. |
| 22 | + [Xcode](https://stackoverflow.com/a/8016333) and CocoaPods refer to these as "Private Headers". |
| 23 | + Note that the usage CocoaPods `private_headers` is deprecated and should instead |
| 24 | + the `source_files` attribute should be used for access them with a repo-relative import. |
| 25 | + |
| 26 | +* *Interop Headers* - A special kind of private header that defines an interface to another library. |
| 27 | + Details in [Firebase Component System docs](Interop/FirebaseComponentSystem.md). |
| 28 | + |
| 29 | +* *Private Umbrella Header* - A single header that includes the library's public API plus any APIs |
| 30 | + provided for other libraries in the repo. Any package manager complexity should be localized to |
| 31 | + this umbrella header. |
| 32 | + |
| 33 | +* *Library Internal Headers* - Headers that are only used by the enclosing library. These headers |
| 34 | + should be located among the source files. [Xcode](https://stackoverflow.com/a/8016333) refers to |
| 35 | + these as "Project Headers". |
| 36 | + |
| 37 | +## Imports - For Header File Consumers |
| 38 | + |
| 39 | +* *Headers within the Library* - Use a repo-relative path for all of the header types above. |
| 40 | + * *Exception* - Public header imports from other public headers should do an unqualified |
| 41 | + import like `#import "publicHeader.h"` to avoid public module collisions. |
| 42 | + |
| 43 | +* *Private Headers from other Libraries* - Import a private umbrella header like |
| 44 | + `FirebaseCore/Sources/Private/FirebaseCoreInternal.h`. For CocoaPods, these files should be |
| 45 | + added to the podspec in the `preserved_path` attribute like: |
| 46 | +``` |
| 47 | + s.preserve_paths = 'Interop/Auth/Public/*.h', 'FirebaseCore/Sources/Private/*.h' |
| 48 | +``` |
| 49 | + |
| 50 | +* *Headers from an external dependency* - Do a module import for Swift Package Manager and an |
| 51 | + umbrella header import otherwise, like: |
| 52 | +``` |
| 53 | +#if SWIFT_PACKAGE |
| 54 | +@import GTMSessionFetcherCore; |
| 55 | +#else |
| 56 | +#import <GTMSessionFetcher/GTMSessionFetcher.h> |
| 57 | +#endif |
| 58 | +``` |
| 59 | + |
| 60 | +## Additional Background |
| 61 | + |
| 62 | +Here is some additional detail that should give deeper insight onto the above guidelines. |
| 63 | + |
| 64 | +### Build Systems |
| 65 | + |
| 66 | +We support building with CocoaPods, cmake, internal Google build system, and Swift Package |
| 67 | +Manager (in development). Using repo-relative headers is a key enabler since it allows all headers |
| 68 | +to be found with a single path specifier no matter what the build system. |
| 69 | + |
| 70 | +#### CocoaPods Build Systems |
| 71 | +CocoaPods itself has a range of options that impact the functionality of header imports. |
| 72 | + |
| 73 | +The `use_frameworks!` option enables `@import {module-name}`. CocoaPods creates a directory structure |
| 74 | +such that `#import <pod-name/header>` works whether or not frameworks are built. |
| 75 | + |
| 76 | +CocoaPods builds a different directory structure for a `Development Pods` install versus an install |
| 77 | +from a published podspec. This can hide errors resulting from header search path pointing outside |
| 78 | +of a particular pod's sources. |
| 79 | + |
| 80 | + |
| 81 | +### "Internal" versus "Private" |
| 82 | + |
| 83 | +"Internal" and "Private" are often used interchangeably since |
| 84 | +[Xcode](https://stackoverflow.com/a/8016333) and CocoaPods usage is |
| 85 | +inconsistent with expectations of C++ developers. "Private" headers are available to clients |
| 86 | +via an explicit import. "Internal" or "Project" headers are only available to their enclosing |
| 87 | +library. Many file names in this repo include "Private" or "Internal" do not comply. Always |
| 88 | +check the build definition to see how the file is used. |
0 commit comments