diff --git a/README.md b/README.md
index f4016073fdf0c5a19646f89761efc6c06978a96c..fd1b689cdec50046fe911dfd96ec446bf62f6d1d 100644
--- a/README.md
+++ b/README.md
@@ -14,8 +14,9 @@ Instructions for a Debian based distribution:
 
 You'll want to download some pre-requisite packages as well. If you're currently
 configured for AOSP development, you should have most required packages.
-Otherwise, you can use the following apt-get list or use the bootstrap script
-(see below) to get a list of packages missing on your system:
+Otherwise, you can use the following apt-get list or use the `--run-bootstrap`
+option on `build.py` (see below) to get a list of packages missing on your
+system:
 
 ```sh
 sudo apt-get install repo git-core gnupg flex bison gperf build-essential \
@@ -27,7 +28,7 @@ sudo apt-get install repo git-core gnupg flex bison gperf build-essential \
   libflatbuffers-dev libtinyxml2-dev \
   libglib2.0-dev libevent-dev libnss3-dev libdbus-1-dev \
   libprotobuf-dev ninja-build generate-ninja protobuf-compiler \
-  libre2-9
+  libre2-9 debmake
 ```
 
 You will also need a recent-ish version of Rust and Cargo. Please follow the
@@ -41,18 +42,22 @@ cd ~/fluoride
 git clone https://android.googlesource.com/platform/packages/modules/Bluetooth/system
 ```
 
-### Use bootstrap.py
+### Using --run-bootstrap on build.py
 
-`bootstrap.py` is a helper script provided to set up your build environment. It
-will set up your build staging directory and also make sure you have all
-required system packages to build (should work on Debian and Ubuntu). You will
-still need to build some unpackaged dependencies.
+`build.py` is the helper script used to build Fluoride for Linux (i.e. Floss).
+It accepts a `--run-bootstrap` option that will set up your build staging
+directory and also make sure you have all required system packages to build
+(should work on Debian and Ubuntu). You will still need to build some unpackaged
+dependencies (like libchrome, modp_b64, googletest, etc).
 
 To use it:
 ```sh
-./bootstrap.py --base-dir=path/to/staging/dir --bt-dir=path/to/bt/dir
+./build.py --run-bootstrap
 ```
 
+This will install your bootstrapped build environment to `~/.floss`. If you want
+to change this, just pass in `--bootstrap-dir` to the script.
+
 ### Build dependencies
 
 The following third-party dependencies are necessary but currently unavailable
@@ -104,7 +109,7 @@ done
 
 ### Rust dependencies
 
-**Note**: Handled by bootstrap script.
+**Note**: Handled by `--run-bootstrap` option.
 
 Run the following to install Rust dependencies:
 ```
@@ -113,7 +118,7 @@ cargo install cxxbridge-cmd
 
 ### Stage your build environment
 
-**Note**: Handled by bootstrap script.
+**Note**: Handled by `--run-bootstrap` option.
 
 For host build, we depend on a few other repositories:
 * [Platform2](https://chromium.googlesource.com/chromiumos/platform2/)
@@ -135,17 +140,18 @@ ln -s $(readlink -f ${PROTO_LOG_DIR}) ${STAGING_DIR}/external/proto_logging
 
 We provide a build script to automate building assuming you've staged your build
 environment already as above. At this point, make sure you have all the
-pre-requisites installed (i.e. bootstrap script and other dependencies above) or
+pre-requisites installed (i.e. bootstrap option and other dependencies above) or
 you will see failures. In addition, you may need to set a `--libdir=` if your
-libraries are not stored in `/usr/lib64` by default.
+libraries are not stored in `/usr/lib` by default.
 
 
 ```sh
-./build.py --output ${OUTPUT_DIR} --platform-dir ${STAGING_DIR} --clang
+./build.py
 ```
 
-This will build all targets to the output directory you've given. You can also
-build each stage separately (if you want to iterate on something specific):
+This will build all targets to the output directory at `--bootstrap-dir` (which
+defaults to `~/.floss`). You can also build each stage separately (if you want
+to iterate on something specific):
 
 * prepare - Generate the GN rules
 * tools - Generate host tools
@@ -157,7 +163,10 @@ build each stage separately (if you want to iterate on something specific):
 You can choose to run only a specific stage by passing an arg via `--target`.
 
 Currently, Rust builds are a separate stage that uses Cargo to build. See
-[gd/rust/README.md](gd/rust/README.md) for more information.
+[gd/rust/README.md](gd/rust/README.md) for more information. If you are
+iterating on Rust code and want to add new crates, you may also want to use the
+`--no-vendored-rust` option (which will let you use crates.io instead of using
+a pre-populated vendored crates repo).
 
 ### Run
 
diff --git a/bootstrap.py b/bootstrap.py
deleted file mode 100755
index c7c04bfd7555ea85f6a285ead2c956303ad08461..0000000000000000000000000000000000000000
--- a/bootstrap.py
+++ /dev/null
@@ -1,243 +0,0 @@
-#!/usr/bin/env python3
-
-#  Copyright 2021 Google, Inc.
-#
-#  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:
-#
-#  http://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.
-""" Bootstrap script to help set up Linux build. """
-
-import argparse
-import os
-import subprocess
-
-PLATFORM2_GIT = 'https://chromium.googlesource.com/chromiumos/platform2'
-RUST_CRATES_GIT = 'https://chromium.googlesource.com/chromiumos/third_party/rust_crates'
-PROTO_LOGGING_GIT = 'https://android.googlesource.com/platform/frameworks/proto_logging'
-
-# List of packages required for linux build
-REQUIRED_APT_PACKAGES = [
-    'bison',
-    'build-essential',
-    'curl',
-    'flatbuffers-compiler',
-    'flex',
-    'g++-multilib',
-    'gcc-multilib',
-    'generate-ninja',
-    'gnupg',
-    'gperf',
-    'libc++-dev',
-    'libdbus-1-dev',
-    'libevent-dev',
-    'libevent-dev',
-    'libflatbuffers-dev',
-    'libflatbuffers1',
-    'libgl1-mesa-dev',
-    'libglib2.0-dev',
-    'liblz4-tool',
-    'libncurses5',
-    'libnss3-dev',
-    'libprotobuf-dev',
-    'libre2-9',
-    'libssl-dev',
-    'libtinyxml2-dev',
-    'libx11-dev',
-    'libxml2-utils',
-    'ninja-build',
-    'openssl',
-    'protobuf-compiler',
-    'unzip',
-    'x11proto-core-dev',
-    'xsltproc',
-    'zip',
-    'zlib1g-dev',
-]
-
-# List of cargo packages required for linux build
-REQUIRED_CARGO_PACKAGES = ['cxxbridge-cmd']
-
-APT_PKG_LIST = ['apt', '-qq', 'list']
-CARGO_PKG_LIST = ['cargo', 'install', '--list']
-
-
-class Bootstrap():
-
-    def __init__(self, base_dir, bt_dir):
-        """ Construct bootstrapper.
-
-        Args:
-            base_dir: Where to stage everything.
-            bt_dir: Where bluetooth source is kept (will be symlinked)
-        """
-        self.base_dir = os.path.abspath(base_dir)
-        self.bt_dir = os.path.abspath(bt_dir)
-
-        if not os.path.isdir(self.base_dir):
-            raise Exception('{} is not a valid directory'.format(self.base_dir))
-
-        if not os.path.isdir(self.bt_dir):
-            raise Exception('{} is not a valid directory'.format(self.bt_dir))
-
-        self.git_dir = os.path.join(self.base_dir, 'repos')
-        self.staging_dir = os.path.join(self.base_dir, 'staging')
-        self.output_dir = os.path.join(self.base_dir, 'output')
-        self.external_dir = os.path.join(self.base_dir, 'staging', 'external')
-
-        self.dir_setup_complete = os.path.join(self.base_dir, '.setup-complete')
-
-    def _setup_platform2(self):
-        """ Set up platform2.
-
-        This will check out all the git repos and symlink everything correctly.
-        """
-
-        # If already set up, exit early
-        if os.path.isfile(self.dir_setup_complete):
-            print('{} is already set-up'.format(self.base_dir))
-            return
-
-        # Create all directories we will need to use
-        for dirpath in [self.git_dir, self.staging_dir, self.output_dir, self.external_dir]:
-            os.makedirs(dirpath)
-
-        # Check out all repos in git directory
-        for repo in [PLATFORM2_GIT, RUST_CRATES_GIT, PROTO_LOGGING_GIT]:
-            subprocess.check_call(['git', 'clone', repo], cwd=self.git_dir)
-
-        # Symlink things
-        symlinks = [
-            (os.path.join(self.git_dir, 'platform2', 'common-mk'), os.path.join(self.staging_dir, 'common-mk')),
-            (os.path.join(self.git_dir, 'platform2', '.gn'), os.path.join(self.staging_dir, '.gn')),
-            (os.path.join(self.bt_dir), os.path.join(self.staging_dir, 'bt')),
-            (os.path.join(self.git_dir, 'rust_crates'), os.path.join(self.external_dir, 'rust')),
-            (os.path.join(self.git_dir, 'proto_logging'), os.path.join(self.external_dir, 'proto_logging')),
-        ]
-
-        # Create symlinks
-        for pairs in symlinks:
-            (src, dst) = pairs
-            os.symlink(src, dst)
-
-        # Write to setup complete file so we don't repeat this step
-        with open(self.dir_setup_complete, 'w') as f:
-            f.write('Setup complete.')
-
-    def _pretty_print_install(self, install_cmd, packages, line_limit=80):
-        """ Pretty print an install command.
-
-        Args:
-            install_cmd: Prefixed install command.
-            packages: Enumerate packages and append them to install command.
-            line_limit: Number of characters per line.
-
-        Return:
-            Array of lines to join and print.
-        """
-        install = [install_cmd]
-        line = '  '
-        # Remainder needed = space + len(pkg) + space + \
-        # Assuming 80 character lines, that's 80 - 3 = 77
-        line_limit = line_limit - 3
-        for pkg in packages:
-            if len(line) + len(pkg) < line_limit:
-                line = '{}{} '.format(line, pkg)
-            else:
-                install.append(line)
-                line = '  {} '.format(pkg)
-
-        if len(line) > 0:
-            install.append(line)
-
-        return install
-
-    def _check_package_installed(self, package, cmd, predicate):
-        """Check that the given package is installed.
-
-        Args:
-            package: Check that this package is installed.
-            cmd: Command prefix to check if installed (package appended to end)
-            predicate: Function/lambda to check if package is installed based
-                       on output. Takes string output and returns boolean.
-
-        Return:
-            True if package is installed.
-        """
-        try:
-            output = subprocess.check_output(cmd + [package], stderr=subprocess.STDOUT)
-            is_installed = predicate(output.decode('utf-8'))
-            print('  {} is {}'.format(package, 'installed' if is_installed else 'missing'))
-
-            return is_installed
-        except Exception as e:
-            print(e)
-            return False
-
-    def _print_missing_packages(self):
-        """Print any missing packages found via apt.
-
-        This will find any missing packages necessary for build using apt and
-        print it out as an apt-get install printf.
-        """
-        print('Checking for any missing packages...')
-        need_packages = []
-        for pkg in REQUIRED_APT_PACKAGES:
-            if not self._check_package_installed(pkg, APT_PKG_LIST, lambda output: 'installed' in output):
-                need_packages.append(pkg)
-
-        # No packages need to be installed
-        if len(need_packages) == 0:
-            print('All required packages are installed')
-            return
-
-        install = self._pretty_print_install('sudo apt-get install', need_packages)
-
-        # Print all lines so they can be run in cmdline
-        print('Missing system packages. Run the following command: ')
-        print(' \\\n'.join(install))
-
-    def _print_missing_rust_packages(self):
-        """Print any missing packages found via cargo.
-
-        This will find any missing packages necessary for build using cargo and
-        print it out as a cargo-install printf.
-        """
-        print('Checking for any missing cargo packages...')
-        need_packages = []
-
-        for pkg in REQUIRED_CARGO_PACKAGES:
-            if not self._check_package_installed(pkg, CARGO_PKG_LIST, lambda output: pkg in output):
-                need_packages.append(pkg)
-
-        # No packages to be installed
-        if len(need_packages) == 0:
-            print('All required cargo packages are installed')
-            return
-
-        install = self._pretty_print_install('cargo install', need_packages)
-        print('Missing cargo packages. Run the following command: ')
-        print(' \\\n'.join(install))
-
-    def bootstrap(self):
-        """ Bootstrap the Linux build."""
-        self._setup_platform2()
-        self._print_missing_packages()
-        self._print_missing_rust_packages()
-
-
-if __name__ == '__main__':
-    parser = argparse.ArgumentParser(description='Bootstrap Linux build')
-    parser.add_argument('--base-dir', help='Where to create build directories.', required=True)
-    parser.add_argument('--bt-dir', help='Path to packages/modules/Bluetooth/system', required=True)
-
-    args = parser.parse_args()
-    bootstrap = Bootstrap(args.base_dir, args.bt_dir)
-    bootstrap.bootstrap()
diff --git a/build.py b/build.py
index 8613315a088079bb0652ed05bf8412c120c67ced..3a2f72fb8001d36c16a700ae81dff7a78f89aae6 100755
--- a/build.py
+++ b/build.py
@@ -77,6 +77,58 @@ HOST_TESTS = [
     # 'net_test_btpackets',
 ]
 
+BOOTSTRAP_GIT_REPOS = {
+    'platform2': 'https://chromium.googlesource.com/chromiumos/platform2',
+    'rust_crates': 'https://chromium.googlesource.com/chromiumos/third_party/rust_crates',
+    'proto_logging': 'https://android.googlesource.com/platform/frameworks/proto_logging'
+}
+
+# List of packages required for linux build
+REQUIRED_APT_PACKAGES = [
+    'bison',
+    'build-essential',
+    'curl',
+    'debmake',
+    'flatbuffers-compiler',
+    'flex',
+    'g++-multilib',
+    'gcc-multilib',
+    'generate-ninja',
+    'gnupg',
+    'gperf',
+    'libc++-dev',
+    'libdbus-1-dev',
+    'libevent-dev',
+    'libevent-dev',
+    'libflatbuffers-dev',
+    'libflatbuffers1',
+    'libgl1-mesa-dev',
+    'libglib2.0-dev',
+    'liblz4-tool',
+    'libncurses5',
+    'libnss3-dev',
+    'libprotobuf-dev',
+    'libre2-9',
+    'libssl-dev',
+    'libtinyxml2-dev',
+    'libx11-dev',
+    'libxml2-utils',
+    'ninja-build',
+    'openssl',
+    'protobuf-compiler',
+    'unzip',
+    'x11proto-core-dev',
+    'xsltproc',
+    'zip',
+    'zlib1g-dev',
+]
+
+# List of cargo packages required for linux build
+REQUIRED_CARGO_PACKAGES = ['cxxbridge-cmd']
+
+APT_PKG_LIST = ['apt', '-qq', 'list']
+CARGO_PKG_LIST = ['cargo', 'install', '--list']
+
 
 class UseFlags():
 
@@ -123,11 +175,14 @@ class HostBuild():
             self.jobs = multiprocessing.cpu_count()
             print("Number of jobs = {}".format(self.jobs))
 
-        # Normalize all directories
-        self.output_dir = os.path.abspath(self.args.output)
-        self.platform_dir = os.path.abspath(self.args.platform_dir)
+        # Normalize bootstrap dir and make sure it exists
+        self.bootstrap_dir = os.path.abspath(self.args.bootstrap_dir)
+        os.makedirs(self.bootstrap_dir, exist_ok=True)
+
+        # Output and platform directories are based on bootstrap
+        self.output_dir = os.path.join(self.bootstrap_dir, 'output')
+        self.platform_dir = os.path.join(self.bootstrap_dir, 'staging')
         self.sysroot = self.args.sysroot
-        self.use_board = os.path.abspath(self.args.use_board) if self.args.use_board else None
         self.libdir = self.args.libdir
 
         # If default target isn't set, build everything
@@ -183,16 +238,6 @@ class HostBuild():
         self.env['RUSTFLAGS'] = self._generate_rustflags()
         self.env['CXX_ROOT_PATH'] = os.path.join(self.platform_dir, 'bt')
 
-        # Configure some GN variables
-        if self.use_board:
-            self.env['PKG_CONFIG_PATH'] = os.path.join(self.use_board, self.libdir, 'pkgconfig')
-            libdir = os.path.join(self.use_board, self.libdir)
-            if self.env.get('LIBRARY_PATH'):
-                libpath = self.env['LIBRARY_PATH']
-                self.env['LIBRARY_PATH'] = '{}:{}'.format(libdir, libpath)
-            else:
-                self.env['LIBRARY_PATH'] = libdir
-
     def run_command(self, target, args, cwd=None, env=None):
         """ Run command and stream the output.
         """
@@ -243,7 +288,7 @@ class HostBuild():
 
         Mostly copied from //common-mk/platform2.py
         """
-        clang = self.args.clang
+        clang = not self.args.no_clang
 
         def to_gn_string(s):
             return '"%s"' % s.replace('"', '\\"')
@@ -288,20 +333,6 @@ class HostBuild():
             self.use.set_flag('clang', True)
             gn_args['external_cxxflags'] += ['-I/usr/include/']
 
-        # EXTREME HACK ALERT
-        #
-        # In my laziness, I am supporting building against an already built
-        # sysroot path (i.e. chromeos board) so that I don't have to build
-        # libchrome or modp_b64 locally.
-        if self.use_board:
-            includedir = os.path.join(self.use_board, 'usr/include')
-            gn_args['external_cxxflags'] += [
-                '-I{}'.format(includedir),
-                '-I{}/libchrome'.format(includedir),
-                '-I{}/gtest'.format(includedir),
-                '-I{}/gmock'.format(includedir),
-                '-I{}/modp_b64'.format(includedir),
-            ]
         gn_args_args = list(to_gn_args_args(gn_args))
         use_args = ['%s=%s' % (k, str(v).lower()) for k, v in self.use.flags.items()]
         gn_args_args += ['use={%s}' % (' '.join(use_args))]
@@ -351,7 +382,7 @@ class HostBuild():
         local-registry = "/nonexistent"
         """
 
-        if self.args.vendored_rust:
+        if not self.args.no_vendored_rust:
             contents = template.format(self.platform_dir)
             with open(os.path.join(self.env['CARGO_HOME'], 'config'), 'w') as f:
                 f.write(contents)
@@ -410,6 +441,8 @@ class HostBuild():
         """ Delete the output directory entirely.
         """
         shutil.rmtree(self.output_dir)
+        # Remove Cargo.lock that may have become generated
+        os.remove(os.path.join(self.platform_dir, 'bt', 'Cargo.lock'))
 
     def _target_all(self):
         """ Build all common targets (skipping test and clean).
@@ -440,21 +473,247 @@ class HostBuild():
             self._target_all()
 
 
+class Bootstrap():
+
+    def __init__(self, base_dir, bt_dir):
+        """ Construct bootstrapper.
+
+        Args:
+            base_dir: Where to stage everything.
+            bt_dir: Where bluetooth source is kept (will be symlinked)
+        """
+        self.base_dir = os.path.abspath(base_dir)
+        self.bt_dir = os.path.abspath(bt_dir)
+
+        # Create base directory if it doesn't already exist
+        os.makedirs(self.base_dir, exist_ok=True)
+
+        if not os.path.isdir(self.bt_dir):
+            raise Exception('{} is not a valid directory'.format(self.bt_dir))
+
+        self.git_dir = os.path.join(self.base_dir, 'repos')
+        self.staging_dir = os.path.join(self.base_dir, 'staging')
+        self.output_dir = os.path.join(self.base_dir, 'output')
+        self.external_dir = os.path.join(self.base_dir, 'staging', 'external')
+
+        self.dir_setup_complete = os.path.join(self.base_dir, '.setup-complete')
+
+    def _update_platform2(self):
+        """Updates repositories used for build."""
+        for repo in BOOTSTRAP_GIT_REPOS.keys():
+            cwd = os.path.join(self.git_dir, repo)
+            subprocess.check_call(['git', 'pull'], cwd=cwd)
+
+    def _setup_platform2(self):
+        """ Set up platform2.
+
+        This will check out all the git repos and symlink everything correctly.
+        """
+
+        # If already set up, exit early
+        if os.path.isfile(self.dir_setup_complete):
+            print('{} already set-up. Updating instead.'.format(self.base_dir))
+            self._update_platform2()
+            return
+
+        # Create all directories we will need to use
+        for dirpath in [self.git_dir, self.staging_dir, self.output_dir, self.external_dir]:
+            os.makedirs(dirpath)
+
+        # Check out all repos in git directory
+        for repo in BOOTSTRAP_GIT_REPOS.values():
+            subprocess.check_call(['git', 'clone', repo], cwd=self.git_dir)
+
+        # Symlink things
+        symlinks = [
+            (os.path.join(self.git_dir, 'platform2', 'common-mk'), os.path.join(self.staging_dir, 'common-mk')),
+            (os.path.join(self.git_dir, 'platform2', '.gn'), os.path.join(self.staging_dir, '.gn')),
+            (os.path.join(self.bt_dir), os.path.join(self.staging_dir, 'bt')),
+            (os.path.join(self.git_dir, 'rust_crates'), os.path.join(self.external_dir, 'rust')),
+            (os.path.join(self.git_dir, 'proto_logging'), os.path.join(self.external_dir, 'proto_logging')),
+        ]
+
+        # Create symlinks
+        for pairs in symlinks:
+            (src, dst) = pairs
+            os.symlink(src, dst)
+
+        # Write to setup complete file so we don't repeat this step
+        with open(self.dir_setup_complete, 'w') as f:
+            f.write('Setup complete.')
+
+    def _pretty_print_install(self, install_cmd, packages, line_limit=80):
+        """ Pretty print an install command.
+
+        Args:
+            install_cmd: Prefixed install command.
+            packages: Enumerate packages and append them to install command.
+            line_limit: Number of characters per line.
+
+        Return:
+            Array of lines to join and print.
+        """
+        install = [install_cmd]
+        line = '  '
+        # Remainder needed = space + len(pkg) + space + \
+        # Assuming 80 character lines, that's 80 - 3 = 77
+        line_limit = line_limit - 3
+        for pkg in packages:
+            if len(line) + len(pkg) < line_limit:
+                line = '{}{} '.format(line, pkg)
+            else:
+                install.append(line)
+                line = '  {} '.format(pkg)
+
+        if len(line) > 0:
+            install.append(line)
+
+        return install
+
+    def _check_package_installed(self, package, cmd, predicate):
+        """Check that the given package is installed.
+
+        Args:
+            package: Check that this package is installed.
+            cmd: Command prefix to check if installed (package appended to end)
+            predicate: Function/lambda to check if package is installed based
+                       on output. Takes string output and returns boolean.
+
+        Return:
+            True if package is installed.
+        """
+        try:
+            output = subprocess.check_output(cmd + [package], stderr=subprocess.STDOUT)
+            is_installed = predicate(output.decode('utf-8'))
+            print('  {} is {}'.format(package, 'installed' if is_installed else 'missing'))
+
+            return is_installed
+        except Exception as e:
+            print(e)
+            return False
+
+    def _get_command_output(self, cmd):
+        """Runs the command and gets the output.
+
+        Args:
+            cmd: Command to run.
+
+        Return:
+            Tuple (Success, Output). Success represents if the command ran ok.
+        """
+        try:
+            output = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
+            return (True, output.decode('utf-8').split('\n'))
+        except Exception as e:
+            print(e)
+            return (False, "")
+
+    def _print_missing_packages(self):
+        """Print any missing packages found via apt.
+
+        This will find any missing packages necessary for build using apt and
+        print it out as an apt-get install printf.
+        """
+        print('Checking for any missing packages...')
+
+        (success, output) = self._get_command_output(APT_PKG_LIST)
+        if not success:
+            raise Exception("Could not query apt for packages.")
+
+        packages_installed = {}
+        for line in output:
+            if 'installed' in line:
+                split = line.split('/', 2)
+                packages_installed[split[0]] = True
+
+        need_packages = []
+        for pkg in REQUIRED_APT_PACKAGES:
+            if pkg not in packages_installed:
+                need_packages.append(pkg)
+
+        # No packages need to be installed
+        if len(need_packages) == 0:
+            print('+ All required packages are installed')
+            return
+
+        install = self._pretty_print_install('sudo apt-get install', need_packages)
+
+        # Print all lines so they can be run in cmdline
+        print('Missing system packages. Run the following command: ')
+        print(' \\\n'.join(install))
+
+    def _print_missing_rust_packages(self):
+        """Print any missing packages found via cargo.
+
+        This will find any missing packages necessary for build using cargo and
+        print it out as a cargo-install printf.
+        """
+        print('Checking for any missing cargo packages...')
+
+        (success, output) = self._get_command_output(CARGO_PKG_LIST)
+        if not success:
+            raise Exception("Could not query cargo for packages.")
+
+        packages_installed = {}
+        for line in output:
+            # Cargo installed packages have this format
+            # <crate name> <version>:
+            #   <binary name>
+            # We only care about the crates themselves
+            if ':' not in line:
+                continue
+
+            split = line.split(' ', 2)
+            packages_installed[split[0]] = True
+
+        need_packages = []
+        for pkg in REQUIRED_CARGO_PACKAGES:
+            if pkg not in packages_installed:
+                need_packages.append(pkg)
+
+        # No packages to be installed
+        if len(need_packages) == 0:
+            print('+ All required cargo packages are installed')
+            return
+
+        install = self._pretty_print_install('cargo install', need_packages)
+        print('Missing cargo packages. Run the following command: ')
+        print(' \\\n'.join(install))
+
+    def bootstrap(self):
+        """ Bootstrap the Linux build."""
+        self._setup_platform2()
+        self._print_missing_packages()
+        self._print_missing_rust_packages()
+
+
 if __name__ == '__main__':
     parser = argparse.ArgumentParser(description='Simple build for host.')
-    parser.add_argument('--output', help='Output directory for the build.', required=True)
-    parser.add_argument('--platform-dir', help='Directory where platform2 is staged.', required=True)
-    parser.add_argument('--clang', help='Use clang compiler.', default=False, action='store_true')
+    parser.add_argument(
+        '--bootstrap-dir', help='Directory to run bootstrap on (or was previously run on).', default="~/.floss")
+    parser.add_argument(
+        '--run-bootstrap',
+        help='Run bootstrap code to verify build env is ok to build.',
+        default=False,
+        action='store_true')
+    parser.add_argument('--no-clang', help='Use clang compiler.', default=False, action='store_true')
     parser.add_argument('--use', help='Set a specific use flag.')
     parser.add_argument('--notest', help="Don't compile test code.", default=False, action='store_true')
     parser.add_argument('--target', help='Run specific build target')
     parser.add_argument('--sysroot', help='Set a specific sysroot path', default='/')
-    parser.add_argument('--libdir', help='Libdir - default = usr/lib64', default='usr/lib64')
-    parser.add_argument('--use-board', help='Use a built x86 board for dependencies. Provide path.')
+    parser.add_argument('--libdir', help='Libdir - default = usr/lib', default='usr/lib')
     parser.add_argument('--jobs', help='Number of jobs to run', default=0, type=int)
-    parser.add_argument('--vendored-rust', help='Use vendored rust crates', default=False, action='store_true')
+    parser.add_argument(
+        '--no-vendored-rust', help='Do not use vendored rust crates', default=False, action='store_true')
     parser.add_argument('--verbose', help='Verbose logs for build.')
-
     args = parser.parse_args()
-    build = HostBuild(args)
-    build.build()
+
+    # Make sure we get absolute path + expanded path for bootstrap directory
+    args.bootstrap_dir = os.path.abspath(os.path.expanduser(args.bootstrap_dir))
+
+    if args.run_bootstrap:
+        bootstrap = Bootstrap(args.bootstrap_dir, os.path.dirname(__file__))
+        bootstrap.bootstrap()
+    else:
+        build = HostBuild(args)
+        build.build()