Make better use of toolchains in the build.

This allows building for different platforms without having to retarget
the build. The configuration is also better checked by the assertions in
the toolchain templates.

A future change will redirect the root build rule to allow BSPs to
fully control their own build and configuration.

Change-Id: Iaae725d3bd000bc0ce7b9ef0f8f083350a73bd16
diff --git a/build/toolchain/BUILD.gn b/build/toolchain/BUILD.gn
new file mode 100644
index 0000000..344d30e
--- /dev/null
+++ b/build/toolchain/BUILD.gn
@@ -0,0 +1,53 @@
+# Copyright 2018 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.
+
+import("//build/toolchain/embedded.gni")
+import("//build/toolchain/host.gni")
+
+host_toolchain("host") {
+  use_fake_arch = false
+}
+
+host_toolchain("host_fake") {
+  use_fake_arch = true
+  max_cpus = 4
+  max_vms = 6
+}
+
+aarch64_toolchain("qemu_aarch64") {
+  cpu = "cortex-a57+nofp"
+  origin_address = "0x40001000"
+  use_pl011 = true
+  pl011_base_address = "0x09000000"
+  max_cpus = 8
+  max_vms = 16
+}
+
+aarch64_toolchain("hikey") {
+  cpu = "cortex-a53+nofp"
+  origin_address = "0x01000000"
+  use_pl011 = true
+  pl011_base_address = "0xf8015000"
+  max_cpus = 8
+  max_vms = 16
+}
+
+aarch64_toolchain("aem_v8a_fvp") {
+  cpu = "cortex-a57+nofp"
+  origin_address = "0x88000000"
+  use_pl011 = true
+  pl011_base_address = "0x1c090000"
+  max_cpus = 8
+  max_vms = 16
+}
diff --git a/build/toolchain/arch/BUILD.gn b/build/toolchain/arch/BUILD.gn
deleted file mode 100644
index 6ce6207..0000000
--- a/build/toolchain/arch/BUILD.gn
+++ /dev/null
@@ -1,131 +0,0 @@
-# Copyright 2018 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.
-
-# Target toolchain specific build arguments.
-declare_args() {
-  # Build with a specific compiler version e.g. when building with clang, set
-  # to "3.9" to build with `clang-3.9`.
-  arch_cc_version = ""
-}
-
-# Template for target toolchains; there is no support for C++ or libraries.
-# Instead, use source_set to group source together.
-template("cc_toolchain") {
-  toolchain(target_name) {
-    assert(defined(invoker.cc), "cc_toolchain() must specify a \"cc\" value")
-    assert(defined(invoker.ld), "cc_toolchain() must specify a \"ld\" value")
-
-    # Combine compiler version and compiler specific flags for this toolchain.
-    cc = "${invoker.cc}"
-    if (arch_cc_version != "") {
-      cc += "-${arch_cc_version}"
-    }
-    if (defined(invoker.cflags)) {
-      cc += " ${invoker.cflags}"
-    }
-
-    tool("cc") {
-      depfile = "{{output}}.d"
-      command = "${cc} -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}"
-      depsformat = "gcc"
-      description = "CC {{output}}"
-      outputs = [
-        "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o",
-      ]
-    }
-
-    tool("asm") {
-      depfile = "{{output}}.d"
-      command = "${cc} -MMD -MF $depfile {{defines}} {{include_dirs}} {{asmflags}} -c {{source}} -o {{output}}"
-      depsformat = "gcc"
-      description = "ASM {{output}}"
-      outputs = [
-        "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o",
-      ]
-    }
-
-    tool("link") {
-      outfile = "{{output_dir}}/{{target_output_name}}{{output_extension}}"
-      rspfile = "$outfile.rsp"
-      command = "${invoker.ld} {{ldflags}} -o $outfile --start-group @$rspfile --end-group"
-      description = "LINK $outfile"
-      default_output_dir = "{{root_out_dir}}"
-      rspfile_content = "{{inputs}}"
-      outputs = [
-        outfile,
-      ]
-    }
-
-    tool("stamp") {
-      command = "touch {{output}}"
-      description = "STAMP {{output}}"
-    }
-
-    tool("copy") {
-      command = "cp -af {{source}} {{output}}"
-      description = "COPY {{source}} {{output}}"
-    }
-
-    toolchain_args = {
-      forward_variables_from(invoker.toolchain_args, "*")
-    }
-  }
-}
-
-# Specialize for clang or gcc
-template("clang_toolchain") {
-  assert(defined(invoker.target),
-         "clang_toolchain() must specify a \"target\" value")
-  assert(defined(invoker.arch_tool_prefix),
-         "gcc_toolchain() must specify a \"arch_tool_prefix\" value")
-
-  cc_toolchain(target_name) {
-    cc = "clang"
-    cflags = "-target ${invoker.target} -fcolor-diagnostics"
-    ld = "ld.lld --color-diagnostics -O2 -lto-O2 --icf=all --fatal-warnings"
-
-    toolchain_args = {
-      arch_tool_prefix = invoker.arch_tool_prefix
-    }
-  }
-}
-
-template("gcc_toolchain") {
-  assert(defined(invoker.arch_tool_prefix),
-         "gcc_toolchain() must specify a \"arch_tool_prefix\" value")
-
-  cc_toolchain(target_name) {
-    cc = "${invoker.arch_tool_prefix}gcc"
-    cflags = "-fdiagnostics-color=always"
-    ld = "${invoker.arch_tool_prefix}ld"
-
-    toolchain_args = {
-      arch_tool_prefix = invoker.arch_tool_prefix
-    }
-  }
-}
-
-# Specialize for different architectures
-
-clang_toolchain("clang_aarch64") {
-  target = "aarch64-none-eabi"
-
-  # TODO: below isn't right for bare metal code, but it works fine
-  arch_tool_prefix = "aarch64-linux-gnu-"
-}
-
-gcc_toolchain("gcc_aarch64") {
-  # TODO: below isn't right for bare metal code, but it works fine
-  arch_tool_prefix = "aarch64-linux-gnu-"
-}
diff --git a/build/toolchain/embedded.gni b/build/toolchain/embedded.gni
new file mode 100644
index 0000000..b9a5cdd
--- /dev/null
+++ b/build/toolchain/embedded.gni
@@ -0,0 +1,248 @@
+# Copyright 2018 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.
+
+declare_args() {
+  # Set by arch toolchain. Prefix for binutils tools.
+  tool_prefix = ""
+}
+
+# Template for embedded toolchains; there is no support for C++ or libraries.
+# Instead, use source_set to group source together.
+template("embedded_cc_toolchain") {
+  toolchain(target_name) {
+    assert(defined(invoker.cc), "\"cc\" must be defined for ${target_name}.")
+    assert(defined(invoker.ld), "\"ld\" must be defined for ${target_name}.")
+
+    # Collect extra flags from the toolchain.
+    extra_defines = ""
+    extra_cflags = "-flto -ffunction-sections -fdata-sections"
+    extra_ldflags = "--gc-sections -pie"
+    if (defined(invoker.extra_defines)) {
+      extra_defines += " ${invoker.extra_defines}"
+    }
+    if (defined(invoker.extra_cflags)) {
+      extra_cflags += " ${invoker.extra_cflags}"
+    }
+    if (defined(invoker.extra_ldflags)) {
+      extra_ldflags += " ${invoker.extra_ldflags}"
+    }
+
+    # Define the tools.
+    tool("cc") {
+      depfile = "{{output}}.d"
+      command = "${invoker.cc} -MMD -MF $depfile ${extra_defines} {{defines}} {{include_dirs}} ${extra_cflags} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}"
+      depsformat = "gcc"
+      description = "CC {{output}}"
+      outputs = [
+        "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o",
+      ]
+    }
+
+    tool("asm") {
+      depfile = "{{output}}.d"
+      command = "${invoker.cc} -MMD -MF $depfile ${extra_defines} {{defines}} {{include_dirs}} {{asmflags}} -c {{source}} -o {{output}}"
+      depsformat = "gcc"
+      description = "ASM {{output}}"
+      outputs = [
+        "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o",
+      ]
+    }
+
+    tool("link") {
+      outfile = "{{output_dir}}/{{target_output_name}}{{output_extension}}"
+      rspfile = "$outfile.rsp"
+      command = "${invoker.ld} ${extra_ldflags} {{ldflags}} -o $outfile --start-group @$rspfile --end-group"
+      description = "LINK $outfile"
+      default_output_dir = "{{root_out_dir}}"
+      rspfile_content = "{{inputs}}"
+      outputs = [
+        outfile,
+      ]
+    }
+
+    tool("stamp") {
+      command = "touch {{output}}"
+      description = "STAMP {{output}}"
+    }
+
+    tool("copy") {
+      command = "cp -af {{source}} {{output}}"
+      description = "COPY {{source}} {{output}}"
+    }
+
+    toolchain_args = {
+      forward_variables_from(invoker.toolchain_args, "*")
+    }
+  }
+}
+
+# Specialize for clang.
+template("embedded_clang_toolchain") {
+  assert(defined(invoker.target),
+         "\"target\" must be defined for ${target_name}.")
+  assert(defined(invoker.tool_prefix),
+         "\"tool_prefix\" must be defined for ${target_name}.")
+
+  embedded_cc_toolchain(target_name) {
+    cc = "clang -target ${invoker.target} -fcolor-diagnostics"
+    ld = "ld.lld --color-diagnostics"
+
+    extra_defines = ""
+    extra_cflags = ""
+    extra_ldflags = "-O2 -lto-O2 --icf=all --fatal-warnings"
+    if (defined(invoker.extra_defines)) {
+      extra_defines += " ${invoker.extra_defines}"
+    }
+    if (defined(invoker.extra_cflags)) {
+      extra_cflags += " ${invoker.extra_cflags}"
+    }
+    if (defined(invoker.extra_ldflags)) {
+      extra_ldflags += " ${invoker.extra_ldflags}"
+    }
+
+    toolchain_args = {
+      tool_prefix = invoker.tool_prefix
+      if (defined(invoker.toolchain_args)) {
+        forward_variables_from(invoker.toolchain_args, "*")
+      }
+    }
+  }
+}
+
+# Specialize for gcc.
+template("embedded_gcc_toolchain") {
+  assert(defined(invoker.tool_prefix),
+         "\"tool_prefix\" must be defined for ${target_name}.")
+
+  embedded_cc_toolchain(target_name) {
+    cc = "${invoker.tool_prefix}gcc -fdiagnostics-color=always"
+    ld = "${invoker.tool_prefix}ld"
+
+    extra_defines = ""
+    extra_cflags = ""
+    extra_ldflags = ""
+    if (defined(invoker.extra_defines)) {
+      extra_defines += " ${invoker.extra_defines}"
+    }
+    if (defined(invoker.extra_cflags)) {
+      extra_cflags += " ${invoker.extra_cflags}"
+    }
+    if (defined(invoker.extra_ldflags)) {
+      extra_ldflags += " ${invoker.extra_ldflags}"
+    }
+
+    toolchain_args = {
+      tool_prefix = invoker.tool_prefix
+      if (defined(invoker.toolchain_args)) {
+        forward_variables_from(invoker.toolchain_args, "*")
+      }
+    }
+  }
+}
+
+# Expand to clang and gcc variants.
+template("embedded_platform_toolchain") {
+  assert(defined(invoker.arch), "\"arch\" must be defined for ${target_name}.")
+  assert(defined(invoker.target),
+         "\"target\" must be defined for ${target_name}.")
+  assert(defined(invoker.tool_prefix),
+         "\"tool_prefix\" must be defined for ${target_name}.")
+  assert(defined(invoker.origin_address),
+         "\"origin_address\" must be defined for ${target_name}.")
+  assert(defined(invoker.max_cpus),
+         "\"max_cpus\" must be defined for ${target_name}.")
+  assert(defined(invoker.max_vms),
+         "\"max_vms\" must be defined for ${target_name}.")
+
+  defines = ""
+  cflags = "-fno-stack-protector -fno-builtin -ffreestanding -fpic"
+  ldflags = "--defsym=ORIGIN_ADDRESS=${invoker.origin_address}"
+  if (defined(invoker.extra_defines)) {
+    defines += " ${invoker.extra_defines}"
+  }
+  if (defined(invoker.extra_cflags)) {
+    cflags += " ${invoker.extra_cflags}"
+  }
+  if (defined(invoker.extra_ldflags)) {
+    ldflags += " ${invoker.extra_ldflags}"
+  }
+
+  embedded_clang_toolchain("${target_name}_clang") {
+    target = invoker.target
+    tool_prefix = invoker.tool_prefix
+    extra_defines = defines
+    extra_cflags = cflags
+    extra_ldflags = ldflags
+    toolchain_args = {
+      platform_max_cpus = invoker.max_cpus
+      platform_max_vms = invoker.max_vms
+      arch = invoker.arch
+      if (defined(invoker.toolchain_args)) {
+        forward_variables_from(invoker.toolchain_args, "*")
+      }
+    }
+  }
+
+  embedded_gcc_toolchain("${target_name}_gcc") {
+    tool_prefix = invoker.tool_prefix
+    extra_defines = defines
+    extra_cflags = cflags
+    extra_ldflags = ldflags
+    toolchain_args = {
+      platform_max_cpus = invoker.max_cpus
+      platform_max_vms = invoker.max_vms
+      arch = invoker.arch
+      if (defined(invoker.toolchain_args)) {
+        forward_variables_from(invoker.toolchain_args, "*")
+      }
+    }
+  }
+}
+
+# Specialize for different architectures.
+
+template("aarch64_toolchain") {
+  assert(defined(invoker.cpu), "\"cpu\" must be defiend for ${target_name}.")
+  assert(defined(invoker.origin_address),
+         "\"origin_address\" must be defined for ${target_name}.")
+  assert(defined(invoker.use_pl011),
+         "\"use_pl011\" must be defined for ${target_name}.")
+  assert(defined(invoker.max_cpus),
+         "\"max_cpus\" must be defined for ${target_name}.")
+  assert(defined(invoker.max_vms),
+         "\"max_vms\" must be defined for ${target_name}.")
+
+  embedded_platform_toolchain(target_name) {
+    forward_variables_from(invoker,
+                           [
+                             "origin_address",
+                             "max_cpus",
+                             "max_vms",
+                           ])
+    arch = "aarch64"
+    target = "aarch64-none-eabi"
+    tool_prefix = "aarch64-linux-gnu-"  # TODO: this isn't right for bare metal but it works.
+    extra_cflags = "-mcpu=${invoker.cpu} -mstrict-align"
+
+    if (invoker.use_pl011) {
+      assert(defined(invoker.pl011_base_address),
+             "\"pl011_base_address\" must be defined for ${target_name}.")
+      extra_defines = "-DPL011_BASE=${invoker.pl011_base_address}"
+    }
+
+    toolchain_args = {
+      arch_aarch64_use_pl011 = invoker.use_pl011
+    }
+  }
+}
diff --git a/build/toolchain/host.gni b/build/toolchain/host.gni
new file mode 100644
index 0000000..e2f8913
--- /dev/null
+++ b/build/toolchain/host.gni
@@ -0,0 +1,176 @@
+# Copyright 2018 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.
+
+# Template for host toolchains.
+template("host_cc_toolchain") {
+  toolchain(target_name) {
+    assert(defined(invoker.ar), "\"ar\" must be defined for ${target_name}.")
+    assert(defined(invoker.cc), "\"cc\" must be defined for ${target_name}.")
+    assert(defined(invoker.cxx), "\"cxx\" must be defined for ${target_name}.")
+
+    # Collect extra flags from the toolchain.
+    extra_defines = ""
+    extra_cflags = ""
+    extra_ldflags = ""
+    if (defined(invoker.extra_defines)) {
+      extra_defines += " ${invoker.extra_defines}"
+    }
+    if (defined(invoker.extra_cflags)) {
+      extra_cflags += " ${invoker.extra_cflags}"
+    }
+    if (defined(invoker.extra_ldflags)) {
+      extra_ldflags += " ${invoker.extra_ldflags}"
+    }
+
+    tool("cc") {
+      depfile = "{{output}}.d"
+      command = "${invoker.cc} -MMD -MF $depfile ${extra_defines} {{defines}} {{include_dirs}} ${extra_cflags} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}"
+      depsformat = "gcc"
+      description = "CC {{output}}"
+      outputs = [
+        "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o",
+      ]
+    }
+
+    tool("cxx") {
+      depfile = "{{output}}.d"
+      command = "${invoker.cxx} -MMD -MF $depfile ${extra_defines} {{defines}} {{include_dirs}} ${extra_cflags} {{cflags}} {{cflags_cc}} -c {{source}} -o {{output}}"
+      depsformat = "gcc"
+      description = "CXX {{output}}"
+      outputs = [
+        "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o",
+      ]
+    }
+
+    tool("alink") {
+      rspfile = "{{output}}.rsp"
+      command = "rm -f {{output}} && ${invoker.ar} rcs {{output}} @$rspfile"
+      description = "AR {{target_output_name}}{{output_extension}}"
+      rspfile_content = "{{inputs}}"
+      outputs = [
+        "{{target_out_dir}}/{{target_output_name}}{{output_extension}}",
+      ]
+      default_output_extension = ".a"
+      output_prefix = "lib"
+    }
+
+    tool("solink") {
+      soname = "{{target_output_name}}{{output_extension}}"  # e.g. "libfoo.so".
+      sofile = "{{output_dir}}/$soname"
+      rspfile = soname + ".rsp"
+
+      command = "${invoker.cxx} -shared ${extra_ldflags} {{ldflags}} -o $sofile -Wl,-soname=$soname @$rspfile"
+      rspfile_content = "-Wl,--whole-archive {{inputs}} {{solibs}} -Wl,--no-whole-archive {{libs}}"
+
+      description = "SOLINK $soname"
+
+      # Use this for {{output_extension}} expansions unless a target manually
+      # overrides it (in which case {{output_extension}} will be what the target
+      # specifies).
+      default_output_extension = ".so"
+
+      # Use this for {{output_dir}} expansions unless a target manually overrides
+      # it (in which case {{output_dir}} will be what the target specifies).
+      default_output_dir = "{{root_out_dir}}"
+
+      outputs = [
+        sofile,
+      ]
+      link_output = sofile
+      depend_output = sofile
+      output_prefix = "lib"
+    }
+
+    tool("link") {
+      outfile = "{{output_dir}}/{{target_output_name}}{{output_extension}}"
+      rspfile = "$outfile.rsp"
+      command = "${invoker.cxx} ${extra_ldflags} {{ldflags}} -o $outfile -Wl,--start-group @$rspfile {{solibs}} -Wl,--end-group {{libs}}"
+      description = "LINK $outfile"
+      default_output_dir = "{{root_out_dir}}"
+      rspfile_content = "{{inputs}}"
+      outputs = [
+        outfile,
+      ]
+    }
+
+    tool("stamp") {
+      command = "touch {{output}}"
+      description = "STAMP {{output}}"
+    }
+
+    tool("copy") {
+      command = "cp -af {{source}} {{output}}"
+      description = "COPY {{source}} {{output}}"
+    }
+
+    if (defined(invoker.toolchain_args)) {
+      toolchain_args = {
+        forward_variables_from(invoker.toolchain_args, "*")
+      }
+    }
+  }
+}
+
+template("host_toolchain") {
+  assert(defined(invoker.use_fake_arch),
+         "\"use_fake_arch\" must be defined for ${target_name}.")
+  if (invoker.use_fake_arch) {
+    assert(defined(invoker.max_cpus),
+           "\"max_cpus\" must be defined for ${target_name}.")
+    assert(defined(invoker.max_vms),
+           "\"max_vms\" must be defined for ${target_name}.")
+  }
+
+  # Specialize for clang.
+  host_cc_toolchain("${target_name}_clang") {
+    ar = "llvm-ar"
+    cc = "clang -fcolor-diagnostics"
+    cxx = "clang++"
+
+    # TODO: remove the need for this
+    extra_defines = "-DPL011_BASE=0"
+
+    if (invoker.use_fake_arch) {
+      toolchain_args = {
+        platform_max_cpus = invoker.max_cpus
+        platform_max_vms = invoker.max_vms
+
+        # When building for the ${target_name}, use the fake architecture to make things
+        # testable.
+        arch = "fake"
+      }
+    }
+  }
+
+  # Specialize for gcc.
+  host_cc_toolchain("${target_name}_gcc") {
+    ar = "ar"
+    cc = "gcc -fdiagnostics-color=always"
+    cxx = "g++ -fdiagnostics-color=always"
+
+    # TODO: remove the need for this
+    extra_defines = "-DPL011_BASE=0"
+
+    if (invoker.use_fake_arch) {
+      toolchain_args = {
+        platform_max_cpus = invoker.max_cpus
+        platform_max_vms = invoker.max_vms
+
+        # When building for the ${target_name}, use the fake architecture to make things
+        # testable.
+        arch = "fake"
+      }
+    }
+  }
+}
diff --git a/build/toolchain/host/BUILD.gn b/build/toolchain/host/BUILD.gn
deleted file mode 100644
index dd344b7..0000000
--- a/build/toolchain/host/BUILD.gn
+++ /dev/null
@@ -1,169 +0,0 @@
-# Copyright 2018 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.
-
-# Host toolchain specific build arguments.
-declare_args() {
-  # Build with a specific compiler version e.g. when building with clang, set
-  # to "3.9" to build with `clang-3.9`.
-  host_cc_version = ""
-}
-
-# Template for host toolchains.
-template("cc_toolchain") {
-  toolchain(target_name) {
-    assert(defined(invoker.ar), "cc_toolchain() must specify a \"ar\" value")
-    assert(defined(invoker.cc), "cc_toolchain() must specify a \"cc\" value")
-    assert(defined(invoker.cxx), "cc_toolchain() must specify a \"cxx\" value")
-
-    cc = "${invoker.cc}"
-    cxx = "${invoker.cxx}"
-    if (host_cc_version != "") {
-      cc += "-${host_cc_version}"
-      cxx += "-${host_cc_version}"
-    }
-    if (defined(invoker.cflags)) {
-      cc += " ${invoker.cflags}"
-      cxx += " ${invoker.cflags}"
-    }
-
-    tool("cc") {
-      depfile = "{{output}}.d"
-      command = "${cc} -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}"
-      depsformat = "gcc"
-      description = "CC {{output}}"
-      outputs = [
-        "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o",
-      ]
-    }
-
-    tool("cxx") {
-      depfile = "{{output}}.d"
-      command = "${cxx} -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} -c {{source}} -o {{output}}"
-      depsformat = "gcc"
-      description = "CXX {{output}}"
-      outputs = [
-        "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o",
-      ]
-    }
-
-    tool("alink") {
-      rspfile = "{{output}}.rsp"
-      command = "rm -f {{output}} && ${invoker.ar} rcs {{output}} @$rspfile"
-      description = "AR {{target_output_name}}{{output_extension}}"
-      rspfile_content = "{{inputs}}"
-      outputs = [
-        "{{target_out_dir}}/{{target_output_name}}{{output_extension}}",
-      ]
-      default_output_extension = ".a"
-      output_prefix = "lib"
-    }
-
-    tool("solink") {
-      soname = "{{target_output_name}}{{output_extension}}"  # e.g. "libfoo.so".
-      sofile = "{{output_dir}}/$soname"
-      rspfile = soname + ".rsp"
-
-      command =
-          "${cxx} -shared {{ldflags}} -o $sofile -Wl,-soname=$soname @$rspfile"
-      rspfile_content = "-Wl,--whole-archive {{inputs}} {{solibs}} -Wl,--no-whole-archive {{libs}}"
-
-      description = "SOLINK $soname"
-
-      # Use this for {{output_extension}} expansions unless a target manually
-      # overrides it (in which case {{output_extension}} will be what the target
-      # specifies).
-      default_output_extension = ".so"
-
-      # Use this for {{output_dir}} expansions unless a target manually overrides
-      # it (in which case {{output_dir}} will be what the target specifies).
-      default_output_dir = "{{root_out_dir}}"
-
-      outputs = [
-        sofile,
-      ]
-      link_output = sofile
-      depend_output = sofile
-      output_prefix = "lib"
-    }
-
-    tool("link") {
-      outfile = "{{output_dir}}/{{target_output_name}}{{output_extension}}"
-      rspfile = "$outfile.rsp"
-      command = "${cxx} {{ldflags}} -o $outfile -Wl,--start-group @$rspfile {{solibs}} -Wl,--end-group {{libs}}"
-      description = "LINK $outfile"
-      default_output_dir = "{{root_out_dir}}"
-      rspfile_content = "{{inputs}}"
-      outputs = [
-        outfile,
-      ]
-    }
-
-    tool("stamp") {
-      command = "touch {{output}}"
-      description = "STAMP {{output}}"
-    }
-
-    tool("copy") {
-      command = "cp -af {{source}} {{output}}"
-      description = "COPY {{source}} {{output}}"
-    }
-
-    if (defined(invoker.toolchain_args)) {
-      toolchain_args = {
-        forward_variables_from(invoker.toolchain_args, "*")
-      }
-    }
-  }
-}
-
-# Specialize for clang or gcc
-cc_toolchain("clang") {
-  ar = "llvm-ar"
-  cc = "clang"
-  cxx = "clang++"
-  cflags = "-fcolor-diagnostics"
-}
-
-cc_toolchain("clang_fake_arch") {
-  ar = "llvm-ar"
-  cc = "clang"
-  cxx = "clang++"
-  cflags = "-fcolor-diagnostics"
-
-  toolchain_args = {
-    # When building for the host, use the fake architecture to make things
-    # testable.
-    arch = "fake"
-  }
-}
-
-cc_toolchain("gcc") {
-  ar = "ar"
-  cc = "gcc"
-  cxx = "g++"
-  cflags = "-fdiagnostics-color=always"
-}
-
-cc_toolchain("gcc_fake_arch") {
-  ar = "ar"
-  cc = "gcc"
-  cxx = "g++"
-  cflags = "-fdiagnostics-color=always"
-
-  toolchain_args = {
-    # When building for the host, use the fake architecture to make things
-    # testable.
-    arch = "fake"
-  }
-}
diff --git a/build/toolchain/platform.gni b/build/toolchain/platform.gni
new file mode 100644
index 0000000..7a1c8a9
--- /dev/null
+++ b/build/toolchain/platform.gni
@@ -0,0 +1,22 @@
+# Copyright 2018 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.
+
+# Configuration of the build for the platform.
+declare_args() {
+  # The maximum number of CPUs available on the platform.
+  platform_max_cpus = 0
+
+  # The maximum number of VMs required for the platform.
+  platform_max_vms = 0
+}