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

Build wheels using QEMU emulation #469

Closed
wants to merge 2 commits into from
Closed

Build wheels using QEMU emulation #469

wants to merge 2 commits into from

Conversation

russkel
Copy link

@russkel russkel commented Nov 28, 2020

From the discussion in #364 I had an attempt at getting builds working using qemu/binfmt which is pretty seamless with Docker.

Running on a Core i7 x86_64 machine:

↳ python -m cibuildwheel --platform linux --print-build-identifiers
cp27-manylinux_x86_64
cp27-manylinux_x86_64
cp35-manylinux_x86_64
cp36-manylinux_x86_64
cp37-manylinux_x86_64
cp38-manylinux_x86_64
cp39-manylinux_x86_64
cp27-manylinux_i686
cp27-manylinux_i686
cp35-manylinux_i686
cp36-manylinux_i686
cp37-manylinux_i686
cp38-manylinux_i686
cp39-manylinux_i686
pp27-manylinux_x86_64
pp36-manylinux_x86_64
pp37-manylinux_x86_64

↳ python -m cibuildwheel --platform linux --print-build-identifiers --use-binfmt
cp27-manylinux_x86_64
cp27-manylinux_x86_64
cp35-manylinux_x86_64
cp36-manylinux_x86_64
cp37-manylinux_x86_64
cp38-manylinux_x86_64
cp39-manylinux_x86_64
cp27-manylinux_i686
cp27-manylinux_i686
cp35-manylinux_i686
cp36-manylinux_i686
cp37-manylinux_i686
cp38-manylinux_i686
cp39-manylinux_i686
pp27-manylinux_x86_64
pp36-manylinux_x86_64
pp37-manylinux_x86_64
cp35-manylinux_aarch64
cp36-manylinux_aarch64
cp37-manylinux_aarch64
cp38-manylinux_aarch64
cp39-manylinux_aarch64
cp35-manylinux_ppc64le
cp36-manylinux_ppc64le
cp37-manylinux_ppc64le
cp38-manylinux_ppc64le
cp39-manylinux_ppc64le
cp35-manylinux_s390x
cp36-manylinux_s390x
cp37-manylinux_s390x
cp38-manylinux_s390x
cp39-manylinux_s390x
$ russ @ sherlock in /tmp [19:29:56]
↳ git clone https://github.com/pyrogram/tgcrypto.git
Cloning into 'tgcrypto'...
remote: Enumerating objects: 17, done.
remote: Counting objects: 100% (17/17), done.
remote: Compressing objects: 100% (15/15), done.
remote: Total 276 (delta 7), reused 5 (delta 2), pack-reused 259
Receiving objects: 100% (276/276), 116.65 KiB | 291.00 KiB/s, done.
Resolving deltas: 100% (161/161), done.

$ russ @ sherlock in /tmp [19:30:02]
↳ cd tgcrypto 

$ russ @ sherlock in /tmp/tgcrypto on  master ● [19:30:04]
↳ CIBW_BUILD=cp39-manylinux_aarch64 python -m cibuildwheel --output-dir wheelhouse --platform linux --use-binfmt

     _ _       _ _   _       _           _
 ___|_| |_ _ _|_| |_| |_ _ _| |_ ___ ___| |
|  _| | . | | | | | . | | | |   | -_| -_| |
|___|_|___|___|_|_|___|_____|_|_|___|___|_|

cibuildwheel version 1.7.0

Build options:
  platform: 'linux'
  before_all: ''
  before_build: None
  before_test: None
  build_selector: BuildSelector('cp39-manylinux_aarch64')
  build_verbosity: 0
  dependency_constraints: DependencyConstraintsPosixPath('/home/russ/Devel/cibuildwheel/cibuildwheel/resources/constraints.txt'))
  environment: ParsedEnvironment([])
  manylinux_images: {'x86_64': 'quay.io/pypa/manylinux2010_x86_64:2020-11-11-201fb79', 'i686': 'quay.io/pypa/manylinux2010_i686:2020-11-11-201fb79', 'pypy_x86_64': 'pypywheels/manylinux2010-pypy_x86_64:2020-11-21-a03b9e9', 'aarch64': 'quay.io/pypa/manylinux2014_aarch64:2020-11-11-bc8ce45', 'ppc64le': 'quay.io/pypa/manylinux2014_ppc64le:2020-11-11-bc8ce45', 's390x': 'quay.io/pypa/manylinux2014_s390x:2020-11-11-bc8ce45'}
  output_dir: PosixPath('wheelhouse')
  package_dir: PosixPath('.')
  repair_command: 'auditwheel repair -w {dest_dir} {wheel}'
  test_command: None
  test_extras: ''
  test_requires: []

