build = async (configPath, options = {}) => {
  const { skipBundle, skipNpmInstall, silent, clean } = options;

  if (!silent) info(`Compiling from "${configPath}"`);

  const config = getPackageConfig(configPath);
  const target = getBuildTarget(configPath, config);
  const destination = getDestinationFromConfig(configPath, config);
  const sourceDir = getSourceFromConfig(configPath, config);

  const cacheDir = join(destination, ".clio", "cache");
  const modulesDir = join(sourceDir, MODULES_PATH);
  const modulesDestDir = join(destination, MODULES_PATH);

  if (!silent) info(`Creating build for target "${target}"`);

  if (clean && existsSync(destination)) {
    if (!silent) info(`Wiping the build directory`);
    rmSync(destination, { recursive: true });
  }

  const progress = new Progress(silent);
  progress.start("Compiling from source...");

  const result = await asyncCompile(
    "main.clio",
    config,
    configPath,
    modulesDir,
    modulesDestDir,
    dirname(configPath),
    "",
    "",
    cacheDir,
    { configs: {}, npmDeps: {}, npmDevDeps: {} }
  ).catch((compileError) => {
    progress.fail();
    console.error(compileError.message);
    process.exit(1);
  });

  progress.succeed();

  try {
    // Copy resources
    progress.start("Copying over the resource files...");
    const nonClioFiles = getNonClioFiles(sourceDir);
    for (const file of nonClioFiles) {
      const relativeFile = relative(sourceDir, file);
      const destFile = join(destination, relativeFile);
      const destDir = dirname(destFile);
      mkdir(destDir);
      await promises.copyFile(file, destFile);
    }
    progress.succeed();

    // Add index.js file
    progress.start("Adding Clio start script...");
    mkdir(join(destination, ".clio"));
    makeStartScript(config, target, destination);
    progress.succeed();

    const { npmDeps } = result;

    const depsNpmDependencies = Object.values(npmDeps).reduce(
      (lhs, rhs) => ({ ...lhs, ...rhs }),
      {}
    );

    // Init npm modules
    try {
      const packageJsonPath = join(destination, "package.json");
      const dependencies = getParsedNpmDependencies(configPath);

      const devDependencies = getParsedNpmDevDependencies(configPath);
      dependencies["clio-run"] = "latest";
      const packageInfo = {};
      if (config.keywords) packageInfo.keywords = config.keywords;
      if (config.authors) packageInfo.authors = config.authors;
      const packageJsonContent = {
        ...packageInfo,
        main: "./main.clio.js",
        type: "module",
        dependencies: { ...depsNpmDependencies, ...dependencies },
        devDependencies,
        ...config.npmOverride,
      };
      writeFileSync(
        packageJsonPath,
        JSON.stringify(packageJsonContent, null, 2),
        { flag: "w" }
      );
    } catch (e) {
      progress.fail(`Error: ${e.message}`);
      error(e, "Dependency Install");
    }
  } catch (e) {
    progress.fail(`Error: ${e}`);
    error(e, "Compilation");
  }

  if (!skipNpmInstall) {
    progress.start("Installing npm dependencies (this may take a while)...");
    await fetchNpmDependencies(destination, silent);
    progress.succeed();
  }

  if (process.env.CLIOPATH) {
    // Link local internals
    warn("Using local internals. This should only be used for debug purposes.");
    warn(
      "If you encounter any unwanted behavior, unset the CLIOPATH environment variable"
    );
    progress.succeed();
    progress.start("Linking dependencies");

    // Install third party dependencies
    const install = (...names) =>
      names.forEach((name) => installExternal(name, destination));

    install("sializer", "buffer", "bufferutil", "ws");

    // Link local dependencies
    const linkToDest = (name, internalName, unlinks) =>
      link(name, internalName, destination, unlinks);

    await linkToDest("clio-run", "run", ["clio-lang-internals", "clio-rpc"]);
    await linkToDest("clio-rpc", "rpc", ["clio-lang-internals"]);
    await linkToDest("clio-lang-internals", "internals");

    progress.succeed();
  }

  try {
    const platform = getPlatform(target);
    await platform.build(destination, skipBundle);
  } catch (e) {
    error(e, "Bundling");
  }
}
@param {string} configPath Path to the project config file
@param {Object} options Options to build