Mobile/Fennec/Android/Clang
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'.