Switch to a new cortex-m4 compiler

This one is newer, so it supports a newer C++ standard. It's also
hermetic.

Also add a variant for building for some Kinetis-K chips with less RAM
that are used on fet12v2.

Change-Id: I9e50b6aae498e0c35acfedb846b3ada619a0e630
diff --git a/WORKSPACE b/WORKSPACE
index 6d3458f..725df52 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -240,3 +240,13 @@
     sha256 = "4b26fe45010817dc136488ee1604ade21bd7c264c29f17d864fc6eba9d7442c4",
     url = "http://frc971.org/Build-Dependencies/arm_frc_gnueabi_deps.tar.gz",
 )
+
+# Downloaded from
+# https://developer.arm.com/-/media/Files/downloads/gnu-rm/7-2018q2/gcc-arm-none-eabi-7-2018-q2-update-linux.tar.bz2?revision=bc2c96c0-14b5-4bb4-9f18-bceb4050fee7?product=GNU%20Arm%20Embedded%20Toolchain,64-bit,,Linux,7-2018-q2-update
+new_http_archive(
+    name = "gcc_arm_none_eabi",
+    build_file = "compilers/gcc_arm_none_eabi.BUILD",
+    sha256 = "bb17109f0ee697254a5d4ae6e5e01440e3ea8f0277f2e8169bf95d07c7d5fe69",
+    strip_prefix = "gcc-arm-none-eabi-7-2018-q2-update/",
+    url = "http://frc971.org/Build-Dependencies/gcc-arm-none-eabi-7-2018-q2-update-linux.tar.bz2",
+)
diff --git a/compilers/gcc_arm_none_eabi.BUILD b/compilers/gcc_arm_none_eabi.BUILD
new file mode 100644
index 0000000..db2cc77
--- /dev/null
+++ b/compilers/gcc_arm_none_eabi.BUILD
@@ -0,0 +1,80 @@
+package(default_visibility = ["//visibility:public"])
+
+filegroup(
+    name = "gcc",
+    srcs = [
+        "bin/arm-none-eabi-gcc",
+    ],
+)
+
+filegroup(
+    name = "ar",
+    srcs = [
+        "bin/arm-none-eabi-ar",
+    ],
+)
+
+filegroup(
+    name = "ld",
+    srcs = [
+        "bin/arm-none-eabi-ld",
+    ],
+)
+
+filegroup(
+    name = "nm",
+    srcs = [
+        "bin/arm-none-eabi-nm",
+    ],
+)
+
+filegroup(
+    name = "objcopy",
+    srcs = [
+        "bin/arm-none-eabi-objcopy",
+    ],
+)
+
+filegroup(
+    name = "objdump",
+    srcs = [
+        "bin/arm-none-eabi-objdump",
+    ],
+)
+
+filegroup(
+    name = "strip",
+    srcs = [
+        "bin/arm-none-eabi-strip",
+    ],
+)
+
+filegroup(
+    name = "as",
+    srcs = [
+        "bin/arm-none-eabi-as",
+    ],
+)
+
+filegroup(
+    name = "compiler_pieces",
+    srcs = glob([
+        "arm-none-eabi/**",
+        "lib/gcc/arm-none-eabi/**",
+        "include/**",
+    ]),
+)
+
+filegroup(
+    name = "compiler_components",
+    srcs = [
+        ":ar",
+        ":as",
+        ":gcc",
+        ":ld",
+        ":nm",
+        ":objcopy",
+        ":objdump",
+        ":strip",
+    ],
+)
diff --git a/motors/core/BUILD b/motors/core/BUILD
index d0385fb..f42a1bc 100644
--- a/motors/core/BUILD
+++ b/motors/core/BUILD
@@ -1,23 +1,26 @@
 load("//tools:environments.bzl", "mcu_cpus")
 
 filegroup(
-  name = 'linkerscript',
-  visibility = ['//tools/cpp:__pkg__'],
-  srcs = [ 'mk64fx512.ld' ],
+    name = "linkerscripts",
+    srcs = [
+        "kinetis_128k.ld",
+        "kinetis_192k.ld",
+    ],
+    visibility = ["//tools/cpp:__pkg__"],
 )
 
 cc_library(
-  name = 'core',
-  visibility = ['//visibility:public'],
-  hdrs = [
-    'kinetis.h',
-    'nonstd.h',
-    'time.h',
-  ],
-  srcs = [
-    'mk20dx128.c',
-    'nonstd.c',
-    'time.cc',
-  ],
-  restricted_to = mcu_cpus,
+    name = "core",
+    srcs = [
+        "mk20dx128.c",
+        "nonstd.c",
+        "time.cc",
+    ],
+    hdrs = [
+        "kinetis.h",
+        "nonstd.h",
+        "time.h",
+    ],
+    restricted_to = mcu_cpus,
+    visibility = ["//visibility:public"],
 )
diff --git a/motors/core/mk64fx512.ld b/motors/core/kinetis_128k.ld
similarity index 94%
copy from motors/core/mk64fx512.ld
copy to motors/core/kinetis_128k.ld
index 05dd9f2..bde65b5 100644
--- a/motors/core/mk64fx512.ld
+++ b/motors/core/kinetis_128k.ld
@@ -28,10 +28,12 @@
  * SOFTWARE.
  */
 
