Running ViroProfiler on aarch64
The container images published on Docker Hub under denglab/ are amd64-only
(I-01), so on an aarch64 host (Apple silicon, AWS Graviton,
NVIDIA GB10/GB200, Ampere) the images have to be built locally from docker/:
bash docker/build_arm64.sh # build + convert to SIF
nextflow run main.nf -profile apptainer,arm64_local --input samplesheet.csv --db ~/viroprofiler
docker/build_arm64.sh covers base, qc, abundance, replicyc, vibrant, bracken,
virsorter2, vcontact3, vclust, vitap, genomad, checkamg, geneannot, binning
and viewer. One image is missing from that list on purpose — host, which cannot be built
for linux-aarch64 at all — and one tool inside binning is likewise unavailable here.
vcontact3 is buildable here only because it does not come from conda: fastcluster and
jenkspy have no linux-aarch64 conda build, so pixi global install -c bioconda vcontact3
and every other conda route fail, while both packages compile from their PyPI sdists. See
I-32.
vitap builds natively with no constraint to work around, which is worth recording because
it is the exception among the taxonomy tools. VITAP itself is pure Python, and all three
executables it calls have linux-aarch64 builds in bioconda:
python3 -c "
import json, urllib.request
for p in ['diamond', 'seqkit', 'prodigal']:
d = json.load(urllib.request.urlopen('https://api.anaconda.org/package/bioconda/' + p))
subs = sorted({f['attrs'].get('subdir') for f in d['files'] if f['version'] == d['latest_version']})
print(p, d['latest_version'], subs)
"
# diamond 2.2.5 ['linux-64', 'linux-aarch64', 'osx-64', 'osx-arm64']
# seqkit 2.13.0 ['linux-64', 'linux-aarch64', 'osx-64', 'osx-arm64']
# prodigal 2.6.3 ['linux-64', 'linux-aarch64', 'osx-64', 'osx-arm64']
The bioconda vitap package is noarch, so the same holds for installing VITAP from
bioconda rather than from source. What made a source install necessary is a version
question, not an architecture one: see docker/viroprofiler-vitap/Dockerfile for why the
image pins 1.7.1 rather than the current 1.12.
The image was built and its smoke test run on an aarch64 host
(bash docker/build_arm64.sh vitap, NVIDIA GB10, Apptainer 1.5.2):
#11 2.864 diamond version 2.1.16
#11 2.868 Prodigal V2.6.3: February, 2016
#11 2.889 seqkit v2.13.0
OK vitap -> /home/allen/singularity/viroprofiler/viroprofiler-vitap.sif
viroprofiler-host — iPHoP
Both halves of the dependency set are x86-64-only.
conda half. Solving the fork's iphop_environment.yml for linux-aarch64 fails
(micromamba 1.5.8, 2026-08-12):
error libmamba Could not solve for environment specs
The following packages are incompatible
├─ blast 2.12** does not exist (perhaps a typo or a missing channel);
├─ hmmer 3.3.2** does not exist (perhaps a typo or a missing channel);
├─ perl-bioperl 1.7.* is installable with the potential options
│ ├─ perl-bioperl 1.7.2 would require
│ │ └─ perl-bioperl-core 1.007002 , which requires
│ │ └─ perl-db-file, which does not exist (perhaps a missing channel);
│ └─ perl-bioperl 1.7.8 would require
│ └─ perl-bio-tools-run-alignment-tcoffee ... t-coffee ... pasta
├─ python 3.8** is not installable because there are no viable options
├─ r-ranger 0.13** does not exist (perhaps a typo or a missing channel);
└─ scikit-learn 0.22.0** does not exist (perhaps a typo or a missing channel).
bioconda does publish linux-aarch64 builds of blast and hmmer, but only of versions
iPHoP does not accept (2.16.0 and 3.4 respectively).
pip half. iPHoP's classifier inference engine has no aarch64 Linux wheel in any release:
| Package | Linux wheel platform tags on PyPI |
|---|---|
tensorflow-decision-forests (all 40 releases) |
manylinux_2_12_x86_64, manylinux_2_17_x86_64 |
tensorflow==2.7.0 |
manylinux2010_x86_64 |
The *_arm64 wheels those projects publish are macosx_12_0_arm64 / macosx_13_0_arm64,
i.e. Apple silicon, not Linux.
Neither constraint can be worked around by relaxing a pin: iPHoP loads Keras models trained
with TF 2.7 through tensorflow-decision-forests 0.2.2, and that package's Linux build has
never targeted aarch64.
Consequence. conf/arm64_local.config sets use_iphop = false, so host prediction is
skipped on aarch64. docker/viroprofiler-host/Dockerfile pins
FROM --platform=linux/amd64, so building it on an aarch64 host requires a registered
binfmt_misc QEMU interpreter and produces an amd64 image that then has to run under
emulation.
DeepVirFinder — removed, replaced by geNomad
DeepVirFinder was frozen to a 2018 stack that bioconda/conda-forge never built for
linux-aarch64. Solving its environment file for that platform failed:
error libmamba Could not solve for environment specs
The following packages are incompatible
├─ deepvirfinder is not installable because it requires
│ └─ keras 2.2.4 , which does not exist (perhaps a missing channel);
├─ keras 2.2.4** does not exist (perhaps a typo or a missing channel);
└─ theano 1.0.3** does not exist (perhaps a typo or a missing channel).
deepvirfinder was not in bioconda at all; it came from the hcc channel, and it has had
no release since 2020.
Resolution. GENOMAD replaced DVF in both workflows. geNomad does virus
identification, provirus excision and marker-based gene annotation in one pass, and every
one of its dependencies — including mmseqs2 and aragorn — has a linux-aarch64 conda
build, so docker/viroprofiler-genomad/ builds natively on both architectures.
CHECKAMG was added alongside it and is likewise architecture-neutral, with one caveat
recorded in docker/viroprofiler-checkamg/Dockerfile: torch_scatter publishes no aarch64
wheel and compiles from its sdist, and its setup.py imports torch at build time, so torch
has to be installed before CheckAMG and the compile has to run with --no-build-isolation.
Consequence for PHAMB. run_RF.py reads a per-contig virus score in DeepVirFinder's
format. PHAMB_DVF_TABLE writes geNomad's scores in that layout, so the missing score table
is no longer what stops PHAMB here — VAMB is. See the next section.
--binning phamb — VAMB
PHAMB classifies VAMB's clusters, and VAMB has no linux-aarch64 artifact in any release
line:
| VAMB | bioconda subdirs | Blocker on aarch64 |
|---|---|---|
| 2.0.1 – 4.1.3 | linux-64, osx-64 |
compiled package, never built for aarch64 |
| 5.0.3, 5.0.4 | noarch |
requires pycoverm, published for linux-64, osx-64, osx-arm64 only |
python3 -c "
import json, urllib.request, collections
for p in ['vamb', 'pycoverm']:
d = json.load(urllib.request.urlopen('https://api.anaconda.org/package/bioconda/' + p))
print(p, dict(collections.Counter(f['attrs'].get('subdir') for f in d['files'])))
"
# vamb {'linux-64': 14, 'osx-64': 14, 'noarch': 2}
# pycoverm {'linux-64': 4, 'osx-arm64': 4, 'osx-64': 4}
docker/viroprofiler-binning/pixi.toml therefore declares [feature.vamb] platforms =
["linux-64"], and the Dockerfile installs that environment only when BuildKit's
TARGETARCH is amd64. The image still builds on aarch64 and still provides vRhyme and
PHAMB's scoring code — it simply has no clusterer for PHAMB to classify.
WorkflowViroprofiler.binningIsAvailable() refuses --binning phamb on aarch64 at
start-up, so the run fails in a second with an explanation instead of hours later on
vamb: command not found. It reads the architecture Nextflow itself runs on, which is exact
for a local executor and a guess on a heterogeneous cluster.
--binning vrhyme is unaffected and is the binner to use on aarch64.
The version pinned is 3.0.2, and that is a compatibility choice rather than a platform one.
VAMB 4 removed --jgi outright — it takes only --bamfiles or a .npz, and hashes the BAM
reference names against the FASTA, so it cannot be handed a contig subset with BAMs mapped
against the full library, which is exactly this pipeline's arrangement. VAMB 5 additionally
renamed and restructured the cluster file PHAMB's read_clusters parses. 3.0.2 is the
release PHAMB was developed against; it runs on Python 3.6, which is why it lives in its own
pixi environment and why the lockfile matters for keeping it installable.
Re-checking these constraints
Package availability changes; both checks are cheap and need no aarch64 hardware, since
--platform makes the solver work cross-platform.
# conda side. Every image except `host` now declares its platforms in a pixi manifest, so
# `pixi lock` reports an unsatisfiable platform at lock time rather than at build time:
# x failed to solve requirements of environment 'vamb' for platform 'linux-aarch64'
# For `host`, whose environment file comes from the iPHoP checkout, use micromamba:
docker run --rm -v "$PWD/iphop_environment.yml:/tmp/e.yml:ro" \
mambaorg/micromamba:1.5.8 \
micromamba create --dry-run --platform linux-aarch64 -n t -f /tmp/e.yml -y
# pip side
curl -s https://pypi.org/pypi/tensorflow-decision-forests/json | python3 -c \
'import json,sys; d=json.load(sys.stdin); print(sorted({f["filename"].split("-")[-1] \
for v in d["releases"] for f in d["releases"][v] if f["filename"].endswith(".whl")}))'
The same --platform linux-64 solve is also the only way to check
docker/viroprofiler-host/Dockerfile without an amd64 machine: it reports
Install: 285 packages for the fork's environment file, and Install: 296 packages once
the typer, seqkit and procps-ng specs the Dockerfile adds are included. Both dry runs
end with a pip failed to install packages error, which is expected — a dry run has no
prefix for the trailing pip: section to install into, and the conda solve has already
completed by then.