building Linux kernel on Mac OS X

41,715

Solution 1

First, I agree that it's usually simpler to just use a Linux VM. That said, if you really want to do this, I have successfully compiled Linux kernel code using the procedure below.

Before you can even start, you may need to install the Linux source tree on a case-sensitive filesystem on your Mac. (the default HFS filesystem is case insensitive.) I won't cover that here, but a lot of people do this to compile the Android source tree, so you can use Google to find instructions.

First you'll need the following files to cross-compile a kernel on an OS X box (copy them from your known-working Linux VM to your local /usr/include):

/usr/include/elf.h
/usr/include/features.h
/usr/include/bits/predefs.h
/usr/include/bits/wordsize.h
/usr/include/gnu/stubs.h
/usr/include/gnu/stubs-64.h

Next you'll need malloc.h to be in the expected location for a Linux system, so do:

sudo ln -s /usr/include/malloc/malloc.h /usr/include/malloc.h

Finally, you'll need to worry about whether or not the compiler installed on your system is suitable for building the Linux kernel. I have used this procedure for kernels compiled for Android, using an appropriate cross-compiler toolchain, but I'm not sure if you can successfully compile a Linux kernel with the default gcc compiler on OS X (assuming you have the one that comes with Xcode...)


EDIT: You may also want to follow the steps pointed out in the bug linked in the comment above from "nmagerko", to ensure you have the correct dependencies, and the GNU version of sed. In particular:

$ sudo port install libelf
$ sudo port install gsed

Solution 2

