As an application developer I want to spend my time on my macbook because it has (in my opinion) a preferable interface to any other development environment. As a hardware enthusiast and operating system hacker I want to remain in that environment, but often the tools required are not pre-configured or just simply not available on OS X. While customizing android on various boards, most recently the Wandboard, I’ve found some nice tricks and workarounds to get builds running in OS X.

Here I’m going to detail the modifications my environment needed to get a standard build completed for the Wandboard Quad (Rev. B1), however most of these steps apply to building android on other Freescale i.MX6 based devices as their android source trees are based on the Freescale release.

Set up a case sensitive file system

By default the filesystem in OS X is case-insensitive and thus poses problems for some case-sensitive portions of the build (the ext family of filesystems is case-sensitive). To get around this you could reformat your hard disk and reinstall OS X, but that would be a pain and theres a better option.

hdiutil is a utility that allows you to create and mount virtual file systems. Before you clone the android source, create a case sensitive filesystem and mount it.

# create the filesystem image
$ hdiutil create -type SPARSE -fs 'Case-sensitive Journaled HFS+' -size 60g -volname <name-of-volume> <path-to-filesystem-image>
# mount it, by default the mount point is /Volumes/<name-of-volume>
$ hdiutil attach <path-to-filesystem-image>

Install required packages

OS X is a unix-like operating system, however it has its own flavor. Mostly that flavor is BSD, with some proprietary Apple stuff thrown into the mix. This can cause some issues when building the Linux kernel because certain system utilities behave differently than expected, and Linux has no official OS X build support (that I know of at least…). To fix the issue we can use homebrew to install the coreutils package, which includes a collection of GNU utilities.

$ brew install coreutils

OS X also ships with a general incompatibility with the ext family of filesystems, as they are FUSE (Filesystem in USErspace) filesystems. To solve this problem, at least to a certain extent, we can install osxfuse and fuse-ext2. osxfuse is a FUSE kernel extension/library for OS X, and fuse-ext2 is a set of tools made to mimic the ext tools available on Linux systems. Refer to each projects documentation for installation and usage instructions.

Install repo, initialize the build directory, and pull down the source tree

The easiest way to install repo is using homebrew.

$ brew install repo


If you’ve built android before and know your way around repo and the build system, you can skip the next few sections and just initialize from a manifest I’ve created to support OS X builds.

$ repo init -u -b jb4.3_1.1.0-ga__wandboard_osx

The steps to build should be the same as any other AOSP build, but the deployment is a bit different. Skip down to Deploying to a microSD card for deployment instructions.

for those who want the whole scoop

Now from your case-sensitive build directory initialize repo against the Wandboard manifest.

$ repo init -u -b jb4.3_1.1.0-ga__wandboard

Here is where we make our first modification to something under source control. Note that changes to the source code will have to be pushed somewhere if you want to share them or store a backup. Any time you customize android you’re bound to end up with at minimum a handful of repositories to keep track of yourself.

We need to edit the manifest file located at .repo/manifests/wandboard-jb4.3.xml. (Note: All paths referenced will be relative to the root of the build directory) The reason we’re editing the manifest is to get a single manifest for our project. People will often initialize repo with one manifest, sync, and then replace the manifest and sync again to get their own modified source trees. Instead we’ll be very explicit that anything in this manifest that does not have the specified remote as ‘wandboard’ will default to being fetched from Googles public android source trees. The diff of the change is shown below.

diff --git a/wandboard-jb4.3.xml b/wandboard-jb4.3.xml
index 5972d9c..f722137 100644
--- a/wandboard-jb4.3.xml
+++ b/wandboard-jb4.3.xml
@@ -2,7 +2,7 @@
   <remote  name="aosp"
-           fetch=".." />
+           fetch="" />
   <default revision="refs/tags/android-4.3_r2.1"
            sync-j="4" />

With this change saved you can pull down the sources using repo sync -c -j8. The -c option only pulls down the git refs needed for branch you’re building on for each repo, making the sync faster. -jN is how you specify how many repos you want syncing concurrently.

