Skip to content

Commit 9f20338

Browse files
manginikendalharland
authored andcommitted
Force-disable BMI2 instruction set when building snappy.lib (#47)
Firebase-cpp-sdk on Windows pulls in firebase-ios-sdk (for firestore code), which pulls in leveldb (for key/value persistence) and Snappy (for efficient data compression). For faster compression, Snappy uses one specific CPU instruction for bit manipulation, bzhi, from the BMI2 instruction set. However, this instruction crashes firestore on a CPU that does not support the BMI2 instructions, which is the case of older CPUs, for example Intel pre-Haswell and AMD pre-Excavator CPUs. By default, Snappy detects if it should use the BMI2 optimized instruction by performing a compilation test on the cmake configure phase , which obviously returns if the build machine supports BMI2, not the target machines. Snappy build setup does not support a compiler directive that overrides that specific compilation test, so it can only build for the host machine BMI2 setup. Unfortunately, due to the very involved dependency chain, there is no good way to patch Snappy's code and the easiest solution in terms of maintenance is to patch the config.h created during the configure step, which is what this PR does. It only changes the automated build process (Github Actions workflow).
1 parent ca172bd commit 9f20338

File tree

1 file changed

+43
-0
lines changed

1 file changed

+43
-0
lines changed

.github/workflows/bcny-firebase.yml

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,25 @@ jobs:
119119
-D CMAKE_MSVC_DEBUG_INFORMATION_FORMAT=Embedded `
120120
-D FIREBASE_PYTHON_HOST_EXECUTABLE:FILEPATH=${{ steps.python.outputs.python-path }} `
121121
-D FLATBUFFERS_FLATC_EXECUTABLE=${{ github.workspace }}/BinaryCache/flatbuffers/Release/flatc.exe
122+
123+
# The step below is necessary since Snappy detects if it should use BMI2 instructions on x64 based only on its ability to
124+
# compile BMI2 code on the host machine, but we need to disable BMI2 instructions so that the resulting nuget package
125+
# can be used on target machines without BMI2 support. Unfortunately Snappy is pulled indirectly from
126+
# another dependency (firebase-ios-sdk) in a very involved dependency chain and there is no good way to
127+
# set SNAPPY_HAVE_BMI2 without patching its code since compiler directives have less precendence than
128+
# the result of the host machine's check_cxx_source_compiles (which ends up in the config.h file).
129+
# So, the less messy solution seems to be to patch the config.h file after the configure step, which is what we do below.
130+
- name: Change SNAPPY_HAVE_BMI2 in snappy config.h
131+
# BMI2 instructions are only relevant in amd64
132+
if: matrix.arch == 'amd64'
133+
run: |
134+
$snappy_config = "${{ github.workspace }}\BinaryCache\firebase\external\src\firestore-build\external\src\snappy-build\config.h"
135+
if (-not (Select-String -Path $snappy_config -Pattern "#define SNAPPY_HAVE_BMI2 1")) {
136+
Write-Error "String '#define SNAPPY_HAVE_BMI2 1' expected but not found in $snappy_config"
137+
exit 1
138+
}
139+
(Get-Content $snappy_config) -replace '#define SNAPPY_HAVE_BMI2 1', '#define SNAPPY_HAVE_BMI2 0' | Set-Content $snappy_config
140+
122141
- name: Build firebase
123142
run: cmake --build ${{ github.workspace }}/BinaryCache/firebase --config RelWithDebInfo
124143
- name: Install firebase
@@ -137,6 +156,30 @@ jobs:
137156
Copy-Item -Path $library.FullName -Destination $destination -Force
138157
Write-Host "... copied ${destination}"
139158
}
159+
160+
# We need this library to be used on CPUs without BMI2 support, so we check that snappy.lib was built correctly,
161+
# and fail if it contains BMI2 instructions.
162+
#
163+
# Note: We explicitly check for bzhi because that is the BMI2 instruction used in snappy source code if BMI2 is enabled:
164+
# https://github.com/google/snappy/blob/2c94e11145f0b7b184b831577c93e5a41c4c0346/snappy.cc#L1197
165+
# It may be possible that the compiler decides to add other BMI2 instructions automatically, but by checking
166+
# for the absense of 'bzhi' we are at least ensuring that the explicit SNAPPY_HAVE_BMI2 change in config.h is
167+
# being respected.
168+
- name: Check for Snappy BMI2 instructions
169+
# BMI2 instructions are only relevant in amd64
170+
if: matrix.arch == 'amd64'
171+
run: |
172+
Write-Host "Checking for BMI2 instructions on Snappy.lib..."
173+
$snappy_lib = "${{ github.workspace }}/BuildRoot/Library/firebase/usr/libs/windows/snappy.lib"
174+
$output = dumpbin /DISASM "$snappy_lib" | Select-String -Pattern "bzhi"
175+
if ($output) {
176+
Write-Host $output
177+
Write-Error "ERROR: A BMI2 instruction ('bzhi') was not supposed to be found in $snappy_lib."
178+
exit 1
179+
} else {
180+
Write-Output "Success! No BMI2 instructions were found in snappy.lib."
181+
}
182+
140183
- uses: actions/upload-artifact@v3
141184
with:
142185
name: firebase-windows-${{ matrix.arch }}

0 commit comments

Comments
 (0)