+/* TODO(Brian): De-duplicate with the version for 192K SRAM. */
+/* TODO(Brian): Split out SRAM_L and SRAM_U intelligently. */
 MEMORY
 {
   FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 512K
-  RAM  (rwx) : ORIGIN = 0x1FFF0000, LENGTH = 192K
+  RAM  (rwx) : ORIGIN = 0x1FFF0000, LENGTH = 128K
 }
 
 ENTRY(_VectorsFlash);
diff --git a/motors/core/mk64fx512.ld b/motors/core/kinetis_192k.ld
similarity index 95%
rename from motors/core/mk64fx512.ld
rename to motors/core/kinetis_192k.ld
index 05dd9f2..c266f3d 100644
--- a/motors/core/mk64fx512.ld
+++ b/motors/core/kinetis_192k.ld
@@ -28,6 +28,8 @@
  * SOFTWARE.
  */
 
+/* TODO(Brian): De-duplicate with the version for 128K SRAM. */
+/* TODO(Brian): Split out SRAM_L and SRAM_U intelligently. */
 MEMORY
 {
   FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 512K
diff --git a/motors/fet12/fet12.cc b/motors/fet12/fet12.cc
index 6fedeab..f008379 100644
--- a/motors/fet12/fet12.cc
+++ b/motors/fet12/fet12.cc
@@ -306,6 +306,8 @@
   delay(1000);
 #if 0
   ZeroMotor();
+#else
+  (void)ZeroMotor;
 #endif
 
   printf("Zeroed motor!\n");
diff --git a/motors/pistol_grip/controller.cc b/motors/pistol_grip/controller.cc
index 8b842b7..2bb3e01 100644
--- a/motors/pistol_grip/controller.cc
+++ b/motors/pistol_grip/controller.cc
@@ -359,20 +359,20 @@
               static_cast<int32_t>(static_cast<uint32_t>(data[0]) |
                                    (static_cast<uint32_t>(data[1]) << 8)) -
               32768) /
-          32768.0f * M_PI / 8.0;
+          static_cast<float>(32768.0 * M_PI / 8.0);
       trigger_goal_velocity =
           static_cast<float>(
               static_cast<int32_t>(static_cast<uint32_t>(data[2]) |
                                    (static_cast<uint32_t>(data[3]) << 8)) -
               32768) /
-          32768.0f * 4.0f;
+          static_cast<float>(32768.0 * 4.0);
 
       trigger_haptic_current =
           static_cast<float>(
               static_cast<int32_t>(static_cast<uint32_t>(data[4]) |
                                    (static_cast<uint32_t>(data[5]) << 8)) -
               32768) /
-          32768.0f * 2.0f;
+          static_cast<float>(32768.0 * 2.0);
       if (trigger_haptic_current > kHapticTriggerCurrentLimit) {
         trigger_haptic_current = kHapticTriggerCurrentLimit;
       } else if (trigger_haptic_current < -kHapticTriggerCurrentLimit) {
@@ -400,20 +400,20 @@
               static_cast<int32_t>(static_cast<uint32_t>(data[0]) |
                                    (static_cast<uint32_t>(data[1]) << 8)) -
               32768) /
-          32768.0f * M_PI;
+          static_cast<float>(32768.0 * M_PI);
       wheel_goal_velocity =
           static_cast<float>(
               static_cast<int32_t>(static_cast<uint32_t>(data[2]) |
                                    (static_cast<uint32_t>(data[3]) << 8)) -
               32768) /
-          32768.0f * 10.0f;
+          static_cast<float>(32768.0 * 10.0);
 
       wheel_haptic_current =
           static_cast<float>(
               static_cast<int32_t>(static_cast<uint32_t>(data[4]) |
                                    (static_cast<uint32_t>(data[5]) << 8)) -
               32768) /
-          32768.0f * 2.0f;
+          static_cast<float>(32768.0 * 2.0);
       if (wheel_haptic_current > kHapticWheelCurrentLimit) {
         wheel_haptic_current = kHapticWheelCurrentLimit;
       } else if (wheel_haptic_current < -kHapticWheelCurrentLimit) {
diff --git a/motors/pistol_grip/drivers_station.cc b/motors/pistol_grip/drivers_station.cc
index d78cfd4..e87d5e3 100644
--- a/motors/pistol_grip/drivers_station.cc
+++ b/motors/pistol_grip/drivers_station.cc
@@ -19,7 +19,8 @@
 
 ::std::atomic<teensy::AcmTty *> global_stdout{nullptr};
 
-void EchoChunks(teensy::AcmTty *tty1) {
+// TODO(Brian): Move this and the other two test functions somewhere else.
+__attribute__((unused)) void EchoChunks(teensy::AcmTty *tty1) {
   while (true) {
     char buffer[512];
     size_t buffered = 0;
@@ -42,7 +43,7 @@
   }
 }
 
-void EchoImmediately(teensy::AcmTty *tty1) {
+__attribute__((unused)) void EchoImmediately(teensy::AcmTty *tty1) {
   while (true) {
     if (false) {
       // Delay for a while.
@@ -60,7 +61,7 @@
   }
 }
 
-void WriteData(teensy::AcmTty *tty1) {
+__attribute__((unused)) void WriteData(teensy::AcmTty *tty1) {
   GPIOC_PTOR = 1 << 5;
   for (int i = 0; i < 100000000; ++i) {
     GPIOC_PSOR = 0;
diff --git a/motors/simple_receiver.cc b/motors/simple_receiver.cc
index f8b38f0..3b174b0 100644
--- a/motors/simple_receiver.cc
+++ b/motors/simple_receiver.cc
@@ -188,7 +188,8 @@
   can_send(id, data, sizeof(data), 2 + vesc_id);
 }
 
-void DoVescTest() {
+// TODO(Brian): Move these two test functions somewhere else.
+__attribute__((unused)) void DoVescTest() {
   uint32_t time = micros();
   while (true) {
     for (int i = 0; i < 6; ++i) {
@@ -212,7 +213,7 @@
   }
 }
 
-void DoReceiverTest2() {
+__attribute__((unused)) void DoReceiverTest2() {
   static constexpr float kMaxRpm = 10000.0f;
   while (true) {
     const bool flip = convert_input_width(2) > 0;
diff --git a/tools/BUILD b/tools/BUILD
index 3f3d4b2..3a75af3 100644
--- a/tools/BUILD
+++ b/tools/BUILD
@@ -29,6 +29,11 @@
 )
 
 config_setting(
+    name = "cpu_cortex_m4f_k22",
+    values = {"cpu": "cortex-m4f-k22"},
+)
+
+config_setting(
     name = "cpu_armhf",
     values = {"cpu": "armhf-debian"},
 )
@@ -56,6 +61,8 @@
 
 environment(name = "cortex-m4f")
 
+environment(name = "cortex-m4f-k22")
+
 environment_group(
     name = "cpus",
     defaults = [
@@ -67,5 +74,6 @@
         ":roborio",
         ":armhf-debian",
         ":cortex-m4f",
+        ":cortex-m4f-k22",
     ],
 )
diff --git a/tools/cpp/BUILD b/tools/cpp/BUILD
index 183d830..d541a8a 100644
--- a/tools/cpp/BUILD
+++ b/tools/cpp/BUILD
@@ -11,6 +11,7 @@
         "//tools:has_asan": [],
         "//tools:has_tsan": [],
         "//tools:cpu_cortex_m4f": [],
+        "//tools:cpu_cortex_m4f_k22": [],
         "//conditions:default": ["//third_party/gperftools:tcmalloc"],
     }),
 )
@@ -32,6 +33,7 @@
         "roborio|gcc": ":cc-compiler-roborio",
         "armhf-debian|clang": "cc-compiler-armhf-debian",
         "cortex-m4f|gcc": "cc-compiler-cortex-m4f",
+        "cortex-m4f-k22|gcc": "cc-compiler-cortex-m4f-k22",
     },
 )
 
@@ -214,18 +216,60 @@
     supports_param_files = 1,
 )
 
+filegroup(
+    name = "gcc_arm_none_eabi_none_files",
+    srcs = [
+        "//tools/cpp/gcc_arm_none_eabi:tool-wrappers",
+        "@gcc_arm_none_eabi//:compiler_pieces",
+    ],
+)
+
+filegroup(
+    name = "gcc_arm_none_eabi_compiler_files",
+    srcs = [
+        "//tools/cpp/gcc_arm_none_eabi:as",
+        "//tools/cpp/gcc_arm_none_eabi:gcc",
+        "//tools/cpp/gcc_arm_none_eabi:ld",
+    ],
+)
+
+filegroup(
+    name = "gcc_arm_none_eabi_linker_files",
+    srcs = [
+        "//motors/core:linkerscripts",
+        "//tools/cpp/gcc_arm_none_eabi:ar",
+        "//tools/cpp/gcc_arm_none_eabi:gcc",
+        "//tools/cpp/gcc_arm_none_eabi:ld",
+        "@gcc_arm_none_eabi//:compiler_pieces",
+    ],
+)
+
 cc_toolchain(
     name = "cc-compiler-cortex-m4f",
-    all_files = ":empty",
-    compiler_files = ":empty",
+    all_files = ":gcc_arm_none_eabi_none_files",
+    compiler_files = ":gcc_arm_none_eabi_compiler_files",
     cpu = "cortex-m4f",
     dwp_files = ":empty",
     dynamic_runtime_libs = [":empty"],
-    linker_files = "//motors/core:linkerscript",
+    linker_files = ":gcc_arm_none_eabi_linker_files",
+    objcopy_files = "//tools/cpp/gcc_arm_none_eabi:objcopy",
+    static_runtime_libs = [":empty"],
+    strip_files = "//tools/cpp/gcc_arm_none_eabi:strip",
+    supports_param_files = 1,
+)
+
+cc_toolchain(
+    name = "cc-compiler-cortex-m4f-k22",
+    all_files = ":gcc_arm_none_eabi_none_files",
+    compiler_files = ":gcc_arm_none_eabi_compiler_files",
+    cpu = "cortex-m4f-k22",
+    dwp_files = ":empty",
+    dynamic_runtime_libs = [":empty"],
+    linker_files = ":gcc_arm_none_eabi_linker_files",
     objcopy_files = ":empty",
     static_runtime_libs = [":empty"],
     strip_files = ":empty",
-    supports_param_files = 0,
+    supports_param_files = 1,
 )
 
 py_binary(
diff --git a/tools/cpp/CROSSTOOL b/tools/cpp/CROSSTOOL
index 9306652..0b1223e 100644
--- a/tools/cpp/CROSSTOOL
+++ b/tools/cpp/CROSSTOOL
@@ -23,6 +23,10 @@
   cpu: "cortex-m4f"
   toolchain_identifier: "cortex-m4f"
 }
+default_toolchain {
+  cpu: "cortex-m4f-k22"
+  toolchain_identifier: "cortex-m4f-k22"
+}
 toolchain {
   toolchain_identifier: "stub_armeabi-v7a"
   host_system_name: "armeabi-v7a"
@@ -817,47 +821,47 @@
   abi_libc_version: "cortex-m4f"
   tool_path {
     name: "ar"
-    path: "/usr/bin/arm-none-eabi-ar"
+    path: "gcc_arm_none_eabi/arm-none-eabi-ar"
   }
   tool_path {
     name: "compat-ld"
-    path: "/usr/bin/arm-none-eabi-ld"
+    path: "gcc_arm_none_eabi/arm-none-eabi-ld"
   }
   tool_path {
     name: "cpp"
-    path: "/usr/bin/arm-none-eabi-cpp"
+    path: "gcc_arm_none_eabi/arm-none-eabi-cpp"
   }
   tool_path {
     name: "dwp"
-    path: "/usr/bin/arm-none-eabi-dwp"
+    path: "gcc_arm_none_eabi/arm-none-eabi-dwp"
   }
   tool_path {
     name: "gcc"
-    path: "/usr/bin/arm-none-eabi-gcc"
+    path: "gcc_arm_none_eabi/arm-none-eabi-gcc"
   }
   tool_path {
     name: "gcov"
-    path: "/usr/bin/arm-none-eabi-gcov"
+    path: "gcc_arm_none_eabi/arm-none-eabi-gcov"
   }
   tool_path {
     name: "ld"
-    path: "/usr/bin/arm-none-eabi-ld"
+    path: "gcc_arm_none_eabi/arm-none-eabi-ld"
   }
   tool_path {
     name: "nm"
-    path: "/usr/bin/arm-none-eabi-nm"
+    path: "gcc_arm_none_eabi/arm-none-eabi-nm"
   }
   tool_path {
     name: "objcopy"
-    path: "/usr/bin/arm-none-eabi-objcopy"
+    path: "gcc_arm_none_eabi/arm-none-eabi-objcopy"
   }
   tool_path {
     name: "objdump"
-    path: "/usr/bin/arm-none-eabi-objdump"
+    path: "gcc_arm_none_eabi/arm-none-eabi-objdump"
   }
   tool_path {
     name: "strip"
-    path: "/usr/bin/arm-none-eabi-strip"
+    path: "gcc_arm_none_eabi/arm-none-eabi-strip"
   }
   supports_gold_linker: false
   supports_thin_archives: false
@@ -887,6 +891,8 @@
   compiler_flag: "-Wformat=2"
   compiler_flag: "-Werror"
   compiler_flag: "-Wstrict-aliasing=2"
+  compiler_flag: "-Wno-misleading-indentation"
+  compiler_flag: "-Wno-int-in-bool-context"
   compiler_flag: "-Wdouble-promotion"
   compiler_flag: "-pipe"
   compiler_flag: "-g"
@@ -901,10 +907,10 @@
   linker_flag: "-fno-strict-aliasing"
   linker_flag: "--specs=nano.specs"
   linker_flag: "-lgcc"
-  linker_flag: "-lstdc++"
+  linker_flag: "-lstdc++_nano"
   linker_flag: "-lm"
-  linker_flag: "-lc"
-  linker_flag: "-Tmotors/core/mk64fx512.ld"
+  linker_flag: "-lc_nano"
+  linker_flag: "-Tmotors/core/kinetis_192k.ld"
   objcopy_embed_flag: "-I"
   objcopy_embed_flag: "binary"
   compilation_mode_flags {
@@ -974,7 +980,209 @@
       action: "c++-header-preprocessing"
       action: "c++-module-compile"
       flag_group {
-        flag: "--std=gnu++11"
+        flag: "--std=gnu++1y"
+        flag: "-fno-exceptions"
+        flag: "-fno-rtti"
+      }
+    }
+  }
+  feature {
+    name: "include_paths"
+    flag_set {
+      action: "preprocess-assemble"
+      action: "c-compile"
+      action: "c++-compile"
+      action: "c++-header-parsing"
+      action: "c++-header-preprocessing"
+      action: "c++-module-compile"
+      flag_group {
+        flag: "-iquote"
+        flag: "%{quote_include_paths}"
+        iterate_over: "quote_include_paths"
+      }
+      flag_group {
+        flag: "-I%{include_paths}"
+        iterate_over: "include_paths"
+      }
+      flag_group {
+        flag: "-I"
+        flag: "%{system_include_paths}"
+        iterate_over: "system_include_paths"
+      }
+    }
+  }
+}
+toolchain {
+  toolchain_identifier: "cortex-m4f-k22"
+  host_system_name: "local"
+  target_system_name: "cortex-m4f-k22"
+  target_cpu: "cortex-m4f-k22"
+  target_libc: "cortex-m4f-k22"
+  compiler: "gcc"
+  abi_version: "cortex-m4f-k22"
+  abi_libc_version: "cortex-m4f-k22"
+  tool_path {
+    name: "ar"
+    path: "gcc_arm_none_eabi/arm-none-eabi-ar"
+  }
+  tool_path {
+    name: "compat-ld"
+    path: "gcc_arm_none_eabi/arm-none-eabi-ld"
+  }
+  tool_path {
+    name: "cpp"
+    path: "gcc_arm_none_eabi/arm-none-eabi-cpp"
+  }
+  tool_path {
+    name: "dwp"
+    path: "gcc_arm_none_eabi/arm-none-eabi-dwp"
+  }
+  tool_path {
+    name: "gcc"
+    path: "gcc_arm_none_eabi/arm-none-eabi-gcc"
+  }
+  tool_path {
+    name: "gcov"
+    path: "gcc_arm_none_eabi/arm-none-eabi-gcov"
+  }
+  tool_path {
+    name: "ld"
+    path: "gcc_arm_none_eabi/arm-none-eabi-ld"
+  }
+  tool_path {
+    name: "nm"
+    path: "gcc_arm_none_eabi/arm-none-eabi-nm"
+  }
+  tool_path {
+    name: "objcopy"
+    path: "gcc_arm_none_eabi/arm-none-eabi-objcopy"
+  }
+  tool_path {
+    name: "objdump"
+    path: "gcc_arm_none_eabi/arm-none-eabi-objdump"
+  }
+  tool_path {
+    name: "strip"
+    path: "gcc_arm_none_eabi/arm-none-eabi-strip"
+  }
+  supports_gold_linker: false
+  supports_thin_archives: false
+  needsPic: false
+  compiler_flag: "-D__STDC_FORMAT_MACROS"
+  compiler_flag: "-D__STDC_CONSTANT_MACROS"
+  compiler_flag: "-D__STDC_LIMIT_MACROS"
+  compiler_flag: "-D__MK22FX512__"
+  compiler_flag: "-DF_CPU=120000000"
+  compiler_flag: "-Wl,--gc-sections"
+  compiler_flag: "-D__have_long32"
+  compiler_flag: "-fstack-protector"
+  compiler_flag: "-mcpu=cortex-m4"
+  compiler_flag: "-mfpu=fpv4-sp-d16"
+  compiler_flag: "-mthumb"
+  compiler_flag: "-mfloat-abi=hard"
+  compiler_flag: "-fno-strict-aliasing"
+  compiler_flag: "-fmessage-length=80"
+  compiler_flag: "-fmax-errors=20"
+  compiler_flag: "-Wall"
+  compiler_flag: "-Wextra"
+  compiler_flag: "-Wpointer-arith"
+  compiler_flag: "-Wcast-qual"
+  compiler_flag: "-Wwrite-strings"
+  compiler_flag: "-Wtype-limits"
+  compiler_flag: "-Wsign-compare"
+  compiler_flag: "-Wformat=2"
+  compiler_flag: "-Werror"
+  compiler_flag: "-Wstrict-aliasing=2"
+  compiler_flag: "-Wno-misleading-indentation"
+  compiler_flag: "-Wno-int-in-bool-context"
+  compiler_flag: "-Wdouble-promotion"
+  compiler_flag: "-pipe"
+  compiler_flag: "-g"
+  compiler_flag: "-fno-common"
+  compiler_flag: "-ffreestanding"
+  compiler_flag: "-fbuiltin"
+  linker_flag: "-no-canonical-prefixes"
+  linker_flag: "-mcpu=cortex-m4"
+  linker_flag: "-mfpu=fpv4-sp-d16"
+  linker_flag: "-mthumb"
+  linker_flag: "-mfloat-abi=hard"
+  linker_flag: "-fno-strict-aliasing"
+  linker_flag: "--specs=nano.specs"
+  linker_flag: "-lgcc"
+  linker_flag: "-lstdc++_nano"
+  linker_flag: "-lm"
+  linker_flag: "-lc_nano"
+  linker_flag: "-Tmotors/core/kinetis_128k.ld"
+  objcopy_embed_flag: "-I"
+  objcopy_embed_flag: "binary"
+  compilation_mode_flags {
+    mode: OPT
+    compiler_flag: "-O2"
+    compiler_flag: "-finline-functions"
+    compiler_flag: "-ffast-math"
+    compiler_flag: "-funroll-loops"
+    compiler_flag: "-DNDEBUG"
+    compiler_flag: "-ffunction-sections"
+    linker_flag: "-Wl,--gc-sections"
+  }
+  linking_mode_flags {
+    mode: FULLY_STATIC
+  }
+  cxx_builtin_include_directory: "/usr/lib/gcc/arm-none-eabi/4.8/include"
+  cxx_builtin_include_directory: "/usr/lib/gcc/arm-none-eabi/4.8/include-fixed"
+  cxx_builtin_include_directory: "/usr/lib/arm-none-eabi/include"
+  cxx_builtin_include_directory: "/usr/include/newlib"
+  builtin_sysroot: ""
+  unfiltered_cxx_flag: "-no-canonical-prefixes"
+  unfiltered_cxx_flag: "-Wno-builtin-macro-redefined"
+  unfiltered_cxx_flag: "-D__DATE__=\"redacted\""
+  unfiltered_cxx_flag: "-D__TIMESTAMP__=\"redacted\""
+  unfiltered_cxx_flag: "-D__TIME__=\"redacted\""
+  supports_normalizing_ar: false
+  supports_start_end_lib: false
+  supports_interface_shared_objects: false
+  supports_incremental_linker: false
+  supports_fission: false
+  feature {
+    name: "dbg"
+    flag_set {
+      action: "preprocess-assemble"
+      action: "c-compile"
+      action: "c++-compile"
+      action: "c++-header-parsing"
+      action: "c++-header-preprocessing"
+      action: "c++-module-compile"
+      flag_group {
+        flag: "-fno-omit-frame-pointer"
+      }
+    }
+    implies: "all_modes"
+  }
+  feature {
+    name: "opt"
+    implies: "all_modes"
+  }
+  feature {
+    name: "fastbuild"
+    implies: "all_modes"
+  }
+  feature {
+    name: "all_modes"
+    flag_set {
+      action: "preprocess-assemble"
+      action: "assemble"
+      action: "c-compile"
+      flag_group {
+        flag: "--std=gnu99"
+      }
+    }
+    flag_set {
+      action: "c++-compile"
+      action: "c++-header-parsing"
+      action: "c++-header-preprocessing"
+      action: "c++-module-compile"
+      flag_group {
+        flag: "--std=gnu++1y"
         flag: "-fno-exceptions"
         flag: "-fno-rtti"
       }
diff --git a/tools/cpp/cortex_m4f_crosstool.pb b/tools/cpp/cortex_m4f_crosstool.pb
index ec02440..cd854fd 100644
--- a/tools/cpp/cortex_m4f_crosstool.pb
+++ b/tools/cpp/cortex_m4f_crosstool.pb
@@ -17,21 +17,21 @@
   target_system_name: "%NAME%"
   toolchain_identifier: "%NAME%"
 
-  tool_path { name: "ar" path: "/usr/bin/arm-none-eabi-ar" }
-  tool_path { name: "compat-ld" path: "/usr/bin/arm-none-eabi-ld" }
-  tool_path { name: "cpp" path: "/usr/bin/arm-none-eabi-cpp" }
-  tool_path { name: "dwp" path: "/usr/bin/arm-none-eabi-dwp" }
-  tool_path { name: "gcc" path: "/usr/bin/arm-none-eabi-gcc" }
-  tool_path { name: "gcov" path: "/usr/bin/arm-none-eabi-gcov" }
+  tool_path { name: "ar" path: "gcc_arm_none_eabi/arm-none-eabi-ar" }
+  tool_path { name: "compat-ld" path: "gcc_arm_none_eabi/arm-none-eabi-ld" }
+  tool_path { name: "cpp" path: "gcc_arm_none_eabi/arm-none-eabi-cpp" }
+  tool_path { name: "dwp" path: "gcc_arm_none_eabi/arm-none-eabi-dwp" }
+  tool_path { name: "gcc" path: "gcc_arm_none_eabi/arm-none-eabi-gcc" }
+  tool_path { name: "gcov" path: "gcc_arm_none_eabi/arm-none-eabi-gcov" }
   # C(++) compiles invoke the compiler (as that is the one knowing where
   # to find libraries), but we provide LD so other rules can invoke the linker.
-  tool_path { name: "ld" path: "/usr/bin/arm-none-eabi-ld" }
-  tool_path { name: "nm" path: "/usr/bin/arm-none-eabi-nm" }
-  tool_path { name: "objcopy" path: "/usr/bin/arm-none-eabi-objcopy" }
+  tool_path { name: "ld" path: "gcc_arm_none_eabi/arm-none-eabi-ld" }
+  tool_path { name: "nm" path: "gcc_arm_none_eabi/arm-none-eabi-nm" }
+  tool_path { name: "objcopy" path: "gcc_arm_none_eabi/arm-none-eabi-objcopy" }
   objcopy_embed_flag: "-I"
   objcopy_embed_flag: "binary"
-  tool_path { name: "objdump" path: "/usr/bin/arm-none-eabi-objdump" }
-  tool_path { name: "strip" path: "/usr/bin/arm-none-eabi-strip" }
+  tool_path { name: "objdump" path: "gcc_arm_none_eabi/arm-none-eabi-objdump" }
+  tool_path { name: "strip" path: "gcc_arm_none_eabi/arm-none-eabi-strip" }
   linking_mode_flags { mode: FULLY_STATIC }
 
   # TODO(bazel-team): In theory, the path here ought to exactly match the path
@@ -84,7 +84,7 @@
       action: "c++-header-preprocessing"
       action: "c++-module-compile"
       flag_group {
-        flag: "--std=gnu++11"
+        flag: "--std=gnu++1y"
         flag: "-fno-exceptions"
         flag: "-fno-rtti"
       }
@@ -137,10 +137,10 @@
 
   # Pretty much everything needs this, including parts of the glibc STL...
   linker_flag: "-lgcc"
-  linker_flag: "-lstdc++"
+  linker_flag: "-lstdc++_nano"
   linker_flag: "-lm"
-  linker_flag: "-lc"
-  linker_flag: "-Tmotors/core/mk64fx512.ld"
+  linker_flag: "-lc_nano"
+  linker_flag: "-T%LINKER_SCRIPT%"
 
   compiler_flag: "-fmessage-length=80"
   compiler_flag: "-fmax-errors=20"
@@ -156,6 +156,10 @@
   compiler_flag: "-Werror"
   compiler_flag: "-Wstrict-aliasing=2"
 
+  # TODO(Brian): Drop these once we upgrade Eigen.
+  compiler_flag: "-Wno-misleading-indentation"
+  compiler_flag: "-Wno-int-in-bool-context"
+
   # Be annoying about using doubles places we probably didn't mean to, because
   # the FPU only does single-precision.
   compiler_flag: "-Wdouble-promotion"
diff --git a/tools/cpp/gcc_arm_none_eabi/BUILD b/tools/cpp/gcc_arm_none_eabi/BUILD
new file mode 100644
index 0000000..485263f
--- /dev/null
+++ b/tools/cpp/gcc_arm_none_eabi/BUILD
@@ -0,0 +1,79 @@
+package(default_visibility = ["//tools/cpp:__pkg__"])
+
+filegroup(
+    name = "gcc",
+    srcs = [
+        "arm-none-eabi-gcc",
+        "@gcc_arm_none_eabi//:gcc",
+    ],
+)
+
+filegroup(
+    name = "ar",
+    srcs = [
+        "arm-none-eabi-ar",
+        "@gcc_arm_none_eabi//:ar",
+    ],
+)
+
+filegroup(
+    name = "ld",
+    srcs = [
+        "arm-none-eabi-ld",
+        "@gcc_arm_none_eabi//:ld",
+    ],
+)
+
+filegroup(
+    name = "nm",
+    srcs = [
+        "arm-none-eabi-nm",
+        "@gcc_arm_none_eabi//:nm",
+    ],
+)
+
+filegroup(
+    name = "objcopy",
+    srcs = [
+        "arm-none-eabi-objcopy",
+        "@gcc_arm_none_eabi//:objcopy",
+    ],
+)
+
+filegroup(
+    name = "objdump",
+    srcs = [
+        "arm-none-eabi-objdump",
+        "@gcc_arm_none_eabi//:objdump",
+    ],
+)
+
+filegroup(
+    name = "strip",
+    srcs = [
+        "arm-none-eabi-strip",
+        "@gcc_arm_none_eabi//:strip",
+    ],
+)
+
+filegroup(
+    name = "as",
+    srcs = [
+        "arm-none-eabi-as",
+        "@gcc_arm_none_eabi//:as",
+    ],
+)
+
+filegroup(
+    name = "tool-wrappers",
+    srcs = [
+        ":ar",
+        ":as",
+        ":gcc",
+        ":ld",
+        ":nm",
+        ":objcopy",
+        ":objdump",
+        ":strip",
+    ],
+)
diff --git a/tools/cpp/gcc_arm_none_eabi/arm-none-eabi-ar b/tools/cpp/gcc_arm_none_eabi/arm-none-eabi-ar
new file mode 100755
index 0000000..377d32e
--- /dev/null
+++ b/tools/cpp/gcc_arm_none_eabi/arm-none-eabi-ar
@@ -0,0 +1,5 @@
+#!/bin/bash --norc
+
+exec -a arm-none-eabi-ar \
+	${BAZEL_OUTPUT_ROOT}external/gcc_arm_none_eabi/bin/arm-none-eabi-ar \
+	"$@"
diff --git a/tools/cpp/gcc_arm_none_eabi/arm-none-eabi-as b/tools/cpp/gcc_arm_none_eabi/arm-none-eabi-as
new file mode 100755
index 0000000..09c589c
--- /dev/null
+++ b/tools/cpp/gcc_arm_none_eabi/arm-none-eabi-as
@@ -0,0 +1,5 @@
+#!/bin/bash --norc
+
+exec -a arm-none-eabi-as \
+	${BAZEL_OUTPUT_ROOT}external/gcc_arm_none_eabi/bin/arm-none-eabi-as \
+	"$@"
diff --git a/tools/cpp/gcc_arm_none_eabi/arm-none-eabi-cpp b/tools/cpp/gcc_arm_none_eabi/arm-none-eabi-cpp
new file mode 100755
index 0000000..a3ff222
--- /dev/null
+++ b/tools/cpp/gcc_arm_none_eabi/arm-none-eabi-cpp
@@ -0,0 +1,5 @@
+#!/bin/bash --norc
+
+exec -a arm-none-eabi-cpp \
+	${BAZEL_OUTPUT_ROOT}external/gcc_arm_none_eabi/bin/arm-none-eabi-cpp \
+	"$@"
diff --git a/tools/cpp/gcc_arm_none_eabi/arm-none-eabi-gcc b/tools/cpp/gcc_arm_none_eabi/arm-none-eabi-gcc
new file mode 100755
index 0000000..6ff0448
--- /dev/null
+++ b/tools/cpp/gcc_arm_none_eabi/arm-none-eabi-gcc
@@ -0,0 +1,6 @@
+#!/bin/bash --norc
+
+PATH="${BAZEL_OUTPUT_ROOT}external/gcc_arm_none_eabi/lib/gcc/arm-none-eabi/7.3.1:$PATH" \
+	exec \
+	${BAZEL_OUTPUT_ROOT}external/gcc_arm_none_eabi/bin/arm-none-eabi-gcc \
+	"$@"
diff --git a/tools/cpp/gcc_arm_none_eabi/arm-none-eabi-gcov b/tools/cpp/gcc_arm_none_eabi/arm-none-eabi-gcov
new file mode 100755
index 0000000..c6ae49e
--- /dev/null
+++ b/tools/cpp/gcc_arm_none_eabi/arm-none-eabi-gcov
@@ -0,0 +1,5 @@
+#!/bin/bash --norc
+
+exec -a arm-none-eabi-gcov \
+	${BAZEL_OUTPUT_ROOT}external/gcc_arm_none_eabi/bin/arm-none-eabi-gcov \
+	"$@"
diff --git a/tools/cpp/gcc_arm_none_eabi/arm-none-eabi-ld b/tools/cpp/gcc_arm_none_eabi/arm-none-eabi-ld
new file mode 100755
index 0000000..7115b82
--- /dev/null
+++ b/tools/cpp/gcc_arm_none_eabi/arm-none-eabi-ld
@@ -0,0 +1,5 @@
+#!/bin/bash --norc
+
+exec -a arm-none-eabi-ld \
+	${BAZEL_OUTPUT_ROOT}external/gcc_arm_none_eabi/bin/arm-none-eabi-ld \
+	"$@"
diff --git a/tools/cpp/gcc_arm_none_eabi/arm-none-eabi-nm b/tools/cpp/gcc_arm_none_eabi/arm-none-eabi-nm
new file mode 100755
index 0000000..7b1f4cd
--- /dev/null
+++ b/tools/cpp/gcc_arm_none_eabi/arm-none-eabi-nm
@@ -0,0 +1,5 @@
+#!/bin/bash --norc
+
+exec -a arm-none-eabi-nm \
+	${BAZEL_OUTPUT_ROOT}external/gcc_arm_none_eabi/bin/arm-none-eabi-nm \
+	"$@"
diff --git a/tools/cpp/gcc_arm_none_eabi/arm-none-eabi-objcopy b/tools/cpp/gcc_arm_none_eabi/arm-none-eabi-objcopy
new file mode 100755
index 0000000..6f27cc4
--- /dev/null
+++ b/tools/cpp/gcc_arm_none_eabi/arm-none-eabi-objcopy
@@ -0,0 +1,5 @@
+#!/bin/bash --norc
+
+exec -a arm-none-eabi-objcopy \
+	${BAZEL_OUTPUT_ROOT}external/gcc_arm_none_eabi/bin/arm-none-eabi-objcopy \
+	"$@"
diff --git a/tools/cpp/gcc_arm_none_eabi/arm-none-eabi-objdump b/tools/cpp/gcc_arm_none_eabi/arm-none-eabi-objdump
new file mode 100755
index 0000000..a677573
--- /dev/null
+++ b/tools/cpp/gcc_arm_none_eabi/arm-none-eabi-objdump
@@ -0,0 +1,5 @@
+#!/bin/bash --norc
+
+exec -a arm-none-eabi-objdump \
+	${BAZEL_OUTPUT_ROOT}external/gcc_arm_none_eabi/bin/arm-none-eabi-objdump \
+	"$@"
diff --git a/tools/cpp/gcc_arm_none_eabi/arm-none-eabi-strip b/tools/cpp/gcc_arm_none_eabi/arm-none-eabi-strip
new file mode 100755
index 0000000..f11bd20
--- /dev/null
+++ b/tools/cpp/gcc_arm_none_eabi/arm-none-eabi-strip
@@ -0,0 +1,5 @@
+#!/bin/bash --norc
+
+exec -a arm-none-eabi-strip \
+	${BAZEL_OUTPUT_ROOT}external/gcc_arm_none_eabi/bin/arm-none-eabi-strip \
+	"$@"
diff --git a/tools/cpp/gen_crosstool.py b/tools/cpp/gen_crosstool.py
index af28c56..547faf0 100644
--- a/tools/cpp/gen_crosstool.py
+++ b/tools/cpp/gen_crosstool.py
@@ -47,6 +47,13 @@
       '%NAME%': 'cortex-m4f',
       '%CPU%': '__MK64FX512__',
       '%F_CPU%': '120000000',
+      '%LINKER_SCRIPT%': 'motors/core/kinetis_192k.ld',
+      })
+  add_m4f_toolchain(crosstool_proto.toolchain.add(), m4f_proto, {
+      '%NAME%': 'cortex-m4f-k22',
+      '%CPU%': '__MK22FX512__',
+      '%F_CPU%': '120000000',
+      '%LINKER_SCRIPT%': 'motors/core/kinetis_128k.ld',
       })
 
   with open(args[2], 'w') as f:
diff --git a/tools/cpp/static_crosstool.pb b/tools/cpp/static_crosstool.pb
index 99a36f9..5cfe31c 100644
--- a/tools/cpp/static_crosstool.pb
+++ b/tools/cpp/static_crosstool.pb
@@ -27,6 +27,11 @@
   toolchain_identifier: "cortex-m4f"
 }
 
+default_toolchain {
+  cpu: "cortex-m4f-k22"
+  toolchain_identifier: "cortex-m4f-k22"
+}
+
 toolchain {
   abi_version: "armeabi-v7a"
   abi_libc_version: "armeabi-v7a"