diff --git a/.travis.yml b/.travis.yml
index 91570c1c93e8ab2e4c92b1942ad4faf387e69123..4be7e2ec77d697388f66e5fe0204988b7936dfb0 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,112 +1,188 @@
 language: rust
-rust: stable
+rust: nightly
 sudo: required
 dist: xenial
 services: docker
 
+stages:
+  - tools-and-build-and-tier1
+  - tier2
+
 matrix:
   include:
-    # 1.13.0 compat
-    - env: TARGET=x86_64-unknown-linux-gnu
-      rust: 1.13.0
-      script: rm -f Cargo.lock && cargo build
-      install: true
-
-    # build documentation
-    - env: TARGET=x86_64-unknown-linux-gnu
-      rust: nightly
+    # TOOLS
+    - name: "Documentation"
+      env: TARGET=x86_64-unknown-linux-gnu
       script: sh ci/dox.sh
       install: true
-
-    # stable compat
-    - env: TARGET=x86_64-unknown-linux-gnu
+      stage: tools-and-build-and-tier1
+    - name: "Shellcheck"
       install: true
-    - env: TARGET=i686-unknown-linux-gnu
-    - os: osx
-      env: TARGET=x86_64-apple-darwin
+      script:
+        - shellcheck --version
+        - shellcheck ci/*.sh
+      stage: tools-and-build-and-tier1
+    - name: "Style"
+      install: rustup component add rustfmt-preview
+      script:
+        - rustc ci/style.rs && ./style src
+        - cargo fmt --all -- --check
+      stage: tools-and-build-and-tier1
+
+    # BUILD stable, beta, nightly
+    - name: "Build Stable Rust"
+      script: sh ci/build.sh
+      stage: tools-and-build-and-tier1
+      rust: stable
+    - name: "Build Beta Rust"
+      script: sh ci/build.sh
+      stage: tools-and-build-and-tier1
+      rust: beta
+    - name: "Build Nightly Rust"
+      script: sh ci/build.sh
+      stage: tools-and-build-and-tier1
+      rust: nightly
+    - name: "Build Stable Rust"
+      script: sh ci/build.sh
+      stage: tools-and-build-and-tier1
+      rust: stable
+      os: osx
       osx_image: xcode10
-      install: true
-    - os: osx
-      env: TARGET=i686-apple-darwin
+    - name: "Build Beta Rust"
+      script: sh ci/build.sh
+      stage: tools-and-build-and-tier1
+      rust: beta
+      os: osx
       osx_image: xcode10
-    - env: TARGET=arm-linux-androideabi
+    - name: "Build Nightly Rust"
+      script: sh ci/build.sh
+      stage: tools-and-build-and-tier1
+      rust: nightly
+      os: osx
+      osx_image: xcode10
+    - name: "Build Stable Rust 1.13.0"
+      script: sh ci/build.sh
+      stage: tools-and-build-and-tier1
+      rust: 1.13.0
+    - name: "Build Stable Rust 1.19.0"
+      script: sh ci/build.sh
+      stage: tools-and-build-and-tier1
+      rust: 1.19.0
+    - name: "Build Stable Rust 1.24.0"
+      script: sh ci/build.sh
+      stage: tools-and-build-and-tier1
+      rust: 1.24.0
+    - name: "Build Stable Rust 1.25.0"
+      script: sh ci/build.sh
+      stage: tools-and-build-and-tier1
+      rust: 1.25.0
+    - name: "Build Stable Rust 1.30.0"
+      script: sh ci/build.sh
+      stage: tools-and-build-and-tier1
+      rust: 1.30.0
+    - name: "Build Stable Rust 1.13.0"
+      script: sh ci/build.sh
+      stage: tools-and-build-and-tier1
+      rust: 1.13.0
+      os: osx
+      osx_image: xcode10
+    - name: "Build Stable Rust 1.19.0"
+      script: sh ci/build.sh
+      stage: tools-and-build-and-tier1
+      rust: 1.19.0
+      os: osx
+      osx_image: xcode10
+    - name: "Build Stable Rust 1.24.0"
+      script: sh ci/build.sh
+      stage: tools-and-build-and-tier1
+      rust: 1.24.0
+      os: osx
+      osx_image: xcode10
+    - name: "Build Stable Rust 1.25.0"
+      script: sh ci/build.sh
+      stage: tools-and-build-and-tier1
+      rust: 1.25.0
+      os: osx
+      osx_image: xcode10
+    - name: "Build Stable Rust 1.30.0"
+      script: sh ci/build.sh
+      stage: tools-and-build-and-tier1
+      rust: 1.30.0
+      os: osx
+      osx_image: xcode10
+    - env: TARGET=i686-apple-darwin
+      os: osx
+      osx_image: xcode10
+      stage: tools-and-build-and-tier1
+    - env: TARGET=i686-unknown-linux-gnu
+      stage: tools-and-build-and-tier1
+    - env: TARGET=x86_64-apple-darwin
+      os: osx
+      osx_image: xcode10
+      stage: tools-and-build-and-tier1
+    - env: TARGET=x86_64-unknown-linux-gnu
+      stage: tools-and-build-and-tier1
+
+    # Tier 2 targets
     - env: TARGET=aarch64-linux-android
-    # FIXME(#826) should reenable
-    #- env: TARGET=i686-linux-android
-    - env: TARGET=x86_64-linux-android
-    - env: TARGET=x86_64-unknown-linux-musl
-    - env: TARGET=i686-unknown-linux-musl
-    - env: TARGET=arm-unknown-linux-gnueabihf
-    - env: TARGET=arm-unknown-linux-musleabihf
+      stage: tier2
     - env: TARGET=aarch64-unknown-linux-gnu
+      stage: tier2
     - env: TARGET=aarch64-unknown-linux-musl
-    - env: TARGET=powerpc-unknown-linux-gnu
-    - env: TARGET=powerpc64-unknown-linux-gnu
-    - env: TARGET=powerpc64le-unknown-linux-gnu
+      stage: tier2
+    - env: TARGET=arm-linux-androideabi
+      stage: tier2
+    - env: TARGET=arm-unknown-linux-gnueabihf
+      stage: tier2
+    - env: TARGET=arm-unknown-linux-musleabihf
+      stage: tier2
+    - env: TARGET=asmjs-unknown-emscripten
+      stage: tier2
+    - env: TARGET=i686-unknown-linux-musl
+      stage: tier2
+    - env: TARGET=mips-unknown-linux-gnu
+      stage: tier2
     - env: TARGET=mips-unknown-linux-musl
-    - env: TARGET=mipsel-unknown-linux-musl
+      stage: tier2
     - env: TARGET=mips64-unknown-linux-gnuabi64
+      stage: tier2
     - env: TARGET=mips64el-unknown-linux-gnuabi64
-    - env: TARGET=mips-unknown-linux-gnu
+      stage: tier2
+    - env: TARGET=mipsel-unknown-linux-musl
+      stage: tier2
+    - env: TARGET=powerpc-unknown-linux-gnu
+      stage: tier2
+    - env: TARGET=powerpc64-unknown-linux-gnu
+      stage: tier2
+    - env: TARGET=powerpc64le-unknown-linux-gnu
+      stage: tier2
     - env: TARGET=s390x-unknown-linux-gnu
+      stage: tier2
     - env: TARGET=sparc64-unknown-linux-gnu
-    - env: TARGET=asmjs-unknown-emscripten
+      stage: tier2
     - env: TARGET=wasm32-unknown-emscripten
-
-    # beta
-    - env: TARGET=x86_64-unknown-linux-gnu
-      rust: beta
-      install: true
-    - os: osx
-      env: TARGET=x86_64-apple-darwin
-      osx_image: xcode10
-      rust: beta
-      install: true
-
-    # nightly
-    - env: TARGET=x86_64-unknown-linux-gnu
-      rust: nightly
-      install: true
-    - os: osx
-      env: TARGET=x86_64-apple-darwin
-      osx_image: xcode10
-      rust: nightly
-      install: true
-    # not available on stable
-    # without --release the build fails
-    # see https://github.com/rust-lang/rust/issues/45417
+      stage: tier2
+    - env: TARGET=x86_64-linux-android
+      stage: tier2
     - env: TARGET=x86_64-unknown-linux-gnux32 OPT="--release"
-      rust: nightly
-
-    - env: TARGET=wasm32-unknown-unknown
-      install: rustup target add $TARGET
-      script: cargo build --no-default-features --target $TARGET --release
-    - name: "Style"
-      install: rustup component add rustfmt-preview
-      script:
-        - rustc ci/style.rs && ./style src
-        - cargo fmt --all -- --check
-    - name: "Shellcheck"
-      install: true
-      script:
-        - shellcheck --version
-        - shellcheck ci/*.sh
+      stage: tier2
+    - env: TARGET=x86_64-unknown-linux-musl
+      stage: tier2
 
   allow_failures:
       # FIXME: https://github.com/rust-lang/libc/issues/1226
       - env: TARGET=asmjs-unknown-emscripten
       - env: TARGET=wasm32-unknown-emscripten
 
-install: rustup target add $TARGET
+install: rustup target add $TARGET || true
+
 script:
   - cargo generate-lockfile --manifest-path libc-test/Cargo.toml
-  - if [[ $TRAVIS_OS_NAME = "linux" ]]; then
+  - if [[ $TRAVIS_OS_NAME = "linux" ]] && [[ $BUILD_ONLY != "1" ]]; then
       sh ci/run-docker.sh $TARGET;
     else
-      export CARGO_TARGET_DIR=`pwd`/target;
       sh ci/run.sh $TARGET;
     fi
-
 env:
   global:
     secure: "e2/3QjgRN9atOuSHp22TrYG7QVKcYUWY48Hi9b60w+r1+BhPkTseIJLte7WefRhdXtqpjjUJTooKDhnurFOeHaCT+nmBgiv+FPU893sBl4bhesY4m0vgUJVbNZcs6lTImYekWVb+aqjGdgV/XAgCw7c3kPmrZV0MzGDWL64Xaps="
diff --git a/ci/build.sh b/ci/build.sh
new file mode 100644
index 0000000000000000000000000000000000000000..69805fcbc281d5875ef4a371774fb924f0198303
--- /dev/null
+++ b/ci/build.sh
@@ -0,0 +1,165 @@
+#!/usr/bin/env sh
+
+# Checks that libc builds properly for all supported targets on a particular
+# Rust version:
+
+set -ex
+
+RUST=${TRAVIS_RUST_VERSION}
+OS=${TRAVIS_OS_NAME}
+
+echo "Testing Rust ${RUST} on ${OS}"
+
+test_target() {
+    TARGET="${1}"
+
+    opt=
+    if [ "${TARGET}" = "x86_64-unknown-linux-gnux32" ]; then
+        # FIXME: x86_64-unknown-linux-gnux32 fail to compile without
+        # --release
+        #
+        # See https://github.com/rust-lang/rust/issues/45417
+        opt="--release"
+    fi
+
+    NO_STD=
+    case ${TARGET} in
+        thumbv*)
+            NO_STD=1
+            ;;
+    esac
+
+    rustup target add "${TARGET}" --toolchain "${RUST}" || true
+
+    # Test that libc builds without any default features (no libstd)
+    cargo "+${RUST}" build -vv $opt --no-default-features --target "${TARGET}"
+
+    # Test that libc builds with default features (e.g. libstd)
+    # if the target supports libstd
+    if [ "$NO_STD" != "1" ]; then
+        cargo "+${RUST}" build -vv $opt --target "${TARGET}"
+    fi
+
+    # Test that libc builds with the `extra_traits` feature
+    cargo "+${RUST}" build -vv $opt --no-default-features --target "${TARGET}" \
+          --features extra_traits
+
+    # Also test that it builds with `extra_traits` and default features:
+    if [ "$NO_STD" != "1" ]; then
+        cargo "+${RUST}" build -vv $opt --target "${TARGET}" \
+              --features extra_traits
+    fi
+}
+
+RUST_LINUX_TARGETS="\
+aarch64-linux-android \
+aarch64-unknown-linux-gnu \
+arm-linux-androideabi \
+arm-unknown-linux-gnueabi \
+arm-unknown-linux-gnueabihf \
+armv7-linux-androideabi \
+armv7-unknown-linux-gnueabihf \
+i586-unknown-linux-gnu \
+i686-linux-android \
+i686-unknown-freebsd \
+i686-unknown-linux-gnu \
+i686-unknown-linux-musl \
+mips-unknown-linux-gnu \
+mips-unknown-linux-musl \
+mips64-unknown-linux-gnuabi64 \
+mips64el-unknown-linux-gnuabi64 \
+mipsel-unknown-linux-gnu \
+mipsel-unknown-linux-gnu \
+mipsel-unknown-linux-musl \
+powerpc-unknown-linux-gnu \
+powerpc64-unknown-linux-gnu \
+powerpc64le-unknown-linux-gnu \
+s390x-unknown-linux-gnu \
+x86_64-unknown-freebsd \
+x86_64-unknown-linux-gnu \
+x86_64-unknown-linux-musl \
+x86_64-unknown-netbsd \
+"
+
+RUST_GT_1_13_LINUX_TARGETS="\
+arm-unknown-linux-musleabi \
+arm-unknown-linux-musleabihf \
+armv7-unknown-linux-musleabihf \
+sparc64-unknown-linux-gnu \
+wasm32-unknown-emscripten \
+x86_64-linux-android \
+x86_64-rumprun-netbsd \
+"
+RUST_GT_1_19_LINUX_TARGETS="\
+aarch64-unknown-linux-musl \
+sparcv9-sun-solaris \
+wasm32-unknown-unknown \
+x86_64-sun-solaris \
+"
+RUST_GT_1_24_LINUX_TARGETS="\
+i586-unknown-linux-musl \
+x86_64-unknown-cloudabi \
+"
+
+RUST_NIGHTLY_LINUX_TARGETS="\
+aarch64-fuchsia \
+thumbv6m-none-eabi \
+thumbv7em-none-eabi \
+thumbv7em-none-eabihf \
+thumbv7m-none-eabi \
+thumbv7neon-linux-androideabi \
+thumbv7neon-unknown-linux-gnueabihf \
+x86_64-fortanix-unknown-sgx \
+x86_64-fuchsia \
+x86_64-unknown-linux-gnux32 \
+x86_64-unknown-redox \
+"
+# FIXME: these do not have a rust-std component available
+# aarch64-unknown-cloudabi armv7-unknown-cloudabi-eabihf
+# i686-unknown-cloudabi powerpc-unknown-linux-gnuspe
+# sparc-unknown-linux-gnu mips-unknown-linux-uclib
+# i686-unknown-haiku mipsel-unknown-unknown-linux-uclib
+# sparc64-unknown-netbsd x86_64-unknown-bitrig x86_64-unknown-haiku
+# x86_64-unknown-openbsd i686-unknown-netbsd
+
+RUST_OSX_TARGETS="\
+aarch64-apple-ios \
+armv7-apple-ios \
+armv7s-apple-ios \
+i386-apple-ios \
+i686-apple-darwin \
+x86_64-apple-darwin \
+x86_64-apple-ios \
+"
+
+# The targets are listed here alphabetically
+TARGETS=""
+case "${OS}" in
+    linux*)
+        TARGETS="${RUST_LINUX_TARGETS}"
+
+        if [ "${RUST}" != "1.13.0" ]; then
+            TARGETS="${TARGETS} ${RUST_GT_1_13_LINUX_TARGETS}"
+            if [ "${RUST}" != "1.19.0" ]; then
+                TARGETS="${TARGETS} ${RUST_GT_1_19_LINUX_TARGETS}"
+                if [ "${RUST}" != "1.24.0" ]; then
+                    TARGETS="${TARGETS} ${RUST_GT_1_24_LINUX_TARGETS}"
+                fi
+            fi
+        fi
+
+        if [ "${RUST}" = "nightly" ]; then
+            TARGETS="${TARGETS} ${RUST_NIGHTLY_LINUX_TARGETS}"
+        fi
+
+        ;;
+    osx*)
+        TARGETS="${RUST_OSX_TARGETS}"
+        ;;
+    *)
+        ;;
+esac
+
+for TARGET in $TARGETS; do
+    test_target "$TARGET"
+done
diff --git a/ci/run.sh b/ci/run.sh
index 1fb5e127a254e1da968c38557f10a3a084234e5f..427d3bf53a8995ab1b105b26ca44d0c1e6a457d4 100755
--- a/ci/run.sh
+++ b/ci/run.sh
@@ -87,17 +87,10 @@ if [ "$TARGET" = "x86_64-unknown-linux-gnux32" ]; then
   opt="--release"
 fi
 
-# Building with --no-default-features is currently broken on rumprun because we
-# need cfg(target_vendor), which is currently unstable.
-if [ "$TARGET" != "x86_64-rumprun-netbsd" ]; then
-  cargo test $opt --no-default-features --manifest-path libc-test/Cargo.toml --target "${TARGET}"
-fi
-# Test the #[repr(align(x))] feature if this is building on Rust >= 1.25
-if [ "$(rustc --version | sed -E 's/^rustc 1\.([0-9]*)\..*/\1/')" -ge 25 ]; then
-  cargo test $opt --features align --manifest-path libc-test/Cargo.toml --target "${TARGET}"
-fi
-# Test the `extra_traits` feature if this is building on Rust >= 1.25
-if [ "$(rustc --version | sed -E 's/^rustc 1\.([0-9]*)\..*/\1/')" -ge 25 ]; then
-  cargo test $opt --features extra_traits --manifest-path libc-test/Cargo.toml --target "${TARGET}"
-fi
-exec cargo test $opt --manifest-path libc-test/Cargo.toml --target "${TARGET}"
+cargo test $opt --no-default-features --manifest-path libc-test/Cargo.toml \
+      --target "${TARGET}"
+
+cargo test $opt --manifest-path libc-test/Cargo.toml --target "${TARGET}"
+
+cargo test $opt --features extra_traits --manifest-path libc-test/Cargo.toml \
+      --target "${TARGET}"