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

BLD Uses cibuildwheel for linux + osx wheels [cd build] #20102

Merged
merged 16 commits into from
Nov 1, 2021

Conversation

thomasjpfan
Copy link
Contributor

@thomasjpfan thomasjpfan commented Oct 11, 2021

Related to MacPython/numpy-wheels#116

This PR:

  1. Enables x86 linux+osx wheels to be built with cibuildwheel.
  2. Allows PR to trigger the wheel build [cd build] is in the commit message, where "cd" means "continuous delivery"

I kept this PR small by only supporting two platforms. Follow up includes:

  1. Windows support
  2. Cross compile universal2 support for macOS
  3. Upload to nightly index at https://pypi.anaconda.org/scipy-wheels-nightly/simple
  4. Maybe linux arm support using QEMU depending on how fast it is

Note: The big diff comes from the licenses that was copied over from numpy-wheels.

@github-actions github-actions bot added the 36 - Build Build related PR label Oct 11, 2021
@mattip
Copy link
Member

mattip commented Oct 11, 2021

Is there a reason you are doing this here rather than at Macpython/numpy-wheels ?

NPY_USE_BLAS_ILP64: 1
CIBW_BUILD: cp${{ matrix.python }}-${{ matrix.platform }}
CIBW_MANYLINUX_X86_64_IMAGE: manylinux2014
CIBW_ENVIRONMENT_LINUX: CFLAGS='-std=c99 -fno-strict-aliasing'
Copy link
Member

Choose a reason for hiding this comment

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

Is -std=c99 definitely needed for the newer compilers? IIRC, there was some discussion that might disable some newer features.

Copy link
Member

Choose a reason for hiding this comment

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

It's only needed for GCC 4.x IIRC, and we should drop that now that we no longer need manylinux1.

Copy link
Member

Choose a reason for hiding this comment

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

Although we should separate dropping that, and not mix it with a CI reshuffle - so the flag is best kept as is here.

Copy link
Member

Choose a reason for hiding this comment

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

how will we remember to do this?

@thomasjpfan
Copy link
Contributor Author

Is there a reason you are doing this here rather than at Macpython/numpy-wheels ?

There are some benefits of moving it to numpy/numpy:

  1. Wheels can be built directly in PRs using a commit containing [cd build].
  2. Do not need to keep numpy-wheels and numpy in sync anymore.

I am also okay with moving this over to MacPython/numpy-wheels. Overall, I think the move to cibuildwheel would make it easier to get wheels built when Python RCs are released.

CC @rgommers Do you have thoughts on moving wheel building to numpy/numpy?

@rgommers
Copy link
Member

CC @rgommers Do you have thoughts on moving wheel building to numpy/numpy?

I think it's time for that. The one advantage of MacPython/numpy-wheels is that we have TravisCI credits there for aarch64/ppc64le builds. But other than that I think it mostly has downsides: hard to discover, more effort to maintain and search for issues because of the split over repos, not enough people paying attention to broken CI because it's a separate repo, etc. We also never intended the repo to be under MacPython, that's an accident of history.

There's a separate question about auto-uploading to PyPI - I know some other projects like it, but I'm still weary of that. Uploading to the Anaconda staging bucket, and having the release manager download those and re-upload when they're ready seems safer to me both release mechanics wise and security wise (e.g., recent codecov security breach exposed secrets).

@rgommers
Copy link
Member

Thanks a lot for working on this @thomasjpfan! Moving to cibuildwheel will be valuable long-term.


# Install GFortran
if [[ $UNAME == "Darwin" ]]; then
# same version of gfortran as the open-libs and numpy-wheel builds
Copy link
Member

Choose a reason for hiding this comment

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

typo: open-libs -> openblas-libs

NPY_USE_BLAS_ILP64: 1
CIBW_BUILD: cp${{ matrix.python }}-${{ matrix.platform }}
CIBW_MANYLINUX_X86_64_IMAGE: manylinux2014
CIBW_ENVIRONMENT_LINUX: CFLAGS='-std=c99 -fno-strict-aliasing'
Copy link
Member

Choose a reason for hiding this comment

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

Although we should separate dropping that, and not mix it with a CI reshuffle - so the flag is best kept as is here.

Copy link
Member

@rgommers rgommers left a comment

Choose a reason for hiding this comment

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

This looks like it will be a very pleasant change of pace, no more bash & submodules:)

tools/wheels/cibw_test_command.sh Show resolved Hide resolved

on:
schedule:
# Nightly build at 1:42 A.M.
Copy link
Member

Choose a reason for hiding this comment

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

add time zone?

with:
submodules: true
# The complete history is required for versioneer.py to work
fetch-depth: 0
Copy link
Member

Choose a reason for hiding this comment

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

I don't think it is - we just need enough commits to have the previous tag. In gitpod.Dockerfile it does git clone --shallow-since=2021-05-22

Copy link
Contributor

Choose a reason for hiding this comment

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

I think this is right. You need enough to get to the tag that started the current version. It is hard to get it right in a maintenance free way. Once could alternatively assume that NumPy will always have fewer than XXXX commits between releases, and then use that.

Copy link
Member

Choose a reason for hiding this comment

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

We tried the "guess the number of commits" and have been wrong before - so probably using the date and bumping it once a year is easier/safer.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I can't find a simple way to get the git describe (versioneer.py) to work with shallow clones:

git clone --shallow-since=2021-05-22 https://github.com/numpy/numpy 
cd numpy
git describe
# fatal: No names found, cannot describe anything.

Currently, a possible solution is:

git clone --depth=1 https://github.com/thomasjpfan/numpy numpy
cd numpy

# pulls in branch with tags
git fetch  --prune origin +d8922518c4ec66d91d16e5549bd9b9390cfee678:refs/remotes/origin/ci_buildwheel_rf_shallow

# checkout branch
git checkout --progress -B ci_buildwheel_rf_shallow refs/remotes/origin/ci_buildwheel_rf_shallow 
git describe 
# v1.22.0.dev0-1425-gd8922518c

I feel like that is a bit too complex compare to fetch-depth: 0.

Note: There is an open issue to get this workflow to work: actions/checkout#338

Copy link
Member

Choose a reason for hiding this comment

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

Agreed that that's too complex - so +1 for doing whatever is simplest here.

I can't find a simple way to get the git describe (versioneer.py) to work with shallow clones:

versioneer continues to be a pain:(

Copy link
Member

Choose a reason for hiding this comment

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

still TBD?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For this PR, I think we leave fetch-depth: 0 for now until actions/checkout#338 gets resolved. It currently takes ~ 14 seconds to fetch the entire history, so I think it is okay for the time being.

Copy link
Member

Choose a reason for hiding this comment

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

I note that --shallow-exclude=v1.21.0.dev0 works. Unfortunately, --shallow-exclude=v1.22.0.dev0^ doesn't.

CIBW_BEFORE_TEST: pip install -r {project}/test_requirements.txt
# Installs libffi so that cffi can be built from source when needed
CIBW_BEFORE_TEST_LINUX: >
[[ "${{ matrix.install_libffi_devel }}" == "1" ]] && yum install -y libffi-devel;
Copy link
Member

Choose a reason for hiding this comment

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

What do we use libffi-devel for, just some optional tests or something more interesting?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

libffi-devel is used to build cffi from source if wheels do not exists. cffi is required by test_requirements here:

# for numpy.random.test.test_extending
cffi

Copy link
Member

Choose a reason for hiding this comment

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

It would be fine to make cffi a soft requirement: if it is unavailable we could skip that test. Is there a way to do that without too much hassle? The test takes the failed import into account

try:
import cffi
except ImportError:
cffi = None

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated test_requirements.txt, to make cffi a soft requirement for python 3.10:

cffi; python_version < '3.10'

.github/workflows/wheels.yml Show resolved Hide resolved
@EpicWink
Copy link

There's a separate question about auto-uploading to PyPI - I know some other projects like it, but I'm still weary of that. Uploading to the Anaconda staging bucket, and having the release manager download those and re-upload when they're ready seems safer to me both release mechanics wise and security wise (e.g., recent codecov security breach exposed secrets).

If PyPI implements draft releases (GitHub PR) (Discourse topic), you could switch to PyPI for this workflow

@thomasjpfan
Copy link
Contributor Author

Uploading to the Anaconda staging bucket, and having the release manager download those and re-upload when they're ready seems safer to me both release mechanics wise and security wise

A follow up to this PR is to upload to an Anaconda staging bucket. From there you can follow your current release workflow of downloading and re-uploaded.

Copy link
Member

@mattip mattip left a comment

Choose a reason for hiding this comment

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

As far as I can tell there is only one nit about a future PR to remove compilation flags, and this looks good to go.

Edit: and the versioneer problem

.github/workflows/wheels.yml Show resolved Hide resolved
with:
submodules: true
# The complete history is required for versioneer.py to work
fetch-depth: 0
Copy link
Member

Choose a reason for hiding this comment

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

still TBD?

NPY_USE_BLAS_ILP64: 1
CIBW_BUILD: cp${{ matrix.python }}-${{ matrix.platform }}
CIBW_MANYLINUX_X86_64_IMAGE: manylinux2014
CIBW_ENVIRONMENT_LINUX: CFLAGS='-std=c99 -fno-strict-aliasing'
Copy link
Member

Choose a reason for hiding this comment

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

how will we remember to do this?

tools/wheels/cibw_test_command.sh Show resolved Hide resolved
@mattip
Copy link
Member

mattip commented Oct 20, 2021

One last thing: it would be good to document the [cd build] string somewhere. See also #18343 which is still open.

@mattip
Copy link
Member

mattip commented Oct 20, 2021

We discussed this at the weekly triage meeting. One workflow that is not clear is the desire to kick off all the different CI that will be used to build wheels against a commit (This PR uses github actions. Currently travis-ci is used for arm64, ppc64le, and s390x. We have concerns that the arm64 builds on travis are flaky and are looking for alternatives, so we may end up with a third CI service). Since we use at least two services, a button to trigger builds on github actions would not be sufficient to complete the task. Currently, the MacPython/numpy-wheels workflow allows us to make a commit to that repo, which then pulls the appropriate commit from here and builds a wheel. If we merge this PR to numpy/numpy, then we could continue with that idea: make a commit to trigger wheel building. But then that commit will become part of the permanent numpy git history. Is that the way other projects use cibuildwheel?

There is also some concern that a run of this CI job will push wheels to anaconda.org, these would be marked as the "latest dev wheels" and picked up by projects building off of latest NumPy wheels. It seems that is a bit too open. Is there a way to limit the ability to upload?

@thomasjpfan
Copy link
Contributor Author

One workflow that is not clear is the desire to kick off all the different CI that will be used to build wheels against a commit

For triggering a build on another service for a specific PR, we can have a button to trigger builds in github actions that calls the other CI services' API to trigger the build. Another option is to manually trigger a build for a specific commit in the CI services' UI.

But then that commit will become part of the permanent numpy git history. Is that the way other projects use cibuildwheel?

I think every project is a little different on how they use cibuildwheel. For scikit-learn, we do have these "build" commit messages in the release/maintenance branches to trigger the build. This places the "which commit the wheel was built on" in the scikit-learn/scikit-learn repo. If numpy maintainers do not wish to have commits for wheel building in the main repo, then an option is to trigger different CI services as suggested above, which does not need a specific commit message.

There is also some concern that a run of this CI job will push wheels to anaconda.org, these would be marked as the "latest dev wheels" and picked up by projects building off of latest NumPy wheels. It seems that is a bit too open. Is there a way to limit the ability to upload?

There are ways to limit the upload. What kind of limits are you thinking of?

@mattip
Copy link
Member

mattip commented Oct 22, 2021

@charris - thoughts?

@EpicWink
Copy link

EpicWink commented Oct 24, 2021

FYI cibuildwheel just released musllinux support

@mattip
Copy link
Member

mattip commented Oct 31, 2021

In recent community/triage discussions we decided to put this in. TBD:

I would like to put this in as-is and do the rest in future PRs. Does that make sense?

@mattip
Copy link
Member

mattip commented Nov 1, 2021

Thanks @thomasjpfan

@thomasjpfan
Copy link
Contributor Author

I would like to put this in as-is and do the rest in future PRs. Does that make sense?

Your plan looks good to me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
36 - Build Build related PR
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants