From 09d89690e5dfd354dbc9124ba8e481779cdc9581 Mon Sep 17 00:00:00 2001 From: Glenn Hickey Date: Tue, 6 Oct 2026 21:57:23 -0400 Subject: [PATCH] Build LAST from a submodule cactus-pangenome and cactus-minigraph train their scoring with LAST by default (), and progressive cactus is to train lastz's with it too. Build LAST with cactus, from a submodule alongside lastz and red, instead of downloading it with the pangenome tools. The submodule is pinned at 1651, the version downloadPangenomeTools has been cloning and building. The rule carries over the script's two makefile patches, which let cactus's CXXFLAGS (its CPU baseline) and jemalloc reach lastal and lastdb. The build still fails if an upstream change stops the first patch from matching. On ARM, where cactus's own make now builds LAST, the rule also drops LAST's -msse4, which only x86 compilers take, as LAST's README does for ARM. The Docker image, CI and the binary release all build LAST through make. The release's check-static covers its binaries, as the script's own ldd check did. Co-Authored-By: Claude Opus 5.5 --- .gitmodules | 3 ++ Makefile | 20 +++++++++++- build-tools/downloadPangenomeTools | 50 +----------------------------- submodules/last | 1 + 4 files changed, 24 insertions(+), 50 deletions(-) create mode 160000 submodules/last diff --git a/.gitmodules b/.gitmodules index ecbb5975d..6162141a5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -50,3 +50,6 @@ path = submodules/minipoa url = https://github.com/ComparativeGenomicsToolkit/minipoa.git branch = cactus-integration +[submodule "submodules/last"] + path = submodules/last + url = https://gitlab.com/mcfrith/last.git diff --git a/Makefile b/Makefile index d214c645d..343aca97d 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ modules = api setup caf bar hal reference pipeline preprocessor # submodules are in multiple pass to handle dependencies cactus2hal being dependent on # both cactus and sonLib # jemalloc is conditionally added based on include.mk settings -submodules1 = sonLib cPecan hal matchingAndOrdering pinchesAndCacti abPOA lastz paffy red collapse-bubble FASTGA FASTAN alntools +submodules1 = sonLib cPecan hal matchingAndOrdering pinchesAndCacti abPOA lastz last paffy red collapse-bubble FASTGA FASTAN alntools ifeq ($(minipoa),on) submodules1 += minipoa endif @@ -406,6 +406,24 @@ else endif ln -f submodules/lastz/src/lastz bin +# LAST: cactus trains its scoring models with last-train (and lastdb and lastal). Its makefile writes +# "CXXFLAGS = ..." with spaces around the '=': make that line add to ours, rather than replace them, and leave the +# sub-make override on its line 3 alone, since that is how src/makefile receives the value. Checked, as a sed that +# stops matching after an upstream change is silently a no-op. LAST has no LIBS variable either, so add one after +# the objects: a static archive named before them resolves nothing, and lastal would quietly keep glibc's +# allocator. Its -msse4 only suits x86 compilers, and its README has ARM builds go without it too. +ifdef arm +lastSedArm = -e 's/ -msse4//' +endif +suball.last: suball.jemalloc + cd submodules/last && sed -i -e 's/^CXXFLAGS *= */CXXFLAGS += /' ${lastSedArm} makefile && grep -qE '^CXXFLAGS \+= ' makefile \ + || { echo "last: no 'CXXFLAGS =' line in its makefile; check that cactus's CXXFLAGS still reach lastal" >&2; exit 1; } + cd submodules/last && sed -i -e '/LIBS/!s/ -lz$$/ -lz $$(LIBS)/' src/makefile && grep -q -- '-lz $$(LIBS)' src/makefile \ + || { echo "last: no '-lz' link line in src/makefile; check that jemalloc still reaches lastal" >&2; exit 1; } + cd submodules/last && CXXFLAGS="$${CXXFLAGS} ${CACTUS_ARCH_FLAGS}" LIBS="${jemallocSubLibs}" ${MAKE} + ln -f submodules/last/bin/lastal submodules/last/bin/lastdb submodules/last/bin/last-train \ + submodules/last/bin/last-postmask ${BINDIR} + suball.paffy: # paffy carries its own sonLib clone, which is put at the commit cactus pins. That clone has only # fetched what its own pin needed, so bring the commit over from cactus's checkout first. diff --git a/build-tools/downloadPangenomeTools b/build-tools/downloadPangenomeTools index f88fec06b..2359fd25b 100755 --- a/build-tools/downloadPangenomeTools +++ b/build-tools/downloadPangenomeTools @@ -49,7 +49,7 @@ fi # CPU baseline. include.mk is the single source of truth; ask make for it rather than # duplicating the arm/legacy/x86 selection here, where it would silently drift. Without this -# nothing built by this script -- minigraph, minimap2, gfatools, last, samtools/bcftools -- +# nothing built by this script -- minigraph, minimap2, gfatools, samtools/bcftools -- # gets an arch flag at all: confirmed against the v3.3.0 tarball, where minigraph carried zero # AVX2 in its own code, only glibc's runtime-dispatched string routines. # MAKEFLAGS is cleared because "make binRelease" reaches this from inside a make recipe. @@ -427,54 +427,6 @@ then mkdir -p ${pangenomeBuildDir} fi -# last -cd ${pangenomeBuildDir} -git clone https://gitlab.com/mcfrith/last.git --recursive -cd last -git checkout 1651 -# last writes "CXXFLAGS = ..." with spaces around the '=', so the old -# 's/CXXFLAGS=/CXXFLAGS+=/' never matched line 1. What it did match was the sub-make -# override on line 3 ($(MAKE) CXXFLAGS="$(CXXFLAGS)" -> CXXFLAGS+="$(CXXFLAGS)"), which only -# doubled last's own flags while its line-1 assignment carried on clobbering ours -- so -# nothing cactus sets has ever reached lastal/lastdb. Anchor to the line start and allow the -# spaces; leave line 3 alone, since that override is how src/makefile receives the value. -# Guarded: this sed was silently a no-op for years, which is exactly what we don't want twice. -grep -qE '^CXXFLAGS *=' makefile || { - echo "ERROR: last: no 'CXXFLAGS =' assignment at the start of a line in makefile." >&2 - echo " Upstream changed its build; re-check that cactus's CXXFLAGS reach lastal." >&2 - exit 1 -} -sed -i makefile -e 's/^CXXFLAGS *= */CXXFLAGS += /' -# last has no LIBS variable, so add one after the objects. Order matters: a static archive -# named before the objects resolves nothing and is discarded, and lastal would silently fall -# back to glibc's allocator. -sed -i src/makefile -e '/LIBS/!s/ -lz$/ -lz $(LIBS)/' -LIBS="${jemallocLib}" make -j ${numcpu} -if [[ $STATIC_CHECK -ne 1 || $(ldd bin/lastal | grep so | wc -l) -eq 0 ]] -then - mv bin/lastal ${binDir} -else - exit 1 -fi -if [[ $STATIC_CHECK -ne 1 || $(ldd bin/lastdb | grep so | wc -l) -eq 0 ]] -then - mv bin/lastdb ${binDir} -else - exit 1 -fi -if [[ $STATIC_CHECK -ne 1 || $(ldd bin/last-train | grep so | wc -l) -eq 0 ]] -then - mv bin/last-train ${binDir} -else - exit 1 -fi -if [[ $STATIC_CHECK -ne 1 || $(ldd bin/last-postmask | grep so | wc -l) -eq 0 ]] -then - mv bin/last-postmask ${binDir} -else - exit 1 -fi - cd ${CWD} rm -rf ${pangenomeBuildDir} diff --git a/submodules/last b/submodules/last new file mode 160000 index 000000000..d20367432 --- /dev/null +++ b/submodules/last @@ -0,0 +1 @@ +Subproject commit d20367432f5e3924689444fab263a0d731417801