Here we go!

Starting Docker image quay.io/pypa/manylinux2014_aarch64:2020-11-11-bc8ce45...

ca13d42d27702eb6f775a9774d57d78ec421c0540c5ecd26987a978ed01d6082
    + /bin/true

                                                              ✓ 0.75s
Copying project into Docker...

    + mkdir -p /project

                                                              ✓ 0.32s

Building cp39-manylinux_aarch64 wheel
CPython 3.9 manylinux aarch64

Setting up build environment...

    + /opt/python/cp38-cp38/bin/python -c 'import sys, json, os; json.dump(os.environ.copy(), sys.stdout)'
    + which python
    + which pip

                                                              ✓ 0.94s
Building wheel...

    + rm -rf /tmp/cibuildwheel/built_wheel
    + mkdir -p /tmp/cibuildwheel/built_wheel
    + pip wheel /project -w /tmp/cibuildwheel/built_wheel --no-deps
Processing /project
Building wheels for collected packages: TgCrypto
  Building wheel for TgCrypto (setup.py): started
  Building wheel for TgCrypto (setup.py): finished with status 'done'
  Created wheel for TgCrypto: filename=TgCrypto-1.2.2-cp39-cp39-linux_aarch64.whl size=65370 sha256=b02b0adca3a65cc823b9c1fe09e0a1217a5e6d28c33c46ebf7f847e1194434ed
  Stored in directory: /tmp/pip-ephem-wheel-cache-irkf8ffx/wheels/b1/d1/e9/62441f1a701c6dcdb0d9ccfd73a0bfbac93e8cf297e5312e15
Successfully built TgCrypto
    + /opt/python/cp38-cp38/bin/python -c 'import sys, json, glob; json.dump(glob.glob('"'"'/tmp/cibuildwheel/built_wheel/*.whl'"'"'), sys.stdout)'
    + rm -rf /tmp/cibuildwheel/repaired_wheel
    + mkdir -p /tmp/cibuildwheel/repaired_wheel

                                                             ✓ 34.74s
Repairing wheel...

    + sh -c 'auditwheel repair -w /tmp/cibuildwheel/repaired_wheel /tmp/cibuildwheel/built_wheel/TgCrypto-1.2.2-cp39-cp39-linux_aarch64.whl'
INFO:auditwheel.main_repair:Repairing TgCrypto-1.2.2-cp39-cp39-linux_aarch64.whl
INFO:auditwheel.wheeltools:Previous filename tags: linux_aarch64
INFO:auditwheel.wheeltools:New filename tags: manylinux2014_aarch64
INFO:auditwheel.wheeltools:Previous WHEEL info tags: cp39-cp39-linux_aarch64
INFO:auditwheel.wheeltools:New WHEEL info tags: cp39-cp39-manylinux2014_aarch64
INFO:auditwheel.main_repair:
Fixed-up wheel written to /tmp/cibuildwheel/repaired_wheel/TgCrypto-1.2.2-cp39-cp39-manylinux2014_aarch64.whl
    + /opt/python/cp38-cp38/bin/python -c 'import sys, json, glob; json.dump(glob.glob('"'"'/tmp/cibuildwheel/repaired_wheel/*.whl'"'"'), sys.stdout)'
    + mkdir -p /output
    + mv /tmp/cibuildwheel/repaired_wheel/TgCrypto-1.2.2-cp39-cp39-manylinux2014_aarch64.whl /output

                                                              ✓ 5.39s

