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'.