Remove breaking packages we don’t need

OS X has no build support for the tools around ubifs. It sucks, but for now its the way things are. There is some consolation though… we don’t care about ubifs. We’re going to boot android from the main MMC 0 micro sd slot, and we’re going to use only FAT32 and ext4 filesystems. The first thing to do is remove the ubifs related packages from device/fsl/imx6/

diff --git a/imx6/ b/imx6/
index 044d019..46e2649 100644
--- a/imx6/
+++ b/imx6/
@@ -286,7 +286,7 @@ omx_excluded_libs :=                                        \
 PRODUCT_PACKAGES += $(omx_libs) $(omx_excluded_libs)
-PRODUCT_PACKAGES += libubi ubinize ubiformat ubiattach ubidetach ubiupdatevol ubimkvol ubinfo mkfs.ubifs
+# PRODUCT_PACKAGES += libubi ubinize ubiformat ubiattach ubidetach ubiupdatevol ubimkvol ubinfo mkfs.ubifs
 # FUSE based emulated sdcard daemon

The other edit we have to make to fully remove the ubifs stuff from the build is in another makefile. You only have to make this edit if you’re going to be running an engineering build, which if you’re hacking android it’s likely what you intend to do. Heres the diff of the other edit in external/mtd-utils/new-utils/

diff --git a/new-utils/ b/new-utils/
index 59b8286..88adb6f 100644
--- a/new-utils/
+++ b/new-utils/
@@ -19,7 +19,7 @@ LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
 LOCAL_MODULE := ubinize
+LOCAL_MODULE_TAGS := optional

Edit the build system

The section of the build system that generates u-boot and the linux kernel makes an assumption that you are compiling from a linux platform. We need to add some conditionals to make sure we’re selecting the darwin host toolchain. We also need to account for flags that are passed to the install command, as the BSD-based implementation native to OS X differs slightly from the GNU implementation that is standard on linux distributions.

The bootloader target

Checking to see which host we’re building from is easy using the uname command, which will return ‘Linux’ or ‘Darwin’. We then set the variables BOOTLOADER_CROSS_TOOLCHAIN and HOST_PROCESSOR accordingly. In the case of a linux build (if you’re trying not to break it…) you need to add an INSTALL_FLAGS variable and set it to -D which tells install to create directories if needed. The last step is to replace the existing flags being passed to install with the INSTALL_FLAGS variable.

The diff below shows the changes needed to complete the build, but it also includes a few changes I made as a preference. When my full build completes I want my bootloader, kernel, and other contents of the boot partition to be in a sub-directory of the PRODUCT_OUT path, namely out/target/product/wandboard/boot. Because of this I changed TARGET_BOOTLOADER_IMAGE to reflect the location I want. In the same vein I added a call to install to copy the SPL into our boot directory. Lastly I had to add a call to mkdir as the BSD-flavor install does not make directories for you.

diff --git a/core/Makefile b/core/Makefile
index 3ac2967..d98c20a 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -739,25 +739,35 @@ endif
 .PHONY: bootloader
 ifneq ($(strip $(TARGET_BOOTLOADER_CONFIG)),)
+ifeq ($(shell uname -s), Linux)
 BOOTLOADER_CROSS_TOOLCHAIN := `pwd`/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin/arm-eabi-
 HOST_PROCESSOR := $(shell cat /proc/cpuinfo | grep processor | wc -l)
+ifeq ($(shell uname -s), Darwin)
+BOOTLOADER_CROSS_TOOLCHAIN := `pwd`/prebuilts/gcc/darwin-x86/arm/arm-eabi-4.6/bin/arm-eabi-
+HOST_PROCESSOR := $(shell sysctl -n hw.ncpu)
 BOOTLOADER_PATH := bootable/bootloader/uboot-imx/
+       mkdir -p $(PRODUCT_OUT)/boot
        @for ubootplat in $(TARGET_BOOTLOADER_CONFIG); do \
                UBOOT_PLATFORM=`echo $$ubootplat | cut -d':' -f1`; \
                UBOOT_CONFIG=`echo $$ubootplat | cut -d':' -f2`; \