✓ cp39-manylinux_aarch64 finished in 41.37s
Copying wheels back to host...


                                                              ✓ 0.32s

$ russ @ sherlock in /tmp/tgcrypto on  master ✖︎ [19:30:57]
↳ ls
 tests/   tgcrypto/   wheelhouse/   COPYING   COPYING.lesser   MANIFEST.in   NOTICE   README.md   setup.py   tox.ini

$ russ @ sherlock in /tmp/tgcrypto on  master ✖︎ [19:31:00]
↳ ls wheelhouse 
 TgCrypto-1.2.2-cp39-cp39-manylinux2014_aarch64.whl

@russkel russkel marked this pull request as draft November 28, 2020 08:50
@russkel russkel changed the title WIP: Build wheels using QEMU emulation Build wheels using QEMU emulation Nov 28, 2020
@henryiii
Copy link
Contributor

henryiii commented Dec 3, 2020

Can this be run on GHA, or do they not support this? I can test it if it can.

@russkel
Copy link
Author

russkel commented Dec 3, 2020

Can this be run on GHA, or do they not support this? I can test it if it can.

I really hope they support it. I have only run it locally at this point. Would be awesome to get someone else to test this as well, thanks @henryiii

edit: Pretty sure there are github actions like "run-on-architecture" that use qemu so I would be surprised if it didn't work.

@henryiii
Copy link
Contributor

henryiii commented Dec 4, 2020

There's an issue I need to fix not related to cibuildwheel, and I have to build NumPy because NumPy is really behind on providing all possible wheels - but it seems to work!!! See https://github.com/scikit-hep/boost-histogram/pull/474/checks?check_run_id=1495728863 (and ignore the one failing test)

@henryiii
Copy link
Contributor

henryiii commented Dec 4, 2020

@joerick We should add tests in cibuildwheel for this, and is the naming, etc fine? I'm really happy to finally be able to build alternative arch wheels on GHA, especially with Travis clamping down / killing open-source support. :)

@russkel
Copy link
Author

russkel commented Dec 4, 2020

There's an issue I need to fix not related to cibuildwheel, and I have to build NumPy because NumPy is really behind on providing all possible wheels - but it seems to work!!! See https://github.com/scikit-hep/boost-histogram/pull/474/checks?check_run_id=1495728863 (and ignore the one failing test)

Great to hear. I looked at the diff and seems really straightforward as intended.

@joerick We should add tests in cibuildwheel for this, and is the naming, etc fine? I'm really happy to finally be able to build alternative arch wheels on GHA, especially with Travis clamping down / killing open-source support. :)

I didn't hear about travis restricting open source access. but I always preferred to use GitHub actions because the infrastructure seemed better and I don't have to write as much boiler plate due to actions.

I think adding tests would be wise. Not sure about naming, I was waiting for input from the maintainer, but he hasn't commented on this yet.

@henryiii
Copy link
Contributor

henryiii commented Dec 4, 2020

I didn't hear about travis restricting open source access

https://blog.travis-ci.com/2020-11-02-travis-ci-new-billing or https://www.jeffgeerling.com/blog/2020/travis-cis-new-pricing-plan-threw-wrench-my-open-source-works

@joerick
Copy link
Contributor

joerick commented Dec 4, 2020

Wow! Thank you @russkel for putting this together! Apologies for not checking this out sooner - I didn't realise it was in a working state already with so little changes :) I'm looking at it again, but I'm still not sure I understand how it works!

Apologies if I'm being a bit slow. Here's what I'm seeing:

  • We start the docker/binfmt image before the build.
    • This just continues to run throughout the build, is that right?
    • This container is perhaps unmaintained, should we use something else going forward?
  • Now it's running, /proc/sys/fs/binfmt_misc/qemu-{arch} on the host indicates that it can run a few more architectures.
    • Does the docker/binfmt image affect this? How?
  • Now we can start other architecture Docker images, like manyinux2014_aarch64, on the x86_64 host.
    • So I guess Docker has built-in support to see these images aren't native and run them through the emulation somehow?

