Macaulay 2 on Ubuntu ARM

I've compiled Macaulay 2 so that I can use it on my cell phone running linuxonandroid.

Here's my most recent architecture-dependent .deb file, for download and installation:

This is an older .deb file:

Compiling Macaulay 2 on ARM has gotten a lot easier in recent years, thanks to advances in the qemu emulator, which does a pretty good job of emulating an ARM processor.

qemu on Linux operates in one of two modes. It can do full virtual machine emulation, booting ARM Linux in a virtualized environment, or it can run individual ARM binaries on an Intel Linux host. The second mode is used during the installation process described below, and the virtual machine emulation is then used to compile Macaulay 2.

My most recent Macaulay 2 .deb files were built on Amazon's EC2 cloud. If you use EC2, I'd recommend an m4.large instance, since qemu's ARM emulator can't use multiple processors, so there's no point using anything larger, and an m3.medium instance doesn't provide enough memory (it swaps incessantly).

I. Get an Ubuntu ARM System running in a qemu Virtual Machine Emulator

  1. get the packages you need on your host system
    apt-get install qemu-system-arm qemu-user-static debootstrap
  3. create a qemu virtual disk
    qemu-img create -f qcow2 ubuntu-arm-qemu.img 25G
  4. format and loopback mount the qemu virtual disk (ignore the I/O error from mke2fs; takes a little over two minutes on my system)
    sudo modprobe nbd
    sudo qemu-nbd  -c /dev/nbd0 ubuntu-arm-qemu.img
    sudo mke2fs -t ext4 /dev/nbd0
    mkdir mnt
    sudo mount /dev/nbd0 mnt
  5. install the base Ubuntu system

    I specify the armhf architecture because that's what matches my cell phone's ARMv7 processor, and I use Ubuntu wily 15.10 because xenial 16.04 won't run on my phone's older Linux kernel. The buildd variant selects packages like gcc needed for package builds.

    The flash-kernel package is designed to install the Linux kernel on a flash partition, isn't needed when running under qemu, and causes constant errors from apt.

    I install an ssh server for logging in to the virtual machine. I prefer this over logging in on its console since ssh does terminal type negotiation, while the console appears to the VM as nothing more than a UART.

    sudo qemu-debootstrap --arch=armhf --variant=buildd --include=linux-generic,ubuntu-minimal,openssh-server --exclude=debfoster,flash-kernel wily mnt

  6. set the network to configure on boot by adding these two lines at the end of mnt/etc/network/interfaces
    auto eth0
    iface eth0 inet dhcp
  7. If you want to set a root password, chroot into the guest system to do it:
    sudo chroot mnt
  8. copy your ssh public key (~/.ssh/ into mnt/root/.ssh/authorized_keys,

  9. copy vmlinuz, initrd.img and lib/firmware/*/device-tree/vexpress-v2p-ca15-tc1.dtb out of mnt

  10. umount the qemu virtual disk, and disconnect /dev/nbd0
    sudo umount mnt
    sudo qemu-nbd -d /dev/nbd0
  11. Make sure vmlinuz is readable by qemu; by default it's only readable by root

  12. My ls -lh now looks like this:
    total 1.6G
    -rw-r--r--  1 root    root     28M Aug 22 14:04 initrd.img
    drwxr-xr-x  2 root    root    4.0K Aug 22 13:58 mnt
    -rw-r--r--  1 baccala baccala 1.6G Aug 22 14:05 ubuntu-arm-qemu.img
    -rw-r--r--  1 root    root     13K Aug 22 14:05 vexpress-v2p-ca15-tc1.dtb
    -rw-r--r--  1 root    root    6.7M Aug 22 14:04 vmlinuz
  13. boot qemu, emulating a Virtual Express board with a 32-bit Cortex-A15 processor (I put this in a shell script)

    QEMU_AUDIO_DRV=none qemu-system-arm -kernel vmlinuz -initrd initrd.img -M vexpress-a15 -m 1024 -append "root=/dev/mmcblk0 rw mem=1024M console=ttyAMA0,38400n8" -sd ubuntu-arm-qemu.img -dtb vexpress-v2p-ca15-tc1.dtb -nographic -net nic -net user,hostfwd=tcp::2222-:22

    This should boot the emulated virtual machine, with a serial console on the tty and an ssh server listening on port 2222.

    In case you're wondering, that .dtb file specifies things like what I/O ports and interrupts are used by the emulated UART and the SD controller, and needs to match the -M vexpress-a15 option to qemu. The dtc tool, provided in the device-tree-compiler package, can be used to decode .dtb files.

II. Build Macaulay 2

All of these steps are done on the emulated ARM virtual machine, i.e, ssh -p 2222 root@localhost, or put something like the following clause in your .ssh/config file:
  1. silence locale warning messages from Perl (only needed once; shouldn't be needed at all on newer Ubuntu systems)
    locale-gen en_US.UTF-8
  2. apt-get install git

  3. git clone --branch=release-1.9.2

  4. Macaulay 2 version 1.9.2 doesn't detect ARM architectures correctly; cd M2 and feed this to patch -p1
    --- a/M2/distributions/deb/
    +++ b/M2/distributions/deb/
    @@ -19,24 +19,7 @@ endif
     ############################## main targets
    -ifeq (@ARCH@,x86_64)
    -ifeq (@ARCH@,i686)
    -# libgc needs to be compiled with i686 to get multiple threads
    -ifeq (@ARCH@,armv7l)
    -ifeq (@ARCH@,armv6l)
    -$(error unrecognized architecture @ARCH@)
    +DEBARCH=$(shell dpkg-architecture -q DEB_TARGET_ARCH)

  5. Install the packages listed in the Macaulay 2 INSTALL file

    apt-get install -y -q autoconf bison emacs flex g++ gcc gfortran libc6-dev libatomic-ops-dev libgc-dev libgdbm-dev liblapack-dev libmpfr-dev libncurses-dev libncurses5-dev libreadline-dev libxml2-dev liblzma-dev libz-dev make openssh-server patch subversion time unzip zlib1g-dev libtool pkg-config libmpc-dev fakeroot

    Several packages required by Macaulay 2 are missing from Ubuntu 15.10 ARM: libcdd-dev libglpk-dev libgmp3-dev libntl-dev libpari-dev

    These libraries might be present on a different OS distribution; otherwise the Macaulay 2 build scripts download and compile them with no problems.

  6. apt-get install wget or apt-get install curl (needed for automatic downloading of dependent libraries)

  7. cd M2; make (this just builds the configure script)

  8. Configure Macaulay 2 to build Debian packages:

    ./configure --enable-download --enable-build-libraries=pari FC=gfortran --enable-deb --disable-ulimits --prefix=/usr

  9. Two of the build steps exceed the build system's CPU time limit when running emulated. I used the prlimit command to manually remove the limits on the problem programs. If I was doing it again, I'd try using the following script to defeat the time limits.
    #! /bin/sh
    # find any Macaulay 2 process that's been running for more than 5 minutes, and unlimit its cpu time
    for pid in `ps -e -o pid,time,comm | grep -v '00:0[0-4]' | grep M2 | cut -d ' ' -f2`; do
        prlimit --pid $pid --cpu=unlimited

    Save this script as unlimiter, make it executable, and set cron to run it every five minutes:

    echo '0,5,10,15,20,25,30,35,40,45,50,55 * * * * $HOME/unlimiter' | crontab -	  

  10. make

  11. About 24 hours later, you should have your .deb packages.
Brent Baccala
August 22, 2016