This is a common question (well, usually it's building on Windows, but the answer is the same).

Just don't do it. You're going to have so much trouble getting anything to build correctly, it's just not worth it. Use a virtual machine, as you said yourself. It's a little slower, but not all that much, and at least building will work correctly.

Kernel development is hard enough without introducing additional, unnecessary problems.

Solution 3

Compile Kernel using AOSP's prebuilts

I've made symlinks to the missing OSX headers from the linux host ones and apparently it worked out well! In my setup I have sync'd the whole AOSP repo, which includes all prebuilts, but the ones that I am actually using to built the kernel are:

Clone them so that the following directory tree is valid:

<SOME-PATH>/prebuilts/
<SOME-PATH>/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.11-4.8/
<SOME-PATH>/prebuilts/gcc/darwin-x86/arm/arm-eabi-4.8/

Make sure you checkout the appropriate branch/tag, according to your Android target version.

Install the missing headers

Not sure if it's the proper way to do it, but putting the a bunch of linux headers in /usr/local/include resolves all issues. Don't forget to chmod +x the script.

install_headers.sh:

#!/bin/sh

PREBUILTS_DIR="<SOME-PATH>/prebuilts" # fill in the path here!

PREBUILT_GCC=$PREBUILTS_DIR"/gcc/linux-x86/host/x86_64-linux-glibc2.11-4.8"
KERNEL_HEADERS=$PREBUILT_GCC"/sysroot/usr/include"
HOST_HEADERS="/usr/local/include"

function install_header() {
    header=$1
    ln -s $KERNEL_HEADERS/$header $HOST_HEADERS/$header
}

# create symlinks for the missing headers
install_header elf.h
install_header features.h
# the following are folders (that contain headers)
install_header bits
install_header gnu
install_header linux
install_header asm
install_header asm-generic

Build the kernel

export PATH=<SOME-PATH>/prebuilts/gcc/darwin-x86/arm/arm-eabi-4.8/bin:$PATH
export ARCH=arm
export SUBARCH=arm
export CROSS_COMPILE=arm-eabi-
# in this example it builds for N6
make shamu_defconfig
make -j8

Voila:

Kernel: arch/arm/boot/zImage-dtb is ready

My configuration

  • macOS Sierra 10.12.3
  • XCode: using MacOSX10.11.sdk, which allows building AOSP on mac
  • Target device: N6/shamu
  • AOSP branch: Marshmallow (updated mac_version.mk in build to allow using 10.12.3 sdk)

Solution 4

Here is an update for Android 6.0 Marshmallow and OSX 10.10 Yosemite. I have done several successful cross builds using this method. The only limitation is that I have only done these with the full AOSP source checked out.

I used brew's libelf to get a nice package managed elf library. This gets us the elf file we need to include, usr/local/opt/libelf/include/libelf/gelf.h

brew install libelf

But this will still throw errors on build if you symlink it to usr/local/include as apparently some definitions are missing. So I stole the missing definitions from <kernel_source>/arch/arm/include/asm/elf.h and created a shim include file:

cat <<EOT >> /usr/local/include/elf.h
#include "../opt/libelf/include/libelf/gelf.h"
#define R_386_NONE 0
#define R_386_32 1
#define R_386_PC32 2
#define R_ARM_NONE 0
#define R_ARM_PC24 1
#define R_ARM_ABS32 2
#define R_MIPS_NONE 0
#define R_MIPS_16 1
#define R_MIPS_32 2
#define R_MIPS_REL32 3
#define R_MIPS_26 4
#define R_MIPS_HI16 5
#define R_MIPS_LO16 6
#define R_IA64_IMM64 0x23 /* symbol + addend, mov imm64 */
#define R_PPC_ADDR32 1 /* 32bit absolute address */
#define R_PPC64_ADDR64 38 /* doubleword64 S + A */
#define R_SH_DIR32 1
#define R_SPARC_64 32 /* Direct 64 bit */
#define R_X86_64_64 1 /* Direct 64 bit */
#define R_390_32 4 /* Direct 32 bit. */
#define R_390_64 22 /* Direct 64 bit. */
#define R_MIPS_64 18
EOT

That should be enough to get the build to complete. If anyone needs further information on this, I have a post that covers a full Android kernel build on OSX.

Solution 5

This works as of kitkat (didn't try earlier versions) - make -j8 ARCH=arm CROSS_COMPILE=arm-eabi- HOSTCFLAGS="-I ../external/elfutils/libelf"

This assumes the rest of the android build is set up as usual and the kernel directory is in the android build.

Share:
41,715

Related videos on Youtube

Alfred Zhong
Author by

Alfred Zhong

Updated on May 10, 2020

Comments

  • Alfred Zhong
    Alfred Zhong about 4 years

    I am doing a project to modify the Linux kernel. I have a desktop Linux machine and I have no problem building kernel on it.

    However, I am going on a trip and I want to work on my way. I only have a MacBook. When I tried to build the Linux kernel, it complained that elf.h was not found.

    I download an elf.h from internet. Now it complains: NO ELF

    I tried copying the entire /usr/include from my Linux desktop, and set it as the include directory, and still get strange errors like "u8" not declared

    What is the standard way of doing kernel development on Mac? I have a virtual machine running Linux on the same Mac, and it will be used to test the modified kernel. However, I don't really want to build kernel on it, as it is kinda slow.

    • nmagerko
      nmagerko over 12 years
    • mpontillo
      mpontillo over 12 years
      Can you post the exact error you're getting? NO ELF doesn't provide a lot of context. When do you see that and what happened before that?
    • Alfred Zhong
      Alfred Zhong over 12 years
      @Mike, I agree, that is the exact error, after I copy a elf.h file from internet and add it to a include directory so that make can find it. I don't know how to make it more informative. It happens pretty early.
    • mpontillo
      mpontillo over 12 years
      @AlfredZhong, what make target do you invoke to get NO ELF? Have you tried adding a verbose flag to make to see what exactly it's doing; I think with Linux you use make V=1? Also, why did you copy elf.h from the internet? I'd copy it from your VM where compiling that kernel is known to work.
    • ninjaSurfer
      ninjaSurfer over 9 years
      fwiw, the same issue applies to trying to build Yocto linux on osx as well.
  • Alfred Zhong
    Alfred Zhong about 12 years
    I agree. I gave up... I thought people might figured it out and came up with convenient way... And it turns out be to wrong.