diff --git a/docs/development.md b/docs/development.md index c5df2ed84..a7a311d25 100644 --- a/docs/development.md +++ b/docs/development.md @@ -47,6 +47,21 @@ Then to run Anki: c:\> \pyenv\scripts\anki ``` +**ARM Linux** + +Since PyQt wheels are not available on PyPI, you'll need to use your system +version instead: + +- Ensure you're on a distro that has Python 3.9/3.10, glibc, and PyQt5.14+ +- Install the PyQt packages, eg `apt install python3-pyqt5.qtwebengine`. +- Use the following commands: + +``` +$ python3.9 -m venv ~/pyenv --system-site-packages +$ ~/pyenv/bin/pip install --upgrade pip +$ ~/pyenv/bin/pip install aqt +``` + ## Building from source Platform-specific instructions: @@ -77,6 +92,8 @@ On Windows: .\scripts\build.bat ``` +Linux users can also optionally [build via Docker](../scripts/docker/README.md). + The generated wheel paths will be printed as the build completes. You can then install them by copying the paths into a pip install command. @@ -89,7 +106,20 @@ 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). +You'll also need to install PyQt: + +``` +$ pip3 install pyqt6 pyqt6-webengine +``` + +or + +``` +$ pip3 install pyqt5 pyqtwebengine +``` + +On ARM Linux, see the instructions in the pre-built wheels section about a system PyQt, +and please see the notes at the bottom of [Linux](./linux.md). ## Running tests diff --git a/docs/docker/README.md b/docs/docker/README.md index eb28a1905..f57232d5c 100644 --- a/docs/docker/README.md +++ b/docs/docker/README.md @@ -1,11 +1,14 @@ # Anki in Docker -This README contains the instructions for building and running the Anki Docker image. +This is an example of how you can build and run Anki from inside Docker. This +approach keeps everything inside Docker images, and sends the GUI to an X11 +display over TCP/IP. This approach keeps things tidy, so may be a good choice +for if you wish to build Anki irregularly and don't want to build it outside of +Docker. -Docker provides a standard for installing software on many systems -(Windows, macOS, Linux), and it allows one to build software without cluttering a system -with dependencies. The Dockerfile contains the instructions for building the Docker image, -and it also serves as instructions for how to build Anki from source on Linux. +It takes longer to build after small changes however, so for development, if you +wish to use Docker, the approach [in the build +scripts](../../scripts/docker/README.md) may be more appropriate. # Build the Docker image diff --git a/docs/linux.md b/docs/linux.md index d150ab925..ed044ab00 100644 --- a/docs/linux.md +++ b/docs/linux.md @@ -6,6 +6,9 @@ These instructions are written for Debian/Ubuntu; adjust for your distribution. Some extra notes have been provided by a forum member: https://forums.ankiweb.net/t/guide-how-to-build-and-run-anki-from-source-with-xubuntu-20-04/12865 +You can see a full list of requirements by looking at the [Dockerfiles](../scripts/docker/README.md) +in the scripts folder. + Glibc is required - if you are on a distro like Alpine that uses musl, you'll need 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). diff --git a/scripts/docker/Dockerfile.amd64 b/scripts/docker/Dockerfile.amd64 new file mode 100644 index 000000000..f130acc69 --- /dev/null +++ b/scripts/docker/Dockerfile.amd64 @@ -0,0 +1,58 @@ +FROM debian:10-slim + +ARG DEBIAN_FRONTEND="noninteractive" +ARG uid=1000 +ARG gid=1000 + +RUN apt-get update \ + && apt-get install --yes --no-install-recommends \ + bash \ + curl \ + curl \ + findutils \ + g++ \ + gcc \ + git \ + grep \ + libdbus-1-3 \ + libfontconfig1 \ + libgl1 \ + libnss3 \ + libpulse-mainloop-glib0 \ + libxcomposite1 \ + libxcursor1 \ + libxi6 \ + libxkbcommon-x11-0 \ + libxkbcommon0 \ + libxrandr2 \ + libxrender1 \ + libxtst6 \ + portaudio19-dev \ + rsync \ + pkg-config \ + libssl-dev \ + libegl1 \ + libxkbfile1 \ + libgstreamer1.0-0 \ + libgstreamer-plugins-base1.0 \ + libgstreamer-gl1.0-0 \ + ca-certificates \ + && rm -rf /var/lib/apt/lists/* + +RUN curl -L https://github.com/bazelbuild/bazelisk/releases/download/v1.10.1/bazelisk-linux-amd64 \ + -o /usr/local/bin/bazel \ + && chmod +x /usr/local/bin/bazel + +RUN mkdir -p /code/bazel-docker/home && \ + echo groupadd -g ${gid} user && \ + useradd -d /code/bazel-docker/home -m -u ${uid} user && \ + chown -R user.user /code + +RUN ln -sf /usr/bin/python3 /usr/bin/python + +USER user +COPY build-entrypoint /tmp +WORKDIR /code +ENV XDG_CACHE_HOME=/code/bazel-docker/home + +ENTRYPOINT ["/bin/bash", "/tmp/build-entrypoint"] diff --git a/scripts/docker/Dockerfile.arm64 b/scripts/docker/Dockerfile.arm64 new file mode 100644 index 000000000..c177b2dac --- /dev/null +++ b/scripts/docker/Dockerfile.arm64 @@ -0,0 +1,61 @@ +FROM debian:11-slim + +ARG DEBIAN_FRONTEND="noninteractive" +ARG uid=1000 +ARG gid=1000 + +RUN apt-get update \ + && apt-get install --yes --no-install-recommends \ + python-is-python3 \ + bash \ + curl \ + curl \ + findutils \ + g++ \ + gcc \ + git \ + grep \ + libdbus-1-3 \ + libfontconfig1 \ + libgl1 \ + libnss3 \ + libpulse-mainloop-glib0 \ + libxcomposite1 \ + libxcursor1 \ + libxi6 \ + libxkbcommon-x11-0 \ + libxkbcommon0 \ + libxrandr2 \ + libxrender1 \ + libxtst6 \ + portaudio19-dev \ + rsync \ + pkg-config \ + libssl-dev \ + libegl1 \ + libxkbfile1 \ + libgstreamer1.0-0 \ + libgstreamer-plugins-base1.0 \ + libgstreamer-gl1.0-0 \ + ca-certificates \ + # -- begin only required for arm64/debian11 + python-is-python3 \ + clang-format \ + python3-pyqt5.qtwebengine \ + # -- end only required for arm64/debian11 + && rm -rf /var/lib/apt/lists/* + + +RUN curl -L https://github.com/bazelbuild/bazelisk/releases/download/v1.10.1/bazelisk-linux-arm64 \ + -o /usr/local/bin/bazel \ + && chmod +x /usr/local/bin/bazel + +RUN echo groupadd -g ${gid} user && useradd -d /code/bazel-docker/home -m -u ${uid} user + +USER user +COPY build-entrypoint /tmp +WORKDIR /code +ENV XDG_CACHE_HOME=/code/bazel-docker/home +ENV PYTHON_SITE_PACKAGES=/usr/lib/python3/dist-packages/ + +ENTRYPOINT ["/bin/bash", "/tmp/build-entrypoint"] diff --git a/scripts/docker/README.md b/scripts/docker/README.md new file mode 100644 index 000000000..a1447b628 --- /dev/null +++ b/scripts/docker/README.md @@ -0,0 +1,28 @@ +# Building in Docker + +This folder contains a script for building Anki inside a Docker container. +It works by creating an image with the required dependencies, and then runs the +build with the source folder mounted into the image. This will cause files to be +written into `bazel-\*` and `node_modules` in the source folder as the build proceeds. +The advantage of doing it this way is that most of the efficiency of building +outside Docker is retained - you can make minor changes and run the build again, +and only the changed parts need to be rebuilt. + +If you're looking for a fully isolated build, [this other +approach](../../docs/docker/README.md) in the docs folder may suit you better. As +it also includes runtime dependencies, it may be a useful reference for libraries +you'll need to install before running Anki. + +# Usage + +Ensure Docker is installed on your machine, and your user has permission to connect +to Docker. Then run the following command from the root folder of this source repo: + +``` +$ scripts/docker/build amd64 +``` + +The resulting wheels will be written into bazel-dist. See +[Development](../docs/development.md) for information on how to install them. + +If you're on an ARM Linux machine, replace amd64 with arm64. diff --git a/scripts/docker/build b/scripts/docker/build new file mode 100755 index 000000000..becfd5f7b --- /dev/null +++ b/scripts/docker/build @@ -0,0 +1,26 @@ +#!/bin/bash + +set -e + +test -e WORKSPACE || ( + echo "Run from project root" + exit 1 +) + +arch=$1 + +if [ "$arch" != "amd64" -a "$arch" != "arm64" ]; then + echo "usage: build [amd64|arm64]" + exit 1 +fi + +rm -rf bazel-dist + +export DOCKER_BUILDKIT=1 + +docker build --tag ankibuild --file scripts/docker/Dockerfile.$arch \ + --build-arg uid=$(id -u) --build-arg gid=$(id -g) \ + scripts/docker +docker run --rm -it \ + --mount type=bind,source="$(pwd)",target=/code \ + ankibuild diff --git a/scripts/docker/build-entrypoint b/scripts/docker/build-entrypoint new file mode 100644 index 000000000..61eab413c --- /dev/null +++ b/scripts/docker/build-entrypoint @@ -0,0 +1,10 @@ +#!/bin/bash + +set -e + +rm -rf bazel-dist +bazel --output_user_root=bazel-docker/root \ + build -c opt dist --symlink_prefix=bazel-docker/links/ \ + --experimental_no_product_name_out_symlink +tar xvf bazel-docker/links/bin/dist.tar +bazel --output_user_root=bazel-docker/root shutdown