diff --git a/.agents/skills/firebase-cpp-builder/SKILL.md b/.agents/skills/firebase-cpp-builder/SKILL.md index 1103971536..f01ff9dbf2 100644 --- a/.agents/skills/firebase-cpp-builder/SKILL.md +++ b/.agents/skills/firebase-cpp-builder/SKILL.md @@ -52,8 +52,7 @@ For iOS, you can use the convenience script from the repository root: _(Run `./build_scripts/ios/build.sh -h` for more options.)_ -Alternatively, you can use CMake's native Xcode generator manually. Ensure you -have CocoaPods installed if building products that depend on iOS SDK Pods. +Alternatively, you can use CMake's native Xcode generator manually. ```bash mkdir ios_build diff --git a/.github/workflows/update-dependencies.yml b/.github/workflows/update-dependencies.yml index d5a8a7abeb..c73f244149 100644 --- a/.github/workflows/update-dependencies.yml +++ b/.github/workflows/update-dependencies.yml @@ -80,84 +80,64 @@ jobs: python scripts/update_android_ios_dependencies.py --skip_android --logfile=${UPDATE_LOGFILE} echo "CHOSEN_DEPS=iOS" >> $GITHUB_ENV fi - # iOS: Update Firestore external version to match Firestore Cocoapod version. - firestore_version=$(grep "pod 'Firebase/Firestore'" ios_pod/Podfile | sed "s/.*'\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\)'.*/\1/") - echo "Setting Firestore external version to ${firestore_version}" - sed -i~ "s/^set(version [^)]*)/set(version CocoaPods-${firestore_version})/i" cmake/external/firestore.cmake - # iOS: Update Analytics header files, used for generating constants. - analytics_version=$(grep "pod 'Firebase/Analytics'" ios_pod/Podfile | sed "s/.*'\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\)'.*/\1/") - if [[ "$(uname)" == "Darwin"* ]]; then - echo "Updating Analytics iOS headers from version ${analytics_version}" - # Unfortunately we can't just download these headers from GitHub, as - # Analytics is closed-source. If it becomes open-source, we could just - # download the header files from the iOS SDK's release branch. So instead, - # download the Firebase Analytics cocoapod (via a stub project) and get the - # header from there. This will only work on macOS. - podtmp="$(mktemp -d)" - cd "${podtmp}" - # Generate a Podfile for Firebase/Analytics. Use the Specs.git - # source to avoid any propagation delays due to CocoaPods mirror. - echo "source 'https://github.com/CocoaPods/Specs.git'" > Podfile - echo "platform :ios, '15.0'" >> Podfile - echo "pod 'Firebase/Analytics', '${analytics_version}'" >> Podfile - pod repo update - pod install || true # ignore error since there is no Xcode project - declare -a header_dirs - # Get all of the framework header directories from the xcframework. - header_dirs=(Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/*/FirebaseAnalytics.framework/Headers) - # Just use the first directory found, the headers should be the same across - # all of the frameworks. - header_dir="${header_dirs[0]}" - cd - - cd analytics/ios_headers - for ios_header in *.h; do - # Each file in this directory matches a file in the Analytics iOS SDK. - cp -vf "${podtmp}/${header_dir}/${ios_header}" . - # If the file doesn't have a Google copyright, add one. - if ! grep -q "^// Copyright [0-9]* Google LLC" "${ios_header}"; then - copyright_line="// Copyright $(date +%Y) Google LLC\n" - else - copyright_line= - fi - # Add a note to each file about its source. - sed -i~ "s|^/// @file|${copyright_line}\n// Copied from Firebase Analytics iOS SDK ${analytics_version}.\n\n/// @file|" "${ios_header}" - rm -f "${ios_header}~" # remove backup file that sed generated - python ../../scripts/format_code.py --f "${ios_header}" - done - cd - - rm -rf "${podtmp}" - fi + # iOS: Update Firestore external version to match Firebase iOS SDK version. + firebase_ios_version=$(grep "firebase-ios-sdk.git" ios_spm/Package.swift | sed 's/.*exact: "\([^"]*\)".*/\1/') + echo "Setting Firestore external version to ${firebase_ios_version}" + sed -i~ "s/^set(version [^)]*)/set(version ${firebase_ios_version})/i" cmake/external/firestore.cmake - # Download the zip distribution and get the Swift header files. - core_version=$(grep "pod 'Firebase/Core'" ios_pod/Podfile | sed "s/.*'\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\)'.*/\1/") - echo "Getting Swift header files from Firebase iOS SDK ${core_version} zip distribution" + # Download the Firebase iOS prebuilt zip distribution for Analytics and Swift headers. + echo "Downloading Firebase iOS SDK ${firebase_ios_version} prebuilt zip distribution" ziptmp="$(mktemp -d)" - # The version might be named vX.Y.Z or simply X.Y.Z, check which exists. declare -a zip_urls - zip_urls=("https://github.com/firebase/firebase-ios-sdk/releases/download/v${core_version}/Firebase.zip" "https://github.com/firebase/firebase-ios-sdk/releases/download/${core_version}/Firebase.zip") + zip_urls=("https://github.com/firebase/firebase-ios-sdk/releases/download/v${firebase_ios_version}/Firebase.zip" "https://github.com/firebase/firebase-ios-sdk/releases/download/${firebase_ios_version}/Firebase.zip") for try_url in ${zip_urls[@]} error; do curl -H 'Authorization: token ${{ github.token }}' -L -f "${try_url}" -o "${ziptmp}/Firebase.zip" 2> /dev/null && break done if [[ "${try_url}" == "error" ]]; then - echo "::error ::Could not download Firebase iOS prebuilt zip file, skipping Swift headers." + echo "::error ::Could not download Firebase iOS prebuilt zip file, skipping iOS headers update." else cd "${ziptmp}" echo "Unzipping..." - unzip -q Firebase.zip '*-Swift.h' + unzip -q Firebase.zip cd - - # Copy all *-Swift.h header files into ios_pod/swift_headers/ - echo "Copying headers..." - find "${ziptmp}" -name '*-Swift.h' -path '*ios*arm64*x86_64*simulator*' -print0 | xargs -0 -n 1 -J REPLACETEXT cp -f REPLACETEXT ios_pod/swift_headers/ + + # iOS: Update Analytics header files, used for generating constants. + echo "Updating Analytics iOS headers from version ${firebase_ios_version}" + declare -a header_dirs + header_dirs=("${ziptmp}"/FirebaseAnalytics/FirebaseAnalytics.xcframework/*/FirebaseAnalytics.framework/Headers) + if [[ -d "${header_dirs[0]}" ]]; then + header_dir="${header_dirs[0]}" + cd analytics/ios_headers + for ios_header in *.h; do + if [[ -f "${header_dir}/${ios_header}" ]]; then + cp -vf "${header_dir}/${ios_header}" . + if ! grep -q "^// Copyright [0-9]* Google LLC" "${ios_header}"; then + copyright_line="// Copyright $(date +%Y) Google LLC\n" + else + copyright_line= + fi + sed -i~ "s|^/// @file|${copyright_line}\n// Copied from Firebase Analytics iOS SDK ${firebase_ios_version}.\n\n/// @file|" "${ios_header}" + rm -f "${ios_header}~" + python ../../scripts/format_code.py --f "${ios_header}" + fi + done + cd - + fi + + # Copy all *-Swift.h header files into ios_spm/swift_headers/ + echo "Copying Swift bridging headers..." + mkdir -p ios_spm/swift_headers + find "${ziptmp}" -name '*-Swift.h' -path '*ios*arm64*x86_64*simulator*' -print0 | xargs -0 -n 1 -J REPLACETEXT cp -f REPLACETEXT ios_spm/swift_headers/ copyright_line="// Copyright $(date +%Y) Google LLC" # Add a note to each file about its source. - for ios_header in ios_pod/swift_headers/*.h; do + for ios_header in ios_spm/swift_headers/*.h; do if ! grep -q "^// Copied from Firebase iOS SDK" "${ios_header}"; then - sed -i~ "s|^// Generated by Apple Swift|${copyright_line}\n// Copied from Firebase iOS SDK ${core_version}.\n\n// Generated by Apple Swift|" "${ios_header}" + sed -i~ "s|^// Generated by Apple Swift|${copyright_line}\n// Copied from Firebase iOS SDK ${firebase_ios_version}.\n\n// Generated by Apple Swift|" "${ios_header}" fi python3 scripts/format_code.py --f "${ios_header}" done fi - rm -rf ${ziptmp} + rm -rf "${ziptmp}" elif [[ ${GITHUB_EVENT_INPUTS_UPDATEANDROID} -eq 1 ]]; then # Update Android only echo "Updating Android dependencies only" diff --git a/AGENTS.md b/AGENTS.md index 83f1b7fe60..8659536d7c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -42,7 +42,6 @@ instructions for your specific platform. recommended) is also needed. * **(Windows Only) Strings**: From Microsoft Sysinternals, required for Android builds on Windows. -* **Cocoapods**: Required for building iOS or tvOS libraries. To build for Desktop, you can install prerequisites by running the following script in the root of the repository: `scripts/gha/install_prereqs_desktop.py` diff --git a/CMakeLists.txt b/CMakeLists.txt index bfd9306cc9..7cd1a549a2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -601,7 +601,7 @@ if(MSVC) add_definitions(-DNOMINMAX) endif() -add_subdirectory(ios_pod) +add_subdirectory(ios_spm) # If we're building tests, we need to include the 'testing' folder before any # of the tests actually get built. diff --git a/README.md b/README.md index 5eee29122e..d8651d95ba 100644 --- a/README.md +++ b/README.md @@ -94,8 +94,6 @@ Note that we include the Gradle wrapper, which if used will acquire the necessary version of Gradle for you. ### Prerequisites for iOS/tvOS -The following prerequisites are required when building the libraries for iOS or tvOS. -- [Cocoapods](https://cocoapods.org/) @@ -192,7 +190,7 @@ that work for both iOS and tvOS. This is helpful as we can use the same deliverable for both iOS and tvOS targets in the same XCode project. ``` bash -# Install prereqs (like cocoapods) +# Install prereqs ./build_scripts/tvos/install_prereqs.sh python3 scripts/gha/build_ios_tvos.py -s . -b ios_tvos_build ``` diff --git a/analytics/CMakeLists.txt b/analytics/CMakeLists.txt index 48d21a8942..f45af19e64 100644 --- a/analytics/CMakeLists.txt +++ b/analytics/CMakeLists.txt @@ -149,13 +149,7 @@ elseif(IOS) target_include_directories(firebase_analytics PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") endif() - # Swift needs to find the FirebaseAnalytics module from CocoaPods - set(pods_dir "${FIREBASE_POD_DIR}/Pods") - - # Point to the base directories containing the .xcframework folders. - # Xcode natively handles XCFrameworks and will pick the right slice automatically. - # Determine the xcframework architecture slice based on the target platform - # and if it is running on simulator or device. + # Swift needs to find the FirebaseAnalytics module from SwiftPM artifacts string(TOLOWER "${CMAKE_OSX_SYSROOT}" sysroot_lower) if(CMAKE_SYSTEM_NAME STREQUAL "tvOS") if(sysroot_lower MATCHES "simulator") @@ -171,9 +165,15 @@ elseif(IOS) endif() endif() - set(analytics_framework_dir "${pods_dir}/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/${analytics_slice}") - set(measurement_framework_dir "${pods_dir}/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/${analytics_slice}") + set(analytics_framework_dir "${FIREBASE_SPM_ARTIFACTS_DIR}/firebase-ios-sdk/FirebaseAnalytics/FirebaseAnalytics.xcframework/${analytics_slice}") + set(measurement_framework_dir "${FIREBASE_SPM_ARTIFACTS_DIR}/googleappmeasurement/GoogleAppMeasurement/GoogleAppMeasurement.xcframework/${analytics_slice}") + target_include_directories(firebase_analytics + PUBLIC + "${analytics_framework_dir}/FirebaseAnalytics.framework/Headers" + "${measurement_framework_dir}/GoogleAppMeasurement.framework/Headers" + ) + target_compile_options(firebase_analytics PRIVATE $<$:-F${analytics_framework_dir}> @@ -191,11 +191,12 @@ elseif(IOS) XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH "YES" ) - setup_pod_headers( + setup_spm_headers( firebase_analytics - POD_NAMES + MODULES FirebaseCore FirebaseAnalytics + GoogleAppMeasurement ) if (FIREBASE_XCODE_TARGET_FORMAT STREQUAL "frameworks") diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index d68b303c46..5c5d735e7e 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -376,13 +376,10 @@ elseif(IOS) # Xcode 14 and is completely unsupported by modern Swift toolchains. target_compile_options(firebase_app PUBLIC $<$>:-fobjc-arc>) - # Add empty include path to get root include folder '.' - setup_pod_headers( + setup_spm_headers( firebase_app - POD_NAMES - . + MODULES FirebaseCore - FirebaseInstanceID ) else() target_link_libraries(firebase_app @@ -469,10 +466,10 @@ if (IOS) ${FIREBASE_SOURCE_DIR}/firestore/src/include/firebase/firestore/transaction.h ${FIREBASE_SOURCE_DIR}/firestore/src/include/firebase/firestore/transaction_options.h ${FIREBASE_SOURCE_DIR}/firestore/src/include/firebase/firestore/write_batch.h - ${FIREBASE_POD_DIR}/Pods/FirebaseFirestoreInternal/Firestore/core/include/firebase/firestore/firestore_errors.h - ${FIREBASE_POD_DIR}/Pods/FirebaseFirestoreInternal/Firestore/core/include/firebase/firestore/firestore_version.h - ${FIREBASE_POD_DIR}/Pods/FirebaseFirestoreInternal/Firestore/core/include/firebase/firestore/geo_point.h - ${FIREBASE_POD_DIR}/Pods/FirebaseFirestoreInternal/Firestore/core/include/firebase/firestore/timestamp.h) + ${FIREBASE_SPM_CHECKOUTS_DIR}/firebase-ios-sdk/Firestore/core/include/firebase/firestore/firestore_errors.h + ${FIREBASE_SPM_CHECKOUTS_DIR}/firebase-ios-sdk/Firestore/core/include/firebase/firestore/firestore_version.h + ${FIREBASE_SPM_CHECKOUTS_DIR}/firebase-ios-sdk/Firestore/core/include/firebase/firestore/geo_point.h + ${FIREBASE_SPM_CHECKOUTS_DIR}/firebase-ios-sdk/Firestore/core/include/firebase/firestore/timestamp.h) set(functions_HDRS ${FIREBASE_SOURCE_DIR}/functions/src/include/firebase/functions.h ${FIREBASE_SOURCE_DIR}/functions/src/include/firebase/functions/callable_reference.h diff --git a/app_check/CMakeLists.txt b/app_check/CMakeLists.txt index a1fea32ad1..f27cc4a870 100644 --- a/app_check/CMakeLists.txt +++ b/app_check/CMakeLists.txt @@ -155,7 +155,7 @@ target_include_directories(firebase_app_check ${CMAKE_CURRENT_LIST_DIR}/src/include PRIVATE ${FIREBASE_CPP_SDK_ROOT_DIR} - ${FIREBASE_CPP_SDK_ROOT_DIR}/ios_pod/swift_headers + ${FIREBASE_SPM_SWIFT_HEADERS_DIR} ) target_compile_definitions(firebase_app_check PRIVATE @@ -171,13 +171,13 @@ elseif(IOS) target_link_libraries(firebase_app_check PUBLIC "-fembed-bitcode") - setup_pod_headers( + setup_spm_headers( firebase_app_check - POD_NAMES + INCLUDE_PRIVATE_HEADERS + MODULES FirebaseCore FirebaseAppCheck - FirebaseAppCheckInterop/FirebaseAppCheck/Interop - INCLUDE_PRIVATE_HEADERS + FirebaseAppCheckInterop ) if (FIREBASE_XCODE_TARGET_FORMAT STREQUAL "frameworks") diff --git a/auth/CMakeLists.txt b/auth/CMakeLists.txt index 235c85d695..2c1dbe3be3 100644 --- a/auth/CMakeLists.txt +++ b/auth/CMakeLists.txt @@ -174,7 +174,7 @@ target_include_directories(firebase_auth ${CMAKE_CURRENT_LIST_DIR}/src/include PRIVATE ${FIREBASE_CPP_SDK_ROOT_DIR} - ${FIREBASE_CPP_SDK_ROOT_DIR}/ios_pod/swift_headers + ${FIREBASE_SPM_SWIFT_HEADERS_DIR} ${additional_include_DIR} ) target_compile_definitions(firebase_auth @@ -191,12 +191,12 @@ elseif(IOS) target_link_libraries(firebase_auth PUBLIC "-fembed-bitcode") - setup_pod_headers( + setup_spm_headers( firebase_auth - POD_NAMES + MODULES FirebaseCore FirebaseAuth - FirebaseAuthInterop/FirebaseAuth/Interop + FirebaseAuthInterop ) if (FIREBASE_XCODE_TARGET_FORMAT STREQUAL "frameworks") set_target_properties(firebase_auth PROPERTIES diff --git a/build_scripts/ios/install_prereqs.sh b/build_scripts/ios/install_prereqs.sh index 1c90d918ab..29d678e85f 100755 --- a/build_scripts/ios/install_prereqs.sh +++ b/build_scripts/ios/install_prereqs.sh @@ -36,11 +36,8 @@ if [[ -z $(xcode-select -p) || ! -d $(xcode-select -p) ]]; then exit 1 fi -if [[ -z $(which pod) ]]; then - echo "Cocoapods not detected, installing..." - sudo gem install cocoapods +if [[ -z $(which swift) ]]; then + echo "Error, swift compiler not installed or not in PATH." + exit 1 fi -echo "Updating Cocoapods repo..." -pod repo update - diff --git a/build_scripts/tvos/install_prereqs.sh b/build_scripts/tvos/install_prereqs.sh index 13f724aecb..929e26f42d 100755 --- a/build_scripts/tvos/install_prereqs.sh +++ b/build_scripts/tvos/install_prereqs.sh @@ -36,11 +36,8 @@ if [[ -z $(xcode-select -p) || ! -d $(xcode-select -p) ]]; then exit 1 fi -if [[ -z $(which pod) ]]; then - echo "Cocoapods not detected, installing..." - sudo gem install cocoapods +if [[ -z $(which swift) ]]; then + echo "Error, swift compiler not installed or not in PATH." + exit 1 fi -echo "Updating Cocoapods repo..." -pod repo update - diff --git a/cmake/external/firestore.cmake b/cmake/external/firestore.cmake index 87abfc8ffe..c7b47e0758 100644 --- a/cmake/external/firestore.cmake +++ b/cmake/external/firestore.cmake @@ -20,8 +20,7 @@ endif() # If the format of the line below changes, then be sure to update # https://github.com/firebase/firebase-cpp-sdk/blob/fd054fa016/.github/workflows/update-dependencies.yml#L81 -#set(version CocoaPods-11.8.1) -set(version CocoaPods-12.19.0) +set(version 12.19.0) function(GetReleasedDep) message("Getting released firebase-ios-sdk @ ${version}") diff --git a/database/CMakeLists.txt b/database/CMakeLists.txt index d66b52433f..1df98b1f3e 100644 --- a/database/CMakeLists.txt +++ b/database/CMakeLists.txt @@ -226,9 +226,9 @@ elseif(IOS) target_link_libraries(firebase_database PUBLIC "-fembed-bitcode") - setup_pod_headers( + setup_spm_headers( firebase_database - POD_NAMES + MODULES FirebaseCore FirebaseDatabase ) diff --git a/firestore/CMakeLists.txt b/firestore/CMakeLists.txt index ae22ddd8ea..a278e26c96 100644 --- a/firestore/CMakeLists.txt +++ b/firestore/CMakeLists.txt @@ -336,21 +336,20 @@ target_include_directories(firebase_firestore if(IOS) target_include_directories(firebase_firestore PUBLIC - # The Firestore core on iOS comes via the FirebaseFirestore CocoaPod, and + # The Firestore core on iOS comes via the FirebaseFirestore Swift Package, and # public headers should come from there. - ${FIREBASE_POD_DIR}/Pods/FirebaseFirestore/Firestore/core/include - ${FIREBASE_POD_DIR}/Pods/FirebaseFirestoreInternal/Firestore/core/include - ${FIREBASE_POD_DIR}/Pods/FirebaseFirestore/Firestore/Protos/nanopb - ${FIREBASE_POD_DIR}/Pods/FirebaseFirestoreInternal/Firestore/Protos/nanopb + ${FIREBASE_SPM_CHECKOUTS_DIR}/firebase-ios-sdk/Firestore/core/include + ${FIREBASE_SPM_CHECKOUTS_DIR}/firebase-ios-sdk/Firestore/Protos/nanopb PRIVATE # Additionally, the core C++ API is not declared publicly within the - # FirebaseFirestore pod, so depend on headers available in the source + # FirebaseFirestore package, so depend on headers available in the source # distribution. - ${FIREBASE_POD_DIR}/Pods/FirebaseFirestore - ${FIREBASE_POD_DIR}/Pods/FirebaseFirestoreInternal + ${FIREBASE_SPM_CHECKOUTS_DIR}/firebase-ios-sdk + ${FIREBASE_SPM_CHECKOUTS_DIR}/firebase-ios-sdk/Firestore + ${FIREBASE_SPM_CHECKOUTS_DIR}/firebase-ios-sdk/FirebaseFirestoreInternal ) set(FIREBASE_FIRESTORE_CORE_HEADER_DIR - ${FIREBASE_POD_DIR}/Pods/FirebaseFirestoreInternal/Firestore/core/include + ${FIREBASE_SPM_CHECKOUTS_DIR}/firebase-ios-sdk/Firestore/core/include ) else() @@ -425,19 +424,17 @@ elseif(IOS) target_link_libraries(firebase_firestore PUBLIC "-fembed-bitcode") - setup_pod_headers( + setup_spm_headers( firebase_firestore INCLUDE_PRIVATE_HEADERS - POD_NAMES + MODULES FirebaseCore FirebaseFirestore FirebaseFirestoreInternal + FirebaseAuthInterop abseil nanopb - gRPC-C++ - gRPC-Core - FirebaseAuthInterop/FirebaseAuth/Interop - FirebaseCoreExtension/FirebaseCore/Extension + gRPC ) if (FIREBASE_XCODE_TARGET_FORMAT STREQUAL "frameworks") diff --git a/firestore/CONTRIBUTING.md b/firestore/CONTRIBUTING.md index 4f9856a511..5756bae3fa 100644 --- a/firestore/CONTRIBUTING.md +++ b/firestore/CONTRIBUTING.md @@ -126,7 +126,7 @@ Then attach the debugger from Android Studio to unblock the testapp. # iOS building and testing -When targting iOS, the SDK gets its dependency from Cocoapods, as opposed to from `cmake/external/firestore.cmake`. +When targting iOS, the SDK gets its dependency from Swift Packages, as opposed to from `cmake/external/firestore.cmake`. The dependencies are specified with `ios_pod/Podfile`. Running cmake for iOS will download the pods listed in this file, and add the C++ headers from the downloaded pods to include directories. diff --git a/functions/CMakeLists.txt b/functions/CMakeLists.txt index 7fe1ceb927..62d3b0fe06 100644 --- a/functions/CMakeLists.txt +++ b/functions/CMakeLists.txt @@ -75,7 +75,7 @@ target_include_directories(firebase_functions ${CMAKE_CURRENT_LIST_DIR}/src/include PRIVATE ${FIREBASE_CPP_SDK_ROOT_DIR} - ${FIREBASE_CPP_SDK_ROOT_DIR}/ios_pod/swift_headers + ${FIREBASE_SPM_SWIFT_HEADERS_DIR} ) target_compile_definitions(firebase_functions PRIVATE @@ -89,11 +89,11 @@ elseif(IOS) target_compile_options(firebase_functions PUBLIC "-fobjc-arc" "-fembed-bitcode") target_link_libraries(firebase_functions - PUBLIC "-fembed-bitcode") + PUBLIC "-fembed-bitcode") - setup_pod_headers( + setup_spm_headers( firebase_functions - POD_NAMES + MODULES FirebaseCore FirebaseFunctions ) diff --git a/installations/CMakeLists.txt b/installations/CMakeLists.txt index ca7741c94d..1ead2dfd92 100644 --- a/installations/CMakeLists.txt +++ b/installations/CMakeLists.txt @@ -74,9 +74,9 @@ elseif(IOS) target_link_libraries(firebase_installations PUBLIC "-fembed-bitcode") - setup_pod_headers( + setup_spm_headers( firebase_installations - POD_NAMES + MODULES FirebaseCore FirebaseInstallations ) diff --git a/ios_pod/CMakeLists.txt b/ios_pod/CMakeLists.txt deleted file mode 100644 index a2c8255aac..0000000000 --- a/ios_pod/CMakeLists.txt +++ /dev/null @@ -1,216 +0,0 @@ -# Copyright 2019 Google -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -if(NOT IOS) - return() -endif() - -# Add these two vars to the cache to make them avaliable in global scope -set(FIREBASE_POD_DIR ${CMAKE_CURRENT_BINARY_DIR} CACHE STRING "") -set(FIREBASE_POD_HEADER_DIR - "${FIREBASE_POD_DIR}/Pods/Headers/Public" - CACHE STRING "" -) -# Rarely, but occasionally, libraries require access to private Firebase -# headers. -set(FIREBASE_POD_PRIVATE_HEADER_DIR - "${FIREBASE_POD_DIR}/Pods/Headers/Private" - CACHE STRING "" -) - -# Copy build files to trigger pod install as it requires a valid Xcode project -file( - COPY - Podfile - empty.cc - empty_CMakeLists.txt DESTINATION - "${FIREBASE_POD_DIR}" -) - -# Rename cmake file -file( - RENAME - "${FIREBASE_POD_DIR}/empty_CMakeLists.txt" - "${FIREBASE_POD_DIR}/CMakeLists.txt" -) - -message("Downloading CocoaPods...") - -execute_process( - COMMAND /bin/bash -c - "mkdir -p ${FIREBASE_POD_DIR} && cd ${FIREBASE_POD_DIR} && cmake . -G Xcode && pod install" - OUTPUT_VARIABLE pods_output -) - -message("${pods_output}") - - - -# Sets up a target to have the correct dependencies on the install pods target -# and also adds the correct include paths to the pod header files -# -# Usage: setup_pod_headers( -# POD_NAMES [...] -# INCLUDE_PRIVATE_HEADERS -# ) -# -# Args: -# target_name: Name of target to add includes to -# pod_names: Array of pod names to configure -# -function(setup_pod_headers target_name) - set(multi OUTPUT_NAME POD_NAMES) - set(options INCLUDE_PRIVATE_HEADERS) - - # Parse the arguments into SETUP_POD_HEADERS_POD_NAMES. - cmake_parse_arguments(SETUP_POD_HEADERS "${options}" "" "${multi}" ${ARGN}) - - if(NOT "${SETUP_POD_HEADERS_POD_NAMES}" STREQUAL "") - foreach (pod ${SETUP_POD_HEADERS_POD_NAMES}) - # Add pod name twice as some frameworks moved includes inside a folder with - # the pod name - target_include_directories(${target_name} - # Link the Pods publicly, so that dependent libraries can access the necessary header files as well. - # Same for the below workaround. - # Also link from the Sources/Public directories, for framework pods. - PUBLIC - ${FIREBASE_POD_HEADER_DIR}/${pod} - ${FIREBASE_POD_HEADER_DIR}/${pod}/${pod} - ${FIREBASE_POD_DIR}/Pods/${pod}/${pod}/Sources/Public - ${FIREBASE_POD_DIR}/Pods/${pod}/${pod}/Sources/Public/${pod} - ${FIREBASE_POD_DIR}/Pods/${pod}/${pod}/Source/Library/Public - ${FIREBASE_POD_DIR}/Pods/${pod}/${pod}/Source/Library/Public/${pod} - ${FIREBASE_POD_DIR}/Pods/${pod}/Public - ) - if("${SETUP_POD_HEADERS_INCLUDE_PRIVATE_HEADERS}") - # Workaround: Private/FirebaseCore/*.h headers include other FirebaseCore headers via the subdirectory, so - # we need to include the top-level Private directory as a header path. This only affects Firestore at the moment, as - # no other C++ library includes a private Pod header. - # Also link from the Sources/Private directory, for framework pods. - target_include_directories(${target_name} - PUBLIC - ${FIREBASE_POD_PRIVATE_HEADER_DIR}/ - ${FIREBASE_POD_PRIVATE_HEADER_DIR}/${pod} - ${FIREBASE_POD_PRIVATE_HEADER_DIR}/${pod}/${pod} - ${FIREBASE_POD_DIR}/Pods/${pod} - ${FIREBASE_POD_DIR}/Pods/${pod}/include - ${FIREBASE_POD_DIR}/Pods/${pod}/${pod}/Sources/Private - ${FIREBASE_POD_DIR}/Pods/${pod}/${pod}/Sources - ${FIREBASE_POD_DIR}/Pods/${pod}/Source - ) - endif() - - symlink_pod_headers(${target_name} ${pod} ${pod}) - endforeach() - endif() -endfunction() - -# Creates a symlink to the header files of the given framework. Used when -# include paths are expecting the header files to be in a subdirectory, when -# accessing the header files directly does not have them in the same structure. -# -# Usage: symlink_pod_headers( -# [FRAMEWORK_DIR_NAME ] -# ) -# -# Args: -# target_name: Name of target to add includes to -# pod_name: Name of the pod in the Podfile -# dir_name: Name of the dir for the symlink (most cases should be same as pod_name) -# framework_dir: Set if pod uses a different folder name for frameworks -# -function(symlink_pod_headers target_name pod_name dir_name) - - set(multi OUTPUT_NAME FRAMEWORK_DIR_NAME) - - # Parse the arguments into SYMLINK_POD_FRAMEWORK_DIR_NAME. - cmake_parse_arguments(SYMLINK_POD "" "" "${multi}" ${ARGN}) - - set(FRAMEWORK_DIR "Frameworks") - - if(NOT "${SYMLINK_POD_FRAMEWORK_DIR_NAME}" STREQUAL "") - set(FRAMEWORK_DIR "${SYMLINK_POD_FRAMEWORK_DIR_NAME}") - endif() - - set(gen_file ${CMAKE_CURRENT_BINARY_DIR}/pod_sym_links/gen_${dir_name}.txt) - set(symlink_dir ${CMAKE_CURRENT_BINARY_DIR}/pod_sym_links/${dir_name}) - set(glob_dir "${FIREBASE_POD_DIR}/Pods/${pod_name}/${FRAMEWORK_DIR}/*/*.framework/Headers") - - file(GLOB framework_dir ${glob_dir}) - - # If failed to find headers, try again one folder up - if(NOT EXISTS ${framework_dir}) - set(glob_dir "${FIREBASE_POD_DIR}/Pods/${pod_name}/${FRAMEWORK_DIR}/*.framework/Headers") - file(GLOB framework_dir ${glob_dir}) - endif() - # If failed to find headers, try xcframework path. - if(NOT EXISTS ${framework_dir}) - set(glob_dir "${FIREBASE_POD_DIR}/Pods/${pod_name}/${FRAMEWORK_DIR}/*/*.xcframework/*/*.framework/Headers") - file(GLOB framework_dirs ${glob_dir}) - # xcframework contains several frameworks. Their Headers are the same. So it's okay use first framework's Headers - list(LENGTH framework_dirs dir_len) - if(dir_len GREATER 0) - list(GET framework_dirs 0 first_dir) - file(GLOB framework_dir ${first_dir}) - endif() - endif() - - # If failed to find headers, try xcframework path. - if(NOT EXISTS ${framework_dir}) - set(glob_dir "${FIREBASE_POD_DIR}/Pods/${pod_name}/${FRAMEWORK_DIR}/*/*.xcframework/*/*.framework/Headers") - file(GLOB framework_dirs ${glob_dir}) - # xcframework contains several frameworks. Their Headers are the same. So it's okay use first framework's Headers - list(LENGTH framework_dirs dir_len) - if(dir_len GREATER 0) - list(GET framework_dirs 0 first_dir) - file(GLOB framework_dir ${first_dir}) - endif() - endif() - - # If failed to find headers, try alternate xcframework path. - if(NOT EXISTS ${framework_dir}) - set(glob_dir "${FIREBASE_POD_DIR}/Pods/${pod_name}/${FRAMEWORK_DIR}/*.xcframework/*/*.framework/Headers") - file(GLOB framework_dirs ${glob_dir}) - # xcframework contains several frameworks. Their Headers are the same. So it's okay use first framework's Headers - list(LENGTH framework_dirs dir_len) - if(dir_len GREATER 0) - list(GET framework_dirs 0 first_dir) - file(GLOB framework_dir ${first_dir}) - endif() - endif() - - # Maybe this pod is not a framework, continue - if(NOT EXISTS ${framework_dir}) - return() - endif() - - add_custom_command( - OUTPUT "${gen_file}" - COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/pod_sym_links - && rm -fr ${symlink_dir} - && ln -sf ${framework_dir} ${symlink_dir} - && touch ${gen_file} - DEPENDS ${FIREBASE_POD_HEADER_DIR} - COMMENT "Sym linking pod framework '${framework_dir}' to '${symlink_dir}'" - ) - - add_custom_target(${target_name}_symlink_${dir_name} DEPENDS ${gen_file}) - add_dependencies(${target_name} ${target_name}_symlink_${dir_name}) - - target_include_directories(${target_name} - PRIVATE - ${CMAKE_CURRENT_BINARY_DIR}/pod_sym_links - ${CMAKE_CURRENT_BINARY_DIR}/pod_sym_links/${dir_name} - ) -endfunction() diff --git a/ios_pod/Podfile b/ios_pod/Podfile deleted file mode 100644 index 66c254e954..0000000000 --- a/ios_pod/Podfile +++ /dev/null @@ -1,21 +0,0 @@ -source 'https://github.com/CocoaPods/Specs.git' -platform :ios, '15.0' -use_frameworks! - -target 'GetPods' do - pod 'Firebase/Core', '12.19.0' - - pod 'GoogleUserMessagingPlatform', '2.3.0' - pod 'Firebase/Analytics', '12.19.0' - pod 'Firebase/AppCheck', '12.19.0' - pod 'Firebase/Auth', '12.19.0' - pod 'Firebase/Crashlytics', '12.19.0' - pod 'Firebase/Database', '12.19.0' - pod 'Firebase/Firestore', '12.19.0' - pod 'Firebase/Functions', '12.19.0' - pod 'Firebase/Installations', '12.19.0' - pod 'Firebase/Messaging', '12.19.0' - pod 'Firebase/RemoteConfig', '12.19.0' - pod 'Firebase/Storage', '12.19.0' - -end diff --git a/ios_pod/empty.cc b/ios_pod/empty.cc deleted file mode 100644 index 8ff4a193ee..0000000000 --- a/ios_pod/empty.cc +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Google -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Stub file to enable cmake to download required pod files diff --git a/ios_pod/empty_CMakeLists.txt b/ios_pod/empty_CMakeLists.txt deleted file mode 100644 index 2f37e4e790..0000000000 --- a/ios_pod/empty_CMakeLists.txt +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright 2019 Google -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Stub cmake project to enable pod files to be installed against - -cmake_minimum_required(VERSION 3.22) - -project (GetPods CXX) -add_library(GetPods empty.cc) diff --git a/ios_pod/readme.txt b/ios_pod/readme.txt deleted file mode 100644 index 616fdd7fa8..0000000000 --- a/ios_pod/readme.txt +++ /dev/null @@ -1,13 +0,0 @@ -firebase-cpp-sdk/ios_pod directory - -This directory contains a Podfile that allows us to install the Firebase iOS SDK -via CocoaPods. The Podfile here must include all Cocoapods used by the Firebase -C++ SDK. The pods are extracted as part of the build process, and the header -files within them are referenced by the Objective-C++ code in this SDK (see -setup_pod_headers in CMakeLists.txt for details). - -The "swift_headers" subdirectory contains copies of the most recent Swift -bridging headers for the Firebase iOS libraries that are written in Swift, -enabling them to be called from this SDK's Objective-C++ code. These headers are -copied from the most recent firebase-ios-sdk release via this repository's -update-dependencies.yml GitHub Actions workflow. diff --git a/ios_spm/CMakeLists.txt b/ios_spm/CMakeLists.txt new file mode 100644 index 0000000000..68222d6a1c --- /dev/null +++ b/ios_spm/CMakeLists.txt @@ -0,0 +1,206 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +if(NOT IOS) + return() +endif() + +# Global variables for Swift Package Manager paths +set(FIREBASE_SPM_DIR "${CMAKE_CURRENT_BINARY_DIR}" CACHE STRING "Directory for Swift Package Manager resolution" FORCE) +set(FIREBASE_SPM_CHECKOUTS_DIR "${FIREBASE_SPM_DIR}/.build/checkouts" CACHE STRING "Path to SwiftPM package checkouts" FORCE) +set(FIREBASE_SPM_ARTIFACTS_DIR "${FIREBASE_SPM_DIR}/.build/artifacts" CACHE STRING "Path to SwiftPM binary artifacts" FORCE) +set(FIREBASE_SPM_SWIFT_HEADERS_DIR "${CMAKE_CURRENT_LIST_DIR}/swift_headers" CACHE STRING "Path to Swift bridging headers" FORCE) + +# Copy Package.swift to the build directory for resolution +file(COPY "${CMAKE_CURRENT_LIST_DIR}/Package.swift" DESTINATION "${FIREBASE_SPM_DIR}") + +message(STATUS "Resolving Swift Package dependencies for iOS/tvOS...") + +execute_process( + COMMAND ${CMAKE_COMMAND} -E env + GIT_CONFIG_COUNT=1 + GIT_CONFIG_KEY_0=safe.bareRepository + GIT_CONFIG_VALUE_0=all + swift package --package-path "${FIREBASE_SPM_DIR}" resolve + RESULT_VARIABLE spm_result + OUTPUT_VARIABLE spm_output + ERROR_VARIABLE spm_error +) + +if(NOT spm_result EQUAL 0) + message(FATAL_ERROR "Failed to resolve Swift packages via SwiftPM:\n${spm_error}\n${spm_output}") +endif() + +message(STATUS "Swift Package dependencies resolved successfully.") + +# Sets up a target with the include directories for the specified SwiftPM modules. +# +# Usage: setup_spm_headers( +# MODULES [...] +# [INCLUDE_PRIVATE_HEADERS] +# ) +# +# Args: +# target_name: Name of target to add includes to +# MODULES: Array of module names to configure (e.g. FirebaseCore, FirebaseAuth, etc.) +# INCLUDE_PRIVATE_HEADERS: Optional flag to also include internal / extension headers +# +function(setup_spm_headers target_name) + set(multi MODULES) + set(options INCLUDE_PRIVATE_HEADERS) + + cmake_parse_arguments(SETUP_SPM "${options}" "" "${multi}" ${ARGN}) + + if(NOT "${SETUP_SPM_MODULES}" STREQUAL "") + foreach(module ${SETUP_SPM_MODULES}) + # Check source checkouts under firebase-ios-sdk and root checkouts + set(public_dirs + "${FIREBASE_SPM_CHECKOUTS_DIR}/firebase-ios-sdk/${module}" + "${FIREBASE_SPM_CHECKOUTS_DIR}/firebase-ios-sdk/${module}/Sources/Public" + "${FIREBASE_SPM_CHECKOUTS_DIR}/firebase-ios-sdk/${module}/Sources/Public/${module}" + "${FIREBASE_SPM_CHECKOUTS_DIR}/firebase-ios-sdk/${module}/Source/Library/Public" + "${FIREBASE_SPM_CHECKOUTS_DIR}/firebase-ios-sdk/${module}/Source/Library/Public/${module}" + "${FIREBASE_SPM_CHECKOUTS_DIR}/firebase-ios-sdk/${module}/Interop/Public" + "${FIREBASE_SPM_CHECKOUTS_DIR}/firebase-ios-sdk/${module}/Interop/Public/${module}" + "${FIREBASE_SPM_CHECKOUTS_DIR}/firebase-ios-sdk/${module}/Public" + "${FIREBASE_SPM_CHECKOUTS_DIR}/firebase-ios-sdk/Firestore/core/include" + "${FIREBASE_SPM_CHECKOUTS_DIR}/firebase-ios-sdk/Firestore/Source/Public" + "${FIREBASE_SPM_CHECKOUTS_DIR}/firebase-ios-sdk/Firestore/Source/Public/FirebaseFirestore" + "${FIREBASE_SPM_CHECKOUTS_DIR}/${module}" + "${FIREBASE_SPM_CHECKOUTS_DIR}/${module}/spm_headers" + "${FIREBASE_SPM_CHECKOUTS_DIR}/interop-ios-for-google-sdks/${module}/Public" + "${FIREBASE_SPM_CHECKOUTS_DIR}/interop-ios-for-google-sdks/${module}/Public/${module}" + ) + + foreach(pdir ${public_dirs}) + if(EXISTS "${pdir}") + target_include_directories(${target_name} PUBLIC "${pdir}") + endif() + endforeach() + + if(SETUP_SPM_INCLUDE_PRIVATE_HEADERS) + set(private_dirs + "${FIREBASE_SPM_CHECKOUTS_DIR}/firebase-ios-sdk/${module}/Extension" + "${FIREBASE_SPM_CHECKOUTS_DIR}/firebase-ios-sdk/${module}/Sources" + "${FIREBASE_SPM_CHECKOUTS_DIR}/firebase-ios-sdk/${module}/Sources/Private" + "${FIREBASE_SPM_CHECKOUTS_DIR}/firebase-ios-sdk/${module}/Source" + "${FIREBASE_SPM_CHECKOUTS_DIR}/firebase-ios-sdk/${module}/Source/Library/Private" + "${FIREBASE_SPM_CHECKOUTS_DIR}/firebase-ios-sdk/${module}/include" + ) + foreach(pdir ${private_dirs}) + if(EXISTS "${pdir}") + target_include_directories(${target_name} PUBLIC "${pdir}") + endif() + endforeach() + endif() + + # Also attempt to symlink any binary xcframework headers for this module + symlink_spm_headers(${target_name} ${module} DIR_NAME ${module}) + endforeach() + endif() +endfunction() + +# Creates a symlink to the header files of the given binary xcframework. +# Used when include paths are expecting headers to be in a subdirectory or framework structure. +# +# Usage: symlink_spm_headers( +# [DIR_NAME ] +# ) +# +# Args: +# target_name: Name of target to add includes to +# module_name: Name of the binary target / artifact +# DIR_NAME: Name of the directory for the symlink (defaults to module_name) +# +function(symlink_spm_headers target_name module_name) + set(single DIR_NAME) + cmake_parse_arguments(SYMLINK_SPM "" "${single}" "" ${ARGN}) + + set(dir_name "${module_name}") + if(NOT "${SYMLINK_SPM_DIR_NAME}" STREQUAL "") + set(dir_name "${SYMLINK_SPM_DIR_NAME}") + endif() + + set(symlink_base_dir "${CMAKE_CURRENT_BINARY_DIR}/spm_sym_links") + + # Search for all header files in .build/artifacts to discover binary frameworks + file(GLOB_RECURSE all_headers "${FIREBASE_SPM_ARTIFACTS_DIR}/*.h") + + # Determine target slice priority if possible + string(TOLOWER "${CMAKE_OSX_SYSROOT}" sysroot_lower) + if(CMAKE_SYSTEM_NAME STREQUAL "tvOS") + if(sysroot_lower MATCHES "simulator") + set(preferred_slice "tvos-arm64_x86_64-simulator") + else() + set(preferred_slice "tvos-arm64") + endif() + else() + if(sysroot_lower MATCHES "simulator") + set(preferred_slice "ios-arm64_x86_64-simulator") + else() + set(preferred_slice "ios-arm64") + endif() + endif() + + # Build list of patterns to match + set(patterns "${module_name}" "${dir_name}") + if(module_name MATCHES "^(abseil|absl)$") + list(APPEND patterns "absl") + elseif(module_name MATCHES "^(grpc|gRPC|gRPC-C\\+\\+|gRPC-Core|grpcpp)$") + list(APPEND patterns "grpc" "grpcpp") + elseif(module_name MATCHES "^(GoogleUserMessagingPlatform|UserMessagingPlatform)$") + list(APPEND patterns "UserMessagingPlatform") + endif() + + set(processed_frameworks "") + + foreach(hdr ${all_headers}) + if(hdr MATCHES "([^/\\\\]+)\\.framework.*Headers") + set(fw_name "${CMAKE_MATCH_1}") + string(REGEX MATCH "(.*[/\\\\]${fw_name}\\.framework([^/\\\\]*)?[/\\\\]Headers)" _ "${hdr}") + set(fw_headers "${CMAKE_MATCH_1}") + + if(NOT "${fw_name}" IN_LIST processed_frameworks) + set(matches FALSE) + foreach(pat ${patterns}) + if(fw_name MATCHES "^${pat}$") + set(matches TRUE) + break() + endif() + endforeach() + + if(matches) + # Check if this header matches preferred slice or if we don't have one yet + if(fw_headers MATCHES "${preferred_slice}" OR NOT EXISTS "${symlink_base_dir}/${fw_name}") + file(MAKE_DIRECTORY "${symlink_base_dir}") + if(EXISTS "${symlink_base_dir}/${fw_name}") + file(REMOVE "${symlink_base_dir}/${fw_name}") + endif() + file(CREATE_LINK "${fw_headers}" "${symlink_base_dir}/${fw_name}" SYMBOLIC COPY_ON_ERROR) + + target_include_directories(${target_name} + PUBLIC + "${symlink_base_dir}" + "${symlink_base_dir}/${fw_name}" + "${fw_headers}" + ) + if(fw_headers MATCHES "${preferred_slice}") + list(APPEND processed_frameworks "${fw_name}") + endif() + endif() + endif() + endif() + endif() + endforeach() +endfunction() diff --git a/ios_spm/Package.swift b/ios_spm/Package.swift new file mode 100644 index 0000000000..c2d26b4389 --- /dev/null +++ b/ios_spm/Package.swift @@ -0,0 +1,49 @@ +// swift-tools-version:5.9 +// +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import PackageDescription + +let package = Package( + name: "FirebaseDependencies", + platforms: [ + .iOS(.v15), + .tvOS(.v15) + ], + products: [ + .library(name: "FirebaseDependencies", targets: ["FirebaseDependencies"]), + ], + dependencies: [ + .package(url: "https://github.com/firebase/firebase-ios-sdk.git", exact: "12.18.0"), + .package(url: "https://github.com/googleads/swift-package-manager-google-user-messaging-platform.git", exact: "2.3.0"), + ], + targets: [ + .target( + name: "FirebaseDependencies", + dependencies: [ + .product(name: "FirebaseAnalytics", package: "firebase-ios-sdk"), + .product(name: "FirebaseAuth", package: "firebase-ios-sdk"), + .product(name: "FirebaseDatabase", package: "firebase-ios-sdk"), + .product(name: "FirebaseFirestore", package: "firebase-ios-sdk"), + .product(name: "FirebaseFunctions", package: "firebase-ios-sdk"), + .product(name: "FirebaseInstallations", package: "firebase-ios-sdk"), + .product(name: "FirebaseMessaging", package: "firebase-ios-sdk"), + .product(name: "FirebaseRemoteConfig", package: "firebase-ios-sdk"), + .product(name: "FirebaseStorage", package: "firebase-ios-sdk"), + .product(name: "GoogleUserMessagingPlatform", package: "swift-package-manager-google-user-messaging-platform"), + ] + ), + ] +) diff --git a/ios_spm/readme.md b/ios_spm/readme.md new file mode 100644 index 0000000000..23ea9c9fa1 --- /dev/null +++ b/ios_spm/readme.md @@ -0,0 +1,15 @@ +# firebase-cpp-sdk/ios_spm directory + +This directory contains a `Package.swift` file that allows us to fetch the +Firebase iOS SDK and Google User Messaging Platform via Swift Package Manager +(SwiftPM). The `Package.swift` here must declare all Swift packages used by +the Firebase C++ SDK. The packages are resolved automatically during the CMake +configure step, and the header files and xcframeworks within them are +referenced by the Objective-C++ and C++ code in this SDK (see `setup_spm_headers` +in `CMakeLists.txt` for details). + +The `swift_headers` subdirectory contains copies of the most recent Swift +bridging headers (`*-Swift.h`) for the Firebase iOS libraries that are written +in Swift, enabling them to be called from this SDK's Objective-C++ code. These +headers are updated via this repository's `update-dependencies.yml` GitHub +Actions workflow. diff --git a/ios_pod/swift_headers/FirebaseAnalytics-Swift.h b/ios_spm/swift_headers/FirebaseAnalytics-Swift.h similarity index 100% rename from ios_pod/swift_headers/FirebaseAnalytics-Swift.h rename to ios_spm/swift_headers/FirebaseAnalytics-Swift.h diff --git a/ios_pod/swift_headers/FirebaseAnalyticsSwift-Swift.h b/ios_spm/swift_headers/FirebaseAnalyticsSwift-Swift.h similarity index 100% rename from ios_pod/swift_headers/FirebaseAnalyticsSwift-Swift.h rename to ios_spm/swift_headers/FirebaseAnalyticsSwift-Swift.h diff --git a/ios_pod/swift_headers/FirebaseAuth-Swift.h b/ios_spm/swift_headers/FirebaseAuth-Swift.h similarity index 100% rename from ios_pod/swift_headers/FirebaseAuth-Swift.h rename to ios_spm/swift_headers/FirebaseAuth-Swift.h diff --git a/ios_pod/swift_headers/FirebaseCoreInternal-Swift.h b/ios_spm/swift_headers/FirebaseCoreInternal-Swift.h similarity index 100% rename from ios_pod/swift_headers/FirebaseCoreInternal-Swift.h rename to ios_spm/swift_headers/FirebaseCoreInternal-Swift.h diff --git a/ios_pod/swift_headers/FirebaseDatabase-Swift.h b/ios_spm/swift_headers/FirebaseDatabase-Swift.h similarity index 100% rename from ios_pod/swift_headers/FirebaseDatabase-Swift.h rename to ios_spm/swift_headers/FirebaseDatabase-Swift.h diff --git a/ios_pod/swift_headers/FirebaseDatabaseSwift-Swift.h b/ios_spm/swift_headers/FirebaseDatabaseSwift-Swift.h similarity index 100% rename from ios_pod/swift_headers/FirebaseDatabaseSwift-Swift.h rename to ios_spm/swift_headers/FirebaseDatabaseSwift-Swift.h diff --git a/ios_pod/swift_headers/FirebaseFirestore-Swift.h b/ios_spm/swift_headers/FirebaseFirestore-Swift.h similarity index 100% rename from ios_pod/swift_headers/FirebaseFirestore-Swift.h rename to ios_spm/swift_headers/FirebaseFirestore-Swift.h diff --git a/ios_pod/swift_headers/FirebaseFirestoreSwift-Swift.h b/ios_spm/swift_headers/FirebaseFirestoreSwift-Swift.h similarity index 100% rename from ios_pod/swift_headers/FirebaseFirestoreSwift-Swift.h rename to ios_spm/swift_headers/FirebaseFirestoreSwift-Swift.h diff --git a/ios_pod/swift_headers/FirebaseFunctions-Swift.h b/ios_spm/swift_headers/FirebaseFunctions-Swift.h similarity index 100% rename from ios_pod/swift_headers/FirebaseFunctions-Swift.h rename to ios_spm/swift_headers/FirebaseFunctions-Swift.h diff --git a/ios_pod/swift_headers/FirebaseInAppMessaging-Swift.h b/ios_spm/swift_headers/FirebaseInAppMessaging-Swift.h similarity index 100% rename from ios_pod/swift_headers/FirebaseInAppMessaging-Swift.h rename to ios_spm/swift_headers/FirebaseInAppMessaging-Swift.h diff --git a/ios_pod/swift_headers/FirebaseInAppMessagingSwift-Swift.h b/ios_spm/swift_headers/FirebaseInAppMessagingSwift-Swift.h similarity index 100% rename from ios_pod/swift_headers/FirebaseInAppMessagingSwift-Swift.h rename to ios_spm/swift_headers/FirebaseInAppMessagingSwift-Swift.h diff --git a/ios_pod/swift_headers/FirebaseMLModelDownloader-Swift.h b/ios_spm/swift_headers/FirebaseMLModelDownloader-Swift.h similarity index 100% rename from ios_pod/swift_headers/FirebaseMLModelDownloader-Swift.h rename to ios_spm/swift_headers/FirebaseMLModelDownloader-Swift.h diff --git a/ios_pod/swift_headers/FirebaseRemoteConfig-Swift.h b/ios_spm/swift_headers/FirebaseRemoteConfig-Swift.h similarity index 100% rename from ios_pod/swift_headers/FirebaseRemoteConfig-Swift.h rename to ios_spm/swift_headers/FirebaseRemoteConfig-Swift.h diff --git a/ios_pod/swift_headers/FirebaseRemoteConfigSwift-Swift.h b/ios_spm/swift_headers/FirebaseRemoteConfigSwift-Swift.h similarity index 100% rename from ios_pod/swift_headers/FirebaseRemoteConfigSwift-Swift.h rename to ios_spm/swift_headers/FirebaseRemoteConfigSwift-Swift.h diff --git a/ios_pod/swift_headers/FirebaseSessions-Swift.h b/ios_spm/swift_headers/FirebaseSessions-Swift.h similarity index 100% rename from ios_pod/swift_headers/FirebaseSessions-Swift.h rename to ios_spm/swift_headers/FirebaseSessions-Swift.h diff --git a/ios_pod/swift_headers/FirebaseSharedSwift-Swift.h b/ios_spm/swift_headers/FirebaseSharedSwift-Swift.h similarity index 100% rename from ios_pod/swift_headers/FirebaseSharedSwift-Swift.h rename to ios_spm/swift_headers/FirebaseSharedSwift-Swift.h diff --git a/ios_pod/swift_headers/FirebaseStorage-Swift.h b/ios_spm/swift_headers/FirebaseStorage-Swift.h similarity index 100% rename from ios_pod/swift_headers/FirebaseStorage-Swift.h rename to ios_spm/swift_headers/FirebaseStorage-Swift.h diff --git a/ios_pod/swift_headers/Promises-Swift.h b/ios_spm/swift_headers/Promises-Swift.h similarity index 100% rename from ios_pod/swift_headers/Promises-Swift.h rename to ios_spm/swift_headers/Promises-Swift.h diff --git a/ios_pod/swift_headers/SwiftProtobuf-Swift.h b/ios_spm/swift_headers/SwiftProtobuf-Swift.h similarity index 100% rename from ios_pod/swift_headers/SwiftProtobuf-Swift.h rename to ios_spm/swift_headers/SwiftProtobuf-Swift.h diff --git a/messaging/CMakeLists.txt b/messaging/CMakeLists.txt index cf2e0378da..a45ace818e 100644 --- a/messaging/CMakeLists.txt +++ b/messaging/CMakeLists.txt @@ -123,9 +123,9 @@ elseif(IOS) target_link_libraries(firebase_messaging PUBLIC "-fembed-bitcode") - setup_pod_headers( + setup_spm_headers( firebase_messaging - POD_NAMES + MODULES FirebaseCore FirebaseMessaging ) diff --git a/remote_config/CMakeLists.txt b/remote_config/CMakeLists.txt index 7038ca475e..cf48e8d85e 100644 --- a/remote_config/CMakeLists.txt +++ b/remote_config/CMakeLists.txt @@ -149,9 +149,9 @@ elseif(IOS) target_link_libraries(firebase_remote_config PUBLIC "-fembed-bitcode") - setup_pod_headers( + setup_spm_headers( firebase_remote_config - POD_NAMES + MODULES FirebaseCore FirebaseRemoteConfig ) diff --git a/scripts/format_code.py b/scripts/format_code.py index 87fbb2f4f9..702b51ed7c 100755 --- a/scripts/format_code.py +++ b/scripts/format_code.py @@ -59,7 +59,7 @@ """Tuple: The file types to run clang-format on. Used to filter out results when searching across directories or git diffs. """ -FILE_PATHS_TO_IGNORE = re.compile(r'.*ios_pod/swift_headers/.*\.h') +FILE_PATHS_TO_IGNORE = re.compile(r'.*ios_(pod|spm)/swift_headers/.*\.h') """Regex pattern for files paths to ignore. Used to filter out results when searching across directories or git diffs. """ diff --git a/scripts/gha/build_ios_tvos.py b/scripts/gha/build_ios_tvos.py index 62d68b557b..016db9e0de 100644 --- a/scripts/gha/build_ios_tvos.py +++ b/scripts/gha/build_ios_tvos.py @@ -19,8 +19,8 @@ ios and tvos. It does the following, -- Build ios and tvos libraries via cmake (after downloading corresponding -cocoapods). +- Build ios and tvos libraries via cmake (after resolving corresponding +Swift packages). - Create a "universal" framework if all platforms and architectures were built. - Create "xcframeworks" combining both ios and tvos frameworks. @@ -558,7 +558,7 @@ def main(): '{0}_cmake_build'.format(apple_os), platform_architecture_token) # CMake configure was having all sorts of issues when run in parallel. - # It might be the Cocoapods that are downloaded in parallel into a + # It might be dependencies that are downloaded in parallel into a # single cache directory. cmake_configure(args.source_dir, build_path, os_platform_variant_config.get('toolchain'), diff --git a/scripts/gha/lint_commenter.py b/scripts/gha/lint_commenter.py index 2ac787173b..b63f7f0743 100755 --- a/scripts/gha/lint_commenter.py +++ b/scripts/gha/lint_commenter.py @@ -50,7 +50,7 @@ EXCLUDE_PATH_REGEX = [ # These files are copied from an external repo and are outside our control. r'^analytics/ios_headers/', - r'^ios_pod/swift_headers/' + r'^ios_(pod|spm)/swift_headers/' ] # The linter gives every error a confidence score. # 1 = It's most likely not really an issue. diff --git a/scripts/gha/print_matrix_configuration.py b/scripts/gha/print_matrix_configuration.py index 9df1eed4bb..2cb093fdc0 100644 --- a/scripts/gha/print_matrix_configuration.py +++ b/scripts/gha/print_matrix_configuration.py @@ -328,7 +328,7 @@ def filter_values_on_diff(parm_key, value, auto_diff): "cmake/external/firestore.cmake": "firestore", "cmake/external/libuv.cmake": "database", "cmake/external/uWebSockets.cmake": "database", - "ios_pod/Podfile":scan_changes_in_file, + "ios_spm/Package.swift":scan_changes_in_file, "Android/firebase_dependencies.gradle":scan_changes_in_file, "release_build_files/Android/firebase_dependencies.gradle":scan_changes_in_file, } @@ -338,7 +338,7 @@ def filter_values_on_diff(parm_key, value, auto_diff): "external": None, "release_build_files": None, # These two handled by file_redirects above. - "ios_pod": None, + "ios_spm": None, "Android": None, # Uncomment the two below lines when debugging this script, or GitHub # actions related to auto-diff mode. diff --git a/scripts/update_android_ios_dependencies.py b/scripts/update_android_ios_dependencies.py index 99d0083977..191c6688a1 100644 --- a/scripts/update_android_ios_dependencies.py +++ b/scripts/update_android_ios_dependencies.py @@ -20,8 +20,7 @@ across the C++ repository. There are 3 types of files being updated by this script, -- Podfile : Files containing lists of cocoapods along with their versions. - Eg: `ios_pods/Podfile` and any integration tests podfiles. +- Package.swift : Files containing Swift packages along with their versions. - Android dependencies gradle file: Gradle files containing list of Android libraries and their versions that is @@ -162,214 +161,148 @@ def get_files(dirs_and_files, file_extension, file_name=None, # Regex to match versions with just digits (ignoring things like -alpha, -beta) RE_NON_EXPERIMENTAL_VERSION = re.compile('[0-9.]+$') -########## iOS pods versions update ####################################### - -# Cocoapods github repo from where we scan available pods and their versions. -PODSPEC_REPOSITORY = 'https://github.com/CocoaPods/Specs.git' - -# List of Pods that we are interested in. -PODS = [ - 'Firebase', - 'FirebaseCore', - 'FirebaseAnalytics', - 'FirebaseAuth', - 'FirebaseCrashlytics', - 'FirebaseDatabase', - 'FirebaseFirestore', - 'FirebaseFunctions', - 'FirebaseInstallations', - 'FirebaseInstanceID', - 'FirebaseMessaging', - 'FirebaseRemoteConfig', - 'FirebaseStorage', - 'GoogleUserMessagingPlatform', -] - -def get_pod_versions(specs_repo, pods=PODS, ignore_pods=None, - allow_experimental=False): - """Get available pods and their versions from the specs repo +########## iOS Swift packages versions update ############################## + +IOS_PACKAGE_REPOSITORIES = { + 'firebase-ios-sdk': 'https://github.com/firebase/firebase-ios-sdk.git', + 'swift-package-manager-google-user-messaging-platform': 'https://github.com/googleads/swift-package-manager-google-user-messaging-platform.git', +} + +def get_git_tag_versions(repo_url, allow_experimental=False): + """Get available semantic versions from git tags for a repository. Args: - local_repo_dir (str): Directory mirroring Cocoapods specs repo - pods (iterable(str), optional): List of pods whose versions we need. - Defaults to PODS. - ignore_pods (list[str], optional): Case insensitive list of substrings - If any of these substrings are present in the pod name, it will not be - updated. - Eg: ['foo', 'bar'] will ignore all pods that have 'foo' or - 'bar' in their name. For example, 'test_foo', 'test_foo_baz' + repo_url (str): Remote git repository URL. allow_experimental (bool): Allow experimental versions. - Eg: 1.2.3-alpha, 1.2.3-beta, 1.2.3-rc + Returns: - dict: Map of the form {:list(str)} - Containing a mapping of podnames to available versions. + list(str): List of versions sorted semantically. """ - if ignore_pods is None: - ignore_pods = [] - - all_versions = defaultdict(list) - logging.info('Fetching pod versions from Specs repo...') - podspec_files = get_files_from_directory(specs_repo, - file_extension='.podspec.json') - for podspec_file in podspec_files: - filename = os.path.basename(podspec_file) - # Example: FirebaseAuth.podspec.json --> FirebaseAuth - podname = filename.split('.')[0] - if podname not in pods: - continue - if any(ignore_pod.lower() in podname.lower() for ignore_pod in ignore_pods): + cmd = ['git', 'ls-remote', '--tags', '--refs', repo_url] + logging.info('Fetching tags from %s...', repo_url) + out = subprocess.check_output(cmd).decode('utf-8') + versions = [] + for line in out.strip().split('\n'): + if not line: continue - parent_dir = os.path.dirname(podspec_file) - version = os.path.basename(parent_dir) - if not allow_experimental and '-cppsdk' not in version: - if not re.match(RE_NON_EXPERIMENTAL_VERSION, version): + tag = line.split('refs/tags/')[-1] + tag_clean = tag.lstrip('v') + if not allow_experimental and '-cppsdk' not in tag_clean: + if not re.match(RE_NON_EXPERIMENTAL_VERSION, tag_clean): continue - all_versions[podname].append(version) - - return all_versions + try: + parsed = packaging.version.parse(tag_clean) + versions.append((parsed, tag_clean)) + except Exception: + continue + versions.sort(key=lambda x: x[0]) + return [v[1] for v in versions] -def get_latest_pod_versions(specs_repo=None, pods=PODS, ignore_pods=None, - allow_experimental=None): - """Get latest versions for specified pods. +def get_latest_ios_package_versions(ignore_packages=None, allow_experimental=False): + """Get latest versions for iOS Swift packages. Args: - pods (iterable(str) optional): Pods for which we need latest version. - Defaults to PODS. - specs_repo (str optional): Local checkout of Cocoapods specs repo. - ignore_pods (list[str], optional): Case insensitive list of substrings - If any of these substrings are present in the pod name, it will not be - updated. - Eg: ['Foo', 'bar'] will ignore all pods that have 'foo' or - 'bar' in their name. For example, 'test_foo', 'test_foo_baz' + ignore_packages (list[str], optional): Case insensitive list of substrings to ignore. allow_experimental (bool): Allow experimental versions. - Eg: 1.2.3-alpha, 1.2.3-beta, 1.2.3-rc Returns: - dict: Map of the form {:} containing a mapping of podnames to - latest version. + dict: Mapping of package name / alias to latest version string. """ - if ignore_pods is None: - ignore_pods = [] - - cleanup_required = False - if specs_repo is None: - specs_repo = tempfile.mkdtemp(suffix='pods') - logging.info('Cloning podspecs git repo...') - git_clone_cmd = ['git', 'clone', '-q', '--depth', '1', - PODSPEC_REPOSITORY, specs_repo] - subprocess.run(git_clone_cmd) - # Temporary directory should be cleaned up after use. - cleanup_required = True - - all_versions = get_pod_versions(specs_repo, pods, ignore_pods, - allow_experimental) - if cleanup_required: - shutil.rmtree(specs_repo) + if ignore_packages is None: + ignore_packages = [] latest_versions = {} - for pod in all_versions: - # all_versions map is in the following format: - # { 'PodnameA' : ['1.0.1', '2.0.4'], 'PodnameB': ['3.0.4', '1.0.2'] } - # Convert string version numbers to semantic version objects - # for easier comparison and get the latest version. - parsed_versions = [] - for v in all_versions[pod]: - try: - parsed_versions.append(packaging.version.parse(v)) - except: - # Sometimes version numbers don't parse; ignore them. - continue - latest_version = max(parsed_versions) - # Replace the list of versions with just the latest version - latest_versions[pod] = latest_version.base_version - print("Latest pod versions retreived from cocoapods specs repo: \n") + for pkg_name, repo_url in IOS_PACKAGE_REPOSITORIES.items(): + if any(ignore_pkg.lower() in pkg_name.lower() for ignore_pkg in ignore_packages): + continue + versions = get_git_tag_versions(repo_url, allow_experimental) + if versions: + latest_version = versions[-1] + latest_versions[pkg_name] = latest_version + # Also add aliases for readme/podfile backward compatibility + if pkg_name == 'firebase-ios-sdk': + latest_versions['Firebase'] = latest_version + latest_versions['FirebaseCore'] = latest_version + latest_versions['FirebaseAnalytics'] = latest_version + latest_versions['FirebaseAuth'] = latest_version + latest_versions['FirebaseDatabase'] = latest_version + latest_versions['FirebaseFirestore'] = latest_version + latest_versions['FirebaseFunctions'] = latest_version + latest_versions['FirebaseInstallations'] = latest_version + latest_versions['FirebaseMessaging'] = latest_version + latest_versions['FirebaseRemoteConfig'] = latest_version + latest_versions['FirebaseStorage'] = latest_version + elif pkg_name == 'swift-package-manager-google-user-messaging-platform': + latest_versions['GoogleUserMessagingPlatform'] = latest_version + latest_versions['UserMessagingPlatform'] = latest_version + + print("Latest iOS Swift package versions retrieved: \n") pprint.pprint(latest_versions) print() return latest_versions -def get_pod_files(dirs_and_files): - """Get final list of podfiles to update. - - If a directory is passed, it is searched recursively. - - Args: - dirs_and_files (iterable(str)): List of paths which could be files or - directories. - - Returns: - iterable(str): Final list of podfiles after recursively searching dirs. - """ - pod_files = [] +def get_package_swift_files(dirs_and_files): + """Get final list of Package.swift files to update.""" + package_files = [] for entry in dirs_and_files: abspath = os.path.abspath(entry) if not os.path.exists(abspath): continue if os.path.isdir(abspath): - pod_files = pod_files + get_files_from_directory(abspath, - file_extension='', - file_name='Podfile') + package_files = package_files + get_files_from_directory( + abspath, file_extension='', file_name='Package.swift' + ) elif os.path.isfile(abspath): - pod_files.append(abspath) + package_files.append(abspath) + return package_files - return pod_files -# Look for lines like, pod 'Firebase/Core', '7.11.0' -RE_PODFILE_VERSION = re.compile( - r"\s+pod '(?P.+)', '(?P.+)'\n") - -def modify_pod_file(pod_file, pod_version_map, dryrun=True, ignore_ios_versions=[]): - """Update pod versions in specified podfile. +# Regex to match lines like: +# .package(url: "https://github.com/firebase/firebase-ios-sdk.git", exact: "12.18.0"), +RE_PACKAGE_SWIFT_DEPENDENCY = re.compile( + r'(?P\.package\(url:\s*\"https://github\.com/[^/]+/(?P[a-zA-Z0-9._-]+)\.git\",\s*exact:\s*\")(?P[0-9.]+)(?P\"\))' +) - Args: - pod_file (str): Absolute path to a podfile. - pod_version_map (dict): Map of podnames to their respective version. - dryrun (bool, optional): Just print the substitutions. - Do not write to file. Defaults to True. - ignore_ios_versions (set): If the old version number for a pod - matches one of these, don't update it. - """ +def modify_package_swift_file(package_swift_file, version_map, dryrun=True, + ignore_ios_versions=[]): + """Update Swift package versions in specified Package.swift file.""" global logfile_lines to_update = False existing_lines = [] - with open(pod_file, "r") as podfile: - existing_lines = podfile.readlines() + with open(package_swift_file, "r") as f: + existing_lines = f.readlines() if not existing_lines: - logging.fatal('Update failed. ' + - 'Could not read contents from pod file {0}.'.format(podfile)) + logging.fatal('Update failed. Could not read contents from file {0}.'.format(package_swift_file)) - logging.debug('Checking if update is required for {0}'.format(pod_file)) + logging.debug('Checking if update is required for {0}'.format(package_swift_file)) substituted_pairs = [] for idx, line in enumerate(existing_lines): - match = re.match(RE_PODFILE_VERSION, line) + match = re.search(RE_PACKAGE_SWIFT_DEPENDENCY, line) if match: - pod_name = match['pod_name'] - skip_line = False - # Check if the old version matches anything in ignore_ios_versions - for ignore_version in ignore_ios_versions: - if ignore_version in match['version']: - skip_line = True - # Firebase/Auth -> Firestore (due to being a subspec) - pod_name_key = re.sub(r'/.*$', '', pod_name) - if pod_name_key in pod_version_map and not skip_line: - latest_version = pod_version_map[pod_name_key] - substituted_line = line.replace(match['version'], latest_version) - if substituted_line != line: + pkg_name = match.group('pkg_name') + old_version = match.group('version') + if any(ignore_ver in old_version for ignore_ver in ignore_ios_versions): + continue + if pkg_name in version_map: + latest_version = version_map[pkg_name] + if latest_version != old_version: + substituted_line = line[:match.start('version')] + latest_version + line[match.end('version'):] substituted_pairs.append((line, substituted_line)) existing_lines[idx] = substituted_line to_update = True - logfile_lines.add('iOS: %s → %s' % (pod_name, latest_version)) + logfile_lines.add('iOS: %s → %s' % (pkg_name, latest_version)) if to_update: - print('Updating contents of {0}'.format(pod_file)) + print('Updating contents of {0}'.format(package_swift_file)) for original, substituted in substituted_pairs: print('(-) ' + original + '(+) ' + substituted) if not dryrun: - with open(pod_file, "w") as podfile: - podfile.writelines(existing_lines) + with open(package_swift_file, "w") as f: + f.writelines(existing_lines) print() @@ -456,23 +389,14 @@ def replace_spm_block(match): # Regex to match lines like: # | | Firebase/Auth Cocoapod (8.2.0) -RE_README_POD_VERSION = re.compile( - r"\|(?P\s+)\| (?P.*) Cocoapod \((?P([0-9.]+))\)") - -def modify_readme_file_pods(readme_filepath, version_map, dryrun=True): - """Modify a readme Markdown file to reference correct cocoapods versions. - - Looks for lines like: - | | Firebase/Auth Cocoapod (8.2.0) - for pods matching the ones in the version map, and modifies them in-place. +# or +# | | Firebase/Auth (8.2.0) +RE_README_IOS_VERSION = re.compile( + r"\|(?P\s+)\| (?P.*?) (?:Cocoapod )?\((?P([0-9.]+))\)" +) - Args: - readme_filepath: Path to readme file to edit. - version_map: Dictionary of packages to version numbers, e.g. { - 'FirebaseAuth': '15.0.0', 'FirebaseDatabase': '14.0.0' } - dryrun (bool, optional): Just print the substitutions. - Do not write to file. Defaults to True. - """ +def modify_readme_file_ios(readme_filepath, version_map, dryrun=True): + """Modify a readme Markdown file to reference correct iOS dependency versions.""" logging.debug('Reading readme file: {0}'.format(readme_filepath)) lines = None @@ -487,19 +411,22 @@ def modify_readme_file_pods(readme_filepath, version_map, dryrun=True): def replace_pod_line(m): if not m.group('pod_name'): return m.group(0) - pod_key = re.sub(r'/.*$', '', m.group('pod_name')) + pod_name = m.group('pod_name').strip() + pod_key = re.sub(r'/.*$', '', pod_name) if pod_key not in version_map: - return m.group(0) - repl = '|%s| %s Cocoapod (%s)' % (m.group('spaces'), - m.group('pod_name'), - version_map[pod_key]) + if pod_name in version_map: + pod_key = pod_name + else: + return m.group(0) + repl = '|%s| %s (%s)' % (m.group('spaces'), + m.group('pod_name'), + version_map[pod_key]) return repl substituted_pairs = [] to_update = False for line in lines: - substituted_line = re.sub(RE_README_POD_VERSION, replace_pod_line, - line) + substituted_line = re.sub(RE_README_IOS_VERSION, replace_pod_line, line) output_lines.append(substituted_line) if substituted_line != line: substituted_pairs.append((line, substituted_line)) @@ -515,7 +442,7 @@ def replace_pod_line(m): readme_file.writelines(output_lines) print() -########## END: iOS pods versions update ##################################### +########## END: iOS Swift packages versions update ########################### ########## Android versions update ############################# @@ -764,8 +691,8 @@ def replace_module_line(m): def parse_cmdline_args(): - parser = argparse.ArgumentParser(description='Update pod files with ' - 'latest pod versions') + parser = argparse.ArgumentParser(description='Update dependencies with ' + 'latest package versions') parser.add_argument('--dryrun', action='store_true', help='Just print the replaced lines, DO NOT overwrite any files') parser.add_argument( "--log_level", default="info", @@ -779,19 +706,18 @@ def parse_cmdline_args(): help='Allow updating to experimental versions (eg:1.2.3-alpha))') # iOS options parser.add_argument('--skip_ios', action='store_true', - help='Skip iOS pod version update completely.') - parser.add_argument('--ignore_ios_pods', nargs='+', default=(), - help='Ignore iOS pods which have any of the items specified in ' + help='Skip iOS package version update completely.') + parser.add_argument('--ignore_ios_packages', '--ignore_ios_pods', nargs='+', default=(), + help='Ignore iOS packages which have any of the items specified in ' 'this list as substrings.') parser.add_argument('--ignore_ios_versions', nargs='+', default=('cppsdk',), - help='Do not update any iOS pods when the old version contains ' + help='Do not update any iOS packages when the old version contains ' 'any of the items specified in this list as substrings.') - parser.add_argument('--podfiles', nargs='+', default=(os.getcwd(),), - help= 'List of pod files or directories containing podfiles') + parser.add_argument('--package_swift_files', nargs='+', + default=('ios_spm/Package.swift',), + help='List of Package.swift files or directories containing them') parser.add_argument('--projectfiles', nargs='+', default=(os.getcwd(),), help= 'List of Xcode project files or directories containing project.pbxproj files') - parser.add_argument('--specs_repo', - help= 'Local checkout of github Cocoapods Specs repository') # Android options parser.add_argument('--skip_android', action='store_true', help='Skip Android libraries version update completely.') @@ -842,23 +768,21 @@ def main(): file_name='readme') if not args.skip_ios: - latest_pod_versions_map = get_latest_pod_versions( - args.specs_repo, - PODS, - set(args.ignore_ios_pods), args.allow_experimental) - pod_files = get_files(args.podfiles, file_extension='', file_name='Podfile', - ignore_directories=set(args.ignore_directories)) - for pod_file in pod_files: - modify_pod_file(pod_file, latest_pod_versions_map, args.dryrun, - args.ignore_ios_versions) + latest_ios_versions_map = get_latest_ios_package_versions( + set(args.ignore_ios_packages), args.allow_experimental) + package_swift_files = get_files(args.package_swift_files, file_extension='.swift', file_name='Package.swift', + ignore_directories=set(args.ignore_directories)) + for package_swift_file in package_swift_files: + modify_package_swift_file(package_swift_file, latest_ios_versions_map, args.dryrun, + args.ignore_ios_versions) project_files = get_files(args.projectfiles, file_extension='.pbxproj', file_name='project.pbxproj', ignore_directories=set(args.ignore_directories)) for project_file in project_files: - modify_project_file_spm(project_file, latest_pod_versions_map, args.dryrun, + modify_project_file_spm(project_file, latest_ios_versions_map, args.dryrun, args.ignore_ios_versions) for readme_file in readme_files: - modify_readme_file_pods(readme_file, latest_pod_versions_map, args.dryrun) + modify_readme_file_ios(readme_file, latest_ios_versions_map, args.dryrun) if not args.skip_android: latest_android_versions_map = get_latest_maven_versions( diff --git a/storage/CMakeLists.txt b/storage/CMakeLists.txt index 2496c10b70..147bfdc18e 100644 --- a/storage/CMakeLists.txt +++ b/storage/CMakeLists.txt @@ -103,7 +103,7 @@ target_include_directories(firebase_storage ${CMAKE_CURRENT_LIST_DIR}/src/include PRIVATE ${FIREBASE_CPP_SDK_ROOT_DIR} - ${FIREBASE_CPP_SDK_ROOT_DIR}/ios_pod/swift_headers + ${FIREBASE_SPM_SWIFT_HEADERS_DIR} ) target_compile_definitions(firebase_storage PRIVATE @@ -120,9 +120,9 @@ elseif(IOS) target_link_libraries(firebase_storage PUBLIC "-fembed-bitcode") - setup_pod_headers( + setup_spm_headers( firebase_storage - POD_NAMES + MODULES FirebaseCore FirebaseStorage ) diff --git a/ump/CMakeLists.txt b/ump/CMakeLists.txt index 32d0eb70d3..9442b1e069 100644 --- a/ump/CMakeLists.txt +++ b/ump/CMakeLists.txt @@ -87,15 +87,14 @@ elseif(IOS) target_link_libraries(firebase_ump PUBLIC "-fembed-bitcode") - setup_pod_headers( + setup_spm_headers( firebase_ump - POD_NAMES + MODULES + UserMessagingPlatform GoogleUserMessagingPlatform ) - # UMP expects the header files to be in a subfolder, so set up a symlink to - # accomplish that. - symlink_pod_headers(firebase_ump GoogleUserMessagingPlatform UserMessagingPlatform) + symlink_spm_headers(firebase_ump UserMessagingPlatform DIR_NAME UserMessagingPlatform) if (FIREBASE_XCODE_TARGET_FORMAT STREQUAL "frameworks") set_target_properties(firebase_ump PROPERTIES