-               $(MAKE) -C bootable/bootloader/uboot-imx/ distclean $(BOOTLOADER_ENV); \
-               $(MAKE) -C bootable/bootloader/uboot-imx/ $$UBOOT_CONFIG $(BOOTLOADER_ENV); \
-               $(MAKE) -C bootable/bootloader/uboot-imx/ $(BOOTLOADER_ENV); \
-               install -D bootable/bootloader/uboot-imx/u-boot.bin $(PRODUCT_OUT)/u-boot-$$UBOOT_PLATFORM.bin; \
-               install -D bootable/bootloader/uboot-imx/u-boot.bin $@; \
+               $(MAKE) -C $(BOOTLOADER_PATH) distclean $(BOOTLOADER_ENV); \
+               $(MAKE) -C $(BOOTLOADER_PATH) $(BOOTLOADER_ENV); \
+               install $(INSTALL_FLAGS) $(BOOTLOADER_PATH)/u-boot.img $(TARGET_BOOTLOADER_IMAGE); \
+               install $(INSTALL_FLAGS) $(BOOTLOADER_PATH)/SPL $(PRODUCT_OUT)/boot/SPL; \

The kernelimage target

Here we want to make changes that are either analogous or identical to the ones we made for the bootloader target. The conditional statements that check uname and their contents are essentially the same, we just replace the variable name BOOTLOADER_CROSS_TOOLCHAIN with KERNEL_CROSS_TOOLCHAIN. The change for the install flags is also identical, and in the same way we updated the TARGET_BOOTLOADER_IMAGE variable we now update the TARGET_PREBUILT_KERNEL and INSTALLED_KERNEL_TARGET paths to represent the location in our new boot folder. In addition to those changes I have removed the regular kernel target, because I’m simply not using it. Our bootloader is set up to load and execute a uImage file, so I only want to copy that file into my boot directory.

The last and possibly most important change shown in the diff below prepends a location to our PATH when executing the command that will actually build our kernel. After some painful debugging it was made apparent that the BSD implementation of stat and the GNU implementation are not fully compatible, and GNU stat is needed to compile a working uImage. We don’t want to replace stat globally on our system for a variety of reasons, so the best solution is to shim in GNU stat only when generating the kernel. If you’ve installed the coreutils package with homebrew then you can prepend PATH with their location. In my case (as it should be for most cases) the utils are available by their proper names at /usr/local/opt/coreutils/libexec/gnubin relative to your system root. If you have an issue with this you can check their install location with brew info coreutils. Obligatory diff.

@@ -765,11 +775,21 @@ endif
 .PHONY: kernelimage
 ifneq ($(strip $(TARGET_NO_KERNEL)),true)
+ifeq ($(shell uname -s), Linux)
 KERNEL_CROSS_TOOLCHAIN := `pwd`/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin/arm-eabi-
 HOST_PROCESSOR := $(shell cat /proc/cpuinfo | grep processor | wc -l)
+ifeq ($(shell uname -s), Darwin)
+KERNEL_CROSS_TOOLCHAIN := `pwd`/prebuilts/gcc/darwin-x86/arm/arm-eabi-4.6/bin/arm-eabi-
+HOST_PROCESSOR := $(shell sysctl -n hw.ncpu)
 KERNEL_CONFIGURE := kernel_imx/.config
 KERNEL_ZIMAGE    := kernel_imx/arch/arm/boot/zImage
@@ -784,12 +804,11 @@ $(KERNEL_CONFIGURE): kernel_imx/arch/arm/configs/$(TARGET_KERNEL_DEFCONF)
        $(MAKE) -C kernel_imx $(TARGET_KERNEL_DEFCONF) $(KERNEL_ENV)
