ENH Add support in micropip for installing binary wheels. This PR is on top of #2589.

We use `packaging.tags.sys_tags` to get the list of supported tags
then use `packaging.utils.parse_wheel_filename` to get the set of
tags the current wheel implement then check if one of the wheel's
tags is a supported tag. This is a fully accurate check method and
could also catch things like abi3 wheels that are compatible with
multiple Python versions.

This allows micropip to be used to install binary emscripten wheels.
In order to manage the ABI issues, I also changed the wheel platform
tag to `emscripten_2_0_27_wasm32` so we can tell which version of
emscripten the wheel was built with.

The normal way that the platform tag is generated is by substituting
in the `uname` OS name and version info. Emscripten has dummy
information in `uname` instead of any actual version, so I patched
`uname` to report the Emscripten version. See upstream issue:
https://github.com/emscripten-core/emscripten/issues/16977

### Checklists

- [x] Add a [CHANGELOG](https://github.com/pyodide/pyodide/blob/main/docs/project/changelog.md) entry
- [x] Add / update tests

#!/usr/bin/env python3
import argparse
import sys

from . import buildall, buildpkg, create_xbuildenv, install_xbuildenv, mkpkg, serve
from .common import init_environment


def make_parser() -> argparse.ArgumentParser:
    """Create an argument parser with argparse"""

    main_parser = argparse.ArgumentParser(prog="pyodide")
    main_parser.description = "A command line interface (CLI) for pyodide_build"
    subparsers = main_parser.add_subparsers(help="action")

    for command_name, module in (
        ("buildpkg", buildpkg),
        ("buildall", buildall),
        ("serve", serve),
        ("mkpkg", mkpkg),
        ("create_xbuildenv", create_xbuildenv),
        ("install_xbuildenv", install_xbuildenv),
    ):
        if "sphinx" in sys.modules and command_name in [
            "buildpkg",
            "buildall",
            "pywasmcross",
        ]:
            # Likely building documentation, skip private API
            continue
        parser = module.make_parser(subparsers.add_parser(command_name))
        parser.set_defaults(func=module.main)
    return main_parser


def main():
    init_environment()

    main_parser = make_parser()

    args = main_parser.parse_args()
    if hasattr(args, "func"):
        # run the selected action
        args.func(args)
    else:
        main_parser.print_help()


if __name__ == "__main__":
    main()

#!/usr/bin/env python3
import argparse
import sys

from . import buildall, buildpkg, create_xbuildenv, install_xbuildenv, mkpkg, serve
from .common import init_environment


def make_parser() -> argparse.ArgumentParser:
    """Create an argument parser with argparse"""

    main_parser = argparse.ArgumentParser(prog="pyodide")
    main_parser.description = "A command line interface (CLI) for pyodide_build"
    subparsers = main_parser.add_subparsers(help="action")

    for command_name, module in (
        ("buildpkg", buildpkg),
        ("buildall", buildall),
        ("serve", serve),
        ("mkpkg", mkpkg),
        ("create_xbuildenv", create_xbuildenv),
        ("install_xbuildenv", install_xbuildenv),
    ):
        if "sphinx" in sys.modules and command_name in [
            "buildpkg",
            "buildall",
            "pywasmcross",
        ]:
            # Likely building documentation, skip private API
            continue
        parser = module.make_parser(subparsers.add_parser(command_name))
        parser.set_defaults(func=module.main)
    return main_parser


def main():
    init_environment()

    main_parser = make_parser()

    args = main_parser.parse_args()
    if hasattr(args, "func"):
        # run the selected action
        args.func(args)
    else:
        main_parser.print_help()


if __name__ == "__main__":
    main()
