mlton for Debian
----------------

1. Repacking upstream tarballs
==============================

The upstream mlton source tarball contains non-DFSG-free files. It also
contains nested tarballs and patches for their extracted contents. We
repack the original tarball to remove the non-DFSG-free files and to
extract the nested tarballs. (Strictly speaking, we don't bother with
sources, but just use the upstream VCS tags.) Here are the instructions
for importing a new upstream release.

First, make sure that upstream MLton's git repository is known to your
local git clone of the Debian packaging:

git remote add mlton https://github.com/MLton/mlton.git

Next, fetch any known tags:

git fetch mlton

We now merge the desired tag into the upstream branch:

export VERSION=202YMMDD
git switch upstream
git merge on-${VERSION}-release
# Make sure we have any relevant upstream tarballs so that
# we can reextract them:
git checkout on-${VERSION}-release -- \
    lib/mllpt-lib/ml-lpt.tgz lib/mllpt-lib/ml-lpt.patch \
    lib/mlrisc-lib/MLRISC.tgz lib/mlrisc-lib/MLRISC.patch \
    lib/smlnj-lib/smlnj-lib.tgz lib/smlnj-lib/smlnj-lib.patch \
    runtime/gdtoa.tgz 'runtime/gdtoa.*.patch'
# Delete previously extracted tarballs to make sure that
# files deleted upstream are deleted in the repacked tarball:
rm -fr \
    lib/ckit-lib/ckit-lib \
    lib/mllpt-lib/ml-lpt \
    lib/mlrisc-lib/MLRISC \
    lib/smlnj-lib/smlnj-lib \
    runtime/gdtoa
# Extract the nested tarballs and apply upstream's patches
make -C lib/ckit-lib ckit-lpt/README
make -C lib/mllpt-lib ml-lpt/README
make -C lib/mlrisc-lib MLRISC/README.mlton
make -C lib/smlnj-lib smlnj-lib/README.mlton
# The Makefile in runtime has a bunch of eval lines that compile files
# before ever getting around to extracting gdtoa.tgz. We extract just
# the relevant Makefile target and run it ourselves with variables
# substituted in:
cd runtime && \
    sed -n '/^gdtoa\/README/,${p;/^$/q}' Makefile | \
    sed -e 's@$(PATCH)@patch@g;s@$(GZIP)@gzip@g;s@$(TAR)@tar@g' | \
    make --file="-" && cd -
# Delete the nested tarballs and patches
rm lib/mllpt-lib/ml-lpt.tgz lib/mllpt-lib/ml-lpt.patch
rm lib/mlrisc-lib/MLRISC.tgz lib/mlrisc-lib/MLRISC.patch
rm lib/smlnj-lib/smlnj-lib.tgz lib/smlnj-lib/smlnj-lib.patch
rm runtime/gdtoa.tgz runtime/gdtoa.*.patch
# Delete non-DFSG-free files from unpacked tarballs
rm -fr lib/smlnj-lib/smlnj-lib/HTML4/tests/
# We need to pass -f to git add because upstream ignores
# extracted contents via .gitignore
git add -f lib runtime
git commit -m "Repacked new upstream release ${VERSION}"
git tag -s "upstream/${VERSION}+dfsg"

Now we can merge in back into the desired packaging branch, e.g.:

git switch debian/unstable
git merge upstream/${VERSION}+dfsg

2. Rebootstrapping
==================

MLton, as with most SML compilers, requires a SML compiler to compile
itself. If ever mlton becomes uninstallable, you will need to compile
it with the last installable version. Unfortunately,

    Building the runtime system requires compiling and executing
    programs that determine characteristics of the platform, which is
    why it isn’t currently feasible to build the runtime system on the
    host machine using a cross-compiler toolchain.

per doc/guide/src/CrossCompiling.adoc. This means that you cannot use
sbuild to locally cross-compile for a different architecture, and that
you will have to manually build the package on that architecture.
Assuming you have access to a porterbox of that architecture, here are
some instructions that you use to bootstrap mlton on that architecture:

1. Create a clean build schroot on the porterbox
------------------------------------------------

