Skip to content

Commit f80b5f8

Browse files
authored
Merge pull request #71 from nextgenusfs/fix-glimmerhmm-sigill
Compile glimmerhmm from source to dodge bioconda's AVX2 baseline (Rosetta 2 SIGILL)
2 parents 4278598 + 13d92ee commit f80b5f8

2 files changed

Lines changed: 115 additions & 1 deletion

File tree

‎Dockerfile‎

Lines changed: 108 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,14 +70,112 @@ RUN set -eux; \
7070
"$PY" -c "import pytantan; from pytantan.lib import RepeatFinder, default_scoring_matrix; print('pytantan smoke test OK', pytantan.__version__)"
7171

7272
# Pre-generate an activation script so the final image doesn't need pixi.
73+
# The post-hook PATH re-prepend keeps /opt/glimmerhmm/bin ahead of
74+
# /app/.pixi/envs/default/bin even after `pixi shell-hook` activation
75+
# prepends the pixi env — so our generic-baseline glimmerhmm shadows the
76+
# bioconda v3 build at runtime. See the glimmerhmm-build stage for why.
7377
RUN mkdir -p /app/bin && \
7478
{ echo '#!/bin/bash'; \
7579
echo 'set -e'; \
7680
pixi shell-hook --shell bash; \
81+
echo 'export PATH="/opt/glimmerhmm/bin:$PATH"'; \
7782
echo 'exec "$@"'; \
7883
} > /app/bin/entrypoint.sh && \
7984
chmod +x /app/bin/entrypoint.sh
8085

