Remove custom CMake cross compilation for Android. (#4584)

Cross compilation [for Android] is not special. Compiler tools are built on the host and installed (using CMake, Bazel, via vcpkg,
via pip, etc.). The runtime and target tests are built for the target, referencing host tools where needed using `IREE_HOST_BINARY_ROOT`. Some parts of the project only build or are only useful on the host, so some configuration like setting `IREE_BUILD_COMPILER=OFF` is still useful.

This removes our custom CMake code and updates all of our scripts and docs to invoke CMake in two explicit steps: once for the host and once for the target.

Fixes https://github.com/google/iree/issues/4323.
Fixes https://github.com/google/iree/issues/4520.
Fixes https://github.com/google/iree/issues/2494 (tentatively).
Helps with https://github.com/google/iree/issues/3843.
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 346937c..bc48728 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -33,8 +33,6 @@
 # Project component configuration
 #-------------------------------------------------------------------------------
 
-# Make sure to also update these options in
-# build_tools/cmake/iree_cross_compile.cmake
 option(IREE_ENABLE_RUNTIME_TRACING "Enables instrumented runtime tracing." OFF)
 option(IREE_ENABLE_MLIR "Enables MLIR/LLVM dependencies." ON)
 option(IREE_ENABLE_EMITC "Enables MLIR EmitC dependencies." OFF)
@@ -181,54 +179,6 @@
 )
 
 #-------------------------------------------------------------------------------
-# Cross compiling configuration
-#-------------------------------------------------------------------------------
-
-if(CMAKE_CROSSCOMPILING)
-  message(STATUS "Detected cross compilation mode; configuring IREE on host...")
-
-  # C/C++ compilers for host compilation.
-  # Note: we need to explicitly set this because IREE does not work well with
-  # GCC at the moment: https://github.com/google/iree/issues/1269
-  set(IREE_HOST_C_COMPILER "$ENV{IREE_HOST_C_COMPILER}" CACHE FILEPATH "C compiler for host compilation")
-  set(IREE_HOST_CXX_COMPILER "$ENV{IREE_HOST_CXX_COMPILER}" CACHE FILEPATH "C++ compiler for host compilation")
-
-  # Master configuration for the binary directory containing all artifacts
-  # compiled for host.
-  if(NOT IREE_HOST_BINARY_ROOT)
-    set(IREE_HOST_BINARY_ROOT "${CMAKE_CURRENT_BINARY_DIR}/host" CACHE FILEPATH "directory containing host artifacts")
-  endif()
-
-  set(IREE_HOST_BUILD_COMPILER ON) # For iree-translate
-  set(IREE_HOST_ENABLE_LLVM ON)    # For iree-tblgen
-
-  # Set the host build directory for LLVM to our directory. Otherwise it will
-  # follow its own convention.
-  set(LLVM_NATIVE_BUILD
-      "${IREE_HOST_BINARY_ROOT}/third_party/llvm-project/llvm"
-      CACHE FILEPATH "directory containing host artifacts for LLVM"
-  )
-
-  # And set host C/C++ compiler for LLVM. This makes cross compilation using
-  # Windows as the host platform nicer. Because we have various development
-  # evnironments on Windows (CMD, Cygwin, MSYS, etc.), LLVM can have problems
-  # figuring out the host triple and toolchain. We are passing in the host
-  # C/C++ compiler toolchain for IREE anyway; so we can give LLVM side some
-  # help here. This hides some complexity and ugliness from the users.
-  set(CROSS_TOOLCHAIN_FLAGS_NATIVE
-      "-DCMAKE_C_COMPILER=\"${IREE_HOST_C_COMPILER}\";-DCMAKE_CXX_COMPILER=\"${IREE_HOST_CXX_COMPILER}\""
-      CACHE FILEPATH "LLVM toolchain configuration for host build"
-  )
-
-  include(iree_cross_compile)
-
-  # Use another CMake invocation to configure a build for host.
-  iree_create_configuration(HOST)
-
-  message(STATUS "Done configuring IREE on host in ${IREE_HOST_BINARY_ROOT}")
-endif()
-
-#-------------------------------------------------------------------------------
 # IREE compilation toolchain configuration
 #-------------------------------------------------------------------------------
 
@@ -449,28 +399,11 @@
 # ruy must come after cpuinfo so it uses already-defined targets.
 add_subdirectory(third_party/ruy EXCLUDE_FROM_ALL)
 
-if(CMAKE_CROSSCOMPILING)
-  # We need flatc to generate some source code. When cross-compiling, we need
-  # to make sure the flatc binary is configured under host environment.
-  iree_declare_host_excutable(flatc "flatc" BUILDONLY)
-  iree_declare_host_excutable(flatcc_cli "flatcc_cli" BUILDONLY)
-
-  # Set the FLATBUFFERS_FLATC_EXECUTABLE. It controls where to find the flatc
-  # binary in BuildFlatBuffers().
-  iree_get_executable_path(FLATBUFFERS_FLATC_EXECUTABLE flatc)
-
-  # Add a custom target to copy the flatc to the binary directory.
-  add_custom_target(iree_host_flatcc_cli
-    COMMAND
-      "${CMAKE_COMMAND}" -E copy_if_different
-        "${CMAKE_CURRENT_SOURCE_DIR}/third_party/flatcc/bin/flatcc${IREE_HOST_EXECUTABLE_SUFFIX}"
-        "${IREE_HOST_BINARY_ROOT}/bin/flatcc_cli${IREE_HOST_EXECUTABLE_SUFFIX}"
-    DEPENDS iree_host_build_flatcc_cli
-    COMMENT "Installing host flatcc..."
-  )
-else()
-  # TODO: unify flatc and flatcc handling to the same mechanism.
-  add_executable(iree_host_flatcc_cli ALIAS flatcc_cli)
+# TODO(scotttodd): Iterate some more and find a better place for this.
+if (NOT CMAKE_CROSSCOMPILING)
+  install(TARGETS iree-flatcc-cli
+          COMPONENT iree-flatcc-cli
+          RUNTIME DESTINATION bin)
 endif()
 
 if(${IREE_BUILD_COMPILER})
diff --git a/bindings/java/build.gradle b/bindings/java/build.gradle
index d560146..a35c25e 100644
--- a/bindings/java/build.gradle
+++ b/bindings/java/build.gradle
@@ -35,12 +35,6 @@
                         '-DIREE_BUILD_TESTS=OFF',
                         '-DIREE_BUILD_SAMPLES=OFF',
                         '-DIREE_BUILD_PYTHON_BINDINGS=OFF',
-
-                        // TODO(#4520): This is being checked in for now with
-                        // the hard-coded linux paths due to complications
-                        // with configuring cross-compilation.
-                        '-DIREE_HOST_C_COMPILER=/usr/bin/clang',
-                        '-DIREE_HOST_CXX_COMPILER=/usr/bin/clang++'
             }
         }
     }
diff --git a/build_tools/buildkite/cmake/android/arm64-v8a/benchmark.yml b/build_tools/buildkite/cmake/android/arm64-v8a/benchmark.yml
index 08e12b6..b634eb2 100644
--- a/build_tools/buildkite/cmake/android/arm64-v8a/benchmark.yml
+++ b/build_tools/buildkite/cmake/android/arm64-v8a/benchmark.yml
@@ -19,7 +19,7 @@
       - "gsutil cp gs://iree-model-artifacts/iree-mobile-bert-artifacts-6fe4616e0ab9958eb18f368960a31276f1362029.tar.gz ."
       - "tar -xzf iree-mobile-bert-artifacts-6fe4616e0ab9958eb18f368960a31276f1362029.tar.gz"
       - "docker run --user=$(id -u):$(id -g) --volume=\\$PWD:\\$IREE_DOCKER_WORKDIR --workdir=\\$IREE_DOCKER_WORKDIR --rm gcr.io/iree-oss/cmake-android@sha256:15d3266ae4865f7642a4ef4d76e5181f0dc3482a7cfba9021b6b55be524208ec build_tools/mako/compile_android_modules.sh --model=tmp/iree/modules/MobileBertSquad/iree_input.mlir --targets=vulkan-spirv,vmla,dylib-llvm-aot --prefix=mobile-bert"
-      - "tar -czvf model-artifacts.tgz build/iree/tools/iree-benchmark-module mobile-bert-*.vmfb tmp/iree/modules/MobileBertSquad/iree_vmla/traces/serving_default/flagfile"
+      - "tar -czvf model-artifacts.tgz build-android/iree/tools/iree-benchmark-module mobile-bert-*.vmfb tmp/iree/modules/MobileBertSquad/iree_vmla/traces/serving_default/flagfile"
     agents:
       - "build=true"
     env:
@@ -34,7 +34,7 @@
       - "buildkite-agent artifact download --step build model-artifacts.tgz ./"
       - "tar xzvf model-artifacts.tgz"
       - "adb shell mkdir -p /data/local/tmp/benchmark_tmpdir"
-      - "adb push build/iree/tools/iree-benchmark-module /data/local/tmp/benchmark_tmpdir"
+      - "adb push build-android/iree/tools/iree-benchmark-module /data/local/tmp/benchmark_tmpdir"
       - "adb push mobile-bert-*.vmfb /data/local/tmp/benchmark_tmpdir"
       - "adb push tmp/iree/modules/MobileBertSquad/iree_vmla/traces/serving_default/flagfile /data/local/tmp/benchmark_tmpdir"
       - "build_tools/mako/benchmark_modules_on_android.sh --targets=vulkan-spirv,vmla,dylib-llvm-aot --benchmark_key=5538704950034432 --model=mobile-bert --git_hash=$(git rev-parse HEAD)"
@@ -54,7 +54,7 @@
       - "buildkite-agent artifact download --step build model-artifacts.tgz ./"
       - "tar xzvf model-artifacts.tgz"
       - "adb shell mkdir -p /data/local/tmp/benchmark_tmpdir"
-      - "adb push build/iree/tools/iree-benchmark-module /data/local/tmp/benchmark_tmpdir"
+      - "adb push build-android/iree/tools/iree-benchmark-module /data/local/tmp/benchmark_tmpdir"
       - "adb push mobile-bert-*.vmfb /data/local/tmp/benchmark_tmpdir"
       - "adb push tmp/iree/modules/MobileBertSquad/iree_vmla/traces/serving_default/flagfile /data/local/tmp/benchmark_tmpdir"
       - "build_tools/mako/benchmark_modules_on_android.sh --targets=vulkan-spirv,vmla,dylib-llvm-aot --benchmark_key=4699630718681088 --model=mobile-bert --git_hash=$(git rev-parse HEAD)"
diff --git a/build_tools/buildkite/cmake/android/arm64-v8a/pipeline.yml b/build_tools/buildkite/cmake/android/arm64-v8a/pipeline.yml
index b6a3e45..150008d 100644
--- a/build_tools/buildkite/cmake/android/arm64-v8a/pipeline.yml
+++ b/build_tools/buildkite/cmake/android/arm64-v8a/pipeline.yml
@@ -16,7 +16,7 @@
   - label: "build"
     commands:
       - "docker run --user=$(id -u):$(id -g) --volume=\\$PWD:\\$IREE_DOCKER_WORKDIR --workdir=\\$IREE_DOCKER_WORKDIR --rm gcr.io/iree-oss/cmake-android@sha256:15d3266ae4865f7642a4ef4d76e5181f0dc3482a7cfba9021b6b55be524208ec build_tools/kokoro/gcp_ubuntu/cmake/android/build.sh arm64-v8a"
-      - "tar --exclude='build/host' --exclude='*.o' --exclude='*.a' -czvf build-artifacts.tgz build"
+      - "tar --exclude='*.o' --exclude='*.a' -czvf build-artifacts.tgz build-android"
     agents:
       - "build=true"
     env:
@@ -29,8 +29,8 @@
     commands:
       - "buildkite-agent artifact download --step build build-artifacts.tgz ./"
       - "tar xzf build-artifacts.tgz"
-      - "find build/ -name '*.cmake' -exec sed -i \"s!\\$IREE_DOCKER_WORKDIR/!\\$PWD/!g\" {} \\;"
-      - "cd build/"
+      - "find build-android/ -name '*.cmake' -exec sed -i \"s!\\$IREE_DOCKER_WORKDIR/!\\$PWD/!g\" {} \\;"
+      - "cd build-android/"
       - "ctest --output-on-failure"
     agents:
       - "test-android=true"
@@ -44,8 +44,8 @@
     commands:
       - "buildkite-agent artifact download --step build build-artifacts.tgz ./"
       - "tar xzf build-artifacts.tgz"
-      - "find build/ -name '*.cmake' -exec sed -i \"s!\\$IREE_DOCKER_WORKDIR/!\\$PWD/!g\" {} \\;"
-      - "cd build/"
+      - "find build-android/ -name '*.cmake' -exec sed -i \"s!\\$IREE_DOCKER_WORKDIR/!\\$PWD/!g\" {} \\;"
+      - "cd build-android/"
       - "ctest --output-on-failure"
     agents:
       - "test-android=true"
@@ -58,8 +58,8 @@
     commands:
       - "buildkite-agent artifact download --step build build-artifacts.tgz ./"
       - "tar xzf build-artifacts.tgz"
-      - "find build/ -name '*.cmake' -exec sed -i \"s!\\$IREE_DOCKER_WORKDIR/!\\$PWD/!g\" {} \\;"
-      - "cd build/"
+      - "find build-android/ -name '*.cmake' -exec sed -i \"s!\\$IREE_DOCKER_WORKDIR/!\\$PWD/!g\" {} \\;"
+      - "cd build-android/"
       - "ctest --output-on-failure"
     agents:
       - "test-android=true"
@@ -75,8 +75,8 @@
     commands:
       - "buildkite-agent artifact download --step build build-artifacts.tgz ./"
       - "tar xzf build-artifacts.tgz"
-      - "find build/ -name '*.cmake' -exec sed -i \"s!\\$IREE_DOCKER_WORKDIR/!\\$PWD/!g\" {} \\;"
-      - "cd build/"
+      - "find build-android/ -name '*.cmake' -exec sed -i \"s!\\$IREE_DOCKER_WORKDIR/!\\$PWD/!g\" {} \\;"
+      - "cd build-android/"
       - "ctest --output-on-failure"
     agents:
       - "test-android=true"
@@ -90,8 +90,8 @@
     commands:
       - "buildkite-agent artifact download --step build build-artifacts.tgz ./"
       - "tar xzf build-artifacts.tgz"
-      - "find build/ -name '*.cmake' -exec sed -i \"s!\\$IREE_DOCKER_WORKDIR/!\\$PWD/!g\" {} \\;"
-      - "cd build/"
+      - "find build-android/ -name '*.cmake' -exec sed -i \"s!\\$IREE_DOCKER_WORKDIR/!\\$PWD/!g\" {} \\;"
+      - "cd build-android/"
       - "ctest --output-on-failure"
     agents:
       - "test-android=true"
@@ -108,8 +108,8 @@
     commands:
       - "buildkite-agent artifact download --step build build-artifacts.tgz ./"
       - "tar xzf build-artifacts.tgz"
-      - "find build/ -name '*.cmake' -exec sed -i \"s!\\$IREE_DOCKER_WORKDIR/!\\$PWD/!g\" {} \\;"
-      - "cd build/"
+      - "find build-android/ -name '*.cmake' -exec sed -i \"s!\\$IREE_DOCKER_WORKDIR/!\\$PWD/!g\" {} \\;"
+      - "cd build-android/"
       - "ctest --output-on-failure"
     agents:
       - "test-android=true"
diff --git a/build_tools/cmake/build_android.sh b/build_tools/cmake/build_android.sh
index d269394..2e967cc 100755
--- a/build_tools/cmake/build_android.sh
+++ b/build_tools/cmake/build_android.sh
@@ -14,7 +14,10 @@
 
 # Cross-compile the IREE project towards Android with CMake. Designed for CI,
 # but can be run manually. This uses previously cached build results and does
-# not clear the build directory.
+# not clear build directories.
+#
+# Host binaries (e.g. compiler tools) will be built and installed in build-host/
+# Android binaries (e.g. tests) will be built in build-android/.
 
 set -x
 set -e
@@ -30,30 +33,54 @@
 
 CMAKE_BIN=${CMAKE_BIN:-$(which cmake)}
 
-"$CMAKE_BIN" --version
+"${CMAKE_BIN?}" --version
 ninja --version
 
 cd ${ROOT_DIR?}
-if [ -d "build" ]
+
+# --------------------------------------------------------------------------- #
+# Build for the host.
+
+if [ -d "build-host" ]
 then
-  echo "Build directory already exists. Will use cached results there."
+  echo "build-host directory already exists. Will use cached results there."
 else
-  echo "Build directory does not already exist. Creating a new one."
-  mkdir build
+  echo "build-host directory does not already exist. Creating a new one."
+  mkdir build-host
 fi
+cd build-host
 
-cd build
+# Configure, build, install.
+"${CMAKE_BIN?}" -G Ninja .. \
+  -DCMAKE_INSTALL_PREFIX=./install \
+  -DIREE_BUILD_COMPILER=ON \
+  -DIREE_BUILD_TESTS=OFF \
+  -DIREE_BUILD_SAMPLES=OFF
+"${CMAKE_BIN?}" --build . --target install
+# --------------------------------------------------------------------------- #
 
-# Configure towards 64-bit Android 10.
-"$CMAKE_BIN" -G Ninja .. \
-  -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake \
-  -DANDROID_ABI="$ANDROID_ABI" \
+cd ${ROOT_DIR?}
+
+# --------------------------------------------------------------------------- #
+# Build for the target (Android).
+
+if [ -d "build-android" ]
+then
+  echo "build-android directory already exists. Will use cached results there."
+else
+  echo "build-android directory does not already exist. Creating a new one."
+  mkdir build-android
+fi
+cd build-android
+
+# Configure towards 64-bit Android 10, then build.
+"${CMAKE_BIN?}" -G Ninja .. \
+  -DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK?}/build/cmake/android.toolchain.cmake \
+  -DANDROID_ABI="${ANDROID_ABI?}" \
   -DANDROID_PLATFORM=android-29 \
+  -DIREE_HOST_BINARY_ROOT=$PWD/../build-host/install \
   -DIREE_BUILD_COMPILER=OFF \
+  -DIREE_ENABLE_MLIR=OFF \
   -DIREE_BUILD_TESTS=ON \
-  -DIREE_BUILD_SAMPLES=OFF \
-  -DIREE_HOST_C_COMPILER=$(which clang) \
-  -DIREE_HOST_CXX_COMPILER=$(which clang++)
-
-# TODO(#2494): Invoke once after fixing the flaky build failure in GCP.
-"$CMAKE_BIN" --build . || "$CMAKE_BIN" --build .
+  -DIREE_BUILD_SAMPLES=OFF
+"${CMAKE_BIN?}" --build .
diff --git a/build_tools/cmake/flatbuffer_c_library.cmake b/build_tools/cmake/flatbuffer_c_library.cmake
index 23ade0c..a812eca 100644
--- a/build_tools/cmake/flatbuffer_c_library.cmake
+++ b/build_tools/cmake/flatbuffer_c_library.cmake
@@ -95,7 +95,7 @@
   endforeach()
   list(TRANSFORM _OUTS PREPEND "${CMAKE_CURRENT_BINARY_DIR}/")
 
-  iree_get_executable_path(_FLATCC_BIN flatcc_cli)
+  iree_get_executable_path(_FLATCC_BIN iree-flatcc-cli)
   add_custom_command(
     OUTPUT
       ${_OUTS}
@@ -110,7 +110,6 @@
     MAIN_DEPENDENCY
       ${_RULE_SRCS}
     DEPENDS
-      iree_host_flatcc_cli
       ${_RULE_SRCS}
     COMMAND_EXPAND_LISTS
   )
diff --git a/build_tools/cmake/iree_cc_binary.cmake b/build_tools/cmake/iree_cc_binary.cmake
index 6fa754d..d35a873 100644
--- a/build_tools/cmake/iree_cc_binary.cmake
+++ b/build_tools/cmake/iree_cc_binary.cmake
@@ -69,22 +69,6 @@
   iree_package_name(_PACKAGE_NAME)
   set(_NAME "${_PACKAGE_NAME}_${_RULE_NAME}")
 
-  if(_RULE_HOSTONLY AND CMAKE_CROSSCOMPILING)
-    # The binary is marked as host only. We need to declare the rules for
-    # generating them under host configuration so when cross-compiling towards
-    # target we can still have this binary.
-    iree_declare_host_excutable(${_RULE_NAME} ${_NAME})
-
-    # Still define the package-prefixed target so we can have a consistent way
-    # to reference this binary, whether cross-compiling or not. But this time
-    # use the target to convey a property for the executable path under host
-    # configuration.
-    iree_get_executable_path(_EXE_PATH ${_RULE_NAME})
-    add_custom_target(${_NAME} DEPENDS ${_EXE_PATH})
-    set_target_properties(${_NAME} PROPERTIES HOST_TARGET_FILE "${_EXE_PATH}")
-    return()
-  endif()
-
   add_executable(${_NAME} "")
   add_executable(${_RULE_NAME} ALIAS ${_NAME})
   if(_RULE_SRCS)
diff --git a/build_tools/cmake/iree_check_test.cmake b/build_tools/cmake/iree_check_test.cmake
index c3cf32e..2ea9b09 100644
--- a/build_tools/cmake/iree_check_test.cmake
+++ b/build_tools/cmake/iree_check_test.cmake
@@ -36,12 +36,6 @@
     return()
   endif()
 
-  # When *not* cross compiling, respect the IREE_BUILD_COMPILER option.
-  # Cross compilation uses its own "IREE_HOST_BUILD_COMPILER" option.
-  if(NOT IREE_BUILD_COMPILER AND NOT CMAKE_CROSSCOMPILING)
-    return()
-  endif()
-
   cmake_parse_arguments(
     _RULE
     ""
diff --git a/build_tools/cmake/iree_copts.cmake b/build_tools/cmake/iree_copts.cmake
index 97e4685..9c40cdb 100644
--- a/build_tools/cmake/iree_copts.cmake
+++ b/build_tools/cmake/iree_copts.cmake
@@ -368,24 +368,6 @@
 set(CPUINFO_BUILD_MOCK_TESTS OFF CACHE BOOL "" FORCE)
 
 #-------------------------------------------------------------------------------
-# Third party: flatbuffers
-#-------------------------------------------------------------------------------
-
-set(FLATBUFFERS_BUILD_TESTS OFF CACHE BOOL "" FORCE)
-set(FLATBUFFERS_BUILD_FLATHASH OFF CACHE BOOL "" FORCE)
-set(FLATBUFFERS_BUILD_GRPCTEST OFF CACHE BOOL "" FORCE)
-set(FLATBUFFERS_INSTALL OFF CACHE BOOL "" FORCE)
-set(FLATBUFFERS_INCLUDE_DIRS
-  "${CMAKE_CURRENT_SOURCE_DIR}/third_party/flatbuffers/include/"
-)
-
-if(CMAKE_CROSSCOMPILING)
-  set(FLATBUFFERS_BUILD_FLATC OFF CACHE BOOL "" FORCE)
-else()
-  set(FLATBUFFERS_BUILD_FLATC ON CACHE BOOL "" FORCE)
-endif()
-
-#-------------------------------------------------------------------------------
 # Third party: flatcc
 #-------------------------------------------------------------------------------
 
diff --git a/build_tools/cmake/iree_cross_compile.cmake b/build_tools/cmake/iree_cross_compile.cmake
deleted file mode 100644
index 43fb5c2..0000000
--- a/build_tools/cmake/iree_cross_compile.cmake
+++ /dev/null
@@ -1,244 +0,0 @@
-# Copyright 2020 Google LLC
-#
-# 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
-#
-#      https://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(iree_macros)
-
-# iree_create_configuration
-#
-# Creates custom commands and targets for an IREE configuration. An IREE
-# configuration means a new IREE CMake invocation with its own set of
-# parameters.
-#
-# This function defines a custom target, `iree_configure_${CONFIG_NAME}`,
-# to drive the generation of a new IREE configuration's `CMakeCache.txt`
-# file. Callers can then depend on either the `CMakeCache.txt` file or the
-# `iree_configure_${CONFIG_NAME}` target to make sure the configuration
-# is invoked as a dependency.
-#
-# This function is typically useful when cross-compiling towards another
-# architecture. For example, when cross-compiling towards Android, we need
-# to have certain tools first compiled on the host so that we can use them
-# to programmatically generate some source code to be compiled together
-# with other checked-in source code. Those host tools will be generated
-# by another CMake invocation configured by this function.
-#
-# Supported CMake options:
-# - IREE_<CONFIG_NAME>_BINARY_ROOT: the root directory for containing IREE build
-#   artifacts for the given `CONFIG_NAME`. If not specified in caller, this is
-#   set to a directory named as `CONFIG_NAME` under the current CMake binary
-#   directory.
-# - IREE_<CONFIG_NAME>_C_COMPILER: C compiler for the given `CONFIG_NAME`.
-#   This must be defined by the caller.
-# - IREE_<CONFIG_NAME>_CXX_COMPILER: C++ compiler for the given `CONFIG_NAME`.
-#   This must be defined by the caller.
-# - IREE_<CONFIG_NAME>_<option>: switch for the given `option` specifically for
-#   `CONFIG_NAME`. If missing, default to OFF for bool options; default to
-#   IREE_<option> for non-bool variables.
-function(iree_create_configuration CONFIG_NAME)
-  # Set IREE_${CONFIG_NAME}_BINARY_ROOT if missing.
-  if(NOT DEFINED IREE_${CONFIG_NAME}_BINARY_ROOT)
-    set(IREE_${CONFIG_NAME}_BINARY_ROOT "${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}")
-    set(IREE_${CONFIG_NAME}_BINARY_ROOT ${IREE_${CONFIG_NAME}_BINARY_ROOT} PARENT_SCOPE)
-    message(STATUS "Setting ${CONFIG_NAME} build directory to ${IREE_${CONFIG_NAME}_BINARY_ROOT}")
-  endif()
-
-  set(_CONFIG_BINARY_ROOT ${IREE_${CONFIG_NAME}_BINARY_ROOT})
-
-  set(_CONFIG_C_COMPILER ${IREE_${CONFIG_NAME}_C_COMPILER})
-  set(_CONFIG_CXX_COMPILER ${IREE_${CONFIG_NAME}_CXX_COMPILER})
-
-  # Check the compilers are specified in the caller.
-  if("${_CONFIG_C_COMPILER}" STREQUAL "")
-    message(FATAL_ERROR "Must define IREE_${CONFIG_NAME}_C_COMPILER for \"${CONFIG_NAME}\" configuration build")
-  endif()
-  if("${_CONFIG_CXX_COMPILER}" STREQUAL "")
-    message(FATAL_ERROR "Must define IREE_${CONFIG_NAME}_CXX_COMPILER for \"${CONFIG_NAME}\" configuration build")
-  endif()
-
-  add_custom_command(OUTPUT ${_CONFIG_BINARY_ROOT}
-    COMMAND ${CMAKE_COMMAND} -E make_directory ${_CONFIG_BINARY_ROOT}
-    COMMENT "Creating ${_CONFIG_BINARY_ROOT}...")
-
-  # Give it a custom target so we can drive the generation manually
-  # when useful.
-  add_custom_target(iree_prepare_${CONFIG_NAME}_dir DEPENDS ${_CONFIG_BINARY_ROOT})
-
-  # Compile options. keep these in sync with the root CMakeLists.txt and the
-  # invoke options below.
-  iree_to_bool(_CONFIG_ENABLE_RUNTIME_TRACING "${IREE_${CONFIG_NAME}_ENABLE_RUNTIME_TRACING}")
-  iree_to_bool(_CONFIG_ENABLE_MLIR "${IREE_${CONFIG_NAME}_ENABLE_MLIR}")
-  iree_to_bool(_CONFIG_ENABLE_EMITC "${IREE_${CONFIG_NAME}_ENABLE_EMITC}")
-
-  iree_to_bool(_CONFIG_BUILD_COMPILER "${IREE_${CONFIG_NAME}_BUILD_COMPILER}")
-  iree_to_bool(_CONFIG_BUILD_TESTS "${IREE_${CONFIG_NAME}_BUILD_TESTS}")
-  iree_to_bool(_CONFIG_BUILD_DOCS "${IREE_${CONFIG_NAME}_BUILD_DOCS}")
-  iree_to_bool(_CONFIG_BUILD_SAMPLES "${IREE_${CONFIG_NAME}_BUILD_SAMPLES}")
-  iree_to_bool(_CONFIG_BUILD_DEBUGGER "${IREE_${CONFIG_NAME}_BUILD_DEBUGGER}")
-  iree_to_bool(_CONFIG_BUILD_PYTHON_BINDINGS "${IREE_${CONFIG_NAME}_BUILD_PYTHON_BINDINGS}")
-  iree_to_bool(_CONFIG_BUILD_JAVA_BINDINGS "${IREE_${CONFIG_NAME}_BUILD_JAVA_BINDINGS}")
-  iree_to_bool(_CONFIG_BUILD_EXPERIMENTAL_MODEL_BUILDER "${IREE_${CONFIG_NAME}_BUILD_EXPERIMENTAL_MODEL_BUILDER}")
-  iree_to_bool(_CONFIG_BUILD_EXPERIMENTAL_REMOTING "${IREE_${CONFIG_NAME}_BUILD_EXPERIMENTAL_REMOTING}")
-  iree_to_bool(_CONFIG_BUILD_TENSORFLOW_COMPILER "${IREE_${CONFIG_NAME}_BUILD_TENSORFLOW_COMPILER}")
-
-  # Escape semicolons in the targets list so that CMake doesn't expand them to
-  # spaces.
-  string(REPLACE ";" "$<SEMICOLON>" _CONFIG_HAL_DRIVERS_TO_BUILD "${IREE_HAL_DRIVERS_TO_BUILD}")
-  string(REPLACE ";" "$<SEMICOLON>" _CONFIG_TARGET_BACKENDS_TO_BUILD "${IREE_TARGET_BACKENDS_TO_BUILD}")
-
-  message(STATUS "C compiler for ${CONFIG_NAME} build: ${_CONFIG_C_COMPILER}")
-  message(STATUS "C++ compiler for ${CONFIG_NAME} build: ${_CONFIG_CXX_COMPILER}")
-
-  add_custom_command(OUTPUT ${IREE_${CONFIG_NAME}_BINARY_ROOT}/CMakeCache.txt
-    COMMAND "${CMAKE_COMMAND}" "${CMAKE_CURRENT_SOURCE_DIR}"
-        -G "${CMAKE_GENERATOR}"
-        -DCMAKE_MAKE_PROGRAM="${CMAKE_MAKE_PROGRAM}"
-        -DCMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE}"
-        -DCMAKE_C_COMPILER="${_CONFIG_C_COMPILER}"
-        -DCMAKE_CXX_COMPILER="${_CONFIG_CXX_COMPILER}"
-        # Invoke options. Keep these in sync with the root CMakeLists.txt and
-        # the compile options above
-        -DIREE_ENABLE_RUNTIME_TRACING=${_CONFIG_ENABLE_RUNTIME_TRACING}
-        -DIREE_ENABLE_MLIR=${_CONFIG_ENABLE_MLIR}
-        -DIREE_ENABLE_EMITC=${_CONFIG_ENABLE_EMITC}
-        -DIREE_BUILD_COMPILER=${_CONFIG_BUILD_COMPILER}
-        -DIREE_BUILD_TESTS=${_CONFIG_BUILD_TESTS}
-        -DIREE_BUILD_DOCS=${_CONFIG_BUILD_DOCS}
-        -DIREE_BUILD_SAMPLES=${_CONFIG_BUILD_SAMPLES}
-        -DIREE_BUILD_DEBUGGER=${_CONFIG_BUILD_DEBUGGER}
-        -DIREE_BUILD_PYTHON_BINDINGS=${_CONFIG_BUILD_PYTHON_BINDINGS}
-        -DIREE_BUILD_JAVA_BINDINGS=${_CONFIG_BUILD_JAVA_BINDINGS}
-        -DIREE_BUILD_EXPERIMENTAL_MODEL_BUILDER=${_CONFIG_BUILD_EXPERIMENTAL_MODEL_BUILDER}
-        -DIREE_BUILD_EXPERIMENTAL_REMOTING=${_CONFIG_BUILD_EXPERIMENTAL_REMOTING}
-        -DIREE_BUILD_TENSORFLOW_COMPILER=${_CONFIG_BUILD_TENSORFLOW_COMPILER}
-
-        -DIREE_HAL_DRIVERS_TO_BUILD="${_CONFIG_HAL_DRIVERS_TO_BUILD}"
-        -DIREE_TARGET_BACKENDS_TO_BUILD="${_CONFIG_TARGET_BACKENDS_TO_BUILD}"
-        -DIREE_ENABLE_ASAN=${IREE_ENABLE_ASAN}
-        -DIREE_ENABLE_MSAN=${IREE_ENABLE_MSAN}
-        -DIREE_ENABLE_TSAN=${IREE_ENABLE_TSAN}
-        -DIREE_ENABLE_CCACHE=${IREE_ENABLE_CCACHE}
-        -DLLVM_CCACHE_BUILD=${LLVM_CCACHE_BUILD}
-        -DCMAKE_VERBOSE_MAKEFILE=${CMAKE_VERBOSE_MAKEFILE}
-    WORKING_DIRECTORY ${_CONFIG_BINARY_ROOT}
-    DEPENDS iree_prepare_${CONFIG_NAME}_dir
-    COMMENT "Configuring IREE for ${CONFIG_NAME} build...")
-
-  add_custom_target(iree_configure_${CONFIG_NAME} DEPENDS ${_CONFIG_BINARY_ROOT}/CMakeCache.txt)
-endfunction()
-
-# iree_get_build_command
-#
-# Gets the CMake build command for the given `EXECUTABLE_TARGET`.
-#
-# Parameters:
-# EXECUTABLE_TARGET: the target for the executable to build.
-# BINDIR: root binary directory containing CMakeCache.txt.
-# CMDVAR: variable name for receiving the build command.
-function(iree_get_build_command EXECUTABLE_TARGET)
-  cmake_parse_arguments(_RULE "" "BINDIR;CMDVAR;CONFIG" "" ${ARGN})
-  if(NOT _RULE_CONFIG)
-    set(_RULE_CONFIG "$<CONFIG>")
-  endif()
-  if(CMAKE_GENERATOR MATCHES "Make")
-    # Use special command for Makefiles to support parallelism.
-    set(${_RULE_CMDVAR}
-        "$(MAKE)" "-C" "${_RULE_BINDIR}" "${EXECUTABLE_TARGET}" PARENT_SCOPE)
-  else()
-    set(${_RULE_CMDVAR}
-        "${CMAKE_COMMAND}" --build ${_RULE_BINDIR}
-                           --target ${EXECUTABLE_TARGET}
-                           --config ${_RULE_CONFIG} PARENT_SCOPE)
-  endif()
-endfunction()
-
-# iree_host_install
-#
-# Defines custom commands and targets for installing the given `EXECUTABLE`
-# under host configuration. The custom target for install will be named as
-# `iree_host_install_${EXECUTABLE}`.
-#
-# Precondition:
-# iree_create_configuration(HOST) is invoked previously.
-#
-# Parameters:
-# EXECUTABLE: the executable to install.
-# COMPONENT: installation component; used for filtering installation targets.
-# PREFIX: the root installation path prefix.
-# DEPENDS: addtional dependencies for the installation.
-function(iree_host_install EXECUTABLE)
-  cmake_parse_arguments(_RULE "" "COMPONENT;PREFIX" "DEPENDS" ${ARGN})
-  if(_RULE_COMPONENT)
-    set(_COMPONENT_OPTION -DCMAKE_INSTALL_COMPONENT="${_RULE_COMPONENT}")
-  endif()
-  if(_RULE_PREFIX)
-    set(_PREFIX_OPTION -DCMAKE_INSTALL_PREFIX="${_RULE_PREFIX}")
-  endif()
-
-  iree_get_executable_path(_OUTPUT_PATH ${EXECUTABLE})
-
-  add_custom_command(
-    OUTPUT ${_OUTPUT_PATH}
-    DEPENDS ${_RULE_DEPENDS}
-    COMMAND "${CMAKE_COMMAND}" ${_COMPONENT_OPTION} ${_PREFIX_OPTION}
-            -P "${IREE_HOST_BINARY_ROOT}/cmake_install.cmake"
-    USES_TERMINAL)
-
-  # Give it a custom target so we can drive the generation manually
-  # when useful.
-  add_custom_target(iree_host_install_${EXECUTABLE} DEPENDS ${_OUTPUT_PATH})
-endfunction()
-
-# iree_declare_host_excutable
-#
-# Generates custom commands and targets for building and installing a tool on
-# host for cross-compilation.
-#
-# Precondition:
-# iree_create_configuration(HOST) is invoked previously.
-#
-# Parameters:
-# EXECUTABLE: the executable to build on host.
-# EXECUTABLE_TARGET: the target name for the executable.
-# BUILDONLY: only generates commands for building the target.
-# DEPENDS: any additional dependencies for the target.
-function(iree_declare_host_excutable EXECUTABLE EXECUTABLE_TARGET)
-  cmake_parse_arguments(_RULE "BUILDONLY" "" "DEPENDS" ${ARGN})
-
-  iree_get_executable_path(_OUTPUT_PATH ${EXECUTABLE})
-
-  iree_get_build_command(${EXECUTABLE_TARGET}
-    BINDIR ${IREE_HOST_BINARY_ROOT}
-    CMDVAR build_cmd)
-
-  add_custom_target(iree_host_build_${EXECUTABLE}
-                    COMMAND ${build_cmd}
-                    DEPENDS iree_configure_HOST ${_RULE_DEPENDS}
-                    WORKING_DIRECTORY "${IREE_HOST_BINARY_ROOT}"
-                    COMMENT "Building host ${EXECUTABLE}..."
-                    USES_TERMINAL)
-
-  if(_RULE_BUILDONLY)
-    return()
-  endif()
-
-  iree_host_install(${EXECUTABLE}
-                    COMPONENT ${EXECUTABLE}
-                    PREFIX ${IREE_HOST_BINARY_ROOT}
-                    DEPENDS iree_host_build_${EXECUTABLE})
-
-  # Note that this is not enabled when BUILDONLY so we can define
-  # iree_host_${EXECUTABLE} to point to another installation path to
-  # allow flexibility.
-  add_custom_target(iree_host_${EXECUTABLE} DEPENDS "${_OUTPUT_PATH}")
-endfunction()
diff --git a/build_tools/cmake/iree_lit_test.cmake b/build_tools/cmake/iree_lit_test.cmake
index e6974b9..3a28ca0 100644
--- a/build_tools/cmake/iree_lit_test.cmake
+++ b/build_tools/cmake/iree_lit_test.cmake
@@ -35,11 +35,9 @@
     return()
   endif()
 