These instructions assume that you are porting mlton via one of
Debian's porterboxes. In this case, it is not possible to
directly install mlton's build dependencies on the host, and you
must instead install them in a chroot.

ARCH=i386      # Arch we are bootstrapping
PORTERBOX=barriere.debian.org
SCHROOT=$USER-sid-$ARCH
REMOTE_TMP=tmp # temporary remote directory for building

cat <<EOF | ssh $PORTERBOX
    schroot -b -c sid_$ARCH-dchroot -n $SCHROOT &&
    dd-schroot-cmd -c $SCHROOT apt-get update &&
    dd-schroot-cmd -c $SCHROOT apt-get dist-upgrade -y &&
    dd-schroot-cmd -c $SCHROOT apt-get install -y eatmydata &&
    dd-schroot-cmd -c $SCHROOT apt-get build-dep -y mlton &&
    mkdir -p $REMOTE_TMP
EOF

If mlton does not already exist for your architecture, you will not be
able to install all build dependencies for mlton (e.g., mlton-compiler
will be missing). This is OK.

2. Git clone a copy of mlton's sources
--------------------------------------

Upstream's bootstrapping infrastructure relies on git-archive(1) to
transfer sources between hosts. Thus, you need to make sure that you
have a Git clone of the sources (either upstream's tree or the Debian
source package).

debcheckout https://salsa.debian.org/debian/mlton.git
cd mlton

3. Build mlton locally
----------------------

Next, we weed a working copy of mlton in our local source tree.
Install any build dependencies, as needed:

apt-get build-dep mlton

Next, the repacked sources pre-extract various embedded tarballs, and we
patch upstream's Makefiles to not extract them. As a result, we must
apply Debian's patches before we can build. We also need to commit these
changes because git-archive only knows about commited changes.

git switch -c local-only/mlton-bootstrap
dpkg-source --before-build .
git add .
git commit -am "Commit applied patches"

Finally, we build the sources in the local source tree:

make

4. Bootstrap the package on the remote architecture
---------------------------------------------------

Upstream's Makefile provides a remote-bootstrap target that uses SSH to
bootstrap mlton on the porterbox. It copies certain files over to
generate binary files with the appropriate symbols, while also using the
local mlton compiler to handle the remainder of the compilation. Please
see the documentation in the Makefile for additional information.

make SCHROOT=$SCHROOT REMOTE_MACHINE=ssh://$PORTERBOX \
    REMOTE_TMP=$REMOTE_TMP remote-bootstrap

5. Send the bootstrapped mlton binary to the porterbox
------------------------------------------------------

If the previous step succeeds, you should have a compressed tarball
whose name follows the pattern mlton-MLTON_VERSION.ARCH-OS.tgz in your
local source directory. It contains a mlton binary and runtime that will
run on the porterbox.

scp mlton-*.tgz $PORTERBOX

6. Send the mlton source package to the porterbox
-------------------------------------------------

Our goal is, after all, to build a Debian binary package on the
porterbox.

git reset --hard HEAD && git clean -qxdf   # clean source tree
dpkg-buildpackage -S --no-sign
VERSION="$(dpkg-parsechangelog --show-field Version)"
dcmd scp ../mlton_$VERSION.dsc $PORTERBOX:

7. Build binary package on porterbox
------------------------------------

We use the clean schroot that we generated plus the binary bootstrapping
files that we just built to build our binary package. We ask
dpkg-buildpackage not to check for build dependencies, because we will
use our bootstrapping copy of mlton instead of the (potentially
nonexistent) mlton binary package.

export BOOTSTRAP=mlton-VERSION.ARCH-OS
tar zxvf $BOOTSTRAP.tgz
# preserve environment to access BOOTSTRAP:
schroot -c $SCHROOT -r --preserve-environment
export PATH=~/$BOOTSTRAP/bin/:$PATH
dpkg-buildpackage -B --no-check-builddeps mlton_*.dsc

 -- Ryan Kavanagh <rak@debian.org>  Fri, 07 Nov 2025 10:38:55 -0500