86+
# ---------------------------------------------------------------------------
87+
# Stage 1b: glimmerhmm — compile glimmerhmm from upstream source with a
88+
# generic x86_64 baseline so it runs on every host (incl. Rosetta 2).
89+
# The bioconda glimmerhmm 3.0.4 build sets -march=x86-64-v3 (AVX2/BMI2)
90+
# and SIGILLs under Rosetta 2 on Apple Silicon / pre-Haswell x86_64
91+
# (the same root cause as augustus and pytantan). glimmerhmm is NOT in
92+
# Ubuntu apt, so we build it ourselves here.
93+
# Install layout matches bioconda's: bin/{glimmerhmm,glimmhmm.pl,trainGlimmerHMM}
94+
# + share/glimmerhmm/{train/*,trained_dir/*}. The trainGlimmerHMM perl
95+
# script locates its support binaries via $RealBin/../share/glimmerhmm/train
96+
# (the same upstream patch applied by both bioconda and this recipe).
97+
# The bioconda glimmerhmm in the pixi env is kept as a shadowed fallback
98+
# (and is what runs on osx-arm64 native dev) — see the PATH order in the
99+
# final stage and the comment in pixi.toml.
100+
# ---------------------------------------------------------------------------
101+
FROM --platform=linux/amd64 ubuntu:${UBUNTU_VERSION} AS glimmerhmm-build
102+
103+
ENV DEBIAN_FRONTEND=noninteractive \
104+
LANG=C.UTF-8 \
105+
LC_ALL=C.UTF-8
106+
107+
RUN apt-get update && \
108+
apt-get install -y --no-install-recommends \
109+
build-essential \
110+
ca-certificates \
111+
wget \
112+
binutils && \
113+
rm -rf /var/lib/apt/lists/*
114+
115+
ARG GLIMMERHMM_VERSION=3.0.4
116+
ARG GLIMMERHMM_SHA256=43e321792b9f49a3d78154cbe8ddd1fb747774dccb9e5c62fbcc37c6d0650727
117+
118+
WORKDIR /build
119+
RUN wget -q https://ccb.jhu.edu/software/glimmerhmm/dl/GlimmerHMM-${GLIMMERHMM_VERSION}.tar.gz && \
120+
echo "${GLIMMERHMM_SHA256} GlimmerHMM-${GLIMMERHMM_VERSION}.tar.gz" | sha256sum -c - && \
121+
tar -xzf GlimmerHMM-${GLIMMERHMM_VERSION}.tar.gz
122+
123+
WORKDIR /build/GlimmerHMM
124+
125+
# Same upstream fixes the bioconda recipe applies (makefile typos +
126+
# self-locating perl entry points). Without these the `all` target in
127+
# train/makefile names "escoreSTOP2" / "rfapp" and clean targets a
128+
# nonexistent "trainGlimmerHMM", and the perl entry points don't find
129+
# their support binaries when invoked via PATH.
130+
RUN sed -i 's|^escoreSTOP2:|scoreSTOP2:|g' train/makefile && \
131+
sed -i 's|^rfapp:|erfapp:|g' train/makefile && \
132+
sed -i 's| trainGlimmerHMM||g' train/makefile && \
133+
sed -i 's|all: build-icm|all: misc.o build-icm.o build-icm-noframe.o build-icm|g' train/makefile && \
134+
sed -i '1 s|^.*$|#!/usr/bin/env perl|g' train/trainGlimmerHMM && \
135+
sed -i 's|FindBin;|FindBin qw($RealBin);|g' train/trainGlimmerHMM && \
136+
sed -i 's|$FindBin::Bin;|"$RealBin/../share/glimmerhmm/train";|g' train/trainGlimmerHMM && \
137+
sed -i '1 s|^.*$|#!/usr/bin/env perl|g' bin/glimmhmm.pl
138+
139+
# -O3 matches the bioconda recipe; -march=x86-64 -mtune=generic gives the
140+
# v1 baseline that every Rosetta-2-emulated CPU can execute.
141+
ENV CFLAGS="-O3 -march=x86-64 -mtune=generic -Wno-format -Wno-deprecated-declarations -Wno-unused-variable -Wno-unused-but-set-variable -Wno-comment" \
142+
CXXFLAGS="-O3 -march=x86-64 -mtune=generic -Wno-format -Wno-deprecated-declarations -Wno-unused-variable -Wno-unused-but-set-variable -Wno-comment"
143+
144+
RUN make -C sources CC=g++ CFLAGS="${CXXFLAGS}" -j"$(nproc)" && \
145+
make -C train clean && \
146+
make -C train all C=gcc CC=g++ CFLAGS="${CXXFLAGS}" -j"$(nproc)"
147+
148+
# Install into /opt/glimmerhmm with the same bin/ + share/ layout
149+
# bioconda uses, so trainGlimmerHMM's $RealBin/../share/... lookup
150+
# still resolves once the tree is copied into the final stage.
151+
RUN mkdir -p /opt/glimmerhmm/bin /opt/glimmerhmm/share/glimmerhmm/train && \
152+
install -m 0755 bin/glimmhmm.pl sources/glimmerhmm train/trainGlimmerHMM /opt/glimmerhmm/bin/ && \
153+
install -m 0755 train/build-icm train/build-icm-noframe train/build1 train/build2 train/erfapp /opt/glimmerhmm/share/glimmerhmm/train/ && \
154+
install -m 0755 train/falsecomp train/findsites train/karlin train/score train/score2 /opt/glimmerhmm/share/glimmerhmm/train/ && \
155+
install -m 0755 train/scoreATG train/scoreATG2 train/scoreSTOP train/scoreSTOP2 train/splicescore /opt/glimmerhmm/share/glimmerhmm/train/ && \
156+
cp -f train/*.pm /opt/glimmerhmm/share/glimmerhmm/train/ && \
157+
cp -Rf trained_dir /opt/glimmerhmm/share/glimmerhmm/
158+
159+
# Verify no AVX/AVX2/AVX512 instructions slipped into the compiled
160+
# binaries (defense-in-depth — same check pytantan uses). Plain SSE2
161+
# (xmm only, non-VEX) is the x86_64 baseline and is fine.
162+
RUN set -eux; \
163+
BAD=""; \
164+
for bin in /opt/glimmerhmm/bin/glimmerhmm \
165+
/opt/glimmerhmm/share/glimmerhmm/train/build1 \
166+
/opt/glimmerhmm/share/glimmerhmm/train/build2 \
167+
/opt/glimmerhmm/share/glimmerhmm/train/build-icm \
168+
/opt/glimmerhmm/share/glimmerhmm/train/build-icm-noframe; do \
169+
hits=$(objdump -d -M intel --no-show-raw-insn "$bin" 2>/dev/null \
170+
| grep -Ec '\b(ymm[0-9]+|zmm[0-9]+|vpbroadcast|vextracti128|vinserti128|vfmadd|vpermd|vpgatherdd)\b' || true); \
171+
echo "$bin -> $hits AVX/AVX2/AVX512 hits"; \
172+
if [ "$hits" -gt 0 ]; then BAD="${BAD} ${bin}"; fi; \
173+
done; \
174+
if [ -n "$BAD" ]; then \
175+
echo "ERROR: AVX-bearing binaries in glimmerhmm:$BAD"; \
176+
exit 1; \
177+
fi
178+
81179
# ---------------------------------------------------------------------------
82180
# Stage 2: dbs — download/build the funannotate2 databases (minus BUSCO)
83181
# ---------------------------------------------------------------------------
@@ -130,6 +228,15 @@ RUN apt-get update && \
130228
COPY --from=build /app/.pixi/envs/default /app/.pixi/envs/default
131229
COPY --from=build /app/bin/entrypoint.sh /app/bin/entrypoint.sh
132230

231+
# Self-compiled glimmerhmm (generic x86_64 baseline). Layered onto PATH
232+
# ahead of /app/.pixi/envs/default/bin so it shadows the bioconda binary
233+
# at runtime — the bioconda glimmerhmm in the pixi env is built with
234+
# -march=x86-64-v3 (AVX2/BMI2) and SIGILLs under Rosetta 2. See the
235+
# glimmerhmm-build stage above for the rationale; the pixi-env glimmerhmm
236+
# remains in the image as a shadowed fallback (and is what runs natively
237+
# on osx-arm64 outside docker).
238+
COPY --from=glimmerhmm-build /opt/glimmerhmm /opt/glimmerhmm
239+
133240
# Pre-built databases (~3 GB; BUSCO lineages download at runtime)
134241
COPY --from=dbs /opt/funannotate2_db /opt/funannotate2_db
135242

@@ -139,7 +246,7 @@ COPY --from=dbs /opt/funannotate2_db /opt/funannotate2_db
139246
# installs new_species.pl, optimize_augustus.pl, etc.
140247
ENV FUNANNOTATE2_DB=/opt/funannotate2_db \
141248
AUGUSTUS_CONFIG_PATH=/usr/share/augustus/config \
142-
PATH=/app/.pixi/envs/default/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
249+
PATH=/opt/glimmerhmm/bin:/app/.pixi/envs/default/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
143250

144251
WORKDIR /data
145252

‎pixi.toml‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,13 @@ pip = "*"
1717
# installs augustus from Ubuntu apt instead (generic-baseline build, runs
1818
# everywhere). On native macOS development the funannotate2 CLI is exercised
1919
# via the dockerized image, so augustus on osx-arm64 is not needed here.
20+
# NOTE: glimmerhmm has the same root cause (bioconda compiles with
21+
# -march=x86-64-v3 → SIGILL under Rosetta 2). It is NOT in Ubuntu apt, so
22+
# the Docker image compiles it from source with a generic baseline and
23+
# layers it onto PATH ahead of the pixi env (see Dockerfile). The bioconda
24+
# entry below is kept anyway: on osx-arm64 it provides the arm64-native
25+
# binary for outside-docker dev work, and inside the image it acts as a
26+
# shadowed fallback if /opt/glimmerhmm is somehow missing.
2027
minimap2 = "*"
2128
miniprot = "*"
2229
snap = "*"

0 commit comments

Comments
 (0)