Skip to content

Commit abf5e55

Browse files
docs(firestore): Add docs on Firestore x SPM integration (#15387)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
1 parent e7e5d83 commit abf5e55

File tree

2 files changed

+199
-0
lines changed

2 files changed

+199
-0
lines changed

Firestore/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ scripts/build.sh Firestore iOS spm
4848
4949
This is rarely necessary for primary development and is done automatically by CI.
5050
51+
For a detailed explanation of the Firestore target hierarchy in the
52+
`Package.swift` manifest, see [FirestoreSPM.md](../docs/FirestoreSPM.md).
53+
5154
### Improving the debugger experience
5255
5356
You can install a set of type formatters to improve the presentation of

docs/FirestoreSPM.md

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
# Firestore Swift Package Manager Target Hierarchy
2+
3+
This document outlines the hierarchy of the Firestore-related targets in the
4+
`Package.swift` manifest. The setup is designed to support three different
5+
build options for Firestore: from a pre-compiled binary (the default), from
6+
source (via the `FIREBASE_SOURCE_FIRESTORE` environment variable), or from a
7+
local binary for CI purposes (via the `FIREBASECI_USE_LOCAL_FIRESTORE_ZIP`
8+
environment variable).
9+
10+
---
11+
12+
## 1. Binary-based build (Default)
13+
14+
When the `FIREBASE_SOURCE_FIRESTORE` environment variable is **not** set, SPM
15+
will use pre-compiled binaries for Firestore and its heavy dependencies. This
16+
is the default and recommended approach for most users.
17+
18+
### Dependency hierarchy
19+
20+
The dependency tree for a binary-based build is as follows:
21+
22+
```
23+
FirebaseFirestore (Library Product)
24+
└── FirebaseFirestoreTarget (Wrapper Target)
25+
└── FirebaseFirestore (Swift Target)
26+
├── FirebaseAppCheckInterop
27+
├── FirebaseCore
28+
├── FirebaseCoreExtension
29+
├── FirebaseSharedSwift
30+
├── leveldb
31+
├── nanopb
32+
├── abseil (binary) (from https://github.com/google/abseil-cpp-binary.git)
33+
├── gRPC-C++ (binary) (from https://github.com/google/grpc-binary.git, contains BoringSSL-GRPC target)
34+
└── FirebaseFirestoreInternalWrapper (Wrapper Target)
35+
└── FirebaseFirestoreInternal (Binary Target)
36+
```
37+
38+
### Target breakdown
39+
40+
* **`FirebaseFirestore`**: The Swift target containing the public API. In this
41+
configuration, it depends on the binary versions of abseil and gRPC, as
42+
well as the `FirebaseFirestoreInternalWrapper`.
43+
* **`FirebaseFirestoreInternalWrapper`**: A thin wrapper target that exists to
44+
expose the headers from the underlying binary target.
45+
* **`FirebaseFirestoreInternal`**: This is a `binaryTarget` that downloads and
46+
links the pre-compiled `FirebaseFirestoreInternal.xcframework`. This
47+
framework contains the compiled C++ core of Firestore.
48+
49+
---
50+
51+
## 2. Source-based build
52+
53+
When the `FIREBASE_SOURCE_FIRESTORE` environment variable is set, Firestore and
54+
its dependencies (like abseil and gRPC) are compiled from source.
55+
56+
### How to build Firestore from source
57+
58+
To build Firestore from source, set the `FIREBASE_SOURCE_FIRESTORE` environment
59+
variable before building the project.
60+
61+
#### Building with Xcode
62+
63+
A direct method for building within Xcode is to pass the environment variable
64+
when opening it from the command line. This approach scopes the variable to the
65+
Xcode instance. To enable an env var within Xcode, first quit any running Xcode
66+
instance, and then open the project from the command line:
67+
68+
```console
69+
open --env FIREBASE_SOURCE_FIRESTORE Package.swift
70+
```
71+
72+
To unset the env var, quit the running Xcode instance. If you need to pass
73+
multiple variables, repeat the `--env` argument for each:
74+
```console
75+
open --env FIREBASECI_USE_LATEST_GOOGLEAPPMEASUREMENT \
76+
--env FIREBASE_SOURCE_FIRESTORE Package.swift
77+
```
78+
79+
#### Command-line builds
80+
81+
For command-line builds using `xcodebuild` or `swift build`, the recommended
82+
approach is to prefix the build command with the environment variable. This sets
83+
the variable only for that specific command, avoiding unintended side effects.
84+
85+
```bash
86+
FIREBASE_SOURCE_FIRESTORE=1 xcodebuild -scheme FirebaseFirestore \
87+
-destination 'generic/platform=iOS'
88+
```
89+
90+
Alternatively, if you plan to run multiple commands that require the variable
91+
to be set, you can `export` it. This will apply the variable to all subsequent
92+
commands in that terminal session.
93+
94+
```bash
95+
export FIREBASE_SOURCE_FIRESTORE=1
96+
xcodebuild -scheme FirebaseFirestore -destination 'generic/platform=iOS'
97+
# Any other commands here will also have the variable set
98+
```
99+
100+
Once the project is built with the variable set, SPM will clone and build
101+
Firestore and its C++ dependencies (like abseil and gRPC) from source.
102+
103+
### Dependency hierarchy
104+
105+
The dependency tree for a source-based build looks like this:
106+
107+
```
108+
FirebaseFirestore (Library Product)
109+
└── FirebaseFirestoreTarget (Wrapper Target)
110+
└── FirebaseFirestore (Swift Target)
111+
├── FirebaseCore
112+
├── FirebaseCoreExtension
113+
├── FirebaseSharedSwift
114+
└── FirebaseFirestoreInternalWrapper (C++ Target)
115+
├── FirebaseAppCheckInterop
116+
├── FirebaseCore
117+
├── leveldb
118+
├── nanopb
119+
├── abseil (source) (from https://github.com/firebase/abseil-cpp-SwiftPM.git)
120+
└── gRPC-cpp (source) (from https://github.com/grpc/grpc-ios.git)
121+
└── BoringSSL (source) (from https://github.com/firebase/boringSSL-SwiftPM.git)
122+
```
123+
124+
### Target breakdown
125+
126+
* **`FirebaseFirestore`**: The main Swift target containing the public Swift
127+
API for Firestore. It acts as a bridge to the underlying C++
128+
implementation.
129+
* **`FirebaseFirestoreInternalWrapper`**: This target compiles the core C++
130+
source code of Firestore. It depends on other low-level libraries and C++
131+
dependencies, which are also built from source.
132+
133+
---
134+
135+
## 3. Local binary build (CI only)
136+
137+
A third, less common build option is available for CI environments. When the
138+
`FIREBASECI_USE_LOCAL_FIRESTORE_ZIP` environment variable is set, the build
139+
system will use a local `FirebaseFirestoreInternal.xcframework` instead of
140+
downloading the pre-compiled binary. This option assumes the xcframework is
141+
located at the root of the repository.
142+
143+
This option is primarily used by internal scripts, such as
144+
`scripts/check_firestore_symbols.sh`, to perform validation against a locally
145+
built version of the Firestore binary. It is not intended for general consumer
146+
use.
147+
148+
---
149+
150+
## Core target explanations
151+
152+
### `FirebaseFirestore` (Library product)
153+
154+
The main entry point for integrating Firestore via SPM is the
155+
`FirebaseFirestore` library product.
156+
157+
```swift
158+
.library(
159+
name: "FirebaseFirestore",
160+
targets: ["FirebaseFirestoreTarget"])
161+
```
162+
163+
This product points to a wrapper target, `FirebaseFirestoreTarget`, which then
164+
depends on the appropriate Firestore targets based on the chosen build option.
165+
166+
### `FirebaseFirestoreTarget` (Wrapper target)
167+
168+
The `FirebaseFirestoreTarget` is a thin wrapper that exists to work around a
169+
limitation in SPM where a single target cannot conditionally depend on
170+
different sets of targets (source vs. binary).
171+
172+
By having clients depend on the wrapper, the `Package.swift` can internally
173+
manage the complexity of switching between source and binary builds. This
174+
provides a stable entry point for all clients and avoids pushing conditional
175+
logic into their own package manifests.
176+
177+
---
178+
179+
## Test targets
180+
181+
The testing infrastructure for Firestore in SPM is designed to be independent
182+
of the build choice (source vs. binary).
183+
184+
* **`FirebaseFirestoreTestingSupport`**: This is a library target, not a test
185+
target. It provides public testing utilities that consumers can use to
186+
write unit tests for their Firestore-dependent code. It has a dependency on
187+
`FirebaseFirestoreTarget`, which means it will link against whichever
188+
version of Firestore (source or binary) is being used in the build.
189+
190+
* **`FirestoreTestingSupportTests`**: This is a test target that contains the
191+
unit tests for the `FirebaseFirestoreTestingSupport` library itself. Its
192+
purpose is to validate the testing utilities.
193+
194+
Because both of these targets depend on the `FirebaseFirestoreTarget` wrapper,
195+
they seamlessly adapt to either the source-based or binary-based build path
196+
without any conditional logic.

0 commit comments

Comments
 (0)