Corrections/comments on the above would be super helpful. I have some ideas on interface too, and of course we'll have to add tests, but it's probably best to start with the basics!

@russkel
Copy link
Author

russkel commented Dec 5, 2020

Hi @joerick ,

This technique was originally found on this Docker blog post: https://www.docker.com/blog/getting-started-with-docker-for-arm-on-linux/ - Also, I am no expert in any of this. I use this technique to cross-compile all sorts of things because it's just so damn straightforward and always seems to work.

This just continues to run throughout the build, is that right?

From wiki: binfmt_misc (Miscellaneous Binary Format) is a capability of the Linux kernel which allows arbitrary executable file formats to be recognized and passed to certain user space applications, such as emulators and virtual machines.[1] It is one of a number of binary format handlers in the kernel that are involved in preparing a user-space program to run.[2]

It looks like binfmt registers some binaries with the kernel. I can't see if they are copied into the file system from the docker image. I don't believe the image continually runs. Upon restart of the machine you need to run the container again to re-register.

This container is perhaps unmaintained, should we use something else going forward?

Looks like you're right. Should be able to substitute with https://github.com/linuxkit/linuxkit/tree/master/pkg/binfmt instead.

Now it's running, /proc/sys/fs/binfmt_misc/qemu-{arch} on the host indicates that it can run a few more architectures.
Does the docker/binfmt image affect this? How?

The kernel creates that sysfs file as a result of binfmt registration that occurs when running that image. It indicates what architectures have been registered.

So I guess Docker has built-in support to see these images aren't native and run them through the emulation somehow?

They might get it for free, because all that docker does is execute things on the host kernel, right? The kernel, through registration knows what userland program to pass foreign architecture binaries to, and throws it over to qemu-static to deal with.

@joerick
Copy link
Contributor

joerick commented Dec 6, 2020

It looks like binfmt registers some binaries with the kernel. I can't see if they are copied into the file system from the docker image. I don't believe the image continually runs. Upon restart of the machine you need to run the container again to re-register.

I see, so perhaps it installs qemu on the host machine when it runs, and tells the kernel to run other binary formats through qemu?

@joerick
Copy link
Contributor

joerick commented Dec 6, 2020

As for interface, my instinct was to expand the list of buildable architectures, as seen here. But that might be a little too much magic for a potentially confusing feature.

So my current thinking would be add an --emulate=ARCH flag onto the command line invocation of cibuildwheel. Then, instead of building wheels in the native architecture, we'll build wheels in just the emulated architecture. This would let the user change CIBW_ options on the separate invocation, if necessary. It's also closer to the experience of building other architectures today, where you'd set up another build job to do so.

Any thoughts @henryiii @YannickJadoul ?

@YannickJadoul
Copy link
Member

Yeah, I agree this is definitely very interesting, but I find it hard to wrap my head around how it works and how cibuildwheel should offer it.

Not sure if I'm a huge fan of --use-binfmt as it gives away a lot of the internal implementation. On the other hand --emulate=ARCH seems like it would cause a lot of redundance. That's why we have CIBW_BUILD/CIBW_SKIP, no?
So from that perspective, I quite like the idea that cibuildwheel would just do its very best to create all wheels it can on the current platform, and --use-binfmt would kind of make sense to 1) opt-in to this behavior, and 2) fail if it's somehow not supported.

It's also closer to the experience of building other architectures today, where you'd set up another build job to do so.

I agree here, but if we want to take a step backwards: is this what we'd want? I had the feeling that the only way this is the case, is because we didn't know how to emulate things.

Also, if I understand correctly, this is a different approach from #364, right? In #364, you're running cibuildwheel in some emulated image, where everything (including the Python interpreter running cibuildwheel) is being tricked to think it's running on another architecture, whereas here, binfmt "teaches" the base system how to execute other architectures?

@henryiii
Copy link
Contributor

henryiii commented Dec 6, 2020

