func writePrototypes(pkgs []*pkg.LocalPackage, w io.Writer) {
	sorted := pkg.SortLclPkgs(pkgs)
	fmt.Fprintf(w, "void os_init(void);\n")
	for _, p := range sorted {
		fmt.Fprintf(w, "void %s(void);\n", p.InitFnName())
	}
}
func writeStage(stage int, pkgs []*pkg.LocalPackage, w io.Writer) {
	sorted := pkg.SortLclPkgs(pkgs)

	fmt.Fprintf(w, "    /*** Stage %d */\n", stage)
	for i, p := range sorted {
		fmt.Fprintf(w, "    /* %d.%d: %s */\n", stage, i, p.Name())
		fmt.Fprintf(w, "    %s();\n", p.InitFnName())
	}
}
func categorizePkgs(
	lpkgs []*pkg.LocalPackage) map[interfaces.PackageType][]*pkg.LocalPackage {

	pmap := map[interfaces.PackageType][]*pkg.LocalPackage{
		pkg.PACKAGE_TYPE_TARGET:   []*pkg.LocalPackage{},
		pkg.PACKAGE_TYPE_APP:      []*pkg.LocalPackage{},
		pkg.PACKAGE_TYPE_UNITTEST: []*pkg.LocalPackage{},
		pkg.PACKAGE_TYPE_BSP:      []*pkg.LocalPackage{},
		pkg.PACKAGE_TYPE_LIB:      []*pkg.LocalPackage{},
	}

	for _, lpkg := range lpkgs {
		typ := normalizePkgType(lpkg.Type())
		pmap[typ] = append(pmap[typ], lpkg)
	}

	for k, v := range pmap {
		pmap[k] = pkg.SortLclPkgs(v)
	}

	return pmap
}
func testRunCmd(cmd *cobra.Command, args []string) {
	if len(args) < 1 {
		NewtUsage(cmd, nil)
	}

	proj := InitProject()

	// Verify and resolve each specified package.
	testAll := false
	packs := []*pkg.LocalPackage{}
	for _, pkgName := range args {
		if pkgName == "all" {
			testAll = true
		} else {
			pack, err := proj.ResolvePackage(proj.LocalRepo(), pkgName)
			if err != nil {
				NewtUsage(cmd, err)
			}

			testPkgs := pkgToUnitTests(pack)
			if len(testPkgs) == 0 {
				NewtUsage(nil, util.FmtNewtError("Package %s contains no "+
					"unit tests", pack.FullName()))
			}

			packs = append(packs, testPkgs...)
		}
	}

	if testAll {
		packItfs := proj.PackagesOfType(pkg.PACKAGE_TYPE_UNITTEST)
		packs = make([]*pkg.LocalPackage, len(packItfs))
		for i, p := range packItfs {
			packs[i] = p.(*pkg.LocalPackage)
		}

		packs = pkg.SortLclPkgs(packs)
	}

	if len(packs) == 0 {
		NewtUsage(nil, util.NewNewtError("No testable packages found"))
	}

	passedPkgs := []*pkg.LocalPackage{}
	failedPkgs := []*pkg.LocalPackage{}
	for _, pack := range packs {
		// Reset the global state for the next test.
		if err := ResetGlobalState(); err != nil {
			NewtUsage(nil, err)
		}

		// Each unit test package gets its own target.  This target is a copy
		// of the base unit test package, just with an appropriate name.  The
		// reason each test needs a unique target is: syscfg and sysinit are
		// target-specific.  If each test package shares a target, they will
		// overwrite these generated headers each time they are run.  Worse, if
		// two tests are run back-to-back, the timestamps may indicate that the
		// headers have not changed between tests, causing build failures.
		baseTarget := ResolveTarget(TARGET_TEST_NAME)
		if baseTarget == nil {
			NewtUsage(nil, util.NewNewtError("Can't find unit test target: "+
				TARGET_TEST_NAME))
		}

		targetName := fmt.Sprintf("%s/%s/%s",
			TARGET_DEFAULT_DIR, TARGET_TEST_NAME,
			builder.TestTargetName(pack.Name()))

		t := ResolveTarget(targetName)
		if t == nil {
			targetName, err := ResolveNewTargetName(targetName)
			if err != nil {
				NewtUsage(nil, err)
			}

			t = baseTarget.Clone(proj.LocalRepo(), targetName)
		}

		b, err := builder.NewTargetTester(t, pack)
		if err != nil {
			NewtUsage(nil, err)
		}

		util.StatusMessage(util.VERBOSITY_DEFAULT, "Testing package %s\n",
			pack.FullName())

		err = b.Test()
		if err == nil {
			passedPkgs = append(passedPkgs, pack)
		} else {
			newtError := err.(*util.NewtError)
			util.StatusMessage(util.VERBOSITY_QUIET, newtError.Text)
			failedPkgs = append(failedPkgs, pack)
		}
	}

	passStr := fmt.Sprintf("Passed tests: [%s]", PackageNameList(passedPkgs))
	failStr := fmt.Sprintf("Failed tests: [%s]", PackageNameList(failedPkgs))

	if len(failedPkgs) > 0 {
		NewtUsage(nil, util.FmtNewtError("Test failure(s):\n%s\n%s", passStr,
			failStr))
	} else {
		util.StatusMessage(util.VERBOSITY_DEFAULT, "%s\n", passStr)
		util.StatusMessage(util.VERBOSITY_DEFAULT, "All tests passed\n")
	}
}