Integrate abcc codebase.

This CL needs https://android-review.googlesource.com/#/c/66545/

Integrated abcc will be used after llvm 3.3 (included) by default.
If we want to build python version, we can add --use-python to build-llvm.sh.

Every host-related will be put under <abcc>/host/.
Every device-related will be put under <abcc>/device/.
Other common-based will be put under <abcc>.

The usage is just the same like before. No learning curve issue.
On host, we can dump information if we use --verbose.
On device, we can -DVERBOSE=1 to dump info to logcat.

Also, fix one bug on run-tests.sh. We need to copy instead of
soft link, otherwise the second abi won't be tested.

Change-Id: Ib95a3aabb40dc85bf73f8a35254108688ac654b7
diff --git a/build/tools/build-llvm.sh b/build/tools/build-llvm.sh
index 8503f1a..e679371 100755
--- a/build/tools/build-llvm.sh
+++ b/build/tools/build-llvm.sh
@@ -53,6 +53,10 @@
 do_check_option () { CHECK=yes; }
 register_option "--check" do_check_option "Check LLVM"
 
+USE_PYTHON=no
+do_use_python_option () { USE_PYTHON=yes; }
+register_option "--use-python" do_use_python_option "Use python bc2native instead of integrated one"
+
 register_jobs_option
 register_canadian_option
 register_try64_option
@@ -236,6 +240,24 @@
 mkdir -p $LLVM_BUILD_OUT && cd $LLVM_BUILD_OUT
 fail_panic "Couldn't cd into llvm build path: $LLVM_BUILD_OUT"
 
+# Only start using integrated bc2native source >= 3.3 by default
+LLVM_VERSION="`echo $TOOLCHAIN | tr '-' '\n' | tail -n 1`"
+LLVM_VERSION_MAJOR=`echo $LLVM_VERSION | tr '.' '\n' | head -n 1`
+LLVM_VERSION_MINOR=`echo $LLVM_VERSION | tr '.' '\n' | tail -n 1`
+if [ $LLVM_VERSION_MAJOR -lt 3 ]; then
+  USE_PYTHON=yes
+elif [ $LLVM_VERSION_MAJOR -eq 3 ] && [ $LLVM_VERSION_MINOR -lt 3 ]; then
+  USE_PYTHON=yes
+fi
+
+if [ "$USE_PYTHON" != "yes" ]; then
+  run cp -a $NDK_DIR/tests/abcc/jni/*.cpp $SRC_DIR/$TOOLCHAIN/llvm/tools/ndk-bc2native
+  run cp -a $NDK_DIR/tests/abcc/jni/*.h $SRC_DIR/$TOOLCHAIN/llvm/tools/ndk-bc2native
+  run cp -a $NDK_DIR/tests/abcc/jni/host/*.cpp $SRC_DIR/$TOOLCHAIN/llvm/tools/ndk-bc2native
+  run cp -a $NDK_DIR/tests/abcc/jni/host/*.h $SRC_DIR/$TOOLCHAIN/llvm/tools/ndk-bc2native
+  export LLVM_TOOLS_FILTER="PARALLEL_DIRS:=\$\$(PARALLEL_DIRS:%=% ndk-bc2native)"
+fi
+
 run $SRC_DIR/$TOOLCHAIN/llvm/configure \
     --prefix=$TOOLCHAIN_BUILD_PREFIX \
     --host=$ABI_CONFIGURE_HOST \
@@ -373,7 +395,13 @@
 find $TOOLCHAIN_BUILD_PREFIX/lib -maxdepth 1 -type f \( -name "*.dll" -o -name "*.so" \) -exec $STRIP {} \;
 
 # install script
-cp -p "$SRC_DIR/$TOOLCHAIN/llvm/tools/ndk-bc2native/ndk-bc2native.py" "$TOOLCHAIN_BUILD_PREFIX/bin/"
+if [ "$USE_PYTHON" != "yes" ]; then
+    # Remove those intermediate cpp
+    rm -f $SRC_DIR/$TOOLCHAIN/llvm/tools/ndk-bc2native/*.cpp
+    rm -f $SRC_DIR/$TOOLCHAIN/llvm/tools/ndk-bc2native/*.h
+else
+    cp -p "$SRC_DIR/$TOOLCHAIN/llvm/tools/ndk-bc2native/ndk-bc2native.py" "$TOOLCHAIN_BUILD_PREFIX/bin/"
+fi
 
 # copy to toolchain path
 run copy_directory "$TOOLCHAIN_BUILD_PREFIX" "$TOOLCHAIN_PATH"
diff --git a/build/tools/make-standalone-toolchain.sh b/build/tools/make-standalone-toolchain.sh
index 30d5439..eca5dd0 100755
--- a/build/tools/make-standalone-toolchain.sh
+++ b/build/tools/make-standalone-toolchain.sh
@@ -290,8 +290,12 @@
     echo '  shift'
     echo 'done'
     echo 'test -z "$output" && output=a.out'
-    echo 'export PYTHONPATH=`dirname $0`/../lib/python2.7/'
-    echo '`dirname $0`/python `dirname $0`/ndk-bc2native.py --sysroot=`dirname $0`/../sysroot --abi='$TARGET_ABI' --platform='$PLATFORM' --file $output $output'
+    echo 'if [ -f "`dirname $0`/ndk-bc2native" ]; then'
+    echo '  `dirname $0`/ndk-bc2native --sysroot=`dirname $0`/../sysroot --abi='$TARGET_ABI' --platform='$PLATFORM' --file $output $output'
+    echo 'else'
+    echo '  export PYTHONPATH=`dirname $0`/../lib/python2.7/'
+    echo '  `dirname $0`/python `dirname $0`/ndk-bc2native.py --sysroot=`dirname $0`/../sysroot --abi='$TARGET_ABI' --platform='$PLATFORM' --file $output $output'
+    echo 'fi'
   else
     echo 'rem Call bc2native if needed'
     echo ''
@@ -310,8 +314,12 @@
     echo '  if not "%output%" == "" goto :check_done'
     echo '  set output=a.out'
     echo ':check_done'
-    echo 'set PYTHONPATH=%~dp0\\..\\lib\\python2.7\\'
-    echo '%~dp0\\python'$HOST_EXE' %~dp0\\ndk-bc2native.py --sysroot=%~dp0\\..\\sysroot --abi='$TARGET_ABI' --platform='$PLATFORM' --file %output% %output%'
+    echo 'if exist %~dp0\\ndk-bc2native'$HOST_EXE' ('
+    echo '  %~dp0\\ndk-bc2native'$HOST_EXE' --sysroot=%~dp0\\.\\sysroot --abi='$TARGET_ABI' --platform='$PLATFORM' --file %output% %output'
+    echo 'else ('
+    echo '  set PYTHONPATH=%~dp0\\..\\lib\\python2.7\\'
+    echo '  %~dp0\\python'$HOST_EXE' %~dp0\\ndk-bc2native.py --sysroot=%~dp0\\..\\sysroot --abi='$TARGET_ABI' --platform='$PLATFORM' --file %output% %output%'
+    echo ')'
   fi
 }
 
diff --git a/tests/abcc/build-abcc.sh b/tests/abcc/build-abcc.sh
index f96f9ae..01f909c 100755
--- a/tests/abcc/build-abcc.sh
+++ b/tests/abcc/build-abcc.sh
@@ -144,6 +144,7 @@
 for ABI in $ABIS; do
   run rm -rf obj libs
   run $NDK_DIR/ndk-build -B APP_ABI=$ABI -C jni
+  fail_panic "Build ndk-build failed. Abort."
   if [ "$DEBUG" = "yes" ]; then
     run rm -f AndroidManifest.xml
     run cp -a AndroidManifest.xml.debug AndroidManifest.xml
diff --git a/tests/abcc/jni/Abcc.cpp b/tests/abcc/jni/Abcc.cpp
new file mode 100644
index 0000000..e597e71
--- /dev/null
+++ b/tests/abcc/jni/Abcc.cpp
@@ -0,0 +1,287 @@
+/*
+ * Copyright 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cstdlib>
+#include <fcntl.h>
+#include <fstream>
+#include <sstream>
+#include <stdint.h>
+#include <unistd.h>
+#include "Abcc.h"
+using namespace abcc;
+
+TargetAbi::TargetAbi(const std::string &abi) {
+  if (abi == "armeabi")
+    mAbi = ARMEABI;
+  else if (abi == "x86")
+    mAbi = X86;
+  else if (abi == "mips")
+    mAbi = MIPS;
+  else
+    mAbi = ARMEABI_V7A;  // Default
+}
+
+
+BitcodeInfo::BitcodeInfo(const std::string &bc)
+  : mShared(false), mBCPath(bc) {
+  std::string stem = mBCPath.substr(0, mBCPath.rfind("."));
+  mTargetBCPath = stem + "-target.bc";
+  mObjPath = stem + ".o";
+  mOutPath = stem;  // If shared, we will add .so after readWrapper
+  mSOName = mBCPath.substr(mBCPath.rfind("/") + 1);
+}
+
+int BitcodeInfo::readWrapper(BitcodeCompiler &compiler) {
+  int fd = open(mBCPath.c_str(), O_RDONLY);
+  if (fd < 0) {
+    return -1;
+  }
+
+  unsigned char buffer[5] = {'\0', '\0', '\0', '\0', '\0'};
+  read(fd, buffer, 4);  // Skip magic number, we have checked
+  read(fd, buffer, 4);  // version
+  read(fd, buffer, 4);  // offset
+  swapEndian(buffer, 4);
+  int offset = transferBytesToNum(buffer, 4);
+  lseek(fd, 4*7, SEEK_SET);
+  offset -= 4*7;  // Useless, skip
+
+  while (offset > 0) {
+    read(fd, buffer, 4);
+    swapEndian(buffer, 4);
+    uint16_t length = transferBytesToNum(buffer, 2);
+    uint16_t tag = transferBytesToNum(buffer+2, 2);
+    LOGV("length: %d", length);
+    LOGV("tag: %d", tag);
+    length = (length + 3) & ~3;
+
+    unsigned char *large_buffer = (unsigned char*) malloc(length+1);
+    if (large_buffer == 0) {
+      LOGE("Cannot create buffer for wrapper field");
+      close(fd);
+      return -1;
+    }
+    large_buffer[length] = '\0';
+    int n = read(fd, large_buffer, length);
+    if (n != length) {
+      LOGE("Read wrapper field error");
+      close(fd);
+      return -1;
+    }
+
+    if (tag == 0x5002) {
+      const char* ldflags = reinterpret_cast<char*>(large_buffer);
+      LOGV("Wrapper field: %s", ldflags);
+      if (compiler.parseLDFlags(*this, ldflags) != 0) {
+        LOGE("Cannot parse ldflags from wrapper");
+        close(fd);
+        return -1;
+      }
+    } else {
+      // Some field maybe useful, but we use wrapper to encode command line,
+      // this is not necessary for now.
+    }
+    offset -= (length + 4);
+    free(large_buffer);
+  } // while
+  close(fd);
+  return 0;
+}
+
+void BitcodeInfo::dropExternalLDLibs(SONameMap &map) {
+  for (SONameMap::iterator i = map.begin(), e = map.end(); i != e; ++i) {
+    BitcodeInfo &info = i->second;
+    for (std::list<std::string>::iterator i_libs = info.mLDLibs.begin(),
+         e_libs = info.mLDLibs.end(); i_libs != e_libs; ) {
+      std::list<std::string>::iterator cur_libs = i_libs++;
+      std::string full_soname = std::string("lib") + *cur_libs + ".so";
+      if (map.find(full_soname) == map.end()) {
+        LOGV("Drop -l%s from %s for linking order decision", cur_libs->c_str(), info.mSOName.c_str());
+        info.mLDLibs.erase(cur_libs);
+      }
+    }
+  }
+}
+
+void BitcodeInfo::swapEndian(unsigned char *buffer, size_t n) {
+  // We uses le32, so it must be LITTLE ENDIAN
+  for (size_t i = 0; i < n/2; ++i) {
+    char tmp = buffer[i];
+    buffer[i] = buffer[n-i-1];
+    buffer[n-i-1] =tmp;
+  }
+}
+
+int BitcodeInfo::transferBytesToNum(const unsigned char *buffer, size_t n) {
+  int ret = 0;
+  for (size_t i = 0; i < n; ++i) {
+    ret = ret * 0x100 + buffer[i];
+  }
+  return ret;
+}
+
+
+BitcodeCompiler::BitcodeCompiler(const std::string &abi, const std::string &sysroot, const std::string &working_dir)
+  : mAbi(abi), mSysroot(sysroot), mWorkingDir(working_dir), mRet(RET_OK) {
+  // CFlags
+  mGlobalCFlags = kGlobalTargetAttrs[mAbi].mBaseCFlags;
+  mGlobalCFlags += std::string(" -mtriple=") + kGlobalTargetAttrs[mAbi].mTriple;
+  mGlobalCFlags += " -filetype=obj -relocation-model=pic -code-model=small";
+  mGlobalCFlags += " -use-init-array -mc-relax-all";
+
+#ifdef DEBUG
+  mGlobalCFlags += std::string(" ") + "-O0";
+#else
+  mGlobalCFlags += std::string(" ") + "-O2";
+#endif
+
+  if (mAbi == TargetAbi::ARMEABI || mAbi == TargetAbi::ARMEABI_V7A)
+    mGlobalCFlags += std::string(" ") + "-arm-enable-ehabi -arm-enable-ehabi-descriptors -float-abi=soft";
+
+  // LDFlags
+  mGlobalLDFlags = kGlobalTargetAttrs[mAbi].mBaseLDFlags;
+  mGlobalLDFlags += std::string(" -Bsymbolic -X -m ") + kGlobalTargetAttrs[mAbi].mLinkEmulation;
+  mGlobalLDFlags += std::string(" --sysroot=") + mSysroot;
+  mGlobalLDFlags += " -eh-frame-hdr -dynamic-linker /system/bin/linker";
+
+  // LDLibs
+  mGlobalLDLibs += "";
+}
+
+void BitcodeCompiler::translate() {
+  for (std::vector<BitcodeInfo>::const_iterator i = mBitcodeFiles.begin(),
+       e = mBitcodeFiles.end(); i != e; ++i) {
+    const BitcodeInfo &bc = *i;
+    std::string cmd = mExecutableToolsPath[(unsigned)CMD_TRANSLATE];
+    cmd += std::string(" -arch=") + kGlobalTargetAttrs[mAbi].mArch;
+    cmd += " " + bc.mBCPath + " -o " + bc.mTargetBCPath;
+    runCmd(cmd, /*dump=*/true);
+    if (returnCode() != RET_OK) {
+      mRet = RET_FAIL_TRANSLATE;
+      return;
+    }
+
+    removeIntermediateFile(bc.mBCPath);
+  }
+}
+
+void BitcodeCompiler::compile() {
+  for (std::vector<BitcodeInfo>::const_iterator i = mBitcodeFiles.begin(),
+       e = mBitcodeFiles.end(); i != e; ++i) {
+    const BitcodeInfo &bc = *i;
+    std::string cmd = mExecutableToolsPath[(unsigned)CMD_COMPILE];
+    cmd += " " + mGlobalCFlags;
+    cmd += " " + bc.mTargetBCPath + " -o " + bc.mObjPath;
+    runCmd(cmd, /*dump=*/true);
+    if (returnCode() != RET_OK) {
+      mRet = RET_FAIL_COMPILE;
+      return;
+    }
+
+    removeIntermediateFile(bc.mTargetBCPath);
+  }
+}
+
+void BitcodeCompiler::link() {
+  BitcodeInfo::dropExternalLDLibs(mSonameMap);
+
+  while (!mSonameMap.empty()) {
+    SONameMap::iterator i = mSonameMap.begin(), e = mSonameMap.end();
+    for (; i != e; ++i) {
+      const BitcodeInfo &bc = i->second;
+
+      if (bc.mLDLibs.empty()) {
+        // No internal dependency for this bitcode
+        LOGV("Process bitcode: %s -> %s", bc.mBCPath.c_str(), bc.mSOName.c_str());
+        std::string cmd = mExecutableToolsPath[(unsigned)CMD_LINK];
+        cmd += " " + mGlobalLDFlags;
+        cmd += " " + bc.mLDFlags;
+        if (bc.mShared) {
+          cmd += std::string(" ") + mSysroot + "/usr/lib/crtbegin_so.o";
+          cmd += " -shared " + bc.mObjPath + " -o " + bc.mOutPath;
+          cmd += " -soname " + bc.mSOName;
+        } else {
+          cmd += std::string(" ") + mSysroot + "/usr/lib/crtbegin_dynamic.o";
+          cmd += " " + bc.mObjPath + " -o " + bc.mOutPath;
+        }
+        // Add ldlibs
+        cmd += " " + mGlobalLDLibs;
+        cmd += " " + bc.mLDLibsStr;
+        cmd += " " + mExecutableToolsPath[(unsigned)CMD_LINK_RUNTIME];
+        if (bc.mShared)
+          cmd += std::string(" ") + mSysroot + "/usr/lib/crtend_so.o";
+        else
+          cmd += std::string(" ") + mSysroot + "/usr/lib/crtend_android.o";
+        runCmd(cmd, /*dump=*/true);
+        if (returnCode() != RET_OK)
+          return;
+
+        copyRuntime(bc);
+        removeIntermediateFile(bc.mObjPath);
+
+        mSonameMap.erase(i);
+        BitcodeInfo::dropExternalLDLibs(mSonameMap);
+        break;  // Re-compute
+      }
+    } // for
+
+    if (i == e) {
+      LOGE("Failed to compute linking order: Internal cyclic dependency!");
+      mRet = RET_FAIL_LINK;
+      return;
+    }
+  } // while
+}
+
+void BitcodeCompiler::runCmd(std::string cmd, bool dump) {
+  LOGV("Command: %s", cmd.c_str());
+  std::string logfilename = mWorkingDir + "/compile_log";
+  if (dump) {
+    cmd += " 2>&1 > " + logfilename;
+  }
+  int ret = system(cmd.c_str());
+  if (ret != 0) {
+    mRet = RET_FAIL_RUN_CMD;
+    if (dump) {
+      std::ifstream ifs(logfilename.c_str());
+      std::stringstream sstr;
+      sstr << ifs.rdbuf();
+      LOGE("Error message: %s", sstr.str().c_str());
+      std::fstream fout;
+      std::string file = mWorkingDir + "/compile_error";
+      fout.open(file.c_str(), std::fstream::out | std::fstream::app);
+      fout << "Failed command: " << cmd << "\n";
+      fout << "Error message: " << sstr.str() << "\n";
+      fout.close();
+    }
+    return;
+  }
+  mRet = RET_OK;
+}
+
+void BitcodeCompiler::prepareBitcodes() {
+  getBitcodeFiles();
+  createSONameMapping();
+}
+
+void BitcodeCompiler::createSONameMapping() {
+  for (std::vector<BitcodeInfo>::const_iterator i = mBitcodeFiles.begin(),
+       e = mBitcodeFiles.end(); i != e; ++i) {
+    const BitcodeInfo &info = *i;
+    LOGV("Map soname %s -> %s", info.mSOName.c_str(), info.mBCPath.c_str());
+    mSonameMap[info.mSOName] = info;
+  }
+}
diff --git a/tests/abcc/jni/Abcc.h b/tests/abcc/jni/Abcc.h
new file mode 100644
index 0000000..6b6d1ba
--- /dev/null
+++ b/tests/abcc/jni/Abcc.h
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ABCC_ABCC_H
+#define ABCC_ABCC_H
+
+#include <list>
+#include <map>
+#include <string>
+#include <vector>
+
+namespace abcc {
+
+enum ReturnCode {
+  RET_OK,
+  RET_FAIL_RUN_CMD,
+  RET_FAIL_UNSUPPORT_ABI,
+  RET_FAIL_PREPARE_BITCODE,
+  RET_FAIL_PREPARE_TOOL,
+  RET_FAIL_CLEANUP,
+  RET_FAIL_TRANSLATE,
+  RET_FAIL_COMPILE,
+  RET_FAIL_LINK,
+};
+
+enum Command {
+  CMD_TRANSLATE = 0,
+  CMD_COMPILE,
+  CMD_LINK,
+  CMD_LINK_RUNTIME,
+};
+
+class TargetAbi {
+public:
+  enum Abi {
+    ARMEABI = 0,
+    ARMEABI_V7A,
+    X86,
+    MIPS,
+  };
+
+private:
+  Abi mAbi;
+
+public:
+  TargetAbi(const std::string &abi);
+  operator int() const { return (int)mAbi; }
+  operator const char*() const {
+    if (mAbi == ARMEABI)  return "armeabi";
+    if (mAbi == ARMEABI_V7A)  return "armeabi-v7a";
+    if (mAbi == X86)  return "x86";
+    if (mAbi == MIPS)  return "mips";
+    return 0;
+  }
+  const char* getArch() const {
+    if (mAbi == ARMEABI || mAbi == ARMEABI_V7A)  return "arm";
+    if (mAbi == X86)  return "x86";
+    if (mAbi == MIPS) return "mips";
+    return 0;
+  }
+};
+
+struct TargetAttributes {
+  const char *mArch;
+  const char *mTriple;
+  const char *mLinkEmulation;
+  const char *mBaseCFlags;
+  const char *mBaseLDFlags;
+};
+
+const TargetAttributes kGlobalTargetAttrs[] = {
+  {"arm", "armv5te-linux-androideabi", "armelf_linux_eabi", "", ""},
+#ifdef FORCE_ARM
+  {"arm", "armv7-linux-androideabi", "armelf_linux_eabi", "", ""},
+#else
+  {"arm", "thumbv7-linux-androideabi", "armelf_linux_eabi", "", ""},
+#endif
+  {"x86", "i686-linux-android", "elf_i386", "-disable-fp-elim -force-align-stack -mattr=-ssse3,-sse41,-sse42,-sse4a,-popcnt", ""},
+  {"mips", "mipsel-linux-android", "elf32ltsmip", "", ""},
+};
+
+// Used when computing mutual dependency
+class BitcodeCompiler;
+class BitcodeInfo;
+typedef std::map<std::string/*soname*/, BitcodeInfo> SONameMap;
+
+class BitcodeInfo {
+public:
+  BitcodeInfo() {}  // Only for stl use
+  BitcodeInfo(const std::string &bc);
+  int readWrapper(BitcodeCompiler &);
+  static void dropExternalLDLibs(SONameMap &map);
+
+  bool mShared;
+  std::string mBCPath;
+  std::string mTargetBCPath;
+  std::string mObjPath;
+  std::string mOutPath;
+  std::string mSOName;
+  std::string mLDFlags; // --no-undefined, ...
+  std::list<std::string> mLDLibs;  // -lxxx, will be removed one-by-one until empty
+  std::string mLDLibsStr; // Immutable once read in
+
+public:
+  static void swapEndian(unsigned char *buffer, size_t n);
+  static int transferBytesToNum(const unsigned char *buffer, size_t n);
+};
+
+
+class BitcodeCompiler {
+protected:
+  TargetAbi mAbi;
+  std::string mSysroot;
+  std::string mWorkingDir;
+
+  // Target-independent, but global
+  std::string mGlobalCFlags;
+  std::string mGlobalLDFlags;
+  std::string mGlobalLDLibs;
+
+  ReturnCode mRet;
+  std::vector<BitcodeInfo> mBitcodeFiles;
+  SONameMap mSonameMap;
+  std::string mExecutableToolsPath[(unsigned)CMD_LINK_RUNTIME+1];
+
+public:
+  BitcodeCompiler(const std::string &abi, const std::string &sysroot, const std::string &working_dir);
+  const ReturnCode returnCode() const { return mRet; }
+  virtual void cleanupPre() {}
+  virtual void cleanupPost() {}
+  void prepare() {
+    prepareBitcodes();
+    if (returnCode() != RET_OK)
+      return;
+
+    prepareToolchain();
+    if (returnCode() != RET_OK)
+      return;
+  }
+  void execute() {
+    translate();
+    if (returnCode() != RET_OK)
+      return;
+
+    compile();
+    if (returnCode() != RET_OK)
+      return;
+
+    link();
+    if (returnCode() != RET_OK)
+      return;
+  }
+
+private:
+  void prepareBitcodes();
+  void createSONameMapping();
+  virtual void getBitcodeFiles() = 0;
+  virtual void prepareToolchain() = 0;
+  virtual void copyRuntime(const BitcodeInfo &info) = 0;
+  virtual void removeIntermediateFile(const std::string &path) = 0;
+  void translate();
+  void compile();
+  void link();
+
+public:
+  virtual int parseLDFlags(BitcodeInfo &info, const std::string &str) = 0;
+
+protected:
+  void runCmd(std::string cmd, bool dump = false);
+};
+
+} // namespace abcc
+
+// FIXME: We use LOGV, LOGE in Abcc.cpp, how to prevent this anti dependency?
+#ifdef ON_DEVICE
+#include "Abcc_device.h"
+#else
+#include "Abcc_host.h"
+#endif
+
+#endif
diff --git a/tests/abcc/jni/Android.mk b/tests/abcc/jni/Android.mk
index 98ed993..c3b184a 100644
--- a/tests/abcc/jni/Android.mk
+++ b/tests/abcc/jni/Android.mk
@@ -20,7 +20,11 @@
 
 LOCAL_MODULE    := libjni_abcc
 LOCAL_MODULE_CLASS := SHARED_LIBRARIES
-LOCAL_SRC_FILES := main.cpp
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/device
+LOCAL_SRC_FILES := \
+  Abcc.cpp \
+  device/Abcc_device.cpp \
+  device/main.cpp
 
 # Check in AOSP or NDK usage
 ifeq ($(SYSTEM_PREBUILT_PACKAGE),true)
@@ -31,6 +35,7 @@
 include $(BUILD_SHARED_LIBRARY)
 else  # SYSTEM_PREBUILT_PACKAGE
 
+LOCAL_CFLAGS += -DON_DEVICE=1
 LOCAL_CFLAGS += -DENABLE_PARALLEL_LLVM_CG=1
 LOCAL_CFLAGS += -DVERBOSE=0
 LOCAL_LDLIBS := -llog
diff --git a/tests/abcc/jni/device/Abcc_device.cpp b/tests/abcc/jni/device/Abcc_device.cpp
new file mode 100644
index 0000000..62a8ea3
--- /dev/null
+++ b/tests/abcc/jni/device/Abcc_device.cpp
@@ -0,0 +1,220 @@
+/*
+ * Copyright 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sstream>
+#include <sys/stat.h>
+#if ENABLE_PARALLEL_LLVM_CG
+#include <cpu-features.h>
+#endif
+#include "Abcc_device.h"
+using namespace abcc;
+
+#if defined(__arm__) && defined(__ARM_ARCH_7A__)
+# define CURRENT_ABI  "armeabi-v7a"
+#elif defined(__arm__)
+# define CURRENT_ABI  "armeabi"
+#elif defined(__i386__)
+# define CURRENT_ABI  "x86"
+#elif defined(__mips__)
+# define CURRENT_ABI  "mips"
+#else
+# error "Unsupport target abi"
+#endif
+
+
+DeviceBitcodeCompiler::DeviceBitcodeCompiler(const std::string &working_dir, const std::string &sysroot)
+  : BitcodeCompiler(CURRENT_ABI, sysroot, working_dir) {}
+
+void DeviceBitcodeCompiler::cleanupPost() {
+  ReturnCode ret = mRet;
+  std::string cmd("echo ");
+  if (ret == RET_OK)
+    cmd += "0";
+  else
+    cmd += "255";
+  cmd += " > " + mWorkingDir + "/compile_result";
+  runCmd(cmd);
+
+  if (ret == RET_OK) {
+    cmd = "rm -f " + mWorkingDir + "/compile_log";
+    runCmd(cmd);
+  }
+  cmd = "chmod 0755 " + mWorkingDir + "/*";
+  runCmd(cmd);
+  mRet = ret; // Restore execution return code
+}
+
+int DeviceBitcodeCompiler::parseLDFlags(BitcodeInfo &info, const std::string &orig_str) {
+  std::stringstream ss(orig_str);
+  std::string str;
+  while (ss >> str) {
+    if (str.find("--sysroot") != std::string::npos) {
+      continue;
+    }
+    if (str == "-o") {
+      ss >> str;
+      continue;
+    }
+    if (str == "-soname") {
+      ss >> str;
+      info.mSOName = str;
+      continue;
+    }
+    if (str == "-shared") {
+      info.mShared = true;
+      info.mOutPath += ".so";
+      continue;
+    }
+
+    // Parse -lxxx
+    if (str.size() > 2 &&
+        str.substr(0, 2) == "-l") {
+      info.mLDLibs.push_back(str.substr(2));
+      info.mLDLibsStr += " " + str;
+      continue;
+    }
+
+    // Some other flags, like --no-undefined, -z now, -z noexecstack, ...
+    info.mLDFlags += str + " ";
+  } // while
+  return 0;
+}
+
+void DeviceBitcodeCompiler::getBitcodeFiles() {
+  std::vector<std::string> files;
+  DIR *dp = opendir(mWorkingDir.c_str());
+  if (!dp) {
+    mRet = RET_FAIL_PREPARE_BITCODE;
+    return;
+  }
+
+  struct dirent *entry = 0;
+  while ((entry = readdir(dp)) != 0) {
+    std::string filename(entry->d_name);
+    std::string full_path = mWorkingDir + "/" + filename;
+    if (filename == "." || filename == "..")
+      continue;
+
+    std::string libpath = mSysroot + "/usr/lib/" + filename.substr(0, filename.rfind('.')) + ".so";
+    struct stat buf;
+    if (stat(libpath.c_str(), &buf) == 0) {
+      // This file has the same name in our runtime library pool.
+      std::string cmd = "rm -f " + full_path;
+      runCmd(cmd.c_str());
+      continue;
+    }
+
+
+    int fd = open(full_path.c_str(), O_RDONLY);
+    if (fd < 0) {
+      LOGV("Error opening file: %s (Ignored)", full_path.c_str());
+      continue;
+    }
+
+    unsigned char buffer[4];
+    read(fd, buffer, 4);
+    close(fd);
+    BitcodeInfo::swapEndian(buffer, 4);
+    int magic = BitcodeInfo::transferBytesToNum(buffer, 4);
+
+    if (magic != 0x0b17c0de) {
+      LOGV("Found file %s magic: %x, but we need a wrapped bitcode.", full_path.c_str(), magic);
+      continue;
+    }
+
+    LOGV("Push_back a bitcode: %s", full_path.c_str());
+    files.push_back(full_path);
+  } // while
+  closedir(dp);
+
+  if (files.empty()) {
+    LOGV("No bitcodes needs to compile");
+    return;
+  }
+
+  if (returnCode() != RET_OK) {
+    LOGV("Cannot get bitcode files from directory: %s", mWorkingDir.c_str());
+    return;
+  }
+
+  for (std::vector<std::string>::const_iterator i = files.begin(),
+       e = files.end(); i != e; ++i) {
+    BitcodeInfo bcinfo(*i);
+    if (bcinfo.readWrapper(*this) != 0) {
+      LOGE("Cannot read wrapper for bitcode %s", i->c_str());
+      mRet = RET_FAIL_PREPARE_BITCODE;
+      return;
+    }
+    mBitcodeFiles.push_back(bcinfo);
+  }
+}
+
+void DeviceBitcodeCompiler::prepareToolchain() {
+  // le32-none-ndk-translate
+  std::string cmd = std::string("LD_LIBRARY_PATH=") + mSysroot + "/usr/lib";
+  cmd += " " + mSysroot + "/usr/bin/le32-none-ndk-translate";
+  mExecutableToolsPath[(unsigned)CMD_TRANSLATE] = cmd;
+
+  // llc
+  cmd = std::string("LD_LIBRARY_PATH=") + mSysroot + "/usr/lib";
+  cmd += " " + mSysroot + "/usr/bin/llc";
+#ifdef ENABLE_PARALLEL_LLVM_CG
+  std::ostringstream stream;
+  stream << android_getCpuCount();
+  cmd += " -thread=" + stream.str();
+#endif
+  mExecutableToolsPath[(unsigned)CMD_COMPILE] = cmd;
+
+  // ld.mcld
+  cmd = std::string("LD_LIBRARY_PATH=") + mSysroot + "/usr/lib";
+  cmd += " " + mSysroot + "/usr/bin/ld.mcld";
+  cmd += " -L" + mWorkingDir;
+  cmd += " -L" + mSysroot + "/usr/lib";
+  cmd += " -L/system/lib";
+  mExecutableToolsPath[(unsigned)CMD_LINK] = cmd;
+
+  cmd = " @" + mSysroot + "/usr/lib/libportable.wrap " + mSysroot + "/usr/lib/libportable.a";
+  cmd += " " + mSysroot + "/usr/lib/libcompiler_rt_static.a";
+  cmd += " " + mSysroot + "/usr/lib/libgabi++_shared.so";
+  cmd += " -ldl";
+  mExecutableToolsPath[(unsigned)CMD_LINK_RUNTIME] = cmd;
+}
+
+void DeviceBitcodeCompiler::copyRuntime(const BitcodeInfo &info) {
+  runCmd(std::string("cp -f ") + mSysroot + "/usr/lib/libgabi++_shared.so " + mWorkingDir + "/libgabi++_shared.so");
+
+  std::stringstream ss(info.mLDLibsStr);
+  std::string deplib;
+  while (ss >> deplib) {
+    if (deplib.substr(0, 2) == "-l") {
+      std::string libname = "lib" + deplib.substr(2) + ".so";
+      std::string libpath = mSysroot + "/usr/lib/" + libname;
+      struct stat buf;
+      if (stat(libpath.c_str(), &buf) == 0) {
+        // Found!
+        LOGV("Copy runtime library: %s", libname.c_str());
+        runCmd("cp -f " + libpath + " " + mWorkingDir + "/" + libname);
+      }
+    }
+  }
+}
+
+void DeviceBitcodeCompiler::removeIntermediateFile(const std::string &path) {
+  runCmd(std::string("rm -f ") + path);
+}
diff --git a/tests/abcc/jni/device/Abcc_device.h b/tests/abcc/jni/device/Abcc_device.h
new file mode 100644
index 0000000..50eda83
--- /dev/null
+++ b/tests/abcc/jni/device/Abcc_device.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ABCC_ABCC_DEVICE_H
+#define ABCC_ABCC_DEVICE_H
+
+#include <android/log.h>
+#if VERBOSE
+#include <sys/time.h>
+#endif
+#include "Abcc.h"
+
+#define LOG_TAG "AbccNative"
+#define LOGE(format, ...)  do {\
+  __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, format, ##__VA_ARGS__);\
+  } while(0)
+
+#if VERBOSE
+#define LOGV(format, ...)  do {\
+  __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, format, ##__VA_ARGS__);\
+  } while(0)
+#else
+#define LOGV(format, ...)
+#endif  // VERBOSE
+
+namespace abcc {
+
+#if VERBOSE
+class Timer {
+private:
+  struct timeval _t0;
+public:
+  Timer() {};
+  void start() { gettimeofday(&_t0, NULL); }
+  long long stop() {
+  struct timeval t;
+    gettimeofday(&t, NULL);
+    long long l0 = _t0.tv_sec * 1000000LL + _t0.tv_usec;
+    long long l = t.tv_sec * 1000000LL + t.tv_usec;
+    return l - l0;
+  }
+};
+#endif // VERBOSE
+
+
+class DeviceBitcodeCompiler : public BitcodeCompiler {
+public:
+  DeviceBitcodeCompiler(const std::string &working_dir, const std::string &sysroot);
+  virtual void cleanupPost();
+
+public:
+  virtual int parseLDFlags(BitcodeInfo &info, const std::string &str);
+
+private:
+  virtual void getBitcodeFiles();
+  virtual void prepareToolchain();
+  virtual void copyRuntime(const BitcodeInfo &info);
+  virtual void removeIntermediateFile(const std::string &path);
+};
+
+} // namespace abcc
+
+#endif
diff --git a/tests/abcc/jni/device/main.cpp b/tests/abcc/jni/device/main.cpp
new file mode 100644
index 0000000..ced2fc7
--- /dev/null
+++ b/tests/abcc/jni/device/main.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <memory>
+#include <jni.h>
+#include "Abcc_device.h"
+using namespace abcc;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+JNIEXPORT jint JNICALL
+Java_compiler_abcc_AbccService_genLibs(JNIEnv *env, jobject thiz,
+                                       jstring j_lib_dir, jstring j_sysroot) {
+  const char *lib_dir = env->GetStringUTFChars(j_lib_dir, 0);
+  LOGV("Working directory: %s", lib_dir);
+
+  const char *sysroot = env->GetStringUTFChars(j_sysroot, 0);
+  LOGV("Sysroot: %s", sysroot);
+
+
+  std::auto_ptr<BitcodeCompiler> compiler(new DeviceBitcodeCompiler(lib_dir, sysroot));
+  compiler->prepare();
+  if (compiler->returnCode() != RET_OK) {
+    LOGE("prepare failed");
+    return -1;
+  }
+
+  compiler->cleanupPre();
+  if (compiler->returnCode() != RET_OK) {
+    LOGE("cleanupPre failed");
+    return -1;
+  }
+
+#if VERBOSE
+  Timer t;
+  t.start();
+#endif
+
+  compiler->execute();
+
+#if VERBOSE
+  long long elapsed_msec = (t.stop() + 500) / 1000;
+  LOGV("Elapsed time: %lld.%03ds", elapsed_msec/1000, (int)elapsed_msec%1000);
+#endif
+
+  compiler->cleanupPost();
+
+  if (compiler->returnCode() != RET_OK) {
+    LOGE("execution failed");
+    return -1;
+  }
+
+  return 0;
+}
+
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/tests/abcc/jni/host/Abcc_host.cpp b/tests/abcc/jni/host/Abcc_host.cpp
new file mode 100644
index 0000000..57ca00c
--- /dev/null
+++ b/tests/abcc/jni/host/Abcc_host.cpp
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sstream>
+#include "Abcc_host.h"
+using namespace abcc;
+
+bool kVerbose = false;
+
+HostBitcodeCompiler::HostBitcodeCompiler(const std::string &abi, const std::string &sysroot,
+                                         const std::string &input, const std::string &output, const std::string &working_dir,
+                                         const std::string &platform)
+  : BitcodeCompiler(abi, sysroot, working_dir), mIn(input), mOut(output),
+    mNDKDir(""), mPlatform(platform) {
+}
+
+HostBitcodeCompiler::HostBitcodeCompiler(const std::string &abi, const std::string &sysroot, const std::string &ndk_dir, const std::string &toolchain_bin,
+                                         const std::string &input, const std::string &output, const std::string &working_dir,
+                                         const std::string &platform)
+  : BitcodeCompiler(abi, sysroot, working_dir), mIn(input), mOut(output),
+    mNDKDir(ndk_dir), mPlatform(platform), mToolchainBinPath(toolchain_bin) {
+}
+
+int HostBitcodeCompiler::parseLDFlags(BitcodeInfo &info, const std::string &orig_str) {
+  std::stringstream ss(orig_str);
+  std::string str;
+  while (ss >> str) {
+    if (str.find("--sysroot") != std::string::npos) {
+      continue;
+    }
+    if (str == "-o") {
+      ss >> str;
+      continue;
+    }
+    if (str == "-soname") {
+      ss >> str;
+      info.mSOName = str;
+      continue;
+    }
+    if (str == "-shared") {
+      info.mShared = true;
+      info.mOutPath += ".so";
+      continue;
+    }
+
+    if (str.size() > 2 &&
+        str.substr(str.size() - 2) == ".a") {
+      info.mLDLibs.push_back(str);
+      info.mLDLibsStr += " " + str;
+      continue;
+    }
+    if (str.size() > 3 &&
+        str.substr(str.size() - 3) == ".so") {
+      info.mLDLibs.push_back(str);
+      info.mLDLibsStr += " " + str;
+      continue;
+    }
+
+    // Parse -lxxx
+    if (str.size() > 2 &&
+        str.substr(0, 2) == "-l") {
+      info.mLDLibs.push_back(str.substr(2));
+      info.mLDLibsStr += " " + str;
+      continue;
+    }
+
+    // Some other flags, like --no-undefined, -z now, -z noexecstack, ...
+    info.mLDFlags += str + " ";
+  } // while
+  return 0;
+}
+
+void HostBitcodeCompiler::getBitcodeFiles() {
+  BitcodeInfo bcinfo(mIn);
+  if (bcinfo.readWrapper(*this) != 0) {
+    LOGE("Cannot read wrapper for bitcode %s", mIn.c_str());
+    mRet = RET_FAIL_PREPARE_BITCODE;
+    return;
+  }
+
+  bcinfo.mOutPath = mOut;
+  mBitcodeFiles.push_back(bcinfo);
+}
+
+void HostBitcodeCompiler::prepareToolchain() {
+  // le32-none-ndk-translate
+  std::string cmd = getToolchainBinPath() + "/le32-none-ndk-translate";
+  mExecutableToolsPath[(unsigned)CMD_TRANSLATE] = cmd;
+
+  // llc
+  cmd = getToolchainBinPath() + "/llc";
+  mExecutableToolsPath[(unsigned)CMD_COMPILE] = cmd;
+
+  // ld.mcld
+  cmd = getToolchainBinPath() + "/ld.mcld";
+  cmd += " -L" + mSysroot + "/usr/lib";
+  mExecutableToolsPath[(unsigned)CMD_LINK] = cmd;
+
+  cmd = " @" + getLibPortablePath() + "/libportable.wrap " + getLibPortablePath() + "/libportable.a";
+  cmd += " " + getCompilerRTPath() + "/libcompiler_rt_static.a";
+  cmd += " " + getGAbixxPath() + "/libgabi++_shared.so";
+  cmd += " -ldl";
+  mExecutableToolsPath[(unsigned)CMD_LINK_RUNTIME] = cmd;
+}
+
+void HostBitcodeCompiler::copyRuntime(const BitcodeInfo &info) {
+}
+
+void HostBitcodeCompiler::removeIntermediateFile(const std::string &path) {
+  if (!kVerbose)
+    runCmd(std::string("rm -f ") + path);
+}
+
+const std::string HostBitcodeCompiler::getToolchainBinPath() const {
+  if (!mNDKDir.empty())
+    return mToolchainBinPath;
+  else
+    return mSysroot + "/usr/bin";
+}
+
+const std::string HostBitcodeCompiler::getCompilerRTPath() const {
+  if (!mNDKDir.empty())
+    return std::string(mNDKDir) + "/sources/android/compiler-rt/libs/" + (const char*)mAbi;
+  else
+    return mSysroot + "/usr/lib";
+}
+
+const std::string HostBitcodeCompiler::getGAbixxPath() const {
+  if (!mNDKDir.empty())
+    return std::string(mNDKDir) + "/sources/cxx-stl/gabi++/libs/" + (const char*)mAbi;
+  else
+    return mSysroot + "/usr/lib";
+}
+
+const std::string HostBitcodeCompiler::getLibPortablePath() const {
+  if (!mNDKDir.empty())
+    return std::string(mNDKDir) + "/sources/android/libportable/libs/" + (const char*)mAbi;
+  else
+    return mSysroot + "/usr/lib";
+}
diff --git a/tests/abcc/jni/host/Abcc_host.h b/tests/abcc/jni/host/Abcc_host.h
new file mode 100644
index 0000000..f0caf05
--- /dev/null
+++ b/tests/abcc/jni/host/Abcc_host.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ABCC_ABCC_HOST_H
+#define ABCC_ABCC_HOST_H
+
+#include <cstdio>
+#include "Abcc.h"
+
+#define LOG(format, ...) do { \
+  fprintf(stderr, format, ##__VA_ARGS__); \
+  fprintf(stderr, "\n"); \
+} while(0)
+
+extern bool kVerbose;
+#define LOGE  LOG
+#define LOGV(format, ...) do {\
+  if (kVerbose) LOG(format, ##__VA_ARGS__); \
+} while(0)
+
+namespace abcc {
+
+class HostBitcodeCompiler : public BitcodeCompiler {
+  std::string mIn;
+  std::string mOut;
+  std::string mNDKDir;  // empty string if standalone mode
+  std::string mPlatform;
+  std::string mToolchainBinPath;  // Used at ndk mode to prevent tedious path issue
+
+public:
+  HostBitcodeCompiler(const std::string &abi, const std::string &sysroot,
+                      const std::string &input, const std::string &output, const std::string &working_dir,
+                      const std::string &platform);
+  HostBitcodeCompiler(const std::string &abi, const std::string &sysroot, const std::string &ndk_dir, const std::string &toolchain_bin,
+                      const std::string &input, const std::string &output, const std::string &working_dir,
+                      const std::string &platform);
+
+public:
+  virtual int parseLDFlags(BitcodeInfo &info, const std::string &str);
+
+private:
+  virtual void getBitcodeFiles();
+  virtual void prepareToolchain();
+  virtual void copyRuntime(const BitcodeInfo &info);
+  virtual void removeIntermediateFile(const std::string &path);
+
+private:
+  const std::string getToolchainBinPath() const;
+  const std::string getCompilerRTPath() const;
+  const std::string getGAbixxPath() const;
+  const std::string getLibPortablePath() const;
+};
+
+} // namespace abcc
+
+#endif
diff --git a/tests/abcc/jni/host/main.cpp b/tests/abcc/jni/host/main.cpp
new file mode 100644
index 0000000..95a07c8
--- /dev/null
+++ b/tests/abcc/jni/host/main.cpp
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <memory>
+#include <unistd.h>
+#include "Abcc_host.h"
+using namespace abcc;
+
+static int parseArguments(char **argv,
+                           std::string &abi, std::string &ndk_dir, std::string &sysroot,
+                           std::string &input, std::string &output, std::string &platform) {
+  unsigned idx = 1;
+  while (argv[idx] != 0) {
+    std::string arg = argv[idx++];
+    if (arg.find("--abi=") != std::string::npos) {
+      abi = arg.substr(arg.rfind('=')+1);
+      continue;
+    }
+    if (arg.find("--ndk-dir=") != std::string::npos) {
+      ndk_dir = arg.substr(arg.rfind('=')+1);
+      continue;
+    }
+    if (arg.find("--sysroot=") != std::string::npos) {
+      sysroot = arg.substr(arg.rfind('=')+1);
+      continue;
+    }
+    if (arg.find("--platform=") != std::string::npos) {
+      platform = arg.substr(arg.rfind('=')+1);
+      continue;
+    }
+    if (arg.find("--file") != std::string::npos) {
+      input = argv[idx++];
+      output = argv[idx++];
+      continue;
+    }
+    if (arg == "--verbose") {
+      kVerbose = true;
+      continue;
+    }
+
+    LOGE("Unsupport argument: %s", arg.c_str());
+    return -1;
+  }
+  return 0;
+}
+
+int main(int argc, char **argv) {
+  char buf[256] = {'\0'};
+  std::string this_bin = argv[0];
+  std::string cwd;
+  if (getcwd(buf, 256))
+    cwd = buf;
+  else {
+    LOGE("getcwd failed");
+    return -1;
+  }
+  std::string abi;
+  std::string ndk_dir;
+  std::string sysroot;
+  std::string input;
+  std::string output;
+  std::string platform;
+  std::string working_dir;
+  std::string toolchain_bin;
+
+  if (parseArguments(argv,
+                     abi, ndk_dir, sysroot, input, output, platform) != 0)
+    return -1;
+
+  // Make sure they are absolute path
+  if (this_bin[0] != '/')
+    this_bin = cwd + "/" + this_bin;
+  if (input[0] != '/')
+    input = cwd + "/" + input;
+  if (output[0] != '/')
+    output = cwd + "/" + output;
+
+  toolchain_bin = this_bin.substr(0, this_bin.rfind('/'));
+  working_dir = input.substr(0, input.rfind('/'));
+  if (platform.empty()) // Folow ndk-bc2native.py usage
+    platform = "android-9";
+
+  if (abi.empty() || input.empty() || output.empty() || toolchain_bin.empty() || platform.empty()) {
+    LOGE("Argument out-of-expect.");
+    return -1;
+  }
+
+  if (sysroot.empty() && ndk_dir.empty()) {
+    LOGE("Must be either standalone or ndk mode");
+    return -1;
+  }
+
+  if (sysroot.empty()) {
+    // NDK mode
+    sysroot = ndk_dir + "/platforms/" + platform + "/arch-" + TargetAbi(abi).getArch();
+  }
+
+
+  std::auto_ptr<BitcodeCompiler> compiler;
+  if (ndk_dir.empty())
+    compiler.reset(new HostBitcodeCompiler(abi, sysroot,
+                                           input, output,
+                                           working_dir, platform));
+  else
+    compiler.reset(new HostBitcodeCompiler(abi, sysroot, ndk_dir, toolchain_bin,
+                                           input, output,
+                                           working_dir, platform));
+
+  compiler->prepare();
+  if (compiler->returnCode() != RET_OK) {
+    LOGE("prepare failed");
+    return -1;
+  }
+
+  compiler->cleanupPre();
+  if (compiler->returnCode() != RET_OK) {
+    LOGE("cleanupPre failed");
+    return -1;
+  }
+
+  compiler->execute();
+  compiler->cleanupPost();
+
+  if (compiler->returnCode() != RET_OK) {
+    LOGE("execution failed");
+    return -1;
+  }
+
+  return 0;
+}
diff --git a/tests/abcc/jni/main.cpp b/tests/abcc/jni/main.cpp
deleted file mode 100644
index 69d200d..0000000
--- a/tests/abcc/jni/main.cpp
+++ /dev/null
@@ -1,690 +0,0 @@
-/*
- * Copyright 2013, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <jni.h>
-#include <android/log.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <list>
-#include <map>
-#include <string>
-#include <utility>
-#include <vector>
-#include <fstream>
-#include <sstream>
-#include <pthread.h>
-#include <sys/stat.h>
-#if ENABLE_PARALLEL_LLVM_CG
-#include <cpu-features.h>
-#endif
-#if VERBOSE
-#include <sys/time.h>
-#endif
-
-#define LOG_TAG "AbccNative"
-#define LOGE(format, ...)  do {\
-  __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, format, ##__VA_ARGS__);\
-  } while(0)
-#define LOGI(format, ...)  do {\
-  __android_log_print(ANDROID_LOG_INFO, LOG_TAG, format, ##__VA_ARGS__);\
-  } while(0)
-#define LOGV(format, ...)  do {\
-  __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, format, ##__VA_ARGS__);\
-  } while(0)
-
-
-enum TargetAbi {
-  abi_armeabi = 0,
-  abi_armeabi_v7a,
-  abi_x86,
-  abi_mips,
-};
-
-#if defined(__arm__) && defined(__ARM_ARCH_7A__)
-TargetAbi abi = abi_armeabi_v7a;
-#elif defined(__arm__)
-TargetAbi abi = abi_armeabi;
-#elif defined(__i386__)
-TargetAbi abi = abi_x86;
-#elif defined(__mips__)
-TargetAbi abi = abi_mips;
-#else
-# error "Unsupport target"
-#endif
-
-enum TargetFieldID {
-  target_arch = 0,
-  target_triple = 1,
-  target_emulation = 2,
-  target_extra_cflags = 3,
-  target_extra_ldflags = 4,
-};
-
-const char* target_data[4][5] = {
-  {"arm", "armv5te-linux-androideabi", "armelf_linux_eabi", "", ""},
-  {"arm", "thumbv7-linux-androideabi", "armelf_linux_eabi", "", ""},
-  {"x86", "i686-linux-android", "elf_i386", "-disable-fp-elim -force-align-stack -mattr=-ssse3,-sse41,-sse42,-sse4a,-popcnt", ""},
-  {"mips", "mipsel-linux-android", "elf32ltsmip", "", ""},
-};
-
-enum ExecutableFieldID {
-  exec_translate = 0,
-  exec_llc = 1,
-  exec_ld = 2,
-};
-
-const unsigned NUM_THREADS = 1;
-const char *lib_dir;
-const char *sysroot;
-
-// Use std::list to easily keep validity while erase
-typedef std::vector<std::string> LDFlagsTy;
-typedef std::list<std::string> LibsDependedTy;
-
-struct BitcodeInfoTy {
-  BitcodeInfoTy() {}
-  BitcodeInfoTy(const std::string &bitcode)
-    : mBitcode(bitcode), mShared(false) {}
-
-  std::string mBitcode;
-  std::string mSOName;
-  LDFlagsTy mLDFlags;
-  LibsDependedTy mLDLibs; // Will be removed again and again until empty while removeExternalLDLibs
-  std::string mLDLibsStr; // Immutable once read in
-  bool mShared;
-};
-
-typedef std::map<std::string/*soname*/, BitcodeInfoTy> SONameMapTy;
-
-void swapEndian(unsigned char *buffer, size_t n) {
-  for (size_t i = 0; i < n/2; ++i) {
-    char tmp = buffer[i];
-    buffer[i] = buffer[n-i-1];
-    buffer[n-i-1] =tmp;
-  }
-}
-
-int transferBytesToNum(const unsigned char *buffer, size_t n) {
-  int ret = 0;
-  for (size_t i = 0; i < n; ++i) {
-    ret = ret * 0x100 + buffer[i];
-  }
-  return ret;
-}
-
-class Timer
-{
-  private:
-    struct timeval _t0;
-  public:
-    Timer() {};
-    void start() { gettimeofday(&_t0, NULL); }
-    long long stop() {
-      struct timeval t;
-      gettimeofday(&t, NULL);
-      long long l0 = _t0.tv_sec * 1000000LL + _t0.tv_usec;
-      long long l = t.tv_sec * 1000000LL + t.tv_usec;
-      return l - l0;
-    }
-};
-
-/*
-  The bitcode wrapper definition:
-
-  struct AndroidBitcodeWrapper {
-    uint32_t Magic;
-    uint32_t Version;
-    uint32_t BitcodeOffset;
-    uint32_t BitcodeSize;
-    uint32_t HeaderVersion;
-    uint32_t TargetAPI;
-    uint32_t PNaClVersion;
-    uint16_t CompilerVersionTag;
-    uint16_t CompilerVersionLen;
-    uint32_t CompilerVersion;
-    uint16_t OptimizationLevelTag;
-    uint16_t OptimizationLevelLen;
-    uint32_t OptimizationLevel;
-  };
-*/
-
-int parseLDFlags(BitcodeInfoTy &info, std::string& ldflags) {
-
-  if (info.mBitcode.empty()) {
-    LOGE("Must set bitcode name before parseLDFlags.");
-    return 1;
-  }
-
-  info.mSOName = info.mBitcode.substr(info.mBitcode.rfind("/") + 1);
-  info.mLDFlags.clear();
-  info.mLDLibs.clear();
-  info.mLDLibsStr.clear();
-
-  std::stringstream ss(ldflags);
-  std::string str;
-
-  while (ss >> str) {
-    if (str.find("--sysroot") != std::string::npos) {
-      continue; // Ignore on-host sysroot
-    }
-    if (str == "-o") {  // Ignore on-host output path
-      ss >> str;
-      continue;
-    }
-    if (str == "-soname") {  // Ignore on-host output path
-      ss >> str;
-      info.mSOName = str;
-      continue;
-    }
-    if (str.substr(0, 2) == "-l") {
-      info.mLDLibs.push_back(str.substr(2));
-      info.mLDLibsStr += std::string(" ") + str;
-      continue;
-    }
-    if (str == "-shared") {
-      info.mShared = true;
-      continue;
-    }
-    if (str.size() > 2 &&
-        str.substr(str.size()-2) == ".a") {
-      str = str.substr(0, str.size()-2);
-      str = str.substr(str.rfind("/") + 4);
-      str = std::string("-l") + str;
-    }
-    if (str.size() > 3 &&
-        str.substr(str.size()-3) == ".so") {
-      str = str.substr(0, str.size()-3);
-      str = str.substr(str.rfind("/") + 4);
-      str = std::string("-l") + str;
-    }
-
-    info.mLDFlags.push_back(str);
-  }
-  return 0;
-}
-
-int readWrapper(BitcodeInfoTy &info) {
-  if (info.mBitcode.empty()) {
-    LOGE("Must set bitcode name before readWrapper.");
-    return 1;
-  }
-  info.mSOName = info.mBitcode.substr(info.mBitcode.rfind("/") + 1);
-  info.mLDFlags.clear();
-  info.mLDLibs.clear();
-  info.mLDLibsStr.clear();
-
-  const char *bc = info.mBitcode.c_str();
-  LOGI("Read wrapper for bitcode: %s", bc);
-  int fd = open(bc, O_RDONLY);
-  unsigned char buffer[5] = {'\0', '\0', '\0', '\0', '\0'};
-  read(fd, buffer, 4);  // magic
-  swapEndian(buffer, 4);
-  int magic = transferBytesToNum(buffer, 4);
-  if (magic != 0x0b17c0de) {
-    LOGE("Wrong bitcode wrapper");
-    close(fd);
-    return 1;
-  }
-  read(fd, buffer, 4);  // version
-  read(fd, buffer, 4);  // offset
-  swapEndian(buffer, 4);
-  int offset = transferBytesToNum(buffer, 4);
-  lseek(fd, 4*7, SEEK_SET);
-  offset -= 4*7;  // skip
-  while (offset > 0) {
-    read(fd, buffer, 4);
-    swapEndian(buffer, 4);
-    uint16_t length = transferBytesToNum(buffer, 2);
-    uint16_t tag = transferBytesToNum(buffer+2, 2);
-    LOGI("length: %d", length);
-    LOGI("tag: %d", tag);
-    length = (length + 3) & ~3;
-
-    unsigned char *large_buffer = (unsigned char*) malloc(length+1);
-    large_buffer[length] = '\0';
-    int n = read(fd, large_buffer, length);
-    if (n != length) {
-      LOGE("Read bitcode data error");
-      close(fd);
-      return 1;
-    }
-    if (tag == 0x5001) {
-      swapEndian(large_buffer, length);
-      int type = transferBytesToNum(large_buffer, length);
-      if (type == /*shared=*/1) {
-        info.mShared = true;
-      }
-    } else if (tag == 0x5002) {
-      std::string ldflags = reinterpret_cast<char*>(large_buffer);
-      parseLDFlags(info,ldflags);
-    } else {
-      // Other field, just omit
-    }
-    offset -= (length + 4);
-    free(large_buffer);
-  }
-  close(fd);
-  return 0;
-}
-
-int handleTask(const std::string &cmd, bool write_err_msg = false) {
-#if VERBOSE
-  LOGV("Command: %s", cmd.c_str());
-#endif
-  int ret;
-  std::string logfilename = std::string(lib_dir) + "/compile_log";
-  if (write_err_msg) {
-    std::string new_cmd = cmd + " > " + logfilename + " 2>&1";
-    ret = system(new_cmd.c_str());
-  } else {
-    ret = system(cmd.c_str());
-  }
-  if (ret != 0) {
-    LOGE("Failed command: %s", cmd.c_str());
-    if (write_err_msg) {
-      std::ifstream ifs(logfilename.c_str());
-      std::stringstream sstr;
-      sstr << ifs.rdbuf();
-
-      LOGE("Error message: %s", sstr.str().c_str());
-
-      std::fstream fout;
-      std::string file = std::string(lib_dir) + "/compile_error";
-      fout.open(file.c_str(), std::fstream::out | std::fstream::app);
-      fout << "Failed command: " << cmd << "\n";
-      fout << "Error message: " << sstr.str() << "\n";
-      fout.close();
-    }
-  }
-  return ret;
-}
-
-int getFilesFromDir(const char *dir, std::vector<std::string> &files) {
-  files.clear();
-  DIR *dp = opendir(dir);
-  if (!dp)  return 1;
-
-  struct dirent *entry = 0;
-  while ((entry = readdir(dp)) != 0) {
-    std::string filename(entry->d_name);
-    if (filename == "." || filename == "..")
-      continue;
-
-    std::string full_path = std::string(dir) + "/" + filename;
-    int fd = open(full_path.c_str(), O_RDONLY);
-    if (fd < 0) {
-      LOGE("Error opening file: %s", full_path.c_str());
-      continue;
-    }
-    unsigned char buffer[4];
-    read(fd, buffer, 4);  // magic
-    close(fd);
-    swapEndian(buffer, 4);
-    int magic = transferBytesToNum(buffer, 4);
-
-    if (magic != 0x0b17c0de) {
-      LOGI("Found file %s magic: %x, but we need: %x (Ignored)", full_path.c_str(), magic, 0x0b17c0de);
-      continue;
-    }
-
-    std::string stem = full_path.substr(0, full_path.rfind("."));
-    std::string lib = stem;
-    int lib_fd = open(lib.c_str(), O_RDONLY);
-    if (lib_fd >= 0) {
-      read(lib_fd, buffer, 4);  // magic
-      close(lib_fd);
-      swapEndian(buffer, 4);
-      int magic = transferBytesToNum(buffer, 4);
-      if (magic == 0x7f454c46) {
-        LOGI("Found file %s magic: %x, No compile for %s", lib.c_str(), magic, full_path.c_str());
-        continue;
-      }
-    }
-
-    lib = stem + ".so";
-    lib_fd = open(lib.c_str(), O_RDONLY);
-    if (lib_fd >= 0) {
-      read(lib_fd, buffer, 4);  // magic
-      close(lib_fd);
-      swapEndian(buffer, 4);
-      int magic = transferBytesToNum(buffer, 4);
-      if (magic == 0x7f454c46) {
-        LOGI("Found file %s magic: %x, No compile for %s", lib.c_str(), magic, full_path.c_str());
-        continue;
-      }
-    }
-
-    LOGI("Push back a bitcode: %s", full_path.c_str());
-    files.push_back(full_path);
-  }
-  closedir(dp);
-  return 0;
-}
-
-void removeExternalLDLibs(SONameMapTy &soname_map) {
-  for (SONameMapTy::iterator i = soname_map.begin(), e = soname_map.end();
-       i != e; ++i) {
-    BitcodeInfoTy &info = i->second;
-    for (LibsDependedTy::iterator i_libs = info.mLDLibs.begin(),
-         e_libs = info.mLDLibs.end(); i_libs != e_libs; ) {
-      LibsDependedTy::iterator cur_it = i_libs;
-      ++i_libs;  // In case we remove this -l field
-      std::string full_soname = std::string("lib") + *cur_it + ".so";
-      if (soname_map.find(full_soname) == soname_map.end()) {
-        LOGI("Drop -l%s from %s for linking order.", (*cur_it).c_str(), info.mBitcode.c_str());
-        info.mLDLibs.erase(cur_it);
-      }
-    }
-  }
-}
-
-void *translateBitcode(void *par) {
-  std::string bc = (char*)par;
-  std::string stem = bc.substr(0, bc.rfind("."));
-  std::string target_bc = stem + "-target.bc";
-
-  /*
-   * le32-none-ndk-translate
-   */
-  std::string cmd;
-  cmd = std::string("LD_LIBRARY_PATH=") + sysroot + "/usr/lib";
-  cmd += std::string(" ") + sysroot + "/usr/bin/le32-none-ndk-translate";
-  cmd += std::string(" -arch=") + target_data[abi][target_arch];
-  cmd += std::string(" -o ") + target_bc;
-  cmd += std::string(" ") + bc;
-
-  int ret = handleTask(cmd, true/*write_err_msg*/);
-  if (ret != 0) {
-    LOGE("Cannot translate bitcode (%s): %s", bc.c_str(), cmd.c_str());
-  } else {
-#ifdef NDEBUG
-    handleTask(std::string("rm -f ") + bc);
-#endif
-  }
-  return (void*)ret;
-}
-
-void *compileBitcode(void *par) {
-  std::string bc = (char*)par;
-  std::string stem = bc.substr(0, bc.rfind("."));
-  std::string target_bc = stem + "-target.bc";
-  std::string obj = stem + ".o";
-
-  /*
-   * llc
-   */
-  std::string cmd;
-  cmd = std::string("LD_LIBRARY_PATH=") + sysroot + "/usr/lib";
-  cmd += std::string(" ") + sysroot + "/usr/bin/llc";
-  cmd += std::string(" -mtriple=") + target_data[abi][target_triple];
-#if defined(__arm__)
-  cmd += std::string(" -arm-enable-ehabi -arm-enable-ehabi-descriptors");
-#endif
-  cmd += " -filetype=obj -relocation-model=pic -code-model=small";
-  cmd += " -use-init-array -mc-relax-all -O2";
-#if defined(__arm__)
-  cmd += " -float-abi=soft";
-#endif
-#if ENABLE_PARALLEL_LLVM_CG
-  std::ostringstream stream;
-  stream << android_getCpuCount();
-  cmd += " -thread=" + stream.str();
-#endif
-  cmd += std::string(" ") + target_data[abi][target_extra_cflags];
-  cmd += std::string(" -o ") + obj;
-  cmd += std::string(" ") + target_bc;
-
-  int ret = handleTask(cmd, true/*write_err_msg*/);
-  if (ret != 0) {
-    LOGE("Cannot compile bitcode (%s): %s", bc.c_str(), cmd.c_str());
-  } else {
-#ifdef NDEBUG
-    handleTask(std::string("rm -f ") + target_bc);
-#endif
-  }
-  return (void*)ret;
-}
-
-int linkBitcode(const BitcodeInfoTy &info) {
-  std::string stem(info.mBitcode);
-  stem = stem.substr(0, stem.rfind("."));
-  std::string obj = stem + ".o";
-  std::string lib = stem;
-  if (info.mShared) {
-    lib += ".so";
-  }
-
-  /*
-   * ld.mcld
-   */
-  handleTask(std::string("rm -f ") + lib);
-  std::string cmd;
-  cmd = std::string("LD_LIBRARY_PATH=") + sysroot + "/usr/lib";
-  cmd += std::string(" ") + sysroot + "/usr/bin/ld.mcld";
-  cmd += std::string(" --sysroot=") + sysroot;
-  if (info.mShared) {
-    cmd += " -shared";
-  }
-  cmd += " -eh-frame-hdr -dynamic-linker /system/bin/linker";
-  cmd += std::string(" -X -m ") + target_data[abi][target_emulation];
-  cmd += std::string(" ") + target_data[abi][target_extra_ldflags];
-  if (info.mShared) {
-    cmd += std::string(" ") + sysroot + "/usr/lib/crtbegin_so.o";
-  } else {
-    cmd += std::string(" ") + sysroot + "/usr/lib/crtbegin_dynamic.o";
-  }
-  if (info.mSOName != "") {
-    cmd += std::string(" -soname ") + info.mSOName;
-  }
-  cmd += std::string(" ") + obj;
-  cmd += std::string(" @") + sysroot + "/usr/lib/libportable.wrap " + sysroot + "/usr/lib/libportable.a";
-  cmd += std::string(" -L/system/lib");
-  cmd += std::string(" -L") + lib_dir;
-  cmd += std::string(" -L") + sysroot + "/usr/lib";
-  for (LDFlagsTy::const_iterator i = info.mLDFlags.begin(), e = info.mLDFlags.end();
-       i != e; ++i) {
-    cmd += std::string(" ") + *i;
-  }
-  // TODO: If this module needs libfoo.so, but since libfoo.so is not a real bitcode under
-  //       our trick, it won't be included at module.info. How did we workaround this?
-  cmd += info.mLDLibsStr;
-  // Replace libgcc by libcompiler-rt + libgabi++
-  cmd += std::string(" ") + sysroot + "/usr/lib/libcompiler_rt_static.a";
-  cmd += std::string(" ") + sysroot + "/usr/lib/libgabi++_shared.so";
-  cmd += std::string(" -ldl");
-
-  if (info.mShared) {
-    cmd += std::string(" ") + sysroot + "/usr/lib/crtend_so.o";
-  } else {
-    cmd += std::string(" ") + sysroot + "/usr/lib/crtend_android.o";
-  }
-  cmd += std::string(" -o ") + lib;
-
-  int ret = handleTask(cmd, true/*write_err_msg*/);
-  if (ret != 0) {
-    LOGE("Cannot link bitcode (%s): %s", info.mBitcode.c_str(), cmd.c_str());
-  } else {
-    handleTask(std::string("chmod 0755 ") + lib);
-#ifdef NDEBUG
-    handleTask(std::string("rm -f ") + obj);
-#endif
-  }
-  return ret;
-}
-
-int prepareRuntime(const BitcodeInfoTy &info) {
-  std::stringstream ss(info.mLDLibsStr);
-  std::string deplibs;
-
-  while (ss >> deplibs) {
-    if (deplibs.substr(0,2) == "-l") {
-      std::string libname = "lib" + deplibs.substr(2) + ".so";
-      std::string full_lib_path = std::string(sysroot) + "/usr/lib/" + libname;
-      struct stat buf;
-      // runtime found
-      if (stat(full_lib_path.c_str(),&buf) == 0) {
-        handleTask("cp -p " + full_lib_path + " " + lib_dir + "/" + libname);
-      }
-    }
-  }
-  return 0;
-}
-
-int genLibs(const char *lib_dir, const char *sysroot) {
-  jint ret = 0;
-
-  std::vector<std::string/*bitcode*/> files;
-  ret = getFilesFromDir(lib_dir, files);
-  if (ret != 0 || files.empty()) {
-    LOGE("Cannot get files from directory: %s", lib_dir);
-    return ret;
-  }
-
-  // Read bitcode wrapper information
-  std::vector<BitcodeInfoTy> bc_infos;
-  for (std::vector<std::string>::const_iterator i = files.begin(),
-       e = files.end(); i != e; ++i) {
-    const std::string &bitcode = *i;
-    BitcodeInfoTy bc_info(bitcode);
-    ret = readWrapper(bc_info);
-    if (ret != 0) {
-      LOGE("Cannot read wrapper for bitcodes.");
-      return ret;
-    }
-    bc_infos.push_back(bc_info);
-  }
-
-  // Create mapping from soname to info
-  SONameMapTy soname_map;
-  for (std::vector<BitcodeInfoTy>::const_iterator i = bc_infos.begin(),
-       e = bc_infos.end(); i != e; ++i) {
-    const BitcodeInfoTy &info = *i;
-    LOGI("Link relationship: %s -> %s (BitcodeInfo)",
-         info.mSOName.c_str(), info.mBitcode.c_str());
-    soname_map[info.mSOName] = info;
-  }
-
-  // Run translate and compile in parallel
-  pthread_t tid[NUM_THREADS];
-
-  // Translate
-  for (std::vector<BitcodeInfoTy>::const_iterator i = bc_infos.begin(),
-       e = bc_infos.end(); i < e; i += NUM_THREADS) {
-    unsigned thread_i;
-    for (thread_i = 0; thread_i < NUM_THREADS; ++thread_i) {
-      if (i + thread_i == e) {
-        break;
-      }
-      const BitcodeInfoTy &info = *(i + thread_i);
-      pthread_create(&tid[thread_i], 0, translateBitcode, (void*)info.mBitcode.c_str());
-    }
-
-    for (unsigned count = 0; count < thread_i; ++count) {
-      pthread_join(tid[count], 0);
-    }
-  }
-
-  // Compile
-  for (std::vector<BitcodeInfoTy>::const_iterator i = bc_infos.begin(),
-       e = bc_infos.end(); i < e; i += NUM_THREADS) {
-    unsigned thread_i;
-    for (thread_i = 0; thread_i < NUM_THREADS; ++thread_i) {
-      if (i + thread_i == e) {
-        break;
-      }
-      const BitcodeInfoTy &info = *(i + thread_i);
-      pthread_create(&tid[thread_i], 0, compileBitcode, (void*)info.mBitcode.c_str());
-    }
-
-    for (unsigned count = 0; count < thread_i; ++count) {
-      pthread_join(tid[count], 0);
-    }
-  }
-
-  // Only linking needs sequential
-  // Remove external ldlibs for topological traverse (linking order)
-  removeExternalLDLibs(soname_map);
-
-  while (!soname_map.empty()) {
-    SONameMapTy::iterator i = soname_map.begin(), e = soname_map.end();
-    for (; i != e; ++i) {
-      BitcodeInfoTy &info = i->second;
-
-      if (info.mLDLibs.empty()) {
-        // No internal dependency for this bitcode
-        LOGI("Process bitcode: %s -> %s", info.mBitcode.c_str(), info.mSOName.c_str());
-        prepareRuntime(info);
-        ret = linkBitcode(info);
-        if (ret != 0) {
-          LOGE("Process bitcode failed on %s!", info.mBitcode.c_str());
-        }
-
-        soname_map.erase(i);
-        removeExternalLDLibs(soname_map);
-        break;
-      }
-    }
-
-    if (i == e) {
-      LOGE("Failed to compute linking order: Internal cyclic dependency!");
-      return 1;
-    }
-  }
-
-  return ret; //unused
-}
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-JNIEXPORT jint JNICALL
-Java_compiler_abcc_AbccService_genLibs(JNIEnv *env, jobject thiz,
-                                       jstring j_lib_dir, jstring j_sysroot) {
-  lib_dir = env->GetStringUTFChars(j_lib_dir, 0);
-  LOGI("Working directory: %s", lib_dir);
-
-  sysroot = env->GetStringUTFChars(j_sysroot, 0);
-  LOGI("Sysroot: %s", sysroot);
-
-  handleTask(std::string("rm -f ") + lib_dir + "/compile_error");
-#if VERBOSE
-  Timer t; t.start();
-#endif
-  genLibs(lib_dir, sysroot);
-#if VERBOSE
-  long long elapsed_msec = (t.stop() + 500) / 1000;
-  LOGV("Elapsed time: %lld.%03ds", elapsed_msec/1000, (int)elapsed_msec%1000);
-#endif
-  handleTask(std::string("cp -p ") + sysroot + "/usr/lib/libgabi++_shared.so " + lib_dir + "/libgabi++_shared.so");
-
-  handleTask(std::string("rm -f ") + lib_dir + "/compile_log");
-  if (handleTask(std::string("ls ") + lib_dir + "/compile_error") != 0) {
-    handleTask(std::string("echo 0 > ") + lib_dir + "/compile_result");
-    handleTask(std::string("chmod 0644 ") + lib_dir + "/compile_result");
-    return 0;
-  } else {
-    handleTask(std::string("echo 56 > ") + lib_dir + "/compile_result");
-    handleTask(std::string("chmod 0644 ") + lib_dir + "/compile_result");
-    handleTask(std::string("chmod 0644 ") + lib_dir + "/compile_error");
-    return 56;
-  }
-}
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
diff --git a/tests/run-tests.sh b/tests/run-tests.sh
index 278ec21..67d97ae 100755
--- a/tests/run-tests.sh
+++ b/tests/run-tests.sh
@@ -792,7 +792,7 @@
             fi
         fi
         if [ "$ABI" = "$(find_ndk_unknown_archs)" ] && [ -d "$BUILD_DIR/`basename $TEST`/libs" ]; then
-            cd $BUILD_DIR/`basename $TEST`/libs && ln -s $ABI $CPU_ABI
+            cd $BUILD_DIR/`basename $TEST`/libs && cp -a $ABI $CPU_ABI
         fi
         SRCDIR="$BUILD_DIR/`basename $TEST`/libs/$CPU_ABI"
         if [ ! -d "$SRCDIR" ] || [ -z "`ls $SRCDIR`" ]; then
diff --git a/toolchains/llvm-3.3/setup-common.mk b/toolchains/llvm-3.3/setup-common.mk
index 79c2ec1..6126d5f 100644
--- a/toolchains/llvm-3.3/setup-common.mk
+++ b/toolchains/llvm-3.3/setup-common.mk
@@ -28,7 +28,12 @@
 # Compiler runtime is determined in bc2native
 TARGET_LIBGCC :=
 
+# Only use integrated binary if existed. Otherwise, use python version
+ifeq (,$(wildcard $(TOOLCHAIN_PREBUILT_ROOT)/bin/ndk-bc2native))
 BC2NATIVE := $(HOST_PYTHON) $(TOOLCHAIN_PREBUILT_ROOT)/bin/ndk-bc2native.py
+else
+BC2NATIVE := $(TOOLCHAIN_PREBUILT_ROOT)/bin/ndk-bc2native$(HOST_EXEEXT)
+endif
 
 TARGET_CFLAGS := \
     -target $(LLVM_TRIPLE) \