I agree with the "use-binfmt" style, even if the name is not ideal (though it does tell the user what is happening?). Controlling the build using CIBW_BUILD and CIBW_SKIP and using these identifiers seems very natural. If there's no reason to communicate the arch's to enable, I don't think we should introduce it. As seen in my example, you'll probably still split this up since it's slow (does Travis actually have hardware for this? Didn't realize they did, but speed indicates they might), but you'd split the same way you can split now using those variables.

@YannickJadoul
Copy link
Member

even if the name is not ideal (though it does tell the user what is happening?)

The actual magic seems to be QEMU, right? binfmt just "registers" QEMU. But something like --with-qemu or --emulate-architectures or so could work?

So if I understand correctly, the Docker image only installs QEMU + registers the binfmt things? And Docker is just an easy way of doing this, but QEMU itself already has a script to register binfmt?
I also just figured out that that's what this Run-On-Arch GitHub Action does, internally: see here.
This might also be another interesting version of this Docker image to look at? https://github.com/multiarch/qemu-user-static seems to be actively maintained?

So, in order to find the best integration with cibuildwheel, it might be interesting to think about this as two sequential steps: first the installation of QEMU and registering it (which could in principle be done independently from cibuildwheel or as a step before in a separate command or ...). Next the step where cibuildwheel doesn't just trust platform.machine() and checks in a different way whether it can run the other architecture's docker images. (https://github.com/multiarch/true could be interesting, but possibly over-complicating, to check if a certain architecture can be run)

@henryiii
Copy link
Contributor

henryiii commented Dec 6, 2020

--all-arch to report all archs instead of checking the platform? And provide an example for step one?

@YannickJadoul
Copy link
Member

--all-arch to report all archs instead of checking the platform?

Hmmm, what if (for some reason) only some architectures can be found?

I think I was trying to argue that cibuildwheel should always try to detect all architectures it can build for (if it can be done cheaply). But I'm not entirely convinced myself. Would there be a problem with that?

And provide an example for step one?

Yeah, I didn't mean we can't provide a way of doing this, btw. Maybe we can add something that says --install-qemu-archs (or --enable-qemu-archs or so), and be nice to the user. But it would decouple things, at least.

@joerick
Copy link
Contributor

joerick commented Dec 6, 2020

Enjoying the discussion here. A few more thoughts-

  • I'm not totally sure about cibuildwheel discovering and autobuilding emulated archs that it finds in the sysfs. If I want arm64 wheels, I should be specifying that and cibuildwheel should be raising an error if it can't be emulated for some reason.
  • I also kinda think that we should provide some fine grained control over what's emulated versus what's native, e.g if I have x86_64 build workers and arm64 build workers, I should be able to say 'emulate ppc64le on the x86_64, but build arm64 on the native worker'

@YannickJadoul
Copy link
Member

YannickJadoul commented Dec 6, 2020

  • I'm not totally sure about cibuildwheel discovering and autobuilding emulated archs that it finds in the sysfs. If I want arm64 wheels, I should be specifying that and cibuildwheel should be raising an error if it can't be emulated for some reason.

OK, yes, I agree we should be careful here; I hadn't fully considered that. Maybe if we'd build this from scratch, CIBW_BUILD/CIBW_SKIP would take care of this, but yes, now it would be tricky to suddenly expect CIBW_BUILD to be set to only the native architecture.

In that case, I'd go for a flag that says "expect all architectures in CIBW_BUILD - CIBW_SKIP to be emulated". If there's a reason once can't be emulated just add it to the skipped ones, and if you only want to build one architecture, make sure to say so in CIBW_BUILD?

That's basically @russkel's original suggestion, though, which I thought I didn't really like :-)

  • I also kinda think that we should provide some fine grained control over what's emulated versus what's native, e.g if I have x86_64 build workers and arm64 build workers, I should be able to say 'emulate ppc64le on the x86_64, but build arm64 on the native worker'

This should already be possible, though.

  • On x86_64: CBIW_BUILD='*-manylinux_x86_64 *-manylinux_ppc64le' or CIBW_SKIP=*-manylinux_aarch64 (potentially adding a flag to enable detection of emulation).
  • On arm64: nothing needed, because by default, just the native architecture gets built/no QEMU is found?

@henryiii
Copy link
Contributor

henryiii commented Dec 6, 2020

How about --emulate? I don't think you would want it on by default, since it is likely to be painfully slow, and if you have native CI hardware, you don't need it. And then if CIBW_BUILD selects an empty set, you get an error, correct?

I wonder if this could be used the other direction, say to build x86 wheels on spare Raspberry pi's?

@russkel
Copy link
Author

russkel commented Dec 7, 2020

I wonder if this could be used the other direction, say to build x86 wheels on spare Raspberry pi's?

It could indeed if qemu is available and binfmt is configured/registered correctly on the ARM platforms.

As for the discussion on selecting builds: my thoughts was there was all this effort put into BUILD/SKIP filtering I didn't see the need to further expand that when sufficient filtering already exists. I simply added to the list of what the machine was capable building wheels for and the end user can select what they want to compile for with pre-existing functionality I didn't need to touch for the sake of the PR.

@joerick
Copy link
Contributor

joerick commented Dec 8, 2020

I think the thing that's tripping me up with using the existing BUILD/SKIP is that they're kinda at a different level to the native machine filtering.

Because really cibuildwheel's build selector logic is-

(matches_os_and_arch & matches_cibw_build) & !matches_cibw_skip

... that is, before BUILD/SKIP come into play, there is an implicit step where you can only build the wheels of the machine/OS you're on. This new emulate functionality changes the matches_os_and_arch bit, in a way that we don't have direct control over.

Let's say you already have a CI config like:

env:
  CIBW_BUILD: "cp3*"
  CIBW_SKIP: "*i686"

linux_x86_64_worker:
  steps:
    run: 
      - cibuildwheel --output-dir wheelhouse .
macos_worker:
  steps:
    run: 
      - cibuildwheel --output-dir wheelhouse .

Then you want to add just aarch64 emulation to the linux worker. How would you change this config to add that? I think it can be done, but it doesn't seem obvious/easy to me.

This is what I mean about the matches_os_and_arch step of our filtering - it's obvious now, but if we introduce emulation, we offload that complexity onto BUILD/SKIP, and there it becomes a boolean algebra problem. It seems like a more explicit option, like --emulate=ARCH, would simplify the above.

How about --emulate? I don't think you would want it on by default, since it is likely to be painfully slow, and if you have native CI hardware, you don't need it. And then if CIBW_BUILD selects an empty set, you get an error, correct?

No, we had a discussion a while back and I decided not to fail on this condition. Admittedly we weren't all in agreement and I was quite strongly in arguing this shouldn't be a failure though! 😛


I did have another idea, which might be a compromise - I'm quite keen on the specific emulation archs being in the hands of the user, and that we can raise an error if emulation isn't possible on the system. Previously I said we could have --emulate=ARCH, which would just build ARCH, but we could change that, so that it was --emulate=ARCH1,ARCH2, and this would just add emulated architectures to the native build. This would keep just one cibuildwheel invocation, would allow a CIBW_EMULATE="ARCH1 ARCH2" option, and would be fine by me as it's keeping things explicit.

@@ -92,8 +104,12 @@ def build(options: BuildOptions) -> None:
file=sys.stderr)
exit(2)

