Skip to content

Commit b414bfc

Browse files
authored
[Release Tooling] Add functionality to build dynamic frameworks (#12890)
1 parent e1e1b93 commit b414bfc

File tree

4 files changed

+110
-68
lines changed

4 files changed

+110
-68
lines changed

.github/workflows/zip.yml

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,9 @@ jobs:
4343
run: |
4444
mkdir -p release_zip_dir
4545
sh -x scripts/build_zip.sh release_zip_dir \
46-
"${{ github.event.inputs.custom_spec_repos || 'https://github.com/firebase/SpecsStaging.git' }}"
46+
"${{ github.event.inputs.custom_spec_repos || 'https://github.com/firebase/SpecsStaging.git' }}" \
47+
build-release \
48+
static
4749
- uses: actions/upload-artifact@v4
4850
with:
4951
name: Firebase-release-zip-zip
@@ -68,6 +70,9 @@ jobs:
6870
# Don't run on private repo.
6971
if: (github.repository == 'Firebase/firebase-ios-sdk' && github.event_name == 'schedule') || github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch'
7072
needs: build
73+
strategy:
74+
matrix:
75+
linking_type: [static, dynamic]
7176
runs-on: macos-14
7277
steps:
7378
- uses: actions/checkout@v4
@@ -84,10 +89,11 @@ jobs:
8489
mkdir -p zip_output_dir
8590
sh -x scripts/build_zip.sh \
8691
zip_output_dir "${{ github.event.inputs.custom_spec_repos || 'https://github.com/firebase/SpecsStaging.git,https://github.com/firebase/SpecsDev.git' }}" \
87-
build-head
92+
build-head \
93+
${{ matrix.linking_type }}
8894
- uses: actions/upload-artifact@v4
8995
with:
90-
name: Firebase-actions-dir
96+
name: ${{ matrix.linking_type == 'static' && 'Firebase-actions-dir' || 'Firebase-actions-dir-dynamic' }}
9197
# Zip the entire output directory since the builder adds subdirectories we don't know the
9298
# name of.
9399
path: zip_output_dir
@@ -103,6 +109,7 @@ jobs:
103109
strategy:
104110
matrix:
105111
os: [macos-13, macos-14]
112+
artifact: [Firebase-actions-dir, Firebase-actions-dir-dynamic]
106113
include:
107114
- os: macos-13
108115
xcode: Xcode_15.2
@@ -114,7 +121,7 @@ jobs:
114121
- name: Get framework dir
115122
uses: actions/download-artifact@v4
116123
with:
117-
name: Firebase-actions-dir
124+
name: ${{ matrix.artifact }}
118125
- uses: ruby/setup-ruby@v1
119126
- name: Setup Bundler
120127
run: ./scripts/setup_bundler.sh
@@ -164,6 +171,7 @@ jobs:
164171
strategy:
165172
matrix:
166173
os: [macos-13, macos-14]
174+
artifact: [Firebase-actions-dir, Firebase-actions-dir-dynamic]
167175
include:
168176
- os: macos-13
169177
xcode: Xcode_15.2
@@ -175,7 +183,7 @@ jobs:
175183
- name: Get framework dir
176184
uses: actions/download-artifact@v4
177185
with:
178-
name: Firebase-actions-dir
186+
name: ${{ matrix.artifact }}
179187
- uses: ruby/setup-ruby@v1
180188
- name: Setup Bundler
181189
run: ./scripts/setup_bundler.sh
@@ -217,6 +225,7 @@ jobs:
217225
strategy:
218226
matrix:
219227
os: [macos-13, macos-14]
228+
artifact: [Firebase-actions-dir, Firebase-actions-dir-dynamic]
220229
include:
221230
- os: macos-13
222231
xcode: Xcode_15.2
@@ -228,7 +237,7 @@ jobs:
228237
- name: Get framework dir
229238
uses: actions/download-artifact@v4
230239
with:
231-
name: Firebase-actions-dir
240+
name: ${{ matrix.artifact }}
232241
- uses: ruby/setup-ruby@v1
233242
- name: Setup Bundler
234243
run: ./scripts/setup_bundler.sh
@@ -268,6 +277,7 @@ jobs:
268277
strategy:
269278
matrix:
270279
os: [macos-13, macos-14]
280+
artifact: [Firebase-actions-dir, Firebase-actions-dir-dynamic]
271281
include:
272282
- os: macos-13
273283
xcode: Xcode_15.2
@@ -279,7 +289,7 @@ jobs:
279289
- name: Get framework dir
280290
uses: actions/download-artifact@v4
281291
with:
282-
name: Firebase-actions-dir
292+
name: ${{ matrix.artifact }}
283293
- uses: ruby/setup-ruby@v1
284294
- name: Setup Bundler
285295
run: ./scripts/setup_bundler.sh
@@ -343,6 +353,7 @@ jobs:
343353
matrix:
344354
os: [macos-13]
345355
xcode: [Xcode_15.2]
356+
artifact: [Firebase-actions-dir, Firebase-actions-dir-dynamic]
346357
# TODO: Building FirebaseUI fails on Xcode 15 because it needs to sign the resources.
347358
# - os: macos-13
348359
# xcode: Xcode_15.2
@@ -352,7 +363,7 @@ jobs:
352363
- name: Get framework dir
353364
uses: actions/download-artifact@v4
354365
with:
355-
name: Firebase-actions-dir
366+
name: ${{ matrix.artifact }}
356367
- uses: ruby/setup-ruby@v1
357368
- name: Setup Bundler
358369
run: ./scripts/setup_bundler.sh
@@ -396,6 +407,7 @@ jobs:
396407
strategy:
397408
matrix:
398409
os: [macos-13, macos-14]
410+
artifact: [Firebase-actions-dir, Firebase-actions-dir-dynamic]
399411
include:
400412
- os: macos-13
401413
xcode: Xcode_15.2
@@ -407,7 +419,7 @@ jobs:
407419
- name: Get framework dir
408420
uses: actions/download-artifact@v4
409421
with:
410-
name: Firebase-actions-dir
422+
name: ${{ matrix.artifact }}
411423
- uses: ruby/setup-ruby@v1
412424
- name: Setup Bundler
413425
run: ./scripts/setup_bundler.sh
@@ -456,14 +468,15 @@ jobs:
456468
# matrix:
457469
# # TODO: Building FirebaseUI fails on Xcode 15 because it needs to sign the resources.
458470
# os: [macos-13]
471+
# artifact: [Firebase-actions-dir, Firebase-actions-dir-dynamic]
459472
# xcode: [Xcode_15.2]
460473
# runs-on: ${{ matrix.os }}
461474
# steps:
462475
# - uses: actions/checkout@v4
463476
# - name: Get framework dir
464477
# uses: actions/download-artifact@v4
465478
# with:
466-
# name: Firebase-actions-dir
479+
# name: ${{ matrix.artifact }}
467480
# - uses: ruby/setup-ruby@v1
468481
# - name: Setup Bundler
469482
# run: ./scripts/setup_bundler.sh
@@ -536,6 +549,7 @@ jobs:
536549
strategy:
537550
matrix:
538551
os: [macos-13, macos-14]
552+
artifact: [Firebase-actions-dir, Firebase-actions-dir-dynamic]
539553
include:
540554
- os: macos-13
541555
xcode: Xcode_15.2
@@ -547,7 +561,7 @@ jobs:
547561
- name: Get framework dir
548562
uses: actions/download-artifact@v4
549563
with:
550-
name: Firebase-actions-dir
564+
name: ${{ matrix.artifact }}
551565
- uses: ruby/setup-ruby@v1
552566
- name: Setup Bundler
553567
run: ./scripts/setup_bundler.sh
@@ -592,6 +606,7 @@ jobs:
592606
strategy:
593607
matrix:
594608
os: [macos-13, macos-14]
609+
artifact: [Firebase-actions-dir, Firebase-actions-dir-dynamic]
595610
include:
596611
- os: macos-13
597612
xcode: Xcode_15.2
@@ -603,7 +618,7 @@ jobs:
603618
- name: Get framework dir
604619
uses: actions/download-artifact@v4
605620
with:
606-
name: Firebase-actions-dir
621+
name: ${{ matrix.artifact }}
607622
- uses: ruby/setup-ruby@v1
608623
- name: Setup Bundler
609624
run: ./scripts/setup_bundler.sh
@@ -647,6 +662,7 @@ jobs:
647662
strategy:
648663
matrix:
649664
os: [macos-13, macos-14]
665+
artifact: [Firebase-actions-dir, Firebase-actions-dir-dynamic]
650666
include:
651667
- os: macos-13
652668
xcode: Xcode_15.2
@@ -658,7 +674,7 @@ jobs:
658674
- name: Get framework dir
659675
uses: actions/download-artifact@v4
660676
with:
661-
name: Firebase-actions-dir
677+
name: ${{ matrix.artifact }}
662678
- uses: ruby/setup-ruby@v1
663679
- name: Setup Bundler
664680
run: ./scripts/setup_bundler.sh

ReleaseTooling/Sources/ZipBuilder/FrameworkBuilder.swift

Lines changed: 4 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -306,18 +306,14 @@ struct FrameworkBuilder {
306306
logsDir: URL) -> [URL] {
307307
// xcframework doesn't lipo things together but accepts fat frameworks for one target.
308308
// We group architectures here to deal with this fact.
309-
var thinFrameworks = [URL]()
310-
for targetPlatform in TargetPlatform.allCases {
311-
let buildDir = projectDir.appendingPathComponent(targetPlatform.buildName)
312-
let slicedFramework = buildSlicedFramework(
313-
withName: FrameworkBuilder.frameworkBuildName(framework),
309+
return targetPlatforms.map { targetPlatform in
310+
buildSlicedFramework(
311+
withName: framework,
314312
targetPlatform: targetPlatform,
315-
buildDir: buildDir,
313+
buildDir: projectDir.appendingPathComponent(targetPlatform.buildName),
316314
logRoot: logsDir
317315
)
318-
thinFrameworks.append(slicedFramework)
319316
}
320-
return thinFrameworks
321317
}
322318

323319
/// Compiles the specified framework in a temporary directory and writes the build logs to file.
@@ -565,17 +561,6 @@ struct FrameworkBuilder {
565561
"\(framework): \(error)")
566562
}
567563

568-
// CocoaPods creates a `_CodeSignature` directory. Delete it.
569-
// Note that the build only produces a `_CodeSignature` directory for
570-
// macOS and macCatalyst, but we try to delete it for other platforms
571-
// just in case it were to appear.
572-
let codeSignatureDir = platformFrameworkDir
573-
.appendingPathComponent(
574-
platform == .catalyst || platform == .macOS ? "Versions/A/" : ""
575-
)
576-
.appendingPathComponent("_CodeSignature")
577-
try? fileManager.removeItem(at: codeSignatureDir)
578-
579564
// The minimum OS version is set to 100.0 to work around b/327020913.
580565
// TODO(ncooke3): Revert this logic once b/327020913 is fixed.
581566
// TODO(ncooke3): Does this need to happen on macOS?
@@ -604,23 +589,6 @@ struct FrameworkBuilder {
604589
)
605590
}
606591

607-
// The macOS slice's `PrivateHeaders` directory may have a
608-
// `PrivateHeaders` file in it that symbolically links to nowhere. Delete
609-
// it here to avoid putting it in the zip or crashing the Carthage hash
610-
// generation. Because this will throw an error for cases where the file
611-
// does not exist, the error is ignored.
612-
let privateHeadersDir = platformFrameworkDir.appendingPathComponent("PrivateHeaders")
613-
if fileManager.directoryExists(at: privateHeadersDir.resolvingSymlinksInPath()) {
614-
try? fileManager
615-
.removeItem(at: privateHeadersDir.resolvingSymlinksInPath()
616-
.appendingPathComponent("PrivateHeaders"))
617-
} else {
618-
try? fileManager.removeItem(at: privateHeadersDir)
619-
}
620-
let headersDir = platformFrameworkDir.appendingPathComponent("Headers")
621-
.resolvingSymlinksInPath()
622-
try? fileManager.removeItem(at: headersDir.appendingPathComponent("Headers"))
623-
624592
// Move privacy manifest containing resource bundles into the framework.
625593
let resourceDir = platformFrameworkDir
626594
.appendingPathComponent(
@@ -638,12 +606,6 @@ struct FrameworkBuilder {
638606
// Bundles are moved rather than copied to prevent them from being
639607
// packaged in a `Resources` directory at the root of the xcframework.
640608
.forEach {
641-
// Delete `gRPCCertificates-Cpp.bundle` since it is not needed (#9184).
642-
guard $0.lastPathComponent != "gRPCCertificates-Cpp.bundle" else {
643-
try fileManager.removeItem(at: $0)
644-
return
645-
}
646-
647609
try fileManager.moveItem(
648610
at: $0,
649611
to: resourceDir.appendingPathComponent($0.lastPathComponent)

ReleaseTooling/Sources/ZipBuilder/ZipBuilder.swift

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,8 @@ struct ZipBuilder {
277277
for groupedFramework in groupedFrameworks {
278278
let name = groupedFramework.key
279279
let xcframework = FrameworkBuilder.makeXCFramework(withName: name,
280-
frameworks: groupedFramework.value,
280+
frameworks: postProcessFrameworks(groupedFramework
281+
.value),
281282
xcframeworksDir: xcframeworksDir,
282283
resourceContents: resources[name])
283284
xcframeworks[name] = [xcframework]
@@ -299,13 +300,60 @@ struct ZipBuilder {
299300

300301
let carthageGoogleUtilitiesXcframework = FrameworkBuilder.makeXCFramework(
301302
withName: "GoogleUtilities",
302-
frameworks: carthageGoogleUtilitiesFrameworks,
303+
frameworks: postProcessFrameworks(carthageGoogleUtilitiesFrameworks),
303304
xcframeworksDir: xcframeworksCarthageDir,
304305
resourceContents: nil
305306
)
306307
return (podsBuilt, xcframeworks, carthageGoogleUtilitiesXcframework)
307308
}
308309

310+
func postProcessFrameworks(_ frameworks: [URL]) -> [URL] {
311+
for framework in frameworks {
312+
// CocoaPods creates a `_CodeSignature` directory. Delete it.
313+
// Note that the build only produces a `_CodeSignature` directory for
314+
// macOS and macCatalyst (`Versions/A/`), but we try to delete it for
315+
// other platforms just in case it were to appear.
316+
for path in ["", "Versions/A/"] {
317+
let codeSignatureDir = framework
318+
.appendingPathComponent(path)
319+
.appendingPathComponent("_CodeSignature")
320+
.resolvingSymlinksInPath()
321+
try? FileManager.default.removeItem(at: codeSignatureDir)
322+
}
323+
324+
// Delete `gRPCCertificates-Cpp.bundle` since it is not needed (#9184).
325+
// Depending on the platform, it may be at the root of the framework or
326+
// in a symlinked `Resources` directory (for macOS, macCatalyst). Attempt
327+
// to delete at either patch for each framework.
328+
for path in ["", "Resources"] {
329+
let grpcCertsBundle = framework
330+
.appendingPathComponent(path)
331+
.appendingPathComponent("gRPCCertificates-Cpp.bundle")
332+
.resolvingSymlinksInPath()
333+
try? FileManager.default.removeItem(at: grpcCertsBundle)
334+
}
335+
336+
// The macOS slice's `PrivateHeaders` directory may have a
337+
// `PrivateHeaders` file in it that symbolically links to nowhere. Delete
338+
// it here to avoid putting it in the zip or crashing the Carthage hash
339+
// generation. Because this will throw an error for cases where the file
340+
// does not exist, the error is ignored.
341+
let privateHeadersDir = framework.appendingPathComponent("PrivateHeaders")
342+
if !FileManager.default.directoryExists(at: privateHeadersDir.resolvingSymlinksInPath()) {
343+
try? FileManager.default.removeItem(at: privateHeadersDir)
344+
}
345+
346+
// The `Headers` and `PrivateHeaders` directories may contain a symlink
347+
// of the same name. Delete it here to avoid putting it in the zip or
348+
// crashing the Carthage hash generation.
349+
for path in ["Headers", "PrivateHeaders"] {
350+
let headersDir = framework.appendingPathComponent(path).resolvingSymlinksInPath()
351+
try? FileManager.default.removeItem(at: headersDir.appendingPathComponent(path))
352+
}
353+
}
354+
return frameworks
355+
}
356+
309357
/// Try to build and package the contents of the Zip file. This will throw an error as soon as it
310358
/// encounters an error, or will quit due to a fatal error with the appropriate log.
311359
///

0 commit comments

Comments
 (0)