diff --git a/docs/development.md b/docs/development.md index 66abd64cb..eac8d36c2 100644 --- a/docs/development.md +++ b/docs/development.md @@ -24,7 +24,7 @@ been fully updated yet. You can install Python from python.org or from your dist ``` $ python3.9 -m venv ~/pyenv $ ~/pyenv/bin/pip install --upgrade pip -$ ~/pyenv/bin/pip install aqt +$ ~/pyenv/bin/pip install aqt[qt6] ``` Then to run Anki: @@ -38,7 +38,7 @@ $ ~/pyenv/bin/anki ``` c:\> python -m venv \pyenv c:\> \pyenv\scripts\pip install --upgrade pip -c:\> \pyenv\scripts\pip install aqt +c:\> \pyenv\scripts\pip install aqt[qt6] ``` Then to run Anki: @@ -89,6 +89,8 @@ pip install --upgrade bazel-dist/*.whl On Windows you'll need to list out the filenames manually. +If building on ARM Linux, please see the notes at the bottom of [Linux](./linux.md). + ## Running tests You can run all tests at once. From the top level project folder: diff --git a/docs/linux.md b/docs/linux.md index a36f72efe..d150ab925 100644 --- a/docs/linux.md +++ b/docs/linux.md @@ -10,6 +10,8 @@ Glibc is required - if you are on a distro like Alpine that uses musl, you'll ne to contribute fixes to the upstream [Rust rules](https://github.com/bazelbuild/rules_rust/issues/390), then follow the steps in [Other Platforms](./new-platform.md). +Users on ARM64, see the notes at the bottom of this file before proceeding. + **Ensure some basic tools are installed**: ``` @@ -99,6 +101,29 @@ To run Anki in optimized mode, use: ./scripts/runopt ``` +## ARM64 support + +Other platforms download PyQt binary wheels from PyPI. There are no PyQt wheels available +for ARM Linux, so you will need to rely on your system-provided libraries instead. As Anki +requires Python 3.9, this means you will need a fairly up-to-date distro such as Debian 11. + +After installing the system libraries (eg 'sudo apt install python3-pyqt5.qtwebengine'), +find the place they are installed (eg '/usr/lib/python3/dist-packages'). Then before +running any commands like './run', tell Anki where they can be found: + +``` +export PYTHON_SITE_PACKAGES=/usr/lib/python3/dist-packages/ +``` + +Note: the trailing slash at the end is required. + +There are a few things to be aware of when doing this: + +- You should use ./run and not scripts/run-qt5\*, even if your system libraries are Qt5. +- If your system libraries are Qt5, when creating an aqt wheel, the wheel will not work + on Qt6 environments. +- Some of the tests only work with PyQt6, and will show failures when run under PyQt5. + ## More For info on running tests, building wheels and so on, please see [Development](./development.md). diff --git a/proto/clang_format.bzl b/proto/clang_format.bzl index a7a9ade37..2ea62cd44 100644 --- a/proto/clang_format.bzl +++ b/proto/clang_format.bzl @@ -18,6 +18,7 @@ alias( "@ankidesktop//platforms:macos_arm64": "@clang_format_macos_x86_64//:clang-format", "@ankidesktop//platforms:macos_x86_64": "@clang_format_macos_x86_64//:clang-format", "@ankidesktop//platforms:linux_x86_64": "@clang_format_linux_x86_64//:clang-format", + "@ankidesktop//platforms:linux_arm64": "@clang_format_local//:clang-format", }), visibility = ["//visibility:public"] ) @@ -60,6 +61,13 @@ def setup_clang_format(name): ], ) + if not native.existing_rule("clang_format_local"): + native.new_local_repository( + name = "clang_format_local", + path = "/usr/bin", + build_file_content = "exports_files(['clang-format'])", + ) + if not native.existing_rule(name): _setup_clang_format( name = name, diff --git a/pylib/anki/BUILD.bazel b/pylib/anki/BUILD.bazel index 4a24cec0f..4ca46641e 100644 --- a/pylib/anki/BUILD.bazel +++ b/pylib/anki/BUILD.bazel @@ -74,7 +74,8 @@ py_wheel( "//platforms:windows_x86_64": "win_amd64", "//platforms:macos_x86_64": "macosx_10_13_x86_64", "//platforms:linux_x86_64": "manylinux_2_28_x86_64", - "//platforms:linux_arm64": "manylinux_2_28_aarch64", + # Built on a Debian 11 image that has Qt 5.15 + "//platforms:linux_arm64": "manylinux_2_31_aarch64", }), python_tag = "cp39", requires = [ @@ -84,7 +85,7 @@ py_wheel( "protobuf>=3.17", "markdown", "stringcase", - 'orjson; platform_machine == "x86_64"', + "orjson", 'psutil; sys_platform == "win32"', 'distro; sys_platform != "darwin" and sys_platform != "win32"', ], diff --git a/python/python.bzl b/python/python.bzl index 6add734f8..f6fd1830c 100644 --- a/python/python.bzl +++ b/python/python.bzl @@ -12,26 +12,40 @@ _python_distros = { url = "https://github.com/ankitects/python-build-standalone/releases/download/anki-2021-10-15/cpython-3.9.7-x86_64-unknown-linux-gnu-install_only-20211013T1538.tar.gz", sha256 = "6a42fe15950f4e42000f5c68ebefacf8fce024f4d80a446789c18b174efdec1b", ), + "linux_arm64": struct( + # pending https://github.com/indygreg/python-build-standalone/issues/95 + url = "https://github.com/ankitects/python-build-standalone/releases/download/anki-2021-10-15/cpython-3.9.7-aarch64-unknown-linux-gnu-install_only-20211013T1538.tar.gz", + sha256 = "2c5812d2e29b83b428a3da1f6c1a99b0581382e65290a767f8de25cbd1269d2a", + ), "windows_amd64": struct( url = "https://github.com/indygreg/python-build-standalone/releases/download/20211012/cpython-3.9.7-x86_64-pc-windows-msvc-shared-install_only-20211011T1926.tar.gz", sha256 = "80370f232fd63d5cb3ff9418121acb87276228b0dafbeee3c57af143aca11f89", ), } -def get_platform(rctx): +def _unix_arch(rctx): + result = rctx.execute(["arch"]) + if result.return_code: + fail("invoking arch failed", result.stderr) + return result.stdout.strip() + +def _get_platform(rctx): if rctx.os.name == "mac os x": - result = rctx.execute(["arch"]) - if result.return_code: - fail("invoking arch failed", result.stderr) - arch = result.stdout.strip() + arch = _unix_arch(rctx) if arch == "i386": return "macos_amd64" elif arch == "arm64": return "macos_arm64" else: - fail("unexpected arch:", arch) + fail("unexpected arch", arch) elif rctx.os.name == "linux": - return "linux_amd64" + arch = _unix_arch(rctx) + if arch == "x86_64": + return "linux_amd64" + elif arch == "aarch64": + return "linux_arm64" + else: + fail("unexpected arch", arch) elif rctx.os.name.startswith("windows"): return "windows_amd64" else: @@ -43,7 +57,7 @@ def _impl(rctx): path = rctx.os.environ.get("PYO3_PYTHON") rctx.symlink(path, "python") else: - platform = get_platform(rctx) + platform = _get_platform(rctx) distro = _python_distros.get(platform) rctx.download_and_extract( url = distro.url, diff --git a/qt/aqt/forms/build_ui.py b/qt/aqt/forms/build_ui.py index 158ab0210..ab7e19038 100644 --- a/qt/aqt/forms/build_ui.py +++ b/qt/aqt/forms/build_ui.py @@ -2,7 +2,13 @@ import re import sys import io import os -from PyQt6.uic import compileUi +try: + from PyQt6.uic import compileUi +except ImportError: + # ARM64 Linux builds may not have access to PyQt6, and may have aliased + # it to PyQt5. We allow fallback, but the _qt6.py files will not be valid. + from PyQt5.uic import compileUi + from dataclasses import dataclass @@ -45,8 +51,13 @@ def with_fixes_for_qt6(code: str) -> str: def with_fixes_for_qt5(code: str) -> str: + code = code.replace( + "from PyQt5 import QtCore, QtGui, QtWidgets", + "from PyQt5 import QtCore, QtGui, QtWidgets\nfrom aqt.utils import tr\n", + ) code = code.replace("Qt6", "Qt5") code = code.replace("QtGui.QAction", "QtWidgets.QAction") + code = code.replace("import icons_rc", "") return code