Skip to content

Commit 1e2dd0e

Browse files
authored
Merge pull request #207 from firebase/feature/js-switch-to-boringssl
Allow all dependencies (curl, websockets, grpc) to use boringssl instead of openssl when making packaged C++ SDK. This PR gives you the option to switch all desktop platforms over to using boringssl rather than openssl, which does not like being embedded in our SDKs. If you are building a binary SDK, you may want to enable this option. If you are linking directly to our SDK from source via cmake, you probably don't need it (but you should ensure that OpenSSL is installed on your system. It will be enabled if you turn on FIREBASE_USE_BORINGSSL at cmake configure time, e.g.: cmake [source directory] -DFIREBASE_USE_BORINGSSL=ON With this option enabled, it will build boringssl during the configure step by shelling out to another instance of cmake. Much work is done in build_external_dependencies to ensure that this (and future) sub-builds correctly match the main project's selection of: - CPU architecture - build type (debug/release) - Windows MSVC runtime - Linux legacy/c++11 ABI A few notes on switching to boringSSL: - We manually set all of the OPENSSL_* flags that CMake's find_package(OpenSSL) sets, so that any subprojects using openssl will get the include files and libraries of boringssl instead. - We have updated to the latest libcurl which supports boringssl properly. - OpenSSL has been removed from the vcpkg files. - Golang has been added as a prerequisite as it's required for boringssl's build. Github runners already have it installed, but I've added it to the prereqs script anyway. Additional changes in this PR: - The Linux build has been switched to use the legacy ABI rather than the C++11 ABI. An upcoming PR will enable both ABIs. - Binutils on Mac is restored to the latest version, as openssl was the cause of the library corruption we were seeing. - Some missing Firestore core headers are now added to the final C++ SDK package. - Integration test github action now builds and runs both openssl and boringssl versions. You'll also see a few workaround at the end of the download_external_sources function, this is to work around a few issues in subprojects that expect openssl but are now getting boringssl. There are PRs to fix these in the upstream sources, but until we update to their latest version these will need to be there.
2 parents 0aae949 + b8a1b2b commit 1e2dd0e

24 files changed

+397
-47
lines changed

.github/workflows/cpp-packaging.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,8 @@ jobs:
6969
binutils_version: "2.35.1"
7070
- os: macos-latest
7171
tools_platform: darwin
72-
# On Mac, use an older Binutils to avoid corrupted libraries.
73-
binutils_version: "2.28.1"
72+
# Binutils 2.35.1 released Sep 19, 2020
73+
binutils_version: "2.35.1"
7474
steps:
7575
- name: setup Xcode version (macos)
7676
if: runner.os == 'macOS'

.github/workflows/desktop.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ jobs:
8888
python scripts/gha/install_prereqs_desktop.py
8989
9090
- name: Build SDK
91+
shell: bash
9192
run: |
9293
python scripts/gha/build_desktop.py --build_tests --arch "${{ matrix.architecture }}" --config "${{ matrix.build_type }}" --msvc_runtime_library "${{ matrix.msvc_runtime }}"
9394

