├── .gitignore ├── opam ├── patches └── memory.txt ├── config ├── m.h ├── s.h └── Makefile ├── Makefile.config ├── README.md └── Makefile /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | ocaml-src 3 | stamp-* 4 | no-man 5 | -------------------------------------------------------------------------------- /opam: -------------------------------------------------------------------------------- 1 | opam-version: "1" 2 | maintainer: "jerome.vouillon@pps.univ-paris-diderot.fr" 3 | build: [[ 4 | "make" "ANDROID_NDK=%{lib}%/android-ndk" "OCAML_SRC=%{lib}%/ocaml-src" 5 | "ANDROID_PREFIX=%{prefix}%/arm-linux-androideabi" 6 | "ANDROID_BINDIR=%{bin}%" 7 | ]] 8 | remove: [[ "./remove.sh" "%{prefix}%" ]] 9 | depends: 10 | ["ocaml-src" {= "4.01.0"} ("android-ndk-linux" | "android-ndk-darwin")] 11 | -------------------------------------------------------------------------------- /patches/memory.txt: -------------------------------------------------------------------------------- 1 | --- byterun/misc.h~ 2 | +++ byterun/misc.h 3 | @@ -26,7 +26,14 @@ 4 | /* Standard definitions */ 5 | 6 | #include 7 | +#if defined(__ANDROID__) && !defined(CAML_MEMORY_H) 8 | +/* Work-around a name clash with system header files */ 9 | +#define CAML_MEMORY_H 10 | #include 11 | +#undef CAML_MEMORY_H 12 | +#else 13 | +#include 14 | +#endif 15 | 16 | /* Basic types and constants */ 17 | 18 | -------------------------------------------------------------------------------- /config/m.h: -------------------------------------------------------------------------------- 1 | #undef ARCH_SIXTYFOUR 2 | #define SIZEOF_INT 4 3 | #define SIZEOF_LONG 4 4 | #define SIZEOF_PTR 4 5 | #define SIZEOF_SHORT 2 6 | #undef ARCH_BIG_ENDIAN 7 | #define ARCH_ALIGN_DOUBLE 8 | #define ARCH_ALIGN_INT64 9 | #undef NONSTANDARD_DIV_MOD 10 | #define ASM_CFI_SUPPORTED 11 | /* New to OCaml 4.02 */ 12 | #define SIZEOF_LONGLONG 8 13 | /* No longer used in OCaml 4.02 */ 14 | #define ARCH_INT64_TYPE long long 15 | #define ARCH_UINT64_TYPE unsigned long long 16 | #define ARCH_INT64_PRINTF_FORMAT "ll" 17 | -------------------------------------------------------------------------------- /Makefile.config: -------------------------------------------------------------------------------- 1 | # Target ABI should be one of: armeabi, armeabi-v7a, x86 2 | # mips ABI is not supported (no native compiler) 3 | ABI = armeabi-v7a 4 | 5 | # Which Android platform to use 6 | ANDROID_PLATFORM = android-14 7 | 8 | # Path of the Android NDK 9 | ANDROID_NDK = ${OPAM_PREFIX}/lib/android-ndk 10 | 11 | # OCaml sources (will be copied) 12 | OCAML_SRC = ${OPAM_PREFIX}/lib/ocaml-src 13 | 14 | # Where the cross-compiler libraries are installed 15 | ANDROID_PREFIX = ${OPAM_PREFIX}/$(HOST_ARCH) 16 | 17 | # Where the cross-compiler binaries are installed 18 | ANDROID_BINDIR = ${OPAM_PREFIX}/bin 19 | 20 | OPAM_PREFIX := $(shell opam config var prefix) 21 | -------------------------------------------------------------------------------- /config/s.h: -------------------------------------------------------------------------------- 1 | #define OCAML_OS_TYPE "Unix" 2 | #define OCAML_STDLIB_DIR "." 3 | #define POSIX_SIGNALS 4 | #define HAS_C99_FLOAT_OPS 5 | #define HAS_GETRUSAGE 6 | #define HAS_TIMES 7 | #define HAS_SOCKETS 8 | #define HAS_SOCKLEN_T 9 | #define HAS_INET_ATON 10 | #define HAS_IPV6 11 | #define HAS_UNISTD 12 | #define HAS_OFF_T 13 | #define HAS_DIRENT 14 | #define HAS_REWINDDIR 15 | #define HAS_LOCKF 16 | #define HAS_MKFIFO 17 | #define HAS_GETCWD 18 | #define HAS_GETWD 19 | #define HAS_GETPRIORITY 20 | #define HAS_UTIME 21 | #define HAS_UTIMES 22 | #define HAS_DUP2 23 | #define HAS_FCHMOD 24 | #define HAS_TRUNCATE 25 | #define HAS_SYS_SELECT_H 26 | #define HAS_SELECT 27 | #define HAS_SYMLINK 28 | #define HAS_WAITPID 29 | #define HAS_WAIT4 30 | #define HAS_GETGROUPS 31 | #define HAS_SETGROUPS 32 | #define HAS_INITGROUPS 33 | #define HAS_TERMIOS 34 | #define HAS_ASYNC_IO 35 | #define HAS_SETITIMER 36 | #define HAS_GETHOSTNAME 37 | #define HAS_UNAME 38 | #define HAS_GETTIMEOFDAY 39 | #define HAS_MKTIME 40 | #define HAS_SETSID 41 | #define HAS_PUTENV 42 | #define HAS_LOCALE 43 | #define SUPPORT_DYNAMIC_LINKING 44 | #define HAS_MMAP 45 | #define HAS_PWRITE 46 | #define HAS_GETHOSTBYNAME_R 6 47 | /* New to OCaml 4.02 */ 48 | #define HAS_MKSTEMP 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ocaml-android 2 | ============= 3 | 4 | Ocaml cross-compiler for Android. 5 | 6 | On a 64bit Debian or Ubuntu installation, you need to install package 7 | `gcc-multilib`: we have to build 32 bit OCaml binaries when targeting 8 | 32 bit architectures. 9 | 10 | Follow the following steps to compile: 11 | - download the Android NDK and the OCaml source code; 12 | - edit `Makefile.config`; 13 | - run `make`. 14 | 15 | For convenience, binaries (`ocamlc`, `ocamlopt`, ...) are put both in 16 | `$ANDROID_BINDIR` 17 | prefixed by `arm-linux-androideabi-`, and in 18 | `$ANDROID_BINDIR/arm-linux-androideabi` 19 | unprefixed. 20 | The Android OCaml runtime `ocamlrun` is in directory 21 | `$ANDROID_PREFIX/bin/`. 22 | 23 | There are a few pitfalls regarding bytecode programs. First, if you 24 | link them without the `-custom` directive, you will need to use 25 | `ocamlrun` explicitly to run them. Second, the `ocamlmklib` command 26 | produces shared libraries `dll*.so` which are not usable. Thus, you 27 | need to use the `-custom` directive to successfully link bytecode 28 | programs that uses libraries with mixed C / OCaml code. Shared 29 | libraries should eventually be disabled, but at the moment, the 30 | `ocamlbuild` plugin of `oasis` requires them to be created. 31 | 32 | Many thanks to Keigo Imai for his OCaml 3.12 cross-compiler patches. 33 | -------------------------------------------------------------------------------- /config/Makefile: -------------------------------------------------------------------------------- 1 | PREFIX=ANDROID_PREFIX 2 | BINDIR=ANDROID_BINDIR/HOST_ARCH 3 | LIBDIR=$(PREFIX)/lib/ocaml 4 | STUBLIBDIR=$(LIBDIR)/stublibs 5 | MANDIR=OCAML_SRC/no-man 6 | MANEXT=1 7 | SYSROOT=ANDROID_NDK/platforms/ANDROID_PLATFORM/arch-ANDROID_ARCH 8 | RANLIB=ANDROID_PATH/HOST_ARCH-ranlib 9 | RANLIBCMD=ANDROID_PATH/HOST_ARCH-ranlib 10 | ARCMD=ANDROID_PATH/HOST_ARCH-ar 11 | SHARPBANGSCRIPTS=true 12 | BNG_ARCH=generic 13 | BNG_ASM_LEVEL=0 14 | PTHREAD_LINK= 15 | X11_INCLUDES=not found 16 | X11_LINK=not found 17 | LIBBFD_LINK=ANDROID_LDFLAGS 18 | BYTECC=ANDROID_PATH/HOST_ARCH-gcc --sysroot $(SYSROOT) -I $(PREFIX)/include -L $(PREFIX)/lib -O2 19 | BYTECCCOMPOPTS=-fno-defer-pop -Wall -D_FILE_OFFSET_BITS=64 ANDROID_CFLAGS 20 | BYTECCLINKOPTS=-Wl,-E ANDROID_LDFLAGS 21 | BYTECCLIBS=ANDROID_MATHLIB -ldl 22 | BYTECCRPATH=-Wl,-rpath, 23 | EXE= 24 | SUPPORTS_SHARED_LIBRARIES=true 25 | SHAREDCCCOMPOPTS=-fPIC 26 | MKSHAREDLIBRPATH=-Wl,-rpath, 27 | NATDYNLINKOPTS=-Wl,-E 28 | SYSLIB=-l$(1) 29 | #ml let syslib x = "-l"^x;; 30 | 31 | ### How to build a static library 32 | MKLIB=ANDROID_PATH/HOST_ARCH-ar rc $(1) $(2); ANDROID_PATH/HOST_ARCH-ranlib $(1) 33 | #ml let mklib out files opts = Printf.sprintf "ANDROID_PATH/HOST_ARCH-ar rc %s %s %s; ANDROID_PATH/HOST_ARCH-ranlib %s" out opts files out;; 34 | ARCH=ANDROID_OCAML_ARCH 35 | MODEL=ANDROID_MODEL 36 | SYSTEM=ANDROID_SYSTEM 37 | NATIVECC=$(BYTECC) 38 | NATIVECCCOMPOPTS=-Wall -D_FILE_OFFSET_BITS=64 ANDROID_CFLAGS 39 | NATIVECCPROFOPTS=$(NATIVECCCOMPOPTS) 40 | NATIVECCLINKOPTS=ANDROID_LDFLAGS 41 | NATIVECCRPATH=-Wl,-rpath, 42 | NATIVECCLIBS=ANDROID_MATHLIB -ldl 43 | ASM=ANDROID_PATH/HOST_ARCH-as 44 | ASPP=$(BYTECC) -c 45 | ASPPPROFFLAGS=-DPROFILING 46 | PROFILING=prof 47 | DYNLINKOPTS= -ldl 48 | OTHERLIBRARIES=unix str num dynlink bigarray threads 49 | CC_PROFILE=-pg 50 | SYSTHREAD_SUPPORT=false 51 | PARTIALLD=ANDROID_PATH/HOST_ARCH-ld -r 52 | PACKLD=$(PARTIALLD) $(NATIVECCLINKOPTS) -o\ 53 | DLLCCCOMPOPTS= 54 | IFLEXDIR= 55 | O=o 56 | A=a 57 | SO=so 58 | EXT_OBJ=.o 59 | EXT_ASM=.s 60 | EXT_LIB=.a 61 | EXT_DLL=.so 62 | EXTRALIBS= 63 | CCOMPTYPE=cc 64 | TOOLCHAIN=cc 65 | NATDYNLINK=false 66 | CMXS=cmxa 67 | MKEXE=$(BYTECC) ANDROID_LDFLAGS 68 | MKEXEDEBUGFLAG=-g 69 | MKDLL=$(BYTECC) -shared ANDROID_LDFLAGS 70 | MKMAINDLL=$(MKDLL) 71 | RUNTIMED=noruntimed 72 | ASM_CFI_SUPPORTED=false 73 | WITH_FRAME_POINTERS=false 74 | # New to OCaml 4.02 75 | UNIX_OR_WIN32=unix 76 | UNIXLIB=unix 77 | GRAPHLIB= 78 | WITH_DEBUGGER= 79 | WITH_OCAMLDOC= 80 | WITH_OCAMLBUILD= 81 | TARGET=HOST_ARCH 82 | HOST=HOST_ARCH 83 | # No longer used in OCaml 4.02 84 | TK_DEFS= 85 | TK_LINK= 86 | DEBUGGER=ocamldebugger 87 | CAMLP4= 88 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | include Makefile.config 3 | 4 | TOOLCHAIN = $(HOST_ARCH)-4.8 5 | ANDROID_OCAML_ARCH = $(ANDROID_ARCH) 6 | ifeq ($(ABI),armeabi-v7a) 7 | HOST_ARCH = arm-linux-androideabi 8 | ANDROID_ARCH = arm 9 | ANDROID_MODEL = armv7 10 | ANDROID_SYSTEM = linux_eabihf 11 | else ifeq ($(ABI),armeabi) 12 | HOST_ARCH = arm-linux-androideabi 13 | ANDROID_ARCH = arm 14 | ANDROID_MODEL = armv5te 15 | ANDROID_SYSTEM = linux_eabi 16 | else ifeq ($(ABI),x86) 17 | HOST_ARCH = i686-linux-android 18 | TOOLCHAIN = x86-4.8 19 | ANDROID_ARCH = x86 20 | ANDROID_OCAML_ARCH = i386 21 | ANDROID_MODEL = default 22 | ANDROID_SYSTEM = linux_elf 23 | else 24 | $(error Unknown ABI $(ABI)) 25 | endif 26 | 27 | ifeq ($(ABI),armeabi-v7a) 28 | ANDROID_CFLAGS = -march=armv7-a -mfpu=vfpv3-d16 -mhard-float \ 29 | -D_NDK_MATH_NO_SOFTFP=1 30 | ANDROID_LDFLAGS = -march=armv7-a -Wl,--fix-cortex-a8 -Wl,--no-warn-mismatch 31 | ANDROID_MATHLIB = -lm_hard 32 | else 33 | ANDROID_CFLAGS = 34 | ANDROID_LDFLAGS = 35 | ANDROID_MATHLIB = -lm 36 | endif 37 | 38 | SRC = ocaml-src 39 | 40 | ARCH=$(shell uname | tr A-Z a-z) 41 | ANDROID_PATH = $(ANDROID_NDK)/toolchains/$(TOOLCHAIN)/prebuilt/$(ARCH)-x86/bin 42 | 43 | CORE_OTHER_LIBS = unix str num dynlink 44 | STDLIB=$(shell $(ANDROID_BINDIR)/ocamlc -config | \ 45 | sed -n 's/standard_library: \(.*\)/\1/p') 46 | 47 | all: stamp-install 48 | 49 | stamp-install: stamp-build 50 | # Install the compiler 51 | cd $(SRC) && make install 52 | # Put links to binaries in $ANDROID_BINDIR 53 | rm -f $(ANDROID_BINDIR)/$(HOST_ARCH)/ocamlbuild 54 | rm -f $(ANDROID_BINDIR)/$(HOST_ARCH)/ocamlbuild.byte 55 | for i in $(ANDROID_BINDIR)/$(HOST_ARCH)/*; do \ 56 | ln -sf $$i $(ANDROID_BINDIR)/$(HOST_ARCH)-`basename $$i`; \ 57 | done 58 | # Install the Android ocamlrun binary 59 | mkdir -p $(ANDROID_PREFIX)/bin 60 | cd $(SRC) && \ 61 | cp byterun/ocamlrun.target $(ANDROID_PREFIX)/bin/ocamlrun 62 | # Add a link to camlp4 libraries 63 | rm -rf $(ANDROID_PREFIX)/lib/ocaml/camlp4 64 | ln -sf $(STDLIB)/camlp4 $(ANDROID_PREFIX)/lib/ocaml/camlp4 65 | touch stamp-install 66 | 67 | stamp-build: stamp-runtime 68 | # Restore the ocamlrun binary for the local machine 69 | cd $(SRC) && cp byterun/ocamlrun.local byterun/ocamlrun 70 | # Compile the libraries for Android 71 | cd $(SRC) && make coreall opt-core otherlibraries otherlibrariesopt 72 | cd $(SRC) && make ocamltoolsopt 73 | touch stamp-build 74 | 75 | stamp-runtime: stamp-prepare 76 | # Recompile the runtime for Android 77 | cd $(SRC) && make -C byterun all 78 | # Save the ARM ocamlrun binary 79 | cd $(SRC) && cp byterun/ocamlrun byterun/ocamlrun.target 80 | touch stamp-runtime 81 | 82 | stamp-prepare: stamp-core 83 | # Update configuration files 84 | set -e; cd config; for f in *; do \ 85 | sed -e 's%ANDROID_NDK%$(ANDROID_NDK)%' \ 86 | -e 's%ANDROID_PATH%$(ANDROID_PATH)%g' \ 87 | -e 's%ANDROID_PREFIX%$(ANDROID_PREFIX)%g' \ 88 | -e 's%ANDROID_BINDIR%$(ANDROID_BINDIR)%g' \ 89 | -e 's%OCAML_SRC%$(OCAML_SRC)%g' \ 90 | -e 's%HOST_ARCH%$(HOST_ARCH)%g' \ 91 | -e 's%ANDROID_CFLAGS%$(ANDROID_CFLAGS)%g' \ 92 | -e 's%ANDROID_LDFLAGS%$(ANDROID_LDFLAGS)%g' \ 93 | -e 's%ANDROID_MATHLIB%$(ANDROID_MATHLIB)%g' \ 94 | -e 's%ANDROID_ARCH%$(ANDROID_ARCH)%g' \ 95 | -e 's%ANDROID_OCAML_ARCH%$(ANDROID_OCAML_ARCH)%g' \ 96 | -e 's%ANDROID_MODEL%$(ANDROID_MODEL)%g' \ 97 | -e 's%ANDROID_SYSTEM%$(ANDROID_SYSTEM)%g' \ 98 | -e 's%ANDROID_PLATFORM%$(ANDROID_PLATFORM)%g' \ 99 | $$f > ../$(SRC)/config/$$f; \ 100 | done 101 | # Apply patches 102 | set -e; for p in patches/*.txt; do \ 103 | (cd $(SRC) && patch -p 0 < ../$$p); \ 104 | done 105 | # Save the ocamlrun binary for the local machine 106 | cd $(SRC) && cp byterun/ocamlrun byterun/ocamlrun.local 107 | # Clean-up runtime and libraries 108 | cd $(SRC) && make -C byterun clean 109 | cd $(SRC) && make -C stdlib clean 110 | set -e; cd $(SRC) && \ 111 | for i in $(CORE_OTHER_LIBS); do \ 112 | make -C otherlibs/$$i clean; \ 113 | done 114 | touch stamp-prepare 115 | 116 | stamp-core: stamp-configure 117 | # Build the bytecode compiler and other core tools 118 | cd $(SRC) && \ 119 | make OTHERLIBRARIES="$(CORE_OTHER_LIBS)" BNG_ASM_LEVEL=0 world 120 | touch stamp-core 121 | 122 | stamp-configure: stamp-copy 123 | # Configuration... 124 | cd $(SRC) && \ 125 | ./configure -prefix $(ANDROID_PREFIX) \ 126 | -bindir $(ANDROID_BINDIR)/$(HOST_ARCH) \ 127 | -mandir $(shell pwd)/no-man \ 128 | -cc "gcc -m32" -as "gcc -m32 -c" -aspp "gcc -m32 -c" \ 129 | -no-pthread 130 | sed -i s/CAMLP4=camlp4/CAMLP4=/ $(SRC)/config/Makefile 131 | touch stamp-configure 132 | 133 | stamp-copy: 134 | # Copy the source code 135 | @if ! [ -d $(OCAML_SRC)/byterun ]; then \ 136 | echo Error: OCaml sources not found. Check OCAML_SRC variable.; \ 137 | exit 1; \ 138 | fi 139 | @if ! [ -d $(ANDROID_PATH) ]; then \ 140 | echo Error: Android NDK not found. Check ANDROID_NDK variable.; \ 141 | exit 1; \ 142 | fi 143 | @if ! [ -f $(ANDROID_BINDIR)/ocamlc ]; then \ 144 | echo Error: $(ANDROID_BINDIR)/ocamlc not found. \ 145 | Check ANDROID_BINDIR variable.; \ 146 | exit 1; \ 147 | fi 148 | cp -a $(OCAML_SRC) $(SRC) 149 | touch stamp-copy 150 | 151 | clean: 152 | rm -rf $(SRC) stamp-* 153 | --------------------------------------------------------------------------------