if options.use_binfmt:
log.step('Installing binfmt...')
subprocess.check_output(['docker', 'run', '--rm', '--privileged', 'docker/binfmt:a7996909642ee92942dcd6cff44b9b95f08dad64'])
Copy link

@scarletcafe scarletcafe Dec 12, 2020

Choose a reason for hiding this comment

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

Judging by the about section and archival of the docker/binfmt repo, maybe this should be replaced with linuxkit/binfmt as per its suggestion?

EDIT: Whoops, just realized this was already discussed in the thread.

Copy link
Author

Choose a reason for hiding this comment

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

Yeah absolutely. I will push up a patch.

@henryiii
Copy link
Contributor

Can QEMU be detected? Maybe the simplest thing would be to let users enable it using the method of their choice, then expand the set, possibly even automatically (or maybe not).

@russkel
Copy link
Author

russkel commented Dec 13, 2020

Can QEMU be detected? Maybe the simplest thing would be to let users enable it using the method of their choice, then expand the set, possibly even automatically (or maybe not).

Yeah, the way I detect the emulated architectures == detection of QEMU.

Maybe that's the way to go, rather than forcing the use of linuxkit/binfmt solution. People can set up qemu and binfmt manually on their machines in a persistent manner. I was going for the all-in-one-batteries-included-just-press-go kind of solution so people could build wheels for everything easily, but maybe that's not ideal?

