diff --git a/BUILD.gn b/BUILD.gn
index 9838d640e4ff008a73377304ad1e7b1e755a4196..8b736cd6a9fc919dbae2cafb8d88045b2e920ec6 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -31,32 +31,6 @@ declare_args() {
   universe_package_labels = []
 }
 
-# Collect the source files that are dependencies of the create_gn_rules.py
-# script, below.  Unfortunately, exec_script cannot use a depfile produced
-# by the script and only supports a separately computed list of dependencies.
-zircon_files =
-    exec_script("//build/zircon/list_source_files.py", [], "list lines")
-
-supporting_templates = [
-  "//build/zircon/header.mako",
-  "//build/zircon/sysroot.mako",
-]
-
-# The following script generates GN build files for Zircon objects.  It is
-# placed before everything else so that //zircon targets are available in
-# due time.  See //build/zircon/README.md for more details.
-exec_script("//build/zircon/create_gn_rules.py",
-            [
-              "--out",
-              rebase_path("//zircon/public"),
-              "--zircon-build",
-              rebase_path(zircon_root_build_dir),
-              "--zircon-manifest",
-              rebase_path("$zircon_root_build_dir/export/manifest-$target_cpu"),
-            ],
-            "",
-            zircon_files + supporting_templates)
-
 # Write a file that can be sourced by `fx`.  This file is produced
 # by `gn gen` and is not known to Ninja at all, so it has nothing to
 # do with the build itself.  Its sole purpose is to leave bread
diff --git a/build/config/fuchsia/BUILD.gn b/build/config/fuchsia/BUILD.gn
index 94ee9e95dd135c01b7abf31e7570ac3ade784a08..4641bd5e9d29359c9a78342f9bb93a0d4a4778a3 100644
--- a/build/config/fuchsia/BUILD.gn
+++ b/build/config/fuchsia/BUILD.gn
@@ -83,14 +83,23 @@ config("compiler_sysroot") {
   # Rather than using --sysroot and populating a sysroot per se, use
   # specific compiler switches to find the C library and its headers from
   # the Zircon build and source tree directly.
-  import("$zircon_root_build_dir/legacy-sysroot-$current_cpu.gni")
+  sysroot_include_dirs = []
+  foreach(entry, zircon_legacy_sysroot) {
+    if (defined(entry.include_dirs)) {
+      sysroot_include_dirs += entry.include_dirs
+    } else if (defined(entry.libc)) {
+      sysroot_libc = entry.libc
+    } else if (defined(entry.crt1)) {
+      sysroot_crt1 = entry.crt1
+    }
+  }
 
   # Point the preprocessor at the include directories.  Use -idirafter
   # so they come in the same place in the search order as the --sysroot
   # include directory would: after the compiler-supplied headers,
   # allowing those to override and wrap libc headers via #include_next.
   cflags = []
-  foreach(dir, zircon_legacy_sysroot.include_dirs) {
+  foreach(dir, sysroot_include_dirs) {
     cflags += [
       "-idirafter",
       rebase_path(dir, root_build_dir, zircon_root_build_dir),
@@ -121,8 +130,8 @@ config("compiler_sysroot") {
   # when they change.  This forces recompiles too since this config()
   # applies to all compilation targets and not just linking ones, but this
   # code only changes when touching core Zircon library sources.
-  libc = rebase_path(zircon_legacy_sysroot.libc, "", zircon_root_build_dir)
-  crt1 = rebase_path(zircon_legacy_sysroot.crt1, "", zircon_root_build_dir)
+  libc = rebase_path(sysroot_libc, "", zircon_root_build_dir)
+  crt1 = rebase_path(sysroot_crt1, "", zircon_root_build_dir)
   inputs = [
     libc,
     crt1,
diff --git a/build/config/fuchsia/zircon.gni b/build/config/fuchsia/zircon.gni
index ba89f68d85bd5a2db5ccafa8d0232763ef8077d9..7d3cd42e0e3393ca1c6a619c79297cc8cfed7117 100644
--- a/build/config/fuchsia/zircon.gni
+++ b/build/config/fuchsia/zircon.gni
@@ -17,6 +17,10 @@ zircon_tools_dir = "$zircon_root_build_dir/tools"
 zircon_legacy_targets =
     read_file("$zircon_root_build_dir/legacy-$target_cpu.json", "json")
 
+# See //zircon/public/sysroot/BUILD.gn and //build/config/fuchsia/BUILD.gn.
+zircon_legacy_sysroot =
+    read_file("$zircon_root_build_dir/legacy_sysroot-$target_cpu.json", "json")
+
 if (current_toolchain == default_toolchain) {
   # By GN evaluation order this is roughly the first thing that happens at
   # all and it's synchronous so after this point we can read in files
diff --git a/build/zircon/BUILD.gn b/build/zircon/BUILD.gn
new file mode 100644
index 0000000000000000000000000000000000000000..60093824c65c6a78b64604018425e4e9b41c3dfa
--- /dev/null
+++ b/build/zircon/BUILD.gn
@@ -0,0 +1,28 @@
+# Copyright 2018 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Define a toolchain to build Zircon in.
+# This allows us to let the target and host toolchains depend on Zircon, which
+# in turn ensure Zircon is built before everything else.
+toolchain("zircon_toolchain") {
+  tool("stamp") {
+    command = "touch {{output}}"
+    description = "STAMP {{output}}"
+  }
+
+  tool("copy") {
+    # We use link instead of copy; the way "copy" tool is being used is
+    # compatible with links since Ninja is tracking changes to the source.
+    command = "ln -f {{source}} {{output}} 2>/dev/null || (rm -rf {{output}} && cp -af {{source}} {{output}})"
+    description = "COPY {{source}} {{output}}"
+  }
+
+  toolchain_args = {
+    toolchain_variant = {
+    }
+    toolchain_variant = {
+      base = get_label_info(":zircon_toolchain", "label_no_toolchain")
+    }
+  }
+}
diff --git a/build/zircon/OWNERS b/build/zircon/OWNERS
index e09a047ddf2e00002c3a570c3016f512f65fd85c..bee30f8dad5799bbbb96c1a85af9263385cc92db 100644
--- a/build/zircon/OWNERS
+++ b/build/zircon/OWNERS
@@ -1,2 +1,4 @@
+juliehockett@google.com
+mcgrathr@google.com
+phosek@google.com
 pylaligand@google.com
-*
diff --git a/build/zircon/README.md b/build/zircon/README.md
index 6f0d9a3155f2f68bb65660d96ff4902f5f75f357..fc15cf0f88831bf0f61c579b52064d3982353a31 100644
--- a/build/zircon/README.md
+++ b/build/zircon/README.md
@@ -1,35 +1,33 @@
 GN support for Zircon
 =====================
 
-This folder contains utilities that help Zircon artifacts better integrate into
-the GN build without having to manually maintain GN build files in sync with the
-existing `rules.mk` build files specific to Zircon.
-It also makes it so that targets in upper layers don't need to know about the
-structure of Zircon's output directory in order to use Zircon build artifacts,
-as knowledge of that structure is confined within the generated GN build files.
+TODO(BLD-353): This will go away when the build is fully unified.
 
-### Process
-
-The main build file [`//build/gn/BUILD.gn`](../gn/BUILD.gn) calls the
-[`//build/zircon/create_gn_rules.py`](create_gn_rules.py) script to produce
-`BUILD.gn` files for Zircon.
+Code in //build/config/fuchsia/zircon.gni populates the
+[`//zircon/public`](../../zircon/public) directory tree with links to
+[`template.gn`](template.gn).  This code generates targets for its
+directory based on instructions written as JSON by the Zircon `gn gen`
+step.  That code uses the `.gni` files here.
 
-That script uses a special, fast build of Zircon (`make packages`) to generate
-manifests for artifacts that are meant to be consumed by upper layers of the
-Fuchsia stack. These manifest are then turned into GN build files under
-[`//zircon/public`][zircon-public] whose targets other parts of the codebase
-can depend on.
+### Process
 
-This script is run early in the build process, before any other build file gets
-evaluated. This ensure that non-Zircon build files can safely depend on the
+The main build file [`//BUILD.gn`](../../BUILD.gn) imports
+[`//build/config/fuchsia/zircon.gni`](../config/fuchsia/zircon.gni).
+That makes that GN code run before all other evaluation in `gn gen`.
+This ensures that non-Zircon build files can safely depend on the
 generated targets.
 
-In order to keep the generated build files up-to-date, that process is repeated
-every time a file changes under `//zircon`.
-
-Note that the generated GN files should only depend on the Zircon source code.
-Invoking the Fuchsia build with different parameters on the same codebase should
-produce identical files.
-
-
-[zircon-public]: https://fuchsia.googlesource.com/fuchsia/+/master/zircon/public/
+This early GN code has the side effect of populating the `//zircon/public`
+subdirectories with `BUILD.gn` files that are links to
+[`template.gn`](template.gn).  This happens on every `gn gen` run, but all
+it does is maintain those directories of `BUILD.gn` links.  So multiple
+separate Fuchsia builds can refer to multiple separate Zircon builds
+without mutual interference, as long as they are referring to the same
+Zircon source tree so there's the same set of `//zircon/public`
+subdirectories to populate.
+
+Each file uses its portion of the instructions written as JSON by the
+Zircon `gn gen` step to define all the appropriate targets for that
+directory.  Hence, the actual operation of each
+`//zircon/public/.../BUILD.gn` file is controlled by the particular Zircon
+build attached to the Fuchsia build, but the files themselves are fixed.
diff --git a/build/zircon/add_library_debug_data.py b/build/zircon/add_library_debug_data.py
deleted file mode 100755
index e6b1113be505c51f20d84728ed0af160d097ab2b..0000000000000000000000000000000000000000
--- a/build/zircon/add_library_debug_data.py
+++ /dev/null
@@ -1,52 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2018 The Fuchsia Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import argparse
-import json
-import os
-import sys
-
-sys.path.append(os.path.join(
-    os.path.dirname(__file__),
-    os.pardir,
-    "cpp",
-))
-import binaries
-
-
-def main():
-    parser = argparse.ArgumentParser('Builds a metadata file')
-    parser.add_argument('--base',
-                        help='Path to the base metadata file',
-                        required=True)
-    parser.add_argument('--out',
-                        help='Path to the output file',
-                        required=True)
-    parser.add_argument('--lib-debug-file',
-                        help='Path to the source debug version of the library',
-                        required=True)
-    parser.add_argument('--debug-mapping',
-                        help='Path to the file where to write the file mapping for the debug library',
-                        required=True)
-    args = parser.parse_args()
-
-    # The path of the debug file in the SDK depends on its build id.
-    debug_path = binaries.get_sdk_debug_path(args.lib_debug_file)
-    with open(args.debug_mapping, 'w') as mappings_file:
-        mappings_file.write(debug_path + '=' + args.lib_debug_file + '\n')
-
-    with open(args.base, 'r') as base_file:
-        metadata = json.load(base_file)
-
-    metadata['binaries'].values()[0]['debug'] = debug_path
-
-    with open(args.out, 'w') as out_file:
-        json.dump(metadata, out_file, indent=2, sort_keys=True)
-
-    return 0
-
-
-if __name__ == '__main__':
-    sys.exit(main())
diff --git a/build/zircon/add_sysroot_debug_data.py b/build/zircon/add_sysroot_debug_data.py
deleted file mode 100755
index 9a879184efc2e3d5472f4c8f0585e0f6c55e7974..0000000000000000000000000000000000000000
--- a/build/zircon/add_sysroot_debug_data.py
+++ /dev/null
@@ -1,55 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2018 The Fuchsia Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import argparse
-import json
-import os
-import sys
-
-sys.path.append(os.path.join(
-    os.path.dirname(__file__),
-    os.pardir,
-    "cpp",
-))
-import binaries
-
-
-def main():
-    parser = argparse.ArgumentParser('Builds a metadata file')
-    parser.add_argument('--base',
-                        help='Path to the base metadata file',
-                        required=True)
-    parser.add_argument('--out',
-                        help='Path to the output file',
-                        required=True)
-    parser.add_argument('--lib-debug-file',
-                        help='Path to the source debug version of the library',
-                        action='append')
-    parser.add_argument('--debug-mapping',
-                        help='Path to the file where to write the file mapping for the debug library',
-                        required=True)
-    args = parser.parse_args()
-
-    debug_files = []
-
-    with open(args.debug_mapping, 'w') as mappings_file:
-        for debug_file in args.lib_debug_file:
-            debug_path = binaries.get_sdk_debug_path(debug_file)
-            mappings_file.write(debug_path + '=' + debug_file + '\n')
-            debug_files.append(debug_path)
-
-    with open(args.base, 'r') as base_file:
-        metadata = json.load(base_file)
-
-    metadata['versions'].values()[0]['debug_libs'] = debug_files
-
-    with open(args.out, 'w') as out_file:
-        json.dump(metadata, out_file, indent=2, sort_keys=True)
-
-    return 0
-
-
-if __name__ == '__main__':
-    sys.exit(main())
diff --git a/build/zircon/create_gn_rules.py b/build/zircon/create_gn_rules.py
deleted file mode 100755
index f630cee9a402ad7400e7dbbf74869a4d046666d2..0000000000000000000000000000000000000000
--- a/build/zircon/create_gn_rules.py
+++ /dev/null
@@ -1,275 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2017 The Fuchsia Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import argparse
-import errno
-import os
-import re
-import shutil
-import subprocess
-import sys
-
-
-SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
-FUCHSIA_ROOT = os.path.dirname(  # $root
-    os.path.dirname(             # build
-        SCRIPT_DIR))                 # zircon
-ZIRCON_ROOT = os.path.join(FUCHSIA_ROOT, 'zircon')
-
-sys.path += [os.path.join(FUCHSIA_ROOT, 'third_party', 'mako')]
-from mako.lookup import TemplateLookup
-from mako.template import Template
-
-
-# Packages included in the sysroot.
-SYSROOT_PACKAGES = ['c', 'zircon']
-
-# Prefixes of Zircon headers that should not appear in SDKs.
-NON_SDK_SYSROOT_HEADER_PREFIXES = [
-    'zircon/device',
-    'zircon/syscalls/definitions.rs',
-]
-# TODO(FIDL-273): remove this allowlist.
-MANDATORY_SDK_HEADERS = [
-    'zircon/device/ioctl.h',         # Needed by zircon/device/ramdisk.h
-    'zircon/device/ioctl-wrapper.h', # Needed by zircon/device/ramdisk.h
-    # TODO(ZX-2503): remove this entry.
-    'zircon/device/ramdisk.h',       # Needed by fs-management/ramdisk.h
-    'zircon/device/sysinfo.h',       # Needed by some external clients
-]
-
-# List of libraries with header files being transitioned from
-# 'include/foo/foo.h' to 'include/lib/foo/foo.h'. During the transition, both
-# the library's 'include/' and 'include/lib' directories are added to the
-# include path so both old and new style include work.
-# TODO(ZX-1871): Once everything in Zircon is migrated, remove this mechanism.
-LIBRARIES_BEING_MOVED = []
-
-# Prebuilt libraries for which headers shouldn't be included in an SDK.
-# While this kind of mechanism exists in the GN build, there's no equivalent in
-# the make build and we have to manually curate these libraries.
-LIBRARIES_WITHOUT_SDK_HEADERS = ['trace-engine']
-
-# Packages which should never appear in SDKs.
-# Dependencies on these packages will not be reflected in generated rules. The
-# lack of distinction between public and private deps in the make build system
-# is the reason why this list is needed.
-NON_SDK_DEPS = ['zircon-internal']
-
-def make_dir(path, is_dir=False):
-    '''Creates the directory at `path`.'''
-    target = path if is_dir else os.path.dirname(path)
-    try:
-        os.makedirs(target)
-    except OSError as exception:
-        if exception.errno == errno.EEXIST and os.path.isdir(target):
-            pass
-        else:
-            raise
-
-
-def try_remove(list, element):
-    '''Attempts to remove an element from a list, returning `true` if
-       successful.'''
-    try:
-        list.remove(element)
-        return True
-    except ValueError:
-        return False
-
-
-def parse_package(lines):
-    '''Parses the content of a package file.'''
-    result = {}
-    section_exp = re.compile('^\[([^\]]+)\]$')
-    attr_exp = re.compile('^([^=]+)=(.*)$')
-    current_section = None
-
-    def finalize_section():
-        if not current_section:
-            return
-        if current_list and current_map:
-            raise Exception('Found both map-style and list-style section')
-        if current_map:
-            result[current_section] = current_map
-        elif current_list:
-            result[current_section] = current_list
-    for line in lines:
-        section_match = section_exp.match(line)
-        if section_match:
-            finalize_section()
-            current_section = section_match.group(1)
-            current_list = []
-            current_map = {}
-            continue
-        attr_match = attr_exp.match(line)
-        if attr_match:
-            name = attr_match.group(1)
-            value = attr_match.group(2)
-            current_map[name] = value
-        else:
-            current_list.append(line.strip())
-    finalize_section()
-    return result
-
-
-def extract_file(name, path, context):
-    '''Extracts file path and base folder path from a map entry.'''
-    # name: foo/bar.h
-    # path: <SOURCE|BUILD>/somewhere/under/zircon/foo/bar.h
-    (full_path, changes) = re.subn('^SOURCE', context.source_base, path)
-    if not changes:
-        (full_path, changes) = re.subn('^BUILD', context.build_base, path)
-    if not changes:
-        raise Exception('Unknown pattern type: %s' % path)
-    folder = None
-    if full_path.endswith(name):
-        folder = os.path.relpath(full_path[:-len(name)], FUCHSIA_ROOT)
-    file = os.path.relpath(full_path, FUCHSIA_ROOT)
-    return (file, folder)
-
-
-def filter_deps(deps):
-    '''Sanitizes a given dependency list.'''
-    return filter(lambda x: x not in SYSROOT_PACKAGES, deps)
-
-
-def filter_sdk_deps(deps):
-    '''Sanitizes a given SDK dependency list.'''
-    return filter(lambda x: x not in NON_SDK_DEPS, deps)
-
-
-def generate_build_file(path, template_name, data, context):
-    '''Creates a build file based on a template.'''
-    make_dir(path)
-    template = context.templates.get_template(template_name)
-    contents = template.render(data=data)
-    with open(path, 'w') as build_file:
-        build_file.write(contents)
-
-
-class Sysroot(object):
-    '''Represents the sysroot created by Zircon.
-
-       Convenience storage object to be consumed by Mako templates.'''
-
-    def __init__(self):
-        self.files = {}
-        self.sdk_files = {}
-        self.headers = []
-        self.link_libs = []
-        self.dist_libs = []
-        self.debug_source_libs = []
-
-
-def generate_sysroot(package, context):
-    '''Generates the build glue for the sysroot.'''
-    data = Sysroot()
-
-    # Includes.
-    for name, path in package.get('includes', {}).iteritems():
-        (file, _) = extract_file(name, path, context)
-        data.files['include/%s' % name] = '//%s' % file
-        in_sdk = True
-        for prefix in NON_SDK_SYSROOT_HEADER_PREFIXES:
-            if name.startswith(prefix) and name not in MANDATORY_SDK_HEADERS:
-                in_sdk = False
-                break
-        if in_sdk:
-            dest = 'include/%s' % name
-            data.sdk_files[dest] = '//%s' % file
-            data.headers.append(dest)
-
-    # Lib.
-    for name, path in package.get('lib', {}).iteritems():
-        (file, _) = extract_file(name, path, context)
-        label = '//%s' % file
-        data.files[name] = label
-        type_dir = os.path.dirname(name)
-        if type_dir == 'debug':
-            data.debug_source_libs.append(label)
-        else:
-            data.sdk_files[name] = label
-            if type_dir == 'lib':
-                data.link_libs.append(name)
-            elif type_dir == 'dist/lib':
-                data.dist_libs.append(name)
-            else:
-                raise Exception('Unknown library type: ' + type_dir)
-
-    # Generate the build file.
-    build_path = os.path.join(context.out_dir, 'sysroot', 'BUILD.gn')
-    generate_build_file(build_path, 'sysroot.mako', data, context)
-
-
-class GenerationContext(object):
-    '''Describes the context in which GN rules should be generated.'''
-
-    def __init__(self, out_dir, source_base, build_base, templates):
-        self.out_dir = out_dir
-        self.source_base = source_base
-        self.build_base = build_base
-        self.templates = templates
-
-
-def main():
-    parser = argparse.ArgumentParser()
-    parser.add_argument('--out',
-                        help='Path to the output directory',
-                        required=True)
-    parser.add_argument('--zircon-build',
-                        help='Path to the Zircon build directory',
-                        required=True)
-    parser.add_argument('--zircon-manifest',
-                        help='Path to the Zircon export/manifest file',
-                        required=True)
-    parser.add_argument('--debug',
-                        help='Whether to print out debug information',
-                        action='store_true')
-    args = parser.parse_args()
-
-    out_dir = os.path.abspath(args.out)
-    shutil.rmtree(os.path.join(out_dir, 'sysroot'), True)
-    debug = args.debug
-
-    # Parse package definitions from Zircon's build.
-    packages = []
-    with open(args.zircon_manifest, 'r') as manifest:
-        for file in manifest:
-            file = file.strip()
-            with open(os.path.join(args.zircon_build, 'export', file), 'r') as pkg_file:
-                packages.append(parse_package(pkg_file.readlines()))
-    if debug:
-        print('Found %s packages:' % len(packages))
-        names = sorted(map(lambda p: p['package']['name'], packages))
-        for name in names:
-            print(' - %s' % name)
-
-    # Generate some GN glue for each package.
-    context = GenerationContext(
-        out_dir,
-        ZIRCON_ROOT,
-        os.path.abspath(args.zircon_build),
-        TemplateLookup(directories=[SCRIPT_DIR]),
-    )
-    for package in packages:
-        name = package['package']['name']
-        type = package['package']['type']
-        arch = package['package']['arch']
-        if name == 'c':
-            generate_sysroot(package, context)
-            print('Generated sysroot')
-            continue
-        if name in SYSROOT_PACKAGES:
-            print('Ignoring sysroot part: %s' % name)
-            continue
-        print('(%s) Unsupported package type: %s/%s, skipping'
-              % (name, type, arch))
-        if debug:
-            print('Processed %s (%s)' % (name, type))
-
-
-if __name__ == '__main__':
-    sys.exit(main())
diff --git a/build/zircon/header.mako b/build/zircon/header.mako
deleted file mode 100644
index cf73679564bb176e157d60eaeed38cec694f43a8..0000000000000000000000000000000000000000
--- a/build/zircon/header.mako
+++ /dev/null
@@ -1,6 +0,0 @@
-# Copyright 2018 The Fuchsia Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# DO NOT MANUALLY EDIT!
-# Generated by //build/zircon/create_gn_rules.py.
diff --git a/build/zircon/list_source_files.py b/build/zircon/list_source_files.py
deleted file mode 100755
index 819309b715ed8562964909fb98765bbb2bef320f..0000000000000000000000000000000000000000
--- a/build/zircon/list_source_files.py
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2017 The Fuchsia Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import os
-import subprocess
-import sys
-
-
-FUCHSIA_ROOT = os.path.dirname(  # $root
-    os.path.dirname(             # build
-    os.path.dirname(             # zircon
-    os.path.abspath(__file__))))
-ZIRCON_ROOT = os.path.join(FUCHSIA_ROOT, "zircon")
-
-
-def list_files(deleted=False):
-    git_cmd = ['git', 'ls-files']
-    if deleted:
-        git_cmd.append('-d')
-    output = subprocess.check_output(git_cmd, cwd=ZIRCON_ROOT)
-    return set(output.splitlines())
-
-
-def get_files():
-    all_files = list_files()
-    deleted_files = list_files(deleted=True)
-    files = all_files - deleted_files
-    return [os.path.join(ZIRCON_ROOT, file) for file in files]
-
-
-def main():
-    for file in get_files():
-        print(file)
-
-
-if __name__ == "__main__":
-    sys.exit(main())
diff --git a/build/zircon/sysroot.mako b/build/zircon/sysroot.mako
deleted file mode 100644
index 7ca2d2f9a43c24312f4fb7769cd3497b93bddc37..0000000000000000000000000000000000000000
--- a/build/zircon/sysroot.mako
+++ /dev/null
@@ -1,126 +0,0 @@
-<%include file="header.mako" />
-
-import("//build/sdk/sdk_atom.gni")
-
-_out_dir = get_label_info(":bogus", "target_out_dir")
-
-<%def name="copy_target(path)">${"copy_%s" % path.replace('/', '_').replace('.', '_')}</%def>
-
-% for path, file in sorted(data.files.iteritems()):
-copy("${copy_target(path)}") {
-  sources = [
-    "${file}",
-  ]
-
-  outputs = [
-    "$_out_dir/sysroot/${path}",
-  ]
-}
-
-% endfor
-
-group("sysroot") {
-  deps = [
-    % for path, file in sorted(data.files.iteritems()):
-    ":${copy_target(path)}",
-    % endfor
-  ]
-}
-
-file_base = "arch/$target_cpu/sysroot"
-
-version_content = {
-  root = file_base
-
-  include_dir = "$file_base/include"
-  headers = []
-  % for header in sorted(data.headers):
-  headers += [ "$file_base/${header}" ]
-  % endfor
-
-  link_libs = []
-  % for lib in sorted(data.link_libs):
-  link_libs += [ "$file_base/${lib}" ]
-  % endfor
-
-  dist_libs = []
-  % for lib in sorted(data.dist_libs):
-  dist_libs += [ "$file_base/${lib}" ]
-  % endfor
-}
-metadata = {
-  type = "sysroot"
-  name = "sysroot"
-  versions = {}
-  if (target_cpu == "arm64") {
-    versions.arm64 = version_content
-  } else if (target_cpu == "x64") {
-    versions.x64 = version_content
-  } else {
-    assert(false, "Unknown CPU type: $target_cpu")
-  }
-}
-
-base_meta_file = "$target_gen_dir/sysroot.base_meta.json"
-write_file(base_meta_file, metadata, "json")
-augmented_meta_file = "$target_gen_dir/sysroot.full_meta.json"
-debug_mapping_file = "$target_gen_dir/sysroot.mapping.txt"
-
-action("sysroot_meta") {
-  script = "//build/zircon/add_sysroot_debug_data.py"
-
-  inputs = [
-    base_meta_file,
-    % for lib in sorted(data.debug_source_libs):
-    "${lib}",
-    % endfor
-  ]
-
-  outputs = [
-    augmented_meta_file,
-  ]
-
-  args = [
-    "--base",
-    rebase_path(base_meta_file),
-    "--out",
-    rebase_path(augmented_meta_file),
-    "--debug-mapping",
-    rebase_path(debug_mapping_file),
-    % for lib in sorted(data.debug_source_libs):
-    "--lib-debug-file",
-    rebase_path("${lib}"),
-    % endfor
-  ]
-
-  deps = [
-    ":sysroot",
-  ]
-}
-
-sdk_atom("sysroot_sdk") {
-  id = "sdk://pkg/sysroot"
-  category = "partner"
-
-  meta = {
-    dest = "pkg/sysroot/meta.json"
-    schema = "sysroot"
-    source = augmented_meta_file
-  }
-
-  files = [
-    % for path, file in sorted(data.sdk_files.iteritems()):
-    {
-      source = "${file}"
-      dest = "$file_base/${path}"
-    },
-    % endfor
-  ]
-
-  file_list = debug_mapping_file
-
-  non_sdk_deps = [
-    ":sysroot",
-    ":sysroot_meta",
-  ]
-}
diff --git a/scripts/build-zircon.sh b/scripts/build-zircon.sh
index 033ffe83fc21abadfd255fef86ffd8254b076d12..a3cce96f3bbc851c0ee330e2b8be3ecc4a12aa14 100755
--- a/scripts/build-zircon.sh
+++ b/scripts/build-zircon.sh
@@ -128,7 +128,7 @@ if $TOOLS_ONLY; then
 else
   NINJA_CMD+=(legacy-host_tests)
   for arch in "${ARCHLIST[@]}"; do
-    NINJA_CMD+=("manifest-$arch")
+    NINJA_CMD+=("legacy-$arch")
   done
 fi
 
diff --git a/zircon/.gitignore b/zircon/.gitignore
index 753de22de789bc83b4f3c5cf4c2dce36101348b1..c3c81cc3d2f08335a11ad18528922c651fcb1427 100644
--- a/zircon/.gitignore
+++ b/zircon/.gitignore
@@ -32,7 +32,6 @@ json_generator_tests_*.txt
 /public/banjo/
 /public/fidl/
 /public/lib/
-/public/sysroot/
 /public/tool/
 .idea/
 CMakeLists.txt
diff --git a/zircon/BUILD.gn b/zircon/BUILD.gn
index cea6382c75941c67e2a3a708b7f5396250dce103..9ea831174652f31a87d729558b01903a032517dd 100644
--- a/zircon/BUILD.gn
+++ b/zircon/BUILD.gn
@@ -4,7 +4,6 @@
 
 import("$zx/public/gn/build_api_module.gni")
 import("$zx/public/gn/config/standard.gni")
-import("$zx/public/gn/legacy_pkg.gni")  # TODO(BLD-353): temporary hack
 import("$zx/public/gn/toolchain/c_utils.gni")
 import("$zx/public/gn/toolchain/environment_redirect.gni")
 import("$zx/public/gn/zbi.gni")
@@ -189,6 +188,16 @@ if (current_toolchain == default_toolchain) {
       }
     }
 
+    build_api_module("legacy_sysroot-$cpu") {
+      testonly = true
+      data_keys = [ "legacy_sysroot" ]
+      walk_keys = [ "legacy_barrier" ]
+      deps = legacy_deps
+      foreach(dep, legacy_cpu_deps) {
+        deps += [ "$dep-$cpu" ]
+      }
+    }
+
     environment_redirect("all-ulib-$cpu") {
       testonly = true
       cpu = cpu
@@ -198,15 +207,6 @@ if (current_toolchain == default_toolchain) {
       ]
     }
 
-    legacy_pkg("manifest-$cpu") {
-      testonly = true
-      data_keys = [ "legacy_pkg_manifest" ]
-      walk_keys = [ "legacy_barrier" ]
-      deps = [
-        ":legacy-$cpu",
-      ]
-    }
-
     # This lists just the one file to link against to get fdio.
     build_api_module("legacy-fdio-$cpu") {
       data_keys = [ "link_output" ]
diff --git a/zircon/public/gn/legacy_pkg.gni b/zircon/public/gn/legacy_pkg.gni
deleted file mode 100644
index b3d269fadbc943f0e0693118a3e6bfa43a458fc6..0000000000000000000000000000000000000000
--- a/zircon/public/gn/legacy_pkg.gni
+++ /dev/null
@@ -1,25 +0,0 @@
-# Copyright 2019 The Fuchsia Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# TODO(BLD-353): This is all temporary stuff to maintain rough compatibility
-# with the old makefile build as used by the higher-layer Fuchsia GN build.
-template("legacy_pkg") {
-  generated_file(target_name) {
-    outputs = [
-      "$root_build_dir/export/$target_name",
-    ]
-    output_conversion = "list lines"
-    forward_variables_from(invoker,
-                           [
-                             "contents",
-                             "data_keys",
-                             "deps",
-                             "walk_keys",
-                             "testonly",
-                           ])
-    metadata = {
-      legacy_pkg_manifest = [ target_name ]
-    }
-  }
-}
diff --git a/zircon/public/sysroot/BUILD.gn b/zircon/public/sysroot/BUILD.gn
new file mode 100644
index 0000000000000000000000000000000000000000..b46d3f52eb28f5cd6f1c19289d6986fbc63ad4c7
--- /dev/null
+++ b/zircon/public/sysroot/BUILD.gn
@@ -0,0 +1,165 @@
+# Copyright 2019 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/fuchsia/zircon.gni")
+import("//build/sdk/sdk_atom.gni")
+
+sysroot_toolchain = "//build/zircon:zircon_toolchain"
+sysroot_dir = get_label_info(":sysroot($sysroot_toolchain)", "target_out_dir")
+sysroot_dir += "/sysroot"
+
+# Collect the metadata for the SDK.
+file_base = "arch/$target_cpu/sysroot"
+sdk_files = []
+
+version_content = {
+  root = file_base
+
+  include_dir = "$file_base/include"
+  headers = []
+  link_libs = []
+  dist_libs = []
+  debug_libs = []
+}
+
+# Turn the information from Zircon into a set of copy() rules for the
+# sysroot while filling in $version_content.
+sysroot_deps = []
+i = 0
+foreach(entry, zircon_legacy_sysroot) {
+  if (defined(entry.sdk)) {
+    sdk = {
+    }
+    sdk = entry.sdk
+    if (defined(sdk.headers)) {
+      # This has to generate a separate copy() target for each file.
+      dir = rebase_path(sdk.include_dir, "", zircon_root_build_dir)
+      foreach(file, sdk.headers) {
+        i = i + 1
+        if (current_toolchain == sysroot_toolchain) {
+          copy_target = "copy_$i"
+          sysroot_deps += [ ":$copy_target" ]
+          copy(copy_target) {
+            visibility = [ ":sysroot" ]
+            sources = [
+              "$dir/$file",
+            ]
+            outputs = [
+              "$sysroot_dir/include/$file",
+            ]
+          }
+        }
+        version_content.headers += [ "$file_base/include/$file" ]
+        sdk_files += [
+          {
+            source = "$dir/$file"
+            dest = "$file_base/include/$file"
+          },
+        ]
+      }
+    } else if (defined(sdk.debug)) {
+      version_content.debug_libs +=
+          [ rebase_path(sdk.source, "", zircon_root_build_dir) ]
+    } else {
+      # This is just a single copy() target.
+      if (defined(sdk.link)) {
+        file = "$sysroot_dir/${sdk.link}"
+        version_content.link_libs += [ "$file_base/${sdk.link}" ]
+        sdk_files += [
+          {
+            source = rebase_path(sdk.source, "", zircon_root_build_dir)
+            dest = "$file_base/${sdk.link}"
+          },
+        ]
+      } else if (defined(sdk.dist)) {
+        file = "$sysroot_dir/${sdk.dist}"
+        version_content.dist_libs += [ "$file_base/${sdk.dist}" ]
+        sdk_files += [
+          {
+            source = rebase_path(sdk.source, "", zircon_root_build_dir)
+            dest = "$file_base/${sdk.dist}"
+          },
+        ]
+      } else {
+        assert(false, "confused by $sdk")
+      }
+      i = i + 1
+      if (current_toolchain == sysroot_toolchain) {
+        copy_target = "copy_$i"
+        sysroot_deps += [ ":$copy_target" ]
+        copy(copy_target) {
+          visibility = [ ":sysroot" ]
+          sources = [
+            "$zircon_root_build_dir/${sdk.source}",
+          ]
+          outputs = [
+            file,
+          ]
+        }
+      }
+    }
+  }
+}
+
+group("sysroot") {
+  if (current_toolchain == sysroot_toolchain) {
+    deps = sysroot_deps
+  } else {
+    assert(sysroot_deps == [])
+    public_deps = [
+      ":sysroot($sysroot_toolchain)",
+    ]
+  }
+}
+
+write_file("$target_gen_dir/sysroot.meta.in.json",
+           {
+             type = "sysroot"
+             name = "sysroot"
+             versions = {
+               if (target_cpu == "arm64") {
+                 arm64 = version_content
+               } else if (target_cpu == "x64") {
+                 x64 = version_content
+               } else {
+                 assert(false, "Unknown CPU type: $target_cpu")
+               }
+             }
+           },
+           "json")
+
+action("sysroot-meta") {
+  visibility = [ ":*" ]
+  script = "//build/zircon/sdk_build_id.py"
+  sources = [
+    "$target_gen_dir/sysroot.meta.in.json",
+  ]
+  outputs = [
+    "$target_out_dir/sysroot.meta.out.json",
+    "$target_out_dir/sysroot.debug.manifest",
+  ]
+  args = [
+    "--input=" + rebase_path(sources[0], root_build_dir),
+    "--output=" + rebase_path(outputs[0], root_build_dir),
+    "--manifest=" + rebase_path(outputs[1], root_build_dir),
+    "--location=/versions/$target_cpu/debug_libs",
+  ]
+}
+meta_outputs = get_target_outputs(":sysroot-meta")
+
+sdk_atom("sysroot_sdk") {
+  id = "sdk://pkg/sysroot"
+  category = "partner"
+
+  non_sdk_deps = [ ":sysroot-meta" ]
+
+  meta = {
+    dest = "pkg/sysroot/meta.json"
+    schema = "sysroot"
+    source = meta_outputs[0]
+  }
+
+  files = sdk_files
+  file_list = meta_outputs[1]
+}
diff --git a/zircon/system/ulib/c/BUILD.gn b/zircon/system/ulib/c/BUILD.gn
index 6f148de3d13894c45e676157a0ad78eaa3322fe8..8faf452e1061a5b4b2fd1259698a647110576c24 100644
--- a/zircon/system/ulib/c/BUILD.gn
+++ b/zircon/system/ulib/c/BUILD.gn
@@ -2,8 +2,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("$zx/public/gn/legacy_pkg.gni")  # TODO(BLD-353): temporary hack
-
 library("c") {
   shared = true
   static = false
@@ -24,10 +22,314 @@ library("c") {
   # Suppress the ${toolchain.implicit_deps} that points back to here.
   no_implicit_deps = true
 
-  if (toolchain.base_environment == "user" &&
-      current_toolchain == toolchain.shlib &&
-      toolchain.tags + [ "gcc" ] - [ "gcc" ] == []) {
-    deps += [ ":c-$current_cpu.pkg" ]
+  # TODO(BLD-353): temporary kludges; see //zircon/public/sysroot
+  metadata = {
+    legacy_sysroot = [
+      {
+        libc = rebase_path("$target_out_dir/libc.so.debug", root_build_dir)
+      },
+      {
+        include_dirs = [
+          "//zircon/system/public",
+          "//zircon/system/ulib/zircon/include",
+          "//zircon/third_party/ulib/musl/include",
+        ]
+      },
+      {
+        sdk = {
+          include_dir = "//zircon/system/public"
+          headers = [
+            "zircon/assert.h",
+            "zircon/boot/bootdata.h",
+            "zircon/boot/driver-config.h",
+            "zircon/boot/e820.h",
+            "zircon/boot/image.h",
+            "zircon/boot/multiboot.h",
+            "zircon/boot/netboot.h",
+            "zircon/boot/sysconfig.h",
+            "zircon/compiler.h",
+            "zircon/driver/binding.h",
+            "zircon/errors.h",
+            "zircon/features.h",
+            "zircon/fidl.h",
+            "zircon/hw/gpt.h",
+            "zircon/hw/i2c.h",
+            "zircon/hw/pci.h",
+            "zircon/hw/usb.h",
+            "zircon/hw/usb/audio.h",
+            "zircon/hw/usb/cdc.h",
+            "zircon/hw/usb/dfu.h",
+            "zircon/hw/usb/hid.h",
+            "zircon/hw/usb/hub.h",
+            "zircon/hw/usb/ums.h",
+            "zircon/hw/usb/video.h",
+            "zircon/limits.h",
+            "zircon/listnode.h",
+            "zircon/pixelformat.h",
+            "zircon/process.h",
+            "zircon/processargs.h",
+            "zircon/rights.h",
+            "zircon/syscalls.abigen",
+            "zircon/syscalls.h",
+            "zircon/syscalls/debug.h",
+            "zircon/syscalls/exception.h",
+            "zircon/syscalls/hypervisor.h",
+            "zircon/syscalls/iommu.h",
+            "zircon/syscalls/log.h",
+            "zircon/syscalls/object.h",
+            "zircon/syscalls/pci.h",
+            "zircon/syscalls/policy.h",
+            "zircon/syscalls/port.h",
+            "zircon/syscalls/profile.h",
+            "zircon/syscalls/resource.h",
+            "zircon/syscalls/smc.h",
+            "zircon/syscalls/system.h",
+            "zircon/syscalls/types.h",
+            "zircon/time.h",
+            "zircon/tls.h",
+            "zircon/types.h",
+
+            # Note: Most of zircon/device is excluded from SDKs.
+            # TODO(FIDL-273,ZX-2503): remove this allowlist.
+            "zircon/device/audio.h",
+            "zircon/device/ioctl-wrapper.h",  # Needed by zircon/device/ramdisk.h
+            "zircon/device/ioctl.h",  # Needed by zircon/device/ramdisk.h
+          ]
+        }
+      },
+      {
+        sdk = {
+          include_dir = "//zircon/third_party/ulib/musl/include"
+          headers = [
+            "alloca.h",
+            "ar.h",
+            "arpa/ftp.h",
+            "arpa/inet.h",
+            "arpa/nameser.h",
+            "arpa/nameser_compat.h",
+            "arpa/telnet.h",
+            "arpa/tftp.h",
+            "assert.h",
+            "bits/aarch64/endian.h",
+            "bits/aarch64/fenv.h",
+            "bits/aarch64/float.h",
+            "bits/aarch64/io.h",
+            "bits/aarch64/ioctl.h",
+            "bits/aarch64/ipc.h",
+            "bits/aarch64/reg.h",
+            "bits/aarch64/setjmp.h",
+            "bits/aarch64/signal.h",
+            "bits/aarch64/stat.h",
+            "bits/alltypes.h",
+            "bits/endian.h",
+            "bits/errno.h",
+            "bits/fcntl.h",
+            "bits/fenv.h",
+            "bits/float.h",
+            "bits/io.h",
+            "bits/ioctl.h",
+            "bits/ipc.h",
+            "bits/limits.h",
+            "bits/msg.h",
+            "bits/null.h",
+            "bits/poll.h",
+            "bits/posix.h",
+            "bits/reg.h",
+            "bits/resource.h",
+            "bits/sem.h",
+            "bits/setjmp.h",
+            "bits/shm.h",
+            "bits/signal.h",
+            "bits/socket.h",
+            "bits/stat.h",
+            "bits/statfs.h",
+            "bits/termios.h",
+            "bits/x86_64/endian.h",
+            "bits/x86_64/fenv.h",
+            "bits/x86_64/float.h",
+            "bits/x86_64/io.h",
+            "bits/x86_64/ioctl.h",
+            "bits/x86_64/ipc.h",
+            "bits/x86_64/reg.h",
+            "bits/x86_64/setjmp.h",
+            "bits/x86_64/signal.h",
+            "bits/x86_64/stat.h",
+            "byteswap.h",
+            "complex.h",
+            "cpio.h",
+            "crypt.h",
+            "ctype.h",
+            "dirent.h",
+            "dlfcn.h",
+            "elf.h",
+            "endian.h",
+            "err.h",
+            "errno.h",
+            "fcntl.h",
+            "features.h",
+            "fenv.h",
+            "float.h",
+            "fmtmsg.h",
+            "fnmatch.h",
+            "ftw.h",
+            "getopt.h",
+            "glob.h",
+            "grp.h",
+            "iconv.h",
+            "ifaddrs.h",
+            "inttypes.h",
+            "iso646.h",
+            "langinfo.h",
+            "libgen.h",
+            "limits.h",
+            "link.h",
+            "locale.h",
+            "malloc.h",
+            "math.h",
+            "memory.h",
+            "monetary.h",
+            "net/ethernet.h",
+            "net/if.h",
+            "net/if_arp.h",
+            "net/route.h",
+            "netdb.h",
+            "netinet/ether.h",
+            "netinet/icmp6.h",
+            "netinet/if_ether.h",
+            "netinet/igmp.h",
+            "netinet/in.h",
+            "netinet/in_systm.h",
+            "netinet/ip.h",
+            "netinet/ip6.h",
+            "netinet/ip_icmp.h",
+            "netinet/tcp.h",
+            "netinet/udp.h",
+            "netpacket/packet.h",
+            "nl_types.h",
+            "paths.h",
+            "poll.h",
+            "pthread.h",
+            "pwd.h",
+            "regex.h",
+            "resolv.h",
+            "sched.h",
+            "search.h",
+            "semaphore.h",
+            "setjmp.h",
+            "signal.h",
+            "spawn.h",
+            "stdio.h",
+            "stdlib.h",
+            "stdnoreturn.h",
+            "string.h",
+            "strings.h",
+            "stropts.h",
+            "sys/acct.h",
+            "sys/auxv.h",
+            "sys/dir.h",
+            "sys/errno.h",
+            "sys/eventfd.h",
+            "sys/fcntl.h",
+            "sys/file.h",
+            "sys/fsuid.h",
+            "sys/io.h",
+            "sys/ioctl.h",
+            "sys/ipc.h",
+            "sys/klog.h",
+            "sys/mman.h",
+            "sys/mount.h",
+            "sys/msg.h",
+            "sys/mtio.h",
+            "sys/param.h",
+            "sys/personality.h",
+            "sys/poll.h",
+            "sys/quota.h",
+            "sys/random.h",
+            "sys/reboot.h",
+            "sys/reg.h",
+            "sys/select.h",
+            "sys/sem.h",
+            "sys/shm.h",
+            "sys/signal.h",
+            "sys/signalfd.h",
+            "sys/socket.h",
+            "sys/stat.h",
+            "sys/statfs.h",
+            "sys/statvfs.h",
+            "sys/stropts.h",
+            "sys/swap.h",
+            "sys/syslog.h",
+            "sys/termios.h",
+            "sys/time.h",
+            "sys/timeb.h",
+            "sys/timerfd.h",
+            "sys/times.h",
+            "sys/timex.h",
+            "sys/ttydefaults.h",
+            "sys/types.h",
+            "sys/ucontext.h",
+            "sys/uio.h",
+            "sys/un.h",
+            "sys/utsname.h",
+            "sys/vfs.h",
+            "sys/wait.h",
+            "sysexits.h",
+            "syslog.h",
+            "tar.h",
+            "termios.h",
+            "threads.h",
+            "time.h",
+            "uchar.h",
+            "ucontext.h",
+            "unistd.h",
+            "utime.h",
+            "values.h",
+            "wait.h",
+            "wchar.h",
+            "wctype.h",
+            "wordexp.h",
+            "zircon/dlfcn.h",
+            "zircon/sanitizer.h",
+            "zircon/threads.h",
+          ]
+        }
+      },
+      {
+        sdk = {
+          source = rebase_path("$target_out_dir/libc.so", root_build_dir)
+          link = "lib/libc.so"
+        }
+      },
+      {
+        sdk = {
+          source = rebase_path("$target_out_dir/libc.so.debug", root_build_dir)
+          debug = "debug/libc.so"
+        }
+      },
+      {
+        sdk = {
+          source = rebase_path("$target_out_dir/libc.so", root_build_dir)
+          dist = "dist/lib/ld.so.1"
+        }
+      },
+    ]
+    foreach(lib,
+            [
+              "libdl.so",
+              "libm.so",
+              "libpthread.so",
+              "librt.so",
+            ]) {
+      legacy_sysroot += [
+        {
+          sdk = {
+            source =
+                rebase_path("$zx/third_party/ulib/musl/lib.ld", root_build_dir)
+            link = "lib/$lib"
+          }
+        },
+      ]
+    }
   }
 }
 
@@ -43,355 +345,17 @@ source_set("crt1") {
   # worthwhile to have PLT entries for main or __libc_start_main, since
   # they are always used eagerly anyway.
   cflags = [ "-fno-plt" ]
-}
-
-# TODO(BLD-353): The generic kludgery can't handle the weirdness here.
-# So emit the pkg file directly.
-if (toolchain.base_environment == "user" &&
-    current_toolchain == toolchain.shlib &&
-    toolchain.tags + [ "gcc" ] - [ "gcc" ] == []) {
-  write_file("$root_build_dir/legacy-sysroot-$current_cpu.gni",
-             {
-               zircon_legacy_sysroot = {
-                 include_dirs = [
-                   "//zircon/system/public",
-                   "//zircon/system/ulib/zircon/include",
-                   "//zircon/third_party/ulib/musl/include",
-                   rebase_path(root_gen_dir, root_build_dir),
-                 ]
-                 crt1 = rebase_path(
-                         get_label_info(":crt1(${toolchain.label})",
-                                        "target_out_dir") + "/crt1.Scrt1.cpp.o",
-                         root_build_dir)
-                 libc = rebase_path("$target_out_dir/libc.so.debug",
-                                    root_build_dir)
-               }
-             },
-             "scope")
-
-  legacy_pkg("c-$current_cpu.pkg") {
-    contents = [
-      "[package]",
-      "name=c",
-      "type=lib",
-      "arch=$zircon_cpu",
-    ]
-
-    contents += [ "[includes]" ]
-    musl_headers = [
-      "alloca.h",
-      "ar.h",
-      "arpa/ftp.h",
-      "arpa/inet.h",
-      "arpa/nameser.h",
-      "arpa/nameser_compat.h",
-      "arpa/telnet.h",
-      "arpa/tftp.h",
-      "assert.h",
-      "bits/aarch64/endian.h",
-      "bits/aarch64/fenv.h",
-      "bits/aarch64/float.h",
-      "bits/aarch64/io.h",
-      "bits/aarch64/ioctl.h",
-      "bits/aarch64/ipc.h",
-      "bits/aarch64/reg.h",
-      "bits/aarch64/setjmp.h",
-      "bits/aarch64/signal.h",
-      "bits/aarch64/stat.h",
-      "bits/alltypes.h",
-      "bits/endian.h",
-      "bits/errno.h",
-      "bits/fcntl.h",
-      "bits/fenv.h",
-      "bits/float.h",
-      "bits/io.h",
-      "bits/ioctl.h",
-      "bits/ipc.h",
-      "bits/limits.h",
-      "bits/msg.h",
-      "bits/null.h",
-      "bits/poll.h",
-      "bits/posix.h",
-      "bits/reg.h",
-      "bits/resource.h",
-      "bits/sem.h",
-      "bits/setjmp.h",
-      "bits/shm.h",
-      "bits/signal.h",
-      "bits/socket.h",
-      "bits/stat.h",
-      "bits/statfs.h",
-      "bits/termios.h",
-      "bits/x86_64/endian.h",
-      "bits/x86_64/fenv.h",
-      "bits/x86_64/float.h",
-      "bits/x86_64/io.h",
-      "bits/x86_64/ioctl.h",
-      "bits/x86_64/ipc.h",
-      "bits/x86_64/reg.h",
-      "bits/x86_64/setjmp.h",
-      "bits/x86_64/signal.h",
-      "bits/x86_64/stat.h",
-      "byteswap.h",
-      "complex.h",
-      "cpio.h",
-      "crypt.h",
-      "ctype.h",
-      "dirent.h",
-      "dlfcn.h",
-      "elf.h",
-      "endian.h",
-      "err.h",
-      "errno.h",
-      "fcntl.h",
-      "features.h",
-      "fenv.h",
-      "float.h",
-      "fmtmsg.h",
-      "fnmatch.h",
-      "ftw.h",
-      "getopt.h",
-      "glob.h",
-      "grp.h",
-      "iconv.h",
-      "ifaddrs.h",
-      "inttypes.h",
-      "iso646.h",
-      "langinfo.h",
-      "libgen.h",
-      "limits.h",
-      "link.h",
-      "locale.h",
-      "malloc.h",
-      "math.h",
-      "memory.h",
-      "monetary.h",
-      "net/ethernet.h",
-      "net/if.h",
-      "net/if_arp.h",
-      "net/route.h",
-      "netdb.h",
-      "netinet/ether.h",
-      "netinet/icmp6.h",
-      "netinet/if_ether.h",
-      "netinet/igmp.h",
-      "netinet/in.h",
-      "netinet/in_systm.h",
-      "netinet/ip.h",
-      "netinet/ip6.h",
-      "netinet/ip_icmp.h",
-      "netinet/tcp.h",
-      "netinet/udp.h",
-      "netpacket/packet.h",
-      "nl_types.h",
-      "paths.h",
-      "poll.h",
-      "pthread.h",
-      "pwd.h",
-      "regex.h",
-      "resolv.h",
-      "sched.h",
-      "search.h",
-      "semaphore.h",
-      "setjmp.h",
-      "signal.h",
-      "spawn.h",
-      "stdio.h",
-      "stdlib.h",
-      "stdnoreturn.h",
-      "string.h",
-      "strings.h",
-      "stropts.h",
-      "sys/acct.h",
-      "sys/auxv.h",
-      "sys/dir.h",
-      "sys/errno.h",
-      "sys/eventfd.h",
-      "sys/fcntl.h",
-      "sys/file.h",
-      "sys/fsuid.h",
-      "sys/io.h",
-      "sys/ioctl.h",
-      "sys/ipc.h",
-      "sys/klog.h",
-      "sys/mman.h",
-      "sys/mount.h",
-      "sys/msg.h",
-      "sys/mtio.h",
-      "sys/param.h",
-      "sys/personality.h",
-      "sys/poll.h",
-      "sys/quota.h",
-      "sys/random.h",
-      "sys/reboot.h",
-      "sys/reg.h",
-      "sys/select.h",
-      "sys/sem.h",
-      "sys/shm.h",
-      "sys/signal.h",
-      "sys/signalfd.h",
-      "sys/socket.h",
-      "sys/stat.h",
-      "sys/statfs.h",
-      "sys/statvfs.h",
-      "sys/stropts.h",
-      "sys/swap.h",
-      "sys/syslog.h",
-      "sys/termios.h",
-      "sys/time.h",
-      "sys/timeb.h",
-      "sys/timerfd.h",
-      "sys/times.h",
-      "sys/timex.h",
-      "sys/ttydefaults.h",
-      "sys/types.h",
-      "sys/ucontext.h",
-      "sys/uio.h",
-      "sys/un.h",
-      "sys/utsname.h",
-      "sys/vfs.h",
-      "sys/wait.h",
-      "sysexits.h",
-      "syslog.h",
-      "tar.h",
-      "termios.h",
-      "threads.h",
-      "time.h",
-      "uchar.h",
-      "ucontext.h",
-      "unistd.h",
-      "utime.h",
-      "values.h",
-      "wait.h",
-      "wchar.h",
-      "wctype.h",
-      "wordexp.h",
-      "zircon/dlfcn.h",
-      "zircon/sanitizer.h",
-      "zircon/threads.h",
-    ]
-    foreach(file, musl_headers) {
-      contents += [ "$file=SOURCE/third_party/ulib/musl/include/$file" ]
-    }
-
-    public_headers = [
-      "zircon/assert.h",
-      "zircon/boot/bootdata.h",
-      "zircon/boot/driver-config.h",
-      "zircon/boot/e820.h",
-      "zircon/boot/image.h",
-      "zircon/boot/multiboot.h",
-      "zircon/boot/netboot.h",
-      "zircon/boot/sysconfig.h",
-      "zircon/compiler.h",
-      "zircon/device/audio-codec.h",
-      "zircon/device/audio.h",
-      "zircon/device/block.h",
-      "zircon/device/bt-hci.h",
-      "zircon/device/display-controller.h",
-      "zircon/device/ethernet.h",
-      "zircon/device/intel-hda.h",
-      "zircon/device/ioctl-wrapper.h",
-      "zircon/device/ioctl.h",
-      "zircon/device/ktrace.h",
-      "zircon/device/media-codec.h",
-      "zircon/device/midi.h",
-      "zircon/device/nand.h",
-      "zircon/device/qmi-transport.h",
-      "zircon/device/scpi.h",
-      "zircon/device/serial.h",
-      "zircon/device/usb-peripheral-test.h",
-      "zircon/device/usb-peripheral.h",
-      "zircon/device/vfs.h",
-      "zircon/driver/binding.h",
-      "zircon/errors.h",
-      "zircon/features.h",
-      "zircon/fidl.h",
-      "zircon/hw/gpt.h",
-      "zircon/hw/i2c.h",
-      "zircon/hw/pci.h",
-      "zircon/hw/usb.h",
-      "zircon/hw/usb/audio.h",
-      "zircon/hw/usb/cdc.h",
-      "zircon/hw/usb/dfu.h",
-      "zircon/hw/usb/hid.h",
-      "zircon/hw/usb/hub.h",
-      "zircon/hw/usb/ums.h",
-      "zircon/hw/usb/video.h",
-      "zircon/limits.h",
-      "zircon/listnode.h",
-      "zircon/pixelformat.h",
-      "zircon/process.h",
-      "zircon/processargs.h",
-      "zircon/rights.h",
-      "zircon/syscalls.abigen",
-      "zircon/syscalls.h",
-      "zircon/syscalls/debug.h",
-      "zircon/syscalls/exception.h",
-      "zircon/syscalls/hypervisor.h",
-      "zircon/syscalls/iommu.h",
-      "zircon/syscalls/log.h",
-      "zircon/syscalls/object.h",
-      "zircon/syscalls/pci.h",
-      "zircon/syscalls/policy.h",
-      "zircon/syscalls/port.h",
-      "zircon/syscalls/profile.h",
-      "zircon/syscalls/resource.h",
-      "zircon/syscalls/smc.h",
-      "zircon/syscalls/system.h",
-      "zircon/syscalls/types.h",
-      "zircon/time.h",
-      "zircon/tls.h",
-      "zircon/types.h",
-    ]
-    foreach(file, public_headers) {
-      contents += [ "$file=SOURCE/system/public/$file" ]
-    }
-
-    vdso_headers = [
-      "zircon/syscalls/definitions.h",
-      "zircon/syscalls/definitions.rs",
-    ]
-    foreach(file, vdso_headers) {
-      contents += [ "$file=BUILD/" +
-                    rebase_path("$root_gen_dir/$file", root_build_dir) ]
-    }
-    contents +=
-        [ "zircon/status.h=SOURCE/system/ulib/zircon/include/zircon/status.h" ]
-
-    contents += [ "[lib]" ]
-
-    debug_libs = [
-      "$target_out_dir/libc.so",
-      get_label_info("$zx/system/ulib/zircon", "target_out_dir") +
-          "/libzircon.so",
-    ]
-    foreach(lib, debug_libs) {
-      contents += [
-        "debug/" + get_path_info(lib, "file") + "=BUILD/" +
-            rebase_path("$lib.debug", root_build_dir),
-        "lib/" + get_path_info(lib, "file") + "=BUILD/" +
-            rebase_path("$lib.debug", root_build_dir),
-      ]
-    }
-
-    dummy_libs = [
-      "libdl.so",
-      "libm.so",
-      "libpthread.so",
-      "librt.so",
-    ]
-    foreach(lib, dummy_libs) {
-      contents += [ "lib/$lib=SOURCE/third_party/ulib/musl/lib.ld" ]
-    }
 
-    contents += [
-      "lib/Scrt1.o=BUILD/" +
-          rebase_path(get_label_info(":crt1(${toolchain.label})",
-                                     "target_out_dir") + "/crt1.Scrt1.cpp.o",
-                      root_build_dir),
-      "dist/lib/ld.so.1=BUILD/" +
-          rebase_path("$target_out_dir/libc.so", root_build_dir),
+  # TODO(BLD-353): temporary kludges
+  metadata = {
+    legacy_sysroot = [
+      {
+        crt1 = rebase_path("$target_out_dir/crt1.Scrt1.cpp.o", root_build_dir)
+        sdk = {
+          source = crt1
+          link = "lib/Scrt1.o"
+        }
+      },
     ]
   }
 }
diff --git a/zircon/system/ulib/zircon/BUILD.gn b/zircon/system/ulib/zircon/BUILD.gn
index 708f3604edd390adf95a14405ddc8e491639a468..6036a36cf75085684841ffec65988116ec6fa96e 100644
--- a/zircon/system/ulib/zircon/BUILD.gn
+++ b/zircon/system/ulib/zircon/BUILD.gn
@@ -77,8 +77,50 @@ if (toolchain.tags + exclude_tags - exclude_tags != toolchain.tags ||
     # This doesn't get normal default deps on libc.
     no_implicit_deps = true
 
+    # TODO(BLD-353): The SDK exports this as part of the sysroot rather
+    # than as an independent library.  Legacy integration likewise does not
+    # use a //zircon/public/lib/zircon buts instead uses libs=["zircon"].
+    # See //zircon/public/sysroot.
     metadata = {
-      # TODO(BLD-353): This is not actually for the SDK.
+      legacy_sysroot = [
+        {
+          include_dirs = rebase_path([
+                                       "include",
+                                       root_gen_dir,
+                                     ],
+                                     root_build_dir)
+        },
+        {
+          sdk = {
+            include_dir = rebase_path(root_gen_dir, root_build_dir)
+            headers = [
+              "zircon/syscalls/definitions.h",
+              # Note not included in SDK: "zircon/syscalls/definitions.rs",
+            ]
+          }
+        },
+        {
+          sdk = {
+            include_dir = rebase_path("include", root_build_dir)
+            headers = [ "zircon/status.h" ]
+          }
+        },
+        {
+          sdk = {
+            source = rebase_path("$target_out_dir/libzircon.so", root_build_dir)
+            link = "lib/libzircon.so"
+          }
+        },
+        {
+          sdk = {
+            source = rebase_path("$target_out_dir/libzircon.so.debug",
+                                 root_build_dir)
+            debug = "debug/libzircon.so"
+          }
+        },
+      ]
+
+      # TODO(BLD-353): This is not actually for the SDK (see above).
       # This is special-cased so no //zircon/public/lib/zircon gets
       # made, but //build/config/fuchsia:compiler_sysroot can look up
       # the metadata to find the right lib_dirs.