-       $(MAKE) -C kernel_imx -j$(HOST_PROCESSOR) uImage $(KERNEL_ENV)
-       install -D $(KERNEL_UIMAGE)  $(PRODUCT_OUT)/uImage
-       install -D $(KERNEL_ZIMAGE)  $(PRODUCT_OUT)/kernel
+       export PATH=/usr/local/opt/coreutils/libexec/gnubin:$$PATH ; $(MAKE) -C kernel_imx -j$(HOST_PROCESSOR) uImage $(KERNEL_ENV)
        $(MAKE) -C kernel_imx -j$(HOST_PROCESSOR) modules $(KERNEL_ENV)

There is one last change that needs to be made at this point to complete the build, and its in a different makefile found at build/target/board/ Since we changed our INSTALLED_KERNEL_TARGET to a different location, we have to update this secondary makefile to know where we’ve put the built kernel. Its a simple one line change, here’s the diff.

diff --git a/target/board/ b/target/board/
index 7d94ee0..805fdae 100644
--- a/target/board/
+++ b/target/board/
@@ -15,7 +15,7 @@ else
 ifneq ($(strip $(TARGET_NO_KERNEL)),true)

Copy files to the right place

The only thing left to deal with now is the placement of the u-boot environment file. The file generated by the u-boot build process is not actually suitable to boot android. To fix this problem I’ve simply added the environment file I want to the tree and inserted a rule into /Volumes/osxbuildtest/device/fsl/imx6/ to copy the file into its proper location during the build. I put the file at /Volumes/osxbuildtest/device/fsl/wandboard/boot/uEnv.txt as it is board specific. Below is the diff of the makefile as well as the contents of the environment file.

diff --git a/imx6/ b/imx6/
index f59f50d..560be28 100644
--- a/imx6/
+++ b/imx6/
@@ -66,3 +66,5 @@ PRODUCT_COPY_FILES += \
+    device/fsl/wandboard/boot/uEnv.txt:boot/uEnv.txt
# /Volumes/osxbuildtest/device/fsl/wandboard/boot/uEnv.txt
bootargs_base=console=ttymxc0,115200 androidboot.console=ttymxc0 androidboot.hardware=wandboard vmalloc=400M
video_mode=display0=dev=hdmi0,mode=1280x720@60,if=RGB24,bpp=32 fbmem=28M

Run the build

After the changes noted above the build should complete, however every system is different and you may still run into issues. The build also takes a long time to run, especially if you run it non-concurrently. The system I develop on, and successfully run this build on all the time, is a Macbook Pro Retina running OS X 10.9.2 (Mavericks). It has a quad-core 2.6 GHz i7 processor, 16 Gigabytes of RAM, and a solid state hard disk. Even with all that computing power, running concurrently with 10 jobs, the build will take between 45 and 75 minutes (depending on what else you’re doing on the machine). This may sound like a long time but in fact its extremely fast considering what’s being compiled, linked, copied, etc.

As an attempt at practicing good habits I redirect the output of the build to a log file so I can view it if something goes awry. The best way to do this is to pipe the build to the tee command. I also like to wrap the call to make with the time command so I can track how long each build takes me. The following is an example of the command to build the whole distribution, and track how long it takes, all while piping the output to a log file.

# execute this command from the root of the tree
time make -j10 2>&1 | tee descriptive_file_name.log

There are a few things to note about the command above. The first one is the -j10 flag. This tells make to run 10 jobs concurrently when building, which will speed things up considerably. Usually you want the number of jobs to be one more than the number of cores on your system. The i7 processor I have in my machine has some fancy functionality built in that essentially makes the four cores act like they’re 8 cores, so to calculate how many jobs to run on my system for optimal performance I did the regular calculation (4 cores + 1 = 5 jobs) and then doubled it. This obviously varies from system to system, as every processor is different. The key is to not get carried away and make this number too large, because then the system will spend more time switching process contexts than it will compiling code, making for longer compile times, which nobody wants.

The other important thing to note in the above command is the 2>&1 tacked on the end of the call to make. This is critical for the log file to be of any use in a crash. It’s redirecting STDERR to STDOUT, so the STDOUT of make contains both the STDOUT and STDERR streams. If you don’t do this, errors from make will be printed to your terminal (because stdout is directed there by default) but not copied into the log file by tee because its taking the stream piped to it from the STDOUT of make and writing it to the log file, nothing else.

Deploying to a microSD card

Now that the build will complete we need to deploy it to a microSD card so we can boot it. The scripts that are provided to do this do not function properly on OS X primarily because they rely on sfdisk, which is not readily available for the platform. We can do the same work with fdisk though, its just a little uglier. Because fdisk is not automatable like sfdisk, we have to use a trick of echoing commands into fdisk with a pipe.

Below is a script that I wrote to replace the scripts that are available for linux. It calculates the disk geometry, clears the partition table, rewrites it, generates the filesystems, burns the prebuilt filesystem images to the card, and then arranges the boot partition with our bootloader, bootloader environment, kernel, and ramdisk. This script must be run as root, from the root of your build directory, and you must specify the device node of the disk to be burned and the product to be deployed. Run it with no arguments to get usage information.

As an example, if the product was called wandboard (which it is by default) and the disk you want to burn to is /dev/disk1 (be careful, this is a destructive operation and will overwrite a disk, you’ve been warned!) then the following should burn the card properly.

# WARNING: Check to make sure /dev/disk1 is the one you actually want to burn. Data will be lost!
$ sudo device/fsl/wandboard/tools/mkcard /dev/rdisk1 wandboard

# A. Ross Cohen
# Android Deployment Script

error() {
    echo "!   $1"

unmount() {
    diskutil unmountDisk $disk >/dev/null

eject() {
    diskutil eject $disk

mb_to_sectors() {
    expr $1 \* $sectors_per_megabyte

calculate_geometry() {
    block_size=`diskutil info $disk | grep "Block Size" | grep -oE "\d+"`
    sectors_per_megabyte=`expr 1048576 / $block_size`
    sectors=`fdisk $disk | grep -oE 'geometry.*\[\d+' | grep -oE '\[\d+' | grep -oE '\d+'`
    megabytes=`expr $sectors / $sectors_per_megabyte`

calculate_partition_sizes() {
    # partition sizes, all but data are static
    data_mb=`expr $megabytes - $bootloader_mb - $boot_mb - $recovery_mb - $system_mb - $cache_mb - $vendor_mb - $misc_mb`
    bootloader_sectors=`mb_to_sectors $bootloader_mb`
    boot_sectors=`mb_to_sectors $boot_mb`
    recovery_sectors=`mb_to_sectors $recovery_mb`
    system_sectors=`mb_to_sectors $system_mb`
    cache_sectors=`mb_to_sectors $cache_mb`
    vendor_sectors=`mb_to_sectors $vendor_mb`
    misc_sectors=`mb_to_sectors $misc_mb`
    data_sectors=`mb_to_sectors $data_mb`
    mbr_one_sectors=`expr $sectors - $bootloader_sectors - $boot_sectors - $recovery_sectors - $data_sectors`

write_partion_scheme() {
    dd if=/dev/zero of=$disk bs=1m count=1
    echo erase;
    echo e 1;
        echo 0C;
        echo n;
        echo $bootloader_sectors;
        echo $boot_sectors;
    echo e 2;
        echo 83;
        echo n;
        echo $recovery_sectors;
    echo e 3;
        echo 05;
        echo n;
        echo $mbr_one_sectors;
    echo e 4;
        echo 83;
        echo n;
        echo $data_sectors
    echo w;
    echo select 3;
        echo y;
        echo erase;
        echo e 1;
            echo 83;
            echo n;
            echo $system_sectors
        echo e 2;
            echo 83;
            echo n;
            echo $cache_sectors
        echo e 3;
            echo 83;
            echo n;
            echo $vendor_sectors
        echo e 4;
            echo 83;
            echo n;
            echo $misc_sectors
        echo w;
        echo exit;
    echo exit;
    ) | fdisk -iey $disk

create_filesystems() {
    echo y | newfs_msdos -F 32 -v imx6 ${disk}s1 
    echo y | newfs_msdos -F 32 -v recovery ${disk}s2 
    echo y | fuse-ext2.mke2fs -T ext4 -L cache ${disk}s6 
    echo y | fuse-ext2.mke2fs -T ext4 -L vendor ${disk}s7 
    echo y | fuse-ext2.mke2fs -T ext4 -L misc ${disk}s8 

create_data_filesystem() {
    echo y | fuse-ext2.mke2fs -T ext4 -L data ${disk}s4 

burn_images() {
    dd if=${product_directory}/boot/SPL of=$disk bs=1k seek=1 
    dd if=${product_directory}/system.img of=${disk}s5 bs=1m 

arrange_boot() {
    diskutil mount -mountPoint /Volumes/imx6 ${disk}s1
    if [ $? ] ; then
        mkdir -p /Volumes/imx6/boot
        cp ${product_directory}/boot/uImage /Volumes/imx6/boot
        cp ${product_directory}/boot/u-boot.img /Volumes/imx6/boot
        cp ${product_directory}/boot/uEnv.txt /Volumes/imx6/boot
        mkimage -A arm -O linux -T ramdisk -C none -a 0x10800800 -n "Android Root Filesystem" -d ${product_directory}/ramdisk.img /Volumes/imx6/boot/uramdisk.img  
        echo "Mount Failed, exiting."

# make sure we have the minimum arguments, if not complain...
if [ "$(id -u)" != "0" ]; then
    error "You must sudo to run this command."
elif [ $# -lt 2 ] ; then
    error "Insufficient Parameters"
    error "Usage: $0 /dev/(r)diskN product"


# make sure the disk exists
if ! [ -e $disk ] ; then
    error "Disk $disk does not exist. Aborting."

# make sure the product exists
if ! [ -f $product_directory/boot/u-boot.img ] ; then
    error "$product_directory/boot/u-boot.img does not exist. Aborting."
elif ! [ -f $product_directory/boot/uImage ] ; then
    error "$product_directory/boot/uImage does not exist. Aborting."
elif ! [ -f $product_directory/system.img ] ; then
    error "$product_directory/system.img does not exist. Aborting."


echo "--------------------"
echo "      disk: $disk"
echo "   product: $product"
echo "--------------------"
echo "block size: $block_size bytes"
echo "   sectors: $sectors"
echo "total size: $megabytes megabytes"
echo "--------------------"
printf "%-10s -> sectors: %-10d megabytes: %-10d\n" bootloader $bootloader_sectors $bootloader_mb
printf "%-10s -> sectors: %-10d megabytes: %-10d\n" boot $boot_sectors $boot_mb
printf "%-10s -> sectors: %-10d megabytes: %-10d\n" recovery $recovery_sectors $recovery_mb
printf "%-10s -> sectors: %-10d megabytes: %-10d\n" data $data_sectors $data_mb
printf "%-10s -> sectors: %-10d megabytes: %-10d\n" system $system_sectors $system_mb
printf "%-10s -> sectors: %-10d megabytes: %-10d\n" cache $cache_sectors $cache_mb
printf "%-10s -> sectors: %-10d megabytes: %-10d\n" vendor $vendor_sectors $vendor_mb
printf "%-10s -> sectors: %-10d megabytes: %-10d\n" misc $misc_sectors $misc_mb
echo "--------------------"
echo "writing partition scheme"
echo "--------------------"
echo "creating filesystems"
echo "--------------------"
echo "burning images"
echo "--------------------"
echo "arranging boot"
echo "--------------------"
echo "creating data filesystem"
echo "--------------------"
echo "ejecting the disk"
echo "--------------------"
echo "done. you may now remove the disk."

To sum it all up

Generally speaking android can be built using OS X and AOSP does support it. Freescale, and thus Wandboard, do not explicitly support building on OS X but it was not all that complicated to implement. All of the solutions listed in this post were discovered with a little stubborn tinkering and some general knowledge of Unix build tools and the discrepancies with their BSD counterparts. You don’t need to change your entire environment just to cross-compile and deploy Linux based operating systems, you just need a little know-how and the willingness to adjust to the requirements.