-  # When *not* cross compiling, respect the IREE_BUILD_COMPILER option.
-  # Cross compilation uses its own "IREE_HOST_BUILD_COMPILER" option.
   # Note: lit tests are not *required* to be "compiler" tests, but we only use
   # them for compiler tests in practice.
-  if(NOT IREE_BUILD_COMPILER AND NOT CMAKE_CROSSCOMPILING)
+  if(NOT IREE_BUILD_COMPILER)
     return()
   endif()
 
diff --git a/build_tools/cmake/iree_macros.cmake b/build_tools/cmake/iree_macros.cmake
index a6ce531..22d4ce9 100644
--- a/build_tools/cmake/iree_macros.cmake
+++ b/build_tools/cmake/iree_macros.cmake
@@ -244,27 +244,6 @@
 endfunction()
 
 #-------------------------------------------------------------------------------
-# Executable dependencies
-#-------------------------------------------------------------------------------
-
-# iree_add_executable_dependencies
-#
-# Adds dependency on a target in a cross-compilation-aware way. This should
-# be used for depending on targets that are used as part of the build, such
-# as for generating files used for later build steps.
-#
-# Parameters:
-# EXECUTABLE: the executable to take on dependencies
-# DEPENDENCY: additional dependencies to append to target
-function(iree_add_executable_dependencies EXECUTABLE DEPENDENCY)
-  if(CMAKE_CROSSCOMPILING)
-    add_dependencies(${EXECUTABLE} iree_host_${DEPENDENCY})
-  else()
-    add_dependencies(${EXECUTABLE} ${DEPENDENCY})
-  endif()
-endfunction()
-
-#-------------------------------------------------------------------------------
 # Tool symlinks
 #-------------------------------------------------------------------------------
 
diff --git a/build_tools/embed_data/CMakeLists.txt b/build_tools/embed_data/CMakeLists.txt
index 8679ccc..48f566d 100644
--- a/build_tools/embed_data/CMakeLists.txt
+++ b/build_tools/embed_data/CMakeLists.txt
@@ -12,9 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-if(CMAKE_CROSSCOMPILING)
-  iree_declare_host_excutable(generate_cc_embed_data "generate_cc_embed_data")
-else()
+if(NOT CMAKE_CROSSCOMPILING)
   add_executable(generate_cc_embed_data)
   target_sources(generate_cc_embed_data PRIVATE generate_cc_embed_data_main.cc)
   set_target_properties(generate_cc_embed_data PROPERTIES OUTPUT_NAME generate_cc_embed_data)
diff --git a/build_tools/mako/compile_android_modules.sh b/build_tools/mako/compile_android_modules.sh
index fd965c3..ace5b86 100755
--- a/build_tools/mako/compile_android_modules.sh
+++ b/build_tools/mako/compile_android_modules.sh
@@ -19,7 +19,7 @@
 #
 # The scripts is used for benchmarking automation, and it assumes:
 #   1) ANDROID_NDK env is set.
-#   2) IREE is built to Android in `build/` directory. E.g., build with
+#   2) IREE is built for the host in `build-host`, e.g. build with
 #      build_tools/cmake/build_android.sh script.
 
 set -e
@@ -50,8 +50,6 @@
   exit 1
 fi
 
-export IREE_LLVMAOT_LINKER_PATH="${ANDROID_NDK?}/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android29-clang++ -static-libstdc++ -O3"
-
 IFS=',' read -ra targets_array <<< "$targets"
 for target in "${targets_array[@]}"
 do
@@ -65,7 +63,7 @@
     *)
       ;;
   esac
-  build/host/iree/tools/iree-translate \
+  build-host/iree/tools/iree-translate \
     --iree-mlir-to-vm-bytecode-module \
     --iree-hal-target-backends="${target}" \
     "${extra_flags[@]}" \
diff --git a/build_tools/third_party/flatcc/CMakeLists.txt b/build_tools/third_party/flatcc/CMakeLists.txt
index f1ad43e..59946d5 100644
--- a/build_tools/third_party/flatcc/CMakeLists.txt
+++ b/build_tools/third_party/flatcc/CMakeLists.txt
@@ -14,7 +14,6 @@
 
 set(FLATCC_ROOT "${IREE_ROOT_DIR}/third_party/flatcc/")
 
-# NOTE: we exclude JSON parsing/printing to avoid additional dependencies.
 external_cc_library(
   PACKAGE
     flatcc
@@ -55,3 +54,22 @@
     "include/flatcc/reflection/flatbuffers_common_reader.h"
   PUBLIC
 )
+
+# Define our own binary target for the CLI, for host builds only.
+# flatcc's `flatcc_cli` target renames itself to `flatcc` or `flatcc_d`
+# depending on the build configuration, so we prefer to just set our own name.
+if(NOT CMAKE_CROSSCOMPILING)
+  add_executable(iree-flatcc-cli
+    "${FLATCC_ROOT}/src/cli/flatcc_cli.c"
+  )
+
+  target_link_libraries(iree-flatcc-cli
+    flatcc
+  )
+
+  target_include_directories(iree-flatcc-cli SYSTEM
+    PUBLIC
+      "${FLATCC_ROOT}/include"
+      "${FLATCC_ROOT}/config"
+  )
+endif()
diff --git a/docs/get_started/cmake_options_and_variables.md b/docs/get_started/cmake_options_and_variables.md
index 1ac4871..b88fe43 100644
--- a/docs/get_started/cmake_options_and_variables.md
+++ b/docs/get_started/cmake_options_and_variables.md
@@ -127,71 +127,8 @@
 
 ## Cross-compilation
 
-[TODO(#2111): The following explanation is developer oriented. Move it to the
-developer build doc once we've created that.]
-
-Cross-compilation involves both a *host* platform and a *target* platform. One
-invokes compiler toolchains on the host platform to generate libraries and
-executables that can be run on the target platform.
-
-IREE uses tools to programmatically generate C/C++ source code from some
-domain-specific descriptions. For example, `flatc` is used to generate C/C++
-code from FlatBuffer schemas. These tools should be compiled for the host
-platform so that we can invoke them during build process. This requires
-cross-compilation for IREE to (conceptually) happen in two stages: first compile
-build tools under host platform, and then use these host tools together with
-cross-compiling toolchains to generate artifacts for the target platform. (The
-build system dependency graph may not have such clear two-stage separation.)
-
-CMake cannot handle multiple compiler toolchains in one CMake invocation. So the
-above conceptual two-stage compilation happens in two separate CMake
-invocations.
-
-When CMake is invoked with a toolchain file, e.g.,
-[`android.toolchain.cmake`](https://android.googlesource.com/platform/ndk/+/master/build/cmake/android.toolchain.cmake),
-we get the compiler toolchain for the target platform from the toolchain file.
-IREE under the hood will
-[create another CMake invocation](https://github.com/google/iree/blob/main/build_tools/cmake/iree_cross_compile.cmake)
-using host platform's compiler toolchain. The inner CMake invocation will be
-placed under `IREE_HOST_BINARY_ROOT`.
-
-The tricky part is to set up target artifacts' dependencies on host executables.
-Normally in CMake we define targets and `target_link_libraries` to express the
-dependency relationship between targets. The optimal way is to
-[`export`](https://cmake.org/cmake/help/latest/command/export.html) targets
-under host configuration and then
-[`import`](https://cmake.org/cmake/help/latest/command/add_executable.html?highlight=import#imported-executables)
-into target configuration. But that is not playing well with LLVM's TableGen
-configurations. LLVM's cross-compilation uses on files for dependencies. So here
-we need to do the same. This results in reverting the relationship between IREE
-artifact output names (e.g., `iree-translate`) and IREE package-prefixed CMake
-target names (e.g., `iree_tools_iree-translate`).
-
-When not cross-compiling, IREE uses the CMake target names as the real unique
-identification inside CMake for defining the object and expressing dependencies;
-the artifact output names are just used for naming the build artifacts. When
-cross-compiling, it's the artifact names being load-bearing. The artifact names
-are used to express dependencies across CMake invocation boundary (remember that
-we cannot access targets defined in another CMake invocation); the
-package-prefixed CMake target names are just custom targets depending on the
-host artifact.
-
-#### `IREE_HOST_BINARY_ROOT`:FILEPATH
-
-Specifies the root directory for containing all host CMake invocation artifacts.
-This defaults to `CMAKE_BINARY_DIR/host` if missing.
-
-#### `IREE_HOST_C_COMPILER`:STRING
-
-Specifies the C compiler for host compilation.
-
-#### `IREE_HOST_CXX_COMPILER`:STRING
-
-Specifies the C++ compiler for host compilation.
-
-#### `IREE_HOST_<option>`:BOOL
-
-For each option described in "IREE-specific CMake Options and Variables", you
-can use the `IREE_HOST_<option>` counterpart to control the feature when
-compiling under host configuration. For example, `IREE_HOST_BUILD_TESTS` will
-enables all tests for the host configuration.
+When cross compiling (using a toolchain file like
+[`android.toolchain.cmake`](https://android.googlesource.com/platform/ndk/+/master/build/cmake/android.toolchain.cmake)),
+first build and install IREE's tools for your host configuration, then use the
+`IREE_HOST_BINARY_ROOT` CMake option to point the cross compiled build at the
+host tools.
diff --git a/docs/get_started/getting_started_android_cmake.md b/docs/get_started/getting_started_android_cmake.md
index 874b183..7aed754 100644
--- a/docs/get_started/getting_started_android_cmake.md
+++ b/docs/get_started/getting_started_android_cmake.md
@@ -61,15 +61,28 @@
 
 ## Configure and build
 
-### Configure on Linux
+### Host configuration
+
+Build and install at least the compiler tools on your host machine, or install
+them from a binary distribution:
+
+```shell
+$ cmake -G Ninja -B ../iree-build-host/ -DCMAKE_INSTALL_PREFIX=../iree-build-host/install .
+$ cmake --build ../iree-build-host/ --target install
+```
+
+### Target configuration
+
+Build the runtime using the Android NDK toolchain:
 
 ```shell
 $ cmake -G Ninja -B ../iree-build-android/ \
   -DCMAKE_TOOLCHAIN_FILE="${ANDROID_NDK?}/build/cmake/android.toolchain.cmake" \
+  -DIREE_HOST_BINARY_ROOT=../iree-build-host/install
   -DANDROID_ABI="arm64-v8a" -DANDROID_PLATFORM=android-29 \
-  -DIREE_BUILD_COMPILER=OFF -DIREE_BUILD_SAMPLES=OFF \
-  -DIREE_HOST_C_COMPILER=`which clang` -DIREE_HOST_CXX_COMPILER=`which clang++` \
+  -DIREE_BUILD_COMPILER=OFF -DIREE_ENABLE_MLIR=OFF -DIREE_BUILD_SAMPLES=OFF \
   .
+$ cmake --build ../iree-build-android/
 ```
 
 *   The above configures IREE to cross-compile towards 64-bit
@@ -81,38 +94,6 @@
     for your target device. You can also refer to Android NDK's
     [CMake documentation](https://developer.android.com/ndk/guides/cmake) for
     more toolchain arguments.
-*   Building IREE compilers and samples for Android is not supported at the
-    moment.
-*   We define `IREE_HOST_{C|CXX}_COMPILER` to Clang here because IREE has
-    [unstable support for GCC](https://github.com/google/iree/issues/1269).
-
-### Configure on Windows
-
-On Windows, we will need the full path to the `cl.exe` compiler. This can be
-obtained by
-[opening a developer command prompt window](https://docs.microsoft.com/en-us/cpp/build/building-on-the-command-line?view=vs-2019#developer_command_prompt)
-and running `where cl.exe`. Then in a command prompt (`cmd.exe`):
-
-```cmd
-> cmake -G Ninja -B ../iree-build-android/  \
-    -DCMAKE_TOOLCHAIN_FILE="%ANDROID_NDK%/build/cmake/android.toolchain.cmake" \
-    -DANDROID_ABI="arm64-v8a" -DANDROID_PLATFORM=android-29 \
-    -DIREE_BUILD_COMPILER=OFF -DIREE_BUILD_SAMPLES=OFF \
-    -DIREE_HOST_C_COMPILER="<full-path-to-cl.exe>" \
-    -DIREE_HOST_CXX_COMPILER="<full-path-to-cl.exe>" \
-    -DLLVM_HOST_TRIPLE="x86_64-pc-windows-msvc" \
-    .
-```
-
-*   See the Linux section in the above for explanations of the used arguments.
-*   We need to define `LLVM_HOST_TRIPLE` in the above because LLVM cannot
-    yet properly detect host triple from the Android CMake toolchain file.
-
-### Build all targets
-
-```shell
-$ cmake --build ../iree-build-android/
-```
 
 ## Test on Android
 
@@ -148,7 +129,7 @@
 
 ```shell
 # Assuming in IREE source root
-$ ../iree-build-android/host/bin/iree-translate \
+$ ../iree-build-host/install/bin/iree-translate \
   -iree-mlir-to-vm-bytecode-module \
   -iree-hal-target-backends=vmla \
   $PWD/iree/tools/test/simple.mlir \
@@ -186,7 +167,7 @@
 Translate a source MLIR into IREE module:
 
 ```shell
-$ ../iree-build-android/host/bin/iree-translate \
+$ ../iree-build-host/install/bin/iree-translate \
     -iree-mlir-to-vm-bytecode-module \
     -iree-hal-target-backends=vulkan-spirv \
     $PWD/iree/tools/test/simple.mlir \
@@ -259,22 +240,10 @@
 
 ### Dylib LLVM AOT backend
 
-To compile an IREE module using the Dylib LLVM ahead-of-time (AOT) backend for
-a target Android device (e.g. Android 10 AArch64) we need to use the
-corresponding standalone toolchain which can be found in `ANDROID_NDK`.
-Set the AOT linker path environment variable:
-
-```shell
-$ export IREE_LLVMAOT_LINKER_PATH="${ANDROID_NDK?}/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android29-clang++ -static-libstdc++ -O3"
-```
-
-`-static-libstdc++` is needed because some dynamic libraries would not be able
-to open.
-
 Translate a source MLIR into an IREE module:
 
 ```shell
-$ ../iree-build-android/host/bin/iree-translate \
+$ ../iree-build-host/install/bin/iree-translate \
   -iree-mlir-to-vm-bytecode-module \
   -iree-hal-target-backends=dylib-llvm-aot \
   -iree-llvm-target-triple=aarch64-linux-android \
diff --git a/iree/compiler/Dialect/HAL/Target/LLVM/internal/UnixLinkerTool.cpp b/iree/compiler/Dialect/HAL/Target/LLVM/internal/UnixLinkerTool.cpp
index 71a13bb..a2ba44c 100644
--- a/iree/compiler/Dialect/HAL/Target/LLVM/internal/UnixLinkerTool.cpp
+++ b/iree/compiler/Dialect/HAL/Target/LLVM/internal/UnixLinkerTool.cpp
@@ -33,25 +33,35 @@
   std::string getToolPath() const override {
     auto toolPath = LinkerTool::getToolPath();
     if (!toolPath.empty()) return toolPath;
+
     if (targetTriple.isAndroid()) {
       char *androidNDKPath = std::getenv("ANDROID_NDK");
       if (!androidNDKPath) return toolPath;
-// TODO(ataei, benvanik): Windows cross-linking android NDK support.
-#if defined(IREE_ARCH_X86_64) && defined(IREE_PLATFORM_LINUX)
-      return llvm::Twine(androidNDKPath)
-          .concat("/toolchains/llvm/prebuilt/linux-x86_64/bin/")
-          // TODO(ataei): Set target archicture and ABI from targetTriple.
-          .concat("aarch64-linux-android30-clang++")
-          .str();
-#elif defined(IREE_ARCH_X86_64) && defined(IREE_PLATFORM_APPLE)
-      return llvm::Twine(androidNDKPath)
-          .concat("/toolchains/llvm/prebuilt/darwin-x86_64/bin/")
-          .concat("aarch64-linux-android30-clang++")
-          .str();
+
+      // Select prebuilt toolchain based on host architecture/platform:
+      // https://developer.android.com/ndk/guides/other_build_systems
+      std::string toolchains_binary_path;
+#if defined(IREE_PLATFORM_LINUX) && defined(IREE_ARCH_X86_64)
+      toolchains_binary_path = "/toolchains/llvm/prebuilt/linux-x86_64/bin/";
+#elif defined(IREE_PLATFORM_APPLE) && defined(IREE_ARCH_X86_64)
+      toolchains_binary_path = "/toolchains/llvm/prebuilt/darwin-x86_64/bin/";
+#elif defined(IREE_PLATFORM_WINDOWS) && defined(IREE_ARCH_X86_32)
+      toolchains_binary_path = "/toolchains/llvm/prebuilt/windows/bin/";
+#elif defined(IREE_PLATFORM_WINDOWS) && defined(IREE_ARCH_X86_64)
+      toolchains_binary_path = "/toolchains/llvm/prebuilt/windows-x86_64/bin/";
 #else
-      return toolPath;
-#endif  // IREE_ARCH_X86_64 && IREE_PLATFORM_LINUX
+      llvm::errs() << "Unknown architecture/platform combination"
+                   << "\n";
+      return "";
+#endif  // IREE_PLATFORM_* && IREE_ARCH_*
+
+      // TODO(ataei): Set target architecture and ABI from targetTriple.
+      return llvm::Twine(androidNDKPath)
+          .concat(toolchains_binary_path)
+          .concat("aarch64-linux-android30-clang++")
+          .str();
     }
+
 // TODO(ataei, benvanik): Windows cross-linking discovery support.
 #if defined(IREE_PLATFORM_LINUX) || defined(IREE_PLATFORM_MACOS)
 #define UNIX_SYS_LINKER_PATH_LENGTH 255
diff --git a/iree/tools/CMakeLists.txt b/iree/tools/CMakeLists.txt
index 318e8b3..5a49475 100644
--- a/iree/tools/CMakeLists.txt
+++ b/iree/tools/CMakeLists.txt
@@ -325,6 +325,16 @@
 
   iree_cc_binary(
     NAME
+      iree-translate
+    OUT
+      iree-translate
+    DEPS
+      ::iree_translate_main
+    HOSTONLY
+  )
+
+  iree_cc_binary(
+    NAME
       iree-opt
     OUT
       iree-opt
@@ -381,18 +391,3 @@
     )
   endif()
 endif(${IREE_BUILD_COMPILER})
-
-# If cross-compiling, we need to declare iree-translate under host configuration
-# unconditionally because we need to run it on host to generate VM modules
-# for tests.
-if(${IREE_BUILD_COMPILER} OR CMAKE_CROSSCOMPILING)
-  iree_cc_binary(
-    NAME
-      iree-translate
-    OUT
-      iree-translate
-    DEPS
-      ::iree_translate_main
-    HOSTONLY
-  )
-endif()