Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Crosscompile python aarch64 wheels with dockcross #25418

Merged
merged 6 commits into from Mar 2, 2021

Conversation

jtattermusch
Copy link
Contributor

@jtattermusch jtattermusch commented Feb 11, 2021

Enables building of aarch64 wheels via crosscompilation.
Uses similar tricks (overriding plat-name and EXT_SUFFIX) as protocolbuffers/protobuf#8280.

Some limitations:

  • currently twine check and auditwheel repair is being skipped
  • still need to doublecheck whether the wheels work well

The nice thing is that crosscompilation isn't slower than the regular build (unlike building under emulation).

FTR a very similar technique could be used to crosscompile the armv7 and armv6 (currently under "linux_extra" and being built under an emulator which takes ages).

@jtattermusch jtattermusch changed the title DO NOT MERGE: Crosscompile python aarch64 wheels Crosscompile python aarch64 wheels with dockcross Feb 12, 2021
@jtattermusch
Copy link
Contributor Author

@lidizheng @gnossen this is not ready for merge yet, but good enough for first review pass.

@jtattermusch jtattermusch marked this pull request as ready for review February 12, 2021 14:00
@jtattermusch
Copy link
Contributor Author

@janaknat please review as well.

@jtattermusch jtattermusch added this to the ARM64 support milestone Feb 12, 2021
"${PYTHON}" -m pip install virtualenv
"${PYTHON}" -m virtualenv venv || { "${PYTHON}" -m pip install virtualenv==16.7.9 && "${PYTHON}" -m virtualenv venv; }
venv/bin/python -m pip install "twine<=2.0"
venv/bin/python -m twine check dist/* tools/distrib/python/grpcio_tools/dist/*
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason for skipping twine checks? We are following manylinux2014, should be supported by PyPI official packages?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to skip auditwheel and twine check for now, since when crosscompiling we're running on x64 image, but we got aarch64 wheel. To perform checks, you'd likely need to run the check under qemu (available in the docker image), but also on aarch64 version of python etc.
The plan is to first test the aarch64 wheels manually. It should be possible to add back twine and auditwheel checks, but more work is needed.

src/python/grpcio/commands.py Outdated Show resolved Hide resolved
@jtattermusch
Copy link
Contributor Author

Artifact build results (for aarch64)

built wheels can be downloaded here:
https://console.cloud.google.com/storage/browser/grpc-testing-kokoro-prod/test_result_public/prod/grpc/core/pull_request/linux/grpc_build_artifacts/22486/20210212-055319

@jtattermusch
Copy link
Contributor Author

Manual run of auditwheel show on arm64 machine:

python -m auditwheel show grpcio-1.37.0.dev0-cp38-cp38-manylinux2014_aarch64.whl

grpcio-1.37.0.dev0-cp38-cp38-manylinux2014_aarch64.whl is consistent
with the following platform tag: "manylinux_2_24_aarch64".

The wheel references external versioned symbols in these system-
provided shared libraries: libpthread.so.0 with versions
{'GLIBC_2.17'}, libm.so.6 with versions {'GLIBC_2.17'}, libc.so.6 with
versions {'GLIBC_2.17'}, libstdc++.so.6 with versions
{'GLIBCXX_3.4.17', 'GLIBCXX_3.4.15', 'GLIBCXX_3.4.14',
'GLIBCXX_3.4.18', 'CXXABI_1.3.5', 'GLIBCXX_3.4.11', 'GLIBCXX_3.4.9',
'GLIBCXX_3.4.20', 'CXXABI_1.3', 'GLIBCXX_3.4'}

This constrains the platform tag to "manylinux_2_24_aarch64". In order
to achieve a more compatible tag, you would need to recompile a new
wheel from source on a system with earlier versions of these
libraries, such as a recent manylinux image.

So looks like some work is still needed. Not sure if the problem could be the too-new version of gcc being used (we do use 4.9.4 instead of the default 4.8 because gRPC doesn't compile under gcc 4.8 - see the dockerfile)

@jtattermusch
Copy link
Contributor Author

Manual run of auditwheel show on arm64 machine:

python -m auditwheel show grpcio-1.37.0.dev0-cp38-cp38-manylinux2014_aarch64.whl

grpcio-1.37.0.dev0-cp38-cp38-manylinux2014_aarch64.whl is consistent
with the following platform tag: "manylinux_2_24_aarch64".

The wheel references external versioned symbols in these system-
provided shared libraries: libpthread.so.0 with versions
{'GLIBC_2.17'}, libm.so.6 with versions {'GLIBC_2.17'}, libc.so.6 with
versions {'GLIBC_2.17'}, libstdc++.so.6 with versions
{'GLIBCXX_3.4.17', 'GLIBCXX_3.4.15', 'GLIBCXX_3.4.14',
'GLIBCXX_3.4.18', 'CXXABI_1.3.5', 'GLIBCXX_3.4.11', 'GLIBCXX_3.4.9',
'GLIBCXX_3.4.20', 'CXXABI_1.3', 'GLIBCXX_3.4'}

This constrains the platform tag to "manylinux_2_24_aarch64". In order
to achieve a more compatible tag, you would need to recompile a new
wheel from source on a system with earlier versions of these
libraries, such as a recent manylinux image.

So looks like some work is still needed. Not sure if the problem could be the too-new version of gcc being used (we do use 4.9.4 instead of the default 4.8 because gRPC doesn't compile under gcc 4.8 - see the dockerfile)

An attempt to auditwheel repair:

python -m auditwheel repair grpcio-1.37.0.dev0-cp38-cp38-manylinux2014_aarch64.whl || echo FAILED
INFO:auditwheel.main_repair:Repairing grpcio-1.37.0.dev0-cp38-cp38-manylinux2014_aarch64.whl
usage: __main__.py [-h] [-V] [-v] command ...
__main__.py: error: cannot repair "grpcio-1.37.0.dev0-cp38-cp38-manylinux2014_aarch64.whl" to "manylinux2014_aarch64" ABI because of the presence of too-recent versioned symbols. You'll need to compile the wheel on an older toolchain.

@jtattermusch jtattermusch added release notes: yes Indicates if PR needs to be in release notes lang/Python labels Feb 13, 2021
@jtattermusch
Copy link
Contributor Author

Artifact build results (for aarch64)

built wheels can be downloaded here:
https://console.cloud.google.com/storage/browser/grpc-testing-kokoro-prod/test_result_public/prod/grpc/core/pull_request/linux/grpc_build_artifacts/22486/20210212-055319

The python3.7 failure seems to be caused by a typo that's now fixed.

FROM dockcross/manylinux2014-aarch64:20200929-608e6ac

# Update the package manager
RUN yum update -y && yum install -y curl-devel expat-devel gettext-devel openssl-devel zlib-devel

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these installing the aarch64 dev libs? When I tried it, it pulled in the x86 version.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nope, this is installing x86 libs. I guess the reason why this doesn't matter is that they are actually not strictly required for a successful build (I copied the line from x64 dockerfile and didn't investigate whether they are really needed).

RUN /opt/python/cp36-cp36m/bin/pip install --upgrade cython
RUN /opt/python/cp37-cp37m/bin/pip install --upgrade cython
RUN /opt/python/cp38-cp38/bin/pip install --upgrade cython
RUN /opt/python/cp39-cp39/bin/pip install --upgrade cython

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same question as above.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's a x64 cython, but that doesn't really matter it seems. Even the python itself is a x64 python. That seems correct as we're crosscompiling and we need to run the build on a x64 machine (and cython is what invokes the build commands).

@@ -57,6 +58,7 @@ ${SETARCH_CMD} "${PYTHON}" setup.py sdist

# Wheel has a bug where directories don't get excluded.
# https://bitbucket.org/pypa/wheel/issues/99/cannot-exclude-directory
# shellcheck disable=SC2086
${SETARCH_CMD} "${PYTHON}" setup.py bdist_wheel $WHEEL_PLAT_NAME_FLAG
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Double quote (SC2086) seems applicable to this shell command. Quoting variables should fix the shellcheck complain.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That wouldn't work. WHEEL_PLAT_NAME_FLAG can be empty and in that case "$WHEEL_PLAT_NAME_FLAG" becomes "" and an empty arg will be forcibly passed to the command (which does break it).


# Set to empty string to disable the option (see https://github.com/grpc/grpc/issues/24498)
# TODO: enable ASM optimizations for crosscompiled wheels
export GRPC_BUILD_WITH_BORING_SSL_ASM=""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe link to the PR changing the BoringSSL ASM enable flag? #25444

@jtattermusch
Copy link
Contributor Author

jtattermusch commented Feb 16, 2021

Looks like the only problematic symbol is
0000000000000000 DF *UND* 0000000000000000 GLIBCXX_3.4.20 _ZSt24__throw_out_of_range_fmtPKcz (and it seems to be used by absl)

@jtattermusch
Copy link
Contributor Author

jtattermusch commented Mar 1, 2021

So far I haven't figured out how to make sure that the GCC 4.9 crosscompiler in the dockcross image uses symbols that are compliant with manylinux2014 (as discussed in #25418 (comment)), but I used a workaround instead:

  • when crosscompiling linux aarch64 wheels, use -static-libstdc++ after which no libstdc++ are referenced (because they are linked statically) and the resulting wheels are manylinux2014 compatible (confirmed with manual run auditwheel)
  • this approach increases the size of the binary wheels slightly (increase of size approx. 33MB to ~35MB), but that seems reasonable since we currently don't have a better way of crosscompiling for aarch64. The plan is to remove the workaround in the future, but for now having a set of aarch64 wheels is the priority.

@lidizheng @gnossen I think this PR is now ready to merge. PTAL

Copy link
Contributor

@gnossen gnossen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice investigation!

Copy link
Contributor

@lidizheng lidizheng left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for digging this!

@jtattermusch
Copy link
Contributor Author

known failures:
#25594

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
lang/Python release notes: yes Indicates if PR needs to be in release notes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants