You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by cc...@apache.org on 2016/10/02 20:42:17 UTC

[1/2] incubator-mynewt-newt git commit: Syscfg / sysinit update

Repository: incubator-mynewt-newt
Updated Branches:
  refs/heads/develop 23179e28e -> dd715c24b


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/dd715c24/newt/pkg/localpackage.go
----------------------------------------------------------------------
diff --git a/newt/pkg/localpackage.go b/newt/pkg/localpackage.go
index 19cd3b1..755a477 100644
--- a/newt/pkg/localpackage.go
+++ b/newt/pkg/localpackage.go
@@ -70,8 +70,11 @@ type LocalPackage struct {
 	// example, SELFTEST gets set when the newt test command is used.
 	injectedSettings map[string]string
 
-	// Pointer to pkg.yml configuration structure
-	Viper *viper.Viper
+	// Settings read from pkg.yml.
+	PkgV *viper.Viper
+
+	// Settings read from syscfg.yml.
+	SyscfgV *viper.Viper
 
 	// Names of all source yml files; used to determine if rebuild required.
 	cfgFilenames []string
@@ -79,9 +82,9 @@ type LocalPackage struct {
 
 func NewLocalPackage(r *repo.Repo, pkgDir string) *LocalPackage {
 	pkg := &LocalPackage{
-		desc: &PackageDesc{},
-		// XXX: Initialize viper object; clients should not need to check for
-		// nil pointer.
+		desc:             &PackageDesc{},
+		PkgV:             viper.New(),
+		SyscfgV:          viper.New(),
 		repo:             r,
 		basePath:         filepath.Clean(pkgDir) + "/", // XXX: Remove slash.
 		injectedSettings: map[string]string{},
@@ -194,8 +197,6 @@ func (pkg *LocalPackage) HasDep(searchDep *Dependency) bool {
 }
 
 func (pkg *LocalPackage) AddDep(dep *Dependency) {
-	// Remember the name of the configuration file so that it can be specified
-	// as a dependency to the compiler.
 	pkg.deps = append(pkg.deps, dep)
 }
 
@@ -217,8 +218,8 @@ func (pkg *LocalPackage) readDesc(v *viper.Viper) (*PackageDesc, error) {
 func (pkg *LocalPackage) sequenceString(key string) string {
 	var buffer bytes.Buffer
 
-	if pkg.Viper != nil {
-		for _, f := range pkg.Viper.GetStringSlice(key) {
+	if pkg.PkgV != nil {
+		for _, f := range pkg.PkgV.GetStringSlice(key) {
 			buffer.WriteString("    - " + yaml.EscapeString(f) + "\n")
 		}
 	}
@@ -276,17 +277,19 @@ func (pkg *LocalPackage) Load() error {
 	// Load configuration
 	log.Debugf("Loading configuration for package %s", pkg.basePath)
 
-	v, err := util.ReadConfig(pkg.basePath,
+	var err error
+
+	pkg.PkgV, err = util.ReadConfig(pkg.basePath,
 		strings.TrimSuffix(PACKAGE_FILE_NAME, ".yml"))
 	if err != nil {
 		return err
 	}
-	pkg.Viper = v
+	pkg.AddCfgFilename(pkg.basePath + PACKAGE_FILE_NAME)
 
 	// Set package name from the package
-	pkg.name = v.GetString("pkg.name")
+	pkg.name = pkg.PkgV.GetString("pkg.name")
 
-	typeString := v.GetString("pkg.type")
+	typeString := pkg.PkgV.GetString("pkg.type")
 	pkg.packageType = PACKAGE_TYPE_LIB
 	for t, n := range PackageTypeNames {
 		if typeString == n {
@@ -295,16 +298,24 @@ func (pkg *LocalPackage) Load() error {
 		}
 	}
 
-	pkg.initFnName = v.GetString("pkg.init_function")
-	pkg.initStage = v.GetInt("pkg.init_stage")
+	pkg.initFnName = pkg.PkgV.GetString("pkg.init_function")
+	pkg.initStage = pkg.PkgV.GetInt("pkg.init_stage")
 
 	// Read the package description from the file
-	pkg.desc, err = pkg.readDesc(v)
+	pkg.desc, err = pkg.readDesc(pkg.PkgV)
 	if err != nil {
 		return err
 	}
 
-	pkg.AddCfgFilename(pkg.basePath + PACKAGE_FILE_NAME)
+	// Load syscfg settings.
+	if util.NodeExist(pkg.basePath + "/" + SYSCFG_YAML_FILENAME) {
+		pkg.SyscfgV, err = util.ReadConfig(pkg.basePath,
+			strings.TrimSuffix(SYSCFG_YAML_FILENAME, ".yml"))
+		if err != nil {
+			return err
+		}
+		pkg.AddCfgFilename(pkg.basePath + SYSCFG_YAML_FILENAME)
+	}
 
 	return nil
 }

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/dd715c24/newt/pkg/package.go
----------------------------------------------------------------------
diff --git a/newt/pkg/package.go b/newt/pkg/package.go
index 644889e..b3b4d3b 100644
--- a/newt/pkg/package.go
+++ b/newt/pkg/package.go
@@ -22,6 +22,7 @@ package pkg
 import "mynewt.apache.org/newt/newt/interfaces"
 
 const PACKAGE_FILE_NAME = "pkg.yml"
+const SYSCFG_YAML_FILENAME = "syscfg.yml"
 
 const (
 	PACKAGE_STABILITY_STABLE = "stable"
@@ -37,6 +38,7 @@ const (
 	PACKAGE_TYPE_LIB
 	PACKAGE_TYPE_TARGET
 	PACKAGE_TYPE_UNITTEST
+	PACKAGE_TYPE_GENERATED
 )
 
 var PackageTypeNames = map[interfaces.PackageType]string{

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/dd715c24/newt/pkg/packageutil.go
----------------------------------------------------------------------
diff --git a/newt/pkg/packageutil.go b/newt/pkg/packageutil.go
index f3f6132..2cadc28 100644
--- a/newt/pkg/packageutil.go
+++ b/newt/pkg/packageutil.go
@@ -1,7 +1,10 @@
 package pkg
 
 import (
+	"path/filepath"
 	"sort"
+
+	"mynewt.apache.org/newt/newt/interfaces"
 )
 
 type lpkgSorter struct {
@@ -30,3 +33,7 @@ func SortLclPkgs(pkgs []*LocalPackage) []*LocalPackage {
 	sort.Sort(sorter)
 	return sorter.pkgs
 }
+
+func ShortName(p interfaces.PackageInterface) string {
+	return filepath.Base(p.Name())
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/dd715c24/newt/project/project.go
----------------------------------------------------------------------
diff --git a/newt/project/project.go b/newt/project/project.go
index 5099e6f..857bcfb 100644
--- a/newt/project/project.go
+++ b/newt/project/project.go
@@ -67,7 +67,6 @@ type Project struct {
 
 func InitProject(dir string) error {
 	var err error
-
 	globalProject, err = LoadProject(dir)
 	if err != nil {
 		return err
@@ -79,30 +78,32 @@ func InitProject(dir string) error {
 	return nil
 }
 
-func Initialize() error {
+func initialize() error {
 	if globalProject == nil {
 		wd, err := os.Getwd()
 		if err != nil {
 			return util.NewNewtError(err.Error())
 		}
-		if err = InitProject(wd); err != nil {
+		if err := InitProject(wd); err != nil {
 			return err
 		}
 	}
 	return nil
 }
 
-func GetProject() *Project {
+func TryGetProject() (*Project, error) {
 	if globalProject == nil {
-		wd, err := os.Getwd()
-		if err != nil {
-			panic(err.Error())
-		}
-		err = InitProject(wd)
-		if err != nil {
-			return nil
+		if err := initialize(); err != nil {
+			return nil, err
 		}
 	}
+	return globalProject, nil
+}
+func GetProject() *Project {
+	if _, err := TryGetProject(); err != nil {
+		panic(err.Error())
+	}
+
 	return globalProject
 }
 
@@ -111,6 +112,7 @@ func ResetProject() {
 }
 
 func ResetDeps(newList interfaces.PackageList) interfaces.PackageList {
+	return nil
 	if globalProject == nil {
 		return nil
 	}
@@ -514,6 +516,42 @@ func (proj *Project) ResolveDependency(dep interfaces.DependencyInterface) inter
 	return nil
 }
 
+func (proj *Project) ResolvePackage(
+	dfltRepo interfaces.RepoInterface, name string) (*pkg.LocalPackage, error) {
+
+	// Trim trailing slash from name.  This is necessary when tab
+	// completion is used to specify the name.
+	name = strings.TrimSuffix(name, "/")
+
+	repoName, pkgName, err := newtutil.ParsePackageString(name)
+	if err != nil {
+		return nil, util.FmtNewtError("invalid package name: %s (%s)", name,
+			err.Error())
+	}
+
+	var repo interfaces.RepoInterface
+	if repoName == "" {
+		repo = dfltRepo
+	} else {
+		repo = proj.repos[repoName]
+	}
+
+	dep, err := pkg.NewDependency(repo, pkgName)
+	if err != nil {
+		return nil, util.FmtNewtError("invalid package name: %s (%s)", name,
+			err.Error())
+	}
+	if dep == nil {
+		return nil, util.NewNewtError("invalid package name: " + name)
+	}
+	pack := proj.ResolveDependency(dep)
+	if pack == nil {
+		return nil, util.NewNewtError("unknown package: " + name)
+	}
+
+	return pack.(*pkg.LocalPackage), nil
+}
+
 func findProjectDir(dir string) (string, error) {
 	for {
 		projFile := path.Clean(dir) + "/" + PROJECT_FILE_NAME

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/dd715c24/newt/repo/repo.go
----------------------------------------------------------------------
diff --git a/newt/repo/repo.go b/newt/repo/repo.go
index a7b0253..7a5c654 100644
--- a/newt/repo/repo.go
+++ b/newt/repo/repo.go
@@ -92,7 +92,8 @@ func (repo *Repo) FilteredSearchList(curPath string) ([]string, error) {
 
 	dirList, err := ioutil.ReadDir(filepath.Join(repo.Path(), curPath))
 	if err != nil {
-		return list, util.NewNewtError(err.Error())
+		return list, util.FmtNewtError("failed to read repo \"%s\": %s",
+			repo.Name(), err.Error())
 	}
 	for _, dirEnt := range dirList {
 		if !dirEnt.IsDir() {

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/dd715c24/newt/resolve/resolve.go
----------------------------------------------------------------------
diff --git a/newt/resolve/resolve.go b/newt/resolve/resolve.go
new file mode 100644
index 0000000..fc2f34c
--- /dev/null
+++ b/newt/resolve/resolve.go
@@ -0,0 +1,540 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+package resolve
+
+import (
+	"fmt"
+	"sort"
+	"strings"
+
+	log "github.com/Sirupsen/logrus"
+
+	"mynewt.apache.org/newt/newt/newtutil"
+	"mynewt.apache.org/newt/newt/pkg"
+	"mynewt.apache.org/newt/newt/project"
+	"mynewt.apache.org/newt/newt/syscfg"
+	"mynewt.apache.org/newt/util"
+)
+
+type Resolver struct {
+	apis             map[string]*ResolvePackage
+	pkgMap           map[*pkg.LocalPackage]*ResolvePackage
+	injectedSettings map[string]string
+	cfg              syscfg.Cfg
+}
+
+type ResolvePackage struct {
+	*pkg.LocalPackage
+
+	// Keeps track of API requirements and whether they are satisfied.
+	reqApiMap map[string]bool
+
+	depsResolved  bool
+	apisSatisfied bool
+}
+
+type CfgResolution struct {
+	Cfg             syscfg.Cfg
+	ApiMap          map[string]*pkg.LocalPackage
+	UnsatisfiedApis map[string][]*pkg.LocalPackage
+}
+
+func newResolver() *Resolver {
+	return &Resolver{
+		apis:             map[string]*ResolvePackage{},
+		pkgMap:           map[*pkg.LocalPackage]*ResolvePackage{},
+		injectedSettings: map[string]string{},
+		cfg:              syscfg.NewCfg(),
+	}
+}
+
+func newResolvePkg(lpkg *pkg.LocalPackage) *ResolvePackage {
+	return &ResolvePackage{
+		LocalPackage: lpkg,
+		reqApiMap:    map[string]bool{},
+	}
+}
+
+func newCfgResolution() CfgResolution {
+	return CfgResolution{
+		Cfg:             syscfg.NewCfg(),
+		ApiMap:          map[string]*pkg.LocalPackage{},
+		UnsatisfiedApis: map[string][]*pkg.LocalPackage{},
+	}
+}
+
+func (r *Resolver) lpkgSlice() []*pkg.LocalPackage {
+	lpkgs := make([]*pkg.LocalPackage, len(r.pkgMap))
+
+	i := 0
+	for lpkg, _ := range r.pkgMap {
+		lpkgs[i] = lpkg
+		i++
+	}
+
+	return lpkgs
+}
+
+func (r *Resolver) apiSlice() []string {
+	apis := make([]string, len(r.apis))
+
+	i := 0
+	for api, _ := range r.apis {
+		apis[i] = api
+		i++
+	}
+
+	return apis
+}
+
+func (r *Resolver) addPkg(lpkg *pkg.LocalPackage) *ResolvePackage {
+	rpkg := newResolvePkg(lpkg)
+	r.pkgMap[lpkg] = rpkg
+	return rpkg
+}
+
+// @return bool                 true if this is a new API.
+func (r *Resolver) addApi(apiString string, rpkg *ResolvePackage) bool {
+	curRpkg := r.apis[apiString]
+	if curRpkg == nil {
+		r.apis[apiString] = rpkg
+		return true
+	} else {
+		if curRpkg != rpkg {
+			util.StatusMessage(util.VERBOSITY_QUIET,
+				"Warning: API conflict: %s (%s <-> %s)\n", apiString,
+				curRpkg.Name(), rpkg.Name())
+		}
+		return false
+	}
+}
+
+// Searches for a package which can satisfy bpkg's API requirement.  If such a
+// package is found, bpkg's API requirement is marked as satisfied, and the
+// package is added to bpkg's dependency list.
+func (r *Resolver) satisfyReqApi(rpkg *ResolvePackage, reqApi string) bool {
+	depRpkg := r.apis[reqApi]
+	if depRpkg == nil {
+		// Insert nil to indicate an unsatisfied API.
+		r.apis[reqApi] = nil
+		return false
+	}
+
+	dep := &pkg.Dependency{
+		Name: depRpkg.Name(),
+		Repo: depRpkg.Repo().Name(),
+	}
+	rpkg.reqApiMap[reqApi] = true
+
+	// This package now has a new unresolved dependency.
+	rpkg.depsResolved = false
+
+	log.Debugf("API requirement satisfied; pkg=%s API=(%s, %s)",
+		rpkg.Name(), reqApi, dep.String())
+
+	return true
+}
+
+// @return bool                 true if a new dependency was detected as a
+//                                  result of satisfying an API for this
+//                                  package.
+func (r *Resolver) satisfyApis(rpkg *ResolvePackage) bool {
+	// Assume all this package's APIs are satisfied and that no new
+	// dependencies will be detected.
+	rpkg.apisSatisfied = true
+	newDeps := false
+
+	features := r.cfg.FeaturesForLpkg(rpkg.LocalPackage)
+
+	// Determine if any of the package's API requirements can now be satisfied.
+	// If so, another full iteration is required.
+	reqApis := newtutil.GetStringSliceFeatures(rpkg.PkgV, features,
+		"pkg.req_apis")
+	for _, reqApi := range reqApis {
+		reqStatus := rpkg.reqApiMap[reqApi]
+		if !reqStatus {
+			apiSatisfied := r.satisfyReqApi(rpkg, reqApi)
+			if apiSatisfied {
+				// An API was satisfied; the package now has a new dependency
+				// that needs to be resolved.
+				newDeps = true
+				reqStatus = true
+			} else {
+				rpkg.reqApiMap[reqApi] = false
+			}
+		}
+		if reqStatus {
+			rpkg.apisSatisfied = false
+		}
+	}
+
+	return newDeps
+}
+
+// @return bool                 True if this this function changed the builder
+//                                  state; another full iteration is required
+//                                  in this case.
+//         error                non-nil on failure.
+func (r *Resolver) loadDepsForPkg(rpkg *ResolvePackage) (bool, error) {
+	proj := project.GetProject()
+	features := r.cfg.FeaturesForLpkg(rpkg.LocalPackage)
+
+	changed := false
+
+	newDeps := newtutil.GetStringSliceFeatures(rpkg.PkgV, features, "pkg.deps")
+	for _, newDepStr := range newDeps {
+		newDep, err := pkg.NewDependency(rpkg.Repo(), newDepStr)
+		if err != nil {
+			return false, err
+		}
+
+		lpkg, ok := proj.ResolveDependency(newDep).(*pkg.LocalPackage)
+		if !ok {
+			return false,
+				util.NewNewtError("Could not resolve package dependency " +
+					newDep.String())
+		}
+
+		if r.pkgMap[lpkg] == nil {
+			changed = true
+			r.addPkg(lpkg)
+		}
+	}
+
+	// Determine if this package supports any APIs that we haven't seen
+	// yet.  If so, another full iteration is required.
+	apis := newtutil.GetStringSliceFeatures(rpkg.PkgV, features, "pkg.apis")
+	for _, api := range apis {
+		newApi := r.addApi(api, rpkg)
+		if newApi {
+			changed = true
+		}
+	}
+
+	return changed, nil
+}
+
+// Attempts to resolve all of a build package's dependencies, identities, APIs,
+// and required APIs.  This function should be called repeatedly until the
+// package is fully resolved.
+//
+// If a dependency is resolved by this function, the new dependency needs to be
+// processed.  The caller should attempt to resolve all packages again.
+//
+// If a new supported feature is detected by this function, all pacakges need
+// to be reprocessed from scratch.  The caller should set all packages'
+// depsResolved and apisSatisfied variables to false and attempt to resolve
+// everything again.
+//
+// @return bool                 true if >=1 dependencies were resolved
+//         bool                 true if >=1 new features were detected
+func (r *Resolver) resolvePkg(rpkg *ResolvePackage) (bool, error) {
+	var err error
+	newDeps := false
+
+	if !rpkg.depsResolved {
+		newDeps, err = r.loadDepsForPkg(rpkg)
+		if err != nil {
+			return false, err
+		}
+
+		rpkg.depsResolved = !newDeps
+	}
+
+	if !rpkg.apisSatisfied {
+		newApiDep := r.satisfyApis(rpkg)
+		if newApiDep {
+			newDeps = true
+		}
+	}
+
+	return newDeps, nil
+}
+
+// @return                      changed,err
+func (r *Resolver) reloadCfg() (bool, error) {
+	lpkgs := r.lpkgSlice()
+	apis := r.apiSlice()
+
+	// Determine which features have been detected so far.  The feature map is
+	// required for reloading syscfg, as features may unlock additional
+	// settings.
+	features := r.cfg.Features()
+	cfg, err := syscfg.Read(lpkgs, apis, r.injectedSettings, features)
+	if err != nil {
+		return false, err
+	}
+
+	changed := false
+	for k, v := range cfg.Settings {
+		oldval, ok := r.cfg.Settings[k]
+		if !ok || len(oldval.History) != len(v.History) {
+			r.cfg = cfg
+			changed = true
+		}
+	}
+
+	return changed, nil
+}
+
+func (r *Resolver) loadDepsOnce() (bool, error) {
+	// Circularly resolve dependencies, APIs, and required APIs until no new
+	// ones exist.
+	newDeps := false
+	for {
+		reprocess := false
+		for _, rpkg := range r.pkgMap {
+			newDeps, err := r.resolvePkg(rpkg)
+			if err != nil {
+				return false, err
+			}
+
+			if newDeps {
+				// The new dependencies need to be processed.  Iterate again
+				// after this iteration completes.
+				reprocess = true
+			}
+		}
+
+		if !reprocess {
+			break
+		}
+	}
+
+	return newDeps, nil
+}
+
+func (r *Resolver) loadDepsAndCfg() error {
+	if _, err := r.loadDepsOnce(); err != nil {
+		return err
+	}
+
+	for {
+		cfgChanged, err := r.reloadCfg()
+		if err != nil {
+			return err
+		}
+		if cfgChanged {
+			// A new supported feature was discovered.  It is impossible
+			// to determine what new dependency and API requirements are
+			// generated as a result.  All packages need to be
+			// reprocessed.
+			for _, rpkg := range r.pkgMap {
+				rpkg.depsResolved = false
+				rpkg.apisSatisfied = false
+			}
+		}
+
+		newDeps, err := r.loadDepsOnce()
+		if err != nil {
+			return err
+		}
+
+		if !newDeps && !cfgChanged {
+			break
+		}
+	}
+
+	// Log the final syscfg.
+	r.cfg.Log()
+
+	return nil
+}
+
+func pkgSliceUnion(left []*pkg.LocalPackage,
+	right []*pkg.LocalPackage) []*pkg.LocalPackage {
+
+	set := make(map[*pkg.LocalPackage]struct{}, len(left)+len(right))
+	for _, lpkg := range left {
+		set[lpkg] = struct{}{}
+	}
+	for _, lpkg := range right {
+		set[lpkg] = struct{}{}
+	}
+
+	result := []*pkg.LocalPackage{}
+	for lpkg := range set {
+		result = append(result, lpkg)
+	}
+
+	return result
+}
+
+func pkgSliceRemove(slice []*pkg.LocalPackage,
+	toRemove *pkg.LocalPackage) []*pkg.LocalPackage {
+
+	for i, lpkg := range slice {
+		if lpkg == toRemove {
+			return append(slice[:i], slice[i+1:]...)
+		}
+	}
+
+	return slice
+}
+
+func ResolvePkgs(cfgResolution CfgResolution,
+	seedPkgs []*pkg.LocalPackage) ([]*pkg.LocalPackage, error) {
+
+	r := newResolver()
+	r.cfg = cfgResolution.Cfg
+	for _, lpkg := range seedPkgs {
+		r.addPkg(lpkg)
+	}
+
+	if _, err := r.loadDepsOnce(); err != nil {
+		return nil, err
+	}
+
+	// Satisfy API requirements.
+	for _, rpkg := range r.pkgMap {
+		for api, _ := range rpkg.reqApiMap {
+			apiPkg := cfgResolution.ApiMap[api]
+			if apiPkg == nil {
+				return nil, util.FmtNewtError(
+					"Unsatisfied API at unexpected time: %s", api)
+			}
+
+			r.addPkg(apiPkg)
+		}
+	}
+
+	lpkgs := make([]*pkg.LocalPackage, len(r.pkgMap))
+	i := 0
+	for lpkg, _ := range r.pkgMap {
+		lpkgs[i] = lpkg
+		i++
+	}
+
+	return lpkgs, nil
+}
+
+func ResolveSplitPkgs(cfgResolution CfgResolution,
+	appLoaderPkg *pkg.LocalPackage,
+	appAppPkg *pkg.LocalPackage,
+	bspPkg *pkg.LocalPackage,
+	compilerPkg *pkg.LocalPackage,
+	targetPkg *pkg.LocalPackage) (
+
+	loaderPkgs []*pkg.LocalPackage,
+	appPkgs []*pkg.LocalPackage,
+	err error) {
+
+	if appLoaderPkg != nil {
+		loaderSeedPkgs := []*pkg.LocalPackage{
+			appLoaderPkg, bspPkg, compilerPkg, targetPkg}
+		loaderPkgs, err = ResolvePkgs(cfgResolution, loaderSeedPkgs)
+		if err != nil {
+			return
+		}
+	}
+
+	appSeedPkgs := []*pkg.LocalPackage{
+		appAppPkg, bspPkg, compilerPkg, targetPkg}
+	appPkgs, err = ResolvePkgs(cfgResolution, appSeedPkgs)
+	if err != nil {
+		return
+	}
+
+	// The app image needs to have access to all the loader packages except
+	// the loader app itself.  This is required because the app sysinit
+	// function needs to initialize every package in the build.
+	if appLoaderPkg != nil {
+		appPkgs = pkgSliceUnion(appPkgs, loaderPkgs)
+		appPkgs = pkgSliceRemove(appPkgs, appLoaderPkg)
+	}
+
+	return
+}
+
+func ResolveCfg(seedPkgs []*pkg.LocalPackage,
+	injectedSettings map[string]string) (CfgResolution, error) {
+
+	resolution := newCfgResolution()
+
+	r := newResolver()
+	if injectedSettings == nil {
+		injectedSettings = map[string]string{}
+	}
+	r.injectedSettings = injectedSettings
+
+	for _, lpkg := range seedPkgs {
+		r.addPkg(lpkg)
+	}
+
+	if err := r.loadDepsAndCfg(); err != nil {
+		return resolution, err
+	}
+
+	resolution.Cfg = r.cfg
+	resolution.ApiMap = make(map[string]*pkg.LocalPackage, len(r.apis))
+	anyUnsatisfied := false
+	for api, rpkg := range r.apis {
+		if rpkg == nil {
+			anyUnsatisfied = true
+		} else {
+			resolution.ApiMap[api] = rpkg.LocalPackage
+		}
+	}
+
+	if anyUnsatisfied {
+		for lpkg, rpkg := range r.pkgMap {
+			for api, satisfied := range rpkg.reqApiMap {
+				if !satisfied {
+					slice := resolution.UnsatisfiedApis[api]
+					slice = append(slice, lpkg)
+					resolution.UnsatisfiedApis[api] = slice
+				}
+			}
+		}
+	}
+
+	return resolution, nil
+}
+
+func (cfgResolution *CfgResolution) ErrorText() string {
+	str := ""
+
+	if len(cfgResolution.UnsatisfiedApis) > 0 {
+		apiNames := make([]string, 0, len(cfgResolution.UnsatisfiedApis))
+		for api, _ := range cfgResolution.UnsatisfiedApis {
+			apiNames = append(apiNames, api)
+		}
+		sort.Strings(apiNames)
+
+		str += "Unsatisfied APIs detected:\n"
+		for _, api := range apiNames {
+			str += fmt.Sprintf("    * %s, required by: ", api)
+
+			pkgs := cfgResolution.UnsatisfiedApis[api]
+			pkgNames := make([]string, len(pkgs))
+			for i, lpkg := range pkgs {
+				pkgNames[i] = lpkg.Name()
+			}
+			sort.Strings(pkgNames)
+
+			str += strings.Join(pkgNames, ", ")
+			str += "\n"
+		}
+	}
+
+	str += cfgResolution.Cfg.ErrorText()
+
+	return strings.TrimSpace(str)
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/dd715c24/newt/syscfg/syscfg.go
----------------------------------------------------------------------
diff --git a/newt/syscfg/syscfg.go b/newt/syscfg/syscfg.go
index 04241ec..2b6b0c4 100644
--- a/newt/syscfg/syscfg.go
+++ b/newt/syscfg/syscfg.go
@@ -39,11 +39,9 @@ import (
 	"mynewt.apache.org/newt/util"
 )
 
-const SYSCFG_INCLUDE_SUBDIR = "include/syscfg"
+const SYSCFG_INCLUDE_SUBDIR = "syscfg"
 const SYSCFG_HEADER_FILENAME = "syscfg.h"
 
-const SYSCFG_PREFIX_API = "MYNEWT_API_"
-const SYSCFG_PREFIX_PKG = "MYNEWT_PKG_"
 const SYSCFG_PREFIX_SETTING = "MYNEWT_VAL_"
 
 type CfgSettingType int
@@ -74,40 +72,53 @@ type CfgPoint struct {
 	Source *pkg.LocalPackage
 }
 
+type CfgRestriction struct {
+	ReqSetting  string
+	ReqVal      bool
+	BaseSetting string
+	BaseVal     bool
+}
+
 type CfgEntry struct {
-	Name        string
-	Value       string
-	History     []CfgPoint
-	Description string
-	SettingType CfgSettingType
+	Name         string
+	Value        string
+	Description  string
+	SettingType  CfgSettingType
+	Restrictions []CfgRestriction
+
+	History []CfgPoint
 }
 
-type CfgRoster struct {
-	settings    map[string]string
-	pkgsPresent map[string]bool
-	apisPresent map[string]bool
+type CfgLateral struct {
+	PkgName     string
+	SettingName string
 }
 
 type Cfg struct {
-	Settings    map[string]CfgEntry
-	Roster      CfgRoster
-	Orphans     map[string][]CfgPoint
-	Ambiguities []CfgEntry
-}
+	Settings map[string]CfgEntry
 
-func newRoster() CfgRoster {
-	return CfgRoster{
-		settings:    map[string]string{},
-		pkgsPresent: map[string]bool{},
-		apisPresent: map[string]bool{},
-	}
+	//// Errors
+	// Overrides of undefined settings.
+	Orphans map[string][]CfgPoint
+
+	// Two packages of equal priority override a setting with different
+	// values; not overridden by higher priority package.
+	Ambiguities map[string][]CfgPoint
+
+	// Setting restrictions not met.
+	Violations map[string][]CfgRestriction
+
+	// Attempted override by bottom-priority packages (libraries).
+	Laterals []CfgLateral
 }
 
 func NewCfg() Cfg {
 	return Cfg{
-		Settings: map[string]CfgEntry{},
-		Roster:   newRoster(),
-		Orphans:  map[string][]CfgPoint{},
+		Settings:    map[string]CfgEntry{},
+		Orphans:     map[string][]CfgPoint{},
+		Ambiguities: map[string][]CfgPoint{},
+		Violations:  map[string][]CfgRestriction{},
+		Laterals:    []CfgLateral{},
 	}
 }
 
@@ -177,9 +188,24 @@ func (entry *CfgEntry) appendValue(lpkg *pkg.LocalPackage, value interface{}) {
 	entry.Value = strval
 }
 
-func (entry *CfgEntry) ambiguousCount() int {
+func historyToString(history []CfgPoint) string {
+	str := "["
+	for i, _ := range history {
+		if i != 0 {
+			str += ", "
+		}
+		p := history[len(history)-i-1]
+		str += fmt.Sprintf("%s:%s", p.Name(), p.Value)
+	}
+	str += "]"
+
+	return str
+}
+
+func (entry *CfgEntry) ambiguities() []CfgPoint {
 	diffVals := false
-	count := 0
+	var points []CfgPoint
+
 	for i := 1; i < len(entry.History)-1; i++ {
 		cur := entry.History[len(entry.History)-i-1]
 		next := entry.History[len(entry.History)-i]
@@ -200,42 +226,61 @@ func (entry *CfgEntry) ambiguousCount() int {
 			diffVals = true
 		}
 
-		count++
-	}
-
-	// Account for final package that was skipped in loop.
-	if count > 0 {
-		count++
+		if len(points) == 0 {
+			points = append(points, cur)
+		}
+		points = append(points, next)
 	}
 
 	// If all values are identical, there is no ambiguity
 	if !diffVals {
-		count = 0
+		points = nil
 	}
 
-	return count
+	return points
 }
 
-func (entry *CfgEntry) ambiguousText() string {
-	count := entry.ambiguousCount()
-	if count == 0 {
+func (entry *CfgEntry) ambiguityText() string {
+	points := entry.ambiguities()
+	if len(points) == 0 {
 		return ""
 	}
 
-	str := fmt.Sprintf("%s [", entry.Name)
-
-	for i := 0; i < count; i++ {
-		cur := entry.History[len(entry.History)-i-1]
-		if i != 0 {
+	str := fmt.Sprintf("Setting: %s, Packages: [", entry.Name)
+	for i, p := range points {
+		if i > 0 {
 			str += ", "
 		}
-		str += fmt.Sprintf("%s:%s", cur.Name(), cur.Value)
+
+		str += p.Source.Name()
 	}
 	str += "]"
 
 	return str
 }
 
+func (cfg *Cfg) violationText(entry CfgEntry, r CfgRestriction) string {
+	str := fmt.Sprintf("%s=%s ", entry.Name, entry.Value)
+
+	reqVal := ""
+	if r.ReqVal {
+		reqVal = "1"
+	} else {
+		reqVal = "0"
+	}
+
+	str += fmt.Sprintf("requires %s=%s, but %s", r.ReqSetting, reqVal,
+		r.ReqSetting)
+	reqEntry, ok := cfg.Settings[r.ReqSetting]
+	if !ok {
+		str += "undefined"
+	} else {
+		str += fmt.Sprintf("=%s", reqEntry.Value)
+	}
+
+	return str
+}
+
 func FeatureToCflag(featureName string) string {
 	return fmt.Sprintf("-D%s=1", settingName(featureName))
 }
@@ -244,6 +289,68 @@ func stringValue(val interface{}) string {
 	return strings.TrimSpace(cast.ToString(val))
 }
 
+func parseRestrictionConsequent(field string) (string, bool) {
+	var val bool
+	var name string
+
+	if strings.HasPrefix(field, "!") {
+		val = false
+		name = strings.TrimPrefix(field, "!")
+	} else {
+		val = true
+		name = field
+	}
+
+	return name, val
+}
+
+// Parses a restriction expression.
+//
+// It would be better to have a real expression parser.  For now, only very
+// simple expressions are supported.  A restriction expression must be of the
+// following form:
+//     [!]<req-setting> [if <base-val>]
+//
+// All setting values are interpreted as booleans.  If a setting is "0", "",
+// or undefined, it is false; otherwise it is true.
+//
+// Examples:
+//     # Can't enable this setting unless LOG_FCB is enabled.
+//	   pkg.restrictions:
+//         LOG_FCB
+//
+//     # Can't enable this setting unless LOG_FCB is disabled.
+//	   pkg.restrictions:
+//         !LOG_FCB
+//
+//     # Can't disable this setting unless LOG_FCB is enabled.
+//	   pkg.restrictions:
+//         LOG_FCB if 0
+func readRestriction(baseSetting string, text string) (CfgRestriction, error) {
+	r := CfgRestriction{
+		BaseSetting: baseSetting,
+	}
+
+	fields := strings.Fields(text)
+	switch len(fields) {
+	case 1:
+		r.ReqSetting, r.ReqVal = parseRestrictionConsequent(fields[0])
+		r.BaseVal = true
+
+	case 3:
+		if fields[1] != "if" {
+			return r, util.FmtNewtError("invalid restriction: %s", text)
+		}
+		r.ReqSetting, r.ReqVal = parseRestrictionConsequent(fields[0])
+		r.BaseVal = ValueIsTrue(fields[2])
+
+	default:
+		return r, util.FmtNewtError("invalid restriction: %s", text)
+	}
+
+	return r, nil
+}
+
 func readSetting(name string, lpkg *pkg.LocalPackage,
 	vals map[interface{}]interface{}) (CfgEntry, error) {
 
@@ -263,22 +370,32 @@ func readSetting(name string, lpkg *pkg.LocalPackage,
 				"setting %s specifies invalid type: %s", name, typename)
 		}
 	}
-
 	entry.appendValue(lpkg, entry.Value)
 
+	entry.Restrictions = []CfgRestriction{}
+	restrictionStrings := cast.ToStringSlice(vals["restrictions"])
+	for _, rstring := range restrictionStrings {
+		r, err := readRestriction(name, rstring)
+		if err != nil {
+			return entry,
+				util.PreNewtError(err, "error parsing setting %s", name)
+		}
+		entry.Restrictions = append(entry.Restrictions, r)
+	}
+
 	return entry, nil
 }
 
 func (cfg *Cfg) readDefsOnce(lpkg *pkg.LocalPackage,
 	features map[string]bool) error {
-	v := lpkg.Viper
+	v := lpkg.SyscfgV
 
 	lfeatures := cfg.FeaturesForLpkg(lpkg)
 	for k, _ := range features {
 		lfeatures[k] = true
 	}
 
-	settings := newtutil.GetStringMapFeatures(v, lfeatures, "pkg.syscfg_defs")
+	settings := newtutil.GetStringMapFeatures(v, lfeatures, "syscfg.defs")
 	if settings != nil {
 		for k, v := range settings {
 			vals := v.(map[interface{}]interface{})
@@ -301,15 +418,24 @@ func (cfg *Cfg) readDefsOnce(lpkg *pkg.LocalPackage,
 
 func (cfg *Cfg) readValsOnce(lpkg *pkg.LocalPackage,
 	features map[string]bool) error {
-	v := lpkg.Viper
+	v := lpkg.SyscfgV
 
 	lfeatures := cfg.FeaturesForLpkg(lpkg)
 	for k, _ := range features {
 		lfeatures[k] = true
 	}
-	values := newtutil.GetStringMapFeatures(v, lfeatures, "pkg.syscfg_vals")
-	if values != nil {
-		for k, v := range values {
+
+	values := newtutil.GetStringMapFeatures(v, lfeatures, "syscfg.vals")
+	for k, v := range values {
+		if normalizePkgType(lpkg.Type()) == pkg.PACKAGE_TYPE_LIB {
+			// A library package is overriding a setting; this is disallowed.
+			// Overrides must come from a higher priority package.
+			lateral := CfgLateral{
+				PkgName:     lpkg.Name(),
+				SettingName: k,
+			}
+			cfg.Laterals = append(cfg.Laterals, lateral)
+		} else {
 			entry, ok := cfg.Settings[k]
 			if ok {
 				entry.appendValue(lpkg, v)
@@ -321,7 +447,6 @@ func (cfg *Cfg) readValsOnce(lpkg *pkg.LocalPackage,
 				}
 				cfg.Orphans[k] = append(cfg.Orphans[k], orphan)
 			}
-
 		}
 	}
 
@@ -341,17 +466,8 @@ func (cfg *Cfg) Log() {
 	for _, k := range keys {
 		entry := cfg.Settings[k]
 
-		str := fmt.Sprintf("    %s=%s [", k, entry.Value)
-
-		for i, p := range entry.History {
-			if i != 0 {
-				str += ", "
-			}
-			str += fmt.Sprintf("%s:%s", p.Name(), p.Value)
-		}
-		str += "]"
-
-		log.Debug(str)
+		log.Debugf("    %s=%s %s", k, entry.Value,
+			historyToString(entry.History))
 	}
 
 	keys = make([]string, len(cfg.Orphans))
@@ -376,16 +492,93 @@ func (cfg *Cfg) Log() {
 	}
 }
 
-func (cfg *Cfg) DetectErrors() error {
-	if len(cfg.Ambiguities) == 0 {
-		return nil
+func (cfg *Cfg) restrictionMet(r CfgRestriction) bool {
+	baseEntry := cfg.Settings[r.BaseSetting]
+	baseVal := baseEntry.IsTrue()
+
+	if baseVal != r.BaseVal {
+		// Restriction does not apply.
+		return true
 	}
 
-	str := "Syscfg ambiguities detected:"
-	for _, entry := range cfg.Ambiguities {
-		str += "\n    " + entry.ambiguousText()
+	reqEntry, ok := cfg.Settings[r.ReqSetting]
+	reqVal := ok && reqEntry.IsTrue()
+
+	return reqVal == r.ReqVal
+}
+
+func (cfg *Cfg) detectViolations() {
+	for _, entry := range cfg.Settings {
+		var ev []CfgRestriction
+		for _, r := range entry.Restrictions {
+			if !cfg.restrictionMet(r) {
+				ev = append(ev, r)
+			}
+		}
+
+		if ev != nil {
+			cfg.Violations[entry.Name] = ev
+		}
 	}
-	return util.NewNewtError(str)
+}
+
+func (cfg *Cfg) ErrorText() string {
+	str := ""
+
+	interestingNames := map[string]struct{}{}
+
+	if len(cfg.Violations) > 0 {
+		str += "Syscfg restriction violations detected:\n"
+		for settingName, rslice := range cfg.Violations {
+			interestingNames[settingName] = struct{}{}
+
+			entry := cfg.Settings[settingName]
+			for _, r := range rslice {
+				interestingNames[r.ReqSetting] = struct{}{}
+				str += "    " + cfg.violationText(entry, r) + "\n"
+			}
+		}
+	}
+
+	if len(cfg.Ambiguities) > 0 {
+		str += "Syscfg ambiguities detected:\n"
+
+		settingNames := make([]string, 0, len(cfg.Ambiguities))
+		for k, _ := range cfg.Ambiguities {
+			settingNames = append(settingNames, k)
+		}
+		sort.Strings(settingNames)
+
+		for _, name := range settingNames {
+			entry := cfg.Settings[name]
+			interestingNames[entry.Name] = struct{}{}
+			str += "    " + entry.ambiguityText()
+		}
+	}
+
+	if len(cfg.Laterals) > 0 {
+		str += "Lateral overrides detected (bottom-priority packages " +
+			"cannot override settings):\n"
+		for _, lateral := range cfg.Laterals {
+			interestingNames[lateral.SettingName] = struct{}{}
+
+			str += fmt.Sprintf("    Package: %s, Setting: %s\n",
+				lateral.PkgName, lateral.SettingName)
+		}
+	}
+
+	if str == "" {
+		return ""
+	}
+
+	str += "\nSetting history:\n"
+	for name, _ := range interestingNames {
+		entry := cfg.Settings[name]
+		str += fmt.Sprintf("    %s: %s\n", name,
+			historyToString(entry.History))
+	}
+
+	return strings.TrimSpace(str)
 }
 
 func escapeStr(s string) string {
@@ -396,30 +589,10 @@ func escapeStr(s string) string {
 	return s
 }
 
-func isSettingVal(s string) bool {
-	return strings.HasPrefix(s, SYSCFG_PREFIX_SETTING)
-}
-
-func isPkgVal(s string) bool {
-	return strings.HasPrefix(s, SYSCFG_PREFIX_PKG)
-}
-
-func isApiVal(s string) bool {
-	return strings.HasPrefix(s, SYSCFG_PREFIX_API)
-}
-
 func settingName(setting string) string {
 	return SYSCFG_PREFIX_SETTING + escapeStr(setting)
 }
 
-func pkgPresentName(pkgName string) string {
-	return SYSCFG_PREFIX_PKG + escapeStr(pkgName)
-}
-
-func apiPresentName(apiName string) string {
-	return SYSCFG_PREFIX_API + strings.ToUpper(apiName)
-}
-
 func normalizePkgType(typ interfaces.PackageType) interfaces.PackageType {
 	switch typ {
 	case pkg.PACKAGE_TYPE_TARGET:
@@ -435,7 +608,9 @@ func normalizePkgType(typ interfaces.PackageType) interfaces.PackageType {
 	}
 }
 
-func categorizePkgs(lpkgs []*pkg.LocalPackage) map[interfaces.PackageType][]*pkg.LocalPackage {
+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{},
@@ -473,14 +648,12 @@ func (cfg *Cfg) readForPkgType(lpkgs []*pkg.LocalPackage,
 	return nil
 }
 
-func detectAmbiguities(cfg Cfg) Cfg {
+func (cfg *Cfg) detectAmbiguities() {
 	for _, entry := range cfg.Settings {
-		if entry.ambiguousCount() > 0 {
-			cfg.Ambiguities = append(cfg.Ambiguities, entry)
+		if points := entry.ambiguities(); len(points) > 0 {
+			cfg.Ambiguities[entry.Name] = points
 		}
 	}
-
-	return cfg
 }
 
 func Read(lpkgs []*pkg.LocalPackage, apis []string,
@@ -526,12 +699,8 @@ func Read(lpkgs []*pkg.LocalPackage, apis []string,
 		}
 	}
 
-	cfg.buildCfgRoster(lpkgs, apis)
-	if err := fixupSettings(cfg); err != nil {
-		return cfg, err
-	}
-
-	cfg = detectAmbiguities(cfg)
+	cfg.detectAmbiguities()
+	cfg.detectViolations()
 
 	return cfg, nil
 }
@@ -622,15 +791,13 @@ func calcPriorities(cfg Cfg, settingType CfgSettingType, max int,
 
 func writeCheckMacros(w io.Writer) {
 	s := `/**
- * These macros exists to ensure code includes this header when needed.  If
- * code checks the existence of a setting directly via ifdef without including
- * this header, the setting macro will silently evaluate to 0.  In contrast, an
+ * This macro exists to ensure code includes this header when needed.  If code
+ * checks the existence of a setting directly via ifdef without including this
+ * header, the setting macro will silently evaluate to 0.  In contrast, an
  * attempt to use these macros without including this header will result in a
  * compiler error.
  */
 #define MYNEWT_VAL(x)                           MYNEWT_VAL_ ## x
-#define MYNEWT_PKG(x)                           MYNEWT_PKG_ ## x
-#define MYNEWT_API(x)                           MYNEWT_API_ ## x
 `
 	fmt.Fprintf(w, "%s\n", s)
 }
@@ -644,125 +811,13 @@ func writeComment(entry CfgEntry, w io.Writer) {
 }
 
 func writeDefine(key string, value string, w io.Writer) {
-	fmt.Fprintf(w, "#ifndef %s\n", key)
-	fmt.Fprintf(w, "#define %s (%s)\n", key, value)
-	fmt.Fprintf(w, "#endif\n")
-}
-
-func (cfg *Cfg) specialValues() (apis, pkgs, settings []string) {
-	for _, entry := range cfg.Settings {
-		if isApiVal(entry.Value) {
-			apis = append(apis, entry.Value)
-		} else if isPkgVal(entry.Value) {
-			pkgs = append(pkgs, entry.Value)
-		} else if isSettingVal(entry.Value) {
-			settings = append(settings, entry.Value)
-		}
-	}
-
-	return
-}
-
-func (cfg *Cfg) buildCfgRoster(lpkgs []*pkg.LocalPackage, apis []string) {
-	roster := CfgRoster{
-		settings:    make(map[string]string, len(cfg.Settings)),
-		pkgsPresent: make(map[string]bool, len(lpkgs)),
-		apisPresent: make(map[string]bool, len(apis)),
-	}
-
-	for k, v := range cfg.Settings {
-		roster.settings[settingName(k)] = v.Value
-	}
-
-	for _, v := range lpkgs {
-		roster.pkgsPresent[pkgPresentName(v.Name())] = true
-	}
-
-	for _, v := range apis {
-		roster.apisPresent[apiPresentName(v)] = true
-	}
-
-	apisNotPresent, pkgsNotPresent, _ := cfg.specialValues()
-
-	for _, v := range apisNotPresent {
-		_, ok := roster.apisPresent[v]
-		if !ok {
-			roster.apisPresent[v] = false
-		}
-	}
-
-	for _, v := range pkgsNotPresent {
-		_, ok := roster.pkgsPresent[v]
-		if !ok {
-			roster.pkgsPresent[v] = false
-		}
-	}
-
-	cfg.Roster = roster
-}
-
-func settingValueToConstant(value string,
-	roster CfgRoster) (string, bool, error) {
-
-	seen := map[string]struct{}{}
-	curVal := value
-	for {
-		v, ok := roster.settings[curVal]
-		if ok {
-			if _, ok := seen[v]; ok {
-				return "", false, util.FmtNewtError("Syscfg cycle detected: "+
-					"%s <==> %s", value, v)
-			}
-			seen[v] = struct{}{}
-			curVal = v
-		} else {
-			break
-		}
-	}
-	if curVal != value {
-		return curVal, true, nil
-	}
-
-	v, ok := roster.apisPresent[value]
-	if ok {
-		if v {
-			return "1", true, nil
-		} else {
-			return "0", true, nil
-		}
-	}
-
-	v, ok = roster.pkgsPresent[value]
-	if ok {
-		if v {
-			return "1", true, nil
-		} else {
-			return "0", true, nil
-		}
-	}
-
-	return value, false, nil
-}
-
-func fixupSettings(cfg Cfg) error {
-	for k, entry := range cfg.Settings {
-		value, changed, err := settingValueToConstant(entry.Value, cfg.Roster)
-		if err != nil {
-			return err
-		}
-
-		if changed {
-			entry.Value = value
-			cfg.Settings[k] = entry
-		}
+	if value == "" {
+		fmt.Fprintf(w, "#undef %s\n", key)
+	} else {
+		fmt.Fprintf(w, "#ifndef %s\n", key)
+		fmt.Fprintf(w, "#define %s (%s)\n", key, value)
+		fmt.Fprintf(w, "#endif\n")
 	}
-
-	return nil
-}
-
-func UnfixedValue(entry CfgEntry) string {
-	point := mostRecentPoint(entry)
-	return point.Value
 }
 
 func EntriesByPkg(cfg Cfg) map[string][]CfgEntry {
@@ -777,27 +832,29 @@ func EntriesByPkg(cfg Cfg) map[string][]CfgEntry {
 func writeSettingsOnePkg(cfg Cfg, pkgName string, pkgEntries []CfgEntry,
 	w io.Writer) {
 
-	fmt.Fprintf(w, "/*** %s */\n", pkgName)
-
 	names := make([]string, len(pkgEntries), len(pkgEntries))
 	for i, entry := range pkgEntries {
 		names[i] = entry.Name
 	}
+
+	if len(names) == 0 {
+		return
+	}
 	sort.Strings(names)
 
+	fmt.Fprintf(w, "/*** %s */\n", pkgName)
+
 	first := true
 	for _, n := range names {
 		entry := cfg.Settings[n]
-		if entry.Value != "" {
-			if first {
-				first = false
-			} else {
-				fmt.Fprintf(w, "\n")
-			}
-
-			writeComment(entry, w)
-			writeDefine(settingName(n), entry.Value, w)
+		if first {
+			first = false
+		} else {
+			fmt.Fprintf(w, "\n")
 		}
+
+		writeComment(entry, w)
+		writeDefine(settingName(n), entry.Value, w)
 	}
 }
 
@@ -812,8 +869,6 @@ func writeSettings(cfg Cfg, w io.Writer) {
 	}
 	sort.Strings(pkgNames)
 
-	fmt.Fprintf(w, "/***** Settings */\n")
-
 	for _, name := range pkgNames {
 		fmt.Fprintf(w, "\n")
 		entries := pkgEntries[name]
@@ -821,62 +876,6 @@ func writeSettings(cfg Cfg, w io.Writer) {
 	}
 }
 
-func writePkgsPresent(roster CfgRoster, w io.Writer) {
-	present := make([]string, 0, len(roster.pkgsPresent))
-	notPresent := make([]string, 0, len(roster.pkgsPresent))
-	for k, v := range roster.pkgsPresent {
-		if v {
-			present = append(present, k)
-		} else {
-			notPresent = append(notPresent, k)
-		}
-	}
-
-	sort.Strings(present)
-	sort.Strings(notPresent)
-
-	fmt.Fprintf(w, "/*** Packages (present) */\n")
-	for _, symbol := range present {
-		fmt.Fprintf(w, "\n")
-		writeDefine(symbol, "1", w)
-	}
-
-	fmt.Fprintf(w, "\n")
-	fmt.Fprintf(w, "/*** Packages (not present)*/\n")
-	for _, symbol := range notPresent {
-		fmt.Fprintf(w, "\n")
-		writeDefine(symbol, "0", w)
-	}
-}
-
-func writeApisPresent(roster CfgRoster, w io.Writer) {
-	present := make([]string, 0, len(roster.apisPresent))
-	notPresent := make([]string, 0, len(roster.apisPresent))
-	for k, v := range roster.apisPresent {
-		if v {
-			present = append(present, k)
-		} else {
-			notPresent = append(notPresent, k)
-		}
-	}
-
-	sort.Strings(present)
-	sort.Strings(notPresent)
-
-	fmt.Fprintf(w, "/*** APIs (present) */\n")
-	for _, symbol := range present {
-		fmt.Fprintf(w, "\n")
-		writeDefine(symbol, "1", w)
-	}
-
-	fmt.Fprintf(w, "\n")
-	fmt.Fprintf(w, "/*** APIs (not present) */\n")
-	for _, symbol := range notPresent {
-		writeDefine(symbol, "0", w)
-		fmt.Fprintf(w, "\n")
-	}
-}
-
 func write(cfg Cfg, w io.Writer) {
 	WritePreamble(w)
 
@@ -889,12 +888,6 @@ func write(cfg Cfg, w io.Writer) {
 	writeSettings(cfg, w)
 	fmt.Fprintf(w, "\n")
 
-	writePkgsPresent(cfg.Roster, w)
-	fmt.Fprintf(w, "\n")
-
-	writeApisPresent(cfg.Roster, w)
-	fmt.Fprintf(w, "\n")
-
 	fmt.Fprintf(w, "#endif\n")
 }
 
@@ -913,14 +906,12 @@ func writeRequired(contents []byte, path string) (bool, error) {
 	return rc != 0, nil
 }
 
-func headerPath(targetPath string) string {
-	return fmt.Sprintf("%s/%s/%s", targetPath, SYSCFG_INCLUDE_SUBDIR,
+func headerPath(includeDir string) string {
+	return fmt.Sprintf("%s/%s/%s", includeDir, SYSCFG_INCLUDE_SUBDIR,
 		SYSCFG_HEADER_FILENAME)
 }
 
-func EnsureWritten(cfg Cfg, lpkgs []*pkg.LocalPackage,
-	apis []string, targetPath string) error {
-
+func EnsureWritten(cfg Cfg, includeDir string) error {
 	if err := calcPriorities(cfg, CFG_SETTING_TYPE_TASK_PRIO,
 		SYSCFG_TASK_PRIO_MAX, false); err != nil {
 
@@ -933,15 +924,10 @@ func EnsureWritten(cfg Cfg, lpkgs []*pkg.LocalPackage,
 		return err
 	}
 
-	cfg.buildCfgRoster(lpkgs, apis)
-	if err := fixupSettings(cfg); err != nil {
-		return err
-	}
-
 	buf := bytes.Buffer{}
 	write(cfg, &buf)
 
-	path := headerPath(targetPath)
+	path := headerPath(includeDir)
 
 	writeReqd, err := writeRequired(buf.Bytes(), path)
 	if err != nil {

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/dd715c24/newt/sysinit/sysinit.go
----------------------------------------------------------------------
diff --git a/newt/sysinit/sysinit.go b/newt/sysinit/sysinit.go
index 8e8188b..5d6d392 100644
--- a/newt/sysinit/sysinit.go
+++ b/newt/sysinit/sysinit.go
@@ -35,12 +35,6 @@ import (
 	"mynewt.apache.org/newt/util"
 )
 
-const FILENAME = "sysinit.c"
-const SYSINIT_FN_SIG = `void
-sysinit(void)
-{
-`
-
 func buildStageMap(pkgs []*pkg.LocalPackage) map[int][]*pkg.LocalPackage {
 	sm := map[int][]*pkg.LocalPackage{}
 
@@ -54,6 +48,7 @@ func buildStageMap(pkgs []*pkg.LocalPackage) map[int][]*pkg.LocalPackage {
 
 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())
 	}
@@ -80,7 +75,9 @@ func onlyPkgsWithInit(pkgs []*pkg.LocalPackage) []*pkg.LocalPackage {
 	return good
 }
 
-func write(pkgs []*pkg.LocalPackage, w io.Writer) {
+func write(pkgs []*pkg.LocalPackage, isLoader bool,
+	w io.Writer) {
+
 	goodPkgs := onlyPkgsWithInit(pkgs)
 	stageMap := buildStageMap(goodPkgs)
 
@@ -94,19 +91,32 @@ func write(pkgs []*pkg.LocalPackage, w io.Writer) {
 
 	syscfg.WritePreamble(w)
 
+	if isLoader {
+		fmt.Fprintf(w, "#if SPLIT_LOADER\n\n")
+	} else {
+		fmt.Fprintf(w, "#if !SPLIT_LOADER\n\n")
+	}
+
 	writePrototypes(goodPkgs, w)
-	fmt.Fprintf(w, "\n")
 
-	fmt.Fprintf(w, "%s", SYSINIT_FN_SIG)
-	for i, s := range stages {
-		if i != 0 {
-			fmt.Fprintf(w, "\n")
-		}
+	var fnName string
+	if isLoader {
+		fnName = "sysinit_loader"
+	} else {
+		fnName = "sysinit_app"
+	}
+
+	fmt.Fprintf(w, "\n")
+	fmt.Fprintf(w, "void\n%s(void)\n{\n", fnName)
+	fmt.Fprintf(w, "    os_init();\n")
 
+	for _, s := range stages {
+		fmt.Fprintf(w, "\n")
 		writeStage(s, stageMap[s], w)
 	}
 
-	fmt.Fprintf(w, "}\n")
+	fmt.Fprintf(w, "}\n\n")
+	fmt.Fprintf(w, "#endif\n")
 }
 
 func writeRequired(contents []byte, path string) (bool, error) {
@@ -124,11 +134,18 @@ func writeRequired(contents []byte, path string) (bool, error) {
 	return rc != 0, nil
 }
 
-func EnsureWritten(pkgs []*pkg.LocalPackage, targetPath string) error {
+func EnsureWritten(pkgs []*pkg.LocalPackage, srcDir string, targetName string,
+	isLoader bool) error {
+
 	buf := bytes.Buffer{}
-	write(pkgs, &buf)
+	write(pkgs, isLoader, &buf)
 
-	path := fmt.Sprintf("%s/src/%s", targetPath, FILENAME)
+	var path string
+	if isLoader {
+		path = fmt.Sprintf("%s/%s-sysinit-loader.c", srcDir, targetName)
+	} else {
+		path = fmt.Sprintf("%s/%s-sysinit-app.c", srcDir, targetName)
+	}
 
 	writeReqd, err := writeRequired(buf.Bytes(), path)
 	if err != nil {

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/dd715c24/newt/target/target.go
----------------------------------------------------------------------
diff --git a/newt/target/target.go b/newt/target/target.go
index eadfa60..00d3e72 100644
--- a/newt/target/target.go
+++ b/newt/target/target.go
@@ -122,7 +122,6 @@ func (target *Target) Validate(appRequired bool) error {
 			return util.NewNewtError("Target does not specify an app " +
 				"package (target.app)")
 		}
-
 		app := target.resolvePackageName(target.AppName)
 		if app == nil {
 			return util.FmtNewtError("Could not resolve app package: %s",
@@ -134,6 +133,21 @@ func (target *Target) Validate(appRequired bool) error {
 				"type app; type is: %s\n", app.Name(),
 				pkg.PackageTypeNames[app.Type()])
 		}
+
+		if target.LoaderName != "" {
+			loader := target.resolvePackageName(target.LoaderName)
+			if loader == nil {
+				return util.FmtNewtError(
+					"Could not resolve loader package: %s", target.LoaderName)
+			}
+
+			if loader.Type() != pkg.PACKAGE_TYPE_APP {
+				return util.FmtNewtError(
+					"target.loader package (%s) is not of type app; type "+
+						"is: %s\n", loader.Name(),
+					pkg.PackageTypeNames[loader.Type()])
+			}
+		}
 	}
 
 	return nil

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/dd715c24/newt/toolchain/compiler.go
----------------------------------------------------------------------
diff --git a/newt/toolchain/compiler.go b/newt/toolchain/compiler.go
index a961051..c2cfa7d 100644
--- a/newt/toolchain/compiler.go
+++ b/newt/toolchain/compiler.go
@@ -254,9 +254,6 @@ func (c *Compiler) load(compilerDir string, buildProfile string) error {
 			buildProfile, runtime.GOOS)
 	}
 
-	log.Infof("ccPath = %s, arPath = %s, flags = %s", c.ccPath,
-		c.arPath, c.info.Cflags)
-
 	return nil
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/dd715c24/newt/vendor/mynewt.apache.org/newt/util/util.go
----------------------------------------------------------------------
diff --git a/newt/vendor/mynewt.apache.org/newt/util/util.go b/newt/vendor/mynewt.apache.org/newt/util/util.go
index 930c24e..ad517cd 100644
--- a/newt/vendor/mynewt.apache.org/newt/util/util.go
+++ b/newt/vendor/mynewt.apache.org/newt/util/util.go
@@ -82,6 +82,13 @@ func FmtNewtError(format string, args ...interface{}) *NewtError {
 	return NewNewtError(fmt.Sprintf(format, args...))
 }
 
+func PreNewtError(err error, format string, args ...interface{}) *NewtError {
+	baseErr := err.(*NewtError)
+	baseErr.Text = fmt.Sprintf(format, args...) + "; " + baseErr.Text
+
+	return baseErr
+}
+
 // Print Silent, Quiet and Verbose aware status messages to stdout.
 func StatusMessage(level int, message string, args ...interface{}) {
 	if Verbosity >= level {

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/dd715c24/util/util.go
----------------------------------------------------------------------
diff --git a/util/util.go b/util/util.go
index 27b407c..ad517cd 100644
--- a/util/util.go
+++ b/util/util.go
@@ -32,6 +32,7 @@ import (
 	"path/filepath"
 	"runtime"
 	"sort"
+	"strconv"
 	"strings"
 	"syscall"
 	"time"
@@ -81,6 +82,13 @@ func FmtNewtError(format string, args ...interface{}) *NewtError {
 	return NewNewtError(fmt.Sprintf(format, args...))
 }
 
+func PreNewtError(err error, format string, args ...interface{}) *NewtError {
+	baseErr := err.(*NewtError)
+	baseErr.Text = fmt.Sprintf(format, args...) + "; " + baseErr.Text
+
+	return baseErr
+}
+
 // Print Silent, Quiet and Verbose aware status messages to stdout.
 func StatusMessage(level int, message string, args ...interface{}) {
 	if Verbosity >= level {
@@ -422,3 +430,23 @@ func SortFields(wsSepStrings ...string) []string {
 	sort.Strings(slice)
 	return slice
 }
+
+func AtoiNoOct(s string) (int, error) {
+	var runLen int
+	for runLen = 0; runLen < len(s)-1; runLen++ {
+		if s[runLen] != '0' || s[runLen+1] == 'x' {
+			break
+		}
+	}
+
+	if runLen > 0 {
+		s = s[runLen:]
+	}
+
+	i, err := strconv.ParseInt(s, 0, 0)
+	if err != nil {
+		return 0, NewNewtError(err.Error())
+	}
+
+	return int(i), nil
+}


[2/2] incubator-mynewt-newt git commit: Syscfg / sysinit update

Posted by cc...@apache.org.
Syscfg / sysinit update

    * Move syscfg from pkg.yml to syscfg.yml.
    * Fix for split images.
    * Don't allow lateral overrides by library packages.
    * System initialization is done via sysinit() now, not os_init().


Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/commit/dd715c24
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/tree/dd715c24
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/diff/dd715c24

Branch: refs/heads/develop
Commit: dd715c24b20d18fd77e52c02cab1a9f860ed329f
Parents: 23179e2
Author: Christopher Collins <cc...@apache.org>
Authored: Wed Sep 28 16:29:24 2016 -0700
Committer: Christopher Collins <cc...@apache.org>
Committed: Sun Oct 2 13:39:41 2016 -0700

----------------------------------------------------------------------
 newt/builder/build.go                           | 359 ++++-------
 newt/builder/buildpackage.go                    | 254 +++-----
 newt/builder/buildutil.go                       | 120 ++--
 newt/builder/library.go                         |   9 +-
 newt/builder/load.go                            |  43 +-
 newt/builder/size.go                            |  16 +-
 newt/builder/targetbuild.go                     | 418 +++++++------
 newt/cli/build_cmds.go                          |  98 ++-
 newt/cli/complete_cmd.go                        |   3 +-
 newt/cli/image_cmds.go                          |  37 +-
 newt/cli/project_cmds.go                        |  21 +-
 newt/cli/run_cmds.go                            |  52 +-
 newt/cli/target_cmds.go                         |  71 ++-
 newt/cli/util.go                                |  21 -
 newt/cli/vars.go                                |   7 +-
 newt/image/image.go                             |   4 +-
 newt/newt.go                                    |   7 +-
 newt/pkg/bsp_package.go                         |  12 +-
 newt/pkg/localpackage.go                        |  45 +-
 newt/pkg/package.go                             |   2 +
 newt/pkg/packageutil.go                         |   7 +
 newt/project/project.go                         |  60 +-
 newt/repo/repo.go                               |   3 +-
 newt/resolve/resolve.go                         | 540 ++++++++++++++++
 newt/syscfg/syscfg.go                           | 610 +++++++++----------
 newt/sysinit/sysinit.go                         |  51 +-
 newt/target/target.go                           |  16 +-
 newt/toolchain/compiler.go                      |   3 -
 newt/vendor/mynewt.apache.org/newt/util/util.go |   7 +
 util/util.go                                    |  28 +
 30 files changed, 1701 insertions(+), 1223 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/dd715c24/newt/builder/build.go
----------------------------------------------------------------------
diff --git a/newt/builder/build.go b/newt/builder/build.go
index 271372c..5d57153 100644
--- a/newt/builder/build.go
+++ b/newt/builder/build.go
@@ -23,191 +23,123 @@ import (
 	"fmt"
 	"os"
 	"path/filepath"
-	"regexp"
-	"strings"
 
 	log "github.com/Sirupsen/logrus"
 
 	"mynewt.apache.org/newt/newt/pkg"
 	"mynewt.apache.org/newt/newt/project"
+	"mynewt.apache.org/newt/newt/repo"
 	"mynewt.apache.org/newt/newt/symbol"
 	"mynewt.apache.org/newt/newt/syscfg"
-	"mynewt.apache.org/newt/newt/sysinit"
 	"mynewt.apache.org/newt/newt/target"
 	"mynewt.apache.org/newt/newt/toolchain"
 	"mynewt.apache.org/newt/util"
 )
 
 type Builder struct {
-	Packages         map[*pkg.LocalPackage]*BuildPackage
-	apis             map[string]*BuildPackage
+	PkgMap map[*pkg.LocalPackage]*BuildPackage
+
+	apiMap           map[string]*BuildPackage
 	appPkg           *BuildPackage
-	BspPkg           *pkg.LocalPackage
+	bspPkg           *BuildPackage
+	compilerPkg      *BuildPackage
+	targetPkg        *BuildPackage
 	compilerInfo     *toolchain.CompilerInfo
-	target           *TargetBuilder
+	targetBuilder    *TargetBuilder
+	cfg              syscfg.Cfg
 	linkerScript     string
 	buildName        string
-	LinkElf          string
+	linkElf          string
 	injectedSettings map[string]string
-
-	Cfg syscfg.Cfg
 }
 
-func NewBuilder(t *TargetBuilder, buildName string) (*Builder, error) {
+func NewBuilder(t *TargetBuilder, buildName string, lpkgs []*pkg.LocalPackage,
+	apiMap map[string]*pkg.LocalPackage, cfg syscfg.Cfg) (*Builder, error) {
+
 	b := &Builder{
-		Packages:         map[*pkg.LocalPackage]*BuildPackage{},
+		PkgMap: make(map[*pkg.LocalPackage]*BuildPackage, len(lpkgs)),
+		cfg:    cfg,
+
 		buildName:        buildName,
-		apis:             map[string]*BuildPackage{},
-		LinkElf:          "",
-		target:           t,
+		apiMap:           make(map[string]*BuildPackage, len(apiMap)),
+		linkElf:          "",
+		targetBuilder:    t,
 		injectedSettings: map[string]string{},
-		Cfg:              syscfg.NewCfg(),
 	}
 
-	return b, nil
-}
-
-func (b *Builder) AddPackage(npkg *pkg.LocalPackage) *BuildPackage {
-	// Don't allow nil entries to the map
-	if npkg == nil {
-		panic("Cannot add nil package builder map")
+	for _, lpkg := range lpkgs {
+		if _, err := b.addPackage(lpkg); err != nil {
+			return nil, err
+		}
 	}
 
-	bpkg := b.Packages[npkg]
-	if bpkg == nil {
-		bpkg = NewBuildPackage(npkg)
-		b.Packages[npkg] = bpkg
+	// Create a pseudo build package for the generated sysinit code.
+	if _, err := b.addSysinitBpkg(); err != nil {
+		return nil, err
 	}
 
-	return bpkg
-}
-
-// @return bool                 true if this is a new API.
-func (b *Builder) AddApi(apiString string, bpkg *BuildPackage) bool {
-	curBpkg := b.apis[apiString]
-	if curBpkg == nil {
-		b.apis[apiString] = bpkg
-		return true
-	} else {
-		if curBpkg != bpkg {
-			util.StatusMessage(util.VERBOSITY_QUIET,
-				"Warning: API conflict: %s (%s <-> %s)\n", apiString,
-				curBpkg.Name(), bpkg.Name())
+	for api, lpkg := range apiMap {
+		bpkg := b.PkgMap[lpkg]
+		if bpkg == nil {
+			for _, lpkg := range b.sortedLocalPackages() {
+				log.Debugf("    * %s", lpkg.Name())
+			}
+			return nil, util.FmtNewtError(
+				"Unexpected unsatisfied API: %s; required by: %s", api,
+				lpkg.Name())
 		}
-		return false
-	}
-}
-
-func (b *Builder) ApiNames() []string {
-	apiNames := make([]string, len(b.apis), len(b.apis))
 
-	i := 0
-	for api, _ := range b.apis {
-		apiNames[i] = api
-		i += 1
+		b.apiMap[api] = bpkg
 	}
 
-	return apiNames
+	return b, nil
 }
 
-// @return                      changed,err
-func (b *Builder) reloadCfg() (bool, error) {
-	apis := make([]string, len(b.apis))
-	i := 0
-	for api, _ := range b.apis {
-		apis[i] = api
-		i++
-	}
-
-	// Determine which features have been detected so far.  The feature map is
-	// required for reloading syscfg, as features may unlock additional
-	// settings.
-	features := b.Cfg.Features()
-	cfg, err := syscfg.Read(b.sortedLocalPackages(), apis, b.injectedSettings,
-		features)
-	if err != nil {
-		return false, err
-	}
-
-	changed := false
-	for k, v := range cfg.Settings {
-		oldval, ok := b.Cfg.Settings[k]
-		if !ok || len(oldval.History) != len(v.History) {
-			b.Cfg = cfg
-			changed = true
-		}
+func (b *Builder) addPackage(npkg *pkg.LocalPackage) (*BuildPackage, error) {
+	// Don't allow nil entries to the map
+	if npkg == nil {
+		panic("Cannot add nil package builder map")
 	}
 
-	return changed, nil
-}
+	bpkg := b.PkgMap[npkg]
+	if bpkg == nil {
+		bpkg = NewBuildPackage(npkg)
 
-func (b *Builder) loadDepsOnce() (bool, error) {
-	// Circularly resolve dependencies, APIs, and required APIs until no new
-	// ones exist.
-	newDeps := false
-	for {
-		reprocess := false
-		for _, bpkg := range b.Packages {
-			newDeps, err := bpkg.Resolve(b, b.Cfg)
-			if err != nil {
-				return false, err
+		switch bpkg.Type() {
+		case pkg.PACKAGE_TYPE_APP:
+			if b.appPkg != nil {
+				return nil, pkgTypeConflictErr(b.appPkg, bpkg)
 			}
+			b.appPkg = bpkg
 
-			if newDeps {
-				// The new dependencies need to be processed.  Iterate again
-				// after this iteration completes.
-				reprocess = true
+		case pkg.PACKAGE_TYPE_BSP:
+			if b.bspPkg != nil {
+				return nil, pkgTypeConflictErr(b.bspPkg, bpkg)
 			}
-		}
-
-		if !reprocess {
-			break
-		}
-	}
-
-	return newDeps, nil
-}
-
-func (b *Builder) loadDeps() error {
-	if _, err := b.loadDepsOnce(); err != nil {
-		return err
-	}
+			b.bspPkg = bpkg
 
-	for {
-		cfgChanged, err := b.reloadCfg()
-		if err != nil {
-			return err
-		}
-		if cfgChanged {
-			// A new supported feature was discovered.  It is impossible
-			// to determine what new dependency and API requirements are
-			// generated as a result.  All packages need to be
-			// reprocessed.
-			for _, bpkg := range b.Packages {
-				bpkg.depsResolved = false
-				bpkg.apisSatisfied = false
+		case pkg.PACKAGE_TYPE_COMPILER:
+			if b.compilerPkg != nil {
+				return nil, pkgTypeConflictErr(b.compilerPkg, bpkg)
 			}
-		}
+			b.compilerPkg = bpkg
 
-		newDeps, err := b.loadDepsOnce()
-		if err != nil {
-			return err
+		case pkg.PACKAGE_TYPE_TARGET:
+			if b.targetPkg != nil {
+				return nil, pkgTypeConflictErr(b.targetPkg, bpkg)
+			}
+			b.targetPkg = bpkg
 		}
 
-		if !newDeps && !cfgChanged {
-			break
-		}
+		b.PkgMap[npkg] = bpkg
 	}
 
-	// Log the final syscfg.
-	b.Cfg.Log()
-
-	// Report syscfg errors.
-	if err := b.Cfg.DetectErrors(); err != nil {
-		return err
-	}
+	return bpkg, nil
+}
 
-	return nil
+func pkgTypeConflictErr(p1 *BuildPackage, p2 *BuildPackage) error {
+	return util.FmtNewtError("Two %s packages in build: %s, %s",
+		pkg.PackageTypeNames[p1.Type()], p1.Name(), p2.Name())
 }
 
 // Recursively compiles all the .c and .s files in the specified directory.
@@ -267,7 +199,7 @@ func buildDir(srcDir string, c *toolchain.Compiler, arch string,
 func (b *Builder) newCompiler(bpkg *BuildPackage,
 	dstDir string) (*toolchain.Compiler, error) {
 
-	c, err := b.target.NewCompiler(dstDir)
+	c, err := b.targetBuilder.NewCompiler(dstDir)
 	if err != nil {
 		return nil, err
 	}
@@ -288,7 +220,7 @@ func (b *Builder) newCompiler(bpkg *BuildPackage,
 
 // Compiles and archives a package.
 func (b *Builder) buildPackage(bpkg *BuildPackage) error {
-	c, err := b.newCompiler(bpkg, b.PkgBinDir(bpkg.Name()))
+	c, err := b.newCompiler(bpkg, b.PkgBinDir(bpkg))
 	if err != nil {
 		return err
 	}
@@ -316,7 +248,7 @@ func (b *Builder) buildPackage(bpkg *BuildPackage) error {
 	}
 
 	for _, dir := range srcDirs {
-		if err = buildDir(dir, c, b.target.Bsp.Arch, nil); err != nil {
+		if err = buildDir(dir, c, b.targetBuilder.bspPkg.Arch, nil); err != nil {
 			return err
 		}
 	}
@@ -325,7 +257,7 @@ func (b *Builder) buildPackage(bpkg *BuildPackage) error {
 	if err := os.Chdir(bpkg.BasePath() + "/"); err != nil {
 		return util.NewNewtError(err.Error())
 	}
-	archiveFile := b.ArchivePath(bpkg.Name())
+	archiveFile := b.ArchivePath(bpkg)
 	if err = c.CompileArchive(archiveFile); err != nil {
 		return err
 	}
@@ -334,11 +266,10 @@ func (b *Builder) buildPackage(bpkg *BuildPackage) error {
 }
 
 func (b *Builder) RemovePackages(cmn map[string]bool) error {
-
 	for pkgName, _ := range cmn {
-		for lp, bpkg := range b.Packages {
+		for lp, bpkg := range b.PkgMap {
 			if bpkg.Name() == pkgName {
-				delete(b.Packages, lp)
+				delete(b.PkgMap, lp)
 			}
 		}
 	}
@@ -347,7 +278,7 @@ func (b *Builder) RemovePackages(cmn map[string]bool) error {
 
 func (b *Builder) ExtractSymbolInfo() (error, *symbol.SymbolMap) {
 	syms := symbol.NewSymbolMap()
-	for _, bpkg := range b.Packages {
+	for _, bpkg := range b.PkgMap {
 		err, sm := b.ParseObjectLibrary(bpkg)
 		if err == nil {
 			syms, err = (*syms).Merge(sm)
@@ -361,24 +292,28 @@ func (b *Builder) ExtractSymbolInfo() (error, *symbol.SymbolMap) {
 
 func (b *Builder) link(elfName string, linkerScript string,
 	keepSymbols []string) error {
-	c, err := b.newCompiler(b.appPkg, b.PkgBinDir(elfName))
+
+	c, err := b.newCompiler(b.appPkg, b.FileBinDir(elfName))
 	if err != nil {
 		return err
 	}
 
-	/* always used the trimmed archive files */
+	/* Always used the trimmed archive files. */
 	pkgNames := []string{}
 
-	for _, bpkg := range b.Packages {
-		if util.NodeExist(b.ArchivePath(bpkg.Name())) {
-			pkgNames = append(pkgNames, b.ArchivePath(bpkg.Name()))
+	for _, bpkg := range b.PkgMap {
+		if util.NodeExist(b.ArchivePath(bpkg)) {
+			pkgNames = append(pkgNames, b.ArchivePath(bpkg))
 		}
 	}
 
+	// Include sysinit archive in elf file. */
+	//pkgNames = append(pkgNames, SysinitArchivePath(b.targetPkg.Name()))
+
 	if linkerScript != "" {
-		c.LinkerScript = b.target.Bsp.BasePath() + "/" + linkerScript
+		c.LinkerScript = b.bspPkg.BasePath() + "/" + linkerScript
 	}
-	err = c.CompileElf(elfName, pkgNames, keepSymbols, b.LinkElf)
+	err = c.CompileElf(elfName, pkgNames, keepSymbols, b.linkElf)
 	if err != nil {
 		return err
 	}
@@ -389,43 +324,16 @@ func (b *Builder) link(elfName string, linkerScript string,
 // Populates the builder with all the packages that need to be built and
 // configures each package's build settings.  After this function executes,
 // packages are ready to be built.
-func (b *Builder) PrepBuild(appPkg *pkg.LocalPackage,
-	bspPkg *pkg.LocalPackage, targetPkg *pkg.LocalPackage) error {
-
-	// Seed the builder with the app (if present), bsp, and target packages.
-
-	b.BspPkg = bspPkg
-
-	var appBpkg *BuildPackage
-	if appPkg != nil {
-		appBpkg = b.Packages[appPkg]
-		if appBpkg == nil {
-			appBpkg = b.AddPackage(appPkg)
+func (b *Builder) PrepBuild() error {
+	// Populate the full set of packages to be built.
+	for _, bpkg := range b.PkgMap {
+		if err := bpkg.resolveDeps(b.cfg, b.apiMap); err != nil {
+			return err
 		}
-		b.appPkg = appBpkg
-	}
-
-	bspBpkg := b.Packages[bspPkg]
-
-	if bspBpkg == nil {
-		bspBpkg = b.AddPackage(bspPkg)
-	}
-
-	targetBpkg := b.AddPackage(targetPkg)
-
-	// Populate the full set of packages to be built and resolve the feature
-	// set.
-	if err := b.loadDeps(); err != nil {
-		return err
 	}
 
 	b.logDepInfo()
 
-	// Terminate if any package has an unmet API requirement.
-	if err := b.verifyApisSatisfied(); err != nil {
-		return err
-	}
-
 	// Populate the base set of compiler flags.  Flags from the following
 	// packages get applied to every source file:
 	//     * target
@@ -446,17 +354,17 @@ func (b *Builder) PrepBuild(appPkg *pkg.LocalPackage,
 
 	// Target flags.
 	log.Debugf("Generating build flags for target %s",
-		b.target.target.FullName())
-	targetCi, err := targetBpkg.CompilerInfo(b)
+		b.targetPkg.FullName())
+	targetCi, err := b.targetPkg.CompilerInfo(b)
 	if err != nil {
 		return err
 	}
 	baseCi.AddCompilerInfo(targetCi)
 
 	// App flags.
-	if appBpkg != nil {
-		log.Debugf("Generating build flags for app %s", appPkg.FullName())
-		appCi, err := appBpkg.CompilerInfo(b)
+	if b.appPkg != nil {
+		log.Debugf("Generating build flags for app %s", b.appPkg.FullName())
+		appCi, err := b.appPkg.CompilerInfo(b)
 		if err != nil {
 			return err
 		}
@@ -465,71 +373,51 @@ func (b *Builder) PrepBuild(appPkg *pkg.LocalPackage,
 	}
 
 	// Bsp flags.
-	log.Debugf("Generating build flags for bsp %s", bspPkg.FullName())
-	bspCi, err := bspBpkg.CompilerInfo(b)
+	log.Debugf("Generating build flags for bsp %s", b.bspPkg.FullName())
+	bspCi, err := b.bspPkg.CompilerInfo(b)
 	if err != nil {
 		return err
 	}
 
 	// Define a cpp symbol indicating the BSP architecture, name of the
 	// BSP and app.
-	bspCi.Cflags = append(bspCi.Cflags, "-DARCH_"+b.target.Bsp.Arch)
+	bspCi.Cflags = append(bspCi.Cflags, "-DARCH_"+b.targetBuilder.bspPkg.Arch)
 	bspCi.Cflags = append(bspCi.Cflags,
-		"-DBSP_NAME=\""+filepath.Base(b.target.Bsp.Name())+"\"")
-	if appPkg != nil {
+		"-DBSP_NAME=\""+filepath.Base(b.bspPkg.Name())+"\"")
+	if b.appPkg != nil {
 		bspCi.Cflags = append(bspCi.Cflags,
-			"-DAPP_NAME=\""+filepath.Base(appPkg.Name())+"\"")
+			"-DAPP_NAME=\""+filepath.Base(b.appPkg.Name())+"\"")
 	}
 	baseCi.AddCompilerInfo(bspCi)
 
+	// All packages have access to the generated syscfg header directory.
+	baseCi.Cflags = append(baseCi.Cflags,
+		"-I"+GeneratedIncludeDir(b.targetPkg.Name()))
+
 	// Note: Compiler flags get added at the end, after the flags for library
 	// package being built are calculated.
 	b.compilerInfo = baseCi
 
-	lpkgs := b.sortedLocalPackages()
-	if err := syscfg.EnsureWritten(b.Cfg, lpkgs, b.ApiNames(),
-		targetPkg.BasePath()); err != nil {
-		return err
-	}
-
-	if err := sysinit.EnsureWritten(lpkgs, targetPkg.BasePath()); err != nil {
-		return err
-	}
-
-	b.compilerInfo = baseCi
-
 	return nil
 }
 
-func (b *Builder) matchFeature(flist []map[string]interface{},
-	pkg pkg.Package, featureName string) bool {
-
-	fullName := ""
-	if pkg != nil {
-		fullName = pkg.FullName()
-	}
-
-	for _, matchList := range flist {
-		for pkgDesc, featureDesc := range matchList {
-			re, _ := regexp.Compile(pkgDesc)
-			if re.MatchString(fullName) {
-				if strings.Compare(featureDesc.(string), featureName) == 0 {
-					return true
-				}
-			}
-		}
-	}
-
-	return false
-}
-
 func (b *Builder) AddCompilerInfo(info *toolchain.CompilerInfo) {
 	b.compilerInfo.AddCompilerInfo(info)
 }
 
+func (b *Builder) addSysinitBpkg() (*BuildPackage, error) {
+	lpkg := pkg.NewLocalPackage(b.targetPkg.Repo().(*repo.Repo),
+		GeneratedBaseDir(b.targetPkg.Name()))
+	lpkg.SetName(pkg.ShortName(b.targetPkg) + "-sysinit-" + b.buildName)
+	lpkg.SetType(pkg.PACKAGE_TYPE_GENERATED)
+
+	return b.addPackage(lpkg)
+}
+
 func (b *Builder) Build() error {
 	// Build the packages alphabetically to ensure a consistent order.
 	bpkgs := b.sortedBuildPackages()
+
 	for _, bpkg := range bpkgs {
 		if err := b.buildPackage(bpkg); err != nil {
 			return err
@@ -568,7 +456,7 @@ func (b *Builder) TestLink(linkerScript string) error {
 }
 
 func (b *Builder) pkgWithPath(path string) *BuildPackage {
-	for _, p := range b.Packages {
+	for _, p := range b.PkgMap {
 		if p.BasePath() == path {
 			return p
 		}
@@ -608,7 +496,8 @@ func (b *Builder) Test(p *pkg.LocalPackage) error {
 		}
 	}
 
-	testFilename := b.TestExePath(p.Name())
+	testBpkg := b.PkgMap[p]
+	testFilename := b.TestExePath(testBpkg)
 	if err := b.link(testFilename, "", nil); err != nil {
 		return err
 	}
@@ -633,7 +522,7 @@ func (b *Builder) Test(p *pkg.LocalPackage) error {
 func (b *Builder) FetchSymbolMap() (error, *symbol.SymbolMap) {
 	loader_sm := symbol.NewSymbolMap()
 
-	for _, value := range b.Packages {
+	for _, value := range b.PkgMap {
 		err, sm := b.ParseObjectLibrary(value)
 		if err == nil {
 			util.StatusMessage(util.VERBOSITY_VERBOSE,
@@ -649,7 +538,7 @@ func (b *Builder) FetchSymbolMap() (error, *symbol.SymbolMap) {
 }
 
 func (b *Builder) GetTarget() *target.Target {
-	return b.target.GetTarget()
+	return b.targetBuilder.GetTarget()
 }
 
 func (b *Builder) buildRomElf(common *symbol.SymbolMap) error {
@@ -657,7 +546,7 @@ func (b *Builder) buildRomElf(common *symbol.SymbolMap) error {
 	/* check dependencies on the ROM ELF.  This is really dependent on
 	 * all of the .a files, but since we already depend on the loader
 	 * .as to build the initial elf, we only need to check the app .a */
-	c, err := b.target.NewCompiler(b.AppElfPath())
+	c, err := b.targetBuilder.NewCompiler(b.AppElfPath())
 	d := toolchain.NewDepTracker(c)
 	if err != nil {
 		return err
@@ -666,8 +555,8 @@ func (b *Builder) buildRomElf(common *symbol.SymbolMap) error {
 	archNames := []string{}
 
 	/* build the set of archive file names */
-	for _, bpkg := range b.Packages {
-		archivePath := b.ArchivePath(bpkg.Name())
+	for _, bpkg := range b.PkgMap {
+		archivePath := b.ArchivePath(bpkg)
 		if util.NodeExist(archivePath) {
 			archNames = append(archNames, archivePath)
 		}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/dd715c24/newt/builder/buildpackage.go
----------------------------------------------------------------------
diff --git a/newt/builder/buildpackage.go b/newt/builder/buildpackage.go
index 596b359..1806901 100644
--- a/newt/builder/buildpackage.go
+++ b/newt/builder/buildpackage.go
@@ -20,7 +20,6 @@
 package builder
 
 import (
-	"fmt"
 	"os"
 	"path/filepath"
 	"regexp"
@@ -35,26 +34,11 @@ import (
 	"mynewt.apache.org/newt/util"
 )
 
-// Indicates whether a package's API dependency has been another package.
-type reqApiStatus int
-
-const (
-	REQ_API_STATUS_UNSATISFIED reqApiStatus = iota
-	REQ_API_STATUS_SATISFIED
-)
-
 type BuildPackage struct {
 	*pkg.LocalPackage
 
-	ci *toolchain.CompilerInfo
-
+	ci                *toolchain.CompilerInfo
 	SourceDirectories []string
-
-	// Keeps track of API requirements and whether they are satisfied.
-	reqApiMap map[string]reqApiStatus
-
-	depsResolved  bool
-	apisSatisfied bool
 }
 
 // Recursively iterates through an pkg's dependencies, adding each pkg
@@ -74,15 +58,16 @@ func (bpkg *BuildPackage) collectDepsAux(b *Builder,
 		}
 
 		// Get pkg structure
-		dpkg := project.GetProject().ResolveDependency(dep).(*pkg.LocalPackage)
-		if dpkg == nil {
-			return util.NewNewtError("Cannot resolve dependency " + dep.String())
+		p := project.GetProject().ResolveDependency(dep)
+		if p == nil {
+			return util.FmtNewtError("Cannot resolve dependency %+v", dep)
 		}
+		dpkg := p.(*pkg.LocalPackage)
 
-		dbpkg := b.Packages[dpkg]
+		dbpkg := b.PkgMap[dpkg]
 		if dbpkg == nil {
-			return util.NewNewtError(fmt.Sprintf("Package not found (%s)",
-				dpkg.Name()))
+			return util.FmtNewtError("Package not found %s; required by %s",
+				dpkg.Name(), bpkg.Name())
 		}
 
 		if err := dbpkg.collectDepsAux(b, set); err != nil {
@@ -113,7 +98,9 @@ func (bpkg *BuildPackage) collectDeps(b *Builder) ([]*BuildPackage, error) {
 
 // Calculates the include paths exported by the specified pkg and all of
 // its recursive dependencies.
-func (bpkg *BuildPackage) recursiveIncludePaths(b *Builder) ([]string, error) {
+func (bpkg *BuildPackage) recursiveIncludePaths(
+	b *Builder) ([]string, error) {
+
 	deps, err := bpkg.collectDeps(b)
 	if err != nil {
 		return nil, err
@@ -121,17 +108,14 @@ func (bpkg *BuildPackage) recursiveIncludePaths(b *Builder) ([]string, error) {
 
 	incls := []string{}
 	for _, p := range deps {
-		incls = append(incls, p.publicIncludeDirs(b)...)
+		incls = append(incls, p.publicIncludeDirs(b.targetBuilder.bspPkg)...)
 	}
 
 	return incls, nil
 }
 
-func (bpkg *BuildPackage) CompilerInfo(b *Builder) (*toolchain.CompilerInfo, error) {
-	if !bpkg.depsResolved || !bpkg.apisSatisfied {
-		return nil, util.NewNewtError("Package must be resolved before " +
-			"compiler info is fetched; package=" + bpkg.Name())
-	}
+func (bpkg *BuildPackage) CompilerInfo(
+	b *Builder) (*toolchain.CompilerInfo, error) {
 
 	// If this package's compiler info has already been generated, returned the
 	// cached copy.
@@ -140,43 +124,45 @@ func (bpkg *BuildPackage) CompilerInfo(b *Builder) (*toolchain.CompilerInfo, err
 	}
 
 	ci := toolchain.NewCompilerInfo()
-	features := b.Cfg.FeaturesForLpkg(bpkg.LocalPackage)
-	ci.Cflags = newtutil.GetStringSliceFeatures(bpkg.Viper, features,
+	features := b.cfg.FeaturesForLpkg(bpkg.LocalPackage)
+	ci.Cflags = newtutil.GetStringSliceFeatures(bpkg.PkgV, features,
 		"pkg.cflags")
-	ci.Lflags = newtutil.GetStringSliceFeatures(bpkg.Viper, features,
+	ci.Lflags = newtutil.GetStringSliceFeatures(bpkg.PkgV, features,
 		"pkg.lflags")
-	ci.Aflags = newtutil.GetStringSliceFeatures(bpkg.Viper, features,
+	ci.Aflags = newtutil.GetStringSliceFeatures(bpkg.PkgV, features,
 		"pkg.aflags")
 
+	// Package-specific injected settings get specified as C flags on the
+	// command line.
 	for k, _ := range bpkg.InjectedSettings() {
 		ci.Cflags = append(ci.Cflags, syscfg.FeatureToCflag(k))
 	}
 
 	ci.IgnoreFiles = []*regexp.Regexp{}
-	ignPats := newtutil.GetStringSliceFeatures(bpkg.Viper,
+	ignPats := newtutil.GetStringSliceFeatures(bpkg.PkgV,
 		features, "pkg.ign_files")
 	for _, str := range ignPats {
 		re, err := regexp.Compile(str)
 		if err != nil {
-			return nil, util.NewNewtError("Ignore files, unable to compile re: " +
-				err.Error())
+			return nil, util.NewNewtError(
+				"Ignore files, unable to compile re: " + err.Error())
 		}
 		ci.IgnoreFiles = append(ci.IgnoreFiles, re)
 	}
 
 	ci.IgnoreDirs = []*regexp.Regexp{}
-	ignPats = newtutil.GetStringSliceFeatures(bpkg.Viper,
+	ignPats = newtutil.GetStringSliceFeatures(bpkg.PkgV,
 		features, "pkg.ign_dirs")
 	for _, str := range ignPats {
 		re, err := regexp.Compile(str)
 		if err != nil {
-			return nil, util.NewNewtError("Ignore dirs, unable to compile re: " +
-				err.Error())
+			return nil, util.NewNewtError(
+				"Ignore dirs, unable to compile re: " + err.Error())
 		}
 		ci.IgnoreDirs = append(ci.IgnoreDirs, re)
 	}
 
-	bpkg.SourceDirectories = newtutil.GetStringSliceFeatures(bpkg.Viper,
+	bpkg.SourceDirectories = newtutil.GetStringSliceFeatures(bpkg.PkgV,
 		features, "pkg.src_dirs")
 
 	includePaths, err := bpkg.recursiveIncludePaths(b)
@@ -193,128 +179,34 @@ func (bpkg *BuildPackage) CompilerInfo(b *Builder) (*toolchain.CompilerInfo, err
 // Searches for a package which can satisfy bpkg's API requirement.  If such a
 // package is found, bpkg's API requirement is marked as satisfied, and the
 // package is added to bpkg's dependency list.
-func (bpkg *BuildPackage) satisfyReqApi(b *Builder, reqApi string) bool {
-	depBpkg := b.apis[reqApi]
-	if depBpkg == nil {
-		return false
-	}
+func (bpkg *BuildPackage) satisfyReqApi(
+	reqApi string, apiPkg *BuildPackage) error {
 
 	dep := &pkg.Dependency{
-		Name: depBpkg.Name(),
-		Repo: depBpkg.Repo().Name(),
+		Name: apiPkg.Name(),
+		Repo: apiPkg.Repo().Name(),
 	}
 	bpkg.AddDep(dep)
-	bpkg.reqApiMap[reqApi] = REQ_API_STATUS_SATISFIED
-
-	// This package now has a new unresolved dependency.
-	bpkg.depsResolved = false
 
 	log.Debugf("API requirement satisfied; pkg=%s API=(%s, %s)",
 		bpkg.Name(), reqApi, dep.String())
 
-	return true
-}
-
-// @return bool                 True if this this function changed the builder
-//                                  state; another full iteration is required
-//                                  in this case.
-//         error                non-nil on failure.
-func (bpkg *BuildPackage) loadDeps(b *Builder,
-	features map[string]bool) (bool, error) {
-
-	proj := project.GetProject()
-
-	changed := false
-
-	newDeps := newtutil.GetStringSliceFeatures(bpkg.Viper, features, "pkg.deps")
-	for _, newDepStr := range newDeps {
-		newDep, err := pkg.NewDependency(bpkg.Repo(), newDepStr)
-		if err != nil {
-			return false, err
-		}
-
-		pkg, ok := proj.ResolveDependency(newDep).(*pkg.LocalPackage)
-		if !ok {
-			return false,
-				util.NewNewtError("Could not resolve package dependency " +
-					newDep.String())
-		}
-
-		if b.Packages[pkg] == nil {
-			changed = true
-			b.AddPackage(pkg)
-		}
-
-		if !bpkg.HasDep(newDep) {
-			changed = true
-			bpkg.AddDep(newDep)
-		}
-	}
-
-	// Determine if this package supports any APIs that we haven't seen
-	// yet.  If so, another full iteration is required.
-	apis := newtutil.GetStringSliceFeatures(bpkg.Viper, features, "pkg.apis")
-	for _, api := range apis {
-		newApi := b.AddApi(api, bpkg)
-		if newApi {
-			changed = true
-		}
-	}
-
-	return changed, nil
-}
-
-// @return bool                 true if a new dependency was detected as a
-//                                  result of satisfying an API for this
-//                                  package.
-func (bpkg *BuildPackage) satisfyApis(b *Builder,
-	features map[string]bool) bool {
-
-	// Assume all this package's APIs are satisfied and that no new
-	// dependencies will be detected.
-	bpkg.apisSatisfied = true
-	newDeps := false
-
-	// Determine if any of the package's API requirements can now be satisfied.
-	// If so, another full iteration is required.
-	reqApis := newtutil.GetStringSliceFeatures(bpkg.Viper, features,
-		"pkg.req_apis")
-	for _, reqApi := range reqApis {
-		reqStatus, ok := bpkg.reqApiMap[reqApi]
-		if !ok {
-			reqStatus = REQ_API_STATUS_UNSATISFIED
-			bpkg.reqApiMap[reqApi] = reqStatus
-		}
-
-		if reqStatus == REQ_API_STATUS_UNSATISFIED {
-			apiSatisfied := bpkg.satisfyReqApi(b, reqApi)
-			if apiSatisfied {
-				// An API was satisfied; the package now has a new dependency
-				// that needs to be resolved.
-				newDeps = true
-				reqStatus = REQ_API_STATUS_SATISFIED
-			}
-		}
-		if reqStatus == REQ_API_STATUS_UNSATISFIED {
-			bpkg.apisSatisfied = false
-		}
-	}
-
-	return newDeps
+	return nil
 }
 
 func (bpkg *BuildPackage) findSdkIncludes() []string {
 	sdkDir := bpkg.BasePath() + "/src/ext/"
 
 	sdkPathList := []string{}
-	err := filepath.Walk(sdkDir, func(path string, info os.FileInfo, err error) error {
-		if !info.IsDir() {
-			return nil
-		}
+	err := filepath.Walk(sdkDir,
+		func(path string, info os.FileInfo, err error) error {
+			if !info.IsDir() {
+				return nil
+			}
 
-		sdkPathList = append(sdkPathList, path)
-		return nil
-	})
+			sdkPathList = append(sdkPathList, path)
+			return nil
+		})
 	if err != nil {
 		return []string{}
 	}
@@ -322,17 +214,17 @@ func (bpkg *BuildPackage) findSdkIncludes() []string {
 	return sdkPathList
 }
 
-func (bpkg *BuildPackage) publicIncludeDirs(b *Builder) []string {
+func (bpkg *BuildPackage) publicIncludeDirs(bspPkg *pkg.BspPackage) []string {
 	pkgBase := filepath.Base(bpkg.Name())
 	bp := bpkg.BasePath()
 
 	incls := []string{
 		bp + "/include",
-		bp + "/include/" + pkgBase + "/arch/" + b.target.Bsp.Arch,
+		bp + "/include/" + pkgBase + "/arch/" + bspPkg.Arch,
 	}
 
 	if bpkg.Type() == pkg.PACKAGE_TYPE_SDK {
-		incls = append(incls, b.target.Bsp.BasePath()+"/include/bsp/")
+		incls = append(incls, bspPkg.BasePath()+"/include/bsp/")
 
 		sdkIncls := bpkg.findSdkIncludes()
 		incls = append(incls, sdkIncls...)
@@ -346,13 +238,13 @@ func (bpkg *BuildPackage) privateIncludeDirs(b *Builder) []string {
 
 	incls := []string{}
 	incls = append(incls, srcDir)
-	incls = append(incls, srcDir+"/arch/"+b.target.Bsp.Arch)
+	incls = append(incls, srcDir+"/arch/"+b.targetBuilder.bspPkg.Arch)
 
 	switch bpkg.Type() {
 	case pkg.PACKAGE_TYPE_SDK:
 		// If pkgType == SDK, include all the items in "ext" directly into the
 		// include path
-		incls = append(incls, b.target.Bsp.BasePath()+"/include/bsp/")
+		incls = append(incls, b.bspPkg.BasePath()+"/include/bsp/")
 
 		sdkIncls := bpkg.findSdkIncludes()
 		incls = append(incls, sdkIncls...)
@@ -372,51 +264,47 @@ func (bpkg *BuildPackage) privateIncludeDirs(b *Builder) []string {
 	return incls
 }
 
-// Attempts to resolve all of a build package's dependencies, identities, APIs,
-// and required APIs.  This function should be called repeatedly until the
-// package is fully resolved.
-//
-// If a dependency is resolved by this function, the new dependency needs to be
-// processed.  The caller should attempt to resolve all packages again.
-//
-// If a new supported feature is detected by this function, all pacakges need
-// to be reprocessed from scratch.  The caller should set all packages'
-// depsResolved and apisSatisfied variables to false and attempt to resolve
-// everything again.
-//
-// @return bool                 true if >=1 dependencies were resolved
-//         bool                 true if >=1 new features were detected
-func (bpkg *BuildPackage) Resolve(b *Builder,
-	cfg syscfg.Cfg) (bool, error) {
-
-	var err error
-	newDeps := false
+// Resolves all of a build package's dependencies and API requirements.
+func (bpkg *BuildPackage) resolveDeps(
+	cfg syscfg.Cfg, apiMap map[string]*BuildPackage) error {
 
 	features := cfg.FeaturesForLpkg(bpkg.LocalPackage)
 
-	if !bpkg.depsResolved {
-		newDeps, err = bpkg.loadDeps(b, features)
+	// Match each required API with the package which implements it.
+	reqApis := newtutil.GetStringSliceFeatures(bpkg.PkgV, features,
+		"pkg.req_apis")
+	for _, reqApi := range reqApis {
+		if err := bpkg.satisfyReqApi(reqApi, apiMap[reqApi]); err != nil {
+			return err
+		}
+	}
+
+	proj := project.GetProject()
+	newDeps := newtutil.GetStringSliceFeatures(bpkg.PkgV, features,
+		"pkg.deps")
+	for _, newDepStr := range newDeps {
+		newDep, err := pkg.NewDependency(bpkg.Repo(), newDepStr)
 		if err != nil {
-			return false, err
+			return err
 		}
 
-		bpkg.depsResolved = !newDeps
-	}
+		_, ok := proj.ResolveDependency(newDep).(*pkg.LocalPackage)
+		if !ok {
+			return util.NewNewtError("Could not resolve package dependency " +
+				newDep.String())
+		}
 
-	if !bpkg.apisSatisfied {
-		newApiDep := bpkg.satisfyApis(b, features)
-		if newApiDep {
-			newDeps = true
+		if !bpkg.HasDep(newDep) {
+			bpkg.AddDep(newDep)
 		}
 	}
 
-	return newDeps, nil
+	return nil
 }
 
 func NewBuildPackage(pkg *pkg.LocalPackage) *BuildPackage {
 	bpkg := &BuildPackage{
 		LocalPackage: pkg,
-		reqApiMap:    map[string]reqApiStatus{},
 	}
 
 	return bpkg

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/dd715c24/newt/builder/buildutil.go
----------------------------------------------------------------------
diff --git a/newt/builder/buildutil.go b/newt/builder/buildutil.go
index be87509..ea1e7f4 100644
--- a/newt/builder/buildutil.go
+++ b/newt/builder/buildutil.go
@@ -30,7 +30,6 @@ import (
 	"mynewt.apache.org/newt/newt/pkg"
 	"mynewt.apache.org/newt/newt/project"
 	"mynewt.apache.org/newt/newt/target"
-	"mynewt.apache.org/newt/util"
 )
 
 func BinRoot() string {
@@ -41,61 +40,88 @@ func TargetBinDir(target *target.Target) string {
 	return BinRoot() + "/" + target.Name()
 }
 
+func GeneratedBaseDir(targetName string) string {
+	return BinRoot() + "/" + targetName + "/generated"
+}
+
+func GeneratedSrcDir(targetName string) string {
+	return GeneratedBaseDir(targetName) + "/src"
+}
+
+func GeneratedIncludeDir(targetName string) string {
+	return GeneratedBaseDir(targetName) + "/include"
+}
+
+func GeneratedBinDir(targetName string) string {
+	return GeneratedBaseDir(targetName) + "/bin"
+}
+
+func SysinitArchivePath(targetName string) string {
+	return GeneratedBinDir(targetName) + "/sysinit.a"
+}
+
 func (b *Builder) BinDir() string {
-	return BinRoot() + "/" + b.target.target.Name() + "/" + b.buildName
+	return BinRoot() + "/" + b.targetPkg.Name() + "/" + b.buildName
 }
 
-func (b *Builder) PkgBinDir(pkgName string) string {
+func (b *Builder) FileBinDir(pkgName string) string {
 	return b.BinDir() + "/" + pkgName
 }
 
+func (b *Builder) PkgBinDir(bpkg *BuildPackage) string {
+	switch bpkg.Type() {
+	case pkg.PACKAGE_TYPE_GENERATED:
+		return GeneratedBinDir(b.targetPkg.Name())
+	default:
+		return b.FileBinDir(bpkg.Name())
+	}
+}
+
 // Generates the path+filename of the specified package's .a file.
-func (b *Builder) ArchivePath(pkgName string) string {
-	return b.PkgBinDir(pkgName) + "/" + filepath.Base(pkgName) + ".a"
+func (b *Builder) ArchivePath(bpkg *BuildPackage) string {
+	return b.PkgBinDir(bpkg) + "/" + filepath.Base(bpkg.Name()) + ".a"
 }
 
 func (b *Builder) AppTempElfPath() string {
-	pkgName := b.appPkg.Name()
-	return b.PkgBinDir(pkgName) + "/" + filepath.Base(pkgName) + "_tmp.elf"
+	return b.PkgBinDir(b.appPkg) + "/" + filepath.Base(b.appPkg.Name()) +
+		"_tmp.elf"
 }
 
 func (b *Builder) AppElfPath() string {
-	pkgName := b.appPkg.Name()
-	return b.PkgBinDir(pkgName) + "/" + filepath.Base(pkgName) + ".elf"
+	return b.PkgBinDir(b.appPkg) + "/" + filepath.Base(b.appPkg.Name()) +
+		".elf"
 }
 
 func (b *Builder) AppLinkerElfPath() string {
-	pkgName := b.appPkg.Name()
-	return b.PkgBinDir(pkgName) + "/" + filepath.Base(pkgName) + "linker.elf"
+	return b.PkgBinDir(b.appPkg) + "/" + filepath.Base(b.appPkg.Name()) +
+		"linker.elf"
 }
 
 func (b *Builder) AppImgPath() string {
-	pkgName := b.appPkg.Name()
-	return b.PkgBinDir(pkgName) + "/" + filepath.Base(pkgName) + ".img"
+	return b.PkgBinDir(b.appPkg) + "/" + filepath.Base(b.appPkg.Name()) +
+		".img"
 }
 
 func (b *Builder) AppPath() string {
-	pkgName := b.appPkg.Name()
-	return b.PkgBinDir(pkgName) + "/"
+	return b.PkgBinDir(b.appPkg) + "/"
 }
 
 func (b *Builder) AppBinBasePath() string {
-	pkgName := b.appPkg.Name()
-	return b.PkgBinDir(pkgName) + "/" + filepath.Base(pkgName)
+	return b.PkgBinDir(b.appPkg) + "/" + filepath.Base(b.appPkg.Name())
 }
 
 func TestTargetName(testPkgName string) string {
 	return strings.Replace(testPkgName, "/", "_", -1)
 }
 
-func (b *Builder) TestExePath(pkgName string) string {
-	return b.PkgBinDir(pkgName) + "/" + TestTargetName(pkgName)
+func (b *Builder) TestExePath(bpkg *BuildPackage) string {
+	return b.PkgBinDir(bpkg) + "/" + TestTargetName(bpkg.Name())
 }
 
 func (b *Builder) FeatureString() string {
 	var buffer bytes.Buffer
 
-	featureMap := b.Cfg.Features()
+	featureMap := b.cfg.Features()
 	featureSlice := make([]string, 0, len(featureMap))
 	for k, _ := range featureMap {
 		featureSlice = append(featureSlice, k)
@@ -112,44 +138,6 @@ func (b *Builder) FeatureString() string {
 	return buffer.String()
 }
 
-// Makes sure all packages with required APIs have been augmented with a
-// dependency that satisfies that requirement.  If there are any unsatisfied
-// requirements, an error is returned.
-func (b *Builder) verifyApisSatisfied() error {
-	unsatisfied := map[*BuildPackage][]string{}
-
-	for _, bpkg := range b.Packages {
-		for api, status := range bpkg.reqApiMap {
-			if status == REQ_API_STATUS_UNSATISFIED {
-				slice := unsatisfied[bpkg]
-				if slice == nil {
-					unsatisfied[bpkg] = []string{api}
-				} else {
-					slice = append(slice, api)
-				}
-			}
-		}
-	}
-
-	if len(unsatisfied) != 0 {
-		var buffer bytes.Buffer
-		for bpkg, apis := range unsatisfied {
-			buffer.WriteString("Package " + bpkg.Name() +
-				" has unsatisfied required APIs: ")
-			for i, api := range apis {
-				if i != 0 {
-					buffer.WriteString(", ")
-				}
-				buffer.WriteString(api)
-			}
-			buffer.WriteString("\n")
-		}
-		return util.NewNewtError(buffer.String())
-	}
-
-	return nil
-}
-
 type bpkgSorter struct {
 	bpkgs []*BuildPackage
 }
@@ -166,10 +154,10 @@ func (b bpkgSorter) Less(i, j int) bool {
 
 func (b *Builder) sortedBuildPackages() []*BuildPackage {
 	sorter := bpkgSorter{
-		bpkgs: make([]*BuildPackage, 0, len(b.Packages)),
+		bpkgs: make([]*BuildPackage, 0, len(b.PkgMap)),
 	}
 
-	for _, bpkg := range b.Packages {
+	for _, bpkg := range b.PkgMap {
 		sorter.bpkgs = append(sorter.bpkgs, bpkg)
 	}
 
@@ -193,23 +181,23 @@ func (b *Builder) logDepInfo() {
 	log.Debugf("Feature set: [" + b.FeatureString() + "]")
 
 	// Log API set.
-	apis := make([]string, 0, len(b.apis))
-	for api, _ := range b.apis {
+	apis := make([]string, 0, len(b.apiMap))
+	for api, _ := range b.apiMap {
 		apis = append(apis, api)
 	}
 	sort.Strings(apis)
 
 	log.Debugf("API set:")
 	for _, api := range apis {
-		bpkg := b.apis[api]
-		log.Debugf("    * " + api + " (" + bpkg.Name() + ")")
+		bpkg := b.apiMap[api]
+		log.Debugf("    * " + api + " (" + bpkg.FullName() + ")")
 	}
 
 	// Log dependency graph.
 	bpkgSorter := bpkgSorter{
-		bpkgs: make([]*BuildPackage, 0, len(b.Packages)),
+		bpkgs: make([]*BuildPackage, 0, len(b.PkgMap)),
 	}
-	for _, bpkg := range b.Packages {
+	for _, bpkg := range b.PkgMap {
 		bpkgSorter.bpkgs = append(bpkgSorter.bpkgs, bpkg)
 	}
 	sort.Sort(bpkgSorter)

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/dd715c24/newt/builder/library.go
----------------------------------------------------------------------
diff --git a/newt/builder/library.go b/newt/builder/library.go
index c3d7cde..40a0752 100644
--- a/newt/builder/library.go
+++ b/newt/builder/library.go
@@ -113,9 +113,10 @@ func getParseRexeg() (error, *regexp.Regexp) {
 	return nil, r
 }
 
-func (b *Builder) ParseObjectLibrary(bp *BuildPackage) (error, *symbol.SymbolMap) {
+func (b *Builder) ParseObjectLibrary(bp *BuildPackage) (
+	error, *symbol.SymbolMap) {
 
-	file := b.ArchivePath(bp.Name())
+	file := b.ArchivePath(bp)
 	return b.ParseObjectLibraryFile(bp, file, true)
 }
 
@@ -126,7 +127,7 @@ func (b *Builder) ParseObjectElf(elf_file string) (error, *symbol.SymbolMap) {
 func (b *Builder) ParseObjectLibraryFile(bp *BuildPackage,
 	file string, textDataOnly bool) (error, *symbol.SymbolMap) {
 
-	c, err := b.target.NewCompiler(b.AppElfPath())
+	c, err := b.targetBuilder.NewCompiler(b.AppElfPath())
 
 	ext := filepath.Ext(file)
 
@@ -206,7 +207,7 @@ func (b *Builder) ParseObjectLibraryFile(bp *BuildPackage,
 
 func (b *Builder) CopySymbols(sm *symbol.SymbolMap) error {
 
-	c, err := b.target.NewCompiler(b.AppElfPath())
+	c, err := b.targetBuilder.NewCompiler(b.AppElfPath())
 
 	if err != nil {
 		return err

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/dd715c24/newt/builder/load.go
----------------------------------------------------------------------
diff --git a/newt/builder/load.go b/newt/builder/load.go
index f3d0bbe..fba8e93 100644
--- a/newt/builder/load.go
+++ b/newt/builder/load.go
@@ -36,13 +36,13 @@ func (t *TargetBuilder) Load(extraJtagCmd string) error {
 		return err
 	}
 
-	if t.Loader != nil {
-		err = t.App.Load(1, extraJtagCmd)
+	if t.LoaderBuilder != nil {
+		err = t.AppBuilder.Load(1, extraJtagCmd)
 		if err == nil {
-			err = t.Loader.Load(0, extraJtagCmd)
+			err = t.LoaderBuilder.Load(0, extraJtagCmd)
 		}
 	} else {
-		err = t.App.Load(0, extraJtagCmd)
+		err = t.AppBuilder.Load(0, extraJtagCmd)
 	}
 
 	return err
@@ -56,22 +56,23 @@ func (b *Builder) Load(image_slot int, extraJtagCmd string) error {
 	/*
 	 * Populate the package list and feature sets.
 	 */
-	err := b.target.PrepBuild()
+	err := b.targetBuilder.PrepBuild()
 	if err != nil {
 		return err
 	}
 
-	if b.target.Bsp.DownloadScript == "" {
+	if b.targetBuilder.bspPkg.DownloadScript == "" {
 		/*
 		 *
 		 */
 		util.StatusMessage(util.VERBOSITY_DEFAULT,
-			"No download script for BSP %s\n", b.target.Bsp.Name())
+			"No download script for BSP %s\n", b.bspPkg.Name())
 		return nil
 	}
 
-	bspPath := b.target.Bsp.BasePath()
-	downloadScript := filepath.Join(bspPath, b.target.Bsp.DownloadScript)
+	bspPath := b.bspPkg.BasePath()
+	downloadScript := filepath.Join(bspPath,
+		b.targetBuilder.bspPkg.DownloadScript)
 	binBaseName := b.AppBinBasePath()
 	featureString := b.FeatureString()
 
@@ -88,7 +89,7 @@ func (b *Builder) Load(image_slot int, extraJtagCmd string) error {
 	downloadCmd := fmt.Sprintf("%s %s %s %s", envSettings, downloadScript,
 		bspPath, binBaseName)
 
-	features := b.Cfg.Features()
+	features := b.cfg.Features()
 
 	if _, ok := features["bootloader"]; ok {
 		util.StatusMessage(util.VERBOSITY_DEFAULT,
@@ -118,17 +119,10 @@ func (t *TargetBuilder) Debug(extraJtagCmd string, reset bool) error {
 		return err
 	}
 
-	//	if t.Loader != nil {
-	//		basename := t.Loader.AppElfPath()
-	//		name := strings.TrimSuffix(basename, filepath.Ext(basename))
-	//		additional_libs = append(additional_libs, name)
-	//	}
-
-	//	return t.App.Debug(additional_libs)
-	if t.Loader == nil {
-		return t.App.Debug(extraJtagCmd, reset)
+	if t.LoaderBuilder == nil {
+		return t.AppBuilder.Debug(extraJtagCmd, reset)
 	}
-	return t.Loader.Debug(extraJtagCmd, reset)
+	return t.LoaderBuilder.Debug(extraJtagCmd, reset)
 }
 
 func (b *Builder) Debug(extraJtagCmd string, reset bool) error {
@@ -139,12 +133,12 @@ func (b *Builder) Debug(extraJtagCmd string, reset bool) error {
 	/*
 	 * Populate the package list and feature sets.
 	 */
-	err := b.target.PrepBuild()
+	err := b.targetBuilder.PrepBuild()
 	if err != nil {
 		return err
 	}
 
-	bspPath := b.target.Bsp.BasePath()
+	bspPath := b.bspPkg.BasePath()
 	binBaseName := b.AppBinBasePath()
 	featureString := b.FeatureString()
 
@@ -160,11 +154,12 @@ func (b *Builder) Debug(extraJtagCmd string, reset bool) error {
 	if reset == true {
 		envSettings = append(envSettings, fmt.Sprintf("RESET=true"))
 	}
-	debugScript := filepath.Join(bspPath, b.target.Bsp.DebugScript)
+	debugScript := filepath.Join(bspPath, b.targetBuilder.bspPkg.DebugScript)
 
 	os.Chdir(project.GetProject().Path())
 
-	// bspPath, binBaseName are passed in command line for backwards compatibility
+	// bspPath, binBaseName are passed in command line for backwards
+	// compatibility
 	cmdLine := []string{debugScript, bspPath, binBaseName}
 
 	fmt.Printf("%s\n", cmdLine)

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/dd715c24/newt/builder/size.go
----------------------------------------------------------------------
diff --git a/newt/builder/size.go b/newt/builder/size.go
index 37f1b47..970db2d 100644
--- a/newt/builder/size.go
+++ b/newt/builder/size.go
@@ -323,13 +323,13 @@ func (t *TargetBuilder) Size() error {
 		return err
 	}
 
-	fmt.Printf("Size of Application Image: %s\n", t.App.buildName)
-	err = t.App.Size()
+	fmt.Printf("Size of Application Image: %s\n", t.AppBuilder.buildName)
+	err = t.AppBuilder.Size()
 
 	if err == nil {
-		if t.Loader != nil {
-			fmt.Printf("Size of Loader Image: %s\n", t.Loader.buildName)
-			err = t.Loader.Size()
+		if t.LoaderBuilder != nil {
+			fmt.Printf("Size of Loader Image: %s\n", t.LoaderBuilder.buildName)
+			err = t.LoaderBuilder.Size()
 		}
 	}
 
@@ -341,11 +341,11 @@ func (b *Builder) Size() error {
 		return util.NewNewtError("app package not specified for this target")
 	}
 
-	err := b.target.PrepBuild()
+	err := b.targetBuilder.PrepBuild()
 	if err != nil {
 		return err
 	}
-	if b.target.Bsp.Arch == "sim" {
+	if b.targetBuilder.bspPkg.Arch == "sim" {
 		fmt.Println("'newt size' not supported for sim targets.")
 		return nil
 	}
@@ -361,7 +361,7 @@ func (b *Builder) Size() error {
 	}
 	fmt.Printf("%s", output)
 
-	c, err := b.newCompiler(b.appPkg, b.PkgBinDir(b.AppElfPath()))
+	c, err := b.newCompiler(b.appPkg, b.FileBinDir(b.AppElfPath()))
 	if err != nil {
 		return err
 	}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/dd715c24/newt/builder/targetbuild.go
----------------------------------------------------------------------
diff --git a/newt/builder/targetbuild.go b/newt/builder/targetbuild.go
index 0ca8154..a34b885 100644
--- a/newt/builder/targetbuild.go
+++ b/newt/builder/targetbuild.go
@@ -24,32 +24,57 @@ import (
 	"os"
 	"strings"
 
+	log "github.com/Sirupsen/logrus"
+
 	"mynewt.apache.org/newt/newt/interfaces"
 	"mynewt.apache.org/newt/newt/pkg"
 	"mynewt.apache.org/newt/newt/project"
+	"mynewt.apache.org/newt/newt/resolve"
 	"mynewt.apache.org/newt/newt/symbol"
+	"mynewt.apache.org/newt/newt/syscfg"
+	"mynewt.apache.org/newt/newt/sysinit"
 	"mynewt.apache.org/newt/newt/target"
 	"mynewt.apache.org/newt/newt/toolchain"
 	"mynewt.apache.org/newt/util"
 )
 
 type TargetBuilder struct {
-	compilerPkg *pkg.LocalPackage
-	Bsp         *pkg.BspPackage
 	target      *target.Target
+	bspPkg      *pkg.BspPackage
+	compilerPkg *pkg.LocalPackage
+	appPkg      *pkg.LocalPackage
+	loaderPkg   *pkg.LocalPackage
+	testPkg     *pkg.LocalPackage
 
-	App     *Builder
-	AppList interfaces.PackageList
+	AppBuilder *Builder
+	AppList    interfaces.PackageList
 
-	Loader     *Builder
-	LoaderList interfaces.PackageList
+	LoaderBuilder *Builder
+	LoaderList    interfaces.PackageList
 }
 
-func NewTargetBuilder(target *target.Target) (*TargetBuilder, error) {
-	t := &TargetBuilder{}
+func NewTargetBuilder(target *target.Target,
+	testPkg *pkg.LocalPackage) (*TargetBuilder, error) {
 
-	/* TODO */
-	t.target = target
+	if err := target.Validate(testPkg == nil); err != nil {
+		return nil, err
+	}
+
+	bspPkg := pkg.NewBspPackage(target.Bsp())
+	compilerPkg, err := project.GetProject().ResolvePackage(
+		bspPkg.Repo(), bspPkg.CompilerName)
+	if err != nil {
+		return nil, err
+	}
+
+	t := &TargetBuilder{
+		target:      target,
+		bspPkg:      bspPkg,
+		compilerPkg: compilerPkg,
+		appPkg:      target.App(),
+		loaderPkg:   target.Loader(),
+		testPkg:     testPkg,
+	}
 
 	return t, nil
 }
@@ -61,84 +86,157 @@ func (t *TargetBuilder) NewCompiler(dstDir string) (*toolchain.Compiler, error)
 	return c, err
 }
 
-func (t *TargetBuilder) PrepBuild() error {
+func (t *TargetBuilder) resolveCfg(injectedSettings map[string]string) (
+	resolve.CfgResolution, error) {
 
-	if t.Bsp != nil {
-		// Already prepped
-		return nil
-	}
-	// Collect the seed packages.
-	bspPkg := t.target.Bsp()
-	if bspPkg == nil {
-		if t.target.BspName == "" {
-			return util.NewNewtError("BSP package not specified by target")
-		} else {
-			return util.NewNewtError("BSP package not found: " +
-				t.target.BspName)
-		}
+	seeds := []*pkg.LocalPackage{
+		t.bspPkg.LocalPackage,
+		t.compilerPkg,
+		t.target.Package(),
 	}
-	t.Bsp = pkg.NewBspPackage(bspPkg)
 
-	compilerPkg := t.resolveCompiler()
-	if compilerPkg == nil {
-		if t.Bsp.CompilerName == "" {
-			return util.NewNewtError("Compiler package not specified by BSP")
-		} else {
-			return util.NewNewtError("Compiler package not found: " +
-				t.Bsp.CompilerName)
-		}
+	if t.loaderPkg != nil {
+		seeds = append(seeds, t.loaderPkg)
+	}
+
+	if t.appPkg != nil {
+		seeds = append(seeds, t.appPkg)
+	}
+
+	if t.testPkg != nil {
+		seeds = append(seeds, t.testPkg)
+	}
+
+	cfgResolution, err := resolve.ResolveCfg(seeds, injectedSettings)
+	if err != nil {
+		return cfgResolution, err
+	}
+
+	return cfgResolution, nil
+}
+
+func (t *TargetBuilder) resolveCfgBuild() (resolve.CfgResolution, error) {
+	return t.resolveCfg(nil)
+}
+
+func (t *TargetBuilder) resolveCfgTest() (resolve.CfgResolution, error) {
+	// Inject the TEST setting into the entire build.  This setting
+	// exposes unit test code in each package.
+	return t.resolveCfg(map[string]string{"TEST": "1"})
+}
+
+func (t *TargetBuilder) validateAndWriteCfg(
+	cfgResolution resolve.CfgResolution) error {
+
+	if errText := cfgResolution.ErrorText(); errText != "" {
+		return util.NewNewtError(errText)
 	}
-	t.compilerPkg = compilerPkg
 
-	appPkg := t.target.App()
-	targetPkg := t.target.Package()
+	if err := syscfg.EnsureWritten(cfgResolution.Cfg,
+		GeneratedIncludeDir(t.target.Name())); err != nil {
 
-	app, err := NewBuilder(t, "app")
+		return err
+	}
 
-	if err == nil {
-		t.App = app
+	return nil
+}
+
+func (t *TargetBuilder) resolvePkgs(cfgResolution resolve.CfgResolution) (
+	[]*pkg.LocalPackage, []*pkg.LocalPackage, error) {
+
+	var appPkg *pkg.LocalPackage
+	if t.appPkg != nil {
+		appPkg = t.appPkg
 	} else {
+		appPkg = t.testPkg
+	}
+
+	return resolve.ResolveSplitPkgs(cfgResolution,
+		t.loaderPkg,
+		appPkg,
+		t.bspPkg.LocalPackage,
+		t.compilerPkg,
+		t.target.Package())
+}
+
+func (t *TargetBuilder) buildSysinit(
+	cfgResolution resolve.CfgResolution) error {
+
+	loaderPkgs, appPkgs, err := t.resolvePkgs(cfgResolution)
+	if err != nil {
 		return err
 	}
 
-	loaderPkg := t.target.Loader()
+	srcDir := GeneratedSrcDir(t.target.Name())
+
+	if loaderPkgs != nil {
+		sysinit.EnsureWritten(loaderPkgs, srcDir,
+			pkg.ShortName(t.target.Package()), true)
+	}
 
-	if loaderPkg != nil {
-		loader, err := NewBuilder(t, "loader")
+	sysinit.EnsureWritten(appPkgs, srcDir,
+		pkg.ShortName(t.target.Package()), false)
 
-		if err == nil {
-			t.Loader = loader
-		} else {
-			return err
-		}
+	return nil
+}
+
+func (t *TargetBuilder) ExportCfg() (resolve.CfgResolution, error) {
+	return t.resolveCfgBuild()
+}
 
-		err = t.Loader.PrepBuild(loaderPkg, bspPkg, targetPkg)
+func (t *TargetBuilder) PrepBuild() error {
+	cfgResolution, err := t.resolveCfgBuild()
+	if err != nil {
+		return err
+	}
+
+	if err := t.validateAndWriteCfg(cfgResolution); err != nil {
+		return err
+	}
+
+	loaderPkgs, appPkgs, err := t.resolvePkgs(cfgResolution)
+	if err != nil {
+		return err
+	}
+
+	if loaderPkgs != nil {
+		t.LoaderBuilder, err = NewBuilder(t, "loader", loaderPkgs,
+			cfgResolution.ApiMap, cfgResolution.Cfg)
 		if err != nil {
 			return err
 		}
+		if err := t.LoaderBuilder.PrepBuild(); err != nil {
+			return err
+		}
 
-		loader_flag := toolchain.NewCompilerInfo()
-		loader_flag.Cflags = append(loader_flag.Cflags, "-DSPLIT_LOADER")
-		t.Loader.AddCompilerInfo(loader_flag)
+		loaderFlags := toolchain.NewCompilerInfo()
+		loaderFlags.Cflags = append(loaderFlags.Cflags, "-DSPLIT_LOADER")
+		t.LoaderBuilder.AddCompilerInfo(loaderFlags)
 
 		t.LoaderList = project.ResetDeps(nil)
 	}
 
-	bsp_pkg := t.target.Bsp()
-
-	err = t.App.PrepBuild(appPkg, bsp_pkg, targetPkg)
+	t.AppBuilder, err = NewBuilder(t, "app", appPkgs,
+		cfgResolution.ApiMap, cfgResolution.Cfg)
 	if err != nil {
 		return err
-
 	}
-	if loaderPkg != nil {
-		app_flag := toolchain.NewCompilerInfo()
-		app_flag.Cflags = append(app_flag.Cflags, "-DSPLIT_APPLICATION")
-		t.App.AddCompilerInfo(app_flag)
+	if err := t.AppBuilder.PrepBuild(); err != nil {
+		return err
+	}
+
+	if loaderPkgs != nil {
+		appFlags := toolchain.NewCompilerInfo()
+		appFlags.Cflags = append(appFlags.Cflags, "-DSPLIT_APPLICATION")
+		t.AppBuilder.AddCompilerInfo(appFlags)
 	}
 
 	t.AppList = project.ResetDeps(nil)
 
+	if err := t.buildSysinit(cfgResolution); err != nil {
+		return err
+	}
+
 	return nil
 }
 
@@ -146,10 +244,6 @@ func (t *TargetBuilder) Build() error {
 	var err error
 	var linkerScript string
 
-	if err = t.target.Validate(true); err != nil {
-		return err
-	}
-
 	if err = t.PrepBuild(); err != nil {
 		return err
 	}
@@ -157,24 +251,24 @@ func (t *TargetBuilder) Build() error {
 	/* Build the Apps */
 	project.ResetDeps(t.AppList)
 
-	if err := t.Bsp.Reload(t.App.Cfg.Features()); err != nil {
+	if err := t.bspPkg.Reload(t.AppBuilder.cfg.Features()); err != nil {
 		return err
 	}
 
-	err = t.App.Build()
+	err = t.AppBuilder.Build()
 	if err != nil {
 		return err
 	}
 
 	/* if we have no loader, we are done here.  All of the rest of this
 	 * function is for split images */
-	if t.Loader == nil {
-		err = t.App.Link(t.Bsp.LinkerScript)
+	if t.LoaderBuilder == nil {
+		err = t.AppBuilder.Link(t.bspPkg.LinkerScript)
 		return err
 	}
 
 	/* Link the app as a test (using the normal single image linker script) */
-	err = t.App.TestLink(t.Bsp.LinkerScript)
+	err = t.AppBuilder.TestLink(t.bspPkg.LinkerScript)
 	if err != nil {
 		return err
 	}
@@ -182,51 +276,50 @@ func (t *TargetBuilder) Build() error {
 	/* rebuild the loader */
 	project.ResetDeps(t.LoaderList)
 
-	if err = t.Bsp.Reload(t.Loader.Cfg.Features()); err != nil {
+	if err = t.bspPkg.Reload(t.LoaderBuilder.cfg.Features()); err != nil {
 		return err
 	}
 
-	err = t.Loader.Build()
+	err = t.LoaderBuilder.Build()
 
 	if err != nil {
 		return err
 	}
 
 	/* perform a test link of the loader */
-	err = t.Loader.TestLink(t.Bsp.LinkerScript)
+	err = t.LoaderBuilder.TestLink(t.bspPkg.LinkerScript)
 
 	if err != nil {
 		return err
 	}
 
 	/* re-link the loader with app dependencies */
-	err, common_pkgs, common_syms := t.RelinkLoader()
+	err, commonPkgs, commonSyms := t.RelinkLoader()
 	if err != nil {
 		return err
 	}
 
 	/* The app can ignore these packages next time */
-	t.App.RemovePackages(common_pkgs)
-	/* add back the BSP package which needs linking in both */
-	t.App.AddPackage(t.Bsp.LocalPackage)
+	delete(commonPkgs, t.bspPkg.Name())
+	t.AppBuilder.RemovePackages(commonPkgs)
 
 	/* create the special elf to link the app against */
 	/* its just the elf with a set of symbols removed and renamed */
-	err = t.Loader.buildRomElf(common_syms)
+	err = t.LoaderBuilder.buildRomElf(commonSyms)
 	if err != nil {
 		return err
 	}
 
 	/* set up the linker elf and linker script for the app */
-	t.App.LinkElf = t.Loader.AppLinkerElfPath()
-	linkerScript = t.Bsp.Part2LinkerScript
+	t.AppBuilder.linkElf = t.LoaderBuilder.AppLinkerElfPath()
+	linkerScript = t.bspPkg.Part2LinkerScript
 
 	if linkerScript == "" {
-		return util.NewNewtError("BSP Must specify Linker script ")
+		return util.NewNewtError("BSP must specify linker script ")
 	}
 
 	/* link the app */
-	err = t.App.Link(linkerScript)
+	err = t.AppBuilder.Link(linkerScript)
 	if err != nil {
 		return err
 	}
@@ -239,73 +332,86 @@ func (t *TargetBuilder) Build() error {
  * shared with the app. Returns a list of the common packages shared
  * by the app and loader
  */
-func (t *TargetBuilder) RelinkLoader() (error, map[string]bool, *symbol.SymbolMap) {
+func (t *TargetBuilder) RelinkLoader() (error, map[string]bool,
+	*symbol.SymbolMap) {
 
 	/* fetch symbols from the elf and from the libraries themselves */
-	err, appLibSym := t.App.ExtractSymbolInfo()
+	log.Debugf("Loader packages:")
+	for _, lpkg := range t.LoaderBuilder.sortedLocalPackages() {
+		log.Debugf("    * %s", lpkg.Name())
+	}
+	log.Debugf("App packages:")
+	for _, lpkg := range t.AppBuilder.sortedLocalPackages() {
+		log.Debugf("    * %s", lpkg.Name())
+	}
+	err, appLibSym := t.AppBuilder.ExtractSymbolInfo()
 	if err != nil {
 		return err, nil, nil
 	}
 
 	/* fetch the symbol list from the app temporary elf */
-	err, appElfSym := t.App.ParseObjectElf(t.App.AppTempElfPath())
+	err, appElfSym := t.AppBuilder.ParseObjectElf(t.AppBuilder.AppTempElfPath())
 	if err != nil {
 		return err, nil, nil
 	}
 
 	/* extract the library symbols and elf symbols from the loader */
-	err, loaderLibSym := t.Loader.ExtractSymbolInfo()
+	err, loaderLibSym := t.LoaderBuilder.ExtractSymbolInfo()
 	if err != nil {
 		return err, nil, nil
 	}
 
-	err, loaderElfSym := t.Loader.ParseObjectElf(t.Loader.AppTempElfPath())
+	err, loaderElfSym := t.LoaderBuilder.ParseObjectElf(
+		t.LoaderBuilder.AppTempElfPath())
 	if err != nil {
 		return err, nil, nil
 	}
 
 	/* create the set of matching and non-matching symbols */
-	err, sm_match, sm_nomatch := symbol.IdenticalUnion(appLibSym,
+	err, smMatch, smNomatch := symbol.IdenticalUnion(appLibSym,
 		loaderLibSym, true, false)
 
 	/* which packages are shared between the two */
-	common_pkgs := sm_match.Packages()
-	uncommon_pkgs := sm_nomatch.Packages()
+	commonPkgs := smMatch.Packages()
+	uncommonPkgs := smNomatch.Packages()
 
 	/* ensure that the loader and app packages are never shared */
-	delete(common_pkgs, t.App.appPkg.Name())
-	uncommon_pkgs[t.App.appPkg.Name()] = true
-	ma := sm_match.FilterPkg(t.App.appPkg.Name())
-	sm_match.RemoveMap(ma)
+	delete(commonPkgs, t.AppBuilder.appPkg.Name())
+	uncommonPkgs[t.AppBuilder.appPkg.Name()] = true
+	ma := smMatch.FilterPkg(t.AppBuilder.appPkg.Name())
+	smMatch.RemoveMap(ma)
 
-	delete(common_pkgs, t.Loader.appPkg.Name())
-	uncommon_pkgs[t.Loader.appPkg.Name()] = true
-	ml := sm_match.FilterPkg(t.Loader.appPkg.Name())
-	sm_match.RemoveMap(ml)
+	delete(commonPkgs, t.LoaderBuilder.appPkg.Name())
+	uncommonPkgs[t.LoaderBuilder.appPkg.Name()] = true
+	ml := smMatch.FilterPkg(t.LoaderBuilder.appPkg.Name())
+	smMatch.RemoveMap(ml)
 
 	util.StatusMessage(util.VERBOSITY_VERBOSE,
-		"Putting %d symbols from %d packages into Loader\n",
-		len(*sm_match), len(common_pkgs))
+		"Putting %d symbols from %d packages into loader\n",
+		len(*smMatch), len(commonPkgs))
 
 	/* This is worth a special comment.  We are building both apps as
 	 * stand-alone apps against the normal linker file, so they will both
 	 * have a Reset_Handler symbol.  We need to ignore this here.  When
 	 * we build the split app, we use a special linker file which
 	 * uses a different entry point */
-	special_sm := symbol.NewSymbolMap()
-	special_sm.Add(*symbol.NewElfSymbol("Reset_Handler(app)"))
-	special_sm.Add(*symbol.NewElfSymbol("Reset_Handler(loader)"))
+	specialSm := symbol.NewSymbolMap()
+	specialSm.Add(*symbol.NewElfSymbol("Reset_Handler(app)"))
+	specialSm.Add(*symbol.NewElfSymbol("Reset_Handler(loader)"))
 
 	var badpkgs []string
-	var symbol_str string
-	for v, _ := range uncommon_pkgs {
-		if t.App.appPkg != nil && t.App.appPkg.Name() != v &&
-			t.Loader.appPkg != nil && t.Loader.appPkg.Name() != v {
-			trouble := sm_nomatch.FilterPkg(v)
+	var symbolStr string
+	for v, _ := range uncommonPkgs {
+		if t.AppBuilder.appPkg != nil &&
+			t.AppBuilder.appPkg.Name() != v &&
+			t.LoaderBuilder.appPkg != nil &&
+			t.LoaderBuilder.appPkg.Name() != v {
+
+			trouble := smNomatch.FilterPkg(v)
 
 			var found bool
 			for _, sym := range *trouble {
-				if _, ok := special_sm.Find(sym.Name); !ok {
+				if _, ok := specialSm.Find(sym.Name); !ok {
 					if !sym.IsLocal() {
 						found = true
 					}
@@ -313,32 +419,33 @@ func (t *TargetBuilder) RelinkLoader() (error, map[string]bool, *symbol.SymbolMa
 			}
 
 			if found {
-				symbol_str = (*trouble).String("Non Matching Symbols")
+				symbolStr = (*trouble).String("Non Matching Symbols")
 				badpkgs = append(badpkgs, v)
-				delete(common_pkgs, v)
+				delete(commonPkgs, v)
 			}
 		}
 	}
 
 	if len(badpkgs) > 0 {
-		errStr := fmt.Sprintf("Common packages with different implementaiton\n %s \n",
+		errStr := fmt.Sprintf(
+			"Common packages with different implementaiton\n %s \n",
 			strings.Join(badpkgs, "\n "))
-		errStr += symbol_str
+		errStr += symbolStr
 		return util.NewNewtError(errStr), nil, nil
 	}
 
 	/* for each symbol in the elf of the app, if that symbol is in
 	 * a common package, keep that symbol in the loader */
-	preserve_elf := symbol.NewSymbolMap()
+	preserveElf := symbol.NewSymbolMap()
 
 	/* go through each symbol in the app */
 	for _, elfsym := range *appElfSym {
 		name := elfsym.Name
 		if libsym, ok := (*appLibSym)[name]; ok {
-			if _, ok := common_pkgs[libsym.Bpkg]; ok {
+			if _, ok := commonPkgs[libsym.Bpkg]; ok {
 				/* if its not in the loader elf, add it as undefined */
 				if _, ok := (*loaderElfSym)[name]; !ok {
-					preserve_elf.Add(elfsym)
+					preserveElf.Add(elfsym)
 				}
 			}
 		}
@@ -348,84 +455,53 @@ func (t *TargetBuilder) RelinkLoader() (error, map[string]bool, *symbol.SymbolMa
 	project.ResetDeps(t.LoaderList)
 
 	util.StatusMessage(util.VERBOSITY_VERBOSE,
-		"Migrating %d unused symbols into Loader\n", len(*preserve_elf))
+		"Migrating %d unused symbols into Loader\n", len(*preserveElf))
 
-	err = t.Loader.KeepLink(t.Bsp.LinkerScript, preserve_elf)
+	err = t.LoaderBuilder.KeepLink(t.bspPkg.LinkerScript, preserveElf)
 
 	if err != nil {
 		return err, nil, nil
 	}
-	return err, common_pkgs, sm_match
+	return err, commonPkgs, smMatch
 }
 
-func (t *TargetBuilder) Test(p *pkg.LocalPackage) error {
-	if err := t.target.Validate(false); err != nil {
-		return err
-	}
+func (t *TargetBuilder) Test() error {
+	// Inject the SELFTEST setting into the package under test.  This setting
+	// indicates that the package needs to provide its own main().
+	t.testPkg.InjectedSettings()["SELFTEST"] = "1"
 
-	if t.Bsp != nil {
-		// Already prepped
-		return nil
-	}
-	// Collect the seed packages.
-	bspPkg := t.target.Bsp()
-	if bspPkg == nil {
-		if t.target.BspName == "" {
-			return util.NewNewtError("BSP package not specified by target")
-		} else {
-			return util.NewNewtError("BSP package not found: " +
-				t.target.BspName)
-		}
+	cfgResolution, err := t.resolveCfgTest()
+	if err != nil {
+		return err
 	}
-	t.Bsp = pkg.NewBspPackage(bspPkg)
 
-	compilerPkg := t.resolveCompiler()
-	if compilerPkg == nil {
-		if t.Bsp.CompilerName == "" {
-			return util.NewNewtError("Compiler package not specified by BSP")
-		} else {
-			return util.NewNewtError("Compiler package not found: " +
-				t.Bsp.CompilerName)
-		}
+	if err := t.validateAndWriteCfg(cfgResolution); err != nil {
+		return err
 	}
-	t.compilerPkg = compilerPkg
 
-	targetPkg := t.target.Package()
-
-	app, err := NewBuilder(t, "test")
-
-	if err == nil {
-		t.App = app
-	} else {
+	_, appPkgs, err := t.resolvePkgs(cfgResolution)
+	if err != nil {
 		return err
 	}
 
-	// A few features are automatically supported when the test command is
-	// used:
-	//     * TEST:      ensures that the test code gets compiled.
-	//     * SELFTEST:  indicates that there is no app.
-	t.App.injectedSettings["TEST"] = "1"
-	p.InjectedSettings()["SELFTEST"] = "1"
-
-	t.App.AddPackage(p)
-	err = t.App.PrepBuild(nil, bspPkg, targetPkg)
-
+	t.AppBuilder, err = NewBuilder(t, "test", appPkgs,
+		cfgResolution.ApiMap, cfgResolution.Cfg)
 	if err != nil {
 		return err
 	}
+	if err := t.AppBuilder.PrepBuild(); err != nil {
+		return err
+	}
 
-	err = t.App.Test(p)
-
-	return err
-}
+	if err := t.buildSysinit(cfgResolution); err != nil {
+		return err
+	}
 
-func (t *TargetBuilder) resolveCompiler() *pkg.LocalPackage {
-	if t.Bsp.CompilerName == "" {
-		return nil
+	if err := t.AppBuilder.Test(t.testPkg); err != nil {
+		return err
 	}
-	dep, _ := pkg.NewDependency(t.Bsp.Repo(), t.Bsp.CompilerName)
-	mypkg := project.GetProject().ResolveDependency(dep).(*pkg.LocalPackage)
-	return mypkg
+
+	return nil
 }
 
 func (t *TargetBuilder) Clean() error {

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/dd715c24/newt/cli/build_cmds.go
----------------------------------------------------------------------
diff --git a/newt/cli/build_cmds.go b/newt/cli/build_cmds.go
index 08118cc..7c7fb9d 100644
--- a/newt/cli/build_cmds.go
+++ b/newt/cli/build_cmds.go
@@ -44,8 +44,8 @@ func testablePkgs() map[*pkg.LocalPackage]struct{} {
 	testablePkgMap := map[*pkg.LocalPackage]struct{}{}
 
 	// Create a map of path => lclPkg.
-	proj := project.GetProject()
-	if proj == nil {
+	proj, err := project.TryGetProject()
+	if err != nil {
 		return nil
 	}
 
@@ -101,13 +101,14 @@ func pkgToUnitTests(pack *pkg.LocalPackage) []*pkg.LocalPackage {
 var extraJtagCmd string
 
 func buildRunCmd(cmd *cobra.Command, args []string) {
-	if err := project.Initialize(); err != nil {
-		NewtUsage(cmd, err)
-	}
 	if len(args) < 1 {
 		NewtUsage(cmd, nil)
 	}
 
+	if _, err := project.TryGetProject(); err != nil {
+		NewtUsage(nil, err)
+	}
+
 	// Verify that all target names are valid.
 	_, err := ResolveTargets(args...)
 	if err != nil {
@@ -131,31 +132,31 @@ func buildRunCmd(cmd *cobra.Command, args []string) {
 		util.StatusMessage(util.VERBOSITY_DEFAULT, "Building target %s\n",
 			t.FullName())
 
-		b, err := builder.NewTargetBuilder(t)
+		b, err := builder.NewTargetBuilder(t, nil)
 		if err != nil {
 			NewtUsage(nil, err)
 		}
 
-		err = b.Build()
-		if err != nil {
+		if err := b.Build(); err != nil {
 			NewtUsage(nil, err)
 		}
 
-		util.StatusMessage(util.VERBOSITY_DEFAULT, "Target successfully built: "+
-			"%s\n", targetName)
+		util.StatusMessage(util.VERBOSITY_DEFAULT,
+			"Target successfully built: %s\n", targetName)
 
 		/* TODO */
 	}
 }
 
 func cleanRunCmd(cmd *cobra.Command, args []string) {
-	if err := project.Initialize(); err != nil {
-		NewtUsage(cmd, err)
-	}
 	if len(args) < 1 {
 		NewtUsage(cmd, util.NewNewtError("Must specify target"))
 	}
 
+	if _, err := project.TryGetProject(); err != nil {
+		NewtUsage(nil, err)
+	}
+
 	cleanAll := false
 	targets := []*target.Target{}
 	for _, arg := range args {
@@ -181,12 +182,11 @@ func cleanRunCmd(cmd *cobra.Command, args []string) {
 		}
 	} else {
 		for _, t := range targets {
-			b, err := builder.NewTargetBuilder(t)
+			b, err := builder.NewTargetBuilder(t, nil)
 			if err != nil {
-				NewtUsage(cmd, err)
+				NewtUsage(nil, err)
 			}
-			err = b.Clean()
-			if err != nil {
+			if err := b.Clean(); err != nil {
 				NewtUsage(cmd, err)
 			}
 		}
@@ -208,6 +208,11 @@ func testRunCmd(cmd *cobra.Command, args []string) {
 		NewtUsage(cmd, nil)
 	}
 
+	proj, err := project.TryGetProject()
+	if err != nil {
+		NewtUsage(nil, err)
+	}
+
 	// Verify and resolve each specified package.
 	testAll := false
 	packs := []*pkg.LocalPackage{}
@@ -215,7 +220,7 @@ func testRunCmd(cmd *cobra.Command, args []string) {
 		if pkgName == "all" {
 			testAll = true
 		} else {
-			pack, err := ResolvePackage(pkgName)
+			pack, err := proj.ResolvePackage(proj.LocalRepo(), pkgName)
 			if err != nil {
 				NewtUsage(cmd, err)
 			}
@@ -230,8 +235,6 @@ func testRunCmd(cmd *cobra.Command, args []string) {
 		}
 	}
 
-	proj := project.GetProject()
-
 	if testAll {
 		packItfs := proj.PackagesOfType(pkg.PACKAGE_TYPE_UNITTEST)
 		packs = make([]*pkg.LocalPackage, len(packItfs))
@@ -284,7 +287,7 @@ func testRunCmd(cmd *cobra.Command, args []string) {
 			}
 		}
 
-		b, err := builder.NewTargetBuilder(t)
+		b, err := builder.NewTargetBuilder(t, pack)
 		if err != nil {
 			NewtUsage(nil, err)
 		}
@@ -292,16 +295,7 @@ func testRunCmd(cmd *cobra.Command, args []string) {
 		util.StatusMessage(util.VERBOSITY_DEFAULT, "Testing package %s\n",
 			pack.FullName())
 
-		// The package under test needs to be resolved again now that the
-		// project has been reset.
-		newPack, err := ResolvePackage(pack.FullName())
-		if err != nil {
-			NewtUsage(nil, util.NewNewtError("Failed to resolve package: "+
-				pack.Name()))
-		}
-		pack = newPack
-
-		err = b.Test(pack)
+		err = b.Test()
 		if err == nil {
 			passedPkgs = append(passedPkgs, pack)
 		} else {
@@ -324,73 +318,73 @@ func testRunCmd(cmd *cobra.Command, args []string) {
 }
 
 func loadRunCmd(cmd *cobra.Command, args []string) {
-	if err := project.Initialize(); err != nil {
-		NewtUsage(cmd, err)
-	}
 	if len(args) < 1 {
 		NewtUsage(cmd, util.NewNewtError("Must specify target"))
 	}
 
+	if _, err := project.TryGetProject(); err != nil {
+		NewtUsage(nil, err)
+	}
+
 	t := ResolveTarget(args[0])
 	if t == nil {
 		NewtUsage(cmd, util.NewNewtError("Invalid target name: "+args[0]))
 	}
 
-	b, err := builder.NewTargetBuilder(t)
+	b, err := builder.NewTargetBuilder(t, nil)
 	if err != nil {
-		NewtUsage(cmd, err)
+		NewtUsage(nil, err)
 	}
 
-	err = b.Load(extraJtagCmd)
-	if err != nil {
+	if err := b.Load(extraJtagCmd); err != nil {
 		NewtUsage(cmd, err)
 	}
 }
 
 func debugRunCmd(cmd *cobra.Command, args []string) {
-	if err := project.Initialize(); err != nil {
-		NewtUsage(cmd, err)
-	}
 	if len(args) < 1 {
 		NewtUsage(cmd, util.NewNewtError("Must specify target"))
 	}
 
+	if _, err := project.TryGetProject(); err != nil {
+		NewtUsage(nil, err)
+	}
+
 	t := ResolveTarget(args[0])
 	if t == nil {
 		NewtUsage(cmd, util.NewNewtError("Invalid target name: "+args[0]))
 	}
 
-	b, err := builder.NewTargetBuilder(t)
+	b, err := builder.NewTargetBuilder(t, nil)
 	if err != nil {
-		NewtUsage(cmd, err)
+		NewtUsage(nil, err)
 	}
 
-	err = b.Debug(extraJtagCmd, false)
-	if err != nil {
+	if err := b.Debug(extraJtagCmd, false); err != nil {
 		NewtUsage(cmd, err)
 	}
 }
 
 func sizeRunCmd(cmd *cobra.Command, args []string) {
-	if err := project.Initialize(); err != nil {
-		NewtUsage(cmd, err)
-	}
 	if len(args) < 1 {
 		NewtUsage(cmd, util.NewNewtError("Must specify target"))
 	}
 
+	if _, err := project.TryGetProject(); err != nil {
+		NewtUsage(nil, err)
+	}
+
 	t := ResolveTarget(args[0])
 	if t == nil {
 		NewtUsage(cmd, util.NewNewtError("Invalid target name: "+args[0]))
 	}
 
-	b, err := builder.NewTargetBuilder(t)
+	b, err := builder.NewTargetBuilder(t, nil)
 	if err != nil {
-		NewtUsage(cmd, err)
+		NewtUsage(nil, err)
 	}
 
-	err = b.Size()
-	if err != nil {
+	if err := b.Size(); err != nil {
 		NewtUsage(cmd, err)
 	}
 }

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/dd715c24/newt/cli/complete_cmd.go
----------------------------------------------------------------------
diff --git a/newt/cli/complete_cmd.go b/newt/cli/complete_cmd.go
index 68213da..31de297 100644
--- a/newt/cli/complete_cmd.go
+++ b/newt/cli/complete_cmd.go
@@ -36,8 +36,7 @@ import (
 func targetList() []string {
 	targetNames := []string{}
 
-	err := project.Initialize()
-	if err != nil {
+	if _, err := project.TryGetProject(); err != nil {
 		return targetNames
 	}
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/dd715c24/newt/cli/image_cmds.go
----------------------------------------------------------------------
diff --git a/newt/cli/image_cmds.go b/newt/cli/image_cmds.go
index 50cb7ac..1e04c2c 100644
--- a/newt/cli/image_cmds.go
+++ b/newt/cli/image_cmds.go
@@ -65,13 +65,14 @@ func createImageRunCmd(cmd *cobra.Command, args []string) {
 	var keyId uint8
 	var keystr string
 
-	if err := project.Initialize(); err != nil {
-		NewtUsage(cmd, err)
-	}
 	if len(args) < 2 {
 		NewtUsage(cmd, util.NewNewtError("Must specify target and version"))
 	}
 
+	if _, err := project.TryGetProject(); err != nil {
+		NewtUsage(nil, err)
+	}
+
 	targetName := args[0]
 	t := ResolveTarget(targetName)
 	if t == nil {
@@ -92,35 +93,35 @@ func createImageRunCmd(cmd *cobra.Command, args []string) {
 		keystr = args[2]
 	}
 
-	b, err := builder.NewTargetBuilder(t)
+	b, err := builder.NewTargetBuilder(t, nil)
 	if err != nil {
-		NewtUsage(cmd, err)
-		return
+		NewtUsage(nil, err)
 	}
 
-	err = b.PrepBuild()
-	if err != nil {
+	if err := b.PrepBuild(); err != nil {
 		NewtUsage(cmd, err)
 		return
 	}
 
-	var app_img *image.Image
-	var loader_img *image.Image
+	var appImg *image.Image
+	var loaderImg *image.Image
 
-	if b.Loader == nil {
-		err, app_img = CreateImage(b.App, version, keystr, keyId, nil)
+	if b.LoaderBuilder == nil {
+		err, appImg = CreateImage(b.AppBuilder, version, keystr, keyId, nil)
 		if err != nil {
 			NewtUsage(cmd, err)
 			return
 		}
 	} else {
-		err, loader_img = CreateImage(b.Loader, version, keystr, keyId, nil)
+		err, loaderImg = CreateImage(b.LoaderBuilder, version, keystr,
+			keyId, nil)
 		if err != nil {
 			NewtUsage(cmd, err)
 			return
 		}
 
-		err, app_img = CreateImage(b.App, version, keystr, keyId, loader_img)
+		err, appImg = CreateImage(b.AppBuilder, version, keystr, keyId,
+			loaderImg)
 		if err != nil {
 			NewtUsage(cmd, err)
 			return
@@ -128,8 +129,12 @@ func createImageRunCmd(cmd *cobra.Command, args []string) {
 
 	}
 
-	build_id := image.CreateBuildId(app_img, loader_img)
-	err = image.CreateManifest(b, app_img, loader_img, build_id)
+	buildId := image.CreateBuildId(appImg, loaderImg)
+	if err := image.CreateManifest(b, appImg, loaderImg,
+		buildId); err != nil {
+
+		NewtUsage(nil, err)
+	}
 }
 
 func AddImageCommands(cmd *cobra.Command) {

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/dd715c24/newt/cli/project_cmds.go
----------------------------------------------------------------------
diff --git a/newt/cli/project_cmds.go b/newt/cli/project_cmds.go
index 8b4dc43..e1377a8 100644
--- a/newt/cli/project_cmds.go
+++ b/newt/cli/project_cmds.go
@@ -75,10 +75,10 @@ func newRunCmd(cmd *cobra.Command, args []string) {
 }
 
 func installRunCmd(cmd *cobra.Command, args []string) {
-	if err := project.Initialize(); err != nil {
-		NewtUsage(cmd, err)
+	proj, err := project.TryGetProject()
+	if err != nil {
+		NewtUsage(nil, err)
 	}
-	proj := project.GetProject()
 	interfaces.SetProject(proj)
 
 	if err := proj.Install(false, projectForce); err != nil {
@@ -87,10 +87,10 @@ func installRunCmd(cmd *cobra.Command, args []string) {
 }
 
 func upgradeRunCmd(cmd *cobra.Command, args []string) {
-	if err := project.Initialize(); err != nil {
-		NewtUsage(cmd, err)
+	proj, err := project.TryGetProject()
+	if err != nil {
+		NewtUsage(nil, err)
 	}
-	proj := project.GetProject()
 	interfaces.SetProject(proj)
 
 	if err := proj.Upgrade(projectForce); err != nil {
@@ -104,10 +104,10 @@ func infoRunCmd(cmd *cobra.Command, args []string) {
 		reqRepoName = strings.TrimPrefix(args[0], "@")
 	}
 
-	if err := project.Initialize(); err != nil {
+	proj, err := project.TryGetProject()
+	if err != nil {
 		NewtUsage(nil, err)
 	}
-	proj := project.GetProject()
 
 	repoNames := []string{}
 	for repoName, _ := range proj.PackageList() {
@@ -160,7 +160,10 @@ func infoRunCmd(cmd *cobra.Command, args []string) {
 }
 
 func syncRunCmd(cmd *cobra.Command, args []string) {
-	proj := project.GetProject()
+	proj, err := project.TryGetProject()
+	if err != nil {
+		NewtUsage(nil, err)
+	}
 	repos := proj.Repos()
 
 	ps, err := project.LoadProjectState()

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/dd715c24/newt/cli/run_cmds.go
----------------------------------------------------------------------
diff --git a/newt/cli/run_cmds.go b/newt/cli/run_cmds.go
index 9d2d2bf..8fa1afb 100644
--- a/newt/cli/run_cmds.go
+++ b/newt/cli/run_cmds.go
@@ -30,25 +30,25 @@ import (
 )
 
 func runRunCmd(cmd *cobra.Command, args []string) {
-	if err := project.Initialize(); err != nil {
-		NewtUsage(cmd, err)
-	}
 	if len(args) < 1 {
 		NewtUsage(cmd, util.NewNewtError("Must specify target"))
 	}
 
+	if _, err := project.TryGetProject(); err != nil {
+		NewtUsage(nil, err)
+	}
+
 	t := ResolveTarget(args[0])
 	if t == nil {
 		NewtUsage(cmd, util.NewNewtError("Invalid target name: "+args[0]))
 	}
 
-	b, err := builder.NewTargetBuilder(t)
+	b, err := builder.NewTargetBuilder(t, nil)
 	if err != nil {
 		NewtUsage(nil, err)
 	}
 
-	err = b.Build()
-	if err != nil {
+	if err := b.Build(); err != nil {
 		NewtUsage(nil, err)
 	}
 
@@ -58,48 +58,48 @@ func runRunCmd(cmd *cobra.Command, args []string) {
 	 * will barf if it needs an image for this type of target, instead of
 	 * downloading an older version.
 	 */
-	var app_img *image.Image
-	var loader_img *image.Image
+	var appImg *image.Image
+	var loaderImg *image.Image
+
 	if len(args) > 1 {
-		if b.Loader == nil {
-			err, app_img = CreateImage(b.App, args[1], "", 0, nil)
+		if b.LoaderBuilder == nil {
+			err, appImg = CreateImage(b.AppBuilder, args[1], "", 0, nil)
 			if err != nil {
 				NewtUsage(cmd, err)
 			}
 		} else {
-			err, loader_img = CreateImage(b.Loader, args[1], "", 0, nil)
+			err, loaderImg = CreateImage(b.LoaderBuilder, args[1], "", 0, nil)
 			if err != nil {
 				NewtUsage(cmd, err)
 			}
-			err, app_img = CreateImage(b.App, args[1], "", 0, loader_img)
+			err, appImg = CreateImage(b.AppBuilder, args[1], "", 0, loaderImg)
 			if err != nil {
 				NewtUsage(cmd, err)
 			}
 
 		}
 	} else {
-		os.Remove(b.App.AppImgPath())
+		os.Remove(b.AppBuilder.AppImgPath())
 
-		if b.Loader != nil {
-			os.Remove(b.Loader.AppImgPath())
+		if b.LoaderBuilder != nil {
+			os.Remove(b.LoaderBuilder.AppImgPath())
 		}
 	}
-	if app_img != nil {
-		build_id := image.CreateBuildId(app_img, loader_img)
+	if appImg != nil {
+		buildId := image.CreateBuildId(appImg, loaderImg)
 
-		err = image.CreateManifest(b, app_img, loader_img, build_id)
-		if err != nil {
-			NewtUsage(cmd, err)
+		if err := image.CreateManifest(b, appImg, loaderImg,
+			buildId); err != nil {
+
+			NewtUsage(nil, err)
 		}
 	}
 
-	err = b.Load(extraJtagCmd)
-	if err != nil {
-		NewtUsage(cmd, err)
+	if err := b.Load(extraJtagCmd); err != nil {
+		NewtUsage(nil, err)
 	}
-	err = b.Debug(extraJtagCmd, true)
-	if err != nil {
-		NewtUsage(cmd, err)
+	if err := b.Debug(extraJtagCmd, true); err != nil {
+		NewtUsage(nil, err)
 	}
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/dd715c24/newt/cli/target_cmds.go
----------------------------------------------------------------------
diff --git a/newt/cli/target_cmds.go b/newt/cli/target_cmds.go
index dca4163..631aa75 100644
--- a/newt/cli/target_cmds.go
+++ b/newt/cli/target_cmds.go
@@ -71,7 +71,7 @@ func targetContainsUserFiles(t *target.Target) (bool, error) {
 }
 
 func pkgVarSliceString(pack *pkg.LocalPackage, key string) string {
-	features := pack.Viper.GetStringSlice(key)
+	features := pack.PkgV.GetStringSlice(key)
 	sort.Strings(features)
 
 	var buffer bytes.Buffer
@@ -83,8 +83,8 @@ func pkgVarSliceString(pack *pkg.LocalPackage, key string) string {
 }
 
 func targetShowCmd(cmd *cobra.Command, args []string) {
-	if err := project.Initialize(); err != nil {
-		NewtUsage(cmd, err)
+	if _, err := project.TryGetProject(); err != nil {
+		NewtUsage(nil, err)
 	}
 	targetNames := []string{}
 	if len(args) == 0 {
@@ -143,15 +143,16 @@ func targetShowCmd(cmd *cobra.Command, args []string) {
 }
 
 func targetSetCmd(cmd *cobra.Command, args []string) {
-	if err := project.Initialize(); err != nil {
-		NewtUsage(cmd, err)
-	}
 	if len(args) < 2 {
 		NewtUsage(cmd,
 			util.NewNewtError("Must specify at least two arguments "+
 				"(target-name & k=v) to set"))
 	}
 
+	if _, err := project.TryGetProject(); err != nil {
+		NewtUsage(nil, err)
+	}
+
 	// Parse target name.
 	t, err := resolveExistingTargetArg(args[0])
 	if err != nil {
@@ -191,9 +192,9 @@ func targetSetCmd(cmd *cobra.Command, args []string) {
 			kv[0] = "pkg." + strings.TrimPrefix(kv[0], "target.")
 			if kv[1] == "" {
 				// User specified empty value; delete variable.
-				t.Package().Viper.Set(kv[0], nil)
+				t.Package().PkgV.Set(kv[0], nil)
 			} else {
-				t.Package().Viper.Set(kv[0], strings.Fields(kv[1]))
+				t.Package().PkgV.Set(kv[0], strings.Fields(kv[1]))
 			}
 		} else {
 			if kv[1] == "" {
@@ -223,19 +224,21 @@ func targetSetCmd(cmd *cobra.Command, args []string) {
 }
 
 func targetCreateCmd(cmd *cobra.Command, args []string) {
-	if err := project.Initialize(); err != nil {
-		NewtUsage(cmd, err)
-	}
 	if len(args) != 1 {
 		NewtUsage(cmd, util.NewNewtError("Missing target name"))
 	}
 
+	proj, err := project.TryGetProject()
+	if err != nil {
+		NewtUsage(nil, err)
+	}
+
 	pkgName, err := ResolveNewTargetName(args[0])
 	if err != nil {
 		NewtUsage(cmd, err)
 	}
 
-	repo := project.GetProject().LocalRepo()
+	repo := proj.LocalRepo()
 	pack := pkg.NewLocalPackage(repo, repo.Path()+"/"+pkgName)
 	pack.SetName(pkgName)
 	pack.SetType(pkg.PACKAGE_TYPE_TARGET)
@@ -281,14 +284,15 @@ func targetDelOne(t *target.Target) error {
 }
 
 func targetDelCmd(cmd *cobra.Command, args []string) {
-	if err := project.Initialize(); err != nil {
-		NewtUsage(cmd, err)
-	}
 	if len(args) < 1 {
 		NewtUsage(cmd, util.NewNewtError("Must specify at least one "+
 			"target to delete"))
 	}
 
+	if _, err := project.TryGetProject(); err != nil {
+		NewtUsage(nil, err)
+	}
+
 	targets, err := ResolveTargets(args...)
 	if err != nil {
 		NewtUsage(cmd, err)
@@ -302,14 +306,16 @@ func targetDelCmd(cmd *cobra.Command, args []string) {
 }
 
 func targetCopyCmd(cmd *cobra.Command, args []string) {
-	if err := project.Initialize(); err != nil {
-		NewtUsage(cmd, err)
-	}
 	if len(args) != 2 {
 		NewtUsage(cmd, util.NewNewtError("Must specify exactly one "+
 			"source target and one destination target"))
 	}
 
+	proj, err := project.TryGetProject()
+	if err != nil {
+		NewtUsage(nil, err)
+	}
+
 	srcTarget, err := resolveExistingTargetArg(args[0])
 	if err != nil {
 		NewtUsage(cmd, err)
@@ -322,7 +328,7 @@ func targetCopyCmd(cmd *cobra.Command, args []string) {
 
 	// Copy the source target's base package and adjust the fields which need
 	// to change.
-	dstTarget := srcTarget.Clone(project.GetProject().LocalRepo(), dstName)
+	dstTarget := srcTarget.Clone(proj.LocalRepo(), dstName)
 
 	// Save the new target.
 	err = dstTarget.Save()
@@ -345,10 +351,6 @@ func printSetting(entry syscfg.CfgEntry) {
 	util.StatusMessage(util.VERBOSITY_DEFAULT,
 		"    * Value: %s", entry.Value)
 
-	unfixed := syscfg.UnfixedValue(entry)
-	if unfixed != entry.Value {
-		util.StatusMessage(util.VERBOSITY_DEFAULT, " [%s]", unfixed)
-	}
 	util.StatusMessage(util.VERBOSITY_DEFAULT, "\n")
 
 	if len(entry.History) > 1 {
@@ -377,7 +379,12 @@ func printPkgCfg(pkgName string, cfg syscfg.Cfg, entries []syscfg.CfgEntry) {
 	}
 }
 
-func printCfg(cfg syscfg.Cfg) {
+func printCfg(targetName string, cfg syscfg.Cfg) {
+	if errText := cfg.ErrorText(); errText != "" {
+		util.StatusMessage(util.VERBOSITY_DEFAULT, "!!! %s\n\n", errText)
+	}
+
+	util.StatusMessage(util.VERBOSITY_DEFAULT, "Syscfg for %s:\n", targetName)
 	pkgNameEntryMap := syscfg.EntriesByPkg(cfg)
 
 	pkgNames := make([]string, 0, len(pkgNameEntryMap))
@@ -395,28 +402,30 @@ func printCfg(cfg syscfg.Cfg) {
 }
 
 func targetConfigCmd(cmd *cobra.Command, args []string) {
-	if err := project.Initialize(); err != nil {
-		NewtUsage(cmd, err)
-	}
 	if len(args) != 1 {
 		NewtUsage(cmd, util.NewNewtError("Must specify target name"))
 	}
 
+	if _, err := project.TryGetProject(); err != nil {
+		NewtUsage(nil, err)
+	}
+
 	t, err := resolveExistingTargetArg(args[0])
 	if err != nil {
 		NewtUsage(cmd, err)
 	}
 
-	b, err := builder.NewTargetBuilder(t)
+	b, err := builder.NewTargetBuilder(t, nil)
 	if err != nil {
 		NewtUsage(nil, err)
 	}
 
-	if err := b.PrepBuild(); err != nil {
+	cfgResolution, err := b.ExportCfg()
+	if err != nil {
 		NewtUsage(nil, err)
 	}
 
-	printCfg(b.App.Cfg)
+	printCfg(t.Name(), cfgResolution.Cfg)
 }
 
 func AddTargetCommands(cmd *cobra.Command) {
@@ -514,7 +523,7 @@ func AddTargetCommands(cmd *cobra.Command) {
 	configHelpText := "View a target's system configuration."
 
 	configCmd := &cobra.Command{
-		Use:       "config <target-name>",
+		Use:       "config",
 		Short:     "View target system configuration",
 		Long:      configHelpText,
 		Run:       targetConfigCmd,

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/dd715c24/newt/cli/util.go
----------------------------------------------------------------------
diff --git a/newt/cli/util.go b/newt/cli/util.go
index 5db85e7..23615bb 100644
--- a/newt/cli/util.go
+++ b/newt/cli/util.go
@@ -149,27 +149,6 @@ func ResolveNewTargetName(name string) (string, error) {
 	return pkgName, nil
 }
 
-func ResolvePackage(name string) (*pkg.LocalPackage, error) {
-	// Trim trailing slash from name.  This is necessary when tab
-	// completion is used to specify the name.
-	name = strings.TrimSuffix(name, "/")
-
-	dep, err := pkg.NewDependency(nil, name)
-	if err != nil {
-		return nil, util.FmtNewtError("invalid package name: %s (%s)", name,
-			err.Error())
-	}
-	if dep == nil {
-		return nil, util.NewNewtError("invalid package name: " + name)
-	}
-	pack := project.GetProject().ResolveDependency(dep)
-	if pack == nil {
-		return nil, util.NewNewtError("unknown package: " + name)
-	}
-
-	return pack.(*pkg.LocalPackage), nil
-}
-
 func PackageNameList(pkgs []*pkg.LocalPackage) string {
 	var buffer bytes.Buffer
 	for i, pack := range pkgs {

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/dd715c24/newt/cli/vars.go
----------------------------------------------------------------------
diff --git a/newt/cli/vars.go b/newt/cli/vars.go
index 45859ea..91fe4f4 100644
--- a/newt/cli/vars.go
+++ b/newt/cli/vars.go
@@ -55,7 +55,7 @@ func settingValues(settingName string) ([]string, error) {
 	packs := project.GetProject().PackagesOfType(-1)
 	for _, pack := range packs {
 		settings :=
-			pack.(*pkg.LocalPackage).Viper.GetStringSlice(settingName)
+			pack.(*pkg.LocalPackage).PkgV.GetStringSlice(settingName)
 
 		for _, setting := range settings {
 			settingMap[setting] = struct{}{}
@@ -141,6 +141,11 @@ var varsMap = map[string]func() ([]string, error){
 // Returns a slice of valid values for the target variable with the specified
 // name.  If an invalid target variable is specified, an error is returned.
 func VarValues(varName string) ([]string, error) {
+	_, err := project.TryGetProject()
+	if err != nil {
+		return nil, err
+	}
+
 	fn := varsMap[varName]
 	if fn == nil {
 		err := util.NewNewtError(fmt.Sprintf("Unknown setting name: \"%s\"",

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/dd715c24/newt/image/image.go
----------------------------------------------------------------------
diff --git a/newt/image/image.go b/newt/image/image.go
index 52432d9..cc57d3a 100644
--- a/newt/image/image.go
+++ b/newt/image/image.go
@@ -464,7 +464,7 @@ func CreateManifest(t *builder.TargetBuilder, app *Image, loader *Image, build_i
 		Date:      timeStr,
 	}
 
-	for _, builtPkg := range t.App.Packages {
+	for _, builtPkg := range t.AppBuilder.PkgMap {
 		imgPkg := &ImageManifestPkg{
 			Name: builtPkg.Name(),
 		}
@@ -475,7 +475,7 @@ func CreateManifest(t *builder.TargetBuilder, app *Image, loader *Image, build_i
 		manifest.Loader = filepath.Base(loader.targetImg)
 		manifest.LoaderHash = fmt.Sprintf("%x", loader.hash)
 
-		for _, builtPkg := range t.Loader.Packages {
+		for _, builtPkg := range t.LoaderBuilder.PkgMap {
 			imgPkg := &ImageManifestPkg{
 				Name: builtPkg.Name(),
 			}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/dd715c24/newt/newt.go
----------------------------------------------------------------------
diff --git a/newt/newt.go b/newt/newt.go
index 7f9f244..de37ad8 100644
--- a/newt/newt.go
+++ b/newt/newt.go
@@ -28,7 +28,6 @@ import (
 
 	"mynewt.apache.org/newt/newt/cli"
 	"mynewt.apache.org/newt/newt/newtutil"
-	"mynewt.apache.org/newt/newt/project"
 	"mynewt.apache.org/newt/util"
 )
 
@@ -121,8 +120,6 @@ func main() {
 	hold_lvl := log.GetLevel()
 	log.SetLevel(log.FatalLevel)
 
-	project.Initialize()
-
 	cli.AddCompleteCommands(cmd)
 	cli.AddProjectCommands(cmd)
 	cli.AddTargetCommands(cmd)
@@ -149,5 +146,7 @@ func main() {
 	}
 
 	log.SetLevel(hold_lvl)
-	cmd.Execute()
+	if err := cmd.Execute(); err != nil {
+		cli.NewtUsage(nil, err)
+	}
 }

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/dd715c24/newt/pkg/bsp_package.go
----------------------------------------------------------------------
diff --git a/newt/pkg/bsp_package.go b/newt/pkg/bsp_package.go
index a50a61a..99fab5f 100644
--- a/newt/pkg/bsp_package.go
+++ b/newt/pkg/bsp_package.go
@@ -35,17 +35,17 @@ type BspPackage struct {
 }
 
 func (bsp *BspPackage) Reload(features map[string]bool) error {
-	bsp.CompilerName = newtutil.GetStringFeatures(bsp.LocalPackage.Viper,
+	bsp.CompilerName = newtutil.GetStringFeatures(bsp.LocalPackage.PkgV,
 		features, "pkg.compiler")
-	bsp.Arch = newtutil.GetStringFeatures(bsp.LocalPackage.Viper,
+	bsp.Arch = newtutil.GetStringFeatures(bsp.LocalPackage.PkgV,
 		features, "pkg.arch")
-	bsp.LinkerScript = newtutil.GetStringFeatures(bsp.LocalPackage.Viper,
+	bsp.LinkerScript = newtutil.GetStringFeatures(bsp.LocalPackage.PkgV,
 		features, "pkg.linkerscript")
-	bsp.Part2LinkerScript = newtutil.GetStringFeatures(bsp.LocalPackage.Viper,
+	bsp.Part2LinkerScript = newtutil.GetStringFeatures(bsp.LocalPackage.PkgV,
 		features, "pkg.part2linkerscript")
-	bsp.DownloadScript = newtutil.GetStringFeatures(bsp.LocalPackage.Viper,
+	bsp.DownloadScript = newtutil.GetStringFeatures(bsp.LocalPackage.PkgV,
 		features, "pkg.downloadscript")
-	bsp.DebugScript = newtutil.GetStringFeatures(bsp.LocalPackage.Viper,
+	bsp.DebugScript = newtutil.GetStringFeatures(bsp.LocalPackage.PkgV,
 		features, "pkg.debugscript")
 
 	if bsp.CompilerName == "" {