@henryiii
Copy link
Contributor

henryiii commented Dec 13, 2020

Expanding on that now that I have a keyboard. :) I'm thinking of one of two things - the first before reading @joerick's comment above.

  1. Assuming we can detect if we can run emulated arch's, then the list automatically gets expanded. The workflow would be an enable step, left up to the user, but with a couple of examples, and then you would be able to select with skip/enable. If this has not been run already, the list stays to just the native wheels.

  2. More explicit, and more in line with what @joerick was thinking above, possibly. We add an --arch option - if not set, it detects the native arch as it does now; if set, it just assumes that one or ones when building the targets. I don't think we have to make it a list, as emulation is slow, so the most reasonable thing is to run one job per arch or more, but it wouldn't hurt - maybe someone wants to do one job per Python version, for example. I would still leave the enabling of QEMU up to the user - it's a one line run in Docker, or a simple third party action, correct?

Or, at the very least, have a --qemu or --binfmt flag separate from the --arch flag, that turn this on. So you could enable it yourself, or ask to have it done with a built-in linuxkit/binfmt usage.

I feel like 1) is a bit more idealistic, and avoids new flags, but 2) might be favored and more explicit?

matches_os_and_arch

But doesn't this already cross compile 32 bit and 64 bit? You can build a 32 bit wheel on 64 bit host? Doesn't this just expand that logic to new systems? In the example, you should either expand CIBW_SKIP: "*i686" to include all arches you don't want to build, or better, use CIBW_BUILD: "cp3*x86_64 cp3*aarch64" to select what you want rather than assuming there will only be one other possible arch on your system? If your logic is "I want these two systems only", you should write it that way, not try to invert it and exclude everything but the two you want. Excluding should be for "I don't support X, so don't build it", not for "I want the inverse of this".

@henryiii
Copy link
Contributor

We also should be thinking a bit about how this will expand to building macOS wheels, as we soon will need to have ways to select Universal2/AS/Intel wheels.

@YannickJadoul
Copy link
Member

I feel like 1) is a bit more idealistic, and avoids new flags, but 2) might be favored and more explicit?

I think (correct me if I'm wrong, please!) that @joerick was mostly worried about silently ignoring errors, with 1), when I suggested something similar? I.e., by explicitly requiring something to be built, you can also detect an error if it then is not available.

@YannickJadoul
Copy link
Member

Can QEMU be detected? Maybe the simplest thing would be to let users enable it using the method of their choice, then expand the set, possibly even automatically (or maybe not).

Yeah, the way I detect the emulated architectures == detection of QEMU.

Maybe that's the way to go, rather than forcing the use of linuxkit/binfmt solution. People can set up qemu and binfmt manually on their machines in a persistent manner. I was going for the all-in-one-batteries-included-just-press-go kind of solution so people could build wheels for everything easily, but maybe that's not ideal?

This is a probably slower, but more generic way of detecting it, if Docker is available:

(https://github.com/multiarch/true could be interesting, but possibly over-complicating, to check if a certain architecture can be run)

@joerick
Copy link
Contributor

joerick commented Dec 16, 2020

To keep everyone posted - I'm leaning in favour of the approach in #482 - that is, to keep the binfmt/qemu setup out of cibuildwheel, and a simple --archs flag that would allow cibuildwheel to build a non-native architecture. But thank you for the PR @russkel! Your input in #482 would be appreciated.

@joerick joerick closed this Dec 16, 2020
@russkel
Copy link
Author

russkel commented Dec 17, 2020

Cool. As long as the general functionality gets merged I am happy!

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

Successfully merging this pull request may close these issues.

5 participants