Repository: bazelbuild/bazel
Issue: Support NDK r18
Labels: type: feature request
P2
team-Android

Expected release date: [September 2018](https://github.com/android-ndk/ndk/wiki#ndk-r18)

Beta 1 should be out later this month.

Roadmap: https://android.googlesource.com/platform/ndk/+/master/docs/Roadmap.md

Expected changes to Bazel:

- Remove support for non-`libc++` STLs

> libc++ has been the default for a release and has proven to be stable. It is a strict improvement over the other STLs (more features, better Clang compatibility, Apache licensed, most reliable). The fact that the NDK supports multiple STLs is a common pain point for users (it's confusing for newcomers, and it makes sharing libraries difficult because they must all use the same STL).

> Now that we have a good choice for a single STL, we‘ll remove the others. We’ll most likely move the source we have for these along with building instructions to a separate project so that people that need these for ABI compatibility reasons can continue using them, but support for these will end completely.

- Remove support for GCC

> GCC is still in the NDK today because some of gnustl's C++11 features were written such that they do not work with Clang (threading and atomics, mostly). Now that libc++ is the best choice of STL, this is no longer blocking, so GCC can be removed.

Issue comments:
Looking at this, support should be pretty simple it seems? Even almost working as-is?
Looking at the commit, never mind 😄 

Pull request review comments:

Patch that resolved the issue:
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidNdkRepositoryFunction.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidNdkRepositoryFunction.java
index c4a1d77e278593..716135552158fe 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidNdkRepositoryFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidNdkRepositoryFunction.java
@@ -211,7 +211,7 @@ public RepositoryDirectoryValue.Builder fetch(
       String hostPlatform = AndroidNdkCrosstools.getHostPlatform(ndkRelease);
       NdkPaths ndkPaths = new NdkPaths(ruleName, hostPlatform, apiLevel, ndkRelease.majorRevision);
 
-      for (StlImpl stlImpl : StlImpls.get(ndkPaths)) {
+      for (StlImpl stlImpl : StlImpls.get(ndkPaths, ndkRelease.majorRevision)) {
         CrosstoolRelease crosstoolRelease =
             ndkMajorRevision.crosstoolRelease(ndkPaths, stlImpl, hostPlatform);
         crosstoolsAndStls.add(new CrosstoolStlPair(crosstoolRelease, stlImpl));
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/AndroidNdkCrosstools.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/AndroidNdkCrosstools.java
index 8823899c055306..d595dfe5b340d2 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/AndroidNdkCrosstools.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/AndroidNdkCrosstools.java
@@ -22,6 +22,7 @@
 import com.google.devtools.build.lib.bazel.rules.android.ndkcrosstools.r13.NdkMajorRevisionR13;
 import com.google.devtools.build.lib.bazel.rules.android.ndkcrosstools.r15.NdkMajorRevisionR15;
 import com.google.devtools.build.lib.bazel.rules.android.ndkcrosstools.r17.NdkMajorRevisionR17;
+import com.google.devtools.build.lib.bazel.rules.android.ndkcrosstools.r18.NdkMajorRevisionR18;
 import com.google.devtools.build.lib.util.OS;
 import java.util.Map;
 
@@ -48,6 +49,7 @@ private AndroidNdkCrosstools() {}
           // usage of the unified headers. Support for unified headers were added in r15.
           .put(16, new NdkMajorRevisionR15("5.0.300080")) // no changes relevant to Bazel
           .put(17, new NdkMajorRevisionR17("6.0.2"))
+          .put(18, new NdkMajorRevisionR18("7.0.2"))
           .build();
 
   public static final Map.Entry<Integer, NdkMajorRevision> LATEST_KNOWN_REVISION =
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/StlImpl.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/StlImpl.java
index b132258aeba370..f9ae3f889b3936 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/StlImpl.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/StlImpl.java
@@ -21,6 +21,7 @@
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import javax.annotation.Nullable;
 
 /**
  * An NdkStlImpl adds a specific Android NDK C++ STL implementation to a given CToolchain proto
@@ -55,7 +56,7 @@ protected StlImpl(String name, NdkPaths ndkPaths) {
   }
 
   public void addStlImpl(
-      List<CToolchain.Builder> baseToolchains, String gccVersion) {
+      List<CToolchain.Builder> baseToolchains, @Nullable String gccVersion) {
 
     for (CToolchain.Builder baseToolchain : baseToolchains) {
       addStlImpl(baseToolchain, gccVersion);
@@ -68,9 +69,9 @@ public void addStlImpl(
    * @param toolchain the toolchain to add the STL implementation to
    * @param gccVersion the gcc version for the STL impl. Applicable only to gnu-libstdc++
    */
-  public abstract void addStlImpl(CToolchain.Builder toolchain, String gccVersion);
+  public abstract void addStlImpl(CToolchain.Builder toolchain, @Nullable String gccVersion);
 
-  protected void addBaseStlImpl(CToolchain.Builder toolchain, String gccVersion) {
+  protected void addBaseStlImpl(CToolchain.Builder toolchain, @Nullable String gccVersion) {
  
     toolchain
       .setToolchainIdentifier(toolchain.getToolchainIdentifier() + "-" + name)
@@ -84,7 +85,7 @@ protected void addBaseStlImpl(CToolchain.Builder toolchain, String gccVersion) {
   }
 
   private String createRuntimeLibrariesFilegroup(
-      String stl, String gccVersion, String targetCpu, RuntimeType type) {
+      String stl, @Nullable String gccVersion, String targetCpu, RuntimeType type) {
 
     // gnu-libstlc++ has separate libraries for 4.8 and 4.9
     String fullStlName = stl;
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/StlImpls.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/StlImpls.java
index 9c64b18df99ac4..4a0fed51c6cf9e 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/StlImpls.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/StlImpls.java
@@ -17,6 +17,7 @@
 import com.google.common.collect.ImmutableList;
 import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.CToolchain;
 import java.util.List;
+import javax.annotation.Nullable;
 
 /**
  * Class that contains implementations of NdkStlImpl, one for each STL implementation of the STL
@@ -35,7 +36,7 @@ public GnuLibStdCppStlImpl(NdkPaths ndkPaths) {
     }
 
     @Override
-    public void addStlImpl(CToolchain.Builder toolchain, String gccVersion) {
+    public void addStlImpl(CToolchain.Builder toolchain, @Nullable String gccVersion) {
       addBaseStlImpl(toolchain, gccVersion);
       toolchain.addAllUnfilteredCxxFlag(createIncludeFlags(
           ndkPaths.createGnuLibstdcIncludePaths(gccVersion, toolchain.getTargetCpu())));
@@ -51,7 +52,7 @@ public LibCppStlImpl(NdkPaths ndkPaths) {
     }
 
     @Override
-    public void addStlImpl(CToolchain.Builder toolchain, String gccVersion) {
+    public void addStlImpl(CToolchain.Builder toolchain, @Nullable String gccVersion) {
       addBaseStlImpl(toolchain, null);
       toolchain.addAllUnfilteredCxxFlag(createIncludeFlags(ndkPaths.createLibcxxIncludePaths()));
       toolchain.addLinkerFlag("-L" + ndkPaths.createLibcppLinkerPath(toolchain.getTargetCpu()));
@@ -67,20 +68,27 @@ public StlPortStlImpl(NdkPaths ndkPaths) {
     }
 
     @Override
-    public void addStlImpl(CToolchain.Builder toolchain, String gccVersion) {
+    public void addStlImpl(CToolchain.Builder toolchain, @Nullable String gccVersion) {
       addBaseStlImpl(toolchain, null);
       toolchain.addAllUnfilteredCxxFlag(createIncludeFlags(ndkPaths.createStlportIncludePaths()));
     }
   }
 
   /**
+   * Gets the list of runtime libraries (STL) in the NDK.
+   *
+   * NDK r17 and lower contains gnustl, STLport and libc++.
+   * NDK r18 and above contains libc++ only.
+   *
    * @param ndkPaths NdkPaths to use for creating the NdkStlImpls
    * @return an ImmutableList of every available NdkStlImpl
    */
-  public static List<StlImpl> get(NdkPaths ndkPaths) {
-    return ImmutableList.of(
-        new GnuLibStdCppStlImpl(ndkPaths),
-        new StlPortStlImpl(ndkPaths),
-        new LibCppStlImpl(ndkPaths));
+  public static List<StlImpl> get(NdkPaths ndkPaths, Integer ndkMajorRevision) {
+    return ndkMajorRevision < 18
+        ? ImmutableList.of(
+            new GnuLibStdCppStlImpl(ndkPaths),
+            new StlPortStlImpl(ndkPaths),
+            new LibCppStlImpl(ndkPaths))
+        : ImmutableList.of(new LibCppStlImpl(ndkPaths));
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/r18/AndroidNdkCrosstoolsR18.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/r18/AndroidNdkCrosstoolsR18.java
new file mode 100644
index 00000000000000..7f241986e383cb
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/r18/AndroidNdkCrosstoolsR18.java
@@ -0,0 +1,108 @@
+// Copyright 2018 The Bazel Authors. All rights reserved.
+//
+// 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.
+
+package com.google.devtools.build.lib.bazel.rules.android.ndkcrosstools.r18;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.bazel.rules.android.ndkcrosstools.NdkPaths;
+import com.google.devtools.build.lib.bazel.rules.android.ndkcrosstools.StlImpl;
+import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.CToolchain;
+import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.CrosstoolRelease;
+import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.DefaultCpuToolchain;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/** Generates a CrosstoolRelease proto for the Android NDK. */
+final class AndroidNdkCrosstoolsR18 {
+
+  /**
+   * Creates a CrosstoolRelease proto for the Android NDK, given the API level to use and the
+   * release revision. The crosstools are generated through code rather than checked in as a flat
+   * file to reduce the amount of templating needed (for parameters like the release name and
+   * certain paths), to reduce duplication, and to make it easier to support future versions of the
+   * NDK. TODO(bazel-team): Eventually we should move this into Skylark so the crosstools can be
+   * updated independently of Bazel itself.
+   *
+   * @return A CrosstoolRelease for the Android NDK.
+   */
+  static CrosstoolRelease create(
+      NdkPaths ndkPaths, StlImpl stlImpl, String hostPlatform, String clangVersion) {
+    return CrosstoolRelease.newBuilder()
+        .setMajorVersion("android")
+        .setMinorVersion("")
+        .setDefaultTargetCpu("armeabi")
+        .addAllDefaultToolchain(getDefaultCpuToolchains(stlImpl, clangVersion))
+        .addAllToolchain(createToolchains(ndkPaths, stlImpl, hostPlatform, clangVersion))
+        .build();
+  }
+
+  private static ImmutableList<CToolchain> createToolchains(
+      NdkPaths ndkPaths, StlImpl stlImpl, String hostPlatform, String clangVersion) {
+
+    List<CToolchain.Builder> toolchainBuilders = new ArrayList<>();
+    toolchainBuilders.addAll(new ArmCrosstools(ndkPaths, stlImpl, clangVersion).createCrosstools());
+    toolchainBuilders.addAll(new X86Crosstools(ndkPaths, stlImpl, clangVersion).createCrosstools());
+
+    ImmutableList.Builder<CToolchain> toolchains = new ImmutableList.Builder<>();
+
+    // Set attributes common to all toolchains.
+    for (CToolchain.Builder toolchainBuilder : toolchainBuilders) {
+      toolchainBuilder
+          .setHostSystemName(hostPlatform)
+          .setTargetLibc("local")
+          .setAbiVersion(toolchainBuilder.getTargetCpu())
+          .setAbiLibcVersion("local");
+
+      // builtin_sysroot is set individually on each toolchain.
+      // platforms/arch sysroot
+      toolchainBuilder.addCxxBuiltinIncludeDirectory("%sysroot%/usr/include");
+      toolchainBuilder.addCxxBuiltinIncludeDirectory(
+          ndkPaths.createBuiltinSysroot() + "/usr/include");
+      toolchainBuilder.addUnfilteredCxxFlag(
+          "-isystem%ndk%/usr/include".replace("%ndk%", ndkPaths.createBuiltinSysroot()));
+
+      toolchains.add(toolchainBuilder.build());
+    }
+
+    return toolchains.build();
+  }
+
+  private static ImmutableList<DefaultCpuToolchain> getDefaultCpuToolchains(
+      StlImpl stlImpl, String clangVersion) {
+    // TODO(bazel-team): It would be better to auto-generate this somehow.
+
+    ImmutableMap<String, String> defaultCpus =
+        ImmutableMap.<String, String>builder()
+            // arm
+            .put("armeabi-v7a", "arm-linux-androideabi-clang" + clangVersion + "-v7a")
+            .put("arm64-v8a", "aarch64-linux-android-clang" + clangVersion)
+
+            // x86
+            .put("x86", "x86-clang" + clangVersion)
+            .put("x86_64", "x86_64-clang" + clangVersion)
+            .build();
+
+    ImmutableList.Builder<DefaultCpuToolchain> defaultCpuToolchains = ImmutableList.builder();
+    for (Map.Entry<String, String> defaultCpu : defaultCpus.entrySet()) {
+      defaultCpuToolchains.add(
+          DefaultCpuToolchain.newBuilder()
+              .setCpu(defaultCpu.getKey())
+              .setToolchainIdentifier(defaultCpu.getValue() + "-" + stlImpl.getName())
+              .build());
+    }
+    return defaultCpuToolchains.build();
+  }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/r18/ApiLevelR18.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/r18/ApiLevelR18.java
new file mode 100644
index 00000000000000..42a739a1f2feb1
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/r18/ApiLevelR18.java
@@ -0,0 +1,61 @@
+// Copyright 2018 The Bazel Authors. All rights reserved.
+//
+// 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.
+
+package com.google.devtools.build.lib.bazel.rules.android.ndkcrosstools.r18;
+
+import com.google.common.collect.ImmutableListMultimap;
+import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.bazel.rules.android.ndkcrosstools.ApiLevel;
+import com.google.devtools.build.lib.events.EventHandler;
+
+/** Class which encodes information from the Android NDK makefiles about API levels. */
+final class ApiLevelR18 extends ApiLevel {
+  /** This is the contents of {@code platforms/android-*} */
+  private static final ImmutableListMultimap<String, String> API_LEVEL_TO_ARCHITECTURES =
+      ImmutableListMultimap.<String, String>builder()
+          .putAll("16", "arm", "x86")
+          .putAll("17", "arm", "x86")
+          .putAll("18", "arm", "x86")
+          .putAll("19", "arm", "x86")
+          .putAll("21", "arm", "x86", "arm64", "x86_64")
+          .putAll("22", "arm", "x86", "arm64", "x86_64")
+          .putAll("23", "arm", "x86", "arm64", "x86_64")
+          .putAll("24", "arm", "x86", "arm64", "x86_64")
+          .putAll("26", "arm", "x86", "arm64", "x86_64")
+          .putAll("27", "arm", "x86", "arm64", "x86_64")
+          .putAll("28", "arm", "x86", "arm64", "x86_64")
+          .build();
+
+  /** This map fill in the gaps of {@code API_LEVEL_TO_ARCHITECTURES}. */
+  private static final ImmutableMap<String, String> API_EQUIVALENCIES =
+      ImmutableMap.<String, String>builder()
+          .put("16", "16")
+          .put("17", "16")
+          .put("18", "18")
+          .put("19", "19")
+          .put("20", "19")
+          .put("21", "21")
+          .put("22", "22")
+          .put("23", "23")
+          .put("24", "24")
+          .put("25", "24")
+          .put("26", "26")
+          .put("27", "27")
+          .put("28", "28")
+          .build();
+
+  ApiLevelR18(EventHandler eventHandler, String repositoryName, String apiLevel) {
+    super(API_LEVEL_TO_ARCHITECTURES, API_EQUIVALENCIES, eventHandler, repositoryName, apiLevel);
+  }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/r18/ArmCrosstools.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/r18/ArmCrosstools.java
new file mode 100644
index 00000000000000..9e0d9e7f24fa32
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/r18/ArmCrosstools.java
@@ -0,0 +1,172 @@
+// Copyright 2018 The Bazel Authors. All rights reserved.
+//
+// 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.
+
+package com.google.devtools.build.lib.bazel.rules.android.ndkcrosstools.r18;
+
+import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.lib.bazel.rules.android.ndkcrosstools.NdkPaths;
+import com.google.devtools.build.lib.bazel.rules.android.ndkcrosstools.StlImpl;
+import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.CToolchain;
+import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.CompilationMode;
+import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.CompilationModeFlags;
+
+/**
+ * Crosstool definitions for ARM. These values are based on the setup.mk files in the Android NDK
+ * toolchain directories.
+ */
+final class ArmCrosstools {
+  private final NdkPaths ndkPaths;
+  private final StlImpl stlImpl;
+  private final String clangVersion;
+
+  ArmCrosstools(NdkPaths ndkPaths, StlImpl stlImpl, String clangVersion) {
+    this.ndkPaths = ndkPaths;
+    this.stlImpl = stlImpl;
+    this.clangVersion = clangVersion;
+  }
+
+  ImmutableList<CToolchain.Builder> createCrosstools() {
+    CToolchain.Builder aarch64Toolchain = createAarch64ClangToolchain();
+    CToolchain.Builder armeabiToolchain = createArmeabiClangToolchain();
+
+    stlImpl.addStlImpl(aarch64Toolchain, "4.9");
+    stlImpl.addStlImpl(armeabiToolchain, "4.9");
+
+    return ImmutableList.<CToolchain.Builder>builder()
+        .add(aarch64Toolchain)
+        .add(armeabiToolchain)
+        .build();
+  }
+
+  private CToolchain.Builder createAarch64ClangToolchain() {
+    String toolchainName = "aarch64-linux-android-4.9";
+    String targetPlatform = "aarch64-linux-android";
+    String gccToolchain = ndkPaths.createGccToolchainPath(toolchainName);
+    String llvmTriple = "aarch64-none-linux-android";
+
+    return CToolchain.newBuilder()
+        .setToolchainIdentifier("aarch64-linux-android-clang" + clangVersion)
+        .setTargetSystemName(targetPlatform)
+        .setTargetCpu("arm64-v8a")
+        .setCompiler("clang" + clangVersion)
+        .addAllToolPath(ndkPaths.createClangToolpaths(toolchainName, targetPlatform, null))
+        .addCxxBuiltinIncludeDirectory(
+            ndkPaths.createClangToolchainBuiltinIncludeDirectory(clangVersion))
+        .setBuiltinSysroot(ndkPaths.createBuiltinSysroot("arm64"))
+
+        // Compiler flags
+        .addCompilerFlag("-gcc-toolchain")
+        .addCompilerFlag(gccToolchain)
+        .addCompilerFlag("-target")
+        .addCompilerFlag(llvmTriple)
+        .addCompilerFlag("-ffunction-sections")
+        .addCompilerFlag("-funwind-tables")
+        .addCompilerFlag("-fstack-protector-strong")
+        .addCompilerFlag("-fpic")
+        .addCompilerFlag("-Wno-invalid-command-line-argument")
+        .addCompilerFlag("-Wno-unused-command-line-argument")
+        .addCompilerFlag("-no-canonical-prefixes")
+        .addCompilerFlag(
+            "-isystem%ndk%/usr/include/%triple%"
+                .replace("%ndk%", ndkPaths.createBuiltinSysroot())
+                .replace("%triple%", targetPlatform))
+        .addCompilerFlag("-D__ANDROID_API__=" + ndkPaths.getCorrectedApiLevel("arm"))
+
+        // Linker flags
+        .addLinkerFlag("-gcc-toolchain")
+        .addLinkerFlag(gccToolchain)
+        .addLinkerFlag("-target")
+        .addLinkerFlag(llvmTriple)
+        .addLinkerFlag("-no-canonical-prefixes")
+
+        // Additional release flags
+        .addCompilationModeFlags(
+            CompilationModeFlags.newBuilder()
+                .setMode(CompilationMode.OPT)
+                .addCompilerFlag("-O2")
+                .addCompilerFlag("-g")
+                .addCompilerFlag("-DNDEBUG"))
+
+        // Additional debug flags
+        .addCompilationModeFlags(
+            CompilationModeFlags.newBuilder()
+                .setMode(CompilationMode.DBG)
+                .addCompilerFlag("-O0")
+                .addCompilerFlag("-g")
+                .addCompilerFlag("-UNDEBUG"));
+  }
+
+  private CToolchain.Builder createArmeabiClangToolchain() {
+    String toolchainName = "arm-linux-androideabi-4.9";
+    String targetPlatform = "arm-linux-androideabi";
+    String gccToolchain = ndkPaths.createGccToolchainPath("arm-linux-androideabi-4.9");
+
+    return CToolchain.newBuilder()
+        .setToolchainIdentifier("arm-linux-androideabi-clang" + clangVersion + "-v7a")
+        .setTargetCpu("armeabi-v7a")
+        .setTargetSystemName("arm-linux-androideabi")
+        .setCompiler("clang" + clangVersion)
+        .addAllToolPath(ndkPaths.createClangToolpaths(toolchainName, targetPlatform, null))
+        .addCxxBuiltinIncludeDirectory(
+            ndkPaths.createClangToolchainBuiltinIncludeDirectory(clangVersion))
+        .setBuiltinSysroot(ndkPaths.createBuiltinSysroot("arm"))
+        .addCompilerFlag("-D__ANDROID_API__=" + ndkPaths.getCorrectedApiLevel("arm"))
+        .addCompilerFlag(
+            "-isystem%ndk%/usr/include/%triple%"
+                .replace("%ndk%", ndkPaths.createBuiltinSysroot())
+                .replace("%triple%", targetPlatform))
+
+        // Compiler flags
+        .addCompilerFlag("-target")
+        .addCompilerFlag("armv7-none-linux-androideabi") // LLVM_TRIPLE
+        .addCompilerFlag("-march=armv7-a")
+        .addCompilerFlag("-mfloat-abi=softfp")
+        .addCompilerFlag("-mfpu=vfpv3-d16")
+        .addCompilerFlag("-gcc-toolchain")
+        .addCompilerFlag(gccToolchain)
+        .addCompilerFlag("-fpic")
+        .addCompilerFlag("-ffunction-sections")
+        .addCompilerFlag("-funwind-tables")
+        .addCompilerFlag("-fstack-protector-strong")
+        .addCompilerFlag("-Wno-invalid-command-line-argument")
+        .addCompilerFlag("-Wno-unused-command-line-argument")
+        .addCompilerFlag("-no-canonical-prefixes")
+
+        // Linker flags
+        .addLinkerFlag("-target")
+        .addLinkerFlag("armv7-none-linux-androideabi") // LLVM_TRIPLE
+        .addLinkerFlag("-Wl,--fix-cortex-a8")
+        .addLinkerFlag("-gcc-toolchain")
+        .addLinkerFlag(gccToolchain)
+        .addLinkerFlag("-no-canonical-prefixes")
+
+        // Additional release flags
+        .addCompilationModeFlags(
+            CompilationModeFlags.newBuilder()
+                .setMode(CompilationMode.OPT)
+                .addCompilerFlag("-mthumb")
+                .addCompilerFlag("-Os")
+                .addCompilerFlag("-g")
+                .addCompilerFlag("-DNDEBUG"))
+
+        // Additional debug flags
+        .addCompilationModeFlags(
+            CompilationModeFlags.newBuilder()
+                .setMode(CompilationMode.DBG)
+                .addCompilerFlag("-g")
+                .addCompilerFlag("-fno-strict-aliasing")
+                .addCompilerFlag("-O0")
+                .addCompilerFlag("-UNDEBUG"));
+  }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/r18/NdkMajorRevisionR18.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/r18/NdkMajorRevisionR18.java
new file mode 100644
index 00000000000000..44a01ea445d80c
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/r18/NdkMajorRevisionR18.java
@@ -0,0 +1,43 @@
+// Copyright 2018 The Bazel Authors. All rights reserved.
+//
+// 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.
+
+package com.google.devtools.build.lib.bazel.rules.android.ndkcrosstools.r18;
+
+import com.google.devtools.build.lib.bazel.rules.android.ndkcrosstools.ApiLevel;
+import com.google.devtools.build.lib.bazel.rules.android.ndkcrosstools.NdkMajorRevision;
+import com.google.devtools.build.lib.bazel.rules.android.ndkcrosstools.NdkPaths;
+import com.google.devtools.build.lib.bazel.rules.android.ndkcrosstools.StlImpl;
+import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.CrosstoolRelease;
+
+/** Logic specific to Android NDK R17. */
+public class NdkMajorRevisionR18 implements NdkMajorRevision {
+  private final String clangVersion;
+
+  public NdkMajorRevisionR18(String clangVersion) {
+    this.clangVersion = clangVersion;
+  }
+
+  @Override
+  public CrosstoolRelease crosstoolRelease(
+      NdkPaths ndkPaths, StlImpl stlImpl, String hostPlatform) {
+    return AndroidNdkCrosstoolsR18
+        .create(ndkPaths, stlImpl, hostPlatform, clangVersion);
+  }
+
+  @Override
+  public ApiLevel apiLevel(EventHandler eventHandler, String name, String apiLevel) {
+    return new ApiLevelR18(eventHandler, name, apiLevel);
+  }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/r18/X86Crosstools.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/r18/X86Crosstools.java
new file mode 100644
index 00000000000000..dd01408d92c1f5
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/ndkcrosstools/r18/X86Crosstools.java
@@ -0,0 +1,118 @@
+// Copyright 2018 The Bazel Authors. All rights reserved.
+//
+// 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.
+
+package com.google.devtools.build.lib.bazel.rules.android.ndkcrosstools.r18;
+
+import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.lib.bazel.rules.android.ndkcrosstools.NdkPaths;
+import com.google.devtools.build.lib.bazel.rules.android.ndkcrosstools.StlImpl;
+import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.CToolchain;
+import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.CompilationMode;
+import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.CompilationModeFlags;
+
+/**
+ * Crosstool definitions for x86. These values are based on the setup.mk files in the Android NDK
+ * toolchain directories.
+ */
+final class X86Crosstools {
+  private final NdkPaths ndkPaths;
+  private final StlImpl stlImpl;
+  private final String clangVersion;
+
+  X86Crosstools(NdkPaths ndkPaths, StlImpl stlImpl, String clangVersion) {
+    this.ndkPaths = ndkPaths;
+    this.stlImpl = stlImpl;
+    this.clangVersion = clangVersion;
+  }
+
+  ImmutableList<CToolchain.Builder> createCrosstools() {
+    /** x86 */
+    // clang
+    CToolchain.Builder x86Clang =
+        createBaseX86ClangToolchain("x86", "i686", "i686-linux-android")
+            // Workaround for https://code.google.com/p/android/issues/detail?id=220159.
+            .addCompilerFlag("-mstackrealign")
+            .setToolchainIdentifier("x86-clang" + clangVersion)
+            .setTargetCpu("x86")
+            .addAllToolPath(ndkPaths.createClangToolpaths("x86-4.9", "i686-linux-android", null))
+            .setBuiltinSysroot(ndkPaths.createBuiltinSysroot("x86"));
+
+    stlImpl.addStlImpl(x86Clang, null);
+
+    /** x86_64 */
+    CToolchain.Builder x8664Clang =
+        createBaseX86ClangToolchain("x86_64", "x86_64", "x86_64-linux-android")
+            .setToolchainIdentifier("x86_64-clang" + clangVersion)
+            .setTargetCpu("x86_64")
+            .addAllToolPath(
+                ndkPaths.createClangToolpaths("x86_64-4.9", "x86_64-linux-android", null))
+            .setBuiltinSysroot(ndkPaths.createBuiltinSysroot("x86_64"));
+
+    stlImpl.addStlImpl(x8664Clang, null);
+
+    return ImmutableList.of(x86Clang, x8664Clang);
+  }
+
+  private CToolchain.Builder createBaseX86ClangToolchain(
+      String x86Arch, String llvmArch, String triple) {
+    String gccToolchain = ndkPaths.createGccToolchainPath(x86Arch + "-4.9");
+    String llvmTriple = llvmArch + "-none-linux-android";
+
+    return CToolchain.newBuilder()
+        .setCompiler("clang" + clangVersion)
+        .addCxxBuiltinIncludeDirectory(
+            ndkPaths.createClangToolchainBuiltinIncludeDirectory(clangVersion))
+
+        // Compiler flags
+        .addCompilerFlag("-gcc-toolchain")
+        .addCompilerFlag(gccToolchain)
+        .addCompilerFlag("-target")
+        .addCompilerFlag(llvmTriple)
+        .addCompilerFlag("-ffunction-sections")
+        .addCompilerFlag("-funwind-tables")
+        .addCompilerFlag("-fstack-protector-strong")
+        .addCompilerFlag("-fPIC")
+        .addCompilerFlag("-Wno-invalid-command-line-argument")
+        .addCompilerFlag("-Wno-unused-command-line-argument")
+        .addCompilerFlag("-no-canonical-prefixes")
+        .addCompilerFlag(
+            "-isystem%ndk%/usr/include/%triple%"
+                .replace("%ndk%", ndkPaths.createBuiltinSysroot())
+                .replace("%triple%", triple))
+        .addCompilerFlag("-D__ANDROID_API__=" + ndkPaths.getCorrectedApiLevel(x86Arch))
+
+        // Linker flags
+        .addLinkerFlag("-gcc-toolchain")
+        .addLinkerFlag(gccToolchain)
+        .addLinkerFlag("-target")
+        .addLinkerFlag(llvmTriple)
+        .addLinkerFlag("-no-canonical-prefixes")
+
+        // Additional release flags
+        .addCompilationModeFlags(
+            CompilationModeFlags.newBuilder()
+                .setMode(CompilationMode.OPT)
+                .addCompilerFlag("-O2")
+                .addCompilerFlag("-g")
+                .addCompilerFlag("-DNDEBUG"))
+
+        // Additional debug flags
+        .addCompilationModeFlags(
+            CompilationModeFlags.newBuilder()
+                .setMode(CompilationMode.DBG)
+                .addCompilerFlag("-O0")
+                .addCompilerFlag("-g"))
+        .setTargetSystemName("x86-linux-android");
+  }
+}


Test patch: