Mobile/Fennec/Android/Clang

From MozillaWiki
< Mobile‎ | Fennec‎ | Android(Redirected from Android/Clang)
Jump to: navigation, search

Build GCC

clang still depends on gcc for some stuff, like gnu assembler. So we need to make a new gcc. The reason we use a new gcc instead of the NDK gcc is because we need to compile it against binutils 2.21 instead of the default NDK binutils (2.19).

Assuming there's a working NDK (r5 or above), run:

/PATH/TO/NDK/build/tools/download-toolchain-sources.sh ~/ndk-src
cd ~/ndk-src/binutils
wget http://ftp.gnu.org/gnu/binutils/binutils-2.21.1.tar.bz2
tar -xf binutils-2.21.1.tar.bz2
/PATH/TO/NDK/build/tools/build-gcc.sh --binutils-version=2.21.1 [--try-64] ~/ndk-src ~/ndk-clang arm-linux-androideabi-4.4.3

Include --try-64 for 64-bit build.

Build clang

svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm
cd llvm/tools
svn co http://llvm.org/svn/llvm-project/cfe/trunk clang
cd ..
./configure --prefix=${HOME}/ndk-clang/toolchains/clang --enable-optimized --enable-targets=x86,arm

Apply this patch (for now) to tools/clang:

Index: lib/Target/ARM/ARMInstrThumb.td
===================================================================
--- lib/Target/ARM/ARMInstrThumb.td	(revision 136922)
+++ lib/Target/ARM/ARMInstrThumb.td	(working copy)
@@ -628,10 +628,9 @@
}
 
 // Load tconstpool
-// FIXME: Use ldr.n to work around a Darwin assembler bug.
 let canFoldAsLoad = 1, isReMaterializable = 1, isCodeGenOnly = 1 in
 def tLDRpci : T1pIs<(outs tGPR:$Rt), (ins t_addrmode_pc:$addr), IIC_iLoad_i,
-                  "ldr", ".n\t$Rt, $addr",
+                  "ldr", "\t$Rt, $addr",
                   [(set tGPR:$Rt, (load (ARMWrapper tconstpool:$addr)))]>,
               T1Encoding<{0,1,0,0,1,?}> {
   // A6.2 & A8.6.59
@@ -641,19 +640,6 @@
   let Inst{7-0}  = addr;
 }
 
-// FIXME: Remove this entry when the above ldr.n workaround is fixed.
-// For disassembly use only.
-def tLDRpciDIS : T1pIs<(outs tGPR:$Rt), (ins t_addrmode_pc:$addr), IIC_iLoad_i,
-                       "ldr", "\t$Rt, $addr",
-                       [/* disassembly only */]>,
-                 T1Encoding<{0,1,0,0,1,?}> {
-  // A6.2 & A8.6.59
-  bits<3> Rt;
-  bits<8> addr;
-  let Inst{10-8} = Rt;
-  let Inst{7-0}  = addr;
-}
-
 // A8.6.194 & A8.6.192
 defm tSTR  : thumb_st_rr_ri_enc<0b000, 0b0110, t_addrmode_rrs4,
                                 t_addrmode_is4, AddrModeT1_4,

Then let it compile,

make -j4 install

Build clang glue files

Now there should be both gcc and clang under ~/ndk-clang, but we still need glue files to connect them together (so clang will use our gcc instead of the system gcc):

mkdir ~/ndk-clang/toolchains/clang-android
cd ~/ndk-clang/toolchains/clang-android
ln -s ../clang/include include
ln -s ../clang/lib lib
mkdir bin
cd bin
ln -s gcc/bin/arm-linux-androideabi-ar arm-eabi-ar
ln -s gcc/bin/arm-linux-androideabi-as arm-eabi-as
ln -s gcc/bin/arm-linux-androideabi-ranlib arm-eabi-ranlib
ln -s gcc/bin/arm-linux-androideabi-strip arm-eabi-strip
ln -s ../../arm-linux-androideabi-4.4.3/prebuilt/linux-x86 gcc

The last line should be changed if the path to gcc is different.

Now we need to create cpp, g++, and gcc under the bin directory. We need to pass extra parameters to clang so we use a shell script rather than a symlink:

cat > arm-eabi-cpp << EOF
  #!/bin/sh
  `dirname $0`/../../clang/bin/clang \
    -ccc-host-triple arm-eabi \
    -ccc-gcc-name "`dirname $0`/gcc/bin/arm-linux-androideabi-gcc" \
    -D__ANDROID__ -DANDROID -D__linux__ -D__ELF__ \
    -U__USER_LABEL_PREFIX__ -D__USER_LABEL_PREFIX__= \
    -D__compiler_offsetof=__builtin_offsetof -E $*
EOF
cat > arm-eabi-g++ << EOF
  #!/bin/sh
  `dirname $0`/../../clang/bin/clang \
    -ccc-host-triple arm-eabi \
    -ccc-gcc-name "`dirname $0`/gcc/bin/arm-linux-androideabi-g++" \
    -D__ANDROID__ -DANDROID -D__linux__ -D__ELF__ \
    -U__USER_LABEL_PREFIX__ -D__USER_LABEL_PREFIX__= \
    -D__compiler_offsetof=__builtin_offsetof -Wa,-march=armv7-a $*
EOF
cat > arm-eabi-gcc << EOF
  #!/bin/sh
  `dirname $0`/../../clang/bin/clang \
    -ccc-host-triple arm-eabi \
    -ccc-gcc-name "`dirname $0`/gcc/bin/arm-linux-androideabi-gcc" \
    -D__ANDROID__ -DANDROID -D__linux__ -D__ELF__ \
    -U__USER_LABEL_PREFIX__ -D__USER_LABEL_PREFIX__= \
    -D__compiler_offsetof=__builtin_offsetof -Wa,-march=armv7-a $*
EOF
chmod +x arm-eabi-cpp arm-eabi-g++ arm-eabi-gcc

This is ugly but works for now until there's a better solution.

Using clang

Now that clang is built, a .mozconfig change should be all that's needed. Sample .mozconfig:

OBJDIR=objdir-android-clang
mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/$OBJDIR
mk_add_options MOZ_MAKE_FLAGS="-j4"

# Add the correct paths here:
ac_add_options --with-android-ndk="/PATH/TO/ORIGINAL-NDK/"
ac_add_options --with-android-sdk="/PATH/TO/SDK/platforms/android-8"
ac_add_options --with-android-toolchain="@HOME@/ndk-clang/toolchains/clang-android"
ac_add_options --with-android-platform="/PATH/TO/ORIGINAL-NDK/platforms/android-8/arch-arm"
ac_add_options --with-android-version=8

# android options
ac_add_options --enable-application=mobile
ac_add_options --target=arm-android-eabi
ac_add_options --with-endian=little
ac_add_options --with-system-zlib

ac_add_options --disable-tests
ac_add_options --enable-optimize
ac_add_options --disable-debug
ac_add_options --disable-elf-hack

ac_add_options --enable-debug-symbols=-gdwarf-2
export MOZ_DEBUG_SYMBOLS=1
export CFLAGS="-flimit-debug-info"
export CXXFLAGS="-flimit-debug-info"

Note:

  • The stock NDK is still needed (/PATH/TO/ORIGINAL-NDK above)
  • elfhack should be disabled ('ac_add_options --disable-elf-hack')
  • Debug builds don't seem to work because the resulting binary is too big (likely a llvm bug but need to investigate). For now, use 'ac_add_options --disable-debug' and 'ac_add_options --enable-optimize'.