gn build: Add a stage2 toolchain for Android.

This makes it possible to build llvm-symbolizer for Android, which
is one of the prerequisites for running the sanitizer tests on Android.

Differential Revision: https://reviews.llvm.org/D56577

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@350979 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/utils/gn/build/BUILDCONFIG.gn b/utils/gn/build/BUILDCONFIG.gn
index 1e5af9a..a46725c 100644
--- a/utils/gn/build/BUILDCONFIG.gn
+++ b/utils/gn/build/BUILDCONFIG.gn
@@ -25,6 +25,13 @@
   configs = shared_binary_target_configs
 }
 
+if (target_os == "") {
+  target_os = host_os
+}
+if (current_os == "") {
+  current_os = target_os
+}
+
 if (host_os == "win") {
   host_toolchain = "//llvm/utils/gn/build/toolchain:win"
 } else {
diff --git a/utils/gn/build/libs/pthread/BUILD.gn b/utils/gn/build/libs/pthread/BUILD.gn
index 51e7f1f..7708d31 100644
--- a/utils/gn/build/libs/pthread/BUILD.gn
+++ b/utils/gn/build/libs/pthread/BUILD.gn
@@ -6,7 +6,8 @@
 }
 
 group("pthread") {
-  if (llvm_enable_threads && host_os != "win") {
+  # On Android, bionic has built-in support for pthreads.
+  if (llvm_enable_threads && current_os != "win" && current_os != "android") {
     public_configs = [ ":pthread_config" ]
   }
 }
diff --git a/utils/gn/build/toolchain/BUILD.gn b/utils/gn/build/toolchain/BUILD.gn
index c53f753..87276ea 100644
--- a/utils/gn/build/toolchain/BUILD.gn
+++ b/utils/gn/build/toolchain/BUILD.gn
@@ -12,10 +12,16 @@
 template("unix_toolchain") {
   toolchain(target_name) {
     forward_variables_from(invoker, "*")
+    if (!defined(target_cflags)) {
+      target_cflags = ""
+    }
+    if (!defined(target_ldflags)) {
+      target_ldflags = ""
+    }
 
     tool("cc") {
       depfile = "{{output}}.d"
-      command = "$cc -MMD -MF $depfile -o {{output}} -c {{source}} {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}}"
+      command = "$cc -MMD -MF $depfile -o {{output}} -c {{source}} {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} $target_cflags"
       depsformat = "gcc"
       description = "CC {{output}}"
       outputs = [
@@ -25,7 +31,7 @@
 
     tool("cxx") {
       depfile = "{{output}}.d"
-      command = "$cxx -MMD -MF $depfile -o {{output}} -c {{source}} {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}}"
+      command = "$cxx -MMD -MF $depfile -o {{output}} -c {{source}} {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} $target_cflags"
       depsformat = "gcc"
       description = "CXX {{output}}"
       outputs = [
@@ -39,7 +45,8 @@
       } else {
         # Remove the output file first so that ar doesn't try to modify the
         # existing file.
-        command = "rm -f {{output}} && $ar rcsDT {{arflags}} {{output}} {{inputs}}"
+        command =
+            "rm -f {{output}} && $ar rcsDT {{arflags}} {{output}} {{inputs}}"
       }
       description = "AR {{output}}"
       outputs = [
@@ -52,11 +59,10 @@
     tool("solink") {
       outfile = "{{output_dir}}/{{target_output_name}}{{output_extension}}"
       if (current_os == "mac") {
-        command = "$ld -shared {{ldflags}} -o $outfile {{libs}} {{inputs}}"
+        command = "$ld -shared {{ldflags}} -o $outfile {{libs}} {{inputs}} $target_ldflags"
         default_output_extension = ".dylib"
       } else {
-        command =
-            "$ld -shared {{ldflags}} -Wl,-z,defs -o $outfile {{libs}} {{inputs}}"
+        command = "$ld -shared {{ldflags}} -Wl,-z,defs -o $outfile {{libs}} {{inputs}} $target_ldflags"
         default_output_extension = ".so"
       }
       description = "SOLINK $outfile"
@@ -71,10 +77,10 @@
     tool("solink_module") {
       outfile = "{{output_dir}}/{{target_output_name}}{{output_extension}}"
       if (current_os == "mac") {
-        command = "$ld -shared {{ldflags}} -Wl,-flat_namespace -Wl,-undefined,suppress -o $outfile {{libs}} {{inputs}}"
+        command = "$ld -shared {{ldflags}} -Wl,-flat_namespace -Wl,-undefined,suppress -o $outfile {{libs}} {{inputs}} $target_ldflags"
         default_output_extension = ".dylib"
       } else {
-        command = "$ld -shared {{ldflags}} -o $outfile {{libs}} {{inputs}}"
+        command = "$ld -shared {{ldflags}} -o $outfile {{libs}} {{inputs}} $target_ldflags"
         default_output_extension = ".so"
       }
       description = "SOLINK $outfile"
@@ -88,9 +94,10 @@
     tool("link") {
       outfile = "{{output_dir}}/{{target_output_name}}{{output_extension}}"
       if (current_os == "mac") {
-        command = "$ld {{ldflags}} -o $outfile {{libs}} {{inputs}}"
+        command =
+            "$ld {{ldflags}} -o $outfile {{libs}} {{inputs}} $target_ldflags"
       } else {
-        command = "$ld {{ldflags}} -o $outfile {{libs}} -Wl,--start-group {{inputs}} -Wl,--end-group"
+        command = "$ld {{ldflags}} -o $outfile {{libs}} -Wl,--start-group {{inputs}} -Wl,--end-group $target_ldflags"
       }
       description = "LINK $outfile"
       outputs = [
@@ -137,6 +144,37 @@
   }
 }
 
+if (android_ndk_path != "") {
+  unix_toolchain("stage2_android_aarch64") {
+    cc = "bin/clang"
+    cxx = "bin/clang++"
+    ld = cxx
+    ar = "bin/llvm-ar"
+
+    deps = [
+      "//:clang($host_toolchain)",
+      "//:lld($host_toolchain)",
+      "//:llvm-ar($host_toolchain)",
+    ]
+
+    toolchain_args = {
+      current_os = "android"
+    }
+
+    libcxx_path = "$android_ndk_path/sources/cxx-stl/llvm-libc++"
+    platform_lib_path =
+        "$android_ndk_path/platforms/android-21/arch-arm64/usr/lib"
+    libgcc_path = "$android_ndk_path/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/lib/gcc/aarch64-linux-android/4.9.x"
+
+    target_flags =
+        "--target=aarch64-linux-android21 --sysroot=$android_ndk_path/sysroot"
+    target_cflags = "$target_flags -isystem $libcxx_path/include"
+    target_ldflags = "$target_flags -fuse-ld=lld -B$platform_lib_path -L$platform_lib_path -L$libgcc_path"
+    target_ldflags +=
+        " -nostdlib++ -L$libcxx_path/libs/arm64-v8a -l:libc++.a.21"
+  }
+}
+
 toolchain("win") {
   cl = "cl"
   link = "link"
diff --git a/utils/gn/build/toolchain/compiler.gni b/utils/gn/build/toolchain/compiler.gni
index 92d965e..c7e89b3 100644
--- a/utils/gn/build/toolchain/compiler.gni
+++ b/utils/gn/build/toolchain/compiler.gni
@@ -9,6 +9,10 @@
   # On Windows, setting this also causes lld-link to be used as linker.
   # Example value: getenv("HOME") + "/src/llvm-build/Release+Asserts"
   clang_base_path = ""
+
+  # Set this to the path to Android NDK r18b. If set, cross compilation targeting
+  # Android will be enabled.
+  android_ndk_path = ""
 }
 
 declare_args() {
diff --git a/utils/gn/secondary/BUILD.gn b/utils/gn/secondary/BUILD.gn
index af8f596..0aca00b 100644
--- a/utils/gn/secondary/BUILD.gn
+++ b/utils/gn/secondary/BUILD.gn
@@ -1,5 +1,6 @@
 import("//clang/lib/ARCMigrate/enable.gni")
 import("//clang/lib/StaticAnalyzer/Frontend/enable.gni")
+import("//llvm/utils/gn/build/toolchain/compiler.gni")
 
 group("default") {
   deps = [
@@ -7,6 +8,13 @@
     "//lld/test",
     "//llvm/test",
   ]
+
+  if (android_ndk_path != "") {
+    # FIXME: This should be a dependency of a test target instead of being
+    # depended on from here.
+    deps += [ "//llvm/tools/llvm-symbolizer(//llvm/utils/gn/build/toolchain:stage2_android_aarch64)" ]
+  }
+
   testonly = true
 }
 
diff --git a/utils/gn/secondary/llvm/include/llvm/Config/BUILD.gn b/utils/gn/secondary/llvm/include/llvm/Config/BUILD.gn
index 41e1a31..56cae14 100644
--- a/utils/gn/secondary/llvm/include/llvm/Config/BUILD.gn
+++ b/utils/gn/secondary/llvm/include/llvm/Config/BUILD.gn
@@ -128,7 +128,7 @@
     "LLVM_DEFAULT_TARGET_TRIPLE=$llvm_target_triple",
   ]
 
-  if (host_os == "linux") {
+  if (current_os == "linux" || current_os == "android") {
     values += [
       "HAVE_FUTIMENS=1",
       "HAVE_LINK_H=1",
@@ -138,7 +138,6 @@
       "HAVE_SCHED_GETAFFINITY=1",
       "HAVE_CPU_COUNT=1",
       "HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC=1",
-      "HAVE_VALGRIND_VALGRIND_H=1",
     ]
   } else {
     values += [
@@ -150,11 +149,16 @@
       "HAVE_SCHED_GETAFFINITY=",
       "HAVE_CPU_COUNT=",
       "HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC=",
-      "HAVE_VALGRIND_VALGRIND_H=",
     ]
   }
 
-  if (host_os == "mac") {
+  if (current_os == "linux") {
+    values += [ "HAVE_VALGRIND_VALGRIND_H=1" ]
+  } else {
+    values += [ "HAVE_VALGRIND_VALGRIND_H=" ]
+  }
+
+  if (current_os == "mac") {
     values += [
       "HAVE_CRASHREPORTER_INFO=1",
       "HAVE_DECL_ARC4RANDOM=1",
@@ -178,9 +182,22 @@
     ]
   }
 
-  if (host_os == "win") {
+  if (current_os == "linux" || current_os == "mac") {
+    values += [
+      "HAVE_BACKTRACE=1",
+      "HAVE_POSIX_SPAWN=1",
+      "HAVE_PTHREAD_GETNAME_NP=1",
+    ]
+  } else {
     values += [
       "HAVE_BACKTRACE=",
+      "HAVE_POSIX_SPAWN=",
+      "HAVE_PTHREAD_GETNAME_NP=",
+    ]
+  }
+
+  if (current_os == "win") {
+    values += [
       "HAVE_DECL_STRERROR_S=1",
       "HAVE_DLFCN_H=",
       "HAVE_DLOPEN=",
@@ -190,10 +207,8 @@
       "HAVE_GETRUSAGE=",
       "HAVE_ISATTY=",
       "HAVE_LIBPTHREAD=",
-      "HAVE_PTHREAD_GETNAME_NP=",
       "HAVE_PTHREAD_SETNAME_NP=",
       "HAVE_LIBZ=",
-      "HAVE_POSIX_SPAWN=",
       "HAVE_PREAD=",
       "HAVE_PTHREAD_GETSPECIFIC=",
       "HAVE_PTHREAD_H=",
@@ -222,7 +237,6 @@
   } else {
     # POSIX-y system defaults.
     values += [
-      "HAVE_BACKTRACE=1",
       "HAVE_DECL_STRERROR_S=",
       "HAVE_DLFCN_H=1",
       "HAVE_DLOPEN=1",
@@ -232,10 +246,8 @@
       "HAVE_GETRUSAGE=1",
       "HAVE_ISATTY=1",
       "HAVE_LIBPTHREAD=1",
-      "HAVE_PTHREAD_GETNAME_NP=1",
       "HAVE_PTHREAD_SETNAME_NP=1",
       "HAVE_LIBZ=1",
-      "HAVE_POSIX_SPAWN=1",
       "HAVE_PREAD=1",
       "HAVE_PTHREAD_GETSPECIFIC=1",
       "HAVE_PTHREAD_H=1",
@@ -263,11 +275,11 @@
     ]
   }
 
-  if (host_os == "linux") {
+  if (current_os == "linux" || current_os == "android") {
     values += [ "LTDL_SHLIB_EXT=.so" ]
-  } else if (host_os == "mac") {
+  } else if (current_os == "mac") {
     values += [ "LTDL_SHLIB_EXT=.dylib" ]
-  } else if (host_os == "win") {
+  } else if (current_os == "win") {
     values += [ "LTDL_SHLIB_EXT=.dll" ]
   }
 
@@ -328,7 +340,7 @@
     "LLVM_FORCE_ENABLE_STATS=",
   ]
 
-  if (host_os == "win") {
+  if (current_os == "win") {
     values += [ "LLVM_ON_UNIX=" ]
   } else {
     values += [ "LLVM_ON_UNIX=1" ]
@@ -361,9 +373,7 @@
     foreach(target, llvm_targets_to_build) {
       value = "$value${invoker.value}($target)\n"
     }
-    values = [
-      "${invoker.key}=$value",
-    ]
+    values = [ "${invoker.key}=$value" ]
   }
 }