.github/workflows/integration_tests.yml

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ on:
1515
description: 'CSV of VMs to run on'
1616
default: 'ubuntu-latest,windows-latest,macos-latest'
1717
required: true
18+
desktop_ssl_variants:
19+
description: 'CSV of desktop SSL variants to use'
20+
default: 'openssl,boringssl'
21+
required: true
1822
android_device:
1923
description: 'Android device model'
2024
default: 'flame'
@@ -36,6 +40,7 @@ jobs:
3640
outputs:
3741
matrix_os: ${{ steps.set-matrix-os.outputs.matrix_os }}
3842
matrix_platform: ${{ steps.set-matrix-os.outputs.matrix_platform }}
43+
matrix_ssl: ${{ steps.set-matrix-os.outputs.matrix_ssl }}
3944
steps:
4045
- id: set-matrix-os
4146
# e.g. 'ubuntu-latest,macos-latest' -> '["ubuntu-latest","macos-latest"]'
@@ -44,20 +49,27 @@ jobs:
4449
echo "::set-output name=matrix_os::${OS_JSON}"
4550
PLATFORM_JSON=[\"$(echo ${{ github.event.inputs.platforms }} | sed 's/,/","/g')\"]
4651
echo "::set-output name=matrix_platform::${PLATFORM_JSON}"
52+
SSL_JSON=[\"$(echo ${{ github.event.inputs.desktop_ssl_variants }} | sed 's/,/","/g')\"]
53+
echo "::set-output name=matrix_ssl::${SSL_JSON}"
4754
tests:
48-
name: ${{ matrix.os }}-${{ matrix.target_platform }}
55+
name: ${{ matrix.os }}-${{ matrix.target_platform }}-${{ matrix.ssl_variant }}
4956
needs: prepare_matrix
5057
runs-on: ${{ matrix.os }}
5158
strategy:
5259
fail-fast: false
5360
matrix:
5461
os: ${{ fromJson(needs.prepare_matrix.outputs.matrix_os) }}
5562
target_platform: ${{ fromJson(needs.prepare_matrix.outputs.matrix_platform) }}
63+
ssl_variant: ${{ fromJson(needs.prepare_matrix.outputs.matrix_ssl) }}
5664
exclude:
5765
- os: ubuntu-latest
5866
target_platform: iOS
5967
- os: windows-latest
6068
target_platform: iOS
69+
- target_platform: iOS
70+
ssl_variant: boringssl
71+
- target_platform: Android
72+
ssl_variant: boringssl
6173

6274
steps:
6375
- uses: actions/checkout@v2
@@ -117,8 +129,14 @@ jobs:
117129
python scripts/gha/restore_secrets.py --passphrase "${{ secrets.TEST_SECRET }}"
118130
119131
- name: Build integration tests
132+
shell: bash
120133
run: |
121-
python scripts/gha/build_testapps.py --t ${{ github.event.inputs.apis }} --p ${{ matrix.target_platform }} --output_directory ${{ github.workspace }} --use_vcpkg --noadd_timestamp
134+
# Default SSL is openssl.
135+
ssl_option=
136+
if [[ "${{ matrix.ssl_variant }}" == "boringssl" ]]; then
137+
ssl_option=--cmake_flag=-DFIREBASE_USE_BORINGSSL=ON
138+
fi
139+
python scripts/gha/build_testapps.py --t ${{ github.event.inputs.apis }} --p ${{ matrix.target_platform }} --output_directory ${{ github.workspace }} --use_vcpkg --noadd_timestamp ${ssl_option}
122140
123141
- name: Run desktop integration tests
124142
if: matrix.target_platform == 'Desktop' && !cancelled()

CMakeLists.txt

Lines changed: 101 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ option(FIREBASE_CPP_BUILD_PACKAGE
6666
"Bundle the Firebase C++ libraries into a zip file." OFF)
6767
option(FIREBASE_CPP_USE_PRIOR_GRADLE_BUILD
6868
"When building with Gradle, use the previously built libraries." OFF)
69+
option(FIREBASE_USE_BORINGSSL
70+
"Build against BoringSSL instead of using your system's OpenSSL." OFF)
6971

7072
set(FIREBASE_ANDROID_STL "" CACHE STRING "STL implementation to use.")
7173
if (NOT FIREBASE_ANDROID_STL STREQUAL "")
@@ -115,6 +117,13 @@ else()
115117
set(DESKTOP OFF)
116118
endif()
117119

120+
if(DESKTOP AND NOT MSVC AND NOT APPLE)
121+
# Linux-specific option.
122+
add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0)
123+
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_GLIBCXX_USE_CXX11_ABI=0")
124+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_GLIBCXX_USE_CXX11_ABI=0")
125+
endif()
126+
118127
# Set directories needed by the Firebase subprojects
119128
# Directory to store generated files.
120129
set(FIREBASE_GEN_FILE_DIR ${CMAKE_BINARY_DIR}/generated)
@@ -174,6 +183,87 @@ else()
174183
set(FIRESTORE_SOURCE_DIR ${FIREBASE_BINARY_DIR}/external/src/firestore)
175184
endif()
176185

186+
if(DESKTOP)
187+
# Use the static versions of the OpenSSL libraries.
188+
set(OPENSSL_USE_STATIC_LIBS TRUE)
189+
if (MSVC)
190+
# Get the correct version of the OpenSSL libraries based on building for MT.
191+
if ("${CMAKE_CXX_FLAGS_DEBUG}" MATCHES "/MTd" OR
192+
"${CMAKE_CXX_FLAGS_RELEASE}" MATCHES "/MT")
193+
set(OPENSSL_MSVC_STATIC_RT TRUE)
194+
else()
195+
set(OPENSSL_MSVC_STATIC_RT FALSE)
196+
endif()
197+
endif()
198+
199+
if(FIREBASE_USE_BORINGSSL)
200+
# Use BoringSSL instead of OpenSSL.
201+
set(BORINGSSL_ROOT_DIR ${PROJECT_BINARY_DIR}/external/src/boringssl/src CACHE STRING "" FORCE)
202+
set(BORINGSSL_BINARY_DIR ${PROJECT_BINARY_DIR}/external/src/boringssl-build CACHE STRING "" FORCE)
203+
set(OPENSSL_ROOT_DIR ${BORINGSSL_ROOT_DIR} CACHE STRING "" FORCE)
204+
205+
# The call below to build_external_dependencies will make sure that these
206+
# libraries exist before the libraries are imported via add_library.
207+
if (MSVC)
208+
if (CMAKE_BUILD_TYPE)
209+
set(BORINGSSL_LIB_SUBDIR "${CMAKE_BUILD_TYPE}")
210+
else()
211+
set(BORINGSSL_LIB_SUBDIR "Debug")
212+
endif()
213+
set(OPENSSL_SSL_LIBRARY ${BORINGSSL_BINARY_DIR}/ssl/${BORINGSSL_LIB_SUBDIR}/ssl.lib CACHE FILEPATH "" FORCE)
214+
set(OPENSSL_CRYPTO_LIBRARY ${BORINGSSL_BINARY_DIR}/crypto/${BORINGSSL_LIB_SUBDIR}/crypto.lib CACHE FILEPATH "" FORCE)
215+
else()
216+
set(OPENSSL_SSL_LIBRARY ${BORINGSSL_BINARY_DIR}/ssl/libssl.a CACHE FILEPATH "" FORCE)
217+
set(OPENSSL_CRYPTO_LIBRARY ${BORINGSSL_BINARY_DIR}/crypto/libcrypto.a CACHE FILEPATH "" FORCE)
218+
endif()
219+
endif()
220+
endif()
221+
222+
223+
if(DESKTOP)
224+
message(STATUS "Building external project dependencies...")
225+
build_external_dependencies()
226+
message(STATUS "Build of external project dependencies complete.")
227+
228+
if(FIREBASE_USE_BORINGSSL)
229+
set(OPENSSL_FOUND TRUE CACHE BOOL "" FORCE)
230+
set(OPENSSL_NO_ASM TRUE) # Force cross-platform BoringSSL, no ASM.
231+
set(OPENSSL_INCLUDE_DIR ${BORINGSSL_ROOT_DIR}/include CACHE PATH "" FORCE)
232+
set(OPENSSL_CRYPTO_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
233+
set(OPENSSL_SSL_LIBRARIES ${OPENSSL_SSL_LIBRARY})
234+
set(OPENSSL_LIBRARIES ${OPENSSL_SSL_LIBRARIES} ${OPENSSL_CRYPTO_LIBRARIES})
235+
set(OPENSSL_VERSION '1.1.0' CACHE STRING "" FORCE)
236+
237+
add_library(OpenSSL::SSL STATIC IMPORTED)
238+
add_library(OpenSSL::Crypto STATIC IMPORTED)
239+
set_target_properties(OpenSSL::SSL PROPERTIES
240+
IMPORTED_LOCATION "${OPENSSL_SSL_LIBRARY}"
241+
INTERFACE_INCLUDE_DIRECTORIES "${OPENSSL_INCLUDE_DIR}"
242+
INTERFACE_LINK_LIBRARIES OpenSSL::Crypto
243+
)
244+
245+
set_target_properties(OpenSSL::Crypto PROPERTIES
246+
IMPORTED_LOCATION "${OPENSSL_CRYPTO_LIBRARY}"
247+
INTERFACE_INCLUDE_DIRECTORIES "${OPENSSL_INCLUDE_DIR}"
248+
)
249+
# Now if we do find_package(OpenSSL) it should give us BoringSSL.
250+
find_package(OpenSSL)
251+
252+
if(NOT "${OPENSSL_INCLUDE_DIR}" MATCHES boringssl OR
253+
NOT "${OPENSSL_SSL_LIBRARY}" MATCHES boringssl OR
254+
NOT "${OPENSSL_CRYPTO_LIBRARY}" MATCHES boringssl)
255+
message(FATAL_ERROR "BoringSSL was not configured correctly.\nINCLUDE_DIR=${OPENSSL_INCLUDE_DIR}\nSSL_LIBRARY=${OPENSSL_SSL_LIBRARY}\nCRYPTO_LIBRARY=${OPENSSL_CRYPTO_LIBRARY}")
256+
endif()
257+
else()
258+
# Don't use BoringSSL, use OpenSSL. If you are linking against the libraries directly
259+
# from source, you probably want this instead.
260+
#
261+
# If the find_package fails to find OpenSSL, set OPENSSL_ROOT_DIR to OpenSSL'S install
262+
# location on your system.
263+
find_package(OpenSSL REQUIRED)
264+
endif()
265+
endif()
266+
177267
# Include Firestore's external build early to resolve conflicts on packages.
178268
if(FIRESTORE_USE_EXTERNAL_CMAKE_BUILD)
179269
set(FIRESTORE_BINARY_DIR ${FIRESTORE_SOURCE_DIR}-build)
@@ -223,37 +313,28 @@ endif()
223313

224314
# Some of the external libraries are not used for mobile.
225315
if(DESKTOP)
226-
# Use the static versions of the OpenSSL libraries.
227-
set(OPENSSL_USE_STATIC_LIBS TRUE)
228-
if (MSVC)
229-
# Get the correct version of the OpenSSL libraries based on building for MT.
230-
if ("${CMAKE_CXX_FLAGS_DEBUG}" MATCHES "/MT" OR
231-
"${CMAKE_CXX_FLAGS_RELEASE}" MATCHES "/MT")
232-
set(OPENSSL_MSVC_STATIC_RT TRUE)
233-
else()
234-
set(OPENSSL_MSVC_STATIC_RT FALSE)
235-
endif()
236-
endif()
237-
238316
# Build curl as a static library
239317
set(CURL_STATICLIB ON CACHE BOOL "")
240318
if (WIN32)
241-
set(CMAKE_USE_WINSSL ON CACHE BOOL "")
319+
# Enable Windows native SSL/TLS in libcurl.
320+
set(CMAKE_USE_SCHANNEL ON CACHE BOOL "")
242321
endif()
322+
323+
# Current Curl library defaults to requiring some dependencies we don't need, disable them.
324+
set(CMAKE_USE_LIBSSH2 OFF)
325+
set(HTTP_ONLY ON)
326+
set(BUILD_TESTING OFF)
243327
add_external_library(curl)
244328

245329
add_external_library(libuv)
246330

247-
find_package(OpenSSL)
248-
249331
add_external_library(zlib)
250332

251333
add_external_library(uWebSockets)
252334

253335
# Binutils on Mac doesn't support thread-local storage (required by
254-
# websockets), but because we only use websockets via the scheduler,
255-
# we don't need it.
256-
336+
# websockets), but because we only use websockets via the scheduler, we don't
337+
# need it. Deactivate this by blanking out the __thread keyword.
257338
set(websockets_additional_defines "-D__thread=")
258339

259340
# uWebSockets does not come with a CMakeLists file, so define the target.
@@ -304,7 +385,8 @@ if(DESKTOP)
304385
)
305386
target_link_libraries(libuWS
306387
PRIVATE
307-
${OPENSSL_LIBRARIES}
388+
OpenSSL::SSL
389+
OpenSSL::Crypto
308390
uv_a
309391
zlibstatic
310392
)

app/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,7 @@ target_compile_definitions(firebase_app
325325
PRIVATE
326326
-DINTERNAL_EXPERIMENTAL=1
327327
)
328+
328329
# firebase_app has a dependency on flatbuffers, which needs to be included.
329330
target_link_libraries(firebase_app
330331
PRIVATE

app/rest/CMakeLists.txt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,13 +68,19 @@ target_compile_definitions(firebase_rest_lib
6868
"${rest_additional_defines}"
6969
)
7070

71+
set(FIREBASE_CURL_DEPENDENCY libcurl)
72+
if (MSVC)
73+
# libcurl on Windows depends on internal Windows SSL via its crypt32 library.
74+
set(FIREBASE_CURL_DEPENDENCY ${FIREBASE_CURL_DEPENDENCY} crypt32)
75+
endif()
76+
7177
# firebase_rest_lib has a dependency on flatbuffers, which needs to be included.
7278
target_link_libraries(firebase_rest_lib
7379
PUBLIC
7480
firebase_app
7581
PRIVATE
7682
flatbuffers
77-
libcurl
83+
${FIREBASE_CURL_DEPENDENCY}
7884
zlibstatic
7985
${CMAKE_DL_LIBS}
8086
)

build_scripts/desktop/package.sh

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -149,26 +149,28 @@ fi
149149

150150
# Library dependencies to merge. Each should be a whitespace-delimited list of path globs.
151151
readonly deps_firebase_app="
152-
*/${prefix}firebase_instance_id*${suffix}.${ext}
153-
*/${prefix}firebase_rest_lib${suffix}.${ext}
152+
*/${prefix}firebase_instance_id*.${ext}
153+
*/${prefix}firebase_rest_lib.${ext}
154154
"
155155
readonly deps_hidden_firebase_app="
156-
*/${subdir}${prefix}curl${suffix}.${ext}
157-
*/${subdir}${prefix}flatbuffers${suffix}.${ext}
156+
*/curl-build/lib/${subdir}libcurl${suffix}.${ext}
157+
*/${subdir}${prefix}flatbuffers.${ext}
158158
*/zlib-build/${subdir}${prefix}z.${ext}
159159
*/zlib-build/${subdir}zlibstatic*.${ext}
160-
*/vcpkg-libs/libcrypto.${ext}
161-
*/vcpkg-libs/libssl.${ext}
160+
*/boringssl-build/crypto/${subdir}${prefix}crypto.${ext}
161+
*/boringssl-build/ssl/${subdir}${prefix}ssl.${ext}
162162
*/firestore-build/*/leveldb-build*/${prefix}*.${ext}
163163
*/firestore-build/*/nanopb-build*/${prefix}*.${ext}
164164
"
165165
readonly deps_hidden_firebase_database="
166-
*/${subdir}${prefix}uv_a${suffix}.${ext}
167-
*/${subdir}${prefix}libuWS${suffix}.${ext}
166+
*/${subdir}${prefix}uv_a.${ext}
167+
*/${subdir}${prefix}libuWS.${ext}
168168
"
169169
readonly deps_hidden_firebase_firestore="
170170
*/firestore-build/Firestore/*/${prefix}*.${ext}
171-
*/firestore-build/*/grpc-build*/${prefix}*.${ext}
171+
*/firestore-build/*/grpc-build/${subdir}${prefix}*.${ext}
172+
*/firestore-build/*/grpc-build/third_party/cares/*${subdir}${prefix}*.${ext}
173+
*/firestore-build/*/grpc-build/third_party/abseil-cpp/*${subdir}${prefix}*.${ext}
172174
"
173175

174176
# List of C++ namespaces to be renamed, so as to not conflict with the
@@ -281,13 +283,31 @@ for product in ${product_list[*]}; do
281283
deps_hidden+="${found}"
282284
done
283285
done
286+
if [[ "${product}" != "app" ]]; then
287+
# For any library other than app, also rename some symbols that were already renamed in app
288+
# that are used by other libraries (e.g. zlib is used in Firestore).
289+
for dep in ${deps_hidden_firebase_app}; do
290+
for found in $(find . -path ${dep}); do
291+
if [[ ! -z ${deps_hidden} ]]; then deps_hidden+=","; fi
292+
deps_hidden+="${found}"
293+
done
294+
done
295+
fi
284296
echo -n "${libfile_out}"
285297
if [[ ! -z ${deps_basenames[*]} ]]; then
286-
echo -n " <- ${deps_basenames[*]}"
298+
echo -n " <- ${deps[*]}"
287299
fi
288300
echo
289301
outfile="${full_output_path}/${libfile_out}"
290302
rm -f "${outfile}"
303+
if [[ ${verbose} -eq 1 ]]; then
304+
echo "${python_cmd}" "${merge_libraries_script}" \
305+
${merge_libraries_params[*]} \
306+
--output="${outfile}" \
307+
--scan_libs="${allfiles}" \
308+
--hide_c_symbols="${deps_hidden}" \
309+
${libfile_src} ${deps[*]}
310+
fi
291311
"${python_cmd}" "${merge_libraries_script}" \
292312
${merge_libraries_params[*]} \
293313
--output="${outfile}" \
@@ -296,3 +316,9 @@ for product in ${product_list[*]}; do
296316
${libfile_src} ${deps[*]}
297317
done
298318
cd "${run_path}"
319+
320+
# Copy Firestore core headers into the package's include directory.
321+
mkdir -p "${output_package_path}/include/firebase/firestore"
322+
cp -av \
323+
"${built_sdk_path}/external/src/firestore/Firestore/core/include/firebase/firestore/"* \
324+
"${output_package_path}/include/firebase/firestore"

cmake/external/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ include(firestore)
2828

2929
# Some of the external dependencies are not needed for mobile.
3030
if (${FIREBASE_EXTERNAL_PLATFORM} STREQUAL "DESKTOP")
31+
include(boringssl)
3132
include(curl)
3233
include(libuv)
3334
include(leveldb)

0 commit comments

Comments
 (0)