Bluish Coder

Programming Languages, Martials Arts and Computers. The Weblog of Chris Double.


Cross Compiling ATS Programs

A few years ago I wrote a mailing list post on cross compiling ATS to Android. With ATS2 being released the ability to cross compile has been made easier. In this post I'll show how to produce static linux binaries using musl libc and how to build Android and Windows ATS programs by cross compiling on linux.

For these examples I'm using ATS2-0.3.8. I'll use the simplest of 'Hello World' programs in ATS to cross compile. The following is the contents of hello.dats:

implement main0() = print!("Hello World\n")

To compile:

$ cat hello.dats
implement main0() = print!("Hello World\n")

$ patscc -o hello hello.dats
$ ./hello
Hello World

Static musl libc binaries

musl libc is a lightweight standard library for C programs. I use this instead of glibc because statically linked binaries using glibc have issues using networking functionality. There are no problems using networking routines with musl libc, it's smaller and lightweight and works well statically linked into executables. To build musl libc I used these steps:

$ git clone git://
$ cd musl
$ ./configure
$ make
$ sudo make install
$ export PATH=$PATH:/usr/local/musl/bin/

The ATS compiler, patscc, compiles ATS code to C. It defaults to using gcc but takes an atsccomp command line argument to define an alternative C compiler to use for compiling the generated C code. Unknown command line arguments are passed directly to that C compiler. Given musl libc installed in /usr/local/musl as above, a static binary can be built with musl-gcc like so:

$ patscc -o hello -atsccomp "/usr/local/musl/bin/musl-gcc" -static \
         -I $PATSHOME/ccomp/runtime -I $PATSHOME \

I pass the -static flag to produce a statically linked binary and two -I include paths to find the ATS runtime. These appear to be required if -atsccomp is used. In this case I use the environment variable PATSHOME to find the installation directory of ATS. Hopefully that was set at ATS installation time. If this command succeeded then we have a static binary:

$ ./hello
Hello World
$ ldd hello
not a dynamic executable
$ strip hello && ls -l hello
-rwxr-xr-x 1 myuser myuser 18224 Dec  2 23:21 hello
$ file hello
hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, stripped

Cross compiling Windows binaries

To build Windows compatible binaries on Linux I used mingw-w64. On Ubuntu this is available in the gcc-mingw-w64 package. With that installed a Windows hello binary can be built with:

 $ patscc -o hello.exe -atsccomp "i686-w64-mingw-gcc" \
         -I $PATSHOME/ccomp/runtime -I $PATSHOME \
 $ file hello.exe
 hello.exe: PE32 executable (console) Intel 80386, for MS Windows

Copying to a Windows machine:

C:\Users\Myuser> .\hello
Hello World

Cross compiling Android binaries

To build on Android I generated a standalone toolchain using the Android NDK. This produces standard command line compilers that generate Android compatible binaries. Install the Android NDK - I used android-ndk-r16 - and run:

$ANDROID_NDK/build/tools/ \
  --arch=arm --install-dir=$STK_ROOT

Replace ANDROID_NDK with the path to the Android NDK and STK_ROOT with the destination where you want the standalone toolchain installed. Use arm64 instead of arm to build an ARM 64-bit binary.

Now the "Hello World" program can be built using the C compiler from the standalone toolchain. To build on 32-bit using an arm standalone toolchain, use arm-linux-androideabi-clang as the C compiler:

 $ patscc -o hello -atsccomp $STK_ROOT/bin/arm-linux-androideabi-clang \
         -I $PATSHOME/ccomp/runtime -I $PATSHOME \
 $ file hello
 hello: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV),
        dynamically linked, interpreter /system/bin/linker, not stripped

To build on 64-bit ARM using an arm64 standalone toolchain, use aarch64-linux-android-clang as the compiler:

 $ patscc -o hello -atsccomp $STK_ROOT/bin/aarch64-linux-android-clang \
         -I $PATSHOME/ccomp/runtime -I $PATSHOME \
 $ file hello
 hello64: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV),
          dynamically linked, interpreter /system/bin/linker64, not stripped

Notice the use of clang instead of gcc. I believe gcc support for building native Android executables with the NDK is deprecated - I got link errors when I tried.

Copy the hello executable to an Android phone. It needs to be somewhere writeable on the phone. On a recent non-rooted phone you should be able to use /data/local/tmp. The following adb commands work for me when the device is connected:

$ adb push hello /data/local/tmp
$ adb shell
$ cd /data/local/tmp
$ chmod 0755 hello
$ ./hello
Hello World

Producing an actual Android application would require using the ATS FFI to interface with the Android runtime - given the low level nature of ATS, if it can be done in C, it should be able to be done in ATS.


This site is accessable over tor as hidden service mh7mkfvezts5j6yu.onion, or Freenet using key: